2 /* $NetBSD: citrus_prop.c,v 1.3 2006/11/22 23:47:21 tnozaki Exp $ */
5 * Copyright (c)2006 Citrus Project,
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 #include <sys/cdefs.h>
43 #include "citrus_namespace.h"
44 #include "citrus_bcs.h"
45 #include "citrus_region.h"
46 #include "citrus_memstream.h"
47 #include "citrus_prop.h"
50 _citrus_prop_type_t type;
57 } _citrus_prop_object_t;
60 _citrus_prop_object_init(_citrus_prop_object_t *obj, _citrus_prop_type_t type)
64 memset(&obj->u, 0, sizeof(obj->u));
68 _citrus_prop_object_uninit(_citrus_prop_object_t *obj)
71 if (obj->type == _CITRUS_PROP_STR)
72 free(__DECONST(void *, obj->u.str));
75 static const char *xdigit = "0123456789ABCDEF";
77 #define _CITRUS_PROP_READ_UINT_COMMON(_func_, _type_, _max_) \
79 _citrus_prop_read_##_func_##_common(struct _memstream * __restrict ms, \
80 _type_ * __restrict result, int base) \
87 cutoff = _max_ / base; \
88 cutlim = _max_ % base; \
90 ch = _memstream_getc(ms); \
91 p = strchr(xdigit, _bcs_toupper(ch)); \
92 if (p == NULL || (n = (p - xdigit)) >= base) \
94 if (acc > cutoff || (acc == cutoff && n > cutlim)) \
99 _memstream_ungetc(ms, ch); \
103 _CITRUS_PROP_READ_UINT_COMMON(chr, int, UCHAR_MAX)
104 _CITRUS_PROP_READ_UINT_COMMON(num, uint64_t, UINT64_MAX)
105 #undef _CITRUS_PROP_READ_UINT_COMMON
107 #define _CITRUS_PROP_READ_INT(_func_, _type_) \
109 _citrus_prop_read_##_func_(struct _memstream * __restrict ms, \
110 _citrus_prop_object_t * __restrict obj) \
114 _memstream_skip_ws(ms); \
115 ch = _memstream_getc(ms); \
121 ch = _memstream_getc(ms); \
126 ch = _memstream_getc(ms); \
127 if (ch == 'x' || ch == 'X') { \
128 ch = _memstream_getc(ms); \
129 if (_bcs_isxdigit(ch) == 0) { \
130 _memstream_ungetc(ms, ch); \
136 } else if (_bcs_isdigit(ch) == 0) \
138 _memstream_ungetc(ms, ch); \
139 return (_citrus_prop_read_##_func_##_common \
140 (ms, &obj->u._func_, base)); \
142 _CITRUS_PROP_READ_INT(chr, int)
143 _CITRUS_PROP_READ_INT(num, uint64_t)
144 #undef _CITRUS_PROP_READ_INT
147 _citrus_prop_read_character_common(struct _memstream * __restrict ms,
148 int * __restrict result)
152 ch = _memstream_getc(ms);
156 ch = _memstream_getc(ms);
180 case '0': case '1': case '2': case '3':
181 case '4': case '5': case '6': case '7':
182 _memstream_ungetc(ms, ch);
186 return (_citrus_prop_read_chr_common(ms, result, base));
197 _citrus_prop_read_character(struct _memstream * __restrict ms,
198 _citrus_prop_object_t * __restrict obj)
202 _memstream_skip_ws(ms);
203 ch = _memstream_getc(ms);
205 _memstream_ungetc(ms, ch);
206 return (_citrus_prop_read_chr(ms, obj));
208 errnum = _citrus_prop_read_character_common(ms, &ch);
212 ch = _memstream_getc(ms);
219 _citrus_prop_read_bool(struct _memstream * __restrict ms,
220 _citrus_prop_object_t * __restrict obj)
223 _memstream_skip_ws(ms);
224 switch (_bcs_tolower(_memstream_getc(ms))) {
226 if (_bcs_tolower(_memstream_getc(ms)) == 'r' &&
227 _bcs_tolower(_memstream_getc(ms)) == 'u' &&
228 _bcs_tolower(_memstream_getc(ms)) == 'e') {
229 obj->u.boolean = true;
234 if (_bcs_tolower(_memstream_getc(ms)) == 'a' &&
235 _bcs_tolower(_memstream_getc(ms)) == 'l' &&
236 _bcs_tolower(_memstream_getc(ms)) == 's' &&
237 _bcs_tolower(_memstream_getc(ms)) == 'e') {
238 obj->u.boolean = false;
246 _citrus_prop_read_str(struct _memstream * __restrict ms,
247 _citrus_prop_object_t * __restrict obj)
249 int ch, errnum, quot;
251 #define _CITRUS_PROP_STR_BUFSIZ 512
254 m = _CITRUS_PROP_STR_BUFSIZ;
259 _memstream_skip_ws(ms);
260 quot = _memstream_getc(ms);
266 _memstream_ungetc(ms, quot);
269 case '\"': case '\'':
278 m = _CITRUS_PROP_STR_BUFSIZ;
279 t = realloc(s, n + m);
286 ch = _memstream_getc(ms);
287 if (quot == ch || (quot == EOF &&
288 (ch == ';' || _bcs_isspace(ch)))) {
291 obj->u.str = (const char *)s;
294 _memstream_ungetc(ms, ch);
295 errnum = _citrus_prop_read_character_common(ms, &ch);
303 #undef _CITRUS_PROP_STR_BUFSIZ
306 typedef int (*_citrus_prop_read_type_t)(struct _memstream * __restrict,
307 _citrus_prop_object_t * __restrict);
309 static const _citrus_prop_read_type_t readers[] = {
310 _citrus_prop_read_bool,
311 _citrus_prop_read_str,
312 _citrus_prop_read_character,
313 _citrus_prop_read_num,
317 _citrus_prop_read_symbol(struct _memstream * __restrict ms,
318 char * __restrict s, size_t n)
323 for (m = 0; m < n; ++m) {
324 ch = _memstream_getc(ms);
325 if (ch != '_' && _bcs_isalnum(ch) == 0)
329 ch = _memstream_getc(ms);
330 if (ch == '_' || _bcs_isalnum(ch) != 0)
334 _memstream_ungetc(ms, ch);
341 _citrus_prop_parse_element(struct _memstream * __restrict ms,
342 const _citrus_prop_hint_t * __restrict hints, void ** __restrict context)
345 #define _CITRUS_PROP_HINT_NAME_LEN_MAX 255
346 char name[_CITRUS_PROP_HINT_NAME_LEN_MAX + 1];
347 const _citrus_prop_hint_t *hint;
348 _citrus_prop_object_t ostart, oend;
350 errnum = _citrus_prop_read_symbol(ms, name, sizeof(name));
353 for (hint = hints; hint->name != NULL; ++hint)
354 if (_citrus_bcs_strcasecmp(name, hint->name) == 0)
359 _memstream_skip_ws(ms);
360 ch = _memstream_getc(ms);
361 if (ch != '=' && ch != ':')
362 _memstream_ungetc(ms, ch);
364 _citrus_prop_object_init(&ostart, hint->type);
365 _citrus_prop_object_init(&oend, hint->type);
366 errnum = (*readers[hint->type])(ms, &ostart);
369 _memstream_skip_ws(ms);
370 ch = _memstream_getc(ms);
371 switch (hint->type) {
372 case _CITRUS_PROP_BOOL:
374 case _CITRUS_PROP_STR:
379 errnum = (*readers[hint->type])(ms, &oend);
382 _memstream_skip_ws(ms);
383 ch = _memstream_getc(ms);
385 #define CALL0(_func_) \
387 errnum = (*hint->cb._func_.func)(context, \
388 hint->name, ostart.u._func_); \
390 #define CALL1(_func_) \
392 errnum = (*hint->cb._func_.func)(context, \
393 hint->name, ostart.u._func_, oend.u._func_);\
395 switch (hint->type) {
396 case _CITRUS_PROP_BOOL:
399 case _CITRUS_PROP_STR:
402 case _CITRUS_PROP_CHR:
405 case _CITRUS_PROP_NUM:
414 _citrus_prop_object_uninit(&ostart);
415 _citrus_prop_object_uninit(&oend);
420 _memstream_ungetc(ms, ch);
425 _citrus_prop_parse_variable(const _citrus_prop_hint_t * __restrict hints,
426 void * __restrict context, const void *var, size_t lenvar)
428 struct _memstream ms;
431 _memstream_bind_ptr(&ms, __DECONST(void *, var), lenvar);
433 _memstream_skip_ws(&ms);
434 ch = _memstream_getc(&ms);
435 if (ch == EOF || ch == '\0')
437 _memstream_ungetc(&ms, ch);
438 errnum = _citrus_prop_parse_element(
439 &ms, hints, (void ** __restrict)context);