Fix broken hash-table merge.
[bpt/guile.git] / libguile / fports.c
CommitLineData
b226295a 1/* Copyright (C) 1995,1996,1997,1998,1999,2000,2001, 2002, 2003, 2004, 2006, 2007, 2008 Free Software Foundation, Inc.
0f2d19dd 2 *
73be1d9e
MV
3 * This library is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU Lesser General Public
5 * License as published by the Free Software Foundation; either
6 * version 2.1 of the License, or (at your option) any later version.
0f2d19dd 7 *
73be1d9e
MV
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
0f2d19dd 12 *
73be1d9e
MV
13 * You should have received a copy of the GNU Lesser General Public
14 * License along with this library; if not, write to the Free Software
92205699 15 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
73be1d9e 16 */
1bbd0b84 17
1bbd0b84 18
0f2d19dd 19\f
8ab3d8a0
KR
20#define _LARGEFILE64_SOURCE /* ask for stat64 etc */
21
85286595
RB
22#if HAVE_CONFIG_H
23# include <config.h>
24#endif
0f2d19dd
JB
25
26#include <stdio.h>
cb63cf9e 27#include <fcntl.h>
a0599745
MD
28#include "libguile/_scm.h"
29#include "libguile/strings.h"
a0599745 30#include "libguile/validate.h"
6b72ac1d 31#include "libguile/gc.h"
eb372585 32#include "libguile/posix.h"
7f9994d9 33#include "libguile/dynwind.h"
5dbc6c06 34#include "libguile/hashtab.h"
6b72ac1d 35
a0599745 36#include "libguile/fports.h"
95b88819
GH
37
38#ifdef HAVE_STRING_H
39#include <string.h>
40#endif
0f2d19dd
JB
41#ifdef HAVE_UNISTD_H
42#include <unistd.h>
0f2d19dd 43#endif
b8b17bfd
MV
44#ifdef HAVE_IO_H
45#include <io.h>
46#endif
f47a5239 47#ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
cb63cf9e
JB
48#include <sys/stat.h>
49#endif
0f2d19dd 50
cb63cf9e 51#include <errno.h>
8ab3d8a0 52#include <sys/types.h>
e145dd02 53
a0599745 54#include "libguile/iselect.h"
edb810bb
SJ
55
56/* Some defines for Windows (native port, not Cygwin). */
82893676
MG
57#ifdef __MINGW32__
58# include <sys/stat.h>
59# include <winsock2.h>
82893676 60#endif /* __MINGW32__ */
cb63cf9e 61
8ab3d8a0
KR
62/* Mingw (version 3.4.5, circa 2006) has ftruncate as an alias for chsize
63 already, but have this code here in case that wasn't so in past versions,
64 or perhaps to help other minimal DOS environments.
65
66 gnulib ftruncate.c has code using fcntl F_CHSIZE and F_FREESP, which
67 might be possibilities if we've got other systems without ftruncate. */
68
69#if HAVE_CHSIZE && ! HAVE_FTRUNCATE
70# define ftruncate(fd, size) chsize (fd, size)
71#undef HAVE_FTRUNCATE
72#define HAVE_FTRUNCATE 1
73#endif
74
75#if SIZEOF_OFF_T == SIZEOF_INT
76#define OFF_T_MAX INT_MAX
77#define OFF_T_MIN INT_MIN
78#elif SIZEOF_OFF_T == SIZEOF_LONG
79#define OFF_T_MAX LONG_MAX
80#define OFF_T_MIN LONG_MIN
81#elif SIZEOF_OFF_T == SIZEOF_LONG_LONG
82#define OFF_T_MAX LONG_LONG_MAX
83#define OFF_T_MIN LONG_LONG_MIN
84#else
85#error Oops, unknown OFF_T size
86#endif
a98bddfd 87
92c2555f 88scm_t_bits scm_tc16_fport;
a98bddfd
DH
89
90
19b27fa2 91/* default buffer size, used if the O/S won't supply a value. */
1be6b49c 92static const size_t default_buffer_size = 1024;
19b27fa2 93
cb63cf9e
JB
94/* create FPORT buffer with specified sizes (or -1 to use default size or
95 0 for no buffer. */
96static void
c014a02e 97scm_fport_buffer_add (SCM port, long read_size, int write_size)
c6c79933 98#define FUNC_NAME "scm_fport_buffer_add"
e145dd02 99{
92c2555f 100 scm_t_port *pt = SCM_PTAB_ENTRY (port);
e145dd02 101
cb63cf9e
JB
102 if (read_size == -1 || write_size == -1)
103 {
1be6b49c 104 size_t default_size;
f47a5239 105#ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
cb63cf9e 106 struct stat st;
b8b17bfd 107 scm_t_fport *fp = SCM_FSTREAM (port);
cb63cf9e 108
19b27fa2
GH
109 default_size = (fstat (fp->fdes, &st) == -1) ? default_buffer_size
110 : st.st_blksize;
cb63cf9e 111#else
19b27fa2 112 default_size = default_buffer_size;
cb63cf9e
JB
113#endif
114 if (read_size == -1)
115 read_size = default_size;
116 if (write_size == -1)
117 write_size = default_size;
118 }
0f2d19dd 119
f5f2dcff 120 if (SCM_INPUT_PORT_P (port) && read_size > 0)
cb63cf9e 121 {
92d8fd32 122 pt->read_buf = scm_gc_malloc_pointerless (read_size, "port buffer");
cb63cf9e
JB
123 pt->read_pos = pt->read_end = pt->read_buf;
124 pt->read_buf_size = read_size;
125 }
126 else
127 {
840ae05d 128 pt->read_pos = pt->read_buf = pt->read_end = &pt->shortbuf;
cb63cf9e
JB
129 pt->read_buf_size = 1;
130 }
1717856b 131
f5f2dcff 132 if (SCM_OUTPUT_PORT_P (port) && write_size > 0)
cb63cf9e 133 {
92d8fd32 134 pt->write_buf = scm_gc_malloc_pointerless (write_size, "port buffer");
cb63cf9e
JB
135 pt->write_pos = pt->write_buf;
136 pt->write_buf_size = write_size;
137 }
138 else
139 {
140 pt->write_buf = pt->write_pos = &pt->shortbuf;
141 pt->write_buf_size = 1;
142 }
143
144 pt->write_end = pt->write_buf + pt->write_buf_size;
145 if (read_size > 0 || write_size > 0)
54778cd3 146 SCM_SET_CELL_WORD_0 (port, SCM_CELL_WORD_0 (port) & ~SCM_BUF0);
cb63cf9e 147 else
54778cd3 148 SCM_SET_CELL_WORD_0 (port, SCM_CELL_WORD_0 (port) | SCM_BUF0);
7a6f1ffa 149}
c6c79933 150#undef FUNC_NAME
7a6f1ffa 151
a1ec6916 152SCM_DEFINE (scm_setvbuf, "setvbuf", 2, 1, 0,
1bbd0b84 153 (SCM port, SCM mode, SCM size),
fc0d72d4
MD
154 "Set the buffering mode for @var{port}. @var{mode} can be:\n"
155 "@table @code\n"
156 "@item _IONBF\n"
157 "non-buffered\n"
158 "@item _IOLBF\n"
159 "line buffered\n"
160 "@item _IOFBF\n"
161 "block buffered, using a newly allocated buffer of @var{size} bytes.\n"
162 "If @var{size} is omitted, a default size will be used.\n"
2c1ae20e 163 "@end table")
1bbd0b84 164#define FUNC_NAME s_scm_setvbuf
7a6f1ffa 165{
1be6b49c 166 int cmode;
c014a02e 167 long csize;
92c2555f 168 scm_t_port *pt;
7a6f1ffa 169
78446828
MV
170 port = SCM_COERCE_OUTPORT (port);
171
3b3b36dd 172 SCM_VALIDATE_OPFPORT (1,port);
a55c2b68 173 cmode = scm_to_int (mode);
d3639214 174 if (cmode != _IONBF && cmode != _IOFBF && cmode != _IOLBF)
1bbd0b84 175 scm_out_of_range (FUNC_NAME, mode);
d3639214
GH
176
177 if (cmode == _IOLBF)
178 {
54778cd3 179 SCM_SET_CELL_WORD_0 (port, SCM_CELL_WORD_0 (port) | SCM_BUFLINE);
d3639214
GH
180 cmode = _IOFBF;
181 }
182 else
183 {
2b829bbb 184 SCM_SET_CELL_WORD_0 (port, SCM_CELL_WORD_0 (port) & ~(scm_t_bits)SCM_BUFLINE);
d3639214
GH
185 }
186
7a6f1ffa 187 if (SCM_UNBNDP (size))
cb63cf9e
JB
188 {
189 if (cmode == _IOFBF)
190 csize = -1;
191 else
192 csize = 0;
193 }
7a6f1ffa
GH
194 else
195 {
a55c2b68 196 csize = scm_to_int (size);
cb63cf9e 197 if (csize < 0 || (cmode == _IONBF && csize > 0))
1bbd0b84 198 scm_out_of_range (FUNC_NAME, size);
7a6f1ffa 199 }
d3639214 200
cb63cf9e 201 pt = SCM_PTAB_ENTRY (port);
7a6f1ffa 202
4c9419ac
MV
203 /* silently discards buffered and put-back chars. */
204 if (pt->read_buf == pt->putback_buf)
205 {
206 pt->read_buf = pt->saved_read_buf;
207 pt->read_pos = pt->saved_read_pos;
208 pt->read_end = pt->saved_read_end;
209 pt->read_buf_size = pt->saved_read_buf_size;
210 }
cb63cf9e 211 if (pt->read_buf != &pt->shortbuf)
4c9419ac 212 scm_gc_free (pt->read_buf, pt->read_buf_size, "port buffer");
cb63cf9e 213 if (pt->write_buf != &pt->shortbuf)
4c9419ac 214 scm_gc_free (pt->write_buf, pt->write_buf_size, "port buffer");
7a6f1ffa 215
cb63cf9e
JB
216 scm_fport_buffer_add (port, csize, csize);
217 return SCM_UNSPECIFIED;
0f2d19dd 218}
1bbd0b84 219#undef FUNC_NAME
0f2d19dd 220
eadd48de 221/* Move ports with the specified file descriptor to new descriptors,
387d418c 222 * resetting the revealed count to 0.
0f2d19dd 223 */
ee834df4
LC
224static void
225scm_i_evict_port (void *closure, SCM port)
0f2d19dd 226{
5dbc6c06 227 int fd = * (int*) closure;
0f2d19dd 228
5dbc6c06 229 if (SCM_FPORTP (port))
eadd48de 230 {
5dbc6c06 231 scm_t_fport *fp = SCM_FSTREAM (port);
cb63cf9e 232
5dbc6c06 233 if (fp->fdes == fd)
eadd48de 234 {
5dbc6c06
HWN
235 fp->fdes = dup (fd);
236 if (fp->fdes == -1)
237 scm_syserror ("scm_evict_ports");
238 scm_set_port_revealed_x (port, scm_from_int (0));
eadd48de
GH
239 }
240 }
5dbc6c06
HWN
241}
242
243void
244scm_evict_ports (int fd)
245{
ee834df4 246 scm_c_port_for_each (scm_i_evict_port, (void *) &fd);
eadd48de 247}
0f2d19dd 248
efa40607
DH
249
250SCM_DEFINE (scm_file_port_p, "file-port?", 1, 0, 0,
251 (SCM obj),
2069af38 252 "Determine whether @var{obj} is a port that is related to a file.")
efa40607
DH
253#define FUNC_NAME s_scm_file_port_p
254{
7888309b 255 return scm_from_bool (SCM_FPORTP (obj));
efa40607
DH
256}
257#undef FUNC_NAME
258
259
0f2d19dd
JB
260/* scm_open_file
261 * Return a new port open on a given file.
262 *
263 * The mode string must match the pattern: [rwa+]** which
264 * is interpreted in the usual unix way.
265 *
266 * Return the new port.
267 */
3b3b36dd 268SCM_DEFINE (scm_open_file, "open-file", 2, 0, 0,
1e6808ea
MG
269 (SCM filename, SCM mode),
270 "Open the file whose name is @var{filename}, and return a port\n"
fc0d72d4 271 "representing that file. The attributes of the port are\n"
1e6808ea
MG
272 "determined by the @var{mode} string. The way in which this is\n"
273 "interpreted is similar to C stdio. The first character must be\n"
274 "one of the following:\n"
fc0d72d4
MD
275 "@table @samp\n"
276 "@item r\n"
277 "Open an existing file for input.\n"
278 "@item w\n"
279 "Open a file for output, creating it if it doesn't already exist\n"
280 "or removing its contents if it does.\n"
281 "@item a\n"
1e6808ea
MG
282 "Open a file for output, creating it if it doesn't already\n"
283 "exist. All writes to the port will go to the end of the file.\n"
fc0d72d4
MD
284 "The \"append mode\" can be turned off while the port is in use\n"
285 "@pxref{Ports and File Descriptors, fcntl}\n"
1e6808ea
MG
286 "@end table\n"
287 "The following additional characters can be appended:\n"
fc0d72d4 288 "@table @samp\n"
fc9c5d06
HWN
289 "@item b\n"
290 "Open the underlying file in binary mode, if supported by the operating system. "
fc0d72d4
MD
291 "@item +\n"
292 "Open the port for both input and output. E.g., @code{r+}: open\n"
293 "an existing file for both input and output.\n"
294 "@item 0\n"
1e6808ea
MG
295 "Create an \"unbuffered\" port. In this case input and output\n"
296 "operations are passed directly to the underlying port\n"
297 "implementation without additional buffering. This is likely to\n"
298 "slow down I/O operations. The buffering mode can be changed\n"
299 "while a port is in use @pxref{Ports and File Descriptors,\n"
300 "setvbuf}\n"
fc0d72d4
MD
301 "@item l\n"
302 "Add line-buffering to the port. The port output buffer will be\n"
303 "automatically flushed whenever a newline character is written.\n"
1e6808ea
MG
304 "@end table\n"
305 "In theory we could create read/write ports which were buffered\n"
306 "in one direction only. However this isn't included in the\n"
307 "current interfaces. If a file cannot be opened with the access\n"
308 "requested, @code{open-file} throws an exception.")
1bbd0b84 309#define FUNC_NAME s_scm_open_file
0f2d19dd 310{
19639113 311 SCM port;
cb63cf9e
JB
312 int fdes;
313 int flags = 0;
19639113 314 char *file;
1e6808ea 315 char *md;
cb63cf9e 316 char *ptr;
19639113 317
661ae7ab 318 scm_dynwind_begin (0);
19639113 319
7f9994d9 320 file = scm_to_locale_string (filename);
661ae7ab 321 scm_dynwind_free (file);
7f9994d9
MV
322
323 md = scm_to_locale_string (mode);
661ae7ab 324 scm_dynwind_free (md);
19639113 325
1e6808ea 326 switch (*md)
0f2d19dd 327 {
cb63cf9e
JB
328 case 'r':
329 flags |= O_RDONLY;
330 break;
331 case 'w':
332 flags |= O_WRONLY | O_CREAT | O_TRUNC;
333 break;
334 case 'a':
335 flags |= O_WRONLY | O_CREAT | O_APPEND;
336 break;
337 default:
1e6808ea 338 scm_out_of_range (FUNC_NAME, mode);
0f2d19dd 339 }
1e6808ea 340 ptr = md + 1;
cb63cf9e 341 while (*ptr != '\0')
e145dd02 342 {
cb63cf9e
JB
343 switch (*ptr)
344 {
345 case '+':
346 flags = (flags & ~(O_RDONLY | O_WRONLY)) | O_RDWR;
347 break;
9f561420
GH
348 case 'b':
349#if defined (O_BINARY)
350 flags |= O_BINARY;
351#endif
352 break;
cb63cf9e 353 case '0': /* unbuffered: handled later. */
d3639214 354 case 'l': /* line buffered: handled during output. */
cb63cf9e
JB
355 break;
356 default:
1e6808ea 357 scm_out_of_range (FUNC_NAME, mode);
cb63cf9e
JB
358 }
359 ptr++;
e145dd02 360 }
8ab3d8a0 361 SCM_SYSCALL (fdes = open_or_open64 (file, flags, 0666));
cb63cf9e 362 if (fdes == -1)
e145dd02 363 {
cb63cf9e
JB
364 int en = errno;
365
5d2d2ffc 366 SCM_SYSERROR_MSG ("~A: ~S",
fd08c236 367 scm_cons (scm_strerror (scm_from_int (en)),
5d2d2ffc 368 scm_cons (filename, SCM_EOL)), en);
0f2d19dd 369 }
d617ee18 370 port = scm_i_fdes_to_port (fdes, scm_i_mode_bits (mode), filename);
7f9994d9 371
661ae7ab 372 scm_dynwind_end ();
7f9994d9 373
0f2d19dd
JB
374 return port;
375}
1bbd0b84 376#undef FUNC_NAME
0f2d19dd 377
e145dd02 378\f
82893676
MG
379#ifdef __MINGW32__
380/*
381 * Try getting the appropiate file flags for a given file descriptor
382 * under Windows. This incorporates some fancy operations because Windows
383 * differentiates between file, pipe and socket descriptors.
384 */
385#ifndef O_ACCMODE
386# define O_ACCMODE 0x0003
387#endif
388
389static int getflags (int fdes)
390{
391 int flags = 0;
392 struct stat buf;
393 int error, optlen = sizeof (int);
394
395 /* Is this a socket ? */
396 if (getsockopt (fdes, SOL_SOCKET, SO_ERROR, (void *) &error, &optlen) >= 0)
397 flags = O_RDWR;
398 /* Maybe a regular file ? */
399 else if (fstat (fdes, &buf) < 0)
400 flags = -1;
401 else
402 {
403 /* Or an anonymous pipe handle ? */
b8b17bfd 404 if (buf.st_mode & _S_IFIFO)
8f99e3f3
SJ
405 flags = PeekNamedPipe ((HANDLE) _get_osfhandle (fdes), NULL, 0,
406 NULL, NULL, NULL) ? O_RDONLY : O_WRONLY;
82893676 407 /* stdin ? */
b8b17bfd 408 else if (fdes == fileno (stdin) && isatty (fdes))
82893676
MG
409 flags = O_RDONLY;
410 /* stdout / stderr ? */
b8b17bfd
MV
411 else if ((fdes == fileno (stdout) || fdes == fileno (stderr)) &&
412 isatty (fdes))
82893676
MG
413 flags = O_WRONLY;
414 else
415 flags = buf.st_mode;
416 }
417 return flags;
418}
419#endif /* __MINGW32__ */
420
cb63cf9e 421/* Building Guile ports from a file descriptor. */
e145dd02 422
cb63cf9e 423/* Build a Scheme port from an open file descriptor `fdes'.
a089567e
JB
424 MODE indicates whether FILE is open for reading or writing; it uses
425 the same notation as open-file's second argument.
19b27fa2
GH
426 NAME is a string to be used as the port's filename.
427*/
a089567e 428SCM
d617ee18 429scm_i_fdes_to_port (int fdes, long mode_bits, SCM name)
19b27fa2 430#define FUNC_NAME "scm_fdes_to_port"
a089567e 431{
a089567e 432 SCM port;
92c2555f 433 scm_t_port *pt;
19b27fa2
GH
434 int flags;
435
436 /* test that fdes is valid. */
82893676
MG
437#ifdef __MINGW32__
438 flags = getflags (fdes);
439#else
19b27fa2 440 flags = fcntl (fdes, F_GETFL, 0);
82893676 441#endif
19b27fa2
GH
442 if (flags == -1)
443 SCM_SYSERROR;
444 flags &= O_ACCMODE;
445 if (flags != O_RDWR
446 && ((flags != O_WRONLY && (mode_bits & SCM_WRTNG))
447 || (flags != O_RDONLY && (mode_bits & SCM_RDNG))))
448 {
449 SCM_MISC_ERROR ("requested file mode not available on fdes", SCM_EOL);
450 }
a089567e 451
9de87eea 452 scm_i_scm_pthread_mutex_lock (&scm_i_port_table_mutex);
da220f27
HWN
453
454 port = scm_new_port_table_entry (scm_tc16_fport);
455 SCM_SET_CELL_TYPE(port, scm_tc16_fport | mode_bits);
456 pt = SCM_PTAB_ENTRY(port);
a089567e 457 {
92c2555f 458 scm_t_fport *fp
92d8fd32
LC
459 = (scm_t_fport *) scm_gc_malloc_pointerless (sizeof (scm_t_fport),
460 "file port");
c6c79933 461
cb63cf9e 462 fp->fdes = fdes;
0de97b83 463 pt->rw_random = SCM_FDES_RANDOM_P (fdes);
cb63cf9e
JB
464 SCM_SETSTREAM (port, fp);
465 if (mode_bits & SCM_BUF0)
466 scm_fport_buffer_add (port, 0, 0);
467 else
468 scm_fport_buffer_add (port, -1, -1);
a089567e 469 }
b24b5e13 470 SCM_SET_FILENAME (port, name);
9de87eea 471 scm_i_pthread_mutex_unlock (&scm_i_port_table_mutex);
e145dd02
JB
472 return port;
473}
19b27fa2 474#undef FUNC_NAME
e145dd02 475
d617ee18
MV
476SCM
477scm_fdes_to_port (int fdes, char *mode, SCM name)
478{
479 return scm_i_fdes_to_port (fdes, scm_mode_bits (mode), name);
480}
481
affc96b5 482/* Return a lower bound on the number of bytes available for input. */
cb63cf9e 483static int
affc96b5 484fport_input_waiting (SCM port)
e145dd02 485{
cb63cf9e 486#ifdef HAVE_SELECT
23f2b9a3 487 int fdes = SCM_FSTREAM (port)->fdes;
cb63cf9e
JB
488 struct timeval timeout;
489 SELECT_TYPE read_set;
490 SELECT_TYPE write_set;
491 SELECT_TYPE except_set;
492
493 FD_ZERO (&read_set);
494 FD_ZERO (&write_set);
495 FD_ZERO (&except_set);
496
497 FD_SET (fdes, &read_set);
498
499 timeout.tv_sec = 0;
500 timeout.tv_usec = 0;
501
502 if (select (SELECT_SET_SIZE,
503 &read_set, &write_set, &except_set, &timeout)
504 < 0)
affc96b5
GH
505 scm_syserror ("fport_input_waiting");
506 return FD_ISSET (fdes, &read_set) ? 1 : 0;
23f2b9a3
KR
507
508#elif HAVE_IOCTL && defined (FIONREAD)
509 /* Note: cannot test just defined(FIONREAD) here, since mingw has FIONREAD
510 (for use with winsock ioctlsocket()) but not ioctl(). */
511 int fdes = SCM_FSTREAM (port)->fdes;
cb63cf9e
JB
512 int remir;
513 ioctl(fdes, FIONREAD, &remir);
514 return remir;
23f2b9a3 515
cb63cf9e 516#else
affc96b5 517 scm_misc_error ("fport_input_waiting",
cb63cf9e
JB
518 "Not fully implemented on this platform",
519 SCM_EOL);
520#endif
a089567e
JB
521}
522
cb63cf9e 523\f
0f2d19dd 524static int
e81d98ec 525fport_print (SCM exp, SCM port, scm_print_state *pstate SCM_UNUSED)
0f2d19dd 526{
b3ec3c64
MD
527 scm_puts ("#<", port);
528 scm_print_port_mode (exp, port);
529 if (SCM_OPFPORTP (exp))
0f2d19dd 530 {
b3ec3c64 531 int fdes;
b24b5e13 532 SCM name = SCM_FILENAME (exp);
cc95e00a 533 if (scm_is_string (name) || scm_is_symbol (name))
b24b5e13
DH
534 scm_display (name, port);
535 else
536 scm_puts (SCM_PTOBNAME (SCM_PTOBNUM (exp)), port);
b3ec3c64
MD
537 scm_putc (' ', port);
538 fdes = (SCM_FSTREAM (exp))->fdes;
539
82893676 540#ifdef HAVE_TTYNAME
b3ec3c64 541 if (isatty (fdes))
eb372585 542 scm_display (scm_ttyname (exp), port);
b3ec3c64 543 else
82893676 544#endif /* HAVE_TTYNAME */
b3ec3c64 545 scm_intprint (fdes, 10, port);
0f2d19dd
JB
546 }
547 else
548 {
b3ec3c64
MD
549 scm_puts (SCM_PTOBNAME (SCM_PTOBNUM (exp)), port);
550 scm_putc (' ', port);
0345e278 551 scm_uintprint ((scm_t_bits) SCM_PTAB_ENTRY (exp), 16, port);
0f2d19dd 552 }
b3ec3c64
MD
553 scm_putc ('>', port);
554 return 1;
0f2d19dd
JB
555}
556
2e945bcc 557#ifndef __MINGW32__
cb63cf9e
JB
558/* thread-local block for input on fport's fdes. */
559static void
560fport_wait_for_input (SCM port)
3cb988bd 561{
cb63cf9e 562 int fdes = SCM_FSTREAM (port)->fdes;
3cb988bd 563
affc96b5 564 if (!fport_input_waiting (port))
8122b543 565 {
cb63cf9e
JB
566 int n;
567 SELECT_TYPE readfds;
568 int flags = fcntl (fdes, F_GETFL);
569
570 if (flags == -1)
571 scm_syserror ("scm_fdes_wait_for_input");
572 if (!(flags & O_NONBLOCK))
573 do
574 {
575 FD_ZERO (&readfds);
576 FD_SET (fdes, &readfds);
9de87eea 577 n = scm_std_select (fdes + 1, &readfds, NULL, NULL, NULL);
cb63cf9e
JB
578 }
579 while (n == -1 && errno == EINTR);
8122b543 580 }
3cb988bd 581}
2e945bcc 582#endif /* !__MINGW32__ */
0f2d19dd 583
affc96b5 584static void fport_flush (SCM port);
0f2d19dd 585
c2da2648
GH
586/* fill a port's read-buffer with a single read. returns the first
587 char or EOF if end of file. */
0f2d19dd 588static int
affc96b5 589fport_fill_input (SCM port)
0f2d19dd 590{
c014a02e 591 long count;
92c2555f
MV
592 scm_t_port *pt = SCM_PTAB_ENTRY (port);
593 scm_t_fport *fp = SCM_FSTREAM (port);
cb63cf9e 594
2e945bcc 595#ifndef __MINGW32__
cb63cf9e 596 fport_wait_for_input (port);
2e945bcc 597#endif /* !__MINGW32__ */
cb63cf9e
JB
598 SCM_SYSCALL (count = read (fp->fdes, pt->read_buf, pt->read_buf_size));
599 if (count == -1)
affc96b5 600 scm_syserror ("fport_fill_input");
cb63cf9e
JB
601 if (count == 0)
602 return EOF;
603 else
604 {
5c070ca7 605 pt->read_pos = pt->read_buf;
cb63cf9e 606 pt->read_end = pt->read_buf + count;
5c070ca7 607 return *pt->read_buf;
cb63cf9e 608 }
0f2d19dd
JB
609}
610
8ab3d8a0
KR
611static off_t_or_off64_t
612fport_seek_or_seek64 (SCM port, off_t_or_off64_t offset, int whence)
0f2d19dd 613{
92c2555f
MV
614 scm_t_port *pt = SCM_PTAB_ENTRY (port);
615 scm_t_fport *fp = SCM_FSTREAM (port);
8ab3d8a0
KR
616 off_t_or_off64_t rv;
617 off_t_or_off64_t result;
7dcb364d
GH
618
619 if (pt->rw_active == SCM_PORT_WRITE)
620 {
621 if (offset != 0 || whence != SEEK_CUR)
622 {
623 fport_flush (port);
8ab3d8a0 624 result = rv = lseek_or_lseek64 (fp->fdes, offset, whence);
7dcb364d
GH
625 }
626 else
627 {
628 /* read current position without disturbing the buffer. */
8ab3d8a0 629 rv = lseek_or_lseek64 (fp->fdes, offset, whence);
7dcb364d
GH
630 result = rv + (pt->write_pos - pt->write_buf);
631 }
632 }
633 else if (pt->rw_active == SCM_PORT_READ)
634 {
635 if (offset != 0 || whence != SEEK_CUR)
636 {
637 /* could expand to avoid a second seek. */
638 scm_end_input (port);
8ab3d8a0 639 result = rv = lseek_or_lseek64 (fp->fdes, offset, whence);
7dcb364d
GH
640 }
641 else
642 {
643 /* read current position without disturbing the buffer
644 (particularly the unread-char buffer). */
8ab3d8a0 645 rv = lseek_or_lseek64 (fp->fdes, offset, whence);
7dcb364d
GH
646 result = rv - (pt->read_end - pt->read_pos);
647
648 if (pt->read_buf == pt->putback_buf)
649 result -= pt->saved_read_end - pt->saved_read_pos;
650 }
651 }
652 else /* SCM_PORT_NEITHER */
653 {
8ab3d8a0 654 result = rv = lseek_or_lseek64 (fp->fdes, offset, whence);
7dcb364d 655 }
cb8dfa3f 656
7dcb364d 657 if (rv == -1)
affc96b5 658 scm_syserror ("fport_seek");
7dcb364d 659
cb8dfa3f 660 return result;
0f2d19dd
JB
661}
662
8ab3d8a0
KR
663/* If we've got largefile and off_t isn't already off64_t then
664 fport_seek_or_seek64 needs a range checking wrapper to be fport_seek in
665 the port descriptor.
666
667 Otherwise if no largefile, or off_t is the same as off64_t (which is the
668 case on NetBSD apparently), then fport_seek_or_seek64 is right to be
669 fport_seek already. */
670
d05bcb2e 671#if GUILE_USE_64_CALLS && HAVE_STAT64 && SIZEOF_OFF_T != SIZEOF_OFF64_T
8ab3d8a0
KR
672static off_t
673fport_seek (SCM port, off_t offset, int whence)
674{
675 off64_t rv = fport_seek_or_seek64 (port, (off64_t) offset, whence);
676 if (rv > OFF_T_MAX || rv < OFF_T_MIN)
677 {
678 errno = EOVERFLOW;
679 scm_syserror ("fport_seek");
680 }
681 return (off_t) rv;
682
683}
684#else
685#define fport_seek fport_seek_or_seek64
686#endif
687
688/* `how' has been validated and is one of SEEK_SET, SEEK_CUR or SEEK_END */
689SCM
690scm_i_fport_seek (SCM port, SCM offset, int how)
691{
692 return scm_from_off_t_or_off64_t
693 (fport_seek_or_seek64 (port, scm_to_off_t_or_off64_t (offset), how));
694}
695
840ae05d 696static void
affc96b5 697fport_truncate (SCM port, off_t length)
840ae05d 698{
92c2555f 699 scm_t_fport *fp = SCM_FSTREAM (port);
840ae05d
JB
700
701 if (ftruncate (fp->fdes, length) == -1)
702 scm_syserror ("ftruncate");
703}
704
8ab3d8a0
KR
705int
706scm_i_fport_truncate (SCM port, SCM length)
707{
708 scm_t_fport *fp = SCM_FSTREAM (port);
709 return ftruncate_or_ftruncate64 (fp->fdes, scm_to_off_t_or_off64_t (length));
710}
711
0c6d2191
GH
712/* helper for fport_write: try to write data, using multiple system
713 calls if required. */
714#define FUNC_NAME "write_all"
715static void write_all (SCM port, const void *data, size_t remaining)
716{
717 int fdes = SCM_FSTREAM (port)->fdes;
718
719 while (remaining > 0)
720 {
82893676 721 size_t done;
0c6d2191
GH
722
723 SCM_SYSCALL (done = write (fdes, data, remaining));
724
725 if (done == -1)
726 SCM_SYSERROR;
727 remaining -= done;
728 data = ((const char *) data) + done;
729 }
730}
731#undef FUNC_NAME
732
31703ab8 733static void
8aa011a1 734fport_write (SCM port, const void *data, size_t size)
31703ab8 735{
0c6d2191 736 /* this procedure tries to minimize the number of writes/flushes. */
92c2555f 737 scm_t_port *pt = SCM_PTAB_ENTRY (port);
31703ab8 738
0c6d2191
GH
739 if (pt->write_buf == &pt->shortbuf
740 || (pt->write_pos == pt->write_buf && size >= pt->write_buf_size))
31703ab8 741 {
0c6d2191
GH
742 /* "unbuffered" port, or
743 port with empty buffer and data won't fit in buffer. */
744 write_all (port, data, size);
745 return;
31703ab8 746 }
d3639214 747
0c6d2191
GH
748 {
749 off_t space = pt->write_end - pt->write_pos;
750
751 if (size <= space)
752 {
753 /* data fits in buffer. */
754 memcpy (pt->write_pos, data, size);
755 pt->write_pos += size;
756 if (pt->write_pos == pt->write_end)
757 {
affc96b5 758 fport_flush (port);
0c6d2191
GH
759 /* we can skip the line-buffering check if nothing's buffered. */
760 return;
761 }
762 }
763 else
764 {
765 memcpy (pt->write_pos, data, space);
766 pt->write_pos = pt->write_end;
767 fport_flush (port);
768 {
769 const void *ptr = ((const char *) data) + space;
770 size_t remaining = size - space;
771
772 if (size >= pt->write_buf_size)
773 {
774 write_all (port, ptr, remaining);
775 return;
776 }
777 else
778 {
779 memcpy (pt->write_pos, ptr, remaining);
780 pt->write_pos += remaining;
781 }
31703ab8 782 }
0c6d2191 783 }
31703ab8 784
0c6d2191
GH
785 /* handle line buffering. */
786 if ((SCM_CELL_WORD_0 (port) & SCM_BUFLINE) && memchr (data, '\n', size))
787 fport_flush (port);
788 }
31703ab8
GH
789}
790
791/* becomes 1 when process is exiting: normal exception handling won't
792 work by this time. */
04a98cff 793extern int scm_i_terminating;
0f2d19dd 794
cb63cf9e 795static void
affc96b5 796fport_flush (SCM port)
0f2d19dd 797{
92c2555f
MV
798 scm_t_port *pt = SCM_PTAB_ENTRY (port);
799 scm_t_fport *fp = SCM_FSTREAM (port);
6f760c1d 800 unsigned char *ptr = pt->write_buf;
c014a02e
ML
801 long init_size = pt->write_pos - pt->write_buf;
802 long remaining = init_size;
0f2d19dd 803
cb63cf9e
JB
804 while (remaining > 0)
805 {
c014a02e 806 long count;
cb63cf9e
JB
807
808 SCM_SYSCALL (count = write (fp->fdes, ptr, remaining));
809 if (count < 0)
810 {
811 /* error. assume nothing was written this call, but
812 fix up the buffer for any previous successful writes. */
c014a02e 813 long done = init_size - remaining;
cb63cf9e
JB
814
815 if (done > 0)
816 {
817 int i;
818
819 for (i = 0; i < remaining; i++)
820 {
821 *(pt->write_buf + i) = *(pt->write_buf + done + i);
822 }
823 pt->write_pos = pt->write_buf + remaining;
824 }
04a98cff 825 if (scm_i_terminating)
cb63cf9e
JB
826 {
827 const char *msg = "Error: could not flush file-descriptor ";
828 char buf[11];
829
830 write (2, msg, strlen (msg));
831 sprintf (buf, "%d\n", fp->fdes);
832 write (2, buf, strlen (buf));
833
834 count = remaining;
835 }
6b72ac1d
GH
836 else if (scm_gc_running_p)
837 {
838 /* silently ignore the error. scm_error would abort if we
839 called it now. */
840 count = remaining;
841 }
842 else
843 scm_syserror ("fport_flush");
cb63cf9e
JB
844 }
845 ptr += count;
846 remaining -= count;
847 }
848 pt->write_pos = pt->write_buf;
61e452ba 849 pt->rw_active = SCM_PORT_NEITHER;
840ae05d
JB
850}
851
283a1a0e 852/* clear the read buffer and adjust the file position for unread bytes. */
840ae05d 853static void
affc96b5 854fport_end_input (SCM port, int offset)
840ae05d 855{
92c2555f
MV
856 scm_t_fport *fp = SCM_FSTREAM (port);
857 scm_t_port *pt = SCM_PTAB_ENTRY (port);
283a1a0e
GH
858
859 offset += pt->read_end - pt->read_pos;
840ae05d 860
840ae05d
JB
861 if (offset > 0)
862 {
863 pt->read_pos = pt->read_end;
864 /* will throw error if unread-char used at beginning of file
865 then attempting to write. seems correct. */
866 if (lseek (fp->fdes, -offset, SEEK_CUR) == -1)
affc96b5 867 scm_syserror ("fport_end_input");
840ae05d 868 }
61e452ba 869 pt->rw_active = SCM_PORT_NEITHER;
8f29fbd0
JB
870}
871
6a2c4c81 872static int
affc96b5 873fport_close (SCM port)
6a2c4c81 874{
92c2555f
MV
875 scm_t_fport *fp = SCM_FSTREAM (port);
876 scm_t_port *pt = SCM_PTAB_ENTRY (port);
cb63cf9e 877 int rv;
840ae05d 878
affc96b5 879 fport_flush (port);
cb63cf9e
JB
880 SCM_SYSCALL (rv = close (fp->fdes));
881 if (rv == -1 && errno != EBADF)
6b72ac1d
GH
882 {
883 if (scm_gc_running_p)
884 /* silently ignore the error. scm_error would abort if we
885 called it now. */
886 ;
887 else
888 scm_syserror ("fport_close");
889 }
6c951427
GH
890 if (pt->read_buf == pt->putback_buf)
891 pt->read_buf = pt->saved_read_buf;
cb63cf9e 892 if (pt->read_buf != &pt->shortbuf)
4c9419ac 893 scm_gc_free (pt->read_buf, pt->read_buf_size, "port buffer");
cb63cf9e 894 if (pt->write_buf != &pt->shortbuf)
4c9419ac
MV
895 scm_gc_free (pt->write_buf, pt->write_buf_size, "port buffer");
896 scm_gc_free (fp, sizeof (*fp), "file port");
cb63cf9e 897 return rv;
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
a98bddfd 933#include "libguile/fports.x"
0f2d19dd 934}
89e00824
ML
935
936/*
937 Local Variables:
938 c-file-style: "gnu"
939 End:
940*/