1 /* $NetBSD: citrus_prop.c,v 1.5 2014/06/24 22:24:18 spz Exp $ */
4 * Copyright (c)2006 Citrus Project,
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 #include <sys/cdefs.h>
31 #if defined(LIBC_SCCS) && !defined(lint)
32 __RCSID("$NetBSD: citrus_prop.c,v 1.5 2014/06/24 22:24:18 spz Exp $");
33 #endif /* LIBC_SCCS and not lint */
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
)
64 _DIAGASSERT(obj
!= NULL
);
67 memset(&obj
->u
, 0, sizeof(obj
->u
));
71 _citrus_prop_object_uninit(_citrus_prop_object_t
*obj
)
73 _DIAGASSERT(obj
!= NULL
);
75 if (obj
->type
== _CITRUS_PROP_STR
)
76 free(__UNCONST(obj
->u
.str
));
79 static const char *xdigit
= "0123456789ABCDEF";
81 #define _CITRUS_PROP_READ_UINT_COMMON(_func_, _type_, _max_) \
83 _citrus_prop_read_##_func_##_common(struct _memstream * __restrict ms, \
84 _type_ * __restrict result, int base) \
90 _DIAGASSERT(ms != NULL); \
91 _DIAGASSERT(result != NULL); \
94 cutoff = _max_ / base; \
95 cutlim = _max_ % base; \
97 ch = _memstream_getc(ms); \
98 p = strchr(xdigit, _bcs_toupper(ch)); \
99 if (p == NULL || (n = (p - xdigit)) >= base) \
101 if (acc > cutoff || (acc == cutoff && n > cutlim)) \
106 _memstream_ungetc(ms, ch); \
110 _CITRUS_PROP_READ_UINT_COMMON(chr
, int, UCHAR_MAX
)
111 _CITRUS_PROP_READ_UINT_COMMON(num
, uint64_t, UINT64_MAX
)
112 #undef _CITRUS_PROP_READ_UINT_COMMON
114 #define _CITRUS_PROP_READ_INT(_func_, _type_) \
116 _citrus_prop_read_##_func_(struct _memstream * __restrict ms, \
117 _citrus_prop_object_t * __restrict obj) \
121 _DIAGASSERT(ms != NULL); \
122 _DIAGASSERT(obj != NULL); \
124 _memstream_skip_ws(ms); \
125 ch = _memstream_getc(ms); \
131 ch = _memstream_getc(ms); \
136 ch = _memstream_getc(ms); \
137 if (ch == 'x' || ch == 'X') { \
138 ch = _memstream_getc(ms); \
139 if (_bcs_isxdigit(ch) == 0) { \
140 _memstream_ungetc(ms, ch); \
146 } else if (_bcs_isdigit(ch) == 0) \
148 _memstream_ungetc(ms, ch); \
149 return _citrus_prop_read_##_func_##_common \
150 (ms, &obj->u._func_, base); \
152 _CITRUS_PROP_READ_INT(chr
, int)
153 _CITRUS_PROP_READ_INT(num
, uint64_t)
154 #undef _CITRUS_PROP_READ_INT
157 _citrus_prop_read_character_common(struct _memstream
* __restrict ms
,
158 int * __restrict result
)
162 _DIAGASSERT(ms
!= NULL
);
163 _DIAGASSERT(result
!= NULL
);
165 ch
= _memstream_getc(ms
);
169 ch
= _memstream_getc(ms
);
172 case 'a': *result
= '\a'; break;
173 case 'b': *result
= '\b'; break;
174 case 'f': *result
= '\f'; break;
175 case 'n': *result
= '\n'; break;
176 case 'r': *result
= '\r'; break;
177 case 't': *result
= '\t'; break;
178 case 'v': *result
= '\v'; break;
180 case '0': case '1': case '2': case '3':
181 case '4': case '5': case '6': case '7':
182 _memstream_ungetc(ms
, ch
);
185 return _citrus_prop_read_chr_common(ms
, result
, base
);
196 _citrus_prop_read_character(struct _memstream
* __restrict ms
,
197 _citrus_prop_object_t
* __restrict obj
)
201 _DIAGASSERT(ms
!= NULL
);
202 _DIAGASSERT(obj
!= NULL
);
204 _memstream_skip_ws(ms
);
205 ch
= _memstream_getc(ms
);
207 _memstream_ungetc(ms
, ch
);
208 return _citrus_prop_read_chr(ms
, obj
);
210 errnum
= _citrus_prop_read_character_common(ms
, &ch
);
214 ch
= _memstream_getc(ms
);
221 _citrus_prop_read_bool(struct _memstream
* __restrict ms
,
222 _citrus_prop_object_t
* __restrict obj
)
224 _DIAGASSERT(ms
!= NULL
);
225 _DIAGASSERT(obj
!= NULL
);
227 _memstream_skip_ws(ms
);
228 switch (_bcs_tolower(_memstream_getc(ms
))) {
230 if (_bcs_tolower(_memstream_getc(ms
)) == 'r' &&
231 _bcs_tolower(_memstream_getc(ms
)) == 'u' &&
232 _bcs_tolower(_memstream_getc(ms
)) == 'e') {
233 obj
->u
.boolean
= true;
238 if (_bcs_tolower(_memstream_getc(ms
)) == 'a' &&
239 _bcs_tolower(_memstream_getc(ms
)) == 'l' &&
240 _bcs_tolower(_memstream_getc(ms
)) == 's' &&
241 _bcs_tolower(_memstream_getc(ms
)) == 'e') {
242 obj
->u
.boolean
= false;
250 _citrus_prop_read_str(struct _memstream
* __restrict ms
,
251 _citrus_prop_object_t
* __restrict obj
)
253 int errnum
, quot
, ch
;
255 #define _CITRUS_PROP_STR_BUFSIZ 512
258 _DIAGASSERT(ms
!= NULL
);
259 _DIAGASSERT(obj
!= NULL
);
261 m
= _CITRUS_PROP_STR_BUFSIZ
;
266 _memstream_skip_ws(ms
);
267 quot
= _memstream_getc(ms
);
272 _memstream_ungetc(ms
, quot
);
275 case '\"': case '\'':
284 m
= _CITRUS_PROP_STR_BUFSIZ
;
285 t
= realloc(s
, n
+ m
);
292 ch
= _memstream_getc(ms
);
293 if (quot
== ch
|| (quot
== EOF
&&
294 (ch
== ';' || _bcs_isspace(ch
)))) {
297 obj
->u
.str
= (const char *)s
;
300 _memstream_ungetc(ms
, ch
);
301 errnum
= _citrus_prop_read_character_common(ms
, &ch
);
309 #undef _CITRUS_PROP_STR_BUFSIZ
312 typedef int (*_citrus_prop_read_type_t
)(struct _memstream
* __restrict
,
313 _citrus_prop_object_t
* __restrict
);
315 static const _citrus_prop_read_type_t readers
[] = {
316 _citrus_prop_read_bool
,
317 _citrus_prop_read_str
,
318 _citrus_prop_read_character
,
319 _citrus_prop_read_num
,
323 _citrus_prop_read_symbol(struct _memstream
* __restrict ms
,
324 char * __restrict s
, size_t n
)
329 _DIAGASSERT(ms
!= NULL
);
330 _DIAGASSERT(s
!= NULL
);
333 for (m
= 0; m
< n
; ++m
) {
334 ch
= _memstream_getc(ms
);
335 if (ch
!= '_' && _bcs_isalnum(ch
) == 0)
339 ch
= _memstream_getc(ms
);
340 if (ch
== '_' || _bcs_isalnum(ch
) != 0)
344 _memstream_ungetc(ms
, ch
);
351 _citrus_prop_parse_element(struct _memstream
* __restrict ms
,
352 const _citrus_prop_hint_t
* __restrict hints
,
353 void * __restrict context
)
356 #define _CITRUS_PROP_HINT_NAME_LEN_MAX 255
357 char name
[_CITRUS_PROP_HINT_NAME_LEN_MAX
+ 1];
358 const _citrus_prop_hint_t
*hint
;
359 _citrus_prop_object_t ostart
, oend
;
361 _DIAGASSERT(ms
!= NULL
);
362 _DIAGASSERT(hints
!= NULL
);
364 errnum
= _citrus_prop_read_symbol(ms
, name
, sizeof(name
));
367 for (hint
= hints
; hint
->name
!= NULL
; ++hint
) {
368 if (_citrus_bcs_strcasecmp(name
, hint
->name
) == 0)
374 _memstream_skip_ws(ms
);
375 ch
= _memstream_getc(ms
);
376 if (ch
!= '=' && ch
!= ':')
377 _memstream_ungetc(ms
, ch
);
379 _citrus_prop_object_init(&ostart
, hint
->type
);
380 _citrus_prop_object_init(&oend
, hint
->type
);
381 errnum
= (*readers
[hint
->type
])(ms
, &ostart
);
384 _memstream_skip_ws(ms
);
385 ch
= _memstream_getc(ms
);
386 switch (hint
->type
) {
387 case _CITRUS_PROP_BOOL
:
388 case _CITRUS_PROP_STR
:
393 errnum
= (*readers
[hint
->type
])(ms
, &oend
);
396 _memstream_skip_ws(ms
);
397 ch
= _memstream_getc(ms
);
399 #define CALL0(_func_) \
401 _DIAGASSERT(hint->cb._func_.func != NULL); \
402 errnum = (*hint->cb._func_.func)(context, \
403 hint->name, ostart.u._func_); \
404 } while (/*CONSTCOND*/0)
405 #define CALL1(_func_) \
407 _DIAGASSERT(hint->cb._func_.func != NULL); \
408 errnum = (*hint->cb._func_.func)(context, \
409 hint->name, ostart.u._func_, oend.u._func_);\
410 } while (/*CONSTCOND*/0)
412 switch (hint
->type
) {
414 case _CITRUS_PROP_BOOL
:
418 case _CITRUS_PROP_STR
:
422 case _CITRUS_PROP_CHR
:
426 case _CITRUS_PROP_NUM
:
436 _citrus_prop_object_uninit(&ostart
);
437 _citrus_prop_object_uninit(&oend
);
442 _memstream_ungetc(ms
, ch
);
447 _citrus_prop_parse_variable(const _citrus_prop_hint_t
* __restrict hints
,
448 void * __restrict context
, const void *var
, size_t lenvar
)
450 struct _memstream ms
;
453 _DIAGASSERT(hints
!= NULL
);
455 _memstream_bind_ptr(&ms
, __UNCONST(var
), lenvar
);
457 _memstream_skip_ws(&ms
);
458 ch
= _memstream_getc(&ms
);
459 if (ch
== EOF
|| ch
== '\0')
461 _memstream_ungetc(&ms
, ch
);
462 errnum
= _citrus_prop_parse_element(&ms
, hints
, context
);