xref: /freebsd-src/contrib/libucl/src/ucl_parser.c (revision 36c53d67007eda24e9d672ca09d30672547fce6c)
1c99fb5f9SBaptiste Daroussin /* Copyright (c) 2013, Vsevolod Stakhov
2c99fb5f9SBaptiste Daroussin  * All rights reserved.
3c99fb5f9SBaptiste Daroussin  *
4c99fb5f9SBaptiste Daroussin  * Redistribution and use in source and binary forms, with or without
5c99fb5f9SBaptiste Daroussin  * modification, are permitted provided that the following conditions are met:
6c99fb5f9SBaptiste Daroussin  *       * Redistributions of source code must retain the above copyright
7c99fb5f9SBaptiste Daroussin  *         notice, this list of conditions and the following disclaimer.
8c99fb5f9SBaptiste Daroussin  *       * Redistributions in binary form must reproduce the above copyright
9c99fb5f9SBaptiste Daroussin  *         notice, this list of conditions and the following disclaimer in the
10c99fb5f9SBaptiste Daroussin  *         documentation and/or other materials provided with the distribution.
11c99fb5f9SBaptiste Daroussin  *
12c99fb5f9SBaptiste Daroussin  * THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY
13c99fb5f9SBaptiste Daroussin  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
14c99fb5f9SBaptiste Daroussin  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
15c99fb5f9SBaptiste Daroussin  * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY
16c99fb5f9SBaptiste Daroussin  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
17c99fb5f9SBaptiste Daroussin  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
18c99fb5f9SBaptiste Daroussin  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
19c99fb5f9SBaptiste Daroussin  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
20c99fb5f9SBaptiste Daroussin  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
21c99fb5f9SBaptiste Daroussin  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
22c99fb5f9SBaptiste Daroussin  */
23c99fb5f9SBaptiste Daroussin 
24c99fb5f9SBaptiste Daroussin #include "ucl.h"
25c99fb5f9SBaptiste Daroussin #include "ucl_internal.h"
26c99fb5f9SBaptiste Daroussin #include "ucl_chartable.h"
27c99fb5f9SBaptiste Daroussin 
28c99fb5f9SBaptiste Daroussin /**
29c99fb5f9SBaptiste Daroussin  * @file rcl_parser.c
30c99fb5f9SBaptiste Daroussin  * The implementation of rcl parser
31c99fb5f9SBaptiste Daroussin  */
32c99fb5f9SBaptiste Daroussin 
33c99fb5f9SBaptiste Daroussin struct ucl_parser_saved_state {
34c99fb5f9SBaptiste Daroussin 	unsigned int line;
35c99fb5f9SBaptiste Daroussin 	unsigned int column;
36c99fb5f9SBaptiste Daroussin 	size_t remain;
37c99fb5f9SBaptiste Daroussin 	const unsigned char *pos;
38c99fb5f9SBaptiste Daroussin };
39c99fb5f9SBaptiste Daroussin 
40c99fb5f9SBaptiste Daroussin /**
41c99fb5f9SBaptiste Daroussin  * Move up to len characters
42c99fb5f9SBaptiste Daroussin  * @param parser
43c99fb5f9SBaptiste Daroussin  * @param begin
44c99fb5f9SBaptiste Daroussin  * @param len
45c99fb5f9SBaptiste Daroussin  * @return new position in chunk
46c99fb5f9SBaptiste Daroussin  */
47c99fb5f9SBaptiste Daroussin #define ucl_chunk_skipc(chunk, p)    do{					\
48c99fb5f9SBaptiste Daroussin     if (*(p) == '\n') {										\
49c99fb5f9SBaptiste Daroussin         (chunk)->line ++;									\
50c99fb5f9SBaptiste Daroussin         (chunk)->column = 0;								\
51c99fb5f9SBaptiste Daroussin     }														\
52c99fb5f9SBaptiste Daroussin     else (chunk)->column ++;								\
53c99fb5f9SBaptiste Daroussin     (p++);													\
54c99fb5f9SBaptiste Daroussin     (chunk)->pos ++;										\
55c99fb5f9SBaptiste Daroussin     (chunk)->remain --;										\
56c99fb5f9SBaptiste Daroussin     } while (0)
57c99fb5f9SBaptiste Daroussin 
58c99fb5f9SBaptiste Daroussin /**
59c99fb5f9SBaptiste Daroussin  * Save parser state
60c99fb5f9SBaptiste Daroussin  * @param chunk
61c99fb5f9SBaptiste Daroussin  * @param s
62c99fb5f9SBaptiste Daroussin  */
63c99fb5f9SBaptiste Daroussin static inline void
64c99fb5f9SBaptiste Daroussin ucl_chunk_save_state (struct ucl_chunk *chunk, struct ucl_parser_saved_state *s)
65c99fb5f9SBaptiste Daroussin {
66c99fb5f9SBaptiste Daroussin 	s->column = chunk->column;
67c99fb5f9SBaptiste Daroussin 	s->pos = chunk->pos;
68c99fb5f9SBaptiste Daroussin 	s->line = chunk->line;
69c99fb5f9SBaptiste Daroussin 	s->remain = chunk->remain;
70c99fb5f9SBaptiste Daroussin }
71c99fb5f9SBaptiste Daroussin 
72c99fb5f9SBaptiste Daroussin /**
73c99fb5f9SBaptiste Daroussin  * Restore parser state
74c99fb5f9SBaptiste Daroussin  * @param chunk
75c99fb5f9SBaptiste Daroussin  * @param s
76c99fb5f9SBaptiste Daroussin  */
77c99fb5f9SBaptiste Daroussin static inline void
78c99fb5f9SBaptiste Daroussin ucl_chunk_restore_state (struct ucl_chunk *chunk, struct ucl_parser_saved_state *s)
79c99fb5f9SBaptiste Daroussin {
80c99fb5f9SBaptiste Daroussin 	chunk->column = s->column;
81c99fb5f9SBaptiste Daroussin 	chunk->pos = s->pos;
82c99fb5f9SBaptiste Daroussin 	chunk->line = s->line;
83c99fb5f9SBaptiste Daroussin 	chunk->remain = s->remain;
84c99fb5f9SBaptiste Daroussin }
85c99fb5f9SBaptiste Daroussin 
86c99fb5f9SBaptiste Daroussin static inline void
87c99fb5f9SBaptiste Daroussin ucl_set_err (struct ucl_chunk *chunk, int code, const char *str, UT_string **err)
88c99fb5f9SBaptiste Daroussin {
89c99fb5f9SBaptiste Daroussin 	if (chunk->pos < chunk->end) {
90c99fb5f9SBaptiste Daroussin 		if (isgraph (*chunk->pos)) {
91c99fb5f9SBaptiste Daroussin 			ucl_create_err (err, "error on line %d at column %d: '%s', character: '%c'",
92c99fb5f9SBaptiste Daroussin 					chunk->line, chunk->column, str, *chunk->pos);
93c99fb5f9SBaptiste Daroussin 		}
94c99fb5f9SBaptiste Daroussin 		else {
95c99fb5f9SBaptiste Daroussin 			ucl_create_err (err, "error on line %d at column %d: '%s', character: '0x%02x'",
96c99fb5f9SBaptiste Daroussin 					chunk->line, chunk->column, str, (int)*chunk->pos);
97c99fb5f9SBaptiste Daroussin 		}
98c99fb5f9SBaptiste Daroussin 	}
99c99fb5f9SBaptiste Daroussin 	else {
100c99fb5f9SBaptiste Daroussin 		ucl_create_err (err, "error at the end of chunk: %s", str);
101c99fb5f9SBaptiste Daroussin 	}
102c99fb5f9SBaptiste Daroussin }
103c99fb5f9SBaptiste Daroussin 
104c99fb5f9SBaptiste Daroussin /**
105c99fb5f9SBaptiste Daroussin  * Skip all comments from the current pos resolving nested and multiline comments
106c99fb5f9SBaptiste Daroussin  * @param parser
107c99fb5f9SBaptiste Daroussin  * @return
108c99fb5f9SBaptiste Daroussin  */
109c99fb5f9SBaptiste Daroussin static bool
110c99fb5f9SBaptiste Daroussin ucl_skip_comments (struct ucl_parser *parser)
111c99fb5f9SBaptiste Daroussin {
112c99fb5f9SBaptiste Daroussin 	struct ucl_chunk *chunk = parser->chunks;
113c99fb5f9SBaptiste Daroussin 	const unsigned char *p;
114c99fb5f9SBaptiste Daroussin 	int comments_nested = 0;
115c99fb5f9SBaptiste Daroussin 
116c99fb5f9SBaptiste Daroussin 	p = chunk->pos;
117c99fb5f9SBaptiste Daroussin 
118c99fb5f9SBaptiste Daroussin start:
119c99fb5f9SBaptiste Daroussin 	if (*p == '#') {
120c99fb5f9SBaptiste Daroussin 		if (parser->state != UCL_STATE_SCOMMENT &&
121c99fb5f9SBaptiste Daroussin 				parser->state != UCL_STATE_MCOMMENT) {
122c99fb5f9SBaptiste Daroussin 			while (p < chunk->end) {
123c99fb5f9SBaptiste Daroussin 				if (*p == '\n') {
124c99fb5f9SBaptiste Daroussin 					ucl_chunk_skipc (chunk, p);
125c99fb5f9SBaptiste Daroussin 					goto start;
126c99fb5f9SBaptiste Daroussin 				}
127c99fb5f9SBaptiste Daroussin 				ucl_chunk_skipc (chunk, p);
128c99fb5f9SBaptiste Daroussin 			}
129c99fb5f9SBaptiste Daroussin 		}
130c99fb5f9SBaptiste Daroussin 	}
131c99fb5f9SBaptiste Daroussin 	else if (*p == '/' && chunk->remain >= 2) {
132c99fb5f9SBaptiste Daroussin 		if (p[1] == '*') {
133c99fb5f9SBaptiste Daroussin 			ucl_chunk_skipc (chunk, p);
134c99fb5f9SBaptiste Daroussin 			comments_nested ++;
135c99fb5f9SBaptiste Daroussin 			ucl_chunk_skipc (chunk, p);
136c99fb5f9SBaptiste Daroussin 
137c99fb5f9SBaptiste Daroussin 			while (p < chunk->end) {
138c99fb5f9SBaptiste Daroussin 				if (*p == '*') {
139c99fb5f9SBaptiste Daroussin 					ucl_chunk_skipc (chunk, p);
140c99fb5f9SBaptiste Daroussin 					if (*p == '/') {
141c99fb5f9SBaptiste Daroussin 						comments_nested --;
142c99fb5f9SBaptiste Daroussin 						if (comments_nested == 0) {
143c99fb5f9SBaptiste Daroussin 							ucl_chunk_skipc (chunk, p);
144c99fb5f9SBaptiste Daroussin 							goto start;
145c99fb5f9SBaptiste Daroussin 						}
146c99fb5f9SBaptiste Daroussin 					}
147c99fb5f9SBaptiste Daroussin 					ucl_chunk_skipc (chunk, p);
148c99fb5f9SBaptiste Daroussin 				}
149c99fb5f9SBaptiste Daroussin 				else if (p[0] == '/' && chunk->remain >= 2 && p[1] == '*') {
150c99fb5f9SBaptiste Daroussin 					comments_nested ++;
151c99fb5f9SBaptiste Daroussin 					ucl_chunk_skipc (chunk, p);
152c99fb5f9SBaptiste Daroussin 					ucl_chunk_skipc (chunk, p);
153c99fb5f9SBaptiste Daroussin 					continue;
154c99fb5f9SBaptiste Daroussin 				}
155c99fb5f9SBaptiste Daroussin 				ucl_chunk_skipc (chunk, p);
156c99fb5f9SBaptiste Daroussin 			}
157c99fb5f9SBaptiste Daroussin 			if (comments_nested != 0) {
158c99fb5f9SBaptiste Daroussin 				ucl_set_err (chunk, UCL_ENESTED, "unfinished multiline comment", &parser->err);
159c99fb5f9SBaptiste Daroussin 				return false;
160c99fb5f9SBaptiste Daroussin 			}
161c99fb5f9SBaptiste Daroussin 		}
162c99fb5f9SBaptiste Daroussin 	}
163c99fb5f9SBaptiste Daroussin 
164c99fb5f9SBaptiste Daroussin 	return true;
165c99fb5f9SBaptiste Daroussin }
166c99fb5f9SBaptiste Daroussin 
167c99fb5f9SBaptiste Daroussin /**
168c99fb5f9SBaptiste Daroussin  * Return multiplier for a character
169c99fb5f9SBaptiste Daroussin  * @param c multiplier character
170c99fb5f9SBaptiste Daroussin  * @param is_bytes if true use 1024 multiplier
171c99fb5f9SBaptiste Daroussin  * @return multiplier
172c99fb5f9SBaptiste Daroussin  */
173c99fb5f9SBaptiste Daroussin static inline unsigned long
174c99fb5f9SBaptiste Daroussin ucl_lex_num_multiplier (const unsigned char c, bool is_bytes) {
175c99fb5f9SBaptiste Daroussin 	const struct {
176c99fb5f9SBaptiste Daroussin 		char c;
177c99fb5f9SBaptiste Daroussin 		long mult_normal;
178c99fb5f9SBaptiste Daroussin 		long mult_bytes;
179c99fb5f9SBaptiste Daroussin 	} multipliers[] = {
180c99fb5f9SBaptiste Daroussin 			{'m', 1000 * 1000, 1024 * 1024},
181c99fb5f9SBaptiste Daroussin 			{'k', 1000, 1024},
182c99fb5f9SBaptiste Daroussin 			{'g', 1000 * 1000 * 1000, 1024 * 1024 * 1024}
183c99fb5f9SBaptiste Daroussin 	};
184c99fb5f9SBaptiste Daroussin 	int i;
185c99fb5f9SBaptiste Daroussin 
186c99fb5f9SBaptiste Daroussin 	for (i = 0; i < 3; i ++) {
187c99fb5f9SBaptiste Daroussin 		if (tolower (c) == multipliers[i].c) {
188c99fb5f9SBaptiste Daroussin 			if (is_bytes) {
189c99fb5f9SBaptiste Daroussin 				return multipliers[i].mult_bytes;
190c99fb5f9SBaptiste Daroussin 			}
191c99fb5f9SBaptiste Daroussin 			return multipliers[i].mult_normal;
192c99fb5f9SBaptiste Daroussin 		}
193c99fb5f9SBaptiste Daroussin 	}
194c99fb5f9SBaptiste Daroussin 
195c99fb5f9SBaptiste Daroussin 	return 1;
196c99fb5f9SBaptiste Daroussin }
197c99fb5f9SBaptiste Daroussin 
198c99fb5f9SBaptiste Daroussin 
199c99fb5f9SBaptiste Daroussin /**
200c99fb5f9SBaptiste Daroussin  * Return multiplier for time scaling
201c99fb5f9SBaptiste Daroussin  * @param c
202c99fb5f9SBaptiste Daroussin  * @return
203c99fb5f9SBaptiste Daroussin  */
204c99fb5f9SBaptiste Daroussin static inline double
205c99fb5f9SBaptiste Daroussin ucl_lex_time_multiplier (const unsigned char c) {
206c99fb5f9SBaptiste Daroussin 	const struct {
207c99fb5f9SBaptiste Daroussin 		char c;
208c99fb5f9SBaptiste Daroussin 		double mult;
209c99fb5f9SBaptiste Daroussin 	} multipliers[] = {
210c99fb5f9SBaptiste Daroussin 			{'m', 60},
211c99fb5f9SBaptiste Daroussin 			{'h', 60 * 60},
212c99fb5f9SBaptiste Daroussin 			{'d', 60 * 60 * 24},
213c99fb5f9SBaptiste Daroussin 			{'w', 60 * 60 * 24 * 7},
214c99fb5f9SBaptiste Daroussin 			{'y', 60 * 60 * 24 * 7 * 365}
215c99fb5f9SBaptiste Daroussin 	};
216c99fb5f9SBaptiste Daroussin 	int i;
217c99fb5f9SBaptiste Daroussin 
218c99fb5f9SBaptiste Daroussin 	for (i = 0; i < 5; i ++) {
219c99fb5f9SBaptiste Daroussin 		if (tolower (c) == multipliers[i].c) {
220c99fb5f9SBaptiste Daroussin 			return multipliers[i].mult;
221c99fb5f9SBaptiste Daroussin 		}
222c99fb5f9SBaptiste Daroussin 	}
223c99fb5f9SBaptiste Daroussin 
224c99fb5f9SBaptiste Daroussin 	return 1;
225c99fb5f9SBaptiste Daroussin }
226c99fb5f9SBaptiste Daroussin 
227c99fb5f9SBaptiste Daroussin /**
228c99fb5f9SBaptiste Daroussin  * Return true if a character is a end of an atom
229c99fb5f9SBaptiste Daroussin  * @param c
230c99fb5f9SBaptiste Daroussin  * @return
231c99fb5f9SBaptiste Daroussin  */
232c99fb5f9SBaptiste Daroussin static inline bool
233c99fb5f9SBaptiste Daroussin ucl_lex_is_atom_end (const unsigned char c)
234c99fb5f9SBaptiste Daroussin {
235c99fb5f9SBaptiste Daroussin 	return ucl_test_character (c, UCL_CHARACTER_VALUE_END);
236c99fb5f9SBaptiste Daroussin }
237c99fb5f9SBaptiste Daroussin 
238c99fb5f9SBaptiste Daroussin static inline bool
239c99fb5f9SBaptiste Daroussin ucl_lex_is_comment (const unsigned char c1, const unsigned char c2)
240c99fb5f9SBaptiste Daroussin {
241c99fb5f9SBaptiste Daroussin 	if (c1 == '/') {
242c99fb5f9SBaptiste Daroussin 		if (c2 == '*') {
243c99fb5f9SBaptiste Daroussin 			return true;
244c99fb5f9SBaptiste Daroussin 		}
245c99fb5f9SBaptiste Daroussin 	}
246c99fb5f9SBaptiste Daroussin 	else if (c1 == '#') {
247c99fb5f9SBaptiste Daroussin 		return true;
248c99fb5f9SBaptiste Daroussin 	}
249c99fb5f9SBaptiste Daroussin 	return false;
250c99fb5f9SBaptiste Daroussin }
251c99fb5f9SBaptiste Daroussin 
252c99fb5f9SBaptiste Daroussin /**
253c99fb5f9SBaptiste Daroussin  * Check variable found
254c99fb5f9SBaptiste Daroussin  * @param parser
255c99fb5f9SBaptiste Daroussin  * @param ptr
256c99fb5f9SBaptiste Daroussin  * @param remain
257c99fb5f9SBaptiste Daroussin  * @param out_len
258c99fb5f9SBaptiste Daroussin  * @param strict
259c99fb5f9SBaptiste Daroussin  * @param found
260c99fb5f9SBaptiste Daroussin  * @return
261c99fb5f9SBaptiste Daroussin  */
262c99fb5f9SBaptiste Daroussin static inline const char *
263c99fb5f9SBaptiste Daroussin ucl_check_variable_safe (struct ucl_parser *parser, const char *ptr, size_t remain,
264c99fb5f9SBaptiste Daroussin 		size_t *out_len, bool strict, bool *found)
265c99fb5f9SBaptiste Daroussin {
266c99fb5f9SBaptiste Daroussin 	struct ucl_variable *var;
267c99fb5f9SBaptiste Daroussin 
268c99fb5f9SBaptiste Daroussin 	LL_FOREACH (parser->variables, var) {
269c99fb5f9SBaptiste Daroussin 		if (strict) {
270c99fb5f9SBaptiste Daroussin 			if (remain == var->var_len) {
271c99fb5f9SBaptiste Daroussin 				if (memcmp (ptr, var->var, var->var_len) == 0) {
272c99fb5f9SBaptiste Daroussin 					*out_len += var->value_len;
273c99fb5f9SBaptiste Daroussin 					*found = true;
274c99fb5f9SBaptiste Daroussin 					return (ptr + var->var_len);
275c99fb5f9SBaptiste Daroussin 				}
276c99fb5f9SBaptiste Daroussin 			}
277c99fb5f9SBaptiste Daroussin 		}
278c99fb5f9SBaptiste Daroussin 		else {
279c99fb5f9SBaptiste Daroussin 			if (remain >= var->var_len) {
280c99fb5f9SBaptiste Daroussin 				if (memcmp (ptr, var->var, var->var_len) == 0) {
281c99fb5f9SBaptiste Daroussin 					*out_len += var->value_len;
282c99fb5f9SBaptiste Daroussin 					*found = true;
283c99fb5f9SBaptiste Daroussin 					return (ptr + var->var_len);
284c99fb5f9SBaptiste Daroussin 				}
285c99fb5f9SBaptiste Daroussin 			}
286c99fb5f9SBaptiste Daroussin 		}
287c99fb5f9SBaptiste Daroussin 	}
288c99fb5f9SBaptiste Daroussin 
289c99fb5f9SBaptiste Daroussin 	return ptr;
290c99fb5f9SBaptiste Daroussin }
291c99fb5f9SBaptiste Daroussin 
292c99fb5f9SBaptiste Daroussin /**
293c99fb5f9SBaptiste Daroussin  * Check for a variable in a given string
294c99fb5f9SBaptiste Daroussin  * @param parser
295c99fb5f9SBaptiste Daroussin  * @param ptr
296c99fb5f9SBaptiste Daroussin  * @param remain
297c99fb5f9SBaptiste Daroussin  * @param out_len
298c99fb5f9SBaptiste Daroussin  * @param vars_found
299c99fb5f9SBaptiste Daroussin  * @return
300c99fb5f9SBaptiste Daroussin  */
301c99fb5f9SBaptiste Daroussin static const char *
302c99fb5f9SBaptiste Daroussin ucl_check_variable (struct ucl_parser *parser, const char *ptr, size_t remain, size_t *out_len, bool *vars_found)
303c99fb5f9SBaptiste Daroussin {
304c99fb5f9SBaptiste Daroussin 	const char *p, *end, *ret = ptr;
305c99fb5f9SBaptiste Daroussin 	bool found = false;
306c99fb5f9SBaptiste Daroussin 
307c99fb5f9SBaptiste Daroussin 	if (*ptr == '{') {
308c99fb5f9SBaptiste Daroussin 		/* We need to match the variable enclosed in braces */
309c99fb5f9SBaptiste Daroussin 		p = ptr + 1;
310c99fb5f9SBaptiste Daroussin 		end = ptr + remain;
311c99fb5f9SBaptiste Daroussin 		while (p < end) {
312c99fb5f9SBaptiste Daroussin 			if (*p == '}') {
313c99fb5f9SBaptiste Daroussin 				ret = ucl_check_variable_safe (parser, ptr + 1, p - ptr - 1, out_len, true, &found);
314c99fb5f9SBaptiste Daroussin 				if (found) {
315c99fb5f9SBaptiste Daroussin 					/* {} must be excluded actually */
316c99fb5f9SBaptiste Daroussin 					ret ++;
317c99fb5f9SBaptiste Daroussin 					if (!*vars_found) {
318c99fb5f9SBaptiste Daroussin 						*vars_found = true;
319c99fb5f9SBaptiste Daroussin 					}
320c99fb5f9SBaptiste Daroussin 				}
321c99fb5f9SBaptiste Daroussin 				else {
322c99fb5f9SBaptiste Daroussin 					*out_len += 2;
323c99fb5f9SBaptiste Daroussin 				}
324c99fb5f9SBaptiste Daroussin 				break;
325c99fb5f9SBaptiste Daroussin 			}
326c99fb5f9SBaptiste Daroussin 			p ++;
327c99fb5f9SBaptiste Daroussin 		}
328c99fb5f9SBaptiste Daroussin 	}
329c99fb5f9SBaptiste Daroussin 	else if (*ptr != '$') {
330c99fb5f9SBaptiste Daroussin 		/* Not count escaped dollar sign */
331c99fb5f9SBaptiste Daroussin 		ret = ucl_check_variable_safe (parser, ptr, remain, out_len, false, &found);
332c99fb5f9SBaptiste Daroussin 		if (found && !*vars_found) {
333c99fb5f9SBaptiste Daroussin 			*vars_found = true;
334c99fb5f9SBaptiste Daroussin 		}
335c99fb5f9SBaptiste Daroussin 		if (!found) {
336c99fb5f9SBaptiste Daroussin 			(*out_len) ++;
337c99fb5f9SBaptiste Daroussin 		}
338c99fb5f9SBaptiste Daroussin 	}
339c99fb5f9SBaptiste Daroussin 	else {
340c99fb5f9SBaptiste Daroussin 		ret ++;
341c99fb5f9SBaptiste Daroussin 		(*out_len) ++;
342c99fb5f9SBaptiste Daroussin 	}
343c99fb5f9SBaptiste Daroussin 
344c99fb5f9SBaptiste Daroussin 	return ret;
345c99fb5f9SBaptiste Daroussin }
346c99fb5f9SBaptiste Daroussin 
347c99fb5f9SBaptiste Daroussin /**
348c99fb5f9SBaptiste Daroussin  * Expand a single variable
349c99fb5f9SBaptiste Daroussin  * @param parser
350c99fb5f9SBaptiste Daroussin  * @param ptr
351c99fb5f9SBaptiste Daroussin  * @param remain
352c99fb5f9SBaptiste Daroussin  * @param dest
353c99fb5f9SBaptiste Daroussin  * @return
354c99fb5f9SBaptiste Daroussin  */
355c99fb5f9SBaptiste Daroussin static const char *
356c99fb5f9SBaptiste Daroussin ucl_expand_single_variable (struct ucl_parser *parser, const char *ptr,
357c99fb5f9SBaptiste Daroussin 		size_t remain, unsigned char **dest)
358c99fb5f9SBaptiste Daroussin {
359c99fb5f9SBaptiste Daroussin 	unsigned char *d = *dest;
360c99fb5f9SBaptiste Daroussin 	const char *p = ptr + 1, *ret;
361c99fb5f9SBaptiste Daroussin 	struct ucl_variable *var;
362c99fb5f9SBaptiste Daroussin 	bool found = false;
363c99fb5f9SBaptiste Daroussin 
364c99fb5f9SBaptiste Daroussin 	ret = ptr + 1;
365c99fb5f9SBaptiste Daroussin 	remain --;
366c99fb5f9SBaptiste Daroussin 
367c99fb5f9SBaptiste Daroussin 	if (*p == '$') {
368c99fb5f9SBaptiste Daroussin 		*d++ = *p++;
369c99fb5f9SBaptiste Daroussin 		*dest = d;
370c99fb5f9SBaptiste Daroussin 		return p;
371c99fb5f9SBaptiste Daroussin 	}
372c99fb5f9SBaptiste Daroussin 	else if (*p == '{') {
373c99fb5f9SBaptiste Daroussin 		p ++;
374c99fb5f9SBaptiste Daroussin 		ret += 2;
375c99fb5f9SBaptiste Daroussin 		remain -= 2;
376c99fb5f9SBaptiste Daroussin 	}
377c99fb5f9SBaptiste Daroussin 
378c99fb5f9SBaptiste Daroussin 	LL_FOREACH (parser->variables, var) {
379c99fb5f9SBaptiste Daroussin 		if (remain >= var->var_len) {
380c99fb5f9SBaptiste Daroussin 			if (memcmp (p, var->var, var->var_len) == 0) {
381c99fb5f9SBaptiste Daroussin 				memcpy (d, var->value, var->value_len);
382c99fb5f9SBaptiste Daroussin 				ret += var->var_len;
383c99fb5f9SBaptiste Daroussin 				d += var->value_len;
384c99fb5f9SBaptiste Daroussin 				found = true;
385c99fb5f9SBaptiste Daroussin 				break;
386c99fb5f9SBaptiste Daroussin 			}
387c99fb5f9SBaptiste Daroussin 		}
388c99fb5f9SBaptiste Daroussin 	}
389c99fb5f9SBaptiste Daroussin 	if (!found) {
390c99fb5f9SBaptiste Daroussin 		memcpy (d, ptr, 2);
391c99fb5f9SBaptiste Daroussin 		d += 2;
392c99fb5f9SBaptiste Daroussin 		ret --;
393c99fb5f9SBaptiste Daroussin 	}
394c99fb5f9SBaptiste Daroussin 
395c99fb5f9SBaptiste Daroussin 	*dest = d;
396c99fb5f9SBaptiste Daroussin 	return ret;
397c99fb5f9SBaptiste Daroussin }
398c99fb5f9SBaptiste Daroussin 
399c99fb5f9SBaptiste Daroussin /**
400c99fb5f9SBaptiste Daroussin  * Expand variables in string
401c99fb5f9SBaptiste Daroussin  * @param parser
402c99fb5f9SBaptiste Daroussin  * @param dst
403c99fb5f9SBaptiste Daroussin  * @param src
404c99fb5f9SBaptiste Daroussin  * @param in_len
405c99fb5f9SBaptiste Daroussin  * @return
406c99fb5f9SBaptiste Daroussin  */
407c99fb5f9SBaptiste Daroussin static ssize_t
408c99fb5f9SBaptiste Daroussin ucl_expand_variable (struct ucl_parser *parser, unsigned char **dst,
409c99fb5f9SBaptiste Daroussin 		const char *src, size_t in_len)
410c99fb5f9SBaptiste Daroussin {
411c99fb5f9SBaptiste Daroussin 	const char *p, *end = src + in_len;
412c99fb5f9SBaptiste Daroussin 	unsigned char *d;
413c99fb5f9SBaptiste Daroussin 	size_t out_len = 0;
414c99fb5f9SBaptiste Daroussin 	bool vars_found = false;
415c99fb5f9SBaptiste Daroussin 
416c99fb5f9SBaptiste Daroussin 	p = src;
417c99fb5f9SBaptiste Daroussin 	while (p != end) {
418c99fb5f9SBaptiste Daroussin 		if (*p == '$') {
419c99fb5f9SBaptiste Daroussin 			p = ucl_check_variable (parser, p + 1, end - p - 1, &out_len, &vars_found);
420c99fb5f9SBaptiste Daroussin 		}
421c99fb5f9SBaptiste Daroussin 		else {
422c99fb5f9SBaptiste Daroussin 			p ++;
423c99fb5f9SBaptiste Daroussin 			out_len ++;
424c99fb5f9SBaptiste Daroussin 		}
425c99fb5f9SBaptiste Daroussin 	}
426c99fb5f9SBaptiste Daroussin 
427c99fb5f9SBaptiste Daroussin 	if (!vars_found) {
428c99fb5f9SBaptiste Daroussin 		/* Trivial case */
429c99fb5f9SBaptiste Daroussin 		*dst = NULL;
430c99fb5f9SBaptiste Daroussin 		return in_len;
431c99fb5f9SBaptiste Daroussin 	}
432c99fb5f9SBaptiste Daroussin 
433c99fb5f9SBaptiste Daroussin 	*dst = UCL_ALLOC (out_len + 1);
434c99fb5f9SBaptiste Daroussin 	if (*dst == NULL) {
435c99fb5f9SBaptiste Daroussin 		return in_len;
436c99fb5f9SBaptiste Daroussin 	}
437c99fb5f9SBaptiste Daroussin 
438c99fb5f9SBaptiste Daroussin 	d = *dst;
439c99fb5f9SBaptiste Daroussin 	p = src;
440c99fb5f9SBaptiste Daroussin 	while (p != end) {
441c99fb5f9SBaptiste Daroussin 		if (*p == '$') {
442c99fb5f9SBaptiste Daroussin 			p = ucl_expand_single_variable (parser, p, end - p, &d);
443c99fb5f9SBaptiste Daroussin 		}
444c99fb5f9SBaptiste Daroussin 		else {
445c99fb5f9SBaptiste Daroussin 			*d++ = *p++;
446c99fb5f9SBaptiste Daroussin 		}
447c99fb5f9SBaptiste Daroussin 	}
448c99fb5f9SBaptiste Daroussin 
449c99fb5f9SBaptiste Daroussin 	*d = '\0';
450c99fb5f9SBaptiste Daroussin 
451c99fb5f9SBaptiste Daroussin 	return out_len;
452c99fb5f9SBaptiste Daroussin }
453c99fb5f9SBaptiste Daroussin 
454c99fb5f9SBaptiste Daroussin /**
455c99fb5f9SBaptiste Daroussin  * Store or copy pointer to the trash stack
456c99fb5f9SBaptiste Daroussin  * @param parser parser object
457c99fb5f9SBaptiste Daroussin  * @param src src string
458c99fb5f9SBaptiste Daroussin  * @param dst destination buffer (trash stack pointer)
459c99fb5f9SBaptiste Daroussin  * @param dst_const const destination pointer (e.g. value of object)
460c99fb5f9SBaptiste Daroussin  * @param in_len input length
461c99fb5f9SBaptiste Daroussin  * @param need_unescape need to unescape source (and copy it)
462c99fb5f9SBaptiste Daroussin  * @param need_lowercase need to lowercase value (and copy)
463c99fb5f9SBaptiste Daroussin  * @param need_expand need to expand variables (and copy as well)
464c99fb5f9SBaptiste Daroussin  * @return output length (excluding \0 symbol)
465c99fb5f9SBaptiste Daroussin  */
466c99fb5f9SBaptiste Daroussin static inline ssize_t
467c99fb5f9SBaptiste Daroussin ucl_copy_or_store_ptr (struct ucl_parser *parser,
468c99fb5f9SBaptiste Daroussin 		const unsigned char *src, unsigned char **dst,
469c99fb5f9SBaptiste Daroussin 		const char **dst_const, size_t in_len,
470c99fb5f9SBaptiste Daroussin 		bool need_unescape, bool need_lowercase, bool need_expand)
471c99fb5f9SBaptiste Daroussin {
472c99fb5f9SBaptiste Daroussin 	ssize_t ret = -1, tret;
473c99fb5f9SBaptiste Daroussin 	unsigned char *tmp;
474c99fb5f9SBaptiste Daroussin 
475c99fb5f9SBaptiste Daroussin 	if (need_unescape || need_lowercase ||
476c99fb5f9SBaptiste Daroussin 			(need_expand && parser->variables != NULL) ||
477c99fb5f9SBaptiste Daroussin 			!(parser->flags & UCL_PARSER_ZEROCOPY)) {
478c99fb5f9SBaptiste Daroussin 		/* Copy string */
479c99fb5f9SBaptiste Daroussin 		*dst = UCL_ALLOC (in_len + 1);
480c99fb5f9SBaptiste Daroussin 		if (*dst == NULL) {
481c99fb5f9SBaptiste Daroussin 			ucl_set_err (parser->chunks, 0, "cannot allocate memory for a string", &parser->err);
482c99fb5f9SBaptiste Daroussin 			return false;
483c99fb5f9SBaptiste Daroussin 		}
484c99fb5f9SBaptiste Daroussin 		if (need_lowercase) {
485c99fb5f9SBaptiste Daroussin 			ret = ucl_strlcpy_tolower (*dst, src, in_len + 1);
486c99fb5f9SBaptiste Daroussin 		}
487c99fb5f9SBaptiste Daroussin 		else {
488c99fb5f9SBaptiste Daroussin 			ret = ucl_strlcpy_unsafe (*dst, src, in_len + 1);
489c99fb5f9SBaptiste Daroussin 		}
490c99fb5f9SBaptiste Daroussin 
491c99fb5f9SBaptiste Daroussin 		if (need_unescape) {
492c99fb5f9SBaptiste Daroussin 			ret = ucl_unescape_json_string (*dst, ret);
493c99fb5f9SBaptiste Daroussin 		}
494c99fb5f9SBaptiste Daroussin 		if (need_expand) {
495c99fb5f9SBaptiste Daroussin 			tmp = *dst;
496c99fb5f9SBaptiste Daroussin 			tret = ret;
497c99fb5f9SBaptiste Daroussin 			ret = ucl_expand_variable (parser, dst, tmp, ret);
498c99fb5f9SBaptiste Daroussin 			if (*dst == NULL) {
499c99fb5f9SBaptiste Daroussin 				/* Nothing to expand */
500c99fb5f9SBaptiste Daroussin 				*dst = tmp;
501c99fb5f9SBaptiste Daroussin 				ret = tret;
502c99fb5f9SBaptiste Daroussin 			}
503c99fb5f9SBaptiste Daroussin 		}
504c99fb5f9SBaptiste Daroussin 		*dst_const = *dst;
505c99fb5f9SBaptiste Daroussin 	}
506c99fb5f9SBaptiste Daroussin 	else {
507c99fb5f9SBaptiste Daroussin 		*dst_const = src;
508c99fb5f9SBaptiste Daroussin 		ret = in_len;
509c99fb5f9SBaptiste Daroussin 	}
510c99fb5f9SBaptiste Daroussin 
511c99fb5f9SBaptiste Daroussin 	return ret;
512c99fb5f9SBaptiste Daroussin }
513c99fb5f9SBaptiste Daroussin 
514c99fb5f9SBaptiste Daroussin /**
515c99fb5f9SBaptiste Daroussin  * Create and append an object at the specified level
516c99fb5f9SBaptiste Daroussin  * @param parser
517c99fb5f9SBaptiste Daroussin  * @param is_array
518c99fb5f9SBaptiste Daroussin  * @param level
519c99fb5f9SBaptiste Daroussin  * @return
520c99fb5f9SBaptiste Daroussin  */
521c99fb5f9SBaptiste Daroussin static inline ucl_object_t *
522c99fb5f9SBaptiste Daroussin ucl_add_parser_stack (ucl_object_t *obj, struct ucl_parser *parser, bool is_array, int level)
523c99fb5f9SBaptiste Daroussin {
524c99fb5f9SBaptiste Daroussin 	struct ucl_stack *st;
525c99fb5f9SBaptiste Daroussin 
526c99fb5f9SBaptiste Daroussin 	if (!is_array) {
527c99fb5f9SBaptiste Daroussin 		if (obj == NULL) {
528c99fb5f9SBaptiste Daroussin 			obj = ucl_object_typed_new (UCL_OBJECT);
529c99fb5f9SBaptiste Daroussin 		}
530c99fb5f9SBaptiste Daroussin 		else {
531c99fb5f9SBaptiste Daroussin 			obj->type = UCL_OBJECT;
532c99fb5f9SBaptiste Daroussin 		}
533c99fb5f9SBaptiste Daroussin 		obj->value.ov = ucl_hash_create ();
534c99fb5f9SBaptiste Daroussin 		parser->state = UCL_STATE_KEY;
535c99fb5f9SBaptiste Daroussin 	}
536c99fb5f9SBaptiste Daroussin 	else {
537c99fb5f9SBaptiste Daroussin 		if (obj == NULL) {
538c99fb5f9SBaptiste Daroussin 			obj = ucl_object_typed_new (UCL_ARRAY);
539c99fb5f9SBaptiste Daroussin 		}
540c99fb5f9SBaptiste Daroussin 		else {
541c99fb5f9SBaptiste Daroussin 			obj->type = UCL_ARRAY;
542c99fb5f9SBaptiste Daroussin 		}
543c99fb5f9SBaptiste Daroussin 		parser->state = UCL_STATE_VALUE;
544c99fb5f9SBaptiste Daroussin 	}
545c99fb5f9SBaptiste Daroussin 
546c99fb5f9SBaptiste Daroussin 	st = UCL_ALLOC (sizeof (struct ucl_stack));
547c99fb5f9SBaptiste Daroussin 	st->obj = obj;
548c99fb5f9SBaptiste Daroussin 	st->level = level;
549c99fb5f9SBaptiste Daroussin 	LL_PREPEND (parser->stack, st);
550c99fb5f9SBaptiste Daroussin 	parser->cur_obj = obj;
551c99fb5f9SBaptiste Daroussin 
552c99fb5f9SBaptiste Daroussin 	return obj;
553c99fb5f9SBaptiste Daroussin }
554c99fb5f9SBaptiste Daroussin 
555c99fb5f9SBaptiste Daroussin int
556c99fb5f9SBaptiste Daroussin ucl_maybe_parse_number (ucl_object_t *obj,
557c99fb5f9SBaptiste Daroussin 		const char *start, const char *end, const char **pos, bool allow_double, bool number_bytes)
558c99fb5f9SBaptiste Daroussin {
559c99fb5f9SBaptiste Daroussin 	const char *p = start, *c = start;
560c99fb5f9SBaptiste Daroussin 	char *endptr;
561c99fb5f9SBaptiste Daroussin 	bool got_dot = false, got_exp = false, need_double = false,
562c99fb5f9SBaptiste Daroussin 			is_date = false, valid_start = false, is_hex = false,
563c99fb5f9SBaptiste Daroussin 			is_neg = false;
564c99fb5f9SBaptiste Daroussin 	double dv = 0;
565c99fb5f9SBaptiste Daroussin 	int64_t lv = 0;
566c99fb5f9SBaptiste Daroussin 
567c99fb5f9SBaptiste Daroussin 	if (*p == '-') {
568c99fb5f9SBaptiste Daroussin 		is_neg = true;
569c99fb5f9SBaptiste Daroussin 		c ++;
570c99fb5f9SBaptiste Daroussin 		p ++;
571c99fb5f9SBaptiste Daroussin 	}
572c99fb5f9SBaptiste Daroussin 	while (p < end) {
573c99fb5f9SBaptiste Daroussin 		if (is_hex && isxdigit (*p)) {
574c99fb5f9SBaptiste Daroussin 			p ++;
575c99fb5f9SBaptiste Daroussin 		}
576c99fb5f9SBaptiste Daroussin 		else if (isdigit (*p)) {
577c99fb5f9SBaptiste Daroussin 			valid_start = true;
578c99fb5f9SBaptiste Daroussin 			p ++;
579c99fb5f9SBaptiste Daroussin 		}
580c99fb5f9SBaptiste Daroussin 		else if (!is_hex && (*p == 'x' || *p == 'X')) {
581c99fb5f9SBaptiste Daroussin 			is_hex = true;
582c99fb5f9SBaptiste Daroussin 			allow_double = false;
583c99fb5f9SBaptiste Daroussin 			c = p + 1;
584c99fb5f9SBaptiste Daroussin 		}
585c99fb5f9SBaptiste Daroussin 		else if (allow_double) {
586c99fb5f9SBaptiste Daroussin 			if (p == c) {
587c99fb5f9SBaptiste Daroussin 				/* Empty digits sequence, not a number */
588c99fb5f9SBaptiste Daroussin 				*pos = start;
589c99fb5f9SBaptiste Daroussin 				return EINVAL;
590c99fb5f9SBaptiste Daroussin 			}
591c99fb5f9SBaptiste Daroussin 			else if (*p == '.') {
592c99fb5f9SBaptiste Daroussin 				if (got_dot) {
593c99fb5f9SBaptiste Daroussin 					/* Double dots, not a number */
594c99fb5f9SBaptiste Daroussin 					*pos = start;
595c99fb5f9SBaptiste Daroussin 					return EINVAL;
596c99fb5f9SBaptiste Daroussin 				}
597c99fb5f9SBaptiste Daroussin 				else {
598c99fb5f9SBaptiste Daroussin 					got_dot = true;
599c99fb5f9SBaptiste Daroussin 					need_double = true;
600c99fb5f9SBaptiste Daroussin 					p ++;
601c99fb5f9SBaptiste Daroussin 				}
602c99fb5f9SBaptiste Daroussin 			}
603c99fb5f9SBaptiste Daroussin 			else if (*p == 'e' || *p == 'E') {
604c99fb5f9SBaptiste Daroussin 				if (got_exp) {
605c99fb5f9SBaptiste Daroussin 					/* Double exp, not a number */
606c99fb5f9SBaptiste Daroussin 					*pos = start;
607c99fb5f9SBaptiste Daroussin 					return EINVAL;
608c99fb5f9SBaptiste Daroussin 				}
609c99fb5f9SBaptiste Daroussin 				else {
610c99fb5f9SBaptiste Daroussin 					got_exp = true;
611c99fb5f9SBaptiste Daroussin 					need_double = true;
612c99fb5f9SBaptiste Daroussin 					p ++;
613c99fb5f9SBaptiste Daroussin 					if (p >= end) {
614c99fb5f9SBaptiste Daroussin 						*pos = start;
615c99fb5f9SBaptiste Daroussin 						return EINVAL;
616c99fb5f9SBaptiste Daroussin 					}
617c99fb5f9SBaptiste Daroussin 					if (!isdigit (*p) && *p != '+' && *p != '-') {
618c99fb5f9SBaptiste Daroussin 						/* Wrong exponent sign */
619c99fb5f9SBaptiste Daroussin 						*pos = start;
620c99fb5f9SBaptiste Daroussin 						return EINVAL;
621c99fb5f9SBaptiste Daroussin 					}
622c99fb5f9SBaptiste Daroussin 					else {
623c99fb5f9SBaptiste Daroussin 						p ++;
624c99fb5f9SBaptiste Daroussin 					}
625c99fb5f9SBaptiste Daroussin 				}
626c99fb5f9SBaptiste Daroussin 			}
627c99fb5f9SBaptiste Daroussin 			else {
628c99fb5f9SBaptiste Daroussin 				/* Got the end of the number, need to check */
629c99fb5f9SBaptiste Daroussin 				break;
630c99fb5f9SBaptiste Daroussin 			}
631c99fb5f9SBaptiste Daroussin 		}
632c99fb5f9SBaptiste Daroussin 		else {
633c99fb5f9SBaptiste Daroussin 			break;
634c99fb5f9SBaptiste Daroussin 		}
635c99fb5f9SBaptiste Daroussin 	}
636c99fb5f9SBaptiste Daroussin 
637c99fb5f9SBaptiste Daroussin 	if (!valid_start) {
638c99fb5f9SBaptiste Daroussin 		*pos = start;
639c99fb5f9SBaptiste Daroussin 		return EINVAL;
640c99fb5f9SBaptiste Daroussin 	}
641c99fb5f9SBaptiste Daroussin 
642c99fb5f9SBaptiste Daroussin 	errno = 0;
643c99fb5f9SBaptiste Daroussin 	if (need_double) {
644c99fb5f9SBaptiste Daroussin 		dv = strtod (c, &endptr);
645c99fb5f9SBaptiste Daroussin 	}
646c99fb5f9SBaptiste Daroussin 	else {
647c99fb5f9SBaptiste Daroussin 		if (is_hex) {
648c99fb5f9SBaptiste Daroussin 			lv = strtoimax (c, &endptr, 16);
649c99fb5f9SBaptiste Daroussin 		}
650c99fb5f9SBaptiste Daroussin 		else {
651c99fb5f9SBaptiste Daroussin 			lv = strtoimax (c, &endptr, 10);
652c99fb5f9SBaptiste Daroussin 		}
653c99fb5f9SBaptiste Daroussin 	}
654c99fb5f9SBaptiste Daroussin 	if (errno == ERANGE) {
655c99fb5f9SBaptiste Daroussin 		*pos = start;
656c99fb5f9SBaptiste Daroussin 		return ERANGE;
657c99fb5f9SBaptiste Daroussin 	}
658c99fb5f9SBaptiste Daroussin 
659c99fb5f9SBaptiste Daroussin 	/* Now check endptr */
660c99fb5f9SBaptiste Daroussin 	if (endptr == NULL || ucl_lex_is_atom_end (*endptr) || *endptr == '\0') {
661c99fb5f9SBaptiste Daroussin 		p = endptr;
662c99fb5f9SBaptiste Daroussin 		goto set_obj;
663c99fb5f9SBaptiste Daroussin 	}
664c99fb5f9SBaptiste Daroussin 
665c99fb5f9SBaptiste Daroussin 	if (endptr < end && endptr != start) {
666c99fb5f9SBaptiste Daroussin 		p = endptr;
667c99fb5f9SBaptiste Daroussin 		switch (*p) {
668c99fb5f9SBaptiste Daroussin 		case 'm':
669c99fb5f9SBaptiste Daroussin 		case 'M':
670c99fb5f9SBaptiste Daroussin 		case 'g':
671c99fb5f9SBaptiste Daroussin 		case 'G':
672c99fb5f9SBaptiste Daroussin 		case 'k':
673c99fb5f9SBaptiste Daroussin 		case 'K':
674c99fb5f9SBaptiste Daroussin 			if (end - p >= 2) {
675c99fb5f9SBaptiste Daroussin 				if (p[1] == 's' || p[1] == 'S') {
676c99fb5f9SBaptiste Daroussin 					/* Milliseconds */
677c99fb5f9SBaptiste Daroussin 					if (!need_double) {
678c99fb5f9SBaptiste Daroussin 						need_double = true;
679c99fb5f9SBaptiste Daroussin 						dv = lv;
680c99fb5f9SBaptiste Daroussin 					}
681c99fb5f9SBaptiste Daroussin 					is_date = true;
682c99fb5f9SBaptiste Daroussin 					if (p[0] == 'm' || p[0] == 'M') {
683c99fb5f9SBaptiste Daroussin 						dv /= 1000.;
684c99fb5f9SBaptiste Daroussin 					}
685c99fb5f9SBaptiste Daroussin 					else {
686c99fb5f9SBaptiste Daroussin 						dv *= ucl_lex_num_multiplier (*p, false);
687c99fb5f9SBaptiste Daroussin 					}
688c99fb5f9SBaptiste Daroussin 					p += 2;
689c99fb5f9SBaptiste Daroussin 					goto set_obj;
690c99fb5f9SBaptiste Daroussin 				}
691c99fb5f9SBaptiste Daroussin 				else if (number_bytes || (p[1] == 'b' || p[1] == 'B')) {
692c99fb5f9SBaptiste Daroussin 					/* Bytes */
693c99fb5f9SBaptiste Daroussin 					if (need_double) {
694c99fb5f9SBaptiste Daroussin 						need_double = false;
695c99fb5f9SBaptiste Daroussin 						lv = dv;
696c99fb5f9SBaptiste Daroussin 					}
697c99fb5f9SBaptiste Daroussin 					lv *= ucl_lex_num_multiplier (*p, true);
698c99fb5f9SBaptiste Daroussin 					p += 2;
699c99fb5f9SBaptiste Daroussin 					goto set_obj;
700c99fb5f9SBaptiste Daroussin 				}
701c99fb5f9SBaptiste Daroussin 				else if (ucl_lex_is_atom_end (p[1])) {
702c99fb5f9SBaptiste Daroussin 					if (need_double) {
703c99fb5f9SBaptiste Daroussin 						dv *= ucl_lex_num_multiplier (*p, false);
704c99fb5f9SBaptiste Daroussin 					}
705c99fb5f9SBaptiste Daroussin 					else {
706c99fb5f9SBaptiste Daroussin 						lv *= ucl_lex_num_multiplier (*p, number_bytes);
707c99fb5f9SBaptiste Daroussin 					}
708c99fb5f9SBaptiste Daroussin 					p ++;
709c99fb5f9SBaptiste Daroussin 					goto set_obj;
710c99fb5f9SBaptiste Daroussin 				}
711c99fb5f9SBaptiste Daroussin 				else if (end - p >= 3) {
712c99fb5f9SBaptiste Daroussin 					if (tolower (p[0]) == 'm' &&
713c99fb5f9SBaptiste Daroussin 							tolower (p[1]) == 'i' &&
714c99fb5f9SBaptiste Daroussin 							tolower (p[2]) == 'n') {
715c99fb5f9SBaptiste Daroussin 						/* Minutes */
716c99fb5f9SBaptiste Daroussin 						if (!need_double) {
717c99fb5f9SBaptiste Daroussin 							need_double = true;
718c99fb5f9SBaptiste Daroussin 							dv = lv;
719c99fb5f9SBaptiste Daroussin 						}
720c99fb5f9SBaptiste Daroussin 						is_date = true;
721c99fb5f9SBaptiste Daroussin 						dv *= 60.;
722c99fb5f9SBaptiste Daroussin 						p += 3;
723c99fb5f9SBaptiste Daroussin 						goto set_obj;
724c99fb5f9SBaptiste Daroussin 					}
725c99fb5f9SBaptiste Daroussin 				}
726c99fb5f9SBaptiste Daroussin 			}
727c99fb5f9SBaptiste Daroussin 			else {
728c99fb5f9SBaptiste Daroussin 				if (need_double) {
729c99fb5f9SBaptiste Daroussin 					dv *= ucl_lex_num_multiplier (*p, false);
730c99fb5f9SBaptiste Daroussin 				}
731c99fb5f9SBaptiste Daroussin 				else {
732c99fb5f9SBaptiste Daroussin 					lv *= ucl_lex_num_multiplier (*p, number_bytes);
733c99fb5f9SBaptiste Daroussin 				}
734c99fb5f9SBaptiste Daroussin 				p ++;
735c99fb5f9SBaptiste Daroussin 				goto set_obj;
736c99fb5f9SBaptiste Daroussin 			}
737c99fb5f9SBaptiste Daroussin 			break;
738c99fb5f9SBaptiste Daroussin 		case 'S':
739c99fb5f9SBaptiste Daroussin 		case 's':
740c99fb5f9SBaptiste Daroussin 			if (p == end - 1 || ucl_lex_is_atom_end (p[1])) {
741c99fb5f9SBaptiste Daroussin 				if (!need_double) {
742c99fb5f9SBaptiste Daroussin 					need_double = true;
743c99fb5f9SBaptiste Daroussin 					dv = lv;
744c99fb5f9SBaptiste Daroussin 				}
745c99fb5f9SBaptiste Daroussin 				p ++;
746c99fb5f9SBaptiste Daroussin 				is_date = true;
747c99fb5f9SBaptiste Daroussin 				goto set_obj;
748c99fb5f9SBaptiste Daroussin 			}
749c99fb5f9SBaptiste Daroussin 			break;
750c99fb5f9SBaptiste Daroussin 		case 'h':
751c99fb5f9SBaptiste Daroussin 		case 'H':
752c99fb5f9SBaptiste Daroussin 		case 'd':
753c99fb5f9SBaptiste Daroussin 		case 'D':
754c99fb5f9SBaptiste Daroussin 		case 'w':
755c99fb5f9SBaptiste Daroussin 		case 'W':
756c99fb5f9SBaptiste Daroussin 		case 'Y':
757c99fb5f9SBaptiste Daroussin 		case 'y':
758c99fb5f9SBaptiste Daroussin 			if (p == end - 1 || ucl_lex_is_atom_end (p[1])) {
759c99fb5f9SBaptiste Daroussin 				if (!need_double) {
760c99fb5f9SBaptiste Daroussin 					need_double = true;
761c99fb5f9SBaptiste Daroussin 					dv = lv;
762c99fb5f9SBaptiste Daroussin 				}
763c99fb5f9SBaptiste Daroussin 				is_date = true;
764c99fb5f9SBaptiste Daroussin 				dv *= ucl_lex_time_multiplier (*p);
765c99fb5f9SBaptiste Daroussin 				p ++;
766c99fb5f9SBaptiste Daroussin 				goto set_obj;
767c99fb5f9SBaptiste Daroussin 			}
768c99fb5f9SBaptiste Daroussin 			break;
769c99fb5f9SBaptiste Daroussin 		}
770c99fb5f9SBaptiste Daroussin 	}
771c99fb5f9SBaptiste Daroussin 
772c99fb5f9SBaptiste Daroussin 	*pos = c;
773c99fb5f9SBaptiste Daroussin 	return EINVAL;
774c99fb5f9SBaptiste Daroussin 
775c99fb5f9SBaptiste Daroussin 	set_obj:
776c99fb5f9SBaptiste Daroussin 	if (allow_double && (need_double || is_date)) {
777c99fb5f9SBaptiste Daroussin 		if (!is_date) {
778c99fb5f9SBaptiste Daroussin 			obj->type = UCL_FLOAT;
779c99fb5f9SBaptiste Daroussin 		}
780c99fb5f9SBaptiste Daroussin 		else {
781c99fb5f9SBaptiste Daroussin 			obj->type = UCL_TIME;
782c99fb5f9SBaptiste Daroussin 		}
783c99fb5f9SBaptiste Daroussin 		obj->value.dv = is_neg ? (-dv) : dv;
784c99fb5f9SBaptiste Daroussin 	}
785c99fb5f9SBaptiste Daroussin 	else {
786c99fb5f9SBaptiste Daroussin 		obj->type = UCL_INT;
787c99fb5f9SBaptiste Daroussin 		obj->value.iv = is_neg ? (-lv) : lv;
788c99fb5f9SBaptiste Daroussin 	}
789c99fb5f9SBaptiste Daroussin 	*pos = p;
790c99fb5f9SBaptiste Daroussin 	return 0;
791c99fb5f9SBaptiste Daroussin }
792c99fb5f9SBaptiste Daroussin 
793c99fb5f9SBaptiste Daroussin /**
794c99fb5f9SBaptiste Daroussin  * Parse possible number
795c99fb5f9SBaptiste Daroussin  * @param parser
796c99fb5f9SBaptiste Daroussin  * @param chunk
797c99fb5f9SBaptiste Daroussin  * @return true if a number has been parsed
798c99fb5f9SBaptiste Daroussin  */
799c99fb5f9SBaptiste Daroussin static bool
800c99fb5f9SBaptiste Daroussin ucl_lex_number (struct ucl_parser *parser,
801c99fb5f9SBaptiste Daroussin 		struct ucl_chunk *chunk, ucl_object_t *obj)
802c99fb5f9SBaptiste Daroussin {
803c99fb5f9SBaptiste Daroussin 	const unsigned char *pos;
804c99fb5f9SBaptiste Daroussin 	int ret;
805c99fb5f9SBaptiste Daroussin 
806c99fb5f9SBaptiste Daroussin 	ret = ucl_maybe_parse_number (obj, chunk->pos, chunk->end, (const char **)&pos, true, false);
807c99fb5f9SBaptiste Daroussin 
808c99fb5f9SBaptiste Daroussin 	if (ret == 0) {
809c99fb5f9SBaptiste Daroussin 		chunk->remain -= pos - chunk->pos;
810c99fb5f9SBaptiste Daroussin 		chunk->column += pos - chunk->pos;
811c99fb5f9SBaptiste Daroussin 		chunk->pos = pos;
812c99fb5f9SBaptiste Daroussin 		return true;
813c99fb5f9SBaptiste Daroussin 	}
814c99fb5f9SBaptiste Daroussin 	else if (ret == ERANGE) {
815c99fb5f9SBaptiste Daroussin 		ucl_set_err (chunk, ERANGE, "numeric value out of range", &parser->err);
816c99fb5f9SBaptiste Daroussin 	}
817c99fb5f9SBaptiste Daroussin 
818c99fb5f9SBaptiste Daroussin 	return false;
819c99fb5f9SBaptiste Daroussin }
820c99fb5f9SBaptiste Daroussin 
821c99fb5f9SBaptiste Daroussin /**
822c99fb5f9SBaptiste Daroussin  * Parse quoted string with possible escapes
823c99fb5f9SBaptiste Daroussin  * @param parser
824c99fb5f9SBaptiste Daroussin  * @param chunk
825c99fb5f9SBaptiste Daroussin  * @return true if a string has been parsed
826c99fb5f9SBaptiste Daroussin  */
827c99fb5f9SBaptiste Daroussin static bool
828c99fb5f9SBaptiste Daroussin ucl_lex_json_string (struct ucl_parser *parser,
829c99fb5f9SBaptiste Daroussin 		struct ucl_chunk *chunk, bool *need_unescape, bool *ucl_escape, bool *var_expand)
830c99fb5f9SBaptiste Daroussin {
831c99fb5f9SBaptiste Daroussin 	const unsigned char *p = chunk->pos;
832c99fb5f9SBaptiste Daroussin 	unsigned char c;
833c99fb5f9SBaptiste Daroussin 	int i;
834c99fb5f9SBaptiste Daroussin 
835c99fb5f9SBaptiste Daroussin 	while (p < chunk->end) {
836c99fb5f9SBaptiste Daroussin 		c = *p;
837c99fb5f9SBaptiste Daroussin 		if (c < 0x1F) {
838c99fb5f9SBaptiste Daroussin 			/* Unmasked control character */
839c99fb5f9SBaptiste Daroussin 			if (c == '\n') {
840c99fb5f9SBaptiste Daroussin 				ucl_set_err (chunk, UCL_ESYNTAX, "unexpected newline", &parser->err);
841c99fb5f9SBaptiste Daroussin 			}
842c99fb5f9SBaptiste Daroussin 			else {
843c99fb5f9SBaptiste Daroussin 				ucl_set_err (chunk, UCL_ESYNTAX, "unexpected control character", &parser->err);
844c99fb5f9SBaptiste Daroussin 			}
845c99fb5f9SBaptiste Daroussin 			return false;
846c99fb5f9SBaptiste Daroussin 		}
847c99fb5f9SBaptiste Daroussin 		else if (c == '\\') {
848c99fb5f9SBaptiste Daroussin 			ucl_chunk_skipc (chunk, p);
849c99fb5f9SBaptiste Daroussin 			c = *p;
850c99fb5f9SBaptiste Daroussin 			if (p >= chunk->end) {
851c99fb5f9SBaptiste Daroussin 				ucl_set_err (chunk, UCL_ESYNTAX, "unfinished escape character", &parser->err);
852c99fb5f9SBaptiste Daroussin 				return false;
853c99fb5f9SBaptiste Daroussin 			}
854c99fb5f9SBaptiste Daroussin 			else if (ucl_test_character (c, UCL_CHARACTER_ESCAPE)) {
855c99fb5f9SBaptiste Daroussin 				if (c == 'u') {
856c99fb5f9SBaptiste Daroussin 					ucl_chunk_skipc (chunk, p);
857c99fb5f9SBaptiste Daroussin 					for (i = 0; i < 4 && p < chunk->end; i ++) {
858c99fb5f9SBaptiste Daroussin 						if (!isxdigit (*p)) {
859c99fb5f9SBaptiste Daroussin 							ucl_set_err (chunk, UCL_ESYNTAX, "invalid utf escape", &parser->err);
860c99fb5f9SBaptiste Daroussin 							return false;
861c99fb5f9SBaptiste Daroussin 						}
862c99fb5f9SBaptiste Daroussin 						ucl_chunk_skipc (chunk, p);
863c99fb5f9SBaptiste Daroussin 					}
864c99fb5f9SBaptiste Daroussin 					if (p >= chunk->end) {
865c99fb5f9SBaptiste Daroussin 						ucl_set_err (chunk, UCL_ESYNTAX, "unfinished escape character", &parser->err);
866c99fb5f9SBaptiste Daroussin 						return false;
867c99fb5f9SBaptiste Daroussin 					}
868c99fb5f9SBaptiste Daroussin 				}
869c99fb5f9SBaptiste Daroussin 				else {
870c99fb5f9SBaptiste Daroussin 					ucl_chunk_skipc (chunk, p);
871c99fb5f9SBaptiste Daroussin 				}
872c99fb5f9SBaptiste Daroussin 			}
873c99fb5f9SBaptiste Daroussin 			*need_unescape = true;
874c99fb5f9SBaptiste Daroussin 			*ucl_escape = true;
875c99fb5f9SBaptiste Daroussin 			continue;
876c99fb5f9SBaptiste Daroussin 		}
877c99fb5f9SBaptiste Daroussin 		else if (c == '"') {
878c99fb5f9SBaptiste Daroussin 			ucl_chunk_skipc (chunk, p);
879c99fb5f9SBaptiste Daroussin 			return true;
880c99fb5f9SBaptiste Daroussin 		}
881c99fb5f9SBaptiste Daroussin 		else if (ucl_test_character (c, UCL_CHARACTER_UCL_UNSAFE)) {
882c99fb5f9SBaptiste Daroussin 			*ucl_escape = true;
883c99fb5f9SBaptiste Daroussin 		}
884c99fb5f9SBaptiste Daroussin 		else if (c == '$') {
885c99fb5f9SBaptiste Daroussin 			*var_expand = true;
886c99fb5f9SBaptiste Daroussin 		}
887c99fb5f9SBaptiste Daroussin 		ucl_chunk_skipc (chunk, p);
888c99fb5f9SBaptiste Daroussin 	}
889c99fb5f9SBaptiste Daroussin 
890c99fb5f9SBaptiste Daroussin 	ucl_set_err (chunk, UCL_ESYNTAX, "no quote at the end of json string", &parser->err);
891c99fb5f9SBaptiste Daroussin 	return false;
892c99fb5f9SBaptiste Daroussin }
893c99fb5f9SBaptiste Daroussin 
894c99fb5f9SBaptiste Daroussin /**
895c99fb5f9SBaptiste Daroussin  * Parse a key in an object
896c99fb5f9SBaptiste Daroussin  * @param parser
897c99fb5f9SBaptiste Daroussin  * @param chunk
898c99fb5f9SBaptiste Daroussin  * @return true if a key has been parsed
899c99fb5f9SBaptiste Daroussin  */
900c99fb5f9SBaptiste Daroussin static bool
901c99fb5f9SBaptiste Daroussin ucl_parse_key (struct ucl_parser *parser, struct ucl_chunk *chunk, bool *next_key, bool *end_of_object)
902c99fb5f9SBaptiste Daroussin {
903c99fb5f9SBaptiste Daroussin 	const unsigned char *p, *c = NULL, *end, *t;
904c99fb5f9SBaptiste Daroussin 	const char *key = NULL;
905c99fb5f9SBaptiste Daroussin 	bool got_quote = false, got_eq = false, got_semicolon = false,
906c99fb5f9SBaptiste Daroussin 			need_unescape = false, ucl_escape = false, var_expand = false,
907c99fb5f9SBaptiste Daroussin 			got_content = false, got_sep = false;
908c99fb5f9SBaptiste Daroussin 	ucl_object_t *nobj, *tobj;
909c99fb5f9SBaptiste Daroussin 	ucl_hash_t *container;
910c99fb5f9SBaptiste Daroussin 	ssize_t keylen;
911c99fb5f9SBaptiste Daroussin 
912c99fb5f9SBaptiste Daroussin 	p = chunk->pos;
913c99fb5f9SBaptiste Daroussin 
914c99fb5f9SBaptiste Daroussin 	if (*p == '.') {
915c99fb5f9SBaptiste Daroussin 		/* It is macro actually */
916c99fb5f9SBaptiste Daroussin 		ucl_chunk_skipc (chunk, p);
917c99fb5f9SBaptiste Daroussin 		parser->prev_state = parser->state;
918c99fb5f9SBaptiste Daroussin 		parser->state = UCL_STATE_MACRO_NAME;
919c99fb5f9SBaptiste Daroussin 		return true;
920c99fb5f9SBaptiste Daroussin 	}
921c99fb5f9SBaptiste Daroussin 	while (p < chunk->end) {
922c99fb5f9SBaptiste Daroussin 		/*
923c99fb5f9SBaptiste Daroussin 		 * A key must start with alpha, number, '/' or '_' and end with space character
924c99fb5f9SBaptiste Daroussin 		 */
925c99fb5f9SBaptiste Daroussin 		if (c == NULL) {
926c99fb5f9SBaptiste Daroussin 			if (chunk->remain >= 2 && ucl_lex_is_comment (p[0], p[1])) {
927c99fb5f9SBaptiste Daroussin 				if (!ucl_skip_comments (parser)) {
928c99fb5f9SBaptiste Daroussin 					return false;
929c99fb5f9SBaptiste Daroussin 				}
930c99fb5f9SBaptiste Daroussin 				p = chunk->pos;
931c99fb5f9SBaptiste Daroussin 			}
932c99fb5f9SBaptiste Daroussin 			else if (ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE)) {
933c99fb5f9SBaptiste Daroussin 				ucl_chunk_skipc (chunk, p);
934c99fb5f9SBaptiste Daroussin 			}
935c99fb5f9SBaptiste Daroussin 			else if (ucl_test_character (*p, UCL_CHARACTER_KEY_START)) {
936c99fb5f9SBaptiste Daroussin 				/* The first symbol */
937c99fb5f9SBaptiste Daroussin 				c = p;
938c99fb5f9SBaptiste Daroussin 				ucl_chunk_skipc (chunk, p);
939c99fb5f9SBaptiste Daroussin 				got_content = true;
940c99fb5f9SBaptiste Daroussin 			}
941c99fb5f9SBaptiste Daroussin 			else if (*p == '"') {
942c99fb5f9SBaptiste Daroussin 				/* JSON style key */
943c99fb5f9SBaptiste Daroussin 				c = p + 1;
944c99fb5f9SBaptiste Daroussin 				got_quote = true;
945c99fb5f9SBaptiste Daroussin 				got_content = true;
946c99fb5f9SBaptiste Daroussin 				ucl_chunk_skipc (chunk, p);
947c99fb5f9SBaptiste Daroussin 			}
948c99fb5f9SBaptiste Daroussin 			else if (*p == '}') {
949c99fb5f9SBaptiste Daroussin 				/* We have actually end of an object */
950c99fb5f9SBaptiste Daroussin 				*end_of_object = true;
951c99fb5f9SBaptiste Daroussin 				return true;
952c99fb5f9SBaptiste Daroussin 			}
953c99fb5f9SBaptiste Daroussin 			else if (*p == '.') {
954c99fb5f9SBaptiste Daroussin 				ucl_chunk_skipc (chunk, p);
955c99fb5f9SBaptiste Daroussin 				parser->prev_state = parser->state;
956c99fb5f9SBaptiste Daroussin 				parser->state = UCL_STATE_MACRO_NAME;
957c99fb5f9SBaptiste Daroussin 				return true;
958c99fb5f9SBaptiste Daroussin 			}
959c99fb5f9SBaptiste Daroussin 			else {
960c99fb5f9SBaptiste Daroussin 				/* Invalid identifier */
961c99fb5f9SBaptiste Daroussin 				ucl_set_err (chunk, UCL_ESYNTAX, "key must begin with a letter", &parser->err);
962c99fb5f9SBaptiste Daroussin 				return false;
963c99fb5f9SBaptiste Daroussin 			}
964c99fb5f9SBaptiste Daroussin 		}
965c99fb5f9SBaptiste Daroussin 		else {
966c99fb5f9SBaptiste Daroussin 			/* Parse the body of a key */
967c99fb5f9SBaptiste Daroussin 			if (!got_quote) {
968c99fb5f9SBaptiste Daroussin 				if (ucl_test_character (*p, UCL_CHARACTER_KEY)) {
969c99fb5f9SBaptiste Daroussin 					got_content = true;
970c99fb5f9SBaptiste Daroussin 					ucl_chunk_skipc (chunk, p);
971c99fb5f9SBaptiste Daroussin 				}
972c99fb5f9SBaptiste Daroussin 				else if (ucl_test_character (*p, UCL_CHARACTER_KEY_SEP)) {
973c99fb5f9SBaptiste Daroussin 					end = p;
974c99fb5f9SBaptiste Daroussin 					break;
975c99fb5f9SBaptiste Daroussin 				}
976c99fb5f9SBaptiste Daroussin 				else {
977c99fb5f9SBaptiste Daroussin 					ucl_set_err (chunk, UCL_ESYNTAX, "invalid character in a key", &parser->err);
978c99fb5f9SBaptiste Daroussin 					return false;
979c99fb5f9SBaptiste Daroussin 				}
980c99fb5f9SBaptiste Daroussin 			}
981c99fb5f9SBaptiste Daroussin 			else {
982c99fb5f9SBaptiste Daroussin 				/* We need to parse json like quoted string */
983c99fb5f9SBaptiste Daroussin 				if (!ucl_lex_json_string (parser, chunk, &need_unescape, &ucl_escape, &var_expand)) {
984c99fb5f9SBaptiste Daroussin 					return false;
985c99fb5f9SBaptiste Daroussin 				}
986c99fb5f9SBaptiste Daroussin 				/* Always escape keys obtained via json */
987c99fb5f9SBaptiste Daroussin 				end = chunk->pos - 1;
988c99fb5f9SBaptiste Daroussin 				p = chunk->pos;
989c99fb5f9SBaptiste Daroussin 				break;
990c99fb5f9SBaptiste Daroussin 			}
991c99fb5f9SBaptiste Daroussin 		}
992c99fb5f9SBaptiste Daroussin 	}
993c99fb5f9SBaptiste Daroussin 
994c99fb5f9SBaptiste Daroussin 	if (p >= chunk->end && got_content) {
995c99fb5f9SBaptiste Daroussin 		ucl_set_err (chunk, UCL_ESYNTAX, "unfinished key", &parser->err);
996c99fb5f9SBaptiste Daroussin 		return false;
997c99fb5f9SBaptiste Daroussin 	}
998c99fb5f9SBaptiste Daroussin 	else if (!got_content) {
999c99fb5f9SBaptiste Daroussin 		return true;
1000c99fb5f9SBaptiste Daroussin 	}
1001c99fb5f9SBaptiste Daroussin 	*end_of_object = false;
1002c99fb5f9SBaptiste Daroussin 	/* We are now at the end of the key, need to parse the rest */
1003c99fb5f9SBaptiste Daroussin 	while (p < chunk->end) {
1004c99fb5f9SBaptiste Daroussin 		if (ucl_test_character (*p, UCL_CHARACTER_WHITESPACE)) {
1005c99fb5f9SBaptiste Daroussin 			ucl_chunk_skipc (chunk, p);
1006c99fb5f9SBaptiste Daroussin 		}
1007c99fb5f9SBaptiste Daroussin 		else if (*p == '=') {
1008c99fb5f9SBaptiste Daroussin 			if (!got_eq && !got_semicolon) {
1009c99fb5f9SBaptiste Daroussin 				ucl_chunk_skipc (chunk, p);
1010c99fb5f9SBaptiste Daroussin 				got_eq = true;
1011c99fb5f9SBaptiste Daroussin 			}
1012c99fb5f9SBaptiste Daroussin 			else {
1013c99fb5f9SBaptiste Daroussin 				ucl_set_err (chunk, UCL_ESYNTAX, "unexpected '=' character", &parser->err);
1014c99fb5f9SBaptiste Daroussin 				return false;
1015c99fb5f9SBaptiste Daroussin 			}
1016c99fb5f9SBaptiste Daroussin 		}
1017c99fb5f9SBaptiste Daroussin 		else if (*p == ':') {
1018c99fb5f9SBaptiste Daroussin 			if (!got_eq && !got_semicolon) {
1019c99fb5f9SBaptiste Daroussin 				ucl_chunk_skipc (chunk, p);
1020c99fb5f9SBaptiste Daroussin 				got_semicolon = true;
1021c99fb5f9SBaptiste Daroussin 			}
1022c99fb5f9SBaptiste Daroussin 			else {
1023c99fb5f9SBaptiste Daroussin 				ucl_set_err (chunk, UCL_ESYNTAX, "unexpected ':' character", &parser->err);
1024c99fb5f9SBaptiste Daroussin 				return false;
1025c99fb5f9SBaptiste Daroussin 			}
1026c99fb5f9SBaptiste Daroussin 		}
1027c99fb5f9SBaptiste Daroussin 		else if (chunk->remain >= 2 && ucl_lex_is_comment (p[0], p[1])) {
1028c99fb5f9SBaptiste Daroussin 			/* Check for comment */
1029c99fb5f9SBaptiste Daroussin 			if (!ucl_skip_comments (parser)) {
1030c99fb5f9SBaptiste Daroussin 				return false;
1031c99fb5f9SBaptiste Daroussin 			}
1032c99fb5f9SBaptiste Daroussin 			p = chunk->pos;
1033c99fb5f9SBaptiste Daroussin 		}
1034c99fb5f9SBaptiste Daroussin 		else {
1035c99fb5f9SBaptiste Daroussin 			/* Start value */
1036c99fb5f9SBaptiste Daroussin 			break;
1037c99fb5f9SBaptiste Daroussin 		}
1038c99fb5f9SBaptiste Daroussin 	}
1039c99fb5f9SBaptiste Daroussin 
1040c99fb5f9SBaptiste Daroussin 	if (p >= chunk->end && got_content) {
1041c99fb5f9SBaptiste Daroussin 		ucl_set_err (chunk, UCL_ESYNTAX, "unfinished key", &parser->err);
1042c99fb5f9SBaptiste Daroussin 		return false;
1043c99fb5f9SBaptiste Daroussin 	}
1044c99fb5f9SBaptiste Daroussin 
1045c99fb5f9SBaptiste Daroussin 	got_sep = got_semicolon || got_eq;
1046c99fb5f9SBaptiste Daroussin 
1047c99fb5f9SBaptiste Daroussin 	if (!got_sep) {
1048c99fb5f9SBaptiste Daroussin 		/*
1049c99fb5f9SBaptiste Daroussin 		 * Maybe we have more keys nested, so search for termination character.
1050c99fb5f9SBaptiste Daroussin 		 * Possible choices:
1051c99fb5f9SBaptiste Daroussin 		 * 1) key1 key2 ... keyN [:=] value <- we treat that as error
1052c99fb5f9SBaptiste Daroussin 		 * 2) key1 ... keyN {} or [] <- we treat that as nested objects
1053c99fb5f9SBaptiste Daroussin 		 * 3) key1 value[;,\n] <- we treat that as linear object
1054c99fb5f9SBaptiste Daroussin 		 */
1055c99fb5f9SBaptiste Daroussin 		t = p;
1056c99fb5f9SBaptiste Daroussin 		*next_key = false;
1057c99fb5f9SBaptiste Daroussin 		while (ucl_test_character (*t, UCL_CHARACTER_WHITESPACE)) {
1058c99fb5f9SBaptiste Daroussin 			t ++;
1059c99fb5f9SBaptiste Daroussin 		}
1060c99fb5f9SBaptiste Daroussin 		/* Check first non-space character after a key */
1061c99fb5f9SBaptiste Daroussin 		if (*t != '{' && *t != '[') {
1062c99fb5f9SBaptiste Daroussin 			while (t < chunk->end) {
1063c99fb5f9SBaptiste Daroussin 				if (*t == ',' || *t == ';' || *t == '\n' || *t == '\r') {
1064c99fb5f9SBaptiste Daroussin 					break;
1065c99fb5f9SBaptiste Daroussin 				}
1066c99fb5f9SBaptiste Daroussin 				else if (*t == '{' || *t == '[') {
1067c99fb5f9SBaptiste Daroussin 					*next_key = true;
1068c99fb5f9SBaptiste Daroussin 					break;
1069c99fb5f9SBaptiste Daroussin 				}
1070c99fb5f9SBaptiste Daroussin 				t ++;
1071c99fb5f9SBaptiste Daroussin 			}
1072c99fb5f9SBaptiste Daroussin 		}
1073c99fb5f9SBaptiste Daroussin 	}
1074c99fb5f9SBaptiste Daroussin 
1075c99fb5f9SBaptiste Daroussin 	/* Create a new object */
1076c99fb5f9SBaptiste Daroussin 	nobj = ucl_object_new ();
1077c99fb5f9SBaptiste Daroussin 	keylen = ucl_copy_or_store_ptr (parser, c, &nobj->trash_stack[UCL_TRASH_KEY],
1078c99fb5f9SBaptiste Daroussin 			&key, end - c, need_unescape, parser->flags & UCL_PARSER_KEY_LOWERCASE, false);
1079c99fb5f9SBaptiste Daroussin 	if (keylen == -1) {
1080c99fb5f9SBaptiste Daroussin 		ucl_object_free(nobj);
1081c99fb5f9SBaptiste Daroussin 		return false;
1082c99fb5f9SBaptiste Daroussin 	}
1083c99fb5f9SBaptiste Daroussin 	else if (keylen == 0) {
1084c99fb5f9SBaptiste Daroussin 		ucl_set_err (chunk, UCL_ESYNTAX, "empty keys are not allowed", &parser->err);
1085c99fb5f9SBaptiste Daroussin 		ucl_object_free(nobj);
1086c99fb5f9SBaptiste Daroussin 		return false;
1087c99fb5f9SBaptiste Daroussin 	}
1088c99fb5f9SBaptiste Daroussin 
1089c99fb5f9SBaptiste Daroussin 	container = parser->stack->obj->value.ov;
1090c99fb5f9SBaptiste Daroussin 	nobj->key = key;
1091c99fb5f9SBaptiste Daroussin 	nobj->keylen = keylen;
1092c99fb5f9SBaptiste Daroussin 	tobj = ucl_hash_search_obj (container, nobj);
1093c99fb5f9SBaptiste Daroussin 	if (tobj == NULL) {
1094c99fb5f9SBaptiste Daroussin 		container = ucl_hash_insert_object (container, nobj);
1095c99fb5f9SBaptiste Daroussin 		nobj->prev = nobj;
1096c99fb5f9SBaptiste Daroussin 		nobj->next = NULL;
1097c99fb5f9SBaptiste Daroussin 		parser->stack->obj->len ++;
1098c99fb5f9SBaptiste Daroussin 	}
1099c99fb5f9SBaptiste Daroussin 	else {
1100c99fb5f9SBaptiste Daroussin 		DL_APPEND (tobj, nobj);
1101c99fb5f9SBaptiste Daroussin 	}
1102c99fb5f9SBaptiste Daroussin 
1103c99fb5f9SBaptiste Daroussin 	if (ucl_escape) {
1104c99fb5f9SBaptiste Daroussin 		nobj->flags |= UCL_OBJECT_NEED_KEY_ESCAPE;
1105c99fb5f9SBaptiste Daroussin 	}
1106c99fb5f9SBaptiste Daroussin 	parser->stack->obj->value.ov = container;
1107c99fb5f9SBaptiste Daroussin 
1108c99fb5f9SBaptiste Daroussin 	parser->cur_obj = nobj;
1109c99fb5f9SBaptiste Daroussin 
1110c99fb5f9SBaptiste Daroussin 	return true;
1111c99fb5f9SBaptiste Daroussin }
1112c99fb5f9SBaptiste Daroussin 
1113c99fb5f9SBaptiste Daroussin /**
1114c99fb5f9SBaptiste Daroussin  * Parse a cl string
1115c99fb5f9SBaptiste Daroussin  * @param parser
1116c99fb5f9SBaptiste Daroussin  * @param chunk
1117c99fb5f9SBaptiste Daroussin  * @return true if a key has been parsed
1118c99fb5f9SBaptiste Daroussin  */
1119c99fb5f9SBaptiste Daroussin static bool
1120c99fb5f9SBaptiste Daroussin ucl_parse_string_value (struct ucl_parser *parser,
1121c99fb5f9SBaptiste Daroussin 		struct ucl_chunk *chunk, bool *var_expand, bool *need_unescape)
1122c99fb5f9SBaptiste Daroussin {
1123c99fb5f9SBaptiste Daroussin 	const unsigned char *p;
1124c99fb5f9SBaptiste Daroussin 	enum {
1125c99fb5f9SBaptiste Daroussin 		UCL_BRACE_ROUND = 0,
1126c99fb5f9SBaptiste Daroussin 		UCL_BRACE_SQUARE,
1127c99fb5f9SBaptiste Daroussin 		UCL_BRACE_FIGURE
1128c99fb5f9SBaptiste Daroussin 	};
1129c99fb5f9SBaptiste Daroussin 	int braces[3][2] = {{0, 0}, {0, 0}, {0, 0}};
1130c99fb5f9SBaptiste Daroussin 
1131c99fb5f9SBaptiste Daroussin 	p = chunk->pos;
1132c99fb5f9SBaptiste Daroussin 
1133c99fb5f9SBaptiste Daroussin 	while (p < chunk->end) {
1134c99fb5f9SBaptiste Daroussin 
1135c99fb5f9SBaptiste Daroussin 		/* Skip pairs of figure braces */
1136c99fb5f9SBaptiste Daroussin 		if (*p == '{') {
1137c99fb5f9SBaptiste Daroussin 			braces[UCL_BRACE_FIGURE][0] ++;
1138c99fb5f9SBaptiste Daroussin 		}
1139c99fb5f9SBaptiste Daroussin 		else if (*p == '}') {
1140c99fb5f9SBaptiste Daroussin 			braces[UCL_BRACE_FIGURE][1] ++;
1141c99fb5f9SBaptiste Daroussin 			if (braces[UCL_BRACE_FIGURE][1] <= braces[UCL_BRACE_FIGURE][0]) {
1142c99fb5f9SBaptiste Daroussin 				/* This is not a termination symbol, continue */
1143c99fb5f9SBaptiste Daroussin 				ucl_chunk_skipc (chunk, p);
1144c99fb5f9SBaptiste Daroussin 				continue;
1145c99fb5f9SBaptiste Daroussin 			}
1146c99fb5f9SBaptiste Daroussin 		}
1147c99fb5f9SBaptiste Daroussin 		/* Skip pairs of square braces */
1148c99fb5f9SBaptiste Daroussin 		else if (*p == '[') {
1149c99fb5f9SBaptiste Daroussin 			braces[UCL_BRACE_SQUARE][0] ++;
1150c99fb5f9SBaptiste Daroussin 		}
1151c99fb5f9SBaptiste Daroussin 		else if (*p == ']') {
1152c99fb5f9SBaptiste Daroussin 			braces[UCL_BRACE_SQUARE][1] ++;
1153c99fb5f9SBaptiste Daroussin 			if (braces[UCL_BRACE_SQUARE][1] <= braces[UCL_BRACE_SQUARE][0]) {
1154c99fb5f9SBaptiste Daroussin 				/* This is not a termination symbol, continue */
1155c99fb5f9SBaptiste Daroussin 				ucl_chunk_skipc (chunk, p);
1156c99fb5f9SBaptiste Daroussin 				continue;
1157c99fb5f9SBaptiste Daroussin 			}
1158c99fb5f9SBaptiste Daroussin 		}
1159c99fb5f9SBaptiste Daroussin 		else if (*p == '$') {
1160c99fb5f9SBaptiste Daroussin 			*var_expand = true;
1161c99fb5f9SBaptiste Daroussin 		}
1162c99fb5f9SBaptiste Daroussin 		else if (*p == '\\') {
1163c99fb5f9SBaptiste Daroussin 			*need_unescape = true;
1164c99fb5f9SBaptiste Daroussin 			ucl_chunk_skipc (chunk, p);
1165c99fb5f9SBaptiste Daroussin 			if (p < chunk->end) {
1166c99fb5f9SBaptiste Daroussin 				ucl_chunk_skipc (chunk, p);
1167c99fb5f9SBaptiste Daroussin 			}
1168c99fb5f9SBaptiste Daroussin 			continue;
1169c99fb5f9SBaptiste Daroussin 		}
1170c99fb5f9SBaptiste Daroussin 
1171c99fb5f9SBaptiste Daroussin 		if (ucl_lex_is_atom_end (*p) || (chunk->remain >= 2 && ucl_lex_is_comment (p[0], p[1]))) {
1172c99fb5f9SBaptiste Daroussin 			break;
1173c99fb5f9SBaptiste Daroussin 		}
1174c99fb5f9SBaptiste Daroussin 		ucl_chunk_skipc (chunk, p);
1175c99fb5f9SBaptiste Daroussin 	}
1176c99fb5f9SBaptiste Daroussin 
1177c99fb5f9SBaptiste Daroussin 	if (p >= chunk->end) {
1178c99fb5f9SBaptiste Daroussin 		ucl_set_err (chunk, UCL_ESYNTAX, "unfinished value", &parser->err);
1179c99fb5f9SBaptiste Daroussin 		return false;
1180c99fb5f9SBaptiste Daroussin 	}
1181c99fb5f9SBaptiste Daroussin 
1182c99fb5f9SBaptiste Daroussin 	return true;
1183c99fb5f9SBaptiste Daroussin }
1184c99fb5f9SBaptiste Daroussin 
1185c99fb5f9SBaptiste Daroussin /**
1186c99fb5f9SBaptiste Daroussin  * Parse multiline string ending with \n{term}\n
1187c99fb5f9SBaptiste Daroussin  * @param parser
1188c99fb5f9SBaptiste Daroussin  * @param chunk
1189c99fb5f9SBaptiste Daroussin  * @param term
1190c99fb5f9SBaptiste Daroussin  * @param term_len
1191c99fb5f9SBaptiste Daroussin  * @return size of multiline string or 0 in case of error
1192c99fb5f9SBaptiste Daroussin  */
1193c99fb5f9SBaptiste Daroussin static int
1194c99fb5f9SBaptiste Daroussin ucl_parse_multiline_string (struct ucl_parser *parser,
1195c99fb5f9SBaptiste Daroussin 		struct ucl_chunk *chunk, const unsigned char *term,
1196c99fb5f9SBaptiste Daroussin 		int term_len, unsigned char const **beg,
1197c99fb5f9SBaptiste Daroussin 		bool *var_expand)
1198c99fb5f9SBaptiste Daroussin {
1199c99fb5f9SBaptiste Daroussin 	const unsigned char *p, *c;
1200c99fb5f9SBaptiste Daroussin 	bool newline = false;
1201c99fb5f9SBaptiste Daroussin 	int len = 0;
1202c99fb5f9SBaptiste Daroussin 
1203c99fb5f9SBaptiste Daroussin 	p = chunk->pos;
1204c99fb5f9SBaptiste Daroussin 
1205c99fb5f9SBaptiste Daroussin 	c = p;
1206c99fb5f9SBaptiste Daroussin 
1207c99fb5f9SBaptiste Daroussin 	while (p < chunk->end) {
1208c99fb5f9SBaptiste Daroussin 		if (newline) {
1209c99fb5f9SBaptiste Daroussin 			if (chunk->end - p < term_len) {
1210c99fb5f9SBaptiste Daroussin 				return 0;
1211c99fb5f9SBaptiste Daroussin 			}
1212c99fb5f9SBaptiste Daroussin 			else if (memcmp (p, term, term_len) == 0 && (p[term_len] == '\n' || p[term_len] == '\r')) {
1213c99fb5f9SBaptiste Daroussin 				len = p - c;
1214c99fb5f9SBaptiste Daroussin 				chunk->remain -= term_len;
1215c99fb5f9SBaptiste Daroussin 				chunk->pos = p + term_len;
1216c99fb5f9SBaptiste Daroussin 				chunk->column = term_len;
1217c99fb5f9SBaptiste Daroussin 				*beg = c;
1218c99fb5f9SBaptiste Daroussin 				break;
1219c99fb5f9SBaptiste Daroussin 			}
1220c99fb5f9SBaptiste Daroussin 		}
1221c99fb5f9SBaptiste Daroussin 		if (*p == '\n') {
1222c99fb5f9SBaptiste Daroussin 			newline = true;
1223c99fb5f9SBaptiste Daroussin 		}
1224c99fb5f9SBaptiste Daroussin 		else {
1225c99fb5f9SBaptiste Daroussin 			if (*p == '$') {
1226c99fb5f9SBaptiste Daroussin 				*var_expand = true;
1227c99fb5f9SBaptiste Daroussin 			}
1228c99fb5f9SBaptiste Daroussin 			newline = false;
1229c99fb5f9SBaptiste Daroussin 		}
1230c99fb5f9SBaptiste Daroussin 		ucl_chunk_skipc (chunk, p);
1231c99fb5f9SBaptiste Daroussin 	}
1232c99fb5f9SBaptiste Daroussin 
1233c99fb5f9SBaptiste Daroussin 	return len;
1234c99fb5f9SBaptiste Daroussin }
1235c99fb5f9SBaptiste Daroussin 
1236*36c53d67SBaptiste Daroussin static ucl_object_t*
1237*36c53d67SBaptiste Daroussin ucl_get_value_object (struct ucl_parser *parser)
1238c99fb5f9SBaptiste Daroussin {
1239*36c53d67SBaptiste Daroussin 	ucl_object_t *t, *obj = NULL;
1240c99fb5f9SBaptiste Daroussin 
1241c99fb5f9SBaptiste Daroussin 	if (parser->stack->obj->type == UCL_ARRAY) {
1242c99fb5f9SBaptiste Daroussin 		/* Object must be allocated */
1243c99fb5f9SBaptiste Daroussin 		obj = ucl_object_new ();
1244c99fb5f9SBaptiste Daroussin 		t = parser->stack->obj->value.av;
1245c99fb5f9SBaptiste Daroussin 		DL_APPEND (t, obj);
1246c99fb5f9SBaptiste Daroussin 		parser->cur_obj = obj;
1247c99fb5f9SBaptiste Daroussin 		parser->stack->obj->value.av = t;
1248c99fb5f9SBaptiste Daroussin 		parser->stack->obj->len ++;
1249c99fb5f9SBaptiste Daroussin 	}
1250c99fb5f9SBaptiste Daroussin 	else {
1251c99fb5f9SBaptiste Daroussin 		/* Object has been already allocated */
1252c99fb5f9SBaptiste Daroussin 		obj = parser->cur_obj;
1253c99fb5f9SBaptiste Daroussin 	}
1254*36c53d67SBaptiste Daroussin 
1255*36c53d67SBaptiste Daroussin 	return obj;
1256c99fb5f9SBaptiste Daroussin }
1257*36c53d67SBaptiste Daroussin 
1258*36c53d67SBaptiste Daroussin /**
1259*36c53d67SBaptiste Daroussin  * Handle value data
1260*36c53d67SBaptiste Daroussin  * @param parser
1261*36c53d67SBaptiste Daroussin  * @param chunk
1262*36c53d67SBaptiste Daroussin  * @return
1263*36c53d67SBaptiste Daroussin  */
1264*36c53d67SBaptiste Daroussin static bool
1265*36c53d67SBaptiste Daroussin ucl_parse_value (struct ucl_parser *parser, struct ucl_chunk *chunk)
1266*36c53d67SBaptiste Daroussin {
1267*36c53d67SBaptiste Daroussin 	const unsigned char *p, *c;
1268*36c53d67SBaptiste Daroussin 	ucl_object_t *obj = NULL;
1269*36c53d67SBaptiste Daroussin 	unsigned int stripped_spaces;
1270*36c53d67SBaptiste Daroussin 	int str_len;
1271*36c53d67SBaptiste Daroussin 	bool need_unescape = false, ucl_escape = false, var_expand = false;
1272*36c53d67SBaptiste Daroussin 
1273*36c53d67SBaptiste Daroussin 	p = chunk->pos;
1274*36c53d67SBaptiste Daroussin 
1275*36c53d67SBaptiste Daroussin 	/* Skip any spaces and comments */
1276*36c53d67SBaptiste Daroussin 	if (ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE) ||
1277*36c53d67SBaptiste Daroussin 			(chunk->remain >= 2 && ucl_lex_is_comment (p[0], p[1]))) {
1278*36c53d67SBaptiste Daroussin 		while (p < chunk->end && ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE)) {
1279*36c53d67SBaptiste Daroussin 			ucl_chunk_skipc (chunk, p);
1280*36c53d67SBaptiste Daroussin 		}
1281*36c53d67SBaptiste Daroussin 		if (!ucl_skip_comments (parser)) {
1282*36c53d67SBaptiste Daroussin 			return false;
1283*36c53d67SBaptiste Daroussin 		}
1284*36c53d67SBaptiste Daroussin 		p = chunk->pos;
1285*36c53d67SBaptiste Daroussin 	}
1286*36c53d67SBaptiste Daroussin 
1287*36c53d67SBaptiste Daroussin 	while (p < chunk->end) {
1288c99fb5f9SBaptiste Daroussin 		c = p;
1289c99fb5f9SBaptiste Daroussin 		switch (*p) {
1290c99fb5f9SBaptiste Daroussin 		case '"':
1291*36c53d67SBaptiste Daroussin 			obj = ucl_get_value_object (parser);
1292c99fb5f9SBaptiste Daroussin 			ucl_chunk_skipc (chunk, p);
1293c99fb5f9SBaptiste Daroussin 			if (!ucl_lex_json_string (parser, chunk, &need_unescape, &ucl_escape, &var_expand)) {
1294c99fb5f9SBaptiste Daroussin 				return false;
1295c99fb5f9SBaptiste Daroussin 			}
1296c99fb5f9SBaptiste Daroussin 			str_len = chunk->pos - c - 2;
1297c99fb5f9SBaptiste Daroussin 			obj->type = UCL_STRING;
1298c99fb5f9SBaptiste Daroussin 			if ((str_len = ucl_copy_or_store_ptr (parser, c + 1, &obj->trash_stack[UCL_TRASH_VALUE],
1299c99fb5f9SBaptiste Daroussin 					&obj->value.sv, str_len, need_unescape, false, var_expand)) == -1) {
1300c99fb5f9SBaptiste Daroussin 				return false;
1301c99fb5f9SBaptiste Daroussin 			}
1302c99fb5f9SBaptiste Daroussin 			obj->len = str_len;
1303c99fb5f9SBaptiste Daroussin 			parser->state = UCL_STATE_AFTER_VALUE;
1304c99fb5f9SBaptiste Daroussin 			p = chunk->pos;
1305c99fb5f9SBaptiste Daroussin 			return true;
1306c99fb5f9SBaptiste Daroussin 			break;
1307c99fb5f9SBaptiste Daroussin 		case '{':
1308*36c53d67SBaptiste Daroussin 			obj = ucl_get_value_object (parser);
1309c99fb5f9SBaptiste Daroussin 			/* We have a new object */
1310c99fb5f9SBaptiste Daroussin 			obj = ucl_add_parser_stack (obj, parser, false, parser->stack->level);
1311c99fb5f9SBaptiste Daroussin 
1312c99fb5f9SBaptiste Daroussin 			ucl_chunk_skipc (chunk, p);
1313c99fb5f9SBaptiste Daroussin 			return true;
1314c99fb5f9SBaptiste Daroussin 			break;
1315c99fb5f9SBaptiste Daroussin 		case '[':
1316*36c53d67SBaptiste Daroussin 			obj = ucl_get_value_object (parser);
1317c99fb5f9SBaptiste Daroussin 			/* We have a new array */
1318c99fb5f9SBaptiste Daroussin 			obj = ucl_add_parser_stack (obj, parser, true, parser->stack->level);
1319c99fb5f9SBaptiste Daroussin 
1320c99fb5f9SBaptiste Daroussin 			ucl_chunk_skipc (chunk, p);
1321c99fb5f9SBaptiste Daroussin 			return true;
1322c99fb5f9SBaptiste Daroussin 			break;
1323*36c53d67SBaptiste Daroussin 		case ']':
1324*36c53d67SBaptiste Daroussin 			/* We have the array ending */
1325*36c53d67SBaptiste Daroussin 			if (parser->stack && parser->stack->obj->type == UCL_ARRAY) {
1326*36c53d67SBaptiste Daroussin 				parser->state = UCL_STATE_AFTER_VALUE;
1327*36c53d67SBaptiste Daroussin 				return true;
1328*36c53d67SBaptiste Daroussin 			}
1329*36c53d67SBaptiste Daroussin 			else {
1330*36c53d67SBaptiste Daroussin 				goto parse_string;
1331*36c53d67SBaptiste Daroussin 			}
1332*36c53d67SBaptiste Daroussin 			break;
1333c99fb5f9SBaptiste Daroussin 		case '<':
1334*36c53d67SBaptiste Daroussin 			obj = ucl_get_value_object (parser);
1335c99fb5f9SBaptiste Daroussin 			/* We have something like multiline value, which must be <<[A-Z]+\n */
1336c99fb5f9SBaptiste Daroussin 			if (chunk->end - p > 3) {
1337c99fb5f9SBaptiste Daroussin 				if (memcmp (p, "<<", 2) == 0) {
1338c99fb5f9SBaptiste Daroussin 					p += 2;
1339c99fb5f9SBaptiste Daroussin 					/* We allow only uppercase characters in multiline definitions */
1340c99fb5f9SBaptiste Daroussin 					while (p < chunk->end && *p >= 'A' && *p <= 'Z') {
1341c99fb5f9SBaptiste Daroussin 						p ++;
1342c99fb5f9SBaptiste Daroussin 					}
1343c99fb5f9SBaptiste Daroussin 					if (*p =='\n') {
1344c99fb5f9SBaptiste Daroussin 						/* Set chunk positions and start multiline parsing */
1345c99fb5f9SBaptiste Daroussin 						c += 2;
1346c99fb5f9SBaptiste Daroussin 						chunk->remain -= p - c;
1347c99fb5f9SBaptiste Daroussin 						chunk->pos = p + 1;
1348c99fb5f9SBaptiste Daroussin 						chunk->column = 0;
1349c99fb5f9SBaptiste Daroussin 						chunk->line ++;
1350c99fb5f9SBaptiste Daroussin 						if ((str_len = ucl_parse_multiline_string (parser, chunk, c,
1351c99fb5f9SBaptiste Daroussin 								p - c, &c, &var_expand)) == 0) {
1352c99fb5f9SBaptiste Daroussin 							ucl_set_err (chunk, UCL_ESYNTAX, "unterminated multiline value", &parser->err);
1353c99fb5f9SBaptiste Daroussin 							return false;
1354c99fb5f9SBaptiste Daroussin 						}
1355c99fb5f9SBaptiste Daroussin 						obj->type = UCL_STRING;
1356c99fb5f9SBaptiste Daroussin 						if ((str_len = ucl_copy_or_store_ptr (parser, c, &obj->trash_stack[UCL_TRASH_VALUE],
1357c99fb5f9SBaptiste Daroussin 							&obj->value.sv, str_len - 1, false, false, var_expand)) == -1) {
1358c99fb5f9SBaptiste Daroussin 							return false;
1359c99fb5f9SBaptiste Daroussin 						}
1360c99fb5f9SBaptiste Daroussin 						obj->len = str_len;
1361c99fb5f9SBaptiste Daroussin 						parser->state = UCL_STATE_AFTER_VALUE;
1362c99fb5f9SBaptiste Daroussin 						return true;
1363c99fb5f9SBaptiste Daroussin 					}
1364c99fb5f9SBaptiste Daroussin 				}
1365c99fb5f9SBaptiste Daroussin 			}
1366c99fb5f9SBaptiste Daroussin 			/* Fallback to ordinary strings */
1367c99fb5f9SBaptiste Daroussin 		default:
1368*36c53d67SBaptiste Daroussin parse_string:
1369*36c53d67SBaptiste Daroussin 			if (obj == NULL) {
1370*36c53d67SBaptiste Daroussin 				obj = ucl_get_value_object (parser);
1371c99fb5f9SBaptiste Daroussin 			}
1372c99fb5f9SBaptiste Daroussin 			/* Parse atom */
1373c99fb5f9SBaptiste Daroussin 			if (ucl_test_character (*p, UCL_CHARACTER_VALUE_DIGIT_START)) {
1374c99fb5f9SBaptiste Daroussin 				if (!ucl_lex_number (parser, chunk, obj)) {
1375c99fb5f9SBaptiste Daroussin 					if (parser->state == UCL_STATE_ERROR) {
1376c99fb5f9SBaptiste Daroussin 						return false;
1377c99fb5f9SBaptiste Daroussin 					}
1378c99fb5f9SBaptiste Daroussin 				}
1379c99fb5f9SBaptiste Daroussin 				else {
1380c99fb5f9SBaptiste Daroussin 					parser->state = UCL_STATE_AFTER_VALUE;
1381c99fb5f9SBaptiste Daroussin 					return true;
1382c99fb5f9SBaptiste Daroussin 				}
1383c99fb5f9SBaptiste Daroussin 				/* Fallback to normal string */
1384c99fb5f9SBaptiste Daroussin 			}
1385c99fb5f9SBaptiste Daroussin 
1386c99fb5f9SBaptiste Daroussin 			if (!ucl_parse_string_value (parser, chunk, &var_expand, &need_unescape)) {
1387c99fb5f9SBaptiste Daroussin 				return false;
1388c99fb5f9SBaptiste Daroussin 			}
1389c99fb5f9SBaptiste Daroussin 			/* Cut trailing spaces */
1390c99fb5f9SBaptiste Daroussin 			stripped_spaces = 0;
1391c99fb5f9SBaptiste Daroussin 			while (ucl_test_character (*(chunk->pos - 1 - stripped_spaces),
1392c99fb5f9SBaptiste Daroussin 					UCL_CHARACTER_WHITESPACE)) {
1393c99fb5f9SBaptiste Daroussin 				stripped_spaces ++;
1394c99fb5f9SBaptiste Daroussin 			}
1395c99fb5f9SBaptiste Daroussin 			str_len = chunk->pos - c - stripped_spaces;
1396c99fb5f9SBaptiste Daroussin 			if (str_len <= 0) {
1397c99fb5f9SBaptiste Daroussin 				ucl_set_err (chunk, 0, "string value must not be empty", &parser->err);
1398c99fb5f9SBaptiste Daroussin 				return false;
1399c99fb5f9SBaptiste Daroussin 			}
1400c99fb5f9SBaptiste Daroussin 			else if (str_len == 4 && memcmp (c, "null", 4) == 0) {
1401c99fb5f9SBaptiste Daroussin 				obj->len = 0;
1402c99fb5f9SBaptiste Daroussin 				obj->type = UCL_NULL;
1403c99fb5f9SBaptiste Daroussin 			}
1404c99fb5f9SBaptiste Daroussin 			else if (!ucl_maybe_parse_boolean (obj, c, str_len)) {
1405c99fb5f9SBaptiste Daroussin 				obj->type = UCL_STRING;
1406c99fb5f9SBaptiste Daroussin 				if ((str_len = ucl_copy_or_store_ptr (parser, c, &obj->trash_stack[UCL_TRASH_VALUE],
1407c99fb5f9SBaptiste Daroussin 						&obj->value.sv, str_len, need_unescape,
1408c99fb5f9SBaptiste Daroussin 						false, var_expand)) == -1) {
1409c99fb5f9SBaptiste Daroussin 					return false;
1410c99fb5f9SBaptiste Daroussin 				}
1411c99fb5f9SBaptiste Daroussin 				obj->len = str_len;
1412c99fb5f9SBaptiste Daroussin 			}
1413c99fb5f9SBaptiste Daroussin 			parser->state = UCL_STATE_AFTER_VALUE;
1414c99fb5f9SBaptiste Daroussin 			p = chunk->pos;
1415c99fb5f9SBaptiste Daroussin 
1416c99fb5f9SBaptiste Daroussin 			return true;
1417c99fb5f9SBaptiste Daroussin 			break;
1418c99fb5f9SBaptiste Daroussin 		}
1419c99fb5f9SBaptiste Daroussin 	}
1420c99fb5f9SBaptiste Daroussin 
1421c99fb5f9SBaptiste Daroussin 	return true;
1422c99fb5f9SBaptiste Daroussin }
1423c99fb5f9SBaptiste Daroussin 
1424c99fb5f9SBaptiste Daroussin /**
1425c99fb5f9SBaptiste Daroussin  * Handle after value data
1426c99fb5f9SBaptiste Daroussin  * @param parser
1427c99fb5f9SBaptiste Daroussin  * @param chunk
1428c99fb5f9SBaptiste Daroussin  * @return
1429c99fb5f9SBaptiste Daroussin  */
1430c99fb5f9SBaptiste Daroussin static bool
1431c99fb5f9SBaptiste Daroussin ucl_parse_after_value (struct ucl_parser *parser, struct ucl_chunk *chunk)
1432c99fb5f9SBaptiste Daroussin {
1433c99fb5f9SBaptiste Daroussin 	const unsigned char *p;
1434c99fb5f9SBaptiste Daroussin 	bool got_sep = false;
1435c99fb5f9SBaptiste Daroussin 	struct ucl_stack *st;
1436c99fb5f9SBaptiste Daroussin 
1437c99fb5f9SBaptiste Daroussin 	p = chunk->pos;
1438c99fb5f9SBaptiste Daroussin 
1439c99fb5f9SBaptiste Daroussin 	while (p < chunk->end) {
1440c99fb5f9SBaptiste Daroussin 		if (ucl_test_character (*p, UCL_CHARACTER_WHITESPACE)) {
1441c99fb5f9SBaptiste Daroussin 			/* Skip whitespaces */
1442c99fb5f9SBaptiste Daroussin 			ucl_chunk_skipc (chunk, p);
1443c99fb5f9SBaptiste Daroussin 		}
1444c99fb5f9SBaptiste Daroussin 		else if (chunk->remain >= 2 && ucl_lex_is_comment (p[0], p[1])) {
1445c99fb5f9SBaptiste Daroussin 			/* Skip comment */
1446c99fb5f9SBaptiste Daroussin 			if (!ucl_skip_comments (parser)) {
1447c99fb5f9SBaptiste Daroussin 				return false;
1448c99fb5f9SBaptiste Daroussin 			}
1449c99fb5f9SBaptiste Daroussin 			/* Treat comment as a separator */
1450c99fb5f9SBaptiste Daroussin 			got_sep = true;
1451c99fb5f9SBaptiste Daroussin 			p = chunk->pos;
1452c99fb5f9SBaptiste Daroussin 		}
1453c99fb5f9SBaptiste Daroussin 		else if (ucl_test_character (*p, UCL_CHARACTER_VALUE_END)) {
1454c99fb5f9SBaptiste Daroussin 			if (*p == '}' || *p == ']') {
1455c99fb5f9SBaptiste Daroussin 				if (parser->stack == NULL) {
1456c99fb5f9SBaptiste Daroussin 					ucl_set_err (chunk, UCL_ESYNTAX, "end of array or object detected without corresponding start", &parser->err);
1457c99fb5f9SBaptiste Daroussin 					return false;
1458c99fb5f9SBaptiste Daroussin 				}
1459c99fb5f9SBaptiste Daroussin 				if ((*p == '}' && parser->stack->obj->type == UCL_OBJECT) ||
1460c99fb5f9SBaptiste Daroussin 						(*p == ']' && parser->stack->obj->type == UCL_ARRAY)) {
1461c99fb5f9SBaptiste Daroussin 
1462c99fb5f9SBaptiste Daroussin 					/* Pop all nested objects from a stack */
1463c99fb5f9SBaptiste Daroussin 					st = parser->stack;
1464c99fb5f9SBaptiste Daroussin 					parser->stack = st->next;
1465c99fb5f9SBaptiste Daroussin 					UCL_FREE (sizeof (struct ucl_stack), st);
1466c99fb5f9SBaptiste Daroussin 
1467c99fb5f9SBaptiste Daroussin 					while (parser->stack != NULL) {
1468c99fb5f9SBaptiste Daroussin 						st = parser->stack;
1469c99fb5f9SBaptiste Daroussin 						if (st->next == NULL || st->next->level == st->level) {
1470c99fb5f9SBaptiste Daroussin 							break;
1471c99fb5f9SBaptiste Daroussin 						}
1472c99fb5f9SBaptiste Daroussin 						parser->stack = st->next;
1473c99fb5f9SBaptiste Daroussin 						UCL_FREE (sizeof (struct ucl_stack), st);
1474c99fb5f9SBaptiste Daroussin 					}
1475c99fb5f9SBaptiste Daroussin 				}
1476c99fb5f9SBaptiste Daroussin 				else {
1477c99fb5f9SBaptiste Daroussin 					ucl_set_err (chunk, UCL_ESYNTAX, "unexpected terminating symbol detected", &parser->err);
1478c99fb5f9SBaptiste Daroussin 					return false;
1479c99fb5f9SBaptiste Daroussin 				}
1480c99fb5f9SBaptiste Daroussin 
1481c99fb5f9SBaptiste Daroussin 				if (parser->stack == NULL) {
1482c99fb5f9SBaptiste Daroussin 					/* Ignore everything after a top object */
1483c99fb5f9SBaptiste Daroussin 					return true;
1484c99fb5f9SBaptiste Daroussin 				}
1485c99fb5f9SBaptiste Daroussin 				else {
1486c99fb5f9SBaptiste Daroussin 					ucl_chunk_skipc (chunk, p);
1487c99fb5f9SBaptiste Daroussin 				}
1488c99fb5f9SBaptiste Daroussin 				got_sep = true;
1489c99fb5f9SBaptiste Daroussin 			}
1490c99fb5f9SBaptiste Daroussin 			else {
1491c99fb5f9SBaptiste Daroussin 				/* Got a separator */
1492c99fb5f9SBaptiste Daroussin 				got_sep = true;
1493c99fb5f9SBaptiste Daroussin 				ucl_chunk_skipc (chunk, p);
1494c99fb5f9SBaptiste Daroussin 			}
1495c99fb5f9SBaptiste Daroussin 		}
1496c99fb5f9SBaptiste Daroussin 		else {
1497c99fb5f9SBaptiste Daroussin 			/* Anything else */
1498c99fb5f9SBaptiste Daroussin 			if (!got_sep) {
1499c99fb5f9SBaptiste Daroussin 				ucl_set_err (chunk, UCL_ESYNTAX, "delimiter is missing", &parser->err);
1500c99fb5f9SBaptiste Daroussin 				return false;
1501c99fb5f9SBaptiste Daroussin 			}
1502c99fb5f9SBaptiste Daroussin 			return true;
1503c99fb5f9SBaptiste Daroussin 		}
1504c99fb5f9SBaptiste Daroussin 	}
1505c99fb5f9SBaptiste Daroussin 
1506c99fb5f9SBaptiste Daroussin 	return true;
1507c99fb5f9SBaptiste Daroussin }
1508c99fb5f9SBaptiste Daroussin 
1509c99fb5f9SBaptiste Daroussin /**
1510c99fb5f9SBaptiste Daroussin  * Handle macro data
1511c99fb5f9SBaptiste Daroussin  * @param parser
1512c99fb5f9SBaptiste Daroussin  * @param chunk
1513c99fb5f9SBaptiste Daroussin  * @return
1514c99fb5f9SBaptiste Daroussin  */
1515c99fb5f9SBaptiste Daroussin static bool
1516c99fb5f9SBaptiste Daroussin ucl_parse_macro_value (struct ucl_parser *parser,
1517c99fb5f9SBaptiste Daroussin 		struct ucl_chunk *chunk, struct ucl_macro *macro,
1518c99fb5f9SBaptiste Daroussin 		unsigned char const **macro_start, size_t *macro_len)
1519c99fb5f9SBaptiste Daroussin {
1520c99fb5f9SBaptiste Daroussin 	const unsigned char *p, *c;
1521c99fb5f9SBaptiste Daroussin 	bool need_unescape = false, ucl_escape = false, var_expand = false;
1522c99fb5f9SBaptiste Daroussin 
1523c99fb5f9SBaptiste Daroussin 	p = chunk->pos;
1524c99fb5f9SBaptiste Daroussin 
1525c99fb5f9SBaptiste Daroussin 	switch (*p) {
1526c99fb5f9SBaptiste Daroussin 	case '"':
1527c99fb5f9SBaptiste Daroussin 		/* We have macro value encoded in quotes */
1528c99fb5f9SBaptiste Daroussin 		c = p;
1529c99fb5f9SBaptiste Daroussin 		ucl_chunk_skipc (chunk, p);
1530c99fb5f9SBaptiste Daroussin 		if (!ucl_lex_json_string (parser, chunk, &need_unescape, &ucl_escape, &var_expand)) {
1531c99fb5f9SBaptiste Daroussin 			return false;
1532c99fb5f9SBaptiste Daroussin 		}
1533c99fb5f9SBaptiste Daroussin 
1534c99fb5f9SBaptiste Daroussin 		*macro_start = c + 1;
1535c99fb5f9SBaptiste Daroussin 		*macro_len = chunk->pos - c - 2;
1536c99fb5f9SBaptiste Daroussin 		p = chunk->pos;
1537c99fb5f9SBaptiste Daroussin 		break;
1538c99fb5f9SBaptiste Daroussin 	case '{':
1539c99fb5f9SBaptiste Daroussin 		/* We got a multiline macro body */
1540c99fb5f9SBaptiste Daroussin 		ucl_chunk_skipc (chunk, p);
1541c99fb5f9SBaptiste Daroussin 		/* Skip spaces at the beginning */
1542c99fb5f9SBaptiste Daroussin 		while (p < chunk->end) {
1543c99fb5f9SBaptiste Daroussin 			if (ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE)) {
1544c99fb5f9SBaptiste Daroussin 				ucl_chunk_skipc (chunk, p);
1545c99fb5f9SBaptiste Daroussin 			}
1546c99fb5f9SBaptiste Daroussin 			else {
1547c99fb5f9SBaptiste Daroussin 				break;
1548c99fb5f9SBaptiste Daroussin 			}
1549c99fb5f9SBaptiste Daroussin 		}
1550c99fb5f9SBaptiste Daroussin 		c = p;
1551c99fb5f9SBaptiste Daroussin 		while (p < chunk->end) {
1552c99fb5f9SBaptiste Daroussin 			if (*p == '}') {
1553c99fb5f9SBaptiste Daroussin 				break;
1554c99fb5f9SBaptiste Daroussin 			}
1555c99fb5f9SBaptiste Daroussin 			ucl_chunk_skipc (chunk, p);
1556c99fb5f9SBaptiste Daroussin 		}
1557c99fb5f9SBaptiste Daroussin 		*macro_start = c;
1558c99fb5f9SBaptiste Daroussin 		*macro_len = p - c;
1559c99fb5f9SBaptiste Daroussin 		ucl_chunk_skipc (chunk, p);
1560c99fb5f9SBaptiste Daroussin 		break;
1561c99fb5f9SBaptiste Daroussin 	default:
1562c99fb5f9SBaptiste Daroussin 		/* Macro is not enclosed in quotes or braces */
1563c99fb5f9SBaptiste Daroussin 		c = p;
1564c99fb5f9SBaptiste Daroussin 		while (p < chunk->end) {
1565c99fb5f9SBaptiste Daroussin 			if (ucl_lex_is_atom_end (*p)) {
1566c99fb5f9SBaptiste Daroussin 				break;
1567c99fb5f9SBaptiste Daroussin 			}
1568c99fb5f9SBaptiste Daroussin 			ucl_chunk_skipc (chunk, p);
1569c99fb5f9SBaptiste Daroussin 		}
1570c99fb5f9SBaptiste Daroussin 		*macro_start = c;
1571c99fb5f9SBaptiste Daroussin 		*macro_len = p - c;
1572c99fb5f9SBaptiste Daroussin 		break;
1573c99fb5f9SBaptiste Daroussin 	}
1574c99fb5f9SBaptiste Daroussin 
1575c99fb5f9SBaptiste Daroussin 	/* We are at the end of a macro */
1576c99fb5f9SBaptiste Daroussin 	/* Skip ';' and space characters and return to previous state */
1577c99fb5f9SBaptiste Daroussin 	while (p < chunk->end) {
1578c99fb5f9SBaptiste Daroussin 		if (!ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE) && *p != ';') {
1579c99fb5f9SBaptiste Daroussin 			break;
1580c99fb5f9SBaptiste Daroussin 		}
1581c99fb5f9SBaptiste Daroussin 		ucl_chunk_skipc (chunk, p);
1582c99fb5f9SBaptiste Daroussin 	}
1583c99fb5f9SBaptiste Daroussin 	return true;
1584c99fb5f9SBaptiste Daroussin }
1585c99fb5f9SBaptiste Daroussin 
1586c99fb5f9SBaptiste Daroussin /**
1587c99fb5f9SBaptiste Daroussin  * Handle the main states of rcl parser
1588c99fb5f9SBaptiste Daroussin  * @param parser parser structure
1589c99fb5f9SBaptiste Daroussin  * @param data the pointer to the beginning of a chunk
1590c99fb5f9SBaptiste Daroussin  * @param len the length of a chunk
1591c99fb5f9SBaptiste Daroussin  * @return true if chunk has been parsed and false in case of error
1592c99fb5f9SBaptiste Daroussin  */
1593c99fb5f9SBaptiste Daroussin static bool
1594c99fb5f9SBaptiste Daroussin ucl_state_machine (struct ucl_parser *parser)
1595c99fb5f9SBaptiste Daroussin {
1596c99fb5f9SBaptiste Daroussin 	ucl_object_t *obj;
1597c99fb5f9SBaptiste Daroussin 	struct ucl_chunk *chunk = parser->chunks;
1598c99fb5f9SBaptiste Daroussin 	const unsigned char *p, *c = NULL, *macro_start = NULL;
1599c99fb5f9SBaptiste Daroussin 	unsigned char *macro_escaped;
1600c99fb5f9SBaptiste Daroussin 	size_t macro_len = 0;
1601c99fb5f9SBaptiste Daroussin 	struct ucl_macro *macro = NULL;
1602c99fb5f9SBaptiste Daroussin 	bool next_key = false, end_of_object = false;
1603c99fb5f9SBaptiste Daroussin 
1604c99fb5f9SBaptiste Daroussin 	if (parser->top_obj == NULL) {
1605c99fb5f9SBaptiste Daroussin 		if (*chunk->pos == '[') {
1606c99fb5f9SBaptiste Daroussin 			obj = ucl_add_parser_stack (NULL, parser, true, 0);
1607c99fb5f9SBaptiste Daroussin 		}
1608c99fb5f9SBaptiste Daroussin 		else {
1609c99fb5f9SBaptiste Daroussin 			obj = ucl_add_parser_stack (NULL, parser, false, 0);
1610c99fb5f9SBaptiste Daroussin 		}
1611c99fb5f9SBaptiste Daroussin 		parser->top_obj = obj;
1612c99fb5f9SBaptiste Daroussin 		parser->cur_obj = obj;
1613c99fb5f9SBaptiste Daroussin 		parser->state = UCL_STATE_INIT;
1614c99fb5f9SBaptiste Daroussin 	}
1615c99fb5f9SBaptiste Daroussin 
1616c99fb5f9SBaptiste Daroussin 	p = chunk->pos;
1617c99fb5f9SBaptiste Daroussin 	while (chunk->pos < chunk->end) {
1618c99fb5f9SBaptiste Daroussin 		switch (parser->state) {
1619c99fb5f9SBaptiste Daroussin 		case UCL_STATE_INIT:
1620c99fb5f9SBaptiste Daroussin 			/*
1621c99fb5f9SBaptiste Daroussin 			 * At the init state we can either go to the parse array or object
1622c99fb5f9SBaptiste Daroussin 			 * if we got [ or { correspondingly or can just treat new data as
1623c99fb5f9SBaptiste Daroussin 			 * a key of newly created object
1624c99fb5f9SBaptiste Daroussin 			 */
1625c99fb5f9SBaptiste Daroussin 			obj = parser->cur_obj;
1626c99fb5f9SBaptiste Daroussin 			if (!ucl_skip_comments (parser)) {
1627c99fb5f9SBaptiste Daroussin 				parser->prev_state = parser->state;
1628c99fb5f9SBaptiste Daroussin 				parser->state = UCL_STATE_ERROR;
1629c99fb5f9SBaptiste Daroussin 				return false;
1630c99fb5f9SBaptiste Daroussin 			}
1631c99fb5f9SBaptiste Daroussin 			else {
1632c99fb5f9SBaptiste Daroussin 				p = chunk->pos;
1633c99fb5f9SBaptiste Daroussin 				if (*p == '[') {
1634c99fb5f9SBaptiste Daroussin 					parser->state = UCL_STATE_VALUE;
1635c99fb5f9SBaptiste Daroussin 					ucl_chunk_skipc (chunk, p);
1636c99fb5f9SBaptiste Daroussin 				}
1637c99fb5f9SBaptiste Daroussin 				else {
1638c99fb5f9SBaptiste Daroussin 					parser->state = UCL_STATE_KEY;
1639c99fb5f9SBaptiste Daroussin 					if (*p == '{') {
1640c99fb5f9SBaptiste Daroussin 						ucl_chunk_skipc (chunk, p);
1641c99fb5f9SBaptiste Daroussin 					}
1642c99fb5f9SBaptiste Daroussin 				}
1643c99fb5f9SBaptiste Daroussin 			}
1644c99fb5f9SBaptiste Daroussin 			break;
1645c99fb5f9SBaptiste Daroussin 		case UCL_STATE_KEY:
1646c99fb5f9SBaptiste Daroussin 			/* Skip any spaces */
1647c99fb5f9SBaptiste Daroussin 			while (p < chunk->end && ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE)) {
1648c99fb5f9SBaptiste Daroussin 				ucl_chunk_skipc (chunk, p);
1649c99fb5f9SBaptiste Daroussin 			}
1650c99fb5f9SBaptiste Daroussin 			if (*p == '}') {
1651c99fb5f9SBaptiste Daroussin 				/* We have the end of an object */
1652c99fb5f9SBaptiste Daroussin 				parser->state = UCL_STATE_AFTER_VALUE;
1653c99fb5f9SBaptiste Daroussin 				continue;
1654c99fb5f9SBaptiste Daroussin 			}
1655c99fb5f9SBaptiste Daroussin 			if (parser->stack == NULL) {
1656c99fb5f9SBaptiste Daroussin 				/* No objects are on stack, but we want to parse a key */
1657c99fb5f9SBaptiste Daroussin 				ucl_set_err (chunk, UCL_ESYNTAX, "top object is finished but the parser "
1658c99fb5f9SBaptiste Daroussin 						"expects a key", &parser->err);
1659c99fb5f9SBaptiste Daroussin 				parser->prev_state = parser->state;
1660c99fb5f9SBaptiste Daroussin 				parser->state = UCL_STATE_ERROR;
1661c99fb5f9SBaptiste Daroussin 				return false;
1662c99fb5f9SBaptiste Daroussin 			}
1663c99fb5f9SBaptiste Daroussin 			if (!ucl_parse_key (parser, chunk, &next_key, &end_of_object)) {
1664c99fb5f9SBaptiste Daroussin 				parser->prev_state = parser->state;
1665c99fb5f9SBaptiste Daroussin 				parser->state = UCL_STATE_ERROR;
1666c99fb5f9SBaptiste Daroussin 				return false;
1667c99fb5f9SBaptiste Daroussin 			}
1668c99fb5f9SBaptiste Daroussin 			if (end_of_object) {
1669c99fb5f9SBaptiste Daroussin 				p = chunk->pos;
1670c99fb5f9SBaptiste Daroussin 				parser->state = UCL_STATE_AFTER_VALUE;
1671c99fb5f9SBaptiste Daroussin 				continue;
1672c99fb5f9SBaptiste Daroussin 			}
1673c99fb5f9SBaptiste Daroussin 			else if (parser->state != UCL_STATE_MACRO_NAME) {
1674c99fb5f9SBaptiste Daroussin 				if (next_key && parser->stack->obj->type == UCL_OBJECT) {
1675c99fb5f9SBaptiste Daroussin 					/* Parse more keys and nest objects accordingly */
1676c99fb5f9SBaptiste Daroussin 					obj = ucl_add_parser_stack (parser->cur_obj, parser, false, parser->stack->level + 1);
1677c99fb5f9SBaptiste Daroussin 				}
1678c99fb5f9SBaptiste Daroussin 				else {
1679c99fb5f9SBaptiste Daroussin 					parser->state = UCL_STATE_VALUE;
1680c99fb5f9SBaptiste Daroussin 				}
1681c99fb5f9SBaptiste Daroussin 			}
1682c99fb5f9SBaptiste Daroussin 			else {
1683c99fb5f9SBaptiste Daroussin 				c = chunk->pos;
1684c99fb5f9SBaptiste Daroussin 			}
1685c99fb5f9SBaptiste Daroussin 			p = chunk->pos;
1686c99fb5f9SBaptiste Daroussin 			break;
1687c99fb5f9SBaptiste Daroussin 		case UCL_STATE_VALUE:
1688c99fb5f9SBaptiste Daroussin 			/* We need to check what we do have */
1689c99fb5f9SBaptiste Daroussin 			if (!ucl_parse_value (parser, chunk)) {
1690c99fb5f9SBaptiste Daroussin 				parser->prev_state = parser->state;
1691c99fb5f9SBaptiste Daroussin 				parser->state = UCL_STATE_ERROR;
1692c99fb5f9SBaptiste Daroussin 				return false;
1693c99fb5f9SBaptiste Daroussin 			}
1694c99fb5f9SBaptiste Daroussin 			/* State is set in ucl_parse_value call */
1695c99fb5f9SBaptiste Daroussin 			p = chunk->pos;
1696c99fb5f9SBaptiste Daroussin 			break;
1697c99fb5f9SBaptiste Daroussin 		case UCL_STATE_AFTER_VALUE:
1698c99fb5f9SBaptiste Daroussin 			if (!ucl_parse_after_value (parser, chunk)) {
1699c99fb5f9SBaptiste Daroussin 				parser->prev_state = parser->state;
1700c99fb5f9SBaptiste Daroussin 				parser->state = UCL_STATE_ERROR;
1701c99fb5f9SBaptiste Daroussin 				return false;
1702c99fb5f9SBaptiste Daroussin 			}
1703c99fb5f9SBaptiste Daroussin 			if (parser->stack != NULL) {
1704c99fb5f9SBaptiste Daroussin 				if (parser->stack->obj->type == UCL_OBJECT) {
1705c99fb5f9SBaptiste Daroussin 					parser->state = UCL_STATE_KEY;
1706c99fb5f9SBaptiste Daroussin 				}
1707c99fb5f9SBaptiste Daroussin 				else {
1708c99fb5f9SBaptiste Daroussin 					/* Array */
1709c99fb5f9SBaptiste Daroussin 					parser->state = UCL_STATE_VALUE;
1710c99fb5f9SBaptiste Daroussin 				}
1711c99fb5f9SBaptiste Daroussin 			}
1712c99fb5f9SBaptiste Daroussin 			else {
1713c99fb5f9SBaptiste Daroussin 				/* Skip everything at the end */
1714c99fb5f9SBaptiste Daroussin 				return true;
1715c99fb5f9SBaptiste Daroussin 			}
1716c99fb5f9SBaptiste Daroussin 			p = chunk->pos;
1717c99fb5f9SBaptiste Daroussin 			break;
1718c99fb5f9SBaptiste Daroussin 		case UCL_STATE_MACRO_NAME:
1719c99fb5f9SBaptiste Daroussin 			if (!ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE)) {
1720c99fb5f9SBaptiste Daroussin 				ucl_chunk_skipc (chunk, p);
1721c99fb5f9SBaptiste Daroussin 			}
1722c99fb5f9SBaptiste Daroussin 			else if (p - c > 0) {
1723c99fb5f9SBaptiste Daroussin 				/* We got macro name */
1724c99fb5f9SBaptiste Daroussin 				macro_len = (size_t)(p - c);
1725c99fb5f9SBaptiste Daroussin 				HASH_FIND (hh, parser->macroes, c, macro_len, macro);
1726c99fb5f9SBaptiste Daroussin 				if (macro == NULL) {
1727c99fb5f9SBaptiste Daroussin 					ucl_create_err (&parser->err, "error on line %d at column %d: "
1728c99fb5f9SBaptiste Daroussin 							"unknown macro: '%.*s', character: '%c'",
1729c99fb5f9SBaptiste Daroussin 								chunk->line, chunk->column, (int)(p - c), c, *chunk->pos);
1730c99fb5f9SBaptiste Daroussin 					parser->state = UCL_STATE_ERROR;
1731c99fb5f9SBaptiste Daroussin 					return false;
1732c99fb5f9SBaptiste Daroussin 				}
1733c99fb5f9SBaptiste Daroussin 				/* Now we need to skip all spaces */
1734c99fb5f9SBaptiste Daroussin 				while (p < chunk->end) {
1735c99fb5f9SBaptiste Daroussin 					if (!ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE)) {
1736c99fb5f9SBaptiste Daroussin 						if (chunk->remain >= 2 && ucl_lex_is_comment (p[0], p[1])) {
1737c99fb5f9SBaptiste Daroussin 							/* Skip comment */
1738c99fb5f9SBaptiste Daroussin 							if (!ucl_skip_comments (parser)) {
1739c99fb5f9SBaptiste Daroussin 								return false;
1740c99fb5f9SBaptiste Daroussin 							}
1741c99fb5f9SBaptiste Daroussin 							p = chunk->pos;
1742c99fb5f9SBaptiste Daroussin 						}
1743c99fb5f9SBaptiste Daroussin 						break;
1744c99fb5f9SBaptiste Daroussin 					}
1745c99fb5f9SBaptiste Daroussin 					ucl_chunk_skipc (chunk, p);
1746c99fb5f9SBaptiste Daroussin 				}
1747c99fb5f9SBaptiste Daroussin 				parser->state = UCL_STATE_MACRO;
1748c99fb5f9SBaptiste Daroussin 			}
1749c99fb5f9SBaptiste Daroussin 			break;
1750c99fb5f9SBaptiste Daroussin 		case UCL_STATE_MACRO:
1751c99fb5f9SBaptiste Daroussin 			if (!ucl_parse_macro_value (parser, chunk, macro,
1752c99fb5f9SBaptiste Daroussin 					&macro_start, &macro_len)) {
1753c99fb5f9SBaptiste Daroussin 				parser->prev_state = parser->state;
1754c99fb5f9SBaptiste Daroussin 				parser->state = UCL_STATE_ERROR;
1755c99fb5f9SBaptiste Daroussin 				return false;
1756c99fb5f9SBaptiste Daroussin 			}
1757c99fb5f9SBaptiste Daroussin 			macro_len = ucl_expand_variable (parser, &macro_escaped, macro_start, macro_len);
1758c99fb5f9SBaptiste Daroussin 			parser->state = parser->prev_state;
1759c99fb5f9SBaptiste Daroussin 			if (macro_escaped == NULL) {
1760c99fb5f9SBaptiste Daroussin 				if (!macro->handler (macro_start, macro_len, macro->ud)) {
1761c99fb5f9SBaptiste Daroussin 					return false;
1762c99fb5f9SBaptiste Daroussin 				}
1763c99fb5f9SBaptiste Daroussin 			}
1764c99fb5f9SBaptiste Daroussin 			else {
1765c99fb5f9SBaptiste Daroussin 				if (!macro->handler (macro_escaped, macro_len, macro->ud)) {
1766c99fb5f9SBaptiste Daroussin 					UCL_FREE (macro_len + 1, macro_escaped);
1767c99fb5f9SBaptiste Daroussin 					return false;
1768c99fb5f9SBaptiste Daroussin 				}
1769c99fb5f9SBaptiste Daroussin 				UCL_FREE (macro_len + 1, macro_escaped);
1770c99fb5f9SBaptiste Daroussin 			}
1771c99fb5f9SBaptiste Daroussin 			p = chunk->pos;
1772c99fb5f9SBaptiste Daroussin 			break;
1773c99fb5f9SBaptiste Daroussin 		default:
1774c99fb5f9SBaptiste Daroussin 			/* TODO: add all states */
1775c99fb5f9SBaptiste Daroussin 			ucl_set_err (chunk, UCL_EINTERNAL, "internal error: parser is in an unknown state", &parser->err);
1776c99fb5f9SBaptiste Daroussin 			parser->state = UCL_STATE_ERROR;
1777c99fb5f9SBaptiste Daroussin 			return false;
1778c99fb5f9SBaptiste Daroussin 		}
1779c99fb5f9SBaptiste Daroussin 	}
1780c99fb5f9SBaptiste Daroussin 
1781c99fb5f9SBaptiste Daroussin 	return true;
1782c99fb5f9SBaptiste Daroussin }
1783c99fb5f9SBaptiste Daroussin 
1784c99fb5f9SBaptiste Daroussin struct ucl_parser*
1785c99fb5f9SBaptiste Daroussin ucl_parser_new (int flags)
1786c99fb5f9SBaptiste Daroussin {
1787c99fb5f9SBaptiste Daroussin 	struct ucl_parser *new;
1788c99fb5f9SBaptiste Daroussin 
1789c99fb5f9SBaptiste Daroussin 	new = UCL_ALLOC (sizeof (struct ucl_parser));
1790c99fb5f9SBaptiste Daroussin 	memset (new, 0, sizeof (struct ucl_parser));
1791c99fb5f9SBaptiste Daroussin 
1792c99fb5f9SBaptiste Daroussin 	ucl_parser_register_macro (new, "include", ucl_include_handler, new);
1793c99fb5f9SBaptiste Daroussin 	ucl_parser_register_macro (new, "try_include", ucl_try_include_handler, new);
1794c99fb5f9SBaptiste Daroussin 	ucl_parser_register_macro (new, "includes", ucl_includes_handler, new);
1795c99fb5f9SBaptiste Daroussin 
1796c99fb5f9SBaptiste Daroussin 	new->flags = flags;
1797c99fb5f9SBaptiste Daroussin 
1798c99fb5f9SBaptiste Daroussin 	/* Initial assumption about filevars */
1799c99fb5f9SBaptiste Daroussin 	ucl_parser_set_filevars (new, NULL, false);
1800c99fb5f9SBaptiste Daroussin 
1801c99fb5f9SBaptiste Daroussin 	return new;
1802c99fb5f9SBaptiste Daroussin }
1803c99fb5f9SBaptiste Daroussin 
1804c99fb5f9SBaptiste Daroussin 
1805c99fb5f9SBaptiste Daroussin void
1806c99fb5f9SBaptiste Daroussin ucl_parser_register_macro (struct ucl_parser *parser, const char *macro,
1807c99fb5f9SBaptiste Daroussin 		ucl_macro_handler handler, void* ud)
1808c99fb5f9SBaptiste Daroussin {
1809c99fb5f9SBaptiste Daroussin 	struct ucl_macro *new;
1810c99fb5f9SBaptiste Daroussin 
1811c99fb5f9SBaptiste Daroussin 	new = UCL_ALLOC (sizeof (struct ucl_macro));
1812c99fb5f9SBaptiste Daroussin 	memset (new, 0, sizeof (struct ucl_macro));
1813c99fb5f9SBaptiste Daroussin 	new->handler = handler;
1814c99fb5f9SBaptiste Daroussin 	new->name = strdup (macro);
1815c99fb5f9SBaptiste Daroussin 	new->ud = ud;
1816c99fb5f9SBaptiste Daroussin 	HASH_ADD_KEYPTR (hh, parser->macroes, new->name, strlen (new->name), new);
1817c99fb5f9SBaptiste Daroussin }
1818c99fb5f9SBaptiste Daroussin 
1819c99fb5f9SBaptiste Daroussin void
1820c99fb5f9SBaptiste Daroussin ucl_parser_register_variable (struct ucl_parser *parser, const char *var,
1821c99fb5f9SBaptiste Daroussin 		const char *value)
1822c99fb5f9SBaptiste Daroussin {
1823c99fb5f9SBaptiste Daroussin 	struct ucl_variable *new = NULL, *cur;
1824c99fb5f9SBaptiste Daroussin 
1825c99fb5f9SBaptiste Daroussin 	if (var == NULL) {
1826c99fb5f9SBaptiste Daroussin 		return;
1827c99fb5f9SBaptiste Daroussin 	}
1828c99fb5f9SBaptiste Daroussin 
1829c99fb5f9SBaptiste Daroussin 	/* Find whether a variable already exists */
1830c99fb5f9SBaptiste Daroussin 	LL_FOREACH (parser->variables, cur) {
1831c99fb5f9SBaptiste Daroussin 		if (strcmp (cur->var, var) == 0) {
1832c99fb5f9SBaptiste Daroussin 			new = cur;
1833c99fb5f9SBaptiste Daroussin 			break;
1834c99fb5f9SBaptiste Daroussin 		}
1835c99fb5f9SBaptiste Daroussin 	}
1836c99fb5f9SBaptiste Daroussin 
1837c99fb5f9SBaptiste Daroussin 	if (value == NULL) {
1838c99fb5f9SBaptiste Daroussin 
1839c99fb5f9SBaptiste Daroussin 		if (new != NULL) {
1840c99fb5f9SBaptiste Daroussin 			/* Remove variable */
1841c99fb5f9SBaptiste Daroussin 			LL_DELETE (parser->variables, new);
1842c99fb5f9SBaptiste Daroussin 			free (new->var);
1843c99fb5f9SBaptiste Daroussin 			free (new->value);
1844c99fb5f9SBaptiste Daroussin 			UCL_FREE (sizeof (struct ucl_variable), new);
1845c99fb5f9SBaptiste Daroussin 		}
1846c99fb5f9SBaptiste Daroussin 		else {
1847c99fb5f9SBaptiste Daroussin 			/* Do nothing */
1848c99fb5f9SBaptiste Daroussin 			return;
1849c99fb5f9SBaptiste Daroussin 		}
1850c99fb5f9SBaptiste Daroussin 	}
1851c99fb5f9SBaptiste Daroussin 	else {
1852c99fb5f9SBaptiste Daroussin 		if (new == NULL) {
1853c99fb5f9SBaptiste Daroussin 			new = UCL_ALLOC (sizeof (struct ucl_variable));
1854c99fb5f9SBaptiste Daroussin 			memset (new, 0, sizeof (struct ucl_variable));
1855c99fb5f9SBaptiste Daroussin 			new->var = strdup (var);
1856c99fb5f9SBaptiste Daroussin 			new->var_len = strlen (var);
1857c99fb5f9SBaptiste Daroussin 			new->value = strdup (value);
1858c99fb5f9SBaptiste Daroussin 			new->value_len = strlen (value);
1859c99fb5f9SBaptiste Daroussin 
1860c99fb5f9SBaptiste Daroussin 			LL_PREPEND (parser->variables, new);
1861c99fb5f9SBaptiste Daroussin 		}
1862c99fb5f9SBaptiste Daroussin 		else {
1863c99fb5f9SBaptiste Daroussin 			free (new->value);
1864c99fb5f9SBaptiste Daroussin 			new->value = strdup (value);
1865c99fb5f9SBaptiste Daroussin 			new->value_len = strlen (value);
1866c99fb5f9SBaptiste Daroussin 		}
1867c99fb5f9SBaptiste Daroussin 	}
1868c99fb5f9SBaptiste Daroussin }
1869c99fb5f9SBaptiste Daroussin 
1870c99fb5f9SBaptiste Daroussin bool
1871c99fb5f9SBaptiste Daroussin ucl_parser_add_chunk (struct ucl_parser *parser, const unsigned char *data,
1872c99fb5f9SBaptiste Daroussin 		size_t len)
1873c99fb5f9SBaptiste Daroussin {
1874c99fb5f9SBaptiste Daroussin 	struct ucl_chunk *chunk;
1875c99fb5f9SBaptiste Daroussin 
1876c99fb5f9SBaptiste Daroussin 	if (parser->state != UCL_STATE_ERROR) {
1877c99fb5f9SBaptiste Daroussin 		chunk = UCL_ALLOC (sizeof (struct ucl_chunk));
1878c99fb5f9SBaptiste Daroussin 		chunk->begin = data;
1879c99fb5f9SBaptiste Daroussin 		chunk->remain = len;
1880c99fb5f9SBaptiste Daroussin 		chunk->pos = chunk->begin;
1881c99fb5f9SBaptiste Daroussin 		chunk->end = chunk->begin + len;
1882c99fb5f9SBaptiste Daroussin 		chunk->line = 1;
1883c99fb5f9SBaptiste Daroussin 		chunk->column = 0;
1884c99fb5f9SBaptiste Daroussin 		LL_PREPEND (parser->chunks, chunk);
1885c99fb5f9SBaptiste Daroussin 		parser->recursion ++;
1886c99fb5f9SBaptiste Daroussin 		if (parser->recursion > UCL_MAX_RECURSION) {
1887c99fb5f9SBaptiste Daroussin 			ucl_create_err (&parser->err, "maximum include nesting limit is reached: %d",
1888c99fb5f9SBaptiste Daroussin 					parser->recursion);
1889c99fb5f9SBaptiste Daroussin 			return false;
1890c99fb5f9SBaptiste Daroussin 		}
1891c99fb5f9SBaptiste Daroussin 		return ucl_state_machine (parser);
1892c99fb5f9SBaptiste Daroussin 	}
1893c99fb5f9SBaptiste Daroussin 
1894c99fb5f9SBaptiste Daroussin 	ucl_create_err (&parser->err, "a parser is in an invalid state");
1895c99fb5f9SBaptiste Daroussin 
1896c99fb5f9SBaptiste Daroussin 	return false;
1897c99fb5f9SBaptiste Daroussin }
1898