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