Print the faulty object upon invalid-keyword errors.
[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>
edb810bb 49
634aa8de
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"
59
60#include "libguile/fports.h"
61
8ab3d8a0
KR
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))
210 scm_flush (port);
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)
3ace9a8e
MW
418 {
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);
430 }
431 else
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
473SCM_DEFINE (scm_i_open_file, "open-file", 2, 0, 1,
474 (SCM filename, SCM mode, SCM keyword_args),
475 "Open the file whose name is @var{filename}, and return a port\n"
476 "representing that file. The attributes of the port are\n"
477 "determined by the @var{mode} string. The way in which this is\n"
478 "interpreted is similar to C stdio. The first character must be\n"
479 "one of the following:\n"
480 "@table @samp\n"
481 "@item r\n"
482 "Open an existing file for input.\n"
483 "@item w\n"
484 "Open a file for output, creating it if it doesn't already exist\n"
485 "or removing its contents if it does.\n"
486 "@item a\n"
487 "Open a file for output, creating it if it doesn't already\n"
488 "exist. All writes to the port will go to the end of the file.\n"
489 "The \"append mode\" can be turned off while the port is in use\n"
490 "@pxref{Ports and File Descriptors, fcntl}\n"
491 "@end table\n"
492 "The following additional characters can be appended:\n"
493 "@table @samp\n"
494 "@item b\n"
495 "Open the underlying file in binary mode, if supported by the system.\n"
496 "Also, open the file using the binary-compatible character encoding\n"
497 "\"ISO-8859-1\", ignoring the default port encoding.\n"
498 "@item +\n"
499 "Open the port for both input and output. E.g., @code{r+}: open\n"
500 "an existing file for both input and output.\n"
501 "@item 0\n"
502 "Create an \"unbuffered\" port. In this case input and output\n"
503 "operations are passed directly to the underlying port\n"
504 "implementation without additional buffering. This is likely to\n"
505 "slow down I/O operations. The buffering mode can be changed\n"
506 "while a port is in use @pxref{Ports and File Descriptors,\n"
507 "setvbuf}\n"
508 "@item l\n"
509 "Add line-buffering to the port. The port output buffer will be\n"
510 "automatically flushed whenever a newline character is written.\n"
511 "@end table\n"
512 "In theory we could create read/write ports which were buffered\n"
513 "in one direction only. However this isn't included in the\n"
514 "current interfaces. If a file cannot be opened with the access\n"
515 "requested, @code{open-file} throws an exception.")
516#define FUNC_NAME s_scm_i_open_file
517{
518 SCM encoding = SCM_BOOL_F;
519 SCM guess_encoding = SCM_BOOL_F;
520
521 scm_c_bind_keyword_arguments (FUNC_NAME, keyword_args, 0,
522 k_guess_encoding, &guess_encoding,
523 k_encoding, &encoding,
524 SCM_UNDEFINED);
525
526 return scm_open_file_with_encoding (filename, mode,
527 guess_encoding, encoding);
528}
529#undef FUNC_NAME
530
e145dd02 531\f
cb63cf9e 532/* Building Guile ports from a file descriptor. */
e145dd02 533
cb63cf9e 534/* Build a Scheme port from an open file descriptor `fdes'.
a089567e
JB
535 MODE indicates whether FILE is open for reading or writing; it uses
536 the same notation as open-file's second argument.
19b27fa2
GH
537 NAME is a string to be used as the port's filename.
538*/
a089567e 539SCM
d617ee18 540scm_i_fdes_to_port (int fdes, long mode_bits, SCM name)
19b27fa2 541#define FUNC_NAME "scm_fdes_to_port"
a089567e 542{
a089567e 543 SCM port;
92c2555f 544 scm_t_port *pt;
19b27fa2 545
09b204d3
AW
546 /* Test that fdes is valid. */
547#ifdef F_GETFL
548 int flags = fcntl (fdes, F_GETFL, 0);
19b27fa2
GH
549 if (flags == -1)
550 SCM_SYSERROR;
551 flags &= O_ACCMODE;
552 if (flags != O_RDWR
553 && ((flags != O_WRONLY && (mode_bits & SCM_WRTNG))
554 || (flags != O_RDONLY && (mode_bits & SCM_RDNG))))
555 {
556 SCM_MISC_ERROR ("requested file mode not available on fdes", SCM_EOL);
557 }
09b204d3
AW
558#else
559 /* If we don't have F_GETFL, as on mingw, at least we can test that
560 it is a valid file descriptor. */
561 struct stat st;
562 if (fstat (fdes, &st) != 0)
563 SCM_SYSERROR;
564#endif
a089567e 565
9de87eea 566 scm_i_scm_pthread_mutex_lock (&scm_i_port_table_mutex);
da220f27
HWN
567
568 port = scm_new_port_table_entry (scm_tc16_fport);
569 SCM_SET_CELL_TYPE(port, scm_tc16_fport | mode_bits);
570 pt = SCM_PTAB_ENTRY(port);
a089567e 571 {
92c2555f 572 scm_t_fport *fp
92d8fd32
LC
573 = (scm_t_fport *) scm_gc_malloc_pointerless (sizeof (scm_t_fport),
574 "file port");
c6c79933 575
cb63cf9e 576 fp->fdes = fdes;
0de97b83 577 pt->rw_random = SCM_FDES_RANDOM_P (fdes);
cb63cf9e
JB
578 SCM_SETSTREAM (port, fp);
579 if (mode_bits & SCM_BUF0)
580 scm_fport_buffer_add (port, 0, 0);
581 else
582 scm_fport_buffer_add (port, -1, -1);
a089567e 583 }
b24b5e13 584 SCM_SET_FILENAME (port, name);
9de87eea 585 scm_i_pthread_mutex_unlock (&scm_i_port_table_mutex);
e145dd02
JB
586 return port;
587}
19b27fa2 588#undef FUNC_NAME
e145dd02 589
d617ee18
MV
590SCM
591scm_fdes_to_port (int fdes, char *mode, SCM name)
592{
593 return scm_i_fdes_to_port (fdes, scm_mode_bits (mode), name);
594}
595
affc96b5 596/* Return a lower bound on the number of bytes available for input. */
cb63cf9e 597static int
affc96b5 598fport_input_waiting (SCM port)
e145dd02 599{
23f2b9a3 600 int fdes = SCM_FSTREAM (port)->fdes;
c7519da3 601
c7519da3
CC
602 struct pollfd pollfd = { fdes, POLLIN, 0 };
603
604 if (poll (&pollfd, 1, 0) < 0)
605 scm_syserror ("fport_input_waiting");
606
607 return pollfd.revents & POLLIN ? 1 : 0;
a089567e
JB
608}
609
cb63cf9e 610\f
0f2d19dd 611static int
e81d98ec 612fport_print (SCM exp, SCM port, scm_print_state *pstate SCM_UNUSED)
0f2d19dd 613{
b3ec3c64
MD
614 scm_puts ("#<", port);
615 scm_print_port_mode (exp, port);
616 if (SCM_OPFPORTP (exp))
0f2d19dd 617 {
b3ec3c64 618 int fdes;
b24b5e13 619 SCM name = SCM_FILENAME (exp);
cc95e00a 620 if (scm_is_string (name) || scm_is_symbol (name))
b24b5e13
DH
621 scm_display (name, port);
622 else
623 scm_puts (SCM_PTOBNAME (SCM_PTOBNUM (exp)), port);
b3ec3c64
MD
624 scm_putc (' ', port);
625 fdes = (SCM_FSTREAM (exp))->fdes;
073167ef
LC
626
627#if (defined HAVE_TTYNAME) && (defined HAVE_POSIX)
b3ec3c64 628 if (isatty (fdes))
eb372585 629 scm_display (scm_ttyname (exp), port);
b3ec3c64 630 else
82893676 631#endif /* HAVE_TTYNAME */
b3ec3c64 632 scm_intprint (fdes, 10, port);
0f2d19dd
JB
633 }
634 else
635 {
b3ec3c64
MD
636 scm_puts (SCM_PTOBNAME (SCM_PTOBNUM (exp)), port);
637 scm_putc (' ', port);
0345e278 638 scm_uintprint ((scm_t_bits) SCM_PTAB_ENTRY (exp), 16, port);
0f2d19dd 639 }
b3ec3c64
MD
640 scm_putc ('>', port);
641 return 1;
0f2d19dd
JB
642}
643
affc96b5 644static void fport_flush (SCM port);
0f2d19dd 645
c2da2648
GH
646/* fill a port's read-buffer with a single read. returns the first
647 char or EOF if end of file. */
889975e5 648static scm_t_wchar
affc96b5 649fport_fill_input (SCM port)
0f2d19dd 650{
c014a02e 651 long count;
92c2555f
MV
652 scm_t_port *pt = SCM_PTAB_ENTRY (port);
653 scm_t_fport *fp = SCM_FSTREAM (port);
cb63cf9e 654
cb63cf9e
JB
655 SCM_SYSCALL (count = read (fp->fdes, pt->read_buf, pt->read_buf_size));
656 if (count == -1)
affc96b5 657 scm_syserror ("fport_fill_input");
cb63cf9e 658 if (count == 0)
889975e5 659 return (scm_t_wchar) EOF;
cb63cf9e
JB
660 else
661 {
5c070ca7 662 pt->read_pos = pt->read_buf;
cb63cf9e 663 pt->read_end = pt->read_buf + count;
5c070ca7 664 return *pt->read_buf;
cb63cf9e 665 }
0f2d19dd
JB
666}
667
0a94eb00
LC
668static scm_t_off
669fport_seek (SCM port, scm_t_off offset, int whence)
0f2d19dd 670{
92c2555f
MV
671 scm_t_port *pt = SCM_PTAB_ENTRY (port);
672 scm_t_fport *fp = SCM_FSTREAM (port);
8ab3d8a0
KR
673 off_t_or_off64_t rv;
674 off_t_or_off64_t result;
7dcb364d
GH
675
676 if (pt->rw_active == SCM_PORT_WRITE)
677 {
678 if (offset != 0 || whence != SEEK_CUR)
679 {
680 fport_flush (port);
8ab3d8a0 681 result = rv = lseek_or_lseek64 (fp->fdes, offset, whence);
7dcb364d
GH
682 }
683 else
684 {
685 /* read current position without disturbing the buffer. */
8ab3d8a0 686 rv = lseek_or_lseek64 (fp->fdes, offset, whence);
7dcb364d
GH
687 result = rv + (pt->write_pos - pt->write_buf);
688 }
689 }
690 else if (pt->rw_active == SCM_PORT_READ)
691 {
692 if (offset != 0 || whence != SEEK_CUR)
693 {
694 /* could expand to avoid a second seek. */
695 scm_end_input (port);
8ab3d8a0 696 result = rv = lseek_or_lseek64 (fp->fdes, offset, whence);
7dcb364d
GH
697 }
698 else
699 {
700 /* read current position without disturbing the buffer
701 (particularly the unread-char buffer). */
8ab3d8a0 702 rv = lseek_or_lseek64 (fp->fdes, offset, whence);
7dcb364d
GH
703 result = rv - (pt->read_end - pt->read_pos);
704
705 if (pt->read_buf == pt->putback_buf)
706 result -= pt->saved_read_end - pt->saved_read_pos;
707 }
708 }
709 else /* SCM_PORT_NEITHER */
710 {
8ab3d8a0 711 result = rv = lseek_or_lseek64 (fp->fdes, offset, whence);
7dcb364d 712 }
cb8dfa3f 713
7dcb364d 714 if (rv == -1)
affc96b5 715 scm_syserror ("fport_seek");
7dcb364d 716
cb8dfa3f 717 return result;
0f2d19dd
JB
718}
719
840ae05d 720static void
f1ce9199 721fport_truncate (SCM port, scm_t_off length)
840ae05d 722{
92c2555f 723 scm_t_fport *fp = SCM_FSTREAM (port);
840ae05d
JB
724
725 if (ftruncate (fp->fdes, length) == -1)
726 scm_syserror ("ftruncate");
727}
728
31703ab8 729static void
8aa011a1 730fport_write (SCM port, const void *data, size_t size)
daa4a3f1 731#define FUNC_NAME "fport_write"
31703ab8 732{
0c6d2191 733 /* this procedure tries to minimize the number of writes/flushes. */
92c2555f 734 scm_t_port *pt = SCM_PTAB_ENTRY (port);
31703ab8 735
0c6d2191
GH
736 if (pt->write_buf == &pt->shortbuf
737 || (pt->write_pos == pt->write_buf && size >= pt->write_buf_size))
31703ab8 738 {
daa4a3f1
LC
739 /* Unbuffered port, or port with empty buffer and data won't fit in
740 buffer. */
741 if (full_write (SCM_FPORT_FDES (port), data, size) < size)
742 SCM_SYSERROR;
743
0c6d2191 744 return;
31703ab8 745 }
d3639214 746
0c6d2191 747 {
f1ce9199 748 scm_t_off space = pt->write_end - pt->write_pos;
0c6d2191
GH
749
750 if (size <= space)
751 {
752 /* data fits in buffer. */
753 memcpy (pt->write_pos, data, size);
754 pt->write_pos += size;
755 if (pt->write_pos == pt->write_end)
756 {
affc96b5 757 fport_flush (port);
0c6d2191
GH
758 /* we can skip the line-buffering check if nothing's buffered. */
759 return;
760 }
761 }
762 else
763 {
764 memcpy (pt->write_pos, data, space);
765 pt->write_pos = pt->write_end;
766 fport_flush (port);
767 {
768 const void *ptr = ((const char *) data) + space;
769 size_t remaining = size - space;
770
771 if (size >= pt->write_buf_size)
772 {
daa4a3f1
LC
773 if (full_write (SCM_FPORT_FDES (port), ptr, remaining)
774 < remaining)
775 SCM_SYSERROR;
0c6d2191
GH
776 return;
777 }
778 else
779 {
780 memcpy (pt->write_pos, ptr, remaining);
781 pt->write_pos += remaining;
782 }
31703ab8 783 }
0c6d2191 784 }
31703ab8 785
0c6d2191
GH
786 /* handle line buffering. */
787 if ((SCM_CELL_WORD_0 (port) & SCM_BUFLINE) && memchr (data, '\n', size))
788 fport_flush (port);
789 }
31703ab8 790}
daa4a3f1 791#undef FUNC_NAME
31703ab8 792
cb63cf9e 793static void
affc96b5 794fport_flush (SCM port)
0f2d19dd 795{
5335850d 796 size_t written;
92c2555f
MV
797 scm_t_port *pt = SCM_PTAB_ENTRY (port);
798 scm_t_fport *fp = SCM_FSTREAM (port);
5335850d 799 size_t count = pt->write_pos - pt->write_buf;
cb63cf9e 800
5335850d
LC
801 written = full_write (fp->fdes, pt->write_buf, count);
802 if (written < count)
803 scm_syserror ("scm_flush");
cb63cf9e 804
cb63cf9e 805 pt->write_pos = pt->write_buf;
61e452ba 806 pt->rw_active = SCM_PORT_NEITHER;
840ae05d
JB
807}
808
283a1a0e 809/* clear the read buffer and adjust the file position for unread bytes. */
840ae05d 810static void
affc96b5 811fport_end_input (SCM port, int offset)
840ae05d 812{
92c2555f
MV
813 scm_t_fport *fp = SCM_FSTREAM (port);
814 scm_t_port *pt = SCM_PTAB_ENTRY (port);
283a1a0e
GH
815
816 offset += pt->read_end - pt->read_pos;
840ae05d 817
840ae05d
JB
818 if (offset > 0)
819 {
820 pt->read_pos = pt->read_end;
821 /* will throw error if unread-char used at beginning of file
822 then attempting to write. seems correct. */
823 if (lseek (fp->fdes, -offset, SEEK_CUR) == -1)
affc96b5 824 scm_syserror ("fport_end_input");
840ae05d 825 }
61e452ba 826 pt->rw_active = SCM_PORT_NEITHER;
8f29fbd0
JB
827}
828
6a2c4c81 829static int
affc96b5 830fport_close (SCM port)
6a2c4c81 831{
92c2555f
MV
832 scm_t_fport *fp = SCM_FSTREAM (port);
833 scm_t_port *pt = SCM_PTAB_ENTRY (port);
cb63cf9e 834 int rv;
840ae05d 835
affc96b5 836 fport_flush (port);
cb63cf9e
JB
837 SCM_SYSCALL (rv = close (fp->fdes));
838 if (rv == -1 && errno != EBADF)
6b72ac1d
GH
839 {
840 if (scm_gc_running_p)
841 /* silently ignore the error. scm_error would abort if we
842 called it now. */
843 ;
844 else
845 scm_syserror ("fport_close");
846 }
6c951427
GH
847 if (pt->read_buf == pt->putback_buf)
848 pt->read_buf = pt->saved_read_buf;
cb63cf9e 849 if (pt->read_buf != &pt->shortbuf)
4c9419ac 850 scm_gc_free (pt->read_buf, pt->read_buf_size, "port buffer");
cb63cf9e 851 if (pt->write_buf != &pt->shortbuf)
4c9419ac
MV
852 scm_gc_free (pt->write_buf, pt->write_buf_size, "port buffer");
853 scm_gc_free (fp, sizeof (*fp), "file port");
cb63cf9e 854 return rv;
6a2c4c81
JB
855}
856
1be6b49c 857static size_t
affc96b5 858fport_free (SCM port)
b3ec3c64 859{
affc96b5 860 fport_close (port);
b3ec3c64
MD
861 return 0;
862}
863
92c2555f 864static scm_t_bits
b3ec3c64
MD
865scm_make_fptob ()
866{
92c2555f 867 scm_t_bits tc = scm_make_port_type ("file", fport_fill_input, fport_write);
a98bddfd 868
affc96b5 869 scm_set_port_free (tc, fport_free);
e841c3e0 870 scm_set_port_print (tc, fport_print);
affc96b5
GH
871 scm_set_port_flush (tc, fport_flush);
872 scm_set_port_end_input (tc, fport_end_input);
873 scm_set_port_close (tc, fport_close);
874 scm_set_port_seek (tc, fport_seek);
875 scm_set_port_truncate (tc, fport_truncate);
876 scm_set_port_input_waiting (tc, fport_input_waiting);
a98bddfd
DH
877
878 return tc;
b3ec3c64 879}
0f2d19dd 880
3ace9a8e
MW
881/* We can't initialize the keywords from 'scm_init_fports', because
882 keywords haven't yet been initialized at that point. */
883void
884scm_init_fports_keywords ()
885{
886 k_guess_encoding = scm_from_latin1_keyword ("guess-encoding");
887 k_encoding = scm_from_latin1_keyword ("encoding");
888}
889
0f2d19dd
JB
890void
891scm_init_fports ()
0f2d19dd 892{
a98bddfd
DH
893 scm_tc16_fport = scm_make_fptob ();
894
e11e83f3
MV
895 scm_c_define ("_IOFBF", scm_from_int (_IOFBF));
896 scm_c_define ("_IOLBF", scm_from_int (_IOLBF));
897 scm_c_define ("_IONBF", scm_from_int (_IONBF));
a98bddfd 898
69cac238
AW
899 sys_file_port_name_canonicalization = scm_make_fluid ();
900 scm_c_define ("%file-port-name-canonicalization",
901 sys_file_port_name_canonicalization);
902
a98bddfd 903#include "libguile/fports.x"
0f2d19dd 904}
89e00824
ML
905
906/*
907 Local Variables:
908 c-file-style: "gnu"
909 End:
910*/