xref: /freebsd/contrib/libucl/src/ucl_parser.c (revision b5e2bd5ef38181ce4a445ec19f1fa5cb6c8ea692)
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 					&macro_start, &macro_len)) {
2660 				parser->prev_state = parser->state;
2661 				parser->state = UCL_STATE_ERROR;
2662 				return false;
2663 			}
2664 			macro_len = ucl_expand_variable (parser, &macro_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