Lots of fixes to make guile (at some time) compile with strict typing.
[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 95 if (openp)
74a16888 96 return SCM_PACK (SCM_STREAM (ptr));
0f2d19dd
JB
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"
b380b885 643 "which are not needed in the new process.")
1bbd0b84 644#define FUNC_NAME s_scm_close_all_ports_except
0f2d19dd
JB
645{
646 int i = 0;
3b3b36dd 647 SCM_VALIDATE_CONS (1,ports);
0f2d19dd
JB
648 while (i < scm_port_table_size)
649 {
650 SCM thisport = scm_port_table[i]->port;
651 int found = 0;
652 SCM ports_ptr = ports;
653
654 while (SCM_NNULLP (ports_ptr))
655 {
78446828 656 SCM port = SCM_COERCE_OUTPORT (SCM_CAR (ports_ptr));
0f2d19dd 657 if (i == 0)
3b3b36dd 658 SCM_VALIDATE_OPPORT (SCM_ARG1,port);
54778cd3 659 if (SCM_EQ_P (port, thisport))
0f2d19dd
JB
660 found = 1;
661 ports_ptr = SCM_CDR (ports_ptr);
662 }
663 if (found)
664 i++;
665 else
666 /* i is not to be incremented here. */
667 scm_close_port (thisport);
668 }
0f2d19dd
JB
669 return SCM_UNSPECIFIED;
670}
1bbd0b84 671#undef FUNC_NAME
0f2d19dd 672
d68fee48
JB
673
674\f
675/* Utter miscellany. Gosh, we should clean this up some time. */
676
3b3b36dd 677SCM_DEFINE (scm_input_port_p, "input-port?", 1, 0, 0,
1bbd0b84 678 (SCM x),
bfc46627
GB
679 "Returns @code{#t} if @var{x} is an input port, otherwise returns\n"
680 "@code{#f}. Any object satisfying this predicate also satisfies\n"
681 "@code{port?}.")
1bbd0b84 682#define FUNC_NAME s_scm_input_port_p
0f2d19dd
JB
683{
684 if (SCM_IMP (x))
4a94d8ca 685 return SCM_BOOL_F;
1bbd0b84 686 return SCM_BOOL(SCM_INPORTP (x));
0f2d19dd 687}
1bbd0b84 688#undef FUNC_NAME
0f2d19dd 689
3b3b36dd 690SCM_DEFINE (scm_output_port_p, "output-port?", 1, 0, 0,
1bbd0b84 691 (SCM x),
bfc46627
GB
692 "Returns @code{#t} if @var{x} is an output port, otherwise returns\n"
693 "@code{#f}. Any object satisfying this predicate also satisfies\n"
694 "@code{port?}.")
1bbd0b84 695#define FUNC_NAME s_scm_output_port_p
0f2d19dd
JB
696{
697 if (SCM_IMP (x))
4a94d8ca
MD
698 return SCM_BOOL_F;
699 if (SCM_PORT_WITH_PS_P (x))
700 x = SCM_PORT_WITH_PS_PORT (x);
1bbd0b84 701 return SCM_BOOL(SCM_OUTPORTP (x));
0f2d19dd 702}
1bbd0b84 703#undef FUNC_NAME
0f2d19dd 704
3b3b36dd 705SCM_DEFINE (scm_port_closed_p, "port-closed?", 1, 0, 0,
1bbd0b84 706 (SCM port),
b380b885 707 "Returns @code{#t} if @var{port} is closed or @code{#f} if it is open.")
1bbd0b84 708#define FUNC_NAME s_scm_port_closed_p
60d0643d 709{
c1bfcf60 710 SCM_VALIDATE_PORT (1,port);
1bbd0b84 711 return SCM_NEGATE_BOOL(SCM_OPPORTP (port));
60d0643d 712}
1bbd0b84 713#undef FUNC_NAME
0f2d19dd 714
3b3b36dd 715SCM_DEFINE (scm_eof_object_p, "eof-object?", 1, 0, 0,
1bbd0b84 716 (SCM x),
bfc46627
GB
717 "Returns @code{#t} if @var{x} is an end-of-file object; otherwise\n"
718 "returns @code{#f}.")
1bbd0b84 719#define FUNC_NAME s_scm_eof_object_p
0f2d19dd 720{
1bbd0b84 721 return SCM_BOOL(SCM_EOF_OBJECT_P (x));
0f2d19dd 722}
1bbd0b84 723#undef FUNC_NAME
0f2d19dd 724
3b3b36dd 725SCM_DEFINE (scm_force_output, "force-output", 0, 1, 0,
1bbd0b84 726 (SCM port),
b380b885
MD
727 "Flush the specified output port, or the current output port if @var{port}\n"
728 "is omitted. The current output buffer contents are passed to the \n"
729 "underlying port implementation (e.g., in the case of fports, the\n"
730 "data will be written to the file and the output buffer will be cleared.)\n"
731 "It has no effect on an unbuffered port.\n\n"
732 "The return value is unspecified.")
1bbd0b84 733#define FUNC_NAME s_scm_force_output
0f2d19dd
JB
734{
735 if (SCM_UNBNDP (port))
3e877d15 736 port = scm_cur_outp;
0f2d19dd 737 else
78446828
MV
738 {
739 port = SCM_COERCE_OUTPORT (port);
3b3b36dd 740 SCM_VALIDATE_OPOUTPORT (1,port);
78446828 741 }
affc96b5 742 scm_flush (port);
ee149d03 743 return SCM_UNSPECIFIED;
0f2d19dd 744}
1bbd0b84 745#undef FUNC_NAME
0f2d19dd 746
a1ec6916 747SCM_DEFINE (scm_flush_all_ports, "flush-all-ports", 0, 0, 0,
1bbd0b84 748 (),
b380b885
MD
749 "Equivalent to calling @code{force-output} on\n"
750 "all open output ports. The return value is unspecified.")
1bbd0b84 751#define FUNC_NAME s_scm_flush_all_ports
89ea5b7c
GH
752{
753 int i;
754
755 for (i = 0; i < scm_port_table_size; i++)
756 {
ee149d03 757 if (SCM_OPOUTPORTP (scm_port_table[i]->port))
affc96b5 758 scm_flush (scm_port_table[i]->port);
89ea5b7c
GH
759 }
760 return SCM_UNSPECIFIED;
761}
1bbd0b84 762#undef FUNC_NAME
0f2d19dd 763
3b3b36dd 764SCM_DEFINE (scm_read_char, "read-char", 0, 1, 0,
1bbd0b84 765 (SCM port),
bfc46627
GB
766 "Returns the next character available from @var{port}, updating\n"
767 "@var{port} to point to the following character. If no more\n"
768 "characters are available, an end-of-file object is returned.")
1bbd0b84 769#define FUNC_NAME s_scm_read_char
0f2d19dd
JB
770{
771 int c;
772 if (SCM_UNBNDP (port))
334341aa 773 port = scm_cur_inp;
3b3b36dd 774 SCM_VALIDATE_OPINPORT (1,port);
b7f3516f 775 c = scm_getc (port);
0f2d19dd
JB
776 if (EOF == c)
777 return SCM_EOF_VAL;
7866a09b 778 return SCM_MAKE_CHAR (c);
0f2d19dd 779}
1bbd0b84 780#undef FUNC_NAME
0f2d19dd 781
5c070ca7 782/* this should only be called when the read buffer is empty. it
affc96b5 783 tries to refill the read buffer. it returns the first char from
5c070ca7 784 the port, which is either EOF or *(pt->read_pos). */
6c951427 785int
affc96b5 786scm_fill_input (SCM port)
6c951427 787{
283a1a0e
GH
788 scm_port *pt = SCM_PTAB_ENTRY (port);
789
6c951427
GH
790 if (pt->read_buf == pt->putback_buf)
791 {
792 /* finished reading put-back chars. */
793 pt->read_buf = pt->saved_read_buf;
794 pt->read_pos = pt->saved_read_pos;
795 pt->read_end = pt->saved_read_end;
796 pt->read_buf_size = pt->saved_read_buf_size;
797 if (pt->read_pos < pt->read_end)
5c070ca7 798 return *(pt->read_pos);
6c951427 799 }
affc96b5 800 return scm_ptobs[SCM_PTOBNUM (port)].fill_input (port);
6c951427
GH
801}
802
ee149d03 803int
a284e297 804scm_getc (SCM port)
0f2d19dd
JB
805{
806 int c;
840ae05d 807 scm_port *pt = SCM_PTAB_ENTRY (port);
ee149d03 808
840ae05d
JB
809 if (pt->rw_active == SCM_PORT_WRITE)
810 {
affc96b5
GH
811 /* may be marginally faster than calling scm_flush. */
812 scm_ptobs[SCM_PTOBNUM (port)].flush (port);
840ae05d 813 }
6c951427 814
5c070ca7
GH
815 if (pt->rw_random)
816 pt->rw_active = SCM_PORT_READ;
817
818 if (pt->read_pos >= pt->read_end)
ee149d03 819 {
affc96b5 820 if (scm_fill_input (port) == EOF)
5c070ca7 821 return EOF;
ee149d03
JB
822 }
823
5c070ca7 824 c = *(pt->read_pos++);
840ae05d 825
ee149d03
JB
826 if (c == '\n')
827 {
828 SCM_INCLINE (port);
829 }
830 else if (c == '\t')
831 {
832 SCM_TABCOL (port);
833 }
834 else
835 {
836 SCM_INCCOL (port);
837 }
838
839 return c;
0f2d19dd
JB
840}
841
ee149d03 842void
a284e297 843scm_putc (char c, SCM port)
ee149d03 844{
265e6a4d 845 scm_lfwrite (&c, 1, port);
ee149d03 846}
3cb988bd 847
ee149d03 848void
70d63753 849scm_puts (const char *s, SCM port)
3cb988bd 850{
265e6a4d 851 scm_lfwrite (s, strlen (s), port);
ee149d03 852}
3cb988bd 853
ee149d03 854void
70d63753 855scm_lfwrite (const char *ptr, scm_sizet size, SCM port)
ee149d03 856{
840ae05d 857 scm_port *pt = SCM_PTAB_ENTRY (port);
f12733c9 858 scm_ptob_descriptor *ptob = &scm_ptobs[SCM_PTOBNUM (port)];
3e2043c4 859
840ae05d 860 if (pt->rw_active == SCM_PORT_READ)
affc96b5 861 scm_end_input (port);
283a1a0e 862
31703ab8 863 ptob->write (port, ptr, size);
840ae05d
JB
864
865 if (pt->rw_random)
866 pt->rw_active = SCM_PORT_WRITE;
ee149d03 867}
3cb988bd 868
3cb988bd 869
ee149d03 870void
a284e297 871scm_flush (SCM port)
ee149d03
JB
872{
873 scm_sizet i = SCM_PTOBNUM (port);
affc96b5 874 (scm_ptobs[i].flush) (port);
ee149d03
JB
875}
876
283a1a0e 877void
a284e297 878scm_end_input (SCM port)
283a1a0e
GH
879{
880 int offset;
881 scm_port *pt = SCM_PTAB_ENTRY (port);
882
883 if (pt->read_buf == pt->putback_buf)
884 {
885 offset = pt->read_end - pt->read_pos;
886 pt->read_buf = pt->saved_read_buf;
887 pt->read_pos = pt->saved_read_pos;
888 pt->read_end = pt->saved_read_end;
889 pt->read_buf_size = pt->saved_read_buf_size;
890 }
891 else
892 offset = 0;
893
affc96b5 894 scm_ptobs[SCM_PTOBNUM (port)].end_input (port, offset);
283a1a0e
GH
895}
896
ee149d03
JB
897\f
898
899
900void
a284e297 901scm_ungetc (int c, SCM port)
ee149d03 902{
840ae05d
JB
903 scm_port *pt = SCM_PTAB_ENTRY (port);
904
6c951427
GH
905 if (pt->read_buf == pt->putback_buf)
906 /* already using the put-back buffer. */
907 {
908 /* enlarge putback_buf if necessary. */
909 if (pt->read_end == pt->read_buf + pt->read_buf_size
910 && pt->read_buf == pt->read_pos)
911 {
912 int new_size = pt->read_buf_size * 2;
913 unsigned char *tmp =
914 (unsigned char *) realloc (pt->putback_buf, new_size);
915
916 if (tmp == NULL)
917 scm_memory_error ("scm_ungetc");
918 pt->read_pos = pt->read_buf = pt->putback_buf = tmp;
919 pt->read_end = pt->read_buf + pt->read_buf_size;
920 pt->read_buf_size = pt->putback_buf_size = new_size;
921 }
922
923 /* shift any existing bytes to buffer + 1. */
924 if (pt->read_pos == pt->read_end)
925 pt->read_end = pt->read_buf + 1;
926 else if (pt->read_pos != pt->read_buf + 1)
927 {
928 int count = pt->read_end - pt->read_pos;
929
930 memmove (pt->read_buf + 1, pt->read_pos, count);
931 pt->read_end = pt->read_buf + 1 + count;
932 }
933
934 pt->read_pos = pt->read_buf;
935 }
936 else
937 /* switch to the put-back buffer. */
938 {
939 if (pt->putback_buf == NULL)
940 {
6e2e75db 941 pt->putback_buf = (char *) malloc (SCM_INITIAL_PUTBACK_BUF_SIZE);
6c951427
GH
942 if (pt->putback_buf == NULL)
943 scm_memory_error ("scm_ungetc");
944 pt->putback_buf_size = SCM_INITIAL_PUTBACK_BUF_SIZE;
945 }
946
947 pt->saved_read_buf = pt->read_buf;
948 pt->saved_read_pos = pt->read_pos;
949 pt->saved_read_end = pt->read_end;
950 pt->saved_read_buf_size = pt->read_buf_size;
951
952 pt->read_pos = pt->read_buf = pt->putback_buf;
953 pt->read_end = pt->read_buf + 1;
954 pt->read_buf_size = pt->putback_buf_size;
955 }
956
957 *pt->read_buf = c;
ee149d03 958
840ae05d
JB
959 if (pt->rw_random)
960 pt->rw_active = SCM_PORT_READ;
961
ee149d03
JB
962 if (c == '\n')
963 {
964 /* What should col be in this case?
965 * We'll leave it at -1.
966 */
967 SCM_LINUM (port) -= 1;
968 }
969 else
970 SCM_COL(port) -= 1;
971}
972
973
974void
70d63753 975scm_ungets (const char *s, int n, SCM port)
ee149d03
JB
976{
977 /* This is simple minded and inefficient, but unreading strings is
978 * probably not a common operation, and remember that line and
979 * column numbers have to be handled...
980 *
981 * Please feel free to write an optimized version!
982 */
983 while (n--)
984 scm_ungetc (s[n], port);
985}
986
987
3b3b36dd 988SCM_DEFINE (scm_peek_char, "peek-char", 0, 1, 0,
1bbd0b84 989 (SCM port),
bfc46627
GB
990 "Returns the next character available from @var{port},\n"
991 "@emph{without} updating @var{port} to point to the following\n"
992 "character. If no more characters are available, an end-of-file object\n"
993 "is returned.@footnote{The value returned by a call to @code{peek-char}\n"
994 "is the same as the value that would have been returned by a call to\n"
995 "@code{read-char} on the same port. The only difference is that the very\n"
996 "next call to @code{read-char} or @code{peek-char} on that\n"
997 "@var{port} will return the value returned by the preceding call to\n"
998 "@code{peek-char}. In particular, a call to @code{peek-char} on an\n"
999 "interactive port will hang waiting for input whenever a call to\n"
1000 "@code{read-char} would have hung.}")
1bbd0b84 1001#define FUNC_NAME s_scm_peek_char
ee149d03
JB
1002{
1003 int c;
1004 if (SCM_UNBNDP (port))
1005 port = scm_cur_inp;
1006 else
3b3b36dd 1007 SCM_VALIDATE_OPINPORT (1,port);
ee149d03
JB
1008 c = scm_getc (port);
1009 if (EOF == c)
1010 return SCM_EOF_VAL;
1011 scm_ungetc (c, port);
7866a09b 1012 return SCM_MAKE_CHAR (c);
3cb988bd 1013}
1bbd0b84 1014#undef FUNC_NAME
3cb988bd 1015
a1ec6916 1016SCM_DEFINE (scm_unread_char, "unread-char", 2, 0, 0,
1bbd0b84 1017 (SCM cobj, SCM port),
b380b885
MD
1018 "Place @var{char} in @var{port} so that it will be read by the\n"
1019 "next read operation. If called multiple times, the unread characters\n"
1020 "will be read again in last-in first-out order. If @var{port} is\n"
1021 "not supplied, the current input port is used.")
1bbd0b84 1022#define FUNC_NAME s_scm_unread_char
0f2d19dd
JB
1023{
1024 int c;
1025
7866a09b 1026 SCM_VALIDATE_CHAR (1,cobj);
0f2d19dd
JB
1027 if (SCM_UNBNDP (port))
1028 port = scm_cur_inp;
1029 else
3b3b36dd 1030 SCM_VALIDATE_OPINPORT (2,port);
0f2d19dd 1031
7866a09b 1032 c = SCM_CHAR (cobj);
0f2d19dd 1033
b7f3516f 1034 scm_ungetc (c, port);
0f2d19dd
JB
1035 return cobj;
1036}
1bbd0b84 1037#undef FUNC_NAME
0f2d19dd 1038
a1ec6916 1039SCM_DEFINE (scm_unread_string, "unread-string", 2, 0, 0,
1bbd0b84 1040 (SCM str, SCM port),
b380b885
MD
1041 "Place the string @var{str} in @var{port} so that its characters will be\n"
1042 "read in subsequent read operations. If called multiple times, the\n"
1043 "unread characters will be read again in last-in first-out order. If\n"
1044 "@var{port} is not supplied, the current-input-port is used.")
1bbd0b84 1045#define FUNC_NAME s_scm_unread_string
ee1e7e13 1046{
3b3b36dd 1047 SCM_VALIDATE_STRING (1,str);
ee1e7e13
MD
1048 if (SCM_UNBNDP (port))
1049 port = scm_cur_inp;
1050 else
3b3b36dd 1051 SCM_VALIDATE_OPINPORT (2,port);
ee1e7e13 1052
d1c90db5 1053 scm_ungets (SCM_ROUCHARS (str), SCM_LENGTH (str), port);
ee1e7e13
MD
1054
1055 return str;
1056}
1bbd0b84 1057#undef FUNC_NAME
ee1e7e13 1058
a1ec6916 1059SCM_DEFINE (scm_seek, "seek", 3, 0, 0,
1bbd0b84 1060 (SCM object, SCM offset, SCM whence),
b380b885
MD
1061 "Sets the current position of @var{fd/port} to the integer @var{offset},\n"
1062 "which is interpreted according to the value of @var{whence}.\n\n"
1063 "One of the following variables should be supplied\n"
1064 "for @var{whence}:\n"
1065 "@defvar SEEK_SET\n"
1066 "Seek from the beginning of the file.\n"
1067 "@end defvar\n"
1068 "@defvar SEEK_CUR\n"
1069 "Seek from the current position.\n"
1070 "@end defvar\n"
1071 "@defvar SEEK_END\n"
1072 "Seek from the end of the file.\n"
1073 "@end defvar\n\n"
1074 "If @var{fd/port} is a file descriptor, the underlying system call is\n"
1075 "@code{lseek}. @var{port} may be a string port.\n\n"
1076 "The value returned is the new position in the file. This means that\n"
1077 "the current position of a port can be obtained using:\n"
1078 "@smalllisp\n"
1079 "(seek port 0 SEEK_CUR)\n"
1080 "@end smalllisp")
1bbd0b84 1081#define FUNC_NAME s_scm_seek
840ae05d
JB
1082{
1083 off_t off;
1084 off_t rv;
1085 int how;
1086
1087 object = SCM_COERCE_OUTPORT (object);
1088
1bbd0b84 1089 off = SCM_NUM2LONG (2,offset);
3b3b36dd 1090 SCM_VALIDATE_INUM_COPY (3,whence,how);
840ae05d 1091 if (how != SEEK_SET && how != SEEK_CUR && how != SEEK_END)
1bbd0b84 1092 SCM_OUT_OF_RANGE (3, whence);
0c95b57d 1093 if (SCM_OPPORTP (object))
840ae05d 1094 {
f12733c9 1095 scm_ptob_descriptor *ptob = scm_ptobs + SCM_PTOBNUM (object);
840ae05d
JB
1096
1097 if (!ptob->seek)
1bbd0b84
GB
1098 SCM_MISC_ERROR ("port is not seekable",
1099 scm_cons (object, SCM_EOL));
840ae05d 1100 else
7dcb364d 1101 rv = ptob->seek (object, off, how);
840ae05d
JB
1102 }
1103 else /* file descriptor?. */
1104 {
3b3b36dd 1105 SCM_VALIDATE_INUM (1,object);
840ae05d
JB
1106 rv = lseek (SCM_INUM (object), off, how);
1107 if (rv == -1)
1bbd0b84 1108 SCM_SYSERROR;
840ae05d
JB
1109 }
1110 return scm_long2num (rv);
1111}
1bbd0b84 1112#undef FUNC_NAME
840ae05d 1113
a1ec6916 1114SCM_DEFINE (scm_truncate_file, "truncate-file", 1, 1, 0,
1bbd0b84 1115 (SCM object, SCM length),
b380b885
MD
1116 "Truncates the object referred to by @var{obj} to at most @var{size} bytes.\n"
1117 "@var{obj} can be a string containing a file name or an integer file\n"
1118 "descriptor or a port. @var{size} may be omitted if @var{obj} is not\n"
1119 "a file name, in which case the truncation occurs at the current port.\n"
1120 "position.\n\n"
1121 "The return value is unspecified.")
1bbd0b84 1122#define FUNC_NAME s_scm_truncate_file
840ae05d 1123{
69bc9ff3
GH
1124 int rv;
1125 off_t c_length;
1126
1127 /* object can be a port, fdes or filename. */
840ae05d 1128
840ae05d
JB
1129 if (SCM_UNBNDP (length))
1130 {
69bc9ff3 1131 /* must supply length if object is a filename. */
0c95b57d 1132 if (SCM_ROSTRINGP (object))
c1bfcf60 1133 SCM_MISC_ERROR("must supply length if OBJECT is a filename",SCM_EOL);
69bc9ff3 1134
c94577b4 1135 length = scm_seek (object, SCM_INUM0, SCM_MAKINUM (SEEK_CUR));
840ae05d 1136 }
1bbd0b84 1137 c_length = SCM_NUM2LONG (2,length);
69bc9ff3 1138 if (c_length < 0)
1bbd0b84 1139 SCM_MISC_ERROR ("negative offset", SCM_EOL);
3fe6190f 1140
69bc9ff3
GH
1141 object = SCM_COERCE_OUTPORT (object);
1142 if (SCM_INUMP (object))
1143 {
1144 SCM_SYSCALL (rv = ftruncate (SCM_INUM (object), c_length));
1145 }
0c95b57d 1146 else if (SCM_OPOUTPORTP (object))
69bc9ff3
GH
1147 {
1148 scm_port *pt = SCM_PTAB_ENTRY (object);
f12733c9 1149 scm_ptob_descriptor *ptob = scm_ptobs + SCM_PTOBNUM (object);
69bc9ff3 1150
affc96b5 1151 if (!ptob->truncate)
1bbd0b84 1152 SCM_MISC_ERROR ("port is not truncatable", SCM_EOL);
69bc9ff3 1153 if (pt->rw_active == SCM_PORT_READ)
affc96b5 1154 scm_end_input (object);
69bc9ff3 1155 else if (pt->rw_active == SCM_PORT_WRITE)
affc96b5 1156 ptob->flush (object);
69bc9ff3 1157
affc96b5 1158 ptob->truncate (object, c_length);
69bc9ff3
GH
1159 rv = 0;
1160 }
1161 else
1162 {
3b3b36dd 1163 SCM_VALIDATE_ROSTRING (1,object);
69bc9ff3
GH
1164 SCM_COERCE_SUBSTR (object);
1165 SCM_SYSCALL (rv = truncate (SCM_ROCHARS (object), c_length));
1166 }
1167 if (rv == -1)
1bbd0b84 1168 SCM_SYSERROR;
840ae05d
JB
1169 return SCM_UNSPECIFIED;
1170}
1bbd0b84 1171#undef FUNC_NAME
840ae05d 1172
a1ec6916 1173SCM_DEFINE (scm_port_line, "port-line", 1, 0, 0,
1bbd0b84 1174 (SCM port),
b450f070 1175 "Return the current line number for PORT.")
1bbd0b84 1176#define FUNC_NAME s_scm_port_line
0f2d19dd 1177{
78446828 1178 port = SCM_COERCE_OUTPORT (port);
3b3b36dd 1179 SCM_VALIDATE_OPENPORT (1,port);
360fc44c 1180 return SCM_MAKINUM (SCM_LINUM (port));
0f2d19dd 1181}
1bbd0b84 1182#undef FUNC_NAME
0f2d19dd 1183
a1ec6916 1184SCM_DEFINE (scm_set_port_line_x, "set-port-line!", 2, 0, 0,
1bbd0b84 1185 (SCM port, SCM line),
b450f070 1186 "Set the current line number for PORT to LINE.")
1bbd0b84 1187#define FUNC_NAME s_scm_set_port_line_x
d043d8c2 1188{
360fc44c 1189 port = SCM_COERCE_OUTPORT (port);
3b3b36dd
GB
1190 SCM_VALIDATE_OPENPORT (1,port);
1191 SCM_VALIDATE_INUM (2,line);
564478fd
GB
1192 SCM_PTAB_ENTRY (port)->line_number = SCM_INUM (line);
1193 return SCM_UNSPECIFIED;
d043d8c2 1194}
1bbd0b84 1195#undef FUNC_NAME
d043d8c2 1196
a1ec6916 1197SCM_DEFINE (scm_port_column, "port-column", 1, 0, 0,
1bbd0b84 1198 (SCM port),
b380b885
MD
1199 "@deffnx primitive port-line [input-port]\n"
1200 "Return the current column number or line number of @var{input-port},\n"
1201 "using the current input port if none is specified. If the number is\n"
1202 "unknown, the result is #f. Otherwise, the result is a 0-origin integer\n"
1203 "- i.e. the first character of the first line is line 0, column 0.\n"
1204 "(However, when you display a file position, for example in an error\n"
1205 "message, we recommand you add 1 to get 1-origin integers. This is\n"
1206 "because lines and column numbers traditionally start with 1, and that is\n"
1207 "what non-programmers will find most natural.)")
1bbd0b84 1208#define FUNC_NAME s_scm_port_column
0f2d19dd 1209{
78446828 1210 port = SCM_COERCE_OUTPORT (port);
3b3b36dd 1211 SCM_VALIDATE_OPENPORT (1,port);
360fc44c 1212 return SCM_MAKINUM (SCM_COL (port));
0f2d19dd 1213}
1bbd0b84 1214#undef FUNC_NAME
0f2d19dd 1215
a1ec6916 1216SCM_DEFINE (scm_set_port_column_x, "set-port-column!", 2, 0, 0,
1bbd0b84 1217 (SCM port, SCM column),
564478fd 1218 "@deffnx primitive set-port-column! [input-port] column\n"
b380b885
MD
1219 "Set the current column or line number of @var{input-port}, using the\n"
1220 "current input port if none is specified.")
1bbd0b84 1221#define FUNC_NAME s_scm_set_port_column_x
d043d8c2 1222{
360fc44c 1223 port = SCM_COERCE_OUTPORT (port);
3b3b36dd
GB
1224 SCM_VALIDATE_OPENPORT (1,port);
1225 SCM_VALIDATE_INUM (2,column);
564478fd
GB
1226 SCM_PTAB_ENTRY (port)->column_number = SCM_INUM (column);
1227 return SCM_UNSPECIFIED;
d043d8c2 1228}
1bbd0b84 1229#undef FUNC_NAME
d043d8c2 1230
a1ec6916 1231SCM_DEFINE (scm_port_filename, "port-filename", 1, 0, 0,
1bbd0b84 1232 (SCM port),
b380b885 1233 "Return the filename associated with @var{port}. This function returns\n"
a3c8b9fc
MD
1234 "the strings \"standard input\", \"standard output\" and \"standard error\""
1235 "when called on the current input, output and error ports respectively.")
1bbd0b84 1236#define FUNC_NAME s_scm_port_filename
0f2d19dd 1237{
78446828 1238 port = SCM_COERCE_OUTPORT (port);
3b3b36dd 1239 SCM_VALIDATE_OPENPORT (1,port);
360fc44c 1240 return SCM_PTAB_ENTRY (port)->file_name;
0f2d19dd 1241}
1bbd0b84 1242#undef FUNC_NAME
0f2d19dd 1243
a1ec6916 1244SCM_DEFINE (scm_set_port_filename_x, "set-port-filename!", 2, 0, 0,
1bbd0b84 1245 (SCM port, SCM filename),
b380b885
MD
1246 "Change the filename associated with @var{port}, using the current input\n"
1247 "port if none is specified. Note that this does not change the port's\n"
1248 "source of data, but only the value that is returned by\n"
1249 "@code{port-filename} and reported in diagnostic output.")
1bbd0b84 1250#define FUNC_NAME s_scm_set_port_filename_x
d14af9f2 1251{
360fc44c 1252 port = SCM_COERCE_OUTPORT (port);
3b3b36dd 1253 SCM_VALIDATE_OPENPORT (1,port);
360fc44c 1254 /* We allow the user to set the filename to whatever he likes. */
d14af9f2
MD
1255 return SCM_PTAB_ENTRY (port)->file_name = filename;
1256}
1bbd0b84 1257#undef FUNC_NAME
d14af9f2 1258
0f2d19dd
JB
1259#ifndef ttyname
1260extern char * ttyname();
1261#endif
1262
f12733c9
MD
1263void
1264scm_print_port_mode (SCM exp, SCM port)
1265{
1266 scm_puts (SCM_CLOSEDP (exp)
1267 ? "closed: "
f1267706
MD
1268 : (SCM_RDNG & SCM_UNPACK_CAR (exp)
1269 ? (SCM_WRTNG & SCM_UNPACK_CAR (exp)
f12733c9
MD
1270 ? "input-output: "
1271 : "input: ")
f1267706 1272 : (SCM_WRTNG & SCM_UNPACK_CAR (exp)
f12733c9
MD
1273 ? "output: "
1274 : "bogus: ")),
1275 port);
1276}
1cc91f1b 1277
f12733c9
MD
1278int
1279scm_port_print (SCM exp, SCM port, scm_print_state *pstate)
0f2d19dd 1280{
f12733c9
MD
1281 char *type = SCM_PTOBNAME (SCM_PTOBNUM (exp));
1282 if (!type)
1283 type = "port";
b7f3516f 1284 scm_puts ("#<", port);
f12733c9 1285 scm_print_port_mode (exp, port);
b7f3516f
TT
1286 scm_puts (type, port);
1287 scm_putc (' ', port);
c209c88e 1288 scm_intprint ((int) SCM_CDR (exp), 16, port);
b7f3516f 1289 scm_putc ('>', port);
f12733c9 1290 return 1;
0f2d19dd
JB
1291}
1292
f12733c9
MD
1293extern void scm_make_fptob ();
1294extern void scm_make_stptob ();
1295extern void scm_make_sfptob ();
1cc91f1b 1296
0f2d19dd
JB
1297void
1298scm_ports_prehistory ()
0f2d19dd
JB
1299{
1300 scm_numptob = 0;
f12733c9 1301 scm_ptobs = (scm_ptob_descriptor *) malloc (sizeof (scm_ptob_descriptor));
0f2d19dd
JB
1302
1303 /* WARNING: These scm_newptob calls must be done in this order.
1304 * They must agree with the port declarations in tags.h.
1305 */
f12733c9
MD
1306 /* scm_tc16_fport = */ scm_make_fptob ();
1307 /* scm_tc16_pipe was here */ scm_make_fptob (); /* dummy. */
1308 /* scm_tc16_strport = */ scm_make_stptob ();
1309 /* scm_tc16_sfport = */ scm_make_sfptob ();
0f2d19dd 1310}
0f2d19dd
JB
1311
1312\f
ee149d03 1313
d68fee48 1314/* Void ports. */
0f2d19dd 1315
f12733c9 1316long scm_tc16_void_port = 0;
0f2d19dd 1317
70df8af6 1318static int fill_input_void_port (SCM port)
283a1a0e 1319{
70df8af6 1320 return EOF;
283a1a0e
GH
1321}
1322
31703ab8 1323static void
8aa011a1 1324write_void_port (SCM port, const void *data, size_t size)
31703ab8
GH
1325{
1326}
1327
0f2d19dd 1328SCM
a284e297 1329scm_void_port (char *mode_str)
0f2d19dd
JB
1330{
1331 int mode_bits;
1332 SCM answer;
840ae05d 1333 scm_port * pt;
0f2d19dd
JB
1334
1335 SCM_NEWCELL (answer);
1336 SCM_DEFER_INTS;
1337 mode_bits = scm_mode_bits (mode_str);
1338 pt = scm_add_to_port_table (answer);
70df8af6 1339 scm_port_non_buffer (pt);
0f2d19dd 1340 SCM_SETPTAB_ENTRY (answer, pt);
ee149d03 1341 SCM_SETSTREAM (answer, 0);
54778cd3 1342 SCM_SET_CELL_TYPE (answer, scm_tc16_void_port | mode_bits);
0f2d19dd
JB
1343 SCM_ALLOW_INTS;
1344 return answer;
1345}
1346
a1ec6916 1347SCM_DEFINE (scm_sys_make_void_port, "%make-void-port", 1, 0, 0,
1bbd0b84 1348 (SCM mode),
70df8af6
GH
1349 "Create and return a new void port. A void port acts like\n"
1350 "/dev/null. The @var{mode} argument\n"
1351 "specifies the input/output modes for this port: see the\n"
b380b885 1352 "documentation for @code{open-file} in @ref{File Ports}.")
1bbd0b84 1353#define FUNC_NAME s_scm_sys_make_void_port
0f2d19dd 1354{
3b3b36dd 1355 SCM_VALIDATE_ROSTRING (1,mode);
89958ad0 1356 SCM_COERCE_SUBSTR (mode);
0f2d19dd
JB
1357 return scm_void_port (SCM_ROCHARS (mode));
1358}
1bbd0b84 1359#undef FUNC_NAME
0f2d19dd 1360
0f2d19dd 1361\f
89545eba 1362/* Initialization. */
1cc91f1b 1363
0f2d19dd
JB
1364void
1365scm_init_ports ()
0f2d19dd 1366{
840ae05d
JB
1367 /* lseek() symbols. */
1368 scm_sysintern ("SEEK_SET", SCM_MAKINUM (SEEK_SET));
1369 scm_sysintern ("SEEK_CUR", SCM_MAKINUM (SEEK_CUR));
1370 scm_sysintern ("SEEK_END", SCM_MAKINUM (SEEK_END));
1371
70df8af6
GH
1372 scm_tc16_void_port = scm_make_port_type ("void", fill_input_void_port,
1373 write_void_port);
0f2d19dd
JB
1374#include "ports.x"
1375}
89e00824
ML
1376
1377/*
1378 Local Variables:
1379 c-file-style: "gnu"
1380 End:
1381*/