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