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