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