* gh_data.c, ports.c, strop.c: Alternatively use bcopy if memmove
[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 #ifdef HAVE_MEMMOVE
829 memmove (pt->read_buf + 1, pt->read_pos, count);
830 #else
831 #ifdef HAVE_BCOPY
832 bcopy (pt->read_pos, pt->read_buf + 1, count);
833 #else
834 #error Need memmove. Please send a bug report to bug-guile@gnu.org.
835 #endif
836 #endif
837 pt->read_end = pt->read_buf + 1 + count;
838 }
839
840 pt->read_pos = pt->read_buf;
841 }
842 else
843 /* switch to the put-back buffer. */
844 {
845 if (pt->putback_buf == NULL)
846 {
847 pt->putback_buf = (char *) malloc (SCM_INITIAL_PUTBACK_BUF_SIZE);
848 if (pt->putback_buf == NULL)
849 scm_memory_error ("scm_ungetc");
850 pt->putback_buf_size = SCM_INITIAL_PUTBACK_BUF_SIZE;
851 }
852
853 pt->saved_read_buf = pt->read_buf;
854 pt->saved_read_pos = pt->read_pos;
855 pt->saved_read_end = pt->read_end;
856 pt->saved_read_buf_size = pt->read_buf_size;
857
858 pt->read_pos = pt->read_buf = pt->putback_buf;
859 pt->read_end = pt->read_buf + 1;
860 pt->read_buf_size = pt->putback_buf_size;
861 }
862
863 *pt->read_buf = c;
864
865 if (pt->rw_random)
866 pt->rw_active = SCM_PORT_READ;
867
868 if (c == '\n')
869 {
870 /* What should col be in this case?
871 * We'll leave it at -1.
872 */
873 SCM_LINUM (port) -= 1;
874 }
875 else
876 SCM_COL(port) -= 1;
877 }
878
879
880 void
881 scm_ungets (char *s, int n, SCM port)
882 {
883 /* This is simple minded and inefficient, but unreading strings is
884 * probably not a common operation, and remember that line and
885 * column numbers have to be handled...
886 *
887 * Please feel free to write an optimized version!
888 */
889 while (n--)
890 scm_ungetc (s[n], port);
891 }
892
893
894 SCM_PROC(s_peek_char, "peek-char", 0, 1, 0, scm_peek_char);
895
896 SCM
897 scm_peek_char (SCM port)
898 {
899 int c;
900 if (SCM_UNBNDP (port))
901 port = scm_cur_inp;
902 else
903 SCM_ASSERT (SCM_NIMP (port) && SCM_OPINPORTP (port), port, SCM_ARG1, s_peek_char);
904 c = scm_getc (port);
905 if (EOF == c)
906 return SCM_EOF_VAL;
907 scm_ungetc (c, port);
908 return SCM_MAKICHR (c);
909 }
910
911 SCM_PROC (s_unread_char, "unread-char", 2, 0, 0, scm_unread_char);
912
913 SCM
914 scm_unread_char (SCM cobj, SCM port)
915 {
916 int c;
917
918 SCM_ASSERT (SCM_ICHRP (cobj), cobj, SCM_ARG1, s_unread_char);
919
920 if (SCM_UNBNDP (port))
921 port = scm_cur_inp;
922 else
923 SCM_ASSERT (SCM_NIMP (port) && SCM_OPINPORTP (port), port, SCM_ARG2, s_unread_char);
924
925
926 c = SCM_ICHR (cobj);
927
928 scm_ungetc (c, port);
929 return cobj;
930 }
931
932 SCM_PROC (s_unread_string, "unread-string", 2, 0, 0, scm_unread_string);
933
934 SCM
935 scm_unread_string (SCM str, SCM port)
936 {
937 SCM_ASSERT (SCM_NIMP (str) && SCM_STRINGP (str),
938 str, SCM_ARG1, s_unread_string);
939
940 if (SCM_UNBNDP (port))
941 port = scm_cur_inp;
942 else
943 SCM_ASSERT (SCM_NIMP (port) && SCM_OPINPORTP (port),
944 port, SCM_ARG2, s_unread_string);
945
946 scm_ungets (SCM_ROUCHARS (str), SCM_LENGTH (str), port);
947
948 return str;
949 }
950
951 SCM_PROC (s_seek, "seek", 3, 0, 0, scm_seek);
952 SCM
953 scm_seek (SCM object, SCM offset, SCM whence)
954 {
955 off_t off;
956 off_t rv;
957 int how;
958
959 object = SCM_COERCE_OUTPORT (object);
960
961 off = scm_num2long (offset, (char *)SCM_ARG2, s_seek);
962 SCM_ASSERT (SCM_INUMP (whence), whence, SCM_ARG3, s_seek);
963 how = SCM_INUM (whence);
964 if (how != SEEK_SET && how != SEEK_CUR && how != SEEK_END)
965 scm_out_of_range (s_seek, whence);
966 if (SCM_NIMP (object) && SCM_OPPORTP (object))
967 {
968 scm_port *pt = SCM_PTAB_ENTRY (object);
969 scm_ptob_descriptor *ptob = scm_ptobs + SCM_PTOBNUM (object);
970
971 if (!ptob->seek)
972 scm_misc_error (s_seek, "port is not seekable",
973 scm_cons (object, SCM_EOL));
974 else
975 {
976 if (pt->rw_active == SCM_PORT_READ)
977 scm_end_input (object);
978 else if (pt->rw_active == SCM_PORT_WRITE)
979 ptob->flush (object);
980
981 rv = ptob->seek (object, off, how);
982 }
983 }
984 else /* file descriptor?. */
985 {
986 SCM_ASSERT (SCM_INUMP (object), object, SCM_ARG1, s_seek);
987 rv = lseek (SCM_INUM (object), off, how);
988 if (rv == -1)
989 scm_syserror (s_seek);
990 }
991 return scm_long2num (rv);
992 }
993
994 SCM_PROC (s_truncate_file, "truncate-file", 1, 1, 0, scm_truncate_file);
995
996 SCM
997 scm_truncate_file (SCM object, SCM length)
998 {
999 int rv;
1000 off_t c_length;
1001
1002 /* object can be a port, fdes or filename. */
1003
1004 if (SCM_UNBNDP (length))
1005 {
1006 /* must supply length if object is a filename. */
1007 if (SCM_NIMP (object) && SCM_ROSTRINGP (object))
1008 scm_wrong_num_args (scm_makfrom0str (s_truncate_file));
1009
1010 length = scm_seek (object, SCM_INUM0, SCM_MAKINUM (SEEK_CUR));
1011 }
1012 c_length = scm_num2long (length, (char *)SCM_ARG2, s_truncate_file);
1013 if (c_length < 0)
1014 scm_misc_error (s_truncate_file, "negative offset", SCM_EOL);
1015
1016 object = SCM_COERCE_OUTPORT (object);
1017 if (SCM_INUMP (object))
1018 {
1019 SCM_SYSCALL (rv = ftruncate (SCM_INUM (object), c_length));
1020 }
1021 else if (SCM_NIMP (object) && SCM_OPOUTPORTP (object))
1022 {
1023 scm_port *pt = SCM_PTAB_ENTRY (object);
1024 scm_ptob_descriptor *ptob = scm_ptobs + SCM_PTOBNUM (object);
1025
1026 if (!ptob->truncate)
1027 scm_misc_error (s_truncate_file, "port is not truncatable", SCM_EOL);
1028 if (pt->rw_active == SCM_PORT_READ)
1029 scm_end_input (object);
1030 else if (pt->rw_active == SCM_PORT_WRITE)
1031 ptob->flush (object);
1032
1033 ptob->truncate (object, c_length);
1034 rv = 0;
1035 }
1036 else
1037 {
1038 SCM_ASSERT (SCM_NIMP (object) && SCM_ROSTRINGP (object),
1039 object, SCM_ARG1, s_truncate_file);
1040 SCM_COERCE_SUBSTR (object);
1041 SCM_SYSCALL (rv = truncate (SCM_ROCHARS (object), c_length));
1042 }
1043 if (rv == -1)
1044 scm_syserror (s_truncate_file);
1045 return SCM_UNSPECIFIED;
1046 }
1047
1048 SCM_PROC (s_port_line, "port-line", 1, 0, 0, scm_port_line);
1049
1050 SCM
1051 scm_port_line (SCM port)
1052 {
1053 port = SCM_COERCE_OUTPORT (port);
1054 SCM_ASSERT (SCM_NIMP (port) && SCM_PORTP (port) && SCM_OPENP (port),
1055 port,
1056 SCM_ARG1,
1057 s_port_line);
1058 return SCM_MAKINUM (SCM_LINUM (port));
1059 }
1060
1061 SCM_PROC (s_set_port_line_x, "set-port-line!", 2, 0, 0, scm_set_port_line_x);
1062
1063 SCM
1064 scm_set_port_line_x (SCM port, SCM line)
1065 {
1066 port = SCM_COERCE_OUTPORT (port);
1067 SCM_ASSERT (SCM_NIMP (port) && SCM_PORTP (port) && SCM_OPENP (port),
1068 port,
1069 SCM_ARG1,
1070 s_set_port_line_x);
1071 SCM_ASSERT (SCM_INUMP (line), line, SCM_ARG2, s_set_port_line_x);
1072 return SCM_PTAB_ENTRY (port)->line_number = SCM_INUM (line);
1073 }
1074
1075 SCM_PROC (s_port_column, "port-column", 1, 0, 0, scm_port_column);
1076
1077 SCM
1078 scm_port_column (SCM port)
1079 {
1080 port = SCM_COERCE_OUTPORT (port);
1081 SCM_ASSERT (SCM_NIMP (port) && SCM_PORTP (port) && SCM_OPENP (port),
1082 port,
1083 SCM_ARG1,
1084 s_port_column);
1085 return SCM_MAKINUM (SCM_COL (port));
1086 }
1087
1088 SCM_PROC (s_set_port_column_x, "set-port-column!", 2, 0, 0, scm_set_port_column_x);
1089
1090 SCM
1091 scm_set_port_column_x (SCM port, SCM column)
1092 {
1093 port = SCM_COERCE_OUTPORT (port);
1094 SCM_ASSERT (SCM_NIMP (port) && SCM_PORTP (port) && SCM_OPENP (port),
1095 port,
1096 SCM_ARG1,
1097 s_set_port_column_x);
1098 SCM_ASSERT (SCM_INUMP (column), column, SCM_ARG2, s_set_port_column_x);
1099 return SCM_PTAB_ENTRY (port)->column_number = SCM_INUM (column);
1100 }
1101
1102 SCM_PROC (s_port_filename, "port-filename", 1, 0, 0, scm_port_filename);
1103
1104 SCM
1105 scm_port_filename (SCM port)
1106 {
1107 port = SCM_COERCE_OUTPORT (port);
1108 SCM_ASSERT (SCM_NIMP (port) && SCM_PORTP (port) && SCM_OPENP (port),
1109 port,
1110 SCM_ARG1,
1111 s_port_filename);
1112 return SCM_PTAB_ENTRY (port)->file_name;
1113 }
1114
1115 SCM_PROC (s_set_port_filename_x, "set-port-filename!", 2, 0, 0, scm_set_port_filename_x);
1116
1117 SCM
1118 scm_set_port_filename_x (SCM port, SCM filename)
1119 {
1120 port = SCM_COERCE_OUTPORT (port);
1121 SCM_ASSERT (SCM_NIMP (port) && SCM_PORTP (port) && SCM_OPENP (port),
1122 port,
1123 SCM_ARG1,
1124 s_set_port_filename_x);
1125 /* We allow the user to set the filename to whatever he likes. */
1126 return SCM_PTAB_ENTRY (port)->file_name = filename;
1127 }
1128
1129 #ifndef ttyname
1130 extern char * ttyname();
1131 #endif
1132
1133 void
1134 scm_print_port_mode (SCM exp, SCM port)
1135 {
1136 scm_puts (SCM_CLOSEDP (exp)
1137 ? "closed: "
1138 : (SCM_RDNG & SCM_CAR (exp)
1139 ? (SCM_WRTNG & SCM_CAR (exp)
1140 ? "input-output: "
1141 : "input: ")
1142 : (SCM_WRTNG & SCM_CAR (exp)
1143 ? "output: "
1144 : "bogus: ")),
1145 port);
1146 }
1147
1148 int
1149 scm_port_print (SCM exp, SCM port, scm_print_state *pstate)
1150 {
1151 char *type = SCM_PTOBNAME (SCM_PTOBNUM (exp));
1152 if (!type)
1153 type = "port";
1154 scm_puts ("#<", port);
1155 scm_print_port_mode (exp, port);
1156 scm_puts (type, port);
1157 scm_putc (' ', port);
1158 scm_intprint (SCM_CDR (exp), 16, port);
1159 scm_putc ('>', port);
1160 return 1;
1161 }
1162
1163 extern void scm_make_fptob ();
1164 extern void scm_make_stptob ();
1165 extern void scm_make_sfptob ();
1166
1167 void
1168 scm_ports_prehistory ()
1169 {
1170 scm_numptob = 0;
1171 scm_ptobs = (scm_ptob_descriptor *) malloc (sizeof (scm_ptob_descriptor));
1172
1173 /* WARNING: These scm_newptob calls must be done in this order.
1174 * They must agree with the port declarations in tags.h.
1175 */
1176 /* scm_tc16_fport = */ scm_make_fptob ();
1177 /* scm_tc16_pipe was here */ scm_make_fptob (); /* dummy. */
1178 /* scm_tc16_strport = */ scm_make_stptob ();
1179 /* scm_tc16_sfport = */ scm_make_sfptob ();
1180 }
1181
1182 \f
1183
1184 /* Void ports. */
1185
1186 long scm_tc16_void_port = 0;
1187
1188 static void
1189 flush_void_port (SCM port)
1190 {
1191 }
1192
1193 static void
1194 end_input_void_port (SCM port, int offset)
1195 {
1196 }
1197
1198 static void
1199 write_void_port (SCM port, void *data, size_t size)
1200 {
1201 }
1202
1203 SCM
1204 scm_void_port (char *mode_str)
1205 {
1206 int mode_bits;
1207 SCM answer;
1208 scm_port * pt;
1209
1210 SCM_NEWCELL (answer);
1211 SCM_DEFER_INTS;
1212 mode_bits = scm_mode_bits (mode_str);
1213 pt = scm_add_to_port_table (answer);
1214 SCM_SETPTAB_ENTRY (answer, pt);
1215 SCM_SETSTREAM (answer, 0);
1216 SCM_SETCAR (answer, scm_tc16_void_port | mode_bits);
1217 SCM_ALLOW_INTS;
1218 return answer;
1219 }
1220
1221
1222 SCM_PROC (s_sys_make_void_port, "%make-void-port", 1, 0, 0, scm_sys_make_void_port);
1223
1224 SCM
1225 scm_sys_make_void_port (SCM mode)
1226 {
1227 SCM_ASSERT (SCM_NIMP (mode) && SCM_ROSTRINGP (mode), mode,
1228 SCM_ARG1, s_sys_make_void_port);
1229
1230 SCM_COERCE_SUBSTR (mode);
1231 return scm_void_port (SCM_ROCHARS (mode));
1232 }
1233
1234 \f
1235 /* Initialization. */
1236
1237 void
1238 scm_init_ports ()
1239 {
1240 /* lseek() symbols. */
1241 scm_sysintern ("SEEK_SET", SCM_MAKINUM (SEEK_SET));
1242 scm_sysintern ("SEEK_CUR", SCM_MAKINUM (SEEK_CUR));
1243 scm_sysintern ("SEEK_END", SCM_MAKINUM (SEEK_END));
1244
1245 scm_tc16_void_port = scm_make_port_type ("void", 0, write_void_port);
1246 #include "ports.x"
1247 }