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