ucl_parser.c revision 290071
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
92262395Sbapt/**
93262395Sbapt * Skip all comments from the current pos resolving nested and multiline comments
94262395Sbapt * @param parser
95262395Sbapt * @return
96262395Sbapt */
97262395Sbaptstatic bool
98262395Sbaptucl_skip_comments (struct ucl_parser *parser)
99262395Sbapt{
100262395Sbapt	struct ucl_chunk *chunk = parser->chunks;
101262395Sbapt	const unsigned char *p;
102262395Sbapt	int comments_nested = 0;
103275223Sbapt	bool quoted = false;
104262395Sbapt
105262395Sbapt	p = chunk->pos;
106262395Sbapt
107262395Sbaptstart:
108275223Sbapt	if (chunk->remain > 0 && *p == '#') {
109262395Sbapt		if (parser->state != UCL_STATE_SCOMMENT &&
110262395Sbapt				parser->state != UCL_STATE_MCOMMENT) {
111262395Sbapt			while (p < chunk->end) {
112262395Sbapt				if (*p == '\n') {
113262395Sbapt					ucl_chunk_skipc (chunk, p);
114262395Sbapt					goto start;
115262395Sbapt				}
116262395Sbapt				ucl_chunk_skipc (chunk, p);
117262395Sbapt			}
118262395Sbapt		}
119262395Sbapt	}
120275223Sbapt	else if (chunk->remain >= 2 && *p == '/') {
121262395Sbapt		if (p[1] == '*') {
122262395Sbapt			ucl_chunk_skipc (chunk, p);
123262395Sbapt			comments_nested ++;
124262395Sbapt			ucl_chunk_skipc (chunk, p);
125262395Sbapt
126262395Sbapt			while (p < chunk->end) {
127275223Sbapt				if (*p == '"' && *(p - 1) != '\\') {
128275223Sbapt					quoted = !quoted;
129275223Sbapt				}
130275223Sbapt
131275223Sbapt				if (!quoted) {
132275223Sbapt					if (*p == '*') {
133275223Sbapt						ucl_chunk_skipc (chunk, p);
134275223Sbapt						if (*p == '/') {
135275223Sbapt							comments_nested --;
136275223Sbapt							if (comments_nested == 0) {
137275223Sbapt								ucl_chunk_skipc (chunk, p);
138275223Sbapt								goto start;
139275223Sbapt							}
140262395Sbapt						}
141275223Sbapt						ucl_chunk_skipc (chunk, p);
142262395Sbapt					}
143275223Sbapt					else if (p[0] == '/' && chunk->remain >= 2 && p[1] == '*') {
144275223Sbapt						comments_nested ++;
145275223Sbapt						ucl_chunk_skipc (chunk, p);
146275223Sbapt						ucl_chunk_skipc (chunk, p);
147275223Sbapt						continue;
148275223Sbapt					}
149262395Sbapt				}
150262395Sbapt				ucl_chunk_skipc (chunk, p);
151262395Sbapt			}
152262395Sbapt			if (comments_nested != 0) {
153275223Sbapt				ucl_set_err (parser, UCL_ENESTED,
154275223Sbapt						"unfinished multiline comment", &parser->err);
155262395Sbapt				return false;
156262395Sbapt			}
157262395Sbapt		}
158262395Sbapt	}
159262395Sbapt
160262395Sbapt	return true;
161262395Sbapt}
162262395Sbapt
163262395Sbapt/**
164262395Sbapt * Return multiplier for a character
165262395Sbapt * @param c multiplier character
166262395Sbapt * @param is_bytes if true use 1024 multiplier
167262395Sbapt * @return multiplier
168262395Sbapt */
169262395Sbaptstatic inline unsigned long
170262395Sbaptucl_lex_num_multiplier (const unsigned char c, bool is_bytes) {
171262395Sbapt	const struct {
172262395Sbapt		char c;
173262395Sbapt		long mult_normal;
174262395Sbapt		long mult_bytes;
175262395Sbapt	} multipliers[] = {
176262395Sbapt			{'m', 1000 * 1000, 1024 * 1024},
177262395Sbapt			{'k', 1000, 1024},
178262395Sbapt			{'g', 1000 * 1000 * 1000, 1024 * 1024 * 1024}
179262395Sbapt	};
180262395Sbapt	int i;
181262395Sbapt
182262395Sbapt	for (i = 0; i < 3; i ++) {
183262395Sbapt		if (tolower (c) == multipliers[i].c) {
184262395Sbapt			if (is_bytes) {
185262395Sbapt				return multipliers[i].mult_bytes;
186262395Sbapt			}
187262395Sbapt			return multipliers[i].mult_normal;
188262395Sbapt		}
189262395Sbapt	}
190262395Sbapt
191262395Sbapt	return 1;
192262395Sbapt}
193262395Sbapt
194262395Sbapt
195262395Sbapt/**
196262395Sbapt * Return multiplier for time scaling
197262395Sbapt * @param c
198262395Sbapt * @return
199262395Sbapt */
200262395Sbaptstatic inline double
201262395Sbaptucl_lex_time_multiplier (const unsigned char c) {
202262395Sbapt	const struct {
203262395Sbapt		char c;
204262395Sbapt		double mult;
205262395Sbapt	} multipliers[] = {
206262395Sbapt			{'m', 60},
207262395Sbapt			{'h', 60 * 60},
208262395Sbapt			{'d', 60 * 60 * 24},
209262395Sbapt			{'w', 60 * 60 * 24 * 7},
210262395Sbapt			{'y', 60 * 60 * 24 * 7 * 365}
211262395Sbapt	};
212262395Sbapt	int i;
213262395Sbapt
214262395Sbapt	for (i = 0; i < 5; i ++) {
215262395Sbapt		if (tolower (c) == multipliers[i].c) {
216262395Sbapt			return multipliers[i].mult;
217262395Sbapt		}
218262395Sbapt	}
219262395Sbapt
220262395Sbapt	return 1;
221262395Sbapt}
222262395Sbapt
223262395Sbapt/**
224262395Sbapt * Return true if a character is a end of an atom
225262395Sbapt * @param c
226262395Sbapt * @return
227262395Sbapt */
228262395Sbaptstatic inline bool
229262395Sbaptucl_lex_is_atom_end (const unsigned char c)
230262395Sbapt{
231262395Sbapt	return ucl_test_character (c, UCL_CHARACTER_VALUE_END);
232262395Sbapt}
233262395Sbapt
234262395Sbaptstatic inline bool
235262395Sbaptucl_lex_is_comment (const unsigned char c1, const unsigned char c2)
236262395Sbapt{
237262395Sbapt	if (c1 == '/') {
238262395Sbapt		if (c2 == '*') {
239262395Sbapt			return true;
240262395Sbapt		}
241262395Sbapt	}
242262395Sbapt	else if (c1 == '#') {
243262395Sbapt		return true;
244262395Sbapt	}
245262395Sbapt	return false;
246262395Sbapt}
247262395Sbapt
248262395Sbapt/**
249262395Sbapt * Check variable found
250262395Sbapt * @param parser
251262395Sbapt * @param ptr
252262395Sbapt * @param remain
253262395Sbapt * @param out_len
254262395Sbapt * @param strict
255262395Sbapt * @param found
256262395Sbapt * @return
257262395Sbapt */
258262395Sbaptstatic inline const char *
259262395Sbaptucl_check_variable_safe (struct ucl_parser *parser, const char *ptr, size_t remain,
260262395Sbapt		size_t *out_len, bool strict, bool *found)
261262395Sbapt{
262262395Sbapt	struct ucl_variable *var;
263266636Sbapt	unsigned char *dst;
264266636Sbapt	size_t dstlen;
265266636Sbapt	bool need_free = false;
266262395Sbapt
267262395Sbapt	LL_FOREACH (parser->variables, var) {
268262395Sbapt		if (strict) {
269262395Sbapt			if (remain == var->var_len) {
270262395Sbapt				if (memcmp (ptr, var->var, var->var_len) == 0) {
271262395Sbapt					*out_len += var->value_len;
272262395Sbapt					*found = true;
273262395Sbapt					return (ptr + var->var_len);
274262395Sbapt				}
275262395Sbapt			}
276262395Sbapt		}
277262395Sbapt		else {
278262395Sbapt			if (remain >= var->var_len) {
279262395Sbapt				if (memcmp (ptr, var->var, var->var_len) == 0) {
280262395Sbapt					*out_len += var->value_len;
281262395Sbapt					*found = true;
282262395Sbapt					return (ptr + var->var_len);
283262395Sbapt				}
284262395Sbapt			}
285262395Sbapt		}
286262395Sbapt	}
287262395Sbapt
288266636Sbapt	/* XXX: can only handle ${VAR} */
289266636Sbapt	if (!(*found) && parser->var_handler != NULL && strict) {
290266636Sbapt		/* Call generic handler */
291266636Sbapt		if (parser->var_handler (ptr, remain, &dst, &dstlen, &need_free,
292266636Sbapt				parser->var_data)) {
293266636Sbapt			*found = true;
294266636Sbapt			if (need_free) {
295266636Sbapt				free (dst);
296266636Sbapt			}
297266636Sbapt			return (ptr + remain);
298266636Sbapt		}
299266636Sbapt	}
300266636Sbapt
301262395Sbapt	return ptr;
302262395Sbapt}
303262395Sbapt
304262395Sbapt/**
305262395Sbapt * Check for a variable in a given string
306262395Sbapt * @param parser
307262395Sbapt * @param ptr
308262395Sbapt * @param remain
309262395Sbapt * @param out_len
310262395Sbapt * @param vars_found
311262395Sbapt * @return
312262395Sbapt */
313262395Sbaptstatic const char *
314266636Sbaptucl_check_variable (struct ucl_parser *parser, const char *ptr,
315266636Sbapt		size_t remain, size_t *out_len, bool *vars_found)
316262395Sbapt{
317262395Sbapt	const char *p, *end, *ret = ptr;
318262395Sbapt	bool found = false;
319262395Sbapt
320262395Sbapt	if (*ptr == '{') {
321262395Sbapt		/* We need to match the variable enclosed in braces */
322262395Sbapt		p = ptr + 1;
323262395Sbapt		end = ptr + remain;
324262395Sbapt		while (p < end) {
325262395Sbapt			if (*p == '}') {
326266636Sbapt				ret = ucl_check_variable_safe (parser, ptr + 1, p - ptr - 1,
327266636Sbapt						out_len, true, &found);
328262395Sbapt				if (found) {
329262395Sbapt					/* {} must be excluded actually */
330262395Sbapt					ret ++;
331262395Sbapt					if (!*vars_found) {
332262395Sbapt						*vars_found = true;
333262395Sbapt					}
334262395Sbapt				}
335262395Sbapt				else {
336262395Sbapt					*out_len += 2;
337262395Sbapt				}
338262395Sbapt				break;
339262395Sbapt			}
340262395Sbapt			p ++;
341262395Sbapt		}
342262395Sbapt	}
343262395Sbapt	else if (*ptr != '$') {
344262395Sbapt		/* Not count escaped dollar sign */
345262395Sbapt		ret = ucl_check_variable_safe (parser, ptr, remain, out_len, false, &found);
346262395Sbapt		if (found && !*vars_found) {
347262395Sbapt			*vars_found = true;
348262395Sbapt		}
349262395Sbapt		if (!found) {
350262395Sbapt			(*out_len) ++;
351262395Sbapt		}
352262395Sbapt	}
353262395Sbapt	else {
354262395Sbapt		ret ++;
355262395Sbapt		(*out_len) ++;
356262395Sbapt	}
357262395Sbapt
358262395Sbapt	return ret;
359262395Sbapt}
360262395Sbapt
361262395Sbapt/**
362262395Sbapt * Expand a single variable
363262395Sbapt * @param parser
364262395Sbapt * @param ptr
365262395Sbapt * @param remain
366262395Sbapt * @param dest
367262395Sbapt * @return
368262395Sbapt */
369262395Sbaptstatic const char *
370262395Sbaptucl_expand_single_variable (struct ucl_parser *parser, const char *ptr,
371262395Sbapt		size_t remain, unsigned char **dest)
372262395Sbapt{
373266636Sbapt	unsigned char *d = *dest, *dst;
374262395Sbapt	const char *p = ptr + 1, *ret;
375262395Sbapt	struct ucl_variable *var;
376266636Sbapt	size_t dstlen;
377266636Sbapt	bool need_free = false;
378262395Sbapt	bool found = false;
379266636Sbapt	bool strict = false;
380262395Sbapt
381262395Sbapt	ret = ptr + 1;
382262395Sbapt	remain --;
383262395Sbapt
384262395Sbapt	if (*p == '$') {
385262395Sbapt		*d++ = *p++;
386262395Sbapt		*dest = d;
387262395Sbapt		return p;
388262395Sbapt	}
389262395Sbapt	else if (*p == '{') {
390262395Sbapt		p ++;
391266636Sbapt		strict = true;
392262395Sbapt		ret += 2;
393262395Sbapt		remain -= 2;
394262395Sbapt	}
395262395Sbapt
396262395Sbapt	LL_FOREACH (parser->variables, var) {
397262395Sbapt		if (remain >= var->var_len) {
398262395Sbapt			if (memcmp (p, var->var, var->var_len) == 0) {
399262395Sbapt				memcpy (d, var->value, var->value_len);
400262395Sbapt				ret += var->var_len;
401262395Sbapt				d += var->value_len;
402262395Sbapt				found = true;
403262395Sbapt				break;
404262395Sbapt			}
405262395Sbapt		}
406262395Sbapt	}
407262395Sbapt	if (!found) {
408266636Sbapt		if (strict && parser->var_handler != NULL) {
409266636Sbapt			if (parser->var_handler (ptr, remain, &dst, &dstlen, &need_free,
410266636Sbapt							parser->var_data)) {
411266636Sbapt				memcpy (d, dst, dstlen);
412266636Sbapt				ret += dstlen;
413266636Sbapt				d += remain;
414266636Sbapt				found = true;
415266636Sbapt			}
416266636Sbapt		}
417266636Sbapt
418266636Sbapt		/* Leave variable as is */
419266636Sbapt		if (!found) {
420268831Sbapt			if (strict) {
421268831Sbapt				/* Copy '${' */
422268831Sbapt				memcpy (d, ptr, 2);
423268831Sbapt				d += 2;
424268831Sbapt				ret --;
425268831Sbapt			}
426268831Sbapt			else {
427268831Sbapt				memcpy (d, ptr, 1);
428268831Sbapt				d ++;
429268831Sbapt			}
430266636Sbapt		}
431262395Sbapt	}
432262395Sbapt
433262395Sbapt	*dest = d;
434262395Sbapt	return ret;
435262395Sbapt}
436262395Sbapt
437262395Sbapt/**
438262395Sbapt * Expand variables in string
439262395Sbapt * @param parser
440262395Sbapt * @param dst
441262395Sbapt * @param src
442262395Sbapt * @param in_len
443262395Sbapt * @return
444262395Sbapt */
445262395Sbaptstatic ssize_t
446262395Sbaptucl_expand_variable (struct ucl_parser *parser, unsigned char **dst,
447262395Sbapt		const char *src, size_t in_len)
448262395Sbapt{
449262395Sbapt	const char *p, *end = src + in_len;
450262395Sbapt	unsigned char *d;
451262395Sbapt	size_t out_len = 0;
452262395Sbapt	bool vars_found = false;
453262395Sbapt
454262395Sbapt	p = src;
455262395Sbapt	while (p != end) {
456262395Sbapt		if (*p == '$') {
457262395Sbapt			p = ucl_check_variable (parser, p + 1, end - p - 1, &out_len, &vars_found);
458262395Sbapt		}
459262395Sbapt		else {
460262395Sbapt			p ++;
461262395Sbapt			out_len ++;
462262395Sbapt		}
463262395Sbapt	}
464262395Sbapt
465262395Sbapt	if (!vars_found) {
466262395Sbapt		/* Trivial case */
467262395Sbapt		*dst = NULL;
468262395Sbapt		return in_len;
469262395Sbapt	}
470262395Sbapt
471262395Sbapt	*dst = UCL_ALLOC (out_len + 1);
472262395Sbapt	if (*dst == NULL) {
473262395Sbapt		return in_len;
474262395Sbapt	}
475262395Sbapt
476262395Sbapt	d = *dst;
477262395Sbapt	p = src;
478262395Sbapt	while (p != end) {
479262395Sbapt		if (*p == '$') {
480262395Sbapt			p = ucl_expand_single_variable (parser, p, end - p, &d);
481262395Sbapt		}
482262395Sbapt		else {
483262395Sbapt			*d++ = *p++;
484262395Sbapt		}
485262395Sbapt	}
486262395Sbapt
487262395Sbapt	*d = '\0';
488262395Sbapt
489262395Sbapt	return out_len;
490262395Sbapt}
491262395Sbapt
492262395Sbapt/**
493262395Sbapt * Store or copy pointer to the trash stack
494262395Sbapt * @param parser parser object
495262395Sbapt * @param src src string
496262395Sbapt * @param dst destination buffer (trash stack pointer)
497262395Sbapt * @param dst_const const destination pointer (e.g. value of object)
498262395Sbapt * @param in_len input length
499262395Sbapt * @param need_unescape need to unescape source (and copy it)
500262395Sbapt * @param need_lowercase need to lowercase value (and copy)
501262395Sbapt * @param need_expand need to expand variables (and copy as well)
502262395Sbapt * @return output length (excluding \0 symbol)
503262395Sbapt */
504262395Sbaptstatic inline ssize_t
505262395Sbaptucl_copy_or_store_ptr (struct ucl_parser *parser,
506262395Sbapt		const unsigned char *src, unsigned char **dst,
507262395Sbapt		const char **dst_const, size_t in_len,
508262395Sbapt		bool need_unescape, bool need_lowercase, bool need_expand)
509262395Sbapt{
510262395Sbapt	ssize_t ret = -1, tret;
511262395Sbapt	unsigned char *tmp;
512262395Sbapt
513262395Sbapt	if (need_unescape || need_lowercase ||
514262395Sbapt			(need_expand && parser->variables != NULL) ||
515262395Sbapt			!(parser->flags & UCL_PARSER_ZEROCOPY)) {
516262395Sbapt		/* Copy string */
517262395Sbapt		*dst = UCL_ALLOC (in_len + 1);
518262395Sbapt		if (*dst == NULL) {
519290071Sbapt			ucl_set_err (parser, UCL_EINTERNAL, "cannot allocate memory for a string",
520275223Sbapt					&parser->err);
521262395Sbapt			return false;
522262395Sbapt		}
523262395Sbapt		if (need_lowercase) {
524262395Sbapt			ret = ucl_strlcpy_tolower (*dst, src, in_len + 1);
525262395Sbapt		}
526262395Sbapt		else {
527262395Sbapt			ret = ucl_strlcpy_unsafe (*dst, src, in_len + 1);
528262395Sbapt		}
529262395Sbapt
530262395Sbapt		if (need_unescape) {
531262395Sbapt			ret = ucl_unescape_json_string (*dst, ret);
532262395Sbapt		}
533262395Sbapt		if (need_expand) {
534262395Sbapt			tmp = *dst;
535262395Sbapt			tret = ret;
536262395Sbapt			ret = ucl_expand_variable (parser, dst, tmp, ret);
537262395Sbapt			if (*dst == NULL) {
538262395Sbapt				/* Nothing to expand */
539262395Sbapt				*dst = tmp;
540262395Sbapt				ret = tret;
541262395Sbapt			}
542275223Sbapt			else {
543275223Sbapt				/* Free unexpanded value */
544275223Sbapt				UCL_FREE (in_len + 1, tmp);
545275223Sbapt			}
546262395Sbapt		}
547262395Sbapt		*dst_const = *dst;
548262395Sbapt	}
549262395Sbapt	else {
550262395Sbapt		*dst_const = src;
551262395Sbapt		ret = in_len;
552262395Sbapt	}
553262395Sbapt
554262395Sbapt	return ret;
555262395Sbapt}
556262395Sbapt
557262395Sbapt/**
558262395Sbapt * Create and append an object at the specified level
559262395Sbapt * @param parser
560262395Sbapt * @param is_array
561262395Sbapt * @param level
562262395Sbapt * @return
563262395Sbapt */
564262395Sbaptstatic inline ucl_object_t *
565290071Sbaptucl_parser_add_container (ucl_object_t *obj, struct ucl_parser *parser,
566290071Sbapt		bool is_array, int level)
567262395Sbapt{
568262395Sbapt	struct ucl_stack *st;
569262395Sbapt
570262395Sbapt	if (!is_array) {
571262395Sbapt		if (obj == NULL) {
572275223Sbapt			obj = ucl_object_new_full (UCL_OBJECT, parser->chunks->priority);
573262395Sbapt		}
574262395Sbapt		else {
575262395Sbapt			obj->type = UCL_OBJECT;
576262395Sbapt		}
577290071Sbapt		if (obj->value.ov == NULL) {
578290071Sbapt			obj->value.ov = ucl_hash_create (parser->flags & UCL_PARSER_KEY_LOWERCASE);
579290071Sbapt		}
580262395Sbapt		parser->state = UCL_STATE_KEY;
581262395Sbapt	}
582262395Sbapt	else {
583262395Sbapt		if (obj == NULL) {
584275223Sbapt			obj = ucl_object_new_full (UCL_ARRAY, parser->chunks->priority);
585262395Sbapt		}
586262395Sbapt		else {
587262395Sbapt			obj->type = UCL_ARRAY;
588262395Sbapt		}
589262395Sbapt		parser->state = UCL_STATE_VALUE;
590262395Sbapt	}
591262395Sbapt
592262395Sbapt	st = UCL_ALLOC (sizeof (struct ucl_stack));
593263648Sbapt	if (st == NULL) {
594290071Sbapt		ucl_set_err (parser, UCL_EINTERNAL, "cannot allocate memory for an object",
595275223Sbapt				&parser->err);
596275223Sbapt		ucl_object_unref (obj);
597263648Sbapt		return NULL;
598263648Sbapt	}
599262395Sbapt	st->obj = obj;
600262395Sbapt	st->level = level;
601262395Sbapt	LL_PREPEND (parser->stack, st);
602262395Sbapt	parser->cur_obj = obj;
603262395Sbapt
604262395Sbapt	return obj;
605262395Sbapt}
606262395Sbapt
607262395Sbaptint
608262395Sbaptucl_maybe_parse_number (ucl_object_t *obj,
609263648Sbapt		const char *start, const char *end, const char **pos,
610263648Sbapt		bool allow_double, bool number_bytes, bool allow_time)
611262395Sbapt{
612262395Sbapt	const char *p = start, *c = start;
613262395Sbapt	char *endptr;
614262395Sbapt	bool got_dot = false, got_exp = false, need_double = false,
615263648Sbapt			is_time = false, valid_start = false, is_hex = false,
616262395Sbapt			is_neg = false;
617262395Sbapt	double dv = 0;
618262395Sbapt	int64_t lv = 0;
619262395Sbapt
620262395Sbapt	if (*p == '-') {
621262395Sbapt		is_neg = true;
622262395Sbapt		c ++;
623262395Sbapt		p ++;
624262395Sbapt	}
625262395Sbapt	while (p < end) {
626262395Sbapt		if (is_hex && isxdigit (*p)) {
627262395Sbapt			p ++;
628262395Sbapt		}
629262395Sbapt		else if (isdigit (*p)) {
630262395Sbapt			valid_start = true;
631262395Sbapt			p ++;
632262395Sbapt		}
633262395Sbapt		else if (!is_hex && (*p == 'x' || *p == 'X')) {
634262395Sbapt			is_hex = true;
635262395Sbapt			allow_double = false;
636262395Sbapt			c = p + 1;
637262395Sbapt		}
638262395Sbapt		else if (allow_double) {
639262395Sbapt			if (p == c) {
640262395Sbapt				/* Empty digits sequence, not a number */
641262395Sbapt				*pos = start;
642262395Sbapt				return EINVAL;
643262395Sbapt			}
644262395Sbapt			else if (*p == '.') {
645262395Sbapt				if (got_dot) {
646262395Sbapt					/* Double dots, not a number */
647262395Sbapt					*pos = start;
648262395Sbapt					return EINVAL;
649262395Sbapt				}
650262395Sbapt				else {
651262395Sbapt					got_dot = true;
652262395Sbapt					need_double = true;
653262395Sbapt					p ++;
654262395Sbapt				}
655262395Sbapt			}
656262395Sbapt			else if (*p == 'e' || *p == 'E') {
657262395Sbapt				if (got_exp) {
658262395Sbapt					/* Double exp, not a number */
659262395Sbapt					*pos = start;
660262395Sbapt					return EINVAL;
661262395Sbapt				}
662262395Sbapt				else {
663262395Sbapt					got_exp = true;
664262395Sbapt					need_double = true;
665262395Sbapt					p ++;
666262395Sbapt					if (p >= end) {
667262395Sbapt						*pos = start;
668262395Sbapt						return EINVAL;
669262395Sbapt					}
670262395Sbapt					if (!isdigit (*p) && *p != '+' && *p != '-') {
671262395Sbapt						/* Wrong exponent sign */
672262395Sbapt						*pos = start;
673262395Sbapt						return EINVAL;
674262395Sbapt					}
675262395Sbapt					else {
676262395Sbapt						p ++;
677262395Sbapt					}
678262395Sbapt				}
679262395Sbapt			}
680262395Sbapt			else {
681262395Sbapt				/* Got the end of the number, need to check */
682262395Sbapt				break;
683262395Sbapt			}
684262395Sbapt		}
685262395Sbapt		else {
686262395Sbapt			break;
687262395Sbapt		}
688262395Sbapt	}
689262395Sbapt
690262395Sbapt	if (!valid_start) {
691262395Sbapt		*pos = start;
692262395Sbapt		return EINVAL;
693262395Sbapt	}
694262395Sbapt
695262395Sbapt	errno = 0;
696262395Sbapt	if (need_double) {
697262395Sbapt		dv = strtod (c, &endptr);
698262395Sbapt	}
699262395Sbapt	else {
700262395Sbapt		if (is_hex) {
701262395Sbapt			lv = strtoimax (c, &endptr, 16);
702262395Sbapt		}
703262395Sbapt		else {
704262395Sbapt			lv = strtoimax (c, &endptr, 10);
705262395Sbapt		}
706262395Sbapt	}
707262395Sbapt	if (errno == ERANGE) {
708262395Sbapt		*pos = start;
709262395Sbapt		return ERANGE;
710262395Sbapt	}
711262395Sbapt
712262395Sbapt	/* Now check endptr */
713275223Sbapt	if (endptr == NULL || ucl_lex_is_atom_end (*endptr) || *endptr == '\0') {
714262395Sbapt		p = endptr;
715262395Sbapt		goto set_obj;
716262395Sbapt	}
717262395Sbapt
718262395Sbapt	if (endptr < end && endptr != start) {
719262395Sbapt		p = endptr;
720262395Sbapt		switch (*p) {
721262395Sbapt		case 'm':
722262395Sbapt		case 'M':
723262395Sbapt		case 'g':
724262395Sbapt		case 'G':
725262395Sbapt		case 'k':
726262395Sbapt		case 'K':
727262395Sbapt			if (end - p >= 2) {
728262395Sbapt				if (p[1] == 's' || p[1] == 'S') {
729262395Sbapt					/* Milliseconds */
730262395Sbapt					if (!need_double) {
731262395Sbapt						need_double = true;
732262395Sbapt						dv = lv;
733262395Sbapt					}
734263648Sbapt					is_time = true;
735262395Sbapt					if (p[0] == 'm' || p[0] == 'M') {
736262395Sbapt						dv /= 1000.;
737262395Sbapt					}
738262395Sbapt					else {
739262395Sbapt						dv *= ucl_lex_num_multiplier (*p, false);
740262395Sbapt					}
741262395Sbapt					p += 2;
742262395Sbapt					goto set_obj;
743262395Sbapt				}
744262395Sbapt				else if (number_bytes || (p[1] == 'b' || p[1] == 'B')) {
745262395Sbapt					/* Bytes */
746262395Sbapt					if (need_double) {
747262395Sbapt						need_double = false;
748262395Sbapt						lv = dv;
749262395Sbapt					}
750262395Sbapt					lv *= ucl_lex_num_multiplier (*p, true);
751262395Sbapt					p += 2;
752262395Sbapt					goto set_obj;
753262395Sbapt				}
754262395Sbapt				else if (ucl_lex_is_atom_end (p[1])) {
755262395Sbapt					if (need_double) {
756262395Sbapt						dv *= ucl_lex_num_multiplier (*p, false);
757262395Sbapt					}
758262395Sbapt					else {
759262395Sbapt						lv *= ucl_lex_num_multiplier (*p, number_bytes);
760262395Sbapt					}
761262395Sbapt					p ++;
762262395Sbapt					goto set_obj;
763262395Sbapt				}
764263648Sbapt				else if (allow_time && end - p >= 3) {
765262395Sbapt					if (tolower (p[0]) == 'm' &&
766262395Sbapt							tolower (p[1]) == 'i' &&
767262395Sbapt							tolower (p[2]) == 'n') {
768262395Sbapt						/* Minutes */
769262395Sbapt						if (!need_double) {
770262395Sbapt							need_double = true;
771262395Sbapt							dv = lv;
772262395Sbapt						}
773263648Sbapt						is_time = true;
774262395Sbapt						dv *= 60.;
775262395Sbapt						p += 3;
776262395Sbapt						goto set_obj;
777262395Sbapt					}
778262395Sbapt				}
779262395Sbapt			}
780262395Sbapt			else {
781262395Sbapt				if (need_double) {
782262395Sbapt					dv *= ucl_lex_num_multiplier (*p, false);
783262395Sbapt				}
784262395Sbapt				else {
785262395Sbapt					lv *= ucl_lex_num_multiplier (*p, number_bytes);
786262395Sbapt				}
787262395Sbapt				p ++;
788262395Sbapt				goto set_obj;
789262395Sbapt			}
790262395Sbapt			break;
791262395Sbapt		case 'S':
792262395Sbapt		case 's':
793263648Sbapt			if (allow_time &&
794263648Sbapt					(p == end - 1 || ucl_lex_is_atom_end (p[1]))) {
795262395Sbapt				if (!need_double) {
796262395Sbapt					need_double = true;
797262395Sbapt					dv = lv;
798262395Sbapt				}
799262395Sbapt				p ++;
800263648Sbapt				is_time = true;
801262395Sbapt				goto set_obj;
802262395Sbapt			}
803262395Sbapt			break;
804262395Sbapt		case 'h':
805262395Sbapt		case 'H':
806262395Sbapt		case 'd':
807262395Sbapt		case 'D':
808262395Sbapt		case 'w':
809262395Sbapt		case 'W':
810262395Sbapt		case 'Y':
811262395Sbapt		case 'y':
812263648Sbapt			if (allow_time &&
813263648Sbapt					(p == end - 1 || ucl_lex_is_atom_end (p[1]))) {
814262395Sbapt				if (!need_double) {
815262395Sbapt					need_double = true;
816262395Sbapt					dv = lv;
817262395Sbapt				}
818263648Sbapt				is_time = true;
819262395Sbapt				dv *= ucl_lex_time_multiplier (*p);
820262395Sbapt				p ++;
821262395Sbapt				goto set_obj;
822262395Sbapt			}
823262395Sbapt			break;
824275223Sbapt		case '\t':
825275223Sbapt		case ' ':
826275223Sbapt			while (p < end && ucl_test_character(*p, UCL_CHARACTER_WHITESPACE)) {
827275223Sbapt				p++;
828275223Sbapt			}
829275223Sbapt			if (ucl_lex_is_atom_end(*p))
830275223Sbapt				goto set_obj;
831275223Sbapt			break;
832262395Sbapt		}
833262395Sbapt	}
834275223Sbapt	else if (endptr == end) {
835275223Sbapt		/* Just a number at the end of chunk */
836275223Sbapt		p = endptr;
837275223Sbapt		goto set_obj;
838275223Sbapt	}
839262395Sbapt
840262395Sbapt	*pos = c;
841262395Sbapt	return EINVAL;
842262395Sbapt
843290071Sbaptset_obj:
844290071Sbapt	if (obj != NULL) {
845290071Sbapt		if (allow_double && (need_double || is_time)) {
846290071Sbapt			if (!is_time) {
847290071Sbapt				obj->type = UCL_FLOAT;
848290071Sbapt			}
849290071Sbapt			else {
850290071Sbapt				obj->type = UCL_TIME;
851290071Sbapt			}
852290071Sbapt			obj->value.dv = is_neg ? (-dv) : dv;
853262395Sbapt		}
854262395Sbapt		else {
855290071Sbapt			obj->type = UCL_INT;
856290071Sbapt			obj->value.iv = is_neg ? (-lv) : lv;
857262395Sbapt		}
858262395Sbapt	}
859262395Sbapt	*pos = p;
860262395Sbapt	return 0;
861262395Sbapt}
862262395Sbapt
863262395Sbapt/**
864262395Sbapt * Parse possible number
865262395Sbapt * @param parser
866262395Sbapt * @param chunk
867290071Sbapt * @param obj
868262395Sbapt * @return true if a number has been parsed
869262395Sbapt */
870262395Sbaptstatic bool
871262395Sbaptucl_lex_number (struct ucl_parser *parser,
872262395Sbapt		struct ucl_chunk *chunk, ucl_object_t *obj)
873262395Sbapt{
874262395Sbapt	const unsigned char *pos;
875262395Sbapt	int ret;
876262395Sbapt
877263648Sbapt	ret = ucl_maybe_parse_number (obj, chunk->pos, chunk->end, (const char **)&pos,
878263648Sbapt			true, false, ((parser->flags & UCL_PARSER_NO_TIME) == 0));
879262395Sbapt
880262395Sbapt	if (ret == 0) {
881262395Sbapt		chunk->remain -= pos - chunk->pos;
882262395Sbapt		chunk->column += pos - chunk->pos;
883262395Sbapt		chunk->pos = pos;
884262395Sbapt		return true;
885262395Sbapt	}
886262395Sbapt	else if (ret == ERANGE) {
887290071Sbapt		ucl_set_err (parser, UCL_ESYNTAX, "numeric value out of range",
888290071Sbapt				&parser->err);
889262395Sbapt	}
890262395Sbapt
891262395Sbapt	return false;
892262395Sbapt}
893262395Sbapt
894262395Sbapt/**
895262395Sbapt * Parse quoted string with possible escapes
896262395Sbapt * @param parser
897262395Sbapt * @param chunk
898290071Sbapt * @param need_unescape
899290071Sbapt * @param ucl_escape
900290071Sbapt * @param var_expand
901262395Sbapt * @return true if a string has been parsed
902262395Sbapt */
903262395Sbaptstatic bool
904262395Sbaptucl_lex_json_string (struct ucl_parser *parser,
905262395Sbapt		struct ucl_chunk *chunk, bool *need_unescape, bool *ucl_escape, bool *var_expand)
906262395Sbapt{
907262395Sbapt	const unsigned char *p = chunk->pos;
908262395Sbapt	unsigned char c;
909262395Sbapt	int i;
910262395Sbapt
911262395Sbapt	while (p < chunk->end) {
912262395Sbapt		c = *p;
913262395Sbapt		if (c < 0x1F) {
914262395Sbapt			/* Unmasked control character */
915262395Sbapt			if (c == '\n') {
916275223Sbapt				ucl_set_err (parser, UCL_ESYNTAX, "unexpected newline",
917275223Sbapt						&parser->err);
918262395Sbapt			}
919262395Sbapt			else {
920275223Sbapt				ucl_set_err (parser, UCL_ESYNTAX, "unexpected control character",
921275223Sbapt						&parser->err);
922262395Sbapt			}
923262395Sbapt			return false;
924262395Sbapt		}
925262395Sbapt		else if (c == '\\') {
926262395Sbapt			ucl_chunk_skipc (chunk, p);
927262395Sbapt			c = *p;
928262395Sbapt			if (p >= chunk->end) {
929275223Sbapt				ucl_set_err (parser, UCL_ESYNTAX, "unfinished escape character",
930275223Sbapt						&parser->err);
931262395Sbapt				return false;
932262395Sbapt			}
933262395Sbapt			else if (ucl_test_character (c, UCL_CHARACTER_ESCAPE)) {
934262395Sbapt				if (c == 'u') {
935262395Sbapt					ucl_chunk_skipc (chunk, p);
936262395Sbapt					for (i = 0; i < 4 && p < chunk->end; i ++) {
937262395Sbapt						if (!isxdigit (*p)) {
938275223Sbapt							ucl_set_err (parser, UCL_ESYNTAX, "invalid utf escape",
939275223Sbapt									&parser->err);
940262395Sbapt							return false;
941262395Sbapt						}
942262395Sbapt						ucl_chunk_skipc (chunk, p);
943262395Sbapt					}
944262395Sbapt					if (p >= chunk->end) {
945275223Sbapt						ucl_set_err (parser, UCL_ESYNTAX, "unfinished escape character",
946275223Sbapt								&parser->err);
947262395Sbapt						return false;
948262395Sbapt					}
949262395Sbapt				}
950262395Sbapt				else {
951262395Sbapt					ucl_chunk_skipc (chunk, p);
952262395Sbapt				}
953262395Sbapt			}
954262395Sbapt			*need_unescape = true;
955262395Sbapt			*ucl_escape = true;
956262395Sbapt			continue;
957262395Sbapt		}
958262395Sbapt		else if (c == '"') {
959262395Sbapt			ucl_chunk_skipc (chunk, p);
960262395Sbapt			return true;
961262395Sbapt		}
962262395Sbapt		else if (ucl_test_character (c, UCL_CHARACTER_UCL_UNSAFE)) {
963262395Sbapt			*ucl_escape = true;
964262395Sbapt		}
965262395Sbapt		else if (c == '$') {
966262395Sbapt			*var_expand = true;
967262395Sbapt		}
968262395Sbapt		ucl_chunk_skipc (chunk, p);
969262395Sbapt	}
970262395Sbapt
971275223Sbapt	ucl_set_err (parser, UCL_ESYNTAX, "no quote at the end of json string",
972275223Sbapt			&parser->err);
973262395Sbapt	return false;
974262395Sbapt}
975262395Sbapt
976275223Sbaptstatic void
977275223Sbaptucl_parser_append_elt (struct ucl_parser *parser, ucl_hash_t *cont,
978275223Sbapt		ucl_object_t *top,
979275223Sbapt		ucl_object_t *elt)
980275223Sbapt{
981275223Sbapt	ucl_object_t *nobj;
982275223Sbapt
983275223Sbapt	if ((parser->flags & UCL_PARSER_NO_IMPLICIT_ARRAYS) == 0) {
984275223Sbapt		/* Implicit array */
985275223Sbapt		top->flags |= UCL_OBJECT_MULTIVALUE;
986275223Sbapt		DL_APPEND (top, elt);
987290071Sbapt		parser->stack->obj->len ++;
988275223Sbapt	}
989275223Sbapt	else {
990275223Sbapt		if ((top->flags & UCL_OBJECT_MULTIVALUE) != 0) {
991275223Sbapt			/* Just add to the explicit array */
992279549Sbapt			ucl_array_append (top, elt);
993275223Sbapt		}
994275223Sbapt		else {
995275223Sbapt			/* Convert to an array */
996275223Sbapt			nobj = ucl_object_typed_new (UCL_ARRAY);
997275223Sbapt			nobj->key = top->key;
998275223Sbapt			nobj->keylen = top->keylen;
999275223Sbapt			nobj->flags |= UCL_OBJECT_MULTIVALUE;
1000279549Sbapt			ucl_array_append (nobj, top);
1001279549Sbapt			ucl_array_append (nobj, elt);
1002290071Sbapt			ucl_hash_replace (cont, top, nobj);
1003275223Sbapt		}
1004275223Sbapt	}
1005275223Sbapt}
1006275223Sbapt
1007290071Sbaptbool
1008290071Sbaptucl_parser_process_object_element (struct ucl_parser *parser, ucl_object_t *nobj)
1009290071Sbapt{
1010290071Sbapt	ucl_hash_t *container;
1011290071Sbapt	ucl_object_t *tobj;
1012290071Sbapt
1013290071Sbapt	container = parser->stack->obj->value.ov;
1014290071Sbapt
1015290071Sbapt	tobj = __DECONST (ucl_object_t *, ucl_hash_search_obj (container, nobj));
1016290071Sbapt	if (tobj == NULL) {
1017290071Sbapt		container = ucl_hash_insert_object (container, nobj,
1018290071Sbapt				parser->flags & UCL_PARSER_KEY_LOWERCASE);
1019290071Sbapt		nobj->prev = nobj;
1020290071Sbapt		nobj->next = NULL;
1021290071Sbapt		parser->stack->obj->len ++;
1022290071Sbapt	}
1023290071Sbapt	else {
1024290071Sbapt		unsigned priold = ucl_object_get_priority (tobj),
1025290071Sbapt				prinew = ucl_object_get_priority (nobj);
1026290071Sbapt		switch (parser->chunks->strategy) {
1027290071Sbapt
1028290071Sbapt		case UCL_DUPLICATE_APPEND:
1029290071Sbapt			/*
1030290071Sbapt			 * The logic here is the following:
1031290071Sbapt			 *
1032290071Sbapt			 * - if we have two objects with the same priority, then we form an
1033290071Sbapt			 * implicit or explicit array
1034290071Sbapt			 * - if a new object has bigger priority, then we overwrite an old one
1035290071Sbapt			 * - if a new object has lower priority, then we ignore it
1036290071Sbapt			 */
1037290071Sbapt
1038290071Sbapt
1039290071Sbapt			/* Special case for inherited objects */
1040290071Sbapt			if (tobj->flags & UCL_OBJECT_INHERITED) {
1041290071Sbapt				prinew = priold + 1;
1042290071Sbapt			}
1043290071Sbapt
1044290071Sbapt			if (priold == prinew) {
1045290071Sbapt				ucl_parser_append_elt (parser, container, tobj, nobj);
1046290071Sbapt			}
1047290071Sbapt			else if (priold > prinew) {
1048290071Sbapt				/*
1049290071Sbapt				 * We add this new object to a list of trash objects just to ensure
1050290071Sbapt				 * that it won't come to any real object
1051290071Sbapt				 * XXX: rather inefficient approach
1052290071Sbapt				 */
1053290071Sbapt				DL_APPEND (parser->trash_objs, nobj);
1054290071Sbapt			}
1055290071Sbapt			else {
1056290071Sbapt				ucl_hash_replace (container, tobj, nobj);
1057290071Sbapt				ucl_object_unref (tobj);
1058290071Sbapt			}
1059290071Sbapt
1060290071Sbapt			break;
1061290071Sbapt
1062290071Sbapt		case UCL_DUPLICATE_REWRITE:
1063290071Sbapt			/* We just rewrite old values regardless of priority */
1064290071Sbapt			ucl_hash_replace (container, tobj, nobj);
1065290071Sbapt			ucl_object_unref (tobj);
1066290071Sbapt
1067290071Sbapt			break;
1068290071Sbapt
1069290071Sbapt		case UCL_DUPLICATE_ERROR:
1070290071Sbapt			ucl_create_err (&parser->err, "error while parsing %s: "
1071290071Sbapt					"line: %d, column: %d: duplicate element for key '%s' "
1072290071Sbapt					"has been found",
1073290071Sbapt					parser->cur_file ? parser->cur_file : "<unknown>",
1074290071Sbapt					parser->chunks->line, parser->chunks->column, nobj->key);
1075290071Sbapt			return false;
1076290071Sbapt
1077290071Sbapt		case UCL_DUPLICATE_MERGE:
1078290071Sbapt			/*
1079290071Sbapt			 * Here we do have some old object so we just push it on top of objects stack
1080290071Sbapt			 */
1081290071Sbapt			if (tobj->type == UCL_OBJECT || tobj->type == UCL_ARRAY) {
1082290071Sbapt				ucl_object_unref (nobj);
1083290071Sbapt				nobj = tobj;
1084290071Sbapt			}
1085290071Sbapt			else {
1086290071Sbapt				/* For other types we create implicit array as usual */
1087290071Sbapt				ucl_parser_append_elt (parser, container, tobj, nobj);
1088290071Sbapt			}
1089290071Sbapt			break;
1090290071Sbapt		}
1091290071Sbapt	}
1092290071Sbapt
1093290071Sbapt	parser->stack->obj->value.ov = container;
1094290071Sbapt	parser->cur_obj = nobj;
1095290071Sbapt
1096290071Sbapt	return true;
1097290071Sbapt}
1098290071Sbapt
1099262395Sbapt/**
1100262395Sbapt * Parse a key in an object
1101262395Sbapt * @param parser
1102262395Sbapt * @param chunk
1103290071Sbapt * @param next_key
1104290071Sbapt * @param end_of_object
1105262395Sbapt * @return true if a key has been parsed
1106262395Sbapt */
1107262395Sbaptstatic bool
1108290071Sbaptucl_parse_key (struct ucl_parser *parser, struct ucl_chunk *chunk,
1109290071Sbapt		bool *next_key, bool *end_of_object)
1110262395Sbapt{
1111262395Sbapt	const unsigned char *p, *c = NULL, *end, *t;
1112262395Sbapt	const char *key = NULL;
1113262395Sbapt	bool got_quote = false, got_eq = false, got_semicolon = false,
1114262395Sbapt			need_unescape = false, ucl_escape = false, var_expand = false,
1115262395Sbapt			got_content = false, got_sep = false;
1116290071Sbapt	ucl_object_t *nobj;
1117262395Sbapt	ssize_t keylen;
1118262395Sbapt
1119262395Sbapt	p = chunk->pos;
1120262395Sbapt
1121262395Sbapt	if (*p == '.') {
1122262395Sbapt		/* It is macro actually */
1123262395Sbapt		ucl_chunk_skipc (chunk, p);
1124262395Sbapt		parser->prev_state = parser->state;
1125262395Sbapt		parser->state = UCL_STATE_MACRO_NAME;
1126279549Sbapt		*end_of_object = false;
1127262395Sbapt		return true;
1128262395Sbapt	}
1129262395Sbapt	while (p < chunk->end) {
1130262395Sbapt		/*
1131262395Sbapt		 * A key must start with alpha, number, '/' or '_' and end with space character
1132262395Sbapt		 */
1133262395Sbapt		if (c == NULL) {
1134262395Sbapt			if (chunk->remain >= 2 && ucl_lex_is_comment (p[0], p[1])) {
1135262395Sbapt				if (!ucl_skip_comments (parser)) {
1136262395Sbapt					return false;
1137262395Sbapt				}
1138262395Sbapt				p = chunk->pos;
1139262395Sbapt			}
1140262395Sbapt			else if (ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE)) {
1141262395Sbapt				ucl_chunk_skipc (chunk, p);
1142262395Sbapt			}
1143262395Sbapt			else if (ucl_test_character (*p, UCL_CHARACTER_KEY_START)) {
1144262395Sbapt				/* The first symbol */
1145262395Sbapt				c = p;
1146262395Sbapt				ucl_chunk_skipc (chunk, p);
1147262395Sbapt				got_content = true;
1148262395Sbapt			}
1149262395Sbapt			else if (*p == '"') {
1150262395Sbapt				/* JSON style key */
1151262395Sbapt				c = p + 1;
1152262395Sbapt				got_quote = true;
1153262395Sbapt				got_content = true;
1154262395Sbapt				ucl_chunk_skipc (chunk, p);
1155262395Sbapt			}
1156262395Sbapt			else if (*p == '}') {
1157262395Sbapt				/* We have actually end of an object */
1158262395Sbapt				*end_of_object = true;
1159262395Sbapt				return true;
1160262395Sbapt			}
1161262395Sbapt			else if (*p == '.') {
1162262395Sbapt				ucl_chunk_skipc (chunk, p);
1163262395Sbapt				parser->prev_state = parser->state;
1164262395Sbapt				parser->state = UCL_STATE_MACRO_NAME;
1165262395Sbapt				return true;
1166262395Sbapt			}
1167262395Sbapt			else {
1168262395Sbapt				/* Invalid identifier */
1169275223Sbapt				ucl_set_err (parser, UCL_ESYNTAX, "key must begin with a letter",
1170275223Sbapt						&parser->err);
1171262395Sbapt				return false;
1172262395Sbapt			}
1173262395Sbapt		}
1174262395Sbapt		else {
1175262395Sbapt			/* Parse the body of a key */
1176262395Sbapt			if (!got_quote) {
1177262395Sbapt				if (ucl_test_character (*p, UCL_CHARACTER_KEY)) {
1178262395Sbapt					got_content = true;
1179262395Sbapt					ucl_chunk_skipc (chunk, p);
1180262395Sbapt				}
1181262395Sbapt				else if (ucl_test_character (*p, UCL_CHARACTER_KEY_SEP)) {
1182262395Sbapt					end = p;
1183262395Sbapt					break;
1184262395Sbapt				}
1185262395Sbapt				else {
1186275223Sbapt					ucl_set_err (parser, UCL_ESYNTAX, "invalid character in a key",
1187275223Sbapt							&parser->err);
1188262395Sbapt					return false;
1189262395Sbapt				}
1190262395Sbapt			}
1191262395Sbapt			else {
1192262395Sbapt				/* We need to parse json like quoted string */
1193262395Sbapt				if (!ucl_lex_json_string (parser, chunk, &need_unescape, &ucl_escape, &var_expand)) {
1194262395Sbapt					return false;
1195262395Sbapt				}
1196262395Sbapt				/* Always escape keys obtained via json */
1197262395Sbapt				end = chunk->pos - 1;
1198262395Sbapt				p = chunk->pos;
1199262395Sbapt				break;
1200262395Sbapt			}
1201262395Sbapt		}
1202262395Sbapt	}
1203262395Sbapt
1204262395Sbapt	if (p >= chunk->end && got_content) {
1205275223Sbapt		ucl_set_err (parser, UCL_ESYNTAX, "unfinished key", &parser->err);
1206262395Sbapt		return false;
1207262395Sbapt	}
1208262395Sbapt	else if (!got_content) {
1209262395Sbapt		return true;
1210262395Sbapt	}
1211262395Sbapt	*end_of_object = false;
1212262395Sbapt	/* We are now at the end of the key, need to parse the rest */
1213262395Sbapt	while (p < chunk->end) {
1214262395Sbapt		if (ucl_test_character (*p, UCL_CHARACTER_WHITESPACE)) {
1215262395Sbapt			ucl_chunk_skipc (chunk, p);
1216262395Sbapt		}
1217262395Sbapt		else if (*p == '=') {
1218262395Sbapt			if (!got_eq && !got_semicolon) {
1219262395Sbapt				ucl_chunk_skipc (chunk, p);
1220262395Sbapt				got_eq = true;
1221262395Sbapt			}
1222262395Sbapt			else {
1223275223Sbapt				ucl_set_err (parser, UCL_ESYNTAX, "unexpected '=' character",
1224275223Sbapt						&parser->err);
1225262395Sbapt				return false;
1226262395Sbapt			}
1227262395Sbapt		}
1228262395Sbapt		else if (*p == ':') {
1229262395Sbapt			if (!got_eq && !got_semicolon) {
1230262395Sbapt				ucl_chunk_skipc (chunk, p);
1231262395Sbapt				got_semicolon = true;
1232262395Sbapt			}
1233262395Sbapt			else {
1234275223Sbapt				ucl_set_err (parser, UCL_ESYNTAX, "unexpected ':' character",
1235275223Sbapt						&parser->err);
1236262395Sbapt				return false;
1237262395Sbapt			}
1238262395Sbapt		}
1239262395Sbapt		else if (chunk->remain >= 2 && ucl_lex_is_comment (p[0], p[1])) {
1240262395Sbapt			/* Check for comment */
1241262395Sbapt			if (!ucl_skip_comments (parser)) {
1242262395Sbapt				return false;
1243262395Sbapt			}
1244262395Sbapt			p = chunk->pos;
1245262395Sbapt		}
1246262395Sbapt		else {
1247262395Sbapt			/* Start value */
1248262395Sbapt			break;
1249262395Sbapt		}
1250262395Sbapt	}
1251262395Sbapt
1252262395Sbapt	if (p >= chunk->end && got_content) {
1253275223Sbapt		ucl_set_err (parser, UCL_ESYNTAX, "unfinished key", &parser->err);
1254262395Sbapt		return false;
1255262395Sbapt	}
1256262395Sbapt
1257262395Sbapt	got_sep = got_semicolon || got_eq;
1258262395Sbapt
1259262395Sbapt	if (!got_sep) {
1260262395Sbapt		/*
1261262395Sbapt		 * Maybe we have more keys nested, so search for termination character.
1262262395Sbapt		 * Possible choices:
1263262395Sbapt		 * 1) key1 key2 ... keyN [:=] value <- we treat that as error
1264262395Sbapt		 * 2) key1 ... keyN {} or [] <- we treat that as nested objects
1265262395Sbapt		 * 3) key1 value[;,\n] <- we treat that as linear object
1266262395Sbapt		 */
1267262395Sbapt		t = p;
1268262395Sbapt		*next_key = false;
1269262395Sbapt		while (ucl_test_character (*t, UCL_CHARACTER_WHITESPACE)) {
1270262395Sbapt			t ++;
1271262395Sbapt		}
1272262395Sbapt		/* Check first non-space character after a key */
1273262395Sbapt		if (*t != '{' && *t != '[') {
1274262395Sbapt			while (t < chunk->end) {
1275262395Sbapt				if (*t == ',' || *t == ';' || *t == '\n' || *t == '\r') {
1276262395Sbapt					break;
1277262395Sbapt				}
1278262395Sbapt				else if (*t == '{' || *t == '[') {
1279262395Sbapt					*next_key = true;
1280262395Sbapt					break;
1281262395Sbapt				}
1282262395Sbapt				t ++;
1283262395Sbapt			}
1284262395Sbapt		}
1285262395Sbapt	}
1286262395Sbapt
1287262395Sbapt	/* Create a new object */
1288275223Sbapt	nobj = ucl_object_new_full (UCL_NULL, parser->chunks->priority);
1289262395Sbapt	keylen = ucl_copy_or_store_ptr (parser, c, &nobj->trash_stack[UCL_TRASH_KEY],
1290262395Sbapt			&key, end - c, need_unescape, parser->flags & UCL_PARSER_KEY_LOWERCASE, false);
1291262395Sbapt	if (keylen == -1) {
1292264789Sbapt		ucl_object_unref (nobj);
1293262395Sbapt		return false;
1294262395Sbapt	}
1295262395Sbapt	else if (keylen == 0) {
1296275223Sbapt		ucl_set_err (parser, UCL_ESYNTAX, "empty keys are not allowed", &parser->err);
1297264789Sbapt		ucl_object_unref (nobj);
1298262395Sbapt		return false;
1299262395Sbapt	}
1300262395Sbapt
1301262395Sbapt	nobj->key = key;
1302262395Sbapt	nobj->keylen = keylen;
1303290071Sbapt
1304290071Sbapt	if (!ucl_parser_process_object_element (parser, nobj)) {
1305290071Sbapt		return false;
1306262395Sbapt	}
1307262395Sbapt
1308262395Sbapt	if (ucl_escape) {
1309262395Sbapt		nobj->flags |= UCL_OBJECT_NEED_KEY_ESCAPE;
1310262395Sbapt	}
1311262395Sbapt
1312262395Sbapt
1313262395Sbapt	return true;
1314262395Sbapt}
1315262395Sbapt
1316262395Sbapt/**
1317262395Sbapt * Parse a cl string
1318262395Sbapt * @param parser
1319262395Sbapt * @param chunk
1320290071Sbapt * @param var_expand
1321290071Sbapt * @param need_unescape
1322262395Sbapt * @return true if a key has been parsed
1323262395Sbapt */
1324262395Sbaptstatic bool
1325262395Sbaptucl_parse_string_value (struct ucl_parser *parser,
1326262395Sbapt		struct ucl_chunk *chunk, bool *var_expand, bool *need_unescape)
1327262395Sbapt{
1328262395Sbapt	const unsigned char *p;
1329262395Sbapt	enum {
1330262395Sbapt		UCL_BRACE_ROUND = 0,
1331262395Sbapt		UCL_BRACE_SQUARE,
1332262395Sbapt		UCL_BRACE_FIGURE
1333262395Sbapt	};
1334262395Sbapt	int braces[3][2] = {{0, 0}, {0, 0}, {0, 0}};
1335262395Sbapt
1336262395Sbapt	p = chunk->pos;
1337262395Sbapt
1338262395Sbapt	while (p < chunk->end) {
1339262395Sbapt
1340262395Sbapt		/* Skip pairs of figure braces */
1341262395Sbapt		if (*p == '{') {
1342262395Sbapt			braces[UCL_BRACE_FIGURE][0] ++;
1343262395Sbapt		}
1344262395Sbapt		else if (*p == '}') {
1345262395Sbapt			braces[UCL_BRACE_FIGURE][1] ++;
1346262395Sbapt			if (braces[UCL_BRACE_FIGURE][1] <= braces[UCL_BRACE_FIGURE][0]) {
1347262395Sbapt				/* This is not a termination symbol, continue */
1348262395Sbapt				ucl_chunk_skipc (chunk, p);
1349262395Sbapt				continue;
1350262395Sbapt			}
1351262395Sbapt		}
1352262395Sbapt		/* Skip pairs of square braces */
1353262395Sbapt		else if (*p == '[') {
1354262395Sbapt			braces[UCL_BRACE_SQUARE][0] ++;
1355262395Sbapt		}
1356262395Sbapt		else if (*p == ']') {
1357262395Sbapt			braces[UCL_BRACE_SQUARE][1] ++;
1358262395Sbapt			if (braces[UCL_BRACE_SQUARE][1] <= braces[UCL_BRACE_SQUARE][0]) {
1359262395Sbapt				/* This is not a termination symbol, continue */
1360262395Sbapt				ucl_chunk_skipc (chunk, p);
1361262395Sbapt				continue;
1362262395Sbapt			}
1363262395Sbapt		}
1364262395Sbapt		else if (*p == '$') {
1365262395Sbapt			*var_expand = true;
1366262395Sbapt		}
1367262395Sbapt		else if (*p == '\\') {
1368262395Sbapt			*need_unescape = true;
1369262395Sbapt			ucl_chunk_skipc (chunk, p);
1370262395Sbapt			if (p < chunk->end) {
1371262395Sbapt				ucl_chunk_skipc (chunk, p);
1372262395Sbapt			}
1373262395Sbapt			continue;
1374262395Sbapt		}
1375262395Sbapt
1376262395Sbapt		if (ucl_lex_is_atom_end (*p) || (chunk->remain >= 2 && ucl_lex_is_comment (p[0], p[1]))) {
1377262395Sbapt			break;
1378262395Sbapt		}
1379262395Sbapt		ucl_chunk_skipc (chunk, p);
1380262395Sbapt	}
1381262395Sbapt
1382262395Sbapt	return true;
1383262395Sbapt}
1384262395Sbapt
1385262395Sbapt/**
1386262395Sbapt * Parse multiline string ending with \n{term}\n
1387262395Sbapt * @param parser
1388262395Sbapt * @param chunk
1389262395Sbapt * @param term
1390262395Sbapt * @param term_len
1391290071Sbapt * @param beg
1392290071Sbapt * @param var_expand
1393262395Sbapt * @return size of multiline string or 0 in case of error
1394262395Sbapt */
1395262395Sbaptstatic int
1396262395Sbaptucl_parse_multiline_string (struct ucl_parser *parser,
1397262395Sbapt		struct ucl_chunk *chunk, const unsigned char *term,
1398262395Sbapt		int term_len, unsigned char const **beg,
1399262395Sbapt		bool *var_expand)
1400262395Sbapt{
1401275223Sbapt	const unsigned char *p, *c, *tend;
1402262395Sbapt	bool newline = false;
1403262395Sbapt	int len = 0;
1404262395Sbapt
1405262395Sbapt	p = chunk->pos;
1406262395Sbapt
1407262395Sbapt	c = p;
1408262395Sbapt
1409262395Sbapt	while (p < chunk->end) {
1410262395Sbapt		if (newline) {
1411262395Sbapt			if (chunk->end - p < term_len) {
1412262395Sbapt				return 0;
1413262395Sbapt			}
1414275223Sbapt			else if (memcmp (p, term, term_len) == 0) {
1415275223Sbapt				tend = p + term_len;
1416275223Sbapt				if (*tend != '\n' && *tend != ';' && *tend != ',') {
1417275223Sbapt					/* Incomplete terminator */
1418275223Sbapt					ucl_chunk_skipc (chunk, p);
1419275223Sbapt					continue;
1420275223Sbapt				}
1421262395Sbapt				len = p - c;
1422262395Sbapt				chunk->remain -= term_len;
1423262395Sbapt				chunk->pos = p + term_len;
1424262395Sbapt				chunk->column = term_len;
1425262395Sbapt				*beg = c;
1426262395Sbapt				break;
1427262395Sbapt			}
1428262395Sbapt		}
1429262395Sbapt		if (*p == '\n') {
1430262395Sbapt			newline = true;
1431262395Sbapt		}
1432262395Sbapt		else {
1433262395Sbapt			if (*p == '$') {
1434262395Sbapt				*var_expand = true;
1435262395Sbapt			}
1436262395Sbapt			newline = false;
1437262395Sbapt		}
1438262395Sbapt		ucl_chunk_skipc (chunk, p);
1439262395Sbapt	}
1440262395Sbapt
1441262395Sbapt	return len;
1442262395Sbapt}
1443262395Sbapt
1444290071Sbaptstatic inline ucl_object_t*
1445290071Sbaptucl_parser_get_container (struct ucl_parser *parser)
1446262975Sbapt{
1447262975Sbapt	ucl_object_t *t, *obj = NULL;
1448262975Sbapt
1449279549Sbapt	if (parser == NULL || parser->stack == NULL || parser->stack->obj == NULL) {
1450279549Sbapt		return NULL;
1451279549Sbapt	}
1452279549Sbapt
1453262975Sbapt	if (parser->stack->obj->type == UCL_ARRAY) {
1454262975Sbapt		/* Object must be allocated */
1455275223Sbapt		obj = ucl_object_new_full (UCL_NULL, parser->chunks->priority);
1456279549Sbapt		t = parser->stack->obj;
1457290071Sbapt
1458290071Sbapt		if (!ucl_array_append (t, obj)) {
1459290071Sbapt			ucl_object_unref (obj);
1460290071Sbapt			return NULL;
1461290071Sbapt		}
1462290071Sbapt
1463262975Sbapt		parser->cur_obj = obj;
1464262975Sbapt	}
1465262975Sbapt	else {
1466262975Sbapt		/* Object has been already allocated */
1467262975Sbapt		obj = parser->cur_obj;
1468262975Sbapt	}
1469262975Sbapt
1470262975Sbapt	return obj;
1471262975Sbapt}
1472262975Sbapt
1473262395Sbapt/**
1474262395Sbapt * Handle value data
1475262395Sbapt * @param parser
1476262395Sbapt * @param chunk
1477262395Sbapt * @return
1478262395Sbapt */
1479262395Sbaptstatic bool
1480262395Sbaptucl_parse_value (struct ucl_parser *parser, struct ucl_chunk *chunk)
1481262395Sbapt{
1482262395Sbapt	const unsigned char *p, *c;
1483262975Sbapt	ucl_object_t *obj = NULL;
1484262395Sbapt	unsigned int stripped_spaces;
1485262395Sbapt	int str_len;
1486262395Sbapt	bool need_unescape = false, ucl_escape = false, var_expand = false;
1487262395Sbapt
1488262395Sbapt	p = chunk->pos;
1489262395Sbapt
1490262975Sbapt	/* Skip any spaces and comments */
1491262975Sbapt	if (ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE) ||
1492262975Sbapt			(chunk->remain >= 2 && ucl_lex_is_comment (p[0], p[1]))) {
1493262975Sbapt		while (p < chunk->end && ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE)) {
1494262975Sbapt			ucl_chunk_skipc (chunk, p);
1495262975Sbapt		}
1496262975Sbapt		if (!ucl_skip_comments (parser)) {
1497262975Sbapt			return false;
1498262975Sbapt		}
1499262975Sbapt		p = chunk->pos;
1500262975Sbapt	}
1501262975Sbapt
1502262395Sbapt	while (p < chunk->end) {
1503262395Sbapt		c = p;
1504262395Sbapt		switch (*p) {
1505262395Sbapt		case '"':
1506262395Sbapt			ucl_chunk_skipc (chunk, p);
1507290071Sbapt
1508290071Sbapt			if (!ucl_lex_json_string (parser, chunk, &need_unescape, &ucl_escape,
1509290071Sbapt					&var_expand)) {
1510262395Sbapt				return false;
1511262395Sbapt			}
1512290071Sbapt
1513290071Sbapt			obj = ucl_parser_get_container (parser);
1514262395Sbapt			str_len = chunk->pos - c - 2;
1515262395Sbapt			obj->type = UCL_STRING;
1516290071Sbapt			if ((str_len = ucl_copy_or_store_ptr (parser, c + 1,
1517290071Sbapt					&obj->trash_stack[UCL_TRASH_VALUE],
1518290071Sbapt					&obj->value.sv, str_len, need_unescape, false,
1519290071Sbapt					var_expand)) == -1) {
1520262395Sbapt				return false;
1521262395Sbapt			}
1522262395Sbapt			obj->len = str_len;
1523290071Sbapt
1524262395Sbapt			parser->state = UCL_STATE_AFTER_VALUE;
1525262395Sbapt			p = chunk->pos;
1526290071Sbapt
1527262395Sbapt			return true;
1528262395Sbapt			break;
1529262395Sbapt		case '{':
1530290071Sbapt			obj = ucl_parser_get_container (parser);
1531262395Sbapt			/* We have a new object */
1532290071Sbapt			obj = ucl_parser_add_container (obj, parser, false, parser->stack->level);
1533263648Sbapt			if (obj == NULL) {
1534263648Sbapt				return false;
1535263648Sbapt			}
1536262395Sbapt
1537262395Sbapt			ucl_chunk_skipc (chunk, p);
1538290071Sbapt
1539262395Sbapt			return true;
1540262395Sbapt			break;
1541262395Sbapt		case '[':
1542290071Sbapt			obj = ucl_parser_get_container (parser);
1543262395Sbapt			/* We have a new array */
1544290071Sbapt			obj = ucl_parser_add_container (obj, parser, true, parser->stack->level);
1545263648Sbapt			if (obj == NULL) {
1546263648Sbapt				return false;
1547263648Sbapt			}
1548262395Sbapt
1549262395Sbapt			ucl_chunk_skipc (chunk, p);
1550290071Sbapt
1551262395Sbapt			return true;
1552262395Sbapt			break;
1553262975Sbapt		case ']':
1554262975Sbapt			/* We have the array ending */
1555262975Sbapt			if (parser->stack && parser->stack->obj->type == UCL_ARRAY) {
1556262975Sbapt				parser->state = UCL_STATE_AFTER_VALUE;
1557262975Sbapt				return true;
1558262975Sbapt			}
1559262975Sbapt			else {
1560262975Sbapt				goto parse_string;
1561262975Sbapt			}
1562262975Sbapt			break;
1563262395Sbapt		case '<':
1564290071Sbapt			obj = ucl_parser_get_container (parser);
1565262395Sbapt			/* We have something like multiline value, which must be <<[A-Z]+\n */
1566262395Sbapt			if (chunk->end - p > 3) {
1567262395Sbapt				if (memcmp (p, "<<", 2) == 0) {
1568262395Sbapt					p += 2;
1569262395Sbapt					/* We allow only uppercase characters in multiline definitions */
1570262395Sbapt					while (p < chunk->end && *p >= 'A' && *p <= 'Z') {
1571262395Sbapt						p ++;
1572262395Sbapt					}
1573262395Sbapt					if (*p =='\n') {
1574262395Sbapt						/* Set chunk positions and start multiline parsing */
1575262395Sbapt						c += 2;
1576262395Sbapt						chunk->remain -= p - c;
1577262395Sbapt						chunk->pos = p + 1;
1578262395Sbapt						chunk->column = 0;
1579262395Sbapt						chunk->line ++;
1580262395Sbapt						if ((str_len = ucl_parse_multiline_string (parser, chunk, c,
1581262395Sbapt								p - c, &c, &var_expand)) == 0) {
1582275223Sbapt							ucl_set_err (parser, UCL_ESYNTAX,
1583275223Sbapt									"unterminated multiline value", &parser->err);
1584262395Sbapt							return false;
1585262395Sbapt						}
1586290071Sbapt
1587262395Sbapt						obj->type = UCL_STRING;
1588290071Sbapt						obj->flags |= UCL_OBJECT_MULTILINE;
1589290071Sbapt						if ((str_len = ucl_copy_or_store_ptr (parser, c,
1590290071Sbapt								&obj->trash_stack[UCL_TRASH_VALUE],
1591290071Sbapt								&obj->value.sv, str_len - 1, false,
1592290071Sbapt								false, var_expand)) == -1) {
1593262395Sbapt							return false;
1594262395Sbapt						}
1595262395Sbapt						obj->len = str_len;
1596290071Sbapt
1597262395Sbapt						parser->state = UCL_STATE_AFTER_VALUE;
1598290071Sbapt
1599262395Sbapt						return true;
1600262395Sbapt					}
1601262395Sbapt				}
1602262395Sbapt			}
1603262395Sbapt			/* Fallback to ordinary strings */
1604262395Sbapt		default:
1605262975Sbaptparse_string:
1606262975Sbapt			if (obj == NULL) {
1607290071Sbapt				obj = ucl_parser_get_container (parser);
1608262395Sbapt			}
1609290071Sbapt
1610262395Sbapt			/* Parse atom */
1611262395Sbapt			if (ucl_test_character (*p, UCL_CHARACTER_VALUE_DIGIT_START)) {
1612262395Sbapt				if (!ucl_lex_number (parser, chunk, obj)) {
1613262395Sbapt					if (parser->state == UCL_STATE_ERROR) {
1614262395Sbapt						return false;
1615262395Sbapt					}
1616262395Sbapt				}
1617262395Sbapt				else {
1618262395Sbapt					parser->state = UCL_STATE_AFTER_VALUE;
1619262395Sbapt					return true;
1620262395Sbapt				}
1621262395Sbapt				/* Fallback to normal string */
1622262395Sbapt			}
1623262395Sbapt
1624290071Sbapt			if (!ucl_parse_string_value (parser, chunk, &var_expand,
1625290071Sbapt					&need_unescape)) {
1626262395Sbapt				return false;
1627262395Sbapt			}
1628262395Sbapt			/* Cut trailing spaces */
1629262395Sbapt			stripped_spaces = 0;
1630262395Sbapt			while (ucl_test_character (*(chunk->pos - 1 - stripped_spaces),
1631262395Sbapt					UCL_CHARACTER_WHITESPACE)) {
1632262395Sbapt				stripped_spaces ++;
1633262395Sbapt			}
1634262395Sbapt			str_len = chunk->pos - c - stripped_spaces;
1635262395Sbapt			if (str_len <= 0) {
1636290071Sbapt				ucl_set_err (parser, UCL_ESYNTAX, "string value must not be empty",
1637275223Sbapt						&parser->err);
1638262395Sbapt				return false;
1639262395Sbapt			}
1640262395Sbapt			else if (str_len == 4 && memcmp (c, "null", 4) == 0) {
1641262395Sbapt				obj->len = 0;
1642262395Sbapt				obj->type = UCL_NULL;
1643262395Sbapt			}
1644262395Sbapt			else if (!ucl_maybe_parse_boolean (obj, c, str_len)) {
1645262395Sbapt				obj->type = UCL_STRING;
1646290071Sbapt				if ((str_len = ucl_copy_or_store_ptr (parser, c,
1647290071Sbapt						&obj->trash_stack[UCL_TRASH_VALUE],
1648262395Sbapt						&obj->value.sv, str_len, need_unescape,
1649262395Sbapt						false, var_expand)) == -1) {
1650262395Sbapt					return false;
1651262395Sbapt				}
1652262395Sbapt				obj->len = str_len;
1653262395Sbapt			}
1654262395Sbapt			parser->state = UCL_STATE_AFTER_VALUE;
1655262395Sbapt			p = chunk->pos;
1656262395Sbapt
1657262395Sbapt			return true;
1658262395Sbapt			break;
1659262395Sbapt		}
1660262395Sbapt	}
1661262395Sbapt
1662262395Sbapt	return true;
1663262395Sbapt}
1664262395Sbapt
1665262395Sbapt/**
1666262395Sbapt * Handle after value data
1667262395Sbapt * @param parser
1668262395Sbapt * @param chunk
1669262395Sbapt * @return
1670262395Sbapt */
1671262395Sbaptstatic bool
1672262395Sbaptucl_parse_after_value (struct ucl_parser *parser, struct ucl_chunk *chunk)
1673262395Sbapt{
1674262395Sbapt	const unsigned char *p;
1675262395Sbapt	bool got_sep = false;
1676262395Sbapt	struct ucl_stack *st;
1677262395Sbapt
1678262395Sbapt	p = chunk->pos;
1679262395Sbapt
1680262395Sbapt	while (p < chunk->end) {
1681262395Sbapt		if (ucl_test_character (*p, UCL_CHARACTER_WHITESPACE)) {
1682262395Sbapt			/* Skip whitespaces */
1683262395Sbapt			ucl_chunk_skipc (chunk, p);
1684262395Sbapt		}
1685262395Sbapt		else if (chunk->remain >= 2 && ucl_lex_is_comment (p[0], p[1])) {
1686262395Sbapt			/* Skip comment */
1687262395Sbapt			if (!ucl_skip_comments (parser)) {
1688262395Sbapt				return false;
1689262395Sbapt			}
1690262395Sbapt			/* Treat comment as a separator */
1691262395Sbapt			got_sep = true;
1692262395Sbapt			p = chunk->pos;
1693262395Sbapt		}
1694262395Sbapt		else if (ucl_test_character (*p, UCL_CHARACTER_VALUE_END)) {
1695262395Sbapt			if (*p == '}' || *p == ']') {
1696262395Sbapt				if (parser->stack == NULL) {
1697275223Sbapt					ucl_set_err (parser, UCL_ESYNTAX,
1698275223Sbapt							"end of array or object detected without corresponding start",
1699275223Sbapt							&parser->err);
1700262395Sbapt					return false;
1701262395Sbapt				}
1702262395Sbapt				if ((*p == '}' && parser->stack->obj->type == UCL_OBJECT) ||
1703262395Sbapt						(*p == ']' && parser->stack->obj->type == UCL_ARRAY)) {
1704262395Sbapt
1705262395Sbapt					/* Pop all nested objects from a stack */
1706262395Sbapt					st = parser->stack;
1707262395Sbapt					parser->stack = st->next;
1708262395Sbapt					UCL_FREE (sizeof (struct ucl_stack), st);
1709262395Sbapt
1710262395Sbapt					while (parser->stack != NULL) {
1711262395Sbapt						st = parser->stack;
1712262395Sbapt						if (st->next == NULL || st->next->level == st->level) {
1713262395Sbapt							break;
1714262395Sbapt						}
1715262395Sbapt						parser->stack = st->next;
1716262395Sbapt						UCL_FREE (sizeof (struct ucl_stack), st);
1717262395Sbapt					}
1718262395Sbapt				}
1719262395Sbapt				else {
1720275223Sbapt					ucl_set_err (parser, UCL_ESYNTAX,
1721275223Sbapt							"unexpected terminating symbol detected",
1722275223Sbapt							&parser->err);
1723262395Sbapt					return false;
1724262395Sbapt				}
1725262395Sbapt
1726262395Sbapt				if (parser->stack == NULL) {
1727262395Sbapt					/* Ignore everything after a top object */
1728262395Sbapt					return true;
1729262395Sbapt				}
1730262395Sbapt				else {
1731262395Sbapt					ucl_chunk_skipc (chunk, p);
1732262395Sbapt				}
1733262395Sbapt				got_sep = true;
1734262395Sbapt			}
1735262395Sbapt			else {
1736262395Sbapt				/* Got a separator */
1737262395Sbapt				got_sep = true;
1738262395Sbapt				ucl_chunk_skipc (chunk, p);
1739262395Sbapt			}
1740262395Sbapt		}
1741262395Sbapt		else {
1742262395Sbapt			/* Anything else */
1743262395Sbapt			if (!got_sep) {
1744275223Sbapt				ucl_set_err (parser, UCL_ESYNTAX, "delimiter is missing",
1745275223Sbapt						&parser->err);
1746262395Sbapt				return false;
1747262395Sbapt			}
1748262395Sbapt			return true;
1749262395Sbapt		}
1750262395Sbapt	}
1751262395Sbapt
1752262395Sbapt	return true;
1753262395Sbapt}
1754262395Sbapt
1755262395Sbapt/**
1756262395Sbapt * Handle macro data
1757262395Sbapt * @param parser
1758262395Sbapt * @param chunk
1759290071Sbapt * @param marco
1760290071Sbapt * @param macro_start
1761290071Sbapt * @param macro_len
1762262395Sbapt * @return
1763262395Sbapt */
1764262395Sbaptstatic bool
1765262395Sbaptucl_parse_macro_value (struct ucl_parser *parser,
1766262395Sbapt		struct ucl_chunk *chunk, struct ucl_macro *macro,
1767262395Sbapt		unsigned char const **macro_start, size_t *macro_len)
1768262395Sbapt{
1769262395Sbapt	const unsigned char *p, *c;
1770262395Sbapt	bool need_unescape = false, ucl_escape = false, var_expand = false;
1771262395Sbapt
1772262395Sbapt	p = chunk->pos;
1773262395Sbapt
1774262395Sbapt	switch (*p) {
1775262395Sbapt	case '"':
1776262395Sbapt		/* We have macro value encoded in quotes */
1777262395Sbapt		c = p;
1778262395Sbapt		ucl_chunk_skipc (chunk, p);
1779262395Sbapt		if (!ucl_lex_json_string (parser, chunk, &need_unescape, &ucl_escape, &var_expand)) {
1780262395Sbapt			return false;
1781262395Sbapt		}
1782262395Sbapt
1783262395Sbapt		*macro_start = c + 1;
1784262395Sbapt		*macro_len = chunk->pos - c - 2;
1785262395Sbapt		p = chunk->pos;
1786262395Sbapt		break;
1787262395Sbapt	case '{':
1788262395Sbapt		/* We got a multiline macro body */
1789262395Sbapt		ucl_chunk_skipc (chunk, p);
1790262395Sbapt		/* Skip spaces at the beginning */
1791262395Sbapt		while (p < chunk->end) {
1792262395Sbapt			if (ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE)) {
1793262395Sbapt				ucl_chunk_skipc (chunk, p);
1794262395Sbapt			}
1795262395Sbapt			else {
1796262395Sbapt				break;
1797262395Sbapt			}
1798262395Sbapt		}
1799262395Sbapt		c = p;
1800262395Sbapt		while (p < chunk->end) {
1801262395Sbapt			if (*p == '}') {
1802262395Sbapt				break;
1803262395Sbapt			}
1804262395Sbapt			ucl_chunk_skipc (chunk, p);
1805262395Sbapt		}
1806262395Sbapt		*macro_start = c;
1807262395Sbapt		*macro_len = p - c;
1808262395Sbapt		ucl_chunk_skipc (chunk, p);
1809262395Sbapt		break;
1810262395Sbapt	default:
1811262395Sbapt		/* Macro is not enclosed in quotes or braces */
1812262395Sbapt		c = p;
1813262395Sbapt		while (p < chunk->end) {
1814262395Sbapt			if (ucl_lex_is_atom_end (*p)) {
1815262395Sbapt				break;
1816262395Sbapt			}
1817262395Sbapt			ucl_chunk_skipc (chunk, p);
1818262395Sbapt		}
1819262395Sbapt		*macro_start = c;
1820262395Sbapt		*macro_len = p - c;
1821262395Sbapt		break;
1822262395Sbapt	}
1823262395Sbapt
1824262395Sbapt	/* We are at the end of a macro */
1825262395Sbapt	/* Skip ';' and space characters and return to previous state */
1826262395Sbapt	while (p < chunk->end) {
1827262395Sbapt		if (!ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE) && *p != ';') {
1828262395Sbapt			break;
1829262395Sbapt		}
1830262395Sbapt		ucl_chunk_skipc (chunk, p);
1831262395Sbapt	}
1832262395Sbapt	return true;
1833262395Sbapt}
1834262395Sbapt
1835262395Sbapt/**
1836275223Sbapt * Parse macro arguments as UCL object
1837275223Sbapt * @param parser parser structure
1838275223Sbapt * @param chunk the current data chunk
1839275223Sbapt * @return
1840275223Sbapt */
1841275223Sbaptstatic ucl_object_t *
1842275223Sbaptucl_parse_macro_arguments (struct ucl_parser *parser,
1843275223Sbapt		struct ucl_chunk *chunk)
1844275223Sbapt{
1845275223Sbapt	ucl_object_t *res = NULL;
1846275223Sbapt	struct ucl_parser *params_parser;
1847275223Sbapt	int obraces = 1, ebraces = 0, state = 0;
1848275223Sbapt	const unsigned char *p, *c;
1849275223Sbapt	size_t args_len = 0;
1850275223Sbapt	struct ucl_parser_saved_state saved;
1851275223Sbapt
1852275223Sbapt	saved.column = chunk->column;
1853275223Sbapt	saved.line = chunk->line;
1854275223Sbapt	saved.pos = chunk->pos;
1855275223Sbapt	saved.remain = chunk->remain;
1856275223Sbapt	p = chunk->pos;
1857275223Sbapt
1858275223Sbapt	if (*p != '(' || chunk->remain < 2) {
1859275223Sbapt		return NULL;
1860275223Sbapt	}
1861275223Sbapt
1862275223Sbapt	/* Set begin and start */
1863275223Sbapt	ucl_chunk_skipc (chunk, p);
1864275223Sbapt	c = p;
1865275223Sbapt
1866275223Sbapt	while ((p) < (chunk)->end) {
1867275223Sbapt		switch (state) {
1868275223Sbapt		case 0:
1869275223Sbapt			/* Parse symbols and check for '(', ')' and '"' */
1870275223Sbapt			if (*p == '(') {
1871275223Sbapt				obraces ++;
1872275223Sbapt			}
1873275223Sbapt			else if (*p == ')') {
1874275223Sbapt				ebraces ++;
1875275223Sbapt			}
1876275223Sbapt			else if (*p == '"') {
1877275223Sbapt				state = 1;
1878275223Sbapt			}
1879275223Sbapt			/* Check pairing */
1880275223Sbapt			if (obraces == ebraces) {
1881275223Sbapt				state = 99;
1882275223Sbapt			}
1883275223Sbapt			else {
1884275223Sbapt				args_len ++;
1885275223Sbapt			}
1886275223Sbapt			/* Check overflow */
1887275223Sbapt			if (chunk->remain == 0) {
1888275223Sbapt				goto restore_chunk;
1889275223Sbapt			}
1890275223Sbapt			ucl_chunk_skipc (chunk, p);
1891275223Sbapt			break;
1892275223Sbapt		case 1:
1893275223Sbapt			/* We have quote character, so skip all but quotes */
1894275223Sbapt			if (*p == '"' && *(p - 1) != '\\') {
1895275223Sbapt				state = 0;
1896275223Sbapt			}
1897275223Sbapt			if (chunk->remain == 0) {
1898275223Sbapt				goto restore_chunk;
1899275223Sbapt			}
1900290071Sbapt			args_len ++;
1901275223Sbapt			ucl_chunk_skipc (chunk, p);
1902275223Sbapt			break;
1903275223Sbapt		case 99:
1904275223Sbapt			/*
1905275223Sbapt			 * We have read the full body of arguments, so we need to parse and set
1906275223Sbapt			 * object from that
1907275223Sbapt			 */
1908275223Sbapt			params_parser = ucl_parser_new (parser->flags);
1909275223Sbapt			if (!ucl_parser_add_chunk (params_parser, c, args_len)) {
1910275223Sbapt				ucl_set_err (parser, UCL_ESYNTAX, "macro arguments parsing error",
1911275223Sbapt						&parser->err);
1912275223Sbapt			}
1913275223Sbapt			else {
1914275223Sbapt				res = ucl_parser_get_object (params_parser);
1915275223Sbapt			}
1916275223Sbapt			ucl_parser_free (params_parser);
1917275223Sbapt
1918275223Sbapt			return res;
1919275223Sbapt
1920275223Sbapt			break;
1921275223Sbapt		}
1922275223Sbapt	}
1923275223Sbapt
1924275223Sbapt	return res;
1925275223Sbapt
1926275223Sbaptrestore_chunk:
1927275223Sbapt	chunk->column = saved.column;
1928275223Sbapt	chunk->line = saved.line;
1929275223Sbapt	chunk->pos = saved.pos;
1930275223Sbapt	chunk->remain = saved.remain;
1931275223Sbapt
1932275223Sbapt	return NULL;
1933275223Sbapt}
1934275223Sbapt
1935275223Sbapt#define SKIP_SPACES_COMMENTS(parser, chunk, p) do {								\
1936275223Sbapt	while ((p) < (chunk)->end) {												\
1937275223Sbapt		if (!ucl_test_character (*(p), UCL_CHARACTER_WHITESPACE_UNSAFE)) {		\
1938275223Sbapt			if ((chunk)->remain >= 2 && ucl_lex_is_comment ((p)[0], (p)[1])) {	\
1939275223Sbapt				if (!ucl_skip_comments (parser)) {								\
1940275223Sbapt					return false;												\
1941275223Sbapt				}																\
1942275223Sbapt				p = (chunk)->pos;												\
1943275223Sbapt			}																	\
1944275223Sbapt			break;																\
1945275223Sbapt		}																		\
1946275223Sbapt		ucl_chunk_skipc (chunk, p);												\
1947275223Sbapt	}																			\
1948275223Sbapt} while(0)
1949275223Sbapt
1950275223Sbapt/**
1951262395Sbapt * Handle the main states of rcl parser
1952262395Sbapt * @param parser parser structure
1953262395Sbapt * @return true if chunk has been parsed and false in case of error
1954262395Sbapt */
1955262395Sbaptstatic bool
1956262395Sbaptucl_state_machine (struct ucl_parser *parser)
1957262395Sbapt{
1958275223Sbapt	ucl_object_t *obj, *macro_args;
1959262395Sbapt	struct ucl_chunk *chunk = parser->chunks;
1960262395Sbapt	const unsigned char *p, *c = NULL, *macro_start = NULL;
1961262395Sbapt	unsigned char *macro_escaped;
1962262395Sbapt	size_t macro_len = 0;
1963262395Sbapt	struct ucl_macro *macro = NULL;
1964275223Sbapt	bool next_key = false, end_of_object = false, ret;
1965262395Sbapt
1966262395Sbapt	if (parser->top_obj == NULL) {
1967262395Sbapt		parser->state = UCL_STATE_INIT;
1968262395Sbapt	}
1969262395Sbapt
1970262395Sbapt	p = chunk->pos;
1971262395Sbapt	while (chunk->pos < chunk->end) {
1972262395Sbapt		switch (parser->state) {
1973262395Sbapt		case UCL_STATE_INIT:
1974262395Sbapt			/*
1975262395Sbapt			 * At the init state we can either go to the parse array or object
1976262395Sbapt			 * if we got [ or { correspondingly or can just treat new data as
1977262395Sbapt			 * a key of newly created object
1978262395Sbapt			 */
1979262395Sbapt			if (!ucl_skip_comments (parser)) {
1980262395Sbapt				parser->prev_state = parser->state;
1981262395Sbapt				parser->state = UCL_STATE_ERROR;
1982262395Sbapt				return false;
1983262395Sbapt			}
1984262395Sbapt			else {
1985268876Sbapt				/* Skip any spaces */
1986268876Sbapt				while (p < chunk->end && ucl_test_character (*p,
1987268876Sbapt						UCL_CHARACTER_WHITESPACE_UNSAFE)) {
1988268876Sbapt					ucl_chunk_skipc (chunk, p);
1989268876Sbapt				}
1990290071Sbapt
1991262395Sbapt				p = chunk->pos;
1992290071Sbapt
1993262395Sbapt				if (*p == '[') {
1994262395Sbapt					parser->state = UCL_STATE_VALUE;
1995262395Sbapt					ucl_chunk_skipc (chunk, p);
1996262395Sbapt				}
1997262395Sbapt				else {
1998262395Sbapt					parser->state = UCL_STATE_KEY;
1999262395Sbapt					if (*p == '{') {
2000262395Sbapt						ucl_chunk_skipc (chunk, p);
2001262395Sbapt					}
2002262395Sbapt				}
2003290071Sbapt
2004290071Sbapt				if (parser->top_obj == NULL) {
2005290071Sbapt					if (parser->state == UCL_STATE_VALUE) {
2006290071Sbapt						obj = ucl_parser_add_container (NULL, parser, true, 0);
2007290071Sbapt					}
2008290071Sbapt					else {
2009290071Sbapt						obj = ucl_parser_add_container (NULL, parser, false, 0);
2010290071Sbapt					}
2011290071Sbapt
2012290071Sbapt					if (obj == NULL) {
2013290071Sbapt						return false;
2014290071Sbapt					}
2015290071Sbapt
2016290071Sbapt					parser->top_obj = obj;
2017290071Sbapt					parser->cur_obj = obj;
2018290071Sbapt				}
2019290071Sbapt
2020262395Sbapt			}
2021262395Sbapt			break;
2022262395Sbapt		case UCL_STATE_KEY:
2023262395Sbapt			/* Skip any spaces */
2024262395Sbapt			while (p < chunk->end && ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE)) {
2025262395Sbapt				ucl_chunk_skipc (chunk, p);
2026262395Sbapt			}
2027262395Sbapt			if (*p == '}') {
2028262395Sbapt				/* We have the end of an object */
2029262395Sbapt				parser->state = UCL_STATE_AFTER_VALUE;
2030262395Sbapt				continue;
2031262395Sbapt			}
2032262395Sbapt			if (parser->stack == NULL) {
2033262395Sbapt				/* No objects are on stack, but we want to parse a key */
2034275223Sbapt				ucl_set_err (parser, UCL_ESYNTAX, "top object is finished but the parser "
2035262395Sbapt						"expects a key", &parser->err);
2036262395Sbapt				parser->prev_state = parser->state;
2037262395Sbapt				parser->state = UCL_STATE_ERROR;
2038262395Sbapt				return false;
2039262395Sbapt			}
2040262395Sbapt			if (!ucl_parse_key (parser, chunk, &next_key, &end_of_object)) {
2041262395Sbapt				parser->prev_state = parser->state;
2042262395Sbapt				parser->state = UCL_STATE_ERROR;
2043262395Sbapt				return false;
2044262395Sbapt			}
2045262395Sbapt			if (end_of_object) {
2046262395Sbapt				p = chunk->pos;
2047262395Sbapt				parser->state = UCL_STATE_AFTER_VALUE;
2048262395Sbapt				continue;
2049262395Sbapt			}
2050262395Sbapt			else if (parser->state != UCL_STATE_MACRO_NAME) {
2051262395Sbapt				if (next_key && parser->stack->obj->type == UCL_OBJECT) {
2052262395Sbapt					/* Parse more keys and nest objects accordingly */
2053290071Sbapt					obj = ucl_parser_add_container (parser->cur_obj, parser, false,
2054263648Sbapt							parser->stack->level + 1);
2055263648Sbapt					if (obj == NULL) {
2056263648Sbapt						return false;
2057263648Sbapt					}
2058262395Sbapt				}
2059262395Sbapt				else {
2060262395Sbapt					parser->state = UCL_STATE_VALUE;
2061262395Sbapt				}
2062262395Sbapt			}
2063262395Sbapt			else {
2064262395Sbapt				c = chunk->pos;
2065262395Sbapt			}
2066262395Sbapt			p = chunk->pos;
2067262395Sbapt			break;
2068262395Sbapt		case UCL_STATE_VALUE:
2069262395Sbapt			/* We need to check what we do have */
2070262395Sbapt			if (!ucl_parse_value (parser, chunk)) {
2071262395Sbapt				parser->prev_state = parser->state;
2072262395Sbapt				parser->state = UCL_STATE_ERROR;
2073262395Sbapt				return false;
2074262395Sbapt			}
2075262395Sbapt			/* State is set in ucl_parse_value call */
2076262395Sbapt			p = chunk->pos;
2077262395Sbapt			break;
2078262395Sbapt		case UCL_STATE_AFTER_VALUE:
2079262395Sbapt			if (!ucl_parse_after_value (parser, chunk)) {
2080262395Sbapt				parser->prev_state = parser->state;
2081262395Sbapt				parser->state = UCL_STATE_ERROR;
2082262395Sbapt				return false;
2083262395Sbapt			}
2084290071Sbapt
2085262395Sbapt			if (parser->stack != NULL) {
2086262395Sbapt				if (parser->stack->obj->type == UCL_OBJECT) {
2087262395Sbapt					parser->state = UCL_STATE_KEY;
2088262395Sbapt				}
2089262395Sbapt				else {
2090262395Sbapt					/* Array */
2091262395Sbapt					parser->state = UCL_STATE_VALUE;
2092262395Sbapt				}
2093262395Sbapt			}
2094262395Sbapt			else {
2095262395Sbapt				/* Skip everything at the end */
2096262395Sbapt				return true;
2097262395Sbapt			}
2098262395Sbapt			p = chunk->pos;
2099262395Sbapt			break;
2100262395Sbapt		case UCL_STATE_MACRO_NAME:
2101275223Sbapt			if (!ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE) &&
2102275223Sbapt					*p != '(') {
2103262395Sbapt				ucl_chunk_skipc (chunk, p);
2104262395Sbapt			}
2105290071Sbapt			else {
2106290071Sbapt				if (p - c > 0) {
2107290071Sbapt					/* We got macro name */
2108290071Sbapt					macro_len = (size_t) (p - c);
2109290071Sbapt					HASH_FIND (hh, parser->macroes, c, macro_len, macro);
2110290071Sbapt					if (macro == NULL) {
2111290071Sbapt						ucl_create_err (&parser->err,
2112290071Sbapt								"error on line %d at column %d: "
2113290071Sbapt										"unknown macro: '%.*s', character: '%c'",
2114290071Sbapt								chunk->line,
2115290071Sbapt								chunk->column,
2116290071Sbapt								(int) (p - c),
2117290071Sbapt								c,
2118290071Sbapt								*chunk->pos);
2119290071Sbapt						parser->state = UCL_STATE_ERROR;
2120290071Sbapt						return false;
2121290071Sbapt					}
2122290071Sbapt					/* Now we need to skip all spaces */
2123290071Sbapt					SKIP_SPACES_COMMENTS(parser, chunk, p);
2124290071Sbapt					parser->state = UCL_STATE_MACRO;
2125290071Sbapt				}
2126290071Sbapt				else {
2127290071Sbapt					/* We have invalid macro name */
2128290071Sbapt					ucl_create_err (&parser->err,
2129290071Sbapt							"error on line %d at column %d: invalid macro name",
2130290071Sbapt							chunk->line,
2131290071Sbapt							chunk->column);
2132262395Sbapt					parser->state = UCL_STATE_ERROR;
2133262395Sbapt					return false;
2134262395Sbapt				}
2135262395Sbapt			}
2136262395Sbapt			break;
2137262395Sbapt		case UCL_STATE_MACRO:
2138275223Sbapt			if (*chunk->pos == '(') {
2139275223Sbapt				macro_args = ucl_parse_macro_arguments (parser, chunk);
2140275223Sbapt				p = chunk->pos;
2141275223Sbapt				if (macro_args) {
2142275223Sbapt					SKIP_SPACES_COMMENTS(parser, chunk, p);
2143275223Sbapt				}
2144275223Sbapt			}
2145275223Sbapt			else {
2146275223Sbapt				macro_args = NULL;
2147275223Sbapt			}
2148262395Sbapt			if (!ucl_parse_macro_value (parser, chunk, macro,
2149262395Sbapt					&macro_start, &macro_len)) {
2150262395Sbapt				parser->prev_state = parser->state;
2151262395Sbapt				parser->state = UCL_STATE_ERROR;
2152262395Sbapt				return false;
2153262395Sbapt			}
2154275223Sbapt			macro_len = ucl_expand_variable (parser, &macro_escaped,
2155275223Sbapt					macro_start, macro_len);
2156262395Sbapt			parser->state = parser->prev_state;
2157262395Sbapt			if (macro_escaped == NULL) {
2158290071Sbapt				if (macro->is_context) {
2159290071Sbapt					ret = macro->h.context_handler (macro_start, macro_len,
2160290071Sbapt							macro_args,
2161290071Sbapt							parser->top_obj,
2162290071Sbapt							macro->ud);
2163290071Sbapt				}
2164290071Sbapt				else {
2165290071Sbapt					ret = macro->h.handler (macro_start, macro_len, macro_args,
2166290071Sbapt							macro->ud);
2167290071Sbapt				}
2168262395Sbapt			}
2169262395Sbapt			else {
2170290071Sbapt				if (macro->is_context) {
2171290071Sbapt					ret = macro->h.context_handler (macro_escaped, macro_len,
2172290071Sbapt							macro_args,
2173290071Sbapt							parser->top_obj,
2174290071Sbapt							macro->ud);
2175290071Sbapt				}
2176290071Sbapt				else {
2177290071Sbapt					ret = macro->h.handler (macro_escaped, macro_len, macro_args,
2178275223Sbapt						macro->ud);
2179290071Sbapt				}
2180290071Sbapt
2181262395Sbapt				UCL_FREE (macro_len + 1, macro_escaped);
2182262395Sbapt			}
2183290071Sbapt
2184290071Sbapt			/*
2185290071Sbapt			 * Chunk can be modified within macro handler
2186290071Sbapt			 */
2187290071Sbapt			chunk = parser->chunks;
2188262395Sbapt			p = chunk->pos;
2189275223Sbapt			if (macro_args) {
2190275223Sbapt				ucl_object_unref (macro_args);
2191275223Sbapt			}
2192275223Sbapt			if (!ret) {
2193275223Sbapt				return false;
2194275223Sbapt			}
2195262395Sbapt			break;
2196262395Sbapt		default:
2197262395Sbapt			/* TODO: add all states */
2198275223Sbapt			ucl_set_err (parser, UCL_EINTERNAL,
2199275223Sbapt					"internal error: parser is in an unknown state", &parser->err);
2200262395Sbapt			parser->state = UCL_STATE_ERROR;
2201262395Sbapt			return false;
2202262395Sbapt		}
2203262395Sbapt	}
2204262395Sbapt
2205262395Sbapt	return true;
2206262395Sbapt}
2207262395Sbapt
2208262395Sbaptstruct ucl_parser*
2209262395Sbaptucl_parser_new (int flags)
2210262395Sbapt{
2211262395Sbapt	struct ucl_parser *new;
2212262395Sbapt
2213262395Sbapt	new = UCL_ALLOC (sizeof (struct ucl_parser));
2214263648Sbapt	if (new == NULL) {
2215263648Sbapt		return NULL;
2216263648Sbapt	}
2217290071Sbapt
2218262395Sbapt	memset (new, 0, sizeof (struct ucl_parser));
2219262395Sbapt
2220262395Sbapt	ucl_parser_register_macro (new, "include", ucl_include_handler, new);
2221262395Sbapt	ucl_parser_register_macro (new, "try_include", ucl_try_include_handler, new);
2222262395Sbapt	ucl_parser_register_macro (new, "includes", ucl_includes_handler, new);
2223290071Sbapt	ucl_parser_register_macro (new, "priority", ucl_priority_handler, new);
2224290071Sbapt	ucl_parser_register_macro (new, "load", ucl_load_handler, new);
2225290071Sbapt	ucl_parser_register_context_macro (new, "inherit", ucl_inherit_handler, new);
2226262395Sbapt
2227262395Sbapt	new->flags = flags;
2228290071Sbapt	new->includepaths = NULL;
2229262395Sbapt
2230262395Sbapt	/* Initial assumption about filevars */
2231262395Sbapt	ucl_parser_set_filevars (new, NULL, false);
2232262395Sbapt
2233262395Sbapt	return new;
2234262395Sbapt}
2235262395Sbapt
2236290071Sbaptbool
2237290071Sbaptucl_parser_set_default_priority (struct ucl_parser *parser, unsigned prio)
2238290071Sbapt{
2239290071Sbapt	if (parser == NULL) {
2240290071Sbapt		return false;
2241290071Sbapt	}
2242262395Sbapt
2243290071Sbapt	parser->default_priority = prio;
2244290071Sbapt
2245290071Sbapt	return true;
2246290071Sbapt}
2247290071Sbapt
2248262395Sbaptvoid
2249262395Sbaptucl_parser_register_macro (struct ucl_parser *parser, const char *macro,
2250262395Sbapt		ucl_macro_handler handler, void* ud)
2251262395Sbapt{
2252262395Sbapt	struct ucl_macro *new;
2253262395Sbapt
2254263648Sbapt	if (macro == NULL || handler == NULL) {
2255263648Sbapt		return;
2256263648Sbapt	}
2257290071Sbapt
2258262395Sbapt	new = UCL_ALLOC (sizeof (struct ucl_macro));
2259263648Sbapt	if (new == NULL) {
2260263648Sbapt		return;
2261263648Sbapt	}
2262290071Sbapt
2263262395Sbapt	memset (new, 0, sizeof (struct ucl_macro));
2264290071Sbapt	new->h.handler = handler;
2265262395Sbapt	new->name = strdup (macro);
2266262395Sbapt	new->ud = ud;
2267262395Sbapt	HASH_ADD_KEYPTR (hh, parser->macroes, new->name, strlen (new->name), new);
2268262395Sbapt}
2269262395Sbapt
2270262395Sbaptvoid
2271290071Sbaptucl_parser_register_context_macro (struct ucl_parser *parser, const char *macro,
2272290071Sbapt		ucl_context_macro_handler handler, void* ud)
2273290071Sbapt{
2274290071Sbapt	struct ucl_macro *new;
2275290071Sbapt
2276290071Sbapt	if (macro == NULL || handler == NULL) {
2277290071Sbapt		return;
2278290071Sbapt	}
2279290071Sbapt
2280290071Sbapt	new = UCL_ALLOC (sizeof (struct ucl_macro));
2281290071Sbapt	if (new == NULL) {
2282290071Sbapt		return;
2283290071Sbapt	}
2284290071Sbapt
2285290071Sbapt	memset (new, 0, sizeof (struct ucl_macro));
2286290071Sbapt	new->h.context_handler = handler;
2287290071Sbapt	new->name = strdup (macro);
2288290071Sbapt	new->ud = ud;
2289290071Sbapt	new->is_context = true;
2290290071Sbapt	HASH_ADD_KEYPTR (hh, parser->macroes, new->name, strlen (new->name), new);
2291290071Sbapt}
2292290071Sbapt
2293290071Sbaptvoid
2294262395Sbaptucl_parser_register_variable (struct ucl_parser *parser, const char *var,
2295262395Sbapt		const char *value)
2296262395Sbapt{
2297262395Sbapt	struct ucl_variable *new = NULL, *cur;
2298262395Sbapt
2299262395Sbapt	if (var == NULL) {
2300262395Sbapt		return;
2301262395Sbapt	}
2302262395Sbapt
2303262395Sbapt	/* Find whether a variable already exists */
2304262395Sbapt	LL_FOREACH (parser->variables, cur) {
2305262395Sbapt		if (strcmp (cur->var, var) == 0) {
2306262395Sbapt			new = cur;
2307262395Sbapt			break;
2308262395Sbapt		}
2309262395Sbapt	}
2310262395Sbapt
2311262395Sbapt	if (value == NULL) {
2312262395Sbapt
2313262395Sbapt		if (new != NULL) {
2314262395Sbapt			/* Remove variable */
2315275223Sbapt			DL_DELETE (parser->variables, new);
2316262395Sbapt			free (new->var);
2317262395Sbapt			free (new->value);
2318262395Sbapt			UCL_FREE (sizeof (struct ucl_variable), new);
2319262395Sbapt		}
2320262395Sbapt		else {
2321262395Sbapt			/* Do nothing */
2322262395Sbapt			return;
2323262395Sbapt		}
2324262395Sbapt	}
2325262395Sbapt	else {
2326262395Sbapt		if (new == NULL) {
2327262395Sbapt			new = UCL_ALLOC (sizeof (struct ucl_variable));
2328263648Sbapt			if (new == NULL) {
2329263648Sbapt				return;
2330263648Sbapt			}
2331262395Sbapt			memset (new, 0, sizeof (struct ucl_variable));
2332262395Sbapt			new->var = strdup (var);
2333262395Sbapt			new->var_len = strlen (var);
2334262395Sbapt			new->value = strdup (value);
2335262395Sbapt			new->value_len = strlen (value);
2336262395Sbapt
2337275223Sbapt			DL_APPEND (parser->variables, new);
2338262395Sbapt		}
2339262395Sbapt		else {
2340262395Sbapt			free (new->value);
2341262395Sbapt			new->value = strdup (value);
2342262395Sbapt			new->value_len = strlen (value);
2343262395Sbapt		}
2344262395Sbapt	}
2345262395Sbapt}
2346262395Sbapt
2347266636Sbaptvoid
2348266636Sbaptucl_parser_set_variables_handler (struct ucl_parser *parser,
2349266636Sbapt		ucl_variable_handler handler, void *ud)
2350266636Sbapt{
2351266636Sbapt	parser->var_handler = handler;
2352266636Sbapt	parser->var_data = ud;
2353266636Sbapt}
2354266636Sbapt
2355262395Sbaptbool
2356290071Sbaptucl_parser_add_chunk_full (struct ucl_parser *parser, const unsigned char *data,
2357290071Sbapt		size_t len, unsigned priority, enum ucl_duplicate_strategy strat,
2358290071Sbapt		enum ucl_parse_type parse_type)
2359262395Sbapt{
2360262395Sbapt	struct ucl_chunk *chunk;
2361262395Sbapt
2362290071Sbapt	if (parser == NULL) {
2363290071Sbapt		return false;
2364290071Sbapt	}
2365290071Sbapt
2366275223Sbapt	if (data == NULL) {
2367263648Sbapt		ucl_create_err (&parser->err, "invalid chunk added");
2368263648Sbapt		return false;
2369263648Sbapt	}
2370275223Sbapt	if (len == 0) {
2371275223Sbapt		parser->top_obj = ucl_object_new_full (UCL_OBJECT, priority);
2372275223Sbapt		return true;
2373275223Sbapt	}
2374262395Sbapt	if (parser->state != UCL_STATE_ERROR) {
2375262395Sbapt		chunk = UCL_ALLOC (sizeof (struct ucl_chunk));
2376263648Sbapt		if (chunk == NULL) {
2377263648Sbapt			ucl_create_err (&parser->err, "cannot allocate chunk structure");
2378263648Sbapt			return false;
2379263648Sbapt		}
2380262395Sbapt		chunk->begin = data;
2381262395Sbapt		chunk->remain = len;
2382262395Sbapt		chunk->pos = chunk->begin;
2383262395Sbapt		chunk->end = chunk->begin + len;
2384262395Sbapt		chunk->line = 1;
2385262395Sbapt		chunk->column = 0;
2386275223Sbapt		chunk->priority = priority;
2387290071Sbapt		chunk->strategy = strat;
2388290071Sbapt		chunk->parse_type = parse_type;
2389262395Sbapt		LL_PREPEND (parser->chunks, chunk);
2390262395Sbapt		parser->recursion ++;
2391290071Sbapt
2392262395Sbapt		if (parser->recursion > UCL_MAX_RECURSION) {
2393262395Sbapt			ucl_create_err (&parser->err, "maximum include nesting limit is reached: %d",
2394262395Sbapt					parser->recursion);
2395262395Sbapt			return false;
2396262395Sbapt		}
2397290071Sbapt
2398290071Sbapt		switch (parse_type) {
2399290071Sbapt		default:
2400290071Sbapt		case UCL_PARSE_UCL:
2401290071Sbapt			return ucl_state_machine (parser);
2402290071Sbapt		case UCL_PARSE_MSGPACK:
2403290071Sbapt			return ucl_parse_msgpack (parser);
2404290071Sbapt		}
2405262395Sbapt	}
2406262395Sbapt
2407262395Sbapt	ucl_create_err (&parser->err, "a parser is in an invalid state");
2408262395Sbapt
2409262395Sbapt	return false;
2410262395Sbapt}
2411263648Sbapt
2412263648Sbaptbool
2413290071Sbaptucl_parser_add_chunk_priority (struct ucl_parser *parser,
2414290071Sbapt		const unsigned char *data, size_t len, unsigned priority)
2415290071Sbapt{
2416290071Sbapt	/* We dereference parser, so this check is essential */
2417290071Sbapt	if (parser == NULL) {
2418290071Sbapt		return false;
2419290071Sbapt	}
2420290071Sbapt
2421290071Sbapt	return ucl_parser_add_chunk_full (parser, data, len,
2422290071Sbapt				priority, UCL_DUPLICATE_APPEND, UCL_PARSE_UCL);
2423290071Sbapt}
2424290071Sbapt
2425290071Sbaptbool
2426275223Sbaptucl_parser_add_chunk (struct ucl_parser *parser, const unsigned char *data,
2427275223Sbapt		size_t len)
2428275223Sbapt{
2429290071Sbapt	if (parser == NULL) {
2430290071Sbapt		return false;
2431290071Sbapt	}
2432290071Sbapt
2433290071Sbapt	return ucl_parser_add_chunk_full (parser, data, len,
2434290071Sbapt			parser->default_priority, UCL_DUPLICATE_APPEND, UCL_PARSE_UCL);
2435275223Sbapt}
2436275223Sbapt
2437275223Sbaptbool
2438290071Sbaptucl_parser_add_string_priority (struct ucl_parser *parser, const char *data,
2439290071Sbapt		size_t len, unsigned priority)
2440263648Sbapt{
2441263648Sbapt	if (data == NULL) {
2442263648Sbapt		ucl_create_err (&parser->err, "invalid string added");
2443263648Sbapt		return false;
2444263648Sbapt	}
2445263648Sbapt	if (len == 0) {
2446263648Sbapt		len = strlen (data);
2447263648Sbapt	}
2448263648Sbapt
2449290071Sbapt	return ucl_parser_add_chunk_priority (parser,
2450290071Sbapt			(const unsigned char *)data, len, priority);
2451263648Sbapt}
2452290071Sbapt
2453290071Sbaptbool
2454290071Sbaptucl_parser_add_string (struct ucl_parser *parser, const char *data,
2455290071Sbapt		size_t len)
2456290071Sbapt{
2457290071Sbapt	if (parser == NULL) {
2458290071Sbapt		return false;
2459290071Sbapt	}
2460290071Sbapt
2461290071Sbapt	return ucl_parser_add_string_priority (parser,
2462290071Sbapt			(const unsigned char *)data, len, parser->default_priority);
2463290071Sbapt}
2464290071Sbapt
2465290071Sbaptbool
2466290071Sbaptucl_set_include_path (struct ucl_parser *parser, ucl_object_t *paths)
2467290071Sbapt{
2468290071Sbapt	if (parser == NULL || paths == NULL) {
2469290071Sbapt		return false;
2470290071Sbapt	}
2471290071Sbapt
2472290071Sbapt	if (parser->includepaths == NULL) {
2473290071Sbapt		parser->includepaths = ucl_object_copy (paths);
2474290071Sbapt	}
2475290071Sbapt	else {
2476290071Sbapt		ucl_object_unref (parser->includepaths);
2477290071Sbapt		parser->includepaths = ucl_object_copy (paths);
2478290071Sbapt	}
2479290071Sbapt
2480290071Sbapt	if (parser->includepaths == NULL) {
2481290071Sbapt		return false;
2482290071Sbapt	}
2483290071Sbapt
2484290071Sbapt	return true;
2485290071Sbapt}
2486