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