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