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