* gh_data.c (gh_set_substr): Revert change of 1999-08-29; bcopy is
[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 (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
96 static void flush_void_port (SCM port);
97 static void end_input_void_port (SCM port, int offset);
98 static void write_void_port (SCM port, void *data, size_t size);
99
100 long
101 scm_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
145 void
146 scm_set_port_mark (long tc, SCM (*mark) (SCM))
147 {
148 scm_ptobs[SCM_TC2PTOBNUM (tc)].mark = mark;
149 }
150
151 void
152 scm_set_port_free (long tc, scm_sizet (*free) (SCM))
153 {
154 scm_ptobs[SCM_TC2PTOBNUM (tc)].free = free;
155 }
156
157 void
158 scm_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
164 void
165 scm_set_port_equalp (long tc, SCM (*equalp) (SCM, SCM))
166 {
167 scm_ptobs[SCM_TC2PTOBNUM (tc)].equalp = equalp;
168 }
169
170 void
171 scm_set_port_flush (long tc, void (*flush) (SCM port))
172 {
173 scm_ptobs[SCM_TC2PTOBNUM (tc)].flush = flush;
174 }
175
176 void
177 scm_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
182 void
183 scm_set_port_close (long tc, int (*close) (SCM))
184 {
185 scm_ptobs[SCM_TC2PTOBNUM (tc)].close = close;
186 }
187
188 void
189 scm_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
196 void
197 scm_set_port_truncate (long tc, void (*truncate) (SCM port, off_t length))
198 {
199 scm_ptobs[SCM_TC2PTOBNUM (tc)].truncate = truncate;
200 }
201
202 void
203 scm_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
210 SCM_PROC(s_char_ready_p, "char-ready?", 0, 1, 0, scm_char_ready_p);
211
212 SCM
213 scm_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. */
244 SCM_PROC (s_drain_input, "drain-input", 1, 0, 0, scm_drain_input);
245 SCM
246 scm_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
278 SCM_PROC(s_current_input_port, "current-input-port", 0, 0, 0, scm_current_input_port);
279
280 SCM
281 scm_current_input_port ()
282 {
283 return scm_cur_inp;
284 }
285
286 SCM_PROC(s_current_output_port, "current-output-port", 0, 0, 0, scm_current_output_port);
287
288 SCM
289 scm_current_output_port ()
290 {
291 return scm_cur_outp;
292 }
293
294 SCM_PROC(s_current_error_port, "current-error-port", 0, 0, 0, scm_current_error_port);
295
296 SCM
297 scm_current_error_port ()
298 {
299 return scm_cur_errp;
300 }
301
302 SCM_PROC(s_current_load_port, "current-load-port", 0, 0, 0, scm_current_load_port);
303
304 SCM
305 scm_current_load_port ()
306 {
307 return scm_cur_loadp;
308 }
309
310 SCM_PROC(s_set_current_input_port, "set-current-input-port", 1, 0, 0, scm_set_current_input_port);
311
312 SCM
313 scm_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
322 SCM_PROC(s_set_current_output_port, "set-current-output-port", 1, 0, 0, scm_set_current_output_port);
323
324 SCM
325 scm_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
335 SCM_PROC(s_set_current_error_port, "set-current-error-port", 1, 0, 0, scm_set_current_error_port);
336
337 SCM
338 scm_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
350 scm_port **scm_port_table;
351
352 int scm_port_table_size = 0; /* Number of ports in scm_port_table. */
353 int scm_port_table_room = 20; /* Size of the array. */
354
355 /* Add a port to the table. */
356
357 scm_port *
358 scm_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
387 scm_port_table[scm_port_table_size] = entry;
388 scm_port_table_size++;
389
390 return entry;
391 }
392
393 /* Remove a port from the table and destroy it. */
394
395 void
396 scm_remove_from_port_table (SCM port)
397 {
398 scm_port *p = SCM_PTAB_ENTRY (port);
399 int i = p->entry;
400
401 if (i >= scm_port_table_size)
402 scm_wta (port, "Port not in table", "scm_remove_from_port_table");
403 if (p->putback_buf)
404 free (p->putback_buf);
405 free (p);
406 /* Since we have just freed slot i we can shrink the table by moving
407 the last entry to that slot... */
408 if (i < scm_port_table_size - 1)
409 {
410 scm_port_table[i] = scm_port_table[scm_port_table_size - 1];
411 scm_port_table[i]->entry = i;
412 }
413 SCM_SETPTAB_ENTRY (port, 0);
414 scm_port_table_size--;
415 }
416
417 #ifdef GUILE_DEBUG
418 /* Undocumented functions for debugging. */
419 /* Return the number of ports in the table. */
420
421 SCM_PROC(s_pt_size, "pt-size", 0, 0, 0, scm_pt_size);
422 SCM
423 scm_pt_size ()
424 {
425 return SCM_MAKINUM (scm_port_table_size);
426 }
427
428 /* Return the ith member of the port table. */
429 SCM_PROC(s_pt_member, "pt-member", 1, 0, 0, scm_pt_member);
430 SCM
431 scm_pt_member (SCM member)
432 {
433 int i;
434 SCM_ASSERT (SCM_INUMP (member), member, SCM_ARG1, s_pt_member);
435 i = SCM_INUM (member);
436 if (i < 0 || i >= scm_port_table_size)
437 return SCM_BOOL_F;
438 else
439 return scm_port_table[i]->port;
440 }
441 #endif
442
443
444 \f
445 /* Revealed counts --- an oddity inherited from SCSH. */
446
447 /* Find a port in the table and return its revealed count.
448 Also used by the garbage collector.
449 */
450
451 int
452 scm_revealed_count (SCM port)
453 {
454 return SCM_REVEALED(port);
455 }
456
457
458
459 /* Return the revealed count for a port. */
460
461 SCM_PROC(s_port_revealed, "port-revealed", 1, 0, 0, scm_port_revealed);
462
463 SCM
464 scm_port_revealed (SCM port)
465 {
466 port = SCM_COERCE_OUTPORT (port);
467 SCM_ASSERT (SCM_NIMP (port) && SCM_PORTP (port), port, SCM_ARG1, s_port_revealed);
468 return SCM_MAKINUM (scm_revealed_count (port));
469 }
470
471 /* Set the revealed count for a port. */
472 SCM_PROC(s_set_port_revealed_x, "set-port-revealed!", 2, 0, 0, scm_set_port_revealed_x);
473
474 SCM
475 scm_set_port_revealed_x (SCM port, SCM rcount)
476 {
477 port = SCM_COERCE_OUTPORT (port);
478 SCM_ASSERT (SCM_NIMP (port) && SCM_PORTP (port),
479 port, SCM_ARG1, s_set_port_revealed_x);
480 SCM_ASSERT (SCM_INUMP (rcount), rcount, SCM_ARG2, s_set_port_revealed_x);
481 SCM_REVEALED (port) = SCM_INUM (rcount);
482 return SCM_UNSPECIFIED;
483 }
484
485
486 \f
487 /* Retrieving a port's mode. */
488
489 /* Return the flags that characterize a port based on the mode
490 * string used to open a file for that port.
491 *
492 * See PORT FLAGS in scm.h
493 */
494
495 long
496 scm_mode_bits (char *modes)
497 {
498 return (SCM_OPN
499 | (strchr (modes, 'r') || strchr (modes, '+') ? SCM_RDNG : 0)
500 | ( strchr (modes, 'w')
501 || strchr (modes, 'a')
502 || strchr (modes, '+') ? SCM_WRTNG : 0)
503 | (strchr (modes, '0') ? SCM_BUF0 : 0)
504 | (strchr (modes, 'l') ? SCM_BUFLINE : 0));
505 }
506
507
508 /* Return the mode flags from an open port.
509 * Some modes such as "append" are only used when opening
510 * a file and are not returned here. */
511
512 SCM_PROC(s_port_mode, "port-mode", 1, 0, 0, scm_port_mode);
513
514 SCM
515 scm_port_mode (SCM port)
516 {
517 char modes[3];
518 modes[0] = '\0';
519
520 port = SCM_COERCE_OUTPORT (port);
521 SCM_ASSERT (SCM_NIMP (port) && SCM_OPPORTP (port), port, SCM_ARG1, s_port_mode);
522 if (SCM_CAR (port) & SCM_RDNG) {
523 if (SCM_CAR (port) & SCM_WRTNG)
524 strcpy (modes, "r+");
525 else
526 strcpy (modes, "r");
527 }
528 else if (SCM_CAR (port) & SCM_WRTNG)
529 strcpy (modes, "w");
530 if (SCM_CAR (port) & SCM_BUF0)
531 strcat (modes, "0");
532 return scm_makfromstr (modes, strlen (modes), 0);
533 }
534
535
536 \f
537 /* Closing ports. */
538
539 /* scm_close_port
540 * Call the close operation on a port object.
541 * see also scm_close.
542 */
543 SCM_PROC(s_close_port, "close-port", 1, 0, 0, scm_close_port);
544
545 SCM
546 scm_close_port (SCM port)
547 {
548 scm_sizet i;
549 int rv;
550
551 port = SCM_COERCE_OUTPORT (port);
552
553 SCM_ASSERT (SCM_NIMP (port) && SCM_PORTP (port), port, SCM_ARG1,
554 s_close_port);
555 if (SCM_CLOSEDP (port))
556 return SCM_BOOL_F;
557 i = SCM_PTOBNUM (port);
558 if (scm_ptobs[i].close)
559 rv = (scm_ptobs[i].close) (port);
560 else
561 rv = 0;
562 scm_remove_from_port_table (port);
563 SCM_SETAND_CAR (port, ~SCM_OPN);
564 return (rv < 0) ? SCM_BOOL_F : SCM_BOOL_T;
565 }
566
567 SCM_PROC(s_close_all_ports_except, "close-all-ports-except", 0, 0, 1, scm_close_all_ports_except);
568
569 SCM
570 scm_close_all_ports_except (SCM ports)
571 {
572 int i = 0;
573 SCM_ASSERT (SCM_NIMP (ports) && SCM_CONSP (ports), ports, SCM_ARG1, s_close_all_ports_except);
574 while (i < scm_port_table_size)
575 {
576 SCM thisport = scm_port_table[i]->port;
577 int found = 0;
578 SCM ports_ptr = ports;
579
580 while (SCM_NNULLP (ports_ptr))
581 {
582 SCM port = SCM_COERCE_OUTPORT (SCM_CAR (ports_ptr));
583 if (i == 0)
584 SCM_ASSERT (SCM_NIMP (port) && SCM_OPPORTP (port), port, SCM_ARG1, s_close_all_ports_except);
585 if (port == thisport)
586 found = 1;
587 ports_ptr = SCM_CDR (ports_ptr);
588 }
589 if (found)
590 i++;
591 else
592 /* i is not to be incremented here. */
593 scm_close_port (thisport);
594 }
595 return SCM_UNSPECIFIED;
596 }
597
598
599 \f
600 /* Utter miscellany. Gosh, we should clean this up some time. */
601
602 SCM_PROC(s_input_port_p, "input-port?", 1, 0, 0, scm_input_port_p);
603
604 SCM
605 scm_input_port_p (SCM x)
606 {
607 if (SCM_IMP (x))
608 return SCM_BOOL_F;
609 return SCM_INPORTP (x) ? SCM_BOOL_T : SCM_BOOL_F;
610 }
611
612 SCM_PROC(s_output_port_p, "output-port?", 1, 0, 0, scm_output_port_p);
613
614 SCM
615 scm_output_port_p (SCM x)
616 {
617 if (SCM_IMP (x))
618 return SCM_BOOL_F;
619 if (SCM_PORT_WITH_PS_P (x))
620 x = SCM_PORT_WITH_PS_PORT (x);
621 return SCM_OUTPORTP (x) ? SCM_BOOL_T : SCM_BOOL_F;
622 }
623
624
625 SCM_PROC(s_eof_object_p, "eof-object?", 1, 0, 0, scm_eof_object_p);
626
627 SCM
628 scm_eof_object_p (SCM x)
629 {
630 return SCM_EOF_OBJECT_P (x) ? SCM_BOOL_T : SCM_BOOL_F;
631 }
632
633 SCM_PROC(s_force_output, "force-output", 0, 1, 0, scm_force_output);
634
635 SCM
636 scm_force_output (SCM port)
637 {
638 if (SCM_UNBNDP (port))
639 port = scm_cur_outp;
640 else
641 {
642 port = SCM_COERCE_OUTPORT (port);
643 SCM_ASSERT (SCM_NIMP (port) && SCM_OPOUTPORTP (port), port, SCM_ARG1,
644 s_force_output);
645 }
646 scm_flush (port);
647 return SCM_UNSPECIFIED;
648 }
649
650 SCM_PROC (s_flush_all_ports, "flush-all-ports", 0, 0, 0, scm_flush_all_ports);
651 SCM
652 scm_flush_all_ports ()
653 {
654 int i;
655
656 for (i = 0; i < scm_port_table_size; i++)
657 {
658 if (SCM_OPOUTPORTP (scm_port_table[i]->port))
659 scm_flush (scm_port_table[i]->port);
660 }
661 return SCM_UNSPECIFIED;
662 }
663
664 SCM_PROC(s_read_char, "read-char", 0, 1, 0, scm_read_char);
665
666 SCM
667 scm_read_char (SCM port)
668 {
669 int c;
670 if (SCM_UNBNDP (port))
671 port = scm_cur_inp;
672 else
673 SCM_ASSERT (SCM_NIMP (port) && SCM_OPINPORTP (port), port, SCM_ARG1, s_read_char);
674 c = scm_getc (port);
675 if (EOF == c)
676 return SCM_EOF_VAL;
677 return SCM_MAKICHR (c);
678 }
679
680 /* this should only be called when the read buffer is empty. it
681 tries to refill the read buffer. it returns the first char from
682 the port, which is either EOF or *(pt->read_pos). */
683 int
684 scm_fill_input (SCM port)
685 {
686 scm_port *pt = SCM_PTAB_ENTRY (port);
687
688 if (pt->read_buf == pt->putback_buf)
689 {
690 /* finished reading put-back chars. */
691 pt->read_buf = pt->saved_read_buf;
692 pt->read_pos = pt->saved_read_pos;
693 pt->read_end = pt->saved_read_end;
694 pt->read_buf_size = pt->saved_read_buf_size;
695 if (pt->read_pos < pt->read_end)
696 return *(pt->read_pos);
697 }
698 return scm_ptobs[SCM_PTOBNUM (port)].fill_input (port);
699 }
700
701 int
702 scm_getc (SCM port)
703 {
704 int c;
705 scm_port *pt = SCM_PTAB_ENTRY (port);
706
707 if (pt->rw_active == SCM_PORT_WRITE)
708 {
709 /* may be marginally faster than calling scm_flush. */
710 scm_ptobs[SCM_PTOBNUM (port)].flush (port);
711 }
712
713 if (pt->rw_random)
714 pt->rw_active = SCM_PORT_READ;
715
716 if (pt->read_pos >= pt->read_end)
717 {
718 if (scm_fill_input (port) == EOF)
719 return EOF;
720 }
721
722 c = *(pt->read_pos++);
723
724 if (c == '\n')
725 {
726 SCM_INCLINE (port);
727 }
728 else if (c == '\t')
729 {
730 SCM_TABCOL (port);
731 }
732 else
733 {
734 SCM_INCCOL (port);
735 }
736
737 return c;
738 }
739
740 void
741 scm_putc (char c, SCM port)
742 {
743 scm_lfwrite (&c, 1, port);
744 }
745
746 void
747 scm_puts (char *s, SCM port)
748 {
749 scm_lfwrite (s, strlen (s), port);
750 }
751
752 void
753 scm_lfwrite (char *ptr, scm_sizet size, SCM port)
754 {
755 scm_port *pt = SCM_PTAB_ENTRY (port);
756 scm_ptob_descriptor *ptob = &scm_ptobs[SCM_PTOBNUM (port)];
757
758 if (pt->rw_active == SCM_PORT_READ)
759 scm_end_input (port);
760
761 ptob->write (port, ptr, size);
762
763 if (pt->rw_random)
764 pt->rw_active = SCM_PORT_WRITE;
765 }
766
767
768 void
769 scm_flush (SCM port)
770 {
771 scm_sizet i = SCM_PTOBNUM (port);
772 (scm_ptobs[i].flush) (port);
773 }
774
775 void
776 scm_end_input (SCM port)
777 {
778 int offset;
779 scm_port *pt = SCM_PTAB_ENTRY (port);
780
781 if (pt->read_buf == pt->putback_buf)
782 {
783 offset = pt->read_end - pt->read_pos;
784 pt->read_buf = pt->saved_read_buf;
785 pt->read_pos = pt->saved_read_pos;
786 pt->read_end = pt->saved_read_end;
787 pt->read_buf_size = pt->saved_read_buf_size;
788 }
789 else
790 offset = 0;
791
792 scm_ptobs[SCM_PTOBNUM (port)].end_input (port, offset);
793 }
794
795 \f
796
797
798 void
799 scm_ungetc (int c, SCM port)
800 {
801 scm_port *pt = SCM_PTAB_ENTRY (port);
802
803 if (pt->read_buf == pt->putback_buf)
804 /* already using the put-back buffer. */
805 {
806 /* enlarge putback_buf if necessary. */
807 if (pt->read_end == pt->read_buf + pt->read_buf_size
808 && pt->read_buf == pt->read_pos)
809 {
810 int new_size = pt->read_buf_size * 2;
811 unsigned char *tmp =
812 (unsigned char *) realloc (pt->putback_buf, new_size);
813
814 if (tmp == NULL)
815 scm_memory_error ("scm_ungetc");
816 pt->read_pos = pt->read_buf = pt->putback_buf = tmp;
817 pt->read_end = pt->read_buf + pt->read_buf_size;
818 pt->read_buf_size = pt->putback_buf_size = new_size;
819 }
820
821 /* shift any existing bytes to buffer + 1. */
822 if (pt->read_pos == pt->read_end)
823 pt->read_end = pt->read_buf + 1;
824 else if (pt->read_pos != pt->read_buf + 1)
825 {
826 int count = pt->read_end - pt->read_pos;
827
828 memmove (pt->read_buf + 1, pt->read_pos, count);
829 pt->read_end = pt->read_buf + 1 + count;
830 }
831
832 pt->read_pos = pt->read_buf;
833 }
834 else
835 /* switch to the put-back buffer. */
836 {
837 if (pt->putback_buf == NULL)
838 {
839 pt->putback_buf = (char *) malloc (SCM_INITIAL_PUTBACK_BUF_SIZE);
840 if (pt->putback_buf == NULL)
841 scm_memory_error ("scm_ungetc");
842 pt->putback_buf_size = SCM_INITIAL_PUTBACK_BUF_SIZE;
843 }
844
845 pt->saved_read_buf = pt->read_buf;
846 pt->saved_read_pos = pt->read_pos;
847 pt->saved_read_end = pt->read_end;
848 pt->saved_read_buf_size = pt->read_buf_size;
849
850 pt->read_pos = pt->read_buf = pt->putback_buf;
851 pt->read_end = pt->read_buf + 1;
852 pt->read_buf_size = pt->putback_buf_size;
853 }
854
855 *pt->read_buf = c;
856
857 if (pt->rw_random)
858 pt->rw_active = SCM_PORT_READ;
859
860 if (c == '\n')
861 {
862 /* What should col be in this case?
863 * We'll leave it at -1.
864 */
865 SCM_LINUM (port) -= 1;
866 }
867 else
868 SCM_COL(port) -= 1;
869 }
870
871
872 void
873 scm_ungets (char *s, int n, SCM port)
874 {
875 /* This is simple minded and inefficient, but unreading strings is
876 * probably not a common operation, and remember that line and
877 * column numbers have to be handled...
878 *
879 * Please feel free to write an optimized version!
880 */
881 while (n--)
882 scm_ungetc (s[n], port);
883 }
884
885
886 SCM_PROC(s_peek_char, "peek-char", 0, 1, 0, scm_peek_char);
887
888 SCM
889 scm_peek_char (SCM port)
890 {
891 int c;
892 if (SCM_UNBNDP (port))
893 port = scm_cur_inp;
894 else
895 SCM_ASSERT (SCM_NIMP (port) && SCM_OPINPORTP (port), port, SCM_ARG1, s_peek_char);
896 c = scm_getc (port);
897 if (EOF == c)
898 return SCM_EOF_VAL;
899 scm_ungetc (c, port);
900 return SCM_MAKICHR (c);
901 }
902
903 SCM_PROC (s_unread_char, "unread-char", 2, 0, 0, scm_unread_char);
904
905 SCM
906 scm_unread_char (SCM cobj, SCM port)
907 {
908 int c;
909
910 SCM_ASSERT (SCM_ICHRP (cobj), cobj, SCM_ARG1, s_unread_char);
911
912 if (SCM_UNBNDP (port))
913 port = scm_cur_inp;
914 else
915 SCM_ASSERT (SCM_NIMP (port) && SCM_OPINPORTP (port), port, SCM_ARG2, s_unread_char);
916
917
918 c = SCM_ICHR (cobj);
919
920 scm_ungetc (c, port);
921 return cobj;
922 }
923
924 SCM_PROC (s_unread_string, "unread-string", 2, 0, 0, scm_unread_string);
925
926 SCM
927 scm_unread_string (SCM str, SCM port)
928 {
929 SCM_ASSERT (SCM_NIMP (str) && SCM_STRINGP (str),
930 str, SCM_ARG1, s_unread_string);
931
932 if (SCM_UNBNDP (port))
933 port = scm_cur_inp;
934 else
935 SCM_ASSERT (SCM_NIMP (port) && SCM_OPINPORTP (port),
936 port, SCM_ARG2, s_unread_string);
937
938 scm_ungets (SCM_ROUCHARS (str), SCM_LENGTH (str), port);
939
940 return str;
941 }
942
943 SCM_PROC (s_seek, "seek", 3, 0, 0, scm_seek);
944 SCM
945 scm_seek (SCM object, SCM offset, SCM whence)
946 {
947 off_t off;
948 off_t rv;
949 int how;
950
951 object = SCM_COERCE_OUTPORT (object);
952
953 off = scm_num2long (offset, (char *)SCM_ARG2, s_seek);
954 SCM_ASSERT (SCM_INUMP (whence), whence, SCM_ARG3, s_seek);
955 how = SCM_INUM (whence);
956 if (how != SEEK_SET && how != SEEK_CUR && how != SEEK_END)
957 scm_out_of_range (s_seek, whence);
958 if (SCM_NIMP (object) && SCM_OPPORTP (object))
959 {
960 scm_port *pt = SCM_PTAB_ENTRY (object);
961 scm_ptob_descriptor *ptob = scm_ptobs + SCM_PTOBNUM (object);
962
963 if (!ptob->seek)
964 scm_misc_error (s_seek, "port is not seekable",
965 scm_cons (object, SCM_EOL));
966 else
967 {
968 if (pt->rw_active == SCM_PORT_READ)
969 scm_end_input (object);
970 else if (pt->rw_active == SCM_PORT_WRITE)
971 ptob->flush (object);
972
973 rv = ptob->seek (object, off, how);
974 }
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
986 SCM_PROC (s_truncate_file, "truncate-file", 1, 1, 0, scm_truncate_file);
987
988 SCM
989 scm_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
1040 SCM_PROC (s_port_line, "port-line", 1, 0, 0, scm_port_line);
1041
1042 SCM
1043 scm_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
1053 SCM_PROC (s_set_port_line_x, "set-port-line!", 2, 0, 0, scm_set_port_line_x);
1054
1055 SCM
1056 scm_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
1067 SCM_PROC (s_port_column, "port-column", 1, 0, 0, scm_port_column);
1068
1069 SCM
1070 scm_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
1080 SCM_PROC (s_set_port_column_x, "set-port-column!", 2, 0, 0, scm_set_port_column_x);
1081
1082 SCM
1083 scm_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
1094 SCM_PROC (s_port_filename, "port-filename", 1, 0, 0, scm_port_filename);
1095
1096 SCM
1097 scm_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
1107 SCM_PROC (s_set_port_filename_x, "set-port-filename!", 2, 0, 0, scm_set_port_filename_x);
1108
1109 SCM
1110 scm_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
1122 extern char * ttyname();
1123 #endif
1124
1125 void
1126 scm_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
1140 int
1141 scm_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
1155 extern void scm_make_fptob ();
1156 extern void scm_make_stptob ();
1157 extern void scm_make_sfptob ();
1158
1159 void
1160 scm_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
1178 long scm_tc16_void_port = 0;
1179
1180 static void
1181 flush_void_port (SCM port)
1182 {
1183 }
1184
1185 static void
1186 end_input_void_port (SCM port, int offset)
1187 {
1188 }
1189
1190 static void
1191 write_void_port (SCM port, void *data, size_t size)
1192 {
1193 }
1194
1195 SCM
1196 scm_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
1214 SCM_PROC (s_sys_make_void_port, "%make-void-port", 1, 0, 0, scm_sys_make_void_port);
1215
1216 SCM
1217 scm_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
1229 void
1230 scm_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 }