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