1 /* Copyright (C) 2009 Free Software Foundation, Inc.
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.
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.
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
31 #include "libguile/_scm.h"
32 #include "libguile/bytevectors.h"
33 #include "libguile/chars.h"
34 #include "libguile/eval.h"
35 #include "libguile/r6rs-ports.h"
36 #include "libguile/strings.h"
37 #include "libguile/validate.h"
38 #include "libguile/values.h"
39 #include "libguile/vectors.h"
43 /* Unimplemented features. */
46 /* Transoders are currently not implemented since Guile 1.8 is not
47 Unicode-capable. Thus, most of the code here assumes the use of the
50 transcoders_not_implemented (void)
52 fprintf (stderr
, "%s: warning: transcoders not implemented\n",
57 /* End-of-file object. */
59 SCM_DEFINE (scm_eof_object
, "eof-object", 0, 0, 0,
61 "Return the end-of-file object.")
62 #define FUNC_NAME s_scm_eof_object
72 # define MIN(a,b) ((a) < (b) ? (a) : (b))
75 /* Bytevector input ports or "bip" for short. */
76 static scm_t_bits bytevector_input_port_type
= 0;
85 const unsigned long mode_bits
= SCM_OPN
| SCM_RDNG
;
87 port
= scm_new_port_table_entry (bytevector_input_port_type
);
89 /* Prevent BV from being GC'd. */
90 SCM_SETSTREAM (port
, SCM_UNPACK (bv
));
92 /* Have the port directly access the bytevector. */
93 c_bv
= (char *) SCM_BYTEVECTOR_CONTENTS (bv
);
94 c_len
= SCM_BYTEVECTOR_LENGTH (bv
);
96 c_port
= SCM_PTAB_ENTRY (port
);
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
;
101 /* Mark PORT as open, readable and unbuffered (hmm, how elegant...). */
102 SCM_SET_CELL_TYPE (port
, bytevector_input_port_type
| mode_bits
);
110 /* Mark the underlying bytevector. */
111 return (SCM_PACK (SCM_STREAM (port
)));
115 bip_fill_input (SCM port
)
118 scm_t_port
*c_port
= SCM_PTAB_ENTRY (port
);
120 if (c_port
->read_pos
>= c_port
->read_end
)
123 result
= (int) *c_port
->read_pos
;
129 bip_seek (SCM port
, scm_t_off offset
, int whence
)
130 #define FUNC_NAME "bip_seek"
132 scm_t_off c_result
= 0;
133 scm_t_port
*c_port
= SCM_PTAB_ENTRY (port
);
138 offset
+= c_port
->read_pos
- c_port
->read_buf
;
142 if (c_port
->read_buf
+ offset
< c_port
->read_end
)
144 c_port
->read_pos
= c_port
->read_buf
+ offset
;
148 scm_out_of_range (FUNC_NAME
, scm_from_int (offset
));
152 if (c_port
->read_end
- offset
>= c_port
->read_buf
)
154 c_port
->read_pos
= c_port
->read_end
- offset
;
155 c_result
= c_port
->read_pos
- c_port
->read_buf
;
158 scm_out_of_range (FUNC_NAME
, scm_from_int (offset
));
162 scm_wrong_type_arg_msg (FUNC_NAME
, 0, port
,
163 "invalid `seek' parameter");
171 /* Instantiate the bytevector input port type. */
173 initialize_bytevector_input_ports (void)
175 bytevector_input_port_type
=
176 scm_make_port_type ("r6rs-bytevector-input-port", bip_fill_input
,
179 scm_set_port_mark (bytevector_input_port_type
, bip_mark
);
180 scm_set_port_seek (bytevector_input_port_type
, bip_seek
);
184 SCM_DEFINE (scm_open_bytevector_input_port
,
185 "open-bytevector-input-port", 1, 1, 0,
186 (SCM bv
, SCM transcoder
),
187 "Return an input port whose contents are drawn from "
188 "bytevector @var{bv}.")
189 #define FUNC_NAME s_scm_open_bytevector_input_port
191 SCM_VALIDATE_BYTEVECTOR (1, bv
);
192 if (!SCM_UNBNDP (transcoder
) && !scm_is_false (transcoder
))
193 transcoders_not_implemented ();
195 return (make_bip (bv
));
200 /* Custom binary ports. The following routines are shared by input and
201 output custom binary ports. */
203 #define SCM_CBP_GET_POSITION_PROC(_port) \
204 SCM_SIMPLE_VECTOR_REF (SCM_PACK (SCM_STREAM (_port)), 1)
205 #define SCM_CBP_SET_POSITION_PROC(_port) \
206 SCM_SIMPLE_VECTOR_REF (SCM_PACK (SCM_STREAM (_port)), 2)
207 #define SCM_CBP_CLOSE_PROC(_port) \
208 SCM_SIMPLE_VECTOR_REF (SCM_PACK (SCM_STREAM (_port)), 3)
213 /* Mark the underlying method and object vector. */
214 if (SCM_OPENP (port
))
215 return SCM_PACK (SCM_STREAM (port
));
221 cbp_seek (SCM port
, scm_t_off offset
, int whence
)
222 #define FUNC_NAME "cbp_seek"
225 scm_t_off c_result
= 0;
231 SCM get_position_proc
;
233 get_position_proc
= SCM_CBP_GET_POSITION_PROC (port
);
234 if (SCM_LIKELY (scm_is_true (get_position_proc
)))
235 result
= scm_call_0 (get_position_proc
);
237 scm_wrong_type_arg_msg (FUNC_NAME
, 0, port
,
238 "R6RS custom binary port does not "
239 "support `port-position'");
241 offset
+= scm_to_int (result
);
247 SCM set_position_proc
;
249 set_position_proc
= SCM_CBP_SET_POSITION_PROC (port
);
250 if (SCM_LIKELY (scm_is_true (set_position_proc
)))
251 result
= scm_call_1 (set_position_proc
, scm_from_int (offset
));
253 scm_wrong_type_arg_msg (FUNC_NAME
, 0, port
,
254 "R6RS custom binary port does not "
255 "support `set-port-position!'");
257 /* Assuming setting the position succeeded. */
263 /* `SEEK_END' cannot be supported. */
264 scm_wrong_type_arg_msg (FUNC_NAME
, 0, port
,
265 "R6RS custom binary ports do not "
266 "support `SEEK_END'");
278 close_proc
= SCM_CBP_CLOSE_PROC (port
);
279 if (scm_is_true (close_proc
))
280 /* Invoke the `close' thunk. */
281 scm_call_0 (close_proc
);
287 /* Custom binary input port ("cbip" for short). */
289 static scm_t_bits custom_binary_input_port_type
= 0;
291 /* Size of the buffer embedded in custom binary input ports. */
292 #define CBIP_BUFFER_SIZE 4096
294 /* Return the bytevector associated with PORT. */
295 #define SCM_CBIP_BYTEVECTOR(_port) \
296 SCM_SIMPLE_VECTOR_REF (SCM_PACK (SCM_STREAM (_port)), 4)
298 /* Return the various procedures of PORT. */
299 #define SCM_CBIP_READ_PROC(_port) \
300 SCM_SIMPLE_VECTOR_REF (SCM_PACK (SCM_STREAM (_port)), 0)
304 make_cbip (SCM read_proc
, SCM get_position_proc
,
305 SCM set_position_proc
, SCM close_proc
)
307 SCM port
, bv
, method_vector
;
311 const unsigned long mode_bits
= SCM_OPN
| SCM_RDNG
;
313 /* Use a bytevector as the underlying buffer. */
314 c_len
= CBIP_BUFFER_SIZE
;
315 bv
= scm_c_make_bytevector (c_len
);
316 c_bv
= (char *) SCM_BYTEVECTOR_CONTENTS (bv
);
318 /* Store the various methods and bytevector in a vector. */
319 method_vector
= scm_c_make_vector (5, SCM_BOOL_F
);
320 SCM_SIMPLE_VECTOR_SET (method_vector
, 4, bv
);
321 SCM_SIMPLE_VECTOR_SET (method_vector
, 0, read_proc
);
322 SCM_SIMPLE_VECTOR_SET (method_vector
, 1, get_position_proc
);
323 SCM_SIMPLE_VECTOR_SET (method_vector
, 2, set_position_proc
);
324 SCM_SIMPLE_VECTOR_SET (method_vector
, 3, close_proc
);
326 port
= scm_new_port_table_entry (custom_binary_input_port_type
);
328 /* Attach it the method vector. */
329 SCM_SETSTREAM (port
, SCM_UNPACK (method_vector
));
331 /* Have the port directly access the buffer (bytevector). */
332 c_port
= SCM_PTAB_ENTRY (port
);
333 c_port
->read_pos
= c_port
->read_buf
= (unsigned char *) c_bv
;
334 c_port
->read_end
= (unsigned char *) c_bv
;
335 c_port
->read_buf_size
= c_len
;
337 /* Mark PORT as open, readable and unbuffered (hmm, how elegant...). */
338 SCM_SET_CELL_TYPE (port
, custom_binary_input_port_type
| mode_bits
);
344 cbip_fill_input (SCM port
)
345 #define FUNC_NAME "cbip_fill_input"
348 scm_t_port
*c_port
= SCM_PTAB_ENTRY (port
);
351 if (c_port
->read_pos
>= c_port
->read_end
)
353 /* Invoke the user's `read!' procedure. */
355 SCM bv
, read_proc
, octets
;
357 /* Use the bytevector associated with PORT as the buffer passed to the
358 `read!' procedure, thereby avoiding additional allocations. */
359 bv
= SCM_CBIP_BYTEVECTOR (port
);
360 read_proc
= SCM_CBIP_READ_PROC (port
);
362 /* The assumption here is that C_PORT's internal buffer wasn't changed
364 assert (c_port
->read_buf
==
365 (unsigned char *) SCM_BYTEVECTOR_CONTENTS (bv
));
366 assert ((unsigned) c_port
->read_buf_size
367 == SCM_BYTEVECTOR_LENGTH (bv
));
369 octets
= scm_call_3 (read_proc
, bv
, SCM_INUM0
,
370 SCM_I_MAKINUM (CBIP_BUFFER_SIZE
));
371 c_octets
= scm_to_uint (octets
);
373 c_port
->read_pos
= (unsigned char *) SCM_BYTEVECTOR_CONTENTS (bv
);
374 c_port
->read_end
= (unsigned char *) c_port
->read_pos
+ c_octets
;
382 result
= (int) *c_port
->read_pos
;
389 SCM_DEFINE (scm_make_custom_binary_input_port
,
390 "make-custom-binary-input-port", 5, 0, 0,
391 (SCM id
, SCM read_proc
, SCM get_position_proc
,
392 SCM set_position_proc
, SCM close_proc
),
393 "Return a new custom binary input port whose input is drained "
394 "by invoking @var{read_proc} and passing it a bytevector, an "
395 "index where octets should be written, and an octet count.")
396 #define FUNC_NAME s_scm_make_custom_binary_input_port
398 SCM_VALIDATE_STRING (1, id
);
399 SCM_VALIDATE_PROC (2, read_proc
);
401 if (!scm_is_false (get_position_proc
))
402 SCM_VALIDATE_PROC (3, get_position_proc
);
404 if (!scm_is_false (set_position_proc
))
405 SCM_VALIDATE_PROC (4, set_position_proc
);
407 if (!scm_is_false (close_proc
))
408 SCM_VALIDATE_PROC (5, close_proc
);
410 return (make_cbip (read_proc
, get_position_proc
, set_position_proc
,
416 /* Instantiate the custom binary input port type. */
418 initialize_custom_binary_input_ports (void)
420 custom_binary_input_port_type
=
421 scm_make_port_type ("r6rs-custom-binary-input-port",
422 cbip_fill_input
, NULL
);
424 scm_set_port_mark (custom_binary_input_port_type
, cbp_mark
);
425 scm_set_port_seek (custom_binary_input_port_type
, cbp_seek
);
426 scm_set_port_close (custom_binary_input_port_type
, cbp_close
);
433 /* We currently don't support specific binary input ports. */
434 #define SCM_VALIDATE_BINARY_INPUT_PORT SCM_VALIDATE_OPINPORT
436 SCM_DEFINE (scm_get_u8
, "get-u8", 1, 0, 0,
438 "Read an octet from @var{port}, a binary input port, "
439 "blocking as necessary.")
440 #define FUNC_NAME s_scm_get_u8
445 SCM_VALIDATE_BINARY_INPUT_PORT (1, port
);
447 c_result
= scm_getc (port
);
449 result
= SCM_EOF_VAL
;
451 result
= SCM_I_MAKINUM ((unsigned char) c_result
);
457 SCM_DEFINE (scm_lookahead_u8
, "lookahead-u8", 1, 0, 0,
459 "Like @code{get-u8} but does not update @var{port} to "
460 "point past the octet.")
461 #define FUNC_NAME s_scm_lookahead_u8
465 SCM_VALIDATE_BINARY_INPUT_PORT (1, port
);
467 result
= scm_peek_char (port
);
468 if (SCM_CHARP (result
))
469 result
= SCM_I_MAKINUM ((signed char) SCM_CHAR (result
));
471 result
= SCM_EOF_VAL
;
477 SCM_DEFINE (scm_get_bytevector_n
, "get-bytevector-n", 2, 0, 0,
478 (SCM port
, SCM count
),
479 "Read @var{count} octets from @var{port}, blocking as "
480 "necessary and return a bytevector containing the octets "
481 "read. If fewer bytes are available, a bytevector smaller "
482 "than @var{count} is returned.")
483 #define FUNC_NAME s_scm_get_bytevector_n
490 SCM_VALIDATE_BINARY_INPUT_PORT (1, port
);
491 c_count
= scm_to_uint (count
);
493 result
= scm_c_make_bytevector (c_count
);
494 c_bv
= (char *) SCM_BYTEVECTOR_CONTENTS (result
);
496 if (SCM_LIKELY (c_count
> 0))
497 /* XXX: `scm_c_read ()' does not update the port position. */
498 c_read
= scm_c_read (port
, c_bv
, c_count
);
500 /* Don't invoke `scm_c_read ()' since it may block. */
503 if ((c_read
== 0) && (c_count
> 0))
505 if (SCM_EOF_OBJECT_P (scm_peek_char (port
)))
506 result
= SCM_EOF_VAL
;
508 result
= scm_null_bytevector
;
512 if (c_read
< c_count
)
513 result
= scm_c_shrink_bytevector (result
, c_read
);
520 SCM_DEFINE (scm_get_bytevector_n_x
, "get-bytevector-n!", 4, 0, 0,
521 (SCM port
, SCM bv
, SCM start
, SCM count
),
522 "Read @var{count} bytes from @var{port} and store them "
523 "in @var{bv} starting at index @var{start}. Return either "
524 "the number of bytes actually read or the end-of-file "
526 #define FUNC_NAME s_scm_get_bytevector_n_x
530 unsigned c_start
, c_count
, c_len
;
533 SCM_VALIDATE_BINARY_INPUT_PORT (1, port
);
534 SCM_VALIDATE_BYTEVECTOR (2, bv
);
535 c_start
= scm_to_uint (start
);
536 c_count
= scm_to_uint (count
);
538 c_bv
= (char *) SCM_BYTEVECTOR_CONTENTS (bv
);
539 c_len
= SCM_BYTEVECTOR_LENGTH (bv
);
541 if (SCM_UNLIKELY (c_start
+ c_count
> c_len
))
542 scm_out_of_range (FUNC_NAME
, count
);
544 if (SCM_LIKELY (c_count
> 0))
545 c_read
= scm_c_read (port
, c_bv
+ c_start
, c_count
);
547 /* Don't invoke `scm_c_read ()' since it may block. */
550 if ((c_read
== 0) && (c_count
> 0))
552 if (SCM_EOF_OBJECT_P (scm_peek_char (port
)))
553 result
= SCM_EOF_VAL
;
555 result
= SCM_I_MAKINUM (0);
558 result
= scm_from_size_t (c_read
);
565 SCM_DEFINE (scm_get_bytevector_some
, "get-bytevector-some", 1, 0, 0,
567 "Read from @var{port}, blocking as necessary, until data "
568 "are available or and end-of-file is reached. Return either "
569 "a new bytevector containing the data read or the "
570 "end-of-file object.")
571 #define FUNC_NAME s_scm_get_bytevector_some
573 /* Read at least one byte, unless the end-of-file is already reached, and
574 read while characters are available (buffered). */
581 SCM_VALIDATE_BINARY_INPUT_PORT (1, port
);
584 c_bv
= (char *) scm_gc_malloc (c_len
, SCM_GC_BYTEVECTOR
);
591 if (c_total
+ 1 > c_len
)
593 /* Grow the bytevector. */
594 c_bv
= (char *) scm_gc_realloc (c_bv
, c_len
, c_len
* 2,
599 /* We can't use `scm_c_read ()' since it blocks. */
600 c_chr
= scm_getc (port
);
603 c_bv
[c_total
] = (char) c_chr
;
607 while ((scm_is_true (scm_char_ready_p (port
)))
608 && (!SCM_EOF_OBJECT_P (scm_peek_char (port
))));
612 result
= SCM_EOF_VAL
;
613 scm_gc_free (c_bv
, c_len
, SCM_GC_BYTEVECTOR
);
619 /* Shrink the bytevector. */
620 c_bv
= (char *) scm_gc_realloc (c_bv
, c_len
, c_total
,
622 c_len
= (unsigned) c_total
;
625 result
= scm_c_take_bytevector ((signed char *) c_bv
, c_len
);
632 SCM_DEFINE (scm_get_bytevector_all
, "get-bytevector-all", 1, 0, 0,
634 "Read from @var{port}, blocking as necessary, until "
635 "the end-of-file is reached. Return either "
636 "a new bytevector containing the data read or the "
637 "end-of-file object (if no data were available).")
638 #define FUNC_NAME s_scm_get_bytevector_all
642 unsigned c_len
, c_count
;
643 size_t c_read
, c_total
;
645 SCM_VALIDATE_BINARY_INPUT_PORT (1, port
);
647 c_len
= c_count
= 4096;
648 c_bv
= (char *) scm_gc_malloc (c_len
, SCM_GC_BYTEVECTOR
);
649 c_total
= c_read
= 0;
653 if (c_total
+ c_read
> c_len
)
655 /* Grow the bytevector. */
656 c_bv
= (char *) scm_gc_realloc (c_bv
, c_len
, c_len
* 2,
662 /* `scm_c_read ()' blocks until C_COUNT bytes are available or EOF is
664 c_read
= scm_c_read (port
, c_bv
+ c_total
, c_count
);
665 c_total
+= c_read
, c_count
-= c_read
;
667 while (!SCM_EOF_OBJECT_P (scm_peek_char (port
)));
671 result
= SCM_EOF_VAL
;
672 scm_gc_free (c_bv
, c_len
, SCM_GC_BYTEVECTOR
);
678 /* Shrink the bytevector. */
679 c_bv
= (char *) scm_gc_realloc (c_bv
, c_len
, c_total
,
681 c_len
= (unsigned) c_total
;
684 result
= scm_c_take_bytevector ((signed char *) c_bv
, c_len
);
695 /* We currently don't support specific binary input ports. */
696 #define SCM_VALIDATE_BINARY_OUTPUT_PORT SCM_VALIDATE_OPOUTPORT
699 SCM_DEFINE (scm_put_u8
, "put-u8", 2, 0, 0,
700 (SCM port
, SCM octet
),
701 "Write @var{octet} to binary port @var{port}.")
702 #define FUNC_NAME s_scm_put_u8
706 SCM_VALIDATE_BINARY_OUTPUT_PORT (1, port
);
707 c_octet
= scm_to_uint8 (octet
);
709 scm_putc ((char) c_octet
, port
);
711 return SCM_UNSPECIFIED
;
715 SCM_DEFINE (scm_put_bytevector
, "put-bytevector", 2, 2, 0,
716 (SCM port
, SCM bv
, SCM start
, SCM count
),
717 "Write the contents of @var{bv} to @var{port}, optionally "
718 "starting at index @var{start} and limiting to @var{count} "
720 #define FUNC_NAME s_scm_put_bytevector
723 unsigned c_start
, c_count
, c_len
;
725 SCM_VALIDATE_BINARY_OUTPUT_PORT (1, port
);
726 SCM_VALIDATE_BYTEVECTOR (2, bv
);
728 c_len
= SCM_BYTEVECTOR_LENGTH (bv
);
729 c_bv
= (char *) SCM_BYTEVECTOR_CONTENTS (bv
);
731 if (start
!= SCM_UNDEFINED
)
733 c_start
= scm_to_uint (start
);
735 if (count
!= SCM_UNDEFINED
)
737 c_count
= scm_to_uint (count
);
738 if (SCM_UNLIKELY (c_start
+ c_count
> c_len
))
739 scm_out_of_range (FUNC_NAME
, count
);
743 if (SCM_UNLIKELY (c_start
>= c_len
))
744 scm_out_of_range (FUNC_NAME
, start
);
746 c_count
= c_len
- c_start
;
750 c_start
= 0, c_count
= c_len
;
752 scm_c_write (port
, c_bv
+ c_start
, c_count
);
754 return SCM_UNSPECIFIED
;
760 /* Bytevector output port ("bop" for short). */
762 /* Implementation of "bops".
764 Each bop has an internal buffer, of type `scm_t_bop_buffer', attached to
765 it. The procedure returned along with the output port is actually an
766 applicable SMOB. The SMOB holds a reference to the port. When applied,
767 the SMOB swallows the port's internal buffer, turning it into a
768 bytevector, and resets it.
770 XXX: Access to a bop's internal buffer is not thread-safe. */
772 static scm_t_bits bytevector_output_port_type
= 0;
774 SCM_SMOB (bytevector_output_port_procedure
,
775 "r6rs-bytevector-output-port-procedure",
778 #define SCM_GC_BOP "r6rs-bytevector-output-port"
779 #define SCM_BOP_BUFFER_INITIAL_SIZE 4096
781 /* Representation of a bop's internal buffer. */
791 /* Accessing a bop's buffer. */
792 #define SCM_BOP_BUFFER(_port) \
793 ((scm_t_bop_buffer *) SCM_STREAM (_port))
794 #define SCM_SET_BOP_BUFFER(_port, _buf) \
795 (SCM_SETSTREAM ((_port), (scm_t_bits) (_buf)))
799 bop_buffer_init (scm_t_bop_buffer
*buf
)
801 buf
->total_len
= buf
->len
= buf
->pos
= 0;
806 bop_buffer_grow (scm_t_bop_buffer
*buf
, size_t min_size
)
811 for (new_size
= buf
->total_len
812 ? buf
->total_len
: SCM_BOP_BUFFER_INITIAL_SIZE
;
817 new_buf
= scm_gc_realloc ((void *) buf
->buffer
, buf
->total_len
,
818 new_size
, SCM_GC_BOP
);
820 new_buf
= scm_gc_malloc (new_size
, SCM_GC_BOP
);
822 buf
->buffer
= new_buf
;
823 buf
->total_len
= new_size
;
831 scm_t_bop_buffer
*buf
;
832 const unsigned long mode_bits
= SCM_OPN
| SCM_WRTNG
;
834 port
= scm_new_port_table_entry (bytevector_output_port_type
);
836 buf
= (scm_t_bop_buffer
*) scm_gc_malloc (sizeof (* buf
), SCM_GC_BOP
);
837 bop_buffer_init (buf
);
839 c_port
= SCM_PTAB_ENTRY (port
);
840 c_port
->write_buf
= c_port
->write_pos
= c_port
->write_end
= NULL
;
841 c_port
->write_buf_size
= 0;
843 SCM_SET_BOP_BUFFER (port
, buf
);
845 /* Mark PORT as open and writable. */
846 SCM_SET_CELL_TYPE (port
, bytevector_output_port_type
| mode_bits
);
848 /* Make the bop procedure. */
849 SCM_NEWSMOB (bop_proc
, bytevector_output_port_procedure
,
852 return (scm_values (scm_list_2 (port
, bop_proc
)));
858 /* The port itself is necessarily freed _after_ the bop proc, since the bop
859 proc holds a reference to it. Thus we can safely free the internal
860 buffer when the bop becomes unreferenced. */
861 scm_t_bop_buffer
*buf
;
863 buf
= SCM_BOP_BUFFER (port
);
865 scm_gc_free (buf
->buffer
, buf
->total_len
, SCM_GC_BOP
);
867 scm_gc_free (buf
, sizeof (* buf
), SCM_GC_BOP
);
872 /* Write SIZE octets from DATA to PORT. */
874 bop_write (SCM port
, const void *data
, size_t size
)
876 scm_t_bop_buffer
*buf
;
878 buf
= SCM_BOP_BUFFER (port
);
880 if (buf
->pos
+ size
> buf
->total_len
)
881 bop_buffer_grow (buf
, buf
->pos
+ size
);
883 memcpy (buf
->buffer
+ buf
->pos
, data
, size
);
885 buf
->len
= (buf
->len
> buf
->pos
) ? buf
->len
: buf
->pos
;
889 bop_seek (SCM port
, scm_t_off offset
, int whence
)
890 #define FUNC_NAME "bop_seek"
892 scm_t_bop_buffer
*buf
;
894 buf
= SCM_BOP_BUFFER (port
);
898 offset
+= (scm_t_off
) buf
->pos
;
902 if (offset
< 0 || (unsigned) offset
> buf
->len
)
903 scm_out_of_range (FUNC_NAME
, scm_from_int (offset
));
909 if (offset
< 0 || (unsigned) offset
>= buf
->len
)
910 scm_out_of_range (FUNC_NAME
, scm_from_int (offset
));
912 buf
->pos
= buf
->len
- (offset
+ 1);
916 scm_wrong_type_arg_msg (FUNC_NAME
, 0, port
,
917 "invalid `seek' parameter");
924 /* Fetch data from a bop. */
925 SCM_SMOB_APPLY (bytevector_output_port_procedure
,
926 bop_proc_apply
, 0, 0, 0, (SCM bop_proc
))
929 scm_t_bop_buffer
*buf
, result_buf
;
931 port
= SCM_PACK (SCM_SMOB_DATA (bop_proc
));
932 buf
= SCM_BOP_BUFFER (port
);
935 bop_buffer_init (buf
);
937 if (result_buf
.len
== 0)
938 bv
= scm_c_take_bytevector (NULL
, 0);
941 if (result_buf
.total_len
> result_buf
.len
)
942 /* Shrink the buffer. */
943 result_buf
.buffer
= scm_gc_realloc ((void *) result_buf
.buffer
,
944 result_buf
.total_len
,
948 bv
= scm_c_take_bytevector ((signed char *) result_buf
.buffer
,
955 SCM_SMOB_MARK (bytevector_output_port_procedure
, bop_proc_mark
,
958 /* Mark the port associated with BOP_PROC. */
959 return (SCM_PACK (SCM_SMOB_DATA (bop_proc
)));
963 SCM_DEFINE (scm_open_bytevector_output_port
,
964 "open-bytevector-output-port", 0, 1, 0,
966 "Return two values: an output port and a procedure. The latter "
967 "should be called with zero arguments to obtain a bytevector "
968 "containing the data accumulated by the port.")
969 #define FUNC_NAME s_scm_open_bytevector_output_port
971 if (!SCM_UNBNDP (transcoder
) && !scm_is_false (transcoder
))
972 transcoders_not_implemented ();
974 return (make_bop ());
979 initialize_bytevector_output_ports (void)
981 bytevector_output_port_type
=
982 scm_make_port_type ("r6rs-bytevector-output-port",
985 scm_set_port_seek (bytevector_output_port_type
, bop_seek
);
986 scm_set_port_free (bytevector_output_port_type
, bop_free
);
990 /* Custom binary output port ("cbop" for short). */
992 static scm_t_bits custom_binary_output_port_type
;
994 /* Return the various procedures of PORT. */
995 #define SCM_CBOP_WRITE_PROC(_port) \
996 SCM_SIMPLE_VECTOR_REF (SCM_PACK (SCM_STREAM (_port)), 0)
1000 make_cbop (SCM write_proc
, SCM get_position_proc
,
1001 SCM set_position_proc
, SCM close_proc
)
1003 SCM port
, method_vector
;
1005 const unsigned long mode_bits
= SCM_OPN
| SCM_WRTNG
;
1007 /* Store the various methods and bytevector in a vector. */
1008 method_vector
= scm_c_make_vector (4, SCM_BOOL_F
);
1009 SCM_SIMPLE_VECTOR_SET (method_vector
, 0, write_proc
);
1010 SCM_SIMPLE_VECTOR_SET (method_vector
, 1, get_position_proc
);
1011 SCM_SIMPLE_VECTOR_SET (method_vector
, 2, set_position_proc
);
1012 SCM_SIMPLE_VECTOR_SET (method_vector
, 3, close_proc
);
1014 port
= scm_new_port_table_entry (custom_binary_output_port_type
);
1016 /* Attach it the method vector. */
1017 SCM_SETSTREAM (port
, SCM_UNPACK (method_vector
));
1019 /* Have the port directly access the buffer (bytevector). */
1020 c_port
= SCM_PTAB_ENTRY (port
);
1021 c_port
->write_buf
= c_port
->write_pos
= c_port
->write_end
= NULL
;
1022 c_port
->write_buf_size
= c_port
->read_buf_size
= 0;
1024 /* Mark PORT as open, writable and unbuffered. */
1025 SCM_SET_CELL_TYPE (port
, custom_binary_output_port_type
| mode_bits
);
1030 /* Write SIZE octets from DATA to PORT. */
1032 cbop_write (SCM port
, const void *data
, size_t size
)
1033 #define FUNC_NAME "cbop_write"
1037 SCM bv
, write_proc
, result
;
1039 /* XXX: Allocating a new bytevector at each `write' call is inefficient,
1040 but necessary since (1) we don't control the lifetime of the buffer
1041 pointed to by DATA, and (2) the `write!' procedure could capture the
1042 bytevector it is passed. */
1043 bv
= scm_c_make_bytevector (size
);
1044 memcpy (SCM_BYTEVECTOR_CONTENTS (bv
), data
, size
);
1046 write_proc
= SCM_CBOP_WRITE_PROC (port
);
1048 /* Since the `write' procedure of Guile's ports has type `void', it must
1049 try hard to write exactly SIZE bytes, regardless of how many bytes the
1053 c_written
+= c_result
)
1055 result
= scm_call_3 (write_proc
, bv
,
1056 scm_from_size_t (c_written
),
1057 scm_from_size_t (size
- c_written
));
1059 c_result
= scm_to_long (result
);
1060 if (SCM_UNLIKELY (c_result
< 0
1061 || (size_t) c_result
> (size
- c_written
)))
1062 scm_wrong_type_arg_msg (FUNC_NAME
, 0, result
,
1063 "R6RS custom binary output port `write!' "
1064 "returned a incorrect integer");
1070 SCM_DEFINE (scm_make_custom_binary_output_port
,
1071 "make-custom-binary-output-port", 5, 0, 0,
1072 (SCM id
, SCM write_proc
, SCM get_position_proc
,
1073 SCM set_position_proc
, SCM close_proc
),
1074 "Return a new custom binary output port whose output is drained "
1075 "by invoking @var{write_proc} and passing it a bytevector, an "
1076 "index where octets should be written, and an octet count.")
1077 #define FUNC_NAME s_scm_make_custom_binary_output_port
1079 SCM_VALIDATE_STRING (1, id
);
1080 SCM_VALIDATE_PROC (2, write_proc
);
1082 if (!scm_is_false (get_position_proc
))
1083 SCM_VALIDATE_PROC (3, get_position_proc
);
1085 if (!scm_is_false (set_position_proc
))
1086 SCM_VALIDATE_PROC (4, set_position_proc
);
1088 if (!scm_is_false (close_proc
))
1089 SCM_VALIDATE_PROC (5, close_proc
);
1091 return (make_cbop (write_proc
, get_position_proc
, set_position_proc
,
1097 /* Instantiate the custom binary output port type. */
1099 initialize_custom_binary_output_ports (void)
1101 custom_binary_output_port_type
=
1102 scm_make_port_type ("r6rs-custom-binary-output-port",
1105 scm_set_port_mark (custom_binary_output_port_type
, cbp_mark
);
1106 scm_set_port_seek (custom_binary_output_port_type
, cbp_seek
);
1107 scm_set_port_close (custom_binary_output_port_type
, cbp_close
);
1111 /* Initialization. */
1114 scm_init_r6rs_ports (void)
1116 #include "libguile/r6rs-ports.x"
1118 initialize_bytevector_input_ports ();
1119 initialize_custom_binary_input_ports ();
1120 initialize_bytevector_output_ports ();
1121 initialize_custom_binary_output_ports ();