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