Rapid spam filtering system https://rspamd.com/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3136 lines
68 KiB

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