ucl_parser.c revision 290071
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 "ucl.h"
25#include "ucl_internal.h"
26#include "ucl_chartable.h"
27
28/**
29 * @file ucl_parser.c
30 * The implementation of ucl parser
31 */
32
33struct ucl_parser_saved_state {
34	unsigned int line;
35	unsigned int column;
36	size_t remain;
37	const unsigned char *pos;
38};
39
40/**
41 * Move up to len characters
42 * @param parser
43 * @param begin
44 * @param len
45 * @return new position in chunk
46 */
47#define ucl_chunk_skipc(chunk, p)    do{					\
48    if (*(p) == '\n') {										\
49        (chunk)->line ++;									\
50        (chunk)->column = 0;								\
51    }														\
52    else (chunk)->column ++;								\
53    (p++);													\
54    (chunk)->pos ++;										\
55    (chunk)->remain --;										\
56    } while (0)
57
58static inline void
59ucl_set_err (struct ucl_parser *parser, int code, const char *str, UT_string **err)
60{
61	const char *fmt_string, *filename;
62	struct ucl_chunk *chunk = parser->chunks;
63
64	if (parser->cur_file) {
65		filename = parser->cur_file;
66	}
67	else {
68		filename = "<unknown>";
69	}
70
71	if (chunk->pos < chunk->end) {
72		if (isgraph (*chunk->pos)) {
73			fmt_string = "error while parsing %s: "
74					"line: %d, column: %d - '%s', character: '%c'";
75		}
76		else {
77			fmt_string = "error while parsing %s: "
78					"line: %d, column: %d - '%s', character: '0x%02x'";
79		}
80		ucl_create_err (err, fmt_string,
81			filename, chunk->line, chunk->column,
82			str, *chunk->pos);
83	}
84	else {
85		ucl_create_err (err, "error while parsing %s: at the end of chunk: %s",
86			filename, str);
87	}
88
89	parser->err_code = code;
90}
91
92/**
93 * Skip all comments from the current pos resolving nested and multiline comments
94 * @param parser
95 * @return
96 */
97static bool
98ucl_skip_comments (struct ucl_parser *parser)
99{
100	struct ucl_chunk *chunk = parser->chunks;
101	const unsigned char *p;
102	int comments_nested = 0;
103	bool quoted = false;
104
105	p = chunk->pos;
106
107start:
108	if (chunk->remain > 0 && *p == '#') {
109		if (parser->state != UCL_STATE_SCOMMENT &&
110				parser->state != UCL_STATE_MCOMMENT) {
111			while (p < chunk->end) {
112				if (*p == '\n') {
113					ucl_chunk_skipc (chunk, p);
114					goto start;
115				}
116				ucl_chunk_skipc (chunk, p);
117			}
118		}
119	}
120	else if (chunk->remain >= 2 && *p == '/') {
121		if (p[1] == '*') {
122			ucl_chunk_skipc (chunk, p);
123			comments_nested ++;
124			ucl_chunk_skipc (chunk, p);
125
126			while (p < chunk->end) {
127				if (*p == '"' && *(p - 1) != '\\') {
128					quoted = !quoted;
129				}
130
131				if (!quoted) {
132					if (*p == '*') {
133						ucl_chunk_skipc (chunk, p);
134						if (*p == '/') {
135							comments_nested --;
136							if (comments_nested == 0) {
137								ucl_chunk_skipc (chunk, p);
138								goto start;
139							}
140						}
141						ucl_chunk_skipc (chunk, p);
142					}
143					else if (p[0] == '/' && chunk->remain >= 2 && p[1] == '*') {
144						comments_nested ++;
145						ucl_chunk_skipc (chunk, p);
146						ucl_chunk_skipc (chunk, p);
147						continue;
148					}
149				}
150				ucl_chunk_skipc (chunk, p);
151			}
152			if (comments_nested != 0) {
153				ucl_set_err (parser, UCL_ENESTED,
154						"unfinished multiline comment", &parser->err);
155				return false;
156			}
157		}
158	}
159
160	return true;
161}
162
163/**
164 * Return multiplier for a character
165 * @param c multiplier character
166 * @param is_bytes if true use 1024 multiplier
167 * @return multiplier
168 */
169static inline unsigned long
170ucl_lex_num_multiplier (const unsigned char c, bool is_bytes) {
171	const struct {
172		char c;
173		long mult_normal;
174		long mult_bytes;
175	} multipliers[] = {
176			{'m', 1000 * 1000, 1024 * 1024},
177			{'k', 1000, 1024},
178			{'g', 1000 * 1000 * 1000, 1024 * 1024 * 1024}
179	};
180	int i;
181
182	for (i = 0; i < 3; i ++) {
183		if (tolower (c) == multipliers[i].c) {
184			if (is_bytes) {
185				return multipliers[i].mult_bytes;
186			}
187			return multipliers[i].mult_normal;
188		}
189	}
190
191	return 1;
192}
193
194
195/**
196 * Return multiplier for time scaling
197 * @param c
198 * @return
199 */
200static inline double
201ucl_lex_time_multiplier (const unsigned char c) {
202	const struct {
203		char c;
204		double mult;
205	} multipliers[] = {
206			{'m', 60},
207			{'h', 60 * 60},
208			{'d', 60 * 60 * 24},
209			{'w', 60 * 60 * 24 * 7},
210			{'y', 60 * 60 * 24 * 7 * 365}
211	};
212	int i;
213
214	for (i = 0; i < 5; i ++) {
215		if (tolower (c) == multipliers[i].c) {
216			return multipliers[i].mult;
217		}
218	}
219
220	return 1;
221}
222
223/**
224 * Return true if a character is a end of an atom
225 * @param c
226 * @return
227 */
228static inline bool
229ucl_lex_is_atom_end (const unsigned char c)
230{
231	return ucl_test_character (c, UCL_CHARACTER_VALUE_END);
232}
233
234static inline bool
235ucl_lex_is_comment (const unsigned char c1, const unsigned char c2)
236{
237	if (c1 == '/') {
238		if (c2 == '*') {
239			return true;
240		}
241	}
242	else if (c1 == '#') {
243		return true;
244	}
245	return false;
246}
247
248/**
249 * Check variable found
250 * @param parser
251 * @param ptr
252 * @param remain
253 * @param out_len
254 * @param strict
255 * @param found
256 * @return
257 */
258static inline const char *
259ucl_check_variable_safe (struct ucl_parser *parser, const char *ptr, size_t remain,
260		size_t *out_len, bool strict, bool *found)
261{
262	struct ucl_variable *var;
263	unsigned char *dst;
264	size_t dstlen;
265	bool need_free = false;
266
267	LL_FOREACH (parser->variables, var) {
268		if (strict) {
269			if (remain == var->var_len) {
270				if (memcmp (ptr, var->var, var->var_len) == 0) {
271					*out_len += var->value_len;
272					*found = true;
273					return (ptr + var->var_len);
274				}
275			}
276		}
277		else {
278			if (remain >= var->var_len) {
279				if (memcmp (ptr, var->var, var->var_len) == 0) {
280					*out_len += var->value_len;
281					*found = true;
282					return (ptr + var->var_len);
283				}
284			}
285		}
286	}
287
288	/* XXX: can only handle ${VAR} */
289	if (!(*found) && parser->var_handler != NULL && strict) {
290		/* Call generic handler */
291		if (parser->var_handler (ptr, remain, &dst, &dstlen, &need_free,
292				parser->var_data)) {
293			*found = true;
294			if (need_free) {
295				free (dst);
296			}
297			return (ptr + remain);
298		}
299	}
300
301	return ptr;
302}
303
304/**
305 * Check for a variable in a given string
306 * @param parser
307 * @param ptr
308 * @param remain
309 * @param out_len
310 * @param vars_found
311 * @return
312 */
313static const char *
314ucl_check_variable (struct ucl_parser *parser, const char *ptr,
315		size_t remain, size_t *out_len, bool *vars_found)
316{
317	const char *p, *end, *ret = ptr;
318	bool found = false;
319
320	if (*ptr == '{') {
321		/* We need to match the variable enclosed in braces */
322		p = ptr + 1;
323		end = ptr + remain;
324		while (p < end) {
325			if (*p == '}') {
326				ret = ucl_check_variable_safe (parser, ptr + 1, p - ptr - 1,
327						out_len, true, &found);
328				if (found) {
329					/* {} must be excluded actually */
330					ret ++;
331					if (!*vars_found) {
332						*vars_found = true;
333					}
334				}
335				else {
336					*out_len += 2;
337				}
338				break;
339			}
340			p ++;
341		}
342	}
343	else if (*ptr != '$') {
344		/* Not count escaped dollar sign */
345		ret = ucl_check_variable_safe (parser, ptr, remain, out_len, false, &found);
346		if (found && !*vars_found) {
347			*vars_found = true;
348		}
349		if (!found) {
350			(*out_len) ++;
351		}
352	}
353	else {
354		ret ++;
355		(*out_len) ++;
356	}
357
358	return ret;
359}
360
361/**
362 * Expand a single variable
363 * @param parser
364 * @param ptr
365 * @param remain
366 * @param dest
367 * @return
368 */
369static const char *
370ucl_expand_single_variable (struct ucl_parser *parser, const char *ptr,
371		size_t remain, unsigned char **dest)
372{
373	unsigned char *d = *dest, *dst;
374	const char *p = ptr + 1, *ret;
375	struct ucl_variable *var;
376	size_t dstlen;
377	bool need_free = false;
378	bool found = false;
379	bool strict = false;
380
381	ret = ptr + 1;
382	remain --;
383
384	if (*p == '$') {
385		*d++ = *p++;
386		*dest = d;
387		return p;
388	}
389	else if (*p == '{') {
390		p ++;
391		strict = true;
392		ret += 2;
393		remain -= 2;
394	}
395
396	LL_FOREACH (parser->variables, var) {
397		if (remain >= var->var_len) {
398			if (memcmp (p, var->var, var->var_len) == 0) {
399				memcpy (d, var->value, var->value_len);
400				ret += var->var_len;
401				d += var->value_len;
402				found = true;
403				break;
404			}
405		}
406	}
407	if (!found) {
408		if (strict && parser->var_handler != NULL) {
409			if (parser->var_handler (ptr, remain, &dst, &dstlen, &need_free,
410							parser->var_data)) {
411				memcpy (d, dst, dstlen);
412				ret += dstlen;
413				d += remain;
414				found = true;
415			}
416		}
417
418		/* Leave variable as is */
419		if (!found) {
420			if (strict) {
421				/* Copy '${' */
422				memcpy (d, ptr, 2);
423				d += 2;
424				ret --;
425			}
426			else {
427				memcpy (d, ptr, 1);
428				d ++;
429			}
430		}
431	}
432
433	*dest = d;
434	return ret;
435}
436
437/**
438 * Expand variables in string
439 * @param parser
440 * @param dst
441 * @param src
442 * @param in_len
443 * @return
444 */
445static ssize_t
446ucl_expand_variable (struct ucl_parser *parser, unsigned char **dst,
447		const char *src, size_t in_len)
448{
449	const char *p, *end = src + in_len;
450	unsigned char *d;
451	size_t out_len = 0;
452	bool vars_found = false;
453
454	p = src;
455	while (p != end) {
456		if (*p == '$') {
457			p = ucl_check_variable (parser, p + 1, end - p - 1, &out_len, &vars_found);
458		}
459		else {
460			p ++;
461			out_len ++;
462		}
463	}
464
465	if (!vars_found) {
466		/* Trivial case */
467		*dst = NULL;
468		return in_len;
469	}
470
471	*dst = UCL_ALLOC (out_len + 1);
472	if (*dst == NULL) {
473		return in_len;
474	}
475
476	d = *dst;
477	p = src;
478	while (p != end) {
479		if (*p == '$') {
480			p = ucl_expand_single_variable (parser, p, end - p, &d);
481		}
482		else {
483			*d++ = *p++;
484		}
485	}
486
487	*d = '\0';
488
489	return out_len;
490}
491
492/**
493 * Store or copy pointer to the trash stack
494 * @param parser parser object
495 * @param src src string
496 * @param dst destination buffer (trash stack pointer)
497 * @param dst_const const destination pointer (e.g. value of object)
498 * @param in_len input length
499 * @param need_unescape need to unescape source (and copy it)
500 * @param need_lowercase need to lowercase value (and copy)
501 * @param need_expand need to expand variables (and copy as well)
502 * @return output length (excluding \0 symbol)
503 */
504static inline ssize_t
505ucl_copy_or_store_ptr (struct ucl_parser *parser,
506		const unsigned char *src, unsigned char **dst,
507		const char **dst_const, size_t in_len,
508		bool need_unescape, bool need_lowercase, bool need_expand)
509{
510	ssize_t ret = -1, tret;
511	unsigned char *tmp;
512
513	if (need_unescape || need_lowercase ||
514			(need_expand && parser->variables != NULL) ||
515			!(parser->flags & UCL_PARSER_ZEROCOPY)) {
516		/* Copy string */
517		*dst = UCL_ALLOC (in_len + 1);
518		if (*dst == NULL) {
519			ucl_set_err (parser, UCL_EINTERNAL, "cannot allocate memory for a string",
520					&parser->err);
521			return false;
522		}
523		if (need_lowercase) {
524			ret = ucl_strlcpy_tolower (*dst, src, in_len + 1);
525		}
526		else {
527			ret = ucl_strlcpy_unsafe (*dst, src, in_len + 1);
528		}
529
530		if (need_unescape) {
531			ret = ucl_unescape_json_string (*dst, ret);
532		}
533		if (need_expand) {
534			tmp = *dst;
535			tret = ret;
536			ret = ucl_expand_variable (parser, dst, tmp, ret);
537			if (*dst == NULL) {
538				/* Nothing to expand */
539				*dst = tmp;
540				ret = tret;
541			}
542			else {
543				/* Free unexpanded value */
544				UCL_FREE (in_len + 1, tmp);
545			}
546		}
547		*dst_const = *dst;
548	}
549	else {
550		*dst_const = src;
551		ret = in_len;
552	}
553
554	return ret;
555}
556
557/**
558 * Create and append an object at the specified level
559 * @param parser
560 * @param is_array
561 * @param level
562 * @return
563 */
564static inline ucl_object_t *
565ucl_parser_add_container (ucl_object_t *obj, struct ucl_parser *parser,
566		bool is_array, int level)
567{
568	struct ucl_stack *st;
569
570	if (!is_array) {
571		if (obj == NULL) {
572			obj = ucl_object_new_full (UCL_OBJECT, parser->chunks->priority);
573		}
574		else {
575			obj->type = UCL_OBJECT;
576		}
577		if (obj->value.ov == NULL) {
578			obj->value.ov = ucl_hash_create (parser->flags & UCL_PARSER_KEY_LOWERCASE);
579		}
580		parser->state = UCL_STATE_KEY;
581	}
582	else {
583		if (obj == NULL) {
584			obj = ucl_object_new_full (UCL_ARRAY, parser->chunks->priority);
585		}
586		else {
587			obj->type = UCL_ARRAY;
588		}
589		parser->state = UCL_STATE_VALUE;
590	}
591
592	st = UCL_ALLOC (sizeof (struct ucl_stack));
593	if (st == NULL) {
594		ucl_set_err (parser, UCL_EINTERNAL, "cannot allocate memory for an object",
595				&parser->err);
596		ucl_object_unref (obj);
597		return NULL;
598	}
599	st->obj = obj;
600	st->level = level;
601	LL_PREPEND (parser->stack, st);
602	parser->cur_obj = obj;
603
604	return obj;
605}
606
607int
608ucl_maybe_parse_number (ucl_object_t *obj,
609		const char *start, const char *end, const char **pos,
610		bool allow_double, bool number_bytes, bool allow_time)
611{
612	const char *p = start, *c = start;
613	char *endptr;
614	bool got_dot = false, got_exp = false, need_double = false,
615			is_time = false, valid_start = false, is_hex = false,
616			is_neg = false;
617	double dv = 0;
618	int64_t lv = 0;
619
620	if (*p == '-') {
621		is_neg = true;
622		c ++;
623		p ++;
624	}
625	while (p < end) {
626		if (is_hex && isxdigit (*p)) {
627			p ++;
628		}
629		else if (isdigit (*p)) {
630			valid_start = true;
631			p ++;
632		}
633		else if (!is_hex && (*p == 'x' || *p == 'X')) {
634			is_hex = true;
635			allow_double = false;
636			c = p + 1;
637		}
638		else if (allow_double) {
639			if (p == c) {
640				/* Empty digits sequence, not a number */
641				*pos = start;
642				return EINVAL;
643			}
644			else if (*p == '.') {
645				if (got_dot) {
646					/* Double dots, not a number */
647					*pos = start;
648					return EINVAL;
649				}
650				else {
651					got_dot = true;
652					need_double = true;
653					p ++;
654				}
655			}
656			else if (*p == 'e' || *p == 'E') {
657				if (got_exp) {
658					/* Double exp, not a number */
659					*pos = start;
660					return EINVAL;
661				}
662				else {
663					got_exp = true;
664					need_double = true;
665					p ++;
666					if (p >= end) {
667						*pos = start;
668						return EINVAL;
669					}
670					if (!isdigit (*p) && *p != '+' && *p != '-') {
671						/* Wrong exponent sign */
672						*pos = start;
673						return EINVAL;
674					}
675					else {
676						p ++;
677					}
678				}
679			}
680			else {
681				/* Got the end of the number, need to check */
682				break;
683			}
684		}
685		else {
686			break;
687		}
688	}
689
690	if (!valid_start) {
691		*pos = start;
692		return EINVAL;
693	}
694
695	errno = 0;
696	if (need_double) {
697		dv = strtod (c, &endptr);
698	}
699	else {
700		if (is_hex) {
701			lv = strtoimax (c, &endptr, 16);
702		}
703		else {
704			lv = strtoimax (c, &endptr, 10);
705		}
706	}
707	if (errno == ERANGE) {
708		*pos = start;
709		return ERANGE;
710	}
711
712	/* Now check endptr */
713	if (endptr == NULL || ucl_lex_is_atom_end (*endptr) || *endptr == '\0') {
714		p = endptr;
715		goto set_obj;
716	}
717
718	if (endptr < end && endptr != start) {
719		p = endptr;
720		switch (*p) {
721		case 'm':
722		case 'M':
723		case 'g':
724		case 'G':
725		case 'k':
726		case 'K':
727			if (end - p >= 2) {
728				if (p[1] == 's' || p[1] == 'S') {
729					/* Milliseconds */
730					if (!need_double) {
731						need_double = true;
732						dv = lv;
733					}
734					is_time = true;
735					if (p[0] == 'm' || p[0] == 'M') {
736						dv /= 1000.;
737					}
738					else {
739						dv *= ucl_lex_num_multiplier (*p, false);
740					}
741					p += 2;
742					goto set_obj;
743				}
744				else if (number_bytes || (p[1] == 'b' || p[1] == 'B')) {
745					/* Bytes */
746					if (need_double) {
747						need_double = false;
748						lv = dv;
749					}
750					lv *= ucl_lex_num_multiplier (*p, true);
751					p += 2;
752					goto set_obj;
753				}
754				else if (ucl_lex_is_atom_end (p[1])) {
755					if (need_double) {
756						dv *= ucl_lex_num_multiplier (*p, false);
757					}
758					else {
759						lv *= ucl_lex_num_multiplier (*p, number_bytes);
760					}
761					p ++;
762					goto set_obj;
763				}
764				else if (allow_time && end - p >= 3) {
765					if (tolower (p[0]) == 'm' &&
766							tolower (p[1]) == 'i' &&
767							tolower (p[2]) == 'n') {
768						/* Minutes */
769						if (!need_double) {
770							need_double = true;
771							dv = lv;
772						}
773						is_time = true;
774						dv *= 60.;
775						p += 3;
776						goto set_obj;
777					}
778				}
779			}
780			else {
781				if (need_double) {
782					dv *= ucl_lex_num_multiplier (*p, false);
783				}
784				else {
785					lv *= ucl_lex_num_multiplier (*p, number_bytes);
786				}
787				p ++;
788				goto set_obj;
789			}
790			break;
791		case 'S':
792		case 's':
793			if (allow_time &&
794					(p == end - 1 || ucl_lex_is_atom_end (p[1]))) {
795				if (!need_double) {
796					need_double = true;
797					dv = lv;
798				}
799				p ++;
800				is_time = true;
801				goto set_obj;
802			}
803			break;
804		case 'h':
805		case 'H':
806		case 'd':
807		case 'D':
808		case 'w':
809		case 'W':
810		case 'Y':
811		case 'y':
812			if (allow_time &&
813					(p == end - 1 || ucl_lex_is_atom_end (p[1]))) {
814				if (!need_double) {
815					need_double = true;
816					dv = lv;
817				}
818				is_time = true;
819				dv *= ucl_lex_time_multiplier (*p);
820				p ++;
821				goto set_obj;
822			}
823			break;
824		case '\t':
825		case ' ':
826			while (p < end && ucl_test_character(*p, UCL_CHARACTER_WHITESPACE)) {
827				p++;
828			}
829			if (ucl_lex_is_atom_end(*p))
830				goto set_obj;
831			break;
832		}
833	}
834	else if (endptr == end) {
835		/* Just a number at the end of chunk */
836		p = endptr;
837		goto set_obj;
838	}
839
840	*pos = c;
841	return EINVAL;
842
843set_obj:
844	if (obj != NULL) {
845		if (allow_double && (need_double || is_time)) {
846			if (!is_time) {
847				obj->type = UCL_FLOAT;
848			}
849			else {
850				obj->type = UCL_TIME;
851			}
852			obj->value.dv = is_neg ? (-dv) : dv;
853		}
854		else {
855			obj->type = UCL_INT;
856			obj->value.iv = is_neg ? (-lv) : lv;
857		}
858	}
859	*pos = p;
860	return 0;
861}
862
863/**
864 * Parse possible number
865 * @param parser
866 * @param chunk
867 * @param obj
868 * @return true if a number has been parsed
869 */
870static bool
871ucl_lex_number (struct ucl_parser *parser,
872		struct ucl_chunk *chunk, ucl_object_t *obj)
873{
874	const unsigned char *pos;
875	int ret;
876
877	ret = ucl_maybe_parse_number (obj, chunk->pos, chunk->end, (const char **)&pos,
878			true, false, ((parser->flags & UCL_PARSER_NO_TIME) == 0));
879
880	if (ret == 0) {
881		chunk->remain -= pos - chunk->pos;
882		chunk->column += pos - chunk->pos;
883		chunk->pos = pos;
884		return true;
885	}
886	else if (ret == ERANGE) {
887		ucl_set_err (parser, UCL_ESYNTAX, "numeric value out of range",
888				&parser->err);
889	}
890
891	return false;
892}
893
894/**
895 * Parse quoted string with possible escapes
896 * @param parser
897 * @param chunk
898 * @param need_unescape
899 * @param ucl_escape
900 * @param var_expand
901 * @return true if a string has been parsed
902 */
903static bool
904ucl_lex_json_string (struct ucl_parser *parser,
905		struct ucl_chunk *chunk, bool *need_unescape, bool *ucl_escape, bool *var_expand)
906{
907	const unsigned char *p = chunk->pos;
908	unsigned char c;
909	int i;
910
911	while (p < chunk->end) {
912		c = *p;
913		if (c < 0x1F) {
914			/* Unmasked control character */
915			if (c == '\n') {
916				ucl_set_err (parser, UCL_ESYNTAX, "unexpected newline",
917						&parser->err);
918			}
919			else {
920				ucl_set_err (parser, UCL_ESYNTAX, "unexpected control character",
921						&parser->err);
922			}
923			return false;
924		}
925		else if (c == '\\') {
926			ucl_chunk_skipc (chunk, p);
927			c = *p;
928			if (p >= chunk->end) {
929				ucl_set_err (parser, UCL_ESYNTAX, "unfinished escape character",
930						&parser->err);
931				return false;
932			}
933			else if (ucl_test_character (c, UCL_CHARACTER_ESCAPE)) {
934				if (c == 'u') {
935					ucl_chunk_skipc (chunk, p);
936					for (i = 0; i < 4 && p < chunk->end; i ++) {
937						if (!isxdigit (*p)) {
938							ucl_set_err (parser, UCL_ESYNTAX, "invalid utf escape",
939									&parser->err);
940							return false;
941						}
942						ucl_chunk_skipc (chunk, p);
943					}
944					if (p >= chunk->end) {
945						ucl_set_err (parser, UCL_ESYNTAX, "unfinished escape character",
946								&parser->err);
947						return false;
948					}
949				}
950				else {
951					ucl_chunk_skipc (chunk, p);
952				}
953			}
954			*need_unescape = true;
955			*ucl_escape = true;
956			continue;
957		}
958		else if (c == '"') {
959			ucl_chunk_skipc (chunk, p);
960			return true;
961		}
962		else if (ucl_test_character (c, UCL_CHARACTER_UCL_UNSAFE)) {
963			*ucl_escape = true;
964		}
965		else if (c == '$') {
966			*var_expand = true;
967		}
968		ucl_chunk_skipc (chunk, p);
969	}
970
971	ucl_set_err (parser, UCL_ESYNTAX, "no quote at the end of json string",
972			&parser->err);
973	return false;
974}
975
976static void
977ucl_parser_append_elt (struct ucl_parser *parser, ucl_hash_t *cont,
978		ucl_object_t *top,
979		ucl_object_t *elt)
980{
981	ucl_object_t *nobj;
982
983	if ((parser->flags & UCL_PARSER_NO_IMPLICIT_ARRAYS) == 0) {
984		/* Implicit array */
985		top->flags |= UCL_OBJECT_MULTIVALUE;
986		DL_APPEND (top, elt);
987		parser->stack->obj->len ++;
988	}
989	else {
990		if ((top->flags & UCL_OBJECT_MULTIVALUE) != 0) {
991			/* Just add to the explicit array */
992			ucl_array_append (top, elt);
993		}
994		else {
995			/* Convert to an array */
996			nobj = ucl_object_typed_new (UCL_ARRAY);
997			nobj->key = top->key;
998			nobj->keylen = top->keylen;
999			nobj->flags |= UCL_OBJECT_MULTIVALUE;
1000			ucl_array_append (nobj, top);
1001			ucl_array_append (nobj, elt);
1002			ucl_hash_replace (cont, top, nobj);
1003		}
1004	}
1005}
1006
1007bool
1008ucl_parser_process_object_element (struct ucl_parser *parser, ucl_object_t *nobj)
1009{
1010	ucl_hash_t *container;
1011	ucl_object_t *tobj;
1012
1013	container = parser->stack->obj->value.ov;
1014
1015	tobj = __DECONST (ucl_object_t *, ucl_hash_search_obj (container, nobj));
1016	if (tobj == NULL) {
1017		container = ucl_hash_insert_object (container, nobj,
1018				parser->flags & UCL_PARSER_KEY_LOWERCASE);
1019		nobj->prev = nobj;
1020		nobj->next = NULL;
1021		parser->stack->obj->len ++;
1022	}
1023	else {
1024		unsigned priold = ucl_object_get_priority (tobj),
1025				prinew = ucl_object_get_priority (nobj);
1026		switch (parser->chunks->strategy) {
1027
1028		case UCL_DUPLICATE_APPEND:
1029			/*
1030			 * The logic here is the following:
1031			 *
1032			 * - if we have two objects with the same priority, then we form an
1033			 * implicit or explicit array
1034			 * - if a new object has bigger priority, then we overwrite an old one
1035			 * - if a new object has lower priority, then we ignore it
1036			 */
1037
1038
1039			/* Special case for inherited objects */
1040			if (tobj->flags & UCL_OBJECT_INHERITED) {
1041				prinew = priold + 1;
1042			}
1043
1044			if (priold == prinew) {
1045				ucl_parser_append_elt (parser, container, tobj, nobj);
1046			}
1047			else if (priold > prinew) {
1048				/*
1049				 * We add this new object to a list of trash objects just to ensure
1050				 * that it won't come to any real object
1051				 * XXX: rather inefficient approach
1052				 */
1053				DL_APPEND (parser->trash_objs, nobj);
1054			}
1055			else {
1056				ucl_hash_replace (container, tobj, nobj);
1057				ucl_object_unref (tobj);
1058			}
1059
1060			break;
1061
1062		case UCL_DUPLICATE_REWRITE:
1063			/* We just rewrite old values regardless of priority */
1064			ucl_hash_replace (container, tobj, nobj);
1065			ucl_object_unref (tobj);
1066
1067			break;
1068
1069		case UCL_DUPLICATE_ERROR:
1070			ucl_create_err (&parser->err, "error while parsing %s: "
1071					"line: %d, column: %d: duplicate element for key '%s' "
1072					"has been found",
1073					parser->cur_file ? parser->cur_file : "<unknown>",
1074					parser->chunks->line, parser->chunks->column, nobj->key);
1075			return false;
1076
1077		case UCL_DUPLICATE_MERGE:
1078			/*
1079			 * Here we do have some old object so we just push it on top of objects stack
1080			 */
1081			if (tobj->type == UCL_OBJECT || tobj->type == UCL_ARRAY) {
1082				ucl_object_unref (nobj);
1083				nobj = tobj;
1084			}
1085			else {
1086				/* For other types we create implicit array as usual */
1087				ucl_parser_append_elt (parser, container, tobj, nobj);
1088			}
1089			break;
1090		}
1091	}
1092
1093	parser->stack->obj->value.ov = container;
1094	parser->cur_obj = nobj;
1095
1096	return true;
1097}
1098
1099/**
1100 * Parse a key in an object
1101 * @param parser
1102 * @param chunk
1103 * @param next_key
1104 * @param end_of_object
1105 * @return true if a key has been parsed
1106 */
1107static bool
1108ucl_parse_key (struct ucl_parser *parser, struct ucl_chunk *chunk,
1109		bool *next_key, bool *end_of_object)
1110{
1111	const unsigned char *p, *c = NULL, *end, *t;
1112	const char *key = NULL;
1113	bool got_quote = false, got_eq = false, got_semicolon = false,
1114			need_unescape = false, ucl_escape = false, var_expand = false,
1115			got_content = false, got_sep = false;
1116	ucl_object_t *nobj;
1117	ssize_t keylen;
1118
1119	p = chunk->pos;
1120
1121	if (*p == '.') {
1122		/* It is macro actually */
1123		ucl_chunk_skipc (chunk, p);
1124		parser->prev_state = parser->state;
1125		parser->state = UCL_STATE_MACRO_NAME;
1126		*end_of_object = false;
1127		return true;
1128	}
1129	while (p < chunk->end) {
1130		/*
1131		 * A key must start with alpha, number, '/' or '_' and end with space character
1132		 */
1133		if (c == NULL) {
1134			if (chunk->remain >= 2 && ucl_lex_is_comment (p[0], p[1])) {
1135				if (!ucl_skip_comments (parser)) {
1136					return false;
1137				}
1138				p = chunk->pos;
1139			}
1140			else if (ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE)) {
1141				ucl_chunk_skipc (chunk, p);
1142			}
1143			else if (ucl_test_character (*p, UCL_CHARACTER_KEY_START)) {
1144				/* The first symbol */
1145				c = p;
1146				ucl_chunk_skipc (chunk, p);
1147				got_content = true;
1148			}
1149			else if (*p == '"') {
1150				/* JSON style key */
1151				c = p + 1;
1152				got_quote = true;
1153				got_content = true;
1154				ucl_chunk_skipc (chunk, p);
1155			}
1156			else if (*p == '}') {
1157				/* We have actually end of an object */
1158				*end_of_object = true;
1159				return true;
1160			}
1161			else if (*p == '.') {
1162				ucl_chunk_skipc (chunk, p);
1163				parser->prev_state = parser->state;
1164				parser->state = UCL_STATE_MACRO_NAME;
1165				return true;
1166			}
1167			else {
1168				/* Invalid identifier */
1169				ucl_set_err (parser, UCL_ESYNTAX, "key must begin with a letter",
1170						&parser->err);
1171				return false;
1172			}
1173		}
1174		else {
1175			/* Parse the body of a key */
1176			if (!got_quote) {
1177				if (ucl_test_character (*p, UCL_CHARACTER_KEY)) {
1178					got_content = true;
1179					ucl_chunk_skipc (chunk, p);
1180				}
1181				else if (ucl_test_character (*p, UCL_CHARACTER_KEY_SEP)) {
1182					end = p;
1183					break;
1184				}
1185				else {
1186					ucl_set_err (parser, UCL_ESYNTAX, "invalid character in a key",
1187							&parser->err);
1188					return false;
1189				}
1190			}
1191			else {
1192				/* We need to parse json like quoted string */
1193				if (!ucl_lex_json_string (parser, chunk, &need_unescape, &ucl_escape, &var_expand)) {
1194					return false;
1195				}
1196				/* Always escape keys obtained via json */
1197				end = chunk->pos - 1;
1198				p = chunk->pos;
1199				break;
1200			}
1201		}
1202	}
1203
1204	if (p >= chunk->end && got_content) {
1205		ucl_set_err (parser, UCL_ESYNTAX, "unfinished key", &parser->err);
1206		return false;
1207	}
1208	else if (!got_content) {
1209		return true;
1210	}
1211	*end_of_object = false;
1212	/* We are now at the end of the key, need to parse the rest */
1213	while (p < chunk->end) {
1214		if (ucl_test_character (*p, UCL_CHARACTER_WHITESPACE)) {
1215			ucl_chunk_skipc (chunk, p);
1216		}
1217		else if (*p == '=') {
1218			if (!got_eq && !got_semicolon) {
1219				ucl_chunk_skipc (chunk, p);
1220				got_eq = true;
1221			}
1222			else {
1223				ucl_set_err (parser, UCL_ESYNTAX, "unexpected '=' character",
1224						&parser->err);
1225				return false;
1226			}
1227		}
1228		else if (*p == ':') {
1229			if (!got_eq && !got_semicolon) {
1230				ucl_chunk_skipc (chunk, p);
1231				got_semicolon = true;
1232			}
1233			else {
1234				ucl_set_err (parser, UCL_ESYNTAX, "unexpected ':' character",
1235						&parser->err);
1236				return false;
1237			}
1238		}
1239		else if (chunk->remain >= 2 && ucl_lex_is_comment (p[0], p[1])) {
1240			/* Check for comment */
1241			if (!ucl_skip_comments (parser)) {
1242				return false;
1243			}
1244			p = chunk->pos;
1245		}
1246		else {
1247			/* Start value */
1248			break;
1249		}
1250	}
1251
1252	if (p >= chunk->end && got_content) {
1253		ucl_set_err (parser, UCL_ESYNTAX, "unfinished key", &parser->err);
1254		return false;
1255	}
1256
1257	got_sep = got_semicolon || got_eq;
1258
1259	if (!got_sep) {
1260		/*
1261		 * Maybe we have more keys nested, so search for termination character.
1262		 * Possible choices:
1263		 * 1) key1 key2 ... keyN [:=] value <- we treat that as error
1264		 * 2) key1 ... keyN {} or [] <- we treat that as nested objects
1265		 * 3) key1 value[;,\n] <- we treat that as linear object
1266		 */
1267		t = p;
1268		*next_key = false;
1269		while (ucl_test_character (*t, UCL_CHARACTER_WHITESPACE)) {
1270			t ++;
1271		}
1272		/* Check first non-space character after a key */
1273		if (*t != '{' && *t != '[') {
1274			while (t < chunk->end) {
1275				if (*t == ',' || *t == ';' || *t == '\n' || *t == '\r') {
1276					break;
1277				}
1278				else if (*t == '{' || *t == '[') {
1279					*next_key = true;
1280					break;
1281				}
1282				t ++;
1283			}
1284		}
1285	}
1286
1287	/* Create a new object */
1288	nobj = ucl_object_new_full (UCL_NULL, parser->chunks->priority);
1289	keylen = ucl_copy_or_store_ptr (parser, c, &nobj->trash_stack[UCL_TRASH_KEY],
1290			&key, end - c, need_unescape, parser->flags & UCL_PARSER_KEY_LOWERCASE, false);
1291	if (keylen == -1) {
1292		ucl_object_unref (nobj);
1293		return false;
1294	}
1295	else if (keylen == 0) {
1296		ucl_set_err (parser, UCL_ESYNTAX, "empty keys are not allowed", &parser->err);
1297		ucl_object_unref (nobj);
1298		return false;
1299	}
1300
1301	nobj->key = key;
1302	nobj->keylen = keylen;
1303
1304	if (!ucl_parser_process_object_element (parser, nobj)) {
1305		return false;
1306	}
1307
1308	if (ucl_escape) {
1309		nobj->flags |= UCL_OBJECT_NEED_KEY_ESCAPE;
1310	}
1311
1312
1313	return true;
1314}
1315
1316/**
1317 * Parse a cl string
1318 * @param parser
1319 * @param chunk
1320 * @param var_expand
1321 * @param need_unescape
1322 * @return true if a key has been parsed
1323 */
1324static bool
1325ucl_parse_string_value (struct ucl_parser *parser,
1326		struct ucl_chunk *chunk, bool *var_expand, bool *need_unescape)
1327{
1328	const unsigned char *p;
1329	enum {
1330		UCL_BRACE_ROUND = 0,
1331		UCL_BRACE_SQUARE,
1332		UCL_BRACE_FIGURE
1333	};
1334	int braces[3][2] = {{0, 0}, {0, 0}, {0, 0}};
1335
1336	p = chunk->pos;
1337
1338	while (p < chunk->end) {
1339
1340		/* Skip pairs of figure braces */
1341		if (*p == '{') {
1342			braces[UCL_BRACE_FIGURE][0] ++;
1343		}
1344		else if (*p == '}') {
1345			braces[UCL_BRACE_FIGURE][1] ++;
1346			if (braces[UCL_BRACE_FIGURE][1] <= braces[UCL_BRACE_FIGURE][0]) {
1347				/* This is not a termination symbol, continue */
1348				ucl_chunk_skipc (chunk, p);
1349				continue;
1350			}
1351		}
1352		/* Skip pairs of square braces */
1353		else if (*p == '[') {
1354			braces[UCL_BRACE_SQUARE][0] ++;
1355		}
1356		else if (*p == ']') {
1357			braces[UCL_BRACE_SQUARE][1] ++;
1358			if (braces[UCL_BRACE_SQUARE][1] <= braces[UCL_BRACE_SQUARE][0]) {
1359				/* This is not a termination symbol, continue */
1360				ucl_chunk_skipc (chunk, p);
1361				continue;
1362			}
1363		}
1364		else if (*p == '$') {
1365			*var_expand = true;
1366		}
1367		else if (*p == '\\') {
1368			*need_unescape = true;
1369			ucl_chunk_skipc (chunk, p);
1370			if (p < chunk->end) {
1371				ucl_chunk_skipc (chunk, p);
1372			}
1373			continue;
1374		}
1375
1376		if (ucl_lex_is_atom_end (*p) || (chunk->remain >= 2 && ucl_lex_is_comment (p[0], p[1]))) {
1377			break;
1378		}
1379		ucl_chunk_skipc (chunk, p);
1380	}
1381
1382	return true;
1383}
1384
1385/**
1386 * Parse multiline string ending with \n{term}\n
1387 * @param parser
1388 * @param chunk
1389 * @param term
1390 * @param term_len
1391 * @param beg
1392 * @param var_expand
1393 * @return size of multiline string or 0 in case of error
1394 */
1395static int
1396ucl_parse_multiline_string (struct ucl_parser *parser,
1397		struct ucl_chunk *chunk, const unsigned char *term,
1398		int term_len, unsigned char const **beg,
1399		bool *var_expand)
1400{
1401	const unsigned char *p, *c, *tend;
1402	bool newline = false;
1403	int len = 0;
1404
1405	p = chunk->pos;
1406
1407	c = p;
1408
1409	while (p < chunk->end) {
1410		if (newline) {
1411			if (chunk->end - p < term_len) {
1412				return 0;
1413			}
1414			else if (memcmp (p, term, term_len) == 0) {
1415				tend = p + term_len;
1416				if (*tend != '\n' && *tend != ';' && *tend != ',') {
1417					/* Incomplete terminator */
1418					ucl_chunk_skipc (chunk, p);
1419					continue;
1420				}
1421				len = p - c;
1422				chunk->remain -= term_len;
1423				chunk->pos = p + term_len;
1424				chunk->column = term_len;
1425				*beg = c;
1426				break;
1427			}
1428		}
1429		if (*p == '\n') {
1430			newline = true;
1431		}
1432		else {
1433			if (*p == '$') {
1434				*var_expand = true;
1435			}
1436			newline = false;
1437		}
1438		ucl_chunk_skipc (chunk, p);
1439	}
1440
1441	return len;
1442}
1443
1444static inline ucl_object_t*
1445ucl_parser_get_container (struct ucl_parser *parser)
1446{
1447	ucl_object_t *t, *obj = NULL;
1448
1449	if (parser == NULL || parser->stack == NULL || parser->stack->obj == NULL) {
1450		return NULL;
1451	}
1452
1453	if (parser->stack->obj->type == UCL_ARRAY) {
1454		/* Object must be allocated */
1455		obj = ucl_object_new_full (UCL_NULL, parser->chunks->priority);
1456		t = parser->stack->obj;
1457
1458		if (!ucl_array_append (t, obj)) {
1459			ucl_object_unref (obj);
1460			return NULL;
1461		}
1462
1463		parser->cur_obj = obj;
1464	}
1465	else {
1466		/* Object has been already allocated */
1467		obj = parser->cur_obj;
1468	}
1469
1470	return obj;
1471}
1472
1473/**
1474 * Handle value data
1475 * @param parser
1476 * @param chunk
1477 * @return
1478 */
1479static bool
1480ucl_parse_value (struct ucl_parser *parser, struct ucl_chunk *chunk)
1481{
1482	const unsigned char *p, *c;
1483	ucl_object_t *obj = NULL;
1484	unsigned int stripped_spaces;
1485	int str_len;
1486	bool need_unescape = false, ucl_escape = false, var_expand = false;
1487
1488	p = chunk->pos;
1489
1490	/* Skip any spaces and comments */
1491	if (ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE) ||
1492			(chunk->remain >= 2 && ucl_lex_is_comment (p[0], p[1]))) {
1493		while (p < chunk->end && ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE)) {
1494			ucl_chunk_skipc (chunk, p);
1495		}
1496		if (!ucl_skip_comments (parser)) {
1497			return false;
1498		}
1499		p = chunk->pos;
1500	}
1501
1502	while (p < chunk->end) {
1503		c = p;
1504		switch (*p) {
1505		case '"':
1506			ucl_chunk_skipc (chunk, p);
1507
1508			if (!ucl_lex_json_string (parser, chunk, &need_unescape, &ucl_escape,
1509					&var_expand)) {
1510				return false;
1511			}
1512
1513			obj = ucl_parser_get_container (parser);
1514			str_len = chunk->pos - c - 2;
1515			obj->type = UCL_STRING;
1516			if ((str_len = ucl_copy_or_store_ptr (parser, c + 1,
1517					&obj->trash_stack[UCL_TRASH_VALUE],
1518					&obj->value.sv, str_len, need_unescape, false,
1519					var_expand)) == -1) {
1520				return false;
1521			}
1522			obj->len = str_len;
1523
1524			parser->state = UCL_STATE_AFTER_VALUE;
1525			p = chunk->pos;
1526
1527			return true;
1528			break;
1529		case '{':
1530			obj = ucl_parser_get_container (parser);
1531			/* We have a new object */
1532			obj = ucl_parser_add_container (obj, parser, false, parser->stack->level);
1533			if (obj == NULL) {
1534				return false;
1535			}
1536
1537			ucl_chunk_skipc (chunk, p);
1538
1539			return true;
1540			break;
1541		case '[':
1542			obj = ucl_parser_get_container (parser);
1543			/* We have a new array */
1544			obj = ucl_parser_add_container (obj, parser, true, parser->stack->level);
1545			if (obj == NULL) {
1546				return false;
1547			}
1548
1549			ucl_chunk_skipc (chunk, p);
1550
1551			return true;
1552			break;
1553		case ']':
1554			/* We have the array ending */
1555			if (parser->stack && parser->stack->obj->type == UCL_ARRAY) {
1556				parser->state = UCL_STATE_AFTER_VALUE;
1557				return true;
1558			}
1559			else {
1560				goto parse_string;
1561			}
1562			break;
1563		case '<':
1564			obj = ucl_parser_get_container (parser);
1565			/* We have something like multiline value, which must be <<[A-Z]+\n */
1566			if (chunk->end - p > 3) {
1567				if (memcmp (p, "<<", 2) == 0) {
1568					p += 2;
1569					/* We allow only uppercase characters in multiline definitions */
1570					while (p < chunk->end && *p >= 'A' && *p <= 'Z') {
1571						p ++;
1572					}
1573					if (*p =='\n') {
1574						/* Set chunk positions and start multiline parsing */
1575						c += 2;
1576						chunk->remain -= p - c;
1577						chunk->pos = p + 1;
1578						chunk->column = 0;
1579						chunk->line ++;
1580						if ((str_len = ucl_parse_multiline_string (parser, chunk, c,
1581								p - c, &c, &var_expand)) == 0) {
1582							ucl_set_err (parser, UCL_ESYNTAX,
1583									"unterminated multiline value", &parser->err);
1584							return false;
1585						}
1586
1587						obj->type = UCL_STRING;
1588						obj->flags |= UCL_OBJECT_MULTILINE;
1589						if ((str_len = ucl_copy_or_store_ptr (parser, c,
1590								&obj->trash_stack[UCL_TRASH_VALUE],
1591								&obj->value.sv, str_len - 1, false,
1592								false, var_expand)) == -1) {
1593							return false;
1594						}
1595						obj->len = str_len;
1596
1597						parser->state = UCL_STATE_AFTER_VALUE;
1598
1599						return true;
1600					}
1601				}
1602			}
1603			/* Fallback to ordinary strings */
1604		default:
1605parse_string:
1606			if (obj == NULL) {
1607				obj = ucl_parser_get_container (parser);
1608			}
1609
1610			/* Parse atom */
1611			if (ucl_test_character (*p, UCL_CHARACTER_VALUE_DIGIT_START)) {
1612				if (!ucl_lex_number (parser, chunk, obj)) {
1613					if (parser->state == UCL_STATE_ERROR) {
1614						return false;
1615					}
1616				}
1617				else {
1618					parser->state = UCL_STATE_AFTER_VALUE;
1619					return true;
1620				}
1621				/* Fallback to normal string */
1622			}
1623
1624			if (!ucl_parse_string_value (parser, chunk, &var_expand,
1625					&need_unescape)) {
1626				return false;
1627			}
1628			/* Cut trailing spaces */
1629			stripped_spaces = 0;
1630			while (ucl_test_character (*(chunk->pos - 1 - stripped_spaces),
1631					UCL_CHARACTER_WHITESPACE)) {
1632				stripped_spaces ++;
1633			}
1634			str_len = chunk->pos - c - stripped_spaces;
1635			if (str_len <= 0) {
1636				ucl_set_err (parser, UCL_ESYNTAX, "string value must not be empty",
1637						&parser->err);
1638				return false;
1639			}
1640			else if (str_len == 4 && memcmp (c, "null", 4) == 0) {
1641				obj->len = 0;
1642				obj->type = UCL_NULL;
1643			}
1644			else if (!ucl_maybe_parse_boolean (obj, c, str_len)) {
1645				obj->type = UCL_STRING;
1646				if ((str_len = ucl_copy_or_store_ptr (parser, c,
1647						&obj->trash_stack[UCL_TRASH_VALUE],
1648						&obj->value.sv, str_len, need_unescape,
1649						false, var_expand)) == -1) {
1650					return false;
1651				}
1652				obj->len = str_len;
1653			}
1654			parser->state = UCL_STATE_AFTER_VALUE;
1655			p = chunk->pos;
1656
1657			return true;
1658			break;
1659		}
1660	}
1661
1662	return true;
1663}
1664
1665/**
1666 * Handle after value data
1667 * @param parser
1668 * @param chunk
1669 * @return
1670 */
1671static bool
1672ucl_parse_after_value (struct ucl_parser *parser, struct ucl_chunk *chunk)
1673{
1674	const unsigned char *p;
1675	bool got_sep = false;
1676	struct ucl_stack *st;
1677
1678	p = chunk->pos;
1679
1680	while (p < chunk->end) {
1681		if (ucl_test_character (*p, UCL_CHARACTER_WHITESPACE)) {
1682			/* Skip whitespaces */
1683			ucl_chunk_skipc (chunk, p);
1684		}
1685		else if (chunk->remain >= 2 && ucl_lex_is_comment (p[0], p[1])) {
1686			/* Skip comment */
1687			if (!ucl_skip_comments (parser)) {
1688				return false;
1689			}
1690			/* Treat comment as a separator */
1691			got_sep = true;
1692			p = chunk->pos;
1693		}
1694		else if (ucl_test_character (*p, UCL_CHARACTER_VALUE_END)) {
1695			if (*p == '}' || *p == ']') {
1696				if (parser->stack == NULL) {
1697					ucl_set_err (parser, UCL_ESYNTAX,
1698							"end of array or object detected without corresponding start",
1699							&parser->err);
1700					return false;
1701				}
1702				if ((*p == '}' && parser->stack->obj->type == UCL_OBJECT) ||
1703						(*p == ']' && parser->stack->obj->type == UCL_ARRAY)) {
1704
1705					/* Pop all nested objects from a stack */
1706					st = parser->stack;
1707					parser->stack = st->next;
1708					UCL_FREE (sizeof (struct ucl_stack), st);
1709
1710					while (parser->stack != NULL) {
1711						st = parser->stack;
1712						if (st->next == NULL || st->next->level == st->level) {
1713							break;
1714						}
1715						parser->stack = st->next;
1716						UCL_FREE (sizeof (struct ucl_stack), st);
1717					}
1718				}
1719				else {
1720					ucl_set_err (parser, UCL_ESYNTAX,
1721							"unexpected terminating symbol detected",
1722							&parser->err);
1723					return false;
1724				}
1725
1726				if (parser->stack == NULL) {
1727					/* Ignore everything after a top object */
1728					return true;
1729				}
1730				else {
1731					ucl_chunk_skipc (chunk, p);
1732				}
1733				got_sep = true;
1734			}
1735			else {
1736				/* Got a separator */
1737				got_sep = true;
1738				ucl_chunk_skipc (chunk, p);
1739			}
1740		}
1741		else {
1742			/* Anything else */
1743			if (!got_sep) {
1744				ucl_set_err (parser, UCL_ESYNTAX, "delimiter is missing",
1745						&parser->err);
1746				return false;
1747			}
1748			return true;
1749		}
1750	}
1751
1752	return true;
1753}
1754
1755/**
1756 * Handle macro data
1757 * @param parser
1758 * @param chunk
1759 * @param marco
1760 * @param macro_start
1761 * @param macro_len
1762 * @return
1763 */
1764static bool
1765ucl_parse_macro_value (struct ucl_parser *parser,
1766		struct ucl_chunk *chunk, struct ucl_macro *macro,
1767		unsigned char const **macro_start, size_t *macro_len)
1768{
1769	const unsigned char *p, *c;
1770	bool need_unescape = false, ucl_escape = false, var_expand = false;
1771
1772	p = chunk->pos;
1773
1774	switch (*p) {
1775	case '"':
1776		/* We have macro value encoded in quotes */
1777		c = p;
1778		ucl_chunk_skipc (chunk, p);
1779		if (!ucl_lex_json_string (parser, chunk, &need_unescape, &ucl_escape, &var_expand)) {
1780			return false;
1781		}
1782
1783		*macro_start = c + 1;
1784		*macro_len = chunk->pos - c - 2;
1785		p = chunk->pos;
1786		break;
1787	case '{':
1788		/* We got a multiline macro body */
1789		ucl_chunk_skipc (chunk, p);
1790		/* Skip spaces at the beginning */
1791		while (p < chunk->end) {
1792			if (ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE)) {
1793				ucl_chunk_skipc (chunk, p);
1794			}
1795			else {
1796				break;
1797			}
1798		}
1799		c = p;
1800		while (p < chunk->end) {
1801			if (*p == '}') {
1802				break;
1803			}
1804			ucl_chunk_skipc (chunk, p);
1805		}
1806		*macro_start = c;
1807		*macro_len = p - c;
1808		ucl_chunk_skipc (chunk, p);
1809		break;
1810	default:
1811		/* Macro is not enclosed in quotes or braces */
1812		c = p;
1813		while (p < chunk->end) {
1814			if (ucl_lex_is_atom_end (*p)) {
1815				break;
1816			}
1817			ucl_chunk_skipc (chunk, p);
1818		}
1819		*macro_start = c;
1820		*macro_len = p - c;
1821		break;
1822	}
1823
1824	/* We are at the end of a macro */
1825	/* Skip ';' and space characters and return to previous state */
1826	while (p < chunk->end) {
1827		if (!ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE) && *p != ';') {
1828			break;
1829		}
1830		ucl_chunk_skipc (chunk, p);
1831	}
1832	return true;
1833}
1834
1835/**
1836 * Parse macro arguments as UCL object
1837 * @param parser parser structure
1838 * @param chunk the current data chunk
1839 * @return
1840 */
1841static ucl_object_t *
1842ucl_parse_macro_arguments (struct ucl_parser *parser,
1843		struct ucl_chunk *chunk)
1844{
1845	ucl_object_t *res = NULL;
1846	struct ucl_parser *params_parser;
1847	int obraces = 1, ebraces = 0, state = 0;
1848	const unsigned char *p, *c;
1849	size_t args_len = 0;
1850	struct ucl_parser_saved_state saved;
1851
1852	saved.column = chunk->column;
1853	saved.line = chunk->line;
1854	saved.pos = chunk->pos;
1855	saved.remain = chunk->remain;
1856	p = chunk->pos;
1857
1858	if (*p != '(' || chunk->remain < 2) {
1859		return NULL;
1860	}
1861
1862	/* Set begin and start */
1863	ucl_chunk_skipc (chunk, p);
1864	c = p;
1865
1866	while ((p) < (chunk)->end) {
1867		switch (state) {
1868		case 0:
1869			/* Parse symbols and check for '(', ')' and '"' */
1870			if (*p == '(') {
1871				obraces ++;
1872			}
1873			else if (*p == ')') {
1874				ebraces ++;
1875			}
1876			else if (*p == '"') {
1877				state = 1;
1878			}
1879			/* Check pairing */
1880			if (obraces == ebraces) {
1881				state = 99;
1882			}
1883			else {
1884				args_len ++;
1885			}
1886			/* Check overflow */
1887			if (chunk->remain == 0) {
1888				goto restore_chunk;
1889			}
1890			ucl_chunk_skipc (chunk, p);
1891			break;
1892		case 1:
1893			/* We have quote character, so skip all but quotes */
1894			if (*p == '"' && *(p - 1) != '\\') {
1895				state = 0;
1896			}
1897			if (chunk->remain == 0) {
1898				goto restore_chunk;
1899			}
1900			args_len ++;
1901			ucl_chunk_skipc (chunk, p);
1902			break;
1903		case 99:
1904			/*
1905			 * We have read the full body of arguments, so we need to parse and set
1906			 * object from that
1907			 */
1908			params_parser = ucl_parser_new (parser->flags);
1909			if (!ucl_parser_add_chunk (params_parser, c, args_len)) {
1910				ucl_set_err (parser, UCL_ESYNTAX, "macro arguments parsing error",
1911						&parser->err);
1912			}
1913			else {
1914				res = ucl_parser_get_object (params_parser);
1915			}
1916			ucl_parser_free (params_parser);
1917
1918			return res;
1919
1920			break;
1921		}
1922	}
1923
1924	return res;
1925
1926restore_chunk:
1927	chunk->column = saved.column;
1928	chunk->line = saved.line;
1929	chunk->pos = saved.pos;
1930	chunk->remain = saved.remain;
1931
1932	return NULL;
1933}
1934
1935#define SKIP_SPACES_COMMENTS(parser, chunk, p) do {								\
1936	while ((p) < (chunk)->end) {												\
1937		if (!ucl_test_character (*(p), UCL_CHARACTER_WHITESPACE_UNSAFE)) {		\
1938			if ((chunk)->remain >= 2 && ucl_lex_is_comment ((p)[0], (p)[1])) {	\
1939				if (!ucl_skip_comments (parser)) {								\
1940					return false;												\
1941				}																\
1942				p = (chunk)->pos;												\
1943			}																	\
1944			break;																\
1945		}																		\
1946		ucl_chunk_skipc (chunk, p);												\
1947	}																			\
1948} while(0)
1949
1950/**
1951 * Handle the main states of rcl parser
1952 * @param parser parser structure
1953 * @return true if chunk has been parsed and false in case of error
1954 */
1955static bool
1956ucl_state_machine (struct ucl_parser *parser)
1957{
1958	ucl_object_t *obj, *macro_args;
1959	struct ucl_chunk *chunk = parser->chunks;
1960	const unsigned char *p, *c = NULL, *macro_start = NULL;
1961	unsigned char *macro_escaped;
1962	size_t macro_len = 0;
1963	struct ucl_macro *macro = NULL;
1964	bool next_key = false, end_of_object = false, ret;
1965
1966	if (parser->top_obj == NULL) {
1967		parser->state = UCL_STATE_INIT;
1968	}
1969
1970	p = chunk->pos;
1971	while (chunk->pos < chunk->end) {
1972		switch (parser->state) {
1973		case UCL_STATE_INIT:
1974			/*
1975			 * At the init state we can either go to the parse array or object
1976			 * if we got [ or { correspondingly or can just treat new data as
1977			 * a key of newly created object
1978			 */
1979			if (!ucl_skip_comments (parser)) {
1980				parser->prev_state = parser->state;
1981				parser->state = UCL_STATE_ERROR;
1982				return false;
1983			}
1984			else {
1985				/* Skip any spaces */
1986				while (p < chunk->end && ucl_test_character (*p,
1987						UCL_CHARACTER_WHITESPACE_UNSAFE)) {
1988					ucl_chunk_skipc (chunk, p);
1989				}
1990
1991				p = chunk->pos;
1992
1993				if (*p == '[') {
1994					parser->state = UCL_STATE_VALUE;
1995					ucl_chunk_skipc (chunk, p);
1996				}
1997				else {
1998					parser->state = UCL_STATE_KEY;
1999					if (*p == '{') {
2000						ucl_chunk_skipc (chunk, p);
2001					}
2002				}
2003
2004				if (parser->top_obj == NULL) {
2005					if (parser->state == UCL_STATE_VALUE) {
2006						obj = ucl_parser_add_container (NULL, parser, true, 0);
2007					}
2008					else {
2009						obj = ucl_parser_add_container (NULL, parser, false, 0);
2010					}
2011
2012					if (obj == NULL) {
2013						return false;
2014					}
2015
2016					parser->top_obj = obj;
2017					parser->cur_obj = obj;
2018				}
2019
2020			}
2021			break;
2022		case UCL_STATE_KEY:
2023			/* Skip any spaces */
2024			while (p < chunk->end && ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE)) {
2025				ucl_chunk_skipc (chunk, p);
2026			}
2027			if (*p == '}') {
2028				/* We have the end of an object */
2029				parser->state = UCL_STATE_AFTER_VALUE;
2030				continue;
2031			}
2032			if (parser->stack == NULL) {
2033				/* No objects are on stack, but we want to parse a key */
2034				ucl_set_err (parser, UCL_ESYNTAX, "top object is finished but the parser "
2035						"expects a key", &parser->err);
2036				parser->prev_state = parser->state;
2037				parser->state = UCL_STATE_ERROR;
2038				return false;
2039			}
2040			if (!ucl_parse_key (parser, chunk, &next_key, &end_of_object)) {
2041				parser->prev_state = parser->state;
2042				parser->state = UCL_STATE_ERROR;
2043				return false;
2044			}
2045			if (end_of_object) {
2046				p = chunk->pos;
2047				parser->state = UCL_STATE_AFTER_VALUE;
2048				continue;
2049			}
2050			else if (parser->state != UCL_STATE_MACRO_NAME) {
2051				if (next_key && parser->stack->obj->type == UCL_OBJECT) {
2052					/* Parse more keys and nest objects accordingly */
2053					obj = ucl_parser_add_container (parser->cur_obj, parser, false,
2054							parser->stack->level + 1);
2055					if (obj == NULL) {
2056						return false;
2057					}
2058				}
2059				else {
2060					parser->state = UCL_STATE_VALUE;
2061				}
2062			}
2063			else {
2064				c = chunk->pos;
2065			}
2066			p = chunk->pos;
2067			break;
2068		case UCL_STATE_VALUE:
2069			/* We need to check what we do have */
2070			if (!ucl_parse_value (parser, chunk)) {
2071				parser->prev_state = parser->state;
2072				parser->state = UCL_STATE_ERROR;
2073				return false;
2074			}
2075			/* State is set in ucl_parse_value call */
2076			p = chunk->pos;
2077			break;
2078		case UCL_STATE_AFTER_VALUE:
2079			if (!ucl_parse_after_value (parser, chunk)) {
2080				parser->prev_state = parser->state;
2081				parser->state = UCL_STATE_ERROR;
2082				return false;
2083			}
2084
2085			if (parser->stack != NULL) {
2086				if (parser->stack->obj->type == UCL_OBJECT) {
2087					parser->state = UCL_STATE_KEY;
2088				}
2089				else {
2090					/* Array */
2091					parser->state = UCL_STATE_VALUE;
2092				}
2093			}
2094			else {
2095				/* Skip everything at the end */
2096				return true;
2097			}
2098			p = chunk->pos;
2099			break;
2100		case UCL_STATE_MACRO_NAME:
2101			if (!ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE) &&
2102					*p != '(') {
2103				ucl_chunk_skipc (chunk, p);
2104			}
2105			else {
2106				if (p - c > 0) {
2107					/* We got macro name */
2108					macro_len = (size_t) (p - c);
2109					HASH_FIND (hh, parser->macroes, c, macro_len, macro);
2110					if (macro == NULL) {
2111						ucl_create_err (&parser->err,
2112								"error on line %d at column %d: "
2113										"unknown macro: '%.*s', character: '%c'",
2114								chunk->line,
2115								chunk->column,
2116								(int) (p - c),
2117								c,
2118								*chunk->pos);
2119						parser->state = UCL_STATE_ERROR;
2120						return false;
2121					}
2122					/* Now we need to skip all spaces */
2123					SKIP_SPACES_COMMENTS(parser, chunk, p);
2124					parser->state = UCL_STATE_MACRO;
2125				}
2126				else {
2127					/* We have invalid macro name */
2128					ucl_create_err (&parser->err,
2129							"error on line %d at column %d: invalid macro name",
2130							chunk->line,
2131							chunk->column);
2132					parser->state = UCL_STATE_ERROR;
2133					return false;
2134				}
2135			}
2136			break;
2137		case UCL_STATE_MACRO:
2138			if (*chunk->pos == '(') {
2139				macro_args = ucl_parse_macro_arguments (parser, chunk);
2140				p = chunk->pos;
2141				if (macro_args) {
2142					SKIP_SPACES_COMMENTS(parser, chunk, p);
2143				}
2144			}
2145			else {
2146				macro_args = NULL;
2147			}
2148			if (!ucl_parse_macro_value (parser, chunk, macro,
2149					&macro_start, &macro_len)) {
2150				parser->prev_state = parser->state;
2151				parser->state = UCL_STATE_ERROR;
2152				return false;
2153			}
2154			macro_len = ucl_expand_variable (parser, &macro_escaped,
2155					macro_start, macro_len);
2156			parser->state = parser->prev_state;
2157			if (macro_escaped == NULL) {
2158				if (macro->is_context) {
2159					ret = macro->h.context_handler (macro_start, macro_len,
2160							macro_args,
2161							parser->top_obj,
2162							macro->ud);
2163				}
2164				else {
2165					ret = macro->h.handler (macro_start, macro_len, macro_args,
2166							macro->ud);
2167				}
2168			}
2169			else {
2170				if (macro->is_context) {
2171					ret = macro->h.context_handler (macro_escaped, macro_len,
2172							macro_args,
2173							parser->top_obj,
2174							macro->ud);
2175				}
2176				else {
2177					ret = macro->h.handler (macro_escaped, macro_len, macro_args,
2178						macro->ud);
2179				}
2180
2181				UCL_FREE (macro_len + 1, macro_escaped);
2182			}
2183
2184			/*
2185			 * Chunk can be modified within macro handler
2186			 */
2187			chunk = parser->chunks;
2188			p = chunk->pos;
2189			if (macro_args) {
2190				ucl_object_unref (macro_args);
2191			}
2192			if (!ret) {
2193				return false;
2194			}
2195			break;
2196		default:
2197			/* TODO: add all states */
2198			ucl_set_err (parser, UCL_EINTERNAL,
2199					"internal error: parser is in an unknown state", &parser->err);
2200			parser->state = UCL_STATE_ERROR;
2201			return false;
2202		}
2203	}
2204
2205	return true;
2206}
2207
2208struct ucl_parser*
2209ucl_parser_new (int flags)
2210{
2211	struct ucl_parser *new;
2212
2213	new = UCL_ALLOC (sizeof (struct ucl_parser));
2214	if (new == NULL) {
2215		return NULL;
2216	}
2217
2218	memset (new, 0, sizeof (struct ucl_parser));
2219
2220	ucl_parser_register_macro (new, "include", ucl_include_handler, new);
2221	ucl_parser_register_macro (new, "try_include", ucl_try_include_handler, new);
2222	ucl_parser_register_macro (new, "includes", ucl_includes_handler, new);
2223	ucl_parser_register_macro (new, "priority", ucl_priority_handler, new);
2224	ucl_parser_register_macro (new, "load", ucl_load_handler, new);
2225	ucl_parser_register_context_macro (new, "inherit", ucl_inherit_handler, new);
2226
2227	new->flags = flags;
2228	new->includepaths = NULL;
2229
2230	/* Initial assumption about filevars */
2231	ucl_parser_set_filevars (new, NULL, false);
2232
2233	return new;
2234}
2235
2236bool
2237ucl_parser_set_default_priority (struct ucl_parser *parser, unsigned prio)
2238{
2239	if (parser == NULL) {
2240		return false;
2241	}
2242
2243	parser->default_priority = prio;
2244
2245	return true;
2246}
2247
2248void
2249ucl_parser_register_macro (struct ucl_parser *parser, const char *macro,
2250		ucl_macro_handler handler, void* ud)
2251{
2252	struct ucl_macro *new;
2253
2254	if (macro == NULL || handler == NULL) {
2255		return;
2256	}
2257
2258	new = UCL_ALLOC (sizeof (struct ucl_macro));
2259	if (new == NULL) {
2260		return;
2261	}
2262
2263	memset (new, 0, sizeof (struct ucl_macro));
2264	new->h.handler = handler;
2265	new->name = strdup (macro);
2266	new->ud = ud;
2267	HASH_ADD_KEYPTR (hh, parser->macroes, new->name, strlen (new->name), new);
2268}
2269
2270void
2271ucl_parser_register_context_macro (struct ucl_parser *parser, const char *macro,
2272		ucl_context_macro_handler handler, void* ud)
2273{
2274	struct ucl_macro *new;
2275
2276	if (macro == NULL || handler == NULL) {
2277		return;
2278	}
2279
2280	new = UCL_ALLOC (sizeof (struct ucl_macro));
2281	if (new == NULL) {
2282		return;
2283	}
2284
2285	memset (new, 0, sizeof (struct ucl_macro));
2286	new->h.context_handler = handler;
2287	new->name = strdup (macro);
2288	new->ud = ud;
2289	new->is_context = true;
2290	HASH_ADD_KEYPTR (hh, parser->macroes, new->name, strlen (new->name), new);
2291}
2292
2293void
2294ucl_parser_register_variable (struct ucl_parser *parser, const char *var,
2295		const char *value)
2296{
2297	struct ucl_variable *new = NULL, *cur;
2298
2299	if (var == NULL) {
2300		return;
2301	}
2302
2303	/* Find whether a variable already exists */
2304	LL_FOREACH (parser->variables, cur) {
2305		if (strcmp (cur->var, var) == 0) {
2306			new = cur;
2307			break;
2308		}
2309	}
2310
2311	if (value == NULL) {
2312
2313		if (new != NULL) {
2314			/* Remove variable */
2315			DL_DELETE (parser->variables, new);
2316			free (new->var);
2317			free (new->value);
2318			UCL_FREE (sizeof (struct ucl_variable), new);
2319		}
2320		else {
2321			/* Do nothing */
2322			return;
2323		}
2324	}
2325	else {
2326		if (new == NULL) {
2327			new = UCL_ALLOC (sizeof (struct ucl_variable));
2328			if (new == NULL) {
2329				return;
2330			}
2331			memset (new, 0, sizeof (struct ucl_variable));
2332			new->var = strdup (var);
2333			new->var_len = strlen (var);
2334			new->value = strdup (value);
2335			new->value_len = strlen (value);
2336
2337			DL_APPEND (parser->variables, new);
2338		}
2339		else {
2340			free (new->value);
2341			new->value = strdup (value);
2342			new->value_len = strlen (value);
2343		}
2344	}
2345}
2346
2347void
2348ucl_parser_set_variables_handler (struct ucl_parser *parser,
2349		ucl_variable_handler handler, void *ud)
2350{
2351	parser->var_handler = handler;
2352	parser->var_data = ud;
2353}
2354
2355bool
2356ucl_parser_add_chunk_full (struct ucl_parser *parser, const unsigned char *data,
2357		size_t len, unsigned priority, enum ucl_duplicate_strategy strat,
2358		enum ucl_parse_type parse_type)
2359{
2360	struct ucl_chunk *chunk;
2361
2362	if (parser == NULL) {
2363		return false;
2364	}
2365
2366	if (data == NULL) {
2367		ucl_create_err (&parser->err, "invalid chunk added");
2368		return false;
2369	}
2370	if (len == 0) {
2371		parser->top_obj = ucl_object_new_full (UCL_OBJECT, priority);
2372		return true;
2373	}
2374	if (parser->state != UCL_STATE_ERROR) {
2375		chunk = UCL_ALLOC (sizeof (struct ucl_chunk));
2376		if (chunk == NULL) {
2377			ucl_create_err (&parser->err, "cannot allocate chunk structure");
2378			return false;
2379		}
2380		chunk->begin = data;
2381		chunk->remain = len;
2382		chunk->pos = chunk->begin;
2383		chunk->end = chunk->begin + len;
2384		chunk->line = 1;
2385		chunk->column = 0;
2386		chunk->priority = priority;
2387		chunk->strategy = strat;
2388		chunk->parse_type = parse_type;
2389		LL_PREPEND (parser->chunks, chunk);
2390		parser->recursion ++;
2391
2392		if (parser->recursion > UCL_MAX_RECURSION) {
2393			ucl_create_err (&parser->err, "maximum include nesting limit is reached: %d",
2394					parser->recursion);
2395			return false;
2396		}
2397
2398		switch (parse_type) {
2399		default:
2400		case UCL_PARSE_UCL:
2401			return ucl_state_machine (parser);
2402		case UCL_PARSE_MSGPACK:
2403			return ucl_parse_msgpack (parser);
2404		}
2405	}
2406
2407	ucl_create_err (&parser->err, "a parser is in an invalid state");
2408
2409	return false;
2410}
2411
2412bool
2413ucl_parser_add_chunk_priority (struct ucl_parser *parser,
2414		const unsigned char *data, size_t len, unsigned priority)
2415{
2416	/* We dereference parser, so this check is essential */
2417	if (parser == NULL) {
2418		return false;
2419	}
2420
2421	return ucl_parser_add_chunk_full (parser, data, len,
2422				priority, UCL_DUPLICATE_APPEND, UCL_PARSE_UCL);
2423}
2424
2425bool
2426ucl_parser_add_chunk (struct ucl_parser *parser, const unsigned char *data,
2427		size_t len)
2428{
2429	if (parser == NULL) {
2430		return false;
2431	}
2432
2433	return ucl_parser_add_chunk_full (parser, data, len,
2434			parser->default_priority, UCL_DUPLICATE_APPEND, UCL_PARSE_UCL);
2435}
2436
2437bool
2438ucl_parser_add_string_priority (struct ucl_parser *parser, const char *data,
2439		size_t len, unsigned priority)
2440{
2441	if (data == NULL) {
2442		ucl_create_err (&parser->err, "invalid string added");
2443		return false;
2444	}
2445	if (len == 0) {
2446		len = strlen (data);
2447	}
2448
2449	return ucl_parser_add_chunk_priority (parser,
2450			(const unsigned char *)data, len, priority);
2451}
2452
2453bool
2454ucl_parser_add_string (struct ucl_parser *parser, const char *data,
2455		size_t len)
2456{
2457	if (parser == NULL) {
2458		return false;
2459	}
2460
2461	return ucl_parser_add_string_priority (parser,
2462			(const unsigned char *)data, len, parser->default_priority);
2463}
2464
2465bool
2466ucl_set_include_path (struct ucl_parser *parser, ucl_object_t *paths)
2467{
2468	if (parser == NULL || paths == NULL) {
2469		return false;
2470	}
2471
2472	if (parser->includepaths == NULL) {
2473		parser->includepaths = ucl_object_copy (paths);
2474	}
2475	else {
2476		ucl_object_unref (parser->includepaths);
2477		parser->includepaths = ucl_object_copy (paths);
2478	}
2479
2480	if (parser->includepaths == NULL) {
2481		return false;
2482	}
2483
2484	return true;
2485}
2486