aboutsummaryrefslogtreecommitdiffstats
path: root/src/ucl
diff options
context:
space:
mode:
authorVsevolod Stakhov <vsevolod@highsecure.ru>2013-10-23 16:51:01 +0100
committerVsevolod Stakhov <vsevolod@highsecure.ru>2013-10-23 16:51:01 +0100
commit7ecc32babdc9ea9db7f051923d95715fbcc3a30f (patch)
tree23578250d07203192834310cd7e43d5acb6ef668 /src/ucl
parent0039ba84e6bca24128cbc75f7f20137ff4070368 (diff)
downloadrspamd-7ecc32babdc9ea9db7f051923d95715fbcc3a30f.tar.gz
rspamd-7ecc32babdc9ea9db7f051923d95715fbcc3a30f.zip
Sync with libucl.
Diffstat (limited to 'src/ucl')
-rw-r--r--src/ucl/include/ucl.h135
-rw-r--r--src/ucl/src/ucl_chartable.h29
-rw-r--r--src/ucl/src/ucl_emitter.c14
-rw-r--r--src/ucl/src/ucl_internal.h9
-rw-r--r--src/ucl/src/ucl_parser.c163
-rw-r--r--src/ucl/src/ucl_util.c107
-rw-r--r--src/ucl/tests/generate.res3
-rw-r--r--src/ucl/tests/test_basic.c22
-rw-r--r--src/ucl/tests/test_generate.c7
-rw-r--r--src/ucl/tests/test_speed.c11
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 */
@@ -162,21 +198,6 @@ ucl_object_new (void)
}
/**
- * 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
* @param len length (if len is zero, than str is treated as NULL terminated)
@@ -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,9 +664,14 @@ 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 <ctype.h>
#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,
- &macro_start, &macro_len, err)) {
+ &macro_start, &macro_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;
}