From 7ecc32babdc9ea9db7f051923d95715fbcc3a30f Mon Sep 17 00:00:00 2001 From: Vsevolod Stakhov Date: Wed, 23 Oct 2013 16:51:01 +0100 Subject: [PATCH] Sync with libucl. --- src/ucl/include/ucl.h | 135 ++++++++++++++-------------- src/ucl/src/ucl_chartable.h | 29 +++--- src/ucl/src/ucl_emitter.c | 14 ++- src/ucl/src/ucl_internal.h | 9 +- src/ucl/src/ucl_parser.c | 163 ++++++++++++++++++---------------- src/ucl/src/ucl_util.c | 107 ++++++++++++++++------ src/ucl/tests/generate.res | 3 + src/ucl/tests/test_basic.c | 22 ++--- src/ucl/tests/test_generate.c | 7 ++ src/ucl/tests/test_speed.c | 11 ++- 10 files changed, 289 insertions(+), 211 deletions(-) diff --git a/src/ucl/include/ucl.h b/src/ucl/include/ucl.h index 1b8fa8631..0f132a375 100644 --- a/src/ucl/include/ucl.h +++ b/src/ucl/include/ucl.h @@ -35,7 +35,6 @@ #include "uthash.h" #include "utlist.h" -#include "utstring.h" /** * @file rcl.h @@ -90,29 +89,65 @@ enum ucl_error { UCL_ESSL //!< UCL_ESSL }; +/** + * Object types + */ enum ucl_type { - UCL_OBJECT = 0, - UCL_ARRAY, - UCL_INT, - UCL_FLOAT, - UCL_STRING, - UCL_BOOLEAN, - UCL_TIME, - UCL_USERDATA + UCL_OBJECT = 0,//!< UCL_OBJECT + UCL_ARRAY, //!< UCL_ARRAY + UCL_INT, //!< UCL_INT + UCL_FLOAT, //!< UCL_FLOAT + UCL_STRING, //!< UCL_STRING + UCL_BOOLEAN, //!< UCL_BOOLEAN + UCL_TIME, //!< UCL_TIME + UCL_USERDATA //!< UCL_USERDATA }; +/** + * Emitting types + */ enum ucl_emitter { - UCL_EMIT_JSON = 0, - UCL_EMIT_JSON_COMPACT, - UCL_EMIT_CONFIG, - UCL_EMIT_YAML + UCL_EMIT_JSON = 0, //!< UCL_EMIT_JSON + UCL_EMIT_JSON_COMPACT,//!< UCL_EMIT_JSON_COMPACT + UCL_EMIT_CONFIG, //!< UCL_EMIT_CONFIG + UCL_EMIT_YAML //!< UCL_EMIT_YAML +}; + +/** + * Parsing flags + */ +enum ucl_parser_flags { + UCL_PARSER_KEY_LOWERCASE = 0x1,//!< UCL_FLAG_KEY_LOWERCASE + UCL_PARSER_ZEROCOPY = 0x2 //!< UCL_FLAG_ZEROCOPY +}; + +/** + * String conversion flags + */ +enum ucl_string_flags { + UCL_STRING_ESCAPE = 0x1, /**< UCL_STRING_ESCAPE perform JSON escape */ + UCL_STRING_TRIM = 0x2, /**< UCL_STRING_TRIM trim leading and trailing whitespaces */ + UCL_STRING_PARSE_BOOLEAN = 0x4, /**< UCL_STRING_PARSE_BOOLEAN parse passed string and detect boolean */ + UCL_STRING_PARSE_INT = 0x8, /**< UCL_STRING_PARSE_INT parse passed string and detect integer number */ + UCL_STRING_PARSE_DOUBLE = 0x10, /**< UCL_STRING_PARSE_DOUBLE parse passed string and detect integer or float number */ + UCL_STRING_PARSE_NUMBER = UCL_STRING_PARSE_INT|UCL_STRING_PARSE_DOUBLE , /**< + UCL_STRING_PARSE_NUMBER parse passed string and detect number */ + UCL_STRING_PARSE = UCL_STRING_PARSE_BOOLEAN|UCL_STRING_PARSE_NUMBER /**< + UCL_STRING_PARSE parse passed string (and detect booleans and numbers) */ }; -enum ucl_flags { - UCL_FLAG_KEY_LOWERCASE = 0x1, - UCL_FLAG_ZEROCOPY = 0x2 +/** + * Basic flags for an object + */ +enum ucl_object_flags { + UCL_OBJECT_ALLOCATED_KEY = 1, //!< UCL_OBJECT_ALLOCATED_KEY + UCL_OBJECT_ALLOCATED_VALUE = 2, //!< UCL_OBJECT_ALLOCATED_VALUE + UCL_OBJECT_NEED_KEY_ESCAPE = 4 //!< UCL_OBJECT_NEED_KEY_ESCAPE }; +/** + * UCL object + */ typedef struct ucl_object_s { union { int64_t iv; /**< int value of an object */ @@ -122,7 +157,8 @@ typedef struct ucl_object_s { void* ud; /**< opaque user data */ } value; enum ucl_type type; /**< real type */ - int ref; /**< reference count */ + short int ref; /**< reference count */ + short int flags; /**< object flags */ size_t len; /**< size of an object */ struct ucl_object_s *next; /**< array handle */ struct ucl_object_s *prev; /**< array handle */ @@ -161,21 +197,6 @@ ucl_object_new (void) return new; } -/** - * String conversion flags - */ -enum ucl_string_flags { - UCL_STRING_ESCAPE = 0x1, /**< UCL_STRING_ESCAPE perform JSON escape */ - UCL_STRING_TRIM = 0x2, /**< UCL_STRING_TRIM trim leading and trailing whitespaces */ - UCL_STRING_PARSE_BOOLEAN = 0x4, /**< UCL_STRING_PARSE_BOOLEAN parse passed string and detect boolean */ - UCL_STRING_PARSE_INT = 0x8, /**< UCL_STRING_PARSE_INT parse passed string and detect integer number */ - UCL_STRING_PARSE_DOUBLE = 0x10, /**< UCL_STRING_PARSE_DOUBLE parse passed string and detect integer or float number */ - UCL_STRING_PARSE_NUMBER = UCL_STRING_PARSE_INT|UCL_STRING_PARSE_DOUBLE , /**< - UCL_STRING_PARSE_NUMBER parse passed string and detect number */ - UCL_STRING_PARSE = UCL_STRING_PARSE_BOOLEAN|UCL_STRING_PARSE_NUMBER /**< - UCL_STRING_PARSE parse passed string (and detect booleans and numbers) */ -}; - /** * Convert any string to an ucl object making the specified transformations * @param str fixed size or NULL terminated string @@ -274,37 +295,8 @@ ucl_object_frombool (bool bv) * @param copy_key make an internal copy of key * @return new value of top object */ -static inline ucl_object_t * -ucl_object_insert_key (ucl_object_t *top, ucl_object_t *elt, - const char *key, size_t keylen, bool copy_key) -{ - ucl_object_t *found; - - if (elt == NULL || key == NULL) { - return NULL; - } - - if (top == NULL) { - top = ucl_object_new (); - top->type = UCL_OBJECT; - } - if (keylen == 0) { - keylen = strlen (key); - } - - HASH_FIND (hh, top->value.ov, key, keylen, found); - - if (!found) { - HASH_ADD_KEYPTR (hh, top->value.ov, key, keylen, elt); - } - DL_APPEND (found, elt); - - if (copy_key) { - ucl_copy_key_trash (elt); - } - - return top; -} +ucl_object_t* ucl_object_insert_key (ucl_object_t *top, ucl_object_t *elt, + const char *key, size_t keylen, bool copy_key); /** * Append an element to the array object @@ -625,7 +617,7 @@ ucl_object_keyl (ucl_object_t *obj, size_t *len) * @param err error pointer * @return true if macro has been parsed */ -typedef bool (*ucl_macro_handler) (const unsigned char *data, size_t len, void* ud, UT_string **err); +typedef bool (*ucl_macro_handler) (const unsigned char *data, size_t len, void* ud); /* Opaque parser */ struct ucl_parser; @@ -655,8 +647,7 @@ void ucl_parser_register_macro (struct ucl_parser *parser, const char *macro, * @param err if *err is NULL it is set to parser error * @return true if chunk has been added and false in case of error */ -bool ucl_parser_add_chunk (struct ucl_parser *parser, const unsigned char *data, - size_t len, UT_string **err); +bool ucl_parser_add_chunk (struct ucl_parser *parser, const unsigned char *data, size_t len); /** * Load and add data from a file @@ -665,8 +656,7 @@ bool ucl_parser_add_chunk (struct ucl_parser *parser, const unsigned char *data, * @param err if *err is NULL it is set to parser error * @return true if chunk has been added and false in case of error */ -bool ucl_parser_add_file (struct ucl_parser *parser, const char *filename, - UT_string **err); +bool ucl_parser_add_file (struct ucl_parser *parser, const char *filename); /** * Get a top object for a parser @@ -674,8 +664,13 @@ bool ucl_parser_add_file (struct ucl_parser *parser, const char *filename, * @param err if *err is NULL it is set to parser error * @return top parser object or NULL */ -ucl_object_t* ucl_parser_get_object (struct ucl_parser *parser, UT_string **err); +ucl_object_t* ucl_parser_get_object (struct ucl_parser *parser); +/** + * Get the error string if failing + * @param parser parser object + */ +const char *ucl_parser_get_error(struct ucl_parser *parser); /** * Free cl parser object * @param parser parser object @@ -726,6 +721,6 @@ unsigned char *ucl_object_emit (ucl_object_t *obj, enum ucl_emitter emit_type); * @param err if *err is NULL it is set to parser error * @return true if a key has been successfully added */ -bool ucl_pubkey_add (struct ucl_parser *parser, const unsigned char *key, size_t len, UT_string **err); +bool ucl_pubkey_add (struct ucl_parser *parser, const unsigned char *key, size_t len); #endif /* RCL_H_ */ diff --git a/src/ucl/src/ucl_chartable.h b/src/ucl/src/ucl_chartable.h index 232043c1b..5248e117c 100644 --- a/src/ucl/src/ucl_chartable.h +++ b/src/ucl/src/ucl_chartable.h @@ -29,21 +29,22 @@ static const unsigned int ucl_chartable[255] = { UCL_CHARACTER_VALUE_END, UCL_CHARACTER_DENIED, UCL_CHARACTER_DENIED, UCL_CHARACTER_DENIED, UCL_CHARACTER_DENIED, UCL_CHARACTER_DENIED, -UCL_CHARACTER_DENIED, UCL_CHARACTER_DENIED, UCL_CHARACTER_JSON_UNSAFE, -UCL_CHARACTER_WHITESPACE|UCL_CHARACTER_WHITESPACE_UNSAFE|UCL_CHARACTER_KEY_SEP|UCL_CHARACTER_JSON_UNSAFE, -UCL_CHARACTER_WHITESPACE_UNSAFE|UCL_CHARACTER_VALUE_END|UCL_CHARACTER_JSON_UNSAFE, +UCL_CHARACTER_DENIED, UCL_CHARACTER_DENIED, +UCL_CHARACTER_JSON_UNSAFE|UCL_CHARACTER_UCL_UNSAFE, +UCL_CHARACTER_WHITESPACE|UCL_CHARACTER_WHITESPACE_UNSAFE|UCL_CHARACTER_KEY_SEP|UCL_CHARACTER_JSON_UNSAFE|UCL_CHARACTER_UCL_UNSAFE, +UCL_CHARACTER_WHITESPACE_UNSAFE|UCL_CHARACTER_VALUE_END|UCL_CHARACTER_JSON_UNSAFE|UCL_CHARACTER_UCL_UNSAFE, UCL_CHARACTER_WHITESPACE_UNSAFE, -UCL_CHARACTER_WHITESPACE_UNSAFE|UCL_CHARACTER_JSON_UNSAFE, -UCL_CHARACTER_WHITESPACE_UNSAFE|UCL_CHARACTER_VALUE_END|UCL_CHARACTER_JSON_UNSAFE, +UCL_CHARACTER_WHITESPACE_UNSAFE|UCL_CHARACTER_JSON_UNSAFE|UCL_CHARACTER_UCL_UNSAFE, +UCL_CHARACTER_WHITESPACE_UNSAFE|UCL_CHARACTER_VALUE_END|UCL_CHARACTER_JSON_UNSAFE|UCL_CHARACTER_UCL_UNSAFE, UCL_CHARACTER_DENIED, UCL_CHARACTER_DENIED, UCL_CHARACTER_DENIED, UCL_CHARACTER_DENIED, UCL_CHARACTER_DENIED, UCL_CHARACTER_DENIED, UCL_CHARACTER_DENIED, UCL_CHARACTER_DENIED, UCL_CHARACTER_DENIED, UCL_CHARACTER_DENIED, UCL_CHARACTER_DENIED, UCL_CHARACTER_DENIED, UCL_CHARACTER_DENIED, UCL_CHARACTER_DENIED, UCL_CHARACTER_DENIED, UCL_CHARACTER_DENIED, UCL_CHARACTER_DENIED, UCL_CHARACTER_DENIED, -UCL_CHARACTER_WHITESPACE|UCL_CHARACTER_WHITESPACE_UNSAFE|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_KEY_SEP /* */, +UCL_CHARACTER_WHITESPACE|UCL_CHARACTER_WHITESPACE_UNSAFE|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_KEY_SEP|UCL_CHARACTER_UCL_UNSAFE /* */, UCL_CHARACTER_VALUE_STR /* ! */, -UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_ESCAPE|UCL_CHARACTER_JSON_UNSAFE /* " */, +UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_ESCAPE|UCL_CHARACTER_JSON_UNSAFE|UCL_CHARACTER_UCL_UNSAFE /* " */, UCL_CHARACTER_VALUE_END /* # */, UCL_CHARACTER_VALUE_STR /* $ */, UCL_CHARACTER_VALUE_STR /* % */, UCL_CHARACTER_VALUE_STR /* & */, UCL_CHARACTER_VALUE_STR /* ' */, UCL_CHARACTER_VALUE_STR /* ( */, @@ -63,9 +64,9 @@ UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_ UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT_START|UCL_CHARACTER_VALUE_DIGIT /* 7 */, UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT_START|UCL_CHARACTER_VALUE_DIGIT /* 8 */, UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT_START|UCL_CHARACTER_VALUE_DIGIT /* 9 */, -UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_KEY_SEP /* : */, +UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_KEY_SEP|UCL_CHARACTER_UCL_UNSAFE /* : */, UCL_CHARACTER_VALUE_END /* ; */, UCL_CHARACTER_VALUE_STR /* < */, -UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_KEY_SEP /* = */, +UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_KEY_SEP|UCL_CHARACTER_UCL_UNSAFE /* = */, UCL_CHARACTER_VALUE_STR /* > */, UCL_CHARACTER_VALUE_STR /* ? */, UCL_CHARACTER_VALUE_STR /* @ */, UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* A */, @@ -94,8 +95,8 @@ UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_ UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* X */, UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* Y */, UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* Z */, -UCL_CHARACTER_VALUE_STR /* [ */, -UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_ESCAPE|UCL_CHARACTER_JSON_UNSAFE /* \ */, +UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_UCL_UNSAFE /* [ */, +UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_ESCAPE|UCL_CHARACTER_JSON_UNSAFE|UCL_CHARACTER_UCL_UNSAFE /* \ */, UCL_CHARACTER_VALUE_END /* ] */, UCL_CHARACTER_VALUE_STR /* ^ */, UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR /* _ */, UCL_CHARACTER_VALUE_STR /* ` */, @@ -125,9 +126,9 @@ UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_ UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* x */, UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* y */, UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* z */, -UCL_CHARACTER_VALUE_STR /* { */, UCL_CHARACTER_VALUE_STR /* | */, -UCL_CHARACTER_VALUE_END /* } */, UCL_CHARACTER_VALUE_STR /* ~ */, -UCL_CHARACTER_DENIED, +UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_UCL_UNSAFE /* { */, +UCL_CHARACTER_VALUE_STR /* | */, UCL_CHARACTER_VALUE_END /* } */, +UCL_CHARACTER_VALUE_STR /* ~ */, UCL_CHARACTER_DENIED, UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR, UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR, UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR, diff --git a/src/ucl/src/ucl_emitter.c b/src/ucl/src/ucl_emitter.c index 78e321c53..38d4b3d18 100644 --- a/src/ucl/src/ucl_emitter.c +++ b/src/ucl/src/ucl_emitter.c @@ -346,7 +346,12 @@ ucl_elt_obj_write_rcl (ucl_object_t *obj, UT_string *buf, unsigned int tabs, boo HASH_ITER (hh, obj, cur, tmp) { ucl_add_tabs (buf, tabs + 1, is_top); - utstring_append_len (buf, cur->hh.key, cur->hh.keylen); + if (cur->flags & UCL_OBJECT_NEED_KEY_ESCAPE) { + ucl_elt_string_write_json (cur->hh.key, cur->hh.keylen, buf); + } + else { + utstring_append_len (buf, cur->hh.key, cur->hh.keylen); + } if (cur->type != UCL_OBJECT && cur->type != UCL_ARRAY) { utstring_append_len (buf, " = ", 3); } @@ -481,7 +486,12 @@ ucl_elt_obj_write_yaml (ucl_object_t *obj, UT_string *buf, unsigned int tabs, bo HASH_ITER (hh, obj, cur, tmp) { ucl_add_tabs (buf, tabs + 1, is_top); - utstring_append_len (buf, cur->hh.key, cur->hh.keylen); + if (obj->flags & UCL_OBJECT_NEED_KEY_ESCAPE) { + ucl_elt_string_write_json (cur->hh.key, cur->hh.keylen, buf); + } + else { + utstring_append_len (buf, cur->hh.key, cur->hh.keylen); + } if (cur->type != UCL_OBJECT && cur->type != UCL_ARRAY) { utstring_append_len (buf, " : ", 3); } diff --git a/src/ucl/src/ucl_internal.h b/src/ucl/src/ucl_internal.h index 97613c824..393ecf85a 100644 --- a/src/ucl/src/ucl_internal.h +++ b/src/ucl/src/ucl_internal.h @@ -36,6 +36,7 @@ #include #include "utlist.h" +#include "utstring.h" #include "ucl.h" #ifdef HAVE_OPENSSL @@ -78,7 +79,8 @@ enum ucl_character_type { UCL_CHARACTER_VALUE_DIGIT_START = 1 << 7, UCL_CHARACTER_ESCAPE = 1 << 8, UCL_CHARACTER_KEY_SEP = 1 << 9, - UCL_CHARACTER_JSON_UNSAFE = 1 << 10 + UCL_CHARACTER_JSON_UNSAFE = 1 << 10, + UCL_CHARACTER_UCL_UNSAFE = 1 << 11 }; struct ucl_macro { @@ -125,6 +127,7 @@ struct ucl_parser { struct ucl_stack *stack; struct ucl_chunk *chunks; struct ucl_pubkey *keys; + UT_string *err; }; /** @@ -141,7 +144,7 @@ size_t ucl_unescape_json_string (char *str, size_t len); * @param err error ptr * @return */ -bool ucl_include_handler (const unsigned char *data, size_t len, void* ud, UT_string **err); +bool ucl_include_handler (const unsigned char *data, size_t len, void* ud); /** * Handle includes macro @@ -151,7 +154,7 @@ bool ucl_include_handler (const unsigned char *data, size_t len, void* ud, UT_st * @param err error ptr * @return */ -bool ucl_includes_handler (const unsigned char *data, size_t len, void* ud, UT_string **err); +bool ucl_includes_handler (const unsigned char *data, size_t len, void* ud); size_t ucl_strlcpy (char *dst, const char *src, size_t siz); size_t ucl_strlcpy_unsafe (char *dst, const char *src, size_t siz); diff --git a/src/ucl/src/ucl_parser.c b/src/ucl/src/ucl_parser.c index 30106ebd3..e125caee4 100644 --- a/src/ucl/src/ucl_parser.c +++ b/src/ucl/src/ucl_parser.c @@ -91,7 +91,7 @@ ucl_set_err (struct ucl_chunk *chunk, int code, const char *str, UT_string **err } static bool -ucl_skip_comments (struct ucl_parser *parser, UT_string **err) +ucl_skip_comments (struct ucl_parser *parser) { struct ucl_chunk *chunk = parser->chunks; const unsigned char *p; @@ -139,7 +139,7 @@ start: ucl_chunk_skipc (chunk, p); } if (comments_nested != 0) { - ucl_set_err (chunk, UCL_ENESTED, "comments nesting is invalid", err); + ucl_set_err (chunk, UCL_ENESTED, "comments nesting is invalid", &parser->err); return false; } } @@ -237,15 +237,15 @@ static inline size_t ucl_copy_or_store_ptr (struct ucl_parser *parser, const unsigned char *src, unsigned char **dst, const char **dst_const, size_t in_len, - bool need_unescape, bool need_lowercase, UT_string **err) + bool need_unescape, bool need_lowercase) { size_t ret = 0; - if (need_unescape || need_lowercase || !(parser->flags & UCL_FLAG_ZEROCOPY)) { + if (need_unescape || need_lowercase || !(parser->flags & UCL_PARSER_ZEROCOPY)) { /* Copy string */ *dst = UCL_ALLOC (in_len + 1); if (*dst == NULL) { - ucl_set_err (parser->chunks, 0, "cannot allocate memory for a string", err); + ucl_set_err (parser->chunks, 0, "cannot allocate memory for a string", &parser->err); return false; } if (need_lowercase) { @@ -274,7 +274,7 @@ ucl_maybe_parse_number (ucl_object_t *obj, { const char *p = start, *c = start; char *endptr; - bool got_dot = false, got_exp = false, need_double = false, is_date = false; + bool got_dot = false, got_exp = false, need_double = false, is_date = false, valid_start = false; double dv; int64_t lv; @@ -283,6 +283,7 @@ ucl_maybe_parse_number (ucl_object_t *obj, } while (p < end) { if (isdigit (*p)) { + valid_start = true; p ++; } else if (allow_double) { @@ -337,6 +338,11 @@ ucl_maybe_parse_number (ucl_object_t *obj, } } + if (!valid_start) { + *pos = start; + return EINVAL; + } + errno = 0; if (need_double) { dv = strtod (c, &endptr); @@ -355,7 +361,7 @@ ucl_maybe_parse_number (ucl_object_t *obj, goto set_obj; } - if (endptr < end) { + if (endptr < end && endptr != start) { p = endptr; switch (*p) { case 'm': @@ -487,12 +493,11 @@ ucl_maybe_parse_number (ucl_object_t *obj, * Parse possible number * @param parser * @param chunk - * @param err * @return true if a number has been parsed */ static bool ucl_lex_number (struct ucl_parser *parser, - struct ucl_chunk *chunk, ucl_object_t *obj, UT_string **err) + struct ucl_chunk *chunk, ucl_object_t *obj) { const unsigned char *pos; int ret; @@ -506,7 +511,7 @@ ucl_lex_number (struct ucl_parser *parser, return true; } else if (ret == ERANGE) { - ucl_set_err (chunk, ERANGE, "numeric value out of range", err); + ucl_set_err (chunk, ERANGE, "numeric value out of range", &parser->err); } return false; @@ -516,12 +521,11 @@ ucl_lex_number (struct ucl_parser *parser, * Parse quoted string with possible escapes * @param parser * @param chunk - * @param err * @return true if a string has been parsed */ static bool ucl_lex_json_string (struct ucl_parser *parser, - struct ucl_chunk *chunk, bool *need_unescape, UT_string **err) + struct ucl_chunk *chunk, bool *need_unescape, bool *ucl_escape) { const unsigned char *p = chunk->pos; unsigned char c; @@ -532,10 +536,10 @@ ucl_lex_json_string (struct ucl_parser *parser, if (c < 0x1F) { /* Unmasked control character */ if (c == '\n') { - ucl_set_err (chunk, UCL_ESYNTAX, "unexpected newline", err); + ucl_set_err (chunk, UCL_ESYNTAX, "unexpected newline", &parser->err); } else { - ucl_set_err (chunk, UCL_ESYNTAX, "unexpected control character", err); + ucl_set_err (chunk, UCL_ESYNTAX, "unexpected control character", &parser->err); } return false; } @@ -543,7 +547,7 @@ ucl_lex_json_string (struct ucl_parser *parser, ucl_chunk_skipc (chunk, p); c = *p; if (p >= chunk->end) { - ucl_set_err (chunk, UCL_ESYNTAX, "unfinished escape character", err); + ucl_set_err (chunk, UCL_ESYNTAX, "unfinished escape character", &parser->err); return false; } else if (ucl_test_character (c, UCL_CHARACTER_ESCAPE)) { @@ -551,13 +555,13 @@ ucl_lex_json_string (struct ucl_parser *parser, ucl_chunk_skipc (chunk, p); for (i = 0; i < 4 && p < chunk->end; i ++) { if (!isxdigit (*p)) { - ucl_set_err (chunk, UCL_ESYNTAX, "invalid utf escape", err); + ucl_set_err (chunk, UCL_ESYNTAX, "invalid utf escape", &parser->err); return false; } ucl_chunk_skipc (chunk, p); } if (p >= chunk->end) { - ucl_set_err (chunk, UCL_ESYNTAX, "unfinished escape character", err); + ucl_set_err (chunk, UCL_ESYNTAX, "unfinished escape character", &parser->err); return false; } } @@ -566,20 +570,24 @@ ucl_lex_json_string (struct ucl_parser *parser, } } else { - ucl_set_err (chunk, UCL_ESYNTAX, "invalid escape character", err); + ucl_set_err (chunk, UCL_ESYNTAX, "invalid escape character", &parser->err); return false; } *need_unescape = true; + *ucl_escape = true; continue; } else if (c == '"') { ucl_chunk_skipc (chunk, p); return true; } + else if (ucl_test_character (c, UCL_CHARACTER_UCL_UNSAFE)) { + *ucl_escape = true; + } ucl_chunk_skipc (chunk, p); } - ucl_set_err (chunk, UCL_ESYNTAX, "no quote at the end of json string", err); + ucl_set_err (chunk, UCL_ESYNTAX, "no quote at the end of json string", &parser->err); return false; } @@ -587,16 +595,15 @@ ucl_lex_json_string (struct ucl_parser *parser, * Parse a key in an object * @param parser * @param chunk - * @param err * @return true if a key has been parsed */ static bool -ucl_parse_key (struct ucl_parser *parser, - struct ucl_chunk *chunk, UT_string **err) +ucl_parse_key (struct ucl_parser *parser, struct ucl_chunk *chunk) { const unsigned char *p, *c = NULL, *end; const char *key; - bool got_quote = false, got_eq = false, got_semicolon = false, need_unescape = false; + bool got_quote = false, got_eq = false, got_semicolon = false, + need_unescape = false, ucl_escape = false; ucl_object_t *nobj, *tobj, *container; size_t keylen; @@ -615,7 +622,7 @@ ucl_parse_key (struct ucl_parser *parser, */ if (c == NULL) { if (ucl_lex_is_comment (p[0], p[1])) { - if (!ucl_skip_comments (parser, err)) { + if (!ucl_skip_comments (parser)) { return false; } p = chunk->pos; @@ -633,7 +640,7 @@ ucl_parse_key (struct ucl_parser *parser, } else { /* Invalid identifier */ - ucl_set_err (chunk, UCL_ESYNTAX, "key must begin with a letter", err); + ucl_set_err (chunk, UCL_ESYNTAX, "key must begin with a letter", &parser->err); return false; } } @@ -648,15 +655,16 @@ ucl_parse_key (struct ucl_parser *parser, break; } else { - ucl_set_err (chunk, UCL_ESYNTAX, "invalid character in a key", err); + ucl_set_err (chunk, UCL_ESYNTAX, "invalid character in a key", &parser->err); return false; } } else { /* We need to parse json like quoted string */ - if (!ucl_lex_json_string (parser, chunk, &need_unescape, err)) { + if (!ucl_lex_json_string (parser, chunk, &need_unescape, &ucl_escape)) { return false; } + /* Always escape keys obtained via json */ end = chunk->pos - 1; p = chunk->pos; break; @@ -665,7 +673,7 @@ ucl_parse_key (struct ucl_parser *parser, } if (p >= chunk->end) { - ucl_set_err (chunk, UCL_ESYNTAX, "unfinished key", err); + ucl_set_err (chunk, UCL_ESYNTAX, "unfinished key", &parser->err); return false; } @@ -680,7 +688,7 @@ ucl_parse_key (struct ucl_parser *parser, got_eq = true; } else { - ucl_set_err (chunk, UCL_ESYNTAX, "unexpected '=' character", err); + ucl_set_err (chunk, UCL_ESYNTAX, "unexpected '=' character", &parser->err); return false; } } @@ -690,13 +698,13 @@ ucl_parse_key (struct ucl_parser *parser, got_semicolon = true; } else { - ucl_set_err (chunk, UCL_ESYNTAX, "unexpected ':' character", err); + ucl_set_err (chunk, UCL_ESYNTAX, "unexpected ':' character", &parser->err); return false; } } else if (ucl_lex_is_comment (p[0], p[1])) { /* Check for comment */ - if (!ucl_skip_comments (parser, err)) { + if (!ucl_skip_comments (parser)) { return false; } p = chunk->pos; @@ -708,14 +716,14 @@ ucl_parse_key (struct ucl_parser *parser, } if (p >= chunk->end) { - ucl_set_err (chunk, UCL_ESYNTAX, "unfinished key", err); + ucl_set_err (chunk, UCL_ESYNTAX, "unfinished key", &parser->err); return false; } /* Create a new object */ nobj = ucl_object_new (); keylen = ucl_copy_or_store_ptr (parser, c, &nobj->trash_stack[UCL_TRASH_KEY], - &key, end - c, need_unescape, parser->flags & UCL_FLAG_KEY_LOWERCASE, err); + &key, end - c, need_unescape, parser->flags & UCL_PARSER_KEY_LOWERCASE); if (keylen == 0) { return false; } @@ -730,6 +738,9 @@ ucl_parse_key (struct ucl_parser *parser, DL_APPEND (tobj, nobj); } + if (ucl_escape) { + nobj->flags |= UCL_OBJECT_NEED_KEY_ESCAPE; + } parser->stack->obj->value.ov = container; parser->cur_obj = nobj; @@ -741,12 +752,11 @@ ucl_parse_key (struct ucl_parser *parser, * Parse a cl string * @param parser * @param chunk - * @param err * @return true if a key has been parsed */ static bool ucl_parse_string_value (struct ucl_parser *parser, - struct ucl_chunk *chunk, UT_string **err) + struct ucl_chunk *chunk) { const unsigned char *p; enum { @@ -792,7 +802,7 @@ ucl_parse_string_value (struct ucl_parser *parser, } if (p >= chunk->end) { - ucl_set_err (chunk, UCL_ESYNTAX, "unfinished value", err); + ucl_set_err (chunk, UCL_ESYNTAX, "unfinished value", &parser->err); return false; } @@ -805,13 +815,12 @@ ucl_parse_string_value (struct ucl_parser *parser, * @param chunk * @param term * @param term_len - * @param err * @return size of multiline string or 0 in case of error */ static int ucl_parse_multiline_string (struct ucl_parser *parser, struct ucl_chunk *chunk, const unsigned char *term, - int term_len, unsigned char const **beg, UT_string **err) + int term_len, unsigned char const **beg) { const unsigned char *p, *c; bool newline = false; @@ -851,18 +860,17 @@ ucl_parse_multiline_string (struct ucl_parser *parser, * Handle value data * @param parser * @param chunk - * @param err * @return */ static bool -ucl_parse_value (struct ucl_parser *parser, struct ucl_chunk *chunk, UT_string **err) +ucl_parse_value (struct ucl_parser *parser, struct ucl_chunk *chunk) { const unsigned char *p, *c; struct ucl_stack *st; ucl_object_t *obj = NULL, *t; unsigned int stripped_spaces; int str_len; - bool need_unescape = false; + bool need_unescape = false, ucl_escape = false; p = chunk->pos; @@ -885,13 +893,13 @@ ucl_parse_value (struct ucl_parser *parser, struct ucl_chunk *chunk, UT_string * switch (*p) { case '"': ucl_chunk_skipc (chunk, p); - if (!ucl_lex_json_string (parser, chunk, &need_unescape, err)) { + if (!ucl_lex_json_string (parser, chunk, &need_unescape, &ucl_escape)) { return false; } str_len = chunk->pos - c - 2; obj->type = UCL_STRING; if ((str_len = ucl_copy_or_store_ptr (parser, c + 1, &obj->trash_stack[UCL_TRASH_VALUE], - &obj->value.sv, str_len, need_unescape, false, err)) == 0) { + &obj->value.sv, str_len, need_unescape, false)) == 0) { return false; } obj->len = str_len; @@ -943,13 +951,13 @@ ucl_parse_value (struct ucl_parser *parser, struct ucl_chunk *chunk, UT_string * chunk->column = 0; chunk->line ++; if ((str_len = ucl_parse_multiline_string (parser, chunk, c, - p - c, &c, err)) == 0) { - ucl_set_err (chunk, UCL_ESYNTAX, "unterminated multiline value", err); + p - c, &c)) == 0) { + ucl_set_err (chunk, UCL_ESYNTAX, "unterminated multiline value", &parser->err); return false; } obj->type = UCL_STRING; if ((str_len = ucl_copy_or_store_ptr (parser, c, &obj->trash_stack[UCL_TRASH_VALUE], - &obj->value.sv, str_len - 1, false, false, err)) == 0) { + &obj->value.sv, str_len - 1, false, false)) == 0) { return false; } obj->len = str_len; @@ -966,7 +974,7 @@ ucl_parse_value (struct ucl_parser *parser, struct ucl_chunk *chunk, UT_string * while (p < chunk->end && ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE)) { ucl_chunk_skipc (chunk, p); } - if (!ucl_skip_comments (parser, err)) { + if (!ucl_skip_comments (parser)) { return false; } p = chunk->pos; @@ -974,11 +982,11 @@ ucl_parse_value (struct ucl_parser *parser, struct ucl_chunk *chunk, UT_string * } /* Parse atom */ if (ucl_test_character (*p, UCL_CHARACTER_VALUE_DIGIT_START)) { - if (!ucl_lex_number (parser, chunk, obj, err)) { + if (!ucl_lex_number (parser, chunk, obj)) { if (parser->state == UCL_STATE_ERROR) { return false; } - if (!ucl_parse_string_value (parser, chunk, err)) { + if (!ucl_parse_string_value (parser, chunk)) { return false; } if (!ucl_maybe_parse_boolean (obj, c, chunk->pos - c)) { @@ -990,12 +998,12 @@ ucl_parse_value (struct ucl_parser *parser, struct ucl_chunk *chunk, UT_string * } str_len = chunk->pos - c - stripped_spaces; if (str_len <= 0) { - ucl_set_err (chunk, 0, "string value must not be empty", err); + ucl_set_err (chunk, 0, "string value must not be empty", &parser->err); return false; } obj->type = UCL_STRING; if ((str_len = ucl_copy_or_store_ptr (parser, c, &obj->trash_stack[UCL_TRASH_VALUE], - &obj->value.sv, str_len, false, false, err)) == 0) { + &obj->value.sv, str_len, false, false)) == 0) { return false; } obj->len = str_len; @@ -1009,7 +1017,7 @@ ucl_parse_value (struct ucl_parser *parser, struct ucl_chunk *chunk, UT_string * } } else { - if (!ucl_parse_string_value (parser, chunk, err)) { + if (!ucl_parse_string_value (parser, chunk)) { return false; } if (!ucl_maybe_parse_boolean (obj, c, chunk->pos - c)) { @@ -1022,12 +1030,12 @@ ucl_parse_value (struct ucl_parser *parser, struct ucl_chunk *chunk, UT_string * } str_len = chunk->pos - c - stripped_spaces; if (str_len <= 0) { - ucl_set_err (chunk, 0, "string value must not be empty", err); + ucl_set_err (chunk, 0, "string value must not be empty", &parser->err); return false; } obj->type = UCL_STRING; if ((str_len = ucl_copy_or_store_ptr (parser, c, &obj->trash_stack[UCL_TRASH_VALUE], - &obj->value.sv, str_len, false, false, err)) == 0) { + &obj->value.sv, str_len, false, false)) == 0) { return false; } obj->len = str_len; @@ -1047,11 +1055,10 @@ ucl_parse_value (struct ucl_parser *parser, struct ucl_chunk *chunk, UT_string * * Handle after value data * @param parser * @param chunk - * @param err * @return */ static bool -ucl_parse_after_value (struct ucl_parser *parser, struct ucl_chunk *chunk, UT_string **err) +ucl_parse_after_value (struct ucl_parser *parser, struct ucl_chunk *chunk) { const unsigned char *p; bool got_sep = false; @@ -1066,7 +1073,7 @@ ucl_parse_after_value (struct ucl_parser *parser, struct ucl_chunk *chunk, UT_st } else if (ucl_lex_is_comment (p[0], p[1])) { /* Skip comment */ - if (!ucl_skip_comments (parser, err)) { + if (!ucl_skip_comments (parser)) { return false; } /* Treat comment as a separator */ @@ -1076,7 +1083,7 @@ ucl_parse_after_value (struct ucl_parser *parser, struct ucl_chunk *chunk, UT_st else if (ucl_test_character (*p, UCL_CHARACTER_VALUE_END)) { if (*p == '}' || *p == ']') { if (parser->stack == NULL) { - ucl_set_err (chunk, UCL_ESYNTAX, "unexpected } detected", err); + ucl_set_err (chunk, UCL_ESYNTAX, "unexpected } detected", &parser->err); return false; } if ((*p == '}' && parser->stack->obj->type == UCL_OBJECT) || @@ -1088,7 +1095,7 @@ ucl_parse_after_value (struct ucl_parser *parser, struct ucl_chunk *chunk, UT_st UCL_FREE (sizeof (struct ucl_stack), st); } else { - ucl_set_err (chunk, UCL_ESYNTAX, "unexpected terminating symbol detected", err); + ucl_set_err (chunk, UCL_ESYNTAX, "unexpected terminating symbol detected", &parser->err); return false; } @@ -1110,7 +1117,7 @@ ucl_parse_after_value (struct ucl_parser *parser, struct ucl_chunk *chunk, UT_st else { /* Anything else */ if (!got_sep) { - ucl_set_err (chunk, UCL_ESYNTAX, "delimiter is missing", err); + ucl_set_err (chunk, UCL_ESYNTAX, "delimiter is missing", &parser->err); return false; } return true; @@ -1124,16 +1131,15 @@ ucl_parse_after_value (struct ucl_parser *parser, struct ucl_chunk *chunk, UT_st * Handle macro data * @param parser * @param chunk - * @param err * @return */ static bool ucl_parse_macro_value (struct ucl_parser *parser, struct ucl_chunk *chunk, struct ucl_macro *macro, - unsigned char const **macro_start, size_t *macro_len, UT_string **err) + unsigned char const **macro_start, size_t *macro_len) { const unsigned char *p, *c; - bool need_unescape = false; + bool need_unescape = false, ucl_escape = false; p = chunk->pos; @@ -1142,7 +1148,7 @@ ucl_parse_macro_value (struct ucl_parser *parser, /* We have macro value encoded in quotes */ c = p; ucl_chunk_skipc (chunk, p); - if (!ucl_lex_json_string (parser, chunk, &need_unescape, err)) { + if (!ucl_lex_json_string (parser, chunk, &need_unescape, &ucl_escape)) { return false; } @@ -1203,11 +1209,10 @@ ucl_parse_macro_value (struct ucl_parser *parser, * @param parser parser structure * @param data the pointer to the beginning of a chunk * @param len the length of a chunk - * @param err if *err is NULL it is set to parser error * @return true if chunk has been parsed and false in case of error */ static bool -ucl_state_machine (struct ucl_parser *parser, UT_string **err) +ucl_state_machine (struct ucl_parser *parser) { ucl_object_t *obj; struct ucl_chunk *chunk = parser->chunks; @@ -1225,7 +1230,7 @@ ucl_state_machine (struct ucl_parser *parser, UT_string **err) * if we got [ or { correspondingly or can just treat new data as * a key of newly created object */ - if (!ucl_skip_comments (parser, err)) { + if (!ucl_skip_comments (parser)) { parser->prev_state = parser->state; parser->state = UCL_STATE_ERROR; return false; @@ -1262,7 +1267,7 @@ ucl_state_machine (struct ucl_parser *parser, UT_string **err) parser->state = UCL_STATE_AFTER_VALUE; continue; } - if (!ucl_parse_key (parser, chunk, err)) { + if (!ucl_parse_key (parser, chunk)) { parser->prev_state = parser->state; parser->state = UCL_STATE_ERROR; return false; @@ -1277,7 +1282,7 @@ ucl_state_machine (struct ucl_parser *parser, UT_string **err) break; case UCL_STATE_VALUE: /* We need to check what we do have */ - if (!ucl_parse_value (parser, chunk, err)) { + if (!ucl_parse_value (parser, chunk)) { parser->prev_state = parser->state; parser->state = UCL_STATE_ERROR; return false; @@ -1286,7 +1291,7 @@ ucl_state_machine (struct ucl_parser *parser, UT_string **err) p = chunk->pos; break; case UCL_STATE_AFTER_VALUE: - if (!ucl_parse_after_value (parser, chunk, err)) { + if (!ucl_parse_after_value (parser, chunk)) { parser->prev_state = parser->state; parser->state = UCL_STATE_ERROR; return false; @@ -1314,7 +1319,7 @@ ucl_state_machine (struct ucl_parser *parser, UT_string **err) /* We got macro name */ HASH_FIND (hh, parser->macroes, c, (p - c), macro); if (macro == NULL) { - ucl_set_err (chunk, UCL_EMACRO, "unknown macro", err); + ucl_set_err (chunk, UCL_EMACRO, "unknown macro", &parser->err); parser->state = UCL_STATE_ERROR; return false; } @@ -1323,7 +1328,7 @@ ucl_state_machine (struct ucl_parser *parser, UT_string **err) if (!ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE)) { if (ucl_lex_is_comment (p[0], p[1])) { /* Skip comment */ - if (!ucl_skip_comments (parser, err)) { + if (!ucl_skip_comments (parser)) { return false; } p = chunk->pos; @@ -1337,20 +1342,20 @@ ucl_state_machine (struct ucl_parser *parser, UT_string **err) break; case UCL_STATE_MACRO: if (!ucl_parse_macro_value (parser, chunk, macro, - ¯o_start, ¯o_len, err)) { + ¯o_start, ¯o_len)) { parser->prev_state = parser->state; parser->state = UCL_STATE_ERROR; return false; } parser->state = parser->prev_state; - if (!macro->handler (macro_start, macro_len, macro->ud, err)) { + if (!macro->handler (macro_start, macro_len, macro->ud)) { return false; } p = chunk->pos; break; default: /* TODO: add all states */ - ucl_set_err (chunk, UCL_EMACRO, "internal error: parser is in an unknown state", err); + ucl_set_err (chunk, UCL_EMACRO, "internal error: parser is in an unknown state", &parser->err); parser->state = UCL_STATE_ERROR; return false; } @@ -1392,7 +1397,7 @@ ucl_parser_register_macro (struct ucl_parser *parser, const char *macro, bool ucl_parser_add_chunk (struct ucl_parser *parser, const unsigned char *data, - size_t len, UT_string **err) + size_t len) { struct ucl_chunk *chunk; @@ -1407,14 +1412,14 @@ ucl_parser_add_chunk (struct ucl_parser *parser, const unsigned char *data, LL_PREPEND (parser->chunks, chunk); parser->recursion ++; if (parser->recursion > UCL_MAX_RECURSION) { - ucl_create_err (err, "maximum include nesting limit is reached: %d", + ucl_create_err (&parser->err, "maximum include nesting limit is reached: %d", parser->recursion); return false; } - return ucl_state_machine (parser, err); + return ucl_state_machine (parser); } - ucl_create_err (err, "a parser is in an invalid state"); + ucl_create_err (&parser->err, "a parser is in an invalid state"); return false; } diff --git a/src/ucl/src/ucl_util.c b/src/ucl/src/ucl_util.c index 510035c55..09123e91e 100644 --- a/src/ucl/src/ucl_util.c +++ b/src/ucl/src/ucl_util.c @@ -186,6 +186,7 @@ ucl_copy_key_trash (ucl_object_t *obj) obj->trash_stack[UCL_TRASH_KEY][obj->hh.keylen] = '\0'; } obj->hh.key = obj->trash_stack[UCL_TRASH_KEY]; + obj->flags |= UCL_OBJECT_ALLOCATED_KEY; } return obj->trash_stack[UCL_TRASH_KEY]; @@ -202,6 +203,7 @@ ucl_copy_value_trash (ucl_object_t *obj) if (obj->trash_stack[UCL_TRASH_VALUE] != NULL) { memcpy (obj->trash_stack[UCL_TRASH_VALUE], obj->value.sv, obj->len); obj->trash_stack[UCL_TRASH_VALUE][obj->len] = '\0'; + obj->value.sv = obj->trash_stack[UCL_TRASH_VALUE]; } } else { @@ -215,12 +217,13 @@ ucl_copy_value_trash (ucl_object_t *obj) free (emitted); } } + obj->flags |= UCL_OBJECT_ALLOCATED_VALUE; } return obj->trash_stack[UCL_TRASH_VALUE]; } ucl_object_t* -ucl_parser_get_object (struct ucl_parser *parser, UT_string **err) +ucl_parser_get_object (struct ucl_parser *parser) { if (parser->state != UCL_STATE_INIT && parser->state != UCL_STATE_ERROR) { return ucl_object_ref (parser->top_obj); @@ -256,15 +259,28 @@ ucl_parser_free (struct ucl_parser *parser) UCL_FREE (sizeof (struct ucl_pubkey), key); } + if (parser->err != NULL) { + utstring_free(parser->err); + } + UCL_FREE (sizeof (struct ucl_parser), parser); } +const char * +ucl_parser_get_error(struct ucl_parser *parser) +{ + if (parser->err == NULL) + return NULL; + + return utstring_body(parser->err); +} + bool -ucl_pubkey_add (struct ucl_parser *parser, const unsigned char *key, size_t len, UT_string **err) +ucl_pubkey_add (struct ucl_parser *parser, const unsigned char *key, size_t len) { struct ucl_pubkey *nkey; #ifndef HAVE_OPENSSL - ucl_create_err (err, "cannot check signatures without openssl"); + ucl_create_err (&parser->err, "cannot check signatures without openssl"); return false; #else # if (OPENSSL_VERSION_NUMBER < 0x10000000L) @@ -279,7 +295,7 @@ ucl_pubkey_add (struct ucl_parser *parser, const unsigned char *key, size_t len, BIO_free (mem); if (nkey->key == NULL) { UCL_FREE (sizeof (struct ucl_pubkey), nkey); - ucl_create_err (err, "%s", + ucl_create_err (&parser->err, "%s", ERR_error_string (ERR_get_error (), NULL)); return false; } @@ -345,7 +361,7 @@ ucl_fetch_url (const unsigned char *url, unsigned char **buf, size_t *buflen, UT } *buflen = us.size; - *buf = g_malloc (*buflen); + *buf = malloc (*buflen); if (*buf == NULL) { ucl_create_err (err, "cannot allocate buffer for URL %s: %s", url, strerror (errno)); @@ -499,7 +515,7 @@ ucl_sig_check (const unsigned char *data, size_t datalen, */ static bool ucl_include_url (const unsigned char *data, size_t len, - struct ucl_parser *parser, bool check_signature, UT_string **err) + struct ucl_parser *parser, bool check_signature) { bool res; @@ -510,7 +526,7 @@ ucl_include_url (const unsigned char *data, size_t len, snprintf (urlbuf, sizeof (urlbuf), "%.*s", (int)len, data); - if (!ucl_fetch_url (urlbuf, &buf, &buflen, err)) { + if (!ucl_fetch_url (urlbuf, &buf, &buflen, &parser->err)) { return false; } @@ -518,11 +534,11 @@ ucl_include_url (const unsigned char *data, size_t len, #if (defined(HAVE_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10000000L) /* We need to check signature first */ snprintf (urlbuf, sizeof (urlbuf), "%.*s.sig", (int)len, data); - if (!ucl_fetch_file (urlbuf, &sigbuf, &siglen, err)) { + if (!ucl_fetch_file (urlbuf, &sigbuf, &siglen, &parser->err)) { return false; } if (!ucl_sig_check (buf, buflen, sigbuf, siglen, parser)) { - ucl_create_err (err, "cannot verify url %s: %s", + ucl_create_err (&parser->err, "cannot verify url %s: %s", urlbuf, ERR_error_string (ERR_get_error (), NULL)); munmap (sigbuf, siglen); @@ -532,7 +548,7 @@ ucl_include_url (const unsigned char *data, size_t len, #endif } - res = ucl_parser_add_chunk (parser, buf, buflen, err); + res = ucl_parser_add_chunk (parser, buf, buflen); if (res == true) { /* Remove chunk from the stack */ chunk = parser->chunks; @@ -556,7 +572,7 @@ ucl_include_url (const unsigned char *data, size_t len, */ static bool ucl_include_file (const unsigned char *data, size_t len, - struct ucl_parser *parser, bool check_signature, UT_string **err) + struct ucl_parser *parser, bool check_signature) { bool res; struct ucl_chunk *chunk; @@ -566,13 +582,13 @@ ucl_include_file (const unsigned char *data, size_t len, snprintf (filebuf, sizeof (filebuf), "%.*s", (int)len, data); if (realpath (filebuf, realbuf) == NULL) { - ucl_create_err (err, "cannot open file %s: %s", + ucl_create_err (&parser->err, "cannot open file %s: %s", filebuf, strerror (errno)); return false; } - if (!ucl_fetch_file (realbuf, &buf, &buflen, err)) { + if (!ucl_fetch_file (realbuf, &buf, &buflen, &parser->err)) { return false; } @@ -580,11 +596,11 @@ ucl_include_file (const unsigned char *data, size_t len, #if (defined(HAVE_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10000000L) /* We need to check signature first */ snprintf (filebuf, sizeof (filebuf), "%s.sig", realbuf); - if (!ucl_fetch_file (filebuf, &sigbuf, &siglen, err)) { + if (!ucl_fetch_file (filebuf, &sigbuf, &siglen, &parser->err)) { return false; } if (!ucl_sig_check (buf, buflen, sigbuf, siglen, parser)) { - ucl_create_err (err, "cannot verify file %s: %s", + ucl_create_err (&parser->err, "cannot verify file %s: %s", filebuf, ERR_error_string (ERR_get_error (), NULL)); munmap (sigbuf, siglen); @@ -594,7 +610,7 @@ ucl_include_file (const unsigned char *data, size_t len, #endif } - res = ucl_parser_add_chunk (parser, buf, buflen, err); + res = ucl_parser_add_chunk (parser, buf, buflen); if (res == true) { /* Remove chunk from the stack */ chunk = parser->chunks; @@ -617,16 +633,16 @@ ucl_include_file (const unsigned char *data, size_t len, * @return */ bool -ucl_include_handler (const unsigned char *data, size_t len, void* ud, UT_string **err) +ucl_include_handler (const unsigned char *data, size_t len, void* ud) { struct ucl_parser *parser = ud; if (*data == '/' || *data == '.') { /* Try to load a file */ - return ucl_include_file (data, len, parser, false, err); + return ucl_include_file (data, len, parser, false); } - return ucl_include_url (data, len, parser, false, err); + return ucl_include_url (data, len, parser, false); } /** @@ -638,31 +654,30 @@ ucl_include_handler (const unsigned char *data, size_t len, void* ud, UT_string * @return */ bool -ucl_includes_handler (const unsigned char *data, size_t len, void* ud, UT_string **err) +ucl_includes_handler (const unsigned char *data, size_t len, void* ud) { struct ucl_parser *parser = ud; if (*data == '/' || *data == '.') { /* Try to load a file */ - return ucl_include_file (data, len, parser, true, err); + return ucl_include_file (data, len, parser, true); } - return ucl_include_url (data, len, parser, true, err); + return ucl_include_url (data, len, parser, true); } bool -ucl_parser_add_file (struct ucl_parser *parser, const char *filename, - UT_string **err) +ucl_parser_add_file (struct ucl_parser *parser, const char *filename) { unsigned char *buf; size_t len; bool ret; - if (!ucl_fetch_file (filename, &buf, &len, err)) { + if (!ucl_fetch_file (filename, &buf, &len, &parser->err)) { return false; } - ret = ucl_parser_add_chunk (parser, buf, len, err); + ret = ucl_parser_add_chunk (parser, buf, len); munmap (buf, len); @@ -839,3 +854,43 @@ ucl_object_fromstring_common (const char *str, size_t len, enum ucl_string_flags return obj; } + +ucl_object_t * +ucl_object_insert_key (ucl_object_t *top, ucl_object_t *elt, + const char *key, size_t keylen, bool copy_key) +{ + ucl_object_t *found; + const char *p; + + if (elt == NULL || key == NULL) { + return NULL; + } + + if (top == NULL) { + top = ucl_object_new (); + top->type = UCL_OBJECT; + } + if (keylen == 0) { + keylen = strlen (key); + } + + for (p = key; p < key + keylen; p ++) { + if (ucl_test_character (*p, UCL_CHARACTER_UCL_UNSAFE)) { + elt->flags |= UCL_OBJECT_NEED_KEY_ESCAPE; + break; + } + } + + HASH_FIND (hh, top->value.ov, key, keylen, found); + + if (!found) { + HASH_ADD_KEYPTR (hh, top->value.ov, key, keylen, elt); + } + DL_APPEND (found, elt); + + if (copy_key) { + ucl_copy_key_trash (elt); + } + + return top; +} diff --git a/src/ucl/tests/generate.res b/src/ucl/tests/generate.res index e7659ec3a..63857aac5 100644 --- a/src/ucl/tests/generate.res +++ b/src/ucl/tests/generate.res @@ -15,4 +15,7 @@ key8 = 1048576; key9 = 3.140000; key10 = true; key11 = false; +key12 = "gslin@gslin.org"; +key13 = "#test"; +"k=3" = true; diff --git a/src/ucl/tests/test_basic.c b/src/ucl/tests/test_basic.c index d4d4786d6..7444d901b 100644 --- a/src/ucl/tests/test_basic.c +++ b/src/ucl/tests/test_basic.c @@ -32,7 +32,6 @@ main (int argc, char **argv) struct ucl_parser *parser, *parser2; ucl_object_t *obj; FILE *in, *out; - UT_string *err = NULL; unsigned char *emitted; const char *fname_in = NULL, *fname_out = NULL; int ret = 0; @@ -56,11 +55,11 @@ main (int argc, char **argv) else { in = stdin; } - parser = ucl_parser_new (UCL_FLAG_KEY_LOWERCASE); + parser = ucl_parser_new (UCL_PARSER_KEY_LOWERCASE); while (!feof (in)) { fread (inbuf, sizeof (inbuf), 1, in); - ucl_parser_add_chunk (parser, inbuf, strlen (inbuf), &err); + ucl_parser_add_chunk (parser, inbuf, strlen (inbuf)); } fclose (in); @@ -73,20 +72,20 @@ main (int argc, char **argv) else { out = stdout; } - if (err != NULL) { - fprintf (out, "Error occurred: %s\n", err->d); + if (ucl_parser_get_error(parser) != NULL) { + fprintf (out, "Error occurred: %s\n", ucl_parser_get_error(parser)); ret = 1; goto end; } - obj = ucl_parser_get_object (parser, &err); + obj = ucl_parser_get_object (parser); emitted = ucl_object_emit (obj, UCL_EMIT_CONFIG); ucl_parser_free (parser); ucl_object_unref (obj); - parser2 = ucl_parser_new (UCL_FLAG_KEY_LOWERCASE); - ucl_parser_add_chunk (parser2, emitted, strlen (emitted), &err); + parser2 = ucl_parser_new (UCL_PARSER_KEY_LOWERCASE); + ucl_parser_add_chunk (parser2, emitted, strlen (emitted)); - if (err != NULL) { - fprintf (out, "Error occurred: %s\n", err->d); + if (ucl_parser_get_error(parser2) != NULL) { + fprintf (out, "Error occurred: %s\n", ucl_parser_get_error(parser2)); fprintf (out, "%s\n", emitted); ret = 1; goto end; @@ -94,7 +93,7 @@ main (int argc, char **argv) if (emitted != NULL) { free (emitted); } - obj = ucl_parser_get_object (parser2, &err); + obj = ucl_parser_get_object (parser2); emitted = ucl_object_emit (obj, UCL_EMIT_CONFIG); fprintf (out, "%s\n", emitted); @@ -107,6 +106,7 @@ end: if (parser2 != NULL) { ucl_parser_free (parser2); } + fclose (out); return ret; diff --git a/src/ucl/tests/test_generate.c b/src/ucl/tests/test_generate.c index a61b35396..f269e00dc 100644 --- a/src/ucl/tests/test_generate.c +++ b/src/ucl/tests/test_generate.c @@ -83,6 +83,13 @@ main (int argc, char **argv) obj = ucl_object_insert_key (obj, cur, "key10", 0, false); cur = ucl_object_fromstring_common (" off ", 0, UCL_STRING_PARSE | UCL_STRING_TRIM); obj = ucl_object_insert_key (obj, cur, "key11", 0, false); + cur = ucl_object_fromstring_common ("gslin@gslin.org", 0, UCL_STRING_PARSE_INT); + obj = ucl_object_insert_key (obj, cur, "key12", 0, false); + cur = ucl_object_fromstring_common ("#test", 0, UCL_STRING_PARSE_INT); + obj = ucl_object_insert_key (obj, cur, "key13", 0, false); + cur = ucl_object_frombool (true); + obj = ucl_object_insert_key (obj, cur, "k=3", 0, false); + emitted = ucl_object_emit (obj, UCL_EMIT_CONFIG); diff --git a/src/ucl/tests/test_speed.c b/src/ucl/tests/test_speed.c index 92a972aa5..39229becb 100644 --- a/src/ucl/tests/test_speed.c +++ b/src/ucl/tests/test_speed.c @@ -40,7 +40,6 @@ main (int argc, char **argv) struct ucl_parser *parser; ucl_object_t *obj; int fin; - UT_string *err = NULL; unsigned char *emitted; struct stat st; const char *fname_in = NULL; @@ -59,7 +58,7 @@ main (int argc, char **argv) perror ("open failed"); exit (EXIT_FAILURE); } - parser = ucl_parser_new (UCL_FLAG_ZEROCOPY); + parser = ucl_parser_new (UCL_PARSER_ZEROCOPY); (void)fstat (fin, &st); map = mmap (NULL, st.st_size, PROT_READ, MAP_SHARED, fin, 0); @@ -71,15 +70,15 @@ main (int argc, char **argv) close (fin); clock_gettime (CLOCK_MONOTONIC, &start); - ucl_parser_add_chunk (parser, map, st.st_size, &err); + ucl_parser_add_chunk (parser, map, st.st_size); - obj = ucl_parser_get_object (parser, &err); + obj = ucl_parser_get_object (parser); clock_gettime (CLOCK_MONOTONIC, &end); seconds = (end.tv_sec - start.tv_sec) + (end.tv_nsec - start.tv_nsec) / 1000000000.; printf ("ucl: parsed input in %.4f seconds\n", seconds); - if (err != NULL) { - printf ("Error occurred: %s\n", err->d); + if (ucl_parser_get_error(parser)) { + printf ("Error occurred: %s\n", ucl_parser_get_error(parser)); ret = 1; } -- 2.39.5