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