Merge remote-tracking branch 'origin/stable-2.0'
[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>
e145dd02 49
5335850d
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"
8ab3d8a0 59
629987ed 60#include "libguile/fports.h"
8ab3d8a0
KR
61
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))
4251ae2e 210 scm_flush_unlocked (port);
67a72dc1 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"
352 "\"ISO-8859-1\", ignoring the port's encoding and the coding declaration\n"
353 "at the top of the input file, if any.\n"
fc0d72d4
MD
354 "@item +\n"
355 "Open the port for both input and output. E.g., @code{r+}: open\n"
356 "an existing file for both input and output.\n"
357 "@item 0\n"
1e6808ea
MG
358 "Create an \"unbuffered\" port. In this case input and output\n"
359 "operations are passed directly to the underlying port\n"
360 "implementation without additional buffering. This is likely to\n"
361 "slow down I/O operations. The buffering mode can be changed\n"
362 "while a port is in use @pxref{Ports and File Descriptors,\n"
363 "setvbuf}\n"
fc0d72d4
MD
364 "@item l\n"
365 "Add line-buffering to the port. The port output buffer will be\n"
366 "automatically flushed whenever a newline character is written.\n"
1e6808ea 367 "@end table\n"
211683cc
MG
368 "When the file is opened, this procedure will scan for a coding\n"
369 "declaration@pxref{Character Encoding of Source Files}. If present\n"
370 "will use that encoding for interpreting the file. Otherwise, the\n"
371 "port's encoding will be used.\n"
372 "\n"
1e6808ea
MG
373 "In theory we could create read/write ports which were buffered\n"
374 "in one direction only. However this isn't included in the\n"
375 "current interfaces. If a file cannot be opened with the access\n"
376 "requested, @code{open-file} throws an exception.")
1bbd0b84 377#define FUNC_NAME s_scm_open_file
0f2d19dd 378{
19639113 379 SCM port;
211683cc 380 int fdes, flags = 0, use_encoding = 1;
64e3a89c
LC
381 unsigned int retries;
382 char *file, *md, *ptr;
19639113 383
661ae7ab 384 scm_dynwind_begin (0);
19639113 385
7f9994d9 386 file = scm_to_locale_string (filename);
661ae7ab 387 scm_dynwind_free (file);
7f9994d9
MV
388
389 md = scm_to_locale_string (mode);
661ae7ab 390 scm_dynwind_free (md);
19639113 391
1e6808ea 392 switch (*md)
0f2d19dd 393 {
cb63cf9e
JB
394 case 'r':
395 flags |= O_RDONLY;
396 break;
397 case 'w':
398 flags |= O_WRONLY | O_CREAT | O_TRUNC;
399 break;
400 case 'a':
401 flags |= O_WRONLY | O_CREAT | O_APPEND;
402 break;
403 default:
1e6808ea 404 scm_out_of_range (FUNC_NAME, mode);
0f2d19dd 405 }
1e6808ea 406 ptr = md + 1;
cb63cf9e 407 while (*ptr != '\0')
e145dd02 408 {
cb63cf9e
JB
409 switch (*ptr)
410 {
411 case '+':
412 flags = (flags & ~(O_RDONLY | O_WRONLY)) | O_RDWR;
413 break;
9f561420 414 case 'b':
211683cc 415 use_encoding = 0;
9f561420
GH
416#if defined (O_BINARY)
417 flags |= O_BINARY;
418#endif
419 break;
cb63cf9e 420 case '0': /* unbuffered: handled later. */
d3639214 421 case 'l': /* line buffered: handled during output. */
cb63cf9e
JB
422 break;
423 default:
1e6808ea 424 scm_out_of_range (FUNC_NAME, mode);
cb63cf9e
JB
425 }
426 ptr++;
e145dd02 427 }
cb63cf9e 428
64e3a89c
LC
429 for (retries = 0, fdes = -1;
430 fdes < 0 && retries < 2;
431 retries++)
432 {
433 SCM_SYSCALL (fdes = open_or_open64 (file, flags, 0666));
434 if (fdes == -1)
435 {
436 int en = errno;
437
438 if (en == EMFILE && retries == 0)
439 /* Run the GC in case it collects open file ports that are no
440 longer referenced. */
441 scm_i_gc (FUNC_NAME);
442 else
443 SCM_SYSERROR_MSG ("~A: ~S",
444 scm_cons (scm_strerror (scm_from_int (en)),
445 scm_cons (filename, SCM_EOL)), en);
446 }
0f2d19dd 447 }
64e3a89c 448
211683cc
MG
449 /* Create a port from this file descriptor. The port's encoding is initially
450 %default-port-encoding. */
0157a341
AW
451 port = scm_i_fdes_to_port (fdes, scm_i_mode_bits (mode),
452 fport_canonicalize_filename (filename));
7f9994d9 453
211683cc
MG
454 if (use_encoding)
455 {
456 /* If this file has a coding declaration, use that as the port
457 encoding. */
458 if (SCM_INPUT_PORT_P (port))
459 {
460 char *enc = scm_i_scan_for_encoding (port);
461 if (enc != NULL)
462 scm_i_set_port_encoding_x (port, enc);
463 }
464 }
465 else
466 /* If this is a binary file, use the binary-friendly ISO-8859-1
467 encoding. */
468 scm_i_set_port_encoding_x (port, NULL);
469
661ae7ab 470 scm_dynwind_end ();
7f9994d9 471
0f2d19dd
JB
472 return port;
473}
1bbd0b84 474#undef FUNC_NAME
0f2d19dd 475
e145dd02 476\f
cb63cf9e 477/* Building Guile ports from a file descriptor. */
e145dd02 478
cb63cf9e 479/* Build a Scheme port from an open file descriptor `fdes'.
a089567e
JB
480 MODE indicates whether FILE is open for reading or writing; it uses
481 the same notation as open-file's second argument.
19b27fa2
GH
482 NAME is a string to be used as the port's filename.
483*/
a089567e 484SCM
d617ee18 485scm_i_fdes_to_port (int fdes, long mode_bits, SCM name)
19b27fa2 486#define FUNC_NAME "scm_fdes_to_port"
a089567e 487{
a089567e 488 SCM port;
2721f918 489 scm_t_fport *fp;
19b27fa2 490
09b204d3
AW
491 /* Test that fdes is valid. */
492#ifdef F_GETFL
493 int flags = fcntl (fdes, F_GETFL, 0);
19b27fa2
GH
494 if (flags == -1)
495 SCM_SYSERROR;
496 flags &= O_ACCMODE;
497 if (flags != O_RDWR
498 && ((flags != O_WRONLY && (mode_bits & SCM_WRTNG))
499 || (flags != O_RDONLY && (mode_bits & SCM_RDNG))))
500 {
501 SCM_MISC_ERROR ("requested file mode not available on fdes", SCM_EOL);
502 }
09b204d3
AW
503#else
504 /* If we don't have F_GETFL, as on mingw, at least we can test that
505 it is a valid file descriptor. */
506 struct stat st;
507 if (fstat (fdes, &st) != 0)
508 SCM_SYSERROR;
509#endif
a089567e 510
2721f918
AW
511 fp = (scm_t_fport *) scm_gc_malloc_pointerless (sizeof (scm_t_fport),
512 "file port");
513 fp->fdes = fdes;
514
515 port = scm_c_make_port (scm_tc16_fport, mode_bits, (scm_t_bits)fp);
516
517 SCM_PTAB_ENTRY (port)->rw_random = SCM_FDES_RANDOM_P (fdes);
518
519 if (mode_bits & SCM_BUF0)
520 scm_fport_buffer_add (port, 0, 0);
521 else
522 scm_fport_buffer_add (port, -1, -1);
523
b24b5e13 524 SCM_SET_FILENAME (port, name);
2721f918 525
e145dd02
JB
526 return port;
527}
19b27fa2 528#undef FUNC_NAME
e145dd02 529
d617ee18
MV
530SCM
531scm_fdes_to_port (int fdes, char *mode, SCM name)
532{
533 return scm_i_fdes_to_port (fdes, scm_mode_bits (mode), name);
534}
535
affc96b5 536/* Return a lower bound on the number of bytes available for input. */
cb63cf9e 537static int
affc96b5 538fport_input_waiting (SCM port)
e145dd02 539{
23f2b9a3 540 int fdes = SCM_FSTREAM (port)->fdes;
c7519da3 541
c7519da3
CC
542 struct pollfd pollfd = { fdes, POLLIN, 0 };
543
544 if (poll (&pollfd, 1, 0) < 0)
545 scm_syserror ("fport_input_waiting");
546
547 return pollfd.revents & POLLIN ? 1 : 0;
a089567e
JB
548}
549
3753e227
AW
550
551\f
552
553/* Revealed counts --- an oddity inherited from SCSH. */
554
555#define SCM_REVEALED(x) (SCM_FSTREAM(x)->revealed)
556
557static SCM revealed_ports = SCM_EOL;
558static scm_i_pthread_mutex_t revealed_lock = SCM_I_PTHREAD_MUTEX_INITIALIZER;
3753e227
AW
559
560/* Find a port in the table and return its revealed count.
561 Also used by the garbage collector.
562 */
563int
564scm_revealed_count (SCM port)
565{
566 int ret;
567
568 scm_i_pthread_mutex_lock (&revealed_lock);
569 ret = SCM_REVEALED (port);
570 scm_i_pthread_mutex_unlock (&revealed_lock);
571
572 return ret;
573}
574
575SCM_DEFINE (scm_port_revealed, "port-revealed", 1, 0, 0,
576 (SCM port),
577 "Return the revealed count for @var{port}.")
578#define FUNC_NAME s_scm_port_revealed
579{
580 port = SCM_COERCE_OUTPORT (port);
581 SCM_VALIDATE_OPFPORT (1, port);
582 return scm_from_int (scm_revealed_count (port));
583}
584#undef FUNC_NAME
585
586/* Set the revealed count for a port. */
587SCM_DEFINE (scm_set_port_revealed_x, "set-port-revealed!", 2, 0, 0,
588 (SCM port, SCM rcount),
589 "Sets the revealed count for a port to a given value.\n"
590 "The return value is unspecified.")
591#define FUNC_NAME s_scm_set_port_revealed_x
592{
593 int r, prev;
594
595 port = SCM_COERCE_OUTPORT (port);
596 SCM_VALIDATE_OPFPORT (1, port);
597
598 r = scm_to_int (rcount);
599
600 scm_i_pthread_mutex_lock (&revealed_lock);
601
602 prev = SCM_REVEALED (port);
603 SCM_REVEALED (port) = r;
604
605 if (r && !prev)
606 revealed_ports = scm_cons (port, revealed_ports);
607 else if (prev && !r)
608 revealed_ports = scm_delq_x (port, revealed_ports);
609
610 scm_i_pthread_mutex_unlock (&revealed_lock);
611
612 return SCM_UNSPECIFIED;
613}
614#undef FUNC_NAME
615
616/* Set the revealed count for a port. */
617SCM_DEFINE (scm_adjust_port_revealed_x, "adjust-port-revealed!", 2, 0, 0,
618 (SCM port, SCM addend),
619 "Add @var{addend} to the revealed count of @var{port}.\n"
620 "The return value is unspecified.")
621#define FUNC_NAME s_scm_adjust_port_revealed_x
622{
623 int a;
624
625 port = SCM_COERCE_OUTPORT (port);
626 SCM_VALIDATE_OPFPORT (1, port);
627
628 a = scm_to_int (addend);
629 if (!a)
630 return SCM_UNSPECIFIED;
631
632 scm_i_pthread_mutex_lock (&revealed_lock);
633
634 SCM_REVEALED (port) += a;
635 if (SCM_REVEALED (port) == a)
636 revealed_ports = scm_cons (port, revealed_ports);
637 else if (!SCM_REVEALED (port))
638 revealed_ports = scm_delq_x (port, revealed_ports);
639
640 scm_i_pthread_mutex_unlock (&revealed_lock);
641
642 return SCM_UNSPECIFIED;
643}
644#undef FUNC_NAME
645
646
cb63cf9e 647\f
0f2d19dd 648static int
e81d98ec 649fport_print (SCM exp, SCM port, scm_print_state *pstate SCM_UNUSED)
0f2d19dd 650{
0607ebbf 651 scm_puts_unlocked ("#<", port);
b3ec3c64
MD
652 scm_print_port_mode (exp, port);
653 if (SCM_OPFPORTP (exp))
0f2d19dd 654 {
b3ec3c64 655 int fdes;
b24b5e13 656 SCM name = SCM_FILENAME (exp);
cc95e00a 657 if (scm_is_string (name) || scm_is_symbol (name))
b24b5e13
DH
658 scm_display (name, port);
659 else
0607ebbf
AW
660 scm_puts_unlocked (SCM_PTOBNAME (SCM_PTOBNUM (exp)), port);
661 scm_putc_unlocked (' ', port);
b3ec3c64 662 fdes = (SCM_FSTREAM (exp))->fdes;
073167ef
LC
663
664#if (defined HAVE_TTYNAME) && (defined HAVE_POSIX)
b3ec3c64 665 if (isatty (fdes))
eb372585 666 scm_display (scm_ttyname (exp), port);
b3ec3c64 667 else
82893676 668#endif /* HAVE_TTYNAME */
b3ec3c64 669 scm_intprint (fdes, 10, port);
0f2d19dd
JB
670 }
671 else
672 {
0607ebbf
AW
673 scm_puts_unlocked (SCM_PTOBNAME (SCM_PTOBNUM (exp)), port);
674 scm_putc_unlocked (' ', port);
0345e278 675 scm_uintprint ((scm_t_bits) SCM_PTAB_ENTRY (exp), 16, port);
0f2d19dd 676 }
0607ebbf 677 scm_putc_unlocked ('>', port);
b3ec3c64 678 return 1;
0f2d19dd
JB
679}
680
affc96b5 681static void fport_flush (SCM port);
0f2d19dd 682
c2da2648
GH
683/* fill a port's read-buffer with a single read. returns the first
684 char or EOF if end of file. */
889975e5 685static scm_t_wchar
affc96b5 686fport_fill_input (SCM port)
0f2d19dd 687{
c014a02e 688 long count;
92c2555f
MV
689 scm_t_port *pt = SCM_PTAB_ENTRY (port);
690 scm_t_fport *fp = SCM_FSTREAM (port);
cb63cf9e 691
cb63cf9e
JB
692 SCM_SYSCALL (count = read (fp->fdes, pt->read_buf, pt->read_buf_size));
693 if (count == -1)
affc96b5 694 scm_syserror ("fport_fill_input");
cb63cf9e 695 if (count == 0)
889975e5 696 return (scm_t_wchar) EOF;
cb63cf9e
JB
697 else
698 {
5c070ca7 699 pt->read_pos = pt->read_buf;
cb63cf9e 700 pt->read_end = pt->read_buf + count;
5c070ca7 701 return *pt->read_buf;
cb63cf9e 702 }
0f2d19dd
JB
703}
704
0a94eb00
LC
705static scm_t_off
706fport_seek (SCM port, scm_t_off offset, int whence)
0f2d19dd 707{
92c2555f
MV
708 scm_t_port *pt = SCM_PTAB_ENTRY (port);
709 scm_t_fport *fp = SCM_FSTREAM (port);
8ab3d8a0
KR
710 off_t_or_off64_t rv;
711 off_t_or_off64_t result;
7dcb364d
GH
712
713 if (pt->rw_active == SCM_PORT_WRITE)
714 {
715 if (offset != 0 || whence != SEEK_CUR)
716 {
717 fport_flush (port);
8ab3d8a0 718 result = rv = lseek_or_lseek64 (fp->fdes, offset, whence);
7dcb364d
GH
719 }
720 else
721 {
722 /* read current position without disturbing the buffer. */
8ab3d8a0 723 rv = lseek_or_lseek64 (fp->fdes, offset, whence);
7dcb364d
GH
724 result = rv + (pt->write_pos - pt->write_buf);
725 }
726 }
727 else if (pt->rw_active == SCM_PORT_READ)
728 {
729 if (offset != 0 || whence != SEEK_CUR)
730 {
731 /* could expand to avoid a second seek. */
4251ae2e 732 scm_end_input_unlocked (port);
8ab3d8a0 733 result = rv = lseek_or_lseek64 (fp->fdes, offset, whence);
7dcb364d
GH
734 }
735 else
736 {
737 /* read current position without disturbing the buffer
738 (particularly the unread-char buffer). */
8ab3d8a0 739 rv = lseek_or_lseek64 (fp->fdes, offset, whence);
7dcb364d
GH
740 result = rv - (pt->read_end - pt->read_pos);
741
742 if (pt->read_buf == pt->putback_buf)
743 result -= pt->saved_read_end - pt->saved_read_pos;
744 }
745 }
746 else /* SCM_PORT_NEITHER */
747 {
8ab3d8a0 748 result = rv = lseek_or_lseek64 (fp->fdes, offset, whence);
7dcb364d 749 }
cb8dfa3f 750
7dcb364d 751 if (rv == -1)
affc96b5 752 scm_syserror ("fport_seek");
7dcb364d 753
cb8dfa3f 754 return result;
0f2d19dd
JB
755}
756
840ae05d 757static void
f1ce9199 758fport_truncate (SCM port, scm_t_off length)
840ae05d 759{
92c2555f 760 scm_t_fport *fp = SCM_FSTREAM (port);
840ae05d
JB
761
762 if (ftruncate (fp->fdes, length) == -1)
763 scm_syserror ("ftruncate");
764}
765
31703ab8 766static void
8aa011a1 767fport_write (SCM port, const void *data, size_t size)
daa4a3f1 768#define FUNC_NAME "fport_write"
31703ab8 769{
0c6d2191 770 /* this procedure tries to minimize the number of writes/flushes. */
92c2555f 771 scm_t_port *pt = SCM_PTAB_ENTRY (port);
31703ab8 772
0c6d2191
GH
773 if (pt->write_buf == &pt->shortbuf
774 || (pt->write_pos == pt->write_buf && size >= pt->write_buf_size))
31703ab8 775 {
daa4a3f1
LC
776 /* Unbuffered port, or port with empty buffer and data won't fit in
777 buffer. */
778 if (full_write (SCM_FPORT_FDES (port), data, size) < size)
779 SCM_SYSERROR;
780
0c6d2191 781 return;
31703ab8 782 }
d3639214 783
0c6d2191 784 {
f1ce9199 785 scm_t_off space = pt->write_end - pt->write_pos;
0c6d2191
GH
786
787 if (size <= space)
788 {
789 /* data fits in buffer. */
790 memcpy (pt->write_pos, data, size);
791 pt->write_pos += size;
792 if (pt->write_pos == pt->write_end)
793 {
affc96b5 794 fport_flush (port);
0c6d2191
GH
795 /* we can skip the line-buffering check if nothing's buffered. */
796 return;
797 }
798 }
799 else
800 {
801 memcpy (pt->write_pos, data, space);
802 pt->write_pos = pt->write_end;
803 fport_flush (port);
804 {
805 const void *ptr = ((const char *) data) + space;
806 size_t remaining = size - space;
807
808 if (size >= pt->write_buf_size)
809 {
daa4a3f1
LC
810 if (full_write (SCM_FPORT_FDES (port), ptr, remaining)
811 < remaining)
812 SCM_SYSERROR;
0c6d2191
GH
813 return;
814 }
815 else
816 {
817 memcpy (pt->write_pos, ptr, remaining);
818 pt->write_pos += remaining;
819 }
31703ab8 820 }
0c6d2191 821 }
31703ab8 822
0c6d2191
GH
823 /* handle line buffering. */
824 if ((SCM_CELL_WORD_0 (port) & SCM_BUFLINE) && memchr (data, '\n', size))
825 fport_flush (port);
826 }
31703ab8 827}
daa4a3f1 828#undef FUNC_NAME
31703ab8 829
cb63cf9e 830static void
affc96b5 831fport_flush (SCM port)
0f2d19dd 832{
5335850d 833 size_t written;
92c2555f
MV
834 scm_t_port *pt = SCM_PTAB_ENTRY (port);
835 scm_t_fport *fp = SCM_FSTREAM (port);
5335850d 836 size_t count = pt->write_pos - pt->write_buf;
cb63cf9e 837
5335850d
LC
838 written = full_write (fp->fdes, pt->write_buf, count);
839 if (written < count)
840 scm_syserror ("scm_flush");
cb63cf9e 841
cb63cf9e 842 pt->write_pos = pt->write_buf;
61e452ba 843 pt->rw_active = SCM_PORT_NEITHER;
840ae05d
JB
844}
845
283a1a0e 846/* clear the read buffer and adjust the file position for unread bytes. */
840ae05d 847static void
affc96b5 848fport_end_input (SCM port, int offset)
840ae05d 849{
92c2555f
MV
850 scm_t_fport *fp = SCM_FSTREAM (port);
851 scm_t_port *pt = SCM_PTAB_ENTRY (port);
283a1a0e
GH
852
853 offset += pt->read_end - pt->read_pos;
840ae05d 854
840ae05d
JB
855 if (offset > 0)
856 {
857 pt->read_pos = pt->read_end;
858 /* will throw error if unread-char used at beginning of file
859 then attempting to write. seems correct. */
860 if (lseek (fp->fdes, -offset, SEEK_CUR) == -1)
affc96b5 861 scm_syserror ("fport_end_input");
840ae05d 862 }
61e452ba 863 pt->rw_active = SCM_PORT_NEITHER;
8f29fbd0
JB
864}
865
5a771d5f
AW
866static void
867close_the_fd (void *data)
868{
869 scm_t_fport *fp = data;
870
871 close (fp->fdes);
872 /* There's already one exception. That's probably enough! */
873 errno = 0;
874}
875
6a2c4c81 876static int
affc96b5 877fport_close (SCM port)
6a2c4c81 878{
92c2555f 879 scm_t_fport *fp = SCM_FSTREAM (port);
cb63cf9e 880 int rv;
840ae05d 881
5a771d5f
AW
882 scm_dynwind_begin (0);
883 scm_dynwind_unwind_handler (close_the_fd, fp, 0);
affc96b5 884 fport_flush (port);
5a771d5f
AW
885 scm_dynwind_end ();
886
887 scm_port_non_buffer (SCM_PTAB_ENTRY (port));
888
889 rv = close (fp->fdes);
890 if (rv)
891 /* It's not useful to retry after EINTR, as the file descriptor is
892 in an undefined state. See http://lwn.net/Articles/365294/.
893 Instead just throw an error if close fails, trusting that the fd
894 was cleaned up. */
895 scm_syserror ("fport_close");
896
897 return 0;
6a2c4c81
JB
898}
899
1be6b49c 900static size_t
affc96b5 901fport_free (SCM port)
b3ec3c64 902{
affc96b5 903 fport_close (port);
b3ec3c64
MD
904 return 0;
905}
906
92c2555f 907static scm_t_bits
b3ec3c64
MD
908scm_make_fptob ()
909{
92c2555f 910 scm_t_bits tc = scm_make_port_type ("file", fport_fill_input, fport_write);
a98bddfd 911
affc96b5 912 scm_set_port_free (tc, fport_free);
e841c3e0 913 scm_set_port_print (tc, fport_print);
affc96b5
GH
914 scm_set_port_flush (tc, fport_flush);
915 scm_set_port_end_input (tc, fport_end_input);
916 scm_set_port_close (tc, fport_close);
917 scm_set_port_seek (tc, fport_seek);
918 scm_set_port_truncate (tc, fport_truncate);
919 scm_set_port_input_waiting (tc, fport_input_waiting);
a98bddfd
DH
920
921 return tc;
b3ec3c64 922}
0f2d19dd 923
0f2d19dd
JB
924void
925scm_init_fports ()
0f2d19dd 926{
a98bddfd
DH
927 scm_tc16_fport = scm_make_fptob ();
928
e11e83f3
MV
929 scm_c_define ("_IOFBF", scm_from_int (_IOFBF));
930 scm_c_define ("_IOLBF", scm_from_int (_IOLBF));
931 scm_c_define ("_IONBF", scm_from_int (_IONBF));
a98bddfd 932
69cac238
AW
933 sys_file_port_name_canonicalization = scm_make_fluid ();
934 scm_c_define ("%file-port-name-canonicalization",
935 sys_file_port_name_canonicalization);
936
a98bddfd 937#include "libguile/fports.x"
0f2d19dd 938}
89e00824
ML
939
940/*
941 Local Variables:
942 c-file-style: "gnu"
943 End:
944*/