Implemented binary output (Section 7.2.11).
[guile-r6rs-libs.git] / src / ports.c
blob286000d7519f2b92ae384cfd6a47b98f0c9425e6
1 /* Guile-R6RS-Libs --- Implementation of R6RS standard libraries.
2 Copyright (C) 2007 Ludovic Courtès <ludovic.courtes@laas.fr>
4 Guile-R6RS-Libs is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
9 Guile-R6RS-Libs is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
14 You should have received a copy of the GNU Lesser General Public
15 License along with Guile-R6RS-Libs; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
18 #include "config.h"
20 #include <libguile.h>
21 #include <stdio.h>
23 #include "bytevector.h"
24 #include "utils.h"
28 /* End-of-file object. */
30 SCM_DEFINE (scm_r6rs_eof_object, "eof-object", 0, 0, 0,
31 (void),
32 "Return the end-of-file object.")
33 #define FUNC_NAME s_scm_r6rs_eof_object
35 return (SCM_EOF_VAL);
37 #undef FUNC_NAME
40 /* Binary input. */
42 /* We currently don't support specific binary input ports. */
43 #define SCM_VALIDATE_R6RS_BINARY_INPUT_PORT SCM_VALIDATE_INPUT_PORT
45 SCM_DEFINE (scm_r6rs_get_u8, "get-u8", 1, 0, 0,
46 (SCM port),
47 "Read an octet from @var{port}, a binary input port, "
48 "blocking as necessary.")
49 #define FUNC_NAME s_scm_r6rs_get_u8
51 SCM result;
52 int c_result;
54 SCM_VALIDATE_R6RS_BINARY_INPUT_PORT (1, port);
56 c_result = scm_getc (port);
57 if (c_result == EOF)
58 result = SCM_EOF_VAL;
59 else
60 result = SCM_I_MAKINUM ((unsigned char) c_result);
62 return result;
64 #undef FUNC_NAME
66 SCM_DEFINE (scm_r6rs_lookahead_u8, "lookahead-u8", 1, 0, 0,
67 (SCM port),
68 "Like @code{get-u8} but does not update @var{port} to "
69 "point past the octet.")
70 #define FUNC_NAME s_scm_r6rs_lookahead_u8
72 SCM result;
74 SCM_VALIDATE_R6RS_BINARY_INPUT_PORT (1, port);
76 result = scm_peek_char (port);
77 if (SCM_CHARP (result))
78 result = SCM_I_MAKINUM ((signed char) SCM_CHAR (result));
79 else
80 result = SCM_EOF_VAL;
82 return result;
84 #undef FUNC_NAME
86 SCM_DEFINE (scm_r6rs_get_bytevector_n, "get-bytevector-n", 2, 0, 0,
87 (SCM port, SCM count),
88 "Read @var{count} octets from @var{port}, blocking as "
89 "necessary and return a bytevector containing the octets "
90 "read. If fewer bytes are available, a bytevector smaller "
91 "than @var{count} is returned.")
92 #define FUNC_NAME s_scm_r6rs_get_bytevector_n
94 SCM result;
95 char *c_bv;
96 unsigned c_count;
97 size_t read;
99 SCM_VALIDATE_R6RS_BINARY_INPUT_PORT (1, port);
100 c_count = scm_to_uint (count);
102 c_bv = (char *) scm_gc_malloc (c_count, SCM_GC_BYTEVECTOR);
104 /* XXX: `scm_c_read ()' does not update the port position. */
105 read = scm_c_read (port, c_bv, c_count);
107 if (read == 0)
109 if (SCM_EOF_OBJECT_P (scm_peek_char (port)))
110 result = SCM_EOF_VAL;
111 else
112 result = scm_r6rs_c_take_bytevector (NULL, 0);
114 else
116 if (read < c_count)
117 c_bv = (char *) scm_gc_realloc (c_bv, c_count, read,
118 SCM_GC_BYTEVECTOR);
120 result = scm_r6rs_c_take_bytevector ((signed char *) c_bv, read);
123 return result;
125 #undef FUNC_NAME
127 SCM_DEFINE (scm_r6rs_get_bytevector_n_x, "get-bytevector-n!", 4, 0, 0,
128 (SCM port, SCM bv, SCM start, SCM count),
129 "Read @var{count} bytes from @var{port} and store them "
130 "in @var{bv} starting at index @var{start}. Return either "
131 "the number of bytes actually read or the end-of-file "
132 "object.")
133 #define FUNC_NAME s_scm_r6rs_get_bytevector_n_x
135 SCM result;
136 char *c_bv;
137 unsigned c_start, c_count, c_len;
138 size_t c_read;
140 SCM_VALIDATE_R6RS_BINARY_INPUT_PORT (1, port);
141 SCM_VALIDATE_R6RS_BYTEVECTOR (2, bv);
142 c_start = scm_to_uint (start);
143 c_count = scm_to_uint (count);
145 c_bv = (char *) SCM_R6RS_BYTEVECTOR_CONTENTS (bv);
146 c_len = SCM_R6RS_BYTEVECTOR_LENGTH (bv);
148 if (EXPECT_FALSE (c_start + c_count > c_len))
149 scm_out_of_range (FUNC_NAME, count);
151 c_read = scm_c_read (port, c_bv + c_start, c_count);
152 if (c_read == 0)
154 if (SCM_EOF_OBJECT_P (scm_peek_char (port)))
155 result = SCM_EOF_VAL;
156 else
157 result = SCM_I_MAKINUM (0);
159 else
160 result = scm_from_size_t (c_read);
162 return result;
164 #undef FUNC_NAME
167 SCM_DEFINE (scm_r6rs_get_bytevector_some, "get-bytevector-some", 1, 0, 0,
168 (SCM port),
169 "Read from @var{port}, blocking as necessary, until data "
170 "are available or and end-of-file is reached. Return either "
171 "a new bytevector containing the data read or the "
172 "end-of-file object.")
173 #define FUNC_NAME s_scm_r6rs_get_bytevector_some
175 /* Read at least one byte, unless the end-of-file is already reached, and
176 read while characters are available (buffered). */
178 SCM result;
179 char *c_bv;
180 unsigned c_len;
181 size_t c_total;
183 SCM_VALIDATE_R6RS_BINARY_INPUT_PORT (1, port);
185 c_len = 4096;
186 c_bv = (char *) scm_gc_malloc (c_len, SCM_GC_BYTEVECTOR);
187 c_total = 0;
191 int c_chr;
193 if (c_total + 1 > c_len)
195 /* Grow the bytevector. */
196 c_bv = (char *) scm_gc_realloc (c_bv, c_len, c_len * 2,
197 SCM_GC_BYTEVECTOR);
198 c_len *= 2;
201 /* We can't use `scm_c_read ()' since it blocks. */
202 c_chr = scm_getc (port);
203 if (c_chr != EOF)
205 c_bv[c_total] = (char) c_chr;
206 c_total++;
209 while ((scm_is_true (scm_char_ready_p (port)))
210 && (!SCM_EOF_OBJECT_P (scm_peek_char (port))));
212 if (c_total == 0)
214 result = SCM_EOF_VAL;
215 scm_gc_free (c_bv, c_len, SCM_GC_BYTEVECTOR);
217 else
219 if (c_len > c_total)
221 /* Shrink the bytevector. */
222 c_bv = (char *) scm_gc_realloc (c_bv, c_len, c_total,
223 SCM_GC_BYTEVECTOR);
224 c_len = (unsigned) c_total;
227 result = scm_r6rs_c_take_bytevector ((signed char *) c_bv, c_len);
230 return result;
232 #undef FUNC_NAME
234 SCM_DEFINE (scm_r6rs_get_bytevector_all, "get-bytevector-all", 1, 0, 0,
235 (SCM port),
236 "Read from @var{port}, blocking as necessary, until "
237 "the end-of-file is reached. Return either "
238 "a new bytevector containing the data read or the "
239 "end-of-file object (if no data were available).")
240 #define FUNC_NAME s_scm_r6rs_get_bytevector_all
242 SCM result;
243 char *c_bv;
244 unsigned c_len, c_count;
245 size_t c_read, c_total;
247 SCM_VALIDATE_R6RS_BINARY_INPUT_PORT (1, port);
249 c_len = c_count = 4096;
250 c_bv = (char *) scm_gc_malloc (c_len, SCM_GC_BYTEVECTOR);
251 c_total = c_read = 0;
255 if (c_total + c_read > c_len)
257 /* Grow the bytevector. */
258 c_bv = (char *) scm_gc_realloc (c_bv, c_len, c_len * 2,
259 SCM_GC_BYTEVECTOR);
260 c_count = c_len;
261 c_len *= 2;
264 /* `scm_c_read ()' blocks until C_COUNT bytes are available or EOF is
265 reached. */
266 c_read = scm_c_read (port, c_bv + c_total, c_count);
267 c_total += c_read, c_count -= c_read;
269 while (!SCM_EOF_OBJECT_P (scm_peek_char (port)));
271 if (c_total == 0)
273 result = SCM_EOF_VAL;
274 scm_gc_free (c_bv, c_len, SCM_GC_BYTEVECTOR);
276 else
278 if (c_len > c_total)
280 /* Shrink the bytevector. */
281 c_bv = (char *) scm_gc_realloc (c_bv, c_len, c_total,
282 SCM_GC_BYTEVECTOR);
283 c_len = (unsigned) c_total;
286 result = scm_r6rs_c_take_bytevector ((signed char *) c_bv, c_len);
289 return result;
291 #undef FUNC_NAME
295 /* Binary output. */
297 /* We currently don't support specific binary input ports. */
298 #define SCM_VALIDATE_R6RS_BINARY_OUTPUT_PORT SCM_VALIDATE_OUTPUT_PORT
301 SCM_DEFINE (scm_r6rs_put_u8, "put-u8", 2, 0, 0,
302 (SCM port, SCM octet),
303 "Write @var{octet} to binary port @var{port}.")
304 #define FUNC_NAME s_scm_r6rs_put_u8
306 scm_t_uint8 c_octet;
308 SCM_VALIDATE_R6RS_BINARY_OUTPUT_PORT (1, port);
309 c_octet = scm_to_uint8 (octet);
311 scm_putc ((char) c_octet, port);
313 return SCM_UNSPECIFIED;
315 #undef FUNC_NAME
317 SCM_DEFINE (scm_r6rs_put_bytevector, "put-bytevector", 2, 2, 0,
318 (SCM port, SCM bv, SCM start, SCM count),
319 "Write the contents of @var{bv} to @var{port}, optionally "
320 "starting at index @var{start} and limiting to @var{count} "
321 "octets.")
322 #define FUNC_NAME s_scm_r6rs_put_bytevector
324 char *c_bv;
325 unsigned c_start, c_count, c_len;
327 SCM_VALIDATE_R6RS_BINARY_OUTPUT_PORT (1, port);
328 SCM_VALIDATE_R6RS_BYTEVECTOR (2, bv);
330 c_len = SCM_R6RS_BYTEVECTOR_LENGTH (bv);
331 c_bv = SCM_R6RS_BYTEVECTOR_CONTENTS (bv);
333 if (start != SCM_UNDEFINED)
335 c_start = scm_to_uint (start);
337 if (count != SCM_UNDEFINED)
339 c_count = scm_to_uint (count);
340 if (EXPECT_FALSE (c_start + c_count > c_len))
341 scm_out_of_range (FUNC_NAME, count);
343 else
345 if (EXPECT_FALSE (c_start >= c_len))
346 scm_out_of_range (FUNC_NAME, start);
347 else
348 c_count = c_len - c_start;
351 else
352 c_start = 0, c_count = c_len;
354 scm_c_write (port, c_bv + c_start, c_count);
356 return SCM_UNSPECIFIED;
358 #undef FUNC_NAME
361 /* Initialization. */
363 void
364 scm_init_r6rs_ports (void)
366 #include "ports.c.x"
369 /* arch-tag: c041ffd6-8871-40e8-a25a-d0f8768a71dc