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