1 /* Copyright (c) 2013, Vsevolod Stakhov
2 * All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 * * Redistributions of source code must retain the above copyright
7 * notice, this list of conditions and the following disclaimer.
8 * * Redistributions in binary form must reproduce the above copyright
9 * notice, this list of conditions and the following disclaimer in the
10 * documentation and/or other materials provided with the distribution.
11 *
12 * THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY
13 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
14 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
15 * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY
16 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
17 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
18 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
19 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
20 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
21 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
22 */
23
24 #include <math.h>
25 #include "ucl.h"
26 #include "ucl_internal.h"
27 #include "ucl_chartable.h"
28
29 /**
30 * @file ucl_parser.c
31 * The implementation of ucl parser
32 */
33
34 struct ucl_parser_saved_state {
35 unsigned int line;
36 unsigned int column;
37 size_t remain;
38 const unsigned char *pos;
39 };
40
41 /**
42 * Move up to len characters
43 * @param parser
44 * @param begin
45 * @param len
46 * @return new position in chunk
47 */
48 #define ucl_chunk_skipc(chunk, p) \
49 do { \
50 if (p == chunk->end) { \
51 break; \
52 } \
53 if (*(p) == '\n') { \
54 (chunk)->line ++; \
55 (chunk)->column = 0; \
56 } \
57 else (chunk)->column ++; \
58 (p++); \
59 (chunk)->pos ++; \
60 (chunk)->remain --; \
61 } while (0)
62
63 static inline void
ucl_set_err(struct ucl_parser * parser,int code,const char * str,UT_string ** err)64 ucl_set_err (struct ucl_parser *parser, int code, const char *str, UT_string **err)
65 {
66 const char *fmt_string, *filename;
67 struct ucl_chunk *chunk = parser->chunks;
68
69 if (parser->cur_file) {
70 filename = parser->cur_file;
71 }
72 else {
73 filename = "<unknown>";
74 }
75
76 if (chunk->pos < chunk->end) {
77 if (isgraph (*chunk->pos)) {
78 fmt_string = "error while parsing %s: "
79 "line: %d, column: %d - '%s', character: '%c'";
80 }
81 else {
82 fmt_string = "error while parsing %s: "
83 "line: %d, column: %d - '%s', character: '0x%02x'";
84 }
85 ucl_create_err (err, fmt_string,
86 filename, chunk->line, chunk->column,
87 str, *chunk->pos);
88 }
89 else {
90 ucl_create_err (err, "error while parsing %s: at the end of chunk: %s",
91 filename, str);
92 }
93
94 parser->err_code = code;
95 parser->state = UCL_STATE_ERROR;
96 }
97
98 static void
ucl_save_comment(struct ucl_parser * parser,const char * begin,size_t len)99 ucl_save_comment (struct ucl_parser *parser, const char *begin, size_t len)
100 {
101 ucl_object_t *nobj;
102
103 if (len > 0 && begin != NULL) {
104 nobj = ucl_object_fromstring_common (begin, len, 0);
105
106 if (parser->last_comment) {
107 /* We need to append data to an existing object */
108 DL_APPEND (parser->last_comment, nobj);
109 }
110 else {
111 parser->last_comment = nobj;
112 }
113 }
114 }
115
116 static void
ucl_attach_comment(struct ucl_parser * parser,ucl_object_t * obj,bool before)117 ucl_attach_comment (struct ucl_parser *parser, ucl_object_t *obj, bool before)
118 {
119 if (parser->last_comment) {
120 ucl_object_insert_key (parser->comments, parser->last_comment,
121 (const char *)&obj, sizeof (void *), true);
122
123 if (before) {
124 parser->last_comment->flags |= UCL_OBJECT_INHERITED;
125 }
126
127 parser->last_comment = NULL;
128 }
129 }
130
131 /**
132 * Skip all comments from the current pos resolving nested and multiline comments
133 * @param parser
134 * @return
135 */
136 static bool
ucl_skip_comments(struct ucl_parser * parser)137 ucl_skip_comments (struct ucl_parser *parser)
138 {
139 struct ucl_chunk *chunk = parser->chunks;
140 const unsigned char *p, *beg = NULL;
141 int comments_nested = 0;
142 bool quoted = false;
143
144 p = chunk->pos;
145
146 start:
147 if (chunk->remain > 0 && *p == '#') {
148 if (parser->state != UCL_STATE_SCOMMENT &&
149 parser->state != UCL_STATE_MCOMMENT) {
150 beg = p;
151
152 while (p < chunk->end) {
153 if (*p == '\n') {
154 if (parser->flags & UCL_PARSER_SAVE_COMMENTS) {
155 ucl_save_comment (parser, beg, p - beg);
156 beg = NULL;
157 }
158
159 ucl_chunk_skipc (chunk, p);
160
161 goto start;
162 }
163 ucl_chunk_skipc (chunk, p);
164 }
165 }
166 }
167 else if (chunk->remain >= 2 && *p == '/' && p[1] == '*') {
168 beg = p;
169 comments_nested ++;
170 ucl_chunk_skipc (chunk, p);
171 ucl_chunk_skipc (chunk, p);
172 while (p < chunk->end) {
173 if (*p == '"' && *(p - 1) != '\\') {
174 /* begin or end double-quoted string */
175 quoted = !quoted;
176 ucl_chunk_skipc (chunk, p);
177 }
178 else if (quoted) {
179 /* quoted character */
180 ucl_chunk_skipc (chunk, p);
181 }
182 else if (chunk->remain >= 2 && *p == '*' && p[1] == '/') {
183 /* end of comment */
184 ucl_chunk_skipc (chunk, p);
185 ucl_chunk_skipc (chunk, p);
186 comments_nested --;
187 if (comments_nested == 0) {
188 if (parser->flags & UCL_PARSER_SAVE_COMMENTS) {
189 ucl_save_comment (parser, beg, p - beg + 1);
190 beg = NULL;
191 }
192 goto start;
193 }
194 }
195 else if (chunk->remain >= 2 && *p == '/' && p[1] == '*') {
196 /* start of nested comment */
197 comments_nested ++;
198 ucl_chunk_skipc (chunk, p);
199 ucl_chunk_skipc (chunk, p);
200 }
201 else {
202 /* anything else */
203 ucl_chunk_skipc (chunk, p);
204 }
205 }
206 if (comments_nested != 0) {
207 ucl_set_err (parser, UCL_ENESTED,
208 "unfinished multiline comment", &parser->err);
209 return false;
210 }
211 }
212
213 if (beg && p > beg && (parser->flags & UCL_PARSER_SAVE_COMMENTS)) {
214 ucl_save_comment (parser, beg, p - beg);
215 }
216
217 return true;
218 }
219
220 /**
221 * Return multiplier for a character
222 * @param c multiplier character
223 * @param is_bytes if true use 1024 multiplier
224 * @return multiplier
225 */
226 static inline unsigned long
ucl_lex_num_multiplier(const unsigned char c,bool is_bytes)227 ucl_lex_num_multiplier (const unsigned char c, bool is_bytes) {
228 const struct {
229 char c;
230 long mult_normal;
231 long mult_bytes;
232 } multipliers[] = {
233 {'m', 1000 * 1000, 1024 * 1024},
234 {'k', 1000, 1024},
235 {'g', 1000 * 1000 * 1000, 1024 * 1024 * 1024}
236 };
237 int i;
238
239 for (i = 0; i < 3; i ++) {
240 if (tolower (c) == multipliers[i].c) {
241 if (is_bytes) {
242 return multipliers[i].mult_bytes;
243 }
244 return multipliers[i].mult_normal;
245 }
246 }
247
248 return 1;
249 }
250
251
252 /**
253 * Return multiplier for time scaling
254 * @param c
255 * @return
256 */
257 static inline double
ucl_lex_time_multiplier(const unsigned char c)258 ucl_lex_time_multiplier (const unsigned char c) {
259 const struct {
260 char c;
261 double mult;
262 } multipliers[] = {
263 {'m', 60},
264 {'h', 60 * 60},
265 {'d', 60 * 60 * 24},
266 {'w', 60 * 60 * 24 * 7},
267 {'y', 60 * 60 * 24 * 365}
268 };
269 int i;
270
271 for (i = 0; i < 5; i ++) {
272 if (tolower (c) == multipliers[i].c) {
273 return multipliers[i].mult;
274 }
275 }
276
277 return 1;
278 }
279
280 /**
281 * Return true if a character is a end of an atom
282 * @param c
283 * @return
284 */
285 static inline bool
ucl_lex_is_atom_end(const unsigned char c)286 ucl_lex_is_atom_end (const unsigned char c)
287 {
288 return ucl_test_character (c, UCL_CHARACTER_VALUE_END);
289 }
290
291 static inline bool
ucl_lex_is_comment(const unsigned char c1,const unsigned char c2)292 ucl_lex_is_comment (const unsigned char c1, const unsigned char c2)
293 {
294 if (c1 == '/') {
295 if (c2 == '*') {
296 return true;
297 }
298 }
299 else if (c1 == '#') {
300 return true;
301 }
302 return false;
303 }
304
305 /**
306 * Check variable found
307 * @param parser
308 * @param ptr
309 * @param remain
310 * @param out_len
311 * @param strict
312 * @param found
313 * @return
314 */
315 static inline const char *
ucl_check_variable_safe(struct ucl_parser * parser,const char * ptr,size_t remain,size_t * out_len,bool strict,bool * found)316 ucl_check_variable_safe (struct ucl_parser *parser, const char *ptr, size_t remain,
317 size_t *out_len, bool strict, bool *found)
318 {
319 struct ucl_variable *var;
320 unsigned char *dst;
321 size_t dstlen;
322 bool need_free = false;
323
324 LL_FOREACH (parser->variables, var) {
325 if (strict) {
326 if (remain == var->var_len) {
327 if (memcmp (ptr, var->var, var->var_len) == 0) {
328 *out_len += var->value_len;
329 *found = true;
330 return (ptr + var->var_len);
331 }
332 }
333 }
334 else {
335 if (remain >= var->var_len) {
336 if (memcmp (ptr, var->var, var->var_len) == 0) {
337 *out_len += var->value_len;
338 *found = true;
339 return (ptr + var->var_len);
340 }
341 }
342 }
343 }
344
345 /* XXX: can only handle ${VAR} */
346 if (!(*found) && parser->var_handler != NULL && strict) {
347 /* Call generic handler */
348 if (parser->var_handler (ptr, remain, &dst, &dstlen, &need_free,
349 parser->var_data)) {
350 *found = true;
351 *out_len = dstlen;
352
353 if (need_free) {
354 free (dst);
355 }
356 return (ptr + remain);
357 }
358 }
359
360 return ptr;
361 }
362
363 /**
364 * Check for a variable in a given string
365 * @param parser
366 * @param ptr
367 * @param remain
368 * @param out_len
369 * @param vars_found
370 * @return
371 */
372 static const char *
ucl_check_variable(struct ucl_parser * parser,const char * ptr,size_t remain,size_t * out_len,bool * vars_found)373 ucl_check_variable (struct ucl_parser *parser, const char *ptr,
374 size_t remain, size_t *out_len, bool *vars_found)
375 {
376 const char *p, *end, *ret = ptr;
377 bool found = false;
378
379 if (*ptr == '{') {
380 /* We need to match the variable enclosed in braces */
381 p = ptr + 1;
382 end = ptr + remain;
383 while (p < end) {
384 if (*p == '}') {
385 ret = ucl_check_variable_safe (parser, ptr + 1, p - ptr - 1,
386 out_len, true, &found);
387 if (found) {
388 /* {} must be excluded actually */
389 ret ++;
390 if (!*vars_found) {
391 *vars_found = true;
392 }
393 }
394 else {
395 *out_len += 2;
396 }
397 break;
398 }
399 p ++;
400 }
401 if(p == end) {
402 (*out_len) ++;
403 }
404 }
405 else if (*ptr != '$') {
406 /* Not count escaped dollar sign */
407 ret = ucl_check_variable_safe (parser, ptr, remain, out_len, false, &found);
408 if (found && !*vars_found) {
409 *vars_found = true;
410 }
411 if (!found) {
412 (*out_len) ++;
413 }
414 }
415 else {
416 ret ++;
417 (*out_len) ++;
418 }
419
420 return ret;
421 }
422
423 /**
424 * Expand a single variable
425 * @param parser
426 * @param ptr
427 * @param in_len
428 * @param dest
429 * @param out_len
430 * @return
431 */
432 static const char *
ucl_expand_single_variable(struct ucl_parser * parser,const char * ptr,size_t in_len,unsigned char ** dest,size_t out_len)433 ucl_expand_single_variable (struct ucl_parser *parser, const char *ptr,
434 size_t in_len, unsigned char **dest, size_t out_len)
435 {
436 unsigned char *d = *dest, *dst;
437 const char *p = ptr + 1, *ret;
438 struct ucl_variable *var;
439 size_t dstlen;
440 bool need_free = false;
441 bool found = false;
442 bool strict = false;
443
444 ret = ptr + 1;
445 /* For the $ sign */
446 in_len --;
447
448 if (*p == '$') {
449 *d++ = *p++;
450 *dest = d;
451 return p;
452 }
453 else if (*p == '{') {
454 p ++;
455 in_len --;
456 strict = true;
457 ret += 2;
458 }
459
460 LL_FOREACH (parser->variables, var) {
461 if (out_len >= var->value_len && in_len >= (var->var_len + (strict ? 1 : 0))) {
462 if (memcmp (p, var->var, var->var_len) == 0) {
463 if (!strict || p[var->var_len] == '}') {
464 memcpy (d, var->value, var->value_len);
465 ret += var->var_len;
466 d += var->value_len;
467 found = true;
468 break;
469 }
470 }
471 }
472 }
473
474 if (!found) {
475 if (strict && parser->var_handler != NULL) {
476 dstlen = out_len;
477
478 if (parser->var_handler (p, in_len, &dst, &dstlen, &need_free,
479 parser->var_data)) {
480 if (dstlen > out_len) {
481 /* We do not have enough space! */
482 if (need_free) {
483 free (dst);
484 }
485 }
486 else {
487 memcpy(d, dst, dstlen);
488 ret += in_len;
489 d += dstlen;
490 found = true;
491
492 if (need_free) {
493 free(dst);
494 }
495 }
496 }
497 }
498
499 /* Leave variable as is, in this case we use dest */
500 if (!found) {
501 if (strict && out_len >= 2) {
502 /* Copy '${' */
503 memcpy (d, ptr, 2);
504 d += 2;
505 ret --;
506 }
507 else {
508 memcpy (d, ptr, 1);
509 d ++;
510 }
511 }
512 }
513
514 *dest = d;
515 return ret;
516 }
517
518 /**
519 * Expand variables in string
520 * @param parser
521 * @param dst
522 * @param src
523 * @param in_len
524 * @return
525 */
526 static ssize_t
ucl_expand_variable(struct ucl_parser * parser,unsigned char ** dst,const char * src,size_t in_len)527 ucl_expand_variable (struct ucl_parser *parser, unsigned char **dst,
528 const char *src, size_t in_len)
529 {
530 const char *p, *end = src + in_len;
531 unsigned char *d, *d_end;
532 size_t out_len = 0;
533 bool vars_found = false;
534
535 if (parser->flags & UCL_PARSER_DISABLE_MACRO) {
536 *dst = NULL;
537 return in_len;
538 }
539
540 p = src;
541 while (p != end) {
542 if (*p == '$' && p + 1 != end) {
543 p = ucl_check_variable (parser, p + 1, end - p - 1, &out_len, &vars_found);
544 }
545 else {
546 p ++;
547 out_len ++;
548 }
549 }
550
551 if (!vars_found) {
552 /* Trivial case */
553 *dst = NULL;
554 return in_len;
555 }
556
557 *dst = UCL_ALLOC (out_len + 1);
558 if (*dst == NULL) {
559 return in_len;
560 }
561
562 d = *dst;
563 d_end = d + out_len;
564 p = src;
565 while (p != end && d != d_end) {
566 if (*p == '$' && p + 1 != end) {
567 p = ucl_expand_single_variable (parser, p, end - p, &d, d_end - d);
568 }
569 else {
570 *d++ = *p++;
571 }
572 }
573
574 *d = '\0';
575
576 return out_len;
577 }
578
579 /**
580 * Store or copy pointer to the trash stack
581 * @param parser parser object
582 * @param src src string
583 * @param dst destination buffer (trash stack pointer)
584 * @param dst_const const destination pointer (e.g. value of object)
585 * @param in_len input length
586 * @param need_unescape need to unescape source (and copy it)
587 * @param need_lowercase need to lowercase value (and copy)
588 * @param need_expand need to expand variables (and copy as well)
589 * @param unescape_squote unescape single quoted string
590 * @return output length (excluding \0 symbol)
591 */
592 static inline ssize_t
ucl_copy_or_store_ptr(struct ucl_parser * parser,const unsigned char * src,unsigned char ** dst,const char ** dst_const,size_t in_len,bool need_unescape,bool need_lowercase,bool need_expand,bool unescape_squote)593 ucl_copy_or_store_ptr (struct ucl_parser *parser,
594 const unsigned char *src, unsigned char **dst,
595 const char **dst_const, size_t in_len,
596 bool need_unescape, bool need_lowercase, bool need_expand,
597 bool unescape_squote)
598 {
599 ssize_t ret = -1, tret;
600 unsigned char *tmp;
601
602 if (need_unescape || need_lowercase ||
603 (need_expand && parser->variables != NULL) ||
604 !(parser->flags & UCL_PARSER_ZEROCOPY)) {
605 /* Copy string */
606 *dst = UCL_ALLOC (in_len + 1);
607 if (*dst == NULL) {
608 ucl_set_err (parser, UCL_EINTERNAL, "cannot allocate memory for a string",
609 &parser->err);
610 return false;
611 }
612 if (need_lowercase) {
613 ret = ucl_strlcpy_tolower (*dst, src, in_len + 1);
614 }
615 else {
616 ret = ucl_strlcpy_unsafe (*dst, src, in_len + 1);
617 }
618
619 if (need_unescape) {
620 if (!unescape_squote) {
621 ret = ucl_unescape_json_string (*dst, ret);
622 }
623 else {
624 ret = ucl_unescape_squoted_string (*dst, ret);
625 }
626 }
627
628 if (need_expand) {
629 tmp = *dst;
630 tret = ret;
631 ret = ucl_expand_variable (parser, dst, tmp, ret);
632 if (*dst == NULL) {
633 /* Nothing to expand */
634 *dst = tmp;
635 ret = tret;
636 }
637 else {
638 /* Free unexpanded value */
639 UCL_FREE (in_len + 1, tmp);
640 }
641 }
642 *dst_const = *dst;
643 }
644 else {
645 *dst_const = src;
646 ret = in_len;
647 }
648
649 return ret;
650 }
651
652 /**
653 * Create and append an object at the specified level
654 * @param parser
655 * @param is_array
656 * @param level
657 * @return
658 */
659 static inline ucl_object_t *
ucl_parser_add_container(ucl_object_t * obj,struct ucl_parser * parser,bool is_array,uint32_t level,bool has_obrace)660 ucl_parser_add_container (ucl_object_t *obj, struct ucl_parser *parser,
661 bool is_array, uint32_t level, bool has_obrace)
662 {
663 struct ucl_stack *st;
664 ucl_object_t *nobj;
665
666 if (obj == NULL) {
667 nobj = ucl_object_new_full (is_array ? UCL_ARRAY : UCL_OBJECT, parser->chunks->priority);
668 if (nobj == NULL) {
669 goto enomem0;
670 }
671 } else {
672 if (obj->type == (is_array ? UCL_OBJECT : UCL_ARRAY)) {
673 /* Bad combination for merge: array and object */
674 ucl_set_err (parser, UCL_EMERGE,
675 "cannot merge an object with an array",
676 &parser->err);
677
678 return NULL;
679 }
680 nobj = obj;
681 nobj->type = is_array ? UCL_ARRAY : UCL_OBJECT;
682 }
683
684 if (!is_array) {
685 if (nobj->value.ov == NULL) {
686 nobj->value.ov = ucl_hash_create (parser->flags & UCL_PARSER_KEY_LOWERCASE);
687 if (nobj->value.ov == NULL) {
688 goto enomem1;
689 }
690 }
691 parser->state = UCL_STATE_KEY;
692 } else {
693 parser->state = UCL_STATE_VALUE;
694 }
695
696 st = UCL_ALLOC (sizeof (struct ucl_stack));
697
698 if (st == NULL) {
699 goto enomem1;
700 }
701
702 st->obj = nobj;
703
704 if (level >= UINT16_MAX) {
705 ucl_set_err (parser, UCL_ENESTED,
706 "objects are nesting too deep (over 65535 limit)",
707 &parser->err);
708 if (nobj != obj) {
709 ucl_object_unref (obj);
710 }
711
712 UCL_FREE(sizeof (struct ucl_stack), st);
713
714 return NULL;
715 }
716
717
718 st->e.params.level = level;
719 st->e.params.line = parser->chunks->line;
720 st->chunk = parser->chunks;
721
722 if (has_obrace) {
723 st->e.params.flags = UCL_STACK_HAS_OBRACE;
724 }
725 else {
726 st->e.params.flags = 0;
727 }
728
729 LL_PREPEND (parser->stack, st);
730 parser->cur_obj = nobj;
731
732 return nobj;
733 enomem1:
734 if (nobj != obj)
735 ucl_object_unref (nobj);
736 enomem0:
737 ucl_set_err (parser, UCL_EINTERNAL, "cannot allocate memory for an object",
738 &parser->err);
739 return NULL;
740 }
741
742 int
ucl_maybe_parse_number(ucl_object_t * obj,const char * start,const char * end,const char ** pos,bool allow_double,bool number_bytes,bool allow_time)743 ucl_maybe_parse_number (ucl_object_t *obj,
744 const char *start, const char *end, const char **pos,
745 bool allow_double, bool number_bytes, bool allow_time)
746 {
747 const char *p = start, *c = start;
748 char *endptr;
749 bool got_dot = false, got_exp = false, need_double = false,
750 is_time = false, valid_start = false, is_hex = false;
751 int is_neg = 0;
752 double dv = 0;
753 int64_t lv = 0;
754
755 if (*p == '-') {
756 is_neg = 1;
757 c ++;
758 p ++;
759 }
760 while (p < end) {
761 if (is_hex && isxdigit (*p)) {
762 p ++;
763 }
764 else if (isdigit (*p)) {
765 valid_start = true;
766 p ++;
767 }
768 else if (!is_hex && (*p == 'x' || *p == 'X')) {
769 is_hex = true;
770 allow_double = false;
771 c = p + 1;
772 p ++;
773 }
774 else if (allow_double) {
775 if (p == c) {
776 /* Empty digits sequence, not a number */
777 *pos = start;
778 return EINVAL;
779 }
780 else if (*p == '.') {
781 if (got_dot) {
782 /* Double dots, not a number */
783 *pos = start;
784 return EINVAL;
785 }
786 else {
787 got_dot = true;
788 need_double = true;
789 p ++;
790 }
791 }
792 else if (*p == 'e' || *p == 'E') {
793 if (got_exp) {
794 /* Double exp, not a number */
795 *pos = start;
796 return EINVAL;
797 }
798 else {
799 got_exp = true;
800 need_double = true;
801 p ++;
802 if (p >= end) {
803 *pos = start;
804 return EINVAL;
805 }
806 if (!isdigit (*p) && *p != '+' && *p != '-') {
807 /* Wrong exponent sign */
808 *pos = start;
809 return EINVAL;
810 }
811 else {
812 p ++;
813 }
814 }
815 }
816 else {
817 /* Got the end of the number, need to check */
818 break;
819 }
820 }
821 else if (!allow_double && *p == '.') {
822 /* Unexpected dot */
823 *pos = start;
824 return EINVAL;
825 }
826 else {
827 break;
828 }
829 }
830
831 if (!valid_start || p == c) {
832 *pos = start;
833 return EINVAL;
834 }
835
836 char numbuf[128];
837
838 if ((size_t)(p - c + 1) >= sizeof(numbuf)) {
839 *pos = start;
840 return EINVAL;
841 }
842
843 if (is_neg) {
844 numbuf[0] = '-';
845 ucl_strlcpy (&numbuf[1], c, p - c + 1);
846 }
847 else {
848 ucl_strlcpy (numbuf, c, p - c + 1);
849 }
850
851 errno = 0;
852 if (need_double) {
853 dv = strtod (numbuf, &endptr);
854 }
855 else {
856 if (is_hex) {
857 lv = strtoimax (numbuf, &endptr, 16);
858 }
859 else {
860 lv = strtoimax (numbuf, &endptr, 10);
861 }
862 }
863 if (errno == ERANGE) {
864 *pos = start;
865 return ERANGE;
866 }
867
868 /* Now check endptr and move it from numbuf to the real ending */
869 if (endptr != NULL) {
870 long shift = endptr - numbuf - is_neg;
871 endptr = (char *)c + shift;
872 }
873 if (endptr >= end) {
874 p = end;
875 goto set_obj;
876 }
877 if (endptr == NULL || ucl_lex_is_atom_end (*endptr) || *endptr == '\0') {
878 p = endptr;
879 goto set_obj;
880 }
881
882 if (endptr < end && endptr != start) {
883 p = endptr;
884 switch (*p) {
885 case 'm':
886 case 'M':
887 case 'g':
888 case 'G':
889 case 'k':
890 case 'K':
891 if (end - p >= 2) {
892 if (p[1] == 's' || p[1] == 'S') {
893 /* Milliseconds */
894 if (!need_double) {
895 need_double = true;
896 dv = lv;
897 }
898 is_time = true;
899 if (p[0] == 'm' || p[0] == 'M') {
900 dv /= 1000.;
901 }
902 else {
903 dv *= ucl_lex_num_multiplier (*p, false);
904 }
905 p += 2;
906 if (end - p > 0 && !ucl_lex_is_atom_end (*p)) {
907 *pos = start;
908 return EINVAL;
909 }
910 goto set_obj;
911 }
912 else if (number_bytes || (p[1] == 'b' || p[1] == 'B')) {
913 /* Bytes */
914 if (need_double) {
915 need_double = false;
916 lv = dv;
917 }
918 lv *= ucl_lex_num_multiplier (*p, true);
919 p += 2;
920 if (end - p > 0 && !ucl_lex_is_atom_end (*p)) {
921 *pos = start;
922 return EINVAL;
923 }
924 goto set_obj;
925 }
926 else if (ucl_lex_is_atom_end (p[1])) {
927 if (need_double) {
928 dv *= ucl_lex_num_multiplier (*p, false);
929 }
930 else {
931 lv *= ucl_lex_num_multiplier (*p, number_bytes);
932 }
933 p ++;
934 goto set_obj;
935 }
936 else if (allow_time && end - p >= 3) {
937 if (tolower (p[0]) == 'm' &&
938 tolower (p[1]) == 'i' &&
939 tolower (p[2]) == 'n') {
940 /* Minutes */
941 if (!need_double) {
942 need_double = true;
943 dv = lv;
944 }
945 is_time = true;
946 dv *= 60.;
947 p += 3;
948 if (end - p > 0 && !ucl_lex_is_atom_end (*p)) {
949 *pos = start;
950 return EINVAL;
951 }
952 goto set_obj;
953 }
954 }
955 }
956 else {
957 if (need_double) {
958 dv *= ucl_lex_num_multiplier (*p, false);
959 }
960 else {
961 lv *= ucl_lex_num_multiplier (*p, number_bytes);
962 }
963 p ++;
964 if (end - p > 0 && !ucl_lex_is_atom_end (*p)) {
965 *pos = start;
966 return EINVAL;
967 }
968 goto set_obj;
969 }
970 break;
971 case 'S':
972 case 's':
973 if (allow_time &&
974 (p == end - 1 || ucl_lex_is_atom_end (p[1]))) {
975 if (!need_double) {
976 need_double = true;
977 dv = lv;
978 }
979 p ++;
980 is_time = true;
981 goto set_obj;
982 }
983 break;
984 case 'h':
985 case 'H':
986 case 'd':
987 case 'D':
988 case 'w':
989 case 'W':
990 case 'Y':
991 case 'y':
992 if (allow_time &&
993 (p == end - 1 || ucl_lex_is_atom_end (p[1]))) {
994 if (!need_double) {
995 need_double = true;
996 dv = lv;
997 }
998 is_time = true;
999 dv *= ucl_lex_time_multiplier (*p);
1000 p ++;
1001 goto set_obj;
1002 }
1003 break;
1004 case '\t':
1005 case ' ':
1006 while (p < end && ucl_test_character(*p, UCL_CHARACTER_WHITESPACE)) {
1007 p++;
1008 }
1009 if (ucl_lex_is_atom_end(*p))
1010 goto set_obj;
1011 break;
1012 }
1013 }
1014 else if (endptr == end) {
1015 /* Just a number at the end of chunk */
1016 p = end;
1017 goto set_obj;
1018 }
1019
1020 *pos = c;
1021 return EINVAL;
1022
1023 set_obj:
1024 if (obj != NULL) {
1025 if (allow_double && (need_double || is_time)) {
1026 if (!is_time) {
1027 obj->type = UCL_FLOAT;
1028 }
1029 else {
1030 obj->type = UCL_TIME;
1031 }
1032 obj->value.dv = dv;
1033 }
1034 else {
1035 obj->type = UCL_INT;
1036 obj->value.iv = lv;
1037 }
1038 }
1039 *pos = p;
1040 return 0;
1041 }
1042
1043 /**
1044 * Parse possible number
1045 * @param parser
1046 * @param chunk
1047 * @param obj
1048 * @return true if a number has been parsed
1049 */
1050 static bool
ucl_lex_number(struct ucl_parser * parser,struct ucl_chunk * chunk,ucl_object_t * obj)1051 ucl_lex_number (struct ucl_parser *parser,
1052 struct ucl_chunk *chunk, ucl_object_t *obj)
1053 {
1054 const unsigned char *pos;
1055 int ret;
1056
1057 ret = ucl_maybe_parse_number (obj, chunk->pos, chunk->end, (const char **)&pos,
1058 true, false, ((parser->flags & UCL_PARSER_NO_TIME) == 0));
1059
1060 if (ret == 0) {
1061 chunk->remain -= pos - chunk->pos;
1062 chunk->column += pos - chunk->pos;
1063 chunk->pos = pos;
1064 return true;
1065 }
1066 else if (ret == ERANGE) {
1067 ucl_set_err (parser, UCL_ESYNTAX, "numeric value out of range",
1068 &parser->err);
1069 }
1070
1071 return false;
1072 }
1073
1074 /**
1075 * Parse quoted string with possible escapes
1076 * @param parser
1077 * @param chunk
1078 * @param need_unescape
1079 * @param ucl_escape
1080 * @param var_expand
1081 * @return true if a string has been parsed
1082 */
1083 static bool
ucl_lex_json_string(struct ucl_parser * parser,struct ucl_chunk * chunk,bool * need_unescape,bool * ucl_escape,bool * var_expand)1084 ucl_lex_json_string (struct ucl_parser *parser,
1085 struct ucl_chunk *chunk,
1086 bool *need_unescape,
1087 bool *ucl_escape,
1088 bool *var_expand)
1089 {
1090 const unsigned char *p = chunk->pos;
1091 unsigned char c;
1092 int i;
1093
1094 while (p < chunk->end) {
1095 c = *p;
1096 if (c < 0x1F) {
1097 /* Unmasked control character */
1098 if (c == '\n') {
1099 ucl_set_err (parser, UCL_ESYNTAX, "unexpected newline",
1100 &parser->err);
1101 }
1102 else {
1103 ucl_set_err (parser, UCL_ESYNTAX, "unexpected control character",
1104 &parser->err);
1105 }
1106 return false;
1107 }
1108 else if (c == '\\') {
1109 ucl_chunk_skipc (chunk, p);
1110 if (p >= chunk->end) {
1111 ucl_set_err (parser, UCL_ESYNTAX, "unfinished escape character",
1112 &parser->err);
1113 return false;
1114 }
1115 c = *p;
1116 if (ucl_test_character (c, UCL_CHARACTER_ESCAPE)) {
1117 if (c == 'u') {
1118 ucl_chunk_skipc (chunk, p);
1119 for (i = 0; i < 4 && p < chunk->end; i ++) {
1120 if (!isxdigit (*p)) {
1121 ucl_set_err (parser, UCL_ESYNTAX, "invalid utf escape",
1122 &parser->err);
1123 return false;
1124 }
1125 ucl_chunk_skipc (chunk, p);
1126 }
1127 if (p >= chunk->end) {
1128 ucl_set_err (parser, UCL_ESYNTAX,
1129 "unfinished escape character",
1130 &parser->err);
1131 return false;
1132 }
1133 }
1134 else {
1135 ucl_chunk_skipc (chunk, p);
1136 }
1137 }
1138 *need_unescape = true;
1139 *ucl_escape = true;
1140 continue;
1141 }
1142 else if (c == '"') {
1143 ucl_chunk_skipc (chunk, p);
1144 return true;
1145 }
1146 else if (ucl_test_character (c, UCL_CHARACTER_UCL_UNSAFE)) {
1147 *ucl_escape = true;
1148 }
1149 else if (c == '$') {
1150 *var_expand = true;
1151 }
1152 ucl_chunk_skipc (chunk, p);
1153 }
1154
1155 ucl_set_err (parser, UCL_ESYNTAX,
1156 "no quote at the end of json string",
1157 &parser->err);
1158 return false;
1159 }
1160
1161 /**
1162 * Process single quoted string
1163 * @param parser
1164 * @param chunk
1165 * @param need_unescape
1166 * @return
1167 */
1168 static bool
ucl_lex_squoted_string(struct ucl_parser * parser,struct ucl_chunk * chunk,bool * need_unescape)1169 ucl_lex_squoted_string (struct ucl_parser *parser,
1170 struct ucl_chunk *chunk, bool *need_unescape)
1171 {
1172 const unsigned char *p = chunk->pos;
1173 unsigned char c;
1174
1175 while (p < chunk->end) {
1176 c = *p;
1177 if (c == '\\') {
1178 ucl_chunk_skipc (chunk, p);
1179
1180 if (p >= chunk->end) {
1181 ucl_set_err (parser, UCL_ESYNTAX,
1182 "unfinished escape character",
1183 &parser->err);
1184 return false;
1185 }
1186 else {
1187 ucl_chunk_skipc (chunk, p);
1188 }
1189
1190 *need_unescape = true;
1191 continue;
1192 }
1193 else if (c == '\'') {
1194 ucl_chunk_skipc (chunk, p);
1195 return true;
1196 }
1197
1198 ucl_chunk_skipc (chunk, p);
1199 }
1200
1201 ucl_set_err (parser, UCL_ESYNTAX,
1202 "no quote at the end of single quoted string",
1203 &parser->err);
1204 return false;
1205 }
1206
1207 static void
ucl_parser_append_elt(struct ucl_parser * parser,ucl_hash_t * cont,ucl_object_t * top,ucl_object_t * elt)1208 ucl_parser_append_elt (struct ucl_parser *parser, ucl_hash_t *cont,
1209 ucl_object_t *top,
1210 ucl_object_t *elt)
1211 {
1212 ucl_object_t *nobj;
1213
1214 if ((parser->flags & UCL_PARSER_NO_IMPLICIT_ARRAYS) == 0) {
1215 /* Implicit array */
1216 top->flags |= UCL_OBJECT_MULTIVALUE;
1217 DL_APPEND (top, elt);
1218 parser->stack->obj->len ++;
1219 }
1220 else {
1221 if ((top->flags & UCL_OBJECT_MULTIVALUE) != 0) {
1222 /* Just add to the explicit array */
1223 ucl_array_append (top, elt);
1224 }
1225 else {
1226 /* Convert to an array */
1227 nobj = ucl_object_typed_new (UCL_ARRAY);
1228 nobj->key = top->key;
1229 nobj->keylen = top->keylen;
1230 nobj->flags |= UCL_OBJECT_MULTIVALUE;
1231 ucl_array_append (nobj, top);
1232 ucl_array_append (nobj, elt);
1233 ucl_hash_replace (cont, top, nobj);
1234 }
1235 }
1236 }
1237
1238 bool
ucl_parser_process_object_element(struct ucl_parser * parser,ucl_object_t * nobj)1239 ucl_parser_process_object_element (struct ucl_parser *parser, ucl_object_t *nobj)
1240 {
1241 ucl_hash_t *container;
1242 ucl_object_t *tobj = NULL, *cur;
1243 char errmsg[256];
1244
1245 container = parser->stack->obj->value.ov;
1246
1247 DL_FOREACH (parser->stack->obj, cur) {
1248 tobj = __DECONST (ucl_object_t *, ucl_hash_search_obj (cur->value.ov, nobj));
1249
1250 if (tobj != NULL) {
1251 break;
1252 }
1253 }
1254
1255
1256 if (tobj == NULL) {
1257 container = ucl_hash_insert_object (container, nobj,
1258 parser->flags & UCL_PARSER_KEY_LOWERCASE);
1259 if (container == NULL) {
1260 return false;
1261 }
1262 nobj->prev = nobj;
1263 nobj->next = NULL;
1264 parser->stack->obj->len ++;
1265 }
1266 else {
1267 unsigned priold = ucl_object_get_priority (tobj),
1268 prinew = ucl_object_get_priority (nobj);
1269 switch (parser->chunks->strategy) {
1270
1271 case UCL_DUPLICATE_APPEND:
1272 /*
1273 * The logic here is the following:
1274 *
1275 * - if we have two objects with the same priority, then we form an
1276 * implicit or explicit array
1277 * - if a new object has bigger priority, then we overwrite an old one
1278 * - if a new object has lower priority, then we ignore it
1279 */
1280 /* Special case for inherited objects */
1281 if (tobj->flags & UCL_OBJECT_INHERITED) {
1282 prinew = priold + 1;
1283 }
1284
1285 if (priold == prinew) {
1286 ucl_parser_append_elt (parser, container, tobj, nobj);
1287 }
1288 else if (priold > prinew) {
1289 /*
1290 * We add this new object to a list of trash objects just to ensure
1291 * that it won't come to any real object
1292 * XXX: rather inefficient approach
1293 */
1294 DL_APPEND (parser->trash_objs, nobj);
1295 }
1296 else {
1297 ucl_hash_replace (container, tobj, nobj);
1298 ucl_object_unref (tobj);
1299 }
1300
1301 break;
1302
1303 case UCL_DUPLICATE_REWRITE:
1304 /* We just rewrite old values regardless of priority */
1305 ucl_hash_replace (container, tobj, nobj);
1306 ucl_object_unref (tobj);
1307
1308 break;
1309
1310 case UCL_DUPLICATE_ERROR:
1311 snprintf(errmsg, sizeof(errmsg),
1312 "duplicate element for key '%s' found",
1313 nobj->key);
1314 ucl_set_err (parser, UCL_EMERGE, errmsg, &parser->err);
1315 return false;
1316
1317 case UCL_DUPLICATE_MERGE:
1318 /*
1319 * Here we do have some old object so we just push it on top of objects stack
1320 * Check priority and then perform the merge on the remaining objects
1321 */
1322 if (tobj->type == UCL_OBJECT || tobj->type == UCL_ARRAY) {
1323 ucl_object_unref (nobj);
1324 nobj = tobj;
1325 }
1326 else if (priold == prinew) {
1327 ucl_parser_append_elt (parser, container, tobj, nobj);
1328 }
1329 else if (priold > prinew) {
1330 /*
1331 * We add this new object to a list of trash objects just to ensure
1332 * that it won't come to any real object
1333 * XXX: rather inefficient approach
1334 */
1335 DL_APPEND (parser->trash_objs, nobj);
1336 }
1337 else {
1338 ucl_hash_replace (container, tobj, nobj);
1339 ucl_object_unref (tobj);
1340 }
1341 break;
1342 }
1343 }
1344
1345 parser->stack->obj->value.ov = container;
1346 parser->cur_obj = nobj;
1347 ucl_attach_comment (parser, nobj, false);
1348
1349 return true;
1350 }
1351
1352 /**
1353 * Parse a key in an object
1354 * @param parser
1355 * @param chunk
1356 * @param next_key
1357 * @param end_of_object
1358 * @return true if a key has been parsed
1359 */
1360 static bool
ucl_parse_key(struct ucl_parser * parser,struct ucl_chunk * chunk,bool * next_key,bool * end_of_object,bool * got_content)1361 ucl_parse_key (struct ucl_parser *parser, struct ucl_chunk *chunk,
1362 bool *next_key, bool *end_of_object, bool *got_content)
1363 {
1364 const unsigned char *p, *c = NULL, *end, *t;
1365 const char *key = NULL;
1366 bool got_quote = false, got_eq = false, got_semicolon = false,
1367 need_unescape = false, ucl_escape = false, var_expand = false,
1368 got_sep = false;
1369 ucl_object_t *nobj;
1370 ssize_t keylen;
1371
1372 p = chunk->pos;
1373
1374 if (*p == '.' && !(parser->flags & UCL_PARSER_DISABLE_MACRO)) {
1375 ucl_chunk_skipc (chunk, p);
1376 parser->prev_state = parser->state;
1377 parser->state = UCL_STATE_MACRO_NAME;
1378 *end_of_object = false;
1379 return true;
1380 }
1381 while (p < chunk->end) {
1382 /*
1383 * A key must start with alpha, number, '/' or '_' and end with space character
1384 */
1385 if (c == NULL) {
1386 if (chunk->remain >= 2 && ucl_lex_is_comment (p[0], p[1])) {
1387 if (!ucl_skip_comments (parser)) {
1388 return false;
1389 }
1390 p = chunk->pos;
1391 }
1392 else if (ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE)) {
1393 ucl_chunk_skipc (chunk, p);
1394 }
1395 else if (ucl_test_character (*p, UCL_CHARACTER_KEY_START)) {
1396 /* The first symbol */
1397 c = p;
1398 ucl_chunk_skipc (chunk, p);
1399 *got_content = true;
1400 }
1401 else if (*p == '"') {
1402 /* JSON style key */
1403 c = p + 1;
1404 got_quote = true;
1405 *got_content = true;
1406 ucl_chunk_skipc (chunk, p);
1407 }
1408 else if (*p == '}') {
1409 /* We have actually end of an object */
1410 *end_of_object = true;
1411 return true;
1412 }
1413 else if (*p == '.' && !(parser->flags & UCL_PARSER_DISABLE_MACRO)) {
1414 ucl_chunk_skipc (chunk, p);
1415 parser->prev_state = parser->state;
1416 parser->state = UCL_STATE_MACRO_NAME;
1417 return true;
1418 }
1419 else {
1420 /* Invalid identifier */
1421 ucl_set_err (parser, UCL_ESYNTAX, "key must begin with a letter",
1422 &parser->err);
1423 return false;
1424 }
1425 }
1426 else {
1427 /* Parse the body of a key */
1428 if (!got_quote) {
1429 if (ucl_test_character (*p, UCL_CHARACTER_KEY)) {
1430 *got_content = true;
1431 ucl_chunk_skipc (chunk, p);
1432 }
1433 else if (ucl_test_character (*p, UCL_CHARACTER_KEY_SEP)) {
1434 end = p;
1435 break;
1436 }
1437 else {
1438 ucl_set_err (parser, UCL_ESYNTAX, "invalid character in a key",
1439 &parser->err);
1440 return false;
1441 }
1442 }
1443 else {
1444 /* We need to parse json like quoted string */
1445 if (!ucl_lex_json_string (parser, chunk, &need_unescape, &ucl_escape, &var_expand)) {
1446 return false;
1447 }
1448 /* Always escape keys obtained via json */
1449 end = chunk->pos - 1;
1450 p = chunk->pos;
1451 break;
1452 }
1453 }
1454 }
1455
1456 if (p >= chunk->end && *got_content) {
1457 ucl_set_err (parser, UCL_ESYNTAX, "unfinished key", &parser->err);
1458 return false;
1459 }
1460 else if (!*got_content) {
1461 return true;
1462 }
1463 *end_of_object = false;
1464 /* We are now at the end of the key, need to parse the rest */
1465 while (p < chunk->end) {
1466 if (ucl_test_character (*p, UCL_CHARACTER_WHITESPACE)) {
1467 ucl_chunk_skipc (chunk, p);
1468 }
1469 else if (*p == '=') {
1470 if (!got_eq && !got_semicolon) {
1471 ucl_chunk_skipc (chunk, p);
1472 got_eq = true;
1473 }
1474 else {
1475 ucl_set_err (parser, UCL_ESYNTAX, "unexpected '=' character",
1476 &parser->err);
1477 return false;
1478 }
1479 }
1480 else if (*p == ':') {
1481 if (!got_eq && !got_semicolon) {
1482 ucl_chunk_skipc (chunk, p);
1483 got_semicolon = true;
1484 }
1485 else {
1486 ucl_set_err (parser, UCL_ESYNTAX, "unexpected ':' character",
1487 &parser->err);
1488 return false;
1489 }
1490 }
1491 else if (chunk->remain >= 2 && ucl_lex_is_comment (p[0], p[1])) {
1492 /* Check for comment */
1493 if (!ucl_skip_comments (parser)) {
1494 return false;
1495 }
1496 p = chunk->pos;
1497 }
1498 else {
1499 /* Start value */
1500 break;
1501 }
1502 }
1503
1504 if (p >= chunk->end && got_content) {
1505 ucl_set_err (parser, UCL_ESYNTAX, "unfinished key", &parser->err);
1506 return false;
1507 }
1508
1509 got_sep = got_semicolon || got_eq;
1510
1511 if (!got_sep) {
1512 /*
1513 * Maybe we have more keys nested, so search for termination character.
1514 * Possible choices:
1515 * 1) key1 key2 ... keyN [:=] value <- we treat that as error
1516 * 2) key1 ... keyN {} or [] <- we treat that as nested objects
1517 * 3) key1 value[;,\n] <- we treat that as linear object
1518 */
1519 t = p;
1520 *next_key = false;
1521 while (ucl_test_character (*t, UCL_CHARACTER_WHITESPACE)) {
1522 t ++;
1523 }
1524 /* Check first non-space character after a key */
1525 if (*t != '{' && *t != '[') {
1526 while (t < chunk->end) {
1527 if (*t == ',' || *t == ';' || *t == '\n' || *t == '\r') {
1528 break;
1529 }
1530 else if (*t == '{' || *t == '[') {
1531 *next_key = true;
1532 break;
1533 }
1534 t ++;
1535 }
1536 }
1537 }
1538
1539 /* Create a new object */
1540 nobj = ucl_object_new_full (UCL_NULL, parser->chunks->priority);
1541 if (nobj == NULL) {
1542 return false;
1543 }
1544 keylen = ucl_copy_or_store_ptr (parser, c, &nobj->trash_stack[UCL_TRASH_KEY],
1545 &key, end - c, need_unescape, parser->flags & UCL_PARSER_KEY_LOWERCASE,
1546 false, false);
1547 if (keylen == -1) {
1548 ucl_object_unref (nobj);
1549 return false;
1550 }
1551 else if (keylen == 0) {
1552 ucl_set_err (parser, UCL_ESYNTAX, "empty keys are not allowed", &parser->err);
1553 ucl_object_unref (nobj);
1554 return false;
1555 }
1556
1557 nobj->key = key;
1558 nobj->keylen = keylen;
1559
1560 if (!ucl_parser_process_object_element (parser, nobj)) {
1561 return false;
1562 }
1563
1564 if (ucl_escape) {
1565 nobj->flags |= UCL_OBJECT_NEED_KEY_ESCAPE;
1566 }
1567
1568
1569 return true;
1570 }
1571
1572 /**
1573 * Parse a cl string
1574 * @param parser
1575 * @param chunk
1576 * @param var_expand
1577 * @param need_unescape
1578 * @return true if a key has been parsed
1579 */
1580 static bool
ucl_parse_string_value(struct ucl_parser * parser,struct ucl_chunk * chunk,bool * var_expand,bool * need_unescape)1581 ucl_parse_string_value (struct ucl_parser *parser,
1582 struct ucl_chunk *chunk, bool *var_expand, bool *need_unescape)
1583 {
1584 const unsigned char *p;
1585 enum {
1586 UCL_BRACE_ROUND = 0,
1587 UCL_BRACE_SQUARE,
1588 UCL_BRACE_FIGURE
1589 };
1590 int braces[3][2] = {{0, 0}, {0, 0}, {0, 0}};
1591
1592 p = chunk->pos;
1593
1594 while (p < chunk->end) {
1595
1596 /* Skip pairs of figure braces */
1597 if (*p == '{') {
1598 braces[UCL_BRACE_FIGURE][0] ++;
1599 }
1600 else if (*p == '}') {
1601 braces[UCL_BRACE_FIGURE][1] ++;
1602 if (braces[UCL_BRACE_FIGURE][1] <= braces[UCL_BRACE_FIGURE][0]) {
1603 /* This is not a termination symbol, continue */
1604 ucl_chunk_skipc (chunk, p);
1605 continue;
1606 }
1607 }
1608 /* Skip pairs of square braces */
1609 else if (*p == '[') {
1610 braces[UCL_BRACE_SQUARE][0] ++;
1611 }
1612 else if (*p == ']') {
1613 braces[UCL_BRACE_SQUARE][1] ++;
1614 if (braces[UCL_BRACE_SQUARE][1] <= braces[UCL_BRACE_SQUARE][0]) {
1615 /* This is not a termination symbol, continue */
1616 ucl_chunk_skipc (chunk, p);
1617 continue;
1618 }
1619 }
1620 else if (*p == '$') {
1621 *var_expand = true;
1622 }
1623 else if (*p == '\\') {
1624 *need_unescape = true;
1625 ucl_chunk_skipc (chunk, p);
1626 if (p < chunk->end) {
1627 ucl_chunk_skipc (chunk, p);
1628 }
1629 continue;
1630 }
1631
1632 if (ucl_lex_is_atom_end (*p) || (chunk->remain >= 2 && ucl_lex_is_comment (p[0], p[1]))) {
1633 break;
1634 }
1635 ucl_chunk_skipc (chunk, p);
1636 }
1637
1638 return true;
1639 }
1640
1641 /**
1642 * Parse multiline string ending with \n{term}\n
1643 * @param parser
1644 * @param chunk
1645 * @param term
1646 * @param term_len
1647 * @param beg
1648 * @param var_expand
1649 * @return size of multiline string or 0 in case of error
1650 */
1651 static int
ucl_parse_multiline_string(struct ucl_parser * parser,struct ucl_chunk * chunk,const unsigned char * term,int term_len,unsigned char const ** beg,bool * var_expand)1652 ucl_parse_multiline_string (struct ucl_parser *parser,
1653 struct ucl_chunk *chunk, const unsigned char *term,
1654 int term_len, unsigned char const **beg,
1655 bool *var_expand)
1656 {
1657 const unsigned char *p, *c, *tend;
1658 bool newline = false;
1659 int len = 0;
1660
1661 p = chunk->pos;
1662
1663 c = p;
1664
1665 while (p < chunk->end) {
1666 if (newline) {
1667 if (chunk->end - p < term_len) {
1668 return 0;
1669 }
1670 else if (memcmp (p, term, term_len) == 0) {
1671 tend = p + term_len;
1672 if (*tend != '\n' && *tend != ';' && *tend != ',') {
1673 /* Incomplete terminator */
1674 ucl_chunk_skipc (chunk, p);
1675 continue;
1676 }
1677 len = p - c;
1678 chunk->remain -= term_len;
1679 chunk->pos = p + term_len;
1680 chunk->column = term_len;
1681 *beg = c;
1682 break;
1683 }
1684 }
1685 if (*p == '\n') {
1686 newline = true;
1687 }
1688 else {
1689 if (*p == '$') {
1690 *var_expand = true;
1691 }
1692 newline = false;
1693 }
1694 ucl_chunk_skipc (chunk, p);
1695 }
1696
1697 return len;
1698 }
1699
1700 static inline ucl_object_t*
ucl_parser_get_container(struct ucl_parser * parser)1701 ucl_parser_get_container (struct ucl_parser *parser)
1702 {
1703 ucl_object_t *t, *obj = NULL;
1704
1705 if (parser == NULL || parser->stack == NULL || parser->stack->obj == NULL) {
1706 return NULL;
1707 }
1708
1709 if (parser->stack->obj->type == UCL_ARRAY) {
1710 /* Object must be allocated */
1711 obj = ucl_object_new_full (UCL_NULL, parser->chunks->priority);
1712 t = parser->stack->obj;
1713
1714 if (!ucl_array_append (t, obj)) {
1715 ucl_object_unref (obj);
1716 return NULL;
1717 }
1718
1719 parser->cur_obj = obj;
1720 ucl_attach_comment (parser, obj, false);
1721 }
1722 else {
1723 /* Object has been already allocated */
1724 obj = parser->cur_obj;
1725 }
1726
1727 return obj;
1728 }
1729
1730 /**
1731 * Handle value data
1732 * @param parser
1733 * @param chunk
1734 * @return
1735 */
1736 static bool
ucl_parse_value(struct ucl_parser * parser,struct ucl_chunk * chunk)1737 ucl_parse_value (struct ucl_parser *parser, struct ucl_chunk *chunk)
1738 {
1739 const unsigned char *p, *c;
1740 ucl_object_t *obj = NULL;
1741 unsigned int stripped_spaces;
1742 ssize_t str_len;
1743 bool need_unescape = false, ucl_escape = false, var_expand = false;
1744
1745 p = chunk->pos;
1746
1747 /* Skip any spaces and comments */
1748 if (ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE) ||
1749 (chunk->remain >= 2 && ucl_lex_is_comment (p[0], p[1]))) {
1750 while (p < chunk->end && ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE)) {
1751 ucl_chunk_skipc (chunk, p);
1752 }
1753 if (!ucl_skip_comments (parser)) {
1754 return false;
1755 }
1756 p = chunk->pos;
1757 }
1758
1759 while (p < chunk->end) {
1760 c = p;
1761 switch (*p) {
1762 case '"':
1763 ucl_chunk_skipc (chunk, p);
1764
1765 if (!ucl_lex_json_string (parser, chunk, &need_unescape, &ucl_escape,
1766 &var_expand)) {
1767 return false;
1768 }
1769
1770 obj = ucl_parser_get_container (parser);
1771 if (!obj) {
1772 return false;
1773 }
1774
1775 str_len = chunk->pos - c - 2;
1776 obj->type = UCL_STRING;
1777 if ((str_len = ucl_copy_or_store_ptr (parser, c + 1,
1778 &obj->trash_stack[UCL_TRASH_VALUE],
1779 &obj->value.sv, str_len, need_unescape, false,
1780 var_expand, false)) == -1) {
1781 return false;
1782 }
1783
1784 obj->len = str_len;
1785 parser->state = UCL_STATE_AFTER_VALUE;
1786
1787 return true;
1788 break;
1789 case '\'':
1790 ucl_chunk_skipc (chunk, p);
1791
1792 if (!ucl_lex_squoted_string (parser, chunk, &need_unescape)) {
1793 return false;
1794 }
1795
1796 obj = ucl_parser_get_container (parser);
1797 if (!obj) {
1798 return false;
1799 }
1800
1801 str_len = chunk->pos - c - 2;
1802 obj->type = UCL_STRING;
1803 obj->flags |= UCL_OBJECT_SQUOTED;
1804
1805 if ((str_len = ucl_copy_or_store_ptr (parser, c + 1,
1806 &obj->trash_stack[UCL_TRASH_VALUE],
1807 &obj->value.sv, str_len, need_unescape, false,
1808 var_expand, true)) == -1) {
1809 return false;
1810 }
1811
1812 obj->len = str_len;
1813
1814 parser->state = UCL_STATE_AFTER_VALUE;
1815
1816 return true;
1817 break;
1818 case '{':
1819 obj = ucl_parser_get_container (parser);
1820 if (obj == NULL) {
1821 parser->state = UCL_STATE_ERROR;
1822 ucl_set_err(parser, UCL_ESYNTAX, "object value must be a part of an object",
1823 &parser->err);
1824 return false;
1825 }
1826 /* We have a new object */
1827 if (parser->stack) {
1828 obj = ucl_parser_add_container (obj, parser, false,
1829 parser->stack->e.params.level, true);
1830 }
1831 else {
1832 return false;
1833 }
1834 if (obj == NULL) {
1835 return false;
1836 }
1837
1838 ucl_chunk_skipc (chunk, p);
1839
1840 return true;
1841 break;
1842 case '[':
1843 obj = ucl_parser_get_container (parser);
1844 if (obj == NULL) {
1845 parser->state = UCL_STATE_ERROR;
1846 ucl_set_err(parser, UCL_ESYNTAX, "array value must be a part of an object",
1847 &parser->err);
1848 return false;
1849 }
1850 /* We have a new array */
1851 if (parser->stack) {
1852 obj = ucl_parser_add_container (obj, parser, true,
1853 parser->stack->e.params.level, true);
1854 }
1855 else {
1856 return false;
1857 }
1858
1859 if (obj == NULL) {
1860 return false;
1861 }
1862
1863 ucl_chunk_skipc (chunk, p);
1864
1865 return true;
1866 break;
1867 case ']':
1868 /* We have the array ending */
1869 if (parser->stack && parser->stack->obj->type == UCL_ARRAY) {
1870 parser->state = UCL_STATE_AFTER_VALUE;
1871 return true;
1872 }
1873 else {
1874 goto parse_string;
1875 }
1876 break;
1877 case '<':
1878 obj = ucl_parser_get_container (parser);
1879 if (obj == NULL) {
1880 parser->state = UCL_STATE_ERROR;
1881 ucl_set_err(parser, UCL_ESYNTAX, "multiline value must be a part of an object",
1882 &parser->err);
1883 return false;
1884 }
1885 /* We have something like multiline value, which must be <<[A-Z]+\n */
1886 if (chunk->end - p > 3) {
1887 if (memcmp (p, "<<", 2) == 0) {
1888 p += 2;
1889 /* We allow only uppercase characters in multiline definitions */
1890 while (p < chunk->end && *p >= 'A' && *p <= 'Z') {
1891 p ++;
1892 }
1893 if(p == chunk->end) {
1894 ucl_set_err (parser, UCL_ESYNTAX,
1895 "unterminated multiline value", &parser->err);
1896 return false;
1897 }
1898 if (*p =='\n') {
1899 /* Set chunk positions and start multiline parsing */
1900 chunk->remain -= p - c + 1;
1901 c += 2;
1902 chunk->pos = p + 1;
1903 chunk->column = 0;
1904 chunk->line ++;
1905 if ((str_len = ucl_parse_multiline_string (parser, chunk, c,
1906 p - c, &c, &var_expand)) == 0) {
1907 ucl_set_err (parser, UCL_ESYNTAX,
1908 "unterminated multiline value", &parser->err);
1909 return false;
1910 }
1911
1912 obj->type = UCL_STRING;
1913 obj->flags |= UCL_OBJECT_MULTILINE;
1914 if ((str_len = ucl_copy_or_store_ptr (parser, c,
1915 &obj->trash_stack[UCL_TRASH_VALUE],
1916 &obj->value.sv, str_len - 1, false,
1917 false, var_expand, false)) == -1) {
1918 return false;
1919 }
1920 obj->len = str_len;
1921
1922 parser->state = UCL_STATE_AFTER_VALUE;
1923
1924 return true;
1925 }
1926 }
1927 }
1928 /* Fallback to ordinary strings */
1929 /* FALLTHRU */
1930 default:
1931 parse_string:
1932 if (obj == NULL) {
1933 obj = ucl_parser_get_container (parser);
1934 }
1935
1936 if (obj == NULL) {
1937 parser->state = UCL_STATE_ERROR;
1938 ucl_set_err(parser, UCL_ESYNTAX, "value must be a part of an object",
1939 &parser->err);
1940 return false;
1941 }
1942
1943 /* Parse atom */
1944 if (ucl_test_character (*p, UCL_CHARACTER_VALUE_DIGIT_START)) {
1945 if (!ucl_lex_number (parser, chunk, obj)) {
1946 if (parser->state == UCL_STATE_ERROR) {
1947 return false;
1948 }
1949 }
1950 else {
1951 parser->state = UCL_STATE_AFTER_VALUE;
1952 return true;
1953 }
1954 /* Fallback to normal string */
1955 }
1956
1957 if (!ucl_parse_string_value (parser, chunk, &var_expand,
1958 &need_unescape)) {
1959 return false;
1960 }
1961 /* Cut trailing spaces */
1962 stripped_spaces = 0;
1963 while (ucl_test_character (*(chunk->pos - 1 - stripped_spaces),
1964 UCL_CHARACTER_WHITESPACE)) {
1965 stripped_spaces ++;
1966 }
1967 str_len = chunk->pos - c - stripped_spaces;
1968 if (str_len <= 0) {
1969 ucl_set_err (parser, UCL_ESYNTAX, "string value must not be empty",
1970 &parser->err);
1971 return false;
1972 }
1973 else if (str_len == 4 && memcmp (c, "null", 4) == 0) {
1974 obj->len = 0;
1975 obj->type = UCL_NULL;
1976 }
1977 else if (str_len == 3 && memcmp (c, "nan", 3) == 0) {
1978 obj->len = 0;
1979 obj->type = UCL_FLOAT;
1980 obj->value.dv = NAN;
1981 }
1982 else if (str_len == 3 && memcmp (c, "inf", 3) == 0) {
1983 obj->len = 0;
1984 obj->type = UCL_FLOAT;
1985 obj->value.dv = INFINITY;
1986 }
1987 else if (!ucl_maybe_parse_boolean (obj, c, str_len)) {
1988 obj->type = UCL_STRING;
1989 if ((str_len = ucl_copy_or_store_ptr (parser, c,
1990 &obj->trash_stack[UCL_TRASH_VALUE],
1991 &obj->value.sv, str_len, need_unescape,
1992 false, var_expand, false)) == -1) {
1993 return false;
1994 }
1995 obj->len = str_len;
1996 }
1997
1998 parser->state = UCL_STATE_AFTER_VALUE;
1999
2000 return true;
2001 break;
2002 }
2003 }
2004
2005 return true;
2006 }
2007
2008 /**
2009 * Handle after value data
2010 * @param parser
2011 * @param chunk
2012 * @return
2013 */
2014 static bool
ucl_parse_after_value(struct ucl_parser * parser,struct ucl_chunk * chunk)2015 ucl_parse_after_value (struct ucl_parser *parser, struct ucl_chunk *chunk)
2016 {
2017 const unsigned char *p;
2018 bool got_sep = false;
2019 struct ucl_stack *st;
2020
2021 p = chunk->pos;
2022
2023 while (p < chunk->end) {
2024 if (ucl_test_character (*p, UCL_CHARACTER_WHITESPACE)) {
2025 /* Skip whitespaces */
2026 ucl_chunk_skipc (chunk, p);
2027 }
2028 else if (chunk->remain >= 2 && ucl_lex_is_comment (p[0], p[1])) {
2029 /* Skip comment */
2030 if (!ucl_skip_comments (parser)) {
2031 return false;
2032 }
2033 /* Treat comment as a separator */
2034 got_sep = true;
2035 p = chunk->pos;
2036 }
2037 else if (ucl_test_character (*p, UCL_CHARACTER_VALUE_END)) {
2038 if (*p == '}' || *p == ']') {
2039 if (parser->stack == NULL) {
2040 ucl_set_err (parser, UCL_ESYNTAX,
2041 "end of array or object detected without corresponding start",
2042 &parser->err);
2043 return false;
2044 }
2045 if ((*p == '}' && parser->stack->obj->type == UCL_OBJECT) ||
2046 (*p == ']' && parser->stack->obj->type == UCL_ARRAY)) {
2047
2048 /* Pop all nested objects from a stack */
2049 st = parser->stack;
2050
2051 if (!(st->e.params.flags & UCL_STACK_HAS_OBRACE)) {
2052 parser->err_code = UCL_EUNPAIRED;
2053 ucl_create_err (&parser->err,
2054 "%s:%d object closed with } is not opened with { at line %d",
2055 chunk->fname ? chunk->fname : "memory",
2056 parser->chunks->line, st->e.params.line);
2057
2058 return false;
2059 }
2060
2061 parser->stack = st->next;
2062 UCL_FREE (sizeof (struct ucl_stack), st);
2063
2064 if (parser->cur_obj) {
2065 ucl_attach_comment (parser, parser->cur_obj, true);
2066 }
2067
2068 while (parser->stack != NULL) {
2069 st = parser->stack;
2070
2071 if (st->next == NULL) {
2072 break;
2073 }
2074 else if (st->next->e.params.level == st->e.params.level) {
2075 break;
2076 }
2077
2078
2079 parser->stack = st->next;
2080 parser->cur_obj = st->obj;
2081 UCL_FREE (sizeof (struct ucl_stack), st);
2082 }
2083 }
2084 else {
2085 ucl_set_err (parser, UCL_ESYNTAX,
2086 "unexpected terminating symbol detected",
2087 &parser->err);
2088 return false;
2089 }
2090
2091 if (parser->stack == NULL) {
2092 /* Ignore everything after a top object */
2093 return true;
2094 }
2095 else {
2096 ucl_chunk_skipc (chunk, p);
2097 }
2098 got_sep = true;
2099 }
2100 else {
2101 /* Got a separator */
2102 got_sep = true;
2103 ucl_chunk_skipc (chunk, p);
2104 }
2105 }
2106 else {
2107 /* Anything else */
2108 if (!got_sep) {
2109 ucl_set_err (parser, UCL_ESYNTAX, "delimiter is missing",
2110 &parser->err);
2111 return false;
2112 }
2113 return true;
2114 }
2115 }
2116
2117 return true;
2118 }
2119
2120 static bool
ucl_skip_macro_as_comment(struct ucl_parser * parser,struct ucl_chunk * chunk)2121 ucl_skip_macro_as_comment (struct ucl_parser *parser,
2122 struct ucl_chunk *chunk)
2123 {
2124 const unsigned char *p, *c;
2125 enum {
2126 macro_skip_start = 0,
2127 macro_has_symbols,
2128 macro_has_obrace,
2129 macro_has_quote,
2130 macro_has_backslash,
2131 macro_has_sqbrace,
2132 macro_save
2133 } state = macro_skip_start, prev_state = macro_skip_start;
2134
2135 p = chunk->pos;
2136 c = chunk->pos;
2137
2138 while (p < chunk->end) {
2139 switch (state) {
2140 case macro_skip_start:
2141 if (!ucl_test_character (*p, UCL_CHARACTER_WHITESPACE)) {
2142 state = macro_has_symbols;
2143 }
2144 else if (ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE)) {
2145 state = macro_save;
2146 continue;
2147 }
2148
2149 ucl_chunk_skipc (chunk, p);
2150 break;
2151
2152 case macro_has_symbols:
2153 if (*p == '{') {
2154 state = macro_has_sqbrace;
2155 }
2156 else if (*p == '(') {
2157 state = macro_has_obrace;
2158 }
2159 else if (*p == '"') {
2160 state = macro_has_quote;
2161 }
2162 else if (*p == '\n') {
2163 state = macro_save;
2164 continue;
2165 }
2166
2167 ucl_chunk_skipc (chunk, p);
2168 break;
2169
2170 case macro_has_obrace:
2171 if (*p == '\\') {
2172 prev_state = state;
2173 state = macro_has_backslash;
2174 }
2175 else if (*p == ')') {
2176 state = macro_has_symbols;
2177 }
2178
2179 ucl_chunk_skipc (chunk, p);
2180 break;
2181
2182 case macro_has_sqbrace:
2183 if (*p == '\\') {
2184 prev_state = state;
2185 state = macro_has_backslash;
2186 }
2187 else if (*p == '}') {
2188 state = macro_save;
2189 }
2190
2191 ucl_chunk_skipc (chunk, p);
2192 break;
2193
2194 case macro_has_quote:
2195 if (*p == '\\') {
2196 prev_state = state;
2197 state = macro_has_backslash;
2198 }
2199 else if (*p == '"') {
2200 state = macro_save;
2201 }
2202
2203 ucl_chunk_skipc (chunk, p);
2204 break;
2205
2206 case macro_has_backslash:
2207 state = prev_state;
2208 ucl_chunk_skipc (chunk, p);
2209 break;
2210
2211 case macro_save:
2212 if (parser->flags & UCL_PARSER_SAVE_COMMENTS) {
2213 ucl_save_comment (parser, c, p - c);
2214 }
2215
2216 return true;
2217 }
2218 }
2219
2220 return false;
2221 }
2222
2223 /**
2224 * Handle macro data
2225 * @param parser
2226 * @param chunk
2227 * @param marco
2228 * @param macro_start
2229 * @param macro_len
2230 * @return
2231 */
2232 static bool
ucl_parse_macro_value(struct ucl_parser * parser,struct ucl_chunk * chunk,struct ucl_macro * macro,unsigned char const ** macro_start,size_t * macro_len)2233 ucl_parse_macro_value (struct ucl_parser *parser,
2234 struct ucl_chunk *chunk, struct ucl_macro *macro,
2235 unsigned char const **macro_start, size_t *macro_len)
2236 {
2237 const unsigned char *p, *c;
2238 bool need_unescape = false, ucl_escape = false, var_expand = false;
2239
2240 p = chunk->pos;
2241
2242 switch (*p) {
2243 case '"':
2244 /* We have macro value encoded in quotes */
2245 c = p;
2246 ucl_chunk_skipc (chunk, p);
2247 if (!ucl_lex_json_string (parser, chunk, &need_unescape, &ucl_escape, &var_expand)) {
2248 return false;
2249 }
2250
2251 *macro_start = c + 1;
2252 *macro_len = chunk->pos - c - 2;
2253 p = chunk->pos;
2254 break;
2255 case '{':
2256 /* We got a multiline macro body */
2257 ucl_chunk_skipc (chunk, p);
2258 /* Skip spaces at the beginning */
2259 while (p < chunk->end) {
2260 if (ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE)) {
2261 ucl_chunk_skipc (chunk, p);
2262 }
2263 else {
2264 break;
2265 }
2266 }
2267 c = p;
2268 while (p < chunk->end) {
2269 if (*p == '}') {
2270 break;
2271 }
2272 ucl_chunk_skipc (chunk, p);
2273 }
2274 *macro_start = c;
2275 *macro_len = p - c;
2276 ucl_chunk_skipc (chunk, p);
2277 break;
2278 default:
2279 /* Macro is not enclosed in quotes or braces */
2280 c = p;
2281 while (p < chunk->end) {
2282 if (ucl_lex_is_atom_end (*p)) {
2283 break;
2284 }
2285 ucl_chunk_skipc (chunk, p);
2286 }
2287 *macro_start = c;
2288 *macro_len = p - c;
2289 break;
2290 }
2291
2292 /* We are at the end of a macro */
2293 /* Skip ';' and space characters and return to previous state */
2294 while (p < chunk->end) {
2295 if (!ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE) && *p != ';') {
2296 break;
2297 }
2298 ucl_chunk_skipc (chunk, p);
2299 }
2300 return true;
2301 }
2302
2303 /**
2304 * Parse macro arguments as UCL object
2305 * @param parser parser structure
2306 * @param chunk the current data chunk
2307 * @return
2308 */
2309 static ucl_object_t *
ucl_parse_macro_arguments(struct ucl_parser * parser,struct ucl_chunk * chunk)2310 ucl_parse_macro_arguments (struct ucl_parser *parser,
2311 struct ucl_chunk *chunk)
2312 {
2313 ucl_object_t *res = NULL;
2314 struct ucl_parser *params_parser;
2315 int obraces = 1, ebraces = 0, state = 0;
2316 const unsigned char *p, *c;
2317 size_t args_len = 0;
2318 struct ucl_parser_saved_state saved;
2319
2320 saved.column = chunk->column;
2321 saved.line = chunk->line;
2322 saved.pos = chunk->pos;
2323 saved.remain = chunk->remain;
2324 p = chunk->pos;
2325
2326 if (*p != '(' || chunk->remain < 2) {
2327 return NULL;
2328 }
2329
2330 /* Set begin and start */
2331 ucl_chunk_skipc (chunk, p);
2332 c = p;
2333
2334 while ((p) < (chunk)->end) {
2335 switch (state) {
2336 case 0:
2337 /* Parse symbols and check for '(', ')' and '"' */
2338 if (*p == '(') {
2339 obraces ++;
2340 }
2341 else if (*p == ')') {
2342 ebraces ++;
2343 }
2344 else if (*p == '"') {
2345 state = 1;
2346 }
2347 /* Check pairing */
2348 if (obraces == ebraces) {
2349 state = 99;
2350 }
2351 else {
2352 args_len ++;
2353 }
2354 /* Check overflow */
2355 if (chunk->remain == 0) {
2356 goto restore_chunk;
2357 }
2358 ucl_chunk_skipc (chunk, p);
2359 break;
2360 case 1:
2361 /* We have quote character, so skip all but quotes */
2362 if (*p == '"' && *(p - 1) != '\\') {
2363 state = 0;
2364 }
2365 if (chunk->remain == 0) {
2366 goto restore_chunk;
2367 }
2368 args_len ++;
2369 ucl_chunk_skipc (chunk, p);
2370 break;
2371 case 99:
2372 /*
2373 * We have read the full body of arguments, so we need to parse and set
2374 * object from that
2375 */
2376 params_parser = ucl_parser_new (parser->flags);
2377 if (!ucl_parser_add_chunk (params_parser, c, args_len)) {
2378 ucl_set_err (parser, UCL_ESYNTAX, "macro arguments parsing error",
2379 &parser->err);
2380 }
2381 else {
2382 res = ucl_parser_get_object (params_parser);
2383 }
2384 ucl_parser_free (params_parser);
2385
2386 return res;
2387
2388 break;
2389 }
2390 }
2391
2392 return res;
2393
2394 restore_chunk:
2395 chunk->column = saved.column;
2396 chunk->line = saved.line;
2397 chunk->pos = saved.pos;
2398 chunk->remain = saved.remain;
2399
2400 return NULL;
2401 }
2402
2403 #define SKIP_SPACES_COMMENTS(parser, chunk, p) do { \
2404 while ((p) < (chunk)->end) { \
2405 if (!ucl_test_character (*(p), UCL_CHARACTER_WHITESPACE_UNSAFE)) { \
2406 if ((chunk)->remain >= 2 && ucl_lex_is_comment ((p)[0], (p)[1])) { \
2407 if (!ucl_skip_comments (parser)) { \
2408 return false; \
2409 } \
2410 p = (chunk)->pos; \
2411 } \
2412 break; \
2413 } \
2414 ucl_chunk_skipc (chunk, p); \
2415 } \
2416 } while(0)
2417
2418 /**
2419 * Handle the main states of rcl parser
2420 * @param parser parser structure
2421 * @return true if chunk has been parsed and false in case of error
2422 */
2423 static bool
ucl_state_machine(struct ucl_parser * parser)2424 ucl_state_machine (struct ucl_parser *parser)
2425 {
2426 ucl_object_t *obj, *macro_args;
2427 struct ucl_chunk *chunk = parser->chunks;
2428 const unsigned char *p, *c = NULL, *macro_start = NULL;
2429 unsigned char *macro_escaped;
2430 size_t macro_len = 0;
2431 struct ucl_macro *macro = NULL;
2432 bool next_key = false, end_of_object = false, got_content = false, ret;
2433
2434 if (parser->top_obj == NULL) {
2435 parser->state = UCL_STATE_INIT;
2436 }
2437
2438 p = chunk->pos;
2439 while (chunk->pos < chunk->end) {
2440 switch (parser->state) {
2441 case UCL_STATE_INIT:
2442 /*
2443 * At the init state we can either go to the parse array or object
2444 * if we got [ or { correspondingly or can just treat new data as
2445 * a key of newly created object
2446 */
2447 if (!ucl_skip_comments (parser)) {
2448 parser->prev_state = parser->state;
2449 parser->state = UCL_STATE_ERROR;
2450 return false;
2451 }
2452 else {
2453 bool seen_obrace = false;
2454
2455 /* Skip any spaces */
2456 while (p < chunk->end && ucl_test_character (*p,
2457 UCL_CHARACTER_WHITESPACE_UNSAFE)) {
2458 ucl_chunk_skipc (chunk, p);
2459 }
2460
2461 p = chunk->pos;
2462
2463 if (p < chunk->end) {
2464 if (*p == '[') {
2465 parser->state = UCL_STATE_VALUE;
2466 ucl_chunk_skipc (chunk, p);
2467 seen_obrace = true;
2468 }
2469 else {
2470
2471 if (*p == '{') {
2472 ucl_chunk_skipc (chunk, p);
2473 parser->state = UCL_STATE_KEY_OBRACE;
2474 seen_obrace = true;
2475 }
2476 else {
2477 parser->state = UCL_STATE_KEY;
2478 }
2479 }
2480 }
2481
2482 if (parser->top_obj == NULL) {
2483 if (parser->state == UCL_STATE_VALUE) {
2484 obj = ucl_parser_add_container (NULL, parser, true, 0,
2485 seen_obrace);
2486 }
2487 else {
2488 obj = ucl_parser_add_container (NULL, parser, false, 0,
2489 seen_obrace);
2490 }
2491
2492 if (obj == NULL) {
2493 return false;
2494 }
2495
2496 parser->top_obj = obj;
2497 parser->cur_obj = obj;
2498 }
2499
2500 }
2501 break;
2502 case UCL_STATE_KEY:
2503 case UCL_STATE_KEY_OBRACE:
2504 /* Skip any spaces */
2505 while (p < chunk->end && ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE)) {
2506 ucl_chunk_skipc (chunk, p);
2507 }
2508 if (p == chunk->end || *p == '}') {
2509 /* We have the end of an object */
2510 parser->state = UCL_STATE_AFTER_VALUE;
2511 continue;
2512 }
2513 if (parser->stack == NULL) {
2514 /* No objects are on stack, but we want to parse a key */
2515 ucl_set_err (parser, UCL_ESYNTAX, "top object is finished but the parser "
2516 "expects a key", &parser->err);
2517 parser->prev_state = parser->state;
2518 parser->state = UCL_STATE_ERROR;
2519 return false;
2520 }
2521
2522 got_content = false;
2523
2524 if (!ucl_parse_key (parser, chunk, &next_key, &end_of_object, &got_content)) {
2525 parser->prev_state = parser->state;
2526 parser->state = UCL_STATE_ERROR;
2527 return false;
2528 }
2529
2530 if (end_of_object) {
2531 p = chunk->pos;
2532 parser->state = UCL_STATE_AFTER_VALUE;
2533 continue;
2534 }
2535 else if (parser->state != UCL_STATE_MACRO_NAME) {
2536 if (next_key && parser->stack->obj->type == UCL_OBJECT) {
2537 /* Parse more keys and nest objects accordingly */
2538 obj = ucl_parser_add_container (parser->cur_obj,
2539 parser,
2540 false,
2541 parser->stack->e.params.level + 1,
2542 parser->state == UCL_STATE_KEY_OBRACE);
2543 if (obj == NULL) {
2544 return false;
2545 }
2546 }
2547 else if (got_content) {
2548 /* Do not switch state if we have not read any content */
2549 parser->state = UCL_STATE_VALUE;
2550 }
2551 }
2552 else {
2553 c = chunk->pos;
2554 }
2555 p = chunk->pos;
2556 break;
2557 case UCL_STATE_VALUE:
2558 /* We need to check what we do have */
2559 if (!parser->cur_obj || !ucl_parse_value (parser, chunk)) {
2560 parser->prev_state = parser->state;
2561 parser->state = UCL_STATE_ERROR;
2562 return false;
2563 }
2564 /* State is set in ucl_parse_value call */
2565 p = chunk->pos;
2566 break;
2567 case UCL_STATE_AFTER_VALUE:
2568 if (!ucl_parse_after_value (parser, chunk)) {
2569 parser->prev_state = parser->state;
2570 parser->state = UCL_STATE_ERROR;
2571 return false;
2572 }
2573
2574 if (parser->stack != NULL) {
2575 if (parser->stack->obj->type == UCL_OBJECT) {
2576 parser->state = UCL_STATE_KEY;
2577 }
2578 else {
2579 /* Array */
2580 parser->state = UCL_STATE_VALUE;
2581 }
2582 }
2583 else {
2584 /* Skip everything at the end */
2585 return true;
2586 }
2587
2588 p = chunk->pos;
2589 break;
2590 case UCL_STATE_MACRO_NAME:
2591 if (parser->flags & UCL_PARSER_DISABLE_MACRO) {
2592 if (!ucl_skip_macro_as_comment (parser, chunk)) {
2593 /* We have invalid macro */
2594 ucl_create_err (&parser->err,
2595 "error at %s:%d at column %d: invalid macro",
2596 chunk->fname ? chunk->fname : "memory",
2597 chunk->line,
2598 chunk->column);
2599 parser->state = UCL_STATE_ERROR;
2600 return false;
2601 }
2602 else {
2603 p = chunk->pos;
2604 parser->state = parser->prev_state;
2605 }
2606 }
2607 else {
2608 if (!ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE) &&
2609 *p != '(') {
2610 ucl_chunk_skipc (chunk, p);
2611 }
2612 else {
2613 if (c != NULL && p - c > 0) {
2614 /* We got macro name */
2615 macro_len = (size_t) (p - c);
2616 HASH_FIND (hh, parser->macroes, c, macro_len, macro);
2617 if (macro == NULL) {
2618 ucl_create_err (&parser->err,
2619 "error at %s:%d at column %d: "
2620 "unknown macro: '%.*s', character: '%c'",
2621 chunk->fname ? chunk->fname : "memory",
2622 chunk->line,
2623 chunk->column,
2624 (int) (p - c),
2625 c,
2626 *chunk->pos);
2627 parser->state = UCL_STATE_ERROR;
2628 return false;
2629 }
2630 /* Now we need to skip all spaces */
2631 SKIP_SPACES_COMMENTS(parser, chunk, p);
2632 parser->state = UCL_STATE_MACRO;
2633 }
2634 else {
2635 /* We have invalid macro name */
2636 ucl_create_err (&parser->err,
2637 "error at %s:%d at column %d: invalid macro name",
2638 chunk->fname ? chunk->fname : "memory",
2639 chunk->line,
2640 chunk->column);
2641 parser->state = UCL_STATE_ERROR;
2642 return false;
2643 }
2644 }
2645 }
2646 break;
2647 case UCL_STATE_MACRO:
2648 if (*chunk->pos == '(') {
2649 macro_args = ucl_parse_macro_arguments (parser, chunk);
2650 p = chunk->pos;
2651 if (macro_args) {
2652 SKIP_SPACES_COMMENTS(parser, chunk, p);
2653 }
2654 }
2655 else {
2656 macro_args = NULL;
2657 }
2658 if (!ucl_parse_macro_value (parser, chunk, macro,
2659 ¯o_start, ¯o_len)) {
2660 parser->prev_state = parser->state;
2661 parser->state = UCL_STATE_ERROR;
2662 return false;
2663 }
2664 macro_len = ucl_expand_variable (parser, ¯o_escaped,
2665 macro_start, macro_len);
2666 parser->state = parser->prev_state;
2667
2668 if (macro_escaped == NULL && macro != NULL) {
2669 if (macro->is_context) {
2670 ret = macro->h.context_handler (macro_start, macro_len,
2671 macro_args,
2672 parser->top_obj,
2673 macro->ud);
2674 }
2675 else {
2676 ret = macro->h.handler (macro_start, macro_len, macro_args,
2677 macro->ud);
2678 }
2679 }
2680 else if (macro != NULL) {
2681 if (macro->is_context) {
2682 ret = macro->h.context_handler (macro_escaped, macro_len,
2683 macro_args,
2684 parser->top_obj,
2685 macro->ud);
2686 }
2687 else {
2688 ret = macro->h.handler (macro_escaped, macro_len, macro_args,
2689 macro->ud);
2690 }
2691
2692 UCL_FREE (macro_len + 1, macro_escaped);
2693 }
2694 else {
2695 ret = false;
2696 ucl_set_err (parser, UCL_EINTERNAL,
2697 "internal error: parser has macro undefined", &parser->err);
2698 }
2699
2700 /*
2701 * Chunk can be modified within macro handler
2702 */
2703 chunk = parser->chunks;
2704 p = chunk->pos;
2705
2706 if (macro_args) {
2707 ucl_object_unref (macro_args);
2708 }
2709
2710 if (!ret) {
2711 return false;
2712 }
2713 break;
2714 case UCL_STATE_ERROR:
2715 /* Already in the error state */
2716 return false;
2717 default:
2718 ucl_set_err (parser, UCL_EINTERNAL,
2719 "internal error: parser is in an unknown state", &parser->err);
2720 parser->state = UCL_STATE_ERROR;
2721 return false;
2722 }
2723 }
2724
2725 if (parser->last_comment) {
2726 if (parser->cur_obj) {
2727 ucl_attach_comment (parser, parser->cur_obj, true);
2728 }
2729 else if (parser->stack && parser->stack->obj) {
2730 ucl_attach_comment (parser, parser->stack->obj, true);
2731 }
2732 else if (parser->top_obj) {
2733 ucl_attach_comment (parser, parser->top_obj, true);
2734 }
2735 else {
2736 ucl_object_unref (parser->last_comment);
2737 }
2738 }
2739
2740 if (parser->stack != NULL && parser->state != UCL_STATE_ERROR) {
2741 struct ucl_stack *st;
2742 bool has_error = false;
2743
2744 LL_FOREACH (parser->stack, st) {
2745 if (st->chunk != parser->chunks) {
2746 break; /* Not our chunk, give up */
2747 }
2748 if (st->e.params.flags & UCL_STACK_HAS_OBRACE) {
2749 if (parser->err == NULL) {
2750 utstring_new (parser->err);
2751 }
2752
2753 utstring_printf (parser->err, "%s:%d unmatched open brace at %d; ",
2754 chunk->fname ? chunk->fname : "memory",
2755 parser->chunks->line,
2756 st->e.params.line);
2757
2758 has_error = true;
2759 }
2760 }
2761
2762 if (has_error) {
2763 parser->err_code = UCL_EUNPAIRED;
2764
2765 return false;
2766 }
2767 }
2768
2769 return true;
2770 }
2771
2772 #define UPRM_SAFE(fn, a, b, c, el) do { \
2773 if (!fn(a, b, c, a)) \
2774 goto el; \
2775 } while (0)
2776
2777 struct ucl_parser*
ucl_parser_new(int flags)2778 ucl_parser_new (int flags)
2779 {
2780 struct ucl_parser *parser;
2781
2782 parser = UCL_ALLOC (sizeof (struct ucl_parser));
2783 if (parser == NULL) {
2784 return NULL;
2785 }
2786
2787 memset (parser, 0, sizeof (struct ucl_parser));
2788
2789 UPRM_SAFE(ucl_parser_register_macro, parser, "include", ucl_include_handler, e0);
2790 UPRM_SAFE(ucl_parser_register_macro, parser, "try_include", ucl_try_include_handler, e0);
2791 UPRM_SAFE(ucl_parser_register_macro, parser, "includes", ucl_includes_handler, e0);
2792 UPRM_SAFE(ucl_parser_register_macro, parser, "priority", ucl_priority_handler, e0);
2793 UPRM_SAFE(ucl_parser_register_macro, parser, "load", ucl_load_handler, e0);
2794 UPRM_SAFE(ucl_parser_register_context_macro, parser, "inherit", ucl_inherit_handler, e0);
2795
2796 parser->flags = flags;
2797 parser->includepaths = NULL;
2798
2799 if (flags & UCL_PARSER_SAVE_COMMENTS) {
2800 parser->comments = ucl_object_typed_new (UCL_OBJECT);
2801 }
2802
2803 if (!(flags & UCL_PARSER_NO_FILEVARS)) {
2804 /* Initial assumption about filevars */
2805 ucl_parser_set_filevars (parser, NULL, false);
2806 }
2807
2808 return parser;
2809 e0:
2810 ucl_parser_free(parser);
2811 return NULL;
2812 }
2813
2814 bool
ucl_parser_set_default_priority(struct ucl_parser * parser,unsigned prio)2815 ucl_parser_set_default_priority (struct ucl_parser *parser, unsigned prio)
2816 {
2817 if (parser == NULL) {
2818 return false;
2819 }
2820
2821 parser->default_priority = prio;
2822
2823 return true;
2824 }
2825
2826 int
ucl_parser_get_default_priority(struct ucl_parser * parser)2827 ucl_parser_get_default_priority (struct ucl_parser *parser)
2828 {
2829 if (parser == NULL) {
2830 return -1;
2831 }
2832
2833 return parser->default_priority;
2834 }
2835
2836 bool
ucl_parser_register_macro(struct ucl_parser * parser,const char * macro,ucl_macro_handler handler,void * ud)2837 ucl_parser_register_macro (struct ucl_parser *parser, const char *macro,
2838 ucl_macro_handler handler, void* ud)
2839 {
2840 struct ucl_macro *new;
2841
2842 if (macro == NULL || handler == NULL) {
2843 return false;
2844 }
2845
2846 new = UCL_ALLOC (sizeof (struct ucl_macro));
2847 if (new == NULL) {
2848 return false;
2849 }
2850
2851 memset (new, 0, sizeof (struct ucl_macro));
2852 new->h.handler = handler;
2853 new->name = strdup (macro);
2854 if (new->name == NULL) {
2855 UCL_FREE (sizeof (struct ucl_macro), new);
2856 return false;
2857 }
2858 new->ud = ud;
2859 HASH_ADD_KEYPTR (hh, parser->macroes, new->name, strlen (new->name), new);
2860 return true;
2861 }
2862
2863 bool
ucl_parser_register_context_macro(struct ucl_parser * parser,const char * macro,ucl_context_macro_handler handler,void * ud)2864 ucl_parser_register_context_macro (struct ucl_parser *parser, const char *macro,
2865 ucl_context_macro_handler handler, void* ud)
2866 {
2867 struct ucl_macro *new;
2868
2869 if (macro == NULL || handler == NULL) {
2870 return false;
2871 }
2872
2873 new = UCL_ALLOC (sizeof (struct ucl_macro));
2874 if (new == NULL) {
2875 return false;
2876 }
2877
2878 memset (new, 0, sizeof (struct ucl_macro));
2879 new->h.context_handler = handler;
2880 new->name = strdup (macro);
2881 if (new->name == NULL) {
2882 UCL_FREE (sizeof (struct ucl_macro), new);
2883 return false;
2884 }
2885 new->ud = ud;
2886 new->is_context = true;
2887 HASH_ADD_KEYPTR (hh, parser->macroes, new->name, strlen (new->name), new);
2888 return true;
2889 }
2890
2891 void
ucl_parser_register_variable(struct ucl_parser * parser,const char * var,const char * value)2892 ucl_parser_register_variable (struct ucl_parser *parser, const char *var,
2893 const char *value)
2894 {
2895 struct ucl_variable *new = NULL, *cur;
2896
2897 if (var == NULL) {
2898 return;
2899 }
2900
2901 /* Find whether a variable already exists */
2902 LL_FOREACH (parser->variables, cur) {
2903 if (strcmp (cur->var, var) == 0) {
2904 new = cur;
2905 break;
2906 }
2907 }
2908
2909 if (value == NULL) {
2910
2911 if (new != NULL) {
2912 /* Remove variable */
2913 DL_DELETE (parser->variables, new);
2914 free (new->var);
2915 free (new->value);
2916 UCL_FREE (sizeof (struct ucl_variable), new);
2917 }
2918 else {
2919 /* Do nothing */
2920 return;
2921 }
2922 }
2923 else {
2924 if (new == NULL) {
2925 new = UCL_ALLOC (sizeof (struct ucl_variable));
2926 if (new == NULL) {
2927 return;
2928 }
2929 memset (new, 0, sizeof (struct ucl_variable));
2930 new->var = strdup (var);
2931 new->var_len = strlen (var);
2932 new->value = strdup (value);
2933 new->value_len = strlen (value);
2934
2935 DL_APPEND (parser->variables, new);
2936 }
2937 else {
2938 free (new->value);
2939 new->value = strdup (value);
2940 new->value_len = strlen (value);
2941 }
2942 }
2943 }
2944
2945 void
ucl_parser_set_variables_handler(struct ucl_parser * parser,ucl_variable_handler handler,void * ud)2946 ucl_parser_set_variables_handler (struct ucl_parser *parser,
2947 ucl_variable_handler handler, void *ud)
2948 {
2949 parser->var_handler = handler;
2950 parser->var_data = ud;
2951 }
2952
2953 bool
ucl_parser_add_chunk_full(struct ucl_parser * parser,const unsigned char * data,size_t len,unsigned priority,enum ucl_duplicate_strategy strat,enum ucl_parse_type parse_type)2954 ucl_parser_add_chunk_full (struct ucl_parser *parser, const unsigned char *data,
2955 size_t len, unsigned priority, enum ucl_duplicate_strategy strat,
2956 enum ucl_parse_type parse_type)
2957 {
2958 struct ucl_chunk *chunk;
2959 struct ucl_parser_special_handler *special_handler;
2960
2961 if (parser == NULL) {
2962 return false;
2963 }
2964
2965 if (data == NULL && len != 0) {
2966 ucl_create_err (&parser->err, "invalid chunk added");
2967 return false;
2968 }
2969
2970 if (parser->state != UCL_STATE_ERROR) {
2971 chunk = UCL_ALLOC (sizeof (struct ucl_chunk));
2972 if (chunk == NULL) {
2973 ucl_create_err (&parser->err, "cannot allocate chunk structure");
2974 return false;
2975 }
2976
2977 memset (chunk, 0, sizeof (*chunk));
2978
2979 /* Apply all matching handlers from the first to the last */
2980 LL_FOREACH (parser->special_handlers, special_handler) {
2981 if ((special_handler->flags & UCL_SPECIAL_HANDLER_PREPROCESS_ALL) ||
2982 (len >= special_handler->magic_len &&
2983 memcmp (data, special_handler->magic, special_handler->magic_len) == 0)) {
2984 unsigned char *ndata = NULL;
2985 size_t nlen = 0;
2986
2987 if (!special_handler->handler (parser, data, len, &ndata, &nlen,
2988 special_handler->user_data)) {
2989 UCL_FREE(sizeof (struct ucl_chunk), chunk);
2990 ucl_create_err (&parser->err, "call for external handler failed");
2991
2992 return false;
2993 }
2994
2995 struct ucl_parser_special_handler_chain *nchain;
2996 nchain = UCL_ALLOC (sizeof (*nchain));
2997 nchain->begin = ndata;
2998 nchain->len = nlen;
2999 nchain->special_handler = special_handler;
3000
3001 /* Free order is reversed */
3002 LL_PREPEND (chunk->special_handlers, nchain);
3003
3004 data = ndata;
3005 len = nlen;
3006 }
3007 }
3008
3009 if (parse_type == UCL_PARSE_AUTO && len > 0) {
3010 /* We need to detect parse type by the first symbol */
3011 if ((*data & 0x80) == 0x80) {
3012 parse_type = UCL_PARSE_MSGPACK;
3013 }
3014 else if (*data == '(') {
3015 parse_type = UCL_PARSE_CSEXP;
3016 }
3017 else {
3018 parse_type = UCL_PARSE_UCL;
3019 }
3020 }
3021
3022 chunk->begin = data;
3023 chunk->remain = len;
3024 chunk->pos = chunk->begin;
3025 chunk->end = chunk->begin + len;
3026 chunk->line = 1;
3027 chunk->column = 0;
3028 chunk->priority = priority;
3029 chunk->strategy = strat;
3030 chunk->parse_type = parse_type;
3031
3032 if (parser->cur_file) {
3033 chunk->fname = strdup (parser->cur_file);
3034 }
3035
3036 LL_PREPEND (parser->chunks, chunk);
3037 parser->recursion ++;
3038
3039 if (parser->recursion > UCL_MAX_RECURSION) {
3040 ucl_create_err (&parser->err, "maximum include nesting limit is reached: %d",
3041 parser->recursion);
3042 return false;
3043 }
3044
3045 if (len > 0) {
3046 /* Need to parse something */
3047 switch (parse_type) {
3048 default:
3049 case UCL_PARSE_UCL:
3050 return ucl_state_machine (parser);
3051 case UCL_PARSE_MSGPACK:
3052 return ucl_parse_msgpack (parser);
3053 case UCL_PARSE_CSEXP:
3054 return ucl_parse_csexp (parser);
3055 }
3056 }
3057 else {
3058 /* Just add empty chunk and go forward */
3059 if (parser->top_obj == NULL) {
3060 /*
3061 * In case of empty object, create one to indicate that we've
3062 * read something
3063 */
3064 parser->top_obj = ucl_object_new_full (UCL_OBJECT, priority);
3065 }
3066
3067 return true;
3068 }
3069 }
3070
3071 ucl_create_err (&parser->err, "a parser is in an invalid state");
3072
3073 return false;
3074 }
3075
3076 bool
ucl_parser_add_chunk_priority(struct ucl_parser * parser,const unsigned char * data,size_t len,unsigned priority)3077 ucl_parser_add_chunk_priority (struct ucl_parser *parser,
3078 const unsigned char *data, size_t len, unsigned priority)
3079 {
3080 /* We dereference parser, so this check is essential */
3081 if (parser == NULL) {
3082 return false;
3083 }
3084
3085 return ucl_parser_add_chunk_full (parser, data, len,
3086 priority, UCL_DUPLICATE_APPEND, UCL_PARSE_UCL);
3087 }
3088
3089 bool
ucl_parser_add_chunk(struct ucl_parser * parser,const unsigned char * data,size_t len)3090 ucl_parser_add_chunk (struct ucl_parser *parser, const unsigned char *data,
3091 size_t len)
3092 {
3093 if (parser == NULL) {
3094 return false;
3095 }
3096
3097 return ucl_parser_add_chunk_full (parser, data, len,
3098 parser->default_priority, UCL_DUPLICATE_APPEND, UCL_PARSE_UCL);
3099 }
3100
3101 bool
ucl_parser_insert_chunk(struct ucl_parser * parser,const unsigned char * data,size_t len)3102 ucl_parser_insert_chunk (struct ucl_parser *parser, const unsigned char *data,
3103 size_t len)
3104 {
3105 if (parser == NULL || parser->top_obj == NULL) {
3106 return false;
3107 }
3108
3109 bool res;
3110 struct ucl_chunk *chunk;
3111
3112 int state = parser->state;
3113 parser->state = UCL_STATE_INIT;
3114
3115 /* Prevent inserted chunks from unintentionally closing the current object */
3116 if (parser->stack != NULL && parser->stack->next != NULL) {
3117 parser->stack->e.params.level = parser->stack->next->e.params.level;
3118 }
3119
3120 res = ucl_parser_add_chunk_full (parser, data, len, parser->chunks->priority,
3121 parser->chunks->strategy, parser->chunks->parse_type);
3122
3123 /* Remove chunk from the stack */
3124 chunk = parser->chunks;
3125 if (chunk != NULL) {
3126 parser->chunks = chunk->next;
3127 ucl_chunk_free (chunk);
3128 parser->recursion --;
3129 }
3130
3131 parser->state = state;
3132
3133 return res;
3134 }
3135
3136 bool
ucl_parser_add_string_priority(struct ucl_parser * parser,const char * data,size_t len,unsigned priority)3137 ucl_parser_add_string_priority (struct ucl_parser *parser, const char *data,
3138 size_t len, unsigned priority)
3139 {
3140 if (data == NULL) {
3141 ucl_create_err (&parser->err, "invalid string added");
3142 return false;
3143 }
3144 if (len == 0) {
3145 len = strlen (data);
3146 }
3147
3148 return ucl_parser_add_chunk_priority (parser,
3149 (const unsigned char *)data, len, priority);
3150 }
3151
3152 bool
ucl_parser_add_string(struct ucl_parser * parser,const char * data,size_t len)3153 ucl_parser_add_string (struct ucl_parser *parser, const char *data,
3154 size_t len)
3155 {
3156 if (parser == NULL) {
3157 return false;
3158 }
3159
3160 return ucl_parser_add_string_priority (parser,
3161 (const unsigned char *)data, len, parser->default_priority);
3162 }
3163
3164 bool
ucl_set_include_path(struct ucl_parser * parser,ucl_object_t * paths)3165 ucl_set_include_path (struct ucl_parser *parser, ucl_object_t *paths)
3166 {
3167 if (parser == NULL || paths == NULL) {
3168 return false;
3169 }
3170
3171 if (parser->includepaths == NULL) {
3172 parser->includepaths = ucl_object_copy (paths);
3173 }
3174 else {
3175 ucl_object_unref (parser->includepaths);
3176 parser->includepaths = ucl_object_copy (paths);
3177 }
3178
3179 if (parser->includepaths == NULL) {
3180 return false;
3181 }
3182
3183 return true;
3184 }
3185
ucl_parser_chunk_peek(struct ucl_parser * parser)3186 unsigned char ucl_parser_chunk_peek (struct ucl_parser *parser)
3187 {
3188 if (parser == NULL || parser->chunks == NULL || parser->chunks->pos == NULL || parser->chunks->end == NULL ||
3189 parser->chunks->pos == parser->chunks->end) {
3190 return 0;
3191 }
3192
3193 return( *parser->chunks->pos );
3194 }
3195
ucl_parser_chunk_skip(struct ucl_parser * parser)3196 bool ucl_parser_chunk_skip (struct ucl_parser *parser)
3197 {
3198 if (parser == NULL || parser->chunks == NULL || parser->chunks->pos == NULL || parser->chunks->end == NULL ||
3199 parser->chunks->pos == parser->chunks->end) {
3200 return false;
3201 }
3202
3203 const unsigned char *p = parser->chunks->pos;
3204 ucl_chunk_skipc( parser->chunks, p );
3205 if( parser->chunks->pos != NULL ) return true;
3206 return false;
3207 }
3208
3209 ucl_object_t*
ucl_parser_get_current_stack_object(struct ucl_parser * parser,unsigned int depth)3210 ucl_parser_get_current_stack_object (struct ucl_parser *parser, unsigned int depth)
3211 {
3212 ucl_object_t *obj;
3213
3214 if (parser == NULL || parser->stack == NULL) {
3215 return NULL;
3216 }
3217
3218 struct ucl_stack *stack = parser->stack;
3219 if(stack == NULL || stack->obj == NULL || ucl_object_type (stack->obj) != UCL_OBJECT)
3220 {
3221 return NULL;
3222 }
3223
3224 for( unsigned int i = 0; i < depth; ++i )
3225 {
3226 stack = stack->next;
3227 if(stack == NULL || stack->obj == NULL || ucl_object_type (stack->obj) != UCL_OBJECT)
3228 {
3229 return NULL;
3230 }
3231 }
3232
3233 obj = ucl_object_ref (stack->obj);
3234 return obj;
3235 }
3236
3237