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