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));
547262395Sbapt	st->obj = obj;
548262395Sbapt	st->level = level;
549262395Sbapt	LL_PREPEND (parser->stack, st);
550262395Sbapt	parser->cur_obj = obj;
551262395Sbapt
552262395Sbapt	return obj;
553262395Sbapt}
554262395Sbapt
555262395Sbaptint
556262395Sbaptucl_maybe_parse_number (ucl_object_t *obj,
557262395Sbapt		const char *start, const char *end, const char **pos, bool allow_double, bool number_bytes)
558262395Sbapt{
559262395Sbapt	const char *p = start, *c = start;
560262395Sbapt	char *endptr;
561262395Sbapt	bool got_dot = false, got_exp = false, need_double = false,
562262395Sbapt			is_date = false, valid_start = false, is_hex = false,
563262395Sbapt			is_neg = false;
564262395Sbapt	double dv = 0;
565262395Sbapt	int64_t lv = 0;
566262395Sbapt
567262395Sbapt	if (*p == '-') {
568262395Sbapt		is_neg = true;
569262395Sbapt		c ++;
570262395Sbapt		p ++;
571262395Sbapt	}
572262395Sbapt	while (p < end) {
573262395Sbapt		if (is_hex && isxdigit (*p)) {
574262395Sbapt			p ++;
575262395Sbapt		}
576262395Sbapt		else if (isdigit (*p)) {
577262395Sbapt			valid_start = true;
578262395Sbapt			p ++;
579262395Sbapt		}
580262395Sbapt		else if (!is_hex && (*p == 'x' || *p == 'X')) {
581262395Sbapt			is_hex = true;
582262395Sbapt			allow_double = false;
583262395Sbapt			c = p + 1;
584262395Sbapt		}
585262395Sbapt		else if (allow_double) {
586262395Sbapt			if (p == c) {
587262395Sbapt				/* Empty digits sequence, not a number */
588262395Sbapt				*pos = start;
589262395Sbapt				return EINVAL;
590262395Sbapt			}
591262395Sbapt			else if (*p == '.') {
592262395Sbapt				if (got_dot) {
593262395Sbapt					/* Double dots, not a number */
594262395Sbapt					*pos = start;
595262395Sbapt					return EINVAL;
596262395Sbapt				}
597262395Sbapt				else {
598262395Sbapt					got_dot = true;
599262395Sbapt					need_double = true;
600262395Sbapt					p ++;
601262395Sbapt				}
602262395Sbapt			}
603262395Sbapt			else if (*p == 'e' || *p == 'E') {
604262395Sbapt				if (got_exp) {
605262395Sbapt					/* Double exp, not a number */
606262395Sbapt					*pos = start;
607262395Sbapt					return EINVAL;
608262395Sbapt				}
609262395Sbapt				else {
610262395Sbapt					got_exp = true;
611262395Sbapt					need_double = true;
612262395Sbapt					p ++;
613262395Sbapt					if (p >= end) {
614262395Sbapt						*pos = start;
615262395Sbapt						return EINVAL;
616262395Sbapt					}
617262395Sbapt					if (!isdigit (*p) && *p != '+' && *p != '-') {
618262395Sbapt						/* Wrong exponent sign */
619262395Sbapt						*pos = start;
620262395Sbapt						return EINVAL;
621262395Sbapt					}
622262395Sbapt					else {
623262395Sbapt						p ++;
624262395Sbapt					}
625262395Sbapt				}
626262395Sbapt			}
627262395Sbapt			else {
628262395Sbapt				/* Got the end of the number, need to check */
629262395Sbapt				break;
630262395Sbapt			}
631262395Sbapt		}
632262395Sbapt		else {
633262395Sbapt			break;
634262395Sbapt		}
635262395Sbapt	}
636262395Sbapt
637262395Sbapt	if (!valid_start) {
638262395Sbapt		*pos = start;
639262395Sbapt		return EINVAL;
640262395Sbapt	}
641262395Sbapt
642262395Sbapt	errno = 0;
643262395Sbapt	if (need_double) {
644262395Sbapt		dv = strtod (c, &endptr);
645262395Sbapt	}
646262395Sbapt	else {
647262395Sbapt		if (is_hex) {
648262395Sbapt			lv = strtoimax (c, &endptr, 16);
649262395Sbapt		}
650262395Sbapt		else {
651262395Sbapt			lv = strtoimax (c, &endptr, 10);
652262395Sbapt		}
653262395Sbapt	}
654262395Sbapt	if (errno == ERANGE) {
655262395Sbapt		*pos = start;
656262395Sbapt		return ERANGE;
657262395Sbapt	}
658262395Sbapt
659262395Sbapt	/* Now check endptr */
660262395Sbapt	if (endptr == NULL || ucl_lex_is_atom_end (*endptr) || *endptr == '\0') {
661262395Sbapt		p = endptr;
662262395Sbapt		goto set_obj;
663262395Sbapt	}
664262395Sbapt
665262395Sbapt	if (endptr < end && endptr != start) {
666262395Sbapt		p = endptr;
667262395Sbapt		switch (*p) {
668262395Sbapt		case 'm':
669262395Sbapt		case 'M':
670262395Sbapt		case 'g':
671262395Sbapt		case 'G':
672262395Sbapt		case 'k':
673262395Sbapt		case 'K':
674262395Sbapt			if (end - p >= 2) {
675262395Sbapt				if (p[1] == 's' || p[1] == 'S') {
676262395Sbapt					/* Milliseconds */
677262395Sbapt					if (!need_double) {
678262395Sbapt						need_double = true;
679262395Sbapt						dv = lv;
680262395Sbapt					}
681262395Sbapt					is_date = true;
682262395Sbapt					if (p[0] == 'm' || p[0] == 'M') {
683262395Sbapt						dv /= 1000.;
684262395Sbapt					}
685262395Sbapt					else {
686262395Sbapt						dv *= ucl_lex_num_multiplier (*p, false);
687262395Sbapt					}
688262395Sbapt					p += 2;
689262395Sbapt					goto set_obj;
690262395Sbapt				}
691262395Sbapt				else if (number_bytes || (p[1] == 'b' || p[1] == 'B')) {
692262395Sbapt					/* Bytes */
693262395Sbapt					if (need_double) {
694262395Sbapt						need_double = false;
695262395Sbapt						lv = dv;
696262395Sbapt					}
697262395Sbapt					lv *= ucl_lex_num_multiplier (*p, true);
698262395Sbapt					p += 2;
699262395Sbapt					goto set_obj;
700262395Sbapt				}
701262395Sbapt				else if (ucl_lex_is_atom_end (p[1])) {
702262395Sbapt					if (need_double) {
703262395Sbapt						dv *= ucl_lex_num_multiplier (*p, false);
704262395Sbapt					}
705262395Sbapt					else {
706262395Sbapt						lv *= ucl_lex_num_multiplier (*p, number_bytes);
707262395Sbapt					}
708262395Sbapt					p ++;
709262395Sbapt					goto set_obj;
710262395Sbapt				}
711262395Sbapt				else if (end - p >= 3) {
712262395Sbapt					if (tolower (p[0]) == 'm' &&
713262395Sbapt							tolower (p[1]) == 'i' &&
714262395Sbapt							tolower (p[2]) == 'n') {
715262395Sbapt						/* Minutes */
716262395Sbapt						if (!need_double) {
717262395Sbapt							need_double = true;
718262395Sbapt							dv = lv;
719262395Sbapt						}
720262395Sbapt						is_date = true;
721262395Sbapt						dv *= 60.;
722262395Sbapt						p += 3;
723262395Sbapt						goto set_obj;
724262395Sbapt					}
725262395Sbapt				}
726262395Sbapt			}
727262395Sbapt			else {
728262395Sbapt				if (need_double) {
729262395Sbapt					dv *= ucl_lex_num_multiplier (*p, false);
730262395Sbapt				}
731262395Sbapt				else {
732262395Sbapt					lv *= ucl_lex_num_multiplier (*p, number_bytes);
733262395Sbapt				}
734262395Sbapt				p ++;
735262395Sbapt				goto set_obj;
736262395Sbapt			}
737262395Sbapt			break;
738262395Sbapt		case 'S':
739262395Sbapt		case 's':
740262395Sbapt			if (p == end - 1 || ucl_lex_is_atom_end (p[1])) {
741262395Sbapt				if (!need_double) {
742262395Sbapt					need_double = true;
743262395Sbapt					dv = lv;
744262395Sbapt				}
745262395Sbapt				p ++;
746262395Sbapt				is_date = true;
747262395Sbapt				goto set_obj;
748262395Sbapt			}
749262395Sbapt			break;
750262395Sbapt		case 'h':
751262395Sbapt		case 'H':
752262395Sbapt		case 'd':
753262395Sbapt		case 'D':
754262395Sbapt		case 'w':
755262395Sbapt		case 'W':
756262395Sbapt		case 'Y':
757262395Sbapt		case 'y':
758262395Sbapt			if (p == end - 1 || ucl_lex_is_atom_end (p[1])) {
759262395Sbapt				if (!need_double) {
760262395Sbapt					need_double = true;
761262395Sbapt					dv = lv;
762262395Sbapt				}
763262395Sbapt				is_date = true;
764262395Sbapt				dv *= ucl_lex_time_multiplier (*p);
765262395Sbapt				p ++;
766262395Sbapt				goto set_obj;
767262395Sbapt			}
768262395Sbapt			break;
769262395Sbapt		}
770262395Sbapt	}
771262395Sbapt
772262395Sbapt	*pos = c;
773262395Sbapt	return EINVAL;
774262395Sbapt
775262395Sbapt	set_obj:
776262395Sbapt	if (allow_double && (need_double || is_date)) {
777262395Sbapt		if (!is_date) {
778262395Sbapt			obj->type = UCL_FLOAT;
779262395Sbapt		}
780262395Sbapt		else {
781262395Sbapt			obj->type = UCL_TIME;
782262395Sbapt		}
783262395Sbapt		obj->value.dv = is_neg ? (-dv) : dv;
784262395Sbapt	}
785262395Sbapt	else {
786262395Sbapt		obj->type = UCL_INT;
787262395Sbapt		obj->value.iv = is_neg ? (-lv) : lv;
788262395Sbapt	}
789262395Sbapt	*pos = p;
790262395Sbapt	return 0;
791262395Sbapt}
792262395Sbapt
793262395Sbapt/**
794262395Sbapt * Parse possible number
795262395Sbapt * @param parser
796262395Sbapt * @param chunk
797262395Sbapt * @return true if a number has been parsed
798262395Sbapt */
799262395Sbaptstatic bool
800262395Sbaptucl_lex_number (struct ucl_parser *parser,
801262395Sbapt		struct ucl_chunk *chunk, ucl_object_t *obj)
802262395Sbapt{
803262395Sbapt	const unsigned char *pos;
804262395Sbapt	int ret;
805262395Sbapt
806262395Sbapt	ret = ucl_maybe_parse_number (obj, chunk->pos, chunk->end, (const char **)&pos, true, false);
807262395Sbapt
808262395Sbapt	if (ret == 0) {
809262395Sbapt		chunk->remain -= pos - chunk->pos;
810262395Sbapt		chunk->column += pos - chunk->pos;
811262395Sbapt		chunk->pos = pos;
812262395Sbapt		return true;
813262395Sbapt	}
814262395Sbapt	else if (ret == ERANGE) {
815262395Sbapt		ucl_set_err (chunk, ERANGE, "numeric value out of range", &parser->err);
816262395Sbapt	}
817262395Sbapt
818262395Sbapt	return false;
819262395Sbapt}
820262395Sbapt
821262395Sbapt/**
822262395Sbapt * Parse quoted string with possible escapes
823262395Sbapt * @param parser
824262395Sbapt * @param chunk
825262395Sbapt * @return true if a string has been parsed
826262395Sbapt */
827262395Sbaptstatic bool
828262395Sbaptucl_lex_json_string (struct ucl_parser *parser,
829262395Sbapt		struct ucl_chunk *chunk, bool *need_unescape, bool *ucl_escape, bool *var_expand)
830262395Sbapt{
831262395Sbapt	const unsigned char *p = chunk->pos;
832262395Sbapt	unsigned char c;
833262395Sbapt	int i;
834262395Sbapt
835262395Sbapt	while (p < chunk->end) {
836262395Sbapt		c = *p;
837262395Sbapt		if (c < 0x1F) {
838262395Sbapt			/* Unmasked control character */
839262395Sbapt			if (c == '\n') {
840262395Sbapt				ucl_set_err (chunk, UCL_ESYNTAX, "unexpected newline", &parser->err);
841262395Sbapt			}
842262395Sbapt			else {
843262395Sbapt				ucl_set_err (chunk, UCL_ESYNTAX, "unexpected control character", &parser->err);
844262395Sbapt			}
845262395Sbapt			return false;
846262395Sbapt		}
847262395Sbapt		else if (c == '\\') {
848262395Sbapt			ucl_chunk_skipc (chunk, p);
849262395Sbapt			c = *p;
850262395Sbapt			if (p >= chunk->end) {
851262395Sbapt				ucl_set_err (chunk, UCL_ESYNTAX, "unfinished escape character", &parser->err);
852262395Sbapt				return false;
853262395Sbapt			}
854262395Sbapt			else if (ucl_test_character (c, UCL_CHARACTER_ESCAPE)) {
855262395Sbapt				if (c == 'u') {
856262395Sbapt					ucl_chunk_skipc (chunk, p);
857262395Sbapt					for (i = 0; i < 4 && p < chunk->end; i ++) {
858262395Sbapt						if (!isxdigit (*p)) {
859262395Sbapt							ucl_set_err (chunk, UCL_ESYNTAX, "invalid utf escape", &parser->err);
860262395Sbapt							return false;
861262395Sbapt						}
862262395Sbapt						ucl_chunk_skipc (chunk, p);
863262395Sbapt					}
864262395Sbapt					if (p >= chunk->end) {
865262395Sbapt						ucl_set_err (chunk, UCL_ESYNTAX, "unfinished escape character", &parser->err);
866262395Sbapt						return false;
867262395Sbapt					}
868262395Sbapt				}
869262395Sbapt				else {
870262395Sbapt					ucl_chunk_skipc (chunk, p);
871262395Sbapt				}
872262395Sbapt			}
873262395Sbapt			*need_unescape = true;
874262395Sbapt			*ucl_escape = true;
875262395Sbapt			continue;
876262395Sbapt		}
877262395Sbapt		else if (c == '"') {
878262395Sbapt			ucl_chunk_skipc (chunk, p);
879262395Sbapt			return true;
880262395Sbapt		}
881262395Sbapt		else if (ucl_test_character (c, UCL_CHARACTER_UCL_UNSAFE)) {
882262395Sbapt			*ucl_escape = true;
883262395Sbapt		}
884262395Sbapt		else if (c == '$') {
885262395Sbapt			*var_expand = true;
886262395Sbapt		}
887262395Sbapt		ucl_chunk_skipc (chunk, p);
888262395Sbapt	}
889262395Sbapt
890262395Sbapt	ucl_set_err (chunk, UCL_ESYNTAX, "no quote at the end of json string", &parser->err);
891262395Sbapt	return false;
892262395Sbapt}
893262395Sbapt
894262395Sbapt/**
895262395Sbapt * Parse a key in an object
896262395Sbapt * @param parser
897262395Sbapt * @param chunk
898262395Sbapt * @return true if a key has been parsed
899262395Sbapt */
900262395Sbaptstatic bool
901262395Sbaptucl_parse_key (struct ucl_parser *parser, struct ucl_chunk *chunk, bool *next_key, bool *end_of_object)
902262395Sbapt{
903262395Sbapt	const unsigned char *p, *c = NULL, *end, *t;
904262395Sbapt	const char *key = NULL;
905262395Sbapt	bool got_quote = false, got_eq = false, got_semicolon = false,
906262395Sbapt			need_unescape = false, ucl_escape = false, var_expand = false,
907262395Sbapt			got_content = false, got_sep = false;
908262395Sbapt	ucl_object_t *nobj, *tobj;
909262395Sbapt	ucl_hash_t *container;
910262395Sbapt	ssize_t keylen;
911262395Sbapt
912262395Sbapt	p = chunk->pos;
913262395Sbapt
914262395Sbapt	if (*p == '.') {
915262395Sbapt		/* It is macro actually */
916262395Sbapt		ucl_chunk_skipc (chunk, p);
917262395Sbapt		parser->prev_state = parser->state;
918262395Sbapt		parser->state = UCL_STATE_MACRO_NAME;
919262395Sbapt		return true;
920262395Sbapt	}
921262395Sbapt	while (p < chunk->end) {
922262395Sbapt		/*
923262395Sbapt		 * A key must start with alpha, number, '/' or '_' and end with space character
924262395Sbapt		 */
925262395Sbapt		if (c == NULL) {
926262395Sbapt			if (chunk->remain >= 2 && ucl_lex_is_comment (p[0], p[1])) {
927262395Sbapt				if (!ucl_skip_comments (parser)) {
928262395Sbapt					return false;
929262395Sbapt				}
930262395Sbapt				p = chunk->pos;
931262395Sbapt			}
932262395Sbapt			else if (ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE)) {
933262395Sbapt				ucl_chunk_skipc (chunk, p);
934262395Sbapt			}
935262395Sbapt			else if (ucl_test_character (*p, UCL_CHARACTER_KEY_START)) {
936262395Sbapt				/* The first symbol */
937262395Sbapt				c = p;
938262395Sbapt				ucl_chunk_skipc (chunk, p);
939262395Sbapt				got_content = true;
940262395Sbapt			}
941262395Sbapt			else if (*p == '"') {
942262395Sbapt				/* JSON style key */
943262395Sbapt				c = p + 1;
944262395Sbapt				got_quote = true;
945262395Sbapt				got_content = true;
946262395Sbapt				ucl_chunk_skipc (chunk, p);
947262395Sbapt			}
948262395Sbapt			else if (*p == '}') {
949262395Sbapt				/* We have actually end of an object */
950262395Sbapt				*end_of_object = true;
951262395Sbapt				return true;
952262395Sbapt			}
953262395Sbapt			else if (*p == '.') {
954262395Sbapt				ucl_chunk_skipc (chunk, p);
955262395Sbapt				parser->prev_state = parser->state;
956262395Sbapt				parser->state = UCL_STATE_MACRO_NAME;
957262395Sbapt				return true;
958262395Sbapt			}
959262395Sbapt			else {
960262395Sbapt				/* Invalid identifier */
961262395Sbapt				ucl_set_err (chunk, UCL_ESYNTAX, "key must begin with a letter", &parser->err);
962262395Sbapt				return false;
963262395Sbapt			}
964262395Sbapt		}
965262395Sbapt		else {
966262395Sbapt			/* Parse the body of a key */
967262395Sbapt			if (!got_quote) {
968262395Sbapt				if (ucl_test_character (*p, UCL_CHARACTER_KEY)) {
969262395Sbapt					got_content = true;
970262395Sbapt					ucl_chunk_skipc (chunk, p);
971262395Sbapt				}
972262395Sbapt				else if (ucl_test_character (*p, UCL_CHARACTER_KEY_SEP)) {
973262395Sbapt					end = p;
974262395Sbapt					break;
975262395Sbapt				}
976262395Sbapt				else {
977262395Sbapt					ucl_set_err (chunk, UCL_ESYNTAX, "invalid character in a key", &parser->err);
978262395Sbapt					return false;
979262395Sbapt				}
980262395Sbapt			}
981262395Sbapt			else {
982262395Sbapt				/* We need to parse json like quoted string */
983262395Sbapt				if (!ucl_lex_json_string (parser, chunk, &need_unescape, &ucl_escape, &var_expand)) {
984262395Sbapt					return false;
985262395Sbapt				}
986262395Sbapt				/* Always escape keys obtained via json */
987262395Sbapt				end = chunk->pos - 1;
988262395Sbapt				p = chunk->pos;
989262395Sbapt				break;
990262395Sbapt			}
991262395Sbapt		}
992262395Sbapt	}
993262395Sbapt
994262395Sbapt	if (p >= chunk->end && got_content) {
995262395Sbapt		ucl_set_err (chunk, UCL_ESYNTAX, "unfinished key", &parser->err);
996262395Sbapt		return false;
997262395Sbapt	}
998262395Sbapt	else if (!got_content) {
999262395Sbapt		return true;
1000262395Sbapt	}
1001262395Sbapt	*end_of_object = false;
1002262395Sbapt	/* We are now at the end of the key, need to parse the rest */
1003262395Sbapt	while (p < chunk->end) {
1004262395Sbapt		if (ucl_test_character (*p, UCL_CHARACTER_WHITESPACE)) {
1005262395Sbapt			ucl_chunk_skipc (chunk, p);
1006262395Sbapt		}
1007262395Sbapt		else if (*p == '=') {
1008262395Sbapt			if (!got_eq && !got_semicolon) {
1009262395Sbapt				ucl_chunk_skipc (chunk, p);
1010262395Sbapt				got_eq = true;
1011262395Sbapt			}
1012262395Sbapt			else {
1013262395Sbapt				ucl_set_err (chunk, UCL_ESYNTAX, "unexpected '=' character", &parser->err);
1014262395Sbapt				return false;
1015262395Sbapt			}
1016262395Sbapt		}
1017262395Sbapt		else if (*p == ':') {
1018262395Sbapt			if (!got_eq && !got_semicolon) {
1019262395Sbapt				ucl_chunk_skipc (chunk, p);
1020262395Sbapt				got_semicolon = true;
1021262395Sbapt			}
1022262395Sbapt			else {
1023262395Sbapt				ucl_set_err (chunk, UCL_ESYNTAX, "unexpected ':' character", &parser->err);
1024262395Sbapt				return false;
1025262395Sbapt			}
1026262395Sbapt		}
1027262395Sbapt		else if (chunk->remain >= 2 && ucl_lex_is_comment (p[0], p[1])) {
1028262395Sbapt			/* Check for comment */
1029262395Sbapt			if (!ucl_skip_comments (parser)) {
1030262395Sbapt				return false;
1031262395Sbapt			}
1032262395Sbapt			p = chunk->pos;
1033262395Sbapt		}
1034262395Sbapt		else {
1035262395Sbapt			/* Start value */
1036262395Sbapt			break;
1037262395Sbapt		}
1038262395Sbapt	}
1039262395Sbapt
1040262395Sbapt	if (p >= chunk->end && got_content) {
1041262395Sbapt		ucl_set_err (chunk, UCL_ESYNTAX, "unfinished key", &parser->err);
1042262395Sbapt		return false;
1043262395Sbapt	}
1044262395Sbapt
1045262395Sbapt	got_sep = got_semicolon || got_eq;
1046262395Sbapt
1047262395Sbapt	if (!got_sep) {
1048262395Sbapt		/*
1049262395Sbapt		 * Maybe we have more keys nested, so search for termination character.
1050262395Sbapt		 * Possible choices:
1051262395Sbapt		 * 1) key1 key2 ... keyN [:=] value <- we treat that as error
1052262395Sbapt		 * 2) key1 ... keyN {} or [] <- we treat that as nested objects
1053262395Sbapt		 * 3) key1 value[;,\n] <- we treat that as linear object
1054262395Sbapt		 */
1055262395Sbapt		t = p;
1056262395Sbapt		*next_key = false;
1057262395Sbapt		while (ucl_test_character (*t, UCL_CHARACTER_WHITESPACE)) {
1058262395Sbapt			t ++;
1059262395Sbapt		}
1060262395Sbapt		/* Check first non-space character after a key */
1061262395Sbapt		if (*t != '{' && *t != '[') {
1062262395Sbapt			while (t < chunk->end) {
1063262395Sbapt				if (*t == ',' || *t == ';' || *t == '\n' || *t == '\r') {
1064262395Sbapt					break;
1065262395Sbapt				}
1066262395Sbapt				else if (*t == '{' || *t == '[') {
1067262395Sbapt					*next_key = true;
1068262395Sbapt					break;
1069262395Sbapt				}
1070262395Sbapt				t ++;
1071262395Sbapt			}
1072262395Sbapt		}
1073262395Sbapt	}
1074262395Sbapt
1075262395Sbapt	/* Create a new object */
1076262395Sbapt	nobj = ucl_object_new ();
1077262395Sbapt	keylen = ucl_copy_or_store_ptr (parser, c, &nobj->trash_stack[UCL_TRASH_KEY],
1078262395Sbapt			&key, end - c, need_unescape, parser->flags & UCL_PARSER_KEY_LOWERCASE, false);
1079262395Sbapt	if (keylen == -1) {
1080262395Sbapt		ucl_object_free(nobj);
1081262395Sbapt		return false;
1082262395Sbapt	}
1083262395Sbapt	else if (keylen == 0) {
1084262395Sbapt		ucl_set_err (chunk, UCL_ESYNTAX, "empty keys are not allowed", &parser->err);
1085262395Sbapt		ucl_object_free(nobj);
1086262395Sbapt		return false;
1087262395Sbapt	}
1088262395Sbapt
1089262395Sbapt	container = parser->stack->obj->value.ov;
1090262395Sbapt	nobj->key = key;
1091262395Sbapt	nobj->keylen = keylen;
1092262395Sbapt	tobj = ucl_hash_search_obj (container, nobj);
1093262395Sbapt	if (tobj == NULL) {
1094262395Sbapt		container = ucl_hash_insert_object (container, nobj);
1095262395Sbapt		nobj->prev = nobj;
1096262395Sbapt		nobj->next = NULL;
1097262395Sbapt		parser->stack->obj->len ++;
1098262395Sbapt	}
1099262395Sbapt	else {
1100262395Sbapt		DL_APPEND (tobj, nobj);
1101262395Sbapt	}
1102262395Sbapt
1103262395Sbapt	if (ucl_escape) {
1104262395Sbapt		nobj->flags |= UCL_OBJECT_NEED_KEY_ESCAPE;
1105262395Sbapt	}
1106262395Sbapt	parser->stack->obj->value.ov = container;
1107262395Sbapt
1108262395Sbapt	parser->cur_obj = nobj;
1109262395Sbapt
1110262395Sbapt	return true;
1111262395Sbapt}
1112262395Sbapt
1113262395Sbapt/**
1114262395Sbapt * Parse a cl string
1115262395Sbapt * @param parser
1116262395Sbapt * @param chunk
1117262395Sbapt * @return true if a key has been parsed
1118262395Sbapt */
1119262395Sbaptstatic bool
1120262395Sbaptucl_parse_string_value (struct ucl_parser *parser,
1121262395Sbapt		struct ucl_chunk *chunk, bool *var_expand, bool *need_unescape)
1122262395Sbapt{
1123262395Sbapt	const unsigned char *p;
1124262395Sbapt	enum {
1125262395Sbapt		UCL_BRACE_ROUND = 0,
1126262395Sbapt		UCL_BRACE_SQUARE,
1127262395Sbapt		UCL_BRACE_FIGURE
1128262395Sbapt	};
1129262395Sbapt	int braces[3][2] = {{0, 0}, {0, 0}, {0, 0}};
1130262395Sbapt
1131262395Sbapt	p = chunk->pos;
1132262395Sbapt
1133262395Sbapt	while (p < chunk->end) {
1134262395Sbapt
1135262395Sbapt		/* Skip pairs of figure braces */
1136262395Sbapt		if (*p == '{') {
1137262395Sbapt			braces[UCL_BRACE_FIGURE][0] ++;
1138262395Sbapt		}
1139262395Sbapt		else if (*p == '}') {
1140262395Sbapt			braces[UCL_BRACE_FIGURE][1] ++;
1141262395Sbapt			if (braces[UCL_BRACE_FIGURE][1] <= braces[UCL_BRACE_FIGURE][0]) {
1142262395Sbapt				/* This is not a termination symbol, continue */
1143262395Sbapt				ucl_chunk_skipc (chunk, p);
1144262395Sbapt				continue;
1145262395Sbapt			}
1146262395Sbapt		}
1147262395Sbapt		/* Skip pairs of square braces */
1148262395Sbapt		else if (*p == '[') {
1149262395Sbapt			braces[UCL_BRACE_SQUARE][0] ++;
1150262395Sbapt		}
1151262395Sbapt		else if (*p == ']') {
1152262395Sbapt			braces[UCL_BRACE_SQUARE][1] ++;
1153262395Sbapt			if (braces[UCL_BRACE_SQUARE][1] <= braces[UCL_BRACE_SQUARE][0]) {
1154262395Sbapt				/* This is not a termination symbol, continue */
1155262395Sbapt				ucl_chunk_skipc (chunk, p);
1156262395Sbapt				continue;
1157262395Sbapt			}
1158262395Sbapt		}
1159262395Sbapt		else if (*p == '$') {
1160262395Sbapt			*var_expand = true;
1161262395Sbapt		}
1162262395Sbapt		else if (*p == '\\') {
1163262395Sbapt			*need_unescape = true;
1164262395Sbapt			ucl_chunk_skipc (chunk, p);
1165262395Sbapt			if (p < chunk->end) {
1166262395Sbapt				ucl_chunk_skipc (chunk, p);
1167262395Sbapt			}
1168262395Sbapt			continue;
1169262395Sbapt		}
1170262395Sbapt
1171262395Sbapt		if (ucl_lex_is_atom_end (*p) || (chunk->remain >= 2 && ucl_lex_is_comment (p[0], p[1]))) {
1172262395Sbapt			break;
1173262395Sbapt		}
1174262395Sbapt		ucl_chunk_skipc (chunk, p);
1175262395Sbapt	}
1176262395Sbapt
1177262395Sbapt	if (p >= chunk->end) {
1178262395Sbapt		ucl_set_err (chunk, UCL_ESYNTAX, "unfinished value", &parser->err);
1179262395Sbapt		return false;
1180262395Sbapt	}
1181262395Sbapt
1182262395Sbapt	return true;
1183262395Sbapt}
1184262395Sbapt
1185262395Sbapt/**
1186262395Sbapt * Parse multiline string ending with \n{term}\n
1187262395Sbapt * @param parser
1188262395Sbapt * @param chunk
1189262395Sbapt * @param term
1190262395Sbapt * @param term_len
1191262395Sbapt * @return size of multiline string or 0 in case of error
1192262395Sbapt */
1193262395Sbaptstatic int
1194262395Sbaptucl_parse_multiline_string (struct ucl_parser *parser,
1195262395Sbapt		struct ucl_chunk *chunk, const unsigned char *term,
1196262395Sbapt		int term_len, unsigned char const **beg,
1197262395Sbapt		bool *var_expand)
1198262395Sbapt{
1199262395Sbapt	const unsigned char *p, *c;
1200262395Sbapt	bool newline = false;
1201262395Sbapt	int len = 0;
1202262395Sbapt
1203262395Sbapt	p = chunk->pos;
1204262395Sbapt
1205262395Sbapt	c = p;
1206262395Sbapt
1207262395Sbapt	while (p < chunk->end) {
1208262395Sbapt		if (newline) {
1209262395Sbapt			if (chunk->end - p < term_len) {
1210262395Sbapt				return 0;
1211262395Sbapt			}
1212262395Sbapt			else if (memcmp (p, term, term_len) == 0 && (p[term_len] == '\n' || p[term_len] == '\r')) {
1213262395Sbapt				len = p - c;
1214262395Sbapt				chunk->remain -= term_len;
1215262395Sbapt				chunk->pos = p + term_len;
1216262395Sbapt				chunk->column = term_len;
1217262395Sbapt				*beg = c;
1218262395Sbapt				break;
1219262395Sbapt			}
1220262395Sbapt		}
1221262395Sbapt		if (*p == '\n') {
1222262395Sbapt			newline = true;
1223262395Sbapt		}
1224262395Sbapt		else {
1225262395Sbapt			if (*p == '$') {
1226262395Sbapt				*var_expand = true;
1227262395Sbapt			}
1228262395Sbapt			newline = false;
1229262395Sbapt		}
1230262395Sbapt		ucl_chunk_skipc (chunk, p);
1231262395Sbapt	}
1232262395Sbapt
1233262395Sbapt	return len;
1234262395Sbapt}
1235262395Sbapt
1236263032Sbaptstatic ucl_object_t*
1237263032Sbaptucl_get_value_object (struct ucl_parser *parser)
1238263032Sbapt{
1239263032Sbapt	ucl_object_t *t, *obj = NULL;
1240263032Sbapt
1241263032Sbapt	if (parser->stack->obj->type == UCL_ARRAY) {
1242263032Sbapt		/* Object must be allocated */
1243263032Sbapt		obj = ucl_object_new ();
1244263032Sbapt		t = parser->stack->obj->value.av;
1245263032Sbapt		DL_APPEND (t, obj);
1246263032Sbapt		parser->cur_obj = obj;
1247263032Sbapt		parser->stack->obj->value.av = t;
1248263032Sbapt		parser->stack->obj->len ++;
1249263032Sbapt	}
1250263032Sbapt	else {
1251263032Sbapt		/* Object has been already allocated */
1252263032Sbapt		obj = parser->cur_obj;
1253263032Sbapt	}
1254263032Sbapt
1255263032Sbapt	return obj;
1256263032Sbapt}
1257263032Sbapt
1258262395Sbapt/**
1259262395Sbapt * Handle value data
1260262395Sbapt * @param parser
1261262395Sbapt * @param chunk
1262262395Sbapt * @return
1263262395Sbapt */
1264262395Sbaptstatic bool
1265262395Sbaptucl_parse_value (struct ucl_parser *parser, struct ucl_chunk *chunk)
1266262395Sbapt{
1267262395Sbapt	const unsigned char *p, *c;
1268263032Sbapt	ucl_object_t *obj = NULL;
1269262395Sbapt	unsigned int stripped_spaces;
1270262395Sbapt	int str_len;
1271262395Sbapt	bool need_unescape = false, ucl_escape = false, var_expand = false;
1272262395Sbapt
1273262395Sbapt	p = chunk->pos;
1274262395Sbapt
1275263032Sbapt	/* Skip any spaces and comments */
1276263032Sbapt	if (ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE) ||
1277263032Sbapt			(chunk->remain >= 2 && ucl_lex_is_comment (p[0], p[1]))) {
1278263032Sbapt		while (p < chunk->end && ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE)) {
1279263032Sbapt			ucl_chunk_skipc (chunk, p);
1280263032Sbapt		}
1281263032Sbapt		if (!ucl_skip_comments (parser)) {
1282263032Sbapt			return false;
1283263032Sbapt		}
1284263032Sbapt		p = chunk->pos;
1285263032Sbapt	}
1286263032Sbapt
1287262395Sbapt	while (p < chunk->end) {
1288262395Sbapt		c = p;
1289262395Sbapt		switch (*p) {
1290262395Sbapt		case '"':
1291263032Sbapt			obj = ucl_get_value_object (parser);
1292262395Sbapt			ucl_chunk_skipc (chunk, p);
1293262395Sbapt			if (!ucl_lex_json_string (parser, chunk, &need_unescape, &ucl_escape, &var_expand)) {
1294262395Sbapt				return false;
1295262395Sbapt			}
1296262395Sbapt			str_len = chunk->pos - c - 2;
1297262395Sbapt			obj->type = UCL_STRING;
1298262395Sbapt			if ((str_len = ucl_copy_or_store_ptr (parser, c + 1, &obj->trash_stack[UCL_TRASH_VALUE],
1299262395Sbapt					&obj->value.sv, str_len, need_unescape, false, var_expand)) == -1) {
1300262395Sbapt				return false;
1301262395Sbapt			}
1302262395Sbapt			obj->len = str_len;
1303262395Sbapt			parser->state = UCL_STATE_AFTER_VALUE;
1304262395Sbapt			p = chunk->pos;
1305262395Sbapt			return true;
1306262395Sbapt			break;
1307262395Sbapt		case '{':
1308263032Sbapt			obj = ucl_get_value_object (parser);
1309262395Sbapt			/* We have a new object */
1310262395Sbapt			obj = ucl_add_parser_stack (obj, parser, false, parser->stack->level);
1311262395Sbapt
1312262395Sbapt			ucl_chunk_skipc (chunk, p);
1313262395Sbapt			return true;
1314262395Sbapt			break;
1315262395Sbapt		case '[':
1316263032Sbapt			obj = ucl_get_value_object (parser);
1317262395Sbapt			/* We have a new array */
1318262395Sbapt			obj = ucl_add_parser_stack (obj, parser, true, parser->stack->level);
1319262395Sbapt
1320262395Sbapt			ucl_chunk_skipc (chunk, p);
1321262395Sbapt			return true;
1322262395Sbapt			break;
1323263032Sbapt		case ']':
1324263032Sbapt			/* We have the array ending */
1325263032Sbapt			if (parser->stack && parser->stack->obj->type == UCL_ARRAY) {
1326263032Sbapt				parser->state = UCL_STATE_AFTER_VALUE;
1327263032Sbapt				return true;
1328263032Sbapt			}
1329263032Sbapt			else {
1330263032Sbapt				goto parse_string;
1331263032Sbapt			}
1332263032Sbapt			break;
1333262395Sbapt		case '<':
1334263032Sbapt			obj = ucl_get_value_object (parser);
1335262395Sbapt			/* We have something like multiline value, which must be <<[A-Z]+\n */
1336262395Sbapt			if (chunk->end - p > 3) {
1337262395Sbapt				if (memcmp (p, "<<", 2) == 0) {
1338262395Sbapt					p += 2;
1339262395Sbapt					/* We allow only uppercase characters in multiline definitions */
1340262395Sbapt					while (p < chunk->end && *p >= 'A' && *p <= 'Z') {
1341262395Sbapt						p ++;
1342262395Sbapt					}
1343262395Sbapt					if (*p =='\n') {
1344262395Sbapt						/* Set chunk positions and start multiline parsing */
1345262395Sbapt						c += 2;
1346262395Sbapt						chunk->remain -= p - c;
1347262395Sbapt						chunk->pos = p + 1;
1348262395Sbapt						chunk->column = 0;
1349262395Sbapt						chunk->line ++;
1350262395Sbapt						if ((str_len = ucl_parse_multiline_string (parser, chunk, c,
1351262395Sbapt								p - c, &c, &var_expand)) == 0) {
1352262395Sbapt							ucl_set_err (chunk, UCL_ESYNTAX, "unterminated multiline value", &parser->err);
1353262395Sbapt							return false;
1354262395Sbapt						}
1355262395Sbapt						obj->type = UCL_STRING;
1356262395Sbapt						if ((str_len = ucl_copy_or_store_ptr (parser, c, &obj->trash_stack[UCL_TRASH_VALUE],
1357262395Sbapt							&obj->value.sv, str_len - 1, false, false, var_expand)) == -1) {
1358262395Sbapt							return false;
1359262395Sbapt						}
1360262395Sbapt						obj->len = str_len;
1361262395Sbapt						parser->state = UCL_STATE_AFTER_VALUE;
1362262395Sbapt						return true;
1363262395Sbapt					}
1364262395Sbapt				}
1365262395Sbapt			}
1366262395Sbapt			/* Fallback to ordinary strings */
1367262395Sbapt		default:
1368263032Sbaptparse_string:
1369263032Sbapt			if (obj == NULL) {
1370263032Sbapt				obj = ucl_get_value_object (parser);
1371262395Sbapt			}
1372262395Sbapt			/* Parse atom */
1373262395Sbapt			if (ucl_test_character (*p, UCL_CHARACTER_VALUE_DIGIT_START)) {
1374262395Sbapt				if (!ucl_lex_number (parser, chunk, obj)) {
1375262395Sbapt					if (parser->state == UCL_STATE_ERROR) {
1376262395Sbapt						return false;
1377262395Sbapt					}
1378262395Sbapt				}
1379262395Sbapt				else {
1380262395Sbapt					parser->state = UCL_STATE_AFTER_VALUE;
1381262395Sbapt					return true;
1382262395Sbapt				}
1383262395Sbapt				/* Fallback to normal string */
1384262395Sbapt			}
1385262395Sbapt
1386262395Sbapt			if (!ucl_parse_string_value (parser, chunk, &var_expand, &need_unescape)) {
1387262395Sbapt				return false;
1388262395Sbapt			}
1389262395Sbapt			/* Cut trailing spaces */
1390262395Sbapt			stripped_spaces = 0;
1391262395Sbapt			while (ucl_test_character (*(chunk->pos - 1 - stripped_spaces),
1392262395Sbapt					UCL_CHARACTER_WHITESPACE)) {
1393262395Sbapt				stripped_spaces ++;
1394262395Sbapt			}
1395262395Sbapt			str_len = chunk->pos - c - stripped_spaces;
1396262395Sbapt			if (str_len <= 0) {
1397262395Sbapt				ucl_set_err (chunk, 0, "string value must not be empty", &parser->err);
1398262395Sbapt				return false;
1399262395Sbapt			}
1400262395Sbapt			else if (str_len == 4 && memcmp (c, "null", 4) == 0) {
1401262395Sbapt				obj->len = 0;
1402262395Sbapt				obj->type = UCL_NULL;
1403262395Sbapt			}
1404262395Sbapt			else if (!ucl_maybe_parse_boolean (obj, c, str_len)) {
1405262395Sbapt				obj->type = UCL_STRING;
1406262395Sbapt				if ((str_len = ucl_copy_or_store_ptr (parser, c, &obj->trash_stack[UCL_TRASH_VALUE],
1407262395Sbapt						&obj->value.sv, str_len, need_unescape,
1408262395Sbapt						false, var_expand)) == -1) {
1409262395Sbapt					return false;
1410262395Sbapt				}
1411262395Sbapt				obj->len = str_len;
1412262395Sbapt			}
1413262395Sbapt			parser->state = UCL_STATE_AFTER_VALUE;
1414262395Sbapt			p = chunk->pos;
1415262395Sbapt
1416262395Sbapt			return true;
1417262395Sbapt			break;
1418262395Sbapt		}
1419262395Sbapt	}
1420262395Sbapt
1421262395Sbapt	return true;
1422262395Sbapt}
1423262395Sbapt
1424262395Sbapt/**
1425262395Sbapt * Handle after value data
1426262395Sbapt * @param parser
1427262395Sbapt * @param chunk
1428262395Sbapt * @return
1429262395Sbapt */
1430262395Sbaptstatic bool
1431262395Sbaptucl_parse_after_value (struct ucl_parser *parser, struct ucl_chunk *chunk)
1432262395Sbapt{
1433262395Sbapt	const unsigned char *p;
1434262395Sbapt	bool got_sep = false;
1435262395Sbapt	struct ucl_stack *st;
1436262395Sbapt
1437262395Sbapt	p = chunk->pos;
1438262395Sbapt
1439262395Sbapt	while (p < chunk->end) {
1440262395Sbapt		if (ucl_test_character (*p, UCL_CHARACTER_WHITESPACE)) {
1441262395Sbapt			/* Skip whitespaces */
1442262395Sbapt			ucl_chunk_skipc (chunk, p);
1443262395Sbapt		}
1444262395Sbapt		else if (chunk->remain >= 2 && ucl_lex_is_comment (p[0], p[1])) {
1445262395Sbapt			/* Skip comment */
1446262395Sbapt			if (!ucl_skip_comments (parser)) {
1447262395Sbapt				return false;
1448262395Sbapt			}
1449262395Sbapt			/* Treat comment as a separator */
1450262395Sbapt			got_sep = true;
1451262395Sbapt			p = chunk->pos;
1452262395Sbapt		}
1453262395Sbapt		else if (ucl_test_character (*p, UCL_CHARACTER_VALUE_END)) {
1454262395Sbapt			if (*p == '}' || *p == ']') {
1455262395Sbapt				if (parser->stack == NULL) {
1456262395Sbapt					ucl_set_err (chunk, UCL_ESYNTAX, "end of array or object detected without corresponding start", &parser->err);
1457262395Sbapt					return false;
1458262395Sbapt				}
1459262395Sbapt				if ((*p == '}' && parser->stack->obj->type == UCL_OBJECT) ||
1460262395Sbapt						(*p == ']' && parser->stack->obj->type == UCL_ARRAY)) {
1461262395Sbapt
1462262395Sbapt					/* Pop all nested objects from a stack */
1463262395Sbapt					st = parser->stack;
1464262395Sbapt					parser->stack = st->next;
1465262395Sbapt					UCL_FREE (sizeof (struct ucl_stack), st);
1466262395Sbapt
1467262395Sbapt					while (parser->stack != NULL) {
1468262395Sbapt						st = parser->stack;
1469262395Sbapt						if (st->next == NULL || st->next->level == st->level) {
1470262395Sbapt							break;
1471262395Sbapt						}
1472262395Sbapt						parser->stack = st->next;
1473262395Sbapt						UCL_FREE (sizeof (struct ucl_stack), st);
1474262395Sbapt					}
1475262395Sbapt				}
1476262395Sbapt				else {
1477262395Sbapt					ucl_set_err (chunk, UCL_ESYNTAX, "unexpected terminating symbol detected", &parser->err);
1478262395Sbapt					return false;
1479262395Sbapt				}
1480262395Sbapt
1481262395Sbapt				if (parser->stack == NULL) {
1482262395Sbapt					/* Ignore everything after a top object */
1483262395Sbapt					return true;
1484262395Sbapt				}
1485262395Sbapt				else {
1486262395Sbapt					ucl_chunk_skipc (chunk, p);
1487262395Sbapt				}
1488262395Sbapt				got_sep = true;
1489262395Sbapt			}
1490262395Sbapt			else {
1491262395Sbapt				/* Got a separator */
1492262395Sbapt				got_sep = true;
1493262395Sbapt				ucl_chunk_skipc (chunk, p);
1494262395Sbapt			}
1495262395Sbapt		}
1496262395Sbapt		else {
1497262395Sbapt			/* Anything else */
1498262395Sbapt			if (!got_sep) {
1499262395Sbapt				ucl_set_err (chunk, UCL_ESYNTAX, "delimiter is missing", &parser->err);
1500262395Sbapt				return false;
1501262395Sbapt			}
1502262395Sbapt			return true;
1503262395Sbapt		}
1504262395Sbapt	}
1505262395Sbapt
1506262395Sbapt	return true;
1507262395Sbapt}
1508262395Sbapt
1509262395Sbapt/**
1510262395Sbapt * Handle macro data
1511262395Sbapt * @param parser
1512262395Sbapt * @param chunk
1513262395Sbapt * @return
1514262395Sbapt */
1515262395Sbaptstatic bool
1516262395Sbaptucl_parse_macro_value (struct ucl_parser *parser,
1517262395Sbapt		struct ucl_chunk *chunk, struct ucl_macro *macro,
1518262395Sbapt		unsigned char const **macro_start, size_t *macro_len)
1519262395Sbapt{
1520262395Sbapt	const unsigned char *p, *c;
1521262395Sbapt	bool need_unescape = false, ucl_escape = false, var_expand = false;
1522262395Sbapt
1523262395Sbapt	p = chunk->pos;
1524262395Sbapt
1525262395Sbapt	switch (*p) {
1526262395Sbapt	case '"':
1527262395Sbapt		/* We have macro value encoded in quotes */
1528262395Sbapt		c = p;
1529262395Sbapt		ucl_chunk_skipc (chunk, p);
1530262395Sbapt		if (!ucl_lex_json_string (parser, chunk, &need_unescape, &ucl_escape, &var_expand)) {
1531262395Sbapt			return false;
1532262395Sbapt		}
1533262395Sbapt
1534262395Sbapt		*macro_start = c + 1;
1535262395Sbapt		*macro_len = chunk->pos - c - 2;
1536262395Sbapt		p = chunk->pos;
1537262395Sbapt		break;
1538262395Sbapt	case '{':
1539262395Sbapt		/* We got a multiline macro body */
1540262395Sbapt		ucl_chunk_skipc (chunk, p);
1541262395Sbapt		/* Skip spaces at the beginning */
1542262395Sbapt		while (p < chunk->end) {
1543262395Sbapt			if (ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE)) {
1544262395Sbapt				ucl_chunk_skipc (chunk, p);
1545262395Sbapt			}
1546262395Sbapt			else {
1547262395Sbapt				break;
1548262395Sbapt			}
1549262395Sbapt		}
1550262395Sbapt		c = p;
1551262395Sbapt		while (p < chunk->end) {
1552262395Sbapt			if (*p == '}') {
1553262395Sbapt				break;
1554262395Sbapt			}
1555262395Sbapt			ucl_chunk_skipc (chunk, p);
1556262395Sbapt		}
1557262395Sbapt		*macro_start = c;
1558262395Sbapt		*macro_len = p - c;
1559262395Sbapt		ucl_chunk_skipc (chunk, p);
1560262395Sbapt		break;
1561262395Sbapt	default:
1562262395Sbapt		/* Macro is not enclosed in quotes or braces */
1563262395Sbapt		c = p;
1564262395Sbapt		while (p < chunk->end) {
1565262395Sbapt			if (ucl_lex_is_atom_end (*p)) {
1566262395Sbapt				break;
1567262395Sbapt			}
1568262395Sbapt			ucl_chunk_skipc (chunk, p);
1569262395Sbapt		}
1570262395Sbapt		*macro_start = c;
1571262395Sbapt		*macro_len = p - c;
1572262395Sbapt		break;
1573262395Sbapt	}
1574262395Sbapt
1575262395Sbapt	/* We are at the end of a macro */
1576262395Sbapt	/* Skip ';' and space characters and return to previous state */
1577262395Sbapt	while (p < chunk->end) {
1578262395Sbapt		if (!ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE) && *p != ';') {
1579262395Sbapt			break;
1580262395Sbapt		}
1581262395Sbapt		ucl_chunk_skipc (chunk, p);
1582262395Sbapt	}
1583262395Sbapt	return true;
1584262395Sbapt}
1585262395Sbapt
1586262395Sbapt/**
1587262395Sbapt * Handle the main states of rcl parser
1588262395Sbapt * @param parser parser structure
1589262395Sbapt * @param data the pointer to the beginning of a chunk
1590262395Sbapt * @param len the length of a chunk
1591262395Sbapt * @return true if chunk has been parsed and false in case of error
1592262395Sbapt */
1593262395Sbaptstatic bool
1594262395Sbaptucl_state_machine (struct ucl_parser *parser)
1595262395Sbapt{
1596262395Sbapt	ucl_object_t *obj;
1597262395Sbapt	struct ucl_chunk *chunk = parser->chunks;
1598262395Sbapt	const unsigned char *p, *c = NULL, *macro_start = NULL;
1599262395Sbapt	unsigned char *macro_escaped;
1600262395Sbapt	size_t macro_len = 0;
1601262395Sbapt	struct ucl_macro *macro = NULL;
1602262395Sbapt	bool next_key = false, end_of_object = false;
1603262395Sbapt
1604262395Sbapt	if (parser->top_obj == NULL) {
1605262395Sbapt		if (*chunk->pos == '[') {
1606262395Sbapt			obj = ucl_add_parser_stack (NULL, parser, true, 0);
1607262395Sbapt		}
1608262395Sbapt		else {
1609262395Sbapt			obj = ucl_add_parser_stack (NULL, parser, false, 0);
1610262395Sbapt		}
1611262395Sbapt		parser->top_obj = obj;
1612262395Sbapt		parser->cur_obj = obj;
1613262395Sbapt		parser->state = UCL_STATE_INIT;
1614262395Sbapt	}
1615262395Sbapt
1616262395Sbapt	p = chunk->pos;
1617262395Sbapt	while (chunk->pos < chunk->end) {
1618262395Sbapt		switch (parser->state) {
1619262395Sbapt		case UCL_STATE_INIT:
1620262395Sbapt			/*
1621262395Sbapt			 * At the init state we can either go to the parse array or object
1622262395Sbapt			 * if we got [ or { correspondingly or can just treat new data as
1623262395Sbapt			 * a key of newly created object
1624262395Sbapt			 */
1625262395Sbapt			obj = parser->cur_obj;
1626262395Sbapt			if (!ucl_skip_comments (parser)) {
1627262395Sbapt				parser->prev_state = parser->state;
1628262395Sbapt				parser->state = UCL_STATE_ERROR;
1629262395Sbapt				return false;
1630262395Sbapt			}
1631262395Sbapt			else {
1632262395Sbapt				p = chunk->pos;
1633262395Sbapt				if (*p == '[') {
1634262395Sbapt					parser->state = UCL_STATE_VALUE;
1635262395Sbapt					ucl_chunk_skipc (chunk, p);
1636262395Sbapt				}
1637262395Sbapt				else {
1638262395Sbapt					parser->state = UCL_STATE_KEY;
1639262395Sbapt					if (*p == '{') {
1640262395Sbapt						ucl_chunk_skipc (chunk, p);
1641262395Sbapt					}
1642262395Sbapt				}
1643262395Sbapt			}
1644262395Sbapt			break;
1645262395Sbapt		case UCL_STATE_KEY:
1646262395Sbapt			/* Skip any spaces */
1647262395Sbapt			while (p < chunk->end && ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE)) {
1648262395Sbapt				ucl_chunk_skipc (chunk, p);
1649262395Sbapt			}
1650262395Sbapt			if (*p == '}') {
1651262395Sbapt				/* We have the end of an object */
1652262395Sbapt				parser->state = UCL_STATE_AFTER_VALUE;
1653262395Sbapt				continue;
1654262395Sbapt			}
1655262395Sbapt			if (parser->stack == NULL) {
1656262395Sbapt				/* No objects are on stack, but we want to parse a key */
1657262395Sbapt				ucl_set_err (chunk, UCL_ESYNTAX, "top object is finished but the parser "
1658262395Sbapt						"expects a key", &parser->err);
1659262395Sbapt				parser->prev_state = parser->state;
1660262395Sbapt				parser->state = UCL_STATE_ERROR;
1661262395Sbapt				return false;
1662262395Sbapt			}
1663262395Sbapt			if (!ucl_parse_key (parser, chunk, &next_key, &end_of_object)) {
1664262395Sbapt				parser->prev_state = parser->state;
1665262395Sbapt				parser->state = UCL_STATE_ERROR;
1666262395Sbapt				return false;
1667262395Sbapt			}
1668262395Sbapt			if (end_of_object) {
1669262395Sbapt				p = chunk->pos;
1670262395Sbapt				parser->state = UCL_STATE_AFTER_VALUE;
1671262395Sbapt				continue;
1672262395Sbapt			}
1673262395Sbapt			else if (parser->state != UCL_STATE_MACRO_NAME) {
1674262395Sbapt				if (next_key && parser->stack->obj->type == UCL_OBJECT) {
1675262395Sbapt					/* Parse more keys and nest objects accordingly */
1676262395Sbapt					obj = ucl_add_parser_stack (parser->cur_obj, parser, false, parser->stack->level + 1);
1677262395Sbapt				}
1678262395Sbapt				else {
1679262395Sbapt					parser->state = UCL_STATE_VALUE;
1680262395Sbapt				}
1681262395Sbapt			}
1682262395Sbapt			else {
1683262395Sbapt				c = chunk->pos;
1684262395Sbapt			}
1685262395Sbapt			p = chunk->pos;
1686262395Sbapt			break;
1687262395Sbapt		case UCL_STATE_VALUE:
1688262395Sbapt			/* We need to check what we do have */
1689262395Sbapt			if (!ucl_parse_value (parser, chunk)) {
1690262395Sbapt				parser->prev_state = parser->state;
1691262395Sbapt				parser->state = UCL_STATE_ERROR;
1692262395Sbapt				return false;
1693262395Sbapt			}
1694262395Sbapt			/* State is set in ucl_parse_value call */
1695262395Sbapt			p = chunk->pos;
1696262395Sbapt			break;
1697262395Sbapt		case UCL_STATE_AFTER_VALUE:
1698262395Sbapt			if (!ucl_parse_after_value (parser, chunk)) {
1699262395Sbapt				parser->prev_state = parser->state;
1700262395Sbapt				parser->state = UCL_STATE_ERROR;
1701262395Sbapt				return false;
1702262395Sbapt			}
1703262395Sbapt			if (parser->stack != NULL) {
1704262395Sbapt				if (parser->stack->obj->type == UCL_OBJECT) {
1705262395Sbapt					parser->state = UCL_STATE_KEY;
1706262395Sbapt				}
1707262395Sbapt				else {
1708262395Sbapt					/* Array */
1709262395Sbapt					parser->state = UCL_STATE_VALUE;
1710262395Sbapt				}
1711262395Sbapt			}
1712262395Sbapt			else {
1713262395Sbapt				/* Skip everything at the end */
1714262395Sbapt				return true;
1715262395Sbapt			}
1716262395Sbapt			p = chunk->pos;
1717262395Sbapt			break;
1718262395Sbapt		case UCL_STATE_MACRO_NAME:
1719262395Sbapt			if (!ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE)) {
1720262395Sbapt				ucl_chunk_skipc (chunk, p);
1721262395Sbapt			}
1722262395Sbapt			else if (p - c > 0) {
1723262395Sbapt				/* We got macro name */
1724262395Sbapt				macro_len = (size_t)(p - c);
1725262395Sbapt				HASH_FIND (hh, parser->macroes, c, macro_len, macro);
1726262395Sbapt				if (macro == NULL) {
1727262395Sbapt					ucl_create_err (&parser->err, "error on line %d at column %d: "
1728262395Sbapt							"unknown macro: '%.*s', character: '%c'",
1729262395Sbapt								chunk->line, chunk->column, (int)(p - c), c, *chunk->pos);
1730262395Sbapt					parser->state = UCL_STATE_ERROR;
1731262395Sbapt					return false;
1732262395Sbapt				}
1733262395Sbapt				/* Now we need to skip all spaces */
1734262395Sbapt				while (p < chunk->end) {
1735262395Sbapt					if (!ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE)) {
1736262395Sbapt						if (chunk->remain >= 2 && ucl_lex_is_comment (p[0], p[1])) {
1737262395Sbapt							/* Skip comment */
1738262395Sbapt							if (!ucl_skip_comments (parser)) {
1739262395Sbapt								return false;
1740262395Sbapt							}
1741262395Sbapt							p = chunk->pos;
1742262395Sbapt						}
1743262395Sbapt						break;
1744262395Sbapt					}
1745262395Sbapt					ucl_chunk_skipc (chunk, p);
1746262395Sbapt				}
1747262395Sbapt				parser->state = UCL_STATE_MACRO;
1748262395Sbapt			}
1749262395Sbapt			break;
1750262395Sbapt		case UCL_STATE_MACRO:
1751262395Sbapt			if (!ucl_parse_macro_value (parser, chunk, macro,
1752262395Sbapt					&macro_start, &macro_len)) {
1753262395Sbapt				parser->prev_state = parser->state;
1754262395Sbapt				parser->state = UCL_STATE_ERROR;
1755262395Sbapt				return false;
1756262395Sbapt			}
1757262395Sbapt			macro_len = ucl_expand_variable (parser, &macro_escaped, macro_start, macro_len);
1758262395Sbapt			parser->state = parser->prev_state;
1759262395Sbapt			if (macro_escaped == NULL) {
1760262395Sbapt				if (!macro->handler (macro_start, macro_len, macro->ud)) {
1761262395Sbapt					return false;
1762262395Sbapt				}
1763262395Sbapt			}
1764262395Sbapt			else {
1765262395Sbapt				if (!macro->handler (macro_escaped, macro_len, macro->ud)) {
1766262395Sbapt					UCL_FREE (macro_len + 1, macro_escaped);
1767262395Sbapt					return false;
1768262395Sbapt				}
1769262395Sbapt				UCL_FREE (macro_len + 1, macro_escaped);
1770262395Sbapt			}
1771262395Sbapt			p = chunk->pos;
1772262395Sbapt			break;
1773262395Sbapt		default:
1774262395Sbapt			/* TODO: add all states */
1775262395Sbapt			ucl_set_err (chunk, UCL_EINTERNAL, "internal error: parser is in an unknown state", &parser->err);
1776262395Sbapt			parser->state = UCL_STATE_ERROR;
1777262395Sbapt			return false;
1778262395Sbapt		}
1779262395Sbapt	}
1780262395Sbapt
1781262395Sbapt	return true;
1782262395Sbapt}
1783262395Sbapt
1784262395Sbaptstruct ucl_parser*
1785262395Sbaptucl_parser_new (int flags)
1786262395Sbapt{
1787262395Sbapt	struct ucl_parser *new;
1788262395Sbapt
1789262395Sbapt	new = UCL_ALLOC (sizeof (struct ucl_parser));
1790262395Sbapt	memset (new, 0, sizeof (struct ucl_parser));
1791262395Sbapt
1792262395Sbapt	ucl_parser_register_macro (new, "include", ucl_include_handler, new);
1793262395Sbapt	ucl_parser_register_macro (new, "try_include", ucl_try_include_handler, new);
1794262395Sbapt	ucl_parser_register_macro (new, "includes", ucl_includes_handler, new);
1795262395Sbapt
1796262395Sbapt	new->flags = flags;
1797262395Sbapt
1798262395Sbapt	/* Initial assumption about filevars */
1799262395Sbapt	ucl_parser_set_filevars (new, NULL, false);
1800262395Sbapt
1801262395Sbapt	return new;
1802262395Sbapt}
1803262395Sbapt
1804262395Sbapt
1805262395Sbaptvoid
1806262395Sbaptucl_parser_register_macro (struct ucl_parser *parser, const char *macro,
1807262395Sbapt		ucl_macro_handler handler, void* ud)
1808262395Sbapt{
1809262395Sbapt	struct ucl_macro *new;
1810262395Sbapt
1811262395Sbapt	new = UCL_ALLOC (sizeof (struct ucl_macro));
1812262395Sbapt	memset (new, 0, sizeof (struct ucl_macro));
1813262395Sbapt	new->handler = handler;
1814262395Sbapt	new->name = strdup (macro);
1815262395Sbapt	new->ud = ud;
1816262395Sbapt	HASH_ADD_KEYPTR (hh, parser->macroes, new->name, strlen (new->name), new);
1817262395Sbapt}
1818262395Sbapt
1819262395Sbaptvoid
1820262395Sbaptucl_parser_register_variable (struct ucl_parser *parser, const char *var,
1821262395Sbapt		const char *value)
1822262395Sbapt{
1823262395Sbapt	struct ucl_variable *new = NULL, *cur;
1824262395Sbapt
1825262395Sbapt	if (var == NULL) {
1826262395Sbapt		return;
1827262395Sbapt	}
1828262395Sbapt
1829262395Sbapt	/* Find whether a variable already exists */
1830262395Sbapt	LL_FOREACH (parser->variables, cur) {
1831262395Sbapt		if (strcmp (cur->var, var) == 0) {
1832262395Sbapt			new = cur;
1833262395Sbapt			break;
1834262395Sbapt		}
1835262395Sbapt	}
1836262395Sbapt
1837262395Sbapt	if (value == NULL) {
1838262395Sbapt
1839262395Sbapt		if (new != NULL) {
1840262395Sbapt			/* Remove variable */
1841262395Sbapt			LL_DELETE (parser->variables, new);
1842262395Sbapt			free (new->var);
1843262395Sbapt			free (new->value);
1844262395Sbapt			UCL_FREE (sizeof (struct ucl_variable), new);
1845262395Sbapt		}
1846262395Sbapt		else {
1847262395Sbapt			/* Do nothing */
1848262395Sbapt			return;
1849262395Sbapt		}
1850262395Sbapt	}
1851262395Sbapt	else {
1852262395Sbapt		if (new == NULL) {
1853262395Sbapt			new = UCL_ALLOC (sizeof (struct ucl_variable));
1854262395Sbapt			memset (new, 0, sizeof (struct ucl_variable));
1855262395Sbapt			new->var = strdup (var);
1856262395Sbapt			new->var_len = strlen (var);
1857262395Sbapt			new->value = strdup (value);
1858262395Sbapt			new->value_len = strlen (value);
1859262395Sbapt
1860262395Sbapt			LL_PREPEND (parser->variables, new);
1861262395Sbapt		}
1862262395Sbapt		else {
1863262395Sbapt			free (new->value);
1864262395Sbapt			new->value = strdup (value);
1865262395Sbapt			new->value_len = strlen (value);
1866262395Sbapt		}
1867262395Sbapt	}
1868262395Sbapt}
1869262395Sbapt
1870262395Sbaptbool
1871262395Sbaptucl_parser_add_chunk (struct ucl_parser *parser, const unsigned char *data,
1872262395Sbapt		size_t len)
1873262395Sbapt{
1874262395Sbapt	struct ucl_chunk *chunk;
1875262395Sbapt
1876262395Sbapt	if (parser->state != UCL_STATE_ERROR) {
1877262395Sbapt		chunk = UCL_ALLOC (sizeof (struct ucl_chunk));
1878262395Sbapt		chunk->begin = data;
1879262395Sbapt		chunk->remain = len;
1880262395Sbapt		chunk->pos = chunk->begin;
1881262395Sbapt		chunk->end = chunk->begin + len;
1882262395Sbapt		chunk->line = 1;
1883262395Sbapt		chunk->column = 0;
1884262395Sbapt		LL_PREPEND (parser->chunks, chunk);
1885262395Sbapt		parser->recursion ++;
1886262395Sbapt		if (parser->recursion > UCL_MAX_RECURSION) {
1887262395Sbapt			ucl_create_err (&parser->err, "maximum include nesting limit is reached: %d",
1888262395Sbapt					parser->recursion);
1889262395Sbapt			return false;
1890262395Sbapt		}
1891262395Sbapt		return ucl_state_machine (parser);
1892262395Sbapt	}
1893262395Sbapt
1894262395Sbapt	ucl_create_err (&parser->err, "a parser is in an invalid state");
1895262395Sbapt
1896262395Sbapt	return false;
1897262395Sbapt}
1898