ucl_parser.c revision 301339
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)) {
345266636Sbapt			*found = true;
346266636Sbapt			if (need_free) {
347266636Sbapt				free (dst);
348266636Sbapt			}
349266636Sbapt			return (ptr + remain);
350266636Sbapt		}
351266636Sbapt	}
352266636Sbapt
353262395Sbapt	return ptr;
354262395Sbapt}
355262395Sbapt
356262395Sbapt/**
357262395Sbapt * Check for a variable in a given string
358262395Sbapt * @param parser
359262395Sbapt * @param ptr
360262395Sbapt * @param remain
361262395Sbapt * @param out_len
362262395Sbapt * @param vars_found
363262395Sbapt * @return
364262395Sbapt */
365262395Sbaptstatic const char *
366266636Sbaptucl_check_variable (struct ucl_parser *parser, const char *ptr,
367266636Sbapt		size_t remain, size_t *out_len, bool *vars_found)
368262395Sbapt{
369262395Sbapt	const char *p, *end, *ret = ptr;
370262395Sbapt	bool found = false;
371262395Sbapt
372262395Sbapt	if (*ptr == '{') {
373262395Sbapt		/* We need to match the variable enclosed in braces */
374262395Sbapt		p = ptr + 1;
375262395Sbapt		end = ptr + remain;
376262395Sbapt		while (p < end) {
377262395Sbapt			if (*p == '}') {
378266636Sbapt				ret = ucl_check_variable_safe (parser, ptr + 1, p - ptr - 1,
379266636Sbapt						out_len, true, &found);
380262395Sbapt				if (found) {
381262395Sbapt					/* {} must be excluded actually */
382262395Sbapt					ret ++;
383262395Sbapt					if (!*vars_found) {
384262395Sbapt						*vars_found = true;
385262395Sbapt					}
386262395Sbapt				}
387262395Sbapt				else {
388262395Sbapt					*out_len += 2;
389262395Sbapt				}
390262395Sbapt				break;
391262395Sbapt			}
392262395Sbapt			p ++;
393262395Sbapt		}
394262395Sbapt	}
395262395Sbapt	else if (*ptr != '$') {
396262395Sbapt		/* Not count escaped dollar sign */
397262395Sbapt		ret = ucl_check_variable_safe (parser, ptr, remain, out_len, false, &found);
398262395Sbapt		if (found && !*vars_found) {
399262395Sbapt			*vars_found = true;
400262395Sbapt		}
401262395Sbapt		if (!found) {
402262395Sbapt			(*out_len) ++;
403262395Sbapt		}
404262395Sbapt	}
405262395Sbapt	else {
406262395Sbapt		ret ++;
407262395Sbapt		(*out_len) ++;
408262395Sbapt	}
409262395Sbapt
410262395Sbapt	return ret;
411262395Sbapt}
412262395Sbapt
413262395Sbapt/**
414262395Sbapt * Expand a single variable
415262395Sbapt * @param parser
416262395Sbapt * @param ptr
417262395Sbapt * @param remain
418262395Sbapt * @param dest
419262395Sbapt * @return
420262395Sbapt */
421262395Sbaptstatic const char *
422262395Sbaptucl_expand_single_variable (struct ucl_parser *parser, const char *ptr,
423262395Sbapt		size_t remain, unsigned char **dest)
424262395Sbapt{
425266636Sbapt	unsigned char *d = *dest, *dst;
426262395Sbapt	const char *p = ptr + 1, *ret;
427262395Sbapt	struct ucl_variable *var;
428266636Sbapt	size_t dstlen;
429266636Sbapt	bool need_free = false;
430262395Sbapt	bool found = false;
431266636Sbapt	bool strict = false;
432262395Sbapt
433262395Sbapt	ret = ptr + 1;
434262395Sbapt	remain --;
435262395Sbapt
436262395Sbapt	if (*p == '$') {
437262395Sbapt		*d++ = *p++;
438262395Sbapt		*dest = d;
439262395Sbapt		return p;
440262395Sbapt	}
441262395Sbapt	else if (*p == '{') {
442262395Sbapt		p ++;
443266636Sbapt		strict = true;
444262395Sbapt		ret += 2;
445262395Sbapt		remain -= 2;
446262395Sbapt	}
447262395Sbapt
448262395Sbapt	LL_FOREACH (parser->variables, var) {
449262395Sbapt		if (remain >= var->var_len) {
450262395Sbapt			if (memcmp (p, var->var, var->var_len) == 0) {
451262395Sbapt				memcpy (d, var->value, var->value_len);
452262395Sbapt				ret += var->var_len;
453262395Sbapt				d += var->value_len;
454262395Sbapt				found = true;
455262395Sbapt				break;
456262395Sbapt			}
457262395Sbapt		}
458262395Sbapt	}
459262395Sbapt	if (!found) {
460266636Sbapt		if (strict && parser->var_handler != NULL) {
461266636Sbapt			if (parser->var_handler (ptr, remain, &dst, &dstlen, &need_free,
462266636Sbapt							parser->var_data)) {
463266636Sbapt				memcpy (d, dst, dstlen);
464266636Sbapt				ret += dstlen;
465266636Sbapt				d += remain;
466266636Sbapt				found = true;
467266636Sbapt			}
468266636Sbapt		}
469266636Sbapt
470266636Sbapt		/* Leave variable as is */
471266636Sbapt		if (!found) {
472268831Sbapt			if (strict) {
473268831Sbapt				/* Copy '${' */
474268831Sbapt				memcpy (d, ptr, 2);
475268831Sbapt				d += 2;
476268831Sbapt				ret --;
477268831Sbapt			}
478268831Sbapt			else {
479268831Sbapt				memcpy (d, ptr, 1);
480268831Sbapt				d ++;
481268831Sbapt			}
482266636Sbapt		}
483262395Sbapt	}
484262395Sbapt
485262395Sbapt	*dest = d;
486262395Sbapt	return ret;
487262395Sbapt}
488262395Sbapt
489262395Sbapt/**
490262395Sbapt * Expand variables in string
491262395Sbapt * @param parser
492262395Sbapt * @param dst
493262395Sbapt * @param src
494262395Sbapt * @param in_len
495262395Sbapt * @return
496262395Sbapt */
497262395Sbaptstatic ssize_t
498262395Sbaptucl_expand_variable (struct ucl_parser *parser, unsigned char **dst,
499262395Sbapt		const char *src, size_t in_len)
500262395Sbapt{
501262395Sbapt	const char *p, *end = src + in_len;
502262395Sbapt	unsigned char *d;
503262395Sbapt	size_t out_len = 0;
504262395Sbapt	bool vars_found = false;
505262395Sbapt
506298166Sbapt	if (parser->flags & UCL_PARSER_DISABLE_MACRO) {
507298166Sbapt		*dst = NULL;
508298166Sbapt		return in_len;
509298166Sbapt	}
510298166Sbapt
511262395Sbapt	p = src;
512262395Sbapt	while (p != end) {
513262395Sbapt		if (*p == '$') {
514262395Sbapt			p = ucl_check_variable (parser, p + 1, end - p - 1, &out_len, &vars_found);
515262395Sbapt		}
516262395Sbapt		else {
517262395Sbapt			p ++;
518262395Sbapt			out_len ++;
519262395Sbapt		}
520262395Sbapt	}
521262395Sbapt
522262395Sbapt	if (!vars_found) {
523262395Sbapt		/* Trivial case */
524262395Sbapt		*dst = NULL;
525262395Sbapt		return in_len;
526262395Sbapt	}
527262395Sbapt
528262395Sbapt	*dst = UCL_ALLOC (out_len + 1);
529262395Sbapt	if (*dst == NULL) {
530262395Sbapt		return in_len;
531262395Sbapt	}
532262395Sbapt
533262395Sbapt	d = *dst;
534262395Sbapt	p = src;
535262395Sbapt	while (p != end) {
536262395Sbapt		if (*p == '$') {
537262395Sbapt			p = ucl_expand_single_variable (parser, p, end - p, &d);
538262395Sbapt		}
539262395Sbapt		else {
540262395Sbapt			*d++ = *p++;
541262395Sbapt		}
542262395Sbapt	}
543262395Sbapt
544262395Sbapt	*d = '\0';
545262395Sbapt
546262395Sbapt	return out_len;
547262395Sbapt}
548262395Sbapt
549262395Sbapt/**
550262395Sbapt * Store or copy pointer to the trash stack
551262395Sbapt * @param parser parser object
552262395Sbapt * @param src src string
553262395Sbapt * @param dst destination buffer (trash stack pointer)
554262395Sbapt * @param dst_const const destination pointer (e.g. value of object)
555262395Sbapt * @param in_len input length
556262395Sbapt * @param need_unescape need to unescape source (and copy it)
557262395Sbapt * @param need_lowercase need to lowercase value (and copy)
558262395Sbapt * @param need_expand need to expand variables (and copy as well)
559262395Sbapt * @return output length (excluding \0 symbol)
560262395Sbapt */
561262395Sbaptstatic inline ssize_t
562262395Sbaptucl_copy_or_store_ptr (struct ucl_parser *parser,
563262395Sbapt		const unsigned char *src, unsigned char **dst,
564262395Sbapt		const char **dst_const, size_t in_len,
565262395Sbapt		bool need_unescape, bool need_lowercase, bool need_expand)
566262395Sbapt{
567262395Sbapt	ssize_t ret = -1, tret;
568262395Sbapt	unsigned char *tmp;
569262395Sbapt
570262395Sbapt	if (need_unescape || need_lowercase ||
571262395Sbapt			(need_expand && parser->variables != NULL) ||
572262395Sbapt			!(parser->flags & UCL_PARSER_ZEROCOPY)) {
573262395Sbapt		/* Copy string */
574262395Sbapt		*dst = UCL_ALLOC (in_len + 1);
575262395Sbapt		if (*dst == NULL) {
576290071Sbapt			ucl_set_err (parser, UCL_EINTERNAL, "cannot allocate memory for a string",
577275223Sbapt					&parser->err);
578262395Sbapt			return false;
579262395Sbapt		}
580262395Sbapt		if (need_lowercase) {
581262395Sbapt			ret = ucl_strlcpy_tolower (*dst, src, in_len + 1);
582262395Sbapt		}
583262395Sbapt		else {
584262395Sbapt			ret = ucl_strlcpy_unsafe (*dst, src, in_len + 1);
585262395Sbapt		}
586262395Sbapt
587262395Sbapt		if (need_unescape) {
588262395Sbapt			ret = ucl_unescape_json_string (*dst, ret);
589262395Sbapt		}
590262395Sbapt		if (need_expand) {
591262395Sbapt			tmp = *dst;
592262395Sbapt			tret = ret;
593262395Sbapt			ret = ucl_expand_variable (parser, dst, tmp, ret);
594262395Sbapt			if (*dst == NULL) {
595262395Sbapt				/* Nothing to expand */
596262395Sbapt				*dst = tmp;
597262395Sbapt				ret = tret;
598262395Sbapt			}
599275223Sbapt			else {
600275223Sbapt				/* Free unexpanded value */
601275223Sbapt				UCL_FREE (in_len + 1, tmp);
602275223Sbapt			}
603262395Sbapt		}
604262395Sbapt		*dst_const = *dst;
605262395Sbapt	}
606262395Sbapt	else {
607262395Sbapt		*dst_const = src;
608262395Sbapt		ret = in_len;
609262395Sbapt	}
610262395Sbapt
611262395Sbapt	return ret;
612262395Sbapt}
613262395Sbapt
614262395Sbapt/**
615262395Sbapt * Create and append an object at the specified level
616262395Sbapt * @param parser
617262395Sbapt * @param is_array
618262395Sbapt * @param level
619262395Sbapt * @return
620262395Sbapt */
621262395Sbaptstatic inline ucl_object_t *
622290071Sbaptucl_parser_add_container (ucl_object_t *obj, struct ucl_parser *parser,
623290071Sbapt		bool is_array, int level)
624262395Sbapt{
625262395Sbapt	struct ucl_stack *st;
626262395Sbapt
627262395Sbapt	if (!is_array) {
628262395Sbapt		if (obj == NULL) {
629275223Sbapt			obj = ucl_object_new_full (UCL_OBJECT, parser->chunks->priority);
630262395Sbapt		}
631262395Sbapt		else {
632262395Sbapt			obj->type = UCL_OBJECT;
633262395Sbapt		}
634290071Sbapt		if (obj->value.ov == NULL) {
635290071Sbapt			obj->value.ov = ucl_hash_create (parser->flags & UCL_PARSER_KEY_LOWERCASE);
636290071Sbapt		}
637262395Sbapt		parser->state = UCL_STATE_KEY;
638262395Sbapt	}
639262395Sbapt	else {
640262395Sbapt		if (obj == NULL) {
641275223Sbapt			obj = ucl_object_new_full (UCL_ARRAY, parser->chunks->priority);
642262395Sbapt		}
643262395Sbapt		else {
644262395Sbapt			obj->type = UCL_ARRAY;
645262395Sbapt		}
646262395Sbapt		parser->state = UCL_STATE_VALUE;
647262395Sbapt	}
648262395Sbapt
649262395Sbapt	st = UCL_ALLOC (sizeof (struct ucl_stack));
650298166Sbapt
651263648Sbapt	if (st == NULL) {
652290071Sbapt		ucl_set_err (parser, UCL_EINTERNAL, "cannot allocate memory for an object",
653275223Sbapt				&parser->err);
654275223Sbapt		ucl_object_unref (obj);
655263648Sbapt		return NULL;
656263648Sbapt	}
657298166Sbapt
658262395Sbapt	st->obj = obj;
659262395Sbapt	st->level = level;
660262395Sbapt	LL_PREPEND (parser->stack, st);
661262395Sbapt	parser->cur_obj = obj;
662262395Sbapt
663262395Sbapt	return obj;
664262395Sbapt}
665262395Sbapt
666262395Sbaptint
667262395Sbaptucl_maybe_parse_number (ucl_object_t *obj,
668263648Sbapt		const char *start, const char *end, const char **pos,
669263648Sbapt		bool allow_double, bool number_bytes, bool allow_time)
670262395Sbapt{
671262395Sbapt	const char *p = start, *c = start;
672262395Sbapt	char *endptr;
673262395Sbapt	bool got_dot = false, got_exp = false, need_double = false,
674263648Sbapt			is_time = false, valid_start = false, is_hex = false,
675262395Sbapt			is_neg = false;
676262395Sbapt	double dv = 0;
677262395Sbapt	int64_t lv = 0;
678262395Sbapt
679262395Sbapt	if (*p == '-') {
680262395Sbapt		is_neg = true;
681262395Sbapt		c ++;
682262395Sbapt		p ++;
683262395Sbapt	}
684262395Sbapt	while (p < end) {
685262395Sbapt		if (is_hex && isxdigit (*p)) {
686262395Sbapt			p ++;
687262395Sbapt		}
688262395Sbapt		else if (isdigit (*p)) {
689262395Sbapt			valid_start = true;
690262395Sbapt			p ++;
691262395Sbapt		}
692262395Sbapt		else if (!is_hex && (*p == 'x' || *p == 'X')) {
693262395Sbapt			is_hex = true;
694262395Sbapt			allow_double = false;
695262395Sbapt			c = p + 1;
696262395Sbapt		}
697262395Sbapt		else if (allow_double) {
698262395Sbapt			if (p == c) {
699262395Sbapt				/* Empty digits sequence, not a number */
700262395Sbapt				*pos = start;
701262395Sbapt				return EINVAL;
702262395Sbapt			}
703262395Sbapt			else if (*p == '.') {
704262395Sbapt				if (got_dot) {
705262395Sbapt					/* Double dots, not a number */
706262395Sbapt					*pos = start;
707262395Sbapt					return EINVAL;
708262395Sbapt				}
709262395Sbapt				else {
710262395Sbapt					got_dot = true;
711262395Sbapt					need_double = true;
712262395Sbapt					p ++;
713262395Sbapt				}
714262395Sbapt			}
715262395Sbapt			else if (*p == 'e' || *p == 'E') {
716262395Sbapt				if (got_exp) {
717262395Sbapt					/* Double exp, not a number */
718262395Sbapt					*pos = start;
719262395Sbapt					return EINVAL;
720262395Sbapt				}
721262395Sbapt				else {
722262395Sbapt					got_exp = true;
723262395Sbapt					need_double = true;
724262395Sbapt					p ++;
725262395Sbapt					if (p >= end) {
726262395Sbapt						*pos = start;
727262395Sbapt						return EINVAL;
728262395Sbapt					}
729262395Sbapt					if (!isdigit (*p) && *p != '+' && *p != '-') {
730262395Sbapt						/* Wrong exponent sign */
731262395Sbapt						*pos = start;
732262395Sbapt						return EINVAL;
733262395Sbapt					}
734262395Sbapt					else {
735262395Sbapt						p ++;
736262395Sbapt					}
737262395Sbapt				}
738262395Sbapt			}
739262395Sbapt			else {
740262395Sbapt				/* Got the end of the number, need to check */
741262395Sbapt				break;
742262395Sbapt			}
743262395Sbapt		}
744262395Sbapt		else {
745262395Sbapt			break;
746262395Sbapt		}
747262395Sbapt	}
748262395Sbapt
749262395Sbapt	if (!valid_start) {
750262395Sbapt		*pos = start;
751262395Sbapt		return EINVAL;
752262395Sbapt	}
753262395Sbapt
754262395Sbapt	errno = 0;
755262395Sbapt	if (need_double) {
756262395Sbapt		dv = strtod (c, &endptr);
757262395Sbapt	}
758262395Sbapt	else {
759262395Sbapt		if (is_hex) {
760262395Sbapt			lv = strtoimax (c, &endptr, 16);
761262395Sbapt		}
762262395Sbapt		else {
763262395Sbapt			lv = strtoimax (c, &endptr, 10);
764262395Sbapt		}
765262395Sbapt	}
766262395Sbapt	if (errno == ERANGE) {
767262395Sbapt		*pos = start;
768262395Sbapt		return ERANGE;
769262395Sbapt	}
770262395Sbapt
771262395Sbapt	/* Now check endptr */
772275223Sbapt	if (endptr == NULL || ucl_lex_is_atom_end (*endptr) || *endptr == '\0') {
773262395Sbapt		p = endptr;
774262395Sbapt		goto set_obj;
775262395Sbapt	}
776262395Sbapt
777262395Sbapt	if (endptr < end && endptr != start) {
778262395Sbapt		p = endptr;
779262395Sbapt		switch (*p) {
780262395Sbapt		case 'm':
781262395Sbapt		case 'M':
782262395Sbapt		case 'g':
783262395Sbapt		case 'G':
784262395Sbapt		case 'k':
785262395Sbapt		case 'K':
786262395Sbapt			if (end - p >= 2) {
787262395Sbapt				if (p[1] == 's' || p[1] == 'S') {
788262395Sbapt					/* Milliseconds */
789262395Sbapt					if (!need_double) {
790262395Sbapt						need_double = true;
791262395Sbapt						dv = lv;
792262395Sbapt					}
793263648Sbapt					is_time = true;
794262395Sbapt					if (p[0] == 'm' || p[0] == 'M') {
795262395Sbapt						dv /= 1000.;
796262395Sbapt					}
797262395Sbapt					else {
798262395Sbapt						dv *= ucl_lex_num_multiplier (*p, false);
799262395Sbapt					}
800262395Sbapt					p += 2;
801262395Sbapt					goto set_obj;
802262395Sbapt				}
803262395Sbapt				else if (number_bytes || (p[1] == 'b' || p[1] == 'B')) {
804262395Sbapt					/* Bytes */
805262395Sbapt					if (need_double) {
806262395Sbapt						need_double = false;
807262395Sbapt						lv = dv;
808262395Sbapt					}
809262395Sbapt					lv *= ucl_lex_num_multiplier (*p, true);
810262395Sbapt					p += 2;
811262395Sbapt					goto set_obj;
812262395Sbapt				}
813262395Sbapt				else if (ucl_lex_is_atom_end (p[1])) {
814262395Sbapt					if (need_double) {
815262395Sbapt						dv *= ucl_lex_num_multiplier (*p, false);
816262395Sbapt					}
817262395Sbapt					else {
818262395Sbapt						lv *= ucl_lex_num_multiplier (*p, number_bytes);
819262395Sbapt					}
820262395Sbapt					p ++;
821262395Sbapt					goto set_obj;
822262395Sbapt				}
823263648Sbapt				else if (allow_time && end - p >= 3) {
824262395Sbapt					if (tolower (p[0]) == 'm' &&
825262395Sbapt							tolower (p[1]) == 'i' &&
826262395Sbapt							tolower (p[2]) == 'n') {
827262395Sbapt						/* Minutes */
828262395Sbapt						if (!need_double) {
829262395Sbapt							need_double = true;
830262395Sbapt							dv = lv;
831262395Sbapt						}
832263648Sbapt						is_time = true;
833262395Sbapt						dv *= 60.;
834262395Sbapt						p += 3;
835262395Sbapt						goto set_obj;
836262395Sbapt					}
837262395Sbapt				}
838262395Sbapt			}
839262395Sbapt			else {
840262395Sbapt				if (need_double) {
841262395Sbapt					dv *= ucl_lex_num_multiplier (*p, false);
842262395Sbapt				}
843262395Sbapt				else {
844262395Sbapt					lv *= ucl_lex_num_multiplier (*p, number_bytes);
845262395Sbapt				}
846262395Sbapt				p ++;
847262395Sbapt				goto set_obj;
848262395Sbapt			}
849262395Sbapt			break;
850262395Sbapt		case 'S':
851262395Sbapt		case 's':
852263648Sbapt			if (allow_time &&
853263648Sbapt					(p == end - 1 || ucl_lex_is_atom_end (p[1]))) {
854262395Sbapt				if (!need_double) {
855262395Sbapt					need_double = true;
856262395Sbapt					dv = lv;
857262395Sbapt				}
858262395Sbapt				p ++;
859263648Sbapt				is_time = true;
860262395Sbapt				goto set_obj;
861262395Sbapt			}
862262395Sbapt			break;
863262395Sbapt		case 'h':
864262395Sbapt		case 'H':
865262395Sbapt		case 'd':
866262395Sbapt		case 'D':
867262395Sbapt		case 'w':
868262395Sbapt		case 'W':
869262395Sbapt		case 'Y':
870262395Sbapt		case 'y':
871263648Sbapt			if (allow_time &&
872263648Sbapt					(p == end - 1 || ucl_lex_is_atom_end (p[1]))) {
873262395Sbapt				if (!need_double) {
874262395Sbapt					need_double = true;
875262395Sbapt					dv = lv;
876262395Sbapt				}
877263648Sbapt				is_time = true;
878262395Sbapt				dv *= ucl_lex_time_multiplier (*p);
879262395Sbapt				p ++;
880262395Sbapt				goto set_obj;
881262395Sbapt			}
882262395Sbapt			break;
883275223Sbapt		case '\t':
884275223Sbapt		case ' ':
885275223Sbapt			while (p < end && ucl_test_character(*p, UCL_CHARACTER_WHITESPACE)) {
886275223Sbapt				p++;
887275223Sbapt			}
888275223Sbapt			if (ucl_lex_is_atom_end(*p))
889275223Sbapt				goto set_obj;
890275223Sbapt			break;
891262395Sbapt		}
892262395Sbapt	}
893275223Sbapt	else if (endptr == end) {
894275223Sbapt		/* Just a number at the end of chunk */
895275223Sbapt		p = endptr;
896275223Sbapt		goto set_obj;
897275223Sbapt	}
898262395Sbapt
899262395Sbapt	*pos = c;
900262395Sbapt	return EINVAL;
901262395Sbapt
902290071Sbaptset_obj:
903290071Sbapt	if (obj != NULL) {
904290071Sbapt		if (allow_double && (need_double || is_time)) {
905290071Sbapt			if (!is_time) {
906290071Sbapt				obj->type = UCL_FLOAT;
907290071Sbapt			}
908290071Sbapt			else {
909290071Sbapt				obj->type = UCL_TIME;
910290071Sbapt			}
911290071Sbapt			obj->value.dv = is_neg ? (-dv) : dv;
912262395Sbapt		}
913262395Sbapt		else {
914290071Sbapt			obj->type = UCL_INT;
915290071Sbapt			obj->value.iv = is_neg ? (-lv) : lv;
916262395Sbapt		}
917262395Sbapt	}
918262395Sbapt	*pos = p;
919262395Sbapt	return 0;
920262395Sbapt}
921262395Sbapt
922262395Sbapt/**
923262395Sbapt * Parse possible number
924262395Sbapt * @param parser
925262395Sbapt * @param chunk
926290071Sbapt * @param obj
927262395Sbapt * @return true if a number has been parsed
928262395Sbapt */
929262395Sbaptstatic bool
930262395Sbaptucl_lex_number (struct ucl_parser *parser,
931262395Sbapt		struct ucl_chunk *chunk, ucl_object_t *obj)
932262395Sbapt{
933262395Sbapt	const unsigned char *pos;
934262395Sbapt	int ret;
935262395Sbapt
936263648Sbapt	ret = ucl_maybe_parse_number (obj, chunk->pos, chunk->end, (const char **)&pos,
937263648Sbapt			true, false, ((parser->flags & UCL_PARSER_NO_TIME) == 0));
938262395Sbapt
939262395Sbapt	if (ret == 0) {
940262395Sbapt		chunk->remain -= pos - chunk->pos;
941262395Sbapt		chunk->column += pos - chunk->pos;
942262395Sbapt		chunk->pos = pos;
943262395Sbapt		return true;
944262395Sbapt	}
945262395Sbapt	else if (ret == ERANGE) {
946290071Sbapt		ucl_set_err (parser, UCL_ESYNTAX, "numeric value out of range",
947290071Sbapt				&parser->err);
948262395Sbapt	}
949262395Sbapt
950262395Sbapt	return false;
951262395Sbapt}
952262395Sbapt
953262395Sbapt/**
954262395Sbapt * Parse quoted string with possible escapes
955262395Sbapt * @param parser
956262395Sbapt * @param chunk
957290071Sbapt * @param need_unescape
958290071Sbapt * @param ucl_escape
959290071Sbapt * @param var_expand
960262395Sbapt * @return true if a string has been parsed
961262395Sbapt */
962262395Sbaptstatic bool
963262395Sbaptucl_lex_json_string (struct ucl_parser *parser,
964262395Sbapt		struct ucl_chunk *chunk, bool *need_unescape, bool *ucl_escape, bool *var_expand)
965262395Sbapt{
966262395Sbapt	const unsigned char *p = chunk->pos;
967262395Sbapt	unsigned char c;
968262395Sbapt	int i;
969262395Sbapt
970262395Sbapt	while (p < chunk->end) {
971262395Sbapt		c = *p;
972262395Sbapt		if (c < 0x1F) {
973262395Sbapt			/* Unmasked control character */
974262395Sbapt			if (c == '\n') {
975275223Sbapt				ucl_set_err (parser, UCL_ESYNTAX, "unexpected newline",
976275223Sbapt						&parser->err);
977262395Sbapt			}
978262395Sbapt			else {
979275223Sbapt				ucl_set_err (parser, UCL_ESYNTAX, "unexpected control character",
980275223Sbapt						&parser->err);
981262395Sbapt			}
982262395Sbapt			return false;
983262395Sbapt		}
984262395Sbapt		else if (c == '\\') {
985262395Sbapt			ucl_chunk_skipc (chunk, p);
986262395Sbapt			c = *p;
987262395Sbapt			if (p >= chunk->end) {
988275223Sbapt				ucl_set_err (parser, UCL_ESYNTAX, "unfinished escape character",
989275223Sbapt						&parser->err);
990262395Sbapt				return false;
991262395Sbapt			}
992262395Sbapt			else if (ucl_test_character (c, UCL_CHARACTER_ESCAPE)) {
993262395Sbapt				if (c == 'u') {
994262395Sbapt					ucl_chunk_skipc (chunk, p);
995262395Sbapt					for (i = 0; i < 4 && p < chunk->end; i ++) {
996262395Sbapt						if (!isxdigit (*p)) {
997275223Sbapt							ucl_set_err (parser, UCL_ESYNTAX, "invalid utf escape",
998275223Sbapt									&parser->err);
999262395Sbapt							return false;
1000262395Sbapt						}
1001262395Sbapt						ucl_chunk_skipc (chunk, p);
1002262395Sbapt					}
1003262395Sbapt					if (p >= chunk->end) {
1004275223Sbapt						ucl_set_err (parser, UCL_ESYNTAX, "unfinished escape character",
1005275223Sbapt								&parser->err);
1006262395Sbapt						return false;
1007262395Sbapt					}
1008262395Sbapt				}
1009262395Sbapt				else {
1010262395Sbapt					ucl_chunk_skipc (chunk, p);
1011262395Sbapt				}
1012262395Sbapt			}
1013262395Sbapt			*need_unescape = true;
1014262395Sbapt			*ucl_escape = true;
1015262395Sbapt			continue;
1016262395Sbapt		}
1017262395Sbapt		else if (c == '"') {
1018262395Sbapt			ucl_chunk_skipc (chunk, p);
1019262395Sbapt			return true;
1020262395Sbapt		}
1021262395Sbapt		else if (ucl_test_character (c, UCL_CHARACTER_UCL_UNSAFE)) {
1022262395Sbapt			*ucl_escape = true;
1023262395Sbapt		}
1024262395Sbapt		else if (c == '$') {
1025262395Sbapt			*var_expand = true;
1026262395Sbapt		}
1027262395Sbapt		ucl_chunk_skipc (chunk, p);
1028262395Sbapt	}
1029262395Sbapt
1030275223Sbapt	ucl_set_err (parser, UCL_ESYNTAX, "no quote at the end of json string",
1031275223Sbapt			&parser->err);
1032262395Sbapt	return false;
1033262395Sbapt}
1034262395Sbapt
1035275223Sbaptstatic void
1036275223Sbaptucl_parser_append_elt (struct ucl_parser *parser, ucl_hash_t *cont,
1037275223Sbapt		ucl_object_t *top,
1038275223Sbapt		ucl_object_t *elt)
1039275223Sbapt{
1040275223Sbapt	ucl_object_t *nobj;
1041275223Sbapt
1042275223Sbapt	if ((parser->flags & UCL_PARSER_NO_IMPLICIT_ARRAYS) == 0) {
1043275223Sbapt		/* Implicit array */
1044275223Sbapt		top->flags |= UCL_OBJECT_MULTIVALUE;
1045275223Sbapt		DL_APPEND (top, elt);
1046290071Sbapt		parser->stack->obj->len ++;
1047275223Sbapt	}
1048275223Sbapt	else {
1049275223Sbapt		if ((top->flags & UCL_OBJECT_MULTIVALUE) != 0) {
1050275223Sbapt			/* Just add to the explicit array */
1051279549Sbapt			ucl_array_append (top, elt);
1052275223Sbapt		}
1053275223Sbapt		else {
1054275223Sbapt			/* Convert to an array */
1055275223Sbapt			nobj = ucl_object_typed_new (UCL_ARRAY);
1056275223Sbapt			nobj->key = top->key;
1057275223Sbapt			nobj->keylen = top->keylen;
1058275223Sbapt			nobj->flags |= UCL_OBJECT_MULTIVALUE;
1059279549Sbapt			ucl_array_append (nobj, top);
1060279549Sbapt			ucl_array_append (nobj, elt);
1061290071Sbapt			ucl_hash_replace (cont, top, nobj);
1062275223Sbapt		}
1063275223Sbapt	}
1064275223Sbapt}
1065275223Sbapt
1066290071Sbaptbool
1067290071Sbaptucl_parser_process_object_element (struct ucl_parser *parser, ucl_object_t *nobj)
1068290071Sbapt{
1069290071Sbapt	ucl_hash_t *container;
1070290071Sbapt	ucl_object_t *tobj;
1071298166Sbapt	char errmsg[256];
1072290071Sbapt
1073290071Sbapt	container = parser->stack->obj->value.ov;
1074290071Sbapt
1075290071Sbapt	tobj = __DECONST (ucl_object_t *, ucl_hash_search_obj (container, nobj));
1076290071Sbapt	if (tobj == NULL) {
1077290071Sbapt		container = ucl_hash_insert_object (container, nobj,
1078290071Sbapt				parser->flags & UCL_PARSER_KEY_LOWERCASE);
1079290071Sbapt		nobj->prev = nobj;
1080290071Sbapt		nobj->next = NULL;
1081290071Sbapt		parser->stack->obj->len ++;
1082290071Sbapt	}
1083290071Sbapt	else {
1084290071Sbapt		unsigned priold = ucl_object_get_priority (tobj),
1085290071Sbapt				prinew = ucl_object_get_priority (nobj);
1086290071Sbapt		switch (parser->chunks->strategy) {
1087290071Sbapt
1088290071Sbapt		case UCL_DUPLICATE_APPEND:
1089290071Sbapt			/*
1090290071Sbapt			 * The logic here is the following:
1091290071Sbapt			 *
1092290071Sbapt			 * - if we have two objects with the same priority, then we form an
1093290071Sbapt			 * implicit or explicit array
1094290071Sbapt			 * - if a new object has bigger priority, then we overwrite an old one
1095290071Sbapt			 * - if a new object has lower priority, then we ignore it
1096290071Sbapt			 */
1097290071Sbapt
1098290071Sbapt
1099290071Sbapt			/* Special case for inherited objects */
1100290071Sbapt			if (tobj->flags & UCL_OBJECT_INHERITED) {
1101290071Sbapt				prinew = priold + 1;
1102290071Sbapt			}
1103290071Sbapt
1104290071Sbapt			if (priold == prinew) {
1105290071Sbapt				ucl_parser_append_elt (parser, container, tobj, nobj);
1106290071Sbapt			}
1107290071Sbapt			else if (priold > prinew) {
1108290071Sbapt				/*
1109290071Sbapt				 * We add this new object to a list of trash objects just to ensure
1110290071Sbapt				 * that it won't come to any real object
1111290071Sbapt				 * XXX: rather inefficient approach
1112290071Sbapt				 */
1113290071Sbapt				DL_APPEND (parser->trash_objs, nobj);
1114290071Sbapt			}
1115290071Sbapt			else {
1116290071Sbapt				ucl_hash_replace (container, tobj, nobj);
1117290071Sbapt				ucl_object_unref (tobj);
1118290071Sbapt			}
1119290071Sbapt
1120290071Sbapt			break;
1121290071Sbapt
1122290071Sbapt		case UCL_DUPLICATE_REWRITE:
1123290071Sbapt			/* We just rewrite old values regardless of priority */
1124290071Sbapt			ucl_hash_replace (container, tobj, nobj);
1125290071Sbapt			ucl_object_unref (tobj);
1126290071Sbapt
1127290071Sbapt			break;
1128290071Sbapt
1129290071Sbapt		case UCL_DUPLICATE_ERROR:
1130298166Sbapt			snprintf(errmsg, sizeof(errmsg),
1131298166Sbapt					"duplicate element for key '%s' found",
1132298166Sbapt					nobj->key);
1133298166Sbapt			ucl_set_err (parser, UCL_EMERGE, errmsg, &parser->err);
1134290071Sbapt			return false;
1135290071Sbapt
1136290071Sbapt		case UCL_DUPLICATE_MERGE:
1137290071Sbapt			/*
1138290071Sbapt			 * Here we do have some old object so we just push it on top of objects stack
1139298166Sbapt			 * Check priority and then perform the merge on the remaining objects
1140290071Sbapt			 */
1141290071Sbapt			if (tobj->type == UCL_OBJECT || tobj->type == UCL_ARRAY) {
1142290071Sbapt				ucl_object_unref (nobj);
1143290071Sbapt				nobj = tobj;
1144290071Sbapt			}
1145298166Sbapt			else if (priold == prinew) {
1146290071Sbapt				ucl_parser_append_elt (parser, container, tobj, nobj);
1147290071Sbapt			}
1148298166Sbapt			else if (priold > prinew) {
1149298166Sbapt				/*
1150298166Sbapt				 * We add this new object to a list of trash objects just to ensure
1151298166Sbapt				 * that it won't come to any real object
1152298166Sbapt				 * XXX: rather inefficient approach
1153298166Sbapt				 */
1154298166Sbapt				DL_APPEND (parser->trash_objs, nobj);
1155298166Sbapt			}
1156298166Sbapt			else {
1157298166Sbapt				ucl_hash_replace (container, tobj, nobj);
1158298166Sbapt				ucl_object_unref (tobj);
1159298166Sbapt			}
1160290071Sbapt			break;
1161290071Sbapt		}
1162290071Sbapt	}
1163290071Sbapt
1164290071Sbapt	parser->stack->obj->value.ov = container;
1165290071Sbapt	parser->cur_obj = nobj;
1166298166Sbapt	ucl_attach_comment (parser, nobj, false);
1167290071Sbapt
1168290071Sbapt	return true;
1169290071Sbapt}
1170290071Sbapt
1171262395Sbapt/**
1172262395Sbapt * Parse a key in an object
1173262395Sbapt * @param parser
1174262395Sbapt * @param chunk
1175290071Sbapt * @param next_key
1176290071Sbapt * @param end_of_object
1177262395Sbapt * @return true if a key has been parsed
1178262395Sbapt */
1179262395Sbaptstatic bool
1180290071Sbaptucl_parse_key (struct ucl_parser *parser, struct ucl_chunk *chunk,
1181290071Sbapt		bool *next_key, bool *end_of_object)
1182262395Sbapt{
1183262395Sbapt	const unsigned char *p, *c = NULL, *end, *t;
1184262395Sbapt	const char *key = NULL;
1185262395Sbapt	bool got_quote = false, got_eq = false, got_semicolon = false,
1186262395Sbapt			need_unescape = false, ucl_escape = false, var_expand = false,
1187262395Sbapt			got_content = false, got_sep = false;
1188290071Sbapt	ucl_object_t *nobj;
1189262395Sbapt	ssize_t keylen;
1190262395Sbapt
1191262395Sbapt	p = chunk->pos;
1192262395Sbapt
1193262395Sbapt	if (*p == '.') {
1194262395Sbapt		/* It is macro actually */
1195298166Sbapt		if (!(parser->flags & UCL_PARSER_DISABLE_MACRO)) {
1196298166Sbapt			ucl_chunk_skipc (chunk, p);
1197298166Sbapt		}
1198298166Sbapt
1199262395Sbapt		parser->prev_state = parser->state;
1200262395Sbapt		parser->state = UCL_STATE_MACRO_NAME;
1201279549Sbapt		*end_of_object = false;
1202262395Sbapt		return true;
1203262395Sbapt	}
1204262395Sbapt	while (p < chunk->end) {
1205262395Sbapt		/*
1206262395Sbapt		 * A key must start with alpha, number, '/' or '_' and end with space character
1207262395Sbapt		 */
1208262395Sbapt		if (c == NULL) {
1209262395Sbapt			if (chunk->remain >= 2 && ucl_lex_is_comment (p[0], p[1])) {
1210262395Sbapt				if (!ucl_skip_comments (parser)) {
1211262395Sbapt					return false;
1212262395Sbapt				}
1213262395Sbapt				p = chunk->pos;
1214262395Sbapt			}
1215262395Sbapt			else if (ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE)) {
1216262395Sbapt				ucl_chunk_skipc (chunk, p);
1217262395Sbapt			}
1218262395Sbapt			else if (ucl_test_character (*p, UCL_CHARACTER_KEY_START)) {
1219262395Sbapt				/* The first symbol */
1220262395Sbapt				c = p;
1221262395Sbapt				ucl_chunk_skipc (chunk, p);
1222262395Sbapt				got_content = true;
1223262395Sbapt			}
1224262395Sbapt			else if (*p == '"') {
1225262395Sbapt				/* JSON style key */
1226262395Sbapt				c = p + 1;
1227262395Sbapt				got_quote = true;
1228262395Sbapt				got_content = true;
1229262395Sbapt				ucl_chunk_skipc (chunk, p);
1230262395Sbapt			}
1231262395Sbapt			else if (*p == '}') {
1232262395Sbapt				/* We have actually end of an object */
1233262395Sbapt				*end_of_object = true;
1234262395Sbapt				return true;
1235262395Sbapt			}
1236262395Sbapt			else if (*p == '.') {
1237262395Sbapt				ucl_chunk_skipc (chunk, p);
1238262395Sbapt				parser->prev_state = parser->state;
1239262395Sbapt				parser->state = UCL_STATE_MACRO_NAME;
1240262395Sbapt				return true;
1241262395Sbapt			}
1242262395Sbapt			else {
1243262395Sbapt				/* Invalid identifier */
1244275223Sbapt				ucl_set_err (parser, UCL_ESYNTAX, "key must begin with a letter",
1245275223Sbapt						&parser->err);
1246262395Sbapt				return false;
1247262395Sbapt			}
1248262395Sbapt		}
1249262395Sbapt		else {
1250262395Sbapt			/* Parse the body of a key */
1251262395Sbapt			if (!got_quote) {
1252262395Sbapt				if (ucl_test_character (*p, UCL_CHARACTER_KEY)) {
1253262395Sbapt					got_content = true;
1254262395Sbapt					ucl_chunk_skipc (chunk, p);
1255262395Sbapt				}
1256262395Sbapt				else if (ucl_test_character (*p, UCL_CHARACTER_KEY_SEP)) {
1257262395Sbapt					end = p;
1258262395Sbapt					break;
1259262395Sbapt				}
1260262395Sbapt				else {
1261275223Sbapt					ucl_set_err (parser, UCL_ESYNTAX, "invalid character in a key",
1262275223Sbapt							&parser->err);
1263262395Sbapt					return false;
1264262395Sbapt				}
1265262395Sbapt			}
1266262395Sbapt			else {
1267262395Sbapt				/* We need to parse json like quoted string */
1268262395Sbapt				if (!ucl_lex_json_string (parser, chunk, &need_unescape, &ucl_escape, &var_expand)) {
1269262395Sbapt					return false;
1270262395Sbapt				}
1271262395Sbapt				/* Always escape keys obtained via json */
1272262395Sbapt				end = chunk->pos - 1;
1273262395Sbapt				p = chunk->pos;
1274262395Sbapt				break;
1275262395Sbapt			}
1276262395Sbapt		}
1277262395Sbapt	}
1278262395Sbapt
1279262395Sbapt	if (p >= chunk->end && got_content) {
1280275223Sbapt		ucl_set_err (parser, UCL_ESYNTAX, "unfinished key", &parser->err);
1281262395Sbapt		return false;
1282262395Sbapt	}
1283262395Sbapt	else if (!got_content) {
1284262395Sbapt		return true;
1285262395Sbapt	}
1286262395Sbapt	*end_of_object = false;
1287262395Sbapt	/* We are now at the end of the key, need to parse the rest */
1288262395Sbapt	while (p < chunk->end) {
1289262395Sbapt		if (ucl_test_character (*p, UCL_CHARACTER_WHITESPACE)) {
1290262395Sbapt			ucl_chunk_skipc (chunk, p);
1291262395Sbapt		}
1292262395Sbapt		else if (*p == '=') {
1293262395Sbapt			if (!got_eq && !got_semicolon) {
1294262395Sbapt				ucl_chunk_skipc (chunk, p);
1295262395Sbapt				got_eq = true;
1296262395Sbapt			}
1297262395Sbapt			else {
1298275223Sbapt				ucl_set_err (parser, UCL_ESYNTAX, "unexpected '=' character",
1299275223Sbapt						&parser->err);
1300262395Sbapt				return false;
1301262395Sbapt			}
1302262395Sbapt		}
1303262395Sbapt		else if (*p == ':') {
1304262395Sbapt			if (!got_eq && !got_semicolon) {
1305262395Sbapt				ucl_chunk_skipc (chunk, p);
1306262395Sbapt				got_semicolon = true;
1307262395Sbapt			}
1308262395Sbapt			else {
1309275223Sbapt				ucl_set_err (parser, UCL_ESYNTAX, "unexpected ':' character",
1310275223Sbapt						&parser->err);
1311262395Sbapt				return false;
1312262395Sbapt			}
1313262395Sbapt		}
1314262395Sbapt		else if (chunk->remain >= 2 && ucl_lex_is_comment (p[0], p[1])) {
1315262395Sbapt			/* Check for comment */
1316262395Sbapt			if (!ucl_skip_comments (parser)) {
1317262395Sbapt				return false;
1318262395Sbapt			}
1319262395Sbapt			p = chunk->pos;
1320262395Sbapt		}
1321262395Sbapt		else {
1322262395Sbapt			/* Start value */
1323262395Sbapt			break;
1324262395Sbapt		}
1325262395Sbapt	}
1326262395Sbapt
1327262395Sbapt	if (p >= chunk->end && got_content) {
1328275223Sbapt		ucl_set_err (parser, UCL_ESYNTAX, "unfinished key", &parser->err);
1329262395Sbapt		return false;
1330262395Sbapt	}
1331262395Sbapt
1332262395Sbapt	got_sep = got_semicolon || got_eq;
1333262395Sbapt
1334262395Sbapt	if (!got_sep) {
1335262395Sbapt		/*
1336262395Sbapt		 * Maybe we have more keys nested, so search for termination character.
1337262395Sbapt		 * Possible choices:
1338262395Sbapt		 * 1) key1 key2 ... keyN [:=] value <- we treat that as error
1339262395Sbapt		 * 2) key1 ... keyN {} or [] <- we treat that as nested objects
1340262395Sbapt		 * 3) key1 value[;,\n] <- we treat that as linear object
1341262395Sbapt		 */
1342262395Sbapt		t = p;
1343262395Sbapt		*next_key = false;
1344262395Sbapt		while (ucl_test_character (*t, UCL_CHARACTER_WHITESPACE)) {
1345262395Sbapt			t ++;
1346262395Sbapt		}
1347262395Sbapt		/* Check first non-space character after a key */
1348262395Sbapt		if (*t != '{' && *t != '[') {
1349262395Sbapt			while (t < chunk->end) {
1350262395Sbapt				if (*t == ',' || *t == ';' || *t == '\n' || *t == '\r') {
1351262395Sbapt					break;
1352262395Sbapt				}
1353262395Sbapt				else if (*t == '{' || *t == '[') {
1354262395Sbapt					*next_key = true;
1355262395Sbapt					break;
1356262395Sbapt				}
1357262395Sbapt				t ++;
1358262395Sbapt			}
1359262395Sbapt		}
1360262395Sbapt	}
1361262395Sbapt
1362262395Sbapt	/* Create a new object */
1363275223Sbapt	nobj = ucl_object_new_full (UCL_NULL, parser->chunks->priority);
1364262395Sbapt	keylen = ucl_copy_or_store_ptr (parser, c, &nobj->trash_stack[UCL_TRASH_KEY],
1365262395Sbapt			&key, end - c, need_unescape, parser->flags & UCL_PARSER_KEY_LOWERCASE, false);
1366262395Sbapt	if (keylen == -1) {
1367264789Sbapt		ucl_object_unref (nobj);
1368262395Sbapt		return false;
1369262395Sbapt	}
1370262395Sbapt	else if (keylen == 0) {
1371275223Sbapt		ucl_set_err (parser, UCL_ESYNTAX, "empty keys are not allowed", &parser->err);
1372264789Sbapt		ucl_object_unref (nobj);
1373262395Sbapt		return false;
1374262395Sbapt	}
1375262395Sbapt
1376262395Sbapt	nobj->key = key;
1377262395Sbapt	nobj->keylen = keylen;
1378290071Sbapt
1379290071Sbapt	if (!ucl_parser_process_object_element (parser, nobj)) {
1380290071Sbapt		return false;
1381262395Sbapt	}
1382262395Sbapt
1383262395Sbapt	if (ucl_escape) {
1384262395Sbapt		nobj->flags |= UCL_OBJECT_NEED_KEY_ESCAPE;
1385262395Sbapt	}
1386262395Sbapt
1387262395Sbapt
1388262395Sbapt	return true;
1389262395Sbapt}
1390262395Sbapt
1391262395Sbapt/**
1392262395Sbapt * Parse a cl string
1393262395Sbapt * @param parser
1394262395Sbapt * @param chunk
1395290071Sbapt * @param var_expand
1396290071Sbapt * @param need_unescape
1397262395Sbapt * @return true if a key has been parsed
1398262395Sbapt */
1399262395Sbaptstatic bool
1400262395Sbaptucl_parse_string_value (struct ucl_parser *parser,
1401262395Sbapt		struct ucl_chunk *chunk, bool *var_expand, bool *need_unescape)
1402262395Sbapt{
1403262395Sbapt	const unsigned char *p;
1404262395Sbapt	enum {
1405262395Sbapt		UCL_BRACE_ROUND = 0,
1406262395Sbapt		UCL_BRACE_SQUARE,
1407262395Sbapt		UCL_BRACE_FIGURE
1408262395Sbapt	};
1409262395Sbapt	int braces[3][2] = {{0, 0}, {0, 0}, {0, 0}};
1410262395Sbapt
1411262395Sbapt	p = chunk->pos;
1412262395Sbapt
1413262395Sbapt	while (p < chunk->end) {
1414262395Sbapt
1415262395Sbapt		/* Skip pairs of figure braces */
1416262395Sbapt		if (*p == '{') {
1417262395Sbapt			braces[UCL_BRACE_FIGURE][0] ++;
1418262395Sbapt		}
1419262395Sbapt		else if (*p == '}') {
1420262395Sbapt			braces[UCL_BRACE_FIGURE][1] ++;
1421262395Sbapt			if (braces[UCL_BRACE_FIGURE][1] <= braces[UCL_BRACE_FIGURE][0]) {
1422262395Sbapt				/* This is not a termination symbol, continue */
1423262395Sbapt				ucl_chunk_skipc (chunk, p);
1424262395Sbapt				continue;
1425262395Sbapt			}
1426262395Sbapt		}
1427262395Sbapt		/* Skip pairs of square braces */
1428262395Sbapt		else if (*p == '[') {
1429262395Sbapt			braces[UCL_BRACE_SQUARE][0] ++;
1430262395Sbapt		}
1431262395Sbapt		else if (*p == ']') {
1432262395Sbapt			braces[UCL_BRACE_SQUARE][1] ++;
1433262395Sbapt			if (braces[UCL_BRACE_SQUARE][1] <= braces[UCL_BRACE_SQUARE][0]) {
1434262395Sbapt				/* This is not a termination symbol, continue */
1435262395Sbapt				ucl_chunk_skipc (chunk, p);
1436262395Sbapt				continue;
1437262395Sbapt			}
1438262395Sbapt		}
1439262395Sbapt		else if (*p == '$') {
1440262395Sbapt			*var_expand = true;
1441262395Sbapt		}
1442262395Sbapt		else if (*p == '\\') {
1443262395Sbapt			*need_unescape = true;
1444262395Sbapt			ucl_chunk_skipc (chunk, p);
1445262395Sbapt			if (p < chunk->end) {
1446262395Sbapt				ucl_chunk_skipc (chunk, p);
1447262395Sbapt			}
1448262395Sbapt			continue;
1449262395Sbapt		}
1450262395Sbapt
1451262395Sbapt		if (ucl_lex_is_atom_end (*p) || (chunk->remain >= 2 && ucl_lex_is_comment (p[0], p[1]))) {
1452262395Sbapt			break;
1453262395Sbapt		}
1454262395Sbapt		ucl_chunk_skipc (chunk, p);
1455262395Sbapt	}
1456262395Sbapt
1457262395Sbapt	return true;
1458262395Sbapt}
1459262395Sbapt
1460262395Sbapt/**
1461262395Sbapt * Parse multiline string ending with \n{term}\n
1462262395Sbapt * @param parser
1463262395Sbapt * @param chunk
1464262395Sbapt * @param term
1465262395Sbapt * @param term_len
1466290071Sbapt * @param beg
1467290071Sbapt * @param var_expand
1468262395Sbapt * @return size of multiline string or 0 in case of error
1469262395Sbapt */
1470262395Sbaptstatic int
1471262395Sbaptucl_parse_multiline_string (struct ucl_parser *parser,
1472262395Sbapt		struct ucl_chunk *chunk, const unsigned char *term,
1473262395Sbapt		int term_len, unsigned char const **beg,
1474262395Sbapt		bool *var_expand)
1475262395Sbapt{
1476275223Sbapt	const unsigned char *p, *c, *tend;
1477262395Sbapt	bool newline = false;
1478262395Sbapt	int len = 0;
1479262395Sbapt
1480262395Sbapt	p = chunk->pos;
1481262395Sbapt
1482262395Sbapt	c = p;
1483262395Sbapt
1484262395Sbapt	while (p < chunk->end) {
1485262395Sbapt		if (newline) {
1486262395Sbapt			if (chunk->end - p < term_len) {
1487262395Sbapt				return 0;
1488262395Sbapt			}
1489275223Sbapt			else if (memcmp (p, term, term_len) == 0) {
1490275223Sbapt				tend = p + term_len;
1491275223Sbapt				if (*tend != '\n' && *tend != ';' && *tend != ',') {
1492275223Sbapt					/* Incomplete terminator */
1493275223Sbapt					ucl_chunk_skipc (chunk, p);
1494275223Sbapt					continue;
1495275223Sbapt				}
1496262395Sbapt				len = p - c;
1497262395Sbapt				chunk->remain -= term_len;
1498262395Sbapt				chunk->pos = p + term_len;
1499262395Sbapt				chunk->column = term_len;
1500262395Sbapt				*beg = c;
1501262395Sbapt				break;
1502262395Sbapt			}
1503262395Sbapt		}
1504262395Sbapt		if (*p == '\n') {
1505262395Sbapt			newline = true;
1506262395Sbapt		}
1507262395Sbapt		else {
1508262395Sbapt			if (*p == '$') {
1509262395Sbapt				*var_expand = true;
1510262395Sbapt			}
1511262395Sbapt			newline = false;
1512262395Sbapt		}
1513262395Sbapt		ucl_chunk_skipc (chunk, p);
1514262395Sbapt	}
1515262395Sbapt
1516262395Sbapt	return len;
1517262395Sbapt}
1518262395Sbapt
1519290071Sbaptstatic inline ucl_object_t*
1520290071Sbaptucl_parser_get_container (struct ucl_parser *parser)
1521262975Sbapt{
1522262975Sbapt	ucl_object_t *t, *obj = NULL;
1523262975Sbapt
1524279549Sbapt	if (parser == NULL || parser->stack == NULL || parser->stack->obj == NULL) {
1525279549Sbapt		return NULL;
1526279549Sbapt	}
1527279549Sbapt
1528262975Sbapt	if (parser->stack->obj->type == UCL_ARRAY) {
1529262975Sbapt		/* Object must be allocated */
1530275223Sbapt		obj = ucl_object_new_full (UCL_NULL, parser->chunks->priority);
1531279549Sbapt		t = parser->stack->obj;
1532290071Sbapt
1533290071Sbapt		if (!ucl_array_append (t, obj)) {
1534290071Sbapt			ucl_object_unref (obj);
1535290071Sbapt			return NULL;
1536290071Sbapt		}
1537290071Sbapt
1538262975Sbapt		parser->cur_obj = obj;
1539298166Sbapt		ucl_attach_comment (parser, obj, false);
1540262975Sbapt	}
1541262975Sbapt	else {
1542262975Sbapt		/* Object has been already allocated */
1543262975Sbapt		obj = parser->cur_obj;
1544262975Sbapt	}
1545262975Sbapt
1546262975Sbapt	return obj;
1547262975Sbapt}
1548262975Sbapt
1549262395Sbapt/**
1550262395Sbapt * Handle value data
1551262395Sbapt * @param parser
1552262395Sbapt * @param chunk
1553262395Sbapt * @return
1554262395Sbapt */
1555262395Sbaptstatic bool
1556262395Sbaptucl_parse_value (struct ucl_parser *parser, struct ucl_chunk *chunk)
1557262395Sbapt{
1558262395Sbapt	const unsigned char *p, *c;
1559262975Sbapt	ucl_object_t *obj = NULL;
1560262395Sbapt	unsigned int stripped_spaces;
1561262395Sbapt	int str_len;
1562262395Sbapt	bool need_unescape = false, ucl_escape = false, var_expand = false;
1563262395Sbapt
1564262395Sbapt	p = chunk->pos;
1565262395Sbapt
1566262975Sbapt	/* Skip any spaces and comments */
1567262975Sbapt	if (ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE) ||
1568262975Sbapt			(chunk->remain >= 2 && ucl_lex_is_comment (p[0], p[1]))) {
1569262975Sbapt		while (p < chunk->end && ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE)) {
1570262975Sbapt			ucl_chunk_skipc (chunk, p);
1571262975Sbapt		}
1572262975Sbapt		if (!ucl_skip_comments (parser)) {
1573262975Sbapt			return false;
1574262975Sbapt		}
1575262975Sbapt		p = chunk->pos;
1576262975Sbapt	}
1577262975Sbapt
1578262395Sbapt	while (p < chunk->end) {
1579262395Sbapt		c = p;
1580262395Sbapt		switch (*p) {
1581262395Sbapt		case '"':
1582262395Sbapt			ucl_chunk_skipc (chunk, p);
1583290071Sbapt
1584290071Sbapt			if (!ucl_lex_json_string (parser, chunk, &need_unescape, &ucl_escape,
1585290071Sbapt					&var_expand)) {
1586262395Sbapt				return false;
1587262395Sbapt			}
1588290071Sbapt
1589290071Sbapt			obj = ucl_parser_get_container (parser);
1590298166Sbapt			if (!obj) {
1591298166Sbapt				return false;
1592298166Sbapt			}
1593298166Sbapt
1594262395Sbapt			str_len = chunk->pos - c - 2;
1595262395Sbapt			obj->type = UCL_STRING;
1596290071Sbapt			if ((str_len = ucl_copy_or_store_ptr (parser, c + 1,
1597290071Sbapt					&obj->trash_stack[UCL_TRASH_VALUE],
1598290071Sbapt					&obj->value.sv, str_len, need_unescape, false,
1599290071Sbapt					var_expand)) == -1) {
1600262395Sbapt				return false;
1601262395Sbapt			}
1602262395Sbapt			obj->len = str_len;
1603290071Sbapt
1604262395Sbapt			parser->state = UCL_STATE_AFTER_VALUE;
1605262395Sbapt			p = chunk->pos;
1606290071Sbapt
1607262395Sbapt			return true;
1608262395Sbapt			break;
1609262395Sbapt		case '{':
1610290071Sbapt			obj = ucl_parser_get_container (parser);
1611262395Sbapt			/* We have a new object */
1612290071Sbapt			obj = ucl_parser_add_container (obj, parser, false, parser->stack->level);
1613263648Sbapt			if (obj == NULL) {
1614263648Sbapt				return false;
1615263648Sbapt			}
1616262395Sbapt
1617262395Sbapt			ucl_chunk_skipc (chunk, p);
1618290071Sbapt
1619262395Sbapt			return true;
1620262395Sbapt			break;
1621262395Sbapt		case '[':
1622290071Sbapt			obj = ucl_parser_get_container (parser);
1623262395Sbapt			/* We have a new array */
1624290071Sbapt			obj = ucl_parser_add_container (obj, parser, true, parser->stack->level);
1625263648Sbapt			if (obj == NULL) {
1626263648Sbapt				return false;
1627263648Sbapt			}
1628262395Sbapt
1629262395Sbapt			ucl_chunk_skipc (chunk, p);
1630290071Sbapt
1631262395Sbapt			return true;
1632262395Sbapt			break;
1633262975Sbapt		case ']':
1634262975Sbapt			/* We have the array ending */
1635262975Sbapt			if (parser->stack && parser->stack->obj->type == UCL_ARRAY) {
1636262975Sbapt				parser->state = UCL_STATE_AFTER_VALUE;
1637262975Sbapt				return true;
1638262975Sbapt			}
1639262975Sbapt			else {
1640262975Sbapt				goto parse_string;
1641262975Sbapt			}
1642262975Sbapt			break;
1643262395Sbapt		case '<':
1644290071Sbapt			obj = ucl_parser_get_container (parser);
1645262395Sbapt			/* We have something like multiline value, which must be <<[A-Z]+\n */
1646262395Sbapt			if (chunk->end - p > 3) {
1647262395Sbapt				if (memcmp (p, "<<", 2) == 0) {
1648262395Sbapt					p += 2;
1649262395Sbapt					/* We allow only uppercase characters in multiline definitions */
1650262395Sbapt					while (p < chunk->end && *p >= 'A' && *p <= 'Z') {
1651262395Sbapt						p ++;
1652262395Sbapt					}
1653262395Sbapt					if (*p =='\n') {
1654262395Sbapt						/* Set chunk positions and start multiline parsing */
1655262395Sbapt						c += 2;
1656262395Sbapt						chunk->remain -= p - c;
1657262395Sbapt						chunk->pos = p + 1;
1658262395Sbapt						chunk->column = 0;
1659262395Sbapt						chunk->line ++;
1660262395Sbapt						if ((str_len = ucl_parse_multiline_string (parser, chunk, c,
1661262395Sbapt								p - c, &c, &var_expand)) == 0) {
1662275223Sbapt							ucl_set_err (parser, UCL_ESYNTAX,
1663275223Sbapt									"unterminated multiline value", &parser->err);
1664262395Sbapt							return false;
1665262395Sbapt						}
1666290071Sbapt
1667262395Sbapt						obj->type = UCL_STRING;
1668290071Sbapt						obj->flags |= UCL_OBJECT_MULTILINE;
1669290071Sbapt						if ((str_len = ucl_copy_or_store_ptr (parser, c,
1670290071Sbapt								&obj->trash_stack[UCL_TRASH_VALUE],
1671290071Sbapt								&obj->value.sv, str_len - 1, false,
1672290071Sbapt								false, var_expand)) == -1) {
1673262395Sbapt							return false;
1674262395Sbapt						}
1675262395Sbapt						obj->len = str_len;
1676290071Sbapt
1677262395Sbapt						parser->state = UCL_STATE_AFTER_VALUE;
1678290071Sbapt
1679262395Sbapt						return true;
1680262395Sbapt					}
1681262395Sbapt				}
1682262395Sbapt			}
1683262395Sbapt			/* Fallback to ordinary strings */
1684262395Sbapt		default:
1685262975Sbaptparse_string:
1686262975Sbapt			if (obj == NULL) {
1687290071Sbapt				obj = ucl_parser_get_container (parser);
1688262395Sbapt			}
1689290071Sbapt
1690262395Sbapt			/* Parse atom */
1691262395Sbapt			if (ucl_test_character (*p, UCL_CHARACTER_VALUE_DIGIT_START)) {
1692262395Sbapt				if (!ucl_lex_number (parser, chunk, obj)) {
1693262395Sbapt					if (parser->state == UCL_STATE_ERROR) {
1694262395Sbapt						return false;
1695262395Sbapt					}
1696262395Sbapt				}
1697262395Sbapt				else {
1698262395Sbapt					parser->state = UCL_STATE_AFTER_VALUE;
1699262395Sbapt					return true;
1700262395Sbapt				}
1701262395Sbapt				/* Fallback to normal string */
1702262395Sbapt			}
1703262395Sbapt
1704290071Sbapt			if (!ucl_parse_string_value (parser, chunk, &var_expand,
1705290071Sbapt					&need_unescape)) {
1706262395Sbapt				return false;
1707262395Sbapt			}
1708262395Sbapt			/* Cut trailing spaces */
1709262395Sbapt			stripped_spaces = 0;
1710262395Sbapt			while (ucl_test_character (*(chunk->pos - 1 - stripped_spaces),
1711262395Sbapt					UCL_CHARACTER_WHITESPACE)) {
1712262395Sbapt				stripped_spaces ++;
1713262395Sbapt			}
1714262395Sbapt			str_len = chunk->pos - c - stripped_spaces;
1715262395Sbapt			if (str_len <= 0) {
1716290071Sbapt				ucl_set_err (parser, UCL_ESYNTAX, "string value must not be empty",
1717275223Sbapt						&parser->err);
1718262395Sbapt				return false;
1719262395Sbapt			}
1720262395Sbapt			else if (str_len == 4 && memcmp (c, "null", 4) == 0) {
1721262395Sbapt				obj->len = 0;
1722262395Sbapt				obj->type = UCL_NULL;
1723262395Sbapt			}
1724262395Sbapt			else if (!ucl_maybe_parse_boolean (obj, c, str_len)) {
1725262395Sbapt				obj->type = UCL_STRING;
1726290071Sbapt				if ((str_len = ucl_copy_or_store_ptr (parser, c,
1727290071Sbapt						&obj->trash_stack[UCL_TRASH_VALUE],
1728262395Sbapt						&obj->value.sv, str_len, need_unescape,
1729262395Sbapt						false, var_expand)) == -1) {
1730262395Sbapt					return false;
1731262395Sbapt				}
1732262395Sbapt				obj->len = str_len;
1733262395Sbapt			}
1734262395Sbapt			parser->state = UCL_STATE_AFTER_VALUE;
1735262395Sbapt			p = chunk->pos;
1736262395Sbapt
1737262395Sbapt			return true;
1738262395Sbapt			break;
1739262395Sbapt		}
1740262395Sbapt	}
1741262395Sbapt
1742262395Sbapt	return true;
1743262395Sbapt}
1744262395Sbapt
1745262395Sbapt/**
1746262395Sbapt * Handle after value data
1747262395Sbapt * @param parser
1748262395Sbapt * @param chunk
1749262395Sbapt * @return
1750262395Sbapt */
1751262395Sbaptstatic bool
1752262395Sbaptucl_parse_after_value (struct ucl_parser *parser, struct ucl_chunk *chunk)
1753262395Sbapt{
1754262395Sbapt	const unsigned char *p;
1755262395Sbapt	bool got_sep = false;
1756262395Sbapt	struct ucl_stack *st;
1757262395Sbapt
1758262395Sbapt	p = chunk->pos;
1759262395Sbapt
1760262395Sbapt	while (p < chunk->end) {
1761262395Sbapt		if (ucl_test_character (*p, UCL_CHARACTER_WHITESPACE)) {
1762262395Sbapt			/* Skip whitespaces */
1763262395Sbapt			ucl_chunk_skipc (chunk, p);
1764262395Sbapt		}
1765262395Sbapt		else if (chunk->remain >= 2 && ucl_lex_is_comment (p[0], p[1])) {
1766262395Sbapt			/* Skip comment */
1767262395Sbapt			if (!ucl_skip_comments (parser)) {
1768262395Sbapt				return false;
1769262395Sbapt			}
1770262395Sbapt			/* Treat comment as a separator */
1771262395Sbapt			got_sep = true;
1772262395Sbapt			p = chunk->pos;
1773262395Sbapt		}
1774262395Sbapt		else if (ucl_test_character (*p, UCL_CHARACTER_VALUE_END)) {
1775262395Sbapt			if (*p == '}' || *p == ']') {
1776262395Sbapt				if (parser->stack == NULL) {
1777275223Sbapt					ucl_set_err (parser, UCL_ESYNTAX,
1778275223Sbapt							"end of array or object detected without corresponding start",
1779275223Sbapt							&parser->err);
1780262395Sbapt					return false;
1781262395Sbapt				}
1782262395Sbapt				if ((*p == '}' && parser->stack->obj->type == UCL_OBJECT) ||
1783262395Sbapt						(*p == ']' && parser->stack->obj->type == UCL_ARRAY)) {
1784262395Sbapt
1785262395Sbapt					/* Pop all nested objects from a stack */
1786262395Sbapt					st = parser->stack;
1787262395Sbapt					parser->stack = st->next;
1788262395Sbapt					UCL_FREE (sizeof (struct ucl_stack), st);
1789262395Sbapt
1790298166Sbapt					if (parser->cur_obj) {
1791298166Sbapt						ucl_attach_comment (parser, parser->cur_obj, true);
1792298166Sbapt					}
1793298166Sbapt
1794262395Sbapt					while (parser->stack != NULL) {
1795262395Sbapt						st = parser->stack;
1796298166Sbapt
1797262395Sbapt						if (st->next == NULL || st->next->level == st->level) {
1798262395Sbapt							break;
1799262395Sbapt						}
1800298166Sbapt
1801262395Sbapt						parser->stack = st->next;
1802298166Sbapt						parser->cur_obj = st->obj;
1803262395Sbapt						UCL_FREE (sizeof (struct ucl_stack), st);
1804262395Sbapt					}
1805262395Sbapt				}
1806262395Sbapt				else {
1807275223Sbapt					ucl_set_err (parser, UCL_ESYNTAX,
1808275223Sbapt							"unexpected terminating symbol detected",
1809275223Sbapt							&parser->err);
1810262395Sbapt					return false;
1811262395Sbapt				}
1812262395Sbapt
1813262395Sbapt				if (parser->stack == NULL) {
1814262395Sbapt					/* Ignore everything after a top object */
1815262395Sbapt					return true;
1816262395Sbapt				}
1817262395Sbapt				else {
1818262395Sbapt					ucl_chunk_skipc (chunk, p);
1819262395Sbapt				}
1820262395Sbapt				got_sep = true;
1821262395Sbapt			}
1822262395Sbapt			else {
1823262395Sbapt				/* Got a separator */
1824262395Sbapt				got_sep = true;
1825262395Sbapt				ucl_chunk_skipc (chunk, p);
1826262395Sbapt			}
1827262395Sbapt		}
1828262395Sbapt		else {
1829262395Sbapt			/* Anything else */
1830262395Sbapt			if (!got_sep) {
1831275223Sbapt				ucl_set_err (parser, UCL_ESYNTAX, "delimiter is missing",
1832275223Sbapt						&parser->err);
1833262395Sbapt				return false;
1834262395Sbapt			}
1835262395Sbapt			return true;
1836262395Sbapt		}
1837262395Sbapt	}
1838262395Sbapt
1839262395Sbapt	return true;
1840262395Sbapt}
1841262395Sbapt
1842298166Sbaptstatic bool
1843298166Sbaptucl_skip_macro_as_comment (struct ucl_parser *parser,
1844298166Sbapt		struct ucl_chunk *chunk)
1845298166Sbapt{
1846298166Sbapt	const unsigned char *p, *c;
1847298166Sbapt	enum {
1848298166Sbapt		macro_skip_start = 0,
1849298166Sbapt		macro_has_symbols,
1850298166Sbapt		macro_has_obrace,
1851298166Sbapt		macro_has_quote,
1852298166Sbapt		macro_has_backslash,
1853298166Sbapt		macro_has_sqbrace,
1854298166Sbapt		macro_save
1855298166Sbapt	} state = macro_skip_start, prev_state = macro_skip_start;
1856298166Sbapt
1857298166Sbapt	p = chunk->pos;
1858298166Sbapt	c = chunk->pos;
1859298166Sbapt
1860298166Sbapt	while (p < chunk->end) {
1861298166Sbapt		switch (state) {
1862298166Sbapt		case macro_skip_start:
1863298166Sbapt			if (!ucl_test_character (*p, UCL_CHARACTER_WHITESPACE)) {
1864298166Sbapt				state = macro_has_symbols;
1865298166Sbapt			}
1866298166Sbapt			else if (ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE)) {
1867298166Sbapt				state = macro_save;
1868298166Sbapt				continue;
1869298166Sbapt			}
1870298166Sbapt
1871298166Sbapt			ucl_chunk_skipc (chunk, p);
1872298166Sbapt			break;
1873298166Sbapt
1874298166Sbapt		case macro_has_symbols:
1875298166Sbapt			if (*p == '{') {
1876298166Sbapt				state = macro_has_sqbrace;
1877298166Sbapt			}
1878298166Sbapt			else if (*p == '(') {
1879298166Sbapt				state = macro_has_obrace;
1880298166Sbapt			}
1881298166Sbapt			else if (*p == '"') {
1882298166Sbapt				state = macro_has_quote;
1883298166Sbapt			}
1884298166Sbapt			else if (*p == '\n') {
1885298166Sbapt				state = macro_save;
1886298166Sbapt				continue;
1887298166Sbapt			}
1888298166Sbapt
1889298166Sbapt			ucl_chunk_skipc (chunk, p);
1890298166Sbapt			break;
1891298166Sbapt
1892298166Sbapt		case macro_has_obrace:
1893298166Sbapt			if (*p == '\\') {
1894298166Sbapt				prev_state = state;
1895298166Sbapt				state = macro_has_backslash;
1896298166Sbapt			}
1897298166Sbapt			else if (*p == ')') {
1898298166Sbapt				state = macro_has_symbols;
1899298166Sbapt			}
1900298166Sbapt
1901298166Sbapt			ucl_chunk_skipc (chunk, p);
1902298166Sbapt			break;
1903298166Sbapt
1904298166Sbapt		case macro_has_sqbrace:
1905298166Sbapt			if (*p == '\\') {
1906298166Sbapt				prev_state = state;
1907298166Sbapt				state = macro_has_backslash;
1908298166Sbapt			}
1909298166Sbapt			else if (*p == '}') {
1910298166Sbapt				state = macro_save;
1911298166Sbapt			}
1912298166Sbapt
1913298166Sbapt			ucl_chunk_skipc (chunk, p);
1914298166Sbapt			break;
1915298166Sbapt
1916298166Sbapt		case macro_has_quote:
1917298166Sbapt			if (*p == '\\') {
1918298166Sbapt				prev_state = state;
1919298166Sbapt				state = macro_has_backslash;
1920298166Sbapt			}
1921298166Sbapt			else if (*p == '"') {
1922298166Sbapt				state = macro_save;
1923298166Sbapt			}
1924298166Sbapt
1925298166Sbapt			ucl_chunk_skipc (chunk, p);
1926298166Sbapt			break;
1927298166Sbapt
1928298166Sbapt		case macro_has_backslash:
1929298166Sbapt			state = prev_state;
1930298166Sbapt			ucl_chunk_skipc (chunk, p);
1931298166Sbapt			break;
1932298166Sbapt
1933298166Sbapt		case macro_save:
1934298166Sbapt			if (parser->flags & UCL_PARSER_SAVE_COMMENTS) {
1935298166Sbapt				ucl_save_comment (parser, c, p - c);
1936298166Sbapt			}
1937298166Sbapt
1938298166Sbapt			return true;
1939298166Sbapt		}
1940298166Sbapt	}
1941298166Sbapt
1942298166Sbapt	return false;
1943298166Sbapt}
1944298166Sbapt
1945262395Sbapt/**
1946262395Sbapt * Handle macro data
1947262395Sbapt * @param parser
1948262395Sbapt * @param chunk
1949290071Sbapt * @param marco
1950290071Sbapt * @param macro_start
1951290071Sbapt * @param macro_len
1952262395Sbapt * @return
1953262395Sbapt */
1954262395Sbaptstatic bool
1955262395Sbaptucl_parse_macro_value (struct ucl_parser *parser,
1956262395Sbapt		struct ucl_chunk *chunk, struct ucl_macro *macro,
1957262395Sbapt		unsigned char const **macro_start, size_t *macro_len)
1958262395Sbapt{
1959262395Sbapt	const unsigned char *p, *c;
1960262395Sbapt	bool need_unescape = false, ucl_escape = false, var_expand = false;
1961262395Sbapt
1962262395Sbapt	p = chunk->pos;
1963262395Sbapt
1964262395Sbapt	switch (*p) {
1965262395Sbapt	case '"':
1966262395Sbapt		/* We have macro value encoded in quotes */
1967262395Sbapt		c = p;
1968262395Sbapt		ucl_chunk_skipc (chunk, p);
1969262395Sbapt		if (!ucl_lex_json_string (parser, chunk, &need_unescape, &ucl_escape, &var_expand)) {
1970262395Sbapt			return false;
1971262395Sbapt		}
1972262395Sbapt
1973262395Sbapt		*macro_start = c + 1;
1974262395Sbapt		*macro_len = chunk->pos - c - 2;
1975262395Sbapt		p = chunk->pos;
1976262395Sbapt		break;
1977262395Sbapt	case '{':
1978262395Sbapt		/* We got a multiline macro body */
1979262395Sbapt		ucl_chunk_skipc (chunk, p);
1980262395Sbapt		/* Skip spaces at the beginning */
1981262395Sbapt		while (p < chunk->end) {
1982262395Sbapt			if (ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE)) {
1983262395Sbapt				ucl_chunk_skipc (chunk, p);
1984262395Sbapt			}
1985262395Sbapt			else {
1986262395Sbapt				break;
1987262395Sbapt			}
1988262395Sbapt		}
1989262395Sbapt		c = p;
1990262395Sbapt		while (p < chunk->end) {
1991262395Sbapt			if (*p == '}') {
1992262395Sbapt				break;
1993262395Sbapt			}
1994262395Sbapt			ucl_chunk_skipc (chunk, p);
1995262395Sbapt		}
1996262395Sbapt		*macro_start = c;
1997262395Sbapt		*macro_len = p - c;
1998262395Sbapt		ucl_chunk_skipc (chunk, p);
1999262395Sbapt		break;
2000262395Sbapt	default:
2001262395Sbapt		/* Macro is not enclosed in quotes or braces */
2002262395Sbapt		c = p;
2003262395Sbapt		while (p < chunk->end) {
2004262395Sbapt			if (ucl_lex_is_atom_end (*p)) {
2005262395Sbapt				break;
2006262395Sbapt			}
2007262395Sbapt			ucl_chunk_skipc (chunk, p);
2008262395Sbapt		}
2009262395Sbapt		*macro_start = c;
2010262395Sbapt		*macro_len = p - c;
2011262395Sbapt		break;
2012262395Sbapt	}
2013262395Sbapt
2014262395Sbapt	/* We are at the end of a macro */
2015262395Sbapt	/* Skip ';' and space characters and return to previous state */
2016262395Sbapt	while (p < chunk->end) {
2017262395Sbapt		if (!ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE) && *p != ';') {
2018262395Sbapt			break;
2019262395Sbapt		}
2020262395Sbapt		ucl_chunk_skipc (chunk, p);
2021262395Sbapt	}
2022262395Sbapt	return true;
2023262395Sbapt}
2024262395Sbapt
2025262395Sbapt/**
2026275223Sbapt * Parse macro arguments as UCL object
2027275223Sbapt * @param parser parser structure
2028275223Sbapt * @param chunk the current data chunk
2029275223Sbapt * @return
2030275223Sbapt */
2031275223Sbaptstatic ucl_object_t *
2032275223Sbaptucl_parse_macro_arguments (struct ucl_parser *parser,
2033275223Sbapt		struct ucl_chunk *chunk)
2034275223Sbapt{
2035275223Sbapt	ucl_object_t *res = NULL;
2036275223Sbapt	struct ucl_parser *params_parser;
2037275223Sbapt	int obraces = 1, ebraces = 0, state = 0;
2038275223Sbapt	const unsigned char *p, *c;
2039275223Sbapt	size_t args_len = 0;
2040275223Sbapt	struct ucl_parser_saved_state saved;
2041275223Sbapt
2042275223Sbapt	saved.column = chunk->column;
2043275223Sbapt	saved.line = chunk->line;
2044275223Sbapt	saved.pos = chunk->pos;
2045275223Sbapt	saved.remain = chunk->remain;
2046275223Sbapt	p = chunk->pos;
2047275223Sbapt
2048275223Sbapt	if (*p != '(' || chunk->remain < 2) {
2049275223Sbapt		return NULL;
2050275223Sbapt	}
2051275223Sbapt
2052275223Sbapt	/* Set begin and start */
2053275223Sbapt	ucl_chunk_skipc (chunk, p);
2054275223Sbapt	c = p;
2055275223Sbapt
2056275223Sbapt	while ((p) < (chunk)->end) {
2057275223Sbapt		switch (state) {
2058275223Sbapt		case 0:
2059275223Sbapt			/* Parse symbols and check for '(', ')' and '"' */
2060275223Sbapt			if (*p == '(') {
2061275223Sbapt				obraces ++;
2062275223Sbapt			}
2063275223Sbapt			else if (*p == ')') {
2064275223Sbapt				ebraces ++;
2065275223Sbapt			}
2066275223Sbapt			else if (*p == '"') {
2067275223Sbapt				state = 1;
2068275223Sbapt			}
2069275223Sbapt			/* Check pairing */
2070275223Sbapt			if (obraces == ebraces) {
2071275223Sbapt				state = 99;
2072275223Sbapt			}
2073275223Sbapt			else {
2074275223Sbapt				args_len ++;
2075275223Sbapt			}
2076275223Sbapt			/* Check overflow */
2077275223Sbapt			if (chunk->remain == 0) {
2078275223Sbapt				goto restore_chunk;
2079275223Sbapt			}
2080275223Sbapt			ucl_chunk_skipc (chunk, p);
2081275223Sbapt			break;
2082275223Sbapt		case 1:
2083275223Sbapt			/* We have quote character, so skip all but quotes */
2084275223Sbapt			if (*p == '"' && *(p - 1) != '\\') {
2085275223Sbapt				state = 0;
2086275223Sbapt			}
2087275223Sbapt			if (chunk->remain == 0) {
2088275223Sbapt				goto restore_chunk;
2089275223Sbapt			}
2090290071Sbapt			args_len ++;
2091275223Sbapt			ucl_chunk_skipc (chunk, p);
2092275223Sbapt			break;
2093275223Sbapt		case 99:
2094275223Sbapt			/*
2095275223Sbapt			 * We have read the full body of arguments, so we need to parse and set
2096275223Sbapt			 * object from that
2097275223Sbapt			 */
2098275223Sbapt			params_parser = ucl_parser_new (parser->flags);
2099275223Sbapt			if (!ucl_parser_add_chunk (params_parser, c, args_len)) {
2100275223Sbapt				ucl_set_err (parser, UCL_ESYNTAX, "macro arguments parsing error",
2101275223Sbapt						&parser->err);
2102275223Sbapt			}
2103275223Sbapt			else {
2104275223Sbapt				res = ucl_parser_get_object (params_parser);
2105275223Sbapt			}
2106275223Sbapt			ucl_parser_free (params_parser);
2107275223Sbapt
2108275223Sbapt			return res;
2109275223Sbapt
2110275223Sbapt			break;
2111275223Sbapt		}
2112275223Sbapt	}
2113275223Sbapt
2114275223Sbapt	return res;
2115275223Sbapt
2116275223Sbaptrestore_chunk:
2117275223Sbapt	chunk->column = saved.column;
2118275223Sbapt	chunk->line = saved.line;
2119275223Sbapt	chunk->pos = saved.pos;
2120275223Sbapt	chunk->remain = saved.remain;
2121275223Sbapt
2122275223Sbapt	return NULL;
2123275223Sbapt}
2124275223Sbapt
2125275223Sbapt#define SKIP_SPACES_COMMENTS(parser, chunk, p) do {								\
2126275223Sbapt	while ((p) < (chunk)->end) {												\
2127275223Sbapt		if (!ucl_test_character (*(p), UCL_CHARACTER_WHITESPACE_UNSAFE)) {		\
2128275223Sbapt			if ((chunk)->remain >= 2 && ucl_lex_is_comment ((p)[0], (p)[1])) {	\
2129275223Sbapt				if (!ucl_skip_comments (parser)) {								\
2130275223Sbapt					return false;												\
2131275223Sbapt				}																\
2132275223Sbapt				p = (chunk)->pos;												\
2133275223Sbapt			}																	\
2134275223Sbapt			break;																\
2135275223Sbapt		}																		\
2136275223Sbapt		ucl_chunk_skipc (chunk, p);												\
2137275223Sbapt	}																			\
2138275223Sbapt} while(0)
2139275223Sbapt
2140275223Sbapt/**
2141262395Sbapt * Handle the main states of rcl parser
2142262395Sbapt * @param parser parser structure
2143262395Sbapt * @return true if chunk has been parsed and false in case of error
2144262395Sbapt */
2145262395Sbaptstatic bool
2146262395Sbaptucl_state_machine (struct ucl_parser *parser)
2147262395Sbapt{
2148275223Sbapt	ucl_object_t *obj, *macro_args;
2149262395Sbapt	struct ucl_chunk *chunk = parser->chunks;
2150262395Sbapt	const unsigned char *p, *c = NULL, *macro_start = NULL;
2151262395Sbapt	unsigned char *macro_escaped;
2152262395Sbapt	size_t macro_len = 0;
2153262395Sbapt	struct ucl_macro *macro = NULL;
2154275223Sbapt	bool next_key = false, end_of_object = false, ret;
2155262395Sbapt
2156262395Sbapt	if (parser->top_obj == NULL) {
2157262395Sbapt		parser->state = UCL_STATE_INIT;
2158262395Sbapt	}
2159262395Sbapt
2160262395Sbapt	p = chunk->pos;
2161262395Sbapt	while (chunk->pos < chunk->end) {
2162262395Sbapt		switch (parser->state) {
2163262395Sbapt		case UCL_STATE_INIT:
2164262395Sbapt			/*
2165262395Sbapt			 * At the init state we can either go to the parse array or object
2166262395Sbapt			 * if we got [ or { correspondingly or can just treat new data as
2167262395Sbapt			 * a key of newly created object
2168262395Sbapt			 */
2169262395Sbapt			if (!ucl_skip_comments (parser)) {
2170262395Sbapt				parser->prev_state = parser->state;
2171262395Sbapt				parser->state = UCL_STATE_ERROR;
2172262395Sbapt				return false;
2173262395Sbapt			}
2174262395Sbapt			else {
2175268876Sbapt				/* Skip any spaces */
2176268876Sbapt				while (p < chunk->end && ucl_test_character (*p,
2177268876Sbapt						UCL_CHARACTER_WHITESPACE_UNSAFE)) {
2178268876Sbapt					ucl_chunk_skipc (chunk, p);
2179268876Sbapt				}
2180290071Sbapt
2181262395Sbapt				p = chunk->pos;
2182290071Sbapt
2183262395Sbapt				if (*p == '[') {
2184262395Sbapt					parser->state = UCL_STATE_VALUE;
2185262395Sbapt					ucl_chunk_skipc (chunk, p);
2186262395Sbapt				}
2187262395Sbapt				else {
2188262395Sbapt					parser->state = UCL_STATE_KEY;
2189262395Sbapt					if (*p == '{') {
2190262395Sbapt						ucl_chunk_skipc (chunk, p);
2191262395Sbapt					}
2192262395Sbapt				}
2193290071Sbapt
2194290071Sbapt				if (parser->top_obj == NULL) {
2195290071Sbapt					if (parser->state == UCL_STATE_VALUE) {
2196290071Sbapt						obj = ucl_parser_add_container (NULL, parser, true, 0);
2197290071Sbapt					}
2198290071Sbapt					else {
2199290071Sbapt						obj = ucl_parser_add_container (NULL, parser, false, 0);
2200290071Sbapt					}
2201290071Sbapt
2202290071Sbapt					if (obj == NULL) {
2203290071Sbapt						return false;
2204290071Sbapt					}
2205290071Sbapt
2206290071Sbapt					parser->top_obj = obj;
2207290071Sbapt					parser->cur_obj = obj;
2208290071Sbapt				}
2209290071Sbapt
2210262395Sbapt			}
2211262395Sbapt			break;
2212262395Sbapt		case UCL_STATE_KEY:
2213262395Sbapt			/* Skip any spaces */
2214262395Sbapt			while (p < chunk->end && ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE)) {
2215262395Sbapt				ucl_chunk_skipc (chunk, p);
2216262395Sbapt			}
2217298166Sbapt			if (p == chunk->end || *p == '}') {
2218262395Sbapt				/* We have the end of an object */
2219262395Sbapt				parser->state = UCL_STATE_AFTER_VALUE;
2220262395Sbapt				continue;
2221262395Sbapt			}
2222262395Sbapt			if (parser->stack == NULL) {
2223262395Sbapt				/* No objects are on stack, but we want to parse a key */
2224275223Sbapt				ucl_set_err (parser, UCL_ESYNTAX, "top object is finished but the parser "
2225262395Sbapt						"expects a key", &parser->err);
2226262395Sbapt				parser->prev_state = parser->state;
2227262395Sbapt				parser->state = UCL_STATE_ERROR;
2228262395Sbapt				return false;
2229262395Sbapt			}
2230262395Sbapt			if (!ucl_parse_key (parser, chunk, &next_key, &end_of_object)) {
2231262395Sbapt				parser->prev_state = parser->state;
2232262395Sbapt				parser->state = UCL_STATE_ERROR;
2233262395Sbapt				return false;
2234262395Sbapt			}
2235262395Sbapt			if (end_of_object) {
2236262395Sbapt				p = chunk->pos;
2237262395Sbapt				parser->state = UCL_STATE_AFTER_VALUE;
2238262395Sbapt				continue;
2239262395Sbapt			}
2240262395Sbapt			else if (parser->state != UCL_STATE_MACRO_NAME) {
2241262395Sbapt				if (next_key && parser->stack->obj->type == UCL_OBJECT) {
2242262395Sbapt					/* Parse more keys and nest objects accordingly */
2243290071Sbapt					obj = ucl_parser_add_container (parser->cur_obj, parser, false,
2244263648Sbapt							parser->stack->level + 1);
2245263648Sbapt					if (obj == NULL) {
2246263648Sbapt						return false;
2247263648Sbapt					}
2248262395Sbapt				}
2249262395Sbapt				else {
2250262395Sbapt					parser->state = UCL_STATE_VALUE;
2251262395Sbapt				}
2252262395Sbapt			}
2253262395Sbapt			else {
2254262395Sbapt				c = chunk->pos;
2255262395Sbapt			}
2256262395Sbapt			p = chunk->pos;
2257262395Sbapt			break;
2258262395Sbapt		case UCL_STATE_VALUE:
2259262395Sbapt			/* We need to check what we do have */
2260298166Sbapt			if (!parser->cur_obj || !ucl_parse_value (parser, chunk)) {
2261262395Sbapt				parser->prev_state = parser->state;
2262262395Sbapt				parser->state = UCL_STATE_ERROR;
2263262395Sbapt				return false;
2264262395Sbapt			}
2265262395Sbapt			/* State is set in ucl_parse_value call */
2266262395Sbapt			p = chunk->pos;
2267262395Sbapt			break;
2268262395Sbapt		case UCL_STATE_AFTER_VALUE:
2269262395Sbapt			if (!ucl_parse_after_value (parser, chunk)) {
2270262395Sbapt				parser->prev_state = parser->state;
2271262395Sbapt				parser->state = UCL_STATE_ERROR;
2272262395Sbapt				return false;
2273262395Sbapt			}
2274290071Sbapt
2275262395Sbapt			if (parser->stack != NULL) {
2276262395Sbapt				if (parser->stack->obj->type == UCL_OBJECT) {
2277262395Sbapt					parser->state = UCL_STATE_KEY;
2278262395Sbapt				}
2279262395Sbapt				else {
2280262395Sbapt					/* Array */
2281262395Sbapt					parser->state = UCL_STATE_VALUE;
2282262395Sbapt				}
2283262395Sbapt			}
2284262395Sbapt			else {
2285262395Sbapt				/* Skip everything at the end */
2286262395Sbapt				return true;
2287262395Sbapt			}
2288298166Sbapt
2289262395Sbapt			p = chunk->pos;
2290262395Sbapt			break;
2291262395Sbapt		case UCL_STATE_MACRO_NAME:
2292298166Sbapt			if (parser->flags & UCL_PARSER_DISABLE_MACRO) {
2293298166Sbapt				if (!ucl_skip_macro_as_comment (parser, chunk)) {
2294298166Sbapt					/* We have invalid macro */
2295298166Sbapt					ucl_create_err (&parser->err,
2296298166Sbapt							"error on line %d at column %d: invalid macro",
2297298166Sbapt							chunk->line,
2298298166Sbapt							chunk->column);
2299298166Sbapt					parser->state = UCL_STATE_ERROR;
2300298166Sbapt					return false;
2301298166Sbapt				}
2302298166Sbapt				else {
2303298166Sbapt					p = chunk->pos;
2304298166Sbapt					parser->state = parser->prev_state;
2305298166Sbapt				}
2306262395Sbapt			}
2307290071Sbapt			else {
2308298166Sbapt				if (!ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE) &&
2309298166Sbapt						*p != '(') {
2310298166Sbapt					ucl_chunk_skipc (chunk, p);
2311298166Sbapt				}
2312298166Sbapt				else {
2313298166Sbapt					if (c != NULL && p - c > 0) {
2314298166Sbapt						/* We got macro name */
2315298166Sbapt						macro_len = (size_t) (p - c);
2316298166Sbapt						HASH_FIND (hh, parser->macroes, c, macro_len, macro);
2317298166Sbapt						if (macro == NULL) {
2318298166Sbapt							ucl_create_err (&parser->err,
2319298166Sbapt									"error on line %d at column %d: "
2320298166Sbapt									"unknown macro: '%.*s', character: '%c'",
2321298166Sbapt									chunk->line,
2322298166Sbapt									chunk->column,
2323298166Sbapt									(int) (p - c),
2324298166Sbapt									c,
2325298166Sbapt									*chunk->pos);
2326298166Sbapt							parser->state = UCL_STATE_ERROR;
2327298166Sbapt							return false;
2328298166Sbapt						}
2329298166Sbapt						/* Now we need to skip all spaces */
2330298166Sbapt						SKIP_SPACES_COMMENTS(parser, chunk, p);
2331298166Sbapt						parser->state = UCL_STATE_MACRO;
2332298166Sbapt					}
2333298166Sbapt					else {
2334298166Sbapt						/* We have invalid macro name */
2335290071Sbapt						ucl_create_err (&parser->err,
2336298166Sbapt								"error on line %d at column %d: invalid macro name",
2337290071Sbapt								chunk->line,
2338298166Sbapt								chunk->column);
2339290071Sbapt						parser->state = UCL_STATE_ERROR;
2340290071Sbapt						return false;
2341290071Sbapt					}
2342290071Sbapt				}
2343262395Sbapt			}
2344262395Sbapt			break;
2345262395Sbapt		case UCL_STATE_MACRO:
2346275223Sbapt			if (*chunk->pos == '(') {
2347275223Sbapt				macro_args = ucl_parse_macro_arguments (parser, chunk);
2348275223Sbapt				p = chunk->pos;
2349275223Sbapt				if (macro_args) {
2350275223Sbapt					SKIP_SPACES_COMMENTS(parser, chunk, p);
2351275223Sbapt				}
2352275223Sbapt			}
2353275223Sbapt			else {
2354275223Sbapt				macro_args = NULL;
2355275223Sbapt			}
2356262395Sbapt			if (!ucl_parse_macro_value (parser, chunk, macro,
2357262395Sbapt					&macro_start, &macro_len)) {
2358262395Sbapt				parser->prev_state = parser->state;
2359262395Sbapt				parser->state = UCL_STATE_ERROR;
2360262395Sbapt				return false;
2361262395Sbapt			}
2362275223Sbapt			macro_len = ucl_expand_variable (parser, &macro_escaped,
2363275223Sbapt					macro_start, macro_len);
2364262395Sbapt			parser->state = parser->prev_state;
2365298166Sbapt
2366298166Sbapt			if (macro_escaped == NULL && macro != NULL) {
2367290071Sbapt				if (macro->is_context) {
2368290071Sbapt					ret = macro->h.context_handler (macro_start, macro_len,
2369290071Sbapt							macro_args,
2370290071Sbapt							parser->top_obj,
2371290071Sbapt							macro->ud);
2372290071Sbapt				}
2373290071Sbapt				else {
2374290071Sbapt					ret = macro->h.handler (macro_start, macro_len, macro_args,
2375290071Sbapt							macro->ud);
2376290071Sbapt				}
2377262395Sbapt			}
2378298166Sbapt			else if (macro != NULL) {
2379290071Sbapt				if (macro->is_context) {
2380290071Sbapt					ret = macro->h.context_handler (macro_escaped, macro_len,
2381290071Sbapt							macro_args,
2382290071Sbapt							parser->top_obj,
2383290071Sbapt							macro->ud);
2384290071Sbapt				}
2385290071Sbapt				else {
2386290071Sbapt					ret = macro->h.handler (macro_escaped, macro_len, macro_args,
2387275223Sbapt						macro->ud);
2388290071Sbapt				}
2389290071Sbapt
2390262395Sbapt				UCL_FREE (macro_len + 1, macro_escaped);
2391262395Sbapt			}
2392298166Sbapt			else {
2393298166Sbapt				ret = false;
2394298166Sbapt				ucl_set_err (parser, UCL_EINTERNAL,
2395298166Sbapt						"internal error: parser has macro undefined", &parser->err);
2396298166Sbapt			}
2397290071Sbapt
2398290071Sbapt			/*
2399290071Sbapt			 * Chunk can be modified within macro handler
2400290071Sbapt			 */
2401290071Sbapt			chunk = parser->chunks;
2402262395Sbapt			p = chunk->pos;
2403298166Sbapt
2404275223Sbapt			if (macro_args) {
2405275223Sbapt				ucl_object_unref (macro_args);
2406275223Sbapt			}
2407298166Sbapt
2408275223Sbapt			if (!ret) {
2409275223Sbapt				return false;
2410275223Sbapt			}
2411262395Sbapt			break;
2412262395Sbapt		default:
2413275223Sbapt			ucl_set_err (parser, UCL_EINTERNAL,
2414275223Sbapt					"internal error: parser is in an unknown state", &parser->err);
2415262395Sbapt			parser->state = UCL_STATE_ERROR;
2416262395Sbapt			return false;
2417262395Sbapt		}
2418262395Sbapt	}
2419262395Sbapt
2420298166Sbapt	if (parser->last_comment) {
2421298166Sbapt		if (parser->cur_obj) {
2422298166Sbapt			ucl_attach_comment (parser, parser->cur_obj, true);
2423298166Sbapt		}
2424298166Sbapt		else if (parser->stack && parser->stack->obj) {
2425298166Sbapt			ucl_attach_comment (parser, parser->stack->obj, true);
2426298166Sbapt		}
2427298166Sbapt		else if (parser->top_obj) {
2428298166Sbapt			ucl_attach_comment (parser, parser->top_obj, true);
2429298166Sbapt		}
2430298166Sbapt		else {
2431298166Sbapt			ucl_object_unref (parser->last_comment);
2432298166Sbapt		}
2433298166Sbapt	}
2434298166Sbapt
2435262395Sbapt	return true;
2436262395Sbapt}
2437262395Sbapt
2438262395Sbaptstruct ucl_parser*
2439262395Sbaptucl_parser_new (int flags)
2440262395Sbapt{
2441298166Sbapt	struct ucl_parser *parser;
2442262395Sbapt
2443298166Sbapt	parser = UCL_ALLOC (sizeof (struct ucl_parser));
2444298166Sbapt	if (parser == NULL) {
2445263648Sbapt		return NULL;
2446263648Sbapt	}
2447290071Sbapt
2448298166Sbapt	memset (parser, 0, sizeof (struct ucl_parser));
2449262395Sbapt
2450298166Sbapt	ucl_parser_register_macro (parser, "include", ucl_include_handler, parser);
2451298166Sbapt	ucl_parser_register_macro (parser, "try_include", ucl_try_include_handler, parser);
2452298166Sbapt	ucl_parser_register_macro (parser, "includes", ucl_includes_handler, parser);
2453298166Sbapt	ucl_parser_register_macro (parser, "priority", ucl_priority_handler, parser);
2454298166Sbapt	ucl_parser_register_macro (parser, "load", ucl_load_handler, parser);
2455298166Sbapt	ucl_parser_register_context_macro (parser, "inherit", ucl_inherit_handler, parser);
2456262395Sbapt
2457298166Sbapt	parser->flags = flags;
2458298166Sbapt	parser->includepaths = NULL;
2459262395Sbapt
2460298166Sbapt	if (flags & UCL_PARSER_SAVE_COMMENTS) {
2461298166Sbapt		parser->comments = ucl_object_typed_new (UCL_OBJECT);
2462298166Sbapt	}
2463298166Sbapt
2464262395Sbapt	/* Initial assumption about filevars */
2465298166Sbapt	ucl_parser_set_filevars (parser, NULL, false);
2466262395Sbapt
2467298166Sbapt	return parser;
2468262395Sbapt}
2469262395Sbapt
2470290071Sbaptbool
2471290071Sbaptucl_parser_set_default_priority (struct ucl_parser *parser, unsigned prio)
2472290071Sbapt{
2473290071Sbapt	if (parser == NULL) {
2474290071Sbapt		return false;
2475290071Sbapt	}
2476262395Sbapt
2477290071Sbapt	parser->default_priority = prio;
2478290071Sbapt
2479290071Sbapt	return true;
2480290071Sbapt}
2481290071Sbapt
2482262395Sbaptvoid
2483262395Sbaptucl_parser_register_macro (struct ucl_parser *parser, const char *macro,
2484262395Sbapt		ucl_macro_handler handler, void* ud)
2485262395Sbapt{
2486262395Sbapt	struct ucl_macro *new;
2487262395Sbapt
2488263648Sbapt	if (macro == NULL || handler == NULL) {
2489263648Sbapt		return;
2490263648Sbapt	}
2491290071Sbapt
2492262395Sbapt	new = UCL_ALLOC (sizeof (struct ucl_macro));
2493263648Sbapt	if (new == NULL) {
2494263648Sbapt		return;
2495263648Sbapt	}
2496290071Sbapt
2497262395Sbapt	memset (new, 0, sizeof (struct ucl_macro));
2498290071Sbapt	new->h.handler = handler;
2499262395Sbapt	new->name = strdup (macro);
2500262395Sbapt	new->ud = ud;
2501262395Sbapt	HASH_ADD_KEYPTR (hh, parser->macroes, new->name, strlen (new->name), new);
2502262395Sbapt}
2503262395Sbapt
2504262395Sbaptvoid
2505290071Sbaptucl_parser_register_context_macro (struct ucl_parser *parser, const char *macro,
2506290071Sbapt		ucl_context_macro_handler handler, void* ud)
2507290071Sbapt{
2508290071Sbapt	struct ucl_macro *new;
2509290071Sbapt
2510290071Sbapt	if (macro == NULL || handler == NULL) {
2511290071Sbapt		return;
2512290071Sbapt	}
2513290071Sbapt
2514290071Sbapt	new = UCL_ALLOC (sizeof (struct ucl_macro));
2515290071Sbapt	if (new == NULL) {
2516290071Sbapt		return;
2517290071Sbapt	}
2518290071Sbapt
2519290071Sbapt	memset (new, 0, sizeof (struct ucl_macro));
2520290071Sbapt	new->h.context_handler = handler;
2521290071Sbapt	new->name = strdup (macro);
2522290071Sbapt	new->ud = ud;
2523290071Sbapt	new->is_context = true;
2524290071Sbapt	HASH_ADD_KEYPTR (hh, parser->macroes, new->name, strlen (new->name), new);
2525290071Sbapt}
2526290071Sbapt
2527290071Sbaptvoid
2528262395Sbaptucl_parser_register_variable (struct ucl_parser *parser, const char *var,
2529262395Sbapt		const char *value)
2530262395Sbapt{
2531262395Sbapt	struct ucl_variable *new = NULL, *cur;
2532262395Sbapt
2533262395Sbapt	if (var == NULL) {
2534262395Sbapt		return;
2535262395Sbapt	}
2536262395Sbapt
2537262395Sbapt	/* Find whether a variable already exists */
2538262395Sbapt	LL_FOREACH (parser->variables, cur) {
2539262395Sbapt		if (strcmp (cur->var, var) == 0) {
2540262395Sbapt			new = cur;
2541262395Sbapt			break;
2542262395Sbapt		}
2543262395Sbapt	}
2544262395Sbapt
2545262395Sbapt	if (value == NULL) {
2546262395Sbapt
2547262395Sbapt		if (new != NULL) {
2548262395Sbapt			/* Remove variable */
2549275223Sbapt			DL_DELETE (parser->variables, new);
2550262395Sbapt			free (new->var);
2551262395Sbapt			free (new->value);
2552262395Sbapt			UCL_FREE (sizeof (struct ucl_variable), new);
2553262395Sbapt		}
2554262395Sbapt		else {
2555262395Sbapt			/* Do nothing */
2556262395Sbapt			return;
2557262395Sbapt		}
2558262395Sbapt	}
2559262395Sbapt	else {
2560262395Sbapt		if (new == NULL) {
2561262395Sbapt			new = UCL_ALLOC (sizeof (struct ucl_variable));
2562263648Sbapt			if (new == NULL) {
2563263648Sbapt				return;
2564263648Sbapt			}
2565262395Sbapt			memset (new, 0, sizeof (struct ucl_variable));
2566262395Sbapt			new->var = strdup (var);
2567262395Sbapt			new->var_len = strlen (var);
2568262395Sbapt			new->value = strdup (value);
2569262395Sbapt			new->value_len = strlen (value);
2570262395Sbapt
2571275223Sbapt			DL_APPEND (parser->variables, new);
2572262395Sbapt		}
2573262395Sbapt		else {
2574262395Sbapt			free (new->value);
2575262395Sbapt			new->value = strdup (value);
2576262395Sbapt			new->value_len = strlen (value);
2577262395Sbapt		}
2578262395Sbapt	}
2579262395Sbapt}
2580262395Sbapt
2581266636Sbaptvoid
2582266636Sbaptucl_parser_set_variables_handler (struct ucl_parser *parser,
2583266636Sbapt		ucl_variable_handler handler, void *ud)
2584266636Sbapt{
2585266636Sbapt	parser->var_handler = handler;
2586266636Sbapt	parser->var_data = ud;
2587266636Sbapt}
2588266636Sbapt
2589262395Sbaptbool
2590290071Sbaptucl_parser_add_chunk_full (struct ucl_parser *parser, const unsigned char *data,
2591290071Sbapt		size_t len, unsigned priority, enum ucl_duplicate_strategy strat,
2592290071Sbapt		enum ucl_parse_type parse_type)
2593262395Sbapt{
2594262395Sbapt	struct ucl_chunk *chunk;
2595262395Sbapt
2596290071Sbapt	if (parser == NULL) {
2597290071Sbapt		return false;
2598290071Sbapt	}
2599290071Sbapt
2600301339Sbapt	if (data == NULL && len != 0) {
2601263648Sbapt		ucl_create_err (&parser->err, "invalid chunk added");
2602263648Sbapt		return false;
2603263648Sbapt	}
2604298166Sbapt
2605262395Sbapt	if (parser->state != UCL_STATE_ERROR) {
2606262395Sbapt		chunk = UCL_ALLOC (sizeof (struct ucl_chunk));
2607263648Sbapt		if (chunk == NULL) {
2608263648Sbapt			ucl_create_err (&parser->err, "cannot allocate chunk structure");
2609263648Sbapt			return false;
2610263648Sbapt		}
2611301339Sbapt
2612262395Sbapt		chunk->begin = data;
2613262395Sbapt		chunk->remain = len;
2614262395Sbapt		chunk->pos = chunk->begin;
2615262395Sbapt		chunk->end = chunk->begin + len;
2616262395Sbapt		chunk->line = 1;
2617262395Sbapt		chunk->column = 0;
2618275223Sbapt		chunk->priority = priority;
2619290071Sbapt		chunk->strategy = strat;
2620290071Sbapt		chunk->parse_type = parse_type;
2621262395Sbapt		LL_PREPEND (parser->chunks, chunk);
2622262395Sbapt		parser->recursion ++;
2623290071Sbapt
2624262395Sbapt		if (parser->recursion > UCL_MAX_RECURSION) {
2625262395Sbapt			ucl_create_err (&parser->err, "maximum include nesting limit is reached: %d",
2626262395Sbapt					parser->recursion);
2627262395Sbapt			return false;
2628262395Sbapt		}
2629290071Sbapt
2630301339Sbapt		if (len > 0) {
2631301339Sbapt			/* Need to parse something */
2632301339Sbapt			switch (parse_type) {
2633301339Sbapt			default:
2634301339Sbapt			case UCL_PARSE_UCL:
2635301339Sbapt				return ucl_state_machine (parser);
2636301339Sbapt			case UCL_PARSE_MSGPACK:
2637301339Sbapt				return ucl_parse_msgpack (parser);
2638301339Sbapt			}
2639290071Sbapt		}
2640301339Sbapt		else {
2641301339Sbapt			/* Just add empty chunk and go forward */
2642301339Sbapt			if (parser->top_obj == NULL) {
2643301339Sbapt				/*
2644301339Sbapt				 * In case of empty object, create one to indicate that we've
2645301339Sbapt				 * read something
2646301339Sbapt				 */
2647301339Sbapt				parser->top_obj = ucl_object_new_full (UCL_OBJECT, priority);
2648301339Sbapt			}
2649301339Sbapt
2650301339Sbapt			return true;
2651301339Sbapt		}
2652262395Sbapt	}
2653262395Sbapt
2654262395Sbapt	ucl_create_err (&parser->err, "a parser is in an invalid state");
2655262395Sbapt
2656262395Sbapt	return false;
2657262395Sbapt}
2658263648Sbapt
2659263648Sbaptbool
2660290071Sbaptucl_parser_add_chunk_priority (struct ucl_parser *parser,
2661290071Sbapt		const unsigned char *data, size_t len, unsigned priority)
2662290071Sbapt{
2663290071Sbapt	/* We dereference parser, so this check is essential */
2664290071Sbapt	if (parser == NULL) {
2665290071Sbapt		return false;
2666290071Sbapt	}
2667290071Sbapt
2668290071Sbapt	return ucl_parser_add_chunk_full (parser, data, len,
2669290071Sbapt				priority, UCL_DUPLICATE_APPEND, UCL_PARSE_UCL);
2670290071Sbapt}
2671290071Sbapt
2672290071Sbaptbool
2673275223Sbaptucl_parser_add_chunk (struct ucl_parser *parser, const unsigned char *data,
2674275223Sbapt		size_t len)
2675275223Sbapt{
2676290071Sbapt	if (parser == NULL) {
2677290071Sbapt		return false;
2678290071Sbapt	}
2679290071Sbapt
2680290071Sbapt	return ucl_parser_add_chunk_full (parser, data, len,
2681290071Sbapt			parser->default_priority, UCL_DUPLICATE_APPEND, UCL_PARSE_UCL);
2682275223Sbapt}
2683275223Sbapt
2684275223Sbaptbool
2685290071Sbaptucl_parser_add_string_priority (struct ucl_parser *parser, const char *data,
2686290071Sbapt		size_t len, unsigned priority)
2687263648Sbapt{
2688263648Sbapt	if (data == NULL) {
2689263648Sbapt		ucl_create_err (&parser->err, "invalid string added");
2690263648Sbapt		return false;
2691263648Sbapt	}
2692263648Sbapt	if (len == 0) {
2693263648Sbapt		len = strlen (data);
2694263648Sbapt	}
2695263648Sbapt
2696290071Sbapt	return ucl_parser_add_chunk_priority (parser,
2697290071Sbapt			(const unsigned char *)data, len, priority);
2698263648Sbapt}
2699290071Sbapt
2700290071Sbaptbool
2701290071Sbaptucl_parser_add_string (struct ucl_parser *parser, const char *data,
2702290071Sbapt		size_t len)
2703290071Sbapt{
2704290071Sbapt	if (parser == NULL) {
2705290071Sbapt		return false;
2706290071Sbapt	}
2707290071Sbapt
2708290071Sbapt	return ucl_parser_add_string_priority (parser,
2709290071Sbapt			(const unsigned char *)data, len, parser->default_priority);
2710290071Sbapt}
2711290071Sbapt
2712290071Sbaptbool
2713290071Sbaptucl_set_include_path (struct ucl_parser *parser, ucl_object_t *paths)
2714290071Sbapt{
2715290071Sbapt	if (parser == NULL || paths == NULL) {
2716290071Sbapt		return false;
2717290071Sbapt	}
2718290071Sbapt
2719290071Sbapt	if (parser->includepaths == NULL) {
2720290071Sbapt		parser->includepaths = ucl_object_copy (paths);
2721290071Sbapt	}
2722290071Sbapt	else {
2723290071Sbapt		ucl_object_unref (parser->includepaths);
2724290071Sbapt		parser->includepaths = ucl_object_copy (paths);
2725290071Sbapt	}
2726290071Sbapt
2727290071Sbapt	if (parser->includepaths == NULL) {
2728290071Sbapt		return false;
2729290071Sbapt	}
2730290071Sbapt
2731290071Sbapt	return true;
2732290071Sbapt}
2733