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