1262395Sbapt/* Copyright (c) 2013, Vsevolod Stakhov 2262395Sbapt * All rights reserved. 3262395Sbapt * 4262395Sbapt * Redistribution and use in source and binary forms, with or without 5262395Sbapt * modification, are permitted provided that the following conditions are met: 6262395Sbapt * * Redistributions of source code must retain the above copyright 7262395Sbapt * notice, this list of conditions and the following disclaimer. 8262395Sbapt * * Redistributions in binary form must reproduce the above copyright 9262395Sbapt * notice, this list of conditions and the following disclaimer in the 10262395Sbapt * documentation and/or other materials provided with the distribution. 11262395Sbapt * 12262395Sbapt * THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY 13262395Sbapt * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 14262395Sbapt * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 15262395Sbapt * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY 16262395Sbapt * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 17262395Sbapt * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 18262395Sbapt * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 19262395Sbapt * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 20262395Sbapt * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 21262395Sbapt * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 22262395Sbapt */ 23262395Sbapt 24262395Sbapt#include "ucl.h" 25262395Sbapt#include "ucl_internal.h" 26262395Sbapt#include "ucl_chartable.h" 27262395Sbapt 28262395Sbapt/** 29275223Sbapt * @file ucl_parser.c 30275223Sbapt * The implementation of ucl parser 31262395Sbapt */ 32262395Sbapt 33262395Sbaptstruct ucl_parser_saved_state { 34262395Sbapt unsigned int line; 35262395Sbapt unsigned int column; 36262395Sbapt size_t remain; 37262395Sbapt const unsigned char *pos; 38262395Sbapt}; 39262395Sbapt 40262395Sbapt/** 41262395Sbapt * Move up to len characters 42262395Sbapt * @param parser 43262395Sbapt * @param begin 44262395Sbapt * @param len 45262395Sbapt * @return new position in chunk 46262395Sbapt */ 47262395Sbapt#define ucl_chunk_skipc(chunk, p) do{ \ 48262395Sbapt if (*(p) == '\n') { \ 49262395Sbapt (chunk)->line ++; \ 50262395Sbapt (chunk)->column = 0; \ 51262395Sbapt } \ 52262395Sbapt else (chunk)->column ++; \ 53262395Sbapt (p++); \ 54262395Sbapt (chunk)->pos ++; \ 55262395Sbapt (chunk)->remain --; \ 56262395Sbapt } while (0) 57262395Sbapt 58262395Sbaptstatic inline void 59275223Sbaptucl_set_err (struct ucl_parser *parser, int code, const char *str, UT_string **err) 60262395Sbapt{ 61275223Sbapt const char *fmt_string, *filename; 62275223Sbapt struct ucl_chunk *chunk = parser->chunks; 63275223Sbapt 64275223Sbapt if (parser->cur_file) { 65275223Sbapt filename = parser->cur_file; 66275223Sbapt } 67275223Sbapt else { 68275223Sbapt filename = "<unknown>"; 69275223Sbapt } 70290071Sbapt 71262395Sbapt if (chunk->pos < chunk->end) { 72262395Sbapt if (isgraph (*chunk->pos)) { 73275223Sbapt fmt_string = "error while parsing %s: " 74275223Sbapt "line: %d, column: %d - '%s', character: '%c'"; 75262395Sbapt } 76262395Sbapt else { 77275223Sbapt fmt_string = "error while parsing %s: " 78275223Sbapt "line: %d, column: %d - '%s', character: '0x%02x'"; 79262395Sbapt } 80275223Sbapt ucl_create_err (err, fmt_string, 81275223Sbapt filename, chunk->line, chunk->column, 82275223Sbapt str, *chunk->pos); 83262395Sbapt } 84262395Sbapt else { 85275223Sbapt ucl_create_err (err, "error while parsing %s: at the end of chunk: %s", 86275223Sbapt filename, str); 87262395Sbapt } 88290071Sbapt 89290071Sbapt parser->err_code = code; 90262395Sbapt} 91262395Sbapt 92298166Sbaptstatic void 93298166Sbaptucl_save_comment (struct ucl_parser *parser, const char *begin, size_t len) 94298166Sbapt{ 95298166Sbapt ucl_object_t *nobj; 96298166Sbapt 97298166Sbapt if (len > 0 && begin != NULL) { 98298166Sbapt nobj = ucl_object_fromstring_common (begin, len, 0); 99298166Sbapt 100298166Sbapt if (parser->last_comment) { 101298166Sbapt /* We need to append data to an existing object */ 102298166Sbapt DL_APPEND (parser->last_comment, nobj); 103298166Sbapt } 104298166Sbapt else { 105298166Sbapt parser->last_comment = nobj; 106298166Sbapt } 107298166Sbapt } 108298166Sbapt} 109298166Sbapt 110298166Sbaptstatic void 111298166Sbaptucl_attach_comment (struct ucl_parser *parser, ucl_object_t *obj, bool before) 112298166Sbapt{ 113298166Sbapt if (parser->last_comment) { 114298166Sbapt ucl_object_insert_key (parser->comments, parser->last_comment, 115298166Sbapt (const char *)&obj, sizeof (void *), true); 116298166Sbapt 117298166Sbapt if (before) { 118298166Sbapt parser->last_comment->flags |= UCL_OBJECT_INHERITED; 119298166Sbapt } 120298166Sbapt 121298166Sbapt parser->last_comment = NULL; 122298166Sbapt } 123298166Sbapt} 124298166Sbapt 125262395Sbapt/** 126262395Sbapt * Skip all comments from the current pos resolving nested and multiline comments 127262395Sbapt * @param parser 128262395Sbapt * @return 129262395Sbapt */ 130262395Sbaptstatic bool 131262395Sbaptucl_skip_comments (struct ucl_parser *parser) 132262395Sbapt{ 133262395Sbapt struct ucl_chunk *chunk = parser->chunks; 134298166Sbapt const unsigned char *p, *beg = NULL; 135262395Sbapt int comments_nested = 0; 136275223Sbapt bool quoted = false; 137262395Sbapt 138262395Sbapt p = chunk->pos; 139262395Sbapt 140262395Sbaptstart: 141275223Sbapt if (chunk->remain > 0 && *p == '#') { 142262395Sbapt if (parser->state != UCL_STATE_SCOMMENT && 143262395Sbapt parser->state != UCL_STATE_MCOMMENT) { 144298166Sbapt beg = p; 145298166Sbapt 146262395Sbapt while (p < chunk->end) { 147262395Sbapt if (*p == '\n') { 148298166Sbapt if (parser->flags & UCL_PARSER_SAVE_COMMENTS) { 149298166Sbapt ucl_save_comment (parser, beg, p - beg); 150298166Sbapt beg = NULL; 151298166Sbapt } 152298166Sbapt 153262395Sbapt ucl_chunk_skipc (chunk, p); 154298166Sbapt 155262395Sbapt goto start; 156262395Sbapt } 157262395Sbapt ucl_chunk_skipc (chunk, p); 158262395Sbapt } 159262395Sbapt } 160262395Sbapt } 161275223Sbapt else if (chunk->remain >= 2 && *p == '/') { 162262395Sbapt if (p[1] == '*') { 163298166Sbapt beg = p; 164262395Sbapt ucl_chunk_skipc (chunk, p); 165262395Sbapt comments_nested ++; 166262395Sbapt ucl_chunk_skipc (chunk, p); 167262395Sbapt 168262395Sbapt while (p < chunk->end) { 169275223Sbapt if (*p == '"' && *(p - 1) != '\\') { 170275223Sbapt quoted = !quoted; 171275223Sbapt } 172275223Sbapt 173275223Sbapt if (!quoted) { 174275223Sbapt if (*p == '*') { 175275223Sbapt ucl_chunk_skipc (chunk, p); 176275223Sbapt if (*p == '/') { 177275223Sbapt comments_nested --; 178275223Sbapt if (comments_nested == 0) { 179298166Sbapt if (parser->flags & UCL_PARSER_SAVE_COMMENTS) { 180298166Sbapt ucl_save_comment (parser, beg, p - beg + 1); 181298166Sbapt beg = NULL; 182298166Sbapt } 183298166Sbapt 184275223Sbapt ucl_chunk_skipc (chunk, p); 185275223Sbapt goto start; 186275223Sbapt } 187262395Sbapt } 188275223Sbapt ucl_chunk_skipc (chunk, p); 189262395Sbapt } 190275223Sbapt else if (p[0] == '/' && chunk->remain >= 2 && p[1] == '*') { 191275223Sbapt comments_nested ++; 192275223Sbapt ucl_chunk_skipc (chunk, p); 193275223Sbapt ucl_chunk_skipc (chunk, p); 194275223Sbapt continue; 195275223Sbapt } 196262395Sbapt } 197298166Sbapt 198262395Sbapt ucl_chunk_skipc (chunk, p); 199262395Sbapt } 200262395Sbapt if (comments_nested != 0) { 201275223Sbapt ucl_set_err (parser, UCL_ENESTED, 202275223Sbapt "unfinished multiline comment", &parser->err); 203262395Sbapt return false; 204262395Sbapt } 205262395Sbapt } 206262395Sbapt } 207262395Sbapt 208298166Sbapt if (beg && p > beg && (parser->flags & UCL_PARSER_SAVE_COMMENTS)) { 209298166Sbapt ucl_save_comment (parser, beg, p - beg); 210298166Sbapt } 211298166Sbapt 212262395Sbapt return true; 213262395Sbapt} 214262395Sbapt 215262395Sbapt/** 216262395Sbapt * Return multiplier for a character 217262395Sbapt * @param c multiplier character 218262395Sbapt * @param is_bytes if true use 1024 multiplier 219262395Sbapt * @return multiplier 220262395Sbapt */ 221262395Sbaptstatic inline unsigned long 222262395Sbaptucl_lex_num_multiplier (const unsigned char c, bool is_bytes) { 223262395Sbapt const struct { 224262395Sbapt char c; 225262395Sbapt long mult_normal; 226262395Sbapt long mult_bytes; 227262395Sbapt } multipliers[] = { 228262395Sbapt {'m', 1000 * 1000, 1024 * 1024}, 229262395Sbapt {'k', 1000, 1024}, 230262395Sbapt {'g', 1000 * 1000 * 1000, 1024 * 1024 * 1024} 231262395Sbapt }; 232262395Sbapt int i; 233262395Sbapt 234262395Sbapt for (i = 0; i < 3; i ++) { 235262395Sbapt if (tolower (c) == multipliers[i].c) { 236262395Sbapt if (is_bytes) { 237262395Sbapt return multipliers[i].mult_bytes; 238262395Sbapt } 239262395Sbapt return multipliers[i].mult_normal; 240262395Sbapt } 241262395Sbapt } 242262395Sbapt 243262395Sbapt return 1; 244262395Sbapt} 245262395Sbapt 246262395Sbapt 247262395Sbapt/** 248262395Sbapt * Return multiplier for time scaling 249262395Sbapt * @param c 250262395Sbapt * @return 251262395Sbapt */ 252262395Sbaptstatic inline double 253262395Sbaptucl_lex_time_multiplier (const unsigned char c) { 254262395Sbapt const struct { 255262395Sbapt char c; 256262395Sbapt double mult; 257262395Sbapt } multipliers[] = { 258262395Sbapt {'m', 60}, 259262395Sbapt {'h', 60 * 60}, 260262395Sbapt {'d', 60 * 60 * 24}, 261262395Sbapt {'w', 60 * 60 * 24 * 7}, 262298166Sbapt {'y', 60 * 60 * 24 * 365} 263262395Sbapt }; 264262395Sbapt int i; 265262395Sbapt 266262395Sbapt for (i = 0; i < 5; i ++) { 267262395Sbapt if (tolower (c) == multipliers[i].c) { 268262395Sbapt return multipliers[i].mult; 269262395Sbapt } 270262395Sbapt } 271262395Sbapt 272262395Sbapt return 1; 273262395Sbapt} 274262395Sbapt 275262395Sbapt/** 276262395Sbapt * Return true if a character is a end of an atom 277262395Sbapt * @param c 278262395Sbapt * @return 279262395Sbapt */ 280262395Sbaptstatic inline bool 281262395Sbaptucl_lex_is_atom_end (const unsigned char c) 282262395Sbapt{ 283262395Sbapt return ucl_test_character (c, UCL_CHARACTER_VALUE_END); 284262395Sbapt} 285262395Sbapt 286262395Sbaptstatic inline bool 287262395Sbaptucl_lex_is_comment (const unsigned char c1, const unsigned char c2) 288262395Sbapt{ 289262395Sbapt if (c1 == '/') { 290262395Sbapt if (c2 == '*') { 291262395Sbapt return true; 292262395Sbapt } 293262395Sbapt } 294262395Sbapt else if (c1 == '#') { 295262395Sbapt return true; 296262395Sbapt } 297262395Sbapt return false; 298262395Sbapt} 299262395Sbapt 300262395Sbapt/** 301262395Sbapt * Check variable found 302262395Sbapt * @param parser 303262395Sbapt * @param ptr 304262395Sbapt * @param remain 305262395Sbapt * @param out_len 306262395Sbapt * @param strict 307262395Sbapt * @param found 308262395Sbapt * @return 309262395Sbapt */ 310262395Sbaptstatic inline const char * 311262395Sbaptucl_check_variable_safe (struct ucl_parser *parser, const char *ptr, size_t remain, 312262395Sbapt size_t *out_len, bool strict, bool *found) 313262395Sbapt{ 314262395Sbapt struct ucl_variable *var; 315266636Sbapt unsigned char *dst; 316266636Sbapt size_t dstlen; 317266636Sbapt bool need_free = false; 318262395Sbapt 319262395Sbapt LL_FOREACH (parser->variables, var) { 320262395Sbapt if (strict) { 321262395Sbapt if (remain == var->var_len) { 322262395Sbapt if (memcmp (ptr, var->var, var->var_len) == 0) { 323262395Sbapt *out_len += var->value_len; 324262395Sbapt *found = true; 325262395Sbapt return (ptr + var->var_len); 326262395Sbapt } 327262395Sbapt } 328262395Sbapt } 329262395Sbapt else { 330262395Sbapt if (remain >= var->var_len) { 331262395Sbapt if (memcmp (ptr, var->var, var->var_len) == 0) { 332262395Sbapt *out_len += var->value_len; 333262395Sbapt *found = true; 334262395Sbapt return (ptr + var->var_len); 335262395Sbapt } 336262395Sbapt } 337262395Sbapt } 338262395Sbapt } 339262395Sbapt 340266636Sbapt /* XXX: can only handle ${VAR} */ 341266636Sbapt if (!(*found) && parser->var_handler != NULL && strict) { 342266636Sbapt /* Call generic handler */ 343266636Sbapt if (parser->var_handler (ptr, remain, &dst, &dstlen, &need_free, 344266636Sbapt parser->var_data)) { 345307790Sbapt *out_len += dstlen; 346266636Sbapt *found = true; 347266636Sbapt if (need_free) { 348266636Sbapt free (dst); 349266636Sbapt } 350266636Sbapt return (ptr + remain); 351266636Sbapt } 352266636Sbapt } 353266636Sbapt 354262395Sbapt return ptr; 355262395Sbapt} 356262395Sbapt 357262395Sbapt/** 358262395Sbapt * Check for a variable in a given string 359262395Sbapt * @param parser 360262395Sbapt * @param ptr 361262395Sbapt * @param remain 362262395Sbapt * @param out_len 363262395Sbapt * @param vars_found 364262395Sbapt * @return 365262395Sbapt */ 366262395Sbaptstatic const char * 367266636Sbaptucl_check_variable (struct ucl_parser *parser, const char *ptr, 368266636Sbapt size_t remain, size_t *out_len, bool *vars_found) 369262395Sbapt{ 370262395Sbapt const char *p, *end, *ret = ptr; 371262395Sbapt bool found = false; 372262395Sbapt 373262395Sbapt if (*ptr == '{') { 374262395Sbapt /* We need to match the variable enclosed in braces */ 375262395Sbapt p = ptr + 1; 376262395Sbapt end = ptr + remain; 377262395Sbapt while (p < end) { 378262395Sbapt if (*p == '}') { 379266636Sbapt ret = ucl_check_variable_safe (parser, ptr + 1, p - ptr - 1, 380266636Sbapt out_len, true, &found); 381262395Sbapt if (found) { 382262395Sbapt /* {} must be excluded actually */ 383262395Sbapt ret ++; 384262395Sbapt if (!*vars_found) { 385262395Sbapt *vars_found = true; 386262395Sbapt } 387262395Sbapt } 388262395Sbapt else { 389262395Sbapt *out_len += 2; 390262395Sbapt } 391262395Sbapt break; 392262395Sbapt } 393262395Sbapt p ++; 394262395Sbapt } 395262395Sbapt } 396262395Sbapt else if (*ptr != '$') { 397262395Sbapt /* Not count escaped dollar sign */ 398262395Sbapt ret = ucl_check_variable_safe (parser, ptr, remain, out_len, false, &found); 399262395Sbapt if (found && !*vars_found) { 400262395Sbapt *vars_found = true; 401262395Sbapt } 402262395Sbapt if (!found) { 403262395Sbapt (*out_len) ++; 404262395Sbapt } 405262395Sbapt } 406262395Sbapt else { 407262395Sbapt ret ++; 408262395Sbapt (*out_len) ++; 409262395Sbapt } 410262395Sbapt 411262395Sbapt return ret; 412262395Sbapt} 413262395Sbapt 414262395Sbapt/** 415262395Sbapt * Expand a single variable 416262395Sbapt * @param parser 417262395Sbapt * @param ptr 418262395Sbapt * @param remain 419262395Sbapt * @param dest 420262395Sbapt * @return 421262395Sbapt */ 422262395Sbaptstatic const char * 423262395Sbaptucl_expand_single_variable (struct ucl_parser *parser, const char *ptr, 424262395Sbapt size_t remain, unsigned char **dest) 425262395Sbapt{ 426266636Sbapt unsigned char *d = *dest, *dst; 427262395Sbapt const char *p = ptr + 1, *ret; 428262395Sbapt struct ucl_variable *var; 429266636Sbapt size_t dstlen; 430266636Sbapt bool need_free = false; 431262395Sbapt bool found = false; 432266636Sbapt bool strict = false; 433262395Sbapt 434262395Sbapt ret = ptr + 1; 435262395Sbapt remain --; 436262395Sbapt 437262395Sbapt if (*p == '$') { 438262395Sbapt *d++ = *p++; 439262395Sbapt *dest = d; 440262395Sbapt return p; 441262395Sbapt } 442262395Sbapt else if (*p == '{') { 443262395Sbapt p ++; 444266636Sbapt strict = true; 445262395Sbapt ret += 2; 446262395Sbapt remain -= 2; 447262395Sbapt } 448262395Sbapt 449262395Sbapt LL_FOREACH (parser->variables, var) { 450262395Sbapt if (remain >= var->var_len) { 451262395Sbapt if (memcmp (p, var->var, var->var_len) == 0) { 452262395Sbapt memcpy (d, var->value, var->value_len); 453262395Sbapt ret += var->var_len; 454262395Sbapt d += var->value_len; 455262395Sbapt found = true; 456262395Sbapt break; 457262395Sbapt } 458262395Sbapt } 459262395Sbapt } 460262395Sbapt if (!found) { 461266636Sbapt if (strict && parser->var_handler != NULL) { 462307790Sbapt size_t var_len = 0; 463307790Sbapt while (var_len < remain && p[var_len] != '}') 464307790Sbapt var_len ++; 465307790Sbapt 466307790Sbapt if (parser->var_handler (p, var_len, &dst, &dstlen, &need_free, 467266636Sbapt parser->var_data)) { 468266636Sbapt memcpy (d, dst, dstlen); 469307790Sbapt ret += var_len; 470307790Sbapt d += dstlen; 471307790Sbapt if (need_free) { 472307790Sbapt free (dst); 473307790Sbapt } 474266636Sbapt found = true; 475266636Sbapt } 476266636Sbapt } 477266636Sbapt 478266636Sbapt /* Leave variable as is */ 479266636Sbapt if (!found) { 480268831Sbapt if (strict) { 481268831Sbapt /* Copy '${' */ 482268831Sbapt memcpy (d, ptr, 2); 483268831Sbapt d += 2; 484268831Sbapt ret --; 485268831Sbapt } 486268831Sbapt else { 487268831Sbapt memcpy (d, ptr, 1); 488268831Sbapt d ++; 489268831Sbapt } 490266636Sbapt } 491262395Sbapt } 492262395Sbapt 493262395Sbapt *dest = d; 494262395Sbapt return ret; 495262395Sbapt} 496262395Sbapt 497262395Sbapt/** 498262395Sbapt * Expand variables in string 499262395Sbapt * @param parser 500262395Sbapt * @param dst 501262395Sbapt * @param src 502262395Sbapt * @param in_len 503262395Sbapt * @return 504262395Sbapt */ 505262395Sbaptstatic ssize_t 506262395Sbaptucl_expand_variable (struct ucl_parser *parser, unsigned char **dst, 507262395Sbapt const char *src, size_t in_len) 508262395Sbapt{ 509262395Sbapt const char *p, *end = src + in_len; 510262395Sbapt unsigned char *d; 511262395Sbapt size_t out_len = 0; 512262395Sbapt bool vars_found = false; 513262395Sbapt 514298166Sbapt if (parser->flags & UCL_PARSER_DISABLE_MACRO) { 515298166Sbapt *dst = NULL; 516298166Sbapt return in_len; 517298166Sbapt } 518298166Sbapt 519262395Sbapt p = src; 520262395Sbapt while (p != end) { 521262395Sbapt if (*p == '$') { 522262395Sbapt p = ucl_check_variable (parser, p + 1, end - p - 1, &out_len, &vars_found); 523262395Sbapt } 524262395Sbapt else { 525262395Sbapt p ++; 526262395Sbapt out_len ++; 527262395Sbapt } 528262395Sbapt } 529262395Sbapt 530262395Sbapt if (!vars_found) { 531262395Sbapt /* Trivial case */ 532262395Sbapt *dst = NULL; 533262395Sbapt return in_len; 534262395Sbapt } 535262395Sbapt 536262395Sbapt *dst = UCL_ALLOC (out_len + 1); 537262395Sbapt if (*dst == NULL) { 538262395Sbapt return in_len; 539262395Sbapt } 540262395Sbapt 541262395Sbapt d = *dst; 542262395Sbapt p = src; 543262395Sbapt while (p != end) { 544262395Sbapt if (*p == '$') { 545262395Sbapt p = ucl_expand_single_variable (parser, p, end - p, &d); 546262395Sbapt } 547262395Sbapt else { 548262395Sbapt *d++ = *p++; 549262395Sbapt } 550262395Sbapt } 551262395Sbapt 552262395Sbapt *d = '\0'; 553262395Sbapt 554262395Sbapt return out_len; 555262395Sbapt} 556262395Sbapt 557262395Sbapt/** 558262395Sbapt * Store or copy pointer to the trash stack 559262395Sbapt * @param parser parser object 560262395Sbapt * @param src src string 561262395Sbapt * @param dst destination buffer (trash stack pointer) 562262395Sbapt * @param dst_const const destination pointer (e.g. value of object) 563262395Sbapt * @param in_len input length 564262395Sbapt * @param need_unescape need to unescape source (and copy it) 565262395Sbapt * @param need_lowercase need to lowercase value (and copy) 566262395Sbapt * @param need_expand need to expand variables (and copy as well) 567262395Sbapt * @return output length (excluding \0 symbol) 568262395Sbapt */ 569262395Sbaptstatic inline ssize_t 570262395Sbaptucl_copy_or_store_ptr (struct ucl_parser *parser, 571262395Sbapt const unsigned char *src, unsigned char **dst, 572262395Sbapt const char **dst_const, size_t in_len, 573262395Sbapt bool need_unescape, bool need_lowercase, bool need_expand) 574262395Sbapt{ 575262395Sbapt ssize_t ret = -1, tret; 576262395Sbapt unsigned char *tmp; 577262395Sbapt 578262395Sbapt if (need_unescape || need_lowercase || 579262395Sbapt (need_expand && parser->variables != NULL) || 580262395Sbapt !(parser->flags & UCL_PARSER_ZEROCOPY)) { 581262395Sbapt /* Copy string */ 582262395Sbapt *dst = UCL_ALLOC (in_len + 1); 583262395Sbapt if (*dst == NULL) { 584290071Sbapt ucl_set_err (parser, UCL_EINTERNAL, "cannot allocate memory for a string", 585275223Sbapt &parser->err); 586262395Sbapt return false; 587262395Sbapt } 588262395Sbapt if (need_lowercase) { 589262395Sbapt ret = ucl_strlcpy_tolower (*dst, src, in_len + 1); 590262395Sbapt } 591262395Sbapt else { 592262395Sbapt ret = ucl_strlcpy_unsafe (*dst, src, in_len + 1); 593262395Sbapt } 594262395Sbapt 595262395Sbapt if (need_unescape) { 596262395Sbapt ret = ucl_unescape_json_string (*dst, ret); 597262395Sbapt } 598262395Sbapt if (need_expand) { 599262395Sbapt tmp = *dst; 600262395Sbapt tret = ret; 601262395Sbapt ret = ucl_expand_variable (parser, dst, tmp, ret); 602262395Sbapt if (*dst == NULL) { 603262395Sbapt /* Nothing to expand */ 604262395Sbapt *dst = tmp; 605262395Sbapt ret = tret; 606262395Sbapt } 607275223Sbapt else { 608275223Sbapt /* Free unexpanded value */ 609275223Sbapt UCL_FREE (in_len + 1, tmp); 610275223Sbapt } 611262395Sbapt } 612262395Sbapt *dst_const = *dst; 613262395Sbapt } 614262395Sbapt else { 615262395Sbapt *dst_const = src; 616262395Sbapt ret = in_len; 617262395Sbapt } 618262395Sbapt 619262395Sbapt return ret; 620262395Sbapt} 621262395Sbapt 622262395Sbapt/** 623262395Sbapt * Create and append an object at the specified level 624262395Sbapt * @param parser 625262395Sbapt * @param is_array 626262395Sbapt * @param level 627262395Sbapt * @return 628262395Sbapt */ 629262395Sbaptstatic inline ucl_object_t * 630290071Sbaptucl_parser_add_container (ucl_object_t *obj, struct ucl_parser *parser, 631290071Sbapt bool is_array, int level) 632262395Sbapt{ 633262395Sbapt struct ucl_stack *st; 634262395Sbapt 635262395Sbapt if (!is_array) { 636262395Sbapt if (obj == NULL) { 637275223Sbapt obj = ucl_object_new_full (UCL_OBJECT, parser->chunks->priority); 638262395Sbapt } 639262395Sbapt else { 640262395Sbapt obj->type = UCL_OBJECT; 641262395Sbapt } 642290071Sbapt if (obj->value.ov == NULL) { 643290071Sbapt obj->value.ov = ucl_hash_create (parser->flags & UCL_PARSER_KEY_LOWERCASE); 644290071Sbapt } 645262395Sbapt parser->state = UCL_STATE_KEY; 646262395Sbapt } 647262395Sbapt else { 648262395Sbapt if (obj == NULL) { 649275223Sbapt obj = ucl_object_new_full (UCL_ARRAY, parser->chunks->priority); 650262395Sbapt } 651262395Sbapt else { 652262395Sbapt obj->type = UCL_ARRAY; 653262395Sbapt } 654262395Sbapt parser->state = UCL_STATE_VALUE; 655262395Sbapt } 656262395Sbapt 657262395Sbapt st = UCL_ALLOC (sizeof (struct ucl_stack)); 658298166Sbapt 659263648Sbapt if (st == NULL) { 660290071Sbapt ucl_set_err (parser, UCL_EINTERNAL, "cannot allocate memory for an object", 661275223Sbapt &parser->err); 662275223Sbapt ucl_object_unref (obj); 663263648Sbapt return NULL; 664263648Sbapt } 665298166Sbapt 666262395Sbapt st->obj = obj; 667262395Sbapt st->level = level; 668262395Sbapt LL_PREPEND (parser->stack, st); 669262395Sbapt parser->cur_obj = obj; 670262395Sbapt 671262395Sbapt return obj; 672262395Sbapt} 673262395Sbapt 674262395Sbaptint 675262395Sbaptucl_maybe_parse_number (ucl_object_t *obj, 676263648Sbapt const char *start, const char *end, const char **pos, 677263648Sbapt bool allow_double, bool number_bytes, bool allow_time) 678262395Sbapt{ 679262395Sbapt const char *p = start, *c = start; 680262395Sbapt char *endptr; 681262395Sbapt bool got_dot = false, got_exp = false, need_double = false, 682263648Sbapt is_time = false, valid_start = false, is_hex = false, 683262395Sbapt is_neg = false; 684262395Sbapt double dv = 0; 685262395Sbapt int64_t lv = 0; 686262395Sbapt 687262395Sbapt if (*p == '-') { 688262395Sbapt is_neg = true; 689262395Sbapt c ++; 690262395Sbapt p ++; 691262395Sbapt } 692262395Sbapt while (p < end) { 693262395Sbapt if (is_hex && isxdigit (*p)) { 694262395Sbapt p ++; 695262395Sbapt } 696262395Sbapt else if (isdigit (*p)) { 697262395Sbapt valid_start = true; 698262395Sbapt p ++; 699262395Sbapt } 700262395Sbapt else if (!is_hex && (*p == 'x' || *p == 'X')) { 701262395Sbapt is_hex = true; 702262395Sbapt allow_double = false; 703262395Sbapt c = p + 1; 704262395Sbapt } 705262395Sbapt else if (allow_double) { 706262395Sbapt if (p == c) { 707262395Sbapt /* Empty digits sequence, not a number */ 708262395Sbapt *pos = start; 709262395Sbapt return EINVAL; 710262395Sbapt } 711262395Sbapt else if (*p == '.') { 712262395Sbapt if (got_dot) { 713262395Sbapt /* Double dots, not a number */ 714262395Sbapt *pos = start; 715262395Sbapt return EINVAL; 716262395Sbapt } 717262395Sbapt else { 718262395Sbapt got_dot = true; 719262395Sbapt need_double = true; 720262395Sbapt p ++; 721262395Sbapt } 722262395Sbapt } 723262395Sbapt else if (*p == 'e' || *p == 'E') { 724262395Sbapt if (got_exp) { 725262395Sbapt /* Double exp, not a number */ 726262395Sbapt *pos = start; 727262395Sbapt return EINVAL; 728262395Sbapt } 729262395Sbapt else { 730262395Sbapt got_exp = true; 731262395Sbapt need_double = true; 732262395Sbapt p ++; 733262395Sbapt if (p >= end) { 734262395Sbapt *pos = start; 735262395Sbapt return EINVAL; 736262395Sbapt } 737262395Sbapt if (!isdigit (*p) && *p != '+' && *p != '-') { 738262395Sbapt /* Wrong exponent sign */ 739262395Sbapt *pos = start; 740262395Sbapt return EINVAL; 741262395Sbapt } 742262395Sbapt else { 743262395Sbapt p ++; 744262395Sbapt } 745262395Sbapt } 746262395Sbapt } 747262395Sbapt else { 748262395Sbapt /* Got the end of the number, need to check */ 749262395Sbapt break; 750262395Sbapt } 751262395Sbapt } 752262395Sbapt else { 753262395Sbapt break; 754262395Sbapt } 755262395Sbapt } 756262395Sbapt 757262395Sbapt if (!valid_start) { 758262395Sbapt *pos = start; 759262395Sbapt return EINVAL; 760262395Sbapt } 761262395Sbapt 762262395Sbapt errno = 0; 763262395Sbapt if (need_double) { 764262395Sbapt dv = strtod (c, &endptr); 765262395Sbapt } 766262395Sbapt else { 767262395Sbapt if (is_hex) { 768262395Sbapt lv = strtoimax (c, &endptr, 16); 769262395Sbapt } 770262395Sbapt else { 771262395Sbapt lv = strtoimax (c, &endptr, 10); 772262395Sbapt } 773262395Sbapt } 774262395Sbapt if (errno == ERANGE) { 775262395Sbapt *pos = start; 776262395Sbapt return ERANGE; 777262395Sbapt } 778262395Sbapt 779262395Sbapt /* Now check endptr */ 780275223Sbapt if (endptr == NULL || ucl_lex_is_atom_end (*endptr) || *endptr == '\0') { 781262395Sbapt p = endptr; 782262395Sbapt goto set_obj; 783262395Sbapt } 784262395Sbapt 785262395Sbapt if (endptr < end && endptr != start) { 786262395Sbapt p = endptr; 787262395Sbapt switch (*p) { 788262395Sbapt case 'm': 789262395Sbapt case 'M': 790262395Sbapt case 'g': 791262395Sbapt case 'G': 792262395Sbapt case 'k': 793262395Sbapt case 'K': 794262395Sbapt if (end - p >= 2) { 795262395Sbapt if (p[1] == 's' || p[1] == 'S') { 796262395Sbapt /* Milliseconds */ 797262395Sbapt if (!need_double) { 798262395Sbapt need_double = true; 799262395Sbapt dv = lv; 800262395Sbapt } 801263648Sbapt is_time = true; 802262395Sbapt if (p[0] == 'm' || p[0] == 'M') { 803262395Sbapt dv /= 1000.; 804262395Sbapt } 805262395Sbapt else { 806262395Sbapt dv *= ucl_lex_num_multiplier (*p, false); 807262395Sbapt } 808262395Sbapt p += 2; 809262395Sbapt goto set_obj; 810262395Sbapt } 811262395Sbapt else if (number_bytes || (p[1] == 'b' || p[1] == 'B')) { 812262395Sbapt /* Bytes */ 813262395Sbapt if (need_double) { 814262395Sbapt need_double = false; 815262395Sbapt lv = dv; 816262395Sbapt } 817262395Sbapt lv *= ucl_lex_num_multiplier (*p, true); 818262395Sbapt p += 2; 819262395Sbapt goto set_obj; 820262395Sbapt } 821262395Sbapt else if (ucl_lex_is_atom_end (p[1])) { 822262395Sbapt if (need_double) { 823262395Sbapt dv *= ucl_lex_num_multiplier (*p, false); 824262395Sbapt } 825262395Sbapt else { 826262395Sbapt lv *= ucl_lex_num_multiplier (*p, number_bytes); 827262395Sbapt } 828262395Sbapt p ++; 829262395Sbapt goto set_obj; 830262395Sbapt } 831263648Sbapt else if (allow_time && end - p >= 3) { 832262395Sbapt if (tolower (p[0]) == 'm' && 833262395Sbapt tolower (p[1]) == 'i' && 834262395Sbapt tolower (p[2]) == 'n') { 835262395Sbapt /* Minutes */ 836262395Sbapt if (!need_double) { 837262395Sbapt need_double = true; 838262395Sbapt dv = lv; 839262395Sbapt } 840263648Sbapt is_time = true; 841262395Sbapt dv *= 60.; 842262395Sbapt p += 3; 843262395Sbapt goto set_obj; 844262395Sbapt } 845262395Sbapt } 846262395Sbapt } 847262395Sbapt else { 848262395Sbapt if (need_double) { 849262395Sbapt dv *= ucl_lex_num_multiplier (*p, false); 850262395Sbapt } 851262395Sbapt else { 852262395Sbapt lv *= ucl_lex_num_multiplier (*p, number_bytes); 853262395Sbapt } 854262395Sbapt p ++; 855262395Sbapt goto set_obj; 856262395Sbapt } 857262395Sbapt break; 858262395Sbapt case 'S': 859262395Sbapt case 's': 860263648Sbapt if (allow_time && 861263648Sbapt (p == end - 1 || ucl_lex_is_atom_end (p[1]))) { 862262395Sbapt if (!need_double) { 863262395Sbapt need_double = true; 864262395Sbapt dv = lv; 865262395Sbapt } 866262395Sbapt p ++; 867263648Sbapt is_time = true; 868262395Sbapt goto set_obj; 869262395Sbapt } 870262395Sbapt break; 871262395Sbapt case 'h': 872262395Sbapt case 'H': 873262395Sbapt case 'd': 874262395Sbapt case 'D': 875262395Sbapt case 'w': 876262395Sbapt case 'W': 877262395Sbapt case 'Y': 878262395Sbapt case 'y': 879263648Sbapt if (allow_time && 880263648Sbapt (p == end - 1 || ucl_lex_is_atom_end (p[1]))) { 881262395Sbapt if (!need_double) { 882262395Sbapt need_double = true; 883262395Sbapt dv = lv; 884262395Sbapt } 885263648Sbapt is_time = true; 886262395Sbapt dv *= ucl_lex_time_multiplier (*p); 887262395Sbapt p ++; 888262395Sbapt goto set_obj; 889262395Sbapt } 890262395Sbapt break; 891275223Sbapt case '\t': 892275223Sbapt case ' ': 893275223Sbapt while (p < end && ucl_test_character(*p, UCL_CHARACTER_WHITESPACE)) { 894275223Sbapt p++; 895275223Sbapt } 896275223Sbapt if (ucl_lex_is_atom_end(*p)) 897275223Sbapt goto set_obj; 898275223Sbapt break; 899262395Sbapt } 900262395Sbapt } 901275223Sbapt else if (endptr == end) { 902275223Sbapt /* Just a number at the end of chunk */ 903275223Sbapt p = endptr; 904275223Sbapt goto set_obj; 905275223Sbapt } 906262395Sbapt 907262395Sbapt *pos = c; 908262395Sbapt return EINVAL; 909262395Sbapt 910290071Sbaptset_obj: 911290071Sbapt if (obj != NULL) { 912290071Sbapt if (allow_double && (need_double || is_time)) { 913290071Sbapt if (!is_time) { 914290071Sbapt obj->type = UCL_FLOAT; 915290071Sbapt } 916290071Sbapt else { 917290071Sbapt obj->type = UCL_TIME; 918290071Sbapt } 919290071Sbapt obj->value.dv = is_neg ? (-dv) : dv; 920262395Sbapt } 921262395Sbapt else { 922290071Sbapt obj->type = UCL_INT; 923290071Sbapt obj->value.iv = is_neg ? (-lv) : lv; 924262395Sbapt } 925262395Sbapt } 926262395Sbapt *pos = p; 927262395Sbapt return 0; 928262395Sbapt} 929262395Sbapt 930262395Sbapt/** 931262395Sbapt * Parse possible number 932262395Sbapt * @param parser 933262395Sbapt * @param chunk 934290071Sbapt * @param obj 935262395Sbapt * @return true if a number has been parsed 936262395Sbapt */ 937262395Sbaptstatic bool 938262395Sbaptucl_lex_number (struct ucl_parser *parser, 939262395Sbapt struct ucl_chunk *chunk, ucl_object_t *obj) 940262395Sbapt{ 941262395Sbapt const unsigned char *pos; 942262395Sbapt int ret; 943262395Sbapt 944263648Sbapt ret = ucl_maybe_parse_number (obj, chunk->pos, chunk->end, (const char **)&pos, 945263648Sbapt true, false, ((parser->flags & UCL_PARSER_NO_TIME) == 0)); 946262395Sbapt 947262395Sbapt if (ret == 0) { 948262395Sbapt chunk->remain -= pos - chunk->pos; 949262395Sbapt chunk->column += pos - chunk->pos; 950262395Sbapt chunk->pos = pos; 951262395Sbapt return true; 952262395Sbapt } 953262395Sbapt else if (ret == ERANGE) { 954290071Sbapt ucl_set_err (parser, UCL_ESYNTAX, "numeric value out of range", 955290071Sbapt &parser->err); 956262395Sbapt } 957262395Sbapt 958262395Sbapt return false; 959262395Sbapt} 960262395Sbapt 961262395Sbapt/** 962262395Sbapt * Parse quoted string with possible escapes 963262395Sbapt * @param parser 964262395Sbapt * @param chunk 965290071Sbapt * @param need_unescape 966290071Sbapt * @param ucl_escape 967290071Sbapt * @param var_expand 968262395Sbapt * @return true if a string has been parsed 969262395Sbapt */ 970262395Sbaptstatic bool 971262395Sbaptucl_lex_json_string (struct ucl_parser *parser, 972262395Sbapt struct ucl_chunk *chunk, bool *need_unescape, bool *ucl_escape, bool *var_expand) 973262395Sbapt{ 974262395Sbapt const unsigned char *p = chunk->pos; 975262395Sbapt unsigned char c; 976262395Sbapt int i; 977262395Sbapt 978262395Sbapt while (p < chunk->end) { 979262395Sbapt c = *p; 980262395Sbapt if (c < 0x1F) { 981262395Sbapt /* Unmasked control character */ 982262395Sbapt if (c == '\n') { 983275223Sbapt ucl_set_err (parser, UCL_ESYNTAX, "unexpected newline", 984275223Sbapt &parser->err); 985262395Sbapt } 986262395Sbapt else { 987275223Sbapt ucl_set_err (parser, UCL_ESYNTAX, "unexpected control character", 988275223Sbapt &parser->err); 989262395Sbapt } 990262395Sbapt return false; 991262395Sbapt } 992262395Sbapt else if (c == '\\') { 993262395Sbapt ucl_chunk_skipc (chunk, p); 994262395Sbapt c = *p; 995262395Sbapt if (p >= chunk->end) { 996275223Sbapt ucl_set_err (parser, UCL_ESYNTAX, "unfinished escape character", 997275223Sbapt &parser->err); 998262395Sbapt return false; 999262395Sbapt } 1000262395Sbapt else if (ucl_test_character (c, UCL_CHARACTER_ESCAPE)) { 1001262395Sbapt if (c == 'u') { 1002262395Sbapt ucl_chunk_skipc (chunk, p); 1003262395Sbapt for (i = 0; i < 4 && p < chunk->end; i ++) { 1004262395Sbapt if (!isxdigit (*p)) { 1005275223Sbapt ucl_set_err (parser, UCL_ESYNTAX, "invalid utf escape", 1006275223Sbapt &parser->err); 1007262395Sbapt return false; 1008262395Sbapt } 1009262395Sbapt ucl_chunk_skipc (chunk, p); 1010262395Sbapt } 1011262395Sbapt if (p >= chunk->end) { 1012275223Sbapt ucl_set_err (parser, UCL_ESYNTAX, "unfinished escape character", 1013275223Sbapt &parser->err); 1014262395Sbapt return false; 1015262395Sbapt } 1016262395Sbapt } 1017262395Sbapt else { 1018262395Sbapt ucl_chunk_skipc (chunk, p); 1019262395Sbapt } 1020262395Sbapt } 1021262395Sbapt *need_unescape = true; 1022262395Sbapt *ucl_escape = true; 1023262395Sbapt continue; 1024262395Sbapt } 1025262395Sbapt else if (c == '"') { 1026262395Sbapt ucl_chunk_skipc (chunk, p); 1027262395Sbapt return true; 1028262395Sbapt } 1029262395Sbapt else if (ucl_test_character (c, UCL_CHARACTER_UCL_UNSAFE)) { 1030262395Sbapt *ucl_escape = true; 1031262395Sbapt } 1032262395Sbapt else if (c == '$') { 1033262395Sbapt *var_expand = true; 1034262395Sbapt } 1035262395Sbapt ucl_chunk_skipc (chunk, p); 1036262395Sbapt } 1037262395Sbapt 1038275223Sbapt ucl_set_err (parser, UCL_ESYNTAX, "no quote at the end of json string", 1039275223Sbapt &parser->err); 1040262395Sbapt return false; 1041262395Sbapt} 1042262395Sbapt 1043275223Sbaptstatic void 1044275223Sbaptucl_parser_append_elt (struct ucl_parser *parser, ucl_hash_t *cont, 1045275223Sbapt ucl_object_t *top, 1046275223Sbapt ucl_object_t *elt) 1047275223Sbapt{ 1048275223Sbapt ucl_object_t *nobj; 1049275223Sbapt 1050275223Sbapt if ((parser->flags & UCL_PARSER_NO_IMPLICIT_ARRAYS) == 0) { 1051275223Sbapt /* Implicit array */ 1052275223Sbapt top->flags |= UCL_OBJECT_MULTIVALUE; 1053275223Sbapt DL_APPEND (top, elt); 1054290071Sbapt parser->stack->obj->len ++; 1055275223Sbapt } 1056275223Sbapt else { 1057275223Sbapt if ((top->flags & UCL_OBJECT_MULTIVALUE) != 0) { 1058275223Sbapt /* Just add to the explicit array */ 1059279549Sbapt ucl_array_append (top, elt); 1060275223Sbapt } 1061275223Sbapt else { 1062275223Sbapt /* Convert to an array */ 1063275223Sbapt nobj = ucl_object_typed_new (UCL_ARRAY); 1064275223Sbapt nobj->key = top->key; 1065275223Sbapt nobj->keylen = top->keylen; 1066275223Sbapt nobj->flags |= UCL_OBJECT_MULTIVALUE; 1067279549Sbapt ucl_array_append (nobj, top); 1068279549Sbapt ucl_array_append (nobj, elt); 1069290071Sbapt ucl_hash_replace (cont, top, nobj); 1070275223Sbapt } 1071275223Sbapt } 1072275223Sbapt} 1073275223Sbapt 1074290071Sbaptbool 1075290071Sbaptucl_parser_process_object_element (struct ucl_parser *parser, ucl_object_t *nobj) 1076290071Sbapt{ 1077290071Sbapt ucl_hash_t *container; 1078290071Sbapt ucl_object_t *tobj; 1079298166Sbapt char errmsg[256]; 1080290071Sbapt 1081290071Sbapt container = parser->stack->obj->value.ov; 1082290071Sbapt 1083290071Sbapt tobj = __DECONST (ucl_object_t *, ucl_hash_search_obj (container, nobj)); 1084290071Sbapt if (tobj == NULL) { 1085290071Sbapt container = ucl_hash_insert_object (container, nobj, 1086290071Sbapt parser->flags & UCL_PARSER_KEY_LOWERCASE); 1087290071Sbapt nobj->prev = nobj; 1088290071Sbapt nobj->next = NULL; 1089290071Sbapt parser->stack->obj->len ++; 1090290071Sbapt } 1091290071Sbapt else { 1092290071Sbapt unsigned priold = ucl_object_get_priority (tobj), 1093290071Sbapt prinew = ucl_object_get_priority (nobj); 1094290071Sbapt switch (parser->chunks->strategy) { 1095290071Sbapt 1096290071Sbapt case UCL_DUPLICATE_APPEND: 1097290071Sbapt /* 1098290071Sbapt * The logic here is the following: 1099290071Sbapt * 1100290071Sbapt * - if we have two objects with the same priority, then we form an 1101290071Sbapt * implicit or explicit array 1102290071Sbapt * - if a new object has bigger priority, then we overwrite an old one 1103290071Sbapt * - if a new object has lower priority, then we ignore it 1104290071Sbapt */ 1105290071Sbapt 1106290071Sbapt 1107290071Sbapt /* Special case for inherited objects */ 1108290071Sbapt if (tobj->flags & UCL_OBJECT_INHERITED) { 1109290071Sbapt prinew = priold + 1; 1110290071Sbapt } 1111290071Sbapt 1112290071Sbapt if (priold == prinew) { 1113290071Sbapt ucl_parser_append_elt (parser, container, tobj, nobj); 1114290071Sbapt } 1115290071Sbapt else if (priold > prinew) { 1116290071Sbapt /* 1117290071Sbapt * We add this new object to a list of trash objects just to ensure 1118290071Sbapt * that it won't come to any real object 1119290071Sbapt * XXX: rather inefficient approach 1120290071Sbapt */ 1121290071Sbapt DL_APPEND (parser->trash_objs, nobj); 1122290071Sbapt } 1123290071Sbapt else { 1124290071Sbapt ucl_hash_replace (container, tobj, nobj); 1125290071Sbapt ucl_object_unref (tobj); 1126290071Sbapt } 1127290071Sbapt 1128290071Sbapt break; 1129290071Sbapt 1130290071Sbapt case UCL_DUPLICATE_REWRITE: 1131290071Sbapt /* We just rewrite old values regardless of priority */ 1132290071Sbapt ucl_hash_replace (container, tobj, nobj); 1133290071Sbapt ucl_object_unref (tobj); 1134290071Sbapt 1135290071Sbapt break; 1136290071Sbapt 1137290071Sbapt case UCL_DUPLICATE_ERROR: 1138298166Sbapt snprintf(errmsg, sizeof(errmsg), 1139298166Sbapt "duplicate element for key '%s' found", 1140298166Sbapt nobj->key); 1141298166Sbapt ucl_set_err (parser, UCL_EMERGE, errmsg, &parser->err); 1142290071Sbapt return false; 1143290071Sbapt 1144290071Sbapt case UCL_DUPLICATE_MERGE: 1145290071Sbapt /* 1146290071Sbapt * Here we do have some old object so we just push it on top of objects stack 1147298166Sbapt * Check priority and then perform the merge on the remaining objects 1148290071Sbapt */ 1149290071Sbapt if (tobj->type == UCL_OBJECT || tobj->type == UCL_ARRAY) { 1150290071Sbapt ucl_object_unref (nobj); 1151290071Sbapt nobj = tobj; 1152290071Sbapt } 1153298166Sbapt else if (priold == prinew) { 1154290071Sbapt ucl_parser_append_elt (parser, container, tobj, nobj); 1155290071Sbapt } 1156298166Sbapt else if (priold > prinew) { 1157298166Sbapt /* 1158298166Sbapt * We add this new object to a list of trash objects just to ensure 1159298166Sbapt * that it won't come to any real object 1160298166Sbapt * XXX: rather inefficient approach 1161298166Sbapt */ 1162298166Sbapt DL_APPEND (parser->trash_objs, nobj); 1163298166Sbapt } 1164298166Sbapt else { 1165298166Sbapt ucl_hash_replace (container, tobj, nobj); 1166298166Sbapt ucl_object_unref (tobj); 1167298166Sbapt } 1168290071Sbapt break; 1169290071Sbapt } 1170290071Sbapt } 1171290071Sbapt 1172290071Sbapt parser->stack->obj->value.ov = container; 1173290071Sbapt parser->cur_obj = nobj; 1174298166Sbapt ucl_attach_comment (parser, nobj, false); 1175290071Sbapt 1176290071Sbapt return true; 1177290071Sbapt} 1178290071Sbapt 1179262395Sbapt/** 1180262395Sbapt * Parse a key in an object 1181262395Sbapt * @param parser 1182262395Sbapt * @param chunk 1183290071Sbapt * @param next_key 1184290071Sbapt * @param end_of_object 1185262395Sbapt * @return true if a key has been parsed 1186262395Sbapt */ 1187262395Sbaptstatic bool 1188290071Sbaptucl_parse_key (struct ucl_parser *parser, struct ucl_chunk *chunk, 1189290071Sbapt bool *next_key, bool *end_of_object) 1190262395Sbapt{ 1191262395Sbapt const unsigned char *p, *c = NULL, *end, *t; 1192262395Sbapt const char *key = NULL; 1193262395Sbapt bool got_quote = false, got_eq = false, got_semicolon = false, 1194262395Sbapt need_unescape = false, ucl_escape = false, var_expand = false, 1195262395Sbapt got_content = false, got_sep = false; 1196290071Sbapt ucl_object_t *nobj; 1197262395Sbapt ssize_t keylen; 1198262395Sbapt 1199262395Sbapt p = chunk->pos; 1200262395Sbapt 1201262395Sbapt if (*p == '.') { 1202262395Sbapt /* It is macro actually */ 1203298166Sbapt if (!(parser->flags & UCL_PARSER_DISABLE_MACRO)) { 1204298166Sbapt ucl_chunk_skipc (chunk, p); 1205298166Sbapt } 1206298166Sbapt 1207262395Sbapt parser->prev_state = parser->state; 1208262395Sbapt parser->state = UCL_STATE_MACRO_NAME; 1209279549Sbapt *end_of_object = false; 1210262395Sbapt return true; 1211262395Sbapt } 1212262395Sbapt while (p < chunk->end) { 1213262395Sbapt /* 1214262395Sbapt * A key must start with alpha, number, '/' or '_' and end with space character 1215262395Sbapt */ 1216262395Sbapt if (c == NULL) { 1217262395Sbapt if (chunk->remain >= 2 && ucl_lex_is_comment (p[0], p[1])) { 1218262395Sbapt if (!ucl_skip_comments (parser)) { 1219262395Sbapt return false; 1220262395Sbapt } 1221262395Sbapt p = chunk->pos; 1222262395Sbapt } 1223262395Sbapt else if (ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE)) { 1224262395Sbapt ucl_chunk_skipc (chunk, p); 1225262395Sbapt } 1226262395Sbapt else if (ucl_test_character (*p, UCL_CHARACTER_KEY_START)) { 1227262395Sbapt /* The first symbol */ 1228262395Sbapt c = p; 1229262395Sbapt ucl_chunk_skipc (chunk, p); 1230262395Sbapt got_content = true; 1231262395Sbapt } 1232262395Sbapt else if (*p == '"') { 1233262395Sbapt /* JSON style key */ 1234262395Sbapt c = p + 1; 1235262395Sbapt got_quote = true; 1236262395Sbapt got_content = true; 1237262395Sbapt ucl_chunk_skipc (chunk, p); 1238262395Sbapt } 1239262395Sbapt else if (*p == '}') { 1240262395Sbapt /* We have actually end of an object */ 1241262395Sbapt *end_of_object = true; 1242262395Sbapt return true; 1243262395Sbapt } 1244262395Sbapt else if (*p == '.') { 1245262395Sbapt ucl_chunk_skipc (chunk, p); 1246262395Sbapt parser->prev_state = parser->state; 1247262395Sbapt parser->state = UCL_STATE_MACRO_NAME; 1248262395Sbapt return true; 1249262395Sbapt } 1250262395Sbapt else { 1251262395Sbapt /* Invalid identifier */ 1252275223Sbapt ucl_set_err (parser, UCL_ESYNTAX, "key must begin with a letter", 1253275223Sbapt &parser->err); 1254262395Sbapt return false; 1255262395Sbapt } 1256262395Sbapt } 1257262395Sbapt else { 1258262395Sbapt /* Parse the body of a key */ 1259262395Sbapt if (!got_quote) { 1260262395Sbapt if (ucl_test_character (*p, UCL_CHARACTER_KEY)) { 1261262395Sbapt got_content = true; 1262262395Sbapt ucl_chunk_skipc (chunk, p); 1263262395Sbapt } 1264262395Sbapt else if (ucl_test_character (*p, UCL_CHARACTER_KEY_SEP)) { 1265262395Sbapt end = p; 1266262395Sbapt break; 1267262395Sbapt } 1268262395Sbapt else { 1269275223Sbapt ucl_set_err (parser, UCL_ESYNTAX, "invalid character in a key", 1270275223Sbapt &parser->err); 1271262395Sbapt return false; 1272262395Sbapt } 1273262395Sbapt } 1274262395Sbapt else { 1275262395Sbapt /* We need to parse json like quoted string */ 1276262395Sbapt if (!ucl_lex_json_string (parser, chunk, &need_unescape, &ucl_escape, &var_expand)) { 1277262395Sbapt return false; 1278262395Sbapt } 1279262395Sbapt /* Always escape keys obtained via json */ 1280262395Sbapt end = chunk->pos - 1; 1281262395Sbapt p = chunk->pos; 1282262395Sbapt break; 1283262395Sbapt } 1284262395Sbapt } 1285262395Sbapt } 1286262395Sbapt 1287262395Sbapt if (p >= chunk->end && got_content) { 1288275223Sbapt ucl_set_err (parser, UCL_ESYNTAX, "unfinished key", &parser->err); 1289262395Sbapt return false; 1290262395Sbapt } 1291262395Sbapt else if (!got_content) { 1292262395Sbapt return true; 1293262395Sbapt } 1294262395Sbapt *end_of_object = false; 1295262395Sbapt /* We are now at the end of the key, need to parse the rest */ 1296262395Sbapt while (p < chunk->end) { 1297262395Sbapt if (ucl_test_character (*p, UCL_CHARACTER_WHITESPACE)) { 1298262395Sbapt ucl_chunk_skipc (chunk, p); 1299262395Sbapt } 1300262395Sbapt else if (*p == '=') { 1301262395Sbapt if (!got_eq && !got_semicolon) { 1302262395Sbapt ucl_chunk_skipc (chunk, p); 1303262395Sbapt got_eq = true; 1304262395Sbapt } 1305262395Sbapt else { 1306275223Sbapt ucl_set_err (parser, UCL_ESYNTAX, "unexpected '=' character", 1307275223Sbapt &parser->err); 1308262395Sbapt return false; 1309262395Sbapt } 1310262395Sbapt } 1311262395Sbapt else if (*p == ':') { 1312262395Sbapt if (!got_eq && !got_semicolon) { 1313262395Sbapt ucl_chunk_skipc (chunk, p); 1314262395Sbapt got_semicolon = true; 1315262395Sbapt } 1316262395Sbapt else { 1317275223Sbapt ucl_set_err (parser, UCL_ESYNTAX, "unexpected ':' character", 1318275223Sbapt &parser->err); 1319262395Sbapt return false; 1320262395Sbapt } 1321262395Sbapt } 1322262395Sbapt else if (chunk->remain >= 2 && ucl_lex_is_comment (p[0], p[1])) { 1323262395Sbapt /* Check for comment */ 1324262395Sbapt if (!ucl_skip_comments (parser)) { 1325262395Sbapt return false; 1326262395Sbapt } 1327262395Sbapt p = chunk->pos; 1328262395Sbapt } 1329262395Sbapt else { 1330262395Sbapt /* Start value */ 1331262395Sbapt break; 1332262395Sbapt } 1333262395Sbapt } 1334262395Sbapt 1335262395Sbapt if (p >= chunk->end && got_content) { 1336275223Sbapt ucl_set_err (parser, UCL_ESYNTAX, "unfinished key", &parser->err); 1337262395Sbapt return false; 1338262395Sbapt } 1339262395Sbapt 1340262395Sbapt got_sep = got_semicolon || got_eq; 1341262395Sbapt 1342262395Sbapt if (!got_sep) { 1343262395Sbapt /* 1344262395Sbapt * Maybe we have more keys nested, so search for termination character. 1345262395Sbapt * Possible choices: 1346262395Sbapt * 1) key1 key2 ... keyN [:=] value <- we treat that as error 1347262395Sbapt * 2) key1 ... keyN {} or [] <- we treat that as nested objects 1348262395Sbapt * 3) key1 value[;,\n] <- we treat that as linear object 1349262395Sbapt */ 1350262395Sbapt t = p; 1351262395Sbapt *next_key = false; 1352262395Sbapt while (ucl_test_character (*t, UCL_CHARACTER_WHITESPACE)) { 1353262395Sbapt t ++; 1354262395Sbapt } 1355262395Sbapt /* Check first non-space character after a key */ 1356262395Sbapt if (*t != '{' && *t != '[') { 1357262395Sbapt while (t < chunk->end) { 1358262395Sbapt if (*t == ',' || *t == ';' || *t == '\n' || *t == '\r') { 1359262395Sbapt break; 1360262395Sbapt } 1361262395Sbapt else if (*t == '{' || *t == '[') { 1362262395Sbapt *next_key = true; 1363262395Sbapt break; 1364262395Sbapt } 1365262395Sbapt t ++; 1366262395Sbapt } 1367262395Sbapt } 1368262395Sbapt } 1369262395Sbapt 1370262395Sbapt /* Create a new object */ 1371275223Sbapt nobj = ucl_object_new_full (UCL_NULL, parser->chunks->priority); 1372262395Sbapt keylen = ucl_copy_or_store_ptr (parser, c, &nobj->trash_stack[UCL_TRASH_KEY], 1373262395Sbapt &key, end - c, need_unescape, parser->flags & UCL_PARSER_KEY_LOWERCASE, false); 1374262395Sbapt if (keylen == -1) { 1375264789Sbapt ucl_object_unref (nobj); 1376262395Sbapt return false; 1377262395Sbapt } 1378262395Sbapt else if (keylen == 0) { 1379275223Sbapt ucl_set_err (parser, UCL_ESYNTAX, "empty keys are not allowed", &parser->err); 1380264789Sbapt ucl_object_unref (nobj); 1381262395Sbapt return false; 1382262395Sbapt } 1383262395Sbapt 1384262395Sbapt nobj->key = key; 1385262395Sbapt nobj->keylen = keylen; 1386290071Sbapt 1387290071Sbapt if (!ucl_parser_process_object_element (parser, nobj)) { 1388290071Sbapt return false; 1389262395Sbapt } 1390262395Sbapt 1391262395Sbapt if (ucl_escape) { 1392262395Sbapt nobj->flags |= UCL_OBJECT_NEED_KEY_ESCAPE; 1393262395Sbapt } 1394262395Sbapt 1395262395Sbapt 1396262395Sbapt return true; 1397262395Sbapt} 1398262395Sbapt 1399262395Sbapt/** 1400262395Sbapt * Parse a cl string 1401262395Sbapt * @param parser 1402262395Sbapt * @param chunk 1403290071Sbapt * @param var_expand 1404290071Sbapt * @param need_unescape 1405262395Sbapt * @return true if a key has been parsed 1406262395Sbapt */ 1407262395Sbaptstatic bool 1408262395Sbaptucl_parse_string_value (struct ucl_parser *parser, 1409262395Sbapt struct ucl_chunk *chunk, bool *var_expand, bool *need_unescape) 1410262395Sbapt{ 1411262395Sbapt const unsigned char *p; 1412262395Sbapt enum { 1413262395Sbapt UCL_BRACE_ROUND = 0, 1414262395Sbapt UCL_BRACE_SQUARE, 1415262395Sbapt UCL_BRACE_FIGURE 1416262395Sbapt }; 1417262395Sbapt int braces[3][2] = {{0, 0}, {0, 0}, {0, 0}}; 1418262395Sbapt 1419262395Sbapt p = chunk->pos; 1420262395Sbapt 1421262395Sbapt while (p < chunk->end) { 1422262395Sbapt 1423262395Sbapt /* Skip pairs of figure braces */ 1424262395Sbapt if (*p == '{') { 1425262395Sbapt braces[UCL_BRACE_FIGURE][0] ++; 1426262395Sbapt } 1427262395Sbapt else if (*p == '}') { 1428262395Sbapt braces[UCL_BRACE_FIGURE][1] ++; 1429262395Sbapt if (braces[UCL_BRACE_FIGURE][1] <= braces[UCL_BRACE_FIGURE][0]) { 1430262395Sbapt /* This is not a termination symbol, continue */ 1431262395Sbapt ucl_chunk_skipc (chunk, p); 1432262395Sbapt continue; 1433262395Sbapt } 1434262395Sbapt } 1435262395Sbapt /* Skip pairs of square braces */ 1436262395Sbapt else if (*p == '[') { 1437262395Sbapt braces[UCL_BRACE_SQUARE][0] ++; 1438262395Sbapt } 1439262395Sbapt else if (*p == ']') { 1440262395Sbapt braces[UCL_BRACE_SQUARE][1] ++; 1441262395Sbapt if (braces[UCL_BRACE_SQUARE][1] <= braces[UCL_BRACE_SQUARE][0]) { 1442262395Sbapt /* This is not a termination symbol, continue */ 1443262395Sbapt ucl_chunk_skipc (chunk, p); 1444262395Sbapt continue; 1445262395Sbapt } 1446262395Sbapt } 1447262395Sbapt else if (*p == '$') { 1448262395Sbapt *var_expand = true; 1449262395Sbapt } 1450262395Sbapt else if (*p == '\\') { 1451262395Sbapt *need_unescape = true; 1452262395Sbapt ucl_chunk_skipc (chunk, p); 1453262395Sbapt if (p < chunk->end) { 1454262395Sbapt ucl_chunk_skipc (chunk, p); 1455262395Sbapt } 1456262395Sbapt continue; 1457262395Sbapt } 1458262395Sbapt 1459262395Sbapt if (ucl_lex_is_atom_end (*p) || (chunk->remain >= 2 && ucl_lex_is_comment (p[0], p[1]))) { 1460262395Sbapt break; 1461262395Sbapt } 1462262395Sbapt ucl_chunk_skipc (chunk, p); 1463262395Sbapt } 1464262395Sbapt 1465262395Sbapt return true; 1466262395Sbapt} 1467262395Sbapt 1468262395Sbapt/** 1469262395Sbapt * Parse multiline string ending with \n{term}\n 1470262395Sbapt * @param parser 1471262395Sbapt * @param chunk 1472262395Sbapt * @param term 1473262395Sbapt * @param term_len 1474290071Sbapt * @param beg 1475290071Sbapt * @param var_expand 1476262395Sbapt * @return size of multiline string or 0 in case of error 1477262395Sbapt */ 1478262395Sbaptstatic int 1479262395Sbaptucl_parse_multiline_string (struct ucl_parser *parser, 1480262395Sbapt struct ucl_chunk *chunk, const unsigned char *term, 1481262395Sbapt int term_len, unsigned char const **beg, 1482262395Sbapt bool *var_expand) 1483262395Sbapt{ 1484275223Sbapt const unsigned char *p, *c, *tend; 1485262395Sbapt bool newline = false; 1486262395Sbapt int len = 0; 1487262395Sbapt 1488262395Sbapt p = chunk->pos; 1489262395Sbapt 1490262395Sbapt c = p; 1491262395Sbapt 1492262395Sbapt while (p < chunk->end) { 1493262395Sbapt if (newline) { 1494262395Sbapt if (chunk->end - p < term_len) { 1495262395Sbapt return 0; 1496262395Sbapt } 1497275223Sbapt else if (memcmp (p, term, term_len) == 0) { 1498275223Sbapt tend = p + term_len; 1499275223Sbapt if (*tend != '\n' && *tend != ';' && *tend != ',') { 1500275223Sbapt /* Incomplete terminator */ 1501275223Sbapt ucl_chunk_skipc (chunk, p); 1502275223Sbapt continue; 1503275223Sbapt } 1504262395Sbapt len = p - c; 1505262395Sbapt chunk->remain -= term_len; 1506262395Sbapt chunk->pos = p + term_len; 1507262395Sbapt chunk->column = term_len; 1508262395Sbapt *beg = c; 1509262395Sbapt break; 1510262395Sbapt } 1511262395Sbapt } 1512262395Sbapt if (*p == '\n') { 1513262395Sbapt newline = true; 1514262395Sbapt } 1515262395Sbapt else { 1516262395Sbapt if (*p == '$') { 1517262395Sbapt *var_expand = true; 1518262395Sbapt } 1519262395Sbapt newline = false; 1520262395Sbapt } 1521262395Sbapt ucl_chunk_skipc (chunk, p); 1522262395Sbapt } 1523262395Sbapt 1524262395Sbapt return len; 1525262395Sbapt} 1526262395Sbapt 1527290071Sbaptstatic inline ucl_object_t* 1528290071Sbaptucl_parser_get_container (struct ucl_parser *parser) 1529262975Sbapt{ 1530262975Sbapt ucl_object_t *t, *obj = NULL; 1531262975Sbapt 1532279549Sbapt if (parser == NULL || parser->stack == NULL || parser->stack->obj == NULL) { 1533279549Sbapt return NULL; 1534279549Sbapt } 1535279549Sbapt 1536262975Sbapt if (parser->stack->obj->type == UCL_ARRAY) { 1537262975Sbapt /* Object must be allocated */ 1538275223Sbapt obj = ucl_object_new_full (UCL_NULL, parser->chunks->priority); 1539279549Sbapt t = parser->stack->obj; 1540290071Sbapt 1541290071Sbapt if (!ucl_array_append (t, obj)) { 1542290071Sbapt ucl_object_unref (obj); 1543290071Sbapt return NULL; 1544290071Sbapt } 1545290071Sbapt 1546262975Sbapt parser->cur_obj = obj; 1547298166Sbapt ucl_attach_comment (parser, obj, false); 1548262975Sbapt } 1549262975Sbapt else { 1550262975Sbapt /* Object has been already allocated */ 1551262975Sbapt obj = parser->cur_obj; 1552262975Sbapt } 1553262975Sbapt 1554262975Sbapt return obj; 1555262975Sbapt} 1556262975Sbapt 1557262395Sbapt/** 1558262395Sbapt * Handle value data 1559262395Sbapt * @param parser 1560262395Sbapt * @param chunk 1561262395Sbapt * @return 1562262395Sbapt */ 1563262395Sbaptstatic bool 1564262395Sbaptucl_parse_value (struct ucl_parser *parser, struct ucl_chunk *chunk) 1565262395Sbapt{ 1566262395Sbapt const unsigned char *p, *c; 1567262975Sbapt ucl_object_t *obj = NULL; 1568262395Sbapt unsigned int stripped_spaces; 1569262395Sbapt int str_len; 1570262395Sbapt bool need_unescape = false, ucl_escape = false, var_expand = false; 1571262395Sbapt 1572262395Sbapt p = chunk->pos; 1573262395Sbapt 1574262975Sbapt /* Skip any spaces and comments */ 1575262975Sbapt if (ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE) || 1576262975Sbapt (chunk->remain >= 2 && ucl_lex_is_comment (p[0], p[1]))) { 1577262975Sbapt while (p < chunk->end && ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE)) { 1578262975Sbapt ucl_chunk_skipc (chunk, p); 1579262975Sbapt } 1580262975Sbapt if (!ucl_skip_comments (parser)) { 1581262975Sbapt return false; 1582262975Sbapt } 1583262975Sbapt p = chunk->pos; 1584262975Sbapt } 1585262975Sbapt 1586262395Sbapt while (p < chunk->end) { 1587262395Sbapt c = p; 1588262395Sbapt switch (*p) { 1589262395Sbapt case '"': 1590262395Sbapt ucl_chunk_skipc (chunk, p); 1591290071Sbapt 1592290071Sbapt if (!ucl_lex_json_string (parser, chunk, &need_unescape, &ucl_escape, 1593290071Sbapt &var_expand)) { 1594262395Sbapt return false; 1595262395Sbapt } 1596290071Sbapt 1597290071Sbapt obj = ucl_parser_get_container (parser); 1598298166Sbapt if (!obj) { 1599298166Sbapt return false; 1600298166Sbapt } 1601298166Sbapt 1602262395Sbapt str_len = chunk->pos - c - 2; 1603262395Sbapt obj->type = UCL_STRING; 1604290071Sbapt if ((str_len = ucl_copy_or_store_ptr (parser, c + 1, 1605290071Sbapt &obj->trash_stack[UCL_TRASH_VALUE], 1606290071Sbapt &obj->value.sv, str_len, need_unescape, false, 1607290071Sbapt var_expand)) == -1) { 1608262395Sbapt return false; 1609262395Sbapt } 1610262395Sbapt obj->len = str_len; 1611290071Sbapt 1612262395Sbapt parser->state = UCL_STATE_AFTER_VALUE; 1613262395Sbapt p = chunk->pos; 1614290071Sbapt 1615262395Sbapt return true; 1616262395Sbapt break; 1617262395Sbapt case '{': 1618290071Sbapt obj = ucl_parser_get_container (parser); 1619262395Sbapt /* We have a new object */ 1620290071Sbapt obj = ucl_parser_add_container (obj, parser, false, parser->stack->level); 1621263648Sbapt if (obj == NULL) { 1622263648Sbapt return false; 1623263648Sbapt } 1624262395Sbapt 1625262395Sbapt ucl_chunk_skipc (chunk, p); 1626290071Sbapt 1627262395Sbapt return true; 1628262395Sbapt break; 1629262395Sbapt case '[': 1630290071Sbapt obj = ucl_parser_get_container (parser); 1631262395Sbapt /* We have a new array */ 1632290071Sbapt obj = ucl_parser_add_container (obj, parser, true, parser->stack->level); 1633263648Sbapt if (obj == NULL) { 1634263648Sbapt return false; 1635263648Sbapt } 1636262395Sbapt 1637262395Sbapt ucl_chunk_skipc (chunk, p); 1638290071Sbapt 1639262395Sbapt return true; 1640262395Sbapt break; 1641262975Sbapt case ']': 1642262975Sbapt /* We have the array ending */ 1643262975Sbapt if (parser->stack && parser->stack->obj->type == UCL_ARRAY) { 1644262975Sbapt parser->state = UCL_STATE_AFTER_VALUE; 1645262975Sbapt return true; 1646262975Sbapt } 1647262975Sbapt else { 1648262975Sbapt goto parse_string; 1649262975Sbapt } 1650262975Sbapt break; 1651262395Sbapt case '<': 1652290071Sbapt obj = ucl_parser_get_container (parser); 1653262395Sbapt /* We have something like multiline value, which must be <<[A-Z]+\n */ 1654262395Sbapt if (chunk->end - p > 3) { 1655262395Sbapt if (memcmp (p, "<<", 2) == 0) { 1656262395Sbapt p += 2; 1657262395Sbapt /* We allow only uppercase characters in multiline definitions */ 1658262395Sbapt while (p < chunk->end && *p >= 'A' && *p <= 'Z') { 1659262395Sbapt p ++; 1660262395Sbapt } 1661262395Sbapt if (*p =='\n') { 1662262395Sbapt /* Set chunk positions and start multiline parsing */ 1663262395Sbapt c += 2; 1664262395Sbapt chunk->remain -= p - c; 1665262395Sbapt chunk->pos = p + 1; 1666262395Sbapt chunk->column = 0; 1667262395Sbapt chunk->line ++; 1668262395Sbapt if ((str_len = ucl_parse_multiline_string (parser, chunk, c, 1669262395Sbapt p - c, &c, &var_expand)) == 0) { 1670275223Sbapt ucl_set_err (parser, UCL_ESYNTAX, 1671275223Sbapt "unterminated multiline value", &parser->err); 1672262395Sbapt return false; 1673262395Sbapt } 1674290071Sbapt 1675262395Sbapt obj->type = UCL_STRING; 1676290071Sbapt obj->flags |= UCL_OBJECT_MULTILINE; 1677290071Sbapt if ((str_len = ucl_copy_or_store_ptr (parser, c, 1678290071Sbapt &obj->trash_stack[UCL_TRASH_VALUE], 1679290071Sbapt &obj->value.sv, str_len - 1, false, 1680290071Sbapt false, var_expand)) == -1) { 1681262395Sbapt return false; 1682262395Sbapt } 1683262395Sbapt obj->len = str_len; 1684290071Sbapt 1685262395Sbapt parser->state = UCL_STATE_AFTER_VALUE; 1686290071Sbapt 1687262395Sbapt return true; 1688262395Sbapt } 1689262395Sbapt } 1690262395Sbapt } 1691262395Sbapt /* Fallback to ordinary strings */ 1692262395Sbapt default: 1693262975Sbaptparse_string: 1694262975Sbapt if (obj == NULL) { 1695290071Sbapt obj = ucl_parser_get_container (parser); 1696262395Sbapt } 1697290071Sbapt 1698262395Sbapt /* Parse atom */ 1699262395Sbapt if (ucl_test_character (*p, UCL_CHARACTER_VALUE_DIGIT_START)) { 1700262395Sbapt if (!ucl_lex_number (parser, chunk, obj)) { 1701262395Sbapt if (parser->state == UCL_STATE_ERROR) { 1702262395Sbapt return false; 1703262395Sbapt } 1704262395Sbapt } 1705262395Sbapt else { 1706262395Sbapt parser->state = UCL_STATE_AFTER_VALUE; 1707262395Sbapt return true; 1708262395Sbapt } 1709262395Sbapt /* Fallback to normal string */ 1710262395Sbapt } 1711262395Sbapt 1712290071Sbapt if (!ucl_parse_string_value (parser, chunk, &var_expand, 1713290071Sbapt &need_unescape)) { 1714262395Sbapt return false; 1715262395Sbapt } 1716262395Sbapt /* Cut trailing spaces */ 1717262395Sbapt stripped_spaces = 0; 1718262395Sbapt while (ucl_test_character (*(chunk->pos - 1 - stripped_spaces), 1719262395Sbapt UCL_CHARACTER_WHITESPACE)) { 1720262395Sbapt stripped_spaces ++; 1721262395Sbapt } 1722262395Sbapt str_len = chunk->pos - c - stripped_spaces; 1723262395Sbapt if (str_len <= 0) { 1724290071Sbapt ucl_set_err (parser, UCL_ESYNTAX, "string value must not be empty", 1725275223Sbapt &parser->err); 1726262395Sbapt return false; 1727262395Sbapt } 1728262395Sbapt else if (str_len == 4 && memcmp (c, "null", 4) == 0) { 1729262395Sbapt obj->len = 0; 1730262395Sbapt obj->type = UCL_NULL; 1731262395Sbapt } 1732262395Sbapt else if (!ucl_maybe_parse_boolean (obj, c, str_len)) { 1733262395Sbapt obj->type = UCL_STRING; 1734290071Sbapt if ((str_len = ucl_copy_or_store_ptr (parser, c, 1735290071Sbapt &obj->trash_stack[UCL_TRASH_VALUE], 1736262395Sbapt &obj->value.sv, str_len, need_unescape, 1737262395Sbapt false, var_expand)) == -1) { 1738262395Sbapt return false; 1739262395Sbapt } 1740262395Sbapt obj->len = str_len; 1741262395Sbapt } 1742262395Sbapt parser->state = UCL_STATE_AFTER_VALUE; 1743262395Sbapt p = chunk->pos; 1744262395Sbapt 1745262395Sbapt return true; 1746262395Sbapt break; 1747262395Sbapt } 1748262395Sbapt } 1749262395Sbapt 1750262395Sbapt return true; 1751262395Sbapt} 1752262395Sbapt 1753262395Sbapt/** 1754262395Sbapt * Handle after value data 1755262395Sbapt * @param parser 1756262395Sbapt * @param chunk 1757262395Sbapt * @return 1758262395Sbapt */ 1759262395Sbaptstatic bool 1760262395Sbaptucl_parse_after_value (struct ucl_parser *parser, struct ucl_chunk *chunk) 1761262395Sbapt{ 1762262395Sbapt const unsigned char *p; 1763262395Sbapt bool got_sep = false; 1764262395Sbapt struct ucl_stack *st; 1765262395Sbapt 1766262395Sbapt p = chunk->pos; 1767262395Sbapt 1768262395Sbapt while (p < chunk->end) { 1769262395Sbapt if (ucl_test_character (*p, UCL_CHARACTER_WHITESPACE)) { 1770262395Sbapt /* Skip whitespaces */ 1771262395Sbapt ucl_chunk_skipc (chunk, p); 1772262395Sbapt } 1773262395Sbapt else if (chunk->remain >= 2 && ucl_lex_is_comment (p[0], p[1])) { 1774262395Sbapt /* Skip comment */ 1775262395Sbapt if (!ucl_skip_comments (parser)) { 1776262395Sbapt return false; 1777262395Sbapt } 1778262395Sbapt /* Treat comment as a separator */ 1779262395Sbapt got_sep = true; 1780262395Sbapt p = chunk->pos; 1781262395Sbapt } 1782262395Sbapt else if (ucl_test_character (*p, UCL_CHARACTER_VALUE_END)) { 1783262395Sbapt if (*p == '}' || *p == ']') { 1784262395Sbapt if (parser->stack == NULL) { 1785275223Sbapt ucl_set_err (parser, UCL_ESYNTAX, 1786275223Sbapt "end of array or object detected without corresponding start", 1787275223Sbapt &parser->err); 1788262395Sbapt return false; 1789262395Sbapt } 1790262395Sbapt if ((*p == '}' && parser->stack->obj->type == UCL_OBJECT) || 1791262395Sbapt (*p == ']' && parser->stack->obj->type == UCL_ARRAY)) { 1792262395Sbapt 1793262395Sbapt /* Pop all nested objects from a stack */ 1794262395Sbapt st = parser->stack; 1795262395Sbapt parser->stack = st->next; 1796262395Sbapt UCL_FREE (sizeof (struct ucl_stack), st); 1797262395Sbapt 1798298166Sbapt if (parser->cur_obj) { 1799298166Sbapt ucl_attach_comment (parser, parser->cur_obj, true); 1800298166Sbapt } 1801298166Sbapt 1802262395Sbapt while (parser->stack != NULL) { 1803262395Sbapt st = parser->stack; 1804298166Sbapt 1805262395Sbapt if (st->next == NULL || st->next->level == st->level) { 1806262395Sbapt break; 1807262395Sbapt } 1808298166Sbapt 1809262395Sbapt parser->stack = st->next; 1810298166Sbapt parser->cur_obj = st->obj; 1811262395Sbapt UCL_FREE (sizeof (struct ucl_stack), st); 1812262395Sbapt } 1813262395Sbapt } 1814262395Sbapt else { 1815275223Sbapt ucl_set_err (parser, UCL_ESYNTAX, 1816275223Sbapt "unexpected terminating symbol detected", 1817275223Sbapt &parser->err); 1818262395Sbapt return false; 1819262395Sbapt } 1820262395Sbapt 1821262395Sbapt if (parser->stack == NULL) { 1822262395Sbapt /* Ignore everything after a top object */ 1823262395Sbapt return true; 1824262395Sbapt } 1825262395Sbapt else { 1826262395Sbapt ucl_chunk_skipc (chunk, p); 1827262395Sbapt } 1828262395Sbapt got_sep = true; 1829262395Sbapt } 1830262395Sbapt else { 1831262395Sbapt /* Got a separator */ 1832262395Sbapt got_sep = true; 1833262395Sbapt ucl_chunk_skipc (chunk, p); 1834262395Sbapt } 1835262395Sbapt } 1836262395Sbapt else { 1837262395Sbapt /* Anything else */ 1838262395Sbapt if (!got_sep) { 1839275223Sbapt ucl_set_err (parser, UCL_ESYNTAX, "delimiter is missing", 1840275223Sbapt &parser->err); 1841262395Sbapt return false; 1842262395Sbapt } 1843262395Sbapt return true; 1844262395Sbapt } 1845262395Sbapt } 1846262395Sbapt 1847262395Sbapt return true; 1848262395Sbapt} 1849262395Sbapt 1850298166Sbaptstatic bool 1851298166Sbaptucl_skip_macro_as_comment (struct ucl_parser *parser, 1852298166Sbapt struct ucl_chunk *chunk) 1853298166Sbapt{ 1854298166Sbapt const unsigned char *p, *c; 1855298166Sbapt enum { 1856298166Sbapt macro_skip_start = 0, 1857298166Sbapt macro_has_symbols, 1858298166Sbapt macro_has_obrace, 1859298166Sbapt macro_has_quote, 1860298166Sbapt macro_has_backslash, 1861298166Sbapt macro_has_sqbrace, 1862298166Sbapt macro_save 1863298166Sbapt } state = macro_skip_start, prev_state = macro_skip_start; 1864298166Sbapt 1865298166Sbapt p = chunk->pos; 1866298166Sbapt c = chunk->pos; 1867298166Sbapt 1868298166Sbapt while (p < chunk->end) { 1869298166Sbapt switch (state) { 1870298166Sbapt case macro_skip_start: 1871298166Sbapt if (!ucl_test_character (*p, UCL_CHARACTER_WHITESPACE)) { 1872298166Sbapt state = macro_has_symbols; 1873298166Sbapt } 1874298166Sbapt else if (ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE)) { 1875298166Sbapt state = macro_save; 1876298166Sbapt continue; 1877298166Sbapt } 1878298166Sbapt 1879298166Sbapt ucl_chunk_skipc (chunk, p); 1880298166Sbapt break; 1881298166Sbapt 1882298166Sbapt case macro_has_symbols: 1883298166Sbapt if (*p == '{') { 1884298166Sbapt state = macro_has_sqbrace; 1885298166Sbapt } 1886298166Sbapt else if (*p == '(') { 1887298166Sbapt state = macro_has_obrace; 1888298166Sbapt } 1889298166Sbapt else if (*p == '"') { 1890298166Sbapt state = macro_has_quote; 1891298166Sbapt } 1892298166Sbapt else if (*p == '\n') { 1893298166Sbapt state = macro_save; 1894298166Sbapt continue; 1895298166Sbapt } 1896298166Sbapt 1897298166Sbapt ucl_chunk_skipc (chunk, p); 1898298166Sbapt break; 1899298166Sbapt 1900298166Sbapt case macro_has_obrace: 1901298166Sbapt if (*p == '\\') { 1902298166Sbapt prev_state = state; 1903298166Sbapt state = macro_has_backslash; 1904298166Sbapt } 1905298166Sbapt else if (*p == ')') { 1906298166Sbapt state = macro_has_symbols; 1907298166Sbapt } 1908298166Sbapt 1909298166Sbapt ucl_chunk_skipc (chunk, p); 1910298166Sbapt break; 1911298166Sbapt 1912298166Sbapt case macro_has_sqbrace: 1913298166Sbapt if (*p == '\\') { 1914298166Sbapt prev_state = state; 1915298166Sbapt state = macro_has_backslash; 1916298166Sbapt } 1917298166Sbapt else if (*p == '}') { 1918298166Sbapt state = macro_save; 1919298166Sbapt } 1920298166Sbapt 1921298166Sbapt ucl_chunk_skipc (chunk, p); 1922298166Sbapt break; 1923298166Sbapt 1924298166Sbapt case macro_has_quote: 1925298166Sbapt if (*p == '\\') { 1926298166Sbapt prev_state = state; 1927298166Sbapt state = macro_has_backslash; 1928298166Sbapt } 1929298166Sbapt else if (*p == '"') { 1930298166Sbapt state = macro_save; 1931298166Sbapt } 1932298166Sbapt 1933298166Sbapt ucl_chunk_skipc (chunk, p); 1934298166Sbapt break; 1935298166Sbapt 1936298166Sbapt case macro_has_backslash: 1937298166Sbapt state = prev_state; 1938298166Sbapt ucl_chunk_skipc (chunk, p); 1939298166Sbapt break; 1940298166Sbapt 1941298166Sbapt case macro_save: 1942298166Sbapt if (parser->flags & UCL_PARSER_SAVE_COMMENTS) { 1943298166Sbapt ucl_save_comment (parser, c, p - c); 1944298166Sbapt } 1945298166Sbapt 1946298166Sbapt return true; 1947298166Sbapt } 1948298166Sbapt } 1949298166Sbapt 1950298166Sbapt return false; 1951298166Sbapt} 1952298166Sbapt 1953262395Sbapt/** 1954262395Sbapt * Handle macro data 1955262395Sbapt * @param parser 1956262395Sbapt * @param chunk 1957290071Sbapt * @param marco 1958290071Sbapt * @param macro_start 1959290071Sbapt * @param macro_len 1960262395Sbapt * @return 1961262395Sbapt */ 1962262395Sbaptstatic bool 1963262395Sbaptucl_parse_macro_value (struct ucl_parser *parser, 1964262395Sbapt struct ucl_chunk *chunk, struct ucl_macro *macro, 1965262395Sbapt unsigned char const **macro_start, size_t *macro_len) 1966262395Sbapt{ 1967262395Sbapt const unsigned char *p, *c; 1968262395Sbapt bool need_unescape = false, ucl_escape = false, var_expand = false; 1969262395Sbapt 1970262395Sbapt p = chunk->pos; 1971262395Sbapt 1972262395Sbapt switch (*p) { 1973262395Sbapt case '"': 1974262395Sbapt /* We have macro value encoded in quotes */ 1975262395Sbapt c = p; 1976262395Sbapt ucl_chunk_skipc (chunk, p); 1977262395Sbapt if (!ucl_lex_json_string (parser, chunk, &need_unescape, &ucl_escape, &var_expand)) { 1978262395Sbapt return false; 1979262395Sbapt } 1980262395Sbapt 1981262395Sbapt *macro_start = c + 1; 1982262395Sbapt *macro_len = chunk->pos - c - 2; 1983262395Sbapt p = chunk->pos; 1984262395Sbapt break; 1985262395Sbapt case '{': 1986262395Sbapt /* We got a multiline macro body */ 1987262395Sbapt ucl_chunk_skipc (chunk, p); 1988262395Sbapt /* Skip spaces at the beginning */ 1989262395Sbapt while (p < chunk->end) { 1990262395Sbapt if (ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE)) { 1991262395Sbapt ucl_chunk_skipc (chunk, p); 1992262395Sbapt } 1993262395Sbapt else { 1994262395Sbapt break; 1995262395Sbapt } 1996262395Sbapt } 1997262395Sbapt c = p; 1998262395Sbapt while (p < chunk->end) { 1999262395Sbapt if (*p == '}') { 2000262395Sbapt break; 2001262395Sbapt } 2002262395Sbapt ucl_chunk_skipc (chunk, p); 2003262395Sbapt } 2004262395Sbapt *macro_start = c; 2005262395Sbapt *macro_len = p - c; 2006262395Sbapt ucl_chunk_skipc (chunk, p); 2007262395Sbapt break; 2008262395Sbapt default: 2009262395Sbapt /* Macro is not enclosed in quotes or braces */ 2010262395Sbapt c = p; 2011262395Sbapt while (p < chunk->end) { 2012262395Sbapt if (ucl_lex_is_atom_end (*p)) { 2013262395Sbapt break; 2014262395Sbapt } 2015262395Sbapt ucl_chunk_skipc (chunk, p); 2016262395Sbapt } 2017262395Sbapt *macro_start = c; 2018262395Sbapt *macro_len = p - c; 2019262395Sbapt break; 2020262395Sbapt } 2021262395Sbapt 2022262395Sbapt /* We are at the end of a macro */ 2023262395Sbapt /* Skip ';' and space characters and return to previous state */ 2024262395Sbapt while (p < chunk->end) { 2025262395Sbapt if (!ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE) && *p != ';') { 2026262395Sbapt break; 2027262395Sbapt } 2028262395Sbapt ucl_chunk_skipc (chunk, p); 2029262395Sbapt } 2030262395Sbapt return true; 2031262395Sbapt} 2032262395Sbapt 2033262395Sbapt/** 2034275223Sbapt * Parse macro arguments as UCL object 2035275223Sbapt * @param parser parser structure 2036275223Sbapt * @param chunk the current data chunk 2037275223Sbapt * @return 2038275223Sbapt */ 2039275223Sbaptstatic ucl_object_t * 2040275223Sbaptucl_parse_macro_arguments (struct ucl_parser *parser, 2041275223Sbapt struct ucl_chunk *chunk) 2042275223Sbapt{ 2043275223Sbapt ucl_object_t *res = NULL; 2044275223Sbapt struct ucl_parser *params_parser; 2045275223Sbapt int obraces = 1, ebraces = 0, state = 0; 2046275223Sbapt const unsigned char *p, *c; 2047275223Sbapt size_t args_len = 0; 2048275223Sbapt struct ucl_parser_saved_state saved; 2049275223Sbapt 2050275223Sbapt saved.column = chunk->column; 2051275223Sbapt saved.line = chunk->line; 2052275223Sbapt saved.pos = chunk->pos; 2053275223Sbapt saved.remain = chunk->remain; 2054275223Sbapt p = chunk->pos; 2055275223Sbapt 2056275223Sbapt if (*p != '(' || chunk->remain < 2) { 2057275223Sbapt return NULL; 2058275223Sbapt } 2059275223Sbapt 2060275223Sbapt /* Set begin and start */ 2061275223Sbapt ucl_chunk_skipc (chunk, p); 2062275223Sbapt c = p; 2063275223Sbapt 2064275223Sbapt while ((p) < (chunk)->end) { 2065275223Sbapt switch (state) { 2066275223Sbapt case 0: 2067275223Sbapt /* Parse symbols and check for '(', ')' and '"' */ 2068275223Sbapt if (*p == '(') { 2069275223Sbapt obraces ++; 2070275223Sbapt } 2071275223Sbapt else if (*p == ')') { 2072275223Sbapt ebraces ++; 2073275223Sbapt } 2074275223Sbapt else if (*p == '"') { 2075275223Sbapt state = 1; 2076275223Sbapt } 2077275223Sbapt /* Check pairing */ 2078275223Sbapt if (obraces == ebraces) { 2079275223Sbapt state = 99; 2080275223Sbapt } 2081275223Sbapt else { 2082275223Sbapt args_len ++; 2083275223Sbapt } 2084275223Sbapt /* Check overflow */ 2085275223Sbapt if (chunk->remain == 0) { 2086275223Sbapt goto restore_chunk; 2087275223Sbapt } 2088275223Sbapt ucl_chunk_skipc (chunk, p); 2089275223Sbapt break; 2090275223Sbapt case 1: 2091275223Sbapt /* We have quote character, so skip all but quotes */ 2092275223Sbapt if (*p == '"' && *(p - 1) != '\\') { 2093275223Sbapt state = 0; 2094275223Sbapt } 2095275223Sbapt if (chunk->remain == 0) { 2096275223Sbapt goto restore_chunk; 2097275223Sbapt } 2098290071Sbapt args_len ++; 2099275223Sbapt ucl_chunk_skipc (chunk, p); 2100275223Sbapt break; 2101275223Sbapt case 99: 2102275223Sbapt /* 2103275223Sbapt * We have read the full body of arguments, so we need to parse and set 2104275223Sbapt * object from that 2105275223Sbapt */ 2106275223Sbapt params_parser = ucl_parser_new (parser->flags); 2107275223Sbapt if (!ucl_parser_add_chunk (params_parser, c, args_len)) { 2108275223Sbapt ucl_set_err (parser, UCL_ESYNTAX, "macro arguments parsing error", 2109275223Sbapt &parser->err); 2110275223Sbapt } 2111275223Sbapt else { 2112275223Sbapt res = ucl_parser_get_object (params_parser); 2113275223Sbapt } 2114275223Sbapt ucl_parser_free (params_parser); 2115275223Sbapt 2116275223Sbapt return res; 2117275223Sbapt 2118275223Sbapt break; 2119275223Sbapt } 2120275223Sbapt } 2121275223Sbapt 2122275223Sbapt return res; 2123275223Sbapt 2124275223Sbaptrestore_chunk: 2125275223Sbapt chunk->column = saved.column; 2126275223Sbapt chunk->line = saved.line; 2127275223Sbapt chunk->pos = saved.pos; 2128275223Sbapt chunk->remain = saved.remain; 2129275223Sbapt 2130275223Sbapt return NULL; 2131275223Sbapt} 2132275223Sbapt 2133275223Sbapt#define SKIP_SPACES_COMMENTS(parser, chunk, p) do { \ 2134275223Sbapt while ((p) < (chunk)->end) { \ 2135275223Sbapt if (!ucl_test_character (*(p), UCL_CHARACTER_WHITESPACE_UNSAFE)) { \ 2136275223Sbapt if ((chunk)->remain >= 2 && ucl_lex_is_comment ((p)[0], (p)[1])) { \ 2137275223Sbapt if (!ucl_skip_comments (parser)) { \ 2138275223Sbapt return false; \ 2139275223Sbapt } \ 2140275223Sbapt p = (chunk)->pos; \ 2141275223Sbapt } \ 2142275223Sbapt break; \ 2143275223Sbapt } \ 2144275223Sbapt ucl_chunk_skipc (chunk, p); \ 2145275223Sbapt } \ 2146275223Sbapt} while(0) 2147275223Sbapt 2148275223Sbapt/** 2149262395Sbapt * Handle the main states of rcl parser 2150262395Sbapt * @param parser parser structure 2151262395Sbapt * @return true if chunk has been parsed and false in case of error 2152262395Sbapt */ 2153262395Sbaptstatic bool 2154262395Sbaptucl_state_machine (struct ucl_parser *parser) 2155262395Sbapt{ 2156275223Sbapt ucl_object_t *obj, *macro_args; 2157262395Sbapt struct ucl_chunk *chunk = parser->chunks; 2158262395Sbapt const unsigned char *p, *c = NULL, *macro_start = NULL; 2159262395Sbapt unsigned char *macro_escaped; 2160262395Sbapt size_t macro_len = 0; 2161262395Sbapt struct ucl_macro *macro = NULL; 2162275223Sbapt bool next_key = false, end_of_object = false, ret; 2163262395Sbapt 2164262395Sbapt if (parser->top_obj == NULL) { 2165262395Sbapt parser->state = UCL_STATE_INIT; 2166262395Sbapt } 2167262395Sbapt 2168262395Sbapt p = chunk->pos; 2169262395Sbapt while (chunk->pos < chunk->end) { 2170262395Sbapt switch (parser->state) { 2171262395Sbapt case UCL_STATE_INIT: 2172262395Sbapt /* 2173262395Sbapt * At the init state we can either go to the parse array or object 2174262395Sbapt * if we got [ or { correspondingly or can just treat new data as 2175262395Sbapt * a key of newly created object 2176262395Sbapt */ 2177262395Sbapt if (!ucl_skip_comments (parser)) { 2178262395Sbapt parser->prev_state = parser->state; 2179262395Sbapt parser->state = UCL_STATE_ERROR; 2180262395Sbapt return false; 2181262395Sbapt } 2182262395Sbapt else { 2183268876Sbapt /* Skip any spaces */ 2184268876Sbapt while (p < chunk->end && ucl_test_character (*p, 2185268876Sbapt UCL_CHARACTER_WHITESPACE_UNSAFE)) { 2186268876Sbapt ucl_chunk_skipc (chunk, p); 2187268876Sbapt } 2188290071Sbapt 2189262395Sbapt p = chunk->pos; 2190290071Sbapt 2191262395Sbapt if (*p == '[') { 2192262395Sbapt parser->state = UCL_STATE_VALUE; 2193262395Sbapt ucl_chunk_skipc (chunk, p); 2194262395Sbapt } 2195262395Sbapt else { 2196262395Sbapt parser->state = UCL_STATE_KEY; 2197262395Sbapt if (*p == '{') { 2198262395Sbapt ucl_chunk_skipc (chunk, p); 2199262395Sbapt } 2200262395Sbapt } 2201290071Sbapt 2202290071Sbapt if (parser->top_obj == NULL) { 2203290071Sbapt if (parser->state == UCL_STATE_VALUE) { 2204290071Sbapt obj = ucl_parser_add_container (NULL, parser, true, 0); 2205290071Sbapt } 2206290071Sbapt else { 2207290071Sbapt obj = ucl_parser_add_container (NULL, parser, false, 0); 2208290071Sbapt } 2209290071Sbapt 2210290071Sbapt if (obj == NULL) { 2211290071Sbapt return false; 2212290071Sbapt } 2213290071Sbapt 2214290071Sbapt parser->top_obj = obj; 2215290071Sbapt parser->cur_obj = obj; 2216290071Sbapt } 2217290071Sbapt 2218262395Sbapt } 2219262395Sbapt break; 2220262395Sbapt case UCL_STATE_KEY: 2221262395Sbapt /* Skip any spaces */ 2222262395Sbapt while (p < chunk->end && ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE)) { 2223262395Sbapt ucl_chunk_skipc (chunk, p); 2224262395Sbapt } 2225298166Sbapt if (p == chunk->end || *p == '}') { 2226262395Sbapt /* We have the end of an object */ 2227262395Sbapt parser->state = UCL_STATE_AFTER_VALUE; 2228262395Sbapt continue; 2229262395Sbapt } 2230262395Sbapt if (parser->stack == NULL) { 2231262395Sbapt /* No objects are on stack, but we want to parse a key */ 2232275223Sbapt ucl_set_err (parser, UCL_ESYNTAX, "top object is finished but the parser " 2233262395Sbapt "expects a key", &parser->err); 2234262395Sbapt parser->prev_state = parser->state; 2235262395Sbapt parser->state = UCL_STATE_ERROR; 2236262395Sbapt return false; 2237262395Sbapt } 2238262395Sbapt if (!ucl_parse_key (parser, chunk, &next_key, &end_of_object)) { 2239262395Sbapt parser->prev_state = parser->state; 2240262395Sbapt parser->state = UCL_STATE_ERROR; 2241262395Sbapt return false; 2242262395Sbapt } 2243262395Sbapt if (end_of_object) { 2244262395Sbapt p = chunk->pos; 2245262395Sbapt parser->state = UCL_STATE_AFTER_VALUE; 2246262395Sbapt continue; 2247262395Sbapt } 2248262395Sbapt else if (parser->state != UCL_STATE_MACRO_NAME) { 2249262395Sbapt if (next_key && parser->stack->obj->type == UCL_OBJECT) { 2250262395Sbapt /* Parse more keys and nest objects accordingly */ 2251290071Sbapt obj = ucl_parser_add_container (parser->cur_obj, parser, false, 2252263648Sbapt parser->stack->level + 1); 2253263648Sbapt if (obj == NULL) { 2254263648Sbapt return false; 2255263648Sbapt } 2256262395Sbapt } 2257262395Sbapt else { 2258262395Sbapt parser->state = UCL_STATE_VALUE; 2259262395Sbapt } 2260262395Sbapt } 2261262395Sbapt else { 2262262395Sbapt c = chunk->pos; 2263262395Sbapt } 2264262395Sbapt p = chunk->pos; 2265262395Sbapt break; 2266262395Sbapt case UCL_STATE_VALUE: 2267262395Sbapt /* We need to check what we do have */ 2268298166Sbapt if (!parser->cur_obj || !ucl_parse_value (parser, chunk)) { 2269262395Sbapt parser->prev_state = parser->state; 2270262395Sbapt parser->state = UCL_STATE_ERROR; 2271262395Sbapt return false; 2272262395Sbapt } 2273262395Sbapt /* State is set in ucl_parse_value call */ 2274262395Sbapt p = chunk->pos; 2275262395Sbapt break; 2276262395Sbapt case UCL_STATE_AFTER_VALUE: 2277262395Sbapt if (!ucl_parse_after_value (parser, chunk)) { 2278262395Sbapt parser->prev_state = parser->state; 2279262395Sbapt parser->state = UCL_STATE_ERROR; 2280262395Sbapt return false; 2281262395Sbapt } 2282290071Sbapt 2283262395Sbapt if (parser->stack != NULL) { 2284262395Sbapt if (parser->stack->obj->type == UCL_OBJECT) { 2285262395Sbapt parser->state = UCL_STATE_KEY; 2286262395Sbapt } 2287262395Sbapt else { 2288262395Sbapt /* Array */ 2289262395Sbapt parser->state = UCL_STATE_VALUE; 2290262395Sbapt } 2291262395Sbapt } 2292262395Sbapt else { 2293262395Sbapt /* Skip everything at the end */ 2294262395Sbapt return true; 2295262395Sbapt } 2296298166Sbapt 2297262395Sbapt p = chunk->pos; 2298262395Sbapt break; 2299262395Sbapt case UCL_STATE_MACRO_NAME: 2300298166Sbapt if (parser->flags & UCL_PARSER_DISABLE_MACRO) { 2301298166Sbapt if (!ucl_skip_macro_as_comment (parser, chunk)) { 2302298166Sbapt /* We have invalid macro */ 2303298166Sbapt ucl_create_err (&parser->err, 2304298166Sbapt "error on line %d at column %d: invalid macro", 2305298166Sbapt chunk->line, 2306298166Sbapt chunk->column); 2307298166Sbapt parser->state = UCL_STATE_ERROR; 2308298166Sbapt return false; 2309298166Sbapt } 2310298166Sbapt else { 2311298166Sbapt p = chunk->pos; 2312298166Sbapt parser->state = parser->prev_state; 2313298166Sbapt } 2314262395Sbapt } 2315290071Sbapt else { 2316298166Sbapt if (!ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE) && 2317298166Sbapt *p != '(') { 2318298166Sbapt ucl_chunk_skipc (chunk, p); 2319298166Sbapt } 2320298166Sbapt else { 2321298166Sbapt if (c != NULL && p - c > 0) { 2322298166Sbapt /* We got macro name */ 2323298166Sbapt macro_len = (size_t) (p - c); 2324298166Sbapt HASH_FIND (hh, parser->macroes, c, macro_len, macro); 2325298166Sbapt if (macro == NULL) { 2326298166Sbapt ucl_create_err (&parser->err, 2327298166Sbapt "error on line %d at column %d: " 2328298166Sbapt "unknown macro: '%.*s', character: '%c'", 2329298166Sbapt chunk->line, 2330298166Sbapt chunk->column, 2331298166Sbapt (int) (p - c), 2332298166Sbapt c, 2333298166Sbapt *chunk->pos); 2334298166Sbapt parser->state = UCL_STATE_ERROR; 2335298166Sbapt return false; 2336298166Sbapt } 2337298166Sbapt /* Now we need to skip all spaces */ 2338298166Sbapt SKIP_SPACES_COMMENTS(parser, chunk, p); 2339298166Sbapt parser->state = UCL_STATE_MACRO; 2340298166Sbapt } 2341298166Sbapt else { 2342298166Sbapt /* We have invalid macro name */ 2343290071Sbapt ucl_create_err (&parser->err, 2344298166Sbapt "error on line %d at column %d: invalid macro name", 2345290071Sbapt chunk->line, 2346298166Sbapt chunk->column); 2347290071Sbapt parser->state = UCL_STATE_ERROR; 2348290071Sbapt return false; 2349290071Sbapt } 2350290071Sbapt } 2351262395Sbapt } 2352262395Sbapt break; 2353262395Sbapt case UCL_STATE_MACRO: 2354275223Sbapt if (*chunk->pos == '(') { 2355275223Sbapt macro_args = ucl_parse_macro_arguments (parser, chunk); 2356275223Sbapt p = chunk->pos; 2357275223Sbapt if (macro_args) { 2358275223Sbapt SKIP_SPACES_COMMENTS(parser, chunk, p); 2359275223Sbapt } 2360275223Sbapt } 2361275223Sbapt else { 2362275223Sbapt macro_args = NULL; 2363275223Sbapt } 2364262395Sbapt if (!ucl_parse_macro_value (parser, chunk, macro, 2365262395Sbapt ¯o_start, ¯o_len)) { 2366262395Sbapt parser->prev_state = parser->state; 2367262395Sbapt parser->state = UCL_STATE_ERROR; 2368262395Sbapt return false; 2369262395Sbapt } 2370275223Sbapt macro_len = ucl_expand_variable (parser, ¯o_escaped, 2371275223Sbapt macro_start, macro_len); 2372262395Sbapt parser->state = parser->prev_state; 2373298166Sbapt 2374298166Sbapt if (macro_escaped == NULL && macro != NULL) { 2375290071Sbapt if (macro->is_context) { 2376290071Sbapt ret = macro->h.context_handler (macro_start, macro_len, 2377290071Sbapt macro_args, 2378290071Sbapt parser->top_obj, 2379290071Sbapt macro->ud); 2380290071Sbapt } 2381290071Sbapt else { 2382290071Sbapt ret = macro->h.handler (macro_start, macro_len, macro_args, 2383290071Sbapt macro->ud); 2384290071Sbapt } 2385262395Sbapt } 2386298166Sbapt else if (macro != NULL) { 2387290071Sbapt if (macro->is_context) { 2388290071Sbapt ret = macro->h.context_handler (macro_escaped, macro_len, 2389290071Sbapt macro_args, 2390290071Sbapt parser->top_obj, 2391290071Sbapt macro->ud); 2392290071Sbapt } 2393290071Sbapt else { 2394290071Sbapt ret = macro->h.handler (macro_escaped, macro_len, macro_args, 2395275223Sbapt macro->ud); 2396290071Sbapt } 2397290071Sbapt 2398262395Sbapt UCL_FREE (macro_len + 1, macro_escaped); 2399262395Sbapt } 2400298166Sbapt else { 2401298166Sbapt ret = false; 2402298166Sbapt ucl_set_err (parser, UCL_EINTERNAL, 2403298166Sbapt "internal error: parser has macro undefined", &parser->err); 2404298166Sbapt } 2405290071Sbapt 2406290071Sbapt /* 2407290071Sbapt * Chunk can be modified within macro handler 2408290071Sbapt */ 2409290071Sbapt chunk = parser->chunks; 2410262395Sbapt p = chunk->pos; 2411298166Sbapt 2412275223Sbapt if (macro_args) { 2413275223Sbapt ucl_object_unref (macro_args); 2414275223Sbapt } 2415298166Sbapt 2416275223Sbapt if (!ret) { 2417275223Sbapt return false; 2418275223Sbapt } 2419262395Sbapt break; 2420262395Sbapt default: 2421275223Sbapt ucl_set_err (parser, UCL_EINTERNAL, 2422275223Sbapt "internal error: parser is in an unknown state", &parser->err); 2423262395Sbapt parser->state = UCL_STATE_ERROR; 2424262395Sbapt return false; 2425262395Sbapt } 2426262395Sbapt } 2427262395Sbapt 2428298166Sbapt if (parser->last_comment) { 2429298166Sbapt if (parser->cur_obj) { 2430298166Sbapt ucl_attach_comment (parser, parser->cur_obj, true); 2431298166Sbapt } 2432298166Sbapt else if (parser->stack && parser->stack->obj) { 2433298166Sbapt ucl_attach_comment (parser, parser->stack->obj, true); 2434298166Sbapt } 2435298166Sbapt else if (parser->top_obj) { 2436298166Sbapt ucl_attach_comment (parser, parser->top_obj, true); 2437298166Sbapt } 2438298166Sbapt else { 2439298166Sbapt ucl_object_unref (parser->last_comment); 2440298166Sbapt } 2441298166Sbapt } 2442298166Sbapt 2443262395Sbapt return true; 2444262395Sbapt} 2445262395Sbapt 2446262395Sbaptstruct ucl_parser* 2447262395Sbaptucl_parser_new (int flags) 2448262395Sbapt{ 2449298166Sbapt struct ucl_parser *parser; 2450262395Sbapt 2451298166Sbapt parser = UCL_ALLOC (sizeof (struct ucl_parser)); 2452298166Sbapt if (parser == NULL) { 2453263648Sbapt return NULL; 2454263648Sbapt } 2455290071Sbapt 2456298166Sbapt memset (parser, 0, sizeof (struct ucl_parser)); 2457262395Sbapt 2458298166Sbapt ucl_parser_register_macro (parser, "include", ucl_include_handler, parser); 2459298166Sbapt ucl_parser_register_macro (parser, "try_include", ucl_try_include_handler, parser); 2460298166Sbapt ucl_parser_register_macro (parser, "includes", ucl_includes_handler, parser); 2461298166Sbapt ucl_parser_register_macro (parser, "priority", ucl_priority_handler, parser); 2462298166Sbapt ucl_parser_register_macro (parser, "load", ucl_load_handler, parser); 2463298166Sbapt ucl_parser_register_context_macro (parser, "inherit", ucl_inherit_handler, parser); 2464262395Sbapt 2465298166Sbapt parser->flags = flags; 2466298166Sbapt parser->includepaths = NULL; 2467262395Sbapt 2468298166Sbapt if (flags & UCL_PARSER_SAVE_COMMENTS) { 2469298166Sbapt parser->comments = ucl_object_typed_new (UCL_OBJECT); 2470298166Sbapt } 2471298166Sbapt 2472314278Sbapt if (!(flags & UCL_PARSER_NO_FILEVARS)) { 2473314278Sbapt /* Initial assumption about filevars */ 2474314278Sbapt ucl_parser_set_filevars (parser, NULL, false); 2475314278Sbapt } 2476262395Sbapt 2477298166Sbapt return parser; 2478262395Sbapt} 2479262395Sbapt 2480290071Sbaptbool 2481290071Sbaptucl_parser_set_default_priority (struct ucl_parser *parser, unsigned prio) 2482290071Sbapt{ 2483290071Sbapt if (parser == NULL) { 2484290071Sbapt return false; 2485290071Sbapt } 2486262395Sbapt 2487290071Sbapt parser->default_priority = prio; 2488290071Sbapt 2489290071Sbapt return true; 2490290071Sbapt} 2491290071Sbapt 2492262395Sbaptvoid 2493262395Sbaptucl_parser_register_macro (struct ucl_parser *parser, const char *macro, 2494262395Sbapt ucl_macro_handler handler, void* ud) 2495262395Sbapt{ 2496262395Sbapt struct ucl_macro *new; 2497262395Sbapt 2498263648Sbapt if (macro == NULL || handler == NULL) { 2499263648Sbapt return; 2500263648Sbapt } 2501290071Sbapt 2502262395Sbapt new = UCL_ALLOC (sizeof (struct ucl_macro)); 2503263648Sbapt if (new == NULL) { 2504263648Sbapt return; 2505263648Sbapt } 2506290071Sbapt 2507262395Sbapt memset (new, 0, sizeof (struct ucl_macro)); 2508290071Sbapt new->h.handler = handler; 2509262395Sbapt new->name = strdup (macro); 2510262395Sbapt new->ud = ud; 2511262395Sbapt HASH_ADD_KEYPTR (hh, parser->macroes, new->name, strlen (new->name), new); 2512262395Sbapt} 2513262395Sbapt 2514262395Sbaptvoid 2515290071Sbaptucl_parser_register_context_macro (struct ucl_parser *parser, const char *macro, 2516290071Sbapt ucl_context_macro_handler handler, void* ud) 2517290071Sbapt{ 2518290071Sbapt struct ucl_macro *new; 2519290071Sbapt 2520290071Sbapt if (macro == NULL || handler == NULL) { 2521290071Sbapt return; 2522290071Sbapt } 2523290071Sbapt 2524290071Sbapt new = UCL_ALLOC (sizeof (struct ucl_macro)); 2525290071Sbapt if (new == NULL) { 2526290071Sbapt return; 2527290071Sbapt } 2528290071Sbapt 2529290071Sbapt memset (new, 0, sizeof (struct ucl_macro)); 2530290071Sbapt new->h.context_handler = handler; 2531290071Sbapt new->name = strdup (macro); 2532290071Sbapt new->ud = ud; 2533290071Sbapt new->is_context = true; 2534290071Sbapt HASH_ADD_KEYPTR (hh, parser->macroes, new->name, strlen (new->name), new); 2535290071Sbapt} 2536290071Sbapt 2537290071Sbaptvoid 2538262395Sbaptucl_parser_register_variable (struct ucl_parser *parser, const char *var, 2539262395Sbapt const char *value) 2540262395Sbapt{ 2541262395Sbapt struct ucl_variable *new = NULL, *cur; 2542262395Sbapt 2543262395Sbapt if (var == NULL) { 2544262395Sbapt return; 2545262395Sbapt } 2546262395Sbapt 2547262395Sbapt /* Find whether a variable already exists */ 2548262395Sbapt LL_FOREACH (parser->variables, cur) { 2549262395Sbapt if (strcmp (cur->var, var) == 0) { 2550262395Sbapt new = cur; 2551262395Sbapt break; 2552262395Sbapt } 2553262395Sbapt } 2554262395Sbapt 2555262395Sbapt if (value == NULL) { 2556262395Sbapt 2557262395Sbapt if (new != NULL) { 2558262395Sbapt /* Remove variable */ 2559275223Sbapt DL_DELETE (parser->variables, new); 2560262395Sbapt free (new->var); 2561262395Sbapt free (new->value); 2562262395Sbapt UCL_FREE (sizeof (struct ucl_variable), new); 2563262395Sbapt } 2564262395Sbapt else { 2565262395Sbapt /* Do nothing */ 2566262395Sbapt return; 2567262395Sbapt } 2568262395Sbapt } 2569262395Sbapt else { 2570262395Sbapt if (new == NULL) { 2571262395Sbapt new = UCL_ALLOC (sizeof (struct ucl_variable)); 2572263648Sbapt if (new == NULL) { 2573263648Sbapt return; 2574263648Sbapt } 2575262395Sbapt memset (new, 0, sizeof (struct ucl_variable)); 2576262395Sbapt new->var = strdup (var); 2577262395Sbapt new->var_len = strlen (var); 2578262395Sbapt new->value = strdup (value); 2579262395Sbapt new->value_len = strlen (value); 2580262395Sbapt 2581275223Sbapt DL_APPEND (parser->variables, new); 2582262395Sbapt } 2583262395Sbapt else { 2584262395Sbapt free (new->value); 2585262395Sbapt new->value = strdup (value); 2586262395Sbapt new->value_len = strlen (value); 2587262395Sbapt } 2588262395Sbapt } 2589262395Sbapt} 2590262395Sbapt 2591266636Sbaptvoid 2592266636Sbaptucl_parser_set_variables_handler (struct ucl_parser *parser, 2593266636Sbapt ucl_variable_handler handler, void *ud) 2594266636Sbapt{ 2595266636Sbapt parser->var_handler = handler; 2596266636Sbapt parser->var_data = ud; 2597266636Sbapt} 2598266636Sbapt 2599262395Sbaptbool 2600290071Sbaptucl_parser_add_chunk_full (struct ucl_parser *parser, const unsigned char *data, 2601290071Sbapt size_t len, unsigned priority, enum ucl_duplicate_strategy strat, 2602290071Sbapt enum ucl_parse_type parse_type) 2603262395Sbapt{ 2604262395Sbapt struct ucl_chunk *chunk; 2605262395Sbapt 2606290071Sbapt if (parser == NULL) { 2607290071Sbapt return false; 2608290071Sbapt } 2609290071Sbapt 2610301339Sbapt if (data == NULL && len != 0) { 2611263648Sbapt ucl_create_err (&parser->err, "invalid chunk added"); 2612263648Sbapt return false; 2613263648Sbapt } 2614298166Sbapt 2615262395Sbapt if (parser->state != UCL_STATE_ERROR) { 2616262395Sbapt chunk = UCL_ALLOC (sizeof (struct ucl_chunk)); 2617263648Sbapt if (chunk == NULL) { 2618263648Sbapt ucl_create_err (&parser->err, "cannot allocate chunk structure"); 2619263648Sbapt return false; 2620263648Sbapt } 2621301339Sbapt 2622314278Sbapt if (parse_type == UCL_PARSE_AUTO && len > 0) { 2623314278Sbapt /* We need to detect parse type by the first symbol */ 2624314278Sbapt if ((*data & 0x80) == 0x80 && (*data >= 0xdc && *data <= 0xdf)) { 2625314278Sbapt parse_type = UCL_PARSE_MSGPACK; 2626314278Sbapt } 2627314278Sbapt else if (*data == '(') { 2628314278Sbapt parse_type = UCL_PARSE_CSEXP; 2629314278Sbapt } 2630314278Sbapt else { 2631314278Sbapt parse_type = UCL_PARSE_UCL; 2632314278Sbapt } 2633314278Sbapt } 2634314278Sbapt 2635262395Sbapt chunk->begin = data; 2636262395Sbapt chunk->remain = len; 2637262395Sbapt chunk->pos = chunk->begin; 2638262395Sbapt chunk->end = chunk->begin + len; 2639262395Sbapt chunk->line = 1; 2640262395Sbapt chunk->column = 0; 2641275223Sbapt chunk->priority = priority; 2642290071Sbapt chunk->strategy = strat; 2643290071Sbapt chunk->parse_type = parse_type; 2644262395Sbapt LL_PREPEND (parser->chunks, chunk); 2645262395Sbapt parser->recursion ++; 2646290071Sbapt 2647262395Sbapt if (parser->recursion > UCL_MAX_RECURSION) { 2648262395Sbapt ucl_create_err (&parser->err, "maximum include nesting limit is reached: %d", 2649262395Sbapt parser->recursion); 2650262395Sbapt return false; 2651262395Sbapt } 2652290071Sbapt 2653301339Sbapt if (len > 0) { 2654301339Sbapt /* Need to parse something */ 2655301339Sbapt switch (parse_type) { 2656301339Sbapt default: 2657301339Sbapt case UCL_PARSE_UCL: 2658301339Sbapt return ucl_state_machine (parser); 2659301339Sbapt case UCL_PARSE_MSGPACK: 2660301339Sbapt return ucl_parse_msgpack (parser); 2661314278Sbapt case UCL_PARSE_CSEXP: 2662314278Sbapt return ucl_parse_csexp (parser); 2663301339Sbapt } 2664290071Sbapt } 2665301339Sbapt else { 2666301339Sbapt /* Just add empty chunk and go forward */ 2667301339Sbapt if (parser->top_obj == NULL) { 2668301339Sbapt /* 2669301339Sbapt * In case of empty object, create one to indicate that we've 2670301339Sbapt * read something 2671301339Sbapt */ 2672301339Sbapt parser->top_obj = ucl_object_new_full (UCL_OBJECT, priority); 2673301339Sbapt } 2674301339Sbapt 2675301339Sbapt return true; 2676301339Sbapt } 2677262395Sbapt } 2678262395Sbapt 2679262395Sbapt ucl_create_err (&parser->err, "a parser is in an invalid state"); 2680262395Sbapt 2681262395Sbapt return false; 2682262395Sbapt} 2683263648Sbapt 2684263648Sbaptbool 2685290071Sbaptucl_parser_add_chunk_priority (struct ucl_parser *parser, 2686290071Sbapt const unsigned char *data, size_t len, unsigned priority) 2687290071Sbapt{ 2688290071Sbapt /* We dereference parser, so this check is essential */ 2689290071Sbapt if (parser == NULL) { 2690290071Sbapt return false; 2691290071Sbapt } 2692290071Sbapt 2693290071Sbapt return ucl_parser_add_chunk_full (parser, data, len, 2694290071Sbapt priority, UCL_DUPLICATE_APPEND, UCL_PARSE_UCL); 2695290071Sbapt} 2696290071Sbapt 2697290071Sbaptbool 2698275223Sbaptucl_parser_add_chunk (struct ucl_parser *parser, const unsigned char *data, 2699275223Sbapt size_t len) 2700275223Sbapt{ 2701290071Sbapt if (parser == NULL) { 2702290071Sbapt return false; 2703290071Sbapt } 2704290071Sbapt 2705290071Sbapt return ucl_parser_add_chunk_full (parser, data, len, 2706290071Sbapt parser->default_priority, UCL_DUPLICATE_APPEND, UCL_PARSE_UCL); 2707275223Sbapt} 2708275223Sbapt 2709275223Sbaptbool 2710290071Sbaptucl_parser_add_string_priority (struct ucl_parser *parser, const char *data, 2711290071Sbapt size_t len, unsigned priority) 2712263648Sbapt{ 2713263648Sbapt if (data == NULL) { 2714263648Sbapt ucl_create_err (&parser->err, "invalid string added"); 2715263648Sbapt return false; 2716263648Sbapt } 2717263648Sbapt if (len == 0) { 2718263648Sbapt len = strlen (data); 2719263648Sbapt } 2720263648Sbapt 2721290071Sbapt return ucl_parser_add_chunk_priority (parser, 2722290071Sbapt (const unsigned char *)data, len, priority); 2723263648Sbapt} 2724290071Sbapt 2725290071Sbaptbool 2726290071Sbaptucl_parser_add_string (struct ucl_parser *parser, const char *data, 2727290071Sbapt size_t len) 2728290071Sbapt{ 2729290071Sbapt if (parser == NULL) { 2730290071Sbapt return false; 2731290071Sbapt } 2732290071Sbapt 2733290071Sbapt return ucl_parser_add_string_priority (parser, 2734290071Sbapt (const unsigned char *)data, len, parser->default_priority); 2735290071Sbapt} 2736290071Sbapt 2737290071Sbaptbool 2738290071Sbaptucl_set_include_path (struct ucl_parser *parser, ucl_object_t *paths) 2739290071Sbapt{ 2740290071Sbapt if (parser == NULL || paths == NULL) { 2741290071Sbapt return false; 2742290071Sbapt } 2743290071Sbapt 2744290071Sbapt if (parser->includepaths == NULL) { 2745290071Sbapt parser->includepaths = ucl_object_copy (paths); 2746290071Sbapt } 2747290071Sbapt else { 2748290071Sbapt ucl_object_unref (parser->includepaths); 2749290071Sbapt parser->includepaths = ucl_object_copy (paths); 2750290071Sbapt } 2751290071Sbapt 2752290071Sbapt if (parser->includepaths == NULL) { 2753290071Sbapt return false; 2754290071Sbapt } 2755290071Sbapt 2756290071Sbapt return true; 2757290071Sbapt} 2758