1c99fb5f9SBaptiste Daroussin /* Copyright (c) 2013, Vsevolod Stakhov 2c99fb5f9SBaptiste Daroussin * All rights reserved. 3c99fb5f9SBaptiste Daroussin * 4c99fb5f9SBaptiste Daroussin * Redistribution and use in source and binary forms, with or without 5c99fb5f9SBaptiste Daroussin * modification, are permitted provided that the following conditions are met: 6c99fb5f9SBaptiste Daroussin * * Redistributions of source code must retain the above copyright 7c99fb5f9SBaptiste Daroussin * notice, this list of conditions and the following disclaimer. 8c99fb5f9SBaptiste Daroussin * * Redistributions in binary form must reproduce the above copyright 9c99fb5f9SBaptiste Daroussin * notice, this list of conditions and the following disclaimer in the 10c99fb5f9SBaptiste Daroussin * documentation and/or other materials provided with the distribution. 11c99fb5f9SBaptiste Daroussin * 12c99fb5f9SBaptiste Daroussin * THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY 13c99fb5f9SBaptiste Daroussin * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 14c99fb5f9SBaptiste Daroussin * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 15c99fb5f9SBaptiste Daroussin * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY 16c99fb5f9SBaptiste Daroussin * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 17c99fb5f9SBaptiste Daroussin * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 18c99fb5f9SBaptiste Daroussin * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 19c99fb5f9SBaptiste Daroussin * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 20c99fb5f9SBaptiste Daroussin * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 21c99fb5f9SBaptiste Daroussin * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 22c99fb5f9SBaptiste Daroussin */ 23c99fb5f9SBaptiste Daroussin 24c99fb5f9SBaptiste Daroussin #include "ucl.h" 25c99fb5f9SBaptiste Daroussin #include "ucl_internal.h" 26c99fb5f9SBaptiste Daroussin #include "ucl_chartable.h" 27c99fb5f9SBaptiste Daroussin 28c99fb5f9SBaptiste Daroussin /** 29c99fb5f9SBaptiste Daroussin * @file rcl_parser.c 30c99fb5f9SBaptiste Daroussin * The implementation of rcl parser 31c99fb5f9SBaptiste Daroussin */ 32c99fb5f9SBaptiste Daroussin 33c99fb5f9SBaptiste Daroussin struct ucl_parser_saved_state { 34c99fb5f9SBaptiste Daroussin unsigned int line; 35c99fb5f9SBaptiste Daroussin unsigned int column; 36c99fb5f9SBaptiste Daroussin size_t remain; 37c99fb5f9SBaptiste Daroussin const unsigned char *pos; 38c99fb5f9SBaptiste Daroussin }; 39c99fb5f9SBaptiste Daroussin 40c99fb5f9SBaptiste Daroussin /** 41c99fb5f9SBaptiste Daroussin * Move up to len characters 42c99fb5f9SBaptiste Daroussin * @param parser 43c99fb5f9SBaptiste Daroussin * @param begin 44c99fb5f9SBaptiste Daroussin * @param len 45c99fb5f9SBaptiste Daroussin * @return new position in chunk 46c99fb5f9SBaptiste Daroussin */ 47c99fb5f9SBaptiste Daroussin #define ucl_chunk_skipc(chunk, p) do{ \ 48c99fb5f9SBaptiste Daroussin if (*(p) == '\n') { \ 49c99fb5f9SBaptiste Daroussin (chunk)->line ++; \ 50c99fb5f9SBaptiste Daroussin (chunk)->column = 0; \ 51c99fb5f9SBaptiste Daroussin } \ 52c99fb5f9SBaptiste Daroussin else (chunk)->column ++; \ 53c99fb5f9SBaptiste Daroussin (p++); \ 54c99fb5f9SBaptiste Daroussin (chunk)->pos ++; \ 55c99fb5f9SBaptiste Daroussin (chunk)->remain --; \ 56c99fb5f9SBaptiste Daroussin } while (0) 57c99fb5f9SBaptiste Daroussin 58c99fb5f9SBaptiste Daroussin /** 59c99fb5f9SBaptiste Daroussin * Save parser state 60c99fb5f9SBaptiste Daroussin * @param chunk 61c99fb5f9SBaptiste Daroussin * @param s 62c99fb5f9SBaptiste Daroussin */ 63c99fb5f9SBaptiste Daroussin static inline void 64c99fb5f9SBaptiste Daroussin ucl_chunk_save_state (struct ucl_chunk *chunk, struct ucl_parser_saved_state *s) 65c99fb5f9SBaptiste Daroussin { 66c99fb5f9SBaptiste Daroussin s->column = chunk->column; 67c99fb5f9SBaptiste Daroussin s->pos = chunk->pos; 68c99fb5f9SBaptiste Daroussin s->line = chunk->line; 69c99fb5f9SBaptiste Daroussin s->remain = chunk->remain; 70c99fb5f9SBaptiste Daroussin } 71c99fb5f9SBaptiste Daroussin 72c99fb5f9SBaptiste Daroussin /** 73c99fb5f9SBaptiste Daroussin * Restore parser state 74c99fb5f9SBaptiste Daroussin * @param chunk 75c99fb5f9SBaptiste Daroussin * @param s 76c99fb5f9SBaptiste Daroussin */ 77c99fb5f9SBaptiste Daroussin static inline void 78c99fb5f9SBaptiste Daroussin ucl_chunk_restore_state (struct ucl_chunk *chunk, struct ucl_parser_saved_state *s) 79c99fb5f9SBaptiste Daroussin { 80c99fb5f9SBaptiste Daroussin chunk->column = s->column; 81c99fb5f9SBaptiste Daroussin chunk->pos = s->pos; 82c99fb5f9SBaptiste Daroussin chunk->line = s->line; 83c99fb5f9SBaptiste Daroussin chunk->remain = s->remain; 84c99fb5f9SBaptiste Daroussin } 85c99fb5f9SBaptiste Daroussin 86c99fb5f9SBaptiste Daroussin static inline void 87c99fb5f9SBaptiste Daroussin ucl_set_err (struct ucl_chunk *chunk, int code, const char *str, UT_string **err) 88c99fb5f9SBaptiste Daroussin { 89c99fb5f9SBaptiste Daroussin if (chunk->pos < chunk->end) { 90c99fb5f9SBaptiste Daroussin if (isgraph (*chunk->pos)) { 91c99fb5f9SBaptiste Daroussin ucl_create_err (err, "error on line %d at column %d: '%s', character: '%c'", 92c99fb5f9SBaptiste Daroussin chunk->line, chunk->column, str, *chunk->pos); 93c99fb5f9SBaptiste Daroussin } 94c99fb5f9SBaptiste Daroussin else { 95c99fb5f9SBaptiste Daroussin ucl_create_err (err, "error on line %d at column %d: '%s', character: '0x%02x'", 96c99fb5f9SBaptiste Daroussin chunk->line, chunk->column, str, (int)*chunk->pos); 97c99fb5f9SBaptiste Daroussin } 98c99fb5f9SBaptiste Daroussin } 99c99fb5f9SBaptiste Daroussin else { 100c99fb5f9SBaptiste Daroussin ucl_create_err (err, "error at the end of chunk: %s", str); 101c99fb5f9SBaptiste Daroussin } 102c99fb5f9SBaptiste Daroussin } 103c99fb5f9SBaptiste Daroussin 104c99fb5f9SBaptiste Daroussin /** 105c99fb5f9SBaptiste Daroussin * Skip all comments from the current pos resolving nested and multiline comments 106c99fb5f9SBaptiste Daroussin * @param parser 107c99fb5f9SBaptiste Daroussin * @return 108c99fb5f9SBaptiste Daroussin */ 109c99fb5f9SBaptiste Daroussin static bool 110c99fb5f9SBaptiste Daroussin ucl_skip_comments (struct ucl_parser *parser) 111c99fb5f9SBaptiste Daroussin { 112c99fb5f9SBaptiste Daroussin struct ucl_chunk *chunk = parser->chunks; 113c99fb5f9SBaptiste Daroussin const unsigned char *p; 114c99fb5f9SBaptiste Daroussin int comments_nested = 0; 115c99fb5f9SBaptiste Daroussin 116c99fb5f9SBaptiste Daroussin p = chunk->pos; 117c99fb5f9SBaptiste Daroussin 118c99fb5f9SBaptiste Daroussin start: 119c99fb5f9SBaptiste Daroussin if (*p == '#') { 120c99fb5f9SBaptiste Daroussin if (parser->state != UCL_STATE_SCOMMENT && 121c99fb5f9SBaptiste Daroussin parser->state != UCL_STATE_MCOMMENT) { 122c99fb5f9SBaptiste Daroussin while (p < chunk->end) { 123c99fb5f9SBaptiste Daroussin if (*p == '\n') { 124c99fb5f9SBaptiste Daroussin ucl_chunk_skipc (chunk, p); 125c99fb5f9SBaptiste Daroussin goto start; 126c99fb5f9SBaptiste Daroussin } 127c99fb5f9SBaptiste Daroussin ucl_chunk_skipc (chunk, p); 128c99fb5f9SBaptiste Daroussin } 129c99fb5f9SBaptiste Daroussin } 130c99fb5f9SBaptiste Daroussin } 131c99fb5f9SBaptiste Daroussin else if (*p == '/' && chunk->remain >= 2) { 132c99fb5f9SBaptiste Daroussin if (p[1] == '*') { 133c99fb5f9SBaptiste Daroussin ucl_chunk_skipc (chunk, p); 134c99fb5f9SBaptiste Daroussin comments_nested ++; 135c99fb5f9SBaptiste Daroussin ucl_chunk_skipc (chunk, p); 136c99fb5f9SBaptiste Daroussin 137c99fb5f9SBaptiste Daroussin while (p < chunk->end) { 138c99fb5f9SBaptiste Daroussin if (*p == '*') { 139c99fb5f9SBaptiste Daroussin ucl_chunk_skipc (chunk, p); 140c99fb5f9SBaptiste Daroussin if (*p == '/') { 141c99fb5f9SBaptiste Daroussin comments_nested --; 142c99fb5f9SBaptiste Daroussin if (comments_nested == 0) { 143c99fb5f9SBaptiste Daroussin ucl_chunk_skipc (chunk, p); 144c99fb5f9SBaptiste Daroussin goto start; 145c99fb5f9SBaptiste Daroussin } 146c99fb5f9SBaptiste Daroussin } 147c99fb5f9SBaptiste Daroussin ucl_chunk_skipc (chunk, p); 148c99fb5f9SBaptiste Daroussin } 149c99fb5f9SBaptiste Daroussin else if (p[0] == '/' && chunk->remain >= 2 && p[1] == '*') { 150c99fb5f9SBaptiste Daroussin comments_nested ++; 151c99fb5f9SBaptiste Daroussin ucl_chunk_skipc (chunk, p); 152c99fb5f9SBaptiste Daroussin ucl_chunk_skipc (chunk, p); 153c99fb5f9SBaptiste Daroussin continue; 154c99fb5f9SBaptiste Daroussin } 155c99fb5f9SBaptiste Daroussin ucl_chunk_skipc (chunk, p); 156c99fb5f9SBaptiste Daroussin } 157c99fb5f9SBaptiste Daroussin if (comments_nested != 0) { 158c99fb5f9SBaptiste Daroussin ucl_set_err (chunk, UCL_ENESTED, "unfinished multiline comment", &parser->err); 159c99fb5f9SBaptiste Daroussin return false; 160c99fb5f9SBaptiste Daroussin } 161c99fb5f9SBaptiste Daroussin } 162c99fb5f9SBaptiste Daroussin } 163c99fb5f9SBaptiste Daroussin 164c99fb5f9SBaptiste Daroussin return true; 165c99fb5f9SBaptiste Daroussin } 166c99fb5f9SBaptiste Daroussin 167c99fb5f9SBaptiste Daroussin /** 168c99fb5f9SBaptiste Daroussin * Return multiplier for a character 169c99fb5f9SBaptiste Daroussin * @param c multiplier character 170c99fb5f9SBaptiste Daroussin * @param is_bytes if true use 1024 multiplier 171c99fb5f9SBaptiste Daroussin * @return multiplier 172c99fb5f9SBaptiste Daroussin */ 173c99fb5f9SBaptiste Daroussin static inline unsigned long 174c99fb5f9SBaptiste Daroussin ucl_lex_num_multiplier (const unsigned char c, bool is_bytes) { 175c99fb5f9SBaptiste Daroussin const struct { 176c99fb5f9SBaptiste Daroussin char c; 177c99fb5f9SBaptiste Daroussin long mult_normal; 178c99fb5f9SBaptiste Daroussin long mult_bytes; 179c99fb5f9SBaptiste Daroussin } multipliers[] = { 180c99fb5f9SBaptiste Daroussin {'m', 1000 * 1000, 1024 * 1024}, 181c99fb5f9SBaptiste Daroussin {'k', 1000, 1024}, 182c99fb5f9SBaptiste Daroussin {'g', 1000 * 1000 * 1000, 1024 * 1024 * 1024} 183c99fb5f9SBaptiste Daroussin }; 184c99fb5f9SBaptiste Daroussin int i; 185c99fb5f9SBaptiste Daroussin 186c99fb5f9SBaptiste Daroussin for (i = 0; i < 3; i ++) { 187c99fb5f9SBaptiste Daroussin if (tolower (c) == multipliers[i].c) { 188c99fb5f9SBaptiste Daroussin if (is_bytes) { 189c99fb5f9SBaptiste Daroussin return multipliers[i].mult_bytes; 190c99fb5f9SBaptiste Daroussin } 191c99fb5f9SBaptiste Daroussin return multipliers[i].mult_normal; 192c99fb5f9SBaptiste Daroussin } 193c99fb5f9SBaptiste Daroussin } 194c99fb5f9SBaptiste Daroussin 195c99fb5f9SBaptiste Daroussin return 1; 196c99fb5f9SBaptiste Daroussin } 197c99fb5f9SBaptiste Daroussin 198c99fb5f9SBaptiste Daroussin 199c99fb5f9SBaptiste Daroussin /** 200c99fb5f9SBaptiste Daroussin * Return multiplier for time scaling 201c99fb5f9SBaptiste Daroussin * @param c 202c99fb5f9SBaptiste Daroussin * @return 203c99fb5f9SBaptiste Daroussin */ 204c99fb5f9SBaptiste Daroussin static inline double 205c99fb5f9SBaptiste Daroussin ucl_lex_time_multiplier (const unsigned char c) { 206c99fb5f9SBaptiste Daroussin const struct { 207c99fb5f9SBaptiste Daroussin char c; 208c99fb5f9SBaptiste Daroussin double mult; 209c99fb5f9SBaptiste Daroussin } multipliers[] = { 210c99fb5f9SBaptiste Daroussin {'m', 60}, 211c99fb5f9SBaptiste Daroussin {'h', 60 * 60}, 212c99fb5f9SBaptiste Daroussin {'d', 60 * 60 * 24}, 213c99fb5f9SBaptiste Daroussin {'w', 60 * 60 * 24 * 7}, 214c99fb5f9SBaptiste Daroussin {'y', 60 * 60 * 24 * 7 * 365} 215c99fb5f9SBaptiste Daroussin }; 216c99fb5f9SBaptiste Daroussin int i; 217c99fb5f9SBaptiste Daroussin 218c99fb5f9SBaptiste Daroussin for (i = 0; i < 5; i ++) { 219c99fb5f9SBaptiste Daroussin if (tolower (c) == multipliers[i].c) { 220c99fb5f9SBaptiste Daroussin return multipliers[i].mult; 221c99fb5f9SBaptiste Daroussin } 222c99fb5f9SBaptiste Daroussin } 223c99fb5f9SBaptiste Daroussin 224c99fb5f9SBaptiste Daroussin return 1; 225c99fb5f9SBaptiste Daroussin } 226c99fb5f9SBaptiste Daroussin 227c99fb5f9SBaptiste Daroussin /** 228c99fb5f9SBaptiste Daroussin * Return true if a character is a end of an atom 229c99fb5f9SBaptiste Daroussin * @param c 230c99fb5f9SBaptiste Daroussin * @return 231c99fb5f9SBaptiste Daroussin */ 232c99fb5f9SBaptiste Daroussin static inline bool 233c99fb5f9SBaptiste Daroussin ucl_lex_is_atom_end (const unsigned char c) 234c99fb5f9SBaptiste Daroussin { 235c99fb5f9SBaptiste Daroussin return ucl_test_character (c, UCL_CHARACTER_VALUE_END); 236c99fb5f9SBaptiste Daroussin } 237c99fb5f9SBaptiste Daroussin 238c99fb5f9SBaptiste Daroussin static inline bool 239c99fb5f9SBaptiste Daroussin ucl_lex_is_comment (const unsigned char c1, const unsigned char c2) 240c99fb5f9SBaptiste Daroussin { 241c99fb5f9SBaptiste Daroussin if (c1 == '/') { 242c99fb5f9SBaptiste Daroussin if (c2 == '*') { 243c99fb5f9SBaptiste Daroussin return true; 244c99fb5f9SBaptiste Daroussin } 245c99fb5f9SBaptiste Daroussin } 246c99fb5f9SBaptiste Daroussin else if (c1 == '#') { 247c99fb5f9SBaptiste Daroussin return true; 248c99fb5f9SBaptiste Daroussin } 249c99fb5f9SBaptiste Daroussin return false; 250c99fb5f9SBaptiste Daroussin } 251c99fb5f9SBaptiste Daroussin 252c99fb5f9SBaptiste Daroussin /** 253c99fb5f9SBaptiste Daroussin * Check variable found 254c99fb5f9SBaptiste Daroussin * @param parser 255c99fb5f9SBaptiste Daroussin * @param ptr 256c99fb5f9SBaptiste Daroussin * @param remain 257c99fb5f9SBaptiste Daroussin * @param out_len 258c99fb5f9SBaptiste Daroussin * @param strict 259c99fb5f9SBaptiste Daroussin * @param found 260c99fb5f9SBaptiste Daroussin * @return 261c99fb5f9SBaptiste Daroussin */ 262c99fb5f9SBaptiste Daroussin static inline const char * 263c99fb5f9SBaptiste Daroussin ucl_check_variable_safe (struct ucl_parser *parser, const char *ptr, size_t remain, 264c99fb5f9SBaptiste Daroussin size_t *out_len, bool strict, bool *found) 265c99fb5f9SBaptiste Daroussin { 266c99fb5f9SBaptiste Daroussin struct ucl_variable *var; 267c99fb5f9SBaptiste Daroussin 268c99fb5f9SBaptiste Daroussin LL_FOREACH (parser->variables, var) { 269c99fb5f9SBaptiste Daroussin if (strict) { 270c99fb5f9SBaptiste Daroussin if (remain == var->var_len) { 271c99fb5f9SBaptiste Daroussin if (memcmp (ptr, var->var, var->var_len) == 0) { 272c99fb5f9SBaptiste Daroussin *out_len += var->value_len; 273c99fb5f9SBaptiste Daroussin *found = true; 274c99fb5f9SBaptiste Daroussin return (ptr + var->var_len); 275c99fb5f9SBaptiste Daroussin } 276c99fb5f9SBaptiste Daroussin } 277c99fb5f9SBaptiste Daroussin } 278c99fb5f9SBaptiste Daroussin else { 279c99fb5f9SBaptiste Daroussin if (remain >= var->var_len) { 280c99fb5f9SBaptiste Daroussin if (memcmp (ptr, var->var, var->var_len) == 0) { 281c99fb5f9SBaptiste Daroussin *out_len += var->value_len; 282c99fb5f9SBaptiste Daroussin *found = true; 283c99fb5f9SBaptiste Daroussin return (ptr + var->var_len); 284c99fb5f9SBaptiste Daroussin } 285c99fb5f9SBaptiste Daroussin } 286c99fb5f9SBaptiste Daroussin } 287c99fb5f9SBaptiste Daroussin } 288c99fb5f9SBaptiste Daroussin 289c99fb5f9SBaptiste Daroussin return ptr; 290c99fb5f9SBaptiste Daroussin } 291c99fb5f9SBaptiste Daroussin 292c99fb5f9SBaptiste Daroussin /** 293c99fb5f9SBaptiste Daroussin * Check for a variable in a given string 294c99fb5f9SBaptiste Daroussin * @param parser 295c99fb5f9SBaptiste Daroussin * @param ptr 296c99fb5f9SBaptiste Daroussin * @param remain 297c99fb5f9SBaptiste Daroussin * @param out_len 298c99fb5f9SBaptiste Daroussin * @param vars_found 299c99fb5f9SBaptiste Daroussin * @return 300c99fb5f9SBaptiste Daroussin */ 301c99fb5f9SBaptiste Daroussin static const char * 302c99fb5f9SBaptiste Daroussin ucl_check_variable (struct ucl_parser *parser, const char *ptr, size_t remain, size_t *out_len, bool *vars_found) 303c99fb5f9SBaptiste Daroussin { 304c99fb5f9SBaptiste Daroussin const char *p, *end, *ret = ptr; 305c99fb5f9SBaptiste Daroussin bool found = false; 306c99fb5f9SBaptiste Daroussin 307c99fb5f9SBaptiste Daroussin if (*ptr == '{') { 308c99fb5f9SBaptiste Daroussin /* We need to match the variable enclosed in braces */ 309c99fb5f9SBaptiste Daroussin p = ptr + 1; 310c99fb5f9SBaptiste Daroussin end = ptr + remain; 311c99fb5f9SBaptiste Daroussin while (p < end) { 312c99fb5f9SBaptiste Daroussin if (*p == '}') { 313c99fb5f9SBaptiste Daroussin ret = ucl_check_variable_safe (parser, ptr + 1, p - ptr - 1, out_len, true, &found); 314c99fb5f9SBaptiste Daroussin if (found) { 315c99fb5f9SBaptiste Daroussin /* {} must be excluded actually */ 316c99fb5f9SBaptiste Daroussin ret ++; 317c99fb5f9SBaptiste Daroussin if (!*vars_found) { 318c99fb5f9SBaptiste Daroussin *vars_found = true; 319c99fb5f9SBaptiste Daroussin } 320c99fb5f9SBaptiste Daroussin } 321c99fb5f9SBaptiste Daroussin else { 322c99fb5f9SBaptiste Daroussin *out_len += 2; 323c99fb5f9SBaptiste Daroussin } 324c99fb5f9SBaptiste Daroussin break; 325c99fb5f9SBaptiste Daroussin } 326c99fb5f9SBaptiste Daroussin p ++; 327c99fb5f9SBaptiste Daroussin } 328c99fb5f9SBaptiste Daroussin } 329c99fb5f9SBaptiste Daroussin else if (*ptr != '$') { 330c99fb5f9SBaptiste Daroussin /* Not count escaped dollar sign */ 331c99fb5f9SBaptiste Daroussin ret = ucl_check_variable_safe (parser, ptr, remain, out_len, false, &found); 332c99fb5f9SBaptiste Daroussin if (found && !*vars_found) { 333c99fb5f9SBaptiste Daroussin *vars_found = true; 334c99fb5f9SBaptiste Daroussin } 335c99fb5f9SBaptiste Daroussin if (!found) { 336c99fb5f9SBaptiste Daroussin (*out_len) ++; 337c99fb5f9SBaptiste Daroussin } 338c99fb5f9SBaptiste Daroussin } 339c99fb5f9SBaptiste Daroussin else { 340c99fb5f9SBaptiste Daroussin ret ++; 341c99fb5f9SBaptiste Daroussin (*out_len) ++; 342c99fb5f9SBaptiste Daroussin } 343c99fb5f9SBaptiste Daroussin 344c99fb5f9SBaptiste Daroussin return ret; 345c99fb5f9SBaptiste Daroussin } 346c99fb5f9SBaptiste Daroussin 347c99fb5f9SBaptiste Daroussin /** 348c99fb5f9SBaptiste Daroussin * Expand a single variable 349c99fb5f9SBaptiste Daroussin * @param parser 350c99fb5f9SBaptiste Daroussin * @param ptr 351c99fb5f9SBaptiste Daroussin * @param remain 352c99fb5f9SBaptiste Daroussin * @param dest 353c99fb5f9SBaptiste Daroussin * @return 354c99fb5f9SBaptiste Daroussin */ 355c99fb5f9SBaptiste Daroussin static const char * 356c99fb5f9SBaptiste Daroussin ucl_expand_single_variable (struct ucl_parser *parser, const char *ptr, 357c99fb5f9SBaptiste Daroussin size_t remain, unsigned char **dest) 358c99fb5f9SBaptiste Daroussin { 359c99fb5f9SBaptiste Daroussin unsigned char *d = *dest; 360c99fb5f9SBaptiste Daroussin const char *p = ptr + 1, *ret; 361c99fb5f9SBaptiste Daroussin struct ucl_variable *var; 362c99fb5f9SBaptiste Daroussin bool found = false; 363c99fb5f9SBaptiste Daroussin 364c99fb5f9SBaptiste Daroussin ret = ptr + 1; 365c99fb5f9SBaptiste Daroussin remain --; 366c99fb5f9SBaptiste Daroussin 367c99fb5f9SBaptiste Daroussin if (*p == '$') { 368c99fb5f9SBaptiste Daroussin *d++ = *p++; 369c99fb5f9SBaptiste Daroussin *dest = d; 370c99fb5f9SBaptiste Daroussin return p; 371c99fb5f9SBaptiste Daroussin } 372c99fb5f9SBaptiste Daroussin else if (*p == '{') { 373c99fb5f9SBaptiste Daroussin p ++; 374c99fb5f9SBaptiste Daroussin ret += 2; 375c99fb5f9SBaptiste Daroussin remain -= 2; 376c99fb5f9SBaptiste Daroussin } 377c99fb5f9SBaptiste Daroussin 378c99fb5f9SBaptiste Daroussin LL_FOREACH (parser->variables, var) { 379c99fb5f9SBaptiste Daroussin if (remain >= var->var_len) { 380c99fb5f9SBaptiste Daroussin if (memcmp (p, var->var, var->var_len) == 0) { 381c99fb5f9SBaptiste Daroussin memcpy (d, var->value, var->value_len); 382c99fb5f9SBaptiste Daroussin ret += var->var_len; 383c99fb5f9SBaptiste Daroussin d += var->value_len; 384c99fb5f9SBaptiste Daroussin found = true; 385c99fb5f9SBaptiste Daroussin break; 386c99fb5f9SBaptiste Daroussin } 387c99fb5f9SBaptiste Daroussin } 388c99fb5f9SBaptiste Daroussin } 389c99fb5f9SBaptiste Daroussin if (!found) { 390c99fb5f9SBaptiste Daroussin memcpy (d, ptr, 2); 391c99fb5f9SBaptiste Daroussin d += 2; 392c99fb5f9SBaptiste Daroussin ret --; 393c99fb5f9SBaptiste Daroussin } 394c99fb5f9SBaptiste Daroussin 395c99fb5f9SBaptiste Daroussin *dest = d; 396c99fb5f9SBaptiste Daroussin return ret; 397c99fb5f9SBaptiste Daroussin } 398c99fb5f9SBaptiste Daroussin 399c99fb5f9SBaptiste Daroussin /** 400c99fb5f9SBaptiste Daroussin * Expand variables in string 401c99fb5f9SBaptiste Daroussin * @param parser 402c99fb5f9SBaptiste Daroussin * @param dst 403c99fb5f9SBaptiste Daroussin * @param src 404c99fb5f9SBaptiste Daroussin * @param in_len 405c99fb5f9SBaptiste Daroussin * @return 406c99fb5f9SBaptiste Daroussin */ 407c99fb5f9SBaptiste Daroussin static ssize_t 408c99fb5f9SBaptiste Daroussin ucl_expand_variable (struct ucl_parser *parser, unsigned char **dst, 409c99fb5f9SBaptiste Daroussin const char *src, size_t in_len) 410c99fb5f9SBaptiste Daroussin { 411c99fb5f9SBaptiste Daroussin const char *p, *end = src + in_len; 412c99fb5f9SBaptiste Daroussin unsigned char *d; 413c99fb5f9SBaptiste Daroussin size_t out_len = 0; 414c99fb5f9SBaptiste Daroussin bool vars_found = false; 415c99fb5f9SBaptiste Daroussin 416c99fb5f9SBaptiste Daroussin p = src; 417c99fb5f9SBaptiste Daroussin while (p != end) { 418c99fb5f9SBaptiste Daroussin if (*p == '$') { 419c99fb5f9SBaptiste Daroussin p = ucl_check_variable (parser, p + 1, end - p - 1, &out_len, &vars_found); 420c99fb5f9SBaptiste Daroussin } 421c99fb5f9SBaptiste Daroussin else { 422c99fb5f9SBaptiste Daroussin p ++; 423c99fb5f9SBaptiste Daroussin out_len ++; 424c99fb5f9SBaptiste Daroussin } 425c99fb5f9SBaptiste Daroussin } 426c99fb5f9SBaptiste Daroussin 427c99fb5f9SBaptiste Daroussin if (!vars_found) { 428c99fb5f9SBaptiste Daroussin /* Trivial case */ 429c99fb5f9SBaptiste Daroussin *dst = NULL; 430c99fb5f9SBaptiste Daroussin return in_len; 431c99fb5f9SBaptiste Daroussin } 432c99fb5f9SBaptiste Daroussin 433c99fb5f9SBaptiste Daroussin *dst = UCL_ALLOC (out_len + 1); 434c99fb5f9SBaptiste Daroussin if (*dst == NULL) { 435c99fb5f9SBaptiste Daroussin return in_len; 436c99fb5f9SBaptiste Daroussin } 437c99fb5f9SBaptiste Daroussin 438c99fb5f9SBaptiste Daroussin d = *dst; 439c99fb5f9SBaptiste Daroussin p = src; 440c99fb5f9SBaptiste Daroussin while (p != end) { 441c99fb5f9SBaptiste Daroussin if (*p == '$') { 442c99fb5f9SBaptiste Daroussin p = ucl_expand_single_variable (parser, p, end - p, &d); 443c99fb5f9SBaptiste Daroussin } 444c99fb5f9SBaptiste Daroussin else { 445c99fb5f9SBaptiste Daroussin *d++ = *p++; 446c99fb5f9SBaptiste Daroussin } 447c99fb5f9SBaptiste Daroussin } 448c99fb5f9SBaptiste Daroussin 449c99fb5f9SBaptiste Daroussin *d = '\0'; 450c99fb5f9SBaptiste Daroussin 451c99fb5f9SBaptiste Daroussin return out_len; 452c99fb5f9SBaptiste Daroussin } 453c99fb5f9SBaptiste Daroussin 454c99fb5f9SBaptiste Daroussin /** 455c99fb5f9SBaptiste Daroussin * Store or copy pointer to the trash stack 456c99fb5f9SBaptiste Daroussin * @param parser parser object 457c99fb5f9SBaptiste Daroussin * @param src src string 458c99fb5f9SBaptiste Daroussin * @param dst destination buffer (trash stack pointer) 459c99fb5f9SBaptiste Daroussin * @param dst_const const destination pointer (e.g. value of object) 460c99fb5f9SBaptiste Daroussin * @param in_len input length 461c99fb5f9SBaptiste Daroussin * @param need_unescape need to unescape source (and copy it) 462c99fb5f9SBaptiste Daroussin * @param need_lowercase need to lowercase value (and copy) 463c99fb5f9SBaptiste Daroussin * @param need_expand need to expand variables (and copy as well) 464c99fb5f9SBaptiste Daroussin * @return output length (excluding \0 symbol) 465c99fb5f9SBaptiste Daroussin */ 466c99fb5f9SBaptiste Daroussin static inline ssize_t 467c99fb5f9SBaptiste Daroussin ucl_copy_or_store_ptr (struct ucl_parser *parser, 468c99fb5f9SBaptiste Daroussin const unsigned char *src, unsigned char **dst, 469c99fb5f9SBaptiste Daroussin const char **dst_const, size_t in_len, 470c99fb5f9SBaptiste Daroussin bool need_unescape, bool need_lowercase, bool need_expand) 471c99fb5f9SBaptiste Daroussin { 472c99fb5f9SBaptiste Daroussin ssize_t ret = -1, tret; 473c99fb5f9SBaptiste Daroussin unsigned char *tmp; 474c99fb5f9SBaptiste Daroussin 475c99fb5f9SBaptiste Daroussin if (need_unescape || need_lowercase || 476c99fb5f9SBaptiste Daroussin (need_expand && parser->variables != NULL) || 477c99fb5f9SBaptiste Daroussin !(parser->flags & UCL_PARSER_ZEROCOPY)) { 478c99fb5f9SBaptiste Daroussin /* Copy string */ 479c99fb5f9SBaptiste Daroussin *dst = UCL_ALLOC (in_len + 1); 480c99fb5f9SBaptiste Daroussin if (*dst == NULL) { 481c99fb5f9SBaptiste Daroussin ucl_set_err (parser->chunks, 0, "cannot allocate memory for a string", &parser->err); 482c99fb5f9SBaptiste Daroussin return false; 483c99fb5f9SBaptiste Daroussin } 484c99fb5f9SBaptiste Daroussin if (need_lowercase) { 485c99fb5f9SBaptiste Daroussin ret = ucl_strlcpy_tolower (*dst, src, in_len + 1); 486c99fb5f9SBaptiste Daroussin } 487c99fb5f9SBaptiste Daroussin else { 488c99fb5f9SBaptiste Daroussin ret = ucl_strlcpy_unsafe (*dst, src, in_len + 1); 489c99fb5f9SBaptiste Daroussin } 490c99fb5f9SBaptiste Daroussin 491c99fb5f9SBaptiste Daroussin if (need_unescape) { 492c99fb5f9SBaptiste Daroussin ret = ucl_unescape_json_string (*dst, ret); 493c99fb5f9SBaptiste Daroussin } 494c99fb5f9SBaptiste Daroussin if (need_expand) { 495c99fb5f9SBaptiste Daroussin tmp = *dst; 496c99fb5f9SBaptiste Daroussin tret = ret; 497c99fb5f9SBaptiste Daroussin ret = ucl_expand_variable (parser, dst, tmp, ret); 498c99fb5f9SBaptiste Daroussin if (*dst == NULL) { 499c99fb5f9SBaptiste Daroussin /* Nothing to expand */ 500c99fb5f9SBaptiste Daroussin *dst = tmp; 501c99fb5f9SBaptiste Daroussin ret = tret; 502c99fb5f9SBaptiste Daroussin } 503c99fb5f9SBaptiste Daroussin } 504c99fb5f9SBaptiste Daroussin *dst_const = *dst; 505c99fb5f9SBaptiste Daroussin } 506c99fb5f9SBaptiste Daroussin else { 507c99fb5f9SBaptiste Daroussin *dst_const = src; 508c99fb5f9SBaptiste Daroussin ret = in_len; 509c99fb5f9SBaptiste Daroussin } 510c99fb5f9SBaptiste Daroussin 511c99fb5f9SBaptiste Daroussin return ret; 512c99fb5f9SBaptiste Daroussin } 513c99fb5f9SBaptiste Daroussin 514c99fb5f9SBaptiste Daroussin /** 515c99fb5f9SBaptiste Daroussin * Create and append an object at the specified level 516c99fb5f9SBaptiste Daroussin * @param parser 517c99fb5f9SBaptiste Daroussin * @param is_array 518c99fb5f9SBaptiste Daroussin * @param level 519c99fb5f9SBaptiste Daroussin * @return 520c99fb5f9SBaptiste Daroussin */ 521c99fb5f9SBaptiste Daroussin static inline ucl_object_t * 522c99fb5f9SBaptiste Daroussin ucl_add_parser_stack (ucl_object_t *obj, struct ucl_parser *parser, bool is_array, int level) 523c99fb5f9SBaptiste Daroussin { 524c99fb5f9SBaptiste Daroussin struct ucl_stack *st; 525c99fb5f9SBaptiste Daroussin 526c99fb5f9SBaptiste Daroussin if (!is_array) { 527c99fb5f9SBaptiste Daroussin if (obj == NULL) { 528c99fb5f9SBaptiste Daroussin obj = ucl_object_typed_new (UCL_OBJECT); 529c99fb5f9SBaptiste Daroussin } 530c99fb5f9SBaptiste Daroussin else { 531c99fb5f9SBaptiste Daroussin obj->type = UCL_OBJECT; 532c99fb5f9SBaptiste Daroussin } 533c99fb5f9SBaptiste Daroussin obj->value.ov = ucl_hash_create (); 534c99fb5f9SBaptiste Daroussin parser->state = UCL_STATE_KEY; 535c99fb5f9SBaptiste Daroussin } 536c99fb5f9SBaptiste Daroussin else { 537c99fb5f9SBaptiste Daroussin if (obj == NULL) { 538c99fb5f9SBaptiste Daroussin obj = ucl_object_typed_new (UCL_ARRAY); 539c99fb5f9SBaptiste Daroussin } 540c99fb5f9SBaptiste Daroussin else { 541c99fb5f9SBaptiste Daroussin obj->type = UCL_ARRAY; 542c99fb5f9SBaptiste Daroussin } 543c99fb5f9SBaptiste Daroussin parser->state = UCL_STATE_VALUE; 544c99fb5f9SBaptiste Daroussin } 545c99fb5f9SBaptiste Daroussin 546c99fb5f9SBaptiste Daroussin st = UCL_ALLOC (sizeof (struct ucl_stack)); 547c99fb5f9SBaptiste Daroussin st->obj = obj; 548c99fb5f9SBaptiste Daroussin st->level = level; 549c99fb5f9SBaptiste Daroussin LL_PREPEND (parser->stack, st); 550c99fb5f9SBaptiste Daroussin parser->cur_obj = obj; 551c99fb5f9SBaptiste Daroussin 552c99fb5f9SBaptiste Daroussin return obj; 553c99fb5f9SBaptiste Daroussin } 554c99fb5f9SBaptiste Daroussin 555c99fb5f9SBaptiste Daroussin int 556c99fb5f9SBaptiste Daroussin ucl_maybe_parse_number (ucl_object_t *obj, 557c99fb5f9SBaptiste Daroussin const char *start, const char *end, const char **pos, bool allow_double, bool number_bytes) 558c99fb5f9SBaptiste Daroussin { 559c99fb5f9SBaptiste Daroussin const char *p = start, *c = start; 560c99fb5f9SBaptiste Daroussin char *endptr; 561c99fb5f9SBaptiste Daroussin bool got_dot = false, got_exp = false, need_double = false, 562c99fb5f9SBaptiste Daroussin is_date = false, valid_start = false, is_hex = false, 563c99fb5f9SBaptiste Daroussin is_neg = false; 564c99fb5f9SBaptiste Daroussin double dv = 0; 565c99fb5f9SBaptiste Daroussin int64_t lv = 0; 566c99fb5f9SBaptiste Daroussin 567c99fb5f9SBaptiste Daroussin if (*p == '-') { 568c99fb5f9SBaptiste Daroussin is_neg = true; 569c99fb5f9SBaptiste Daroussin c ++; 570c99fb5f9SBaptiste Daroussin p ++; 571c99fb5f9SBaptiste Daroussin } 572c99fb5f9SBaptiste Daroussin while (p < end) { 573c99fb5f9SBaptiste Daroussin if (is_hex && isxdigit (*p)) { 574c99fb5f9SBaptiste Daroussin p ++; 575c99fb5f9SBaptiste Daroussin } 576c99fb5f9SBaptiste Daroussin else if (isdigit (*p)) { 577c99fb5f9SBaptiste Daroussin valid_start = true; 578c99fb5f9SBaptiste Daroussin p ++; 579c99fb5f9SBaptiste Daroussin } 580c99fb5f9SBaptiste Daroussin else if (!is_hex && (*p == 'x' || *p == 'X')) { 581c99fb5f9SBaptiste Daroussin is_hex = true; 582c99fb5f9SBaptiste Daroussin allow_double = false; 583c99fb5f9SBaptiste Daroussin c = p + 1; 584c99fb5f9SBaptiste Daroussin } 585c99fb5f9SBaptiste Daroussin else if (allow_double) { 586c99fb5f9SBaptiste Daroussin if (p == c) { 587c99fb5f9SBaptiste Daroussin /* Empty digits sequence, not a number */ 588c99fb5f9SBaptiste Daroussin *pos = start; 589c99fb5f9SBaptiste Daroussin return EINVAL; 590c99fb5f9SBaptiste Daroussin } 591c99fb5f9SBaptiste Daroussin else if (*p == '.') { 592c99fb5f9SBaptiste Daroussin if (got_dot) { 593c99fb5f9SBaptiste Daroussin /* Double dots, not a number */ 594c99fb5f9SBaptiste Daroussin *pos = start; 595c99fb5f9SBaptiste Daroussin return EINVAL; 596c99fb5f9SBaptiste Daroussin } 597c99fb5f9SBaptiste Daroussin else { 598c99fb5f9SBaptiste Daroussin got_dot = true; 599c99fb5f9SBaptiste Daroussin need_double = true; 600c99fb5f9SBaptiste Daroussin p ++; 601c99fb5f9SBaptiste Daroussin } 602c99fb5f9SBaptiste Daroussin } 603c99fb5f9SBaptiste Daroussin else if (*p == 'e' || *p == 'E') { 604c99fb5f9SBaptiste Daroussin if (got_exp) { 605c99fb5f9SBaptiste Daroussin /* Double exp, not a number */ 606c99fb5f9SBaptiste Daroussin *pos = start; 607c99fb5f9SBaptiste Daroussin return EINVAL; 608c99fb5f9SBaptiste Daroussin } 609c99fb5f9SBaptiste Daroussin else { 610c99fb5f9SBaptiste Daroussin got_exp = true; 611c99fb5f9SBaptiste Daroussin need_double = true; 612c99fb5f9SBaptiste Daroussin p ++; 613c99fb5f9SBaptiste Daroussin if (p >= end) { 614c99fb5f9SBaptiste Daroussin *pos = start; 615c99fb5f9SBaptiste Daroussin return EINVAL; 616c99fb5f9SBaptiste Daroussin } 617c99fb5f9SBaptiste Daroussin if (!isdigit (*p) && *p != '+' && *p != '-') { 618c99fb5f9SBaptiste Daroussin /* Wrong exponent sign */ 619c99fb5f9SBaptiste Daroussin *pos = start; 620c99fb5f9SBaptiste Daroussin return EINVAL; 621c99fb5f9SBaptiste Daroussin } 622c99fb5f9SBaptiste Daroussin else { 623c99fb5f9SBaptiste Daroussin p ++; 624c99fb5f9SBaptiste Daroussin } 625c99fb5f9SBaptiste Daroussin } 626c99fb5f9SBaptiste Daroussin } 627c99fb5f9SBaptiste Daroussin else { 628c99fb5f9SBaptiste Daroussin /* Got the end of the number, need to check */ 629c99fb5f9SBaptiste Daroussin break; 630c99fb5f9SBaptiste Daroussin } 631c99fb5f9SBaptiste Daroussin } 632c99fb5f9SBaptiste Daroussin else { 633c99fb5f9SBaptiste Daroussin break; 634c99fb5f9SBaptiste Daroussin } 635c99fb5f9SBaptiste Daroussin } 636c99fb5f9SBaptiste Daroussin 637c99fb5f9SBaptiste Daroussin if (!valid_start) { 638c99fb5f9SBaptiste Daroussin *pos = start; 639c99fb5f9SBaptiste Daroussin return EINVAL; 640c99fb5f9SBaptiste Daroussin } 641c99fb5f9SBaptiste Daroussin 642c99fb5f9SBaptiste Daroussin errno = 0; 643c99fb5f9SBaptiste Daroussin if (need_double) { 644c99fb5f9SBaptiste Daroussin dv = strtod (c, &endptr); 645c99fb5f9SBaptiste Daroussin } 646c99fb5f9SBaptiste Daroussin else { 647c99fb5f9SBaptiste Daroussin if (is_hex) { 648c99fb5f9SBaptiste Daroussin lv = strtoimax (c, &endptr, 16); 649c99fb5f9SBaptiste Daroussin } 650c99fb5f9SBaptiste Daroussin else { 651c99fb5f9SBaptiste Daroussin lv = strtoimax (c, &endptr, 10); 652c99fb5f9SBaptiste Daroussin } 653c99fb5f9SBaptiste Daroussin } 654c99fb5f9SBaptiste Daroussin if (errno == ERANGE) { 655c99fb5f9SBaptiste Daroussin *pos = start; 656c99fb5f9SBaptiste Daroussin return ERANGE; 657c99fb5f9SBaptiste Daroussin } 658c99fb5f9SBaptiste Daroussin 659c99fb5f9SBaptiste Daroussin /* Now check endptr */ 660c99fb5f9SBaptiste Daroussin if (endptr == NULL || ucl_lex_is_atom_end (*endptr) || *endptr == '\0') { 661c99fb5f9SBaptiste Daroussin p = endptr; 662c99fb5f9SBaptiste Daroussin goto set_obj; 663c99fb5f9SBaptiste Daroussin } 664c99fb5f9SBaptiste Daroussin 665c99fb5f9SBaptiste Daroussin if (endptr < end && endptr != start) { 666c99fb5f9SBaptiste Daroussin p = endptr; 667c99fb5f9SBaptiste Daroussin switch (*p) { 668c99fb5f9SBaptiste Daroussin case 'm': 669c99fb5f9SBaptiste Daroussin case 'M': 670c99fb5f9SBaptiste Daroussin case 'g': 671c99fb5f9SBaptiste Daroussin case 'G': 672c99fb5f9SBaptiste Daroussin case 'k': 673c99fb5f9SBaptiste Daroussin case 'K': 674c99fb5f9SBaptiste Daroussin if (end - p >= 2) { 675c99fb5f9SBaptiste Daroussin if (p[1] == 's' || p[1] == 'S') { 676c99fb5f9SBaptiste Daroussin /* Milliseconds */ 677c99fb5f9SBaptiste Daroussin if (!need_double) { 678c99fb5f9SBaptiste Daroussin need_double = true; 679c99fb5f9SBaptiste Daroussin dv = lv; 680c99fb5f9SBaptiste Daroussin } 681c99fb5f9SBaptiste Daroussin is_date = true; 682c99fb5f9SBaptiste Daroussin if (p[0] == 'm' || p[0] == 'M') { 683c99fb5f9SBaptiste Daroussin dv /= 1000.; 684c99fb5f9SBaptiste Daroussin } 685c99fb5f9SBaptiste Daroussin else { 686c99fb5f9SBaptiste Daroussin dv *= ucl_lex_num_multiplier (*p, false); 687c99fb5f9SBaptiste Daroussin } 688c99fb5f9SBaptiste Daroussin p += 2; 689c99fb5f9SBaptiste Daroussin goto set_obj; 690c99fb5f9SBaptiste Daroussin } 691c99fb5f9SBaptiste Daroussin else if (number_bytes || (p[1] == 'b' || p[1] == 'B')) { 692c99fb5f9SBaptiste Daroussin /* Bytes */ 693c99fb5f9SBaptiste Daroussin if (need_double) { 694c99fb5f9SBaptiste Daroussin need_double = false; 695c99fb5f9SBaptiste Daroussin lv = dv; 696c99fb5f9SBaptiste Daroussin } 697c99fb5f9SBaptiste Daroussin lv *= ucl_lex_num_multiplier (*p, true); 698c99fb5f9SBaptiste Daroussin p += 2; 699c99fb5f9SBaptiste Daroussin goto set_obj; 700c99fb5f9SBaptiste Daroussin } 701c99fb5f9SBaptiste Daroussin else if (ucl_lex_is_atom_end (p[1])) { 702c99fb5f9SBaptiste Daroussin if (need_double) { 703c99fb5f9SBaptiste Daroussin dv *= ucl_lex_num_multiplier (*p, false); 704c99fb5f9SBaptiste Daroussin } 705c99fb5f9SBaptiste Daroussin else { 706c99fb5f9SBaptiste Daroussin lv *= ucl_lex_num_multiplier (*p, number_bytes); 707c99fb5f9SBaptiste Daroussin } 708c99fb5f9SBaptiste Daroussin p ++; 709c99fb5f9SBaptiste Daroussin goto set_obj; 710c99fb5f9SBaptiste Daroussin } 711c99fb5f9SBaptiste Daroussin else if (end - p >= 3) { 712c99fb5f9SBaptiste Daroussin if (tolower (p[0]) == 'm' && 713c99fb5f9SBaptiste Daroussin tolower (p[1]) == 'i' && 714c99fb5f9SBaptiste Daroussin tolower (p[2]) == 'n') { 715c99fb5f9SBaptiste Daroussin /* Minutes */ 716c99fb5f9SBaptiste Daroussin if (!need_double) { 717c99fb5f9SBaptiste Daroussin need_double = true; 718c99fb5f9SBaptiste Daroussin dv = lv; 719c99fb5f9SBaptiste Daroussin } 720c99fb5f9SBaptiste Daroussin is_date = true; 721c99fb5f9SBaptiste Daroussin dv *= 60.; 722c99fb5f9SBaptiste Daroussin p += 3; 723c99fb5f9SBaptiste Daroussin goto set_obj; 724c99fb5f9SBaptiste Daroussin } 725c99fb5f9SBaptiste Daroussin } 726c99fb5f9SBaptiste Daroussin } 727c99fb5f9SBaptiste Daroussin else { 728c99fb5f9SBaptiste Daroussin if (need_double) { 729c99fb5f9SBaptiste Daroussin dv *= ucl_lex_num_multiplier (*p, false); 730c99fb5f9SBaptiste Daroussin } 731c99fb5f9SBaptiste Daroussin else { 732c99fb5f9SBaptiste Daroussin lv *= ucl_lex_num_multiplier (*p, number_bytes); 733c99fb5f9SBaptiste Daroussin } 734c99fb5f9SBaptiste Daroussin p ++; 735c99fb5f9SBaptiste Daroussin goto set_obj; 736c99fb5f9SBaptiste Daroussin } 737c99fb5f9SBaptiste Daroussin break; 738c99fb5f9SBaptiste Daroussin case 'S': 739c99fb5f9SBaptiste Daroussin case 's': 740c99fb5f9SBaptiste Daroussin if (p == end - 1 || ucl_lex_is_atom_end (p[1])) { 741c99fb5f9SBaptiste Daroussin if (!need_double) { 742c99fb5f9SBaptiste Daroussin need_double = true; 743c99fb5f9SBaptiste Daroussin dv = lv; 744c99fb5f9SBaptiste Daroussin } 745c99fb5f9SBaptiste Daroussin p ++; 746c99fb5f9SBaptiste Daroussin is_date = true; 747c99fb5f9SBaptiste Daroussin goto set_obj; 748c99fb5f9SBaptiste Daroussin } 749c99fb5f9SBaptiste Daroussin break; 750c99fb5f9SBaptiste Daroussin case 'h': 751c99fb5f9SBaptiste Daroussin case 'H': 752c99fb5f9SBaptiste Daroussin case 'd': 753c99fb5f9SBaptiste Daroussin case 'D': 754c99fb5f9SBaptiste Daroussin case 'w': 755c99fb5f9SBaptiste Daroussin case 'W': 756c99fb5f9SBaptiste Daroussin case 'Y': 757c99fb5f9SBaptiste Daroussin case 'y': 758c99fb5f9SBaptiste Daroussin if (p == end - 1 || ucl_lex_is_atom_end (p[1])) { 759c99fb5f9SBaptiste Daroussin if (!need_double) { 760c99fb5f9SBaptiste Daroussin need_double = true; 761c99fb5f9SBaptiste Daroussin dv = lv; 762c99fb5f9SBaptiste Daroussin } 763c99fb5f9SBaptiste Daroussin is_date = true; 764c99fb5f9SBaptiste Daroussin dv *= ucl_lex_time_multiplier (*p); 765c99fb5f9SBaptiste Daroussin p ++; 766c99fb5f9SBaptiste Daroussin goto set_obj; 767c99fb5f9SBaptiste Daroussin } 768c99fb5f9SBaptiste Daroussin break; 769c99fb5f9SBaptiste Daroussin } 770c99fb5f9SBaptiste Daroussin } 771c99fb5f9SBaptiste Daroussin 772c99fb5f9SBaptiste Daroussin *pos = c; 773c99fb5f9SBaptiste Daroussin return EINVAL; 774c99fb5f9SBaptiste Daroussin 775c99fb5f9SBaptiste Daroussin set_obj: 776c99fb5f9SBaptiste Daroussin if (allow_double && (need_double || is_date)) { 777c99fb5f9SBaptiste Daroussin if (!is_date) { 778c99fb5f9SBaptiste Daroussin obj->type = UCL_FLOAT; 779c99fb5f9SBaptiste Daroussin } 780c99fb5f9SBaptiste Daroussin else { 781c99fb5f9SBaptiste Daroussin obj->type = UCL_TIME; 782c99fb5f9SBaptiste Daroussin } 783c99fb5f9SBaptiste Daroussin obj->value.dv = is_neg ? (-dv) : dv; 784c99fb5f9SBaptiste Daroussin } 785c99fb5f9SBaptiste Daroussin else { 786c99fb5f9SBaptiste Daroussin obj->type = UCL_INT; 787c99fb5f9SBaptiste Daroussin obj->value.iv = is_neg ? (-lv) : lv; 788c99fb5f9SBaptiste Daroussin } 789c99fb5f9SBaptiste Daroussin *pos = p; 790c99fb5f9SBaptiste Daroussin return 0; 791c99fb5f9SBaptiste Daroussin } 792c99fb5f9SBaptiste Daroussin 793c99fb5f9SBaptiste Daroussin /** 794c99fb5f9SBaptiste Daroussin * Parse possible number 795c99fb5f9SBaptiste Daroussin * @param parser 796c99fb5f9SBaptiste Daroussin * @param chunk 797c99fb5f9SBaptiste Daroussin * @return true if a number has been parsed 798c99fb5f9SBaptiste Daroussin */ 799c99fb5f9SBaptiste Daroussin static bool 800c99fb5f9SBaptiste Daroussin ucl_lex_number (struct ucl_parser *parser, 801c99fb5f9SBaptiste Daroussin struct ucl_chunk *chunk, ucl_object_t *obj) 802c99fb5f9SBaptiste Daroussin { 803c99fb5f9SBaptiste Daroussin const unsigned char *pos; 804c99fb5f9SBaptiste Daroussin int ret; 805c99fb5f9SBaptiste Daroussin 806c99fb5f9SBaptiste Daroussin ret = ucl_maybe_parse_number (obj, chunk->pos, chunk->end, (const char **)&pos, true, false); 807c99fb5f9SBaptiste Daroussin 808c99fb5f9SBaptiste Daroussin if (ret == 0) { 809c99fb5f9SBaptiste Daroussin chunk->remain -= pos - chunk->pos; 810c99fb5f9SBaptiste Daroussin chunk->column += pos - chunk->pos; 811c99fb5f9SBaptiste Daroussin chunk->pos = pos; 812c99fb5f9SBaptiste Daroussin return true; 813c99fb5f9SBaptiste Daroussin } 814c99fb5f9SBaptiste Daroussin else if (ret == ERANGE) { 815c99fb5f9SBaptiste Daroussin ucl_set_err (chunk, ERANGE, "numeric value out of range", &parser->err); 816c99fb5f9SBaptiste Daroussin } 817c99fb5f9SBaptiste Daroussin 818c99fb5f9SBaptiste Daroussin return false; 819c99fb5f9SBaptiste Daroussin } 820c99fb5f9SBaptiste Daroussin 821c99fb5f9SBaptiste Daroussin /** 822c99fb5f9SBaptiste Daroussin * Parse quoted string with possible escapes 823c99fb5f9SBaptiste Daroussin * @param parser 824c99fb5f9SBaptiste Daroussin * @param chunk 825c99fb5f9SBaptiste Daroussin * @return true if a string has been parsed 826c99fb5f9SBaptiste Daroussin */ 827c99fb5f9SBaptiste Daroussin static bool 828c99fb5f9SBaptiste Daroussin ucl_lex_json_string (struct ucl_parser *parser, 829c99fb5f9SBaptiste Daroussin struct ucl_chunk *chunk, bool *need_unescape, bool *ucl_escape, bool *var_expand) 830c99fb5f9SBaptiste Daroussin { 831c99fb5f9SBaptiste Daroussin const unsigned char *p = chunk->pos; 832c99fb5f9SBaptiste Daroussin unsigned char c; 833c99fb5f9SBaptiste Daroussin int i; 834c99fb5f9SBaptiste Daroussin 835c99fb5f9SBaptiste Daroussin while (p < chunk->end) { 836c99fb5f9SBaptiste Daroussin c = *p; 837c99fb5f9SBaptiste Daroussin if (c < 0x1F) { 838c99fb5f9SBaptiste Daroussin /* Unmasked control character */ 839c99fb5f9SBaptiste Daroussin if (c == '\n') { 840c99fb5f9SBaptiste Daroussin ucl_set_err (chunk, UCL_ESYNTAX, "unexpected newline", &parser->err); 841c99fb5f9SBaptiste Daroussin } 842c99fb5f9SBaptiste Daroussin else { 843c99fb5f9SBaptiste Daroussin ucl_set_err (chunk, UCL_ESYNTAX, "unexpected control character", &parser->err); 844c99fb5f9SBaptiste Daroussin } 845c99fb5f9SBaptiste Daroussin return false; 846c99fb5f9SBaptiste Daroussin } 847c99fb5f9SBaptiste Daroussin else if (c == '\\') { 848c99fb5f9SBaptiste Daroussin ucl_chunk_skipc (chunk, p); 849c99fb5f9SBaptiste Daroussin c = *p; 850c99fb5f9SBaptiste Daroussin if (p >= chunk->end) { 851c99fb5f9SBaptiste Daroussin ucl_set_err (chunk, UCL_ESYNTAX, "unfinished escape character", &parser->err); 852c99fb5f9SBaptiste Daroussin return false; 853c99fb5f9SBaptiste Daroussin } 854c99fb5f9SBaptiste Daroussin else if (ucl_test_character (c, UCL_CHARACTER_ESCAPE)) { 855c99fb5f9SBaptiste Daroussin if (c == 'u') { 856c99fb5f9SBaptiste Daroussin ucl_chunk_skipc (chunk, p); 857c99fb5f9SBaptiste Daroussin for (i = 0; i < 4 && p < chunk->end; i ++) { 858c99fb5f9SBaptiste Daroussin if (!isxdigit (*p)) { 859c99fb5f9SBaptiste Daroussin ucl_set_err (chunk, UCL_ESYNTAX, "invalid utf escape", &parser->err); 860c99fb5f9SBaptiste Daroussin return false; 861c99fb5f9SBaptiste Daroussin } 862c99fb5f9SBaptiste Daroussin ucl_chunk_skipc (chunk, p); 863c99fb5f9SBaptiste Daroussin } 864c99fb5f9SBaptiste Daroussin if (p >= chunk->end) { 865c99fb5f9SBaptiste Daroussin ucl_set_err (chunk, UCL_ESYNTAX, "unfinished escape character", &parser->err); 866c99fb5f9SBaptiste Daroussin return false; 867c99fb5f9SBaptiste Daroussin } 868c99fb5f9SBaptiste Daroussin } 869c99fb5f9SBaptiste Daroussin else { 870c99fb5f9SBaptiste Daroussin ucl_chunk_skipc (chunk, p); 871c99fb5f9SBaptiste Daroussin } 872c99fb5f9SBaptiste Daroussin } 873c99fb5f9SBaptiste Daroussin *need_unescape = true; 874c99fb5f9SBaptiste Daroussin *ucl_escape = true; 875c99fb5f9SBaptiste Daroussin continue; 876c99fb5f9SBaptiste Daroussin } 877c99fb5f9SBaptiste Daroussin else if (c == '"') { 878c99fb5f9SBaptiste Daroussin ucl_chunk_skipc (chunk, p); 879c99fb5f9SBaptiste Daroussin return true; 880c99fb5f9SBaptiste Daroussin } 881c99fb5f9SBaptiste Daroussin else if (ucl_test_character (c, UCL_CHARACTER_UCL_UNSAFE)) { 882c99fb5f9SBaptiste Daroussin *ucl_escape = true; 883c99fb5f9SBaptiste Daroussin } 884c99fb5f9SBaptiste Daroussin else if (c == '$') { 885c99fb5f9SBaptiste Daroussin *var_expand = true; 886c99fb5f9SBaptiste Daroussin } 887c99fb5f9SBaptiste Daroussin ucl_chunk_skipc (chunk, p); 888c99fb5f9SBaptiste Daroussin } 889c99fb5f9SBaptiste Daroussin 890c99fb5f9SBaptiste Daroussin ucl_set_err (chunk, UCL_ESYNTAX, "no quote at the end of json string", &parser->err); 891c99fb5f9SBaptiste Daroussin return false; 892c99fb5f9SBaptiste Daroussin } 893c99fb5f9SBaptiste Daroussin 894c99fb5f9SBaptiste Daroussin /** 895c99fb5f9SBaptiste Daroussin * Parse a key in an object 896c99fb5f9SBaptiste Daroussin * @param parser 897c99fb5f9SBaptiste Daroussin * @param chunk 898c99fb5f9SBaptiste Daroussin * @return true if a key has been parsed 899c99fb5f9SBaptiste Daroussin */ 900c99fb5f9SBaptiste Daroussin static bool 901c99fb5f9SBaptiste Daroussin ucl_parse_key (struct ucl_parser *parser, struct ucl_chunk *chunk, bool *next_key, bool *end_of_object) 902c99fb5f9SBaptiste Daroussin { 903c99fb5f9SBaptiste Daroussin const unsigned char *p, *c = NULL, *end, *t; 904c99fb5f9SBaptiste Daroussin const char *key = NULL; 905c99fb5f9SBaptiste Daroussin bool got_quote = false, got_eq = false, got_semicolon = false, 906c99fb5f9SBaptiste Daroussin need_unescape = false, ucl_escape = false, var_expand = false, 907c99fb5f9SBaptiste Daroussin got_content = false, got_sep = false; 908c99fb5f9SBaptiste Daroussin ucl_object_t *nobj, *tobj; 909c99fb5f9SBaptiste Daroussin ucl_hash_t *container; 910c99fb5f9SBaptiste Daroussin ssize_t keylen; 911c99fb5f9SBaptiste Daroussin 912c99fb5f9SBaptiste Daroussin p = chunk->pos; 913c99fb5f9SBaptiste Daroussin 914c99fb5f9SBaptiste Daroussin if (*p == '.') { 915c99fb5f9SBaptiste Daroussin /* It is macro actually */ 916c99fb5f9SBaptiste Daroussin ucl_chunk_skipc (chunk, p); 917c99fb5f9SBaptiste Daroussin parser->prev_state = parser->state; 918c99fb5f9SBaptiste Daroussin parser->state = UCL_STATE_MACRO_NAME; 919c99fb5f9SBaptiste Daroussin return true; 920c99fb5f9SBaptiste Daroussin } 921c99fb5f9SBaptiste Daroussin while (p < chunk->end) { 922c99fb5f9SBaptiste Daroussin /* 923c99fb5f9SBaptiste Daroussin * A key must start with alpha, number, '/' or '_' and end with space character 924c99fb5f9SBaptiste Daroussin */ 925c99fb5f9SBaptiste Daroussin if (c == NULL) { 926c99fb5f9SBaptiste Daroussin if (chunk->remain >= 2 && ucl_lex_is_comment (p[0], p[1])) { 927c99fb5f9SBaptiste Daroussin if (!ucl_skip_comments (parser)) { 928c99fb5f9SBaptiste Daroussin return false; 929c99fb5f9SBaptiste Daroussin } 930c99fb5f9SBaptiste Daroussin p = chunk->pos; 931c99fb5f9SBaptiste Daroussin } 932c99fb5f9SBaptiste Daroussin else if (ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE)) { 933c99fb5f9SBaptiste Daroussin ucl_chunk_skipc (chunk, p); 934c99fb5f9SBaptiste Daroussin } 935c99fb5f9SBaptiste Daroussin else if (ucl_test_character (*p, UCL_CHARACTER_KEY_START)) { 936c99fb5f9SBaptiste Daroussin /* The first symbol */ 937c99fb5f9SBaptiste Daroussin c = p; 938c99fb5f9SBaptiste Daroussin ucl_chunk_skipc (chunk, p); 939c99fb5f9SBaptiste Daroussin got_content = true; 940c99fb5f9SBaptiste Daroussin } 941c99fb5f9SBaptiste Daroussin else if (*p == '"') { 942c99fb5f9SBaptiste Daroussin /* JSON style key */ 943c99fb5f9SBaptiste Daroussin c = p + 1; 944c99fb5f9SBaptiste Daroussin got_quote = true; 945c99fb5f9SBaptiste Daroussin got_content = true; 946c99fb5f9SBaptiste Daroussin ucl_chunk_skipc (chunk, p); 947c99fb5f9SBaptiste Daroussin } 948c99fb5f9SBaptiste Daroussin else if (*p == '}') { 949c99fb5f9SBaptiste Daroussin /* We have actually end of an object */ 950c99fb5f9SBaptiste Daroussin *end_of_object = true; 951c99fb5f9SBaptiste Daroussin return true; 952c99fb5f9SBaptiste Daroussin } 953c99fb5f9SBaptiste Daroussin else if (*p == '.') { 954c99fb5f9SBaptiste Daroussin ucl_chunk_skipc (chunk, p); 955c99fb5f9SBaptiste Daroussin parser->prev_state = parser->state; 956c99fb5f9SBaptiste Daroussin parser->state = UCL_STATE_MACRO_NAME; 957c99fb5f9SBaptiste Daroussin return true; 958c99fb5f9SBaptiste Daroussin } 959c99fb5f9SBaptiste Daroussin else { 960c99fb5f9SBaptiste Daroussin /* Invalid identifier */ 961c99fb5f9SBaptiste Daroussin ucl_set_err (chunk, UCL_ESYNTAX, "key must begin with a letter", &parser->err); 962c99fb5f9SBaptiste Daroussin return false; 963c99fb5f9SBaptiste Daroussin } 964c99fb5f9SBaptiste Daroussin } 965c99fb5f9SBaptiste Daroussin else { 966c99fb5f9SBaptiste Daroussin /* Parse the body of a key */ 967c99fb5f9SBaptiste Daroussin if (!got_quote) { 968c99fb5f9SBaptiste Daroussin if (ucl_test_character (*p, UCL_CHARACTER_KEY)) { 969c99fb5f9SBaptiste Daroussin got_content = true; 970c99fb5f9SBaptiste Daroussin ucl_chunk_skipc (chunk, p); 971c99fb5f9SBaptiste Daroussin } 972c99fb5f9SBaptiste Daroussin else if (ucl_test_character (*p, UCL_CHARACTER_KEY_SEP)) { 973c99fb5f9SBaptiste Daroussin end = p; 974c99fb5f9SBaptiste Daroussin break; 975c99fb5f9SBaptiste Daroussin } 976c99fb5f9SBaptiste Daroussin else { 977c99fb5f9SBaptiste Daroussin ucl_set_err (chunk, UCL_ESYNTAX, "invalid character in a key", &parser->err); 978c99fb5f9SBaptiste Daroussin return false; 979c99fb5f9SBaptiste Daroussin } 980c99fb5f9SBaptiste Daroussin } 981c99fb5f9SBaptiste Daroussin else { 982c99fb5f9SBaptiste Daroussin /* We need to parse json like quoted string */ 983c99fb5f9SBaptiste Daroussin if (!ucl_lex_json_string (parser, chunk, &need_unescape, &ucl_escape, &var_expand)) { 984c99fb5f9SBaptiste Daroussin return false; 985c99fb5f9SBaptiste Daroussin } 986c99fb5f9SBaptiste Daroussin /* Always escape keys obtained via json */ 987c99fb5f9SBaptiste Daroussin end = chunk->pos - 1; 988c99fb5f9SBaptiste Daroussin p = chunk->pos; 989c99fb5f9SBaptiste Daroussin break; 990c99fb5f9SBaptiste Daroussin } 991c99fb5f9SBaptiste Daroussin } 992c99fb5f9SBaptiste Daroussin } 993c99fb5f9SBaptiste Daroussin 994c99fb5f9SBaptiste Daroussin if (p >= chunk->end && got_content) { 995c99fb5f9SBaptiste Daroussin ucl_set_err (chunk, UCL_ESYNTAX, "unfinished key", &parser->err); 996c99fb5f9SBaptiste Daroussin return false; 997c99fb5f9SBaptiste Daroussin } 998c99fb5f9SBaptiste Daroussin else if (!got_content) { 999c99fb5f9SBaptiste Daroussin return true; 1000c99fb5f9SBaptiste Daroussin } 1001c99fb5f9SBaptiste Daroussin *end_of_object = false; 1002c99fb5f9SBaptiste Daroussin /* We are now at the end of the key, need to parse the rest */ 1003c99fb5f9SBaptiste Daroussin while (p < chunk->end) { 1004c99fb5f9SBaptiste Daroussin if (ucl_test_character (*p, UCL_CHARACTER_WHITESPACE)) { 1005c99fb5f9SBaptiste Daroussin ucl_chunk_skipc (chunk, p); 1006c99fb5f9SBaptiste Daroussin } 1007c99fb5f9SBaptiste Daroussin else if (*p == '=') { 1008c99fb5f9SBaptiste Daroussin if (!got_eq && !got_semicolon) { 1009c99fb5f9SBaptiste Daroussin ucl_chunk_skipc (chunk, p); 1010c99fb5f9SBaptiste Daroussin got_eq = true; 1011c99fb5f9SBaptiste Daroussin } 1012c99fb5f9SBaptiste Daroussin else { 1013c99fb5f9SBaptiste Daroussin ucl_set_err (chunk, UCL_ESYNTAX, "unexpected '=' character", &parser->err); 1014c99fb5f9SBaptiste Daroussin return false; 1015c99fb5f9SBaptiste Daroussin } 1016c99fb5f9SBaptiste Daroussin } 1017c99fb5f9SBaptiste Daroussin else if (*p == ':') { 1018c99fb5f9SBaptiste Daroussin if (!got_eq && !got_semicolon) { 1019c99fb5f9SBaptiste Daroussin ucl_chunk_skipc (chunk, p); 1020c99fb5f9SBaptiste Daroussin got_semicolon = true; 1021c99fb5f9SBaptiste Daroussin } 1022c99fb5f9SBaptiste Daroussin else { 1023c99fb5f9SBaptiste Daroussin ucl_set_err (chunk, UCL_ESYNTAX, "unexpected ':' character", &parser->err); 1024c99fb5f9SBaptiste Daroussin return false; 1025c99fb5f9SBaptiste Daroussin } 1026c99fb5f9SBaptiste Daroussin } 1027c99fb5f9SBaptiste Daroussin else if (chunk->remain >= 2 && ucl_lex_is_comment (p[0], p[1])) { 1028c99fb5f9SBaptiste Daroussin /* Check for comment */ 1029c99fb5f9SBaptiste Daroussin if (!ucl_skip_comments (parser)) { 1030c99fb5f9SBaptiste Daroussin return false; 1031c99fb5f9SBaptiste Daroussin } 1032c99fb5f9SBaptiste Daroussin p = chunk->pos; 1033c99fb5f9SBaptiste Daroussin } 1034c99fb5f9SBaptiste Daroussin else { 1035c99fb5f9SBaptiste Daroussin /* Start value */ 1036c99fb5f9SBaptiste Daroussin break; 1037c99fb5f9SBaptiste Daroussin } 1038c99fb5f9SBaptiste Daroussin } 1039c99fb5f9SBaptiste Daroussin 1040c99fb5f9SBaptiste Daroussin if (p >= chunk->end && got_content) { 1041c99fb5f9SBaptiste Daroussin ucl_set_err (chunk, UCL_ESYNTAX, "unfinished key", &parser->err); 1042c99fb5f9SBaptiste Daroussin return false; 1043c99fb5f9SBaptiste Daroussin } 1044c99fb5f9SBaptiste Daroussin 1045c99fb5f9SBaptiste Daroussin got_sep = got_semicolon || got_eq; 1046c99fb5f9SBaptiste Daroussin 1047c99fb5f9SBaptiste Daroussin if (!got_sep) { 1048c99fb5f9SBaptiste Daroussin /* 1049c99fb5f9SBaptiste Daroussin * Maybe we have more keys nested, so search for termination character. 1050c99fb5f9SBaptiste Daroussin * Possible choices: 1051c99fb5f9SBaptiste Daroussin * 1) key1 key2 ... keyN [:=] value <- we treat that as error 1052c99fb5f9SBaptiste Daroussin * 2) key1 ... keyN {} or [] <- we treat that as nested objects 1053c99fb5f9SBaptiste Daroussin * 3) key1 value[;,\n] <- we treat that as linear object 1054c99fb5f9SBaptiste Daroussin */ 1055c99fb5f9SBaptiste Daroussin t = p; 1056c99fb5f9SBaptiste Daroussin *next_key = false; 1057c99fb5f9SBaptiste Daroussin while (ucl_test_character (*t, UCL_CHARACTER_WHITESPACE)) { 1058c99fb5f9SBaptiste Daroussin t ++; 1059c99fb5f9SBaptiste Daroussin } 1060c99fb5f9SBaptiste Daroussin /* Check first non-space character after a key */ 1061c99fb5f9SBaptiste Daroussin if (*t != '{' && *t != '[') { 1062c99fb5f9SBaptiste Daroussin while (t < chunk->end) { 1063c99fb5f9SBaptiste Daroussin if (*t == ',' || *t == ';' || *t == '\n' || *t == '\r') { 1064c99fb5f9SBaptiste Daroussin break; 1065c99fb5f9SBaptiste Daroussin } 1066c99fb5f9SBaptiste Daroussin else if (*t == '{' || *t == '[') { 1067c99fb5f9SBaptiste Daroussin *next_key = true; 1068c99fb5f9SBaptiste Daroussin break; 1069c99fb5f9SBaptiste Daroussin } 1070c99fb5f9SBaptiste Daroussin t ++; 1071c99fb5f9SBaptiste Daroussin } 1072c99fb5f9SBaptiste Daroussin } 1073c99fb5f9SBaptiste Daroussin } 1074c99fb5f9SBaptiste Daroussin 1075c99fb5f9SBaptiste Daroussin /* Create a new object */ 1076c99fb5f9SBaptiste Daroussin nobj = ucl_object_new (); 1077c99fb5f9SBaptiste Daroussin keylen = ucl_copy_or_store_ptr (parser, c, &nobj->trash_stack[UCL_TRASH_KEY], 1078c99fb5f9SBaptiste Daroussin &key, end - c, need_unescape, parser->flags & UCL_PARSER_KEY_LOWERCASE, false); 1079c99fb5f9SBaptiste Daroussin if (keylen == -1) { 1080c99fb5f9SBaptiste Daroussin ucl_object_free(nobj); 1081c99fb5f9SBaptiste Daroussin return false; 1082c99fb5f9SBaptiste Daroussin } 1083c99fb5f9SBaptiste Daroussin else if (keylen == 0) { 1084c99fb5f9SBaptiste Daroussin ucl_set_err (chunk, UCL_ESYNTAX, "empty keys are not allowed", &parser->err); 1085c99fb5f9SBaptiste Daroussin ucl_object_free(nobj); 1086c99fb5f9SBaptiste Daroussin return false; 1087c99fb5f9SBaptiste Daroussin } 1088c99fb5f9SBaptiste Daroussin 1089c99fb5f9SBaptiste Daroussin container = parser->stack->obj->value.ov; 1090c99fb5f9SBaptiste Daroussin nobj->key = key; 1091c99fb5f9SBaptiste Daroussin nobj->keylen = keylen; 1092c99fb5f9SBaptiste Daroussin tobj = ucl_hash_search_obj (container, nobj); 1093c99fb5f9SBaptiste Daroussin if (tobj == NULL) { 1094c99fb5f9SBaptiste Daroussin container = ucl_hash_insert_object (container, nobj); 1095c99fb5f9SBaptiste Daroussin nobj->prev = nobj; 1096c99fb5f9SBaptiste Daroussin nobj->next = NULL; 1097c99fb5f9SBaptiste Daroussin parser->stack->obj->len ++; 1098c99fb5f9SBaptiste Daroussin } 1099c99fb5f9SBaptiste Daroussin else { 1100c99fb5f9SBaptiste Daroussin DL_APPEND (tobj, nobj); 1101c99fb5f9SBaptiste Daroussin } 1102c99fb5f9SBaptiste Daroussin 1103c99fb5f9SBaptiste Daroussin if (ucl_escape) { 1104c99fb5f9SBaptiste Daroussin nobj->flags |= UCL_OBJECT_NEED_KEY_ESCAPE; 1105c99fb5f9SBaptiste Daroussin } 1106c99fb5f9SBaptiste Daroussin parser->stack->obj->value.ov = container; 1107c99fb5f9SBaptiste Daroussin 1108c99fb5f9SBaptiste Daroussin parser->cur_obj = nobj; 1109c99fb5f9SBaptiste Daroussin 1110c99fb5f9SBaptiste Daroussin return true; 1111c99fb5f9SBaptiste Daroussin } 1112c99fb5f9SBaptiste Daroussin 1113c99fb5f9SBaptiste Daroussin /** 1114c99fb5f9SBaptiste Daroussin * Parse a cl string 1115c99fb5f9SBaptiste Daroussin * @param parser 1116c99fb5f9SBaptiste Daroussin * @param chunk 1117c99fb5f9SBaptiste Daroussin * @return true if a key has been parsed 1118c99fb5f9SBaptiste Daroussin */ 1119c99fb5f9SBaptiste Daroussin static bool 1120c99fb5f9SBaptiste Daroussin ucl_parse_string_value (struct ucl_parser *parser, 1121c99fb5f9SBaptiste Daroussin struct ucl_chunk *chunk, bool *var_expand, bool *need_unescape) 1122c99fb5f9SBaptiste Daroussin { 1123c99fb5f9SBaptiste Daroussin const unsigned char *p; 1124c99fb5f9SBaptiste Daroussin enum { 1125c99fb5f9SBaptiste Daroussin UCL_BRACE_ROUND = 0, 1126c99fb5f9SBaptiste Daroussin UCL_BRACE_SQUARE, 1127c99fb5f9SBaptiste Daroussin UCL_BRACE_FIGURE 1128c99fb5f9SBaptiste Daroussin }; 1129c99fb5f9SBaptiste Daroussin int braces[3][2] = {{0, 0}, {0, 0}, {0, 0}}; 1130c99fb5f9SBaptiste Daroussin 1131c99fb5f9SBaptiste Daroussin p = chunk->pos; 1132c99fb5f9SBaptiste Daroussin 1133c99fb5f9SBaptiste Daroussin while (p < chunk->end) { 1134c99fb5f9SBaptiste Daroussin 1135c99fb5f9SBaptiste Daroussin /* Skip pairs of figure braces */ 1136c99fb5f9SBaptiste Daroussin if (*p == '{') { 1137c99fb5f9SBaptiste Daroussin braces[UCL_BRACE_FIGURE][0] ++; 1138c99fb5f9SBaptiste Daroussin } 1139c99fb5f9SBaptiste Daroussin else if (*p == '}') { 1140c99fb5f9SBaptiste Daroussin braces[UCL_BRACE_FIGURE][1] ++; 1141c99fb5f9SBaptiste Daroussin if (braces[UCL_BRACE_FIGURE][1] <= braces[UCL_BRACE_FIGURE][0]) { 1142c99fb5f9SBaptiste Daroussin /* This is not a termination symbol, continue */ 1143c99fb5f9SBaptiste Daroussin ucl_chunk_skipc (chunk, p); 1144c99fb5f9SBaptiste Daroussin continue; 1145c99fb5f9SBaptiste Daroussin } 1146c99fb5f9SBaptiste Daroussin } 1147c99fb5f9SBaptiste Daroussin /* Skip pairs of square braces */ 1148c99fb5f9SBaptiste Daroussin else if (*p == '[') { 1149c99fb5f9SBaptiste Daroussin braces[UCL_BRACE_SQUARE][0] ++; 1150c99fb5f9SBaptiste Daroussin } 1151c99fb5f9SBaptiste Daroussin else if (*p == ']') { 1152c99fb5f9SBaptiste Daroussin braces[UCL_BRACE_SQUARE][1] ++; 1153c99fb5f9SBaptiste Daroussin if (braces[UCL_BRACE_SQUARE][1] <= braces[UCL_BRACE_SQUARE][0]) { 1154c99fb5f9SBaptiste Daroussin /* This is not a termination symbol, continue */ 1155c99fb5f9SBaptiste Daroussin ucl_chunk_skipc (chunk, p); 1156c99fb5f9SBaptiste Daroussin continue; 1157c99fb5f9SBaptiste Daroussin } 1158c99fb5f9SBaptiste Daroussin } 1159c99fb5f9SBaptiste Daroussin else if (*p == '$') { 1160c99fb5f9SBaptiste Daroussin *var_expand = true; 1161c99fb5f9SBaptiste Daroussin } 1162c99fb5f9SBaptiste Daroussin else if (*p == '\\') { 1163c99fb5f9SBaptiste Daroussin *need_unescape = true; 1164c99fb5f9SBaptiste Daroussin ucl_chunk_skipc (chunk, p); 1165c99fb5f9SBaptiste Daroussin if (p < chunk->end) { 1166c99fb5f9SBaptiste Daroussin ucl_chunk_skipc (chunk, p); 1167c99fb5f9SBaptiste Daroussin } 1168c99fb5f9SBaptiste Daroussin continue; 1169c99fb5f9SBaptiste Daroussin } 1170c99fb5f9SBaptiste Daroussin 1171c99fb5f9SBaptiste Daroussin if (ucl_lex_is_atom_end (*p) || (chunk->remain >= 2 && ucl_lex_is_comment (p[0], p[1]))) { 1172c99fb5f9SBaptiste Daroussin break; 1173c99fb5f9SBaptiste Daroussin } 1174c99fb5f9SBaptiste Daroussin ucl_chunk_skipc (chunk, p); 1175c99fb5f9SBaptiste Daroussin } 1176c99fb5f9SBaptiste Daroussin 1177c99fb5f9SBaptiste Daroussin if (p >= chunk->end) { 1178c99fb5f9SBaptiste Daroussin ucl_set_err (chunk, UCL_ESYNTAX, "unfinished value", &parser->err); 1179c99fb5f9SBaptiste Daroussin return false; 1180c99fb5f9SBaptiste Daroussin } 1181c99fb5f9SBaptiste Daroussin 1182c99fb5f9SBaptiste Daroussin return true; 1183c99fb5f9SBaptiste Daroussin } 1184c99fb5f9SBaptiste Daroussin 1185c99fb5f9SBaptiste Daroussin /** 1186c99fb5f9SBaptiste Daroussin * Parse multiline string ending with \n{term}\n 1187c99fb5f9SBaptiste Daroussin * @param parser 1188c99fb5f9SBaptiste Daroussin * @param chunk 1189c99fb5f9SBaptiste Daroussin * @param term 1190c99fb5f9SBaptiste Daroussin * @param term_len 1191c99fb5f9SBaptiste Daroussin * @return size of multiline string or 0 in case of error 1192c99fb5f9SBaptiste Daroussin */ 1193c99fb5f9SBaptiste Daroussin static int 1194c99fb5f9SBaptiste Daroussin ucl_parse_multiline_string (struct ucl_parser *parser, 1195c99fb5f9SBaptiste Daroussin struct ucl_chunk *chunk, const unsigned char *term, 1196c99fb5f9SBaptiste Daroussin int term_len, unsigned char const **beg, 1197c99fb5f9SBaptiste Daroussin bool *var_expand) 1198c99fb5f9SBaptiste Daroussin { 1199c99fb5f9SBaptiste Daroussin const unsigned char *p, *c; 1200c99fb5f9SBaptiste Daroussin bool newline = false; 1201c99fb5f9SBaptiste Daroussin int len = 0; 1202c99fb5f9SBaptiste Daroussin 1203c99fb5f9SBaptiste Daroussin p = chunk->pos; 1204c99fb5f9SBaptiste Daroussin 1205c99fb5f9SBaptiste Daroussin c = p; 1206c99fb5f9SBaptiste Daroussin 1207c99fb5f9SBaptiste Daroussin while (p < chunk->end) { 1208c99fb5f9SBaptiste Daroussin if (newline) { 1209c99fb5f9SBaptiste Daroussin if (chunk->end - p < term_len) { 1210c99fb5f9SBaptiste Daroussin return 0; 1211c99fb5f9SBaptiste Daroussin } 1212c99fb5f9SBaptiste Daroussin else if (memcmp (p, term, term_len) == 0 && (p[term_len] == '\n' || p[term_len] == '\r')) { 1213c99fb5f9SBaptiste Daroussin len = p - c; 1214c99fb5f9SBaptiste Daroussin chunk->remain -= term_len; 1215c99fb5f9SBaptiste Daroussin chunk->pos = p + term_len; 1216c99fb5f9SBaptiste Daroussin chunk->column = term_len; 1217c99fb5f9SBaptiste Daroussin *beg = c; 1218c99fb5f9SBaptiste Daroussin break; 1219c99fb5f9SBaptiste Daroussin } 1220c99fb5f9SBaptiste Daroussin } 1221c99fb5f9SBaptiste Daroussin if (*p == '\n') { 1222c99fb5f9SBaptiste Daroussin newline = true; 1223c99fb5f9SBaptiste Daroussin } 1224c99fb5f9SBaptiste Daroussin else { 1225c99fb5f9SBaptiste Daroussin if (*p == '$') { 1226c99fb5f9SBaptiste Daroussin *var_expand = true; 1227c99fb5f9SBaptiste Daroussin } 1228c99fb5f9SBaptiste Daroussin newline = false; 1229c99fb5f9SBaptiste Daroussin } 1230c99fb5f9SBaptiste Daroussin ucl_chunk_skipc (chunk, p); 1231c99fb5f9SBaptiste Daroussin } 1232c99fb5f9SBaptiste Daroussin 1233c99fb5f9SBaptiste Daroussin return len; 1234c99fb5f9SBaptiste Daroussin } 1235c99fb5f9SBaptiste Daroussin 1236*36c53d67SBaptiste Daroussin static ucl_object_t* 1237*36c53d67SBaptiste Daroussin ucl_get_value_object (struct ucl_parser *parser) 1238c99fb5f9SBaptiste Daroussin { 1239*36c53d67SBaptiste Daroussin ucl_object_t *t, *obj = NULL; 1240c99fb5f9SBaptiste Daroussin 1241c99fb5f9SBaptiste Daroussin if (parser->stack->obj->type == UCL_ARRAY) { 1242c99fb5f9SBaptiste Daroussin /* Object must be allocated */ 1243c99fb5f9SBaptiste Daroussin obj = ucl_object_new (); 1244c99fb5f9SBaptiste Daroussin t = parser->stack->obj->value.av; 1245c99fb5f9SBaptiste Daroussin DL_APPEND (t, obj); 1246c99fb5f9SBaptiste Daroussin parser->cur_obj = obj; 1247c99fb5f9SBaptiste Daroussin parser->stack->obj->value.av = t; 1248c99fb5f9SBaptiste Daroussin parser->stack->obj->len ++; 1249c99fb5f9SBaptiste Daroussin } 1250c99fb5f9SBaptiste Daroussin else { 1251c99fb5f9SBaptiste Daroussin /* Object has been already allocated */ 1252c99fb5f9SBaptiste Daroussin obj = parser->cur_obj; 1253c99fb5f9SBaptiste Daroussin } 1254*36c53d67SBaptiste Daroussin 1255*36c53d67SBaptiste Daroussin return obj; 1256c99fb5f9SBaptiste Daroussin } 1257*36c53d67SBaptiste Daroussin 1258*36c53d67SBaptiste Daroussin /** 1259*36c53d67SBaptiste Daroussin * Handle value data 1260*36c53d67SBaptiste Daroussin * @param parser 1261*36c53d67SBaptiste Daroussin * @param chunk 1262*36c53d67SBaptiste Daroussin * @return 1263*36c53d67SBaptiste Daroussin */ 1264*36c53d67SBaptiste Daroussin static bool 1265*36c53d67SBaptiste Daroussin ucl_parse_value (struct ucl_parser *parser, struct ucl_chunk *chunk) 1266*36c53d67SBaptiste Daroussin { 1267*36c53d67SBaptiste Daroussin const unsigned char *p, *c; 1268*36c53d67SBaptiste Daroussin ucl_object_t *obj = NULL; 1269*36c53d67SBaptiste Daroussin unsigned int stripped_spaces; 1270*36c53d67SBaptiste Daroussin int str_len; 1271*36c53d67SBaptiste Daroussin bool need_unescape = false, ucl_escape = false, var_expand = false; 1272*36c53d67SBaptiste Daroussin 1273*36c53d67SBaptiste Daroussin p = chunk->pos; 1274*36c53d67SBaptiste Daroussin 1275*36c53d67SBaptiste Daroussin /* Skip any spaces and comments */ 1276*36c53d67SBaptiste Daroussin if (ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE) || 1277*36c53d67SBaptiste Daroussin (chunk->remain >= 2 && ucl_lex_is_comment (p[0], p[1]))) { 1278*36c53d67SBaptiste Daroussin while (p < chunk->end && ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE)) { 1279*36c53d67SBaptiste Daroussin ucl_chunk_skipc (chunk, p); 1280*36c53d67SBaptiste Daroussin } 1281*36c53d67SBaptiste Daroussin if (!ucl_skip_comments (parser)) { 1282*36c53d67SBaptiste Daroussin return false; 1283*36c53d67SBaptiste Daroussin } 1284*36c53d67SBaptiste Daroussin p = chunk->pos; 1285*36c53d67SBaptiste Daroussin } 1286*36c53d67SBaptiste Daroussin 1287*36c53d67SBaptiste Daroussin while (p < chunk->end) { 1288c99fb5f9SBaptiste Daroussin c = p; 1289c99fb5f9SBaptiste Daroussin switch (*p) { 1290c99fb5f9SBaptiste Daroussin case '"': 1291*36c53d67SBaptiste Daroussin obj = ucl_get_value_object (parser); 1292c99fb5f9SBaptiste Daroussin ucl_chunk_skipc (chunk, p); 1293c99fb5f9SBaptiste Daroussin if (!ucl_lex_json_string (parser, chunk, &need_unescape, &ucl_escape, &var_expand)) { 1294c99fb5f9SBaptiste Daroussin return false; 1295c99fb5f9SBaptiste Daroussin } 1296c99fb5f9SBaptiste Daroussin str_len = chunk->pos - c - 2; 1297c99fb5f9SBaptiste Daroussin obj->type = UCL_STRING; 1298c99fb5f9SBaptiste Daroussin if ((str_len = ucl_copy_or_store_ptr (parser, c + 1, &obj->trash_stack[UCL_TRASH_VALUE], 1299c99fb5f9SBaptiste Daroussin &obj->value.sv, str_len, need_unescape, false, var_expand)) == -1) { 1300c99fb5f9SBaptiste Daroussin return false; 1301c99fb5f9SBaptiste Daroussin } 1302c99fb5f9SBaptiste Daroussin obj->len = str_len; 1303c99fb5f9SBaptiste Daroussin parser->state = UCL_STATE_AFTER_VALUE; 1304c99fb5f9SBaptiste Daroussin p = chunk->pos; 1305c99fb5f9SBaptiste Daroussin return true; 1306c99fb5f9SBaptiste Daroussin break; 1307c99fb5f9SBaptiste Daroussin case '{': 1308*36c53d67SBaptiste Daroussin obj = ucl_get_value_object (parser); 1309c99fb5f9SBaptiste Daroussin /* We have a new object */ 1310c99fb5f9SBaptiste Daroussin obj = ucl_add_parser_stack (obj, parser, false, parser->stack->level); 1311c99fb5f9SBaptiste Daroussin 1312c99fb5f9SBaptiste Daroussin ucl_chunk_skipc (chunk, p); 1313c99fb5f9SBaptiste Daroussin return true; 1314c99fb5f9SBaptiste Daroussin break; 1315c99fb5f9SBaptiste Daroussin case '[': 1316*36c53d67SBaptiste Daroussin obj = ucl_get_value_object (parser); 1317c99fb5f9SBaptiste Daroussin /* We have a new array */ 1318c99fb5f9SBaptiste Daroussin obj = ucl_add_parser_stack (obj, parser, true, parser->stack->level); 1319c99fb5f9SBaptiste Daroussin 1320c99fb5f9SBaptiste Daroussin ucl_chunk_skipc (chunk, p); 1321c99fb5f9SBaptiste Daroussin return true; 1322c99fb5f9SBaptiste Daroussin break; 1323*36c53d67SBaptiste Daroussin case ']': 1324*36c53d67SBaptiste Daroussin /* We have the array ending */ 1325*36c53d67SBaptiste Daroussin if (parser->stack && parser->stack->obj->type == UCL_ARRAY) { 1326*36c53d67SBaptiste Daroussin parser->state = UCL_STATE_AFTER_VALUE; 1327*36c53d67SBaptiste Daroussin return true; 1328*36c53d67SBaptiste Daroussin } 1329*36c53d67SBaptiste Daroussin else { 1330*36c53d67SBaptiste Daroussin goto parse_string; 1331*36c53d67SBaptiste Daroussin } 1332*36c53d67SBaptiste Daroussin break; 1333c99fb5f9SBaptiste Daroussin case '<': 1334*36c53d67SBaptiste Daroussin obj = ucl_get_value_object (parser); 1335c99fb5f9SBaptiste Daroussin /* We have something like multiline value, which must be <<[A-Z]+\n */ 1336c99fb5f9SBaptiste Daroussin if (chunk->end - p > 3) { 1337c99fb5f9SBaptiste Daroussin if (memcmp (p, "<<", 2) == 0) { 1338c99fb5f9SBaptiste Daroussin p += 2; 1339c99fb5f9SBaptiste Daroussin /* We allow only uppercase characters in multiline definitions */ 1340c99fb5f9SBaptiste Daroussin while (p < chunk->end && *p >= 'A' && *p <= 'Z') { 1341c99fb5f9SBaptiste Daroussin p ++; 1342c99fb5f9SBaptiste Daroussin } 1343c99fb5f9SBaptiste Daroussin if (*p =='\n') { 1344c99fb5f9SBaptiste Daroussin /* Set chunk positions and start multiline parsing */ 1345c99fb5f9SBaptiste Daroussin c += 2; 1346c99fb5f9SBaptiste Daroussin chunk->remain -= p - c; 1347c99fb5f9SBaptiste Daroussin chunk->pos = p + 1; 1348c99fb5f9SBaptiste Daroussin chunk->column = 0; 1349c99fb5f9SBaptiste Daroussin chunk->line ++; 1350c99fb5f9SBaptiste Daroussin if ((str_len = ucl_parse_multiline_string (parser, chunk, c, 1351c99fb5f9SBaptiste Daroussin p - c, &c, &var_expand)) == 0) { 1352c99fb5f9SBaptiste Daroussin ucl_set_err (chunk, UCL_ESYNTAX, "unterminated multiline value", &parser->err); 1353c99fb5f9SBaptiste Daroussin return false; 1354c99fb5f9SBaptiste Daroussin } 1355c99fb5f9SBaptiste Daroussin obj->type = UCL_STRING; 1356c99fb5f9SBaptiste Daroussin if ((str_len = ucl_copy_or_store_ptr (parser, c, &obj->trash_stack[UCL_TRASH_VALUE], 1357c99fb5f9SBaptiste Daroussin &obj->value.sv, str_len - 1, false, false, var_expand)) == -1) { 1358c99fb5f9SBaptiste Daroussin return false; 1359c99fb5f9SBaptiste Daroussin } 1360c99fb5f9SBaptiste Daroussin obj->len = str_len; 1361c99fb5f9SBaptiste Daroussin parser->state = UCL_STATE_AFTER_VALUE; 1362c99fb5f9SBaptiste Daroussin return true; 1363c99fb5f9SBaptiste Daroussin } 1364c99fb5f9SBaptiste Daroussin } 1365c99fb5f9SBaptiste Daroussin } 1366c99fb5f9SBaptiste Daroussin /* Fallback to ordinary strings */ 1367c99fb5f9SBaptiste Daroussin default: 1368*36c53d67SBaptiste Daroussin parse_string: 1369*36c53d67SBaptiste Daroussin if (obj == NULL) { 1370*36c53d67SBaptiste Daroussin obj = ucl_get_value_object (parser); 1371c99fb5f9SBaptiste Daroussin } 1372c99fb5f9SBaptiste Daroussin /* Parse atom */ 1373c99fb5f9SBaptiste Daroussin if (ucl_test_character (*p, UCL_CHARACTER_VALUE_DIGIT_START)) { 1374c99fb5f9SBaptiste Daroussin if (!ucl_lex_number (parser, chunk, obj)) { 1375c99fb5f9SBaptiste Daroussin if (parser->state == UCL_STATE_ERROR) { 1376c99fb5f9SBaptiste Daroussin return false; 1377c99fb5f9SBaptiste Daroussin } 1378c99fb5f9SBaptiste Daroussin } 1379c99fb5f9SBaptiste Daroussin else { 1380c99fb5f9SBaptiste Daroussin parser->state = UCL_STATE_AFTER_VALUE; 1381c99fb5f9SBaptiste Daroussin return true; 1382c99fb5f9SBaptiste Daroussin } 1383c99fb5f9SBaptiste Daroussin /* Fallback to normal string */ 1384c99fb5f9SBaptiste Daroussin } 1385c99fb5f9SBaptiste Daroussin 1386c99fb5f9SBaptiste Daroussin if (!ucl_parse_string_value (parser, chunk, &var_expand, &need_unescape)) { 1387c99fb5f9SBaptiste Daroussin return false; 1388c99fb5f9SBaptiste Daroussin } 1389c99fb5f9SBaptiste Daroussin /* Cut trailing spaces */ 1390c99fb5f9SBaptiste Daroussin stripped_spaces = 0; 1391c99fb5f9SBaptiste Daroussin while (ucl_test_character (*(chunk->pos - 1 - stripped_spaces), 1392c99fb5f9SBaptiste Daroussin UCL_CHARACTER_WHITESPACE)) { 1393c99fb5f9SBaptiste Daroussin stripped_spaces ++; 1394c99fb5f9SBaptiste Daroussin } 1395c99fb5f9SBaptiste Daroussin str_len = chunk->pos - c - stripped_spaces; 1396c99fb5f9SBaptiste Daroussin if (str_len <= 0) { 1397c99fb5f9SBaptiste Daroussin ucl_set_err (chunk, 0, "string value must not be empty", &parser->err); 1398c99fb5f9SBaptiste Daroussin return false; 1399c99fb5f9SBaptiste Daroussin } 1400c99fb5f9SBaptiste Daroussin else if (str_len == 4 && memcmp (c, "null", 4) == 0) { 1401c99fb5f9SBaptiste Daroussin obj->len = 0; 1402c99fb5f9SBaptiste Daroussin obj->type = UCL_NULL; 1403c99fb5f9SBaptiste Daroussin } 1404c99fb5f9SBaptiste Daroussin else if (!ucl_maybe_parse_boolean (obj, c, str_len)) { 1405c99fb5f9SBaptiste Daroussin obj->type = UCL_STRING; 1406c99fb5f9SBaptiste Daroussin if ((str_len = ucl_copy_or_store_ptr (parser, c, &obj->trash_stack[UCL_TRASH_VALUE], 1407c99fb5f9SBaptiste Daroussin &obj->value.sv, str_len, need_unescape, 1408c99fb5f9SBaptiste Daroussin false, var_expand)) == -1) { 1409c99fb5f9SBaptiste Daroussin return false; 1410c99fb5f9SBaptiste Daroussin } 1411c99fb5f9SBaptiste Daroussin obj->len = str_len; 1412c99fb5f9SBaptiste Daroussin } 1413c99fb5f9SBaptiste Daroussin parser->state = UCL_STATE_AFTER_VALUE; 1414c99fb5f9SBaptiste Daroussin p = chunk->pos; 1415c99fb5f9SBaptiste Daroussin 1416c99fb5f9SBaptiste Daroussin return true; 1417c99fb5f9SBaptiste Daroussin break; 1418c99fb5f9SBaptiste Daroussin } 1419c99fb5f9SBaptiste Daroussin } 1420c99fb5f9SBaptiste Daroussin 1421c99fb5f9SBaptiste Daroussin return true; 1422c99fb5f9SBaptiste Daroussin } 1423c99fb5f9SBaptiste Daroussin 1424c99fb5f9SBaptiste Daroussin /** 1425c99fb5f9SBaptiste Daroussin * Handle after value data 1426c99fb5f9SBaptiste Daroussin * @param parser 1427c99fb5f9SBaptiste Daroussin * @param chunk 1428c99fb5f9SBaptiste Daroussin * @return 1429c99fb5f9SBaptiste Daroussin */ 1430c99fb5f9SBaptiste Daroussin static bool 1431c99fb5f9SBaptiste Daroussin ucl_parse_after_value (struct ucl_parser *parser, struct ucl_chunk *chunk) 1432c99fb5f9SBaptiste Daroussin { 1433c99fb5f9SBaptiste Daroussin const unsigned char *p; 1434c99fb5f9SBaptiste Daroussin bool got_sep = false; 1435c99fb5f9SBaptiste Daroussin struct ucl_stack *st; 1436c99fb5f9SBaptiste Daroussin 1437c99fb5f9SBaptiste Daroussin p = chunk->pos; 1438c99fb5f9SBaptiste Daroussin 1439c99fb5f9SBaptiste Daroussin while (p < chunk->end) { 1440c99fb5f9SBaptiste Daroussin if (ucl_test_character (*p, UCL_CHARACTER_WHITESPACE)) { 1441c99fb5f9SBaptiste Daroussin /* Skip whitespaces */ 1442c99fb5f9SBaptiste Daroussin ucl_chunk_skipc (chunk, p); 1443c99fb5f9SBaptiste Daroussin } 1444c99fb5f9SBaptiste Daroussin else if (chunk->remain >= 2 && ucl_lex_is_comment (p[0], p[1])) { 1445c99fb5f9SBaptiste Daroussin /* Skip comment */ 1446c99fb5f9SBaptiste Daroussin if (!ucl_skip_comments (parser)) { 1447c99fb5f9SBaptiste Daroussin return false; 1448c99fb5f9SBaptiste Daroussin } 1449c99fb5f9SBaptiste Daroussin /* Treat comment as a separator */ 1450c99fb5f9SBaptiste Daroussin got_sep = true; 1451c99fb5f9SBaptiste Daroussin p = chunk->pos; 1452c99fb5f9SBaptiste Daroussin } 1453c99fb5f9SBaptiste Daroussin else if (ucl_test_character (*p, UCL_CHARACTER_VALUE_END)) { 1454c99fb5f9SBaptiste Daroussin if (*p == '}' || *p == ']') { 1455c99fb5f9SBaptiste Daroussin if (parser->stack == NULL) { 1456c99fb5f9SBaptiste Daroussin ucl_set_err (chunk, UCL_ESYNTAX, "end of array or object detected without corresponding start", &parser->err); 1457c99fb5f9SBaptiste Daroussin return false; 1458c99fb5f9SBaptiste Daroussin } 1459c99fb5f9SBaptiste Daroussin if ((*p == '}' && parser->stack->obj->type == UCL_OBJECT) || 1460c99fb5f9SBaptiste Daroussin (*p == ']' && parser->stack->obj->type == UCL_ARRAY)) { 1461c99fb5f9SBaptiste Daroussin 1462c99fb5f9SBaptiste Daroussin /* Pop all nested objects from a stack */ 1463c99fb5f9SBaptiste Daroussin st = parser->stack; 1464c99fb5f9SBaptiste Daroussin parser->stack = st->next; 1465c99fb5f9SBaptiste Daroussin UCL_FREE (sizeof (struct ucl_stack), st); 1466c99fb5f9SBaptiste Daroussin 1467c99fb5f9SBaptiste Daroussin while (parser->stack != NULL) { 1468c99fb5f9SBaptiste Daroussin st = parser->stack; 1469c99fb5f9SBaptiste Daroussin if (st->next == NULL || st->next->level == st->level) { 1470c99fb5f9SBaptiste Daroussin break; 1471c99fb5f9SBaptiste Daroussin } 1472c99fb5f9SBaptiste Daroussin parser->stack = st->next; 1473c99fb5f9SBaptiste Daroussin UCL_FREE (sizeof (struct ucl_stack), st); 1474c99fb5f9SBaptiste Daroussin } 1475c99fb5f9SBaptiste Daroussin } 1476c99fb5f9SBaptiste Daroussin else { 1477c99fb5f9SBaptiste Daroussin ucl_set_err (chunk, UCL_ESYNTAX, "unexpected terminating symbol detected", &parser->err); 1478c99fb5f9SBaptiste Daroussin return false; 1479c99fb5f9SBaptiste Daroussin } 1480c99fb5f9SBaptiste Daroussin 1481c99fb5f9SBaptiste Daroussin if (parser->stack == NULL) { 1482c99fb5f9SBaptiste Daroussin /* Ignore everything after a top object */ 1483c99fb5f9SBaptiste Daroussin return true; 1484c99fb5f9SBaptiste Daroussin } 1485c99fb5f9SBaptiste Daroussin else { 1486c99fb5f9SBaptiste Daroussin ucl_chunk_skipc (chunk, p); 1487c99fb5f9SBaptiste Daroussin } 1488c99fb5f9SBaptiste Daroussin got_sep = true; 1489c99fb5f9SBaptiste Daroussin } 1490c99fb5f9SBaptiste Daroussin else { 1491c99fb5f9SBaptiste Daroussin /* Got a separator */ 1492c99fb5f9SBaptiste Daroussin got_sep = true; 1493c99fb5f9SBaptiste Daroussin ucl_chunk_skipc (chunk, p); 1494c99fb5f9SBaptiste Daroussin } 1495c99fb5f9SBaptiste Daroussin } 1496c99fb5f9SBaptiste Daroussin else { 1497c99fb5f9SBaptiste Daroussin /* Anything else */ 1498c99fb5f9SBaptiste Daroussin if (!got_sep) { 1499c99fb5f9SBaptiste Daroussin ucl_set_err (chunk, UCL_ESYNTAX, "delimiter is missing", &parser->err); 1500c99fb5f9SBaptiste Daroussin return false; 1501c99fb5f9SBaptiste Daroussin } 1502c99fb5f9SBaptiste Daroussin return true; 1503c99fb5f9SBaptiste Daroussin } 1504c99fb5f9SBaptiste Daroussin } 1505c99fb5f9SBaptiste Daroussin 1506c99fb5f9SBaptiste Daroussin return true; 1507c99fb5f9SBaptiste Daroussin } 1508c99fb5f9SBaptiste Daroussin 1509c99fb5f9SBaptiste Daroussin /** 1510c99fb5f9SBaptiste Daroussin * Handle macro data 1511c99fb5f9SBaptiste Daroussin * @param parser 1512c99fb5f9SBaptiste Daroussin * @param chunk 1513c99fb5f9SBaptiste Daroussin * @return 1514c99fb5f9SBaptiste Daroussin */ 1515c99fb5f9SBaptiste Daroussin static bool 1516c99fb5f9SBaptiste Daroussin ucl_parse_macro_value (struct ucl_parser *parser, 1517c99fb5f9SBaptiste Daroussin struct ucl_chunk *chunk, struct ucl_macro *macro, 1518c99fb5f9SBaptiste Daroussin unsigned char const **macro_start, size_t *macro_len) 1519c99fb5f9SBaptiste Daroussin { 1520c99fb5f9SBaptiste Daroussin const unsigned char *p, *c; 1521c99fb5f9SBaptiste Daroussin bool need_unescape = false, ucl_escape = false, var_expand = false; 1522c99fb5f9SBaptiste Daroussin 1523c99fb5f9SBaptiste Daroussin p = chunk->pos; 1524c99fb5f9SBaptiste Daroussin 1525c99fb5f9SBaptiste Daroussin switch (*p) { 1526c99fb5f9SBaptiste Daroussin case '"': 1527c99fb5f9SBaptiste Daroussin /* We have macro value encoded in quotes */ 1528c99fb5f9SBaptiste Daroussin c = p; 1529c99fb5f9SBaptiste Daroussin ucl_chunk_skipc (chunk, p); 1530c99fb5f9SBaptiste Daroussin if (!ucl_lex_json_string (parser, chunk, &need_unescape, &ucl_escape, &var_expand)) { 1531c99fb5f9SBaptiste Daroussin return false; 1532c99fb5f9SBaptiste Daroussin } 1533c99fb5f9SBaptiste Daroussin 1534c99fb5f9SBaptiste Daroussin *macro_start = c + 1; 1535c99fb5f9SBaptiste Daroussin *macro_len = chunk->pos - c - 2; 1536c99fb5f9SBaptiste Daroussin p = chunk->pos; 1537c99fb5f9SBaptiste Daroussin break; 1538c99fb5f9SBaptiste Daroussin case '{': 1539c99fb5f9SBaptiste Daroussin /* We got a multiline macro body */ 1540c99fb5f9SBaptiste Daroussin ucl_chunk_skipc (chunk, p); 1541c99fb5f9SBaptiste Daroussin /* Skip spaces at the beginning */ 1542c99fb5f9SBaptiste Daroussin while (p < chunk->end) { 1543c99fb5f9SBaptiste Daroussin if (ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE)) { 1544c99fb5f9SBaptiste Daroussin ucl_chunk_skipc (chunk, p); 1545c99fb5f9SBaptiste Daroussin } 1546c99fb5f9SBaptiste Daroussin else { 1547c99fb5f9SBaptiste Daroussin break; 1548c99fb5f9SBaptiste Daroussin } 1549c99fb5f9SBaptiste Daroussin } 1550c99fb5f9SBaptiste Daroussin c = p; 1551c99fb5f9SBaptiste Daroussin while (p < chunk->end) { 1552c99fb5f9SBaptiste Daroussin if (*p == '}') { 1553c99fb5f9SBaptiste Daroussin break; 1554c99fb5f9SBaptiste Daroussin } 1555c99fb5f9SBaptiste Daroussin ucl_chunk_skipc (chunk, p); 1556c99fb5f9SBaptiste Daroussin } 1557c99fb5f9SBaptiste Daroussin *macro_start = c; 1558c99fb5f9SBaptiste Daroussin *macro_len = p - c; 1559c99fb5f9SBaptiste Daroussin ucl_chunk_skipc (chunk, p); 1560c99fb5f9SBaptiste Daroussin break; 1561c99fb5f9SBaptiste Daroussin default: 1562c99fb5f9SBaptiste Daroussin /* Macro is not enclosed in quotes or braces */ 1563c99fb5f9SBaptiste Daroussin c = p; 1564c99fb5f9SBaptiste Daroussin while (p < chunk->end) { 1565c99fb5f9SBaptiste Daroussin if (ucl_lex_is_atom_end (*p)) { 1566c99fb5f9SBaptiste Daroussin break; 1567c99fb5f9SBaptiste Daroussin } 1568c99fb5f9SBaptiste Daroussin ucl_chunk_skipc (chunk, p); 1569c99fb5f9SBaptiste Daroussin } 1570c99fb5f9SBaptiste Daroussin *macro_start = c; 1571c99fb5f9SBaptiste Daroussin *macro_len = p - c; 1572c99fb5f9SBaptiste Daroussin break; 1573c99fb5f9SBaptiste Daroussin } 1574c99fb5f9SBaptiste Daroussin 1575c99fb5f9SBaptiste Daroussin /* We are at the end of a macro */ 1576c99fb5f9SBaptiste Daroussin /* Skip ';' and space characters and return to previous state */ 1577c99fb5f9SBaptiste Daroussin while (p < chunk->end) { 1578c99fb5f9SBaptiste Daroussin if (!ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE) && *p != ';') { 1579c99fb5f9SBaptiste Daroussin break; 1580c99fb5f9SBaptiste Daroussin } 1581c99fb5f9SBaptiste Daroussin ucl_chunk_skipc (chunk, p); 1582c99fb5f9SBaptiste Daroussin } 1583c99fb5f9SBaptiste Daroussin return true; 1584c99fb5f9SBaptiste Daroussin } 1585c99fb5f9SBaptiste Daroussin 1586c99fb5f9SBaptiste Daroussin /** 1587c99fb5f9SBaptiste Daroussin * Handle the main states of rcl parser 1588c99fb5f9SBaptiste Daroussin * @param parser parser structure 1589c99fb5f9SBaptiste Daroussin * @param data the pointer to the beginning of a chunk 1590c99fb5f9SBaptiste Daroussin * @param len the length of a chunk 1591c99fb5f9SBaptiste Daroussin * @return true if chunk has been parsed and false in case of error 1592c99fb5f9SBaptiste Daroussin */ 1593c99fb5f9SBaptiste Daroussin static bool 1594c99fb5f9SBaptiste Daroussin ucl_state_machine (struct ucl_parser *parser) 1595c99fb5f9SBaptiste Daroussin { 1596c99fb5f9SBaptiste Daroussin ucl_object_t *obj; 1597c99fb5f9SBaptiste Daroussin struct ucl_chunk *chunk = parser->chunks; 1598c99fb5f9SBaptiste Daroussin const unsigned char *p, *c = NULL, *macro_start = NULL; 1599c99fb5f9SBaptiste Daroussin unsigned char *macro_escaped; 1600c99fb5f9SBaptiste Daroussin size_t macro_len = 0; 1601c99fb5f9SBaptiste Daroussin struct ucl_macro *macro = NULL; 1602c99fb5f9SBaptiste Daroussin bool next_key = false, end_of_object = false; 1603c99fb5f9SBaptiste Daroussin 1604c99fb5f9SBaptiste Daroussin if (parser->top_obj == NULL) { 1605c99fb5f9SBaptiste Daroussin if (*chunk->pos == '[') { 1606c99fb5f9SBaptiste Daroussin obj = ucl_add_parser_stack (NULL, parser, true, 0); 1607c99fb5f9SBaptiste Daroussin } 1608c99fb5f9SBaptiste Daroussin else { 1609c99fb5f9SBaptiste Daroussin obj = ucl_add_parser_stack (NULL, parser, false, 0); 1610c99fb5f9SBaptiste Daroussin } 1611c99fb5f9SBaptiste Daroussin parser->top_obj = obj; 1612c99fb5f9SBaptiste Daroussin parser->cur_obj = obj; 1613c99fb5f9SBaptiste Daroussin parser->state = UCL_STATE_INIT; 1614c99fb5f9SBaptiste Daroussin } 1615c99fb5f9SBaptiste Daroussin 1616c99fb5f9SBaptiste Daroussin p = chunk->pos; 1617c99fb5f9SBaptiste Daroussin while (chunk->pos < chunk->end) { 1618c99fb5f9SBaptiste Daroussin switch (parser->state) { 1619c99fb5f9SBaptiste Daroussin case UCL_STATE_INIT: 1620c99fb5f9SBaptiste Daroussin /* 1621c99fb5f9SBaptiste Daroussin * At the init state we can either go to the parse array or object 1622c99fb5f9SBaptiste Daroussin * if we got [ or { correspondingly or can just treat new data as 1623c99fb5f9SBaptiste Daroussin * a key of newly created object 1624c99fb5f9SBaptiste Daroussin */ 1625c99fb5f9SBaptiste Daroussin obj = parser->cur_obj; 1626c99fb5f9SBaptiste Daroussin if (!ucl_skip_comments (parser)) { 1627c99fb5f9SBaptiste Daroussin parser->prev_state = parser->state; 1628c99fb5f9SBaptiste Daroussin parser->state = UCL_STATE_ERROR; 1629c99fb5f9SBaptiste Daroussin return false; 1630c99fb5f9SBaptiste Daroussin } 1631c99fb5f9SBaptiste Daroussin else { 1632c99fb5f9SBaptiste Daroussin p = chunk->pos; 1633c99fb5f9SBaptiste Daroussin if (*p == '[') { 1634c99fb5f9SBaptiste Daroussin parser->state = UCL_STATE_VALUE; 1635c99fb5f9SBaptiste Daroussin ucl_chunk_skipc (chunk, p); 1636c99fb5f9SBaptiste Daroussin } 1637c99fb5f9SBaptiste Daroussin else { 1638c99fb5f9SBaptiste Daroussin parser->state = UCL_STATE_KEY; 1639c99fb5f9SBaptiste Daroussin if (*p == '{') { 1640c99fb5f9SBaptiste Daroussin ucl_chunk_skipc (chunk, p); 1641c99fb5f9SBaptiste Daroussin } 1642c99fb5f9SBaptiste Daroussin } 1643c99fb5f9SBaptiste Daroussin } 1644c99fb5f9SBaptiste Daroussin break; 1645c99fb5f9SBaptiste Daroussin case UCL_STATE_KEY: 1646c99fb5f9SBaptiste Daroussin /* Skip any spaces */ 1647c99fb5f9SBaptiste Daroussin while (p < chunk->end && ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE)) { 1648c99fb5f9SBaptiste Daroussin ucl_chunk_skipc (chunk, p); 1649c99fb5f9SBaptiste Daroussin } 1650c99fb5f9SBaptiste Daroussin if (*p == '}') { 1651c99fb5f9SBaptiste Daroussin /* We have the end of an object */ 1652c99fb5f9SBaptiste Daroussin parser->state = UCL_STATE_AFTER_VALUE; 1653c99fb5f9SBaptiste Daroussin continue; 1654c99fb5f9SBaptiste Daroussin } 1655c99fb5f9SBaptiste Daroussin if (parser->stack == NULL) { 1656c99fb5f9SBaptiste Daroussin /* No objects are on stack, but we want to parse a key */ 1657c99fb5f9SBaptiste Daroussin ucl_set_err (chunk, UCL_ESYNTAX, "top object is finished but the parser " 1658c99fb5f9SBaptiste Daroussin "expects a key", &parser->err); 1659c99fb5f9SBaptiste Daroussin parser->prev_state = parser->state; 1660c99fb5f9SBaptiste Daroussin parser->state = UCL_STATE_ERROR; 1661c99fb5f9SBaptiste Daroussin return false; 1662c99fb5f9SBaptiste Daroussin } 1663c99fb5f9SBaptiste Daroussin if (!ucl_parse_key (parser, chunk, &next_key, &end_of_object)) { 1664c99fb5f9SBaptiste Daroussin parser->prev_state = parser->state; 1665c99fb5f9SBaptiste Daroussin parser->state = UCL_STATE_ERROR; 1666c99fb5f9SBaptiste Daroussin return false; 1667c99fb5f9SBaptiste Daroussin } 1668c99fb5f9SBaptiste Daroussin if (end_of_object) { 1669c99fb5f9SBaptiste Daroussin p = chunk->pos; 1670c99fb5f9SBaptiste Daroussin parser->state = UCL_STATE_AFTER_VALUE; 1671c99fb5f9SBaptiste Daroussin continue; 1672c99fb5f9SBaptiste Daroussin } 1673c99fb5f9SBaptiste Daroussin else if (parser->state != UCL_STATE_MACRO_NAME) { 1674c99fb5f9SBaptiste Daroussin if (next_key && parser->stack->obj->type == UCL_OBJECT) { 1675c99fb5f9SBaptiste Daroussin /* Parse more keys and nest objects accordingly */ 1676c99fb5f9SBaptiste Daroussin obj = ucl_add_parser_stack (parser->cur_obj, parser, false, parser->stack->level + 1); 1677c99fb5f9SBaptiste Daroussin } 1678c99fb5f9SBaptiste Daroussin else { 1679c99fb5f9SBaptiste Daroussin parser->state = UCL_STATE_VALUE; 1680c99fb5f9SBaptiste Daroussin } 1681c99fb5f9SBaptiste Daroussin } 1682c99fb5f9SBaptiste Daroussin else { 1683c99fb5f9SBaptiste Daroussin c = chunk->pos; 1684c99fb5f9SBaptiste Daroussin } 1685c99fb5f9SBaptiste Daroussin p = chunk->pos; 1686c99fb5f9SBaptiste Daroussin break; 1687c99fb5f9SBaptiste Daroussin case UCL_STATE_VALUE: 1688c99fb5f9SBaptiste Daroussin /* We need to check what we do have */ 1689c99fb5f9SBaptiste Daroussin if (!ucl_parse_value (parser, chunk)) { 1690c99fb5f9SBaptiste Daroussin parser->prev_state = parser->state; 1691c99fb5f9SBaptiste Daroussin parser->state = UCL_STATE_ERROR; 1692c99fb5f9SBaptiste Daroussin return false; 1693c99fb5f9SBaptiste Daroussin } 1694c99fb5f9SBaptiste Daroussin /* State is set in ucl_parse_value call */ 1695c99fb5f9SBaptiste Daroussin p = chunk->pos; 1696c99fb5f9SBaptiste Daroussin break; 1697c99fb5f9SBaptiste Daroussin case UCL_STATE_AFTER_VALUE: 1698c99fb5f9SBaptiste Daroussin if (!ucl_parse_after_value (parser, chunk)) { 1699c99fb5f9SBaptiste Daroussin parser->prev_state = parser->state; 1700c99fb5f9SBaptiste Daroussin parser->state = UCL_STATE_ERROR; 1701c99fb5f9SBaptiste Daroussin return false; 1702c99fb5f9SBaptiste Daroussin } 1703c99fb5f9SBaptiste Daroussin if (parser->stack != NULL) { 1704c99fb5f9SBaptiste Daroussin if (parser->stack->obj->type == UCL_OBJECT) { 1705c99fb5f9SBaptiste Daroussin parser->state = UCL_STATE_KEY; 1706c99fb5f9SBaptiste Daroussin } 1707c99fb5f9SBaptiste Daroussin else { 1708c99fb5f9SBaptiste Daroussin /* Array */ 1709c99fb5f9SBaptiste Daroussin parser->state = UCL_STATE_VALUE; 1710c99fb5f9SBaptiste Daroussin } 1711c99fb5f9SBaptiste Daroussin } 1712c99fb5f9SBaptiste Daroussin else { 1713c99fb5f9SBaptiste Daroussin /* Skip everything at the end */ 1714c99fb5f9SBaptiste Daroussin return true; 1715c99fb5f9SBaptiste Daroussin } 1716c99fb5f9SBaptiste Daroussin p = chunk->pos; 1717c99fb5f9SBaptiste Daroussin break; 1718c99fb5f9SBaptiste Daroussin case UCL_STATE_MACRO_NAME: 1719c99fb5f9SBaptiste Daroussin if (!ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE)) { 1720c99fb5f9SBaptiste Daroussin ucl_chunk_skipc (chunk, p); 1721c99fb5f9SBaptiste Daroussin } 1722c99fb5f9SBaptiste Daroussin else if (p - c > 0) { 1723c99fb5f9SBaptiste Daroussin /* We got macro name */ 1724c99fb5f9SBaptiste Daroussin macro_len = (size_t)(p - c); 1725c99fb5f9SBaptiste Daroussin HASH_FIND (hh, parser->macroes, c, macro_len, macro); 1726c99fb5f9SBaptiste Daroussin if (macro == NULL) { 1727c99fb5f9SBaptiste Daroussin ucl_create_err (&parser->err, "error on line %d at column %d: " 1728c99fb5f9SBaptiste Daroussin "unknown macro: '%.*s', character: '%c'", 1729c99fb5f9SBaptiste Daroussin chunk->line, chunk->column, (int)(p - c), c, *chunk->pos); 1730c99fb5f9SBaptiste Daroussin parser->state = UCL_STATE_ERROR; 1731c99fb5f9SBaptiste Daroussin return false; 1732c99fb5f9SBaptiste Daroussin } 1733c99fb5f9SBaptiste Daroussin /* Now we need to skip all spaces */ 1734c99fb5f9SBaptiste Daroussin while (p < chunk->end) { 1735c99fb5f9SBaptiste Daroussin if (!ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE)) { 1736c99fb5f9SBaptiste Daroussin if (chunk->remain >= 2 && ucl_lex_is_comment (p[0], p[1])) { 1737c99fb5f9SBaptiste Daroussin /* Skip comment */ 1738c99fb5f9SBaptiste Daroussin if (!ucl_skip_comments (parser)) { 1739c99fb5f9SBaptiste Daroussin return false; 1740c99fb5f9SBaptiste Daroussin } 1741c99fb5f9SBaptiste Daroussin p = chunk->pos; 1742c99fb5f9SBaptiste Daroussin } 1743c99fb5f9SBaptiste Daroussin break; 1744c99fb5f9SBaptiste Daroussin } 1745c99fb5f9SBaptiste Daroussin ucl_chunk_skipc (chunk, p); 1746c99fb5f9SBaptiste Daroussin } 1747c99fb5f9SBaptiste Daroussin parser->state = UCL_STATE_MACRO; 1748c99fb5f9SBaptiste Daroussin } 1749c99fb5f9SBaptiste Daroussin break; 1750c99fb5f9SBaptiste Daroussin case UCL_STATE_MACRO: 1751c99fb5f9SBaptiste Daroussin if (!ucl_parse_macro_value (parser, chunk, macro, 1752c99fb5f9SBaptiste Daroussin ¯o_start, ¯o_len)) { 1753c99fb5f9SBaptiste Daroussin parser->prev_state = parser->state; 1754c99fb5f9SBaptiste Daroussin parser->state = UCL_STATE_ERROR; 1755c99fb5f9SBaptiste Daroussin return false; 1756c99fb5f9SBaptiste Daroussin } 1757c99fb5f9SBaptiste Daroussin macro_len = ucl_expand_variable (parser, ¯o_escaped, macro_start, macro_len); 1758c99fb5f9SBaptiste Daroussin parser->state = parser->prev_state; 1759c99fb5f9SBaptiste Daroussin if (macro_escaped == NULL) { 1760c99fb5f9SBaptiste Daroussin if (!macro->handler (macro_start, macro_len, macro->ud)) { 1761c99fb5f9SBaptiste Daroussin return false; 1762c99fb5f9SBaptiste Daroussin } 1763c99fb5f9SBaptiste Daroussin } 1764c99fb5f9SBaptiste Daroussin else { 1765c99fb5f9SBaptiste Daroussin if (!macro->handler (macro_escaped, macro_len, macro->ud)) { 1766c99fb5f9SBaptiste Daroussin UCL_FREE (macro_len + 1, macro_escaped); 1767c99fb5f9SBaptiste Daroussin return false; 1768c99fb5f9SBaptiste Daroussin } 1769c99fb5f9SBaptiste Daroussin UCL_FREE (macro_len + 1, macro_escaped); 1770c99fb5f9SBaptiste Daroussin } 1771c99fb5f9SBaptiste Daroussin p = chunk->pos; 1772c99fb5f9SBaptiste Daroussin break; 1773c99fb5f9SBaptiste Daroussin default: 1774c99fb5f9SBaptiste Daroussin /* TODO: add all states */ 1775c99fb5f9SBaptiste Daroussin ucl_set_err (chunk, UCL_EINTERNAL, "internal error: parser is in an unknown state", &parser->err); 1776c99fb5f9SBaptiste Daroussin parser->state = UCL_STATE_ERROR; 1777c99fb5f9SBaptiste Daroussin return false; 1778c99fb5f9SBaptiste Daroussin } 1779c99fb5f9SBaptiste Daroussin } 1780c99fb5f9SBaptiste Daroussin 1781c99fb5f9SBaptiste Daroussin return true; 1782c99fb5f9SBaptiste Daroussin } 1783c99fb5f9SBaptiste Daroussin 1784c99fb5f9SBaptiste Daroussin struct ucl_parser* 1785c99fb5f9SBaptiste Daroussin ucl_parser_new (int flags) 1786c99fb5f9SBaptiste Daroussin { 1787c99fb5f9SBaptiste Daroussin struct ucl_parser *new; 1788c99fb5f9SBaptiste Daroussin 1789c99fb5f9SBaptiste Daroussin new = UCL_ALLOC (sizeof (struct ucl_parser)); 1790c99fb5f9SBaptiste Daroussin memset (new, 0, sizeof (struct ucl_parser)); 1791c99fb5f9SBaptiste Daroussin 1792c99fb5f9SBaptiste Daroussin ucl_parser_register_macro (new, "include", ucl_include_handler, new); 1793c99fb5f9SBaptiste Daroussin ucl_parser_register_macro (new, "try_include", ucl_try_include_handler, new); 1794c99fb5f9SBaptiste Daroussin ucl_parser_register_macro (new, "includes", ucl_includes_handler, new); 1795c99fb5f9SBaptiste Daroussin 1796c99fb5f9SBaptiste Daroussin new->flags = flags; 1797c99fb5f9SBaptiste Daroussin 1798c99fb5f9SBaptiste Daroussin /* Initial assumption about filevars */ 1799c99fb5f9SBaptiste Daroussin ucl_parser_set_filevars (new, NULL, false); 1800c99fb5f9SBaptiste Daroussin 1801c99fb5f9SBaptiste Daroussin return new; 1802c99fb5f9SBaptiste Daroussin } 1803c99fb5f9SBaptiste Daroussin 1804c99fb5f9SBaptiste Daroussin 1805c99fb5f9SBaptiste Daroussin void 1806c99fb5f9SBaptiste Daroussin ucl_parser_register_macro (struct ucl_parser *parser, const char *macro, 1807c99fb5f9SBaptiste Daroussin ucl_macro_handler handler, void* ud) 1808c99fb5f9SBaptiste Daroussin { 1809c99fb5f9SBaptiste Daroussin struct ucl_macro *new; 1810c99fb5f9SBaptiste Daroussin 1811c99fb5f9SBaptiste Daroussin new = UCL_ALLOC (sizeof (struct ucl_macro)); 1812c99fb5f9SBaptiste Daroussin memset (new, 0, sizeof (struct ucl_macro)); 1813c99fb5f9SBaptiste Daroussin new->handler = handler; 1814c99fb5f9SBaptiste Daroussin new->name = strdup (macro); 1815c99fb5f9SBaptiste Daroussin new->ud = ud; 1816c99fb5f9SBaptiste Daroussin HASH_ADD_KEYPTR (hh, parser->macroes, new->name, strlen (new->name), new); 1817c99fb5f9SBaptiste Daroussin } 1818c99fb5f9SBaptiste Daroussin 1819c99fb5f9SBaptiste Daroussin void 1820c99fb5f9SBaptiste Daroussin ucl_parser_register_variable (struct ucl_parser *parser, const char *var, 1821c99fb5f9SBaptiste Daroussin const char *value) 1822c99fb5f9SBaptiste Daroussin { 1823c99fb5f9SBaptiste Daroussin struct ucl_variable *new = NULL, *cur; 1824c99fb5f9SBaptiste Daroussin 1825c99fb5f9SBaptiste Daroussin if (var == NULL) { 1826c99fb5f9SBaptiste Daroussin return; 1827c99fb5f9SBaptiste Daroussin } 1828c99fb5f9SBaptiste Daroussin 1829c99fb5f9SBaptiste Daroussin /* Find whether a variable already exists */ 1830c99fb5f9SBaptiste Daroussin LL_FOREACH (parser->variables, cur) { 1831c99fb5f9SBaptiste Daroussin if (strcmp (cur->var, var) == 0) { 1832c99fb5f9SBaptiste Daroussin new = cur; 1833c99fb5f9SBaptiste Daroussin break; 1834c99fb5f9SBaptiste Daroussin } 1835c99fb5f9SBaptiste Daroussin } 1836c99fb5f9SBaptiste Daroussin 1837c99fb5f9SBaptiste Daroussin if (value == NULL) { 1838c99fb5f9SBaptiste Daroussin 1839c99fb5f9SBaptiste Daroussin if (new != NULL) { 1840c99fb5f9SBaptiste Daroussin /* Remove variable */ 1841c99fb5f9SBaptiste Daroussin LL_DELETE (parser->variables, new); 1842c99fb5f9SBaptiste Daroussin free (new->var); 1843c99fb5f9SBaptiste Daroussin free (new->value); 1844c99fb5f9SBaptiste Daroussin UCL_FREE (sizeof (struct ucl_variable), new); 1845c99fb5f9SBaptiste Daroussin } 1846c99fb5f9SBaptiste Daroussin else { 1847c99fb5f9SBaptiste Daroussin /* Do nothing */ 1848c99fb5f9SBaptiste Daroussin return; 1849c99fb5f9SBaptiste Daroussin } 1850c99fb5f9SBaptiste Daroussin } 1851c99fb5f9SBaptiste Daroussin else { 1852c99fb5f9SBaptiste Daroussin if (new == NULL) { 1853c99fb5f9SBaptiste Daroussin new = UCL_ALLOC (sizeof (struct ucl_variable)); 1854c99fb5f9SBaptiste Daroussin memset (new, 0, sizeof (struct ucl_variable)); 1855c99fb5f9SBaptiste Daroussin new->var = strdup (var); 1856c99fb5f9SBaptiste Daroussin new->var_len = strlen (var); 1857c99fb5f9SBaptiste Daroussin new->value = strdup (value); 1858c99fb5f9SBaptiste Daroussin new->value_len = strlen (value); 1859c99fb5f9SBaptiste Daroussin 1860c99fb5f9SBaptiste Daroussin LL_PREPEND (parser->variables, new); 1861c99fb5f9SBaptiste Daroussin } 1862c99fb5f9SBaptiste Daroussin else { 1863c99fb5f9SBaptiste Daroussin free (new->value); 1864c99fb5f9SBaptiste Daroussin new->value = strdup (value); 1865c99fb5f9SBaptiste Daroussin new->value_len = strlen (value); 1866c99fb5f9SBaptiste Daroussin } 1867c99fb5f9SBaptiste Daroussin } 1868c99fb5f9SBaptiste Daroussin } 1869c99fb5f9SBaptiste Daroussin 1870c99fb5f9SBaptiste Daroussin bool 1871c99fb5f9SBaptiste Daroussin ucl_parser_add_chunk (struct ucl_parser *parser, const unsigned char *data, 1872c99fb5f9SBaptiste Daroussin size_t len) 1873c99fb5f9SBaptiste Daroussin { 1874c99fb5f9SBaptiste Daroussin struct ucl_chunk *chunk; 1875c99fb5f9SBaptiste Daroussin 1876c99fb5f9SBaptiste Daroussin if (parser->state != UCL_STATE_ERROR) { 1877c99fb5f9SBaptiste Daroussin chunk = UCL_ALLOC (sizeof (struct ucl_chunk)); 1878c99fb5f9SBaptiste Daroussin chunk->begin = data; 1879c99fb5f9SBaptiste Daroussin chunk->remain = len; 1880c99fb5f9SBaptiste Daroussin chunk->pos = chunk->begin; 1881c99fb5f9SBaptiste Daroussin chunk->end = chunk->begin + len; 1882c99fb5f9SBaptiste Daroussin chunk->line = 1; 1883c99fb5f9SBaptiste Daroussin chunk->column = 0; 1884c99fb5f9SBaptiste Daroussin LL_PREPEND (parser->chunks, chunk); 1885c99fb5f9SBaptiste Daroussin parser->recursion ++; 1886c99fb5f9SBaptiste Daroussin if (parser->recursion > UCL_MAX_RECURSION) { 1887c99fb5f9SBaptiste Daroussin ucl_create_err (&parser->err, "maximum include nesting limit is reached: %d", 1888c99fb5f9SBaptiste Daroussin parser->recursion); 1889c99fb5f9SBaptiste Daroussin return false; 1890c99fb5f9SBaptiste Daroussin } 1891c99fb5f9SBaptiste Daroussin return ucl_state_machine (parser); 1892c99fb5f9SBaptiste Daroussin } 1893c99fb5f9SBaptiste Daroussin 1894c99fb5f9SBaptiste Daroussin ucl_create_err (&parser->err, "a parser is in an invalid state"); 1895c99fb5f9SBaptiste Daroussin 1896c99fb5f9SBaptiste Daroussin return false; 1897c99fb5f9SBaptiste Daroussin } 1898