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