Merge commit 'fdd319e9bd4121d844662d3d8ccc69b462b60840'
[bpt/guile.git] / libguile / r6rs-ports.c
1 /* Copyright (C) 2009, 2010, 2011, 2013, 2014 Free Software Foundation, Inc.
2 *
3 * This library is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU Lesser General Public License
5 * as published by the Free Software Foundation; either version 3 of
6 * the License, or (at your option) any later version.
7 *
8 * This library is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public
14 * License along with this library; if not, write to the Free Software
15 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
16 * 02110-1301 USA
17 */
18
19 #ifdef HAVE_CONFIG_H
20 # include <config.h>
21 #endif
22
23 #include <unistd.h>
24 #include <string.h>
25 #include <stdio.h>
26 #include <assert.h>
27
28 #include "libguile/_scm.h"
29 #include "libguile/bytevectors.h"
30 #include "libguile/chars.h"
31 #include "libguile/eval.h"
32 #include "libguile/r6rs-ports.h"
33 #include "libguile/strings.h"
34 #include "libguile/validate.h"
35 #include "libguile/values.h"
36 #include "libguile/vectors.h"
37 #include "libguile/ports-internal.h"
38
39
40 \f
41 /* Unimplemented features. */
42
43
44 /* Transoders are currently not implemented since Guile 1.8 is not
45 Unicode-capable. Thus, most of the code here assumes the use of the
46 binary transcoder. */
47 static inline void
48 transcoders_not_implemented (void)
49 {
50 fprintf (stderr, "%s: warning: transcoders not implemented\n",
51 PACKAGE_NAME);
52 }
53
54 \f
55 /* End-of-file object. */
56
57 SCM_DEFINE (scm_eof_object, "eof-object", 0, 0, 0,
58 (void),
59 "Return the end-of-file object.")
60 #define FUNC_NAME s_scm_eof_object
61 {
62 return (SCM_EOF_VAL);
63 }
64 #undef FUNC_NAME
65
66 \f
67 /* Input ports. */
68
69 #ifndef MIN
70 # define MIN(a,b) ((a) < (b) ? (a) : (b))
71 #endif
72
73 /* Bytevector input ports or "bip" for short. */
74 static scm_t_bits bytevector_input_port_type = 0;
75
76 static inline SCM
77 make_bip (SCM bv)
78 {
79 SCM port;
80 char *c_bv;
81 unsigned c_len;
82 scm_t_port *c_port;
83 const unsigned long mode_bits = SCM_OPN | SCM_RDNG;
84
85 port = scm_c_make_port_with_encoding (bytevector_input_port_type,
86 mode_bits,
87 NULL, /* encoding */
88 SCM_FAILED_CONVERSION_ERROR,
89 SCM_UNPACK (bv));
90
91 c_port = SCM_PTAB_ENTRY (port);
92
93 /* Have the port directly access the bytevector. */
94 c_bv = (char *) SCM_BYTEVECTOR_CONTENTS (bv);
95 c_len = SCM_BYTEVECTOR_LENGTH (bv);
96
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;
100
101 return port;
102 }
103
104 static int
105 bip_fill_input (SCM port)
106 {
107 int result;
108 scm_t_port *c_port = SCM_PTAB_ENTRY (port);
109
110 if (c_port->read_pos >= c_port->read_end)
111 result = EOF;
112 else
113 result = (int) *c_port->read_pos;
114
115 return result;
116 }
117
118 static scm_t_off
119 bip_seek (SCM port, scm_t_off offset, int whence)
120 #define FUNC_NAME "bip_seek"
121 {
122 scm_t_off c_result = 0;
123 scm_t_port *c_port = SCM_PTAB_ENTRY (port);
124
125 switch (whence)
126 {
127 case SEEK_CUR:
128 offset += c_port->read_pos - c_port->read_buf;
129 /* Fall through. */
130
131 case SEEK_SET:
132 if (c_port->read_buf + offset <= c_port->read_end)
133 {
134 c_port->read_pos = c_port->read_buf + offset;
135 c_result = offset;
136 }
137 else
138 scm_out_of_range (FUNC_NAME, scm_from_int (offset));
139 break;
140
141 case SEEK_END:
142 if (c_port->read_end - offset >= c_port->read_buf)
143 {
144 c_port->read_pos = c_port->read_end - offset;
145 c_result = c_port->read_pos - c_port->read_buf;
146 }
147 else
148 scm_out_of_range (FUNC_NAME, scm_from_int (offset));
149 break;
150
151 default:
152 scm_wrong_type_arg_msg (FUNC_NAME, 0, port,
153 "invalid `seek' parameter");
154 }
155
156 return c_result;
157 }
158 #undef FUNC_NAME
159
160
161 /* Instantiate the bytevector input port type. */
162 static inline void
163 initialize_bytevector_input_ports (void)
164 {
165 bytevector_input_port_type =
166 scm_make_port_type ("r6rs-bytevector-input-port", bip_fill_input,
167 NULL);
168
169 scm_set_port_seek (bytevector_input_port_type, bip_seek);
170 }
171
172
173 SCM_DEFINE (scm_open_bytevector_input_port,
174 "open-bytevector-input-port", 1, 1, 0,
175 (SCM bv, SCM transcoder),
176 "Return an input port whose contents are drawn from "
177 "bytevector @var{bv}.")
178 #define FUNC_NAME s_scm_open_bytevector_input_port
179 {
180 SCM_VALIDATE_BYTEVECTOR (1, bv);
181 if (!SCM_UNBNDP (transcoder) && !scm_is_false (transcoder))
182 transcoders_not_implemented ();
183
184 return (make_bip (bv));
185 }
186 #undef FUNC_NAME
187
188 \f
189 /* Custom binary ports. The following routines are shared by input and
190 output custom binary ports. */
191
192 #define SCM_CBP_GET_POSITION_PROC(_port) \
193 SCM_SIMPLE_VECTOR_REF (SCM_PACK (SCM_STREAM (_port)), 1)
194 #define SCM_CBP_SET_POSITION_PROC(_port) \
195 SCM_SIMPLE_VECTOR_REF (SCM_PACK (SCM_STREAM (_port)), 2)
196 #define SCM_CBP_CLOSE_PROC(_port) \
197 SCM_SIMPLE_VECTOR_REF (SCM_PACK (SCM_STREAM (_port)), 3)
198
199 static scm_t_off
200 cbp_seek (SCM port, scm_t_off offset, int whence)
201 #define FUNC_NAME "cbp_seek"
202 {
203 SCM result;
204 scm_t_off c_result = 0;
205
206 switch (whence)
207 {
208 case SEEK_CUR:
209 {
210 SCM get_position_proc;
211
212 get_position_proc = SCM_CBP_GET_POSITION_PROC (port);
213 if (SCM_LIKELY (scm_is_true (get_position_proc)))
214 result = scm_call_0 (get_position_proc);
215 else
216 scm_wrong_type_arg_msg (FUNC_NAME, 0, port,
217 "R6RS custom binary port with "
218 "`port-position' support");
219 c_result = scm_to_int (result);
220 if (offset == 0)
221 /* We just want to know the current position. */
222 break;
223
224 offset += c_result;
225 /* Fall through. */
226 }
227
228 case SEEK_SET:
229 {
230 SCM set_position_proc;
231
232 set_position_proc = SCM_CBP_SET_POSITION_PROC (port);
233 if (SCM_LIKELY (scm_is_true (set_position_proc)))
234 result = scm_call_1 (set_position_proc, scm_from_int (offset));
235 else
236 scm_wrong_type_arg_msg (FUNC_NAME, 0, port,
237 "seekable R6RS custom binary port");
238
239 /* Assuming setting the position succeeded. */
240 c_result = offset;
241 break;
242 }
243
244 default:
245 /* `SEEK_END' cannot be supported. */
246 scm_wrong_type_arg_msg (FUNC_NAME, 0, port,
247 "R6RS custom binary ports do not "
248 "support `SEEK_END'");
249 }
250
251 return c_result;
252 }
253 #undef FUNC_NAME
254
255 static int
256 cbp_close (SCM port)
257 {
258 SCM close_proc;
259
260 close_proc = SCM_CBP_CLOSE_PROC (port);
261 if (scm_is_true (close_proc))
262 /* Invoke the `close' thunk. */
263 scm_call_0 (close_proc);
264
265 return 1;
266 }
267
268 \f
269 /* Custom binary input port ("cbip" for short). */
270
271 static scm_t_bits custom_binary_input_port_type = 0;
272
273 /* Initial size of the buffer embedded in custom binary input ports. */
274 #define CBIP_BUFFER_SIZE 8192
275
276 /* Return the bytevector associated with PORT. */
277 #define SCM_CBIP_BYTEVECTOR(_port) \
278 SCM_SIMPLE_VECTOR_REF (SCM_PACK (SCM_STREAM (_port)), 4)
279
280 /* Set BV as the bytevector associated with PORT. */
281 #define SCM_SET_CBIP_BYTEVECTOR(_port, _bv) \
282 SCM_SIMPLE_VECTOR_SET (SCM_PACK (SCM_STREAM (_port)), 4, (_bv))
283
284 /* Return the various procedures of PORT. */
285 #define SCM_CBIP_READ_PROC(_port) \
286 SCM_SIMPLE_VECTOR_REF (SCM_PACK (SCM_STREAM (_port)), 0)
287
288
289 /* Set PORT's internal buffer according to READ_SIZE. */
290 static void
291 cbip_setvbuf (SCM port, long read_size, long write_size)
292 {
293 SCM bv;
294 scm_t_port *pt;
295
296 pt = SCM_PTAB_ENTRY (port);
297 bv = SCM_CBIP_BYTEVECTOR (port);
298
299 switch (read_size)
300 {
301 case 0:
302 /* Unbuffered: keep PORT's bytevector as is (it will be used in
303 future 'scm_c_read' calls), but point to the one-byte buffer. */
304 pt->read_buf = &pt->shortbuf;
305 pt->read_buf_size = 1;
306 break;
307
308 case -1:
309 /* Preferred size: keep the current bytevector and use it as the
310 backing store. */
311 pt->read_buf = (unsigned char *) SCM_BYTEVECTOR_CONTENTS (bv);
312 pt->read_buf_size = SCM_BYTEVECTOR_LENGTH (bv);
313 break;
314
315 default:
316 /* Fully buffered: allocate a buffer of READ_SIZE bytes. */
317 bv = scm_c_make_bytevector (read_size);
318 SCM_SET_CBIP_BYTEVECTOR (port, bv);
319 pt->read_buf = (unsigned char *) SCM_BYTEVECTOR_CONTENTS (bv);
320 pt->read_buf_size = read_size;
321 }
322
323 pt->read_pos = pt->read_end = pt->read_buf;
324 }
325
326 static inline SCM
327 make_cbip (SCM read_proc, SCM get_position_proc,
328 SCM set_position_proc, SCM close_proc)
329 {
330 SCM port, bv, method_vector;
331 char *c_bv;
332 unsigned c_len;
333 scm_t_port *c_port;
334 const unsigned long mode_bits = SCM_OPN | SCM_RDNG;
335
336 /* Use a bytevector as the underlying buffer. */
337 c_len = CBIP_BUFFER_SIZE;
338 bv = scm_c_make_bytevector (c_len);
339 c_bv = (char *) SCM_BYTEVECTOR_CONTENTS (bv);
340
341 /* Store the various methods and bytevector in a vector. */
342 method_vector = scm_c_make_vector (5, SCM_BOOL_F);
343 SCM_SIMPLE_VECTOR_SET (method_vector, 4, bv);
344 SCM_SIMPLE_VECTOR_SET (method_vector, 0, read_proc);
345 SCM_SIMPLE_VECTOR_SET (method_vector, 1, get_position_proc);
346 SCM_SIMPLE_VECTOR_SET (method_vector, 2, set_position_proc);
347 SCM_SIMPLE_VECTOR_SET (method_vector, 3, close_proc);
348
349 port = scm_c_make_port_with_encoding (custom_binary_input_port_type,
350 mode_bits,
351 NULL, /* encoding */
352 SCM_FAILED_CONVERSION_ERROR,
353 SCM_UNPACK (method_vector));
354
355 c_port = SCM_PTAB_ENTRY (port);
356
357 /* Have the port directly access the buffer (bytevector). */
358 c_port->read_pos = c_port->read_buf = (unsigned char *) c_bv;
359 c_port->read_end = (unsigned char *) c_bv;
360 c_port->read_buf_size = c_len;
361
362 return port;
363 }
364
365 static int
366 cbip_fill_input (SCM port)
367 #define FUNC_NAME "cbip_fill_input"
368 {
369 int result;
370 scm_t_port *c_port = SCM_PTAB_ENTRY (port);
371
372 if (c_port->read_pos >= c_port->read_end)
373 {
374 /* Invoke the user's `read!' procedure. */
375 int buffered;
376 size_t c_octets, c_requested;
377 SCM bv, read_proc, octets;
378
379 c_requested = c_port->read_buf_size;
380 read_proc = SCM_CBIP_READ_PROC (port);
381
382 bv = SCM_CBIP_BYTEVECTOR (port);
383 buffered =
384 (c_port->read_buf == (unsigned char *) SCM_BYTEVECTOR_CONTENTS (bv));
385
386 if (buffered)
387 {
388 /* Make sure the buffer isn't corrupt. BV can be passed directly
389 to READ_PROC. */
390 assert (c_port->read_buf_size == SCM_BYTEVECTOR_LENGTH (bv));
391 c_port->read_pos = (unsigned char *) SCM_BYTEVECTOR_CONTENTS (bv);
392 }
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 }