deprecated eval-when situations
[bpt/guile.git] / libguile / r6rs-ports.c
CommitLineData
ed72201a 1/* Copyright (C) 2009, 2010, 2011, 2013-2015 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:
ed72201a
LC
302 /* Unbuffered: keep using PORT's bytevector as the underlying
303 buffer (it will also be used by future 'scm_c_read' calls.) */
304 assert (SCM_BYTEVECTOR_LENGTH (bv) >= 1);
305 pt->read_buf = (unsigned char *) SCM_BYTEVECTOR_CONTENTS (bv);
8ca97482
LC
306 pt->read_buf_size = 1;
307 break;
308
309 case -1:
310 /* Preferred size: keep the current bytevector and use it as the
311 backing store. */
312 pt->read_buf = (unsigned char *) SCM_BYTEVECTOR_CONTENTS (bv);
313 pt->read_buf_size = SCM_BYTEVECTOR_LENGTH (bv);
314 break;
315
316 default:
317 /* Fully buffered: allocate a buffer of READ_SIZE bytes. */
318 bv = scm_c_make_bytevector (read_size);
319 SCM_SET_CBIP_BYTEVECTOR (port, bv);
320 pt->read_buf = (unsigned char *) SCM_BYTEVECTOR_CONTENTS (bv);
321 pt->read_buf_size = read_size;
322 }
323
324 pt->read_pos = pt->read_end = pt->read_buf;
325}
326
1ee2c72e
LC
327static inline SCM
328make_cbip (SCM read_proc, SCM get_position_proc,
329 SCM set_position_proc, SCM close_proc)
330{
331 SCM port, bv, method_vector;
332 char *c_bv;
333 unsigned c_len;
334 scm_t_port *c_port;
335 const unsigned long mode_bits = SCM_OPN | SCM_RDNG;
336
337 /* Use a bytevector as the underlying buffer. */
338 c_len = CBIP_BUFFER_SIZE;
339 bv = scm_c_make_bytevector (c_len);
340 c_bv = (char *) SCM_BYTEVECTOR_CONTENTS (bv);
341
342 /* Store the various methods and bytevector in a vector. */
343 method_vector = scm_c_make_vector (5, SCM_BOOL_F);
344 SCM_SIMPLE_VECTOR_SET (method_vector, 4, bv);
345 SCM_SIMPLE_VECTOR_SET (method_vector, 0, read_proc);
346 SCM_SIMPLE_VECTOR_SET (method_vector, 1, get_position_proc);
347 SCM_SIMPLE_VECTOR_SET (method_vector, 2, set_position_proc);
348 SCM_SIMPLE_VECTOR_SET (method_vector, 3, close_proc);
349
2721f918
AW
350 port = scm_c_make_port_with_encoding (custom_binary_input_port_type,
351 mode_bits,
352 NULL, /* encoding */
353 SCM_FAILED_CONVERSION_ERROR,
354 SCM_UNPACK (method_vector));
a653d32a 355
96128014
LC
356 c_port = SCM_PTAB_ENTRY (port);
357
1ee2c72e 358 /* Have the port directly access the buffer (bytevector). */
1ee2c72e
LC
359 c_port->read_pos = c_port->read_buf = (unsigned char *) c_bv;
360 c_port->read_end = (unsigned char *) c_bv;
361 c_port->read_buf_size = c_len;
362
1ee2c72e
LC
363 return port;
364}
365
366static int
367cbip_fill_input (SCM port)
368#define FUNC_NAME "cbip_fill_input"
369{
370 int result;
371 scm_t_port *c_port = SCM_PTAB_ENTRY (port);
372
1ee2c72e
LC
373 if (c_port->read_pos >= c_port->read_end)
374 {
375 /* Invoke the user's `read!' procedure. */
8ca97482 376 int buffered;
6df03222 377 size_t c_octets, c_requested;
1ee2c72e
LC
378 SCM bv, read_proc, octets;
379
6df03222 380 c_requested = c_port->read_buf_size;
8ca97482 381 read_proc = SCM_CBIP_READ_PROC (port);
6df03222 382
1ee2c72e 383 bv = SCM_CBIP_BYTEVECTOR (port);
8ca97482
LC
384 buffered =
385 (c_port->read_buf == (unsigned char *) SCM_BYTEVECTOR_CONTENTS (bv));
1ee2c72e 386
8ca97482 387 if (buffered)
45a28515 388 {
ed72201a
LC
389 /* Make sure the buffer isn't corrupt. Its size can be 1 when
390 someone called 'setvbuf' with _IONBF. BV can be passed
391 directly to READ_PROC. */
392 assert (c_port->read_buf_size == SCM_BYTEVECTOR_LENGTH (bv)
393 || c_port->read_buf_size == 1);
45a28515
LC
394 c_port->read_pos = (unsigned char *) SCM_BYTEVECTOR_CONTENTS (bv);
395 }
8ca97482
LC
396 else
397 {
398 /* This is an unbuffered port. When called via the
399 'get-bytevector-*' procedures, and thus via 'scm_c_read', we
400 are passed the caller-provided buffer, so we need to check its
401 size. */
402 if (SCM_BYTEVECTOR_LENGTH (bv) < c_requested)
403 {
404 /* Bad luck: we have to make another allocation. Save that
405 bytevector for later reuse, in the hope that the application
406 has regular access patterns. */
407 bv = scm_c_make_bytevector (c_requested);
408 SCM_SET_CBIP_BYTEVECTOR (port, bv);
409 }
410 }
1ee2c72e
LC
411
412 octets = scm_call_3 (read_proc, bv, SCM_INUM0,
6df03222
LC
413 scm_from_size_t (c_requested));
414 c_octets = scm_to_size_t (octets);
415 if (SCM_UNLIKELY (c_octets > c_requested))
416 scm_out_of_range (FUNC_NAME, octets);
1ee2c72e 417
8ca97482
LC
418 if (!buffered)
419 /* Copy the data back to the internal buffer. */
420 memcpy ((char *) c_port->read_pos, SCM_BYTEVECTOR_CONTENTS (bv),
421 c_octets);
422
1ee2c72e
LC
423 c_port->read_end = (unsigned char *) c_port->read_pos + c_octets;
424
8ca97482
LC
425 if (c_octets != 0 || c_requested == 0)
426 result = (int) *c_port->read_pos;
1ee2c72e
LC
427 else
428 result = EOF;
429 }
430 else
431 result = (int) *c_port->read_pos;
432
433 return result;
434}
435#undef FUNC_NAME
436
437
438SCM_DEFINE (scm_make_custom_binary_input_port,
439 "make-custom-binary-input-port", 5, 0, 0,
440 (SCM id, SCM read_proc, SCM get_position_proc,
441 SCM set_position_proc, SCM close_proc),
442 "Return a new custom binary input port whose input is drained "
443 "by invoking @var{read_proc} and passing it a bytevector, an "
444 "index where octets should be written, and an octet count.")
445#define FUNC_NAME s_scm_make_custom_binary_input_port
446{
447 SCM_VALIDATE_STRING (1, id);
448 SCM_VALIDATE_PROC (2, read_proc);
449
450 if (!scm_is_false (get_position_proc))
451 SCM_VALIDATE_PROC (3, get_position_proc);
452
453 if (!scm_is_false (set_position_proc))
454 SCM_VALIDATE_PROC (4, set_position_proc);
455
456 if (!scm_is_false (close_proc))
457 SCM_VALIDATE_PROC (5, close_proc);
458
459 return (make_cbip (read_proc, get_position_proc, set_position_proc,
460 close_proc));
461}
462#undef FUNC_NAME
463
464
465/* Instantiate the custom binary input port type. */
466static inline void
467initialize_custom_binary_input_ports (void)
468{
469 custom_binary_input_port_type =
470 scm_make_port_type ("r6rs-custom-binary-input-port",
471 cbip_fill_input, NULL);
472
1ee2c72e
LC
473 scm_set_port_seek (custom_binary_input_port_type, cbp_seek);
474 scm_set_port_close (custom_binary_input_port_type, cbp_close);
e4eb0e39 475 scm_set_port_setvbuf (custom_binary_input_port_type, cbip_setvbuf);
1ee2c72e
LC
476}
477
478
479\f
480/* Binary input. */
481
482/* We currently don't support specific binary input ports. */
483#define SCM_VALIDATE_BINARY_INPUT_PORT SCM_VALIDATE_OPINPORT
484
485SCM_DEFINE (scm_get_u8, "get-u8", 1, 0, 0,
486 (SCM port),
487 "Read an octet from @var{port}, a binary input port, "
488 "blocking as necessary.")
489#define FUNC_NAME s_scm_get_u8
490{
491 SCM result;
492 int c_result;
493
494 SCM_VALIDATE_BINARY_INPUT_PORT (1, port);
495
8aa47f26 496 c_result = scm_get_byte_or_eof (port);
1ee2c72e
LC
497 if (c_result == EOF)
498 result = SCM_EOF_VAL;
499 else
500 result = SCM_I_MAKINUM ((unsigned char) c_result);
501
502 return result;
503}
504#undef FUNC_NAME
505
506SCM_DEFINE (scm_lookahead_u8, "lookahead-u8", 1, 0, 0,
507 (SCM port),
508 "Like @code{get-u8} but does not update @var{port} to "
509 "point past the octet.")
510#define FUNC_NAME s_scm_lookahead_u8
511{
8aa47f26 512 int u8;
1ee2c72e
LC
513 SCM result;
514
515 SCM_VALIDATE_BINARY_INPUT_PORT (1, port);
516
452c5ad9 517 u8 = scm_peek_byte_or_eof (port);
8aa47f26 518 if (u8 == EOF)
1ee2c72e 519 result = SCM_EOF_VAL;
8aa47f26 520 else
452c5ad9 521 result = SCM_I_MAKINUM ((scm_t_uint8) u8);
1ee2c72e
LC
522
523 return result;
524}
525#undef FUNC_NAME
526
527SCM_DEFINE (scm_get_bytevector_n, "get-bytevector-n", 2, 0, 0,
528 (SCM port, SCM count),
529 "Read @var{count} octets from @var{port}, blocking as "
530 "necessary and return a bytevector containing the octets "
531 "read. If fewer bytes are available, a bytevector smaller "
532 "than @var{count} is returned.")
533#define FUNC_NAME s_scm_get_bytevector_n
534{
535 SCM result;
536 char *c_bv;
537 unsigned c_count;
538 size_t c_read;
539
540 SCM_VALIDATE_BINARY_INPUT_PORT (1, port);
541 c_count = scm_to_uint (count);
542
543 result = scm_c_make_bytevector (c_count);
544 c_bv = (char *) SCM_BYTEVECTOR_CONTENTS (result);
545
546 if (SCM_LIKELY (c_count > 0))
547 /* XXX: `scm_c_read ()' does not update the port position. */
be632904 548 c_read = scm_c_read_unlocked (port, c_bv, c_count);
1ee2c72e
LC
549 else
550 /* Don't invoke `scm_c_read ()' since it may block. */
551 c_read = 0;
552
47f2bce5 553 if (c_read < c_count)
1ee2c72e 554 {
47f2bce5
MW
555 if (c_read == 0)
556 result = SCM_EOF_VAL;
1ee2c72e 557 else
1ee2c72e
LC
558 result = scm_c_shrink_bytevector (result, c_read);
559 }
560
561 return result;
562}
563#undef FUNC_NAME
564
565SCM_DEFINE (scm_get_bytevector_n_x, "get-bytevector-n!", 4, 0, 0,
566 (SCM port, SCM bv, SCM start, SCM count),
567 "Read @var{count} bytes from @var{port} and store them "
568 "in @var{bv} starting at index @var{start}. Return either "
569 "the number of bytes actually read or the end-of-file "
570 "object.")
571#define FUNC_NAME s_scm_get_bytevector_n_x
572{
573 SCM result;
574 char *c_bv;
575 unsigned c_start, c_count, c_len;
576 size_t c_read;
577
578 SCM_VALIDATE_BINARY_INPUT_PORT (1, port);
579 SCM_VALIDATE_BYTEVECTOR (2, bv);
580 c_start = scm_to_uint (start);
581 c_count = scm_to_uint (count);
582
583 c_bv = (char *) SCM_BYTEVECTOR_CONTENTS (bv);
584 c_len = SCM_BYTEVECTOR_LENGTH (bv);
585
586 if (SCM_UNLIKELY (c_start + c_count > c_len))
587 scm_out_of_range (FUNC_NAME, count);
588
589 if (SCM_LIKELY (c_count > 0))
be632904 590 c_read = scm_c_read_unlocked (port, c_bv + c_start, c_count);
1ee2c72e
LC
591 else
592 /* Don't invoke `scm_c_read ()' since it may block. */
593 c_read = 0;
594
47f2bce5
MW
595 if (c_read == 0 && c_count > 0)
596 result = SCM_EOF_VAL;
1ee2c72e
LC
597 else
598 result = scm_from_size_t (c_read);
599
600 return result;
601}
602#undef FUNC_NAME
603
604
605SCM_DEFINE (scm_get_bytevector_some, "get-bytevector-some", 1, 0, 0,
606 (SCM port),
21bbe22a
MW
607 "Read from @var{port}, blocking as necessary, until bytes "
608 "are available or an end-of-file is reached. Return either "
609 "the end-of-file object or a new bytevector containing some "
610 "of the available bytes (at least one), and update the port "
611 "position to point just past these bytes.")
1ee2c72e
LC
612#define FUNC_NAME s_scm_get_bytevector_some
613{
21bbe22a
MW
614 scm_t_port *pt;
615 size_t size;
616 SCM bv;
1ee2c72e
LC
617
618 SCM_VALIDATE_BINARY_INPUT_PORT (1, port);
21bbe22a 619 pt = SCM_PTAB_ENTRY (port);
1ee2c72e 620
21bbe22a 621 if (pt->rw_active == SCM_PORT_WRITE)
f6f4feb0 622 scm_flush_unlocked (port);
1ee2c72e 623
21bbe22a
MW
624 if (pt->rw_random)
625 pt->rw_active = SCM_PORT_READ;
1ee2c72e 626
21bbe22a 627 if (pt->read_pos >= pt->read_end)
1ee2c72e 628 {
f6f4feb0 629 if (scm_fill_input_unlocked (port) == EOF)
21bbe22a 630 return SCM_EOF_VAL;
1ee2c72e 631 }
1ee2c72e 632
21bbe22a
MW
633 size = pt->read_end - pt->read_pos;
634 if (pt->read_buf == pt->putback_buf)
635 size += pt->saved_read_end - pt->saved_read_pos;
1ee2c72e 636
21bbe22a
MW
637 bv = scm_c_make_bytevector (size);
638 scm_take_from_input_buffers
639 (port, (char *) SCM_BYTEVECTOR_CONTENTS (bv), size);
640
641 return bv;
1ee2c72e
LC
642}
643#undef FUNC_NAME
644
645SCM_DEFINE (scm_get_bytevector_all, "get-bytevector-all", 1, 0, 0,
646 (SCM port),
647 "Read from @var{port}, blocking as necessary, until "
648 "the end-of-file is reached. Return either "
649 "a new bytevector containing the data read or the "
650 "end-of-file object (if no data were available).")
651#define FUNC_NAME s_scm_get_bytevector_all
652{
653 SCM result;
654 char *c_bv;
655 unsigned c_len, c_count;
656 size_t c_read, c_total;
657
658 SCM_VALIDATE_BINARY_INPUT_PORT (1, port);
659
660 c_len = c_count = 4096;
05762e72 661 c_bv = (char *) scm_gc_malloc_pointerless (c_len, SCM_GC_BYTEVECTOR);
1ee2c72e
LC
662 c_total = c_read = 0;
663
664 do
665 {
666 if (c_total + c_read > c_len)
667 {
668 /* Grow the bytevector. */
669 c_bv = (char *) scm_gc_realloc (c_bv, c_len, c_len * 2,
670 SCM_GC_BYTEVECTOR);
671 c_count = c_len;
672 c_len *= 2;
673 }
674
675 /* `scm_c_read ()' blocks until C_COUNT bytes are available or EOF is
676 reached. */
be632904 677 c_read = scm_c_read_unlocked (port, c_bv + c_total, c_count);
1ee2c72e
LC
678 c_total += c_read, c_count -= c_read;
679 }
47f2bce5 680 while (c_count == 0);
1ee2c72e
LC
681
682 if (c_total == 0)
683 {
684 result = SCM_EOF_VAL;
685 scm_gc_free (c_bv, c_len, SCM_GC_BYTEVECTOR);
686 }
687 else
688 {
689 if (c_len > c_total)
690 {
691 /* Shrink the bytevector. */
692 c_bv = (char *) scm_gc_realloc (c_bv, c_len, c_total,
693 SCM_GC_BYTEVECTOR);
694 c_len = (unsigned) c_total;
695 }
696
8b66aa8f
AW
697 result = scm_c_take_gc_bytevector ((signed char *) c_bv, c_len,
698 SCM_BOOL_F);
1ee2c72e
LC
699 }
700
701 return result;
702}
703#undef FUNC_NAME
704
705
706\f
707/* Binary output. */
708
709/* We currently don't support specific binary input ports. */
710#define SCM_VALIDATE_BINARY_OUTPUT_PORT SCM_VALIDATE_OPOUTPORT
711
712
713SCM_DEFINE (scm_put_u8, "put-u8", 2, 0, 0,
714 (SCM port, SCM octet),
715 "Write @var{octet} to binary port @var{port}.")
716#define FUNC_NAME s_scm_put_u8
717{
718 scm_t_uint8 c_octet;
719
720 SCM_VALIDATE_BINARY_OUTPUT_PORT (1, port);
721 c_octet = scm_to_uint8 (octet);
722
0607ebbf 723 scm_putc_unlocked ((char) c_octet, port);
1ee2c72e
LC
724
725 return SCM_UNSPECIFIED;
726}
727#undef FUNC_NAME
728
729SCM_DEFINE (scm_put_bytevector, "put-bytevector", 2, 2, 0,
730 (SCM port, SCM bv, SCM start, SCM count),
731 "Write the contents of @var{bv} to @var{port}, optionally "
732 "starting at index @var{start} and limiting to @var{count} "
733 "octets.")
734#define FUNC_NAME s_scm_put_bytevector
735{
736 char *c_bv;
737 unsigned c_start, c_count, c_len;
738
739 SCM_VALIDATE_BINARY_OUTPUT_PORT (1, port);
740 SCM_VALIDATE_BYTEVECTOR (2, bv);
741
742 c_len = SCM_BYTEVECTOR_LENGTH (bv);
743 c_bv = (char *) SCM_BYTEVECTOR_CONTENTS (bv);
744
d223c3fc 745 if (!scm_is_eq (start, SCM_UNDEFINED))
1ee2c72e
LC
746 {
747 c_start = scm_to_uint (start);
748
d223c3fc 749 if (!scm_is_eq (count, SCM_UNDEFINED))
1ee2c72e
LC
750 {
751 c_count = scm_to_uint (count);
752 if (SCM_UNLIKELY (c_start + c_count > c_len))
753 scm_out_of_range (FUNC_NAME, count);
754 }
755 else
756 {
757 if (SCM_UNLIKELY (c_start >= c_len))
758 scm_out_of_range (FUNC_NAME, start);
759 else
760 c_count = c_len - c_start;
761 }
762 }
763 else
764 c_start = 0, c_count = c_len;
765
f209aeee 766 scm_c_write_unlocked (port, c_bv + c_start, c_count);
1ee2c72e
LC
767
768 return SCM_UNSPECIFIED;
769}
770#undef FUNC_NAME
771
7f6c3f8f
MW
772SCM_DEFINE (scm_unget_bytevector, "unget-bytevector", 2, 2, 0,
773 (SCM port, SCM bv, SCM start, SCM count),
774 "Unget the contents of @var{bv} to @var{port}, optionally "
775 "starting at index @var{start} and limiting to @var{count} "
776 "octets.")
777#define FUNC_NAME s_scm_unget_bytevector
778{
779 unsigned char *c_bv;
780 size_t c_start, c_count, c_len;
781
782 SCM_VALIDATE_BINARY_INPUT_PORT (1, port);
783 SCM_VALIDATE_BYTEVECTOR (2, bv);
784
785 c_len = SCM_BYTEVECTOR_LENGTH (bv);
786 c_bv = (unsigned char *) SCM_BYTEVECTOR_CONTENTS (bv);
787
788 if (!scm_is_eq (start, SCM_UNDEFINED))
789 {
790 c_start = scm_to_size_t (start);
791
792 if (!scm_is_eq (count, SCM_UNDEFINED))
793 {
794 c_count = scm_to_size_t (count);
795 if (SCM_UNLIKELY (c_start + c_count > c_len))
796 scm_out_of_range (FUNC_NAME, count);
797 }
798 else
799 {
800 if (SCM_UNLIKELY (c_start >= c_len))
801 scm_out_of_range (FUNC_NAME, start);
802 else
803 c_count = c_len - c_start;
804 }
805 }
806 else
807 c_start = 0, c_count = c_len;
808
809 scm_unget_bytes (c_bv + c_start, c_count, port);
810
811 return SCM_UNSPECIFIED;
812}
813#undef FUNC_NAME
814
1ee2c72e
LC
815
816\f
817/* Bytevector output port ("bop" for short). */
818
819/* Implementation of "bops".
820
821 Each bop has an internal buffer, of type `scm_t_bop_buffer', attached to
822 it. The procedure returned along with the output port is actually an
823 applicable SMOB. The SMOB holds a reference to the port. When applied,
824 the SMOB swallows the port's internal buffer, turning it into a
825 bytevector, and resets it.
826
827 XXX: Access to a bop's internal buffer is not thread-safe. */
828
829static scm_t_bits bytevector_output_port_type = 0;
830
831SCM_SMOB (bytevector_output_port_procedure,
832 "r6rs-bytevector-output-port-procedure",
833 0);
834
835#define SCM_GC_BOP "r6rs-bytevector-output-port"
836#define SCM_BOP_BUFFER_INITIAL_SIZE 4096
837
838/* Representation of a bop's internal buffer. */
839typedef struct
840{
841 size_t total_len;
842 size_t len;
843 size_t pos;
844 char *buffer;
845} scm_t_bop_buffer;
846
847
848/* Accessing a bop's buffer. */
849#define SCM_BOP_BUFFER(_port) \
850 ((scm_t_bop_buffer *) SCM_STREAM (_port))
851#define SCM_SET_BOP_BUFFER(_port, _buf) \
852 (SCM_SETSTREAM ((_port), (scm_t_bits) (_buf)))
853
854
855static inline void
856bop_buffer_init (scm_t_bop_buffer *buf)
857{
858 buf->total_len = buf->len = buf->pos = 0;
859 buf->buffer = NULL;
860}
861
862static inline void
863bop_buffer_grow (scm_t_bop_buffer *buf, size_t min_size)
864{
865 char *new_buf;
866 size_t new_size;
867
868 for (new_size = buf->total_len
869 ? buf->total_len : SCM_BOP_BUFFER_INITIAL_SIZE;
870 new_size < min_size;
871 new_size *= 2);
872
873 if (buf->buffer)
874 new_buf = scm_gc_realloc ((void *) buf->buffer, buf->total_len,
875 new_size, SCM_GC_BOP);
876 else
05762e72 877 new_buf = scm_gc_malloc_pointerless (new_size, SCM_GC_BOP);
1ee2c72e
LC
878
879 buf->buffer = new_buf;
880 buf->total_len = new_size;
881}
882
883static inline SCM
884make_bop (void)
885{
886 SCM port, bop_proc;
887 scm_t_port *c_port;
888 scm_t_bop_buffer *buf;
889 const unsigned long mode_bits = SCM_OPN | SCM_WRTNG;
890
1ee2c72e
LC
891 buf = (scm_t_bop_buffer *) scm_gc_malloc (sizeof (* buf), SCM_GC_BOP);
892 bop_buffer_init (buf);
893
2721f918
AW
894 port = scm_c_make_port_with_encoding (bytevector_output_port_type,
895 mode_bits,
896 NULL, /* encoding */
897 SCM_FAILED_CONVERSION_ERROR,
898 (scm_t_bits)buf);
1ee2c72e 899
2721f918 900 c_port = SCM_PTAB_ENTRY (port);
1ee2c72e 901
2721f918
AW
902 c_port->write_buf = c_port->write_pos = c_port->write_end = NULL;
903 c_port->write_buf_size = 0;
a653d32a 904
1ee2c72e 905 /* Make the bop procedure. */
a653d32a 906 SCM_NEWSMOB (bop_proc, bytevector_output_port_procedure, buf);
1ee2c72e
LC
907
908 return (scm_values (scm_list_2 (port, bop_proc)));
909}
910
1ee2c72e
LC
911/* Write SIZE octets from DATA to PORT. */
912static void
913bop_write (SCM port, const void *data, size_t size)
914{
915 scm_t_bop_buffer *buf;
916
917 buf = SCM_BOP_BUFFER (port);
918
919 if (buf->pos + size > buf->total_len)
920 bop_buffer_grow (buf, buf->pos + size);
921
922 memcpy (buf->buffer + buf->pos, data, size);
923 buf->pos += size;
924 buf->len = (buf->len > buf->pos) ? buf->len : buf->pos;
925}
926
f1ce9199
LC
927static scm_t_off
928bop_seek (SCM port, scm_t_off offset, int whence)
1ee2c72e
LC
929#define FUNC_NAME "bop_seek"
930{
931 scm_t_bop_buffer *buf;
932
933 buf = SCM_BOP_BUFFER (port);
934 switch (whence)
935 {
936 case SEEK_CUR:
f1ce9199 937 offset += (scm_t_off) buf->pos;
1ee2c72e
LC
938 /* Fall through. */
939
940 case SEEK_SET:
941 if (offset < 0 || (unsigned) offset > buf->len)
942 scm_out_of_range (FUNC_NAME, scm_from_int (offset));
943 else
944 buf->pos = offset;
945 break;
946
947 case SEEK_END:
948 if (offset < 0 || (unsigned) offset >= buf->len)
949 scm_out_of_range (FUNC_NAME, scm_from_int (offset));
950 else
951 buf->pos = buf->len - (offset + 1);
952 break;
953
954 default:
955 scm_wrong_type_arg_msg (FUNC_NAME, 0, port,
956 "invalid `seek' parameter");
957 }
958
959 return buf->pos;
960}
961#undef FUNC_NAME
962
963/* Fetch data from a bop. */
964SCM_SMOB_APPLY (bytevector_output_port_procedure,
965 bop_proc_apply, 0, 0, 0, (SCM bop_proc))
966{
a653d32a 967 SCM bv;
1ee2c72e
LC
968 scm_t_bop_buffer *buf, result_buf;
969
a653d32a 970 buf = (scm_t_bop_buffer *) SCM_SMOB_DATA (bop_proc);
1ee2c72e
LC
971
972 result_buf = *buf;
973 bop_buffer_init (buf);
974
975 if (result_buf.len == 0)
8b66aa8f 976 bv = scm_c_take_gc_bytevector (NULL, 0, SCM_BOOL_F);
1ee2c72e
LC
977 else
978 {
979 if (result_buf.total_len > result_buf.len)
980 /* Shrink the buffer. */
981 result_buf.buffer = scm_gc_realloc ((void *) result_buf.buffer,
982 result_buf.total_len,
983 result_buf.len,
984 SCM_GC_BOP);
985
fb031aba 986 bv = scm_c_take_gc_bytevector ((signed char *) result_buf.buffer,
8b66aa8f 987 result_buf.len, SCM_BOOL_F);
1ee2c72e
LC
988 }
989
990 return bv;
991}
992
1ee2c72e
LC
993SCM_DEFINE (scm_open_bytevector_output_port,
994 "open-bytevector-output-port", 0, 1, 0,
995 (SCM transcoder),
996 "Return two values: an output port and a procedure. The latter "
997 "should be called with zero arguments to obtain a bytevector "
998 "containing the data accumulated by the port.")
999#define FUNC_NAME s_scm_open_bytevector_output_port
1000{
1001 if (!SCM_UNBNDP (transcoder) && !scm_is_false (transcoder))
1002 transcoders_not_implemented ();
1003
1004 return (make_bop ());
1005}
1006#undef FUNC_NAME
1007
1008static inline void
1009initialize_bytevector_output_ports (void)
1010{
1011 bytevector_output_port_type =
1012 scm_make_port_type ("r6rs-bytevector-output-port",
1013 NULL, bop_write);
1014
1015 scm_set_port_seek (bytevector_output_port_type, bop_seek);
1ee2c72e
LC
1016}
1017
1018\f
1019/* Custom binary output port ("cbop" for short). */
1020
1021static scm_t_bits custom_binary_output_port_type;
1022
1023/* Return the various procedures of PORT. */
1024#define SCM_CBOP_WRITE_PROC(_port) \
1025 SCM_SIMPLE_VECTOR_REF (SCM_PACK (SCM_STREAM (_port)), 0)
1026
1027
1028static inline SCM
1029make_cbop (SCM write_proc, SCM get_position_proc,
1030 SCM set_position_proc, SCM close_proc)
1031{
1032 SCM port, method_vector;
1033 scm_t_port *c_port;
1034 const unsigned long mode_bits = SCM_OPN | SCM_WRTNG;
1035
1036 /* Store the various methods and bytevector in a vector. */
1037 method_vector = scm_c_make_vector (4, SCM_BOOL_F);
1038 SCM_SIMPLE_VECTOR_SET (method_vector, 0, write_proc);
1039 SCM_SIMPLE_VECTOR_SET (method_vector, 1, get_position_proc);
1040 SCM_SIMPLE_VECTOR_SET (method_vector, 2, set_position_proc);
1041 SCM_SIMPLE_VECTOR_SET (method_vector, 3, close_proc);
1042
2721f918
AW
1043 port = scm_c_make_port_with_encoding (custom_binary_output_port_type,
1044 mode_bits,
1045 NULL, /* encoding */
1046 SCM_FAILED_CONVERSION_ERROR,
1047 SCM_UNPACK (method_vector));
a653d32a 1048
96128014
LC
1049 c_port = SCM_PTAB_ENTRY (port);
1050
1ee2c72e 1051 /* Have the port directly access the buffer (bytevector). */
1ee2c72e
LC
1052 c_port->write_buf = c_port->write_pos = c_port->write_end = NULL;
1053 c_port->write_buf_size = c_port->read_buf_size = 0;
1054
1ee2c72e
LC
1055 return port;
1056}
1057
1058/* Write SIZE octets from DATA to PORT. */
1059static void
1060cbop_write (SCM port, const void *data, size_t size)
1061#define FUNC_NAME "cbop_write"
1062{
1063 long int c_result;
1064 size_t c_written;
1065 SCM bv, write_proc, result;
1066
1067 /* XXX: Allocating a new bytevector at each `write' call is inefficient,
1068 but necessary since (1) we don't control the lifetime of the buffer
1069 pointed to by DATA, and (2) the `write!' procedure could capture the
1070 bytevector it is passed. */
1071 bv = scm_c_make_bytevector (size);
1072 memcpy (SCM_BYTEVECTOR_CONTENTS (bv), data, size);
1073
1074 write_proc = SCM_CBOP_WRITE_PROC (port);
1075
1076 /* Since the `write' procedure of Guile's ports has type `void', it must
1077 try hard to write exactly SIZE bytes, regardless of how many bytes the
1078 sink can handle. */
1079 for (c_written = 0;
1080 c_written < size;
1081 c_written += c_result)
1082 {
1083 result = scm_call_3 (write_proc, bv,
1084 scm_from_size_t (c_written),
1085 scm_from_size_t (size - c_written));
1086
1087 c_result = scm_to_long (result);
1088 if (SCM_UNLIKELY (c_result < 0
1089 || (size_t) c_result > (size - c_written)))
1090 scm_wrong_type_arg_msg (FUNC_NAME, 0, result,
1091 "R6RS custom binary output port `write!' "
1092 "returned a incorrect integer");
1093 }
1094}
1095#undef FUNC_NAME
1096
1097
1098SCM_DEFINE (scm_make_custom_binary_output_port,
1099 "make-custom-binary-output-port", 5, 0, 0,
1100 (SCM id, SCM write_proc, SCM get_position_proc,
1101 SCM set_position_proc, SCM close_proc),
1102 "Return a new custom binary output port whose output is drained "
1103 "by invoking @var{write_proc} and passing it a bytevector, an "
1104 "index where octets should be written, and an octet count.")
1105#define FUNC_NAME s_scm_make_custom_binary_output_port
1106{
1107 SCM_VALIDATE_STRING (1, id);
1108 SCM_VALIDATE_PROC (2, write_proc);
1109
1110 if (!scm_is_false (get_position_proc))
1111 SCM_VALIDATE_PROC (3, get_position_proc);
1112
1113 if (!scm_is_false (set_position_proc))
1114 SCM_VALIDATE_PROC (4, set_position_proc);
1115
1116 if (!scm_is_false (close_proc))
1117 SCM_VALIDATE_PROC (5, close_proc);
1118
1119 return (make_cbop (write_proc, get_position_proc, set_position_proc,
1120 close_proc));
1121}
1122#undef FUNC_NAME
1123
1124
1125/* Instantiate the custom binary output port type. */
1126static inline void
1127initialize_custom_binary_output_ports (void)
1128{
1129 custom_binary_output_port_type =
1130 scm_make_port_type ("r6rs-custom-binary-output-port",
1131 NULL, cbop_write);
1132
1ee2c72e
LC
1133 scm_set_port_seek (custom_binary_output_port_type, cbp_seek);
1134 scm_set_port_close (custom_binary_output_port_type, cbp_close);
1135}
1136
1137\f
1044537d
AR
1138/* Transcoded ports ("tp" for short). */
1139static scm_t_bits transcoded_port_type = 0;
1140
1141#define TP_INPUT_BUFFER_SIZE 4096
1142
1143#define SCM_TP_BINARY_PORT(_port) SCM_PACK (SCM_STREAM (_port))
1144
1145static inline SCM
1146make_tp (SCM binary_port, unsigned long mode)
1147{
1148 SCM port;
1149 scm_t_port *c_port;
1150 const unsigned long mode_bits = SCM_OPN | mode;
1151
2721f918
AW
1152 port = scm_c_make_port (transcoded_port_type, mode_bits,
1153 SCM_UNPACK (binary_port));
1044537d
AR
1154
1155 if (SCM_INPUT_PORT_P (port))
1156 {
1157 c_port = SCM_PTAB_ENTRY (port);
1158 c_port->read_buf = scm_gc_malloc_pointerless (TP_INPUT_BUFFER_SIZE,
1159 "port buffer");
1160 c_port->read_pos = c_port->read_end = c_port->read_buf;
1161 c_port->read_buf_size = TP_INPUT_BUFFER_SIZE;
1162
1163 SCM_SET_CELL_WORD_0 (port, SCM_CELL_WORD_0 (port) & ~SCM_BUF0);
1164 }
1165
1044537d
AR
1166 return port;
1167}
1168
1169static void
1170tp_write (SCM port, const void *data, size_t size)
1171{
f209aeee 1172 scm_c_write_unlocked (SCM_TP_BINARY_PORT (port), data, size);
1044537d
AR
1173}
1174
1175static int
1176tp_fill_input (SCM port)
1177{
1178 size_t count;
1179 scm_t_port *c_port = SCM_PTAB_ENTRY (port);
1180 SCM bport = SCM_TP_BINARY_PORT (port);
1181 scm_t_port *c_bport = SCM_PTAB_ENTRY (bport);
1182
1183 /* We can't use `scm_c_read' here, since it blocks until the whole
1184 block has been read or EOF. */
1185
1186 if (c_bport->rw_active == SCM_PORT_WRITE)
1187 scm_force_output (bport);
1188
1189 if (c_bport->read_pos >= c_bport->read_end)
4251ae2e 1190 scm_fill_input_unlocked (bport);
1044537d
AR
1191
1192 count = c_bport->read_end - c_bport->read_pos;
1193 if (count > c_port->read_buf_size)
1194 count = c_port->read_buf_size;
1195
1196 memcpy (c_port->read_buf, c_bport->read_pos, count);
1197 c_bport->read_pos += count;
1198
1199 if (c_bport->rw_random)
1200 c_bport->rw_active = SCM_PORT_READ;
1201
1202 if (count == 0)
1203 return EOF;
1204 else
1205 {
1206 c_port->read_pos = c_port->read_buf;
1207 c_port->read_end = c_port->read_buf + count;
1208 return *c_port->read_buf;
1209 }
1210}
1211
1212static void
1213tp_flush (SCM port)
1214{
1215 SCM binary_port = SCM_TP_BINARY_PORT (port);
1216 scm_t_port *c_port = SCM_PTAB_ENTRY (port);
1217 size_t count = c_port->write_pos - c_port->write_buf;
1218
dfb572a7
AR
1219 /* As the runtime will try to flush all ports upon exit, we test for
1220 the underlying port still being open here. Otherwise, when you
1221 would explicitly close the underlying port and the transcoded port
1222 still had data outstanding, you'd get an exception on Guile exit.
1223
1224 We just throw away the data when the underlying port is closed. */
1225
1226 if (SCM_OPOUTPORTP (binary_port))
f209aeee 1227 scm_c_write_unlocked (binary_port, c_port->write_buf, count);
1044537d
AR
1228
1229 c_port->write_pos = c_port->write_buf;
1230 c_port->rw_active = SCM_PORT_NEITHER;
1231
dfb572a7
AR
1232 if (SCM_OPOUTPORTP (binary_port))
1233 scm_force_output (binary_port);
1044537d
AR
1234}
1235
1236static int
1237tp_close (SCM port)
1238{
1239 if (SCM_OUTPUT_PORT_P (port))
1240 tp_flush (port);
1241 return scm_is_true (scm_close_port (SCM_TP_BINARY_PORT (port))) ? 0 : -1;
1242}
1243
1244static inline void
1245initialize_transcoded_ports (void)
1246{
1247 transcoded_port_type =
1248 scm_make_port_type ("r6rs-transcoded-port", tp_fill_input, tp_write);
1249
1250 scm_set_port_flush (transcoded_port_type, tp_flush);
1251 scm_set_port_close (transcoded_port_type, tp_close);
1252}
1253
36cc0b90
AW
1254SCM_INTERNAL SCM scm_i_make_transcoded_port (SCM);
1255
1044537d
AR
1256SCM_DEFINE (scm_i_make_transcoded_port,
1257 "%make-transcoded-port", 1, 0, 0,
1258 (SCM port),
1259 "Return a new port which reads and writes to @var{port}")
1260#define FUNC_NAME s_scm_i_make_transcoded_port
1261{
1262 SCM result;
1263 unsigned long mode = 0;
1264
1265 SCM_VALIDATE_PORT (SCM_ARG1, port);
1266
1267 if (scm_is_true (scm_output_port_p (port)))
1268 mode |= SCM_WRTNG;
1269 else if (scm_is_true (scm_input_port_p (port)))
1270 mode |= SCM_RDNG;
1271
1272 result = make_tp (port, mode);
1273
1274 /* FIXME: We should actually close `port' "in a special way" here,
1275 according to R6RS. As there is no way to do that in Guile without
1276 rendering the underlying port unusable for our purposes as well, we
1277 just leave it open. */
1278
1279 return result;
1280}
1281#undef FUNC_NAME
1282
1283\f
a6c377f7
AR
1284/* Textual I/O */
1285
1286SCM_DEFINE (scm_get_string_n_x,
1287 "get-string-n!", 4, 0, 0,
1288 (SCM port, SCM str, SCM start, SCM count),
1289 "Read up to @var{count} characters from @var{port} into "
1290 "@var{str}, starting at @var{start}. If no characters "
1291 "can be read before the end of file is encountered, the end "
1292 "of file object is returned. Otherwise, the number of "
1293 "characters read is returned.")
1294#define FUNC_NAME s_scm_get_string_n_x
1295{
1296 size_t c_start, c_count, c_len, c_end, j;
1297 scm_t_wchar c;
1298
1299 SCM_VALIDATE_OPINPORT (1, port);
1300 SCM_VALIDATE_STRING (2, str);
1301 c_len = scm_c_string_length (str);
1302 c_start = scm_to_size_t (start);
1303 c_count = scm_to_size_t (count);
1304 c_end = c_start + c_count;
1305
1306 if (SCM_UNLIKELY (c_end > c_len))
1307 scm_out_of_range (FUNC_NAME, count);
1308
1309 for (j = c_start; j < c_end; j++)
1310 {
be632904 1311 c = scm_getc_unlocked (port);
a6c377f7
AR
1312 if (c == EOF)
1313 {
1314 size_t chars_read = j - c_start;
1315 return chars_read == 0 ? SCM_EOF_VAL : scm_from_size_t (chars_read);
1316 }
1317 scm_c_string_set_x (str, j, SCM_MAKE_CHAR (c));
1318 }
1319 return count;
1320}
1321#undef FUNC_NAME
1322
1323\f
1ee2c72e
LC
1324/* Initialization. */
1325
c0062328
LC
1326void
1327scm_register_r6rs_ports (void)
1328{
1329 scm_c_register_extension ("libguile-" SCM_EFFECTIVE_VERSION,
1330 "scm_init_r6rs_ports",
1331 (scm_t_extension_init_func) scm_init_r6rs_ports,
1332 NULL);
1333}
1334
1ee2c72e
LC
1335void
1336scm_init_r6rs_ports (void)
1337{
62e9a9b7 1338#include "libguile/r6rs-ports.x"
1ee2c72e
LC
1339
1340 initialize_bytevector_input_ports ();
1341 initialize_custom_binary_input_ports ();
1342 initialize_bytevector_output_ports ();
1343 initialize_custom_binary_output_ports ();
1044537d 1344 initialize_transcoded_ports ();
1ee2c72e 1345}