replace port table with weak hash table. This simplifies
[bpt/guile.git] / libguile / fports.c
CommitLineData
2b829bbb 1/* Copyright (C) 1995,1996,1997,1998,1999,2000,2001, 2002, 2003, 2004, 2006 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 {
4c9419ac 122 pt->read_buf = scm_gc_malloc (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 {
4c9419ac 134 pt->write_buf = scm_gc_malloc (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 */
5dbc6c06
HWN
224static SCM
225scm_i_evict_port (SCM handle, void *closure)
0f2d19dd 226{
5dbc6c06
HWN
227 int fd = * (int*) closure;
228 SCM port = SCM_CAR (handle);
0f2d19dd 229
5dbc6c06 230 if (SCM_FPORTP (port))
eadd48de 231 {
5dbc6c06 232 scm_t_fport *fp = SCM_FSTREAM (port);
cb63cf9e 233
5dbc6c06 234 if (fp->fdes == fd)
eadd48de 235 {
5dbc6c06
HWN
236 fp->fdes = dup (fd);
237 if (fp->fdes == -1)
238 scm_syserror ("scm_evict_ports");
239 scm_set_port_revealed_x (port, scm_from_int (0));
eadd48de
GH
240 }
241 }
b9ad392e 242
5dbc6c06
HWN
243 return handle;
244}
245
246void
247scm_evict_ports (int fd)
248{
249 scm_i_scm_pthread_mutex_lock (&scm_i_port_table_mutex);
250 scm_internal_hash_for_each_handle (&scm_i_evict_port,
251 (void*) &fd,
252 scm_i_port_weak_hash);
9de87eea 253 scm_i_pthread_mutex_unlock (&scm_i_port_table_mutex);
eadd48de 254}
0f2d19dd 255
efa40607
DH
256
257SCM_DEFINE (scm_file_port_p, "file-port?", 1, 0, 0,
258 (SCM obj),
2069af38 259 "Determine whether @var{obj} is a port that is related to a file.")
efa40607
DH
260#define FUNC_NAME s_scm_file_port_p
261{
7888309b 262 return scm_from_bool (SCM_FPORTP (obj));
efa40607
DH
263}
264#undef FUNC_NAME
265
266
0f2d19dd
JB
267/* scm_open_file
268 * Return a new port open on a given file.
269 *
270 * The mode string must match the pattern: [rwa+]** which
271 * is interpreted in the usual unix way.
272 *
273 * Return the new port.
274 */
3b3b36dd 275SCM_DEFINE (scm_open_file, "open-file", 2, 0, 0,
1e6808ea
MG
276 (SCM filename, SCM mode),
277 "Open the file whose name is @var{filename}, and return a port\n"
fc0d72d4 278 "representing that file. The attributes of the port are\n"
1e6808ea
MG
279 "determined by the @var{mode} string. The way in which this is\n"
280 "interpreted is similar to C stdio. The first character must be\n"
281 "one of the following:\n"
fc0d72d4
MD
282 "@table @samp\n"
283 "@item r\n"
284 "Open an existing file for input.\n"
285 "@item w\n"
286 "Open a file for output, creating it if it doesn't already exist\n"
287 "or removing its contents if it does.\n"
288 "@item a\n"
1e6808ea
MG
289 "Open a file for output, creating it if it doesn't already\n"
290 "exist. All writes to the port will go to the end of the file.\n"
fc0d72d4
MD
291 "The \"append mode\" can be turned off while the port is in use\n"
292 "@pxref{Ports and File Descriptors, fcntl}\n"
1e6808ea
MG
293 "@end table\n"
294 "The following additional characters can be appended:\n"
fc0d72d4 295 "@table @samp\n"
fc9c5d06
HWN
296 "@item b\n"
297 "Open the underlying file in binary mode, if supported by the operating system. "
fc0d72d4
MD
298 "@item +\n"
299 "Open the port for both input and output. E.g., @code{r+}: open\n"
300 "an existing file for both input and output.\n"
301 "@item 0\n"
1e6808ea
MG
302 "Create an \"unbuffered\" port. In this case input and output\n"
303 "operations are passed directly to the underlying port\n"
304 "implementation without additional buffering. This is likely to\n"
305 "slow down I/O operations. The buffering mode can be changed\n"
306 "while a port is in use @pxref{Ports and File Descriptors,\n"
307 "setvbuf}\n"
fc0d72d4
MD
308 "@item l\n"
309 "Add line-buffering to the port. The port output buffer will be\n"
310 "automatically flushed whenever a newline character is written.\n"
1e6808ea
MG
311 "@end table\n"
312 "In theory we could create read/write ports which were buffered\n"
313 "in one direction only. However this isn't included in the\n"
314 "current interfaces. If a file cannot be opened with the access\n"
315 "requested, @code{open-file} throws an exception.")
1bbd0b84 316#define FUNC_NAME s_scm_open_file
0f2d19dd 317{
19639113 318 SCM port;
cb63cf9e
JB
319 int fdes;
320 int flags = 0;
19639113 321 char *file;
1e6808ea 322 char *md;
cb63cf9e 323 char *ptr;
19639113 324
661ae7ab 325 scm_dynwind_begin (0);
19639113 326
7f9994d9 327 file = scm_to_locale_string (filename);
661ae7ab 328 scm_dynwind_free (file);
7f9994d9
MV
329
330 md = scm_to_locale_string (mode);
661ae7ab 331 scm_dynwind_free (md);
19639113 332
1e6808ea 333 switch (*md)
0f2d19dd 334 {
cb63cf9e
JB
335 case 'r':
336 flags |= O_RDONLY;
337 break;
338 case 'w':
339 flags |= O_WRONLY | O_CREAT | O_TRUNC;
340 break;
341 case 'a':
342 flags |= O_WRONLY | O_CREAT | O_APPEND;
343 break;
344 default:
1e6808ea 345 scm_out_of_range (FUNC_NAME, mode);
0f2d19dd 346 }
1e6808ea 347 ptr = md + 1;
cb63cf9e 348 while (*ptr != '\0')
e145dd02 349 {
cb63cf9e
JB
350 switch (*ptr)
351 {
352 case '+':
353 flags = (flags & ~(O_RDONLY | O_WRONLY)) | O_RDWR;
354 break;
9f561420
GH
355 case 'b':
356#if defined (O_BINARY)
357 flags |= O_BINARY;
358#endif
359 break;
cb63cf9e 360 case '0': /* unbuffered: handled later. */
d3639214 361 case 'l': /* line buffered: handled during output. */
cb63cf9e
JB
362 break;
363 default:
1e6808ea 364 scm_out_of_range (FUNC_NAME, mode);
cb63cf9e
JB
365 }
366 ptr++;
e145dd02 367 }
8ab3d8a0 368 SCM_SYSCALL (fdes = open_or_open64 (file, flags, 0666));
cb63cf9e 369 if (fdes == -1)
e145dd02 370 {
cb63cf9e
JB
371 int en = errno;
372
5d2d2ffc 373 SCM_SYSERROR_MSG ("~A: ~S",
fd08c236 374 scm_cons (scm_strerror (scm_from_int (en)),
5d2d2ffc 375 scm_cons (filename, SCM_EOL)), en);
0f2d19dd 376 }
d617ee18 377 port = scm_i_fdes_to_port (fdes, scm_i_mode_bits (mode), filename);
7f9994d9 378
661ae7ab 379 scm_dynwind_end ();
7f9994d9 380
0f2d19dd
JB
381 return port;
382}
1bbd0b84 383#undef FUNC_NAME
0f2d19dd 384
e145dd02 385\f
82893676
MG
386#ifdef __MINGW32__
387/*
388 * Try getting the appropiate file flags for a given file descriptor
389 * under Windows. This incorporates some fancy operations because Windows
390 * differentiates between file, pipe and socket descriptors.
391 */
392#ifndef O_ACCMODE
393# define O_ACCMODE 0x0003
394#endif
395
396static int getflags (int fdes)
397{
398 int flags = 0;
399 struct stat buf;
400 int error, optlen = sizeof (int);
401
402 /* Is this a socket ? */
403 if (getsockopt (fdes, SOL_SOCKET, SO_ERROR, (void *) &error, &optlen) >= 0)
404 flags = O_RDWR;
405 /* Maybe a regular file ? */
406 else if (fstat (fdes, &buf) < 0)
407 flags = -1;
408 else
409 {
410 /* Or an anonymous pipe handle ? */
b8b17bfd 411 if (buf.st_mode & _S_IFIFO)
8f99e3f3
SJ
412 flags = PeekNamedPipe ((HANDLE) _get_osfhandle (fdes), NULL, 0,
413 NULL, NULL, NULL) ? O_RDONLY : O_WRONLY;
82893676 414 /* stdin ? */
b8b17bfd 415 else if (fdes == fileno (stdin) && isatty (fdes))
82893676
MG
416 flags = O_RDONLY;
417 /* stdout / stderr ? */
b8b17bfd
MV
418 else if ((fdes == fileno (stdout) || fdes == fileno (stderr)) &&
419 isatty (fdes))
82893676
MG
420 flags = O_WRONLY;
421 else
422 flags = buf.st_mode;
423 }
424 return flags;
425}
426#endif /* __MINGW32__ */
427
cb63cf9e 428/* Building Guile ports from a file descriptor. */
e145dd02 429
cb63cf9e 430/* Build a Scheme port from an open file descriptor `fdes'.
a089567e
JB
431 MODE indicates whether FILE is open for reading or writing; it uses
432 the same notation as open-file's second argument.
19b27fa2
GH
433 NAME is a string to be used as the port's filename.
434*/
a089567e 435SCM
d617ee18 436scm_i_fdes_to_port (int fdes, long mode_bits, SCM name)
19b27fa2 437#define FUNC_NAME "scm_fdes_to_port"
a089567e 438{
a089567e 439 SCM port;
92c2555f 440 scm_t_port *pt;
19b27fa2
GH
441 int flags;
442
443 /* test that fdes is valid. */
82893676
MG
444#ifdef __MINGW32__
445 flags = getflags (fdes);
446#else
19b27fa2 447 flags = fcntl (fdes, F_GETFL, 0);
82893676 448#endif
19b27fa2
GH
449 if (flags == -1)
450 SCM_SYSERROR;
451 flags &= O_ACCMODE;
452 if (flags != O_RDWR
453 && ((flags != O_WRONLY && (mode_bits & SCM_WRTNG))
454 || (flags != O_RDONLY && (mode_bits & SCM_RDNG))))
455 {
456 SCM_MISC_ERROR ("requested file mode not available on fdes", SCM_EOL);
457 }
a089567e 458
9de87eea 459 scm_i_scm_pthread_mutex_lock (&scm_i_port_table_mutex);
da220f27
HWN
460
461 port = scm_new_port_table_entry (scm_tc16_fport);
462 SCM_SET_CELL_TYPE(port, scm_tc16_fport | mode_bits);
463 pt = SCM_PTAB_ENTRY(port);
a089567e 464 {
92c2555f 465 scm_t_fport *fp
4c9419ac 466 = (scm_t_fport *) scm_gc_malloc (sizeof (scm_t_fport), "file port");
c6c79933 467
cb63cf9e 468 fp->fdes = fdes;
0de97b83 469 pt->rw_random = SCM_FDES_RANDOM_P (fdes);
cb63cf9e
JB
470 SCM_SETSTREAM (port, fp);
471 if (mode_bits & SCM_BUF0)
472 scm_fport_buffer_add (port, 0, 0);
473 else
474 scm_fport_buffer_add (port, -1, -1);
a089567e 475 }
b24b5e13 476 SCM_SET_FILENAME (port, name);
9de87eea 477 scm_i_pthread_mutex_unlock (&scm_i_port_table_mutex);
e145dd02
JB
478 return port;
479}
19b27fa2 480#undef FUNC_NAME
e145dd02 481
d617ee18
MV
482SCM
483scm_fdes_to_port (int fdes, char *mode, SCM name)
484{
485 return scm_i_fdes_to_port (fdes, scm_mode_bits (mode), name);
486}
487
affc96b5 488/* Return a lower bound on the number of bytes available for input. */
cb63cf9e 489static int
affc96b5 490fport_input_waiting (SCM port)
e145dd02 491{
cb63cf9e 492#ifdef HAVE_SELECT
23f2b9a3 493 int fdes = SCM_FSTREAM (port)->fdes;
cb63cf9e
JB
494 struct timeval timeout;
495 SELECT_TYPE read_set;
496 SELECT_TYPE write_set;
497 SELECT_TYPE except_set;
498
499 FD_ZERO (&read_set);
500 FD_ZERO (&write_set);
501 FD_ZERO (&except_set);
502
503 FD_SET (fdes, &read_set);
504
505 timeout.tv_sec = 0;
506 timeout.tv_usec = 0;
507
508 if (select (SELECT_SET_SIZE,
509 &read_set, &write_set, &except_set, &timeout)
510 < 0)
affc96b5
GH
511 scm_syserror ("fport_input_waiting");
512 return FD_ISSET (fdes, &read_set) ? 1 : 0;
23f2b9a3
KR
513
514#elif HAVE_IOCTL && defined (FIONREAD)
515 /* Note: cannot test just defined(FIONREAD) here, since mingw has FIONREAD
516 (for use with winsock ioctlsocket()) but not ioctl(). */
517 int fdes = SCM_FSTREAM (port)->fdes;
cb63cf9e
JB
518 int remir;
519 ioctl(fdes, FIONREAD, &remir);
520 return remir;
23f2b9a3 521
cb63cf9e 522#else
affc96b5 523 scm_misc_error ("fport_input_waiting",
cb63cf9e
JB
524 "Not fully implemented on this platform",
525 SCM_EOL);
526#endif
a089567e
JB
527}
528
cb63cf9e 529\f
0f2d19dd 530static int
e81d98ec 531fport_print (SCM exp, SCM port, scm_print_state *pstate SCM_UNUSED)
0f2d19dd 532{
b3ec3c64
MD
533 scm_puts ("#<", port);
534 scm_print_port_mode (exp, port);
535 if (SCM_OPFPORTP (exp))
0f2d19dd 536 {
b3ec3c64 537 int fdes;
b24b5e13 538 SCM name = SCM_FILENAME (exp);
cc95e00a 539 if (scm_is_string (name) || scm_is_symbol (name))
b24b5e13
DH
540 scm_display (name, port);
541 else
542 scm_puts (SCM_PTOBNAME (SCM_PTOBNUM (exp)), port);
b3ec3c64
MD
543 scm_putc (' ', port);
544 fdes = (SCM_FSTREAM (exp))->fdes;
545
82893676 546#ifdef HAVE_TTYNAME
b3ec3c64 547 if (isatty (fdes))
eb372585 548 scm_display (scm_ttyname (exp), port);
b3ec3c64 549 else
82893676 550#endif /* HAVE_TTYNAME */
b3ec3c64 551 scm_intprint (fdes, 10, port);
0f2d19dd
JB
552 }
553 else
554 {
b3ec3c64
MD
555 scm_puts (SCM_PTOBNAME (SCM_PTOBNUM (exp)), port);
556 scm_putc (' ', port);
0345e278 557 scm_uintprint ((scm_t_bits) SCM_PTAB_ENTRY (exp), 16, port);
0f2d19dd 558 }
b3ec3c64
MD
559 scm_putc ('>', port);
560 return 1;
0f2d19dd
JB
561}
562
2e945bcc 563#ifndef __MINGW32__
cb63cf9e
JB
564/* thread-local block for input on fport's fdes. */
565static void
566fport_wait_for_input (SCM port)
3cb988bd 567{
cb63cf9e 568 int fdes = SCM_FSTREAM (port)->fdes;
3cb988bd 569
affc96b5 570 if (!fport_input_waiting (port))
8122b543 571 {
cb63cf9e
JB
572 int n;
573 SELECT_TYPE readfds;
574 int flags = fcntl (fdes, F_GETFL);
575
576 if (flags == -1)
577 scm_syserror ("scm_fdes_wait_for_input");
578 if (!(flags & O_NONBLOCK))
579 do
580 {
581 FD_ZERO (&readfds);
582 FD_SET (fdes, &readfds);
9de87eea 583 n = scm_std_select (fdes + 1, &readfds, NULL, NULL, NULL);
cb63cf9e
JB
584 }
585 while (n == -1 && errno == EINTR);
8122b543 586 }
3cb988bd 587}
2e945bcc 588#endif /* !__MINGW32__ */
0f2d19dd 589
affc96b5 590static void fport_flush (SCM port);
0f2d19dd 591
c2da2648
GH
592/* fill a port's read-buffer with a single read. returns the first
593 char or EOF if end of file. */
0f2d19dd 594static int
affc96b5 595fport_fill_input (SCM port)
0f2d19dd 596{
c014a02e 597 long count;
92c2555f
MV
598 scm_t_port *pt = SCM_PTAB_ENTRY (port);
599 scm_t_fport *fp = SCM_FSTREAM (port);
cb63cf9e 600
2e945bcc 601#ifndef __MINGW32__
cb63cf9e 602 fport_wait_for_input (port);
2e945bcc 603#endif /* !__MINGW32__ */
cb63cf9e
JB
604 SCM_SYSCALL (count = read (fp->fdes, pt->read_buf, pt->read_buf_size));
605 if (count == -1)
affc96b5 606 scm_syserror ("fport_fill_input");
cb63cf9e
JB
607 if (count == 0)
608 return EOF;
609 else
610 {
5c070ca7 611 pt->read_pos = pt->read_buf;
cb63cf9e 612 pt->read_end = pt->read_buf + count;
5c070ca7 613 return *pt->read_buf;
cb63cf9e 614 }
0f2d19dd
JB
615}
616
8ab3d8a0
KR
617static off_t_or_off64_t
618fport_seek_or_seek64 (SCM port, off_t_or_off64_t offset, int whence)
0f2d19dd 619{
92c2555f
MV
620 scm_t_port *pt = SCM_PTAB_ENTRY (port);
621 scm_t_fport *fp = SCM_FSTREAM (port);
8ab3d8a0
KR
622 off_t_or_off64_t rv;
623 off_t_or_off64_t result;
7dcb364d
GH
624
625 if (pt->rw_active == SCM_PORT_WRITE)
626 {
627 if (offset != 0 || whence != SEEK_CUR)
628 {
629 fport_flush (port);
8ab3d8a0 630 result = rv = lseek_or_lseek64 (fp->fdes, offset, whence);
7dcb364d
GH
631 }
632 else
633 {
634 /* read current position without disturbing the buffer. */
8ab3d8a0 635 rv = lseek_or_lseek64 (fp->fdes, offset, whence);
7dcb364d
GH
636 result = rv + (pt->write_pos - pt->write_buf);
637 }
638 }
639 else if (pt->rw_active == SCM_PORT_READ)
640 {
641 if (offset != 0 || whence != SEEK_CUR)
642 {
643 /* could expand to avoid a second seek. */
644 scm_end_input (port);
8ab3d8a0 645 result = rv = lseek_or_lseek64 (fp->fdes, offset, whence);
7dcb364d
GH
646 }
647 else
648 {
649 /* read current position without disturbing the buffer
650 (particularly the unread-char buffer). */
8ab3d8a0 651 rv = lseek_or_lseek64 (fp->fdes, offset, whence);
7dcb364d
GH
652 result = rv - (pt->read_end - pt->read_pos);
653
654 if (pt->read_buf == pt->putback_buf)
655 result -= pt->saved_read_end - pt->saved_read_pos;
656 }
657 }
658 else /* SCM_PORT_NEITHER */
659 {
8ab3d8a0 660 result = rv = lseek_or_lseek64 (fp->fdes, offset, whence);
7dcb364d 661 }
cb8dfa3f 662
7dcb364d 663 if (rv == -1)
affc96b5 664 scm_syserror ("fport_seek");
7dcb364d 665
cb8dfa3f 666 return result;
0f2d19dd
JB
667}
668
8ab3d8a0
KR
669/* If we've got largefile and off_t isn't already off64_t then
670 fport_seek_or_seek64 needs a range checking wrapper to be fport_seek in
671 the port descriptor.
672
673 Otherwise if no largefile, or off_t is the same as off64_t (which is the
674 case on NetBSD apparently), then fport_seek_or_seek64 is right to be
675 fport_seek already. */
676
677#if HAVE_STAT64 && SIZEOF_OFF_T != SIZEOF_OFF64_T
678static off_t
679fport_seek (SCM port, off_t offset, int whence)
680{
681 off64_t rv = fport_seek_or_seek64 (port, (off64_t) offset, whence);
682 if (rv > OFF_T_MAX || rv < OFF_T_MIN)
683 {
684 errno = EOVERFLOW;
685 scm_syserror ("fport_seek");
686 }
687 return (off_t) rv;
688
689}
690#else
691#define fport_seek fport_seek_or_seek64
692#endif
693
694/* `how' has been validated and is one of SEEK_SET, SEEK_CUR or SEEK_END */
695SCM
696scm_i_fport_seek (SCM port, SCM offset, int how)
697{
698 return scm_from_off_t_or_off64_t
699 (fport_seek_or_seek64 (port, scm_to_off_t_or_off64_t (offset), how));
700}
701
840ae05d 702static void
affc96b5 703fport_truncate (SCM port, off_t length)
840ae05d 704{
92c2555f 705 scm_t_fport *fp = SCM_FSTREAM (port);
840ae05d
JB
706
707 if (ftruncate (fp->fdes, length) == -1)
708 scm_syserror ("ftruncate");
709}
710
8ab3d8a0
KR
711int
712scm_i_fport_truncate (SCM port, SCM length)
713{
714 scm_t_fport *fp = SCM_FSTREAM (port);
715 return ftruncate_or_ftruncate64 (fp->fdes, scm_to_off_t_or_off64_t (length));
716}
717
0c6d2191
GH
718/* helper for fport_write: try to write data, using multiple system
719 calls if required. */
720#define FUNC_NAME "write_all"
721static void write_all (SCM port, const void *data, size_t remaining)
722{
723 int fdes = SCM_FSTREAM (port)->fdes;
724
725 while (remaining > 0)
726 {
82893676 727 size_t done;
0c6d2191
GH
728
729 SCM_SYSCALL (done = write (fdes, data, remaining));
730
731 if (done == -1)
732 SCM_SYSERROR;
733 remaining -= done;
734 data = ((const char *) data) + done;
735 }
736}
737#undef FUNC_NAME
738
31703ab8 739static void
8aa011a1 740fport_write (SCM port, const void *data, size_t size)
31703ab8 741{
0c6d2191 742 /* this procedure tries to minimize the number of writes/flushes. */
92c2555f 743 scm_t_port *pt = SCM_PTAB_ENTRY (port);
31703ab8 744
0c6d2191
GH
745 if (pt->write_buf == &pt->shortbuf
746 || (pt->write_pos == pt->write_buf && size >= pt->write_buf_size))
31703ab8 747 {
0c6d2191
GH
748 /* "unbuffered" port, or
749 port with empty buffer and data won't fit in buffer. */
750 write_all (port, data, size);
751 return;
31703ab8 752 }
d3639214 753
0c6d2191
GH
754 {
755 off_t space = pt->write_end - pt->write_pos;
756
757 if (size <= space)
758 {
759 /* data fits in buffer. */
760 memcpy (pt->write_pos, data, size);
761 pt->write_pos += size;
762 if (pt->write_pos == pt->write_end)
763 {
affc96b5 764 fport_flush (port);
0c6d2191
GH
765 /* we can skip the line-buffering check if nothing's buffered. */
766 return;
767 }
768 }
769 else
770 {
771 memcpy (pt->write_pos, data, space);
772 pt->write_pos = pt->write_end;
773 fport_flush (port);
774 {
775 const void *ptr = ((const char *) data) + space;
776 size_t remaining = size - space;
777
778 if (size >= pt->write_buf_size)
779 {
780 write_all (port, ptr, remaining);
781 return;
782 }
783 else
784 {
785 memcpy (pt->write_pos, ptr, remaining);
786 pt->write_pos += remaining;
787 }
31703ab8 788 }
0c6d2191 789 }
31703ab8 790
0c6d2191
GH
791 /* handle line buffering. */
792 if ((SCM_CELL_WORD_0 (port) & SCM_BUFLINE) && memchr (data, '\n', size))
793 fport_flush (port);
794 }
31703ab8
GH
795}
796
797/* becomes 1 when process is exiting: normal exception handling won't
798 work by this time. */
04a98cff 799extern int scm_i_terminating;
0f2d19dd 800
cb63cf9e 801static void
affc96b5 802fport_flush (SCM port)
0f2d19dd 803{
92c2555f
MV
804 scm_t_port *pt = SCM_PTAB_ENTRY (port);
805 scm_t_fport *fp = SCM_FSTREAM (port);
6f760c1d 806 unsigned char *ptr = pt->write_buf;
c014a02e
ML
807 long init_size = pt->write_pos - pt->write_buf;
808 long remaining = init_size;
0f2d19dd 809
cb63cf9e
JB
810 while (remaining > 0)
811 {
c014a02e 812 long count;
cb63cf9e
JB
813
814 SCM_SYSCALL (count = write (fp->fdes, ptr, remaining));
815 if (count < 0)
816 {
817 /* error. assume nothing was written this call, but
818 fix up the buffer for any previous successful writes. */
c014a02e 819 long done = init_size - remaining;
cb63cf9e
JB
820
821 if (done > 0)
822 {
823 int i;
824
825 for (i = 0; i < remaining; i++)
826 {
827 *(pt->write_buf + i) = *(pt->write_buf + done + i);
828 }
829 pt->write_pos = pt->write_buf + remaining;
830 }
04a98cff 831 if (scm_i_terminating)
cb63cf9e
JB
832 {
833 const char *msg = "Error: could not flush file-descriptor ";
834 char buf[11];
835
836 write (2, msg, strlen (msg));
837 sprintf (buf, "%d\n", fp->fdes);
838 write (2, buf, strlen (buf));
839
840 count = remaining;
841 }
6b72ac1d
GH
842 else if (scm_gc_running_p)
843 {
844 /* silently ignore the error. scm_error would abort if we
845 called it now. */
846 count = remaining;
847 }
848 else
849 scm_syserror ("fport_flush");
cb63cf9e
JB
850 }
851 ptr += count;
852 remaining -= count;
853 }
854 pt->write_pos = pt->write_buf;
61e452ba 855 pt->rw_active = SCM_PORT_NEITHER;
840ae05d
JB
856}
857
283a1a0e 858/* clear the read buffer and adjust the file position for unread bytes. */
840ae05d 859static void
affc96b5 860fport_end_input (SCM port, int offset)
840ae05d 861{
92c2555f
MV
862 scm_t_fport *fp = SCM_FSTREAM (port);
863 scm_t_port *pt = SCM_PTAB_ENTRY (port);
283a1a0e
GH
864
865 offset += pt->read_end - pt->read_pos;
840ae05d 866
840ae05d
JB
867 if (offset > 0)
868 {
869 pt->read_pos = pt->read_end;
870 /* will throw error if unread-char used at beginning of file
871 then attempting to write. seems correct. */
872 if (lseek (fp->fdes, -offset, SEEK_CUR) == -1)
affc96b5 873 scm_syserror ("fport_end_input");
840ae05d 874 }
61e452ba 875 pt->rw_active = SCM_PORT_NEITHER;
8f29fbd0
JB
876}
877
6a2c4c81 878static int
affc96b5 879fport_close (SCM port)
6a2c4c81 880{
92c2555f
MV
881 scm_t_fport *fp = SCM_FSTREAM (port);
882 scm_t_port *pt = SCM_PTAB_ENTRY (port);
cb63cf9e 883 int rv;
840ae05d 884
affc96b5 885 fport_flush (port);
cb63cf9e
JB
886 SCM_SYSCALL (rv = close (fp->fdes));
887 if (rv == -1 && errno != EBADF)
6b72ac1d
GH
888 {
889 if (scm_gc_running_p)
890 /* silently ignore the error. scm_error would abort if we
891 called it now. */
892 ;
893 else
894 scm_syserror ("fport_close");
895 }
6c951427
GH
896 if (pt->read_buf == pt->putback_buf)
897 pt->read_buf = pt->saved_read_buf;
cb63cf9e 898 if (pt->read_buf != &pt->shortbuf)
4c9419ac 899 scm_gc_free (pt->read_buf, pt->read_buf_size, "port buffer");
cb63cf9e 900 if (pt->write_buf != &pt->shortbuf)
4c9419ac
MV
901 scm_gc_free (pt->write_buf, pt->write_buf_size, "port buffer");
902 scm_gc_free (fp, sizeof (*fp), "file port");
cb63cf9e 903 return rv;
6a2c4c81
JB
904}
905
1be6b49c 906static size_t
affc96b5 907fport_free (SCM port)
b3ec3c64 908{
affc96b5 909 fport_close (port);
b3ec3c64
MD
910 return 0;
911}
912
92c2555f 913static scm_t_bits
b3ec3c64
MD
914scm_make_fptob ()
915{
92c2555f 916 scm_t_bits tc = scm_make_port_type ("file", fport_fill_input, fport_write);
a98bddfd 917
affc96b5 918 scm_set_port_free (tc, fport_free);
e841c3e0 919 scm_set_port_print (tc, fport_print);
affc96b5
GH
920 scm_set_port_flush (tc, fport_flush);
921 scm_set_port_end_input (tc, fport_end_input);
922 scm_set_port_close (tc, fport_close);
923 scm_set_port_seek (tc, fport_seek);
924 scm_set_port_truncate (tc, fport_truncate);
925 scm_set_port_input_waiting (tc, fport_input_waiting);
a98bddfd
DH
926
927 return tc;
b3ec3c64 928}
0f2d19dd 929
0f2d19dd
JB
930void
931scm_init_fports ()
0f2d19dd 932{
a98bddfd
DH
933 scm_tc16_fport = scm_make_fptob ();
934
e11e83f3
MV
935 scm_c_define ("_IOFBF", scm_from_int (_IOFBF));
936 scm_c_define ("_IOLBF", scm_from_int (_IOLBF));
937 scm_c_define ("_IONBF", scm_from_int (_IONBF));
a98bddfd 938
a98bddfd 939#include "libguile/fports.x"
0f2d19dd 940}
89e00824
ML
941
942/*
943 Local Variables:
944 c-file-style: "gnu"
945 End:
946*/