ucl_parser.c revision 290071
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 92262395Sbapt/** 93262395Sbapt * Skip all comments from the current pos resolving nested and multiline comments 94262395Sbapt * @param parser 95262395Sbapt * @return 96262395Sbapt */ 97262395Sbaptstatic bool 98262395Sbaptucl_skip_comments (struct ucl_parser *parser) 99262395Sbapt{ 100262395Sbapt struct ucl_chunk *chunk = parser->chunks; 101262395Sbapt const unsigned char *p; 102262395Sbapt int comments_nested = 0; 103275223Sbapt bool quoted = false; 104262395Sbapt 105262395Sbapt p = chunk->pos; 106262395Sbapt 107262395Sbaptstart: 108275223Sbapt if (chunk->remain > 0 && *p == '#') { 109262395Sbapt if (parser->state != UCL_STATE_SCOMMENT && 110262395Sbapt parser->state != UCL_STATE_MCOMMENT) { 111262395Sbapt while (p < chunk->end) { 112262395Sbapt if (*p == '\n') { 113262395Sbapt ucl_chunk_skipc (chunk, p); 114262395Sbapt goto start; 115262395Sbapt } 116262395Sbapt ucl_chunk_skipc (chunk, p); 117262395Sbapt } 118262395Sbapt } 119262395Sbapt } 120275223Sbapt else if (chunk->remain >= 2 && *p == '/') { 121262395Sbapt if (p[1] == '*') { 122262395Sbapt ucl_chunk_skipc (chunk, p); 123262395Sbapt comments_nested ++; 124262395Sbapt ucl_chunk_skipc (chunk, p); 125262395Sbapt 126262395Sbapt while (p < chunk->end) { 127275223Sbapt if (*p == '"' && *(p - 1) != '\\') { 128275223Sbapt quoted = !quoted; 129275223Sbapt } 130275223Sbapt 131275223Sbapt if (!quoted) { 132275223Sbapt if (*p == '*') { 133275223Sbapt ucl_chunk_skipc (chunk, p); 134275223Sbapt if (*p == '/') { 135275223Sbapt comments_nested --; 136275223Sbapt if (comments_nested == 0) { 137275223Sbapt ucl_chunk_skipc (chunk, p); 138275223Sbapt goto start; 139275223Sbapt } 140262395Sbapt } 141275223Sbapt ucl_chunk_skipc (chunk, p); 142262395Sbapt } 143275223Sbapt else if (p[0] == '/' && chunk->remain >= 2 && p[1] == '*') { 144275223Sbapt comments_nested ++; 145275223Sbapt ucl_chunk_skipc (chunk, p); 146275223Sbapt ucl_chunk_skipc (chunk, p); 147275223Sbapt continue; 148275223Sbapt } 149262395Sbapt } 150262395Sbapt ucl_chunk_skipc (chunk, p); 151262395Sbapt } 152262395Sbapt if (comments_nested != 0) { 153275223Sbapt ucl_set_err (parser, UCL_ENESTED, 154275223Sbapt "unfinished multiline comment", &parser->err); 155262395Sbapt return false; 156262395Sbapt } 157262395Sbapt } 158262395Sbapt } 159262395Sbapt 160262395Sbapt return true; 161262395Sbapt} 162262395Sbapt 163262395Sbapt/** 164262395Sbapt * Return multiplier for a character 165262395Sbapt * @param c multiplier character 166262395Sbapt * @param is_bytes if true use 1024 multiplier 167262395Sbapt * @return multiplier 168262395Sbapt */ 169262395Sbaptstatic inline unsigned long 170262395Sbaptucl_lex_num_multiplier (const unsigned char c, bool is_bytes) { 171262395Sbapt const struct { 172262395Sbapt char c; 173262395Sbapt long mult_normal; 174262395Sbapt long mult_bytes; 175262395Sbapt } multipliers[] = { 176262395Sbapt {'m', 1000 * 1000, 1024 * 1024}, 177262395Sbapt {'k', 1000, 1024}, 178262395Sbapt {'g', 1000 * 1000 * 1000, 1024 * 1024 * 1024} 179262395Sbapt }; 180262395Sbapt int i; 181262395Sbapt 182262395Sbapt for (i = 0; i < 3; i ++) { 183262395Sbapt if (tolower (c) == multipliers[i].c) { 184262395Sbapt if (is_bytes) { 185262395Sbapt return multipliers[i].mult_bytes; 186262395Sbapt } 187262395Sbapt return multipliers[i].mult_normal; 188262395Sbapt } 189262395Sbapt } 190262395Sbapt 191262395Sbapt return 1; 192262395Sbapt} 193262395Sbapt 194262395Sbapt 195262395Sbapt/** 196262395Sbapt * Return multiplier for time scaling 197262395Sbapt * @param c 198262395Sbapt * @return 199262395Sbapt */ 200262395Sbaptstatic inline double 201262395Sbaptucl_lex_time_multiplier (const unsigned char c) { 202262395Sbapt const struct { 203262395Sbapt char c; 204262395Sbapt double mult; 205262395Sbapt } multipliers[] = { 206262395Sbapt {'m', 60}, 207262395Sbapt {'h', 60 * 60}, 208262395Sbapt {'d', 60 * 60 * 24}, 209262395Sbapt {'w', 60 * 60 * 24 * 7}, 210262395Sbapt {'y', 60 * 60 * 24 * 7 * 365} 211262395Sbapt }; 212262395Sbapt int i; 213262395Sbapt 214262395Sbapt for (i = 0; i < 5; i ++) { 215262395Sbapt if (tolower (c) == multipliers[i].c) { 216262395Sbapt return multipliers[i].mult; 217262395Sbapt } 218262395Sbapt } 219262395Sbapt 220262395Sbapt return 1; 221262395Sbapt} 222262395Sbapt 223262395Sbapt/** 224262395Sbapt * Return true if a character is a end of an atom 225262395Sbapt * @param c 226262395Sbapt * @return 227262395Sbapt */ 228262395Sbaptstatic inline bool 229262395Sbaptucl_lex_is_atom_end (const unsigned char c) 230262395Sbapt{ 231262395Sbapt return ucl_test_character (c, UCL_CHARACTER_VALUE_END); 232262395Sbapt} 233262395Sbapt 234262395Sbaptstatic inline bool 235262395Sbaptucl_lex_is_comment (const unsigned char c1, const unsigned char c2) 236262395Sbapt{ 237262395Sbapt if (c1 == '/') { 238262395Sbapt if (c2 == '*') { 239262395Sbapt return true; 240262395Sbapt } 241262395Sbapt } 242262395Sbapt else if (c1 == '#') { 243262395Sbapt return true; 244262395Sbapt } 245262395Sbapt return false; 246262395Sbapt} 247262395Sbapt 248262395Sbapt/** 249262395Sbapt * Check variable found 250262395Sbapt * @param parser 251262395Sbapt * @param ptr 252262395Sbapt * @param remain 253262395Sbapt * @param out_len 254262395Sbapt * @param strict 255262395Sbapt * @param found 256262395Sbapt * @return 257262395Sbapt */ 258262395Sbaptstatic inline const char * 259262395Sbaptucl_check_variable_safe (struct ucl_parser *parser, const char *ptr, size_t remain, 260262395Sbapt size_t *out_len, bool strict, bool *found) 261262395Sbapt{ 262262395Sbapt struct ucl_variable *var; 263266636Sbapt unsigned char *dst; 264266636Sbapt size_t dstlen; 265266636Sbapt bool need_free = false; 266262395Sbapt 267262395Sbapt LL_FOREACH (parser->variables, var) { 268262395Sbapt if (strict) { 269262395Sbapt if (remain == var->var_len) { 270262395Sbapt if (memcmp (ptr, var->var, var->var_len) == 0) { 271262395Sbapt *out_len += var->value_len; 272262395Sbapt *found = true; 273262395Sbapt return (ptr + var->var_len); 274262395Sbapt } 275262395Sbapt } 276262395Sbapt } 277262395Sbapt else { 278262395Sbapt if (remain >= var->var_len) { 279262395Sbapt if (memcmp (ptr, var->var, var->var_len) == 0) { 280262395Sbapt *out_len += var->value_len; 281262395Sbapt *found = true; 282262395Sbapt return (ptr + var->var_len); 283262395Sbapt } 284262395Sbapt } 285262395Sbapt } 286262395Sbapt } 287262395Sbapt 288266636Sbapt /* XXX: can only handle ${VAR} */ 289266636Sbapt if (!(*found) && parser->var_handler != NULL && strict) { 290266636Sbapt /* Call generic handler */ 291266636Sbapt if (parser->var_handler (ptr, remain, &dst, &dstlen, &need_free, 292266636Sbapt parser->var_data)) { 293266636Sbapt *found = true; 294266636Sbapt if (need_free) { 295266636Sbapt free (dst); 296266636Sbapt } 297266636Sbapt return (ptr + remain); 298266636Sbapt } 299266636Sbapt } 300266636Sbapt 301262395Sbapt return ptr; 302262395Sbapt} 303262395Sbapt 304262395Sbapt/** 305262395Sbapt * Check for a variable in a given string 306262395Sbapt * @param parser 307262395Sbapt * @param ptr 308262395Sbapt * @param remain 309262395Sbapt * @param out_len 310262395Sbapt * @param vars_found 311262395Sbapt * @return 312262395Sbapt */ 313262395Sbaptstatic const char * 314266636Sbaptucl_check_variable (struct ucl_parser *parser, const char *ptr, 315266636Sbapt size_t remain, size_t *out_len, bool *vars_found) 316262395Sbapt{ 317262395Sbapt const char *p, *end, *ret = ptr; 318262395Sbapt bool found = false; 319262395Sbapt 320262395Sbapt if (*ptr == '{') { 321262395Sbapt /* We need to match the variable enclosed in braces */ 322262395Sbapt p = ptr + 1; 323262395Sbapt end = ptr + remain; 324262395Sbapt while (p < end) { 325262395Sbapt if (*p == '}') { 326266636Sbapt ret = ucl_check_variable_safe (parser, ptr + 1, p - ptr - 1, 327266636Sbapt out_len, true, &found); 328262395Sbapt if (found) { 329262395Sbapt /* {} must be excluded actually */ 330262395Sbapt ret ++; 331262395Sbapt if (!*vars_found) { 332262395Sbapt *vars_found = true; 333262395Sbapt } 334262395Sbapt } 335262395Sbapt else { 336262395Sbapt *out_len += 2; 337262395Sbapt } 338262395Sbapt break; 339262395Sbapt } 340262395Sbapt p ++; 341262395Sbapt } 342262395Sbapt } 343262395Sbapt else if (*ptr != '$') { 344262395Sbapt /* Not count escaped dollar sign */ 345262395Sbapt ret = ucl_check_variable_safe (parser, ptr, remain, out_len, false, &found); 346262395Sbapt if (found && !*vars_found) { 347262395Sbapt *vars_found = true; 348262395Sbapt } 349262395Sbapt if (!found) { 350262395Sbapt (*out_len) ++; 351262395Sbapt } 352262395Sbapt } 353262395Sbapt else { 354262395Sbapt ret ++; 355262395Sbapt (*out_len) ++; 356262395Sbapt } 357262395Sbapt 358262395Sbapt return ret; 359262395Sbapt} 360262395Sbapt 361262395Sbapt/** 362262395Sbapt * Expand a single variable 363262395Sbapt * @param parser 364262395Sbapt * @param ptr 365262395Sbapt * @param remain 366262395Sbapt * @param dest 367262395Sbapt * @return 368262395Sbapt */ 369262395Sbaptstatic const char * 370262395Sbaptucl_expand_single_variable (struct ucl_parser *parser, const char *ptr, 371262395Sbapt size_t remain, unsigned char **dest) 372262395Sbapt{ 373266636Sbapt unsigned char *d = *dest, *dst; 374262395Sbapt const char *p = ptr + 1, *ret; 375262395Sbapt struct ucl_variable *var; 376266636Sbapt size_t dstlen; 377266636Sbapt bool need_free = false; 378262395Sbapt bool found = false; 379266636Sbapt bool strict = false; 380262395Sbapt 381262395Sbapt ret = ptr + 1; 382262395Sbapt remain --; 383262395Sbapt 384262395Sbapt if (*p == '$') { 385262395Sbapt *d++ = *p++; 386262395Sbapt *dest = d; 387262395Sbapt return p; 388262395Sbapt } 389262395Sbapt else if (*p == '{') { 390262395Sbapt p ++; 391266636Sbapt strict = true; 392262395Sbapt ret += 2; 393262395Sbapt remain -= 2; 394262395Sbapt } 395262395Sbapt 396262395Sbapt LL_FOREACH (parser->variables, var) { 397262395Sbapt if (remain >= var->var_len) { 398262395Sbapt if (memcmp (p, var->var, var->var_len) == 0) { 399262395Sbapt memcpy (d, var->value, var->value_len); 400262395Sbapt ret += var->var_len; 401262395Sbapt d += var->value_len; 402262395Sbapt found = true; 403262395Sbapt break; 404262395Sbapt } 405262395Sbapt } 406262395Sbapt } 407262395Sbapt if (!found) { 408266636Sbapt if (strict && parser->var_handler != NULL) { 409266636Sbapt if (parser->var_handler (ptr, remain, &dst, &dstlen, &need_free, 410266636Sbapt parser->var_data)) { 411266636Sbapt memcpy (d, dst, dstlen); 412266636Sbapt ret += dstlen; 413266636Sbapt d += remain; 414266636Sbapt found = true; 415266636Sbapt } 416266636Sbapt } 417266636Sbapt 418266636Sbapt /* Leave variable as is */ 419266636Sbapt if (!found) { 420268831Sbapt if (strict) { 421268831Sbapt /* Copy '${' */ 422268831Sbapt memcpy (d, ptr, 2); 423268831Sbapt d += 2; 424268831Sbapt ret --; 425268831Sbapt } 426268831Sbapt else { 427268831Sbapt memcpy (d, ptr, 1); 428268831Sbapt d ++; 429268831Sbapt } 430266636Sbapt } 431262395Sbapt } 432262395Sbapt 433262395Sbapt *dest = d; 434262395Sbapt return ret; 435262395Sbapt} 436262395Sbapt 437262395Sbapt/** 438262395Sbapt * Expand variables in string 439262395Sbapt * @param parser 440262395Sbapt * @param dst 441262395Sbapt * @param src 442262395Sbapt * @param in_len 443262395Sbapt * @return 444262395Sbapt */ 445262395Sbaptstatic ssize_t 446262395Sbaptucl_expand_variable (struct ucl_parser *parser, unsigned char **dst, 447262395Sbapt const char *src, size_t in_len) 448262395Sbapt{ 449262395Sbapt const char *p, *end = src + in_len; 450262395Sbapt unsigned char *d; 451262395Sbapt size_t out_len = 0; 452262395Sbapt bool vars_found = false; 453262395Sbapt 454262395Sbapt p = src; 455262395Sbapt while (p != end) { 456262395Sbapt if (*p == '$') { 457262395Sbapt p = ucl_check_variable (parser, p + 1, end - p - 1, &out_len, &vars_found); 458262395Sbapt } 459262395Sbapt else { 460262395Sbapt p ++; 461262395Sbapt out_len ++; 462262395Sbapt } 463262395Sbapt } 464262395Sbapt 465262395Sbapt if (!vars_found) { 466262395Sbapt /* Trivial case */ 467262395Sbapt *dst = NULL; 468262395Sbapt return in_len; 469262395Sbapt } 470262395Sbapt 471262395Sbapt *dst = UCL_ALLOC (out_len + 1); 472262395Sbapt if (*dst == NULL) { 473262395Sbapt return in_len; 474262395Sbapt } 475262395Sbapt 476262395Sbapt d = *dst; 477262395Sbapt p = src; 478262395Sbapt while (p != end) { 479262395Sbapt if (*p == '$') { 480262395Sbapt p = ucl_expand_single_variable (parser, p, end - p, &d); 481262395Sbapt } 482262395Sbapt else { 483262395Sbapt *d++ = *p++; 484262395Sbapt } 485262395Sbapt } 486262395Sbapt 487262395Sbapt *d = '\0'; 488262395Sbapt 489262395Sbapt return out_len; 490262395Sbapt} 491262395Sbapt 492262395Sbapt/** 493262395Sbapt * Store or copy pointer to the trash stack 494262395Sbapt * @param parser parser object 495262395Sbapt * @param src src string 496262395Sbapt * @param dst destination buffer (trash stack pointer) 497262395Sbapt * @param dst_const const destination pointer (e.g. value of object) 498262395Sbapt * @param in_len input length 499262395Sbapt * @param need_unescape need to unescape source (and copy it) 500262395Sbapt * @param need_lowercase need to lowercase value (and copy) 501262395Sbapt * @param need_expand need to expand variables (and copy as well) 502262395Sbapt * @return output length (excluding \0 symbol) 503262395Sbapt */ 504262395Sbaptstatic inline ssize_t 505262395Sbaptucl_copy_or_store_ptr (struct ucl_parser *parser, 506262395Sbapt const unsigned char *src, unsigned char **dst, 507262395Sbapt const char **dst_const, size_t in_len, 508262395Sbapt bool need_unescape, bool need_lowercase, bool need_expand) 509262395Sbapt{ 510262395Sbapt ssize_t ret = -1, tret; 511262395Sbapt unsigned char *tmp; 512262395Sbapt 513262395Sbapt if (need_unescape || need_lowercase || 514262395Sbapt (need_expand && parser->variables != NULL) || 515262395Sbapt !(parser->flags & UCL_PARSER_ZEROCOPY)) { 516262395Sbapt /* Copy string */ 517262395Sbapt *dst = UCL_ALLOC (in_len + 1); 518262395Sbapt if (*dst == NULL) { 519290071Sbapt ucl_set_err (parser, UCL_EINTERNAL, "cannot allocate memory for a string", 520275223Sbapt &parser->err); 521262395Sbapt return false; 522262395Sbapt } 523262395Sbapt if (need_lowercase) { 524262395Sbapt ret = ucl_strlcpy_tolower (*dst, src, in_len + 1); 525262395Sbapt } 526262395Sbapt else { 527262395Sbapt ret = ucl_strlcpy_unsafe (*dst, src, in_len + 1); 528262395Sbapt } 529262395Sbapt 530262395Sbapt if (need_unescape) { 531262395Sbapt ret = ucl_unescape_json_string (*dst, ret); 532262395Sbapt } 533262395Sbapt if (need_expand) { 534262395Sbapt tmp = *dst; 535262395Sbapt tret = ret; 536262395Sbapt ret = ucl_expand_variable (parser, dst, tmp, ret); 537262395Sbapt if (*dst == NULL) { 538262395Sbapt /* Nothing to expand */ 539262395Sbapt *dst = tmp; 540262395Sbapt ret = tret; 541262395Sbapt } 542275223Sbapt else { 543275223Sbapt /* Free unexpanded value */ 544275223Sbapt UCL_FREE (in_len + 1, tmp); 545275223Sbapt } 546262395Sbapt } 547262395Sbapt *dst_const = *dst; 548262395Sbapt } 549262395Sbapt else { 550262395Sbapt *dst_const = src; 551262395Sbapt ret = in_len; 552262395Sbapt } 553262395Sbapt 554262395Sbapt return ret; 555262395Sbapt} 556262395Sbapt 557262395Sbapt/** 558262395Sbapt * Create and append an object at the specified level 559262395Sbapt * @param parser 560262395Sbapt * @param is_array 561262395Sbapt * @param level 562262395Sbapt * @return 563262395Sbapt */ 564262395Sbaptstatic inline ucl_object_t * 565290071Sbaptucl_parser_add_container (ucl_object_t *obj, struct ucl_parser *parser, 566290071Sbapt bool is_array, int level) 567262395Sbapt{ 568262395Sbapt struct ucl_stack *st; 569262395Sbapt 570262395Sbapt if (!is_array) { 571262395Sbapt if (obj == NULL) { 572275223Sbapt obj = ucl_object_new_full (UCL_OBJECT, parser->chunks->priority); 573262395Sbapt } 574262395Sbapt else { 575262395Sbapt obj->type = UCL_OBJECT; 576262395Sbapt } 577290071Sbapt if (obj->value.ov == NULL) { 578290071Sbapt obj->value.ov = ucl_hash_create (parser->flags & UCL_PARSER_KEY_LOWERCASE); 579290071Sbapt } 580262395Sbapt parser->state = UCL_STATE_KEY; 581262395Sbapt } 582262395Sbapt else { 583262395Sbapt if (obj == NULL) { 584275223Sbapt obj = ucl_object_new_full (UCL_ARRAY, parser->chunks->priority); 585262395Sbapt } 586262395Sbapt else { 587262395Sbapt obj->type = UCL_ARRAY; 588262395Sbapt } 589262395Sbapt parser->state = UCL_STATE_VALUE; 590262395Sbapt } 591262395Sbapt 592262395Sbapt st = UCL_ALLOC (sizeof (struct ucl_stack)); 593263648Sbapt if (st == NULL) { 594290071Sbapt ucl_set_err (parser, UCL_EINTERNAL, "cannot allocate memory for an object", 595275223Sbapt &parser->err); 596275223Sbapt ucl_object_unref (obj); 597263648Sbapt return NULL; 598263648Sbapt } 599262395Sbapt st->obj = obj; 600262395Sbapt st->level = level; 601262395Sbapt LL_PREPEND (parser->stack, st); 602262395Sbapt parser->cur_obj = obj; 603262395Sbapt 604262395Sbapt return obj; 605262395Sbapt} 606262395Sbapt 607262395Sbaptint 608262395Sbaptucl_maybe_parse_number (ucl_object_t *obj, 609263648Sbapt const char *start, const char *end, const char **pos, 610263648Sbapt bool allow_double, bool number_bytes, bool allow_time) 611262395Sbapt{ 612262395Sbapt const char *p = start, *c = start; 613262395Sbapt char *endptr; 614262395Sbapt bool got_dot = false, got_exp = false, need_double = false, 615263648Sbapt is_time = false, valid_start = false, is_hex = false, 616262395Sbapt is_neg = false; 617262395Sbapt double dv = 0; 618262395Sbapt int64_t lv = 0; 619262395Sbapt 620262395Sbapt if (*p == '-') { 621262395Sbapt is_neg = true; 622262395Sbapt c ++; 623262395Sbapt p ++; 624262395Sbapt } 625262395Sbapt while (p < end) { 626262395Sbapt if (is_hex && isxdigit (*p)) { 627262395Sbapt p ++; 628262395Sbapt } 629262395Sbapt else if (isdigit (*p)) { 630262395Sbapt valid_start = true; 631262395Sbapt p ++; 632262395Sbapt } 633262395Sbapt else if (!is_hex && (*p == 'x' || *p == 'X')) { 634262395Sbapt is_hex = true; 635262395Sbapt allow_double = false; 636262395Sbapt c = p + 1; 637262395Sbapt } 638262395Sbapt else if (allow_double) { 639262395Sbapt if (p == c) { 640262395Sbapt /* Empty digits sequence, not a number */ 641262395Sbapt *pos = start; 642262395Sbapt return EINVAL; 643262395Sbapt } 644262395Sbapt else if (*p == '.') { 645262395Sbapt if (got_dot) { 646262395Sbapt /* Double dots, not a number */ 647262395Sbapt *pos = start; 648262395Sbapt return EINVAL; 649262395Sbapt } 650262395Sbapt else { 651262395Sbapt got_dot = true; 652262395Sbapt need_double = true; 653262395Sbapt p ++; 654262395Sbapt } 655262395Sbapt } 656262395Sbapt else if (*p == 'e' || *p == 'E') { 657262395Sbapt if (got_exp) { 658262395Sbapt /* Double exp, not a number */ 659262395Sbapt *pos = start; 660262395Sbapt return EINVAL; 661262395Sbapt } 662262395Sbapt else { 663262395Sbapt got_exp = true; 664262395Sbapt need_double = true; 665262395Sbapt p ++; 666262395Sbapt if (p >= end) { 667262395Sbapt *pos = start; 668262395Sbapt return EINVAL; 669262395Sbapt } 670262395Sbapt if (!isdigit (*p) && *p != '+' && *p != '-') { 671262395Sbapt /* Wrong exponent sign */ 672262395Sbapt *pos = start; 673262395Sbapt return EINVAL; 674262395Sbapt } 675262395Sbapt else { 676262395Sbapt p ++; 677262395Sbapt } 678262395Sbapt } 679262395Sbapt } 680262395Sbapt else { 681262395Sbapt /* Got the end of the number, need to check */ 682262395Sbapt break; 683262395Sbapt } 684262395Sbapt } 685262395Sbapt else { 686262395Sbapt break; 687262395Sbapt } 688262395Sbapt } 689262395Sbapt 690262395Sbapt if (!valid_start) { 691262395Sbapt *pos = start; 692262395Sbapt return EINVAL; 693262395Sbapt } 694262395Sbapt 695262395Sbapt errno = 0; 696262395Sbapt if (need_double) { 697262395Sbapt dv = strtod (c, &endptr); 698262395Sbapt } 699262395Sbapt else { 700262395Sbapt if (is_hex) { 701262395Sbapt lv = strtoimax (c, &endptr, 16); 702262395Sbapt } 703262395Sbapt else { 704262395Sbapt lv = strtoimax (c, &endptr, 10); 705262395Sbapt } 706262395Sbapt } 707262395Sbapt if (errno == ERANGE) { 708262395Sbapt *pos = start; 709262395Sbapt return ERANGE; 710262395Sbapt } 711262395Sbapt 712262395Sbapt /* Now check endptr */ 713275223Sbapt if (endptr == NULL || ucl_lex_is_atom_end (*endptr) || *endptr == '\0') { 714262395Sbapt p = endptr; 715262395Sbapt goto set_obj; 716262395Sbapt } 717262395Sbapt 718262395Sbapt if (endptr < end && endptr != start) { 719262395Sbapt p = endptr; 720262395Sbapt switch (*p) { 721262395Sbapt case 'm': 722262395Sbapt case 'M': 723262395Sbapt case 'g': 724262395Sbapt case 'G': 725262395Sbapt case 'k': 726262395Sbapt case 'K': 727262395Sbapt if (end - p >= 2) { 728262395Sbapt if (p[1] == 's' || p[1] == 'S') { 729262395Sbapt /* Milliseconds */ 730262395Sbapt if (!need_double) { 731262395Sbapt need_double = true; 732262395Sbapt dv = lv; 733262395Sbapt } 734263648Sbapt is_time = true; 735262395Sbapt if (p[0] == 'm' || p[0] == 'M') { 736262395Sbapt dv /= 1000.; 737262395Sbapt } 738262395Sbapt else { 739262395Sbapt dv *= ucl_lex_num_multiplier (*p, false); 740262395Sbapt } 741262395Sbapt p += 2; 742262395Sbapt goto set_obj; 743262395Sbapt } 744262395Sbapt else if (number_bytes || (p[1] == 'b' || p[1] == 'B')) { 745262395Sbapt /* Bytes */ 746262395Sbapt if (need_double) { 747262395Sbapt need_double = false; 748262395Sbapt lv = dv; 749262395Sbapt } 750262395Sbapt lv *= ucl_lex_num_multiplier (*p, true); 751262395Sbapt p += 2; 752262395Sbapt goto set_obj; 753262395Sbapt } 754262395Sbapt else if (ucl_lex_is_atom_end (p[1])) { 755262395Sbapt if (need_double) { 756262395Sbapt dv *= ucl_lex_num_multiplier (*p, false); 757262395Sbapt } 758262395Sbapt else { 759262395Sbapt lv *= ucl_lex_num_multiplier (*p, number_bytes); 760262395Sbapt } 761262395Sbapt p ++; 762262395Sbapt goto set_obj; 763262395Sbapt } 764263648Sbapt else if (allow_time && end - p >= 3) { 765262395Sbapt if (tolower (p[0]) == 'm' && 766262395Sbapt tolower (p[1]) == 'i' && 767262395Sbapt tolower (p[2]) == 'n') { 768262395Sbapt /* Minutes */ 769262395Sbapt if (!need_double) { 770262395Sbapt need_double = true; 771262395Sbapt dv = lv; 772262395Sbapt } 773263648Sbapt is_time = true; 774262395Sbapt dv *= 60.; 775262395Sbapt p += 3; 776262395Sbapt goto set_obj; 777262395Sbapt } 778262395Sbapt } 779262395Sbapt } 780262395Sbapt else { 781262395Sbapt if (need_double) { 782262395Sbapt dv *= ucl_lex_num_multiplier (*p, false); 783262395Sbapt } 784262395Sbapt else { 785262395Sbapt lv *= ucl_lex_num_multiplier (*p, number_bytes); 786262395Sbapt } 787262395Sbapt p ++; 788262395Sbapt goto set_obj; 789262395Sbapt } 790262395Sbapt break; 791262395Sbapt case 'S': 792262395Sbapt case 's': 793263648Sbapt if (allow_time && 794263648Sbapt (p == end - 1 || ucl_lex_is_atom_end (p[1]))) { 795262395Sbapt if (!need_double) { 796262395Sbapt need_double = true; 797262395Sbapt dv = lv; 798262395Sbapt } 799262395Sbapt p ++; 800263648Sbapt is_time = true; 801262395Sbapt goto set_obj; 802262395Sbapt } 803262395Sbapt break; 804262395Sbapt case 'h': 805262395Sbapt case 'H': 806262395Sbapt case 'd': 807262395Sbapt case 'D': 808262395Sbapt case 'w': 809262395Sbapt case 'W': 810262395Sbapt case 'Y': 811262395Sbapt case 'y': 812263648Sbapt if (allow_time && 813263648Sbapt (p == end - 1 || ucl_lex_is_atom_end (p[1]))) { 814262395Sbapt if (!need_double) { 815262395Sbapt need_double = true; 816262395Sbapt dv = lv; 817262395Sbapt } 818263648Sbapt is_time = true; 819262395Sbapt dv *= ucl_lex_time_multiplier (*p); 820262395Sbapt p ++; 821262395Sbapt goto set_obj; 822262395Sbapt } 823262395Sbapt break; 824275223Sbapt case '\t': 825275223Sbapt case ' ': 826275223Sbapt while (p < end && ucl_test_character(*p, UCL_CHARACTER_WHITESPACE)) { 827275223Sbapt p++; 828275223Sbapt } 829275223Sbapt if (ucl_lex_is_atom_end(*p)) 830275223Sbapt goto set_obj; 831275223Sbapt break; 832262395Sbapt } 833262395Sbapt } 834275223Sbapt else if (endptr == end) { 835275223Sbapt /* Just a number at the end of chunk */ 836275223Sbapt p = endptr; 837275223Sbapt goto set_obj; 838275223Sbapt } 839262395Sbapt 840262395Sbapt *pos = c; 841262395Sbapt return EINVAL; 842262395Sbapt 843290071Sbaptset_obj: 844290071Sbapt if (obj != NULL) { 845290071Sbapt if (allow_double && (need_double || is_time)) { 846290071Sbapt if (!is_time) { 847290071Sbapt obj->type = UCL_FLOAT; 848290071Sbapt } 849290071Sbapt else { 850290071Sbapt obj->type = UCL_TIME; 851290071Sbapt } 852290071Sbapt obj->value.dv = is_neg ? (-dv) : dv; 853262395Sbapt } 854262395Sbapt else { 855290071Sbapt obj->type = UCL_INT; 856290071Sbapt obj->value.iv = is_neg ? (-lv) : lv; 857262395Sbapt } 858262395Sbapt } 859262395Sbapt *pos = p; 860262395Sbapt return 0; 861262395Sbapt} 862262395Sbapt 863262395Sbapt/** 864262395Sbapt * Parse possible number 865262395Sbapt * @param parser 866262395Sbapt * @param chunk 867290071Sbapt * @param obj 868262395Sbapt * @return true if a number has been parsed 869262395Sbapt */ 870262395Sbaptstatic bool 871262395Sbaptucl_lex_number (struct ucl_parser *parser, 872262395Sbapt struct ucl_chunk *chunk, ucl_object_t *obj) 873262395Sbapt{ 874262395Sbapt const unsigned char *pos; 875262395Sbapt int ret; 876262395Sbapt 877263648Sbapt ret = ucl_maybe_parse_number (obj, chunk->pos, chunk->end, (const char **)&pos, 878263648Sbapt true, false, ((parser->flags & UCL_PARSER_NO_TIME) == 0)); 879262395Sbapt 880262395Sbapt if (ret == 0) { 881262395Sbapt chunk->remain -= pos - chunk->pos; 882262395Sbapt chunk->column += pos - chunk->pos; 883262395Sbapt chunk->pos = pos; 884262395Sbapt return true; 885262395Sbapt } 886262395Sbapt else if (ret == ERANGE) { 887290071Sbapt ucl_set_err (parser, UCL_ESYNTAX, "numeric value out of range", 888290071Sbapt &parser->err); 889262395Sbapt } 890262395Sbapt 891262395Sbapt return false; 892262395Sbapt} 893262395Sbapt 894262395Sbapt/** 895262395Sbapt * Parse quoted string with possible escapes 896262395Sbapt * @param parser 897262395Sbapt * @param chunk 898290071Sbapt * @param need_unescape 899290071Sbapt * @param ucl_escape 900290071Sbapt * @param var_expand 901262395Sbapt * @return true if a string has been parsed 902262395Sbapt */ 903262395Sbaptstatic bool 904262395Sbaptucl_lex_json_string (struct ucl_parser *parser, 905262395Sbapt struct ucl_chunk *chunk, bool *need_unescape, bool *ucl_escape, bool *var_expand) 906262395Sbapt{ 907262395Sbapt const unsigned char *p = chunk->pos; 908262395Sbapt unsigned char c; 909262395Sbapt int i; 910262395Sbapt 911262395Sbapt while (p < chunk->end) { 912262395Sbapt c = *p; 913262395Sbapt if (c < 0x1F) { 914262395Sbapt /* Unmasked control character */ 915262395Sbapt if (c == '\n') { 916275223Sbapt ucl_set_err (parser, UCL_ESYNTAX, "unexpected newline", 917275223Sbapt &parser->err); 918262395Sbapt } 919262395Sbapt else { 920275223Sbapt ucl_set_err (parser, UCL_ESYNTAX, "unexpected control character", 921275223Sbapt &parser->err); 922262395Sbapt } 923262395Sbapt return false; 924262395Sbapt } 925262395Sbapt else if (c == '\\') { 926262395Sbapt ucl_chunk_skipc (chunk, p); 927262395Sbapt c = *p; 928262395Sbapt if (p >= chunk->end) { 929275223Sbapt ucl_set_err (parser, UCL_ESYNTAX, "unfinished escape character", 930275223Sbapt &parser->err); 931262395Sbapt return false; 932262395Sbapt } 933262395Sbapt else if (ucl_test_character (c, UCL_CHARACTER_ESCAPE)) { 934262395Sbapt if (c == 'u') { 935262395Sbapt ucl_chunk_skipc (chunk, p); 936262395Sbapt for (i = 0; i < 4 && p < chunk->end; i ++) { 937262395Sbapt if (!isxdigit (*p)) { 938275223Sbapt ucl_set_err (parser, UCL_ESYNTAX, "invalid utf escape", 939275223Sbapt &parser->err); 940262395Sbapt return false; 941262395Sbapt } 942262395Sbapt ucl_chunk_skipc (chunk, p); 943262395Sbapt } 944262395Sbapt if (p >= chunk->end) { 945275223Sbapt ucl_set_err (parser, UCL_ESYNTAX, "unfinished escape character", 946275223Sbapt &parser->err); 947262395Sbapt return false; 948262395Sbapt } 949262395Sbapt } 950262395Sbapt else { 951262395Sbapt ucl_chunk_skipc (chunk, p); 952262395Sbapt } 953262395Sbapt } 954262395Sbapt *need_unescape = true; 955262395Sbapt *ucl_escape = true; 956262395Sbapt continue; 957262395Sbapt } 958262395Sbapt else if (c == '"') { 959262395Sbapt ucl_chunk_skipc (chunk, p); 960262395Sbapt return true; 961262395Sbapt } 962262395Sbapt else if (ucl_test_character (c, UCL_CHARACTER_UCL_UNSAFE)) { 963262395Sbapt *ucl_escape = true; 964262395Sbapt } 965262395Sbapt else if (c == '$') { 966262395Sbapt *var_expand = true; 967262395Sbapt } 968262395Sbapt ucl_chunk_skipc (chunk, p); 969262395Sbapt } 970262395Sbapt 971275223Sbapt ucl_set_err (parser, UCL_ESYNTAX, "no quote at the end of json string", 972275223Sbapt &parser->err); 973262395Sbapt return false; 974262395Sbapt} 975262395Sbapt 976275223Sbaptstatic void 977275223Sbaptucl_parser_append_elt (struct ucl_parser *parser, ucl_hash_t *cont, 978275223Sbapt ucl_object_t *top, 979275223Sbapt ucl_object_t *elt) 980275223Sbapt{ 981275223Sbapt ucl_object_t *nobj; 982275223Sbapt 983275223Sbapt if ((parser->flags & UCL_PARSER_NO_IMPLICIT_ARRAYS) == 0) { 984275223Sbapt /* Implicit array */ 985275223Sbapt top->flags |= UCL_OBJECT_MULTIVALUE; 986275223Sbapt DL_APPEND (top, elt); 987290071Sbapt parser->stack->obj->len ++; 988275223Sbapt } 989275223Sbapt else { 990275223Sbapt if ((top->flags & UCL_OBJECT_MULTIVALUE) != 0) { 991275223Sbapt /* Just add to the explicit array */ 992279549Sbapt ucl_array_append (top, elt); 993275223Sbapt } 994275223Sbapt else { 995275223Sbapt /* Convert to an array */ 996275223Sbapt nobj = ucl_object_typed_new (UCL_ARRAY); 997275223Sbapt nobj->key = top->key; 998275223Sbapt nobj->keylen = top->keylen; 999275223Sbapt nobj->flags |= UCL_OBJECT_MULTIVALUE; 1000279549Sbapt ucl_array_append (nobj, top); 1001279549Sbapt ucl_array_append (nobj, elt); 1002290071Sbapt ucl_hash_replace (cont, top, nobj); 1003275223Sbapt } 1004275223Sbapt } 1005275223Sbapt} 1006275223Sbapt 1007290071Sbaptbool 1008290071Sbaptucl_parser_process_object_element (struct ucl_parser *parser, ucl_object_t *nobj) 1009290071Sbapt{ 1010290071Sbapt ucl_hash_t *container; 1011290071Sbapt ucl_object_t *tobj; 1012290071Sbapt 1013290071Sbapt container = parser->stack->obj->value.ov; 1014290071Sbapt 1015290071Sbapt tobj = __DECONST (ucl_object_t *, ucl_hash_search_obj (container, nobj)); 1016290071Sbapt if (tobj == NULL) { 1017290071Sbapt container = ucl_hash_insert_object (container, nobj, 1018290071Sbapt parser->flags & UCL_PARSER_KEY_LOWERCASE); 1019290071Sbapt nobj->prev = nobj; 1020290071Sbapt nobj->next = NULL; 1021290071Sbapt parser->stack->obj->len ++; 1022290071Sbapt } 1023290071Sbapt else { 1024290071Sbapt unsigned priold = ucl_object_get_priority (tobj), 1025290071Sbapt prinew = ucl_object_get_priority (nobj); 1026290071Sbapt switch (parser->chunks->strategy) { 1027290071Sbapt 1028290071Sbapt case UCL_DUPLICATE_APPEND: 1029290071Sbapt /* 1030290071Sbapt * The logic here is the following: 1031290071Sbapt * 1032290071Sbapt * - if we have two objects with the same priority, then we form an 1033290071Sbapt * implicit or explicit array 1034290071Sbapt * - if a new object has bigger priority, then we overwrite an old one 1035290071Sbapt * - if a new object has lower priority, then we ignore it 1036290071Sbapt */ 1037290071Sbapt 1038290071Sbapt 1039290071Sbapt /* Special case for inherited objects */ 1040290071Sbapt if (tobj->flags & UCL_OBJECT_INHERITED) { 1041290071Sbapt prinew = priold + 1; 1042290071Sbapt } 1043290071Sbapt 1044290071Sbapt if (priold == prinew) { 1045290071Sbapt ucl_parser_append_elt (parser, container, tobj, nobj); 1046290071Sbapt } 1047290071Sbapt else if (priold > prinew) { 1048290071Sbapt /* 1049290071Sbapt * We add this new object to a list of trash objects just to ensure 1050290071Sbapt * that it won't come to any real object 1051290071Sbapt * XXX: rather inefficient approach 1052290071Sbapt */ 1053290071Sbapt DL_APPEND (parser->trash_objs, nobj); 1054290071Sbapt } 1055290071Sbapt else { 1056290071Sbapt ucl_hash_replace (container, tobj, nobj); 1057290071Sbapt ucl_object_unref (tobj); 1058290071Sbapt } 1059290071Sbapt 1060290071Sbapt break; 1061290071Sbapt 1062290071Sbapt case UCL_DUPLICATE_REWRITE: 1063290071Sbapt /* We just rewrite old values regardless of priority */ 1064290071Sbapt ucl_hash_replace (container, tobj, nobj); 1065290071Sbapt ucl_object_unref (tobj); 1066290071Sbapt 1067290071Sbapt break; 1068290071Sbapt 1069290071Sbapt case UCL_DUPLICATE_ERROR: 1070290071Sbapt ucl_create_err (&parser->err, "error while parsing %s: " 1071290071Sbapt "line: %d, column: %d: duplicate element for key '%s' " 1072290071Sbapt "has been found", 1073290071Sbapt parser->cur_file ? parser->cur_file : "<unknown>", 1074290071Sbapt parser->chunks->line, parser->chunks->column, nobj->key); 1075290071Sbapt return false; 1076290071Sbapt 1077290071Sbapt case UCL_DUPLICATE_MERGE: 1078290071Sbapt /* 1079290071Sbapt * Here we do have some old object so we just push it on top of objects stack 1080290071Sbapt */ 1081290071Sbapt if (tobj->type == UCL_OBJECT || tobj->type == UCL_ARRAY) { 1082290071Sbapt ucl_object_unref (nobj); 1083290071Sbapt nobj = tobj; 1084290071Sbapt } 1085290071Sbapt else { 1086290071Sbapt /* For other types we create implicit array as usual */ 1087290071Sbapt ucl_parser_append_elt (parser, container, tobj, nobj); 1088290071Sbapt } 1089290071Sbapt break; 1090290071Sbapt } 1091290071Sbapt } 1092290071Sbapt 1093290071Sbapt parser->stack->obj->value.ov = container; 1094290071Sbapt parser->cur_obj = nobj; 1095290071Sbapt 1096290071Sbapt return true; 1097290071Sbapt} 1098290071Sbapt 1099262395Sbapt/** 1100262395Sbapt * Parse a key in an object 1101262395Sbapt * @param parser 1102262395Sbapt * @param chunk 1103290071Sbapt * @param next_key 1104290071Sbapt * @param end_of_object 1105262395Sbapt * @return true if a key has been parsed 1106262395Sbapt */ 1107262395Sbaptstatic bool 1108290071Sbaptucl_parse_key (struct ucl_parser *parser, struct ucl_chunk *chunk, 1109290071Sbapt bool *next_key, bool *end_of_object) 1110262395Sbapt{ 1111262395Sbapt const unsigned char *p, *c = NULL, *end, *t; 1112262395Sbapt const char *key = NULL; 1113262395Sbapt bool got_quote = false, got_eq = false, got_semicolon = false, 1114262395Sbapt need_unescape = false, ucl_escape = false, var_expand = false, 1115262395Sbapt got_content = false, got_sep = false; 1116290071Sbapt ucl_object_t *nobj; 1117262395Sbapt ssize_t keylen; 1118262395Sbapt 1119262395Sbapt p = chunk->pos; 1120262395Sbapt 1121262395Sbapt if (*p == '.') { 1122262395Sbapt /* It is macro actually */ 1123262395Sbapt ucl_chunk_skipc (chunk, p); 1124262395Sbapt parser->prev_state = parser->state; 1125262395Sbapt parser->state = UCL_STATE_MACRO_NAME; 1126279549Sbapt *end_of_object = false; 1127262395Sbapt return true; 1128262395Sbapt } 1129262395Sbapt while (p < chunk->end) { 1130262395Sbapt /* 1131262395Sbapt * A key must start with alpha, number, '/' or '_' and end with space character 1132262395Sbapt */ 1133262395Sbapt if (c == NULL) { 1134262395Sbapt if (chunk->remain >= 2 && ucl_lex_is_comment (p[0], p[1])) { 1135262395Sbapt if (!ucl_skip_comments (parser)) { 1136262395Sbapt return false; 1137262395Sbapt } 1138262395Sbapt p = chunk->pos; 1139262395Sbapt } 1140262395Sbapt else if (ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE)) { 1141262395Sbapt ucl_chunk_skipc (chunk, p); 1142262395Sbapt } 1143262395Sbapt else if (ucl_test_character (*p, UCL_CHARACTER_KEY_START)) { 1144262395Sbapt /* The first symbol */ 1145262395Sbapt c = p; 1146262395Sbapt ucl_chunk_skipc (chunk, p); 1147262395Sbapt got_content = true; 1148262395Sbapt } 1149262395Sbapt else if (*p == '"') { 1150262395Sbapt /* JSON style key */ 1151262395Sbapt c = p + 1; 1152262395Sbapt got_quote = true; 1153262395Sbapt got_content = true; 1154262395Sbapt ucl_chunk_skipc (chunk, p); 1155262395Sbapt } 1156262395Sbapt else if (*p == '}') { 1157262395Sbapt /* We have actually end of an object */ 1158262395Sbapt *end_of_object = true; 1159262395Sbapt return true; 1160262395Sbapt } 1161262395Sbapt else if (*p == '.') { 1162262395Sbapt ucl_chunk_skipc (chunk, p); 1163262395Sbapt parser->prev_state = parser->state; 1164262395Sbapt parser->state = UCL_STATE_MACRO_NAME; 1165262395Sbapt return true; 1166262395Sbapt } 1167262395Sbapt else { 1168262395Sbapt /* Invalid identifier */ 1169275223Sbapt ucl_set_err (parser, UCL_ESYNTAX, "key must begin with a letter", 1170275223Sbapt &parser->err); 1171262395Sbapt return false; 1172262395Sbapt } 1173262395Sbapt } 1174262395Sbapt else { 1175262395Sbapt /* Parse the body of a key */ 1176262395Sbapt if (!got_quote) { 1177262395Sbapt if (ucl_test_character (*p, UCL_CHARACTER_KEY)) { 1178262395Sbapt got_content = true; 1179262395Sbapt ucl_chunk_skipc (chunk, p); 1180262395Sbapt } 1181262395Sbapt else if (ucl_test_character (*p, UCL_CHARACTER_KEY_SEP)) { 1182262395Sbapt end = p; 1183262395Sbapt break; 1184262395Sbapt } 1185262395Sbapt else { 1186275223Sbapt ucl_set_err (parser, UCL_ESYNTAX, "invalid character in a key", 1187275223Sbapt &parser->err); 1188262395Sbapt return false; 1189262395Sbapt } 1190262395Sbapt } 1191262395Sbapt else { 1192262395Sbapt /* We need to parse json like quoted string */ 1193262395Sbapt if (!ucl_lex_json_string (parser, chunk, &need_unescape, &ucl_escape, &var_expand)) { 1194262395Sbapt return false; 1195262395Sbapt } 1196262395Sbapt /* Always escape keys obtained via json */ 1197262395Sbapt end = chunk->pos - 1; 1198262395Sbapt p = chunk->pos; 1199262395Sbapt break; 1200262395Sbapt } 1201262395Sbapt } 1202262395Sbapt } 1203262395Sbapt 1204262395Sbapt if (p >= chunk->end && got_content) { 1205275223Sbapt ucl_set_err (parser, UCL_ESYNTAX, "unfinished key", &parser->err); 1206262395Sbapt return false; 1207262395Sbapt } 1208262395Sbapt else if (!got_content) { 1209262395Sbapt return true; 1210262395Sbapt } 1211262395Sbapt *end_of_object = false; 1212262395Sbapt /* We are now at the end of the key, need to parse the rest */ 1213262395Sbapt while (p < chunk->end) { 1214262395Sbapt if (ucl_test_character (*p, UCL_CHARACTER_WHITESPACE)) { 1215262395Sbapt ucl_chunk_skipc (chunk, p); 1216262395Sbapt } 1217262395Sbapt else if (*p == '=') { 1218262395Sbapt if (!got_eq && !got_semicolon) { 1219262395Sbapt ucl_chunk_skipc (chunk, p); 1220262395Sbapt got_eq = true; 1221262395Sbapt } 1222262395Sbapt else { 1223275223Sbapt ucl_set_err (parser, UCL_ESYNTAX, "unexpected '=' character", 1224275223Sbapt &parser->err); 1225262395Sbapt return false; 1226262395Sbapt } 1227262395Sbapt } 1228262395Sbapt else if (*p == ':') { 1229262395Sbapt if (!got_eq && !got_semicolon) { 1230262395Sbapt ucl_chunk_skipc (chunk, p); 1231262395Sbapt got_semicolon = true; 1232262395Sbapt } 1233262395Sbapt else { 1234275223Sbapt ucl_set_err (parser, UCL_ESYNTAX, "unexpected ':' character", 1235275223Sbapt &parser->err); 1236262395Sbapt return false; 1237262395Sbapt } 1238262395Sbapt } 1239262395Sbapt else if (chunk->remain >= 2 && ucl_lex_is_comment (p[0], p[1])) { 1240262395Sbapt /* Check for comment */ 1241262395Sbapt if (!ucl_skip_comments (parser)) { 1242262395Sbapt return false; 1243262395Sbapt } 1244262395Sbapt p = chunk->pos; 1245262395Sbapt } 1246262395Sbapt else { 1247262395Sbapt /* Start value */ 1248262395Sbapt break; 1249262395Sbapt } 1250262395Sbapt } 1251262395Sbapt 1252262395Sbapt if (p >= chunk->end && got_content) { 1253275223Sbapt ucl_set_err (parser, UCL_ESYNTAX, "unfinished key", &parser->err); 1254262395Sbapt return false; 1255262395Sbapt } 1256262395Sbapt 1257262395Sbapt got_sep = got_semicolon || got_eq; 1258262395Sbapt 1259262395Sbapt if (!got_sep) { 1260262395Sbapt /* 1261262395Sbapt * Maybe we have more keys nested, so search for termination character. 1262262395Sbapt * Possible choices: 1263262395Sbapt * 1) key1 key2 ... keyN [:=] value <- we treat that as error 1264262395Sbapt * 2) key1 ... keyN {} or [] <- we treat that as nested objects 1265262395Sbapt * 3) key1 value[;,\n] <- we treat that as linear object 1266262395Sbapt */ 1267262395Sbapt t = p; 1268262395Sbapt *next_key = false; 1269262395Sbapt while (ucl_test_character (*t, UCL_CHARACTER_WHITESPACE)) { 1270262395Sbapt t ++; 1271262395Sbapt } 1272262395Sbapt /* Check first non-space character after a key */ 1273262395Sbapt if (*t != '{' && *t != '[') { 1274262395Sbapt while (t < chunk->end) { 1275262395Sbapt if (*t == ',' || *t == ';' || *t == '\n' || *t == '\r') { 1276262395Sbapt break; 1277262395Sbapt } 1278262395Sbapt else if (*t == '{' || *t == '[') { 1279262395Sbapt *next_key = true; 1280262395Sbapt break; 1281262395Sbapt } 1282262395Sbapt t ++; 1283262395Sbapt } 1284262395Sbapt } 1285262395Sbapt } 1286262395Sbapt 1287262395Sbapt /* Create a new object */ 1288275223Sbapt nobj = ucl_object_new_full (UCL_NULL, parser->chunks->priority); 1289262395Sbapt keylen = ucl_copy_or_store_ptr (parser, c, &nobj->trash_stack[UCL_TRASH_KEY], 1290262395Sbapt &key, end - c, need_unescape, parser->flags & UCL_PARSER_KEY_LOWERCASE, false); 1291262395Sbapt if (keylen == -1) { 1292264789Sbapt ucl_object_unref (nobj); 1293262395Sbapt return false; 1294262395Sbapt } 1295262395Sbapt else if (keylen == 0) { 1296275223Sbapt ucl_set_err (parser, UCL_ESYNTAX, "empty keys are not allowed", &parser->err); 1297264789Sbapt ucl_object_unref (nobj); 1298262395Sbapt return false; 1299262395Sbapt } 1300262395Sbapt 1301262395Sbapt nobj->key = key; 1302262395Sbapt nobj->keylen = keylen; 1303290071Sbapt 1304290071Sbapt if (!ucl_parser_process_object_element (parser, nobj)) { 1305290071Sbapt return false; 1306262395Sbapt } 1307262395Sbapt 1308262395Sbapt if (ucl_escape) { 1309262395Sbapt nobj->flags |= UCL_OBJECT_NEED_KEY_ESCAPE; 1310262395Sbapt } 1311262395Sbapt 1312262395Sbapt 1313262395Sbapt return true; 1314262395Sbapt} 1315262395Sbapt 1316262395Sbapt/** 1317262395Sbapt * Parse a cl string 1318262395Sbapt * @param parser 1319262395Sbapt * @param chunk 1320290071Sbapt * @param var_expand 1321290071Sbapt * @param need_unescape 1322262395Sbapt * @return true if a key has been parsed 1323262395Sbapt */ 1324262395Sbaptstatic bool 1325262395Sbaptucl_parse_string_value (struct ucl_parser *parser, 1326262395Sbapt struct ucl_chunk *chunk, bool *var_expand, bool *need_unescape) 1327262395Sbapt{ 1328262395Sbapt const unsigned char *p; 1329262395Sbapt enum { 1330262395Sbapt UCL_BRACE_ROUND = 0, 1331262395Sbapt UCL_BRACE_SQUARE, 1332262395Sbapt UCL_BRACE_FIGURE 1333262395Sbapt }; 1334262395Sbapt int braces[3][2] = {{0, 0}, {0, 0}, {0, 0}}; 1335262395Sbapt 1336262395Sbapt p = chunk->pos; 1337262395Sbapt 1338262395Sbapt while (p < chunk->end) { 1339262395Sbapt 1340262395Sbapt /* Skip pairs of figure braces */ 1341262395Sbapt if (*p == '{') { 1342262395Sbapt braces[UCL_BRACE_FIGURE][0] ++; 1343262395Sbapt } 1344262395Sbapt else if (*p == '}') { 1345262395Sbapt braces[UCL_BRACE_FIGURE][1] ++; 1346262395Sbapt if (braces[UCL_BRACE_FIGURE][1] <= braces[UCL_BRACE_FIGURE][0]) { 1347262395Sbapt /* This is not a termination symbol, continue */ 1348262395Sbapt ucl_chunk_skipc (chunk, p); 1349262395Sbapt continue; 1350262395Sbapt } 1351262395Sbapt } 1352262395Sbapt /* Skip pairs of square braces */ 1353262395Sbapt else if (*p == '[') { 1354262395Sbapt braces[UCL_BRACE_SQUARE][0] ++; 1355262395Sbapt } 1356262395Sbapt else if (*p == ']') { 1357262395Sbapt braces[UCL_BRACE_SQUARE][1] ++; 1358262395Sbapt if (braces[UCL_BRACE_SQUARE][1] <= braces[UCL_BRACE_SQUARE][0]) { 1359262395Sbapt /* This is not a termination symbol, continue */ 1360262395Sbapt ucl_chunk_skipc (chunk, p); 1361262395Sbapt continue; 1362262395Sbapt } 1363262395Sbapt } 1364262395Sbapt else if (*p == '$') { 1365262395Sbapt *var_expand = true; 1366262395Sbapt } 1367262395Sbapt else if (*p == '\\') { 1368262395Sbapt *need_unescape = true; 1369262395Sbapt ucl_chunk_skipc (chunk, p); 1370262395Sbapt if (p < chunk->end) { 1371262395Sbapt ucl_chunk_skipc (chunk, p); 1372262395Sbapt } 1373262395Sbapt continue; 1374262395Sbapt } 1375262395Sbapt 1376262395Sbapt if (ucl_lex_is_atom_end (*p) || (chunk->remain >= 2 && ucl_lex_is_comment (p[0], p[1]))) { 1377262395Sbapt break; 1378262395Sbapt } 1379262395Sbapt ucl_chunk_skipc (chunk, p); 1380262395Sbapt } 1381262395Sbapt 1382262395Sbapt return true; 1383262395Sbapt} 1384262395Sbapt 1385262395Sbapt/** 1386262395Sbapt * Parse multiline string ending with \n{term}\n 1387262395Sbapt * @param parser 1388262395Sbapt * @param chunk 1389262395Sbapt * @param term 1390262395Sbapt * @param term_len 1391290071Sbapt * @param beg 1392290071Sbapt * @param var_expand 1393262395Sbapt * @return size of multiline string or 0 in case of error 1394262395Sbapt */ 1395262395Sbaptstatic int 1396262395Sbaptucl_parse_multiline_string (struct ucl_parser *parser, 1397262395Sbapt struct ucl_chunk *chunk, const unsigned char *term, 1398262395Sbapt int term_len, unsigned char const **beg, 1399262395Sbapt bool *var_expand) 1400262395Sbapt{ 1401275223Sbapt const unsigned char *p, *c, *tend; 1402262395Sbapt bool newline = false; 1403262395Sbapt int len = 0; 1404262395Sbapt 1405262395Sbapt p = chunk->pos; 1406262395Sbapt 1407262395Sbapt c = p; 1408262395Sbapt 1409262395Sbapt while (p < chunk->end) { 1410262395Sbapt if (newline) { 1411262395Sbapt if (chunk->end - p < term_len) { 1412262395Sbapt return 0; 1413262395Sbapt } 1414275223Sbapt else if (memcmp (p, term, term_len) == 0) { 1415275223Sbapt tend = p + term_len; 1416275223Sbapt if (*tend != '\n' && *tend != ';' && *tend != ',') { 1417275223Sbapt /* Incomplete terminator */ 1418275223Sbapt ucl_chunk_skipc (chunk, p); 1419275223Sbapt continue; 1420275223Sbapt } 1421262395Sbapt len = p - c; 1422262395Sbapt chunk->remain -= term_len; 1423262395Sbapt chunk->pos = p + term_len; 1424262395Sbapt chunk->column = term_len; 1425262395Sbapt *beg = c; 1426262395Sbapt break; 1427262395Sbapt } 1428262395Sbapt } 1429262395Sbapt if (*p == '\n') { 1430262395Sbapt newline = true; 1431262395Sbapt } 1432262395Sbapt else { 1433262395Sbapt if (*p == '$') { 1434262395Sbapt *var_expand = true; 1435262395Sbapt } 1436262395Sbapt newline = false; 1437262395Sbapt } 1438262395Sbapt ucl_chunk_skipc (chunk, p); 1439262395Sbapt } 1440262395Sbapt 1441262395Sbapt return len; 1442262395Sbapt} 1443262395Sbapt 1444290071Sbaptstatic inline ucl_object_t* 1445290071Sbaptucl_parser_get_container (struct ucl_parser *parser) 1446262975Sbapt{ 1447262975Sbapt ucl_object_t *t, *obj = NULL; 1448262975Sbapt 1449279549Sbapt if (parser == NULL || parser->stack == NULL || parser->stack->obj == NULL) { 1450279549Sbapt return NULL; 1451279549Sbapt } 1452279549Sbapt 1453262975Sbapt if (parser->stack->obj->type == UCL_ARRAY) { 1454262975Sbapt /* Object must be allocated */ 1455275223Sbapt obj = ucl_object_new_full (UCL_NULL, parser->chunks->priority); 1456279549Sbapt t = parser->stack->obj; 1457290071Sbapt 1458290071Sbapt if (!ucl_array_append (t, obj)) { 1459290071Sbapt ucl_object_unref (obj); 1460290071Sbapt return NULL; 1461290071Sbapt } 1462290071Sbapt 1463262975Sbapt parser->cur_obj = obj; 1464262975Sbapt } 1465262975Sbapt else { 1466262975Sbapt /* Object has been already allocated */ 1467262975Sbapt obj = parser->cur_obj; 1468262975Sbapt } 1469262975Sbapt 1470262975Sbapt return obj; 1471262975Sbapt} 1472262975Sbapt 1473262395Sbapt/** 1474262395Sbapt * Handle value data 1475262395Sbapt * @param parser 1476262395Sbapt * @param chunk 1477262395Sbapt * @return 1478262395Sbapt */ 1479262395Sbaptstatic bool 1480262395Sbaptucl_parse_value (struct ucl_parser *parser, struct ucl_chunk *chunk) 1481262395Sbapt{ 1482262395Sbapt const unsigned char *p, *c; 1483262975Sbapt ucl_object_t *obj = NULL; 1484262395Sbapt unsigned int stripped_spaces; 1485262395Sbapt int str_len; 1486262395Sbapt bool need_unescape = false, ucl_escape = false, var_expand = false; 1487262395Sbapt 1488262395Sbapt p = chunk->pos; 1489262395Sbapt 1490262975Sbapt /* Skip any spaces and comments */ 1491262975Sbapt if (ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE) || 1492262975Sbapt (chunk->remain >= 2 && ucl_lex_is_comment (p[0], p[1]))) { 1493262975Sbapt while (p < chunk->end && ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE)) { 1494262975Sbapt ucl_chunk_skipc (chunk, p); 1495262975Sbapt } 1496262975Sbapt if (!ucl_skip_comments (parser)) { 1497262975Sbapt return false; 1498262975Sbapt } 1499262975Sbapt p = chunk->pos; 1500262975Sbapt } 1501262975Sbapt 1502262395Sbapt while (p < chunk->end) { 1503262395Sbapt c = p; 1504262395Sbapt switch (*p) { 1505262395Sbapt case '"': 1506262395Sbapt ucl_chunk_skipc (chunk, p); 1507290071Sbapt 1508290071Sbapt if (!ucl_lex_json_string (parser, chunk, &need_unescape, &ucl_escape, 1509290071Sbapt &var_expand)) { 1510262395Sbapt return false; 1511262395Sbapt } 1512290071Sbapt 1513290071Sbapt obj = ucl_parser_get_container (parser); 1514262395Sbapt str_len = chunk->pos - c - 2; 1515262395Sbapt obj->type = UCL_STRING; 1516290071Sbapt if ((str_len = ucl_copy_or_store_ptr (parser, c + 1, 1517290071Sbapt &obj->trash_stack[UCL_TRASH_VALUE], 1518290071Sbapt &obj->value.sv, str_len, need_unescape, false, 1519290071Sbapt var_expand)) == -1) { 1520262395Sbapt return false; 1521262395Sbapt } 1522262395Sbapt obj->len = str_len; 1523290071Sbapt 1524262395Sbapt parser->state = UCL_STATE_AFTER_VALUE; 1525262395Sbapt p = chunk->pos; 1526290071Sbapt 1527262395Sbapt return true; 1528262395Sbapt break; 1529262395Sbapt case '{': 1530290071Sbapt obj = ucl_parser_get_container (parser); 1531262395Sbapt /* We have a new object */ 1532290071Sbapt obj = ucl_parser_add_container (obj, parser, false, parser->stack->level); 1533263648Sbapt if (obj == NULL) { 1534263648Sbapt return false; 1535263648Sbapt } 1536262395Sbapt 1537262395Sbapt ucl_chunk_skipc (chunk, p); 1538290071Sbapt 1539262395Sbapt return true; 1540262395Sbapt break; 1541262395Sbapt case '[': 1542290071Sbapt obj = ucl_parser_get_container (parser); 1543262395Sbapt /* We have a new array */ 1544290071Sbapt obj = ucl_parser_add_container (obj, parser, true, parser->stack->level); 1545263648Sbapt if (obj == NULL) { 1546263648Sbapt return false; 1547263648Sbapt } 1548262395Sbapt 1549262395Sbapt ucl_chunk_skipc (chunk, p); 1550290071Sbapt 1551262395Sbapt return true; 1552262395Sbapt break; 1553262975Sbapt case ']': 1554262975Sbapt /* We have the array ending */ 1555262975Sbapt if (parser->stack && parser->stack->obj->type == UCL_ARRAY) { 1556262975Sbapt parser->state = UCL_STATE_AFTER_VALUE; 1557262975Sbapt return true; 1558262975Sbapt } 1559262975Sbapt else { 1560262975Sbapt goto parse_string; 1561262975Sbapt } 1562262975Sbapt break; 1563262395Sbapt case '<': 1564290071Sbapt obj = ucl_parser_get_container (parser); 1565262395Sbapt /* We have something like multiline value, which must be <<[A-Z]+\n */ 1566262395Sbapt if (chunk->end - p > 3) { 1567262395Sbapt if (memcmp (p, "<<", 2) == 0) { 1568262395Sbapt p += 2; 1569262395Sbapt /* We allow only uppercase characters in multiline definitions */ 1570262395Sbapt while (p < chunk->end && *p >= 'A' && *p <= 'Z') { 1571262395Sbapt p ++; 1572262395Sbapt } 1573262395Sbapt if (*p =='\n') { 1574262395Sbapt /* Set chunk positions and start multiline parsing */ 1575262395Sbapt c += 2; 1576262395Sbapt chunk->remain -= p - c; 1577262395Sbapt chunk->pos = p + 1; 1578262395Sbapt chunk->column = 0; 1579262395Sbapt chunk->line ++; 1580262395Sbapt if ((str_len = ucl_parse_multiline_string (parser, chunk, c, 1581262395Sbapt p - c, &c, &var_expand)) == 0) { 1582275223Sbapt ucl_set_err (parser, UCL_ESYNTAX, 1583275223Sbapt "unterminated multiline value", &parser->err); 1584262395Sbapt return false; 1585262395Sbapt } 1586290071Sbapt 1587262395Sbapt obj->type = UCL_STRING; 1588290071Sbapt obj->flags |= UCL_OBJECT_MULTILINE; 1589290071Sbapt if ((str_len = ucl_copy_or_store_ptr (parser, c, 1590290071Sbapt &obj->trash_stack[UCL_TRASH_VALUE], 1591290071Sbapt &obj->value.sv, str_len - 1, false, 1592290071Sbapt false, var_expand)) == -1) { 1593262395Sbapt return false; 1594262395Sbapt } 1595262395Sbapt obj->len = str_len; 1596290071Sbapt 1597262395Sbapt parser->state = UCL_STATE_AFTER_VALUE; 1598290071Sbapt 1599262395Sbapt return true; 1600262395Sbapt } 1601262395Sbapt } 1602262395Sbapt } 1603262395Sbapt /* Fallback to ordinary strings */ 1604262395Sbapt default: 1605262975Sbaptparse_string: 1606262975Sbapt if (obj == NULL) { 1607290071Sbapt obj = ucl_parser_get_container (parser); 1608262395Sbapt } 1609290071Sbapt 1610262395Sbapt /* Parse atom */ 1611262395Sbapt if (ucl_test_character (*p, UCL_CHARACTER_VALUE_DIGIT_START)) { 1612262395Sbapt if (!ucl_lex_number (parser, chunk, obj)) { 1613262395Sbapt if (parser->state == UCL_STATE_ERROR) { 1614262395Sbapt return false; 1615262395Sbapt } 1616262395Sbapt } 1617262395Sbapt else { 1618262395Sbapt parser->state = UCL_STATE_AFTER_VALUE; 1619262395Sbapt return true; 1620262395Sbapt } 1621262395Sbapt /* Fallback to normal string */ 1622262395Sbapt } 1623262395Sbapt 1624290071Sbapt if (!ucl_parse_string_value (parser, chunk, &var_expand, 1625290071Sbapt &need_unescape)) { 1626262395Sbapt return false; 1627262395Sbapt } 1628262395Sbapt /* Cut trailing spaces */ 1629262395Sbapt stripped_spaces = 0; 1630262395Sbapt while (ucl_test_character (*(chunk->pos - 1 - stripped_spaces), 1631262395Sbapt UCL_CHARACTER_WHITESPACE)) { 1632262395Sbapt stripped_spaces ++; 1633262395Sbapt } 1634262395Sbapt str_len = chunk->pos - c - stripped_spaces; 1635262395Sbapt if (str_len <= 0) { 1636290071Sbapt ucl_set_err (parser, UCL_ESYNTAX, "string value must not be empty", 1637275223Sbapt &parser->err); 1638262395Sbapt return false; 1639262395Sbapt } 1640262395Sbapt else if (str_len == 4 && memcmp (c, "null", 4) == 0) { 1641262395Sbapt obj->len = 0; 1642262395Sbapt obj->type = UCL_NULL; 1643262395Sbapt } 1644262395Sbapt else if (!ucl_maybe_parse_boolean (obj, c, str_len)) { 1645262395Sbapt obj->type = UCL_STRING; 1646290071Sbapt if ((str_len = ucl_copy_or_store_ptr (parser, c, 1647290071Sbapt &obj->trash_stack[UCL_TRASH_VALUE], 1648262395Sbapt &obj->value.sv, str_len, need_unescape, 1649262395Sbapt false, var_expand)) == -1) { 1650262395Sbapt return false; 1651262395Sbapt } 1652262395Sbapt obj->len = str_len; 1653262395Sbapt } 1654262395Sbapt parser->state = UCL_STATE_AFTER_VALUE; 1655262395Sbapt p = chunk->pos; 1656262395Sbapt 1657262395Sbapt return true; 1658262395Sbapt break; 1659262395Sbapt } 1660262395Sbapt } 1661262395Sbapt 1662262395Sbapt return true; 1663262395Sbapt} 1664262395Sbapt 1665262395Sbapt/** 1666262395Sbapt * Handle after value data 1667262395Sbapt * @param parser 1668262395Sbapt * @param chunk 1669262395Sbapt * @return 1670262395Sbapt */ 1671262395Sbaptstatic bool 1672262395Sbaptucl_parse_after_value (struct ucl_parser *parser, struct ucl_chunk *chunk) 1673262395Sbapt{ 1674262395Sbapt const unsigned char *p; 1675262395Sbapt bool got_sep = false; 1676262395Sbapt struct ucl_stack *st; 1677262395Sbapt 1678262395Sbapt p = chunk->pos; 1679262395Sbapt 1680262395Sbapt while (p < chunk->end) { 1681262395Sbapt if (ucl_test_character (*p, UCL_CHARACTER_WHITESPACE)) { 1682262395Sbapt /* Skip whitespaces */ 1683262395Sbapt ucl_chunk_skipc (chunk, p); 1684262395Sbapt } 1685262395Sbapt else if (chunk->remain >= 2 && ucl_lex_is_comment (p[0], p[1])) { 1686262395Sbapt /* Skip comment */ 1687262395Sbapt if (!ucl_skip_comments (parser)) { 1688262395Sbapt return false; 1689262395Sbapt } 1690262395Sbapt /* Treat comment as a separator */ 1691262395Sbapt got_sep = true; 1692262395Sbapt p = chunk->pos; 1693262395Sbapt } 1694262395Sbapt else if (ucl_test_character (*p, UCL_CHARACTER_VALUE_END)) { 1695262395Sbapt if (*p == '}' || *p == ']') { 1696262395Sbapt if (parser->stack == NULL) { 1697275223Sbapt ucl_set_err (parser, UCL_ESYNTAX, 1698275223Sbapt "end of array or object detected without corresponding start", 1699275223Sbapt &parser->err); 1700262395Sbapt return false; 1701262395Sbapt } 1702262395Sbapt if ((*p == '}' && parser->stack->obj->type == UCL_OBJECT) || 1703262395Sbapt (*p == ']' && parser->stack->obj->type == UCL_ARRAY)) { 1704262395Sbapt 1705262395Sbapt /* Pop all nested objects from a stack */ 1706262395Sbapt st = parser->stack; 1707262395Sbapt parser->stack = st->next; 1708262395Sbapt UCL_FREE (sizeof (struct ucl_stack), st); 1709262395Sbapt 1710262395Sbapt while (parser->stack != NULL) { 1711262395Sbapt st = parser->stack; 1712262395Sbapt if (st->next == NULL || st->next->level == st->level) { 1713262395Sbapt break; 1714262395Sbapt } 1715262395Sbapt parser->stack = st->next; 1716262395Sbapt UCL_FREE (sizeof (struct ucl_stack), st); 1717262395Sbapt } 1718262395Sbapt } 1719262395Sbapt else { 1720275223Sbapt ucl_set_err (parser, UCL_ESYNTAX, 1721275223Sbapt "unexpected terminating symbol detected", 1722275223Sbapt &parser->err); 1723262395Sbapt return false; 1724262395Sbapt } 1725262395Sbapt 1726262395Sbapt if (parser->stack == NULL) { 1727262395Sbapt /* Ignore everything after a top object */ 1728262395Sbapt return true; 1729262395Sbapt } 1730262395Sbapt else { 1731262395Sbapt ucl_chunk_skipc (chunk, p); 1732262395Sbapt } 1733262395Sbapt got_sep = true; 1734262395Sbapt } 1735262395Sbapt else { 1736262395Sbapt /* Got a separator */ 1737262395Sbapt got_sep = true; 1738262395Sbapt ucl_chunk_skipc (chunk, p); 1739262395Sbapt } 1740262395Sbapt } 1741262395Sbapt else { 1742262395Sbapt /* Anything else */ 1743262395Sbapt if (!got_sep) { 1744275223Sbapt ucl_set_err (parser, UCL_ESYNTAX, "delimiter is missing", 1745275223Sbapt &parser->err); 1746262395Sbapt return false; 1747262395Sbapt } 1748262395Sbapt return true; 1749262395Sbapt } 1750262395Sbapt } 1751262395Sbapt 1752262395Sbapt return true; 1753262395Sbapt} 1754262395Sbapt 1755262395Sbapt/** 1756262395Sbapt * Handle macro data 1757262395Sbapt * @param parser 1758262395Sbapt * @param chunk 1759290071Sbapt * @param marco 1760290071Sbapt * @param macro_start 1761290071Sbapt * @param macro_len 1762262395Sbapt * @return 1763262395Sbapt */ 1764262395Sbaptstatic bool 1765262395Sbaptucl_parse_macro_value (struct ucl_parser *parser, 1766262395Sbapt struct ucl_chunk *chunk, struct ucl_macro *macro, 1767262395Sbapt unsigned char const **macro_start, size_t *macro_len) 1768262395Sbapt{ 1769262395Sbapt const unsigned char *p, *c; 1770262395Sbapt bool need_unescape = false, ucl_escape = false, var_expand = false; 1771262395Sbapt 1772262395Sbapt p = chunk->pos; 1773262395Sbapt 1774262395Sbapt switch (*p) { 1775262395Sbapt case '"': 1776262395Sbapt /* We have macro value encoded in quotes */ 1777262395Sbapt c = p; 1778262395Sbapt ucl_chunk_skipc (chunk, p); 1779262395Sbapt if (!ucl_lex_json_string (parser, chunk, &need_unescape, &ucl_escape, &var_expand)) { 1780262395Sbapt return false; 1781262395Sbapt } 1782262395Sbapt 1783262395Sbapt *macro_start = c + 1; 1784262395Sbapt *macro_len = chunk->pos - c - 2; 1785262395Sbapt p = chunk->pos; 1786262395Sbapt break; 1787262395Sbapt case '{': 1788262395Sbapt /* We got a multiline macro body */ 1789262395Sbapt ucl_chunk_skipc (chunk, p); 1790262395Sbapt /* Skip spaces at the beginning */ 1791262395Sbapt while (p < chunk->end) { 1792262395Sbapt if (ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE)) { 1793262395Sbapt ucl_chunk_skipc (chunk, p); 1794262395Sbapt } 1795262395Sbapt else { 1796262395Sbapt break; 1797262395Sbapt } 1798262395Sbapt } 1799262395Sbapt c = p; 1800262395Sbapt while (p < chunk->end) { 1801262395Sbapt if (*p == '}') { 1802262395Sbapt break; 1803262395Sbapt } 1804262395Sbapt ucl_chunk_skipc (chunk, p); 1805262395Sbapt } 1806262395Sbapt *macro_start = c; 1807262395Sbapt *macro_len = p - c; 1808262395Sbapt ucl_chunk_skipc (chunk, p); 1809262395Sbapt break; 1810262395Sbapt default: 1811262395Sbapt /* Macro is not enclosed in quotes or braces */ 1812262395Sbapt c = p; 1813262395Sbapt while (p < chunk->end) { 1814262395Sbapt if (ucl_lex_is_atom_end (*p)) { 1815262395Sbapt break; 1816262395Sbapt } 1817262395Sbapt ucl_chunk_skipc (chunk, p); 1818262395Sbapt } 1819262395Sbapt *macro_start = c; 1820262395Sbapt *macro_len = p - c; 1821262395Sbapt break; 1822262395Sbapt } 1823262395Sbapt 1824262395Sbapt /* We are at the end of a macro */ 1825262395Sbapt /* Skip ';' and space characters and return to previous state */ 1826262395Sbapt while (p < chunk->end) { 1827262395Sbapt if (!ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE) && *p != ';') { 1828262395Sbapt break; 1829262395Sbapt } 1830262395Sbapt ucl_chunk_skipc (chunk, p); 1831262395Sbapt } 1832262395Sbapt return true; 1833262395Sbapt} 1834262395Sbapt 1835262395Sbapt/** 1836275223Sbapt * Parse macro arguments as UCL object 1837275223Sbapt * @param parser parser structure 1838275223Sbapt * @param chunk the current data chunk 1839275223Sbapt * @return 1840275223Sbapt */ 1841275223Sbaptstatic ucl_object_t * 1842275223Sbaptucl_parse_macro_arguments (struct ucl_parser *parser, 1843275223Sbapt struct ucl_chunk *chunk) 1844275223Sbapt{ 1845275223Sbapt ucl_object_t *res = NULL; 1846275223Sbapt struct ucl_parser *params_parser; 1847275223Sbapt int obraces = 1, ebraces = 0, state = 0; 1848275223Sbapt const unsigned char *p, *c; 1849275223Sbapt size_t args_len = 0; 1850275223Sbapt struct ucl_parser_saved_state saved; 1851275223Sbapt 1852275223Sbapt saved.column = chunk->column; 1853275223Sbapt saved.line = chunk->line; 1854275223Sbapt saved.pos = chunk->pos; 1855275223Sbapt saved.remain = chunk->remain; 1856275223Sbapt p = chunk->pos; 1857275223Sbapt 1858275223Sbapt if (*p != '(' || chunk->remain < 2) { 1859275223Sbapt return NULL; 1860275223Sbapt } 1861275223Sbapt 1862275223Sbapt /* Set begin and start */ 1863275223Sbapt ucl_chunk_skipc (chunk, p); 1864275223Sbapt c = p; 1865275223Sbapt 1866275223Sbapt while ((p) < (chunk)->end) { 1867275223Sbapt switch (state) { 1868275223Sbapt case 0: 1869275223Sbapt /* Parse symbols and check for '(', ')' and '"' */ 1870275223Sbapt if (*p == '(') { 1871275223Sbapt obraces ++; 1872275223Sbapt } 1873275223Sbapt else if (*p == ')') { 1874275223Sbapt ebraces ++; 1875275223Sbapt } 1876275223Sbapt else if (*p == '"') { 1877275223Sbapt state = 1; 1878275223Sbapt } 1879275223Sbapt /* Check pairing */ 1880275223Sbapt if (obraces == ebraces) { 1881275223Sbapt state = 99; 1882275223Sbapt } 1883275223Sbapt else { 1884275223Sbapt args_len ++; 1885275223Sbapt } 1886275223Sbapt /* Check overflow */ 1887275223Sbapt if (chunk->remain == 0) { 1888275223Sbapt goto restore_chunk; 1889275223Sbapt } 1890275223Sbapt ucl_chunk_skipc (chunk, p); 1891275223Sbapt break; 1892275223Sbapt case 1: 1893275223Sbapt /* We have quote character, so skip all but quotes */ 1894275223Sbapt if (*p == '"' && *(p - 1) != '\\') { 1895275223Sbapt state = 0; 1896275223Sbapt } 1897275223Sbapt if (chunk->remain == 0) { 1898275223Sbapt goto restore_chunk; 1899275223Sbapt } 1900290071Sbapt args_len ++; 1901275223Sbapt ucl_chunk_skipc (chunk, p); 1902275223Sbapt break; 1903275223Sbapt case 99: 1904275223Sbapt /* 1905275223Sbapt * We have read the full body of arguments, so we need to parse and set 1906275223Sbapt * object from that 1907275223Sbapt */ 1908275223Sbapt params_parser = ucl_parser_new (parser->flags); 1909275223Sbapt if (!ucl_parser_add_chunk (params_parser, c, args_len)) { 1910275223Sbapt ucl_set_err (parser, UCL_ESYNTAX, "macro arguments parsing error", 1911275223Sbapt &parser->err); 1912275223Sbapt } 1913275223Sbapt else { 1914275223Sbapt res = ucl_parser_get_object (params_parser); 1915275223Sbapt } 1916275223Sbapt ucl_parser_free (params_parser); 1917275223Sbapt 1918275223Sbapt return res; 1919275223Sbapt 1920275223Sbapt break; 1921275223Sbapt } 1922275223Sbapt } 1923275223Sbapt 1924275223Sbapt return res; 1925275223Sbapt 1926275223Sbaptrestore_chunk: 1927275223Sbapt chunk->column = saved.column; 1928275223Sbapt chunk->line = saved.line; 1929275223Sbapt chunk->pos = saved.pos; 1930275223Sbapt chunk->remain = saved.remain; 1931275223Sbapt 1932275223Sbapt return NULL; 1933275223Sbapt} 1934275223Sbapt 1935275223Sbapt#define SKIP_SPACES_COMMENTS(parser, chunk, p) do { \ 1936275223Sbapt while ((p) < (chunk)->end) { \ 1937275223Sbapt if (!ucl_test_character (*(p), UCL_CHARACTER_WHITESPACE_UNSAFE)) { \ 1938275223Sbapt if ((chunk)->remain >= 2 && ucl_lex_is_comment ((p)[0], (p)[1])) { \ 1939275223Sbapt if (!ucl_skip_comments (parser)) { \ 1940275223Sbapt return false; \ 1941275223Sbapt } \ 1942275223Sbapt p = (chunk)->pos; \ 1943275223Sbapt } \ 1944275223Sbapt break; \ 1945275223Sbapt } \ 1946275223Sbapt ucl_chunk_skipc (chunk, p); \ 1947275223Sbapt } \ 1948275223Sbapt} while(0) 1949275223Sbapt 1950275223Sbapt/** 1951262395Sbapt * Handle the main states of rcl parser 1952262395Sbapt * @param parser parser structure 1953262395Sbapt * @return true if chunk has been parsed and false in case of error 1954262395Sbapt */ 1955262395Sbaptstatic bool 1956262395Sbaptucl_state_machine (struct ucl_parser *parser) 1957262395Sbapt{ 1958275223Sbapt ucl_object_t *obj, *macro_args; 1959262395Sbapt struct ucl_chunk *chunk = parser->chunks; 1960262395Sbapt const unsigned char *p, *c = NULL, *macro_start = NULL; 1961262395Sbapt unsigned char *macro_escaped; 1962262395Sbapt size_t macro_len = 0; 1963262395Sbapt struct ucl_macro *macro = NULL; 1964275223Sbapt bool next_key = false, end_of_object = false, ret; 1965262395Sbapt 1966262395Sbapt if (parser->top_obj == NULL) { 1967262395Sbapt parser->state = UCL_STATE_INIT; 1968262395Sbapt } 1969262395Sbapt 1970262395Sbapt p = chunk->pos; 1971262395Sbapt while (chunk->pos < chunk->end) { 1972262395Sbapt switch (parser->state) { 1973262395Sbapt case UCL_STATE_INIT: 1974262395Sbapt /* 1975262395Sbapt * At the init state we can either go to the parse array or object 1976262395Sbapt * if we got [ or { correspondingly or can just treat new data as 1977262395Sbapt * a key of newly created object 1978262395Sbapt */ 1979262395Sbapt if (!ucl_skip_comments (parser)) { 1980262395Sbapt parser->prev_state = parser->state; 1981262395Sbapt parser->state = UCL_STATE_ERROR; 1982262395Sbapt return false; 1983262395Sbapt } 1984262395Sbapt else { 1985268876Sbapt /* Skip any spaces */ 1986268876Sbapt while (p < chunk->end && ucl_test_character (*p, 1987268876Sbapt UCL_CHARACTER_WHITESPACE_UNSAFE)) { 1988268876Sbapt ucl_chunk_skipc (chunk, p); 1989268876Sbapt } 1990290071Sbapt 1991262395Sbapt p = chunk->pos; 1992290071Sbapt 1993262395Sbapt if (*p == '[') { 1994262395Sbapt parser->state = UCL_STATE_VALUE; 1995262395Sbapt ucl_chunk_skipc (chunk, p); 1996262395Sbapt } 1997262395Sbapt else { 1998262395Sbapt parser->state = UCL_STATE_KEY; 1999262395Sbapt if (*p == '{') { 2000262395Sbapt ucl_chunk_skipc (chunk, p); 2001262395Sbapt } 2002262395Sbapt } 2003290071Sbapt 2004290071Sbapt if (parser->top_obj == NULL) { 2005290071Sbapt if (parser->state == UCL_STATE_VALUE) { 2006290071Sbapt obj = ucl_parser_add_container (NULL, parser, true, 0); 2007290071Sbapt } 2008290071Sbapt else { 2009290071Sbapt obj = ucl_parser_add_container (NULL, parser, false, 0); 2010290071Sbapt } 2011290071Sbapt 2012290071Sbapt if (obj == NULL) { 2013290071Sbapt return false; 2014290071Sbapt } 2015290071Sbapt 2016290071Sbapt parser->top_obj = obj; 2017290071Sbapt parser->cur_obj = obj; 2018290071Sbapt } 2019290071Sbapt 2020262395Sbapt } 2021262395Sbapt break; 2022262395Sbapt case UCL_STATE_KEY: 2023262395Sbapt /* Skip any spaces */ 2024262395Sbapt while (p < chunk->end && ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE)) { 2025262395Sbapt ucl_chunk_skipc (chunk, p); 2026262395Sbapt } 2027262395Sbapt if (*p == '}') { 2028262395Sbapt /* We have the end of an object */ 2029262395Sbapt parser->state = UCL_STATE_AFTER_VALUE; 2030262395Sbapt continue; 2031262395Sbapt } 2032262395Sbapt if (parser->stack == NULL) { 2033262395Sbapt /* No objects are on stack, but we want to parse a key */ 2034275223Sbapt ucl_set_err (parser, UCL_ESYNTAX, "top object is finished but the parser " 2035262395Sbapt "expects a key", &parser->err); 2036262395Sbapt parser->prev_state = parser->state; 2037262395Sbapt parser->state = UCL_STATE_ERROR; 2038262395Sbapt return false; 2039262395Sbapt } 2040262395Sbapt if (!ucl_parse_key (parser, chunk, &next_key, &end_of_object)) { 2041262395Sbapt parser->prev_state = parser->state; 2042262395Sbapt parser->state = UCL_STATE_ERROR; 2043262395Sbapt return false; 2044262395Sbapt } 2045262395Sbapt if (end_of_object) { 2046262395Sbapt p = chunk->pos; 2047262395Sbapt parser->state = UCL_STATE_AFTER_VALUE; 2048262395Sbapt continue; 2049262395Sbapt } 2050262395Sbapt else if (parser->state != UCL_STATE_MACRO_NAME) { 2051262395Sbapt if (next_key && parser->stack->obj->type == UCL_OBJECT) { 2052262395Sbapt /* Parse more keys and nest objects accordingly */ 2053290071Sbapt obj = ucl_parser_add_container (parser->cur_obj, parser, false, 2054263648Sbapt parser->stack->level + 1); 2055263648Sbapt if (obj == NULL) { 2056263648Sbapt return false; 2057263648Sbapt } 2058262395Sbapt } 2059262395Sbapt else { 2060262395Sbapt parser->state = UCL_STATE_VALUE; 2061262395Sbapt } 2062262395Sbapt } 2063262395Sbapt else { 2064262395Sbapt c = chunk->pos; 2065262395Sbapt } 2066262395Sbapt p = chunk->pos; 2067262395Sbapt break; 2068262395Sbapt case UCL_STATE_VALUE: 2069262395Sbapt /* We need to check what we do have */ 2070262395Sbapt if (!ucl_parse_value (parser, chunk)) { 2071262395Sbapt parser->prev_state = parser->state; 2072262395Sbapt parser->state = UCL_STATE_ERROR; 2073262395Sbapt return false; 2074262395Sbapt } 2075262395Sbapt /* State is set in ucl_parse_value call */ 2076262395Sbapt p = chunk->pos; 2077262395Sbapt break; 2078262395Sbapt case UCL_STATE_AFTER_VALUE: 2079262395Sbapt if (!ucl_parse_after_value (parser, chunk)) { 2080262395Sbapt parser->prev_state = parser->state; 2081262395Sbapt parser->state = UCL_STATE_ERROR; 2082262395Sbapt return false; 2083262395Sbapt } 2084290071Sbapt 2085262395Sbapt if (parser->stack != NULL) { 2086262395Sbapt if (parser->stack->obj->type == UCL_OBJECT) { 2087262395Sbapt parser->state = UCL_STATE_KEY; 2088262395Sbapt } 2089262395Sbapt else { 2090262395Sbapt /* Array */ 2091262395Sbapt parser->state = UCL_STATE_VALUE; 2092262395Sbapt } 2093262395Sbapt } 2094262395Sbapt else { 2095262395Sbapt /* Skip everything at the end */ 2096262395Sbapt return true; 2097262395Sbapt } 2098262395Sbapt p = chunk->pos; 2099262395Sbapt break; 2100262395Sbapt case UCL_STATE_MACRO_NAME: 2101275223Sbapt if (!ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE) && 2102275223Sbapt *p != '(') { 2103262395Sbapt ucl_chunk_skipc (chunk, p); 2104262395Sbapt } 2105290071Sbapt else { 2106290071Sbapt if (p - c > 0) { 2107290071Sbapt /* We got macro name */ 2108290071Sbapt macro_len = (size_t) (p - c); 2109290071Sbapt HASH_FIND (hh, parser->macroes, c, macro_len, macro); 2110290071Sbapt if (macro == NULL) { 2111290071Sbapt ucl_create_err (&parser->err, 2112290071Sbapt "error on line %d at column %d: " 2113290071Sbapt "unknown macro: '%.*s', character: '%c'", 2114290071Sbapt chunk->line, 2115290071Sbapt chunk->column, 2116290071Sbapt (int) (p - c), 2117290071Sbapt c, 2118290071Sbapt *chunk->pos); 2119290071Sbapt parser->state = UCL_STATE_ERROR; 2120290071Sbapt return false; 2121290071Sbapt } 2122290071Sbapt /* Now we need to skip all spaces */ 2123290071Sbapt SKIP_SPACES_COMMENTS(parser, chunk, p); 2124290071Sbapt parser->state = UCL_STATE_MACRO; 2125290071Sbapt } 2126290071Sbapt else { 2127290071Sbapt /* We have invalid macro name */ 2128290071Sbapt ucl_create_err (&parser->err, 2129290071Sbapt "error on line %d at column %d: invalid macro name", 2130290071Sbapt chunk->line, 2131290071Sbapt chunk->column); 2132262395Sbapt parser->state = UCL_STATE_ERROR; 2133262395Sbapt return false; 2134262395Sbapt } 2135262395Sbapt } 2136262395Sbapt break; 2137262395Sbapt case UCL_STATE_MACRO: 2138275223Sbapt if (*chunk->pos == '(') { 2139275223Sbapt macro_args = ucl_parse_macro_arguments (parser, chunk); 2140275223Sbapt p = chunk->pos; 2141275223Sbapt if (macro_args) { 2142275223Sbapt SKIP_SPACES_COMMENTS(parser, chunk, p); 2143275223Sbapt } 2144275223Sbapt } 2145275223Sbapt else { 2146275223Sbapt macro_args = NULL; 2147275223Sbapt } 2148262395Sbapt if (!ucl_parse_macro_value (parser, chunk, macro, 2149262395Sbapt ¯o_start, ¯o_len)) { 2150262395Sbapt parser->prev_state = parser->state; 2151262395Sbapt parser->state = UCL_STATE_ERROR; 2152262395Sbapt return false; 2153262395Sbapt } 2154275223Sbapt macro_len = ucl_expand_variable (parser, ¯o_escaped, 2155275223Sbapt macro_start, macro_len); 2156262395Sbapt parser->state = parser->prev_state; 2157262395Sbapt if (macro_escaped == NULL) { 2158290071Sbapt if (macro->is_context) { 2159290071Sbapt ret = macro->h.context_handler (macro_start, macro_len, 2160290071Sbapt macro_args, 2161290071Sbapt parser->top_obj, 2162290071Sbapt macro->ud); 2163290071Sbapt } 2164290071Sbapt else { 2165290071Sbapt ret = macro->h.handler (macro_start, macro_len, macro_args, 2166290071Sbapt macro->ud); 2167290071Sbapt } 2168262395Sbapt } 2169262395Sbapt else { 2170290071Sbapt if (macro->is_context) { 2171290071Sbapt ret = macro->h.context_handler (macro_escaped, macro_len, 2172290071Sbapt macro_args, 2173290071Sbapt parser->top_obj, 2174290071Sbapt macro->ud); 2175290071Sbapt } 2176290071Sbapt else { 2177290071Sbapt ret = macro->h.handler (macro_escaped, macro_len, macro_args, 2178275223Sbapt macro->ud); 2179290071Sbapt } 2180290071Sbapt 2181262395Sbapt UCL_FREE (macro_len + 1, macro_escaped); 2182262395Sbapt } 2183290071Sbapt 2184290071Sbapt /* 2185290071Sbapt * Chunk can be modified within macro handler 2186290071Sbapt */ 2187290071Sbapt chunk = parser->chunks; 2188262395Sbapt p = chunk->pos; 2189275223Sbapt if (macro_args) { 2190275223Sbapt ucl_object_unref (macro_args); 2191275223Sbapt } 2192275223Sbapt if (!ret) { 2193275223Sbapt return false; 2194275223Sbapt } 2195262395Sbapt break; 2196262395Sbapt default: 2197262395Sbapt /* TODO: add all states */ 2198275223Sbapt ucl_set_err (parser, UCL_EINTERNAL, 2199275223Sbapt "internal error: parser is in an unknown state", &parser->err); 2200262395Sbapt parser->state = UCL_STATE_ERROR; 2201262395Sbapt return false; 2202262395Sbapt } 2203262395Sbapt } 2204262395Sbapt 2205262395Sbapt return true; 2206262395Sbapt} 2207262395Sbapt 2208262395Sbaptstruct ucl_parser* 2209262395Sbaptucl_parser_new (int flags) 2210262395Sbapt{ 2211262395Sbapt struct ucl_parser *new; 2212262395Sbapt 2213262395Sbapt new = UCL_ALLOC (sizeof (struct ucl_parser)); 2214263648Sbapt if (new == NULL) { 2215263648Sbapt return NULL; 2216263648Sbapt } 2217290071Sbapt 2218262395Sbapt memset (new, 0, sizeof (struct ucl_parser)); 2219262395Sbapt 2220262395Sbapt ucl_parser_register_macro (new, "include", ucl_include_handler, new); 2221262395Sbapt ucl_parser_register_macro (new, "try_include", ucl_try_include_handler, new); 2222262395Sbapt ucl_parser_register_macro (new, "includes", ucl_includes_handler, new); 2223290071Sbapt ucl_parser_register_macro (new, "priority", ucl_priority_handler, new); 2224290071Sbapt ucl_parser_register_macro (new, "load", ucl_load_handler, new); 2225290071Sbapt ucl_parser_register_context_macro (new, "inherit", ucl_inherit_handler, new); 2226262395Sbapt 2227262395Sbapt new->flags = flags; 2228290071Sbapt new->includepaths = NULL; 2229262395Sbapt 2230262395Sbapt /* Initial assumption about filevars */ 2231262395Sbapt ucl_parser_set_filevars (new, NULL, false); 2232262395Sbapt 2233262395Sbapt return new; 2234262395Sbapt} 2235262395Sbapt 2236290071Sbaptbool 2237290071Sbaptucl_parser_set_default_priority (struct ucl_parser *parser, unsigned prio) 2238290071Sbapt{ 2239290071Sbapt if (parser == NULL) { 2240290071Sbapt return false; 2241290071Sbapt } 2242262395Sbapt 2243290071Sbapt parser->default_priority = prio; 2244290071Sbapt 2245290071Sbapt return true; 2246290071Sbapt} 2247290071Sbapt 2248262395Sbaptvoid 2249262395Sbaptucl_parser_register_macro (struct ucl_parser *parser, const char *macro, 2250262395Sbapt ucl_macro_handler handler, void* ud) 2251262395Sbapt{ 2252262395Sbapt struct ucl_macro *new; 2253262395Sbapt 2254263648Sbapt if (macro == NULL || handler == NULL) { 2255263648Sbapt return; 2256263648Sbapt } 2257290071Sbapt 2258262395Sbapt new = UCL_ALLOC (sizeof (struct ucl_macro)); 2259263648Sbapt if (new == NULL) { 2260263648Sbapt return; 2261263648Sbapt } 2262290071Sbapt 2263262395Sbapt memset (new, 0, sizeof (struct ucl_macro)); 2264290071Sbapt new->h.handler = handler; 2265262395Sbapt new->name = strdup (macro); 2266262395Sbapt new->ud = ud; 2267262395Sbapt HASH_ADD_KEYPTR (hh, parser->macroes, new->name, strlen (new->name), new); 2268262395Sbapt} 2269262395Sbapt 2270262395Sbaptvoid 2271290071Sbaptucl_parser_register_context_macro (struct ucl_parser *parser, const char *macro, 2272290071Sbapt ucl_context_macro_handler handler, void* ud) 2273290071Sbapt{ 2274290071Sbapt struct ucl_macro *new; 2275290071Sbapt 2276290071Sbapt if (macro == NULL || handler == NULL) { 2277290071Sbapt return; 2278290071Sbapt } 2279290071Sbapt 2280290071Sbapt new = UCL_ALLOC (sizeof (struct ucl_macro)); 2281290071Sbapt if (new == NULL) { 2282290071Sbapt return; 2283290071Sbapt } 2284290071Sbapt 2285290071Sbapt memset (new, 0, sizeof (struct ucl_macro)); 2286290071Sbapt new->h.context_handler = handler; 2287290071Sbapt new->name = strdup (macro); 2288290071Sbapt new->ud = ud; 2289290071Sbapt new->is_context = true; 2290290071Sbapt HASH_ADD_KEYPTR (hh, parser->macroes, new->name, strlen (new->name), new); 2291290071Sbapt} 2292290071Sbapt 2293290071Sbaptvoid 2294262395Sbaptucl_parser_register_variable (struct ucl_parser *parser, const char *var, 2295262395Sbapt const char *value) 2296262395Sbapt{ 2297262395Sbapt struct ucl_variable *new = NULL, *cur; 2298262395Sbapt 2299262395Sbapt if (var == NULL) { 2300262395Sbapt return; 2301262395Sbapt } 2302262395Sbapt 2303262395Sbapt /* Find whether a variable already exists */ 2304262395Sbapt LL_FOREACH (parser->variables, cur) { 2305262395Sbapt if (strcmp (cur->var, var) == 0) { 2306262395Sbapt new = cur; 2307262395Sbapt break; 2308262395Sbapt } 2309262395Sbapt } 2310262395Sbapt 2311262395Sbapt if (value == NULL) { 2312262395Sbapt 2313262395Sbapt if (new != NULL) { 2314262395Sbapt /* Remove variable */ 2315275223Sbapt DL_DELETE (parser->variables, new); 2316262395Sbapt free (new->var); 2317262395Sbapt free (new->value); 2318262395Sbapt UCL_FREE (sizeof (struct ucl_variable), new); 2319262395Sbapt } 2320262395Sbapt else { 2321262395Sbapt /* Do nothing */ 2322262395Sbapt return; 2323262395Sbapt } 2324262395Sbapt } 2325262395Sbapt else { 2326262395Sbapt if (new == NULL) { 2327262395Sbapt new = UCL_ALLOC (sizeof (struct ucl_variable)); 2328263648Sbapt if (new == NULL) { 2329263648Sbapt return; 2330263648Sbapt } 2331262395Sbapt memset (new, 0, sizeof (struct ucl_variable)); 2332262395Sbapt new->var = strdup (var); 2333262395Sbapt new->var_len = strlen (var); 2334262395Sbapt new->value = strdup (value); 2335262395Sbapt new->value_len = strlen (value); 2336262395Sbapt 2337275223Sbapt DL_APPEND (parser->variables, new); 2338262395Sbapt } 2339262395Sbapt else { 2340262395Sbapt free (new->value); 2341262395Sbapt new->value = strdup (value); 2342262395Sbapt new->value_len = strlen (value); 2343262395Sbapt } 2344262395Sbapt } 2345262395Sbapt} 2346262395Sbapt 2347266636Sbaptvoid 2348266636Sbaptucl_parser_set_variables_handler (struct ucl_parser *parser, 2349266636Sbapt ucl_variable_handler handler, void *ud) 2350266636Sbapt{ 2351266636Sbapt parser->var_handler = handler; 2352266636Sbapt parser->var_data = ud; 2353266636Sbapt} 2354266636Sbapt 2355262395Sbaptbool 2356290071Sbaptucl_parser_add_chunk_full (struct ucl_parser *parser, const unsigned char *data, 2357290071Sbapt size_t len, unsigned priority, enum ucl_duplicate_strategy strat, 2358290071Sbapt enum ucl_parse_type parse_type) 2359262395Sbapt{ 2360262395Sbapt struct ucl_chunk *chunk; 2361262395Sbapt 2362290071Sbapt if (parser == NULL) { 2363290071Sbapt return false; 2364290071Sbapt } 2365290071Sbapt 2366275223Sbapt if (data == NULL) { 2367263648Sbapt ucl_create_err (&parser->err, "invalid chunk added"); 2368263648Sbapt return false; 2369263648Sbapt } 2370275223Sbapt if (len == 0) { 2371275223Sbapt parser->top_obj = ucl_object_new_full (UCL_OBJECT, priority); 2372275223Sbapt return true; 2373275223Sbapt } 2374262395Sbapt if (parser->state != UCL_STATE_ERROR) { 2375262395Sbapt chunk = UCL_ALLOC (sizeof (struct ucl_chunk)); 2376263648Sbapt if (chunk == NULL) { 2377263648Sbapt ucl_create_err (&parser->err, "cannot allocate chunk structure"); 2378263648Sbapt return false; 2379263648Sbapt } 2380262395Sbapt chunk->begin = data; 2381262395Sbapt chunk->remain = len; 2382262395Sbapt chunk->pos = chunk->begin; 2383262395Sbapt chunk->end = chunk->begin + len; 2384262395Sbapt chunk->line = 1; 2385262395Sbapt chunk->column = 0; 2386275223Sbapt chunk->priority = priority; 2387290071Sbapt chunk->strategy = strat; 2388290071Sbapt chunk->parse_type = parse_type; 2389262395Sbapt LL_PREPEND (parser->chunks, chunk); 2390262395Sbapt parser->recursion ++; 2391290071Sbapt 2392262395Sbapt if (parser->recursion > UCL_MAX_RECURSION) { 2393262395Sbapt ucl_create_err (&parser->err, "maximum include nesting limit is reached: %d", 2394262395Sbapt parser->recursion); 2395262395Sbapt return false; 2396262395Sbapt } 2397290071Sbapt 2398290071Sbapt switch (parse_type) { 2399290071Sbapt default: 2400290071Sbapt case UCL_PARSE_UCL: 2401290071Sbapt return ucl_state_machine (parser); 2402290071Sbapt case UCL_PARSE_MSGPACK: 2403290071Sbapt return ucl_parse_msgpack (parser); 2404290071Sbapt } 2405262395Sbapt } 2406262395Sbapt 2407262395Sbapt ucl_create_err (&parser->err, "a parser is in an invalid state"); 2408262395Sbapt 2409262395Sbapt return false; 2410262395Sbapt} 2411263648Sbapt 2412263648Sbaptbool 2413290071Sbaptucl_parser_add_chunk_priority (struct ucl_parser *parser, 2414290071Sbapt const unsigned char *data, size_t len, unsigned priority) 2415290071Sbapt{ 2416290071Sbapt /* We dereference parser, so this check is essential */ 2417290071Sbapt if (parser == NULL) { 2418290071Sbapt return false; 2419290071Sbapt } 2420290071Sbapt 2421290071Sbapt return ucl_parser_add_chunk_full (parser, data, len, 2422290071Sbapt priority, UCL_DUPLICATE_APPEND, UCL_PARSE_UCL); 2423290071Sbapt} 2424290071Sbapt 2425290071Sbaptbool 2426275223Sbaptucl_parser_add_chunk (struct ucl_parser *parser, const unsigned char *data, 2427275223Sbapt size_t len) 2428275223Sbapt{ 2429290071Sbapt if (parser == NULL) { 2430290071Sbapt return false; 2431290071Sbapt } 2432290071Sbapt 2433290071Sbapt return ucl_parser_add_chunk_full (parser, data, len, 2434290071Sbapt parser->default_priority, UCL_DUPLICATE_APPEND, UCL_PARSE_UCL); 2435275223Sbapt} 2436275223Sbapt 2437275223Sbaptbool 2438290071Sbaptucl_parser_add_string_priority (struct ucl_parser *parser, const char *data, 2439290071Sbapt size_t len, unsigned priority) 2440263648Sbapt{ 2441263648Sbapt if (data == NULL) { 2442263648Sbapt ucl_create_err (&parser->err, "invalid string added"); 2443263648Sbapt return false; 2444263648Sbapt } 2445263648Sbapt if (len == 0) { 2446263648Sbapt len = strlen (data); 2447263648Sbapt } 2448263648Sbapt 2449290071Sbapt return ucl_parser_add_chunk_priority (parser, 2450290071Sbapt (const unsigned char *)data, len, priority); 2451263648Sbapt} 2452290071Sbapt 2453290071Sbaptbool 2454290071Sbaptucl_parser_add_string (struct ucl_parser *parser, const char *data, 2455290071Sbapt size_t len) 2456290071Sbapt{ 2457290071Sbapt if (parser == NULL) { 2458290071Sbapt return false; 2459290071Sbapt } 2460290071Sbapt 2461290071Sbapt return ucl_parser_add_string_priority (parser, 2462290071Sbapt (const unsigned char *)data, len, parser->default_priority); 2463290071Sbapt} 2464290071Sbapt 2465290071Sbaptbool 2466290071Sbaptucl_set_include_path (struct ucl_parser *parser, ucl_object_t *paths) 2467290071Sbapt{ 2468290071Sbapt if (parser == NULL || paths == NULL) { 2469290071Sbapt return false; 2470290071Sbapt } 2471290071Sbapt 2472290071Sbapt if (parser->includepaths == NULL) { 2473290071Sbapt parser->includepaths = ucl_object_copy (paths); 2474290071Sbapt } 2475290071Sbapt else { 2476290071Sbapt ucl_object_unref (parser->includepaths); 2477290071Sbapt parser->includepaths = ucl_object_copy (paths); 2478290071Sbapt } 2479290071Sbapt 2480290071Sbapt if (parser->includepaths == NULL) { 2481290071Sbapt return false; 2482290071Sbapt } 2483290071Sbapt 2484290071Sbapt return true; 2485290071Sbapt} 2486