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