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