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