aboutsummaryrefslogtreecommitdiffstats
path: root/contrib
diff options
context:
space:
mode:
authorVsevolod Stakhov <vsevolod@highsecure.ru>2016-02-08 18:26:58 +0000
committerVsevolod Stakhov <vsevolod@highsecure.ru>2016-02-08 18:26:58 +0000
commitff660e595fb04857e73e1f84d1e13d412fb980ef (patch)
tree89311f8e1131729d6216537c282925166408dd47 /contrib
parent40d4ca29664da075d9078161814b01070b6c0058 (diff)
downloadrspamd-ff660e595fb04857e73e1f84d1e13d412fb980ef.tar.gz
rspamd-ff660e595fb04857e73e1f84d1e13d412fb980ef.zip
Update libucl
Diffstat (limited to 'contrib')
-rw-r--r--contrib/libucl/CMakeLists.txt3
-rw-r--r--contrib/libucl/ucl.h51
-rw-r--r--contrib/libucl/ucl_emitter.c41
-rw-r--r--contrib/libucl/ucl_emitter_streamline.c10
-rw-r--r--contrib/libucl/ucl_hash.c2
-rw-r--r--contrib/libucl/ucl_hash.h6
-rw-r--r--contrib/libucl/ucl_internal.h2
-rw-r--r--contrib/libucl/ucl_parser.c299
-rw-r--r--contrib/libucl/ucl_schema.c13
-rw-r--r--contrib/libucl/ucl_sexp.c226
-rw-r--r--contrib/libucl/ucl_util.c77
11 files changed, 656 insertions, 74 deletions
diff --git a/contrib/libucl/CMakeLists.txt b/contrib/libucl/CMakeLists.txt
index a1e919484..cda809116 100644
--- a/contrib/libucl/CMakeLists.txt
+++ b/contrib/libucl/CMakeLists.txt
@@ -6,7 +6,8 @@ SET(UCLSRC ucl_util.c
ucl_hash.c
ucl_schema.c
lua_ucl.c
- ucl_msgpack.c)
+ ucl_msgpack.c
+ ucl_sexp.c)
SET (LIB_TYPE STATIC)
diff --git a/contrib/libucl/ucl.h b/contrib/libucl/ucl.h
index cfe62c081..14e72d119 100644
--- a/contrib/libucl/ucl.h
+++ b/contrib/libucl/ucl.h
@@ -147,11 +147,13 @@ typedef enum ucl_emitter {
* UCL still has to perform copying implicitly.
*/
typedef enum ucl_parser_flags {
- UCL_PARSER_DEFAULT = 0x0, /**< No special flags */
- UCL_PARSER_KEY_LOWERCASE = 0x1, /**< Convert all keys to lower case */
- UCL_PARSER_ZEROCOPY = 0x2, /**< Parse input in zero-copy mode if possible */
- UCL_PARSER_NO_TIME = 0x4, /**< Do not parse time and treat time values as strings */
- UCL_PARSER_NO_IMPLICIT_ARRAYS = 0x8 /** Create explicit arrays instead of implicit ones */
+ UCL_PARSER_DEFAULT = 0, /**< No special flags */
+ UCL_PARSER_KEY_LOWERCASE = (1 << 0), /**< Convert all keys to lower case */
+ UCL_PARSER_ZEROCOPY = (1 << 1), /**< Parse input in zero-copy mode if possible */
+ UCL_PARSER_NO_TIME = (1 << 2), /**< Do not parse time and treat time values as strings */
+ UCL_PARSER_NO_IMPLICIT_ARRAYS = (1 << 3), /** Create explicit arrays instead of implicit ones */
+ UCL_PARSER_SAVE_COMMENTS = (1 << 4), /** Save comments in the parser context */
+ UCL_PARSER_DISABLE_MACRO = (1 << 5) /** Treat macros as comments */
} ucl_parser_flags_t;
/**
@@ -159,17 +161,17 @@ typedef enum ucl_parser_flags {
*/
typedef enum ucl_string_flags {
UCL_STRING_RAW = 0x0, /**< Treat string as is */
- UCL_STRING_ESCAPE = 0x1, /**< Perform JSON escape */
- UCL_STRING_TRIM = 0x2, /**< Trim leading and trailing whitespaces */
- UCL_STRING_PARSE_BOOLEAN = 0x4, /**< Parse passed string and detect boolean */
- UCL_STRING_PARSE_INT = 0x8, /**< Parse passed string and detect integer number */
- UCL_STRING_PARSE_DOUBLE = 0x10, /**< Parse passed string and detect integer or float number */
- UCL_STRING_PARSE_TIME = 0x20, /**< Parse time strings */
+ UCL_STRING_ESCAPE = (1 << 0), /**< Perform JSON escape */
+ UCL_STRING_TRIM = (1 << 1), /**< Trim leading and trailing whitespaces */
+ UCL_STRING_PARSE_BOOLEAN = (1 << 2), /**< Parse passed string and detect boolean */
+ UCL_STRING_PARSE_INT = (1 << 3), /**< Parse passed string and detect integer number */
+ UCL_STRING_PARSE_DOUBLE = (1 << 4), /**< Parse passed string and detect integer or float number */
+ UCL_STRING_PARSE_TIME = (1 << 5), /**< Parse time strings */
UCL_STRING_PARSE_NUMBER = UCL_STRING_PARSE_INT|UCL_STRING_PARSE_DOUBLE|UCL_STRING_PARSE_TIME, /**<
Parse passed string and detect number */
UCL_STRING_PARSE = UCL_STRING_PARSE_BOOLEAN|UCL_STRING_PARSE_NUMBER, /**<
Parse passed string (and detect booleans and numbers) */
- UCL_STRING_PARSE_BYTES = 0x40 /**< Treat numbers as bytes */
+ UCL_STRING_PARSE_BYTES = (1 << 6) /**< Treat numbers as bytes */
} ucl_string_flags_t;
/**
@@ -1091,6 +1093,23 @@ UCL_EXTERN void ucl_parser_clear_error(struct ucl_parser *parser);
UCL_EXTERN void ucl_parser_free (struct ucl_parser *parser);
/**
+ * Get constant opaque pointer to comments structure for this parser. Increase
+ * refcount to prevent this object to be destroyed on parser's destruction
+ * @param parser parser structure
+ * @return ucl comments pointer or NULL
+ */
+UCL_EXTERN const ucl_object_t * ucl_parser_get_comments (struct ucl_parser *parser);
+
+/**
+ * Utility function to find a comment object for the specified object in the input
+ * @param comments comments object
+ * @param srch search object
+ * @return string comment enclosed in ucl_object_t
+ */
+UCL_EXTERN const ucl_object_t * ucl_comments_find (const ucl_object_t *comments,
+ const ucl_object_t *srch);
+
+/**
* Add new public key to parser for signatures check
* @param parser parser object
* @param key PEM representation of a key
@@ -1171,8 +1190,8 @@ struct ucl_emitter_context {
unsigned int indent;
/** Top level object */
const ucl_object_t *top;
- /** The rest of context */
- unsigned char data[1];
+ /** Optional comments */
+ const ucl_object_t *comments;
};
/**
@@ -1202,11 +1221,13 @@ UCL_EXTERN unsigned char *ucl_object_emit_len (const ucl_object_t *obj,
* @param emit_type if type is #UCL_EMIT_JSON then emit json, if type is
* #UCL_EMIT_CONFIG then emit config like object
* @param emitter a set of emitter functions
+ * @param comments optional comments for the parser
* @return dump of an object (must be freed after using) or NULL in case of error
*/
UCL_EXTERN bool ucl_object_emit_full (const ucl_object_t *obj,
enum ucl_emitter emit_type,
- struct ucl_emitter_functions *emitter);
+ struct ucl_emitter_functions *emitter,
+ const ucl_object_t *comments);
/**
* Start streamlined UCL object emitter
diff --git a/contrib/libucl/ucl_emitter.c b/contrib/libucl/ucl_emitter.c
index 8bfbf09b8..84108e21d 100644
--- a/contrib/libucl/ucl_emitter.c
+++ b/contrib/libucl/ucl_emitter.c
@@ -362,6 +362,7 @@ ucl_emitter_common_elt (struct ucl_emitter_context *ctx,
const struct ucl_emitter_functions *func = ctx->func;
bool flag;
struct ucl_object_userdata *ud;
+ const ucl_object_t *comment = NULL, *cur_comment;
const char *ud_out = "";
if (ctx->id != UCL_EMIT_CONFIG && !first) {
@@ -379,6 +380,25 @@ ucl_emitter_common_elt (struct ucl_emitter_context *ctx,
ucl_add_tabs (func, ctx->indent, compact);
+ if (ctx->comments && ctx->id == UCL_EMIT_CONFIG) {
+ comment = ucl_object_find_keyl (ctx->comments, (const char *)&obj,
+ sizeof (void *));
+
+ if (comment) {
+ if (!(comment->flags & UCL_OBJECT_INHERITED)) {
+ DL_FOREACH (comment, cur_comment) {
+ func->ucl_emitter_append_len (cur_comment->value.sv,
+ cur_comment->len,
+ func->ud);
+ func->ucl_emitter_append_character ('\n', 1, func->ud);
+ ucl_add_tabs (func, ctx->indent, compact);
+ }
+
+ comment = NULL;
+ }
+ }
+ }
+
switch (obj->type) {
case UCL_INT:
ucl_emitter_print_key (print_key, ctx, obj, compact);
@@ -438,6 +458,19 @@ ucl_emitter_common_elt (struct ucl_emitter_context *ctx,
ucl_emitter_finish_object (ctx, obj, compact, !print_key);
break;
}
+
+ if (comment) {
+ DL_FOREACH (comment, cur_comment) {
+ func->ucl_emitter_append_len (cur_comment->value.sv,
+ cur_comment->len,
+ func->ud);
+ func->ucl_emitter_append_character ('\n', 1, func->ud);
+
+ if (cur_comment->next) {
+ ucl_add_tabs (func, ctx->indent, compact);
+ }
+ }
+ }
}
/*
@@ -605,10 +638,10 @@ ucl_object_emit_len (const ucl_object_t *obj, enum ucl_emitter emit_type,
}
func = ucl_object_emit_memory_funcs ((void **)&res);
- s = func->ud;
if (func != NULL) {
- ucl_object_emit_full (obj, emit_type, func);
+ s = func->ud;
+ ucl_object_emit_full (obj, emit_type, func, NULL);
if (outlen != NULL) {
*outlen = s->i;
@@ -622,7 +655,8 @@ ucl_object_emit_len (const ucl_object_t *obj, enum ucl_emitter emit_type,
bool
ucl_object_emit_full (const ucl_object_t *obj, enum ucl_emitter emit_type,
- struct ucl_emitter_functions *emitter)
+ struct ucl_emitter_functions *emitter,
+ const ucl_object_t *comments)
{
const struct ucl_emitter_context *ctx;
struct ucl_emitter_context my_ctx;
@@ -634,6 +668,7 @@ ucl_object_emit_full (const ucl_object_t *obj, enum ucl_emitter emit_type,
my_ctx.func = emitter;
my_ctx.indent = 0;
my_ctx.top = obj;
+ my_ctx.comments = comments;
my_ctx.ops->ucl_emitter_write_elt (&my_ctx, obj, true, false);
res = true;
diff --git a/contrib/libucl/ucl_emitter_streamline.c b/contrib/libucl/ucl_emitter_streamline.c
index ff27c8824..a7178c5d7 100644
--- a/contrib/libucl/ucl_emitter_streamline.c
+++ b/contrib/libucl/ucl_emitter_streamline.c
@@ -38,12 +38,20 @@ struct ucl_emitter_streamline_stack {
struct ucl_emitter_context_streamline {
/* Inherited from the main context */
+ /** Name of emitter (e.g. json, compact_json) */
const char *name;
+ /** Unique id (e.g. UCL_EMIT_JSON for standard emitters */
int id;
+ /** A set of output functions */
const struct ucl_emitter_functions *func;
+ /** A set of output operations */
const struct ucl_emitter_operations *ops;
- unsigned int ident;
+ /** Current amount of indent tabs */
+ unsigned int indent;
+ /** Top level object */
const ucl_object_t *top;
+ /** Optional comments */
+ const ucl_object_t *comments;
/* Streamline specific fields */
struct ucl_emitter_streamline_stack *containers;
diff --git a/contrib/libucl/ucl_hash.c b/contrib/libucl/ucl_hash.c
index 7de8196fa..174ebb685 100644
--- a/contrib/libucl/ucl_hash.c
+++ b/contrib/libucl/ucl_hash.c
@@ -247,7 +247,7 @@ ucl_hash_create (bool ignore_case)
return new;
}
-void ucl_hash_destroy (ucl_hash_t* hashlin, ucl_hash_free_func *func)
+void ucl_hash_destroy (ucl_hash_t* hashlin, ucl_hash_free_func func)
{
const ucl_object_t *cur, *tmp;
diff --git a/contrib/libucl/ucl_hash.h b/contrib/libucl/ucl_hash.h
index 64c83eac8..92021e340 100644
--- a/contrib/libucl/ucl_hash.h
+++ b/contrib/libucl/ucl_hash.h
@@ -31,8 +31,8 @@
struct ucl_hash_node_s;
typedef struct ucl_hash_node_s ucl_hash_node_t;
-typedef int ucl_hash_cmp_func (const void* void_a, const void* void_b);
-typedef void ucl_hash_free_func (void *ptr);
+typedef int (*ucl_hash_cmp_func) (const void* void_a, const void* void_b);
+typedef void (*ucl_hash_free_func) (void *ptr);
typedef void* ucl_hash_iter_t;
@@ -51,7 +51,7 @@ ucl_hash_t* ucl_hash_create (bool ignore_case);
/**
* Deinitializes the hashtable.
*/
-void ucl_hash_destroy (ucl_hash_t* hashlin, ucl_hash_free_func *func);
+void ucl_hash_destroy (ucl_hash_t* hashlin, ucl_hash_free_func func);
/**
* Inserts an element in the the hashtable.
diff --git a/contrib/libucl/ucl_internal.h b/contrib/libucl/ucl_internal.h
index 64938592a..db8a12c40 100644
--- a/contrib/libucl/ucl_internal.h
+++ b/contrib/libucl/ucl_internal.h
@@ -211,6 +211,8 @@ struct ucl_parser {
struct ucl_variable *variables;
ucl_variable_handler var_handler;
void *var_data;
+ ucl_object_t *comments;
+ ucl_object_t *last_comment;
UT_string *err;
};
diff --git a/contrib/libucl/ucl_parser.c b/contrib/libucl/ucl_parser.c
index 9bd41391b..fa906b7fe 100644
--- a/contrib/libucl/ucl_parser.c
+++ b/contrib/libucl/ucl_parser.c
@@ -89,6 +89,39 @@ ucl_set_err (struct ucl_parser *parser, int code, const char *str, UT_string **e
parser->err_code = code;
}
+static void
+ucl_save_comment (struct ucl_parser *parser, const char *begin, size_t len)
+{
+ ucl_object_t *nobj;
+
+ if (len > 0 && begin != NULL) {
+ nobj = ucl_object_fromstring_common (begin, len, 0);
+
+ if (parser->last_comment) {
+ /* We need to append data to an existing object */
+ DL_APPEND (parser->last_comment, nobj);
+ }
+ else {
+ parser->last_comment = nobj;
+ }
+ }
+}
+
+static void
+ucl_attach_comment (struct ucl_parser *parser, ucl_object_t *obj, bool before)
+{
+ if (parser->last_comment) {
+ ucl_object_insert_key (parser->comments, parser->last_comment,
+ (const char *)&obj, sizeof (void *), true);
+
+ if (before) {
+ parser->last_comment->flags |= UCL_OBJECT_INHERITED;
+ }
+
+ parser->last_comment = NULL;
+ }
+}
+
/**
* Skip all comments from the current pos resolving nested and multiline comments
* @param parser
@@ -98,7 +131,7 @@ static bool
ucl_skip_comments (struct ucl_parser *parser)
{
struct ucl_chunk *chunk = parser->chunks;
- const unsigned char *p;
+ const unsigned char *p, *beg = NULL;
int comments_nested = 0;
bool quoted = false;
@@ -108,9 +141,17 @@ start:
if (chunk->remain > 0 && *p == '#') {
if (parser->state != UCL_STATE_SCOMMENT &&
parser->state != UCL_STATE_MCOMMENT) {
+ beg = p;
+
while (p < chunk->end) {
if (*p == '\n') {
+ if (parser->flags & UCL_PARSER_SAVE_COMMENTS) {
+ ucl_save_comment (parser, beg, p - beg);
+ beg = NULL;
+ }
+
ucl_chunk_skipc (chunk, p);
+
goto start;
}
ucl_chunk_skipc (chunk, p);
@@ -119,6 +160,7 @@ start:
}
else if (chunk->remain >= 2 && *p == '/') {
if (p[1] == '*') {
+ beg = p;
ucl_chunk_skipc (chunk, p);
comments_nested ++;
ucl_chunk_skipc (chunk, p);
@@ -134,6 +176,11 @@ start:
if (*p == '/') {
comments_nested --;
if (comments_nested == 0) {
+ if (parser->flags & UCL_PARSER_SAVE_COMMENTS) {
+ ucl_save_comment (parser, beg, p - beg + 1);
+ beg = NULL;
+ }
+
ucl_chunk_skipc (chunk, p);
goto start;
}
@@ -147,6 +194,7 @@ start:
continue;
}
}
+
ucl_chunk_skipc (chunk, p);
}
if (comments_nested != 0) {
@@ -157,6 +205,10 @@ start:
}
}
+ if (beg && p > beg && (parser->flags & UCL_PARSER_SAVE_COMMENTS)) {
+ ucl_save_comment (parser, beg, p - beg);
+ }
+
return true;
}
@@ -451,6 +503,11 @@ ucl_expand_variable (struct ucl_parser *parser, unsigned char **dst,
size_t out_len = 0;
bool vars_found = false;
+ if (parser->flags & UCL_PARSER_DISABLE_MACRO) {
+ *dst = NULL;
+ return in_len;
+ }
+
p = src;
while (p != end) {
if (*p == '$') {
@@ -590,12 +647,14 @@ ucl_parser_add_container (ucl_object_t *obj, struct ucl_parser *parser,
}
st = UCL_ALLOC (sizeof (struct ucl_stack));
+
if (st == NULL) {
ucl_set_err (parser, UCL_EINTERNAL, "cannot allocate memory for an object",
&parser->err);
ucl_object_unref (obj);
return NULL;
}
+
st->obj = obj;
st->level = level;
LL_PREPEND (parser->stack, st);
@@ -1092,6 +1151,7 @@ ucl_parser_process_object_element (struct ucl_parser *parser, ucl_object_t *nobj
parser->stack->obj->value.ov = container;
parser->cur_obj = nobj;
+ ucl_attach_comment (parser, nobj, false);
return true;
}
@@ -1120,7 +1180,10 @@ ucl_parse_key (struct ucl_parser *parser, struct ucl_chunk *chunk,
if (*p == '.') {
/* It is macro actually */
- ucl_chunk_skipc (chunk, p);
+ if (!(parser->flags & UCL_PARSER_DISABLE_MACRO)) {
+ ucl_chunk_skipc (chunk, p);
+ }
+
parser->prev_state = parser->state;
parser->state = UCL_STATE_MACRO_NAME;
*end_of_object = false;
@@ -1461,6 +1524,7 @@ ucl_parser_get_container (struct ucl_parser *parser)
}
parser->cur_obj = obj;
+ ucl_attach_comment (parser, obj, false);
}
else {
/* Object has been already allocated */
@@ -1707,12 +1771,19 @@ ucl_parse_after_value (struct ucl_parser *parser, struct ucl_chunk *chunk)
parser->stack = st->next;
UCL_FREE (sizeof (struct ucl_stack), st);
+ if (parser->cur_obj) {
+ ucl_attach_comment (parser, parser->cur_obj, true);
+ }
+
while (parser->stack != NULL) {
st = parser->stack;
+
if (st->next == NULL || st->next->level == st->level) {
break;
}
+
parser->stack = st->next;
+ parser->cur_obj = st->obj;
UCL_FREE (sizeof (struct ucl_stack), st);
}
}
@@ -1752,6 +1823,109 @@ ucl_parse_after_value (struct ucl_parser *parser, struct ucl_chunk *chunk)
return true;
}
+static bool
+ucl_skip_macro_as_comment (struct ucl_parser *parser,
+ struct ucl_chunk *chunk)
+{
+ const unsigned char *p, *c;
+ enum {
+ macro_skip_start = 0,
+ macro_has_symbols,
+ macro_has_obrace,
+ macro_has_quote,
+ macro_has_backslash,
+ macro_has_sqbrace,
+ macro_save
+ } state = macro_skip_start, prev_state = macro_skip_start;
+
+ p = chunk->pos;
+ c = chunk->pos;
+
+ while (p < chunk->end) {
+ switch (state) {
+ case macro_skip_start:
+ if (!ucl_test_character (*p, UCL_CHARACTER_WHITESPACE)) {
+ state = macro_has_symbols;
+ }
+ else if (ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE)) {
+ state = macro_save;
+ continue;
+ }
+
+ ucl_chunk_skipc (chunk, p);
+ break;
+
+ case macro_has_symbols:
+ if (*p == '{') {
+ state = macro_has_sqbrace;
+ }
+ else if (*p == '(') {
+ state = macro_has_obrace;
+ }
+ else if (*p == '"') {
+ state = macro_has_quote;
+ }
+ else if (*p == '\n') {
+ state = macro_save;
+ continue;
+ }
+
+ ucl_chunk_skipc (chunk, p);
+ break;
+
+ case macro_has_obrace:
+ if (*p == '\\') {
+ prev_state = state;
+ state = macro_has_backslash;
+ }
+ else if (*p == ')') {
+ state = macro_has_symbols;
+ }
+
+ ucl_chunk_skipc (chunk, p);
+ break;
+
+ case macro_has_sqbrace:
+ if (*p == '\\') {
+ prev_state = state;
+ state = macro_has_backslash;
+ }
+ else if (*p == '}') {
+ state = macro_save;
+ }
+
+ ucl_chunk_skipc (chunk, p);
+ break;
+
+ case macro_has_quote:
+ if (*p == '\\') {
+ prev_state = state;
+ state = macro_has_backslash;
+ }
+ else if (*p == '"') {
+ state = macro_save;
+ }
+
+ ucl_chunk_skipc (chunk, p);
+ break;
+
+ case macro_has_backslash:
+ state = prev_state;
+ ucl_chunk_skipc (chunk, p);
+ break;
+
+ case macro_save:
+ if (parser->flags & UCL_PARSER_SAVE_COMMENTS) {
+ ucl_save_comment (parser, c, p - c);
+ }
+
+ return true;
+ }
+ }
+
+ return false;
+}
+
/**
* Handle macro data
* @param parser
@@ -2067,7 +2241,7 @@ ucl_state_machine (struct ucl_parser *parser)
break;
case UCL_STATE_VALUE:
/* We need to check what we do have */
- if (!ucl_parse_value (parser, chunk)) {
+ if (!parser->cur_obj || !ucl_parse_value (parser, chunk)) {
parser->prev_state = parser->state;
parser->state = UCL_STATE_ERROR;
return false;
@@ -2095,42 +2269,60 @@ ucl_state_machine (struct ucl_parser *parser)
/* Skip everything at the end */
return true;
}
+
p = chunk->pos;
break;
case UCL_STATE_MACRO_NAME:
- if (!ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE) &&
- *p != '(') {
- ucl_chunk_skipc (chunk, p);
+ if (parser->flags & UCL_PARSER_DISABLE_MACRO) {
+ if (!ucl_skip_macro_as_comment (parser, chunk)) {
+ /* We have invalid macro */
+ ucl_create_err (&parser->err,
+ "error on line %d at column %d: invalid macro",
+ chunk->line,
+ chunk->column);
+ parser->state = UCL_STATE_ERROR;
+ return false;
+ }
+ else {
+ p = chunk->pos;
+ parser->state = parser->prev_state;
+ }
}
else {
- if (p - c > 0) {
- /* We got macro name */
- macro_len = (size_t) (p - c);
- HASH_FIND (hh, parser->macroes, c, macro_len, macro);
- if (macro == NULL) {
+ if (!ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE) &&
+ *p != '(') {
+ ucl_chunk_skipc (chunk, p);
+ }
+ else {
+ if (p - c > 0) {
+ /* We got macro name */
+ macro_len = (size_t) (p - c);
+ HASH_FIND (hh, parser->macroes, c, macro_len, macro);
+ if (macro == NULL) {
+ ucl_create_err (&parser->err,
+ "error on line %d at column %d: "
+ "unknown macro: '%.*s', character: '%c'",
+ chunk->line,
+ chunk->column,
+ (int) (p - c),
+ c,
+ *chunk->pos);
+ parser->state = UCL_STATE_ERROR;
+ return false;
+ }
+ /* Now we need to skip all spaces */
+ SKIP_SPACES_COMMENTS(parser, chunk, p);
+ parser->state = UCL_STATE_MACRO;
+ }
+ else {
+ /* We have invalid macro name */
ucl_create_err (&parser->err,
- "error on line %d at column %d: "
- "unknown macro: '%.*s', character: '%c'",
+ "error on line %d at column %d: invalid macro name",
chunk->line,
- chunk->column,
- (int) (p - c),
- c,
- *chunk->pos);
+ chunk->column);
parser->state = UCL_STATE_ERROR;
return false;
}
- /* Now we need to skip all spaces */
- SKIP_SPACES_COMMENTS(parser, chunk, p);
- parser->state = UCL_STATE_MACRO;
- }
- else {
- /* We have invalid macro name */
- ucl_create_err (&parser->err,
- "error on line %d at column %d: invalid macro name",
- chunk->line,
- chunk->column);
- parser->state = UCL_STATE_ERROR;
- return false;
}
}
break;
@@ -2154,6 +2346,7 @@ ucl_state_machine (struct ucl_parser *parser)
macro_len = ucl_expand_variable (parser, &macro_escaped,
macro_start, macro_len);
parser->state = parser->prev_state;
+
if (macro_escaped == NULL) {
if (macro->is_context) {
ret = macro->h.context_handler (macro_start, macro_len,
@@ -2194,7 +2387,6 @@ ucl_state_machine (struct ucl_parser *parser)
}
break;
default:
- /* TODO: add all states */
ucl_set_err (parser, UCL_EINTERNAL,
"internal error: parser is in an unknown state", &parser->err);
parser->state = UCL_STATE_ERROR;
@@ -2202,35 +2394,54 @@ ucl_state_machine (struct ucl_parser *parser)
}
}
+ if (parser->last_comment) {
+ if (parser->cur_obj) {
+ ucl_attach_comment (parser, parser->cur_obj, true);
+ }
+ else if (parser->stack && parser->stack->obj) {
+ ucl_attach_comment (parser, parser->stack->obj, true);
+ }
+ else if (parser->top_obj) {
+ ucl_attach_comment (parser, parser->top_obj, true);
+ }
+ else {
+ ucl_object_unref (parser->last_comment);
+ }
+ }
+
return true;
}
struct ucl_parser*
ucl_parser_new (int flags)
{
- struct ucl_parser *new;
+ struct ucl_parser *parser;
- new = UCL_ALLOC (sizeof (struct ucl_parser));
- if (new == NULL) {
+ parser = UCL_ALLOC (sizeof (struct ucl_parser));
+ if (parser == NULL) {
return NULL;
}
- memset (new, 0, sizeof (struct ucl_parser));
+ memset (parser, 0, sizeof (struct ucl_parser));
- ucl_parser_register_macro (new, "include", ucl_include_handler, new);
- ucl_parser_register_macro (new, "try_include", ucl_try_include_handler, new);
- ucl_parser_register_macro (new, "includes", ucl_includes_handler, new);
- ucl_parser_register_macro (new, "priority", ucl_priority_handler, new);
- ucl_parser_register_macro (new, "load", ucl_load_handler, new);
- ucl_parser_register_context_macro (new, "inherit", ucl_inherit_handler, new);
+ ucl_parser_register_macro (parser, "include", ucl_include_handler, parser);
+ ucl_parser_register_macro (parser, "try_include", ucl_try_include_handler, parser);
+ ucl_parser_register_macro (parser, "includes", ucl_includes_handler, parser);
+ ucl_parser_register_macro (parser, "priority", ucl_priority_handler, parser);
+ ucl_parser_register_macro (parser, "load", ucl_load_handler, parser);
+ ucl_parser_register_context_macro (parser, "inherit", ucl_inherit_handler, parser);
- new->flags = flags;
- new->includepaths = NULL;
+ parser->flags = flags;
+ parser->includepaths = NULL;
+
+ if (flags & UCL_PARSER_SAVE_COMMENTS) {
+ parser->comments = ucl_object_typed_new (UCL_OBJECT);
+ }
/* Initial assumption about filevars */
- ucl_parser_set_filevars (new, NULL, false);
+ ucl_parser_set_filevars (parser, NULL, false);
- return new;
+ return parser;
}
bool
diff --git a/contrib/libucl/ucl_schema.c b/contrib/libucl/ucl_schema.c
index 9b96da5ef..531cf848c 100644
--- a/contrib/libucl/ucl_schema.c
+++ b/contrib/libucl/ucl_schema.c
@@ -753,7 +753,7 @@ ucl_schema_resolve_ref (const ucl_object_t *root, const char *ref,
if (ext_obj == NULL) {
if (ucl_strnstr (p, "://", strlen (p)) != NULL) {
if (!ucl_fetch_url (p, &url_buf, &url_buflen, &url_err, true)) {
- free (url_copy);
+
ucl_schema_create_error (err,
UCL_SCHEMA_INVALID_SCHEMA,
root,
@@ -761,13 +761,14 @@ ucl_schema_resolve_ref (const ucl_object_t *root, const char *ref,
p,
url_err != NULL ? utstring_body (url_err)
: "unknown");
+ free (url_copy);
+
return NULL;
}
}
else {
if (!ucl_fetch_file (p, &url_buf, &url_buflen, &url_err,
true)) {
- free (url_copy);
ucl_schema_create_error (err,
UCL_SCHEMA_INVALID_SCHEMA,
root,
@@ -775,6 +776,8 @@ ucl_schema_resolve_ref (const ucl_object_t *root, const char *ref,
p,
url_err != NULL ? utstring_body (url_err)
: "unknown");
+ free (url_copy);
+
return NULL;
}
}
@@ -782,11 +785,12 @@ ucl_schema_resolve_ref (const ucl_object_t *root, const char *ref,
parser = ucl_parser_new (0);
if (!ucl_parser_add_chunk (parser, url_buf, url_buflen)) {
- free (url_copy);
ucl_schema_create_error (err, UCL_SCHEMA_INVALID_SCHEMA, root,
"cannot fetch reference %s: %s", p,
ucl_parser_get_error (parser));
ucl_parser_free (parser);
+ free (url_copy);
+
return NULL;
}
@@ -794,9 +798,10 @@ ucl_schema_resolve_ref (const ucl_object_t *root, const char *ref,
ext_obj = url_obj;
ucl_object_insert_key (ext_ref, url_obj, p, 0, true);
free (url_buf);
- free (url_copy);
}
+ free (url_copy);
+
if (hash_ptr) {
p = hash_ptr + 1;
}
diff --git a/contrib/libucl/ucl_sexp.c b/contrib/libucl/ucl_sexp.c
new file mode 100644
index 000000000..1ad93d234
--- /dev/null
+++ b/contrib/libucl/ucl_sexp.c
@@ -0,0 +1,226 @@
+/*
+ * Copyright (c) 2015, Vsevolod Stakhov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY AUTHOR ''AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <ucl.h>
+#include "ucl.h"
+#include "ucl_internal.h"
+#include "utlist.h"
+
+#define NEXT_STATE do { \
+if (p >= end) { \
+ if (state != read_ebrace) { \
+ ucl_create_err (&parser->err,\
+ "extra data");\
+ state = parse_err; \
+ } \
+} \
+else { \
+switch (*p) { \
+ case '(': \
+ state = read_obrace; \
+ break; \
+ case ')': \
+ state = read_ebrace; \
+ break; \
+ default: \
+ len = 0; \
+ mult = 1; \
+ state = read_length; \
+ break; \
+ } \
+} \
+} while(0)
+
+bool
+ucl_parse_csexp (struct ucl_parser *parser)
+{
+ const unsigned char *p, *end;
+ ucl_object_t *obj;
+ struct ucl_stack *st;
+ uint64_t len = 0, mult = 1;
+ enum {
+ start_parse,
+ read_obrace,
+ read_length,
+ read_value,
+ read_ebrace,
+ parse_err
+ } state = start_parse;
+
+ assert (parser != NULL);
+ assert (parser->chunks != NULL);
+ assert (parser->chunks->begin != NULL);
+ assert (parser->chunks->remain != 0);
+
+ p = parser->chunks->begin;
+ end = p + parser->chunks->remain;
+
+ while (p < end) {
+ switch (state) {
+ case start_parse:
+ /* At this point we expect open brace */
+ if (*p == '(') {
+ state = read_obrace;
+ }
+ else {
+ ucl_create_err (&parser->err, "bad starting character for "
+ "sexp block: %x", (int)*p);
+ state = parse_err;
+ }
+ break;
+
+ case read_obrace:
+ st = calloc (1, sizeof (*st));
+
+ if (st == NULL) {
+ ucl_create_err (&parser->err, "no memory");
+ state = parse_err;
+ continue;
+ }
+
+ st->obj = ucl_object_typed_new (UCL_ARRAY);
+
+ if (st->obj == NULL) {
+ ucl_create_err (&parser->err, "no memory");
+ state = parse_err;
+ free (st);
+ continue;
+ }
+
+ if (parser->stack == NULL) {
+ /* We have no stack */
+ parser->stack = st;
+
+ if (parser->top_obj == NULL) {
+ parser->top_obj = st->obj;
+ }
+ }
+ else {
+ /* Prepend new element to the stack */
+ LL_PREPEND (parser->stack, st);
+ }
+
+ p ++;
+ NEXT_STATE;
+
+ break;
+
+ case read_length:
+ if (*p == ':') {
+ if (len == 0) {
+ ucl_create_err (&parser->err, "zero length element");
+ state = parse_err;
+ continue;
+ }
+
+ state = read_value;
+ }
+ else if (*p >= '0' && *p <= '9') {
+ len += (*p - '0') * mult;
+ mult *= 10;
+
+ if (len > UINT32_MAX) {
+ ucl_create_err (&parser->err, "too big length of an "
+ "element");
+ state = parse_err;
+ continue;
+ }
+ }
+ else {
+ ucl_create_err (&parser->err, "bad length character: %x",
+ (int)*p);
+ state = parse_err;
+ continue;
+ }
+
+ p ++;
+ break;
+
+ case read_value:
+ if ((uint64_t)(end - p) > len || len == 0) {
+ ucl_create_err (&parser->err, "invalid length: %llu, %ld "
+ "remain", (long long unsigned)len, (long)(end - p));
+ state = parse_err;
+ continue;
+ }
+ obj = ucl_object_typed_new (UCL_STRING);
+
+ obj->value.sv = (const char*)p;
+ obj->len = len;
+ obj->flags |= UCL_OBJECT_BINARY;
+
+ if (!(parser->flags & UCL_PARSER_ZEROCOPY)) {
+ ucl_copy_value_trash (obj);
+ }
+
+ ucl_array_append (parser->stack->obj, obj);
+ p += len;
+ NEXT_STATE;
+ break;
+
+ case read_ebrace:
+ if (parser->stack == NULL) {
+ /* We have an extra end brace */
+ ucl_create_err (&parser->err, "invalid length: %llu, %ld "
+ "remain", (long long unsigned)len, (long)(end - p));
+ state = parse_err;
+ continue;
+ }
+ /* Pop the container */
+ st = parser->stack;
+ parser->stack = st->next;
+
+ if (parser->stack->obj->type == UCL_ARRAY) {
+ ucl_array_append (parser->stack->obj, st->obj);
+ }
+ else {
+ ucl_create_err (&parser->err, "bad container object, array "
+ "expected");
+ state = parse_err;
+ continue;
+ }
+
+ free (st);
+ st = NULL;
+ p++;
+ NEXT_STATE;
+ break;
+
+ case parse_err:
+ default:
+ return false;
+ }
+ }
+
+ if (state != read_ebrace) {
+ ucl_create_err (&parser->err, "invalid finishing state: %d", state);
+ return false;
+ }
+
+ return true;
+}
diff --git a/contrib/libucl/ucl_util.c b/contrib/libucl/ucl_util.c
index 2bd0c2a3f..15439feea 100644
--- a/contrib/libucl/ucl_util.c
+++ b/contrib/libucl/ucl_util.c
@@ -236,7 +236,7 @@ ucl_object_free_internal (ucl_object_t *obj, bool allow_rec, ucl_object_dtor dto
}
else if (obj->type == UCL_OBJECT) {
if (obj->value.ov != NULL) {
- ucl_hash_destroy (obj->value.ov, (ucl_hash_free_func *)dtor);
+ ucl_hash_destroy (obj->value.ov, (ucl_hash_free_func)dtor);
}
obj->value.ov = NULL;
}
@@ -504,6 +504,10 @@ ucl_parser_free (struct ucl_parser *parser)
free (parser->cur_file);
}
+ if (parser->comments) {
+ ucl_object_unref (parser->comments);
+ }
+
UCL_FREE (sizeof (struct ucl_parser), parser);
}
@@ -1037,6 +1041,16 @@ ucl_include_file_single (const unsigned char *data, size_t len,
else if (old_obj == NULL) {
/* Create an object with key: prefix */
nest_obj = ucl_object_new_full (UCL_OBJECT, params->priority);
+
+ if (nest_obj == NULL) {
+ ucl_create_err (&parser->err, "cannot allocate memory for an object");
+ if (buflen > 0) {
+ ucl_munmap (buf, buflen);
+ }
+
+ return false;
+ }
+
nest_obj->key = params->prefix;
nest_obj->keylen = strlen (params->prefix);
ucl_copy_key_trash(nest_obj);
@@ -1052,6 +1066,14 @@ ucl_include_file_single (const unsigned char *data, size_t len,
if (ucl_object_type(old_obj) == UCL_ARRAY) {
/* Append to the existing array */
nest_obj = ucl_object_new_full (UCL_OBJECT, params->priority);
+ if (nest_obj == NULL) {
+ ucl_create_err (&parser->err, "cannot allocate memory for an object");
+ if (buflen > 0) {
+ ucl_munmap (buf, buflen);
+ }
+
+ return false;
+ }
nest_obj->prev = nest_obj;
nest_obj->next = NULL;
@@ -1060,6 +1082,14 @@ ucl_include_file_single (const unsigned char *data, size_t len,
else {
/* Convert the object to an array */
new_obj = ucl_object_typed_new (UCL_ARRAY);
+ if (new_obj == NULL) {
+ ucl_create_err (&parser->err, "cannot allocate memory for an object");
+ if (buflen > 0) {
+ ucl_munmap (buf, buflen);
+ }
+
+ return false;
+ }
new_obj->key = old_obj->key;
new_obj->keylen = old_obj->keylen;
new_obj->flags |= UCL_OBJECT_MULTIVALUE;
@@ -1067,6 +1097,14 @@ ucl_include_file_single (const unsigned char *data, size_t len,
new_obj->next = NULL;
nest_obj = ucl_object_new_full (UCL_OBJECT, params->priority);
+ if (nest_obj == NULL) {
+ ucl_create_err (&parser->err, "cannot allocate memory for an object");
+ if (buflen > 0) {
+ ucl_munmap (buf, buflen);
+ }
+
+ return false;
+ }
nest_obj->prev = nest_obj;
nest_obj->next = NULL;
@@ -1085,6 +1123,10 @@ ucl_include_file_single (const unsigned char *data, size_t len,
ucl_create_err (&parser->err,
"Conflicting type for key: %s",
params->prefix);
+ if (buflen > 0) {
+ ucl_munmap (buf, buflen);
+ }
+
return false;
}
}
@@ -1097,7 +1139,11 @@ ucl_include_file_single (const unsigned char *data, size_t len,
if (st == NULL) {
ucl_create_err (&parser->err, "cannot allocate memory for an object");
ucl_object_unref (nest_obj);
- return NULL;
+ if (buflen > 0) {
+ ucl_munmap (buf, buflen);
+ }
+
+ return false;
}
st->obj = nest_obj;
st->level = parser->stack->level;
@@ -1579,6 +1625,10 @@ ucl_load_handler (const unsigned char *data, size_t len,
old_obj = __DECONST (ucl_object_t *, ucl_hash_search (container, prefix, strlen (prefix)));
if (old_obj != NULL) {
ucl_create_err (&parser->err, "Key %s already exists", prefix);
+ if (buflen > 0) {
+ ucl_munmap (buf, buflen);
+ }
+
return false;
}
@@ -1610,6 +1660,7 @@ ucl_load_handler (const unsigned char *data, size_t len,
parser->flags & UCL_PARSER_KEY_LOWERCASE);
parser->stack->obj->value.ov = container;
}
+
return true;
}
@@ -3323,3 +3374,25 @@ ucl_object_type_to_string (ucl_type_t type)
return res;
}
+
+const ucl_object_t *
+ucl_parser_get_comments (struct ucl_parser *parser)
+{
+ if (parser && parser->comments) {
+ return parser->comments;
+ }
+
+ return NULL;
+}
+
+const ucl_object_t *
+ucl_comments_find (const ucl_object_t *comments,
+ const ucl_object_t *srch)
+{
+ if (comments && srch) {
+ return ucl_object_find_keyl (comments, (const char *)&srch,
+ sizeof (void *));
+ }
+
+ return NULL;
+}