fix scm_protects deprecation warning
[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 (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_port *pt;
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 scm_i_scm_pthread_mutex_lock (&scm_i_port_table_mutex);
557
558 port = scm_new_port_table_entry (scm_tc16_fport);
559 SCM_SET_CELL_TYPE(port, scm_tc16_fport | mode_bits);
560 pt = SCM_PTAB_ENTRY(port);
561 {
562 scm_t_fport *fp
563 = (scm_t_fport *) scm_gc_malloc_pointerless (sizeof (scm_t_fport),
564 "file port");
565
566 fp->fdes = fdes;
567 pt->rw_random = SCM_FDES_RANDOM_P (fdes);
568 SCM_SETSTREAM (port, fp);
569 if (mode_bits & SCM_BUF0)
570 scm_fport_buffer_add (port, 0, 0);
571 else
572 scm_fport_buffer_add (port, -1, -1);
573 }
574 SCM_SET_FILENAME (port, name);
575 scm_i_pthread_mutex_unlock (&scm_i_port_table_mutex);
576 return port;
577 }
578 #undef FUNC_NAME
579
580 SCM
581 scm_fdes_to_port (int fdes, char *mode, SCM name)
582 {
583 return scm_i_fdes_to_port (fdes, scm_mode_bits (mode), name);
584 }
585
586 /* Return a lower bound on the number of bytes available for input. */
587 static int
588 fport_input_waiting (SCM port)
589 {
590 int fdes = SCM_FSTREAM (port)->fdes;
591
592 /* `FD_SETSIZE', which is 1024 on GNU systems, effectively limits the
593 highest numerical value of file descriptors that can be monitored.
594 Thus, use poll(2) whenever that is possible. */
595
596 #ifdef HAVE_POLL
597 struct pollfd pollfd = { fdes, POLLIN, 0 };
598
599 if (poll (&pollfd, 1, 0) < 0)
600 scm_syserror ("fport_input_waiting");
601
602 return pollfd.revents & POLLIN ? 1 : 0;
603
604 #elif defined(HAVE_SELECT)
605 struct timeval timeout;
606 SELECT_TYPE read_set;
607 SELECT_TYPE write_set;
608 SELECT_TYPE except_set;
609
610 FD_ZERO (&read_set);
611 FD_ZERO (&write_set);
612 FD_ZERO (&except_set);
613
614 FD_SET (fdes, &read_set);
615
616 timeout.tv_sec = 0;
617 timeout.tv_usec = 0;
618
619 if (select (SELECT_SET_SIZE,
620 &read_set, &write_set, &except_set, &timeout)
621 < 0)
622 scm_syserror ("fport_input_waiting");
623 return FD_ISSET (fdes, &read_set) ? 1 : 0;
624
625 #elif HAVE_IOCTL && defined (FIONREAD)
626 /* Note: cannot test just defined(FIONREAD) here, since mingw has FIONREAD
627 (for use with winsock ioctlsocket()) but not ioctl(). */
628 int fdes = SCM_FSTREAM (port)->fdes;
629 int remir;
630 ioctl(fdes, FIONREAD, &remir);
631 return remir;
632
633 #else
634 scm_misc_error ("fport_input_waiting",
635 "Not fully implemented on this platform",
636 SCM_EOL);
637 #endif
638 }
639
640 \f
641 static int
642 fport_print (SCM exp, SCM port, scm_print_state *pstate SCM_UNUSED)
643 {
644 scm_puts ("#<", port);
645 scm_print_port_mode (exp, port);
646 if (SCM_OPFPORTP (exp))
647 {
648 int fdes;
649 SCM name = SCM_FILENAME (exp);
650 if (scm_is_string (name) || scm_is_symbol (name))
651 scm_display (name, port);
652 else
653 scm_puts (SCM_PTOBNAME (SCM_PTOBNUM (exp)), port);
654 scm_putc (' ', port);
655 fdes = (SCM_FSTREAM (exp))->fdes;
656
657 #if (defined HAVE_TTYNAME) && (defined HAVE_POSIX)
658 if (isatty (fdes))
659 scm_display (scm_ttyname (exp), port);
660 else
661 #endif /* HAVE_TTYNAME */
662 scm_intprint (fdes, 10, port);
663 }
664 else
665 {
666 scm_puts (SCM_PTOBNAME (SCM_PTOBNUM (exp)), port);
667 scm_putc (' ', port);
668 scm_uintprint ((scm_t_bits) SCM_PTAB_ENTRY (exp), 16, port);
669 }
670 scm_putc ('>', port);
671 return 1;
672 }
673
674 static void fport_flush (SCM port);
675
676 /* fill a port's read-buffer with a single read. returns the first
677 char or EOF if end of file. */
678 static scm_t_wchar
679 fport_fill_input (SCM port)
680 {
681 long count;
682 scm_t_port *pt = SCM_PTAB_ENTRY (port);
683 scm_t_fport *fp = SCM_FSTREAM (port);
684
685 SCM_SYSCALL (count = read (fp->fdes, pt->read_buf, pt->read_buf_size));
686 if (count == -1)
687 scm_syserror ("fport_fill_input");
688 if (count == 0)
689 return (scm_t_wchar) EOF;
690 else
691 {
692 pt->read_pos = pt->read_buf;
693 pt->read_end = pt->read_buf + count;
694 return *pt->read_buf;
695 }
696 }
697
698 static scm_t_off
699 fport_seek (SCM port, scm_t_off offset, int whence)
700 {
701 scm_t_port *pt = SCM_PTAB_ENTRY (port);
702 scm_t_fport *fp = SCM_FSTREAM (port);
703 off_t_or_off64_t rv;
704 off_t_or_off64_t result;
705
706 if (pt->rw_active == SCM_PORT_WRITE)
707 {
708 if (offset != 0 || whence != SEEK_CUR)
709 {
710 fport_flush (port);
711 result = rv = lseek_or_lseek64 (fp->fdes, offset, whence);
712 }
713 else
714 {
715 /* read current position without disturbing the buffer. */
716 rv = lseek_or_lseek64 (fp->fdes, offset, whence);
717 result = rv + (pt->write_pos - pt->write_buf);
718 }
719 }
720 else if (pt->rw_active == SCM_PORT_READ)
721 {
722 if (offset != 0 || whence != SEEK_CUR)
723 {
724 /* could expand to avoid a second seek. */
725 scm_end_input (port);
726 result = rv = lseek_or_lseek64 (fp->fdes, offset, whence);
727 }
728 else
729 {
730 /* read current position without disturbing the buffer
731 (particularly the unread-char buffer). */
732 rv = lseek_or_lseek64 (fp->fdes, offset, whence);
733 result = rv - (pt->read_end - pt->read_pos);
734
735 if (pt->read_buf == pt->putback_buf)
736 result -= pt->saved_read_end - pt->saved_read_pos;
737 }
738 }
739 else /* SCM_PORT_NEITHER */
740 {
741 result = rv = lseek_or_lseek64 (fp->fdes, offset, whence);
742 }
743
744 if (rv == -1)
745 scm_syserror ("fport_seek");
746
747 return result;
748 }
749
750 static void
751 fport_truncate (SCM port, scm_t_off length)
752 {
753 scm_t_fport *fp = SCM_FSTREAM (port);
754
755 if (ftruncate (fp->fdes, length) == -1)
756 scm_syserror ("ftruncate");
757 }
758
759 static void
760 fport_write (SCM port, const void *data, size_t size)
761 #define FUNC_NAME "fport_write"
762 {
763 /* this procedure tries to minimize the number of writes/flushes. */
764 scm_t_port *pt = SCM_PTAB_ENTRY (port);
765
766 if (pt->write_buf == &pt->shortbuf
767 || (pt->write_pos == pt->write_buf && size >= pt->write_buf_size))
768 {
769 /* Unbuffered port, or port with empty buffer and data won't fit in
770 buffer. */
771 if (full_write (SCM_FPORT_FDES (port), data, size) < size)
772 SCM_SYSERROR;
773
774 return;
775 }
776
777 {
778 scm_t_off space = pt->write_end - pt->write_pos;
779
780 if (size <= space)
781 {
782 /* data fits in buffer. */
783 memcpy (pt->write_pos, data, size);
784 pt->write_pos += size;
785 if (pt->write_pos == pt->write_end)
786 {
787 fport_flush (port);
788 /* we can skip the line-buffering check if nothing's buffered. */
789 return;
790 }
791 }
792 else
793 {
794 memcpy (pt->write_pos, data, space);
795 pt->write_pos = pt->write_end;
796 fport_flush (port);
797 {
798 const void *ptr = ((const char *) data) + space;
799 size_t remaining = size - space;
800
801 if (size >= pt->write_buf_size)
802 {
803 if (full_write (SCM_FPORT_FDES (port), ptr, remaining)
804 < remaining)
805 SCM_SYSERROR;
806 return;
807 }
808 else
809 {
810 memcpy (pt->write_pos, ptr, remaining);
811 pt->write_pos += remaining;
812 }
813 }
814 }
815
816 /* handle line buffering. */
817 if ((SCM_CELL_WORD_0 (port) & SCM_BUFLINE) && memchr (data, '\n', size))
818 fport_flush (port);
819 }
820 }
821 #undef FUNC_NAME
822
823 static void
824 fport_flush (SCM port)
825 {
826 size_t written;
827 scm_t_port *pt = SCM_PTAB_ENTRY (port);
828 scm_t_fport *fp = SCM_FSTREAM (port);
829 size_t count = pt->write_pos - pt->write_buf;
830
831 written = full_write (fp->fdes, pt->write_buf, count);
832 if (written < count)
833 scm_syserror ("scm_flush");
834
835 pt->write_pos = pt->write_buf;
836 pt->rw_active = SCM_PORT_NEITHER;
837 }
838
839 /* clear the read buffer and adjust the file position for unread bytes. */
840 static void
841 fport_end_input (SCM port, int offset)
842 {
843 scm_t_fport *fp = SCM_FSTREAM (port);
844 scm_t_port *pt = SCM_PTAB_ENTRY (port);
845
846 offset += pt->read_end - pt->read_pos;
847
848 if (offset > 0)
849 {
850 pt->read_pos = pt->read_end;
851 /* will throw error if unread-char used at beginning of file
852 then attempting to write. seems correct. */
853 if (lseek (fp->fdes, -offset, SEEK_CUR) == -1)
854 scm_syserror ("fport_end_input");
855 }
856 pt->rw_active = SCM_PORT_NEITHER;
857 }
858
859 static int
860 fport_close (SCM port)
861 {
862 scm_t_fport *fp = SCM_FSTREAM (port);
863 scm_t_port *pt = SCM_PTAB_ENTRY (port);
864 int rv;
865
866 fport_flush (port);
867 SCM_SYSCALL (rv = close (fp->fdes));
868 if (rv == -1 && errno != EBADF)
869 {
870 if (scm_gc_running_p)
871 /* silently ignore the error. scm_error would abort if we
872 called it now. */
873 ;
874 else
875 scm_syserror ("fport_close");
876 }
877 if (pt->read_buf == pt->putback_buf)
878 pt->read_buf = pt->saved_read_buf;
879 if (pt->read_buf != &pt->shortbuf)
880 scm_gc_free (pt->read_buf, pt->read_buf_size, "port buffer");
881 if (pt->write_buf != &pt->shortbuf)
882 scm_gc_free (pt->write_buf, pt->write_buf_size, "port buffer");
883 scm_gc_free (fp, sizeof (*fp), "file port");
884 return rv;
885 }
886
887 static size_t
888 fport_free (SCM port)
889 {
890 fport_close (port);
891 return 0;
892 }
893
894 static scm_t_bits
895 scm_make_fptob ()
896 {
897 scm_t_bits tc = scm_make_port_type ("file", fport_fill_input, fport_write);
898
899 scm_set_port_free (tc, fport_free);
900 scm_set_port_print (tc, fport_print);
901 scm_set_port_flush (tc, fport_flush);
902 scm_set_port_end_input (tc, fport_end_input);
903 scm_set_port_close (tc, fport_close);
904 scm_set_port_seek (tc, fport_seek);
905 scm_set_port_truncate (tc, fport_truncate);
906 scm_set_port_input_waiting (tc, fport_input_waiting);
907
908 return tc;
909 }
910
911 void
912 scm_init_fports ()
913 {
914 scm_tc16_fport = scm_make_fptob ();
915
916 scm_c_define ("_IOFBF", scm_from_int (_IOFBF));
917 scm_c_define ("_IOLBF", scm_from_int (_IOLBF));
918 scm_c_define ("_IONBF", scm_from_int (_IONBF));
919
920 sys_file_port_name_canonicalization = scm_make_fluid ();
921 scm_c_define ("%file-port-name-canonicalization",
922 sys_file_port_name_canonicalization);
923
924 #include "libguile/fports.x"
925 }
926
927 /*
928 Local Variables:
929 c-file-style: "gnu"
930 End:
931 */