Coverage Report

Created: 2024-02-25 06:19

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