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;
67a72dc1 177 SCM drained;
92c2555f 178 scm_t_port *pt;
7a6f1ffa 179
78446828
MV
180 port = SCM_COERCE_OUTPORT (port);
181
3b3b36dd 182 SCM_VALIDATE_OPFPORT (1,port);
a55c2b68 183 cmode = scm_to_int (mode);
d3639214 184 if (cmode != _IONBF && cmode != _IOFBF && cmode != _IOLBF)
1bbd0b84 185 scm_out_of_range (FUNC_NAME, mode);
d3639214
GH
186
187 if (cmode == _IOLBF)
188 {
54778cd3 189 SCM_SET_CELL_WORD_0 (port, SCM_CELL_WORD_0 (port) | SCM_BUFLINE);
d3639214
GH
190 cmode = _IOFBF;
191 }
192 else
193 {
2b829bbb 194 SCM_SET_CELL_WORD_0 (port, SCM_CELL_WORD_0 (port) & ~(scm_t_bits)SCM_BUFLINE);
d3639214
GH
195 }
196
7a6f1ffa 197 if (SCM_UNBNDP (size))
cb63cf9e
JB
198 {
199 if (cmode == _IOFBF)
200 csize = -1;
201 else
202 csize = 0;
203 }
7a6f1ffa
GH
204 else
205 {
a55c2b68 206 csize = scm_to_int (size);
cb63cf9e 207 if (csize < 0 || (cmode == _IONBF && csize > 0))
1bbd0b84 208 scm_out_of_range (FUNC_NAME, size);
7a6f1ffa 209 }
d3639214 210
cb63cf9e 211 pt = SCM_PTAB_ENTRY (port);
7a6f1ffa 212
67a72dc1
AW
213 if (SCM_INPUT_PORT_P (port))
214 drained = scm_drain_input (port);
215 else
216 drained = scm_nullstr;
217
218 if (SCM_OUTPUT_PORT_P (port))
4251ae2e 219 scm_flush_unlocked (port);
67a72dc1 220
4c9419ac
MV
221 if (pt->read_buf == pt->putback_buf)
222 {
223 pt->read_buf = pt->saved_read_buf;
224 pt->read_pos = pt->saved_read_pos;
225 pt->read_end = pt->saved_read_end;
226 pt->read_buf_size = pt->saved_read_buf_size;
227 }
cb63cf9e 228 if (pt->read_buf != &pt->shortbuf)
4c9419ac 229 scm_gc_free (pt->read_buf, pt->read_buf_size, "port buffer");
cb63cf9e 230 if (pt->write_buf != &pt->shortbuf)
4c9419ac 231 scm_gc_free (pt->write_buf, pt->write_buf_size, "port buffer");
7a6f1ffa 232
cb63cf9e 233 scm_fport_buffer_add (port, csize, csize);
67a72dc1
AW
234
235 if (scm_is_true (drained) && scm_c_string_length (drained))
236 scm_unread_string (drained, port);
237
cb63cf9e 238 return SCM_UNSPECIFIED;
0f2d19dd 239}
1bbd0b84 240#undef FUNC_NAME
0f2d19dd 241
eadd48de 242/* Move ports with the specified file descriptor to new descriptors,
387d418c 243 * resetting the revealed count to 0.
0f2d19dd 244 */
ee834df4
LC
245static void
246scm_i_evict_port (void *closure, SCM port)
0f2d19dd 247{
5dbc6c06 248 int fd = * (int*) closure;
0f2d19dd 249
5dbc6c06 250 if (SCM_FPORTP (port))
eadd48de 251 {
e9d8bc25
LC
252 scm_t_port *p;
253 scm_t_fport *fp;
254
255 /* XXX: In some cases, we can encounter a port with no associated ptab
256 entry. */
257 p = SCM_PTAB_ENTRY (port);
258 fp = (p != NULL) ? (scm_t_fport *) p->stream : NULL;
cb63cf9e 259
e9d8bc25 260 if ((fp != NULL) && (fp->fdes == fd))
eadd48de 261 {
5dbc6c06
HWN
262 fp->fdes = dup (fd);
263 if (fp->fdes == -1)
264 scm_syserror ("scm_evict_ports");
265 scm_set_port_revealed_x (port, scm_from_int (0));
eadd48de
GH
266 }
267 }
5dbc6c06
HWN
268}
269
270void
271scm_evict_ports (int fd)
272{
ee834df4 273 scm_c_port_for_each (scm_i_evict_port, (void *) &fd);
eadd48de 274}
0f2d19dd 275
efa40607
DH
276
277SCM_DEFINE (scm_file_port_p, "file-port?", 1, 0, 0,
278 (SCM obj),
2069af38 279 "Determine whether @var{obj} is a port that is related to a file.")
efa40607
DH
280#define FUNC_NAME s_scm_file_port_p
281{
7888309b 282 return scm_from_bool (SCM_FPORTP (obj));
efa40607
DH
283}
284#undef FUNC_NAME
285
286
69cac238 287static SCM sys_file_port_name_canonicalization;
0157a341
AW
288SCM_SYMBOL (sym_relative, "relative");
289SCM_SYMBOL (sym_absolute, "absolute");
290
291static SCM
292fport_canonicalize_filename (SCM filename)
293{
69cac238
AW
294 SCM mode = scm_fluid_ref (sys_file_port_name_canonicalization);
295
0157a341
AW
296 if (!scm_is_string (filename))
297 {
298 return filename;
299 }
69cac238 300 else if (scm_is_eq (mode, sym_relative))
0157a341 301 {
22457d57
AW
302 SCM path, rel;
303
304 path = scm_variable_ref (scm_c_module_lookup (scm_the_root_module (),
305 "%load-path"));
306 rel = scm_i_relativize_path (filename, path);
307
308 return scm_is_true (rel) ? rel : filename;
0157a341 309 }
69cac238 310 else if (scm_is_eq (mode, sym_absolute))
0157a341
AW
311 {
312 char *str, *canon;
313
314 str = scm_to_locale_string (filename);
315 canon = canonicalize_file_name (str);
316 free (str);
317
318 return canon ? scm_take_locale_string (canon) : filename;
319 }
320 else
321 {
322 return filename;
323 }
324}
325
326
0f2d19dd
JB
327/* scm_open_file
328 * Return a new port open on a given file.
329 *
330 * The mode string must match the pattern: [rwa+]** which
331 * is interpreted in the usual unix way.
332 *
333 * Return the new port.
334 */
3b3b36dd 335SCM_DEFINE (scm_open_file, "open-file", 2, 0, 0,
211683cc 336 (SCM filename, SCM mode),
1e6808ea 337 "Open the file whose name is @var{filename}, and return a port\n"
fc0d72d4 338 "representing that file. The attributes of the port are\n"
1e6808ea
MG
339 "determined by the @var{mode} string. The way in which this is\n"
340 "interpreted is similar to C stdio. The first character must be\n"
341 "one of the following:\n"
fc0d72d4
MD
342 "@table @samp\n"
343 "@item r\n"
344 "Open an existing file for input.\n"
345 "@item w\n"
346 "Open a file for output, creating it if it doesn't already exist\n"
347 "or removing its contents if it does.\n"
348 "@item a\n"
1e6808ea
MG
349 "Open a file for output, creating it if it doesn't already\n"
350 "exist. All writes to the port will go to the end of the file.\n"
fc0d72d4
MD
351 "The \"append mode\" can be turned off while the port is in use\n"
352 "@pxref{Ports and File Descriptors, fcntl}\n"
1e6808ea
MG
353 "@end table\n"
354 "The following additional characters can be appended:\n"
fc0d72d4 355 "@table @samp\n"
fc9c5d06 356 "@item b\n"
211683cc
MG
357 "Open the underlying file in binary mode, if supported by the system.\n"
358 "Also, open the file using the binary-compatible character encoding\n"
359 "\"ISO-8859-1\", ignoring the port's encoding and the coding declaration\n"
360 "at the top of the input file, if any.\n"
fc0d72d4
MD
361 "@item +\n"
362 "Open the port for both input and output. E.g., @code{r+}: open\n"
363 "an existing file for both input and output.\n"
364 "@item 0\n"
1e6808ea
MG
365 "Create an \"unbuffered\" port. In this case input and output\n"
366 "operations are passed directly to the underlying port\n"
367 "implementation without additional buffering. This is likely to\n"
368 "slow down I/O operations. The buffering mode can be changed\n"
369 "while a port is in use @pxref{Ports and File Descriptors,\n"
370 "setvbuf}\n"
fc0d72d4
MD
371 "@item l\n"
372 "Add line-buffering to the port. The port output buffer will be\n"
373 "automatically flushed whenever a newline character is written.\n"
1e6808ea 374 "@end table\n"
211683cc
MG
375 "When the file is opened, this procedure will scan for a coding\n"
376 "declaration@pxref{Character Encoding of Source Files}. If present\n"
377 "will use that encoding for interpreting the file. Otherwise, the\n"
378 "port's encoding will be used.\n"
379 "\n"
1e6808ea
MG
380 "In theory we could create read/write ports which were buffered\n"
381 "in one direction only. However this isn't included in the\n"
382 "current interfaces. If a file cannot be opened with the access\n"
383 "requested, @code{open-file} throws an exception.")
1bbd0b84 384#define FUNC_NAME s_scm_open_file
0f2d19dd 385{
19639113 386 SCM port;
211683cc 387 int fdes, flags = 0, use_encoding = 1;
64e3a89c
LC
388 unsigned int retries;
389 char *file, *md, *ptr;
19639113 390
661ae7ab 391 scm_dynwind_begin (0);
19639113 392
7f9994d9 393 file = scm_to_locale_string (filename);
661ae7ab 394 scm_dynwind_free (file);
7f9994d9
MV
395
396 md = scm_to_locale_string (mode);
661ae7ab 397 scm_dynwind_free (md);
19639113 398
1e6808ea 399 switch (*md)
0f2d19dd 400 {
cb63cf9e
JB
401 case 'r':
402 flags |= O_RDONLY;
403 break;
404 case 'w':
405 flags |= O_WRONLY | O_CREAT | O_TRUNC;
406 break;
407 case 'a':
408 flags |= O_WRONLY | O_CREAT | O_APPEND;
409 break;
410 default:
1e6808ea 411 scm_out_of_range (FUNC_NAME, mode);
0f2d19dd 412 }
1e6808ea 413 ptr = md + 1;
cb63cf9e 414 while (*ptr != '\0')
e145dd02 415 {
cb63cf9e
JB
416 switch (*ptr)
417 {
418 case '+':
419 flags = (flags & ~(O_RDONLY | O_WRONLY)) | O_RDWR;
420 break;
9f561420 421 case 'b':
211683cc 422 use_encoding = 0;
9f561420
GH
423#if defined (O_BINARY)
424 flags |= O_BINARY;
425#endif
426 break;
cb63cf9e 427 case '0': /* unbuffered: handled later. */
d3639214 428 case 'l': /* line buffered: handled during output. */
cb63cf9e
JB
429 break;
430 default:
1e6808ea 431 scm_out_of_range (FUNC_NAME, mode);
cb63cf9e
JB
432 }
433 ptr++;
e145dd02 434 }
cb63cf9e 435
64e3a89c
LC
436 for (retries = 0, fdes = -1;
437 fdes < 0 && retries < 2;
438 retries++)
439 {
440 SCM_SYSCALL (fdes = open_or_open64 (file, flags, 0666));
441 if (fdes == -1)
442 {
443 int en = errno;
444
445 if (en == EMFILE && retries == 0)
446 /* Run the GC in case it collects open file ports that are no
447 longer referenced. */
448 scm_i_gc (FUNC_NAME);
449 else
450 SCM_SYSERROR_MSG ("~A: ~S",
451 scm_cons (scm_strerror (scm_from_int (en)),
452 scm_cons (filename, SCM_EOL)), en);
453 }
0f2d19dd 454 }
64e3a89c 455
211683cc
MG
456 /* Create a port from this file descriptor. The port's encoding is initially
457 %default-port-encoding. */
0157a341
AW
458 port = scm_i_fdes_to_port (fdes, scm_i_mode_bits (mode),
459 fport_canonicalize_filename (filename));
7f9994d9 460
211683cc
MG
461 if (use_encoding)
462 {
463 /* If this file has a coding declaration, use that as the port
464 encoding. */
465 if (SCM_INPUT_PORT_P (port))
466 {
467 char *enc = scm_i_scan_for_encoding (port);
468 if (enc != NULL)
469 scm_i_set_port_encoding_x (port, enc);
470 }
471 }
472 else
473 /* If this is a binary file, use the binary-friendly ISO-8859-1
474 encoding. */
475 scm_i_set_port_encoding_x (port, NULL);
476
661ae7ab 477 scm_dynwind_end ();
7f9994d9 478
0f2d19dd
JB
479 return port;
480}
1bbd0b84 481#undef FUNC_NAME
0f2d19dd 482
e145dd02 483\f
82893676
MG
484#ifdef __MINGW32__
485/*
486 * Try getting the appropiate file flags for a given file descriptor
487 * under Windows. This incorporates some fancy operations because Windows
488 * differentiates between file, pipe and socket descriptors.
489 */
490#ifndef O_ACCMODE
491# define O_ACCMODE 0x0003
492#endif
493
494static int getflags (int fdes)
495{
496 int flags = 0;
497 struct stat buf;
498 int error, optlen = sizeof (int);
499
500 /* Is this a socket ? */
501 if (getsockopt (fdes, SOL_SOCKET, SO_ERROR, (void *) &error, &optlen) >= 0)
502 flags = O_RDWR;
503 /* Maybe a regular file ? */
504 else if (fstat (fdes, &buf) < 0)
505 flags = -1;
506 else
507 {
508 /* Or an anonymous pipe handle ? */
b8b17bfd 509 if (buf.st_mode & _S_IFIFO)
8f99e3f3
SJ
510 flags = PeekNamedPipe ((HANDLE) _get_osfhandle (fdes), NULL, 0,
511 NULL, NULL, NULL) ? O_RDONLY : O_WRONLY;
82893676 512 /* stdin ? */
b8b17bfd 513 else if (fdes == fileno (stdin) && isatty (fdes))
82893676
MG
514 flags = O_RDONLY;
515 /* stdout / stderr ? */
b8b17bfd
MV
516 else if ((fdes == fileno (stdout) || fdes == fileno (stderr)) &&
517 isatty (fdes))
82893676
MG
518 flags = O_WRONLY;
519 else
520 flags = buf.st_mode;
521 }
522 return flags;
523}
524#endif /* __MINGW32__ */
525
cb63cf9e 526/* Building Guile ports from a file descriptor. */
e145dd02 527
cb63cf9e 528/* Build a Scheme port from an open file descriptor `fdes'.
a089567e
JB
529 MODE indicates whether FILE is open for reading or writing; it uses
530 the same notation as open-file's second argument.
19b27fa2
GH
531 NAME is a string to be used as the port's filename.
532*/
a089567e 533SCM
d617ee18 534scm_i_fdes_to_port (int fdes, long mode_bits, SCM name)
19b27fa2 535#define FUNC_NAME "scm_fdes_to_port"
a089567e 536{
a089567e 537 SCM port;
2721f918 538 scm_t_fport *fp;
19b27fa2
GH
539 int flags;
540
541 /* test that fdes is valid. */
82893676
MG
542#ifdef __MINGW32__
543 flags = getflags (fdes);
544#else
19b27fa2 545 flags = fcntl (fdes, F_GETFL, 0);
82893676 546#endif
19b27fa2
GH
547 if (flags == -1)
548 SCM_SYSERROR;
549 flags &= O_ACCMODE;
550 if (flags != O_RDWR
551 && ((flags != O_WRONLY && (mode_bits & SCM_WRTNG))
552 || (flags != O_RDONLY && (mode_bits & SCM_RDNG))))
553 {
554 SCM_MISC_ERROR ("requested file mode not available on fdes", SCM_EOL);
555 }
a089567e 556
2721f918
AW
557 fp = (scm_t_fport *) scm_gc_malloc_pointerless (sizeof (scm_t_fport),
558 "file port");
559 fp->fdes = fdes;
560
561 port = scm_c_make_port (scm_tc16_fport, mode_bits, (scm_t_bits)fp);
562
563 SCM_PTAB_ENTRY (port)->rw_random = SCM_FDES_RANDOM_P (fdes);
564
565 if (mode_bits & SCM_BUF0)
566 scm_fport_buffer_add (port, 0, 0);
567 else
568 scm_fport_buffer_add (port, -1, -1);
569
b24b5e13 570 SCM_SET_FILENAME (port, name);
2721f918 571
e145dd02
JB
572 return port;
573}
19b27fa2 574#undef FUNC_NAME
e145dd02 575
d617ee18
MV
576SCM
577scm_fdes_to_port (int fdes, char *mode, SCM name)
578{
579 return scm_i_fdes_to_port (fdes, scm_mode_bits (mode), name);
580}
581
affc96b5 582/* Return a lower bound on the number of bytes available for input. */
cb63cf9e 583static int
affc96b5 584fport_input_waiting (SCM port)
e145dd02 585{
23f2b9a3 586 int fdes = SCM_FSTREAM (port)->fdes;
c7519da3
CC
587
588 /* `FD_SETSIZE', which is 1024 on GNU systems, effectively limits the
589 highest numerical value of file descriptors that can be monitored.
590 Thus, use poll(2) whenever that is possible. */
591
592#ifdef HAVE_POLL
593 struct pollfd pollfd = { fdes, POLLIN, 0 };
594
595 if (poll (&pollfd, 1, 0) < 0)
596 scm_syserror ("fport_input_waiting");
597
598 return pollfd.revents & POLLIN ? 1 : 0;
599
600#elif defined(HAVE_SELECT)
cb63cf9e
JB
601 struct timeval timeout;
602 SELECT_TYPE read_set;
603 SELECT_TYPE write_set;
604 SELECT_TYPE except_set;
605
606 FD_ZERO (&read_set);
607 FD_ZERO (&write_set);
608 FD_ZERO (&except_set);
609
610 FD_SET (fdes, &read_set);
611
612 timeout.tv_sec = 0;
613 timeout.tv_usec = 0;
614
615 if (select (SELECT_SET_SIZE,
616 &read_set, &write_set, &except_set, &timeout)
617 < 0)
affc96b5
GH
618 scm_syserror ("fport_input_waiting");
619 return FD_ISSET (fdes, &read_set) ? 1 : 0;
23f2b9a3
KR
620
621#elif HAVE_IOCTL && defined (FIONREAD)
622 /* Note: cannot test just defined(FIONREAD) here, since mingw has FIONREAD
623 (for use with winsock ioctlsocket()) but not ioctl(). */
624 int fdes = SCM_FSTREAM (port)->fdes;
cb63cf9e
JB
625 int remir;
626 ioctl(fdes, FIONREAD, &remir);
627 return remir;
23f2b9a3 628
cb63cf9e 629#else
affc96b5 630 scm_misc_error ("fport_input_waiting",
cb63cf9e
JB
631 "Not fully implemented on this platform",
632 SCM_EOL);
633#endif
a089567e
JB
634}
635
3753e227
AW
636
637\f
638
639/* Revealed counts --- an oddity inherited from SCSH. */
640
641#define SCM_REVEALED(x) (SCM_FSTREAM(x)->revealed)
642
643static SCM revealed_ports = SCM_EOL;
644static scm_i_pthread_mutex_t revealed_lock = SCM_I_PTHREAD_MUTEX_INITIALIZER;
3753e227
AW
645
646/* Find a port in the table and return its revealed count.
647 Also used by the garbage collector.
648 */
649int
650scm_revealed_count (SCM port)
651{
652 int ret;
653
654 scm_i_pthread_mutex_lock (&revealed_lock);
655 ret = SCM_REVEALED (port);
656 scm_i_pthread_mutex_unlock (&revealed_lock);
657
658 return ret;
659}
660
661SCM_DEFINE (scm_port_revealed, "port-revealed", 1, 0, 0,
662 (SCM port),
663 "Return the revealed count for @var{port}.")
664#define FUNC_NAME s_scm_port_revealed
665{
666 port = SCM_COERCE_OUTPORT (port);
667 SCM_VALIDATE_OPFPORT (1, port);
668 return scm_from_int (scm_revealed_count (port));
669}
670#undef FUNC_NAME
671
672/* Set the revealed count for a port. */
673SCM_DEFINE (scm_set_port_revealed_x, "set-port-revealed!", 2, 0, 0,
674 (SCM port, SCM rcount),
675 "Sets the revealed count for a port to a given value.\n"
676 "The return value is unspecified.")
677#define FUNC_NAME s_scm_set_port_revealed_x
678{
679 int r, prev;
680
681 port = SCM_COERCE_OUTPORT (port);
682 SCM_VALIDATE_OPFPORT (1, port);
683
684 r = scm_to_int (rcount);
685
686 scm_i_pthread_mutex_lock (&revealed_lock);
687
688 prev = SCM_REVEALED (port);
689 SCM_REVEALED (port) = r;
690
691 if (r && !prev)
692 revealed_ports = scm_cons (port, revealed_ports);
693 else if (prev && !r)
694 revealed_ports = scm_delq_x (port, revealed_ports);
695
696 scm_i_pthread_mutex_unlock (&revealed_lock);
697
698 return SCM_UNSPECIFIED;
699}
700#undef FUNC_NAME
701
702/* Set the revealed count for a port. */
703SCM_DEFINE (scm_adjust_port_revealed_x, "adjust-port-revealed!", 2, 0, 0,
704 (SCM port, SCM addend),
705 "Add @var{addend} to the revealed count of @var{port}.\n"
706 "The return value is unspecified.")
707#define FUNC_NAME s_scm_adjust_port_revealed_x
708{
709 int a;
710
711 port = SCM_COERCE_OUTPORT (port);
712 SCM_VALIDATE_OPFPORT (1, port);
713
714 a = scm_to_int (addend);
715 if (!a)
716 return SCM_UNSPECIFIED;
717
718 scm_i_pthread_mutex_lock (&revealed_lock);
719
720 SCM_REVEALED (port) += a;
721 if (SCM_REVEALED (port) == a)
722 revealed_ports = scm_cons (port, revealed_ports);
723 else if (!SCM_REVEALED (port))
724 revealed_ports = scm_delq_x (port, revealed_ports);
725
726 scm_i_pthread_mutex_unlock (&revealed_lock);
727
728 return SCM_UNSPECIFIED;
729}
730#undef FUNC_NAME
731
732
cb63cf9e 733\f
0f2d19dd 734static int
e81d98ec 735fport_print (SCM exp, SCM port, scm_print_state *pstate SCM_UNUSED)
0f2d19dd 736{
0607ebbf 737 scm_puts_unlocked ("#<", port);
b3ec3c64
MD
738 scm_print_port_mode (exp, port);
739 if (SCM_OPFPORTP (exp))
0f2d19dd 740 {
b3ec3c64 741 int fdes;
b24b5e13 742 SCM name = SCM_FILENAME (exp);
cc95e00a 743 if (scm_is_string (name) || scm_is_symbol (name))
b24b5e13
DH
744 scm_display (name, port);
745 else
0607ebbf
AW
746 scm_puts_unlocked (SCM_PTOBNAME (SCM_PTOBNUM (exp)), port);
747 scm_putc_unlocked (' ', port);
b3ec3c64 748 fdes = (SCM_FSTREAM (exp))->fdes;
073167ef
LC
749
750#if (defined HAVE_TTYNAME) && (defined HAVE_POSIX)
b3ec3c64 751 if (isatty (fdes))
eb372585 752 scm_display (scm_ttyname (exp), port);
b3ec3c64 753 else
82893676 754#endif /* HAVE_TTYNAME */
b3ec3c64 755 scm_intprint (fdes, 10, port);
0f2d19dd
JB
756 }
757 else
758 {
0607ebbf
AW
759 scm_puts_unlocked (SCM_PTOBNAME (SCM_PTOBNUM (exp)), port);
760 scm_putc_unlocked (' ', port);
0345e278 761 scm_uintprint ((scm_t_bits) SCM_PTAB_ENTRY (exp), 16, port);
0f2d19dd 762 }
0607ebbf 763 scm_putc_unlocked ('>', port);
b3ec3c64 764 return 1;
0f2d19dd
JB
765}
766
affc96b5 767static void fport_flush (SCM port);
0f2d19dd 768
c2da2648
GH
769/* fill a port's read-buffer with a single read. returns the first
770 char or EOF if end of file. */
889975e5 771static scm_t_wchar
affc96b5 772fport_fill_input (SCM port)
0f2d19dd 773{
c014a02e 774 long count;
92c2555f
MV
775 scm_t_port *pt = SCM_PTAB_ENTRY (port);
776 scm_t_fport *fp = SCM_FSTREAM (port);
cb63cf9e 777
cb63cf9e
JB
778 SCM_SYSCALL (count = read (fp->fdes, pt->read_buf, pt->read_buf_size));
779 if (count == -1)
affc96b5 780 scm_syserror ("fport_fill_input");
cb63cf9e 781 if (count == 0)
889975e5 782 return (scm_t_wchar) EOF;
cb63cf9e
JB
783 else
784 {
5c070ca7 785 pt->read_pos = pt->read_buf;
cb63cf9e 786 pt->read_end = pt->read_buf + count;
5c070ca7 787 return *pt->read_buf;
cb63cf9e 788 }
0f2d19dd
JB
789}
790
0a94eb00
LC
791static scm_t_off
792fport_seek (SCM port, scm_t_off offset, int whence)
0f2d19dd 793{
92c2555f
MV
794 scm_t_port *pt = SCM_PTAB_ENTRY (port);
795 scm_t_fport *fp = SCM_FSTREAM (port);
8ab3d8a0
KR
796 off_t_or_off64_t rv;
797 off_t_or_off64_t result;
7dcb364d
GH
798
799 if (pt->rw_active == SCM_PORT_WRITE)
800 {
801 if (offset != 0 || whence != SEEK_CUR)
802 {
803 fport_flush (port);
8ab3d8a0 804 result = rv = lseek_or_lseek64 (fp->fdes, offset, whence);
7dcb364d
GH
805 }
806 else
807 {
808 /* read current position without disturbing the buffer. */
8ab3d8a0 809 rv = lseek_or_lseek64 (fp->fdes, offset, whence);
7dcb364d
GH
810 result = rv + (pt->write_pos - pt->write_buf);
811 }
812 }
813 else if (pt->rw_active == SCM_PORT_READ)
814 {
815 if (offset != 0 || whence != SEEK_CUR)
816 {
817 /* could expand to avoid a second seek. */
4251ae2e 818 scm_end_input_unlocked (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
824 (particularly the unread-char buffer). */
8ab3d8a0 825 rv = lseek_or_lseek64 (fp->fdes, offset, whence);
7dcb364d
GH
826 result = rv - (pt->read_end - pt->read_pos);
827
828 if (pt->read_buf == pt->putback_buf)
829 result -= pt->saved_read_end - pt->saved_read_pos;
830 }
831 }
832 else /* SCM_PORT_NEITHER */
833 {
8ab3d8a0 834 result = rv = lseek_or_lseek64 (fp->fdes, offset, whence);
7dcb364d 835 }
cb8dfa3f 836
7dcb364d 837 if (rv == -1)
affc96b5 838 scm_syserror ("fport_seek");
7dcb364d 839
cb8dfa3f 840 return result;
0f2d19dd
JB
841}
842
840ae05d 843static void
f1ce9199 844fport_truncate (SCM port, scm_t_off length)
840ae05d 845{
92c2555f 846 scm_t_fport *fp = SCM_FSTREAM (port);
840ae05d
JB
847
848 if (ftruncate (fp->fdes, length) == -1)
849 scm_syserror ("ftruncate");
850}
851
31703ab8 852static void
8aa011a1 853fport_write (SCM port, const void *data, size_t size)
daa4a3f1 854#define FUNC_NAME "fport_write"
31703ab8 855{
0c6d2191 856 /* this procedure tries to minimize the number of writes/flushes. */
92c2555f 857 scm_t_port *pt = SCM_PTAB_ENTRY (port);
31703ab8 858
0c6d2191
GH
859 if (pt->write_buf == &pt->shortbuf
860 || (pt->write_pos == pt->write_buf && size >= pt->write_buf_size))
31703ab8 861 {
daa4a3f1
LC
862 /* Unbuffered port, or port with empty buffer and data won't fit in
863 buffer. */
864 if (full_write (SCM_FPORT_FDES (port), data, size) < size)
865 SCM_SYSERROR;
866
0c6d2191 867 return;
31703ab8 868 }
d3639214 869
0c6d2191 870 {
f1ce9199 871 scm_t_off space = pt->write_end - pt->write_pos;
0c6d2191
GH
872
873 if (size <= space)
874 {
875 /* data fits in buffer. */
876 memcpy (pt->write_pos, data, size);
877 pt->write_pos += size;
878 if (pt->write_pos == pt->write_end)
879 {
affc96b5 880 fport_flush (port);
0c6d2191
GH
881 /* we can skip the line-buffering check if nothing's buffered. */
882 return;
883 }
884 }
885 else
886 {
887 memcpy (pt->write_pos, data, space);
888 pt->write_pos = pt->write_end;
889 fport_flush (port);
890 {
891 const void *ptr = ((const char *) data) + space;
892 size_t remaining = size - space;
893
894 if (size >= pt->write_buf_size)
895 {
daa4a3f1
LC
896 if (full_write (SCM_FPORT_FDES (port), ptr, remaining)
897 < remaining)
898 SCM_SYSERROR;
0c6d2191
GH
899 return;
900 }
901 else
902 {
903 memcpy (pt->write_pos, ptr, remaining);
904 pt->write_pos += remaining;
905 }
31703ab8 906 }
0c6d2191 907 }
31703ab8 908
0c6d2191
GH
909 /* handle line buffering. */
910 if ((SCM_CELL_WORD_0 (port) & SCM_BUFLINE) && memchr (data, '\n', size))
911 fport_flush (port);
912 }
31703ab8 913}
daa4a3f1 914#undef FUNC_NAME
31703ab8 915
cb63cf9e 916static void
affc96b5 917fport_flush (SCM port)
0f2d19dd 918{
5335850d 919 size_t written;
92c2555f
MV
920 scm_t_port *pt = SCM_PTAB_ENTRY (port);
921 scm_t_fport *fp = SCM_FSTREAM (port);
5335850d 922 size_t count = pt->write_pos - pt->write_buf;
cb63cf9e 923
5335850d
LC
924 written = full_write (fp->fdes, pt->write_buf, count);
925 if (written < count)
926 scm_syserror ("scm_flush");
cb63cf9e 927
cb63cf9e 928 pt->write_pos = pt->write_buf;
61e452ba 929 pt->rw_active = SCM_PORT_NEITHER;
840ae05d
JB
930}
931
283a1a0e 932/* clear the read buffer and adjust the file position for unread bytes. */
840ae05d 933static void
affc96b5 934fport_end_input (SCM port, int offset)
840ae05d 935{
92c2555f
MV
936 scm_t_fport *fp = SCM_FSTREAM (port);
937 scm_t_port *pt = SCM_PTAB_ENTRY (port);
283a1a0e
GH
938
939 offset += pt->read_end - pt->read_pos;
840ae05d 940
840ae05d
JB
941 if (offset > 0)
942 {
943 pt->read_pos = pt->read_end;
944 /* will throw error if unread-char used at beginning of file
945 then attempting to write. seems correct. */
946 if (lseek (fp->fdes, -offset, SEEK_CUR) == -1)
affc96b5 947 scm_syserror ("fport_end_input");
840ae05d 948 }
61e452ba 949 pt->rw_active = SCM_PORT_NEITHER;
8f29fbd0
JB
950}
951
5a771d5f
AW
952static void
953close_the_fd (void *data)
954{
955 scm_t_fport *fp = data;
956
957 close (fp->fdes);
958 /* There's already one exception. That's probably enough! */
959 errno = 0;
960}
961
6a2c4c81 962static int
affc96b5 963fport_close (SCM port)
6a2c4c81 964{
92c2555f 965 scm_t_fport *fp = SCM_FSTREAM (port);
cb63cf9e 966 int rv;
840ae05d 967
5a771d5f
AW
968 scm_dynwind_begin (0);
969 scm_dynwind_unwind_handler (close_the_fd, fp, 0);
affc96b5 970 fport_flush (port);
5a771d5f
AW
971 scm_dynwind_end ();
972
973 scm_port_non_buffer (SCM_PTAB_ENTRY (port));
974
975 rv = close (fp->fdes);
976 if (rv)
977 /* It's not useful to retry after EINTR, as the file descriptor is
978 in an undefined state. See http://lwn.net/Articles/365294/.
979 Instead just throw an error if close fails, trusting that the fd
980 was cleaned up. */
981 scm_syserror ("fport_close");
982
983 return 0;
6a2c4c81
JB
984}
985
1be6b49c 986static size_t
affc96b5 987fport_free (SCM port)
b3ec3c64 988{
affc96b5 989 fport_close (port);
b3ec3c64
MD
990 return 0;
991}
992
92c2555f 993static scm_t_bits
b3ec3c64
MD
994scm_make_fptob ()
995{
92c2555f 996 scm_t_bits tc = scm_make_port_type ("file", fport_fill_input, fport_write);
a98bddfd 997
affc96b5 998 scm_set_port_free (tc, fport_free);
e841c3e0 999 scm_set_port_print (tc, fport_print);
affc96b5
GH
1000 scm_set_port_flush (tc, fport_flush);
1001 scm_set_port_end_input (tc, fport_end_input);
1002 scm_set_port_close (tc, fport_close);
1003 scm_set_port_seek (tc, fport_seek);
1004 scm_set_port_truncate (tc, fport_truncate);
1005 scm_set_port_input_waiting (tc, fport_input_waiting);
a98bddfd
DH
1006
1007 return tc;
b3ec3c64 1008}
0f2d19dd 1009
0f2d19dd
JB
1010void
1011scm_init_fports ()
0f2d19dd 1012{
a98bddfd
DH
1013 scm_tc16_fport = scm_make_fptob ();
1014
e11e83f3
MV
1015 scm_c_define ("_IOFBF", scm_from_int (_IOFBF));
1016 scm_c_define ("_IOLBF", scm_from_int (_IOLBF));
1017 scm_c_define ("_IONBF", scm_from_int (_IONBF));
a98bddfd 1018
69cac238
AW
1019 sys_file_port_name_canonicalization = scm_make_fluid ();
1020 scm_c_define ("%file-port-name-canonicalization",
1021 sys_file_port_name_canonicalization);
1022
a98bddfd 1023#include "libguile/fports.x"
0f2d19dd 1024}
89e00824
ML
1025
1026/*
1027 Local Variables:
1028 c-file-style: "gnu"
1029 End:
1030*/