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