*** empty log message ***
[bpt/guile.git] / libguile / fports.c
CommitLineData
7dc6e754 1/* Copyright (C) 1995,1996,1997,1998 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. */
0f2d19dd
JB
41\f
42
43#include <stdio.h>
cb63cf9e 44#include <fcntl.h>
0f2d19dd 45#include "_scm.h"
20e6290e
JB
46
47#include "fports.h"
95b88819
GH
48
49#ifdef HAVE_STRING_H
50#include <string.h>
51#endif
0f2d19dd
JB
52#ifdef HAVE_UNISTD_H
53#include <unistd.h>
54#else
0f2d19dd
JB
55scm_sizet fwrite ();
56#endif
cb63cf9e
JB
57#ifdef HAVE_ST_BLKSIZE
58#include <sys/stat.h>
59#endif
0f2d19dd 60
cb63cf9e 61#include <errno.h>
e145dd02 62
cb63cf9e
JB
63#include "iselect.h"
64
65/* create FPORT buffer with specified sizes (or -1 to use default size or
66 0 for no buffer. */
67static void
68scm_fport_buffer_add (SCM port, int read_size, int write_size)
e145dd02 69{
cb63cf9e
JB
70 struct scm_fport *fp = SCM_FSTREAM (port);
71 struct scm_port_table *pt = SCM_PTAB_ENTRY (port);
72 char *s_scm_fport_buffer_add = "scm_fport_buffer_add";
e145dd02 73
cb63cf9e
JB
74 if (read_size == -1 || write_size == -1)
75 {
76 int default_size;
77#ifdef HAVE_ST_BLKSIZE
78 struct stat st;
79
80 if (fstat (fp->fdes, &st) == -1)
81 scm_syserror (s_scm_fport_buffer_add);
82 default_size = st.st_blksize;
83#else
84 default_size = 1024;
85#endif
86 if (read_size == -1)
87 read_size = default_size;
88 if (write_size == -1)
89 write_size = default_size;
90 }
0f2d19dd 91
cb63cf9e
JB
92 if (SCM_INPORTP (port) && read_size > 0)
93 {
94 pt->read_buf = scm_must_malloc (read_size, s_scm_fport_buffer_add);
95 pt->read_pos = pt->read_end = pt->read_buf;
96 pt->read_buf_size = read_size;
97 }
98 else
99 {
100 pt->read_buf = pt->read_pos = pt->read_end = &pt->shortbuf;
101 pt->read_buf_size = 1;
102 }
1717856b 103
cb63cf9e
JB
104 if (SCM_OUTPORTP (port) && write_size > 0)
105 {
106 pt->write_buf = scm_must_malloc (write_size, s_scm_fport_buffer_add);
107 pt->write_pos = pt->write_buf;
108 pt->write_buf_size = write_size;
109 }
110 else
111 {
112 pt->write_buf = pt->write_pos = &pt->shortbuf;
113 pt->write_buf_size = 1;
114 }
115
116 pt->write_end = pt->write_buf + pt->write_buf_size;
117 if (read_size > 0 || write_size > 0)
118 SCM_SETCAR (port, SCM_CAR (port) & ~SCM_BUF0);
119 else
120 SCM_SETCAR (port, (SCM_CAR (port) | SCM_BUF0));
7a6f1ffa
GH
121}
122
123SCM_PROC (s_setvbuf, "setvbuf", 2, 1, 0, scm_setvbuf);
124SCM
125scm_setvbuf (SCM port, SCM mode, SCM size)
126{
7a6f1ffa 127 int cmode, csize;
cb63cf9e 128 struct scm_port_table *pt;
7a6f1ffa 129
78446828
MV
130 port = SCM_COERCE_OUTPORT (port);
131
cb63cf9e
JB
132 SCM_ASSERT (SCM_NIMP (port) && SCM_OPFPORTP (port), port, SCM_ARG1,
133 s_setvbuf);
7a6f1ffa 134 SCM_ASSERT (SCM_INUMP (mode), mode, SCM_ARG2, s_setvbuf);
cb63cf9e
JB
135 cmode = SCM_INUM (mode);
136 if (cmode != _IONBF && cmode != _IOFBF)
137 scm_out_of_range (s_setvbuf, mode);
7a6f1ffa 138 if (SCM_UNBNDP (size))
cb63cf9e
JB
139 {
140 if (cmode == _IOFBF)
141 csize = -1;
142 else
143 csize = 0;
144 }
7a6f1ffa
GH
145 else
146 {
147 SCM_ASSERT (SCM_INUMP (size), size, SCM_ARG3, s_setvbuf);
148 csize = SCM_INUM (size);
cb63cf9e
JB
149 if (csize < 0 || (cmode == _IONBF && csize > 0))
150 scm_out_of_range (s_setvbuf, size);
7a6f1ffa 151 }
cb63cf9e 152 pt = SCM_PTAB_ENTRY (port);
7a6f1ffa 153
cb63cf9e
JB
154 /* silently discards buffered chars. */
155 if (pt->read_buf != &pt->shortbuf)
156 scm_must_free (pt->read_buf);
157 if (pt->write_buf != &pt->shortbuf)
158 scm_must_free (pt->write_buf);
7a6f1ffa 159
cb63cf9e
JB
160 scm_fport_buffer_add (port, csize, csize);
161 return SCM_UNSPECIFIED;
0f2d19dd
JB
162}
163
eadd48de
GH
164/* Move ports with the specified file descriptor to new descriptors,
165 * reseting the revealed count to 0.
0f2d19dd 166 */
1717856b 167
eadd48de
GH
168void
169scm_evict_ports (fd)
170 int fd;
0f2d19dd 171{
eadd48de 172 int i;
0f2d19dd 173
eadd48de
GH
174 for (i = 0; i < scm_port_table_size; i++)
175 {
cb63cf9e
JB
176 SCM port = scm_port_table[i]->port;
177
178 if (SCM_FPORTP (port))
eadd48de 179 {
cb63cf9e
JB
180 struct scm_fport *fp = SCM_FSTREAM (port);
181
182 if (fp->fdes == fd)
183 {
184 fp->fdes = dup (fd);
185 if (fp->fdes == -1)
186 scm_syserror ("scm_evict_ports");
187 scm_set_port_revealed_x (port, SCM_MAKINUM (0));
188 }
eadd48de
GH
189 }
190 }
191}
0f2d19dd
JB
192
193/* scm_open_file
194 * Return a new port open on a given file.
195 *
196 * The mode string must match the pattern: [rwa+]** which
197 * is interpreted in the usual unix way.
198 *
199 * Return the new port.
200 */
19639113 201SCM_PROC(s_open_file, "open-file", 2, 0, 0, scm_open_file);
1717856b 202
0f2d19dd 203SCM
19639113
GH
204scm_open_file (filename, modes)
205 SCM filename;
206 SCM modes;
0f2d19dd 207{
19639113 208 SCM port;
cb63cf9e
JB
209 int fdes;
210 int flags = 0;
19639113
GH
211 char *file;
212 char *mode;
cb63cf9e 213 char *ptr;
19639113
GH
214
215 SCM_ASSERT (SCM_NIMP (filename) && SCM_ROSTRINGP (filename), filename, SCM_ARG1, s_open_file);
216 SCM_ASSERT (SCM_NIMP (modes) && SCM_ROSTRINGP (modes), modes, SCM_ARG2, s_open_file);
217 if (SCM_SUBSTRP (filename))
218 filename = scm_makfromstr (SCM_ROCHARS (filename), SCM_ROLENGTH (filename), 0);
219 if (SCM_SUBSTRP (modes))
220 modes = scm_makfromstr (SCM_ROCHARS (modes), SCM_ROLENGTH (modes), 0);
221
222 file = SCM_ROCHARS (filename);
223 mode = SCM_ROCHARS (modes);
224
cb63cf9e 225 switch (*mode)
0f2d19dd 226 {
cb63cf9e
JB
227 case 'r':
228 flags |= O_RDONLY;
229 break;
230 case 'w':
231 flags |= O_WRONLY | O_CREAT | O_TRUNC;
232 break;
233 case 'a':
234 flags |= O_WRONLY | O_CREAT | O_APPEND;
235 break;
236 default:
237 scm_out_of_range (s_open_file, modes);
0f2d19dd 238 }
cb63cf9e
JB
239 ptr = mode + 1;
240 while (*ptr != '\0')
e145dd02 241 {
cb63cf9e
JB
242 switch (*ptr)
243 {
244 case '+':
245 flags = (flags & ~(O_RDONLY | O_WRONLY)) | O_RDWR;
246 break;
247 case '0': /* unbuffered: handled later. */
248 case 'b': /* 'binary' mode: ignored. */
249 break;
250 default:
251 scm_out_of_range (s_open_file, modes);
252 }
253 ptr++;
e145dd02 254 }
cb63cf9e
JB
255 SCM_SYSCALL (fdes = open (file, flags, 0666));
256 if (fdes == -1)
e145dd02 257 {
cb63cf9e
JB
258 int en = errno;
259
260 scm_syserror_msg (s_open_file, "%s: %S",
261 scm_cons (scm_makfrom0str (strerror (en)),
262 scm_cons (filename, SCM_EOL)),
263 en);
0f2d19dd 264 }
cb63cf9e 265 port = scm_fdes_to_port (fdes, mode, filename);
0f2d19dd
JB
266 return port;
267}
268
e145dd02 269\f
cb63cf9e 270/* Building Guile ports from a file descriptor. */
e145dd02 271
cb63cf9e 272/* Build a Scheme port from an open file descriptor `fdes'.
a089567e
JB
273 MODE indicates whether FILE is open for reading or writing; it uses
274 the same notation as open-file's second argument.
e145dd02 275 Use NAME as the port's filename. */
cb63cf9e 276
a089567e 277SCM
cb63cf9e 278scm_fdes_to_port (int fdes, char *mode, SCM name)
a089567e
JB
279{
280 long mode_bits = scm_mode_bits (mode);
281 SCM port;
282 struct scm_port_table * pt;
283
284 SCM_NEWCELL (port);
285 SCM_DEFER_INTS;
cb63cf9e
JB
286 pt = scm_add_to_port_table (port);
287 SCM_SETPTAB_ENTRY (port, pt);
288 SCM_SETCAR (port, (scm_tc16_fport | mode_bits));
289
a089567e 290 {
cb63cf9e
JB
291 struct scm_fport *fp
292 = (struct scm_fport *) scm_must_malloc (sizeof (struct scm_fport),
293 "scm_fdes_to_port");
294 fp->fdes = fdes;
295 fp->random = SCM_FDES_RANDOM_P (fdes);
296
297 SCM_SETSTREAM (port, fp);
298 if (mode_bits & SCM_BUF0)
299 scm_fport_buffer_add (port, 0, 0);
300 else
301 scm_fport_buffer_add (port, -1, -1);
a089567e 302 }
cb63cf9e 303 SCM_PTAB_ENTRY (port)->file_name = name;
a089567e 304 SCM_ALLOW_INTS;
e145dd02
JB
305 return port;
306}
307
308
cb63cf9e
JB
309/* Check whether an fport's fdes can supply input. */
310static int
311fport_input_waiting_p (SCM port)
e145dd02 312{
cb63cf9e
JB
313 int fdes = SCM_FSTREAM (port)->fdes;
314
315#ifdef HAVE_SELECT
316 struct timeval timeout;
317 SELECT_TYPE read_set;
318 SELECT_TYPE write_set;
319 SELECT_TYPE except_set;
320
321 FD_ZERO (&read_set);
322 FD_ZERO (&write_set);
323 FD_ZERO (&except_set);
324
325 FD_SET (fdes, &read_set);
326
327 timeout.tv_sec = 0;
328 timeout.tv_usec = 0;
329
330 if (select (SELECT_SET_SIZE,
331 &read_set, &write_set, &except_set, &timeout)
332 < 0)
333 scm_syserror ("fport_input_waiting_p");
334 return FD_ISSET (fdes, &read_set);
335#elif defined (FIONREAD)
336 int remir;
337 ioctl(fdes, FIONREAD, &remir);
338 return remir;
339#else
340 scm_misc_error ("fport_input_waiting_p",
341 "Not fully implemented on this platform",
342 SCM_EOL);
343#endif
a089567e
JB
344}
345
cb63cf9e
JB
346/* Clear an fport's read buffer and return buffered chars. */
347char *
348scm_fport_drain_input (SCM port, int *count_return)
349{
350 struct scm_port_table *pt = SCM_PTAB_ENTRY (port);
351 char *result = pt->read_pos;
a089567e 352
cb63cf9e
JB
353 *count_return = pt->read_end - pt->read_pos;
354 pt->read_pos = pt->read_end;
355 return result;
356}
1717856b 357
cb63cf9e 358\f
1717856b
JB
359static int prinfport SCM_P ((SCM exp, SCM port, scm_print_state *pstate));
360
0f2d19dd 361static int
1717856b 362prinfport (exp, port, pstate)
0f2d19dd
JB
363 SCM exp;
364 SCM port;
1717856b 365 scm_print_state *pstate;
0f2d19dd
JB
366{
367 SCM name;
368 char * c;
369 if (SCM_CLOSEDP (exp))
370 {
371 c = "file";
372 }
373 else
374 {
375 name = SCM_PTAB_ENTRY (exp)->file_name;
376 if (SCM_NIMP (name) && SCM_ROSTRINGP (name))
377 c = SCM_ROCHARS (name);
378 else
379 c = "file";
380 }
19639113 381
0f2d19dd
JB
382 scm_prinport (exp, port, c);
383 return !0;
384}
385
cb63cf9e
JB
386#ifdef GUILE_ISELECT
387/* thread-local block for input on fport's fdes. */
388static void
389fport_wait_for_input (SCM port)
3cb988bd 390{
cb63cf9e 391 int fdes = SCM_FSTREAM (port)->fdes;
3cb988bd 392
cb63cf9e 393 if (!fport_input_waiting_p (port))
8122b543 394 {
cb63cf9e
JB
395 int n;
396 SELECT_TYPE readfds;
397 int flags = fcntl (fdes, F_GETFL);
398
399 if (flags == -1)
400 scm_syserror ("scm_fdes_wait_for_input");
401 if (!(flags & O_NONBLOCK))
402 do
403 {
404 FD_ZERO (&readfds);
405 FD_SET (fdes, &readfds);
406 n = scm_internal_select (fdes + 1, &readfds, NULL, NULL, NULL);
407 }
408 while (n == -1 && errno == EINTR);
8122b543 409 }
3cb988bd 410}
0f2d19dd
JB
411#endif
412
cb63cf9e 413static void local_fflush (SCM port);
0f2d19dd 414
cb63cf9e
JB
415/* fill a port's read-buffer with a single read.
416 returns the first char and moves the read_pos pointer past it.
417 or returns EOF if end of file. */
0f2d19dd 418static int
cb63cf9e 419fport_fill_buffer (SCM port)
0f2d19dd 420{
cb63cf9e
JB
421 int count;
422 struct scm_port_table *pt = SCM_PTAB_ENTRY (port);
423 struct scm_fport *fp = SCM_FSTREAM (port);
424
425 if (fp->random)
426 {
427 /* flush any write buffer first: fix file position and allow the
428 newly written chars to be read. */
429 if (pt->write_pos > pt->write_buf)
430 local_fflush (port);
431 pt->write_needs_seek = 1;
432 }
433#ifdef GUILE_ISELECT
434 fport_wait_for_input (port);
435#endif
436 SCM_SYSCALL (count = read (fp->fdes, pt->read_buf, pt->read_buf_size));
437 if (count == -1)
438 scm_syserror ("fport_fill_buffer");
439 if (count == 0)
440 return EOF;
441 else
442 {
443 pt->read_pos = pt->read_buf + 1;
444 pt->read_end = pt->read_buf + count;
445 return (*(pt->read_buf));
446 }
0f2d19dd
JB
447}
448
cb63cf9e
JB
449static off_t
450local_seek (SCM port, off_t offset, int whence)
0f2d19dd 451{
cb63cf9e 452 struct scm_fport *fp = SCM_FSTREAM (port);
ea9fc30d 453
cb63cf9e 454 return lseek (fp->fdes, offset, whence);
0f2d19dd
JB
455}
456
cb63cf9e
JB
457/* becomes 1 when process is exiting: exception handling is disabled. */
458extern int terminating;
0f2d19dd 459
cb63cf9e
JB
460static void
461local_fflush (SCM port)
0f2d19dd 462{
cb63cf9e
JB
463 struct scm_port_table *pt = SCM_PTAB_ENTRY (port);
464 struct scm_fport *fp = SCM_FSTREAM (port);
465 char *ptr = pt->write_buf;
466 int init_size = pt->write_pos - pt->write_buf;
467 int remaining = init_size;
0f2d19dd 468
cb63cf9e
JB
469 while (remaining > 0)
470 {
471 int count;
472
473 SCM_SYSCALL (count = write (fp->fdes, ptr, remaining));
474 if (count < 0)
475 {
476 /* error. assume nothing was written this call, but
477 fix up the buffer for any previous successful writes. */
478 int done = init_size - remaining;
479
480 if (done > 0)
481 {
482 int i;
483
484 for (i = 0; i < remaining; i++)
485 {
486 *(pt->write_buf + i) = *(pt->write_buf + done + i);
487 }
488 pt->write_pos = pt->write_buf + remaining;
489 }
490 if (!terminating)
491 scm_syserror ("local_fflush");
492 else
493 {
494 const char *msg = "Error: could not flush file-descriptor ";
495 char buf[11];
496
497 write (2, msg, strlen (msg));
498 sprintf (buf, "%d\n", fp->fdes);
499 write (2, buf, strlen (buf));
500
501 count = remaining;
502 }
503 }
504 ptr += count;
505 remaining -= count;
506 }
507 pt->write_pos = pt->write_buf;
8f29fbd0
JB
508}
509
6a2c4c81 510static int
cb63cf9e 511local_fclose (SCM port)
6a2c4c81 512{
cb63cf9e
JB
513 struct scm_fport *fp = SCM_FSTREAM (port);
514 struct scm_port_table *pt = SCM_PTAB_ENTRY (port);
515 int rv;
516
517 local_fflush (port);
518 SCM_SYSCALL (rv = close (fp->fdes));
519 if (rv == -1 && errno != EBADF)
520 scm_syserror ("local_fclose");
521 if (pt->read_buf != &pt->shortbuf)
522 scm_must_free (pt->read_buf);
523 if (pt->write_buf != &pt->shortbuf)
524 scm_must_free (pt->write_buf);
525 scm_must_free ((char *) fp);
526 return rv;
6a2c4c81
JB
527}
528
0f2d19dd 529scm_ptobfuns scm_fptob =
cb63cf9e 530 {
dc53f026 531 0,
ea9fc30d 532 local_fclose,
0f2d19dd
JB
533 prinfport,
534 0,
ea9fc30d 535 local_fflush,
cb63cf9e
JB
536 local_fclose,
537 fport_fill_buffer,
538 local_seek,
539 fport_input_waiting_p,
19468eff 540};
0f2d19dd 541
0f2d19dd
JB
542void
543scm_init_fports ()
0f2d19dd
JB
544{
545#include "fports.x"
7a6f1ffa
GH
546 scm_sysintern ("_IOFBF", SCM_MAKINUM (_IOFBF));
547 scm_sysintern ("_IOLBF", SCM_MAKINUM (_IOLBF));
548 scm_sysintern ("_IONBF", SCM_MAKINUM (_IONBF));
0f2d19dd 549}