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