* Made the port implementations less tightly coupled within guile.
[bpt/guile.git] / libguile / ports.c
CommitLineData
7a754ca6 1/* Copyright (C) 1995,1996,1997,1998,1999, 2000 Free Software Foundation, Inc.
0f2d19dd
JB
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
82892bed
JB
15 * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
16 * Boston, MA 02111-1307 USA
0f2d19dd
JB
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.
82892bed 40 * If you do not wish that, delete this exception notice. */
1bbd0b84
GB
41
42/* Software engineering face-lift by Greg J. Badros, 11-Dec-1999,
43 gjb@cs.washington.edu, http://www.cs.washington.edu/homes/gjb */
44
0f2d19dd 45\f
d68fee48
JB
46/* Headers. */
47
0f2d19dd 48#include <stdio.h>
a0599745 49#include "libguile/_scm.h"
f0942910 50#include "libguile/eval.h"
a0599745
MD
51#include "libguile/objects.h"
52#include "libguile/smob.h"
53#include "libguile/chars.h"
0f2d19dd 54
a0599745
MD
55#include "libguile/keywords.h"
56#include "libguile/root.h"
57#include "libguile/strings.h"
20e6290e 58
a0599745
MD
59#include "libguile/validate.h"
60#include "libguile/ports.h"
0f2d19dd 61
bd9e24b3
GH
62#ifdef HAVE_STRING_H
63#include <string.h>
64#endif
65
0f2d19dd 66#ifdef HAVE_MALLOC_H
95b88819 67#include <malloc.h>
0f2d19dd
JB
68#endif
69
70#ifdef HAVE_UNISTD_H
71#include <unistd.h>
72#endif
73
95b88819
GH
74#ifdef HAVE_SYS_IOCTL_H
75#include <sys/ioctl.h>
76#endif
d68fee48 77
0f2d19dd 78\f
d68fee48 79/* The port kind table --- a dynamically resized array of port types. */
0f2d19dd
JB
80
81
82/* scm_ptobs scm_numptob
83 * implement a dynamicly resized array of ptob records.
84 * Indexes into this table are used when generating type
85 * tags for smobjects (if you know a tag you can get an index and conversely).
86 */
f12733c9 87scm_ptob_descriptor *scm_ptobs;
a1c95c45 88int scm_numptob;
0f2d19dd 89
ee149d03 90/* GC marker for a port with stream of SCM type. */
0f2d19dd 91SCM
a284e297 92scm_markstream (SCM ptr)
0f2d19dd
JB
93{
94 int openp;
f9a64404 95 openp = SCM_CELL_WORD_0 (ptr) & SCM_OPN;
0f2d19dd 96 if (openp)
74a16888 97 return SCM_PACK (SCM_STREAM (ptr));
0f2d19dd
JB
98 else
99 return SCM_BOOL_F;
100}
101
f12733c9 102/*
f12733c9 103 * We choose to use an interface similar to the smob interface with
affc96b5 104 * fill_input and write as standard fields, passed to the port
f12733c9
MD
105 * type constructor, and optional fields set by setters.
106 */
107
70df8af6
GH
108static void
109flush_port_default (SCM port)
110{
111}
112
113static void
114end_input_default (SCM port, int offset)
115{
116}
0f2d19dd 117
a98bddfd 118scm_bits_t
f12733c9 119scm_make_port_type (char *name,
affc96b5 120 int (*fill_input) (SCM port),
8aa011a1 121 void (*write) (SCM port, const void *data, size_t size))
0f2d19dd
JB
122{
123 char *tmp;
124 if (255 <= scm_numptob)
125 goto ptoberr;
f12733c9
MD
126 SCM_DEFER_INTS;
127 SCM_SYSCALL (tmp = (char *) realloc ((char *) scm_ptobs,
128 (1 + scm_numptob)
129 * sizeof (scm_ptob_descriptor)));
0f2d19dd
JB
130 if (tmp)
131 {
f12733c9 132 scm_ptobs = (scm_ptob_descriptor *) tmp;
affc96b5 133
f12733c9
MD
134 scm_ptobs[scm_numptob].name = name;
135 scm_ptobs[scm_numptob].mark = 0;
136 scm_ptobs[scm_numptob].free = scm_free0;
137 scm_ptobs[scm_numptob].print = scm_port_print;
138 scm_ptobs[scm_numptob].equalp = 0;
affc96b5
GH
139 scm_ptobs[scm_numptob].close = 0;
140
141 scm_ptobs[scm_numptob].write = write;
70df8af6 142 scm_ptobs[scm_numptob].flush = flush_port_default;
affc96b5 143
70df8af6 144 scm_ptobs[scm_numptob].end_input = end_input_default;
affc96b5
GH
145 scm_ptobs[scm_numptob].fill_input = fill_input;
146 scm_ptobs[scm_numptob].input_waiting = 0;
147
f12733c9 148 scm_ptobs[scm_numptob].seek = 0;
affc96b5
GH
149 scm_ptobs[scm_numptob].truncate = 0;
150
0f2d19dd
JB
151 scm_numptob++;
152 }
f12733c9 153 SCM_ALLOW_INTS;
0f2d19dd 154 if (!tmp)
2500356c
DH
155 {
156 ptoberr:
157 scm_memory_error ("scm_make_port_type");
158 }
f12733c9
MD
159 /* Make a class object if Goops is present */
160 if (scm_port_class)
161 scm_make_port_classes (scm_numptob - 1, SCM_PTOBNAME (scm_numptob - 1));
0f2d19dd
JB
162 return scm_tc7_port + (scm_numptob - 1) * 256;
163}
164
f12733c9 165void
6c747373 166scm_set_port_mark (long tc, SCM (*mark) (SCM))
f12733c9
MD
167{
168 scm_ptobs[SCM_TC2PTOBNUM (tc)].mark = mark;
169}
170
171void
6c747373 172scm_set_port_free (long tc, scm_sizet (*free) (SCM))
f12733c9
MD
173{
174 scm_ptobs[SCM_TC2PTOBNUM (tc)].free = free;
175}
176
177void
6c747373 178scm_set_port_print (long tc, int (*print) (SCM exp, SCM port,
f12733c9
MD
179 scm_print_state *pstate))
180{
181 scm_ptobs[SCM_TC2PTOBNUM (tc)].print = print;
182}
183
184void
6c747373 185scm_set_port_equalp (long tc, SCM (*equalp) (SCM, SCM))
f12733c9
MD
186{
187 scm_ptobs[SCM_TC2PTOBNUM (tc)].equalp = equalp;
188}
189
31703ab8 190void
affc96b5 191scm_set_port_flush (long tc, void (*flush) (SCM port))
31703ab8 192{
affc96b5 193 scm_ptobs[SCM_TC2PTOBNUM (tc)].flush = flush;
31703ab8
GH
194}
195
f12733c9 196void
affc96b5 197scm_set_port_end_input (long tc, void (*end_input) (SCM port, int offset))
f12733c9 198{
affc96b5 199 scm_ptobs[SCM_TC2PTOBNUM (tc)].end_input = end_input;
f12733c9
MD
200}
201
202void
6c747373 203scm_set_port_close (long tc, int (*close) (SCM))
f12733c9 204{
affc96b5 205 scm_ptobs[SCM_TC2PTOBNUM (tc)].close = close;
f12733c9
MD
206}
207
208void
6c747373 209scm_set_port_seek (long tc, off_t (*seek) (SCM port,
f12733c9
MD
210 off_t OFFSET,
211 int WHENCE))
212{
213 scm_ptobs[SCM_TC2PTOBNUM (tc)].seek = seek;
214}
215
216void
6c747373 217scm_set_port_truncate (long tc, void (*truncate) (SCM port, off_t length))
f12733c9 218{
affc96b5 219 scm_ptobs[SCM_TC2PTOBNUM (tc)].truncate = truncate;
f12733c9
MD
220}
221
222void
affc96b5 223scm_set_port_input_waiting (long tc, int (*input_waiting) (SCM))
f12733c9 224{
affc96b5 225 scm_ptobs[SCM_TC2PTOBNUM (tc)].input_waiting = input_waiting;
f12733c9
MD
226}
227
0f2d19dd 228\f
0f2d19dd 229
3b3b36dd 230SCM_DEFINE (scm_char_ready_p, "char-ready?", 0, 1, 0,
1bbd0b84 231 (SCM port),
bfc46627
GB
232 "Returns @code{#t} if a character is ready on input @var{port} and\n"
233 "returns @code{#f} otherwise. If @code{char-ready?} returns @code{#t}\n"
234 "then the next @code{read-char} operation on @var{port} is\n"
235 "guaranteed not to hang. If @var{port} is a file port at end of\n"
236 "file then @code{char-ready?} returns @code{#t}.\n"
237 "@footnote{@code{char-ready?} exists to make it possible for a\n"
238 "program to accept characters from interactive ports without getting\n"
239 "stuck waiting for input. Any input editors associated with such ports\n"
240 "must make sure that characters whose existence has been asserted by\n"
241 "@code{char-ready?} cannot be rubbed out. If @code{char-ready?} were to\n"
242 "return @code{#f} at end of file, a port at end of file would be\n"
243 "indistinguishable from an interactive port that has no ready\n"
244 "characters.}")
1bbd0b84 245#define FUNC_NAME s_scm_char_ready_p
0f2d19dd 246{
ae4c4016 247 scm_port *pt;
6c951427 248
0f2d19dd
JB
249 if (SCM_UNBNDP (port))
250 port = scm_cur_inp;
251 else
3b3b36dd 252 SCM_VALIDATE_OPINPORT (1,port);
d68fee48 253
ae4c4016
JB
254 pt = SCM_PTAB_ENTRY (port);
255
6c951427
GH
256 /* if the current read buffer is filled, or the
257 last pushed-back char has been read and the saved buffer is
258 filled, result is true. */
259 if (pt->read_pos < pt->read_end
260 || (pt->read_buf == pt->putback_buf
261 && pt->saved_read_pos < pt->saved_read_end))
0f2d19dd 262 return SCM_BOOL_T;
ee149d03
JB
263 else
264 {
f12733c9 265 scm_ptob_descriptor *ptob = &scm_ptobs[SCM_PTOBNUM (port)];
ee149d03 266
affc96b5 267 if (ptob->input_waiting)
1bbd0b84 268 return SCM_BOOL(ptob->input_waiting (port));
ee149d03 269 else
6c951427 270 return SCM_BOOL_T;
ee149d03 271 }
0f2d19dd 272}
1bbd0b84 273#undef FUNC_NAME
0f2d19dd 274
c2da2648
GH
275/* move up to read_len chars from port's putback and/or read buffers
276 into memory starting at dest. returns the number of chars moved. */
277size_t scm_take_from_input_buffers (SCM port, char *dest, size_t read_len)
278{
279 scm_port *pt = SCM_PTAB_ENTRY (port);
280 size_t chars_read = 0;
281 size_t from_buf = min (pt->read_end - pt->read_pos, read_len);
282
283 if (from_buf > 0)
284 {
285 memcpy (dest, pt->read_pos, from_buf);
286 pt->read_pos += from_buf;
287 chars_read += from_buf;
288 read_len -= from_buf;
289 dest += from_buf;
290 }
291
292 /* if putback was active, try the real input buffer too. */
293 if (pt->read_buf == pt->putback_buf)
294 {
295 from_buf = min (pt->saved_read_end - pt->saved_read_pos, read_len);
296 if (from_buf > 0)
297 {
298 memcpy (dest, pt->saved_read_pos, from_buf);
299 pt->saved_read_pos += from_buf;
300 chars_read += from_buf;
301 }
302 }
303 return chars_read;
304}
305
6c951427 306/* Clear a port's read buffers, returning the contents. */
a1ec6916 307SCM_DEFINE (scm_drain_input, "drain-input", 1, 0, 0,
1bbd0b84 308 (SCM port),
b380b885
MD
309 "Drains @var{PORT}'s read buffers (including any pushed-back characters)\n"
310 "and returns the contents as a single string.")
1bbd0b84 311#define FUNC_NAME s_scm_drain_input
ee149d03 312{
840ae05d
JB
313 SCM result;
314 scm_port *pt = SCM_PTAB_ENTRY (port);
6c951427 315 int count;
ee149d03 316
3b3b36dd 317 SCM_VALIDATE_OPINPORT (1,port);
840ae05d 318
6c951427
GH
319 count = pt->read_end - pt->read_pos;
320 if (pt->read_buf == pt->putback_buf)
321 count += pt->saved_read_end - pt->saved_read_pos;
840ae05d 322
6c951427 323 result = scm_makstr (count, 0);
c2da2648 324 scm_take_from_input_buffers (port, SCM_STRING_CHARS (result), count);
6c951427 325
840ae05d 326 return result;
ee149d03 327}
1bbd0b84 328#undef FUNC_NAME
0f2d19dd
JB
329
330\f
d68fee48 331/* Standard ports --- current input, output, error, and more(!). */
0f2d19dd 332
3b3b36dd 333SCM_DEFINE (scm_current_input_port, "current-input-port", 0, 0, 0,
1bbd0b84 334 (),
bfc46627
GB
335 "Returns the current input port. This is the default port used by many\n"
336 "input procedures. Initially, @code{current-input-port} returns the\n"
337 "value of @code{???}.")
1bbd0b84 338#define FUNC_NAME s_scm_current_input_port
0f2d19dd
JB
339{
340 return scm_cur_inp;
341}
1bbd0b84 342#undef FUNC_NAME
0f2d19dd 343
3b3b36dd 344SCM_DEFINE (scm_current_output_port, "current-output-port", 0, 0, 0,
1bbd0b84 345 (),
bfc46627
GB
346 "Returns the current output port. This is the default port used by many\n"
347 "output procedures. Initially, @code{current-output-port} returns the\n"
348 "value of @code{???}.")
1bbd0b84 349#define FUNC_NAME s_scm_current_output_port
0f2d19dd
JB
350{
351 return scm_cur_outp;
352}
1bbd0b84 353#undef FUNC_NAME
0f2d19dd 354
3b3b36dd 355SCM_DEFINE (scm_current_error_port, "current-error-port", 0, 0, 0,
1bbd0b84 356 (),
b380b885
MD
357 "Return the port to which errors and warnings should be sent (the\n"
358 "@dfn{standard error} in Unix and C terminology).")
1bbd0b84 359#define FUNC_NAME s_scm_current_error_port
0f2d19dd
JB
360{
361 return scm_cur_errp;
362}
1bbd0b84 363#undef FUNC_NAME
0f2d19dd 364
3b3b36dd 365SCM_DEFINE (scm_current_load_port, "current-load-port", 0, 0, 0,
1bbd0b84 366 (),
b450f070
GB
367 "Return the current-load-port.\n"
368 "The load port is used internally by `primitive-load'.")
1bbd0b84 369#define FUNC_NAME s_scm_current_load_port
31614d8e
MD
370{
371 return scm_cur_loadp;
372}
1bbd0b84 373#undef FUNC_NAME
31614d8e 374
3b3b36dd 375SCM_DEFINE (scm_set_current_input_port, "set-current-input-port", 1, 0, 0,
1bbd0b84 376 (SCM port),
b380b885
MD
377 "@deffnx primitive set-current-output-port port\n"
378 "@deffnx primitive set-current-error-port port\n"
379 "Change the ports returned by @code{current-input-port},\n"
380 "@code{current-output-port} and @code{current-error-port}, respectively,\n"
381 "so that they use the supplied @var{port} for input or output.")
1bbd0b84 382#define FUNC_NAME s_scm_set_current_input_port
0f2d19dd
JB
383{
384 SCM oinp = scm_cur_inp;
3b3b36dd 385 SCM_VALIDATE_OPINPORT (1,port);
0f2d19dd
JB
386 scm_cur_inp = port;
387 return oinp;
388}
1bbd0b84 389#undef FUNC_NAME
0f2d19dd
JB
390
391
3b3b36dd 392SCM_DEFINE (scm_set_current_output_port, "set-current-output-port", 1, 0, 0,
1bbd0b84 393 (SCM port),
b450f070 394 "Set the current default output port to PORT.")
1bbd0b84 395#define FUNC_NAME s_scm_set_current_output_port
0f2d19dd
JB
396{
397 SCM ooutp = scm_cur_outp;
78446828 398 port = SCM_COERCE_OUTPORT (port);
3b3b36dd 399 SCM_VALIDATE_OPOUTPORT (1,port);
0f2d19dd
JB
400 scm_cur_outp = port;
401 return ooutp;
402}
1bbd0b84 403#undef FUNC_NAME
0f2d19dd
JB
404
405
3b3b36dd 406SCM_DEFINE (scm_set_current_error_port, "set-current-error-port", 1, 0, 0,
1bbd0b84 407 (SCM port),
b450f070 408 "Set the current default error port to PORT.")
1bbd0b84 409#define FUNC_NAME s_scm_set_current_error_port
0f2d19dd
JB
410{
411 SCM oerrp = scm_cur_errp;
78446828 412 port = SCM_COERCE_OUTPORT (port);
3b3b36dd 413 SCM_VALIDATE_OPOUTPORT (1,port);
0f2d19dd
JB
414 scm_cur_errp = port;
415 return oerrp;
416}
1bbd0b84 417#undef FUNC_NAME
0f2d19dd
JB
418
419\f
840ae05d 420/* The port table --- an array of pointers to ports. */
0f2d19dd 421
840ae05d 422scm_port **scm_port_table;
0f2d19dd
JB
423
424int scm_port_table_size = 0; /* Number of ports in scm_port_table. */
425int scm_port_table_room = 20; /* Size of the array. */
426
ee149d03 427/* Add a port to the table. */
1cc91f1b 428
840ae05d 429scm_port *
a284e297 430scm_add_to_port_table (SCM port)
0f2d19dd 431{
840ae05d
JB
432 scm_port *entry;
433
0f2d19dd
JB
434 if (scm_port_table_size == scm_port_table_room)
435 {
ee149d03 436 void *newt = realloc ((char *) scm_port_table,
840ae05d 437 (scm_sizet) (sizeof (scm_port *)
ee149d03
JB
438 * scm_port_table_room * 2));
439 if (newt == NULL)
840ae05d
JB
440 scm_memory_error ("scm_add_to_port_table");
441 scm_port_table = (scm_port **) newt;
0f2d19dd
JB
442 scm_port_table_room *= 2;
443 }
840ae05d
JB
444 entry = (scm_port *) malloc (sizeof (scm_port));
445 if (entry == NULL)
446 scm_memory_error ("scm_add_to_port_table");
447
448 entry->port = port;
449 entry->entry = scm_port_table_size;
450 entry->revealed = 0;
451 entry->stream = 0;
452 entry->file_name = SCM_BOOL_F;
453 entry->line_number = 0;
454 entry->column_number = 0;
6c951427
GH
455 entry->putback_buf = 0;
456 entry->putback_buf_size = 0;
61e452ba 457 entry->rw_active = SCM_PORT_NEITHER;
0de97b83 458 entry->rw_random = 0;
840ae05d
JB
459
460 scm_port_table[scm_port_table_size] = entry;
461 scm_port_table_size++;
462
463 return entry;
0f2d19dd
JB
464}
465
6c951427 466/* Remove a port from the table and destroy it. */
1cc91f1b 467
0f2d19dd 468void
a284e297 469scm_remove_from_port_table (SCM port)
0f2d19dd 470{
840ae05d 471 scm_port *p = SCM_PTAB_ENTRY (port);
ee1e7e13 472 int i = p->entry;
6c951427 473
ee1e7e13
MD
474 if (i >= scm_port_table_size)
475 scm_wta (port, "Port not in table", "scm_remove_from_port_table");
6c951427
GH
476 if (p->putback_buf)
477 free (p->putback_buf);
840ae05d 478 free (p);
ee1e7e13
MD
479 /* Since we have just freed slot i we can shrink the table by moving
480 the last entry to that slot... */
481 if (i < scm_port_table_size - 1)
0f2d19dd 482 {
ee1e7e13
MD
483 scm_port_table[i] = scm_port_table[scm_port_table_size - 1];
484 scm_port_table[i]->entry = i;
0f2d19dd 485 }
0f2d19dd
JB
486 SCM_SETPTAB_ENTRY (port, 0);
487 scm_port_table_size--;
488}
489
fea6b4ea 490#ifdef GUILE_DEBUG
b450f070 491/* Functions for debugging. */
1cc91f1b 492
3b3b36dd 493SCM_DEFINE (scm_pt_size, "pt-size", 0, 0, 0,
b450f070
GB
494 (),
495 "Returns the number of ports in the port table.\n"
496 "`pt-size' is only included in GUILE_DEBUG builds.")
1bbd0b84 497#define FUNC_NAME s_scm_pt_size
0f2d19dd
JB
498{
499 return SCM_MAKINUM (scm_port_table_size);
500}
1bbd0b84 501#undef FUNC_NAME
0f2d19dd 502
3b3b36dd 503SCM_DEFINE (scm_pt_member, "pt-member", 1, 0, 0,
b450f070
GB
504 (SCM index),
505 "Returns the port at INDEX in the port table.\n"
506 "`pt-member' is only included in GUILE_DEBUG builds.")
1bbd0b84 507#define FUNC_NAME s_scm_pt_member
0f2d19dd
JB
508{
509 int i;
b450f070 510 SCM_VALIDATE_INUM_COPY (1,index,i);
0f2d19dd
JB
511 if (i < 0 || i >= scm_port_table_size)
512 return SCM_BOOL_F;
513 else
514 return scm_port_table[i]->port;
515}
1bbd0b84 516#undef FUNC_NAME
0f2d19dd
JB
517#endif
518
70df8af6
GH
519void
520scm_port_non_buffer (scm_port *pt)
521{
522 pt->read_pos = pt->read_buf = pt->read_end = &pt->shortbuf;
523 pt->write_buf = pt->write_pos = &pt->shortbuf;
524 pt->read_buf_size = pt->write_buf_size = 1;
525 pt->write_end = pt->write_buf + pt->write_buf_size;
526}
0f2d19dd 527
d68fee48
JB
528\f
529/* Revealed counts --- an oddity inherited from SCSH. */
530
8b13c6b3
GH
531/* Find a port in the table and return its revealed count.
532 Also used by the garbage collector.
0f2d19dd 533 */
1cc91f1b 534
0f2d19dd 535int
a284e297 536scm_revealed_count (SCM port)
0f2d19dd
JB
537{
538 return SCM_REVEALED(port);
539}
540
541
542
543/* Return the revealed count for a port. */
544
3b3b36dd 545SCM_DEFINE (scm_port_revealed, "port-revealed", 1, 0, 0,
1bbd0b84 546 (SCM port),
b380b885 547 "Returns the revealed count for @var{port}.")
1bbd0b84 548#define FUNC_NAME s_scm_port_revealed
0f2d19dd 549{
78446828 550 port = SCM_COERCE_OUTPORT (port);
3b3b36dd 551 SCM_VALIDATE_PORT (1,port);
8b13c6b3 552 return SCM_MAKINUM (scm_revealed_count (port));
0f2d19dd 553}
1bbd0b84 554#undef FUNC_NAME
0f2d19dd
JB
555
556/* Set the revealed count for a port. */
3b3b36dd 557SCM_DEFINE (scm_set_port_revealed_x, "set-port-revealed!", 2, 0, 0,
1bbd0b84 558 (SCM port, SCM rcount),
b450f070 559 "Sets the revealed count for a port to a given value.\n"
b380b885 560 "The return value is unspecified.")
1bbd0b84 561#define FUNC_NAME s_scm_set_port_revealed_x
0f2d19dd 562{
78446828 563 port = SCM_COERCE_OUTPORT (port);
3b3b36dd
GB
564 SCM_VALIDATE_PORT (1,port);
565 SCM_VALIDATE_INUM (2,rcount);
0f2d19dd 566 SCM_REVEALED (port) = SCM_INUM (rcount);
8b13c6b3 567 return SCM_UNSPECIFIED;
0f2d19dd 568}
1bbd0b84 569#undef FUNC_NAME
0f2d19dd 570
d68fee48
JB
571
572\f
573/* Retrieving a port's mode. */
574
eadd48de
GH
575/* Return the flags that characterize a port based on the mode
576 * string used to open a file for that port.
577 *
578 * See PORT FLAGS in scm.h
579 */
580
581long
a284e297 582scm_mode_bits (char *modes)
eadd48de
GH
583{
584 return (SCM_OPN
585 | (strchr (modes, 'r') || strchr (modes, '+') ? SCM_RDNG : 0)
586 | ( strchr (modes, 'w')
587 || strchr (modes, 'a')
588 || strchr (modes, '+') ? SCM_WRTNG : 0)
ee149d03
JB
589 | (strchr (modes, '0') ? SCM_BUF0 : 0)
590 | (strchr (modes, 'l') ? SCM_BUFLINE : 0));
eadd48de
GH
591}
592
593
594/* Return the mode flags from an open port.
595 * Some modes such as "append" are only used when opening
596 * a file and are not returned here. */
597
3b3b36dd 598SCM_DEFINE (scm_port_mode, "port-mode", 1, 0, 0,
1bbd0b84 599 (SCM port),
b380b885
MD
600 "Returns the port modes associated with the open port @var{port}. These\n"
601 "will not necessarily be identical to the modes used when the port was\n"
602 "opened, since modes such as \"append\" which are used only during\n"
603 "port creation are not retained.")
1bbd0b84 604#define FUNC_NAME s_scm_port_mode
eadd48de
GH
605{
606 char modes[3];
607 modes[0] = '\0';
78446828
MV
608
609 port = SCM_COERCE_OUTPORT (port);
3b3b36dd 610 SCM_VALIDATE_OPPORT (1,port);
f9a64404
DH
611 if (SCM_CELL_WORD_0 (port) & SCM_RDNG) {
612 if (SCM_CELL_WORD_0 (port) & SCM_WRTNG)
eadd48de
GH
613 strcpy (modes, "r+");
614 else
615 strcpy (modes, "r");
616 }
f9a64404 617 else if (SCM_CELL_WORD_0 (port) & SCM_WRTNG)
eadd48de 618 strcpy (modes, "w");
f9a64404 619 if (SCM_CELL_WORD_0 (port) & SCM_BUF0)
eadd48de
GH
620 strcat (modes, "0");
621 return scm_makfromstr (modes, strlen (modes), 0);
622}
1bbd0b84 623#undef FUNC_NAME
eadd48de
GH
624
625
d68fee48
JB
626\f
627/* Closing ports. */
628
0f2d19dd
JB
629/* scm_close_port
630 * Call the close operation on a port object.
eadd48de 631 * see also scm_close.
0f2d19dd 632 */
3b3b36dd 633SCM_DEFINE (scm_close_port, "close-port", 1, 0, 0,
1bbd0b84 634 (SCM port),
b380b885
MD
635 "Close the specified port object. Returns @code{#t} if it successfully\n"
636 "closes a port or @code{#f} if it was already\n"
637 "closed. An exception may be raised if an error occurs, for example\n"
638 "when flushing buffered output.\n"
639 "See also @ref{Ports and File Descriptors, close}, for a procedure\n"
640 "which can close file descriptors.")
1bbd0b84 641#define FUNC_NAME s_scm_close_port
0f2d19dd
JB
642{
643 scm_sizet i;
eadd48de
GH
644 int rv;
645
78446828
MV
646 port = SCM_COERCE_OUTPORT (port);
647
7a754ca6 648 SCM_VALIDATE_PORT (1, port);
0f2d19dd 649 if (SCM_CLOSEDP (port))
eadd48de 650 return SCM_BOOL_F;
0f2d19dd 651 i = SCM_PTOBNUM (port);
affc96b5
GH
652 if (scm_ptobs[i].close)
653 rv = (scm_ptobs[i].close) (port);
eadd48de
GH
654 else
655 rv = 0;
0f2d19dd 656 scm_remove_from_port_table (port);
898a256f 657 SCM_SETAND_CAR (port, ~SCM_OPN);
7a754ca6
MD
658 return SCM_NEGATE_BOOL (rv < 0);
659}
660#undef FUNC_NAME
661
662SCM_DEFINE (scm_close_input_port, "close-input-port", 1, 0, 0,
663 (SCM port),
664 "Close the specified input port object. The routine has no effect if\n"
665 "the file has already been closed. An exception may be raised if an\n"
666 "error occurs. The value returned is unspecified.\n\n"
667 "See also @ref{Ports and File Descriptors, close}, for a procedure\n"
668 "which can close file descriptors.")
669#define FUNC_NAME s_scm_close_input_port
670{
671 SCM_VALIDATE_INPUT_PORT (1, port);
672 scm_close_port (port);
673 return SCM_UNSPECIFIED;
674}
675#undef FUNC_NAME
676
677SCM_DEFINE (scm_close_output_port, "close-output-port", 1, 0, 0,
678 (SCM port),
679 "Close the specified output port object. The routine has no effect if\n"
680 "the file has already been closed. An exception may be raised if an\n"
681 "error occurs. The value returned is unspecified.\n\n"
682 "See also @ref{Ports and File Descriptors, close}, for a procedure\n"
683 "which can close file descriptors.")
684#define FUNC_NAME s_scm_close_output_port
685{
686 port = SCM_COERCE_OUTPORT (port);
687 SCM_VALIDATE_OUTPUT_PORT (1, port);
688 scm_close_port (port);
689 return SCM_UNSPECIFIED;
0f2d19dd 690}
1bbd0b84 691#undef FUNC_NAME
0f2d19dd 692
c2ca4493
GH
693SCM_DEFINE (scm_port_for_each, "port-for-each", 1, 0, 0,
694 (SCM proc),
695 "Apply @var{proc} to each port in the Guile port table\n"
696 "in turn. The return value is unspecified.")
697#define FUNC_NAME s_scm_port_for_each
698{
699 int i;
700 SCM_VALIDATE_PROC (1, proc);
701
702 /* when pre-emptive multithreading is supported, access to the port
703 table will need to be controlled by a mutex. */
704 SCM_DEFER_INTS;
705 for (i = 0; i < scm_port_table_size; i++)
706 {
707 scm_apply (proc, scm_cons (scm_port_table[i]->port, SCM_EOL), SCM_EOL);
708 }
709 return SCM_UNSPECIFIED;
710}
711#undef FUNC_NAME
712
b875c468
GH
713#if (SCM_DEBUG_DEPRECATED == 0)
714
3b3b36dd 715SCM_DEFINE (scm_close_all_ports_except, "close-all-ports-except", 0, 0, 1,
1bbd0b84 716 (SCM ports),
b875c468 717 "[DEPRECATED] Close all open file ports used by the interpreter\n"
b380b885 718 "except for those supplied as arguments. This procedure\n"
b875c468
GH
719 "was intended to be used before an exec call to close file descriptors\n"
720 "which are not needed in the new process. However it has the\n"
721 "undesirable side-effect of flushing buffes, so it's deprecated.\n"
722 "Use port-for-each instead.")
1bbd0b84 723#define FUNC_NAME s_scm_close_all_ports_except
0f2d19dd
JB
724{
725 int i = 0;
af45e3b0 726 SCM_VALIDATE_REST_ARGUMENT (ports);
0f2d19dd
JB
727 while (i < scm_port_table_size)
728 {
729 SCM thisport = scm_port_table[i]->port;
730 int found = 0;
731 SCM ports_ptr = ports;
732
733 while (SCM_NNULLP (ports_ptr))
734 {
78446828 735 SCM port = SCM_COERCE_OUTPORT (SCM_CAR (ports_ptr));
0f2d19dd 736 if (i == 0)
3b3b36dd 737 SCM_VALIDATE_OPPORT (SCM_ARG1,port);
54778cd3 738 if (SCM_EQ_P (port, thisport))
0f2d19dd
JB
739 found = 1;
740 ports_ptr = SCM_CDR (ports_ptr);
741 }
742 if (found)
743 i++;
744 else
745 /* i is not to be incremented here. */
746 scm_close_port (thisport);
747 }
0f2d19dd
JB
748 return SCM_UNSPECIFIED;
749}
1bbd0b84 750#undef FUNC_NAME
0f2d19dd 751
b875c468 752#endif
d68fee48
JB
753
754\f
755/* Utter miscellany. Gosh, we should clean this up some time. */
756
3b3b36dd 757SCM_DEFINE (scm_input_port_p, "input-port?", 1, 0, 0,
1bbd0b84 758 (SCM x),
bfc46627
GB
759 "Returns @code{#t} if @var{x} is an input port, otherwise returns\n"
760 "@code{#f}. Any object satisfying this predicate also satisfies\n"
761 "@code{port?}.")
1bbd0b84 762#define FUNC_NAME s_scm_input_port_p
0f2d19dd
JB
763{
764 if (SCM_IMP (x))
4a94d8ca 765 return SCM_BOOL_F;
f5f2dcff 766 return SCM_BOOL(SCM_INPUT_PORT_P (x));
0f2d19dd 767}
1bbd0b84 768#undef FUNC_NAME
0f2d19dd 769
3b3b36dd 770SCM_DEFINE (scm_output_port_p, "output-port?", 1, 0, 0,
1bbd0b84 771 (SCM x),
bfc46627
GB
772 "Returns @code{#t} if @var{x} is an output port, otherwise returns\n"
773 "@code{#f}. Any object satisfying this predicate also satisfies\n"
774 "@code{port?}.")
1bbd0b84 775#define FUNC_NAME s_scm_output_port_p
0f2d19dd
JB
776{
777 if (SCM_IMP (x))
4a94d8ca
MD
778 return SCM_BOOL_F;
779 if (SCM_PORT_WITH_PS_P (x))
780 x = SCM_PORT_WITH_PS_PORT (x);
f5f2dcff 781 return SCM_BOOL(SCM_OUTPUT_PORT_P (x));
0f2d19dd 782}
1bbd0b84 783#undef FUNC_NAME
0f2d19dd 784
eb5c0a2a
GH
785SCM_DEFINE (scm_port_p, "port?", 1, 0, 0,
786 (SCM x),
787 "Returns a boolean indicating whether @var{x} is a port.\n"
788 "Equivalent to @code{(or (input-port? X) (output-port? X))}.")
789#define FUNC_NAME s_scm_port_p
790{
791 return SCM_BOOL (SCM_PORTP (x));
792}
793#undef FUNC_NAME
794
3b3b36dd 795SCM_DEFINE (scm_port_closed_p, "port-closed?", 1, 0, 0,
1bbd0b84 796 (SCM port),
b380b885 797 "Returns @code{#t} if @var{port} is closed or @code{#f} if it is open.")
1bbd0b84 798#define FUNC_NAME s_scm_port_closed_p
60d0643d 799{
c1bfcf60 800 SCM_VALIDATE_PORT (1,port);
1bbd0b84 801 return SCM_NEGATE_BOOL(SCM_OPPORTP (port));
60d0643d 802}
1bbd0b84 803#undef FUNC_NAME
0f2d19dd 804
3b3b36dd 805SCM_DEFINE (scm_eof_object_p, "eof-object?", 1, 0, 0,
1bbd0b84 806 (SCM x),
bfc46627
GB
807 "Returns @code{#t} if @var{x} is an end-of-file object; otherwise\n"
808 "returns @code{#f}.")
1bbd0b84 809#define FUNC_NAME s_scm_eof_object_p
0f2d19dd 810{
1bbd0b84 811 return SCM_BOOL(SCM_EOF_OBJECT_P (x));
0f2d19dd 812}
1bbd0b84 813#undef FUNC_NAME
0f2d19dd 814
3b3b36dd 815SCM_DEFINE (scm_force_output, "force-output", 0, 1, 0,
1bbd0b84 816 (SCM port),
b380b885
MD
817 "Flush the specified output port, or the current output port if @var{port}\n"
818 "is omitted. The current output buffer contents are passed to the \n"
819 "underlying port implementation (e.g., in the case of fports, the\n"
820 "data will be written to the file and the output buffer will be cleared.)\n"
821 "It has no effect on an unbuffered port.\n\n"
822 "The return value is unspecified.")
1bbd0b84 823#define FUNC_NAME s_scm_force_output
0f2d19dd
JB
824{
825 if (SCM_UNBNDP (port))
3e877d15 826 port = scm_cur_outp;
0f2d19dd 827 else
78446828
MV
828 {
829 port = SCM_COERCE_OUTPORT (port);
3b3b36dd 830 SCM_VALIDATE_OPOUTPORT (1,port);
78446828 831 }
affc96b5 832 scm_flush (port);
ee149d03 833 return SCM_UNSPECIFIED;
0f2d19dd 834}
1bbd0b84 835#undef FUNC_NAME
0f2d19dd 836
a1ec6916 837SCM_DEFINE (scm_flush_all_ports, "flush-all-ports", 0, 0, 0,
1bbd0b84 838 (),
b380b885
MD
839 "Equivalent to calling @code{force-output} on\n"
840 "all open output ports. The return value is unspecified.")
1bbd0b84 841#define FUNC_NAME s_scm_flush_all_ports
89ea5b7c
GH
842{
843 int i;
844
845 for (i = 0; i < scm_port_table_size; i++)
846 {
ee149d03 847 if (SCM_OPOUTPORTP (scm_port_table[i]->port))
affc96b5 848 scm_flush (scm_port_table[i]->port);
89ea5b7c
GH
849 }
850 return SCM_UNSPECIFIED;
851}
1bbd0b84 852#undef FUNC_NAME
0f2d19dd 853
3b3b36dd 854SCM_DEFINE (scm_read_char, "read-char", 0, 1, 0,
1bbd0b84 855 (SCM port),
bfc46627
GB
856 "Returns the next character available from @var{port}, updating\n"
857 "@var{port} to point to the following character. If no more\n"
858 "characters are available, an end-of-file object is returned.")
1bbd0b84 859#define FUNC_NAME s_scm_read_char
0f2d19dd
JB
860{
861 int c;
862 if (SCM_UNBNDP (port))
334341aa 863 port = scm_cur_inp;
3b3b36dd 864 SCM_VALIDATE_OPINPORT (1,port);
b7f3516f 865 c = scm_getc (port);
0f2d19dd
JB
866 if (EOF == c)
867 return SCM_EOF_VAL;
7866a09b 868 return SCM_MAKE_CHAR (c);
0f2d19dd 869}
1bbd0b84 870#undef FUNC_NAME
0f2d19dd 871
5c070ca7 872/* this should only be called when the read buffer is empty. it
affc96b5 873 tries to refill the read buffer. it returns the first char from
5c070ca7 874 the port, which is either EOF or *(pt->read_pos). */
6c951427 875int
affc96b5 876scm_fill_input (SCM port)
6c951427 877{
283a1a0e
GH
878 scm_port *pt = SCM_PTAB_ENTRY (port);
879
6c951427
GH
880 if (pt->read_buf == pt->putback_buf)
881 {
882 /* finished reading put-back chars. */
883 pt->read_buf = pt->saved_read_buf;
884 pt->read_pos = pt->saved_read_pos;
885 pt->read_end = pt->saved_read_end;
886 pt->read_buf_size = pt->saved_read_buf_size;
887 if (pt->read_pos < pt->read_end)
5c070ca7 888 return *(pt->read_pos);
6c951427 889 }
affc96b5 890 return scm_ptobs[SCM_PTOBNUM (port)].fill_input (port);
6c951427
GH
891}
892
ee149d03 893int
a284e297 894scm_getc (SCM port)
0f2d19dd
JB
895{
896 int c;
840ae05d 897 scm_port *pt = SCM_PTAB_ENTRY (port);
ee149d03 898
840ae05d
JB
899 if (pt->rw_active == SCM_PORT_WRITE)
900 {
affc96b5
GH
901 /* may be marginally faster than calling scm_flush. */
902 scm_ptobs[SCM_PTOBNUM (port)].flush (port);
840ae05d 903 }
6c951427 904
5c070ca7
GH
905 if (pt->rw_random)
906 pt->rw_active = SCM_PORT_READ;
907
908 if (pt->read_pos >= pt->read_end)
ee149d03 909 {
affc96b5 910 if (scm_fill_input (port) == EOF)
5c070ca7 911 return EOF;
ee149d03
JB
912 }
913
5c070ca7 914 c = *(pt->read_pos++);
840ae05d 915
ee149d03
JB
916 if (c == '\n')
917 {
918 SCM_INCLINE (port);
919 }
920 else if (c == '\t')
921 {
922 SCM_TABCOL (port);
923 }
924 else
925 {
926 SCM_INCCOL (port);
927 }
928
929 return c;
0f2d19dd
JB
930}
931
ee149d03 932void
a284e297 933scm_putc (char c, SCM port)
ee149d03 934{
265e6a4d 935 scm_lfwrite (&c, 1, port);
ee149d03 936}
3cb988bd 937
ee149d03 938void
70d63753 939scm_puts (const char *s, SCM port)
3cb988bd 940{
265e6a4d 941 scm_lfwrite (s, strlen (s), port);
ee149d03 942}
3cb988bd 943
ee149d03 944void
70d63753 945scm_lfwrite (const char *ptr, scm_sizet size, SCM port)
ee149d03 946{
840ae05d 947 scm_port *pt = SCM_PTAB_ENTRY (port);
f12733c9 948 scm_ptob_descriptor *ptob = &scm_ptobs[SCM_PTOBNUM (port)];
3e2043c4 949
840ae05d 950 if (pt->rw_active == SCM_PORT_READ)
affc96b5 951 scm_end_input (port);
283a1a0e 952
31703ab8 953 ptob->write (port, ptr, size);
840ae05d
JB
954
955 if (pt->rw_random)
956 pt->rw_active = SCM_PORT_WRITE;
ee149d03 957}
3cb988bd 958
3cb988bd 959
ee149d03 960void
a284e297 961scm_flush (SCM port)
ee149d03
JB
962{
963 scm_sizet i = SCM_PTOBNUM (port);
affc96b5 964 (scm_ptobs[i].flush) (port);
ee149d03
JB
965}
966
283a1a0e 967void
a284e297 968scm_end_input (SCM port)
283a1a0e
GH
969{
970 int offset;
971 scm_port *pt = SCM_PTAB_ENTRY (port);
972
973 if (pt->read_buf == pt->putback_buf)
974 {
975 offset = pt->read_end - pt->read_pos;
976 pt->read_buf = pt->saved_read_buf;
977 pt->read_pos = pt->saved_read_pos;
978 pt->read_end = pt->saved_read_end;
979 pt->read_buf_size = pt->saved_read_buf_size;
980 }
981 else
982 offset = 0;
983
affc96b5 984 scm_ptobs[SCM_PTOBNUM (port)].end_input (port, offset);
283a1a0e
GH
985}
986
ee149d03
JB
987\f
988
989
990void
a284e297 991scm_ungetc (int c, SCM port)
ee149d03 992{
840ae05d
JB
993 scm_port *pt = SCM_PTAB_ENTRY (port);
994
6c951427
GH
995 if (pt->read_buf == pt->putback_buf)
996 /* already using the put-back buffer. */
997 {
998 /* enlarge putback_buf if necessary. */
999 if (pt->read_end == pt->read_buf + pt->read_buf_size
1000 && pt->read_buf == pt->read_pos)
1001 {
1002 int new_size = pt->read_buf_size * 2;
1003 unsigned char *tmp =
1004 (unsigned char *) realloc (pt->putback_buf, new_size);
1005
1006 if (tmp == NULL)
1007 scm_memory_error ("scm_ungetc");
1008 pt->read_pos = pt->read_buf = pt->putback_buf = tmp;
1009 pt->read_end = pt->read_buf + pt->read_buf_size;
1010 pt->read_buf_size = pt->putback_buf_size = new_size;
1011 }
1012
1013 /* shift any existing bytes to buffer + 1. */
1014 if (pt->read_pos == pt->read_end)
1015 pt->read_end = pt->read_buf + 1;
1016 else if (pt->read_pos != pt->read_buf + 1)
1017 {
1018 int count = pt->read_end - pt->read_pos;
1019
1020 memmove (pt->read_buf + 1, pt->read_pos, count);
1021 pt->read_end = pt->read_buf + 1 + count;
1022 }
1023
1024 pt->read_pos = pt->read_buf;
1025 }
1026 else
1027 /* switch to the put-back buffer. */
1028 {
1029 if (pt->putback_buf == NULL)
1030 {
c357d546
MD
1031 pt->putback_buf
1032 = (unsigned char *) malloc (SCM_INITIAL_PUTBACK_BUF_SIZE);
6c951427
GH
1033 if (pt->putback_buf == NULL)
1034 scm_memory_error ("scm_ungetc");
1035 pt->putback_buf_size = SCM_INITIAL_PUTBACK_BUF_SIZE;
1036 }
1037
1038 pt->saved_read_buf = pt->read_buf;
1039 pt->saved_read_pos = pt->read_pos;
1040 pt->saved_read_end = pt->read_end;
1041 pt->saved_read_buf_size = pt->read_buf_size;
1042
1043 pt->read_pos = pt->read_buf = pt->putback_buf;
1044 pt->read_end = pt->read_buf + 1;
1045 pt->read_buf_size = pt->putback_buf_size;
1046 }
1047
1048 *pt->read_buf = c;
ee149d03 1049
840ae05d
JB
1050 if (pt->rw_random)
1051 pt->rw_active = SCM_PORT_READ;
1052
ee149d03
JB
1053 if (c == '\n')
1054 {
1055 /* What should col be in this case?
1056 * We'll leave it at -1.
1057 */
1058 SCM_LINUM (port) -= 1;
1059 }
1060 else
1061 SCM_COL(port) -= 1;
1062}
1063
1064
1065void
70d63753 1066scm_ungets (const char *s, int n, SCM port)
ee149d03
JB
1067{
1068 /* This is simple minded and inefficient, but unreading strings is
1069 * probably not a common operation, and remember that line and
1070 * column numbers have to be handled...
1071 *
1072 * Please feel free to write an optimized version!
1073 */
1074 while (n--)
1075 scm_ungetc (s[n], port);
1076}
1077
1078
3b3b36dd 1079SCM_DEFINE (scm_peek_char, "peek-char", 0, 1, 0,
1bbd0b84 1080 (SCM port),
bfc46627
GB
1081 "Returns the next character available from @var{port},\n"
1082 "@emph{without} updating @var{port} to point to the following\n"
1083 "character. If no more characters are available, an end-of-file object\n"
1084 "is returned.@footnote{The value returned by a call to @code{peek-char}\n"
1085 "is the same as the value that would have been returned by a call to\n"
1086 "@code{read-char} on the same port. The only difference is that the very\n"
1087 "next call to @code{read-char} or @code{peek-char} on that\n"
1088 "@var{port} will return the value returned by the preceding call to\n"
1089 "@code{peek-char}. In particular, a call to @code{peek-char} on an\n"
1090 "interactive port will hang waiting for input whenever a call to\n"
1091 "@code{read-char} would have hung.}")
1bbd0b84 1092#define FUNC_NAME s_scm_peek_char
ee149d03
JB
1093{
1094 int c;
1095 if (SCM_UNBNDP (port))
1096 port = scm_cur_inp;
1097 else
3b3b36dd 1098 SCM_VALIDATE_OPINPORT (1,port);
ee149d03
JB
1099 c = scm_getc (port);
1100 if (EOF == c)
1101 return SCM_EOF_VAL;
1102 scm_ungetc (c, port);
7866a09b 1103 return SCM_MAKE_CHAR (c);
3cb988bd 1104}
1bbd0b84 1105#undef FUNC_NAME
3cb988bd 1106
a1ec6916 1107SCM_DEFINE (scm_unread_char, "unread-char", 2, 0, 0,
1bbd0b84 1108 (SCM cobj, SCM port),
b380b885
MD
1109 "Place @var{char} in @var{port} so that it will be read by the\n"
1110 "next read operation. If called multiple times, the unread characters\n"
1111 "will be read again in last-in first-out order. If @var{port} is\n"
1112 "not supplied, the current input port is used.")
1bbd0b84 1113#define FUNC_NAME s_scm_unread_char
0f2d19dd
JB
1114{
1115 int c;
1116
7866a09b 1117 SCM_VALIDATE_CHAR (1,cobj);
0f2d19dd
JB
1118 if (SCM_UNBNDP (port))
1119 port = scm_cur_inp;
1120 else
3b3b36dd 1121 SCM_VALIDATE_OPINPORT (2,port);
0f2d19dd 1122
7866a09b 1123 c = SCM_CHAR (cobj);
0f2d19dd 1124
b7f3516f 1125 scm_ungetc (c, port);
0f2d19dd
JB
1126 return cobj;
1127}
1bbd0b84 1128#undef FUNC_NAME
0f2d19dd 1129
a1ec6916 1130SCM_DEFINE (scm_unread_string, "unread-string", 2, 0, 0,
1bbd0b84 1131 (SCM str, SCM port),
b380b885
MD
1132 "Place the string @var{str} in @var{port} so that its characters will be\n"
1133 "read in subsequent read operations. If called multiple times, the\n"
1134 "unread characters will be read again in last-in first-out order. If\n"
1135 "@var{port} is not supplied, the current-input-port is used.")
1bbd0b84 1136#define FUNC_NAME s_scm_unread_string
ee1e7e13 1137{
3b3b36dd 1138 SCM_VALIDATE_STRING (1,str);
ee1e7e13
MD
1139 if (SCM_UNBNDP (port))
1140 port = scm_cur_inp;
1141 else
3b3b36dd 1142 SCM_VALIDATE_OPINPORT (2,port);
ee1e7e13 1143
34f0f2b8 1144 scm_ungets (SCM_STRING_CHARS (str), SCM_STRING_LENGTH (str), port);
ee1e7e13
MD
1145
1146 return str;
1147}
1bbd0b84 1148#undef FUNC_NAME
ee1e7e13 1149
a1ec6916 1150SCM_DEFINE (scm_seek, "seek", 3, 0, 0,
1bbd0b84 1151 (SCM object, SCM offset, SCM whence),
b380b885
MD
1152 "Sets the current position of @var{fd/port} to the integer @var{offset},\n"
1153 "which is interpreted according to the value of @var{whence}.\n\n"
1154 "One of the following variables should be supplied\n"
1155 "for @var{whence}:\n"
1156 "@defvar SEEK_SET\n"
1157 "Seek from the beginning of the file.\n"
1158 "@end defvar\n"
1159 "@defvar SEEK_CUR\n"
1160 "Seek from the current position.\n"
1161 "@end defvar\n"
1162 "@defvar SEEK_END\n"
1163 "Seek from the end of the file.\n"
1164 "@end defvar\n\n"
1165 "If @var{fd/port} is a file descriptor, the underlying system call is\n"
1166 "@code{lseek}. @var{port} may be a string port.\n\n"
1167 "The value returned is the new position in the file. This means that\n"
1168 "the current position of a port can be obtained using:\n"
1169 "@smalllisp\n"
1170 "(seek port 0 SEEK_CUR)\n"
1171 "@end smalllisp")
1bbd0b84 1172#define FUNC_NAME s_scm_seek
840ae05d
JB
1173{
1174 off_t off;
1175 off_t rv;
1176 int how;
1177
1178 object = SCM_COERCE_OUTPORT (object);
1179
1bbd0b84 1180 off = SCM_NUM2LONG (2,offset);
3b3b36dd 1181 SCM_VALIDATE_INUM_COPY (3,whence,how);
840ae05d 1182 if (how != SEEK_SET && how != SEEK_CUR && how != SEEK_END)
1bbd0b84 1183 SCM_OUT_OF_RANGE (3, whence);
0c95b57d 1184 if (SCM_OPPORTP (object))
840ae05d 1185 {
f12733c9 1186 scm_ptob_descriptor *ptob = scm_ptobs + SCM_PTOBNUM (object);
840ae05d
JB
1187
1188 if (!ptob->seek)
1bbd0b84
GB
1189 SCM_MISC_ERROR ("port is not seekable",
1190 scm_cons (object, SCM_EOL));
840ae05d 1191 else
7dcb364d 1192 rv = ptob->seek (object, off, how);
840ae05d
JB
1193 }
1194 else /* file descriptor?. */
1195 {
3b3b36dd 1196 SCM_VALIDATE_INUM (1,object);
840ae05d
JB
1197 rv = lseek (SCM_INUM (object), off, how);
1198 if (rv == -1)
1bbd0b84 1199 SCM_SYSERROR;
840ae05d
JB
1200 }
1201 return scm_long2num (rv);
1202}
1bbd0b84 1203#undef FUNC_NAME
840ae05d 1204
a1ec6916 1205SCM_DEFINE (scm_truncate_file, "truncate-file", 1, 1, 0,
1bbd0b84 1206 (SCM object, SCM length),
b380b885
MD
1207 "Truncates the object referred to by @var{obj} to at most @var{size} bytes.\n"
1208 "@var{obj} can be a string containing a file name or an integer file\n"
1209 "descriptor or a port. @var{size} may be omitted if @var{obj} is not\n"
1210 "a file name, in which case the truncation occurs at the current port.\n"
1211 "position.\n\n"
1212 "The return value is unspecified.")
1bbd0b84 1213#define FUNC_NAME s_scm_truncate_file
840ae05d 1214{
69bc9ff3
GH
1215 int rv;
1216 off_t c_length;
1217
1218 /* object can be a port, fdes or filename. */
840ae05d 1219
840ae05d
JB
1220 if (SCM_UNBNDP (length))
1221 {
69bc9ff3 1222 /* must supply length if object is a filename. */
a6d9e5ab 1223 if (SCM_STRINGP (object))
c1bfcf60 1224 SCM_MISC_ERROR("must supply length if OBJECT is a filename",SCM_EOL);
69bc9ff3 1225
c94577b4 1226 length = scm_seek (object, SCM_INUM0, SCM_MAKINUM (SEEK_CUR));
840ae05d 1227 }
1bbd0b84 1228 c_length = SCM_NUM2LONG (2,length);
69bc9ff3 1229 if (c_length < 0)
1bbd0b84 1230 SCM_MISC_ERROR ("negative offset", SCM_EOL);
3fe6190f 1231
69bc9ff3
GH
1232 object = SCM_COERCE_OUTPORT (object);
1233 if (SCM_INUMP (object))
1234 {
1235 SCM_SYSCALL (rv = ftruncate (SCM_INUM (object), c_length));
1236 }
0c95b57d 1237 else if (SCM_OPOUTPORTP (object))
69bc9ff3
GH
1238 {
1239 scm_port *pt = SCM_PTAB_ENTRY (object);
f12733c9 1240 scm_ptob_descriptor *ptob = scm_ptobs + SCM_PTOBNUM (object);
69bc9ff3 1241
affc96b5 1242 if (!ptob->truncate)
1bbd0b84 1243 SCM_MISC_ERROR ("port is not truncatable", SCM_EOL);
69bc9ff3 1244 if (pt->rw_active == SCM_PORT_READ)
affc96b5 1245 scm_end_input (object);
69bc9ff3 1246 else if (pt->rw_active == SCM_PORT_WRITE)
affc96b5 1247 ptob->flush (object);
69bc9ff3 1248
affc96b5 1249 ptob->truncate (object, c_length);
69bc9ff3
GH
1250 rv = 0;
1251 }
1252 else
1253 {
a6d9e5ab
DH
1254 SCM_VALIDATE_STRING (1, object);
1255 SCM_STRING_COERCE_0TERMINATION_X (object);
1256 SCM_SYSCALL (rv = truncate (SCM_STRING_CHARS (object), c_length));
69bc9ff3
GH
1257 }
1258 if (rv == -1)
1bbd0b84 1259 SCM_SYSERROR;
840ae05d
JB
1260 return SCM_UNSPECIFIED;
1261}
1bbd0b84 1262#undef FUNC_NAME
840ae05d 1263
a1ec6916 1264SCM_DEFINE (scm_port_line, "port-line", 1, 0, 0,
1bbd0b84 1265 (SCM port),
b450f070 1266 "Return the current line number for PORT.")
1bbd0b84 1267#define FUNC_NAME s_scm_port_line
0f2d19dd 1268{
78446828 1269 port = SCM_COERCE_OUTPORT (port);
3b3b36dd 1270 SCM_VALIDATE_OPENPORT (1,port);
360fc44c 1271 return SCM_MAKINUM (SCM_LINUM (port));
0f2d19dd 1272}
1bbd0b84 1273#undef FUNC_NAME
0f2d19dd 1274
a1ec6916 1275SCM_DEFINE (scm_set_port_line_x, "set-port-line!", 2, 0, 0,
1bbd0b84 1276 (SCM port, SCM line),
b450f070 1277 "Set the current line number for PORT to LINE.")
1bbd0b84 1278#define FUNC_NAME s_scm_set_port_line_x
d043d8c2 1279{
360fc44c 1280 port = SCM_COERCE_OUTPORT (port);
3b3b36dd
GB
1281 SCM_VALIDATE_OPENPORT (1,port);
1282 SCM_VALIDATE_INUM (2,line);
564478fd
GB
1283 SCM_PTAB_ENTRY (port)->line_number = SCM_INUM (line);
1284 return SCM_UNSPECIFIED;
d043d8c2 1285}
1bbd0b84 1286#undef FUNC_NAME
d043d8c2 1287
a1ec6916 1288SCM_DEFINE (scm_port_column, "port-column", 1, 0, 0,
1bbd0b84 1289 (SCM port),
b380b885
MD
1290 "@deffnx primitive port-line [input-port]\n"
1291 "Return the current column number or line number of @var{input-port},\n"
1292 "using the current input port if none is specified. If the number is\n"
1293 "unknown, the result is #f. Otherwise, the result is a 0-origin integer\n"
1294 "- i.e. the first character of the first line is line 0, column 0.\n"
1295 "(However, when you display a file position, for example in an error\n"
1296 "message, we recommand you add 1 to get 1-origin integers. This is\n"
1297 "because lines and column numbers traditionally start with 1, and that is\n"
1298 "what non-programmers will find most natural.)")
1bbd0b84 1299#define FUNC_NAME s_scm_port_column
0f2d19dd 1300{
78446828 1301 port = SCM_COERCE_OUTPORT (port);
3b3b36dd 1302 SCM_VALIDATE_OPENPORT (1,port);
360fc44c 1303 return SCM_MAKINUM (SCM_COL (port));
0f2d19dd 1304}
1bbd0b84 1305#undef FUNC_NAME
0f2d19dd 1306
a1ec6916 1307SCM_DEFINE (scm_set_port_column_x, "set-port-column!", 2, 0, 0,
1bbd0b84 1308 (SCM port, SCM column),
92ccc1f1
NJ
1309 "@deffnx primitive set-port-line! port line\n"
1310 "Set the current column or line number of @var{port}, using the\n"
b380b885 1311 "current input port if none is specified.")
1bbd0b84 1312#define FUNC_NAME s_scm_set_port_column_x
d043d8c2 1313{
360fc44c 1314 port = SCM_COERCE_OUTPORT (port);
3b3b36dd
GB
1315 SCM_VALIDATE_OPENPORT (1,port);
1316 SCM_VALIDATE_INUM (2,column);
564478fd
GB
1317 SCM_PTAB_ENTRY (port)->column_number = SCM_INUM (column);
1318 return SCM_UNSPECIFIED;
d043d8c2 1319}
1bbd0b84 1320#undef FUNC_NAME
d043d8c2 1321
a1ec6916 1322SCM_DEFINE (scm_port_filename, "port-filename", 1, 0, 0,
1bbd0b84 1323 (SCM port),
b380b885 1324 "Return the filename associated with @var{port}. This function returns\n"
2a2a730b 1325 "the strings \"standard input\", \"standard output\" and \"standard error\"\n"
a3c8b9fc 1326 "when called on the current input, output and error ports respectively.")
1bbd0b84 1327#define FUNC_NAME s_scm_port_filename
0f2d19dd 1328{
78446828 1329 port = SCM_COERCE_OUTPORT (port);
3b3b36dd 1330 SCM_VALIDATE_OPENPORT (1,port);
b24b5e13 1331 return SCM_FILENAME (port);
0f2d19dd 1332}
1bbd0b84 1333#undef FUNC_NAME
0f2d19dd 1334
a1ec6916 1335SCM_DEFINE (scm_set_port_filename_x, "set-port-filename!", 2, 0, 0,
1bbd0b84 1336 (SCM port, SCM filename),
b380b885
MD
1337 "Change the filename associated with @var{port}, using the current input\n"
1338 "port if none is specified. Note that this does not change the port's\n"
1339 "source of data, but only the value that is returned by\n"
1340 "@code{port-filename} and reported in diagnostic output.")
1bbd0b84 1341#define FUNC_NAME s_scm_set_port_filename_x
d14af9f2 1342{
360fc44c 1343 port = SCM_COERCE_OUTPORT (port);
3b3b36dd 1344 SCM_VALIDATE_OPENPORT (1,port);
360fc44c 1345 /* We allow the user to set the filename to whatever he likes. */
b24b5e13
DH
1346 SCM_SET_FILENAME (port, filename);
1347 return SCM_UNSPECIFIED;
d14af9f2 1348}
1bbd0b84 1349#undef FUNC_NAME
d14af9f2 1350
0f2d19dd
JB
1351#ifndef ttyname
1352extern char * ttyname();
1353#endif
1354
f12733c9
MD
1355void
1356scm_print_port_mode (SCM exp, SCM port)
1357{
1358 scm_puts (SCM_CLOSEDP (exp)
1359 ? "closed: "
f9a64404
DH
1360 : (SCM_RDNG & SCM_CELL_WORD_0 (exp)
1361 ? (SCM_WRTNG & SCM_CELL_WORD_0 (exp)
f12733c9
MD
1362 ? "input-output: "
1363 : "input: ")
f9a64404 1364 : (SCM_WRTNG & SCM_CELL_WORD_0 (exp)
f12733c9
MD
1365 ? "output: "
1366 : "bogus: ")),
1367 port);
1368}
1cc91f1b 1369
f12733c9
MD
1370int
1371scm_port_print (SCM exp, SCM port, scm_print_state *pstate)
0f2d19dd 1372{
f12733c9
MD
1373 char *type = SCM_PTOBNAME (SCM_PTOBNUM (exp));
1374 if (!type)
1375 type = "port";
b7f3516f 1376 scm_puts ("#<", port);
f12733c9 1377 scm_print_port_mode (exp, port);
b7f3516f
TT
1378 scm_puts (type, port);
1379 scm_putc (' ', port);
12a8b769 1380 scm_intprint (SCM_CELL_WORD_1 (exp), 16, port);
b7f3516f 1381 scm_putc ('>', port);
f12733c9 1382 return 1;
0f2d19dd
JB
1383}
1384
0f2d19dd
JB
1385void
1386scm_ports_prehistory ()
0f2d19dd
JB
1387{
1388 scm_numptob = 0;
f12733c9 1389 scm_ptobs = (scm_ptob_descriptor *) malloc (sizeof (scm_ptob_descriptor));
0f2d19dd 1390}
0f2d19dd
JB
1391
1392\f
ee149d03 1393
d68fee48 1394/* Void ports. */
0f2d19dd 1395
e841c3e0 1396scm_bits_t scm_tc16_void_port = 0;
0f2d19dd 1397
70df8af6 1398static int fill_input_void_port (SCM port)
283a1a0e 1399{
70df8af6 1400 return EOF;
283a1a0e
GH
1401}
1402
31703ab8 1403static void
8aa011a1 1404write_void_port (SCM port, const void *data, size_t size)
31703ab8
GH
1405{
1406}
1407
0f2d19dd 1408SCM
a284e297 1409scm_void_port (char *mode_str)
0f2d19dd
JB
1410{
1411 int mode_bits;
1412 SCM answer;
840ae05d 1413 scm_port * pt;
0f2d19dd
JB
1414
1415 SCM_NEWCELL (answer);
1416 SCM_DEFER_INTS;
1417 mode_bits = scm_mode_bits (mode_str);
1418 pt = scm_add_to_port_table (answer);
70df8af6 1419 scm_port_non_buffer (pt);
0f2d19dd 1420 SCM_SETPTAB_ENTRY (answer, pt);
ee149d03 1421 SCM_SETSTREAM (answer, 0);
54778cd3 1422 SCM_SET_CELL_TYPE (answer, scm_tc16_void_port | mode_bits);
0f2d19dd
JB
1423 SCM_ALLOW_INTS;
1424 return answer;
1425}
1426
a1ec6916 1427SCM_DEFINE (scm_sys_make_void_port, "%make-void-port", 1, 0, 0,
1bbd0b84 1428 (SCM mode),
70df8af6
GH
1429 "Create and return a new void port. A void port acts like\n"
1430 "/dev/null. The @var{mode} argument\n"
1431 "specifies the input/output modes for this port: see the\n"
b380b885 1432 "documentation for @code{open-file} in @ref{File Ports}.")
1bbd0b84 1433#define FUNC_NAME s_scm_sys_make_void_port
0f2d19dd 1434{
a6d9e5ab
DH
1435 SCM_VALIDATE_STRING (1, mode);
1436 SCM_STRING_COERCE_0TERMINATION_X (mode);
1437 return scm_void_port (SCM_STRING_CHARS (mode));
0f2d19dd 1438}
1bbd0b84 1439#undef FUNC_NAME
0f2d19dd 1440
0f2d19dd 1441\f
89545eba 1442/* Initialization. */
1cc91f1b 1443
0f2d19dd
JB
1444void
1445scm_init_ports ()
0f2d19dd 1446{
840ae05d
JB
1447 /* lseek() symbols. */
1448 scm_sysintern ("SEEK_SET", SCM_MAKINUM (SEEK_SET));
1449 scm_sysintern ("SEEK_CUR", SCM_MAKINUM (SEEK_CUR));
1450 scm_sysintern ("SEEK_END", SCM_MAKINUM (SEEK_END));
1451
70df8af6
GH
1452 scm_tc16_void_port = scm_make_port_type ("void", fill_input_void_port,
1453 write_void_port);
8dc9439f 1454#ifndef SCM_MAGIC_SNARFER
a0599745 1455#include "libguile/ports.x"
8dc9439f 1456#endif
0f2d19dd 1457}
89e00824
ML
1458
1459/*
1460 Local Variables:
1461 c-file-style: "gnu"
1462 End:
1463*/