1 /* Copyright (C) 1995,1996,1997,1998,1999 Free Software Foundation, Inc.
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)
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.
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
15 * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
16 * Boston, MA 02111-1307 USA
18 * As a special exception, the Free Software Foundation gives permission
19 * for additional uses of the text contained in its release of GUILE.
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.
27 * This exception does not however invalidate any other reasons why
28 * the executable file might be covered by the GNU General Public License.
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.
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.
40 * If you do not wish that, delete this exception notice. */
42 /* Software engineering face-lift by Greg J. Badros, 11-Dec-1999,
43 gjb@cs.washington.edu, http://www.cs.washington.edu/homes/gjb */
51 #include "scm_validate.h"
62 #ifdef HAVE_ST_BLKSIZE
70 /* create FPORT buffer with specified sizes (or -1 to use default size or
73 scm_fport_buffer_add (SCM port
, int read_size
, int write_size
)
75 struct scm_fport
*fp
= SCM_FSTREAM (port
);
76 scm_port
*pt
= SCM_PTAB_ENTRY (port
);
77 char *s_scm_fport_buffer_add
= "scm_fport_buffer_add";
79 if (read_size
== -1 || write_size
== -1)
82 #ifdef HAVE_ST_BLKSIZE
85 if (fstat (fp
->fdes
, &st
) == -1)
86 scm_syserror (s_scm_fport_buffer_add
);
87 default_size
= st
.st_blksize
;
92 read_size
= default_size
;
94 write_size
= default_size
;
97 if (SCM_INPORTP (port
) && read_size
> 0)
99 pt
->read_buf
= malloc (read_size
);
100 if (pt
->read_buf
== NULL
)
101 scm_memory_error (s_scm_fport_buffer_add
);
102 pt
->read_pos
= pt
->read_end
= pt
->read_buf
;
103 pt
->read_buf_size
= read_size
;
107 pt
->read_pos
= pt
->read_buf
= pt
->read_end
= &pt
->shortbuf
;
108 pt
->read_buf_size
= 1;
111 if (SCM_OUTPORTP (port
) && write_size
> 0)
113 pt
->write_buf
= malloc (write_size
);
114 if (pt
->write_buf
== NULL
)
115 scm_memory_error (s_scm_fport_buffer_add
);
116 pt
->write_pos
= pt
->write_buf
;
117 pt
->write_buf_size
= write_size
;
121 pt
->write_buf
= pt
->write_pos
= &pt
->shortbuf
;
122 pt
->write_buf_size
= 1;
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
);
129 SCM_SETCAR (port
, (SCM_CAR (port
) | SCM_BUF0
));
132 SCM_DEFINE (scm_setvbuf
, "setvbuf", 2, 1, 0,
133 (SCM port
, SCM mode
, SCM size
),
134 "Set the buffering mode for @var{port}. @var{mode} can be:
141 block buffered, using a newly allocated buffer of @var{size} bytes.
142 If @var{size} is omitted, a default size will be used.
146 @deffn primitive fcntl fd/port command [value]
147 Apply @var{command} to the specified file descriptor or the underlying
148 file descriptor of the specified port. @var{value} is an optional
151 Values for @var{command} are:
155 Duplicate a file descriptor
157 Get flags associated with the file descriptor.
159 Set flags associated with the file descriptor to @var{value}.
161 Get flags associated with the open file.
163 Set flags associated with the open file to @var{value}
165 Get the process ID of a socket's owner, for @code{SIGIO} signals.
167 Set the process that owns a socket to @var{value}, for @code{SIGIO} signals.
169 The value used to indicate the "close on exec
" flag with @code{F_GETFL} or
173 #define FUNC_NAME s_scm_setvbuf
178 port
= SCM_COERCE_OUTPORT (port
);
180 SCM_VALIDATE_OPFPORT (1,port
);
181 SCM_VALIDATE_INUM_COPY (2,mode
,cmode
);
182 if (cmode
!= _IONBF
&& cmode
!= _IOFBF
&& cmode
!= _IOLBF
)
183 scm_out_of_range (FUNC_NAME
, mode
);
187 SCM_SETCAR (port
, SCM_CAR (port
) | SCM_BUFLINE
);
192 SCM_SETCAR (port
, SCM_CAR (port
) ^ SCM_BUFLINE
);
195 if (SCM_UNBNDP (size
))
204 SCM_VALIDATE_INUM_COPY (3,size
,csize
);
205 if (csize
< 0 || (cmode
== _IONBF
&& csize
> 0))
206 scm_out_of_range (FUNC_NAME
, size
);
209 pt
= SCM_PTAB_ENTRY (port
);
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
);
217 scm_fport_buffer_add (port
, csize
, csize
);
218 return SCM_UNSPECIFIED
;
222 /* Move ports with the specified file descriptor to new descriptors,
223 * reseting the revealed count to 0.
227 scm_evict_ports (int fd
)
231 for (i
= 0; i
< scm_port_table_size
; i
++)
233 SCM port
= scm_port_table
[i
]->port
;
235 if (SCM_FPORTP (port
))
237 struct scm_fport
*fp
= SCM_FSTREAM (port
);
243 scm_syserror ("scm_evict_ports");
244 scm_set_port_revealed_x (port
, SCM_MAKINUM (0));
251 * Return a new port open on a given file.
253 * The mode string must match the pattern: [rwa+]** which
254 * is interpreted in the usual unix way.
256 * Return the new port.
258 SCM_DEFINE (scm_open_file
, "open-file", 2, 0, 0,
259 (SCM filename
, SCM modes
),
260 "Open the file whose name is @var{string}, and return a port
261 representing that file. The attributes of the port are
262 determined by the @var{mode} string. The way in
263 which this is interpreted is similar to C stdio:
265 The first character must be one of the following:
269 Open an existing file for input.
271 Open a file for output, creating it if it doesn't already exist
272 or removing its contents if it does.
274 Open a file for output, creating it if it doesn't already exist.
275 All writes to the port will go to the end of the file.
276 The "append mode
" can be turned off while the port is in use
277 @pxref{Ports and File Descriptors, fcntl}
280 The following additional characters can be appended:
284 Open the port for both input and output. E.g., @code{r+}: open
285 an existing file for both input and output.
287 Create an "unbuffered
" port. In this case input and output operations
288 are passed directly to the underlying port implementation without
289 additional buffering. This is likely to slow down I/O operations.
290 The buffering mode can be changed while a port is in use
291 @pxref{Ports and File Descriptors, setvbuf}
293 Add line-buffering to the port. The port output buffer will be
294 automatically flushed whenever a newline character is written.
297 In theory we could create read/write ports which were buffered in one
298 direction only. However this isn't included in the current interfaces.
300 If a file cannot be opened with the access requested,
301 @code{open-file} throws an exception.")
302 #define FUNC_NAME s_scm_open_file
311 SCM_VALIDATE_ROSTRING (1,filename
);
312 SCM_VALIDATE_ROSTRING (2,modes
);
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);
318 file
= SCM_ROCHARS (filename
);
319 mode
= SCM_ROCHARS (modes
);
327 flags
|= O_WRONLY
| O_CREAT
| O_TRUNC
;
330 flags
|= O_WRONLY
| O_CREAT
| O_APPEND
;
333 scm_out_of_range (FUNC_NAME
, modes
);
341 flags
= (flags
& ~(O_RDONLY
| O_WRONLY
)) | O_RDWR
;
343 case '0': /* unbuffered: handled later. */
344 case 'b': /* 'binary' mode: ignored. */
345 case 'l': /* line buffered: handled during output. */
348 scm_out_of_range (FUNC_NAME
, modes
);
352 SCM_SYSCALL (fdes
= open (file
, flags
, 0666));
357 scm_syserror_msg (FUNC_NAME
, "%s: %S",
358 scm_cons (scm_makfrom0str (strerror (en
)),
359 scm_cons (filename
, SCM_EOL
)),
362 port
= scm_fdes_to_port (fdes
, mode
, filename
);
368 /* Building Guile ports from a file descriptor. */
370 /* Build a Scheme port from an open file descriptor `fdes'.
371 MODE indicates whether FILE is open for reading or writing; it uses
372 the same notation as open-file's second argument.
373 Use NAME as the port's filename. */
376 scm_fdes_to_port (int fdes
, char *mode
, SCM name
)
378 long mode_bits
= scm_mode_bits (mode
);
384 pt
= scm_add_to_port_table (port
);
385 SCM_SETPTAB_ENTRY (port
, pt
);
386 SCM_SETCAR (port
, (scm_tc16_fport
| mode_bits
));
390 = (struct scm_fport
*) malloc (sizeof (struct scm_fport
));
392 scm_memory_error ("scm_fdes_to_port");
394 pt
->rw_random
= SCM_FDES_RANDOM_P (fdes
);
395 SCM_SETSTREAM (port
, fp
);
396 if (mode_bits
& SCM_BUF0
)
397 scm_fport_buffer_add (port
, 0, 0);
399 scm_fport_buffer_add (port
, -1, -1);
401 SCM_PTAB_ENTRY (port
)->file_name
= name
;
407 /* Return a lower bound on the number of bytes available for input. */
409 fport_input_waiting (SCM port
)
411 int fdes
= SCM_FSTREAM (port
)->fdes
;
414 struct timeval timeout
;
415 SELECT_TYPE read_set
;
416 SELECT_TYPE write_set
;
417 SELECT_TYPE except_set
;
420 FD_ZERO (&write_set
);
421 FD_ZERO (&except_set
);
423 FD_SET (fdes
, &read_set
);
428 if (select (SELECT_SET_SIZE
,
429 &read_set
, &write_set
, &except_set
, &timeout
)
431 scm_syserror ("fport_input_waiting");
432 return FD_ISSET (fdes
, &read_set
) ? 1 : 0;
433 #elif defined (FIONREAD)
435 ioctl(fdes
, FIONREAD
, &remir
);
438 scm_misc_error ("fport_input_waiting",
439 "Not fully implemented on this platform",
446 prinfport (SCM exp
,SCM port
,scm_print_state
*pstate
)
448 scm_puts ("#<", port
);
449 scm_print_port_mode (exp
, port
);
450 if (SCM_OPFPORTP (exp
))
453 SCM name
= SCM_PTAB_ENTRY (exp
)->file_name
;
454 scm_puts (SCM_ROSTRINGP (name
)
456 : SCM_PTOBNAME (SCM_PTOBNUM (exp
)),
458 scm_putc (' ', port
);
459 fdes
= (SCM_FSTREAM (exp
))->fdes
;
462 scm_puts (ttyname (fdes
), port
);
464 scm_intprint (fdes
, 10, port
);
468 scm_puts (SCM_PTOBNAME (SCM_PTOBNUM (exp
)), port
);
469 scm_putc (' ', port
);
470 scm_intprint (SCM_CDR (exp
), 16, port
);
472 scm_putc ('>', port
);
477 /* thread-local block for input on fport's fdes. */
479 fport_wait_for_input (SCM port
)
481 int fdes
= SCM_FSTREAM (port
)->fdes
;
483 if (!fport_input_waiting (port
))
487 int flags
= fcntl (fdes
, F_GETFL
);
490 scm_syserror ("scm_fdes_wait_for_input");
491 if (!(flags
& O_NONBLOCK
))
495 FD_SET (fdes
, &readfds
);
496 n
= scm_internal_select (fdes
+ 1, &readfds
, NULL
, NULL
, NULL
);
498 while (n
== -1 && errno
== EINTR
);
503 static void fport_flush (SCM port
);
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. */
509 fport_fill_input (SCM port
)
512 scm_port
*pt
= SCM_PTAB_ENTRY (port
);
513 struct scm_fport
*fp
= SCM_FSTREAM (port
);
516 fport_wait_for_input (port
);
518 SCM_SYSCALL (count
= read (fp
->fdes
, pt
->read_buf
, pt
->read_buf_size
));
520 scm_syserror ("fport_fill_input");
525 pt
->read_pos
= pt
->read_buf
;
526 pt
->read_end
= pt
->read_buf
+ count
;
527 return *pt
->read_buf
;
532 fport_seek (SCM port
, off_t offset
, int whence
)
534 scm_port
*pt
= SCM_PTAB_ENTRY (port
);
535 struct scm_fport
*fp
= SCM_FSTREAM (port
);
539 if (pt
->rw_active
== SCM_PORT_WRITE
)
541 if (offset
!= 0 || whence
!= SEEK_CUR
)
544 result
= rv
= lseek (fp
->fdes
, offset
, whence
);
548 /* read current position without disturbing the buffer. */
549 rv
= lseek (fp
->fdes
, offset
, whence
);
550 result
= rv
+ (pt
->write_pos
- pt
->write_buf
);
553 else if (pt
->rw_active
== SCM_PORT_READ
)
555 if (offset
!= 0 || whence
!= SEEK_CUR
)
557 /* could expand to avoid a second seek. */
558 scm_end_input (port
);
559 result
= rv
= lseek (fp
->fdes
, offset
, whence
);
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
);
568 if (pt
->read_buf
== pt
->putback_buf
)
569 result
-= pt
->saved_read_end
- pt
->saved_read_pos
;
572 else /* SCM_PORT_NEITHER */
574 result
= rv
= lseek (fp
->fdes
, offset
, whence
);
578 scm_syserror ("fport_seek");
584 fport_truncate (SCM port
, off_t length
)
586 struct scm_fport
*fp
= SCM_FSTREAM (port
);
588 if (ftruncate (fp
->fdes
, length
) == -1)
589 scm_syserror ("ftruncate");
593 fport_write (SCM port
, void *data
, size_t size
)
595 scm_port
*pt
= SCM_PTAB_ENTRY (port
);
597 if (pt
->write_buf
== &pt
->shortbuf
)
599 /* "unbuffered" port. */
600 int fdes
= SCM_FSTREAM (port
)->fdes
;
602 if (write (fdes
, data
, size
) == -1)
603 scm_syserror ("fport_write");
607 const char *input
= (char *) data
;
608 size_t remaining
= size
;
610 while (remaining
> 0)
612 int space
= pt
->write_end
- pt
->write_pos
;
613 int write_len
= (remaining
> space
) ? space
: remaining
;
615 memcpy (pt
->write_pos
, input
, write_len
);
616 pt
->write_pos
+= write_len
;
617 remaining
-= write_len
;
619 if (write_len
== space
)
623 /* handle line buffering. */
624 if ((SCM_CAR (port
) & SCM_BUFLINE
) && memchr (data
, '\n', size
))
629 /* becomes 1 when process is exiting: normal exception handling won't
630 work by this time. */
631 extern int terminating
;
634 fport_flush (SCM port
)
636 scm_port
*pt
= SCM_PTAB_ENTRY (port
);
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
;
642 while (remaining
> 0)
646 SCM_SYSCALL (count
= write (fp
->fdes
, ptr
, remaining
));
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
;
657 for (i
= 0; i
< remaining
; i
++)
659 *(pt
->write_buf
+ i
) = *(pt
->write_buf
+ done
+ i
);
661 pt
->write_pos
= pt
->write_buf
+ remaining
;
664 scm_syserror ("fport_flush");
667 const char *msg
= "Error: could not flush file-descriptor ";
670 write (2, msg
, strlen (msg
));
671 sprintf (buf
, "%d\n", fp
->fdes
);
672 write (2, buf
, strlen (buf
));
680 pt
->write_pos
= pt
->write_buf
;
681 pt
->rw_active
= SCM_PORT_NEITHER
;
684 /* clear the read buffer and adjust the file position for unread bytes. */
686 fport_end_input (SCM port
, int offset
)
688 struct scm_fport
*fp
= SCM_FSTREAM (port
);
689 scm_port
*pt
= SCM_PTAB_ENTRY (port
);
691 offset
+= pt
->read_end
- pt
->read_pos
;
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)
699 scm_syserror ("fport_end_input");
701 pt
->rw_active
= SCM_PORT_NEITHER
;
705 fport_close (SCM port
)
707 struct scm_fport
*fp
= SCM_FSTREAM (port
);
708 scm_port
*pt
= SCM_PTAB_ENTRY (port
);
712 SCM_SYSCALL (rv
= close (fp
->fdes
));
713 if (rv
== -1 && errno
!= EBADF
)
714 scm_syserror ("fport_close");
715 if (pt
->read_buf
== pt
->putback_buf
)
716 pt
->read_buf
= pt
->saved_read_buf
;
717 if (pt
->read_buf
!= &pt
->shortbuf
)
719 if (pt
->write_buf
!= &pt
->shortbuf
)
720 free (pt
->write_buf
);
726 fport_free (SCM port
)
732 void scm_make_fptob (void); /* Called from ports.c */
737 long tc
= scm_make_port_type ("file", fport_fill_input
, fport_write
);
738 scm_set_port_free (tc
, fport_free
);
739 scm_set_port_print (tc
, prinfport
);
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
);
752 scm_sysintern ("_IOFBF", SCM_MAKINUM (_IOFBF
));
753 scm_sysintern ("_IOLBF", SCM_MAKINUM (_IOLBF
));
754 scm_sysintern ("_IONBF", SCM_MAKINUM (_IONBF
));