("scm_new_port_table_entry"): return a boxed SCM in
[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"
edb810bb
SJ
72
73/* Some defines for Windows (native port, not Cygwin). */
82893676
MG
74#ifdef __MINGW32__
75# include <sys/stat.h>
76# include <winsock2.h>
77# define ftruncate(fd, size) chsize (fd, size)
78#endif /* __MINGW32__ */
cb63cf9e 79
a98bddfd 80
92c2555f 81scm_t_bits scm_tc16_fport;
a98bddfd
DH
82
83
19b27fa2 84/* default buffer size, used if the O/S won't supply a value. */
1be6b49c 85static const size_t default_buffer_size = 1024;
19b27fa2 86
cb63cf9e
JB
87/* create FPORT buffer with specified sizes (or -1 to use default size or
88 0 for no buffer. */
89static void
c014a02e 90scm_fport_buffer_add (SCM port, long read_size, int write_size)
c6c79933 91#define FUNC_NAME "scm_fport_buffer_add"
e145dd02 92{
92c2555f 93 scm_t_port *pt = SCM_PTAB_ENTRY (port);
e145dd02 94
cb63cf9e
JB
95 if (read_size == -1 || write_size == -1)
96 {
1be6b49c 97 size_t default_size;
f47a5239 98#ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
cb63cf9e 99 struct stat st;
b8b17bfd 100 scm_t_fport *fp = SCM_FSTREAM (port);
cb63cf9e 101
19b27fa2
GH
102 default_size = (fstat (fp->fdes, &st) == -1) ? default_buffer_size
103 : st.st_blksize;
cb63cf9e 104#else
19b27fa2 105 default_size = default_buffer_size;
cb63cf9e
JB
106#endif
107 if (read_size == -1)
108 read_size = default_size;
109 if (write_size == -1)
110 write_size = default_size;
111 }
0f2d19dd 112
f5f2dcff 113 if (SCM_INPUT_PORT_P (port) && read_size > 0)
cb63cf9e 114 {
4c9419ac 115 pt->read_buf = scm_gc_malloc (read_size, "port buffer");
cb63cf9e
JB
116 pt->read_pos = pt->read_end = pt->read_buf;
117 pt->read_buf_size = read_size;
118 }
119 else
120 {
840ae05d 121 pt->read_pos = pt->read_buf = pt->read_end = &pt->shortbuf;
cb63cf9e
JB
122 pt->read_buf_size = 1;
123 }
1717856b 124
f5f2dcff 125 if (SCM_OUTPUT_PORT_P (port) && write_size > 0)
cb63cf9e 126 {
4c9419ac 127 pt->write_buf = scm_gc_malloc (write_size, "port buffer");
cb63cf9e
JB
128 pt->write_pos = pt->write_buf;
129 pt->write_buf_size = write_size;
130 }
131 else
132 {
133 pt->write_buf = pt->write_pos = &pt->shortbuf;
134 pt->write_buf_size = 1;
135 }
136
137 pt->write_end = pt->write_buf + pt->write_buf_size;
138 if (read_size > 0 || write_size > 0)
54778cd3 139 SCM_SET_CELL_WORD_0 (port, SCM_CELL_WORD_0 (port) & ~SCM_BUF0);
cb63cf9e 140 else
54778cd3 141 SCM_SET_CELL_WORD_0 (port, SCM_CELL_WORD_0 (port) | SCM_BUF0);
7a6f1ffa 142}
c6c79933 143#undef FUNC_NAME
7a6f1ffa 144
a1ec6916 145SCM_DEFINE (scm_setvbuf, "setvbuf", 2, 1, 0,
1bbd0b84 146 (SCM port, SCM mode, SCM size),
fc0d72d4
MD
147 "Set the buffering mode for @var{port}. @var{mode} can be:\n"
148 "@table @code\n"
149 "@item _IONBF\n"
150 "non-buffered\n"
151 "@item _IOLBF\n"
152 "line buffered\n"
153 "@item _IOFBF\n"
154 "block buffered, using a newly allocated buffer of @var{size} bytes.\n"
155 "If @var{size} is omitted, a default size will be used.\n"
2c1ae20e 156 "@end table")
1bbd0b84 157#define FUNC_NAME s_scm_setvbuf
7a6f1ffa 158{
1be6b49c 159 int cmode;
c014a02e 160 long csize;
92c2555f 161 scm_t_port *pt;
7a6f1ffa 162
78446828
MV
163 port = SCM_COERCE_OUTPORT (port);
164
3b3b36dd
GB
165 SCM_VALIDATE_OPFPORT (1,port);
166 SCM_VALIDATE_INUM_COPY (2,mode,cmode);
d3639214 167 if (cmode != _IONBF && cmode != _IOFBF && cmode != _IOLBF)
1bbd0b84 168 scm_out_of_range (FUNC_NAME, mode);
d3639214
GH
169
170 if (cmode == _IOLBF)
171 {
54778cd3 172 SCM_SET_CELL_WORD_0 (port, SCM_CELL_WORD_0 (port) | SCM_BUFLINE);
d3639214
GH
173 cmode = _IOFBF;
174 }
175 else
176 {
54778cd3 177 SCM_SET_CELL_WORD_0 (port, SCM_CELL_WORD_0 (port) ^ SCM_BUFLINE);
d3639214
GH
178 }
179
7a6f1ffa 180 if (SCM_UNBNDP (size))
cb63cf9e
JB
181 {
182 if (cmode == _IOFBF)
183 csize = -1;
184 else
185 csize = 0;
186 }
7a6f1ffa
GH
187 else
188 {
3b3b36dd 189 SCM_VALIDATE_INUM_COPY (3,size,csize);
cb63cf9e 190 if (csize < 0 || (cmode == _IONBF && csize > 0))
1bbd0b84 191 scm_out_of_range (FUNC_NAME, size);
7a6f1ffa 192 }
d3639214 193
cb63cf9e 194 pt = SCM_PTAB_ENTRY (port);
7a6f1ffa 195
4c9419ac
MV
196 /* silently discards buffered and put-back chars. */
197 if (pt->read_buf == pt->putback_buf)
198 {
199 pt->read_buf = pt->saved_read_buf;
200 pt->read_pos = pt->saved_read_pos;
201 pt->read_end = pt->saved_read_end;
202 pt->read_buf_size = pt->saved_read_buf_size;
203 }
cb63cf9e 204 if (pt->read_buf != &pt->shortbuf)
4c9419ac 205 scm_gc_free (pt->read_buf, pt->read_buf_size, "port buffer");
cb63cf9e 206 if (pt->write_buf != &pt->shortbuf)
4c9419ac 207 scm_gc_free (pt->write_buf, pt->write_buf_size, "port buffer");
7a6f1ffa 208
cb63cf9e
JB
209 scm_fport_buffer_add (port, csize, csize);
210 return SCM_UNSPECIFIED;
0f2d19dd 211}
1bbd0b84 212#undef FUNC_NAME
0f2d19dd 213
eadd48de 214/* Move ports with the specified file descriptor to new descriptors,
387d418c 215 * resetting the revealed count to 0.
0f2d19dd 216 */
1717856b 217
eadd48de 218void
6e8d25a6 219scm_evict_ports (int fd)
0f2d19dd 220{
c014a02e 221 long i;
0f2d19dd 222
f5fd8aa2 223 for (i = 0; i < scm_port_table_size; i++)
eadd48de 224 {
f5fd8aa2 225 SCM port = scm_port_table[i]->port;
cb63cf9e
JB
226
227 if (SCM_FPORTP (port))
eadd48de 228 {
92c2555f 229 scm_t_fport *fp = SCM_FSTREAM (port);
cb63cf9e
JB
230
231 if (fp->fdes == fd)
232 {
233 fp->fdes = dup (fd);
234 if (fp->fdes == -1)
235 scm_syserror ("scm_evict_ports");
236 scm_set_port_revealed_x (port, SCM_MAKINUM (0));
237 }
eadd48de
GH
238 }
239 }
240}
0f2d19dd 241
efa40607
DH
242
243SCM_DEFINE (scm_file_port_p, "file-port?", 1, 0, 0,
244 (SCM obj),
2069af38 245 "Determine whether @var{obj} is a port that is related to a file.")
efa40607
DH
246#define FUNC_NAME s_scm_file_port_p
247{
248 return SCM_BOOL (SCM_FPORTP (obj));
249}
250#undef FUNC_NAME
251
252
0f2d19dd
JB
253/* scm_open_file
254 * Return a new port open on a given file.
255 *
256 * The mode string must match the pattern: [rwa+]** which
257 * is interpreted in the usual unix way.
258 *
259 * Return the new port.
260 */
3b3b36dd 261SCM_DEFINE (scm_open_file, "open-file", 2, 0, 0,
1e6808ea
MG
262 (SCM filename, SCM mode),
263 "Open the file whose name is @var{filename}, and return a port\n"
fc0d72d4 264 "representing that file. The attributes of the port are\n"
1e6808ea
MG
265 "determined by the @var{mode} string. The way in which this is\n"
266 "interpreted is similar to C stdio. The first character must be\n"
267 "one of the following:\n"
fc0d72d4
MD
268 "@table @samp\n"
269 "@item r\n"
270 "Open an existing file for input.\n"
271 "@item w\n"
272 "Open a file for output, creating it if it doesn't already exist\n"
273 "or removing its contents if it does.\n"
274 "@item a\n"
1e6808ea
MG
275 "Open a file for output, creating it if it doesn't already\n"
276 "exist. All writes to the port will go to the end of the file.\n"
fc0d72d4
MD
277 "The \"append mode\" can be turned off while the port is in use\n"
278 "@pxref{Ports and File Descriptors, fcntl}\n"
1e6808ea
MG
279 "@end table\n"
280 "The following additional characters can be appended:\n"
fc0d72d4
MD
281 "@table @samp\n"
282 "@item +\n"
283 "Open the port for both input and output. E.g., @code{r+}: open\n"
284 "an existing file for both input and output.\n"
285 "@item 0\n"
1e6808ea
MG
286 "Create an \"unbuffered\" port. In this case input and output\n"
287 "operations are passed directly to the underlying port\n"
288 "implementation without additional buffering. This is likely to\n"
289 "slow down I/O operations. The buffering mode can be changed\n"
290 "while a port is in use @pxref{Ports and File Descriptors,\n"
291 "setvbuf}\n"
fc0d72d4
MD
292 "@item l\n"
293 "Add line-buffering to the port. The port output buffer will be\n"
294 "automatically flushed whenever a newline character is written.\n"
1e6808ea
MG
295 "@end table\n"
296 "In theory we could create read/write ports which were buffered\n"
297 "in one direction only. However this isn't included in the\n"
298 "current interfaces. If a file cannot be opened with the access\n"
299 "requested, @code{open-file} throws an exception.")
1bbd0b84 300#define FUNC_NAME s_scm_open_file
0f2d19dd 301{
19639113 302 SCM port;
cb63cf9e
JB
303 int fdes;
304 int flags = 0;
19639113 305 char *file;
1e6808ea 306 char *md;
cb63cf9e 307 char *ptr;
19639113 308
a6d9e5ab 309 SCM_VALIDATE_STRING (1, filename);
1e6808ea 310 SCM_VALIDATE_STRING (2, mode);
19639113 311
a6d9e5ab 312 file = SCM_STRING_CHARS (filename);
1e6808ea 313 md = SCM_STRING_CHARS (mode);
19639113 314
1e6808ea 315 switch (*md)
0f2d19dd 316 {
cb63cf9e
JB
317 case 'r':
318 flags |= O_RDONLY;
319 break;
320 case 'w':
321 flags |= O_WRONLY | O_CREAT | O_TRUNC;
322 break;
323 case 'a':
324 flags |= O_WRONLY | O_CREAT | O_APPEND;
325 break;
326 default:
1e6808ea 327 scm_out_of_range (FUNC_NAME, mode);
0f2d19dd 328 }
1e6808ea 329 ptr = md + 1;
cb63cf9e 330 while (*ptr != '\0')
e145dd02 331 {
cb63cf9e
JB
332 switch (*ptr)
333 {
334 case '+':
335 flags = (flags & ~(O_RDONLY | O_WRONLY)) | O_RDWR;
336 break;
9f561420
GH
337 case 'b':
338#if defined (O_BINARY)
339 flags |= O_BINARY;
340#endif
341 break;
cb63cf9e 342 case '0': /* unbuffered: handled later. */
d3639214 343 case 'l': /* line buffered: handled during output. */
cb63cf9e
JB
344 break;
345 default:
1e6808ea 346 scm_out_of_range (FUNC_NAME, mode);
cb63cf9e
JB
347 }
348 ptr++;
e145dd02 349 }
cb63cf9e
JB
350 SCM_SYSCALL (fdes = open (file, flags, 0666));
351 if (fdes == -1)
e145dd02 352 {
cb63cf9e
JB
353 int en = errno;
354
5d2d2ffc 355 SCM_SYSERROR_MSG ("~A: ~S",
cb63cf9e 356 scm_cons (scm_makfrom0str (strerror (en)),
5d2d2ffc 357 scm_cons (filename, SCM_EOL)), en);
0f2d19dd 358 }
1e6808ea 359 port = scm_fdes_to_port (fdes, md, filename);
0f2d19dd
JB
360 return port;
361}
1bbd0b84 362#undef FUNC_NAME
0f2d19dd 363
e145dd02 364\f
82893676
MG
365#ifdef __MINGW32__
366/*
367 * Try getting the appropiate file flags for a given file descriptor
368 * under Windows. This incorporates some fancy operations because Windows
369 * differentiates between file, pipe and socket descriptors.
370 */
371#ifndef O_ACCMODE
372# define O_ACCMODE 0x0003
373#endif
374
375static int getflags (int fdes)
376{
377 int flags = 0;
378 struct stat buf;
379 int error, optlen = sizeof (int);
380
381 /* Is this a socket ? */
382 if (getsockopt (fdes, SOL_SOCKET, SO_ERROR, (void *) &error, &optlen) >= 0)
383 flags = O_RDWR;
384 /* Maybe a regular file ? */
385 else if (fstat (fdes, &buf) < 0)
386 flags = -1;
387 else
388 {
389 /* Or an anonymous pipe handle ? */
b8b17bfd 390 if (buf.st_mode & _S_IFIFO)
8f99e3f3
SJ
391 flags = PeekNamedPipe ((HANDLE) _get_osfhandle (fdes), NULL, 0,
392 NULL, NULL, NULL) ? O_RDONLY : O_WRONLY;
82893676 393 /* stdin ? */
b8b17bfd 394 else if (fdes == fileno (stdin) && isatty (fdes))
82893676
MG
395 flags = O_RDONLY;
396 /* stdout / stderr ? */
b8b17bfd
MV
397 else if ((fdes == fileno (stdout) || fdes == fileno (stderr)) &&
398 isatty (fdes))
82893676
MG
399 flags = O_WRONLY;
400 else
401 flags = buf.st_mode;
402 }
403 return flags;
404}
405#endif /* __MINGW32__ */
406
cb63cf9e 407/* Building Guile ports from a file descriptor. */
e145dd02 408
cb63cf9e 409/* Build a Scheme port from an open file descriptor `fdes'.
a089567e
JB
410 MODE indicates whether FILE is open for reading or writing; it uses
411 the same notation as open-file's second argument.
19b27fa2
GH
412 NAME is a string to be used as the port's filename.
413*/
a089567e 414SCM
cb63cf9e 415scm_fdes_to_port (int fdes, char *mode, SCM name)
19b27fa2 416#define FUNC_NAME "scm_fdes_to_port"
a089567e
JB
417{
418 long mode_bits = scm_mode_bits (mode);
419 SCM port;
92c2555f 420 scm_t_port *pt;
19b27fa2
GH
421 int flags;
422
423 /* test that fdes is valid. */
82893676
MG
424#ifdef __MINGW32__
425 flags = getflags (fdes);
426#else
19b27fa2 427 flags = fcntl (fdes, F_GETFL, 0);
82893676 428#endif
19b27fa2
GH
429 if (flags == -1)
430 SCM_SYSERROR;
431 flags &= O_ACCMODE;
432 if (flags != O_RDWR
433 && ((flags != O_WRONLY && (mode_bits & SCM_WRTNG))
434 || (flags != O_RDONLY && (mode_bits & SCM_RDNG))))
435 {
436 SCM_MISC_ERROR ("requested file mode not available on fdes", SCM_EOL);
437 }
a089567e 438
a089567e 439 SCM_DEFER_INTS;
da220f27
HWN
440
441 port = scm_new_port_table_entry (scm_tc16_fport);
442 SCM_SET_CELL_TYPE(port, scm_tc16_fport | mode_bits);
443 pt = SCM_PTAB_ENTRY(port);
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. */
04a98cff 729extern int scm_i_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 }
04a98cff 761 if (scm_i_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 868
a98bddfd 869#include "libguile/fports.x"
0f2d19dd 870}
89e00824
ML
871
872/*
873 Local Variables:
874 c-file-style: "gnu"
875 End:
876*/