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