1bdcf3f2bSJohn Marino /* $FreeBSD: head/lib/libc/iconv/citrus_prop.c 281798 2015-04-20 22:09:50Z pfg $ */
2bdcf3f2bSJohn Marino /* $NetBSD: citrus_prop.c,v 1.4 2011/03/30 08:22:01 jruoho Exp $ */
352347f71SHasso Tepper
452347f71SHasso Tepper /*-
552347f71SHasso Tepper * Copyright (c)2006 Citrus Project,
652347f71SHasso Tepper * All rights reserved.
752347f71SHasso Tepper *
852347f71SHasso Tepper * Redistribution and use in source and binary forms, with or without
952347f71SHasso Tepper * modification, are permitted provided that the following conditions
1052347f71SHasso Tepper * are met:
1152347f71SHasso Tepper * 1. Redistributions of source code must retain the above copyright
1252347f71SHasso Tepper * notice, this list of conditions and the following disclaimer.
1352347f71SHasso Tepper * 2. Redistributions in binary form must reproduce the above copyright
1452347f71SHasso Tepper * notice, this list of conditions and the following disclaimer in the
1552347f71SHasso Tepper * documentation and/or other materials provided with the distribution.
1652347f71SHasso Tepper *
1752347f71SHasso Tepper * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1852347f71SHasso Tepper * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1952347f71SHasso Tepper * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2052347f71SHasso Tepper * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2152347f71SHasso Tepper * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2252347f71SHasso Tepper * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2352347f71SHasso Tepper * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2452347f71SHasso Tepper * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2552347f71SHasso Tepper * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2652347f71SHasso Tepper * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2752347f71SHasso Tepper * SUCH DAMAGE.
2852347f71SHasso Tepper *
2952347f71SHasso Tepper */
3052347f71SHasso Tepper
310d5acd74SJohn Marino #include <sys/cdefs.h>
320d5acd74SJohn Marino
3352347f71SHasso Tepper #include <assert.h>
3452347f71SHasso Tepper #include <errno.h>
350d5acd74SJohn Marino #include <limits.h>
360d5acd74SJohn Marino #include <stdbool.h>
3752347f71SHasso Tepper #include <stddef.h>
3852347f71SHasso Tepper #include <stdio.h>
3952347f71SHasso Tepper #include <stdint.h>
4052347f71SHasso Tepper #include <stdlib.h>
4152347f71SHasso Tepper #include <string.h>
4252347f71SHasso Tepper
4352347f71SHasso Tepper #include "citrus_namespace.h"
4452347f71SHasso Tepper #include "citrus_bcs.h"
4552347f71SHasso Tepper #include "citrus_region.h"
4652347f71SHasso Tepper #include "citrus_memstream.h"
4752347f71SHasso Tepper #include "citrus_prop.h"
4852347f71SHasso Tepper
4952347f71SHasso Tepper typedef struct {
5052347f71SHasso Tepper _citrus_prop_type_t type;
5152347f71SHasso Tepper union {
5252347f71SHasso Tepper const char *str;
530d5acd74SJohn Marino int chr;
540d5acd74SJohn Marino bool boolean;
5552347f71SHasso Tepper uint64_t num;
5652347f71SHasso Tepper } u;
5752347f71SHasso Tepper } _citrus_prop_object_t;
5852347f71SHasso Tepper
5952347f71SHasso Tepper static __inline void
_citrus_prop_object_init(_citrus_prop_object_t * obj,_citrus_prop_type_t type)6052347f71SHasso Tepper _citrus_prop_object_init(_citrus_prop_object_t *obj, _citrus_prop_type_t type)
6152347f71SHasso Tepper {
6252347f71SHasso Tepper
6352347f71SHasso Tepper obj->type = type;
6452347f71SHasso Tepper memset(&obj->u, 0, sizeof(obj->u));
6552347f71SHasso Tepper }
6652347f71SHasso Tepper
6752347f71SHasso Tepper static __inline void
_citrus_prop_object_uninit(_citrus_prop_object_t * obj)6852347f71SHasso Tepper _citrus_prop_object_uninit(_citrus_prop_object_t *obj)
6952347f71SHasso Tepper {
7052347f71SHasso Tepper
7152347f71SHasso Tepper if (obj->type == _CITRUS_PROP_STR)
7252347f71SHasso Tepper free(__DECONST(void *, obj->u.str));
7352347f71SHasso Tepper }
7452347f71SHasso Tepper
7552347f71SHasso Tepper static const char *xdigit = "0123456789ABCDEF";
7652347f71SHasso Tepper
7752347f71SHasso Tepper #define _CITRUS_PROP_READ_UINT_COMMON(_func_, _type_, _max_) \
7852347f71SHasso Tepper static int \
7952347f71SHasso Tepper _citrus_prop_read_##_func_##_common(struct _memstream * __restrict ms, \
8052347f71SHasso Tepper _type_ * __restrict result, int base) \
8152347f71SHasso Tepper { \
8252347f71SHasso Tepper _type_ acc, cutoff; \
830d5acd74SJohn Marino int ch, cutlim, n; \
8452347f71SHasso Tepper char *p; \
8552347f71SHasso Tepper \
8652347f71SHasso Tepper acc = (_type_)0; \
8752347f71SHasso Tepper cutoff = _max_ / base; \
8852347f71SHasso Tepper cutlim = _max_ % base; \
8952347f71SHasso Tepper for (;;) { \
9052347f71SHasso Tepper ch = _memstream_getc(ms); \
9152347f71SHasso Tepper p = strchr(xdigit, _bcs_toupper(ch)); \
9252347f71SHasso Tepper if (p == NULL || (n = (p - xdigit)) >= base) \
9352347f71SHasso Tepper break; \
9452347f71SHasso Tepper if (acc > cutoff || (acc == cutoff && n > cutlim)) \
9552347f71SHasso Tepper break; \
9652347f71SHasso Tepper acc *= base; \
9752347f71SHasso Tepper acc += n; \
9852347f71SHasso Tepper } \
9952347f71SHasso Tepper _memstream_ungetc(ms, ch); \
10052347f71SHasso Tepper *result = acc; \
1010d5acd74SJohn Marino return (0); \
10252347f71SHasso Tepper }
_CITRUS_PROP_READ_UINT_COMMON(chr,int,UCHAR_MAX)10352347f71SHasso Tepper _CITRUS_PROP_READ_UINT_COMMON(chr, int, UCHAR_MAX)
10452347f71SHasso Tepper _CITRUS_PROP_READ_UINT_COMMON(num, uint64_t, UINT64_MAX)
10552347f71SHasso Tepper #undef _CITRUS_PROP_READ_UINT_COMMON
10652347f71SHasso Tepper
10752347f71SHasso Tepper #define _CITRUS_PROP_READ_INT(_func_, _type_) \
10852347f71SHasso Tepper static int \
10952347f71SHasso Tepper _citrus_prop_read_##_func_(struct _memstream * __restrict ms, \
11052347f71SHasso Tepper _citrus_prop_object_t * __restrict obj) \
11152347f71SHasso Tepper { \
112cf515c3aSJohn Marino int base, ch; \
11352347f71SHasso Tepper \
11452347f71SHasso Tepper _memstream_skip_ws(ms); \
11552347f71SHasso Tepper ch = _memstream_getc(ms); \
11652347f71SHasso Tepper switch (ch) { \
11752347f71SHasso Tepper case '+': \
11852347f71SHasso Tepper ch = _memstream_getc(ms); \
11952347f71SHasso Tepper } \
12052347f71SHasso Tepper base = 10; \
12152347f71SHasso Tepper if (ch == '0') { \
12252347f71SHasso Tepper base -= 2; \
12352347f71SHasso Tepper ch = _memstream_getc(ms); \
12452347f71SHasso Tepper if (ch == 'x' || ch == 'X') { \
12552347f71SHasso Tepper ch = _memstream_getc(ms); \
12652347f71SHasso Tepper if (_bcs_isxdigit(ch) == 0) { \
12752347f71SHasso Tepper _memstream_ungetc(ms, ch); \
12852347f71SHasso Tepper obj->u._func_ = 0; \
1290d5acd74SJohn Marino return (0); \
13052347f71SHasso Tepper } \
13152347f71SHasso Tepper base += 8; \
13252347f71SHasso Tepper } \
13352347f71SHasso Tepper } else if (_bcs_isdigit(ch) == 0) \
1340d5acd74SJohn Marino return (EINVAL); \
13552347f71SHasso Tepper _memstream_ungetc(ms, ch); \
1360d5acd74SJohn Marino return (_citrus_prop_read_##_func_##_common \
1370d5acd74SJohn Marino (ms, &obj->u._func_, base)); \
13852347f71SHasso Tepper }
13952347f71SHasso Tepper _CITRUS_PROP_READ_INT(chr, int)
14052347f71SHasso Tepper _CITRUS_PROP_READ_INT(num, uint64_t)
14152347f71SHasso Tepper #undef _CITRUS_PROP_READ_INT
14252347f71SHasso Tepper
14352347f71SHasso Tepper static int
14452347f71SHasso Tepper _citrus_prop_read_character_common(struct _memstream * __restrict ms,
14552347f71SHasso Tepper int * __restrict result)
14652347f71SHasso Tepper {
1470d5acd74SJohn Marino int base, ch;
14852347f71SHasso Tepper
14952347f71SHasso Tepper ch = _memstream_getc(ms);
1500d5acd74SJohn Marino if (ch != '\\')
15152347f71SHasso Tepper *result = ch;
1520d5acd74SJohn Marino else {
15352347f71SHasso Tepper ch = _memstream_getc(ms);
15452347f71SHasso Tepper base = 16;
15552347f71SHasso Tepper switch (ch) {
1560d5acd74SJohn Marino case 'a':
1570d5acd74SJohn Marino *result = '\a';
1580d5acd74SJohn Marino break;
1590d5acd74SJohn Marino case 'b':
1600d5acd74SJohn Marino *result = '\b';
1610d5acd74SJohn Marino break;
1620d5acd74SJohn Marino case 'f':
1630d5acd74SJohn Marino *result = '\f';
1640d5acd74SJohn Marino break;
1650d5acd74SJohn Marino case 'n':
1660d5acd74SJohn Marino *result = '\n';
1670d5acd74SJohn Marino break;
1680d5acd74SJohn Marino case 'r':
1690d5acd74SJohn Marino *result = '\r';
1700d5acd74SJohn Marino break;
1710d5acd74SJohn Marino case 't':
1720d5acd74SJohn Marino *result = '\t';
1730d5acd74SJohn Marino break;
1740d5acd74SJohn Marino case 'v':
1750d5acd74SJohn Marino *result = '\v';
1760d5acd74SJohn Marino break;
17752347f71SHasso Tepper case '0': case '1': case '2': case '3':
17852347f71SHasso Tepper case '4': case '5': case '6': case '7':
17952347f71SHasso Tepper _memstream_ungetc(ms, ch);
18052347f71SHasso Tepper base -= 8;
1810d5acd74SJohn Marino /*FALLTHROUGH*/
18252347f71SHasso Tepper case 'x':
1830d5acd74SJohn Marino return (_citrus_prop_read_chr_common(ms, result, base));
1840d5acd74SJohn Marino /*NOTREACHED*/
18552347f71SHasso Tepper default:
18652347f71SHasso Tepper /* unknown escape */
18752347f71SHasso Tepper *result = ch;
18852347f71SHasso Tepper }
18952347f71SHasso Tepper }
1900d5acd74SJohn Marino return (0);
19152347f71SHasso Tepper }
19252347f71SHasso Tepper
19352347f71SHasso Tepper static int
_citrus_prop_read_character(struct _memstream * __restrict ms,_citrus_prop_object_t * __restrict obj)19452347f71SHasso Tepper _citrus_prop_read_character(struct _memstream * __restrict ms,
19552347f71SHasso Tepper _citrus_prop_object_t * __restrict obj)
19652347f71SHasso Tepper {
19752347f71SHasso Tepper int ch, errnum;
19852347f71SHasso Tepper
19952347f71SHasso Tepper _memstream_skip_ws(ms);
20052347f71SHasso Tepper ch = _memstream_getc(ms);
20152347f71SHasso Tepper if (ch != '\'') {
20252347f71SHasso Tepper _memstream_ungetc(ms, ch);
2030d5acd74SJohn Marino return (_citrus_prop_read_chr(ms, obj));
20452347f71SHasso Tepper }
20552347f71SHasso Tepper errnum = _citrus_prop_read_character_common(ms, &ch);
20652347f71SHasso Tepper if (errnum != 0)
2070d5acd74SJohn Marino return (errnum);
20852347f71SHasso Tepper obj->u.chr = ch;
20952347f71SHasso Tepper ch = _memstream_getc(ms);
21052347f71SHasso Tepper if (ch != '\'')
2110d5acd74SJohn Marino return (EINVAL);
2120d5acd74SJohn Marino return (0);
21352347f71SHasso Tepper }
21452347f71SHasso Tepper
21552347f71SHasso Tepper static int
_citrus_prop_read_bool(struct _memstream * __restrict ms,_citrus_prop_object_t * __restrict obj)21652347f71SHasso Tepper _citrus_prop_read_bool(struct _memstream * __restrict ms,
21752347f71SHasso Tepper _citrus_prop_object_t * __restrict obj)
21852347f71SHasso Tepper {
21952347f71SHasso Tepper
22052347f71SHasso Tepper _memstream_skip_ws(ms);
22152347f71SHasso Tepper switch (_bcs_tolower(_memstream_getc(ms))) {
22252347f71SHasso Tepper case 't':
22352347f71SHasso Tepper if (_bcs_tolower(_memstream_getc(ms)) == 'r' &&
22452347f71SHasso Tepper _bcs_tolower(_memstream_getc(ms)) == 'u' &&
22552347f71SHasso Tepper _bcs_tolower(_memstream_getc(ms)) == 'e') {
2260d5acd74SJohn Marino obj->u.boolean = true;
2270d5acd74SJohn Marino return (0);
22852347f71SHasso Tepper }
22952347f71SHasso Tepper break;
23052347f71SHasso Tepper case 'f':
23152347f71SHasso Tepper if (_bcs_tolower(_memstream_getc(ms)) == 'a' &&
23252347f71SHasso Tepper _bcs_tolower(_memstream_getc(ms)) == 'l' &&
23352347f71SHasso Tepper _bcs_tolower(_memstream_getc(ms)) == 's' &&
23452347f71SHasso Tepper _bcs_tolower(_memstream_getc(ms)) == 'e') {
2350d5acd74SJohn Marino obj->u.boolean = false;
2360d5acd74SJohn Marino return (0);
23752347f71SHasso Tepper }
23852347f71SHasso Tepper }
2390d5acd74SJohn Marino return (EINVAL);
24052347f71SHasso Tepper }
24152347f71SHasso Tepper
24252347f71SHasso Tepper static int
_citrus_prop_read_str(struct _memstream * __restrict ms,_citrus_prop_object_t * __restrict obj)24352347f71SHasso Tepper _citrus_prop_read_str(struct _memstream * __restrict ms,
24452347f71SHasso Tepper _citrus_prop_object_t * __restrict obj)
24552347f71SHasso Tepper {
2460d5acd74SJohn Marino int ch, errnum, quot;
24752347f71SHasso Tepper char *s, *t;
24852347f71SHasso Tepper #define _CITRUS_PROP_STR_BUFSIZ 512
2490d5acd74SJohn Marino size_t m, n;
25052347f71SHasso Tepper
25152347f71SHasso Tepper m = _CITRUS_PROP_STR_BUFSIZ;
25252347f71SHasso Tepper s = malloc(m);
25352347f71SHasso Tepper if (s == NULL)
2540d5acd74SJohn Marino return (ENOMEM);
25552347f71SHasso Tepper n = 0;
25652347f71SHasso Tepper _memstream_skip_ws(ms);
25752347f71SHasso Tepper quot = _memstream_getc(ms);
25852347f71SHasso Tepper switch (quot) {
25952347f71SHasso Tepper case EOF:
26052347f71SHasso Tepper goto done;
2610d5acd74SJohn Marino /*NOTREACHED*/
26252347f71SHasso Tepper case '\\':
26352347f71SHasso Tepper _memstream_ungetc(ms, quot);
26452347f71SHasso Tepper quot = EOF;
26552347f71SHasso Tepper /*FALLTHROUGH*/
26652347f71SHasso Tepper case '\"': case '\'':
26752347f71SHasso Tepper break;
26852347f71SHasso Tepper default:
26952347f71SHasso Tepper s[n] = quot;
27052347f71SHasso Tepper ++n, --m;
27152347f71SHasso Tepper quot = EOF;
27252347f71SHasso Tepper }
27352347f71SHasso Tepper for (;;) {
27452347f71SHasso Tepper if (m < 1) {
27552347f71SHasso Tepper m = _CITRUS_PROP_STR_BUFSIZ;
27652347f71SHasso Tepper t = realloc(s, n + m);
27752347f71SHasso Tepper if (t == NULL) {
27852347f71SHasso Tepper free(s);
2790d5acd74SJohn Marino return (ENOMEM);
28052347f71SHasso Tepper }
28152347f71SHasso Tepper s = t;
28252347f71SHasso Tepper }
28352347f71SHasso Tepper ch = _memstream_getc(ms);
28452347f71SHasso Tepper if (quot == ch || (quot == EOF &&
28552347f71SHasso Tepper (ch == ';' || _bcs_isspace(ch)))) {
28652347f71SHasso Tepper done:
28752347f71SHasso Tepper s[n] = '\0';
28852347f71SHasso Tepper obj->u.str = (const char *)s;
2890d5acd74SJohn Marino return (0);
29052347f71SHasso Tepper }
29152347f71SHasso Tepper _memstream_ungetc(ms, ch);
29252347f71SHasso Tepper errnum = _citrus_prop_read_character_common(ms, &ch);
293*f60c0e7fSJohn Marino if (errnum != 0) {
294*f60c0e7fSJohn Marino free(s);
2950d5acd74SJohn Marino return (errnum);
296*f60c0e7fSJohn Marino }
29752347f71SHasso Tepper s[n] = ch;
29852347f71SHasso Tepper ++n, --m;
29952347f71SHasso Tepper }
30052347f71SHasso Tepper free(s);
3010d5acd74SJohn Marino return (EINVAL);
30252347f71SHasso Tepper #undef _CITRUS_PROP_STR_BUFSIZ
30352347f71SHasso Tepper }
30452347f71SHasso Tepper
30552347f71SHasso Tepper typedef int (*_citrus_prop_read_type_t)(struct _memstream * __restrict,
30652347f71SHasso Tepper _citrus_prop_object_t * __restrict);
30752347f71SHasso Tepper
30852347f71SHasso Tepper static const _citrus_prop_read_type_t readers[] = {
30952347f71SHasso Tepper _citrus_prop_read_bool,
31052347f71SHasso Tepper _citrus_prop_read_str,
31152347f71SHasso Tepper _citrus_prop_read_character,
31252347f71SHasso Tepper _citrus_prop_read_num,
31352347f71SHasso Tepper };
31452347f71SHasso Tepper
31552347f71SHasso Tepper static __inline int
_citrus_prop_read_symbol(struct _memstream * __restrict ms,char * __restrict s,size_t n)31652347f71SHasso Tepper _citrus_prop_read_symbol(struct _memstream * __restrict ms,
31752347f71SHasso Tepper char * __restrict s, size_t n)
31852347f71SHasso Tepper {
31952347f71SHasso Tepper int ch;
32052347f71SHasso Tepper size_t m;
32152347f71SHasso Tepper
32252347f71SHasso Tepper for (m = 0; m < n; ++m) {
32352347f71SHasso Tepper ch = _memstream_getc(ms);
32452347f71SHasso Tepper if (ch != '_' && _bcs_isalnum(ch) == 0)
32552347f71SHasso Tepper goto name_found;
32652347f71SHasso Tepper s[m] = ch;
32752347f71SHasso Tepper }
32852347f71SHasso Tepper ch = _memstream_getc(ms);
32952347f71SHasso Tepper if (ch == '_' || _bcs_isalnum(ch) != 0)
3300d5acd74SJohn Marino return (EINVAL);
33152347f71SHasso Tepper
33252347f71SHasso Tepper name_found:
33352347f71SHasso Tepper _memstream_ungetc(ms, ch);
33452347f71SHasso Tepper s[m] = '\0';
33552347f71SHasso Tepper
3360d5acd74SJohn Marino return (0);
33752347f71SHasso Tepper }
33852347f71SHasso Tepper
33952347f71SHasso Tepper static int
_citrus_prop_parse_element(struct _memstream * __restrict ms,const _citrus_prop_hint_t * __restrict hints,void * __restrict context)34052347f71SHasso Tepper _citrus_prop_parse_element(struct _memstream * __restrict ms,
341bdcf3f2bSJohn Marino const _citrus_prop_hint_t * __restrict hints, void * __restrict context)
34252347f71SHasso Tepper {
34352347f71SHasso Tepper int ch, errnum;
34452347f71SHasso Tepper #define _CITRUS_PROP_HINT_NAME_LEN_MAX 255
34552347f71SHasso Tepper char name[_CITRUS_PROP_HINT_NAME_LEN_MAX + 1];
34652347f71SHasso Tepper const _citrus_prop_hint_t *hint;
34752347f71SHasso Tepper _citrus_prop_object_t ostart, oend;
34852347f71SHasso Tepper
34952347f71SHasso Tepper errnum = _citrus_prop_read_symbol(ms, name, sizeof(name));
35052347f71SHasso Tepper if (errnum != 0)
3510d5acd74SJohn Marino return (errnum);
3520d5acd74SJohn Marino for (hint = hints; hint->name != NULL; ++hint)
35352347f71SHasso Tepper if (_citrus_bcs_strcasecmp(name, hint->name) == 0)
35452347f71SHasso Tepper goto hint_found;
3550d5acd74SJohn Marino return (EINVAL);
35652347f71SHasso Tepper
35752347f71SHasso Tepper hint_found:
35852347f71SHasso Tepper _memstream_skip_ws(ms);
35952347f71SHasso Tepper ch = _memstream_getc(ms);
36052347f71SHasso Tepper if (ch != '=' && ch != ':')
36152347f71SHasso Tepper _memstream_ungetc(ms, ch);
36252347f71SHasso Tepper do {
36352347f71SHasso Tepper _citrus_prop_object_init(&ostart, hint->type);
36452347f71SHasso Tepper _citrus_prop_object_init(&oend, hint->type);
36552347f71SHasso Tepper errnum = (*readers[hint->type])(ms, &ostart);
36652347f71SHasso Tepper if (errnum != 0)
3670d5acd74SJohn Marino return (errnum);
36852347f71SHasso Tepper _memstream_skip_ws(ms);
36952347f71SHasso Tepper ch = _memstream_getc(ms);
37052347f71SHasso Tepper switch (hint->type) {
37152347f71SHasso Tepper case _CITRUS_PROP_BOOL:
3720d5acd74SJohn Marino /*FALLTHROUGH*/
37352347f71SHasso Tepper case _CITRUS_PROP_STR:
37452347f71SHasso Tepper break;
37552347f71SHasso Tepper default:
37652347f71SHasso Tepper if (ch != '-')
37752347f71SHasso Tepper break;
37852347f71SHasso Tepper errnum = (*readers[hint->type])(ms, &oend);
37952347f71SHasso Tepper if (errnum != 0)
3800d5acd74SJohn Marino return (errnum);
38152347f71SHasso Tepper _memstream_skip_ws(ms);
38252347f71SHasso Tepper ch = _memstream_getc(ms);
38352347f71SHasso Tepper }
38452347f71SHasso Tepper #define CALL0(_func_) \
38552347f71SHasso Tepper do { \
38652347f71SHasso Tepper errnum = (*hint->cb._func_.func)(context, \
38752347f71SHasso Tepper hint->name, ostart.u._func_); \
3880d5acd74SJohn Marino } while (0)
38952347f71SHasso Tepper #define CALL1(_func_) \
39052347f71SHasso Tepper do { \
39152347f71SHasso Tepper errnum = (*hint->cb._func_.func)(context, \
39252347f71SHasso Tepper hint->name, ostart.u._func_, oend.u._func_);\
3930d5acd74SJohn Marino } while (0)
39452347f71SHasso Tepper switch (hint->type) {
3950d5acd74SJohn Marino case _CITRUS_PROP_BOOL:
3960d5acd74SJohn Marino CALL0(boolean);
3970d5acd74SJohn Marino break;
3980d5acd74SJohn Marino case _CITRUS_PROP_STR:
3990d5acd74SJohn Marino CALL0(str);
4000d5acd74SJohn Marino break;
4010d5acd74SJohn Marino case _CITRUS_PROP_CHR:
4020d5acd74SJohn Marino CALL1(chr);
4030d5acd74SJohn Marino break;
4040d5acd74SJohn Marino case _CITRUS_PROP_NUM:
4050d5acd74SJohn Marino CALL1(num);
4060d5acd74SJohn Marino break;
40752347f71SHasso Tepper default:
40852347f71SHasso Tepper abort();
40952347f71SHasso Tepper /*NOTREACHED*/
41052347f71SHasso Tepper }
41152347f71SHasso Tepper #undef CALL0
41252347f71SHasso Tepper #undef CALL1
41352347f71SHasso Tepper _citrus_prop_object_uninit(&ostart);
41452347f71SHasso Tepper _citrus_prop_object_uninit(&oend);
41552347f71SHasso Tepper if (errnum != 0)
4160d5acd74SJohn Marino return (errnum);
41752347f71SHasso Tepper } while (ch == ',');
41852347f71SHasso Tepper if (ch != ';')
41952347f71SHasso Tepper _memstream_ungetc(ms, ch);
4200d5acd74SJohn Marino return (0);
42152347f71SHasso Tepper }
42252347f71SHasso Tepper
42352347f71SHasso Tepper int
_citrus_prop_parse_variable(const _citrus_prop_hint_t * __restrict hints,void * __restrict context,const void * var,size_t lenvar)42452347f71SHasso Tepper _citrus_prop_parse_variable(const _citrus_prop_hint_t * __restrict hints,
42552347f71SHasso Tepper void * __restrict context, const void *var, size_t lenvar)
42652347f71SHasso Tepper {
42752347f71SHasso Tepper struct _memstream ms;
4280d5acd74SJohn Marino int ch, errnum;
42952347f71SHasso Tepper
43052347f71SHasso Tepper _memstream_bind_ptr(&ms, __DECONST(void *, var), lenvar);
43152347f71SHasso Tepper for (;;) {
43252347f71SHasso Tepper _memstream_skip_ws(&ms);
43352347f71SHasso Tepper ch = _memstream_getc(&ms);
43452347f71SHasso Tepper if (ch == EOF || ch == '\0')
43552347f71SHasso Tepper break;
43652347f71SHasso Tepper _memstream_ungetc(&ms, ch);
437bdcf3f2bSJohn Marino errnum = _citrus_prop_parse_element(&ms, hints, context);
43852347f71SHasso Tepper if (errnum != 0)
4390d5acd74SJohn Marino return (errnum);
44052347f71SHasso Tepper }
4410d5acd74SJohn Marino return (0);
44252347f71SHasso Tepper }
443