Make port properties accessible from Scheme.
[bpt/guile.git] / libguile / ports.c
CommitLineData
e4598559
MW
1/* Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2006,
2 * 2007, 2008, 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc.
f4bc4e59 3 *
73be1d9e 4 * This library is free software; you can redistribute it and/or
53befeb7
NJ
5 * modify it under the terms of the GNU Lesser General Public License
6 * as published by the Free Software Foundation; either version 3 of
7 * the License, or (at your option) any later version.
0f2d19dd 8 *
53befeb7
NJ
9 * This library is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
73be1d9e
MV
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
0f2d19dd 13 *
73be1d9e
MV
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
53befeb7
NJ
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 * 02110-1301 USA
73be1d9e 18 */
1bbd0b84 19
1bbd0b84 20
0f2d19dd 21\f
d68fee48
JB
22/* Headers. */
23
2b829bbb
KR
24#define _LARGEFILE64_SOURCE /* ask for stat64 etc */
25
dbb605f5 26#ifdef HAVE_CONFIG_H
bd515f37
RB
27# include <config.h>
28#endif
29
0f2d19dd 30#include <stdio.h>
e6e2e95a 31#include <errno.h>
8ab3d8a0 32#include <fcntl.h> /* for chsize on mingw */
b5cb4464 33#include <assert.h>
f4bc4e59 34#include <iconv.h>
889975e5
MG
35#include <uniconv.h>
36#include <unistr.h>
37#include <striconveh.h>
96965a6e 38#include <c-strcase.h>
e6e2e95a 39
fca43887
LC
40#include <assert.h>
41
a0599745 42#include "libguile/_scm.h"
4e047c3e 43#include "libguile/async.h"
8269ba5b 44#include "libguile/deprecation.h"
f0942910 45#include "libguile/eval.h"
8ab3d8a0 46#include "libguile/fports.h" /* direct access for seek and truncate */
9511876f 47#include "libguile/goops.h"
a0599745
MD
48#include "libguile/smob.h"
49#include "libguile/chars.h"
185e369a 50#include "libguile/dynwind.h"
0f2d19dd 51
a0599745 52#include "libguile/keywords.h"
5dbc6c06 53#include "libguile/hashtab.h"
a0599745
MD
54#include "libguile/root.h"
55#include "libguile/strings.h"
b42170a4 56#include "libguile/mallocs.h"
a0599745
MD
57#include "libguile/validate.h"
58#include "libguile/ports.h"
e4598559 59#include "libguile/ports-internal.h"
3a5fb14d 60#include "libguile/vectors.h"
5dbc6c06 61#include "libguile/weaks.h"
9de87eea 62#include "libguile/fluids.h"
889975e5 63#include "libguile/eq.h"
a38024ba 64#include "libguile/alist.h"
0f2d19dd 65
bd9e24b3
GH
66#ifdef HAVE_STRING_H
67#include <string.h>
68#endif
69
ec65f5da
MV
70#ifdef HAVE_IO_H
71#include <io.h>
72#endif
73
0f2d19dd
JB
74#ifdef HAVE_UNISTD_H
75#include <unistd.h>
76#endif
77
95b88819
GH
78#ifdef HAVE_SYS_IOCTL_H
79#include <sys/ioctl.h>
80#endif
d68fee48 81
8ab3d8a0
KR
82/* Mingw (version 3.4.5, circa 2006) has ftruncate as an alias for chsize
83 already, but have this code here in case that wasn't so in past versions,
84 or perhaps to help other minimal DOS environments.
85
86 gnulib ftruncate.c has code using fcntl F_CHSIZE and F_FREESP, which
87 might be possibilities if we've got other systems without ftruncate. */
88
56a3dcd4 89#if defined HAVE_CHSIZE && ! defined HAVE_FTRUNCATE
82893676 90#define ftruncate(fd, size) chsize (fd, size)
8ab3d8a0
KR
91#undef HAVE_FTRUNCATE
92#define HAVE_FTRUNCATE 1
82893676
MG
93#endif
94
0f2d19dd 95\f
d68fee48 96/* The port kind table --- a dynamically resized array of port types. */
0f2d19dd
JB
97
98
99/* scm_ptobs scm_numptob
5dbc6c06 100 * implement a dynamically resized array of ptob records.
0f2d19dd
JB
101 * Indexes into this table are used when generating type
102 * tags for smobjects (if you know a tag you can get an index and conversely).
103 */
dd3a26f3
AW
104scm_t_ptob_descriptor *scm_ptobs = NULL;
105long scm_numptob = 0;
0f2d19dd 106
ee149d03 107/* GC marker for a port with stream of SCM type. */
0f2d19dd 108SCM
a284e297 109scm_markstream (SCM ptr)
0f2d19dd
JB
110{
111 int openp;
f9a64404 112 openp = SCM_CELL_WORD_0 (ptr) & SCM_OPN;
0f2d19dd 113 if (openp)
74a16888 114 return SCM_PACK (SCM_STREAM (ptr));
0f2d19dd
JB
115 else
116 return SCM_BOOL_F;
117}
118
f12733c9 119/*
f12733c9 120 * We choose to use an interface similar to the smob interface with
affc96b5 121 * fill_input and write as standard fields, passed to the port
f12733c9
MD
122 * type constructor, and optional fields set by setters.
123 */
124
70df8af6 125static void
e81d98ec 126flush_port_default (SCM port SCM_UNUSED)
70df8af6
GH
127{
128}
129
130static void
e81d98ec 131end_input_default (SCM port SCM_UNUSED, int offset SCM_UNUSED)
70df8af6
GH
132{
133}
0f2d19dd 134
92c2555f 135scm_t_bits
f12733c9 136scm_make_port_type (char *name,
affc96b5 137 int (*fill_input) (SCM port),
8aa011a1 138 void (*write) (SCM port, const void *data, size_t size))
0f2d19dd
JB
139{
140 char *tmp;
0953b549 141 if (SCM_I_MAX_PORT_TYPE_COUNT - 1 <= scm_numptob)
0f2d19dd 142 goto ptoberr;
9de87eea 143 SCM_CRITICAL_SECTION_START;
fca43887
LC
144 tmp = (char *) scm_gc_realloc ((char *) scm_ptobs,
145 scm_numptob * sizeof (scm_t_ptob_descriptor),
146 (1 + scm_numptob)
147 * sizeof (scm_t_ptob_descriptor),
148 "port-type");
0f2d19dd
JB
149 if (tmp)
150 {
92c2555f 151 scm_ptobs = (scm_t_ptob_descriptor *) tmp;
affc96b5 152
f12733c9
MD
153 scm_ptobs[scm_numptob].name = name;
154 scm_ptobs[scm_numptob].mark = 0;
3051344b 155 scm_ptobs[scm_numptob].free = NULL;
f12733c9
MD
156 scm_ptobs[scm_numptob].print = scm_port_print;
157 scm_ptobs[scm_numptob].equalp = 0;
affc96b5
GH
158 scm_ptobs[scm_numptob].close = 0;
159
160 scm_ptobs[scm_numptob].write = write;
70df8af6 161 scm_ptobs[scm_numptob].flush = flush_port_default;
affc96b5 162
70df8af6 163 scm_ptobs[scm_numptob].end_input = end_input_default;
affc96b5
GH
164 scm_ptobs[scm_numptob].fill_input = fill_input;
165 scm_ptobs[scm_numptob].input_waiting = 0;
166
f12733c9 167 scm_ptobs[scm_numptob].seek = 0;
affc96b5
GH
168 scm_ptobs[scm_numptob].truncate = 0;
169
0f2d19dd
JB
170 scm_numptob++;
171 }
9de87eea 172 SCM_CRITICAL_SECTION_END;
0f2d19dd 173 if (!tmp)
2500356c
DH
174 {
175 ptoberr:
176 scm_memory_error ("scm_make_port_type");
177 }
f12733c9 178 /* Make a class object if Goops is present */
63385df2 179 if (SCM_UNPACK (scm_port_class[0]) != 0)
f12733c9 180 scm_make_port_classes (scm_numptob - 1, SCM_PTOBNAME (scm_numptob - 1));
0f2d19dd
JB
181 return scm_tc7_port + (scm_numptob - 1) * 256;
182}
183
f12733c9 184void
23f2b9a3 185scm_set_port_mark (scm_t_bits tc, SCM (*mark) (SCM))
f12733c9
MD
186{
187 scm_ptobs[SCM_TC2PTOBNUM (tc)].mark = mark;
188}
189
190void
23f2b9a3 191scm_set_port_free (scm_t_bits tc, size_t (*free) (SCM))
f12733c9
MD
192{
193 scm_ptobs[SCM_TC2PTOBNUM (tc)].free = free;
194}
195
196void
23f2b9a3 197scm_set_port_print (scm_t_bits tc, int (*print) (SCM exp, SCM port,
f12733c9
MD
198 scm_print_state *pstate))
199{
200 scm_ptobs[SCM_TC2PTOBNUM (tc)].print = print;
201}
202
203void
23f2b9a3 204scm_set_port_equalp (scm_t_bits tc, SCM (*equalp) (SCM, SCM))
f12733c9
MD
205{
206 scm_ptobs[SCM_TC2PTOBNUM (tc)].equalp = equalp;
207}
208
31703ab8 209void
23f2b9a3 210scm_set_port_flush (scm_t_bits tc, void (*flush) (SCM port))
31703ab8 211{
affc96b5 212 scm_ptobs[SCM_TC2PTOBNUM (tc)].flush = flush;
31703ab8
GH
213}
214
f12733c9 215void
23f2b9a3 216scm_set_port_end_input (scm_t_bits tc, void (*end_input) (SCM port, int offset))
f12733c9 217{
affc96b5 218 scm_ptobs[SCM_TC2PTOBNUM (tc)].end_input = end_input;
f12733c9
MD
219}
220
221void
23f2b9a3 222scm_set_port_close (scm_t_bits tc, int (*close) (SCM))
f12733c9 223{
affc96b5 224 scm_ptobs[SCM_TC2PTOBNUM (tc)].close = close;
f12733c9
MD
225}
226
227void
f1ce9199
LC
228scm_set_port_seek (scm_t_bits tc,
229 scm_t_off (*seek) (SCM, scm_t_off, int))
f12733c9
MD
230{
231 scm_ptobs[SCM_TC2PTOBNUM (tc)].seek = seek;
232}
233
234void
f1ce9199 235scm_set_port_truncate (scm_t_bits tc, void (*truncate) (SCM, scm_t_off))
f12733c9 236{
affc96b5 237 scm_ptobs[SCM_TC2PTOBNUM (tc)].truncate = truncate;
f12733c9
MD
238}
239
240void
23f2b9a3 241scm_set_port_input_waiting (scm_t_bits tc, int (*input_waiting) (SCM))
f12733c9 242{
affc96b5 243 scm_ptobs[SCM_TC2PTOBNUM (tc)].input_waiting = input_waiting;
f12733c9
MD
244}
245
45c0878b
MW
246static void
247scm_i_set_pending_eof (SCM port)
248{
249 SCM_PORT_GET_INTERNAL (port)->pending_eof = 1;
250}
251
252static void
253scm_i_clear_pending_eof (SCM port)
254{
255 SCM_PORT_GET_INTERNAL (port)->pending_eof = 0;
256}
257
a38024ba
MW
258SCM_DEFINE (scm_i_port_property, "%port-property", 2, 0, 0,
259 (SCM port, SCM key),
260 "Return the property of @var{port} associated with @var{key}.")
261#define FUNC_NAME s_scm_i_port_property
05d7f762 262{
a38024ba
MW
263 SCM_VALIDATE_OPPORT (1, port);
264 return scm_assq_ref (SCM_PORT_GET_INTERNAL (port)->alist, key);
05d7f762 265}
a38024ba 266#undef FUNC_NAME
05d7f762 267
a38024ba
MW
268SCM_DEFINE (scm_i_set_port_property_x, "%set-port-property!", 3, 0, 0,
269 (SCM port, SCM key, SCM value),
270 "Set the property of @var{port} associated with @var{key} to @var{value}.")
271#define FUNC_NAME s_scm_i_set_port_property_x
05d7f762 272{
a38024ba
MW
273 scm_t_port_internal *pti;
274
275 SCM_VALIDATE_OPPORT (1, port);
276 pti = SCM_PORT_GET_INTERNAL (port);
277 pti->alist = scm_assq_set_x (pti->alist, key, value);
278 return SCM_UNSPECIFIED;
05d7f762 279}
a38024ba 280#undef FUNC_NAME
05d7f762 281
0f2d19dd 282\f
0f2d19dd 283
3b3b36dd 284SCM_DEFINE (scm_char_ready_p, "char-ready?", 0, 1, 0,
1e6808ea
MG
285 (SCM port),
286 "Return @code{#t} if a character is ready on input @var{port}\n"
287 "and return @code{#f} otherwise. If @code{char-ready?} returns\n"
288 "@code{#t} then the next @code{read-char} operation on\n"
289 "@var{port} is guaranteed not to hang. If @var{port} is a file\n"
290 "port at end of file then @code{char-ready?} returns @code{#t}.\n"
c2dfff19
KR
291 "\n"
292 "@code{char-ready?} exists to make it possible for a\n"
1e6808ea
MG
293 "program to accept characters from interactive ports without\n"
294 "getting stuck waiting for input. Any input editors associated\n"
295 "with such ports must make sure that characters whose existence\n"
296 "has been asserted by @code{char-ready?} cannot be rubbed out.\n"
297 "If @code{char-ready?} were to return @code{#f} at end of file,\n"
298 "a port at end of file would be indistinguishable from an\n"
c2dfff19 299 "interactive port that has no ready characters.")
1bbd0b84 300#define FUNC_NAME s_scm_char_ready_p
0f2d19dd 301{
92c2555f 302 scm_t_port *pt;
6c951427 303
0f2d19dd 304 if (SCM_UNBNDP (port))
9de87eea 305 port = scm_current_input_port ();
b2456dd4
AW
306 /* It's possible to close the current input port, so validate even in
307 this case. */
308 SCM_VALIDATE_OPINPORT (1, port);
d68fee48 309
ae4c4016
JB
310 pt = SCM_PTAB_ENTRY (port);
311
6c951427
GH
312 /* if the current read buffer is filled, or the
313 last pushed-back char has been read and the saved buffer is
314 filled, result is true. */
315 if (pt->read_pos < pt->read_end
316 || (pt->read_buf == pt->putback_buf
317 && pt->saved_read_pos < pt->saved_read_end))
0f2d19dd 318 return SCM_BOOL_T;
ee149d03
JB
319 else
320 {
92c2555f 321 scm_t_ptob_descriptor *ptob = &scm_ptobs[SCM_PTOBNUM (port)];
ee149d03 322
affc96b5 323 if (ptob->input_waiting)
7888309b 324 return scm_from_bool(ptob->input_waiting (port));
ee149d03 325 else
6c951427 326 return SCM_BOOL_T;
ee149d03 327 }
0f2d19dd 328}
1bbd0b84 329#undef FUNC_NAME
0f2d19dd 330
e8b21eec
LC
331/* Move up to READ_LEN bytes from PORT's putback and/or read buffers
332 into memory starting at DEST. Return the number of bytes moved.
333 PORT's line/column numbers are left unchanged. */
334size_t
335scm_take_from_input_buffers (SCM port, char *dest, size_t read_len)
c2da2648 336{
92c2555f 337 scm_t_port *pt = SCM_PTAB_ENTRY (port);
e8b21eec 338 size_t bytes_read = 0;
c2da2648
GH
339 size_t from_buf = min (pt->read_end - pt->read_pos, read_len);
340
341 if (from_buf > 0)
342 {
343 memcpy (dest, pt->read_pos, from_buf);
344 pt->read_pos += from_buf;
e8b21eec 345 bytes_read += from_buf;
c2da2648
GH
346 read_len -= from_buf;
347 dest += from_buf;
348 }
349
350 /* if putback was active, try the real input buffer too. */
351 if (pt->read_buf == pt->putback_buf)
352 {
353 from_buf = min (pt->saved_read_end - pt->saved_read_pos, read_len);
354 if (from_buf > 0)
355 {
356 memcpy (dest, pt->saved_read_pos, from_buf);
357 pt->saved_read_pos += from_buf;
e8b21eec 358 bytes_read += from_buf;
c2da2648
GH
359 }
360 }
e8b21eec
LC
361
362 return bytes_read;
c2da2648
GH
363}
364
6c951427 365/* Clear a port's read buffers, returning the contents. */
a1ec6916 366SCM_DEFINE (scm_drain_input, "drain-input", 1, 0, 0,
1bbd0b84 367 (SCM port),
4a151b3d
GH
368 "This procedure clears a port's input buffers, similar\n"
369 "to the way that force-output clears the output buffer. The\n"
370 "contents of the buffers are returned as a single string, e.g.,\n"
371 "\n"
372 "@lisp\n"
373 "(define p (open-input-file ...))\n"
374 "(drain-input p) => empty string, nothing buffered yet.\n"
375 "(unread-char (read-char p) p)\n"
376 "(drain-input p) => initial chars from p, up to the buffer size.\n"
377 "@end lisp\n\n"
378 "Draining the buffers may be useful for cleanly finishing\n"
379 "buffered I/O so that the file descriptor can be used directly\n"
380 "for further input.")
1bbd0b84 381#define FUNC_NAME s_scm_drain_input
ee149d03 382{
840ae05d 383 SCM result;
3a5fb14d 384 char *data;
28a6e1b0 385 scm_t_port *pt;
c014a02e 386 long count;
ee149d03 387
34d19ef6 388 SCM_VALIDATE_OPINPORT (1, port);
28a6e1b0 389 pt = SCM_PTAB_ENTRY (port);
840ae05d 390
6c951427
GH
391 count = pt->read_end - pt->read_pos;
392 if (pt->read_buf == pt->putback_buf)
393 count += pt->saved_read_end - pt->saved_read_pos;
840ae05d 394
67a72dc1
AW
395 if (count)
396 {
190d4b0d 397 result = scm_i_make_string (count, &data, 0);
67a72dc1
AW
398 scm_take_from_input_buffers (port, data, count);
399 }
400 else
401 result = scm_nullstr;
402
840ae05d 403 return result;
ee149d03 404}
1bbd0b84 405#undef FUNC_NAME
0f2d19dd
JB
406
407\f
d68fee48 408/* Standard ports --- current input, output, error, and more(!). */
0f2d19dd 409
34297700
AW
410static SCM cur_inport_fluid = SCM_BOOL_F;
411static SCM cur_outport_fluid = SCM_BOOL_F;
412static SCM cur_errport_fluid = SCM_BOOL_F;
413static SCM cur_loadport_fluid = SCM_BOOL_F;
9de87eea 414
3b3b36dd 415SCM_DEFINE (scm_current_input_port, "current-input-port", 0, 0, 0,
e1546b65
MG
416 (),
417 "Return the current input port. This is the default port used\n"
418 "by many input procedures. Initially, @code{current-input-port}\n"
419 "returns the @dfn{standard input} in Unix and C terminology.")
1bbd0b84 420#define FUNC_NAME s_scm_current_input_port
0f2d19dd 421{
34297700 422 if (scm_is_true (cur_inport_fluid))
889975e5
MG
423 return scm_fluid_ref (cur_inport_fluid);
424 else
425 return SCM_BOOL_F;
0f2d19dd 426}
1bbd0b84 427#undef FUNC_NAME
0f2d19dd 428
3b3b36dd 429SCM_DEFINE (scm_current_output_port, "current-output-port", 0, 0, 0,
e1546b65
MG
430 (),
431 "Return the current output port. This is the default port used\n"
9401323e 432 "by many output procedures. Initially,\n"
e1546b65
MG
433 "@code{current-output-port} returns the @dfn{standard output} in\n"
434 "Unix and C terminology.")
1bbd0b84 435#define FUNC_NAME s_scm_current_output_port
0f2d19dd 436{
34297700 437 if (scm_is_true (cur_outport_fluid))
889975e5
MG
438 return scm_fluid_ref (cur_outport_fluid);
439 else
440 return SCM_BOOL_F;
0f2d19dd 441}
1bbd0b84 442#undef FUNC_NAME
0f2d19dd 443
3b3b36dd 444SCM_DEFINE (scm_current_error_port, "current-error-port", 0, 0, 0,
1bbd0b84 445 (),
b380b885
MD
446 "Return the port to which errors and warnings should be sent (the\n"
447 "@dfn{standard error} in Unix and C terminology).")
1bbd0b84 448#define FUNC_NAME s_scm_current_error_port
0f2d19dd 449{
34297700 450 if (scm_is_true (cur_errport_fluid))
889975e5
MG
451 return scm_fluid_ref (cur_errport_fluid);
452 else
453 return SCM_BOOL_F;
0f2d19dd 454}
1bbd0b84 455#undef FUNC_NAME
0f2d19dd 456
3972de76
AW
457SCM
458scm_current_warning_port (void)
459{
f57ea23a
MW
460 static SCM cwp_var = SCM_UNDEFINED;
461 static scm_i_pthread_mutex_t cwp_var_mutex
462 = SCM_I_PTHREAD_MUTEX_INITIALIZER;
463
464 scm_i_scm_pthread_mutex_lock (&cwp_var_mutex);
465 if (SCM_UNBNDP (cwp_var))
466 cwp_var = scm_c_private_variable ("guile", "current-warning-port");
467 scm_i_pthread_mutex_unlock (&cwp_var_mutex);
3972de76
AW
468
469 return scm_call_0 (scm_variable_ref (cwp_var));
470}
471
3b3b36dd 472SCM_DEFINE (scm_current_load_port, "current-load-port", 0, 0, 0,
e1546b65 473 (),
b450f070 474 "Return the current-load-port.\n"
e1546b65 475 "The load port is used internally by @code{primitive-load}.")
1bbd0b84 476#define FUNC_NAME s_scm_current_load_port
31614d8e 477{
9de87eea 478 return scm_fluid_ref (cur_loadport_fluid);
31614d8e 479}
1bbd0b84 480#undef FUNC_NAME
31614d8e 481
3b3b36dd 482SCM_DEFINE (scm_set_current_input_port, "set-current-input-port", 1, 0, 0,
1bbd0b84 483 (SCM port),
8f85c0c6
NJ
484 "@deffnx {Scheme Procedure} set-current-output-port port\n"
485 "@deffnx {Scheme Procedure} set-current-error-port port\n"
b380b885
MD
486 "Change the ports returned by @code{current-input-port},\n"
487 "@code{current-output-port} and @code{current-error-port}, respectively,\n"
488 "so that they use the supplied @var{port} for input or output.")
1bbd0b84 489#define FUNC_NAME s_scm_set_current_input_port
0f2d19dd 490{
9de87eea 491 SCM oinp = scm_fluid_ref (cur_inport_fluid);
34d19ef6 492 SCM_VALIDATE_OPINPORT (1, port);
9de87eea 493 scm_fluid_set_x (cur_inport_fluid, port);
0f2d19dd
JB
494 return oinp;
495}
1bbd0b84 496#undef FUNC_NAME
0f2d19dd
JB
497
498
3b3b36dd 499SCM_DEFINE (scm_set_current_output_port, "set-current-output-port", 1, 0, 0,
e1546b65
MG
500 (SCM port),
501 "Set the current default output port to @var{port}.")
1bbd0b84 502#define FUNC_NAME s_scm_set_current_output_port
0f2d19dd 503{
9de87eea 504 SCM ooutp = scm_fluid_ref (cur_outport_fluid);
78446828 505 port = SCM_COERCE_OUTPORT (port);
34d19ef6 506 SCM_VALIDATE_OPOUTPORT (1, port);
9de87eea 507 scm_fluid_set_x (cur_outport_fluid, port);
0f2d19dd
JB
508 return ooutp;
509}
1bbd0b84 510#undef FUNC_NAME
0f2d19dd
JB
511
512
3b3b36dd 513SCM_DEFINE (scm_set_current_error_port, "set-current-error-port", 1, 0, 0,
e1546b65
MG
514 (SCM port),
515 "Set the current default error port to @var{port}.")
1bbd0b84 516#define FUNC_NAME s_scm_set_current_error_port
0f2d19dd 517{
9de87eea 518 SCM oerrp = scm_fluid_ref (cur_errport_fluid);
78446828 519 port = SCM_COERCE_OUTPORT (port);
34d19ef6 520 SCM_VALIDATE_OPOUTPORT (1, port);
9de87eea 521 scm_fluid_set_x (cur_errport_fluid, port);
0f2d19dd
JB
522 return oerrp;
523}
1bbd0b84 524#undef FUNC_NAME
0f2d19dd 525
3972de76
AW
526
527SCM
528scm_set_current_warning_port (SCM port)
529{
530 static SCM cwp_var = SCM_BOOL_F;
531
532 if (scm_is_false (cwp_var))
533 cwp_var = scm_c_private_lookup ("guile", "current-warning-port");
534
535 return scm_call_1 (scm_variable_ref (cwp_var), port);
536}
537
538
185e369a 539void
661ae7ab 540scm_dynwind_current_input_port (SCM port)
9de87eea 541#define FUNC_NAME NULL
185e369a 542{
9de87eea 543 SCM_VALIDATE_OPINPORT (1, port);
661ae7ab 544 scm_dynwind_fluid (cur_inport_fluid, port);
185e369a 545}
9de87eea 546#undef FUNC_NAME
185e369a
MV
547
548void
661ae7ab 549scm_dynwind_current_output_port (SCM port)
9de87eea 550#define FUNC_NAME NULL
185e369a 551{
9de87eea
MV
552 port = SCM_COERCE_OUTPORT (port);
553 SCM_VALIDATE_OPOUTPORT (1, port);
661ae7ab 554 scm_dynwind_fluid (cur_outport_fluid, port);
185e369a 555}
9de87eea 556#undef FUNC_NAME
185e369a
MV
557
558void
661ae7ab 559scm_dynwind_current_error_port (SCM port)
9de87eea
MV
560#define FUNC_NAME NULL
561{
562 port = SCM_COERCE_OUTPORT (port);
563 SCM_VALIDATE_OPOUTPORT (1, port);
661ae7ab 564 scm_dynwind_fluid (cur_errport_fluid, port);
9de87eea
MV
565}
566#undef FUNC_NAME
567
568void
661ae7ab 569scm_i_dynwind_current_load_port (SCM port)
185e369a 570{
661ae7ab 571 scm_dynwind_fluid (cur_loadport_fluid, port);
185e369a
MV
572}
573
0f2d19dd 574\f
840ae05d 575/* The port table --- an array of pointers to ports. */
0f2d19dd 576
5dbc6c06
HWN
577/*
578 We need a global registry of ports to flush them all at exit, and to
05d7f762 579 get all the ports matching a file descriptor.
5dbc6c06
HWN
580 */
581SCM scm_i_port_weak_hash;
0f2d19dd 582
9de87eea 583scm_i_pthread_mutex_t scm_i_port_table_mutex = SCM_I_PTHREAD_MUTEX_INITIALIZER;
b9ad392e 584
651a0735
LC
585\f
586/* Port finalization. */
587
1cc91f1b 588
6922d92f 589static void finalize_port (void *, void *);
651a0735 590
f4bc4e59 591/* Register a finalizer for PORT. */
651a0735
LC
592static SCM_C_INLINE_KEYWORD void
593register_finalizer_for_port (SCM port)
594{
337edc59
MW
595 /* Register a finalizer for PORT so that its
596 type's `free' function gets called. */
75ba64d6 597 scm_i_set_finalizer (SCM2PTR (port), finalize_port, NULL);
651a0735
LC
598}
599
600/* Finalize the object (a port) pointed to by PTR. */
601static void
6922d92f 602finalize_port (void *ptr, void *data)
651a0735
LC
603{
604 long port_type;
605 SCM port = PTR2SCM (ptr);
606
607 if (!SCM_PORTP (port))
608 abort ();
609
610 if (SCM_OPENP (port))
611 {
612 if (SCM_REVEALED (port) > 0)
613 /* Keep "revealed" ports alive and re-register a finalizer. */
614 register_finalizer_for_port (port);
615 else
616 {
617 port_type = SCM_TC2PTOBNUM (SCM_CELL_TYPE (port));
618 if (port_type >= scm_numptob)
619 abort ();
620
621 if (scm_ptobs[port_type].free)
622 /* Yes, I really do mean `.free' rather than `.close'. `.close'
623 is for explicit `close-port' by user. */
624 scm_ptobs[port_type].free (port);
625
626 SCM_SETSTREAM (port, 0);
627 SCM_CLR_PORT_OPEN_FLAG (port);
651a0735
LC
628
629 scm_gc_ports_collected++;
630 }
631 }
632}
633
634
635
636\f
637
638/* This function is not and should not be thread safe. */
da220f27
HWN
639SCM
640scm_new_port_table_entry (scm_t_bits tag)
402788a9 641#define FUNC_NAME "scm_new_port_table_entry"
0f2d19dd 642{
85835e59
HWN
643 /*
644 We initialize the cell to empty, this is in case scm_gc_calloc
645 triggers GC ; we don't want the GC to scan a half-finished Z.
646 */
647
67329a9e 648 SCM z = scm_cons (SCM_EOL, SCM_EOL);
e4598559
MW
649 scm_t_port *entry = scm_gc_typed_calloc (scm_t_port);
650 scm_t_port_internal *pti = scm_gc_typed_calloc (scm_t_port_internal);
337edc59 651 const char *encoding;
5f16b897 652
840ae05d 653 entry->file_name = SCM_BOOL_F;
61e452ba 654 entry->rw_active = SCM_PORT_NEITHER;
5dbc6c06 655 entry->port = z;
9d9c66ba 656
889975e5
MG
657 /* Initialize this port with the thread's current default
658 encoding. */
337edc59 659 encoding = scm_i_default_port_encoding ();
b22e94db 660 entry->ilseq_handler = scm_i_default_port_conversion_handler ();
337edc59 661 entry->encoding = encoding ? scm_gc_strdup (encoding, "port") : NULL;
96965a6e 662 if (encoding && c_strcasecmp (encoding, "UTF-8") == 0)
337edc59
MW
663 pti->encoding_mode = SCM_PORT_ENCODING_MODE_UTF8;
664 else
665 pti->encoding_mode = SCM_PORT_ENCODING_MODE_ICONV;
666 pti->iconv_descriptors = NULL;
5f16b897 667
cdd3d6c9
MW
668 pti->at_stream_start_for_bom_read = 1;
669 pti->at_stream_start_for_bom_write = 1;
670
e4598559
MW
671 /* XXX These fields are not what they seem. They have been
672 repurposed, but cannot safely be renamed in 2.0 without breaking
673 ABI compatibility. This will be cleaned up in 2.2. */
674 entry->input_cd = pti; /* XXX pointer to the internal port structure */
675 entry->output_cd = NULL; /* XXX unused */
676
45c0878b 677 pti->pending_eof = 0;
05d7f762
MW
678 pti->alist = SCM_EOL;
679
5dbc6c06
HWN
680 SCM_SET_CELL_TYPE (z, tag);
681 SCM_SETPTAB_ENTRY (z, entry);
840ae05d 682
05d7f762 683 scm_hashq_set_x (scm_i_port_weak_hash, z, SCM_BOOL_F);
651a0735
LC
684
685 /* For each new port, register a finalizer so that it port type's free
686 function can be invoked eventually. */
687 register_finalizer_for_port (z);
688
da220f27 689 return z;
0f2d19dd 690}
c6c79933 691#undef FUNC_NAME
0f2d19dd 692
67329a9e 693#if SCM_ENABLE_DEPRECATED==1
8269ba5b 694scm_t_port *
67329a9e
HWN
695scm_add_to_port_table (SCM port)
696{
8269ba5b
AW
697 SCM z;
698 scm_t_port * pt;
67329a9e 699
8269ba5b
AW
700 scm_c_issue_deprecation_warning ("scm_add_to_port_table is deprecated.");
701
702 scm_i_pthread_mutex_lock (&scm_i_port_table_mutex);
703 z = scm_new_port_table_entry (scm_tc7_port);
704 pt = SCM_PTAB_ENTRY(z);
67329a9e 705 pt->port = port;
5dbc6c06
HWN
706 SCM_SETCAR (z, SCM_EOL);
707 SCM_SETCDR (z, SCM_EOL);
85835e59 708 SCM_SETPTAB_ENTRY (port, pt);
8269ba5b
AW
709 scm_i_pthread_mutex_unlock (&scm_i_port_table_mutex);
710
67329a9e
HWN
711 return pt;
712}
713#endif
714
715
6c951427 716/* Remove a port from the table and destroy it. */
b9ad392e 717
337edc59
MW
718static void close_iconv_descriptors (scm_t_iconv_descriptors *id);
719
8269ba5b 720static void
5dbc6c06
HWN
721scm_i_remove_port (SCM port)
722#define FUNC_NAME "scm_remove_port"
0f2d19dd 723{
8269ba5b 724 scm_t_port *p;
e4598559 725 scm_t_port_internal *pti;
682d78d0 726
8269ba5b 727 scm_i_scm_pthread_mutex_lock (&scm_i_port_table_mutex);
682d78d0 728
8269ba5b 729 p = SCM_PTAB_ENTRY (port);
e4598559 730 pti = SCM_PORT_GET_INTERNAL (port);
8269ba5b 731 scm_port_non_buffer (p);
682d78d0
LC
732 p->putback_buf = NULL;
733 p->putback_buf_size = 0;
3e05fc04 734
337edc59 735 if (pti->iconv_descriptors)
3e05fc04 736 {
337edc59
MW
737 close_iconv_descriptors (pti->iconv_descriptors);
738 pti->iconv_descriptors = NULL;
3e05fc04
AW
739 }
740
0f2d19dd 741 SCM_SETPTAB_ENTRY (port, 0);
8269ba5b 742
5dbc6c06 743 scm_hashq_remove_x (scm_i_port_weak_hash, port);
8269ba5b
AW
744
745 scm_i_pthread_mutex_unlock (&scm_i_port_table_mutex);
0f2d19dd 746}
db4b4ca6
DH
747#undef FUNC_NAME
748
0f2d19dd 749
b450f070 750/* Functions for debugging. */
5dbc6c06 751#ifdef GUILE_DEBUG
3b3b36dd 752SCM_DEFINE (scm_pt_size, "pt-size", 0, 0, 0,
b450f070 753 (),
1e6808ea 754 "Return the number of ports in the port table. @code{pt-size}\n"
5352393c 755 "is only included in @code{--enable-guile-debug} builds.")
1bbd0b84 756#define FUNC_NAME s_scm_pt_size
0f2d19dd 757{
5dbc6c06 758 return scm_from_int (SCM_HASHTABLE_N_ITEMS (scm_i_port_weak_hash));
0f2d19dd 759}
1bbd0b84 760#undef FUNC_NAME
0f2d19dd
JB
761#endif
762
70df8af6 763void
92c2555f 764scm_port_non_buffer (scm_t_port *pt)
70df8af6
GH
765{
766 pt->read_pos = pt->read_buf = pt->read_end = &pt->shortbuf;
767 pt->write_buf = pt->write_pos = &pt->shortbuf;
768 pt->read_buf_size = pt->write_buf_size = 1;
769 pt->write_end = pt->write_buf + pt->write_buf_size;
770}
0f2d19dd 771
d68fee48
JB
772\f
773/* Revealed counts --- an oddity inherited from SCSH. */
774
8b13c6b3
GH
775/* Find a port in the table and return its revealed count.
776 Also used by the garbage collector.
0f2d19dd 777 */
1cc91f1b 778
0f2d19dd 779int
a284e297 780scm_revealed_count (SCM port)
0f2d19dd
JB
781{
782 return SCM_REVEALED(port);
783}
784
785
786
787/* Return the revealed count for a port. */
788
3b3b36dd 789SCM_DEFINE (scm_port_revealed, "port-revealed", 1, 0, 0,
1bbd0b84 790 (SCM port),
1e6808ea 791 "Return the revealed count for @var{port}.")
1bbd0b84 792#define FUNC_NAME s_scm_port_revealed
0f2d19dd 793{
78446828 794 port = SCM_COERCE_OUTPORT (port);
34d19ef6 795 SCM_VALIDATE_OPENPORT (1, port);
e11e83f3 796 return scm_from_int (scm_revealed_count (port));
0f2d19dd 797}
1bbd0b84 798#undef FUNC_NAME
0f2d19dd
JB
799
800/* Set the revealed count for a port. */
3b3b36dd 801SCM_DEFINE (scm_set_port_revealed_x, "set-port-revealed!", 2, 0, 0,
1bbd0b84 802 (SCM port, SCM rcount),
b450f070 803 "Sets the revealed count for a port to a given value.\n"
b380b885 804 "The return value is unspecified.")
1bbd0b84 805#define FUNC_NAME s_scm_set_port_revealed_x
0f2d19dd 806{
78446828 807 port = SCM_COERCE_OUTPORT (port);
34d19ef6 808 SCM_VALIDATE_OPENPORT (1, port);
a55c2b68 809 SCM_REVEALED (port) = scm_to_int (rcount);
8b13c6b3 810 return SCM_UNSPECIFIED;
0f2d19dd 811}
1bbd0b84 812#undef FUNC_NAME
0f2d19dd 813
d68fee48
JB
814
815\f
816/* Retrieving a port's mode. */
817
eadd48de
GH
818/* Return the flags that characterize a port based on the mode
819 * string used to open a file for that port.
820 *
821 * See PORT FLAGS in scm.h
822 */
823
3a5fb14d 824static long
889975e5 825scm_i_mode_bits_n (SCM modes)
3a5fb14d
MV
826{
827 return (SCM_OPN
889975e5
MG
828 | (scm_i_string_contains_char (modes, 'r')
829 || scm_i_string_contains_char (modes, '+') ? SCM_RDNG : 0)
830 | (scm_i_string_contains_char (modes, 'w')
831 || scm_i_string_contains_char (modes, 'a')
832 || scm_i_string_contains_char (modes, '+') ? SCM_WRTNG : 0)
833 | (scm_i_string_contains_char (modes, '0') ? SCM_BUF0 : 0)
834 | (scm_i_string_contains_char (modes, 'l') ? SCM_BUFLINE : 0));
3a5fb14d
MV
835}
836
eadd48de 837long
a284e297 838scm_mode_bits (char *modes)
eadd48de 839{
889975e5 840 return scm_i_mode_bits (scm_from_locale_string (modes));
eadd48de
GH
841}
842
d617ee18
MV
843long
844scm_i_mode_bits (SCM modes)
845{
846 long bits;
847
848 if (!scm_is_string (modes))
849 scm_wrong_type_arg_msg (NULL, 0, modes, "string");
850
889975e5 851 bits = scm_i_mode_bits_n (modes);
d617ee18
MV
852 scm_remember_upto_here_1 (modes);
853 return bits;
854}
eadd48de
GH
855
856/* Return the mode flags from an open port.
857 * Some modes such as "append" are only used when opening
858 * a file and are not returned here. */
859
3b3b36dd 860SCM_DEFINE (scm_port_mode, "port-mode", 1, 0, 0,
1bbd0b84 861 (SCM port),
1e6808ea
MG
862 "Return the port modes associated with the open port @var{port}.\n"
863 "These will not necessarily be identical to the modes used when\n"
864 "the port was opened, since modes such as \"append\" which are\n"
865 "used only during port creation are not retained.")
1bbd0b84 866#define FUNC_NAME s_scm_port_mode
eadd48de 867{
26a3038d 868 char modes[4];
eadd48de 869 modes[0] = '\0';
78446828
MV
870
871 port = SCM_COERCE_OUTPORT (port);
34d19ef6 872 SCM_VALIDATE_OPPORT (1, port);
f9a64404
DH
873 if (SCM_CELL_WORD_0 (port) & SCM_RDNG) {
874 if (SCM_CELL_WORD_0 (port) & SCM_WRTNG)
eadd48de
GH
875 strcpy (modes, "r+");
876 else
877 strcpy (modes, "r");
878 }
f9a64404 879 else if (SCM_CELL_WORD_0 (port) & SCM_WRTNG)
eadd48de 880 strcpy (modes, "w");
f9a64404 881 if (SCM_CELL_WORD_0 (port) & SCM_BUF0)
eadd48de 882 strcat (modes, "0");
3a5fb14d 883 return scm_from_locale_string (modes);
eadd48de 884}
1bbd0b84 885#undef FUNC_NAME
eadd48de
GH
886
887
d68fee48
JB
888\f
889/* Closing ports. */
890
0f2d19dd
JB
891/* scm_close_port
892 * Call the close operation on a port object.
eadd48de 893 * see also scm_close.
0f2d19dd 894 */
3b3b36dd 895SCM_DEFINE (scm_close_port, "close-port", 1, 0, 0,
1bbd0b84 896 (SCM port),
1e6808ea
MG
897 "Close the specified port object. Return @code{#t} if it\n"
898 "successfully closes a port or @code{#f} if it was already\n"
899 "closed. An exception may be raised if an error occurs, for\n"
900 "example when flushing buffered output. See also @ref{Ports and\n"
901 "File Descriptors, close}, for a procedure which can close file\n"
902 "descriptors.")
1bbd0b84 903#define FUNC_NAME s_scm_close_port
0f2d19dd 904{
1be6b49c 905 size_t i;
eadd48de
GH
906 int rv;
907
78446828
MV
908 port = SCM_COERCE_OUTPORT (port);
909
7a754ca6 910 SCM_VALIDATE_PORT (1, port);
0f2d19dd 911 if (SCM_CLOSEDP (port))
eadd48de 912 return SCM_BOOL_F;
0f2d19dd 913 i = SCM_PTOBNUM (port);
affc96b5
GH
914 if (scm_ptobs[i].close)
915 rv = (scm_ptobs[i].close) (port);
eadd48de
GH
916 else
917 rv = 0;
5dbc6c06 918 scm_i_remove_port (port);
22a52da1 919 SCM_CLR_PORT_OPEN_FLAG (port);
7888309b 920 return scm_from_bool (rv >= 0);
7a754ca6
MD
921}
922#undef FUNC_NAME
923
924SCM_DEFINE (scm_close_input_port, "close-input-port", 1, 0, 0,
925 (SCM port),
926 "Close the specified input port object. The routine has no effect if\n"
927 "the file has already been closed. An exception may be raised if an\n"
928 "error occurs. The value returned is unspecified.\n\n"
929 "See also @ref{Ports and File Descriptors, close}, for a procedure\n"
930 "which can close file descriptors.")
931#define FUNC_NAME s_scm_close_input_port
932{
933 SCM_VALIDATE_INPUT_PORT (1, port);
934 scm_close_port (port);
935 return SCM_UNSPECIFIED;
936}
937#undef FUNC_NAME
938
939SCM_DEFINE (scm_close_output_port, "close-output-port", 1, 0, 0,
940 (SCM port),
941 "Close the specified output port object. The routine has no effect if\n"
942 "the file has already been closed. An exception may be raised if an\n"
943 "error occurs. The value returned is unspecified.\n\n"
944 "See also @ref{Ports and File Descriptors, close}, for a procedure\n"
945 "which can close file descriptors.")
946#define FUNC_NAME s_scm_close_output_port
947{
948 port = SCM_COERCE_OUTPORT (port);
949 SCM_VALIDATE_OUTPUT_PORT (1, port);
950 scm_close_port (port);
951 return SCM_UNSPECIFIED;
0f2d19dd 952}
1bbd0b84 953#undef FUNC_NAME
0f2d19dd 954
5dbc6c06 955static SCM
b7b4aef9 956collect_keys (void *unused, SCM key, SCM value, SCM result)
5dbc6c06 957{
b7b4aef9 958 return scm_cons (key, result);
5dbc6c06
HWN
959}
960
c536b4b3
MV
961void
962scm_c_port_for_each (void (*proc)(void *data, SCM p), void *data)
c2ca4493 963{
fdfe6305
MV
964 SCM ports;
965
b7b4aef9
AW
966 /* Copy out the port table as a list so that we get strong references
967 to all the values. */
5dbc6c06 968 scm_i_pthread_mutex_lock (&scm_i_port_table_mutex);
b7b4aef9
AW
969 ports = scm_internal_hash_fold (collect_keys, NULL,
970 SCM_EOL, scm_i_port_weak_hash);
9de87eea 971 scm_i_pthread_mutex_unlock (&scm_i_port_table_mutex);
3a5fb14d 972
b7b4aef9
AW
973 for (; scm_is_pair (ports); ports = scm_cdr (ports))
974 {
975 SCM p = scm_car (ports);
976 if (SCM_PORTP (p))
977 proc (data, p);
978 }
c536b4b3 979}
fdfe6305 980
c536b4b3
MV
981SCM_DEFINE (scm_port_for_each, "port-for-each", 1, 0, 0,
982 (SCM proc),
983 "Apply @var{proc} to each port in the Guile port table\n"
984 "in turn. The return value is unspecified. More specifically,\n"
985 "@var{proc} is applied exactly once to every port that exists\n"
b7e64f8b
BT
986 "in the system at the time @code{port-for-each} is invoked.\n"
987 "Changes to the port table while @code{port-for-each} is running\n"
988 "have no effect as far as @code{port-for-each} is concerned.")
c536b4b3
MV
989#define FUNC_NAME s_scm_port_for_each
990{
1b3daef0
AW
991 SCM ports;
992
c536b4b3
MV
993 SCM_VALIDATE_PROC (1, proc);
994
1b3daef0
AW
995 /* Copy out the port table as a list so that we get strong references
996 to all the values. */
997 scm_i_pthread_mutex_lock (&scm_i_port_table_mutex);
998 ports = scm_internal_hash_fold (collect_keys, NULL,
999 SCM_EOL, scm_i_port_weak_hash);
1000 scm_i_pthread_mutex_unlock (&scm_i_port_table_mutex);
1001
1002 for (; scm_is_pair (ports); ports = scm_cdr (ports))
1003 if (SCM_PORTP (SCM_CAR (ports)))
1004 scm_call_1 (proc, SCM_CAR (ports));
1005
c2ca4493
GH
1006 return SCM_UNSPECIFIED;
1007}
1008#undef FUNC_NAME
1009
c536b4b3 1010
d68fee48
JB
1011\f
1012/* Utter miscellany. Gosh, we should clean this up some time. */
1013
3b3b36dd 1014SCM_DEFINE (scm_input_port_p, "input-port?", 1, 0, 0,
1bbd0b84 1015 (SCM x),
1e6808ea
MG
1016 "Return @code{#t} if @var{x} is an input port, otherwise return\n"
1017 "@code{#f}. Any object satisfying this predicate also satisfies\n"
1018 "@code{port?}.")
1bbd0b84 1019#define FUNC_NAME s_scm_input_port_p
0f2d19dd 1020{
7888309b 1021 return scm_from_bool (SCM_INPUT_PORT_P (x));
0f2d19dd 1022}
1bbd0b84 1023#undef FUNC_NAME
0f2d19dd 1024
3b3b36dd 1025SCM_DEFINE (scm_output_port_p, "output-port?", 1, 0, 0,
1bbd0b84 1026 (SCM x),
1e6808ea
MG
1027 "Return @code{#t} if @var{x} is an output port, otherwise return\n"
1028 "@code{#f}. Any object satisfying this predicate also satisfies\n"
1029 "@code{port?}.")
1bbd0b84 1030#define FUNC_NAME s_scm_output_port_p
0f2d19dd 1031{
82893676 1032 x = SCM_COERCE_OUTPORT (x);
7888309b 1033 return scm_from_bool (SCM_OUTPUT_PORT_P (x));
0f2d19dd 1034}
1bbd0b84 1035#undef FUNC_NAME
0f2d19dd 1036
eb5c0a2a
GH
1037SCM_DEFINE (scm_port_p, "port?", 1, 0, 0,
1038 (SCM x),
1e6808ea 1039 "Return a boolean indicating whether @var{x} is a port.\n"
5352393c
MG
1040 "Equivalent to @code{(or (input-port? @var{x}) (output-port?\n"
1041 "@var{x}))}.")
eb5c0a2a
GH
1042#define FUNC_NAME s_scm_port_p
1043{
7888309b 1044 return scm_from_bool (SCM_PORTP (x));
eb5c0a2a
GH
1045}
1046#undef FUNC_NAME
1047
3b3b36dd 1048SCM_DEFINE (scm_port_closed_p, "port-closed?", 1, 0, 0,
1bbd0b84 1049 (SCM port),
1e6808ea
MG
1050 "Return @code{#t} if @var{port} is closed or @code{#f} if it is\n"
1051 "open.")
1bbd0b84 1052#define FUNC_NAME s_scm_port_closed_p
60d0643d 1053{
34d19ef6 1054 SCM_VALIDATE_PORT (1, port);
7888309b 1055 return scm_from_bool (!SCM_OPPORTP (port));
60d0643d 1056}
1bbd0b84 1057#undef FUNC_NAME
0f2d19dd 1058
3b3b36dd 1059SCM_DEFINE (scm_eof_object_p, "eof-object?", 1, 0, 0,
1bbd0b84 1060 (SCM x),
1e6808ea
MG
1061 "Return @code{#t} if @var{x} is an end-of-file object; otherwise\n"
1062 "return @code{#f}.")
1bbd0b84 1063#define FUNC_NAME s_scm_eof_object_p
0f2d19dd 1064{
7888309b 1065 return scm_from_bool(SCM_EOF_OBJECT_P (x));
0f2d19dd 1066}
1bbd0b84 1067#undef FUNC_NAME
0f2d19dd 1068
3b3b36dd 1069SCM_DEFINE (scm_force_output, "force-output", 0, 1, 0,
1bbd0b84 1070 (SCM port),
b380b885 1071 "Flush the specified output port, or the current output port if @var{port}\n"
9401323e 1072 "is omitted. The current output buffer contents are passed to the\n"
b380b885
MD
1073 "underlying port implementation (e.g., in the case of fports, the\n"
1074 "data will be written to the file and the output buffer will be cleared.)\n"
1075 "It has no effect on an unbuffered port.\n\n"
1076 "The return value is unspecified.")
1bbd0b84 1077#define FUNC_NAME s_scm_force_output
0f2d19dd
JB
1078{
1079 if (SCM_UNBNDP (port))
9de87eea 1080 port = scm_current_output_port ();
0f2d19dd 1081 else
78446828
MV
1082 {
1083 port = SCM_COERCE_OUTPORT (port);
34d19ef6 1084 SCM_VALIDATE_OPOUTPORT (1, port);
78446828 1085 }
affc96b5 1086 scm_flush (port);
ee149d03 1087 return SCM_UNSPECIFIED;
0f2d19dd 1088}
1bbd0b84 1089#undef FUNC_NAME
0f2d19dd 1090
5dbc6c06
HWN
1091
1092static void
61d3568b 1093flush_output_port (void *closure, SCM port)
5dbc6c06 1094{
5dbc6c06
HWN
1095 if (SCM_OPOUTPORTP (port))
1096 scm_flush (port);
1097}
1098
a1ec6916 1099SCM_DEFINE (scm_flush_all_ports, "flush-all-ports", 0, 0, 0,
1bbd0b84 1100 (),
b380b885
MD
1101 "Equivalent to calling @code{force-output} on\n"
1102 "all open output ports. The return value is unspecified.")
1bbd0b84 1103#define FUNC_NAME s_scm_flush_all_ports
89ea5b7c 1104{
5dbc6c06 1105 scm_c_port_for_each (&flush_output_port, NULL);
89ea5b7c
GH
1106 return SCM_UNSPECIFIED;
1107}
1bbd0b84 1108#undef FUNC_NAME
0f2d19dd 1109
3b3b36dd 1110SCM_DEFINE (scm_read_char, "read-char", 0, 1, 0,
1bbd0b84 1111 (SCM port),
1e6808ea
MG
1112 "Return the next character available from @var{port}, updating\n"
1113 "@var{port} to point to the following character. If no more\n"
c62da8f8
LC
1114 "characters are available, the end-of-file object is returned.\n"
1115 "\n"
1116 "When @var{port}'s data cannot be decoded according to its\n"
1117 "character encoding, a @code{decoding-error} is raised and\n"
1118 "@var{port} points past the erroneous byte sequence.\n")
1bbd0b84 1119#define FUNC_NAME s_scm_read_char
0f2d19dd 1120{
889975e5 1121 scm_t_wchar c;
0f2d19dd 1122 if (SCM_UNBNDP (port))
9de87eea 1123 port = scm_current_input_port ();
34d19ef6 1124 SCM_VALIDATE_OPINPORT (1, port);
b7f3516f 1125 c = scm_getc (port);
0f2d19dd
JB
1126 if (EOF == c)
1127 return SCM_EOF_VAL;
7866a09b 1128 return SCM_MAKE_CHAR (c);
0f2d19dd 1129}
1bbd0b84 1130#undef FUNC_NAME
0f2d19dd 1131
f4bc4e59
LC
1132/* Update the line and column number of PORT after consumption of C. */
1133static inline void
1134update_port_lf (scm_t_wchar c, SCM port)
1135{
1136 switch (c)
1137 {
1138 case '\a':
7b292a9d 1139 case EOF:
f4bc4e59
LC
1140 break;
1141 case '\b':
1142 SCM_DECCOL (port);
1143 break;
1144 case '\n':
1145 SCM_INCLINE (port);
1146 break;
1147 case '\r':
1148 SCM_ZEROCOL (port);
1149 break;
1150 case '\t':
1151 SCM_TABCOL (port);
1152 break;
1153 default:
1154 SCM_INCCOL (port);
1155 break;
1156 }
1157}
1158
889975e5
MG
1159#define SCM_MBCHAR_BUF_SIZE (4)
1160
f4bc4e59
LC
1161/* Convert the SIZE-byte UTF-8 sequence in UTF8_BUF to a codepoint.
1162 UTF8_BUF is assumed to contain a valid UTF-8 sequence. */
1163static scm_t_wchar
1164utf8_to_codepoint (const scm_t_uint8 *utf8_buf, size_t size)
1165{
1166 scm_t_wchar codepoint;
1167
1168 if (utf8_buf[0] <= 0x7f)
1169 {
1170 assert (size == 1);
1171 codepoint = utf8_buf[0];
1172 }
1173 else if ((utf8_buf[0] & 0xe0) == 0xc0)
1174 {
1175 assert (size == 2);
1176 codepoint = ((scm_t_wchar) utf8_buf[0] & 0x1f) << 6UL
1177 | (utf8_buf[1] & 0x3f);
1178 }
1179 else if ((utf8_buf[0] & 0xf0) == 0xe0)
1180 {
1181 assert (size == 3);
1182 codepoint = ((scm_t_wchar) utf8_buf[0] & 0x0f) << 12UL
1183 | ((scm_t_wchar) utf8_buf[1] & 0x3f) << 6UL
1184 | (utf8_buf[2] & 0x3f);
1185 }
1186 else
1187 {
1188 assert (size == 4);
1189 codepoint = ((scm_t_wchar) utf8_buf[0] & 0x07) << 18UL
1190 | ((scm_t_wchar) utf8_buf[1] & 0x3f) << 12UL
1191 | ((scm_t_wchar) utf8_buf[2] & 0x3f) << 6UL
1192 | (utf8_buf[3] & 0x3f);
1193 }
1194
1195 return codepoint;
1196}
1197
7b292a9d
LC
1198/* Read a UTF-8 sequence from PORT. On success, return 0 and set
1199 *CODEPOINT to the codepoint that was read, fill BUF with its UTF-8
1200 representation, and set *LEN to the length in bytes. Return
1201 `EILSEQ' on error. */
c62da8f8 1202static int
7b292a9d
LC
1203get_utf8_codepoint (SCM port, scm_t_wchar *codepoint,
1204 scm_t_uint8 buf[SCM_MBCHAR_BUF_SIZE], size_t *len)
889975e5 1205{
7b292a9d
LC
1206#define ASSERT_NOT_EOF(b) \
1207 if (SCM_UNLIKELY ((b) == EOF)) \
1208 goto invalid_seq
7be1705d
LC
1209#define CONSUME_PEEKED_BYTE() \
1210 pt->read_pos++
7b292a9d
LC
1211
1212 int byte;
7be1705d 1213 scm_t_port *pt;
7b292a9d
LC
1214
1215 *len = 0;
7be1705d 1216 pt = SCM_PTAB_ENTRY (port);
7b292a9d
LC
1217
1218 byte = scm_get_byte_or_eof (port);
1219 if (byte == EOF)
1220 {
1221 *codepoint = EOF;
1222 return 0;
1223 }
1224
1225 buf[0] = (scm_t_uint8) byte;
1226 *len = 1;
1227
1228 if (buf[0] <= 0x7f)
1229 /* 1-byte form. */
1230 *codepoint = buf[0];
1231 else if (buf[0] >= 0xc2 && buf[0] <= 0xdf)
1232 {
1233 /* 2-byte form. */
7be1705d 1234 byte = scm_peek_byte_or_eof (port);
7b292a9d
LC
1235 ASSERT_NOT_EOF (byte);
1236
7b292a9d
LC
1237 if (SCM_UNLIKELY ((byte & 0xc0) != 0x80))
1238 goto invalid_seq;
1239
7be1705d
LC
1240 CONSUME_PEEKED_BYTE ();
1241 buf[1] = (scm_t_uint8) byte;
1242 *len = 2;
1243
7b292a9d
LC
1244 *codepoint = ((scm_t_wchar) buf[0] & 0x1f) << 6UL
1245 | (buf[1] & 0x3f);
1246 }
1247 else if ((buf[0] & 0xf0) == 0xe0)
1248 {
1249 /* 3-byte form. */
7be1705d
LC
1250 byte = scm_peek_byte_or_eof (port);
1251 ASSERT_NOT_EOF (byte);
7b292a9d
LC
1252
1253 if (SCM_UNLIKELY ((byte & 0xc0) != 0x80
1254 || (buf[0] == 0xe0 && byte < 0xa0)
1255 || (buf[0] == 0xed && byte > 0x9f)))
7be1705d 1256 goto invalid_seq;
7b292a9d 1257
7be1705d
LC
1258 CONSUME_PEEKED_BYTE ();
1259 buf[1] = (scm_t_uint8) byte;
1260 *len = 2;
7b292a9d 1261
7be1705d 1262 byte = scm_peek_byte_or_eof (port);
7b292a9d
LC
1263 ASSERT_NOT_EOF (byte);
1264
7b292a9d
LC
1265 if (SCM_UNLIKELY ((byte & 0xc0) != 0x80))
1266 goto invalid_seq;
1267
7be1705d
LC
1268 CONSUME_PEEKED_BYTE ();
1269 buf[2] = (scm_t_uint8) byte;
1270 *len = 3;
1271
7b292a9d
LC
1272 *codepoint = ((scm_t_wchar) buf[0] & 0x0f) << 12UL
1273 | ((scm_t_wchar) buf[1] & 0x3f) << 6UL
1274 | (buf[2] & 0x3f);
1275 }
1276 else if (buf[0] >= 0xf0 && buf[0] <= 0xf4)
1277 {
1278 /* 4-byte form. */
7be1705d 1279 byte = scm_peek_byte_or_eof (port);
7b292a9d
LC
1280 ASSERT_NOT_EOF (byte);
1281
7b292a9d
LC
1282 if (SCM_UNLIKELY (((byte & 0xc0) != 0x80)
1283 || (buf[0] == 0xf0 && byte < 0x90)
1284 || (buf[0] == 0xf4 && byte > 0x8f)))
7be1705d 1285 goto invalid_seq;
7b292a9d 1286
7be1705d
LC
1287 CONSUME_PEEKED_BYTE ();
1288 buf[1] = (scm_t_uint8) byte;
1289 *len = 2;
1290
1291 byte = scm_peek_byte_or_eof (port);
7b292a9d
LC
1292 ASSERT_NOT_EOF (byte);
1293
7be1705d
LC
1294 if (SCM_UNLIKELY ((byte & 0xc0) != 0x80))
1295 goto invalid_seq;
1296
1297 CONSUME_PEEKED_BYTE ();
7b292a9d
LC
1298 buf[2] = (scm_t_uint8) byte;
1299 *len = 3;
1300
7be1705d 1301 byte = scm_peek_byte_or_eof (port);
7b292a9d
LC
1302 ASSERT_NOT_EOF (byte);
1303
7b292a9d
LC
1304 if (SCM_UNLIKELY ((byte & 0xc0) != 0x80))
1305 goto invalid_seq;
1306
7be1705d
LC
1307 CONSUME_PEEKED_BYTE ();
1308 buf[3] = (scm_t_uint8) byte;
1309 *len = 4;
1310
7b292a9d
LC
1311 *codepoint = ((scm_t_wchar) buf[0] & 0x07) << 18UL
1312 | ((scm_t_wchar) buf[1] & 0x3f) << 12UL
1313 | ((scm_t_wchar) buf[2] & 0x3f) << 6UL
1314 | (buf[3] & 0x3f);
1315 }
1316 else
1317 goto invalid_seq;
1318
1319 return 0;
1320
1321 invalid_seq:
7be1705d
LC
1322 /* Here we could choose the consume the faulty byte when it's not a
1323 valid starting byte, but it's not a requirement. What Section 3.9
1324 of Unicode 6.0.0 mandates, though, is to not consume a byte that
1325 would otherwise be a valid starting byte. */
1326
7b292a9d
LC
1327 return EILSEQ;
1328
7be1705d 1329#undef CONSUME_PEEKED_BYTE
7b292a9d
LC
1330#undef ASSERT_NOT_EOF
1331}
1332
1333/* Likewise, read a byte sequence from PORT, passing it through its
1334 input conversion descriptor. */
1335static int
1336get_iconv_codepoint (SCM port, scm_t_wchar *codepoint,
1337 char buf[SCM_MBCHAR_BUF_SIZE], size_t *len)
1338{
cdd3d6c9 1339 scm_t_iconv_descriptors *id;
f4bc4e59 1340 scm_t_uint8 utf8_buf[SCM_MBCHAR_BUF_SIZE];
1ee237d9 1341 size_t input_size = 0;
889975e5 1342
cdd3d6c9
MW
1343 id = scm_i_port_iconv_descriptors (port, SCM_PORT_READ);
1344
1ee237d9 1345 for (;;)
63479112 1346 {
1ee237d9
MW
1347 int byte_read;
1348 char *input, *output;
f4bc4e59 1349 size_t input_left, output_left, done;
889975e5 1350
f4bc4e59 1351 byte_read = scm_get_byte_or_eof (port);
1ee237d9 1352 if (SCM_UNLIKELY (byte_read == EOF))
889975e5 1353 {
1ee237d9
MW
1354 if (SCM_LIKELY (input_size == 0))
1355 {
1356 *codepoint = (scm_t_wchar) EOF;
1357 *len = input_size;
1358 return 0;
1359 }
1360 else
45c0878b
MW
1361 {
1362 /* EOF found in the middle of a multibyte character. */
1363 scm_i_set_pending_eof (port);
1364 return EILSEQ;
1365 }
889975e5
MG
1366 }
1367
1ee237d9 1368 buf[input_size++] = byte_read;
889975e5 1369
f4bc4e59 1370 input = buf;
1ee237d9
MW
1371 input_left = input_size;
1372 output = (char *) utf8_buf;
f4bc4e59 1373 output_left = sizeof (utf8_buf);
889975e5 1374
337edc59 1375 done = iconv (id->input_cd, &input, &input_left, &output, &output_left);
1ee237d9 1376
f4bc4e59 1377 if (done == (size_t) -1)
889975e5 1378 {
1ee237d9
MW
1379 int err = errno;
1380 if (SCM_LIKELY (err == EINVAL))
1381 /* The input byte sequence did not form a complete
1382 character. Read another byte and try again. */
1383 continue;
1384 else
1385 return err;
889975e5 1386 }
f4bc4e59 1387 else
1ee237d9
MW
1388 {
1389 size_t output_size = sizeof (utf8_buf) - output_left;
1390 if (SCM_LIKELY (output_size > 0))
1391 {
1392 /* iconv generated output. Convert the UTF8_BUF sequence
1393 to a Unicode code point. */
1394 *codepoint = utf8_to_codepoint (utf8_buf, output_size);
1395 *len = input_size;
1396 return 0;
1397 }
1398 else
1399 {
1400 /* iconv consumed some bytes without producing any output.
1401 Most likely this means that a Unicode byte-order mark
1402 (BOM) was consumed, which should not be included in the
1403 returned buf. Shift any remaining bytes to the beginning
1404 of buf, and continue the loop. */
1405 memmove (buf, input, input_left);
1406 input_size = input_left;
1407 continue;
1408 }
1409 }
7b292a9d 1410 }
7b292a9d 1411}
c62da8f8 1412
7b292a9d
LC
1413/* Read a codepoint from PORT and return it in *CODEPOINT. Fill BUF
1414 with the byte representation of the codepoint in PORT's encoding, and
1415 set *LEN to the length in bytes of that representation. Return 0 on
1416 success and an errno value on error. */
1417static int
1418get_codepoint (SCM port, scm_t_wchar *codepoint,
1419 char buf[SCM_MBCHAR_BUF_SIZE], size_t *len)
1420{
1421 int err;
1422 scm_t_port *pt = SCM_PTAB_ENTRY (port);
e4598559 1423 scm_t_port_internal *pti = SCM_PORT_GET_INTERNAL (port);
7b292a9d 1424
337edc59 1425 if (pti->encoding_mode == SCM_PORT_ENCODING_MODE_UTF8)
7b292a9d 1426 err = get_utf8_codepoint (port, codepoint, (scm_t_uint8 *) buf, len);
cc540d0b 1427 else
7b292a9d
LC
1428 err = get_iconv_codepoint (port, codepoint, buf, len);
1429
1430 if (SCM_LIKELY (err == 0))
cdd3d6c9
MW
1431 {
1432 if (SCM_UNLIKELY (pti->at_stream_start_for_bom_read))
1433 {
1434 /* Record that we're no longer at stream start. */
1435 pti->at_stream_start_for_bom_read = 0;
1436 if (pt->rw_random)
1437 pti->at_stream_start_for_bom_write = 0;
1438
1439 /* If we just read a BOM in an encoding that recognizes them,
1440 then silently consume it and read another code point. */
1441 if (SCM_UNLIKELY
1442 (*codepoint == SCM_UNICODE_BOM
1443 && (pti->encoding_mode == SCM_PORT_ENCODING_MODE_UTF8
96965a6e
MW
1444 || c_strcasecmp (pt->encoding, "UTF-16") == 0
1445 || c_strcasecmp (pt->encoding, "UTF-32") == 0)))
cdd3d6c9
MW
1446 return get_codepoint (port, codepoint, buf, len);
1447 }
1448 update_port_lf (*codepoint, port);
1449 }
7b292a9d 1450 else if (pt->ilseq_handler == SCM_ICONVEH_QUESTION_MARK)
a42d7971 1451 {
7b292a9d
LC
1452 *codepoint = '?';
1453 err = 0;
a42d7971
LC
1454 update_port_lf (*codepoint, port);
1455 }
889975e5 1456
c62da8f8 1457 return err;
889975e5
MG
1458}
1459
fd5eec2b
LC
1460/* Read a codepoint from PORT and return it. */
1461scm_t_wchar
1462scm_getc (SCM port)
c62da8f8 1463#define FUNC_NAME "scm_getc"
fd5eec2b 1464{
c62da8f8 1465 int err;
fd5eec2b 1466 size_t len;
c62da8f8 1467 scm_t_wchar codepoint;
fd5eec2b
LC
1468 char buf[SCM_MBCHAR_BUF_SIZE];
1469
c62da8f8
LC
1470 err = get_codepoint (port, &codepoint, buf, &len);
1471 if (SCM_UNLIKELY (err != 0))
1472 /* At this point PORT should point past the invalid encoding, as per
1473 R6RS-lib Section 8.2.4. */
1474 scm_decoding_error (FUNC_NAME, err, "input decoding error", port);
1475
1476 return codepoint;
fd5eec2b 1477}
c62da8f8 1478#undef FUNC_NAME
889975e5 1479
5c070ca7 1480/* this should only be called when the read buffer is empty. it
affc96b5 1481 tries to refill the read buffer. it returns the first char from
5c070ca7 1482 the port, which is either EOF or *(pt->read_pos). */
187fa0b9
MW
1483static int
1484scm_i_fill_input (SCM port)
6c951427 1485{
92c2555f 1486 scm_t_port *pt = SCM_PTAB_ENTRY (port);
45c0878b 1487 scm_t_port_internal *pti = SCM_PORT_GET_INTERNAL (port);
283a1a0e 1488
b5cb4464
NJ
1489 assert (pt->read_pos == pt->read_end);
1490
45c0878b
MW
1491 if (pti->pending_eof)
1492 {
1493 pti->pending_eof = 0;
1494 return EOF;
1495 }
1496
6c951427
GH
1497 if (pt->read_buf == pt->putback_buf)
1498 {
1499 /* finished reading put-back chars. */
1500 pt->read_buf = pt->saved_read_buf;
1501 pt->read_pos = pt->saved_read_pos;
1502 pt->read_end = pt->saved_read_end;
1503 pt->read_buf_size = pt->saved_read_buf_size;
1504 if (pt->read_pos < pt->read_end)
5c070ca7 1505 return *(pt->read_pos);
6c951427 1506 }
affc96b5 1507 return scm_ptobs[SCM_PTOBNUM (port)].fill_input (port);
6c951427
GH
1508}
1509
187fa0b9
MW
1510int
1511scm_fill_input (SCM port)
1512{
1513 return scm_i_fill_input (port);
1514}
1515
8a2b5965
MW
1516/* Slow-path fallback for 'scm_get_byte_or_eof' in inline.h */
1517int
e00793d7 1518scm_slow_get_byte_or_eof (SCM port)
8a2b5965
MW
1519{
1520 scm_t_port *pt = SCM_PTAB_ENTRY (port);
1521
1522 if (pt->rw_active == SCM_PORT_WRITE)
1523 scm_flush (port);
1524
1525 if (pt->rw_random)
1526 pt->rw_active = SCM_PORT_READ;
1527
1528 if (pt->read_pos >= pt->read_end)
1529 {
1530 if (SCM_UNLIKELY (scm_i_fill_input (port) == EOF))
1531 return EOF;
1532 }
1533
1534 return *pt->read_pos++;
1535}
1536
1537/* Slow-path fallback for 'scm_peek_byte_or_eof' in inline.h */
1538int
e00793d7 1539scm_slow_peek_byte_or_eof (SCM port)
8a2b5965
MW
1540{
1541 scm_t_port *pt = SCM_PTAB_ENTRY (port);
1542
1543 if (pt->rw_active == SCM_PORT_WRITE)
1544 scm_flush (port);
1545
1546 if (pt->rw_random)
1547 pt->rw_active = SCM_PORT_READ;
1548
1549 if (pt->read_pos >= pt->read_end)
1550 {
1551 if (SCM_UNLIKELY (scm_i_fill_input (port) == EOF))
45c0878b
MW
1552 {
1553 scm_i_set_pending_eof (port);
1554 return EOF;
1555 }
8a2b5965
MW
1556 }
1557
1558 return *pt->read_pos;
1559}
1560
3cb988bd 1561
6fe692e9
MD
1562/* scm_lfwrite
1563 *
53802ea8
MV
1564 * This function differs from scm_c_write; it updates port line and
1565 * column. */
6fe692e9 1566
9c44cd45 1567void
1be6b49c 1568scm_lfwrite (const char *ptr, size_t size, SCM port)
ee149d03 1569{
92c2555f
MV
1570 scm_t_port *pt = SCM_PTAB_ENTRY (port);
1571 scm_t_ptob_descriptor *ptob = &scm_ptobs[SCM_PTOBNUM (port)];
3e2043c4 1572
840ae05d 1573 if (pt->rw_active == SCM_PORT_READ)
affc96b5 1574 scm_end_input (port);
283a1a0e 1575
31703ab8 1576 ptob->write (port, ptr, size);
840ae05d 1577
9c44cd45
MG
1578 for (; size; ptr++, size--)
1579 update_port_lf ((scm_t_wchar) (unsigned char) *ptr, port);
1580
1581 if (pt->rw_random)
1582 pt->rw_active = SCM_PORT_WRITE;
1583}
1584
4325620f 1585/* Write STR to PORT from START inclusive to END exclusive. */
9c44cd45
MG
1586void
1587scm_lfwrite_substr (SCM str, size_t start, size_t end, SCM port)
1588{
9c44cd45 1589 scm_t_port *pt = SCM_PTAB_ENTRY (port);
9c44cd45
MG
1590
1591 if (pt->rw_active == SCM_PORT_READ)
1592 scm_end_input (port);
1593
4325620f
LC
1594 if (end == (size_t) -1)
1595 end = scm_i_string_length (str);
9c44cd45 1596
b908768a 1597 scm_i_display_substring (str, start, end, port);
53802ea8 1598
840ae05d
JB
1599 if (pt->rw_random)
1600 pt->rw_active = SCM_PORT_WRITE;
ee149d03 1601}
3cb988bd 1602
6fe692e9
MD
1603/* scm_c_read
1604 *
1605 * Used by an application to read arbitrary number of bytes from an
1606 * SCM port. Same semantics as libc read, except that scm_c_read only
1607 * returns less than SIZE bytes if at end-of-file.
1608 *
1609 * Warning: Doesn't update port line and column counts! */
1610
b5cb4464
NJ
1611/* This structure, and the following swap_buffer function, are used
1612 for temporarily swapping a port's own read buffer, and the buffer
1613 that the caller of scm_c_read provides. */
1614struct port_and_swap_buffer
1615{
1616 scm_t_port *pt;
1617 unsigned char *buffer;
1618 size_t size;
1619};
1620
1621static void
1622swap_buffer (void *data)
1623{
1624 struct port_and_swap_buffer *psb = (struct port_and_swap_buffer *) data;
1625 unsigned char *old_buf = psb->pt->read_buf;
1626 size_t old_size = psb->pt->read_buf_size;
1627
1628 /* Make the port use (buffer, size) from the struct. */
1629 psb->pt->read_pos = psb->pt->read_buf = psb->pt->read_end = psb->buffer;
1630 psb->pt->read_buf_size = psb->size;
1631
1632 /* Save the port's old (buffer, size) in the struct. */
1633 psb->buffer = old_buf;
1634 psb->size = old_size;
1635}
1636
1be6b49c
ML
1637size_t
1638scm_c_read (SCM port, void *buffer, size_t size)
693758d5 1639#define FUNC_NAME "scm_c_read"
6fe692e9 1640{
693758d5 1641 scm_t_port *pt;
1be6b49c 1642 size_t n_read = 0, n_available;
b5cb4464 1643 struct port_and_swap_buffer psb;
6fe692e9 1644
693758d5
LC
1645 SCM_VALIDATE_OPINPORT (1, port);
1646
1647 pt = SCM_PTAB_ENTRY (port);
6fe692e9
MD
1648 if (pt->rw_active == SCM_PORT_WRITE)
1649 scm_ptobs[SCM_PTOBNUM (port)].flush (port);
1650
1651 if (pt->rw_random)
1652 pt->rw_active = SCM_PORT_READ;
1653
b5cb4464
NJ
1654 /* Take bytes first from the port's read buffer. */
1655 if (pt->read_pos < pt->read_end)
6fe692e9 1656 {
b5cb4464 1657 n_available = min (size, pt->read_end - pt->read_pos);
6fe692e9 1658 memcpy (buffer, pt->read_pos, n_available);
910d1e40 1659 buffer = (char *) buffer + n_available;
6fe692e9
MD
1660 pt->read_pos += n_available;
1661 n_read += n_available;
6fe692e9 1662 size -= n_available;
6fe692e9
MD
1663 }
1664
b5cb4464
NJ
1665 /* Avoid the scm_dynwind_* costs if we now have enough data. */
1666 if (size == 0)
1667 return n_read;
1668
187fa0b9
MW
1669 /* Now we will call scm_i_fill_input repeatedly until we have read the
1670 requested number of bytes. (Note that a single scm_i_fill_input
b5cb4464 1671 call does not guarantee to fill the whole of the port's read
6d227556 1672 buffer.) */
c61be450
LC
1673 if (pt->read_buf_size <= 1 &&
1674 (pt->encoding == NULL
1675 || c_strcasecmp (pt->encoding, "ISO-8859-1") == 0))
b5cb4464 1676 {
6d227556
NJ
1677 /* The port that we are reading from is unbuffered - i.e. does
1678 not have its own persistent buffer - but we have a buffer,
1679 provided by our caller, that is the right size for the data
187fa0b9 1680 that is wanted. For the following scm_i_fill_input calls,
6d227556
NJ
1681 therefore, we use the buffer in hand as the port's read
1682 buffer.
1683
1684 We need to make sure that the port's normal (1 byte) buffer
187fa0b9 1685 is reinstated in case one of the scm_i_fill_input () calls
6d227556 1686 throws an exception; we use the scm_dynwind_* API to achieve
75192345
MG
1687 that.
1688
1689 A consequence of this optimization is that the fill_input
1690 functions can't unget characters. That'll push data to the
1691 pushback buffer instead of this psb buffer. */
1692#if SCM_DEBUG == 1
1693 unsigned char *pback = pt->putback_buf;
1694#endif
6d227556
NJ
1695 psb.pt = pt;
1696 psb.buffer = buffer;
1697 psb.size = size;
1698 scm_dynwind_begin (SCM_F_DYNWIND_REWINDABLE);
1699 scm_dynwind_rewind_handler (swap_buffer, &psb, SCM_F_WIND_EXPLICITLY);
1700 scm_dynwind_unwind_handler (swap_buffer, &psb, SCM_F_WIND_EXPLICITLY);
1701
187fa0b9 1702 /* Call scm_i_fill_input until we have all the bytes that we need,
6d227556 1703 or we hit EOF. */
187fa0b9 1704 while (pt->read_buf_size && (scm_i_fill_input (port) != EOF))
6d227556
NJ
1705 {
1706 pt->read_buf_size -= (pt->read_end - pt->read_pos);
1707 pt->read_pos = pt->read_buf = pt->read_end;
1708 }
75192345
MG
1709#if SCM_DEBUG == 1
1710 if (pback != pt->putback_buf
1711 || pt->read_buf - (unsigned char *) buffer < 0)
1712 scm_misc_error (FUNC_NAME,
1713 "scm_c_read must not call a fill function that pushes "
1714 "back characters onto an unbuffered port", SCM_EOL);
1715#endif
6d227556 1716 n_read += pt->read_buf - (unsigned char *) buffer;
75192345 1717
6d227556
NJ
1718 /* Reinstate the port's normal buffer. */
1719 scm_dynwind_end ();
1720 }
1721 else
1722 {
1723 /* The port has its own buffer. It is important that we use it,
1724 even if it happens to be smaller than our caller's buffer, so
1725 that a custom port implementation's entry points (in
1726 particular, fill_input) can rely on the buffer always being
1727 the same as they first set up. */
187fa0b9 1728 while (size && (scm_i_fill_input (port) != EOF))
6d227556
NJ
1729 {
1730 n_available = min (size, pt->read_end - pt->read_pos);
1731 memcpy (buffer, pt->read_pos, n_available);
1732 buffer = (char *) buffer + n_available;
1733 pt->read_pos += n_available;
1734 n_read += n_available;
1735 size -= n_available;
1736 }
1737 }
6fe692e9 1738
b5cb4464 1739 return n_read;
6fe692e9 1740}
693758d5 1741#undef FUNC_NAME
6fe692e9
MD
1742
1743/* scm_c_write
1744 *
1745 * Used by an application to write arbitrary number of bytes to an SCM
1746 * port. Similar semantics as libc write. However, unlike libc
1747 * write, scm_c_write writes the requested number of bytes and has no
1748 * return value.
1749 *
1750 * Warning: Doesn't update port line and column counts!
1751 */
1752
693758d5 1753void
1be6b49c 1754scm_c_write (SCM port, const void *ptr, size_t size)
693758d5 1755#define FUNC_NAME "scm_c_write"
6fe692e9 1756{
693758d5
LC
1757 scm_t_port *pt;
1758 scm_t_ptob_descriptor *ptob;
1759
1760 SCM_VALIDATE_OPOUTPORT (1, port);
1761
1762 pt = SCM_PTAB_ENTRY (port);
1763 ptob = &scm_ptobs[SCM_PTOBNUM (port)];
6fe692e9
MD
1764
1765 if (pt->rw_active == SCM_PORT_READ)
1766 scm_end_input (port);
1767
1768 ptob->write (port, ptr, size);
1769
1770 if (pt->rw_random)
1771 pt->rw_active = SCM_PORT_WRITE;
1772}
693758d5 1773#undef FUNC_NAME
3cb988bd 1774
fca43887 1775void
a284e297 1776scm_flush (SCM port)
ee149d03 1777{
c014a02e 1778 long i = SCM_PTOBNUM (port);
7f2a6c38 1779 assert (i >= 0);
affc96b5 1780 (scm_ptobs[i].flush) (port);
ee149d03
JB
1781}
1782
283a1a0e 1783void
a284e297 1784scm_end_input (SCM port)
283a1a0e 1785{
c014a02e 1786 long offset;
92c2555f 1787 scm_t_port *pt = SCM_PTAB_ENTRY (port);
283a1a0e 1788
45c0878b 1789 scm_i_clear_pending_eof (port);
283a1a0e
GH
1790 if (pt->read_buf == pt->putback_buf)
1791 {
1792 offset = pt->read_end - pt->read_pos;
1793 pt->read_buf = pt->saved_read_buf;
1794 pt->read_pos = pt->saved_read_pos;
1795 pt->read_end = pt->saved_read_end;
1796 pt->read_buf_size = pt->saved_read_buf_size;
1797 }
1798 else
1799 offset = 0;
1800
affc96b5 1801 scm_ptobs[SCM_PTOBNUM (port)].end_input (port, offset);
283a1a0e
GH
1802}
1803
ee149d03
JB
1804\f
1805
1806
7f6c3f8f
MW
1807static void
1808scm_i_unget_bytes (const unsigned char *buf, size_t len, SCM port)
1809#define FUNC_NAME "scm_unget_bytes"
ee149d03 1810{
92c2555f 1811 scm_t_port *pt = SCM_PTAB_ENTRY (port);
7f6c3f8f 1812 size_t old_len, new_len;
840ae05d 1813
45c0878b 1814 scm_i_clear_pending_eof (port);
6c951427 1815
7f6c3f8f 1816 if (pt->read_buf != pt->putback_buf)
6c951427
GH
1817 /* switch to the put-back buffer. */
1818 {
1819 if (pt->putback_buf == NULL)
1820 {
7f6c3f8f
MW
1821 pt->putback_buf_size = (len > SCM_INITIAL_PUTBACK_BUF_SIZE
1822 ? len : SCM_INITIAL_PUTBACK_BUF_SIZE);
c357d546 1823 pt->putback_buf
92d8fd32 1824 = (unsigned char *) scm_gc_malloc_pointerless
7f6c3f8f 1825 (pt->putback_buf_size, "putback buffer");
6c951427
GH
1826 }
1827
1828 pt->saved_read_buf = pt->read_buf;
1829 pt->saved_read_pos = pt->read_pos;
1830 pt->saved_read_end = pt->read_end;
1831 pt->saved_read_buf_size = pt->read_buf_size;
1832
7f6c3f8f
MW
1833 /* Put read_pos at the end of the buffer, so that ungets will not
1834 have to shift the buffer contents each time. */
1835 pt->read_buf = pt->putback_buf;
1836 pt->read_pos = pt->read_end = pt->putback_buf + pt->putback_buf_size;
6c951427
GH
1837 pt->read_buf_size = pt->putback_buf_size;
1838 }
1839
7f6c3f8f
MW
1840 old_len = pt->read_end - pt->read_pos;
1841 new_len = old_len + len;
1842
1843 if (new_len > pt->read_buf_size)
1844 /* The putback buffer needs to be enlarged. */
1845 {
1846 size_t new_buf_size;
1847 unsigned char *new_buf, *new_end, *new_pos;
1848
1849 new_buf_size = pt->read_buf_size * 2;
1850 if (new_buf_size < new_len)
1851 new_buf_size = new_len;
1852
1853 new_buf = (unsigned char *)
1854 scm_gc_malloc_pointerless (new_buf_size, "putback buffer");
1855
1856 /* Put the bytes at the end of the buffer, so that future
1857 ungets won't need to shift the buffer. */
1858 new_end = new_buf + new_buf_size;
1859 new_pos = new_end - old_len;
1860 memcpy (new_pos, pt->read_pos, old_len);
1861
1862 pt->read_buf = pt->putback_buf = new_buf;
1863 pt->read_pos = new_pos;
1864 pt->read_end = new_end;
1865 pt->read_buf_size = pt->putback_buf_size = new_buf_size;
1866 }
1867 else if (pt->read_buf + len < pt->read_pos)
1868 /* If needed, shift the existing buffer contents up.
1869 This should not happen unless some external code
1870 manipulates the putback buffer pointers. */
1871 {
1872 unsigned char *new_end = pt->read_buf + pt->read_buf_size;
1873 unsigned char *new_pos = new_end - old_len;
1874
1875 memmove (new_pos, pt->read_pos, old_len);
1876 pt->read_pos = new_pos;
1877 pt->read_end = new_end;
1878 }
1879
1880 /* Move read_pos back and copy the bytes there. */
1881 pt->read_pos -= len;
1882 memcpy (pt->read_buf + (pt->read_pos - pt->read_buf), buf, len);
1883
1884 if (pt->rw_active == SCM_PORT_WRITE)
1885 scm_flush (port);
ee149d03 1886
840ae05d
JB
1887 if (pt->rw_random)
1888 pt->rw_active = SCM_PORT_READ;
889975e5
MG
1889}
1890#undef FUNC_NAME
1891
7f6c3f8f
MW
1892void
1893scm_unget_bytes (const unsigned char *buf, size_t len, SCM port)
1894{
1895 scm_i_unget_bytes (buf, len, port);
1896}
1897
1898void
1899scm_unget_byte (int c, SCM port)
1900{
1901 unsigned char byte;
1902
1903 byte = c;
1904 scm_i_unget_bytes (&byte, 1, port);
1905}
1906
63479112 1907void
889975e5
MG
1908scm_ungetc (scm_t_wchar c, SCM port)
1909#define FUNC_NAME "scm_ungetc"
1910{
1911 scm_t_port *pt = SCM_PTAB_ENTRY (port);
63479112
LC
1912 char *result;
1913 char result_buf[10];
1914 const char *encoding;
889975e5 1915 size_t len;
889975e5 1916
63479112
LC
1917 if (pt->encoding != NULL)
1918 encoding = pt->encoding;
1919 else
1920 encoding = "ISO-8859-1";
1921
1922 len = sizeof (result_buf);
1923 result = u32_conv_to_encoding (encoding,
1924 (enum iconv_ilseq_handler) pt->ilseq_handler,
1925 (uint32_t *) &c, 1, NULL,
1926 result_buf, &len);
1927
1928 if (SCM_UNLIKELY (result == NULL || len == 0))
6851d3be
LC
1929 scm_encoding_error (FUNC_NAME, errno,
1930 "conversion to port encoding failed",
1931 SCM_BOOL_F, SCM_MAKE_CHAR (c));
63479112 1932
7f6c3f8f 1933 scm_i_unget_bytes ((unsigned char *) result, len, port);
63479112
LC
1934
1935 if (SCM_UNLIKELY (result != result_buf))
1936 free (result);
840ae05d 1937
ee149d03
JB
1938 if (c == '\n')
1939 {
1940 /* What should col be in this case?
1941 * We'll leave it at -1.
1942 */
1943 SCM_LINUM (port) -= 1;
1944 }
1945 else
1946 SCM_COL(port) -= 1;
1947}
c6c79933 1948#undef FUNC_NAME
ee149d03
JB
1949
1950
1951void
70d63753 1952scm_ungets (const char *s, int n, SCM port)
ee149d03
JB
1953{
1954 /* This is simple minded and inefficient, but unreading strings is
1955 * probably not a common operation, and remember that line and
1956 * column numbers have to be handled...
1957 *
1958 * Please feel free to write an optimized version!
1959 */
1960 while (n--)
1961 scm_ungetc (s[n], port);
1962}
1963
1964
3b3b36dd 1965SCM_DEFINE (scm_peek_char, "peek-char", 0, 1, 0,
1bbd0b84 1966 (SCM port),
1e6808ea
MG
1967 "Return the next character available from @var{port},\n"
1968 "@emph{without} updating @var{port} to point to the following\n"
1969 "character. If no more characters are available, the\n"
c2dfff19
KR
1970 "end-of-file object is returned.\n"
1971 "\n"
1972 "The value returned by\n"
1e6808ea
MG
1973 "a call to @code{peek-char} is the same as the value that would\n"
1974 "have been returned by a call to @code{read-char} on the same\n"
1975 "port. The only difference is that the very next call to\n"
1976 "@code{read-char} or @code{peek-char} on that @var{port} will\n"
1977 "return the value returned by the preceding call to\n"
1978 "@code{peek-char}. In particular, a call to @code{peek-char} on\n"
1979 "an interactive port will hang waiting for input whenever a call\n"
c62da8f8
LC
1980 "to @code{read-char} would have hung.\n"
1981 "\n"
1982 "As for @code{read-char}, a @code{decoding-error} may be raised\n"
1983 "if such a situation occurs. However, unlike with @code{read-char},\n"
1984 "@var{port} still points at the beginning of the erroneous byte\n"
1985 "sequence when the error is raised.\n")
1bbd0b84 1986#define FUNC_NAME s_scm_peek_char
ee149d03 1987{
c62da8f8 1988 int err;
fd5eec2b
LC
1989 SCM result;
1990 scm_t_wchar c;
1991 char bytes[SCM_MBCHAR_BUF_SIZE];
7f6c3f8f 1992 long column, line;
fd5eec2b
LC
1993 size_t len;
1994
ee149d03 1995 if (SCM_UNBNDP (port))
9de87eea 1996 port = scm_current_input_port ();
b2456dd4 1997 SCM_VALIDATE_OPINPORT (1, port);
fd5eec2b
LC
1998
1999 column = SCM_COL (port);
2000 line = SCM_LINUM (port);
2001
c62da8f8 2002 err = get_codepoint (port, &c, bytes, &len);
fd5eec2b 2003
7f6c3f8f 2004 scm_i_unget_bytes ((unsigned char *) bytes, len, port);
fd5eec2b 2005
c62da8f8
LC
2006 SCM_COL (port) = column;
2007 SCM_LINUM (port) = line;
fd5eec2b 2008
c62da8f8
LC
2009 if (SCM_UNLIKELY (err != 0))
2010 {
2011 scm_decoding_error (FUNC_NAME, err, "input decoding error", port);
2012
2013 /* Shouldn't happen since `catch' always aborts to prompt. */
2014 result = SCM_BOOL_F;
fd5eec2b 2015 }
c62da8f8 2016 else if (c == EOF)
45c0878b
MW
2017 {
2018 scm_i_set_pending_eof (port);
2019 result = SCM_EOF_VAL;
2020 }
c62da8f8
LC
2021 else
2022 result = SCM_MAKE_CHAR (c);
fd5eec2b
LC
2023
2024 return result;
3cb988bd 2025}
1bbd0b84 2026#undef FUNC_NAME
3cb988bd 2027
1be4270a 2028SCM_DEFINE (scm_unread_char, "unread-char", 1, 1, 0,
1bbd0b84 2029 (SCM cobj, SCM port),
b7e64f8b
BT
2030 "Place character @var{cobj} in @var{port} so that it will be\n"
2031 "read by the next read operation. If called multiple times, the\n"
2032 "unread characters will be read again in last-in first-out\n"
2033 "order. If @var{port} is not supplied, the current input port\n"
2034 "is used.")
1bbd0b84 2035#define FUNC_NAME s_scm_unread_char
0f2d19dd
JB
2036{
2037 int c;
2038
34d19ef6 2039 SCM_VALIDATE_CHAR (1, cobj);
0f2d19dd 2040 if (SCM_UNBNDP (port))
9de87eea 2041 port = scm_current_input_port ();
b2456dd4 2042 SCM_VALIDATE_OPINPORT (2, port);
0f2d19dd 2043
7866a09b 2044 c = SCM_CHAR (cobj);
0f2d19dd 2045
b7f3516f 2046 scm_ungetc (c, port);
0f2d19dd
JB
2047 return cobj;
2048}
1bbd0b84 2049#undef FUNC_NAME
0f2d19dd 2050
a1ec6916 2051SCM_DEFINE (scm_unread_string, "unread-string", 2, 0, 0,
1bbd0b84 2052 (SCM str, SCM port),
b380b885
MD
2053 "Place the string @var{str} in @var{port} so that its characters will be\n"
2054 "read in subsequent read operations. If called multiple times, the\n"
2055 "unread characters will be read again in last-in first-out order. If\n"
2056 "@var{port} is not supplied, the current-input-port is used.")
1bbd0b84 2057#define FUNC_NAME s_scm_unread_string
ee1e7e13 2058{
889975e5 2059 int n;
34d19ef6 2060 SCM_VALIDATE_STRING (1, str);
ee1e7e13 2061 if (SCM_UNBNDP (port))
9de87eea 2062 port = scm_current_input_port ();
b2456dd4 2063 SCM_VALIDATE_OPINPORT (2, port);
ee1e7e13 2064
889975e5
MG
2065 n = scm_i_string_length (str);
2066
2067 while (n--)
2068 scm_ungetc (scm_i_string_ref (str, n), port);
ee1e7e13
MD
2069
2070 return str;
2071}
1bbd0b84 2072#undef FUNC_NAME
ee1e7e13 2073
a1ec6916 2074SCM_DEFINE (scm_seek, "seek", 3, 0, 0,
1e6808ea 2075 (SCM fd_port, SCM offset, SCM whence),
b7e64f8b 2076 "Sets the current position of @var{fd_port} to the integer\n"
1e6808ea
MG
2077 "@var{offset}, which is interpreted according to the value of\n"
2078 "@var{whence}.\n"
2079 "\n"
2080 "One of the following variables should be supplied for\n"
2081 "@var{whence}:\n"
b380b885
MD
2082 "@defvar SEEK_SET\n"
2083 "Seek from the beginning of the file.\n"
2084 "@end defvar\n"
2085 "@defvar SEEK_CUR\n"
2086 "Seek from the current position.\n"
2087 "@end defvar\n"
2088 "@defvar SEEK_END\n"
2089 "Seek from the end of the file.\n"
1e6808ea 2090 "@end defvar\n"
b7e64f8b 2091 "If @var{fd_port} is a file descriptor, the underlying system\n"
1e6808ea
MG
2092 "call is @code{lseek}. @var{port} may be a string port.\n"
2093 "\n"
2094 "The value returned is the new position in the file. This means\n"
2095 "that the current position of a port can be obtained using:\n"
2096 "@lisp\n"
b380b885 2097 "(seek port 0 SEEK_CUR)\n"
1e6808ea 2098 "@end lisp")
1bbd0b84 2099#define FUNC_NAME s_scm_seek
840ae05d 2100{
840ae05d
JB
2101 int how;
2102
1e6808ea 2103 fd_port = SCM_COERCE_OUTPORT (fd_port);
840ae05d 2104
a55c2b68 2105 how = scm_to_int (whence);
840ae05d 2106 if (how != SEEK_SET && how != SEEK_CUR && how != SEEK_END)
1bbd0b84 2107 SCM_OUT_OF_RANGE (3, whence);
23f2b9a3 2108
0a94eb00 2109 if (SCM_OPPORTP (fd_port))
840ae05d 2110 {
cdd3d6c9 2111 scm_t_port_internal *pti = SCM_PORT_GET_INTERNAL (fd_port);
92c2555f 2112 scm_t_ptob_descriptor *ptob = scm_ptobs + SCM_PTOBNUM (fd_port);
f1ce9199
LC
2113 off_t_or_off64_t off = scm_to_off_t_or_off64_t (offset);
2114 off_t_or_off64_t rv;
840ae05d
JB
2115
2116 if (!ptob->seek)
1bbd0b84 2117 SCM_MISC_ERROR ("port is not seekable",
1e6808ea 2118 scm_cons (fd_port, SCM_EOL));
840ae05d 2119 else
cdd3d6c9
MW
2120 rv = ptob->seek (fd_port, off, how);
2121
2122 /* Set stream-start flags according to new position. */
2123 pti->at_stream_start_for_bom_read = (rv == 0);
2124 pti->at_stream_start_for_bom_write = (rv == 0);
2125
2126 scm_i_clear_pending_eof (fd_port);
2127
f1ce9199 2128 return scm_from_off_t_or_off64_t (rv);
840ae05d
JB
2129 }
2130 else /* file descriptor?. */
2131 {
23f2b9a3
KR
2132 off_t_or_off64_t off = scm_to_off_t_or_off64_t (offset);
2133 off_t_or_off64_t rv;
2134 rv = lseek_or_lseek64 (scm_to_int (fd_port), off, how);
840ae05d 2135 if (rv == -1)
1bbd0b84 2136 SCM_SYSERROR;
23f2b9a3 2137 return scm_from_off_t_or_off64_t (rv);
840ae05d 2138 }
840ae05d 2139}
1bbd0b84 2140#undef FUNC_NAME
840ae05d 2141
8ab3d8a0
KR
2142#ifndef O_BINARY
2143#define O_BINARY 0
2144#endif
2145
2146/* Mingw has ftruncate(), perhaps implemented above using chsize, but
2147 doesn't have the filename version truncate(), hence this code. */
2148#if HAVE_FTRUNCATE && ! HAVE_TRUNCATE
2149static int
2150truncate (const char *file, off_t length)
82893676 2151{
8ab3d8a0
KR
2152 int ret, fdes;
2153
2154 fdes = open (file, O_BINARY | O_WRONLY);
2155 if (fdes == -1)
2156 return -1;
2157
2158 ret = ftruncate (fdes, length);
2159 if (ret == -1)
82893676 2160 {
8ab3d8a0 2161 int save_errno = errno;
82893676 2162 close (fdes);
8ab3d8a0
KR
2163 errno = save_errno;
2164 return -1;
82893676 2165 }
8ab3d8a0
KR
2166
2167 return close (fdes);
82893676 2168}
8ab3d8a0 2169#endif /* HAVE_FTRUNCATE && ! HAVE_TRUNCATE */
82893676 2170
a1ec6916 2171SCM_DEFINE (scm_truncate_file, "truncate-file", 1, 1, 0,
1bbd0b84 2172 (SCM object, SCM length),
b7e64f8b
BT
2173 "Truncate file @var{object} to @var{length} bytes. @var{object}\n"
2174 "can be a filename string, a port object, or an integer file\n"
2175 "descriptor.\n"
8ab3d8a0
KR
2176 "The return value is unspecified.\n"
2177 "\n"
2178 "For a port or file descriptor @var{length} can be omitted, in\n"
2179 "which case the file is truncated at the current position (per\n"
2180 "@code{ftell} above).\n"
2181 "\n"
2182 "On most systems a file can be extended by giving a length\n"
2183 "greater than the current size, but this is not mandatory in the\n"
2184 "POSIX standard.")
1bbd0b84 2185#define FUNC_NAME s_scm_truncate_file
840ae05d 2186{
69bc9ff3 2187 int rv;
69bc9ff3 2188
2b829bbb
KR
2189 /* "object" can be a port, fdes or filename.
2190
2191 Negative "length" makes no sense, but it's left to truncate() or
2192 ftruncate() to give back an error for that (normally EINVAL).
2193 */
840ae05d 2194
840ae05d
JB
2195 if (SCM_UNBNDP (length))
2196 {
69bc9ff3 2197 /* must supply length if object is a filename. */
7f9994d9 2198 if (scm_is_string (object))
34d19ef6 2199 SCM_MISC_ERROR("must supply length if OBJECT is a filename", SCM_EOL);
69bc9ff3 2200
e11e83f3 2201 length = scm_seek (object, SCM_INUM0, scm_from_int (SEEK_CUR));
840ae05d 2202 }
3fe6190f 2203
69bc9ff3 2204 object = SCM_COERCE_OUTPORT (object);
e11e83f3 2205 if (scm_is_integer (object))
69bc9ff3 2206 {
23f2b9a3
KR
2207 off_t_or_off64_t c_length = scm_to_off_t_or_off64_t (length);
2208 SCM_SYSCALL (rv = ftruncate_or_ftruncate64 (scm_to_int (object),
2209 c_length));
69bc9ff3 2210 }
0c95b57d 2211 else if (SCM_OPOUTPORTP (object))
69bc9ff3 2212 {
f1ce9199 2213 off_t_or_off64_t c_length = scm_to_off_t_or_off64_t (length);
92c2555f
MV
2214 scm_t_port *pt = SCM_PTAB_ENTRY (object);
2215 scm_t_ptob_descriptor *ptob = scm_ptobs + SCM_PTOBNUM (object);
45c0878b 2216
affc96b5 2217 if (!ptob->truncate)
1bbd0b84 2218 SCM_MISC_ERROR ("port is not truncatable", SCM_EOL);
45c0878b
MW
2219
2220 scm_i_clear_pending_eof (object);
69bc9ff3 2221 if (pt->rw_active == SCM_PORT_READ)
affc96b5 2222 scm_end_input (object);
69bc9ff3 2223 else if (pt->rw_active == SCM_PORT_WRITE)
affc96b5 2224 ptob->flush (object);
45c0878b 2225
affc96b5 2226 ptob->truncate (object, c_length);
69bc9ff3
GH
2227 rv = 0;
2228 }
2229 else
2230 {
2b829bbb 2231 off_t_or_off64_t c_length = scm_to_off_t_or_off64_t (length);
7f9994d9
MV
2232 char *str = scm_to_locale_string (object);
2233 int eno;
2b829bbb 2234 SCM_SYSCALL (rv = truncate_or_truncate64 (str, c_length));
7f9994d9
MV
2235 eno = errno;
2236 free (str);
2237 errno = eno;
69bc9ff3
GH
2238 }
2239 if (rv == -1)
1bbd0b84 2240 SCM_SYSERROR;
840ae05d
JB
2241 return SCM_UNSPECIFIED;
2242}
1bbd0b84 2243#undef FUNC_NAME
840ae05d 2244
a1ec6916 2245SCM_DEFINE (scm_port_line, "port-line", 1, 0, 0,
1bbd0b84 2246 (SCM port),
a150979d
KR
2247 "Return the current line number for @var{port}.\n"
2248 "\n"
2249 "The first line of a file is 0. But you might want to add 1\n"
2250 "when printing line numbers, since starting from 1 is\n"
2251 "traditional in error messages, and likely to be more natural to\n"
2252 "non-programmers.")
1bbd0b84 2253#define FUNC_NAME s_scm_port_line
0f2d19dd 2254{
78446828 2255 port = SCM_COERCE_OUTPORT (port);
34d19ef6 2256 SCM_VALIDATE_OPENPORT (1, port);
651f2cd2 2257 return scm_from_long (SCM_LINUM (port));
0f2d19dd 2258}
1bbd0b84 2259#undef FUNC_NAME
0f2d19dd 2260
a1ec6916 2261SCM_DEFINE (scm_set_port_line_x, "set-port-line!", 2, 0, 0,
1bbd0b84 2262 (SCM port, SCM line),
a150979d
KR
2263 "Set the current line number for @var{port} to @var{line}. The\n"
2264 "first line of a file is 0.")
1bbd0b84 2265#define FUNC_NAME s_scm_set_port_line_x
d043d8c2 2266{
360fc44c 2267 port = SCM_COERCE_OUTPORT (port);
34d19ef6 2268 SCM_VALIDATE_OPENPORT (1, port);
651f2cd2 2269 SCM_PTAB_ENTRY (port)->line_number = scm_to_long (line);
564478fd 2270 return SCM_UNSPECIFIED;
d043d8c2 2271}
1bbd0b84 2272#undef FUNC_NAME
d043d8c2 2273
a1ec6916 2274SCM_DEFINE (scm_port_column, "port-column", 1, 0, 0,
1bbd0b84 2275 (SCM port),
a150979d
KR
2276 "Return the current column number of @var{port}.\n"
2277 "If the number is\n"
b380b885
MD
2278 "unknown, the result is #f. Otherwise, the result is a 0-origin integer\n"
2279 "- i.e. the first character of the first line is line 0, column 0.\n"
2280 "(However, when you display a file position, for example in an error\n"
650a1cf9 2281 "message, we recommend you add 1 to get 1-origin integers. This is\n"
b380b885
MD
2282 "because lines and column numbers traditionally start with 1, and that is\n"
2283 "what non-programmers will find most natural.)")
1bbd0b84 2284#define FUNC_NAME s_scm_port_column
0f2d19dd 2285{
78446828 2286 port = SCM_COERCE_OUTPORT (port);
34d19ef6 2287 SCM_VALIDATE_OPENPORT (1, port);
e11e83f3 2288 return scm_from_int (SCM_COL (port));
0f2d19dd 2289}
1bbd0b84 2290#undef FUNC_NAME
0f2d19dd 2291
a1ec6916 2292SCM_DEFINE (scm_set_port_column_x, "set-port-column!", 2, 0, 0,
1bbd0b84 2293 (SCM port, SCM column),
a150979d
KR
2294 "Set the current column of @var{port}. Before reading the first\n"
2295 "character on a line the column should be 0.")
1bbd0b84 2296#define FUNC_NAME s_scm_set_port_column_x
d043d8c2 2297{
360fc44c 2298 port = SCM_COERCE_OUTPORT (port);
34d19ef6 2299 SCM_VALIDATE_OPENPORT (1, port);
a55c2b68 2300 SCM_PTAB_ENTRY (port)->column_number = scm_to_int (column);
564478fd 2301 return SCM_UNSPECIFIED;
d043d8c2 2302}
1bbd0b84 2303#undef FUNC_NAME
d043d8c2 2304
a1ec6916 2305SCM_DEFINE (scm_port_filename, "port-filename", 1, 0, 0,
1bbd0b84 2306 (SCM port),
ac012a27
AW
2307 "Return the filename associated with @var{port}, or @code{#f}\n"
2308 "if no filename is associated with the port.")
1bbd0b84 2309#define FUNC_NAME s_scm_port_filename
0f2d19dd 2310{
78446828 2311 port = SCM_COERCE_OUTPORT (port);
34d19ef6 2312 SCM_VALIDATE_OPENPORT (1, port);
b24b5e13 2313 return SCM_FILENAME (port);
0f2d19dd 2314}
1bbd0b84 2315#undef FUNC_NAME
0f2d19dd 2316
a1ec6916 2317SCM_DEFINE (scm_set_port_filename_x, "set-port-filename!", 2, 0, 0,
1bbd0b84 2318 (SCM port, SCM filename),
b380b885
MD
2319 "Change the filename associated with @var{port}, using the current input\n"
2320 "port if none is specified. Note that this does not change the port's\n"
2321 "source of data, but only the value that is returned by\n"
2322 "@code{port-filename} and reported in diagnostic output.")
1bbd0b84 2323#define FUNC_NAME s_scm_set_port_filename_x
d14af9f2 2324{
360fc44c 2325 port = SCM_COERCE_OUTPORT (port);
34d19ef6 2326 SCM_VALIDATE_OPENPORT (1, port);
360fc44c 2327 /* We allow the user to set the filename to whatever he likes. */
b24b5e13
DH
2328 SCM_SET_FILENAME (port, filename);
2329 return SCM_UNSPECIFIED;
d14af9f2 2330}
1bbd0b84 2331#undef FUNC_NAME
d14af9f2 2332
d6a6989e
LC
2333/* A fluid specifying the default encoding for newly created ports. If it is
2334 a string, that is the encoding. If it is #f, it is in the "native"
2335 (Latin-1) encoding. */
2336SCM_VARIABLE (default_port_encoding_var, "%default-port-encoding");
2337
889975e5
MG
2338static int scm_port_encoding_init = 0;
2339
9d9c66ba
LC
2340/* Use ENCODING as the default encoding for future ports. */
2341void
2342scm_i_set_default_port_encoding (const char *encoding)
2343{
2344 if (!scm_port_encoding_init
2345 || !scm_is_fluid (SCM_VARIABLE_REF (default_port_encoding_var)))
2346 scm_misc_error (NULL, "tried to set port encoding fluid before it is initialized",
2347 SCM_EOL);
2348
2349 if (encoding == NULL
96965a6e
MW
2350 || c_strcasecmp (encoding, "ASCII") == 0
2351 || c_strcasecmp (encoding, "ANSI_X3.4-1968") == 0
2352 || c_strcasecmp (encoding, "ISO-8859-1") == 0)
9d9c66ba
LC
2353 scm_fluid_set_x (SCM_VARIABLE_REF (default_port_encoding_var), SCM_BOOL_F);
2354 else
2355 scm_fluid_set_x (SCM_VARIABLE_REF (default_port_encoding_var),
2356 scm_from_locale_string (encoding));
2357}
2358
2359/* Return the name of the default encoding for newly created ports; a
2360 return value of NULL means "ISO-8859-1". */
889975e5 2361const char *
9d9c66ba 2362scm_i_default_port_encoding (void)
889975e5 2363{
9d9c66ba
LC
2364 if (!scm_port_encoding_init)
2365 return NULL;
2366 else if (!scm_is_fluid (SCM_VARIABLE_REF (default_port_encoding_var)))
2367 return NULL;
2368 else
889975e5 2369 {
9d9c66ba
LC
2370 SCM encoding;
2371
2372 encoding = scm_fluid_ref (SCM_VARIABLE_REF (default_port_encoding_var));
2373 if (!scm_is_string (encoding))
889975e5
MG
2374 return NULL;
2375 else
9d9c66ba 2376 return scm_i_string_chars (encoding);
889975e5
MG
2377 }
2378}
2379
cdd3d6c9
MW
2380/* If the next LEN bytes from PORT are equal to those in BYTES, then
2381 return 1, else return 0. Leave the port position unchanged. */
2382static int
2383looking_at_bytes (SCM port, const unsigned char *bytes, int len)
2384{
2385 scm_t_port *pt = SCM_PTAB_ENTRY (port);
cdd3d6c9
MW
2386 int i = 0;
2387
2388 while (i < len && scm_peek_byte_or_eof (port) == bytes[i])
2389 {
2390 pt->read_pos++;
2391 i++;
2392 }
7f6c3f8f
MW
2393 scm_i_unget_bytes (bytes, i, port);
2394 return (i == len);
cdd3d6c9
MW
2395}
2396
2397static const unsigned char scm_utf8_bom[3] = {0xEF, 0xBB, 0xBF};
2398static const unsigned char scm_utf16be_bom[2] = {0xFE, 0xFF};
2399static const unsigned char scm_utf16le_bom[2] = {0xFF, 0xFE};
2400static const unsigned char scm_utf32be_bom[4] = {0x00, 0x00, 0xFE, 0xFF};
2401static const unsigned char scm_utf32le_bom[4] = {0xFF, 0xFE, 0x00, 0x00};
2402
2403/* Decide what byte order to use for a UTF-16 port. Return "UTF-16BE"
2404 or "UTF-16LE". MODE must be either SCM_PORT_READ or SCM_PORT_WRITE,
2405 and specifies which operation is about to be done. The MODE
2406 determines how we will decide the byte order. We deliberately avoid
2407 reading from the port unless the user is about to do so. If the user
2408 is about to read, then we look for a BOM, and if present, we use it
2409 to determine the byte order. Otherwise we choose big endian, as
2410 recommended by the Unicode Standard. Note that the BOM (if any) is
2411 not consumed here. */
2412static const char *
2413decide_utf16_encoding (SCM port, scm_t_port_rw_active mode)
2414{
2415 if (mode == SCM_PORT_READ
2416 && SCM_PORT_GET_INTERNAL (port)->at_stream_start_for_bom_read
2417 && looking_at_bytes (port, scm_utf16le_bom, sizeof scm_utf16le_bom))
2418 return "UTF-16LE";
2419 else
2420 return "UTF-16BE";
2421}
2422
2423/* Decide what byte order to use for a UTF-32 port. Return "UTF-32BE"
2424 or "UTF-32LE". See the comment above 'decide_utf16_encoding' for
2425 details. */
2426static const char *
2427decide_utf32_encoding (SCM port, scm_t_port_rw_active mode)
2428{
2429 if (mode == SCM_PORT_READ
2430 && SCM_PORT_GET_INTERNAL (port)->at_stream_start_for_bom_read
2431 && looking_at_bytes (port, scm_utf32le_bom, sizeof scm_utf32le_bom))
2432 return "UTF-32LE";
2433 else
2434 return "UTF-32BE";
2435}
2436
337edc59 2437static void
1fa89aaf 2438finalize_iconv_descriptors (void *ptr, void *data)
337edc59
MW
2439{
2440 close_iconv_descriptors (ptr);
2441}
2442
2443static scm_t_iconv_descriptors *
2444open_iconv_descriptors (const char *encoding, int reading, int writing)
2445{
2446 scm_t_iconv_descriptors *id;
2447 iconv_t input_cd, output_cd;
2448
2449 input_cd = (iconv_t) -1;
2450 output_cd = (iconv_t) -1;
2451 if (reading)
2452 {
2453 /* Open an input iconv conversion descriptor, from ENCODING
2454 to UTF-8. We choose UTF-8, not UTF-32, because iconv
2455 implementations can typically convert from anything to
2456 UTF-8, but not to UTF-32 (see
2457 <http://lists.gnu.org/archive/html/bug-libunistring/2010-09/msg00007.html>). */
2458
2459 /* Assume opening an iconv descriptor causes about 16 KB of
2460 allocation. */
2461 scm_gc_register_allocation (16 * 1024);
2462
2463 input_cd = iconv_open ("UTF-8", encoding);
2464 if (input_cd == (iconv_t) -1)
2465 goto invalid_encoding;
2466 }
2467
2468 if (writing)
2469 {
2470 /* Assume opening an iconv descriptor causes about 16 KB of
2471 allocation. */
2472 scm_gc_register_allocation (16 * 1024);
2473
2474 output_cd = iconv_open (encoding, "UTF-8");
2475 if (output_cd == (iconv_t) -1)
2476 {
2477 if (input_cd != (iconv_t) -1)
2478 iconv_close (input_cd);
2479 goto invalid_encoding;
2480 }
2481 }
2482
2483 id = scm_gc_malloc_pointerless (sizeof (*id), "iconv descriptors");
2484 id->input_cd = input_cd;
2485 id->output_cd = output_cd;
2486
2487 /* Register a finalizer to close the descriptors. */
2488 scm_i_set_finalizer (id, finalize_iconv_descriptors, NULL);
2489
2490 return id;
2491
2492 invalid_encoding:
2493 {
2494 SCM err;
2495 err = scm_from_locale_string (encoding);
2496 scm_misc_error ("open_iconv_descriptors",
2497 "invalid or unknown character encoding ~s",
2498 scm_list_1 (err));
2499 }
2500}
2501
2502static void
2503close_iconv_descriptors (scm_t_iconv_descriptors *id)
2504{
2505 if (id->input_cd != (iconv_t) -1)
2506 iconv_close (id->input_cd);
2507 if (id->output_cd != (iconv_t) -1)
2508 iconv_close (id->output_cd);
2509 id->input_cd = (void *) -1;
2510 id->output_cd = (void *) -1;
2511}
2512
cdd3d6c9
MW
2513/* Return the iconv_descriptors, initializing them if necessary. MODE
2514 must be either SCM_PORT_READ or SCM_PORT_WRITE, and specifies which
2515 operation is about to be done. We deliberately avoid reading from
2516 the port unless the user was about to do so. */
337edc59 2517scm_t_iconv_descriptors *
cdd3d6c9 2518scm_i_port_iconv_descriptors (SCM port, scm_t_port_rw_active mode)
337edc59 2519{
cdd3d6c9 2520 scm_t_port_internal *pti = SCM_PORT_GET_INTERNAL (port);
337edc59
MW
2521
2522 assert (pti->encoding_mode == SCM_PORT_ENCODING_MODE_ICONV);
2523
2524 if (!pti->iconv_descriptors)
2525 {
cdd3d6c9
MW
2526 scm_t_port *pt = SCM_PTAB_ENTRY (port);
2527 const char *precise_encoding;
2528
337edc59
MW
2529 if (!pt->encoding)
2530 pt->encoding = "ISO-8859-1";
cdd3d6c9
MW
2531
2532 /* If the specified encoding is UTF-16 or UTF-32, then make
2533 that more precise by deciding what byte order to use. */
96965a6e 2534 if (c_strcasecmp (pt->encoding, "UTF-16") == 0)
cdd3d6c9 2535 precise_encoding = decide_utf16_encoding (port, mode);
96965a6e 2536 else if (c_strcasecmp (pt->encoding, "UTF-32") == 0)
cdd3d6c9
MW
2537 precise_encoding = decide_utf32_encoding (port, mode);
2538 else
2539 precise_encoding = pt->encoding;
2540
337edc59 2541 pti->iconv_descriptors =
cdd3d6c9 2542 open_iconv_descriptors (precise_encoding,
337edc59
MW
2543 SCM_INPUT_PORT_P (port),
2544 SCM_OUTPUT_PORT_P (port));
2545 }
2546
2547 return pti->iconv_descriptors;
2548}
2549
889975e5 2550void
064c27c4 2551scm_i_set_port_encoding_x (SCM port, const char *encoding)
889975e5 2552{
889975e5 2553 scm_t_port *pt;
e4598559 2554 scm_t_port_internal *pti;
337edc59 2555 scm_t_iconv_descriptors *prev;
f4bc4e59 2556
9d9c66ba
LC
2557 /* Set the character encoding for this port. */
2558 pt = SCM_PTAB_ENTRY (port);
e4598559 2559 pti = SCM_PORT_GET_INTERNAL (port);
337edc59 2560 prev = pti->iconv_descriptors;
f4bc4e59 2561
cdd3d6c9
MW
2562 /* In order to handle cases where the encoding changes mid-stream
2563 (e.g. within an HTTP stream, or within a file that is composed of
2564 segments with different encodings), we consider this to be "stream
2565 start" for purposes of BOM handling, regardless of our actual file
2566 position. */
2567 pti->at_stream_start_for_bom_read = 1;
2568 pti->at_stream_start_for_bom_write = 1;
2569
9d9c66ba
LC
2570 if (encoding == NULL)
2571 encoding = "ISO-8859-1";
f4bc4e59 2572
7b292a9d
LC
2573 /* If ENCODING is UTF-8, then no conversion descriptor is opened
2574 because we do I/O ourselves. This saves 100+ KiB for each
2575 descriptor. */
cdd3d6c9 2576 pt->encoding = scm_gc_strdup (encoding, "port");
96965a6e 2577 if (c_strcasecmp (encoding, "UTF-8") == 0)
cdd3d6c9 2578 pti->encoding_mode = SCM_PORT_ENCODING_MODE_UTF8;
337edc59 2579 else
cdd3d6c9 2580 pti->encoding_mode = SCM_PORT_ENCODING_MODE_ICONV;
f4bc4e59 2581
cdd3d6c9 2582 pti->iconv_descriptors = NULL;
337edc59
MW
2583 if (prev)
2584 close_iconv_descriptors (prev);
889975e5
MG
2585}
2586
2587SCM_DEFINE (scm_port_encoding, "port-encoding", 1, 0, 0,
2588 (SCM port),
2589 "Returns, as a string, the character encoding that @var{port}\n"
2590 "uses to interpret its input and output.\n")
2591#define FUNC_NAME s_scm_port_encoding
2592{
2593 scm_t_port *pt;
2594 const char *enc;
2595
2596 SCM_VALIDATE_PORT (1, port);
2597
2598 pt = SCM_PTAB_ENTRY (port);
9d9c66ba 2599 enc = pt->encoding;
889975e5
MG
2600 if (enc)
2601 return scm_from_locale_string (pt->encoding);
2602 else
0af34a3f 2603 return SCM_BOOL_F;
889975e5
MG
2604}
2605#undef FUNC_NAME
d6a6989e 2606
889975e5
MG
2607SCM_DEFINE (scm_set_port_encoding_x, "set-port-encoding!", 2, 0, 0,
2608 (SCM port, SCM enc),
2609 "Sets the character encoding that will be used to interpret all\n"
2610 "port I/O. New ports are created with the encoding\n"
2611 "appropriate for the current locale if @code{setlocale} has \n"
2612 "been called or ISO-8859-1 otherwise\n"
2613 "and this procedure can be used to modify that encoding.\n")
889975e5
MG
2614#define FUNC_NAME s_scm_set_port_encoding_x
2615{
2616 char *enc_str;
889975e5
MG
2617
2618 SCM_VALIDATE_PORT (1, port);
2619 SCM_VALIDATE_STRING (2, enc);
2620
2621 enc_str = scm_to_locale_string (enc);
da288f50 2622 scm_i_set_port_encoding_x (port, enc_str);
3e05fc04 2623 free (enc_str);
da288f50 2624
889975e5
MG
2625 return SCM_UNSPECIFIED;
2626}
2627#undef FUNC_NAME
2628
2629
b22e94db
LC
2630/* A fluid specifying the default conversion handler for newly created
2631 ports. Its value should be one of the symbols below. */
2632SCM_VARIABLE (default_conversion_strategy_var,
2633 "%default-port-conversion-strategy");
2634
2635/* Whether the above fluid is initialized. */
889975e5
MG
2636static int scm_conversion_strategy_init = 0;
2637
b22e94db
LC
2638/* The possible conversion strategies. */
2639SCM_SYMBOL (sym_error, "error");
2640SCM_SYMBOL (sym_substitute, "substitute");
2641SCM_SYMBOL (sym_escape, "escape");
2642
2643/* Return the default failed encoding conversion policy for new created
2644 ports. */
889975e5 2645scm_t_string_failed_conversion_handler
b22e94db 2646scm_i_default_port_conversion_handler (void)
889975e5 2647{
b22e94db
LC
2648 scm_t_string_failed_conversion_handler handler;
2649
2650 if (!scm_conversion_strategy_init
2651 || !scm_is_fluid (SCM_VARIABLE_REF (default_conversion_strategy_var)))
2652 handler = SCM_FAILED_CONVERSION_QUESTION_MARK;
889975e5
MG
2653 else
2654 {
b22e94db
LC
2655 SCM fluid, value;
2656
2657 fluid = SCM_VARIABLE_REF (default_conversion_strategy_var);
2658 value = scm_fluid_ref (fluid);
2659
2660 if (scm_is_eq (sym_substitute, value))
2661 handler = SCM_FAILED_CONVERSION_QUESTION_MARK;
2662 else if (scm_is_eq (sym_escape, value))
2663 handler = SCM_FAILED_CONVERSION_ESCAPE_SEQUENCE;
2664 else
2665 /* Default to 'error also when the fluid's value is not one of
2666 the valid symbols. */
2667 handler = SCM_FAILED_CONVERSION_ERROR;
889975e5 2668 }
b22e94db
LC
2669
2670 return handler;
889975e5
MG
2671}
2672
b22e94db 2673/* Use HANDLER as the default conversion strategy for future ports. */
889975e5 2674void
b22e94db
LC
2675scm_i_set_default_port_conversion_handler (scm_t_string_failed_conversion_handler
2676 handler)
889975e5
MG
2677{
2678 SCM strategy;
b22e94db
LC
2679
2680 if (!scm_conversion_strategy_init
2681 || !scm_is_fluid (SCM_VARIABLE_REF (default_conversion_strategy_var)))
2682 scm_misc_error (NULL, "tried to set conversion strategy fluid before it is initialized",
2683 SCM_EOL);
2684
2685 switch (handler)
889975e5 2686 {
b22e94db
LC
2687 case SCM_FAILED_CONVERSION_ERROR:
2688 strategy = sym_error;
2689 break;
2690
2691 case SCM_FAILED_CONVERSION_ESCAPE_SEQUENCE:
2692 strategy = sym_escape;
2693 break;
2694
2695 case SCM_FAILED_CONVERSION_QUESTION_MARK:
2696 strategy = sym_substitute;
2697 break;
2698
2699 default:
2700 abort ();
889975e5 2701 }
b22e94db
LC
2702
2703 scm_fluid_set_x (SCM_VARIABLE_REF (default_conversion_strategy_var),
2704 strategy);
889975e5
MG
2705}
2706
2707SCM_DEFINE (scm_port_conversion_strategy, "port-conversion-strategy",
2708 1, 0, 0, (SCM port),
2709 "Returns the behavior of the port when handling a character that\n"
2710 "is not representable in the port's current encoding.\n"
2711 "It returns the symbol @code{error} if unrepresentable characters\n"
2712 "should cause exceptions, @code{substitute} if the port should\n"
2713 "try to replace unrepresentable characters with question marks or\n"
2714 "approximate characters, or @code{escape} if unrepresentable\n"
2715 "characters should be converted to string escapes.\n"
2716 "\n"
2717 "If @var{port} is @code{#f}, then the current default behavior\n"
2718 "will be returned. New ports will have this default behavior\n"
2719 "when they are created.\n")
2720#define FUNC_NAME s_scm_port_conversion_strategy
2721{
2722 scm_t_string_failed_conversion_handler h;
2723
b22e94db
LC
2724 if (scm_is_false (port))
2725 h = scm_i_default_port_conversion_handler ();
2726 else
889975e5 2727 {
b22e94db
LC
2728 scm_t_port *pt;
2729
889975e5 2730 SCM_VALIDATE_OPPORT (1, port);
b22e94db
LC
2731 pt = SCM_PTAB_ENTRY (port);
2732
2733 h = pt->ilseq_handler;
889975e5
MG
2734 }
2735
889975e5 2736 if (h == SCM_FAILED_CONVERSION_ERROR)
4a655e50 2737 return scm_from_latin1_symbol ("error");
889975e5 2738 else if (h == SCM_FAILED_CONVERSION_QUESTION_MARK)
4a655e50 2739 return scm_from_latin1_symbol ("substitute");
889975e5 2740 else if (h == SCM_FAILED_CONVERSION_ESCAPE_SEQUENCE)
4a655e50 2741 return scm_from_latin1_symbol ("escape");
889975e5
MG
2742 else
2743 abort ();
2744
2745 /* Never gets here. */
2746 return SCM_UNDEFINED;
2747}
2748#undef FUNC_NAME
2749
2750SCM_DEFINE (scm_set_port_conversion_strategy_x, "set-port-conversion-strategy!",
2751 2, 0, 0,
2752 (SCM port, SCM sym),
2753 "Sets the behavior of the interpreter when outputting a character\n"
2754 "that is not representable in the port's current encoding.\n"
2755 "@var{sym} can be either @code{'error}, @code{'substitute}, or\n"
2756 "@code{'escape}. If it is @code{'error}, an error will be thrown\n"
2757 "when an unconvertible character is encountered. If it is\n"
2758 "@code{'substitute}, then unconvertible characters will \n"
2759 "be replaced with approximate characters, or with question marks\n"
2760 "if no approximately correct character is available.\n"
2761 "If it is @code{'escape},\n"
2762 "it will appear as a hex escape when output.\n"
2763 "\n"
2764 "If @var{port} is an open port, the conversion error behavior\n"
2765 "is set for that port. If it is @code{#f}, it is set as the\n"
2766 "default behavior for any future ports that get created in\n"
2767 "this thread.\n")
2768#define FUNC_NAME s_scm_set_port_conversion_strategy_x
2769{
b22e94db 2770 scm_t_string_failed_conversion_handler handler;
889975e5 2771
b22e94db
LC
2772 if (scm_is_eq (sym, sym_error))
2773 handler = SCM_FAILED_CONVERSION_ERROR;
2774 else if (scm_is_eq (sym, sym_substitute))
2775 handler = SCM_FAILED_CONVERSION_QUESTION_MARK;
2776 else if (scm_is_eq (sym, sym_escape))
2777 handler = SCM_FAILED_CONVERSION_ESCAPE_SEQUENCE;
2778 else
2779 SCM_MISC_ERROR ("unknown conversion strategy ~s", scm_list_1 (sym));
889975e5 2780
b22e94db
LC
2781 if (scm_is_false (port))
2782 scm_i_set_default_port_conversion_handler (handler);
2783 else
889975e5 2784 {
b22e94db
LC
2785 SCM_VALIDATE_OPPORT (1, port);
2786 SCM_PTAB_ENTRY (port)->ilseq_handler = handler;
889975e5
MG
2787 }
2788
889975e5
MG
2789 return SCM_UNSPECIFIED;
2790}
2791#undef FUNC_NAME
2792
2793
2794
f12733c9
MD
2795void
2796scm_print_port_mode (SCM exp, SCM port)
2797{
2798 scm_puts (SCM_CLOSEDP (exp)
2799 ? "closed: "
f9a64404
DH
2800 : (SCM_RDNG & SCM_CELL_WORD_0 (exp)
2801 ? (SCM_WRTNG & SCM_CELL_WORD_0 (exp)
f12733c9
MD
2802 ? "input-output: "
2803 : "input: ")
f9a64404 2804 : (SCM_WRTNG & SCM_CELL_WORD_0 (exp)
f12733c9
MD
2805 ? "output: "
2806 : "bogus: ")),
2807 port);
2808}
1cc91f1b 2809
f12733c9 2810int
e81d98ec 2811scm_port_print (SCM exp, SCM port, scm_print_state *pstate SCM_UNUSED)
0f2d19dd 2812{
f12733c9
MD
2813 char *type = SCM_PTOBNAME (SCM_PTOBNUM (exp));
2814 if (!type)
2815 type = "port";
b7f3516f 2816 scm_puts ("#<", port);
f12733c9 2817 scm_print_port_mode (exp, port);
b7f3516f
TT
2818 scm_puts (type, port);
2819 scm_putc (' ', port);
0345e278 2820 scm_uintprint (SCM_CELL_WORD_1 (exp), 16, port);
b7f3516f 2821 scm_putc ('>', port);
f12733c9 2822 return 1;
0f2d19dd
JB
2823}
2824
0f2d19dd 2825\f
ee149d03 2826
d68fee48 2827/* Void ports. */
0f2d19dd 2828
92c2555f 2829scm_t_bits scm_tc16_void_port = 0;
0f2d19dd 2830
e81d98ec 2831static int fill_input_void_port (SCM port SCM_UNUSED)
283a1a0e 2832{
70df8af6 2833 return EOF;
283a1a0e
GH
2834}
2835
31703ab8 2836static void
e81d98ec
DH
2837write_void_port (SCM port SCM_UNUSED,
2838 const void *data SCM_UNUSED,
2839 size_t size SCM_UNUSED)
31703ab8
GH
2840{
2841}
2842
d617ee18
MV
2843static SCM
2844scm_i_void_port (long mode_bits)
0f2d19dd 2845{
9de87eea 2846 scm_i_scm_pthread_mutex_lock (&scm_i_port_table_mutex);
402788a9 2847 {
da220f27
HWN
2848 SCM answer = scm_new_port_table_entry (scm_tc16_void_port);
2849 scm_t_port * pt = SCM_PTAB_ENTRY(answer);
2850
402788a9 2851 scm_port_non_buffer (pt);
402788a9
HWN
2852
2853 SCM_SETSTREAM (answer, 0);
2854 SCM_SET_CELL_TYPE (answer, scm_tc16_void_port | mode_bits);
9de87eea 2855 scm_i_pthread_mutex_unlock (&scm_i_port_table_mutex);
402788a9
HWN
2856 return answer;
2857 }
0f2d19dd
JB
2858}
2859
d617ee18
MV
2860SCM
2861scm_void_port (char *mode_str)
2862{
2863 return scm_i_void_port (scm_mode_bits (mode_str));
2864}
2865
a1ec6916 2866SCM_DEFINE (scm_sys_make_void_port, "%make-void-port", 1, 0, 0,
1bbd0b84 2867 (SCM mode),
70df8af6 2868 "Create and return a new void port. A void port acts like\n"
bb2c02f2 2869 "@file{/dev/null}. The @var{mode} argument\n"
70df8af6 2870 "specifies the input/output modes for this port: see the\n"
b380b885 2871 "documentation for @code{open-file} in @ref{File Ports}.")
1bbd0b84 2872#define FUNC_NAME s_scm_sys_make_void_port
0f2d19dd 2873{
d617ee18 2874 return scm_i_void_port (scm_i_mode_bits (mode));
0f2d19dd 2875}
1bbd0b84 2876#undef FUNC_NAME
0f2d19dd 2877
0f2d19dd 2878\f
89545eba 2879/* Initialization. */
1cc91f1b 2880
0f2d19dd
JB
2881void
2882scm_init_ports ()
0f2d19dd 2883{
840ae05d 2884 /* lseek() symbols. */
e11e83f3
MV
2885 scm_c_define ("SEEK_SET", scm_from_int (SEEK_SET));
2886 scm_c_define ("SEEK_CUR", scm_from_int (SEEK_CUR));
2887 scm_c_define ("SEEK_END", scm_from_int (SEEK_END));
840ae05d 2888
70df8af6
GH
2889 scm_tc16_void_port = scm_make_port_type ("void", fill_input_void_port,
2890 write_void_port);
9de87eea 2891
f39448c5
AW
2892 cur_inport_fluid = scm_make_fluid ();
2893 cur_outport_fluid = scm_make_fluid ();
2894 cur_errport_fluid = scm_make_fluid ();
2895 cur_loadport_fluid = scm_make_fluid ();
9de87eea 2896
f39448c5 2897 scm_i_port_weak_hash = scm_make_weak_key_hash_table (SCM_I_MAKINUM(31));
d6a6989e 2898
a0599745 2899#include "libguile/ports.x"
889975e5 2900
d6a6989e 2901 /* Use Latin-1 as the default port encoding. */
c81c2ad3
AW
2902 SCM_VARIABLE_SET (default_port_encoding_var,
2903 scm_make_fluid_with_default (SCM_BOOL_F));
889975e5 2904 scm_port_encoding_init = 1;
d6a6989e 2905
b22e94db
LC
2906 SCM_VARIABLE_SET (default_conversion_strategy_var,
2907 scm_make_fluid_with_default (sym_substitute));
889975e5 2908 scm_conversion_strategy_init = 1;
b22e94db 2909
9670f238
AW
2910 /* These bindings are used when boot-9 turns `current-input-port' et
2911 al into parameters. They are then removed from the guile module. */
2912 scm_c_define ("%current-input-port-fluid", cur_inport_fluid);
2913 scm_c_define ("%current-output-port-fluid", cur_outport_fluid);
2914 scm_c_define ("%current-error-port-fluid", cur_errport_fluid);
0f2d19dd 2915}
89e00824
ML
2916
2917/*
2918 Local Variables:
2919 c-file-style: "gnu"
2920 End:
2921*/