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