Merge commit 'd364a8971828e38e8f9112b711066f4962bb400e'
[bpt/guile.git] / libguile / fports.c
CommitLineData
073167ef 1/* Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
4c187d46 2 * 2004, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc.
073167ef 3 *
73be1d9e 4 * This library is free software; you can redistribute it and/or
53befeb7
NJ
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.
0f2d19dd 8 *
53befeb7
NJ
9 * This library is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
73be1d9e
MV
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
0f2d19dd 13 *
73be1d9e
MV
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
53befeb7
NJ
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 * 02110-1301 USA
73be1d9e 18 */
1bbd0b84 19
1bbd0b84 20
0f2d19dd 21\f
8ab3d8a0 22#define _LARGEFILE64_SOURCE /* ask for stat64 etc */
9858e529 23#define _GNU_SOURCE /* ask for LONG_LONG_MAX/LONG_LONG_MIN */
8ab3d8a0 24
dbb605f5 25#ifdef HAVE_CONFIG_H
85286595
RB
26# include <config.h>
27#endif
0f2d19dd
JB
28
29#include <stdio.h>
cb63cf9e 30#include <fcntl.h>
95b88819
GH
31
32#ifdef HAVE_STRING_H
33#include <string.h>
34#endif
0f2d19dd
JB
35#ifdef HAVE_UNISTD_H
36#include <unistd.h>
0f2d19dd 37#endif
b8b17bfd
MV
38#ifdef HAVE_IO_H
39#include <io.h>
40#endif
f47a5239 41#ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
cb63cf9e
JB
42#include <sys/stat.h>
43#endif
c7519da3 44#include <poll.h>
cb63cf9e 45#include <errno.h>
8ab3d8a0 46#include <sys/types.h>
09b204d3 47#include <sys/stat.h>
629987ed 48#include <sys/select.h>
e145dd02 49
5335850d
LC
50#include <full-write.h>
51
629987ed
AW
52#include "libguile/_scm.h"
53#include "libguile/strings.h"
54#include "libguile/validate.h"
55#include "libguile/gc.h"
56#include "libguile/posix.h"
57#include "libguile/dynwind.h"
58#include "libguile/hashtab.h"
8ab3d8a0 59
629987ed 60#include "libguile/fports.h"
8ab3d8a0
KR
61
62#if SIZEOF_OFF_T == SIZEOF_INT
63#define OFF_T_MAX INT_MAX
64#define OFF_T_MIN INT_MIN
65#elif SIZEOF_OFF_T == SIZEOF_LONG
66#define OFF_T_MAX LONG_MAX
67#define OFF_T_MIN LONG_MIN
68#elif SIZEOF_OFF_T == SIZEOF_LONG_LONG
69#define OFF_T_MAX LONG_LONG_MAX
70#define OFF_T_MIN LONG_LONG_MIN
71#else
72#error Oops, unknown OFF_T size
73#endif
a98bddfd 74
92c2555f 75scm_t_bits scm_tc16_fport;
a98bddfd
DH
76
77
19b27fa2 78/* default buffer size, used if the O/S won't supply a value. */
1be6b49c 79static const size_t default_buffer_size = 1024;
19b27fa2 80
cb63cf9e
JB
81/* create FPORT buffer with specified sizes (or -1 to use default size or
82 0 for no buffer. */
83static void
c014a02e 84scm_fport_buffer_add (SCM port, long read_size, int write_size)
c6c79933 85#define FUNC_NAME "scm_fport_buffer_add"
e145dd02 86{
92c2555f 87 scm_t_port *pt = SCM_PTAB_ENTRY (port);
e145dd02 88
cb63cf9e
JB
89 if (read_size == -1 || write_size == -1)
90 {
1be6b49c 91 size_t default_size;
f47a5239 92#ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
cb63cf9e 93 struct stat st;
b8b17bfd 94 scm_t_fport *fp = SCM_FSTREAM (port);
cb63cf9e 95
19b27fa2
GH
96 default_size = (fstat (fp->fdes, &st) == -1) ? default_buffer_size
97 : st.st_blksize;
cb63cf9e 98#else
19b27fa2 99 default_size = default_buffer_size;
cb63cf9e
JB
100#endif
101 if (read_size == -1)
102 read_size = default_size;
103 if (write_size == -1)
104 write_size = default_size;
105 }
0f2d19dd 106
f5f2dcff 107 if (SCM_INPUT_PORT_P (port) && read_size > 0)
cb63cf9e 108 {
92d8fd32 109 pt->read_buf = scm_gc_malloc_pointerless (read_size, "port buffer");
cb63cf9e
JB
110 pt->read_pos = pt->read_end = pt->read_buf;
111 pt->read_buf_size = read_size;
112 }
113 else
114 {
840ae05d 115 pt->read_pos = pt->read_buf = pt->read_end = &pt->shortbuf;
cb63cf9e
JB
116 pt->read_buf_size = 1;
117 }
1717856b 118
f5f2dcff 119 if (SCM_OUTPUT_PORT_P (port) && write_size > 0)
cb63cf9e 120 {
92d8fd32 121 pt->write_buf = scm_gc_malloc_pointerless (write_size, "port buffer");
cb63cf9e
JB
122 pt->write_pos = pt->write_buf;
123 pt->write_buf_size = write_size;
124 }
125 else
126 {
127 pt->write_buf = pt->write_pos = &pt->shortbuf;
128 pt->write_buf_size = 1;
129 }
130
131 pt->write_end = pt->write_buf + pt->write_buf_size;
132 if (read_size > 0 || write_size > 0)
54778cd3 133 SCM_SET_CELL_WORD_0 (port, SCM_CELL_WORD_0 (port) & ~SCM_BUF0);
cb63cf9e 134 else
54778cd3 135 SCM_SET_CELL_WORD_0 (port, SCM_CELL_WORD_0 (port) | SCM_BUF0);
7a6f1ffa 136}
c6c79933 137#undef FUNC_NAME
7a6f1ffa 138
a1ec6916 139SCM_DEFINE (scm_setvbuf, "setvbuf", 2, 1, 0,
1bbd0b84 140 (SCM port, SCM mode, SCM size),
fc0d72d4
MD
141 "Set the buffering mode for @var{port}. @var{mode} can be:\n"
142 "@table @code\n"
143 "@item _IONBF\n"
144 "non-buffered\n"
145 "@item _IOLBF\n"
146 "line buffered\n"
147 "@item _IOFBF\n"
148 "block buffered, using a newly allocated buffer of @var{size} bytes.\n"
149 "If @var{size} is omitted, a default size will be used.\n"
2c1ae20e 150 "@end table")
1bbd0b84 151#define FUNC_NAME s_scm_setvbuf
7a6f1ffa 152{
1be6b49c 153 int cmode;
c014a02e 154 long csize;
e8b21eec
LC
155 size_t ndrained;
156 char *drained;
92c2555f 157 scm_t_port *pt;
7a6f1ffa 158
78446828
MV
159 port = SCM_COERCE_OUTPORT (port);
160
3b3b36dd 161 SCM_VALIDATE_OPFPORT (1,port);
a55c2b68 162 cmode = scm_to_int (mode);
d3639214 163 if (cmode != _IONBF && cmode != _IOFBF && cmode != _IOLBF)
1bbd0b84 164 scm_out_of_range (FUNC_NAME, mode);
d3639214
GH
165
166 if (cmode == _IOLBF)
167 {
54778cd3 168 SCM_SET_CELL_WORD_0 (port, SCM_CELL_WORD_0 (port) | SCM_BUFLINE);
d3639214
GH
169 cmode = _IOFBF;
170 }
171 else
172 {
2b829bbb 173 SCM_SET_CELL_WORD_0 (port, SCM_CELL_WORD_0 (port) & ~(scm_t_bits)SCM_BUFLINE);
d3639214
GH
174 }
175
7a6f1ffa 176 if (SCM_UNBNDP (size))
cb63cf9e
JB
177 {
178 if (cmode == _IOFBF)
179 csize = -1;
180 else
181 csize = 0;
182 }
7a6f1ffa
GH
183 else
184 {
a55c2b68 185 csize = scm_to_int (size);
cb63cf9e 186 if (csize < 0 || (cmode == _IONBF && csize > 0))
1bbd0b84 187 scm_out_of_range (FUNC_NAME, size);
7a6f1ffa 188 }
d3639214 189
cb63cf9e 190 pt = SCM_PTAB_ENTRY (port);
7a6f1ffa 191
67a72dc1 192 if (SCM_INPUT_PORT_P (port))
e8b21eec
LC
193 {
194 /* Drain pending input from PORT. Don't use `scm_drain_input' since
195 it returns a string, whereas we want binary input here. */
196 ndrained = pt->read_end - pt->read_pos;
197 if (pt->read_buf == pt->putback_buf)
198 ndrained += pt->saved_read_end - pt->saved_read_pos;
199
200 if (ndrained > 0)
201 {
202 drained = scm_gc_malloc_pointerless (ndrained, "file port");
203 scm_take_from_input_buffers (port, drained, ndrained);
204 }
205 }
67a72dc1 206 else
e8b21eec 207 ndrained = 0;
67a72dc1
AW
208
209 if (SCM_OUTPUT_PORT_P (port))
4251ae2e 210 scm_flush_unlocked (port);
67a72dc1 211
4c9419ac
MV
212 if (pt->read_buf == pt->putback_buf)
213 {
214 pt->read_buf = pt->saved_read_buf;
215 pt->read_pos = pt->saved_read_pos;
216 pt->read_end = pt->saved_read_end;
217 pt->read_buf_size = pt->saved_read_buf_size;
218 }
cb63cf9e 219 if (pt->read_buf != &pt->shortbuf)
4c9419ac 220 scm_gc_free (pt->read_buf, pt->read_buf_size, "port buffer");
cb63cf9e 221 if (pt->write_buf != &pt->shortbuf)
4c9419ac 222 scm_gc_free (pt->write_buf, pt->write_buf_size, "port buffer");
7a6f1ffa 223
cb63cf9e 224 scm_fport_buffer_add (port, csize, csize);
67a72dc1 225
e8b21eec
LC
226 if (ndrained > 0)
227 /* Put DRAINED back to PORT. */
7f6c3f8f 228 scm_unget_bytes ((unsigned char *) drained, ndrained, port);
67a72dc1 229
cb63cf9e 230 return SCM_UNSPECIFIED;
0f2d19dd 231}
1bbd0b84 232#undef FUNC_NAME
0f2d19dd 233
eadd48de 234/* Move ports with the specified file descriptor to new descriptors,
387d418c 235 * resetting the revealed count to 0.
0f2d19dd 236 */
ee834df4
LC
237static void
238scm_i_evict_port (void *closure, SCM port)
0f2d19dd 239{
5dbc6c06 240 int fd = * (int*) closure;
0f2d19dd 241
5dbc6c06 242 if (SCM_FPORTP (port))
eadd48de 243 {
e9d8bc25
LC
244 scm_t_port *p;
245 scm_t_fport *fp;
246
247 /* XXX: In some cases, we can encounter a port with no associated ptab
248 entry. */
249 p = SCM_PTAB_ENTRY (port);
250 fp = (p != NULL) ? (scm_t_fport *) p->stream : NULL;
cb63cf9e 251
e9d8bc25 252 if ((fp != NULL) && (fp->fdes == fd))
eadd48de 253 {
5dbc6c06
HWN
254 fp->fdes = dup (fd);
255 if (fp->fdes == -1)
256 scm_syserror ("scm_evict_ports");
257 scm_set_port_revealed_x (port, scm_from_int (0));
eadd48de
GH
258 }
259 }
5dbc6c06
HWN
260}
261
262void
263scm_evict_ports (int fd)
264{
ee834df4 265 scm_c_port_for_each (scm_i_evict_port, (void *) &fd);
eadd48de 266}
0f2d19dd 267
efa40607
DH
268
269SCM_DEFINE (scm_file_port_p, "file-port?", 1, 0, 0,
270 (SCM obj),
2069af38 271 "Determine whether @var{obj} is a port that is related to a file.")
efa40607
DH
272#define FUNC_NAME s_scm_file_port_p
273{
7888309b 274 return scm_from_bool (SCM_FPORTP (obj));
efa40607
DH
275}
276#undef FUNC_NAME
277
278
69cac238 279static SCM sys_file_port_name_canonicalization;
0157a341
AW
280SCM_SYMBOL (sym_relative, "relative");
281SCM_SYMBOL (sym_absolute, "absolute");
282
283static SCM
284fport_canonicalize_filename (SCM filename)
285{
69cac238
AW
286 SCM mode = scm_fluid_ref (sys_file_port_name_canonicalization);
287
0157a341
AW
288 if (!scm_is_string (filename))
289 {
290 return filename;
291 }
69cac238 292 else if (scm_is_eq (mode, sym_relative))
0157a341 293 {
22457d57
AW
294 SCM path, rel;
295
296 path = scm_variable_ref (scm_c_module_lookup (scm_the_root_module (),
297 "%load-path"));
298 rel = scm_i_relativize_path (filename, path);
299
300 return scm_is_true (rel) ? rel : filename;
0157a341 301 }
69cac238 302 else if (scm_is_eq (mode, sym_absolute))
0157a341
AW
303 {
304 char *str, *canon;
305
306 str = scm_to_locale_string (filename);
307 canon = canonicalize_file_name (str);
308 free (str);
309
310 return canon ? scm_take_locale_string (canon) : filename;
311 }
312 else
313 {
314 return filename;
315 }
316}
317
3ace9a8e
MW
318/* scm_open_file_with_encoding
319 Return a new port open on a given file.
0157a341 320
3ace9a8e
MW
321 The mode string must match the pattern: [rwa+]** which
322 is interpreted in the usual unix way.
323
324 Unless binary mode is requested, the character encoding of the new
325 port is determined as follows: First, if GUESS_ENCODING is true,
326 'file-encoding' is used to guess the encoding of the file. If
327 GUESS_ENCODING is false or if 'file-encoding' fails, ENCODING is used
328 unless it is also false. As a last resort, the default port encoding
329 is used. It is an error to pass a non-false GUESS_ENCODING or
330 ENCODING if binary mode is requested.
331
332 Return the new port. */
333SCM
334scm_open_file_with_encoding (SCM filename, SCM mode,
335 SCM guess_encoding, SCM encoding)
336#define FUNC_NAME "open-file"
0f2d19dd 337{
19639113 338 SCM port;
9a334eb3 339 int fdes, flags = 0, binary = 0;
64e3a89c
LC
340 unsigned int retries;
341 char *file, *md, *ptr;
19639113 342
3ace9a8e
MW
343 if (SCM_UNLIKELY (!(scm_is_false (encoding) || scm_is_string (encoding))))
344 scm_wrong_type_arg_msg (FUNC_NAME, 0, encoding,
345 "encoding to be string or false");
346
661ae7ab 347 scm_dynwind_begin (0);
19639113 348
7f9994d9 349 file = scm_to_locale_string (filename);
661ae7ab 350 scm_dynwind_free (file);
7f9994d9
MV
351
352 md = scm_to_locale_string (mode);
661ae7ab 353 scm_dynwind_free (md);
19639113 354
1e6808ea 355 switch (*md)
0f2d19dd 356 {
cb63cf9e
JB
357 case 'r':
358 flags |= O_RDONLY;
359 break;
360 case 'w':
361 flags |= O_WRONLY | O_CREAT | O_TRUNC;
362 break;
363 case 'a':
364 flags |= O_WRONLY | O_CREAT | O_APPEND;
365 break;
366 default:
1e6808ea 367 scm_out_of_range (FUNC_NAME, mode);
0f2d19dd 368 }
1e6808ea 369 ptr = md + 1;
cb63cf9e 370 while (*ptr != '\0')
e145dd02 371 {
cb63cf9e
JB
372 switch (*ptr)
373 {
374 case '+':
375 flags = (flags & ~(O_RDONLY | O_WRONLY)) | O_RDWR;
376 break;
9f561420 377 case 'b':
9a334eb3 378 binary = 1;
9f561420
GH
379#if defined (O_BINARY)
380 flags |= O_BINARY;
381#endif
382 break;
cb63cf9e 383 case '0': /* unbuffered: handled later. */
d3639214 384 case 'l': /* line buffered: handled during output. */
cb63cf9e
JB
385 break;
386 default:
1e6808ea 387 scm_out_of_range (FUNC_NAME, mode);
cb63cf9e
JB
388 }
389 ptr++;
e145dd02 390 }
cb63cf9e 391
64e3a89c
LC
392 for (retries = 0, fdes = -1;
393 fdes < 0 && retries < 2;
394 retries++)
395 {
396 SCM_SYSCALL (fdes = open_or_open64 (file, flags, 0666));
397 if (fdes == -1)
398 {
399 int en = errno;
400
401 if (en == EMFILE && retries == 0)
402 /* Run the GC in case it collects open file ports that are no
403 longer referenced. */
404 scm_i_gc (FUNC_NAME);
405 else
406 SCM_SYSERROR_MSG ("~A: ~S",
407 scm_cons (scm_strerror (scm_from_int (en)),
408 scm_cons (filename, SCM_EOL)), en);
409 }
0f2d19dd 410 }
64e3a89c 411
211683cc
MG
412 /* Create a port from this file descriptor. The port's encoding is initially
413 %default-port-encoding. */
0157a341
AW
414 port = scm_i_fdes_to_port (fdes, scm_i_mode_bits (mode),
415 fport_canonicalize_filename (filename));
7f9994d9 416
9a334eb3 417 if (binary)
211683cc 418 {
3ace9a8e
MW
419 if (scm_is_true (encoding))
420 scm_misc_error (FUNC_NAME,
421 "Encoding specified on a binary port",
422 scm_list_1 (encoding));
423 if (scm_is_true (guess_encoding))
424 scm_misc_error (FUNC_NAME,
425 "Request to guess encoding on a binary port",
426 SCM_EOL);
427
428 /* Use the binary-friendly ISO-8859-1 encoding. */
429 scm_i_set_port_encoding_x (port, NULL);
211683cc
MG
430 }
431 else
3ace9a8e
MW
432 {
433 char *enc = NULL;
434
435 if (scm_is_true (guess_encoding))
436 {
437 if (SCM_INPUT_PORT_P (port))
438 enc = scm_i_scan_for_encoding (port);
439 else
440 scm_misc_error (FUNC_NAME,
441 "Request to guess encoding on an output-only port",
442 SCM_EOL);
443 }
444
445 if (!enc && scm_is_true (encoding))
446 {
447 char *buf = scm_to_latin1_string (encoding);
448 enc = scm_gc_strdup (buf, "encoding");
449 free (buf);
450 }
451
452 if (enc)
453 scm_i_set_port_encoding_x (port, enc);
454 }
211683cc 455
661ae7ab 456 scm_dynwind_end ();
7f9994d9 457
0f2d19dd
JB
458 return port;
459}
1bbd0b84 460#undef FUNC_NAME
0f2d19dd 461
3ace9a8e
MW
462SCM
463scm_open_file (SCM filename, SCM mode)
464{
465 return scm_open_file_with_encoding (filename, mode, SCM_BOOL_F, SCM_BOOL_F);
466}
467
468/* We can't define these using SCM_KEYWORD, because keywords have not
469 yet been initialized when scm_init_fports is called. */
470static SCM k_guess_encoding = SCM_UNDEFINED;
471static SCM k_encoding = SCM_UNDEFINED;
472
6a9d9e3a
AW
473SCM_INTERNAL SCM scm_i_open_file (SCM, SCM, SCM);
474
3ace9a8e
MW
475SCM_DEFINE (scm_i_open_file, "open-file", 2, 0, 1,
476 (SCM filename, SCM mode, SCM keyword_args),
477 "Open the file whose name is @var{filename}, and return a port\n"
478 "representing that file. The attributes of the port are\n"
479 "determined by the @var{mode} string. The way in which this is\n"
480 "interpreted is similar to C stdio. The first character must be\n"
481 "one of the following:\n"
482 "@table @samp\n"
483 "@item r\n"
484 "Open an existing file for input.\n"
485 "@item w\n"
486 "Open a file for output, creating it if it doesn't already exist\n"
487 "or removing its contents if it does.\n"
488 "@item a\n"
489 "Open a file for output, creating it if it doesn't already\n"
490 "exist. All writes to the port will go to the end of the file.\n"
491 "The \"append mode\" can be turned off while the port is in use\n"
492 "@pxref{Ports and File Descriptors, fcntl}\n"
493 "@end table\n"
494 "The following additional characters can be appended:\n"
495 "@table @samp\n"
496 "@item b\n"
497 "Open the underlying file in binary mode, if supported by the system.\n"
498 "Also, open the file using the binary-compatible character encoding\n"
499 "\"ISO-8859-1\", ignoring the default port encoding.\n"
500 "@item +\n"
501 "Open the port for both input and output. E.g., @code{r+}: open\n"
502 "an existing file for both input and output.\n"
503 "@item 0\n"
504 "Create an \"unbuffered\" port. In this case input and output\n"
505 "operations are passed directly to the underlying port\n"
506 "implementation without additional buffering. This is likely to\n"
507 "slow down I/O operations. The buffering mode can be changed\n"
508 "while a port is in use @pxref{Ports and File Descriptors,\n"
509 "setvbuf}\n"
510 "@item l\n"
511 "Add line-buffering to the port. The port output buffer will be\n"
512 "automatically flushed whenever a newline character is written.\n"
513 "@end table\n"
514 "In theory we could create read/write ports which were buffered\n"
515 "in one direction only. However this isn't included in the\n"
516 "current interfaces. If a file cannot be opened with the access\n"
517 "requested, @code{open-file} throws an exception.")
518#define FUNC_NAME s_scm_i_open_file
519{
520 SCM encoding = SCM_BOOL_F;
521 SCM guess_encoding = SCM_BOOL_F;
522
523 scm_c_bind_keyword_arguments (FUNC_NAME, keyword_args, 0,
524 k_guess_encoding, &guess_encoding,
525 k_encoding, &encoding,
526 SCM_UNDEFINED);
527
528 return scm_open_file_with_encoding (filename, mode,
529 guess_encoding, encoding);
530}
531#undef FUNC_NAME
532
e145dd02 533\f
cb63cf9e 534/* Building Guile ports from a file descriptor. */
e145dd02 535
cb63cf9e 536/* Build a Scheme port from an open file descriptor `fdes'.
a089567e
JB
537 MODE indicates whether FILE is open for reading or writing; it uses
538 the same notation as open-file's second argument.
19b27fa2
GH
539 NAME is a string to be used as the port's filename.
540*/
a089567e 541SCM
d617ee18 542scm_i_fdes_to_port (int fdes, long mode_bits, SCM name)
19b27fa2 543#define FUNC_NAME "scm_fdes_to_port"
a089567e 544{
a089567e 545 SCM port;
2721f918 546 scm_t_fport *fp;
19b27fa2 547
09b204d3
AW
548 /* Test that fdes is valid. */
549#ifdef F_GETFL
550 int flags = fcntl (fdes, F_GETFL, 0);
19b27fa2
GH
551 if (flags == -1)
552 SCM_SYSERROR;
553 flags &= O_ACCMODE;
554 if (flags != O_RDWR
555 && ((flags != O_WRONLY && (mode_bits & SCM_WRTNG))
556 || (flags != O_RDONLY && (mode_bits & SCM_RDNG))))
557 {
558 SCM_MISC_ERROR ("requested file mode not available on fdes", SCM_EOL);
559 }
09b204d3
AW
560#else
561 /* If we don't have F_GETFL, as on mingw, at least we can test that
562 it is a valid file descriptor. */
563 struct stat st;
564 if (fstat (fdes, &st) != 0)
565 SCM_SYSERROR;
566#endif
a089567e 567
2721f918
AW
568 fp = (scm_t_fport *) scm_gc_malloc_pointerless (sizeof (scm_t_fport),
569 "file port");
570 fp->fdes = fdes;
571
572 port = scm_c_make_port (scm_tc16_fport, mode_bits, (scm_t_bits)fp);
573
574 SCM_PTAB_ENTRY (port)->rw_random = SCM_FDES_RANDOM_P (fdes);
575
576 if (mode_bits & SCM_BUF0)
577 scm_fport_buffer_add (port, 0, 0);
578 else
579 scm_fport_buffer_add (port, -1, -1);
580
b24b5e13 581 SCM_SET_FILENAME (port, name);
2721f918 582
e145dd02
JB
583 return port;
584}
19b27fa2 585#undef FUNC_NAME
e145dd02 586
d617ee18
MV
587SCM
588scm_fdes_to_port (int fdes, char *mode, SCM name)
589{
590 return scm_i_fdes_to_port (fdes, scm_mode_bits (mode), name);
591}
592
affc96b5 593/* Return a lower bound on the number of bytes available for input. */
cb63cf9e 594static int
affc96b5 595fport_input_waiting (SCM port)
e145dd02 596{
23f2b9a3 597 int fdes = SCM_FSTREAM (port)->fdes;
c7519da3 598
c7519da3
CC
599 struct pollfd pollfd = { fdes, POLLIN, 0 };
600
601 if (poll (&pollfd, 1, 0) < 0)
602 scm_syserror ("fport_input_waiting");
603
604 return pollfd.revents & POLLIN ? 1 : 0;
a089567e
JB
605}
606
3753e227
AW
607
608\f
609
610/* Revealed counts --- an oddity inherited from SCSH. */
611
612#define SCM_REVEALED(x) (SCM_FSTREAM(x)->revealed)
613
614static SCM revealed_ports = SCM_EOL;
615static scm_i_pthread_mutex_t revealed_lock = SCM_I_PTHREAD_MUTEX_INITIALIZER;
3753e227
AW
616
617/* Find a port in the table and return its revealed count.
618 Also used by the garbage collector.
619 */
620int
621scm_revealed_count (SCM port)
622{
623 int ret;
624
625 scm_i_pthread_mutex_lock (&revealed_lock);
626 ret = SCM_REVEALED (port);
627 scm_i_pthread_mutex_unlock (&revealed_lock);
628
629 return ret;
630}
631
632SCM_DEFINE (scm_port_revealed, "port-revealed", 1, 0, 0,
633 (SCM port),
634 "Return the revealed count for @var{port}.")
635#define FUNC_NAME s_scm_port_revealed
636{
637 port = SCM_COERCE_OUTPORT (port);
638 SCM_VALIDATE_OPFPORT (1, port);
639 return scm_from_int (scm_revealed_count (port));
640}
641#undef FUNC_NAME
642
643/* Set the revealed count for a port. */
644SCM_DEFINE (scm_set_port_revealed_x, "set-port-revealed!", 2, 0, 0,
645 (SCM port, SCM rcount),
646 "Sets the revealed count for a port to a given value.\n"
647 "The return value is unspecified.")
648#define FUNC_NAME s_scm_set_port_revealed_x
649{
650 int r, prev;
651
652 port = SCM_COERCE_OUTPORT (port);
653 SCM_VALIDATE_OPFPORT (1, port);
654
655 r = scm_to_int (rcount);
656
657 scm_i_pthread_mutex_lock (&revealed_lock);
658
659 prev = SCM_REVEALED (port);
660 SCM_REVEALED (port) = r;
661
662 if (r && !prev)
663 revealed_ports = scm_cons (port, revealed_ports);
664 else if (prev && !r)
665 revealed_ports = scm_delq_x (port, revealed_ports);
666
667 scm_i_pthread_mutex_unlock (&revealed_lock);
668
669 return SCM_UNSPECIFIED;
670}
671#undef FUNC_NAME
672
673/* Set the revealed count for a port. */
674SCM_DEFINE (scm_adjust_port_revealed_x, "adjust-port-revealed!", 2, 0, 0,
675 (SCM port, SCM addend),
676 "Add @var{addend} to the revealed count of @var{port}.\n"
677 "The return value is unspecified.")
678#define FUNC_NAME s_scm_adjust_port_revealed_x
679{
680 int a;
681
682 port = SCM_COERCE_OUTPORT (port);
683 SCM_VALIDATE_OPFPORT (1, port);
684
685 a = scm_to_int (addend);
686 if (!a)
687 return SCM_UNSPECIFIED;
688
689 scm_i_pthread_mutex_lock (&revealed_lock);
690
691 SCM_REVEALED (port) += a;
692 if (SCM_REVEALED (port) == a)
693 revealed_ports = scm_cons (port, revealed_ports);
694 else if (!SCM_REVEALED (port))
695 revealed_ports = scm_delq_x (port, revealed_ports);
696
697 scm_i_pthread_mutex_unlock (&revealed_lock);
698
699 return SCM_UNSPECIFIED;
700}
701#undef FUNC_NAME
702
703
cb63cf9e 704\f
0f2d19dd 705static int
e81d98ec 706fport_print (SCM exp, SCM port, scm_print_state *pstate SCM_UNUSED)
0f2d19dd 707{
0607ebbf 708 scm_puts_unlocked ("#<", port);
b3ec3c64
MD
709 scm_print_port_mode (exp, port);
710 if (SCM_OPFPORTP (exp))
0f2d19dd 711 {
b3ec3c64 712 int fdes;
b24b5e13 713 SCM name = SCM_FILENAME (exp);
cc95e00a 714 if (scm_is_string (name) || scm_is_symbol (name))
b24b5e13
DH
715 scm_display (name, port);
716 else
0607ebbf
AW
717 scm_puts_unlocked (SCM_PTOBNAME (SCM_PTOBNUM (exp)), port);
718 scm_putc_unlocked (' ', port);
b3ec3c64 719 fdes = (SCM_FSTREAM (exp))->fdes;
073167ef
LC
720
721#if (defined HAVE_TTYNAME) && (defined HAVE_POSIX)
b3ec3c64 722 if (isatty (fdes))
eb372585 723 scm_display (scm_ttyname (exp), port);
b3ec3c64 724 else
82893676 725#endif /* HAVE_TTYNAME */
b3ec3c64 726 scm_intprint (fdes, 10, port);
0f2d19dd
JB
727 }
728 else
729 {
0607ebbf
AW
730 scm_puts_unlocked (SCM_PTOBNAME (SCM_PTOBNUM (exp)), port);
731 scm_putc_unlocked (' ', port);
0345e278 732 scm_uintprint ((scm_t_bits) SCM_PTAB_ENTRY (exp), 16, port);
0f2d19dd 733 }
0607ebbf 734 scm_putc_unlocked ('>', port);
b3ec3c64 735 return 1;
0f2d19dd
JB
736}
737
affc96b5 738static void fport_flush (SCM port);
0f2d19dd 739
c2da2648
GH
740/* fill a port's read-buffer with a single read. returns the first
741 char or EOF if end of file. */
889975e5 742static scm_t_wchar
affc96b5 743fport_fill_input (SCM port)
0f2d19dd 744{
c014a02e 745 long count;
92c2555f
MV
746 scm_t_port *pt = SCM_PTAB_ENTRY (port);
747 scm_t_fport *fp = SCM_FSTREAM (port);
cb63cf9e 748
cb63cf9e
JB
749 SCM_SYSCALL (count = read (fp->fdes, pt->read_buf, pt->read_buf_size));
750 if (count == -1)
affc96b5 751 scm_syserror ("fport_fill_input");
cb63cf9e 752 if (count == 0)
889975e5 753 return (scm_t_wchar) EOF;
cb63cf9e
JB
754 else
755 {
5c070ca7 756 pt->read_pos = pt->read_buf;
cb63cf9e 757 pt->read_end = pt->read_buf + count;
5c070ca7 758 return *pt->read_buf;
cb63cf9e 759 }
0f2d19dd
JB
760}
761
0a94eb00
LC
762static scm_t_off
763fport_seek (SCM port, scm_t_off offset, int whence)
0f2d19dd 764{
92c2555f
MV
765 scm_t_port *pt = SCM_PTAB_ENTRY (port);
766 scm_t_fport *fp = SCM_FSTREAM (port);
8ab3d8a0
KR
767 off_t_or_off64_t rv;
768 off_t_or_off64_t result;
7dcb364d
GH
769
770 if (pt->rw_active == SCM_PORT_WRITE)
771 {
772 if (offset != 0 || whence != SEEK_CUR)
773 {
774 fport_flush (port);
8ab3d8a0 775 result = rv = lseek_or_lseek64 (fp->fdes, offset, whence);
7dcb364d
GH
776 }
777 else
778 {
779 /* read current position without disturbing the buffer. */
8ab3d8a0 780 rv = lseek_or_lseek64 (fp->fdes, offset, whence);
7dcb364d
GH
781 result = rv + (pt->write_pos - pt->write_buf);
782 }
783 }
784 else if (pt->rw_active == SCM_PORT_READ)
785 {
786 if (offset != 0 || whence != SEEK_CUR)
787 {
788 /* could expand to avoid a second seek. */
4251ae2e 789 scm_end_input_unlocked (port);
8ab3d8a0 790 result = rv = lseek_or_lseek64 (fp->fdes, offset, whence);
7dcb364d
GH
791 }
792 else
793 {
794 /* read current position without disturbing the buffer
795 (particularly the unread-char buffer). */
8ab3d8a0 796 rv = lseek_or_lseek64 (fp->fdes, offset, whence);
7dcb364d
GH
797 result = rv - (pt->read_end - pt->read_pos);
798
799 if (pt->read_buf == pt->putback_buf)
800 result -= pt->saved_read_end - pt->saved_read_pos;
801 }
802 }
803 else /* SCM_PORT_NEITHER */
804 {
8ab3d8a0 805 result = rv = lseek_or_lseek64 (fp->fdes, offset, whence);
7dcb364d 806 }
cb8dfa3f 807
7dcb364d 808 if (rv == -1)
affc96b5 809 scm_syserror ("fport_seek");
7dcb364d 810
cb8dfa3f 811 return result;
0f2d19dd
JB
812}
813
840ae05d 814static void
f1ce9199 815fport_truncate (SCM port, scm_t_off length)
840ae05d 816{
92c2555f 817 scm_t_fport *fp = SCM_FSTREAM (port);
840ae05d
JB
818
819 if (ftruncate (fp->fdes, length) == -1)
820 scm_syserror ("ftruncate");
821}
822
31703ab8 823static void
8aa011a1 824fport_write (SCM port, const void *data, size_t size)
daa4a3f1 825#define FUNC_NAME "fport_write"
31703ab8 826{
0c6d2191 827 /* this procedure tries to minimize the number of writes/flushes. */
92c2555f 828 scm_t_port *pt = SCM_PTAB_ENTRY (port);
31703ab8 829
0c6d2191
GH
830 if (pt->write_buf == &pt->shortbuf
831 || (pt->write_pos == pt->write_buf && size >= pt->write_buf_size))
31703ab8 832 {
daa4a3f1
LC
833 /* Unbuffered port, or port with empty buffer and data won't fit in
834 buffer. */
835 if (full_write (SCM_FPORT_FDES (port), data, size) < size)
836 SCM_SYSERROR;
837
0c6d2191 838 return;
31703ab8 839 }
d3639214 840
0c6d2191 841 {
f1ce9199 842 scm_t_off space = pt->write_end - pt->write_pos;
0c6d2191
GH
843
844 if (size <= space)
845 {
846 /* data fits in buffer. */
847 memcpy (pt->write_pos, data, size);
848 pt->write_pos += size;
849 if (pt->write_pos == pt->write_end)
850 {
affc96b5 851 fport_flush (port);
0c6d2191
GH
852 /* we can skip the line-buffering check if nothing's buffered. */
853 return;
854 }
855 }
856 else
857 {
858 memcpy (pt->write_pos, data, space);
859 pt->write_pos = pt->write_end;
860 fport_flush (port);
861 {
862 const void *ptr = ((const char *) data) + space;
863 size_t remaining = size - space;
864
865 if (size >= pt->write_buf_size)
866 {
daa4a3f1
LC
867 if (full_write (SCM_FPORT_FDES (port), ptr, remaining)
868 < remaining)
869 SCM_SYSERROR;
0c6d2191
GH
870 return;
871 }
872 else
873 {
874 memcpy (pt->write_pos, ptr, remaining);
875 pt->write_pos += remaining;
876 }
31703ab8 877 }
0c6d2191 878 }
31703ab8 879
0c6d2191
GH
880 /* handle line buffering. */
881 if ((SCM_CELL_WORD_0 (port) & SCM_BUFLINE) && memchr (data, '\n', size))
882 fport_flush (port);
883 }
31703ab8 884}
daa4a3f1 885#undef FUNC_NAME
31703ab8 886
cb63cf9e 887static void
affc96b5 888fport_flush (SCM port)
0f2d19dd 889{
5335850d 890 size_t written;
92c2555f
MV
891 scm_t_port *pt = SCM_PTAB_ENTRY (port);
892 scm_t_fport *fp = SCM_FSTREAM (port);
5335850d 893 size_t count = pt->write_pos - pt->write_buf;
cb63cf9e 894
5335850d
LC
895 written = full_write (fp->fdes, pt->write_buf, count);
896 if (written < count)
897 scm_syserror ("scm_flush");
cb63cf9e 898
cb63cf9e 899 pt->write_pos = pt->write_buf;
61e452ba 900 pt->rw_active = SCM_PORT_NEITHER;
840ae05d
JB
901}
902
283a1a0e 903/* clear the read buffer and adjust the file position for unread bytes. */
840ae05d 904static void
affc96b5 905fport_end_input (SCM port, int offset)
840ae05d 906{
92c2555f
MV
907 scm_t_fport *fp = SCM_FSTREAM (port);
908 scm_t_port *pt = SCM_PTAB_ENTRY (port);
283a1a0e
GH
909
910 offset += pt->read_end - pt->read_pos;
840ae05d 911
840ae05d
JB
912 if (offset > 0)
913 {
914 pt->read_pos = pt->read_end;
915 /* will throw error if unread-char used at beginning of file
916 then attempting to write. seems correct. */
917 if (lseek (fp->fdes, -offset, SEEK_CUR) == -1)
affc96b5 918 scm_syserror ("fport_end_input");
840ae05d 919 }
61e452ba 920 pt->rw_active = SCM_PORT_NEITHER;
8f29fbd0
JB
921}
922
5a771d5f
AW
923static void
924close_the_fd (void *data)
925{
926 scm_t_fport *fp = data;
927
928 close (fp->fdes);
929 /* There's already one exception. That's probably enough! */
930 errno = 0;
931}
932
6a2c4c81 933static int
affc96b5 934fport_close (SCM port)
6a2c4c81 935{
92c2555f 936 scm_t_fport *fp = SCM_FSTREAM (port);
cb63cf9e 937 int rv;
840ae05d 938
5a771d5f
AW
939 scm_dynwind_begin (0);
940 scm_dynwind_unwind_handler (close_the_fd, fp, 0);
affc96b5 941 fport_flush (port);
5a771d5f
AW
942 scm_dynwind_end ();
943
944 scm_port_non_buffer (SCM_PTAB_ENTRY (port));
945
946 rv = close (fp->fdes);
947 if (rv)
948 /* It's not useful to retry after EINTR, as the file descriptor is
949 in an undefined state. See http://lwn.net/Articles/365294/.
950 Instead just throw an error if close fails, trusting that the fd
951 was cleaned up. */
952 scm_syserror ("fport_close");
953
954 return 0;
6a2c4c81
JB
955}
956
1be6b49c 957static size_t
affc96b5 958fport_free (SCM port)
b3ec3c64 959{
affc96b5 960 fport_close (port);
b3ec3c64
MD
961 return 0;
962}
963
92c2555f 964static scm_t_bits
b3ec3c64
MD
965scm_make_fptob ()
966{
92c2555f 967 scm_t_bits tc = scm_make_port_type ("file", fport_fill_input, fport_write);
a98bddfd 968
affc96b5 969 scm_set_port_free (tc, fport_free);
e841c3e0 970 scm_set_port_print (tc, fport_print);
affc96b5
GH
971 scm_set_port_flush (tc, fport_flush);
972 scm_set_port_end_input (tc, fport_end_input);
973 scm_set_port_close (tc, fport_close);
974 scm_set_port_seek (tc, fport_seek);
975 scm_set_port_truncate (tc, fport_truncate);
976 scm_set_port_input_waiting (tc, fport_input_waiting);
a98bddfd
DH
977
978 return tc;
b3ec3c64 979}
0f2d19dd 980
3ace9a8e
MW
981/* We can't initialize the keywords from 'scm_init_fports', because
982 keywords haven't yet been initialized at that point. */
983void
984scm_init_fports_keywords ()
985{
986 k_guess_encoding = scm_from_latin1_keyword ("guess-encoding");
987 k_encoding = scm_from_latin1_keyword ("encoding");
988}
989
0f2d19dd
JB
990void
991scm_init_fports ()
0f2d19dd 992{
a98bddfd
DH
993 scm_tc16_fport = scm_make_fptob ();
994
e11e83f3
MV
995 scm_c_define ("_IOFBF", scm_from_int (_IOFBF));
996 scm_c_define ("_IOLBF", scm_from_int (_IOLBF));
997 scm_c_define ("_IONBF", scm_from_int (_IONBF));
a98bddfd 998
69cac238
AW
999 sys_file_port_name_canonicalization = scm_make_fluid ();
1000 scm_c_define ("%file-port-name-canonicalization",
1001 sys_file_port_name_canonicalization);
1002
a98bddfd 1003#include "libguile/fports.x"
0f2d19dd 1004}
89e00824
ML
1005
1006/*
1007 Local Variables:
1008 c-file-style: "gnu"
1009 End:
1010*/