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