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