xref: /freebsd-src/contrib/libucl/src/ucl_parser.c (revision a0409676120c1e558d0ade943019934e0f15118d)
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 
24*a0409676SBaptiste Daroussin #include <math.h>
25c99fb5f9SBaptiste Daroussin #include "ucl.h"
26c99fb5f9SBaptiste Daroussin #include "ucl_internal.h"
27c99fb5f9SBaptiste Daroussin #include "ucl_chartable.h"
28c99fb5f9SBaptiste Daroussin 
29c99fb5f9SBaptiste Daroussin /**
304bf54857SBaptiste Daroussin  * @file ucl_parser.c
314bf54857SBaptiste Daroussin  * The implementation of ucl parser
32c99fb5f9SBaptiste Daroussin  */
33c99fb5f9SBaptiste Daroussin 
34c99fb5f9SBaptiste Daroussin struct ucl_parser_saved_state {
35c99fb5f9SBaptiste Daroussin 	unsigned int line;
36c99fb5f9SBaptiste Daroussin 	unsigned int column;
37c99fb5f9SBaptiste Daroussin 	size_t remain;
38c99fb5f9SBaptiste Daroussin 	const unsigned char *pos;
39c99fb5f9SBaptiste Daroussin };
40c99fb5f9SBaptiste Daroussin 
41c99fb5f9SBaptiste Daroussin /**
42c99fb5f9SBaptiste Daroussin  * Move up to len characters
43c99fb5f9SBaptiste Daroussin  * @param parser
44c99fb5f9SBaptiste Daroussin  * @param begin
45c99fb5f9SBaptiste Daroussin  * @param len
46c99fb5f9SBaptiste Daroussin  * @return new position in chunk
47c99fb5f9SBaptiste Daroussin  */
48*a0409676SBaptiste Daroussin #define ucl_chunk_skipc(chunk, p)    \
49*a0409676SBaptiste Daroussin do {                                 \
50c99fb5f9SBaptiste Daroussin 	if (*(p) == '\n') {          \
51c99fb5f9SBaptiste Daroussin 		(chunk)->line ++;    \
52c99fb5f9SBaptiste Daroussin 		(chunk)->column = 0; \
53c99fb5f9SBaptiste Daroussin 	}                            \
54c99fb5f9SBaptiste Daroussin 	else (chunk)->column ++;     \
55c99fb5f9SBaptiste Daroussin 	(p++);                       \
56c99fb5f9SBaptiste Daroussin 	(chunk)->pos ++;             \
57c99fb5f9SBaptiste Daroussin 	(chunk)->remain --;          \
58c99fb5f9SBaptiste Daroussin } while (0)
59c99fb5f9SBaptiste Daroussin 
60c99fb5f9SBaptiste Daroussin static inline void
ucl_set_err(struct ucl_parser * parser,int code,const char * str,UT_string ** err)614bf54857SBaptiste Daroussin ucl_set_err (struct ucl_parser *parser, int code, const char *str, UT_string **err)
62c99fb5f9SBaptiste Daroussin {
634bf54857SBaptiste Daroussin 	const char *fmt_string, *filename;
644bf54857SBaptiste Daroussin 	struct ucl_chunk *chunk = parser->chunks;
654bf54857SBaptiste Daroussin 
664bf54857SBaptiste Daroussin 	if (parser->cur_file) {
674bf54857SBaptiste Daroussin 		filename = parser->cur_file;
684bf54857SBaptiste Daroussin 	}
694bf54857SBaptiste Daroussin 	else {
704bf54857SBaptiste Daroussin 		filename = "<unknown>";
714bf54857SBaptiste Daroussin 	}
7239ee7a7aSBaptiste Daroussin 
73c99fb5f9SBaptiste Daroussin 	if (chunk->pos < chunk->end) {
74c99fb5f9SBaptiste Daroussin 		if (isgraph (*chunk->pos)) {
754bf54857SBaptiste Daroussin 			fmt_string = "error while parsing %s: "
764bf54857SBaptiste Daroussin 					"line: %d, column: %d - '%s', character: '%c'";
77c99fb5f9SBaptiste Daroussin 		}
78c99fb5f9SBaptiste Daroussin 		else {
794bf54857SBaptiste Daroussin 			fmt_string = "error while parsing %s: "
804bf54857SBaptiste Daroussin 					"line: %d, column: %d - '%s', character: '0x%02x'";
81c99fb5f9SBaptiste Daroussin 		}
824bf54857SBaptiste Daroussin 		ucl_create_err (err, fmt_string,
834bf54857SBaptiste Daroussin 			filename, chunk->line, chunk->column,
844bf54857SBaptiste Daroussin 			str, *chunk->pos);
85c99fb5f9SBaptiste Daroussin 	}
86c99fb5f9SBaptiste Daroussin 	else {
874bf54857SBaptiste Daroussin 		ucl_create_err (err, "error while parsing %s: at the end of chunk: %s",
884bf54857SBaptiste Daroussin 			filename, str);
89c99fb5f9SBaptiste Daroussin 	}
9039ee7a7aSBaptiste Daroussin 
9139ee7a7aSBaptiste Daroussin 	parser->err_code = code;
92*a0409676SBaptiste Daroussin 	parser->state = UCL_STATE_ERROR;
93c99fb5f9SBaptiste Daroussin }
94c99fb5f9SBaptiste Daroussin 
95d9f0ce31SBaptiste Daroussin static void
ucl_save_comment(struct ucl_parser * parser,const char * begin,size_t len)96d9f0ce31SBaptiste Daroussin ucl_save_comment (struct ucl_parser *parser, const char *begin, size_t len)
97d9f0ce31SBaptiste Daroussin {
98d9f0ce31SBaptiste Daroussin 	ucl_object_t *nobj;
99d9f0ce31SBaptiste Daroussin 
100d9f0ce31SBaptiste Daroussin 	if (len > 0 && begin != NULL) {
101d9f0ce31SBaptiste Daroussin 		nobj = ucl_object_fromstring_common (begin, len, 0);
102d9f0ce31SBaptiste Daroussin 
103d9f0ce31SBaptiste Daroussin 		if (parser->last_comment) {
104d9f0ce31SBaptiste Daroussin 			/* We need to append data to an existing object */
105d9f0ce31SBaptiste Daroussin 			DL_APPEND (parser->last_comment, nobj);
106d9f0ce31SBaptiste Daroussin 		}
107d9f0ce31SBaptiste Daroussin 		else {
108d9f0ce31SBaptiste Daroussin 			parser->last_comment = nobj;
109d9f0ce31SBaptiste Daroussin 		}
110d9f0ce31SBaptiste Daroussin 	}
111d9f0ce31SBaptiste Daroussin }
112d9f0ce31SBaptiste Daroussin 
113d9f0ce31SBaptiste Daroussin static void
ucl_attach_comment(struct ucl_parser * parser,ucl_object_t * obj,bool before)114d9f0ce31SBaptiste Daroussin ucl_attach_comment (struct ucl_parser *parser, ucl_object_t *obj, bool before)
115d9f0ce31SBaptiste Daroussin {
116d9f0ce31SBaptiste Daroussin 	if (parser->last_comment) {
117d9f0ce31SBaptiste Daroussin 		ucl_object_insert_key (parser->comments, parser->last_comment,
118d9f0ce31SBaptiste Daroussin 				(const char *)&obj, sizeof (void *), true);
119d9f0ce31SBaptiste Daroussin 
120d9f0ce31SBaptiste Daroussin 		if (before) {
121d9f0ce31SBaptiste Daroussin 			parser->last_comment->flags |= UCL_OBJECT_INHERITED;
122d9f0ce31SBaptiste Daroussin 		}
123d9f0ce31SBaptiste Daroussin 
124d9f0ce31SBaptiste Daroussin 		parser->last_comment = NULL;
125d9f0ce31SBaptiste Daroussin 	}
126d9f0ce31SBaptiste Daroussin }
127d9f0ce31SBaptiste Daroussin 
128c99fb5f9SBaptiste Daroussin /**
129c99fb5f9SBaptiste Daroussin  * Skip all comments from the current pos resolving nested and multiline comments
130c99fb5f9SBaptiste Daroussin  * @param parser
131c99fb5f9SBaptiste Daroussin  * @return
132c99fb5f9SBaptiste Daroussin  */
133c99fb5f9SBaptiste Daroussin static bool
ucl_skip_comments(struct ucl_parser * parser)134c99fb5f9SBaptiste Daroussin ucl_skip_comments (struct ucl_parser *parser)
135c99fb5f9SBaptiste Daroussin {
136c99fb5f9SBaptiste Daroussin 	struct ucl_chunk *chunk = parser->chunks;
137d9f0ce31SBaptiste Daroussin 	const unsigned char *p, *beg = NULL;
138c99fb5f9SBaptiste Daroussin 	int comments_nested = 0;
1394bf54857SBaptiste Daroussin 	bool quoted = false;
140c99fb5f9SBaptiste Daroussin 
141c99fb5f9SBaptiste Daroussin 	p = chunk->pos;
142c99fb5f9SBaptiste Daroussin 
143c99fb5f9SBaptiste Daroussin start:
1444bf54857SBaptiste Daroussin 	if (chunk->remain > 0 && *p == '#') {
145c99fb5f9SBaptiste Daroussin 		if (parser->state != UCL_STATE_SCOMMENT &&
146c99fb5f9SBaptiste Daroussin 				parser->state != UCL_STATE_MCOMMENT) {
147d9f0ce31SBaptiste Daroussin 			beg = p;
148d9f0ce31SBaptiste Daroussin 
149c99fb5f9SBaptiste Daroussin 			while (p < chunk->end) {
150c99fb5f9SBaptiste Daroussin 				if (*p == '\n') {
151d9f0ce31SBaptiste Daroussin 					if (parser->flags & UCL_PARSER_SAVE_COMMENTS) {
152d9f0ce31SBaptiste Daroussin 						ucl_save_comment (parser, beg, p - beg);
153d9f0ce31SBaptiste Daroussin 						beg = NULL;
154d9f0ce31SBaptiste Daroussin 					}
155d9f0ce31SBaptiste Daroussin 
156c99fb5f9SBaptiste Daroussin 					ucl_chunk_skipc (chunk, p);
157d9f0ce31SBaptiste Daroussin 
158c99fb5f9SBaptiste Daroussin 					goto start;
159c99fb5f9SBaptiste Daroussin 				}
160c99fb5f9SBaptiste Daroussin 				ucl_chunk_skipc (chunk, p);
161c99fb5f9SBaptiste Daroussin 			}
162c99fb5f9SBaptiste Daroussin 		}
163c99fb5f9SBaptiste Daroussin 	}
1644bf54857SBaptiste Daroussin 	else if (chunk->remain >= 2 && *p == '/') {
165c99fb5f9SBaptiste Daroussin 		if (p[1] == '*') {
166d9f0ce31SBaptiste Daroussin 			beg = p;
167c99fb5f9SBaptiste Daroussin 			ucl_chunk_skipc (chunk, p);
168c99fb5f9SBaptiste Daroussin 			comments_nested ++;
169c99fb5f9SBaptiste Daroussin 			ucl_chunk_skipc (chunk, p);
170c99fb5f9SBaptiste Daroussin 
171c99fb5f9SBaptiste Daroussin 			while (p < chunk->end) {
1724bf54857SBaptiste Daroussin 				if (*p == '"' && *(p - 1) != '\\') {
1734bf54857SBaptiste Daroussin 					quoted = !quoted;
1744bf54857SBaptiste Daroussin 				}
1754bf54857SBaptiste Daroussin 
1764bf54857SBaptiste Daroussin 				if (!quoted) {
177c99fb5f9SBaptiste Daroussin 					if (*p == '*') {
178c99fb5f9SBaptiste Daroussin 						ucl_chunk_skipc (chunk, p);
179c99fb5f9SBaptiste Daroussin 						if (*p == '/') {
180c99fb5f9SBaptiste Daroussin 							comments_nested --;
181c99fb5f9SBaptiste Daroussin 							if (comments_nested == 0) {
182d9f0ce31SBaptiste Daroussin 								if (parser->flags & UCL_PARSER_SAVE_COMMENTS) {
183d9f0ce31SBaptiste Daroussin 									ucl_save_comment (parser, beg, p - beg + 1);
184d9f0ce31SBaptiste Daroussin 									beg = NULL;
185d9f0ce31SBaptiste Daroussin 								}
186d9f0ce31SBaptiste Daroussin 
187c99fb5f9SBaptiste Daroussin 								ucl_chunk_skipc (chunk, p);
188c99fb5f9SBaptiste Daroussin 								goto start;
189c99fb5f9SBaptiste Daroussin 							}
190c99fb5f9SBaptiste Daroussin 						}
191c99fb5f9SBaptiste Daroussin 						ucl_chunk_skipc (chunk, p);
192c99fb5f9SBaptiste Daroussin 					}
193c99fb5f9SBaptiste Daroussin 					else if (p[0] == '/' && chunk->remain >= 2 && p[1] == '*') {
194c99fb5f9SBaptiste Daroussin 						comments_nested ++;
195c99fb5f9SBaptiste Daroussin 						ucl_chunk_skipc (chunk, p);
196c99fb5f9SBaptiste Daroussin 						ucl_chunk_skipc (chunk, p);
197c99fb5f9SBaptiste Daroussin 						continue;
198c99fb5f9SBaptiste Daroussin 					}
1994bf54857SBaptiste Daroussin 				}
200d9f0ce31SBaptiste Daroussin 
201c99fb5f9SBaptiste Daroussin 				ucl_chunk_skipc (chunk, p);
202c99fb5f9SBaptiste Daroussin 			}
203c99fb5f9SBaptiste Daroussin 			if (comments_nested != 0) {
2044bf54857SBaptiste Daroussin 				ucl_set_err (parser, UCL_ENESTED,
2054bf54857SBaptiste Daroussin 						"unfinished multiline comment", &parser->err);
206c99fb5f9SBaptiste Daroussin 				return false;
207c99fb5f9SBaptiste Daroussin 			}
208c99fb5f9SBaptiste Daroussin 		}
209c99fb5f9SBaptiste Daroussin 	}
210c99fb5f9SBaptiste Daroussin 
211d9f0ce31SBaptiste Daroussin 	if (beg && p > beg && (parser->flags & UCL_PARSER_SAVE_COMMENTS)) {
212d9f0ce31SBaptiste Daroussin 		ucl_save_comment (parser, beg, p - beg);
213d9f0ce31SBaptiste Daroussin 	}
214d9f0ce31SBaptiste Daroussin 
215c99fb5f9SBaptiste Daroussin 	return true;
216c99fb5f9SBaptiste Daroussin }
217c99fb5f9SBaptiste Daroussin 
218c99fb5f9SBaptiste Daroussin /**
219c99fb5f9SBaptiste Daroussin  * Return multiplier for a character
220c99fb5f9SBaptiste Daroussin  * @param c multiplier character
221c99fb5f9SBaptiste Daroussin  * @param is_bytes if true use 1024 multiplier
222c99fb5f9SBaptiste Daroussin  * @return multiplier
223c99fb5f9SBaptiste Daroussin  */
224c99fb5f9SBaptiste Daroussin static inline unsigned long
ucl_lex_num_multiplier(const unsigned char c,bool is_bytes)225c99fb5f9SBaptiste Daroussin ucl_lex_num_multiplier (const unsigned char c, bool is_bytes) {
226c99fb5f9SBaptiste Daroussin 	const struct {
227c99fb5f9SBaptiste Daroussin 		char c;
228c99fb5f9SBaptiste Daroussin 		long mult_normal;
229c99fb5f9SBaptiste Daroussin 		long mult_bytes;
230c99fb5f9SBaptiste Daroussin 	} multipliers[] = {
231c99fb5f9SBaptiste Daroussin 			{'m', 1000 * 1000, 1024 * 1024},
232c99fb5f9SBaptiste Daroussin 			{'k', 1000, 1024},
233c99fb5f9SBaptiste Daroussin 			{'g', 1000 * 1000 * 1000, 1024 * 1024 * 1024}
234c99fb5f9SBaptiste Daroussin 	};
235c99fb5f9SBaptiste Daroussin 	int i;
236c99fb5f9SBaptiste Daroussin 
237c99fb5f9SBaptiste Daroussin 	for (i = 0; i < 3; i ++) {
238c99fb5f9SBaptiste Daroussin 		if (tolower (c) == multipliers[i].c) {
239c99fb5f9SBaptiste Daroussin 			if (is_bytes) {
240c99fb5f9SBaptiste Daroussin 				return multipliers[i].mult_bytes;
241c99fb5f9SBaptiste Daroussin 			}
242c99fb5f9SBaptiste Daroussin 			return multipliers[i].mult_normal;
243c99fb5f9SBaptiste Daroussin 		}
244c99fb5f9SBaptiste Daroussin 	}
245c99fb5f9SBaptiste Daroussin 
246c99fb5f9SBaptiste Daroussin 	return 1;
247c99fb5f9SBaptiste Daroussin }
248c99fb5f9SBaptiste Daroussin 
249c99fb5f9SBaptiste Daroussin 
250c99fb5f9SBaptiste Daroussin /**
251c99fb5f9SBaptiste Daroussin  * Return multiplier for time scaling
252c99fb5f9SBaptiste Daroussin  * @param c
253c99fb5f9SBaptiste Daroussin  * @return
254c99fb5f9SBaptiste Daroussin  */
255c99fb5f9SBaptiste Daroussin static inline double
ucl_lex_time_multiplier(const unsigned char c)256c99fb5f9SBaptiste Daroussin ucl_lex_time_multiplier (const unsigned char c) {
257c99fb5f9SBaptiste Daroussin 	const struct {
258c99fb5f9SBaptiste Daroussin 		char c;
259c99fb5f9SBaptiste Daroussin 		double mult;
260c99fb5f9SBaptiste Daroussin 	} multipliers[] = {
261c99fb5f9SBaptiste Daroussin 			{'m', 60},
262c99fb5f9SBaptiste Daroussin 			{'h', 60 * 60},
263c99fb5f9SBaptiste Daroussin 			{'d', 60 * 60 * 24},
264c99fb5f9SBaptiste Daroussin 			{'w', 60 * 60 * 24 * 7},
265d9f0ce31SBaptiste Daroussin 			{'y', 60 * 60 * 24 * 365}
266c99fb5f9SBaptiste Daroussin 	};
267c99fb5f9SBaptiste Daroussin 	int i;
268c99fb5f9SBaptiste Daroussin 
269c99fb5f9SBaptiste Daroussin 	for (i = 0; i < 5; i ++) {
270c99fb5f9SBaptiste Daroussin 		if (tolower (c) == multipliers[i].c) {
271c99fb5f9SBaptiste Daroussin 			return multipliers[i].mult;
272c99fb5f9SBaptiste Daroussin 		}
273c99fb5f9SBaptiste Daroussin 	}
274c99fb5f9SBaptiste Daroussin 
275c99fb5f9SBaptiste Daroussin 	return 1;
276c99fb5f9SBaptiste Daroussin }
277c99fb5f9SBaptiste Daroussin 
278c99fb5f9SBaptiste Daroussin /**
279c99fb5f9SBaptiste Daroussin  * Return true if a character is a end of an atom
280c99fb5f9SBaptiste Daroussin  * @param c
281c99fb5f9SBaptiste Daroussin  * @return
282c99fb5f9SBaptiste Daroussin  */
283c99fb5f9SBaptiste Daroussin static inline bool
ucl_lex_is_atom_end(const unsigned char c)284c99fb5f9SBaptiste Daroussin ucl_lex_is_atom_end (const unsigned char c)
285c99fb5f9SBaptiste Daroussin {
286c99fb5f9SBaptiste Daroussin 	return ucl_test_character (c, UCL_CHARACTER_VALUE_END);
287c99fb5f9SBaptiste Daroussin }
288c99fb5f9SBaptiste Daroussin 
289c99fb5f9SBaptiste Daroussin static inline bool
ucl_lex_is_comment(const unsigned char c1,const unsigned char c2)290c99fb5f9SBaptiste Daroussin ucl_lex_is_comment (const unsigned char c1, const unsigned char c2)
291c99fb5f9SBaptiste Daroussin {
292c99fb5f9SBaptiste Daroussin 	if (c1 == '/') {
293c99fb5f9SBaptiste Daroussin 		if (c2 == '*') {
294c99fb5f9SBaptiste Daroussin 			return true;
295c99fb5f9SBaptiste Daroussin 		}
296c99fb5f9SBaptiste Daroussin 	}
297c99fb5f9SBaptiste Daroussin 	else if (c1 == '#') {
298c99fb5f9SBaptiste Daroussin 		return true;
299c99fb5f9SBaptiste Daroussin 	}
300c99fb5f9SBaptiste Daroussin 	return false;
301c99fb5f9SBaptiste Daroussin }
302c99fb5f9SBaptiste Daroussin 
303c99fb5f9SBaptiste Daroussin /**
304c99fb5f9SBaptiste Daroussin  * Check variable found
305c99fb5f9SBaptiste Daroussin  * @param parser
306c99fb5f9SBaptiste Daroussin  * @param ptr
307c99fb5f9SBaptiste Daroussin  * @param remain
308c99fb5f9SBaptiste Daroussin  * @param out_len
309c99fb5f9SBaptiste Daroussin  * @param strict
310c99fb5f9SBaptiste Daroussin  * @param found
311c99fb5f9SBaptiste Daroussin  * @return
312c99fb5f9SBaptiste Daroussin  */
313c99fb5f9SBaptiste Daroussin static inline const char *
ucl_check_variable_safe(struct ucl_parser * parser,const char * ptr,size_t remain,size_t * out_len,bool strict,bool * found)314c99fb5f9SBaptiste Daroussin ucl_check_variable_safe (struct ucl_parser *parser, const char *ptr, size_t remain,
315c99fb5f9SBaptiste Daroussin 		size_t *out_len, bool strict, bool *found)
316c99fb5f9SBaptiste Daroussin {
317c99fb5f9SBaptiste Daroussin 	struct ucl_variable *var;
3182e8ed2b8SBaptiste Daroussin 	unsigned char *dst;
3192e8ed2b8SBaptiste Daroussin 	size_t dstlen;
3202e8ed2b8SBaptiste Daroussin 	bool need_free = false;
321c99fb5f9SBaptiste Daroussin 
322c99fb5f9SBaptiste Daroussin 	LL_FOREACH (parser->variables, var) {
323c99fb5f9SBaptiste Daroussin 		if (strict) {
324c99fb5f9SBaptiste Daroussin 			if (remain == var->var_len) {
325c99fb5f9SBaptiste Daroussin 				if (memcmp (ptr, var->var, var->var_len) == 0) {
326c99fb5f9SBaptiste Daroussin 					*out_len += var->value_len;
327c99fb5f9SBaptiste Daroussin 					*found = true;
328c99fb5f9SBaptiste Daroussin 					return (ptr + var->var_len);
329c99fb5f9SBaptiste Daroussin 				}
330c99fb5f9SBaptiste Daroussin 			}
331c99fb5f9SBaptiste Daroussin 		}
332c99fb5f9SBaptiste Daroussin 		else {
333c99fb5f9SBaptiste Daroussin 			if (remain >= var->var_len) {
334c99fb5f9SBaptiste Daroussin 				if (memcmp (ptr, var->var, var->var_len) == 0) {
335c99fb5f9SBaptiste Daroussin 					*out_len += var->value_len;
336c99fb5f9SBaptiste Daroussin 					*found = true;
337c99fb5f9SBaptiste Daroussin 					return (ptr + var->var_len);
338c99fb5f9SBaptiste Daroussin 				}
339c99fb5f9SBaptiste Daroussin 			}
340c99fb5f9SBaptiste Daroussin 		}
341c99fb5f9SBaptiste Daroussin 	}
342c99fb5f9SBaptiste Daroussin 
3432e8ed2b8SBaptiste Daroussin 	/* XXX: can only handle ${VAR} */
3442e8ed2b8SBaptiste Daroussin 	if (!(*found) && parser->var_handler != NULL && strict) {
3452e8ed2b8SBaptiste Daroussin 		/* Call generic handler */
3462e8ed2b8SBaptiste Daroussin 		if (parser->var_handler (ptr, remain, &dst, &dstlen, &need_free,
3472e8ed2b8SBaptiste Daroussin 				parser->var_data)) {
348*a0409676SBaptiste Daroussin 			*out_len = dstlen;
3492e8ed2b8SBaptiste Daroussin 			*found = true;
3502e8ed2b8SBaptiste Daroussin 			if (need_free) {
3512e8ed2b8SBaptiste Daroussin 				free (dst);
3522e8ed2b8SBaptiste Daroussin 			}
3532e8ed2b8SBaptiste Daroussin 			return (ptr + remain);
3542e8ed2b8SBaptiste Daroussin 		}
3552e8ed2b8SBaptiste Daroussin 	}
3562e8ed2b8SBaptiste Daroussin 
357c99fb5f9SBaptiste Daroussin 	return ptr;
358c99fb5f9SBaptiste Daroussin }
359c99fb5f9SBaptiste Daroussin 
360c99fb5f9SBaptiste Daroussin /**
361c99fb5f9SBaptiste Daroussin  * Check for a variable in a given string
362c99fb5f9SBaptiste Daroussin  * @param parser
363c99fb5f9SBaptiste Daroussin  * @param ptr
364c99fb5f9SBaptiste Daroussin  * @param remain
365c99fb5f9SBaptiste Daroussin  * @param out_len
366c99fb5f9SBaptiste Daroussin  * @param vars_found
367c99fb5f9SBaptiste Daroussin  * @return
368c99fb5f9SBaptiste Daroussin  */
369c99fb5f9SBaptiste Daroussin static const char *
ucl_check_variable(struct ucl_parser * parser,const char * ptr,size_t remain,size_t * out_len,bool * vars_found)3702e8ed2b8SBaptiste Daroussin ucl_check_variable (struct ucl_parser *parser, const char *ptr,
3712e8ed2b8SBaptiste Daroussin 		size_t remain, size_t *out_len, bool *vars_found)
372c99fb5f9SBaptiste Daroussin {
373c99fb5f9SBaptiste Daroussin 	const char *p, *end, *ret = ptr;
374c99fb5f9SBaptiste Daroussin 	bool found = false;
375c99fb5f9SBaptiste Daroussin 
376c99fb5f9SBaptiste Daroussin 	if (*ptr == '{') {
377c99fb5f9SBaptiste Daroussin 		/* We need to match the variable enclosed in braces */
378c99fb5f9SBaptiste Daroussin 		p = ptr + 1;
379c99fb5f9SBaptiste Daroussin 		end = ptr + remain;
380c99fb5f9SBaptiste Daroussin 		while (p < end) {
381c99fb5f9SBaptiste Daroussin 			if (*p == '}') {
3822e8ed2b8SBaptiste Daroussin 				ret = ucl_check_variable_safe (parser, ptr + 1, p - ptr - 1,
3832e8ed2b8SBaptiste Daroussin 						out_len, true, &found);
384c99fb5f9SBaptiste Daroussin 				if (found) {
385c99fb5f9SBaptiste Daroussin 					/* {} must be excluded actually */
386c99fb5f9SBaptiste Daroussin 					ret ++;
387c99fb5f9SBaptiste Daroussin 					if (!*vars_found) {
388c99fb5f9SBaptiste Daroussin 						*vars_found = true;
389c99fb5f9SBaptiste Daroussin 					}
390c99fb5f9SBaptiste Daroussin 				}
391c99fb5f9SBaptiste Daroussin 				else {
392c99fb5f9SBaptiste Daroussin 					*out_len += 2;
393c99fb5f9SBaptiste Daroussin 				}
394c99fb5f9SBaptiste Daroussin 				break;
395c99fb5f9SBaptiste Daroussin 			}
396c99fb5f9SBaptiste Daroussin 			p ++;
397c99fb5f9SBaptiste Daroussin 		}
398c99fb5f9SBaptiste Daroussin 	}
399c99fb5f9SBaptiste Daroussin 	else if (*ptr != '$') {
400c99fb5f9SBaptiste Daroussin 		/* Not count escaped dollar sign */
401c99fb5f9SBaptiste Daroussin 		ret = ucl_check_variable_safe (parser, ptr, remain, out_len, false, &found);
402c99fb5f9SBaptiste Daroussin 		if (found && !*vars_found) {
403c99fb5f9SBaptiste Daroussin 			*vars_found = true;
404c99fb5f9SBaptiste Daroussin 		}
405c99fb5f9SBaptiste Daroussin 		if (!found) {
406c99fb5f9SBaptiste Daroussin 			(*out_len) ++;
407c99fb5f9SBaptiste Daroussin 		}
408c99fb5f9SBaptiste Daroussin 	}
409c99fb5f9SBaptiste Daroussin 	else {
410c99fb5f9SBaptiste Daroussin 		ret ++;
411c99fb5f9SBaptiste Daroussin 		(*out_len) ++;
412c99fb5f9SBaptiste Daroussin 	}
413c99fb5f9SBaptiste Daroussin 
414c99fb5f9SBaptiste Daroussin 	return ret;
415c99fb5f9SBaptiste Daroussin }
416c99fb5f9SBaptiste Daroussin 
417c99fb5f9SBaptiste Daroussin /**
418c99fb5f9SBaptiste Daroussin  * Expand a single variable
419c99fb5f9SBaptiste Daroussin  * @param parser
420c99fb5f9SBaptiste Daroussin  * @param ptr
421c99fb5f9SBaptiste Daroussin  * @param remain
422c99fb5f9SBaptiste Daroussin  * @param dest
423c99fb5f9SBaptiste Daroussin  * @return
424c99fb5f9SBaptiste Daroussin  */
425c99fb5f9SBaptiste Daroussin static const char *
ucl_expand_single_variable(struct ucl_parser * parser,const char * ptr,size_t remain,unsigned char ** dest)426c99fb5f9SBaptiste Daroussin ucl_expand_single_variable (struct ucl_parser *parser, const char *ptr,
427c99fb5f9SBaptiste Daroussin 		size_t remain, unsigned char **dest)
428c99fb5f9SBaptiste Daroussin {
4292e8ed2b8SBaptiste Daroussin 	unsigned char *d = *dest, *dst;
430c99fb5f9SBaptiste Daroussin 	const char *p = ptr + 1, *ret;
431c99fb5f9SBaptiste Daroussin 	struct ucl_variable *var;
4322e8ed2b8SBaptiste Daroussin 	size_t dstlen;
4332e8ed2b8SBaptiste Daroussin 	bool need_free = false;
434c99fb5f9SBaptiste Daroussin 	bool found = false;
4352e8ed2b8SBaptiste Daroussin 	bool strict = false;
436c99fb5f9SBaptiste Daroussin 
437c99fb5f9SBaptiste Daroussin 	ret = ptr + 1;
438c99fb5f9SBaptiste Daroussin 	remain --;
439c99fb5f9SBaptiste Daroussin 
440c99fb5f9SBaptiste Daroussin 	if (*p == '$') {
441c99fb5f9SBaptiste Daroussin 		*d++ = *p++;
442c99fb5f9SBaptiste Daroussin 		*dest = d;
443c99fb5f9SBaptiste Daroussin 		return p;
444c99fb5f9SBaptiste Daroussin 	}
445c99fb5f9SBaptiste Daroussin 	else if (*p == '{') {
446c99fb5f9SBaptiste Daroussin 		p ++;
4472e8ed2b8SBaptiste Daroussin 		strict = true;
448c99fb5f9SBaptiste Daroussin 		ret += 2;
449c99fb5f9SBaptiste Daroussin 		remain -= 2;
450c99fb5f9SBaptiste Daroussin 	}
451c99fb5f9SBaptiste Daroussin 
452c99fb5f9SBaptiste Daroussin 	LL_FOREACH (parser->variables, var) {
453c99fb5f9SBaptiste Daroussin 		if (remain >= var->var_len) {
454c99fb5f9SBaptiste Daroussin 			if (memcmp (p, var->var, var->var_len) == 0) {
455c99fb5f9SBaptiste Daroussin 				memcpy (d, var->value, var->value_len);
456c99fb5f9SBaptiste Daroussin 				ret += var->var_len;
457c99fb5f9SBaptiste Daroussin 				d += var->value_len;
458c99fb5f9SBaptiste Daroussin 				found = true;
459c99fb5f9SBaptiste Daroussin 				break;
460c99fb5f9SBaptiste Daroussin 			}
461c99fb5f9SBaptiste Daroussin 		}
462c99fb5f9SBaptiste Daroussin 	}
463c99fb5f9SBaptiste Daroussin 	if (!found) {
4642e8ed2b8SBaptiste Daroussin 		if (strict && parser->var_handler != NULL) {
465*a0409676SBaptiste Daroussin 			if (parser->var_handler (p, remain, &dst, &dstlen, &need_free,
4662e8ed2b8SBaptiste Daroussin 							parser->var_data)) {
4672e8ed2b8SBaptiste Daroussin 				memcpy (d, dst, dstlen);
468*a0409676SBaptiste Daroussin 				ret += remain;
469273c26a3SBaptiste Daroussin 				d += dstlen;
470*a0409676SBaptiste Daroussin 				found = true;
471273c26a3SBaptiste Daroussin 				if (need_free) {
472273c26a3SBaptiste Daroussin 					free (dst);
473273c26a3SBaptiste Daroussin 				}
4742e8ed2b8SBaptiste Daroussin 			}
4752e8ed2b8SBaptiste Daroussin 		}
4762e8ed2b8SBaptiste Daroussin 
4772e8ed2b8SBaptiste Daroussin 		/* Leave variable as is */
4782e8ed2b8SBaptiste Daroussin 		if (!found) {
4793dcf5eb7SBaptiste Daroussin 			if (strict) {
4803dcf5eb7SBaptiste Daroussin 				/* Copy '${' */
481c99fb5f9SBaptiste Daroussin 				memcpy (d, ptr, 2);
482c99fb5f9SBaptiste Daroussin 				d += 2;
483c99fb5f9SBaptiste Daroussin 				ret --;
484c99fb5f9SBaptiste Daroussin 			}
4853dcf5eb7SBaptiste Daroussin 			else {
4863dcf5eb7SBaptiste Daroussin 				memcpy (d, ptr, 1);
4873dcf5eb7SBaptiste Daroussin 				d ++;
4883dcf5eb7SBaptiste Daroussin 			}
4893dcf5eb7SBaptiste Daroussin 		}
4902e8ed2b8SBaptiste Daroussin 	}
491c99fb5f9SBaptiste Daroussin 
492c99fb5f9SBaptiste Daroussin 	*dest = d;
493c99fb5f9SBaptiste Daroussin 	return ret;
494c99fb5f9SBaptiste Daroussin }
495c99fb5f9SBaptiste Daroussin 
496c99fb5f9SBaptiste Daroussin /**
497c99fb5f9SBaptiste Daroussin  * Expand variables in string
498c99fb5f9SBaptiste Daroussin  * @param parser
499c99fb5f9SBaptiste Daroussin  * @param dst
500c99fb5f9SBaptiste Daroussin  * @param src
501c99fb5f9SBaptiste Daroussin  * @param in_len
502c99fb5f9SBaptiste Daroussin  * @return
503c99fb5f9SBaptiste Daroussin  */
504c99fb5f9SBaptiste Daroussin static ssize_t
ucl_expand_variable(struct ucl_parser * parser,unsigned char ** dst,const char * src,size_t in_len)505c99fb5f9SBaptiste Daroussin ucl_expand_variable (struct ucl_parser *parser, unsigned char **dst,
506c99fb5f9SBaptiste Daroussin 		const char *src, size_t in_len)
507c99fb5f9SBaptiste Daroussin {
508c99fb5f9SBaptiste Daroussin 	const char *p, *end = src + in_len;
509c99fb5f9SBaptiste Daroussin 	unsigned char *d;
510c99fb5f9SBaptiste Daroussin 	size_t out_len = 0;
511c99fb5f9SBaptiste Daroussin 	bool vars_found = false;
512c99fb5f9SBaptiste Daroussin 
513d9f0ce31SBaptiste Daroussin 	if (parser->flags & UCL_PARSER_DISABLE_MACRO) {
514d9f0ce31SBaptiste Daroussin 		*dst = NULL;
515d9f0ce31SBaptiste Daroussin 		return in_len;
516d9f0ce31SBaptiste Daroussin 	}
517d9f0ce31SBaptiste Daroussin 
518c99fb5f9SBaptiste Daroussin 	p = src;
519c99fb5f9SBaptiste Daroussin 	while (p != end) {
520c99fb5f9SBaptiste Daroussin 		if (*p == '$') {
521c99fb5f9SBaptiste Daroussin 			p = ucl_check_variable (parser, p + 1, end - p - 1, &out_len, &vars_found);
522c99fb5f9SBaptiste Daroussin 		}
523c99fb5f9SBaptiste Daroussin 		else {
524c99fb5f9SBaptiste Daroussin 			p ++;
525c99fb5f9SBaptiste Daroussin 			out_len ++;
526c99fb5f9SBaptiste Daroussin 		}
527c99fb5f9SBaptiste Daroussin 	}
528c99fb5f9SBaptiste Daroussin 
529c99fb5f9SBaptiste Daroussin 	if (!vars_found) {
530c99fb5f9SBaptiste Daroussin 		/* Trivial case */
531c99fb5f9SBaptiste Daroussin 		*dst = NULL;
532c99fb5f9SBaptiste Daroussin 		return in_len;
533c99fb5f9SBaptiste Daroussin 	}
534c99fb5f9SBaptiste Daroussin 
535c99fb5f9SBaptiste Daroussin 	*dst = UCL_ALLOC (out_len + 1);
536c99fb5f9SBaptiste Daroussin 	if (*dst == NULL) {
537c99fb5f9SBaptiste Daroussin 		return in_len;
538c99fb5f9SBaptiste Daroussin 	}
539c99fb5f9SBaptiste Daroussin 
540c99fb5f9SBaptiste Daroussin 	d = *dst;
541c99fb5f9SBaptiste Daroussin 	p = src;
542c99fb5f9SBaptiste Daroussin 	while (p != end) {
543c99fb5f9SBaptiste Daroussin 		if (*p == '$') {
544c99fb5f9SBaptiste Daroussin 			p = ucl_expand_single_variable (parser, p, end - p, &d);
545c99fb5f9SBaptiste Daroussin 		}
546c99fb5f9SBaptiste Daroussin 		else {
547c99fb5f9SBaptiste Daroussin 			*d++ = *p++;
548c99fb5f9SBaptiste Daroussin 		}
549c99fb5f9SBaptiste Daroussin 	}
550c99fb5f9SBaptiste Daroussin 
551c99fb5f9SBaptiste Daroussin 	*d = '\0';
552c99fb5f9SBaptiste Daroussin 
553c99fb5f9SBaptiste Daroussin 	return out_len;
554c99fb5f9SBaptiste Daroussin }
555c99fb5f9SBaptiste Daroussin 
556c99fb5f9SBaptiste Daroussin /**
557c99fb5f9SBaptiste Daroussin  * Store or copy pointer to the trash stack
558c99fb5f9SBaptiste Daroussin  * @param parser parser object
559c99fb5f9SBaptiste Daroussin  * @param src src string
560c99fb5f9SBaptiste Daroussin  * @param dst destination buffer (trash stack pointer)
561c99fb5f9SBaptiste Daroussin  * @param dst_const const destination pointer (e.g. value of object)
562c99fb5f9SBaptiste Daroussin  * @param in_len input length
563c99fb5f9SBaptiste Daroussin  * @param need_unescape need to unescape source (and copy it)
564c99fb5f9SBaptiste Daroussin  * @param need_lowercase need to lowercase value (and copy)
565c99fb5f9SBaptiste Daroussin  * @param need_expand need to expand variables (and copy as well)
566*a0409676SBaptiste Daroussin  * @param unescape_squote unescape single quoted string
567c99fb5f9SBaptiste Daroussin  * @return output length (excluding \0 symbol)
568c99fb5f9SBaptiste Daroussin  */
569c99fb5f9SBaptiste Daroussin static inline ssize_t
ucl_copy_or_store_ptr(struct ucl_parser * parser,const unsigned char * src,unsigned char ** dst,const char ** dst_const,size_t in_len,bool need_unescape,bool need_lowercase,bool need_expand,bool unescape_squote)570c99fb5f9SBaptiste Daroussin ucl_copy_or_store_ptr (struct ucl_parser *parser,
571c99fb5f9SBaptiste Daroussin 		const unsigned char *src, unsigned char **dst,
572c99fb5f9SBaptiste Daroussin 		const char **dst_const, size_t in_len,
573*a0409676SBaptiste Daroussin 		bool need_unescape, bool need_lowercase, bool need_expand,
574*a0409676SBaptiste Daroussin 		bool unescape_squote)
575c99fb5f9SBaptiste Daroussin {
576c99fb5f9SBaptiste Daroussin 	ssize_t ret = -1, tret;
577c99fb5f9SBaptiste Daroussin 	unsigned char *tmp;
578c99fb5f9SBaptiste Daroussin 
579c99fb5f9SBaptiste Daroussin 	if (need_unescape || need_lowercase ||
580c99fb5f9SBaptiste Daroussin 			(need_expand && parser->variables != NULL) ||
581c99fb5f9SBaptiste Daroussin 			!(parser->flags & UCL_PARSER_ZEROCOPY)) {
582c99fb5f9SBaptiste Daroussin 		/* Copy string */
583c99fb5f9SBaptiste Daroussin 		*dst = UCL_ALLOC (in_len + 1);
584c99fb5f9SBaptiste Daroussin 		if (*dst == NULL) {
58539ee7a7aSBaptiste Daroussin 			ucl_set_err (parser, UCL_EINTERNAL, "cannot allocate memory for a string",
5864bf54857SBaptiste Daroussin 					&parser->err);
587c99fb5f9SBaptiste Daroussin 			return false;
588c99fb5f9SBaptiste Daroussin 		}
589c99fb5f9SBaptiste Daroussin 		if (need_lowercase) {
590c99fb5f9SBaptiste Daroussin 			ret = ucl_strlcpy_tolower (*dst, src, in_len + 1);
591c99fb5f9SBaptiste Daroussin 		}
592c99fb5f9SBaptiste Daroussin 		else {
593c99fb5f9SBaptiste Daroussin 			ret = ucl_strlcpy_unsafe (*dst, src, in_len + 1);
594c99fb5f9SBaptiste Daroussin 		}
595c99fb5f9SBaptiste Daroussin 
596c99fb5f9SBaptiste Daroussin 		if (need_unescape) {
597*a0409676SBaptiste Daroussin 			if (!unescape_squote) {
598c99fb5f9SBaptiste Daroussin 				ret = ucl_unescape_json_string (*dst, ret);
599c99fb5f9SBaptiste Daroussin 			}
600*a0409676SBaptiste Daroussin 			else {
601*a0409676SBaptiste Daroussin 				ret = ucl_unescape_squoted_string (*dst, ret);
602*a0409676SBaptiste Daroussin 			}
603*a0409676SBaptiste Daroussin 		}
604*a0409676SBaptiste Daroussin 
605c99fb5f9SBaptiste Daroussin 		if (need_expand) {
606c99fb5f9SBaptiste Daroussin 			tmp = *dst;
607c99fb5f9SBaptiste Daroussin 			tret = ret;
608c99fb5f9SBaptiste Daroussin 			ret = ucl_expand_variable (parser, dst, tmp, ret);
609c99fb5f9SBaptiste Daroussin 			if (*dst == NULL) {
610c99fb5f9SBaptiste Daroussin 				/* Nothing to expand */
611c99fb5f9SBaptiste Daroussin 				*dst = tmp;
612c99fb5f9SBaptiste Daroussin 				ret = tret;
613c99fb5f9SBaptiste Daroussin 			}
6144bf54857SBaptiste Daroussin 			else {
6154bf54857SBaptiste Daroussin 				/* Free unexpanded value */
6164bf54857SBaptiste Daroussin 				UCL_FREE (in_len + 1, tmp);
6174bf54857SBaptiste Daroussin 			}
618c99fb5f9SBaptiste Daroussin 		}
619c99fb5f9SBaptiste Daroussin 		*dst_const = *dst;
620c99fb5f9SBaptiste Daroussin 	}
621c99fb5f9SBaptiste Daroussin 	else {
622c99fb5f9SBaptiste Daroussin 		*dst_const = src;
623c99fb5f9SBaptiste Daroussin 		ret = in_len;
624c99fb5f9SBaptiste Daroussin 	}
625c99fb5f9SBaptiste Daroussin 
626c99fb5f9SBaptiste Daroussin 	return ret;
627c99fb5f9SBaptiste Daroussin }
628c99fb5f9SBaptiste Daroussin 
629c99fb5f9SBaptiste Daroussin /**
630c99fb5f9SBaptiste Daroussin  * Create and append an object at the specified level
631c99fb5f9SBaptiste Daroussin  * @param parser
632c99fb5f9SBaptiste Daroussin  * @param is_array
633c99fb5f9SBaptiste Daroussin  * @param level
634c99fb5f9SBaptiste Daroussin  * @return
635c99fb5f9SBaptiste Daroussin  */
636c99fb5f9SBaptiste Daroussin static inline ucl_object_t *
ucl_parser_add_container(ucl_object_t * obj,struct ucl_parser * parser,bool is_array,uint32_t level,bool has_obrace)63739ee7a7aSBaptiste Daroussin ucl_parser_add_container (ucl_object_t *obj, struct ucl_parser *parser,
638*a0409676SBaptiste Daroussin 		bool is_array, uint32_t level, bool has_obrace)
639c99fb5f9SBaptiste Daroussin {
640c99fb5f9SBaptiste Daroussin 	struct ucl_stack *st;
641*a0409676SBaptiste Daroussin 	ucl_object_t *nobj;
642*a0409676SBaptiste Daroussin 
643*a0409676SBaptiste Daroussin 	if (obj == NULL) {
644*a0409676SBaptiste Daroussin 		nobj = ucl_object_new_full (is_array ? UCL_ARRAY : UCL_OBJECT, parser->chunks->priority);
645*a0409676SBaptiste Daroussin 		if (nobj == NULL) {
646*a0409676SBaptiste Daroussin 			goto enomem0;
647*a0409676SBaptiste Daroussin 		}
648*a0409676SBaptiste Daroussin 	} else {
649*a0409676SBaptiste Daroussin 		if (obj->type == (is_array ? UCL_OBJECT : UCL_ARRAY)) {
650*a0409676SBaptiste Daroussin 			/* Bad combination for merge: array and object */
651*a0409676SBaptiste Daroussin 			ucl_set_err (parser, UCL_EMERGE,
652*a0409676SBaptiste Daroussin 					"cannot merge an object with an array",
653*a0409676SBaptiste Daroussin 					&parser->err);
654*a0409676SBaptiste Daroussin 
655*a0409676SBaptiste Daroussin 			return NULL;
656*a0409676SBaptiste Daroussin 		}
657*a0409676SBaptiste Daroussin 		nobj = obj;
658*a0409676SBaptiste Daroussin 		nobj->type = is_array ? UCL_ARRAY : UCL_OBJECT;
659*a0409676SBaptiste Daroussin 	}
660c99fb5f9SBaptiste Daroussin 
661c99fb5f9SBaptiste Daroussin 	if (!is_array) {
662*a0409676SBaptiste Daroussin 		if (nobj->value.ov == NULL) {
663*a0409676SBaptiste Daroussin 			nobj->value.ov = ucl_hash_create (parser->flags & UCL_PARSER_KEY_LOWERCASE);
664*a0409676SBaptiste Daroussin 			if (nobj->value.ov == NULL) {
665*a0409676SBaptiste Daroussin 				goto enomem1;
666c99fb5f9SBaptiste Daroussin 			}
66739ee7a7aSBaptiste Daroussin 		}
668c99fb5f9SBaptiste Daroussin 		parser->state = UCL_STATE_KEY;
669*a0409676SBaptiste Daroussin 	} else {
670c99fb5f9SBaptiste Daroussin 		parser->state = UCL_STATE_VALUE;
671c99fb5f9SBaptiste Daroussin 	}
672c99fb5f9SBaptiste Daroussin 
673c99fb5f9SBaptiste Daroussin 	st = UCL_ALLOC (sizeof (struct ucl_stack));
674d9f0ce31SBaptiste Daroussin 
67597bd480fSBaptiste Daroussin 	if (st == NULL) {
676*a0409676SBaptiste Daroussin 		goto enomem1;
677*a0409676SBaptiste Daroussin 	}
678*a0409676SBaptiste Daroussin 
679*a0409676SBaptiste Daroussin 	st->obj = nobj;
680*a0409676SBaptiste Daroussin 
681*a0409676SBaptiste Daroussin 	if (level >= UINT16_MAX) {
682*a0409676SBaptiste Daroussin 		ucl_set_err (parser, UCL_ENESTED,
683*a0409676SBaptiste Daroussin 				"objects are nesting too deep (over 65535 limit)",
6844bf54857SBaptiste Daroussin 				&parser->err);
685*a0409676SBaptiste Daroussin 		if (nobj != obj) {
6864bf54857SBaptiste Daroussin 			ucl_object_unref (obj);
687*a0409676SBaptiste Daroussin 		}
688*a0409676SBaptiste Daroussin 
68997bd480fSBaptiste Daroussin 		return NULL;
69097bd480fSBaptiste Daroussin 	}
691d9f0ce31SBaptiste Daroussin 
692c99fb5f9SBaptiste Daroussin 
693*a0409676SBaptiste Daroussin 	st->e.params.level = level;
694*a0409676SBaptiste Daroussin 	st->e.params.line = parser->chunks->line;
695*a0409676SBaptiste Daroussin 	st->chunk = parser->chunks;
696*a0409676SBaptiste Daroussin 
697*a0409676SBaptiste Daroussin 	if (has_obrace) {
698*a0409676SBaptiste Daroussin 		st->e.params.flags = UCL_STACK_HAS_OBRACE;
699*a0409676SBaptiste Daroussin 	}
700*a0409676SBaptiste Daroussin 	else {
701*a0409676SBaptiste Daroussin 		st->e.params.flags = 0;
702*a0409676SBaptiste Daroussin 	}
703*a0409676SBaptiste Daroussin 
704*a0409676SBaptiste Daroussin 	LL_PREPEND (parser->stack, st);
705*a0409676SBaptiste Daroussin 	parser->cur_obj = nobj;
706*a0409676SBaptiste Daroussin 
707*a0409676SBaptiste Daroussin 	return nobj;
708*a0409676SBaptiste Daroussin enomem1:
709*a0409676SBaptiste Daroussin 	if (nobj != obj)
710*a0409676SBaptiste Daroussin 		ucl_object_unref (nobj);
711*a0409676SBaptiste Daroussin enomem0:
712*a0409676SBaptiste Daroussin 	ucl_set_err (parser, UCL_EINTERNAL, "cannot allocate memory for an object",
713*a0409676SBaptiste Daroussin 			&parser->err);
714*a0409676SBaptiste Daroussin 	return NULL;
715c99fb5f9SBaptiste Daroussin }
716c99fb5f9SBaptiste Daroussin 
717c99fb5f9SBaptiste Daroussin int
ucl_maybe_parse_number(ucl_object_t * obj,const char * start,const char * end,const char ** pos,bool allow_double,bool number_bytes,bool allow_time)718c99fb5f9SBaptiste Daroussin ucl_maybe_parse_number (ucl_object_t *obj,
71997bd480fSBaptiste Daroussin 		const char *start, const char *end, const char **pos,
72097bd480fSBaptiste Daroussin 		bool allow_double, bool number_bytes, bool allow_time)
721c99fb5f9SBaptiste Daroussin {
722c99fb5f9SBaptiste Daroussin 	const char *p = start, *c = start;
723c99fb5f9SBaptiste Daroussin 	char *endptr;
724c99fb5f9SBaptiste Daroussin 	bool got_dot = false, got_exp = false, need_double = false,
72597bd480fSBaptiste Daroussin 			is_time = false, valid_start = false, is_hex = false,
726c99fb5f9SBaptiste Daroussin 			is_neg = false;
727c99fb5f9SBaptiste Daroussin 	double dv = 0;
728c99fb5f9SBaptiste Daroussin 	int64_t lv = 0;
729c99fb5f9SBaptiste Daroussin 
730c99fb5f9SBaptiste Daroussin 	if (*p == '-') {
731c99fb5f9SBaptiste Daroussin 		is_neg = true;
732c99fb5f9SBaptiste Daroussin 		c ++;
733c99fb5f9SBaptiste Daroussin 		p ++;
734c99fb5f9SBaptiste Daroussin 	}
735c99fb5f9SBaptiste Daroussin 	while (p < end) {
736c99fb5f9SBaptiste Daroussin 		if (is_hex && isxdigit (*p)) {
737c99fb5f9SBaptiste Daroussin 			p ++;
738c99fb5f9SBaptiste Daroussin 		}
739c99fb5f9SBaptiste Daroussin 		else if (isdigit (*p)) {
740c99fb5f9SBaptiste Daroussin 			valid_start = true;
741c99fb5f9SBaptiste Daroussin 			p ++;
742c99fb5f9SBaptiste Daroussin 		}
743c99fb5f9SBaptiste Daroussin 		else if (!is_hex && (*p == 'x' || *p == 'X')) {
744c99fb5f9SBaptiste Daroussin 			is_hex = true;
745c99fb5f9SBaptiste Daroussin 			allow_double = false;
746c99fb5f9SBaptiste Daroussin 			c = p + 1;
747c99fb5f9SBaptiste Daroussin 		}
748c99fb5f9SBaptiste Daroussin 		else if (allow_double) {
749c99fb5f9SBaptiste Daroussin 			if (p == c) {
750c99fb5f9SBaptiste Daroussin 				/* Empty digits sequence, not a number */
751c99fb5f9SBaptiste Daroussin 				*pos = start;
752c99fb5f9SBaptiste Daroussin 				return EINVAL;
753c99fb5f9SBaptiste Daroussin 			}
754c99fb5f9SBaptiste Daroussin 			else if (*p == '.') {
755c99fb5f9SBaptiste Daroussin 				if (got_dot) {
756c99fb5f9SBaptiste Daroussin 					/* Double dots, not a number */
757c99fb5f9SBaptiste Daroussin 					*pos = start;
758c99fb5f9SBaptiste Daroussin 					return EINVAL;
759c99fb5f9SBaptiste Daroussin 				}
760c99fb5f9SBaptiste Daroussin 				else {
761c99fb5f9SBaptiste Daroussin 					got_dot = true;
762c99fb5f9SBaptiste Daroussin 					need_double = true;
763c99fb5f9SBaptiste Daroussin 					p ++;
764c99fb5f9SBaptiste Daroussin 				}
765c99fb5f9SBaptiste Daroussin 			}
766c99fb5f9SBaptiste Daroussin 			else if (*p == 'e' || *p == 'E') {
767c99fb5f9SBaptiste Daroussin 				if (got_exp) {
768c99fb5f9SBaptiste Daroussin 					/* Double exp, not a number */
769c99fb5f9SBaptiste Daroussin 					*pos = start;
770c99fb5f9SBaptiste Daroussin 					return EINVAL;
771c99fb5f9SBaptiste Daroussin 				}
772c99fb5f9SBaptiste Daroussin 				else {
773c99fb5f9SBaptiste Daroussin 					got_exp = true;
774c99fb5f9SBaptiste Daroussin 					need_double = true;
775c99fb5f9SBaptiste Daroussin 					p ++;
776c99fb5f9SBaptiste Daroussin 					if (p >= end) {
777c99fb5f9SBaptiste Daroussin 						*pos = start;
778c99fb5f9SBaptiste Daroussin 						return EINVAL;
779c99fb5f9SBaptiste Daroussin 					}
780c99fb5f9SBaptiste Daroussin 					if (!isdigit (*p) && *p != '+' && *p != '-') {
781c99fb5f9SBaptiste Daroussin 						/* Wrong exponent sign */
782c99fb5f9SBaptiste Daroussin 						*pos = start;
783c99fb5f9SBaptiste Daroussin 						return EINVAL;
784c99fb5f9SBaptiste Daroussin 					}
785c99fb5f9SBaptiste Daroussin 					else {
786c99fb5f9SBaptiste Daroussin 						p ++;
787c99fb5f9SBaptiste Daroussin 					}
788c99fb5f9SBaptiste Daroussin 				}
789c99fb5f9SBaptiste Daroussin 			}
790c99fb5f9SBaptiste Daroussin 			else {
791c99fb5f9SBaptiste Daroussin 				/* Got the end of the number, need to check */
792c99fb5f9SBaptiste Daroussin 				break;
793c99fb5f9SBaptiste Daroussin 			}
794c99fb5f9SBaptiste Daroussin 		}
795c99fb5f9SBaptiste Daroussin 		else {
796c99fb5f9SBaptiste Daroussin 			break;
797c99fb5f9SBaptiste Daroussin 		}
798c99fb5f9SBaptiste Daroussin 	}
799c99fb5f9SBaptiste Daroussin 
800c99fb5f9SBaptiste Daroussin 	if (!valid_start) {
801c99fb5f9SBaptiste Daroussin 		*pos = start;
802c99fb5f9SBaptiste Daroussin 		return EINVAL;
803c99fb5f9SBaptiste Daroussin 	}
804c99fb5f9SBaptiste Daroussin 
805c99fb5f9SBaptiste Daroussin 	errno = 0;
806c99fb5f9SBaptiste Daroussin 	if (need_double) {
807c99fb5f9SBaptiste Daroussin 		dv = strtod (c, &endptr);
808c99fb5f9SBaptiste Daroussin 	}
809c99fb5f9SBaptiste Daroussin 	else {
810c99fb5f9SBaptiste Daroussin 		if (is_hex) {
811c99fb5f9SBaptiste Daroussin 			lv = strtoimax (c, &endptr, 16);
812c99fb5f9SBaptiste Daroussin 		}
813c99fb5f9SBaptiste Daroussin 		else {
814c99fb5f9SBaptiste Daroussin 			lv = strtoimax (c, &endptr, 10);
815c99fb5f9SBaptiste Daroussin 		}
816c99fb5f9SBaptiste Daroussin 	}
817c99fb5f9SBaptiste Daroussin 	if (errno == ERANGE) {
818c99fb5f9SBaptiste Daroussin 		*pos = start;
819c99fb5f9SBaptiste Daroussin 		return ERANGE;
820c99fb5f9SBaptiste Daroussin 	}
821c99fb5f9SBaptiste Daroussin 
822c99fb5f9SBaptiste Daroussin 	/* Now check endptr */
8234bf54857SBaptiste Daroussin 	if (endptr == NULL || ucl_lex_is_atom_end (*endptr) || *endptr == '\0') {
824c99fb5f9SBaptiste Daroussin 		p = endptr;
825c99fb5f9SBaptiste Daroussin 		goto set_obj;
826c99fb5f9SBaptiste Daroussin 	}
827c99fb5f9SBaptiste Daroussin 
828c99fb5f9SBaptiste Daroussin 	if (endptr < end && endptr != start) {
829c99fb5f9SBaptiste Daroussin 		p = endptr;
830c99fb5f9SBaptiste Daroussin 		switch (*p) {
831c99fb5f9SBaptiste Daroussin 		case 'm':
832c99fb5f9SBaptiste Daroussin 		case 'M':
833c99fb5f9SBaptiste Daroussin 		case 'g':
834c99fb5f9SBaptiste Daroussin 		case 'G':
835c99fb5f9SBaptiste Daroussin 		case 'k':
836c99fb5f9SBaptiste Daroussin 		case 'K':
837c99fb5f9SBaptiste Daroussin 			if (end - p >= 2) {
838c99fb5f9SBaptiste Daroussin 				if (p[1] == 's' || p[1] == 'S') {
839c99fb5f9SBaptiste Daroussin 					/* Milliseconds */
840c99fb5f9SBaptiste Daroussin 					if (!need_double) {
841c99fb5f9SBaptiste Daroussin 						need_double = true;
842c99fb5f9SBaptiste Daroussin 						dv = lv;
843c99fb5f9SBaptiste Daroussin 					}
84497bd480fSBaptiste Daroussin 					is_time = true;
845c99fb5f9SBaptiste Daroussin 					if (p[0] == 'm' || p[0] == 'M') {
846c99fb5f9SBaptiste Daroussin 						dv /= 1000.;
847c99fb5f9SBaptiste Daroussin 					}
848c99fb5f9SBaptiste Daroussin 					else {
849c99fb5f9SBaptiste Daroussin 						dv *= ucl_lex_num_multiplier (*p, false);
850c99fb5f9SBaptiste Daroussin 					}
851c99fb5f9SBaptiste Daroussin 					p += 2;
852c99fb5f9SBaptiste Daroussin 					goto set_obj;
853c99fb5f9SBaptiste Daroussin 				}
854c99fb5f9SBaptiste Daroussin 				else if (number_bytes || (p[1] == 'b' || p[1] == 'B')) {
855c99fb5f9SBaptiste Daroussin 					/* Bytes */
856c99fb5f9SBaptiste Daroussin 					if (need_double) {
857c99fb5f9SBaptiste Daroussin 						need_double = false;
858c99fb5f9SBaptiste Daroussin 						lv = dv;
859c99fb5f9SBaptiste Daroussin 					}
860c99fb5f9SBaptiste Daroussin 					lv *= ucl_lex_num_multiplier (*p, true);
861c99fb5f9SBaptiste Daroussin 					p += 2;
862c99fb5f9SBaptiste Daroussin 					goto set_obj;
863c99fb5f9SBaptiste Daroussin 				}
864c99fb5f9SBaptiste Daroussin 				else if (ucl_lex_is_atom_end (p[1])) {
865c99fb5f9SBaptiste Daroussin 					if (need_double) {
866c99fb5f9SBaptiste Daroussin 						dv *= ucl_lex_num_multiplier (*p, false);
867c99fb5f9SBaptiste Daroussin 					}
868c99fb5f9SBaptiste Daroussin 					else {
869c99fb5f9SBaptiste Daroussin 						lv *= ucl_lex_num_multiplier (*p, number_bytes);
870c99fb5f9SBaptiste Daroussin 					}
871c99fb5f9SBaptiste Daroussin 					p ++;
872c99fb5f9SBaptiste Daroussin 					goto set_obj;
873c99fb5f9SBaptiste Daroussin 				}
87497bd480fSBaptiste Daroussin 				else if (allow_time && end - p >= 3) {
875c99fb5f9SBaptiste Daroussin 					if (tolower (p[0]) == 'm' &&
876c99fb5f9SBaptiste Daroussin 							tolower (p[1]) == 'i' &&
877c99fb5f9SBaptiste Daroussin 							tolower (p[2]) == 'n') {
878c99fb5f9SBaptiste Daroussin 						/* Minutes */
879c99fb5f9SBaptiste Daroussin 						if (!need_double) {
880c99fb5f9SBaptiste Daroussin 							need_double = true;
881c99fb5f9SBaptiste Daroussin 							dv = lv;
882c99fb5f9SBaptiste Daroussin 						}
88397bd480fSBaptiste Daroussin 						is_time = true;
884c99fb5f9SBaptiste Daroussin 						dv *= 60.;
885c99fb5f9SBaptiste Daroussin 						p += 3;
886c99fb5f9SBaptiste Daroussin 						goto set_obj;
887c99fb5f9SBaptiste Daroussin 					}
888c99fb5f9SBaptiste Daroussin 				}
889c99fb5f9SBaptiste Daroussin 			}
890c99fb5f9SBaptiste Daroussin 			else {
891c99fb5f9SBaptiste Daroussin 				if (need_double) {
892c99fb5f9SBaptiste Daroussin 					dv *= ucl_lex_num_multiplier (*p, false);
893c99fb5f9SBaptiste Daroussin 				}
894c99fb5f9SBaptiste Daroussin 				else {
895c99fb5f9SBaptiste Daroussin 					lv *= ucl_lex_num_multiplier (*p, number_bytes);
896c99fb5f9SBaptiste Daroussin 				}
897c99fb5f9SBaptiste Daroussin 				p ++;
898c99fb5f9SBaptiste Daroussin 				goto set_obj;
899c99fb5f9SBaptiste Daroussin 			}
900c99fb5f9SBaptiste Daroussin 			break;
901c99fb5f9SBaptiste Daroussin 		case 'S':
902c99fb5f9SBaptiste Daroussin 		case 's':
90397bd480fSBaptiste Daroussin 			if (allow_time &&
90497bd480fSBaptiste Daroussin 					(p == end - 1 || ucl_lex_is_atom_end (p[1]))) {
905c99fb5f9SBaptiste Daroussin 				if (!need_double) {
906c99fb5f9SBaptiste Daroussin 					need_double = true;
907c99fb5f9SBaptiste Daroussin 					dv = lv;
908c99fb5f9SBaptiste Daroussin 				}
909c99fb5f9SBaptiste Daroussin 				p ++;
91097bd480fSBaptiste Daroussin 				is_time = true;
911c99fb5f9SBaptiste Daroussin 				goto set_obj;
912c99fb5f9SBaptiste Daroussin 			}
913c99fb5f9SBaptiste Daroussin 			break;
914c99fb5f9SBaptiste Daroussin 		case 'h':
915c99fb5f9SBaptiste Daroussin 		case 'H':
916c99fb5f9SBaptiste Daroussin 		case 'd':
917c99fb5f9SBaptiste Daroussin 		case 'D':
918c99fb5f9SBaptiste Daroussin 		case 'w':
919c99fb5f9SBaptiste Daroussin 		case 'W':
920c99fb5f9SBaptiste Daroussin 		case 'Y':
921c99fb5f9SBaptiste Daroussin 		case 'y':
92297bd480fSBaptiste Daroussin 			if (allow_time &&
92397bd480fSBaptiste Daroussin 					(p == end - 1 || ucl_lex_is_atom_end (p[1]))) {
924c99fb5f9SBaptiste Daroussin 				if (!need_double) {
925c99fb5f9SBaptiste Daroussin 					need_double = true;
926c99fb5f9SBaptiste Daroussin 					dv = lv;
927c99fb5f9SBaptiste Daroussin 				}
92897bd480fSBaptiste Daroussin 				is_time = true;
929c99fb5f9SBaptiste Daroussin 				dv *= ucl_lex_time_multiplier (*p);
930c99fb5f9SBaptiste Daroussin 				p ++;
931c99fb5f9SBaptiste Daroussin 				goto set_obj;
932c99fb5f9SBaptiste Daroussin 			}
933c99fb5f9SBaptiste Daroussin 			break;
9344bf54857SBaptiste Daroussin 		case '\t':
9354bf54857SBaptiste Daroussin 		case ' ':
9364bf54857SBaptiste Daroussin 			while (p < end && ucl_test_character(*p, UCL_CHARACTER_WHITESPACE)) {
9374bf54857SBaptiste Daroussin 				p++;
938c99fb5f9SBaptiste Daroussin 			}
9394bf54857SBaptiste Daroussin 			if (ucl_lex_is_atom_end(*p))
9404bf54857SBaptiste Daroussin 				goto set_obj;
9414bf54857SBaptiste Daroussin 			break;
9424bf54857SBaptiste Daroussin 		}
9434bf54857SBaptiste Daroussin 	}
9444bf54857SBaptiste Daroussin 	else if (endptr == end) {
9454bf54857SBaptiste Daroussin 		/* Just a number at the end of chunk */
9464bf54857SBaptiste Daroussin 		p = endptr;
9474bf54857SBaptiste Daroussin 		goto set_obj;
948c99fb5f9SBaptiste Daroussin 	}
949c99fb5f9SBaptiste Daroussin 
950c99fb5f9SBaptiste Daroussin 	*pos = c;
951c99fb5f9SBaptiste Daroussin 	return EINVAL;
952c99fb5f9SBaptiste Daroussin 
953c99fb5f9SBaptiste Daroussin set_obj:
95439ee7a7aSBaptiste Daroussin 	if (obj != NULL) {
95597bd480fSBaptiste Daroussin 		if (allow_double && (need_double || is_time)) {
95697bd480fSBaptiste Daroussin 			if (!is_time) {
957c99fb5f9SBaptiste Daroussin 				obj->type = UCL_FLOAT;
958c99fb5f9SBaptiste Daroussin 			}
959c99fb5f9SBaptiste Daroussin 			else {
960c99fb5f9SBaptiste Daroussin 				obj->type = UCL_TIME;
961c99fb5f9SBaptiste Daroussin 			}
962c99fb5f9SBaptiste Daroussin 			obj->value.dv = is_neg ? (-dv) : dv;
963c99fb5f9SBaptiste Daroussin 		}
964c99fb5f9SBaptiste Daroussin 		else {
965c99fb5f9SBaptiste Daroussin 			obj->type = UCL_INT;
966c99fb5f9SBaptiste Daroussin 			obj->value.iv = is_neg ? (-lv) : lv;
967c99fb5f9SBaptiste Daroussin 		}
96839ee7a7aSBaptiste Daroussin 	}
969c99fb5f9SBaptiste Daroussin 	*pos = p;
970c99fb5f9SBaptiste Daroussin 	return 0;
971c99fb5f9SBaptiste Daroussin }
972c99fb5f9SBaptiste Daroussin 
973c99fb5f9SBaptiste Daroussin /**
974c99fb5f9SBaptiste Daroussin  * Parse possible number
975c99fb5f9SBaptiste Daroussin  * @param parser
976c99fb5f9SBaptiste Daroussin  * @param chunk
97739ee7a7aSBaptiste Daroussin  * @param obj
978c99fb5f9SBaptiste Daroussin  * @return true if a number has been parsed
979c99fb5f9SBaptiste Daroussin  */
980c99fb5f9SBaptiste Daroussin static bool
ucl_lex_number(struct ucl_parser * parser,struct ucl_chunk * chunk,ucl_object_t * obj)981c99fb5f9SBaptiste Daroussin ucl_lex_number (struct ucl_parser *parser,
982c99fb5f9SBaptiste Daroussin 		struct ucl_chunk *chunk, ucl_object_t *obj)
983c99fb5f9SBaptiste Daroussin {
984c99fb5f9SBaptiste Daroussin 	const unsigned char *pos;
985c99fb5f9SBaptiste Daroussin 	int ret;
986c99fb5f9SBaptiste Daroussin 
98797bd480fSBaptiste Daroussin 	ret = ucl_maybe_parse_number (obj, chunk->pos, chunk->end, (const char **)&pos,
98897bd480fSBaptiste Daroussin 			true, false, ((parser->flags & UCL_PARSER_NO_TIME) == 0));
989c99fb5f9SBaptiste Daroussin 
990c99fb5f9SBaptiste Daroussin 	if (ret == 0) {
991c99fb5f9SBaptiste Daroussin 		chunk->remain -= pos - chunk->pos;
992c99fb5f9SBaptiste Daroussin 		chunk->column += pos - chunk->pos;
993c99fb5f9SBaptiste Daroussin 		chunk->pos = pos;
994c99fb5f9SBaptiste Daroussin 		return true;
995c99fb5f9SBaptiste Daroussin 	}
996c99fb5f9SBaptiste Daroussin 	else if (ret == ERANGE) {
99739ee7a7aSBaptiste Daroussin 		ucl_set_err (parser, UCL_ESYNTAX, "numeric value out of range",
99839ee7a7aSBaptiste Daroussin 				&parser->err);
999c99fb5f9SBaptiste Daroussin 	}
1000c99fb5f9SBaptiste Daroussin 
1001c99fb5f9SBaptiste Daroussin 	return false;
1002c99fb5f9SBaptiste Daroussin }
1003c99fb5f9SBaptiste Daroussin 
1004c99fb5f9SBaptiste Daroussin /**
1005c99fb5f9SBaptiste Daroussin  * Parse quoted string with possible escapes
1006c99fb5f9SBaptiste Daroussin  * @param parser
1007c99fb5f9SBaptiste Daroussin  * @param chunk
100839ee7a7aSBaptiste Daroussin  * @param need_unescape
100939ee7a7aSBaptiste Daroussin  * @param ucl_escape
101039ee7a7aSBaptiste Daroussin  * @param var_expand
1011c99fb5f9SBaptiste Daroussin  * @return true if a string has been parsed
1012c99fb5f9SBaptiste Daroussin  */
1013c99fb5f9SBaptiste Daroussin static bool
ucl_lex_json_string(struct ucl_parser * parser,struct ucl_chunk * chunk,bool * need_unescape,bool * ucl_escape,bool * var_expand)1014c99fb5f9SBaptiste Daroussin ucl_lex_json_string (struct ucl_parser *parser,
1015*a0409676SBaptiste Daroussin 		struct ucl_chunk *chunk,
1016*a0409676SBaptiste Daroussin 		bool *need_unescape,
1017*a0409676SBaptiste Daroussin 		bool *ucl_escape,
1018*a0409676SBaptiste Daroussin 		bool *var_expand)
1019c99fb5f9SBaptiste Daroussin {
1020c99fb5f9SBaptiste Daroussin 	const unsigned char *p = chunk->pos;
1021c99fb5f9SBaptiste Daroussin 	unsigned char c;
1022c99fb5f9SBaptiste Daroussin 	int i;
1023c99fb5f9SBaptiste Daroussin 
1024c99fb5f9SBaptiste Daroussin 	while (p < chunk->end) {
1025c99fb5f9SBaptiste Daroussin 		c = *p;
1026c99fb5f9SBaptiste Daroussin 		if (c < 0x1F) {
1027c99fb5f9SBaptiste Daroussin 			/* Unmasked control character */
1028c99fb5f9SBaptiste Daroussin 			if (c == '\n') {
10294bf54857SBaptiste Daroussin 				ucl_set_err (parser, UCL_ESYNTAX, "unexpected newline",
10304bf54857SBaptiste Daroussin 						&parser->err);
1031c99fb5f9SBaptiste Daroussin 			}
1032c99fb5f9SBaptiste Daroussin 			else {
10334bf54857SBaptiste Daroussin 				ucl_set_err (parser, UCL_ESYNTAX, "unexpected control character",
10344bf54857SBaptiste Daroussin 						&parser->err);
1035c99fb5f9SBaptiste Daroussin 			}
1036c99fb5f9SBaptiste Daroussin 			return false;
1037c99fb5f9SBaptiste Daroussin 		}
1038c99fb5f9SBaptiste Daroussin 		else if (c == '\\') {
1039c99fb5f9SBaptiste Daroussin 			ucl_chunk_skipc (chunk, p);
1040c99fb5f9SBaptiste Daroussin 			c = *p;
1041c99fb5f9SBaptiste Daroussin 			if (p >= chunk->end) {
10424bf54857SBaptiste Daroussin 				ucl_set_err (parser, UCL_ESYNTAX, "unfinished escape character",
10434bf54857SBaptiste Daroussin 						&parser->err);
1044c99fb5f9SBaptiste Daroussin 				return false;
1045c99fb5f9SBaptiste Daroussin 			}
1046c99fb5f9SBaptiste Daroussin 			else if (ucl_test_character (c, UCL_CHARACTER_ESCAPE)) {
1047c99fb5f9SBaptiste Daroussin 				if (c == 'u') {
1048c99fb5f9SBaptiste Daroussin 					ucl_chunk_skipc (chunk, p);
1049c99fb5f9SBaptiste Daroussin 					for (i = 0; i < 4 && p < chunk->end; i ++) {
1050c99fb5f9SBaptiste Daroussin 						if (!isxdigit (*p)) {
10514bf54857SBaptiste Daroussin 							ucl_set_err (parser, UCL_ESYNTAX, "invalid utf escape",
10524bf54857SBaptiste Daroussin 									&parser->err);
1053c99fb5f9SBaptiste Daroussin 							return false;
1054c99fb5f9SBaptiste Daroussin 						}
1055c99fb5f9SBaptiste Daroussin 						ucl_chunk_skipc (chunk, p);
1056c99fb5f9SBaptiste Daroussin 					}
1057c99fb5f9SBaptiste Daroussin 					if (p >= chunk->end) {
1058*a0409676SBaptiste Daroussin 						ucl_set_err (parser, UCL_ESYNTAX,
1059*a0409676SBaptiste Daroussin 								"unfinished escape character",
10604bf54857SBaptiste Daroussin 								&parser->err);
1061c99fb5f9SBaptiste Daroussin 						return false;
1062c99fb5f9SBaptiste Daroussin 					}
1063c99fb5f9SBaptiste Daroussin 				}
1064c99fb5f9SBaptiste Daroussin 				else {
1065c99fb5f9SBaptiste Daroussin 					ucl_chunk_skipc (chunk, p);
1066c99fb5f9SBaptiste Daroussin 				}
1067c99fb5f9SBaptiste Daroussin 			}
1068c99fb5f9SBaptiste Daroussin 			*need_unescape = true;
1069c99fb5f9SBaptiste Daroussin 			*ucl_escape = true;
1070c99fb5f9SBaptiste Daroussin 			continue;
1071c99fb5f9SBaptiste Daroussin 		}
1072c99fb5f9SBaptiste Daroussin 		else if (c == '"') {
1073c99fb5f9SBaptiste Daroussin 			ucl_chunk_skipc (chunk, p);
1074c99fb5f9SBaptiste Daroussin 			return true;
1075c99fb5f9SBaptiste Daroussin 		}
1076c99fb5f9SBaptiste Daroussin 		else if (ucl_test_character (c, UCL_CHARACTER_UCL_UNSAFE)) {
1077c99fb5f9SBaptiste Daroussin 			*ucl_escape = true;
1078c99fb5f9SBaptiste Daroussin 		}
1079c99fb5f9SBaptiste Daroussin 		else if (c == '$') {
1080c99fb5f9SBaptiste Daroussin 			*var_expand = true;
1081c99fb5f9SBaptiste Daroussin 		}
1082c99fb5f9SBaptiste Daroussin 		ucl_chunk_skipc (chunk, p);
1083c99fb5f9SBaptiste Daroussin 	}
1084c99fb5f9SBaptiste Daroussin 
1085*a0409676SBaptiste Daroussin 	ucl_set_err (parser, UCL_ESYNTAX,
1086*a0409676SBaptiste Daroussin 			"no quote at the end of json string",
1087*a0409676SBaptiste Daroussin 			&parser->err);
1088*a0409676SBaptiste Daroussin 	return false;
1089*a0409676SBaptiste Daroussin }
1090*a0409676SBaptiste Daroussin 
1091*a0409676SBaptiste Daroussin /**
1092*a0409676SBaptiste Daroussin  * Process single quoted string
1093*a0409676SBaptiste Daroussin  * @param parser
1094*a0409676SBaptiste Daroussin  * @param chunk
1095*a0409676SBaptiste Daroussin  * @param need_unescape
1096*a0409676SBaptiste Daroussin  * @return
1097*a0409676SBaptiste Daroussin  */
1098*a0409676SBaptiste Daroussin static bool
ucl_lex_squoted_string(struct ucl_parser * parser,struct ucl_chunk * chunk,bool * need_unescape)1099*a0409676SBaptiste Daroussin ucl_lex_squoted_string (struct ucl_parser *parser,
1100*a0409676SBaptiste Daroussin 		struct ucl_chunk *chunk, bool *need_unescape)
1101*a0409676SBaptiste Daroussin {
1102*a0409676SBaptiste Daroussin 	const unsigned char *p = chunk->pos;
1103*a0409676SBaptiste Daroussin 	unsigned char c;
1104*a0409676SBaptiste Daroussin 
1105*a0409676SBaptiste Daroussin 	while (p < chunk->end) {
1106*a0409676SBaptiste Daroussin 		c = *p;
1107*a0409676SBaptiste Daroussin 		if (c == '\\') {
1108*a0409676SBaptiste Daroussin 			ucl_chunk_skipc (chunk, p);
1109*a0409676SBaptiste Daroussin 
1110*a0409676SBaptiste Daroussin 			if (p >= chunk->end) {
1111*a0409676SBaptiste Daroussin 				ucl_set_err (parser, UCL_ESYNTAX,
1112*a0409676SBaptiste Daroussin 						"unfinished escape character",
1113*a0409676SBaptiste Daroussin 						&parser->err);
1114*a0409676SBaptiste Daroussin 				return false;
1115*a0409676SBaptiste Daroussin 			}
1116*a0409676SBaptiste Daroussin 			else {
1117*a0409676SBaptiste Daroussin 				ucl_chunk_skipc (chunk, p);
1118*a0409676SBaptiste Daroussin 			}
1119*a0409676SBaptiste Daroussin 
1120*a0409676SBaptiste Daroussin 			*need_unescape = true;
1121*a0409676SBaptiste Daroussin 			continue;
1122*a0409676SBaptiste Daroussin 		}
1123*a0409676SBaptiste Daroussin 		else if (c == '\'') {
1124*a0409676SBaptiste Daroussin 			ucl_chunk_skipc (chunk, p);
1125*a0409676SBaptiste Daroussin 			return true;
1126*a0409676SBaptiste Daroussin 		}
1127*a0409676SBaptiste Daroussin 
1128*a0409676SBaptiste Daroussin 		ucl_chunk_skipc (chunk, p);
1129*a0409676SBaptiste Daroussin 	}
1130*a0409676SBaptiste Daroussin 
1131*a0409676SBaptiste Daroussin 	ucl_set_err (parser, UCL_ESYNTAX,
1132*a0409676SBaptiste Daroussin 			"no quote at the end of single quoted string",
11334bf54857SBaptiste Daroussin 			&parser->err);
1134c99fb5f9SBaptiste Daroussin 	return false;
1135c99fb5f9SBaptiste Daroussin }
1136c99fb5f9SBaptiste Daroussin 
11374bf54857SBaptiste Daroussin static void
ucl_parser_append_elt(struct ucl_parser * parser,ucl_hash_t * cont,ucl_object_t * top,ucl_object_t * elt)11384bf54857SBaptiste Daroussin ucl_parser_append_elt (struct ucl_parser *parser, ucl_hash_t *cont,
11394bf54857SBaptiste Daroussin 		ucl_object_t *top,
11404bf54857SBaptiste Daroussin 		ucl_object_t *elt)
11414bf54857SBaptiste Daroussin {
11424bf54857SBaptiste Daroussin 	ucl_object_t *nobj;
11434bf54857SBaptiste Daroussin 
11444bf54857SBaptiste Daroussin 	if ((parser->flags & UCL_PARSER_NO_IMPLICIT_ARRAYS) == 0) {
11454bf54857SBaptiste Daroussin 		/* Implicit array */
11464bf54857SBaptiste Daroussin 		top->flags |= UCL_OBJECT_MULTIVALUE;
11474bf54857SBaptiste Daroussin 		DL_APPEND (top, elt);
114839ee7a7aSBaptiste Daroussin 		parser->stack->obj->len ++;
11494bf54857SBaptiste Daroussin 	}
11504bf54857SBaptiste Daroussin 	else {
11514bf54857SBaptiste Daroussin 		if ((top->flags & UCL_OBJECT_MULTIVALUE) != 0) {
11524bf54857SBaptiste Daroussin 			/* Just add to the explicit array */
11538e3b1ab2SBaptiste Daroussin 			ucl_array_append (top, elt);
11544bf54857SBaptiste Daroussin 		}
11554bf54857SBaptiste Daroussin 		else {
11564bf54857SBaptiste Daroussin 			/* Convert to an array */
11574bf54857SBaptiste Daroussin 			nobj = ucl_object_typed_new (UCL_ARRAY);
11584bf54857SBaptiste Daroussin 			nobj->key = top->key;
11594bf54857SBaptiste Daroussin 			nobj->keylen = top->keylen;
11604bf54857SBaptiste Daroussin 			nobj->flags |= UCL_OBJECT_MULTIVALUE;
11618e3b1ab2SBaptiste Daroussin 			ucl_array_append (nobj, top);
11628e3b1ab2SBaptiste Daroussin 			ucl_array_append (nobj, elt);
116339ee7a7aSBaptiste Daroussin 			ucl_hash_replace (cont, top, nobj);
11644bf54857SBaptiste Daroussin 		}
11654bf54857SBaptiste Daroussin 	}
11664bf54857SBaptiste Daroussin }
11674bf54857SBaptiste Daroussin 
116839ee7a7aSBaptiste Daroussin bool
ucl_parser_process_object_element(struct ucl_parser * parser,ucl_object_t * nobj)116939ee7a7aSBaptiste Daroussin ucl_parser_process_object_element (struct ucl_parser *parser, ucl_object_t *nobj)
117039ee7a7aSBaptiste Daroussin {
117139ee7a7aSBaptiste Daroussin 	ucl_hash_t *container;
1172*a0409676SBaptiste Daroussin 	ucl_object_t *tobj = NULL, *cur;
1173d9f0ce31SBaptiste Daroussin 	char errmsg[256];
117439ee7a7aSBaptiste Daroussin 
117539ee7a7aSBaptiste Daroussin 	container = parser->stack->obj->value.ov;
117639ee7a7aSBaptiste Daroussin 
1177*a0409676SBaptiste Daroussin 	DL_FOREACH (parser->stack->obj, cur) {
1178*a0409676SBaptiste Daroussin 		tobj = __DECONST (ucl_object_t *, ucl_hash_search_obj (cur->value.ov, nobj));
1179*a0409676SBaptiste Daroussin 
1180*a0409676SBaptiste Daroussin 		if (tobj != NULL) {
1181*a0409676SBaptiste Daroussin 			break;
1182*a0409676SBaptiste Daroussin 		}
1183*a0409676SBaptiste Daroussin 	}
1184*a0409676SBaptiste Daroussin 
1185*a0409676SBaptiste Daroussin 
118639ee7a7aSBaptiste Daroussin 	if (tobj == NULL) {
118739ee7a7aSBaptiste Daroussin 		container = ucl_hash_insert_object (container, nobj,
118839ee7a7aSBaptiste Daroussin 				parser->flags & UCL_PARSER_KEY_LOWERCASE);
1189*a0409676SBaptiste Daroussin 		if (container == NULL) {
1190*a0409676SBaptiste Daroussin 			return false;
1191*a0409676SBaptiste Daroussin 		}
119239ee7a7aSBaptiste Daroussin 		nobj->prev = nobj;
119339ee7a7aSBaptiste Daroussin 		nobj->next = NULL;
119439ee7a7aSBaptiste Daroussin 		parser->stack->obj->len ++;
119539ee7a7aSBaptiste Daroussin 	}
119639ee7a7aSBaptiste Daroussin 	else {
119739ee7a7aSBaptiste Daroussin 		unsigned priold = ucl_object_get_priority (tobj),
119839ee7a7aSBaptiste Daroussin 				prinew = ucl_object_get_priority (nobj);
119939ee7a7aSBaptiste Daroussin 		switch (parser->chunks->strategy) {
120039ee7a7aSBaptiste Daroussin 
120139ee7a7aSBaptiste Daroussin 		case UCL_DUPLICATE_APPEND:
120239ee7a7aSBaptiste Daroussin 			/*
120339ee7a7aSBaptiste Daroussin 			 * The logic here is the following:
120439ee7a7aSBaptiste Daroussin 			 *
120539ee7a7aSBaptiste Daroussin 			 * - if we have two objects with the same priority, then we form an
120639ee7a7aSBaptiste Daroussin 			 * implicit or explicit array
120739ee7a7aSBaptiste Daroussin 			 * - if a new object has bigger priority, then we overwrite an old one
120839ee7a7aSBaptiste Daroussin 			 * - if a new object has lower priority, then we ignore it
120939ee7a7aSBaptiste Daroussin 			 */
121039ee7a7aSBaptiste Daroussin 			/* Special case for inherited objects */
121139ee7a7aSBaptiste Daroussin 			if (tobj->flags & UCL_OBJECT_INHERITED) {
121239ee7a7aSBaptiste Daroussin 				prinew = priold + 1;
121339ee7a7aSBaptiste Daroussin 			}
121439ee7a7aSBaptiste Daroussin 
121539ee7a7aSBaptiste Daroussin 			if (priold == prinew) {
121639ee7a7aSBaptiste Daroussin 				ucl_parser_append_elt (parser, container, tobj, nobj);
121739ee7a7aSBaptiste Daroussin 			}
121839ee7a7aSBaptiste Daroussin 			else if (priold > prinew) {
121939ee7a7aSBaptiste Daroussin 				/*
122039ee7a7aSBaptiste Daroussin 				 * We add this new object to a list of trash objects just to ensure
122139ee7a7aSBaptiste Daroussin 				 * that it won't come to any real object
122239ee7a7aSBaptiste Daroussin 				 * XXX: rather inefficient approach
122339ee7a7aSBaptiste Daroussin 				 */
122439ee7a7aSBaptiste Daroussin 				DL_APPEND (parser->trash_objs, nobj);
122539ee7a7aSBaptiste Daroussin 			}
122639ee7a7aSBaptiste Daroussin 			else {
122739ee7a7aSBaptiste Daroussin 				ucl_hash_replace (container, tobj, nobj);
122839ee7a7aSBaptiste Daroussin 				ucl_object_unref (tobj);
122939ee7a7aSBaptiste Daroussin 			}
123039ee7a7aSBaptiste Daroussin 
123139ee7a7aSBaptiste Daroussin 			break;
123239ee7a7aSBaptiste Daroussin 
123339ee7a7aSBaptiste Daroussin 		case UCL_DUPLICATE_REWRITE:
123439ee7a7aSBaptiste Daroussin 			/* We just rewrite old values regardless of priority */
123539ee7a7aSBaptiste Daroussin 			ucl_hash_replace (container, tobj, nobj);
123639ee7a7aSBaptiste Daroussin 			ucl_object_unref (tobj);
123739ee7a7aSBaptiste Daroussin 
123839ee7a7aSBaptiste Daroussin 			break;
123939ee7a7aSBaptiste Daroussin 
124039ee7a7aSBaptiste Daroussin 		case UCL_DUPLICATE_ERROR:
1241d9f0ce31SBaptiste Daroussin 			snprintf(errmsg, sizeof(errmsg),
1242d9f0ce31SBaptiste Daroussin 					"duplicate element for key '%s' found",
1243d9f0ce31SBaptiste Daroussin 					nobj->key);
1244d9f0ce31SBaptiste Daroussin 			ucl_set_err (parser, UCL_EMERGE, errmsg, &parser->err);
124539ee7a7aSBaptiste Daroussin 			return false;
124639ee7a7aSBaptiste Daroussin 
124739ee7a7aSBaptiste Daroussin 		case UCL_DUPLICATE_MERGE:
124839ee7a7aSBaptiste Daroussin 			/*
124939ee7a7aSBaptiste Daroussin 			 * Here we do have some old object so we just push it on top of objects stack
1250d9f0ce31SBaptiste Daroussin 			 * Check priority and then perform the merge on the remaining objects
125139ee7a7aSBaptiste Daroussin 			 */
125239ee7a7aSBaptiste Daroussin 			if (tobj->type == UCL_OBJECT || tobj->type == UCL_ARRAY) {
125339ee7a7aSBaptiste Daroussin 				ucl_object_unref (nobj);
125439ee7a7aSBaptiste Daroussin 				nobj = tobj;
125539ee7a7aSBaptiste Daroussin 			}
1256d9f0ce31SBaptiste Daroussin 			else if (priold == prinew) {
125739ee7a7aSBaptiste Daroussin 				ucl_parser_append_elt (parser, container, tobj, nobj);
125839ee7a7aSBaptiste Daroussin 			}
1259d9f0ce31SBaptiste Daroussin 			else if (priold > prinew) {
1260d9f0ce31SBaptiste Daroussin 				/*
1261d9f0ce31SBaptiste Daroussin 				 * We add this new object to a list of trash objects just to ensure
1262d9f0ce31SBaptiste Daroussin 				 * that it won't come to any real object
1263d9f0ce31SBaptiste Daroussin 				 * XXX: rather inefficient approach
1264d9f0ce31SBaptiste Daroussin 				 */
1265d9f0ce31SBaptiste Daroussin 				DL_APPEND (parser->trash_objs, nobj);
1266d9f0ce31SBaptiste Daroussin 			}
1267d9f0ce31SBaptiste Daroussin 			else {
1268d9f0ce31SBaptiste Daroussin 				ucl_hash_replace (container, tobj, nobj);
1269d9f0ce31SBaptiste Daroussin 				ucl_object_unref (tobj);
1270d9f0ce31SBaptiste Daroussin 			}
127139ee7a7aSBaptiste Daroussin 			break;
127239ee7a7aSBaptiste Daroussin 		}
127339ee7a7aSBaptiste Daroussin 	}
127439ee7a7aSBaptiste Daroussin 
127539ee7a7aSBaptiste Daroussin 	parser->stack->obj->value.ov = container;
127639ee7a7aSBaptiste Daroussin 	parser->cur_obj = nobj;
1277d9f0ce31SBaptiste Daroussin 	ucl_attach_comment (parser, nobj, false);
127839ee7a7aSBaptiste Daroussin 
127939ee7a7aSBaptiste Daroussin 	return true;
128039ee7a7aSBaptiste Daroussin }
128139ee7a7aSBaptiste Daroussin 
1282c99fb5f9SBaptiste Daroussin /**
1283c99fb5f9SBaptiste Daroussin  * Parse a key in an object
1284c99fb5f9SBaptiste Daroussin  * @param parser
1285c99fb5f9SBaptiste Daroussin  * @param chunk
128639ee7a7aSBaptiste Daroussin  * @param next_key
128739ee7a7aSBaptiste Daroussin  * @param end_of_object
1288c99fb5f9SBaptiste Daroussin  * @return true if a key has been parsed
1289c99fb5f9SBaptiste Daroussin  */
1290c99fb5f9SBaptiste Daroussin static bool
ucl_parse_key(struct ucl_parser * parser,struct ucl_chunk * chunk,bool * next_key,bool * end_of_object)129139ee7a7aSBaptiste Daroussin ucl_parse_key (struct ucl_parser *parser, struct ucl_chunk *chunk,
129239ee7a7aSBaptiste Daroussin 		bool *next_key, bool *end_of_object)
1293c99fb5f9SBaptiste Daroussin {
1294c99fb5f9SBaptiste Daroussin 	const unsigned char *p, *c = NULL, *end, *t;
1295c99fb5f9SBaptiste Daroussin 	const char *key = NULL;
1296c99fb5f9SBaptiste Daroussin 	bool got_quote = false, got_eq = false, got_semicolon = false,
1297c99fb5f9SBaptiste Daroussin 			need_unescape = false, ucl_escape = false, var_expand = false,
1298c99fb5f9SBaptiste Daroussin 			got_content = false, got_sep = false;
129939ee7a7aSBaptiste Daroussin 	ucl_object_t *nobj;
1300c99fb5f9SBaptiste Daroussin 	ssize_t keylen;
1301c99fb5f9SBaptiste Daroussin 
1302c99fb5f9SBaptiste Daroussin 	p = chunk->pos;
1303c99fb5f9SBaptiste Daroussin 
1304c99fb5f9SBaptiste Daroussin 	if (*p == '.') {
1305c99fb5f9SBaptiste Daroussin 		/* It is macro actually */
1306d9f0ce31SBaptiste Daroussin 		if (!(parser->flags & UCL_PARSER_DISABLE_MACRO)) {
1307c99fb5f9SBaptiste Daroussin 			ucl_chunk_skipc (chunk, p);
1308d9f0ce31SBaptiste Daroussin 		}
1309d9f0ce31SBaptiste Daroussin 
1310c99fb5f9SBaptiste Daroussin 		parser->prev_state = parser->state;
1311c99fb5f9SBaptiste Daroussin 		parser->state = UCL_STATE_MACRO_NAME;
13128e3b1ab2SBaptiste Daroussin 		*end_of_object = false;
1313c99fb5f9SBaptiste Daroussin 		return true;
1314c99fb5f9SBaptiste Daroussin 	}
1315c99fb5f9SBaptiste Daroussin 	while (p < chunk->end) {
1316c99fb5f9SBaptiste Daroussin 		/*
1317c99fb5f9SBaptiste Daroussin 		 * A key must start with alpha, number, '/' or '_' and end with space character
1318c99fb5f9SBaptiste Daroussin 		 */
1319c99fb5f9SBaptiste Daroussin 		if (c == NULL) {
1320c99fb5f9SBaptiste Daroussin 			if (chunk->remain >= 2 && ucl_lex_is_comment (p[0], p[1])) {
1321c99fb5f9SBaptiste Daroussin 				if (!ucl_skip_comments (parser)) {
1322c99fb5f9SBaptiste Daroussin 					return false;
1323c99fb5f9SBaptiste Daroussin 				}
1324c99fb5f9SBaptiste Daroussin 				p = chunk->pos;
1325c99fb5f9SBaptiste Daroussin 			}
1326c99fb5f9SBaptiste Daroussin 			else if (ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE)) {
1327c99fb5f9SBaptiste Daroussin 				ucl_chunk_skipc (chunk, p);
1328c99fb5f9SBaptiste Daroussin 			}
1329c99fb5f9SBaptiste Daroussin 			else if (ucl_test_character (*p, UCL_CHARACTER_KEY_START)) {
1330c99fb5f9SBaptiste Daroussin 				/* The first symbol */
1331c99fb5f9SBaptiste Daroussin 				c = p;
1332c99fb5f9SBaptiste Daroussin 				ucl_chunk_skipc (chunk, p);
1333c99fb5f9SBaptiste Daroussin 				got_content = true;
1334c99fb5f9SBaptiste Daroussin 			}
1335c99fb5f9SBaptiste Daroussin 			else if (*p == '"') {
1336c99fb5f9SBaptiste Daroussin 				/* JSON style key */
1337c99fb5f9SBaptiste Daroussin 				c = p + 1;
1338c99fb5f9SBaptiste Daroussin 				got_quote = true;
1339c99fb5f9SBaptiste Daroussin 				got_content = true;
1340c99fb5f9SBaptiste Daroussin 				ucl_chunk_skipc (chunk, p);
1341c99fb5f9SBaptiste Daroussin 			}
1342c99fb5f9SBaptiste Daroussin 			else if (*p == '}') {
1343c99fb5f9SBaptiste Daroussin 				/* We have actually end of an object */
1344c99fb5f9SBaptiste Daroussin 				*end_of_object = true;
1345c99fb5f9SBaptiste Daroussin 				return true;
1346c99fb5f9SBaptiste Daroussin 			}
1347c99fb5f9SBaptiste Daroussin 			else if (*p == '.') {
1348c99fb5f9SBaptiste Daroussin 				ucl_chunk_skipc (chunk, p);
1349c99fb5f9SBaptiste Daroussin 				parser->prev_state = parser->state;
1350c99fb5f9SBaptiste Daroussin 				parser->state = UCL_STATE_MACRO_NAME;
1351c99fb5f9SBaptiste Daroussin 				return true;
1352c99fb5f9SBaptiste Daroussin 			}
1353c99fb5f9SBaptiste Daroussin 			else {
1354c99fb5f9SBaptiste Daroussin 				/* Invalid identifier */
13554bf54857SBaptiste Daroussin 				ucl_set_err (parser, UCL_ESYNTAX, "key must begin with a letter",
13564bf54857SBaptiste Daroussin 						&parser->err);
1357c99fb5f9SBaptiste Daroussin 				return false;
1358c99fb5f9SBaptiste Daroussin 			}
1359c99fb5f9SBaptiste Daroussin 		}
1360c99fb5f9SBaptiste Daroussin 		else {
1361c99fb5f9SBaptiste Daroussin 			/* Parse the body of a key */
1362c99fb5f9SBaptiste Daroussin 			if (!got_quote) {
1363c99fb5f9SBaptiste Daroussin 				if (ucl_test_character (*p, UCL_CHARACTER_KEY)) {
1364c99fb5f9SBaptiste Daroussin 					got_content = true;
1365c99fb5f9SBaptiste Daroussin 					ucl_chunk_skipc (chunk, p);
1366c99fb5f9SBaptiste Daroussin 				}
1367c99fb5f9SBaptiste Daroussin 				else if (ucl_test_character (*p, UCL_CHARACTER_KEY_SEP)) {
1368c99fb5f9SBaptiste Daroussin 					end = p;
1369c99fb5f9SBaptiste Daroussin 					break;
1370c99fb5f9SBaptiste Daroussin 				}
1371c99fb5f9SBaptiste Daroussin 				else {
13724bf54857SBaptiste Daroussin 					ucl_set_err (parser, UCL_ESYNTAX, "invalid character in a key",
13734bf54857SBaptiste Daroussin 							&parser->err);
1374c99fb5f9SBaptiste Daroussin 					return false;
1375c99fb5f9SBaptiste Daroussin 				}
1376c99fb5f9SBaptiste Daroussin 			}
1377c99fb5f9SBaptiste Daroussin 			else {
1378c99fb5f9SBaptiste Daroussin 				/* We need to parse json like quoted string */
1379c99fb5f9SBaptiste Daroussin 				if (!ucl_lex_json_string (parser, chunk, &need_unescape, &ucl_escape, &var_expand)) {
1380c99fb5f9SBaptiste Daroussin 					return false;
1381c99fb5f9SBaptiste Daroussin 				}
1382c99fb5f9SBaptiste Daroussin 				/* Always escape keys obtained via json */
1383c99fb5f9SBaptiste Daroussin 				end = chunk->pos - 1;
1384c99fb5f9SBaptiste Daroussin 				p = chunk->pos;
1385c99fb5f9SBaptiste Daroussin 				break;
1386c99fb5f9SBaptiste Daroussin 			}
1387c99fb5f9SBaptiste Daroussin 		}
1388c99fb5f9SBaptiste Daroussin 	}
1389c99fb5f9SBaptiste Daroussin 
1390c99fb5f9SBaptiste Daroussin 	if (p >= chunk->end && got_content) {
13914bf54857SBaptiste Daroussin 		ucl_set_err (parser, UCL_ESYNTAX, "unfinished key", &parser->err);
1392c99fb5f9SBaptiste Daroussin 		return false;
1393c99fb5f9SBaptiste Daroussin 	}
1394c99fb5f9SBaptiste Daroussin 	else if (!got_content) {
1395c99fb5f9SBaptiste Daroussin 		return true;
1396c99fb5f9SBaptiste Daroussin 	}
1397c99fb5f9SBaptiste Daroussin 	*end_of_object = false;
1398c99fb5f9SBaptiste Daroussin 	/* We are now at the end of the key, need to parse the rest */
1399c99fb5f9SBaptiste Daroussin 	while (p < chunk->end) {
1400c99fb5f9SBaptiste Daroussin 		if (ucl_test_character (*p, UCL_CHARACTER_WHITESPACE)) {
1401c99fb5f9SBaptiste Daroussin 			ucl_chunk_skipc (chunk, p);
1402c99fb5f9SBaptiste Daroussin 		}
1403c99fb5f9SBaptiste Daroussin 		else if (*p == '=') {
1404c99fb5f9SBaptiste Daroussin 			if (!got_eq && !got_semicolon) {
1405c99fb5f9SBaptiste Daroussin 				ucl_chunk_skipc (chunk, p);
1406c99fb5f9SBaptiste Daroussin 				got_eq = true;
1407c99fb5f9SBaptiste Daroussin 			}
1408c99fb5f9SBaptiste Daroussin 			else {
14094bf54857SBaptiste Daroussin 				ucl_set_err (parser, UCL_ESYNTAX, "unexpected '=' character",
14104bf54857SBaptiste Daroussin 						&parser->err);
1411c99fb5f9SBaptiste Daroussin 				return false;
1412c99fb5f9SBaptiste Daroussin 			}
1413c99fb5f9SBaptiste Daroussin 		}
1414c99fb5f9SBaptiste Daroussin 		else if (*p == ':') {
1415c99fb5f9SBaptiste Daroussin 			if (!got_eq && !got_semicolon) {
1416c99fb5f9SBaptiste Daroussin 				ucl_chunk_skipc (chunk, p);
1417c99fb5f9SBaptiste Daroussin 				got_semicolon = true;
1418c99fb5f9SBaptiste Daroussin 			}
1419c99fb5f9SBaptiste Daroussin 			else {
14204bf54857SBaptiste Daroussin 				ucl_set_err (parser, UCL_ESYNTAX, "unexpected ':' character",
14214bf54857SBaptiste Daroussin 						&parser->err);
1422c99fb5f9SBaptiste Daroussin 				return false;
1423c99fb5f9SBaptiste Daroussin 			}
1424c99fb5f9SBaptiste Daroussin 		}
1425c99fb5f9SBaptiste Daroussin 		else if (chunk->remain >= 2 && ucl_lex_is_comment (p[0], p[1])) {
1426c99fb5f9SBaptiste Daroussin 			/* Check for comment */
1427c99fb5f9SBaptiste Daroussin 			if (!ucl_skip_comments (parser)) {
1428c99fb5f9SBaptiste Daroussin 				return false;
1429c99fb5f9SBaptiste Daroussin 			}
1430c99fb5f9SBaptiste Daroussin 			p = chunk->pos;
1431c99fb5f9SBaptiste Daroussin 		}
1432c99fb5f9SBaptiste Daroussin 		else {
1433c99fb5f9SBaptiste Daroussin 			/* Start value */
1434c99fb5f9SBaptiste Daroussin 			break;
1435c99fb5f9SBaptiste Daroussin 		}
1436c99fb5f9SBaptiste Daroussin 	}
1437c99fb5f9SBaptiste Daroussin 
1438c99fb5f9SBaptiste Daroussin 	if (p >= chunk->end && got_content) {
14394bf54857SBaptiste Daroussin 		ucl_set_err (parser, UCL_ESYNTAX, "unfinished key", &parser->err);
1440c99fb5f9SBaptiste Daroussin 		return false;
1441c99fb5f9SBaptiste Daroussin 	}
1442c99fb5f9SBaptiste Daroussin 
1443c99fb5f9SBaptiste Daroussin 	got_sep = got_semicolon || got_eq;
1444c99fb5f9SBaptiste Daroussin 
1445c99fb5f9SBaptiste Daroussin 	if (!got_sep) {
1446c99fb5f9SBaptiste Daroussin 		/*
1447c99fb5f9SBaptiste Daroussin 		 * Maybe we have more keys nested, so search for termination character.
1448c99fb5f9SBaptiste Daroussin 		 * Possible choices:
1449c99fb5f9SBaptiste Daroussin 		 * 1) key1 key2 ... keyN [:=] value <- we treat that as error
1450c99fb5f9SBaptiste Daroussin 		 * 2) key1 ... keyN {} or [] <- we treat that as nested objects
1451c99fb5f9SBaptiste Daroussin 		 * 3) key1 value[;,\n] <- we treat that as linear object
1452c99fb5f9SBaptiste Daroussin 		 */
1453c99fb5f9SBaptiste Daroussin 		t = p;
1454c99fb5f9SBaptiste Daroussin 		*next_key = false;
1455c99fb5f9SBaptiste Daroussin 		while (ucl_test_character (*t, UCL_CHARACTER_WHITESPACE)) {
1456c99fb5f9SBaptiste Daroussin 			t ++;
1457c99fb5f9SBaptiste Daroussin 		}
1458c99fb5f9SBaptiste Daroussin 		/* Check first non-space character after a key */
1459c99fb5f9SBaptiste Daroussin 		if (*t != '{' && *t != '[') {
1460c99fb5f9SBaptiste Daroussin 			while (t < chunk->end) {
1461c99fb5f9SBaptiste Daroussin 				if (*t == ',' || *t == ';' || *t == '\n' || *t == '\r') {
1462c99fb5f9SBaptiste Daroussin 					break;
1463c99fb5f9SBaptiste Daroussin 				}
1464c99fb5f9SBaptiste Daroussin 				else if (*t == '{' || *t == '[') {
1465c99fb5f9SBaptiste Daroussin 					*next_key = true;
1466c99fb5f9SBaptiste Daroussin 					break;
1467c99fb5f9SBaptiste Daroussin 				}
1468c99fb5f9SBaptiste Daroussin 				t ++;
1469c99fb5f9SBaptiste Daroussin 			}
1470c99fb5f9SBaptiste Daroussin 		}
1471c99fb5f9SBaptiste Daroussin 	}
1472c99fb5f9SBaptiste Daroussin 
1473c99fb5f9SBaptiste Daroussin 	/* Create a new object */
14744bf54857SBaptiste Daroussin 	nobj = ucl_object_new_full (UCL_NULL, parser->chunks->priority);
1475*a0409676SBaptiste Daroussin 	if (nobj == NULL) {
1476*a0409676SBaptiste Daroussin 		return false;
1477*a0409676SBaptiste Daroussin 	}
1478c99fb5f9SBaptiste Daroussin 	keylen = ucl_copy_or_store_ptr (parser, c, &nobj->trash_stack[UCL_TRASH_KEY],
1479*a0409676SBaptiste Daroussin 			&key, end - c, need_unescape, parser->flags & UCL_PARSER_KEY_LOWERCASE,
1480*a0409676SBaptiste Daroussin 			false, false);
1481c99fb5f9SBaptiste Daroussin 	if (keylen == -1) {
1482b04a7a0bSBaptiste Daroussin 		ucl_object_unref (nobj);
1483c99fb5f9SBaptiste Daroussin 		return false;
1484c99fb5f9SBaptiste Daroussin 	}
1485c99fb5f9SBaptiste Daroussin 	else if (keylen == 0) {
14864bf54857SBaptiste Daroussin 		ucl_set_err (parser, UCL_ESYNTAX, "empty keys are not allowed", &parser->err);
1487b04a7a0bSBaptiste Daroussin 		ucl_object_unref (nobj);
1488c99fb5f9SBaptiste Daroussin 		return false;
1489c99fb5f9SBaptiste Daroussin 	}
1490c99fb5f9SBaptiste Daroussin 
1491c99fb5f9SBaptiste Daroussin 	nobj->key = key;
1492c99fb5f9SBaptiste Daroussin 	nobj->keylen = keylen;
149339ee7a7aSBaptiste Daroussin 
149439ee7a7aSBaptiste Daroussin 	if (!ucl_parser_process_object_element (parser, nobj)) {
149539ee7a7aSBaptiste Daroussin 		return false;
1496c99fb5f9SBaptiste Daroussin 	}
1497c99fb5f9SBaptiste Daroussin 
1498c99fb5f9SBaptiste Daroussin 	if (ucl_escape) {
1499c99fb5f9SBaptiste Daroussin 		nobj->flags |= UCL_OBJECT_NEED_KEY_ESCAPE;
1500c99fb5f9SBaptiste Daroussin 	}
1501c99fb5f9SBaptiste Daroussin 
1502c99fb5f9SBaptiste Daroussin 
1503c99fb5f9SBaptiste Daroussin 	return true;
1504c99fb5f9SBaptiste Daroussin }
1505c99fb5f9SBaptiste Daroussin 
1506c99fb5f9SBaptiste Daroussin /**
1507c99fb5f9SBaptiste Daroussin  * Parse a cl string
1508c99fb5f9SBaptiste Daroussin  * @param parser
1509c99fb5f9SBaptiste Daroussin  * @param chunk
151039ee7a7aSBaptiste Daroussin  * @param var_expand
151139ee7a7aSBaptiste Daroussin  * @param need_unescape
1512c99fb5f9SBaptiste Daroussin  * @return true if a key has been parsed
1513c99fb5f9SBaptiste Daroussin  */
1514c99fb5f9SBaptiste Daroussin static bool
ucl_parse_string_value(struct ucl_parser * parser,struct ucl_chunk * chunk,bool * var_expand,bool * need_unescape)1515c99fb5f9SBaptiste Daroussin ucl_parse_string_value (struct ucl_parser *parser,
1516c99fb5f9SBaptiste Daroussin 		struct ucl_chunk *chunk, bool *var_expand, bool *need_unescape)
1517c99fb5f9SBaptiste Daroussin {
1518c99fb5f9SBaptiste Daroussin 	const unsigned char *p;
1519c99fb5f9SBaptiste Daroussin 	enum {
1520c99fb5f9SBaptiste Daroussin 		UCL_BRACE_ROUND = 0,
1521c99fb5f9SBaptiste Daroussin 		UCL_BRACE_SQUARE,
1522c99fb5f9SBaptiste Daroussin 		UCL_BRACE_FIGURE
1523c99fb5f9SBaptiste Daroussin 	};
1524c99fb5f9SBaptiste Daroussin 	int braces[3][2] = {{0, 0}, {0, 0}, {0, 0}};
1525c99fb5f9SBaptiste Daroussin 
1526c99fb5f9SBaptiste Daroussin 	p = chunk->pos;
1527c99fb5f9SBaptiste Daroussin 
1528c99fb5f9SBaptiste Daroussin 	while (p < chunk->end) {
1529c99fb5f9SBaptiste Daroussin 
1530c99fb5f9SBaptiste Daroussin 		/* Skip pairs of figure braces */
1531c99fb5f9SBaptiste Daroussin 		if (*p == '{') {
1532c99fb5f9SBaptiste Daroussin 			braces[UCL_BRACE_FIGURE][0] ++;
1533c99fb5f9SBaptiste Daroussin 		}
1534c99fb5f9SBaptiste Daroussin 		else if (*p == '}') {
1535c99fb5f9SBaptiste Daroussin 			braces[UCL_BRACE_FIGURE][1] ++;
1536c99fb5f9SBaptiste Daroussin 			if (braces[UCL_BRACE_FIGURE][1] <= braces[UCL_BRACE_FIGURE][0]) {
1537c99fb5f9SBaptiste Daroussin 				/* This is not a termination symbol, continue */
1538c99fb5f9SBaptiste Daroussin 				ucl_chunk_skipc (chunk, p);
1539c99fb5f9SBaptiste Daroussin 				continue;
1540c99fb5f9SBaptiste Daroussin 			}
1541c99fb5f9SBaptiste Daroussin 		}
1542c99fb5f9SBaptiste Daroussin 		/* Skip pairs of square braces */
1543c99fb5f9SBaptiste Daroussin 		else if (*p == '[') {
1544c99fb5f9SBaptiste Daroussin 			braces[UCL_BRACE_SQUARE][0] ++;
1545c99fb5f9SBaptiste Daroussin 		}
1546c99fb5f9SBaptiste Daroussin 		else if (*p == ']') {
1547c99fb5f9SBaptiste Daroussin 			braces[UCL_BRACE_SQUARE][1] ++;
1548c99fb5f9SBaptiste Daroussin 			if (braces[UCL_BRACE_SQUARE][1] <= braces[UCL_BRACE_SQUARE][0]) {
1549c99fb5f9SBaptiste Daroussin 				/* This is not a termination symbol, continue */
1550c99fb5f9SBaptiste Daroussin 				ucl_chunk_skipc (chunk, p);
1551c99fb5f9SBaptiste Daroussin 				continue;
1552c99fb5f9SBaptiste Daroussin 			}
1553c99fb5f9SBaptiste Daroussin 		}
1554c99fb5f9SBaptiste Daroussin 		else if (*p == '$') {
1555c99fb5f9SBaptiste Daroussin 			*var_expand = true;
1556c99fb5f9SBaptiste Daroussin 		}
1557c99fb5f9SBaptiste Daroussin 		else if (*p == '\\') {
1558c99fb5f9SBaptiste Daroussin 			*need_unescape = true;
1559c99fb5f9SBaptiste Daroussin 			ucl_chunk_skipc (chunk, p);
1560c99fb5f9SBaptiste Daroussin 			if (p < chunk->end) {
1561c99fb5f9SBaptiste Daroussin 				ucl_chunk_skipc (chunk, p);
1562c99fb5f9SBaptiste Daroussin 			}
1563c99fb5f9SBaptiste Daroussin 			continue;
1564c99fb5f9SBaptiste Daroussin 		}
1565c99fb5f9SBaptiste Daroussin 
1566c99fb5f9SBaptiste Daroussin 		if (ucl_lex_is_atom_end (*p) || (chunk->remain >= 2 && ucl_lex_is_comment (p[0], p[1]))) {
1567c99fb5f9SBaptiste Daroussin 			break;
1568c99fb5f9SBaptiste Daroussin 		}
1569c99fb5f9SBaptiste Daroussin 		ucl_chunk_skipc (chunk, p);
1570c99fb5f9SBaptiste Daroussin 	}
1571c99fb5f9SBaptiste Daroussin 
1572c99fb5f9SBaptiste Daroussin 	return true;
1573c99fb5f9SBaptiste Daroussin }
1574c99fb5f9SBaptiste Daroussin 
1575c99fb5f9SBaptiste Daroussin /**
1576c99fb5f9SBaptiste Daroussin  * Parse multiline string ending with \n{term}\n
1577c99fb5f9SBaptiste Daroussin  * @param parser
1578c99fb5f9SBaptiste Daroussin  * @param chunk
1579c99fb5f9SBaptiste Daroussin  * @param term
1580c99fb5f9SBaptiste Daroussin  * @param term_len
158139ee7a7aSBaptiste Daroussin  * @param beg
158239ee7a7aSBaptiste Daroussin  * @param var_expand
1583c99fb5f9SBaptiste Daroussin  * @return size of multiline string or 0 in case of error
1584c99fb5f9SBaptiste Daroussin  */
1585c99fb5f9SBaptiste Daroussin static int
ucl_parse_multiline_string(struct ucl_parser * parser,struct ucl_chunk * chunk,const unsigned char * term,int term_len,unsigned char const ** beg,bool * var_expand)1586c99fb5f9SBaptiste Daroussin ucl_parse_multiline_string (struct ucl_parser *parser,
1587c99fb5f9SBaptiste Daroussin 		struct ucl_chunk *chunk, const unsigned char *term,
1588c99fb5f9SBaptiste Daroussin 		int term_len, unsigned char const **beg,
1589c99fb5f9SBaptiste Daroussin 		bool *var_expand)
1590c99fb5f9SBaptiste Daroussin {
15914bf54857SBaptiste Daroussin 	const unsigned char *p, *c, *tend;
1592c99fb5f9SBaptiste Daroussin 	bool newline = false;
1593c99fb5f9SBaptiste Daroussin 	int len = 0;
1594c99fb5f9SBaptiste Daroussin 
1595c99fb5f9SBaptiste Daroussin 	p = chunk->pos;
1596c99fb5f9SBaptiste Daroussin 
1597c99fb5f9SBaptiste Daroussin 	c = p;
1598c99fb5f9SBaptiste Daroussin 
1599c99fb5f9SBaptiste Daroussin 	while (p < chunk->end) {
1600c99fb5f9SBaptiste Daroussin 		if (newline) {
1601c99fb5f9SBaptiste Daroussin 			if (chunk->end - p < term_len) {
1602c99fb5f9SBaptiste Daroussin 				return 0;
1603c99fb5f9SBaptiste Daroussin 			}
16044bf54857SBaptiste Daroussin 			else if (memcmp (p, term, term_len) == 0) {
16054bf54857SBaptiste Daroussin 				tend = p + term_len;
16064bf54857SBaptiste Daroussin 				if (*tend != '\n' && *tend != ';' && *tend != ',') {
16074bf54857SBaptiste Daroussin 					/* Incomplete terminator */
16084bf54857SBaptiste Daroussin 					ucl_chunk_skipc (chunk, p);
16094bf54857SBaptiste Daroussin 					continue;
16104bf54857SBaptiste Daroussin 				}
1611c99fb5f9SBaptiste Daroussin 				len = p - c;
1612c99fb5f9SBaptiste Daroussin 				chunk->remain -= term_len;
1613c99fb5f9SBaptiste Daroussin 				chunk->pos = p + term_len;
1614c99fb5f9SBaptiste Daroussin 				chunk->column = term_len;
1615c99fb5f9SBaptiste Daroussin 				*beg = c;
1616c99fb5f9SBaptiste Daroussin 				break;
1617c99fb5f9SBaptiste Daroussin 			}
1618c99fb5f9SBaptiste Daroussin 		}
1619c99fb5f9SBaptiste Daroussin 		if (*p == '\n') {
1620c99fb5f9SBaptiste Daroussin 			newline = true;
1621c99fb5f9SBaptiste Daroussin 		}
1622c99fb5f9SBaptiste Daroussin 		else {
1623c99fb5f9SBaptiste Daroussin 			if (*p == '$') {
1624c99fb5f9SBaptiste Daroussin 				*var_expand = true;
1625c99fb5f9SBaptiste Daroussin 			}
1626c99fb5f9SBaptiste Daroussin 			newline = false;
1627c99fb5f9SBaptiste Daroussin 		}
1628c99fb5f9SBaptiste Daroussin 		ucl_chunk_skipc (chunk, p);
1629c99fb5f9SBaptiste Daroussin 	}
1630c99fb5f9SBaptiste Daroussin 
1631c99fb5f9SBaptiste Daroussin 	return len;
1632c99fb5f9SBaptiste Daroussin }
1633c99fb5f9SBaptiste Daroussin 
163439ee7a7aSBaptiste Daroussin static inline ucl_object_t*
ucl_parser_get_container(struct ucl_parser * parser)163539ee7a7aSBaptiste Daroussin ucl_parser_get_container (struct ucl_parser *parser)
1636c99fb5f9SBaptiste Daroussin {
163736c53d67SBaptiste Daroussin 	ucl_object_t *t, *obj = NULL;
1638c99fb5f9SBaptiste Daroussin 
16398e3b1ab2SBaptiste Daroussin 	if (parser == NULL || parser->stack == NULL || parser->stack->obj == NULL) {
16408e3b1ab2SBaptiste Daroussin 		return NULL;
16418e3b1ab2SBaptiste Daroussin 	}
16428e3b1ab2SBaptiste Daroussin 
1643c99fb5f9SBaptiste Daroussin 	if (parser->stack->obj->type == UCL_ARRAY) {
1644c99fb5f9SBaptiste Daroussin 		/* Object must be allocated */
16454bf54857SBaptiste Daroussin 		obj = ucl_object_new_full (UCL_NULL, parser->chunks->priority);
16468e3b1ab2SBaptiste Daroussin 		t = parser->stack->obj;
164739ee7a7aSBaptiste Daroussin 
164839ee7a7aSBaptiste Daroussin 		if (!ucl_array_append (t, obj)) {
164939ee7a7aSBaptiste Daroussin 			ucl_object_unref (obj);
165039ee7a7aSBaptiste Daroussin 			return NULL;
165139ee7a7aSBaptiste Daroussin 		}
165239ee7a7aSBaptiste Daroussin 
1653c99fb5f9SBaptiste Daroussin 		parser->cur_obj = obj;
1654d9f0ce31SBaptiste Daroussin 		ucl_attach_comment (parser, obj, false);
1655c99fb5f9SBaptiste Daroussin 	}
1656c99fb5f9SBaptiste Daroussin 	else {
1657c99fb5f9SBaptiste Daroussin 		/* Object has been already allocated */
1658c99fb5f9SBaptiste Daroussin 		obj = parser->cur_obj;
1659c99fb5f9SBaptiste Daroussin 	}
166036c53d67SBaptiste Daroussin 
166136c53d67SBaptiste Daroussin 	return obj;
1662c99fb5f9SBaptiste Daroussin }
166336c53d67SBaptiste Daroussin 
166436c53d67SBaptiste Daroussin /**
166536c53d67SBaptiste Daroussin  * Handle value data
166636c53d67SBaptiste Daroussin  * @param parser
166736c53d67SBaptiste Daroussin  * @param chunk
166836c53d67SBaptiste Daroussin  * @return
166936c53d67SBaptiste Daroussin  */
167036c53d67SBaptiste Daroussin static bool
ucl_parse_value(struct ucl_parser * parser,struct ucl_chunk * chunk)167136c53d67SBaptiste Daroussin ucl_parse_value (struct ucl_parser *parser, struct ucl_chunk *chunk)
167236c53d67SBaptiste Daroussin {
167336c53d67SBaptiste Daroussin 	const unsigned char *p, *c;
167436c53d67SBaptiste Daroussin 	ucl_object_t *obj = NULL;
167536c53d67SBaptiste Daroussin 	unsigned int stripped_spaces;
1676*a0409676SBaptiste Daroussin 	ssize_t str_len;
167736c53d67SBaptiste Daroussin 	bool need_unescape = false, ucl_escape = false, var_expand = false;
167836c53d67SBaptiste Daroussin 
167936c53d67SBaptiste Daroussin 	p = chunk->pos;
168036c53d67SBaptiste Daroussin 
168136c53d67SBaptiste Daroussin 	/* Skip any spaces and comments */
168236c53d67SBaptiste Daroussin 	if (ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE) ||
168336c53d67SBaptiste Daroussin 			(chunk->remain >= 2 && ucl_lex_is_comment (p[0], p[1]))) {
168436c53d67SBaptiste Daroussin 		while (p < chunk->end && ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE)) {
168536c53d67SBaptiste Daroussin 			ucl_chunk_skipc (chunk, p);
168636c53d67SBaptiste Daroussin 		}
168736c53d67SBaptiste Daroussin 		if (!ucl_skip_comments (parser)) {
168836c53d67SBaptiste Daroussin 			return false;
168936c53d67SBaptiste Daroussin 		}
169036c53d67SBaptiste Daroussin 		p = chunk->pos;
169136c53d67SBaptiste Daroussin 	}
169236c53d67SBaptiste Daroussin 
169336c53d67SBaptiste Daroussin 	while (p < chunk->end) {
1694c99fb5f9SBaptiste Daroussin 		c = p;
1695c99fb5f9SBaptiste Daroussin 		switch (*p) {
1696c99fb5f9SBaptiste Daroussin 		case '"':
1697c99fb5f9SBaptiste Daroussin 			ucl_chunk_skipc (chunk, p);
169839ee7a7aSBaptiste Daroussin 
169939ee7a7aSBaptiste Daroussin 			if (!ucl_lex_json_string (parser, chunk, &need_unescape, &ucl_escape,
170039ee7a7aSBaptiste Daroussin 					&var_expand)) {
1701c99fb5f9SBaptiste Daroussin 				return false;
1702c99fb5f9SBaptiste Daroussin 			}
170339ee7a7aSBaptiste Daroussin 
170439ee7a7aSBaptiste Daroussin 			obj = ucl_parser_get_container (parser);
1705d9f0ce31SBaptiste Daroussin 			if (!obj) {
1706d9f0ce31SBaptiste Daroussin 				return false;
1707d9f0ce31SBaptiste Daroussin 			}
1708d9f0ce31SBaptiste Daroussin 
1709c99fb5f9SBaptiste Daroussin 			str_len = chunk->pos - c - 2;
1710c99fb5f9SBaptiste Daroussin 			obj->type = UCL_STRING;
171139ee7a7aSBaptiste Daroussin 			if ((str_len = ucl_copy_or_store_ptr (parser, c + 1,
171239ee7a7aSBaptiste Daroussin 					&obj->trash_stack[UCL_TRASH_VALUE],
171339ee7a7aSBaptiste Daroussin 					&obj->value.sv, str_len, need_unescape, false,
1714*a0409676SBaptiste Daroussin 					var_expand, false)) == -1) {
1715c99fb5f9SBaptiste Daroussin 				return false;
1716c99fb5f9SBaptiste Daroussin 			}
1717*a0409676SBaptiste Daroussin 
1718*a0409676SBaptiste Daroussin 			obj->len = str_len;
1719*a0409676SBaptiste Daroussin 			parser->state = UCL_STATE_AFTER_VALUE;
1720*a0409676SBaptiste Daroussin 
1721*a0409676SBaptiste Daroussin 			return true;
1722*a0409676SBaptiste Daroussin 			break;
1723*a0409676SBaptiste Daroussin 		case '\'':
1724*a0409676SBaptiste Daroussin 			ucl_chunk_skipc (chunk, p);
1725*a0409676SBaptiste Daroussin 
1726*a0409676SBaptiste Daroussin 			if (!ucl_lex_squoted_string (parser, chunk, &need_unescape)) {
1727*a0409676SBaptiste Daroussin 				return false;
1728*a0409676SBaptiste Daroussin 			}
1729*a0409676SBaptiste Daroussin 
1730*a0409676SBaptiste Daroussin 			obj = ucl_parser_get_container (parser);
1731*a0409676SBaptiste Daroussin 			if (!obj) {
1732*a0409676SBaptiste Daroussin 				return false;
1733*a0409676SBaptiste Daroussin 			}
1734*a0409676SBaptiste Daroussin 
1735*a0409676SBaptiste Daroussin 			str_len = chunk->pos - c - 2;
1736*a0409676SBaptiste Daroussin 			obj->type = UCL_STRING;
1737*a0409676SBaptiste Daroussin 			obj->flags |= UCL_OBJECT_SQUOTED;
1738*a0409676SBaptiste Daroussin 
1739*a0409676SBaptiste Daroussin 			if ((str_len = ucl_copy_or_store_ptr (parser, c + 1,
1740*a0409676SBaptiste Daroussin 					&obj->trash_stack[UCL_TRASH_VALUE],
1741*a0409676SBaptiste Daroussin 					&obj->value.sv, str_len, need_unescape, false,
1742*a0409676SBaptiste Daroussin 					var_expand, true)) == -1) {
1743*a0409676SBaptiste Daroussin 				return false;
1744*a0409676SBaptiste Daroussin 			}
1745*a0409676SBaptiste Daroussin 
1746c99fb5f9SBaptiste Daroussin 			obj->len = str_len;
174739ee7a7aSBaptiste Daroussin 
1748c99fb5f9SBaptiste Daroussin 			parser->state = UCL_STATE_AFTER_VALUE;
174939ee7a7aSBaptiste Daroussin 
1750c99fb5f9SBaptiste Daroussin 			return true;
1751c99fb5f9SBaptiste Daroussin 			break;
1752c99fb5f9SBaptiste Daroussin 		case '{':
175339ee7a7aSBaptiste Daroussin 			obj = ucl_parser_get_container (parser);
1754*a0409676SBaptiste Daroussin 			if (obj == NULL) {
1755*a0409676SBaptiste Daroussin 				return false;
1756*a0409676SBaptiste Daroussin 			}
1757c99fb5f9SBaptiste Daroussin 			/* We have a new object */
1758*a0409676SBaptiste Daroussin 			if (parser->stack) {
1759*a0409676SBaptiste Daroussin 				obj = ucl_parser_add_container (obj, parser, false,
1760*a0409676SBaptiste Daroussin 						parser->stack->e.params.level, true);
1761*a0409676SBaptiste Daroussin 			}
1762*a0409676SBaptiste Daroussin 			else {
1763*a0409676SBaptiste Daroussin 				return false;
1764*a0409676SBaptiste Daroussin 			}
176597bd480fSBaptiste Daroussin 			if (obj == NULL) {
176697bd480fSBaptiste Daroussin 				return false;
176797bd480fSBaptiste Daroussin 			}
1768c99fb5f9SBaptiste Daroussin 
1769c99fb5f9SBaptiste Daroussin 			ucl_chunk_skipc (chunk, p);
177039ee7a7aSBaptiste Daroussin 
1771c99fb5f9SBaptiste Daroussin 			return true;
1772c99fb5f9SBaptiste Daroussin 			break;
1773c99fb5f9SBaptiste Daroussin 		case '[':
177439ee7a7aSBaptiste Daroussin 			obj = ucl_parser_get_container (parser);
1775*a0409676SBaptiste Daroussin 			if (obj == NULL) {
1776*a0409676SBaptiste Daroussin 				return false;
1777*a0409676SBaptiste Daroussin 			}
1778c99fb5f9SBaptiste Daroussin 			/* We have a new array */
1779*a0409676SBaptiste Daroussin 			if (parser->stack) {
1780*a0409676SBaptiste Daroussin 				obj = ucl_parser_add_container (obj, parser, true,
1781*a0409676SBaptiste Daroussin 						parser->stack->e.params.level, true);
1782*a0409676SBaptiste Daroussin 			}
1783*a0409676SBaptiste Daroussin 			else {
1784*a0409676SBaptiste Daroussin 				return false;
1785*a0409676SBaptiste Daroussin 			}
1786*a0409676SBaptiste Daroussin 
178797bd480fSBaptiste Daroussin 			if (obj == NULL) {
178897bd480fSBaptiste Daroussin 				return false;
178997bd480fSBaptiste Daroussin 			}
1790c99fb5f9SBaptiste Daroussin 
1791c99fb5f9SBaptiste Daroussin 			ucl_chunk_skipc (chunk, p);
179239ee7a7aSBaptiste Daroussin 
1793c99fb5f9SBaptiste Daroussin 			return true;
1794c99fb5f9SBaptiste Daroussin 			break;
179536c53d67SBaptiste Daroussin 		case ']':
179636c53d67SBaptiste Daroussin 			/* We have the array ending */
179736c53d67SBaptiste Daroussin 			if (parser->stack && parser->stack->obj->type == UCL_ARRAY) {
179836c53d67SBaptiste Daroussin 				parser->state = UCL_STATE_AFTER_VALUE;
179936c53d67SBaptiste Daroussin 				return true;
180036c53d67SBaptiste Daroussin 			}
180136c53d67SBaptiste Daroussin 			else {
180236c53d67SBaptiste Daroussin 				goto parse_string;
180336c53d67SBaptiste Daroussin 			}
180436c53d67SBaptiste Daroussin 			break;
1805c99fb5f9SBaptiste Daroussin 		case '<':
180639ee7a7aSBaptiste Daroussin 			obj = ucl_parser_get_container (parser);
1807c99fb5f9SBaptiste Daroussin 			/* We have something like multiline value, which must be <<[A-Z]+\n */
1808c99fb5f9SBaptiste Daroussin 			if (chunk->end - p > 3) {
1809c99fb5f9SBaptiste Daroussin 				if (memcmp (p, "<<", 2) == 0) {
1810c99fb5f9SBaptiste Daroussin 					p += 2;
1811c99fb5f9SBaptiste Daroussin 					/* We allow only uppercase characters in multiline definitions */
1812c99fb5f9SBaptiste Daroussin 					while (p < chunk->end && *p >= 'A' && *p <= 'Z') {
1813c99fb5f9SBaptiste Daroussin 						p ++;
1814c99fb5f9SBaptiste Daroussin 					}
1815c99fb5f9SBaptiste Daroussin 					if (*p =='\n') {
1816c99fb5f9SBaptiste Daroussin 						/* Set chunk positions and start multiline parsing */
1817*a0409676SBaptiste Daroussin 						chunk->remain -= p - c + 1;
1818c99fb5f9SBaptiste Daroussin 						c += 2;
1819c99fb5f9SBaptiste Daroussin 						chunk->pos = p + 1;
1820c99fb5f9SBaptiste Daroussin 						chunk->column = 0;
1821c99fb5f9SBaptiste Daroussin 						chunk->line ++;
1822c99fb5f9SBaptiste Daroussin 						if ((str_len = ucl_parse_multiline_string (parser, chunk, c,
1823c99fb5f9SBaptiste Daroussin 								p - c, &c, &var_expand)) == 0) {
18244bf54857SBaptiste Daroussin 							ucl_set_err (parser, UCL_ESYNTAX,
18254bf54857SBaptiste Daroussin 									"unterminated multiline value", &parser->err);
1826c99fb5f9SBaptiste Daroussin 							return false;
1827c99fb5f9SBaptiste Daroussin 						}
182839ee7a7aSBaptiste Daroussin 
1829c99fb5f9SBaptiste Daroussin 						obj->type = UCL_STRING;
183039ee7a7aSBaptiste Daroussin 						obj->flags |= UCL_OBJECT_MULTILINE;
183139ee7a7aSBaptiste Daroussin 						if ((str_len = ucl_copy_or_store_ptr (parser, c,
183239ee7a7aSBaptiste Daroussin 								&obj->trash_stack[UCL_TRASH_VALUE],
183339ee7a7aSBaptiste Daroussin 								&obj->value.sv, str_len - 1, false,
1834*a0409676SBaptiste Daroussin 								false, var_expand, false)) == -1) {
1835c99fb5f9SBaptiste Daroussin 							return false;
1836c99fb5f9SBaptiste Daroussin 						}
1837c99fb5f9SBaptiste Daroussin 						obj->len = str_len;
183839ee7a7aSBaptiste Daroussin 
1839c99fb5f9SBaptiste Daroussin 						parser->state = UCL_STATE_AFTER_VALUE;
184039ee7a7aSBaptiste Daroussin 
1841c99fb5f9SBaptiste Daroussin 						return true;
1842c99fb5f9SBaptiste Daroussin 					}
1843c99fb5f9SBaptiste Daroussin 				}
1844c99fb5f9SBaptiste Daroussin 			}
1845c99fb5f9SBaptiste Daroussin 			/* Fallback to ordinary strings */
1846*a0409676SBaptiste Daroussin 			/* FALLTHRU */
1847c99fb5f9SBaptiste Daroussin 		default:
184836c53d67SBaptiste Daroussin parse_string:
184936c53d67SBaptiste Daroussin 			if (obj == NULL) {
185039ee7a7aSBaptiste Daroussin 				obj = ucl_parser_get_container (parser);
1851c99fb5f9SBaptiste Daroussin 			}
185239ee7a7aSBaptiste Daroussin 
1853c99fb5f9SBaptiste Daroussin 			/* Parse atom */
1854c99fb5f9SBaptiste Daroussin 			if (ucl_test_character (*p, UCL_CHARACTER_VALUE_DIGIT_START)) {
1855c99fb5f9SBaptiste Daroussin 				if (!ucl_lex_number (parser, chunk, obj)) {
1856c99fb5f9SBaptiste Daroussin 					if (parser->state == UCL_STATE_ERROR) {
1857c99fb5f9SBaptiste Daroussin 						return false;
1858c99fb5f9SBaptiste Daroussin 					}
1859c99fb5f9SBaptiste Daroussin 				}
1860c99fb5f9SBaptiste Daroussin 				else {
1861c99fb5f9SBaptiste Daroussin 					parser->state = UCL_STATE_AFTER_VALUE;
1862c99fb5f9SBaptiste Daroussin 					return true;
1863c99fb5f9SBaptiste Daroussin 				}
1864c99fb5f9SBaptiste Daroussin 				/* Fallback to normal string */
1865c99fb5f9SBaptiste Daroussin 			}
1866c99fb5f9SBaptiste Daroussin 
186739ee7a7aSBaptiste Daroussin 			if (!ucl_parse_string_value (parser, chunk, &var_expand,
186839ee7a7aSBaptiste Daroussin 					&need_unescape)) {
1869c99fb5f9SBaptiste Daroussin 				return false;
1870c99fb5f9SBaptiste Daroussin 			}
1871c99fb5f9SBaptiste Daroussin 			/* Cut trailing spaces */
1872c99fb5f9SBaptiste Daroussin 			stripped_spaces = 0;
1873c99fb5f9SBaptiste Daroussin 			while (ucl_test_character (*(chunk->pos - 1 - stripped_spaces),
1874c99fb5f9SBaptiste Daroussin 					UCL_CHARACTER_WHITESPACE)) {
1875c99fb5f9SBaptiste Daroussin 				stripped_spaces ++;
1876c99fb5f9SBaptiste Daroussin 			}
1877c99fb5f9SBaptiste Daroussin 			str_len = chunk->pos - c - stripped_spaces;
1878c99fb5f9SBaptiste Daroussin 			if (str_len <= 0) {
187939ee7a7aSBaptiste Daroussin 				ucl_set_err (parser, UCL_ESYNTAX, "string value must not be empty",
18804bf54857SBaptiste Daroussin 						&parser->err);
1881c99fb5f9SBaptiste Daroussin 				return false;
1882c99fb5f9SBaptiste Daroussin 			}
1883c99fb5f9SBaptiste Daroussin 			else if (str_len == 4 && memcmp (c, "null", 4) == 0) {
1884c99fb5f9SBaptiste Daroussin 				obj->len = 0;
1885c99fb5f9SBaptiste Daroussin 				obj->type = UCL_NULL;
1886c99fb5f9SBaptiste Daroussin 			}
1887*a0409676SBaptiste Daroussin 			else if (str_len == 3 && memcmp (c, "nan", 3) == 0) {
1888*a0409676SBaptiste Daroussin 				obj->len = 0;
1889*a0409676SBaptiste Daroussin 				obj->type = UCL_FLOAT;
1890*a0409676SBaptiste Daroussin 				obj->value.dv = NAN;
1891*a0409676SBaptiste Daroussin 			}
1892*a0409676SBaptiste Daroussin 			else if (str_len == 3 && memcmp (c, "inf", 3) == 0) {
1893*a0409676SBaptiste Daroussin 				obj->len = 0;
1894*a0409676SBaptiste Daroussin 				obj->type = UCL_FLOAT;
1895*a0409676SBaptiste Daroussin 				obj->value.dv = INFINITY;
1896*a0409676SBaptiste Daroussin 			}
1897c99fb5f9SBaptiste Daroussin 			else if (!ucl_maybe_parse_boolean (obj, c, str_len)) {
1898c99fb5f9SBaptiste Daroussin 				obj->type = UCL_STRING;
189939ee7a7aSBaptiste Daroussin 				if ((str_len = ucl_copy_or_store_ptr (parser, c,
190039ee7a7aSBaptiste Daroussin 						&obj->trash_stack[UCL_TRASH_VALUE],
1901c99fb5f9SBaptiste Daroussin 						&obj->value.sv, str_len, need_unescape,
1902*a0409676SBaptiste Daroussin 						false, var_expand, false)) == -1) {
1903c99fb5f9SBaptiste Daroussin 					return false;
1904c99fb5f9SBaptiste Daroussin 				}
1905c99fb5f9SBaptiste Daroussin 				obj->len = str_len;
1906c99fb5f9SBaptiste Daroussin 			}
1907*a0409676SBaptiste Daroussin 
1908c99fb5f9SBaptiste Daroussin 			parser->state = UCL_STATE_AFTER_VALUE;
1909c99fb5f9SBaptiste Daroussin 
1910c99fb5f9SBaptiste Daroussin 			return true;
1911c99fb5f9SBaptiste Daroussin 			break;
1912c99fb5f9SBaptiste Daroussin 		}
1913c99fb5f9SBaptiste Daroussin 	}
1914c99fb5f9SBaptiste Daroussin 
1915c99fb5f9SBaptiste Daroussin 	return true;
1916c99fb5f9SBaptiste Daroussin }
1917c99fb5f9SBaptiste Daroussin 
1918c99fb5f9SBaptiste Daroussin /**
1919c99fb5f9SBaptiste Daroussin  * Handle after value data
1920c99fb5f9SBaptiste Daroussin  * @param parser
1921c99fb5f9SBaptiste Daroussin  * @param chunk
1922c99fb5f9SBaptiste Daroussin  * @return
1923c99fb5f9SBaptiste Daroussin  */
1924c99fb5f9SBaptiste Daroussin static bool
ucl_parse_after_value(struct ucl_parser * parser,struct ucl_chunk * chunk)1925c99fb5f9SBaptiste Daroussin ucl_parse_after_value (struct ucl_parser *parser, struct ucl_chunk *chunk)
1926c99fb5f9SBaptiste Daroussin {
1927c99fb5f9SBaptiste Daroussin 	const unsigned char *p;
1928c99fb5f9SBaptiste Daroussin 	bool got_sep = false;
1929c99fb5f9SBaptiste Daroussin 	struct ucl_stack *st;
1930c99fb5f9SBaptiste Daroussin 
1931c99fb5f9SBaptiste Daroussin 	p = chunk->pos;
1932c99fb5f9SBaptiste Daroussin 
1933c99fb5f9SBaptiste Daroussin 	while (p < chunk->end) {
1934c99fb5f9SBaptiste Daroussin 		if (ucl_test_character (*p, UCL_CHARACTER_WHITESPACE)) {
1935c99fb5f9SBaptiste Daroussin 			/* Skip whitespaces */
1936c99fb5f9SBaptiste Daroussin 			ucl_chunk_skipc (chunk, p);
1937c99fb5f9SBaptiste Daroussin 		}
1938c99fb5f9SBaptiste Daroussin 		else if (chunk->remain >= 2 && ucl_lex_is_comment (p[0], p[1])) {
1939c99fb5f9SBaptiste Daroussin 			/* Skip comment */
1940c99fb5f9SBaptiste Daroussin 			if (!ucl_skip_comments (parser)) {
1941c99fb5f9SBaptiste Daroussin 				return false;
1942c99fb5f9SBaptiste Daroussin 			}
1943c99fb5f9SBaptiste Daroussin 			/* Treat comment as a separator */
1944c99fb5f9SBaptiste Daroussin 			got_sep = true;
1945c99fb5f9SBaptiste Daroussin 			p = chunk->pos;
1946c99fb5f9SBaptiste Daroussin 		}
1947c99fb5f9SBaptiste Daroussin 		else if (ucl_test_character (*p, UCL_CHARACTER_VALUE_END)) {
1948c99fb5f9SBaptiste Daroussin 			if (*p == '}' || *p == ']') {
1949c99fb5f9SBaptiste Daroussin 				if (parser->stack == NULL) {
19504bf54857SBaptiste Daroussin 					ucl_set_err (parser, UCL_ESYNTAX,
19514bf54857SBaptiste Daroussin 							"end of array or object detected without corresponding start",
19524bf54857SBaptiste Daroussin 							&parser->err);
1953c99fb5f9SBaptiste Daroussin 					return false;
1954c99fb5f9SBaptiste Daroussin 				}
1955c99fb5f9SBaptiste Daroussin 				if ((*p == '}' && parser->stack->obj->type == UCL_OBJECT) ||
1956c99fb5f9SBaptiste Daroussin 						(*p == ']' && parser->stack->obj->type == UCL_ARRAY)) {
1957c99fb5f9SBaptiste Daroussin 
1958c99fb5f9SBaptiste Daroussin 					/* Pop all nested objects from a stack */
1959c99fb5f9SBaptiste Daroussin 					st = parser->stack;
1960*a0409676SBaptiste Daroussin 
1961*a0409676SBaptiste Daroussin 					if (!(st->e.params.flags & UCL_STACK_HAS_OBRACE)) {
1962*a0409676SBaptiste Daroussin 						parser->err_code = UCL_EUNPAIRED;
1963*a0409676SBaptiste Daroussin 						ucl_create_err (&parser->err,
1964*a0409676SBaptiste Daroussin 								"%s:%d object closed with } is not opened with { at line %d",
1965*a0409676SBaptiste Daroussin 								chunk->fname ? chunk->fname : "memory",
1966*a0409676SBaptiste Daroussin 								parser->chunks->line, st->e.params.line);
1967*a0409676SBaptiste Daroussin 
1968*a0409676SBaptiste Daroussin 						return false;
1969*a0409676SBaptiste Daroussin 					}
1970*a0409676SBaptiste Daroussin 
1971c99fb5f9SBaptiste Daroussin 					parser->stack = st->next;
1972c99fb5f9SBaptiste Daroussin 					UCL_FREE (sizeof (struct ucl_stack), st);
1973c99fb5f9SBaptiste Daroussin 
1974d9f0ce31SBaptiste Daroussin 					if (parser->cur_obj) {
1975d9f0ce31SBaptiste Daroussin 						ucl_attach_comment (parser, parser->cur_obj, true);
1976d9f0ce31SBaptiste Daroussin 					}
1977d9f0ce31SBaptiste Daroussin 
1978c99fb5f9SBaptiste Daroussin 					while (parser->stack != NULL) {
1979c99fb5f9SBaptiste Daroussin 						st = parser->stack;
1980d9f0ce31SBaptiste Daroussin 
1981*a0409676SBaptiste Daroussin 						if (st->next == NULL) {
1982c99fb5f9SBaptiste Daroussin 							break;
1983c99fb5f9SBaptiste Daroussin 						}
1984*a0409676SBaptiste Daroussin 						else if (st->next->e.params.level == st->e.params.level) {
1985*a0409676SBaptiste Daroussin 							break;
1986*a0409676SBaptiste Daroussin 						}
1987*a0409676SBaptiste Daroussin 
1988d9f0ce31SBaptiste Daroussin 
1989c99fb5f9SBaptiste Daroussin 						parser->stack = st->next;
1990d9f0ce31SBaptiste Daroussin 						parser->cur_obj = st->obj;
1991c99fb5f9SBaptiste Daroussin 						UCL_FREE (sizeof (struct ucl_stack), st);
1992c99fb5f9SBaptiste Daroussin 					}
1993c99fb5f9SBaptiste Daroussin 				}
1994c99fb5f9SBaptiste Daroussin 				else {
19954bf54857SBaptiste Daroussin 					ucl_set_err (parser, UCL_ESYNTAX,
19964bf54857SBaptiste Daroussin 							"unexpected terminating symbol detected",
19974bf54857SBaptiste Daroussin 							&parser->err);
1998c99fb5f9SBaptiste Daroussin 					return false;
1999c99fb5f9SBaptiste Daroussin 				}
2000c99fb5f9SBaptiste Daroussin 
2001c99fb5f9SBaptiste Daroussin 				if (parser->stack == NULL) {
2002c99fb5f9SBaptiste Daroussin 					/* Ignore everything after a top object */
2003c99fb5f9SBaptiste Daroussin 					return true;
2004c99fb5f9SBaptiste Daroussin 				}
2005c99fb5f9SBaptiste Daroussin 				else {
2006c99fb5f9SBaptiste Daroussin 					ucl_chunk_skipc (chunk, p);
2007c99fb5f9SBaptiste Daroussin 				}
2008c99fb5f9SBaptiste Daroussin 				got_sep = true;
2009c99fb5f9SBaptiste Daroussin 			}
2010c99fb5f9SBaptiste Daroussin 			else {
2011c99fb5f9SBaptiste Daroussin 				/* Got a separator */
2012c99fb5f9SBaptiste Daroussin 				got_sep = true;
2013c99fb5f9SBaptiste Daroussin 				ucl_chunk_skipc (chunk, p);
2014c99fb5f9SBaptiste Daroussin 			}
2015c99fb5f9SBaptiste Daroussin 		}
2016c99fb5f9SBaptiste Daroussin 		else {
2017c99fb5f9SBaptiste Daroussin 			/* Anything else */
2018c99fb5f9SBaptiste Daroussin 			if (!got_sep) {
20194bf54857SBaptiste Daroussin 				ucl_set_err (parser, UCL_ESYNTAX, "delimiter is missing",
20204bf54857SBaptiste Daroussin 						&parser->err);
2021c99fb5f9SBaptiste Daroussin 				return false;
2022c99fb5f9SBaptiste Daroussin 			}
2023c99fb5f9SBaptiste Daroussin 			return true;
2024c99fb5f9SBaptiste Daroussin 		}
2025c99fb5f9SBaptiste Daroussin 	}
2026c99fb5f9SBaptiste Daroussin 
2027c99fb5f9SBaptiste Daroussin 	return true;
2028c99fb5f9SBaptiste Daroussin }
2029c99fb5f9SBaptiste Daroussin 
2030d9f0ce31SBaptiste Daroussin static bool
ucl_skip_macro_as_comment(struct ucl_parser * parser,struct ucl_chunk * chunk)2031d9f0ce31SBaptiste Daroussin ucl_skip_macro_as_comment (struct ucl_parser *parser,
2032d9f0ce31SBaptiste Daroussin 		struct ucl_chunk *chunk)
2033d9f0ce31SBaptiste Daroussin {
2034d9f0ce31SBaptiste Daroussin 	const unsigned char *p, *c;
2035d9f0ce31SBaptiste Daroussin 	enum {
2036d9f0ce31SBaptiste Daroussin 		macro_skip_start = 0,
2037d9f0ce31SBaptiste Daroussin 		macro_has_symbols,
2038d9f0ce31SBaptiste Daroussin 		macro_has_obrace,
2039d9f0ce31SBaptiste Daroussin 		macro_has_quote,
2040d9f0ce31SBaptiste Daroussin 		macro_has_backslash,
2041d9f0ce31SBaptiste Daroussin 		macro_has_sqbrace,
2042d9f0ce31SBaptiste Daroussin 		macro_save
2043d9f0ce31SBaptiste Daroussin 	} state = macro_skip_start, prev_state = macro_skip_start;
2044d9f0ce31SBaptiste Daroussin 
2045d9f0ce31SBaptiste Daroussin 	p = chunk->pos;
2046d9f0ce31SBaptiste Daroussin 	c = chunk->pos;
2047d9f0ce31SBaptiste Daroussin 
2048d9f0ce31SBaptiste Daroussin 	while (p < chunk->end) {
2049d9f0ce31SBaptiste Daroussin 		switch (state) {
2050d9f0ce31SBaptiste Daroussin 		case macro_skip_start:
2051d9f0ce31SBaptiste Daroussin 			if (!ucl_test_character (*p, UCL_CHARACTER_WHITESPACE)) {
2052d9f0ce31SBaptiste Daroussin 				state = macro_has_symbols;
2053d9f0ce31SBaptiste Daroussin 			}
2054d9f0ce31SBaptiste Daroussin 			else if (ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE)) {
2055d9f0ce31SBaptiste Daroussin 				state = macro_save;
2056d9f0ce31SBaptiste Daroussin 				continue;
2057d9f0ce31SBaptiste Daroussin 			}
2058d9f0ce31SBaptiste Daroussin 
2059d9f0ce31SBaptiste Daroussin 			ucl_chunk_skipc (chunk, p);
2060d9f0ce31SBaptiste Daroussin 			break;
2061d9f0ce31SBaptiste Daroussin 
2062d9f0ce31SBaptiste Daroussin 		case macro_has_symbols:
2063d9f0ce31SBaptiste Daroussin 			if (*p == '{') {
2064d9f0ce31SBaptiste Daroussin 				state = macro_has_sqbrace;
2065d9f0ce31SBaptiste Daroussin 			}
2066d9f0ce31SBaptiste Daroussin 			else if (*p == '(') {
2067d9f0ce31SBaptiste Daroussin 				state = macro_has_obrace;
2068d9f0ce31SBaptiste Daroussin 			}
2069d9f0ce31SBaptiste Daroussin 			else if (*p == '"') {
2070d9f0ce31SBaptiste Daroussin 				state = macro_has_quote;
2071d9f0ce31SBaptiste Daroussin 			}
2072d9f0ce31SBaptiste Daroussin 			else if (*p == '\n') {
2073d9f0ce31SBaptiste Daroussin 				state = macro_save;
2074d9f0ce31SBaptiste Daroussin 				continue;
2075d9f0ce31SBaptiste Daroussin 			}
2076d9f0ce31SBaptiste Daroussin 
2077d9f0ce31SBaptiste Daroussin 			ucl_chunk_skipc (chunk, p);
2078d9f0ce31SBaptiste Daroussin 			break;
2079d9f0ce31SBaptiste Daroussin 
2080d9f0ce31SBaptiste Daroussin 		case macro_has_obrace:
2081d9f0ce31SBaptiste Daroussin 			if (*p == '\\') {
2082d9f0ce31SBaptiste Daroussin 				prev_state = state;
2083d9f0ce31SBaptiste Daroussin 				state = macro_has_backslash;
2084d9f0ce31SBaptiste Daroussin 			}
2085d9f0ce31SBaptiste Daroussin 			else if (*p == ')') {
2086d9f0ce31SBaptiste Daroussin 				state = macro_has_symbols;
2087d9f0ce31SBaptiste Daroussin 			}
2088d9f0ce31SBaptiste Daroussin 
2089d9f0ce31SBaptiste Daroussin 			ucl_chunk_skipc (chunk, p);
2090d9f0ce31SBaptiste Daroussin 			break;
2091d9f0ce31SBaptiste Daroussin 
2092d9f0ce31SBaptiste Daroussin 		case macro_has_sqbrace:
2093d9f0ce31SBaptiste Daroussin 			if (*p == '\\') {
2094d9f0ce31SBaptiste Daroussin 				prev_state = state;
2095d9f0ce31SBaptiste Daroussin 				state = macro_has_backslash;
2096d9f0ce31SBaptiste Daroussin 			}
2097d9f0ce31SBaptiste Daroussin 			else if (*p == '}') {
2098d9f0ce31SBaptiste Daroussin 				state = macro_save;
2099d9f0ce31SBaptiste Daroussin 			}
2100d9f0ce31SBaptiste Daroussin 
2101d9f0ce31SBaptiste Daroussin 			ucl_chunk_skipc (chunk, p);
2102d9f0ce31SBaptiste Daroussin 			break;
2103d9f0ce31SBaptiste Daroussin 
2104d9f0ce31SBaptiste Daroussin 		case macro_has_quote:
2105d9f0ce31SBaptiste Daroussin 			if (*p == '\\') {
2106d9f0ce31SBaptiste Daroussin 				prev_state = state;
2107d9f0ce31SBaptiste Daroussin 				state = macro_has_backslash;
2108d9f0ce31SBaptiste Daroussin 			}
2109d9f0ce31SBaptiste Daroussin 			else if (*p == '"') {
2110d9f0ce31SBaptiste Daroussin 				state = macro_save;
2111d9f0ce31SBaptiste Daroussin 			}
2112d9f0ce31SBaptiste Daroussin 
2113d9f0ce31SBaptiste Daroussin 			ucl_chunk_skipc (chunk, p);
2114d9f0ce31SBaptiste Daroussin 			break;
2115d9f0ce31SBaptiste Daroussin 
2116d9f0ce31SBaptiste Daroussin 		case macro_has_backslash:
2117d9f0ce31SBaptiste Daroussin 			state = prev_state;
2118d9f0ce31SBaptiste Daroussin 			ucl_chunk_skipc (chunk, p);
2119d9f0ce31SBaptiste Daroussin 			break;
2120d9f0ce31SBaptiste Daroussin 
2121d9f0ce31SBaptiste Daroussin 		case macro_save:
2122d9f0ce31SBaptiste Daroussin 			if (parser->flags & UCL_PARSER_SAVE_COMMENTS) {
2123d9f0ce31SBaptiste Daroussin 				ucl_save_comment (parser, c, p - c);
2124d9f0ce31SBaptiste Daroussin 			}
2125d9f0ce31SBaptiste Daroussin 
2126d9f0ce31SBaptiste Daroussin 			return true;
2127d9f0ce31SBaptiste Daroussin 		}
2128d9f0ce31SBaptiste Daroussin 	}
2129d9f0ce31SBaptiste Daroussin 
2130d9f0ce31SBaptiste Daroussin 	return false;
2131d9f0ce31SBaptiste Daroussin }
2132d9f0ce31SBaptiste Daroussin 
2133c99fb5f9SBaptiste Daroussin /**
2134c99fb5f9SBaptiste Daroussin  * Handle macro data
2135c99fb5f9SBaptiste Daroussin  * @param parser
2136c99fb5f9SBaptiste Daroussin  * @param chunk
213739ee7a7aSBaptiste Daroussin  * @param marco
213839ee7a7aSBaptiste Daroussin  * @param macro_start
213939ee7a7aSBaptiste Daroussin  * @param macro_len
2140c99fb5f9SBaptiste Daroussin  * @return
2141c99fb5f9SBaptiste Daroussin  */
2142c99fb5f9SBaptiste Daroussin static bool
ucl_parse_macro_value(struct ucl_parser * parser,struct ucl_chunk * chunk,struct ucl_macro * macro,unsigned char const ** macro_start,size_t * macro_len)2143c99fb5f9SBaptiste Daroussin ucl_parse_macro_value (struct ucl_parser *parser,
2144c99fb5f9SBaptiste Daroussin 		struct ucl_chunk *chunk, struct ucl_macro *macro,
2145c99fb5f9SBaptiste Daroussin 		unsigned char const **macro_start, size_t *macro_len)
2146c99fb5f9SBaptiste Daroussin {
2147c99fb5f9SBaptiste Daroussin 	const unsigned char *p, *c;
2148c99fb5f9SBaptiste Daroussin 	bool need_unescape = false, ucl_escape = false, var_expand = false;
2149c99fb5f9SBaptiste Daroussin 
2150c99fb5f9SBaptiste Daroussin 	p = chunk->pos;
2151c99fb5f9SBaptiste Daroussin 
2152c99fb5f9SBaptiste Daroussin 	switch (*p) {
2153c99fb5f9SBaptiste Daroussin 	case '"':
2154c99fb5f9SBaptiste Daroussin 		/* We have macro value encoded in quotes */
2155c99fb5f9SBaptiste Daroussin 		c = p;
2156c99fb5f9SBaptiste Daroussin 		ucl_chunk_skipc (chunk, p);
2157c99fb5f9SBaptiste Daroussin 		if (!ucl_lex_json_string (parser, chunk, &need_unescape, &ucl_escape, &var_expand)) {
2158c99fb5f9SBaptiste Daroussin 			return false;
2159c99fb5f9SBaptiste Daroussin 		}
2160c99fb5f9SBaptiste Daroussin 
2161c99fb5f9SBaptiste Daroussin 		*macro_start = c + 1;
2162c99fb5f9SBaptiste Daroussin 		*macro_len = chunk->pos - c - 2;
2163c99fb5f9SBaptiste Daroussin 		p = chunk->pos;
2164c99fb5f9SBaptiste Daroussin 		break;
2165c99fb5f9SBaptiste Daroussin 	case '{':
2166c99fb5f9SBaptiste Daroussin 		/* We got a multiline macro body */
2167c99fb5f9SBaptiste Daroussin 		ucl_chunk_skipc (chunk, p);
2168c99fb5f9SBaptiste Daroussin 		/* Skip spaces at the beginning */
2169c99fb5f9SBaptiste Daroussin 		while (p < chunk->end) {
2170c99fb5f9SBaptiste Daroussin 			if (ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE)) {
2171c99fb5f9SBaptiste Daroussin 				ucl_chunk_skipc (chunk, p);
2172c99fb5f9SBaptiste Daroussin 			}
2173c99fb5f9SBaptiste Daroussin 			else {
2174c99fb5f9SBaptiste Daroussin 				break;
2175c99fb5f9SBaptiste Daroussin 			}
2176c99fb5f9SBaptiste Daroussin 		}
2177c99fb5f9SBaptiste Daroussin 		c = p;
2178c99fb5f9SBaptiste Daroussin 		while (p < chunk->end) {
2179c99fb5f9SBaptiste Daroussin 			if (*p == '}') {
2180c99fb5f9SBaptiste Daroussin 				break;
2181c99fb5f9SBaptiste Daroussin 			}
2182c99fb5f9SBaptiste Daroussin 			ucl_chunk_skipc (chunk, p);
2183c99fb5f9SBaptiste Daroussin 		}
2184c99fb5f9SBaptiste Daroussin 		*macro_start = c;
2185c99fb5f9SBaptiste Daroussin 		*macro_len = p - c;
2186c99fb5f9SBaptiste Daroussin 		ucl_chunk_skipc (chunk, p);
2187c99fb5f9SBaptiste Daroussin 		break;
2188c99fb5f9SBaptiste Daroussin 	default:
2189c99fb5f9SBaptiste Daroussin 		/* Macro is not enclosed in quotes or braces */
2190c99fb5f9SBaptiste Daroussin 		c = p;
2191c99fb5f9SBaptiste Daroussin 		while (p < chunk->end) {
2192c99fb5f9SBaptiste Daroussin 			if (ucl_lex_is_atom_end (*p)) {
2193c99fb5f9SBaptiste Daroussin 				break;
2194c99fb5f9SBaptiste Daroussin 			}
2195c99fb5f9SBaptiste Daroussin 			ucl_chunk_skipc (chunk, p);
2196c99fb5f9SBaptiste Daroussin 		}
2197c99fb5f9SBaptiste Daroussin 		*macro_start = c;
2198c99fb5f9SBaptiste Daroussin 		*macro_len = p - c;
2199c99fb5f9SBaptiste Daroussin 		break;
2200c99fb5f9SBaptiste Daroussin 	}
2201c99fb5f9SBaptiste Daroussin 
2202c99fb5f9SBaptiste Daroussin 	/* We are at the end of a macro */
2203c99fb5f9SBaptiste Daroussin 	/* Skip ';' and space characters and return to previous state */
2204c99fb5f9SBaptiste Daroussin 	while (p < chunk->end) {
2205c99fb5f9SBaptiste Daroussin 		if (!ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE) && *p != ';') {
2206c99fb5f9SBaptiste Daroussin 			break;
2207c99fb5f9SBaptiste Daroussin 		}
2208c99fb5f9SBaptiste Daroussin 		ucl_chunk_skipc (chunk, p);
2209c99fb5f9SBaptiste Daroussin 	}
2210c99fb5f9SBaptiste Daroussin 	return true;
2211c99fb5f9SBaptiste Daroussin }
2212c99fb5f9SBaptiste Daroussin 
2213c99fb5f9SBaptiste Daroussin /**
22144bf54857SBaptiste Daroussin  * Parse macro arguments as UCL object
22154bf54857SBaptiste Daroussin  * @param parser parser structure
22164bf54857SBaptiste Daroussin  * @param chunk the current data chunk
22174bf54857SBaptiste Daroussin  * @return
22184bf54857SBaptiste Daroussin  */
22194bf54857SBaptiste Daroussin static ucl_object_t *
ucl_parse_macro_arguments(struct ucl_parser * parser,struct ucl_chunk * chunk)22204bf54857SBaptiste Daroussin ucl_parse_macro_arguments (struct ucl_parser *parser,
22214bf54857SBaptiste Daroussin 		struct ucl_chunk *chunk)
22224bf54857SBaptiste Daroussin {
22234bf54857SBaptiste Daroussin 	ucl_object_t *res = NULL;
22244bf54857SBaptiste Daroussin 	struct ucl_parser *params_parser;
22254bf54857SBaptiste Daroussin 	int obraces = 1, ebraces = 0, state = 0;
22264bf54857SBaptiste Daroussin 	const unsigned char *p, *c;
22274bf54857SBaptiste Daroussin 	size_t args_len = 0;
22284bf54857SBaptiste Daroussin 	struct ucl_parser_saved_state saved;
22294bf54857SBaptiste Daroussin 
22304bf54857SBaptiste Daroussin 	saved.column = chunk->column;
22314bf54857SBaptiste Daroussin 	saved.line = chunk->line;
22324bf54857SBaptiste Daroussin 	saved.pos = chunk->pos;
22334bf54857SBaptiste Daroussin 	saved.remain = chunk->remain;
22344bf54857SBaptiste Daroussin 	p = chunk->pos;
22354bf54857SBaptiste Daroussin 
22364bf54857SBaptiste Daroussin 	if (*p != '(' || chunk->remain < 2) {
22374bf54857SBaptiste Daroussin 		return NULL;
22384bf54857SBaptiste Daroussin 	}
22394bf54857SBaptiste Daroussin 
22404bf54857SBaptiste Daroussin 	/* Set begin and start */
22414bf54857SBaptiste Daroussin 	ucl_chunk_skipc (chunk, p);
22424bf54857SBaptiste Daroussin 	c = p;
22434bf54857SBaptiste Daroussin 
22444bf54857SBaptiste Daroussin 	while ((p) < (chunk)->end) {
22454bf54857SBaptiste Daroussin 		switch (state) {
22464bf54857SBaptiste Daroussin 		case 0:
22474bf54857SBaptiste Daroussin 			/* Parse symbols and check for '(', ')' and '"' */
22484bf54857SBaptiste Daroussin 			if (*p == '(') {
22494bf54857SBaptiste Daroussin 				obraces ++;
22504bf54857SBaptiste Daroussin 			}
22514bf54857SBaptiste Daroussin 			else if (*p == ')') {
22524bf54857SBaptiste Daroussin 				ebraces ++;
22534bf54857SBaptiste Daroussin 			}
22544bf54857SBaptiste Daroussin 			else if (*p == '"') {
22554bf54857SBaptiste Daroussin 				state = 1;
22564bf54857SBaptiste Daroussin 			}
22574bf54857SBaptiste Daroussin 			/* Check pairing */
22584bf54857SBaptiste Daroussin 			if (obraces == ebraces) {
22594bf54857SBaptiste Daroussin 				state = 99;
22604bf54857SBaptiste Daroussin 			}
22614bf54857SBaptiste Daroussin 			else {
22624bf54857SBaptiste Daroussin 				args_len ++;
22634bf54857SBaptiste Daroussin 			}
22644bf54857SBaptiste Daroussin 			/* Check overflow */
22654bf54857SBaptiste Daroussin 			if (chunk->remain == 0) {
22664bf54857SBaptiste Daroussin 				goto restore_chunk;
22674bf54857SBaptiste Daroussin 			}
22684bf54857SBaptiste Daroussin 			ucl_chunk_skipc (chunk, p);
22694bf54857SBaptiste Daroussin 			break;
22704bf54857SBaptiste Daroussin 		case 1:
22714bf54857SBaptiste Daroussin 			/* We have quote character, so skip all but quotes */
22724bf54857SBaptiste Daroussin 			if (*p == '"' && *(p - 1) != '\\') {
22734bf54857SBaptiste Daroussin 				state = 0;
22744bf54857SBaptiste Daroussin 			}
22754bf54857SBaptiste Daroussin 			if (chunk->remain == 0) {
22764bf54857SBaptiste Daroussin 				goto restore_chunk;
22774bf54857SBaptiste Daroussin 			}
227839ee7a7aSBaptiste Daroussin 			args_len ++;
22794bf54857SBaptiste Daroussin 			ucl_chunk_skipc (chunk, p);
22804bf54857SBaptiste Daroussin 			break;
22814bf54857SBaptiste Daroussin 		case 99:
22824bf54857SBaptiste Daroussin 			/*
22834bf54857SBaptiste Daroussin 			 * We have read the full body of arguments, so we need to parse and set
22844bf54857SBaptiste Daroussin 			 * object from that
22854bf54857SBaptiste Daroussin 			 */
22864bf54857SBaptiste Daroussin 			params_parser = ucl_parser_new (parser->flags);
22874bf54857SBaptiste Daroussin 			if (!ucl_parser_add_chunk (params_parser, c, args_len)) {
22884bf54857SBaptiste Daroussin 				ucl_set_err (parser, UCL_ESYNTAX, "macro arguments parsing error",
22894bf54857SBaptiste Daroussin 						&parser->err);
22904bf54857SBaptiste Daroussin 			}
22914bf54857SBaptiste Daroussin 			else {
22924bf54857SBaptiste Daroussin 				res = ucl_parser_get_object (params_parser);
22934bf54857SBaptiste Daroussin 			}
22944bf54857SBaptiste Daroussin 			ucl_parser_free (params_parser);
22954bf54857SBaptiste Daroussin 
22964bf54857SBaptiste Daroussin 			return res;
22974bf54857SBaptiste Daroussin 
22984bf54857SBaptiste Daroussin 			break;
22994bf54857SBaptiste Daroussin 		}
23004bf54857SBaptiste Daroussin 	}
23014bf54857SBaptiste Daroussin 
23024bf54857SBaptiste Daroussin 	return res;
23034bf54857SBaptiste Daroussin 
23044bf54857SBaptiste Daroussin restore_chunk:
23054bf54857SBaptiste Daroussin 	chunk->column = saved.column;
23064bf54857SBaptiste Daroussin 	chunk->line = saved.line;
23074bf54857SBaptiste Daroussin 	chunk->pos = saved.pos;
23084bf54857SBaptiste Daroussin 	chunk->remain = saved.remain;
23094bf54857SBaptiste Daroussin 
23104bf54857SBaptiste Daroussin 	return NULL;
23114bf54857SBaptiste Daroussin }
23124bf54857SBaptiste Daroussin 
23134bf54857SBaptiste Daroussin #define SKIP_SPACES_COMMENTS(parser, chunk, p) do {								\
23144bf54857SBaptiste Daroussin 	while ((p) < (chunk)->end) {												\
23154bf54857SBaptiste Daroussin 		if (!ucl_test_character (*(p), UCL_CHARACTER_WHITESPACE_UNSAFE)) {		\
23164bf54857SBaptiste Daroussin 			if ((chunk)->remain >= 2 && ucl_lex_is_comment ((p)[0], (p)[1])) {	\
23174bf54857SBaptiste Daroussin 				if (!ucl_skip_comments (parser)) {								\
23184bf54857SBaptiste Daroussin 					return false;												\
23194bf54857SBaptiste Daroussin 				}																\
23204bf54857SBaptiste Daroussin 				p = (chunk)->pos;												\
23214bf54857SBaptiste Daroussin 			}																	\
23224bf54857SBaptiste Daroussin 			break;																\
23234bf54857SBaptiste Daroussin 		}																		\
23244bf54857SBaptiste Daroussin 		ucl_chunk_skipc (chunk, p);												\
23254bf54857SBaptiste Daroussin 	}																			\
23264bf54857SBaptiste Daroussin } while(0)
23274bf54857SBaptiste Daroussin 
23284bf54857SBaptiste Daroussin /**
2329c99fb5f9SBaptiste Daroussin  * Handle the main states of rcl parser
2330c99fb5f9SBaptiste Daroussin  * @param parser parser structure
2331c99fb5f9SBaptiste Daroussin  * @return true if chunk has been parsed and false in case of error
2332c99fb5f9SBaptiste Daroussin  */
2333c99fb5f9SBaptiste Daroussin static bool
ucl_state_machine(struct ucl_parser * parser)2334c99fb5f9SBaptiste Daroussin ucl_state_machine (struct ucl_parser *parser)
2335c99fb5f9SBaptiste Daroussin {
23364bf54857SBaptiste Daroussin 	ucl_object_t *obj, *macro_args;
2337c99fb5f9SBaptiste Daroussin 	struct ucl_chunk *chunk = parser->chunks;
2338c99fb5f9SBaptiste Daroussin 	const unsigned char *p, *c = NULL, *macro_start = NULL;
2339c99fb5f9SBaptiste Daroussin 	unsigned char *macro_escaped;
2340c99fb5f9SBaptiste Daroussin 	size_t macro_len = 0;
2341c99fb5f9SBaptiste Daroussin 	struct ucl_macro *macro = NULL;
23424bf54857SBaptiste Daroussin 	bool next_key = false, end_of_object = false, ret;
2343c99fb5f9SBaptiste Daroussin 
2344c99fb5f9SBaptiste Daroussin 	if (parser->top_obj == NULL) {
2345c99fb5f9SBaptiste Daroussin 		parser->state = UCL_STATE_INIT;
2346c99fb5f9SBaptiste Daroussin 	}
2347c99fb5f9SBaptiste Daroussin 
2348c99fb5f9SBaptiste Daroussin 	p = chunk->pos;
2349c99fb5f9SBaptiste Daroussin 	while (chunk->pos < chunk->end) {
2350c99fb5f9SBaptiste Daroussin 		switch (parser->state) {
2351c99fb5f9SBaptiste Daroussin 		case UCL_STATE_INIT:
2352c99fb5f9SBaptiste Daroussin 			/*
2353c99fb5f9SBaptiste Daroussin 			 * At the init state we can either go to the parse array or object
2354c99fb5f9SBaptiste Daroussin 			 * if we got [ or { correspondingly or can just treat new data as
2355c99fb5f9SBaptiste Daroussin 			 * a key of newly created object
2356c99fb5f9SBaptiste Daroussin 			 */
2357c99fb5f9SBaptiste Daroussin 			if (!ucl_skip_comments (parser)) {
2358c99fb5f9SBaptiste Daroussin 				parser->prev_state = parser->state;
2359c99fb5f9SBaptiste Daroussin 				parser->state = UCL_STATE_ERROR;
2360c99fb5f9SBaptiste Daroussin 				return false;
2361c99fb5f9SBaptiste Daroussin 			}
2362c99fb5f9SBaptiste Daroussin 			else {
2363*a0409676SBaptiste Daroussin 				bool seen_obrace = false;
2364*a0409676SBaptiste Daroussin 
23650e89acf4SBaptiste Daroussin 				/* Skip any spaces */
23660e89acf4SBaptiste Daroussin 				while (p < chunk->end && ucl_test_character (*p,
23670e89acf4SBaptiste Daroussin 						UCL_CHARACTER_WHITESPACE_UNSAFE)) {
23680e89acf4SBaptiste Daroussin 					ucl_chunk_skipc (chunk, p);
23690e89acf4SBaptiste Daroussin 				}
237039ee7a7aSBaptiste Daroussin 
2371c99fb5f9SBaptiste Daroussin 				p = chunk->pos;
237239ee7a7aSBaptiste Daroussin 
2373*a0409676SBaptiste Daroussin 				if (p < chunk->end) {
2374c99fb5f9SBaptiste Daroussin 					if (*p == '[') {
2375c99fb5f9SBaptiste Daroussin 						parser->state = UCL_STATE_VALUE;
2376c99fb5f9SBaptiste Daroussin 						ucl_chunk_skipc (chunk, p);
2377*a0409676SBaptiste Daroussin 						seen_obrace = true;
2378*a0409676SBaptiste Daroussin 					}
2379*a0409676SBaptiste Daroussin 					else {
2380*a0409676SBaptiste Daroussin 
2381*a0409676SBaptiste Daroussin 						if (*p == '{') {
2382*a0409676SBaptiste Daroussin 							ucl_chunk_skipc (chunk, p);
2383*a0409676SBaptiste Daroussin 							parser->state = UCL_STATE_KEY_OBRACE;
2384*a0409676SBaptiste Daroussin 							seen_obrace = true;
2385c99fb5f9SBaptiste Daroussin 						}
2386c99fb5f9SBaptiste Daroussin 						else {
2387c99fb5f9SBaptiste Daroussin 							parser->state = UCL_STATE_KEY;
2388*a0409676SBaptiste Daroussin 						}
2389c99fb5f9SBaptiste Daroussin 					}
2390c99fb5f9SBaptiste Daroussin 				}
239139ee7a7aSBaptiste Daroussin 
239239ee7a7aSBaptiste Daroussin 				if (parser->top_obj == NULL) {
239339ee7a7aSBaptiste Daroussin 					if (parser->state == UCL_STATE_VALUE) {
2394*a0409676SBaptiste Daroussin 						obj = ucl_parser_add_container (NULL, parser, true, 0,
2395*a0409676SBaptiste Daroussin 								seen_obrace);
239639ee7a7aSBaptiste Daroussin 					}
239739ee7a7aSBaptiste Daroussin 					else {
2398*a0409676SBaptiste Daroussin 						obj = ucl_parser_add_container (NULL, parser, false, 0,
2399*a0409676SBaptiste Daroussin 								seen_obrace);
240039ee7a7aSBaptiste Daroussin 					}
240139ee7a7aSBaptiste Daroussin 
240239ee7a7aSBaptiste Daroussin 					if (obj == NULL) {
240339ee7a7aSBaptiste Daroussin 						return false;
240439ee7a7aSBaptiste Daroussin 					}
240539ee7a7aSBaptiste Daroussin 
240639ee7a7aSBaptiste Daroussin 					parser->top_obj = obj;
240739ee7a7aSBaptiste Daroussin 					parser->cur_obj = obj;
240839ee7a7aSBaptiste Daroussin 				}
240939ee7a7aSBaptiste Daroussin 
2410c99fb5f9SBaptiste Daroussin 			}
2411c99fb5f9SBaptiste Daroussin 			break;
2412c99fb5f9SBaptiste Daroussin 		case UCL_STATE_KEY:
2413*a0409676SBaptiste Daroussin 		case UCL_STATE_KEY_OBRACE:
2414c99fb5f9SBaptiste Daroussin 			/* Skip any spaces */
2415c99fb5f9SBaptiste Daroussin 			while (p < chunk->end && ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE)) {
2416c99fb5f9SBaptiste Daroussin 				ucl_chunk_skipc (chunk, p);
2417c99fb5f9SBaptiste Daroussin 			}
2418d9f0ce31SBaptiste Daroussin 			if (p == chunk->end || *p == '}') {
2419c99fb5f9SBaptiste Daroussin 				/* We have the end of an object */
2420c99fb5f9SBaptiste Daroussin 				parser->state = UCL_STATE_AFTER_VALUE;
2421c99fb5f9SBaptiste Daroussin 				continue;
2422c99fb5f9SBaptiste Daroussin 			}
2423c99fb5f9SBaptiste Daroussin 			if (parser->stack == NULL) {
2424c99fb5f9SBaptiste Daroussin 				/* No objects are on stack, but we want to parse a key */
24254bf54857SBaptiste Daroussin 				ucl_set_err (parser, UCL_ESYNTAX, "top object is finished but the parser "
2426c99fb5f9SBaptiste Daroussin 						"expects a key", &parser->err);
2427c99fb5f9SBaptiste Daroussin 				parser->prev_state = parser->state;
2428c99fb5f9SBaptiste Daroussin 				parser->state = UCL_STATE_ERROR;
2429c99fb5f9SBaptiste Daroussin 				return false;
2430c99fb5f9SBaptiste Daroussin 			}
2431c99fb5f9SBaptiste Daroussin 			if (!ucl_parse_key (parser, chunk, &next_key, &end_of_object)) {
2432c99fb5f9SBaptiste Daroussin 				parser->prev_state = parser->state;
2433c99fb5f9SBaptiste Daroussin 				parser->state = UCL_STATE_ERROR;
2434c99fb5f9SBaptiste Daroussin 				return false;
2435c99fb5f9SBaptiste Daroussin 			}
2436*a0409676SBaptiste Daroussin 
2437c99fb5f9SBaptiste Daroussin 			if (end_of_object) {
2438c99fb5f9SBaptiste Daroussin 				p = chunk->pos;
2439c99fb5f9SBaptiste Daroussin 				parser->state = UCL_STATE_AFTER_VALUE;
2440c99fb5f9SBaptiste Daroussin 				continue;
2441c99fb5f9SBaptiste Daroussin 			}
2442c99fb5f9SBaptiste Daroussin 			else if (parser->state != UCL_STATE_MACRO_NAME) {
2443c99fb5f9SBaptiste Daroussin 				if (next_key && parser->stack->obj->type == UCL_OBJECT) {
2444c99fb5f9SBaptiste Daroussin 					/* Parse more keys and nest objects accordingly */
2445*a0409676SBaptiste Daroussin 					obj = ucl_parser_add_container (parser->cur_obj,
2446*a0409676SBaptiste Daroussin 							parser,
2447*a0409676SBaptiste Daroussin 							false,
2448*a0409676SBaptiste Daroussin 							parser->stack->e.params.level + 1,
2449*a0409676SBaptiste Daroussin 							parser->state == UCL_STATE_KEY_OBRACE);
245097bd480fSBaptiste Daroussin 					if (obj == NULL) {
245197bd480fSBaptiste Daroussin 						return false;
245297bd480fSBaptiste Daroussin 					}
2453c99fb5f9SBaptiste Daroussin 				}
2454c99fb5f9SBaptiste Daroussin 				else {
2455c99fb5f9SBaptiste Daroussin 					parser->state = UCL_STATE_VALUE;
2456c99fb5f9SBaptiste Daroussin 				}
2457c99fb5f9SBaptiste Daroussin 			}
2458c99fb5f9SBaptiste Daroussin 			else {
2459c99fb5f9SBaptiste Daroussin 				c = chunk->pos;
2460c99fb5f9SBaptiste Daroussin 			}
2461c99fb5f9SBaptiste Daroussin 			p = chunk->pos;
2462c99fb5f9SBaptiste Daroussin 			break;
2463c99fb5f9SBaptiste Daroussin 		case UCL_STATE_VALUE:
2464c99fb5f9SBaptiste Daroussin 			/* We need to check what we do have */
2465d9f0ce31SBaptiste Daroussin 			if (!parser->cur_obj || !ucl_parse_value (parser, chunk)) {
2466c99fb5f9SBaptiste Daroussin 				parser->prev_state = parser->state;
2467c99fb5f9SBaptiste Daroussin 				parser->state = UCL_STATE_ERROR;
2468c99fb5f9SBaptiste Daroussin 				return false;
2469c99fb5f9SBaptiste Daroussin 			}
2470c99fb5f9SBaptiste Daroussin 			/* State is set in ucl_parse_value call */
2471c99fb5f9SBaptiste Daroussin 			p = chunk->pos;
2472c99fb5f9SBaptiste Daroussin 			break;
2473c99fb5f9SBaptiste Daroussin 		case UCL_STATE_AFTER_VALUE:
2474c99fb5f9SBaptiste Daroussin 			if (!ucl_parse_after_value (parser, chunk)) {
2475c99fb5f9SBaptiste Daroussin 				parser->prev_state = parser->state;
2476c99fb5f9SBaptiste Daroussin 				parser->state = UCL_STATE_ERROR;
2477c99fb5f9SBaptiste Daroussin 				return false;
2478c99fb5f9SBaptiste Daroussin 			}
247939ee7a7aSBaptiste Daroussin 
2480c99fb5f9SBaptiste Daroussin 			if (parser->stack != NULL) {
2481c99fb5f9SBaptiste Daroussin 				if (parser->stack->obj->type == UCL_OBJECT) {
2482c99fb5f9SBaptiste Daroussin 					parser->state = UCL_STATE_KEY;
2483c99fb5f9SBaptiste Daroussin 				}
2484c99fb5f9SBaptiste Daroussin 				else {
2485c99fb5f9SBaptiste Daroussin 					/* Array */
2486c99fb5f9SBaptiste Daroussin 					parser->state = UCL_STATE_VALUE;
2487c99fb5f9SBaptiste Daroussin 				}
2488c99fb5f9SBaptiste Daroussin 			}
2489c99fb5f9SBaptiste Daroussin 			else {
2490c99fb5f9SBaptiste Daroussin 				/* Skip everything at the end */
2491c99fb5f9SBaptiste Daroussin 				return true;
2492c99fb5f9SBaptiste Daroussin 			}
2493d9f0ce31SBaptiste Daroussin 
2494c99fb5f9SBaptiste Daroussin 			p = chunk->pos;
2495c99fb5f9SBaptiste Daroussin 			break;
2496c99fb5f9SBaptiste Daroussin 		case UCL_STATE_MACRO_NAME:
2497d9f0ce31SBaptiste Daroussin 			if (parser->flags & UCL_PARSER_DISABLE_MACRO) {
2498d9f0ce31SBaptiste Daroussin 				if (!ucl_skip_macro_as_comment (parser, chunk)) {
2499d9f0ce31SBaptiste Daroussin 					/* We have invalid macro */
2500d9f0ce31SBaptiste Daroussin 					ucl_create_err (&parser->err,
2501*a0409676SBaptiste Daroussin 							"error at %s:%d at column %d: invalid macro",
2502*a0409676SBaptiste Daroussin 							chunk->fname ? chunk->fname : "memory",
2503d9f0ce31SBaptiste Daroussin 							chunk->line,
2504d9f0ce31SBaptiste Daroussin 							chunk->column);
2505d9f0ce31SBaptiste Daroussin 					parser->state = UCL_STATE_ERROR;
2506d9f0ce31SBaptiste Daroussin 					return false;
2507d9f0ce31SBaptiste Daroussin 				}
2508d9f0ce31SBaptiste Daroussin 				else {
2509d9f0ce31SBaptiste Daroussin 					p = chunk->pos;
2510d9f0ce31SBaptiste Daroussin 					parser->state = parser->prev_state;
2511d9f0ce31SBaptiste Daroussin 				}
2512d9f0ce31SBaptiste Daroussin 			}
2513d9f0ce31SBaptiste Daroussin 			else {
25144bf54857SBaptiste Daroussin 				if (!ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE) &&
25154bf54857SBaptiste Daroussin 						*p != '(') {
2516c99fb5f9SBaptiste Daroussin 					ucl_chunk_skipc (chunk, p);
2517c99fb5f9SBaptiste Daroussin 				}
251839ee7a7aSBaptiste Daroussin 				else {
2519d9f0ce31SBaptiste Daroussin 					if (c != NULL && p - c > 0) {
2520c99fb5f9SBaptiste Daroussin 						/* We got macro name */
2521c99fb5f9SBaptiste Daroussin 						macro_len = (size_t) (p - c);
2522c99fb5f9SBaptiste Daroussin 						HASH_FIND (hh, parser->macroes, c, macro_len, macro);
2523c99fb5f9SBaptiste Daroussin 						if (macro == NULL) {
252439ee7a7aSBaptiste Daroussin 							ucl_create_err (&parser->err,
2525*a0409676SBaptiste Daroussin 									"error at %s:%d at column %d: "
2526c99fb5f9SBaptiste Daroussin 									"unknown macro: '%.*s', character: '%c'",
2527*a0409676SBaptiste Daroussin 									chunk->fname ? chunk->fname : "memory",
252839ee7a7aSBaptiste Daroussin 									chunk->line,
252939ee7a7aSBaptiste Daroussin 									chunk->column,
253039ee7a7aSBaptiste Daroussin 									(int) (p - c),
253139ee7a7aSBaptiste Daroussin 									c,
253239ee7a7aSBaptiste Daroussin 									*chunk->pos);
2533c99fb5f9SBaptiste Daroussin 							parser->state = UCL_STATE_ERROR;
2534c99fb5f9SBaptiste Daroussin 							return false;
2535c99fb5f9SBaptiste Daroussin 						}
2536c99fb5f9SBaptiste Daroussin 						/* Now we need to skip all spaces */
25374bf54857SBaptiste Daroussin 						SKIP_SPACES_COMMENTS(parser, chunk, p);
2538c99fb5f9SBaptiste Daroussin 						parser->state = UCL_STATE_MACRO;
2539c99fb5f9SBaptiste Daroussin 					}
254039ee7a7aSBaptiste Daroussin 					else {
254139ee7a7aSBaptiste Daroussin 						/* We have invalid macro name */
254239ee7a7aSBaptiste Daroussin 						ucl_create_err (&parser->err,
2543*a0409676SBaptiste Daroussin 								"error at %s:%d at column %d: invalid macro name",
2544*a0409676SBaptiste Daroussin 								chunk->fname ? chunk->fname : "memory",
254539ee7a7aSBaptiste Daroussin 								chunk->line,
254639ee7a7aSBaptiste Daroussin 								chunk->column);
254739ee7a7aSBaptiste Daroussin 						parser->state = UCL_STATE_ERROR;
254839ee7a7aSBaptiste Daroussin 						return false;
254939ee7a7aSBaptiste Daroussin 					}
255039ee7a7aSBaptiste Daroussin 				}
2551d9f0ce31SBaptiste Daroussin 			}
2552c99fb5f9SBaptiste Daroussin 			break;
2553c99fb5f9SBaptiste Daroussin 		case UCL_STATE_MACRO:
25544bf54857SBaptiste Daroussin 			if (*chunk->pos == '(') {
25554bf54857SBaptiste Daroussin 				macro_args = ucl_parse_macro_arguments (parser, chunk);
25564bf54857SBaptiste Daroussin 				p = chunk->pos;
25574bf54857SBaptiste Daroussin 				if (macro_args) {
25584bf54857SBaptiste Daroussin 					SKIP_SPACES_COMMENTS(parser, chunk, p);
25594bf54857SBaptiste Daroussin 				}
25604bf54857SBaptiste Daroussin 			}
25614bf54857SBaptiste Daroussin 			else {
25624bf54857SBaptiste Daroussin 				macro_args = NULL;
25634bf54857SBaptiste Daroussin 			}
2564c99fb5f9SBaptiste Daroussin 			if (!ucl_parse_macro_value (parser, chunk, macro,
2565c99fb5f9SBaptiste Daroussin 					&macro_start, &macro_len)) {
2566c99fb5f9SBaptiste Daroussin 				parser->prev_state = parser->state;
2567c99fb5f9SBaptiste Daroussin 				parser->state = UCL_STATE_ERROR;
2568c99fb5f9SBaptiste Daroussin 				return false;
2569c99fb5f9SBaptiste Daroussin 			}
25704bf54857SBaptiste Daroussin 			macro_len = ucl_expand_variable (parser, &macro_escaped,
25714bf54857SBaptiste Daroussin 					macro_start, macro_len);
2572c99fb5f9SBaptiste Daroussin 			parser->state = parser->prev_state;
2573d9f0ce31SBaptiste Daroussin 
2574d9f0ce31SBaptiste Daroussin 			if (macro_escaped == NULL && macro != NULL) {
257539ee7a7aSBaptiste Daroussin 				if (macro->is_context) {
257639ee7a7aSBaptiste Daroussin 					ret = macro->h.context_handler (macro_start, macro_len,
257739ee7a7aSBaptiste Daroussin 							macro_args,
257839ee7a7aSBaptiste Daroussin 							parser->top_obj,
25794bf54857SBaptiste Daroussin 							macro->ud);
2580c99fb5f9SBaptiste Daroussin 				}
2581c99fb5f9SBaptiste Daroussin 				else {
258239ee7a7aSBaptiste Daroussin 					ret = macro->h.handler (macro_start, macro_len, macro_args,
25834bf54857SBaptiste Daroussin 							macro->ud);
258439ee7a7aSBaptiste Daroussin 				}
258539ee7a7aSBaptiste Daroussin 			}
2586d9f0ce31SBaptiste Daroussin 			else if (macro != NULL) {
258739ee7a7aSBaptiste Daroussin 				if (macro->is_context) {
258839ee7a7aSBaptiste Daroussin 					ret = macro->h.context_handler (macro_escaped, macro_len,
258939ee7a7aSBaptiste Daroussin 							macro_args,
259039ee7a7aSBaptiste Daroussin 							parser->top_obj,
259139ee7a7aSBaptiste Daroussin 							macro->ud);
259239ee7a7aSBaptiste Daroussin 				}
259339ee7a7aSBaptiste Daroussin 				else {
259439ee7a7aSBaptiste Daroussin 					ret = macro->h.handler (macro_escaped, macro_len, macro_args,
259539ee7a7aSBaptiste Daroussin 						macro->ud);
259639ee7a7aSBaptiste Daroussin 				}
259739ee7a7aSBaptiste Daroussin 
2598c99fb5f9SBaptiste Daroussin 				UCL_FREE (macro_len + 1, macro_escaped);
2599c99fb5f9SBaptiste Daroussin 			}
2600d9f0ce31SBaptiste Daroussin 			else {
2601d9f0ce31SBaptiste Daroussin 				ret = false;
2602d9f0ce31SBaptiste Daroussin 				ucl_set_err (parser, UCL_EINTERNAL,
2603d9f0ce31SBaptiste Daroussin 						"internal error: parser has macro undefined", &parser->err);
2604d9f0ce31SBaptiste Daroussin 			}
260539ee7a7aSBaptiste Daroussin 
260639ee7a7aSBaptiste Daroussin 			/*
260739ee7a7aSBaptiste Daroussin 			 * Chunk can be modified within macro handler
260839ee7a7aSBaptiste Daroussin 			 */
260939ee7a7aSBaptiste Daroussin 			chunk = parser->chunks;
2610c99fb5f9SBaptiste Daroussin 			p = chunk->pos;
2611d9f0ce31SBaptiste Daroussin 
26124bf54857SBaptiste Daroussin 			if (macro_args) {
26134bf54857SBaptiste Daroussin 				ucl_object_unref (macro_args);
26144bf54857SBaptiste Daroussin 			}
2615d9f0ce31SBaptiste Daroussin 
26164bf54857SBaptiste Daroussin 			if (!ret) {
26174bf54857SBaptiste Daroussin 				return false;
26184bf54857SBaptiste Daroussin 			}
2619c99fb5f9SBaptiste Daroussin 			break;
2620c99fb5f9SBaptiste Daroussin 		default:
26214bf54857SBaptiste Daroussin 			ucl_set_err (parser, UCL_EINTERNAL,
26224bf54857SBaptiste Daroussin 					"internal error: parser is in an unknown state", &parser->err);
2623c99fb5f9SBaptiste Daroussin 			parser->state = UCL_STATE_ERROR;
2624c99fb5f9SBaptiste Daroussin 			return false;
2625c99fb5f9SBaptiste Daroussin 		}
2626c99fb5f9SBaptiste Daroussin 	}
2627c99fb5f9SBaptiste Daroussin 
2628d9f0ce31SBaptiste Daroussin 	if (parser->last_comment) {
2629d9f0ce31SBaptiste Daroussin 		if (parser->cur_obj) {
2630d9f0ce31SBaptiste Daroussin 			ucl_attach_comment (parser, parser->cur_obj, true);
2631d9f0ce31SBaptiste Daroussin 		}
2632d9f0ce31SBaptiste Daroussin 		else if (parser->stack && parser->stack->obj) {
2633d9f0ce31SBaptiste Daroussin 			ucl_attach_comment (parser, parser->stack->obj, true);
2634d9f0ce31SBaptiste Daroussin 		}
2635d9f0ce31SBaptiste Daroussin 		else if (parser->top_obj) {
2636d9f0ce31SBaptiste Daroussin 			ucl_attach_comment (parser, parser->top_obj, true);
2637d9f0ce31SBaptiste Daroussin 		}
2638d9f0ce31SBaptiste Daroussin 		else {
2639d9f0ce31SBaptiste Daroussin 			ucl_object_unref (parser->last_comment);
2640d9f0ce31SBaptiste Daroussin 		}
2641d9f0ce31SBaptiste Daroussin 	}
2642d9f0ce31SBaptiste Daroussin 
2643*a0409676SBaptiste Daroussin 	if (parser->stack != NULL && parser->state != UCL_STATE_ERROR) {
2644*a0409676SBaptiste Daroussin 		struct ucl_stack *st;
2645*a0409676SBaptiste Daroussin 		bool has_error = false;
2646*a0409676SBaptiste Daroussin 
2647*a0409676SBaptiste Daroussin 		LL_FOREACH (parser->stack, st) {
2648*a0409676SBaptiste Daroussin 			if (st->chunk != parser->chunks) {
2649*a0409676SBaptiste Daroussin 				break; /* Not our chunk, give up */
2650*a0409676SBaptiste Daroussin 			}
2651*a0409676SBaptiste Daroussin 			if (st->e.params.flags & UCL_STACK_HAS_OBRACE) {
2652*a0409676SBaptiste Daroussin 				if (parser->err == NULL) {
2653*a0409676SBaptiste Daroussin 					utstring_new (parser->err);
2654*a0409676SBaptiste Daroussin 				}
2655*a0409676SBaptiste Daroussin 
2656*a0409676SBaptiste Daroussin 				utstring_printf (parser->err, "%s:%d unmatched open brace at %d; ",
2657*a0409676SBaptiste Daroussin 						chunk->fname ? chunk->fname : "memory",
2658*a0409676SBaptiste Daroussin 						parser->chunks->line,
2659*a0409676SBaptiste Daroussin 						st->e.params.line);
2660*a0409676SBaptiste Daroussin 
2661*a0409676SBaptiste Daroussin 				has_error = true;
2662*a0409676SBaptiste Daroussin 			}
2663*a0409676SBaptiste Daroussin 		}
2664*a0409676SBaptiste Daroussin 
2665*a0409676SBaptiste Daroussin 		if (has_error) {
2666*a0409676SBaptiste Daroussin 			parser->err_code = UCL_EUNPAIRED;
2667*a0409676SBaptiste Daroussin 
2668*a0409676SBaptiste Daroussin 			return false;
2669*a0409676SBaptiste Daroussin 		}
2670*a0409676SBaptiste Daroussin 	}
2671*a0409676SBaptiste Daroussin 
2672c99fb5f9SBaptiste Daroussin 	return true;
2673c99fb5f9SBaptiste Daroussin }
2674c99fb5f9SBaptiste Daroussin 
2675*a0409676SBaptiste Daroussin #define UPRM_SAFE(fn, a, b, c, el) do { \
2676*a0409676SBaptiste Daroussin 		if (!fn(a, b, c, a)) \
2677*a0409676SBaptiste Daroussin 			goto el; \
2678*a0409676SBaptiste Daroussin 	} while (0)
2679*a0409676SBaptiste Daroussin 
2680c99fb5f9SBaptiste Daroussin struct ucl_parser*
ucl_parser_new(int flags)2681c99fb5f9SBaptiste Daroussin ucl_parser_new (int flags)
2682c99fb5f9SBaptiste Daroussin {
2683d9f0ce31SBaptiste Daroussin 	struct ucl_parser *parser;
2684c99fb5f9SBaptiste Daroussin 
2685d9f0ce31SBaptiste Daroussin 	parser = UCL_ALLOC (sizeof (struct ucl_parser));
2686d9f0ce31SBaptiste Daroussin 	if (parser == NULL) {
268797bd480fSBaptiste Daroussin 		return NULL;
268897bd480fSBaptiste Daroussin 	}
268939ee7a7aSBaptiste Daroussin 
2690d9f0ce31SBaptiste Daroussin 	memset (parser, 0, sizeof (struct ucl_parser));
2691c99fb5f9SBaptiste Daroussin 
2692*a0409676SBaptiste Daroussin 	UPRM_SAFE(ucl_parser_register_macro, parser, "include", ucl_include_handler, e0);
2693*a0409676SBaptiste Daroussin 	UPRM_SAFE(ucl_parser_register_macro, parser, "try_include", ucl_try_include_handler, e0);
2694*a0409676SBaptiste Daroussin 	UPRM_SAFE(ucl_parser_register_macro, parser, "includes", ucl_includes_handler, e0);
2695*a0409676SBaptiste Daroussin 	UPRM_SAFE(ucl_parser_register_macro, parser, "priority", ucl_priority_handler, e0);
2696*a0409676SBaptiste Daroussin 	UPRM_SAFE(ucl_parser_register_macro, parser, "load", ucl_load_handler, e0);
2697*a0409676SBaptiste Daroussin 	UPRM_SAFE(ucl_parser_register_context_macro, parser, "inherit", ucl_inherit_handler, e0);
2698c99fb5f9SBaptiste Daroussin 
2699d9f0ce31SBaptiste Daroussin 	parser->flags = flags;
2700d9f0ce31SBaptiste Daroussin 	parser->includepaths = NULL;
2701d9f0ce31SBaptiste Daroussin 
2702d9f0ce31SBaptiste Daroussin 	if (flags & UCL_PARSER_SAVE_COMMENTS) {
2703d9f0ce31SBaptiste Daroussin 		parser->comments = ucl_object_typed_new (UCL_OBJECT);
2704d9f0ce31SBaptiste Daroussin 	}
2705c99fb5f9SBaptiste Daroussin 
270611dd9ed6SBaptiste Daroussin 	if (!(flags & UCL_PARSER_NO_FILEVARS)) {
2707c99fb5f9SBaptiste Daroussin 		/* Initial assumption about filevars */
2708d9f0ce31SBaptiste Daroussin 		ucl_parser_set_filevars (parser, NULL, false);
270911dd9ed6SBaptiste Daroussin 	}
2710c99fb5f9SBaptiste Daroussin 
2711d9f0ce31SBaptiste Daroussin 	return parser;
2712*a0409676SBaptiste Daroussin e0:
2713*a0409676SBaptiste Daroussin 	ucl_parser_free(parser);
2714*a0409676SBaptiste Daroussin 	return NULL;
2715c99fb5f9SBaptiste Daroussin }
2716c99fb5f9SBaptiste Daroussin 
271739ee7a7aSBaptiste Daroussin bool
ucl_parser_set_default_priority(struct ucl_parser * parser,unsigned prio)271839ee7a7aSBaptiste Daroussin ucl_parser_set_default_priority (struct ucl_parser *parser, unsigned prio)
271939ee7a7aSBaptiste Daroussin {
272039ee7a7aSBaptiste Daroussin 	if (parser == NULL) {
272139ee7a7aSBaptiste Daroussin 		return false;
272239ee7a7aSBaptiste Daroussin 	}
272339ee7a7aSBaptiste Daroussin 
272439ee7a7aSBaptiste Daroussin 	parser->default_priority = prio;
272539ee7a7aSBaptiste Daroussin 
272639ee7a7aSBaptiste Daroussin 	return true;
272739ee7a7aSBaptiste Daroussin }
2728c99fb5f9SBaptiste Daroussin 
2729*a0409676SBaptiste Daroussin int
ucl_parser_get_default_priority(struct ucl_parser * parser)2730*a0409676SBaptiste Daroussin ucl_parser_get_default_priority (struct ucl_parser *parser)
2731*a0409676SBaptiste Daroussin {
2732*a0409676SBaptiste Daroussin 	if (parser == NULL) {
2733*a0409676SBaptiste Daroussin 		return -1;
2734*a0409676SBaptiste Daroussin 	}
2735*a0409676SBaptiste Daroussin 
2736*a0409676SBaptiste Daroussin 	return parser->default_priority;
2737*a0409676SBaptiste Daroussin }
2738*a0409676SBaptiste Daroussin 
2739*a0409676SBaptiste Daroussin bool
ucl_parser_register_macro(struct ucl_parser * parser,const char * macro,ucl_macro_handler handler,void * ud)2740c99fb5f9SBaptiste Daroussin ucl_parser_register_macro (struct ucl_parser *parser, const char *macro,
2741c99fb5f9SBaptiste Daroussin 		ucl_macro_handler handler, void* ud)
2742c99fb5f9SBaptiste Daroussin {
2743c99fb5f9SBaptiste Daroussin 	struct ucl_macro *new;
2744c99fb5f9SBaptiste Daroussin 
274597bd480fSBaptiste Daroussin 	if (macro == NULL || handler == NULL) {
2746*a0409676SBaptiste Daroussin 		return false;
274797bd480fSBaptiste Daroussin 	}
274839ee7a7aSBaptiste Daroussin 
2749c99fb5f9SBaptiste Daroussin 	new = UCL_ALLOC (sizeof (struct ucl_macro));
275097bd480fSBaptiste Daroussin 	if (new == NULL) {
2751*a0409676SBaptiste Daroussin 		return false;
275297bd480fSBaptiste Daroussin 	}
275339ee7a7aSBaptiste Daroussin 
2754c99fb5f9SBaptiste Daroussin 	memset (new, 0, sizeof (struct ucl_macro));
275539ee7a7aSBaptiste Daroussin 	new->h.handler = handler;
2756c99fb5f9SBaptiste Daroussin 	new->name = strdup (macro);
2757*a0409676SBaptiste Daroussin 	if (new->name == NULL) {
2758*a0409676SBaptiste Daroussin 		UCL_FREE (sizeof (struct ucl_macro), new);
2759*a0409676SBaptiste Daroussin 		return false;
2760*a0409676SBaptiste Daroussin 	}
2761c99fb5f9SBaptiste Daroussin 	new->ud = ud;
2762c99fb5f9SBaptiste Daroussin 	HASH_ADD_KEYPTR (hh, parser->macroes, new->name, strlen (new->name), new);
2763*a0409676SBaptiste Daroussin 	return true;
2764c99fb5f9SBaptiste Daroussin }
2765c99fb5f9SBaptiste Daroussin 
2766*a0409676SBaptiste Daroussin bool
ucl_parser_register_context_macro(struct ucl_parser * parser,const char * macro,ucl_context_macro_handler handler,void * ud)276739ee7a7aSBaptiste Daroussin ucl_parser_register_context_macro (struct ucl_parser *parser, const char *macro,
276839ee7a7aSBaptiste Daroussin 		ucl_context_macro_handler handler, void* ud)
276939ee7a7aSBaptiste Daroussin {
277039ee7a7aSBaptiste Daroussin 	struct ucl_macro *new;
277139ee7a7aSBaptiste Daroussin 
277239ee7a7aSBaptiste Daroussin 	if (macro == NULL || handler == NULL) {
2773*a0409676SBaptiste Daroussin 		return false;
277439ee7a7aSBaptiste Daroussin 	}
277539ee7a7aSBaptiste Daroussin 
277639ee7a7aSBaptiste Daroussin 	new = UCL_ALLOC (sizeof (struct ucl_macro));
277739ee7a7aSBaptiste Daroussin 	if (new == NULL) {
2778*a0409676SBaptiste Daroussin 		return false;
277939ee7a7aSBaptiste Daroussin 	}
278039ee7a7aSBaptiste Daroussin 
278139ee7a7aSBaptiste Daroussin 	memset (new, 0, sizeof (struct ucl_macro));
278239ee7a7aSBaptiste Daroussin 	new->h.context_handler = handler;
278339ee7a7aSBaptiste Daroussin 	new->name = strdup (macro);
2784*a0409676SBaptiste Daroussin 	if (new->name == NULL) {
2785*a0409676SBaptiste Daroussin 		UCL_FREE (sizeof (struct ucl_macro), new);
2786*a0409676SBaptiste Daroussin 		return false;
2787*a0409676SBaptiste Daroussin 	}
278839ee7a7aSBaptiste Daroussin 	new->ud = ud;
278939ee7a7aSBaptiste Daroussin 	new->is_context = true;
279039ee7a7aSBaptiste Daroussin 	HASH_ADD_KEYPTR (hh, parser->macroes, new->name, strlen (new->name), new);
2791*a0409676SBaptiste Daroussin 	return true;
279239ee7a7aSBaptiste Daroussin }
279339ee7a7aSBaptiste Daroussin 
279439ee7a7aSBaptiste Daroussin void
ucl_parser_register_variable(struct ucl_parser * parser,const char * var,const char * value)2795c99fb5f9SBaptiste Daroussin ucl_parser_register_variable (struct ucl_parser *parser, const char *var,
2796c99fb5f9SBaptiste Daroussin 		const char *value)
2797c99fb5f9SBaptiste Daroussin {
2798c99fb5f9SBaptiste Daroussin 	struct ucl_variable *new = NULL, *cur;
2799c99fb5f9SBaptiste Daroussin 
2800c99fb5f9SBaptiste Daroussin 	if (var == NULL) {
2801c99fb5f9SBaptiste Daroussin 		return;
2802c99fb5f9SBaptiste Daroussin 	}
2803c99fb5f9SBaptiste Daroussin 
2804c99fb5f9SBaptiste Daroussin 	/* Find whether a variable already exists */
2805c99fb5f9SBaptiste Daroussin 	LL_FOREACH (parser->variables, cur) {
2806c99fb5f9SBaptiste Daroussin 		if (strcmp (cur->var, var) == 0) {
2807c99fb5f9SBaptiste Daroussin 			new = cur;
2808c99fb5f9SBaptiste Daroussin 			break;
2809c99fb5f9SBaptiste Daroussin 		}
2810c99fb5f9SBaptiste Daroussin 	}
2811c99fb5f9SBaptiste Daroussin 
2812c99fb5f9SBaptiste Daroussin 	if (value == NULL) {
2813c99fb5f9SBaptiste Daroussin 
2814c99fb5f9SBaptiste Daroussin 		if (new != NULL) {
2815c99fb5f9SBaptiste Daroussin 			/* Remove variable */
28164bf54857SBaptiste Daroussin 			DL_DELETE (parser->variables, new);
2817c99fb5f9SBaptiste Daroussin 			free (new->var);
2818c99fb5f9SBaptiste Daroussin 			free (new->value);
2819c99fb5f9SBaptiste Daroussin 			UCL_FREE (sizeof (struct ucl_variable), new);
2820c99fb5f9SBaptiste Daroussin 		}
2821c99fb5f9SBaptiste Daroussin 		else {
2822c99fb5f9SBaptiste Daroussin 			/* Do nothing */
2823c99fb5f9SBaptiste Daroussin 			return;
2824c99fb5f9SBaptiste Daroussin 		}
2825c99fb5f9SBaptiste Daroussin 	}
2826c99fb5f9SBaptiste Daroussin 	else {
2827c99fb5f9SBaptiste Daroussin 		if (new == NULL) {
2828c99fb5f9SBaptiste Daroussin 			new = UCL_ALLOC (sizeof (struct ucl_variable));
282997bd480fSBaptiste Daroussin 			if (new == NULL) {
283097bd480fSBaptiste Daroussin 				return;
283197bd480fSBaptiste Daroussin 			}
2832c99fb5f9SBaptiste Daroussin 			memset (new, 0, sizeof (struct ucl_variable));
2833c99fb5f9SBaptiste Daroussin 			new->var = strdup (var);
2834c99fb5f9SBaptiste Daroussin 			new->var_len = strlen (var);
2835c99fb5f9SBaptiste Daroussin 			new->value = strdup (value);
2836c99fb5f9SBaptiste Daroussin 			new->value_len = strlen (value);
2837c99fb5f9SBaptiste Daroussin 
28384bf54857SBaptiste Daroussin 			DL_APPEND (parser->variables, new);
2839c99fb5f9SBaptiste Daroussin 		}
2840c99fb5f9SBaptiste Daroussin 		else {
2841c99fb5f9SBaptiste Daroussin 			free (new->value);
2842c99fb5f9SBaptiste Daroussin 			new->value = strdup (value);
2843c99fb5f9SBaptiste Daroussin 			new->value_len = strlen (value);
2844c99fb5f9SBaptiste Daroussin 		}
2845c99fb5f9SBaptiste Daroussin 	}
2846c99fb5f9SBaptiste Daroussin }
2847c99fb5f9SBaptiste Daroussin 
28482e8ed2b8SBaptiste Daroussin void
ucl_parser_set_variables_handler(struct ucl_parser * parser,ucl_variable_handler handler,void * ud)28492e8ed2b8SBaptiste Daroussin ucl_parser_set_variables_handler (struct ucl_parser *parser,
28502e8ed2b8SBaptiste Daroussin 		ucl_variable_handler handler, void *ud)
28512e8ed2b8SBaptiste Daroussin {
28522e8ed2b8SBaptiste Daroussin 	parser->var_handler = handler;
28532e8ed2b8SBaptiste Daroussin 	parser->var_data = ud;
28542e8ed2b8SBaptiste Daroussin }
28552e8ed2b8SBaptiste Daroussin 
2856c99fb5f9SBaptiste Daroussin bool
ucl_parser_add_chunk_full(struct ucl_parser * parser,const unsigned char * data,size_t len,unsigned priority,enum ucl_duplicate_strategy strat,enum ucl_parse_type parse_type)285739ee7a7aSBaptiste Daroussin ucl_parser_add_chunk_full (struct ucl_parser *parser, const unsigned char *data,
285839ee7a7aSBaptiste Daroussin 		size_t len, unsigned priority, enum ucl_duplicate_strategy strat,
285939ee7a7aSBaptiste Daroussin 		enum ucl_parse_type parse_type)
2860c99fb5f9SBaptiste Daroussin {
2861c99fb5f9SBaptiste Daroussin 	struct ucl_chunk *chunk;
2862*a0409676SBaptiste Daroussin 	struct ucl_parser_special_handler *special_handler;
2863c99fb5f9SBaptiste Daroussin 
286439ee7a7aSBaptiste Daroussin 	if (parser == NULL) {
286539ee7a7aSBaptiste Daroussin 		return false;
286639ee7a7aSBaptiste Daroussin 	}
286739ee7a7aSBaptiste Daroussin 
28686525738fSBaptiste Daroussin 	if (data == NULL && len != 0) {
2869d9f0ce31SBaptiste Daroussin 		ucl_create_err (&parser->err, "invalid chunk added");
2870d9f0ce31SBaptiste Daroussin 		return false;
2871d9f0ce31SBaptiste Daroussin 	}
2872d9f0ce31SBaptiste Daroussin 
2873c99fb5f9SBaptiste Daroussin 	if (parser->state != UCL_STATE_ERROR) {
2874c99fb5f9SBaptiste Daroussin 		chunk = UCL_ALLOC (sizeof (struct ucl_chunk));
287597bd480fSBaptiste Daroussin 		if (chunk == NULL) {
287697bd480fSBaptiste Daroussin 			ucl_create_err (&parser->err, "cannot allocate chunk structure");
287797bd480fSBaptiste Daroussin 			return false;
287897bd480fSBaptiste Daroussin 		}
28796525738fSBaptiste Daroussin 
2880*a0409676SBaptiste Daroussin 		memset (chunk, 0, sizeof (*chunk));
2881*a0409676SBaptiste Daroussin 
2882*a0409676SBaptiste Daroussin 		/* Apply all matching handlers from the first to the last */
2883*a0409676SBaptiste Daroussin 		LL_FOREACH (parser->special_handlers, special_handler) {
2884*a0409676SBaptiste Daroussin 			if ((special_handler->flags & UCL_SPECIAL_HANDLER_PREPROCESS_ALL) ||
2885*a0409676SBaptiste Daroussin 					(len >= special_handler->magic_len &&
2886*a0409676SBaptiste Daroussin 					 memcmp (data, special_handler->magic, special_handler->magic_len) == 0)) {
2887*a0409676SBaptiste Daroussin 				unsigned char *ndata = NULL;
2888*a0409676SBaptiste Daroussin 				size_t nlen = 0;
2889*a0409676SBaptiste Daroussin 
2890*a0409676SBaptiste Daroussin 				if (!special_handler->handler (parser, data, len, &ndata, &nlen,
2891*a0409676SBaptiste Daroussin 						special_handler->user_data)) {
2892*a0409676SBaptiste Daroussin 					ucl_create_err (&parser->err, "call for external handler failed");
2893*a0409676SBaptiste Daroussin 					return false;
2894*a0409676SBaptiste Daroussin 				}
2895*a0409676SBaptiste Daroussin 
2896*a0409676SBaptiste Daroussin 				struct ucl_parser_special_handler_chain *nchain;
2897*a0409676SBaptiste Daroussin 				nchain = UCL_ALLOC (sizeof (*nchain));
2898*a0409676SBaptiste Daroussin 				nchain->begin = ndata;
2899*a0409676SBaptiste Daroussin 				nchain->len = nlen;
2900*a0409676SBaptiste Daroussin 				nchain->special_handler = special_handler;
2901*a0409676SBaptiste Daroussin 
2902*a0409676SBaptiste Daroussin 				/* Free order is reversed */
2903*a0409676SBaptiste Daroussin 				LL_PREPEND (chunk->special_handlers, nchain);
2904*a0409676SBaptiste Daroussin 
2905*a0409676SBaptiste Daroussin 				data = ndata;
2906*a0409676SBaptiste Daroussin 				len = nlen;
2907*a0409676SBaptiste Daroussin 			}
2908*a0409676SBaptiste Daroussin 		}
2909*a0409676SBaptiste Daroussin 
291011dd9ed6SBaptiste Daroussin 		if (parse_type == UCL_PARSE_AUTO && len > 0) {
291111dd9ed6SBaptiste Daroussin 			/* We need to detect parse type by the first symbol */
291211dd9ed6SBaptiste Daroussin 			if ((*data & 0x80) == 0x80 && (*data >= 0xdc && *data <= 0xdf)) {
291311dd9ed6SBaptiste Daroussin 				parse_type = UCL_PARSE_MSGPACK;
291411dd9ed6SBaptiste Daroussin 			}
291511dd9ed6SBaptiste Daroussin 			else if (*data == '(') {
291611dd9ed6SBaptiste Daroussin 				parse_type = UCL_PARSE_CSEXP;
291711dd9ed6SBaptiste Daroussin 			}
291811dd9ed6SBaptiste Daroussin 			else {
291911dd9ed6SBaptiste Daroussin 				parse_type = UCL_PARSE_UCL;
292011dd9ed6SBaptiste Daroussin 			}
292111dd9ed6SBaptiste Daroussin 		}
292211dd9ed6SBaptiste Daroussin 
2923c99fb5f9SBaptiste Daroussin 		chunk->begin = data;
2924c99fb5f9SBaptiste Daroussin 		chunk->remain = len;
2925c99fb5f9SBaptiste Daroussin 		chunk->pos = chunk->begin;
2926c99fb5f9SBaptiste Daroussin 		chunk->end = chunk->begin + len;
2927c99fb5f9SBaptiste Daroussin 		chunk->line = 1;
2928c99fb5f9SBaptiste Daroussin 		chunk->column = 0;
29294bf54857SBaptiste Daroussin 		chunk->priority = priority;
293039ee7a7aSBaptiste Daroussin 		chunk->strategy = strat;
293139ee7a7aSBaptiste Daroussin 		chunk->parse_type = parse_type;
2932*a0409676SBaptiste Daroussin 
2933*a0409676SBaptiste Daroussin 		if (parser->cur_file) {
2934*a0409676SBaptiste Daroussin 			chunk->fname = strdup (parser->cur_file);
2935*a0409676SBaptiste Daroussin 		}
2936*a0409676SBaptiste Daroussin 
2937c99fb5f9SBaptiste Daroussin 		LL_PREPEND (parser->chunks, chunk);
2938c99fb5f9SBaptiste Daroussin 		parser->recursion ++;
293939ee7a7aSBaptiste Daroussin 
2940c99fb5f9SBaptiste Daroussin 		if (parser->recursion > UCL_MAX_RECURSION) {
2941c99fb5f9SBaptiste Daroussin 			ucl_create_err (&parser->err, "maximum include nesting limit is reached: %d",
2942c99fb5f9SBaptiste Daroussin 					parser->recursion);
2943c99fb5f9SBaptiste Daroussin 			return false;
2944c99fb5f9SBaptiste Daroussin 		}
294539ee7a7aSBaptiste Daroussin 
29466525738fSBaptiste Daroussin 		if (len > 0) {
29476525738fSBaptiste Daroussin 			/* Need to parse something */
294839ee7a7aSBaptiste Daroussin 			switch (parse_type) {
294939ee7a7aSBaptiste Daroussin 			default:
295039ee7a7aSBaptiste Daroussin 			case UCL_PARSE_UCL:
2951c99fb5f9SBaptiste Daroussin 				return ucl_state_machine (parser);
295239ee7a7aSBaptiste Daroussin 			case UCL_PARSE_MSGPACK:
295339ee7a7aSBaptiste Daroussin 				return ucl_parse_msgpack (parser);
295411dd9ed6SBaptiste Daroussin 			case UCL_PARSE_CSEXP:
295511dd9ed6SBaptiste Daroussin 				return ucl_parse_csexp (parser);
295639ee7a7aSBaptiste Daroussin 			}
2957c99fb5f9SBaptiste Daroussin 		}
29586525738fSBaptiste Daroussin 		else {
29596525738fSBaptiste Daroussin 			/* Just add empty chunk and go forward */
29606525738fSBaptiste Daroussin 			if (parser->top_obj == NULL) {
29616525738fSBaptiste Daroussin 				/*
29626525738fSBaptiste Daroussin 				 * In case of empty object, create one to indicate that we've
29636525738fSBaptiste Daroussin 				 * read something
29646525738fSBaptiste Daroussin 				 */
29656525738fSBaptiste Daroussin 				parser->top_obj = ucl_object_new_full (UCL_OBJECT, priority);
29666525738fSBaptiste Daroussin 			}
29676525738fSBaptiste Daroussin 
29686525738fSBaptiste Daroussin 			return true;
29696525738fSBaptiste Daroussin 		}
29706525738fSBaptiste Daroussin 	}
2971c99fb5f9SBaptiste Daroussin 
2972c99fb5f9SBaptiste Daroussin 	ucl_create_err (&parser->err, "a parser is in an invalid state");
2973c99fb5f9SBaptiste Daroussin 
2974c99fb5f9SBaptiste Daroussin 	return false;
2975c99fb5f9SBaptiste Daroussin }
297697bd480fSBaptiste Daroussin 
297797bd480fSBaptiste Daroussin bool
ucl_parser_add_chunk_priority(struct ucl_parser * parser,const unsigned char * data,size_t len,unsigned priority)297839ee7a7aSBaptiste Daroussin ucl_parser_add_chunk_priority (struct ucl_parser *parser,
297939ee7a7aSBaptiste Daroussin 		const unsigned char *data, size_t len, unsigned priority)
29804bf54857SBaptiste Daroussin {
298139ee7a7aSBaptiste Daroussin 	/* We dereference parser, so this check is essential */
298239ee7a7aSBaptiste Daroussin 	if (parser == NULL) {
298339ee7a7aSBaptiste Daroussin 		return false;
298439ee7a7aSBaptiste Daroussin 	}
298539ee7a7aSBaptiste Daroussin 
298639ee7a7aSBaptiste Daroussin 	return ucl_parser_add_chunk_full (parser, data, len,
298739ee7a7aSBaptiste Daroussin 				priority, UCL_DUPLICATE_APPEND, UCL_PARSE_UCL);
29884bf54857SBaptiste Daroussin }
29894bf54857SBaptiste Daroussin 
29904bf54857SBaptiste Daroussin bool
ucl_parser_add_chunk(struct ucl_parser * parser,const unsigned char * data,size_t len)299139ee7a7aSBaptiste Daroussin ucl_parser_add_chunk (struct ucl_parser *parser, const unsigned char *data,
299297bd480fSBaptiste Daroussin 		size_t len)
299397bd480fSBaptiste Daroussin {
299439ee7a7aSBaptiste Daroussin 	if (parser == NULL) {
299539ee7a7aSBaptiste Daroussin 		return false;
299639ee7a7aSBaptiste Daroussin 	}
299739ee7a7aSBaptiste Daroussin 
299839ee7a7aSBaptiste Daroussin 	return ucl_parser_add_chunk_full (parser, data, len,
299939ee7a7aSBaptiste Daroussin 			parser->default_priority, UCL_DUPLICATE_APPEND, UCL_PARSE_UCL);
300039ee7a7aSBaptiste Daroussin }
300139ee7a7aSBaptiste Daroussin 
300239ee7a7aSBaptiste Daroussin bool
ucl_parser_insert_chunk(struct ucl_parser * parser,const unsigned char * data,size_t len)3003*a0409676SBaptiste Daroussin ucl_parser_insert_chunk (struct ucl_parser *parser, const unsigned char *data,
3004*a0409676SBaptiste Daroussin 		size_t len)
3005*a0409676SBaptiste Daroussin {
3006*a0409676SBaptiste Daroussin 	if (parser == NULL || parser->top_obj == NULL) {
3007*a0409676SBaptiste Daroussin 		return false;
3008*a0409676SBaptiste Daroussin 	}
3009*a0409676SBaptiste Daroussin 
3010*a0409676SBaptiste Daroussin 	bool res;
3011*a0409676SBaptiste Daroussin 	struct ucl_chunk *chunk;
3012*a0409676SBaptiste Daroussin 
3013*a0409676SBaptiste Daroussin 	int state = parser->state;
3014*a0409676SBaptiste Daroussin 	parser->state = UCL_STATE_INIT;
3015*a0409676SBaptiste Daroussin 
3016*a0409676SBaptiste Daroussin 	/* Prevent inserted chunks from unintentionally closing the current object */
3017*a0409676SBaptiste Daroussin 	if (parser->stack != NULL && parser->stack->next != NULL) {
3018*a0409676SBaptiste Daroussin 		parser->stack->e.params.level = parser->stack->next->e.params.level;
3019*a0409676SBaptiste Daroussin 	}
3020*a0409676SBaptiste Daroussin 
3021*a0409676SBaptiste Daroussin 	res = ucl_parser_add_chunk_full (parser, data, len, parser->chunks->priority,
3022*a0409676SBaptiste Daroussin 					parser->chunks->strategy, parser->chunks->parse_type);
3023*a0409676SBaptiste Daroussin 
3024*a0409676SBaptiste Daroussin 	/* Remove chunk from the stack */
3025*a0409676SBaptiste Daroussin 	chunk = parser->chunks;
3026*a0409676SBaptiste Daroussin 	if (chunk != NULL) {
3027*a0409676SBaptiste Daroussin 		parser->chunks = chunk->next;
3028*a0409676SBaptiste Daroussin 		ucl_chunk_free (chunk);
3029*a0409676SBaptiste Daroussin 		parser->recursion --;
3030*a0409676SBaptiste Daroussin 	}
3031*a0409676SBaptiste Daroussin 
3032*a0409676SBaptiste Daroussin 	parser->state = state;
3033*a0409676SBaptiste Daroussin 
3034*a0409676SBaptiste Daroussin 	return res;
3035*a0409676SBaptiste Daroussin }
3036*a0409676SBaptiste Daroussin 
3037*a0409676SBaptiste Daroussin bool
ucl_parser_add_string_priority(struct ucl_parser * parser,const char * data,size_t len,unsigned priority)303839ee7a7aSBaptiste Daroussin ucl_parser_add_string_priority (struct ucl_parser *parser, const char *data,
303939ee7a7aSBaptiste Daroussin 		size_t len, unsigned priority)
304039ee7a7aSBaptiste Daroussin {
304197bd480fSBaptiste Daroussin 	if (data == NULL) {
304297bd480fSBaptiste Daroussin 		ucl_create_err (&parser->err, "invalid string added");
304397bd480fSBaptiste Daroussin 		return false;
304497bd480fSBaptiste Daroussin 	}
304597bd480fSBaptiste Daroussin 	if (len == 0) {
304697bd480fSBaptiste Daroussin 		len = strlen (data);
304797bd480fSBaptiste Daroussin 	}
304897bd480fSBaptiste Daroussin 
304939ee7a7aSBaptiste Daroussin 	return ucl_parser_add_chunk_priority (parser,
305039ee7a7aSBaptiste Daroussin 			(const unsigned char *)data, len, priority);
305139ee7a7aSBaptiste Daroussin }
305239ee7a7aSBaptiste Daroussin 
305339ee7a7aSBaptiste Daroussin bool
ucl_parser_add_string(struct ucl_parser * parser,const char * data,size_t len)305439ee7a7aSBaptiste Daroussin ucl_parser_add_string (struct ucl_parser *parser, const char *data,
305539ee7a7aSBaptiste Daroussin 		size_t len)
305639ee7a7aSBaptiste Daroussin {
305739ee7a7aSBaptiste Daroussin 	if (parser == NULL) {
305839ee7a7aSBaptiste Daroussin 		return false;
305939ee7a7aSBaptiste Daroussin 	}
306039ee7a7aSBaptiste Daroussin 
306139ee7a7aSBaptiste Daroussin 	return ucl_parser_add_string_priority (parser,
306239ee7a7aSBaptiste Daroussin 			(const unsigned char *)data, len, parser->default_priority);
306339ee7a7aSBaptiste Daroussin }
306439ee7a7aSBaptiste Daroussin 
306539ee7a7aSBaptiste Daroussin bool
ucl_set_include_path(struct ucl_parser * parser,ucl_object_t * paths)306639ee7a7aSBaptiste Daroussin ucl_set_include_path (struct ucl_parser *parser, ucl_object_t *paths)
306739ee7a7aSBaptiste Daroussin {
306839ee7a7aSBaptiste Daroussin 	if (parser == NULL || paths == NULL) {
306939ee7a7aSBaptiste Daroussin 		return false;
307039ee7a7aSBaptiste Daroussin 	}
307139ee7a7aSBaptiste Daroussin 
307239ee7a7aSBaptiste Daroussin 	if (parser->includepaths == NULL) {
307339ee7a7aSBaptiste Daroussin 		parser->includepaths = ucl_object_copy (paths);
307439ee7a7aSBaptiste Daroussin 	}
307539ee7a7aSBaptiste Daroussin 	else {
307639ee7a7aSBaptiste Daroussin 		ucl_object_unref (parser->includepaths);
307739ee7a7aSBaptiste Daroussin 		parser->includepaths = ucl_object_copy (paths);
307839ee7a7aSBaptiste Daroussin 	}
307939ee7a7aSBaptiste Daroussin 
308039ee7a7aSBaptiste Daroussin 	if (parser->includepaths == NULL) {
308139ee7a7aSBaptiste Daroussin 		return false;
308239ee7a7aSBaptiste Daroussin 	}
308339ee7a7aSBaptiste Daroussin 
308439ee7a7aSBaptiste Daroussin 	return true;
308597bd480fSBaptiste Daroussin }
3086*a0409676SBaptiste Daroussin 
ucl_parser_chunk_peek(struct ucl_parser * parser)3087*a0409676SBaptiste Daroussin unsigned char ucl_parser_chunk_peek (struct ucl_parser *parser)
3088*a0409676SBaptiste Daroussin {
3089*a0409676SBaptiste Daroussin 	if (parser == NULL || parser->chunks == NULL || parser->chunks->pos == NULL || parser->chunks->end == NULL ||
3090*a0409676SBaptiste Daroussin 		parser->chunks->pos == parser->chunks->end) {
3091*a0409676SBaptiste Daroussin 		return 0;
3092*a0409676SBaptiste Daroussin 	}
3093*a0409676SBaptiste Daroussin 
3094*a0409676SBaptiste Daroussin 	return( *parser->chunks->pos );
3095*a0409676SBaptiste Daroussin }
3096*a0409676SBaptiste Daroussin 
ucl_parser_chunk_skip(struct ucl_parser * parser)3097*a0409676SBaptiste Daroussin bool ucl_parser_chunk_skip (struct ucl_parser *parser)
3098*a0409676SBaptiste Daroussin {
3099*a0409676SBaptiste Daroussin 	if (parser == NULL || parser->chunks == NULL || parser->chunks->pos == NULL || parser->chunks->end == NULL ||
3100*a0409676SBaptiste Daroussin 		parser->chunks->pos == parser->chunks->end) {
3101*a0409676SBaptiste Daroussin 		return false;
3102*a0409676SBaptiste Daroussin 	}
3103*a0409676SBaptiste Daroussin 
3104*a0409676SBaptiste Daroussin 	const unsigned char *p = parser->chunks->pos;
3105*a0409676SBaptiste Daroussin 	ucl_chunk_skipc( parser->chunks, p );
3106*a0409676SBaptiste Daroussin 	if( parser->chunks->pos != NULL ) return true;
3107*a0409676SBaptiste Daroussin 	return false;
3108*a0409676SBaptiste Daroussin }
3109*a0409676SBaptiste Daroussin 
3110*a0409676SBaptiste Daroussin ucl_object_t*
ucl_parser_get_current_stack_object(struct ucl_parser * parser,unsigned int depth)3111*a0409676SBaptiste Daroussin ucl_parser_get_current_stack_object (struct ucl_parser *parser, unsigned int depth)
3112*a0409676SBaptiste Daroussin {
3113*a0409676SBaptiste Daroussin 	ucl_object_t *obj;
3114*a0409676SBaptiste Daroussin 
3115*a0409676SBaptiste Daroussin 	if (parser == NULL || parser->stack == NULL) {
3116*a0409676SBaptiste Daroussin 		return NULL;
3117*a0409676SBaptiste Daroussin 	}
3118*a0409676SBaptiste Daroussin 
3119*a0409676SBaptiste Daroussin 	struct ucl_stack *stack = parser->stack;
3120*a0409676SBaptiste Daroussin 	if(stack == NULL || stack->obj == NULL || ucl_object_type (stack->obj) != UCL_OBJECT)
3121*a0409676SBaptiste Daroussin 	{
3122*a0409676SBaptiste Daroussin 		return NULL;
3123*a0409676SBaptiste Daroussin 	}
3124*a0409676SBaptiste Daroussin 
3125*a0409676SBaptiste Daroussin 	for( unsigned int i = 0; i < depth; ++i )
3126*a0409676SBaptiste Daroussin 	{
3127*a0409676SBaptiste Daroussin 		stack = stack->next;
3128*a0409676SBaptiste Daroussin 		if(stack == NULL || stack->obj == NULL || ucl_object_type (stack->obj) != UCL_OBJECT)
3129*a0409676SBaptiste Daroussin 		{
3130*a0409676SBaptiste Daroussin 			return NULL;
3131*a0409676SBaptiste Daroussin 		}
3132*a0409676SBaptiste Daroussin 	}
3133*a0409676SBaptiste Daroussin 
3134*a0409676SBaptiste Daroussin 	obj = ucl_object_ref (stack->obj);
3135*a0409676SBaptiste Daroussin 	return obj;
3136*a0409676SBaptiste Daroussin }
3137*a0409676SBaptiste Daroussin 
3138