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