*** empty log message ***
[bpt/guile.git] / libguile / ports.c
... / ...
CommitLineData
1/* Copyright (C) 1995,1996,1997,1998,1999 Free Software Foundation, Inc.
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
15 * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
16 * Boston, MA 02111-1307 USA
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.
40 * If you do not wish that, delete this exception notice. */
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
45\f
46/* Headers. */
47
48#include <stdio.h>
49#include "_scm.h"
50#include "objects.h"
51#include "smob.h"
52#include "chars.h"
53
54#include "keywords.h"
55
56#include "scm_validate.h"
57#include "ports.h"
58
59#ifdef HAVE_MALLOC_H
60#include <malloc.h>
61#endif
62
63#ifdef HAVE_UNISTD_H
64#include <unistd.h>
65#endif
66
67#ifdef HAVE_SYS_IOCTL_H
68#include <sys/ioctl.h>
69#endif
70
71\f
72/* The port kind table --- a dynamically resized array of port types. */
73
74
75/* scm_ptobs scm_numptob
76 * implement a dynamicly resized array of ptob records.
77 * Indexes into this table are used when generating type
78 * tags for smobjects (if you know a tag you can get an index and conversely).
79 */
80scm_ptob_descriptor *scm_ptobs;
81int scm_numptob;
82
83/* GC marker for a port with stream of SCM type. */
84SCM
85scm_markstream (SCM ptr)
86{
87 int openp;
88 openp = SCM_CAR (ptr) & SCM_OPN;
89 if (openp)
90 return SCM_STREAM (ptr);
91 else
92 return SCM_BOOL_F;
93}
94
95/*
96 * We choose to use an interface similar to the smob interface with
97 * fill_input and write as standard fields, passed to the port
98 * type constructor, and optional fields set by setters.
99 */
100
101static void flush_void_port (SCM port);
102static void end_input_void_port (SCM port, int offset);
103static void write_void_port (SCM port, void *data, size_t size);
104
105long
106scm_make_port_type (char *name,
107 int (*fill_input) (SCM port),
108 void (*write) (SCM port, void *data, size_t size))
109{
110 char *tmp;
111 if (255 <= scm_numptob)
112 goto ptoberr;
113 SCM_DEFER_INTS;
114 SCM_SYSCALL (tmp = (char *) realloc ((char *) scm_ptobs,
115 (1 + scm_numptob)
116 * sizeof (scm_ptob_descriptor)));
117 if (tmp)
118 {
119 scm_ptobs = (scm_ptob_descriptor *) tmp;
120
121 scm_ptobs[scm_numptob].name = name;
122 scm_ptobs[scm_numptob].mark = 0;
123 scm_ptobs[scm_numptob].free = scm_free0;
124 scm_ptobs[scm_numptob].print = scm_port_print;
125 scm_ptobs[scm_numptob].equalp = 0;
126 scm_ptobs[scm_numptob].close = 0;
127
128 scm_ptobs[scm_numptob].write = write;
129 scm_ptobs[scm_numptob].flush = flush_void_port;
130
131 scm_ptobs[scm_numptob].end_input = end_input_void_port;
132 scm_ptobs[scm_numptob].fill_input = fill_input;
133 scm_ptobs[scm_numptob].input_waiting = 0;
134
135 scm_ptobs[scm_numptob].seek = 0;
136 scm_ptobs[scm_numptob].truncate = 0;
137
138 scm_numptob++;
139 }
140 SCM_ALLOW_INTS;
141 if (!tmp)
142 ptoberr:scm_wta (SCM_MAKINUM ((long) scm_numptob),
143 (char *) SCM_NALLOC, "scm_make_port_type");
144 /* Make a class object if Goops is present */
145 if (scm_port_class)
146 scm_make_port_classes (scm_numptob - 1, SCM_PTOBNAME (scm_numptob - 1));
147 return scm_tc7_port + (scm_numptob - 1) * 256;
148}
149
150void
151scm_set_port_mark (long tc, SCM (*mark) (SCM))
152{
153 scm_ptobs[SCM_TC2PTOBNUM (tc)].mark = mark;
154}
155
156void
157scm_set_port_free (long tc, scm_sizet (*free) (SCM))
158{
159 scm_ptobs[SCM_TC2PTOBNUM (tc)].free = free;
160}
161
162void
163scm_set_port_print (long tc, int (*print) (SCM exp, SCM port,
164 scm_print_state *pstate))
165{
166 scm_ptobs[SCM_TC2PTOBNUM (tc)].print = print;
167}
168
169void
170scm_set_port_equalp (long tc, SCM (*equalp) (SCM, SCM))
171{
172 scm_ptobs[SCM_TC2PTOBNUM (tc)].equalp = equalp;
173}
174
175void
176scm_set_port_flush (long tc, void (*flush) (SCM port))
177{
178 scm_ptobs[SCM_TC2PTOBNUM (tc)].flush = flush;
179}
180
181void
182scm_set_port_end_input (long tc, void (*end_input) (SCM port, int offset))
183{
184 scm_ptobs[SCM_TC2PTOBNUM (tc)].end_input = end_input;
185}
186
187void
188scm_set_port_close (long tc, int (*close) (SCM))
189{
190 scm_ptobs[SCM_TC2PTOBNUM (tc)].close = close;
191}
192
193void
194scm_set_port_seek (long tc, off_t (*seek) (SCM port,
195 off_t OFFSET,
196 int WHENCE))
197{
198 scm_ptobs[SCM_TC2PTOBNUM (tc)].seek = seek;
199}
200
201void
202scm_set_port_truncate (long tc, void (*truncate) (SCM port, off_t length))
203{
204 scm_ptobs[SCM_TC2PTOBNUM (tc)].truncate = truncate;
205}
206
207void
208scm_set_port_input_waiting (long tc, int (*input_waiting) (SCM))
209{
210 scm_ptobs[SCM_TC2PTOBNUM (tc)].input_waiting = input_waiting;
211}
212
213\f
214
215GUILE_PROC(scm_char_ready_p, "char-ready?", 0, 1, 0,
216 (SCM port),
217"")
218#define FUNC_NAME s_scm_char_ready_p
219{
220 scm_port *pt;
221
222 if (SCM_UNBNDP (port))
223 port = scm_cur_inp;
224 else
225 SCM_VALIDATE_OPINPORT(1,port);
226
227 pt = SCM_PTAB_ENTRY (port);
228
229 /* if the current read buffer is filled, or the
230 last pushed-back char has been read and the saved buffer is
231 filled, result is true. */
232 if (pt->read_pos < pt->read_end
233 || (pt->read_buf == pt->putback_buf
234 && pt->saved_read_pos < pt->saved_read_end))
235 return SCM_BOOL_T;
236 else
237 {
238 scm_ptob_descriptor *ptob = &scm_ptobs[SCM_PTOBNUM (port)];
239
240 if (ptob->input_waiting)
241 return SCM_BOOL(ptob->input_waiting (port));
242 else
243 return SCM_BOOL_T;
244 }
245}
246#undef FUNC_NAME
247
248/* Clear a port's read buffers, returning the contents. */
249GUILE_PROC (scm_drain_input, "drain-input", 1, 0, 0,
250 (SCM port),
251"Drains @var{PORT}'s read buffers (including any pushed-back characters)
252and returns the contents as a single string.")
253#define FUNC_NAME s_scm_drain_input
254{
255 SCM result;
256 scm_port *pt = SCM_PTAB_ENTRY (port);
257 int count;
258 char *dst;
259
260 SCM_VALIDATE_OPINPORT(1,port);
261
262 count = pt->read_end - pt->read_pos;
263 if (pt->read_buf == pt->putback_buf)
264 count += pt->saved_read_end - pt->saved_read_pos;
265
266 result = scm_makstr (count, 0);
267 dst = SCM_CHARS (result);
268
269 while (pt->read_pos < pt->read_end)
270 *dst++ = *(pt->read_pos++);
271
272 if (pt->read_buf == pt->putback_buf)
273 {
274 while (pt->saved_read_pos < pt->saved_read_end)
275 *dst++ = *(pt->saved_read_pos++);
276 }
277
278 return result;
279}
280#undef FUNC_NAME
281
282\f
283/* Standard ports --- current input, output, error, and more(!). */
284
285GUILE_PROC(scm_current_input_port, "current-input-port", 0, 0, 0,
286 (),
287"")
288#define FUNC_NAME s_scm_current_input_port
289{
290 return scm_cur_inp;
291}
292#undef FUNC_NAME
293
294GUILE_PROC(scm_current_output_port, "current-output-port", 0, 0, 0,
295 (),
296"")
297#define FUNC_NAME s_scm_current_output_port
298{
299 return scm_cur_outp;
300}
301#undef FUNC_NAME
302
303GUILE_PROC(scm_current_error_port, "current-error-port", 0, 0, 0,
304 (),
305"Return the port to which errors and warnings should be sent (the
306@dfn{standard error} in Unix and C terminology).")
307#define FUNC_NAME s_scm_current_error_port
308{
309 return scm_cur_errp;
310}
311#undef FUNC_NAME
312
313GUILE_PROC(scm_current_load_port, "current-load-port", 0, 0, 0,
314 (),
315"")
316#define FUNC_NAME s_scm_current_load_port
317{
318 return scm_cur_loadp;
319}
320#undef FUNC_NAME
321
322GUILE_PROC(scm_set_current_input_port, "set-current-input-port", 1, 0, 0,
323 (SCM port),
324"@deffnx primitive set-current-output-port port
325@deffnx primitive set-current-error-port port
326Change the ports returned by @code{current-input-port},
327@code{current-output-port} and @code{current-error-port}, respectively,
328so that they use the supplied @var{port} for input or output.")
329#define FUNC_NAME s_scm_set_current_input_port
330{
331 SCM oinp = scm_cur_inp;
332 SCM_VALIDATE_OPINPORT(1,port);
333 scm_cur_inp = port;
334 return oinp;
335}
336#undef FUNC_NAME
337
338
339GUILE_PROC(scm_set_current_output_port, "set-current-output-port", 1, 0, 0,
340 (SCM port),
341"")
342#define FUNC_NAME s_scm_set_current_output_port
343{
344 SCM ooutp = scm_cur_outp;
345 port = SCM_COERCE_OUTPORT (port);
346 SCM_VALIDATE_OPOUTPORT(1,port);
347 scm_cur_outp = port;
348 return ooutp;
349}
350#undef FUNC_NAME
351
352
353GUILE_PROC(scm_set_current_error_port, "set-current-error-port", 1, 0, 0,
354 (SCM port),
355"")
356#define FUNC_NAME s_scm_set_current_error_port
357{
358 SCM oerrp = scm_cur_errp;
359 port = SCM_COERCE_OUTPORT (port);
360 SCM_VALIDATE_OPOUTPORT(1,port);
361 scm_cur_errp = port;
362 return oerrp;
363}
364#undef FUNC_NAME
365
366\f
367/* The port table --- an array of pointers to ports. */
368
369scm_port **scm_port_table;
370
371int scm_port_table_size = 0; /* Number of ports in scm_port_table. */
372int scm_port_table_room = 20; /* Size of the array. */
373
374/* Add a port to the table. */
375
376scm_port *
377scm_add_to_port_table (SCM port)
378{
379 scm_port *entry;
380
381 if (scm_port_table_size == scm_port_table_room)
382 {
383 void *newt = realloc ((char *) scm_port_table,
384 (scm_sizet) (sizeof (scm_port *)
385 * scm_port_table_room * 2));
386 if (newt == NULL)
387 scm_memory_error ("scm_add_to_port_table");
388 scm_port_table = (scm_port **) newt;
389 scm_port_table_room *= 2;
390 }
391 entry = (scm_port *) malloc (sizeof (scm_port));
392 if (entry == NULL)
393 scm_memory_error ("scm_add_to_port_table");
394
395 entry->port = port;
396 entry->entry = scm_port_table_size;
397 entry->revealed = 0;
398 entry->stream = 0;
399 entry->file_name = SCM_BOOL_F;
400 entry->line_number = 0;
401 entry->column_number = 0;
402 entry->putback_buf = 0;
403 entry->putback_buf_size = 0;
404 entry->rw_active = SCM_PORT_NEITHER;
405 entry->rw_random = 0;
406
407 scm_port_table[scm_port_table_size] = entry;
408 scm_port_table_size++;
409
410 return entry;
411}
412
413/* Remove a port from the table and destroy it. */
414
415void
416scm_remove_from_port_table (SCM port)
417{
418 scm_port *p = SCM_PTAB_ENTRY (port);
419 int i = p->entry;
420
421 if (i >= scm_port_table_size)
422 scm_wta (port, "Port not in table", "scm_remove_from_port_table");
423 if (p->putback_buf)
424 free (p->putback_buf);
425 free (p);
426 /* Since we have just freed slot i we can shrink the table by moving
427 the last entry to that slot... */
428 if (i < scm_port_table_size - 1)
429 {
430 scm_port_table[i] = scm_port_table[scm_port_table_size - 1];
431 scm_port_table[i]->entry = i;
432 }
433 SCM_SETPTAB_ENTRY (port, 0);
434 scm_port_table_size--;
435}
436
437#ifdef GUILE_DEBUG
438/* Undocumented functions for debugging. */
439/* Return the number of ports in the table. */
440
441GUILE_PROC(scm_pt_size, "pt-size", 0, 0, 0,
442 (),
443"")
444#define FUNC_NAME s_scm_pt_size
445{
446 return SCM_MAKINUM (scm_port_table_size);
447}
448#undef FUNC_NAME
449
450/* Return the ith member of the port table. */
451GUILE_PROC(scm_pt_member, "pt-member", 1, 0, 0,
452 (SCM member),
453"")
454#define FUNC_NAME s_scm_pt_member
455{
456 int i;
457 SCM_VALIDATE_INUM_COPY (1,member,i);
458 if (i < 0 || i >= scm_port_table_size)
459 return SCM_BOOL_F;
460 else
461 return scm_port_table[i]->port;
462}
463#undef FUNC_NAME
464#endif
465
466
467\f
468/* Revealed counts --- an oddity inherited from SCSH. */
469
470/* Find a port in the table and return its revealed count.
471 Also used by the garbage collector.
472 */
473
474int
475scm_revealed_count (SCM port)
476{
477 return SCM_REVEALED(port);
478}
479
480
481
482/* Return the revealed count for a port. */
483
484GUILE_PROC(scm_port_revealed, "port-revealed", 1, 0, 0,
485 (SCM port),
486"Returns the revealed count for @var{port}.")
487#define FUNC_NAME s_scm_port_revealed
488{
489 port = SCM_COERCE_OUTPORT (port);
490 SCM_VALIDATE_PORT(1,port);
491 return SCM_MAKINUM (scm_revealed_count (port));
492}
493#undef FUNC_NAME
494
495/* Set the revealed count for a port. */
496GUILE_PROC(scm_set_port_revealed_x, "set-port-revealed!", 2, 0, 0,
497 (SCM port, SCM rcount),
498"Sets the revealed count for a port to a given value.
499The return value is unspecified.")
500#define FUNC_NAME s_scm_set_port_revealed_x
501{
502 port = SCM_COERCE_OUTPORT (port);
503 SCM_VALIDATE_PORT(1,port);
504 SCM_VALIDATE_INUM(2,rcount);
505 SCM_REVEALED (port) = SCM_INUM (rcount);
506 return SCM_UNSPECIFIED;
507}
508#undef FUNC_NAME
509
510
511\f
512/* Retrieving a port's mode. */
513
514/* Return the flags that characterize a port based on the mode
515 * string used to open a file for that port.
516 *
517 * See PORT FLAGS in scm.h
518 */
519
520long
521scm_mode_bits (char *modes)
522{
523 return (SCM_OPN
524 | (strchr (modes, 'r') || strchr (modes, '+') ? SCM_RDNG : 0)
525 | ( strchr (modes, 'w')
526 || strchr (modes, 'a')
527 || strchr (modes, '+') ? SCM_WRTNG : 0)
528 | (strchr (modes, '0') ? SCM_BUF0 : 0)
529 | (strchr (modes, 'l') ? SCM_BUFLINE : 0));
530}
531
532
533/* Return the mode flags from an open port.
534 * Some modes such as "append" are only used when opening
535 * a file and are not returned here. */
536
537GUILE_PROC(scm_port_mode, "port-mode", 1, 0, 0,
538 (SCM port),
539"Returns the port modes associated with the open port @var{port}. These
540will not necessarily be identical to the modes used when the port was
541opened, since modes such as \"append\" which are used only during
542port creation are not retained.")
543#define FUNC_NAME s_scm_port_mode
544{
545 char modes[3];
546 modes[0] = '\0';
547
548 port = SCM_COERCE_OUTPORT (port);
549 SCM_VALIDATE_OPPORT(1,port);
550 if (SCM_CAR (port) & SCM_RDNG) {
551 if (SCM_CAR (port) & SCM_WRTNG)
552 strcpy (modes, "r+");
553 else
554 strcpy (modes, "r");
555 }
556 else if (SCM_CAR (port) & SCM_WRTNG)
557 strcpy (modes, "w");
558 if (SCM_CAR (port) & SCM_BUF0)
559 strcat (modes, "0");
560 return scm_makfromstr (modes, strlen (modes), 0);
561}
562#undef FUNC_NAME
563
564
565\f
566/* Closing ports. */
567
568/* scm_close_port
569 * Call the close operation on a port object.
570 * see also scm_close.
571 */
572GUILE_PROC(scm_close_port, "close-port", 1, 0, 0,
573 (SCM port),
574"Close the specified port object. Returns @code{#t} if it successfully
575closes a port or @code{#f} if it was already
576closed. An exception may be raised if an error occurs, for example
577when flushing buffered output.
578See also @ref{Ports and File Descriptors, close}, for a procedure
579which can close file descriptors.")
580#define FUNC_NAME s_scm_close_port
581{
582 scm_sizet i;
583 int rv;
584
585 port = SCM_COERCE_OUTPORT (port);
586
587 SCM_VALIDATE_PORT(1,port);
588 if (SCM_CLOSEDP (port))
589 return SCM_BOOL_F;
590 i = SCM_PTOBNUM (port);
591 if (scm_ptobs[i].close)
592 rv = (scm_ptobs[i].close) (port);
593 else
594 rv = 0;
595 scm_remove_from_port_table (port);
596 SCM_SETAND_CAR (port, ~SCM_OPN);
597 return SCM_NEGATE_BOOL(rv < 0);
598}
599#undef FUNC_NAME
600
601GUILE_PROC(scm_close_all_ports_except, "close-all-ports-except", 0, 0, 1,
602 (SCM ports),
603"Close all open file ports used by the interpreter
604except for those supplied as arguments. This procedure
605is intended to be used before an exec call to close file descriptors
606which are not needed in the new process.Close all open file ports used by the interpreter
607except for those supplied as arguments. This procedure
608is intended to be used before an exec call to close file descriptors
609which are not needed in the new process.")
610#define FUNC_NAME s_scm_close_all_ports_except
611{
612 int i = 0;
613 SCM_VALIDATE_CONS(1,ports);
614 while (i < scm_port_table_size)
615 {
616 SCM thisport = scm_port_table[i]->port;
617 int found = 0;
618 SCM ports_ptr = ports;
619
620 while (SCM_NNULLP (ports_ptr))
621 {
622 SCM port = SCM_COERCE_OUTPORT (SCM_CAR (ports_ptr));
623 if (i == 0)
624 SCM_VALIDATE_OPPORT(SCM_ARG1,port);
625 if (port == thisport)
626 found = 1;
627 ports_ptr = SCM_CDR (ports_ptr);
628 }
629 if (found)
630 i++;
631 else
632 /* i is not to be incremented here. */
633 scm_close_port (thisport);
634 }
635 return SCM_UNSPECIFIED;
636}
637#undef FUNC_NAME
638
639
640\f
641/* Utter miscellany. Gosh, we should clean this up some time. */
642
643GUILE_PROC(scm_input_port_p, "input-port?", 1, 0, 0,
644 (SCM x),
645"")
646#define FUNC_NAME s_scm_input_port_p
647{
648 if (SCM_IMP (x))
649 return SCM_BOOL_F;
650 return SCM_BOOL(SCM_INPORTP (x));
651}
652#undef FUNC_NAME
653
654GUILE_PROC(scm_output_port_p, "output-port?", 1, 0, 0,
655 (SCM x),
656"")
657#define FUNC_NAME s_scm_output_port_p
658{
659 if (SCM_IMP (x))
660 return SCM_BOOL_F;
661 if (SCM_PORT_WITH_PS_P (x))
662 x = SCM_PORT_WITH_PS_PORT (x);
663 return SCM_BOOL(SCM_OUTPORTP (x));
664}
665#undef FUNC_NAME
666
667GUILE_PROC(scm_port_closed_p, "port-closed?", 1, 0, 0,
668 (SCM port),
669"Returns @code{#t} if @var{port} is closed or @code{#f} if it is open.")
670#define FUNC_NAME s_scm_port_closed_p
671{
672 SCM_VALIDATE_OPPORT(1,port);
673 return SCM_NEGATE_BOOL(SCM_OPPORTP (port));
674}
675#undef FUNC_NAME
676
677GUILE_PROC(scm_eof_object_p, "eof-object?", 1, 0, 0,
678 (SCM x),
679"")
680#define FUNC_NAME s_scm_eof_object_p
681{
682 return SCM_BOOL(SCM_EOF_OBJECT_P (x));
683}
684#undef FUNC_NAME
685
686GUILE_PROC(scm_force_output, "force-output", 0, 1, 0,
687 (SCM port),
688"Flush the specified output port, or the current output port if @var{port}
689is omitted. The current output buffer contents are passed to the
690underlying port implementation (e.g., in the case of fports, the
691data will be written to the file and the output buffer will be cleared.)
692It has no effect on an unbuffered port.
693
694The return value is unspecified.")
695#define FUNC_NAME s_scm_force_output
696{
697 if (SCM_UNBNDP (port))
698 port = scm_cur_outp;
699 else
700 {
701 port = SCM_COERCE_OUTPORT (port);
702 SCM_VALIDATE_OPOUTPORT(1,port);
703 }
704 scm_flush (port);
705 return SCM_UNSPECIFIED;
706}
707#undef FUNC_NAME
708
709GUILE_PROC (scm_flush_all_ports, "flush-all-ports", 0, 0, 0,
710 (),
711"Equivalent to calling @code{force-output} on
712all open output ports. The return value is unspecified.")
713#define FUNC_NAME s_scm_flush_all_ports
714{
715 int i;
716
717 for (i = 0; i < scm_port_table_size; i++)
718 {
719 if (SCM_OPOUTPORTP (scm_port_table[i]->port))
720 scm_flush (scm_port_table[i]->port);
721 }
722 return SCM_UNSPECIFIED;
723}
724#undef FUNC_NAME
725
726GUILE_PROC(scm_read_char, "read-char", 0, 1, 0,
727 (SCM port),
728"")
729#define FUNC_NAME s_scm_read_char
730{
731 int c;
732 if (SCM_UNBNDP (port))
733 port = scm_cur_inp;
734 SCM_VALIDATE_OPINPORT(1,port);
735 c = scm_getc (port);
736 if (EOF == c)
737 return SCM_EOF_VAL;
738 return SCM_MAKICHR (c);
739}
740#undef FUNC_NAME
741
742/* this should only be called when the read buffer is empty. it
743 tries to refill the read buffer. it returns the first char from
744 the port, which is either EOF or *(pt->read_pos). */
745int
746scm_fill_input (SCM port)
747{
748 scm_port *pt = SCM_PTAB_ENTRY (port);
749
750 if (pt->read_buf == pt->putback_buf)
751 {
752 /* finished reading put-back chars. */
753 pt->read_buf = pt->saved_read_buf;
754 pt->read_pos = pt->saved_read_pos;
755 pt->read_end = pt->saved_read_end;
756 pt->read_buf_size = pt->saved_read_buf_size;
757 if (pt->read_pos < pt->read_end)
758 return *(pt->read_pos);
759 }
760 return scm_ptobs[SCM_PTOBNUM (port)].fill_input (port);
761}
762
763int
764scm_getc (SCM port)
765{
766 int c;
767 scm_port *pt = SCM_PTAB_ENTRY (port);
768
769 if (pt->rw_active == SCM_PORT_WRITE)
770 {
771 /* may be marginally faster than calling scm_flush. */
772 scm_ptobs[SCM_PTOBNUM (port)].flush (port);
773 }
774
775 if (pt->rw_random)
776 pt->rw_active = SCM_PORT_READ;
777
778 if (pt->read_pos >= pt->read_end)
779 {
780 if (scm_fill_input (port) == EOF)
781 return EOF;
782 }
783
784 c = *(pt->read_pos++);
785
786 if (c == '\n')
787 {
788 SCM_INCLINE (port);
789 }
790 else if (c == '\t')
791 {
792 SCM_TABCOL (port);
793 }
794 else
795 {
796 SCM_INCCOL (port);
797 }
798
799 return c;
800}
801
802void
803scm_putc (char c, SCM port)
804{
805 scm_lfwrite (&c, 1, port);
806}
807
808void
809scm_puts (char *s, SCM port)
810{
811 scm_lfwrite (s, strlen (s), port);
812}
813
814void
815scm_lfwrite (char *ptr, scm_sizet size, SCM port)
816{
817 scm_port *pt = SCM_PTAB_ENTRY (port);
818 scm_ptob_descriptor *ptob = &scm_ptobs[SCM_PTOBNUM (port)];
819
820 if (pt->rw_active == SCM_PORT_READ)
821 scm_end_input (port);
822
823 ptob->write (port, ptr, size);
824
825 if (pt->rw_random)
826 pt->rw_active = SCM_PORT_WRITE;
827}
828
829
830void
831scm_flush (SCM port)
832{
833 scm_sizet i = SCM_PTOBNUM (port);
834 (scm_ptobs[i].flush) (port);
835}
836
837void
838scm_end_input (SCM port)
839{
840 int offset;
841 scm_port *pt = SCM_PTAB_ENTRY (port);
842
843 if (pt->read_buf == pt->putback_buf)
844 {
845 offset = pt->read_end - pt->read_pos;
846 pt->read_buf = pt->saved_read_buf;
847 pt->read_pos = pt->saved_read_pos;
848 pt->read_end = pt->saved_read_end;
849 pt->read_buf_size = pt->saved_read_buf_size;
850 }
851 else
852 offset = 0;
853
854 scm_ptobs[SCM_PTOBNUM (port)].end_input (port, offset);
855}
856
857\f
858
859
860void
861scm_ungetc (int c, SCM port)
862{
863 scm_port *pt = SCM_PTAB_ENTRY (port);
864
865 if (pt->read_buf == pt->putback_buf)
866 /* already using the put-back buffer. */
867 {
868 /* enlarge putback_buf if necessary. */
869 if (pt->read_end == pt->read_buf + pt->read_buf_size
870 && pt->read_buf == pt->read_pos)
871 {
872 int new_size = pt->read_buf_size * 2;
873 unsigned char *tmp =
874 (unsigned char *) realloc (pt->putback_buf, new_size);
875
876 if (tmp == NULL)
877 scm_memory_error ("scm_ungetc");
878 pt->read_pos = pt->read_buf = pt->putback_buf = tmp;
879 pt->read_end = pt->read_buf + pt->read_buf_size;
880 pt->read_buf_size = pt->putback_buf_size = new_size;
881 }
882
883 /* shift any existing bytes to buffer + 1. */
884 if (pt->read_pos == pt->read_end)
885 pt->read_end = pt->read_buf + 1;
886 else if (pt->read_pos != pt->read_buf + 1)
887 {
888 int count = pt->read_end - pt->read_pos;
889
890 memmove (pt->read_buf + 1, pt->read_pos, count);
891 pt->read_end = pt->read_buf + 1 + count;
892 }
893
894 pt->read_pos = pt->read_buf;
895 }
896 else
897 /* switch to the put-back buffer. */
898 {
899 if (pt->putback_buf == NULL)
900 {
901 pt->putback_buf = (char *) malloc (SCM_INITIAL_PUTBACK_BUF_SIZE);
902 if (pt->putback_buf == NULL)
903 scm_memory_error ("scm_ungetc");
904 pt->putback_buf_size = SCM_INITIAL_PUTBACK_BUF_SIZE;
905 }
906
907 pt->saved_read_buf = pt->read_buf;
908 pt->saved_read_pos = pt->read_pos;
909 pt->saved_read_end = pt->read_end;
910 pt->saved_read_buf_size = pt->read_buf_size;
911
912 pt->read_pos = pt->read_buf = pt->putback_buf;
913 pt->read_end = pt->read_buf + 1;
914 pt->read_buf_size = pt->putback_buf_size;
915 }
916
917 *pt->read_buf = c;
918
919 if (pt->rw_random)
920 pt->rw_active = SCM_PORT_READ;
921
922 if (c == '\n')
923 {
924 /* What should col be in this case?
925 * We'll leave it at -1.
926 */
927 SCM_LINUM (port) -= 1;
928 }
929 else
930 SCM_COL(port) -= 1;
931}
932
933
934void
935scm_ungets (char *s, int n, SCM port)
936{
937 /* This is simple minded and inefficient, but unreading strings is
938 * probably not a common operation, and remember that line and
939 * column numbers have to be handled...
940 *
941 * Please feel free to write an optimized version!
942 */
943 while (n--)
944 scm_ungetc (s[n], port);
945}
946
947
948GUILE_PROC(scm_peek_char, "peek-char", 0, 1, 0,
949 (SCM port),
950"")
951#define FUNC_NAME s_scm_peek_char
952{
953 int c;
954 if (SCM_UNBNDP (port))
955 port = scm_cur_inp;
956 else
957 SCM_VALIDATE_OPINPORT(1,port);
958 c = scm_getc (port);
959 if (EOF == c)
960 return SCM_EOF_VAL;
961 scm_ungetc (c, port);
962 return SCM_MAKICHR (c);
963}
964#undef FUNC_NAME
965
966GUILE_PROC (scm_unread_char, "unread-char", 2, 0, 0,
967 (SCM cobj, SCM port),
968"Place @var{char} in @var{port} so that it will be read by the
969next read operation. If called multiple times, the unread characters
970will be read again in last-in first-out order. If @var{port} is
971not supplied, the current input port is used.")
972#define FUNC_NAME s_scm_unread_char
973{
974 int c;
975
976 SCM_VALIDATE_CHAR(1,cobj);
977 if (SCM_UNBNDP (port))
978 port = scm_cur_inp;
979 else
980 SCM_VALIDATE_OPINPORT(2,port);
981
982 c = SCM_ICHR (cobj);
983
984 scm_ungetc (c, port);
985 return cobj;
986}
987#undef FUNC_NAME
988
989GUILE_PROC (scm_unread_string, "unread-string", 2, 0, 0,
990 (SCM str, SCM port),
991"Place the string @var{str} in @var{port} so that its characters will be
992read in subsequent read operations. If called multiple times, the
993unread characters will be read again in last-in first-out order. If
994@var{port} is not supplied, the current-input-port is used.")
995#define FUNC_NAME s_scm_unread_string
996{
997 SCM_VALIDATE_STRING(1,str);
998 if (SCM_UNBNDP (port))
999 port = scm_cur_inp;
1000 else
1001 SCM_VALIDATE_OPINPORT(2,port);
1002
1003 scm_ungets (SCM_ROUCHARS (str), SCM_LENGTH (str), port);
1004
1005 return str;
1006}
1007#undef FUNC_NAME
1008
1009GUILE_PROC (scm_seek, "seek", 3, 0, 0,
1010 (SCM object, SCM offset, SCM whence),
1011"Sets the current position of @var{fd/port} to the integer @var{offset},
1012which is interpreted according to the value of @var{whence}.
1013
1014One of the following variables should be supplied
1015for @var{whence}:
1016@defvar SEEK_SET
1017Seek from the beginning of the file.
1018@end defvar
1019@defvar SEEK_CUR
1020Seek from the current position.
1021@end defvar
1022@defvar SEEK_END
1023Seek from the end of the file.
1024@end defvar
1025
1026If @var{fd/port} is a file descriptor, the underlying system call is
1027@code{lseek}. @var{port} may be a string port.
1028
1029The value returned is the new position in the file. This means that
1030the current position of a port can be obtained using:
1031@smalllisp
1032(seek port 0 SEEK_CUR)
1033@end smalllisp")
1034#define FUNC_NAME s_scm_seek
1035{
1036 off_t off;
1037 off_t rv;
1038 int how;
1039
1040 object = SCM_COERCE_OUTPORT (object);
1041
1042 off = SCM_NUM2LONG (2,offset);
1043 SCM_VALIDATE_INUM_COPY(3,whence,how);
1044 if (how != SEEK_SET && how != SEEK_CUR && how != SEEK_END)
1045 SCM_OUT_OF_RANGE (3, whence);
1046 if (SCM_OPPORTP (object))
1047 {
1048 scm_ptob_descriptor *ptob = scm_ptobs + SCM_PTOBNUM (object);
1049
1050 if (!ptob->seek)
1051 SCM_MISC_ERROR ("port is not seekable",
1052 scm_cons (object, SCM_EOL));
1053 else
1054 rv = ptob->seek (object, off, how);
1055 }
1056 else /* file descriptor?. */
1057 {
1058 SCM_VALIDATE_INUM(1,object);
1059 rv = lseek (SCM_INUM (object), off, how);
1060 if (rv == -1)
1061 SCM_SYSERROR;
1062 }
1063 return scm_long2num (rv);
1064}
1065#undef FUNC_NAME
1066
1067GUILE_PROC (scm_truncate_file, "truncate-file", 1, 1, 0,
1068 (SCM object, SCM length),
1069"Truncates the object referred to by @var{obj} to at most @var{size} bytes.
1070@var{obj} can be a string containing a file name or an integer file
1071descriptor or a port. @var{size} may be omitted if @var{obj} is not
1072a file name, in which case the truncation occurs at the current port.
1073position.
1074
1075The return value is unspecified.")
1076#define FUNC_NAME s_scm_truncate_file
1077{
1078 int rv;
1079 off_t c_length;
1080
1081 /* object can be a port, fdes or filename. */
1082
1083 if (SCM_UNBNDP (length))
1084 {
1085 /* must supply length if object is a filename. */
1086 if (SCM_ROSTRINGP (object))
1087 scm_wrong_num_args (SCM_FUNC_NAME);
1088
1089 length = scm_seek (object, SCM_INUM0, SCM_MAKINUM (SEEK_CUR));
1090 }
1091 c_length = SCM_NUM2LONG (2,length);
1092 if (c_length < 0)
1093 SCM_MISC_ERROR ("negative offset", SCM_EOL);
1094
1095 object = SCM_COERCE_OUTPORT (object);
1096 if (SCM_INUMP (object))
1097 {
1098 SCM_SYSCALL (rv = ftruncate (SCM_INUM (object), c_length));
1099 }
1100 else if (SCM_OPOUTPORTP (object))
1101 {
1102 scm_port *pt = SCM_PTAB_ENTRY (object);
1103 scm_ptob_descriptor *ptob = scm_ptobs + SCM_PTOBNUM (object);
1104
1105 if (!ptob->truncate)
1106 SCM_MISC_ERROR ("port is not truncatable", SCM_EOL);
1107 if (pt->rw_active == SCM_PORT_READ)
1108 scm_end_input (object);
1109 else if (pt->rw_active == SCM_PORT_WRITE)
1110 ptob->flush (object);
1111
1112 ptob->truncate (object, c_length);
1113 rv = 0;
1114 }
1115 else
1116 {
1117 SCM_VALIDATE_ROSTRING(1,object);
1118 SCM_COERCE_SUBSTR (object);
1119 SCM_SYSCALL (rv = truncate (SCM_ROCHARS (object), c_length));
1120 }
1121 if (rv == -1)
1122 SCM_SYSERROR;
1123 return SCM_UNSPECIFIED;
1124}
1125#undef FUNC_NAME
1126
1127GUILE_PROC (scm_port_line, "port-line", 1, 0, 0,
1128 (SCM port),
1129"")
1130#define FUNC_NAME s_scm_port_line
1131{
1132 port = SCM_COERCE_OUTPORT (port);
1133 SCM_VALIDATE_OPENPORT(1,port);
1134 return SCM_MAKINUM (SCM_LINUM (port));
1135}
1136#undef FUNC_NAME
1137
1138GUILE_PROC (scm_set_port_line_x, "set-port-line!", 2, 0, 0,
1139 (SCM port, SCM line),
1140"")
1141#define FUNC_NAME s_scm_set_port_line_x
1142{
1143 port = SCM_COERCE_OUTPORT (port);
1144 SCM_VALIDATE_OPENPORT(1,port);
1145 SCM_VALIDATE_INUM(2,line);
1146 return SCM_PTAB_ENTRY (port)->line_number = SCM_INUM (line);
1147}
1148#undef FUNC_NAME
1149
1150GUILE_PROC (scm_port_column, "port-column", 1, 0, 0,
1151 (SCM port),
1152"@deffnx primitive port-line [input-port]
1153Return the current column number or line number of @var{input-port},
1154using the current input port if none is specified. If the number is
1155unknown, the result is #f. Otherwise, the result is a 0-origin integer
1156- i.e. the first character of the first line is line 0, column 0.
1157(However, when you display a file position, for example in an error
1158message, we recommand you add 1 to get 1-origin integers. This is
1159because lines and column numbers traditionally start with 1, and that is
1160what non-programmers will find most natural.)")
1161#define FUNC_NAME s_scm_port_column
1162{
1163 port = SCM_COERCE_OUTPORT (port);
1164 SCM_VALIDATE_OPENPORT(1,port);
1165 return SCM_MAKINUM (SCM_COL (port));
1166}
1167#undef FUNC_NAME
1168
1169GUILE_PROC (scm_set_port_column_x, "set-port-column!", 2, 0, 0,
1170 (SCM port, SCM column),
1171"@deffnx primitive set-port-line! [input-port] line
1172Set the current column or line number of @var{input-port}, using the
1173current input port if none is specified.")
1174#define FUNC_NAME s_scm_set_port_column_x
1175{
1176 port = SCM_COERCE_OUTPORT (port);
1177 SCM_VALIDATE_OPENPORT(1,port);
1178 SCM_VALIDATE_INUM(2,column);
1179 return SCM_PTAB_ENTRY (port)->column_number = SCM_INUM (column);
1180}
1181#undef FUNC_NAME
1182
1183GUILE_PROC (scm_port_filename, "port-filename", 1, 0, 0,
1184 (SCM port),
1185"Return the filename associated with @var{port}. This function returns
1186the strings "standard input", "standard output" and "standard error"
1187when called on the current input, output and error ports respectively.")
1188#define FUNC_NAME s_scm_port_filename
1189{
1190 port = SCM_COERCE_OUTPORT (port);
1191 SCM_VALIDATE_OPENPORT(1,port);
1192 return SCM_PTAB_ENTRY (port)->file_name;
1193}
1194#undef FUNC_NAME
1195
1196GUILE_PROC (scm_set_port_filename_x, "set-port-filename!", 2, 0, 0,
1197 (SCM port, SCM filename),
1198"Change the filename associated with @var{port}, using the current input
1199port if none is specified. Note that this does not change the port's
1200source of data, but only the value that is returned by
1201@code{port-filename} and reported in diagnostic output.")
1202#define FUNC_NAME s_scm_set_port_filename_x
1203{
1204 port = SCM_COERCE_OUTPORT (port);
1205 SCM_VALIDATE_OPENPORT(1,port);
1206 /* We allow the user to set the filename to whatever he likes. */
1207 return SCM_PTAB_ENTRY (port)->file_name = filename;
1208}
1209#undef FUNC_NAME
1210
1211#ifndef ttyname
1212extern char * ttyname();
1213#endif
1214
1215void
1216scm_print_port_mode (SCM exp, SCM port)
1217{
1218 scm_puts (SCM_CLOSEDP (exp)
1219 ? "closed: "
1220 : (SCM_RDNG & SCM_CAR (exp)
1221 ? (SCM_WRTNG & SCM_CAR (exp)
1222 ? "input-output: "
1223 : "input: ")
1224 : (SCM_WRTNG & SCM_CAR (exp)
1225 ? "output: "
1226 : "bogus: ")),
1227 port);
1228}
1229
1230int
1231scm_port_print (SCM exp, SCM port, scm_print_state *pstate)
1232{
1233 char *type = SCM_PTOBNAME (SCM_PTOBNUM (exp));
1234 if (!type)
1235 type = "port";
1236 scm_puts ("#<", port);
1237 scm_print_port_mode (exp, port);
1238 scm_puts (type, port);
1239 scm_putc (' ', port);
1240 scm_intprint (SCM_CDR (exp), 16, port);
1241 scm_putc ('>', port);
1242 return 1;
1243}
1244
1245extern void scm_make_fptob ();
1246extern void scm_make_stptob ();
1247extern void scm_make_sfptob ();
1248
1249void
1250scm_ports_prehistory ()
1251{
1252 scm_numptob = 0;
1253 scm_ptobs = (scm_ptob_descriptor *) malloc (sizeof (scm_ptob_descriptor));
1254
1255 /* WARNING: These scm_newptob calls must be done in this order.
1256 * They must agree with the port declarations in tags.h.
1257 */
1258 /* scm_tc16_fport = */ scm_make_fptob ();
1259 /* scm_tc16_pipe was here */ scm_make_fptob (); /* dummy. */
1260 /* scm_tc16_strport = */ scm_make_stptob ();
1261 /* scm_tc16_sfport = */ scm_make_sfptob ();
1262}
1263
1264\f
1265
1266/* Void ports. */
1267
1268long scm_tc16_void_port = 0;
1269
1270static void
1271flush_void_port (SCM port)
1272{
1273}
1274
1275static void
1276end_input_void_port (SCM port, int offset)
1277{
1278}
1279
1280static void
1281write_void_port (SCM port, void *data, size_t size)
1282{
1283}
1284
1285SCM
1286scm_void_port (char *mode_str)
1287{
1288 int mode_bits;
1289 SCM answer;
1290 scm_port * pt;
1291
1292 SCM_NEWCELL (answer);
1293 SCM_DEFER_INTS;
1294 mode_bits = scm_mode_bits (mode_str);
1295 pt = scm_add_to_port_table (answer);
1296 SCM_SETPTAB_ENTRY (answer, pt);
1297 SCM_SETSTREAM (answer, 0);
1298 SCM_SETCAR (answer, scm_tc16_void_port | mode_bits);
1299 SCM_ALLOW_INTS;
1300 return answer;
1301}
1302
1303
1304GUILE_PROC (scm_sys_make_void_port, "%make-void-port", 1, 0, 0,
1305 (SCM mode),
1306"Create and return a new void port. The @var{mode} argument describes
1307the input/output modes for this port; for a description, see the
1308documentation for @code{open-file} in @ref{File Ports}.")
1309#define FUNC_NAME s_scm_sys_make_void_port
1310{
1311 SCM_VALIDATE_ROSTRING(1,mode);
1312 SCM_COERCE_SUBSTR (mode);
1313 return scm_void_port (SCM_ROCHARS (mode));
1314}
1315#undef FUNC_NAME
1316
1317\f
1318/* Initialization. */
1319
1320void
1321scm_init_ports ()
1322{
1323 /* lseek() symbols. */
1324 scm_sysintern ("SEEK_SET", SCM_MAKINUM (SEEK_SET));
1325 scm_sysintern ("SEEK_CUR", SCM_MAKINUM (SEEK_CUR));
1326 scm_sysintern ("SEEK_END", SCM_MAKINUM (SEEK_END));
1327
1328 scm_tc16_void_port = scm_make_port_type ("void", 0, write_void_port);
1329#include "ports.x"
1330}