add %file-port-name-canonicalization option
[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
0157a341
AW
269static SCM* loc_file_port_name_canonicalization;
270SCM_SYMBOL (sym_relative, "relative");
271SCM_SYMBOL (sym_absolute, "absolute");
272
273static SCM
274fport_canonicalize_filename (SCM filename)
275{
276 if (!scm_is_string (filename))
277 {
278 return filename;
279 }
280 else if (scm_is_eq (*loc_file_port_name_canonicalization, sym_relative))
281 {
282 char *str, *canon;
283 SCM scanon, load_path;
284
285 str = scm_to_locale_string (filename);
286 canon = canonicalize_file_name (str);
287 free (str);
288
289 if (!canon)
290 return filename;
291
292 scanon = scm_take_locale_string (canon);
293
294 for (load_path = scm_variable_ref
295 (scm_c_module_lookup (scm_the_root_module (), "%load-path"));
296 scm_is_pair (load_path);
297 load_path = scm_cdr (load_path))
298 if (scm_is_true (scm_string_prefix_p (scm_car (load_path),
299 scanon,
300 SCM_UNDEFINED, SCM_UNDEFINED,
301 SCM_UNDEFINED, SCM_UNDEFINED)))
302 return scm_substring (scanon,
303 scm_string_length (scm_car (load_path)),
304 SCM_UNDEFINED);
305 return filename;
306 }
307 else if (scm_is_eq (*loc_file_port_name_canonicalization, sym_absolute))
308 {
309 char *str, *canon;
310
311 str = scm_to_locale_string (filename);
312 canon = canonicalize_file_name (str);
313 free (str);
314
315 return canon ? scm_take_locale_string (canon) : filename;
316 }
317 else
318 {
319 return filename;
320 }
321}
322
323
0f2d19dd
JB
324/* scm_open_file
325 * Return a new port open on a given file.
326 *
327 * The mode string must match the pattern: [rwa+]** which
328 * is interpreted in the usual unix way.
329 *
330 * Return the new port.
331 */
3b3b36dd 332SCM_DEFINE (scm_open_file, "open-file", 2, 0, 0,
1e6808ea
MG
333 (SCM filename, SCM mode),
334 "Open the file whose name is @var{filename}, and return a port\n"
fc0d72d4 335 "representing that file. The attributes of the port are\n"
1e6808ea
MG
336 "determined by the @var{mode} string. The way in which this is\n"
337 "interpreted is similar to C stdio. The first character must be\n"
338 "one of the following:\n"
fc0d72d4
MD
339 "@table @samp\n"
340 "@item r\n"
341 "Open an existing file for input.\n"
342 "@item w\n"
343 "Open a file for output, creating it if it doesn't already exist\n"
344 "or removing its contents if it does.\n"
345 "@item a\n"
1e6808ea
MG
346 "Open a file for output, creating it if it doesn't already\n"
347 "exist. All writes to the port will go to the end of the file.\n"
fc0d72d4
MD
348 "The \"append mode\" can be turned off while the port is in use\n"
349 "@pxref{Ports and File Descriptors, fcntl}\n"
1e6808ea
MG
350 "@end table\n"
351 "The following additional characters can be appended:\n"
fc0d72d4 352 "@table @samp\n"
fc9c5d06
HWN
353 "@item b\n"
354 "Open the underlying file in binary mode, if supported by the operating system. "
fc0d72d4
MD
355 "@item +\n"
356 "Open the port for both input and output. E.g., @code{r+}: open\n"
357 "an existing file for both input and output.\n"
358 "@item 0\n"
1e6808ea
MG
359 "Create an \"unbuffered\" port. In this case input and output\n"
360 "operations are passed directly to the underlying port\n"
361 "implementation without additional buffering. This is likely to\n"
362 "slow down I/O operations. The buffering mode can be changed\n"
363 "while a port is in use @pxref{Ports and File Descriptors,\n"
364 "setvbuf}\n"
fc0d72d4
MD
365 "@item l\n"
366 "Add line-buffering to the port. The port output buffer will be\n"
367 "automatically flushed whenever a newline character is written.\n"
1e6808ea
MG
368 "@end table\n"
369 "In theory we could create read/write ports which were buffered\n"
370 "in one direction only. However this isn't included in the\n"
371 "current interfaces. If a file cannot be opened with the access\n"
372 "requested, @code{open-file} throws an exception.")
1bbd0b84 373#define FUNC_NAME s_scm_open_file
0f2d19dd 374{
19639113 375 SCM port;
64e3a89c
LC
376 int fdes, flags = 0;
377 unsigned int retries;
378 char *file, *md, *ptr;
19639113 379
661ae7ab 380 scm_dynwind_begin (0);
19639113 381
7f9994d9 382 file = scm_to_locale_string (filename);
661ae7ab 383 scm_dynwind_free (file);
7f9994d9
MV
384
385 md = scm_to_locale_string (mode);
661ae7ab 386 scm_dynwind_free (md);
19639113 387
1e6808ea 388 switch (*md)
0f2d19dd 389 {
cb63cf9e
JB
390 case 'r':
391 flags |= O_RDONLY;
392 break;
393 case 'w':
394 flags |= O_WRONLY | O_CREAT | O_TRUNC;
395 break;
396 case 'a':
397 flags |= O_WRONLY | O_CREAT | O_APPEND;
398 break;
399 default:
1e6808ea 400 scm_out_of_range (FUNC_NAME, mode);
0f2d19dd 401 }
1e6808ea 402 ptr = md + 1;
cb63cf9e 403 while (*ptr != '\0')
e145dd02 404 {
cb63cf9e
JB
405 switch (*ptr)
406 {
407 case '+':
408 flags = (flags & ~(O_RDONLY | O_WRONLY)) | O_RDWR;
409 break;
9f561420
GH
410 case 'b':
411#if defined (O_BINARY)
412 flags |= O_BINARY;
413#endif
414 break;
cb63cf9e 415 case '0': /* unbuffered: handled later. */
d3639214 416 case 'l': /* line buffered: handled during output. */
cb63cf9e
JB
417 break;
418 default:
1e6808ea 419 scm_out_of_range (FUNC_NAME, mode);
cb63cf9e
JB
420 }
421 ptr++;
e145dd02 422 }
cb63cf9e 423
64e3a89c
LC
424 for (retries = 0, fdes = -1;
425 fdes < 0 && retries < 2;
426 retries++)
427 {
428 SCM_SYSCALL (fdes = open_or_open64 (file, flags, 0666));
429 if (fdes == -1)
430 {
431 int en = errno;
432
433 if (en == EMFILE && retries == 0)
434 /* Run the GC in case it collects open file ports that are no
435 longer referenced. */
436 scm_i_gc (FUNC_NAME);
437 else
438 SCM_SYSERROR_MSG ("~A: ~S",
439 scm_cons (scm_strerror (scm_from_int (en)),
440 scm_cons (filename, SCM_EOL)), en);
441 }
0f2d19dd 442 }
64e3a89c 443
0157a341
AW
444 port = scm_i_fdes_to_port (fdes, scm_i_mode_bits (mode),
445 fport_canonicalize_filename (filename));
7f9994d9 446
661ae7ab 447 scm_dynwind_end ();
7f9994d9 448
0f2d19dd
JB
449 return port;
450}
1bbd0b84 451#undef FUNC_NAME
0f2d19dd 452
e145dd02 453\f
82893676
MG
454#ifdef __MINGW32__
455/*
456 * Try getting the appropiate file flags for a given file descriptor
457 * under Windows. This incorporates some fancy operations because Windows
458 * differentiates between file, pipe and socket descriptors.
459 */
460#ifndef O_ACCMODE
461# define O_ACCMODE 0x0003
462#endif
463
464static int getflags (int fdes)
465{
466 int flags = 0;
467 struct stat buf;
468 int error, optlen = sizeof (int);
469
470 /* Is this a socket ? */
471 if (getsockopt (fdes, SOL_SOCKET, SO_ERROR, (void *) &error, &optlen) >= 0)
472 flags = O_RDWR;
473 /* Maybe a regular file ? */
474 else if (fstat (fdes, &buf) < 0)
475 flags = -1;
476 else
477 {
478 /* Or an anonymous pipe handle ? */
b8b17bfd 479 if (buf.st_mode & _S_IFIFO)
8f99e3f3
SJ
480 flags = PeekNamedPipe ((HANDLE) _get_osfhandle (fdes), NULL, 0,
481 NULL, NULL, NULL) ? O_RDONLY : O_WRONLY;
82893676 482 /* stdin ? */
b8b17bfd 483 else if (fdes == fileno (stdin) && isatty (fdes))
82893676
MG
484 flags = O_RDONLY;
485 /* stdout / stderr ? */
b8b17bfd
MV
486 else if ((fdes == fileno (stdout) || fdes == fileno (stderr)) &&
487 isatty (fdes))
82893676
MG
488 flags = O_WRONLY;
489 else
490 flags = buf.st_mode;
491 }
492 return flags;
493}
494#endif /* __MINGW32__ */
495
cb63cf9e 496/* Building Guile ports from a file descriptor. */
e145dd02 497
cb63cf9e 498/* Build a Scheme port from an open file descriptor `fdes'.
a089567e
JB
499 MODE indicates whether FILE is open for reading or writing; it uses
500 the same notation as open-file's second argument.
19b27fa2
GH
501 NAME is a string to be used as the port's filename.
502*/
a089567e 503SCM
d617ee18 504scm_i_fdes_to_port (int fdes, long mode_bits, SCM name)
19b27fa2 505#define FUNC_NAME "scm_fdes_to_port"
a089567e 506{
a089567e 507 SCM port;
92c2555f 508 scm_t_port *pt;
19b27fa2
GH
509 int flags;
510
511 /* test that fdes is valid. */
82893676
MG
512#ifdef __MINGW32__
513 flags = getflags (fdes);
514#else
19b27fa2 515 flags = fcntl (fdes, F_GETFL, 0);
82893676 516#endif
19b27fa2
GH
517 if (flags == -1)
518 SCM_SYSERROR;
519 flags &= O_ACCMODE;
520 if (flags != O_RDWR
521 && ((flags != O_WRONLY && (mode_bits & SCM_WRTNG))
522 || (flags != O_RDONLY && (mode_bits & SCM_RDNG))))
523 {
524 SCM_MISC_ERROR ("requested file mode not available on fdes", SCM_EOL);
525 }
a089567e 526
9de87eea 527 scm_i_scm_pthread_mutex_lock (&scm_i_port_table_mutex);
da220f27
HWN
528
529 port = scm_new_port_table_entry (scm_tc16_fport);
530 SCM_SET_CELL_TYPE(port, scm_tc16_fport | mode_bits);
531 pt = SCM_PTAB_ENTRY(port);
a089567e 532 {
92c2555f 533 scm_t_fport *fp
92d8fd32
LC
534 = (scm_t_fport *) scm_gc_malloc_pointerless (sizeof (scm_t_fport),
535 "file port");
c6c79933 536
cb63cf9e 537 fp->fdes = fdes;
0de97b83 538 pt->rw_random = SCM_FDES_RANDOM_P (fdes);
cb63cf9e
JB
539 SCM_SETSTREAM (port, fp);
540 if (mode_bits & SCM_BUF0)
541 scm_fport_buffer_add (port, 0, 0);
542 else
543 scm_fport_buffer_add (port, -1, -1);
a089567e 544 }
b24b5e13 545 SCM_SET_FILENAME (port, name);
9de87eea 546 scm_i_pthread_mutex_unlock (&scm_i_port_table_mutex);
e145dd02
JB
547 return port;
548}
19b27fa2 549#undef FUNC_NAME
e145dd02 550
d617ee18
MV
551SCM
552scm_fdes_to_port (int fdes, char *mode, SCM name)
553{
554 return scm_i_fdes_to_port (fdes, scm_mode_bits (mode), name);
555}
556
affc96b5 557/* Return a lower bound on the number of bytes available for input. */
cb63cf9e 558static int
affc96b5 559fport_input_waiting (SCM port)
e145dd02 560{
cb63cf9e 561#ifdef HAVE_SELECT
23f2b9a3 562 int fdes = SCM_FSTREAM (port)->fdes;
cb63cf9e
JB
563 struct timeval timeout;
564 SELECT_TYPE read_set;
565 SELECT_TYPE write_set;
566 SELECT_TYPE except_set;
567
568 FD_ZERO (&read_set);
569 FD_ZERO (&write_set);
570 FD_ZERO (&except_set);
571
572 FD_SET (fdes, &read_set);
573
574 timeout.tv_sec = 0;
575 timeout.tv_usec = 0;
576
577 if (select (SELECT_SET_SIZE,
578 &read_set, &write_set, &except_set, &timeout)
579 < 0)
affc96b5
GH
580 scm_syserror ("fport_input_waiting");
581 return FD_ISSET (fdes, &read_set) ? 1 : 0;
23f2b9a3
KR
582
583#elif HAVE_IOCTL && defined (FIONREAD)
584 /* Note: cannot test just defined(FIONREAD) here, since mingw has FIONREAD
585 (for use with winsock ioctlsocket()) but not ioctl(). */
586 int fdes = SCM_FSTREAM (port)->fdes;
cb63cf9e
JB
587 int remir;
588 ioctl(fdes, FIONREAD, &remir);
589 return remir;
23f2b9a3 590
cb63cf9e 591#else
affc96b5 592 scm_misc_error ("fport_input_waiting",
cb63cf9e
JB
593 "Not fully implemented on this platform",
594 SCM_EOL);
595#endif
a089567e
JB
596}
597
cb63cf9e 598\f
0f2d19dd 599static int
e81d98ec 600fport_print (SCM exp, SCM port, scm_print_state *pstate SCM_UNUSED)
0f2d19dd 601{
b3ec3c64
MD
602 scm_puts ("#<", port);
603 scm_print_port_mode (exp, port);
604 if (SCM_OPFPORTP (exp))
0f2d19dd 605 {
b3ec3c64 606 int fdes;
b24b5e13 607 SCM name = SCM_FILENAME (exp);
cc95e00a 608 if (scm_is_string (name) || scm_is_symbol (name))
b24b5e13
DH
609 scm_display (name, port);
610 else
611 scm_puts (SCM_PTOBNAME (SCM_PTOBNUM (exp)), port);
b3ec3c64
MD
612 scm_putc (' ', port);
613 fdes = (SCM_FSTREAM (exp))->fdes;
614
82893676 615#ifdef HAVE_TTYNAME
b3ec3c64 616 if (isatty (fdes))
eb372585 617 scm_display (scm_ttyname (exp), port);
b3ec3c64 618 else
82893676 619#endif /* HAVE_TTYNAME */
b3ec3c64 620 scm_intprint (fdes, 10, port);
0f2d19dd
JB
621 }
622 else
623 {
b3ec3c64
MD
624 scm_puts (SCM_PTOBNAME (SCM_PTOBNUM (exp)), port);
625 scm_putc (' ', port);
0345e278 626 scm_uintprint ((scm_t_bits) SCM_PTAB_ENTRY (exp), 16, port);
0f2d19dd 627 }
b3ec3c64
MD
628 scm_putc ('>', port);
629 return 1;
0f2d19dd
JB
630}
631
2e945bcc 632#ifndef __MINGW32__
cb63cf9e
JB
633/* thread-local block for input on fport's fdes. */
634static void
635fport_wait_for_input (SCM port)
3cb988bd 636{
cb63cf9e 637 int fdes = SCM_FSTREAM (port)->fdes;
3cb988bd 638
affc96b5 639 if (!fport_input_waiting (port))
8122b543 640 {
cb63cf9e
JB
641 int n;
642 SELECT_TYPE readfds;
643 int flags = fcntl (fdes, F_GETFL);
644
645 if (flags == -1)
646 scm_syserror ("scm_fdes_wait_for_input");
647 if (!(flags & O_NONBLOCK))
648 do
649 {
650 FD_ZERO (&readfds);
651 FD_SET (fdes, &readfds);
9de87eea 652 n = scm_std_select (fdes + 1, &readfds, NULL, NULL, NULL);
cb63cf9e
JB
653 }
654 while (n == -1 && errno == EINTR);
8122b543 655 }
3cb988bd 656}
2e945bcc 657#endif /* !__MINGW32__ */
0f2d19dd 658
affc96b5 659static void fport_flush (SCM port);
0f2d19dd 660
c2da2648
GH
661/* fill a port's read-buffer with a single read. returns the first
662 char or EOF if end of file. */
889975e5 663static scm_t_wchar
affc96b5 664fport_fill_input (SCM port)
0f2d19dd 665{
c014a02e 666 long count;
92c2555f
MV
667 scm_t_port *pt = SCM_PTAB_ENTRY (port);
668 scm_t_fport *fp = SCM_FSTREAM (port);
cb63cf9e 669
2e945bcc 670#ifndef __MINGW32__
cb63cf9e 671 fport_wait_for_input (port);
2e945bcc 672#endif /* !__MINGW32__ */
cb63cf9e
JB
673 SCM_SYSCALL (count = read (fp->fdes, pt->read_buf, pt->read_buf_size));
674 if (count == -1)
affc96b5 675 scm_syserror ("fport_fill_input");
cb63cf9e 676 if (count == 0)
889975e5 677 return (scm_t_wchar) EOF;
cb63cf9e
JB
678 else
679 {
5c070ca7 680 pt->read_pos = pt->read_buf;
cb63cf9e 681 pt->read_end = pt->read_buf + count;
5c070ca7 682 return *pt->read_buf;
cb63cf9e 683 }
0f2d19dd
JB
684}
685
0a94eb00
LC
686static scm_t_off
687fport_seek (SCM port, scm_t_off offset, int whence)
0f2d19dd 688{
92c2555f
MV
689 scm_t_port *pt = SCM_PTAB_ENTRY (port);
690 scm_t_fport *fp = SCM_FSTREAM (port);
8ab3d8a0
KR
691 off_t_or_off64_t rv;
692 off_t_or_off64_t result;
7dcb364d
GH
693
694 if (pt->rw_active == SCM_PORT_WRITE)
695 {
696 if (offset != 0 || whence != SEEK_CUR)
697 {
698 fport_flush (port);
8ab3d8a0 699 result = rv = lseek_or_lseek64 (fp->fdes, offset, whence);
7dcb364d
GH
700 }
701 else
702 {
703 /* read current position without disturbing the buffer. */
8ab3d8a0 704 rv = lseek_or_lseek64 (fp->fdes, offset, whence);
7dcb364d
GH
705 result = rv + (pt->write_pos - pt->write_buf);
706 }
707 }
708 else if (pt->rw_active == SCM_PORT_READ)
709 {
710 if (offset != 0 || whence != SEEK_CUR)
711 {
712 /* could expand to avoid a second seek. */
713 scm_end_input (port);
8ab3d8a0 714 result = rv = lseek_or_lseek64 (fp->fdes, offset, whence);
7dcb364d
GH
715 }
716 else
717 {
718 /* read current position without disturbing the buffer
719 (particularly the unread-char buffer). */
8ab3d8a0 720 rv = lseek_or_lseek64 (fp->fdes, offset, whence);
7dcb364d
GH
721 result = rv - (pt->read_end - pt->read_pos);
722
723 if (pt->read_buf == pt->putback_buf)
724 result -= pt->saved_read_end - pt->saved_read_pos;
725 }
726 }
727 else /* SCM_PORT_NEITHER */
728 {
8ab3d8a0 729 result = rv = lseek_or_lseek64 (fp->fdes, offset, whence);
7dcb364d 730 }
cb8dfa3f 731
7dcb364d 732 if (rv == -1)
affc96b5 733 scm_syserror ("fport_seek");
7dcb364d 734
cb8dfa3f 735 return result;
0f2d19dd
JB
736}
737
840ae05d 738static void
f1ce9199 739fport_truncate (SCM port, scm_t_off length)
840ae05d 740{
92c2555f 741 scm_t_fport *fp = SCM_FSTREAM (port);
840ae05d
JB
742
743 if (ftruncate (fp->fdes, length) == -1)
744 scm_syserror ("ftruncate");
745}
746
31703ab8 747static void
8aa011a1 748fport_write (SCM port, const void *data, size_t size)
daa4a3f1 749#define FUNC_NAME "fport_write"
31703ab8 750{
0c6d2191 751 /* this procedure tries to minimize the number of writes/flushes. */
92c2555f 752 scm_t_port *pt = SCM_PTAB_ENTRY (port);
31703ab8 753
0c6d2191
GH
754 if (pt->write_buf == &pt->shortbuf
755 || (pt->write_pos == pt->write_buf && size >= pt->write_buf_size))
31703ab8 756 {
daa4a3f1
LC
757 /* Unbuffered port, or port with empty buffer and data won't fit in
758 buffer. */
759 if (full_write (SCM_FPORT_FDES (port), data, size) < size)
760 SCM_SYSERROR;
761
0c6d2191 762 return;
31703ab8 763 }
d3639214 764
0c6d2191 765 {
f1ce9199 766 scm_t_off space = pt->write_end - pt->write_pos;
0c6d2191
GH
767
768 if (size <= space)
769 {
770 /* data fits in buffer. */
771 memcpy (pt->write_pos, data, size);
772 pt->write_pos += size;
773 if (pt->write_pos == pt->write_end)
774 {
affc96b5 775 fport_flush (port);
0c6d2191
GH
776 /* we can skip the line-buffering check if nothing's buffered. */
777 return;
778 }
779 }
780 else
781 {
782 memcpy (pt->write_pos, data, space);
783 pt->write_pos = pt->write_end;
784 fport_flush (port);
785 {
786 const void *ptr = ((const char *) data) + space;
787 size_t remaining = size - space;
788
789 if (size >= pt->write_buf_size)
790 {
daa4a3f1
LC
791 if (full_write (SCM_FPORT_FDES (port), ptr, remaining)
792 < remaining)
793 SCM_SYSERROR;
0c6d2191
GH
794 return;
795 }
796 else
797 {
798 memcpy (pt->write_pos, ptr, remaining);
799 pt->write_pos += remaining;
800 }
31703ab8 801 }
0c6d2191 802 }
31703ab8 803
0c6d2191
GH
804 /* handle line buffering. */
805 if ((SCM_CELL_WORD_0 (port) & SCM_BUFLINE) && memchr (data, '\n', size))
806 fport_flush (port);
807 }
31703ab8 808}
daa4a3f1 809#undef FUNC_NAME
31703ab8
GH
810
811/* becomes 1 when process is exiting: normal exception handling won't
812 work by this time. */
04a98cff 813extern int scm_i_terminating;
0f2d19dd 814
cb63cf9e 815static void
affc96b5 816fport_flush (SCM port)
0f2d19dd 817{
92c2555f
MV
818 scm_t_port *pt = SCM_PTAB_ENTRY (port);
819 scm_t_fport *fp = SCM_FSTREAM (port);
6f760c1d 820 unsigned char *ptr = pt->write_buf;
c014a02e
ML
821 long init_size = pt->write_pos - pt->write_buf;
822 long remaining = init_size;
0f2d19dd 823
cb63cf9e
JB
824 while (remaining > 0)
825 {
c014a02e 826 long count;
cb63cf9e
JB
827
828 SCM_SYSCALL (count = write (fp->fdes, ptr, remaining));
829 if (count < 0)
830 {
831 /* error. assume nothing was written this call, but
832 fix up the buffer for any previous successful writes. */
c014a02e 833 long done = init_size - remaining;
cb63cf9e
JB
834
835 if (done > 0)
836 {
837 int i;
838
839 for (i = 0; i < remaining; i++)
840 {
841 *(pt->write_buf + i) = *(pt->write_buf + done + i);
842 }
843 pt->write_pos = pt->write_buf + remaining;
844 }
04a98cff 845 if (scm_i_terminating)
cb63cf9e
JB
846 {
847 const char *msg = "Error: could not flush file-descriptor ";
848 char buf[11];
849
634aa8de 850 full_write (2, msg, strlen (msg));
cb63cf9e 851 sprintf (buf, "%d\n", fp->fdes);
634aa8de 852 full_write (2, buf, strlen (buf));
cb63cf9e
JB
853
854 count = remaining;
855 }
6b72ac1d
GH
856 else if (scm_gc_running_p)
857 {
858 /* silently ignore the error. scm_error would abort if we
859 called it now. */
860 count = remaining;
861 }
862 else
863 scm_syserror ("fport_flush");
cb63cf9e
JB
864 }
865 ptr += count;
866 remaining -= count;
867 }
868 pt->write_pos = pt->write_buf;
61e452ba 869 pt->rw_active = SCM_PORT_NEITHER;
840ae05d
JB
870}
871
283a1a0e 872/* clear the read buffer and adjust the file position for unread bytes. */
840ae05d 873static void
affc96b5 874fport_end_input (SCM port, int offset)
840ae05d 875{
92c2555f
MV
876 scm_t_fport *fp = SCM_FSTREAM (port);
877 scm_t_port *pt = SCM_PTAB_ENTRY (port);
283a1a0e
GH
878
879 offset += pt->read_end - pt->read_pos;
840ae05d 880
840ae05d
JB
881 if (offset > 0)
882 {
883 pt->read_pos = pt->read_end;
884 /* will throw error if unread-char used at beginning of file
885 then attempting to write. seems correct. */
886 if (lseek (fp->fdes, -offset, SEEK_CUR) == -1)
affc96b5 887 scm_syserror ("fport_end_input");
840ae05d 888 }
61e452ba 889 pt->rw_active = SCM_PORT_NEITHER;
8f29fbd0
JB
890}
891
6a2c4c81 892static int
affc96b5 893fport_close (SCM port)
6a2c4c81 894{
92c2555f
MV
895 scm_t_fport *fp = SCM_FSTREAM (port);
896 scm_t_port *pt = SCM_PTAB_ENTRY (port);
cb63cf9e 897 int rv;
840ae05d 898
affc96b5 899 fport_flush (port);
cb63cf9e
JB
900 SCM_SYSCALL (rv = close (fp->fdes));
901 if (rv == -1 && errno != EBADF)
6b72ac1d
GH
902 {
903 if (scm_gc_running_p)
904 /* silently ignore the error. scm_error would abort if we
905 called it now. */
906 ;
907 else
908 scm_syserror ("fport_close");
909 }
6c951427
GH
910 if (pt->read_buf == pt->putback_buf)
911 pt->read_buf = pt->saved_read_buf;
cb63cf9e 912 if (pt->read_buf != &pt->shortbuf)
4c9419ac 913 scm_gc_free (pt->read_buf, pt->read_buf_size, "port buffer");
cb63cf9e 914 if (pt->write_buf != &pt->shortbuf)
4c9419ac
MV
915 scm_gc_free (pt->write_buf, pt->write_buf_size, "port buffer");
916 scm_gc_free (fp, sizeof (*fp), "file port");
cb63cf9e 917 return rv;
6a2c4c81
JB
918}
919
1be6b49c 920static size_t
affc96b5 921fport_free (SCM port)
b3ec3c64 922{
affc96b5 923 fport_close (port);
b3ec3c64
MD
924 return 0;
925}
926
92c2555f 927static scm_t_bits
b3ec3c64
MD
928scm_make_fptob ()
929{
92c2555f 930 scm_t_bits tc = scm_make_port_type ("file", fport_fill_input, fport_write);
a98bddfd 931
affc96b5 932 scm_set_port_free (tc, fport_free);
e841c3e0 933 scm_set_port_print (tc, fport_print);
affc96b5
GH
934 scm_set_port_flush (tc, fport_flush);
935 scm_set_port_end_input (tc, fport_end_input);
936 scm_set_port_close (tc, fport_close);
937 scm_set_port_seek (tc, fport_seek);
938 scm_set_port_truncate (tc, fport_truncate);
939 scm_set_port_input_waiting (tc, fport_input_waiting);
a98bddfd
DH
940
941 return tc;
b3ec3c64 942}
0f2d19dd 943
0f2d19dd
JB
944void
945scm_init_fports ()
0f2d19dd 946{
a98bddfd
DH
947 scm_tc16_fport = scm_make_fptob ();
948
e11e83f3
MV
949 scm_c_define ("_IOFBF", scm_from_int (_IOFBF));
950 scm_c_define ("_IOLBF", scm_from_int (_IOLBF));
951 scm_c_define ("_IONBF", scm_from_int (_IONBF));
a98bddfd 952
0157a341
AW
953 loc_file_port_name_canonicalization =
954 SCM_VARIABLE_LOC (scm_c_define ("%file-port-name-canonicalization",
955 SCM_BOOL_F));
956
a98bddfd 957#include "libguile/fports.x"
0f2d19dd 958}
89e00824
ML
959
960/*
961 Local Variables:
962 c-file-style: "gnu"
963 End:
964*/