1 /* Copyright (C) 2009, 2010, 2011 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 scm_i_scm_pthread_mutex_lock (&scm_i_port_table_mutex
);
89 port
= scm_new_port_table_entry (bytevector_input_port_type
);
90 c_port
= SCM_PTAB_ENTRY (port
);
92 /* Match the expectation of `binary-port?'. */
93 c_port
->encoding
= NULL
;
95 /* Prevent BV from being GC'd. */
96 SCM_SETSTREAM (port
, SCM_UNPACK (bv
));
98 /* Have the port directly access the bytevector. */
99 c_bv
= (char *) SCM_BYTEVECTOR_CONTENTS (bv
);
100 c_len
= SCM_BYTEVECTOR_LENGTH (bv
);
102 c_port
->read_pos
= c_port
->read_buf
= (unsigned char *) c_bv
;
103 c_port
->read_end
= (unsigned char *) c_bv
+ c_len
;
104 c_port
->read_buf_size
= c_len
;
106 /* Mark PORT as open, readable and unbuffered (hmm, how elegant...). */
107 SCM_SET_CELL_TYPE (port
, bytevector_input_port_type
| mode_bits
);
109 scm_i_pthread_mutex_unlock (&scm_i_port_table_mutex
);
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_seek (bytevector_input_port_type
, bip_seek
);
183 SCM_DEFINE (scm_open_bytevector_input_port
,
184 "open-bytevector-input-port", 1, 1, 0,
185 (SCM bv
, SCM transcoder
),
186 "Return an input port whose contents are drawn from "
187 "bytevector @var{bv}.")
188 #define FUNC_NAME s_scm_open_bytevector_input_port
190 SCM_VALIDATE_BYTEVECTOR (1, bv
);
191 if (!SCM_UNBNDP (transcoder
) && !scm_is_false (transcoder
))
192 transcoders_not_implemented ();
194 return (make_bip (bv
));
199 /* Custom binary ports. The following routines are shared by input and
200 output custom binary ports. */
202 #define SCM_CBP_GET_POSITION_PROC(_port) \
203 SCM_SIMPLE_VECTOR_REF (SCM_PACK (SCM_STREAM (_port)), 1)
204 #define SCM_CBP_SET_POSITION_PROC(_port) \
205 SCM_SIMPLE_VECTOR_REF (SCM_PACK (SCM_STREAM (_port)), 2)
206 #define SCM_CBP_CLOSE_PROC(_port) \
207 SCM_SIMPLE_VECTOR_REF (SCM_PACK (SCM_STREAM (_port)), 3)
210 cbp_seek (SCM port
, scm_t_off offset
, int whence
)
211 #define FUNC_NAME "cbp_seek"
214 scm_t_off c_result
= 0;
220 SCM get_position_proc
;
222 get_position_proc
= SCM_CBP_GET_POSITION_PROC (port
);
223 if (SCM_LIKELY (scm_is_true (get_position_proc
)))
224 result
= scm_call_0 (get_position_proc
);
226 scm_wrong_type_arg_msg (FUNC_NAME
, 0, port
,
227 "R6RS custom binary port does not "
228 "support `port-position'");
230 offset
+= scm_to_int (result
);
236 SCM set_position_proc
;
238 set_position_proc
= SCM_CBP_SET_POSITION_PROC (port
);
239 if (SCM_LIKELY (scm_is_true (set_position_proc
)))
240 result
= scm_call_1 (set_position_proc
, scm_from_int (offset
));
242 scm_wrong_type_arg_msg (FUNC_NAME
, 0, port
,
243 "R6RS custom binary port does not "
244 "support `set-port-position!'");
246 /* Assuming setting the position succeeded. */
252 /* `SEEK_END' cannot be supported. */
253 scm_wrong_type_arg_msg (FUNC_NAME
, 0, port
,
254 "R6RS custom binary ports do not "
255 "support `SEEK_END'");
267 close_proc
= SCM_CBP_CLOSE_PROC (port
);
268 if (scm_is_true (close_proc
))
269 /* Invoke the `close' thunk. */
270 scm_call_0 (close_proc
);
276 /* Custom binary input port ("cbip" for short). */
278 static scm_t_bits custom_binary_input_port_type
= 0;
280 /* Size of the buffer embedded in custom binary input ports. */
281 #define CBIP_BUFFER_SIZE 4096
283 /* Return the bytevector associated with PORT. */
284 #define SCM_CBIP_BYTEVECTOR(_port) \
285 SCM_SIMPLE_VECTOR_REF (SCM_PACK (SCM_STREAM (_port)), 4)
287 /* Return the various procedures of PORT. */
288 #define SCM_CBIP_READ_PROC(_port) \
289 SCM_SIMPLE_VECTOR_REF (SCM_PACK (SCM_STREAM (_port)), 0)
293 make_cbip (SCM read_proc
, SCM get_position_proc
,
294 SCM set_position_proc
, SCM close_proc
)
296 SCM port
, bv
, method_vector
;
300 const unsigned long mode_bits
= SCM_OPN
| SCM_RDNG
;
302 /* Use a bytevector as the underlying buffer. */
303 c_len
= CBIP_BUFFER_SIZE
;
304 bv
= scm_c_make_bytevector (c_len
);
305 c_bv
= (char *) SCM_BYTEVECTOR_CONTENTS (bv
);
307 /* Store the various methods and bytevector in a vector. */
308 method_vector
= scm_c_make_vector (5, SCM_BOOL_F
);
309 SCM_SIMPLE_VECTOR_SET (method_vector
, 4, bv
);
310 SCM_SIMPLE_VECTOR_SET (method_vector
, 0, read_proc
);
311 SCM_SIMPLE_VECTOR_SET (method_vector
, 1, get_position_proc
);
312 SCM_SIMPLE_VECTOR_SET (method_vector
, 2, set_position_proc
);
313 SCM_SIMPLE_VECTOR_SET (method_vector
, 3, close_proc
);
315 scm_i_pthread_mutex_lock (&scm_i_port_table_mutex
);
317 port
= scm_new_port_table_entry (custom_binary_input_port_type
);
318 c_port
= SCM_PTAB_ENTRY (port
);
320 /* Match the expectation of `binary-port?'. */
321 c_port
->encoding
= NULL
;
323 /* Attach it the method vector. */
324 SCM_SETSTREAM (port
, SCM_UNPACK (method_vector
));
326 /* Have the port directly access the buffer (bytevector). */
327 c_port
->read_pos
= c_port
->read_buf
= (unsigned char *) c_bv
;
328 c_port
->read_end
= (unsigned char *) c_bv
;
329 c_port
->read_buf_size
= c_len
;
331 /* Mark PORT as open, readable and unbuffered (hmm, how elegant...). */
332 SCM_SET_CELL_TYPE (port
, custom_binary_input_port_type
| mode_bits
);
334 scm_i_pthread_mutex_unlock (&scm_i_port_table_mutex
);
340 cbip_fill_input (SCM port
)
341 #define FUNC_NAME "cbip_fill_input"
344 scm_t_port
*c_port
= SCM_PTAB_ENTRY (port
);
347 if (c_port
->read_pos
>= c_port
->read_end
)
349 /* Invoke the user's `read!' procedure. */
351 SCM bv
, read_proc
, octets
;
353 /* Use the bytevector associated with PORT as the buffer passed to the
354 `read!' procedure, thereby avoiding additional allocations. */
355 bv
= SCM_CBIP_BYTEVECTOR (port
);
356 read_proc
= SCM_CBIP_READ_PROC (port
);
358 /* The assumption here is that C_PORT's internal buffer wasn't changed
360 assert (c_port
->read_buf
==
361 (unsigned char *) SCM_BYTEVECTOR_CONTENTS (bv
));
362 assert ((unsigned) c_port
->read_buf_size
363 == SCM_BYTEVECTOR_LENGTH (bv
));
365 octets
= scm_call_3 (read_proc
, bv
, SCM_INUM0
,
366 SCM_I_MAKINUM (CBIP_BUFFER_SIZE
));
367 c_octets
= scm_to_uint (octets
);
369 c_port
->read_pos
= (unsigned char *) SCM_BYTEVECTOR_CONTENTS (bv
);
370 c_port
->read_end
= (unsigned char *) c_port
->read_pos
+ c_octets
;
378 result
= (int) *c_port
->read_pos
;
385 SCM_DEFINE (scm_make_custom_binary_input_port
,
386 "make-custom-binary-input-port", 5, 0, 0,
387 (SCM id
, SCM read_proc
, SCM get_position_proc
,
388 SCM set_position_proc
, SCM close_proc
),
389 "Return a new custom binary input port whose input is drained "
390 "by invoking @var{read_proc} and passing it a bytevector, an "
391 "index where octets should be written, and an octet count.")
392 #define FUNC_NAME s_scm_make_custom_binary_input_port
394 SCM_VALIDATE_STRING (1, id
);
395 SCM_VALIDATE_PROC (2, read_proc
);
397 if (!scm_is_false (get_position_proc
))
398 SCM_VALIDATE_PROC (3, get_position_proc
);
400 if (!scm_is_false (set_position_proc
))
401 SCM_VALIDATE_PROC (4, set_position_proc
);
403 if (!scm_is_false (close_proc
))
404 SCM_VALIDATE_PROC (5, close_proc
);
406 return (make_cbip (read_proc
, get_position_proc
, set_position_proc
,
412 /* Instantiate the custom binary input port type. */
414 initialize_custom_binary_input_ports (void)
416 custom_binary_input_port_type
=
417 scm_make_port_type ("r6rs-custom-binary-input-port",
418 cbip_fill_input
, NULL
);
420 scm_set_port_seek (custom_binary_input_port_type
, cbp_seek
);
421 scm_set_port_close (custom_binary_input_port_type
, cbp_close
);
428 /* We currently don't support specific binary input ports. */
429 #define SCM_VALIDATE_BINARY_INPUT_PORT SCM_VALIDATE_OPINPORT
431 SCM_DEFINE (scm_get_u8
, "get-u8", 1, 0, 0,
433 "Read an octet from @var{port}, a binary input port, "
434 "blocking as necessary.")
435 #define FUNC_NAME s_scm_get_u8
440 SCM_VALIDATE_BINARY_INPUT_PORT (1, port
);
442 c_result
= scm_get_byte_or_eof (port
);
444 result
= SCM_EOF_VAL
;
446 result
= SCM_I_MAKINUM ((unsigned char) c_result
);
452 SCM_DEFINE (scm_lookahead_u8
, "lookahead-u8", 1, 0, 0,
454 "Like @code{get-u8} but does not update @var{port} to "
455 "point past the octet.")
456 #define FUNC_NAME s_scm_lookahead_u8
461 SCM_VALIDATE_BINARY_INPUT_PORT (1, port
);
463 u8
= scm_peek_byte_or_eof (port
);
465 result
= SCM_EOF_VAL
;
467 result
= SCM_I_MAKINUM ((scm_t_uint8
) u8
);
473 SCM_DEFINE (scm_get_bytevector_n
, "get-bytevector-n", 2, 0, 0,
474 (SCM port
, SCM count
),
475 "Read @var{count} octets from @var{port}, blocking as "
476 "necessary and return a bytevector containing the octets "
477 "read. If fewer bytes are available, a bytevector smaller "
478 "than @var{count} is returned.")
479 #define FUNC_NAME s_scm_get_bytevector_n
486 SCM_VALIDATE_BINARY_INPUT_PORT (1, port
);
487 c_count
= scm_to_uint (count
);
489 result
= scm_c_make_bytevector (c_count
);
490 c_bv
= (char *) SCM_BYTEVECTOR_CONTENTS (result
);
492 if (SCM_LIKELY (c_count
> 0))
493 /* XXX: `scm_c_read ()' does not update the port position. */
494 c_read
= scm_c_read (port
, c_bv
, c_count
);
496 /* Don't invoke `scm_c_read ()' since it may block. */
499 if ((c_read
== 0) && (c_count
> 0))
501 if (SCM_EOF_OBJECT_P (scm_peek_char (port
)))
502 result
= SCM_EOF_VAL
;
504 result
= scm_null_bytevector
;
508 if (c_read
< c_count
)
509 result
= scm_c_shrink_bytevector (result
, c_read
);
516 SCM_DEFINE (scm_get_bytevector_n_x
, "get-bytevector-n!", 4, 0, 0,
517 (SCM port
, SCM bv
, SCM start
, SCM count
),
518 "Read @var{count} bytes from @var{port} and store them "
519 "in @var{bv} starting at index @var{start}. Return either "
520 "the number of bytes actually read or the end-of-file "
522 #define FUNC_NAME s_scm_get_bytevector_n_x
526 unsigned c_start
, c_count
, c_len
;
529 SCM_VALIDATE_BINARY_INPUT_PORT (1, port
);
530 SCM_VALIDATE_BYTEVECTOR (2, bv
);
531 c_start
= scm_to_uint (start
);
532 c_count
= scm_to_uint (count
);
534 c_bv
= (char *) SCM_BYTEVECTOR_CONTENTS (bv
);
535 c_len
= SCM_BYTEVECTOR_LENGTH (bv
);
537 if (SCM_UNLIKELY (c_start
+ c_count
> c_len
))
538 scm_out_of_range (FUNC_NAME
, count
);
540 if (SCM_LIKELY (c_count
> 0))
541 c_read
= scm_c_read (port
, c_bv
+ c_start
, c_count
);
543 /* Don't invoke `scm_c_read ()' since it may block. */
546 if ((c_read
== 0) && (c_count
> 0))
548 if (SCM_EOF_OBJECT_P (scm_peek_char (port
)))
549 result
= SCM_EOF_VAL
;
551 result
= SCM_I_MAKINUM (0);
554 result
= scm_from_size_t (c_read
);
561 SCM_DEFINE (scm_get_bytevector_some
, "get-bytevector-some", 1, 0, 0,
563 "Read from @var{port}, blocking as necessary, until data "
564 "are available or and end-of-file is reached. Return either "
565 "a new bytevector containing the data read or the "
566 "end-of-file object.")
567 #define FUNC_NAME s_scm_get_bytevector_some
569 /* Read at least one byte, unless the end-of-file is already reached, and
570 read while characters are available (buffered). */
577 SCM_VALIDATE_BINARY_INPUT_PORT (1, port
);
580 c_bv
= (char *) scm_gc_malloc_pointerless (c_len
, SCM_GC_BYTEVECTOR
);
587 if (c_total
+ 1 > c_len
)
589 /* Grow the bytevector. */
590 c_bv
= (char *) scm_gc_realloc (c_bv
, c_len
, c_len
* 2,
595 /* We can't use `scm_c_read ()' since it blocks. */
596 c_chr
= scm_getc (port
);
599 c_bv
[c_total
] = (char) c_chr
;
603 while ((scm_is_true (scm_char_ready_p (port
)))
604 && (!SCM_EOF_OBJECT_P (scm_peek_char (port
))));
608 result
= SCM_EOF_VAL
;
609 scm_gc_free (c_bv
, c_len
, SCM_GC_BYTEVECTOR
);
615 /* Shrink the bytevector. */
616 c_bv
= (char *) scm_gc_realloc (c_bv
, c_len
, c_total
,
618 c_len
= (unsigned) c_total
;
621 result
= scm_c_take_gc_bytevector ((signed char *) c_bv
, c_len
);
628 SCM_DEFINE (scm_get_bytevector_all
, "get-bytevector-all", 1, 0, 0,
630 "Read from @var{port}, blocking as necessary, until "
631 "the end-of-file is reached. Return either "
632 "a new bytevector containing the data read or the "
633 "end-of-file object (if no data were available).")
634 #define FUNC_NAME s_scm_get_bytevector_all
638 unsigned c_len
, c_count
;
639 size_t c_read
, c_total
;
641 SCM_VALIDATE_BINARY_INPUT_PORT (1, port
);
643 c_len
= c_count
= 4096;
644 c_bv
= (char *) scm_gc_malloc_pointerless (c_len
, SCM_GC_BYTEVECTOR
);
645 c_total
= c_read
= 0;
649 if (c_total
+ c_read
> c_len
)
651 /* Grow the bytevector. */
652 c_bv
= (char *) scm_gc_realloc (c_bv
, c_len
, c_len
* 2,
658 /* `scm_c_read ()' blocks until C_COUNT bytes are available or EOF is
660 c_read
= scm_c_read (port
, c_bv
+ c_total
, c_count
);
661 c_total
+= c_read
, c_count
-= c_read
;
663 while (!SCM_EOF_OBJECT_P (scm_peek_char (port
)));
667 result
= SCM_EOF_VAL
;
668 scm_gc_free (c_bv
, c_len
, SCM_GC_BYTEVECTOR
);
674 /* Shrink the bytevector. */
675 c_bv
= (char *) scm_gc_realloc (c_bv
, c_len
, c_total
,
677 c_len
= (unsigned) c_total
;
680 result
= scm_c_take_gc_bytevector ((signed char *) c_bv
, c_len
);
691 /* We currently don't support specific binary input ports. */
692 #define SCM_VALIDATE_BINARY_OUTPUT_PORT SCM_VALIDATE_OPOUTPORT
695 SCM_DEFINE (scm_put_u8
, "put-u8", 2, 0, 0,
696 (SCM port
, SCM octet
),
697 "Write @var{octet} to binary port @var{port}.")
698 #define FUNC_NAME s_scm_put_u8
702 SCM_VALIDATE_BINARY_OUTPUT_PORT (1, port
);
703 c_octet
= scm_to_uint8 (octet
);
705 scm_putc ((char) c_octet
, port
);
707 return SCM_UNSPECIFIED
;
711 SCM_DEFINE (scm_put_bytevector
, "put-bytevector", 2, 2, 0,
712 (SCM port
, SCM bv
, SCM start
, SCM count
),
713 "Write the contents of @var{bv} to @var{port}, optionally "
714 "starting at index @var{start} and limiting to @var{count} "
716 #define FUNC_NAME s_scm_put_bytevector
719 unsigned c_start
, c_count
, c_len
;
721 SCM_VALIDATE_BINARY_OUTPUT_PORT (1, port
);
722 SCM_VALIDATE_BYTEVECTOR (2, bv
);
724 c_len
= SCM_BYTEVECTOR_LENGTH (bv
);
725 c_bv
= (char *) SCM_BYTEVECTOR_CONTENTS (bv
);
727 if (!scm_is_eq (start
, SCM_UNDEFINED
))
729 c_start
= scm_to_uint (start
);
731 if (!scm_is_eq (count
, SCM_UNDEFINED
))
733 c_count
= scm_to_uint (count
);
734 if (SCM_UNLIKELY (c_start
+ c_count
> c_len
))
735 scm_out_of_range (FUNC_NAME
, count
);
739 if (SCM_UNLIKELY (c_start
>= c_len
))
740 scm_out_of_range (FUNC_NAME
, start
);
742 c_count
= c_len
- c_start
;
746 c_start
= 0, c_count
= c_len
;
748 scm_c_write (port
, c_bv
+ c_start
, c_count
);
750 return SCM_UNSPECIFIED
;
756 /* Bytevector output port ("bop" for short). */
758 /* Implementation of "bops".
760 Each bop has an internal buffer, of type `scm_t_bop_buffer', attached to
761 it. The procedure returned along with the output port is actually an
762 applicable SMOB. The SMOB holds a reference to the port. When applied,
763 the SMOB swallows the port's internal buffer, turning it into a
764 bytevector, and resets it.
766 XXX: Access to a bop's internal buffer is not thread-safe. */
768 static scm_t_bits bytevector_output_port_type
= 0;
770 SCM_SMOB (bytevector_output_port_procedure
,
771 "r6rs-bytevector-output-port-procedure",
774 #define SCM_GC_BOP "r6rs-bytevector-output-port"
775 #define SCM_BOP_BUFFER_INITIAL_SIZE 4096
777 /* Representation of a bop's internal buffer. */
787 /* Accessing a bop's buffer. */
788 #define SCM_BOP_BUFFER(_port) \
789 ((scm_t_bop_buffer *) SCM_STREAM (_port))
790 #define SCM_SET_BOP_BUFFER(_port, _buf) \
791 (SCM_SETSTREAM ((_port), (scm_t_bits) (_buf)))
795 bop_buffer_init (scm_t_bop_buffer
*buf
)
797 buf
->total_len
= buf
->len
= buf
->pos
= 0;
802 bop_buffer_grow (scm_t_bop_buffer
*buf
, size_t min_size
)
807 for (new_size
= buf
->total_len
808 ? buf
->total_len
: SCM_BOP_BUFFER_INITIAL_SIZE
;
813 new_buf
= scm_gc_realloc ((void *) buf
->buffer
, buf
->total_len
,
814 new_size
, SCM_GC_BOP
);
816 new_buf
= scm_gc_malloc_pointerless (new_size
, SCM_GC_BOP
);
818 buf
->buffer
= new_buf
;
819 buf
->total_len
= new_size
;
827 scm_t_bop_buffer
*buf
;
828 const unsigned long mode_bits
= SCM_OPN
| SCM_WRTNG
;
830 scm_i_pthread_mutex_lock (&scm_i_port_table_mutex
);
832 port
= scm_new_port_table_entry (bytevector_output_port_type
);
833 c_port
= SCM_PTAB_ENTRY (port
);
835 /* Match the expectation of `binary-port?'. */
836 c_port
->encoding
= NULL
;
838 buf
= (scm_t_bop_buffer
*) scm_gc_malloc (sizeof (* buf
), SCM_GC_BOP
);
839 bop_buffer_init (buf
);
841 c_port
->write_buf
= c_port
->write_pos
= c_port
->write_end
= NULL
;
842 c_port
->write_buf_size
= 0;
844 SCM_SET_BOP_BUFFER (port
, buf
);
846 /* Mark PORT as open and writable. */
847 SCM_SET_CELL_TYPE (port
, bytevector_output_port_type
| mode_bits
);
849 scm_i_pthread_mutex_unlock (&scm_i_port_table_mutex
);
851 /* Make the bop procedure. */
852 SCM_NEWSMOB (bop_proc
, bytevector_output_port_procedure
, buf
);
854 return (scm_values (scm_list_2 (port
, bop_proc
)));
857 /* Write SIZE octets from DATA to PORT. */
859 bop_write (SCM port
, const void *data
, size_t size
)
861 scm_t_bop_buffer
*buf
;
863 buf
= SCM_BOP_BUFFER (port
);
865 if (buf
->pos
+ size
> buf
->total_len
)
866 bop_buffer_grow (buf
, buf
->pos
+ size
);
868 memcpy (buf
->buffer
+ buf
->pos
, data
, size
);
870 buf
->len
= (buf
->len
> buf
->pos
) ? buf
->len
: buf
->pos
;
874 bop_seek (SCM port
, scm_t_off offset
, int whence
)
875 #define FUNC_NAME "bop_seek"
877 scm_t_bop_buffer
*buf
;
879 buf
= SCM_BOP_BUFFER (port
);
883 offset
+= (scm_t_off
) buf
->pos
;
887 if (offset
< 0 || (unsigned) offset
> buf
->len
)
888 scm_out_of_range (FUNC_NAME
, scm_from_int (offset
));
894 if (offset
< 0 || (unsigned) offset
>= buf
->len
)
895 scm_out_of_range (FUNC_NAME
, scm_from_int (offset
));
897 buf
->pos
= buf
->len
- (offset
+ 1);
901 scm_wrong_type_arg_msg (FUNC_NAME
, 0, port
,
902 "invalid `seek' parameter");
909 /* Fetch data from a bop. */
910 SCM_SMOB_APPLY (bytevector_output_port_procedure
,
911 bop_proc_apply
, 0, 0, 0, (SCM bop_proc
))
914 scm_t_bop_buffer
*buf
, result_buf
;
916 buf
= (scm_t_bop_buffer
*) SCM_SMOB_DATA (bop_proc
);
919 bop_buffer_init (buf
);
921 if (result_buf
.len
== 0)
922 bv
= scm_c_take_gc_bytevector (NULL
, 0);
925 if (result_buf
.total_len
> result_buf
.len
)
926 /* Shrink the buffer. */
927 result_buf
.buffer
= scm_gc_realloc ((void *) result_buf
.buffer
,
928 result_buf
.total_len
,
932 bv
= scm_c_take_gc_bytevector ((signed char *) result_buf
.buffer
,
939 SCM_DEFINE (scm_open_bytevector_output_port
,
940 "open-bytevector-output-port", 0, 1, 0,
942 "Return two values: an output port and a procedure. The latter "
943 "should be called with zero arguments to obtain a bytevector "
944 "containing the data accumulated by the port.")
945 #define FUNC_NAME s_scm_open_bytevector_output_port
947 if (!SCM_UNBNDP (transcoder
) && !scm_is_false (transcoder
))
948 transcoders_not_implemented ();
950 return (make_bop ());
955 initialize_bytevector_output_ports (void)
957 bytevector_output_port_type
=
958 scm_make_port_type ("r6rs-bytevector-output-port",
961 scm_set_port_seek (bytevector_output_port_type
, bop_seek
);
965 /* Custom binary output port ("cbop" for short). */
967 static scm_t_bits custom_binary_output_port_type
;
969 /* Return the various procedures of PORT. */
970 #define SCM_CBOP_WRITE_PROC(_port) \
971 SCM_SIMPLE_VECTOR_REF (SCM_PACK (SCM_STREAM (_port)), 0)
975 make_cbop (SCM write_proc
, SCM get_position_proc
,
976 SCM set_position_proc
, SCM close_proc
)
978 SCM port
, method_vector
;
980 const unsigned long mode_bits
= SCM_OPN
| SCM_WRTNG
;
982 /* Store the various methods and bytevector in a vector. */
983 method_vector
= scm_c_make_vector (4, SCM_BOOL_F
);
984 SCM_SIMPLE_VECTOR_SET (method_vector
, 0, write_proc
);
985 SCM_SIMPLE_VECTOR_SET (method_vector
, 1, get_position_proc
);
986 SCM_SIMPLE_VECTOR_SET (method_vector
, 2, set_position_proc
);
987 SCM_SIMPLE_VECTOR_SET (method_vector
, 3, close_proc
);
989 scm_i_pthread_mutex_lock (&scm_i_port_table_mutex
);
991 port
= scm_new_port_table_entry (custom_binary_output_port_type
);
992 c_port
= SCM_PTAB_ENTRY (port
);
994 /* Match the expectation of `binary-port?'. */
995 c_port
->encoding
= NULL
;
997 /* Attach it the method vector. */
998 SCM_SETSTREAM (port
, SCM_UNPACK (method_vector
));
1000 /* Have the port directly access the buffer (bytevector). */
1001 c_port
->write_buf
= c_port
->write_pos
= c_port
->write_end
= NULL
;
1002 c_port
->write_buf_size
= c_port
->read_buf_size
= 0;
1004 /* Mark PORT as open, writable and unbuffered. */
1005 SCM_SET_CELL_TYPE (port
, custom_binary_output_port_type
| mode_bits
);
1007 scm_i_pthread_mutex_unlock (&scm_i_port_table_mutex
);
1012 /* Write SIZE octets from DATA to PORT. */
1014 cbop_write (SCM port
, const void *data
, size_t size
)
1015 #define FUNC_NAME "cbop_write"
1019 SCM bv
, write_proc
, result
;
1021 /* XXX: Allocating a new bytevector at each `write' call is inefficient,
1022 but necessary since (1) we don't control the lifetime of the buffer
1023 pointed to by DATA, and (2) the `write!' procedure could capture the
1024 bytevector it is passed. */
1025 bv
= scm_c_make_bytevector (size
);
1026 memcpy (SCM_BYTEVECTOR_CONTENTS (bv
), data
, size
);
1028 write_proc
= SCM_CBOP_WRITE_PROC (port
);
1030 /* Since the `write' procedure of Guile's ports has type `void', it must
1031 try hard to write exactly SIZE bytes, regardless of how many bytes the
1035 c_written
+= c_result
)
1037 result
= scm_call_3 (write_proc
, bv
,
1038 scm_from_size_t (c_written
),
1039 scm_from_size_t (size
- c_written
));
1041 c_result
= scm_to_long (result
);
1042 if (SCM_UNLIKELY (c_result
< 0
1043 || (size_t) c_result
> (size
- c_written
)))
1044 scm_wrong_type_arg_msg (FUNC_NAME
, 0, result
,
1045 "R6RS custom binary output port `write!' "
1046 "returned a incorrect integer");
1052 SCM_DEFINE (scm_make_custom_binary_output_port
,
1053 "make-custom-binary-output-port", 5, 0, 0,
1054 (SCM id
, SCM write_proc
, SCM get_position_proc
,
1055 SCM set_position_proc
, SCM close_proc
),
1056 "Return a new custom binary output port whose output is drained "
1057 "by invoking @var{write_proc} and passing it a bytevector, an "
1058 "index where octets should be written, and an octet count.")
1059 #define FUNC_NAME s_scm_make_custom_binary_output_port
1061 SCM_VALIDATE_STRING (1, id
);
1062 SCM_VALIDATE_PROC (2, write_proc
);
1064 if (!scm_is_false (get_position_proc
))
1065 SCM_VALIDATE_PROC (3, get_position_proc
);
1067 if (!scm_is_false (set_position_proc
))
1068 SCM_VALIDATE_PROC (4, set_position_proc
);
1070 if (!scm_is_false (close_proc
))
1071 SCM_VALIDATE_PROC (5, close_proc
);
1073 return (make_cbop (write_proc
, get_position_proc
, set_position_proc
,
1079 /* Instantiate the custom binary output port type. */
1081 initialize_custom_binary_output_ports (void)
1083 custom_binary_output_port_type
=
1084 scm_make_port_type ("r6rs-custom-binary-output-port",
1087 scm_set_port_seek (custom_binary_output_port_type
, cbp_seek
);
1088 scm_set_port_close (custom_binary_output_port_type
, cbp_close
);
1092 /* Transcoded ports ("tp" for short). */
1093 static scm_t_bits transcoded_port_type
= 0;
1095 #define TP_INPUT_BUFFER_SIZE 4096
1097 #define SCM_TP_BINARY_PORT(_port) SCM_PACK (SCM_STREAM (_port))
1100 make_tp (SCM binary_port
, unsigned long mode
)
1104 const unsigned long mode_bits
= SCM_OPN
| mode
;
1106 scm_i_pthread_mutex_lock (&scm_i_port_table_mutex
);
1108 port
= scm_new_port_table_entry (transcoded_port_type
);
1110 SCM_SETSTREAM (port
, SCM_UNPACK (binary_port
));
1112 SCM_SET_CELL_TYPE (port
, transcoded_port_type
| mode_bits
);
1114 if (SCM_INPUT_PORT_P (port
))
1116 c_port
= SCM_PTAB_ENTRY (port
);
1117 c_port
->read_buf
= scm_gc_malloc_pointerless (TP_INPUT_BUFFER_SIZE
,
1119 c_port
->read_pos
= c_port
->read_end
= c_port
->read_buf
;
1120 c_port
->read_buf_size
= TP_INPUT_BUFFER_SIZE
;
1122 SCM_SET_CELL_WORD_0 (port
, SCM_CELL_WORD_0 (port
) & ~SCM_BUF0
);
1125 scm_i_pthread_mutex_unlock (&scm_i_port_table_mutex
);
1131 tp_write (SCM port
, const void *data
, size_t size
)
1133 scm_c_write (SCM_TP_BINARY_PORT (port
), data
, size
);
1137 tp_fill_input (SCM port
)
1140 scm_t_port
*c_port
= SCM_PTAB_ENTRY (port
);
1141 SCM bport
= SCM_TP_BINARY_PORT (port
);
1142 scm_t_port
*c_bport
= SCM_PTAB_ENTRY (bport
);
1144 /* We can't use `scm_c_read' here, since it blocks until the whole
1145 block has been read or EOF. */
1147 if (c_bport
->rw_active
== SCM_PORT_WRITE
)
1148 scm_force_output (bport
);
1150 if (c_bport
->read_pos
>= c_bport
->read_end
)
1151 scm_fill_input (bport
);
1153 count
= c_bport
->read_end
- c_bport
->read_pos
;
1154 if (count
> c_port
->read_buf_size
)
1155 count
= c_port
->read_buf_size
;
1157 memcpy (c_port
->read_buf
, c_bport
->read_pos
, count
);
1158 c_bport
->read_pos
+= count
;
1160 if (c_bport
->rw_random
)
1161 c_bport
->rw_active
= SCM_PORT_READ
;
1167 c_port
->read_pos
= c_port
->read_buf
;
1168 c_port
->read_end
= c_port
->read_buf
+ count
;
1169 return *c_port
->read_buf
;
1176 SCM binary_port
= SCM_TP_BINARY_PORT (port
);
1177 scm_t_port
*c_port
= SCM_PTAB_ENTRY (port
);
1178 size_t count
= c_port
->write_pos
- c_port
->write_buf
;
1180 /* As the runtime will try to flush all ports upon exit, we test for
1181 the underlying port still being open here. Otherwise, when you
1182 would explicitly close the underlying port and the transcoded port
1183 still had data outstanding, you'd get an exception on Guile exit.
1185 We just throw away the data when the underlying port is closed. */
1187 if (SCM_OPOUTPORTP (binary_port
))
1188 scm_c_write (binary_port
, c_port
->write_buf
, count
);
1190 c_port
->write_pos
= c_port
->write_buf
;
1191 c_port
->rw_active
= SCM_PORT_NEITHER
;
1193 if (SCM_OPOUTPORTP (binary_port
))
1194 scm_force_output (binary_port
);
1200 if (SCM_OUTPUT_PORT_P (port
))
1202 return scm_is_true (scm_close_port (SCM_TP_BINARY_PORT (port
))) ? 0 : -1;
1206 initialize_transcoded_ports (void)
1208 transcoded_port_type
=
1209 scm_make_port_type ("r6rs-transcoded-port", tp_fill_input
, tp_write
);
1211 scm_set_port_flush (transcoded_port_type
, tp_flush
);
1212 scm_set_port_close (transcoded_port_type
, tp_close
);
1215 SCM_DEFINE (scm_i_make_transcoded_port
,
1216 "%make-transcoded-port", 1, 0, 0,
1218 "Return a new port which reads and writes to @var{port}")
1219 #define FUNC_NAME s_scm_i_make_transcoded_port
1222 unsigned long mode
= 0;
1224 SCM_VALIDATE_PORT (SCM_ARG1
, port
);
1226 if (scm_is_true (scm_output_port_p (port
)))
1228 else if (scm_is_true (scm_input_port_p (port
)))
1231 result
= make_tp (port
, mode
);
1233 /* FIXME: We should actually close `port' "in a special way" here,
1234 according to R6RS. As there is no way to do that in Guile without
1235 rendering the underlying port unusable for our purposes as well, we
1236 just leave it open. */
1245 SCM_DEFINE (scm_get_string_n_x
,
1246 "get-string-n!", 4, 0, 0,
1247 (SCM port
, SCM str
, SCM start
, SCM count
),
1248 "Read up to @var{count} characters from @var{port} into "
1249 "@var{str}, starting at @var{start}. If no characters "
1250 "can be read before the end of file is encountered, the end "
1251 "of file object is returned. Otherwise, the number of "
1252 "characters read is returned.")
1253 #define FUNC_NAME s_scm_get_string_n_x
1255 size_t c_start
, c_count
, c_len
, c_end
, j
;
1258 SCM_VALIDATE_OPINPORT (1, port
);
1259 SCM_VALIDATE_STRING (2, str
);
1260 c_len
= scm_c_string_length (str
);
1261 c_start
= scm_to_size_t (start
);
1262 c_count
= scm_to_size_t (count
);
1263 c_end
= c_start
+ c_count
;
1265 if (SCM_UNLIKELY (c_end
> c_len
))
1266 scm_out_of_range (FUNC_NAME
, count
);
1268 for (j
= c_start
; j
< c_end
; j
++)
1270 c
= scm_getc (port
);
1273 size_t chars_read
= j
- c_start
;
1274 return chars_read
== 0 ? SCM_EOF_VAL
: scm_from_size_t (chars_read
);
1276 scm_c_string_set_x (str
, j
, SCM_MAKE_CHAR (c
));
1283 /* Initialization. */
1286 scm_register_r6rs_ports (void)
1288 scm_c_register_extension ("libguile-" SCM_EFFECTIVE_VERSION
,
1289 "scm_init_r6rs_ports",
1290 (scm_t_extension_init_func
) scm_init_r6rs_ports
,
1295 scm_init_r6rs_ports (void)
1297 #include "libguile/r6rs-ports.x"
1299 initialize_bytevector_input_ports ();
1300 initialize_custom_binary_input_ports ();
1301 initialize_bytevector_output_ports ();
1302 initialize_custom_binary_output_ports ();
1303 initialize_transcoded_ports ();