remove mingw32 implementations of {get,end,set}{serv,proto}ent
[bpt/guile.git] / libguile / fports.c
CommitLineData
073167ef 1/* Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
4c187d46 2 * 2004, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc.
073167ef 3 *
73be1d9e 4 * This library is free software; you can redistribute it and/or
53befeb7
NJ
5 * modify it under the terms of the GNU Lesser General Public License
6 * as published by the Free Software Foundation; either version 3 of
7 * the License, or (at your option) any later version.
0f2d19dd 8 *
53befeb7
NJ
9 * This library is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
73be1d9e
MV
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
0f2d19dd 13 *
73be1d9e
MV
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
53befeb7
NJ
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 * 02110-1301 USA
73be1d9e 18 */
1bbd0b84 19
1bbd0b84 20
0f2d19dd 21\f
8ab3d8a0 22#define _LARGEFILE64_SOURCE /* ask for stat64 etc */
9858e529 23#define _GNU_SOURCE /* ask for LONG_LONG_MAX/LONG_LONG_MIN */
8ab3d8a0 24
dbb605f5 25#ifdef HAVE_CONFIG_H
85286595
RB
26# include <config.h>
27#endif
0f2d19dd
JB
28
29#include <stdio.h>
cb63cf9e 30#include <fcntl.h>
a0599745
MD
31#include "libguile/_scm.h"
32#include "libguile/strings.h"
a0599745 33#include "libguile/validate.h"
6b72ac1d 34#include "libguile/gc.h"
eb372585 35#include "libguile/posix.h"
7f9994d9 36#include "libguile/dynwind.h"
5dbc6c06 37#include "libguile/hashtab.h"
6b72ac1d 38
a0599745 39#include "libguile/fports.h"
95b88819
GH
40
41#ifdef HAVE_STRING_H
42#include <string.h>
43#endif
0f2d19dd
JB
44#ifdef HAVE_UNISTD_H
45#include <unistd.h>
0f2d19dd 46#endif
b8b17bfd
MV
47#ifdef HAVE_IO_H
48#include <io.h>
49#endif
f47a5239 50#ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
cb63cf9e
JB
51#include <sys/stat.h>
52#endif
c7519da3
CC
53#ifdef HAVE_POLL_H
54#include <poll.h>
55#endif
cb63cf9e 56#include <errno.h>
8ab3d8a0 57#include <sys/types.h>
e145dd02 58
5335850d
LC
59#include <full-write.h>
60
a0599745 61#include "libguile/iselect.h"
edb810bb
SJ
62
63/* Some defines for Windows (native port, not Cygwin). */
82893676
MG
64#ifdef __MINGW32__
65# include <sys/stat.h>
66# include <winsock2.h>
82893676 67#endif /* __MINGW32__ */
cb63cf9e 68
634aa8de
LC
69#include <full-write.h>
70
8ab3d8a0
KR
71/* Mingw (version 3.4.5, circa 2006) has ftruncate as an alias for chsize
72 already, but have this code here in case that wasn't so in past versions,
73 or perhaps to help other minimal DOS environments.
74
75 gnulib ftruncate.c has code using fcntl F_CHSIZE and F_FREESP, which
76 might be possibilities if we've got other systems without ftruncate. */
77
56a3dcd4 78#if defined HAVE_CHSIZE && ! defined HAVE_FTRUNCATE
8ab3d8a0 79# define ftruncate(fd, size) chsize (fd, size)
56a3dcd4
LC
80# undef HAVE_FTRUNCATE
81# define HAVE_FTRUNCATE 1
8ab3d8a0
KR
82#endif
83
84#if SIZEOF_OFF_T == SIZEOF_INT
85#define OFF_T_MAX INT_MAX
86#define OFF_T_MIN INT_MIN
87#elif SIZEOF_OFF_T == SIZEOF_LONG
88#define OFF_T_MAX LONG_MAX
89#define OFF_T_MIN LONG_MIN
90#elif SIZEOF_OFF_T == SIZEOF_LONG_LONG
91#define OFF_T_MAX LONG_LONG_MAX
92#define OFF_T_MIN LONG_LONG_MIN
93#else
94#error Oops, unknown OFF_T size
95#endif
a98bddfd 96
92c2555f 97scm_t_bits scm_tc16_fport;
a98bddfd
DH
98
99
19b27fa2 100/* default buffer size, used if the O/S won't supply a value. */
1be6b49c 101static const size_t default_buffer_size = 1024;
19b27fa2 102
cb63cf9e
JB
103/* create FPORT buffer with specified sizes (or -1 to use default size or
104 0 for no buffer. */
105static void
c014a02e 106scm_fport_buffer_add (SCM port, long read_size, int write_size)
c6c79933 107#define FUNC_NAME "scm_fport_buffer_add"
e145dd02 108{
92c2555f 109 scm_t_port *pt = SCM_PTAB_ENTRY (port);
e145dd02 110
cb63cf9e
JB
111 if (read_size == -1 || write_size == -1)
112 {
1be6b49c 113 size_t default_size;
f47a5239 114#ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
cb63cf9e 115 struct stat st;
b8b17bfd 116 scm_t_fport *fp = SCM_FSTREAM (port);
cb63cf9e 117
19b27fa2
GH
118 default_size = (fstat (fp->fdes, &st) == -1) ? default_buffer_size
119 : st.st_blksize;
cb63cf9e 120#else
19b27fa2 121 default_size = default_buffer_size;
cb63cf9e
JB
122#endif
123 if (read_size == -1)
124 read_size = default_size;
125 if (write_size == -1)
126 write_size = default_size;
127 }
0f2d19dd 128
f5f2dcff 129 if (SCM_INPUT_PORT_P (port) && read_size > 0)
cb63cf9e 130 {
92d8fd32 131 pt->read_buf = scm_gc_malloc_pointerless (read_size, "port buffer");
cb63cf9e
JB
132 pt->read_pos = pt->read_end = pt->read_buf;
133 pt->read_buf_size = read_size;
134 }
135 else
136 {
840ae05d 137 pt->read_pos = pt->read_buf = pt->read_end = &pt->shortbuf;
cb63cf9e
JB
138 pt->read_buf_size = 1;
139 }
1717856b 140
f5f2dcff 141 if (SCM_OUTPUT_PORT_P (port) && write_size > 0)
cb63cf9e 142 {
92d8fd32 143 pt->write_buf = scm_gc_malloc_pointerless (write_size, "port buffer");
cb63cf9e
JB
144 pt->write_pos = pt->write_buf;
145 pt->write_buf_size = write_size;
146 }
147 else
148 {
149 pt->write_buf = pt->write_pos = &pt->shortbuf;
150 pt->write_buf_size = 1;
151 }
152
153 pt->write_end = pt->write_buf + pt->write_buf_size;
154 if (read_size > 0 || write_size > 0)
54778cd3 155 SCM_SET_CELL_WORD_0 (port, SCM_CELL_WORD_0 (port) & ~SCM_BUF0);
cb63cf9e 156 else
54778cd3 157 SCM_SET_CELL_WORD_0 (port, SCM_CELL_WORD_0 (port) | SCM_BUF0);
7a6f1ffa 158}
c6c79933 159#undef FUNC_NAME
7a6f1ffa 160
a1ec6916 161SCM_DEFINE (scm_setvbuf, "setvbuf", 2, 1, 0,
1bbd0b84 162 (SCM port, SCM mode, SCM size),
fc0d72d4
MD
163 "Set the buffering mode for @var{port}. @var{mode} can be:\n"
164 "@table @code\n"
165 "@item _IONBF\n"
166 "non-buffered\n"
167 "@item _IOLBF\n"
168 "line buffered\n"
169 "@item _IOFBF\n"
170 "block buffered, using a newly allocated buffer of @var{size} bytes.\n"
171 "If @var{size} is omitted, a default size will be used.\n"
2c1ae20e 172 "@end table")
1bbd0b84 173#define FUNC_NAME s_scm_setvbuf
7a6f1ffa 174{
1be6b49c 175 int cmode;
c014a02e 176 long csize;
e8b21eec
LC
177 size_t ndrained;
178 char *drained;
92c2555f 179 scm_t_port *pt;
7a6f1ffa 180
78446828
MV
181 port = SCM_COERCE_OUTPORT (port);
182
3b3b36dd 183 SCM_VALIDATE_OPFPORT (1,port);
a55c2b68 184 cmode = scm_to_int (mode);
d3639214 185 if (cmode != _IONBF && cmode != _IOFBF && cmode != _IOLBF)
1bbd0b84 186 scm_out_of_range (FUNC_NAME, mode);
d3639214
GH
187
188 if (cmode == _IOLBF)
189 {
54778cd3 190 SCM_SET_CELL_WORD_0 (port, SCM_CELL_WORD_0 (port) | SCM_BUFLINE);
d3639214
GH
191 cmode = _IOFBF;
192 }
193 else
194 {
2b829bbb 195 SCM_SET_CELL_WORD_0 (port, SCM_CELL_WORD_0 (port) & ~(scm_t_bits)SCM_BUFLINE);
d3639214
GH
196 }
197
7a6f1ffa 198 if (SCM_UNBNDP (size))
cb63cf9e
JB
199 {
200 if (cmode == _IOFBF)
201 csize = -1;
202 else
203 csize = 0;
204 }
7a6f1ffa
GH
205 else
206 {
a55c2b68 207 csize = scm_to_int (size);
cb63cf9e 208 if (csize < 0 || (cmode == _IONBF && csize > 0))
1bbd0b84 209 scm_out_of_range (FUNC_NAME, size);
7a6f1ffa 210 }
d3639214 211
cb63cf9e 212 pt = SCM_PTAB_ENTRY (port);
7a6f1ffa 213
67a72dc1 214 if (SCM_INPUT_PORT_P (port))
e8b21eec
LC
215 {
216 /* Drain pending input from PORT. Don't use `scm_drain_input' since
217 it returns a string, whereas we want binary input here. */
218 ndrained = pt->read_end - pt->read_pos;
219 if (pt->read_buf == pt->putback_buf)
220 ndrained += pt->saved_read_end - pt->saved_read_pos;
221
222 if (ndrained > 0)
223 {
224 drained = scm_gc_malloc_pointerless (ndrained, "file port");
225 scm_take_from_input_buffers (port, drained, ndrained);
226 }
227 }
67a72dc1 228 else
e8b21eec 229 ndrained = 0;
67a72dc1
AW
230
231 if (SCM_OUTPUT_PORT_P (port))
232 scm_flush (port);
233
4c9419ac
MV
234 if (pt->read_buf == pt->putback_buf)
235 {
236 pt->read_buf = pt->saved_read_buf;
237 pt->read_pos = pt->saved_read_pos;
238 pt->read_end = pt->saved_read_end;
239 pt->read_buf_size = pt->saved_read_buf_size;
240 }
cb63cf9e 241 if (pt->read_buf != &pt->shortbuf)
4c9419ac 242 scm_gc_free (pt->read_buf, pt->read_buf_size, "port buffer");
cb63cf9e 243 if (pt->write_buf != &pt->shortbuf)
4c9419ac 244 scm_gc_free (pt->write_buf, pt->write_buf_size, "port buffer");
7a6f1ffa 245
cb63cf9e 246 scm_fport_buffer_add (port, csize, csize);
67a72dc1 247
e8b21eec
LC
248 if (ndrained > 0)
249 /* Put DRAINED back to PORT. */
250 while (ndrained-- > 0)
251 scm_unget_byte (drained[ndrained], port);
67a72dc1 252
cb63cf9e 253 return SCM_UNSPECIFIED;
0f2d19dd 254}
1bbd0b84 255#undef FUNC_NAME
0f2d19dd 256
eadd48de 257/* Move ports with the specified file descriptor to new descriptors,
387d418c 258 * resetting the revealed count to 0.
0f2d19dd 259 */
ee834df4
LC
260static void
261scm_i_evict_port (void *closure, SCM port)
0f2d19dd 262{
5dbc6c06 263 int fd = * (int*) closure;
0f2d19dd 264
5dbc6c06 265 if (SCM_FPORTP (port))
eadd48de 266 {
e9d8bc25
LC
267 scm_t_port *p;
268 scm_t_fport *fp;
269
270 /* XXX: In some cases, we can encounter a port with no associated ptab
271 entry. */
272 p = SCM_PTAB_ENTRY (port);
273 fp = (p != NULL) ? (scm_t_fport *) p->stream : NULL;
cb63cf9e 274
e9d8bc25 275 if ((fp != NULL) && (fp->fdes == fd))
eadd48de 276 {
5dbc6c06
HWN
277 fp->fdes = dup (fd);
278 if (fp->fdes == -1)
279 scm_syserror ("scm_evict_ports");
280 scm_set_port_revealed_x (port, scm_from_int (0));
eadd48de
GH
281 }
282 }
5dbc6c06
HWN
283}
284
285void
286scm_evict_ports (int fd)
287{
ee834df4 288 scm_c_port_for_each (scm_i_evict_port, (void *) &fd);
eadd48de 289}
0f2d19dd 290
efa40607
DH
291
292SCM_DEFINE (scm_file_port_p, "file-port?", 1, 0, 0,
293 (SCM obj),
2069af38 294 "Determine whether @var{obj} is a port that is related to a file.")
efa40607
DH
295#define FUNC_NAME s_scm_file_port_p
296{
7888309b 297 return scm_from_bool (SCM_FPORTP (obj));
efa40607
DH
298}
299#undef FUNC_NAME
300
301
69cac238 302static SCM sys_file_port_name_canonicalization;
0157a341
AW
303SCM_SYMBOL (sym_relative, "relative");
304SCM_SYMBOL (sym_absolute, "absolute");
305
306static SCM
307fport_canonicalize_filename (SCM filename)
308{
69cac238
AW
309 SCM mode = scm_fluid_ref (sys_file_port_name_canonicalization);
310
0157a341
AW
311 if (!scm_is_string (filename))
312 {
313 return filename;
314 }
69cac238 315 else if (scm_is_eq (mode, sym_relative))
0157a341 316 {
22457d57
AW
317 SCM path, rel;
318
319 path = scm_variable_ref (scm_c_module_lookup (scm_the_root_module (),
320 "%load-path"));
321 rel = scm_i_relativize_path (filename, path);
322
323 return scm_is_true (rel) ? rel : filename;
0157a341 324 }
69cac238 325 else if (scm_is_eq (mode, sym_absolute))
0157a341
AW
326 {
327 char *str, *canon;
328
329 str = scm_to_locale_string (filename);
330 canon = canonicalize_file_name (str);
331 free (str);
332
333 return canon ? scm_take_locale_string (canon) : filename;
334 }
335 else
336 {
337 return filename;
338 }
339}
340
341
0f2d19dd
JB
342/* scm_open_file
343 * Return a new port open on a given file.
344 *
345 * The mode string must match the pattern: [rwa+]** which
346 * is interpreted in the usual unix way.
347 *
348 * Return the new port.
349 */
3b3b36dd 350SCM_DEFINE (scm_open_file, "open-file", 2, 0, 0,
211683cc 351 (SCM filename, SCM mode),
1e6808ea 352 "Open the file whose name is @var{filename}, and return a port\n"
fc0d72d4 353 "representing that file. The attributes of the port are\n"
1e6808ea
MG
354 "determined by the @var{mode} string. The way in which this is\n"
355 "interpreted is similar to C stdio. The first character must be\n"
356 "one of the following:\n"
fc0d72d4
MD
357 "@table @samp\n"
358 "@item r\n"
359 "Open an existing file for input.\n"
360 "@item w\n"
361 "Open a file for output, creating it if it doesn't already exist\n"
362 "or removing its contents if it does.\n"
363 "@item a\n"
1e6808ea
MG
364 "Open a file for output, creating it if it doesn't already\n"
365 "exist. All writes to the port will go to the end of the file.\n"
fc0d72d4
MD
366 "The \"append mode\" can be turned off while the port is in use\n"
367 "@pxref{Ports and File Descriptors, fcntl}\n"
1e6808ea
MG
368 "@end table\n"
369 "The following additional characters can be appended:\n"
fc0d72d4 370 "@table @samp\n"
fc9c5d06 371 "@item b\n"
211683cc
MG
372 "Open the underlying file in binary mode, if supported by the system.\n"
373 "Also, open the file using the binary-compatible character encoding\n"
374 "\"ISO-8859-1\", ignoring the port's encoding and the coding declaration\n"
375 "at the top of the input file, if any.\n"
fc0d72d4
MD
376 "@item +\n"
377 "Open the port for both input and output. E.g., @code{r+}: open\n"
378 "an existing file for both input and output.\n"
379 "@item 0\n"
1e6808ea
MG
380 "Create an \"unbuffered\" port. In this case input and output\n"
381 "operations are passed directly to the underlying port\n"
382 "implementation without additional buffering. This is likely to\n"
383 "slow down I/O operations. The buffering mode can be changed\n"
384 "while a port is in use @pxref{Ports and File Descriptors,\n"
385 "setvbuf}\n"
fc0d72d4
MD
386 "@item l\n"
387 "Add line-buffering to the port. The port output buffer will be\n"
388 "automatically flushed whenever a newline character is written.\n"
1e6808ea 389 "@end table\n"
211683cc
MG
390 "When the file is opened, this procedure will scan for a coding\n"
391 "declaration@pxref{Character Encoding of Source Files}. If present\n"
392 "will use that encoding for interpreting the file. Otherwise, the\n"
393 "port's encoding will be used.\n"
394 "\n"
1e6808ea
MG
395 "In theory we could create read/write ports which were buffered\n"
396 "in one direction only. However this isn't included in the\n"
397 "current interfaces. If a file cannot be opened with the access\n"
398 "requested, @code{open-file} throws an exception.")
1bbd0b84 399#define FUNC_NAME s_scm_open_file
0f2d19dd 400{
19639113 401 SCM port;
419c8736 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':
419c8736 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
419c8736
AW
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
211683cc
MG
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;
92c2555f 553 scm_t_port *pt;
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
9de87eea 572 scm_i_scm_pthread_mutex_lock (&scm_i_port_table_mutex);
da220f27
HWN
573
574 port = scm_new_port_table_entry (scm_tc16_fport);
575 SCM_SET_CELL_TYPE(port, scm_tc16_fport | mode_bits);
576 pt = SCM_PTAB_ENTRY(port);
a089567e 577 {
92c2555f 578 scm_t_fport *fp
92d8fd32
LC
579 = (scm_t_fport *) scm_gc_malloc_pointerless (sizeof (scm_t_fport),
580 "file port");
c6c79933 581
cb63cf9e 582 fp->fdes = fdes;
0de97b83 583 pt->rw_random = SCM_FDES_RANDOM_P (fdes);
cb63cf9e
JB
584 SCM_SETSTREAM (port, fp);
585 if (mode_bits & SCM_BUF0)
586 scm_fport_buffer_add (port, 0, 0);
587 else
588 scm_fport_buffer_add (port, -1, -1);
a089567e 589 }
b24b5e13 590 SCM_SET_FILENAME (port, name);
9de87eea 591 scm_i_pthread_mutex_unlock (&scm_i_port_table_mutex);
e145dd02
JB
592 return port;
593}
19b27fa2 594#undef FUNC_NAME
e145dd02 595
d617ee18
MV
596SCM
597scm_fdes_to_port (int fdes, char *mode, SCM name)
598{
599 return scm_i_fdes_to_port (fdes, scm_mode_bits (mode), name);
600}
601
affc96b5 602/* Return a lower bound on the number of bytes available for input. */
cb63cf9e 603static int
affc96b5 604fport_input_waiting (SCM port)
e145dd02 605{
23f2b9a3 606 int fdes = SCM_FSTREAM (port)->fdes;
c7519da3
CC
607
608 /* `FD_SETSIZE', which is 1024 on GNU systems, effectively limits the
609 highest numerical value of file descriptors that can be monitored.
610 Thus, use poll(2) whenever that is possible. */
611
4c187d46 612#if defined(HAVE_POLL) && defined(HAVE_STRUCT_POLLFD)
c7519da3
CC
613 struct pollfd pollfd = { fdes, POLLIN, 0 };
614
615 if (poll (&pollfd, 1, 0) < 0)
616 scm_syserror ("fport_input_waiting");
617
618 return pollfd.revents & POLLIN ? 1 : 0;
619
620#elif defined(HAVE_SELECT)
cb63cf9e
JB
621 struct timeval timeout;
622 SELECT_TYPE read_set;
623 SELECT_TYPE write_set;
624 SELECT_TYPE except_set;
625
626 FD_ZERO (&read_set);
627 FD_ZERO (&write_set);
628 FD_ZERO (&except_set);
629
630 FD_SET (fdes, &read_set);
631
632 timeout.tv_sec = 0;
633 timeout.tv_usec = 0;
634
635 if (select (SELECT_SET_SIZE,
636 &read_set, &write_set, &except_set, &timeout)
637 < 0)
affc96b5
GH
638 scm_syserror ("fport_input_waiting");
639 return FD_ISSET (fdes, &read_set) ? 1 : 0;
23f2b9a3
KR
640
641#elif HAVE_IOCTL && defined (FIONREAD)
642 /* Note: cannot test just defined(FIONREAD) here, since mingw has FIONREAD
643 (for use with winsock ioctlsocket()) but not ioctl(). */
644 int fdes = SCM_FSTREAM (port)->fdes;
cb63cf9e
JB
645 int remir;
646 ioctl(fdes, FIONREAD, &remir);
647 return remir;
23f2b9a3 648
cb63cf9e 649#else
affc96b5 650 scm_misc_error ("fport_input_waiting",
cb63cf9e
JB
651 "Not fully implemented on this platform",
652 SCM_EOL);
653#endif
a089567e
JB
654}
655
cb63cf9e 656\f
0f2d19dd 657static int
e81d98ec 658fport_print (SCM exp, SCM port, scm_print_state *pstate SCM_UNUSED)
0f2d19dd 659{
b3ec3c64
MD
660 scm_puts ("#<", port);
661 scm_print_port_mode (exp, port);
662 if (SCM_OPFPORTP (exp))
0f2d19dd 663 {
b3ec3c64 664 int fdes;
b24b5e13 665 SCM name = SCM_FILENAME (exp);
cc95e00a 666 if (scm_is_string (name) || scm_is_symbol (name))
b24b5e13
DH
667 scm_display (name, port);
668 else
669 scm_puts (SCM_PTOBNAME (SCM_PTOBNUM (exp)), port);
b3ec3c64
MD
670 scm_putc (' ', port);
671 fdes = (SCM_FSTREAM (exp))->fdes;
073167ef
LC
672
673#if (defined HAVE_TTYNAME) && (defined HAVE_POSIX)
b3ec3c64 674 if (isatty (fdes))
eb372585 675 scm_display (scm_ttyname (exp), port);
b3ec3c64 676 else
82893676 677#endif /* HAVE_TTYNAME */
b3ec3c64 678 scm_intprint (fdes, 10, port);
0f2d19dd
JB
679 }
680 else
681 {
b3ec3c64
MD
682 scm_puts (SCM_PTOBNAME (SCM_PTOBNUM (exp)), port);
683 scm_putc (' ', port);
0345e278 684 scm_uintprint ((scm_t_bits) SCM_PTAB_ENTRY (exp), 16, port);
0f2d19dd 685 }
b3ec3c64
MD
686 scm_putc ('>', port);
687 return 1;
0f2d19dd
JB
688}
689
affc96b5 690static void fport_flush (SCM port);
0f2d19dd 691
c2da2648
GH
692/* fill a port's read-buffer with a single read. returns the first
693 char or EOF if end of file. */
889975e5 694static scm_t_wchar
affc96b5 695fport_fill_input (SCM port)
0f2d19dd 696{
c014a02e 697 long count;
92c2555f
MV
698 scm_t_port *pt = SCM_PTAB_ENTRY (port);
699 scm_t_fport *fp = SCM_FSTREAM (port);
cb63cf9e 700
cb63cf9e
JB
701 SCM_SYSCALL (count = read (fp->fdes, pt->read_buf, pt->read_buf_size));
702 if (count == -1)
affc96b5 703 scm_syserror ("fport_fill_input");
cb63cf9e 704 if (count == 0)
889975e5 705 return (scm_t_wchar) EOF;
cb63cf9e
JB
706 else
707 {
5c070ca7 708 pt->read_pos = pt->read_buf;
cb63cf9e 709 pt->read_end = pt->read_buf + count;
5c070ca7 710 return *pt->read_buf;
cb63cf9e 711 }
0f2d19dd
JB
712}
713
0a94eb00
LC
714static scm_t_off
715fport_seek (SCM port, scm_t_off offset, int whence)
0f2d19dd 716{
92c2555f
MV
717 scm_t_port *pt = SCM_PTAB_ENTRY (port);
718 scm_t_fport *fp = SCM_FSTREAM (port);
8ab3d8a0
KR
719 off_t_or_off64_t rv;
720 off_t_or_off64_t result;
7dcb364d
GH
721
722 if (pt->rw_active == SCM_PORT_WRITE)
723 {
724 if (offset != 0 || whence != SEEK_CUR)
725 {
726 fport_flush (port);
8ab3d8a0 727 result = rv = lseek_or_lseek64 (fp->fdes, offset, whence);
7dcb364d
GH
728 }
729 else
730 {
731 /* read current position without disturbing the buffer. */
8ab3d8a0 732 rv = lseek_or_lseek64 (fp->fdes, offset, whence);
7dcb364d
GH
733 result = rv + (pt->write_pos - pt->write_buf);
734 }
735 }
736 else if (pt->rw_active == SCM_PORT_READ)
737 {
738 if (offset != 0 || whence != SEEK_CUR)
739 {
740 /* could expand to avoid a second seek. */
741 scm_end_input (port);
8ab3d8a0 742 result = rv = lseek_or_lseek64 (fp->fdes, offset, whence);
7dcb364d
GH
743 }
744 else
745 {
746 /* read current position without disturbing the buffer
747 (particularly the unread-char buffer). */
8ab3d8a0 748 rv = lseek_or_lseek64 (fp->fdes, offset, whence);
7dcb364d
GH
749 result = rv - (pt->read_end - pt->read_pos);
750
751 if (pt->read_buf == pt->putback_buf)
752 result -= pt->saved_read_end - pt->saved_read_pos;
753 }
754 }
755 else /* SCM_PORT_NEITHER */
756 {
8ab3d8a0 757 result = rv = lseek_or_lseek64 (fp->fdes, offset, whence);
7dcb364d 758 }
cb8dfa3f 759
7dcb364d 760 if (rv == -1)
affc96b5 761 scm_syserror ("fport_seek");
7dcb364d 762
cb8dfa3f 763 return result;
0f2d19dd
JB
764}
765
840ae05d 766static void
f1ce9199 767fport_truncate (SCM port, scm_t_off length)
840ae05d 768{
92c2555f 769 scm_t_fport *fp = SCM_FSTREAM (port);
840ae05d
JB
770
771 if (ftruncate (fp->fdes, length) == -1)
772 scm_syserror ("ftruncate");
773}
774
31703ab8 775static void
8aa011a1 776fport_write (SCM port, const void *data, size_t size)
daa4a3f1 777#define FUNC_NAME "fport_write"
31703ab8 778{
0c6d2191 779 /* this procedure tries to minimize the number of writes/flushes. */
92c2555f 780 scm_t_port *pt = SCM_PTAB_ENTRY (port);
31703ab8 781
0c6d2191
GH
782 if (pt->write_buf == &pt->shortbuf
783 || (pt->write_pos == pt->write_buf && size >= pt->write_buf_size))
31703ab8 784 {
daa4a3f1
LC
785 /* Unbuffered port, or port with empty buffer and data won't fit in
786 buffer. */
787 if (full_write (SCM_FPORT_FDES (port), data, size) < size)
788 SCM_SYSERROR;
789
0c6d2191 790 return;
31703ab8 791 }
d3639214 792
0c6d2191 793 {
f1ce9199 794 scm_t_off space = pt->write_end - pt->write_pos;
0c6d2191
GH
795
796 if (size <= space)
797 {
798 /* data fits in buffer. */
799 memcpy (pt->write_pos, data, size);
800 pt->write_pos += size;
801 if (pt->write_pos == pt->write_end)
802 {
affc96b5 803 fport_flush (port);
0c6d2191
GH
804 /* we can skip the line-buffering check if nothing's buffered. */
805 return;
806 }
807 }
808 else
809 {
810 memcpy (pt->write_pos, data, space);
811 pt->write_pos = pt->write_end;
812 fport_flush (port);
813 {
814 const void *ptr = ((const char *) data) + space;
815 size_t remaining = size - space;
816
817 if (size >= pt->write_buf_size)
818 {
daa4a3f1
LC
819 if (full_write (SCM_FPORT_FDES (port), ptr, remaining)
820 < remaining)
821 SCM_SYSERROR;
0c6d2191
GH
822 return;
823 }
824 else
825 {
826 memcpy (pt->write_pos, ptr, remaining);
827 pt->write_pos += remaining;
828 }
31703ab8 829 }
0c6d2191 830 }
31703ab8 831
0c6d2191
GH
832 /* handle line buffering. */
833 if ((SCM_CELL_WORD_0 (port) & SCM_BUFLINE) && memchr (data, '\n', size))
834 fport_flush (port);
835 }
31703ab8 836}
daa4a3f1 837#undef FUNC_NAME
31703ab8 838
cb63cf9e 839static void
affc96b5 840fport_flush (SCM port)
0f2d19dd 841{
5335850d 842 size_t written;
92c2555f
MV
843 scm_t_port *pt = SCM_PTAB_ENTRY (port);
844 scm_t_fport *fp = SCM_FSTREAM (port);
5335850d 845 size_t count = pt->write_pos - pt->write_buf;
cb63cf9e 846
5335850d
LC
847 written = full_write (fp->fdes, pt->write_buf, count);
848 if (written < count)
849 scm_syserror ("scm_flush");
cb63cf9e 850
cb63cf9e 851 pt->write_pos = pt->write_buf;
61e452ba 852 pt->rw_active = SCM_PORT_NEITHER;
840ae05d
JB
853}
854
283a1a0e 855/* clear the read buffer and adjust the file position for unread bytes. */
840ae05d 856static void
affc96b5 857fport_end_input (SCM port, int offset)
840ae05d 858{
92c2555f
MV
859 scm_t_fport *fp = SCM_FSTREAM (port);
860 scm_t_port *pt = SCM_PTAB_ENTRY (port);
283a1a0e
GH
861
862 offset += pt->read_end - pt->read_pos;
840ae05d 863
840ae05d
JB
864 if (offset > 0)
865 {
866 pt->read_pos = pt->read_end;
867 /* will throw error if unread-char used at beginning of file
868 then attempting to write. seems correct. */
869 if (lseek (fp->fdes, -offset, SEEK_CUR) == -1)
affc96b5 870 scm_syserror ("fport_end_input");
840ae05d 871 }
61e452ba 872 pt->rw_active = SCM_PORT_NEITHER;
8f29fbd0
JB
873}
874
6a2c4c81 875static int
affc96b5 876fport_close (SCM port)
6a2c4c81 877{
92c2555f
MV
878 scm_t_fport *fp = SCM_FSTREAM (port);
879 scm_t_port *pt = SCM_PTAB_ENTRY (port);
cb63cf9e 880 int rv;
840ae05d 881
affc96b5 882 fport_flush (port);
cb63cf9e
JB
883 SCM_SYSCALL (rv = close (fp->fdes));
884 if (rv == -1 && errno != EBADF)
6b72ac1d
GH
885 {
886 if (scm_gc_running_p)
887 /* silently ignore the error. scm_error would abort if we
888 called it now. */
889 ;
890 else
891 scm_syserror ("fport_close");
892 }
6c951427
GH
893 if (pt->read_buf == pt->putback_buf)
894 pt->read_buf = pt->saved_read_buf;
cb63cf9e 895 if (pt->read_buf != &pt->shortbuf)
4c9419ac 896 scm_gc_free (pt->read_buf, pt->read_buf_size, "port buffer");
cb63cf9e 897 if (pt->write_buf != &pt->shortbuf)
4c9419ac
MV
898 scm_gc_free (pt->write_buf, pt->write_buf_size, "port buffer");
899 scm_gc_free (fp, sizeof (*fp), "file port");
cb63cf9e 900 return rv;
6a2c4c81
JB
901}
902
1be6b49c 903static size_t
affc96b5 904fport_free (SCM port)
b3ec3c64 905{
affc96b5 906 fport_close (port);
b3ec3c64
MD
907 return 0;
908}
909
92c2555f 910static scm_t_bits
b3ec3c64
MD
911scm_make_fptob ()
912{
92c2555f 913 scm_t_bits tc = scm_make_port_type ("file", fport_fill_input, fport_write);
a98bddfd 914
affc96b5 915 scm_set_port_free (tc, fport_free);
e841c3e0 916 scm_set_port_print (tc, fport_print);
affc96b5
GH
917 scm_set_port_flush (tc, fport_flush);
918 scm_set_port_end_input (tc, fport_end_input);
919 scm_set_port_close (tc, fport_close);
920 scm_set_port_seek (tc, fport_seek);
921 scm_set_port_truncate (tc, fport_truncate);
922 scm_set_port_input_waiting (tc, fport_input_waiting);
a98bddfd
DH
923
924 return tc;
b3ec3c64 925}
0f2d19dd 926
0f2d19dd
JB
927void
928scm_init_fports ()
0f2d19dd 929{
a98bddfd
DH
930 scm_tc16_fport = scm_make_fptob ();
931
e11e83f3
MV
932 scm_c_define ("_IOFBF", scm_from_int (_IOFBF));
933 scm_c_define ("_IOLBF", scm_from_int (_IOLBF));
934 scm_c_define ("_IONBF", scm_from_int (_IONBF));
a98bddfd 935
69cac238
AW
936 sys_file_port_name_canonicalization = scm_make_fluid ();
937 scm_c_define ("%file-port-name-canonicalization",
938 sys_file_port_name_canonicalization);
939
a98bddfd 940#include "libguile/fports.x"
0f2d19dd 941}
89e00824
ML
942
943/*
944 Local Variables:
945 c-file-style: "gnu"
946 End:
947*/