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