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