build: Don't include <config.h> in native programs when cross-compiling.
[bpt/guile.git] / libguile / fports.c
CommitLineData
073167ef 1/* Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
122f24cc
LC
2 * 2004, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013,
3 * 2014 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
LC
157 size_t ndrained;
158 char *drained;
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
LC
344 unsigned int retries;
345 char *file, *md, *ptr;
19639113 346
3ace9a8e
MW
347 if (SCM_UNLIKELY (!(scm_is_false (encoding) || scm_is_string (encoding))))
348 scm_wrong_type_arg_msg (FUNC_NAME, 0, encoding,
349 "encoding to be string or false");
350
661ae7ab 351 scm_dynwind_begin (0);
19639113 352
7f9994d9 353 file = scm_to_locale_string (filename);
661ae7ab 354 scm_dynwind_free (file);
7f9994d9
MV
355
356 md = scm_to_locale_string (mode);
661ae7ab 357 scm_dynwind_free (md);
19639113 358
1e6808ea 359 switch (*md)
0f2d19dd 360 {
cb63cf9e
JB
361 case 'r':
362 flags |= O_RDONLY;
363 break;
364 case 'w':
365 flags |= O_WRONLY | O_CREAT | O_TRUNC;
366 break;
367 case 'a':
368 flags |= O_WRONLY | O_CREAT | O_APPEND;
369 break;
370 default:
1e6808ea 371 scm_out_of_range (FUNC_NAME, mode);
0f2d19dd 372 }
1e6808ea 373 ptr = md + 1;
cb63cf9e 374 while (*ptr != '\0')
e145dd02 375 {
cb63cf9e
JB
376 switch (*ptr)
377 {
378 case '+':
379 flags = (flags & ~(O_RDONLY | O_WRONLY)) | O_RDWR;
380 break;
9f561420 381 case 'b':
9a334eb3 382 binary = 1;
9f561420
GH
383#if defined (O_BINARY)
384 flags |= O_BINARY;
385#endif
386 break;
cb63cf9e 387 case '0': /* unbuffered: handled later. */
d3639214 388 case 'l': /* line buffered: handled during output. */
cb63cf9e
JB
389 break;
390 default:
1e6808ea 391 scm_out_of_range (FUNC_NAME, mode);
cb63cf9e
JB
392 }
393 ptr++;
e145dd02 394 }
cb63cf9e 395
64e3a89c
LC
396 for (retries = 0, fdes = -1;
397 fdes < 0 && retries < 2;
398 retries++)
399 {
400 SCM_SYSCALL (fdes = open_or_open64 (file, flags, 0666));
401 if (fdes == -1)
402 {
403 int en = errno;
404
405 if (en == EMFILE && retries == 0)
406 /* Run the GC in case it collects open file ports that are no
407 longer referenced. */
408 scm_i_gc (FUNC_NAME);
409 else
410 SCM_SYSERROR_MSG ("~A: ~S",
411 scm_cons (scm_strerror (scm_from_int (en)),
412 scm_cons (filename, SCM_EOL)), en);
413 }
0f2d19dd 414 }
64e3a89c 415
211683cc
MG
416 /* Create a port from this file descriptor. The port's encoding is initially
417 %default-port-encoding. */
0157a341
AW
418 port = scm_i_fdes_to_port (fdes, scm_i_mode_bits (mode),
419 fport_canonicalize_filename (filename));
7f9994d9 420
9a334eb3 421 if (binary)
3ace9a8e
MW
422 {
423 if (scm_is_true (encoding))
424 scm_misc_error (FUNC_NAME,
425 "Encoding specified on a binary port",
426 scm_list_1 (encoding));
427 if (scm_is_true (guess_encoding))
428 scm_misc_error (FUNC_NAME,
429 "Request to guess encoding on a binary port",
430 SCM_EOL);
431
432 /* Use the binary-friendly ISO-8859-1 encoding. */
433 scm_i_set_port_encoding_x (port, NULL);
434 }
435 else
436 {
437 char *enc = NULL;
438
439 if (scm_is_true (guess_encoding))
440 {
441 if (SCM_INPUT_PORT_P (port))
442 enc = scm_i_scan_for_encoding (port);
443 else
444 scm_misc_error (FUNC_NAME,
445 "Request to guess encoding on an output-only port",
446 SCM_EOL);
447 }
448
449 if (!enc && scm_is_true (encoding))
450 {
451 char *buf = scm_to_latin1_string (encoding);
452 enc = scm_gc_strdup (buf, "encoding");
453 free (buf);
454 }
455
456 if (enc)
457 scm_i_set_port_encoding_x (port, enc);
458 }
211683cc 459
661ae7ab 460 scm_dynwind_end ();
7f9994d9 461
0f2d19dd
JB
462 return port;
463}
1bbd0b84 464#undef FUNC_NAME
0f2d19dd 465
3ace9a8e
MW
466SCM
467scm_open_file (SCM filename, SCM mode)
468{
469 return scm_open_file_with_encoding (filename, mode, SCM_BOOL_F, SCM_BOOL_F);
470}
471
472/* We can't define these using SCM_KEYWORD, because keywords have not
473 yet been initialized when scm_init_fports is called. */
474static SCM k_guess_encoding = SCM_UNDEFINED;
475static SCM k_encoding = SCM_UNDEFINED;
476
477SCM_DEFINE (scm_i_open_file, "open-file", 2, 0, 1,
478 (SCM filename, SCM mode, SCM keyword_args),
479 "Open the file whose name is @var{filename}, and return a port\n"
480 "representing that file. The attributes of the port are\n"
481 "determined by the @var{mode} string. The way in which this is\n"
482 "interpreted is similar to C stdio. The first character must be\n"
483 "one of the following:\n"
484 "@table @samp\n"
485 "@item r\n"
486 "Open an existing file for input.\n"
487 "@item w\n"
488 "Open a file for output, creating it if it doesn't already exist\n"
489 "or removing its contents if it does.\n"
490 "@item a\n"
491 "Open a file for output, creating it if it doesn't already\n"
492 "exist. All writes to the port will go to the end of the file.\n"
493 "The \"append mode\" can be turned off while the port is in use\n"
494 "@pxref{Ports and File Descriptors, fcntl}\n"
495 "@end table\n"
496 "The following additional characters can be appended:\n"
497 "@table @samp\n"
498 "@item b\n"
499 "Open the underlying file in binary mode, if supported by the system.\n"
500 "Also, open the file using the binary-compatible character encoding\n"
501 "\"ISO-8859-1\", ignoring the default port encoding.\n"
502 "@item +\n"
503 "Open the port for both input and output. E.g., @code{r+}: open\n"
504 "an existing file for both input and output.\n"
505 "@item 0\n"
506 "Create an \"unbuffered\" port. In this case input and output\n"
507 "operations are passed directly to the underlying port\n"
508 "implementation without additional buffering. This is likely to\n"
509 "slow down I/O operations. The buffering mode can be changed\n"
510 "while a port is in use @pxref{Ports and File Descriptors,\n"
511 "setvbuf}\n"
512 "@item l\n"
513 "Add line-buffering to the port. The port output buffer will be\n"
514 "automatically flushed whenever a newline character is written.\n"
515 "@end table\n"
516 "In theory we could create read/write ports which were buffered\n"
517 "in one direction only. However this isn't included in the\n"
518 "current interfaces. If a file cannot be opened with the access\n"
519 "requested, @code{open-file} throws an exception.")
520#define FUNC_NAME s_scm_i_open_file
521{
522 SCM encoding = SCM_BOOL_F;
523 SCM guess_encoding = SCM_BOOL_F;
524
525 scm_c_bind_keyword_arguments (FUNC_NAME, keyword_args, 0,
526 k_guess_encoding, &guess_encoding,
527 k_encoding, &encoding,
528 SCM_UNDEFINED);
529
530 return scm_open_file_with_encoding (filename, mode,
531 guess_encoding, encoding);
532}
533#undef FUNC_NAME
534
e145dd02 535\f
cb63cf9e 536/* Building Guile ports from a file descriptor. */
e145dd02 537
cb63cf9e 538/* Build a Scheme port from an open file descriptor `fdes'.
a089567e
JB
539 MODE indicates whether FILE is open for reading or writing; it uses
540 the same notation as open-file's second argument.
19b27fa2
GH
541 NAME is a string to be used as the port's filename.
542*/
a089567e 543SCM
d617ee18 544scm_i_fdes_to_port (int fdes, long mode_bits, SCM name)
19b27fa2 545#define FUNC_NAME "scm_fdes_to_port"
a089567e 546{
a089567e 547 SCM port;
92c2555f 548 scm_t_port *pt;
122f24cc 549 scm_t_port_internal *pti;
19b27fa2 550
09b204d3
AW
551 /* Test that fdes is valid. */
552#ifdef F_GETFL
553 int flags = fcntl (fdes, F_GETFL, 0);
19b27fa2
GH
554 if (flags == -1)
555 SCM_SYSERROR;
556 flags &= O_ACCMODE;
557 if (flags != O_RDWR
558 && ((flags != O_WRONLY && (mode_bits & SCM_WRTNG))
559 || (flags != O_RDONLY && (mode_bits & SCM_RDNG))))
560 {
561 SCM_MISC_ERROR ("requested file mode not available on fdes", SCM_EOL);
562 }
09b204d3
AW
563#else
564 /* If we don't have F_GETFL, as on mingw, at least we can test that
565 it is a valid file descriptor. */
566 struct stat st;
567 if (fstat (fdes, &st) != 0)
568 SCM_SYSERROR;
569#endif
a089567e 570
9de87eea 571 scm_i_scm_pthread_mutex_lock (&scm_i_port_table_mutex);
da220f27
HWN
572
573 port = scm_new_port_table_entry (scm_tc16_fport);
574 SCM_SET_CELL_TYPE(port, scm_tc16_fport | mode_bits);
122f24cc
LC
575 pt = SCM_PTAB_ENTRY (port);
576
577 /* File ports support 'setvbuf'. */
578 pti = SCM_PORT_GET_INTERNAL (port);
579 pti->setvbuf = scm_fport_buffer_add;
580
a089567e 581 {
92c2555f 582 scm_t_fport *fp
92d8fd32
LC
583 = (scm_t_fport *) scm_gc_malloc_pointerless (sizeof (scm_t_fport),
584 "file port");
c6c79933 585
cb63cf9e 586 fp->fdes = fdes;
0de97b83 587 pt->rw_random = SCM_FDES_RANDOM_P (fdes);
cb63cf9e
JB
588 SCM_SETSTREAM (port, fp);
589 if (mode_bits & SCM_BUF0)
590 scm_fport_buffer_add (port, 0, 0);
591 else
592 scm_fport_buffer_add (port, -1, -1);
a089567e 593 }
b24b5e13 594 SCM_SET_FILENAME (port, name);
9de87eea 595 scm_i_pthread_mutex_unlock (&scm_i_port_table_mutex);
e145dd02
JB
596 return port;
597}
19b27fa2 598#undef FUNC_NAME
e145dd02 599
d617ee18
MV
600SCM
601scm_fdes_to_port (int fdes, char *mode, SCM name)
602{
603 return scm_i_fdes_to_port (fdes, scm_mode_bits (mode), name);
604}
605
affc96b5 606/* Return a lower bound on the number of bytes available for input. */
cb63cf9e 607static int
affc96b5 608fport_input_waiting (SCM port)
e145dd02 609{
23f2b9a3 610 int fdes = SCM_FSTREAM (port)->fdes;
c7519da3 611
c7519da3
CC
612 struct pollfd pollfd = { fdes, POLLIN, 0 };
613
614 if (poll (&pollfd, 1, 0) < 0)
615 scm_syserror ("fport_input_waiting");
616
617 return pollfd.revents & POLLIN ? 1 : 0;
a089567e
JB
618}
619
cb63cf9e 620\f
0f2d19dd 621static int
e81d98ec 622fport_print (SCM exp, SCM port, scm_print_state *pstate SCM_UNUSED)
0f2d19dd 623{
b3ec3c64
MD
624 scm_puts ("#<", port);
625 scm_print_port_mode (exp, port);
626 if (SCM_OPFPORTP (exp))
0f2d19dd 627 {
b3ec3c64 628 int fdes;
b24b5e13 629 SCM name = SCM_FILENAME (exp);
cc95e00a 630 if (scm_is_string (name) || scm_is_symbol (name))
b24b5e13
DH
631 scm_display (name, port);
632 else
633 scm_puts (SCM_PTOBNAME (SCM_PTOBNUM (exp)), port);
b3ec3c64
MD
634 scm_putc (' ', port);
635 fdes = (SCM_FSTREAM (exp))->fdes;
073167ef
LC
636
637#if (defined HAVE_TTYNAME) && (defined HAVE_POSIX)
b3ec3c64 638 if (isatty (fdes))
eb372585 639 scm_display (scm_ttyname (exp), port);
b3ec3c64 640 else
82893676 641#endif /* HAVE_TTYNAME */
b3ec3c64 642 scm_intprint (fdes, 10, port);
0f2d19dd
JB
643 }
644 else
645 {
b3ec3c64
MD
646 scm_puts (SCM_PTOBNAME (SCM_PTOBNUM (exp)), port);
647 scm_putc (' ', port);
0345e278 648 scm_uintprint ((scm_t_bits) SCM_PTAB_ENTRY (exp), 16, port);
0f2d19dd 649 }
b3ec3c64
MD
650 scm_putc ('>', port);
651 return 1;
0f2d19dd
JB
652}
653
affc96b5 654static void fport_flush (SCM port);
0f2d19dd 655
c2da2648
GH
656/* fill a port's read-buffer with a single read. returns the first
657 char or EOF if end of file. */
889975e5 658static scm_t_wchar
affc96b5 659fport_fill_input (SCM port)
0f2d19dd 660{
c014a02e 661 long count;
92c2555f
MV
662 scm_t_port *pt = SCM_PTAB_ENTRY (port);
663 scm_t_fport *fp = SCM_FSTREAM (port);
cb63cf9e 664
cb63cf9e
JB
665 SCM_SYSCALL (count = read (fp->fdes, pt->read_buf, pt->read_buf_size));
666 if (count == -1)
affc96b5 667 scm_syserror ("fport_fill_input");
cb63cf9e 668 if (count == 0)
889975e5 669 return (scm_t_wchar) EOF;
cb63cf9e
JB
670 else
671 {
5c070ca7 672 pt->read_pos = pt->read_buf;
cb63cf9e 673 pt->read_end = pt->read_buf + count;
5c070ca7 674 return *pt->read_buf;
cb63cf9e 675 }
0f2d19dd
JB
676}
677
0a94eb00
LC
678static scm_t_off
679fport_seek (SCM port, scm_t_off offset, int whence)
0f2d19dd 680{
92c2555f
MV
681 scm_t_port *pt = SCM_PTAB_ENTRY (port);
682 scm_t_fport *fp = SCM_FSTREAM (port);
8ab3d8a0
KR
683 off_t_or_off64_t rv;
684 off_t_or_off64_t result;
7dcb364d
GH
685
686 if (pt->rw_active == SCM_PORT_WRITE)
687 {
688 if (offset != 0 || whence != SEEK_CUR)
689 {
690 fport_flush (port);
8ab3d8a0 691 result = rv = lseek_or_lseek64 (fp->fdes, offset, whence);
7dcb364d
GH
692 }
693 else
694 {
695 /* read current position without disturbing the buffer. */
8ab3d8a0 696 rv = lseek_or_lseek64 (fp->fdes, offset, whence);
7dcb364d
GH
697 result = rv + (pt->write_pos - pt->write_buf);
698 }
699 }
700 else if (pt->rw_active == SCM_PORT_READ)
701 {
702 if (offset != 0 || whence != SEEK_CUR)
703 {
704 /* could expand to avoid a second seek. */
705 scm_end_input (port);
8ab3d8a0 706 result = rv = lseek_or_lseek64 (fp->fdes, offset, whence);
7dcb364d
GH
707 }
708 else
709 {
710 /* read current position without disturbing the buffer
711 (particularly the unread-char buffer). */
8ab3d8a0 712 rv = lseek_or_lseek64 (fp->fdes, offset, whence);
7dcb364d
GH
713 result = rv - (pt->read_end - pt->read_pos);
714
715 if (pt->read_buf == pt->putback_buf)
716 result -= pt->saved_read_end - pt->saved_read_pos;
717 }
718 }
719 else /* SCM_PORT_NEITHER */
720 {
8ab3d8a0 721 result = rv = lseek_or_lseek64 (fp->fdes, offset, whence);
7dcb364d 722 }
cb8dfa3f 723
7dcb364d 724 if (rv == -1)
affc96b5 725 scm_syserror ("fport_seek");
7dcb364d 726
cb8dfa3f 727 return result;
0f2d19dd
JB
728}
729
840ae05d 730static void
f1ce9199 731fport_truncate (SCM port, scm_t_off length)
840ae05d 732{
92c2555f 733 scm_t_fport *fp = SCM_FSTREAM (port);
840ae05d
JB
734
735 if (ftruncate (fp->fdes, length) == -1)
736 scm_syserror ("ftruncate");
737}
738
31703ab8 739static void
8aa011a1 740fport_write (SCM port, const void *data, size_t size)
daa4a3f1 741#define FUNC_NAME "fport_write"
31703ab8 742{
0c6d2191 743 /* this procedure tries to minimize the number of writes/flushes. */
92c2555f 744 scm_t_port *pt = SCM_PTAB_ENTRY (port);
31703ab8 745
0c6d2191
GH
746 if (pt->write_buf == &pt->shortbuf
747 || (pt->write_pos == pt->write_buf && size >= pt->write_buf_size))
31703ab8 748 {
daa4a3f1
LC
749 /* Unbuffered port, or port with empty buffer and data won't fit in
750 buffer. */
751 if (full_write (SCM_FPORT_FDES (port), data, size) < size)
752 SCM_SYSERROR;
753
0c6d2191 754 return;
31703ab8 755 }
d3639214 756
0c6d2191 757 {
f1ce9199 758 scm_t_off space = pt->write_end - pt->write_pos;
0c6d2191
GH
759
760 if (size <= space)
761 {
762 /* data fits in buffer. */
763 memcpy (pt->write_pos, data, size);
764 pt->write_pos += size;
765 if (pt->write_pos == pt->write_end)
766 {
affc96b5 767 fport_flush (port);
0c6d2191
GH
768 /* we can skip the line-buffering check if nothing's buffered. */
769 return;
770 }
771 }
772 else
773 {
774 memcpy (pt->write_pos, data, space);
775 pt->write_pos = pt->write_end;
776 fport_flush (port);
777 {
778 const void *ptr = ((const char *) data) + space;
779 size_t remaining = size - space;
780
781 if (size >= pt->write_buf_size)
782 {
daa4a3f1
LC
783 if (full_write (SCM_FPORT_FDES (port), ptr, remaining)
784 < remaining)
785 SCM_SYSERROR;
0c6d2191
GH
786 return;
787 }
788 else
789 {
790 memcpy (pt->write_pos, ptr, remaining);
791 pt->write_pos += remaining;
792 }
31703ab8 793 }
0c6d2191 794 }
31703ab8 795
0c6d2191
GH
796 /* handle line buffering. */
797 if ((SCM_CELL_WORD_0 (port) & SCM_BUFLINE) && memchr (data, '\n', size))
798 fport_flush (port);
799 }
31703ab8 800}
daa4a3f1 801#undef FUNC_NAME
31703ab8 802
cb63cf9e 803static void
affc96b5 804fport_flush (SCM port)
0f2d19dd 805{
5335850d 806 size_t written;
92c2555f
MV
807 scm_t_port *pt = SCM_PTAB_ENTRY (port);
808 scm_t_fport *fp = SCM_FSTREAM (port);
5335850d 809 size_t count = pt->write_pos - pt->write_buf;
cb63cf9e 810
5335850d
LC
811 written = full_write (fp->fdes, pt->write_buf, count);
812 if (written < count)
813 scm_syserror ("scm_flush");
cb63cf9e 814
cb63cf9e 815 pt->write_pos = pt->write_buf;
61e452ba 816 pt->rw_active = SCM_PORT_NEITHER;
840ae05d
JB
817}
818
283a1a0e 819/* clear the read buffer and adjust the file position for unread bytes. */
840ae05d 820static void
affc96b5 821fport_end_input (SCM port, int offset)
840ae05d 822{
92c2555f
MV
823 scm_t_fport *fp = SCM_FSTREAM (port);
824 scm_t_port *pt = SCM_PTAB_ENTRY (port);
283a1a0e
GH
825
826 offset += pt->read_end - pt->read_pos;
840ae05d 827
840ae05d
JB
828 if (offset > 0)
829 {
830 pt->read_pos = pt->read_end;
831 /* will throw error if unread-char used at beginning of file
832 then attempting to write. seems correct. */
833 if (lseek (fp->fdes, -offset, SEEK_CUR) == -1)
affc96b5 834 scm_syserror ("fport_end_input");
840ae05d 835 }
61e452ba 836 pt->rw_active = SCM_PORT_NEITHER;
8f29fbd0
JB
837}
838
6a2c4c81 839static int
affc96b5 840fport_close (SCM port)
6a2c4c81 841{
92c2555f
MV
842 scm_t_fport *fp = SCM_FSTREAM (port);
843 scm_t_port *pt = SCM_PTAB_ENTRY (port);
cb63cf9e 844 int rv;
840ae05d 845
affc96b5 846 fport_flush (port);
cb63cf9e
JB
847 SCM_SYSCALL (rv = close (fp->fdes));
848 if (rv == -1 && errno != EBADF)
6b72ac1d
GH
849 {
850 if (scm_gc_running_p)
851 /* silently ignore the error. scm_error would abort if we
852 called it now. */
853 ;
854 else
855 scm_syserror ("fport_close");
856 }
6c951427
GH
857 if (pt->read_buf == pt->putback_buf)
858 pt->read_buf = pt->saved_read_buf;
cb63cf9e 859 if (pt->read_buf != &pt->shortbuf)
4c9419ac 860 scm_gc_free (pt->read_buf, pt->read_buf_size, "port buffer");
cb63cf9e 861 if (pt->write_buf != &pt->shortbuf)
4c9419ac
MV
862 scm_gc_free (pt->write_buf, pt->write_buf_size, "port buffer");
863 scm_gc_free (fp, sizeof (*fp), "file port");
cb63cf9e 864 return rv;
6a2c4c81
JB
865}
866
1be6b49c 867static size_t
affc96b5 868fport_free (SCM port)
b3ec3c64 869{
affc96b5 870 fport_close (port);
b3ec3c64
MD
871 return 0;
872}
873
92c2555f 874static scm_t_bits
b3ec3c64
MD
875scm_make_fptob ()
876{
92c2555f 877 scm_t_bits tc = scm_make_port_type ("file", fport_fill_input, fport_write);
a98bddfd 878
affc96b5 879 scm_set_port_free (tc, fport_free);
e841c3e0 880 scm_set_port_print (tc, fport_print);
affc96b5
GH
881 scm_set_port_flush (tc, fport_flush);
882 scm_set_port_end_input (tc, fport_end_input);
883 scm_set_port_close (tc, fport_close);
884 scm_set_port_seek (tc, fport_seek);
885 scm_set_port_truncate (tc, fport_truncate);
886 scm_set_port_input_waiting (tc, fport_input_waiting);
a98bddfd
DH
887
888 return tc;
b3ec3c64 889}
0f2d19dd 890
3ace9a8e
MW
891/* We can't initialize the keywords from 'scm_init_fports', because
892 keywords haven't yet been initialized at that point. */
893void
894scm_init_fports_keywords ()
895{
896 k_guess_encoding = scm_from_latin1_keyword ("guess-encoding");
897 k_encoding = scm_from_latin1_keyword ("encoding");
898}
899
0f2d19dd
JB
900void
901scm_init_fports ()
0f2d19dd 902{
a98bddfd
DH
903 scm_tc16_fport = scm_make_fptob ();
904
e11e83f3
MV
905 scm_c_define ("_IOFBF", scm_from_int (_IOFBF));
906 scm_c_define ("_IOLBF", scm_from_int (_IOLBF));
907 scm_c_define ("_IONBF", scm_from_int (_IONBF));
a98bddfd 908
69cac238
AW
909 sys_file_port_name_canonicalization = scm_make_fluid ();
910 scm_c_define ("%file-port-name-canonicalization",
911 sys_file_port_name_canonicalization);
912
a98bddfd 913#include "libguile/fports.x"
0f2d19dd 914}
89e00824
ML
915
916/*
917 Local Variables:
918 c-file-style: "gnu"
919 End:
920*/