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