* mallocs.c (scm_malloc_obj): use scm_gc_malloc in stead of
[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 * resetting 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_i_port_table_size; i++)
224 {
225 SCM port = scm_i_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 SCM_DEFER_INTS;
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);
444 {
445 scm_t_fport *fp
446 = (scm_t_fport *) scm_gc_malloc (sizeof (scm_t_fport), "file port");
447
448 fp->fdes = fdes;
449 pt->rw_random = SCM_FDES_RANDOM_P (fdes);
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);
455 }
456 SCM_SET_FILENAME (port, name);
457 SCM_ALLOW_INTS;
458 return port;
459 }
460 #undef FUNC_NAME
461
462 /* Return a lower bound on the number of bytes available for input. */
463 static int
464 fport_input_waiting (SCM port)
465 {
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)
486 scm_syserror ("fport_input_waiting");
487 return FD_ISSET (fdes, &read_set) ? 1 : 0;
488 #elif defined (FIONREAD)
489 int remir;
490 ioctl(fdes, FIONREAD, &remir);
491 return remir;
492 #else
493 scm_misc_error ("fport_input_waiting",
494 "Not fully implemented on this platform",
495 SCM_EOL);
496 #endif
497 }
498
499 \f
500 static int
501 fport_print (SCM exp, SCM port, scm_print_state *pstate SCM_UNUSED)
502 {
503 scm_puts ("#<", port);
504 scm_print_port_mode (exp, port);
505 if (SCM_OPFPORTP (exp))
506 {
507 int fdes;
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);
513 scm_putc (' ', port);
514 fdes = (SCM_FSTREAM (exp))->fdes;
515
516 #ifdef HAVE_TTYNAME
517 if (isatty (fdes))
518 scm_puts (ttyname (fdes), port);
519 else
520 #endif /* HAVE_TTYNAME */
521 scm_intprint (fdes, 10, port);
522 }
523 else
524 {
525 scm_puts (SCM_PTOBNAME (SCM_PTOBNUM (exp)), port);
526 scm_putc (' ', port);
527 scm_intprint ((scm_t_bits) SCM_PTAB_ENTRY (exp), 16, port);
528 }
529 scm_putc ('>', port);
530 return 1;
531 }
532
533 #ifdef GUILE_ISELECT
534 /* thread-local block for input on fport's fdes. */
535 static void
536 fport_wait_for_input (SCM port)
537 {
538 int fdes = SCM_FSTREAM (port)->fdes;
539
540 if (!fport_input_waiting (port))
541 {
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);
556 }
557 }
558 #endif
559
560 static void fport_flush (SCM port);
561
562 /* fill a port's read-buffer with a single read. returns the first
563 char or EOF if end of file. */
564 static int
565 fport_fill_input (SCM port)
566 {
567 long count;
568 scm_t_port *pt = SCM_PTAB_ENTRY (port);
569 scm_t_fport *fp = SCM_FSTREAM (port);
570
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)
576 scm_syserror ("fport_fill_input");
577 if (count == 0)
578 return EOF;
579 else
580 {
581 pt->read_pos = pt->read_buf;
582 pt->read_end = pt->read_buf + count;
583 return *pt->read_buf;
584 }
585 }
586
587 static off_t
588 fport_seek (SCM port, off_t offset, int whence)
589 {
590 scm_t_port *pt = SCM_PTAB_ENTRY (port);
591 scm_t_fport *fp = SCM_FSTREAM (port);
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 }
632
633 if (rv == -1)
634 scm_syserror ("fport_seek");
635
636 return result;
637 }
638
639 static void
640 fport_truncate (SCM port, off_t length)
641 {
642 scm_t_fport *fp = SCM_FSTREAM (port);
643
644 if (ftruncate (fp->fdes, length) == -1)
645 scm_syserror ("ftruncate");
646 }
647
648 /* helper for fport_write: try to write data, using multiple system
649 calls if required. */
650 #define FUNC_NAME "write_all"
651 static 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 {
657 size_t done;
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
669 static void
670 fport_write (SCM port, const void *data, size_t size)
671 {
672 /* this procedure tries to minimize the number of writes/flushes. */
673 scm_t_port *pt = SCM_PTAB_ENTRY (port);
674
675 if (pt->write_buf == &pt->shortbuf
676 || (pt->write_pos == pt->write_buf && size >= pt->write_buf_size))
677 {
678 /* "unbuffered" port, or
679 port with empty buffer and data won't fit in buffer. */
680 write_all (port, data, size);
681 return;
682 }
683
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 {
694 fport_flush (port);
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 }
718 }
719 }
720
721 /* handle line buffering. */
722 if ((SCM_CELL_WORD_0 (port) & SCM_BUFLINE) && memchr (data, '\n', size))
723 fport_flush (port);
724 }
725 }
726
727 /* becomes 1 when process is exiting: normal exception handling won't
728 work by this time. */
729 extern int scm_i_terminating;
730
731 static void
732 fport_flush (SCM port)
733 {
734 scm_t_port *pt = SCM_PTAB_ENTRY (port);
735 scm_t_fport *fp = SCM_FSTREAM (port);
736 unsigned char *ptr = pt->write_buf;
737 long init_size = pt->write_pos - pt->write_buf;
738 long remaining = init_size;
739
740 while (remaining > 0)
741 {
742 long count;
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. */
749 long done = init_size - remaining;
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 }
761 if (scm_i_terminating)
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 }
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");
780 }
781 ptr += count;
782 remaining -= count;
783 }
784 pt->write_pos = pt->write_buf;
785 pt->rw_active = SCM_PORT_NEITHER;
786 }
787
788 /* clear the read buffer and adjust the file position for unread bytes. */
789 static void
790 fport_end_input (SCM port, int offset)
791 {
792 scm_t_fport *fp = SCM_FSTREAM (port);
793 scm_t_port *pt = SCM_PTAB_ENTRY (port);
794
795 offset += pt->read_end - pt->read_pos;
796
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)
803 scm_syserror ("fport_end_input");
804 }
805 pt->rw_active = SCM_PORT_NEITHER;
806 }
807
808 static int
809 fport_close (SCM port)
810 {
811 scm_t_fport *fp = SCM_FSTREAM (port);
812 scm_t_port *pt = SCM_PTAB_ENTRY (port);
813 int rv;
814
815 fport_flush (port);
816 SCM_SYSCALL (rv = close (fp->fdes));
817 if (rv == -1 && errno != EBADF)
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 }
826 if (pt->read_buf == pt->putback_buf)
827 pt->read_buf = pt->saved_read_buf;
828 if (pt->read_buf != &pt->shortbuf)
829 scm_gc_free (pt->read_buf, pt->read_buf_size, "port buffer");
830 if (pt->write_buf != &pt->shortbuf)
831 scm_gc_free (pt->write_buf, pt->write_buf_size, "port buffer");
832 scm_gc_free (fp, sizeof (*fp), "file port");
833 return rv;
834 }
835
836 static size_t
837 fport_free (SCM port)
838 {
839 fport_close (port);
840 return 0;
841 }
842
843 static scm_t_bits
844 scm_make_fptob ()
845 {
846 scm_t_bits tc = scm_make_port_type ("file", fport_fill_input, fport_write);
847
848 scm_set_port_free (tc, fport_free);
849 scm_set_port_print (tc, fport_print);
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);
856
857 return tc;
858 }
859
860 void
861 scm_init_fports ()
862 {
863 scm_tc16_fport = scm_make_fptob ();
864
865 scm_c_define ("_IOFBF", SCM_MAKINUM (_IOFBF));
866 scm_c_define ("_IOLBF", SCM_MAKINUM (_IOLBF));
867 scm_c_define ("_IONBF", SCM_MAKINUM (_IONBF));
868
869 #include "libguile/fports.x"
870 }
871
872 /*
873 Local Variables:
874 c-file-style: "gnu"
875 End:
876 */