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