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