Simplify the interpreter for trivial inits and no letrec
[bpt/guile.git] / libguile / r6rs-ports.c
CommitLineData
c9d55a7e 1/* Copyright (C) 2009, 2010, 2011, 2013, 2014 Free Software Foundation, Inc.
1ee2c72e
LC
2 *
3 * This library is free software; you can redistribute it and/or
53befeb7
NJ
4 * modify it under the terms of the GNU Lesser General Public License
5 * as published by the Free Software Foundation; either version 3 of
6 * the License, or (at your option) any later version.
1ee2c72e 7 *
53befeb7
NJ
8 * This library is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
1ee2c72e
LC
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public
14 * License along with this library; if not, write to the Free Software
53befeb7
NJ
15 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
16 * 02110-1301 USA
1ee2c72e
LC
17 */
18
19#ifdef HAVE_CONFIG_H
20# include <config.h>
21#endif
22
bc8e6d7d 23#include <unistd.h>
1ee2c72e
LC
24#include <string.h>
25#include <stdio.h>
26#include <assert.h>
27
28#include "libguile/_scm.h"
29#include "libguile/bytevectors.h"
30#include "libguile/chars.h"
31#include "libguile/eval.h"
32#include "libguile/r6rs-ports.h"
33#include "libguile/strings.h"
34#include "libguile/validate.h"
35#include "libguile/values.h"
36#include "libguile/vectors.h"
8ca97482 37#include "libguile/ports-internal.h"
1ee2c72e
LC
38
39
40\f
41/* Unimplemented features. */
42
43
44/* Transoders are currently not implemented since Guile 1.8 is not
45 Unicode-capable. Thus, most of the code here assumes the use of the
46 binary transcoder. */
47static inline void
48transcoders_not_implemented (void)
49{
50 fprintf (stderr, "%s: warning: transcoders not implemented\n",
51 PACKAGE_NAME);
52}
53
54\f
55/* End-of-file object. */
56
57SCM_DEFINE (scm_eof_object, "eof-object", 0, 0, 0,
58 (void),
59 "Return the end-of-file object.")
60#define FUNC_NAME s_scm_eof_object
61{
62 return (SCM_EOF_VAL);
63}
64#undef FUNC_NAME
65
66\f
67/* Input ports. */
68
69#ifndef MIN
70# define MIN(a,b) ((a) < (b) ? (a) : (b))
71#endif
72
73/* Bytevector input ports or "bip" for short. */
74static scm_t_bits bytevector_input_port_type = 0;
75
76static inline SCM
77make_bip (SCM bv)
78{
79 SCM port;
80 char *c_bv;
81 unsigned c_len;
82 scm_t_port *c_port;
83 const unsigned long mode_bits = SCM_OPN | SCM_RDNG;
84
2721f918
AW
85 port = scm_c_make_port_with_encoding (bytevector_input_port_type,
86 mode_bits,
87 NULL, /* encoding */
88 SCM_FAILED_CONVERSION_ERROR,
89 SCM_UNPACK (bv));
a653d32a 90
96128014
LC
91 c_port = SCM_PTAB_ENTRY (port);
92
1ee2c72e
LC
93 /* Have the port directly access the bytevector. */
94 c_bv = (char *) SCM_BYTEVECTOR_CONTENTS (bv);
95 c_len = SCM_BYTEVECTOR_LENGTH (bv);
96
1ee2c72e
LC
97 c_port->read_pos = c_port->read_buf = (unsigned char *) c_bv;
98 c_port->read_end = (unsigned char *) c_bv + c_len;
99 c_port->read_buf_size = c_len;
100
1ee2c72e
LC
101 return port;
102}
103
1ee2c72e
LC
104static int
105bip_fill_input (SCM port)
106{
107 int result;
108 scm_t_port *c_port = SCM_PTAB_ENTRY (port);
109
110 if (c_port->read_pos >= c_port->read_end)
111 result = EOF;
112 else
113 result = (int) *c_port->read_pos;
114
115 return result;
116}
117
f1ce9199
LC
118static scm_t_off
119bip_seek (SCM port, scm_t_off offset, int whence)
1ee2c72e
LC
120#define FUNC_NAME "bip_seek"
121{
f1ce9199 122 scm_t_off c_result = 0;
1ee2c72e
LC
123 scm_t_port *c_port = SCM_PTAB_ENTRY (port);
124
125 switch (whence)
126 {
127 case SEEK_CUR:
128 offset += c_port->read_pos - c_port->read_buf;
129 /* Fall through. */
130
131 case SEEK_SET:
c89b4529 132 if (c_port->read_buf + offset <= c_port->read_end)
1ee2c72e
LC
133 {
134 c_port->read_pos = c_port->read_buf + offset;
135 c_result = offset;
136 }
137 else
138 scm_out_of_range (FUNC_NAME, scm_from_int (offset));
139 break;
140
141 case SEEK_END:
142 if (c_port->read_end - offset >= c_port->read_buf)
143 {
144 c_port->read_pos = c_port->read_end - offset;
145 c_result = c_port->read_pos - c_port->read_buf;
146 }
147 else
148 scm_out_of_range (FUNC_NAME, scm_from_int (offset));
149 break;
150
151 default:
152 scm_wrong_type_arg_msg (FUNC_NAME, 0, port,
153 "invalid `seek' parameter");
154 }
155
156 return c_result;
157}
158#undef FUNC_NAME
159
160
161/* Instantiate the bytevector input port type. */
162static inline void
163initialize_bytevector_input_ports (void)
164{
165 bytevector_input_port_type =
166 scm_make_port_type ("r6rs-bytevector-input-port", bip_fill_input,
167 NULL);
168
1ee2c72e
LC
169 scm_set_port_seek (bytevector_input_port_type, bip_seek);
170}
171
172
173SCM_DEFINE (scm_open_bytevector_input_port,
174 "open-bytevector-input-port", 1, 1, 0,
175 (SCM bv, SCM transcoder),
176 "Return an input port whose contents are drawn from "
177 "bytevector @var{bv}.")
178#define FUNC_NAME s_scm_open_bytevector_input_port
179{
180 SCM_VALIDATE_BYTEVECTOR (1, bv);
181 if (!SCM_UNBNDP (transcoder) && !scm_is_false (transcoder))
182 transcoders_not_implemented ();
183
184 return (make_bip (bv));
185}
186#undef FUNC_NAME
187
188\f
189/* Custom binary ports. The following routines are shared by input and
190 output custom binary ports. */
191
192#define SCM_CBP_GET_POSITION_PROC(_port) \
193 SCM_SIMPLE_VECTOR_REF (SCM_PACK (SCM_STREAM (_port)), 1)
194#define SCM_CBP_SET_POSITION_PROC(_port) \
195 SCM_SIMPLE_VECTOR_REF (SCM_PACK (SCM_STREAM (_port)), 2)
196#define SCM_CBP_CLOSE_PROC(_port) \
197 SCM_SIMPLE_VECTOR_REF (SCM_PACK (SCM_STREAM (_port)), 3)
198
f1ce9199
LC
199static scm_t_off
200cbp_seek (SCM port, scm_t_off offset, int whence)
1ee2c72e
LC
201#define FUNC_NAME "cbp_seek"
202{
203 SCM result;
f1ce9199 204 scm_t_off c_result = 0;
1ee2c72e
LC
205
206 switch (whence)
207 {
208 case SEEK_CUR:
209 {
210 SCM get_position_proc;
211
212 get_position_proc = SCM_CBP_GET_POSITION_PROC (port);
213 if (SCM_LIKELY (scm_is_true (get_position_proc)))
214 result = scm_call_0 (get_position_proc);
215 else
216 scm_wrong_type_arg_msg (FUNC_NAME, 0, port,
c9d55a7e
LC
217 "R6RS custom binary port with "
218 "`port-position' support");
219 c_result = scm_to_int (result);
220 if (offset == 0)
221 /* We just want to know the current position. */
222 break;
223
224 offset += c_result;
1ee2c72e
LC
225 /* Fall through. */
226 }
227
228 case SEEK_SET:
229 {
230 SCM set_position_proc;
231
232 set_position_proc = SCM_CBP_SET_POSITION_PROC (port);
233 if (SCM_LIKELY (scm_is_true (set_position_proc)))
234 result = scm_call_1 (set_position_proc, scm_from_int (offset));
235 else
236 scm_wrong_type_arg_msg (FUNC_NAME, 0, port,
c9d55a7e 237 "seekable R6RS custom binary port");
1ee2c72e
LC
238
239 /* Assuming setting the position succeeded. */
240 c_result = offset;
241 break;
242 }
243
244 default:
245 /* `SEEK_END' cannot be supported. */
246 scm_wrong_type_arg_msg (FUNC_NAME, 0, port,
247 "R6RS custom binary ports do not "
248 "support `SEEK_END'");
249 }
250
251 return c_result;
252}
253#undef FUNC_NAME
254
255static int
256cbp_close (SCM port)
257{
258 SCM close_proc;
259
260 close_proc = SCM_CBP_CLOSE_PROC (port);
261 if (scm_is_true (close_proc))
262 /* Invoke the `close' thunk. */
263 scm_call_0 (close_proc);
264
265 return 1;
266}
267
268\f
269/* Custom binary input port ("cbip" for short). */
270
271static scm_t_bits custom_binary_input_port_type = 0;
272
8ca97482
LC
273/* Initial size of the buffer embedded in custom binary input ports. */
274#define CBIP_BUFFER_SIZE 8192
1ee2c72e
LC
275
276/* Return the bytevector associated with PORT. */
277#define SCM_CBIP_BYTEVECTOR(_port) \
278 SCM_SIMPLE_VECTOR_REF (SCM_PACK (SCM_STREAM (_port)), 4)
279
8ca97482
LC
280/* Set BV as the bytevector associated with PORT. */
281#define SCM_SET_CBIP_BYTEVECTOR(_port, _bv) \
282 SCM_SIMPLE_VECTOR_SET (SCM_PACK (SCM_STREAM (_port)), 4, (_bv))
283
1ee2c72e
LC
284/* Return the various procedures of PORT. */
285#define SCM_CBIP_READ_PROC(_port) \
286 SCM_SIMPLE_VECTOR_REF (SCM_PACK (SCM_STREAM (_port)), 0)
287
288
8ca97482
LC
289/* Set PORT's internal buffer according to READ_SIZE. */
290static void
291cbip_setvbuf (SCM port, long read_size, long write_size)
292{
293 SCM bv;
294 scm_t_port *pt;
295
296 pt = SCM_PTAB_ENTRY (port);
297 bv = SCM_CBIP_BYTEVECTOR (port);
298
299 switch (read_size)
300 {
301 case 0:
302 /* Unbuffered: keep PORT's bytevector as is (it will be used in
303 future 'scm_c_read' calls), but point to the one-byte buffer. */
304 pt->read_buf = &pt->shortbuf;
305 pt->read_buf_size = 1;
306 break;
307
308 case -1:
309 /* Preferred size: keep the current bytevector and use it as the
310 backing store. */
311 pt->read_buf = (unsigned char *) SCM_BYTEVECTOR_CONTENTS (bv);
312 pt->read_buf_size = SCM_BYTEVECTOR_LENGTH (bv);
313 break;
314
315 default:
316 /* Fully buffered: allocate a buffer of READ_SIZE bytes. */
317 bv = scm_c_make_bytevector (read_size);
318 SCM_SET_CBIP_BYTEVECTOR (port, bv);
319 pt->read_buf = (unsigned char *) SCM_BYTEVECTOR_CONTENTS (bv);
320 pt->read_buf_size = read_size;
321 }
322
323 pt->read_pos = pt->read_end = pt->read_buf;
324}
325
1ee2c72e
LC
326static inline SCM
327make_cbip (SCM read_proc, SCM get_position_proc,
328 SCM set_position_proc, SCM close_proc)
329{
330 SCM port, bv, method_vector;
331 char *c_bv;
332 unsigned c_len;
333 scm_t_port *c_port;
334 const unsigned long mode_bits = SCM_OPN | SCM_RDNG;
335
336 /* Use a bytevector as the underlying buffer. */
337 c_len = CBIP_BUFFER_SIZE;
338 bv = scm_c_make_bytevector (c_len);
339 c_bv = (char *) SCM_BYTEVECTOR_CONTENTS (bv);
340
341 /* Store the various methods and bytevector in a vector. */
342 method_vector = scm_c_make_vector (5, SCM_BOOL_F);
343 SCM_SIMPLE_VECTOR_SET (method_vector, 4, bv);
344 SCM_SIMPLE_VECTOR_SET (method_vector, 0, read_proc);
345 SCM_SIMPLE_VECTOR_SET (method_vector, 1, get_position_proc);
346 SCM_SIMPLE_VECTOR_SET (method_vector, 2, set_position_proc);
347 SCM_SIMPLE_VECTOR_SET (method_vector, 3, close_proc);
348
2721f918
AW
349 port = scm_c_make_port_with_encoding (custom_binary_input_port_type,
350 mode_bits,
351 NULL, /* encoding */
352 SCM_FAILED_CONVERSION_ERROR,
353 SCM_UNPACK (method_vector));
a653d32a 354
96128014
LC
355 c_port = SCM_PTAB_ENTRY (port);
356
1ee2c72e 357 /* Have the port directly access the buffer (bytevector). */
1ee2c72e
LC
358 c_port->read_pos = c_port->read_buf = (unsigned char *) c_bv;
359 c_port->read_end = (unsigned char *) c_bv;
360 c_port->read_buf_size = c_len;
361
1ee2c72e
LC
362 return port;
363}
364
365static int
366cbip_fill_input (SCM port)
367#define FUNC_NAME "cbip_fill_input"
368{
369 int result;
370 scm_t_port *c_port = SCM_PTAB_ENTRY (port);
371
1ee2c72e
LC
372 if (c_port->read_pos >= c_port->read_end)
373 {
374 /* Invoke the user's `read!' procedure. */
8ca97482 375 int buffered;
6df03222 376 size_t c_octets, c_requested;
1ee2c72e
LC
377 SCM bv, read_proc, octets;
378
6df03222 379 c_requested = c_port->read_buf_size;
8ca97482 380 read_proc = SCM_CBIP_READ_PROC (port);
6df03222 381
1ee2c72e 382 bv = SCM_CBIP_BYTEVECTOR (port);
8ca97482
LC
383 buffered =
384 (c_port->read_buf == (unsigned char *) SCM_BYTEVECTOR_CONTENTS (bv));
1ee2c72e 385
8ca97482 386 if (buffered)
45a28515
LC
387 {
388 /* Make sure the buffer isn't corrupt. BV can be passed directly
389 to READ_PROC. */
390 assert (c_port->read_buf_size == SCM_BYTEVECTOR_LENGTH (bv));
391 c_port->read_pos = (unsigned char *) SCM_BYTEVECTOR_CONTENTS (bv);
392 }
8ca97482
LC
393 else
394 {
395 /* This is an unbuffered port. When called via the
396 'get-bytevector-*' procedures, and thus via 'scm_c_read', we
397 are passed the caller-provided buffer, so we need to check its
398 size. */
399 if (SCM_BYTEVECTOR_LENGTH (bv) < c_requested)
400 {
401 /* Bad luck: we have to make another allocation. Save that
402 bytevector for later reuse, in the hope that the application
403 has regular access patterns. */
404 bv = scm_c_make_bytevector (c_requested);
405 SCM_SET_CBIP_BYTEVECTOR (port, bv);
406 }
407 }
1ee2c72e
LC
408
409 octets = scm_call_3 (read_proc, bv, SCM_INUM0,
6df03222
LC
410 scm_from_size_t (c_requested));
411 c_octets = scm_to_size_t (octets);
412 if (SCM_UNLIKELY (c_octets > c_requested))
413 scm_out_of_range (FUNC_NAME, octets);
1ee2c72e 414
8ca97482
LC
415 if (!buffered)
416 /* Copy the data back to the internal buffer. */
417 memcpy ((char *) c_port->read_pos, SCM_BYTEVECTOR_CONTENTS (bv),
418 c_octets);
419
1ee2c72e
LC
420 c_port->read_end = (unsigned char *) c_port->read_pos + c_octets;
421
8ca97482
LC
422 if (c_octets != 0 || c_requested == 0)
423 result = (int) *c_port->read_pos;
1ee2c72e
LC
424 else
425 result = EOF;
426 }
427 else
428 result = (int) *c_port->read_pos;
429
430 return result;
431}
432#undef FUNC_NAME
433
434
435SCM_DEFINE (scm_make_custom_binary_input_port,
436 "make-custom-binary-input-port", 5, 0, 0,
437 (SCM id, SCM read_proc, SCM get_position_proc,
438 SCM set_position_proc, SCM close_proc),
439 "Return a new custom binary input port whose input is drained "
440 "by invoking @var{read_proc} and passing it a bytevector, an "
441 "index where octets should be written, and an octet count.")
442#define FUNC_NAME s_scm_make_custom_binary_input_port
443{
444 SCM_VALIDATE_STRING (1, id);
445 SCM_VALIDATE_PROC (2, read_proc);
446
447 if (!scm_is_false (get_position_proc))
448 SCM_VALIDATE_PROC (3, get_position_proc);
449
450 if (!scm_is_false (set_position_proc))
451 SCM_VALIDATE_PROC (4, set_position_proc);
452
453 if (!scm_is_false (close_proc))
454 SCM_VALIDATE_PROC (5, close_proc);
455
456 return (make_cbip (read_proc, get_position_proc, set_position_proc,
457 close_proc));
458}
459#undef FUNC_NAME
460
461
462/* Instantiate the custom binary input port type. */
463static inline void
464initialize_custom_binary_input_ports (void)
465{
466 custom_binary_input_port_type =
467 scm_make_port_type ("r6rs-custom-binary-input-port",
468 cbip_fill_input, NULL);
469
1ee2c72e
LC
470 scm_set_port_seek (custom_binary_input_port_type, cbp_seek);
471 scm_set_port_close (custom_binary_input_port_type, cbp_close);
e4eb0e39 472 scm_set_port_setvbuf (custom_binary_input_port_type, cbip_setvbuf);
1ee2c72e
LC
473}
474
475
476\f
477/* Binary input. */
478
479/* We currently don't support specific binary input ports. */
480#define SCM_VALIDATE_BINARY_INPUT_PORT SCM_VALIDATE_OPINPORT
481
482SCM_DEFINE (scm_get_u8, "get-u8", 1, 0, 0,
483 (SCM port),
484 "Read an octet from @var{port}, a binary input port, "
485 "blocking as necessary.")
486#define FUNC_NAME s_scm_get_u8
487{
488 SCM result;
489 int c_result;
490
491 SCM_VALIDATE_BINARY_INPUT_PORT (1, port);
492
8aa47f26 493 c_result = scm_get_byte_or_eof (port);
1ee2c72e
LC
494 if (c_result == EOF)
495 result = SCM_EOF_VAL;
496 else
497 result = SCM_I_MAKINUM ((unsigned char) c_result);
498
499 return result;
500}
501#undef FUNC_NAME
502
503SCM_DEFINE (scm_lookahead_u8, "lookahead-u8", 1, 0, 0,
504 (SCM port),
505 "Like @code{get-u8} but does not update @var{port} to "
506 "point past the octet.")
507#define FUNC_NAME s_scm_lookahead_u8
508{
8aa47f26 509 int u8;
1ee2c72e
LC
510 SCM result;
511
512 SCM_VALIDATE_BINARY_INPUT_PORT (1, port);
513
452c5ad9 514 u8 = scm_peek_byte_or_eof (port);
8aa47f26 515 if (u8 == EOF)
1ee2c72e 516 result = SCM_EOF_VAL;
8aa47f26 517 else
452c5ad9 518 result = SCM_I_MAKINUM ((scm_t_uint8) u8);
1ee2c72e
LC
519
520 return result;
521}
522#undef FUNC_NAME
523
524SCM_DEFINE (scm_get_bytevector_n, "get-bytevector-n", 2, 0, 0,
525 (SCM port, SCM count),
526 "Read @var{count} octets from @var{port}, blocking as "
527 "necessary and return a bytevector containing the octets "
528 "read. If fewer bytes are available, a bytevector smaller "
529 "than @var{count} is returned.")
530#define FUNC_NAME s_scm_get_bytevector_n
531{
532 SCM result;
533 char *c_bv;
534 unsigned c_count;
535 size_t c_read;
536
537 SCM_VALIDATE_BINARY_INPUT_PORT (1, port);
538 c_count = scm_to_uint (count);
539
540 result = scm_c_make_bytevector (c_count);
541 c_bv = (char *) SCM_BYTEVECTOR_CONTENTS (result);
542
543 if (SCM_LIKELY (c_count > 0))
544 /* XXX: `scm_c_read ()' does not update the port position. */
be632904 545 c_read = scm_c_read_unlocked (port, c_bv, c_count);
1ee2c72e
LC
546 else
547 /* Don't invoke `scm_c_read ()' since it may block. */
548 c_read = 0;
549
47f2bce5 550 if (c_read < c_count)
1ee2c72e 551 {
47f2bce5
MW
552 if (c_read == 0)
553 result = SCM_EOF_VAL;
1ee2c72e 554 else
1ee2c72e
LC
555 result = scm_c_shrink_bytevector (result, c_read);
556 }
557
558 return result;
559}
560#undef FUNC_NAME
561
562SCM_DEFINE (scm_get_bytevector_n_x, "get-bytevector-n!", 4, 0, 0,
563 (SCM port, SCM bv, SCM start, SCM count),
564 "Read @var{count} bytes from @var{port} and store them "
565 "in @var{bv} starting at index @var{start}. Return either "
566 "the number of bytes actually read or the end-of-file "
567 "object.")
568#define FUNC_NAME s_scm_get_bytevector_n_x
569{
570 SCM result;
571 char *c_bv;
572 unsigned c_start, c_count, c_len;
573 size_t c_read;
574
575 SCM_VALIDATE_BINARY_INPUT_PORT (1, port);
576 SCM_VALIDATE_BYTEVECTOR (2, bv);
577 c_start = scm_to_uint (start);
578 c_count = scm_to_uint (count);
579
580 c_bv = (char *) SCM_BYTEVECTOR_CONTENTS (bv);
581 c_len = SCM_BYTEVECTOR_LENGTH (bv);
582
583 if (SCM_UNLIKELY (c_start + c_count > c_len))
584 scm_out_of_range (FUNC_NAME, count);
585
586 if (SCM_LIKELY (c_count > 0))
be632904 587 c_read = scm_c_read_unlocked (port, c_bv + c_start, c_count);
1ee2c72e
LC
588 else
589 /* Don't invoke `scm_c_read ()' since it may block. */
590 c_read = 0;
591
47f2bce5
MW
592 if (c_read == 0 && c_count > 0)
593 result = SCM_EOF_VAL;
1ee2c72e
LC
594 else
595 result = scm_from_size_t (c_read);
596
597 return result;
598}
599#undef FUNC_NAME
600
601
602SCM_DEFINE (scm_get_bytevector_some, "get-bytevector-some", 1, 0, 0,
603 (SCM port),
21bbe22a
MW
604 "Read from @var{port}, blocking as necessary, until bytes "
605 "are available or an end-of-file is reached. Return either "
606 "the end-of-file object or a new bytevector containing some "
607 "of the available bytes (at least one), and update the port "
608 "position to point just past these bytes.")
1ee2c72e
LC
609#define FUNC_NAME s_scm_get_bytevector_some
610{
21bbe22a
MW
611 scm_t_port *pt;
612 size_t size;
613 SCM bv;
1ee2c72e
LC
614
615 SCM_VALIDATE_BINARY_INPUT_PORT (1, port);
21bbe22a 616 pt = SCM_PTAB_ENTRY (port);
1ee2c72e 617
21bbe22a 618 if (pt->rw_active == SCM_PORT_WRITE)
f6f4feb0 619 scm_flush_unlocked (port);
1ee2c72e 620
21bbe22a
MW
621 if (pt->rw_random)
622 pt->rw_active = SCM_PORT_READ;
1ee2c72e 623
21bbe22a 624 if (pt->read_pos >= pt->read_end)
1ee2c72e 625 {
f6f4feb0 626 if (scm_fill_input_unlocked (port) == EOF)
21bbe22a 627 return SCM_EOF_VAL;
1ee2c72e 628 }
1ee2c72e 629
21bbe22a
MW
630 size = pt->read_end - pt->read_pos;
631 if (pt->read_buf == pt->putback_buf)
632 size += pt->saved_read_end - pt->saved_read_pos;
1ee2c72e 633
21bbe22a
MW
634 bv = scm_c_make_bytevector (size);
635 scm_take_from_input_buffers
636 (port, (char *) SCM_BYTEVECTOR_CONTENTS (bv), size);
637
638 return bv;
1ee2c72e
LC
639}
640#undef FUNC_NAME
641
642SCM_DEFINE (scm_get_bytevector_all, "get-bytevector-all", 1, 0, 0,
643 (SCM port),
644 "Read from @var{port}, blocking as necessary, until "
645 "the end-of-file is reached. Return either "
646 "a new bytevector containing the data read or the "
647 "end-of-file object (if no data were available).")
648#define FUNC_NAME s_scm_get_bytevector_all
649{
650 SCM result;
651 char *c_bv;
652 unsigned c_len, c_count;
653 size_t c_read, c_total;
654
655 SCM_VALIDATE_BINARY_INPUT_PORT (1, port);
656
657 c_len = c_count = 4096;
05762e72 658 c_bv = (char *) scm_gc_malloc_pointerless (c_len, SCM_GC_BYTEVECTOR);
1ee2c72e
LC
659 c_total = c_read = 0;
660
661 do
662 {
663 if (c_total + c_read > c_len)
664 {
665 /* Grow the bytevector. */
666 c_bv = (char *) scm_gc_realloc (c_bv, c_len, c_len * 2,
667 SCM_GC_BYTEVECTOR);
668 c_count = c_len;
669 c_len *= 2;
670 }
671
672 /* `scm_c_read ()' blocks until C_COUNT bytes are available or EOF is
673 reached. */
be632904 674 c_read = scm_c_read_unlocked (port, c_bv + c_total, c_count);
1ee2c72e
LC
675 c_total += c_read, c_count -= c_read;
676 }
47f2bce5 677 while (c_count == 0);
1ee2c72e
LC
678
679 if (c_total == 0)
680 {
681 result = SCM_EOF_VAL;
682 scm_gc_free (c_bv, c_len, SCM_GC_BYTEVECTOR);
683 }
684 else
685 {
686 if (c_len > c_total)
687 {
688 /* Shrink the bytevector. */
689 c_bv = (char *) scm_gc_realloc (c_bv, c_len, c_total,
690 SCM_GC_BYTEVECTOR);
691 c_len = (unsigned) c_total;
692 }
693
8b66aa8f
AW
694 result = scm_c_take_gc_bytevector ((signed char *) c_bv, c_len,
695 SCM_BOOL_F);
1ee2c72e
LC
696 }
697
698 return result;
699}
700#undef FUNC_NAME
701
702
703\f
704/* Binary output. */
705
706/* We currently don't support specific binary input ports. */
707#define SCM_VALIDATE_BINARY_OUTPUT_PORT SCM_VALIDATE_OPOUTPORT
708
709
710SCM_DEFINE (scm_put_u8, "put-u8", 2, 0, 0,
711 (SCM port, SCM octet),
712 "Write @var{octet} to binary port @var{port}.")
713#define FUNC_NAME s_scm_put_u8
714{
715 scm_t_uint8 c_octet;
716
717 SCM_VALIDATE_BINARY_OUTPUT_PORT (1, port);
718 c_octet = scm_to_uint8 (octet);
719
0607ebbf 720 scm_putc_unlocked ((char) c_octet, port);
1ee2c72e
LC
721
722 return SCM_UNSPECIFIED;
723}
724#undef FUNC_NAME
725
726SCM_DEFINE (scm_put_bytevector, "put-bytevector", 2, 2, 0,
727 (SCM port, SCM bv, SCM start, SCM count),
728 "Write the contents of @var{bv} to @var{port}, optionally "
729 "starting at index @var{start} and limiting to @var{count} "
730 "octets.")
731#define FUNC_NAME s_scm_put_bytevector
732{
733 char *c_bv;
734 unsigned c_start, c_count, c_len;
735
736 SCM_VALIDATE_BINARY_OUTPUT_PORT (1, port);
737 SCM_VALIDATE_BYTEVECTOR (2, bv);
738
739 c_len = SCM_BYTEVECTOR_LENGTH (bv);
740 c_bv = (char *) SCM_BYTEVECTOR_CONTENTS (bv);
741
d223c3fc 742 if (!scm_is_eq (start, SCM_UNDEFINED))
1ee2c72e
LC
743 {
744 c_start = scm_to_uint (start);
745
d223c3fc 746 if (!scm_is_eq (count, SCM_UNDEFINED))
1ee2c72e
LC
747 {
748 c_count = scm_to_uint (count);
749 if (SCM_UNLIKELY (c_start + c_count > c_len))
750 scm_out_of_range (FUNC_NAME, count);
751 }
752 else
753 {
754 if (SCM_UNLIKELY (c_start >= c_len))
755 scm_out_of_range (FUNC_NAME, start);
756 else
757 c_count = c_len - c_start;
758 }
759 }
760 else
761 c_start = 0, c_count = c_len;
762
f209aeee 763 scm_c_write_unlocked (port, c_bv + c_start, c_count);
1ee2c72e
LC
764
765 return SCM_UNSPECIFIED;
766}
767#undef FUNC_NAME
768
7f6c3f8f
MW
769SCM_DEFINE (scm_unget_bytevector, "unget-bytevector", 2, 2, 0,
770 (SCM port, SCM bv, SCM start, SCM count),
771 "Unget the contents of @var{bv} to @var{port}, optionally "
772 "starting at index @var{start} and limiting to @var{count} "
773 "octets.")
774#define FUNC_NAME s_scm_unget_bytevector
775{
776 unsigned char *c_bv;
777 size_t c_start, c_count, c_len;
778
779 SCM_VALIDATE_BINARY_INPUT_PORT (1, port);
780 SCM_VALIDATE_BYTEVECTOR (2, bv);
781
782 c_len = SCM_BYTEVECTOR_LENGTH (bv);
783 c_bv = (unsigned char *) SCM_BYTEVECTOR_CONTENTS (bv);
784
785 if (!scm_is_eq (start, SCM_UNDEFINED))
786 {
787 c_start = scm_to_size_t (start);
788
789 if (!scm_is_eq (count, SCM_UNDEFINED))
790 {
791 c_count = scm_to_size_t (count);
792 if (SCM_UNLIKELY (c_start + c_count > c_len))
793 scm_out_of_range (FUNC_NAME, count);
794 }
795 else
796 {
797 if (SCM_UNLIKELY (c_start >= c_len))
798 scm_out_of_range (FUNC_NAME, start);
799 else
800 c_count = c_len - c_start;
801 }
802 }
803 else
804 c_start = 0, c_count = c_len;
805
806 scm_unget_bytes (c_bv + c_start, c_count, port);
807
808 return SCM_UNSPECIFIED;
809}
810#undef FUNC_NAME
811
1ee2c72e
LC
812
813\f
814/* Bytevector output port ("bop" for short). */
815
816/* Implementation of "bops".
817
818 Each bop has an internal buffer, of type `scm_t_bop_buffer', attached to
819 it. The procedure returned along with the output port is actually an
820 applicable SMOB. The SMOB holds a reference to the port. When applied,
821 the SMOB swallows the port's internal buffer, turning it into a
822 bytevector, and resets it.
823
824 XXX: Access to a bop's internal buffer is not thread-safe. */
825
826static scm_t_bits bytevector_output_port_type = 0;
827
828SCM_SMOB (bytevector_output_port_procedure,
829 "r6rs-bytevector-output-port-procedure",
830 0);
831
832#define SCM_GC_BOP "r6rs-bytevector-output-port"
833#define SCM_BOP_BUFFER_INITIAL_SIZE 4096
834
835/* Representation of a bop's internal buffer. */
836typedef struct
837{
838 size_t total_len;
839 size_t len;
840 size_t pos;
841 char *buffer;
842} scm_t_bop_buffer;
843
844
845/* Accessing a bop's buffer. */
846#define SCM_BOP_BUFFER(_port) \
847 ((scm_t_bop_buffer *) SCM_STREAM (_port))
848#define SCM_SET_BOP_BUFFER(_port, _buf) \
849 (SCM_SETSTREAM ((_port), (scm_t_bits) (_buf)))
850
851
852static inline void
853bop_buffer_init (scm_t_bop_buffer *buf)
854{
855 buf->total_len = buf->len = buf->pos = 0;
856 buf->buffer = NULL;
857}
858
859static inline void
860bop_buffer_grow (scm_t_bop_buffer *buf, size_t min_size)
861{
862 char *new_buf;
863 size_t new_size;
864
865 for (new_size = buf->total_len
866 ? buf->total_len : SCM_BOP_BUFFER_INITIAL_SIZE;
867 new_size < min_size;
868 new_size *= 2);
869
870 if (buf->buffer)
871 new_buf = scm_gc_realloc ((void *) buf->buffer, buf->total_len,
872 new_size, SCM_GC_BOP);
873 else
05762e72 874 new_buf = scm_gc_malloc_pointerless (new_size, SCM_GC_BOP);
1ee2c72e
LC
875
876 buf->buffer = new_buf;
877 buf->total_len = new_size;
878}
879
880static inline SCM
881make_bop (void)
882{
883 SCM port, bop_proc;
884 scm_t_port *c_port;
885 scm_t_bop_buffer *buf;
886 const unsigned long mode_bits = SCM_OPN | SCM_WRTNG;
887
1ee2c72e
LC
888 buf = (scm_t_bop_buffer *) scm_gc_malloc (sizeof (* buf), SCM_GC_BOP);
889 bop_buffer_init (buf);
890
2721f918
AW
891 port = scm_c_make_port_with_encoding (bytevector_output_port_type,
892 mode_bits,
893 NULL, /* encoding */
894 SCM_FAILED_CONVERSION_ERROR,
895 (scm_t_bits)buf);
1ee2c72e 896
2721f918 897 c_port = SCM_PTAB_ENTRY (port);
1ee2c72e 898
2721f918
AW
899 c_port->write_buf = c_port->write_pos = c_port->write_end = NULL;
900 c_port->write_buf_size = 0;
a653d32a 901
1ee2c72e 902 /* Make the bop procedure. */
a653d32a 903 SCM_NEWSMOB (bop_proc, bytevector_output_port_procedure, buf);
1ee2c72e
LC
904
905 return (scm_values (scm_list_2 (port, bop_proc)));
906}
907
1ee2c72e
LC
908/* Write SIZE octets from DATA to PORT. */
909static void
910bop_write (SCM port, const void *data, size_t size)
911{
912 scm_t_bop_buffer *buf;
913
914 buf = SCM_BOP_BUFFER (port);
915
916 if (buf->pos + size > buf->total_len)
917 bop_buffer_grow (buf, buf->pos + size);
918
919 memcpy (buf->buffer + buf->pos, data, size);
920 buf->pos += size;
921 buf->len = (buf->len > buf->pos) ? buf->len : buf->pos;
922}
923
f1ce9199
LC
924static scm_t_off
925bop_seek (SCM port, scm_t_off offset, int whence)
1ee2c72e
LC
926#define FUNC_NAME "bop_seek"
927{
928 scm_t_bop_buffer *buf;
929
930 buf = SCM_BOP_BUFFER (port);
931 switch (whence)
932 {
933 case SEEK_CUR:
f1ce9199 934 offset += (scm_t_off) buf->pos;
1ee2c72e
LC
935 /* Fall through. */
936
937 case SEEK_SET:
938 if (offset < 0 || (unsigned) offset > buf->len)
939 scm_out_of_range (FUNC_NAME, scm_from_int (offset));
940 else
941 buf->pos = offset;
942 break;
943
944 case SEEK_END:
945 if (offset < 0 || (unsigned) offset >= buf->len)
946 scm_out_of_range (FUNC_NAME, scm_from_int (offset));
947 else
948 buf->pos = buf->len - (offset + 1);
949 break;
950
951 default:
952 scm_wrong_type_arg_msg (FUNC_NAME, 0, port,
953 "invalid `seek' parameter");
954 }
955
956 return buf->pos;
957}
958#undef FUNC_NAME
959
960/* Fetch data from a bop. */
961SCM_SMOB_APPLY (bytevector_output_port_procedure,
962 bop_proc_apply, 0, 0, 0, (SCM bop_proc))
963{
a653d32a 964 SCM bv;
1ee2c72e
LC
965 scm_t_bop_buffer *buf, result_buf;
966
a653d32a 967 buf = (scm_t_bop_buffer *) SCM_SMOB_DATA (bop_proc);
1ee2c72e
LC
968
969 result_buf = *buf;
970 bop_buffer_init (buf);
971
972 if (result_buf.len == 0)
8b66aa8f 973 bv = scm_c_take_gc_bytevector (NULL, 0, SCM_BOOL_F);
1ee2c72e
LC
974 else
975 {
976 if (result_buf.total_len > result_buf.len)
977 /* Shrink the buffer. */
978 result_buf.buffer = scm_gc_realloc ((void *) result_buf.buffer,
979 result_buf.total_len,
980 result_buf.len,
981 SCM_GC_BOP);
982
fb031aba 983 bv = scm_c_take_gc_bytevector ((signed char *) result_buf.buffer,
8b66aa8f 984 result_buf.len, SCM_BOOL_F);
1ee2c72e
LC
985 }
986
987 return bv;
988}
989
1ee2c72e
LC
990SCM_DEFINE (scm_open_bytevector_output_port,
991 "open-bytevector-output-port", 0, 1, 0,
992 (SCM transcoder),
993 "Return two values: an output port and a procedure. The latter "
994 "should be called with zero arguments to obtain a bytevector "
995 "containing the data accumulated by the port.")
996#define FUNC_NAME s_scm_open_bytevector_output_port
997{
998 if (!SCM_UNBNDP (transcoder) && !scm_is_false (transcoder))
999 transcoders_not_implemented ();
1000
1001 return (make_bop ());
1002}
1003#undef FUNC_NAME
1004
1005static inline void
1006initialize_bytevector_output_ports (void)
1007{
1008 bytevector_output_port_type =
1009 scm_make_port_type ("r6rs-bytevector-output-port",
1010 NULL, bop_write);
1011
1012 scm_set_port_seek (bytevector_output_port_type, bop_seek);
1ee2c72e
LC
1013}
1014
1015\f
1016/* Custom binary output port ("cbop" for short). */
1017
1018static scm_t_bits custom_binary_output_port_type;
1019
1020/* Return the various procedures of PORT. */
1021#define SCM_CBOP_WRITE_PROC(_port) \
1022 SCM_SIMPLE_VECTOR_REF (SCM_PACK (SCM_STREAM (_port)), 0)
1023
1024
1025static inline SCM
1026make_cbop (SCM write_proc, SCM get_position_proc,
1027 SCM set_position_proc, SCM close_proc)
1028{
1029 SCM port, method_vector;
1030 scm_t_port *c_port;
1031 const unsigned long mode_bits = SCM_OPN | SCM_WRTNG;
1032
1033 /* Store the various methods and bytevector in a vector. */
1034 method_vector = scm_c_make_vector (4, SCM_BOOL_F);
1035 SCM_SIMPLE_VECTOR_SET (method_vector, 0, write_proc);
1036 SCM_SIMPLE_VECTOR_SET (method_vector, 1, get_position_proc);
1037 SCM_SIMPLE_VECTOR_SET (method_vector, 2, set_position_proc);
1038 SCM_SIMPLE_VECTOR_SET (method_vector, 3, close_proc);
1039
2721f918
AW
1040 port = scm_c_make_port_with_encoding (custom_binary_output_port_type,
1041 mode_bits,
1042 NULL, /* encoding */
1043 SCM_FAILED_CONVERSION_ERROR,
1044 SCM_UNPACK (method_vector));
a653d32a 1045
96128014
LC
1046 c_port = SCM_PTAB_ENTRY (port);
1047
1ee2c72e 1048 /* Have the port directly access the buffer (bytevector). */
1ee2c72e
LC
1049 c_port->write_buf = c_port->write_pos = c_port->write_end = NULL;
1050 c_port->write_buf_size = c_port->read_buf_size = 0;
1051
1ee2c72e
LC
1052 return port;
1053}
1054
1055/* Write SIZE octets from DATA to PORT. */
1056static void
1057cbop_write (SCM port, const void *data, size_t size)
1058#define FUNC_NAME "cbop_write"
1059{
1060 long int c_result;
1061 size_t c_written;
1062 SCM bv, write_proc, result;
1063
1064 /* XXX: Allocating a new bytevector at each `write' call is inefficient,
1065 but necessary since (1) we don't control the lifetime of the buffer
1066 pointed to by DATA, and (2) the `write!' procedure could capture the
1067 bytevector it is passed. */
1068 bv = scm_c_make_bytevector (size);
1069 memcpy (SCM_BYTEVECTOR_CONTENTS (bv), data, size);
1070
1071 write_proc = SCM_CBOP_WRITE_PROC (port);
1072
1073 /* Since the `write' procedure of Guile's ports has type `void', it must
1074 try hard to write exactly SIZE bytes, regardless of how many bytes the
1075 sink can handle. */
1076 for (c_written = 0;
1077 c_written < size;
1078 c_written += c_result)
1079 {
1080 result = scm_call_3 (write_proc, bv,
1081 scm_from_size_t (c_written),
1082 scm_from_size_t (size - c_written));
1083
1084 c_result = scm_to_long (result);
1085 if (SCM_UNLIKELY (c_result < 0
1086 || (size_t) c_result > (size - c_written)))
1087 scm_wrong_type_arg_msg (FUNC_NAME, 0, result,
1088 "R6RS custom binary output port `write!' "
1089 "returned a incorrect integer");
1090 }
1091}
1092#undef FUNC_NAME
1093
1094
1095SCM_DEFINE (scm_make_custom_binary_output_port,
1096 "make-custom-binary-output-port", 5, 0, 0,
1097 (SCM id, SCM write_proc, SCM get_position_proc,
1098 SCM set_position_proc, SCM close_proc),
1099 "Return a new custom binary output port whose output is drained "
1100 "by invoking @var{write_proc} and passing it a bytevector, an "
1101 "index where octets should be written, and an octet count.")
1102#define FUNC_NAME s_scm_make_custom_binary_output_port
1103{
1104 SCM_VALIDATE_STRING (1, id);
1105 SCM_VALIDATE_PROC (2, write_proc);
1106
1107 if (!scm_is_false (get_position_proc))
1108 SCM_VALIDATE_PROC (3, get_position_proc);
1109
1110 if (!scm_is_false (set_position_proc))
1111 SCM_VALIDATE_PROC (4, set_position_proc);
1112
1113 if (!scm_is_false (close_proc))
1114 SCM_VALIDATE_PROC (5, close_proc);
1115
1116 return (make_cbop (write_proc, get_position_proc, set_position_proc,
1117 close_proc));
1118}
1119#undef FUNC_NAME
1120
1121
1122/* Instantiate the custom binary output port type. */
1123static inline void
1124initialize_custom_binary_output_ports (void)
1125{
1126 custom_binary_output_port_type =
1127 scm_make_port_type ("r6rs-custom-binary-output-port",
1128 NULL, cbop_write);
1129
1ee2c72e
LC
1130 scm_set_port_seek (custom_binary_output_port_type, cbp_seek);
1131 scm_set_port_close (custom_binary_output_port_type, cbp_close);
1132}
1133
1134\f
1044537d
AR
1135/* Transcoded ports ("tp" for short). */
1136static scm_t_bits transcoded_port_type = 0;
1137
1138#define TP_INPUT_BUFFER_SIZE 4096
1139
1140#define SCM_TP_BINARY_PORT(_port) SCM_PACK (SCM_STREAM (_port))
1141
1142static inline SCM
1143make_tp (SCM binary_port, unsigned long mode)
1144{
1145 SCM port;
1146 scm_t_port *c_port;
1147 const unsigned long mode_bits = SCM_OPN | mode;
1148
2721f918
AW
1149 port = scm_c_make_port (transcoded_port_type, mode_bits,
1150 SCM_UNPACK (binary_port));
1044537d
AR
1151
1152 if (SCM_INPUT_PORT_P (port))
1153 {
1154 c_port = SCM_PTAB_ENTRY (port);
1155 c_port->read_buf = scm_gc_malloc_pointerless (TP_INPUT_BUFFER_SIZE,
1156 "port buffer");
1157 c_port->read_pos = c_port->read_end = c_port->read_buf;
1158 c_port->read_buf_size = TP_INPUT_BUFFER_SIZE;
1159
1160 SCM_SET_CELL_WORD_0 (port, SCM_CELL_WORD_0 (port) & ~SCM_BUF0);
1161 }
1162
1044537d
AR
1163 return port;
1164}
1165
1166static void
1167tp_write (SCM port, const void *data, size_t size)
1168{
f209aeee 1169 scm_c_write_unlocked (SCM_TP_BINARY_PORT (port), data, size);
1044537d
AR
1170}
1171
1172static int
1173tp_fill_input (SCM port)
1174{
1175 size_t count;
1176 scm_t_port *c_port = SCM_PTAB_ENTRY (port);
1177 SCM bport = SCM_TP_BINARY_PORT (port);
1178 scm_t_port *c_bport = SCM_PTAB_ENTRY (bport);
1179
1180 /* We can't use `scm_c_read' here, since it blocks until the whole
1181 block has been read or EOF. */
1182
1183 if (c_bport->rw_active == SCM_PORT_WRITE)
1184 scm_force_output (bport);
1185
1186 if (c_bport->read_pos >= c_bport->read_end)
4251ae2e 1187 scm_fill_input_unlocked (bport);
1044537d
AR
1188
1189 count = c_bport->read_end - c_bport->read_pos;
1190 if (count > c_port->read_buf_size)
1191 count = c_port->read_buf_size;
1192
1193 memcpy (c_port->read_buf, c_bport->read_pos, count);
1194 c_bport->read_pos += count;
1195
1196 if (c_bport->rw_random)
1197 c_bport->rw_active = SCM_PORT_READ;
1198
1199 if (count == 0)
1200 return EOF;
1201 else
1202 {
1203 c_port->read_pos = c_port->read_buf;
1204 c_port->read_end = c_port->read_buf + count;
1205 return *c_port->read_buf;
1206 }
1207}
1208
1209static void
1210tp_flush (SCM port)
1211{
1212 SCM binary_port = SCM_TP_BINARY_PORT (port);
1213 scm_t_port *c_port = SCM_PTAB_ENTRY (port);
1214 size_t count = c_port->write_pos - c_port->write_buf;
1215
dfb572a7
AR
1216 /* As the runtime will try to flush all ports upon exit, we test for
1217 the underlying port still being open here. Otherwise, when you
1218 would explicitly close the underlying port and the transcoded port
1219 still had data outstanding, you'd get an exception on Guile exit.
1220
1221 We just throw away the data when the underlying port is closed. */
1222
1223 if (SCM_OPOUTPORTP (binary_port))
f209aeee 1224 scm_c_write_unlocked (binary_port, c_port->write_buf, count);
1044537d
AR
1225
1226 c_port->write_pos = c_port->write_buf;
1227 c_port->rw_active = SCM_PORT_NEITHER;
1228
dfb572a7
AR
1229 if (SCM_OPOUTPORTP (binary_port))
1230 scm_force_output (binary_port);
1044537d
AR
1231}
1232
1233static int
1234tp_close (SCM port)
1235{
1236 if (SCM_OUTPUT_PORT_P (port))
1237 tp_flush (port);
1238 return scm_is_true (scm_close_port (SCM_TP_BINARY_PORT (port))) ? 0 : -1;
1239}
1240
1241static inline void
1242initialize_transcoded_ports (void)
1243{
1244 transcoded_port_type =
1245 scm_make_port_type ("r6rs-transcoded-port", tp_fill_input, tp_write);
1246
1247 scm_set_port_flush (transcoded_port_type, tp_flush);
1248 scm_set_port_close (transcoded_port_type, tp_close);
1249}
1250
36cc0b90
AW
1251SCM_INTERNAL SCM scm_i_make_transcoded_port (SCM);
1252
1044537d
AR
1253SCM_DEFINE (scm_i_make_transcoded_port,
1254 "%make-transcoded-port", 1, 0, 0,
1255 (SCM port),
1256 "Return a new port which reads and writes to @var{port}")
1257#define FUNC_NAME s_scm_i_make_transcoded_port
1258{
1259 SCM result;
1260 unsigned long mode = 0;
1261
1262 SCM_VALIDATE_PORT (SCM_ARG1, port);
1263
1264 if (scm_is_true (scm_output_port_p (port)))
1265 mode |= SCM_WRTNG;
1266 else if (scm_is_true (scm_input_port_p (port)))
1267 mode |= SCM_RDNG;
1268
1269 result = make_tp (port, mode);
1270
1271 /* FIXME: We should actually close `port' "in a special way" here,
1272 according to R6RS. As there is no way to do that in Guile without
1273 rendering the underlying port unusable for our purposes as well, we
1274 just leave it open. */
1275
1276 return result;
1277}
1278#undef FUNC_NAME
1279
1280\f
a6c377f7
AR
1281/* Textual I/O */
1282
1283SCM_DEFINE (scm_get_string_n_x,
1284 "get-string-n!", 4, 0, 0,
1285 (SCM port, SCM str, SCM start, SCM count),
1286 "Read up to @var{count} characters from @var{port} into "
1287 "@var{str}, starting at @var{start}. If no characters "
1288 "can be read before the end of file is encountered, the end "
1289 "of file object is returned. Otherwise, the number of "
1290 "characters read is returned.")
1291#define FUNC_NAME s_scm_get_string_n_x
1292{
1293 size_t c_start, c_count, c_len, c_end, j;
1294 scm_t_wchar c;
1295
1296 SCM_VALIDATE_OPINPORT (1, port);
1297 SCM_VALIDATE_STRING (2, str);
1298 c_len = scm_c_string_length (str);
1299 c_start = scm_to_size_t (start);
1300 c_count = scm_to_size_t (count);
1301 c_end = c_start + c_count;
1302
1303 if (SCM_UNLIKELY (c_end > c_len))
1304 scm_out_of_range (FUNC_NAME, count);
1305
1306 for (j = c_start; j < c_end; j++)
1307 {
be632904 1308 c = scm_getc_unlocked (port);
a6c377f7
AR
1309 if (c == EOF)
1310 {
1311 size_t chars_read = j - c_start;
1312 return chars_read == 0 ? SCM_EOF_VAL : scm_from_size_t (chars_read);
1313 }
1314 scm_c_string_set_x (str, j, SCM_MAKE_CHAR (c));
1315 }
1316 return count;
1317}
1318#undef FUNC_NAME
1319
1320\f
1ee2c72e
LC
1321/* Initialization. */
1322
c0062328
LC
1323void
1324scm_register_r6rs_ports (void)
1325{
1326 scm_c_register_extension ("libguile-" SCM_EFFECTIVE_VERSION,
1327 "scm_init_r6rs_ports",
1328 (scm_t_extension_init_func) scm_init_r6rs_ports,
1329 NULL);
1330}
1331
1ee2c72e
LC
1332void
1333scm_init_r6rs_ports (void)
1334{
62e9a9b7 1335#include "libguile/r6rs-ports.x"
1ee2c72e
LC
1336
1337 initialize_bytevector_input_ports ();
1338 initialize_custom_binary_input_ports ();
1339 initialize_bytevector_output_ports ();
1340 initialize_custom_binary_output_ports ();
1044537d 1341 initialize_transcoded_ports ();
1ee2c72e 1342}