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