simplify filesys.c via gnulib's select and fstat modules
[bpt/guile.git] / libguile / fports.c
CommitLineData
073167ef 1/* Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
4c187d46 2 * 2004, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc.
073167ef 3 *
73be1d9e 4 * This library is free software; you can redistribute it and/or
53befeb7
NJ
5 * modify it under the terms of the GNU Lesser General Public License
6 * as published by the Free Software Foundation; either version 3 of
7 * the License, or (at your option) any later version.
0f2d19dd 8 *
53befeb7
NJ
9 * This library is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
73be1d9e
MV
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
0f2d19dd 13 *
73be1d9e
MV
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
53befeb7
NJ
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 * 02110-1301 USA
73be1d9e 18 */
1bbd0b84 19
1bbd0b84 20
0f2d19dd 21\f
8ab3d8a0 22#define _LARGEFILE64_SOURCE /* ask for stat64 etc */
9858e529 23#define _GNU_SOURCE /* ask for LONG_LONG_MAX/LONG_LONG_MIN */
8ab3d8a0 24
dbb605f5 25#ifdef HAVE_CONFIG_H
85286595
RB
26# include <config.h>
27#endif
0f2d19dd
JB
28
29#include <stdio.h>
cb63cf9e 30#include <fcntl.h>
a0599745
MD
31#include "libguile/_scm.h"
32#include "libguile/strings.h"
a0599745 33#include "libguile/validate.h"
6b72ac1d 34#include "libguile/gc.h"
eb372585 35#include "libguile/posix.h"
7f9994d9 36#include "libguile/dynwind.h"
5dbc6c06 37#include "libguile/hashtab.h"
6b72ac1d 38
a0599745 39#include "libguile/fports.h"
95b88819
GH
40
41#ifdef HAVE_STRING_H
42#include <string.h>
43#endif
0f2d19dd
JB
44#ifdef HAVE_UNISTD_H
45#include <unistd.h>
0f2d19dd 46#endif
b8b17bfd
MV
47#ifdef HAVE_IO_H
48#include <io.h>
49#endif
f47a5239 50#ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
cb63cf9e
JB
51#include <sys/stat.h>
52#endif
c7519da3
CC
53#ifdef HAVE_POLL_H
54#include <poll.h>
55#endif
cb63cf9e 56#include <errno.h>
8ab3d8a0 57#include <sys/types.h>
09b204d3 58#include <sys/stat.h>
5335850d 59
a0599745 60#include "libguile/iselect.h"
edb810bb 61
634aa8de
LC
62#include <full-write.h>
63
8ab3d8a0
KR
64#if SIZEOF_OFF_T == SIZEOF_INT
65#define OFF_T_MAX INT_MAX
66#define OFF_T_MIN INT_MIN
67#elif SIZEOF_OFF_T == SIZEOF_LONG
68#define OFF_T_MAX LONG_MAX
69#define OFF_T_MIN LONG_MIN
70#elif SIZEOF_OFF_T == SIZEOF_LONG_LONG
71#define OFF_T_MAX LONG_LONG_MAX
72#define OFF_T_MIN LONG_LONG_MIN
73#else
74#error Oops, unknown OFF_T size
75#endif
a98bddfd 76
92c2555f 77scm_t_bits scm_tc16_fport;
a98bddfd
DH
78
79
19b27fa2 80/* default buffer size, used if the O/S won't supply a value. */
1be6b49c 81static const size_t default_buffer_size = 1024;
19b27fa2 82
cb63cf9e
JB
83/* create FPORT buffer with specified sizes (or -1 to use default size or
84 0 for no buffer. */
85static void
c014a02e 86scm_fport_buffer_add (SCM port, long read_size, int write_size)
c6c79933 87#define FUNC_NAME "scm_fport_buffer_add"
e145dd02 88{
92c2555f 89 scm_t_port *pt = SCM_PTAB_ENTRY (port);
e145dd02 90
cb63cf9e
JB
91 if (read_size == -1 || write_size == -1)
92 {
1be6b49c 93 size_t default_size;
f47a5239 94#ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
cb63cf9e 95 struct stat st;
b8b17bfd 96 scm_t_fport *fp = SCM_FSTREAM (port);
cb63cf9e 97
19b27fa2
GH
98 default_size = (fstat (fp->fdes, &st) == -1) ? default_buffer_size
99 : st.st_blksize;
cb63cf9e 100#else
19b27fa2 101 default_size = default_buffer_size;
cb63cf9e
JB
102#endif
103 if (read_size == -1)
104 read_size = default_size;
105 if (write_size == -1)
106 write_size = default_size;
107 }
0f2d19dd 108
f5f2dcff 109 if (SCM_INPUT_PORT_P (port) && read_size > 0)
cb63cf9e 110 {
92d8fd32 111 pt->read_buf = scm_gc_malloc_pointerless (read_size, "port buffer");
cb63cf9e
JB
112 pt->read_pos = pt->read_end = pt->read_buf;
113 pt->read_buf_size = read_size;
114 }
115 else
116 {
840ae05d 117 pt->read_pos = pt->read_buf = pt->read_end = &pt->shortbuf;
cb63cf9e
JB
118 pt->read_buf_size = 1;
119 }
1717856b 120
f5f2dcff 121 if (SCM_OUTPUT_PORT_P (port) && write_size > 0)
cb63cf9e 122 {
92d8fd32 123 pt->write_buf = scm_gc_malloc_pointerless (write_size, "port buffer");
cb63cf9e
JB
124 pt->write_pos = pt->write_buf;
125 pt->write_buf_size = write_size;
126 }
127 else
128 {
129 pt->write_buf = pt->write_pos = &pt->shortbuf;
130 pt->write_buf_size = 1;
131 }
132
133 pt->write_end = pt->write_buf + pt->write_buf_size;
134 if (read_size > 0 || write_size > 0)
54778cd3 135 SCM_SET_CELL_WORD_0 (port, SCM_CELL_WORD_0 (port) & ~SCM_BUF0);
cb63cf9e 136 else
54778cd3 137 SCM_SET_CELL_WORD_0 (port, SCM_CELL_WORD_0 (port) | SCM_BUF0);
7a6f1ffa 138}
c6c79933 139#undef FUNC_NAME
7a6f1ffa 140
a1ec6916 141SCM_DEFINE (scm_setvbuf, "setvbuf", 2, 1, 0,
1bbd0b84 142 (SCM port, SCM mode, SCM size),
fc0d72d4
MD
143 "Set the buffering mode for @var{port}. @var{mode} can be:\n"
144 "@table @code\n"
145 "@item _IONBF\n"
146 "non-buffered\n"
147 "@item _IOLBF\n"
148 "line buffered\n"
149 "@item _IOFBF\n"
150 "block buffered, using a newly allocated buffer of @var{size} bytes.\n"
151 "If @var{size} is omitted, a default size will be used.\n"
2c1ae20e 152 "@end table")
1bbd0b84 153#define FUNC_NAME s_scm_setvbuf
7a6f1ffa 154{
1be6b49c 155 int cmode;
c014a02e 156 long csize;
e8b21eec
LC
157 size_t ndrained;
158 char *drained;
92c2555f 159 scm_t_port *pt;
7a6f1ffa 160
78446828
MV
161 port = SCM_COERCE_OUTPORT (port);
162
3b3b36dd 163 SCM_VALIDATE_OPFPORT (1,port);
a55c2b68 164 cmode = scm_to_int (mode);
d3639214 165 if (cmode != _IONBF && cmode != _IOFBF && cmode != _IOLBF)
1bbd0b84 166 scm_out_of_range (FUNC_NAME, mode);
d3639214
GH
167
168 if (cmode == _IOLBF)
169 {
54778cd3 170 SCM_SET_CELL_WORD_0 (port, SCM_CELL_WORD_0 (port) | SCM_BUFLINE);
d3639214
GH
171 cmode = _IOFBF;
172 }
173 else
174 {
2b829bbb 175 SCM_SET_CELL_WORD_0 (port, SCM_CELL_WORD_0 (port) & ~(scm_t_bits)SCM_BUFLINE);
d3639214
GH
176 }
177
7a6f1ffa 178 if (SCM_UNBNDP (size))
cb63cf9e
JB
179 {
180 if (cmode == _IOFBF)
181 csize = -1;
182 else
183 csize = 0;
184 }
7a6f1ffa
GH
185 else
186 {
a55c2b68 187 csize = scm_to_int (size);
cb63cf9e 188 if (csize < 0 || (cmode == _IONBF && csize > 0))
1bbd0b84 189 scm_out_of_range (FUNC_NAME, size);
7a6f1ffa 190 }
d3639214 191
cb63cf9e 192 pt = SCM_PTAB_ENTRY (port);
7a6f1ffa 193
67a72dc1 194 if (SCM_INPUT_PORT_P (port))
e8b21eec
LC
195 {
196 /* Drain pending input from PORT. Don't use `scm_drain_input' since
197 it returns a string, whereas we want binary input here. */
198 ndrained = pt->read_end - pt->read_pos;
199 if (pt->read_buf == pt->putback_buf)
200 ndrained += pt->saved_read_end - pt->saved_read_pos;
201
202 if (ndrained > 0)
203 {
204 drained = scm_gc_malloc_pointerless (ndrained, "file port");
205 scm_take_from_input_buffers (port, drained, ndrained);
206 }
207 }
67a72dc1 208 else
e8b21eec 209 ndrained = 0;
67a72dc1
AW
210
211 if (SCM_OUTPUT_PORT_P (port))
212 scm_flush (port);
213
4c9419ac
MV
214 if (pt->read_buf == pt->putback_buf)
215 {
216 pt->read_buf = pt->saved_read_buf;
217 pt->read_pos = pt->saved_read_pos;
218 pt->read_end = pt->saved_read_end;
219 pt->read_buf_size = pt->saved_read_buf_size;
220 }
cb63cf9e 221 if (pt->read_buf != &pt->shortbuf)
4c9419ac 222 scm_gc_free (pt->read_buf, pt->read_buf_size, "port buffer");
cb63cf9e 223 if (pt->write_buf != &pt->shortbuf)
4c9419ac 224 scm_gc_free (pt->write_buf, pt->write_buf_size, "port buffer");
7a6f1ffa 225
cb63cf9e 226 scm_fport_buffer_add (port, csize, csize);
67a72dc1 227
e8b21eec
LC
228 if (ndrained > 0)
229 /* Put DRAINED back to PORT. */
230 while (ndrained-- > 0)
231 scm_unget_byte (drained[ndrained], port);
67a72dc1 232
cb63cf9e 233 return SCM_UNSPECIFIED;
0f2d19dd 234}
1bbd0b84 235#undef FUNC_NAME
0f2d19dd 236
eadd48de 237/* Move ports with the specified file descriptor to new descriptors,
387d418c 238 * resetting the revealed count to 0.
0f2d19dd 239 */
ee834df4
LC
240static void
241scm_i_evict_port (void *closure, SCM port)
0f2d19dd 242{
5dbc6c06 243 int fd = * (int*) closure;
0f2d19dd 244
5dbc6c06 245 if (SCM_FPORTP (port))
eadd48de 246 {
e9d8bc25
LC
247 scm_t_port *p;
248 scm_t_fport *fp;
249
250 /* XXX: In some cases, we can encounter a port with no associated ptab
251 entry. */
252 p = SCM_PTAB_ENTRY (port);
253 fp = (p != NULL) ? (scm_t_fport *) p->stream : NULL;
cb63cf9e 254
e9d8bc25 255 if ((fp != NULL) && (fp->fdes == fd))
eadd48de 256 {
5dbc6c06
HWN
257 fp->fdes = dup (fd);
258 if (fp->fdes == -1)
259 scm_syserror ("scm_evict_ports");
260 scm_set_port_revealed_x (port, scm_from_int (0));
eadd48de
GH
261 }
262 }
5dbc6c06
HWN
263}
264
265void
266scm_evict_ports (int fd)
267{
ee834df4 268 scm_c_port_for_each (scm_i_evict_port, (void *) &fd);
eadd48de 269}
0f2d19dd 270
efa40607
DH
271
272SCM_DEFINE (scm_file_port_p, "file-port?", 1, 0, 0,
273 (SCM obj),
2069af38 274 "Determine whether @var{obj} is a port that is related to a file.")
efa40607
DH
275#define FUNC_NAME s_scm_file_port_p
276{
7888309b 277 return scm_from_bool (SCM_FPORTP (obj));
efa40607
DH
278}
279#undef FUNC_NAME
280
281
69cac238 282static SCM sys_file_port_name_canonicalization;
0157a341
AW
283SCM_SYMBOL (sym_relative, "relative");
284SCM_SYMBOL (sym_absolute, "absolute");
285
286static SCM
287fport_canonicalize_filename (SCM filename)
288{
69cac238
AW
289 SCM mode = scm_fluid_ref (sys_file_port_name_canonicalization);
290
0157a341
AW
291 if (!scm_is_string (filename))
292 {
293 return filename;
294 }
69cac238 295 else if (scm_is_eq (mode, sym_relative))
0157a341 296 {
22457d57
AW
297 SCM path, rel;
298
299 path = scm_variable_ref (scm_c_module_lookup (scm_the_root_module (),
300 "%load-path"));
301 rel = scm_i_relativize_path (filename, path);
302
303 return scm_is_true (rel) ? rel : filename;
0157a341 304 }
69cac238 305 else if (scm_is_eq (mode, sym_absolute))
0157a341
AW
306 {
307 char *str, *canon;
308
309 str = scm_to_locale_string (filename);
310 canon = canonicalize_file_name (str);
311 free (str);
312
313 return canon ? scm_take_locale_string (canon) : filename;
314 }
315 else
316 {
317 return filename;
318 }
319}
320
321
0f2d19dd
JB
322/* scm_open_file
323 * Return a new port open on a given file.
324 *
325 * The mode string must match the pattern: [rwa+]** which
326 * is interpreted in the usual unix way.
327 *
328 * Return the new port.
329 */
3b3b36dd 330SCM_DEFINE (scm_open_file, "open-file", 2, 0, 0,
211683cc 331 (SCM filename, SCM mode),
1e6808ea 332 "Open the file whose name is @var{filename}, and return a port\n"
fc0d72d4 333 "representing that file. The attributes of the port are\n"
1e6808ea
MG
334 "determined by the @var{mode} string. The way in which this is\n"
335 "interpreted is similar to C stdio. The first character must be\n"
336 "one of the following:\n"
fc0d72d4
MD
337 "@table @samp\n"
338 "@item r\n"
339 "Open an existing file for input.\n"
340 "@item w\n"
341 "Open a file for output, creating it if it doesn't already exist\n"
342 "or removing its contents if it does.\n"
343 "@item a\n"
1e6808ea
MG
344 "Open a file for output, creating it if it doesn't already\n"
345 "exist. All writes to the port will go to the end of the file.\n"
fc0d72d4
MD
346 "The \"append mode\" can be turned off while the port is in use\n"
347 "@pxref{Ports and File Descriptors, fcntl}\n"
1e6808ea
MG
348 "@end table\n"
349 "The following additional characters can be appended:\n"
fc0d72d4 350 "@table @samp\n"
fc9c5d06 351 "@item b\n"
211683cc
MG
352 "Open the underlying file in binary mode, if supported by the system.\n"
353 "Also, open the file using the binary-compatible character encoding\n"
354 "\"ISO-8859-1\", ignoring the port's encoding and the coding declaration\n"
355 "at the top of the input file, if any.\n"
fc0d72d4
MD
356 "@item +\n"
357 "Open the port for both input and output. E.g., @code{r+}: open\n"
358 "an existing file for both input and output.\n"
359 "@item 0\n"
1e6808ea
MG
360 "Create an \"unbuffered\" port. In this case input and output\n"
361 "operations are passed directly to the underlying port\n"
362 "implementation without additional buffering. This is likely to\n"
363 "slow down I/O operations. The buffering mode can be changed\n"
364 "while a port is in use @pxref{Ports and File Descriptors,\n"
365 "setvbuf}\n"
fc0d72d4
MD
366 "@item l\n"
367 "Add line-buffering to the port. The port output buffer will be\n"
368 "automatically flushed whenever a newline character is written.\n"
1e6808ea 369 "@end table\n"
211683cc
MG
370 "When the file is opened, this procedure will scan for a coding\n"
371 "declaration@pxref{Character Encoding of Source Files}. If present\n"
372 "will use that encoding for interpreting the file. Otherwise, the\n"
373 "port's encoding will be used.\n"
374 "\n"
1e6808ea
MG
375 "In theory we could create read/write ports which were buffered\n"
376 "in one direction only. However this isn't included in the\n"
377 "current interfaces. If a file cannot be opened with the access\n"
378 "requested, @code{open-file} throws an exception.")
1bbd0b84 379#define FUNC_NAME s_scm_open_file
0f2d19dd 380{
19639113 381 SCM port;
419c8736 382 int fdes, flags = 0, use_encoding = 1;
64e3a89c
LC
383 unsigned int retries;
384 char *file, *md, *ptr;
19639113 385
661ae7ab 386 scm_dynwind_begin (0);
19639113 387
7f9994d9 388 file = scm_to_locale_string (filename);
661ae7ab 389 scm_dynwind_free (file);
7f9994d9
MV
390
391 md = scm_to_locale_string (mode);
661ae7ab 392 scm_dynwind_free (md);
19639113 393
1e6808ea 394 switch (*md)
0f2d19dd 395 {
cb63cf9e
JB
396 case 'r':
397 flags |= O_RDONLY;
398 break;
399 case 'w':
400 flags |= O_WRONLY | O_CREAT | O_TRUNC;
401 break;
402 case 'a':
403 flags |= O_WRONLY | O_CREAT | O_APPEND;
404 break;
405 default:
1e6808ea 406 scm_out_of_range (FUNC_NAME, mode);
0f2d19dd 407 }
1e6808ea 408 ptr = md + 1;
cb63cf9e 409 while (*ptr != '\0')
e145dd02 410 {
cb63cf9e
JB
411 switch (*ptr)
412 {
413 case '+':
414 flags = (flags & ~(O_RDONLY | O_WRONLY)) | O_RDWR;
415 break;
9f561420 416 case 'b':
419c8736 417 use_encoding = 0;
9f561420
GH
418#if defined (O_BINARY)
419 flags |= O_BINARY;
420#endif
421 break;
cb63cf9e 422 case '0': /* unbuffered: handled later. */
d3639214 423 case 'l': /* line buffered: handled during output. */
cb63cf9e
JB
424 break;
425 default:
1e6808ea 426 scm_out_of_range (FUNC_NAME, mode);
cb63cf9e
JB
427 }
428 ptr++;
e145dd02 429 }
cb63cf9e 430
64e3a89c
LC
431 for (retries = 0, fdes = -1;
432 fdes < 0 && retries < 2;
433 retries++)
434 {
435 SCM_SYSCALL (fdes = open_or_open64 (file, flags, 0666));
436 if (fdes == -1)
437 {
438 int en = errno;
439
440 if (en == EMFILE && retries == 0)
441 /* Run the GC in case it collects open file ports that are no
442 longer referenced. */
443 scm_i_gc (FUNC_NAME);
444 else
445 SCM_SYSERROR_MSG ("~A: ~S",
446 scm_cons (scm_strerror (scm_from_int (en)),
447 scm_cons (filename, SCM_EOL)), en);
448 }
0f2d19dd 449 }
64e3a89c 450
211683cc
MG
451 /* Create a port from this file descriptor. The port's encoding is initially
452 %default-port-encoding. */
0157a341
AW
453 port = scm_i_fdes_to_port (fdes, scm_i_mode_bits (mode),
454 fport_canonicalize_filename (filename));
7f9994d9 455
419c8736
AW
456 if (use_encoding)
457 {
458 /* If this file has a coding declaration, use that as the port
459 encoding. */
460 if (SCM_INPUT_PORT_P (port))
461 {
462 char *enc = scm_i_scan_for_encoding (port);
463 if (enc != NULL)
464 scm_i_set_port_encoding_x (port, enc);
465 }
466 }
467 else
211683cc
MG
468 /* If this is a binary file, use the binary-friendly ISO-8859-1
469 encoding. */
470 scm_i_set_port_encoding_x (port, NULL);
471
661ae7ab 472 scm_dynwind_end ();
7f9994d9 473
0f2d19dd
JB
474 return port;
475}
1bbd0b84 476#undef FUNC_NAME
0f2d19dd 477
e145dd02 478\f
cb63cf9e 479/* Building Guile ports from a file descriptor. */
e145dd02 480
cb63cf9e 481/* Build a Scheme port from an open file descriptor `fdes'.
a089567e
JB
482 MODE indicates whether FILE is open for reading or writing; it uses
483 the same notation as open-file's second argument.
19b27fa2
GH
484 NAME is a string to be used as the port's filename.
485*/
a089567e 486SCM
d617ee18 487scm_i_fdes_to_port (int fdes, long mode_bits, SCM name)
19b27fa2 488#define FUNC_NAME "scm_fdes_to_port"
a089567e 489{
a089567e 490 SCM port;
92c2555f 491 scm_t_port *pt;
19b27fa2 492
09b204d3
AW
493 /* Test that fdes is valid. */
494#ifdef F_GETFL
495 int flags = fcntl (fdes, F_GETFL, 0);
19b27fa2
GH
496 if (flags == -1)
497 SCM_SYSERROR;
498 flags &= O_ACCMODE;
499 if (flags != O_RDWR
500 && ((flags != O_WRONLY && (mode_bits & SCM_WRTNG))
501 || (flags != O_RDONLY && (mode_bits & SCM_RDNG))))
502 {
503 SCM_MISC_ERROR ("requested file mode not available on fdes", SCM_EOL);
504 }
09b204d3
AW
505#else
506 /* If we don't have F_GETFL, as on mingw, at least we can test that
507 it is a valid file descriptor. */
508 struct stat st;
509 if (fstat (fdes, &st) != 0)
510 SCM_SYSERROR;
511#endif
a089567e 512
9de87eea 513 scm_i_scm_pthread_mutex_lock (&scm_i_port_table_mutex);
da220f27
HWN
514
515 port = scm_new_port_table_entry (scm_tc16_fport);
516 SCM_SET_CELL_TYPE(port, scm_tc16_fport | mode_bits);
517 pt = SCM_PTAB_ENTRY(port);
a089567e 518 {
92c2555f 519 scm_t_fport *fp
92d8fd32
LC
520 = (scm_t_fport *) scm_gc_malloc_pointerless (sizeof (scm_t_fport),
521 "file port");
c6c79933 522
cb63cf9e 523 fp->fdes = fdes;
0de97b83 524 pt->rw_random = SCM_FDES_RANDOM_P (fdes);
cb63cf9e
JB
525 SCM_SETSTREAM (port, fp);
526 if (mode_bits & SCM_BUF0)
527 scm_fport_buffer_add (port, 0, 0);
528 else
529 scm_fport_buffer_add (port, -1, -1);
a089567e 530 }
b24b5e13 531 SCM_SET_FILENAME (port, name);
9de87eea 532 scm_i_pthread_mutex_unlock (&scm_i_port_table_mutex);
e145dd02
JB
533 return port;
534}
19b27fa2 535#undef FUNC_NAME
e145dd02 536
d617ee18
MV
537SCM
538scm_fdes_to_port (int fdes, char *mode, SCM name)
539{
540 return scm_i_fdes_to_port (fdes, scm_mode_bits (mode), name);
541}
542
affc96b5 543/* Return a lower bound on the number of bytes available for input. */
cb63cf9e 544static int
affc96b5 545fport_input_waiting (SCM port)
e145dd02 546{
23f2b9a3 547 int fdes = SCM_FSTREAM (port)->fdes;
c7519da3
CC
548
549 /* `FD_SETSIZE', which is 1024 on GNU systems, effectively limits the
550 highest numerical value of file descriptors that can be monitored.
551 Thus, use poll(2) whenever that is possible. */
552
4c187d46 553#if defined(HAVE_POLL) && defined(HAVE_STRUCT_POLLFD)
c7519da3
CC
554 struct pollfd pollfd = { fdes, POLLIN, 0 };
555
556 if (poll (&pollfd, 1, 0) < 0)
557 scm_syserror ("fport_input_waiting");
558
559 return pollfd.revents & POLLIN ? 1 : 0;
560
561#elif defined(HAVE_SELECT)
cb63cf9e
JB
562 struct timeval timeout;
563 SELECT_TYPE read_set;
564 SELECT_TYPE write_set;
565 SELECT_TYPE except_set;
566
567 FD_ZERO (&read_set);
568 FD_ZERO (&write_set);
569 FD_ZERO (&except_set);
570
571 FD_SET (fdes, &read_set);
572
573 timeout.tv_sec = 0;
574 timeout.tv_usec = 0;
575
576 if (select (SELECT_SET_SIZE,
577 &read_set, &write_set, &except_set, &timeout)
578 < 0)
affc96b5
GH
579 scm_syserror ("fport_input_waiting");
580 return FD_ISSET (fdes, &read_set) ? 1 : 0;
23f2b9a3
KR
581
582#elif HAVE_IOCTL && defined (FIONREAD)
23f2b9a3 583 int fdes = SCM_FSTREAM (port)->fdes;
cb63cf9e
JB
584 int remir;
585 ioctl(fdes, FIONREAD, &remir);
586 return remir;
23f2b9a3 587
cb63cf9e 588#else
affc96b5 589 scm_misc_error ("fport_input_waiting",
cb63cf9e
JB
590 "Not fully implemented on this platform",
591 SCM_EOL);
592#endif
a089567e
JB
593}
594
cb63cf9e 595\f
0f2d19dd 596static int
e81d98ec 597fport_print (SCM exp, SCM port, scm_print_state *pstate SCM_UNUSED)
0f2d19dd 598{
b3ec3c64
MD
599 scm_puts ("#<", port);
600 scm_print_port_mode (exp, port);
601 if (SCM_OPFPORTP (exp))
0f2d19dd 602 {
b3ec3c64 603 int fdes;
b24b5e13 604 SCM name = SCM_FILENAME (exp);
cc95e00a 605 if (scm_is_string (name) || scm_is_symbol (name))
b24b5e13
DH
606 scm_display (name, port);
607 else
608 scm_puts (SCM_PTOBNAME (SCM_PTOBNUM (exp)), port);
b3ec3c64
MD
609 scm_putc (' ', port);
610 fdes = (SCM_FSTREAM (exp))->fdes;
073167ef
LC
611
612#if (defined HAVE_TTYNAME) && (defined HAVE_POSIX)
b3ec3c64 613 if (isatty (fdes))
eb372585 614 scm_display (scm_ttyname (exp), port);
b3ec3c64 615 else
82893676 616#endif /* HAVE_TTYNAME */
b3ec3c64 617 scm_intprint (fdes, 10, port);
0f2d19dd
JB
618 }
619 else
620 {
b3ec3c64
MD
621 scm_puts (SCM_PTOBNAME (SCM_PTOBNUM (exp)), port);
622 scm_putc (' ', port);
0345e278 623 scm_uintprint ((scm_t_bits) SCM_PTAB_ENTRY (exp), 16, port);
0f2d19dd 624 }
b3ec3c64
MD
625 scm_putc ('>', port);
626 return 1;
0f2d19dd
JB
627}
628
affc96b5 629static void fport_flush (SCM port);
0f2d19dd 630
c2da2648
GH
631/* fill a port's read-buffer with a single read. returns the first
632 char or EOF if end of file. */
889975e5 633static scm_t_wchar
affc96b5 634fport_fill_input (SCM port)
0f2d19dd 635{
c014a02e 636 long count;
92c2555f
MV
637 scm_t_port *pt = SCM_PTAB_ENTRY (port);
638 scm_t_fport *fp = SCM_FSTREAM (port);
cb63cf9e 639
cb63cf9e
JB
640 SCM_SYSCALL (count = read (fp->fdes, pt->read_buf, pt->read_buf_size));
641 if (count == -1)
affc96b5 642 scm_syserror ("fport_fill_input");
cb63cf9e 643 if (count == 0)
889975e5 644 return (scm_t_wchar) EOF;
cb63cf9e
JB
645 else
646 {
5c070ca7 647 pt->read_pos = pt->read_buf;
cb63cf9e 648 pt->read_end = pt->read_buf + count;
5c070ca7 649 return *pt->read_buf;
cb63cf9e 650 }
0f2d19dd
JB
651}
652
0a94eb00
LC
653static scm_t_off
654fport_seek (SCM port, scm_t_off offset, int whence)
0f2d19dd 655{
92c2555f
MV
656 scm_t_port *pt = SCM_PTAB_ENTRY (port);
657 scm_t_fport *fp = SCM_FSTREAM (port);
8ab3d8a0
KR
658 off_t_or_off64_t rv;
659 off_t_or_off64_t result;
7dcb364d
GH
660
661 if (pt->rw_active == SCM_PORT_WRITE)
662 {
663 if (offset != 0 || whence != SEEK_CUR)
664 {
665 fport_flush (port);
8ab3d8a0 666 result = rv = lseek_or_lseek64 (fp->fdes, offset, whence);
7dcb364d
GH
667 }
668 else
669 {
670 /* read current position without disturbing the buffer. */
8ab3d8a0 671 rv = lseek_or_lseek64 (fp->fdes, offset, whence);
7dcb364d
GH
672 result = rv + (pt->write_pos - pt->write_buf);
673 }
674 }
675 else if (pt->rw_active == SCM_PORT_READ)
676 {
677 if (offset != 0 || whence != SEEK_CUR)
678 {
679 /* could expand to avoid a second seek. */
680 scm_end_input (port);
8ab3d8a0 681 result = rv = lseek_or_lseek64 (fp->fdes, offset, whence);
7dcb364d
GH
682 }
683 else
684 {
685 /* read current position without disturbing the buffer
686 (particularly the unread-char buffer). */
8ab3d8a0 687 rv = lseek_or_lseek64 (fp->fdes, offset, whence);
7dcb364d
GH
688 result = rv - (pt->read_end - pt->read_pos);
689
690 if (pt->read_buf == pt->putback_buf)
691 result -= pt->saved_read_end - pt->saved_read_pos;
692 }
693 }
694 else /* SCM_PORT_NEITHER */
695 {
8ab3d8a0 696 result = rv = lseek_or_lseek64 (fp->fdes, offset, whence);
7dcb364d 697 }
cb8dfa3f 698
7dcb364d 699 if (rv == -1)
affc96b5 700 scm_syserror ("fport_seek");
7dcb364d 701
cb8dfa3f 702 return result;
0f2d19dd
JB
703}
704
840ae05d 705static void
f1ce9199 706fport_truncate (SCM port, scm_t_off length)
840ae05d 707{
92c2555f 708 scm_t_fport *fp = SCM_FSTREAM (port);
840ae05d
JB
709
710 if (ftruncate (fp->fdes, length) == -1)
711 scm_syserror ("ftruncate");
712}
713
31703ab8 714static void
8aa011a1 715fport_write (SCM port, const void *data, size_t size)
daa4a3f1 716#define FUNC_NAME "fport_write"
31703ab8 717{
0c6d2191 718 /* this procedure tries to minimize the number of writes/flushes. */
92c2555f 719 scm_t_port *pt = SCM_PTAB_ENTRY (port);
31703ab8 720
0c6d2191
GH
721 if (pt->write_buf == &pt->shortbuf
722 || (pt->write_pos == pt->write_buf && size >= pt->write_buf_size))
31703ab8 723 {
daa4a3f1
LC
724 /* Unbuffered port, or port with empty buffer and data won't fit in
725 buffer. */
726 if (full_write (SCM_FPORT_FDES (port), data, size) < size)
727 SCM_SYSERROR;
728
0c6d2191 729 return;
31703ab8 730 }
d3639214 731
0c6d2191 732 {
f1ce9199 733 scm_t_off space = pt->write_end - pt->write_pos;
0c6d2191
GH
734
735 if (size <= space)
736 {
737 /* data fits in buffer. */
738 memcpy (pt->write_pos, data, size);
739 pt->write_pos += size;
740 if (pt->write_pos == pt->write_end)
741 {
affc96b5 742 fport_flush (port);
0c6d2191
GH
743 /* we can skip the line-buffering check if nothing's buffered. */
744 return;
745 }
746 }
747 else
748 {
749 memcpy (pt->write_pos, data, space);
750 pt->write_pos = pt->write_end;
751 fport_flush (port);
752 {
753 const void *ptr = ((const char *) data) + space;
754 size_t remaining = size - space;
755
756 if (size >= pt->write_buf_size)
757 {
daa4a3f1
LC
758 if (full_write (SCM_FPORT_FDES (port), ptr, remaining)
759 < remaining)
760 SCM_SYSERROR;
0c6d2191
GH
761 return;
762 }
763 else
764 {
765 memcpy (pt->write_pos, ptr, remaining);
766 pt->write_pos += remaining;
767 }
31703ab8 768 }
0c6d2191 769 }
31703ab8 770
0c6d2191
GH
771 /* handle line buffering. */
772 if ((SCM_CELL_WORD_0 (port) & SCM_BUFLINE) && memchr (data, '\n', size))
773 fport_flush (port);
774 }
31703ab8 775}
daa4a3f1 776#undef FUNC_NAME
31703ab8 777
cb63cf9e 778static void
affc96b5 779fport_flush (SCM port)
0f2d19dd 780{
5335850d 781 size_t written;
92c2555f
MV
782 scm_t_port *pt = SCM_PTAB_ENTRY (port);
783 scm_t_fport *fp = SCM_FSTREAM (port);
5335850d 784 size_t count = pt->write_pos - pt->write_buf;
cb63cf9e 785
5335850d
LC
786 written = full_write (fp->fdes, pt->write_buf, count);
787 if (written < count)
788 scm_syserror ("scm_flush");
cb63cf9e 789
cb63cf9e 790 pt->write_pos = pt->write_buf;
61e452ba 791 pt->rw_active = SCM_PORT_NEITHER;
840ae05d
JB
792}
793
283a1a0e 794/* clear the read buffer and adjust the file position for unread bytes. */
840ae05d 795static void
affc96b5 796fport_end_input (SCM port, int offset)
840ae05d 797{
92c2555f
MV
798 scm_t_fport *fp = SCM_FSTREAM (port);
799 scm_t_port *pt = SCM_PTAB_ENTRY (port);
283a1a0e
GH
800
801 offset += pt->read_end - pt->read_pos;
840ae05d 802
840ae05d
JB
803 if (offset > 0)
804 {
805 pt->read_pos = pt->read_end;
806 /* will throw error if unread-char used at beginning of file
807 then attempting to write. seems correct. */
808 if (lseek (fp->fdes, -offset, SEEK_CUR) == -1)
affc96b5 809 scm_syserror ("fport_end_input");
840ae05d 810 }
61e452ba 811 pt->rw_active = SCM_PORT_NEITHER;
8f29fbd0
JB
812}
813
6a2c4c81 814static int
affc96b5 815fport_close (SCM port)
6a2c4c81 816{
92c2555f
MV
817 scm_t_fport *fp = SCM_FSTREAM (port);
818 scm_t_port *pt = SCM_PTAB_ENTRY (port);
cb63cf9e 819 int rv;
840ae05d 820
affc96b5 821 fport_flush (port);
cb63cf9e
JB
822 SCM_SYSCALL (rv = close (fp->fdes));
823 if (rv == -1 && errno != EBADF)
6b72ac1d
GH
824 {
825 if (scm_gc_running_p)
826 /* silently ignore the error. scm_error would abort if we
827 called it now. */
828 ;
829 else
830 scm_syserror ("fport_close");
831 }
6c951427
GH
832 if (pt->read_buf == pt->putback_buf)
833 pt->read_buf = pt->saved_read_buf;
cb63cf9e 834 if (pt->read_buf != &pt->shortbuf)
4c9419ac 835 scm_gc_free (pt->read_buf, pt->read_buf_size, "port buffer");
cb63cf9e 836 if (pt->write_buf != &pt->shortbuf)
4c9419ac
MV
837 scm_gc_free (pt->write_buf, pt->write_buf_size, "port buffer");
838 scm_gc_free (fp, sizeof (*fp), "file port");
cb63cf9e 839 return rv;
6a2c4c81
JB
840}
841
1be6b49c 842static size_t
affc96b5 843fport_free (SCM port)
b3ec3c64 844{
affc96b5 845 fport_close (port);
b3ec3c64
MD
846 return 0;
847}
848
92c2555f 849static scm_t_bits
b3ec3c64
MD
850scm_make_fptob ()
851{
92c2555f 852 scm_t_bits tc = scm_make_port_type ("file", fport_fill_input, fport_write);
a98bddfd 853
affc96b5 854 scm_set_port_free (tc, fport_free);
e841c3e0 855 scm_set_port_print (tc, fport_print);
affc96b5
GH
856 scm_set_port_flush (tc, fport_flush);
857 scm_set_port_end_input (tc, fport_end_input);
858 scm_set_port_close (tc, fport_close);
859 scm_set_port_seek (tc, fport_seek);
860 scm_set_port_truncate (tc, fport_truncate);
861 scm_set_port_input_waiting (tc, fport_input_waiting);
a98bddfd
DH
862
863 return tc;
b3ec3c64 864}
0f2d19dd 865
0f2d19dd
JB
866void
867scm_init_fports ()
0f2d19dd 868{
a98bddfd
DH
869 scm_tc16_fport = scm_make_fptob ();
870
e11e83f3
MV
871 scm_c_define ("_IOFBF", scm_from_int (_IOFBF));
872 scm_c_define ("_IOLBF", scm_from_int (_IOLBF));
873 scm_c_define ("_IONBF", scm_from_int (_IONBF));
a98bddfd 874
69cac238
AW
875 sys_file_port_name_canonicalization = scm_make_fluid ();
876 scm_c_define ("%file-port-name-canonicalization",
877 sys_file_port_name_canonicalization);
878
a98bddfd 879#include "libguile/fports.x"
0f2d19dd 880}
89e00824
ML
881
882/*
883 Local Variables:
884 c-file-style: "gnu"
885 End:
886*/