*** empty log message ***
[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
19b27fa2
GH
72/* default buffer size, used if the O/S won't supply a value. */
73static const int default_buffer_size = 1024;
74
cb63cf9e
JB
75/* create FPORT buffer with specified sizes (or -1 to use default size or
76 0 for no buffer. */
77static void
78scm_fport_buffer_add (SCM port, int read_size, int write_size)
e145dd02 79{
cb63cf9e 80 struct scm_fport *fp = SCM_FSTREAM (port);
b24b5e13 81 scm_port *pt = SCM_PTAB_ENTRY (port);
cb63cf9e 82 char *s_scm_fport_buffer_add = "scm_fport_buffer_add";
e145dd02 83
cb63cf9e
JB
84 if (read_size == -1 || write_size == -1)
85 {
86 int default_size;
87#ifdef HAVE_ST_BLKSIZE
88 struct stat st;
89
19b27fa2
GH
90 default_size = (fstat (fp->fdes, &st) == -1) ? default_buffer_size
91 : st.st_blksize;
cb63cf9e 92#else
19b27fa2 93 default_size = default_buffer_size;
cb63cf9e
JB
94#endif
95 if (read_size == -1)
96 read_size = default_size;
97 if (write_size == -1)
98 write_size = default_size;
99 }
0f2d19dd 100
f5f2dcff 101 if (SCM_INPUT_PORT_P (port) && read_size > 0)
cb63cf9e 102 {
840ae05d
JB
103 pt->read_buf = malloc (read_size);
104 if (pt->read_buf == NULL)
105 scm_memory_error (s_scm_fport_buffer_add);
cb63cf9e
JB
106 pt->read_pos = pt->read_end = pt->read_buf;
107 pt->read_buf_size = read_size;
108 }
109 else
110 {
840ae05d 111 pt->read_pos = pt->read_buf = pt->read_end = &pt->shortbuf;
cb63cf9e
JB
112 pt->read_buf_size = 1;
113 }
1717856b 114
f5f2dcff 115 if (SCM_OUTPUT_PORT_P (port) && write_size > 0)
cb63cf9e 116 {
840ae05d
JB
117 pt->write_buf = malloc (write_size);
118 if (pt->write_buf == NULL)
119 scm_memory_error (s_scm_fport_buffer_add);
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
GH
134}
135
a1ec6916 136SCM_DEFINE (scm_setvbuf, "setvbuf", 2, 1, 0,
1bbd0b84 137 (SCM port, SCM mode, SCM size),
fc0d72d4
MD
138 "Set the buffering mode for @var{port}. @var{mode} can be:\n"
139 "@table @code\n"
140 "@item _IONBF\n"
141 "non-buffered\n"
142 "@item _IOLBF\n"
143 "line buffered\n"
144 "@item _IOFBF\n"
145 "block buffered, using a newly allocated buffer of @var{size} bytes.\n"
146 "If @var{size} is omitted, a default size will be used.\n"
2c1ae20e 147 "@end table")
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 {
54778cd3 162 SCM_SET_CELL_WORD_0 (port, SCM_CELL_WORD_0 (port) | SCM_BUFLINE);
d3639214
GH
163 cmode = _IOFBF;
164 }
165 else
166 {
54778cd3 167 SCM_SET_CELL_WORD_0 (port, SCM_CELL_WORD_0 (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)
f30c9c8f 188 free (pt->read_buf);
cb63cf9e 189 if (pt->write_buf != &pt->shortbuf)
f30c9c8f 190 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
a6d9e5ab
DH
280 SCM_VALIDATE_STRING (1, filename);
281 SCM_VALIDATE_STRING (2, modes);
282 SCM_STRING_COERCE_0TERMINATION_X (filename);
283 SCM_STRING_COERCE_0TERMINATION_X (modes);
19639113 284
a6d9e5ab
DH
285 file = SCM_STRING_CHARS (filename);
286 mode = SCM_STRING_CHARS (modes);
19639113 287
cb63cf9e 288 switch (*mode)
0f2d19dd 289 {
cb63cf9e
JB
290 case 'r':
291 flags |= O_RDONLY;
292 break;
293 case 'w':
294 flags |= O_WRONLY | O_CREAT | O_TRUNC;
295 break;
296 case 'a':
297 flags |= O_WRONLY | O_CREAT | O_APPEND;
298 break;
299 default:
1bbd0b84 300 scm_out_of_range (FUNC_NAME, modes);
0f2d19dd 301 }
cb63cf9e
JB
302 ptr = mode + 1;
303 while (*ptr != '\0')
e145dd02 304 {
cb63cf9e
JB
305 switch (*ptr)
306 {
307 case '+':
308 flags = (flags & ~(O_RDONLY | O_WRONLY)) | O_RDWR;
309 break;
9f561420
GH
310 case 'b':
311#if defined (O_BINARY)
312 flags |= O_BINARY;
313#endif
314 break;
cb63cf9e 315 case '0': /* unbuffered: handled later. */
d3639214 316 case 'l': /* line buffered: handled during output. */
cb63cf9e
JB
317 break;
318 default:
1bbd0b84 319 scm_out_of_range (FUNC_NAME, modes);
cb63cf9e
JB
320 }
321 ptr++;
e145dd02 322 }
cb63cf9e
JB
323 SCM_SYSCALL (fdes = open (file, flags, 0666));
324 if (fdes == -1)
e145dd02 325 {
cb63cf9e
JB
326 int en = errno;
327
5d2d2ffc 328 SCM_SYSERROR_MSG ("~A: ~S",
cb63cf9e 329 scm_cons (scm_makfrom0str (strerror (en)),
5d2d2ffc 330 scm_cons (filename, SCM_EOL)), en);
0f2d19dd 331 }
cb63cf9e 332 port = scm_fdes_to_port (fdes, mode, filename);
0f2d19dd
JB
333 return port;
334}
1bbd0b84 335#undef FUNC_NAME
0f2d19dd 336
e145dd02 337\f
cb63cf9e 338/* Building Guile ports from a file descriptor. */
e145dd02 339
cb63cf9e 340/* Build a Scheme port from an open file descriptor `fdes'.
a089567e
JB
341 MODE indicates whether FILE is open for reading or writing; it uses
342 the same notation as open-file's second argument.
19b27fa2
GH
343 NAME is a string to be used as the port's filename.
344*/
a089567e 345SCM
cb63cf9e 346scm_fdes_to_port (int fdes, char *mode, SCM name)
19b27fa2 347#define FUNC_NAME "scm_fdes_to_port"
a089567e
JB
348{
349 long mode_bits = scm_mode_bits (mode);
350 SCM port;
840ae05d 351 scm_port *pt;
19b27fa2
GH
352 int flags;
353
354 /* test that fdes is valid. */
355 flags = fcntl (fdes, F_GETFL, 0);
356 if (flags == -1)
357 SCM_SYSERROR;
358 flags &= O_ACCMODE;
359 if (flags != O_RDWR
360 && ((flags != O_WRONLY && (mode_bits & SCM_WRTNG))
361 || (flags != O_RDONLY && (mode_bits & SCM_RDNG))))
362 {
363 SCM_MISC_ERROR ("requested file mode not available on fdes", SCM_EOL);
364 }
a089567e
JB
365
366 SCM_NEWCELL (port);
367 SCM_DEFER_INTS;
cb63cf9e
JB
368 pt = scm_add_to_port_table (port);
369 SCM_SETPTAB_ENTRY (port, pt);
54778cd3 370 SCM_SET_CELL_TYPE (port, (scm_tc16_fport | mode_bits));
cb63cf9e 371
a089567e 372 {
cb63cf9e 373 struct scm_fport *fp
840ae05d
JB
374 = (struct scm_fport *) malloc (sizeof (struct scm_fport));
375 if (fp == NULL)
19b27fa2 376 SCM_MEMORY_ERROR;
cb63cf9e 377 fp->fdes = fdes;
0de97b83 378 pt->rw_random = SCM_FDES_RANDOM_P (fdes);
cb63cf9e
JB
379 SCM_SETSTREAM (port, fp);
380 if (mode_bits & SCM_BUF0)
381 scm_fport_buffer_add (port, 0, 0);
382 else
383 scm_fport_buffer_add (port, -1, -1);
a089567e 384 }
b24b5e13 385 SCM_SET_FILENAME (port, name);
a089567e 386 SCM_ALLOW_INTS;
e145dd02
JB
387 return port;
388}
19b27fa2 389#undef FUNC_NAME
e145dd02 390
affc96b5 391/* Return a lower bound on the number of bytes available for input. */
cb63cf9e 392static int
affc96b5 393fport_input_waiting (SCM port)
e145dd02 394{
cb63cf9e
JB
395 int fdes = SCM_FSTREAM (port)->fdes;
396
397#ifdef HAVE_SELECT
398 struct timeval timeout;
399 SELECT_TYPE read_set;
400 SELECT_TYPE write_set;
401 SELECT_TYPE except_set;
402
403 FD_ZERO (&read_set);
404 FD_ZERO (&write_set);
405 FD_ZERO (&except_set);
406
407 FD_SET (fdes, &read_set);
408
409 timeout.tv_sec = 0;
410 timeout.tv_usec = 0;
411
412 if (select (SELECT_SET_SIZE,
413 &read_set, &write_set, &except_set, &timeout)
414 < 0)
affc96b5
GH
415 scm_syserror ("fport_input_waiting");
416 return FD_ISSET (fdes, &read_set) ? 1 : 0;
cb63cf9e
JB
417#elif defined (FIONREAD)
418 int remir;
419 ioctl(fdes, FIONREAD, &remir);
420 return remir;
421#else
affc96b5 422 scm_misc_error ("fport_input_waiting",
cb63cf9e
JB
423 "Not fully implemented on this platform",
424 SCM_EOL);
425#endif
a089567e
JB
426}
427
cb63cf9e 428\f
0f2d19dd 429static int
e841c3e0 430fport_print (SCM exp, SCM port, scm_print_state *pstate)
0f2d19dd 431{
b3ec3c64
MD
432 scm_puts ("#<", port);
433 scm_print_port_mode (exp, port);
434 if (SCM_OPFPORTP (exp))
0f2d19dd 435 {
b3ec3c64 436 int fdes;
b24b5e13
DH
437 SCM name = SCM_FILENAME (exp);
438 if (SCM_STRINGP (name) || SCM_SYMBOLP (name))
439 scm_display (name, port);
440 else
441 scm_puts (SCM_PTOBNAME (SCM_PTOBNUM (exp)), port);
b3ec3c64
MD
442 scm_putc (' ', port);
443 fdes = (SCM_FSTREAM (exp))->fdes;
444
445 if (isatty (fdes))
446 scm_puts (ttyname (fdes), port);
447 else
448 scm_intprint (fdes, 10, port);
0f2d19dd
JB
449 }
450 else
451 {
b3ec3c64
MD
452 scm_puts (SCM_PTOBNAME (SCM_PTOBNUM (exp)), port);
453 scm_putc (' ', port);
f1267706 454 scm_intprint (SCM_UNPACK (SCM_CDR (exp)), 16, port);
0f2d19dd 455 }
b3ec3c64
MD
456 scm_putc ('>', port);
457 return 1;
0f2d19dd
JB
458}
459
cb63cf9e
JB
460#ifdef GUILE_ISELECT
461/* thread-local block for input on fport's fdes. */
462static void
463fport_wait_for_input (SCM port)
3cb988bd 464{
cb63cf9e 465 int fdes = SCM_FSTREAM (port)->fdes;
3cb988bd 466
affc96b5 467 if (!fport_input_waiting (port))
8122b543 468 {
cb63cf9e
JB
469 int n;
470 SELECT_TYPE readfds;
471 int flags = fcntl (fdes, F_GETFL);
472
473 if (flags == -1)
474 scm_syserror ("scm_fdes_wait_for_input");
475 if (!(flags & O_NONBLOCK))
476 do
477 {
478 FD_ZERO (&readfds);
479 FD_SET (fdes, &readfds);
480 n = scm_internal_select (fdes + 1, &readfds, NULL, NULL, NULL);
481 }
482 while (n == -1 && errno == EINTR);
8122b543 483 }
3cb988bd 484}
0f2d19dd
JB
485#endif
486
affc96b5 487static void fport_flush (SCM port);
0f2d19dd 488
cb63cf9e
JB
489/* fill a port's read-buffer with a single read.
490 returns the first char and moves the read_pos pointer past it.
491 or returns EOF if end of file. */
0f2d19dd 492static int
affc96b5 493fport_fill_input (SCM port)
0f2d19dd 494{
cb63cf9e 495 int count;
840ae05d 496 scm_port *pt = SCM_PTAB_ENTRY (port);
cb63cf9e
JB
497 struct scm_fport *fp = SCM_FSTREAM (port);
498
cb63cf9e
JB
499#ifdef GUILE_ISELECT
500 fport_wait_for_input (port);
501#endif
502 SCM_SYSCALL (count = read (fp->fdes, pt->read_buf, pt->read_buf_size));
503 if (count == -1)
affc96b5 504 scm_syserror ("fport_fill_input");
cb63cf9e
JB
505 if (count == 0)
506 return EOF;
507 else
508 {
5c070ca7 509 pt->read_pos = pt->read_buf;
cb63cf9e 510 pt->read_end = pt->read_buf + count;
5c070ca7 511 return *pt->read_buf;
cb63cf9e 512 }
0f2d19dd
JB
513}
514
cb63cf9e 515static off_t
affc96b5 516fport_seek (SCM port, off_t offset, int whence)
0f2d19dd 517{
7dcb364d 518 scm_port *pt = SCM_PTAB_ENTRY (port);
cb63cf9e 519 struct scm_fport *fp = SCM_FSTREAM (port);
7dcb364d
GH
520 off_t rv;
521 off_t result;
522
523 if (pt->rw_active == SCM_PORT_WRITE)
524 {
525 if (offset != 0 || whence != SEEK_CUR)
526 {
527 fport_flush (port);
528 result = rv = lseek (fp->fdes, offset, whence);
529 }
530 else
531 {
532 /* read current position without disturbing the buffer. */
533 rv = lseek (fp->fdes, offset, whence);
534 result = rv + (pt->write_pos - pt->write_buf);
535 }
536 }
537 else if (pt->rw_active == SCM_PORT_READ)
538 {
539 if (offset != 0 || whence != SEEK_CUR)
540 {
541 /* could expand to avoid a second seek. */
542 scm_end_input (port);
543 result = rv = lseek (fp->fdes, offset, whence);
544 }
545 else
546 {
547 /* read current position without disturbing the buffer
548 (particularly the unread-char buffer). */
549 rv = lseek (fp->fdes, offset, whence);
550 result = rv - (pt->read_end - pt->read_pos);
551
552 if (pt->read_buf == pt->putback_buf)
553 result -= pt->saved_read_end - pt->saved_read_pos;
554 }
555 }
556 else /* SCM_PORT_NEITHER */
557 {
558 result = rv = lseek (fp->fdes, offset, whence);
559 }
cb8dfa3f 560
7dcb364d 561 if (rv == -1)
affc96b5 562 scm_syserror ("fport_seek");
7dcb364d 563
cb8dfa3f 564 return result;
0f2d19dd
JB
565}
566
840ae05d 567static void
affc96b5 568fport_truncate (SCM port, off_t length)
840ae05d
JB
569{
570 struct scm_fport *fp = SCM_FSTREAM (port);
571
572 if (ftruncate (fp->fdes, length) == -1)
573 scm_syserror ("ftruncate");
574}
575
0c6d2191
GH
576/* helper for fport_write: try to write data, using multiple system
577 calls if required. */
578#define FUNC_NAME "write_all"
579static void write_all (SCM port, const void *data, size_t remaining)
580{
581 int fdes = SCM_FSTREAM (port)->fdes;
582
583 while (remaining > 0)
584 {
585 ssize_t done;
586
587 SCM_SYSCALL (done = write (fdes, data, remaining));
588
589 if (done == -1)
590 SCM_SYSERROR;
591 remaining -= done;
592 data = ((const char *) data) + done;
593 }
594}
595#undef FUNC_NAME
596
31703ab8 597static void
8aa011a1 598fport_write (SCM port, const void *data, size_t size)
31703ab8 599{
0c6d2191 600 /* this procedure tries to minimize the number of writes/flushes. */
31703ab8
GH
601 scm_port *pt = SCM_PTAB_ENTRY (port);
602
0c6d2191
GH
603 if (pt->write_buf == &pt->shortbuf
604 || (pt->write_pos == pt->write_buf && size >= pt->write_buf_size))
31703ab8 605 {
0c6d2191
GH
606 /* "unbuffered" port, or
607 port with empty buffer and data won't fit in buffer. */
608 write_all (port, data, size);
609 return;
31703ab8 610 }
d3639214 611
0c6d2191
GH
612 {
613 off_t space = pt->write_end - pt->write_pos;
614
615 if (size <= space)
616 {
617 /* data fits in buffer. */
618 memcpy (pt->write_pos, data, size);
619 pt->write_pos += size;
620 if (pt->write_pos == pt->write_end)
621 {
affc96b5 622 fport_flush (port);
0c6d2191
GH
623 /* we can skip the line-buffering check if nothing's buffered. */
624 return;
625 }
626 }
627 else
628 {
629 memcpy (pt->write_pos, data, space);
630 pt->write_pos = pt->write_end;
631 fport_flush (port);
632 {
633 const void *ptr = ((const char *) data) + space;
634 size_t remaining = size - space;
635
636 if (size >= pt->write_buf_size)
637 {
638 write_all (port, ptr, remaining);
639 return;
640 }
641 else
642 {
643 memcpy (pt->write_pos, ptr, remaining);
644 pt->write_pos += remaining;
645 }
31703ab8 646 }
0c6d2191 647 }
31703ab8 648
0c6d2191
GH
649 /* handle line buffering. */
650 if ((SCM_CELL_WORD_0 (port) & SCM_BUFLINE) && memchr (data, '\n', size))
651 fport_flush (port);
652 }
31703ab8
GH
653}
654
655/* becomes 1 when process is exiting: normal exception handling won't
656 work by this time. */
cb63cf9e 657extern int terminating;
0f2d19dd 658
cb63cf9e 659static void
affc96b5 660fport_flush (SCM port)
0f2d19dd 661{
840ae05d 662 scm_port *pt = SCM_PTAB_ENTRY (port);
cb63cf9e 663 struct scm_fport *fp = SCM_FSTREAM (port);
6f760c1d 664 unsigned char *ptr = pt->write_buf;
cb63cf9e
JB
665 int init_size = pt->write_pos - pt->write_buf;
666 int remaining = init_size;
0f2d19dd 667
cb63cf9e
JB
668 while (remaining > 0)
669 {
670 int count;
671
672 SCM_SYSCALL (count = write (fp->fdes, ptr, remaining));
673 if (count < 0)
674 {
675 /* error. assume nothing was written this call, but
676 fix up the buffer for any previous successful writes. */
677 int done = init_size - remaining;
678
679 if (done > 0)
680 {
681 int i;
682
683 for (i = 0; i < remaining; i++)
684 {
685 *(pt->write_buf + i) = *(pt->write_buf + done + i);
686 }
687 pt->write_pos = pt->write_buf + remaining;
688 }
6b72ac1d 689 if (terminating)
cb63cf9e
JB
690 {
691 const char *msg = "Error: could not flush file-descriptor ";
692 char buf[11];
693
694 write (2, msg, strlen (msg));
695 sprintf (buf, "%d\n", fp->fdes);
696 write (2, buf, strlen (buf));
697
698 count = remaining;
699 }
6b72ac1d
GH
700 else if (scm_gc_running_p)
701 {
702 /* silently ignore the error. scm_error would abort if we
703 called it now. */
704 count = remaining;
705 }
706 else
707 scm_syserror ("fport_flush");
cb63cf9e
JB
708 }
709 ptr += count;
710 remaining -= count;
711 }
712 pt->write_pos = pt->write_buf;
61e452ba 713 pt->rw_active = SCM_PORT_NEITHER;
840ae05d
JB
714}
715
283a1a0e 716/* clear the read buffer and adjust the file position for unread bytes. */
840ae05d 717static void
affc96b5 718fport_end_input (SCM port, int offset)
840ae05d
JB
719{
720 struct scm_fport *fp = SCM_FSTREAM (port);
721 scm_port *pt = SCM_PTAB_ENTRY (port);
283a1a0e
GH
722
723 offset += pt->read_end - pt->read_pos;
840ae05d 724
840ae05d
JB
725 if (offset > 0)
726 {
727 pt->read_pos = pt->read_end;
728 /* will throw error if unread-char used at beginning of file
729 then attempting to write. seems correct. */
730 if (lseek (fp->fdes, -offset, SEEK_CUR) == -1)
affc96b5 731 scm_syserror ("fport_end_input");
840ae05d 732 }
61e452ba 733 pt->rw_active = SCM_PORT_NEITHER;
8f29fbd0
JB
734}
735
6a2c4c81 736static int
affc96b5 737fport_close (SCM port)
6a2c4c81 738{
cb63cf9e 739 struct scm_fport *fp = SCM_FSTREAM (port);
840ae05d 740 scm_port *pt = SCM_PTAB_ENTRY (port);
cb63cf9e 741 int rv;
840ae05d 742
affc96b5 743 fport_flush (port);
cb63cf9e
JB
744 SCM_SYSCALL (rv = close (fp->fdes));
745 if (rv == -1 && errno != EBADF)
6b72ac1d
GH
746 {
747 if (scm_gc_running_p)
748 /* silently ignore the error. scm_error would abort if we
749 called it now. */
750 ;
751 else
752 scm_syserror ("fport_close");
753 }
6c951427
GH
754 if (pt->read_buf == pt->putback_buf)
755 pt->read_buf = pt->saved_read_buf;
cb63cf9e 756 if (pt->read_buf != &pt->shortbuf)
840ae05d 757 free (pt->read_buf);
cb63cf9e 758 if (pt->write_buf != &pt->shortbuf)
840ae05d
JB
759 free (pt->write_buf);
760 free ((char *) fp);
cb63cf9e 761 return rv;
6a2c4c81
JB
762}
763
b3ec3c64 764static scm_sizet
affc96b5 765fport_free (SCM port)
b3ec3c64 766{
affc96b5 767 fport_close (port);
b3ec3c64
MD
768 return 0;
769}
770
771void scm_make_fptob (void); /* Called from ports.c */
772
773void
774scm_make_fptob ()
775{
affc96b5
GH
776 long tc = scm_make_port_type ("file", fport_fill_input, fport_write);
777 scm_set_port_free (tc, fport_free);
e841c3e0 778 scm_set_port_print (tc, fport_print);
affc96b5
GH
779 scm_set_port_flush (tc, fport_flush);
780 scm_set_port_end_input (tc, fport_end_input);
781 scm_set_port_close (tc, fport_close);
782 scm_set_port_seek (tc, fport_seek);
783 scm_set_port_truncate (tc, fport_truncate);
784 scm_set_port_input_waiting (tc, fport_input_waiting);
b3ec3c64 785}
0f2d19dd 786
0f2d19dd
JB
787void
788scm_init_fports ()
0f2d19dd 789{
8dc9439f 790#ifndef SCM_MAGIC_SNARFER
a0599745 791#include "libguile/fports.x"
8dc9439f 792#endif
7a6f1ffa
GH
793 scm_sysintern ("_IOFBF", SCM_MAKINUM (_IOFBF));
794 scm_sysintern ("_IOLBF", SCM_MAKINUM (_IOLBF));
795 scm_sysintern ("_IONBF", SCM_MAKINUM (_IONBF));
0f2d19dd 796}
89e00824
ML
797
798/*
799 Local Variables:
800 c-file-style: "gnu"
801 End:
802*/