Fix signed/unsigned mismatch in `scm_array_handle_{ref,set} ()'.
[bpt/guile.git] / libguile / ports.c
CommitLineData
0953b549 1/* Copyright (C) 1995,1996,1997,1998,1999,2000,2001, 2003, 2004, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
0f2d19dd 2 *
73be1d9e 3 * This library is free software; you can redistribute it and/or
53befeb7
NJ
4 * modify it under the terms of the GNU Lesser General Public License
5 * as published by the Free Software Foundation; either version 3 of
6 * the License, or (at your option) any later version.
0f2d19dd 7 *
53befeb7
NJ
8 * This library is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
73be1d9e
MV
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
0f2d19dd 12 *
73be1d9e
MV
13 * You should have received a copy of the GNU Lesser General Public
14 * License along with this library; if not, write to the Free Software
53befeb7
NJ
15 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
16 * 02110-1301 USA
73be1d9e 17 */
1bbd0b84 18
1bbd0b84 19
0f2d19dd 20\f
d68fee48
JB
21/* Headers. */
22
2b829bbb
KR
23#define _LARGEFILE64_SOURCE /* ask for stat64 etc */
24
dbb605f5 25#ifdef HAVE_CONFIG_H
bd515f37
RB
26# include <config.h>
27#endif
28
0f2d19dd 29#include <stdio.h>
e6e2e95a 30#include <errno.h>
8ab3d8a0 31#include <fcntl.h> /* for chsize on mingw */
b5cb4464 32#include <assert.h>
889975e5
MG
33#include <uniconv.h>
34#include <unistr.h>
35#include <striconveh.h>
e6e2e95a 36
fca43887
LC
37#include <assert.h>
38
a0599745 39#include "libguile/_scm.h"
4e047c3e 40#include "libguile/async.h"
f0942910 41#include "libguile/eval.h"
8ab3d8a0 42#include "libguile/fports.h" /* direct access for seek and truncate */
a0599745 43#include "libguile/objects.h"
9511876f 44#include "libguile/goops.h"
a0599745
MD
45#include "libguile/smob.h"
46#include "libguile/chars.h"
185e369a 47#include "libguile/dynwind.h"
0f2d19dd 48
a0599745 49#include "libguile/keywords.h"
5dbc6c06 50#include "libguile/hashtab.h"
a0599745
MD
51#include "libguile/root.h"
52#include "libguile/strings.h"
b42170a4 53#include "libguile/mallocs.h"
a0599745
MD
54#include "libguile/validate.h"
55#include "libguile/ports.h"
3a5fb14d 56#include "libguile/vectors.h"
5dbc6c06 57#include "libguile/weaks.h"
9de87eea 58#include "libguile/fluids.h"
889975e5 59#include "libguile/eq.h"
0f2d19dd 60
bd9e24b3
GH
61#ifdef HAVE_STRING_H
62#include <string.h>
63#endif
64
ec65f5da
MV
65#ifdef HAVE_IO_H
66#include <io.h>
67#endif
68
0f2d19dd
JB
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
8ab3d8a0
KR
77/* Mingw (version 3.4.5, circa 2006) has ftruncate as an alias for chsize
78 already, but have this code here in case that wasn't so in past versions,
79 or perhaps to help other minimal DOS environments.
80
81 gnulib ftruncate.c has code using fcntl F_CHSIZE and F_FREESP, which
82 might be possibilities if we've got other systems without ftruncate. */
83
84#if HAVE_CHSIZE && ! HAVE_FTRUNCATE
82893676 85#define ftruncate(fd, size) chsize (fd, size)
8ab3d8a0
KR
86#undef HAVE_FTRUNCATE
87#define HAVE_FTRUNCATE 1
82893676
MG
88#endif
89
0f2d19dd 90\f
d68fee48 91/* The port kind table --- a dynamically resized array of port types. */
0f2d19dd
JB
92
93
94/* scm_ptobs scm_numptob
5dbc6c06 95 * implement a dynamically resized array of ptob records.
0f2d19dd
JB
96 * Indexes into this table are used when generating type
97 * tags for smobjects (if you know a tag you can get an index and conversely).
98 */
92c2555f 99scm_t_ptob_descriptor *scm_ptobs;
c014a02e 100long scm_numptob;
0f2d19dd 101
ee149d03 102/* GC marker for a port with stream of SCM type. */
0f2d19dd 103SCM
a284e297 104scm_markstream (SCM ptr)
0f2d19dd
JB
105{
106 int openp;
f9a64404 107 openp = SCM_CELL_WORD_0 (ptr) & SCM_OPN;
0f2d19dd 108 if (openp)
74a16888 109 return SCM_PACK (SCM_STREAM (ptr));
0f2d19dd
JB
110 else
111 return SCM_BOOL_F;
112}
113
f12733c9 114/*
f12733c9 115 * We choose to use an interface similar to the smob interface with
affc96b5 116 * fill_input and write as standard fields, passed to the port
f12733c9
MD
117 * type constructor, and optional fields set by setters.
118 */
119
70df8af6 120static void
e81d98ec 121flush_port_default (SCM port SCM_UNUSED)
70df8af6
GH
122{
123}
124
125static void
e81d98ec 126end_input_default (SCM port SCM_UNUSED, int offset SCM_UNUSED)
70df8af6
GH
127{
128}
0f2d19dd 129
92c2555f 130scm_t_bits
f12733c9 131scm_make_port_type (char *name,
affc96b5 132 int (*fill_input) (SCM port),
8aa011a1 133 void (*write) (SCM port, const void *data, size_t size))
0f2d19dd
JB
134{
135 char *tmp;
0953b549 136 if (SCM_I_MAX_PORT_TYPE_COUNT - 1 <= scm_numptob)
0f2d19dd 137 goto ptoberr;
9de87eea 138 SCM_CRITICAL_SECTION_START;
fca43887
LC
139 tmp = (char *) scm_gc_realloc ((char *) scm_ptobs,
140 scm_numptob * sizeof (scm_t_ptob_descriptor),
141 (1 + scm_numptob)
142 * sizeof (scm_t_ptob_descriptor),
143 "port-type");
0f2d19dd
JB
144 if (tmp)
145 {
92c2555f 146 scm_ptobs = (scm_t_ptob_descriptor *) tmp;
affc96b5 147
f12733c9
MD
148 scm_ptobs[scm_numptob].name = name;
149 scm_ptobs[scm_numptob].mark = 0;
3051344b 150 scm_ptobs[scm_numptob].free = NULL;
f12733c9
MD
151 scm_ptobs[scm_numptob].print = scm_port_print;
152 scm_ptobs[scm_numptob].equalp = 0;
affc96b5
GH
153 scm_ptobs[scm_numptob].close = 0;
154
155 scm_ptobs[scm_numptob].write = write;
70df8af6 156 scm_ptobs[scm_numptob].flush = flush_port_default;
affc96b5 157
70df8af6 158 scm_ptobs[scm_numptob].end_input = end_input_default;
affc96b5
GH
159 scm_ptobs[scm_numptob].fill_input = fill_input;
160 scm_ptobs[scm_numptob].input_waiting = 0;
161
f12733c9 162 scm_ptobs[scm_numptob].seek = 0;
affc96b5
GH
163 scm_ptobs[scm_numptob].truncate = 0;
164
0f2d19dd
JB
165 scm_numptob++;
166 }
9de87eea 167 SCM_CRITICAL_SECTION_END;
0f2d19dd 168 if (!tmp)
2500356c
DH
169 {
170 ptoberr:
171 scm_memory_error ("scm_make_port_type");
172 }
f12733c9 173 /* Make a class object if Goops is present */
63385df2 174 if (SCM_UNPACK (scm_port_class[0]) != 0)
f12733c9 175 scm_make_port_classes (scm_numptob - 1, SCM_PTOBNAME (scm_numptob - 1));
0f2d19dd
JB
176 return scm_tc7_port + (scm_numptob - 1) * 256;
177}
178
f12733c9 179void
23f2b9a3 180scm_set_port_mark (scm_t_bits tc, SCM (*mark) (SCM))
f12733c9
MD
181{
182 scm_ptobs[SCM_TC2PTOBNUM (tc)].mark = mark;
183}
184
185void
23f2b9a3 186scm_set_port_free (scm_t_bits tc, size_t (*free) (SCM))
f12733c9
MD
187{
188 scm_ptobs[SCM_TC2PTOBNUM (tc)].free = free;
189}
190
191void
23f2b9a3 192scm_set_port_print (scm_t_bits tc, int (*print) (SCM exp, SCM port,
f12733c9
MD
193 scm_print_state *pstate))
194{
195 scm_ptobs[SCM_TC2PTOBNUM (tc)].print = print;
196}
197
198void
23f2b9a3 199scm_set_port_equalp (scm_t_bits tc, SCM (*equalp) (SCM, SCM))
f12733c9
MD
200{
201 scm_ptobs[SCM_TC2PTOBNUM (tc)].equalp = equalp;
202}
203
31703ab8 204void
23f2b9a3 205scm_set_port_flush (scm_t_bits tc, void (*flush) (SCM port))
31703ab8 206{
affc96b5 207 scm_ptobs[SCM_TC2PTOBNUM (tc)].flush = flush;
31703ab8
GH
208}
209
f12733c9 210void
23f2b9a3 211scm_set_port_end_input (scm_t_bits tc, void (*end_input) (SCM port, int offset))
f12733c9 212{
affc96b5 213 scm_ptobs[SCM_TC2PTOBNUM (tc)].end_input = end_input;
f12733c9
MD
214}
215
216void
23f2b9a3 217scm_set_port_close (scm_t_bits tc, int (*close) (SCM))
f12733c9 218{
affc96b5 219 scm_ptobs[SCM_TC2PTOBNUM (tc)].close = close;
f12733c9
MD
220}
221
222void
f1ce9199
LC
223scm_set_port_seek (scm_t_bits tc,
224 scm_t_off (*seek) (SCM, scm_t_off, int))
f12733c9
MD
225{
226 scm_ptobs[SCM_TC2PTOBNUM (tc)].seek = seek;
227}
228
229void
f1ce9199 230scm_set_port_truncate (scm_t_bits tc, void (*truncate) (SCM, scm_t_off))
f12733c9 231{
affc96b5 232 scm_ptobs[SCM_TC2PTOBNUM (tc)].truncate = truncate;
f12733c9
MD
233}
234
235void
23f2b9a3 236scm_set_port_input_waiting (scm_t_bits tc, int (*input_waiting) (SCM))
f12733c9 237{
affc96b5 238 scm_ptobs[SCM_TC2PTOBNUM (tc)].input_waiting = input_waiting;
f12733c9
MD
239}
240
0f2d19dd 241\f
0f2d19dd 242
3b3b36dd 243SCM_DEFINE (scm_char_ready_p, "char-ready?", 0, 1, 0,
1e6808ea
MG
244 (SCM port),
245 "Return @code{#t} if a character is ready on input @var{port}\n"
246 "and return @code{#f} otherwise. If @code{char-ready?} returns\n"
247 "@code{#t} then the next @code{read-char} operation on\n"
248 "@var{port} is guaranteed not to hang. If @var{port} is a file\n"
249 "port at end of file then @code{char-ready?} returns @code{#t}.\n"
c2dfff19
KR
250 "\n"
251 "@code{char-ready?} exists to make it possible for a\n"
1e6808ea
MG
252 "program to accept characters from interactive ports without\n"
253 "getting stuck waiting for input. Any input editors associated\n"
254 "with such ports must make sure that characters whose existence\n"
255 "has been asserted by @code{char-ready?} cannot be rubbed out.\n"
256 "If @code{char-ready?} were to return @code{#f} at end of file,\n"
257 "a port at end of file would be indistinguishable from an\n"
c2dfff19 258 "interactive port that has no ready characters.")
1bbd0b84 259#define FUNC_NAME s_scm_char_ready_p
0f2d19dd 260{
92c2555f 261 scm_t_port *pt;
6c951427 262
0f2d19dd 263 if (SCM_UNBNDP (port))
9de87eea 264 port = scm_current_input_port ();
0f2d19dd 265 else
34d19ef6 266 SCM_VALIDATE_OPINPORT (1, port);
d68fee48 267
ae4c4016
JB
268 pt = SCM_PTAB_ENTRY (port);
269
6c951427
GH
270 /* if the current read buffer is filled, or the
271 last pushed-back char has been read and the saved buffer is
272 filled, result is true. */
273 if (pt->read_pos < pt->read_end
274 || (pt->read_buf == pt->putback_buf
275 && pt->saved_read_pos < pt->saved_read_end))
0f2d19dd 276 return SCM_BOOL_T;
ee149d03
JB
277 else
278 {
92c2555f 279 scm_t_ptob_descriptor *ptob = &scm_ptobs[SCM_PTOBNUM (port)];
ee149d03 280
affc96b5 281 if (ptob->input_waiting)
7888309b 282 return scm_from_bool(ptob->input_waiting (port));
ee149d03 283 else
6c951427 284 return SCM_BOOL_T;
ee149d03 285 }
0f2d19dd 286}
1bbd0b84 287#undef FUNC_NAME
0f2d19dd 288
c2da2648
GH
289/* move up to read_len chars from port's putback and/or read buffers
290 into memory starting at dest. returns the number of chars moved. */
291size_t scm_take_from_input_buffers (SCM port, char *dest, size_t read_len)
292{
92c2555f 293 scm_t_port *pt = SCM_PTAB_ENTRY (port);
c2da2648
GH
294 size_t chars_read = 0;
295 size_t from_buf = min (pt->read_end - pt->read_pos, read_len);
296
297 if (from_buf > 0)
298 {
299 memcpy (dest, pt->read_pos, from_buf);
300 pt->read_pos += from_buf;
301 chars_read += from_buf;
302 read_len -= from_buf;
303 dest += from_buf;
304 }
305
306 /* if putback was active, try the real input buffer too. */
307 if (pt->read_buf == pt->putback_buf)
308 {
309 from_buf = min (pt->saved_read_end - pt->saved_read_pos, read_len);
310 if (from_buf > 0)
311 {
312 memcpy (dest, pt->saved_read_pos, from_buf);
313 pt->saved_read_pos += from_buf;
314 chars_read += from_buf;
315 }
316 }
317 return chars_read;
318}
319
6c951427 320/* Clear a port's read buffers, returning the contents. */
a1ec6916 321SCM_DEFINE (scm_drain_input, "drain-input", 1, 0, 0,
1bbd0b84 322 (SCM port),
4a151b3d
GH
323 "This procedure clears a port's input buffers, similar\n"
324 "to the way that force-output clears the output buffer. The\n"
325 "contents of the buffers are returned as a single string, e.g.,\n"
326 "\n"
327 "@lisp\n"
328 "(define p (open-input-file ...))\n"
329 "(drain-input p) => empty string, nothing buffered yet.\n"
330 "(unread-char (read-char p) p)\n"
331 "(drain-input p) => initial chars from p, up to the buffer size.\n"
332 "@end lisp\n\n"
333 "Draining the buffers may be useful for cleanly finishing\n"
334 "buffered I/O so that the file descriptor can be used directly\n"
335 "for further input.")
1bbd0b84 336#define FUNC_NAME s_scm_drain_input
ee149d03 337{
840ae05d 338 SCM result;
3a5fb14d 339 char *data;
28a6e1b0 340 scm_t_port *pt;
c014a02e 341 long count;
ee149d03 342
34d19ef6 343 SCM_VALIDATE_OPINPORT (1, port);
28a6e1b0 344 pt = SCM_PTAB_ENTRY (port);
840ae05d 345
6c951427
GH
346 count = pt->read_end - pt->read_pos;
347 if (pt->read_buf == pt->putback_buf)
348 count += pt->saved_read_end - pt->saved_read_pos;
840ae05d 349
3a5fb14d
MV
350 result = scm_i_make_string (count, &data);
351 scm_take_from_input_buffers (port, data, count);
840ae05d 352 return result;
ee149d03 353}
1bbd0b84 354#undef FUNC_NAME
0f2d19dd
JB
355
356\f
d68fee48 357/* Standard ports --- current input, output, error, and more(!). */
0f2d19dd 358
889975e5
MG
359static SCM cur_inport_fluid = 0;
360static SCM cur_outport_fluid = 0;
361static SCM cur_errport_fluid = 0;
362static SCM cur_loadport_fluid = 0;
9de87eea 363
3b3b36dd 364SCM_DEFINE (scm_current_input_port, "current-input-port", 0, 0, 0,
e1546b65
MG
365 (),
366 "Return the current input port. This is the default port used\n"
367 "by many input procedures. Initially, @code{current-input-port}\n"
368 "returns the @dfn{standard input} in Unix and C terminology.")
1bbd0b84 369#define FUNC_NAME s_scm_current_input_port
0f2d19dd 370{
889975e5
MG
371 if (cur_inport_fluid)
372 return scm_fluid_ref (cur_inport_fluid);
373 else
374 return SCM_BOOL_F;
0f2d19dd 375}
1bbd0b84 376#undef FUNC_NAME
0f2d19dd 377
3b3b36dd 378SCM_DEFINE (scm_current_output_port, "current-output-port", 0, 0, 0,
e1546b65
MG
379 (),
380 "Return the current output port. This is the default port used\n"
9401323e 381 "by many output procedures. Initially,\n"
e1546b65
MG
382 "@code{current-output-port} returns the @dfn{standard output} in\n"
383 "Unix and C terminology.")
1bbd0b84 384#define FUNC_NAME s_scm_current_output_port
0f2d19dd 385{
889975e5
MG
386 if (cur_outport_fluid)
387 return scm_fluid_ref (cur_outport_fluid);
388 else
389 return SCM_BOOL_F;
0f2d19dd 390}
1bbd0b84 391#undef FUNC_NAME
0f2d19dd 392
3b3b36dd 393SCM_DEFINE (scm_current_error_port, "current-error-port", 0, 0, 0,
1bbd0b84 394 (),
b380b885
MD
395 "Return the port to which errors and warnings should be sent (the\n"
396 "@dfn{standard error} in Unix and C terminology).")
1bbd0b84 397#define FUNC_NAME s_scm_current_error_port
0f2d19dd 398{
889975e5
MG
399 if (cur_errport_fluid)
400 return scm_fluid_ref (cur_errport_fluid);
401 else
402 return SCM_BOOL_F;
0f2d19dd 403}
1bbd0b84 404#undef FUNC_NAME
0f2d19dd 405
3b3b36dd 406SCM_DEFINE (scm_current_load_port, "current-load-port", 0, 0, 0,
e1546b65 407 (),
b450f070 408 "Return the current-load-port.\n"
e1546b65 409 "The load port is used internally by @code{primitive-load}.")
1bbd0b84 410#define FUNC_NAME s_scm_current_load_port
31614d8e 411{
9de87eea 412 return scm_fluid_ref (cur_loadport_fluid);
31614d8e 413}
1bbd0b84 414#undef FUNC_NAME
31614d8e 415
3b3b36dd 416SCM_DEFINE (scm_set_current_input_port, "set-current-input-port", 1, 0, 0,
1bbd0b84 417 (SCM port),
8f85c0c6
NJ
418 "@deffnx {Scheme Procedure} set-current-output-port port\n"
419 "@deffnx {Scheme Procedure} set-current-error-port port\n"
b380b885
MD
420 "Change the ports returned by @code{current-input-port},\n"
421 "@code{current-output-port} and @code{current-error-port}, respectively,\n"
422 "so that they use the supplied @var{port} for input or output.")
1bbd0b84 423#define FUNC_NAME s_scm_set_current_input_port
0f2d19dd 424{
9de87eea 425 SCM oinp = scm_fluid_ref (cur_inport_fluid);
34d19ef6 426 SCM_VALIDATE_OPINPORT (1, port);
9de87eea 427 scm_fluid_set_x (cur_inport_fluid, port);
0f2d19dd
JB
428 return oinp;
429}
1bbd0b84 430#undef FUNC_NAME
0f2d19dd
JB
431
432
3b3b36dd 433SCM_DEFINE (scm_set_current_output_port, "set-current-output-port", 1, 0, 0,
e1546b65
MG
434 (SCM port),
435 "Set the current default output port to @var{port}.")
1bbd0b84 436#define FUNC_NAME s_scm_set_current_output_port
0f2d19dd 437{
9de87eea 438 SCM ooutp = scm_fluid_ref (cur_outport_fluid);
78446828 439 port = SCM_COERCE_OUTPORT (port);
34d19ef6 440 SCM_VALIDATE_OPOUTPORT (1, port);
9de87eea 441 scm_fluid_set_x (cur_outport_fluid, port);
0f2d19dd
JB
442 return ooutp;
443}
1bbd0b84 444#undef FUNC_NAME
0f2d19dd
JB
445
446
3b3b36dd 447SCM_DEFINE (scm_set_current_error_port, "set-current-error-port", 1, 0, 0,
e1546b65
MG
448 (SCM port),
449 "Set the current default error port to @var{port}.")
1bbd0b84 450#define FUNC_NAME s_scm_set_current_error_port
0f2d19dd 451{
9de87eea 452 SCM oerrp = scm_fluid_ref (cur_errport_fluid);
78446828 453 port = SCM_COERCE_OUTPORT (port);
34d19ef6 454 SCM_VALIDATE_OPOUTPORT (1, port);
9de87eea 455 scm_fluid_set_x (cur_errport_fluid, port);
0f2d19dd
JB
456 return oerrp;
457}
1bbd0b84 458#undef FUNC_NAME
0f2d19dd 459
185e369a 460void
661ae7ab 461scm_dynwind_current_input_port (SCM port)
9de87eea 462#define FUNC_NAME NULL
185e369a 463{
9de87eea 464 SCM_VALIDATE_OPINPORT (1, port);
661ae7ab 465 scm_dynwind_fluid (cur_inport_fluid, port);
185e369a 466}
9de87eea 467#undef FUNC_NAME
185e369a
MV
468
469void
661ae7ab 470scm_dynwind_current_output_port (SCM port)
9de87eea 471#define FUNC_NAME NULL
185e369a 472{
9de87eea
MV
473 port = SCM_COERCE_OUTPORT (port);
474 SCM_VALIDATE_OPOUTPORT (1, port);
661ae7ab 475 scm_dynwind_fluid (cur_outport_fluid, port);
185e369a 476}
9de87eea 477#undef FUNC_NAME
185e369a
MV
478
479void
661ae7ab 480scm_dynwind_current_error_port (SCM port)
9de87eea
MV
481#define FUNC_NAME NULL
482{
483 port = SCM_COERCE_OUTPORT (port);
484 SCM_VALIDATE_OPOUTPORT (1, port);
661ae7ab 485 scm_dynwind_fluid (cur_errport_fluid, port);
9de87eea
MV
486}
487#undef FUNC_NAME
488
489void
661ae7ab 490scm_i_dynwind_current_load_port (SCM port)
185e369a 491{
661ae7ab 492 scm_dynwind_fluid (cur_loadport_fluid, port);
185e369a
MV
493}
494
0f2d19dd 495\f
840ae05d 496/* The port table --- an array of pointers to ports. */
0f2d19dd 497
5dbc6c06
HWN
498/*
499 We need a global registry of ports to flush them all at exit, and to
500 get all the ports matching a file descriptor.
501 */
502SCM scm_i_port_weak_hash;
0f2d19dd 503
9de87eea 504scm_i_pthread_mutex_t scm_i_port_table_mutex = SCM_I_PTHREAD_MUTEX_INITIALIZER;
b9ad392e 505
651a0735
LC
506\f
507/* Port finalization. */
508
1cc91f1b 509
651a0735
LC
510static void finalize_port (GC_PTR, GC_PTR);
511
512/* Register a finalizer for PORT, if needed by its port type. */
513static SCM_C_INLINE_KEYWORD void
514register_finalizer_for_port (SCM port)
515{
516 long port_type;
517
518 port_type = SCM_TC2PTOBNUM (SCM_CELL_TYPE (port));
519 if (scm_ptobs[port_type].free)
520 {
521 GC_finalization_proc prev_finalizer;
522 GC_PTR prev_finalization_data;
523
524 GC_REGISTER_FINALIZER_NO_ORDER (SCM2PTR (port), finalize_port, 0,
525 &prev_finalizer,
526 &prev_finalization_data);
527 }
528}
529
530/* Finalize the object (a port) pointed to by PTR. */
531static void
532finalize_port (GC_PTR ptr, GC_PTR data)
533{
534 long port_type;
535 SCM port = PTR2SCM (ptr);
536
537 if (!SCM_PORTP (port))
538 abort ();
539
540 if (SCM_OPENP (port))
541 {
542 if (SCM_REVEALED (port) > 0)
543 /* Keep "revealed" ports alive and re-register a finalizer. */
544 register_finalizer_for_port (port);
545 else
546 {
547 port_type = SCM_TC2PTOBNUM (SCM_CELL_TYPE (port));
548 if (port_type >= scm_numptob)
549 abort ();
550
551 if (scm_ptobs[port_type].free)
552 /* Yes, I really do mean `.free' rather than `.close'. `.close'
553 is for explicit `close-port' by user. */
554 scm_ptobs[port_type].free (port);
555
556 SCM_SETSTREAM (port, 0);
557 SCM_CLR_PORT_OPEN_FLAG (port);
651a0735
LC
558
559 scm_gc_ports_collected++;
560 }
561 }
562}
563
564
565
566\f
567
568/* This function is not and should not be thread safe. */
da220f27
HWN
569SCM
570scm_new_port_table_entry (scm_t_bits tag)
402788a9 571#define FUNC_NAME "scm_new_port_table_entry"
0f2d19dd 572{
85835e59
HWN
573 /*
574 We initialize the cell to empty, this is in case scm_gc_calloc
575 triggers GC ; we don't want the GC to scan a half-finished Z.
576 */
577
67329a9e 578 SCM z = scm_cons (SCM_EOL, SCM_EOL);
39e8f371 579 scm_t_port *entry = (scm_t_port *) scm_gc_calloc (sizeof (scm_t_port), "port");
889975e5 580 const char *enc;
5f16b897 581
840ae05d 582 entry->file_name = SCM_BOOL_F;
61e452ba 583 entry->rw_active = SCM_PORT_NEITHER;
5dbc6c06 584 entry->port = z;
889975e5
MG
585 /* Initialize this port with the thread's current default
586 encoding. */
587 if ((enc = scm_i_get_port_encoding (SCM_BOOL_F)) == NULL)
588 entry->encoding = NULL;
589 else
590 entry->encoding = strdup (enc);
591 entry->ilseq_handler = scm_i_get_conversion_strategy (SCM_BOOL_F);
5f16b897 592
5dbc6c06
HWN
593 SCM_SET_CELL_TYPE (z, tag);
594 SCM_SETPTAB_ENTRY (z, entry);
840ae05d 595
5dbc6c06 596 scm_hashq_set_x (scm_i_port_weak_hash, z, SCM_BOOL_F);
651a0735
LC
597
598 /* For each new port, register a finalizer so that it port type's free
599 function can be invoked eventually. */
600 register_finalizer_for_port (z);
601
da220f27 602 return z;
0f2d19dd 603}
c6c79933 604#undef FUNC_NAME
0f2d19dd 605
67329a9e
HWN
606#if SCM_ENABLE_DEPRECATED==1
607SCM_API scm_t_port *
608scm_add_to_port_table (SCM port)
609{
610 SCM z = scm_new_port_table_entry (scm_tc7_port);
611 scm_t_port * pt = SCM_PTAB_ENTRY(z);
612
613 pt->port = port;
5dbc6c06
HWN
614 SCM_SETCAR (z, SCM_EOL);
615 SCM_SETCDR (z, SCM_EOL);
85835e59 616 SCM_SETPTAB_ENTRY (port, pt);
67329a9e
HWN
617 return pt;
618}
619#endif
620
621
6c951427 622/* Remove a port from the table and destroy it. */
b9ad392e
MD
623
624/* This function is not and should not be thread safe. */
0f2d19dd 625void
5dbc6c06
HWN
626scm_i_remove_port (SCM port)
627#define FUNC_NAME "scm_remove_port"
0f2d19dd 628{
92c2555f 629 scm_t_port *p = SCM_PTAB_ENTRY (port);
6c951427 630 if (p->putback_buf)
4c9419ac 631 scm_gc_free (p->putback_buf, p->putback_buf_size, "putback buffer");
889975e5
MG
632 if (p->encoding)
633 {
634 free (p->encoding);
635 p->encoding = NULL;
636 }
4c9419ac 637 scm_gc_free (p, sizeof (scm_t_port), "port");
5dbc6c06 638
0f2d19dd 639 SCM_SETPTAB_ENTRY (port, 0);
5dbc6c06 640 scm_hashq_remove_x (scm_i_port_weak_hash, port);
0f2d19dd 641}
db4b4ca6
DH
642#undef FUNC_NAME
643
0f2d19dd 644
b450f070 645/* Functions for debugging. */
5dbc6c06 646#ifdef GUILE_DEBUG
3b3b36dd 647SCM_DEFINE (scm_pt_size, "pt-size", 0, 0, 0,
b450f070 648 (),
1e6808ea 649 "Return the number of ports in the port table. @code{pt-size}\n"
5352393c 650 "is only included in @code{--enable-guile-debug} builds.")
1bbd0b84 651#define FUNC_NAME s_scm_pt_size
0f2d19dd 652{
5dbc6c06 653 return scm_from_int (SCM_HASHTABLE_N_ITEMS (scm_i_port_weak_hash));
0f2d19dd 654}
1bbd0b84 655#undef FUNC_NAME
0f2d19dd
JB
656#endif
657
70df8af6 658void
92c2555f 659scm_port_non_buffer (scm_t_port *pt)
70df8af6
GH
660{
661 pt->read_pos = pt->read_buf = pt->read_end = &pt->shortbuf;
662 pt->write_buf = pt->write_pos = &pt->shortbuf;
663 pt->read_buf_size = pt->write_buf_size = 1;
664 pt->write_end = pt->write_buf + pt->write_buf_size;
665}
0f2d19dd 666
d68fee48
JB
667\f
668/* Revealed counts --- an oddity inherited from SCSH. */
669
8b13c6b3
GH
670/* Find a port in the table and return its revealed count.
671 Also used by the garbage collector.
0f2d19dd 672 */
1cc91f1b 673
0f2d19dd 674int
a284e297 675scm_revealed_count (SCM port)
0f2d19dd
JB
676{
677 return SCM_REVEALED(port);
678}
679
680
681
682/* Return the revealed count for a port. */
683
3b3b36dd 684SCM_DEFINE (scm_port_revealed, "port-revealed", 1, 0, 0,
1bbd0b84 685 (SCM port),
1e6808ea 686 "Return the revealed count for @var{port}.")
1bbd0b84 687#define FUNC_NAME s_scm_port_revealed
0f2d19dd 688{
78446828 689 port = SCM_COERCE_OUTPORT (port);
34d19ef6 690 SCM_VALIDATE_OPENPORT (1, port);
e11e83f3 691 return scm_from_int (scm_revealed_count (port));
0f2d19dd 692}
1bbd0b84 693#undef FUNC_NAME
0f2d19dd
JB
694
695/* Set the revealed count for a port. */
3b3b36dd 696SCM_DEFINE (scm_set_port_revealed_x, "set-port-revealed!", 2, 0, 0,
1bbd0b84 697 (SCM port, SCM rcount),
b450f070 698 "Sets the revealed count for a port to a given value.\n"
b380b885 699 "The return value is unspecified.")
1bbd0b84 700#define FUNC_NAME s_scm_set_port_revealed_x
0f2d19dd 701{
78446828 702 port = SCM_COERCE_OUTPORT (port);
34d19ef6 703 SCM_VALIDATE_OPENPORT (1, port);
a55c2b68 704 SCM_REVEALED (port) = scm_to_int (rcount);
8b13c6b3 705 return SCM_UNSPECIFIED;
0f2d19dd 706}
1bbd0b84 707#undef FUNC_NAME
0f2d19dd 708
d68fee48
JB
709
710\f
711/* Retrieving a port's mode. */
712
eadd48de
GH
713/* Return the flags that characterize a port based on the mode
714 * string used to open a file for that port.
715 *
716 * See PORT FLAGS in scm.h
717 */
718
3a5fb14d 719static long
889975e5 720scm_i_mode_bits_n (SCM modes)
3a5fb14d
MV
721{
722 return (SCM_OPN
889975e5
MG
723 | (scm_i_string_contains_char (modes, 'r')
724 || scm_i_string_contains_char (modes, '+') ? SCM_RDNG : 0)
725 | (scm_i_string_contains_char (modes, 'w')
726 || scm_i_string_contains_char (modes, 'a')
727 || scm_i_string_contains_char (modes, '+') ? SCM_WRTNG : 0)
728 | (scm_i_string_contains_char (modes, '0') ? SCM_BUF0 : 0)
729 | (scm_i_string_contains_char (modes, 'l') ? SCM_BUFLINE : 0));
3a5fb14d
MV
730}
731
eadd48de 732long
a284e297 733scm_mode_bits (char *modes)
eadd48de 734{
889975e5 735 return scm_i_mode_bits (scm_from_locale_string (modes));
eadd48de
GH
736}
737
d617ee18
MV
738long
739scm_i_mode_bits (SCM modes)
740{
741 long bits;
742
743 if (!scm_is_string (modes))
744 scm_wrong_type_arg_msg (NULL, 0, modes, "string");
745
889975e5 746 bits = scm_i_mode_bits_n (modes);
d617ee18
MV
747 scm_remember_upto_here_1 (modes);
748 return bits;
749}
eadd48de
GH
750
751/* Return the mode flags from an open port.
752 * Some modes such as "append" are only used when opening
753 * a file and are not returned here. */
754
3b3b36dd 755SCM_DEFINE (scm_port_mode, "port-mode", 1, 0, 0,
1bbd0b84 756 (SCM port),
1e6808ea
MG
757 "Return the port modes associated with the open port @var{port}.\n"
758 "These will not necessarily be identical to the modes used when\n"
759 "the port was opened, since modes such as \"append\" which are\n"
760 "used only during port creation are not retained.")
1bbd0b84 761#define FUNC_NAME s_scm_port_mode
eadd48de 762{
26a3038d 763 char modes[4];
eadd48de 764 modes[0] = '\0';
78446828
MV
765
766 port = SCM_COERCE_OUTPORT (port);
34d19ef6 767 SCM_VALIDATE_OPPORT (1, port);
f9a64404
DH
768 if (SCM_CELL_WORD_0 (port) & SCM_RDNG) {
769 if (SCM_CELL_WORD_0 (port) & SCM_WRTNG)
eadd48de
GH
770 strcpy (modes, "r+");
771 else
772 strcpy (modes, "r");
773 }
f9a64404 774 else if (SCM_CELL_WORD_0 (port) & SCM_WRTNG)
eadd48de 775 strcpy (modes, "w");
f9a64404 776 if (SCM_CELL_WORD_0 (port) & SCM_BUF0)
eadd48de 777 strcat (modes, "0");
3a5fb14d 778 return scm_from_locale_string (modes);
eadd48de 779}
1bbd0b84 780#undef FUNC_NAME
eadd48de
GH
781
782
d68fee48
JB
783\f
784/* Closing ports. */
785
0f2d19dd
JB
786/* scm_close_port
787 * Call the close operation on a port object.
eadd48de 788 * see also scm_close.
0f2d19dd 789 */
3b3b36dd 790SCM_DEFINE (scm_close_port, "close-port", 1, 0, 0,
1bbd0b84 791 (SCM port),
1e6808ea
MG
792 "Close the specified port object. Return @code{#t} if it\n"
793 "successfully closes a port or @code{#f} if it was already\n"
794 "closed. An exception may be raised if an error occurs, for\n"
795 "example when flushing buffered output. See also @ref{Ports and\n"
796 "File Descriptors, close}, for a procedure which can close file\n"
797 "descriptors.")
1bbd0b84 798#define FUNC_NAME s_scm_close_port
0f2d19dd 799{
1be6b49c 800 size_t i;
eadd48de
GH
801 int rv;
802
78446828
MV
803 port = SCM_COERCE_OUTPORT (port);
804
7a754ca6 805 SCM_VALIDATE_PORT (1, port);
0f2d19dd 806 if (SCM_CLOSEDP (port))
eadd48de 807 return SCM_BOOL_F;
0f2d19dd 808 i = SCM_PTOBNUM (port);
affc96b5
GH
809 if (scm_ptobs[i].close)
810 rv = (scm_ptobs[i].close) (port);
eadd48de
GH
811 else
812 rv = 0;
9de87eea 813 scm_i_scm_pthread_mutex_lock (&scm_i_port_table_mutex);
5dbc6c06 814 scm_i_remove_port (port);
9de87eea 815 scm_i_pthread_mutex_unlock (&scm_i_port_table_mutex);
22a52da1 816 SCM_CLR_PORT_OPEN_FLAG (port);
7888309b 817 return scm_from_bool (rv >= 0);
7a754ca6
MD
818}
819#undef FUNC_NAME
820
821SCM_DEFINE (scm_close_input_port, "close-input-port", 1, 0, 0,
822 (SCM port),
823 "Close the specified input port object. The routine has no effect if\n"
824 "the file has already been closed. An exception may be raised if an\n"
825 "error occurs. The value returned is unspecified.\n\n"
826 "See also @ref{Ports and File Descriptors, close}, for a procedure\n"
827 "which can close file descriptors.")
828#define FUNC_NAME s_scm_close_input_port
829{
830 SCM_VALIDATE_INPUT_PORT (1, port);
831 scm_close_port (port);
832 return SCM_UNSPECIFIED;
833}
834#undef FUNC_NAME
835
836SCM_DEFINE (scm_close_output_port, "close-output-port", 1, 0, 0,
837 (SCM port),
838 "Close the specified output port object. The routine has no effect if\n"
839 "the file has already been closed. An exception may be raised if an\n"
840 "error occurs. The value returned is unspecified.\n\n"
841 "See also @ref{Ports and File Descriptors, close}, for a procedure\n"
842 "which can close file descriptors.")
843#define FUNC_NAME s_scm_close_output_port
844{
845 port = SCM_COERCE_OUTPORT (port);
846 SCM_VALIDATE_OUTPUT_PORT (1, port);
847 scm_close_port (port);
848 return SCM_UNSPECIFIED;
0f2d19dd 849}
1bbd0b84 850#undef FUNC_NAME
0f2d19dd 851
5dbc6c06
HWN
852static SCM
853scm_i_collect_keys_in_vector (void *closure, SCM key, SCM value, SCM result)
854{
855 int *i = (int*) closure;
856 scm_c_vector_set_x (result, *i, key);
857 (*i)++;
858
859 return result;
860}
861
c536b4b3
MV
862void
863scm_c_port_for_each (void (*proc)(void *data, SCM p), void *data)
c2ca4493 864{
5dbc6c06 865 int i = 0;
3a5fb14d 866 size_t n;
fdfe6305
MV
867 SCM ports;
868
fdfe6305
MV
869 /* Even without pre-emptive multithreading, running arbitrary code
870 while scanning the port table is unsafe because the port table
3a5fb14d
MV
871 can change arbitrarily (from a GC, for example). So we first
872 collect the ports into a vector. -mvo */
fdfe6305 873
9de87eea 874 scm_i_scm_pthread_mutex_lock (&scm_i_port_table_mutex);
5dbc6c06 875 n = SCM_HASHTABLE_N_ITEMS (scm_i_port_weak_hash);
9de87eea 876 scm_i_pthread_mutex_unlock (&scm_i_port_table_mutex);
4057a3e0 877 ports = scm_c_make_vector (n, SCM_BOOL_F);
3a5fb14d 878
5dbc6c06
HWN
879 scm_i_pthread_mutex_lock (&scm_i_port_table_mutex);
880 ports = scm_internal_hash_fold (scm_i_collect_keys_in_vector, &i,
881 ports, scm_i_port_weak_hash);
9de87eea 882 scm_i_pthread_mutex_unlock (&scm_i_port_table_mutex);
3a5fb14d 883
5dbc6c06
HWN
884 for (i = 0; i < n; i++) {
885 SCM p = SCM_SIMPLE_VECTOR_REF (ports, i);
886 if (SCM_PORTP (p))
887 proc (data, p);
888 }
bd83658e
RB
889
890 scm_remember_upto_here_1 (ports);
c536b4b3 891}
fdfe6305 892
c536b4b3
MV
893SCM_DEFINE (scm_port_for_each, "port-for-each", 1, 0, 0,
894 (SCM proc),
895 "Apply @var{proc} to each port in the Guile port table\n"
896 "in turn. The return value is unspecified. More specifically,\n"
897 "@var{proc} is applied exactly once to every port that exists\n"
898 "in the system at the time @var{port-for-each} is invoked.\n"
899 "Changes to the port table while @var{port-for-each} is running\n"
900 "have no effect as far as @var{port-for-each} is concerned.")
901#define FUNC_NAME s_scm_port_for_each
902{
903 SCM_VALIDATE_PROC (1, proc);
904
905 scm_c_port_for_each ((void (*)(void*,SCM))scm_call_1, proc);
c2ca4493
GH
906 return SCM_UNSPECIFIED;
907}
908#undef FUNC_NAME
909
c536b4b3 910
d68fee48
JB
911\f
912/* Utter miscellany. Gosh, we should clean this up some time. */
913
3b3b36dd 914SCM_DEFINE (scm_input_port_p, "input-port?", 1, 0, 0,
1bbd0b84 915 (SCM x),
1e6808ea
MG
916 "Return @code{#t} if @var{x} is an input port, otherwise return\n"
917 "@code{#f}. Any object satisfying this predicate also satisfies\n"
918 "@code{port?}.")
1bbd0b84 919#define FUNC_NAME s_scm_input_port_p
0f2d19dd 920{
7888309b 921 return scm_from_bool (SCM_INPUT_PORT_P (x));
0f2d19dd 922}
1bbd0b84 923#undef FUNC_NAME
0f2d19dd 924
3b3b36dd 925SCM_DEFINE (scm_output_port_p, "output-port?", 1, 0, 0,
1bbd0b84 926 (SCM x),
1e6808ea
MG
927 "Return @code{#t} if @var{x} is an output port, otherwise return\n"
928 "@code{#f}. Any object satisfying this predicate also satisfies\n"
929 "@code{port?}.")
1bbd0b84 930#define FUNC_NAME s_scm_output_port_p
0f2d19dd 931{
82893676 932 x = SCM_COERCE_OUTPORT (x);
7888309b 933 return scm_from_bool (SCM_OUTPUT_PORT_P (x));
0f2d19dd 934}
1bbd0b84 935#undef FUNC_NAME
0f2d19dd 936
eb5c0a2a
GH
937SCM_DEFINE (scm_port_p, "port?", 1, 0, 0,
938 (SCM x),
1e6808ea 939 "Return a boolean indicating whether @var{x} is a port.\n"
5352393c
MG
940 "Equivalent to @code{(or (input-port? @var{x}) (output-port?\n"
941 "@var{x}))}.")
eb5c0a2a
GH
942#define FUNC_NAME s_scm_port_p
943{
7888309b 944 return scm_from_bool (SCM_PORTP (x));
eb5c0a2a
GH
945}
946#undef FUNC_NAME
947
3b3b36dd 948SCM_DEFINE (scm_port_closed_p, "port-closed?", 1, 0, 0,
1bbd0b84 949 (SCM port),
1e6808ea
MG
950 "Return @code{#t} if @var{port} is closed or @code{#f} if it is\n"
951 "open.")
1bbd0b84 952#define FUNC_NAME s_scm_port_closed_p
60d0643d 953{
34d19ef6 954 SCM_VALIDATE_PORT (1, port);
7888309b 955 return scm_from_bool (!SCM_OPPORTP (port));
60d0643d 956}
1bbd0b84 957#undef FUNC_NAME
0f2d19dd 958
3b3b36dd 959SCM_DEFINE (scm_eof_object_p, "eof-object?", 1, 0, 0,
1bbd0b84 960 (SCM x),
1e6808ea
MG
961 "Return @code{#t} if @var{x} is an end-of-file object; otherwise\n"
962 "return @code{#f}.")
1bbd0b84 963#define FUNC_NAME s_scm_eof_object_p
0f2d19dd 964{
7888309b 965 return scm_from_bool(SCM_EOF_OBJECT_P (x));
0f2d19dd 966}
1bbd0b84 967#undef FUNC_NAME
0f2d19dd 968
3b3b36dd 969SCM_DEFINE (scm_force_output, "force-output", 0, 1, 0,
1bbd0b84 970 (SCM port),
b380b885 971 "Flush the specified output port, or the current output port if @var{port}\n"
9401323e 972 "is omitted. The current output buffer contents are passed to the\n"
b380b885
MD
973 "underlying port implementation (e.g., in the case of fports, the\n"
974 "data will be written to the file and the output buffer will be cleared.)\n"
975 "It has no effect on an unbuffered port.\n\n"
976 "The return value is unspecified.")
1bbd0b84 977#define FUNC_NAME s_scm_force_output
0f2d19dd
JB
978{
979 if (SCM_UNBNDP (port))
9de87eea 980 port = scm_current_output_port ();
0f2d19dd 981 else
78446828
MV
982 {
983 port = SCM_COERCE_OUTPORT (port);
34d19ef6 984 SCM_VALIDATE_OPOUTPORT (1, port);
78446828 985 }
affc96b5 986 scm_flush (port);
ee149d03 987 return SCM_UNSPECIFIED;
0f2d19dd 988}
1bbd0b84 989#undef FUNC_NAME
0f2d19dd 990
5dbc6c06
HWN
991
992static void
61d3568b 993flush_output_port (void *closure, SCM port)
5dbc6c06 994{
5dbc6c06
HWN
995 if (SCM_OPOUTPORTP (port))
996 scm_flush (port);
997}
998
a1ec6916 999SCM_DEFINE (scm_flush_all_ports, "flush-all-ports", 0, 0, 0,
1bbd0b84 1000 (),
b380b885
MD
1001 "Equivalent to calling @code{force-output} on\n"
1002 "all open output ports. The return value is unspecified.")
1bbd0b84 1003#define FUNC_NAME s_scm_flush_all_ports
89ea5b7c 1004{
5dbc6c06 1005 scm_c_port_for_each (&flush_output_port, NULL);
89ea5b7c
GH
1006 return SCM_UNSPECIFIED;
1007}
1bbd0b84 1008#undef FUNC_NAME
0f2d19dd 1009
3b3b36dd 1010SCM_DEFINE (scm_read_char, "read-char", 0, 1, 0,
1bbd0b84 1011 (SCM port),
1e6808ea
MG
1012 "Return the next character available from @var{port}, updating\n"
1013 "@var{port} to point to the following character. If no more\n"
1014 "characters are available, the end-of-file object is returned.")
1bbd0b84 1015#define FUNC_NAME s_scm_read_char
0f2d19dd 1016{
889975e5 1017 scm_t_wchar c;
0f2d19dd 1018 if (SCM_UNBNDP (port))
9de87eea 1019 port = scm_current_input_port ();
34d19ef6 1020 SCM_VALIDATE_OPINPORT (1, port);
b7f3516f 1021 c = scm_getc (port);
0f2d19dd
JB
1022 if (EOF == c)
1023 return SCM_EOF_VAL;
7866a09b 1024 return SCM_MAKE_CHAR (c);
0f2d19dd 1025}
1bbd0b84 1026#undef FUNC_NAME
0f2d19dd 1027
889975e5
MG
1028#define SCM_MBCHAR_BUF_SIZE (4)
1029
1030/* Get one codepoint from a file, using the port's encoding. */
1031scm_t_wchar
1032scm_getc (SCM port)
1033{
1034 int c;
1035 unsigned int bufcount = 0;
1036 char buf[SCM_MBCHAR_BUF_SIZE];
1037 scm_t_wchar codepoint = 0;
1038 scm_t_uint32 *u32;
1039 size_t u32len;
1040 scm_t_port *pt = SCM_PTAB_ENTRY (port);
1041
1042 c = scm_get_byte_or_eof (port);
1043 if (c == EOF)
1044 return (scm_t_wchar) EOF;
1045
1046 buf[0] = c;
1047 bufcount++;
1048
1049 if (pt->encoding == NULL)
1050 {
1051 /* The encoding is Latin-1: bytes are characters. */
8736ef70 1052 codepoint = (unsigned char) buf[0];
889975e5
MG
1053 goto success;
1054 }
1055
1056 for (;;)
1057 {
1058 u32 = u32_conv_from_encoding (pt->encoding,
1059 (enum iconv_ilseq_handler) pt->ilseq_handler,
1060 buf, bufcount, NULL, NULL, &u32len);
1061 if (u32 == NULL || u32len == 0)
1062 {
1063 if (errno == ENOMEM)
1064 scm_memory_error ("Input decoding");
1065
1066 /* Otherwise errno is EILSEQ or EINVAL, so perhaps more
1067 bytes are needed. Keep looping. */
1068 }
1069 else
1070 {
1071 /* Complete codepoint found. */
1072 codepoint = u32[0];
1073 free (u32);
1074 goto success;
1075 }
1076
1077 if (bufcount == SCM_MBCHAR_BUF_SIZE)
1078 {
1079 /* We've read several bytes and didn't find a good
1080 codepoint. Give up. */
1081 goto failure;
1082 }
1083
1084 c = scm_get_byte_or_eof (port);
1085
1086 if (c == EOF)
1087 {
1088 /* EOF before a complete character was read. Push it all
1089 back and return EOF. */
1090 while (bufcount > 0)
1091 {
1092 /* FIXME: this will probably cause errors in the port column. */
1093 scm_unget_byte (buf[bufcount-1], port);
1094 bufcount --;
1095 }
1096 return EOF;
1097 }
1098
1099 if (c == '\n')
1100 {
1101 /* It is always invalid to have EOL in the middle of a
1102 multibyte character. */
1103 scm_unget_byte ('\n', port);
1104 goto failure;
1105 }
1106
1107 buf[bufcount++] = c;
1108 }
1109
1110 success:
1111 switch (codepoint)
1112 {
1113 case '\a':
1114 break;
1115 case '\b':
1116 SCM_DECCOL (port);
1117 break;
1118 case '\n':
1119 SCM_INCLINE (port);
1120 break;
1121 case '\r':
1122 SCM_ZEROCOL (port);
1123 break;
1124 case '\t':
1125 SCM_TABCOL (port);
1126 break;
1127 default:
1128 SCM_INCCOL (port);
1129 break;
1130 }
1131
1132 return codepoint;
1133
1134 failure:
1135 {
1136 char *err_buf;
1137 SCM err_str = scm_i_make_string (bufcount, &err_buf);
1138 memcpy (err_buf, buf, bufcount);
1139
1140 if (errno == EILSEQ)
1141 scm_misc_error (NULL, "input encoding error for ~s: ~s",
1142 scm_list_2 (scm_from_locale_string (scm_i_get_port_encoding (port)),
1143 err_str));
1144 else
1145 scm_misc_error (NULL, "input encoding error (invalid) for ~s: ~s\n",
1146 scm_list_2 (scm_from_locale_string (scm_i_get_port_encoding (port)),
1147 err_str));
1148 }
1149
1150 /* Never gets here. */
1151 return 0;
1152}
1153
1154
5c070ca7 1155/* this should only be called when the read buffer is empty. it
affc96b5 1156 tries to refill the read buffer. it returns the first char from
5c070ca7 1157 the port, which is either EOF or *(pt->read_pos). */
6c951427 1158int
affc96b5 1159scm_fill_input (SCM port)
6c951427 1160{
92c2555f 1161 scm_t_port *pt = SCM_PTAB_ENTRY (port);
283a1a0e 1162
b5cb4464
NJ
1163 assert (pt->read_pos == pt->read_end);
1164
6c951427
GH
1165 if (pt->read_buf == pt->putback_buf)
1166 {
1167 /* finished reading put-back chars. */
1168 pt->read_buf = pt->saved_read_buf;
1169 pt->read_pos = pt->saved_read_pos;
1170 pt->read_end = pt->saved_read_end;
1171 pt->read_buf_size = pt->saved_read_buf_size;
1172 if (pt->read_pos < pt->read_end)
5c070ca7 1173 return *(pt->read_pos);
6c951427 1174 }
affc96b5 1175 return scm_ptobs[SCM_PTOBNUM (port)].fill_input (port);
6c951427
GH
1176}
1177
3cb988bd 1178
6fe692e9
MD
1179/* scm_lfwrite
1180 *
53802ea8
MV
1181 * This function differs from scm_c_write; it updates port line and
1182 * column. */
6fe692e9 1183
9c44cd45
MG
1184static void
1185update_port_lf (scm_t_wchar c, SCM port)
1186{
1187 if (c == '\a')
b0799290 1188 ; /* Do nothing. */
9c44cd45 1189 else if (c == '\b')
b0799290 1190 SCM_DECCOL (port);
9c44cd45 1191 else if (c == '\n')
b0799290 1192 SCM_INCLINE (port);
9c44cd45 1193 else if (c == '\r')
b0799290 1194 SCM_ZEROCOL (port);
9c44cd45 1195 else if (c == '\t')
b0799290 1196 SCM_TABCOL (port);
9c44cd45 1197 else
b0799290 1198 SCM_INCCOL (port);
9c44cd45
MG
1199}
1200
1201void
1be6b49c 1202scm_lfwrite (const char *ptr, size_t size, SCM port)
ee149d03 1203{
92c2555f
MV
1204 scm_t_port *pt = SCM_PTAB_ENTRY (port);
1205 scm_t_ptob_descriptor *ptob = &scm_ptobs[SCM_PTOBNUM (port)];
3e2043c4 1206
840ae05d 1207 if (pt->rw_active == SCM_PORT_READ)
affc96b5 1208 scm_end_input (port);
283a1a0e 1209
31703ab8 1210 ptob->write (port, ptr, size);
840ae05d 1211
9c44cd45
MG
1212 for (; size; ptr++, size--)
1213 update_port_lf ((scm_t_wchar) (unsigned char) *ptr, port);
1214
1215 if (pt->rw_random)
1216 pt->rw_active = SCM_PORT_WRITE;
1217}
1218
1219/* Write a scheme string STR to PORT from START inclusive to END
1220 exclusive. */
1221void
1222scm_lfwrite_substr (SCM str, size_t start, size_t end, SCM port)
1223{
1224 size_t i, size = scm_i_string_length (str);
1225 scm_t_port *pt = SCM_PTAB_ENTRY (port);
1226 scm_t_ptob_descriptor *ptob = &scm_ptobs[SCM_PTOBNUM (port)];
1227 scm_t_wchar p;
1228 char *buf;
1229 size_t len;
1230
1231 if (pt->rw_active == SCM_PORT_READ)
1232 scm_end_input (port);
1233
bd4911ef 1234 if (end == (size_t) (-1))
9c44cd45
MG
1235 end = size;
1236 size = end - start;
1237
06b96190
MG
1238 /* Note that making a substring will likely take the
1239 stringbuf_write_mutex. So, one shouldn't use scm_lfwrite_substr
1240 if the stringbuf write mutex may still be held elsewhere. */
9c44cd45 1241 buf = scm_to_stringn (scm_c_substring (str, start, end), &len,
889975e5 1242 pt->encoding, pt->ilseq_handler);
9c44cd45
MG
1243 ptob->write (port, buf, len);
1244 free (buf);
1245
1246 for (i = 0; i < size; i++)
1247 {
1248 p = scm_i_string_ref (str, i + start);
1249 update_port_lf (p, port);
53802ea8 1250 }
53802ea8 1251
840ae05d
JB
1252 if (pt->rw_random)
1253 pt->rw_active = SCM_PORT_WRITE;
ee149d03 1254}
3cb988bd 1255
9c44cd45
MG
1256/* Write a scheme string STR to PORT. */
1257void
1258scm_lfwrite_str (SCM str, SCM port)
1259{
06b96190
MG
1260 size_t i, size = scm_i_string_length (str);
1261 scm_t_port *pt = SCM_PTAB_ENTRY (port);
1262 scm_t_ptob_descriptor *ptob = &scm_ptobs[SCM_PTOBNUM (port)];
1263 scm_t_wchar p;
1264 char *buf;
1265 size_t len;
1266
1267 if (pt->rw_active == SCM_PORT_READ)
1268 scm_end_input (port);
1269
1270 buf = scm_to_stringn (str, &len,
889975e5 1271 pt->encoding, pt->ilseq_handler);
06b96190
MG
1272 ptob->write (port, buf, len);
1273 free (buf);
1274
1275 for (i = 0; i < size; i++)
1276 {
1277 p = scm_i_string_ref (str, i);
1278 update_port_lf (p, port);
1279 }
1280
1281 if (pt->rw_random)
1282 pt->rw_active = SCM_PORT_WRITE;
9c44cd45
MG
1283}
1284
6fe692e9
MD
1285/* scm_c_read
1286 *
1287 * Used by an application to read arbitrary number of bytes from an
1288 * SCM port. Same semantics as libc read, except that scm_c_read only
1289 * returns less than SIZE bytes if at end-of-file.
1290 *
1291 * Warning: Doesn't update port line and column counts! */
1292
b5cb4464
NJ
1293/* This structure, and the following swap_buffer function, are used
1294 for temporarily swapping a port's own read buffer, and the buffer
1295 that the caller of scm_c_read provides. */
1296struct port_and_swap_buffer
1297{
1298 scm_t_port *pt;
1299 unsigned char *buffer;
1300 size_t size;
1301};
1302
1303static void
1304swap_buffer (void *data)
1305{
1306 struct port_and_swap_buffer *psb = (struct port_and_swap_buffer *) data;
1307 unsigned char *old_buf = psb->pt->read_buf;
1308 size_t old_size = psb->pt->read_buf_size;
1309
1310 /* Make the port use (buffer, size) from the struct. */
1311 psb->pt->read_pos = psb->pt->read_buf = psb->pt->read_end = psb->buffer;
1312 psb->pt->read_buf_size = psb->size;
1313
1314 /* Save the port's old (buffer, size) in the struct. */
1315 psb->buffer = old_buf;
1316 psb->size = old_size;
1317}
1318
1be6b49c
ML
1319size_t
1320scm_c_read (SCM port, void *buffer, size_t size)
693758d5 1321#define FUNC_NAME "scm_c_read"
6fe692e9 1322{
693758d5 1323 scm_t_port *pt;
1be6b49c 1324 size_t n_read = 0, n_available;
b5cb4464 1325 struct port_and_swap_buffer psb;
6fe692e9 1326
693758d5
LC
1327 SCM_VALIDATE_OPINPORT (1, port);
1328
1329 pt = SCM_PTAB_ENTRY (port);
6fe692e9
MD
1330 if (pt->rw_active == SCM_PORT_WRITE)
1331 scm_ptobs[SCM_PTOBNUM (port)].flush (port);
1332
1333 if (pt->rw_random)
1334 pt->rw_active = SCM_PORT_READ;
1335
b5cb4464
NJ
1336 /* Take bytes first from the port's read buffer. */
1337 if (pt->read_pos < pt->read_end)
6fe692e9 1338 {
b5cb4464 1339 n_available = min (size, pt->read_end - pt->read_pos);
6fe692e9 1340 memcpy (buffer, pt->read_pos, n_available);
910d1e40 1341 buffer = (char *) buffer + n_available;
6fe692e9
MD
1342 pt->read_pos += n_available;
1343 n_read += n_available;
6fe692e9 1344 size -= n_available;
6fe692e9
MD
1345 }
1346
b5cb4464
NJ
1347 /* Avoid the scm_dynwind_* costs if we now have enough data. */
1348 if (size == 0)
1349 return n_read;
1350
1351 /* Now we will call scm_fill_input repeatedly until we have read the
1352 requested number of bytes. (Note that a single scm_fill_input
1353 call does not guarantee to fill the whole of the port's read
6d227556 1354 buffer.) */
75192345 1355 if (pt->read_buf_size <= 1 && pt->encoding == NULL)
b5cb4464 1356 {
6d227556
NJ
1357 /* The port that we are reading from is unbuffered - i.e. does
1358 not have its own persistent buffer - but we have a buffer,
1359 provided by our caller, that is the right size for the data
1360 that is wanted. For the following scm_fill_input calls,
1361 therefore, we use the buffer in hand as the port's read
1362 buffer.
1363
1364 We need to make sure that the port's normal (1 byte) buffer
1365 is reinstated in case one of the scm_fill_input () calls
1366 throws an exception; we use the scm_dynwind_* API to achieve
75192345
MG
1367 that.
1368
1369 A consequence of this optimization is that the fill_input
1370 functions can't unget characters. That'll push data to the
1371 pushback buffer instead of this psb buffer. */
1372#if SCM_DEBUG == 1
1373 unsigned char *pback = pt->putback_buf;
1374#endif
6d227556
NJ
1375 psb.pt = pt;
1376 psb.buffer = buffer;
1377 psb.size = size;
1378 scm_dynwind_begin (SCM_F_DYNWIND_REWINDABLE);
1379 scm_dynwind_rewind_handler (swap_buffer, &psb, SCM_F_WIND_EXPLICITLY);
1380 scm_dynwind_unwind_handler (swap_buffer, &psb, SCM_F_WIND_EXPLICITLY);
1381
1382 /* Call scm_fill_input until we have all the bytes that we need,
1383 or we hit EOF. */
1384 while (pt->read_buf_size && (scm_fill_input (port) != EOF))
1385 {
1386 pt->read_buf_size -= (pt->read_end - pt->read_pos);
1387 pt->read_pos = pt->read_buf = pt->read_end;
1388 }
75192345
MG
1389#if SCM_DEBUG == 1
1390 if (pback != pt->putback_buf
1391 || pt->read_buf - (unsigned char *) buffer < 0)
1392 scm_misc_error (FUNC_NAME,
1393 "scm_c_read must not call a fill function that pushes "
1394 "back characters onto an unbuffered port", SCM_EOL);
1395#endif
6d227556 1396 n_read += pt->read_buf - (unsigned char *) buffer;
75192345 1397
6d227556
NJ
1398 /* Reinstate the port's normal buffer. */
1399 scm_dynwind_end ();
1400 }
1401 else
1402 {
1403 /* The port has its own buffer. It is important that we use it,
1404 even if it happens to be smaller than our caller's buffer, so
1405 that a custom port implementation's entry points (in
1406 particular, fill_input) can rely on the buffer always being
1407 the same as they first set up. */
1408 while (size && (scm_fill_input (port) != EOF))
1409 {
1410 n_available = min (size, pt->read_end - pt->read_pos);
1411 memcpy (buffer, pt->read_pos, n_available);
1412 buffer = (char *) buffer + n_available;
1413 pt->read_pos += n_available;
1414 n_read += n_available;
1415 size -= n_available;
1416 }
1417 }
6fe692e9 1418
b5cb4464 1419 return n_read;
6fe692e9 1420}
693758d5 1421#undef FUNC_NAME
6fe692e9
MD
1422
1423/* scm_c_write
1424 *
1425 * Used by an application to write arbitrary number of bytes to an SCM
1426 * port. Similar semantics as libc write. However, unlike libc
1427 * write, scm_c_write writes the requested number of bytes and has no
1428 * return value.
1429 *
1430 * Warning: Doesn't update port line and column counts!
1431 */
1432
693758d5 1433void
1be6b49c 1434scm_c_write (SCM port, const void *ptr, size_t size)
693758d5 1435#define FUNC_NAME "scm_c_write"
6fe692e9 1436{
693758d5
LC
1437 scm_t_port *pt;
1438 scm_t_ptob_descriptor *ptob;
1439
1440 SCM_VALIDATE_OPOUTPORT (1, port);
1441
1442 pt = SCM_PTAB_ENTRY (port);
1443 ptob = &scm_ptobs[SCM_PTOBNUM (port)];
6fe692e9
MD
1444
1445 if (pt->rw_active == SCM_PORT_READ)
1446 scm_end_input (port);
1447
1448 ptob->write (port, ptr, size);
1449
1450 if (pt->rw_random)
1451 pt->rw_active = SCM_PORT_WRITE;
1452}
693758d5 1453#undef FUNC_NAME
3cb988bd 1454
fca43887 1455void
a284e297 1456scm_flush (SCM port)
ee149d03 1457{
c014a02e 1458 long i = SCM_PTOBNUM (port);
7f2a6c38 1459 assert (i >= 0);
affc96b5 1460 (scm_ptobs[i].flush) (port);
ee149d03
JB
1461}
1462
283a1a0e 1463void
a284e297 1464scm_end_input (SCM port)
283a1a0e 1465{
c014a02e 1466 long offset;
92c2555f 1467 scm_t_port *pt = SCM_PTAB_ENTRY (port);
283a1a0e
GH
1468
1469 if (pt->read_buf == pt->putback_buf)
1470 {
1471 offset = pt->read_end - pt->read_pos;
1472 pt->read_buf = pt->saved_read_buf;
1473 pt->read_pos = pt->saved_read_pos;
1474 pt->read_end = pt->saved_read_end;
1475 pt->read_buf_size = pt->saved_read_buf_size;
1476 }
1477 else
1478 offset = 0;
1479
affc96b5 1480 scm_ptobs[SCM_PTOBNUM (port)].end_input (port, offset);
283a1a0e
GH
1481}
1482
ee149d03
JB
1483\f
1484
1485
1486void
889975e5
MG
1487scm_unget_byte (int c, SCM port)
1488#define FUNC_NAME "scm_unget_byte"
ee149d03 1489{
92c2555f 1490 scm_t_port *pt = SCM_PTAB_ENTRY (port);
840ae05d 1491
6c951427
GH
1492 if (pt->read_buf == pt->putback_buf)
1493 /* already using the put-back buffer. */
1494 {
1495 /* enlarge putback_buf if necessary. */
1496 if (pt->read_end == pt->read_buf + pt->read_buf_size
1497 && pt->read_buf == pt->read_pos)
1498 {
1be6b49c 1499 size_t new_size = pt->read_buf_size * 2;
c6c79933 1500 unsigned char *tmp = (unsigned char *)
92d8fd32
LC
1501 /* XXX: Can we use `GC_REALLOC' with `GC_MALLOC_ATOMIC'-allocated
1502 data? (Ludo) */
4c9419ac
MV
1503 scm_gc_realloc (pt->putback_buf, pt->read_buf_size, new_size,
1504 "putback buffer");
6c951427 1505
6c951427
GH
1506 pt->read_pos = pt->read_buf = pt->putback_buf = tmp;
1507 pt->read_end = pt->read_buf + pt->read_buf_size;
1508 pt->read_buf_size = pt->putback_buf_size = new_size;
1509 }
1510
1511 /* shift any existing bytes to buffer + 1. */
1512 if (pt->read_pos == pt->read_end)
1513 pt->read_end = pt->read_buf + 1;
1514 else if (pt->read_pos != pt->read_buf + 1)
1515 {
1516 int count = pt->read_end - pt->read_pos;
1517
1518 memmove (pt->read_buf + 1, pt->read_pos, count);
1519 pt->read_end = pt->read_buf + 1 + count;
1520 }
1521
1522 pt->read_pos = pt->read_buf;
1523 }
1524 else
1525 /* switch to the put-back buffer. */
1526 {
1527 if (pt->putback_buf == NULL)
1528 {
c357d546 1529 pt->putback_buf
92d8fd32
LC
1530 = (unsigned char *) scm_gc_malloc_pointerless
1531 (SCM_INITIAL_PUTBACK_BUF_SIZE, "putback buffer");
6c951427
GH
1532 pt->putback_buf_size = SCM_INITIAL_PUTBACK_BUF_SIZE;
1533 }
1534
1535 pt->saved_read_buf = pt->read_buf;
1536 pt->saved_read_pos = pt->read_pos;
1537 pt->saved_read_end = pt->read_end;
1538 pt->saved_read_buf_size = pt->read_buf_size;
1539
1540 pt->read_pos = pt->read_buf = pt->putback_buf;
1541 pt->read_end = pt->read_buf + 1;
1542 pt->read_buf_size = pt->putback_buf_size;
1543 }
1544
1545 *pt->read_buf = c;
ee149d03 1546
840ae05d
JB
1547 if (pt->rw_random)
1548 pt->rw_active = SCM_PORT_READ;
889975e5
MG
1549}
1550#undef FUNC_NAME
1551
1552void
1553scm_ungetc (scm_t_wchar c, SCM port)
1554#define FUNC_NAME "scm_ungetc"
1555{
1556 scm_t_port *pt = SCM_PTAB_ENTRY (port);
1557 scm_t_wchar *wbuf;
1558 SCM str = scm_i_make_wide_string (1, &wbuf);
1559 char *buf;
1560 size_t len;
1561 int i;
1562
1563 wbuf[0] = c;
1564 buf = scm_to_stringn (str, &len, pt->encoding, pt->ilseq_handler);
1565
1566 for (i = len - 1; i >= 0; i--)
1567 scm_unget_byte (buf[i], port);
840ae05d 1568
ee149d03
JB
1569 if (c == '\n')
1570 {
1571 /* What should col be in this case?
1572 * We'll leave it at -1.
1573 */
1574 SCM_LINUM (port) -= 1;
1575 }
1576 else
1577 SCM_COL(port) -= 1;
1578}
c6c79933 1579#undef FUNC_NAME
ee149d03
JB
1580
1581
1582void
70d63753 1583scm_ungets (const char *s, int n, SCM port)
ee149d03
JB
1584{
1585 /* This is simple minded and inefficient, but unreading strings is
1586 * probably not a common operation, and remember that line and
1587 * column numbers have to be handled...
1588 *
1589 * Please feel free to write an optimized version!
1590 */
1591 while (n--)
1592 scm_ungetc (s[n], port);
1593}
1594
1595
3b3b36dd 1596SCM_DEFINE (scm_peek_char, "peek-char", 0, 1, 0,
1bbd0b84 1597 (SCM port),
1e6808ea
MG
1598 "Return the next character available from @var{port},\n"
1599 "@emph{without} updating @var{port} to point to the following\n"
1600 "character. If no more characters are available, the\n"
c2dfff19
KR
1601 "end-of-file object is returned.\n"
1602 "\n"
1603 "The value returned by\n"
1e6808ea
MG
1604 "a call to @code{peek-char} is the same as the value that would\n"
1605 "have been returned by a call to @code{read-char} on the same\n"
1606 "port. The only difference is that the very next call to\n"
1607 "@code{read-char} or @code{peek-char} on that @var{port} will\n"
1608 "return the value returned by the preceding call to\n"
1609 "@code{peek-char}. In particular, a call to @code{peek-char} on\n"
1610 "an interactive port will hang waiting for input whenever a call\n"
c2dfff19 1611 "to @code{read-char} would have hung.")
1bbd0b84 1612#define FUNC_NAME s_scm_peek_char
ee149d03 1613{
889975e5 1614 scm_t_wchar c, column;
ee149d03 1615 if (SCM_UNBNDP (port))
9de87eea 1616 port = scm_current_input_port ();
ee149d03 1617 else
34d19ef6 1618 SCM_VALIDATE_OPINPORT (1, port);
1a973c42 1619 column = SCM_COL(port);
ee149d03
JB
1620 c = scm_getc (port);
1621 if (EOF == c)
1622 return SCM_EOF_VAL;
1623 scm_ungetc (c, port);
1a973c42 1624 SCM_COL(port) = column;
7866a09b 1625 return SCM_MAKE_CHAR (c);
3cb988bd 1626}
1bbd0b84 1627#undef FUNC_NAME
3cb988bd 1628
1be4270a 1629SCM_DEFINE (scm_unread_char, "unread-char", 1, 1, 0,
1bbd0b84 1630 (SCM cobj, SCM port),
b380b885
MD
1631 "Place @var{char} in @var{port} so that it will be read by the\n"
1632 "next read operation. If called multiple times, the unread characters\n"
1633 "will be read again in last-in first-out order. If @var{port} is\n"
1634 "not supplied, the current input port is used.")
1bbd0b84 1635#define FUNC_NAME s_scm_unread_char
0f2d19dd
JB
1636{
1637 int c;
1638
34d19ef6 1639 SCM_VALIDATE_CHAR (1, cobj);
0f2d19dd 1640 if (SCM_UNBNDP (port))
9de87eea 1641 port = scm_current_input_port ();
0f2d19dd 1642 else
34d19ef6 1643 SCM_VALIDATE_OPINPORT (2, port);
0f2d19dd 1644
7866a09b 1645 c = SCM_CHAR (cobj);
0f2d19dd 1646
b7f3516f 1647 scm_ungetc (c, port);
0f2d19dd
JB
1648 return cobj;
1649}
1bbd0b84 1650#undef FUNC_NAME
0f2d19dd 1651
a1ec6916 1652SCM_DEFINE (scm_unread_string, "unread-string", 2, 0, 0,
1bbd0b84 1653 (SCM str, SCM port),
b380b885
MD
1654 "Place the string @var{str} in @var{port} so that its characters will be\n"
1655 "read in subsequent read operations. If called multiple times, the\n"
1656 "unread characters will be read again in last-in first-out order. If\n"
1657 "@var{port} is not supplied, the current-input-port is used.")
1bbd0b84 1658#define FUNC_NAME s_scm_unread_string
ee1e7e13 1659{
889975e5 1660 int n;
34d19ef6 1661 SCM_VALIDATE_STRING (1, str);
ee1e7e13 1662 if (SCM_UNBNDP (port))
9de87eea 1663 port = scm_current_input_port ();
ee1e7e13 1664 else
34d19ef6 1665 SCM_VALIDATE_OPINPORT (2, port);
ee1e7e13 1666
889975e5
MG
1667 n = scm_i_string_length (str);
1668
1669 while (n--)
1670 scm_ungetc (scm_i_string_ref (str, n), port);
ee1e7e13
MD
1671
1672 return str;
1673}
1bbd0b84 1674#undef FUNC_NAME
ee1e7e13 1675
a1ec6916 1676SCM_DEFINE (scm_seek, "seek", 3, 0, 0,
1e6808ea
MG
1677 (SCM fd_port, SCM offset, SCM whence),
1678 "Sets the current position of @var{fd/port} to the integer\n"
1679 "@var{offset}, which is interpreted according to the value of\n"
1680 "@var{whence}.\n"
1681 "\n"
1682 "One of the following variables should be supplied for\n"
1683 "@var{whence}:\n"
b380b885
MD
1684 "@defvar SEEK_SET\n"
1685 "Seek from the beginning of the file.\n"
1686 "@end defvar\n"
1687 "@defvar SEEK_CUR\n"
1688 "Seek from the current position.\n"
1689 "@end defvar\n"
1690 "@defvar SEEK_END\n"
1691 "Seek from the end of the file.\n"
1e6808ea
MG
1692 "@end defvar\n"
1693 "If @var{fd/port} is a file descriptor, the underlying system\n"
1694 "call is @code{lseek}. @var{port} may be a string port.\n"
1695 "\n"
1696 "The value returned is the new position in the file. This means\n"
1697 "that the current position of a port can be obtained using:\n"
1698 "@lisp\n"
b380b885 1699 "(seek port 0 SEEK_CUR)\n"
1e6808ea 1700 "@end lisp")
1bbd0b84 1701#define FUNC_NAME s_scm_seek
840ae05d 1702{
840ae05d
JB
1703 int how;
1704
1e6808ea 1705 fd_port = SCM_COERCE_OUTPORT (fd_port);
840ae05d 1706
a55c2b68 1707 how = scm_to_int (whence);
840ae05d 1708 if (how != SEEK_SET && how != SEEK_CUR && how != SEEK_END)
1bbd0b84 1709 SCM_OUT_OF_RANGE (3, whence);
23f2b9a3 1710
0a94eb00 1711 if (SCM_OPPORTP (fd_port))
840ae05d 1712 {
92c2555f 1713 scm_t_ptob_descriptor *ptob = scm_ptobs + SCM_PTOBNUM (fd_port);
f1ce9199
LC
1714 off_t_or_off64_t off = scm_to_off_t_or_off64_t (offset);
1715 off_t_or_off64_t rv;
840ae05d
JB
1716
1717 if (!ptob->seek)
1bbd0b84 1718 SCM_MISC_ERROR ("port is not seekable",
1e6808ea 1719 scm_cons (fd_port, SCM_EOL));
840ae05d 1720 else
1e6808ea 1721 rv = ptob->seek (fd_port, off, how);
f1ce9199 1722 return scm_from_off_t_or_off64_t (rv);
840ae05d
JB
1723 }
1724 else /* file descriptor?. */
1725 {
23f2b9a3
KR
1726 off_t_or_off64_t off = scm_to_off_t_or_off64_t (offset);
1727 off_t_or_off64_t rv;
1728 rv = lseek_or_lseek64 (scm_to_int (fd_port), off, how);
840ae05d 1729 if (rv == -1)
1bbd0b84 1730 SCM_SYSERROR;
23f2b9a3 1731 return scm_from_off_t_or_off64_t (rv);
840ae05d 1732 }
840ae05d 1733}
1bbd0b84 1734#undef FUNC_NAME
840ae05d 1735
8ab3d8a0
KR
1736#ifndef O_BINARY
1737#define O_BINARY 0
1738#endif
1739
1740/* Mingw has ftruncate(), perhaps implemented above using chsize, but
1741 doesn't have the filename version truncate(), hence this code. */
1742#if HAVE_FTRUNCATE && ! HAVE_TRUNCATE
1743static int
1744truncate (const char *file, off_t length)
82893676 1745{
8ab3d8a0
KR
1746 int ret, fdes;
1747
1748 fdes = open (file, O_BINARY | O_WRONLY);
1749 if (fdes == -1)
1750 return -1;
1751
1752 ret = ftruncate (fdes, length);
1753 if (ret == -1)
82893676 1754 {
8ab3d8a0 1755 int save_errno = errno;
82893676 1756 close (fdes);
8ab3d8a0
KR
1757 errno = save_errno;
1758 return -1;
82893676 1759 }
8ab3d8a0
KR
1760
1761 return close (fdes);
82893676 1762}
8ab3d8a0 1763#endif /* HAVE_FTRUNCATE && ! HAVE_TRUNCATE */
82893676 1764
a1ec6916 1765SCM_DEFINE (scm_truncate_file, "truncate-file", 1, 1, 0,
1bbd0b84 1766 (SCM object, SCM length),
8ab3d8a0
KR
1767 "Truncate @var{file} to @var{length} bytes. @var{file} can be a\n"
1768 "filename string, a port object, or an integer file descriptor.\n"
1769 "The return value is unspecified.\n"
1770 "\n"
1771 "For a port or file descriptor @var{length} can be omitted, in\n"
1772 "which case the file is truncated at the current position (per\n"
1773 "@code{ftell} above).\n"
1774 "\n"
1775 "On most systems a file can be extended by giving a length\n"
1776 "greater than the current size, but this is not mandatory in the\n"
1777 "POSIX standard.")
1bbd0b84 1778#define FUNC_NAME s_scm_truncate_file
840ae05d 1779{
69bc9ff3 1780 int rv;
69bc9ff3 1781
2b829bbb
KR
1782 /* "object" can be a port, fdes or filename.
1783
1784 Negative "length" makes no sense, but it's left to truncate() or
1785 ftruncate() to give back an error for that (normally EINVAL).
1786 */
840ae05d 1787
840ae05d
JB
1788 if (SCM_UNBNDP (length))
1789 {
69bc9ff3 1790 /* must supply length if object is a filename. */
7f9994d9 1791 if (scm_is_string (object))
34d19ef6 1792 SCM_MISC_ERROR("must supply length if OBJECT is a filename", SCM_EOL);
69bc9ff3 1793
e11e83f3 1794 length = scm_seek (object, SCM_INUM0, scm_from_int (SEEK_CUR));
840ae05d 1795 }
3fe6190f 1796
69bc9ff3 1797 object = SCM_COERCE_OUTPORT (object);
e11e83f3 1798 if (scm_is_integer (object))
69bc9ff3 1799 {
23f2b9a3
KR
1800 off_t_or_off64_t c_length = scm_to_off_t_or_off64_t (length);
1801 SCM_SYSCALL (rv = ftruncate_or_ftruncate64 (scm_to_int (object),
1802 c_length));
69bc9ff3 1803 }
0c95b57d 1804 else if (SCM_OPOUTPORTP (object))
69bc9ff3 1805 {
f1ce9199 1806 off_t_or_off64_t c_length = scm_to_off_t_or_off64_t (length);
92c2555f
MV
1807 scm_t_port *pt = SCM_PTAB_ENTRY (object);
1808 scm_t_ptob_descriptor *ptob = scm_ptobs + SCM_PTOBNUM (object);
69bc9ff3 1809
affc96b5 1810 if (!ptob->truncate)
1bbd0b84 1811 SCM_MISC_ERROR ("port is not truncatable", SCM_EOL);
69bc9ff3 1812 if (pt->rw_active == SCM_PORT_READ)
affc96b5 1813 scm_end_input (object);
69bc9ff3 1814 else if (pt->rw_active == SCM_PORT_WRITE)
affc96b5 1815 ptob->flush (object);
69bc9ff3 1816
affc96b5 1817 ptob->truncate (object, c_length);
69bc9ff3
GH
1818 rv = 0;
1819 }
1820 else
1821 {
2b829bbb 1822 off_t_or_off64_t c_length = scm_to_off_t_or_off64_t (length);
7f9994d9
MV
1823 char *str = scm_to_locale_string (object);
1824 int eno;
2b829bbb 1825 SCM_SYSCALL (rv = truncate_or_truncate64 (str, c_length));
7f9994d9
MV
1826 eno = errno;
1827 free (str);
1828 errno = eno;
69bc9ff3
GH
1829 }
1830 if (rv == -1)
1bbd0b84 1831 SCM_SYSERROR;
840ae05d
JB
1832 return SCM_UNSPECIFIED;
1833}
1bbd0b84 1834#undef FUNC_NAME
840ae05d 1835
a1ec6916 1836SCM_DEFINE (scm_port_line, "port-line", 1, 0, 0,
1bbd0b84 1837 (SCM port),
a150979d
KR
1838 "Return the current line number for @var{port}.\n"
1839 "\n"
1840 "The first line of a file is 0. But you might want to add 1\n"
1841 "when printing line numbers, since starting from 1 is\n"
1842 "traditional in error messages, and likely to be more natural to\n"
1843 "non-programmers.")
1bbd0b84 1844#define FUNC_NAME s_scm_port_line
0f2d19dd 1845{
78446828 1846 port = SCM_COERCE_OUTPORT (port);
34d19ef6 1847 SCM_VALIDATE_OPENPORT (1, port);
651f2cd2 1848 return scm_from_long (SCM_LINUM (port));
0f2d19dd 1849}
1bbd0b84 1850#undef FUNC_NAME
0f2d19dd 1851
a1ec6916 1852SCM_DEFINE (scm_set_port_line_x, "set-port-line!", 2, 0, 0,
1bbd0b84 1853 (SCM port, SCM line),
a150979d
KR
1854 "Set the current line number for @var{port} to @var{line}. The\n"
1855 "first line of a file is 0.")
1bbd0b84 1856#define FUNC_NAME s_scm_set_port_line_x
d043d8c2 1857{
360fc44c 1858 port = SCM_COERCE_OUTPORT (port);
34d19ef6 1859 SCM_VALIDATE_OPENPORT (1, port);
651f2cd2 1860 SCM_PTAB_ENTRY (port)->line_number = scm_to_long (line);
564478fd 1861 return SCM_UNSPECIFIED;
d043d8c2 1862}
1bbd0b84 1863#undef FUNC_NAME
d043d8c2 1864
a1ec6916 1865SCM_DEFINE (scm_port_column, "port-column", 1, 0, 0,
1bbd0b84 1866 (SCM port),
a150979d
KR
1867 "Return the current column number of @var{port}.\n"
1868 "If the number is\n"
b380b885
MD
1869 "unknown, the result is #f. Otherwise, the result is a 0-origin integer\n"
1870 "- i.e. the first character of the first line is line 0, column 0.\n"
1871 "(However, when you display a file position, for example in an error\n"
650a1cf9 1872 "message, we recommend you add 1 to get 1-origin integers. This is\n"
b380b885
MD
1873 "because lines and column numbers traditionally start with 1, and that is\n"
1874 "what non-programmers will find most natural.)")
1bbd0b84 1875#define FUNC_NAME s_scm_port_column
0f2d19dd 1876{
78446828 1877 port = SCM_COERCE_OUTPORT (port);
34d19ef6 1878 SCM_VALIDATE_OPENPORT (1, port);
e11e83f3 1879 return scm_from_int (SCM_COL (port));
0f2d19dd 1880}
1bbd0b84 1881#undef FUNC_NAME
0f2d19dd 1882
a1ec6916 1883SCM_DEFINE (scm_set_port_column_x, "set-port-column!", 2, 0, 0,
1bbd0b84 1884 (SCM port, SCM column),
a150979d
KR
1885 "Set the current column of @var{port}. Before reading the first\n"
1886 "character on a line the column should be 0.")
1bbd0b84 1887#define FUNC_NAME s_scm_set_port_column_x
d043d8c2 1888{
360fc44c 1889 port = SCM_COERCE_OUTPORT (port);
34d19ef6 1890 SCM_VALIDATE_OPENPORT (1, port);
a55c2b68 1891 SCM_PTAB_ENTRY (port)->column_number = scm_to_int (column);
564478fd 1892 return SCM_UNSPECIFIED;
d043d8c2 1893}
1bbd0b84 1894#undef FUNC_NAME
d043d8c2 1895
a1ec6916 1896SCM_DEFINE (scm_port_filename, "port-filename", 1, 0, 0,
1bbd0b84 1897 (SCM port),
b380b885 1898 "Return the filename associated with @var{port}. This function returns\n"
2a2a730b 1899 "the strings \"standard input\", \"standard output\" and \"standard error\"\n"
a3c8b9fc 1900 "when called on the current input, output and error ports respectively.")
1bbd0b84 1901#define FUNC_NAME s_scm_port_filename
0f2d19dd 1902{
78446828 1903 port = SCM_COERCE_OUTPORT (port);
34d19ef6 1904 SCM_VALIDATE_OPENPORT (1, port);
b24b5e13 1905 return SCM_FILENAME (port);
0f2d19dd 1906}
1bbd0b84 1907#undef FUNC_NAME
0f2d19dd 1908
a1ec6916 1909SCM_DEFINE (scm_set_port_filename_x, "set-port-filename!", 2, 0, 0,
1bbd0b84 1910 (SCM port, SCM filename),
b380b885
MD
1911 "Change the filename associated with @var{port}, using the current input\n"
1912 "port if none is specified. Note that this does not change the port's\n"
1913 "source of data, but only the value that is returned by\n"
1914 "@code{port-filename} and reported in diagnostic output.")
1bbd0b84 1915#define FUNC_NAME s_scm_set_port_filename_x
d14af9f2 1916{
360fc44c 1917 port = SCM_COERCE_OUTPORT (port);
34d19ef6 1918 SCM_VALIDATE_OPENPORT (1, port);
360fc44c 1919 /* We allow the user to set the filename to whatever he likes. */
b24b5e13
DH
1920 SCM_SET_FILENAME (port, filename);
1921 return SCM_UNSPECIFIED;
d14af9f2 1922}
1bbd0b84 1923#undef FUNC_NAME
d14af9f2 1924
889975e5
MG
1925/* The default port encoding for this locale. New ports will have this
1926 encoding. If it is a string, that is the encoding. If it #f, it
1927 is in the native (Latin-1) encoding. */
1928SCM_GLOBAL_VARIABLE (scm_port_encoding_var, "%port-encoding");
1929static int scm_port_encoding_init = 0;
1930
1931/* Return a C string representation of the current encoding. */
1932const char *
1933scm_i_get_port_encoding (SCM port)
1934{
1935 SCM encoding;
1936
1937 if (scm_is_false (port))
1938 {
1939 if (!scm_port_encoding_init)
1940 return NULL;
1941 else if (!scm_is_fluid (SCM_VARIABLE_REF (scm_port_encoding_var)))
1942 return NULL;
1943 else
1944 {
1945 encoding = scm_fluid_ref (SCM_VARIABLE_REF (scm_port_encoding_var));
1946 if (!scm_is_string (encoding))
1947 return NULL;
1948 else
1949 return scm_i_string_chars (encoding);
1950 }
1951 }
1952 else
1953 {
1954 scm_t_port *pt;
1955 pt = SCM_PTAB_ENTRY (port);
1956 if (pt->encoding)
1957 return pt->encoding;
1958 else
1959 return NULL;
1960 }
1961}
1962
b77afe82 1963/* Returns ENC if it is a recognized encoding. If it isn't, it tries
889975e5
MG
1964 to find an alias of ENC that is valid. Otherwise, it returns
1965 NULL. */
1966static const char *
1967find_valid_encoding (const char *enc)
1968{
1969 int isvalid = 0;
1970 const char str[] = " ";
1971 scm_t_uint32 *u32;
1972 size_t u32len;
1973
1974 u32 = u32_conv_from_encoding (enc, iconveh_error, str, 1,
1975 NULL, NULL, &u32len);
1976 isvalid = (u32 != NULL);
1977 free (u32);
1978
1979 if (isvalid)
1980 return enc;
1981
1982 return NULL;
1983}
1984
1985void
1986scm_i_set_port_encoding_x (SCM port, const char *enc)
1987{
1988 const char *valid_enc;
1989 scm_t_port *pt;
1990
1991 /* Null is shorthand for the native, Latin-1 encoding. */
1992 if (enc == NULL)
1993 valid_enc = NULL;
1994 else
1995 {
1996 valid_enc = find_valid_encoding (enc);
1997 if (valid_enc == NULL)
1998 {
1999 SCM err;
2000 err = scm_from_locale_string (enc);
2001 scm_misc_error (NULL, "invalid or unknown character encoding ~s",
2002 scm_list_1 (err));
2003 }
2004 }
2005
2006 if (scm_is_false (port))
2007 {
2008 /* Set the default encoding for future ports. */
2009 if (!scm_port_encoding_init
2010 || !scm_is_fluid (SCM_VARIABLE_REF (scm_port_encoding_var)))
2011 scm_misc_error (NULL, "tried to set port encoding fluid before it is initialized",
2012 SCM_EOL);
2013
2014 if (valid_enc == NULL
2015 || !strcmp (valid_enc, "ASCII")
2016 || !strcmp (valid_enc, "ANSI_X3.4-1968")
2017 || !strcmp (valid_enc, "ISO-8859-1"))
2018 scm_fluid_set_x (SCM_VARIABLE_REF (scm_port_encoding_var), SCM_BOOL_F);
2019 else
2020 scm_fluid_set_x (SCM_VARIABLE_REF (scm_port_encoding_var),
2021 scm_from_locale_string (valid_enc));
2022 }
2023 else
2024 {
2025 /* Set the character encoding for this port. */
2026 pt = SCM_PTAB_ENTRY (port);
2027 if (pt->encoding)
2028 free (pt->encoding);
2029 if (valid_enc == NULL)
2030 pt->encoding = NULL;
2031 else
2032 pt->encoding = strdup (valid_enc);
2033 }
2034}
2035
2036SCM_DEFINE (scm_port_encoding, "port-encoding", 1, 0, 0,
2037 (SCM port),
2038 "Returns, as a string, the character encoding that @var{port}\n"
2039 "uses to interpret its input and output.\n")
2040#define FUNC_NAME s_scm_port_encoding
2041{
2042 scm_t_port *pt;
2043 const char *enc;
2044
2045 SCM_VALIDATE_PORT (1, port);
2046
2047 pt = SCM_PTAB_ENTRY (port);
2048 enc = scm_i_get_port_encoding (port);
2049 if (enc)
2050 return scm_from_locale_string (pt->encoding);
2051 else
2052 return scm_from_locale_string ("NONE");
2053}
2054#undef FUNC_NAME
2055
2056SCM_DEFINE (scm_set_port_encoding_x, "set-port-encoding!", 2, 0, 0,
2057 (SCM port, SCM enc),
2058 "Sets the character encoding that will be used to interpret all\n"
2059 "port I/O. New ports are created with the encoding\n"
2060 "appropriate for the current locale if @code{setlocale} has \n"
2061 "been called or ISO-8859-1 otherwise\n"
2062 "and this procedure can be used to modify that encoding.\n")
2063
2064#define FUNC_NAME s_scm_set_port_encoding_x
2065{
2066 char *enc_str;
2067 const char *valid_enc_str;
2068
2069 SCM_VALIDATE_PORT (1, port);
2070 SCM_VALIDATE_STRING (2, enc);
2071
2072 enc_str = scm_to_locale_string (enc);
2073 valid_enc_str = find_valid_encoding (enc_str);
2074 if (valid_enc_str == NULL)
2075 {
2076 free (enc_str);
2077 scm_misc_error (FUNC_NAME, "invalid or unknown character encoding ~s",
2078 scm_list_1 (enc));
2079 }
2080 else
2081 {
2082 scm_i_set_port_encoding_x (port, valid_enc_str);
2083 free (enc_str);
2084 }
2085 return SCM_UNSPECIFIED;
2086}
2087#undef FUNC_NAME
2088
2089
2090/* This determines how conversions handle unconvertible characters. */
2091SCM_GLOBAL_VARIABLE (scm_conversion_strategy, "%port-conversion-strategy");
2092static int scm_conversion_strategy_init = 0;
2093
2094scm_t_string_failed_conversion_handler
2095scm_i_get_conversion_strategy (SCM port)
2096{
2097 SCM encoding;
2098
2099 if (scm_is_false (port))
2100 {
2101 if (!scm_conversion_strategy_init
2102 || !scm_is_fluid (SCM_VARIABLE_REF (scm_conversion_strategy)))
2103 return SCM_FAILED_CONVERSION_QUESTION_MARK;
2104 else
2105 {
2106 encoding = scm_fluid_ref (SCM_VARIABLE_REF (scm_conversion_strategy));
2107 if (scm_is_false (encoding))
2108 return SCM_FAILED_CONVERSION_QUESTION_MARK;
2109 else
2110 return (scm_t_string_failed_conversion_handler) scm_to_int (encoding);
2111 }
2112 }
2113 else
2114 {
2115 scm_t_port *pt;
2116 pt = SCM_PTAB_ENTRY (port);
2117 return pt->ilseq_handler;
2118 }
2119
2120}
2121
2122void
2123scm_i_set_conversion_strategy_x (SCM port,
2124 scm_t_string_failed_conversion_handler handler)
2125{
2126 SCM strategy;
2127 scm_t_port *pt;
2128
2129 strategy = scm_from_int ((int) handler);
2130
2131 if (scm_is_false (port))
2132 {
2133 /* Set the default encoding for future ports. */
2134 if (!scm_conversion_strategy
2135 || !scm_is_fluid (SCM_VARIABLE_REF (scm_conversion_strategy)))
2136 scm_misc_error (NULL, "tried to set conversion strategy fluid before it is initialized",
2137 SCM_EOL);
2138 scm_fluid_set_x (SCM_VARIABLE_REF (scm_conversion_strategy), strategy);
2139 }
2140 else
2141 {
2142 /* Set the character encoding for this port. */
2143 pt = SCM_PTAB_ENTRY (port);
2144 pt->ilseq_handler = handler;
2145 }
2146}
2147
2148SCM_DEFINE (scm_port_conversion_strategy, "port-conversion-strategy",
2149 1, 0, 0, (SCM port),
2150 "Returns the behavior of the port when handling a character that\n"
2151 "is not representable in the port's current encoding.\n"
2152 "It returns the symbol @code{error} if unrepresentable characters\n"
2153 "should cause exceptions, @code{substitute} if the port should\n"
2154 "try to replace unrepresentable characters with question marks or\n"
2155 "approximate characters, or @code{escape} if unrepresentable\n"
2156 "characters should be converted to string escapes.\n"
2157 "\n"
2158 "If @var{port} is @code{#f}, then the current default behavior\n"
2159 "will be returned. New ports will have this default behavior\n"
2160 "when they are created.\n")
2161#define FUNC_NAME s_scm_port_conversion_strategy
2162{
2163 scm_t_string_failed_conversion_handler h;
2164
2165 SCM_VALIDATE_OPPORT (1, port);
2166
2167 if (!scm_is_false (port))
2168 {
2169 SCM_VALIDATE_OPPORT (1, port);
2170 }
2171
2172 h = scm_i_get_conversion_strategy (port);
2173 if (h == SCM_FAILED_CONVERSION_ERROR)
2174 return scm_from_locale_symbol ("error");
2175 else if (h == SCM_FAILED_CONVERSION_QUESTION_MARK)
2176 return scm_from_locale_symbol ("substitute");
2177 else if (h == SCM_FAILED_CONVERSION_ESCAPE_SEQUENCE)
2178 return scm_from_locale_symbol ("escape");
2179 else
2180 abort ();
2181
2182 /* Never gets here. */
2183 return SCM_UNDEFINED;
2184}
2185#undef FUNC_NAME
2186
2187SCM_DEFINE (scm_set_port_conversion_strategy_x, "set-port-conversion-strategy!",
2188 2, 0, 0,
2189 (SCM port, SCM sym),
2190 "Sets the behavior of the interpreter when outputting a character\n"
2191 "that is not representable in the port's current encoding.\n"
2192 "@var{sym} can be either @code{'error}, @code{'substitute}, or\n"
2193 "@code{'escape}. If it is @code{'error}, an error will be thrown\n"
2194 "when an unconvertible character is encountered. If it is\n"
2195 "@code{'substitute}, then unconvertible characters will \n"
2196 "be replaced with approximate characters, or with question marks\n"
2197 "if no approximately correct character is available.\n"
2198 "If it is @code{'escape},\n"
2199 "it will appear as a hex escape when output.\n"
2200 "\n"
2201 "If @var{port} is an open port, the conversion error behavior\n"
2202 "is set for that port. If it is @code{#f}, it is set as the\n"
2203 "default behavior for any future ports that get created in\n"
2204 "this thread.\n")
2205#define FUNC_NAME s_scm_set_port_conversion_strategy_x
2206{
2207 SCM err;
2208 SCM qm;
2209 SCM esc;
2210
2211 if (!scm_is_false (port))
2212 {
2213 SCM_VALIDATE_OPPORT (1, port);
2214 }
2215
2216 err = scm_from_locale_symbol ("error");
2217 if (scm_is_true (scm_eqv_p (sym, err)))
2218 {
2219 scm_i_set_conversion_strategy_x (port, SCM_FAILED_CONVERSION_ERROR);
2220 return SCM_UNSPECIFIED;
2221 }
2222
2223 qm = scm_from_locale_symbol ("substitute");
2224 if (scm_is_true (scm_eqv_p (sym, qm)))
2225 {
2226 scm_i_set_conversion_strategy_x (port,
2227 SCM_FAILED_CONVERSION_QUESTION_MARK);
2228 return SCM_UNSPECIFIED;
2229 }
2230
2231 esc = scm_from_locale_symbol ("escape");
2232 if (scm_is_true (scm_eqv_p (sym, esc)))
2233 {
2234 scm_i_set_conversion_strategy_x (port,
2235 SCM_FAILED_CONVERSION_ESCAPE_SEQUENCE);
2236 return SCM_UNSPECIFIED;
2237 }
2238
2239 SCM_MISC_ERROR ("unknown conversion behavior ~s", scm_list_1 (sym));
2240
2241 return SCM_UNSPECIFIED;
2242}
2243#undef FUNC_NAME
2244
2245
2246
f12733c9
MD
2247void
2248scm_print_port_mode (SCM exp, SCM port)
2249{
2250 scm_puts (SCM_CLOSEDP (exp)
2251 ? "closed: "
f9a64404
DH
2252 : (SCM_RDNG & SCM_CELL_WORD_0 (exp)
2253 ? (SCM_WRTNG & SCM_CELL_WORD_0 (exp)
f12733c9
MD
2254 ? "input-output: "
2255 : "input: ")
f9a64404 2256 : (SCM_WRTNG & SCM_CELL_WORD_0 (exp)
f12733c9
MD
2257 ? "output: "
2258 : "bogus: ")),
2259 port);
2260}
1cc91f1b 2261
f12733c9 2262int
e81d98ec 2263scm_port_print (SCM exp, SCM port, scm_print_state *pstate SCM_UNUSED)
0f2d19dd 2264{
f12733c9
MD
2265 char *type = SCM_PTOBNAME (SCM_PTOBNUM (exp));
2266 if (!type)
2267 type = "port";
b7f3516f 2268 scm_puts ("#<", port);
f12733c9 2269 scm_print_port_mode (exp, port);
b7f3516f
TT
2270 scm_puts (type, port);
2271 scm_putc (' ', port);
0345e278 2272 scm_uintprint (SCM_CELL_WORD_1 (exp), 16, port);
b7f3516f 2273 scm_putc ('>', port);
f12733c9 2274 return 1;
0f2d19dd
JB
2275}
2276
0f2d19dd
JB
2277void
2278scm_ports_prehistory ()
0f2d19dd
JB
2279{
2280 scm_numptob = 0;
fca43887 2281 scm_ptobs = NULL;
0f2d19dd 2282}
0f2d19dd
JB
2283
2284\f
ee149d03 2285
d68fee48 2286/* Void ports. */
0f2d19dd 2287
92c2555f 2288scm_t_bits scm_tc16_void_port = 0;
0f2d19dd 2289
e81d98ec 2290static int fill_input_void_port (SCM port SCM_UNUSED)
283a1a0e 2291{
70df8af6 2292 return EOF;
283a1a0e
GH
2293}
2294
31703ab8 2295static void
e81d98ec
DH
2296write_void_port (SCM port SCM_UNUSED,
2297 const void *data SCM_UNUSED,
2298 size_t size SCM_UNUSED)
31703ab8
GH
2299{
2300}
2301
d617ee18
MV
2302static SCM
2303scm_i_void_port (long mode_bits)
0f2d19dd 2304{
9de87eea 2305 scm_i_scm_pthread_mutex_lock (&scm_i_port_table_mutex);
402788a9 2306 {
da220f27
HWN
2307 SCM answer = scm_new_port_table_entry (scm_tc16_void_port);
2308 scm_t_port * pt = SCM_PTAB_ENTRY(answer);
2309
402788a9 2310 scm_port_non_buffer (pt);
402788a9
HWN
2311
2312 SCM_SETSTREAM (answer, 0);
2313 SCM_SET_CELL_TYPE (answer, scm_tc16_void_port | mode_bits);
9de87eea 2314 scm_i_pthread_mutex_unlock (&scm_i_port_table_mutex);
402788a9
HWN
2315 return answer;
2316 }
0f2d19dd
JB
2317}
2318
d617ee18
MV
2319SCM
2320scm_void_port (char *mode_str)
2321{
2322 return scm_i_void_port (scm_mode_bits (mode_str));
2323}
2324
a1ec6916 2325SCM_DEFINE (scm_sys_make_void_port, "%make-void-port", 1, 0, 0,
1bbd0b84 2326 (SCM mode),
70df8af6 2327 "Create and return a new void port. A void port acts like\n"
bb2c02f2 2328 "@file{/dev/null}. The @var{mode} argument\n"
70df8af6 2329 "specifies the input/output modes for this port: see the\n"
b380b885 2330 "documentation for @code{open-file} in @ref{File Ports}.")
1bbd0b84 2331#define FUNC_NAME s_scm_sys_make_void_port
0f2d19dd 2332{
d617ee18 2333 return scm_i_void_port (scm_i_mode_bits (mode));
0f2d19dd 2334}
1bbd0b84 2335#undef FUNC_NAME
0f2d19dd 2336
0f2d19dd 2337\f
89545eba 2338/* Initialization. */
1cc91f1b 2339
0f2d19dd
JB
2340void
2341scm_init_ports ()
0f2d19dd 2342{
840ae05d 2343 /* lseek() symbols. */
e11e83f3
MV
2344 scm_c_define ("SEEK_SET", scm_from_int (SEEK_SET));
2345 scm_c_define ("SEEK_CUR", scm_from_int (SEEK_CUR));
2346 scm_c_define ("SEEK_END", scm_from_int (SEEK_END));
840ae05d 2347
70df8af6
GH
2348 scm_tc16_void_port = scm_make_port_type ("void", fill_input_void_port,
2349 write_void_port);
9de87eea
MV
2350
2351 cur_inport_fluid = scm_permanent_object (scm_make_fluid ());
2352 cur_outport_fluid = scm_permanent_object (scm_make_fluid ());
2353 cur_errport_fluid = scm_permanent_object (scm_make_fluid ());
2354 cur_loadport_fluid = scm_permanent_object (scm_make_fluid ());
2355
5dbc6c06 2356 scm_i_port_weak_hash = scm_permanent_object (scm_make_weak_key_hash_table (SCM_I_MAKINUM(31)));
a0599745 2357#include "libguile/ports.x"
889975e5
MG
2358
2359 SCM_VARIABLE_SET (scm_port_encoding_var, scm_make_fluid ());
2360 scm_fluid_set_x (SCM_VARIABLE_REF (scm_port_encoding_var), SCM_BOOL_F);
2361 scm_port_encoding_init = 1;
2362
2363 SCM_VARIABLE_SET (scm_conversion_strategy, scm_make_fluid ());
2364 scm_fluid_set_x (SCM_VARIABLE_REF (scm_conversion_strategy),
2365 scm_from_int ((int) SCM_FAILED_CONVERSION_QUESTION_MARK));
2366 scm_conversion_strategy_init = 1;
2367
0f2d19dd 2368}
89e00824
ML
2369
2370/*
2371 Local Variables:
2372 c-file-style: "gnu"
2373 End:
2374*/