1262395Sbapt/* Copyright (c) 2013, Vsevolod Stakhov
2262395Sbapt * All rights reserved.
3262395Sbapt *
4262395Sbapt * Redistribution and use in source and binary forms, with or without
5262395Sbapt * modification, are permitted provided that the following conditions are met:
6262395Sbapt *       * Redistributions of source code must retain the above copyright
7262395Sbapt *         notice, this list of conditions and the following disclaimer.
8262395Sbapt *       * Redistributions in binary form must reproduce the above copyright
9262395Sbapt *         notice, this list of conditions and the following disclaimer in the
10262395Sbapt *         documentation and/or other materials provided with the distribution.
11262395Sbapt *
12262395Sbapt * THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY
13262395Sbapt * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
14262395Sbapt * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
15262395Sbapt * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY
16262395Sbapt * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
17262395Sbapt * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
18262395Sbapt * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
19262395Sbapt * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
20262395Sbapt * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
21262395Sbapt * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
22262395Sbapt */
23262395Sbapt
24262395Sbapt#include "ucl.h"
25262395Sbapt#include "ucl_internal.h"
26262395Sbapt#include "ucl_chartable.h"
27262395Sbapt
28262395Sbapt/**
29275223Sbapt * @file ucl_parser.c
30275223Sbapt * The implementation of ucl parser
31262395Sbapt */
32262395Sbapt
33262395Sbaptstruct ucl_parser_saved_state {
34262395Sbapt	unsigned int line;
35262395Sbapt	unsigned int column;
36262395Sbapt	size_t remain;
37262395Sbapt	const unsigned char *pos;
38262395Sbapt};
39262395Sbapt
40262395Sbapt/**
41262395Sbapt * Move up to len characters
42262395Sbapt * @param parser
43262395Sbapt * @param begin
44262395Sbapt * @param len
45262395Sbapt * @return new position in chunk
46262395Sbapt */
47262395Sbapt#define ucl_chunk_skipc(chunk, p)    do{					\
48262395Sbapt    if (*(p) == '\n') {										\
49262395Sbapt        (chunk)->line ++;									\
50262395Sbapt        (chunk)->column = 0;								\
51262395Sbapt    }														\
52262395Sbapt    else (chunk)->column ++;								\
53262395Sbapt    (p++);													\
54262395Sbapt    (chunk)->pos ++;										\
55262395Sbapt    (chunk)->remain --;										\
56262395Sbapt    } while (0)
57262395Sbapt
58262395Sbaptstatic inline void
59275223Sbaptucl_set_err (struct ucl_parser *parser, int code, const char *str, UT_string **err)
60262395Sbapt{
61275223Sbapt	const char *fmt_string, *filename;
62275223Sbapt	struct ucl_chunk *chunk = parser->chunks;
63275223Sbapt
64275223Sbapt	if (parser->cur_file) {
65275223Sbapt		filename = parser->cur_file;
66275223Sbapt	}
67275223Sbapt	else {
68275223Sbapt		filename = "<unknown>";
69275223Sbapt	}
70290071Sbapt
71262395Sbapt	if (chunk->pos < chunk->end) {
72262395Sbapt		if (isgraph (*chunk->pos)) {
73275223Sbapt			fmt_string = "error while parsing %s: "
74275223Sbapt					"line: %d, column: %d - '%s', character: '%c'";
75262395Sbapt		}
76262395Sbapt		else {
77275223Sbapt			fmt_string = "error while parsing %s: "
78275223Sbapt					"line: %d, column: %d - '%s', character: '0x%02x'";
79262395Sbapt		}
80275223Sbapt		ucl_create_err (err, fmt_string,
81275223Sbapt			filename, chunk->line, chunk->column,
82275223Sbapt			str, *chunk->pos);
83262395Sbapt	}
84262395Sbapt	else {
85275223Sbapt		ucl_create_err (err, "error while parsing %s: at the end of chunk: %s",
86275223Sbapt			filename, str);
87262395Sbapt	}
88290071Sbapt
89290071Sbapt	parser->err_code = code;
90262395Sbapt}
91262395Sbapt
92298166Sbaptstatic void
93298166Sbaptucl_save_comment (struct ucl_parser *parser, const char *begin, size_t len)
94298166Sbapt{
95298166Sbapt	ucl_object_t *nobj;
96298166Sbapt
97298166Sbapt	if (len > 0 && begin != NULL) {
98298166Sbapt		nobj = ucl_object_fromstring_common (begin, len, 0);
99298166Sbapt
100298166Sbapt		if (parser->last_comment) {
101298166Sbapt			/* We need to append data to an existing object */
102298166Sbapt			DL_APPEND (parser->last_comment, nobj);
103298166Sbapt		}
104298166Sbapt		else {
105298166Sbapt			parser->last_comment = nobj;
106298166Sbapt		}
107298166Sbapt	}
108298166Sbapt}
109298166Sbapt
110298166Sbaptstatic void
111298166Sbaptucl_attach_comment (struct ucl_parser *parser, ucl_object_t *obj, bool before)
112298166Sbapt{
113298166Sbapt	if (parser->last_comment) {
114298166Sbapt		ucl_object_insert_key (parser->comments, parser->last_comment,
115298166Sbapt				(const char *)&obj, sizeof (void *), true);
116298166Sbapt
117298166Sbapt		if (before) {
118298166Sbapt			parser->last_comment->flags |= UCL_OBJECT_INHERITED;
119298166Sbapt		}
120298166Sbapt
121298166Sbapt		parser->last_comment = NULL;
122298166Sbapt	}
123298166Sbapt}
124298166Sbapt
125262395Sbapt/**
126262395Sbapt * Skip all comments from the current pos resolving nested and multiline comments
127262395Sbapt * @param parser
128262395Sbapt * @return
129262395Sbapt */
130262395Sbaptstatic bool
131262395Sbaptucl_skip_comments (struct ucl_parser *parser)
132262395Sbapt{
133262395Sbapt	struct ucl_chunk *chunk = parser->chunks;
134298166Sbapt	const unsigned char *p, *beg = NULL;
135262395Sbapt	int comments_nested = 0;
136275223Sbapt	bool quoted = false;
137262395Sbapt
138262395Sbapt	p = chunk->pos;
139262395Sbapt
140262395Sbaptstart:
141275223Sbapt	if (chunk->remain > 0 && *p == '#') {
142262395Sbapt		if (parser->state != UCL_STATE_SCOMMENT &&
143262395Sbapt				parser->state != UCL_STATE_MCOMMENT) {
144298166Sbapt			beg = p;
145298166Sbapt
146262395Sbapt			while (p < chunk->end) {
147262395Sbapt				if (*p == '\n') {
148298166Sbapt					if (parser->flags & UCL_PARSER_SAVE_COMMENTS) {
149298166Sbapt						ucl_save_comment (parser, beg, p - beg);
150298166Sbapt						beg = NULL;
151298166Sbapt					}
152298166Sbapt
153262395Sbapt					ucl_chunk_skipc (chunk, p);
154298166Sbapt
155262395Sbapt					goto start;
156262395Sbapt				}
157262395Sbapt				ucl_chunk_skipc (chunk, p);
158262395Sbapt			}
159262395Sbapt		}
160262395Sbapt	}
161275223Sbapt	else if (chunk->remain >= 2 && *p == '/') {
162262395Sbapt		if (p[1] == '*') {
163298166Sbapt			beg = p;
164262395Sbapt			ucl_chunk_skipc (chunk, p);
165262395Sbapt			comments_nested ++;
166262395Sbapt			ucl_chunk_skipc (chunk, p);
167262395Sbapt
168262395Sbapt			while (p < chunk->end) {
169275223Sbapt				if (*p == '"' && *(p - 1) != '\\') {
170275223Sbapt					quoted = !quoted;
171275223Sbapt				}
172275223Sbapt
173275223Sbapt				if (!quoted) {
174275223Sbapt					if (*p == '*') {
175275223Sbapt						ucl_chunk_skipc (chunk, p);
176275223Sbapt						if (*p == '/') {
177275223Sbapt							comments_nested --;
178275223Sbapt							if (comments_nested == 0) {
179298166Sbapt								if (parser->flags & UCL_PARSER_SAVE_COMMENTS) {
180298166Sbapt									ucl_save_comment (parser, beg, p - beg + 1);
181298166Sbapt									beg = NULL;
182298166Sbapt								}
183298166Sbapt
184275223Sbapt								ucl_chunk_skipc (chunk, p);
185275223Sbapt								goto start;
186275223Sbapt							}
187262395Sbapt						}
188275223Sbapt						ucl_chunk_skipc (chunk, p);
189262395Sbapt					}
190275223Sbapt					else if (p[0] == '/' && chunk->remain >= 2 && p[1] == '*') {
191275223Sbapt						comments_nested ++;
192275223Sbapt						ucl_chunk_skipc (chunk, p);
193275223Sbapt						ucl_chunk_skipc (chunk, p);
194275223Sbapt						continue;
195275223Sbapt					}
196262395Sbapt				}
197298166Sbapt
198262395Sbapt				ucl_chunk_skipc (chunk, p);
199262395Sbapt			}
200262395Sbapt			if (comments_nested != 0) {
201275223Sbapt				ucl_set_err (parser, UCL_ENESTED,
202275223Sbapt						"unfinished multiline comment", &parser->err);
203262395Sbapt				return false;
204262395Sbapt			}
205262395Sbapt		}
206262395Sbapt	}
207262395Sbapt
208298166Sbapt	if (beg && p > beg && (parser->flags & UCL_PARSER_SAVE_COMMENTS)) {
209298166Sbapt		ucl_save_comment (parser, beg, p - beg);
210298166Sbapt	}
211298166Sbapt
212262395Sbapt	return true;
213262395Sbapt}
214262395Sbapt
215262395Sbapt/**
216262395Sbapt * Return multiplier for a character
217262395Sbapt * @param c multiplier character
218262395Sbapt * @param is_bytes if true use 1024 multiplier
219262395Sbapt * @return multiplier
220262395Sbapt */
221262395Sbaptstatic inline unsigned long
222262395Sbaptucl_lex_num_multiplier (const unsigned char c, bool is_bytes) {
223262395Sbapt	const struct {
224262395Sbapt		char c;
225262395Sbapt		long mult_normal;
226262395Sbapt		long mult_bytes;
227262395Sbapt	} multipliers[] = {
228262395Sbapt			{'m', 1000 * 1000, 1024 * 1024},
229262395Sbapt			{'k', 1000, 1024},
230262395Sbapt			{'g', 1000 * 1000 * 1000, 1024 * 1024 * 1024}
231262395Sbapt	};
232262395Sbapt	int i;
233262395Sbapt
234262395Sbapt	for (i = 0; i < 3; i ++) {
235262395Sbapt		if (tolower (c) == multipliers[i].c) {
236262395Sbapt			if (is_bytes) {
237262395Sbapt				return multipliers[i].mult_bytes;
238262395Sbapt			}
239262395Sbapt			return multipliers[i].mult_normal;
240262395Sbapt		}
241262395Sbapt	}
242262395Sbapt
243262395Sbapt	return 1;
244262395Sbapt}
245262395Sbapt
246262395Sbapt
247262395Sbapt/**
248262395Sbapt * Return multiplier for time scaling
249262395Sbapt * @param c
250262395Sbapt * @return
251262395Sbapt */
252262395Sbaptstatic inline double
253262395Sbaptucl_lex_time_multiplier (const unsigned char c) {
254262395Sbapt	const struct {
255262395Sbapt		char c;
256262395Sbapt		double mult;
257262395Sbapt	} multipliers[] = {
258262395Sbapt			{'m', 60},
259262395Sbapt			{'h', 60 * 60},
260262395Sbapt			{'d', 60 * 60 * 24},
261262395Sbapt			{'w', 60 * 60 * 24 * 7},
262298166Sbapt			{'y', 60 * 60 * 24 * 365}
263262395Sbapt	};
264262395Sbapt	int i;
265262395Sbapt
266262395Sbapt	for (i = 0; i < 5; i ++) {
267262395Sbapt		if (tolower (c) == multipliers[i].c) {
268262395Sbapt			return multipliers[i].mult;
269262395Sbapt		}
270262395Sbapt	}
271262395Sbapt
272262395Sbapt	return 1;
273262395Sbapt}
274262395Sbapt
275262395Sbapt/**
276262395Sbapt * Return true if a character is a end of an atom
277262395Sbapt * @param c
278262395Sbapt * @return
279262395Sbapt */
280262395Sbaptstatic inline bool
281262395Sbaptucl_lex_is_atom_end (const unsigned char c)
282262395Sbapt{
283262395Sbapt	return ucl_test_character (c, UCL_CHARACTER_VALUE_END);
284262395Sbapt}
285262395Sbapt
286262395Sbaptstatic inline bool
287262395Sbaptucl_lex_is_comment (const unsigned char c1, const unsigned char c2)
288262395Sbapt{
289262395Sbapt	if (c1 == '/') {
290262395Sbapt		if (c2 == '*') {
291262395Sbapt			return true;
292262395Sbapt		}
293262395Sbapt	}
294262395Sbapt	else if (c1 == '#') {
295262395Sbapt		return true;
296262395Sbapt	}
297262395Sbapt	return false;
298262395Sbapt}
299262395Sbapt
300262395Sbapt/**
301262395Sbapt * Check variable found
302262395Sbapt * @param parser
303262395Sbapt * @param ptr
304262395Sbapt * @param remain
305262395Sbapt * @param out_len
306262395Sbapt * @param strict
307262395Sbapt * @param found
308262395Sbapt * @return
309262395Sbapt */
310262395Sbaptstatic inline const char *
311262395Sbaptucl_check_variable_safe (struct ucl_parser *parser, const char *ptr, size_t remain,
312262395Sbapt		size_t *out_len, bool strict, bool *found)
313262395Sbapt{
314262395Sbapt	struct ucl_variable *var;
315266636Sbapt	unsigned char *dst;
316266636Sbapt	size_t dstlen;
317266636Sbapt	bool need_free = false;
318262395Sbapt
319262395Sbapt	LL_FOREACH (parser->variables, var) {
320262395Sbapt		if (strict) {
321262395Sbapt			if (remain == var->var_len) {
322262395Sbapt				if (memcmp (ptr, var->var, var->var_len) == 0) {
323262395Sbapt					*out_len += var->value_len;
324262395Sbapt					*found = true;
325262395Sbapt					return (ptr + var->var_len);
326262395Sbapt				}
327262395Sbapt			}
328262395Sbapt		}
329262395Sbapt		else {
330262395Sbapt			if (remain >= var->var_len) {
331262395Sbapt				if (memcmp (ptr, var->var, var->var_len) == 0) {
332262395Sbapt					*out_len += var->value_len;
333262395Sbapt					*found = true;
334262395Sbapt					return (ptr + var->var_len);
335262395Sbapt				}
336262395Sbapt			}
337262395Sbapt		}
338262395Sbapt	}
339262395Sbapt
340266636Sbapt	/* XXX: can only handle ${VAR} */
341266636Sbapt	if (!(*found) && parser->var_handler != NULL && strict) {
342266636Sbapt		/* Call generic handler */
343266636Sbapt		if (parser->var_handler (ptr, remain, &dst, &dstlen, &need_free,
344266636Sbapt				parser->var_data)) {
345307790Sbapt			*out_len += dstlen;
346266636Sbapt			*found = true;
347266636Sbapt			if (need_free) {
348266636Sbapt				free (dst);
349266636Sbapt			}
350266636Sbapt			return (ptr + remain);
351266636Sbapt		}
352266636Sbapt	}
353266636Sbapt
354262395Sbapt	return ptr;
355262395Sbapt}
356262395Sbapt
357262395Sbapt/**
358262395Sbapt * Check for a variable in a given string
359262395Sbapt * @param parser
360262395Sbapt * @param ptr
361262395Sbapt * @param remain
362262395Sbapt * @param out_len
363262395Sbapt * @param vars_found
364262395Sbapt * @return
365262395Sbapt */
366262395Sbaptstatic const char *
367266636Sbaptucl_check_variable (struct ucl_parser *parser, const char *ptr,
368266636Sbapt		size_t remain, size_t *out_len, bool *vars_found)
369262395Sbapt{
370262395Sbapt	const char *p, *end, *ret = ptr;
371262395Sbapt	bool found = false;
372262395Sbapt
373262395Sbapt	if (*ptr == '{') {
374262395Sbapt		/* We need to match the variable enclosed in braces */
375262395Sbapt		p = ptr + 1;
376262395Sbapt		end = ptr + remain;
377262395Sbapt		while (p < end) {
378262395Sbapt			if (*p == '}') {
379266636Sbapt				ret = ucl_check_variable_safe (parser, ptr + 1, p - ptr - 1,
380266636Sbapt						out_len, true, &found);
381262395Sbapt				if (found) {
382262395Sbapt					/* {} must be excluded actually */
383262395Sbapt					ret ++;
384262395Sbapt					if (!*vars_found) {
385262395Sbapt						*vars_found = true;
386262395Sbapt					}
387262395Sbapt				}
388262395Sbapt				else {
389262395Sbapt					*out_len += 2;
390262395Sbapt				}
391262395Sbapt				break;
392262395Sbapt			}
393262395Sbapt			p ++;
394262395Sbapt		}
395262395Sbapt	}
396262395Sbapt	else if (*ptr != '$') {
397262395Sbapt		/* Not count escaped dollar sign */
398262395Sbapt		ret = ucl_check_variable_safe (parser, ptr, remain, out_len, false, &found);
399262395Sbapt		if (found && !*vars_found) {
400262395Sbapt			*vars_found = true;
401262395Sbapt		}
402262395Sbapt		if (!found) {
403262395Sbapt			(*out_len) ++;
404262395Sbapt		}
405262395Sbapt	}
406262395Sbapt	else {
407262395Sbapt		ret ++;
408262395Sbapt		(*out_len) ++;
409262395Sbapt	}
410262395Sbapt
411262395Sbapt	return ret;
412262395Sbapt}
413262395Sbapt
414262395Sbapt/**
415262395Sbapt * Expand a single variable
416262395Sbapt * @param parser
417262395Sbapt * @param ptr
418262395Sbapt * @param remain
419262395Sbapt * @param dest
420262395Sbapt * @return
421262395Sbapt */
422262395Sbaptstatic const char *
423262395Sbaptucl_expand_single_variable (struct ucl_parser *parser, const char *ptr,
424262395Sbapt		size_t remain, unsigned char **dest)
425262395Sbapt{
426266636Sbapt	unsigned char *d = *dest, *dst;
427262395Sbapt	const char *p = ptr + 1, *ret;
428262395Sbapt	struct ucl_variable *var;
429266636Sbapt	size_t dstlen;
430266636Sbapt	bool need_free = false;
431262395Sbapt	bool found = false;
432266636Sbapt	bool strict = false;
433262395Sbapt
434262395Sbapt	ret = ptr + 1;
435262395Sbapt	remain --;
436262395Sbapt
437262395Sbapt	if (*p == '$') {
438262395Sbapt		*d++ = *p++;
439262395Sbapt		*dest = d;
440262395Sbapt		return p;
441262395Sbapt	}
442262395Sbapt	else if (*p == '{') {
443262395Sbapt		p ++;
444266636Sbapt		strict = true;
445262395Sbapt		ret += 2;
446262395Sbapt		remain -= 2;
447262395Sbapt	}
448262395Sbapt
449262395Sbapt	LL_FOREACH (parser->variables, var) {
450262395Sbapt		if (remain >= var->var_len) {
451262395Sbapt			if (memcmp (p, var->var, var->var_len) == 0) {
452262395Sbapt				memcpy (d, var->value, var->value_len);
453262395Sbapt				ret += var->var_len;
454262395Sbapt				d += var->value_len;
455262395Sbapt				found = true;
456262395Sbapt				break;
457262395Sbapt			}
458262395Sbapt		}
459262395Sbapt	}
460262395Sbapt	if (!found) {
461266636Sbapt		if (strict && parser->var_handler != NULL) {
462307790Sbapt			size_t var_len = 0;
463307790Sbapt			while (var_len < remain && p[var_len] != '}')
464307790Sbapt				var_len ++;
465307790Sbapt
466307790Sbapt			if (parser->var_handler (p, var_len, &dst, &dstlen, &need_free,
467266636Sbapt							parser->var_data)) {
468266636Sbapt				memcpy (d, dst, dstlen);
469307790Sbapt				ret += var_len;
470307790Sbapt				d += dstlen;
471307790Sbapt				if (need_free) {
472307790Sbapt					free (dst);
473307790Sbapt				}
474266636Sbapt				found = true;
475266636Sbapt			}
476266636Sbapt		}
477266636Sbapt
478266636Sbapt		/* Leave variable as is */
479266636Sbapt		if (!found) {
480268831Sbapt			if (strict) {
481268831Sbapt				/* Copy '${' */
482268831Sbapt				memcpy (d, ptr, 2);
483268831Sbapt				d += 2;
484268831Sbapt				ret --;
485268831Sbapt			}
486268831Sbapt			else {
487268831Sbapt				memcpy (d, ptr, 1);
488268831Sbapt				d ++;
489268831Sbapt			}
490266636Sbapt		}
491262395Sbapt	}
492262395Sbapt
493262395Sbapt	*dest = d;
494262395Sbapt	return ret;
495262395Sbapt}
496262395Sbapt
497262395Sbapt/**
498262395Sbapt * Expand variables in string
499262395Sbapt * @param parser
500262395Sbapt * @param dst
501262395Sbapt * @param src
502262395Sbapt * @param in_len
503262395Sbapt * @return
504262395Sbapt */
505262395Sbaptstatic ssize_t
506262395Sbaptucl_expand_variable (struct ucl_parser *parser, unsigned char **dst,
507262395Sbapt		const char *src, size_t in_len)
508262395Sbapt{
509262395Sbapt	const char *p, *end = src + in_len;
510262395Sbapt	unsigned char *d;
511262395Sbapt	size_t out_len = 0;
512262395Sbapt	bool vars_found = false;
513262395Sbapt
514298166Sbapt	if (parser->flags & UCL_PARSER_DISABLE_MACRO) {
515298166Sbapt		*dst = NULL;
516298166Sbapt		return in_len;
517298166Sbapt	}
518298166Sbapt
519262395Sbapt	p = src;
520262395Sbapt	while (p != end) {
521262395Sbapt		if (*p == '$') {
522262395Sbapt			p = ucl_check_variable (parser, p + 1, end - p - 1, &out_len, &vars_found);
523262395Sbapt		}
524262395Sbapt		else {
525262395Sbapt			p ++;
526262395Sbapt			out_len ++;
527262395Sbapt		}
528262395Sbapt	}
529262395Sbapt
530262395Sbapt	if (!vars_found) {
531262395Sbapt		/* Trivial case */
532262395Sbapt		*dst = NULL;
533262395Sbapt		return in_len;
534262395Sbapt	}
535262395Sbapt
536262395Sbapt	*dst = UCL_ALLOC (out_len + 1);
537262395Sbapt	if (*dst == NULL) {
538262395Sbapt		return in_len;
539262395Sbapt	}
540262395Sbapt
541262395Sbapt	d = *dst;
542262395Sbapt	p = src;
543262395Sbapt	while (p != end) {
544262395Sbapt		if (*p == '$') {
545262395Sbapt			p = ucl_expand_single_variable (parser, p, end - p, &d);
546262395Sbapt		}
547262395Sbapt		else {
548262395Sbapt			*d++ = *p++;
549262395Sbapt		}
550262395Sbapt	}
551262395Sbapt
552262395Sbapt	*d = '\0';
553262395Sbapt
554262395Sbapt	return out_len;
555262395Sbapt}
556262395Sbapt
557262395Sbapt/**
558262395Sbapt * Store or copy pointer to the trash stack
559262395Sbapt * @param parser parser object
560262395Sbapt * @param src src string
561262395Sbapt * @param dst destination buffer (trash stack pointer)
562262395Sbapt * @param dst_const const destination pointer (e.g. value of object)
563262395Sbapt * @param in_len input length
564262395Sbapt * @param need_unescape need to unescape source (and copy it)
565262395Sbapt * @param need_lowercase need to lowercase value (and copy)
566262395Sbapt * @param need_expand need to expand variables (and copy as well)
567262395Sbapt * @return output length (excluding \0 symbol)
568262395Sbapt */
569262395Sbaptstatic inline ssize_t
570262395Sbaptucl_copy_or_store_ptr (struct ucl_parser *parser,
571262395Sbapt		const unsigned char *src, unsigned char **dst,
572262395Sbapt		const char **dst_const, size_t in_len,
573262395Sbapt		bool need_unescape, bool need_lowercase, bool need_expand)
574262395Sbapt{
575262395Sbapt	ssize_t ret = -1, tret;
576262395Sbapt	unsigned char *tmp;
577262395Sbapt
578262395Sbapt	if (need_unescape || need_lowercase ||
579262395Sbapt			(need_expand && parser->variables != NULL) ||
580262395Sbapt			!(parser->flags & UCL_PARSER_ZEROCOPY)) {
581262395Sbapt		/* Copy string */
582262395Sbapt		*dst = UCL_ALLOC (in_len + 1);
583262395Sbapt		if (*dst == NULL) {
584290071Sbapt			ucl_set_err (parser, UCL_EINTERNAL, "cannot allocate memory for a string",
585275223Sbapt					&parser->err);
586262395Sbapt			return false;
587262395Sbapt		}
588262395Sbapt		if (need_lowercase) {
589262395Sbapt			ret = ucl_strlcpy_tolower (*dst, src, in_len + 1);
590262395Sbapt		}
591262395Sbapt		else {
592262395Sbapt			ret = ucl_strlcpy_unsafe (*dst, src, in_len + 1);
593262395Sbapt		}
594262395Sbapt
595262395Sbapt		if (need_unescape) {
596262395Sbapt			ret = ucl_unescape_json_string (*dst, ret);
597262395Sbapt		}
598262395Sbapt		if (need_expand) {
599262395Sbapt			tmp = *dst;
600262395Sbapt			tret = ret;
601262395Sbapt			ret = ucl_expand_variable (parser, dst, tmp, ret);
602262395Sbapt			if (*dst == NULL) {
603262395Sbapt				/* Nothing to expand */
604262395Sbapt				*dst = tmp;
605262395Sbapt				ret = tret;
606262395Sbapt			}
607275223Sbapt			else {
608275223Sbapt				/* Free unexpanded value */
609275223Sbapt				UCL_FREE (in_len + 1, tmp);
610275223Sbapt			}
611262395Sbapt		}
612262395Sbapt		*dst_const = *dst;
613262395Sbapt	}
614262395Sbapt	else {
615262395Sbapt		*dst_const = src;
616262395Sbapt		ret = in_len;
617262395Sbapt	}
618262395Sbapt
619262395Sbapt	return ret;
620262395Sbapt}
621262395Sbapt
622262395Sbapt/**
623262395Sbapt * Create and append an object at the specified level
624262395Sbapt * @param parser
625262395Sbapt * @param is_array
626262395Sbapt * @param level
627262395Sbapt * @return
628262395Sbapt */
629262395Sbaptstatic inline ucl_object_t *
630290071Sbaptucl_parser_add_container (ucl_object_t *obj, struct ucl_parser *parser,
631290071Sbapt		bool is_array, int level)
632262395Sbapt{
633262395Sbapt	struct ucl_stack *st;
634262395Sbapt
635262395Sbapt	if (!is_array) {
636262395Sbapt		if (obj == NULL) {
637275223Sbapt			obj = ucl_object_new_full (UCL_OBJECT, parser->chunks->priority);
638262395Sbapt		}
639262395Sbapt		else {
640262395Sbapt			obj->type = UCL_OBJECT;
641262395Sbapt		}
642290071Sbapt		if (obj->value.ov == NULL) {
643290071Sbapt			obj->value.ov = ucl_hash_create (parser->flags & UCL_PARSER_KEY_LOWERCASE);
644290071Sbapt		}
645262395Sbapt		parser->state = UCL_STATE_KEY;
646262395Sbapt	}
647262395Sbapt	else {
648262395Sbapt		if (obj == NULL) {
649275223Sbapt			obj = ucl_object_new_full (UCL_ARRAY, parser->chunks->priority);
650262395Sbapt		}
651262395Sbapt		else {
652262395Sbapt			obj->type = UCL_ARRAY;
653262395Sbapt		}
654262395Sbapt		parser->state = UCL_STATE_VALUE;
655262395Sbapt	}
656262395Sbapt
657262395Sbapt	st = UCL_ALLOC (sizeof (struct ucl_stack));
658298166Sbapt
659263648Sbapt	if (st == NULL) {
660290071Sbapt		ucl_set_err (parser, UCL_EINTERNAL, "cannot allocate memory for an object",
661275223Sbapt				&parser->err);
662275223Sbapt		ucl_object_unref (obj);
663263648Sbapt		return NULL;
664263648Sbapt	}
665298166Sbapt
666262395Sbapt	st->obj = obj;
667262395Sbapt	st->level = level;
668262395Sbapt	LL_PREPEND (parser->stack, st);
669262395Sbapt	parser->cur_obj = obj;
670262395Sbapt
671262395Sbapt	return obj;
672262395Sbapt}
673262395Sbapt
674262395Sbaptint
675262395Sbaptucl_maybe_parse_number (ucl_object_t *obj,
676263648Sbapt		const char *start, const char *end, const char **pos,
677263648Sbapt		bool allow_double, bool number_bytes, bool allow_time)
678262395Sbapt{
679262395Sbapt	const char *p = start, *c = start;
680262395Sbapt	char *endptr;
681262395Sbapt	bool got_dot = false, got_exp = false, need_double = false,
682263648Sbapt			is_time = false, valid_start = false, is_hex = false,
683262395Sbapt			is_neg = false;
684262395Sbapt	double dv = 0;
685262395Sbapt	int64_t lv = 0;
686262395Sbapt
687262395Sbapt	if (*p == '-') {
688262395Sbapt		is_neg = true;
689262395Sbapt		c ++;
690262395Sbapt		p ++;
691262395Sbapt	}
692262395Sbapt	while (p < end) {
693262395Sbapt		if (is_hex && isxdigit (*p)) {
694262395Sbapt			p ++;
695262395Sbapt		}
696262395Sbapt		else if (isdigit (*p)) {
697262395Sbapt			valid_start = true;
698262395Sbapt			p ++;
699262395Sbapt		}
700262395Sbapt		else if (!is_hex && (*p == 'x' || *p == 'X')) {
701262395Sbapt			is_hex = true;
702262395Sbapt			allow_double = false;
703262395Sbapt			c = p + 1;
704262395Sbapt		}
705262395Sbapt		else if (allow_double) {
706262395Sbapt			if (p == c) {
707262395Sbapt				/* Empty digits sequence, not a number */
708262395Sbapt				*pos = start;
709262395Sbapt				return EINVAL;
710262395Sbapt			}
711262395Sbapt			else if (*p == '.') {
712262395Sbapt				if (got_dot) {
713262395Sbapt					/* Double dots, not a number */
714262395Sbapt					*pos = start;
715262395Sbapt					return EINVAL;
716262395Sbapt				}
717262395Sbapt				else {
718262395Sbapt					got_dot = true;
719262395Sbapt					need_double = true;
720262395Sbapt					p ++;
721262395Sbapt				}
722262395Sbapt			}
723262395Sbapt			else if (*p == 'e' || *p == 'E') {
724262395Sbapt				if (got_exp) {
725262395Sbapt					/* Double exp, not a number */
726262395Sbapt					*pos = start;
727262395Sbapt					return EINVAL;
728262395Sbapt				}
729262395Sbapt				else {
730262395Sbapt					got_exp = true;
731262395Sbapt					need_double = true;
732262395Sbapt					p ++;
733262395Sbapt					if (p >= end) {
734262395Sbapt						*pos = start;
735262395Sbapt						return EINVAL;
736262395Sbapt					}
737262395Sbapt					if (!isdigit (*p) && *p != '+' && *p != '-') {
738262395Sbapt						/* Wrong exponent sign */
739262395Sbapt						*pos = start;
740262395Sbapt						return EINVAL;
741262395Sbapt					}
742262395Sbapt					else {
743262395Sbapt						p ++;
744262395Sbapt					}
745262395Sbapt				}
746262395Sbapt			}
747262395Sbapt			else {
748262395Sbapt				/* Got the end of the number, need to check */
749262395Sbapt				break;
750262395Sbapt			}
751262395Sbapt		}
752262395Sbapt		else {
753262395Sbapt			break;
754262395Sbapt		}
755262395Sbapt	}
756262395Sbapt
757262395Sbapt	if (!valid_start) {
758262395Sbapt		*pos = start;
759262395Sbapt		return EINVAL;
760262395Sbapt	}
761262395Sbapt
762262395Sbapt	errno = 0;
763262395Sbapt	if (need_double) {
764262395Sbapt		dv = strtod (c, &endptr);
765262395Sbapt	}
766262395Sbapt	else {
767262395Sbapt		if (is_hex) {
768262395Sbapt			lv = strtoimax (c, &endptr, 16);
769262395Sbapt		}
770262395Sbapt		else {
771262395Sbapt			lv = strtoimax (c, &endptr, 10);
772262395Sbapt		}
773262395Sbapt	}
774262395Sbapt	if (errno == ERANGE) {
775262395Sbapt		*pos = start;
776262395Sbapt		return ERANGE;
777262395Sbapt	}
778262395Sbapt
779262395Sbapt	/* Now check endptr */
780275223Sbapt	if (endptr == NULL || ucl_lex_is_atom_end (*endptr) || *endptr == '\0') {
781262395Sbapt		p = endptr;
782262395Sbapt		goto set_obj;
783262395Sbapt	}
784262395Sbapt
785262395Sbapt	if (endptr < end && endptr != start) {
786262395Sbapt		p = endptr;
787262395Sbapt		switch (*p) {
788262395Sbapt		case 'm':
789262395Sbapt		case 'M':
790262395Sbapt		case 'g':
791262395Sbapt		case 'G':
792262395Sbapt		case 'k':
793262395Sbapt		case 'K':
794262395Sbapt			if (end - p >= 2) {
795262395Sbapt				if (p[1] == 's' || p[1] == 'S') {
796262395Sbapt					/* Milliseconds */
797262395Sbapt					if (!need_double) {
798262395Sbapt						need_double = true;
799262395Sbapt						dv = lv;
800262395Sbapt					}
801263648Sbapt					is_time = true;
802262395Sbapt					if (p[0] == 'm' || p[0] == 'M') {
803262395Sbapt						dv /= 1000.;
804262395Sbapt					}
805262395Sbapt					else {
806262395Sbapt						dv *= ucl_lex_num_multiplier (*p, false);
807262395Sbapt					}
808262395Sbapt					p += 2;
809262395Sbapt					goto set_obj;
810262395Sbapt				}
811262395Sbapt				else if (number_bytes || (p[1] == 'b' || p[1] == 'B')) {
812262395Sbapt					/* Bytes */
813262395Sbapt					if (need_double) {
814262395Sbapt						need_double = false;
815262395Sbapt						lv = dv;
816262395Sbapt					}
817262395Sbapt					lv *= ucl_lex_num_multiplier (*p, true);
818262395Sbapt					p += 2;
819262395Sbapt					goto set_obj;
820262395Sbapt				}
821262395Sbapt				else if (ucl_lex_is_atom_end (p[1])) {
822262395Sbapt					if (need_double) {
823262395Sbapt						dv *= ucl_lex_num_multiplier (*p, false);
824262395Sbapt					}
825262395Sbapt					else {
826262395Sbapt						lv *= ucl_lex_num_multiplier (*p, number_bytes);
827262395Sbapt					}
828262395Sbapt					p ++;
829262395Sbapt					goto set_obj;
830262395Sbapt				}
831263648Sbapt				else if (allow_time && end - p >= 3) {
832262395Sbapt					if (tolower (p[0]) == 'm' &&
833262395Sbapt							tolower (p[1]) == 'i' &&
834262395Sbapt							tolower (p[2]) == 'n') {
835262395Sbapt						/* Minutes */
836262395Sbapt						if (!need_double) {
837262395Sbapt							need_double = true;
838262395Sbapt							dv = lv;
839262395Sbapt						}
840263648Sbapt						is_time = true;
841262395Sbapt						dv *= 60.;
842262395Sbapt						p += 3;
843262395Sbapt						goto set_obj;
844262395Sbapt					}
845262395Sbapt				}
846262395Sbapt			}
847262395Sbapt			else {
848262395Sbapt				if (need_double) {
849262395Sbapt					dv *= ucl_lex_num_multiplier (*p, false);
850262395Sbapt				}
851262395Sbapt				else {
852262395Sbapt					lv *= ucl_lex_num_multiplier (*p, number_bytes);
853262395Sbapt				}
854262395Sbapt				p ++;
855262395Sbapt				goto set_obj;
856262395Sbapt			}
857262395Sbapt			break;
858262395Sbapt		case 'S':
859262395Sbapt		case 's':
860263648Sbapt			if (allow_time &&
861263648Sbapt					(p == end - 1 || ucl_lex_is_atom_end (p[1]))) {
862262395Sbapt				if (!need_double) {
863262395Sbapt					need_double = true;
864262395Sbapt					dv = lv;
865262395Sbapt				}
866262395Sbapt				p ++;
867263648Sbapt				is_time = true;
868262395Sbapt				goto set_obj;
869262395Sbapt			}
870262395Sbapt			break;
871262395Sbapt		case 'h':
872262395Sbapt		case 'H':
873262395Sbapt		case 'd':
874262395Sbapt		case 'D':
875262395Sbapt		case 'w':
876262395Sbapt		case 'W':
877262395Sbapt		case 'Y':
878262395Sbapt		case 'y':
879263648Sbapt			if (allow_time &&
880263648Sbapt					(p == end - 1 || ucl_lex_is_atom_end (p[1]))) {
881262395Sbapt				if (!need_double) {
882262395Sbapt					need_double = true;
883262395Sbapt					dv = lv;
884262395Sbapt				}
885263648Sbapt				is_time = true;
886262395Sbapt				dv *= ucl_lex_time_multiplier (*p);
887262395Sbapt				p ++;
888262395Sbapt				goto set_obj;
889262395Sbapt			}
890262395Sbapt			break;
891275223Sbapt		case '\t':
892275223Sbapt		case ' ':
893275223Sbapt			while (p < end && ucl_test_character(*p, UCL_CHARACTER_WHITESPACE)) {
894275223Sbapt				p++;
895275223Sbapt			}
896275223Sbapt			if (ucl_lex_is_atom_end(*p))
897275223Sbapt				goto set_obj;
898275223Sbapt			break;
899262395Sbapt		}
900262395Sbapt	}
901275223Sbapt	else if (endptr == end) {
902275223Sbapt		/* Just a number at the end of chunk */
903275223Sbapt		p = endptr;
904275223Sbapt		goto set_obj;
905275223Sbapt	}
906262395Sbapt
907262395Sbapt	*pos = c;
908262395Sbapt	return EINVAL;
909262395Sbapt
910290071Sbaptset_obj:
911290071Sbapt	if (obj != NULL) {
912290071Sbapt		if (allow_double && (need_double || is_time)) {
913290071Sbapt			if (!is_time) {
914290071Sbapt				obj->type = UCL_FLOAT;
915290071Sbapt			}
916290071Sbapt			else {
917290071Sbapt				obj->type = UCL_TIME;
918290071Sbapt			}
919290071Sbapt			obj->value.dv = is_neg ? (-dv) : dv;
920262395Sbapt		}
921262395Sbapt		else {
922290071Sbapt			obj->type = UCL_INT;
923290071Sbapt			obj->value.iv = is_neg ? (-lv) : lv;
924262395Sbapt		}
925262395Sbapt	}
926262395Sbapt	*pos = p;
927262395Sbapt	return 0;
928262395Sbapt}
929262395Sbapt
930262395Sbapt/**
931262395Sbapt * Parse possible number
932262395Sbapt * @param parser
933262395Sbapt * @param chunk
934290071Sbapt * @param obj
935262395Sbapt * @return true if a number has been parsed
936262395Sbapt */
937262395Sbaptstatic bool
938262395Sbaptucl_lex_number (struct ucl_parser *parser,
939262395Sbapt		struct ucl_chunk *chunk, ucl_object_t *obj)
940262395Sbapt{
941262395Sbapt	const unsigned char *pos;
942262395Sbapt	int ret;
943262395Sbapt
944263648Sbapt	ret = ucl_maybe_parse_number (obj, chunk->pos, chunk->end, (const char **)&pos,
945263648Sbapt			true, false, ((parser->flags & UCL_PARSER_NO_TIME) == 0));
946262395Sbapt
947262395Sbapt	if (ret == 0) {
948262395Sbapt		chunk->remain -= pos - chunk->pos;
949262395Sbapt		chunk->column += pos - chunk->pos;
950262395Sbapt		chunk->pos = pos;
951262395Sbapt		return true;
952262395Sbapt	}
953262395Sbapt	else if (ret == ERANGE) {
954290071Sbapt		ucl_set_err (parser, UCL_ESYNTAX, "numeric value out of range",
955290071Sbapt				&parser->err);
956262395Sbapt	}
957262395Sbapt
958262395Sbapt	return false;
959262395Sbapt}
960262395Sbapt
961262395Sbapt/**
962262395Sbapt * Parse quoted string with possible escapes
963262395Sbapt * @param parser
964262395Sbapt * @param chunk
965290071Sbapt * @param need_unescape
966290071Sbapt * @param ucl_escape
967290071Sbapt * @param var_expand
968262395Sbapt * @return true if a string has been parsed
969262395Sbapt */
970262395Sbaptstatic bool
971262395Sbaptucl_lex_json_string (struct ucl_parser *parser,
972262395Sbapt		struct ucl_chunk *chunk, bool *need_unescape, bool *ucl_escape, bool *var_expand)
973262395Sbapt{
974262395Sbapt	const unsigned char *p = chunk->pos;
975262395Sbapt	unsigned char c;
976262395Sbapt	int i;
977262395Sbapt
978262395Sbapt	while (p < chunk->end) {
979262395Sbapt		c = *p;
980262395Sbapt		if (c < 0x1F) {
981262395Sbapt			/* Unmasked control character */
982262395Sbapt			if (c == '\n') {
983275223Sbapt				ucl_set_err (parser, UCL_ESYNTAX, "unexpected newline",
984275223Sbapt						&parser->err);
985262395Sbapt			}
986262395Sbapt			else {
987275223Sbapt				ucl_set_err (parser, UCL_ESYNTAX, "unexpected control character",
988275223Sbapt						&parser->err);
989262395Sbapt			}
990262395Sbapt			return false;
991262395Sbapt		}
992262395Sbapt		else if (c == '\\') {
993262395Sbapt			ucl_chunk_skipc (chunk, p);
994262395Sbapt			c = *p;
995262395Sbapt			if (p >= chunk->end) {
996275223Sbapt				ucl_set_err (parser, UCL_ESYNTAX, "unfinished escape character",
997275223Sbapt						&parser->err);
998262395Sbapt				return false;
999262395Sbapt			}
1000262395Sbapt			else if (ucl_test_character (c, UCL_CHARACTER_ESCAPE)) {
1001262395Sbapt				if (c == 'u') {
1002262395Sbapt					ucl_chunk_skipc (chunk, p);
1003262395Sbapt					for (i = 0; i < 4 && p < chunk->end; i ++) {
1004262395Sbapt						if (!isxdigit (*p)) {
1005275223Sbapt							ucl_set_err (parser, UCL_ESYNTAX, "invalid utf escape",
1006275223Sbapt									&parser->err);
1007262395Sbapt							return false;
1008262395Sbapt						}
1009262395Sbapt						ucl_chunk_skipc (chunk, p);
1010262395Sbapt					}
1011262395Sbapt					if (p >= chunk->end) {
1012275223Sbapt						ucl_set_err (parser, UCL_ESYNTAX, "unfinished escape character",
1013275223Sbapt								&parser->err);
1014262395Sbapt						return false;
1015262395Sbapt					}
1016262395Sbapt				}
1017262395Sbapt				else {
1018262395Sbapt					ucl_chunk_skipc (chunk, p);
1019262395Sbapt				}
1020262395Sbapt			}
1021262395Sbapt			*need_unescape = true;
1022262395Sbapt			*ucl_escape = true;
1023262395Sbapt			continue;
1024262395Sbapt		}
1025262395Sbapt		else if (c == '"') {
1026262395Sbapt			ucl_chunk_skipc (chunk, p);
1027262395Sbapt			return true;
1028262395Sbapt		}
1029262395Sbapt		else if (ucl_test_character (c, UCL_CHARACTER_UCL_UNSAFE)) {
1030262395Sbapt			*ucl_escape = true;
1031262395Sbapt		}
1032262395Sbapt		else if (c == '$') {
1033262395Sbapt			*var_expand = true;
1034262395Sbapt		}
1035262395Sbapt		ucl_chunk_skipc (chunk, p);
1036262395Sbapt	}
1037262395Sbapt
1038275223Sbapt	ucl_set_err (parser, UCL_ESYNTAX, "no quote at the end of json string",
1039275223Sbapt			&parser->err);
1040262395Sbapt	return false;
1041262395Sbapt}
1042262395Sbapt
1043275223Sbaptstatic void
1044275223Sbaptucl_parser_append_elt (struct ucl_parser *parser, ucl_hash_t *cont,
1045275223Sbapt		ucl_object_t *top,
1046275223Sbapt		ucl_object_t *elt)
1047275223Sbapt{
1048275223Sbapt	ucl_object_t *nobj;
1049275223Sbapt
1050275223Sbapt	if ((parser->flags & UCL_PARSER_NO_IMPLICIT_ARRAYS) == 0) {
1051275223Sbapt		/* Implicit array */
1052275223Sbapt		top->flags |= UCL_OBJECT_MULTIVALUE;
1053275223Sbapt		DL_APPEND (top, elt);
1054290071Sbapt		parser->stack->obj->len ++;
1055275223Sbapt	}
1056275223Sbapt	else {
1057275223Sbapt		if ((top->flags & UCL_OBJECT_MULTIVALUE) != 0) {
1058275223Sbapt			/* Just add to the explicit array */
1059279549Sbapt			ucl_array_append (top, elt);
1060275223Sbapt		}
1061275223Sbapt		else {
1062275223Sbapt			/* Convert to an array */
1063275223Sbapt			nobj = ucl_object_typed_new (UCL_ARRAY);
1064275223Sbapt			nobj->key = top->key;
1065275223Sbapt			nobj->keylen = top->keylen;
1066275223Sbapt			nobj->flags |= UCL_OBJECT_MULTIVALUE;
1067279549Sbapt			ucl_array_append (nobj, top);
1068279549Sbapt			ucl_array_append (nobj, elt);
1069290071Sbapt			ucl_hash_replace (cont, top, nobj);
1070275223Sbapt		}
1071275223Sbapt	}
1072275223Sbapt}
1073275223Sbapt
1074290071Sbaptbool
1075290071Sbaptucl_parser_process_object_element (struct ucl_parser *parser, ucl_object_t *nobj)
1076290071Sbapt{
1077290071Sbapt	ucl_hash_t *container;
1078290071Sbapt	ucl_object_t *tobj;
1079298166Sbapt	char errmsg[256];
1080290071Sbapt
1081290071Sbapt	container = parser->stack->obj->value.ov;
1082290071Sbapt
1083290071Sbapt	tobj = __DECONST (ucl_object_t *, ucl_hash_search_obj (container, nobj));
1084290071Sbapt	if (tobj == NULL) {
1085290071Sbapt		container = ucl_hash_insert_object (container, nobj,
1086290071Sbapt				parser->flags & UCL_PARSER_KEY_LOWERCASE);
1087290071Sbapt		nobj->prev = nobj;
1088290071Sbapt		nobj->next = NULL;
1089290071Sbapt		parser->stack->obj->len ++;
1090290071Sbapt	}
1091290071Sbapt	else {
1092290071Sbapt		unsigned priold = ucl_object_get_priority (tobj),
1093290071Sbapt				prinew = ucl_object_get_priority (nobj);
1094290071Sbapt		switch (parser->chunks->strategy) {
1095290071Sbapt
1096290071Sbapt		case UCL_DUPLICATE_APPEND:
1097290071Sbapt			/*
1098290071Sbapt			 * The logic here is the following:
1099290071Sbapt			 *
1100290071Sbapt			 * - if we have two objects with the same priority, then we form an
1101290071Sbapt			 * implicit or explicit array
1102290071Sbapt			 * - if a new object has bigger priority, then we overwrite an old one
1103290071Sbapt			 * - if a new object has lower priority, then we ignore it
1104290071Sbapt			 */
1105290071Sbapt
1106290071Sbapt
1107290071Sbapt			/* Special case for inherited objects */
1108290071Sbapt			if (tobj->flags & UCL_OBJECT_INHERITED) {
1109290071Sbapt				prinew = priold + 1;
1110290071Sbapt			}
1111290071Sbapt
1112290071Sbapt			if (priold == prinew) {
1113290071Sbapt				ucl_parser_append_elt (parser, container, tobj, nobj);
1114290071Sbapt			}
1115290071Sbapt			else if (priold > prinew) {
1116290071Sbapt				/*
1117290071Sbapt				 * We add this new object to a list of trash objects just to ensure
1118290071Sbapt				 * that it won't come to any real object
1119290071Sbapt				 * XXX: rather inefficient approach
1120290071Sbapt				 */
1121290071Sbapt				DL_APPEND (parser->trash_objs, nobj);
1122290071Sbapt			}
1123290071Sbapt			else {
1124290071Sbapt				ucl_hash_replace (container, tobj, nobj);
1125290071Sbapt				ucl_object_unref (tobj);
1126290071Sbapt			}
1127290071Sbapt
1128290071Sbapt			break;
1129290071Sbapt
1130290071Sbapt		case UCL_DUPLICATE_REWRITE:
1131290071Sbapt			/* We just rewrite old values regardless of priority */
1132290071Sbapt			ucl_hash_replace (container, tobj, nobj);
1133290071Sbapt			ucl_object_unref (tobj);
1134290071Sbapt
1135290071Sbapt			break;
1136290071Sbapt
1137290071Sbapt		case UCL_DUPLICATE_ERROR:
1138298166Sbapt			snprintf(errmsg, sizeof(errmsg),
1139298166Sbapt					"duplicate element for key '%s' found",
1140298166Sbapt					nobj->key);
1141298166Sbapt			ucl_set_err (parser, UCL_EMERGE, errmsg, &parser->err);
1142290071Sbapt			return false;
1143290071Sbapt
1144290071Sbapt		case UCL_DUPLICATE_MERGE:
1145290071Sbapt			/*
1146290071Sbapt			 * Here we do have some old object so we just push it on top of objects stack
1147298166Sbapt			 * Check priority and then perform the merge on the remaining objects
1148290071Sbapt			 */
1149290071Sbapt			if (tobj->type == UCL_OBJECT || tobj->type == UCL_ARRAY) {
1150290071Sbapt				ucl_object_unref (nobj);
1151290071Sbapt				nobj = tobj;
1152290071Sbapt			}
1153298166Sbapt			else if (priold == prinew) {
1154290071Sbapt				ucl_parser_append_elt (parser, container, tobj, nobj);
1155290071Sbapt			}
1156298166Sbapt			else if (priold > prinew) {
1157298166Sbapt				/*
1158298166Sbapt				 * We add this new object to a list of trash objects just to ensure
1159298166Sbapt				 * that it won't come to any real object
1160298166Sbapt				 * XXX: rather inefficient approach
1161298166Sbapt				 */
1162298166Sbapt				DL_APPEND (parser->trash_objs, nobj);
1163298166Sbapt			}
1164298166Sbapt			else {
1165298166Sbapt				ucl_hash_replace (container, tobj, nobj);
1166298166Sbapt				ucl_object_unref (tobj);
1167298166Sbapt			}
1168290071Sbapt			break;
1169290071Sbapt		}
1170290071Sbapt	}
1171290071Sbapt
1172290071Sbapt	parser->stack->obj->value.ov = container;
1173290071Sbapt	parser->cur_obj = nobj;
1174298166Sbapt	ucl_attach_comment (parser, nobj, false);
1175290071Sbapt
1176290071Sbapt	return true;
1177290071Sbapt}
1178290071Sbapt
1179262395Sbapt/**
1180262395Sbapt * Parse a key in an object
1181262395Sbapt * @param parser
1182262395Sbapt * @param chunk
1183290071Sbapt * @param next_key
1184290071Sbapt * @param end_of_object
1185262395Sbapt * @return true if a key has been parsed
1186262395Sbapt */
1187262395Sbaptstatic bool
1188290071Sbaptucl_parse_key (struct ucl_parser *parser, struct ucl_chunk *chunk,
1189290071Sbapt		bool *next_key, bool *end_of_object)
1190262395Sbapt{
1191262395Sbapt	const unsigned char *p, *c = NULL, *end, *t;
1192262395Sbapt	const char *key = NULL;
1193262395Sbapt	bool got_quote = false, got_eq = false, got_semicolon = false,
1194262395Sbapt			need_unescape = false, ucl_escape = false, var_expand = false,
1195262395Sbapt			got_content = false, got_sep = false;
1196290071Sbapt	ucl_object_t *nobj;
1197262395Sbapt	ssize_t keylen;
1198262395Sbapt
1199262395Sbapt	p = chunk->pos;
1200262395Sbapt
1201262395Sbapt	if (*p == '.') {
1202262395Sbapt		/* It is macro actually */
1203298166Sbapt		if (!(parser->flags & UCL_PARSER_DISABLE_MACRO)) {
1204298166Sbapt			ucl_chunk_skipc (chunk, p);
1205298166Sbapt		}
1206298166Sbapt
1207262395Sbapt		parser->prev_state = parser->state;
1208262395Sbapt		parser->state = UCL_STATE_MACRO_NAME;
1209279549Sbapt		*end_of_object = false;
1210262395Sbapt		return true;
1211262395Sbapt	}
1212262395Sbapt	while (p < chunk->end) {
1213262395Sbapt		/*
1214262395Sbapt		 * A key must start with alpha, number, '/' or '_' and end with space character
1215262395Sbapt		 */
1216262395Sbapt		if (c == NULL) {
1217262395Sbapt			if (chunk->remain >= 2 && ucl_lex_is_comment (p[0], p[1])) {
1218262395Sbapt				if (!ucl_skip_comments (parser)) {
1219262395Sbapt					return false;
1220262395Sbapt				}
1221262395Sbapt				p = chunk->pos;
1222262395Sbapt			}
1223262395Sbapt			else if (ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE)) {
1224262395Sbapt				ucl_chunk_skipc (chunk, p);
1225262395Sbapt			}
1226262395Sbapt			else if (ucl_test_character (*p, UCL_CHARACTER_KEY_START)) {
1227262395Sbapt				/* The first symbol */
1228262395Sbapt				c = p;
1229262395Sbapt				ucl_chunk_skipc (chunk, p);
1230262395Sbapt				got_content = true;
1231262395Sbapt			}
1232262395Sbapt			else if (*p == '"') {
1233262395Sbapt				/* JSON style key */
1234262395Sbapt				c = p + 1;
1235262395Sbapt				got_quote = true;
1236262395Sbapt				got_content = true;
1237262395Sbapt				ucl_chunk_skipc (chunk, p);
1238262395Sbapt			}
1239262395Sbapt			else if (*p == '}') {
1240262395Sbapt				/* We have actually end of an object */
1241262395Sbapt				*end_of_object = true;
1242262395Sbapt				return true;
1243262395Sbapt			}
1244262395Sbapt			else if (*p == '.') {
1245262395Sbapt				ucl_chunk_skipc (chunk, p);
1246262395Sbapt				parser->prev_state = parser->state;
1247262395Sbapt				parser->state = UCL_STATE_MACRO_NAME;
1248262395Sbapt				return true;
1249262395Sbapt			}
1250262395Sbapt			else {
1251262395Sbapt				/* Invalid identifier */
1252275223Sbapt				ucl_set_err (parser, UCL_ESYNTAX, "key must begin with a letter",
1253275223Sbapt						&parser->err);
1254262395Sbapt				return false;
1255262395Sbapt			}
1256262395Sbapt		}
1257262395Sbapt		else {
1258262395Sbapt			/* Parse the body of a key */
1259262395Sbapt			if (!got_quote) {
1260262395Sbapt				if (ucl_test_character (*p, UCL_CHARACTER_KEY)) {
1261262395Sbapt					got_content = true;
1262262395Sbapt					ucl_chunk_skipc (chunk, p);
1263262395Sbapt				}
1264262395Sbapt				else if (ucl_test_character (*p, UCL_CHARACTER_KEY_SEP)) {
1265262395Sbapt					end = p;
1266262395Sbapt					break;
1267262395Sbapt				}
1268262395Sbapt				else {
1269275223Sbapt					ucl_set_err (parser, UCL_ESYNTAX, "invalid character in a key",
1270275223Sbapt							&parser->err);
1271262395Sbapt					return false;
1272262395Sbapt				}
1273262395Sbapt			}
1274262395Sbapt			else {
1275262395Sbapt				/* We need to parse json like quoted string */
1276262395Sbapt				if (!ucl_lex_json_string (parser, chunk, &need_unescape, &ucl_escape, &var_expand)) {
1277262395Sbapt					return false;
1278262395Sbapt				}
1279262395Sbapt				/* Always escape keys obtained via json */
1280262395Sbapt				end = chunk->pos - 1;
1281262395Sbapt				p = chunk->pos;
1282262395Sbapt				break;
1283262395Sbapt			}
1284262395Sbapt		}
1285262395Sbapt	}
1286262395Sbapt
1287262395Sbapt	if (p >= chunk->end && got_content) {
1288275223Sbapt		ucl_set_err (parser, UCL_ESYNTAX, "unfinished key", &parser->err);
1289262395Sbapt		return false;
1290262395Sbapt	}
1291262395Sbapt	else if (!got_content) {
1292262395Sbapt		return true;
1293262395Sbapt	}
1294262395Sbapt	*end_of_object = false;
1295262395Sbapt	/* We are now at the end of the key, need to parse the rest */
1296262395Sbapt	while (p < chunk->end) {
1297262395Sbapt		if (ucl_test_character (*p, UCL_CHARACTER_WHITESPACE)) {
1298262395Sbapt			ucl_chunk_skipc (chunk, p);
1299262395Sbapt		}
1300262395Sbapt		else if (*p == '=') {
1301262395Sbapt			if (!got_eq && !got_semicolon) {
1302262395Sbapt				ucl_chunk_skipc (chunk, p);
1303262395Sbapt				got_eq = true;
1304262395Sbapt			}
1305262395Sbapt			else {
1306275223Sbapt				ucl_set_err (parser, UCL_ESYNTAX, "unexpected '=' character",
1307275223Sbapt						&parser->err);
1308262395Sbapt				return false;
1309262395Sbapt			}
1310262395Sbapt		}
1311262395Sbapt		else if (*p == ':') {
1312262395Sbapt			if (!got_eq && !got_semicolon) {
1313262395Sbapt				ucl_chunk_skipc (chunk, p);
1314262395Sbapt				got_semicolon = true;
1315262395Sbapt			}
1316262395Sbapt			else {
1317275223Sbapt				ucl_set_err (parser, UCL_ESYNTAX, "unexpected ':' character",
1318275223Sbapt						&parser->err);
1319262395Sbapt				return false;
1320262395Sbapt			}
1321262395Sbapt		}
1322262395Sbapt		else if (chunk->remain >= 2 && ucl_lex_is_comment (p[0], p[1])) {
1323262395Sbapt			/* Check for comment */
1324262395Sbapt			if (!ucl_skip_comments (parser)) {
1325262395Sbapt				return false;
1326262395Sbapt			}
1327262395Sbapt			p = chunk->pos;
1328262395Sbapt		}
1329262395Sbapt		else {
1330262395Sbapt			/* Start value */
1331262395Sbapt			break;
1332262395Sbapt		}
1333262395Sbapt	}
1334262395Sbapt
1335262395Sbapt	if (p >= chunk->end && got_content) {
1336275223Sbapt		ucl_set_err (parser, UCL_ESYNTAX, "unfinished key", &parser->err);
1337262395Sbapt		return false;
1338262395Sbapt	}
1339262395Sbapt
1340262395Sbapt	got_sep = got_semicolon || got_eq;
1341262395Sbapt
1342262395Sbapt	if (!got_sep) {
1343262395Sbapt		/*
1344262395Sbapt		 * Maybe we have more keys nested, so search for termination character.
1345262395Sbapt		 * Possible choices:
1346262395Sbapt		 * 1) key1 key2 ... keyN [:=] value <- we treat that as error
1347262395Sbapt		 * 2) key1 ... keyN {} or [] <- we treat that as nested objects
1348262395Sbapt		 * 3) key1 value[;,\n] <- we treat that as linear object
1349262395Sbapt		 */
1350262395Sbapt		t = p;
1351262395Sbapt		*next_key = false;
1352262395Sbapt		while (ucl_test_character (*t, UCL_CHARACTER_WHITESPACE)) {
1353262395Sbapt			t ++;
1354262395Sbapt		}
1355262395Sbapt		/* Check first non-space character after a key */
1356262395Sbapt		if (*t != '{' && *t != '[') {
1357262395Sbapt			while (t < chunk->end) {
1358262395Sbapt				if (*t == ',' || *t == ';' || *t == '\n' || *t == '\r') {
1359262395Sbapt					break;
1360262395Sbapt				}
1361262395Sbapt				else if (*t == '{' || *t == '[') {
1362262395Sbapt					*next_key = true;
1363262395Sbapt					break;
1364262395Sbapt				}
1365262395Sbapt				t ++;
1366262395Sbapt			}
1367262395Sbapt		}
1368262395Sbapt	}
1369262395Sbapt
1370262395Sbapt	/* Create a new object */
1371275223Sbapt	nobj = ucl_object_new_full (UCL_NULL, parser->chunks->priority);
1372262395Sbapt	keylen = ucl_copy_or_store_ptr (parser, c, &nobj->trash_stack[UCL_TRASH_KEY],
1373262395Sbapt			&key, end - c, need_unescape, parser->flags & UCL_PARSER_KEY_LOWERCASE, false);
1374262395Sbapt	if (keylen == -1) {
1375264789Sbapt		ucl_object_unref (nobj);
1376262395Sbapt		return false;
1377262395Sbapt	}
1378262395Sbapt	else if (keylen == 0) {
1379275223Sbapt		ucl_set_err (parser, UCL_ESYNTAX, "empty keys are not allowed", &parser->err);
1380264789Sbapt		ucl_object_unref (nobj);
1381262395Sbapt		return false;
1382262395Sbapt	}
1383262395Sbapt
1384262395Sbapt	nobj->key = key;
1385262395Sbapt	nobj->keylen = keylen;
1386290071Sbapt
1387290071Sbapt	if (!ucl_parser_process_object_element (parser, nobj)) {
1388290071Sbapt		return false;
1389262395Sbapt	}
1390262395Sbapt
1391262395Sbapt	if (ucl_escape) {
1392262395Sbapt		nobj->flags |= UCL_OBJECT_NEED_KEY_ESCAPE;
1393262395Sbapt	}
1394262395Sbapt
1395262395Sbapt
1396262395Sbapt	return true;
1397262395Sbapt}
1398262395Sbapt
1399262395Sbapt/**
1400262395Sbapt * Parse a cl string
1401262395Sbapt * @param parser
1402262395Sbapt * @param chunk
1403290071Sbapt * @param var_expand
1404290071Sbapt * @param need_unescape
1405262395Sbapt * @return true if a key has been parsed
1406262395Sbapt */
1407262395Sbaptstatic bool
1408262395Sbaptucl_parse_string_value (struct ucl_parser *parser,
1409262395Sbapt		struct ucl_chunk *chunk, bool *var_expand, bool *need_unescape)
1410262395Sbapt{
1411262395Sbapt	const unsigned char *p;
1412262395Sbapt	enum {
1413262395Sbapt		UCL_BRACE_ROUND = 0,
1414262395Sbapt		UCL_BRACE_SQUARE,
1415262395Sbapt		UCL_BRACE_FIGURE
1416262395Sbapt	};
1417262395Sbapt	int braces[3][2] = {{0, 0}, {0, 0}, {0, 0}};
1418262395Sbapt
1419262395Sbapt	p = chunk->pos;
1420262395Sbapt
1421262395Sbapt	while (p < chunk->end) {
1422262395Sbapt
1423262395Sbapt		/* Skip pairs of figure braces */
1424262395Sbapt		if (*p == '{') {
1425262395Sbapt			braces[UCL_BRACE_FIGURE][0] ++;
1426262395Sbapt		}
1427262395Sbapt		else if (*p == '}') {
1428262395Sbapt			braces[UCL_BRACE_FIGURE][1] ++;
1429262395Sbapt			if (braces[UCL_BRACE_FIGURE][1] <= braces[UCL_BRACE_FIGURE][0]) {
1430262395Sbapt				/* This is not a termination symbol, continue */
1431262395Sbapt				ucl_chunk_skipc (chunk, p);
1432262395Sbapt				continue;
1433262395Sbapt			}
1434262395Sbapt		}
1435262395Sbapt		/* Skip pairs of square braces */
1436262395Sbapt		else if (*p == '[') {
1437262395Sbapt			braces[UCL_BRACE_SQUARE][0] ++;
1438262395Sbapt		}
1439262395Sbapt		else if (*p == ']') {
1440262395Sbapt			braces[UCL_BRACE_SQUARE][1] ++;
1441262395Sbapt			if (braces[UCL_BRACE_SQUARE][1] <= braces[UCL_BRACE_SQUARE][0]) {
1442262395Sbapt				/* This is not a termination symbol, continue */
1443262395Sbapt				ucl_chunk_skipc (chunk, p);
1444262395Sbapt				continue;
1445262395Sbapt			}
1446262395Sbapt		}
1447262395Sbapt		else if (*p == '$') {
1448262395Sbapt			*var_expand = true;
1449262395Sbapt		}
1450262395Sbapt		else if (*p == '\\') {
1451262395Sbapt			*need_unescape = true;
1452262395Sbapt			ucl_chunk_skipc (chunk, p);
1453262395Sbapt			if (p < chunk->end) {
1454262395Sbapt				ucl_chunk_skipc (chunk, p);
1455262395Sbapt			}
1456262395Sbapt			continue;
1457262395Sbapt		}
1458262395Sbapt
1459262395Sbapt		if (ucl_lex_is_atom_end (*p) || (chunk->remain >= 2 && ucl_lex_is_comment (p[0], p[1]))) {
1460262395Sbapt			break;
1461262395Sbapt		}
1462262395Sbapt		ucl_chunk_skipc (chunk, p);
1463262395Sbapt	}
1464262395Sbapt
1465262395Sbapt	return true;
1466262395Sbapt}
1467262395Sbapt
1468262395Sbapt/**
1469262395Sbapt * Parse multiline string ending with \n{term}\n
1470262395Sbapt * @param parser
1471262395Sbapt * @param chunk
1472262395Sbapt * @param term
1473262395Sbapt * @param term_len
1474290071Sbapt * @param beg
1475290071Sbapt * @param var_expand
1476262395Sbapt * @return size of multiline string or 0 in case of error
1477262395Sbapt */
1478262395Sbaptstatic int
1479262395Sbaptucl_parse_multiline_string (struct ucl_parser *parser,
1480262395Sbapt		struct ucl_chunk *chunk, const unsigned char *term,
1481262395Sbapt		int term_len, unsigned char const **beg,
1482262395Sbapt		bool *var_expand)
1483262395Sbapt{
1484275223Sbapt	const unsigned char *p, *c, *tend;
1485262395Sbapt	bool newline = false;
1486262395Sbapt	int len = 0;
1487262395Sbapt
1488262395Sbapt	p = chunk->pos;
1489262395Sbapt
1490262395Sbapt	c = p;
1491262395Sbapt
1492262395Sbapt	while (p < chunk->end) {
1493262395Sbapt		if (newline) {
1494262395Sbapt			if (chunk->end - p < term_len) {
1495262395Sbapt				return 0;
1496262395Sbapt			}
1497275223Sbapt			else if (memcmp (p, term, term_len) == 0) {
1498275223Sbapt				tend = p + term_len;
1499275223Sbapt				if (*tend != '\n' && *tend != ';' && *tend != ',') {
1500275223Sbapt					/* Incomplete terminator */
1501275223Sbapt					ucl_chunk_skipc (chunk, p);
1502275223Sbapt					continue;
1503275223Sbapt				}
1504262395Sbapt				len = p - c;
1505262395Sbapt				chunk->remain -= term_len;
1506262395Sbapt				chunk->pos = p + term_len;
1507262395Sbapt				chunk->column = term_len;
1508262395Sbapt				*beg = c;
1509262395Sbapt				break;
1510262395Sbapt			}
1511262395Sbapt		}
1512262395Sbapt		if (*p == '\n') {
1513262395Sbapt			newline = true;
1514262395Sbapt		}
1515262395Sbapt		else {
1516262395Sbapt			if (*p == '$') {
1517262395Sbapt				*var_expand = true;
1518262395Sbapt			}
1519262395Sbapt			newline = false;
1520262395Sbapt		}
1521262395Sbapt		ucl_chunk_skipc (chunk, p);
1522262395Sbapt	}
1523262395Sbapt
1524262395Sbapt	return len;
1525262395Sbapt}
1526262395Sbapt
1527290071Sbaptstatic inline ucl_object_t*
1528290071Sbaptucl_parser_get_container (struct ucl_parser *parser)
1529262975Sbapt{
1530262975Sbapt	ucl_object_t *t, *obj = NULL;
1531262975Sbapt
1532279549Sbapt	if (parser == NULL || parser->stack == NULL || parser->stack->obj == NULL) {
1533279549Sbapt		return NULL;
1534279549Sbapt	}
1535279549Sbapt
1536262975Sbapt	if (parser->stack->obj->type == UCL_ARRAY) {
1537262975Sbapt		/* Object must be allocated */
1538275223Sbapt		obj = ucl_object_new_full (UCL_NULL, parser->chunks->priority);
1539279549Sbapt		t = parser->stack->obj;
1540290071Sbapt
1541290071Sbapt		if (!ucl_array_append (t, obj)) {
1542290071Sbapt			ucl_object_unref (obj);
1543290071Sbapt			return NULL;
1544290071Sbapt		}
1545290071Sbapt
1546262975Sbapt		parser->cur_obj = obj;
1547298166Sbapt		ucl_attach_comment (parser, obj, false);
1548262975Sbapt	}
1549262975Sbapt	else {
1550262975Sbapt		/* Object has been already allocated */
1551262975Sbapt		obj = parser->cur_obj;
1552262975Sbapt	}
1553262975Sbapt
1554262975Sbapt	return obj;
1555262975Sbapt}
1556262975Sbapt
1557262395Sbapt/**
1558262395Sbapt * Handle value data
1559262395Sbapt * @param parser
1560262395Sbapt * @param chunk
1561262395Sbapt * @return
1562262395Sbapt */
1563262395Sbaptstatic bool
1564262395Sbaptucl_parse_value (struct ucl_parser *parser, struct ucl_chunk *chunk)
1565262395Sbapt{
1566262395Sbapt	const unsigned char *p, *c;
1567262975Sbapt	ucl_object_t *obj = NULL;
1568262395Sbapt	unsigned int stripped_spaces;
1569262395Sbapt	int str_len;
1570262395Sbapt	bool need_unescape = false, ucl_escape = false, var_expand = false;
1571262395Sbapt
1572262395Sbapt	p = chunk->pos;
1573262395Sbapt
1574262975Sbapt	/* Skip any spaces and comments */
1575262975Sbapt	if (ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE) ||
1576262975Sbapt			(chunk->remain >= 2 && ucl_lex_is_comment (p[0], p[1]))) {
1577262975Sbapt		while (p < chunk->end && ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE)) {
1578262975Sbapt			ucl_chunk_skipc (chunk, p);
1579262975Sbapt		}
1580262975Sbapt		if (!ucl_skip_comments (parser)) {
1581262975Sbapt			return false;
1582262975Sbapt		}
1583262975Sbapt		p = chunk->pos;
1584262975Sbapt	}
1585262975Sbapt
1586262395Sbapt	while (p < chunk->end) {
1587262395Sbapt		c = p;
1588262395Sbapt		switch (*p) {
1589262395Sbapt		case '"':
1590262395Sbapt			ucl_chunk_skipc (chunk, p);
1591290071Sbapt
1592290071Sbapt			if (!ucl_lex_json_string (parser, chunk, &need_unescape, &ucl_escape,
1593290071Sbapt					&var_expand)) {
1594262395Sbapt				return false;
1595262395Sbapt			}
1596290071Sbapt
1597290071Sbapt			obj = ucl_parser_get_container (parser);
1598298166Sbapt			if (!obj) {
1599298166Sbapt				return false;
1600298166Sbapt			}
1601298166Sbapt
1602262395Sbapt			str_len = chunk->pos - c - 2;
1603262395Sbapt			obj->type = UCL_STRING;
1604290071Sbapt			if ((str_len = ucl_copy_or_store_ptr (parser, c + 1,
1605290071Sbapt					&obj->trash_stack[UCL_TRASH_VALUE],
1606290071Sbapt					&obj->value.sv, str_len, need_unescape, false,
1607290071Sbapt					var_expand)) == -1) {
1608262395Sbapt				return false;
1609262395Sbapt			}
1610262395Sbapt			obj->len = str_len;
1611290071Sbapt
1612262395Sbapt			parser->state = UCL_STATE_AFTER_VALUE;
1613262395Sbapt			p = chunk->pos;
1614290071Sbapt
1615262395Sbapt			return true;
1616262395Sbapt			break;
1617262395Sbapt		case '{':
1618290071Sbapt			obj = ucl_parser_get_container (parser);
1619262395Sbapt			/* We have a new object */
1620290071Sbapt			obj = ucl_parser_add_container (obj, parser, false, parser->stack->level);
1621263648Sbapt			if (obj == NULL) {
1622263648Sbapt				return false;
1623263648Sbapt			}
1624262395Sbapt
1625262395Sbapt			ucl_chunk_skipc (chunk, p);
1626290071Sbapt
1627262395Sbapt			return true;
1628262395Sbapt			break;
1629262395Sbapt		case '[':
1630290071Sbapt			obj = ucl_parser_get_container (parser);
1631262395Sbapt			/* We have a new array */
1632290071Sbapt			obj = ucl_parser_add_container (obj, parser, true, parser->stack->level);
1633263648Sbapt			if (obj == NULL) {
1634263648Sbapt				return false;
1635263648Sbapt			}
1636262395Sbapt
1637262395Sbapt			ucl_chunk_skipc (chunk, p);
1638290071Sbapt
1639262395Sbapt			return true;
1640262395Sbapt			break;
1641262975Sbapt		case ']':
1642262975Sbapt			/* We have the array ending */
1643262975Sbapt			if (parser->stack && parser->stack->obj->type == UCL_ARRAY) {
1644262975Sbapt				parser->state = UCL_STATE_AFTER_VALUE;
1645262975Sbapt				return true;
1646262975Sbapt			}
1647262975Sbapt			else {
1648262975Sbapt				goto parse_string;
1649262975Sbapt			}
1650262975Sbapt			break;
1651262395Sbapt		case '<':
1652290071Sbapt			obj = ucl_parser_get_container (parser);
1653262395Sbapt			/* We have something like multiline value, which must be <<[A-Z]+\n */
1654262395Sbapt			if (chunk->end - p > 3) {
1655262395Sbapt				if (memcmp (p, "<<", 2) == 0) {
1656262395Sbapt					p += 2;
1657262395Sbapt					/* We allow only uppercase characters in multiline definitions */
1658262395Sbapt					while (p < chunk->end && *p >= 'A' && *p <= 'Z') {
1659262395Sbapt						p ++;
1660262395Sbapt					}
1661262395Sbapt					if (*p =='\n') {
1662262395Sbapt						/* Set chunk positions and start multiline parsing */
1663262395Sbapt						c += 2;
1664262395Sbapt						chunk->remain -= p - c;
1665262395Sbapt						chunk->pos = p + 1;
1666262395Sbapt						chunk->column = 0;
1667262395Sbapt						chunk->line ++;
1668262395Sbapt						if ((str_len = ucl_parse_multiline_string (parser, chunk, c,
1669262395Sbapt								p - c, &c, &var_expand)) == 0) {
1670275223Sbapt							ucl_set_err (parser, UCL_ESYNTAX,
1671275223Sbapt									"unterminated multiline value", &parser->err);
1672262395Sbapt							return false;
1673262395Sbapt						}
1674290071Sbapt
1675262395Sbapt						obj->type = UCL_STRING;
1676290071Sbapt						obj->flags |= UCL_OBJECT_MULTILINE;
1677290071Sbapt						if ((str_len = ucl_copy_or_store_ptr (parser, c,
1678290071Sbapt								&obj->trash_stack[UCL_TRASH_VALUE],
1679290071Sbapt								&obj->value.sv, str_len - 1, false,
1680290071Sbapt								false, var_expand)) == -1) {
1681262395Sbapt							return false;
1682262395Sbapt						}
1683262395Sbapt						obj->len = str_len;
1684290071Sbapt
1685262395Sbapt						parser->state = UCL_STATE_AFTER_VALUE;
1686290071Sbapt
1687262395Sbapt						return true;
1688262395Sbapt					}
1689262395Sbapt				}
1690262395Sbapt			}
1691262395Sbapt			/* Fallback to ordinary strings */
1692262395Sbapt		default:
1693262975Sbaptparse_string:
1694262975Sbapt			if (obj == NULL) {
1695290071Sbapt				obj = ucl_parser_get_container (parser);
1696262395Sbapt			}
1697290071Sbapt
1698262395Sbapt			/* Parse atom */
1699262395Sbapt			if (ucl_test_character (*p, UCL_CHARACTER_VALUE_DIGIT_START)) {
1700262395Sbapt				if (!ucl_lex_number (parser, chunk, obj)) {
1701262395Sbapt					if (parser->state == UCL_STATE_ERROR) {
1702262395Sbapt						return false;
1703262395Sbapt					}
1704262395Sbapt				}
1705262395Sbapt				else {
1706262395Sbapt					parser->state = UCL_STATE_AFTER_VALUE;
1707262395Sbapt					return true;
1708262395Sbapt				}
1709262395Sbapt				/* Fallback to normal string */
1710262395Sbapt			}
1711262395Sbapt
1712290071Sbapt			if (!ucl_parse_string_value (parser, chunk, &var_expand,
1713290071Sbapt					&need_unescape)) {
1714262395Sbapt				return false;
1715262395Sbapt			}
1716262395Sbapt			/* Cut trailing spaces */
1717262395Sbapt			stripped_spaces = 0;
1718262395Sbapt			while (ucl_test_character (*(chunk->pos - 1 - stripped_spaces),
1719262395Sbapt					UCL_CHARACTER_WHITESPACE)) {
1720262395Sbapt				stripped_spaces ++;
1721262395Sbapt			}
1722262395Sbapt			str_len = chunk->pos - c - stripped_spaces;
1723262395Sbapt			if (str_len <= 0) {
1724290071Sbapt				ucl_set_err (parser, UCL_ESYNTAX, "string value must not be empty",
1725275223Sbapt						&parser->err);
1726262395Sbapt				return false;
1727262395Sbapt			}
1728262395Sbapt			else if (str_len == 4 && memcmp (c, "null", 4) == 0) {
1729262395Sbapt				obj->len = 0;
1730262395Sbapt				obj->type = UCL_NULL;
1731262395Sbapt			}
1732262395Sbapt			else if (!ucl_maybe_parse_boolean (obj, c, str_len)) {
1733262395Sbapt				obj->type = UCL_STRING;
1734290071Sbapt				if ((str_len = ucl_copy_or_store_ptr (parser, c,
1735290071Sbapt						&obj->trash_stack[UCL_TRASH_VALUE],
1736262395Sbapt						&obj->value.sv, str_len, need_unescape,
1737262395Sbapt						false, var_expand)) == -1) {
1738262395Sbapt					return false;
1739262395Sbapt				}
1740262395Sbapt				obj->len = str_len;
1741262395Sbapt			}
1742262395Sbapt			parser->state = UCL_STATE_AFTER_VALUE;
1743262395Sbapt			p = chunk->pos;
1744262395Sbapt
1745262395Sbapt			return true;
1746262395Sbapt			break;
1747262395Sbapt		}
1748262395Sbapt	}
1749262395Sbapt
1750262395Sbapt	return true;
1751262395Sbapt}
1752262395Sbapt
1753262395Sbapt/**
1754262395Sbapt * Handle after value data
1755262395Sbapt * @param parser
1756262395Sbapt * @param chunk
1757262395Sbapt * @return
1758262395Sbapt */
1759262395Sbaptstatic bool
1760262395Sbaptucl_parse_after_value (struct ucl_parser *parser, struct ucl_chunk *chunk)
1761262395Sbapt{
1762262395Sbapt	const unsigned char *p;
1763262395Sbapt	bool got_sep = false;
1764262395Sbapt	struct ucl_stack *st;
1765262395Sbapt
1766262395Sbapt	p = chunk->pos;
1767262395Sbapt
1768262395Sbapt	while (p < chunk->end) {
1769262395Sbapt		if (ucl_test_character (*p, UCL_CHARACTER_WHITESPACE)) {
1770262395Sbapt			/* Skip whitespaces */
1771262395Sbapt			ucl_chunk_skipc (chunk, p);
1772262395Sbapt		}
1773262395Sbapt		else if (chunk->remain >= 2 && ucl_lex_is_comment (p[0], p[1])) {
1774262395Sbapt			/* Skip comment */
1775262395Sbapt			if (!ucl_skip_comments (parser)) {
1776262395Sbapt				return false;
1777262395Sbapt			}
1778262395Sbapt			/* Treat comment as a separator */
1779262395Sbapt			got_sep = true;
1780262395Sbapt			p = chunk->pos;
1781262395Sbapt		}
1782262395Sbapt		else if (ucl_test_character (*p, UCL_CHARACTER_VALUE_END)) {
1783262395Sbapt			if (*p == '}' || *p == ']') {
1784262395Sbapt				if (parser->stack == NULL) {
1785275223Sbapt					ucl_set_err (parser, UCL_ESYNTAX,
1786275223Sbapt							"end of array or object detected without corresponding start",
1787275223Sbapt							&parser->err);
1788262395Sbapt					return false;
1789262395Sbapt				}
1790262395Sbapt				if ((*p == '}' && parser->stack->obj->type == UCL_OBJECT) ||
1791262395Sbapt						(*p == ']' && parser->stack->obj->type == UCL_ARRAY)) {
1792262395Sbapt
1793262395Sbapt					/* Pop all nested objects from a stack */
1794262395Sbapt					st = parser->stack;
1795262395Sbapt					parser->stack = st->next;
1796262395Sbapt					UCL_FREE (sizeof (struct ucl_stack), st);
1797262395Sbapt
1798298166Sbapt					if (parser->cur_obj) {
1799298166Sbapt						ucl_attach_comment (parser, parser->cur_obj, true);
1800298166Sbapt					}
1801298166Sbapt
1802262395Sbapt					while (parser->stack != NULL) {
1803262395Sbapt						st = parser->stack;
1804298166Sbapt
1805262395Sbapt						if (st->next == NULL || st->next->level == st->level) {
1806262395Sbapt							break;
1807262395Sbapt						}
1808298166Sbapt
1809262395Sbapt						parser->stack = st->next;
1810298166Sbapt						parser->cur_obj = st->obj;
1811262395Sbapt						UCL_FREE (sizeof (struct ucl_stack), st);
1812262395Sbapt					}
1813262395Sbapt				}
1814262395Sbapt				else {
1815275223Sbapt					ucl_set_err (parser, UCL_ESYNTAX,
1816275223Sbapt							"unexpected terminating symbol detected",
1817275223Sbapt							&parser->err);
1818262395Sbapt					return false;
1819262395Sbapt				}
1820262395Sbapt
1821262395Sbapt				if (parser->stack == NULL) {
1822262395Sbapt					/* Ignore everything after a top object */
1823262395Sbapt					return true;
1824262395Sbapt				}
1825262395Sbapt				else {
1826262395Sbapt					ucl_chunk_skipc (chunk, p);
1827262395Sbapt				}
1828262395Sbapt				got_sep = true;
1829262395Sbapt			}
1830262395Sbapt			else {
1831262395Sbapt				/* Got a separator */
1832262395Sbapt				got_sep = true;
1833262395Sbapt				ucl_chunk_skipc (chunk, p);
1834262395Sbapt			}
1835262395Sbapt		}
1836262395Sbapt		else {
1837262395Sbapt			/* Anything else */
1838262395Sbapt			if (!got_sep) {
1839275223Sbapt				ucl_set_err (parser, UCL_ESYNTAX, "delimiter is missing",
1840275223Sbapt						&parser->err);
1841262395Sbapt				return false;
1842262395Sbapt			}
1843262395Sbapt			return true;
1844262395Sbapt		}
1845262395Sbapt	}
1846262395Sbapt
1847262395Sbapt	return true;
1848262395Sbapt}
1849262395Sbapt
1850298166Sbaptstatic bool
1851298166Sbaptucl_skip_macro_as_comment (struct ucl_parser *parser,
1852298166Sbapt		struct ucl_chunk *chunk)
1853298166Sbapt{
1854298166Sbapt	const unsigned char *p, *c;
1855298166Sbapt	enum {
1856298166Sbapt		macro_skip_start = 0,
1857298166Sbapt		macro_has_symbols,
1858298166Sbapt		macro_has_obrace,
1859298166Sbapt		macro_has_quote,
1860298166Sbapt		macro_has_backslash,
1861298166Sbapt		macro_has_sqbrace,
1862298166Sbapt		macro_save
1863298166Sbapt	} state = macro_skip_start, prev_state = macro_skip_start;
1864298166Sbapt
1865298166Sbapt	p = chunk->pos;
1866298166Sbapt	c = chunk->pos;
1867298166Sbapt
1868298166Sbapt	while (p < chunk->end) {
1869298166Sbapt		switch (state) {
1870298166Sbapt		case macro_skip_start:
1871298166Sbapt			if (!ucl_test_character (*p, UCL_CHARACTER_WHITESPACE)) {
1872298166Sbapt				state = macro_has_symbols;
1873298166Sbapt			}
1874298166Sbapt			else if (ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE)) {
1875298166Sbapt				state = macro_save;
1876298166Sbapt				continue;
1877298166Sbapt			}
1878298166Sbapt
1879298166Sbapt			ucl_chunk_skipc (chunk, p);
1880298166Sbapt			break;
1881298166Sbapt
1882298166Sbapt		case macro_has_symbols:
1883298166Sbapt			if (*p == '{') {
1884298166Sbapt				state = macro_has_sqbrace;
1885298166Sbapt			}
1886298166Sbapt			else if (*p == '(') {
1887298166Sbapt				state = macro_has_obrace;
1888298166Sbapt			}
1889298166Sbapt			else if (*p == '"') {
1890298166Sbapt				state = macro_has_quote;
1891298166Sbapt			}
1892298166Sbapt			else if (*p == '\n') {
1893298166Sbapt				state = macro_save;
1894298166Sbapt				continue;
1895298166Sbapt			}
1896298166Sbapt
1897298166Sbapt			ucl_chunk_skipc (chunk, p);
1898298166Sbapt			break;
1899298166Sbapt
1900298166Sbapt		case macro_has_obrace:
1901298166Sbapt			if (*p == '\\') {
1902298166Sbapt				prev_state = state;
1903298166Sbapt				state = macro_has_backslash;
1904298166Sbapt			}
1905298166Sbapt			else if (*p == ')') {
1906298166Sbapt				state = macro_has_symbols;
1907298166Sbapt			}
1908298166Sbapt
1909298166Sbapt			ucl_chunk_skipc (chunk, p);
1910298166Sbapt			break;
1911298166Sbapt
1912298166Sbapt		case macro_has_sqbrace:
1913298166Sbapt			if (*p == '\\') {
1914298166Sbapt				prev_state = state;
1915298166Sbapt				state = macro_has_backslash;
1916298166Sbapt			}
1917298166Sbapt			else if (*p == '}') {
1918298166Sbapt				state = macro_save;
1919298166Sbapt			}
1920298166Sbapt
1921298166Sbapt			ucl_chunk_skipc (chunk, p);
1922298166Sbapt			break;
1923298166Sbapt
1924298166Sbapt		case macro_has_quote:
1925298166Sbapt			if (*p == '\\') {
1926298166Sbapt				prev_state = state;
1927298166Sbapt				state = macro_has_backslash;
1928298166Sbapt			}
1929298166Sbapt			else if (*p == '"') {
1930298166Sbapt				state = macro_save;
1931298166Sbapt			}
1932298166Sbapt
1933298166Sbapt			ucl_chunk_skipc (chunk, p);
1934298166Sbapt			break;
1935298166Sbapt
1936298166Sbapt		case macro_has_backslash:
1937298166Sbapt			state = prev_state;
1938298166Sbapt			ucl_chunk_skipc (chunk, p);
1939298166Sbapt			break;
1940298166Sbapt
1941298166Sbapt		case macro_save:
1942298166Sbapt			if (parser->flags & UCL_PARSER_SAVE_COMMENTS) {
1943298166Sbapt				ucl_save_comment (parser, c, p - c);
1944298166Sbapt			}
1945298166Sbapt
1946298166Sbapt			return true;
1947298166Sbapt		}
1948298166Sbapt	}
1949298166Sbapt
1950298166Sbapt	return false;
1951298166Sbapt}
1952298166Sbapt
1953262395Sbapt/**
1954262395Sbapt * Handle macro data
1955262395Sbapt * @param parser
1956262395Sbapt * @param chunk
1957290071Sbapt * @param marco
1958290071Sbapt * @param macro_start
1959290071Sbapt * @param macro_len
1960262395Sbapt * @return
1961262395Sbapt */
1962262395Sbaptstatic bool
1963262395Sbaptucl_parse_macro_value (struct ucl_parser *parser,
1964262395Sbapt		struct ucl_chunk *chunk, struct ucl_macro *macro,
1965262395Sbapt		unsigned char const **macro_start, size_t *macro_len)
1966262395Sbapt{
1967262395Sbapt	const unsigned char *p, *c;
1968262395Sbapt	bool need_unescape = false, ucl_escape = false, var_expand = false;
1969262395Sbapt
1970262395Sbapt	p = chunk->pos;
1971262395Sbapt
1972262395Sbapt	switch (*p) {
1973262395Sbapt	case '"':
1974262395Sbapt		/* We have macro value encoded in quotes */
1975262395Sbapt		c = p;
1976262395Sbapt		ucl_chunk_skipc (chunk, p);
1977262395Sbapt		if (!ucl_lex_json_string (parser, chunk, &need_unescape, &ucl_escape, &var_expand)) {
1978262395Sbapt			return false;
1979262395Sbapt		}
1980262395Sbapt
1981262395Sbapt		*macro_start = c + 1;
1982262395Sbapt		*macro_len = chunk->pos - c - 2;
1983262395Sbapt		p = chunk->pos;
1984262395Sbapt		break;
1985262395Sbapt	case '{':
1986262395Sbapt		/* We got a multiline macro body */
1987262395Sbapt		ucl_chunk_skipc (chunk, p);
1988262395Sbapt		/* Skip spaces at the beginning */
1989262395Sbapt		while (p < chunk->end) {
1990262395Sbapt			if (ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE)) {
1991262395Sbapt				ucl_chunk_skipc (chunk, p);
1992262395Sbapt			}
1993262395Sbapt			else {
1994262395Sbapt				break;
1995262395Sbapt			}
1996262395Sbapt		}
1997262395Sbapt		c = p;
1998262395Sbapt		while (p < chunk->end) {
1999262395Sbapt			if (*p == '}') {
2000262395Sbapt				break;
2001262395Sbapt			}
2002262395Sbapt			ucl_chunk_skipc (chunk, p);
2003262395Sbapt		}
2004262395Sbapt		*macro_start = c;
2005262395Sbapt		*macro_len = p - c;
2006262395Sbapt		ucl_chunk_skipc (chunk, p);
2007262395Sbapt		break;
2008262395Sbapt	default:
2009262395Sbapt		/* Macro is not enclosed in quotes or braces */
2010262395Sbapt		c = p;
2011262395Sbapt		while (p < chunk->end) {
2012262395Sbapt			if (ucl_lex_is_atom_end (*p)) {
2013262395Sbapt				break;
2014262395Sbapt			}
2015262395Sbapt			ucl_chunk_skipc (chunk, p);
2016262395Sbapt		}
2017262395Sbapt		*macro_start = c;
2018262395Sbapt		*macro_len = p - c;
2019262395Sbapt		break;
2020262395Sbapt	}
2021262395Sbapt
2022262395Sbapt	/* We are at the end of a macro */
2023262395Sbapt	/* Skip ';' and space characters and return to previous state */
2024262395Sbapt	while (p < chunk->end) {
2025262395Sbapt		if (!ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE) && *p != ';') {
2026262395Sbapt			break;
2027262395Sbapt		}
2028262395Sbapt		ucl_chunk_skipc (chunk, p);
2029262395Sbapt	}
2030262395Sbapt	return true;
2031262395Sbapt}
2032262395Sbapt
2033262395Sbapt/**
2034275223Sbapt * Parse macro arguments as UCL object
2035275223Sbapt * @param parser parser structure
2036275223Sbapt * @param chunk the current data chunk
2037275223Sbapt * @return
2038275223Sbapt */
2039275223Sbaptstatic ucl_object_t *
2040275223Sbaptucl_parse_macro_arguments (struct ucl_parser *parser,
2041275223Sbapt		struct ucl_chunk *chunk)
2042275223Sbapt{
2043275223Sbapt	ucl_object_t *res = NULL;
2044275223Sbapt	struct ucl_parser *params_parser;
2045275223Sbapt	int obraces = 1, ebraces = 0, state = 0;
2046275223Sbapt	const unsigned char *p, *c;
2047275223Sbapt	size_t args_len = 0;
2048275223Sbapt	struct ucl_parser_saved_state saved;
2049275223Sbapt
2050275223Sbapt	saved.column = chunk->column;
2051275223Sbapt	saved.line = chunk->line;
2052275223Sbapt	saved.pos = chunk->pos;
2053275223Sbapt	saved.remain = chunk->remain;
2054275223Sbapt	p = chunk->pos;
2055275223Sbapt
2056275223Sbapt	if (*p != '(' || chunk->remain < 2) {
2057275223Sbapt		return NULL;
2058275223Sbapt	}
2059275223Sbapt
2060275223Sbapt	/* Set begin and start */
2061275223Sbapt	ucl_chunk_skipc (chunk, p);
2062275223Sbapt	c = p;
2063275223Sbapt
2064275223Sbapt	while ((p) < (chunk)->end) {
2065275223Sbapt		switch (state) {
2066275223Sbapt		case 0:
2067275223Sbapt			/* Parse symbols and check for '(', ')' and '"' */
2068275223Sbapt			if (*p == '(') {
2069275223Sbapt				obraces ++;
2070275223Sbapt			}
2071275223Sbapt			else if (*p == ')') {
2072275223Sbapt				ebraces ++;
2073275223Sbapt			}
2074275223Sbapt			else if (*p == '"') {
2075275223Sbapt				state = 1;
2076275223Sbapt			}
2077275223Sbapt			/* Check pairing */
2078275223Sbapt			if (obraces == ebraces) {
2079275223Sbapt				state = 99;
2080275223Sbapt			}
2081275223Sbapt			else {
2082275223Sbapt				args_len ++;
2083275223Sbapt			}
2084275223Sbapt			/* Check overflow */
2085275223Sbapt			if (chunk->remain == 0) {
2086275223Sbapt				goto restore_chunk;
2087275223Sbapt			}
2088275223Sbapt			ucl_chunk_skipc (chunk, p);
2089275223Sbapt			break;
2090275223Sbapt		case 1:
2091275223Sbapt			/* We have quote character, so skip all but quotes */
2092275223Sbapt			if (*p == '"' && *(p - 1) != '\\') {
2093275223Sbapt				state = 0;
2094275223Sbapt			}
2095275223Sbapt			if (chunk->remain == 0) {
2096275223Sbapt				goto restore_chunk;
2097275223Sbapt			}
2098290071Sbapt			args_len ++;
2099275223Sbapt			ucl_chunk_skipc (chunk, p);
2100275223Sbapt			break;
2101275223Sbapt		case 99:
2102275223Sbapt			/*
2103275223Sbapt			 * We have read the full body of arguments, so we need to parse and set
2104275223Sbapt			 * object from that
2105275223Sbapt			 */
2106275223Sbapt			params_parser = ucl_parser_new (parser->flags);
2107275223Sbapt			if (!ucl_parser_add_chunk (params_parser, c, args_len)) {
2108275223Sbapt				ucl_set_err (parser, UCL_ESYNTAX, "macro arguments parsing error",
2109275223Sbapt						&parser->err);
2110275223Sbapt			}
2111275223Sbapt			else {
2112275223Sbapt				res = ucl_parser_get_object (params_parser);
2113275223Sbapt			}
2114275223Sbapt			ucl_parser_free (params_parser);
2115275223Sbapt
2116275223Sbapt			return res;
2117275223Sbapt
2118275223Sbapt			break;
2119275223Sbapt		}
2120275223Sbapt	}
2121275223Sbapt
2122275223Sbapt	return res;
2123275223Sbapt
2124275223Sbaptrestore_chunk:
2125275223Sbapt	chunk->column = saved.column;
2126275223Sbapt	chunk->line = saved.line;
2127275223Sbapt	chunk->pos = saved.pos;
2128275223Sbapt	chunk->remain = saved.remain;
2129275223Sbapt
2130275223Sbapt	return NULL;
2131275223Sbapt}
2132275223Sbapt
2133275223Sbapt#define SKIP_SPACES_COMMENTS(parser, chunk, p) do {								\
2134275223Sbapt	while ((p) < (chunk)->end) {												\
2135275223Sbapt		if (!ucl_test_character (*(p), UCL_CHARACTER_WHITESPACE_UNSAFE)) {		\
2136275223Sbapt			if ((chunk)->remain >= 2 && ucl_lex_is_comment ((p)[0], (p)[1])) {	\
2137275223Sbapt				if (!ucl_skip_comments (parser)) {								\
2138275223Sbapt					return false;												\
2139275223Sbapt				}																\
2140275223Sbapt				p = (chunk)->pos;												\
2141275223Sbapt			}																	\
2142275223Sbapt			break;																\
2143275223Sbapt		}																		\
2144275223Sbapt		ucl_chunk_skipc (chunk, p);												\
2145275223Sbapt	}																			\
2146275223Sbapt} while(0)
2147275223Sbapt
2148275223Sbapt/**
2149262395Sbapt * Handle the main states of rcl parser
2150262395Sbapt * @param parser parser structure
2151262395Sbapt * @return true if chunk has been parsed and false in case of error
2152262395Sbapt */
2153262395Sbaptstatic bool
2154262395Sbaptucl_state_machine (struct ucl_parser *parser)
2155262395Sbapt{
2156275223Sbapt	ucl_object_t *obj, *macro_args;
2157262395Sbapt	struct ucl_chunk *chunk = parser->chunks;
2158262395Sbapt	const unsigned char *p, *c = NULL, *macro_start = NULL;
2159262395Sbapt	unsigned char *macro_escaped;
2160262395Sbapt	size_t macro_len = 0;
2161262395Sbapt	struct ucl_macro *macro = NULL;
2162275223Sbapt	bool next_key = false, end_of_object = false, ret;
2163262395Sbapt
2164262395Sbapt	if (parser->top_obj == NULL) {
2165262395Sbapt		parser->state = UCL_STATE_INIT;
2166262395Sbapt	}
2167262395Sbapt
2168262395Sbapt	p = chunk->pos;
2169262395Sbapt	while (chunk->pos < chunk->end) {
2170262395Sbapt		switch (parser->state) {
2171262395Sbapt		case UCL_STATE_INIT:
2172262395Sbapt			/*
2173262395Sbapt			 * At the init state we can either go to the parse array or object
2174262395Sbapt			 * if we got [ or { correspondingly or can just treat new data as
2175262395Sbapt			 * a key of newly created object
2176262395Sbapt			 */
2177262395Sbapt			if (!ucl_skip_comments (parser)) {
2178262395Sbapt				parser->prev_state = parser->state;
2179262395Sbapt				parser->state = UCL_STATE_ERROR;
2180262395Sbapt				return false;
2181262395Sbapt			}
2182262395Sbapt			else {
2183268876Sbapt				/* Skip any spaces */
2184268876Sbapt				while (p < chunk->end && ucl_test_character (*p,
2185268876Sbapt						UCL_CHARACTER_WHITESPACE_UNSAFE)) {
2186268876Sbapt					ucl_chunk_skipc (chunk, p);
2187268876Sbapt				}
2188290071Sbapt
2189262395Sbapt				p = chunk->pos;
2190290071Sbapt
2191262395Sbapt				if (*p == '[') {
2192262395Sbapt					parser->state = UCL_STATE_VALUE;
2193262395Sbapt					ucl_chunk_skipc (chunk, p);
2194262395Sbapt				}
2195262395Sbapt				else {
2196262395Sbapt					parser->state = UCL_STATE_KEY;
2197262395Sbapt					if (*p == '{') {
2198262395Sbapt						ucl_chunk_skipc (chunk, p);
2199262395Sbapt					}
2200262395Sbapt				}
2201290071Sbapt
2202290071Sbapt				if (parser->top_obj == NULL) {
2203290071Sbapt					if (parser->state == UCL_STATE_VALUE) {
2204290071Sbapt						obj = ucl_parser_add_container (NULL, parser, true, 0);
2205290071Sbapt					}
2206290071Sbapt					else {
2207290071Sbapt						obj = ucl_parser_add_container (NULL, parser, false, 0);
2208290071Sbapt					}
2209290071Sbapt
2210290071Sbapt					if (obj == NULL) {
2211290071Sbapt						return false;
2212290071Sbapt					}
2213290071Sbapt
2214290071Sbapt					parser->top_obj = obj;
2215290071Sbapt					parser->cur_obj = obj;
2216290071Sbapt				}
2217290071Sbapt
2218262395Sbapt			}
2219262395Sbapt			break;
2220262395Sbapt		case UCL_STATE_KEY:
2221262395Sbapt			/* Skip any spaces */
2222262395Sbapt			while (p < chunk->end && ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE)) {
2223262395Sbapt				ucl_chunk_skipc (chunk, p);
2224262395Sbapt			}
2225298166Sbapt			if (p == chunk->end || *p == '}') {
2226262395Sbapt				/* We have the end of an object */
2227262395Sbapt				parser->state = UCL_STATE_AFTER_VALUE;
2228262395Sbapt				continue;
2229262395Sbapt			}
2230262395Sbapt			if (parser->stack == NULL) {
2231262395Sbapt				/* No objects are on stack, but we want to parse a key */
2232275223Sbapt				ucl_set_err (parser, UCL_ESYNTAX, "top object is finished but the parser "
2233262395Sbapt						"expects a key", &parser->err);
2234262395Sbapt				parser->prev_state = parser->state;
2235262395Sbapt				parser->state = UCL_STATE_ERROR;
2236262395Sbapt				return false;
2237262395Sbapt			}
2238262395Sbapt			if (!ucl_parse_key (parser, chunk, &next_key, &end_of_object)) {
2239262395Sbapt				parser->prev_state = parser->state;
2240262395Sbapt				parser->state = UCL_STATE_ERROR;
2241262395Sbapt				return false;
2242262395Sbapt			}
2243262395Sbapt			if (end_of_object) {
2244262395Sbapt				p = chunk->pos;
2245262395Sbapt				parser->state = UCL_STATE_AFTER_VALUE;
2246262395Sbapt				continue;
2247262395Sbapt			}
2248262395Sbapt			else if (parser->state != UCL_STATE_MACRO_NAME) {
2249262395Sbapt				if (next_key && parser->stack->obj->type == UCL_OBJECT) {
2250262395Sbapt					/* Parse more keys and nest objects accordingly */
2251290071Sbapt					obj = ucl_parser_add_container (parser->cur_obj, parser, false,
2252263648Sbapt							parser->stack->level + 1);
2253263648Sbapt					if (obj == NULL) {
2254263648Sbapt						return false;
2255263648Sbapt					}
2256262395Sbapt				}
2257262395Sbapt				else {
2258262395Sbapt					parser->state = UCL_STATE_VALUE;
2259262395Sbapt				}
2260262395Sbapt			}
2261262395Sbapt			else {
2262262395Sbapt				c = chunk->pos;
2263262395Sbapt			}
2264262395Sbapt			p = chunk->pos;
2265262395Sbapt			break;
2266262395Sbapt		case UCL_STATE_VALUE:
2267262395Sbapt			/* We need to check what we do have */
2268298166Sbapt			if (!parser->cur_obj || !ucl_parse_value (parser, chunk)) {
2269262395Sbapt				parser->prev_state = parser->state;
2270262395Sbapt				parser->state = UCL_STATE_ERROR;
2271262395Sbapt				return false;
2272262395Sbapt			}
2273262395Sbapt			/* State is set in ucl_parse_value call */
2274262395Sbapt			p = chunk->pos;
2275262395Sbapt			break;
2276262395Sbapt		case UCL_STATE_AFTER_VALUE:
2277262395Sbapt			if (!ucl_parse_after_value (parser, chunk)) {
2278262395Sbapt				parser->prev_state = parser->state;
2279262395Sbapt				parser->state = UCL_STATE_ERROR;
2280262395Sbapt				return false;
2281262395Sbapt			}
2282290071Sbapt
2283262395Sbapt			if (parser->stack != NULL) {
2284262395Sbapt				if (parser->stack->obj->type == UCL_OBJECT) {
2285262395Sbapt					parser->state = UCL_STATE_KEY;
2286262395Sbapt				}
2287262395Sbapt				else {
2288262395Sbapt					/* Array */
2289262395Sbapt					parser->state = UCL_STATE_VALUE;
2290262395Sbapt				}
2291262395Sbapt			}
2292262395Sbapt			else {
2293262395Sbapt				/* Skip everything at the end */
2294262395Sbapt				return true;
2295262395Sbapt			}
2296298166Sbapt
2297262395Sbapt			p = chunk->pos;
2298262395Sbapt			break;
2299262395Sbapt		case UCL_STATE_MACRO_NAME:
2300298166Sbapt			if (parser->flags & UCL_PARSER_DISABLE_MACRO) {
2301298166Sbapt				if (!ucl_skip_macro_as_comment (parser, chunk)) {
2302298166Sbapt					/* We have invalid macro */
2303298166Sbapt					ucl_create_err (&parser->err,
2304298166Sbapt							"error on line %d at column %d: invalid macro",
2305298166Sbapt							chunk->line,
2306298166Sbapt							chunk->column);
2307298166Sbapt					parser->state = UCL_STATE_ERROR;
2308298166Sbapt					return false;
2309298166Sbapt				}
2310298166Sbapt				else {
2311298166Sbapt					p = chunk->pos;
2312298166Sbapt					parser->state = parser->prev_state;
2313298166Sbapt				}
2314262395Sbapt			}
2315290071Sbapt			else {
2316298166Sbapt				if (!ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE) &&
2317298166Sbapt						*p != '(') {
2318298166Sbapt					ucl_chunk_skipc (chunk, p);
2319298166Sbapt				}
2320298166Sbapt				else {
2321298166Sbapt					if (c != NULL && p - c > 0) {
2322298166Sbapt						/* We got macro name */
2323298166Sbapt						macro_len = (size_t) (p - c);
2324298166Sbapt						HASH_FIND (hh, parser->macroes, c, macro_len, macro);
2325298166Sbapt						if (macro == NULL) {
2326298166Sbapt							ucl_create_err (&parser->err,
2327298166Sbapt									"error on line %d at column %d: "
2328298166Sbapt									"unknown macro: '%.*s', character: '%c'",
2329298166Sbapt									chunk->line,
2330298166Sbapt									chunk->column,
2331298166Sbapt									(int) (p - c),
2332298166Sbapt									c,
2333298166Sbapt									*chunk->pos);
2334298166Sbapt							parser->state = UCL_STATE_ERROR;
2335298166Sbapt							return false;
2336298166Sbapt						}
2337298166Sbapt						/* Now we need to skip all spaces */
2338298166Sbapt						SKIP_SPACES_COMMENTS(parser, chunk, p);
2339298166Sbapt						parser->state = UCL_STATE_MACRO;
2340298166Sbapt					}
2341298166Sbapt					else {
2342298166Sbapt						/* We have invalid macro name */
2343290071Sbapt						ucl_create_err (&parser->err,
2344298166Sbapt								"error on line %d at column %d: invalid macro name",
2345290071Sbapt								chunk->line,
2346298166Sbapt								chunk->column);
2347290071Sbapt						parser->state = UCL_STATE_ERROR;
2348290071Sbapt						return false;
2349290071Sbapt					}
2350290071Sbapt				}
2351262395Sbapt			}
2352262395Sbapt			break;
2353262395Sbapt		case UCL_STATE_MACRO:
2354275223Sbapt			if (*chunk->pos == '(') {
2355275223Sbapt				macro_args = ucl_parse_macro_arguments (parser, chunk);
2356275223Sbapt				p = chunk->pos;
2357275223Sbapt				if (macro_args) {
2358275223Sbapt					SKIP_SPACES_COMMENTS(parser, chunk, p);
2359275223Sbapt				}
2360275223Sbapt			}
2361275223Sbapt			else {
2362275223Sbapt				macro_args = NULL;
2363275223Sbapt			}
2364262395Sbapt			if (!ucl_parse_macro_value (parser, chunk, macro,
2365262395Sbapt					&macro_start, &macro_len)) {
2366262395Sbapt				parser->prev_state = parser->state;
2367262395Sbapt				parser->state = UCL_STATE_ERROR;
2368262395Sbapt				return false;
2369262395Sbapt			}
2370275223Sbapt			macro_len = ucl_expand_variable (parser, &macro_escaped,
2371275223Sbapt					macro_start, macro_len);
2372262395Sbapt			parser->state = parser->prev_state;
2373298166Sbapt
2374298166Sbapt			if (macro_escaped == NULL && macro != NULL) {
2375290071Sbapt				if (macro->is_context) {
2376290071Sbapt					ret = macro->h.context_handler (macro_start, macro_len,
2377290071Sbapt							macro_args,
2378290071Sbapt							parser->top_obj,
2379290071Sbapt							macro->ud);
2380290071Sbapt				}
2381290071Sbapt				else {
2382290071Sbapt					ret = macro->h.handler (macro_start, macro_len, macro_args,
2383290071Sbapt							macro->ud);
2384290071Sbapt				}
2385262395Sbapt			}
2386298166Sbapt			else if (macro != NULL) {
2387290071Sbapt				if (macro->is_context) {
2388290071Sbapt					ret = macro->h.context_handler (macro_escaped, macro_len,
2389290071Sbapt							macro_args,
2390290071Sbapt							parser->top_obj,
2391290071Sbapt							macro->ud);
2392290071Sbapt				}
2393290071Sbapt				else {
2394290071Sbapt					ret = macro->h.handler (macro_escaped, macro_len, macro_args,
2395275223Sbapt						macro->ud);
2396290071Sbapt				}
2397290071Sbapt
2398262395Sbapt				UCL_FREE (macro_len + 1, macro_escaped);
2399262395Sbapt			}
2400298166Sbapt			else {
2401298166Sbapt				ret = false;
2402298166Sbapt				ucl_set_err (parser, UCL_EINTERNAL,
2403298166Sbapt						"internal error: parser has macro undefined", &parser->err);
2404298166Sbapt			}
2405290071Sbapt
2406290071Sbapt			/*
2407290071Sbapt			 * Chunk can be modified within macro handler
2408290071Sbapt			 */
2409290071Sbapt			chunk = parser->chunks;
2410262395Sbapt			p = chunk->pos;
2411298166Sbapt
2412275223Sbapt			if (macro_args) {
2413275223Sbapt				ucl_object_unref (macro_args);
2414275223Sbapt			}
2415298166Sbapt
2416275223Sbapt			if (!ret) {
2417275223Sbapt				return false;
2418275223Sbapt			}
2419262395Sbapt			break;
2420262395Sbapt		default:
2421275223Sbapt			ucl_set_err (parser, UCL_EINTERNAL,
2422275223Sbapt					"internal error: parser is in an unknown state", &parser->err);
2423262395Sbapt			parser->state = UCL_STATE_ERROR;
2424262395Sbapt			return false;
2425262395Sbapt		}
2426262395Sbapt	}
2427262395Sbapt
2428298166Sbapt	if (parser->last_comment) {
2429298166Sbapt		if (parser->cur_obj) {
2430298166Sbapt			ucl_attach_comment (parser, parser->cur_obj, true);
2431298166Sbapt		}
2432298166Sbapt		else if (parser->stack && parser->stack->obj) {
2433298166Sbapt			ucl_attach_comment (parser, parser->stack->obj, true);
2434298166Sbapt		}
2435298166Sbapt		else if (parser->top_obj) {
2436298166Sbapt			ucl_attach_comment (parser, parser->top_obj, true);
2437298166Sbapt		}
2438298166Sbapt		else {
2439298166Sbapt			ucl_object_unref (parser->last_comment);
2440298166Sbapt		}
2441298166Sbapt	}
2442298166Sbapt
2443262395Sbapt	return true;
2444262395Sbapt}
2445262395Sbapt
2446262395Sbaptstruct ucl_parser*
2447262395Sbaptucl_parser_new (int flags)
2448262395Sbapt{
2449298166Sbapt	struct ucl_parser *parser;
2450262395Sbapt
2451298166Sbapt	parser = UCL_ALLOC (sizeof (struct ucl_parser));
2452298166Sbapt	if (parser == NULL) {
2453263648Sbapt		return NULL;
2454263648Sbapt	}
2455290071Sbapt
2456298166Sbapt	memset (parser, 0, sizeof (struct ucl_parser));
2457262395Sbapt
2458298166Sbapt	ucl_parser_register_macro (parser, "include", ucl_include_handler, parser);
2459298166Sbapt	ucl_parser_register_macro (parser, "try_include", ucl_try_include_handler, parser);
2460298166Sbapt	ucl_parser_register_macro (parser, "includes", ucl_includes_handler, parser);
2461298166Sbapt	ucl_parser_register_macro (parser, "priority", ucl_priority_handler, parser);
2462298166Sbapt	ucl_parser_register_macro (parser, "load", ucl_load_handler, parser);
2463298166Sbapt	ucl_parser_register_context_macro (parser, "inherit", ucl_inherit_handler, parser);
2464262395Sbapt
2465298166Sbapt	parser->flags = flags;
2466298166Sbapt	parser->includepaths = NULL;
2467262395Sbapt
2468298166Sbapt	if (flags & UCL_PARSER_SAVE_COMMENTS) {
2469298166Sbapt		parser->comments = ucl_object_typed_new (UCL_OBJECT);
2470298166Sbapt	}
2471298166Sbapt
2472314278Sbapt	if (!(flags & UCL_PARSER_NO_FILEVARS)) {
2473314278Sbapt		/* Initial assumption about filevars */
2474314278Sbapt		ucl_parser_set_filevars (parser, NULL, false);
2475314278Sbapt	}
2476262395Sbapt
2477298166Sbapt	return parser;
2478262395Sbapt}
2479262395Sbapt
2480290071Sbaptbool
2481290071Sbaptucl_parser_set_default_priority (struct ucl_parser *parser, unsigned prio)
2482290071Sbapt{
2483290071Sbapt	if (parser == NULL) {
2484290071Sbapt		return false;
2485290071Sbapt	}
2486262395Sbapt
2487290071Sbapt	parser->default_priority = prio;
2488290071Sbapt
2489290071Sbapt	return true;
2490290071Sbapt}
2491290071Sbapt
2492262395Sbaptvoid
2493262395Sbaptucl_parser_register_macro (struct ucl_parser *parser, const char *macro,
2494262395Sbapt		ucl_macro_handler handler, void* ud)
2495262395Sbapt{
2496262395Sbapt	struct ucl_macro *new;
2497262395Sbapt
2498263648Sbapt	if (macro == NULL || handler == NULL) {
2499263648Sbapt		return;
2500263648Sbapt	}
2501290071Sbapt
2502262395Sbapt	new = UCL_ALLOC (sizeof (struct ucl_macro));
2503263648Sbapt	if (new == NULL) {
2504263648Sbapt		return;
2505263648Sbapt	}
2506290071Sbapt
2507262395Sbapt	memset (new, 0, sizeof (struct ucl_macro));
2508290071Sbapt	new->h.handler = handler;
2509262395Sbapt	new->name = strdup (macro);
2510262395Sbapt	new->ud = ud;
2511262395Sbapt	HASH_ADD_KEYPTR (hh, parser->macroes, new->name, strlen (new->name), new);
2512262395Sbapt}
2513262395Sbapt
2514262395Sbaptvoid
2515290071Sbaptucl_parser_register_context_macro (struct ucl_parser *parser, const char *macro,
2516290071Sbapt		ucl_context_macro_handler handler, void* ud)
2517290071Sbapt{
2518290071Sbapt	struct ucl_macro *new;
2519290071Sbapt
2520290071Sbapt	if (macro == NULL || handler == NULL) {
2521290071Sbapt		return;
2522290071Sbapt	}
2523290071Sbapt
2524290071Sbapt	new = UCL_ALLOC (sizeof (struct ucl_macro));
2525290071Sbapt	if (new == NULL) {
2526290071Sbapt		return;
2527290071Sbapt	}
2528290071Sbapt
2529290071Sbapt	memset (new, 0, sizeof (struct ucl_macro));
2530290071Sbapt	new->h.context_handler = handler;
2531290071Sbapt	new->name = strdup (macro);
2532290071Sbapt	new->ud = ud;
2533290071Sbapt	new->is_context = true;
2534290071Sbapt	HASH_ADD_KEYPTR (hh, parser->macroes, new->name, strlen (new->name), new);
2535290071Sbapt}
2536290071Sbapt
2537290071Sbaptvoid
2538262395Sbaptucl_parser_register_variable (struct ucl_parser *parser, const char *var,
2539262395Sbapt		const char *value)
2540262395Sbapt{
2541262395Sbapt	struct ucl_variable *new = NULL, *cur;
2542262395Sbapt
2543262395Sbapt	if (var == NULL) {
2544262395Sbapt		return;
2545262395Sbapt	}
2546262395Sbapt
2547262395Sbapt	/* Find whether a variable already exists */
2548262395Sbapt	LL_FOREACH (parser->variables, cur) {
2549262395Sbapt		if (strcmp (cur->var, var) == 0) {
2550262395Sbapt			new = cur;
2551262395Sbapt			break;
2552262395Sbapt		}
2553262395Sbapt	}
2554262395Sbapt
2555262395Sbapt	if (value == NULL) {
2556262395Sbapt
2557262395Sbapt		if (new != NULL) {
2558262395Sbapt			/* Remove variable */
2559275223Sbapt			DL_DELETE (parser->variables, new);
2560262395Sbapt			free (new->var);
2561262395Sbapt			free (new->value);
2562262395Sbapt			UCL_FREE (sizeof (struct ucl_variable), new);
2563262395Sbapt		}
2564262395Sbapt		else {
2565262395Sbapt			/* Do nothing */
2566262395Sbapt			return;
2567262395Sbapt		}
2568262395Sbapt	}
2569262395Sbapt	else {
2570262395Sbapt		if (new == NULL) {
2571262395Sbapt			new = UCL_ALLOC (sizeof (struct ucl_variable));
2572263648Sbapt			if (new == NULL) {
2573263648Sbapt				return;
2574263648Sbapt			}
2575262395Sbapt			memset (new, 0, sizeof (struct ucl_variable));
2576262395Sbapt			new->var = strdup (var);
2577262395Sbapt			new->var_len = strlen (var);
2578262395Sbapt			new->value = strdup (value);
2579262395Sbapt			new->value_len = strlen (value);
2580262395Sbapt
2581275223Sbapt			DL_APPEND (parser->variables, new);
2582262395Sbapt		}
2583262395Sbapt		else {
2584262395Sbapt			free (new->value);
2585262395Sbapt			new->value = strdup (value);
2586262395Sbapt			new->value_len = strlen (value);
2587262395Sbapt		}
2588262395Sbapt	}
2589262395Sbapt}
2590262395Sbapt
2591266636Sbaptvoid
2592266636Sbaptucl_parser_set_variables_handler (struct ucl_parser *parser,
2593266636Sbapt		ucl_variable_handler handler, void *ud)
2594266636Sbapt{
2595266636Sbapt	parser->var_handler = handler;
2596266636Sbapt	parser->var_data = ud;
2597266636Sbapt}
2598266636Sbapt
2599262395Sbaptbool
2600290071Sbaptucl_parser_add_chunk_full (struct ucl_parser *parser, const unsigned char *data,
2601290071Sbapt		size_t len, unsigned priority, enum ucl_duplicate_strategy strat,
2602290071Sbapt		enum ucl_parse_type parse_type)
2603262395Sbapt{
2604262395Sbapt	struct ucl_chunk *chunk;
2605262395Sbapt
2606290071Sbapt	if (parser == NULL) {
2607290071Sbapt		return false;
2608290071Sbapt	}
2609290071Sbapt
2610301339Sbapt	if (data == NULL && len != 0) {
2611263648Sbapt		ucl_create_err (&parser->err, "invalid chunk added");
2612263648Sbapt		return false;
2613263648Sbapt	}
2614298166Sbapt
2615262395Sbapt	if (parser->state != UCL_STATE_ERROR) {
2616262395Sbapt		chunk = UCL_ALLOC (sizeof (struct ucl_chunk));
2617263648Sbapt		if (chunk == NULL) {
2618263648Sbapt			ucl_create_err (&parser->err, "cannot allocate chunk structure");
2619263648Sbapt			return false;
2620263648Sbapt		}
2621301339Sbapt
2622314278Sbapt		if (parse_type == UCL_PARSE_AUTO && len > 0) {
2623314278Sbapt			/* We need to detect parse type by the first symbol */
2624314278Sbapt			if ((*data & 0x80) == 0x80 && (*data >= 0xdc && *data <= 0xdf)) {
2625314278Sbapt				parse_type = UCL_PARSE_MSGPACK;
2626314278Sbapt			}
2627314278Sbapt			else if (*data == '(') {
2628314278Sbapt				parse_type = UCL_PARSE_CSEXP;
2629314278Sbapt			}
2630314278Sbapt			else {
2631314278Sbapt				parse_type = UCL_PARSE_UCL;
2632314278Sbapt			}
2633314278Sbapt		}
2634314278Sbapt
2635262395Sbapt		chunk->begin = data;
2636262395Sbapt		chunk->remain = len;
2637262395Sbapt		chunk->pos = chunk->begin;
2638262395Sbapt		chunk->end = chunk->begin + len;
2639262395Sbapt		chunk->line = 1;
2640262395Sbapt		chunk->column = 0;
2641275223Sbapt		chunk->priority = priority;
2642290071Sbapt		chunk->strategy = strat;
2643290071Sbapt		chunk->parse_type = parse_type;
2644262395Sbapt		LL_PREPEND (parser->chunks, chunk);
2645262395Sbapt		parser->recursion ++;
2646290071Sbapt
2647262395Sbapt		if (parser->recursion > UCL_MAX_RECURSION) {
2648262395Sbapt			ucl_create_err (&parser->err, "maximum include nesting limit is reached: %d",
2649262395Sbapt					parser->recursion);
2650262395Sbapt			return false;
2651262395Sbapt		}
2652290071Sbapt
2653301339Sbapt		if (len > 0) {
2654301339Sbapt			/* Need to parse something */
2655301339Sbapt			switch (parse_type) {
2656301339Sbapt			default:
2657301339Sbapt			case UCL_PARSE_UCL:
2658301339Sbapt				return ucl_state_machine (parser);
2659301339Sbapt			case UCL_PARSE_MSGPACK:
2660301339Sbapt				return ucl_parse_msgpack (parser);
2661314278Sbapt			case UCL_PARSE_CSEXP:
2662314278Sbapt				return ucl_parse_csexp (parser);
2663301339Sbapt			}
2664290071Sbapt		}
2665301339Sbapt		else {
2666301339Sbapt			/* Just add empty chunk and go forward */
2667301339Sbapt			if (parser->top_obj == NULL) {
2668301339Sbapt				/*
2669301339Sbapt				 * In case of empty object, create one to indicate that we've
2670301339Sbapt				 * read something
2671301339Sbapt				 */
2672301339Sbapt				parser->top_obj = ucl_object_new_full (UCL_OBJECT, priority);
2673301339Sbapt			}
2674301339Sbapt
2675301339Sbapt			return true;
2676301339Sbapt		}
2677262395Sbapt	}
2678262395Sbapt
2679262395Sbapt	ucl_create_err (&parser->err, "a parser is in an invalid state");
2680262395Sbapt
2681262395Sbapt	return false;
2682262395Sbapt}
2683263648Sbapt
2684263648Sbaptbool
2685290071Sbaptucl_parser_add_chunk_priority (struct ucl_parser *parser,
2686290071Sbapt		const unsigned char *data, size_t len, unsigned priority)
2687290071Sbapt{
2688290071Sbapt	/* We dereference parser, so this check is essential */
2689290071Sbapt	if (parser == NULL) {
2690290071Sbapt		return false;
2691290071Sbapt	}
2692290071Sbapt
2693290071Sbapt	return ucl_parser_add_chunk_full (parser, data, len,
2694290071Sbapt				priority, UCL_DUPLICATE_APPEND, UCL_PARSE_UCL);
2695290071Sbapt}
2696290071Sbapt
2697290071Sbaptbool
2698275223Sbaptucl_parser_add_chunk (struct ucl_parser *parser, const unsigned char *data,
2699275223Sbapt		size_t len)
2700275223Sbapt{
2701290071Sbapt	if (parser == NULL) {
2702290071Sbapt		return false;
2703290071Sbapt	}
2704290071Sbapt
2705290071Sbapt	return ucl_parser_add_chunk_full (parser, data, len,
2706290071Sbapt			parser->default_priority, UCL_DUPLICATE_APPEND, UCL_PARSE_UCL);
2707275223Sbapt}
2708275223Sbapt
2709275223Sbaptbool
2710290071Sbaptucl_parser_add_string_priority (struct ucl_parser *parser, const char *data,
2711290071Sbapt		size_t len, unsigned priority)
2712263648Sbapt{
2713263648Sbapt	if (data == NULL) {
2714263648Sbapt		ucl_create_err (&parser->err, "invalid string added");
2715263648Sbapt		return false;
2716263648Sbapt	}
2717263648Sbapt	if (len == 0) {
2718263648Sbapt		len = strlen (data);
2719263648Sbapt	}
2720263648Sbapt
2721290071Sbapt	return ucl_parser_add_chunk_priority (parser,
2722290071Sbapt			(const unsigned char *)data, len, priority);
2723263648Sbapt}
2724290071Sbapt
2725290071Sbaptbool
2726290071Sbaptucl_parser_add_string (struct ucl_parser *parser, const char *data,
2727290071Sbapt		size_t len)
2728290071Sbapt{
2729290071Sbapt	if (parser == NULL) {
2730290071Sbapt		return false;
2731290071Sbapt	}
2732290071Sbapt
2733290071Sbapt	return ucl_parser_add_string_priority (parser,
2734290071Sbapt			(const unsigned char *)data, len, parser->default_priority);
2735290071Sbapt}
2736290071Sbapt
2737290071Sbaptbool
2738290071Sbaptucl_set_include_path (struct ucl_parser *parser, ucl_object_t *paths)
2739290071Sbapt{
2740290071Sbapt	if (parser == NULL || paths == NULL) {
2741290071Sbapt		return false;
2742290071Sbapt	}
2743290071Sbapt
2744290071Sbapt	if (parser->includepaths == NULL) {
2745290071Sbapt		parser->includepaths = ucl_object_copy (paths);
2746290071Sbapt	}
2747290071Sbapt	else {
2748290071Sbapt		ucl_object_unref (parser->includepaths);
2749290071Sbapt		parser->includepaths = ucl_object_copy (paths);
2750290071Sbapt	}
2751290071Sbapt
2752290071Sbapt	if (parser->includepaths == NULL) {
2753290071Sbapt		return false;
2754290071Sbapt	}
2755290071Sbapt
2756290071Sbapt	return true;
2757290071Sbapt}
2758