xref: /dragonfly/lib/libc/citrus/citrus_prop.c (revision f60c0e7f)
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