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