* guardians.c (guardian_print): for sharing guardians, print that
[bpt/guile.git] / libguile / fports.c
CommitLineData
f2c9fcb0 1/* Copyright (C) 1995,1996,1997,1998,1999, 2000 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
GB
41
42/* Software engineering face-lift by Greg J. Badros, 11-Dec-1999,
43 gjb@cs.washington.edu, http://www.cs.washington.edu/homes/gjb */
44
0f2d19dd
JB
45\f
46
47#include <stdio.h>
cb63cf9e 48#include <fcntl.h>
a0599745
MD
49#include "libguile/_scm.h"
50#include "libguile/strings.h"
a0599745 51#include "libguile/validate.h"
6b72ac1d
GH
52#include "libguile/gc.h"
53
a0599745 54#include "libguile/fports.h"
95b88819
GH
55
56#ifdef HAVE_STRING_H
57#include <string.h>
58#endif
0f2d19dd
JB
59#ifdef HAVE_UNISTD_H
60#include <unistd.h>
61#else
0f2d19dd
JB
62scm_sizet fwrite ();
63#endif
cb63cf9e
JB
64#ifdef HAVE_ST_BLKSIZE
65#include <sys/stat.h>
66#endif
0f2d19dd 67
cb63cf9e 68#include <errno.h>
e145dd02 69
a0599745 70#include "libguile/iselect.h"
cb63cf9e 71
19b27fa2
GH
72/* default buffer size, used if the O/S won't supply a value. */
73static const int default_buffer_size = 1024;
74
cb63cf9e
JB
75/* create FPORT buffer with specified sizes (or -1 to use default size or
76 0 for no buffer. */
77static void
78scm_fport_buffer_add (SCM port, int read_size, int write_size)
e145dd02 79{
cb63cf9e 80 struct scm_fport *fp = SCM_FSTREAM (port);
b24b5e13 81 scm_port *pt = SCM_PTAB_ENTRY (port);
cb63cf9e 82 char *s_scm_fport_buffer_add = "scm_fport_buffer_add";
e145dd02 83
cb63cf9e
JB
84 if (read_size == -1 || write_size == -1)
85 {
86 int default_size;
87#ifdef HAVE_ST_BLKSIZE
88 struct stat st;
89
19b27fa2
GH
90 default_size = (fstat (fp->fdes, &st) == -1) ? default_buffer_size
91 : st.st_blksize;
cb63cf9e 92#else
19b27fa2 93 default_size = default_buffer_size;
cb63cf9e
JB
94#endif
95 if (read_size == -1)
96 read_size = default_size;
97 if (write_size == -1)
98 write_size = default_size;
99 }
0f2d19dd 100
f5f2dcff 101 if (SCM_INPUT_PORT_P (port) && read_size > 0)
cb63cf9e 102 {
840ae05d
JB
103 pt->read_buf = malloc (read_size);
104 if (pt->read_buf == NULL)
105 scm_memory_error (s_scm_fport_buffer_add);
cb63cf9e
JB
106 pt->read_pos = pt->read_end = pt->read_buf;
107 pt->read_buf_size = read_size;
108 }
109 else
110 {
840ae05d 111 pt->read_pos = pt->read_buf = pt->read_end = &pt->shortbuf;
cb63cf9e
JB
112 pt->read_buf_size = 1;
113 }
1717856b 114
f5f2dcff 115 if (SCM_OUTPUT_PORT_P (port) && write_size > 0)
cb63cf9e 116 {
840ae05d
JB
117 pt->write_buf = malloc (write_size);
118 if (pt->write_buf == NULL)
119 scm_memory_error (s_scm_fport_buffer_add);
cb63cf9e
JB
120 pt->write_pos = pt->write_buf;
121 pt->write_buf_size = write_size;
122 }
123 else
124 {
125 pt->write_buf = pt->write_pos = &pt->shortbuf;
126 pt->write_buf_size = 1;
127 }
128
129 pt->write_end = pt->write_buf + pt->write_buf_size;
130 if (read_size > 0 || write_size > 0)
54778cd3 131 SCM_SET_CELL_WORD_0 (port, SCM_CELL_WORD_0 (port) & ~SCM_BUF0);
cb63cf9e 132 else
54778cd3 133 SCM_SET_CELL_WORD_0 (port, SCM_CELL_WORD_0 (port) | SCM_BUF0);
7a6f1ffa
GH
134}
135
a1ec6916 136SCM_DEFINE (scm_setvbuf, "setvbuf", 2, 1, 0,
1bbd0b84 137 (SCM port, SCM mode, SCM size),
fc0d72d4
MD
138 "Set the buffering mode for @var{port}. @var{mode} can be:\n"
139 "@table @code\n"
140 "@item _IONBF\n"
141 "non-buffered\n"
142 "@item _IOLBF\n"
143 "line buffered\n"
144 "@item _IOFBF\n"
145 "block buffered, using a newly allocated buffer of @var{size} bytes.\n"
146 "If @var{size} is omitted, a default size will be used.\n"
2c1ae20e 147 "@end table")
1bbd0b84 148#define FUNC_NAME s_scm_setvbuf
7a6f1ffa 149{
7a6f1ffa 150 int cmode, csize;
840ae05d 151 scm_port *pt;
7a6f1ffa 152
78446828
MV
153 port = SCM_COERCE_OUTPORT (port);
154
3b3b36dd
GB
155 SCM_VALIDATE_OPFPORT (1,port);
156 SCM_VALIDATE_INUM_COPY (2,mode,cmode);
d3639214 157 if (cmode != _IONBF && cmode != _IOFBF && cmode != _IOLBF)
1bbd0b84 158 scm_out_of_range (FUNC_NAME, mode);
d3639214
GH
159
160 if (cmode == _IOLBF)
161 {
54778cd3 162 SCM_SET_CELL_WORD_0 (port, SCM_CELL_WORD_0 (port) | SCM_BUFLINE);
d3639214
GH
163 cmode = _IOFBF;
164 }
165 else
166 {
54778cd3 167 SCM_SET_CELL_WORD_0 (port, SCM_CELL_WORD_0 (port) ^ SCM_BUFLINE);
d3639214
GH
168 }
169
7a6f1ffa 170 if (SCM_UNBNDP (size))
cb63cf9e
JB
171 {
172 if (cmode == _IOFBF)
173 csize = -1;
174 else
175 csize = 0;
176 }
7a6f1ffa
GH
177 else
178 {
3b3b36dd 179 SCM_VALIDATE_INUM_COPY (3,size,csize);
cb63cf9e 180 if (csize < 0 || (cmode == _IONBF && csize > 0))
1bbd0b84 181 scm_out_of_range (FUNC_NAME, size);
7a6f1ffa 182 }
d3639214 183
cb63cf9e 184 pt = SCM_PTAB_ENTRY (port);
7a6f1ffa 185
cb63cf9e
JB
186 /* silently discards buffered chars. */
187 if (pt->read_buf != &pt->shortbuf)
f30c9c8f 188 free (pt->read_buf);
cb63cf9e 189 if (pt->write_buf != &pt->shortbuf)
f30c9c8f 190 free (pt->write_buf);
7a6f1ffa 191
cb63cf9e
JB
192 scm_fport_buffer_add (port, csize, csize);
193 return SCM_UNSPECIFIED;
0f2d19dd 194}
1bbd0b84 195#undef FUNC_NAME
0f2d19dd 196
eadd48de
GH
197/* Move ports with the specified file descriptor to new descriptors,
198 * reseting the revealed count to 0.
0f2d19dd 199 */
1717856b 200
eadd48de 201void
6e8d25a6 202scm_evict_ports (int fd)
0f2d19dd 203{
eadd48de 204 int i;
0f2d19dd 205
eadd48de
GH
206 for (i = 0; i < scm_port_table_size; i++)
207 {
cb63cf9e
JB
208 SCM port = scm_port_table[i]->port;
209
210 if (SCM_FPORTP (port))
eadd48de 211 {
cb63cf9e
JB
212 struct scm_fport *fp = SCM_FSTREAM (port);
213
214 if (fp->fdes == fd)
215 {
216 fp->fdes = dup (fd);
217 if (fp->fdes == -1)
218 scm_syserror ("scm_evict_ports");
219 scm_set_port_revealed_x (port, SCM_MAKINUM (0));
220 }
eadd48de
GH
221 }
222 }
223}
0f2d19dd
JB
224
225/* scm_open_file
226 * Return a new port open on a given file.
227 *
228 * The mode string must match the pattern: [rwa+]** which
229 * is interpreted in the usual unix way.
230 *
231 * Return the new port.
232 */
3b3b36dd 233SCM_DEFINE (scm_open_file, "open-file", 2, 0, 0,
1bbd0b84 234 (SCM filename, SCM modes),
fc0d72d4
MD
235 "Open the file whose name is @var{string}, and return a port\n"
236 "representing that file. The attributes of the port are\n"
237 "determined by the @var{mode} string. The way in \n"
238 "which this is interpreted is similar to C stdio:\n\n"
239 "The first character must be one of the following:\n\n"
240 "@table @samp\n"
241 "@item r\n"
242 "Open an existing file for input.\n"
243 "@item w\n"
244 "Open a file for output, creating it if it doesn't already exist\n"
245 "or removing its contents if it does.\n"
246 "@item a\n"
247 "Open a file for output, creating it if it doesn't already exist.\n"
248 "All writes to the port will go to the end of the file.\n"
249 "The \"append mode\" can be turned off while the port is in use\n"
250 "@pxref{Ports and File Descriptors, fcntl}\n"
251 "@end table\n\n"
252 "The following additional characters can be appended:\n\n"
253 "@table @samp\n"
254 "@item +\n"
255 "Open the port for both input and output. E.g., @code{r+}: open\n"
256 "an existing file for both input and output.\n"
257 "@item 0\n"
258 "Create an \"unbuffered\" port. In this case input and output operations\n"
259 "are passed directly to the underlying port implementation without\n"
260 "additional buffering. This is likely to slow down I/O operations.\n"
261 "The buffering mode can be changed while a port is in use\n"
262 "@pxref{Ports and File Descriptors, setvbuf}\n"
263 "@item l\n"
264 "Add line-buffering to the port. The port output buffer will be\n"
265 "automatically flushed whenever a newline character is written.\n"
266 "@end table\n\n"
267 "In theory we could create read/write ports which were buffered in one\n"
268 "direction only. However this isn't included in the current interfaces.\n\n"
269 "If a file cannot be opened with the access requested,\n"
270 "@code{open-file} throws an exception.")
1bbd0b84 271#define FUNC_NAME s_scm_open_file
0f2d19dd 272{
19639113 273 SCM port;
cb63cf9e
JB
274 int fdes;
275 int flags = 0;
19639113
GH
276 char *file;
277 char *mode;
cb63cf9e 278 char *ptr;
19639113 279
a6d9e5ab
DH
280 SCM_VALIDATE_STRING (1, filename);
281 SCM_VALIDATE_STRING (2, modes);
282 SCM_STRING_COERCE_0TERMINATION_X (filename);
283 SCM_STRING_COERCE_0TERMINATION_X (modes);
19639113 284
a6d9e5ab
DH
285 file = SCM_STRING_CHARS (filename);
286 mode = SCM_STRING_CHARS (modes);
19639113 287
cb63cf9e 288 switch (*mode)
0f2d19dd 289 {
cb63cf9e
JB
290 case 'r':
291 flags |= O_RDONLY;
292 break;
293 case 'w':
294 flags |= O_WRONLY | O_CREAT | O_TRUNC;
295 break;
296 case 'a':
297 flags |= O_WRONLY | O_CREAT | O_APPEND;
298 break;
299 default:
1bbd0b84 300 scm_out_of_range (FUNC_NAME, modes);
0f2d19dd 301 }
cb63cf9e
JB
302 ptr = mode + 1;
303 while (*ptr != '\0')
e145dd02 304 {
cb63cf9e
JB
305 switch (*ptr)
306 {
307 case '+':
308 flags = (flags & ~(O_RDONLY | O_WRONLY)) | O_RDWR;
309 break;
9f561420
GH
310 case 'b':
311#if defined (O_BINARY)
312 flags |= O_BINARY;
313#endif
314 break;
cb63cf9e 315 case '0': /* unbuffered: handled later. */
d3639214 316 case 'l': /* line buffered: handled during output. */
cb63cf9e
JB
317 break;
318 default:
1bbd0b84 319 scm_out_of_range (FUNC_NAME, modes);
cb63cf9e
JB
320 }
321 ptr++;
e145dd02 322 }
cb63cf9e
JB
323 SCM_SYSCALL (fdes = open (file, flags, 0666));
324 if (fdes == -1)
e145dd02 325 {
cb63cf9e
JB
326 int en = errno;
327
5d2d2ffc 328 SCM_SYSERROR_MSG ("~A: ~S",
cb63cf9e 329 scm_cons (scm_makfrom0str (strerror (en)),
5d2d2ffc 330 scm_cons (filename, SCM_EOL)), en);
0f2d19dd 331 }
cb63cf9e 332 port = scm_fdes_to_port (fdes, mode, filename);
0f2d19dd
JB
333 return port;
334}
1bbd0b84 335#undef FUNC_NAME
0f2d19dd 336
e145dd02 337\f
cb63cf9e 338/* Building Guile ports from a file descriptor. */
e145dd02 339
cb63cf9e 340/* Build a Scheme port from an open file descriptor `fdes'.
a089567e
JB
341 MODE indicates whether FILE is open for reading or writing; it uses
342 the same notation as open-file's second argument.
19b27fa2
GH
343 NAME is a string to be used as the port's filename.
344*/
a089567e 345SCM
cb63cf9e 346scm_fdes_to_port (int fdes, char *mode, SCM name)
19b27fa2 347#define FUNC_NAME "scm_fdes_to_port"
a089567e
JB
348{
349 long mode_bits = scm_mode_bits (mode);
350 SCM port;
840ae05d 351 scm_port *pt;
19b27fa2
GH
352 int flags;
353
354 /* test that fdes is valid. */
355 flags = fcntl (fdes, F_GETFL, 0);
356 if (flags == -1)
357 SCM_SYSERROR;
358 flags &= O_ACCMODE;
359 if (flags != O_RDWR
360 && ((flags != O_WRONLY && (mode_bits & SCM_WRTNG))
361 || (flags != O_RDONLY && (mode_bits & SCM_RDNG))))
362 {
363 SCM_MISC_ERROR ("requested file mode not available on fdes", SCM_EOL);
364 }
a089567e
JB
365
366 SCM_NEWCELL (port);
367 SCM_DEFER_INTS;
cb63cf9e
JB
368 pt = scm_add_to_port_table (port);
369 SCM_SETPTAB_ENTRY (port, pt);
54778cd3 370 SCM_SET_CELL_TYPE (port, (scm_tc16_fport | mode_bits));
cb63cf9e 371
a089567e 372 {
cb63cf9e 373 struct scm_fport *fp
840ae05d
JB
374 = (struct scm_fport *) malloc (sizeof (struct scm_fport));
375 if (fp == NULL)
19b27fa2 376 SCM_MEMORY_ERROR;
cb63cf9e 377 fp->fdes = fdes;
0de97b83 378 pt->rw_random = SCM_FDES_RANDOM_P (fdes);
cb63cf9e
JB
379 SCM_SETSTREAM (port, fp);
380 if (mode_bits & SCM_BUF0)
381 scm_fport_buffer_add (port, 0, 0);
382 else
383 scm_fport_buffer_add (port, -1, -1);
a089567e 384 }
b24b5e13 385 SCM_SET_FILENAME (port, name);
a089567e 386 SCM_ALLOW_INTS;
e145dd02
JB
387 return port;
388}
19b27fa2 389#undef FUNC_NAME
e145dd02 390
affc96b5 391/* Return a lower bound on the number of bytes available for input. */
cb63cf9e 392static int
affc96b5 393fport_input_waiting (SCM port)
e145dd02 394{
cb63cf9e
JB
395 int fdes = SCM_FSTREAM (port)->fdes;
396
397#ifdef HAVE_SELECT
398 struct timeval timeout;
399 SELECT_TYPE read_set;
400 SELECT_TYPE write_set;
401 SELECT_TYPE except_set;
402
403 FD_ZERO (&read_set);
404 FD_ZERO (&write_set);
405 FD_ZERO (&except_set);
406
407 FD_SET (fdes, &read_set);
408
409 timeout.tv_sec = 0;
410 timeout.tv_usec = 0;
411
412 if (select (SELECT_SET_SIZE,
413 &read_set, &write_set, &except_set, &timeout)
414 < 0)
affc96b5
GH
415 scm_syserror ("fport_input_waiting");
416 return FD_ISSET (fdes, &read_set) ? 1 : 0;
cb63cf9e
JB
417#elif defined (FIONREAD)
418 int remir;
419 ioctl(fdes, FIONREAD, &remir);
420 return remir;
421#else
affc96b5 422 scm_misc_error ("fport_input_waiting",
cb63cf9e
JB
423 "Not fully implemented on this platform",
424 SCM_EOL);
425#endif
a089567e
JB
426}
427
cb63cf9e 428\f
0f2d19dd 429static int
e841c3e0 430fport_print (SCM exp, SCM port, scm_print_state *pstate)
0f2d19dd 431{
b3ec3c64
MD
432 scm_puts ("#<", port);
433 scm_print_port_mode (exp, port);
434 if (SCM_OPFPORTP (exp))
0f2d19dd 435 {
b3ec3c64 436 int fdes;
b24b5e13
DH
437 SCM name = SCM_FILENAME (exp);
438 if (SCM_STRINGP (name) || SCM_SYMBOLP (name))
439 scm_display (name, port);
440 else
441 scm_puts (SCM_PTOBNAME (SCM_PTOBNUM (exp)), port);
b3ec3c64
MD
442 scm_putc (' ', port);
443 fdes = (SCM_FSTREAM (exp))->fdes;
444
445 if (isatty (fdes))
446 scm_puts (ttyname (fdes), port);
447 else
448 scm_intprint (fdes, 10, port);
0f2d19dd
JB
449 }
450 else
451 {
b3ec3c64
MD
452 scm_puts (SCM_PTOBNAME (SCM_PTOBNUM (exp)), port);
453 scm_putc (' ', port);
f1267706 454 scm_intprint (SCM_UNPACK (SCM_CDR (exp)), 16, port);
0f2d19dd 455 }
b3ec3c64
MD
456 scm_putc ('>', port);
457 return 1;
0f2d19dd
JB
458}
459
cb63cf9e
JB
460#ifdef GUILE_ISELECT
461/* thread-local block for input on fport's fdes. */
462static void
463fport_wait_for_input (SCM port)
3cb988bd 464{
cb63cf9e 465 int fdes = SCM_FSTREAM (port)->fdes;
3cb988bd 466
affc96b5 467 if (!fport_input_waiting (port))
8122b543 468 {
cb63cf9e
JB
469 int n;
470 SELECT_TYPE readfds;
471 int flags = fcntl (fdes, F_GETFL);
472
473 if (flags == -1)
474 scm_syserror ("scm_fdes_wait_for_input");
475 if (!(flags & O_NONBLOCK))
476 do
477 {
478 FD_ZERO (&readfds);
479 FD_SET (fdes, &readfds);
480 n = scm_internal_select (fdes + 1, &readfds, NULL, NULL, NULL);
481 }
482 while (n == -1 && errno == EINTR);
8122b543 483 }
3cb988bd 484}
0f2d19dd
JB
485#endif
486
affc96b5 487static void fport_flush (SCM port);
0f2d19dd 488
cb63cf9e
JB
489/* fill a port's read-buffer with a single read.
490 returns the first char and moves the read_pos pointer past it.
491 or returns EOF if end of file. */
0f2d19dd 492static int
affc96b5 493fport_fill_input (SCM port)
0f2d19dd 494{
cb63cf9e 495 int count;
840ae05d 496 scm_port *pt = SCM_PTAB_ENTRY (port);
cb63cf9e
JB
497 struct scm_fport *fp = SCM_FSTREAM (port);
498
cb63cf9e
JB
499#ifdef GUILE_ISELECT
500 fport_wait_for_input (port);
501#endif
502 SCM_SYSCALL (count = read (fp->fdes, pt->read_buf, pt->read_buf_size));
503 if (count == -1)
affc96b5 504 scm_syserror ("fport_fill_input");
cb63cf9e
JB
505 if (count == 0)
506 return EOF;
507 else
508 {
5c070ca7 509 pt->read_pos = pt->read_buf;
cb63cf9e 510 pt->read_end = pt->read_buf + count;
5c070ca7 511 return *pt->read_buf;
cb63cf9e 512 }
0f2d19dd
JB
513}
514
cb63cf9e 515static off_t
affc96b5 516fport_seek (SCM port, off_t offset, int whence)
0f2d19dd 517{
7dcb364d 518 scm_port *pt = SCM_PTAB_ENTRY (port);
cb63cf9e 519 struct scm_fport *fp = SCM_FSTREAM (port);
7dcb364d
GH
520 off_t rv;
521 off_t result;
522
523 if (pt->rw_active == SCM_PORT_WRITE)
524 {
525 if (offset != 0 || whence != SEEK_CUR)
526 {
527 fport_flush (port);
528 result = rv = lseek (fp->fdes, offset, whence);
529 }
530 else
531 {
532 /* read current position without disturbing the buffer. */
533 rv = lseek (fp->fdes, offset, whence);
534 result = rv + (pt->write_pos - pt->write_buf);
535 }
536 }
537 else if (pt->rw_active == SCM_PORT_READ)
538 {
539 if (offset != 0 || whence != SEEK_CUR)
540 {
541 /* could expand to avoid a second seek. */
542 scm_end_input (port);
543 result = rv = lseek (fp->fdes, offset, whence);
544 }
545 else
546 {
547 /* read current position without disturbing the buffer
548 (particularly the unread-char buffer). */
549 rv = lseek (fp->fdes, offset, whence);
550 result = rv - (pt->read_end - pt->read_pos);
551
552 if (pt->read_buf == pt->putback_buf)
553 result -= pt->saved_read_end - pt->saved_read_pos;
554 }
555 }
556 else /* SCM_PORT_NEITHER */
557 {
558 result = rv = lseek (fp->fdes, offset, whence);
559 }
cb8dfa3f 560
7dcb364d 561 if (rv == -1)
affc96b5 562 scm_syserror ("fport_seek");
7dcb364d 563
cb8dfa3f 564 return result;
0f2d19dd
JB
565}
566
840ae05d 567static void
affc96b5 568fport_truncate (SCM port, off_t length)
840ae05d
JB
569{
570 struct scm_fport *fp = SCM_FSTREAM (port);
571
572 if (ftruncate (fp->fdes, length) == -1)
573 scm_syserror ("ftruncate");
574}
575
31703ab8 576static void
8aa011a1 577fport_write (SCM port, const void *data, size_t size)
31703ab8
GH
578{
579 scm_port *pt = SCM_PTAB_ENTRY (port);
580
581 if (pt->write_buf == &pt->shortbuf)
582 {
583 /* "unbuffered" port. */
584 int fdes = SCM_FSTREAM (port)->fdes;
585
586 if (write (fdes, data, size) == -1)
587 scm_syserror ("fport_write");
588 }
589 else
590 {
591 const char *input = (char *) data;
d3639214
GH
592 size_t remaining = size;
593
594 while (remaining > 0)
31703ab8
GH
595 {
596 int space = pt->write_end - pt->write_pos;
d3639214 597 int write_len = (remaining > space) ? space : remaining;
31703ab8 598
162d88ca 599 memcpy (pt->write_pos, input, write_len);
31703ab8 600 pt->write_pos += write_len;
d3639214 601 remaining -= write_len;
31703ab8
GH
602 input += write_len;
603 if (write_len == space)
affc96b5 604 fport_flush (port);
31703ab8
GH
605 }
606
607 /* handle line buffering. */
f9a64404 608 if ((SCM_CELL_WORD_0 (port) & SCM_BUFLINE) && memchr (data, '\n', size))
affc96b5 609 fport_flush (port);
31703ab8
GH
610 }
611}
612
613/* becomes 1 when process is exiting: normal exception handling won't
614 work by this time. */
cb63cf9e 615extern int terminating;
0f2d19dd 616
cb63cf9e 617static void
affc96b5 618fport_flush (SCM port)
0f2d19dd 619{
840ae05d 620 scm_port *pt = SCM_PTAB_ENTRY (port);
cb63cf9e 621 struct scm_fport *fp = SCM_FSTREAM (port);
6f760c1d 622 unsigned char *ptr = pt->write_buf;
cb63cf9e
JB
623 int init_size = pt->write_pos - pt->write_buf;
624 int remaining = init_size;
0f2d19dd 625
cb63cf9e
JB
626 while (remaining > 0)
627 {
628 int count;
629
630 SCM_SYSCALL (count = write (fp->fdes, ptr, remaining));
631 if (count < 0)
632 {
633 /* error. assume nothing was written this call, but
634 fix up the buffer for any previous successful writes. */
635 int done = init_size - remaining;
636
637 if (done > 0)
638 {
639 int i;
640
641 for (i = 0; i < remaining; i++)
642 {
643 *(pt->write_buf + i) = *(pt->write_buf + done + i);
644 }
645 pt->write_pos = pt->write_buf + remaining;
646 }
6b72ac1d 647 if (terminating)
cb63cf9e
JB
648 {
649 const char *msg = "Error: could not flush file-descriptor ";
650 char buf[11];
651
652 write (2, msg, strlen (msg));
653 sprintf (buf, "%d\n", fp->fdes);
654 write (2, buf, strlen (buf));
655
656 count = remaining;
657 }
6b72ac1d
GH
658 else if (scm_gc_running_p)
659 {
660 /* silently ignore the error. scm_error would abort if we
661 called it now. */
662 count = remaining;
663 }
664 else
665 scm_syserror ("fport_flush");
cb63cf9e
JB
666 }
667 ptr += count;
668 remaining -= count;
669 }
670 pt->write_pos = pt->write_buf;
61e452ba 671 pt->rw_active = SCM_PORT_NEITHER;
840ae05d
JB
672}
673
283a1a0e 674/* clear the read buffer and adjust the file position for unread bytes. */
840ae05d 675static void
affc96b5 676fport_end_input (SCM port, int offset)
840ae05d
JB
677{
678 struct scm_fport *fp = SCM_FSTREAM (port);
679 scm_port *pt = SCM_PTAB_ENTRY (port);
283a1a0e
GH
680
681 offset += pt->read_end - pt->read_pos;
840ae05d 682
840ae05d
JB
683 if (offset > 0)
684 {
685 pt->read_pos = pt->read_end;
686 /* will throw error if unread-char used at beginning of file
687 then attempting to write. seems correct. */
688 if (lseek (fp->fdes, -offset, SEEK_CUR) == -1)
affc96b5 689 scm_syserror ("fport_end_input");
840ae05d 690 }
61e452ba 691 pt->rw_active = SCM_PORT_NEITHER;
8f29fbd0
JB
692}
693
6a2c4c81 694static int
affc96b5 695fport_close (SCM port)
6a2c4c81 696{
cb63cf9e 697 struct scm_fport *fp = SCM_FSTREAM (port);
840ae05d 698 scm_port *pt = SCM_PTAB_ENTRY (port);
cb63cf9e 699 int rv;
840ae05d 700
affc96b5 701 fport_flush (port);
cb63cf9e
JB
702 SCM_SYSCALL (rv = close (fp->fdes));
703 if (rv == -1 && errno != EBADF)
6b72ac1d
GH
704 {
705 if (scm_gc_running_p)
706 /* silently ignore the error. scm_error would abort if we
707 called it now. */
708 ;
709 else
710 scm_syserror ("fport_close");
711 }
6c951427
GH
712 if (pt->read_buf == pt->putback_buf)
713 pt->read_buf = pt->saved_read_buf;
cb63cf9e 714 if (pt->read_buf != &pt->shortbuf)
840ae05d 715 free (pt->read_buf);
cb63cf9e 716 if (pt->write_buf != &pt->shortbuf)
840ae05d
JB
717 free (pt->write_buf);
718 free ((char *) fp);
cb63cf9e 719 return rv;
6a2c4c81
JB
720}
721
b3ec3c64 722static scm_sizet
affc96b5 723fport_free (SCM port)
b3ec3c64 724{
affc96b5 725 fport_close (port);
b3ec3c64
MD
726 return 0;
727}
728
729void scm_make_fptob (void); /* Called from ports.c */
730
731void
732scm_make_fptob ()
733{
affc96b5
GH
734 long tc = scm_make_port_type ("file", fport_fill_input, fport_write);
735 scm_set_port_free (tc, fport_free);
e841c3e0 736 scm_set_port_print (tc, fport_print);
affc96b5
GH
737 scm_set_port_flush (tc, fport_flush);
738 scm_set_port_end_input (tc, fport_end_input);
739 scm_set_port_close (tc, fport_close);
740 scm_set_port_seek (tc, fport_seek);
741 scm_set_port_truncate (tc, fport_truncate);
742 scm_set_port_input_waiting (tc, fport_input_waiting);
b3ec3c64 743}
0f2d19dd 744
0f2d19dd
JB
745void
746scm_init_fports ()
0f2d19dd 747{
8dc9439f 748#ifndef SCM_MAGIC_SNARFER
a0599745 749#include "libguile/fports.x"
8dc9439f 750#endif
7a6f1ffa
GH
751 scm_sysintern ("_IOFBF", SCM_MAKINUM (_IOFBF));
752 scm_sysintern ("_IOLBF", SCM_MAKINUM (_IOLBF));
753 scm_sysintern ("_IONBF", SCM_MAKINUM (_IONBF));
0f2d19dd 754}
89e00824
ML
755
756/*
757 Local Variables:
758 c-file-style: "gnu"
759 End:
760*/