2 /* $NetBSD: citrus_prop.c,v 1.4 2011/03/30 08:22:01 jruoho Exp $ */
5 * SPDX-License-Identifier: BSD-2-Clause
7 * Copyright (c)2006 Citrus Project,
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 #include <sys/cdefs.h>
45 #include "citrus_namespace.h"
46 #include "citrus_bcs.h"
47 #include "citrus_region.h"
48 #include "citrus_memstream.h"
49 #include "citrus_prop.h"
52 _citrus_prop_type_t type;
59 } _citrus_prop_object_t;
62 _citrus_prop_object_init(_citrus_prop_object_t *obj, _citrus_prop_type_t type)
66 memset(&obj->u, 0, sizeof(obj->u));
70 _citrus_prop_object_uninit(_citrus_prop_object_t *obj)
73 if (obj->type == _CITRUS_PROP_STR)
74 free(__DECONST(void *, obj->u.str));
77 static const char *xdigit = "0123456789ABCDEF";
79 #define _CITRUS_PROP_READ_UINT_COMMON(_func_, _type_, _max_) \
81 _citrus_prop_read_##_func_##_common(struct _memstream * __restrict ms, \
82 _type_ * __restrict result, int base, int neg) \
89 cutoff = _max_ / base; \
90 cutlim = _max_ % base; \
92 ch = _memstream_getc(ms); \
93 p = strchr(xdigit, _bcs_toupper(ch)); \
94 if (p == NULL || (n = (p - xdigit)) >= base) \
96 if (acc > cutoff || (acc == cutoff && n > cutlim)) \
101 _memstream_ungetc(ms, ch); \
102 *result = neg ? -acc : acc; \
105 _CITRUS_PROP_READ_UINT_COMMON(chr, int, UCHAR_MAX)
106 _CITRUS_PROP_READ_UINT_COMMON(num, uint64_t, UINT64_MAX)
107 #undef _CITRUS_PROP_READ_UINT_COMMON
109 #define _CITRUS_PROP_READ_INT(_func_, _type_) \
111 _citrus_prop_read_##_func_(struct _memstream * __restrict ms, \
112 _citrus_prop_object_t * __restrict obj) \
116 _memstream_skip_ws(ms); \
117 ch = _memstream_getc(ms); \
123 ch = _memstream_getc(ms); \
128 ch = _memstream_getc(ms); \
129 if (ch == 'x' || ch == 'X') { \
130 ch = _memstream_getc(ms); \
131 if (_bcs_isxdigit(ch) == 0) { \
132 _memstream_ungetc(ms, ch); \
138 } else if (_bcs_isdigit(ch) == 0) \
140 _memstream_ungetc(ms, ch); \
141 return (_citrus_prop_read_##_func_##_common \
142 (ms, &obj->u._func_, base, neg)); \
144 _CITRUS_PROP_READ_INT(chr, int)
145 _CITRUS_PROP_READ_INT(num, uint64_t)
146 #undef _CITRUS_PROP_READ_INT
149 _citrus_prop_read_character_common(struct _memstream * __restrict ms,
150 int * __restrict result)
154 ch = _memstream_getc(ms);
158 ch = _memstream_getc(ms);
182 case '0': case '1': case '2': case '3':
183 case '4': case '5': case '6': case '7':
184 _memstream_ungetc(ms, ch);
188 return (_citrus_prop_read_chr_common(ms, result,
200 _citrus_prop_read_character(struct _memstream * __restrict ms,
201 _citrus_prop_object_t * __restrict obj)
205 _memstream_skip_ws(ms);
206 ch = _memstream_getc(ms);
208 _memstream_ungetc(ms, ch);
209 return (_citrus_prop_read_chr(ms, obj));
211 errnum = _citrus_prop_read_character_common(ms, &ch);
215 ch = _memstream_getc(ms);
222 _citrus_prop_read_bool(struct _memstream * __restrict ms,
223 _citrus_prop_object_t * __restrict obj)
226 _memstream_skip_ws(ms);
227 switch (_bcs_tolower(_memstream_getc(ms))) {
229 if (_bcs_tolower(_memstream_getc(ms)) == 'r' &&
230 _bcs_tolower(_memstream_getc(ms)) == 'u' &&
231 _bcs_tolower(_memstream_getc(ms)) == 'e') {
232 obj->u.boolean = true;
237 if (_bcs_tolower(_memstream_getc(ms)) == 'a' &&
238 _bcs_tolower(_memstream_getc(ms)) == 'l' &&
239 _bcs_tolower(_memstream_getc(ms)) == 's' &&
240 _bcs_tolower(_memstream_getc(ms)) == 'e') {
241 obj->u.boolean = false;
249 _citrus_prop_read_str(struct _memstream * __restrict ms,
250 _citrus_prop_object_t * __restrict obj)
252 int ch, errnum, quot;
254 #define _CITRUS_PROP_STR_BUFSIZ 512
257 m = _CITRUS_PROP_STR_BUFSIZ;
262 _memstream_skip_ws(ms);
263 quot = _memstream_getc(ms);
269 _memstream_ungetc(ms, quot);
272 case '\"': case '\'':
281 m = _CITRUS_PROP_STR_BUFSIZ;
282 t = realloc(s, n + m);
289 ch = _memstream_getc(ms);
290 if (quot == ch || (quot == EOF &&
291 (ch == ';' || _bcs_isspace(ch)))) {
294 obj->u.str = (const char *)s;
297 _memstream_ungetc(ms, ch);
298 errnum = _citrus_prop_read_character_common(ms, &ch);
308 #undef _CITRUS_PROP_STR_BUFSIZ
311 typedef int (*_citrus_prop_read_type_t)(struct _memstream * __restrict,
312 _citrus_prop_object_t * __restrict);
314 static const _citrus_prop_read_type_t readers[] = {
315 _citrus_prop_read_bool,
316 _citrus_prop_read_str,
317 _citrus_prop_read_character,
318 _citrus_prop_read_num,
322 _citrus_prop_read_symbol(struct _memstream * __restrict ms,
323 char * __restrict s, size_t n)
328 for (m = 0; m < n; ++m) {
329 ch = _memstream_getc(ms);
330 if (ch != '_' && _bcs_isalnum(ch) == 0)
334 ch = _memstream_getc(ms);
335 if (ch == '_' || _bcs_isalnum(ch) != 0)
339 _memstream_ungetc(ms, ch);
346 _citrus_prop_parse_element(struct _memstream * __restrict ms,
347 const _citrus_prop_hint_t * __restrict hints, void * __restrict context)
350 #define _CITRUS_PROP_HINT_NAME_LEN_MAX 255
351 char name[_CITRUS_PROP_HINT_NAME_LEN_MAX + 1];
352 const _citrus_prop_hint_t *hint;
353 _citrus_prop_object_t ostart, oend;
355 errnum = _citrus_prop_read_symbol(ms, name, sizeof(name));
358 for (hint = hints; hint->name != NULL; ++hint)
359 if (_citrus_bcs_strcasecmp(name, hint->name) == 0)
364 _memstream_skip_ws(ms);
365 ch = _memstream_getc(ms);
366 if (ch != '=' && ch != ':')
367 _memstream_ungetc(ms, ch);
369 _citrus_prop_object_init(&ostart, hint->type);
370 _citrus_prop_object_init(&oend, hint->type);
371 errnum = (*readers[hint->type])(ms, &ostart);
374 _memstream_skip_ws(ms);
375 ch = _memstream_getc(ms);
376 switch (hint->type) {
377 case _CITRUS_PROP_BOOL:
379 case _CITRUS_PROP_STR:
384 errnum = (*readers[hint->type])(ms, &oend);
387 _memstream_skip_ws(ms);
388 ch = _memstream_getc(ms);
390 #define CALL0(_func_) \
392 errnum = (*hint->cb._func_.func)(context, \
393 hint->name, ostart.u._func_); \
395 #define CALL1(_func_) \
397 errnum = (*hint->cb._func_.func)(context, \
398 hint->name, ostart.u._func_, oend.u._func_);\
400 switch (hint->type) {
401 case _CITRUS_PROP_BOOL:
404 case _CITRUS_PROP_STR:
407 case _CITRUS_PROP_CHR:
410 case _CITRUS_PROP_NUM:
419 _citrus_prop_object_uninit(&ostart);
420 _citrus_prop_object_uninit(&oend);
425 _memstream_ungetc(ms, ch);
430 _citrus_prop_parse_variable(const _citrus_prop_hint_t * __restrict hints,
431 void * __restrict context, const void *var, size_t lenvar)
433 struct _memstream ms;
436 _memstream_bind_ptr(&ms, __DECONST(void *, var), lenvar);
438 _memstream_skip_ws(&ms);
439 ch = _memstream_getc(&ms);
440 if (ch == EOF || ch == '\0')
442 _memstream_ungetc(&ms, ch);
443 errnum = _citrus_prop_parse_element(&ms, hints, context);