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