Merge remote-tracking branch 'origin/stable-2.0'
[bpt/guile.git] / libguile / fports.c
CommitLineData
073167ef 1/* Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
3753e227 2 * 2004, 2006, 2007, 2008, 2009, 2010, 2011, 2012 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))
4251ae2e 232 scm_flush_unlocked (port);
67a72dc1 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;
211683cc 402 int fdes, flags = 0, use_encoding = 1;
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;
418 break;
419 case 'w':
420 flags |= O_WRONLY | O_CREAT | O_TRUNC;
421 break;
422 case 'a':
423 flags |= O_WRONLY | O_CREAT | O_APPEND;
424 break;
425 default:
1e6808ea 426 scm_out_of_range (FUNC_NAME, mode);
0f2d19dd 427 }
1e6808ea 428 ptr = md + 1;
cb63cf9e 429 while (*ptr != '\0')
e145dd02 430 {
cb63cf9e
JB
431 switch (*ptr)
432 {
433 case '+':
434 flags = (flags & ~(O_RDONLY | O_WRONLY)) | O_RDWR;
435 break;
9f561420 436 case 'b':
211683cc 437 use_encoding = 0;
9f561420
GH
438#if defined (O_BINARY)
439 flags |= O_BINARY;
440#endif
441 break;
cb63cf9e 442 case '0': /* unbuffered: handled later. */
d3639214 443 case 'l': /* line buffered: handled during output. */
cb63cf9e
JB
444 break;
445 default:
1e6808ea 446 scm_out_of_range (FUNC_NAME, mode);
cb63cf9e
JB
447 }
448 ptr++;
e145dd02 449 }
cb63cf9e 450
64e3a89c
LC
451 for (retries = 0, fdes = -1;
452 fdes < 0 && retries < 2;
453 retries++)
454 {
455 SCM_SYSCALL (fdes = open_or_open64 (file, flags, 0666));
456 if (fdes == -1)
457 {
458 int en = errno;
459
460 if (en == EMFILE && retries == 0)
461 /* Run the GC in case it collects open file ports that are no
462 longer referenced. */
463 scm_i_gc (FUNC_NAME);
464 else
465 SCM_SYSERROR_MSG ("~A: ~S",
466 scm_cons (scm_strerror (scm_from_int (en)),
467 scm_cons (filename, SCM_EOL)), en);
468 }
0f2d19dd 469 }
64e3a89c 470
211683cc
MG
471 /* Create a port from this file descriptor. The port's encoding is initially
472 %default-port-encoding. */
0157a341
AW
473 port = scm_i_fdes_to_port (fdes, scm_i_mode_bits (mode),
474 fport_canonicalize_filename (filename));
7f9994d9 475
211683cc
MG
476 if (use_encoding)
477 {
478 /* If this file has a coding declaration, use that as the port
479 encoding. */
480 if (SCM_INPUT_PORT_P (port))
481 {
482 char *enc = scm_i_scan_for_encoding (port);
483 if (enc != NULL)
484 scm_i_set_port_encoding_x (port, enc);
485 }
486 }
487 else
488 /* If this is a binary file, use the binary-friendly ISO-8859-1
489 encoding. */
490 scm_i_set_port_encoding_x (port, NULL);
491
661ae7ab 492 scm_dynwind_end ();
7f9994d9 493
0f2d19dd
JB
494 return port;
495}
1bbd0b84 496#undef FUNC_NAME
0f2d19dd 497
e145dd02 498\f
82893676
MG
499#ifdef __MINGW32__
500/*
501 * Try getting the appropiate file flags for a given file descriptor
502 * under Windows. This incorporates some fancy operations because Windows
503 * differentiates between file, pipe and socket descriptors.
504 */
505#ifndef O_ACCMODE
506# define O_ACCMODE 0x0003
507#endif
508
509static int getflags (int fdes)
510{
511 int flags = 0;
512 struct stat buf;
513 int error, optlen = sizeof (int);
514
515 /* Is this a socket ? */
516 if (getsockopt (fdes, SOL_SOCKET, SO_ERROR, (void *) &error, &optlen) >= 0)
517 flags = O_RDWR;
518 /* Maybe a regular file ? */
519 else if (fstat (fdes, &buf) < 0)
520 flags = -1;
521 else
522 {
523 /* Or an anonymous pipe handle ? */
b8b17bfd 524 if (buf.st_mode & _S_IFIFO)
8f99e3f3
SJ
525 flags = PeekNamedPipe ((HANDLE) _get_osfhandle (fdes), NULL, 0,
526 NULL, NULL, NULL) ? O_RDONLY : O_WRONLY;
82893676 527 /* stdin ? */
b8b17bfd 528 else if (fdes == fileno (stdin) && isatty (fdes))
82893676
MG
529 flags = O_RDONLY;
530 /* stdout / stderr ? */
b8b17bfd
MV
531 else if ((fdes == fileno (stdout) || fdes == fileno (stderr)) &&
532 isatty (fdes))
82893676
MG
533 flags = O_WRONLY;
534 else
535 flags = buf.st_mode;
536 }
537 return flags;
538}
539#endif /* __MINGW32__ */
540
cb63cf9e 541/* Building Guile ports from a file descriptor. */
e145dd02 542
cb63cf9e 543/* Build a Scheme port from an open file descriptor `fdes'.
a089567e
JB
544 MODE indicates whether FILE is open for reading or writing; it uses
545 the same notation as open-file's second argument.
19b27fa2
GH
546 NAME is a string to be used as the port's filename.
547*/
a089567e 548SCM
d617ee18 549scm_i_fdes_to_port (int fdes, long mode_bits, SCM name)
19b27fa2 550#define FUNC_NAME "scm_fdes_to_port"
a089567e 551{
a089567e 552 SCM port;
2721f918 553 scm_t_fport *fp;
19b27fa2
GH
554 int flags;
555
556 /* test that fdes is valid. */
82893676
MG
557#ifdef __MINGW32__
558 flags = getflags (fdes);
559#else
19b27fa2 560 flags = fcntl (fdes, F_GETFL, 0);
82893676 561#endif
19b27fa2
GH
562 if (flags == -1)
563 SCM_SYSERROR;
564 flags &= O_ACCMODE;
565 if (flags != O_RDWR
566 && ((flags != O_WRONLY && (mode_bits & SCM_WRTNG))
567 || (flags != O_RDONLY && (mode_bits & SCM_RDNG))))
568 {
569 SCM_MISC_ERROR ("requested file mode not available on fdes", SCM_EOL);
570 }
a089567e 571
2721f918
AW
572 fp = (scm_t_fport *) scm_gc_malloc_pointerless (sizeof (scm_t_fport),
573 "file port");
574 fp->fdes = fdes;
575
576 port = scm_c_make_port (scm_tc16_fport, mode_bits, (scm_t_bits)fp);
577
578 SCM_PTAB_ENTRY (port)->rw_random = SCM_FDES_RANDOM_P (fdes);
579
580 if (mode_bits & SCM_BUF0)
581 scm_fport_buffer_add (port, 0, 0);
582 else
583 scm_fport_buffer_add (port, -1, -1);
584
b24b5e13 585 SCM_SET_FILENAME (port, name);
2721f918 586
e145dd02
JB
587 return port;
588}
19b27fa2 589#undef FUNC_NAME
e145dd02 590
d617ee18
MV
591SCM
592scm_fdes_to_port (int fdes, char *mode, SCM name)
593{
594 return scm_i_fdes_to_port (fdes, scm_mode_bits (mode), name);
595}
596
affc96b5 597/* Return a lower bound on the number of bytes available for input. */
cb63cf9e 598static int
affc96b5 599fport_input_waiting (SCM port)
e145dd02 600{
23f2b9a3 601 int fdes = SCM_FSTREAM (port)->fdes;
c7519da3
CC
602
603 /* `FD_SETSIZE', which is 1024 on GNU systems, effectively limits the
604 highest numerical value of file descriptors that can be monitored.
605 Thus, use poll(2) whenever that is possible. */
606
607#ifdef HAVE_POLL
608 struct pollfd pollfd = { fdes, POLLIN, 0 };
609
610 if (poll (&pollfd, 1, 0) < 0)
611 scm_syserror ("fport_input_waiting");
612
613 return pollfd.revents & POLLIN ? 1 : 0;
614
615#elif defined(HAVE_SELECT)
cb63cf9e
JB
616 struct timeval timeout;
617 SELECT_TYPE read_set;
618 SELECT_TYPE write_set;
619 SELECT_TYPE except_set;
620
621 FD_ZERO (&read_set);
622 FD_ZERO (&write_set);
623 FD_ZERO (&except_set);
624
625 FD_SET (fdes, &read_set);
626
627 timeout.tv_sec = 0;
628 timeout.tv_usec = 0;
629
630 if (select (SELECT_SET_SIZE,
631 &read_set, &write_set, &except_set, &timeout)
632 < 0)
affc96b5
GH
633 scm_syserror ("fport_input_waiting");
634 return FD_ISSET (fdes, &read_set) ? 1 : 0;
23f2b9a3
KR
635
636#elif HAVE_IOCTL && defined (FIONREAD)
637 /* Note: cannot test just defined(FIONREAD) here, since mingw has FIONREAD
638 (for use with winsock ioctlsocket()) but not ioctl(). */
639 int fdes = SCM_FSTREAM (port)->fdes;
cb63cf9e
JB
640 int remir;
641 ioctl(fdes, FIONREAD, &remir);
642 return remir;
23f2b9a3 643
cb63cf9e 644#else
affc96b5 645 scm_misc_error ("fport_input_waiting",
cb63cf9e
JB
646 "Not fully implemented on this platform",
647 SCM_EOL);
648#endif
a089567e
JB
649}
650
3753e227
AW
651
652\f
653
654/* Revealed counts --- an oddity inherited from SCSH. */
655
656#define SCM_REVEALED(x) (SCM_FSTREAM(x)->revealed)
657
658static SCM revealed_ports = SCM_EOL;
659static scm_i_pthread_mutex_t revealed_lock = SCM_I_PTHREAD_MUTEX_INITIALIZER;
3753e227
AW
660
661/* Find a port in the table and return its revealed count.
662 Also used by the garbage collector.
663 */
664int
665scm_revealed_count (SCM port)
666{
667 int ret;
668
669 scm_i_pthread_mutex_lock (&revealed_lock);
670 ret = SCM_REVEALED (port);
671 scm_i_pthread_mutex_unlock (&revealed_lock);
672
673 return ret;
674}
675
676SCM_DEFINE (scm_port_revealed, "port-revealed", 1, 0, 0,
677 (SCM port),
678 "Return the revealed count for @var{port}.")
679#define FUNC_NAME s_scm_port_revealed
680{
681 port = SCM_COERCE_OUTPORT (port);
682 SCM_VALIDATE_OPFPORT (1, port);
683 return scm_from_int (scm_revealed_count (port));
684}
685#undef FUNC_NAME
686
687/* Set the revealed count for a port. */
688SCM_DEFINE (scm_set_port_revealed_x, "set-port-revealed!", 2, 0, 0,
689 (SCM port, SCM rcount),
690 "Sets the revealed count for a port to a given value.\n"
691 "The return value is unspecified.")
692#define FUNC_NAME s_scm_set_port_revealed_x
693{
694 int r, prev;
695
696 port = SCM_COERCE_OUTPORT (port);
697 SCM_VALIDATE_OPFPORT (1, port);
698
699 r = scm_to_int (rcount);
700
701 scm_i_pthread_mutex_lock (&revealed_lock);
702
703 prev = SCM_REVEALED (port);
704 SCM_REVEALED (port) = r;
705
706 if (r && !prev)
707 revealed_ports = scm_cons (port, revealed_ports);
708 else if (prev && !r)
709 revealed_ports = scm_delq_x (port, revealed_ports);
710
711 scm_i_pthread_mutex_unlock (&revealed_lock);
712
713 return SCM_UNSPECIFIED;
714}
715#undef FUNC_NAME
716
717/* Set the revealed count for a port. */
718SCM_DEFINE (scm_adjust_port_revealed_x, "adjust-port-revealed!", 2, 0, 0,
719 (SCM port, SCM addend),
720 "Add @var{addend} to the revealed count of @var{port}.\n"
721 "The return value is unspecified.")
722#define FUNC_NAME s_scm_adjust_port_revealed_x
723{
724 int a;
725
726 port = SCM_COERCE_OUTPORT (port);
727 SCM_VALIDATE_OPFPORT (1, port);
728
729 a = scm_to_int (addend);
730 if (!a)
731 return SCM_UNSPECIFIED;
732
733 scm_i_pthread_mutex_lock (&revealed_lock);
734
735 SCM_REVEALED (port) += a;
736 if (SCM_REVEALED (port) == a)
737 revealed_ports = scm_cons (port, revealed_ports);
738 else if (!SCM_REVEALED (port))
739 revealed_ports = scm_delq_x (port, revealed_ports);
740
741 scm_i_pthread_mutex_unlock (&revealed_lock);
742
743 return SCM_UNSPECIFIED;
744}
745#undef FUNC_NAME
746
747
cb63cf9e 748\f
0f2d19dd 749static int
e81d98ec 750fport_print (SCM exp, SCM port, scm_print_state *pstate SCM_UNUSED)
0f2d19dd 751{
0607ebbf 752 scm_puts_unlocked ("#<", port);
b3ec3c64
MD
753 scm_print_port_mode (exp, port);
754 if (SCM_OPFPORTP (exp))
0f2d19dd 755 {
b3ec3c64 756 int fdes;
b24b5e13 757 SCM name = SCM_FILENAME (exp);
cc95e00a 758 if (scm_is_string (name) || scm_is_symbol (name))
b24b5e13
DH
759 scm_display (name, port);
760 else
0607ebbf
AW
761 scm_puts_unlocked (SCM_PTOBNAME (SCM_PTOBNUM (exp)), port);
762 scm_putc_unlocked (' ', port);
b3ec3c64 763 fdes = (SCM_FSTREAM (exp))->fdes;
073167ef
LC
764
765#if (defined HAVE_TTYNAME) && (defined HAVE_POSIX)
b3ec3c64 766 if (isatty (fdes))
eb372585 767 scm_display (scm_ttyname (exp), port);
b3ec3c64 768 else
82893676 769#endif /* HAVE_TTYNAME */
b3ec3c64 770 scm_intprint (fdes, 10, port);
0f2d19dd
JB
771 }
772 else
773 {
0607ebbf
AW
774 scm_puts_unlocked (SCM_PTOBNAME (SCM_PTOBNUM (exp)), port);
775 scm_putc_unlocked (' ', port);
0345e278 776 scm_uintprint ((scm_t_bits) SCM_PTAB_ENTRY (exp), 16, port);
0f2d19dd 777 }
0607ebbf 778 scm_putc_unlocked ('>', port);
b3ec3c64 779 return 1;
0f2d19dd
JB
780}
781
affc96b5 782static void fport_flush (SCM port);
0f2d19dd 783
c2da2648
GH
784/* fill a port's read-buffer with a single read. returns the first
785 char or EOF if end of file. */
889975e5 786static scm_t_wchar
affc96b5 787fport_fill_input (SCM port)
0f2d19dd 788{
c014a02e 789 long count;
92c2555f
MV
790 scm_t_port *pt = SCM_PTAB_ENTRY (port);
791 scm_t_fport *fp = SCM_FSTREAM (port);
cb63cf9e 792
cb63cf9e
JB
793 SCM_SYSCALL (count = read (fp->fdes, pt->read_buf, pt->read_buf_size));
794 if (count == -1)
affc96b5 795 scm_syserror ("fport_fill_input");
cb63cf9e 796 if (count == 0)
889975e5 797 return (scm_t_wchar) EOF;
cb63cf9e
JB
798 else
799 {
5c070ca7 800 pt->read_pos = pt->read_buf;
cb63cf9e 801 pt->read_end = pt->read_buf + count;
5c070ca7 802 return *pt->read_buf;
cb63cf9e 803 }
0f2d19dd
JB
804}
805
0a94eb00
LC
806static scm_t_off
807fport_seek (SCM port, scm_t_off offset, int whence)
0f2d19dd 808{
92c2555f
MV
809 scm_t_port *pt = SCM_PTAB_ENTRY (port);
810 scm_t_fport *fp = SCM_FSTREAM (port);
8ab3d8a0
KR
811 off_t_or_off64_t rv;
812 off_t_or_off64_t result;
7dcb364d
GH
813
814 if (pt->rw_active == SCM_PORT_WRITE)
815 {
816 if (offset != 0 || whence != SEEK_CUR)
817 {
818 fport_flush (port);
8ab3d8a0 819 result = rv = lseek_or_lseek64 (fp->fdes, offset, whence);
7dcb364d
GH
820 }
821 else
822 {
823 /* read current position without disturbing the buffer. */
8ab3d8a0 824 rv = lseek_or_lseek64 (fp->fdes, offset, whence);
7dcb364d
GH
825 result = rv + (pt->write_pos - pt->write_buf);
826 }
827 }
828 else if (pt->rw_active == SCM_PORT_READ)
829 {
830 if (offset != 0 || whence != SEEK_CUR)
831 {
832 /* could expand to avoid a second seek. */
4251ae2e 833 scm_end_input_unlocked (port);
8ab3d8a0 834 result = rv = lseek_or_lseek64 (fp->fdes, offset, whence);
7dcb364d
GH
835 }
836 else
837 {
838 /* read current position without disturbing the buffer
839 (particularly the unread-char buffer). */
8ab3d8a0 840 rv = lseek_or_lseek64 (fp->fdes, offset, whence);
7dcb364d
GH
841 result = rv - (pt->read_end - pt->read_pos);
842
843 if (pt->read_buf == pt->putback_buf)
844 result -= pt->saved_read_end - pt->saved_read_pos;
845 }
846 }
847 else /* SCM_PORT_NEITHER */
848 {
8ab3d8a0 849 result = rv = lseek_or_lseek64 (fp->fdes, offset, whence);
7dcb364d 850 }
cb8dfa3f 851
7dcb364d 852 if (rv == -1)
affc96b5 853 scm_syserror ("fport_seek");
7dcb364d 854
cb8dfa3f 855 return result;
0f2d19dd
JB
856}
857
840ae05d 858static void
f1ce9199 859fport_truncate (SCM port, scm_t_off length)
840ae05d 860{
92c2555f 861 scm_t_fport *fp = SCM_FSTREAM (port);
840ae05d
JB
862
863 if (ftruncate (fp->fdes, length) == -1)
864 scm_syserror ("ftruncate");
865}
866
31703ab8 867static void
8aa011a1 868fport_write (SCM port, const void *data, size_t size)
daa4a3f1 869#define FUNC_NAME "fport_write"
31703ab8 870{
0c6d2191 871 /* this procedure tries to minimize the number of writes/flushes. */
92c2555f 872 scm_t_port *pt = SCM_PTAB_ENTRY (port);
31703ab8 873
0c6d2191
GH
874 if (pt->write_buf == &pt->shortbuf
875 || (pt->write_pos == pt->write_buf && size >= pt->write_buf_size))
31703ab8 876 {
daa4a3f1
LC
877 /* Unbuffered port, or port with empty buffer and data won't fit in
878 buffer. */
879 if (full_write (SCM_FPORT_FDES (port), data, size) < size)
880 SCM_SYSERROR;
881
0c6d2191 882 return;
31703ab8 883 }
d3639214 884
0c6d2191 885 {
f1ce9199 886 scm_t_off space = pt->write_end - pt->write_pos;
0c6d2191
GH
887
888 if (size <= space)
889 {
890 /* data fits in buffer. */
891 memcpy (pt->write_pos, data, size);
892 pt->write_pos += size;
893 if (pt->write_pos == pt->write_end)
894 {
affc96b5 895 fport_flush (port);
0c6d2191
GH
896 /* we can skip the line-buffering check if nothing's buffered. */
897 return;
898 }
899 }
900 else
901 {
902 memcpy (pt->write_pos, data, space);
903 pt->write_pos = pt->write_end;
904 fport_flush (port);
905 {
906 const void *ptr = ((const char *) data) + space;
907 size_t remaining = size - space;
908
909 if (size >= pt->write_buf_size)
910 {
daa4a3f1
LC
911 if (full_write (SCM_FPORT_FDES (port), ptr, remaining)
912 < remaining)
913 SCM_SYSERROR;
0c6d2191
GH
914 return;
915 }
916 else
917 {
918 memcpy (pt->write_pos, ptr, remaining);
919 pt->write_pos += remaining;
920 }
31703ab8 921 }
0c6d2191 922 }
31703ab8 923
0c6d2191
GH
924 /* handle line buffering. */
925 if ((SCM_CELL_WORD_0 (port) & SCM_BUFLINE) && memchr (data, '\n', size))
926 fport_flush (port);
927 }
31703ab8 928}
daa4a3f1 929#undef FUNC_NAME
31703ab8 930
cb63cf9e 931static void
affc96b5 932fport_flush (SCM port)
0f2d19dd 933{
5335850d 934 size_t written;
92c2555f
MV
935 scm_t_port *pt = SCM_PTAB_ENTRY (port);
936 scm_t_fport *fp = SCM_FSTREAM (port);
5335850d 937 size_t count = pt->write_pos - pt->write_buf;
cb63cf9e 938
5335850d
LC
939 written = full_write (fp->fdes, pt->write_buf, count);
940 if (written < count)
941 scm_syserror ("scm_flush");
cb63cf9e 942
cb63cf9e 943 pt->write_pos = pt->write_buf;
61e452ba 944 pt->rw_active = SCM_PORT_NEITHER;
840ae05d
JB
945}
946
283a1a0e 947/* clear the read buffer and adjust the file position for unread bytes. */
840ae05d 948static void
affc96b5 949fport_end_input (SCM port, int offset)
840ae05d 950{
92c2555f
MV
951 scm_t_fport *fp = SCM_FSTREAM (port);
952 scm_t_port *pt = SCM_PTAB_ENTRY (port);
283a1a0e
GH
953
954 offset += pt->read_end - pt->read_pos;
840ae05d 955
840ae05d
JB
956 if (offset > 0)
957 {
958 pt->read_pos = pt->read_end;
959 /* will throw error if unread-char used at beginning of file
960 then attempting to write. seems correct. */
961 if (lseek (fp->fdes, -offset, SEEK_CUR) == -1)
affc96b5 962 scm_syserror ("fport_end_input");
840ae05d 963 }
61e452ba 964 pt->rw_active = SCM_PORT_NEITHER;
8f29fbd0
JB
965}
966
5a771d5f
AW
967static void
968close_the_fd (void *data)
969{
970 scm_t_fport *fp = data;
971
972 close (fp->fdes);
973 /* There's already one exception. That's probably enough! */
974 errno = 0;
975}
976
6a2c4c81 977static int
affc96b5 978fport_close (SCM port)
6a2c4c81 979{
92c2555f 980 scm_t_fport *fp = SCM_FSTREAM (port);
cb63cf9e 981 int rv;
840ae05d 982
5a771d5f
AW
983 scm_dynwind_begin (0);
984 scm_dynwind_unwind_handler (close_the_fd, fp, 0);
affc96b5 985 fport_flush (port);
5a771d5f
AW
986 scm_dynwind_end ();
987
988 scm_port_non_buffer (SCM_PTAB_ENTRY (port));
989
990 rv = close (fp->fdes);
991 if (rv)
992 /* It's not useful to retry after EINTR, as the file descriptor is
993 in an undefined state. See http://lwn.net/Articles/365294/.
994 Instead just throw an error if close fails, trusting that the fd
995 was cleaned up. */
996 scm_syserror ("fport_close");
997
998 return 0;
6a2c4c81
JB
999}
1000
1be6b49c 1001static size_t
affc96b5 1002fport_free (SCM port)
b3ec3c64 1003{
affc96b5 1004 fport_close (port);
b3ec3c64
MD
1005 return 0;
1006}
1007
92c2555f 1008static scm_t_bits
b3ec3c64
MD
1009scm_make_fptob ()
1010{
92c2555f 1011 scm_t_bits tc = scm_make_port_type ("file", fport_fill_input, fport_write);
a98bddfd 1012
affc96b5 1013 scm_set_port_free (tc, fport_free);
e841c3e0 1014 scm_set_port_print (tc, fport_print);
affc96b5
GH
1015 scm_set_port_flush (tc, fport_flush);
1016 scm_set_port_end_input (tc, fport_end_input);
1017 scm_set_port_close (tc, fport_close);
1018 scm_set_port_seek (tc, fport_seek);
1019 scm_set_port_truncate (tc, fport_truncate);
1020 scm_set_port_input_waiting (tc, fport_input_waiting);
a98bddfd
DH
1021
1022 return tc;
b3ec3c64 1023}
0f2d19dd 1024
0f2d19dd
JB
1025void
1026scm_init_fports ()
0f2d19dd 1027{
a98bddfd
DH
1028 scm_tc16_fport = scm_make_fptob ();
1029
e11e83f3
MV
1030 scm_c_define ("_IOFBF", scm_from_int (_IOFBF));
1031 scm_c_define ("_IOLBF", scm_from_int (_IOLBF));
1032 scm_c_define ("_IONBF", scm_from_int (_IONBF));
a98bddfd 1033
69cac238
AW
1034 sys_file_port_name_canonicalization = scm_make_fluid ();
1035 scm_c_define ("%file-port-name-canonicalization",
1036 sys_file_port_name_canonicalization);
1037
a98bddfd 1038#include "libguile/fports.x"
0f2d19dd 1039}
89e00824
ML
1040
1041/*
1042 Local Variables:
1043 c-file-style: "gnu"
1044 End:
1045*/