1 : /*
2 : * Copyright (C) 2005 James Antill
3 : *
4 : * This library is free software; you can redistribute it and/or
5 : * modify it under the terms of the GNU Lesser General Public
6 : * License as published by the Free Software Foundation; either
7 : * version 2 of the License, or (at your option) any later version.
8 : *
9 : * This library is distributed in the hope that it will be useful,
10 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 : * Lesser General Public License for more details.
13 : *
14 : * You should have received a copy of the GNU Lesser General Public
15 : * License along with this library; if not, write to the Free Software
16 : * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 : *
18 : * email: james@and.org
19 : */
20 : /* configuration file functions */
21 :
22 : #define EX_UTILS_NO_FUNCS 1
23 : #include "ex_utils.h"
24 :
25 : #include "conf.h"
26 :
27 : #include <limits.h>
28 :
29 : #include "mk.h"
30 :
31 : #define CLEN COMPILE_STRLEN
32 :
33 : #define VPREFIX(vstr, p, l, cstr) \
34 : (((l) >= CLEN(cstr)) && \
35 : vstr_cmp_buf_eq(vstr, p, CLEN(cstr), cstr, CLEN(cstr)))
36 :
37 : Conf_parse *conf_parse_make(Vstr_conf *conf)
38 38913 : {
39 38913 : Conf_parse *ret = MK(sizeof(Conf_parse));
40 38913 : Vstr_sects *sects = vstr_sects_make(4);
41 38913 : Vstr_base *s1 = vstr_make_base(conf);
42 38913 : Vstr_base *s2 = vstr_make_base(conf);
43 38913 : unsigned int *ptr = MK(sizeof(unsigned int) * 4);
44 :
45 38913 : if (!ret || !s1 || !sects || !ptr)
46 : {
47 0 : F(ret);
48 0 : vstr_sects_free(sects);
49 0 : vstr_free_base(s1);
50 0 : vstr_free_base(s2);
51 0 : F(ptr);
52 0 : return (NULL);
53 : }
54 :
55 38913 : ret->sects = sects;
56 38913 : ret->data = s1;
57 38913 : ret->tmp = s2;
58 38913 : ret->types_sz = 4;
59 38913 : ret->types_ptr = ptr;
60 38913 : ret->uvals_sz = 0;
61 38913 : ret->uvals_num = 0;
62 38913 : ret->uvals_ptr = NULL;
63 38913 : ret->state = CONF_PARSE_STATE_BEG;
64 38913 : ret->depth = 0;
65 :
66 38913 : return (ret);
67 : }
68 :
69 : void conf_parse_free(Conf_parse *conf)
70 38917 : {
71 38917 : if (!conf)
72 0 : return;
73 :
74 38917 : F(conf->types_ptr);
75 38917 : vstr_sects_free(conf->sects);
76 38917 : vstr_free_base(conf->data);
77 38917 : vstr_free_base(conf->tmp);
78 :
79 82244 : while (conf->uvals_num)
80 4410 : vstr_ref_del(conf->uvals_ptr[--conf->uvals_num].ref);
81 38917 : F(conf->uvals_ptr);
82 :
83 38917 : F(conf);
84 : }
85 :
86 : static int conf__parse_type_add(Conf_parse *conf, unsigned int type)
87 205064 : {
88 205064 : unsigned int *ptr = NULL;
89 :
90 102532 : ASSERT(conf->types_sz <= conf->sects->sz);
91 :
92 205064 : if (conf->types_sz == conf->sects->sz)
93 188054 : goto fin_ok;
94 :
95 17010 : if (!MV(conf->types_ptr, ptr, sizeof(unsigned int) * conf->sects->sz))
96 0 : return (FALSE);
97 17010 : conf->types_sz = conf->sects->sz;
98 :
99 205064 : fin_ok:
100 205064 : conf->types_ptr[conf->sects->num - 1] = type;
101 :
102 205064 : return (TRUE);
103 : }
104 :
105 :
106 : static size_t conf__parse_ws(Conf_parse *conf, size_t pos, size_t len)
107 156576 : {
108 156576 : conf->state = CONF_PARSE_STATE_CHOOSE;
109 156576 : return (vstr_spn_cstr_chrs_fwd(conf->data, pos, len, " \t\v\r\n"));
110 : }
111 :
112 : /* if the last token is a line comment token ... comment out that line */
113 : static size_t conf__parse_comment(Conf_parse *conf, size_t pos, size_t len)
114 153090 : {
115 153090 : Vstr_sect_node *node = NULL;
116 :
117 76545 : ASSERT(conf->sects);
118 :
119 153090 : if (conf->sects->malloc_bad)
120 0 : return (0);
121 :
122 76545 : ASSERT(conf->sects->num);
123 :
124 153090 : node = VSTR_SECTS_NUM(conf->sects, conf->sects->num);
125 :
126 153090 : if (node->len >= 1)
127 : {
128 153090 : Vstr_base *data = conf->data;
129 153090 : int byte = vstr_export_chr(data, node->pos);
130 153090 : size_t p = node->pos;
131 153090 : size_t l = node->len;
132 :
133 153090 : if (((byte == ';') && (vstr_spn_cstr_chrs_fwd(data, p, l, ";") == l)) ||
134 : ((byte == '#') && (vstr_spn_cstr_chrs_fwd(data, p, l, "#") == l)))
135 : {
136 8696 : vstr_sects_del(conf->sects, conf->sects->num);
137 8696 : conf->state = CONF_PARSE_STATE_CHOOSE;
138 8696 : return (vstr_cspn_cstr_chrs_fwd(conf->data, pos, len, "\n"));
139 : }
140 : }
141 :
142 144394 : return (0);
143 : }
144 :
145 : static int conf__parse_beg_list(Conf_parse *conf, size_t pos,
146 : unsigned int *list_nums)
147 47302 : {
148 47302 : if (conf->depth >= CONF_PARSE_LIST_DEPTH_SZ)
149 0 : return (FALSE);
150 :
151 47302 : vstr_sects_add(conf->sects, pos, 0);
152 47302 : conf__parse_type_add(conf, CONF_TOKEN_TYPE_ERR);
153 47302 : list_nums[conf->depth++] = conf->sects->num;
154 :
155 47302 : conf->state = CONF_PARSE_STATE_CHOOSE;
156 47302 : return (TRUE);
157 : }
158 :
159 : static int conf__parse_end_list(Conf_parse *conf, unsigned int *list_nums,
160 : int byte)
161 47302 : {
162 47302 : Vstr_sects *sects = conf->sects;
163 47302 : unsigned int depth_beg_num = 0;
164 47302 : Vstr_sect_node *node = NULL;
165 :
166 47302 : if (!conf->depth)
167 0 : return (FALSE);
168 :
169 47302 : depth_beg_num = list_nums[--conf->depth];
170 47302 : node = VSTR_SECTS_NUM(sects, depth_beg_num);
171 47302 : if (byte == ']')
172 : {
173 5720 : conf->types_ptr[depth_beg_num - 1] = CONF_TOKEN_TYPE_SLIST;
174 5720 : if (vstr_export_chr(conf->data, node->pos) != '[')
175 0 : return (FALSE);
176 : }
177 :
178 47302 : if (byte == ')')
179 : {
180 41582 : conf->types_ptr[depth_beg_num - 1] = CONF_TOKEN_TYPE_CLIST;
181 41582 : if (vstr_export_chr(conf->data, node->pos) != '(')
182 0 : return (FALSE);
183 : }
184 :
185 23651 : ASSERT(!node->len);
186 47302 : node->len = sects->num - depth_beg_num;
187 :
188 47302 : conf->state = CONF_PARSE_STATE_CHOOSE;
189 47302 : return (TRUE);
190 : }
191 :
192 : static void conf__parse_beg_quote_d(Conf_parse *conf, size_t pos,
193 : unsigned int *list_nums)
194 2824 : {
195 1412 : ASSERT(conf->depth <= CONF_PARSE_LIST_DEPTH_SZ);
196 :
197 2824 : vstr_sects_add(conf->sects, pos, 0);
198 2824 : conf__parse_type_add(conf, CONF_TOKEN_TYPE_QUOTE_D);
199 2824 : list_nums[conf->depth++] = conf->sects->num;
200 :
201 2824 : conf->state = CONF_PARSE_STATE_QUOTE_D_BEG;
202 2824 : }
203 :
204 : static void conf__parse_beg_quote_s(Conf_parse *conf, size_t pos,
205 : unsigned int *list_nums)
206 1848 : {
207 924 : ASSERT(conf->depth <= CONF_PARSE_LIST_DEPTH_SZ);
208 :
209 1848 : vstr_sects_add(conf->sects, pos, 0);
210 1848 : conf__parse_type_add(conf, CONF_TOKEN_TYPE_QUOTE_S);
211 1848 : list_nums[conf->depth++] = conf->sects->num;
212 :
213 1848 : conf->state = CONF_PARSE_STATE_QUOTE_S_BEG;
214 1848 : }
215 :
216 : static void conf__parse_beg_quote_xxx(Conf_parse *conf, unsigned int *list_nums,
217 : int three)
218 4672 : {
219 4672 : Vstr_sects *sects = conf->sects;
220 4672 : unsigned int depth_beg_num = 0;
221 4672 : size_t mv_pos = 1;
222 4672 : unsigned int state = 0;
223 :
224 2336 : ASSERT(conf->depth);
225 :
226 4672 : depth_beg_num = list_nums[conf->depth - 1];
227 :
228 4672 : if (conf->state == CONF_PARSE_STATE_QUOTE_S_BEG)
229 1848 : state = CONF_PARSE_STATE_QUOTE_S_END;
230 4672 : if (conf->state == CONF_PARSE_STATE_QUOTE_D_BEG)
231 2824 : state = CONF_PARSE_STATE_QUOTE_D_END;
232 :
233 4672 : if (three)
234 : {
235 52 : mv_pos = 3;
236 52 : state += CONF_PARSE_STATE_QUOTE_X2XXX;
237 52 : conf->types_ptr[depth_beg_num - 1] += 2;
238 : }
239 :
240 4672 : VSTR_SECTS_NUM(sects, depth_beg_num)->pos += mv_pos;
241 :
242 4672 : conf->state = state;
243 4672 : }
244 :
245 : static size_t conf__parse_beg_unquote(Conf_parse *conf, size_t pos, size_t len,
246 : unsigned int *list_nums)
247 88 : {
248 88 : size_t plen = 1;
249 88 : int d = FALSE;
250 88 : int xxx = FALSE;
251 :
252 : if (FALSE) { }
253 104 : else if (VPREFIX(conf->data, pos, len, "\"\"\""))
254 : {
255 16 : d = TRUE;
256 16 : xxx = TRUE;
257 : }
258 100 : else if (VPREFIX(conf->data, pos, len, "\""))
259 : {
260 28 : d = TRUE;
261 28 : xxx = FALSE;
262 : }
263 64 : else if (VPREFIX(conf->data, pos, len, "'''"))
264 : {
265 20 : d = FALSE;
266 20 : xxx = TRUE;
267 : }
268 48 : else if (VPREFIX(conf->data, pos, len, "'"))
269 : {
270 24 : d = FALSE;
271 24 : xxx = FALSE;
272 : }
273 : else
274 0 : return (0);
275 :
276 88 : if (d)
277 44 : conf__parse_beg_quote_d(conf, pos, list_nums);
278 : else
279 44 : conf__parse_beg_quote_s(conf, pos, list_nums);
280 :
281 88 : if (!xxx)
282 52 : conf__parse_beg_quote_xxx(conf, list_nums, FALSE);
283 : else
284 : {
285 36 : plen = 3;
286 36 : conf__parse_beg_quote_xxx(conf, list_nums, TRUE);
287 : }
288 :
289 88 : conf->state += CONF_PARSE_STATE_QUOTE2UNQUOTE_END;
290 :
291 88 : len -= plen; pos += plen;
292 88 : if (VPREFIX(conf->data, pos, len, "\\\n")) /* allow first line */
293 : {
294 4 : unsigned int depth_beg_num = list_nums[conf->depth - 1];
295 :
296 4 : VSTR_SECTS_NUM(conf->sects, depth_beg_num)->pos += CLEN("\\\n");
297 4 : plen += CLEN("\\\n");
298 : }
299 :
300 88 : return (plen);
301 : }
302 :
303 : static void conf__parse_end_quote_xxx(Conf_parse *conf, size_t pos,
304 : unsigned int *list_nums)
305 4672 : {
306 4672 : Vstr_sects *sects = conf->sects;
307 4672 : unsigned int depth_beg_num = 0;
308 4672 : size_t beg_pos = 0;
309 :
310 2336 : ASSERT(conf->depth);
311 :
312 4672 : depth_beg_num = list_nums[--conf->depth];
313 4672 : beg_pos = VSTR_SECTS_NUM(sects, depth_beg_num)->pos;
314 4672 : VSTR_SECTS_NUM(sects, depth_beg_num)->pos = beg_pos;
315 4672 : VSTR_SECTS_NUM(sects, depth_beg_num)->len = pos - beg_pos;
316 :
317 4672 : conf->state = CONF_PARSE_STATE_LIST_END_OR_WS;
318 4672 : }
319 :
320 : static int conf__parse_esc_quote(Conf_parse *conf, unsigned int *list_nums,
321 : size_t pos, size_t len, unsigned int type)
322 18444 : {
323 18444 : Vstr_sects *sects = conf->sects;
324 18444 : unsigned int depth_beg_num = 0;
325 :
326 9222 : ASSERT(conf->depth);
327 :
328 18444 : if (len < 2)
329 0 : return (FALSE);
330 :
331 18444 : depth_beg_num = list_nums[conf->depth - 1];
332 18444 : if ((pos == VSTR_SECTS_NUM(sects, depth_beg_num)->pos) &&
333 : vstr_cmp_cstr_eq(conf->data, pos, CLEN("\\\n"), "\\\n"))
334 : {
335 8 : VSTR_SECTS_NUM(sects, depth_beg_num)->pos += CLEN("\\\n");
336 8 : return (TRUE);
337 : }
338 :
339 18436 : if (conf->types_ptr[depth_beg_num - 1] == type)
340 1156 : conf->types_ptr[depth_beg_num - 1] += CONF_TOKEN_TYPE_2ESC;
341 :
342 18436 : return (TRUE);
343 : }
344 : #define CONF__SC_PARSE_ESC_QUOTE(x) do { \
345 : ASSERT(vstr_export_chr(data, pos) == '\\'); \
346 : \
347 : if (!conf__parse_esc_quote(conf, list_nums, pos, len, x)) \
348 : return (CONF_PARSE_ERR); \
349 : plen = 2; \
350 : } while (FALSE)
351 :
352 : #define CONF__SC_PARSE_QUOTE_X_BEG(x) do { \
353 : if (!VPREFIX(data, pos, len, x)) \
354 : conf__parse_beg_quote_xxx(conf, list_nums, FALSE); \
355 : else \
356 : { \
357 : plen = 2; \
358 : conf__parse_beg_quote_xxx(conf, list_nums, TRUE); \
359 : } \
360 : } while (FALSE)
361 :
362 : #define CONF__SC_PARSE_QUOTE_XXX_END(x, y, z) do { \
363 : if (!(plen = vstr_cspn_cstr_chrs_fwd(data, pos, len, x))) \
364 : { \
365 : plen = 3; \
366 : if (VPREFIX(data, pos, len, y)) \
367 : conf__parse_end_quote_xxx(conf, pos, list_nums); \
368 : else if (vstr_export_chr(data, pos) != '\\') \
369 : plen = 1; \
370 : else /* \x */ \
371 : CONF__SC_PARSE_ESC_QUOTE(CONF_TOKEN_TYPE_QUOTE_ ## z); \
372 : } \
373 : } while (FALSE)
374 :
375 : #define CONF__SC_PARSE_QUOTE_X_END(x, y, z) do { \
376 : if (!(plen = vstr_cspn_cstr_chrs_fwd(data, pos, len, x))) \
377 : { \
378 : plen = 1; \
379 : if (vstr_export_chr(data, pos) == y) \
380 : conf__parse_end_quote_xxx(conf, pos, list_nums); \
381 : else /* \x */ \
382 : CONF__SC_PARSE_ESC_QUOTE(CONF_TOKEN_TYPE_QUOTE_ ## z); \
383 : } \
384 : } while (FALSE)
385 :
386 : #define CONF__SC_PARSE_UNQUOTE_END(x) do { \
387 : if (!(plen = vstr_srch_cstr_buf_fwd(data, pos, len, x))) \
388 : plen = len; \
389 : else \
390 : { \
391 : conf__parse_end_quote_xxx(conf, plen, list_nums); \
392 : plen -= pos; \
393 : plen += CLEN(x); \
394 : } \
395 : } while (FALSE)
396 :
397 : int conf_parse_lex(Conf_parse *conf, size_t pos, size_t len)
398 5146 : {
399 : unsigned int list_nums[CONF_PARSE_LIST_DEPTH_SZ + 1];
400 5146 : Vstr_base *data = NULL;
401 :
402 2573 : ASSERT(conf && conf->data && conf->sects &&
403 : conf->types_ptr && conf->types_sz);
404 :
405 5146 : data = conf->data;
406 :
407 5146 : if (conf->state != CONF_PARSE_STATE_BEG)
408 0 : return (CONF_PARSE_ERR);
409 :
410 479671 : while (len)
411 : {
412 471952 : size_t plen = 0; /* amount parsed this loop */
413 :
414 471952 : switch (conf->state)
415 : {
416 : case CONF_PARSE_STATE_BEG: /* unix she-bang */
417 5146 : conf->state = CONF_PARSE_STATE_CHOOSE;
418 5146 : if (VPREFIX(data, pos, len, "#!"))
419 : {
420 4 : plen = vstr_cspn_cstr_chrs_fwd(data, pos, len, "\n");
421 4 : conf->state = CONF_PARSE_STATE_WS;
422 : }
423 2573 : break;
424 :
425 : case CONF_PARSE_STATE_WS:
426 4 : if (!(plen = conf__parse_ws(conf, pos, len)))
427 0 : return (CONF_PARSE_ERR);
428 2 : break;
429 :
430 : case CONF_PARSE_STATE_LIST_END_OR_WS:
431 : {
432 4672 : int byte = vstr_export_chr(data, pos);
433 :
434 4672 : plen = 1;
435 4672 : switch (byte)
436 : {
437 : case ' ': /* whitespace */
438 : case '\t': /* whitespace */
439 : case '\v': /* whitespace */
440 : case '\r': /* whitespace */
441 : case '\n': /* whitespace */
442 4044 : plen = conf__parse_ws(conf, pos, len);
443 4044 : break;
444 :
445 : case ')':
446 : case ']':
447 628 : if (!conf__parse_end_list(conf, list_nums, byte))
448 0 : return (CONF_PARSE_ERR);
449 314 : break;
450 : default:
451 0 : return (CONF_PARSE_ERR);
452 : }
453 : }
454 2336 : break;
455 :
456 : case CONF_PARSE_STATE_CHOOSE:
457 : {
458 259624 : int byte = vstr_export_chr(data, pos);
459 :
460 259624 : plen = 1;
461 259624 : switch (byte)
462 : {
463 : case ' ': /* whitespace */
464 : case '\t': /* whitespace */
465 : case '\v': /* whitespace */
466 : case '\r': /* whitespace */
467 : case '\n': /* whitespace */
468 43740 : plen = conf__parse_ws(conf, pos, len);
469 43740 : break;
470 :
471 : case ')':
472 : case ']':
473 10828 : if (!conf__parse_end_list(conf, list_nums, byte))
474 0 : return (CONF_PARSE_ERR);
475 5414 : break;
476 :
477 : case '(':
478 : case '[':
479 47294 : if (!conf__parse_beg_list(conf, pos, list_nums))
480 0 : return (CONF_PARSE_ERR);
481 23647 : break;
482 :
483 : case '"':
484 2780 : conf__parse_beg_quote_d(conf, pos, list_nums);
485 2780 : break;
486 : case '\'':
487 1804 : conf__parse_beg_quote_s(conf, pos, list_nums);
488 1804 : break;
489 :
490 : case '@': /* allow "raw" strings, for backslashes, @ == C# */
491 : case 'r': /* allow "raw" strings, for backslashes, r == python */
492 2516 : if (len > 1)
493 : {
494 2516 : char tmp = vstr_export_chr(data, pos + 1);
495 2516 : if ((tmp == '"') || (tmp == '\''))
496 : {
497 88 : conf->state = CONF_PARSE_STATE_UNQUOTE_BEG;
498 88 : break;
499 : }
500 : }
501 :
502 : default:
503 153090 : plen = vstr_cspn_cstr_chrs_fwd(data, pos, len, " \t\v\r\n\"'()[]");
504 153090 : conf->state = CONF_PARSE_STATE_SYMBOL_END;
505 153090 : vstr_sects_add(conf->sects, pos, plen);
506 153090 : conf__parse_type_add(conf, CONF_TOKEN_TYPE_SYMBOL);
507 : break;
508 : }
509 : }
510 129812 : break;
511 :
512 : case CONF_PARSE_STATE_QUOTE_D_BEG:
513 2780 : CONF__SC_PARSE_QUOTE_X_BEG("\"\"");
514 1390 : break;
515 :
516 : case CONF_PARSE_STATE_QUOTE_S_BEG:
517 1804 : CONF__SC_PARSE_QUOTE_X_BEG("''");
518 902 : break;
519 :
520 : case CONF_PARSE_STATE_UNQUOTE_BEG:
521 88 : if (!(plen = conf__parse_beg_unquote(conf, pos, len, list_nums)))
522 0 : return (CONF_PARSE_ERR);
523 44 : break;
524 :
525 : case CONF_PARSE_STATE_QUOTE_D_END:
526 41240 : CONF__SC_PARSE_QUOTE_X_END("\"\\", '"', D);
527 20620 : break;
528 :
529 : case CONF_PARSE_STATE_QUOTE_DDD_END:
530 48 : CONF__SC_PARSE_QUOTE_XXX_END("\"\\", "\"\"\"", DDD);
531 24 : break;
532 :
533 : case CONF_PARSE_STATE_QUOTE_S_END:
534 3368 : CONF__SC_PARSE_QUOTE_X_END("'\\", '\'', S);
535 1684 : break;
536 :
537 : case CONF_PARSE_STATE_QUOTE_SSS_END:
538 0 : CONF__SC_PARSE_QUOTE_XXX_END("'\\", "'''", SSS);
539 0 : break;
540 :
541 : case CONF_PARSE_STATE_UNQUOTE_DDD_END:
542 16 : CONF__SC_PARSE_UNQUOTE_END("\"\"\"");
543 8 : break;
544 :
545 : case CONF_PARSE_STATE_UNQUOTE_D_END:
546 28 : CONF__SC_PARSE_UNQUOTE_END("\"");
547 14 : break;
548 :
549 : case CONF_PARSE_STATE_UNQUOTE_SSS_END:
550 20 : CONF__SC_PARSE_UNQUOTE_END("'''");
551 10 : break;
552 :
553 : case CONF_PARSE_STATE_UNQUOTE_S_END:
554 24 : CONF__SC_PARSE_UNQUOTE_END("'");
555 12 : break;
556 :
557 : case CONF_PARSE_STATE_SYMBOL_END:
558 : {
559 153090 : int byte = vstr_export_chr(data, pos);
560 :
561 153090 : switch (byte)
562 : {
563 : case ' ': /* whitespace */
564 : case '\t': /* whitespace */
565 : case '\v': /* whitespace */
566 : case '\r': /* whitespace */
567 : case '\n': /* whitespace */
568 117236 : if (!(plen = conf__parse_comment(conf, pos, len)))
569 108788 : plen = conf__parse_ws(conf, pos, len);
570 58618 : break;
571 :
572 : case ')':
573 : case ']':
574 35846 : if (!(plen = conf__parse_comment(conf, pos, len)))
575 : {
576 35846 : plen = 1;
577 35846 : if (!conf__parse_end_list(conf, list_nums, byte))
578 0 : return (CONF_PARSE_ERR);
579 : }
580 17923 : break;
581 :
582 : case '(':
583 : case '[':
584 8 : if (!(plen = conf__parse_comment(conf, pos, len)))
585 : {
586 8 : plen = 1;
587 8 : if (!conf__parse_beg_list(conf, pos, list_nums))
588 0 : return (CONF_PARSE_ERR);
589 : }
590 4 : break;
591 :
592 : case '"':
593 : case '\'':
594 0 : return (CONF_PARSE_ERR);
595 : default:
596 0 : assert(FALSE);
597 0 : return (CONF_PARSE_ERR);
598 : }
599 : }
600 76545 : break;
601 :
602 : default:
603 0 : assert(FALSE);
604 0 : return (CONF_PARSE_ERR);
605 : }
606 :
607 471952 : len -= plen; pos += plen;
608 : }
609 :
610 5146 : if (conf->sects->malloc_bad || conf->depth)
611 0 : return (CONF_PARSE_ERR);
612 :
613 5146 : conf->state = CONF_PARSE_STATE_END;
614 5146 : return (CONF_PARSE_FIN);
615 : }
616 : #undef CONF__SC_PARSE_ESC_QUOTE
617 : #undef CONF__SC_PARSE_QUOTE_X_BEG
618 : #undef CONF__SC_PARSE_QUOTE_XXX_END
619 : #undef CONF__SC_PARSE_QUOTE_X_END
620 : #undef CONF__SC_PARSE_UNQUOTE_END
621 :
622 : Conf_token *conf_token_make(void)
623 0 : {
624 0 : Conf_token dummy = CONF_TOKEN_INIT;
625 0 : Conf_token *ret = MK(sizeof(Conf_token));
626 :
627 0 : if (!ret)
628 0 : return (NULL);
629 :
630 0 : *ret = dummy;
631 :
632 0 : return (ret);
633 : }
634 :
635 : void conf_token_free(Conf_token *token)
636 0 : {
637 0 : F(token);
638 0 : }
639 :
640 : static const char *conf__token_name_map[] = {
641 : "<** Error **>",
642 : "Circular bracket list",
643 : "Square bracket list",
644 : "Quoted string (double, RAW)",
645 : "Quoted string (double, with Escaping)",
646 : "Quoted string (3x double, RAW)",
647 : "Quoted string (3x double, with Escaping)",
648 : "Quoted string (single, RAW)",
649 : "Quoted string (single, with Escaping)",
650 : "Quoted string (3x single, RAW)",
651 : "Quoted string (3x single, with Escaping)",
652 : "Symbol"
653 : };
654 :
655 : const char *conf_token_name(const Conf_token *token)
656 10436 : {
657 5218 : ASSERT(token);
658 :
659 10436 : if (token->type > CONF_TOKEN_TYPE_SYMBOL)
660 0 : return ("User type");
661 :
662 10436 : return (conf__token_name_map[token->type]);
663 : }
664 :
665 : int conf_sc_token_parse_uint(const Conf_parse *conf, Conf_token *token,
666 : unsigned int *val)
667 4144 : {
668 4144 : unsigned int num = conf_token_list_num(token, token->depth_num);
669 4144 : int ern = CONF_SC_TYPE_RET_OK;
670 4144 : const Vstr_sect_node *pv = NULL;
671 4144 : unsigned int nflags = VSTR_FLAG02(PARSE_NUM, OVERFLOW, SEP);
672 4144 : size_t len = 0;
673 :
674 2072 : ASSERT(val);
675 :
676 4144 : if (!num)
677 0 : return (CONF_SC_TYPE_RET_ERR_NOT_EXIST);
678 4144 : conf_parse_token(conf, token);
679 4144 : if (!(pv = conf_token_value(token)))
680 0 : return (CONF_SC_TYPE_RET_ERR_PARSE);
681 :
682 4144 : *val = vstr_parse_uint(conf->data, pv->pos, pv->len, nflags, &len, NULL);
683 4144 : if (len != pv->len)
684 0 : ern = CONF_SC_TYPE_RET_ERR_PARSE;
685 :
686 4144 : return (ern);
687 : }
688 :
689 : int conf_sc_token_parse_ulong(const Conf_parse *conf, Conf_token *token,
690 : unsigned long *val)
691 0 : {
692 0 : unsigned int num = conf_token_list_num(token, token->depth_num);
693 0 : int ern = CONF_SC_TYPE_RET_OK;
694 0 : const Vstr_sect_node *pv = NULL;
695 0 : unsigned int nflags = VSTR_FLAG02(PARSE_NUM, OVERFLOW, SEP);
696 0 : size_t len = 0;
697 :
698 0 : ASSERT(val);
699 :
700 0 : if (!num)
701 0 : return (CONF_SC_TYPE_RET_ERR_NOT_EXIST);
702 0 : conf_parse_token(conf, token);
703 0 : if (!(pv = conf_token_value(token)))
704 0 : return (CONF_SC_TYPE_RET_ERR_PARSE);
705 :
706 0 : *val = vstr_parse_ulong(conf->data, pv->pos, pv->len, nflags, &len, NULL);
707 0 : if (len != pv->len)
708 0 : ern = CONF_SC_TYPE_RET_ERR_PARSE;
709 :
710 0 : return (ern);
711 : }
712 :
713 : int conf_sc_token_parse_uintmax(const Conf_parse *conf, Conf_token *token,
714 : uintmax_t *val)
715 58512 : {
716 58512 : unsigned int num = conf_token_list_num(token, token->depth_num);
717 58512 : int ern = CONF_SC_TYPE_RET_OK;
718 58512 : const Vstr_sect_node *pv = NULL;
719 58512 : unsigned int nflags = VSTR_FLAG02(PARSE_NUM, OVERFLOW, SEP);
720 58512 : size_t len = 0;
721 :
722 29256 : ASSERT(val);
723 :
724 58512 : if (!num)
725 0 : return (CONF_SC_TYPE_RET_ERR_NOT_EXIST);
726 58512 : conf_parse_token(conf, token);
727 58512 : if (!(pv = conf_token_value(token)))
728 0 : return (CONF_SC_TYPE_RET_ERR_PARSE);
729 :
730 58512 : *val = vstr_parse_uintmax(conf->data, pv->pos, pv->len, nflags, &len, NULL);
731 58512 : if (len != pv->len)
732 13728 : ern = CONF_SC_TYPE_RET_ERR_PARSE;
733 :
734 58512 : return (ern);
735 : }
736 :
737 : int conf_sc_token_app_vstr(const Conf_parse *conf, Conf_token *token,
738 : Vstr_base *s1,
739 : const Vstr_base **a_s1, size_t *a_pos, size_t *a_len)
740 16512 : {
741 16512 : unsigned int num = conf_token_list_num(token, token->depth_num);
742 16512 : int ern = CONF_SC_TYPE_RET_OK;
743 16512 : const Vstr_sect_node *pv = NULL;
744 :
745 8256 : ASSERT(s1);
746 :
747 16512 : if (!num)
748 0 : return (CONF_SC_TYPE_RET_ERR_NOT_EXIST);
749 16512 : conf_parse_token(conf, token);
750 16512 : if (!(pv = conf_token_value(token)))
751 0 : return (CONF_SC_TYPE_RET_ERR_PARSE);
752 :
753 16512 : if (vstr_add_vstr(s1, s1->len, conf->data, pv->pos, pv->len,
754 : VSTR_TYPE_SUB_BUF_REF))
755 : {
756 16512 : *a_s1 = s1;
757 16512 : *a_pos = (s1->len - pv->len) + 1;
758 16512 : *a_len = pv->len;
759 : }
760 :
761 16512 : return (ern);
762 : }
763 :
764 : int conf_sc_token_sub_vstr(const Conf_parse *conf, Conf_token *token,
765 : Vstr_base *s1, size_t pos, size_t len)
766 144 : {
767 144 : unsigned int num = conf_token_list_num(token, token->depth_num);
768 144 : int ern = CONF_SC_TYPE_RET_OK;
769 144 : const Vstr_sect_node *pv = NULL;
770 :
771 72 : ASSERT(s1);
772 :
773 144 : if (!num)
774 0 : return (CONF_SC_TYPE_RET_ERR_NOT_EXIST);
775 144 : conf_parse_token(conf, token);
776 144 : if (!(pv = conf_token_value(token)))
777 0 : return (CONF_SC_TYPE_RET_ERR_PARSE);
778 :
779 144 : vstr_sub_vstr(s1, pos, len, conf->data, pv->pos, pv->len,
780 : VSTR_TYPE_SUB_BUF_REF);
781 :
782 144 : return (ern);
783 : }
784 :
785 : #define SUB2(x, y, z) vstr_sub_cstr_buf(x, y, 2, z)
786 : int conf_sc_conv_unesc(Vstr_base *s1, size_t pos, size_t len,
787 : size_t *ret_len)
788 1152 : {
789 : size_t dummy_len;
790 :
791 1152 : if (!ret_len) ret_len = &dummy_len;
792 :
793 1152 : *ret_len = len;
794 :
795 20736 : while (!s1->conf->malloc_bad && (len > 1))
796 : {
797 18432 : size_t plen = vstr_cspn_cstr_chrs_fwd(s1, pos, len, "\\");
798 :
799 18432 : if (!plen)
800 : {
801 18432 : char chr = vstr_export_chr(s1, pos + 1);
802 :
803 18432 : if (chr == '\n')
804 : {
805 0 : vstr_del(s1, pos, 2);
806 0 : len -= 2; *ret_len -= 2;
807 0 : continue;
808 : }
809 18432 : else if (chr == 't') { SUB2(s1, pos, "\t"); --len; --*ret_len; }
810 18432 : else if (chr == 'v') { SUB2(s1, pos, "\v"); --len; --*ret_len; }
811 18432 : else if (chr == 'r') { SUB2(s1, pos, "\r"); --len; --*ret_len; }
812 18432 : else if (chr == 'n') { SUB2(s1, pos, "\n"); --len; --*ret_len; }
813 18432 : else if (chr == 'b') { SUB2(s1, pos, "\b"); --len; --*ret_len; }
814 18432 : else if ((chr >= '0') && (chr <= '9'))
815 : { /* \0 == NIL \377 | \0377 == UCHAR_MAX */
816 0 : unsigned char val = 0;
817 0 : unsigned int nflags = 8 | VSTR_FLAG_PARSE_NUM_OVERFLOW;
818 0 : unsigned int nlen = min_t(unsigned int, 4, len - 1);
819 :
820 : /* FIXME: ... parse uchar */
821 0 : val = vstr_parse_ushort(s1, pos + 1, nlen, nflags, &plen, NULL);
822 0 : vstr_sub_rep_chr(s1, pos, plen + 1, val, 1);
823 0 : len -= plen; /* byte == \ ... so not plen + 1 */
824 0 : *ret_len -= plen;
825 : }
826 27648 : else if ((chr == 'x') && (len >= 4))
827 : { /* \x00 == NIL \xff == UCHAR_MAX */
828 18432 : unsigned char val = 0;
829 18432 : unsigned int nflags = 16 | VSTR_FLAG_PARSE_NUM_OVERFLOW;
830 :
831 18432 : val = vstr_parse_ushort(s1, pos + 2, 2, nflags, NULL, NULL);
832 18432 : vstr_sub_rep_chr(s1, pos, 4, val, 1);
833 18432 : len -= 3; /* byte == \ ... so not 4 */
834 18432 : *ret_len -= 3;
835 : }
836 : else
837 : { /* rm \ ... Eg. \" == " and \\ == \ */
838 0 : vstr_del(s1, pos, 1);
839 0 : --len; --*ret_len;
840 : }
841 18432 : plen = 1;
842 : }
843 :
844 18432 : len -= plen;
845 18432 : pos += plen;
846 : }
847 :
848 1152 : return (!s1->conf->malloc_bad);
849 : }
850 : #undef SUB
851 :
852 : int conf_token_set_user_value(Conf_parse *conf, Conf_token *token,
853 : unsigned int type,
854 : Vstr_ref *uval, unsigned int nxt)
855 5398 : {
856 5398 : Vstr_ref *oref = NULL;
857 :
858 2699 : ASSERT(conf && token);
859 2699 : ASSERT(type <= (UINT_MAX - CONF_TOKEN_TYPE_USER_BEG));
860 :
861 : /* must not be a CLIST or SLIST */
862 5398 : if ((token->type == CONF_TOKEN_TYPE_CLIST) ||
863 : (token->type == CONF_TOKEN_TYPE_SLIST))
864 0 : return (FALSE);
865 :
866 5398 : if (token->type >= CONF_TOKEN_TYPE_USER_BEG)
867 990 : oref = conf->uvals_ptr[token->u.uval_num].ref;
868 : else
869 : {
870 4408 : if (conf->uvals_sz <= conf->uvals_num)
871 : {
872 3576 : unsigned int num = (conf->uvals_sz << 1) + 1;
873 3576 : Conf__uval_store *uvals = NULL;
874 :
875 3576 : if (num <= conf->uvals_sz)
876 0 : return (FALSE);
877 :
878 3576 : if (!conf->uvals_sz &&
879 : !(conf->uvals_ptr = MK(sizeof(Conf__uval_store) * num)))
880 0 : return (FALSE);
881 3576 : else if (!MV(conf->uvals_ptr, uvals, sizeof(Conf__uval_store) * num))
882 0 : return (FALSE);
883 :
884 3576 : conf->uvals_sz = num;
885 : }
886 4408 : VSTR_SECTS_NUM(conf->sects, token->num)->pos = conf->uvals_num;
887 4408 : token->u.uval_num = conf->uvals_num;
888 :
889 4408 : ++conf->uvals_num;
890 : }
891 :
892 5398 : token->type = CONF_TOKEN_TYPE_USER_BEG + type;
893 :
894 5398 : conf->types_ptr[token->num - 1] = token->type;
895 5398 : conf->uvals_ptr[token->u.uval_num].ref = NULL;
896 5398 : conf->uvals_ptr[token->u.uval_num].nxt = nxt;
897 5398 : if (uval)
898 5050 : conf->uvals_ptr[token->u.uval_num].ref = vstr_ref_add(uval);
899 :
900 5398 : vstr_ref_del(oref);
901 :
902 5398 : return (TRUE);
903 : }
904 :
905 : void conf_parse_compress(Conf_parse *conf)
906 0 : { /* FIXME: remove all Vstr data that isn't referenced, fixup sections */
907 : (void)conf;
908 0 : }
909 :
910 : void conf_parse_backtrace(Vstr_base *out, const char *filename,
911 : const Conf_parse *conf, const Conf_token *token)
912 72 : {
913 72 : const Vstr_sect_node *val = NULL;
914 :
915 72 : if (!out)
916 0 : return;
917 :
918 72 : if (conf->state != CONF_PARSE_STATE_END)
919 : {
920 0 : vstr_add_fmt(out, out->len, "Syntax error in %s, ", filename);
921 0 : vstr_add_fmt(out, out->len, " State was: %d", conf->state);
922 0 : return;
923 : }
924 :
925 : /* walk backwards */
926 72 : if (token->type > CONF_TOKEN_TYPE_SYMBOL)
927 0 : vstr_add_fmt(out, out->len, "Failed parse on node %u (%s %d)",
928 : token->num, conf_token_name(token),
929 : token->type - CONF_TOKEN_TYPE_SYMBOL);
930 72 : else if (!(val = conf_token_value(token)))
931 0 : vstr_add_fmt(out, out->len, "Failed parse on node %u [%s]",
932 : token->num, conf_token_name(token));
933 : else
934 : {
935 72 : Vstr_base *s1 = conf->data;
936 :
937 72 : vstr_add_fmt(out, out->len, "Failed parse on node %u <%s> = ",
938 : token->num, conf_token_name(token));
939 72 : vstr_add_vstr(out, out->len, s1, val->pos, val->len, VSTR_TYPE_ADD_BUF_REF);
940 : }
941 : }
|