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