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