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