]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/libucl/src/ucl_parser.c
MFV: r362286
[FreeBSD/FreeBSD.git] / contrib / libucl / src / ucl_parser.c
1 /* Copyright (c) 2013, Vsevolod Stakhov
2  * All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6  *       * Redistributions of source code must retain the above copyright
7  *         notice, this list of conditions and the following disclaimer.
8  *       * Redistributions in binary form must reproduce the above copyright
9  *         notice, this list of conditions and the following disclaimer in the
10  *         documentation and/or other materials provided with the distribution.
11  *
12  * THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY
13  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
14  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
15  * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY
16  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
17  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
18  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
19  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
20  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
21  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
22  */
23
24 #include "ucl.h"
25 #include "ucl_internal.h"
26 #include "ucl_chartable.h"
27
28 /**
29  * @file ucl_parser.c
30  * The implementation of ucl parser
31  */
32
33 struct ucl_parser_saved_state {
34         unsigned int line;
35         unsigned int column;
36         size_t remain;
37         const unsigned char *pos;
38 };
39
40 /**
41  * Move up to len characters
42  * @param parser
43  * @param begin
44  * @param len
45  * @return new position in chunk
46  */
47 #define ucl_chunk_skipc(chunk, p)    do{                                        \
48     if (*(p) == '\n') {                                                                         \
49         (chunk)->line ++;                                                                       \
50         (chunk)->column = 0;                                                            \
51     }                                                                                                           \
52     else (chunk)->column ++;                                                            \
53     (p++);                                                                                                      \
54     (chunk)->pos ++;                                                                            \
55     (chunk)->remain --;                                                                         \
56     } while (0)
57
58 static inline void
59 ucl_set_err (struct ucl_parser *parser, int code, const char *str, UT_string **err)
60 {
61         const char *fmt_string, *filename;
62         struct ucl_chunk *chunk = parser->chunks;
63
64         if (parser->cur_file) {
65                 filename = parser->cur_file;
66         }
67         else {
68                 filename = "<unknown>";
69         }
70
71         if (chunk->pos < chunk->end) {
72                 if (isgraph (*chunk->pos)) {
73                         fmt_string = "error while parsing %s: "
74                                         "line: %d, column: %d - '%s', character: '%c'";
75                 }
76                 else {
77                         fmt_string = "error while parsing %s: "
78                                         "line: %d, column: %d - '%s', character: '0x%02x'";
79                 }
80                 ucl_create_err (err, fmt_string,
81                         filename, chunk->line, chunk->column,
82                         str, *chunk->pos);
83         }
84         else {
85                 ucl_create_err (err, "error while parsing %s: at the end of chunk: %s",
86                         filename, str);
87         }
88
89         parser->err_code = code;
90 }
91
92 static void
93 ucl_save_comment (struct ucl_parser *parser, const char *begin, size_t len)
94 {
95         ucl_object_t *nobj;
96
97         if (len > 0 && begin != NULL) {
98                 nobj = ucl_object_fromstring_common (begin, len, 0);
99
100                 if (parser->last_comment) {
101                         /* We need to append data to an existing object */
102                         DL_APPEND (parser->last_comment, nobj);
103                 }
104                 else {
105                         parser->last_comment = nobj;
106                 }
107         }
108 }
109
110 static void
111 ucl_attach_comment (struct ucl_parser *parser, ucl_object_t *obj, bool before)
112 {
113         if (parser->last_comment) {
114                 ucl_object_insert_key (parser->comments, parser->last_comment,
115                                 (const char *)&obj, sizeof (void *), true);
116
117                 if (before) {
118                         parser->last_comment->flags |= UCL_OBJECT_INHERITED;
119                 }
120
121                 parser->last_comment = NULL;
122         }
123 }
124
125 /**
126  * Skip all comments from the current pos resolving nested and multiline comments
127  * @param parser
128  * @return
129  */
130 static bool
131 ucl_skip_comments (struct ucl_parser *parser)
132 {
133         struct ucl_chunk *chunk = parser->chunks;
134         const unsigned char *p, *beg = NULL;
135         int comments_nested = 0;
136         bool quoted = false;
137
138         p = chunk->pos;
139
140 start:
141         if (chunk->remain > 0 && *p == '#') {
142                 if (parser->state != UCL_STATE_SCOMMENT &&
143                                 parser->state != UCL_STATE_MCOMMENT) {
144                         beg = p;
145
146                         while (p < chunk->end) {
147                                 if (*p == '\n') {
148                                         if (parser->flags & UCL_PARSER_SAVE_COMMENTS) {
149                                                 ucl_save_comment (parser, beg, p - beg);
150                                                 beg = NULL;
151                                         }
152
153                                         ucl_chunk_skipc (chunk, p);
154
155                                         goto start;
156                                 }
157                                 ucl_chunk_skipc (chunk, p);
158                         }
159                 }
160         }
161         else if (chunk->remain >= 2 && *p == '/') {
162                 if (p[1] == '*') {
163                         beg = p;
164                         ucl_chunk_skipc (chunk, p);
165                         comments_nested ++;
166                         ucl_chunk_skipc (chunk, p);
167
168                         while (p < chunk->end) {
169                                 if (*p == '"' && *(p - 1) != '\\') {
170                                         quoted = !quoted;
171                                 }
172
173                                 if (!quoted) {
174                                         if (*p == '*') {
175                                                 ucl_chunk_skipc (chunk, p);
176                                                 if (*p == '/') {
177                                                         comments_nested --;
178                                                         if (comments_nested == 0) {
179                                                                 if (parser->flags & UCL_PARSER_SAVE_COMMENTS) {
180                                                                         ucl_save_comment (parser, beg, p - beg + 1);
181                                                                         beg = NULL;
182                                                                 }
183
184                                                                 ucl_chunk_skipc (chunk, p);
185                                                                 goto start;
186                                                         }
187                                                 }
188                                                 ucl_chunk_skipc (chunk, p);
189                                         }
190                                         else if (p[0] == '/' && chunk->remain >= 2 && p[1] == '*') {
191                                                 comments_nested ++;
192                                                 ucl_chunk_skipc (chunk, p);
193                                                 ucl_chunk_skipc (chunk, p);
194                                                 continue;
195                                         }
196                                 }
197
198                                 ucl_chunk_skipc (chunk, p);
199                         }
200                         if (comments_nested != 0) {
201                                 ucl_set_err (parser, UCL_ENESTED,
202                                                 "unfinished multiline comment", &parser->err);
203                                 return false;
204                         }
205                 }
206         }
207
208         if (beg && p > beg && (parser->flags & UCL_PARSER_SAVE_COMMENTS)) {
209                 ucl_save_comment (parser, beg, p - beg);
210         }
211
212         return true;
213 }
214
215 /**
216  * Return multiplier for a character
217  * @param c multiplier character
218  * @param is_bytes if true use 1024 multiplier
219  * @return multiplier
220  */
221 static inline unsigned long
222 ucl_lex_num_multiplier (const unsigned char c, bool is_bytes) {
223         const struct {
224                 char c;
225                 long mult_normal;
226                 long mult_bytes;
227         } multipliers[] = {
228                         {'m', 1000 * 1000, 1024 * 1024},
229                         {'k', 1000, 1024},
230                         {'g', 1000 * 1000 * 1000, 1024 * 1024 * 1024}
231         };
232         int i;
233
234         for (i = 0; i < 3; i ++) {
235                 if (tolower (c) == multipliers[i].c) {
236                         if (is_bytes) {
237                                 return multipliers[i].mult_bytes;
238                         }
239                         return multipliers[i].mult_normal;
240                 }
241         }
242
243         return 1;
244 }
245
246
247 /**
248  * Return multiplier for time scaling
249  * @param c
250  * @return
251  */
252 static inline double
253 ucl_lex_time_multiplier (const unsigned char c) {
254         const struct {
255                 char c;
256                 double mult;
257         } multipliers[] = {
258                         {'m', 60},
259                         {'h', 60 * 60},
260                         {'d', 60 * 60 * 24},
261                         {'w', 60 * 60 * 24 * 7},
262                         {'y', 60 * 60 * 24 * 365}
263         };
264         int i;
265
266         for (i = 0; i < 5; i ++) {
267                 if (tolower (c) == multipliers[i].c) {
268                         return multipliers[i].mult;
269                 }
270         }
271
272         return 1;
273 }
274
275 /**
276  * Return true if a character is a end of an atom
277  * @param c
278  * @return
279  */
280 static inline bool
281 ucl_lex_is_atom_end (const unsigned char c)
282 {
283         return ucl_test_character (c, UCL_CHARACTER_VALUE_END);
284 }
285
286 static inline bool
287 ucl_lex_is_comment (const unsigned char c1, const unsigned char c2)
288 {
289         if (c1 == '/') {
290                 if (c2 == '*') {
291                         return true;
292                 }
293         }
294         else if (c1 == '#') {
295                 return true;
296         }
297         return false;
298 }
299
300 /**
301  * Check variable found
302  * @param parser
303  * @param ptr
304  * @param remain
305  * @param out_len
306  * @param strict
307  * @param found
308  * @return
309  */
310 static inline const char *
311 ucl_check_variable_safe (struct ucl_parser *parser, const char *ptr, size_t remain,
312                 size_t *out_len, bool strict, bool *found)
313 {
314         struct ucl_variable *var;
315         unsigned char *dst;
316         size_t dstlen;
317         bool need_free = false;
318
319         LL_FOREACH (parser->variables, var) {
320                 if (strict) {
321                         if (remain == var->var_len) {
322                                 if (memcmp (ptr, var->var, var->var_len) == 0) {
323                                         *out_len += var->value_len;
324                                         *found = true;
325                                         return (ptr + var->var_len);
326                                 }
327                         }
328                 }
329                 else {
330                         if (remain >= var->var_len) {
331                                 if (memcmp (ptr, var->var, var->var_len) == 0) {
332                                         *out_len += var->value_len;
333                                         *found = true;
334                                         return (ptr + var->var_len);
335                                 }
336                         }
337                 }
338         }
339
340         /* XXX: can only handle ${VAR} */
341         if (!(*found) && parser->var_handler != NULL && strict) {
342                 /* Call generic handler */
343                 if (parser->var_handler (ptr, remain, &dst, &dstlen, &need_free,
344                                 parser->var_data)) {
345                         *out_len += dstlen;
346                         *found = true;
347                         if (need_free) {
348                                 free (dst);
349                         }
350                         return (ptr + remain);
351                 }
352         }
353
354         return ptr;
355 }
356
357 /**
358  * Check for a variable in a given string
359  * @param parser
360  * @param ptr
361  * @param remain
362  * @param out_len
363  * @param vars_found
364  * @return
365  */
366 static const char *
367 ucl_check_variable (struct ucl_parser *parser, const char *ptr,
368                 size_t remain, size_t *out_len, bool *vars_found)
369 {
370         const char *p, *end, *ret = ptr;
371         bool found = false;
372
373         if (*ptr == '{') {
374                 /* We need to match the variable enclosed in braces */
375                 p = ptr + 1;
376                 end = ptr + remain;
377                 while (p < end) {
378                         if (*p == '}') {
379                                 ret = ucl_check_variable_safe (parser, ptr + 1, p - ptr - 1,
380                                                 out_len, true, &found);
381                                 if (found) {
382                                         /* {} must be excluded actually */
383                                         ret ++;
384                                         if (!*vars_found) {
385                                                 *vars_found = true;
386                                         }
387                                 }
388                                 else {
389                                         *out_len += 2;
390                                 }
391                                 break;
392                         }
393                         p ++;
394                 }
395         }
396         else if (*ptr != '$') {
397                 /* Not count escaped dollar sign */
398                 ret = ucl_check_variable_safe (parser, ptr, remain, out_len, false, &found);
399                 if (found && !*vars_found) {
400                         *vars_found = true;
401                 }
402                 if (!found) {
403                         (*out_len) ++;
404                 }
405         }
406         else {
407                 ret ++;
408                 (*out_len) ++;
409         }
410
411         return ret;
412 }
413
414 /**
415  * Expand a single variable
416  * @param parser
417  * @param ptr
418  * @param remain
419  * @param dest
420  * @return
421  */
422 static const char *
423 ucl_expand_single_variable (struct ucl_parser *parser, const char *ptr,
424                 size_t remain, unsigned char **dest)
425 {
426         unsigned char *d = *dest, *dst;
427         const char *p = ptr + 1, *ret;
428         struct ucl_variable *var;
429         size_t dstlen;
430         bool need_free = false;
431         bool found = false;
432         bool strict = false;
433
434         ret = ptr + 1;
435         remain --;
436
437         if (*p == '$') {
438                 *d++ = *p++;
439                 *dest = d;
440                 return p;
441         }
442         else if (*p == '{') {
443                 p ++;
444                 strict = true;
445                 ret += 2;
446                 remain -= 2;
447         }
448
449         LL_FOREACH (parser->variables, var) {
450                 if (remain >= var->var_len) {
451                         if (memcmp (p, var->var, var->var_len) == 0) {
452                                 memcpy (d, var->value, var->value_len);
453                                 ret += var->var_len;
454                                 d += var->value_len;
455                                 found = true;
456                                 break;
457                         }
458                 }
459         }
460         if (!found) {
461                 if (strict && parser->var_handler != NULL) {
462                         size_t var_len = 0;
463                         while (var_len < remain && p[var_len] != '}')
464                                 var_len ++;
465
466                         if (parser->var_handler (p, var_len, &dst, &dstlen, &need_free,
467                                                         parser->var_data)) {
468                                 memcpy (d, dst, dstlen);
469                                 ret += var_len;
470                                 d += dstlen;
471                                 if (need_free) {
472                                         free (dst);
473                                 }
474                                 found = true;
475                         }
476                 }
477
478                 /* Leave variable as is */
479                 if (!found) {
480                         if (strict) {
481                                 /* Copy '${' */
482                                 memcpy (d, ptr, 2);
483                                 d += 2;
484                                 ret --;
485                         }
486                         else {
487                                 memcpy (d, ptr, 1);
488                                 d ++;
489                         }
490                 }
491         }
492
493         *dest = d;
494         return ret;
495 }
496
497 /**
498  * Expand variables in string
499  * @param parser
500  * @param dst
501  * @param src
502  * @param in_len
503  * @return
504  */
505 static ssize_t
506 ucl_expand_variable (struct ucl_parser *parser, unsigned char **dst,
507                 const char *src, size_t in_len)
508 {
509         const char *p, *end = src + in_len;
510         unsigned char *d;
511         size_t out_len = 0;
512         bool vars_found = false;
513
514         if (parser->flags & UCL_PARSER_DISABLE_MACRO) {
515                 *dst = NULL;
516                 return in_len;
517         }
518
519         p = src;
520         while (p != end) {
521                 if (*p == '$') {
522                         p = ucl_check_variable (parser, p + 1, end - p - 1, &out_len, &vars_found);
523                 }
524                 else {
525                         p ++;
526                         out_len ++;
527                 }
528         }
529
530         if (!vars_found) {
531                 /* Trivial case */
532                 *dst = NULL;
533                 return in_len;
534         }
535
536         *dst = UCL_ALLOC (out_len + 1);
537         if (*dst == NULL) {
538                 return in_len;
539         }
540
541         d = *dst;
542         p = src;
543         while (p != end) {
544                 if (*p == '$') {
545                         p = ucl_expand_single_variable (parser, p, end - p, &d);
546                 }
547                 else {
548                         *d++ = *p++;
549                 }
550         }
551
552         *d = '\0';
553
554         return out_len;
555 }
556
557 /**
558  * Store or copy pointer to the trash stack
559  * @param parser parser object
560  * @param src src string
561  * @param dst destination buffer (trash stack pointer)
562  * @param dst_const const destination pointer (e.g. value of object)
563  * @param in_len input length
564  * @param need_unescape need to unescape source (and copy it)
565  * @param need_lowercase need to lowercase value (and copy)
566  * @param need_expand need to expand variables (and copy as well)
567  * @return output length (excluding \0 symbol)
568  */
569 static inline ssize_t
570 ucl_copy_or_store_ptr (struct ucl_parser *parser,
571                 const unsigned char *src, unsigned char **dst,
572                 const char **dst_const, size_t in_len,
573                 bool need_unescape, bool need_lowercase, bool need_expand)
574 {
575         ssize_t ret = -1, tret;
576         unsigned char *tmp;
577
578         if (need_unescape || need_lowercase ||
579                         (need_expand && parser->variables != NULL) ||
580                         !(parser->flags & UCL_PARSER_ZEROCOPY)) {
581                 /* Copy string */
582                 *dst = UCL_ALLOC (in_len + 1);
583                 if (*dst == NULL) {
584                         ucl_set_err (parser, UCL_EINTERNAL, "cannot allocate memory for a string",
585                                         &parser->err);
586                         return false;
587                 }
588                 if (need_lowercase) {
589                         ret = ucl_strlcpy_tolower (*dst, src, in_len + 1);
590                 }
591                 else {
592                         ret = ucl_strlcpy_unsafe (*dst, src, in_len + 1);
593                 }
594
595                 if (need_unescape) {
596                         ret = ucl_unescape_json_string (*dst, ret);
597                 }
598                 if (need_expand) {
599                         tmp = *dst;
600                         tret = ret;
601                         ret = ucl_expand_variable (parser, dst, tmp, ret);
602                         if (*dst == NULL) {
603                                 /* Nothing to expand */
604                                 *dst = tmp;
605                                 ret = tret;
606                         }
607                         else {
608                                 /* Free unexpanded value */
609                                 UCL_FREE (in_len + 1, tmp);
610                         }
611                 }
612                 *dst_const = *dst;
613         }
614         else {
615                 *dst_const = src;
616                 ret = in_len;
617         }
618
619         return ret;
620 }
621
622 /**
623  * Create and append an object at the specified level
624  * @param parser
625  * @param is_array
626  * @param level
627  * @return
628  */
629 static inline ucl_object_t *
630 ucl_parser_add_container (ucl_object_t *obj, struct ucl_parser *parser,
631                 bool is_array, int level)
632 {
633         struct ucl_stack *st;
634
635         if (!is_array) {
636                 if (obj == NULL) {
637                         obj = ucl_object_new_full (UCL_OBJECT, parser->chunks->priority);
638                 }
639                 else {
640                         obj->type = UCL_OBJECT;
641                 }
642                 if (obj->value.ov == NULL) {
643                         obj->value.ov = ucl_hash_create (parser->flags & UCL_PARSER_KEY_LOWERCASE);
644                 }
645                 parser->state = UCL_STATE_KEY;
646         }
647         else {
648                 if (obj == NULL) {
649                         obj = ucl_object_new_full (UCL_ARRAY, parser->chunks->priority);
650                 }
651                 else {
652                         obj->type = UCL_ARRAY;
653                 }
654                 parser->state = UCL_STATE_VALUE;
655         }
656
657         st = UCL_ALLOC (sizeof (struct ucl_stack));
658
659         if (st == NULL) {
660                 ucl_set_err (parser, UCL_EINTERNAL, "cannot allocate memory for an object",
661                                 &parser->err);
662                 ucl_object_unref (obj);
663                 return NULL;
664         }
665
666         st->obj = obj;
667         st->level = level;
668         LL_PREPEND (parser->stack, st);
669         parser->cur_obj = obj;
670
671         return obj;
672 }
673
674 int
675 ucl_maybe_parse_number (ucl_object_t *obj,
676                 const char *start, const char *end, const char **pos,
677                 bool allow_double, bool number_bytes, bool allow_time)
678 {
679         const char *p = start, *c = start;
680         char *endptr;
681         bool got_dot = false, got_exp = false, need_double = false,
682                         is_time = false, valid_start = false, is_hex = false,
683                         is_neg = false;
684         double dv = 0;
685         int64_t lv = 0;
686
687         if (*p == '-') {
688                 is_neg = true;
689                 c ++;
690                 p ++;
691         }
692         while (p < end) {
693                 if (is_hex && isxdigit (*p)) {
694                         p ++;
695                 }
696                 else if (isdigit (*p)) {
697                         valid_start = true;
698                         p ++;
699                 }
700                 else if (!is_hex && (*p == 'x' || *p == 'X')) {
701                         is_hex = true;
702                         allow_double = false;
703                         c = p + 1;
704                 }
705                 else if (allow_double) {
706                         if (p == c) {
707                                 /* Empty digits sequence, not a number */
708                                 *pos = start;
709                                 return EINVAL;
710                         }
711                         else if (*p == '.') {
712                                 if (got_dot) {
713                                         /* Double dots, not a number */
714                                         *pos = start;
715                                         return EINVAL;
716                                 }
717                                 else {
718                                         got_dot = true;
719                                         need_double = true;
720                                         p ++;
721                                 }
722                         }
723                         else if (*p == 'e' || *p == 'E') {
724                                 if (got_exp) {
725                                         /* Double exp, not a number */
726                                         *pos = start;
727                                         return EINVAL;
728                                 }
729                                 else {
730                                         got_exp = true;
731                                         need_double = true;
732                                         p ++;
733                                         if (p >= end) {
734                                                 *pos = start;
735                                                 return EINVAL;
736                                         }
737                                         if (!isdigit (*p) && *p != '+' && *p != '-') {
738                                                 /* Wrong exponent sign */
739                                                 *pos = start;
740                                                 return EINVAL;
741                                         }
742                                         else {
743                                                 p ++;
744                                         }
745                                 }
746                         }
747                         else {
748                                 /* Got the end of the number, need to check */
749                                 break;
750                         }
751                 }
752                 else {
753                         break;
754                 }
755         }
756
757         if (!valid_start) {
758                 *pos = start;
759                 return EINVAL;
760         }
761
762         errno = 0;
763         if (need_double) {
764                 dv = strtod (c, &endptr);
765         }
766         else {
767                 if (is_hex) {
768                         lv = strtoimax (c, &endptr, 16);
769                 }
770                 else {
771                         lv = strtoimax (c, &endptr, 10);
772                 }
773         }
774         if (errno == ERANGE) {
775                 *pos = start;
776                 return ERANGE;
777         }
778
779         /* Now check endptr */
780         if (endptr == NULL || ucl_lex_is_atom_end (*endptr) || *endptr == '\0') {
781                 p = endptr;
782                 goto set_obj;
783         }
784
785         if (endptr < end && endptr != start) {
786                 p = endptr;
787                 switch (*p) {
788                 case 'm':
789                 case 'M':
790                 case 'g':
791                 case 'G':
792                 case 'k':
793                 case 'K':
794                         if (end - p >= 2) {
795                                 if (p[1] == 's' || p[1] == 'S') {
796                                         /* Milliseconds */
797                                         if (!need_double) {
798                                                 need_double = true;
799                                                 dv = lv;
800                                         }
801                                         is_time = true;
802                                         if (p[0] == 'm' || p[0] == 'M') {
803                                                 dv /= 1000.;
804                                         }
805                                         else {
806                                                 dv *= ucl_lex_num_multiplier (*p, false);
807                                         }
808                                         p += 2;
809                                         goto set_obj;
810                                 }
811                                 else if (number_bytes || (p[1] == 'b' || p[1] == 'B')) {
812                                         /* Bytes */
813                                         if (need_double) {
814                                                 need_double = false;
815                                                 lv = dv;
816                                         }
817                                         lv *= ucl_lex_num_multiplier (*p, true);
818                                         p += 2;
819                                         goto set_obj;
820                                 }
821                                 else if (ucl_lex_is_atom_end (p[1])) {
822                                         if (need_double) {
823                                                 dv *= ucl_lex_num_multiplier (*p, false);
824                                         }
825                                         else {
826                                                 lv *= ucl_lex_num_multiplier (*p, number_bytes);
827                                         }
828                                         p ++;
829                                         goto set_obj;
830                                 }
831                                 else if (allow_time && end - p >= 3) {
832                                         if (tolower (p[0]) == 'm' &&
833                                                         tolower (p[1]) == 'i' &&
834                                                         tolower (p[2]) == 'n') {
835                                                 /* Minutes */
836                                                 if (!need_double) {
837                                                         need_double = true;
838                                                         dv = lv;
839                                                 }
840                                                 is_time = true;
841                                                 dv *= 60.;
842                                                 p += 3;
843                                                 goto set_obj;
844                                         }
845                                 }
846                         }
847                         else {
848                                 if (need_double) {
849                                         dv *= ucl_lex_num_multiplier (*p, false);
850                                 }
851                                 else {
852                                         lv *= ucl_lex_num_multiplier (*p, number_bytes);
853                                 }
854                                 p ++;
855                                 goto set_obj;
856                         }
857                         break;
858                 case 'S':
859                 case 's':
860                         if (allow_time &&
861                                         (p == end - 1 || ucl_lex_is_atom_end (p[1]))) {
862                                 if (!need_double) {
863                                         need_double = true;
864                                         dv = lv;
865                                 }
866                                 p ++;
867                                 is_time = true;
868                                 goto set_obj;
869                         }
870                         break;
871                 case 'h':
872                 case 'H':
873                 case 'd':
874                 case 'D':
875                 case 'w':
876                 case 'W':
877                 case 'Y':
878                 case 'y':
879                         if (allow_time &&
880                                         (p == end - 1 || ucl_lex_is_atom_end (p[1]))) {
881                                 if (!need_double) {
882                                         need_double = true;
883                                         dv = lv;
884                                 }
885                                 is_time = true;
886                                 dv *= ucl_lex_time_multiplier (*p);
887                                 p ++;
888                                 goto set_obj;
889                         }
890                         break;
891                 case '\t':
892                 case ' ':
893                         while (p < end && ucl_test_character(*p, UCL_CHARACTER_WHITESPACE)) {
894                                 p++;
895                         }
896                         if (ucl_lex_is_atom_end(*p))
897                                 goto set_obj;
898                         break;
899                 }
900         }
901         else if (endptr == end) {
902                 /* Just a number at the end of chunk */
903                 p = endptr;
904                 goto set_obj;
905         }
906
907         *pos = c;
908         return EINVAL;
909
910 set_obj:
911         if (obj != NULL) {
912                 if (allow_double && (need_double || is_time)) {
913                         if (!is_time) {
914                                 obj->type = UCL_FLOAT;
915                         }
916                         else {
917                                 obj->type = UCL_TIME;
918                         }
919                         obj->value.dv = is_neg ? (-dv) : dv;
920                 }
921                 else {
922                         obj->type = UCL_INT;
923                         obj->value.iv = is_neg ? (-lv) : lv;
924                 }
925         }
926         *pos = p;
927         return 0;
928 }
929
930 /**
931  * Parse possible number
932  * @param parser
933  * @param chunk
934  * @param obj
935  * @return true if a number has been parsed
936  */
937 static bool
938 ucl_lex_number (struct ucl_parser *parser,
939                 struct ucl_chunk *chunk, ucl_object_t *obj)
940 {
941         const unsigned char *pos;
942         int ret;
943
944         ret = ucl_maybe_parse_number (obj, chunk->pos, chunk->end, (const char **)&pos,
945                         true, false, ((parser->flags & UCL_PARSER_NO_TIME) == 0));
946
947         if (ret == 0) {
948                 chunk->remain -= pos - chunk->pos;
949                 chunk->column += pos - chunk->pos;
950                 chunk->pos = pos;
951                 return true;
952         }
953         else if (ret == ERANGE) {
954                 ucl_set_err (parser, UCL_ESYNTAX, "numeric value out of range",
955                                 &parser->err);
956         }
957
958         return false;
959 }
960
961 /**
962  * Parse quoted string with possible escapes
963  * @param parser
964  * @param chunk
965  * @param need_unescape
966  * @param ucl_escape
967  * @param var_expand
968  * @return true if a string has been parsed
969  */
970 static bool
971 ucl_lex_json_string (struct ucl_parser *parser,
972                 struct ucl_chunk *chunk, bool *need_unescape, bool *ucl_escape, bool *var_expand)
973 {
974         const unsigned char *p = chunk->pos;
975         unsigned char c;
976         int i;
977
978         while (p < chunk->end) {
979                 c = *p;
980                 if (c < 0x1F) {
981                         /* Unmasked control character */
982                         if (c == '\n') {
983                                 ucl_set_err (parser, UCL_ESYNTAX, "unexpected newline",
984                                                 &parser->err);
985                         }
986                         else {
987                                 ucl_set_err (parser, UCL_ESYNTAX, "unexpected control character",
988                                                 &parser->err);
989                         }
990                         return false;
991                 }
992                 else if (c == '\\') {
993                         ucl_chunk_skipc (chunk, p);
994                         c = *p;
995                         if (p >= chunk->end) {
996                                 ucl_set_err (parser, UCL_ESYNTAX, "unfinished escape character",
997                                                 &parser->err);
998                                 return false;
999                         }
1000                         else if (ucl_test_character (c, UCL_CHARACTER_ESCAPE)) {
1001                                 if (c == 'u') {
1002                                         ucl_chunk_skipc (chunk, p);
1003                                         for (i = 0; i < 4 && p < chunk->end; i ++) {
1004                                                 if (!isxdigit (*p)) {
1005                                                         ucl_set_err (parser, UCL_ESYNTAX, "invalid utf escape",
1006                                                                         &parser->err);
1007                                                         return false;
1008                                                 }
1009                                                 ucl_chunk_skipc (chunk, p);
1010                                         }
1011                                         if (p >= chunk->end) {
1012                                                 ucl_set_err (parser, UCL_ESYNTAX, "unfinished escape character",
1013                                                                 &parser->err);
1014                                                 return false;
1015                                         }
1016                                 }
1017                                 else {
1018                                         ucl_chunk_skipc (chunk, p);
1019                                 }
1020                         }
1021                         *need_unescape = true;
1022                         *ucl_escape = true;
1023                         continue;
1024                 }
1025                 else if (c == '"') {
1026                         ucl_chunk_skipc (chunk, p);
1027                         return true;
1028                 }
1029                 else if (ucl_test_character (c, UCL_CHARACTER_UCL_UNSAFE)) {
1030                         *ucl_escape = true;
1031                 }
1032                 else if (c == '$') {
1033                         *var_expand = true;
1034                 }
1035                 ucl_chunk_skipc (chunk, p);
1036         }
1037
1038         ucl_set_err (parser, UCL_ESYNTAX, "no quote at the end of json string",
1039                         &parser->err);
1040         return false;
1041 }
1042
1043 static void
1044 ucl_parser_append_elt (struct ucl_parser *parser, ucl_hash_t *cont,
1045                 ucl_object_t *top,
1046                 ucl_object_t *elt)
1047 {
1048         ucl_object_t *nobj;
1049
1050         if ((parser->flags & UCL_PARSER_NO_IMPLICIT_ARRAYS) == 0) {
1051                 /* Implicit array */
1052                 top->flags |= UCL_OBJECT_MULTIVALUE;
1053                 DL_APPEND (top, elt);
1054                 parser->stack->obj->len ++;
1055         }
1056         else {
1057                 if ((top->flags & UCL_OBJECT_MULTIVALUE) != 0) {
1058                         /* Just add to the explicit array */
1059                         ucl_array_append (top, elt);
1060                 }
1061                 else {
1062                         /* Convert to an array */
1063                         nobj = ucl_object_typed_new (UCL_ARRAY);
1064                         nobj->key = top->key;
1065                         nobj->keylen = top->keylen;
1066                         nobj->flags |= UCL_OBJECT_MULTIVALUE;
1067                         ucl_array_append (nobj, top);
1068                         ucl_array_append (nobj, elt);
1069                         ucl_hash_replace (cont, top, nobj);
1070                 }
1071         }
1072 }
1073
1074 bool
1075 ucl_parser_process_object_element (struct ucl_parser *parser, ucl_object_t *nobj)
1076 {
1077         ucl_hash_t *container;
1078         ucl_object_t *tobj;
1079         char errmsg[256];
1080
1081         container = parser->stack->obj->value.ov;
1082
1083         tobj = __DECONST (ucl_object_t *, ucl_hash_search_obj (container, nobj));
1084         if (tobj == NULL) {
1085                 container = ucl_hash_insert_object (container, nobj,
1086                                 parser->flags & UCL_PARSER_KEY_LOWERCASE);
1087                 nobj->prev = nobj;
1088                 nobj->next = NULL;
1089                 parser->stack->obj->len ++;
1090         }
1091         else {
1092                 unsigned priold = ucl_object_get_priority (tobj),
1093                                 prinew = ucl_object_get_priority (nobj);
1094                 switch (parser->chunks->strategy) {
1095
1096                 case UCL_DUPLICATE_APPEND:
1097                         /*
1098                          * The logic here is the following:
1099                          *
1100                          * - if we have two objects with the same priority, then we form an
1101                          * implicit or explicit array
1102                          * - if a new object has bigger priority, then we overwrite an old one
1103                          * - if a new object has lower priority, then we ignore it
1104                          */
1105
1106
1107                         /* Special case for inherited objects */
1108                         if (tobj->flags & UCL_OBJECT_INHERITED) {
1109                                 prinew = priold + 1;
1110                         }
1111
1112                         if (priold == prinew) {
1113                                 ucl_parser_append_elt (parser, container, tobj, nobj);
1114                         }
1115                         else if (priold > prinew) {
1116                                 /*
1117                                  * We add this new object to a list of trash objects just to ensure
1118                                  * that it won't come to any real object
1119                                  * XXX: rather inefficient approach
1120                                  */
1121                                 DL_APPEND (parser->trash_objs, nobj);
1122                         }
1123                         else {
1124                                 ucl_hash_replace (container, tobj, nobj);
1125                                 ucl_object_unref (tobj);
1126                         }
1127
1128                         break;
1129
1130                 case UCL_DUPLICATE_REWRITE:
1131                         /* We just rewrite old values regardless of priority */
1132                         ucl_hash_replace (container, tobj, nobj);
1133                         ucl_object_unref (tobj);
1134
1135                         break;
1136
1137                 case UCL_DUPLICATE_ERROR:
1138                         snprintf(errmsg, sizeof(errmsg),
1139                                         "duplicate element for key '%s' found",
1140                                         nobj->key);
1141                         ucl_set_err (parser, UCL_EMERGE, errmsg, &parser->err);
1142                         return false;
1143
1144                 case UCL_DUPLICATE_MERGE:
1145                         /*
1146                          * Here we do have some old object so we just push it on top of objects stack
1147                          * Check priority and then perform the merge on the remaining objects
1148                          */
1149                         if (tobj->type == UCL_OBJECT || tobj->type == UCL_ARRAY) {
1150                                 ucl_object_unref (nobj);
1151                                 nobj = tobj;
1152                         }
1153                         else if (priold == prinew) {
1154                                 ucl_parser_append_elt (parser, container, tobj, nobj);
1155                         }
1156                         else if (priold > prinew) {
1157                                 /*
1158                                  * We add this new object to a list of trash objects just to ensure
1159                                  * that it won't come to any real object
1160                                  * XXX: rather inefficient approach
1161                                  */
1162                                 DL_APPEND (parser->trash_objs, nobj);
1163                         }
1164                         else {
1165                                 ucl_hash_replace (container, tobj, nobj);
1166                                 ucl_object_unref (tobj);
1167                         }
1168                         break;
1169                 }
1170         }
1171
1172         parser->stack->obj->value.ov = container;
1173         parser->cur_obj = nobj;
1174         ucl_attach_comment (parser, nobj, false);
1175
1176         return true;
1177 }
1178
1179 /**
1180  * Parse a key in an object
1181  * @param parser
1182  * @param chunk
1183  * @param next_key
1184  * @param end_of_object
1185  * @return true if a key has been parsed
1186  */
1187 static bool
1188 ucl_parse_key (struct ucl_parser *parser, struct ucl_chunk *chunk,
1189                 bool *next_key, bool *end_of_object)
1190 {
1191         const unsigned char *p, *c = NULL, *end, *t;
1192         const char *key = NULL;
1193         bool got_quote = false, got_eq = false, got_semicolon = false,
1194                         need_unescape = false, ucl_escape = false, var_expand = false,
1195                         got_content = false, got_sep = false;
1196         ucl_object_t *nobj;
1197         ssize_t keylen;
1198
1199         p = chunk->pos;
1200
1201         if (*p == '.') {
1202                 /* It is macro actually */
1203                 if (!(parser->flags & UCL_PARSER_DISABLE_MACRO)) {
1204                         ucl_chunk_skipc (chunk, p);
1205                 }
1206
1207                 parser->prev_state = parser->state;
1208                 parser->state = UCL_STATE_MACRO_NAME;
1209                 *end_of_object = false;
1210                 return true;
1211         }
1212         while (p < chunk->end) {
1213                 /*
1214                  * A key must start with alpha, number, '/' or '_' and end with space character
1215                  */
1216                 if (c == NULL) {
1217                         if (chunk->remain >= 2 && ucl_lex_is_comment (p[0], p[1])) {
1218                                 if (!ucl_skip_comments (parser)) {
1219                                         return false;
1220                                 }
1221                                 p = chunk->pos;
1222                         }
1223                         else if (ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE)) {
1224                                 ucl_chunk_skipc (chunk, p);
1225                         }
1226                         else if (ucl_test_character (*p, UCL_CHARACTER_KEY_START)) {
1227                                 /* The first symbol */
1228                                 c = p;
1229                                 ucl_chunk_skipc (chunk, p);
1230                                 got_content = true;
1231                         }
1232                         else if (*p == '"') {
1233                                 /* JSON style key */
1234                                 c = p + 1;
1235                                 got_quote = true;
1236                                 got_content = true;
1237                                 ucl_chunk_skipc (chunk, p);
1238                         }
1239                         else if (*p == '}') {
1240                                 /* We have actually end of an object */
1241                                 *end_of_object = true;
1242                                 return true;
1243                         }
1244                         else if (*p == '.') {
1245                                 ucl_chunk_skipc (chunk, p);
1246                                 parser->prev_state = parser->state;
1247                                 parser->state = UCL_STATE_MACRO_NAME;
1248                                 return true;
1249                         }
1250                         else {
1251                                 /* Invalid identifier */
1252                                 ucl_set_err (parser, UCL_ESYNTAX, "key must begin with a letter",
1253                                                 &parser->err);
1254                                 return false;
1255                         }
1256                 }
1257                 else {
1258                         /* Parse the body of a key */
1259                         if (!got_quote) {
1260                                 if (ucl_test_character (*p, UCL_CHARACTER_KEY)) {
1261                                         got_content = true;
1262                                         ucl_chunk_skipc (chunk, p);
1263                                 }
1264                                 else if (ucl_test_character (*p, UCL_CHARACTER_KEY_SEP)) {
1265                                         end = p;
1266                                         break;
1267                                 }
1268                                 else {
1269                                         ucl_set_err (parser, UCL_ESYNTAX, "invalid character in a key",
1270                                                         &parser->err);
1271                                         return false;
1272                                 }
1273                         }
1274                         else {
1275                                 /* We need to parse json like quoted string */
1276                                 if (!ucl_lex_json_string (parser, chunk, &need_unescape, &ucl_escape, &var_expand)) {
1277                                         return false;
1278                                 }
1279                                 /* Always escape keys obtained via json */
1280                                 end = chunk->pos - 1;
1281                                 p = chunk->pos;
1282                                 break;
1283                         }
1284                 }
1285         }
1286
1287         if (p >= chunk->end && got_content) {
1288                 ucl_set_err (parser, UCL_ESYNTAX, "unfinished key", &parser->err);
1289                 return false;
1290         }
1291         else if (!got_content) {
1292                 return true;
1293         }
1294         *end_of_object = false;
1295         /* We are now at the end of the key, need to parse the rest */
1296         while (p < chunk->end) {
1297                 if (ucl_test_character (*p, UCL_CHARACTER_WHITESPACE)) {
1298                         ucl_chunk_skipc (chunk, p);
1299                 }
1300                 else if (*p == '=') {
1301                         if (!got_eq && !got_semicolon) {
1302                                 ucl_chunk_skipc (chunk, p);
1303                                 got_eq = true;
1304                         }
1305                         else {
1306                                 ucl_set_err (parser, UCL_ESYNTAX, "unexpected '=' character",
1307                                                 &parser->err);
1308                                 return false;
1309                         }
1310                 }
1311                 else if (*p == ':') {
1312                         if (!got_eq && !got_semicolon) {
1313                                 ucl_chunk_skipc (chunk, p);
1314                                 got_semicolon = true;
1315                         }
1316                         else {
1317                                 ucl_set_err (parser, UCL_ESYNTAX, "unexpected ':' character",
1318                                                 &parser->err);
1319                                 return false;
1320                         }
1321                 }
1322                 else if (chunk->remain >= 2 && ucl_lex_is_comment (p[0], p[1])) {
1323                         /* Check for comment */
1324                         if (!ucl_skip_comments (parser)) {
1325                                 return false;
1326                         }
1327                         p = chunk->pos;
1328                 }
1329                 else {
1330                         /* Start value */
1331                         break;
1332                 }
1333         }
1334
1335         if (p >= chunk->end && got_content) {
1336                 ucl_set_err (parser, UCL_ESYNTAX, "unfinished key", &parser->err);
1337                 return false;
1338         }
1339
1340         got_sep = got_semicolon || got_eq;
1341
1342         if (!got_sep) {
1343                 /*
1344                  * Maybe we have more keys nested, so search for termination character.
1345                  * Possible choices:
1346                  * 1) key1 key2 ... keyN [:=] value <- we treat that as error
1347                  * 2) key1 ... keyN {} or [] <- we treat that as nested objects
1348                  * 3) key1 value[;,\n] <- we treat that as linear object
1349                  */
1350                 t = p;
1351                 *next_key = false;
1352                 while (ucl_test_character (*t, UCL_CHARACTER_WHITESPACE)) {
1353                         t ++;
1354                 }
1355                 /* Check first non-space character after a key */
1356                 if (*t != '{' && *t != '[') {
1357                         while (t < chunk->end) {
1358                                 if (*t == ',' || *t == ';' || *t == '\n' || *t == '\r') {
1359                                         break;
1360                                 }
1361                                 else if (*t == '{' || *t == '[') {
1362                                         *next_key = true;
1363                                         break;
1364                                 }
1365                                 t ++;
1366                         }
1367                 }
1368         }
1369
1370         /* Create a new object */
1371         nobj = ucl_object_new_full (UCL_NULL, parser->chunks->priority);
1372         keylen = ucl_copy_or_store_ptr (parser, c, &nobj->trash_stack[UCL_TRASH_KEY],
1373                         &key, end - c, need_unescape, parser->flags & UCL_PARSER_KEY_LOWERCASE, false);
1374         if (keylen == -1) {
1375                 ucl_object_unref (nobj);
1376                 return false;
1377         }
1378         else if (keylen == 0) {
1379                 ucl_set_err (parser, UCL_ESYNTAX, "empty keys are not allowed", &parser->err);
1380                 ucl_object_unref (nobj);
1381                 return false;
1382         }
1383
1384         nobj->key = key;
1385         nobj->keylen = keylen;
1386
1387         if (!ucl_parser_process_object_element (parser, nobj)) {
1388                 return false;
1389         }
1390
1391         if (ucl_escape) {
1392                 nobj->flags |= UCL_OBJECT_NEED_KEY_ESCAPE;
1393         }
1394
1395
1396         return true;
1397 }
1398
1399 /**
1400  * Parse a cl string
1401  * @param parser
1402  * @param chunk
1403  * @param var_expand
1404  * @param need_unescape
1405  * @return true if a key has been parsed
1406  */
1407 static bool
1408 ucl_parse_string_value (struct ucl_parser *parser,
1409                 struct ucl_chunk *chunk, bool *var_expand, bool *need_unescape)
1410 {
1411         const unsigned char *p;
1412         enum {
1413                 UCL_BRACE_ROUND = 0,
1414                 UCL_BRACE_SQUARE,
1415                 UCL_BRACE_FIGURE
1416         };
1417         int braces[3][2] = {{0, 0}, {0, 0}, {0, 0}};
1418
1419         p = chunk->pos;
1420
1421         while (p < chunk->end) {
1422
1423                 /* Skip pairs of figure braces */
1424                 if (*p == '{') {
1425                         braces[UCL_BRACE_FIGURE][0] ++;
1426                 }
1427                 else if (*p == '}') {
1428                         braces[UCL_BRACE_FIGURE][1] ++;
1429                         if (braces[UCL_BRACE_FIGURE][1] <= braces[UCL_BRACE_FIGURE][0]) {
1430                                 /* This is not a termination symbol, continue */
1431                                 ucl_chunk_skipc (chunk, p);
1432                                 continue;
1433                         }
1434                 }
1435                 /* Skip pairs of square braces */
1436                 else if (*p == '[') {
1437                         braces[UCL_BRACE_SQUARE][0] ++;
1438                 }
1439                 else if (*p == ']') {
1440                         braces[UCL_BRACE_SQUARE][1] ++;
1441                         if (braces[UCL_BRACE_SQUARE][1] <= braces[UCL_BRACE_SQUARE][0]) {
1442                                 /* This is not a termination symbol, continue */
1443                                 ucl_chunk_skipc (chunk, p);
1444                                 continue;
1445                         }
1446                 }
1447                 else if (*p == '$') {
1448                         *var_expand = true;
1449                 }
1450                 else if (*p == '\\') {
1451                         *need_unescape = true;
1452                         ucl_chunk_skipc (chunk, p);
1453                         if (p < chunk->end) {
1454                                 ucl_chunk_skipc (chunk, p);
1455                         }
1456                         continue;
1457                 }
1458
1459                 if (ucl_lex_is_atom_end (*p) || (chunk->remain >= 2 && ucl_lex_is_comment (p[0], p[1]))) {
1460                         break;
1461                 }
1462                 ucl_chunk_skipc (chunk, p);
1463         }
1464
1465         return true;
1466 }
1467
1468 /**
1469  * Parse multiline string ending with \n{term}\n
1470  * @param parser
1471  * @param chunk
1472  * @param term
1473  * @param term_len
1474  * @param beg
1475  * @param var_expand
1476  * @return size of multiline string or 0 in case of error
1477  */
1478 static int
1479 ucl_parse_multiline_string (struct ucl_parser *parser,
1480                 struct ucl_chunk *chunk, const unsigned char *term,
1481                 int term_len, unsigned char const **beg,
1482                 bool *var_expand)
1483 {
1484         const unsigned char *p, *c, *tend;
1485         bool newline = false;
1486         int len = 0;
1487
1488         p = chunk->pos;
1489
1490         c = p;
1491
1492         while (p < chunk->end) {
1493                 if (newline) {
1494                         if (chunk->end - p < term_len) {
1495                                 return 0;
1496                         }
1497                         else if (memcmp (p, term, term_len) == 0) {
1498                                 tend = p + term_len;
1499                                 if (*tend != '\n' && *tend != ';' && *tend != ',') {
1500                                         /* Incomplete terminator */
1501                                         ucl_chunk_skipc (chunk, p);
1502                                         continue;
1503                                 }
1504                                 len = p - c;
1505                                 chunk->remain -= term_len;
1506                                 chunk->pos = p + term_len;
1507                                 chunk->column = term_len;
1508                                 *beg = c;
1509                                 break;
1510                         }
1511                 }
1512                 if (*p == '\n') {
1513                         newline = true;
1514                 }
1515                 else {
1516                         if (*p == '$') {
1517                                 *var_expand = true;
1518                         }
1519                         newline = false;
1520                 }
1521                 ucl_chunk_skipc (chunk, p);
1522         }
1523
1524         return len;
1525 }
1526
1527 static inline ucl_object_t*
1528 ucl_parser_get_container (struct ucl_parser *parser)
1529 {
1530         ucl_object_t *t, *obj = NULL;
1531
1532         if (parser == NULL || parser->stack == NULL || parser->stack->obj == NULL) {
1533                 return NULL;
1534         }
1535
1536         if (parser->stack->obj->type == UCL_ARRAY) {
1537                 /* Object must be allocated */
1538                 obj = ucl_object_new_full (UCL_NULL, parser->chunks->priority);
1539                 t = parser->stack->obj;
1540
1541                 if (!ucl_array_append (t, obj)) {
1542                         ucl_object_unref (obj);
1543                         return NULL;
1544                 }
1545
1546                 parser->cur_obj = obj;
1547                 ucl_attach_comment (parser, obj, false);
1548         }
1549         else {
1550                 /* Object has been already allocated */
1551                 obj = parser->cur_obj;
1552         }
1553
1554         return obj;
1555 }
1556
1557 /**
1558  * Handle value data
1559  * @param parser
1560  * @param chunk
1561  * @return
1562  */
1563 static bool
1564 ucl_parse_value (struct ucl_parser *parser, struct ucl_chunk *chunk)
1565 {
1566         const unsigned char *p, *c;
1567         ucl_object_t *obj = NULL;
1568         unsigned int stripped_spaces;
1569         int str_len;
1570         bool need_unescape = false, ucl_escape = false, var_expand = false;
1571
1572         p = chunk->pos;
1573
1574         /* Skip any spaces and comments */
1575         if (ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE) ||
1576                         (chunk->remain >= 2 && ucl_lex_is_comment (p[0], p[1]))) {
1577                 while (p < chunk->end && ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE)) {
1578                         ucl_chunk_skipc (chunk, p);
1579                 }
1580                 if (!ucl_skip_comments (parser)) {
1581                         return false;
1582                 }
1583                 p = chunk->pos;
1584         }
1585
1586         while (p < chunk->end) {
1587                 c = p;
1588                 switch (*p) {
1589                 case '"':
1590                         ucl_chunk_skipc (chunk, p);
1591
1592                         if (!ucl_lex_json_string (parser, chunk, &need_unescape, &ucl_escape,
1593                                         &var_expand)) {
1594                                 return false;
1595                         }
1596
1597                         obj = ucl_parser_get_container (parser);
1598                         if (!obj) {
1599                                 return false;
1600                         }
1601
1602                         str_len = chunk->pos - c - 2;
1603                         obj->type = UCL_STRING;
1604                         if ((str_len = ucl_copy_or_store_ptr (parser, c + 1,
1605                                         &obj->trash_stack[UCL_TRASH_VALUE],
1606                                         &obj->value.sv, str_len, need_unescape, false,
1607                                         var_expand)) == -1) {
1608                                 return false;
1609                         }
1610                         obj->len = str_len;
1611
1612                         parser->state = UCL_STATE_AFTER_VALUE;
1613                         p = chunk->pos;
1614
1615                         return true;
1616                         break;
1617                 case '{':
1618                         obj = ucl_parser_get_container (parser);
1619                         /* We have a new object */
1620                         obj = ucl_parser_add_container (obj, parser, false, parser->stack->level);
1621                         if (obj == NULL) {
1622                                 return false;
1623                         }
1624
1625                         ucl_chunk_skipc (chunk, p);
1626
1627                         return true;
1628                         break;
1629                 case '[':
1630                         obj = ucl_parser_get_container (parser);
1631                         /* We have a new array */
1632                         obj = ucl_parser_add_container (obj, parser, true, parser->stack->level);
1633                         if (obj == NULL) {
1634                                 return false;
1635                         }
1636
1637                         ucl_chunk_skipc (chunk, p);
1638
1639                         return true;
1640                         break;
1641                 case ']':
1642                         /* We have the array ending */
1643                         if (parser->stack && parser->stack->obj->type == UCL_ARRAY) {
1644                                 parser->state = UCL_STATE_AFTER_VALUE;
1645                                 return true;
1646                         }
1647                         else {
1648                                 goto parse_string;
1649                         }
1650                         break;
1651                 case '<':
1652                         obj = ucl_parser_get_container (parser);
1653                         /* We have something like multiline value, which must be <<[A-Z]+\n */
1654                         if (chunk->end - p > 3) {
1655                                 if (memcmp (p, "<<", 2) == 0) {
1656                                         p += 2;
1657                                         /* We allow only uppercase characters in multiline definitions */
1658                                         while (p < chunk->end && *p >= 'A' && *p <= 'Z') {
1659                                                 p ++;
1660                                         }
1661                                         if (*p =='\n') {
1662                                                 /* Set chunk positions and start multiline parsing */
1663                                                 c += 2;
1664                                                 chunk->remain -= p - c;
1665                                                 chunk->pos = p + 1;
1666                                                 chunk->column = 0;
1667                                                 chunk->line ++;
1668                                                 if ((str_len = ucl_parse_multiline_string (parser, chunk, c,
1669                                                                 p - c, &c, &var_expand)) == 0) {
1670                                                         ucl_set_err (parser, UCL_ESYNTAX,
1671                                                                         "unterminated multiline value", &parser->err);
1672                                                         return false;
1673                                                 }
1674
1675                                                 obj->type = UCL_STRING;
1676                                                 obj->flags |= UCL_OBJECT_MULTILINE;
1677                                                 if ((str_len = ucl_copy_or_store_ptr (parser, c,
1678                                                                 &obj->trash_stack[UCL_TRASH_VALUE],
1679                                                                 &obj->value.sv, str_len - 1, false,
1680                                                                 false, var_expand)) == -1) {
1681                                                         return false;
1682                                                 }
1683                                                 obj->len = str_len;
1684
1685                                                 parser->state = UCL_STATE_AFTER_VALUE;
1686
1687                                                 return true;
1688                                         }
1689                                 }
1690                         }
1691                         /* Fallback to ordinary strings */
1692                 default:
1693 parse_string:
1694                         if (obj == NULL) {
1695                                 obj = ucl_parser_get_container (parser);
1696                         }
1697
1698                         /* Parse atom */
1699                         if (ucl_test_character (*p, UCL_CHARACTER_VALUE_DIGIT_START)) {
1700                                 if (!ucl_lex_number (parser, chunk, obj)) {
1701                                         if (parser->state == UCL_STATE_ERROR) {
1702                                                 return false;
1703                                         }
1704                                 }
1705                                 else {
1706                                         parser->state = UCL_STATE_AFTER_VALUE;
1707                                         return true;
1708                                 }
1709                                 /* Fallback to normal string */
1710                         }
1711
1712                         if (!ucl_parse_string_value (parser, chunk, &var_expand,
1713                                         &need_unescape)) {
1714                                 return false;
1715                         }
1716                         /* Cut trailing spaces */
1717                         stripped_spaces = 0;
1718                         while (ucl_test_character (*(chunk->pos - 1 - stripped_spaces),
1719                                         UCL_CHARACTER_WHITESPACE)) {
1720                                 stripped_spaces ++;
1721                         }
1722                         str_len = chunk->pos - c - stripped_spaces;
1723                         if (str_len <= 0) {
1724                                 ucl_set_err (parser, UCL_ESYNTAX, "string value must not be empty",
1725                                                 &parser->err);
1726                                 return false;
1727                         }
1728                         else if (str_len == 4 && memcmp (c, "null", 4) == 0) {
1729                                 obj->len = 0;
1730                                 obj->type = UCL_NULL;
1731                         }
1732                         else if (!ucl_maybe_parse_boolean (obj, c, str_len)) {
1733                                 obj->type = UCL_STRING;
1734                                 if ((str_len = ucl_copy_or_store_ptr (parser, c,
1735                                                 &obj->trash_stack[UCL_TRASH_VALUE],
1736                                                 &obj->value.sv, str_len, need_unescape,
1737                                                 false, var_expand)) == -1) {
1738                                         return false;
1739                                 }
1740                                 obj->len = str_len;
1741                         }
1742                         parser->state = UCL_STATE_AFTER_VALUE;
1743                         p = chunk->pos;
1744
1745                         return true;
1746                         break;
1747                 }
1748         }
1749
1750         return true;
1751 }
1752
1753 /**
1754  * Handle after value data
1755  * @param parser
1756  * @param chunk
1757  * @return
1758  */
1759 static bool
1760 ucl_parse_after_value (struct ucl_parser *parser, struct ucl_chunk *chunk)
1761 {
1762         const unsigned char *p;
1763         bool got_sep = false;
1764         struct ucl_stack *st;
1765
1766         p = chunk->pos;
1767
1768         while (p < chunk->end) {
1769                 if (ucl_test_character (*p, UCL_CHARACTER_WHITESPACE)) {
1770                         /* Skip whitespaces */
1771                         ucl_chunk_skipc (chunk, p);
1772                 }
1773                 else if (chunk->remain >= 2 && ucl_lex_is_comment (p[0], p[1])) {
1774                         /* Skip comment */
1775                         if (!ucl_skip_comments (parser)) {
1776                                 return false;
1777                         }
1778                         /* Treat comment as a separator */
1779                         got_sep = true;
1780                         p = chunk->pos;
1781                 }
1782                 else if (ucl_test_character (*p, UCL_CHARACTER_VALUE_END)) {
1783                         if (*p == '}' || *p == ']') {
1784                                 if (parser->stack == NULL) {
1785                                         ucl_set_err (parser, UCL_ESYNTAX,
1786                                                         "end of array or object detected without corresponding start",
1787                                                         &parser->err);
1788                                         return false;
1789                                 }
1790                                 if ((*p == '}' && parser->stack->obj->type == UCL_OBJECT) ||
1791                                                 (*p == ']' && parser->stack->obj->type == UCL_ARRAY)) {
1792
1793                                         /* Pop all nested objects from a stack */
1794                                         st = parser->stack;
1795                                         parser->stack = st->next;
1796                                         UCL_FREE (sizeof (struct ucl_stack), st);
1797
1798                                         if (parser->cur_obj) {
1799                                                 ucl_attach_comment (parser, parser->cur_obj, true);
1800                                         }
1801
1802                                         while (parser->stack != NULL) {
1803                                                 st = parser->stack;
1804
1805                                                 if (st->next == NULL || st->next->level == st->level) {
1806                                                         break;
1807                                                 }
1808
1809                                                 parser->stack = st->next;
1810                                                 parser->cur_obj = st->obj;
1811                                                 UCL_FREE (sizeof (struct ucl_stack), st);
1812                                         }
1813                                 }
1814                                 else {
1815                                         ucl_set_err (parser, UCL_ESYNTAX,
1816                                                         "unexpected terminating symbol detected",
1817                                                         &parser->err);
1818                                         return false;
1819                                 }
1820
1821                                 if (parser->stack == NULL) {
1822                                         /* Ignore everything after a top object */
1823                                         return true;
1824                                 }
1825                                 else {
1826                                         ucl_chunk_skipc (chunk, p);
1827                                 }
1828                                 got_sep = true;
1829                         }
1830                         else {
1831                                 /* Got a separator */
1832                                 got_sep = true;
1833                                 ucl_chunk_skipc (chunk, p);
1834                         }
1835                 }
1836                 else {
1837                         /* Anything else */
1838                         if (!got_sep) {
1839                                 ucl_set_err (parser, UCL_ESYNTAX, "delimiter is missing",
1840                                                 &parser->err);
1841                                 return false;
1842                         }
1843                         return true;
1844                 }
1845         }
1846
1847         return true;
1848 }
1849
1850 static bool
1851 ucl_skip_macro_as_comment (struct ucl_parser *parser,
1852                 struct ucl_chunk *chunk)
1853 {
1854         const unsigned char *p, *c;
1855         enum {
1856                 macro_skip_start = 0,
1857                 macro_has_symbols,
1858                 macro_has_obrace,
1859                 macro_has_quote,
1860                 macro_has_backslash,
1861                 macro_has_sqbrace,
1862                 macro_save
1863         } state = macro_skip_start, prev_state = macro_skip_start;
1864
1865         p = chunk->pos;
1866         c = chunk->pos;
1867
1868         while (p < chunk->end) {
1869                 switch (state) {
1870                 case macro_skip_start:
1871                         if (!ucl_test_character (*p, UCL_CHARACTER_WHITESPACE)) {
1872                                 state = macro_has_symbols;
1873                         }
1874                         else if (ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE)) {
1875                                 state = macro_save;
1876                                 continue;
1877                         }
1878
1879                         ucl_chunk_skipc (chunk, p);
1880                         break;
1881
1882                 case macro_has_symbols:
1883                         if (*p == '{') {
1884                                 state = macro_has_sqbrace;
1885                         }
1886                         else if (*p == '(') {
1887                                 state = macro_has_obrace;
1888                         }
1889                         else if (*p == '"') {
1890                                 state = macro_has_quote;
1891                         }
1892                         else if (*p == '\n') {
1893                                 state = macro_save;
1894                                 continue;
1895                         }
1896
1897                         ucl_chunk_skipc (chunk, p);
1898                         break;
1899
1900                 case macro_has_obrace:
1901                         if (*p == '\\') {
1902                                 prev_state = state;
1903                                 state = macro_has_backslash;
1904                         }
1905                         else if (*p == ')') {
1906                                 state = macro_has_symbols;
1907                         }
1908
1909                         ucl_chunk_skipc (chunk, p);
1910                         break;
1911
1912                 case macro_has_sqbrace:
1913                         if (*p == '\\') {
1914                                 prev_state = state;
1915                                 state = macro_has_backslash;
1916                         }
1917                         else if (*p == '}') {
1918                                 state = macro_save;
1919                         }
1920
1921                         ucl_chunk_skipc (chunk, p);
1922                         break;
1923
1924                 case macro_has_quote:
1925                         if (*p == '\\') {
1926                                 prev_state = state;
1927                                 state = macro_has_backslash;
1928                         }
1929                         else if (*p == '"') {
1930                                 state = macro_save;
1931                         }
1932
1933                         ucl_chunk_skipc (chunk, p);
1934                         break;
1935
1936                 case macro_has_backslash:
1937                         state = prev_state;
1938                         ucl_chunk_skipc (chunk, p);
1939                         break;
1940
1941                 case macro_save:
1942                         if (parser->flags & UCL_PARSER_SAVE_COMMENTS) {
1943                                 ucl_save_comment (parser, c, p - c);
1944                         }
1945
1946                         return true;
1947                 }
1948         }
1949
1950         return false;
1951 }
1952
1953 /**
1954  * Handle macro data
1955  * @param parser
1956  * @param chunk
1957  * @param marco
1958  * @param macro_start
1959  * @param macro_len
1960  * @return
1961  */
1962 static bool
1963 ucl_parse_macro_value (struct ucl_parser *parser,
1964                 struct ucl_chunk *chunk, struct ucl_macro *macro,
1965                 unsigned char const **macro_start, size_t *macro_len)
1966 {
1967         const unsigned char *p, *c;
1968         bool need_unescape = false, ucl_escape = false, var_expand = false;
1969
1970         p = chunk->pos;
1971
1972         switch (*p) {
1973         case '"':
1974                 /* We have macro value encoded in quotes */
1975                 c = p;
1976                 ucl_chunk_skipc (chunk, p);
1977                 if (!ucl_lex_json_string (parser, chunk, &need_unescape, &ucl_escape, &var_expand)) {
1978                         return false;
1979                 }
1980
1981                 *macro_start = c + 1;
1982                 *macro_len = chunk->pos - c - 2;
1983                 p = chunk->pos;
1984                 break;
1985         case '{':
1986                 /* We got a multiline macro body */
1987                 ucl_chunk_skipc (chunk, p);
1988                 /* Skip spaces at the beginning */
1989                 while (p < chunk->end) {
1990                         if (ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE)) {
1991                                 ucl_chunk_skipc (chunk, p);
1992                         }
1993                         else {
1994                                 break;
1995                         }
1996                 }
1997                 c = p;
1998                 while (p < chunk->end) {
1999                         if (*p == '}') {
2000                                 break;
2001                         }
2002                         ucl_chunk_skipc (chunk, p);
2003                 }
2004                 *macro_start = c;
2005                 *macro_len = p - c;
2006                 ucl_chunk_skipc (chunk, p);
2007                 break;
2008         default:
2009                 /* Macro is not enclosed in quotes or braces */
2010                 c = p;
2011                 while (p < chunk->end) {
2012                         if (ucl_lex_is_atom_end (*p)) {
2013                                 break;
2014                         }
2015                         ucl_chunk_skipc (chunk, p);
2016                 }
2017                 *macro_start = c;
2018                 *macro_len = p - c;
2019                 break;
2020         }
2021
2022         /* We are at the end of a macro */
2023         /* Skip ';' and space characters and return to previous state */
2024         while (p < chunk->end) {
2025                 if (!ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE) && *p != ';') {
2026                         break;
2027                 }
2028                 ucl_chunk_skipc (chunk, p);
2029         }
2030         return true;
2031 }
2032
2033 /**
2034  * Parse macro arguments as UCL object
2035  * @param parser parser structure
2036  * @param chunk the current data chunk
2037  * @return
2038  */
2039 static ucl_object_t *
2040 ucl_parse_macro_arguments (struct ucl_parser *parser,
2041                 struct ucl_chunk *chunk)
2042 {
2043         ucl_object_t *res = NULL;
2044         struct ucl_parser *params_parser;
2045         int obraces = 1, ebraces = 0, state = 0;
2046         const unsigned char *p, *c;
2047         size_t args_len = 0;
2048         struct ucl_parser_saved_state saved;
2049
2050         saved.column = chunk->column;
2051         saved.line = chunk->line;
2052         saved.pos = chunk->pos;
2053         saved.remain = chunk->remain;
2054         p = chunk->pos;
2055
2056         if (*p != '(' || chunk->remain < 2) {
2057                 return NULL;
2058         }
2059
2060         /* Set begin and start */
2061         ucl_chunk_skipc (chunk, p);
2062         c = p;
2063
2064         while ((p) < (chunk)->end) {
2065                 switch (state) {
2066                 case 0:
2067                         /* Parse symbols and check for '(', ')' and '"' */
2068                         if (*p == '(') {
2069                                 obraces ++;
2070                         }
2071                         else if (*p == ')') {
2072                                 ebraces ++;
2073                         }
2074                         else if (*p == '"') {
2075                                 state = 1;
2076                         }
2077                         /* Check pairing */
2078                         if (obraces == ebraces) {
2079                                 state = 99;
2080                         }
2081                         else {
2082                                 args_len ++;
2083                         }
2084                         /* Check overflow */
2085                         if (chunk->remain == 0) {
2086                                 goto restore_chunk;
2087                         }
2088                         ucl_chunk_skipc (chunk, p);
2089                         break;
2090                 case 1:
2091                         /* We have quote character, so skip all but quotes */
2092                         if (*p == '"' && *(p - 1) != '\\') {
2093                                 state = 0;
2094                         }
2095                         if (chunk->remain == 0) {
2096                                 goto restore_chunk;
2097                         }
2098                         args_len ++;
2099                         ucl_chunk_skipc (chunk, p);
2100                         break;
2101                 case 99:
2102                         /*
2103                          * We have read the full body of arguments, so we need to parse and set
2104                          * object from that
2105                          */
2106                         params_parser = ucl_parser_new (parser->flags);
2107                         if (!ucl_parser_add_chunk (params_parser, c, args_len)) {
2108                                 ucl_set_err (parser, UCL_ESYNTAX, "macro arguments parsing error",
2109                                                 &parser->err);
2110                         }
2111                         else {
2112                                 res = ucl_parser_get_object (params_parser);
2113                         }
2114                         ucl_parser_free (params_parser);
2115
2116                         return res;
2117
2118                         break;
2119                 }
2120         }
2121
2122         return res;
2123
2124 restore_chunk:
2125         chunk->column = saved.column;
2126         chunk->line = saved.line;
2127         chunk->pos = saved.pos;
2128         chunk->remain = saved.remain;
2129
2130         return NULL;
2131 }
2132
2133 #define SKIP_SPACES_COMMENTS(parser, chunk, p) do {                                                             \
2134         while ((p) < (chunk)->end) {                                                                                            \
2135                 if (!ucl_test_character (*(p), UCL_CHARACTER_WHITESPACE_UNSAFE)) {              \
2136                         if ((chunk)->remain >= 2 && ucl_lex_is_comment ((p)[0], (p)[1])) {      \
2137                                 if (!ucl_skip_comments (parser)) {                                                              \
2138                                         return false;                                                                                           \
2139                                 }                                                                                                                               \
2140                                 p = (chunk)->pos;                                                                                               \
2141                         }                                                                                                                                       \
2142                         break;                                                                                                                          \
2143                 }                                                                                                                                               \
2144                 ucl_chunk_skipc (chunk, p);                                                                                             \
2145         }                                                                                                                                                       \
2146 } while(0)
2147
2148 /**
2149  * Handle the main states of rcl parser
2150  * @param parser parser structure
2151  * @return true if chunk has been parsed and false in case of error
2152  */
2153 static bool
2154 ucl_state_machine (struct ucl_parser *parser)
2155 {
2156         ucl_object_t *obj, *macro_args;
2157         struct ucl_chunk *chunk = parser->chunks;
2158         const unsigned char *p, *c = NULL, *macro_start = NULL;
2159         unsigned char *macro_escaped;
2160         size_t macro_len = 0;
2161         struct ucl_macro *macro = NULL;
2162         bool next_key = false, end_of_object = false, ret;
2163
2164         if (parser->top_obj == NULL) {
2165                 parser->state = UCL_STATE_INIT;
2166         }
2167
2168         p = chunk->pos;
2169         while (chunk->pos < chunk->end) {
2170                 switch (parser->state) {
2171                 case UCL_STATE_INIT:
2172                         /*
2173                          * At the init state we can either go to the parse array or object
2174                          * if we got [ or { correspondingly or can just treat new data as
2175                          * a key of newly created object
2176                          */
2177                         if (!ucl_skip_comments (parser)) {
2178                                 parser->prev_state = parser->state;
2179                                 parser->state = UCL_STATE_ERROR;
2180                                 return false;
2181                         }
2182                         else {
2183                                 /* Skip any spaces */
2184                                 while (p < chunk->end && ucl_test_character (*p,
2185                                                 UCL_CHARACTER_WHITESPACE_UNSAFE)) {
2186                                         ucl_chunk_skipc (chunk, p);
2187                                 }
2188
2189                                 p = chunk->pos;
2190
2191                                 if (*p == '[') {
2192                                         parser->state = UCL_STATE_VALUE;
2193                                         ucl_chunk_skipc (chunk, p);
2194                                 }
2195                                 else {
2196                                         parser->state = UCL_STATE_KEY;
2197                                         if (*p == '{') {
2198                                                 ucl_chunk_skipc (chunk, p);
2199                                         }
2200                                 }
2201
2202                                 if (parser->top_obj == NULL) {
2203                                         if (parser->state == UCL_STATE_VALUE) {
2204                                                 obj = ucl_parser_add_container (NULL, parser, true, 0);
2205                                         }
2206                                         else {
2207                                                 obj = ucl_parser_add_container (NULL, parser, false, 0);
2208                                         }
2209
2210                                         if (obj == NULL) {
2211                                                 return false;
2212                                         }
2213
2214                                         parser->top_obj = obj;
2215                                         parser->cur_obj = obj;
2216                                 }
2217
2218                         }
2219                         break;
2220                 case UCL_STATE_KEY:
2221                         /* Skip any spaces */
2222                         while (p < chunk->end && ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE)) {
2223                                 ucl_chunk_skipc (chunk, p);
2224                         }
2225                         if (p == chunk->end || *p == '}') {
2226                                 /* We have the end of an object */
2227                                 parser->state = UCL_STATE_AFTER_VALUE;
2228                                 continue;
2229                         }
2230                         if (parser->stack == NULL) {
2231                                 /* No objects are on stack, but we want to parse a key */
2232                                 ucl_set_err (parser, UCL_ESYNTAX, "top object is finished but the parser "
2233                                                 "expects a key", &parser->err);
2234                                 parser->prev_state = parser->state;
2235                                 parser->state = UCL_STATE_ERROR;
2236                                 return false;
2237                         }
2238                         if (!ucl_parse_key (parser, chunk, &next_key, &end_of_object)) {
2239                                 parser->prev_state = parser->state;
2240                                 parser->state = UCL_STATE_ERROR;
2241                                 return false;
2242                         }
2243                         if (end_of_object) {
2244                                 p = chunk->pos;
2245                                 parser->state = UCL_STATE_AFTER_VALUE;
2246                                 continue;
2247                         }
2248                         else if (parser->state != UCL_STATE_MACRO_NAME) {
2249                                 if (next_key && parser->stack->obj->type == UCL_OBJECT) {
2250                                         /* Parse more keys and nest objects accordingly */
2251                                         obj = ucl_parser_add_container (parser->cur_obj, parser, false,
2252                                                         parser->stack->level + 1);
2253                                         if (obj == NULL) {
2254                                                 return false;
2255                                         }
2256                                 }
2257                                 else {
2258                                         parser->state = UCL_STATE_VALUE;
2259                                 }
2260                         }
2261                         else {
2262                                 c = chunk->pos;
2263                         }
2264                         p = chunk->pos;
2265                         break;
2266                 case UCL_STATE_VALUE:
2267                         /* We need to check what we do have */
2268                         if (!parser->cur_obj || !ucl_parse_value (parser, chunk)) {
2269                                 parser->prev_state = parser->state;
2270                                 parser->state = UCL_STATE_ERROR;
2271                                 return false;
2272                         }
2273                         /* State is set in ucl_parse_value call */
2274                         p = chunk->pos;
2275                         break;
2276                 case UCL_STATE_AFTER_VALUE:
2277                         if (!ucl_parse_after_value (parser, chunk)) {
2278                                 parser->prev_state = parser->state;
2279                                 parser->state = UCL_STATE_ERROR;
2280                                 return false;
2281                         }
2282
2283                         if (parser->stack != NULL) {
2284                                 if (parser->stack->obj->type == UCL_OBJECT) {
2285                                         parser->state = UCL_STATE_KEY;
2286                                 }
2287                                 else {
2288                                         /* Array */
2289                                         parser->state = UCL_STATE_VALUE;
2290                                 }
2291                         }
2292                         else {
2293                                 /* Skip everything at the end */
2294                                 return true;
2295                         }
2296
2297                         p = chunk->pos;
2298                         break;
2299                 case UCL_STATE_MACRO_NAME:
2300                         if (parser->flags & UCL_PARSER_DISABLE_MACRO) {
2301                                 if (!ucl_skip_macro_as_comment (parser, chunk)) {
2302                                         /* We have invalid macro */
2303                                         ucl_create_err (&parser->err,
2304                                                         "error on line %d at column %d: invalid macro",
2305                                                         chunk->line,
2306                                                         chunk->column);
2307                                         parser->state = UCL_STATE_ERROR;
2308                                         return false;
2309                                 }
2310                                 else {
2311                                         p = chunk->pos;
2312                                         parser->state = parser->prev_state;
2313                                 }
2314                         }
2315                         else {
2316                                 if (!ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE) &&
2317                                                 *p != '(') {
2318                                         ucl_chunk_skipc (chunk, p);
2319                                 }
2320                                 else {
2321                                         if (c != NULL && p - c > 0) {
2322                                                 /* We got macro name */
2323                                                 macro_len = (size_t) (p - c);
2324                                                 HASH_FIND (hh, parser->macroes, c, macro_len, macro);
2325                                                 if (macro == NULL) {
2326                                                         ucl_create_err (&parser->err,
2327                                                                         "error on line %d at column %d: "
2328                                                                         "unknown macro: '%.*s', character: '%c'",
2329                                                                         chunk->line,
2330                                                                         chunk->column,
2331                                                                         (int) (p - c),
2332                                                                         c,
2333                                                                         *chunk->pos);
2334                                                         parser->state = UCL_STATE_ERROR;
2335                                                         return false;
2336                                                 }
2337                                                 /* Now we need to skip all spaces */
2338                                                 SKIP_SPACES_COMMENTS(parser, chunk, p);
2339                                                 parser->state = UCL_STATE_MACRO;
2340                                         }
2341                                         else {
2342                                                 /* We have invalid macro name */
2343                                                 ucl_create_err (&parser->err,
2344                                                                 "error on line %d at column %d: invalid macro name",
2345                                                                 chunk->line,
2346                                                                 chunk->column);
2347                                                 parser->state = UCL_STATE_ERROR;
2348                                                 return false;
2349                                         }
2350                                 }
2351                         }
2352                         break;
2353                 case UCL_STATE_MACRO:
2354                         if (*chunk->pos == '(') {
2355                                 macro_args = ucl_parse_macro_arguments (parser, chunk);
2356                                 p = chunk->pos;
2357                                 if (macro_args) {
2358                                         SKIP_SPACES_COMMENTS(parser, chunk, p);
2359                                 }
2360                         }
2361                         else {
2362                                 macro_args = NULL;
2363                         }
2364                         if (!ucl_parse_macro_value (parser, chunk, macro,
2365                                         &macro_start, &macro_len)) {
2366                                 parser->prev_state = parser->state;
2367                                 parser->state = UCL_STATE_ERROR;
2368                                 return false;
2369                         }
2370                         macro_len = ucl_expand_variable (parser, &macro_escaped,
2371                                         macro_start, macro_len);
2372                         parser->state = parser->prev_state;
2373
2374                         if (macro_escaped == NULL && macro != NULL) {
2375                                 if (macro->is_context) {
2376                                         ret = macro->h.context_handler (macro_start, macro_len,
2377                                                         macro_args,
2378                                                         parser->top_obj,
2379                                                         macro->ud);
2380                                 }
2381                                 else {
2382                                         ret = macro->h.handler (macro_start, macro_len, macro_args,
2383                                                         macro->ud);
2384                                 }
2385                         }
2386                         else if (macro != NULL) {
2387                                 if (macro->is_context) {
2388                                         ret = macro->h.context_handler (macro_escaped, macro_len,
2389                                                         macro_args,
2390                                                         parser->top_obj,
2391                                                         macro->ud);
2392                                 }
2393                                 else {
2394                                         ret = macro->h.handler (macro_escaped, macro_len, macro_args,
2395                                                 macro->ud);
2396                                 }
2397
2398                                 UCL_FREE (macro_len + 1, macro_escaped);
2399                         }
2400                         else {
2401                                 ret = false;
2402                                 ucl_set_err (parser, UCL_EINTERNAL,
2403                                                 "internal error: parser has macro undefined", &parser->err);
2404                         }
2405
2406                         /*
2407                          * Chunk can be modified within macro handler
2408                          */
2409                         chunk = parser->chunks;
2410                         p = chunk->pos;
2411
2412                         if (macro_args) {
2413                                 ucl_object_unref (macro_args);
2414                         }
2415
2416                         if (!ret) {
2417                                 return false;
2418                         }
2419                         break;
2420                 default:
2421                         ucl_set_err (parser, UCL_EINTERNAL,
2422                                         "internal error: parser is in an unknown state", &parser->err);
2423                         parser->state = UCL_STATE_ERROR;
2424                         return false;
2425                 }
2426         }
2427
2428         if (parser->last_comment) {
2429                 if (parser->cur_obj) {
2430                         ucl_attach_comment (parser, parser->cur_obj, true);
2431                 }
2432                 else if (parser->stack && parser->stack->obj) {
2433                         ucl_attach_comment (parser, parser->stack->obj, true);
2434                 }
2435                 else if (parser->top_obj) {
2436                         ucl_attach_comment (parser, parser->top_obj, true);
2437                 }
2438                 else {
2439                         ucl_object_unref (parser->last_comment);
2440                 }
2441         }
2442
2443         return true;
2444 }
2445
2446 struct ucl_parser*
2447 ucl_parser_new (int flags)
2448 {
2449         struct ucl_parser *parser;
2450
2451         parser = UCL_ALLOC (sizeof (struct ucl_parser));
2452         if (parser == NULL) {
2453                 return NULL;
2454         }
2455
2456         memset (parser, 0, sizeof (struct ucl_parser));
2457
2458         ucl_parser_register_macro (parser, "include", ucl_include_handler, parser);
2459         ucl_parser_register_macro (parser, "try_include", ucl_try_include_handler, parser);
2460         ucl_parser_register_macro (parser, "includes", ucl_includes_handler, parser);
2461         ucl_parser_register_macro (parser, "priority", ucl_priority_handler, parser);
2462         ucl_parser_register_macro (parser, "load", ucl_load_handler, parser);
2463         ucl_parser_register_context_macro (parser, "inherit", ucl_inherit_handler, parser);
2464
2465         parser->flags = flags;
2466         parser->includepaths = NULL;
2467
2468         if (flags & UCL_PARSER_SAVE_COMMENTS) {
2469                 parser->comments = ucl_object_typed_new (UCL_OBJECT);
2470         }
2471
2472         if (!(flags & UCL_PARSER_NO_FILEVARS)) {
2473                 /* Initial assumption about filevars */
2474                 ucl_parser_set_filevars (parser, NULL, false);
2475         }
2476
2477         return parser;
2478 }
2479
2480 bool
2481 ucl_parser_set_default_priority (struct ucl_parser *parser, unsigned prio)
2482 {
2483         if (parser == NULL) {
2484                 return false;
2485         }
2486
2487         parser->default_priority = prio;
2488
2489         return true;
2490 }
2491
2492 void
2493 ucl_parser_register_macro (struct ucl_parser *parser, const char *macro,
2494                 ucl_macro_handler handler, void* ud)
2495 {
2496         struct ucl_macro *new;
2497
2498         if (macro == NULL || handler == NULL) {
2499                 return;
2500         }
2501
2502         new = UCL_ALLOC (sizeof (struct ucl_macro));
2503         if (new == NULL) {
2504                 return;
2505         }
2506
2507         memset (new, 0, sizeof (struct ucl_macro));
2508         new->h.handler = handler;
2509         new->name = strdup (macro);
2510         new->ud = ud;
2511         HASH_ADD_KEYPTR (hh, parser->macroes, new->name, strlen (new->name), new);
2512 }
2513
2514 void
2515 ucl_parser_register_context_macro (struct ucl_parser *parser, const char *macro,
2516                 ucl_context_macro_handler handler, void* ud)
2517 {
2518         struct ucl_macro *new;
2519
2520         if (macro == NULL || handler == NULL) {
2521                 return;
2522         }
2523
2524         new = UCL_ALLOC (sizeof (struct ucl_macro));
2525         if (new == NULL) {
2526                 return;
2527         }
2528
2529         memset (new, 0, sizeof (struct ucl_macro));
2530         new->h.context_handler = handler;
2531         new->name = strdup (macro);
2532         new->ud = ud;
2533         new->is_context = true;
2534         HASH_ADD_KEYPTR (hh, parser->macroes, new->name, strlen (new->name), new);
2535 }
2536
2537 void
2538 ucl_parser_register_variable (struct ucl_parser *parser, const char *var,
2539                 const char *value)
2540 {
2541         struct ucl_variable *new = NULL, *cur;
2542
2543         if (var == NULL) {
2544                 return;
2545         }
2546
2547         /* Find whether a variable already exists */
2548         LL_FOREACH (parser->variables, cur) {
2549                 if (strcmp (cur->var, var) == 0) {
2550                         new = cur;
2551                         break;
2552                 }
2553         }
2554
2555         if (value == NULL) {
2556
2557                 if (new != NULL) {
2558                         /* Remove variable */
2559                         DL_DELETE (parser->variables, new);
2560                         free (new->var);
2561                         free (new->value);
2562                         UCL_FREE (sizeof (struct ucl_variable), new);
2563                 }
2564                 else {
2565                         /* Do nothing */
2566                         return;
2567                 }
2568         }
2569         else {
2570                 if (new == NULL) {
2571                         new = UCL_ALLOC (sizeof (struct ucl_variable));
2572                         if (new == NULL) {
2573                                 return;
2574                         }
2575                         memset (new, 0, sizeof (struct ucl_variable));
2576                         new->var = strdup (var);
2577                         new->var_len = strlen (var);
2578                         new->value = strdup (value);
2579                         new->value_len = strlen (value);
2580
2581                         DL_APPEND (parser->variables, new);
2582                 }
2583                 else {
2584                         free (new->value);
2585                         new->value = strdup (value);
2586                         new->value_len = strlen (value);
2587                 }
2588         }
2589 }
2590
2591 void
2592 ucl_parser_set_variables_handler (struct ucl_parser *parser,
2593                 ucl_variable_handler handler, void *ud)
2594 {
2595         parser->var_handler = handler;
2596         parser->var_data = ud;
2597 }
2598
2599 bool
2600 ucl_parser_add_chunk_full (struct ucl_parser *parser, const unsigned char *data,
2601                 size_t len, unsigned priority, enum ucl_duplicate_strategy strat,
2602                 enum ucl_parse_type parse_type)
2603 {
2604         struct ucl_chunk *chunk;
2605
2606         if (parser == NULL) {
2607                 return false;
2608         }
2609
2610         if (data == NULL && len != 0) {
2611                 ucl_create_err (&parser->err, "invalid chunk added");
2612                 return false;
2613         }
2614
2615         if (parser->state != UCL_STATE_ERROR) {
2616                 chunk = UCL_ALLOC (sizeof (struct ucl_chunk));
2617                 if (chunk == NULL) {
2618                         ucl_create_err (&parser->err, "cannot allocate chunk structure");
2619                         return false;
2620                 }
2621
2622                 if (parse_type == UCL_PARSE_AUTO && len > 0) {
2623                         /* We need to detect parse type by the first symbol */
2624                         if ((*data & 0x80) == 0x80 && (*data >= 0xdc && *data <= 0xdf)) {
2625                                 parse_type = UCL_PARSE_MSGPACK;
2626                         }
2627                         else if (*data == '(') {
2628                                 parse_type = UCL_PARSE_CSEXP;
2629                         }
2630                         else {
2631                                 parse_type = UCL_PARSE_UCL;
2632                         }
2633                 }
2634
2635                 chunk->begin = data;
2636                 chunk->remain = len;
2637                 chunk->pos = chunk->begin;
2638                 chunk->end = chunk->begin + len;
2639                 chunk->line = 1;
2640                 chunk->column = 0;
2641                 chunk->priority = priority;
2642                 chunk->strategy = strat;
2643                 chunk->parse_type = parse_type;
2644                 LL_PREPEND (parser->chunks, chunk);
2645                 parser->recursion ++;
2646
2647                 if (parser->recursion > UCL_MAX_RECURSION) {
2648                         ucl_create_err (&parser->err, "maximum include nesting limit is reached: %d",
2649                                         parser->recursion);
2650                         return false;
2651                 }
2652
2653                 if (len > 0) {
2654                         /* Need to parse something */
2655                         switch (parse_type) {
2656                         default:
2657                         case UCL_PARSE_UCL:
2658                                 return ucl_state_machine (parser);
2659                         case UCL_PARSE_MSGPACK:
2660                                 return ucl_parse_msgpack (parser);
2661                         case UCL_PARSE_CSEXP:
2662                                 return ucl_parse_csexp (parser);
2663                         }
2664                 }
2665                 else {
2666                         /* Just add empty chunk and go forward */
2667                         if (parser->top_obj == NULL) {
2668                                 /*
2669                                  * In case of empty object, create one to indicate that we've
2670                                  * read something
2671                                  */
2672                                 parser->top_obj = ucl_object_new_full (UCL_OBJECT, priority);
2673                         }
2674
2675                         return true;
2676                 }
2677         }
2678
2679         ucl_create_err (&parser->err, "a parser is in an invalid state");
2680
2681         return false;
2682 }
2683
2684 bool
2685 ucl_parser_add_chunk_priority (struct ucl_parser *parser,
2686                 const unsigned char *data, size_t len, unsigned priority)
2687 {
2688         /* We dereference parser, so this check is essential */
2689         if (parser == NULL) {
2690                 return false;
2691         }
2692
2693         return ucl_parser_add_chunk_full (parser, data, len,
2694                                 priority, UCL_DUPLICATE_APPEND, UCL_PARSE_UCL);
2695 }
2696
2697 bool
2698 ucl_parser_add_chunk (struct ucl_parser *parser, const unsigned char *data,
2699                 size_t len)
2700 {
2701         if (parser == NULL) {
2702                 return false;
2703         }
2704
2705         return ucl_parser_add_chunk_full (parser, data, len,
2706                         parser->default_priority, UCL_DUPLICATE_APPEND, UCL_PARSE_UCL);
2707 }
2708
2709 bool
2710 ucl_parser_add_string_priority (struct ucl_parser *parser, const char *data,
2711                 size_t len, unsigned priority)
2712 {
2713         if (data == NULL) {
2714                 ucl_create_err (&parser->err, "invalid string added");
2715                 return false;
2716         }
2717         if (len == 0) {
2718                 len = strlen (data);
2719         }
2720
2721         return ucl_parser_add_chunk_priority (parser,
2722                         (const unsigned char *)data, len, priority);
2723 }
2724
2725 bool
2726 ucl_parser_add_string (struct ucl_parser *parser, const char *data,
2727                 size_t len)
2728 {
2729         if (parser == NULL) {
2730                 return false;
2731         }
2732
2733         return ucl_parser_add_string_priority (parser,
2734                         (const unsigned char *)data, len, parser->default_priority);
2735 }
2736
2737 bool
2738 ucl_set_include_path (struct ucl_parser *parser, ucl_object_t *paths)
2739 {
2740         if (parser == NULL || paths == NULL) {
2741                 return false;
2742         }
2743
2744         if (parser->includepaths == NULL) {
2745                 parser->includepaths = ucl_object_copy (paths);
2746         }
2747         else {
2748                 ucl_object_unref (parser->includepaths);
2749                 parser->includepaths = ucl_object_copy (paths);
2750         }
2751
2752         if (parser->includepaths == NULL) {
2753                 return false;
2754         }
2755
2756         return true;
2757 }