Changes in doc/ref:
[bpt/guile.git] / libguile / fports.c
1 /* Copyright (C) 1995,1996,1997,1998,1999,2000,2001 Free Software Foundation, Inc.
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
15 * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
16 * Boston, MA 02111-1307 USA
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.
40 * If you do not wish that, delete this exception notice. */
41
42
43 \f
44
45 #include <stdio.h>
46 #include <fcntl.h>
47 #include "libguile/_scm.h"
48 #include "libguile/strings.h"
49 #include "libguile/validate.h"
50 #include "libguile/gc.h"
51
52 #include "libguile/fports.h"
53
54 #ifdef HAVE_STRING_H
55 #include <string.h>
56 #endif
57 #ifdef HAVE_UNISTD_H
58 #include <unistd.h>
59 #else
60 size_t fwrite ();
61 #endif
62 #ifdef HAVE_IO_H
63 #include <io.h>
64 #endif
65 #ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
66 #include <sys/stat.h>
67 #endif
68
69 #include <errno.h>
70
71 #include "libguile/iselect.h"
72
73 /* Some defines for Windows (native port, not Cygwin). */
74 #ifdef __MINGW32__
75 # include <sys/stat.h>
76 # include <winsock2.h>
77 # define ftruncate(fd, size) chsize (fd, size)
78 #endif /* __MINGW32__ */
79
80
81 scm_t_bits scm_tc16_fport;
82
83
84 /* default buffer size, used if the O/S won't supply a value. */
85 static const size_t default_buffer_size = 1024;
86
87 /* create FPORT buffer with specified sizes (or -1 to use default size or
88 0 for no buffer. */
89 static void
90 scm_fport_buffer_add (SCM port, long read_size, int write_size)
91 #define FUNC_NAME "scm_fport_buffer_add"
92 {
93 scm_t_port *pt = SCM_PTAB_ENTRY (port);
94
95 if (read_size == -1 || write_size == -1)
96 {
97 size_t default_size;
98 #ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
99 struct stat st;
100 scm_t_fport *fp = SCM_FSTREAM (port);
101
102 default_size = (fstat (fp->fdes, &st) == -1) ? default_buffer_size
103 : st.st_blksize;
104 #else
105 default_size = default_buffer_size;
106 #endif
107 if (read_size == -1)
108 read_size = default_size;
109 if (write_size == -1)
110 write_size = default_size;
111 }
112
113 if (SCM_INPUT_PORT_P (port) && read_size > 0)
114 {
115 pt->read_buf = scm_gc_malloc (read_size, "port buffer");
116 pt->read_pos = pt->read_end = pt->read_buf;
117 pt->read_buf_size = read_size;
118 }
119 else
120 {
121 pt->read_pos = pt->read_buf = pt->read_end = &pt->shortbuf;
122 pt->read_buf_size = 1;
123 }
124
125 if (SCM_OUTPUT_PORT_P (port) && write_size > 0)
126 {
127 pt->write_buf = scm_gc_malloc (write_size, "port buffer");
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)
139 SCM_SET_CELL_WORD_0 (port, SCM_CELL_WORD_0 (port) & ~SCM_BUF0);
140 else
141 SCM_SET_CELL_WORD_0 (port, SCM_CELL_WORD_0 (port) | SCM_BUF0);
142 }
143 #undef FUNC_NAME
144
145 SCM_DEFINE (scm_setvbuf, "setvbuf", 2, 1, 0,
146 (SCM port, SCM mode, SCM size),
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"
156 "@end table")
157 #define FUNC_NAME s_scm_setvbuf
158 {
159 int cmode;
160 long csize;
161 scm_t_port *pt;
162
163 port = SCM_COERCE_OUTPORT (port);
164
165 SCM_VALIDATE_OPFPORT (1,port);
166 SCM_VALIDATE_INUM_COPY (2,mode,cmode);
167 if (cmode != _IONBF && cmode != _IOFBF && cmode != _IOLBF)
168 scm_out_of_range (FUNC_NAME, mode);
169
170 if (cmode == _IOLBF)
171 {
172 SCM_SET_CELL_WORD_0 (port, SCM_CELL_WORD_0 (port) | SCM_BUFLINE);
173 cmode = _IOFBF;
174 }
175 else
176 {
177 SCM_SET_CELL_WORD_0 (port, SCM_CELL_WORD_0 (port) ^ SCM_BUFLINE);
178 }
179
180 if (SCM_UNBNDP (size))
181 {
182 if (cmode == _IOFBF)
183 csize = -1;
184 else
185 csize = 0;
186 }
187 else
188 {
189 SCM_VALIDATE_INUM_COPY (3,size,csize);
190 if (csize < 0 || (cmode == _IONBF && csize > 0))
191 scm_out_of_range (FUNC_NAME, size);
192 }
193
194 pt = SCM_PTAB_ENTRY (port);
195
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 }
204 if (pt->read_buf != &pt->shortbuf)
205 scm_gc_free (pt->read_buf, pt->read_buf_size, "port buffer");
206 if (pt->write_buf != &pt->shortbuf)
207 scm_gc_free (pt->write_buf, pt->write_buf_size, "port buffer");
208
209 scm_fport_buffer_add (port, csize, csize);
210 return SCM_UNSPECIFIED;
211 }
212 #undef FUNC_NAME
213
214 /* Move ports with the specified file descriptor to new descriptors,
215 * reseting the revealed count to 0.
216 */
217
218 void
219 scm_evict_ports (int fd)
220 {
221 long i;
222
223 for (i = 0; i < scm_port_table_size; i++)
224 {
225 SCM port = scm_port_table[i]->port;
226
227 if (SCM_FPORTP (port))
228 {
229 scm_t_fport *fp = SCM_FSTREAM (port);
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 }
238 }
239 }
240 }
241
242
243 SCM_DEFINE (scm_file_port_p, "file-port?", 1, 0, 0,
244 (SCM obj),
245 "Determine whether @var{obj} is a port that is related to a file.")
246 #define FUNC_NAME s_scm_file_port_p
247 {
248 return SCM_BOOL (SCM_FPORTP (obj));
249 }
250 #undef FUNC_NAME
251
252
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 */
261 SCM_DEFINE (scm_open_file, "open-file", 2, 0, 0,
262 (SCM filename, SCM mode),
263 "Open the file whose name is @var{filename}, and return a port\n"
264 "representing that file. The attributes of the port are\n"
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"
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"
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"
277 "The \"append mode\" can be turned off while the port is in use\n"
278 "@pxref{Ports and File Descriptors, fcntl}\n"
279 "@end table\n"
280 "The following additional characters can be appended:\n"
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"
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"
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"
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.")
300 #define FUNC_NAME s_scm_open_file
301 {
302 SCM port;
303 int fdes;
304 int flags = 0;
305 char *file;
306 char *md;
307 char *ptr;
308
309 SCM_VALIDATE_STRING (1, filename);
310 SCM_VALIDATE_STRING (2, mode);
311
312 file = SCM_STRING_CHARS (filename);
313 md = SCM_STRING_CHARS (mode);
314
315 switch (*md)
316 {
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:
327 scm_out_of_range (FUNC_NAME, mode);
328 }
329 ptr = md + 1;
330 while (*ptr != '\0')
331 {
332 switch (*ptr)
333 {
334 case '+':
335 flags = (flags & ~(O_RDONLY | O_WRONLY)) | O_RDWR;
336 break;
337 case 'b':
338 #if defined (O_BINARY)
339 flags |= O_BINARY;
340 #endif
341 break;
342 case '0': /* unbuffered: handled later. */
343 case 'l': /* line buffered: handled during output. */
344 break;
345 default:
346 scm_out_of_range (FUNC_NAME, mode);
347 }
348 ptr++;
349 }
350 SCM_SYSCALL (fdes = open (file, flags, 0666));
351 if (fdes == -1)
352 {
353 int en = errno;
354
355 SCM_SYSERROR_MSG ("~A: ~S",
356 scm_cons (scm_makfrom0str (strerror (en)),
357 scm_cons (filename, SCM_EOL)), en);
358 }
359 port = scm_fdes_to_port (fdes, md, filename);
360 return port;
361 }
362 #undef FUNC_NAME
363
364 \f
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
375 static 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 ? */
390 if (buf.st_mode & _S_IFIFO)
391 flags = PeekNamedPipe ((HANDLE) _get_osfhandle (fdes), NULL, 0,
392 NULL, NULL, NULL) ? O_RDONLY : O_WRONLY;
393 /* stdin ? */
394 else if (fdes == fileno (stdin) && isatty (fdes))
395 flags = O_RDONLY;
396 /* stdout / stderr ? */
397 else if ((fdes == fileno (stdout) || fdes == fileno (stderr)) &&
398 isatty (fdes))
399 flags = O_WRONLY;
400 else
401 flags = buf.st_mode;
402 }
403 return flags;
404 }
405 #endif /* __MINGW32__ */
406
407 /* Building Guile ports from a file descriptor. */
408
409 /* Build a Scheme port from an open file descriptor `fdes'.
410 MODE indicates whether FILE is open for reading or writing; it uses
411 the same notation as open-file's second argument.
412 NAME is a string to be used as the port's filename.
413 */
414 SCM
415 scm_fdes_to_port (int fdes, char *mode, SCM name)
416 #define FUNC_NAME "scm_fdes_to_port"
417 {
418 long mode_bits = scm_mode_bits (mode);
419 SCM port;
420 scm_t_port *pt;
421 int flags;
422
423 /* test that fdes is valid. */
424 #ifdef __MINGW32__
425 flags = getflags (fdes);
426 #else
427 flags = fcntl (fdes, F_GETFL, 0);
428 #endif
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 }
438
439 port = scm_cell (scm_tc16_fport, 0);
440 SCM_DEFER_INTS;
441 pt = scm_add_to_port_table (port);
442 SCM_SETPTAB_ENTRY (port, pt);
443 SCM_SET_CELL_TYPE (port, (scm_tc16_fport | mode_bits));
444
445 {
446 scm_t_fport *fp
447 = (scm_t_fport *) scm_gc_malloc (sizeof (scm_t_fport), "file port");
448
449 fp->fdes = fdes;
450 pt->rw_random = SCM_FDES_RANDOM_P (fdes);
451 SCM_SETSTREAM (port, fp);
452 if (mode_bits & SCM_BUF0)
453 scm_fport_buffer_add (port, 0, 0);
454 else
455 scm_fport_buffer_add (port, -1, -1);
456 }
457 SCM_SET_FILENAME (port, name);
458 SCM_ALLOW_INTS;
459 return port;
460 }
461 #undef FUNC_NAME
462
463 /* Return a lower bound on the number of bytes available for input. */
464 static int
465 fport_input_waiting (SCM port)
466 {
467 int fdes = SCM_FSTREAM (port)->fdes;
468
469 #ifdef HAVE_SELECT
470 struct timeval timeout;
471 SELECT_TYPE read_set;
472 SELECT_TYPE write_set;
473 SELECT_TYPE except_set;
474
475 FD_ZERO (&read_set);
476 FD_ZERO (&write_set);
477 FD_ZERO (&except_set);
478
479 FD_SET (fdes, &read_set);
480
481 timeout.tv_sec = 0;
482 timeout.tv_usec = 0;
483
484 if (select (SELECT_SET_SIZE,
485 &read_set, &write_set, &except_set, &timeout)
486 < 0)
487 scm_syserror ("fport_input_waiting");
488 return FD_ISSET (fdes, &read_set) ? 1 : 0;
489 #elif defined (FIONREAD)
490 int remir;
491 ioctl(fdes, FIONREAD, &remir);
492 return remir;
493 #else
494 scm_misc_error ("fport_input_waiting",
495 "Not fully implemented on this platform",
496 SCM_EOL);
497 #endif
498 }
499
500 \f
501 static int
502 fport_print (SCM exp, SCM port, scm_print_state *pstate SCM_UNUSED)
503 {
504 scm_puts ("#<", port);
505 scm_print_port_mode (exp, port);
506 if (SCM_OPFPORTP (exp))
507 {
508 int fdes;
509 SCM name = SCM_FILENAME (exp);
510 if (SCM_STRINGP (name) || SCM_SYMBOLP (name))
511 scm_display (name, port);
512 else
513 scm_puts (SCM_PTOBNAME (SCM_PTOBNUM (exp)), port);
514 scm_putc (' ', port);
515 fdes = (SCM_FSTREAM (exp))->fdes;
516
517 #ifdef HAVE_TTYNAME
518 if (isatty (fdes))
519 scm_puts (ttyname (fdes), port);
520 else
521 #endif /* HAVE_TTYNAME */
522 scm_intprint (fdes, 10, port);
523 }
524 else
525 {
526 scm_puts (SCM_PTOBNAME (SCM_PTOBNUM (exp)), port);
527 scm_putc (' ', port);
528 scm_intprint ((scm_t_bits) SCM_PTAB_ENTRY (exp), 16, port);
529 }
530 scm_putc ('>', port);
531 return 1;
532 }
533
534 #ifdef GUILE_ISELECT
535 /* thread-local block for input on fport's fdes. */
536 static void
537 fport_wait_for_input (SCM port)
538 {
539 int fdes = SCM_FSTREAM (port)->fdes;
540
541 if (!fport_input_waiting (port))
542 {
543 int n;
544 SELECT_TYPE readfds;
545 int flags = fcntl (fdes, F_GETFL);
546
547 if (flags == -1)
548 scm_syserror ("scm_fdes_wait_for_input");
549 if (!(flags & O_NONBLOCK))
550 do
551 {
552 FD_ZERO (&readfds);
553 FD_SET (fdes, &readfds);
554 n = scm_internal_select (fdes + 1, &readfds, NULL, NULL, NULL);
555 }
556 while (n == -1 && errno == EINTR);
557 }
558 }
559 #endif
560
561 static void fport_flush (SCM port);
562
563 /* fill a port's read-buffer with a single read. returns the first
564 char or EOF if end of file. */
565 static int
566 fport_fill_input (SCM port)
567 {
568 long count;
569 scm_t_port *pt = SCM_PTAB_ENTRY (port);
570 scm_t_fport *fp = SCM_FSTREAM (port);
571
572 #ifdef GUILE_ISELECT
573 fport_wait_for_input (port);
574 #endif
575 SCM_SYSCALL (count = read (fp->fdes, pt->read_buf, pt->read_buf_size));
576 if (count == -1)
577 scm_syserror ("fport_fill_input");
578 if (count == 0)
579 return EOF;
580 else
581 {
582 pt->read_pos = pt->read_buf;
583 pt->read_end = pt->read_buf + count;
584 return *pt->read_buf;
585 }
586 }
587
588 static off_t
589 fport_seek (SCM port, off_t offset, int whence)
590 {
591 scm_t_port *pt = SCM_PTAB_ENTRY (port);
592 scm_t_fport *fp = SCM_FSTREAM (port);
593 off_t rv;
594 off_t result;
595
596 if (pt->rw_active == SCM_PORT_WRITE)
597 {
598 if (offset != 0 || whence != SEEK_CUR)
599 {
600 fport_flush (port);
601 result = rv = lseek (fp->fdes, offset, whence);
602 }
603 else
604 {
605 /* read current position without disturbing the buffer. */
606 rv = lseek (fp->fdes, offset, whence);
607 result = rv + (pt->write_pos - pt->write_buf);
608 }
609 }
610 else if (pt->rw_active == SCM_PORT_READ)
611 {
612 if (offset != 0 || whence != SEEK_CUR)
613 {
614 /* could expand to avoid a second seek. */
615 scm_end_input (port);
616 result = rv = lseek (fp->fdes, offset, whence);
617 }
618 else
619 {
620 /* read current position without disturbing the buffer
621 (particularly the unread-char buffer). */
622 rv = lseek (fp->fdes, offset, whence);
623 result = rv - (pt->read_end - pt->read_pos);
624
625 if (pt->read_buf == pt->putback_buf)
626 result -= pt->saved_read_end - pt->saved_read_pos;
627 }
628 }
629 else /* SCM_PORT_NEITHER */
630 {
631 result = rv = lseek (fp->fdes, offset, whence);
632 }
633
634 if (rv == -1)
635 scm_syserror ("fport_seek");
636
637 return result;
638 }
639
640 static void
641 fport_truncate (SCM port, off_t length)
642 {
643 scm_t_fport *fp = SCM_FSTREAM (port);
644
645 if (ftruncate (fp->fdes, length) == -1)
646 scm_syserror ("ftruncate");
647 }
648
649 /* helper for fport_write: try to write data, using multiple system
650 calls if required. */
651 #define FUNC_NAME "write_all"
652 static void write_all (SCM port, const void *data, size_t remaining)
653 {
654 int fdes = SCM_FSTREAM (port)->fdes;
655
656 while (remaining > 0)
657 {
658 size_t done;
659
660 SCM_SYSCALL (done = write (fdes, data, remaining));
661
662 if (done == -1)
663 SCM_SYSERROR;
664 remaining -= done;
665 data = ((const char *) data) + done;
666 }
667 }
668 #undef FUNC_NAME
669
670 static void
671 fport_write (SCM port, const void *data, size_t size)
672 {
673 /* this procedure tries to minimize the number of writes/flushes. */
674 scm_t_port *pt = SCM_PTAB_ENTRY (port);
675
676 if (pt->write_buf == &pt->shortbuf
677 || (pt->write_pos == pt->write_buf && size >= pt->write_buf_size))
678 {
679 /* "unbuffered" port, or
680 port with empty buffer and data won't fit in buffer. */
681 write_all (port, data, size);
682 return;
683 }
684
685 {
686 off_t space = pt->write_end - pt->write_pos;
687
688 if (size <= space)
689 {
690 /* data fits in buffer. */
691 memcpy (pt->write_pos, data, size);
692 pt->write_pos += size;
693 if (pt->write_pos == pt->write_end)
694 {
695 fport_flush (port);
696 /* we can skip the line-buffering check if nothing's buffered. */
697 return;
698 }
699 }
700 else
701 {
702 memcpy (pt->write_pos, data, space);
703 pt->write_pos = pt->write_end;
704 fport_flush (port);
705 {
706 const void *ptr = ((const char *) data) + space;
707 size_t remaining = size - space;
708
709 if (size >= pt->write_buf_size)
710 {
711 write_all (port, ptr, remaining);
712 return;
713 }
714 else
715 {
716 memcpy (pt->write_pos, ptr, remaining);
717 pt->write_pos += remaining;
718 }
719 }
720 }
721
722 /* handle line buffering. */
723 if ((SCM_CELL_WORD_0 (port) & SCM_BUFLINE) && memchr (data, '\n', size))
724 fport_flush (port);
725 }
726 }
727
728 /* becomes 1 when process is exiting: normal exception handling won't
729 work by this time. */
730 extern int terminating;
731
732 static void
733 fport_flush (SCM port)
734 {
735 scm_t_port *pt = SCM_PTAB_ENTRY (port);
736 scm_t_fport *fp = SCM_FSTREAM (port);
737 unsigned char *ptr = pt->write_buf;
738 long init_size = pt->write_pos - pt->write_buf;
739 long remaining = init_size;
740
741 while (remaining > 0)
742 {
743 long count;
744
745 SCM_SYSCALL (count = write (fp->fdes, ptr, remaining));
746 if (count < 0)
747 {
748 /* error. assume nothing was written this call, but
749 fix up the buffer for any previous successful writes. */
750 long done = init_size - remaining;
751
752 if (done > 0)
753 {
754 int i;
755
756 for (i = 0; i < remaining; i++)
757 {
758 *(pt->write_buf + i) = *(pt->write_buf + done + i);
759 }
760 pt->write_pos = pt->write_buf + remaining;
761 }
762 if (terminating)
763 {
764 const char *msg = "Error: could not flush file-descriptor ";
765 char buf[11];
766
767 write (2, msg, strlen (msg));
768 sprintf (buf, "%d\n", fp->fdes);
769 write (2, buf, strlen (buf));
770
771 count = remaining;
772 }
773 else if (scm_gc_running_p)
774 {
775 /* silently ignore the error. scm_error would abort if we
776 called it now. */
777 count = remaining;
778 }
779 else
780 scm_syserror ("fport_flush");
781 }
782 ptr += count;
783 remaining -= count;
784 }
785 pt->write_pos = pt->write_buf;
786 pt->rw_active = SCM_PORT_NEITHER;
787 }
788
789 /* clear the read buffer and adjust the file position for unread bytes. */
790 static void
791 fport_end_input (SCM port, int offset)
792 {
793 scm_t_fport *fp = SCM_FSTREAM (port);
794 scm_t_port *pt = SCM_PTAB_ENTRY (port);
795
796 offset += pt->read_end - pt->read_pos;
797
798 if (offset > 0)
799 {
800 pt->read_pos = pt->read_end;
801 /* will throw error if unread-char used at beginning of file
802 then attempting to write. seems correct. */
803 if (lseek (fp->fdes, -offset, SEEK_CUR) == -1)
804 scm_syserror ("fport_end_input");
805 }
806 pt->rw_active = SCM_PORT_NEITHER;
807 }
808
809 static int
810 fport_close (SCM port)
811 {
812 scm_t_fport *fp = SCM_FSTREAM (port);
813 scm_t_port *pt = SCM_PTAB_ENTRY (port);
814 int rv;
815
816 fport_flush (port);
817 SCM_SYSCALL (rv = close (fp->fdes));
818 if (rv == -1 && errno != EBADF)
819 {
820 if (scm_gc_running_p)
821 /* silently ignore the error. scm_error would abort if we
822 called it now. */
823 ;
824 else
825 scm_syserror ("fport_close");
826 }
827 if (pt->read_buf == pt->putback_buf)
828 pt->read_buf = pt->saved_read_buf;
829 if (pt->read_buf != &pt->shortbuf)
830 scm_gc_free (pt->read_buf, pt->read_buf_size, "port buffer");
831 if (pt->write_buf != &pt->shortbuf)
832 scm_gc_free (pt->write_buf, pt->write_buf_size, "port buffer");
833 scm_gc_free (fp, sizeof (*fp), "file port");
834 return rv;
835 }
836
837 static size_t
838 fport_free (SCM port)
839 {
840 fport_close (port);
841 return 0;
842 }
843
844 static scm_t_bits
845 scm_make_fptob ()
846 {
847 scm_t_bits tc = scm_make_port_type ("file", fport_fill_input, fport_write);
848
849 scm_set_port_free (tc, fport_free);
850 scm_set_port_print (tc, fport_print);
851 scm_set_port_flush (tc, fport_flush);
852 scm_set_port_end_input (tc, fport_end_input);
853 scm_set_port_close (tc, fport_close);
854 scm_set_port_seek (tc, fport_seek);
855 scm_set_port_truncate (tc, fport_truncate);
856 scm_set_port_input_waiting (tc, fport_input_waiting);
857
858 return tc;
859 }
860
861 void
862 scm_init_fports ()
863 {
864 scm_tc16_fport = scm_make_fptob ();
865
866 scm_c_define ("_IOFBF", SCM_MAKINUM (_IOFBF));
867 scm_c_define ("_IOLBF", SCM_MAKINUM (_IOLBF));
868 scm_c_define ("_IONBF", SCM_MAKINUM (_IONBF));
869
870 #ifndef SCM_MAGIC_SNARFER
871 #include "libguile/fports.x"
872 #endif
873 }
874
875 /*
876 Local Variables:
877 c-file-style: "gnu"
878 End:
879 */