Merge branch 'master' into boehm-demers-weiser-gc
[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_pointerless (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_pointerless (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_port *p;
234 scm_t_fport *fp;
235
236 /* XXX: In some cases, we can encounter a port with no associated ptab
237 entry. */
238 p = SCM_PTAB_ENTRY (port);
239 fp = (p != NULL) ? (scm_t_fport *) p->stream : NULL;
240
241 if ((fp != NULL) && (fp->fdes == fd))
242 {
243 fp->fdes = dup (fd);
244 if (fp->fdes == -1)
245 scm_syserror ("scm_evict_ports");
246 scm_set_port_revealed_x (port, scm_from_int (0));
247 }
248 }
249 }
250
251 void
252 scm_evict_ports (int fd)
253 {
254 scm_c_port_for_each (scm_i_evict_port, (void *) &fd);
255 }
256
257
258 SCM_DEFINE (scm_file_port_p, "file-port?", 1, 0, 0,
259 (SCM obj),
260 "Determine whether @var{obj} is a port that is related to a file.")
261 #define FUNC_NAME s_scm_file_port_p
262 {
263 return scm_from_bool (SCM_FPORTP (obj));
264 }
265 #undef FUNC_NAME
266
267
268 /* scm_open_file
269 * Return a new port open on a given file.
270 *
271 * The mode string must match the pattern: [rwa+]** which
272 * is interpreted in the usual unix way.
273 *
274 * Return the new port.
275 */
276 SCM_DEFINE (scm_open_file, "open-file", 2, 0, 0,
277 (SCM filename, SCM mode),
278 "Open the file whose name is @var{filename}, and return a port\n"
279 "representing that file. The attributes of the port are\n"
280 "determined by the @var{mode} string. The way in which this is\n"
281 "interpreted is similar to C stdio. The first character must be\n"
282 "one of the following:\n"
283 "@table @samp\n"
284 "@item r\n"
285 "Open an existing file for input.\n"
286 "@item w\n"
287 "Open a file for output, creating it if it doesn't already exist\n"
288 "or removing its contents if it does.\n"
289 "@item a\n"
290 "Open a file for output, creating it if it doesn't already\n"
291 "exist. All writes to the port will go to the end of the file.\n"
292 "The \"append mode\" can be turned off while the port is in use\n"
293 "@pxref{Ports and File Descriptors, fcntl}\n"
294 "@end table\n"
295 "The following additional characters can be appended:\n"
296 "@table @samp\n"
297 "@item b\n"
298 "Open the underlying file in binary mode, if supported by the operating system. "
299 "@item +\n"
300 "Open the port for both input and output. E.g., @code{r+}: open\n"
301 "an existing file for both input and output.\n"
302 "@item 0\n"
303 "Create an \"unbuffered\" port. In this case input and output\n"
304 "operations are passed directly to the underlying port\n"
305 "implementation without additional buffering. This is likely to\n"
306 "slow down I/O operations. The buffering mode can be changed\n"
307 "while a port is in use @pxref{Ports and File Descriptors,\n"
308 "setvbuf}\n"
309 "@item l\n"
310 "Add line-buffering to the port. The port output buffer will be\n"
311 "automatically flushed whenever a newline character is written.\n"
312 "@end table\n"
313 "In theory we could create read/write ports which were buffered\n"
314 "in one direction only. However this isn't included in the\n"
315 "current interfaces. If a file cannot be opened with the access\n"
316 "requested, @code{open-file} throws an exception.")
317 #define FUNC_NAME s_scm_open_file
318 {
319 SCM port;
320 int fdes;
321 int flags = 0;
322 char *file;
323 char *md;
324 char *ptr;
325
326 scm_dynwind_begin (0);
327
328 file = scm_to_locale_string (filename);
329 scm_dynwind_free (file);
330
331 md = scm_to_locale_string (mode);
332 scm_dynwind_free (md);
333
334 switch (*md)
335 {
336 case 'r':
337 flags |= O_RDONLY;
338 break;
339 case 'w':
340 flags |= O_WRONLY | O_CREAT | O_TRUNC;
341 break;
342 case 'a':
343 flags |= O_WRONLY | O_CREAT | O_APPEND;
344 break;
345 default:
346 scm_out_of_range (FUNC_NAME, mode);
347 }
348 ptr = md + 1;
349 while (*ptr != '\0')
350 {
351 switch (*ptr)
352 {
353 case '+':
354 flags = (flags & ~(O_RDONLY | O_WRONLY)) | O_RDWR;
355 break;
356 case 'b':
357 #if defined (O_BINARY)
358 flags |= O_BINARY;
359 #endif
360 break;
361 case '0': /* unbuffered: handled later. */
362 case 'l': /* line buffered: handled during output. */
363 break;
364 default:
365 scm_out_of_range (FUNC_NAME, mode);
366 }
367 ptr++;
368 }
369 SCM_SYSCALL (fdes = open_or_open64 (file, flags, 0666));
370 if (fdes == -1)
371 {
372 int en = errno;
373
374 SCM_SYSERROR_MSG ("~A: ~S",
375 scm_cons (scm_strerror (scm_from_int (en)),
376 scm_cons (filename, SCM_EOL)), en);
377 }
378 port = scm_i_fdes_to_port (fdes, scm_i_mode_bits (mode), filename);
379
380 scm_dynwind_end ();
381
382 return port;
383 }
384 #undef FUNC_NAME
385
386 \f
387 #ifdef __MINGW32__
388 /*
389 * Try getting the appropiate file flags for a given file descriptor
390 * under Windows. This incorporates some fancy operations because Windows
391 * differentiates between file, pipe and socket descriptors.
392 */
393 #ifndef O_ACCMODE
394 # define O_ACCMODE 0x0003
395 #endif
396
397 static int getflags (int fdes)
398 {
399 int flags = 0;
400 struct stat buf;
401 int error, optlen = sizeof (int);
402
403 /* Is this a socket ? */
404 if (getsockopt (fdes, SOL_SOCKET, SO_ERROR, (void *) &error, &optlen) >= 0)
405 flags = O_RDWR;
406 /* Maybe a regular file ? */
407 else if (fstat (fdes, &buf) < 0)
408 flags = -1;
409 else
410 {
411 /* Or an anonymous pipe handle ? */
412 if (buf.st_mode & _S_IFIFO)
413 flags = PeekNamedPipe ((HANDLE) _get_osfhandle (fdes), NULL, 0,
414 NULL, NULL, NULL) ? O_RDONLY : O_WRONLY;
415 /* stdin ? */
416 else if (fdes == fileno (stdin) && isatty (fdes))
417 flags = O_RDONLY;
418 /* stdout / stderr ? */
419 else if ((fdes == fileno (stdout) || fdes == fileno (stderr)) &&
420 isatty (fdes))
421 flags = O_WRONLY;
422 else
423 flags = buf.st_mode;
424 }
425 return flags;
426 }
427 #endif /* __MINGW32__ */
428
429 /* Building Guile ports from a file descriptor. */
430
431 /* Build a Scheme port from an open file descriptor `fdes'.
432 MODE indicates whether FILE is open for reading or writing; it uses
433 the same notation as open-file's second argument.
434 NAME is a string to be used as the port's filename.
435 */
436 SCM
437 scm_i_fdes_to_port (int fdes, long mode_bits, SCM name)
438 #define FUNC_NAME "scm_fdes_to_port"
439 {
440 SCM port;
441 scm_t_port *pt;
442 int flags;
443
444 /* test that fdes is valid. */
445 #ifdef __MINGW32__
446 flags = getflags (fdes);
447 #else
448 flags = fcntl (fdes, F_GETFL, 0);
449 #endif
450 if (flags == -1)
451 SCM_SYSERROR;
452 flags &= O_ACCMODE;
453 if (flags != O_RDWR
454 && ((flags != O_WRONLY && (mode_bits & SCM_WRTNG))
455 || (flags != O_RDONLY && (mode_bits & SCM_RDNG))))
456 {
457 SCM_MISC_ERROR ("requested file mode not available on fdes", SCM_EOL);
458 }
459
460 scm_i_scm_pthread_mutex_lock (&scm_i_port_table_mutex);
461
462 port = scm_new_port_table_entry (scm_tc16_fport);
463 SCM_SET_CELL_TYPE(port, scm_tc16_fport | mode_bits);
464 pt = SCM_PTAB_ENTRY(port);
465 {
466 scm_t_fport *fp
467 = (scm_t_fport *) scm_gc_malloc_pointerless (sizeof (scm_t_fport),
468 "file port");
469
470 fp->fdes = fdes;
471 pt->rw_random = SCM_FDES_RANDOM_P (fdes);
472 SCM_SETSTREAM (port, fp);
473 if (mode_bits & SCM_BUF0)
474 scm_fport_buffer_add (port, 0, 0);
475 else
476 scm_fport_buffer_add (port, -1, -1);
477 }
478 SCM_SET_FILENAME (port, name);
479 scm_i_pthread_mutex_unlock (&scm_i_port_table_mutex);
480 return port;
481 }
482 #undef FUNC_NAME
483
484 SCM
485 scm_fdes_to_port (int fdes, char *mode, SCM name)
486 {
487 return scm_i_fdes_to_port (fdes, scm_mode_bits (mode), name);
488 }
489
490 /* Return a lower bound on the number of bytes available for input. */
491 static int
492 fport_input_waiting (SCM port)
493 {
494 #ifdef HAVE_SELECT
495 int fdes = SCM_FSTREAM (port)->fdes;
496 struct timeval timeout;
497 SELECT_TYPE read_set;
498 SELECT_TYPE write_set;
499 SELECT_TYPE except_set;
500
501 FD_ZERO (&read_set);
502 FD_ZERO (&write_set);
503 FD_ZERO (&except_set);
504
505 FD_SET (fdes, &read_set);
506
507 timeout.tv_sec = 0;
508 timeout.tv_usec = 0;
509
510 if (select (SELECT_SET_SIZE,
511 &read_set, &write_set, &except_set, &timeout)
512 < 0)
513 scm_syserror ("fport_input_waiting");
514 return FD_ISSET (fdes, &read_set) ? 1 : 0;
515
516 #elif HAVE_IOCTL && defined (FIONREAD)
517 /* Note: cannot test just defined(FIONREAD) here, since mingw has FIONREAD
518 (for use with winsock ioctlsocket()) but not ioctl(). */
519 int fdes = SCM_FSTREAM (port)->fdes;
520 int remir;
521 ioctl(fdes, FIONREAD, &remir);
522 return remir;
523
524 #else
525 scm_misc_error ("fport_input_waiting",
526 "Not fully implemented on this platform",
527 SCM_EOL);
528 #endif
529 }
530
531 \f
532 static int
533 fport_print (SCM exp, SCM port, scm_print_state *pstate SCM_UNUSED)
534 {
535 scm_puts ("#<", port);
536 scm_print_port_mode (exp, port);
537 if (SCM_OPFPORTP (exp))
538 {
539 int fdes;
540 SCM name = SCM_FILENAME (exp);
541 if (scm_is_string (name) || scm_is_symbol (name))
542 scm_display (name, port);
543 else
544 scm_puts (SCM_PTOBNAME (SCM_PTOBNUM (exp)), port);
545 scm_putc (' ', port);
546 fdes = (SCM_FSTREAM (exp))->fdes;
547
548 #ifdef HAVE_TTYNAME
549 if (isatty (fdes))
550 scm_display (scm_ttyname (exp), port);
551 else
552 #endif /* HAVE_TTYNAME */
553 scm_intprint (fdes, 10, port);
554 }
555 else
556 {
557 scm_puts (SCM_PTOBNAME (SCM_PTOBNUM (exp)), port);
558 scm_putc (' ', port);
559 scm_uintprint ((scm_t_bits) SCM_PTAB_ENTRY (exp), 16, port);
560 }
561 scm_putc ('>', port);
562 return 1;
563 }
564
565 #ifndef __MINGW32__
566 /* thread-local block for input on fport's fdes. */
567 static void
568 fport_wait_for_input (SCM port)
569 {
570 int fdes = SCM_FSTREAM (port)->fdes;
571
572 if (!fport_input_waiting (port))
573 {
574 int n;
575 SELECT_TYPE readfds;
576 int flags = fcntl (fdes, F_GETFL);
577
578 if (flags == -1)
579 scm_syserror ("scm_fdes_wait_for_input");
580 if (!(flags & O_NONBLOCK))
581 do
582 {
583 FD_ZERO (&readfds);
584 FD_SET (fdes, &readfds);
585 n = scm_std_select (fdes + 1, &readfds, NULL, NULL, NULL);
586 }
587 while (n == -1 && errno == EINTR);
588 }
589 }
590 #endif /* !__MINGW32__ */
591
592 static void fport_flush (SCM port);
593
594 /* fill a port's read-buffer with a single read. returns the first
595 char or EOF if end of file. */
596 static int
597 fport_fill_input (SCM port)
598 {
599 long count;
600 scm_t_port *pt = SCM_PTAB_ENTRY (port);
601 scm_t_fport *fp = SCM_FSTREAM (port);
602
603 #ifndef __MINGW32__
604 fport_wait_for_input (port);
605 #endif /* !__MINGW32__ */
606 SCM_SYSCALL (count = read (fp->fdes, pt->read_buf, pt->read_buf_size));
607 if (count == -1)
608 scm_syserror ("fport_fill_input");
609 if (count == 0)
610 return EOF;
611 else
612 {
613 pt->read_pos = pt->read_buf;
614 pt->read_end = pt->read_buf + count;
615 return *pt->read_buf;
616 }
617 }
618
619 static off_t_or_off64_t
620 fport_seek_or_seek64 (SCM port, off_t_or_off64_t offset, int whence)
621 {
622 scm_t_port *pt = SCM_PTAB_ENTRY (port);
623 scm_t_fport *fp = SCM_FSTREAM (port);
624 off_t_or_off64_t rv;
625 off_t_or_off64_t result;
626
627 if (pt->rw_active == SCM_PORT_WRITE)
628 {
629 if (offset != 0 || whence != SEEK_CUR)
630 {
631 fport_flush (port);
632 result = rv = lseek_or_lseek64 (fp->fdes, offset, whence);
633 }
634 else
635 {
636 /* read current position without disturbing the buffer. */
637 rv = lseek_or_lseek64 (fp->fdes, offset, whence);
638 result = rv + (pt->write_pos - pt->write_buf);
639 }
640 }
641 else if (pt->rw_active == SCM_PORT_READ)
642 {
643 if (offset != 0 || whence != SEEK_CUR)
644 {
645 /* could expand to avoid a second seek. */
646 scm_end_input (port);
647 result = rv = lseek_or_lseek64 (fp->fdes, offset, whence);
648 }
649 else
650 {
651 /* read current position without disturbing the buffer
652 (particularly the unread-char buffer). */
653 rv = lseek_or_lseek64 (fp->fdes, offset, whence);
654 result = rv - (pt->read_end - pt->read_pos);
655
656 if (pt->read_buf == pt->putback_buf)
657 result -= pt->saved_read_end - pt->saved_read_pos;
658 }
659 }
660 else /* SCM_PORT_NEITHER */
661 {
662 result = rv = lseek_or_lseek64 (fp->fdes, offset, whence);
663 }
664
665 if (rv == -1)
666 scm_syserror ("fport_seek");
667
668 return result;
669 }
670
671 /* If we've got largefile and off_t isn't already off64_t then
672 fport_seek_or_seek64 needs a range checking wrapper to be fport_seek in
673 the port descriptor.
674
675 Otherwise if no largefile, or off_t is the same as off64_t (which is the
676 case on NetBSD apparently), then fport_seek_or_seek64 is right to be
677 fport_seek already. */
678
679 #if GUILE_USE_64_CALLS && HAVE_STAT64 && SIZEOF_OFF_T != SIZEOF_OFF64_T
680 static off_t
681 fport_seek (SCM port, off_t offset, int whence)
682 {
683 off64_t rv = fport_seek_or_seek64 (port, (off64_t) offset, whence);
684 if (rv > OFF_T_MAX || rv < OFF_T_MIN)
685 {
686 errno = EOVERFLOW;
687 scm_syserror ("fport_seek");
688 }
689 return (off_t) rv;
690
691 }
692 #else
693 #define fport_seek fport_seek_or_seek64
694 #endif
695
696 /* `how' has been validated and is one of SEEK_SET, SEEK_CUR or SEEK_END */
697 SCM
698 scm_i_fport_seek (SCM port, SCM offset, int how)
699 {
700 return scm_from_off_t_or_off64_t
701 (fport_seek_or_seek64 (port, scm_to_off_t_or_off64_t (offset), how));
702 }
703
704 static void
705 fport_truncate (SCM port, off_t length)
706 {
707 scm_t_fport *fp = SCM_FSTREAM (port);
708
709 if (ftruncate (fp->fdes, length) == -1)
710 scm_syserror ("ftruncate");
711 }
712
713 int
714 scm_i_fport_truncate (SCM port, SCM length)
715 {
716 scm_t_fport *fp = SCM_FSTREAM (port);
717 return ftruncate_or_ftruncate64 (fp->fdes, scm_to_off_t_or_off64_t (length));
718 }
719
720 /* helper for fport_write: try to write data, using multiple system
721 calls if required. */
722 #define FUNC_NAME "write_all"
723 static void write_all (SCM port, const void *data, size_t remaining)
724 {
725 int fdes = SCM_FSTREAM (port)->fdes;
726
727 while (remaining > 0)
728 {
729 size_t done;
730
731 SCM_SYSCALL (done = write (fdes, data, remaining));
732
733 if (done == -1)
734 SCM_SYSERROR;
735 remaining -= done;
736 data = ((const char *) data) + done;
737 }
738 }
739 #undef FUNC_NAME
740
741 static void
742 fport_write (SCM port, const void *data, size_t size)
743 {
744 /* this procedure tries to minimize the number of writes/flushes. */
745 scm_t_port *pt = SCM_PTAB_ENTRY (port);
746
747 if (pt->write_buf == &pt->shortbuf
748 || (pt->write_pos == pt->write_buf && size >= pt->write_buf_size))
749 {
750 /* "unbuffered" port, or
751 port with empty buffer and data won't fit in buffer. */
752 write_all (port, data, size);
753 return;
754 }
755
756 {
757 off_t space = pt->write_end - pt->write_pos;
758
759 if (size <= space)
760 {
761 /* data fits in buffer. */
762 memcpy (pt->write_pos, data, size);
763 pt->write_pos += size;
764 if (pt->write_pos == pt->write_end)
765 {
766 fport_flush (port);
767 /* we can skip the line-buffering check if nothing's buffered. */
768 return;
769 }
770 }
771 else
772 {
773 memcpy (pt->write_pos, data, space);
774 pt->write_pos = pt->write_end;
775 fport_flush (port);
776 {
777 const void *ptr = ((const char *) data) + space;
778 size_t remaining = size - space;
779
780 if (size >= pt->write_buf_size)
781 {
782 write_all (port, ptr, remaining);
783 return;
784 }
785 else
786 {
787 memcpy (pt->write_pos, ptr, remaining);
788 pt->write_pos += remaining;
789 }
790 }
791 }
792
793 /* handle line buffering. */
794 if ((SCM_CELL_WORD_0 (port) & SCM_BUFLINE) && memchr (data, '\n', size))
795 fport_flush (port);
796 }
797 }
798
799 /* becomes 1 when process is exiting: normal exception handling won't
800 work by this time. */
801 extern int scm_i_terminating;
802
803 static void
804 fport_flush (SCM port)
805 {
806 scm_t_port *pt = SCM_PTAB_ENTRY (port);
807 scm_t_fport *fp = SCM_FSTREAM (port);
808 unsigned char *ptr = pt->write_buf;
809 long init_size = pt->write_pos - pt->write_buf;
810 long remaining = init_size;
811
812 while (remaining > 0)
813 {
814 long count;
815
816 SCM_SYSCALL (count = write (fp->fdes, ptr, remaining));
817 if (count < 0)
818 {
819 /* error. assume nothing was written this call, but
820 fix up the buffer for any previous successful writes. */
821 long done = init_size - remaining;
822
823 if (done > 0)
824 {
825 int i;
826
827 for (i = 0; i < remaining; i++)
828 {
829 *(pt->write_buf + i) = *(pt->write_buf + done + i);
830 }
831 pt->write_pos = pt->write_buf + remaining;
832 }
833 if (scm_i_terminating)
834 {
835 const char *msg = "Error: could not flush file-descriptor ";
836 char buf[11];
837
838 full_write (2, msg, strlen (msg));
839 sprintf (buf, "%d\n", fp->fdes);
840 full_write (2, buf, strlen (buf));
841
842 count = remaining;
843 }
844 else if (scm_gc_running_p)
845 {
846 /* silently ignore the error. scm_error would abort if we
847 called it now. */
848 count = remaining;
849 }
850 else
851 scm_syserror ("fport_flush");
852 }
853 ptr += count;
854 remaining -= count;
855 }
856 pt->write_pos = pt->write_buf;
857 pt->rw_active = SCM_PORT_NEITHER;
858 }
859
860 /* clear the read buffer and adjust the file position for unread bytes. */
861 static void
862 fport_end_input (SCM port, int offset)
863 {
864 scm_t_fport *fp = SCM_FSTREAM (port);
865 scm_t_port *pt = SCM_PTAB_ENTRY (port);
866
867 offset += pt->read_end - pt->read_pos;
868
869 if (offset > 0)
870 {
871 pt->read_pos = pt->read_end;
872 /* will throw error if unread-char used at beginning of file
873 then attempting to write. seems correct. */
874 if (lseek (fp->fdes, -offset, SEEK_CUR) == -1)
875 scm_syserror ("fport_end_input");
876 }
877 pt->rw_active = SCM_PORT_NEITHER;
878 }
879
880 static int
881 fport_close (SCM port)
882 {
883 scm_t_fport *fp = SCM_FSTREAM (port);
884 scm_t_port *pt = SCM_PTAB_ENTRY (port);
885 int rv;
886
887 fport_flush (port);
888 SCM_SYSCALL (rv = close (fp->fdes));
889 if (rv == -1 && errno != EBADF)
890 {
891 if (scm_gc_running_p)
892 /* silently ignore the error. scm_error would abort if we
893 called it now. */
894 ;
895 else
896 scm_syserror ("fport_close");
897 }
898 if (pt->read_buf == pt->putback_buf)
899 pt->read_buf = pt->saved_read_buf;
900 if (pt->read_buf != &pt->shortbuf)
901 scm_gc_free (pt->read_buf, pt->read_buf_size, "port buffer");
902 if (pt->write_buf != &pt->shortbuf)
903 scm_gc_free (pt->write_buf, pt->write_buf_size, "port buffer");
904 scm_gc_free (fp, sizeof (*fp), "file port");
905 return rv;
906 }
907
908 static size_t
909 fport_free (SCM port)
910 {
911 fport_close (port);
912 return 0;
913 }
914
915 static scm_t_bits
916 scm_make_fptob ()
917 {
918 scm_t_bits tc = scm_make_port_type ("file", fport_fill_input, fport_write);
919
920 scm_set_port_free (tc, fport_free);
921 scm_set_port_print (tc, fport_print);
922 scm_set_port_flush (tc, fport_flush);
923 scm_set_port_end_input (tc, fport_end_input);
924 scm_set_port_close (tc, fport_close);
925 scm_set_port_seek (tc, fport_seek);
926 scm_set_port_truncate (tc, fport_truncate);
927 scm_set_port_input_waiting (tc, fport_input_waiting);
928
929 return tc;
930 }
931
932 void
933 scm_init_fports ()
934 {
935 scm_tc16_fport = scm_make_fptob ();
936
937 scm_c_define ("_IOFBF", scm_from_int (_IOFBF));
938 scm_c_define ("_IOLBF", scm_from_int (_IOLBF));
939 scm_c_define ("_IONBF", scm_from_int (_IONBF));
940
941 #include "libguile/fports.x"
942 }
943
944 /*
945 Local Variables:
946 c-file-style: "gnu"
947 End:
948 */