1 /* Guile-R6RS-Libs --- Implementation of R6RS standard libraries.
2 Copyright (C) 2007 Ludovic Courtès <ludovic.courtes@laas.fr>
4 Guile-R6RS-Libs is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
9 Guile-R6RS-Libs is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
14 You should have received a copy of the GNU Lesser General Public
15 License along with Guile-R6RS-Libs; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
25 #include "bytevector.h"
29 /* Unimplemented features. */
32 /* Transoders are currently not implemented since Guile 1.8 is not
33 Unicode-capable. Thus, most of the code here assumes the use of the
36 transcoders_not_implemented (void)
38 fprintf (stderr
, "%s: warning: transcoders not implemented\n",
43 /* End-of-file object. */
45 SCM_DEFINE (scm_r6rs_eof_object
, "eof-object", 0, 0, 0,
47 "Return the end-of-file object.")
48 #define FUNC_NAME s_scm_r6rs_eof_object
57 /* Bytevector input ports or "bip" for short. */
58 static scm_t_bits bytevector_input_port_type
= 0;
67 const unsigned long mode_bits
= SCM_OPN
| SCM_RDNG
| SCM_BUF0
;
69 port
= scm_new_port_table_entry (bytevector_input_port_type
);
71 /* Prevent BV from being GC'd. */
72 SCM_SETSTREAM (port
, SCM_UNPACK (bv
));
74 /* Have the port directly access the bytevector. */
75 c_bv
= (char *) SCM_R6RS_BYTEVECTOR_CONTENTS (bv
);
76 c_len
= SCM_R6RS_BYTEVECTOR_LENGTH (bv
);
78 c_port
= SCM_PTAB_ENTRY (port
);
79 c_port
->read_pos
= c_port
->read_buf
= (unsigned char *) c_bv
;
80 c_port
->read_end
= (unsigned char *) c_bv
+ c_len
;
82 /* Mark PORT as open, readable and unbuffered (hmm, how elegant...). */
83 SCM_SET_CELL_TYPE (port
, bytevector_input_port_type
| mode_bits
);
91 /* Mark the underlying bytevector. */
92 return (SCM_PACK (SCM_STREAM (port
)));
96 bip_fill_input (SCM port
)
99 scm_t_port
*c_port
= SCM_PTAB_ENTRY (port
);
101 if (c_port
->read_pos
>= c_port
->read_end
)
104 result
= (int) *c_port
->read_pos
;
110 bip_seek (SCM port
, off_t offset
, int whence
)
111 #define FUNC_NAME "bip_seek"
114 scm_t_port
*c_port
= SCM_PTAB_ENTRY (port
);
119 offset
+= c_port
->read_pos
- c_port
->read_buf
;
123 if (c_port
->read_buf
+ offset
< c_port
->read_end
)
125 c_port
->read_pos
= c_port
->read_buf
+ offset
;
129 scm_out_of_range (FUNC_NAME
, scm_from_int (offset
));
133 if (c_port
->read_end
- offset
>= c_port
->read_buf
)
135 c_port
->read_pos
= c_port
->read_end
- offset
;
136 c_result
= c_port
->read_pos
- c_port
->read_buf
;
139 scm_out_of_range (FUNC_NAME
, scm_from_int (offset
));
143 scm_wrong_type_arg_msg (FUNC_NAME
, 0, port
,
144 "invalid `seek' parameter");
152 /* Instantiate the bytevector input port type. */
154 initialize_bytevector_input_ports (void)
156 bytevector_input_port_type
=
157 scm_make_port_type ("r6rs-bytevector-input-port",
158 bip_fill_input
, NULL
);
160 scm_set_port_mark (bytevector_input_port_type
, bip_mark
);
161 scm_set_port_seek (bytevector_input_port_type
, bip_seek
);
165 SCM_DEFINE (scm_r6rs_open_bytevector_input_port
,
166 "open-bytevector-input-port", 1, 1, 0,
167 (SCM bv
, SCM transcoder
),
168 "Return an input port whose contents are drawn from "
169 "bytevector @var{bv}.")
170 #define FUNC_NAME s_scm_r6rs_open_bytevector_input_port
172 SCM_VALIDATE_R6RS_BYTEVECTOR (1, bv
);
173 if (transcoder
!= SCM_UNDEFINED
)
174 transcoders_not_implemented ();
176 return (make_bip (bv
));
182 /* Custom binary input port ("cbip" for short). */
184 static scm_t_bits custom_binary_input_port_type
= 0;
186 /* Size of the buffer embedded in custom binary input ports. */
187 #define CBIP_BUFFER_SIZE 4096
189 /* Return the bytevector associated to PORT. */
190 #define SCM_R6RS_CBIP_BYTEVECTOR(_port) \
191 SCM_SIMPLE_VECTOR_REF (SCM_PACK (SCM_STREAM (_port)), 0)
193 /* Return the various procedures of PORT. */
194 #define SCM_R6RS_CBIP_READ_PROC(_port) \
195 SCM_SIMPLE_VECTOR_REF (SCM_PACK (SCM_STREAM (_port)), 1)
196 #define SCM_R6RS_CBIP_GET_POSITION_PROC(_port) \
197 SCM_SIMPLE_VECTOR_REF (SCM_PACK (SCM_STREAM (_port)), 2)
198 #define SCM_R6RS_CBIP_SET_POSITION_PROC(_port) \
199 SCM_SIMPLE_VECTOR_REF (SCM_PACK (SCM_STREAM (_port)), 3)
200 #define SCM_R6RS_CBIP_CLOSE_PROC(_port) \
201 SCM_SIMPLE_VECTOR_REF (SCM_PACK (SCM_STREAM (_port)), 4)
205 make_cbip (SCM read_proc
, SCM get_position_proc
,
206 SCM set_position_proc
, SCM close_proc
)
208 SCM port
, bv
, method_vector
;
212 const unsigned long mode_bits
= SCM_OPN
| SCM_RDNG
| SCM_BUF0
;
214 /* Use a bytevector as the underlying buffer. */
215 c_len
= CBIP_BUFFER_SIZE
;
216 bv
= scm_r6rs_c_make_bytevector (c_len
);
217 c_bv
= (char *) SCM_R6RS_BYTEVECTOR_CONTENTS (bv
);
219 /* Store the various methods and bytevector in a vector. */
220 method_vector
= scm_c_make_vector (5, SCM_BOOL_F
);
221 SCM_SIMPLE_VECTOR_SET (method_vector
, 0, bv
);
222 SCM_SIMPLE_VECTOR_SET (method_vector
, 1, read_proc
);
223 SCM_SIMPLE_VECTOR_SET (method_vector
, 2, get_position_proc
);
224 SCM_SIMPLE_VECTOR_SET (method_vector
, 3, set_position_proc
);
225 SCM_SIMPLE_VECTOR_SET (method_vector
, 4, close_proc
);
227 port
= scm_new_port_table_entry (custom_binary_input_port_type
);
229 /* Attach it the method vector. */
230 SCM_SETSTREAM (port
, SCM_UNPACK (method_vector
));
232 /* Have the port directly access the buffer (bytevector). */
233 c_port
= SCM_PTAB_ENTRY (port
);
234 c_port
->read_pos
= c_port
->read_buf
= (unsigned char *) c_bv
;
235 c_port
->read_end
= (unsigned char *) c_bv
;
237 /* Mark PORT as open, readable and unbuffered (hmm, how elegant...). */
238 SCM_SET_CELL_TYPE (port
, custom_binary_input_port_type
| mode_bits
);
246 /* Mark the underlying bytevector and methods. */
247 return (SCM_PACK (SCM_STREAM (port
)));
251 cbip_fill_input (SCM port
)
252 #define FUNC_NAME "cbip_fill_input"
255 scm_t_port
*c_port
= SCM_PTAB_ENTRY (port
);
258 if (c_port
->read_pos
>= c_port
->read_end
)
260 /* Invoke the user's `read!' procedure. */
262 SCM bv
, read_proc
, octets
;
264 bv
= SCM_R6RS_CBIP_BYTEVECTOR (port
);
265 read_proc
= SCM_R6RS_CBIP_READ_PROC (port
);
267 octets
= scm_call_3 (read_proc
, bv
, SCM_INUM0
,
268 SCM_I_MAKINUM (CBIP_BUFFER_SIZE
));
269 c_octets
= scm_to_uint (octets
);
271 c_port
->read_pos
= (unsigned char *) SCM_R6RS_BYTEVECTOR_CONTENTS (bv
);
272 c_port
->read_end
= (unsigned char *) c_port
->read_pos
+ c_octets
;
280 result
= (int) *c_port
->read_pos
;
287 cbip_seek (SCM port
, off_t offset
, int whence
)
288 #define FUNC_NAME "cbip_seek"
297 SCM get_position_proc
;
299 get_position_proc
= SCM_R6RS_CBIP_GET_POSITION_PROC (port
);
300 if (EXPECT_TRUE (scm_is_true (get_position_proc
)))
301 result
= scm_call_0 (get_position_proc
);
303 scm_wrong_type_arg_msg (FUNC_NAME
, 0, port
,
304 "R6RS custom binary input port does not "
305 "support `port-position'");
307 offset
+= scm_to_int (result
);
313 SCM set_position_proc
;
315 set_position_proc
= SCM_R6RS_CBIP_SET_POSITION_PROC (port
);
316 if (EXPECT_TRUE (scm_is_true (set_position_proc
)))
317 result
= scm_call_1 (set_position_proc
, scm_from_int (offset
));
319 scm_wrong_type_arg_msg (FUNC_NAME
, 0, port
,
320 "R6RS custom binary input port does not "
321 "support `set-port-position!'");
323 /* Assuming setting the position succeeded. */
329 /* `SEEK_END' cannot be supported. */
330 scm_wrong_type_arg_msg (FUNC_NAME
, 0, port
,
331 "R6RS custom binary input ports do not "
332 "support `SEEK_END'");
340 cbip_close (SCM port
)
344 close_proc
= SCM_R6RS_CBIP_CLOSE_PROC (port
);
345 if (scm_is_true (close_proc
))
346 /* Invoke the `close' thunk. */
347 scm_call_0 (close_proc
);
353 SCM_DEFINE (scm_r6rs_make_custom_binary_input_port
,
354 "make-custom-binary-input-port", 2, 3, 0,
355 (SCM id
, SCM read_proc
, SCM get_position_proc
,
356 SCM set_position_proc
, SCM close_proc
),
357 "Return a new custom binary input port whose input is drained "
358 "by invoking @var{read_proc} and passing it a bytevector, an "
359 "index where octets should be written, and an octet count.")
360 #define FUNC_NAME s_scm_r6rs_make_custom_binary_input_port
362 SCM_VALIDATE_STRING (1, id
);
363 SCM_VALIDATE_PROC (2, read_proc
);
365 if (get_position_proc
== SCM_UNDEFINED
)
366 get_position_proc
= SCM_BOOL_F
;
368 SCM_VALIDATE_PROC (3, get_position_proc
);
370 if (set_position_proc
== SCM_UNDEFINED
)
371 set_position_proc
= SCM_BOOL_F
;
373 SCM_VALIDATE_PROC (4, set_position_proc
);
375 if (close_proc
== SCM_UNDEFINED
)
376 close_proc
= SCM_BOOL_F
;
378 SCM_VALIDATE_PROC (5, close_proc
);
380 return (make_cbip (read_proc
, get_position_proc
, set_position_proc
,
386 /* Instantiate the custom binary input port type. */
388 initialize_custom_binary_input_ports (void)
390 custom_binary_input_port_type
=
391 scm_make_port_type ("r6rs-custom-binary-input-port",
392 cbip_fill_input
, NULL
);
394 scm_set_port_mark (custom_binary_input_port_type
, cbip_mark
);
395 scm_set_port_seek (custom_binary_input_port_type
, cbip_seek
);
396 scm_set_port_close (custom_binary_input_port_type
, cbip_close
);
403 /* We currently don't support specific binary input ports. */
404 #define SCM_VALIDATE_R6RS_BINARY_INPUT_PORT SCM_VALIDATE_INPUT_PORT
406 SCM_DEFINE (scm_r6rs_get_u8
, "get-u8", 1, 0, 0,
408 "Read an octet from @var{port}, a binary input port, "
409 "blocking as necessary.")
410 #define FUNC_NAME s_scm_r6rs_get_u8
415 SCM_VALIDATE_R6RS_BINARY_INPUT_PORT (1, port
);
417 c_result
= scm_getc (port
);
419 result
= SCM_EOF_VAL
;
421 result
= SCM_I_MAKINUM ((unsigned char) c_result
);
427 SCM_DEFINE (scm_r6rs_lookahead_u8
, "lookahead-u8", 1, 0, 0,
429 "Like @code{get-u8} but does not update @var{port} to "
430 "point past the octet.")
431 #define FUNC_NAME s_scm_r6rs_lookahead_u8
435 SCM_VALIDATE_R6RS_BINARY_INPUT_PORT (1, port
);
437 result
= scm_peek_char (port
);
438 if (SCM_CHARP (result
))
439 result
= SCM_I_MAKINUM ((signed char) SCM_CHAR (result
));
441 result
= SCM_EOF_VAL
;
447 SCM_DEFINE (scm_r6rs_get_bytevector_n
, "get-bytevector-n", 2, 0, 0,
448 (SCM port
, SCM count
),
449 "Read @var{count} octets from @var{port}, blocking as "
450 "necessary and return a bytevector containing the octets "
451 "read. If fewer bytes are available, a bytevector smaller "
452 "than @var{count} is returned.")
453 #define FUNC_NAME s_scm_r6rs_get_bytevector_n
460 SCM_VALIDATE_R6RS_BINARY_INPUT_PORT (1, port
);
461 c_count
= scm_to_uint (count
);
463 c_bv
= (char *) scm_gc_malloc (c_count
, SCM_GC_BYTEVECTOR
);
465 /* XXX: `scm_c_read ()' does not update the port position. */
466 read
= scm_c_read (port
, c_bv
, c_count
);
470 if (SCM_EOF_OBJECT_P (scm_peek_char (port
)))
471 result
= SCM_EOF_VAL
;
473 result
= scm_r6rs_c_take_bytevector (NULL
, 0);
478 c_bv
= (char *) scm_gc_realloc (c_bv
, c_count
, read
,
481 result
= scm_r6rs_c_take_bytevector ((signed char *) c_bv
, read
);
488 SCM_DEFINE (scm_r6rs_get_bytevector_n_x
, "get-bytevector-n!", 4, 0, 0,
489 (SCM port
, SCM bv
, SCM start
, SCM count
),
490 "Read @var{count} bytes from @var{port} and store them "
491 "in @var{bv} starting at index @var{start}. Return either "
492 "the number of bytes actually read or the end-of-file "
494 #define FUNC_NAME s_scm_r6rs_get_bytevector_n_x
498 unsigned c_start
, c_count
, c_len
;
501 SCM_VALIDATE_R6RS_BINARY_INPUT_PORT (1, port
);
502 SCM_VALIDATE_R6RS_BYTEVECTOR (2, bv
);
503 c_start
= scm_to_uint (start
);
504 c_count
= scm_to_uint (count
);
506 c_bv
= (char *) SCM_R6RS_BYTEVECTOR_CONTENTS (bv
);
507 c_len
= SCM_R6RS_BYTEVECTOR_LENGTH (bv
);
509 if (EXPECT_FALSE (c_start
+ c_count
> c_len
))
510 scm_out_of_range (FUNC_NAME
, count
);
512 c_read
= scm_c_read (port
, c_bv
+ c_start
, c_count
);
515 if (SCM_EOF_OBJECT_P (scm_peek_char (port
)))
516 result
= SCM_EOF_VAL
;
518 result
= SCM_I_MAKINUM (0);
521 result
= scm_from_size_t (c_read
);
528 SCM_DEFINE (scm_r6rs_get_bytevector_some
, "get-bytevector-some", 1, 0, 0,
530 "Read from @var{port}, blocking as necessary, until data "
531 "are available or and end-of-file is reached. Return either "
532 "a new bytevector containing the data read or the "
533 "end-of-file object.")
534 #define FUNC_NAME s_scm_r6rs_get_bytevector_some
536 /* Read at least one byte, unless the end-of-file is already reached, and
537 read while characters are available (buffered). */
544 SCM_VALIDATE_R6RS_BINARY_INPUT_PORT (1, port
);
547 c_bv
= (char *) scm_gc_malloc (c_len
, SCM_GC_BYTEVECTOR
);
554 if (c_total
+ 1 > c_len
)
556 /* Grow the bytevector. */
557 c_bv
= (char *) scm_gc_realloc (c_bv
, c_len
, c_len
* 2,
562 /* We can't use `scm_c_read ()' since it blocks. */
563 c_chr
= scm_getc (port
);
566 c_bv
[c_total
] = (char) c_chr
;
570 while ((scm_is_true (scm_char_ready_p (port
)))
571 && (!SCM_EOF_OBJECT_P (scm_peek_char (port
))));
575 result
= SCM_EOF_VAL
;
576 scm_gc_free (c_bv
, c_len
, SCM_GC_BYTEVECTOR
);
582 /* Shrink the bytevector. */
583 c_bv
= (char *) scm_gc_realloc (c_bv
, c_len
, c_total
,
585 c_len
= (unsigned) c_total
;
588 result
= scm_r6rs_c_take_bytevector ((signed char *) c_bv
, c_len
);
595 SCM_DEFINE (scm_r6rs_get_bytevector_all
, "get-bytevector-all", 1, 0, 0,
597 "Read from @var{port}, blocking as necessary, until "
598 "the end-of-file is reached. Return either "
599 "a new bytevector containing the data read or the "
600 "end-of-file object (if no data were available).")
601 #define FUNC_NAME s_scm_r6rs_get_bytevector_all
605 unsigned c_len
, c_count
;
606 size_t c_read
, c_total
;
608 SCM_VALIDATE_R6RS_BINARY_INPUT_PORT (1, port
);
610 c_len
= c_count
= 4096;
611 c_bv
= (char *) scm_gc_malloc (c_len
, SCM_GC_BYTEVECTOR
);
612 c_total
= c_read
= 0;
616 if (c_total
+ c_read
> c_len
)
618 /* Grow the bytevector. */
619 c_bv
= (char *) scm_gc_realloc (c_bv
, c_len
, c_len
* 2,
625 /* `scm_c_read ()' blocks until C_COUNT bytes are available or EOF is
627 c_read
= scm_c_read (port
, c_bv
+ c_total
, c_count
);
628 c_total
+= c_read
, c_count
-= c_read
;
630 while (!SCM_EOF_OBJECT_P (scm_peek_char (port
)));
634 result
= SCM_EOF_VAL
;
635 scm_gc_free (c_bv
, c_len
, SCM_GC_BYTEVECTOR
);
641 /* Shrink the bytevector. */
642 c_bv
= (char *) scm_gc_realloc (c_bv
, c_len
, c_total
,
644 c_len
= (unsigned) c_total
;
647 result
= scm_r6rs_c_take_bytevector ((signed char *) c_bv
, c_len
);
658 /* We currently don't support specific binary input ports. */
659 #define SCM_VALIDATE_R6RS_BINARY_OUTPUT_PORT SCM_VALIDATE_OUTPUT_PORT
662 SCM_DEFINE (scm_r6rs_put_u8
, "put-u8", 2, 0, 0,
663 (SCM port
, SCM octet
),
664 "Write @var{octet} to binary port @var{port}.")
665 #define FUNC_NAME s_scm_r6rs_put_u8
669 SCM_VALIDATE_R6RS_BINARY_OUTPUT_PORT (1, port
);
670 c_octet
= scm_to_uint8 (octet
);
672 scm_putc ((char) c_octet
, port
);
674 return SCM_UNSPECIFIED
;
678 SCM_DEFINE (scm_r6rs_put_bytevector
, "put-bytevector", 2, 2, 0,
679 (SCM port
, SCM bv
, SCM start
, SCM count
),
680 "Write the contents of @var{bv} to @var{port}, optionally "
681 "starting at index @var{start} and limiting to @var{count} "
683 #define FUNC_NAME s_scm_r6rs_put_bytevector
686 unsigned c_start
, c_count
, c_len
;
688 SCM_VALIDATE_R6RS_BINARY_OUTPUT_PORT (1, port
);
689 SCM_VALIDATE_R6RS_BYTEVECTOR (2, bv
);
691 c_len
= SCM_R6RS_BYTEVECTOR_LENGTH (bv
);
692 c_bv
= (char *) SCM_R6RS_BYTEVECTOR_CONTENTS (bv
);
694 if (start
!= SCM_UNDEFINED
)
696 c_start
= scm_to_uint (start
);
698 if (count
!= SCM_UNDEFINED
)
700 c_count
= scm_to_uint (count
);
701 if (EXPECT_FALSE (c_start
+ c_count
> c_len
))
702 scm_out_of_range (FUNC_NAME
, count
);
706 if (EXPECT_FALSE (c_start
>= c_len
))
707 scm_out_of_range (FUNC_NAME
, start
);
709 c_count
= c_len
- c_start
;
713 c_start
= 0, c_count
= c_len
;
715 scm_c_write (port
, c_bv
+ c_start
, c_count
);
717 return SCM_UNSPECIFIED
;
723 /* Bytevector output port ("bop" for short). */
725 /* Implementation of "bops".
727 Each bop has an internal buffer, of type `scm_t_bop_buffer', attached to
728 it. The procedure returned along with the output port is actually an
729 applicable SMOB. The SMOB holds a reference to the port. When applied,
730 the SMOB swallows the port's internal buffer, turning it into a
731 bytevector, and resets it.
733 XXX: Access to a bop's internal buffer is not thread-safe. */
735 static scm_t_bits bytevector_output_port_type
= 0;
737 SCM_SMOB (bytevector_output_port_procedure
,
738 "r6rs-bytevector-output-port-procedure",
741 #define SCM_GC_BOP "r6rs-bytevector-output-port"
742 #define SCM_BOP_BUFFER_INITIAL_SIZE 4096
744 /* Representation of a bop's internal buffer. */
754 /* Accessing a bop's buffer. */
755 #define SCM_R6RS_BOP_BUFFER(_port) \
756 ((scm_t_bop_buffer *) SCM_STREAM (_port))
757 #define SCM_R6RS_SET_BOP_BUFFER(_port, _buf) \
758 (SCM_SETSTREAM ((_port), (scm_t_bits) (_buf)))
762 bop_buffer_init (scm_t_bop_buffer
*buf
)
764 buf
->total_len
= buf
->len
= buf
->pos
= 0;
769 bop_buffer_grow (scm_t_bop_buffer
*buf
)
773 new_buf
= scm_gc_realloc ((void *) buf
->buffer
, buf
->total_len
,
776 buf
->buffer
= new_buf
;
785 scm_t_bop_buffer
*buf
;
786 const unsigned long mode_bits
= SCM_OPN
| SCM_WRTNG
| SCM_BUF0
;
788 port
= scm_new_port_table_entry (bytevector_output_port_type
);
790 buf
= (scm_t_bop_buffer
*) scm_gc_malloc (sizeof (* buf
), SCM_GC_BOP
);
791 bop_buffer_init (buf
);
793 c_port
= SCM_PTAB_ENTRY (port
);
794 c_port
->write_buf
= c_port
->write_pos
= c_port
->write_end
= NULL
;
796 SCM_R6RS_SET_BOP_BUFFER (port
, buf
);
798 /* Mark PORT as open and writable. */
799 SCM_SET_CELL_TYPE (port
, bytevector_output_port_type
| mode_bits
);
801 /* Make the bop procedure. */
802 SCM_NEWSMOB (bop_proc
, bytevector_output_port_procedure
,
805 return (scm_values (scm_list_2 (port
, bop_proc
)));
811 /* The port itself is necessarily freed _after_ the bop proc, since the bop
812 proc holds a reference to it. Thus we can safely free the internal
813 buffer when the bop becomes unreferenced. */
814 scm_t_bop_buffer
*buf
;
816 buf
= SCM_R6RS_BOP_BUFFER (port
);
818 scm_gc_free (buf
->buffer
, buf
->total_len
, SCM_GC_BOP
);
820 scm_gc_free (buf
, sizeof (* buf
), SCM_GC_BOP
);
825 /* Write SIZE octets from DATA to PORT. */
827 bop_write (SCM port
, const void *data
, size_t size
)
829 scm_t_bop_buffer
*buf
;
831 buf
= SCM_R6RS_BOP_BUFFER (port
);
833 while (buf
->pos
+ size
> buf
->total_len
)
835 /* The buffer must be grown. */
836 if (buf
->total_len
== 0)
838 buf
->buffer
= scm_gc_malloc (SCM_BOP_BUFFER_INITIAL_SIZE
,
840 buf
->total_len
= SCM_BOP_BUFFER_INITIAL_SIZE
;
843 bop_buffer_grow (buf
);
846 memcpy (buf
->buffer
+ buf
->pos
, data
, size
);
848 buf
->len
= (buf
->len
> buf
->pos
) ? buf
->len
: buf
->pos
;
852 bop_seek (SCM port
, off_t offset
, int whence
)
853 #define FUNC_NAME "bop_seek"
855 scm_t_bop_buffer
*buf
;
857 buf
= SCM_R6RS_BOP_BUFFER (port
);
861 offset
+= (off_t
) buf
->pos
;
865 if (offset
> buf
->len
)
866 scm_out_of_range (FUNC_NAME
, scm_from_int (offset
));
872 if (offset
>= buf
->len
)
873 scm_out_of_range (FUNC_NAME
, scm_from_int (offset
));
875 buf
->pos
= buf
->len
- offset
;
879 scm_wrong_type_arg_msg (FUNC_NAME
, 0, port
,
880 "invalid `seek' parameter");
887 /* Fetch data from a bop. */
888 SCM_SMOB_APPLY (bytevector_output_port_procedure
,
889 bop_proc_apply
, 0, 0, 0, (SCM bop_proc
))
892 scm_t_bop_buffer
*buf
, result_buf
;
894 port
= SCM_PACK (SCM_SMOB_DATA (bop_proc
));
895 buf
= SCM_R6RS_BOP_BUFFER (port
);
898 bop_buffer_init (buf
);
900 if (result_buf
.len
== 0)
901 bv
= scm_r6rs_c_take_bytevector (NULL
, 0);
904 if (result_buf
.total_len
> result_buf
.len
)
905 /* Shrink the buffer. */
906 result_buf
.buffer
= scm_gc_realloc ((void *) result_buf
.buffer
,
907 result_buf
.total_len
,
911 bv
= scm_r6rs_c_take_bytevector ((signed char *) result_buf
.buffer
,
918 SCM_SMOB_MARK (bytevector_output_port_procedure
, bop_proc_mark
,
921 /* Mark the port associated to BOP_PROC. */
922 return (SCM_PACK (SCM_SMOB_DATA (bop_proc
)));
926 SCM_DEFINE (scm_r6rs_open_bytevector_output_port
,
927 "open-bytevector-output-port", 0, 1, 0,
929 "Return two values: an output port and a procedure. The latter "
930 "should be called with zero arguments to obtain a bytevector "
931 "containing the data accumulated by the port.")
932 #define FUNC_NAME scm_r6rs_open_bytevector_output_port
934 if (transcoder
!= SCM_UNDEFINED
)
935 transcoders_not_implemented ();
937 return (make_bop ());
942 initialize_bytevector_output_ports (void)
944 bytevector_output_port_type
=
945 scm_make_port_type ("r6rs-bytevector-output-port",
948 scm_set_port_seek (bytevector_output_port_type
, bop_seek
);
949 scm_set_port_free (bytevector_output_port_type
, bop_free
);
954 /* Initialization. */
957 scm_init_r6rs_ports (void)
961 initialize_bytevector_input_ports ();
962 initialize_custom_binary_input_ports ();
963 initialize_bytevector_output_ports ();
966 /* arch-tag: c041ffd6-8871-40e8-a25a-d0f8768a71dc