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