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