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