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