19ca40936STijl Coosemans /* $NetBSD: citrus_prop.c,v 1.4 2011/03/30 08:22:01 jruoho Exp $ */
2ad30f8e7SGabor Kovesdan
3ad30f8e7SGabor Kovesdan /*-
4d915a14eSPedro F. Giffuni * SPDX-License-Identifier: BSD-2-Clause
5d915a14eSPedro F. Giffuni *
6ad30f8e7SGabor Kovesdan * Copyright (c)2006 Citrus Project,
7ad30f8e7SGabor Kovesdan * All rights reserved.
8ad30f8e7SGabor Kovesdan *
9ad30f8e7SGabor Kovesdan * Redistribution and use in source and binary forms, with or without
10ad30f8e7SGabor Kovesdan * modification, are permitted provided that the following conditions
11ad30f8e7SGabor Kovesdan * are met:
12ad30f8e7SGabor Kovesdan * 1. Redistributions of source code must retain the above copyright
13ad30f8e7SGabor Kovesdan * notice, this list of conditions and the following disclaimer.
14ad30f8e7SGabor Kovesdan * 2. Redistributions in binary form must reproduce the above copyright
15ad30f8e7SGabor Kovesdan * notice, this list of conditions and the following disclaimer in the
16ad30f8e7SGabor Kovesdan * documentation and/or other materials provided with the distribution.
17ad30f8e7SGabor Kovesdan *
18ad30f8e7SGabor Kovesdan * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19ad30f8e7SGabor Kovesdan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20ad30f8e7SGabor Kovesdan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21ad30f8e7SGabor Kovesdan * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22ad30f8e7SGabor Kovesdan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23ad30f8e7SGabor Kovesdan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24ad30f8e7SGabor Kovesdan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25ad30f8e7SGabor Kovesdan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26ad30f8e7SGabor Kovesdan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27ad30f8e7SGabor Kovesdan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28ad30f8e7SGabor Kovesdan * SUCH DAMAGE.
29ad30f8e7SGabor Kovesdan *
30ad30f8e7SGabor Kovesdan */
31ad30f8e7SGabor Kovesdan
32ad30f8e7SGabor Kovesdan
33ad30f8e7SGabor Kovesdan #include <assert.h>
34ad30f8e7SGabor Kovesdan #include <errno.h>
35ad30f8e7SGabor Kovesdan #include <limits.h>
36ad30f8e7SGabor Kovesdan #include <stdbool.h>
37ad30f8e7SGabor Kovesdan #include <stddef.h>
38ad30f8e7SGabor Kovesdan #include <stdio.h>
39ad30f8e7SGabor Kovesdan #include <stdint.h>
40ad30f8e7SGabor Kovesdan #include <stdlib.h>
41ad30f8e7SGabor Kovesdan #include <string.h>
42ad30f8e7SGabor Kovesdan
43ad30f8e7SGabor Kovesdan #include "citrus_namespace.h"
44ad30f8e7SGabor Kovesdan #include "citrus_bcs.h"
45ad30f8e7SGabor Kovesdan #include "citrus_region.h"
46ad30f8e7SGabor Kovesdan #include "citrus_memstream.h"
47ad30f8e7SGabor Kovesdan #include "citrus_prop.h"
48ad30f8e7SGabor Kovesdan
49ad30f8e7SGabor Kovesdan typedef struct {
50ad30f8e7SGabor Kovesdan _citrus_prop_type_t type;
51ad30f8e7SGabor Kovesdan union {
52ad30f8e7SGabor Kovesdan const char *str;
53ad30f8e7SGabor Kovesdan int chr;
54ad30f8e7SGabor Kovesdan bool boolean;
55ad30f8e7SGabor Kovesdan uint64_t num;
56ad30f8e7SGabor Kovesdan } u;
57ad30f8e7SGabor Kovesdan } _citrus_prop_object_t;
58ad30f8e7SGabor Kovesdan
59ad30f8e7SGabor Kovesdan static __inline void
_citrus_prop_object_init(_citrus_prop_object_t * obj,_citrus_prop_type_t type)60ad30f8e7SGabor Kovesdan _citrus_prop_object_init(_citrus_prop_object_t *obj, _citrus_prop_type_t type)
61ad30f8e7SGabor Kovesdan {
62ad30f8e7SGabor Kovesdan
63ad30f8e7SGabor Kovesdan obj->type = type;
64ad30f8e7SGabor Kovesdan memset(&obj->u, 0, sizeof(obj->u));
65ad30f8e7SGabor Kovesdan }
66ad30f8e7SGabor Kovesdan
67ad30f8e7SGabor Kovesdan static __inline void
_citrus_prop_object_uninit(_citrus_prop_object_t * obj)68ad30f8e7SGabor Kovesdan _citrus_prop_object_uninit(_citrus_prop_object_t *obj)
69ad30f8e7SGabor Kovesdan {
70ad30f8e7SGabor Kovesdan
71ad30f8e7SGabor Kovesdan if (obj->type == _CITRUS_PROP_STR)
72ad30f8e7SGabor Kovesdan free(__DECONST(void *, obj->u.str));
73ad30f8e7SGabor Kovesdan }
74ad30f8e7SGabor Kovesdan
75ad30f8e7SGabor Kovesdan static const char *xdigit = "0123456789ABCDEF";
76ad30f8e7SGabor Kovesdan
77ad30f8e7SGabor Kovesdan #define _CITRUS_PROP_READ_UINT_COMMON(_func_, _type_, _max_) \
78ad30f8e7SGabor Kovesdan static int \
79ad30f8e7SGabor Kovesdan _citrus_prop_read_##_func_##_common(struct _memstream * __restrict ms, \
80*181751a8SKonstantin Belousov _type_ * __restrict result, int base, int neg) \
81ad30f8e7SGabor Kovesdan { \
82ad30f8e7SGabor Kovesdan _type_ acc, cutoff; \
83ad30f8e7SGabor Kovesdan int ch, cutlim, n; \
84ad30f8e7SGabor Kovesdan char *p; \
85ad30f8e7SGabor Kovesdan \
86ad30f8e7SGabor Kovesdan acc = (_type_)0; \
87ad30f8e7SGabor Kovesdan cutoff = _max_ / base; \
88ad30f8e7SGabor Kovesdan cutlim = _max_ % base; \
89ad30f8e7SGabor Kovesdan for (;;) { \
90ad30f8e7SGabor Kovesdan ch = _memstream_getc(ms); \
91ad30f8e7SGabor Kovesdan p = strchr(xdigit, _bcs_toupper(ch)); \
92ad30f8e7SGabor Kovesdan if (p == NULL || (n = (p - xdigit)) >= base) \
93ad30f8e7SGabor Kovesdan break; \
94ad30f8e7SGabor Kovesdan if (acc > cutoff || (acc == cutoff && n > cutlim)) \
95ad30f8e7SGabor Kovesdan break; \
96ad30f8e7SGabor Kovesdan acc *= base; \
97ad30f8e7SGabor Kovesdan acc += n; \
98ad30f8e7SGabor Kovesdan } \
99ad30f8e7SGabor Kovesdan _memstream_ungetc(ms, ch); \
100*181751a8SKonstantin Belousov *result = neg ? -acc : acc; \
101ad30f8e7SGabor Kovesdan return (0); \
102ad30f8e7SGabor Kovesdan }
_CITRUS_PROP_READ_UINT_COMMON(chr,int,UCHAR_MAX)103ad30f8e7SGabor Kovesdan _CITRUS_PROP_READ_UINT_COMMON(chr, int, UCHAR_MAX)
104ad30f8e7SGabor Kovesdan _CITRUS_PROP_READ_UINT_COMMON(num, uint64_t, UINT64_MAX)
105ad30f8e7SGabor Kovesdan #undef _CITRUS_PROP_READ_UINT_COMMON
106ad30f8e7SGabor Kovesdan
107ad30f8e7SGabor Kovesdan #define _CITRUS_PROP_READ_INT(_func_, _type_) \
108ad30f8e7SGabor Kovesdan static int \
109ad30f8e7SGabor Kovesdan _citrus_prop_read_##_func_(struct _memstream * __restrict ms, \
110ad30f8e7SGabor Kovesdan _citrus_prop_object_t * __restrict obj) \
111ad30f8e7SGabor Kovesdan { \
112ad30f8e7SGabor Kovesdan int base, ch, neg; \
113ad30f8e7SGabor Kovesdan \
114ad30f8e7SGabor Kovesdan _memstream_skip_ws(ms); \
115ad30f8e7SGabor Kovesdan ch = _memstream_getc(ms); \
116ad30f8e7SGabor Kovesdan neg = 0; \
117ad30f8e7SGabor Kovesdan switch (ch) { \
118ad30f8e7SGabor Kovesdan case '-': \
119ad30f8e7SGabor Kovesdan neg = 1; \
120ad30f8e7SGabor Kovesdan case '+': \
121ad30f8e7SGabor Kovesdan ch = _memstream_getc(ms); \
122ad30f8e7SGabor Kovesdan } \
123ad30f8e7SGabor Kovesdan base = 10; \
124ad30f8e7SGabor Kovesdan if (ch == '0') { \
125ad30f8e7SGabor Kovesdan base -= 2; \
126ad30f8e7SGabor Kovesdan ch = _memstream_getc(ms); \
127ad30f8e7SGabor Kovesdan if (ch == 'x' || ch == 'X') { \
128ad30f8e7SGabor Kovesdan ch = _memstream_getc(ms); \
129ad30f8e7SGabor Kovesdan if (_bcs_isxdigit(ch) == 0) { \
130ad30f8e7SGabor Kovesdan _memstream_ungetc(ms, ch); \
131ad30f8e7SGabor Kovesdan obj->u._func_ = 0; \
132ad30f8e7SGabor Kovesdan return (0); \
133ad30f8e7SGabor Kovesdan } \
134ad30f8e7SGabor Kovesdan base += 8; \
135ad30f8e7SGabor Kovesdan } \
136ad30f8e7SGabor Kovesdan } else if (_bcs_isdigit(ch) == 0) \
137ad30f8e7SGabor Kovesdan return (EINVAL); \
138ad30f8e7SGabor Kovesdan _memstream_ungetc(ms, ch); \
139ad30f8e7SGabor Kovesdan return (_citrus_prop_read_##_func_##_common \
140*181751a8SKonstantin Belousov (ms, &obj->u._func_, base, neg)); \
141ad30f8e7SGabor Kovesdan }
142ad30f8e7SGabor Kovesdan _CITRUS_PROP_READ_INT(chr, int)
143ad30f8e7SGabor Kovesdan _CITRUS_PROP_READ_INT(num, uint64_t)
144ad30f8e7SGabor Kovesdan #undef _CITRUS_PROP_READ_INT
145ad30f8e7SGabor Kovesdan
146ad30f8e7SGabor Kovesdan static int
147ad30f8e7SGabor Kovesdan _citrus_prop_read_character_common(struct _memstream * __restrict ms,
148ad30f8e7SGabor Kovesdan int * __restrict result)
149ad30f8e7SGabor Kovesdan {
150ad30f8e7SGabor Kovesdan int base, ch;
151ad30f8e7SGabor Kovesdan
152ad30f8e7SGabor Kovesdan ch = _memstream_getc(ms);
153ad30f8e7SGabor Kovesdan if (ch != '\\')
154ad30f8e7SGabor Kovesdan *result = ch;
155ad30f8e7SGabor Kovesdan else {
156ad30f8e7SGabor Kovesdan ch = _memstream_getc(ms);
157ad30f8e7SGabor Kovesdan base = 16;
158ad30f8e7SGabor Kovesdan switch (ch) {
159ad30f8e7SGabor Kovesdan case 'a':
160ad30f8e7SGabor Kovesdan *result = '\a';
161ad30f8e7SGabor Kovesdan break;
162ad30f8e7SGabor Kovesdan case 'b':
163ad30f8e7SGabor Kovesdan *result = '\b';
164ad30f8e7SGabor Kovesdan break;
165ad30f8e7SGabor Kovesdan case 'f':
166ad30f8e7SGabor Kovesdan *result = '\f';
167ad30f8e7SGabor Kovesdan break;
168ad30f8e7SGabor Kovesdan case 'n':
169ad30f8e7SGabor Kovesdan *result = '\n';
170ad30f8e7SGabor Kovesdan break;
171ad30f8e7SGabor Kovesdan case 'r':
172ad30f8e7SGabor Kovesdan *result = '\r';
173ad30f8e7SGabor Kovesdan break;
174ad30f8e7SGabor Kovesdan case 't':
175ad30f8e7SGabor Kovesdan *result = '\t';
176ad30f8e7SGabor Kovesdan break;
177ad30f8e7SGabor Kovesdan case 'v':
178ad30f8e7SGabor Kovesdan *result = '\v';
179ad30f8e7SGabor Kovesdan break;
180ad30f8e7SGabor Kovesdan case '0': case '1': case '2': case '3':
181ad30f8e7SGabor Kovesdan case '4': case '5': case '6': case '7':
182ad30f8e7SGabor Kovesdan _memstream_ungetc(ms, ch);
183ad30f8e7SGabor Kovesdan base -= 8;
184ad30f8e7SGabor Kovesdan /*FALLTHROUGH*/
185ad30f8e7SGabor Kovesdan case 'x':
186*181751a8SKonstantin Belousov return (_citrus_prop_read_chr_common(ms, result,
187*181751a8SKonstantin Belousov base, 0));
188ad30f8e7SGabor Kovesdan /*NOTREACHED*/
189ad30f8e7SGabor Kovesdan default:
190ad30f8e7SGabor Kovesdan /* unknown escape */
191ad30f8e7SGabor Kovesdan *result = ch;
192ad30f8e7SGabor Kovesdan }
193ad30f8e7SGabor Kovesdan }
194ad30f8e7SGabor Kovesdan return (0);
195ad30f8e7SGabor Kovesdan }
196ad30f8e7SGabor Kovesdan
197ad30f8e7SGabor Kovesdan static int
_citrus_prop_read_character(struct _memstream * __restrict ms,_citrus_prop_object_t * __restrict obj)198ad30f8e7SGabor Kovesdan _citrus_prop_read_character(struct _memstream * __restrict ms,
199ad30f8e7SGabor Kovesdan _citrus_prop_object_t * __restrict obj)
200ad30f8e7SGabor Kovesdan {
201ad30f8e7SGabor Kovesdan int ch, errnum;
202ad30f8e7SGabor Kovesdan
203ad30f8e7SGabor Kovesdan _memstream_skip_ws(ms);
204ad30f8e7SGabor Kovesdan ch = _memstream_getc(ms);
205ad30f8e7SGabor Kovesdan if (ch != '\'') {
206ad30f8e7SGabor Kovesdan _memstream_ungetc(ms, ch);
207ad30f8e7SGabor Kovesdan return (_citrus_prop_read_chr(ms, obj));
208ad30f8e7SGabor Kovesdan }
209ad30f8e7SGabor Kovesdan errnum = _citrus_prop_read_character_common(ms, &ch);
210ad30f8e7SGabor Kovesdan if (errnum != 0)
211ad30f8e7SGabor Kovesdan return (errnum);
212ad30f8e7SGabor Kovesdan obj->u.chr = ch;
213ad30f8e7SGabor Kovesdan ch = _memstream_getc(ms);
214ad30f8e7SGabor Kovesdan if (ch != '\'')
215ad30f8e7SGabor Kovesdan return (EINVAL);
216ad30f8e7SGabor Kovesdan return (0);
217ad30f8e7SGabor Kovesdan }
218ad30f8e7SGabor Kovesdan
219ad30f8e7SGabor Kovesdan static int
_citrus_prop_read_bool(struct _memstream * __restrict ms,_citrus_prop_object_t * __restrict obj)220ad30f8e7SGabor Kovesdan _citrus_prop_read_bool(struct _memstream * __restrict ms,
221ad30f8e7SGabor Kovesdan _citrus_prop_object_t * __restrict obj)
222ad30f8e7SGabor Kovesdan {
223ad30f8e7SGabor Kovesdan
224ad30f8e7SGabor Kovesdan _memstream_skip_ws(ms);
225ad30f8e7SGabor Kovesdan switch (_bcs_tolower(_memstream_getc(ms))) {
226ad30f8e7SGabor Kovesdan case 't':
227ad30f8e7SGabor Kovesdan if (_bcs_tolower(_memstream_getc(ms)) == 'r' &&
228ad30f8e7SGabor Kovesdan _bcs_tolower(_memstream_getc(ms)) == 'u' &&
229ad30f8e7SGabor Kovesdan _bcs_tolower(_memstream_getc(ms)) == 'e') {
230ad30f8e7SGabor Kovesdan obj->u.boolean = true;
231ad30f8e7SGabor Kovesdan return (0);
232ad30f8e7SGabor Kovesdan }
233ad30f8e7SGabor Kovesdan break;
234ad30f8e7SGabor Kovesdan case 'f':
235ad30f8e7SGabor Kovesdan if (_bcs_tolower(_memstream_getc(ms)) == 'a' &&
236ad30f8e7SGabor Kovesdan _bcs_tolower(_memstream_getc(ms)) == 'l' &&
237ad30f8e7SGabor Kovesdan _bcs_tolower(_memstream_getc(ms)) == 's' &&
238ad30f8e7SGabor Kovesdan _bcs_tolower(_memstream_getc(ms)) == 'e') {
239ad30f8e7SGabor Kovesdan obj->u.boolean = false;
240ad30f8e7SGabor Kovesdan return (0);
241ad30f8e7SGabor Kovesdan }
242ad30f8e7SGabor Kovesdan }
243ad30f8e7SGabor Kovesdan return (EINVAL);
244ad30f8e7SGabor Kovesdan }
245ad30f8e7SGabor Kovesdan
246ad30f8e7SGabor Kovesdan static int
_citrus_prop_read_str(struct _memstream * __restrict ms,_citrus_prop_object_t * __restrict obj)247ad30f8e7SGabor Kovesdan _citrus_prop_read_str(struct _memstream * __restrict ms,
248ad30f8e7SGabor Kovesdan _citrus_prop_object_t * __restrict obj)
249ad30f8e7SGabor Kovesdan {
250ad30f8e7SGabor Kovesdan int ch, errnum, quot;
251ad30f8e7SGabor Kovesdan char *s, *t;
252ad30f8e7SGabor Kovesdan #define _CITRUS_PROP_STR_BUFSIZ 512
253ad30f8e7SGabor Kovesdan size_t m, n;
254ad30f8e7SGabor Kovesdan
255ad30f8e7SGabor Kovesdan m = _CITRUS_PROP_STR_BUFSIZ;
256ad30f8e7SGabor Kovesdan s = malloc(m);
257ad30f8e7SGabor Kovesdan if (s == NULL)
258ad30f8e7SGabor Kovesdan return (ENOMEM);
259ad30f8e7SGabor Kovesdan n = 0;
260ad30f8e7SGabor Kovesdan _memstream_skip_ws(ms);
261ad30f8e7SGabor Kovesdan quot = _memstream_getc(ms);
262ad30f8e7SGabor Kovesdan switch (quot) {
263ad30f8e7SGabor Kovesdan case EOF:
264ad30f8e7SGabor Kovesdan goto done;
265ad30f8e7SGabor Kovesdan /*NOTREACHED*/
266ad30f8e7SGabor Kovesdan case '\\':
267ad30f8e7SGabor Kovesdan _memstream_ungetc(ms, quot);
268ad30f8e7SGabor Kovesdan quot = EOF;
269ad30f8e7SGabor Kovesdan /*FALLTHROUGH*/
270ad30f8e7SGabor Kovesdan case '\"': case '\'':
271ad30f8e7SGabor Kovesdan break;
272ad30f8e7SGabor Kovesdan default:
273ad30f8e7SGabor Kovesdan s[n] = quot;
274ad30f8e7SGabor Kovesdan ++n, --m;
275ad30f8e7SGabor Kovesdan quot = EOF;
276ad30f8e7SGabor Kovesdan }
277ad30f8e7SGabor Kovesdan for (;;) {
278ad30f8e7SGabor Kovesdan if (m < 1) {
279ad30f8e7SGabor Kovesdan m = _CITRUS_PROP_STR_BUFSIZ;
280ad30f8e7SGabor Kovesdan t = realloc(s, n + m);
281ad30f8e7SGabor Kovesdan if (t == NULL) {
282ad30f8e7SGabor Kovesdan free(s);
283ad30f8e7SGabor Kovesdan return (ENOMEM);
284ad30f8e7SGabor Kovesdan }
285ad30f8e7SGabor Kovesdan s = t;
286ad30f8e7SGabor Kovesdan }
287ad30f8e7SGabor Kovesdan ch = _memstream_getc(ms);
288ad30f8e7SGabor Kovesdan if (quot == ch || (quot == EOF &&
289ad30f8e7SGabor Kovesdan (ch == ';' || _bcs_isspace(ch)))) {
290ad30f8e7SGabor Kovesdan done:
291ad30f8e7SGabor Kovesdan s[n] = '\0';
292ad30f8e7SGabor Kovesdan obj->u.str = (const char *)s;
293ad30f8e7SGabor Kovesdan return (0);
294ad30f8e7SGabor Kovesdan }
295ad30f8e7SGabor Kovesdan _memstream_ungetc(ms, ch);
296ad30f8e7SGabor Kovesdan errnum = _citrus_prop_read_character_common(ms, &ch);
2974194e4e3SPedro F. Giffuni if (errnum != 0) {
2984194e4e3SPedro F. Giffuni free(s);
299ad30f8e7SGabor Kovesdan return (errnum);
3004194e4e3SPedro F. Giffuni }
301ad30f8e7SGabor Kovesdan s[n] = ch;
302ad30f8e7SGabor Kovesdan ++n, --m;
303ad30f8e7SGabor Kovesdan }
304ad30f8e7SGabor Kovesdan free(s);
305ad30f8e7SGabor Kovesdan return (EINVAL);
306ad30f8e7SGabor Kovesdan #undef _CITRUS_PROP_STR_BUFSIZ
307ad30f8e7SGabor Kovesdan }
308ad30f8e7SGabor Kovesdan
309ad30f8e7SGabor Kovesdan typedef int (*_citrus_prop_read_type_t)(struct _memstream * __restrict,
310ad30f8e7SGabor Kovesdan _citrus_prop_object_t * __restrict);
311ad30f8e7SGabor Kovesdan
312ad30f8e7SGabor Kovesdan static const _citrus_prop_read_type_t readers[] = {
313ad30f8e7SGabor Kovesdan _citrus_prop_read_bool,
314ad30f8e7SGabor Kovesdan _citrus_prop_read_str,
315ad30f8e7SGabor Kovesdan _citrus_prop_read_character,
316ad30f8e7SGabor Kovesdan _citrus_prop_read_num,
317ad30f8e7SGabor Kovesdan };
318ad30f8e7SGabor Kovesdan
319ad30f8e7SGabor Kovesdan static __inline int
_citrus_prop_read_symbol(struct _memstream * __restrict ms,char * __restrict s,size_t n)320ad30f8e7SGabor Kovesdan _citrus_prop_read_symbol(struct _memstream * __restrict ms,
321ad30f8e7SGabor Kovesdan char * __restrict s, size_t n)
322ad30f8e7SGabor Kovesdan {
323ad30f8e7SGabor Kovesdan int ch;
324ad30f8e7SGabor Kovesdan size_t m;
325ad30f8e7SGabor Kovesdan
326ad30f8e7SGabor Kovesdan for (m = 0; m < n; ++m) {
327ad30f8e7SGabor Kovesdan ch = _memstream_getc(ms);
328ad30f8e7SGabor Kovesdan if (ch != '_' && _bcs_isalnum(ch) == 0)
329ad30f8e7SGabor Kovesdan goto name_found;
330ad30f8e7SGabor Kovesdan s[m] = ch;
331ad30f8e7SGabor Kovesdan }
332ad30f8e7SGabor Kovesdan ch = _memstream_getc(ms);
333ad30f8e7SGabor Kovesdan if (ch == '_' || _bcs_isalnum(ch) != 0)
334ad30f8e7SGabor Kovesdan return (EINVAL);
335ad30f8e7SGabor Kovesdan
336ad30f8e7SGabor Kovesdan name_found:
337ad30f8e7SGabor Kovesdan _memstream_ungetc(ms, ch);
338ad30f8e7SGabor Kovesdan s[m] = '\0';
339ad30f8e7SGabor Kovesdan
340ad30f8e7SGabor Kovesdan return (0);
341ad30f8e7SGabor Kovesdan }
342ad30f8e7SGabor Kovesdan
343ad30f8e7SGabor Kovesdan static int
_citrus_prop_parse_element(struct _memstream * __restrict ms,const _citrus_prop_hint_t * __restrict hints,void * __restrict context)344ad30f8e7SGabor Kovesdan _citrus_prop_parse_element(struct _memstream * __restrict ms,
34564f204f9STijl Coosemans const _citrus_prop_hint_t * __restrict hints, void * __restrict context)
346ad30f8e7SGabor Kovesdan {
347ad30f8e7SGabor Kovesdan int ch, errnum;
348ad30f8e7SGabor Kovesdan #define _CITRUS_PROP_HINT_NAME_LEN_MAX 255
349ad30f8e7SGabor Kovesdan char name[_CITRUS_PROP_HINT_NAME_LEN_MAX + 1];
350ad30f8e7SGabor Kovesdan const _citrus_prop_hint_t *hint;
351ad30f8e7SGabor Kovesdan _citrus_prop_object_t ostart, oend;
352ad30f8e7SGabor Kovesdan
353ad30f8e7SGabor Kovesdan errnum = _citrus_prop_read_symbol(ms, name, sizeof(name));
354ad30f8e7SGabor Kovesdan if (errnum != 0)
355ad30f8e7SGabor Kovesdan return (errnum);
356ad30f8e7SGabor Kovesdan for (hint = hints; hint->name != NULL; ++hint)
357ad30f8e7SGabor Kovesdan if (_citrus_bcs_strcasecmp(name, hint->name) == 0)
358ad30f8e7SGabor Kovesdan goto hint_found;
359ad30f8e7SGabor Kovesdan return (EINVAL);
360ad30f8e7SGabor Kovesdan
361ad30f8e7SGabor Kovesdan hint_found:
362ad30f8e7SGabor Kovesdan _memstream_skip_ws(ms);
363ad30f8e7SGabor Kovesdan ch = _memstream_getc(ms);
364ad30f8e7SGabor Kovesdan if (ch != '=' && ch != ':')
365ad30f8e7SGabor Kovesdan _memstream_ungetc(ms, ch);
366ad30f8e7SGabor Kovesdan do {
367ad30f8e7SGabor Kovesdan _citrus_prop_object_init(&ostart, hint->type);
368ad30f8e7SGabor Kovesdan _citrus_prop_object_init(&oend, hint->type);
369ad30f8e7SGabor Kovesdan errnum = (*readers[hint->type])(ms, &ostart);
370ad30f8e7SGabor Kovesdan if (errnum != 0)
371ad30f8e7SGabor Kovesdan return (errnum);
372ad30f8e7SGabor Kovesdan _memstream_skip_ws(ms);
373ad30f8e7SGabor Kovesdan ch = _memstream_getc(ms);
374ad30f8e7SGabor Kovesdan switch (hint->type) {
375ad30f8e7SGabor Kovesdan case _CITRUS_PROP_BOOL:
376ad30f8e7SGabor Kovesdan /*FALLTHROUGH*/
377ad30f8e7SGabor Kovesdan case _CITRUS_PROP_STR:
378ad30f8e7SGabor Kovesdan break;
379ad30f8e7SGabor Kovesdan default:
380ad30f8e7SGabor Kovesdan if (ch != '-')
381ad30f8e7SGabor Kovesdan break;
382ad30f8e7SGabor Kovesdan errnum = (*readers[hint->type])(ms, &oend);
383ad30f8e7SGabor Kovesdan if (errnum != 0)
384ad30f8e7SGabor Kovesdan return (errnum);
385ad30f8e7SGabor Kovesdan _memstream_skip_ws(ms);
386ad30f8e7SGabor Kovesdan ch = _memstream_getc(ms);
387ad30f8e7SGabor Kovesdan }
388ad30f8e7SGabor Kovesdan #define CALL0(_func_) \
389ad30f8e7SGabor Kovesdan do { \
390ad30f8e7SGabor Kovesdan errnum = (*hint->cb._func_.func)(context, \
391ad30f8e7SGabor Kovesdan hint->name, ostart.u._func_); \
392ad30f8e7SGabor Kovesdan } while (0)
393ad30f8e7SGabor Kovesdan #define CALL1(_func_) \
394ad30f8e7SGabor Kovesdan do { \
395ad30f8e7SGabor Kovesdan errnum = (*hint->cb._func_.func)(context, \
396ad30f8e7SGabor Kovesdan hint->name, ostart.u._func_, oend.u._func_);\
397ad30f8e7SGabor Kovesdan } while (0)
398ad30f8e7SGabor Kovesdan switch (hint->type) {
399ad30f8e7SGabor Kovesdan case _CITRUS_PROP_BOOL:
400ad30f8e7SGabor Kovesdan CALL0(boolean);
401ad30f8e7SGabor Kovesdan break;
402ad30f8e7SGabor Kovesdan case _CITRUS_PROP_STR:
403ad30f8e7SGabor Kovesdan CALL0(str);
404ad30f8e7SGabor Kovesdan break;
405ad30f8e7SGabor Kovesdan case _CITRUS_PROP_CHR:
406ad30f8e7SGabor Kovesdan CALL1(chr);
407ad30f8e7SGabor Kovesdan break;
408ad30f8e7SGabor Kovesdan case _CITRUS_PROP_NUM:
409ad30f8e7SGabor Kovesdan CALL1(num);
410ad30f8e7SGabor Kovesdan break;
411ad30f8e7SGabor Kovesdan default:
412ad30f8e7SGabor Kovesdan abort();
413ad30f8e7SGabor Kovesdan /*NOTREACHED*/
414ad30f8e7SGabor Kovesdan }
415ad30f8e7SGabor Kovesdan #undef CALL0
416ad30f8e7SGabor Kovesdan #undef CALL1
417ad30f8e7SGabor Kovesdan _citrus_prop_object_uninit(&ostart);
418ad30f8e7SGabor Kovesdan _citrus_prop_object_uninit(&oend);
419ad30f8e7SGabor Kovesdan if (errnum != 0)
420ad30f8e7SGabor Kovesdan return (errnum);
421ad30f8e7SGabor Kovesdan } while (ch == ',');
422ad30f8e7SGabor Kovesdan if (ch != ';')
423ad30f8e7SGabor Kovesdan _memstream_ungetc(ms, ch);
424ad30f8e7SGabor Kovesdan return (0);
425ad30f8e7SGabor Kovesdan }
426ad30f8e7SGabor Kovesdan
427ad30f8e7SGabor Kovesdan int
_citrus_prop_parse_variable(const _citrus_prop_hint_t * __restrict hints,void * __restrict context,const void * var,size_t lenvar)428ad30f8e7SGabor Kovesdan _citrus_prop_parse_variable(const _citrus_prop_hint_t * __restrict hints,
429ad30f8e7SGabor Kovesdan void * __restrict context, const void *var, size_t lenvar)
430ad30f8e7SGabor Kovesdan {
431ad30f8e7SGabor Kovesdan struct _memstream ms;
432ad30f8e7SGabor Kovesdan int ch, errnum;
433ad30f8e7SGabor Kovesdan
434ad30f8e7SGabor Kovesdan _memstream_bind_ptr(&ms, __DECONST(void *, var), lenvar);
435ad30f8e7SGabor Kovesdan for (;;) {
436ad30f8e7SGabor Kovesdan _memstream_skip_ws(&ms);
437ad30f8e7SGabor Kovesdan ch = _memstream_getc(&ms);
438ad30f8e7SGabor Kovesdan if (ch == EOF || ch == '\0')
439ad30f8e7SGabor Kovesdan break;
440ad30f8e7SGabor Kovesdan _memstream_ungetc(&ms, ch);
44164f204f9STijl Coosemans errnum = _citrus_prop_parse_element(&ms, hints, context);
442ad30f8e7SGabor Kovesdan if (errnum != 0)
443ad30f8e7SGabor Kovesdan return (errnum);
444ad30f8e7SGabor Kovesdan }
445ad30f8e7SGabor Kovesdan return (0);
446ad30f8e7SGabor Kovesdan }
447