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