ucl_parser.c revision 263648
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/**
29262395Sbapt * @file rcl_parser.c
30262395Sbapt * The implementation of rcl 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
58262395Sbapt/**
59262395Sbapt * Save parser state
60262395Sbapt * @param chunk
61262395Sbapt * @param s
62262395Sbapt */
63262395Sbaptstatic inline void
64262395Sbaptucl_chunk_save_state (struct ucl_chunk *chunk, struct ucl_parser_saved_state *s)
65262395Sbapt{
66262395Sbapt	s->column = chunk->column;
67262395Sbapt	s->pos = chunk->pos;
68262395Sbapt	s->line = chunk->line;
69262395Sbapt	s->remain = chunk->remain;
70262395Sbapt}
71262395Sbapt
72262395Sbapt/**
73262395Sbapt * Restore parser state
74262395Sbapt * @param chunk
75262395Sbapt * @param s
76262395Sbapt */
77262395Sbaptstatic inline void
78262395Sbaptucl_chunk_restore_state (struct ucl_chunk *chunk, struct ucl_parser_saved_state *s)
79262395Sbapt{
80262395Sbapt	chunk->column = s->column;
81262395Sbapt	chunk->pos = s->pos;
82262395Sbapt	chunk->line = s->line;
83262395Sbapt	chunk->remain = s->remain;
84262395Sbapt}
85262395Sbapt
86262395Sbaptstatic inline void
87262395Sbaptucl_set_err (struct ucl_chunk *chunk, int code, const char *str, UT_string **err)
88262395Sbapt{
89262395Sbapt	if (chunk->pos < chunk->end) {
90262395Sbapt		if (isgraph (*chunk->pos)) {
91262395Sbapt			ucl_create_err (err, "error on line %d at column %d: '%s', character: '%c'",
92262395Sbapt					chunk->line, chunk->column, str, *chunk->pos);
93262395Sbapt		}
94262395Sbapt		else {
95262395Sbapt			ucl_create_err (err, "error on line %d at column %d: '%s', character: '0x%02x'",
96262395Sbapt					chunk->line, chunk->column, str, (int)*chunk->pos);
97262395Sbapt		}
98262395Sbapt	}
99262395Sbapt	else {
100262395Sbapt		ucl_create_err (err, "error at the end of chunk: %s", str);
101262395Sbapt	}
102262395Sbapt}
103262395Sbapt
104262395Sbapt/**
105262395Sbapt * Skip all comments from the current pos resolving nested and multiline comments
106262395Sbapt * @param parser
107262395Sbapt * @return
108262395Sbapt */
109262395Sbaptstatic bool
110262395Sbaptucl_skip_comments (struct ucl_parser *parser)
111262395Sbapt{
112262395Sbapt	struct ucl_chunk *chunk = parser->chunks;
113262395Sbapt	const unsigned char *p;
114262395Sbapt	int comments_nested = 0;
115262395Sbapt
116262395Sbapt	p = chunk->pos;
117262395Sbapt
118262395Sbaptstart:
119262395Sbapt	if (*p == '#') {
120262395Sbapt		if (parser->state != UCL_STATE_SCOMMENT &&
121262395Sbapt				parser->state != UCL_STATE_MCOMMENT) {
122262395Sbapt			while (p < chunk->end) {
123262395Sbapt				if (*p == '\n') {
124262395Sbapt					ucl_chunk_skipc (chunk, p);
125262395Sbapt					goto start;
126262395Sbapt				}
127262395Sbapt				ucl_chunk_skipc (chunk, p);
128262395Sbapt			}
129262395Sbapt		}
130262395Sbapt	}
131262395Sbapt	else if (*p == '/' && chunk->remain >= 2) {
132262395Sbapt		if (p[1] == '*') {
133262395Sbapt			ucl_chunk_skipc (chunk, p);
134262395Sbapt			comments_nested ++;
135262395Sbapt			ucl_chunk_skipc (chunk, p);
136262395Sbapt
137262395Sbapt			while (p < chunk->end) {
138262395Sbapt				if (*p == '*') {
139262395Sbapt					ucl_chunk_skipc (chunk, p);
140262395Sbapt					if (*p == '/') {
141262395Sbapt						comments_nested --;
142262395Sbapt						if (comments_nested == 0) {
143262395Sbapt							ucl_chunk_skipc (chunk, p);
144262395Sbapt							goto start;
145262395Sbapt						}
146262395Sbapt					}
147262395Sbapt					ucl_chunk_skipc (chunk, p);
148262395Sbapt				}
149262395Sbapt				else if (p[0] == '/' && chunk->remain >= 2 && p[1] == '*') {
150262395Sbapt					comments_nested ++;
151262395Sbapt					ucl_chunk_skipc (chunk, p);
152262395Sbapt					ucl_chunk_skipc (chunk, p);
153262395Sbapt					continue;
154262395Sbapt				}
155262395Sbapt				ucl_chunk_skipc (chunk, p);
156262395Sbapt			}
157262395Sbapt			if (comments_nested != 0) {
158262395Sbapt				ucl_set_err (chunk, UCL_ENESTED, "unfinished multiline comment", &parser->err);
159262395Sbapt				return false;
160262395Sbapt			}
161262395Sbapt		}
162262395Sbapt	}
163262395Sbapt
164262395Sbapt	return true;
165262395Sbapt}
166262395Sbapt
167262395Sbapt/**
168262395Sbapt * Return multiplier for a character
169262395Sbapt * @param c multiplier character
170262395Sbapt * @param is_bytes if true use 1024 multiplier
171262395Sbapt * @return multiplier
172262395Sbapt */
173262395Sbaptstatic inline unsigned long
174262395Sbaptucl_lex_num_multiplier (const unsigned char c, bool is_bytes) {
175262395Sbapt	const struct {
176262395Sbapt		char c;
177262395Sbapt		long mult_normal;
178262395Sbapt		long mult_bytes;
179262395Sbapt	} multipliers[] = {
180262395Sbapt			{'m', 1000 * 1000, 1024 * 1024},
181262395Sbapt			{'k', 1000, 1024},
182262395Sbapt			{'g', 1000 * 1000 * 1000, 1024 * 1024 * 1024}
183262395Sbapt	};
184262395Sbapt	int i;
185262395Sbapt
186262395Sbapt	for (i = 0; i < 3; i ++) {
187262395Sbapt		if (tolower (c) == multipliers[i].c) {
188262395Sbapt			if (is_bytes) {
189262395Sbapt				return multipliers[i].mult_bytes;
190262395Sbapt			}
191262395Sbapt			return multipliers[i].mult_normal;
192262395Sbapt		}
193262395Sbapt	}
194262395Sbapt
195262395Sbapt	return 1;
196262395Sbapt}
197262395Sbapt
198262395Sbapt
199262395Sbapt/**
200262395Sbapt * Return multiplier for time scaling
201262395Sbapt * @param c
202262395Sbapt * @return
203262395Sbapt */
204262395Sbaptstatic inline double
205262395Sbaptucl_lex_time_multiplier (const unsigned char c) {
206262395Sbapt	const struct {
207262395Sbapt		char c;
208262395Sbapt		double mult;
209262395Sbapt	} multipliers[] = {
210262395Sbapt			{'m', 60},
211262395Sbapt			{'h', 60 * 60},
212262395Sbapt			{'d', 60 * 60 * 24},
213262395Sbapt			{'w', 60 * 60 * 24 * 7},
214262395Sbapt			{'y', 60 * 60 * 24 * 7 * 365}
215262395Sbapt	};
216262395Sbapt	int i;
217262395Sbapt
218262395Sbapt	for (i = 0; i < 5; i ++) {
219262395Sbapt		if (tolower (c) == multipliers[i].c) {
220262395Sbapt			return multipliers[i].mult;
221262395Sbapt		}
222262395Sbapt	}
223262395Sbapt
224262395Sbapt	return 1;
225262395Sbapt}
226262395Sbapt
227262395Sbapt/**
228262395Sbapt * Return true if a character is a end of an atom
229262395Sbapt * @param c
230262395Sbapt * @return
231262395Sbapt */
232262395Sbaptstatic inline bool
233262395Sbaptucl_lex_is_atom_end (const unsigned char c)
234262395Sbapt{
235262395Sbapt	return ucl_test_character (c, UCL_CHARACTER_VALUE_END);
236262395Sbapt}
237262395Sbapt
238262395Sbaptstatic inline bool
239262395Sbaptucl_lex_is_comment (const unsigned char c1, const unsigned char c2)
240262395Sbapt{
241262395Sbapt	if (c1 == '/') {
242262395Sbapt		if (c2 == '*') {
243262395Sbapt			return true;
244262395Sbapt		}
245262395Sbapt	}
246262395Sbapt	else if (c1 == '#') {
247262395Sbapt		return true;
248262395Sbapt	}
249262395Sbapt	return false;
250262395Sbapt}
251262395Sbapt
252262395Sbapt/**
253262395Sbapt * Check variable found
254262395Sbapt * @param parser
255262395Sbapt * @param ptr
256262395Sbapt * @param remain
257262395Sbapt * @param out_len
258262395Sbapt * @param strict
259262395Sbapt * @param found
260262395Sbapt * @return
261262395Sbapt */
262262395Sbaptstatic inline const char *
263262395Sbaptucl_check_variable_safe (struct ucl_parser *parser, const char *ptr, size_t remain,
264262395Sbapt		size_t *out_len, bool strict, bool *found)
265262395Sbapt{
266262395Sbapt	struct ucl_variable *var;
267262395Sbapt
268262395Sbapt	LL_FOREACH (parser->variables, var) {
269262395Sbapt		if (strict) {
270262395Sbapt			if (remain == var->var_len) {
271262395Sbapt				if (memcmp (ptr, var->var, var->var_len) == 0) {
272262395Sbapt					*out_len += var->value_len;
273262395Sbapt					*found = true;
274262395Sbapt					return (ptr + var->var_len);
275262395Sbapt				}
276262395Sbapt			}
277262395Sbapt		}
278262395Sbapt		else {
279262395Sbapt			if (remain >= var->var_len) {
280262395Sbapt				if (memcmp (ptr, var->var, var->var_len) == 0) {
281262395Sbapt					*out_len += var->value_len;
282262395Sbapt					*found = true;
283262395Sbapt					return (ptr + var->var_len);
284262395Sbapt				}
285262395Sbapt			}
286262395Sbapt		}
287262395Sbapt	}
288262395Sbapt
289262395Sbapt	return ptr;
290262395Sbapt}
291262395Sbapt
292262395Sbapt/**
293262395Sbapt * Check for a variable in a given string
294262395Sbapt * @param parser
295262395Sbapt * @param ptr
296262395Sbapt * @param remain
297262395Sbapt * @param out_len
298262395Sbapt * @param vars_found
299262395Sbapt * @return
300262395Sbapt */
301262395Sbaptstatic const char *
302262395Sbaptucl_check_variable (struct ucl_parser *parser, const char *ptr, size_t remain, size_t *out_len, bool *vars_found)
303262395Sbapt{
304262395Sbapt	const char *p, *end, *ret = ptr;
305262395Sbapt	bool found = false;
306262395Sbapt
307262395Sbapt	if (*ptr == '{') {
308262395Sbapt		/* We need to match the variable enclosed in braces */
309262395Sbapt		p = ptr + 1;
310262395Sbapt		end = ptr + remain;
311262395Sbapt		while (p < end) {
312262395Sbapt			if (*p == '}') {
313262395Sbapt				ret = ucl_check_variable_safe (parser, ptr + 1, p - ptr - 1, out_len, true, &found);
314262395Sbapt				if (found) {
315262395Sbapt					/* {} must be excluded actually */
316262395Sbapt					ret ++;
317262395Sbapt					if (!*vars_found) {
318262395Sbapt						*vars_found = true;
319262395Sbapt					}
320262395Sbapt				}
321262395Sbapt				else {
322262395Sbapt					*out_len += 2;
323262395Sbapt				}
324262395Sbapt				break;
325262395Sbapt			}
326262395Sbapt			p ++;
327262395Sbapt		}
328262395Sbapt	}
329262395Sbapt	else if (*ptr != '$') {
330262395Sbapt		/* Not count escaped dollar sign */
331262395Sbapt		ret = ucl_check_variable_safe (parser, ptr, remain, out_len, false, &found);
332262395Sbapt		if (found && !*vars_found) {
333262395Sbapt			*vars_found = true;
334262395Sbapt		}
335262395Sbapt		if (!found) {
336262395Sbapt			(*out_len) ++;
337262395Sbapt		}
338262395Sbapt	}
339262395Sbapt	else {
340262395Sbapt		ret ++;
341262395Sbapt		(*out_len) ++;
342262395Sbapt	}
343262395Sbapt
344262395Sbapt	return ret;
345262395Sbapt}
346262395Sbapt
347262395Sbapt/**
348262395Sbapt * Expand a single variable
349262395Sbapt * @param parser
350262395Sbapt * @param ptr
351262395Sbapt * @param remain
352262395Sbapt * @param dest
353262395Sbapt * @return
354262395Sbapt */
355262395Sbaptstatic const char *
356262395Sbaptucl_expand_single_variable (struct ucl_parser *parser, const char *ptr,
357262395Sbapt		size_t remain, unsigned char **dest)
358262395Sbapt{
359262395Sbapt	unsigned char *d = *dest;
360262395Sbapt	const char *p = ptr + 1, *ret;
361262395Sbapt	struct ucl_variable *var;
362262395Sbapt	bool found = false;
363262395Sbapt
364262395Sbapt	ret = ptr + 1;
365262395Sbapt	remain --;
366262395Sbapt
367262395Sbapt	if (*p == '$') {
368262395Sbapt		*d++ = *p++;
369262395Sbapt		*dest = d;
370262395Sbapt		return p;
371262395Sbapt	}
372262395Sbapt	else if (*p == '{') {
373262395Sbapt		p ++;
374262395Sbapt		ret += 2;
375262395Sbapt		remain -= 2;
376262395Sbapt	}
377262395Sbapt
378262395Sbapt	LL_FOREACH (parser->variables, var) {
379262395Sbapt		if (remain >= var->var_len) {
380262395Sbapt			if (memcmp (p, var->var, var->var_len) == 0) {
381262395Sbapt				memcpy (d, var->value, var->value_len);
382262395Sbapt				ret += var->var_len;
383262395Sbapt				d += var->value_len;
384262395Sbapt				found = true;
385262395Sbapt				break;
386262395Sbapt			}
387262395Sbapt		}
388262395Sbapt	}
389262395Sbapt	if (!found) {
390262395Sbapt		memcpy (d, ptr, 2);
391262395Sbapt		d += 2;
392262395Sbapt		ret --;
393262395Sbapt	}
394262395Sbapt
395262395Sbapt	*dest = d;
396262395Sbapt	return ret;
397262395Sbapt}
398262395Sbapt
399262395Sbapt/**
400262395Sbapt * Expand variables in string
401262395Sbapt * @param parser
402262395Sbapt * @param dst
403262395Sbapt * @param src
404262395Sbapt * @param in_len
405262395Sbapt * @return
406262395Sbapt */
407262395Sbaptstatic ssize_t
408262395Sbaptucl_expand_variable (struct ucl_parser *parser, unsigned char **dst,
409262395Sbapt		const char *src, size_t in_len)
410262395Sbapt{
411262395Sbapt	const char *p, *end = src + in_len;
412262395Sbapt	unsigned char *d;
413262395Sbapt	size_t out_len = 0;
414262395Sbapt	bool vars_found = false;
415262395Sbapt
416262395Sbapt	p = src;
417262395Sbapt	while (p != end) {
418262395Sbapt		if (*p == '$') {
419262395Sbapt			p = ucl_check_variable (parser, p + 1, end - p - 1, &out_len, &vars_found);
420262395Sbapt		}
421262395Sbapt		else {
422262395Sbapt			p ++;
423262395Sbapt			out_len ++;
424262395Sbapt		}
425262395Sbapt	}
426262395Sbapt
427262395Sbapt	if (!vars_found) {
428262395Sbapt		/* Trivial case */
429262395Sbapt		*dst = NULL;
430262395Sbapt		return in_len;
431262395Sbapt	}
432262395Sbapt
433262395Sbapt	*dst = UCL_ALLOC (out_len + 1);
434262395Sbapt	if (*dst == NULL) {
435262395Sbapt		return in_len;
436262395Sbapt	}
437262395Sbapt
438262395Sbapt	d = *dst;
439262395Sbapt	p = src;
440262395Sbapt	while (p != end) {
441262395Sbapt		if (*p == '$') {
442262395Sbapt			p = ucl_expand_single_variable (parser, p, end - p, &d);
443262395Sbapt		}
444262395Sbapt		else {
445262395Sbapt			*d++ = *p++;
446262395Sbapt		}
447262395Sbapt	}
448262395Sbapt
449262395Sbapt	*d = '\0';
450262395Sbapt
451262395Sbapt	return out_len;
452262395Sbapt}
453262395Sbapt
454262395Sbapt/**
455262395Sbapt * Store or copy pointer to the trash stack
456262395Sbapt * @param parser parser object
457262395Sbapt * @param src src string
458262395Sbapt * @param dst destination buffer (trash stack pointer)
459262395Sbapt * @param dst_const const destination pointer (e.g. value of object)
460262395Sbapt * @param in_len input length
461262395Sbapt * @param need_unescape need to unescape source (and copy it)
462262395Sbapt * @param need_lowercase need to lowercase value (and copy)
463262395Sbapt * @param need_expand need to expand variables (and copy as well)
464262395Sbapt * @return output length (excluding \0 symbol)
465262395Sbapt */
466262395Sbaptstatic inline ssize_t
467262395Sbaptucl_copy_or_store_ptr (struct ucl_parser *parser,
468262395Sbapt		const unsigned char *src, unsigned char **dst,
469262395Sbapt		const char **dst_const, size_t in_len,
470262395Sbapt		bool need_unescape, bool need_lowercase, bool need_expand)
471262395Sbapt{
472262395Sbapt	ssize_t ret = -1, tret;
473262395Sbapt	unsigned char *tmp;
474262395Sbapt
475262395Sbapt	if (need_unescape || need_lowercase ||
476262395Sbapt			(need_expand && parser->variables != NULL) ||
477262395Sbapt			!(parser->flags & UCL_PARSER_ZEROCOPY)) {
478262395Sbapt		/* Copy string */
479262395Sbapt		*dst = UCL_ALLOC (in_len + 1);
480262395Sbapt		if (*dst == NULL) {
481262395Sbapt			ucl_set_err (parser->chunks, 0, "cannot allocate memory for a string", &parser->err);
482262395Sbapt			return false;
483262395Sbapt		}
484262395Sbapt		if (need_lowercase) {
485262395Sbapt			ret = ucl_strlcpy_tolower (*dst, src, in_len + 1);
486262395Sbapt		}
487262395Sbapt		else {
488262395Sbapt			ret = ucl_strlcpy_unsafe (*dst, src, in_len + 1);
489262395Sbapt		}
490262395Sbapt
491262395Sbapt		if (need_unescape) {
492262395Sbapt			ret = ucl_unescape_json_string (*dst, ret);
493262395Sbapt		}
494262395Sbapt		if (need_expand) {
495262395Sbapt			tmp = *dst;
496262395Sbapt			tret = ret;
497262395Sbapt			ret = ucl_expand_variable (parser, dst, tmp, ret);
498262395Sbapt			if (*dst == NULL) {
499262395Sbapt				/* Nothing to expand */
500262395Sbapt				*dst = tmp;
501262395Sbapt				ret = tret;
502262395Sbapt			}
503262395Sbapt		}
504262395Sbapt		*dst_const = *dst;
505262395Sbapt	}
506262395Sbapt	else {
507262395Sbapt		*dst_const = src;
508262395Sbapt		ret = in_len;
509262395Sbapt	}
510262395Sbapt
511262395Sbapt	return ret;
512262395Sbapt}
513262395Sbapt
514262395Sbapt/**
515262395Sbapt * Create and append an object at the specified level
516262395Sbapt * @param parser
517262395Sbapt * @param is_array
518262395Sbapt * @param level
519262395Sbapt * @return
520262395Sbapt */
521262395Sbaptstatic inline ucl_object_t *
522262395Sbaptucl_add_parser_stack (ucl_object_t *obj, struct ucl_parser *parser, bool is_array, int level)
523262395Sbapt{
524262395Sbapt	struct ucl_stack *st;
525262395Sbapt
526262395Sbapt	if (!is_array) {
527262395Sbapt		if (obj == NULL) {
528262395Sbapt			obj = ucl_object_typed_new (UCL_OBJECT);
529262395Sbapt		}
530262395Sbapt		else {
531262395Sbapt			obj->type = UCL_OBJECT;
532262395Sbapt		}
533262395Sbapt		obj->value.ov = ucl_hash_create ();
534262395Sbapt		parser->state = UCL_STATE_KEY;
535262395Sbapt	}
536262395Sbapt	else {
537262395Sbapt		if (obj == NULL) {
538262395Sbapt			obj = ucl_object_typed_new (UCL_ARRAY);
539262395Sbapt		}
540262395Sbapt		else {
541262395Sbapt			obj->type = UCL_ARRAY;
542262395Sbapt		}
543262395Sbapt		parser->state = UCL_STATE_VALUE;
544262395Sbapt	}
545262395Sbapt
546262395Sbapt	st = UCL_ALLOC (sizeof (struct ucl_stack));
547263648Sbapt	if (st == NULL) {
548263648Sbapt		ucl_set_err (parser->chunks, 0, "cannot allocate memory for an object", &parser->err);
549263648Sbapt		return NULL;
550263648Sbapt	}
551262395Sbapt	st->obj = obj;
552262395Sbapt	st->level = level;
553262395Sbapt	LL_PREPEND (parser->stack, st);
554262395Sbapt	parser->cur_obj = obj;
555262395Sbapt
556262395Sbapt	return obj;
557262395Sbapt}
558262395Sbapt
559262395Sbaptint
560262395Sbaptucl_maybe_parse_number (ucl_object_t *obj,
561263648Sbapt		const char *start, const char *end, const char **pos,
562263648Sbapt		bool allow_double, bool number_bytes, bool allow_time)
563262395Sbapt{
564262395Sbapt	const char *p = start, *c = start;
565262395Sbapt	char *endptr;
566262395Sbapt	bool got_dot = false, got_exp = false, need_double = false,
567263648Sbapt			is_time = false, valid_start = false, is_hex = false,
568262395Sbapt			is_neg = false;
569262395Sbapt	double dv = 0;
570262395Sbapt	int64_t lv = 0;
571262395Sbapt
572262395Sbapt	if (*p == '-') {
573262395Sbapt		is_neg = true;
574262395Sbapt		c ++;
575262395Sbapt		p ++;
576262395Sbapt	}
577262395Sbapt	while (p < end) {
578262395Sbapt		if (is_hex && isxdigit (*p)) {
579262395Sbapt			p ++;
580262395Sbapt		}
581262395Sbapt		else if (isdigit (*p)) {
582262395Sbapt			valid_start = true;
583262395Sbapt			p ++;
584262395Sbapt		}
585262395Sbapt		else if (!is_hex && (*p == 'x' || *p == 'X')) {
586262395Sbapt			is_hex = true;
587262395Sbapt			allow_double = false;
588262395Sbapt			c = p + 1;
589262395Sbapt		}
590262395Sbapt		else if (allow_double) {
591262395Sbapt			if (p == c) {
592262395Sbapt				/* Empty digits sequence, not a number */
593262395Sbapt				*pos = start;
594262395Sbapt				return EINVAL;
595262395Sbapt			}
596262395Sbapt			else if (*p == '.') {
597262395Sbapt				if (got_dot) {
598262395Sbapt					/* Double dots, not a number */
599262395Sbapt					*pos = start;
600262395Sbapt					return EINVAL;
601262395Sbapt				}
602262395Sbapt				else {
603262395Sbapt					got_dot = true;
604262395Sbapt					need_double = true;
605262395Sbapt					p ++;
606262395Sbapt				}
607262395Sbapt			}
608262395Sbapt			else if (*p == 'e' || *p == 'E') {
609262395Sbapt				if (got_exp) {
610262395Sbapt					/* Double exp, not a number */
611262395Sbapt					*pos = start;
612262395Sbapt					return EINVAL;
613262395Sbapt				}
614262395Sbapt				else {
615262395Sbapt					got_exp = true;
616262395Sbapt					need_double = true;
617262395Sbapt					p ++;
618262395Sbapt					if (p >= end) {
619262395Sbapt						*pos = start;
620262395Sbapt						return EINVAL;
621262395Sbapt					}
622262395Sbapt					if (!isdigit (*p) && *p != '+' && *p != '-') {
623262395Sbapt						/* Wrong exponent sign */
624262395Sbapt						*pos = start;
625262395Sbapt						return EINVAL;
626262395Sbapt					}
627262395Sbapt					else {
628262395Sbapt						p ++;
629262395Sbapt					}
630262395Sbapt				}
631262395Sbapt			}
632262395Sbapt			else {
633262395Sbapt				/* Got the end of the number, need to check */
634262395Sbapt				break;
635262395Sbapt			}
636262395Sbapt		}
637262395Sbapt		else {
638262395Sbapt			break;
639262395Sbapt		}
640262395Sbapt	}
641262395Sbapt
642262395Sbapt	if (!valid_start) {
643262395Sbapt		*pos = start;
644262395Sbapt		return EINVAL;
645262395Sbapt	}
646262395Sbapt
647262395Sbapt	errno = 0;
648262395Sbapt	if (need_double) {
649262395Sbapt		dv = strtod (c, &endptr);
650262395Sbapt	}
651262395Sbapt	else {
652262395Sbapt		if (is_hex) {
653262395Sbapt			lv = strtoimax (c, &endptr, 16);
654262395Sbapt		}
655262395Sbapt		else {
656262395Sbapt			lv = strtoimax (c, &endptr, 10);
657262395Sbapt		}
658262395Sbapt	}
659262395Sbapt	if (errno == ERANGE) {
660262395Sbapt		*pos = start;
661262395Sbapt		return ERANGE;
662262395Sbapt	}
663262395Sbapt
664262395Sbapt	/* Now check endptr */
665263648Sbapt	if (endptr == NULL || ucl_lex_is_atom_end (*endptr) || *endptr == '\0' ||
666263648Sbapt			ucl_test_character (*endptr, UCL_CHARACTER_WHITESPACE_UNSAFE)) {
667262395Sbapt		p = endptr;
668262395Sbapt		goto set_obj;
669262395Sbapt	}
670262395Sbapt
671262395Sbapt	if (endptr < end && endptr != start) {
672262395Sbapt		p = endptr;
673262395Sbapt		switch (*p) {
674262395Sbapt		case 'm':
675262395Sbapt		case 'M':
676262395Sbapt		case 'g':
677262395Sbapt		case 'G':
678262395Sbapt		case 'k':
679262395Sbapt		case 'K':
680262395Sbapt			if (end - p >= 2) {
681262395Sbapt				if (p[1] == 's' || p[1] == 'S') {
682262395Sbapt					/* Milliseconds */
683262395Sbapt					if (!need_double) {
684262395Sbapt						need_double = true;
685262395Sbapt						dv = lv;
686262395Sbapt					}
687263648Sbapt					is_time = true;
688262395Sbapt					if (p[0] == 'm' || p[0] == 'M') {
689262395Sbapt						dv /= 1000.;
690262395Sbapt					}
691262395Sbapt					else {
692262395Sbapt						dv *= ucl_lex_num_multiplier (*p, false);
693262395Sbapt					}
694262395Sbapt					p += 2;
695262395Sbapt					goto set_obj;
696262395Sbapt				}
697262395Sbapt				else if (number_bytes || (p[1] == 'b' || p[1] == 'B')) {
698262395Sbapt					/* Bytes */
699262395Sbapt					if (need_double) {
700262395Sbapt						need_double = false;
701262395Sbapt						lv = dv;
702262395Sbapt					}
703262395Sbapt					lv *= ucl_lex_num_multiplier (*p, true);
704262395Sbapt					p += 2;
705262395Sbapt					goto set_obj;
706262395Sbapt				}
707262395Sbapt				else if (ucl_lex_is_atom_end (p[1])) {
708262395Sbapt					if (need_double) {
709262395Sbapt						dv *= ucl_lex_num_multiplier (*p, false);
710262395Sbapt					}
711262395Sbapt					else {
712262395Sbapt						lv *= ucl_lex_num_multiplier (*p, number_bytes);
713262395Sbapt					}
714262395Sbapt					p ++;
715262395Sbapt					goto set_obj;
716262395Sbapt				}
717263648Sbapt				else if (allow_time && end - p >= 3) {
718262395Sbapt					if (tolower (p[0]) == 'm' &&
719262395Sbapt							tolower (p[1]) == 'i' &&
720262395Sbapt							tolower (p[2]) == 'n') {
721262395Sbapt						/* Minutes */
722262395Sbapt						if (!need_double) {
723262395Sbapt							need_double = true;
724262395Sbapt							dv = lv;
725262395Sbapt						}
726263648Sbapt						is_time = true;
727262395Sbapt						dv *= 60.;
728262395Sbapt						p += 3;
729262395Sbapt						goto set_obj;
730262395Sbapt					}
731262395Sbapt				}
732262395Sbapt			}
733262395Sbapt			else {
734262395Sbapt				if (need_double) {
735262395Sbapt					dv *= ucl_lex_num_multiplier (*p, false);
736262395Sbapt				}
737262395Sbapt				else {
738262395Sbapt					lv *= ucl_lex_num_multiplier (*p, number_bytes);
739262395Sbapt				}
740262395Sbapt				p ++;
741262395Sbapt				goto set_obj;
742262395Sbapt			}
743262395Sbapt			break;
744262395Sbapt		case 'S':
745262395Sbapt		case 's':
746263648Sbapt			if (allow_time &&
747263648Sbapt					(p == end - 1 || ucl_lex_is_atom_end (p[1]))) {
748262395Sbapt				if (!need_double) {
749262395Sbapt					need_double = true;
750262395Sbapt					dv = lv;
751262395Sbapt				}
752262395Sbapt				p ++;
753263648Sbapt				is_time = true;
754262395Sbapt				goto set_obj;
755262395Sbapt			}
756262395Sbapt			break;
757262395Sbapt		case 'h':
758262395Sbapt		case 'H':
759262395Sbapt		case 'd':
760262395Sbapt		case 'D':
761262395Sbapt		case 'w':
762262395Sbapt		case 'W':
763262395Sbapt		case 'Y':
764262395Sbapt		case 'y':
765263648Sbapt			if (allow_time &&
766263648Sbapt					(p == end - 1 || ucl_lex_is_atom_end (p[1]))) {
767262395Sbapt				if (!need_double) {
768262395Sbapt					need_double = true;
769262395Sbapt					dv = lv;
770262395Sbapt				}
771263648Sbapt				is_time = true;
772262395Sbapt				dv *= ucl_lex_time_multiplier (*p);
773262395Sbapt				p ++;
774262395Sbapt				goto set_obj;
775262395Sbapt			}
776262395Sbapt			break;
777262395Sbapt		}
778262395Sbapt	}
779262395Sbapt
780262395Sbapt	*pos = c;
781262395Sbapt	return EINVAL;
782262395Sbapt
783262395Sbapt	set_obj:
784263648Sbapt	if (allow_double && (need_double || is_time)) {
785263648Sbapt		if (!is_time) {
786262395Sbapt			obj->type = UCL_FLOAT;
787262395Sbapt		}
788262395Sbapt		else {
789262395Sbapt			obj->type = UCL_TIME;
790262395Sbapt		}
791262395Sbapt		obj->value.dv = is_neg ? (-dv) : dv;
792262395Sbapt	}
793262395Sbapt	else {
794262395Sbapt		obj->type = UCL_INT;
795262395Sbapt		obj->value.iv = is_neg ? (-lv) : lv;
796262395Sbapt	}
797262395Sbapt	*pos = p;
798262395Sbapt	return 0;
799262395Sbapt}
800262395Sbapt
801262395Sbapt/**
802262395Sbapt * Parse possible number
803262395Sbapt * @param parser
804262395Sbapt * @param chunk
805262395Sbapt * @return true if a number has been parsed
806262395Sbapt */
807262395Sbaptstatic bool
808262395Sbaptucl_lex_number (struct ucl_parser *parser,
809262395Sbapt		struct ucl_chunk *chunk, ucl_object_t *obj)
810262395Sbapt{
811262395Sbapt	const unsigned char *pos;
812262395Sbapt	int ret;
813262395Sbapt
814263648Sbapt	ret = ucl_maybe_parse_number (obj, chunk->pos, chunk->end, (const char **)&pos,
815263648Sbapt			true, false, ((parser->flags & UCL_PARSER_NO_TIME) == 0));
816262395Sbapt
817262395Sbapt	if (ret == 0) {
818262395Sbapt		chunk->remain -= pos - chunk->pos;
819262395Sbapt		chunk->column += pos - chunk->pos;
820262395Sbapt		chunk->pos = pos;
821262395Sbapt		return true;
822262395Sbapt	}
823262395Sbapt	else if (ret == ERANGE) {
824262395Sbapt		ucl_set_err (chunk, ERANGE, "numeric value out of range", &parser->err);
825262395Sbapt	}
826262395Sbapt
827262395Sbapt	return false;
828262395Sbapt}
829262395Sbapt
830262395Sbapt/**
831262395Sbapt * Parse quoted string with possible escapes
832262395Sbapt * @param parser
833262395Sbapt * @param chunk
834262395Sbapt * @return true if a string has been parsed
835262395Sbapt */
836262395Sbaptstatic bool
837262395Sbaptucl_lex_json_string (struct ucl_parser *parser,
838262395Sbapt		struct ucl_chunk *chunk, bool *need_unescape, bool *ucl_escape, bool *var_expand)
839262395Sbapt{
840262395Sbapt	const unsigned char *p = chunk->pos;
841262395Sbapt	unsigned char c;
842262395Sbapt	int i;
843262395Sbapt
844262395Sbapt	while (p < chunk->end) {
845262395Sbapt		c = *p;
846262395Sbapt		if (c < 0x1F) {
847262395Sbapt			/* Unmasked control character */
848262395Sbapt			if (c == '\n') {
849262395Sbapt				ucl_set_err (chunk, UCL_ESYNTAX, "unexpected newline", &parser->err);
850262395Sbapt			}
851262395Sbapt			else {
852262395Sbapt				ucl_set_err (chunk, UCL_ESYNTAX, "unexpected control character", &parser->err);
853262395Sbapt			}
854262395Sbapt			return false;
855262395Sbapt		}
856262395Sbapt		else if (c == '\\') {
857262395Sbapt			ucl_chunk_skipc (chunk, p);
858262395Sbapt			c = *p;
859262395Sbapt			if (p >= chunk->end) {
860262395Sbapt				ucl_set_err (chunk, UCL_ESYNTAX, "unfinished escape character", &parser->err);
861262395Sbapt				return false;
862262395Sbapt			}
863262395Sbapt			else if (ucl_test_character (c, UCL_CHARACTER_ESCAPE)) {
864262395Sbapt				if (c == 'u') {
865262395Sbapt					ucl_chunk_skipc (chunk, p);
866262395Sbapt					for (i = 0; i < 4 && p < chunk->end; i ++) {
867262395Sbapt						if (!isxdigit (*p)) {
868262395Sbapt							ucl_set_err (chunk, UCL_ESYNTAX, "invalid utf escape", &parser->err);
869262395Sbapt							return false;
870262395Sbapt						}
871262395Sbapt						ucl_chunk_skipc (chunk, p);
872262395Sbapt					}
873262395Sbapt					if (p >= chunk->end) {
874262395Sbapt						ucl_set_err (chunk, UCL_ESYNTAX, "unfinished escape character", &parser->err);
875262395Sbapt						return false;
876262395Sbapt					}
877262395Sbapt				}
878262395Sbapt				else {
879262395Sbapt					ucl_chunk_skipc (chunk, p);
880262395Sbapt				}
881262395Sbapt			}
882262395Sbapt			*need_unescape = true;
883262395Sbapt			*ucl_escape = true;
884262395Sbapt			continue;
885262395Sbapt		}
886262395Sbapt		else if (c == '"') {
887262395Sbapt			ucl_chunk_skipc (chunk, p);
888262395Sbapt			return true;
889262395Sbapt		}
890262395Sbapt		else if (ucl_test_character (c, UCL_CHARACTER_UCL_UNSAFE)) {
891262395Sbapt			*ucl_escape = true;
892262395Sbapt		}
893262395Sbapt		else if (c == '$') {
894262395Sbapt			*var_expand = true;
895262395Sbapt		}
896262395Sbapt		ucl_chunk_skipc (chunk, p);
897262395Sbapt	}
898262395Sbapt
899262395Sbapt	ucl_set_err (chunk, UCL_ESYNTAX, "no quote at the end of json string", &parser->err);
900262395Sbapt	return false;
901262395Sbapt}
902262395Sbapt
903262395Sbapt/**
904262395Sbapt * Parse a key in an object
905262395Sbapt * @param parser
906262395Sbapt * @param chunk
907262395Sbapt * @return true if a key has been parsed
908262395Sbapt */
909262395Sbaptstatic bool
910262395Sbaptucl_parse_key (struct ucl_parser *parser, struct ucl_chunk *chunk, bool *next_key, bool *end_of_object)
911262395Sbapt{
912262395Sbapt	const unsigned char *p, *c = NULL, *end, *t;
913262395Sbapt	const char *key = NULL;
914262395Sbapt	bool got_quote = false, got_eq = false, got_semicolon = false,
915262395Sbapt			need_unescape = false, ucl_escape = false, var_expand = false,
916262395Sbapt			got_content = false, got_sep = false;
917262395Sbapt	ucl_object_t *nobj, *tobj;
918262395Sbapt	ucl_hash_t *container;
919262395Sbapt	ssize_t keylen;
920262395Sbapt
921262395Sbapt	p = chunk->pos;
922262395Sbapt
923262395Sbapt	if (*p == '.') {
924262395Sbapt		/* It is macro actually */
925262395Sbapt		ucl_chunk_skipc (chunk, p);
926262395Sbapt		parser->prev_state = parser->state;
927262395Sbapt		parser->state = UCL_STATE_MACRO_NAME;
928262395Sbapt		return true;
929262395Sbapt	}
930262395Sbapt	while (p < chunk->end) {
931262395Sbapt		/*
932262395Sbapt		 * A key must start with alpha, number, '/' or '_' and end with space character
933262395Sbapt		 */
934262395Sbapt		if (c == NULL) {
935262395Sbapt			if (chunk->remain >= 2 && ucl_lex_is_comment (p[0], p[1])) {
936262395Sbapt				if (!ucl_skip_comments (parser)) {
937262395Sbapt					return false;
938262395Sbapt				}
939262395Sbapt				p = chunk->pos;
940262395Sbapt			}
941262395Sbapt			else if (ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE)) {
942262395Sbapt				ucl_chunk_skipc (chunk, p);
943262395Sbapt			}
944262395Sbapt			else if (ucl_test_character (*p, UCL_CHARACTER_KEY_START)) {
945262395Sbapt				/* The first symbol */
946262395Sbapt				c = p;
947262395Sbapt				ucl_chunk_skipc (chunk, p);
948262395Sbapt				got_content = true;
949262395Sbapt			}
950262395Sbapt			else if (*p == '"') {
951262395Sbapt				/* JSON style key */
952262395Sbapt				c = p + 1;
953262395Sbapt				got_quote = true;
954262395Sbapt				got_content = true;
955262395Sbapt				ucl_chunk_skipc (chunk, p);
956262395Sbapt			}
957262395Sbapt			else if (*p == '}') {
958262395Sbapt				/* We have actually end of an object */
959262395Sbapt				*end_of_object = true;
960262395Sbapt				return true;
961262395Sbapt			}
962262395Sbapt			else if (*p == '.') {
963262395Sbapt				ucl_chunk_skipc (chunk, p);
964262395Sbapt				parser->prev_state = parser->state;
965262395Sbapt				parser->state = UCL_STATE_MACRO_NAME;
966262395Sbapt				return true;
967262395Sbapt			}
968262395Sbapt			else {
969262395Sbapt				/* Invalid identifier */
970262395Sbapt				ucl_set_err (chunk, UCL_ESYNTAX, "key must begin with a letter", &parser->err);
971262395Sbapt				return false;
972262395Sbapt			}
973262395Sbapt		}
974262395Sbapt		else {
975262395Sbapt			/* Parse the body of a key */
976262395Sbapt			if (!got_quote) {
977262395Sbapt				if (ucl_test_character (*p, UCL_CHARACTER_KEY)) {
978262395Sbapt					got_content = true;
979262395Sbapt					ucl_chunk_skipc (chunk, p);
980262395Sbapt				}
981262395Sbapt				else if (ucl_test_character (*p, UCL_CHARACTER_KEY_SEP)) {
982262395Sbapt					end = p;
983262395Sbapt					break;
984262395Sbapt				}
985262395Sbapt				else {
986262395Sbapt					ucl_set_err (chunk, UCL_ESYNTAX, "invalid character in a key", &parser->err);
987262395Sbapt					return false;
988262395Sbapt				}
989262395Sbapt			}
990262395Sbapt			else {
991262395Sbapt				/* We need to parse json like quoted string */
992262395Sbapt				if (!ucl_lex_json_string (parser, chunk, &need_unescape, &ucl_escape, &var_expand)) {
993262395Sbapt					return false;
994262395Sbapt				}
995262395Sbapt				/* Always escape keys obtained via json */
996262395Sbapt				end = chunk->pos - 1;
997262395Sbapt				p = chunk->pos;
998262395Sbapt				break;
999262395Sbapt			}
1000262395Sbapt		}
1001262395Sbapt	}
1002262395Sbapt
1003262395Sbapt	if (p >= chunk->end && got_content) {
1004262395Sbapt		ucl_set_err (chunk, UCL_ESYNTAX, "unfinished key", &parser->err);
1005262395Sbapt		return false;
1006262395Sbapt	}
1007262395Sbapt	else if (!got_content) {
1008262395Sbapt		return true;
1009262395Sbapt	}
1010262395Sbapt	*end_of_object = false;
1011262395Sbapt	/* We are now at the end of the key, need to parse the rest */
1012262395Sbapt	while (p < chunk->end) {
1013262395Sbapt		if (ucl_test_character (*p, UCL_CHARACTER_WHITESPACE)) {
1014262395Sbapt			ucl_chunk_skipc (chunk, p);
1015262395Sbapt		}
1016262395Sbapt		else if (*p == '=') {
1017262395Sbapt			if (!got_eq && !got_semicolon) {
1018262395Sbapt				ucl_chunk_skipc (chunk, p);
1019262395Sbapt				got_eq = true;
1020262395Sbapt			}
1021262395Sbapt			else {
1022262395Sbapt				ucl_set_err (chunk, UCL_ESYNTAX, "unexpected '=' character", &parser->err);
1023262395Sbapt				return false;
1024262395Sbapt			}
1025262395Sbapt		}
1026262395Sbapt		else if (*p == ':') {
1027262395Sbapt			if (!got_eq && !got_semicolon) {
1028262395Sbapt				ucl_chunk_skipc (chunk, p);
1029262395Sbapt				got_semicolon = true;
1030262395Sbapt			}
1031262395Sbapt			else {
1032262395Sbapt				ucl_set_err (chunk, UCL_ESYNTAX, "unexpected ':' character", &parser->err);
1033262395Sbapt				return false;
1034262395Sbapt			}
1035262395Sbapt		}
1036262395Sbapt		else if (chunk->remain >= 2 && ucl_lex_is_comment (p[0], p[1])) {
1037262395Sbapt			/* Check for comment */
1038262395Sbapt			if (!ucl_skip_comments (parser)) {
1039262395Sbapt				return false;
1040262395Sbapt			}
1041262395Sbapt			p = chunk->pos;
1042262395Sbapt		}
1043262395Sbapt		else {
1044262395Sbapt			/* Start value */
1045262395Sbapt			break;
1046262395Sbapt		}
1047262395Sbapt	}
1048262395Sbapt
1049262395Sbapt	if (p >= chunk->end && got_content) {
1050262395Sbapt		ucl_set_err (chunk, UCL_ESYNTAX, "unfinished key", &parser->err);
1051262395Sbapt		return false;
1052262395Sbapt	}
1053262395Sbapt
1054262395Sbapt	got_sep = got_semicolon || got_eq;
1055262395Sbapt
1056262395Sbapt	if (!got_sep) {
1057262395Sbapt		/*
1058262395Sbapt		 * Maybe we have more keys nested, so search for termination character.
1059262395Sbapt		 * Possible choices:
1060262395Sbapt		 * 1) key1 key2 ... keyN [:=] value <- we treat that as error
1061262395Sbapt		 * 2) key1 ... keyN {} or [] <- we treat that as nested objects
1062262395Sbapt		 * 3) key1 value[;,\n] <- we treat that as linear object
1063262395Sbapt		 */
1064262395Sbapt		t = p;
1065262395Sbapt		*next_key = false;
1066262395Sbapt		while (ucl_test_character (*t, UCL_CHARACTER_WHITESPACE)) {
1067262395Sbapt			t ++;
1068262395Sbapt		}
1069262395Sbapt		/* Check first non-space character after a key */
1070262395Sbapt		if (*t != '{' && *t != '[') {
1071262395Sbapt			while (t < chunk->end) {
1072262395Sbapt				if (*t == ',' || *t == ';' || *t == '\n' || *t == '\r') {
1073262395Sbapt					break;
1074262395Sbapt				}
1075262395Sbapt				else if (*t == '{' || *t == '[') {
1076262395Sbapt					*next_key = true;
1077262395Sbapt					break;
1078262395Sbapt				}
1079262395Sbapt				t ++;
1080262395Sbapt			}
1081262395Sbapt		}
1082262395Sbapt	}
1083262395Sbapt
1084262395Sbapt	/* Create a new object */
1085262395Sbapt	nobj = ucl_object_new ();
1086262395Sbapt	keylen = ucl_copy_or_store_ptr (parser, c, &nobj->trash_stack[UCL_TRASH_KEY],
1087262395Sbapt			&key, end - c, need_unescape, parser->flags & UCL_PARSER_KEY_LOWERCASE, false);
1088262395Sbapt	if (keylen == -1) {
1089262395Sbapt		ucl_object_free(nobj);
1090262395Sbapt		return false;
1091262395Sbapt	}
1092262395Sbapt	else if (keylen == 0) {
1093262395Sbapt		ucl_set_err (chunk, UCL_ESYNTAX, "empty keys are not allowed", &parser->err);
1094262395Sbapt		ucl_object_free(nobj);
1095262395Sbapt		return false;
1096262395Sbapt	}
1097262395Sbapt
1098262395Sbapt	container = parser->stack->obj->value.ov;
1099262395Sbapt	nobj->key = key;
1100262395Sbapt	nobj->keylen = keylen;
1101262395Sbapt	tobj = ucl_hash_search_obj (container, nobj);
1102262395Sbapt	if (tobj == NULL) {
1103262395Sbapt		container = ucl_hash_insert_object (container, nobj);
1104262395Sbapt		nobj->prev = nobj;
1105262395Sbapt		nobj->next = NULL;
1106262395Sbapt		parser->stack->obj->len ++;
1107262395Sbapt	}
1108262395Sbapt	else {
1109262395Sbapt		DL_APPEND (tobj, nobj);
1110262395Sbapt	}
1111262395Sbapt
1112262395Sbapt	if (ucl_escape) {
1113262395Sbapt		nobj->flags |= UCL_OBJECT_NEED_KEY_ESCAPE;
1114262395Sbapt	}
1115262395Sbapt	parser->stack->obj->value.ov = container;
1116262395Sbapt
1117262395Sbapt	parser->cur_obj = nobj;
1118262395Sbapt
1119262395Sbapt	return true;
1120262395Sbapt}
1121262395Sbapt
1122262395Sbapt/**
1123262395Sbapt * Parse a cl string
1124262395Sbapt * @param parser
1125262395Sbapt * @param chunk
1126262395Sbapt * @return true if a key has been parsed
1127262395Sbapt */
1128262395Sbaptstatic bool
1129262395Sbaptucl_parse_string_value (struct ucl_parser *parser,
1130262395Sbapt		struct ucl_chunk *chunk, bool *var_expand, bool *need_unescape)
1131262395Sbapt{
1132262395Sbapt	const unsigned char *p;
1133262395Sbapt	enum {
1134262395Sbapt		UCL_BRACE_ROUND = 0,
1135262395Sbapt		UCL_BRACE_SQUARE,
1136262395Sbapt		UCL_BRACE_FIGURE
1137262395Sbapt	};
1138262395Sbapt	int braces[3][2] = {{0, 0}, {0, 0}, {0, 0}};
1139262395Sbapt
1140262395Sbapt	p = chunk->pos;
1141262395Sbapt
1142262395Sbapt	while (p < chunk->end) {
1143262395Sbapt
1144262395Sbapt		/* Skip pairs of figure braces */
1145262395Sbapt		if (*p == '{') {
1146262395Sbapt			braces[UCL_BRACE_FIGURE][0] ++;
1147262395Sbapt		}
1148262395Sbapt		else if (*p == '}') {
1149262395Sbapt			braces[UCL_BRACE_FIGURE][1] ++;
1150262395Sbapt			if (braces[UCL_BRACE_FIGURE][1] <= braces[UCL_BRACE_FIGURE][0]) {
1151262395Sbapt				/* This is not a termination symbol, continue */
1152262395Sbapt				ucl_chunk_skipc (chunk, p);
1153262395Sbapt				continue;
1154262395Sbapt			}
1155262395Sbapt		}
1156262395Sbapt		/* Skip pairs of square braces */
1157262395Sbapt		else if (*p == '[') {
1158262395Sbapt			braces[UCL_BRACE_SQUARE][0] ++;
1159262395Sbapt		}
1160262395Sbapt		else if (*p == ']') {
1161262395Sbapt			braces[UCL_BRACE_SQUARE][1] ++;
1162262395Sbapt			if (braces[UCL_BRACE_SQUARE][1] <= braces[UCL_BRACE_SQUARE][0]) {
1163262395Sbapt				/* This is not a termination symbol, continue */
1164262395Sbapt				ucl_chunk_skipc (chunk, p);
1165262395Sbapt				continue;
1166262395Sbapt			}
1167262395Sbapt		}
1168262395Sbapt		else if (*p == '$') {
1169262395Sbapt			*var_expand = true;
1170262395Sbapt		}
1171262395Sbapt		else if (*p == '\\') {
1172262395Sbapt			*need_unescape = true;
1173262395Sbapt			ucl_chunk_skipc (chunk, p);
1174262395Sbapt			if (p < chunk->end) {
1175262395Sbapt				ucl_chunk_skipc (chunk, p);
1176262395Sbapt			}
1177262395Sbapt			continue;
1178262395Sbapt		}
1179262395Sbapt
1180262395Sbapt		if (ucl_lex_is_atom_end (*p) || (chunk->remain >= 2 && ucl_lex_is_comment (p[0], p[1]))) {
1181262395Sbapt			break;
1182262395Sbapt		}
1183262395Sbapt		ucl_chunk_skipc (chunk, p);
1184262395Sbapt	}
1185262395Sbapt
1186262395Sbapt	if (p >= chunk->end) {
1187262395Sbapt		ucl_set_err (chunk, UCL_ESYNTAX, "unfinished value", &parser->err);
1188262395Sbapt		return false;
1189262395Sbapt	}
1190262395Sbapt
1191262395Sbapt	return true;
1192262395Sbapt}
1193262395Sbapt
1194262395Sbapt/**
1195262395Sbapt * Parse multiline string ending with \n{term}\n
1196262395Sbapt * @param parser
1197262395Sbapt * @param chunk
1198262395Sbapt * @param term
1199262395Sbapt * @param term_len
1200262395Sbapt * @return size of multiline string or 0 in case of error
1201262395Sbapt */
1202262395Sbaptstatic int
1203262395Sbaptucl_parse_multiline_string (struct ucl_parser *parser,
1204262395Sbapt		struct ucl_chunk *chunk, const unsigned char *term,
1205262395Sbapt		int term_len, unsigned char const **beg,
1206262395Sbapt		bool *var_expand)
1207262395Sbapt{
1208262395Sbapt	const unsigned char *p, *c;
1209262395Sbapt	bool newline = false;
1210262395Sbapt	int len = 0;
1211262395Sbapt
1212262395Sbapt	p = chunk->pos;
1213262395Sbapt
1214262395Sbapt	c = p;
1215262395Sbapt
1216262395Sbapt	while (p < chunk->end) {
1217262395Sbapt		if (newline) {
1218262395Sbapt			if (chunk->end - p < term_len) {
1219262395Sbapt				return 0;
1220262395Sbapt			}
1221262395Sbapt			else if (memcmp (p, term, term_len) == 0 && (p[term_len] == '\n' || p[term_len] == '\r')) {
1222262395Sbapt				len = p - c;
1223262395Sbapt				chunk->remain -= term_len;
1224262395Sbapt				chunk->pos = p + term_len;
1225262395Sbapt				chunk->column = term_len;
1226262395Sbapt				*beg = c;
1227262395Sbapt				break;
1228262395Sbapt			}
1229262395Sbapt		}
1230262395Sbapt		if (*p == '\n') {
1231262395Sbapt			newline = true;
1232262395Sbapt		}
1233262395Sbapt		else {
1234262395Sbapt			if (*p == '$') {
1235262395Sbapt				*var_expand = true;
1236262395Sbapt			}
1237262395Sbapt			newline = false;
1238262395Sbapt		}
1239262395Sbapt		ucl_chunk_skipc (chunk, p);
1240262395Sbapt	}
1241262395Sbapt
1242262395Sbapt	return len;
1243262395Sbapt}
1244262395Sbapt
1245262975Sbaptstatic ucl_object_t*
1246262975Sbaptucl_get_value_object (struct ucl_parser *parser)
1247262975Sbapt{
1248262975Sbapt	ucl_object_t *t, *obj = NULL;
1249262975Sbapt
1250262975Sbapt	if (parser->stack->obj->type == UCL_ARRAY) {
1251262975Sbapt		/* Object must be allocated */
1252262975Sbapt		obj = ucl_object_new ();
1253262975Sbapt		t = parser->stack->obj->value.av;
1254262975Sbapt		DL_APPEND (t, obj);
1255262975Sbapt		parser->cur_obj = obj;
1256262975Sbapt		parser->stack->obj->value.av = t;
1257262975Sbapt		parser->stack->obj->len ++;
1258262975Sbapt	}
1259262975Sbapt	else {
1260262975Sbapt		/* Object has been already allocated */
1261262975Sbapt		obj = parser->cur_obj;
1262262975Sbapt	}
1263262975Sbapt
1264262975Sbapt	return obj;
1265262975Sbapt}
1266262975Sbapt
1267262395Sbapt/**
1268262395Sbapt * Handle value data
1269262395Sbapt * @param parser
1270262395Sbapt * @param chunk
1271262395Sbapt * @return
1272262395Sbapt */
1273262395Sbaptstatic bool
1274262395Sbaptucl_parse_value (struct ucl_parser *parser, struct ucl_chunk *chunk)
1275262395Sbapt{
1276262395Sbapt	const unsigned char *p, *c;
1277262975Sbapt	ucl_object_t *obj = NULL;
1278262395Sbapt	unsigned int stripped_spaces;
1279262395Sbapt	int str_len;
1280262395Sbapt	bool need_unescape = false, ucl_escape = false, var_expand = false;
1281262395Sbapt
1282262395Sbapt	p = chunk->pos;
1283262395Sbapt
1284262975Sbapt	/* Skip any spaces and comments */
1285262975Sbapt	if (ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE) ||
1286262975Sbapt			(chunk->remain >= 2 && ucl_lex_is_comment (p[0], p[1]))) {
1287262975Sbapt		while (p < chunk->end && ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE)) {
1288262975Sbapt			ucl_chunk_skipc (chunk, p);
1289262975Sbapt		}
1290262975Sbapt		if (!ucl_skip_comments (parser)) {
1291262975Sbapt			return false;
1292262975Sbapt		}
1293262975Sbapt		p = chunk->pos;
1294262975Sbapt	}
1295262975Sbapt
1296262395Sbapt	while (p < chunk->end) {
1297262395Sbapt		c = p;
1298262395Sbapt		switch (*p) {
1299262395Sbapt		case '"':
1300262975Sbapt			obj = ucl_get_value_object (parser);
1301262395Sbapt			ucl_chunk_skipc (chunk, p);
1302262395Sbapt			if (!ucl_lex_json_string (parser, chunk, &need_unescape, &ucl_escape, &var_expand)) {
1303262395Sbapt				return false;
1304262395Sbapt			}
1305262395Sbapt			str_len = chunk->pos - c - 2;
1306262395Sbapt			obj->type = UCL_STRING;
1307262395Sbapt			if ((str_len = ucl_copy_or_store_ptr (parser, c + 1, &obj->trash_stack[UCL_TRASH_VALUE],
1308262395Sbapt					&obj->value.sv, str_len, need_unescape, false, var_expand)) == -1) {
1309262395Sbapt				return false;
1310262395Sbapt			}
1311262395Sbapt			obj->len = str_len;
1312262395Sbapt			parser->state = UCL_STATE_AFTER_VALUE;
1313262395Sbapt			p = chunk->pos;
1314262395Sbapt			return true;
1315262395Sbapt			break;
1316262395Sbapt		case '{':
1317262975Sbapt			obj = ucl_get_value_object (parser);
1318262395Sbapt			/* We have a new object */
1319262395Sbapt			obj = ucl_add_parser_stack (obj, parser, false, parser->stack->level);
1320263648Sbapt			if (obj == NULL) {
1321263648Sbapt				return false;
1322263648Sbapt			}
1323262395Sbapt
1324262395Sbapt			ucl_chunk_skipc (chunk, p);
1325262395Sbapt			return true;
1326262395Sbapt			break;
1327262395Sbapt		case '[':
1328262975Sbapt			obj = ucl_get_value_object (parser);
1329262395Sbapt			/* We have a new array */
1330262395Sbapt			obj = ucl_add_parser_stack (obj, parser, true, parser->stack->level);
1331263648Sbapt			if (obj == NULL) {
1332263648Sbapt				return false;
1333263648Sbapt			}
1334262395Sbapt
1335262395Sbapt			ucl_chunk_skipc (chunk, p);
1336262395Sbapt			return true;
1337262395Sbapt			break;
1338262975Sbapt		case ']':
1339262975Sbapt			/* We have the array ending */
1340262975Sbapt			if (parser->stack && parser->stack->obj->type == UCL_ARRAY) {
1341262975Sbapt				parser->state = UCL_STATE_AFTER_VALUE;
1342262975Sbapt				return true;
1343262975Sbapt			}
1344262975Sbapt			else {
1345262975Sbapt				goto parse_string;
1346262975Sbapt			}
1347262975Sbapt			break;
1348262395Sbapt		case '<':
1349262975Sbapt			obj = ucl_get_value_object (parser);
1350262395Sbapt			/* We have something like multiline value, which must be <<[A-Z]+\n */
1351262395Sbapt			if (chunk->end - p > 3) {
1352262395Sbapt				if (memcmp (p, "<<", 2) == 0) {
1353262395Sbapt					p += 2;
1354262395Sbapt					/* We allow only uppercase characters in multiline definitions */
1355262395Sbapt					while (p < chunk->end && *p >= 'A' && *p <= 'Z') {
1356262395Sbapt						p ++;
1357262395Sbapt					}
1358262395Sbapt					if (*p =='\n') {
1359262395Sbapt						/* Set chunk positions and start multiline parsing */
1360262395Sbapt						c += 2;
1361262395Sbapt						chunk->remain -= p - c;
1362262395Sbapt						chunk->pos = p + 1;
1363262395Sbapt						chunk->column = 0;
1364262395Sbapt						chunk->line ++;
1365262395Sbapt						if ((str_len = ucl_parse_multiline_string (parser, chunk, c,
1366262395Sbapt								p - c, &c, &var_expand)) == 0) {
1367262395Sbapt							ucl_set_err (chunk, UCL_ESYNTAX, "unterminated multiline value", &parser->err);
1368262395Sbapt							return false;
1369262395Sbapt						}
1370262395Sbapt						obj->type = UCL_STRING;
1371262395Sbapt						if ((str_len = ucl_copy_or_store_ptr (parser, c, &obj->trash_stack[UCL_TRASH_VALUE],
1372262395Sbapt							&obj->value.sv, str_len - 1, false, false, var_expand)) == -1) {
1373262395Sbapt							return false;
1374262395Sbapt						}
1375262395Sbapt						obj->len = str_len;
1376262395Sbapt						parser->state = UCL_STATE_AFTER_VALUE;
1377262395Sbapt						return true;
1378262395Sbapt					}
1379262395Sbapt				}
1380262395Sbapt			}
1381262395Sbapt			/* Fallback to ordinary strings */
1382262395Sbapt		default:
1383262975Sbaptparse_string:
1384262975Sbapt			if (obj == NULL) {
1385262975Sbapt				obj = ucl_get_value_object (parser);
1386262395Sbapt			}
1387262395Sbapt			/* Parse atom */
1388262395Sbapt			if (ucl_test_character (*p, UCL_CHARACTER_VALUE_DIGIT_START)) {
1389262395Sbapt				if (!ucl_lex_number (parser, chunk, obj)) {
1390262395Sbapt					if (parser->state == UCL_STATE_ERROR) {
1391262395Sbapt						return false;
1392262395Sbapt					}
1393262395Sbapt				}
1394262395Sbapt				else {
1395262395Sbapt					parser->state = UCL_STATE_AFTER_VALUE;
1396262395Sbapt					return true;
1397262395Sbapt				}
1398262395Sbapt				/* Fallback to normal string */
1399262395Sbapt			}
1400262395Sbapt
1401262395Sbapt			if (!ucl_parse_string_value (parser, chunk, &var_expand, &need_unescape)) {
1402262395Sbapt				return false;
1403262395Sbapt			}
1404262395Sbapt			/* Cut trailing spaces */
1405262395Sbapt			stripped_spaces = 0;
1406262395Sbapt			while (ucl_test_character (*(chunk->pos - 1 - stripped_spaces),
1407262395Sbapt					UCL_CHARACTER_WHITESPACE)) {
1408262395Sbapt				stripped_spaces ++;
1409262395Sbapt			}
1410262395Sbapt			str_len = chunk->pos - c - stripped_spaces;
1411262395Sbapt			if (str_len <= 0) {
1412262395Sbapt				ucl_set_err (chunk, 0, "string value must not be empty", &parser->err);
1413262395Sbapt				return false;
1414262395Sbapt			}
1415262395Sbapt			else if (str_len == 4 && memcmp (c, "null", 4) == 0) {
1416262395Sbapt				obj->len = 0;
1417262395Sbapt				obj->type = UCL_NULL;
1418262395Sbapt			}
1419262395Sbapt			else if (!ucl_maybe_parse_boolean (obj, c, str_len)) {
1420262395Sbapt				obj->type = UCL_STRING;
1421262395Sbapt				if ((str_len = ucl_copy_or_store_ptr (parser, c, &obj->trash_stack[UCL_TRASH_VALUE],
1422262395Sbapt						&obj->value.sv, str_len, need_unescape,
1423262395Sbapt						false, var_expand)) == -1) {
1424262395Sbapt					return false;
1425262395Sbapt				}
1426262395Sbapt				obj->len = str_len;
1427262395Sbapt			}
1428262395Sbapt			parser->state = UCL_STATE_AFTER_VALUE;
1429262395Sbapt			p = chunk->pos;
1430262395Sbapt
1431262395Sbapt			return true;
1432262395Sbapt			break;
1433262395Sbapt		}
1434262395Sbapt	}
1435262395Sbapt
1436262395Sbapt	return true;
1437262395Sbapt}
1438262395Sbapt
1439262395Sbapt/**
1440262395Sbapt * Handle after value data
1441262395Sbapt * @param parser
1442262395Sbapt * @param chunk
1443262395Sbapt * @return
1444262395Sbapt */
1445262395Sbaptstatic bool
1446262395Sbaptucl_parse_after_value (struct ucl_parser *parser, struct ucl_chunk *chunk)
1447262395Sbapt{
1448262395Sbapt	const unsigned char *p;
1449262395Sbapt	bool got_sep = false;
1450262395Sbapt	struct ucl_stack *st;
1451262395Sbapt
1452262395Sbapt	p = chunk->pos;
1453262395Sbapt
1454262395Sbapt	while (p < chunk->end) {
1455262395Sbapt		if (ucl_test_character (*p, UCL_CHARACTER_WHITESPACE)) {
1456262395Sbapt			/* Skip whitespaces */
1457262395Sbapt			ucl_chunk_skipc (chunk, p);
1458262395Sbapt		}
1459262395Sbapt		else if (chunk->remain >= 2 && ucl_lex_is_comment (p[0], p[1])) {
1460262395Sbapt			/* Skip comment */
1461262395Sbapt			if (!ucl_skip_comments (parser)) {
1462262395Sbapt				return false;
1463262395Sbapt			}
1464262395Sbapt			/* Treat comment as a separator */
1465262395Sbapt			got_sep = true;
1466262395Sbapt			p = chunk->pos;
1467262395Sbapt		}
1468262395Sbapt		else if (ucl_test_character (*p, UCL_CHARACTER_VALUE_END)) {
1469262395Sbapt			if (*p == '}' || *p == ']') {
1470262395Sbapt				if (parser->stack == NULL) {
1471262395Sbapt					ucl_set_err (chunk, UCL_ESYNTAX, "end of array or object detected without corresponding start", &parser->err);
1472262395Sbapt					return false;
1473262395Sbapt				}
1474262395Sbapt				if ((*p == '}' && parser->stack->obj->type == UCL_OBJECT) ||
1475262395Sbapt						(*p == ']' && parser->stack->obj->type == UCL_ARRAY)) {
1476262395Sbapt
1477262395Sbapt					/* Pop all nested objects from a stack */
1478262395Sbapt					st = parser->stack;
1479262395Sbapt					parser->stack = st->next;
1480262395Sbapt					UCL_FREE (sizeof (struct ucl_stack), st);
1481262395Sbapt
1482262395Sbapt					while (parser->stack != NULL) {
1483262395Sbapt						st = parser->stack;
1484262395Sbapt						if (st->next == NULL || st->next->level == st->level) {
1485262395Sbapt							break;
1486262395Sbapt						}
1487262395Sbapt						parser->stack = st->next;
1488262395Sbapt						UCL_FREE (sizeof (struct ucl_stack), st);
1489262395Sbapt					}
1490262395Sbapt				}
1491262395Sbapt				else {
1492262395Sbapt					ucl_set_err (chunk, UCL_ESYNTAX, "unexpected terminating symbol detected", &parser->err);
1493262395Sbapt					return false;
1494262395Sbapt				}
1495262395Sbapt
1496262395Sbapt				if (parser->stack == NULL) {
1497262395Sbapt					/* Ignore everything after a top object */
1498262395Sbapt					return true;
1499262395Sbapt				}
1500262395Sbapt				else {
1501262395Sbapt					ucl_chunk_skipc (chunk, p);
1502262395Sbapt				}
1503262395Sbapt				got_sep = true;
1504262395Sbapt			}
1505262395Sbapt			else {
1506262395Sbapt				/* Got a separator */
1507262395Sbapt				got_sep = true;
1508262395Sbapt				ucl_chunk_skipc (chunk, p);
1509262395Sbapt			}
1510262395Sbapt		}
1511262395Sbapt		else {
1512262395Sbapt			/* Anything else */
1513262395Sbapt			if (!got_sep) {
1514262395Sbapt				ucl_set_err (chunk, UCL_ESYNTAX, "delimiter is missing", &parser->err);
1515262395Sbapt				return false;
1516262395Sbapt			}
1517262395Sbapt			return true;
1518262395Sbapt		}
1519262395Sbapt	}
1520262395Sbapt
1521262395Sbapt	return true;
1522262395Sbapt}
1523262395Sbapt
1524262395Sbapt/**
1525262395Sbapt * Handle macro data
1526262395Sbapt * @param parser
1527262395Sbapt * @param chunk
1528262395Sbapt * @return
1529262395Sbapt */
1530262395Sbaptstatic bool
1531262395Sbaptucl_parse_macro_value (struct ucl_parser *parser,
1532262395Sbapt		struct ucl_chunk *chunk, struct ucl_macro *macro,
1533262395Sbapt		unsigned char const **macro_start, size_t *macro_len)
1534262395Sbapt{
1535262395Sbapt	const unsigned char *p, *c;
1536262395Sbapt	bool need_unescape = false, ucl_escape = false, var_expand = false;
1537262395Sbapt
1538262395Sbapt	p = chunk->pos;
1539262395Sbapt
1540262395Sbapt	switch (*p) {
1541262395Sbapt	case '"':
1542262395Sbapt		/* We have macro value encoded in quotes */
1543262395Sbapt		c = p;
1544262395Sbapt		ucl_chunk_skipc (chunk, p);
1545262395Sbapt		if (!ucl_lex_json_string (parser, chunk, &need_unescape, &ucl_escape, &var_expand)) {
1546262395Sbapt			return false;
1547262395Sbapt		}
1548262395Sbapt
1549262395Sbapt		*macro_start = c + 1;
1550262395Sbapt		*macro_len = chunk->pos - c - 2;
1551262395Sbapt		p = chunk->pos;
1552262395Sbapt		break;
1553262395Sbapt	case '{':
1554262395Sbapt		/* We got a multiline macro body */
1555262395Sbapt		ucl_chunk_skipc (chunk, p);
1556262395Sbapt		/* Skip spaces at the beginning */
1557262395Sbapt		while (p < chunk->end) {
1558262395Sbapt			if (ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE)) {
1559262395Sbapt				ucl_chunk_skipc (chunk, p);
1560262395Sbapt			}
1561262395Sbapt			else {
1562262395Sbapt				break;
1563262395Sbapt			}
1564262395Sbapt		}
1565262395Sbapt		c = p;
1566262395Sbapt		while (p < chunk->end) {
1567262395Sbapt			if (*p == '}') {
1568262395Sbapt				break;
1569262395Sbapt			}
1570262395Sbapt			ucl_chunk_skipc (chunk, p);
1571262395Sbapt		}
1572262395Sbapt		*macro_start = c;
1573262395Sbapt		*macro_len = p - c;
1574262395Sbapt		ucl_chunk_skipc (chunk, p);
1575262395Sbapt		break;
1576262395Sbapt	default:
1577262395Sbapt		/* Macro is not enclosed in quotes or braces */
1578262395Sbapt		c = p;
1579262395Sbapt		while (p < chunk->end) {
1580262395Sbapt			if (ucl_lex_is_atom_end (*p)) {
1581262395Sbapt				break;
1582262395Sbapt			}
1583262395Sbapt			ucl_chunk_skipc (chunk, p);
1584262395Sbapt		}
1585262395Sbapt		*macro_start = c;
1586262395Sbapt		*macro_len = p - c;
1587262395Sbapt		break;
1588262395Sbapt	}
1589262395Sbapt
1590262395Sbapt	/* We are at the end of a macro */
1591262395Sbapt	/* Skip ';' and space characters and return to previous state */
1592262395Sbapt	while (p < chunk->end) {
1593262395Sbapt		if (!ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE) && *p != ';') {
1594262395Sbapt			break;
1595262395Sbapt		}
1596262395Sbapt		ucl_chunk_skipc (chunk, p);
1597262395Sbapt	}
1598262395Sbapt	return true;
1599262395Sbapt}
1600262395Sbapt
1601262395Sbapt/**
1602262395Sbapt * Handle the main states of rcl parser
1603262395Sbapt * @param parser parser structure
1604262395Sbapt * @param data the pointer to the beginning of a chunk
1605262395Sbapt * @param len the length of a chunk
1606262395Sbapt * @return true if chunk has been parsed and false in case of error
1607262395Sbapt */
1608262395Sbaptstatic bool
1609262395Sbaptucl_state_machine (struct ucl_parser *parser)
1610262395Sbapt{
1611262395Sbapt	ucl_object_t *obj;
1612262395Sbapt	struct ucl_chunk *chunk = parser->chunks;
1613262395Sbapt	const unsigned char *p, *c = NULL, *macro_start = NULL;
1614262395Sbapt	unsigned char *macro_escaped;
1615262395Sbapt	size_t macro_len = 0;
1616262395Sbapt	struct ucl_macro *macro = NULL;
1617262395Sbapt	bool next_key = false, end_of_object = false;
1618262395Sbapt
1619262395Sbapt	if (parser->top_obj == NULL) {
1620262395Sbapt		if (*chunk->pos == '[') {
1621262395Sbapt			obj = ucl_add_parser_stack (NULL, parser, true, 0);
1622262395Sbapt		}
1623262395Sbapt		else {
1624262395Sbapt			obj = ucl_add_parser_stack (NULL, parser, false, 0);
1625262395Sbapt		}
1626263648Sbapt		if (obj == NULL) {
1627263648Sbapt			return false;
1628263648Sbapt		}
1629262395Sbapt		parser->top_obj = obj;
1630262395Sbapt		parser->cur_obj = obj;
1631262395Sbapt		parser->state = UCL_STATE_INIT;
1632262395Sbapt	}
1633262395Sbapt
1634262395Sbapt	p = chunk->pos;
1635262395Sbapt	while (chunk->pos < chunk->end) {
1636262395Sbapt		switch (parser->state) {
1637262395Sbapt		case UCL_STATE_INIT:
1638262395Sbapt			/*
1639262395Sbapt			 * At the init state we can either go to the parse array or object
1640262395Sbapt			 * if we got [ or { correspondingly or can just treat new data as
1641262395Sbapt			 * a key of newly created object
1642262395Sbapt			 */
1643262395Sbapt			obj = parser->cur_obj;
1644262395Sbapt			if (!ucl_skip_comments (parser)) {
1645262395Sbapt				parser->prev_state = parser->state;
1646262395Sbapt				parser->state = UCL_STATE_ERROR;
1647262395Sbapt				return false;
1648262395Sbapt			}
1649262395Sbapt			else {
1650262395Sbapt				p = chunk->pos;
1651262395Sbapt				if (*p == '[') {
1652262395Sbapt					parser->state = UCL_STATE_VALUE;
1653262395Sbapt					ucl_chunk_skipc (chunk, p);
1654262395Sbapt				}
1655262395Sbapt				else {
1656262395Sbapt					parser->state = UCL_STATE_KEY;
1657262395Sbapt					if (*p == '{') {
1658262395Sbapt						ucl_chunk_skipc (chunk, p);
1659262395Sbapt					}
1660262395Sbapt				}
1661262395Sbapt			}
1662262395Sbapt			break;
1663262395Sbapt		case UCL_STATE_KEY:
1664262395Sbapt			/* Skip any spaces */
1665262395Sbapt			while (p < chunk->end && ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE)) {
1666262395Sbapt				ucl_chunk_skipc (chunk, p);
1667262395Sbapt			}
1668262395Sbapt			if (*p == '}') {
1669262395Sbapt				/* We have the end of an object */
1670262395Sbapt				parser->state = UCL_STATE_AFTER_VALUE;
1671262395Sbapt				continue;
1672262395Sbapt			}
1673262395Sbapt			if (parser->stack == NULL) {
1674262395Sbapt				/* No objects are on stack, but we want to parse a key */
1675262395Sbapt				ucl_set_err (chunk, UCL_ESYNTAX, "top object is finished but the parser "
1676262395Sbapt						"expects a key", &parser->err);
1677262395Sbapt				parser->prev_state = parser->state;
1678262395Sbapt				parser->state = UCL_STATE_ERROR;
1679262395Sbapt				return false;
1680262395Sbapt			}
1681262395Sbapt			if (!ucl_parse_key (parser, chunk, &next_key, &end_of_object)) {
1682262395Sbapt				parser->prev_state = parser->state;
1683262395Sbapt				parser->state = UCL_STATE_ERROR;
1684262395Sbapt				return false;
1685262395Sbapt			}
1686262395Sbapt			if (end_of_object) {
1687262395Sbapt				p = chunk->pos;
1688262395Sbapt				parser->state = UCL_STATE_AFTER_VALUE;
1689262395Sbapt				continue;
1690262395Sbapt			}
1691262395Sbapt			else if (parser->state != UCL_STATE_MACRO_NAME) {
1692262395Sbapt				if (next_key && parser->stack->obj->type == UCL_OBJECT) {
1693262395Sbapt					/* Parse more keys and nest objects accordingly */
1694263648Sbapt					obj = ucl_add_parser_stack (parser->cur_obj, parser, false,
1695263648Sbapt							parser->stack->level + 1);
1696263648Sbapt					if (obj == NULL) {
1697263648Sbapt						return false;
1698263648Sbapt					}
1699262395Sbapt				}
1700262395Sbapt				else {
1701262395Sbapt					parser->state = UCL_STATE_VALUE;
1702262395Sbapt				}
1703262395Sbapt			}
1704262395Sbapt			else {
1705262395Sbapt				c = chunk->pos;
1706262395Sbapt			}
1707262395Sbapt			p = chunk->pos;
1708262395Sbapt			break;
1709262395Sbapt		case UCL_STATE_VALUE:
1710262395Sbapt			/* We need to check what we do have */
1711262395Sbapt			if (!ucl_parse_value (parser, chunk)) {
1712262395Sbapt				parser->prev_state = parser->state;
1713262395Sbapt				parser->state = UCL_STATE_ERROR;
1714262395Sbapt				return false;
1715262395Sbapt			}
1716262395Sbapt			/* State is set in ucl_parse_value call */
1717262395Sbapt			p = chunk->pos;
1718262395Sbapt			break;
1719262395Sbapt		case UCL_STATE_AFTER_VALUE:
1720262395Sbapt			if (!ucl_parse_after_value (parser, chunk)) {
1721262395Sbapt				parser->prev_state = parser->state;
1722262395Sbapt				parser->state = UCL_STATE_ERROR;
1723262395Sbapt				return false;
1724262395Sbapt			}
1725262395Sbapt			if (parser->stack != NULL) {
1726262395Sbapt				if (parser->stack->obj->type == UCL_OBJECT) {
1727262395Sbapt					parser->state = UCL_STATE_KEY;
1728262395Sbapt				}
1729262395Sbapt				else {
1730262395Sbapt					/* Array */
1731262395Sbapt					parser->state = UCL_STATE_VALUE;
1732262395Sbapt				}
1733262395Sbapt			}
1734262395Sbapt			else {
1735262395Sbapt				/* Skip everything at the end */
1736262395Sbapt				return true;
1737262395Sbapt			}
1738262395Sbapt			p = chunk->pos;
1739262395Sbapt			break;
1740262395Sbapt		case UCL_STATE_MACRO_NAME:
1741262395Sbapt			if (!ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE)) {
1742262395Sbapt				ucl_chunk_skipc (chunk, p);
1743262395Sbapt			}
1744262395Sbapt			else if (p - c > 0) {
1745262395Sbapt				/* We got macro name */
1746262395Sbapt				macro_len = (size_t)(p - c);
1747262395Sbapt				HASH_FIND (hh, parser->macroes, c, macro_len, macro);
1748262395Sbapt				if (macro == NULL) {
1749262395Sbapt					ucl_create_err (&parser->err, "error on line %d at column %d: "
1750262395Sbapt							"unknown macro: '%.*s', character: '%c'",
1751262395Sbapt								chunk->line, chunk->column, (int)(p - c), c, *chunk->pos);
1752262395Sbapt					parser->state = UCL_STATE_ERROR;
1753262395Sbapt					return false;
1754262395Sbapt				}
1755262395Sbapt				/* Now we need to skip all spaces */
1756262395Sbapt				while (p < chunk->end) {
1757262395Sbapt					if (!ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE)) {
1758262395Sbapt						if (chunk->remain >= 2 && ucl_lex_is_comment (p[0], p[1])) {
1759262395Sbapt							/* Skip comment */
1760262395Sbapt							if (!ucl_skip_comments (parser)) {
1761262395Sbapt								return false;
1762262395Sbapt							}
1763262395Sbapt							p = chunk->pos;
1764262395Sbapt						}
1765262395Sbapt						break;
1766262395Sbapt					}
1767262395Sbapt					ucl_chunk_skipc (chunk, p);
1768262395Sbapt				}
1769262395Sbapt				parser->state = UCL_STATE_MACRO;
1770262395Sbapt			}
1771262395Sbapt			break;
1772262395Sbapt		case UCL_STATE_MACRO:
1773262395Sbapt			if (!ucl_parse_macro_value (parser, chunk, macro,
1774262395Sbapt					&macro_start, &macro_len)) {
1775262395Sbapt				parser->prev_state = parser->state;
1776262395Sbapt				parser->state = UCL_STATE_ERROR;
1777262395Sbapt				return false;
1778262395Sbapt			}
1779262395Sbapt			macro_len = ucl_expand_variable (parser, &macro_escaped, macro_start, macro_len);
1780262395Sbapt			parser->state = parser->prev_state;
1781262395Sbapt			if (macro_escaped == NULL) {
1782262395Sbapt				if (!macro->handler (macro_start, macro_len, macro->ud)) {
1783262395Sbapt					return false;
1784262395Sbapt				}
1785262395Sbapt			}
1786262395Sbapt			else {
1787262395Sbapt				if (!macro->handler (macro_escaped, macro_len, macro->ud)) {
1788262395Sbapt					UCL_FREE (macro_len + 1, macro_escaped);
1789262395Sbapt					return false;
1790262395Sbapt				}
1791262395Sbapt				UCL_FREE (macro_len + 1, macro_escaped);
1792262395Sbapt			}
1793262395Sbapt			p = chunk->pos;
1794262395Sbapt			break;
1795262395Sbapt		default:
1796262395Sbapt			/* TODO: add all states */
1797262395Sbapt			ucl_set_err (chunk, UCL_EINTERNAL, "internal error: parser is in an unknown state", &parser->err);
1798262395Sbapt			parser->state = UCL_STATE_ERROR;
1799262395Sbapt			return false;
1800262395Sbapt		}
1801262395Sbapt	}
1802262395Sbapt
1803262395Sbapt	return true;
1804262395Sbapt}
1805262395Sbapt
1806262395Sbaptstruct ucl_parser*
1807262395Sbaptucl_parser_new (int flags)
1808262395Sbapt{
1809262395Sbapt	struct ucl_parser *new;
1810262395Sbapt
1811262395Sbapt	new = UCL_ALLOC (sizeof (struct ucl_parser));
1812263648Sbapt	if (new == NULL) {
1813263648Sbapt		return NULL;
1814263648Sbapt	}
1815262395Sbapt	memset (new, 0, sizeof (struct ucl_parser));
1816262395Sbapt
1817262395Sbapt	ucl_parser_register_macro (new, "include", ucl_include_handler, new);
1818262395Sbapt	ucl_parser_register_macro (new, "try_include", ucl_try_include_handler, new);
1819262395Sbapt	ucl_parser_register_macro (new, "includes", ucl_includes_handler, new);
1820262395Sbapt
1821262395Sbapt	new->flags = flags;
1822262395Sbapt
1823262395Sbapt	/* Initial assumption about filevars */
1824262395Sbapt	ucl_parser_set_filevars (new, NULL, false);
1825262395Sbapt
1826262395Sbapt	return new;
1827262395Sbapt}
1828262395Sbapt
1829262395Sbapt
1830262395Sbaptvoid
1831262395Sbaptucl_parser_register_macro (struct ucl_parser *parser, const char *macro,
1832262395Sbapt		ucl_macro_handler handler, void* ud)
1833262395Sbapt{
1834262395Sbapt	struct ucl_macro *new;
1835262395Sbapt
1836263648Sbapt	if (macro == NULL || handler == NULL) {
1837263648Sbapt		return;
1838263648Sbapt	}
1839262395Sbapt	new = UCL_ALLOC (sizeof (struct ucl_macro));
1840263648Sbapt	if (new == NULL) {
1841263648Sbapt		return;
1842263648Sbapt	}
1843262395Sbapt	memset (new, 0, sizeof (struct ucl_macro));
1844262395Sbapt	new->handler = handler;
1845262395Sbapt	new->name = strdup (macro);
1846262395Sbapt	new->ud = ud;
1847262395Sbapt	HASH_ADD_KEYPTR (hh, parser->macroes, new->name, strlen (new->name), new);
1848262395Sbapt}
1849262395Sbapt
1850262395Sbaptvoid
1851262395Sbaptucl_parser_register_variable (struct ucl_parser *parser, const char *var,
1852262395Sbapt		const char *value)
1853262395Sbapt{
1854262395Sbapt	struct ucl_variable *new = NULL, *cur;
1855262395Sbapt
1856262395Sbapt	if (var == NULL) {
1857262395Sbapt		return;
1858262395Sbapt	}
1859262395Sbapt
1860262395Sbapt	/* Find whether a variable already exists */
1861262395Sbapt	LL_FOREACH (parser->variables, cur) {
1862262395Sbapt		if (strcmp (cur->var, var) == 0) {
1863262395Sbapt			new = cur;
1864262395Sbapt			break;
1865262395Sbapt		}
1866262395Sbapt	}
1867262395Sbapt
1868262395Sbapt	if (value == NULL) {
1869262395Sbapt
1870262395Sbapt		if (new != NULL) {
1871262395Sbapt			/* Remove variable */
1872262395Sbapt			LL_DELETE (parser->variables, new);
1873262395Sbapt			free (new->var);
1874262395Sbapt			free (new->value);
1875262395Sbapt			UCL_FREE (sizeof (struct ucl_variable), new);
1876262395Sbapt		}
1877262395Sbapt		else {
1878262395Sbapt			/* Do nothing */
1879262395Sbapt			return;
1880262395Sbapt		}
1881262395Sbapt	}
1882262395Sbapt	else {
1883262395Sbapt		if (new == NULL) {
1884262395Sbapt			new = UCL_ALLOC (sizeof (struct ucl_variable));
1885263648Sbapt			if (new == NULL) {
1886263648Sbapt				return;
1887263648Sbapt			}
1888262395Sbapt			memset (new, 0, sizeof (struct ucl_variable));
1889262395Sbapt			new->var = strdup (var);
1890262395Sbapt			new->var_len = strlen (var);
1891262395Sbapt			new->value = strdup (value);
1892262395Sbapt			new->value_len = strlen (value);
1893262395Sbapt
1894262395Sbapt			LL_PREPEND (parser->variables, new);
1895262395Sbapt		}
1896262395Sbapt		else {
1897262395Sbapt			free (new->value);
1898262395Sbapt			new->value = strdup (value);
1899262395Sbapt			new->value_len = strlen (value);
1900262395Sbapt		}
1901262395Sbapt	}
1902262395Sbapt}
1903262395Sbapt
1904262395Sbaptbool
1905262395Sbaptucl_parser_add_chunk (struct ucl_parser *parser, const unsigned char *data,
1906262395Sbapt		size_t len)
1907262395Sbapt{
1908262395Sbapt	struct ucl_chunk *chunk;
1909262395Sbapt
1910263648Sbapt	if (data == NULL || len == 0) {
1911263648Sbapt		ucl_create_err (&parser->err, "invalid chunk added");
1912263648Sbapt		return false;
1913263648Sbapt	}
1914262395Sbapt	if (parser->state != UCL_STATE_ERROR) {
1915262395Sbapt		chunk = UCL_ALLOC (sizeof (struct ucl_chunk));
1916263648Sbapt		if (chunk == NULL) {
1917263648Sbapt			ucl_create_err (&parser->err, "cannot allocate chunk structure");
1918263648Sbapt			return false;
1919263648Sbapt		}
1920262395Sbapt		chunk->begin = data;
1921262395Sbapt		chunk->remain = len;
1922262395Sbapt		chunk->pos = chunk->begin;
1923262395Sbapt		chunk->end = chunk->begin + len;
1924262395Sbapt		chunk->line = 1;
1925262395Sbapt		chunk->column = 0;
1926262395Sbapt		LL_PREPEND (parser->chunks, chunk);
1927262395Sbapt		parser->recursion ++;
1928262395Sbapt		if (parser->recursion > UCL_MAX_RECURSION) {
1929262395Sbapt			ucl_create_err (&parser->err, "maximum include nesting limit is reached: %d",
1930262395Sbapt					parser->recursion);
1931262395Sbapt			return false;
1932262395Sbapt		}
1933262395Sbapt		return ucl_state_machine (parser);
1934262395Sbapt	}
1935262395Sbapt
1936262395Sbapt	ucl_create_err (&parser->err, "a parser is in an invalid state");
1937262395Sbapt
1938262395Sbapt	return false;
1939262395Sbapt}
1940263648Sbapt
1941263648Sbaptbool
1942263648Sbaptucl_parser_add_string (struct ucl_parser *parser, const char *data,
1943263648Sbapt		size_t len)
1944263648Sbapt{
1945263648Sbapt	if (data == NULL) {
1946263648Sbapt		ucl_create_err (&parser->err, "invalid string added");
1947263648Sbapt		return false;
1948263648Sbapt	}
1949263648Sbapt	if (len == 0) {
1950263648Sbapt		len = strlen (data);
1951263648Sbapt	}
1952263648Sbapt
1953263648Sbapt	return ucl_parser_add_chunk (parser, (const unsigned char *)data, len);
1954263648Sbapt}
1955