1 /*===========================================================================
2 * Filename : scmport-str.c
3 * About : A ScmBytePort implementation for string
4 *
5 * Copyright (C) 2005-2006 YAMAMOTO Kengo <yamaken AT bp.iij4u.or.jp>
6 * Copyright (c) 2007-2008 SigScheme Project <uim-en AT googlegroups.com>
7 *
8 * All rights reserved.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 *
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. Neither the name of authors nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
24 * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
25 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
26 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
27 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
28 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
29 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
30 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
31 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
32 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
33 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 ===========================================================================*/
35
36 /*
37 * - This file is intended to be portable. Don't depend on SigScheme.
38 * - To isolate and hide implementation-dependent things, don't merge this file
39 * into another
40 */
41
42 #include <config.h>
43
44 #include <stdlib.h>
45 #include <stdio.h>
46 #include <string.h>
47
48 #include "scmint.h"
49 #include "scmport-config.h"
50 #include "scmport.h"
51 #include "scmport-str.h"
52
53 /*=======================================
54 File Local Macro Definitions
55 =======================================*/
56
57 /*=======================================
58 File Local Type Definitions
59 =======================================*/
60 typedef struct ScmInputStrPort_ ScmInputStrPort;
61 typedef struct ScmOutputStrPort_ ScmOutputStrPort;
62
63 struct ScmInputStrPort_ { /* inherits ScmBytePort */
64 const ScmBytePortVTbl *vptr;
65
66 scm_byte_t *str;
67 const scm_byte_t *cur;
68 scm_bool has_str_ownership;
69 void *opaque; /* client-specific opaque information */
70 ScmInputStrPort_finalizer finalize;
71 };
72
73 struct ScmOutputStrPort_ { /* inherits ScmBytePort */
74 const ScmBytePortVTbl *vptr;
75
76 scm_byte_t *str;
77 size_t cur; /* offset to terminal '\0' */
78 size_t buf_size;
79 void *opaque; /* client-specific opaque information */
80 ScmOutputStrPort_finalizer finalize;
81 };
82
83 /*=======================================
84 File Local Function Declarations
85 =======================================*/
86 /* input port */
87 static ScmBytePort *istrport_new(scm_byte_t *str, scm_bool ownership,
88 ScmInputStrPort_finalizer finalize);
89 static void istrport_finalize(char **str, scm_bool ownership, void **opaque);
90
91 static ScmBytePort *istrport_dyn_cast(ScmBytePort *bport,
92 const ScmBytePortVTbl *dest_vptr);
93 static void istrport_close(ScmInputStrPort *port);
94 static char *istrport_inspect(ScmInputStrPort *port);
95 static scm_ichar_t istrport_get_byte(ScmInputStrPort *port);
96 static scm_ichar_t istrport_peek_byte(ScmInputStrPort *port);
97 static scm_bool istrport_byte_readyp(ScmInputStrPort *port);
98 static void istrport_puts(ScmInputStrPort *port, const char *str);
99 static void istrport_write(ScmInputStrPort *port,
100 size_t nbytes, const char *buf);
101 static void istrport_flush(ScmInputStrPort *port);
102
103 /* output port */
104 static void ostrport_finalize(char **str, size_t buf_size, void **opaque);
105
106 static ScmBytePort *ostrport_dyn_cast(ScmBytePort *bport,
107 const ScmBytePortVTbl *dest_vptr);
108 static void ostrport_close(ScmOutputStrPort *port);
109 static char *ostrport_inspect(ScmOutputStrPort *port);
110 static scm_ichar_t ostrport_get_byte(ScmOutputStrPort *port);
111 static scm_ichar_t ostrport_peek_byte(ScmOutputStrPort *port);
112 static scm_bool ostrport_byte_readyp(ScmOutputStrPort *port);
113 static void ostrport_puts(ScmOutputStrPort *port, const char *str);
114 static void ostrport_write(ScmOutputStrPort *port,
115 size_t nbytes, const char *buf);
116 static void ostrport_flush(ScmOutputStrPort *port);
117
118 static void ostrport_append(ScmOutputStrPort *port,
119 size_t len, const scm_byte_t *str);
120
121 /*=======================================
122 Variable Definitions
123 =======================================*/
124 static const ScmBytePortVTbl ScmInputStrPort_vtbl = {
125 (ScmBytePortMethod_dyn_cast) &istrport_dyn_cast,
126 (ScmBytePortMethod_close) &istrport_close,
127 (ScmBytePortMethod_inspect) &istrport_inspect,
128 (ScmBytePortMethod_get_byte) &istrport_get_byte,
129 (ScmBytePortMethod_peek_byte) &istrport_peek_byte,
130 (ScmBytePortMethod_byte_readyp)&istrport_byte_readyp,
131 (ScmBytePortMethod_puts) &istrport_puts,
132 (ScmBytePortMethod_write) &istrport_write,
133 (ScmBytePortMethod_flush) &istrport_flush
134 };
135 SCM_EXPORT const ScmBytePortVTbl *const ScmInputStrPort_vptr
136 = &ScmInputStrPort_vtbl;
137
138 static const ScmBytePortVTbl ScmOutputStrPort_vtbl = {
139 (ScmBytePortMethod_dyn_cast) &ostrport_dyn_cast,
140 (ScmBytePortMethod_close) &ostrport_close,
141 (ScmBytePortMethod_inspect) &ostrport_inspect,
142 (ScmBytePortMethod_get_byte) &ostrport_get_byte,
143 (ScmBytePortMethod_peek_byte) &ostrport_peek_byte,
144 (ScmBytePortMethod_byte_readyp)&ostrport_byte_readyp,
145 (ScmBytePortMethod_puts) &ostrport_puts,
146 (ScmBytePortMethod_write) &ostrport_write,
147 (ScmBytePortMethod_flush) &ostrport_flush
148 };
149 SCM_EXPORT const ScmBytePortVTbl *const ScmOutputStrPort_vptr
150 = &ScmOutputStrPort_vtbl;
151
152 /*=======================================
153 Function Definitions
154 =======================================*/
155
156 /*
157 * Client code must call this first even if current implementation does not
158 * contain actual code.
159 */
160 SCM_EXPORT void
scm_strport_init(void)161 scm_strport_init(void)
162 {
163 }
164
165 static ScmBytePort *
istrport_new(scm_byte_t * str,scm_bool ownership,ScmInputStrPort_finalizer finalize)166 istrport_new(scm_byte_t *str, scm_bool ownership,
167 ScmInputStrPort_finalizer finalize)
168 {
169 ScmInputStrPort *port;
170
171 SCM_PORT_ASSERT(str);
172
173 port = SCM_PORT_MALLOC(sizeof(ScmInputStrPort));
174
175 port->vptr = ScmInputStrPort_vptr;
176 port->cur = port->str = str;
177 port->has_str_ownership = ownership;
178 port->opaque = NULL;
179 port->finalize = (finalize) ? finalize : &istrport_finalize;
180
181 return (ScmBytePort *)port;
182 }
183
184 SCM_EXPORT ScmBytePort *
ScmInputStrPort_new(char * str,ScmInputStrPort_finalizer finalize)185 ScmInputStrPort_new(char *str, ScmInputStrPort_finalizer finalize)
186 {
187 return istrport_new((scm_byte_t *)str, scm_true, finalize);
188 }
189
190 SCM_EXPORT ScmBytePort *
ScmInputStrPort_new_copying(const char * str,ScmInputStrPort_finalizer finalize)191 ScmInputStrPort_new_copying(const char *str,
192 ScmInputStrPort_finalizer finalize)
193 {
194 return istrport_new((scm_byte_t *)SCM_PORT_STRDUP(str),
195 scm_true, finalize);
196 }
197
198 SCM_EXPORT ScmBytePort *
ScmInputStrPort_new_const(const char * str,ScmInputStrPort_finalizer finalize)199 ScmInputStrPort_new_const(const char *str, ScmInputStrPort_finalizer finalize)
200 {
201 /* str is actually treated as const */
202 return istrport_new((scm_byte_t *)str, scm_false, finalize);
203 }
204
205 SCM_EXPORT void **
ScmInputStrPort_ref_opaque(ScmBytePort * bport)206 ScmInputStrPort_ref_opaque(ScmBytePort *bport)
207 {
208 ScmInputStrPort *port;
209
210 port = SCM_BYTEPORT_DYNAMIC_CAST(ScmInputStrPort, bport);
211
212 return &port->opaque;
213 }
214
215 static ScmBytePort *
istrport_dyn_cast(ScmBytePort * bport,const ScmBytePortVTbl * dst_vptr)216 istrport_dyn_cast(ScmBytePort *bport, const ScmBytePortVTbl *dst_vptr)
217 {
218 return (dst_vptr == ScmInputStrPort_vptr) ? bport : NULL;
219 }
220
221 /* default finalizer */
222 static void
istrport_finalize(char ** str,scm_bool ownership,void ** opaque)223 istrport_finalize(char **str, scm_bool ownership, void **opaque)
224 {
225 if (ownership)
226 free(*str);
227 }
228
229 static void
istrport_close(ScmInputStrPort * port)230 istrport_close(ScmInputStrPort *port)
231 {
232 SCM_PORT_ASSERT(port->finalize);
233
234 /* To suppress the "dereferencing type-punned pointer will break
235 * strict-aliasing rules" warning on gcc, apply a reinterpret_cast
236 * here. This operation is safe on the case. -- YamaKen 2007-01-06 */
237 (*port->finalize)((char **)(uintptr_t)&port->str,
238 port->has_str_ownership, &port->opaque);
239 free(port);
240 }
241
242 static char *
istrport_inspect(ScmInputStrPort * port)243 istrport_inspect(ScmInputStrPort *port)
244 {
245 return SCM_PORT_STRDUP("string");
246 }
247
248 static scm_ichar_t
istrport_get_byte(ScmInputStrPort * port)249 istrport_get_byte(ScmInputStrPort *port)
250 {
251 return (*port->cur) ? *port->cur++ : SCM_ICHAR_EOF;
252 }
253
254 static scm_ichar_t
istrport_peek_byte(ScmInputStrPort * port)255 istrport_peek_byte(ScmInputStrPort *port)
256 {
257 return (*port->cur) ? *port->cur : SCM_ICHAR_EOF;
258 }
259
260 static scm_bool
istrport_byte_readyp(ScmInputStrPort * port)261 istrport_byte_readyp(ScmInputStrPort *port)
262 {
263 return scm_true;
264 }
265
266 static void
istrport_puts(ScmInputStrPort * port,const char * str)267 istrport_puts(ScmInputStrPort *port, const char *str)
268 {
269 SCM_PORT_ERROR_INVALID_OPERATION(BYTE, port, ScmInputStrPort);
270 /* NOTREACHED */
271 }
272
273 static void
istrport_write(ScmInputStrPort * port,size_t nbytes,const char * buf)274 istrport_write(ScmInputStrPort *port, size_t nbytes, const char *buf)
275 {
276 SCM_PORT_ERROR_INVALID_OPERATION(BYTE, port, ScmInputStrPort);
277 /* NOTREACHED */
278 }
279
280 static void
istrport_flush(ScmInputStrPort * port)281 istrport_flush(ScmInputStrPort *port)
282 {
283 SCM_PORT_ERROR_INVALID_OPERATION(BYTE, port, ScmInputStrPort);
284 /* NOTREACHED */
285 }
286
287
288 SCM_EXPORT ScmBytePort *
ScmOutputStrPort_new(ScmOutputStrPort_finalizer finalize)289 ScmOutputStrPort_new(ScmOutputStrPort_finalizer finalize)
290 {
291 ScmOutputStrPort *port;
292
293 port = SCM_PORT_MALLOC(sizeof(ScmOutputStrPort));
294
295 port->vptr = ScmOutputStrPort_vptr;
296 port->str = NULL;
297 port->cur = 0;
298 port->buf_size = 0;
299 port->opaque = NULL;
300 port->finalize = (finalize) ? finalize : &ostrport_finalize;
301
302 return (ScmBytePort *)port;
303 }
304
305 SCM_EXPORT const char *
ScmOutputStrPort_str(ScmBytePort * bport)306 ScmOutputStrPort_str(ScmBytePort *bport)
307 {
308 ScmOutputStrPort *port;
309
310 port = SCM_BYTEPORT_DYNAMIC_CAST(ScmOutputStrPort, bport);
311
312 return (port->str) ? (const char *)port->str : "";
313 }
314
315 SCM_EXPORT size_t
ScmOutputStrPort_c_strlen(ScmBytePort * bport)316 ScmOutputStrPort_c_strlen(ScmBytePort *bport)
317 {
318 ScmOutputStrPort *port;
319
320 port = SCM_BYTEPORT_DYNAMIC_CAST(ScmOutputStrPort, bport);
321
322 return (port->buf_size) ? port->buf_size - sizeof("") : 0;
323 }
324
325 SCM_EXPORT void **
ScmOutputStrPort_ref_opaque(ScmBytePort * bport)326 ScmOutputStrPort_ref_opaque(ScmBytePort *bport)
327 {
328 ScmOutputStrPort *port;
329
330 port = SCM_BYTEPORT_DYNAMIC_CAST(ScmOutputStrPort, bport);
331
332 return &port->opaque;
333 }
334
335 static ScmBytePort *
ostrport_dyn_cast(ScmBytePort * bport,const ScmBytePortVTbl * dst_vptr)336 ostrport_dyn_cast(ScmBytePort *bport, const ScmBytePortVTbl *dst_vptr)
337 {
338 return (dst_vptr == ScmOutputStrPort_vptr) ? bport : NULL;
339 }
340
341 static void
ostrport_finalize(char ** str,size_t buf_size,void ** opaque)342 ostrport_finalize(char **str, size_t buf_size, void **opaque)
343 {
344 free(*str);
345 }
346
347 static void
ostrport_close(ScmOutputStrPort * port)348 ostrport_close(ScmOutputStrPort *port)
349 {
350 SCM_PORT_ASSERT(port->finalize);
351
352 /* To suppress the "dereferencing type-punned pointer will break
353 * strict-aliasing rules" warning on gcc, apply a reinterpret_cast
354 * here. This operation is safe on the case. -- YamaKen 2007-01-06 */
355 (*port->finalize)((char **)(uintptr_t)&port->str,
356 port->buf_size, &port->opaque);
357 free(port);
358 }
359
360 static char *
ostrport_inspect(ScmOutputStrPort * port)361 ostrport_inspect(ScmOutputStrPort *port)
362 {
363 return SCM_PORT_STRDUP("string");
364 }
365
366 static scm_ichar_t
ostrport_get_byte(ScmOutputStrPort * port)367 ostrport_get_byte(ScmOutputStrPort *port)
368 {
369 SCM_PORT_ERROR_INVALID_OPERATION(BYTE, port, ScmOutputStrPort);
370 /* NOTREACHED */
371 }
372
373 static scm_ichar_t
ostrport_peek_byte(ScmOutputStrPort * port)374 ostrport_peek_byte(ScmOutputStrPort *port)
375 {
376 SCM_PORT_ERROR_INVALID_OPERATION(BYTE, port, ScmOutputStrPort);
377 /* NOTREACHED */
378 }
379
380 static scm_bool
ostrport_byte_readyp(ScmOutputStrPort * port)381 ostrport_byte_readyp(ScmOutputStrPort *port)
382 {
383 SCM_PORT_ERROR_INVALID_OPERATION(BYTE, port, ScmOutputStrPort);
384 /* NOTREACHED */
385 }
386
387 static void
ostrport_puts(ScmOutputStrPort * port,const char * str)388 ostrport_puts(ScmOutputStrPort *port, const char *str)
389 {
390 ostrport_append(port, strlen(str), (const scm_byte_t *)str);
391 }
392
393 static void
ostrport_write(ScmOutputStrPort * port,size_t nbytes,const char * buf)394 ostrport_write(ScmOutputStrPort *port, size_t nbytes, const char *buf)
395 {
396 ostrport_append(port, nbytes, (const scm_byte_t *)buf);
397 }
398
399 static void
ostrport_flush(ScmOutputStrPort * port)400 ostrport_flush(ScmOutputStrPort *port)
401 {
402 }
403
404 static void
ostrport_append(ScmOutputStrPort * port,size_t len,const scm_byte_t * str)405 ostrport_append(ScmOutputStrPort *port, size_t len, const scm_byte_t *str)
406 {
407 SCM_PORT_ASSERT(str);
408
409 /* extend the buffer */
410 if (port->buf_size - port->cur < len + sizeof("")) {
411 if (!port->buf_size)
412 port->buf_size = sizeof("");
413
414 port->buf_size += len;
415 port->str = SCM_PORT_REALLOC(port->str, port->buf_size);
416 }
417
418 memcpy(port->str + port->cur, str, len);
419 port->cur += len;
420 port->str[port->cur] = '\0';
421 }
422