ucl 0.1.4 → 0.2.0

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