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