* Fix handling of (set-source-property! <obj> 'copy <datum>).
[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
c2da2648
GH
489/* fill a port's read-buffer with a single read. returns the first
490 char or EOF if end of file. */
0f2d19dd 491static int
affc96b5 492fport_fill_input (SCM port)
0f2d19dd 493{
cb63cf9e 494 int count;
840ae05d 495 scm_port *pt = SCM_PTAB_ENTRY (port);
cb63cf9e
JB
496 struct scm_fport *fp = SCM_FSTREAM (port);
497
cb63cf9e
JB
498#ifdef GUILE_ISELECT
499 fport_wait_for_input (port);
500#endif
501 SCM_SYSCALL (count = read (fp->fdes, pt->read_buf, pt->read_buf_size));
502 if (count == -1)
affc96b5 503 scm_syserror ("fport_fill_input");
cb63cf9e
JB
504 if (count == 0)
505 return EOF;
506 else
507 {
5c070ca7 508 pt->read_pos = pt->read_buf;
cb63cf9e 509 pt->read_end = pt->read_buf + count;
5c070ca7 510 return *pt->read_buf;
cb63cf9e 511 }
0f2d19dd
JB
512}
513
cb63cf9e 514static off_t
affc96b5 515fport_seek (SCM port, off_t offset, int whence)
0f2d19dd 516{
7dcb364d 517 scm_port *pt = SCM_PTAB_ENTRY (port);
cb63cf9e 518 struct scm_fport *fp = SCM_FSTREAM (port);
7dcb364d
GH
519 off_t rv;
520 off_t result;
521
522 if (pt->rw_active == SCM_PORT_WRITE)
523 {
524 if (offset != 0 || whence != SEEK_CUR)
525 {
526 fport_flush (port);
527 result = rv = lseek (fp->fdes, offset, whence);
528 }
529 else
530 {
531 /* read current position without disturbing the buffer. */
532 rv = lseek (fp->fdes, offset, whence);
533 result = rv + (pt->write_pos - pt->write_buf);
534 }
535 }
536 else if (pt->rw_active == SCM_PORT_READ)
537 {
538 if (offset != 0 || whence != SEEK_CUR)
539 {
540 /* could expand to avoid a second seek. */
541 scm_end_input (port);
542 result = rv = lseek (fp->fdes, offset, whence);
543 }
544 else
545 {
546 /* read current position without disturbing the buffer
547 (particularly the unread-char buffer). */
548 rv = lseek (fp->fdes, offset, whence);
549 result = rv - (pt->read_end - pt->read_pos);
550
551 if (pt->read_buf == pt->putback_buf)
552 result -= pt->saved_read_end - pt->saved_read_pos;
553 }
554 }
555 else /* SCM_PORT_NEITHER */
556 {
557 result = rv = lseek (fp->fdes, offset, whence);
558 }
cb8dfa3f 559
7dcb364d 560 if (rv == -1)
affc96b5 561 scm_syserror ("fport_seek");
7dcb364d 562
cb8dfa3f 563 return result;
0f2d19dd
JB
564}
565
840ae05d 566static void
affc96b5 567fport_truncate (SCM port, off_t length)
840ae05d
JB
568{
569 struct scm_fport *fp = SCM_FSTREAM (port);
570
571 if (ftruncate (fp->fdes, length) == -1)
572 scm_syserror ("ftruncate");
573}
574
0c6d2191
GH
575/* helper for fport_write: try to write data, using multiple system
576 calls if required. */
577#define FUNC_NAME "write_all"
578static void write_all (SCM port, const void *data, size_t remaining)
579{
580 int fdes = SCM_FSTREAM (port)->fdes;
581
582 while (remaining > 0)
583 {
584 ssize_t done;
585
586 SCM_SYSCALL (done = write (fdes, data, remaining));
587
588 if (done == -1)
589 SCM_SYSERROR;
590 remaining -= done;
591 data = ((const char *) data) + done;
592 }
593}
594#undef FUNC_NAME
595
31703ab8 596static void
8aa011a1 597fport_write (SCM port, const void *data, size_t size)
31703ab8 598{
0c6d2191 599 /* this procedure tries to minimize the number of writes/flushes. */
31703ab8
GH
600 scm_port *pt = SCM_PTAB_ENTRY (port);
601
0c6d2191
GH
602 if (pt->write_buf == &pt->shortbuf
603 || (pt->write_pos == pt->write_buf && size >= pt->write_buf_size))
31703ab8 604 {
0c6d2191
GH
605 /* "unbuffered" port, or
606 port with empty buffer and data won't fit in buffer. */
607 write_all (port, data, size);
608 return;
31703ab8 609 }
d3639214 610
0c6d2191
GH
611 {
612 off_t space = pt->write_end - pt->write_pos;
613
614 if (size <= space)
615 {
616 /* data fits in buffer. */
617 memcpy (pt->write_pos, data, size);
618 pt->write_pos += size;
619 if (pt->write_pos == pt->write_end)
620 {
affc96b5 621 fport_flush (port);
0c6d2191
GH
622 /* we can skip the line-buffering check if nothing's buffered. */
623 return;
624 }
625 }
626 else
627 {
628 memcpy (pt->write_pos, data, space);
629 pt->write_pos = pt->write_end;
630 fport_flush (port);
631 {
632 const void *ptr = ((const char *) data) + space;
633 size_t remaining = size - space;
634
635 if (size >= pt->write_buf_size)
636 {
637 write_all (port, ptr, remaining);
638 return;
639 }
640 else
641 {
642 memcpy (pt->write_pos, ptr, remaining);
643 pt->write_pos += remaining;
644 }
31703ab8 645 }
0c6d2191 646 }
31703ab8 647
0c6d2191
GH
648 /* handle line buffering. */
649 if ((SCM_CELL_WORD_0 (port) & SCM_BUFLINE) && memchr (data, '\n', size))
650 fport_flush (port);
651 }
31703ab8
GH
652}
653
654/* becomes 1 when process is exiting: normal exception handling won't
655 work by this time. */
cb63cf9e 656extern int terminating;
0f2d19dd 657
cb63cf9e 658static void
affc96b5 659fport_flush (SCM port)
0f2d19dd 660{
840ae05d 661 scm_port *pt = SCM_PTAB_ENTRY (port);
cb63cf9e 662 struct scm_fport *fp = SCM_FSTREAM (port);
6f760c1d 663 unsigned char *ptr = pt->write_buf;
cb63cf9e
JB
664 int init_size = pt->write_pos - pt->write_buf;
665 int remaining = init_size;
0f2d19dd 666
cb63cf9e
JB
667 while (remaining > 0)
668 {
669 int count;
670
671 SCM_SYSCALL (count = write (fp->fdes, ptr, remaining));
672 if (count < 0)
673 {
674 /* error. assume nothing was written this call, but
675 fix up the buffer for any previous successful writes. */
676 int done = init_size - remaining;
677
678 if (done > 0)
679 {
680 int i;
681
682 for (i = 0; i < remaining; i++)
683 {
684 *(pt->write_buf + i) = *(pt->write_buf + done + i);
685 }
686 pt->write_pos = pt->write_buf + remaining;
687 }
6b72ac1d 688 if (terminating)
cb63cf9e
JB
689 {
690 const char *msg = "Error: could not flush file-descriptor ";
691 char buf[11];
692
693 write (2, msg, strlen (msg));
694 sprintf (buf, "%d\n", fp->fdes);
695 write (2, buf, strlen (buf));
696
697 count = remaining;
698 }
6b72ac1d
GH
699 else if (scm_gc_running_p)
700 {
701 /* silently ignore the error. scm_error would abort if we
702 called it now. */
703 count = remaining;
704 }
705 else
706 scm_syserror ("fport_flush");
cb63cf9e
JB
707 }
708 ptr += count;
709 remaining -= count;
710 }
711 pt->write_pos = pt->write_buf;
61e452ba 712 pt->rw_active = SCM_PORT_NEITHER;
840ae05d
JB
713}
714
283a1a0e 715/* clear the read buffer and adjust the file position for unread bytes. */
840ae05d 716static void
affc96b5 717fport_end_input (SCM port, int offset)
840ae05d
JB
718{
719 struct scm_fport *fp = SCM_FSTREAM (port);
720 scm_port *pt = SCM_PTAB_ENTRY (port);
283a1a0e
GH
721
722 offset += pt->read_end - pt->read_pos;
840ae05d 723
840ae05d
JB
724 if (offset > 0)
725 {
726 pt->read_pos = pt->read_end;
727 /* will throw error if unread-char used at beginning of file
728 then attempting to write. seems correct. */
729 if (lseek (fp->fdes, -offset, SEEK_CUR) == -1)
affc96b5 730 scm_syserror ("fport_end_input");
840ae05d 731 }
61e452ba 732 pt->rw_active = SCM_PORT_NEITHER;
8f29fbd0
JB
733}
734
6a2c4c81 735static int
affc96b5 736fport_close (SCM port)
6a2c4c81 737{
cb63cf9e 738 struct scm_fport *fp = SCM_FSTREAM (port);
840ae05d 739 scm_port *pt = SCM_PTAB_ENTRY (port);
cb63cf9e 740 int rv;
840ae05d 741
affc96b5 742 fport_flush (port);
cb63cf9e
JB
743 SCM_SYSCALL (rv = close (fp->fdes));
744 if (rv == -1 && errno != EBADF)
6b72ac1d
GH
745 {
746 if (scm_gc_running_p)
747 /* silently ignore the error. scm_error would abort if we
748 called it now. */
749 ;
750 else
751 scm_syserror ("fport_close");
752 }
6c951427
GH
753 if (pt->read_buf == pt->putback_buf)
754 pt->read_buf = pt->saved_read_buf;
cb63cf9e 755 if (pt->read_buf != &pt->shortbuf)
840ae05d 756 free (pt->read_buf);
cb63cf9e 757 if (pt->write_buf != &pt->shortbuf)
840ae05d
JB
758 free (pt->write_buf);
759 free ((char *) fp);
cb63cf9e 760 return rv;
6a2c4c81
JB
761}
762
b3ec3c64 763static scm_sizet
affc96b5 764fport_free (SCM port)
b3ec3c64 765{
affc96b5 766 fport_close (port);
b3ec3c64
MD
767 return 0;
768}
769
770void scm_make_fptob (void); /* Called from ports.c */
771
772void
773scm_make_fptob ()
774{
affc96b5
GH
775 long tc = scm_make_port_type ("file", fport_fill_input, fport_write);
776 scm_set_port_free (tc, fport_free);
e841c3e0 777 scm_set_port_print (tc, fport_print);
affc96b5
GH
778 scm_set_port_flush (tc, fport_flush);
779 scm_set_port_end_input (tc, fport_end_input);
780 scm_set_port_close (tc, fport_close);
781 scm_set_port_seek (tc, fport_seek);
782 scm_set_port_truncate (tc, fport_truncate);
783 scm_set_port_input_waiting (tc, fport_input_waiting);
b3ec3c64 784}
0f2d19dd 785
0f2d19dd
JB
786void
787scm_init_fports ()
0f2d19dd 788{
8dc9439f 789#ifndef SCM_MAGIC_SNARFER
a0599745 790#include "libguile/fports.x"
8dc9439f 791#endif
7a6f1ffa
GH
792 scm_sysintern ("_IOFBF", SCM_MAKINUM (_IOFBF));
793 scm_sysintern ("_IOLBF", SCM_MAKINUM (_IOLBF));
794 scm_sysintern ("_IONBF", SCM_MAKINUM (_IONBF));
0f2d19dd 795}
89e00824
ML
796
797/*
798 Local Variables:
799 c-file-style: "gnu"
800 End:
801*/