diff options
author | Vsevolod Stakhov <vsevolod@highsecure.ru> | 2015-07-28 16:57:15 +0100 |
---|---|---|
committer | Vsevolod Stakhov <vsevolod@highsecure.ru> | 2015-07-28 16:57:15 +0100 |
commit | c9d280cb3d6efeee26239d6cdb7827805e0ddaea (patch) | |
tree | f2331ee672f7158ba1d8c33fec770b53c3abfe99 /contrib/libucl | |
parent | 8bb760de0b6446e0f6f79b83812ffb7d4383e1b8 (diff) | |
download | rspamd-c9d280cb3d6efeee26239d6cdb7827805e0ddaea.tar.gz rspamd-c9d280cb3d6efeee26239d6cdb7827805e0ddaea.zip |
Import the recent libucl.
Diffstat (limited to 'contrib/libucl')
-rw-r--r-- | contrib/libucl/CMakeLists.txt | 3 | ||||
-rw-r--r-- | contrib/libucl/ucl.h | 98 | ||||
-rw-r--r-- | contrib/libucl/ucl_emitter.c | 125 | ||||
-rw-r--r-- | contrib/libucl/ucl_emitter_utils.c | 8 | ||||
-rw-r--r-- | contrib/libucl/ucl_hash.c | 5 | ||||
-rw-r--r-- | contrib/libucl/ucl_internal.h | 98 | ||||
-rw-r--r-- | contrib/libucl/ucl_parser.c | 74 | ||||
-rw-r--r-- | contrib/libucl/ucl_util.c | 667 |
8 files changed, 1000 insertions, 78 deletions
diff --git a/contrib/libucl/CMakeLists.txt b/contrib/libucl/CMakeLists.txt index 80f50155e..a1e919484 100644 --- a/contrib/libucl/CMakeLists.txt +++ b/contrib/libucl/CMakeLists.txt @@ -5,7 +5,8 @@ SET(UCLSRC ucl_util.c ucl_emitter_utils.c ucl_hash.c ucl_schema.c - lua_ucl.c) + lua_ucl.c + ucl_msgpack.c) SET (LIB_TYPE STATIC) diff --git a/contrib/libucl/ucl.h b/contrib/libucl/ucl.h index 0fbd5b822..4d417eebe 100644 --- a/contrib/libucl/ucl.h +++ b/contrib/libucl/ucl.h @@ -135,7 +135,9 @@ typedef enum ucl_emitter { UCL_EMIT_JSON = 0, /**< Emit fine formatted JSON */ UCL_EMIT_JSON_COMPACT, /**< Emit compacted JSON */ UCL_EMIT_CONFIG, /**< Emit human readable config format */ - UCL_EMIT_YAML /**< Emit embedded YAML format */ + UCL_EMIT_YAML, /**< Emit embedded YAML format */ + UCL_EMIT_MSGPACK, /**< Emit msgpack output */ + UCL_EMIT_MAX /**< Unsupported emitter type */ } ucl_emitter_t; /** @@ -623,6 +625,19 @@ UCL_EXTERN const ucl_object_t* ucl_object_find_key (const ucl_object_t *obj, const char *key); /** + * Return object identified by a key in the specified object, if the first key is + * not found then look for the next one. This process is repeated unless + * the next argument in the list is not NULL. So, `ucl_object_find_any_key(obj, key, NULL)` + * is equal to `ucl_object_find_key(obj, key)` + * @param obj object to get a key from (must be of type UCL_OBJECT) + * @param key key to search + * @param ... list of alternative keys to search (NULL terminated) + * @return object matching the specified key or NULL if key was not found + */ +UCL_EXTERN const ucl_object_t* ucl_object_find_any_key (const ucl_object_t *obj, + const char *key, ...); + +/** * Return object identified by a fixed size key in the specified object * @param obj object to get a key from (must be of type UCL_OBJECT) * @param key key to search @@ -883,6 +898,18 @@ UCL_EXTERN bool ucl_parser_add_string (struct ucl_parser *parser, const char *data,size_t len); /** + * Load ucl object from a string + * @param parser parser structure + * @param data the pointer to the string + * @param len the length of the string, if `len` is 0 then `data` must be zero-terminated string + * @param priority the desired priority of a chunk (only 4 least significant bits + * are considered for this parameter) + * @return true if string has been added and false in case of error + */ +UCL_EXTERN bool ucl_parser_add_string_priority (struct ucl_parser *parser, + const char *data, size_t len, unsigned priority); + +/** * Load and add data from a file * @param parser parser structure * @param filename the name of file @@ -893,6 +920,18 @@ UCL_EXTERN bool ucl_parser_add_file (struct ucl_parser *parser, const char *filename); /** + * Load and add data from a file + * @param parser parser structure + * @param filename the name of file + * @param err if *err is NULL it is set to parser error + * @param priority the desired priority of a chunk (only 4 least significant bits + * are considered for this parameter) + * @return true if chunk has been added and false in case of error + */ +UCL_EXTERN bool ucl_parser_add_file_priority (struct ucl_parser *parser, + const char *filename, unsigned priority); + +/** * Load and add data from a file descriptor * @param parser parser structure * @param filename the name of file @@ -903,6 +942,28 @@ UCL_EXTERN bool ucl_parser_add_fd (struct ucl_parser *parser, int fd); /** + * Load and add data from a file descriptor + * @param parser parser structure + * @param filename the name of file + * @param err if *err is NULL it is set to parser error + * @param priority the desired priority of a chunk (only 4 least significant bits + * are considered for this parameter) + * @return true if chunk has been added and false in case of error + */ +UCL_EXTERN bool ucl_parser_add_fd_priority (struct ucl_parser *parser, + int fd, unsigned priority); + +/** + * Provide a UCL_ARRAY of paths to search for include files. The object is + * copied so caller must unref the object. + * @param parser parser structure + * @param paths UCL_ARRAY of paths to search + * @return true if the path search array was replaced in the parser + */ +UCL_EXTERN bool ucl_set_include_path (struct ucl_parser *parser, + ucl_object_t *paths); + +/** * Get a top object for a parser (refcount is increased) * @param parser parser structure * @param err if *err is NULL it is set to parser error @@ -911,12 +972,34 @@ UCL_EXTERN bool ucl_parser_add_fd (struct ucl_parser *parser, UCL_EXTERN ucl_object_t* ucl_parser_get_object (struct ucl_parser *parser); /** - * Get the error string if failing + * Get the error string if parsing has been failed * @param parser parser object + * @return error description */ UCL_EXTERN const char *ucl_parser_get_error(struct ucl_parser *parser); /** + * Get the code of the last error + * @param parser parser object + * @return error code + */ +UCL_EXTERN int ucl_parser_get_error_code(struct ucl_parser *parser); + +/** + * Get the current column number within parser + * @param parser parser object + * @return current column number + */ +UCL_EXTERN unsigned ucl_parser_get_column(struct ucl_parser *parser); + +/** + * Get the current line number within parser + * @param parser parser object + * @return current line number + */ +UCL_EXTERN unsigned ucl_parser_get_linenum(struct ucl_parser *parser); + +/** * Clear the error in the parser * @param parser parser object */ @@ -1024,6 +1107,17 @@ UCL_EXTERN unsigned char *ucl_object_emit (const ucl_object_t *obj, enum ucl_emitter emit_type); /** + * Emit object to a string that can contain `\0` inside + * @param obj object + * @param emit_type if type is #UCL_EMIT_JSON then emit json, if type is + * #UCL_EMIT_CONFIG then emit config like object + * @param len the resulting length + * @return dump of an object (must be freed after using) or NULL in case of error + */ +UCL_EXTERN unsigned char *ucl_object_emit_len (const ucl_object_t *obj, + enum ucl_emitter emit_type, size_t *len); + +/** * Emit object to a string * @param obj object * @param emit_type if type is #UCL_EMIT_JSON then emit json, if type is diff --git a/contrib/libucl/ucl_emitter.c b/contrib/libucl/ucl_emitter.c index 9ddf3584a..12cd31c7d 100644 --- a/contrib/libucl/ucl_emitter.c +++ b/contrib/libucl/ucl_emitter.c @@ -62,6 +62,7 @@ UCL_EMIT_TYPE_OPS(json); UCL_EMIT_TYPE_OPS(json_compact); UCL_EMIT_TYPE_OPS(config); UCL_EMIT_TYPE_OPS(yaml); +UCL_EMIT_TYPE_OPS(msgpack); #define UCL_EMIT_TYPE_CONTENT(type) { \ .ucl_emitter_write_elt = ucl_emit_ ## type ## _elt, \ @@ -71,12 +72,12 @@ UCL_EMIT_TYPE_OPS(yaml); .ucl_emitter_end_array = ucl_emit_ ## type ##_end_array \ } - const struct ucl_emitter_operations ucl_standartd_emitter_ops[] = { [UCL_EMIT_JSON] = UCL_EMIT_TYPE_CONTENT(json), [UCL_EMIT_JSON_COMPACT] = UCL_EMIT_TYPE_CONTENT(json_compact), [UCL_EMIT_CONFIG] = UCL_EMIT_TYPE_CONTENT(config), - [UCL_EMIT_YAML] = UCL_EMIT_TYPE_CONTENT(yaml) + [UCL_EMIT_YAML] = UCL_EMIT_TYPE_CONTENT(yaml), + [UCL_EMIT_MSGPACK] = UCL_EMIT_TYPE_CONTENT(msgpack) }; /* @@ -469,19 +470,139 @@ UCL_EMIT_TYPE_IMPL(json_compact, true) UCL_EMIT_TYPE_IMPL(config, false) UCL_EMIT_TYPE_IMPL(yaml, false) +static void +ucl_emit_msgpack_elt (struct ucl_emitter_context *ctx, + const ucl_object_t *obj, bool first, bool print_key) +{ + ucl_object_iter_t it; + struct ucl_object_userdata *ud; + const char *ud_out; + const ucl_object_t *cur, *celt; + + switch (obj->type) { + case UCL_INT: + ucl_emitter_print_key_msgpack (print_key, ctx, obj); + ucl_emitter_print_int_msgpack (ctx, ucl_object_toint (obj)); + break; + + case UCL_FLOAT: + case UCL_TIME: + ucl_emitter_print_key_msgpack (print_key, ctx, obj); + ucl_emitter_print_double_msgpack (ctx, ucl_object_todouble (obj)); + break; + + case UCL_BOOLEAN: + ucl_emitter_print_key_msgpack (print_key, ctx, obj); + ucl_emitter_print_bool_msgpack (ctx, ucl_object_toboolean (obj)); + break; + + case UCL_STRING: + ucl_emitter_print_key_msgpack (print_key, ctx, obj); + ucl_emitter_print_string_msgpack (ctx, obj->value.sv, obj->len); + break; + + case UCL_NULL: + ucl_emitter_print_key_msgpack (print_key, ctx, obj); + ucl_emitter_print_null_msgpack (ctx); + break; + + case UCL_OBJECT: + ucl_emitter_print_key_msgpack (print_key, ctx, obj); + ucl_emit_msgpack_start_obj (ctx, obj, print_key); + it = ucl_object_iterate_new (obj); + + while ((cur = ucl_object_iterate_safe (it, true)) != NULL) { + LL_FOREACH (cur, celt) { + ucl_emit_msgpack_elt (ctx, celt, false, true); + } + } + + ucl_object_iterate_free (it); + break; + + case UCL_ARRAY: + ucl_emitter_print_key_msgpack (print_key, ctx, obj); + ucl_emit_msgpack_start_array (ctx, obj, print_key); + it = ucl_object_iterate_new (obj); + + while ((cur = ucl_object_iterate_safe (it, true)) != NULL) { + ucl_emit_msgpack_elt (ctx, cur, false, false); + } + + ucl_object_iterate_free (it); + break; + + case UCL_USERDATA: + ud = (struct ucl_object_userdata *)obj; + ucl_emitter_print_key_msgpack (print_key, ctx, obj); + + if (ud->emitter) { + ud_out = ud->emitter (obj->value.ud); + if (ud_out == NULL) { + ud_out = "null"; + } + } + ucl_emitter_print_string_msgpack (ctx, obj->value.sv, obj->len); + break; + } +} + +static void +ucl_emit_msgpack_start_obj (struct ucl_emitter_context *ctx, + const ucl_object_t *obj, bool print_key) +{ + ucl_emitter_print_object_msgpack (ctx, obj->len); +} + +static void +ucl_emit_msgpack_start_array (struct ucl_emitter_context *ctx, + const ucl_object_t *obj, bool print_key) +{ + ucl_emitter_print_array_msgpack (ctx, obj->len); +} + +static void +ucl_emit_msgpack_end_object (struct ucl_emitter_context *ctx, + const ucl_object_t *obj) +{ + +} + +static void +ucl_emit_msgpack_end_array (struct ucl_emitter_context *ctx, + const ucl_object_t *obj) +{ + +} + unsigned char * ucl_object_emit (const ucl_object_t *obj, enum ucl_emitter emit_type) { + return ucl_object_emit_len (obj, emit_type, NULL); +} + +unsigned char * +ucl_object_emit_len (const ucl_object_t *obj, enum ucl_emitter emit_type, + size_t *outlen) +{ unsigned char *res = NULL; struct ucl_emitter_functions *func; + UT_string *s; + if (obj == NULL) { return NULL; } func = ucl_object_emit_memory_funcs ((void **)&res); + s = func->ud; if (func != NULL) { ucl_object_emit_full (obj, emit_type, func); + + if (outlen != NULL) { + *outlen = s->i; + } + ucl_object_emit_funcs_free (func); } diff --git a/contrib/libucl/ucl_emitter_utils.c b/contrib/libucl/ucl_emitter_utils.c index 91cad78bc..95ac9a5d5 100644 --- a/contrib/libucl/ucl_emitter_utils.c +++ b/contrib/libucl/ucl_emitter_utils.c @@ -62,6 +62,12 @@ static const struct ucl_emitter_context ucl_standard_emitters[] = { .id = UCL_EMIT_YAML, .func = NULL, .ops = &ucl_standartd_emitter_ops[UCL_EMIT_YAML] + }, + [UCL_EMIT_MSGPACK] = { + .name = "msgpack", + .id = UCL_EMIT_MSGPACK, + .func = NULL, + .ops = &ucl_standartd_emitter_ops[UCL_EMIT_MSGPACK] } }; @@ -73,7 +79,7 @@ static const struct ucl_emitter_context ucl_standard_emitters[] = { const struct ucl_emitter_context * ucl_emit_get_standard_context (enum ucl_emitter emit_type) { - if (emit_type >= UCL_EMIT_JSON && emit_type <= UCL_EMIT_YAML) { + if (emit_type >= UCL_EMIT_JSON && emit_type < UCL_EMIT_MAX) { return &ucl_standard_emitters[emit_type]; } diff --git a/contrib/libucl/ucl_hash.c b/contrib/libucl/ucl_hash.c index 4730b82b8..183eac84f 100644 --- a/contrib/libucl/ucl_hash.c +++ b/contrib/libucl/ucl_hash.c @@ -371,6 +371,11 @@ ucl_hash_iterate (ucl_hash_t *hashlin, ucl_hash_iter_t *iter) if (it == NULL) { it = UCL_ALLOC (sizeof (*it)); + + if (it == NULL) { + return NULL; + } + it->cur = &hashlin->ar.a[0]; it->end = it->cur + hashlin->ar.n; } diff --git a/contrib/libucl/ucl_internal.h b/contrib/libucl/ucl_internal.h index 836fcad80..fe926dbaa 100644 --- a/contrib/libucl/ucl_internal.h +++ b/contrib/libucl/ucl_internal.h @@ -192,9 +192,11 @@ struct ucl_parser { unsigned int recursion; int flags; unsigned default_priority; + int err_code; ucl_object_t *top_obj; ucl_object_t *cur_obj; ucl_object_t *trash_objs; + ucl_object_t *includepaths; char *cur_file; struct ucl_macro *macroes; struct ucl_stack *stack; @@ -222,13 +224,21 @@ size_t ucl_unescape_json_string (char *str, size_t len); * Handle include macro * @param data include data * @param len length of data + * @param args UCL object representing arguments to the macro * @param ud user data - * @param err error ptr * @return */ bool ucl_include_handler (const unsigned char *data, size_t len, const ucl_object_t *args, void* ud); +/** + * Handle tryinclude macro + * @param data include data + * @param len length of data + * @param args UCL object representing arguments to the macro + * @param ud user data + * @return + */ bool ucl_try_include_handler (const unsigned char *data, size_t len, const ucl_object_t *args, void* ud); @@ -236,17 +246,41 @@ bool ucl_try_include_handler (const unsigned char *data, size_t len, * Handle includes macro * @param data include data * @param len length of data + * @param args UCL object representing arguments to the macro * @param ud user data - * @param err error ptr * @return */ bool ucl_includes_handler (const unsigned char *data, size_t len, const ucl_object_t *args, void* ud); +/** + * Handle priority macro + * @param data include data + * @param len length of data + * @param args UCL object representing arguments to the macro + * @param ud user data + * @return + */ +bool ucl_priority_handler (const unsigned char *data, size_t len, + const ucl_object_t *args, void* ud); + +/** + * Handle load macro + * @param data include data + * @param len length of data + * @param args UCL object representing arguments to the macro + * @param ud user data + * @return + */ +bool ucl_load_handler (const unsigned char *data, size_t len, + const ucl_object_t *args, 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); size_t ucl_strlcpy_tolower (char *dst, const char *src, size_t siz); +char *ucl_strnstr (const char *s, const char *find, int len); +char *ucl_strncasestr (const char *s, const char *find, int len); #ifdef __GNUC__ static inline void @@ -398,4 +432,64 @@ unsigned char * ucl_object_emit_single_json (const ucl_object_t *obj); */ bool ucl_maybe_long_string (const ucl_object_t *obj); +/** + * Print integer to the msgpack output + * @param ctx + * @param val + */ +void ucl_emitter_print_int_msgpack (struct ucl_emitter_context *ctx, + int64_t val); +/** + * Print integer to the msgpack output + * @param ctx + * @param val + */ +void ucl_emitter_print_double_msgpack (struct ucl_emitter_context *ctx, + double val); +/** + * Print double to the msgpack output + * @param ctx + * @param val + */ +void ucl_emitter_print_bool_msgpack (struct ucl_emitter_context *ctx, + bool val); +/** + * Print string to the msgpack output + * @param ctx + * @param s + * @param len + */ +void ucl_emitter_print_string_msgpack (struct ucl_emitter_context *ctx, + const char *s, size_t len); + +/** + * Print array preamble for msgpack + * @param ctx + * @param len + */ +void ucl_emitter_print_array_msgpack (struct ucl_emitter_context *ctx, + size_t len); + +/** + * Print object preamble for msgpack + * @param ctx + * @param len + */ +void ucl_emitter_print_object_msgpack (struct ucl_emitter_context *ctx, + size_t len); +/** + * Print NULL to the msgpack output + * @param ctx + */ +void ucl_emitter_print_null_msgpack (struct ucl_emitter_context *ctx); +/** + * Print object's key if needed to the msgpakc output + * @param print_key + * @param ctx + * @param obj + */ +void ucl_emitter_print_key_msgpack (bool print_key, + struct ucl_emitter_context *ctx, + const ucl_object_t *obj); + #endif /* UCL_INTERNAL_H_ */ diff --git a/contrib/libucl/ucl_parser.c b/contrib/libucl/ucl_parser.c index 804744972..8f177938c 100644 --- a/contrib/libucl/ucl_parser.c +++ b/contrib/libucl/ucl_parser.c @@ -67,6 +67,7 @@ ucl_set_err (struct ucl_parser *parser, int code, const char *str, UT_string **e else { filename = "<unknown>"; } + if (chunk->pos < chunk->end) { if (isgraph (*chunk->pos)) { fmt_string = "error while parsing %s: " @@ -84,6 +85,8 @@ ucl_set_err (struct ucl_parser *parser, int code, const char *str, UT_string **e ucl_create_err (err, "error while parsing %s: at the end of chunk: %s", filename, str); } + + parser->err_code = code; } /** @@ -513,7 +516,7 @@ ucl_copy_or_store_ptr (struct ucl_parser *parser, /* Copy string */ *dst = UCL_ALLOC (in_len + 1); if (*dst == NULL) { - ucl_set_err (parser, 0, "cannot allocate memory for a string", + ucl_set_err (parser, UCL_EINTERNAL, "cannot allocate memory for a string", &parser->err); return false; } @@ -585,7 +588,7 @@ ucl_add_parser_stack (ucl_object_t *obj, struct ucl_parser *parser, bool is_arra st = UCL_ALLOC (sizeof (struct ucl_stack)); if (st == NULL) { - ucl_set_err (parser, 0, "cannot allocate memory for an object", + ucl_set_err (parser, UCL_EINTERNAL, "cannot allocate memory for an object", &parser->err); ucl_object_unref (obj); return NULL; @@ -858,6 +861,7 @@ set_obj: * Parse possible number * @param parser * @param chunk + * @param obj * @return true if a number has been parsed */ static bool @@ -877,7 +881,8 @@ ucl_lex_number (struct ucl_parser *parser, return true; } else if (ret == ERANGE) { - ucl_set_err (parser, ERANGE, "numeric value out of range", &parser->err); + ucl_set_err (parser, UCL_ESYNTAX, "numeric value out of range", + &parser->err); } return false; @@ -887,6 +892,9 @@ ucl_lex_number (struct ucl_parser *parser, * Parse quoted string with possible escapes * @param parser * @param chunk + * @param need_unescape + * @param ucl_escape + * @param var_expand * @return true if a string has been parsed */ static bool @@ -973,6 +981,7 @@ ucl_parser_append_elt (struct ucl_parser *parser, ucl_hash_t *cont, /* Implicit array */ top->flags |= UCL_OBJECT_MULTIVALUE; DL_APPEND (top, elt); + parser->stack->obj->len ++; } else { if ((top->flags & UCL_OBJECT_MULTIVALUE) != 0) { @@ -996,6 +1005,8 @@ ucl_parser_append_elt (struct ucl_parser *parser, ucl_hash_t *cont, * Parse a key in an object * @param parser * @param chunk + * @param next_key + * @param end_of_object * @return true if a key has been parsed */ static bool @@ -1246,6 +1257,8 @@ ucl_parse_key (struct ucl_parser *parser, struct ucl_chunk *chunk, * Parse a cl string * @param parser * @param chunk + * @param var_expand + * @param need_unescape * @return true if a key has been parsed */ static bool @@ -1315,6 +1328,8 @@ ucl_parse_string_value (struct ucl_parser *parser, * @param chunk * @param term * @param term_len + * @param beg + * @param var_expand * @return size of multiline string or 0 in case of error */ static int @@ -1505,6 +1520,7 @@ ucl_parse_value (struct ucl_parser *parser, struct ucl_chunk *chunk) } obj->type = UCL_STRING; + obj->flags |= UCL_OBJECT_MULTILINE; if ((str_len = ucl_copy_or_store_ptr (parser, c, &obj->trash_stack[UCL_TRASH_VALUE], &obj->value.sv, str_len - 1, false, @@ -1552,7 +1568,7 @@ parse_string: } str_len = chunk->pos - c - stripped_spaces; if (str_len <= 0) { - ucl_set_err (parser, 0, "string value must not be empty", + ucl_set_err (parser, UCL_ESYNTAX, "string value must not be empty", &parser->err); return false; } @@ -1675,6 +1691,9 @@ ucl_parse_after_value (struct ucl_parser *parser, struct ucl_chunk *chunk) * Handle macro data * @param parser * @param chunk + * @param marco + * @param macro_start + * @param macro_len * @return */ static bool @@ -1813,6 +1832,7 @@ ucl_parse_macro_arguments (struct ucl_parser *parser, if (chunk->remain == 0) { goto restore_chunk; } + args_len ++; ucl_chunk_skipc (chunk, p); break; case 99: @@ -1865,8 +1885,6 @@ restore_chunk: /** * Handle the main states of rcl parser * @param parser parser structure - * @param data the pointer to the beginning of a chunk - * @param len the length of a chunk * @return true if chunk has been parsed and false in case of error */ static bool @@ -2096,8 +2114,11 @@ ucl_parser_new (int flags) 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); new->flags = flags; + new->includepaths = NULL; /* Initial assumption about filevars */ ucl_parser_set_filevars (new, NULL, false); @@ -2258,8 +2279,8 @@ ucl_parser_add_chunk (struct ucl_parser *parser, const unsigned char *data, } bool -ucl_parser_add_string (struct ucl_parser *parser, const char *data, - size_t len) +ucl_parser_add_string_priority (struct ucl_parser *parser, const char *data, + size_t len, unsigned priority) { if (data == NULL) { ucl_create_err (&parser->err, "invalid string added"); @@ -2269,5 +2290,40 @@ ucl_parser_add_string (struct ucl_parser *parser, const char *data, len = strlen (data); } - return ucl_parser_add_chunk (parser, (const unsigned char *)data, len); + return ucl_parser_add_chunk_priority (parser, + (const unsigned char *)data, len, priority); +} + +bool +ucl_parser_add_string (struct ucl_parser *parser, const char *data, + size_t len) +{ + if (parser == NULL) { + return false; + } + + return ucl_parser_add_string_priority (parser, + (const unsigned char *)data, len, parser->default_priority); +} + +bool +ucl_set_include_path (struct ucl_parser *parser, ucl_object_t *paths) +{ + if (parser == NULL || paths == NULL) { + return false; + } + + if (parser->includepaths == NULL) { + parser->includepaths = ucl_object_copy (paths); + } + else { + ucl_object_unref (parser->includepaths); + parser->includepaths = ucl_object_copy (paths); + } + + if (parser->includepaths == NULL) { + return false; + } + + return true; } diff --git a/contrib/libucl/ucl_util.c b/contrib/libucl/ucl_util.c index c8ea06c26..bdac1d214 100644 --- a/contrib/libucl/ucl_util.c +++ b/contrib/libucl/ucl_util.c @@ -1,4 +1,5 @@ /* Copyright (c) 2013, Vsevolod Stakhov + * Copyright (c) 2015 Allan Jude <allanjude@freebsd.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -25,6 +26,7 @@ #include "ucl_internal.h" #include "ucl_chartable.h" #include "kvec.h" +#include <stdarg.h> #ifndef _WIN32 #include <glob.h> @@ -425,7 +427,7 @@ ucl_copy_value_trash (const ucl_object_t *obj) return obj->trash_stack[UCL_TRASH_VALUE]; } -UCL_EXTERN ucl_object_t* +ucl_object_t* ucl_parser_get_object (struct ucl_parser *parser) { if (parser->state != UCL_STATE_ERROR && parser->top_obj != NULL) { @@ -435,7 +437,7 @@ ucl_parser_get_object (struct ucl_parser *parser) return NULL; } -UCL_EXTERN void +void ucl_parser_free (struct ucl_parser *parser) { struct ucl_stack *stack, *stmp; @@ -453,6 +455,10 @@ ucl_parser_free (struct ucl_parser *parser) ucl_object_unref (parser->top_obj); } + if (parser->includepaths != NULL) { + ucl_object_unref (parser->includepaths); + } + LL_FOREACH_SAFE (parser->stack, stack, stmp) { free (stack); } @@ -487,29 +493,61 @@ ucl_parser_free (struct ucl_parser *parser) UCL_FREE (sizeof (struct ucl_parser), parser); } -UCL_EXTERN const char * +const char * ucl_parser_get_error(struct ucl_parser *parser) { if (parser == NULL) { return NULL; } - if (parser->err == NULL) + if (parser->err == NULL) { return NULL; + } return utstring_body (parser->err); } -UCL_EXTERN void +int +ucl_parser_get_error_code(struct ucl_parser *parser) +{ + if (parser == NULL) { + return 0; + } + + return parser->err_code; +} + +unsigned +ucl_parser_get_column(struct ucl_parser *parser) +{ + if (parser == NULL || parser->chunks == NULL) { + return 0; + } + + return parser->chunks->column; +} + +unsigned +ucl_parser_get_linenum(struct ucl_parser *parser) +{ + if (parser == NULL || parser->chunks == NULL) { + return 0; + } + + return parser->chunks->line; +} + +void ucl_parser_clear_error(struct ucl_parser *parser) { if (parser != NULL && parser->err != NULL) { utstring_free(parser->err); parser->err = NULL; + parser->err_code = 0; } } -UCL_EXTERN bool +bool ucl_pubkey_add (struct ucl_parser *parser, const unsigned char *key, size_t len) { #ifndef HAVE_OPENSSL @@ -769,7 +807,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, bool must_exist, - unsigned priority) + bool use_prefix, const char *prefix, const char *target, unsigned priority) { bool res; @@ -842,20 +880,27 @@ ucl_include_url (const unsigned char *data, size_t len, static bool ucl_include_file_single (const unsigned char *data, size_t len, struct ucl_parser *parser, bool check_signature, bool must_exist, - unsigned priority) + bool use_prefix, const char *prefix, const char *target, + bool soft_fail, unsigned priority) { bool res; struct ucl_chunk *chunk; unsigned char *buf = NULL; - char *old_curfile; - size_t buflen; + char *old_curfile, *ext; + size_t buflen = 0; char filebuf[PATH_MAX], realbuf[PATH_MAX]; int prev_state; struct ucl_variable *cur_var, *tmp_var, *old_curdir = NULL, *old_filename = NULL; + ucl_object_t *nest_obj = NULL, *old_obj = NULL, *new_obj = NULL; + ucl_hash_t *container = NULL; + struct ucl_stack *st = NULL; snprintf (filebuf, sizeof (filebuf), "%.*s", (int)len, data); if (ucl_realpath (filebuf, realbuf) == NULL) { + if (soft_fail) { + return false; + } if (!must_exist) { return true; } @@ -867,12 +912,18 @@ ucl_include_file_single (const unsigned char *data, size_t len, if (parser->cur_file && strcmp (realbuf, parser->cur_file) == 0) { /* We are likely including the file itself */ + if (soft_fail) { + return false; + } ucl_create_err (&parser->err, "trying to include the file %s from itself", realbuf); return false; } if (!ucl_fetch_file (realbuf, &buf, &buflen, &parser->err, must_exist)) { + if (soft_fail) { + return false; + } return (!must_exist || false); } @@ -920,6 +971,111 @@ ucl_include_file_single (const unsigned char *data, size_t len, prev_state = parser->state; parser->state = UCL_STATE_INIT; + if (use_prefix && prefix == NULL) { + /* Auto generate a key name based on the included filename */ + prefix = basename (realbuf); + ext = strrchr(prefix, '.'); + if (ext != NULL && (strcmp (ext, ".conf") == 0 || strcmp (ext, ".ucl") == 0)) { + /* Strip off .conf or .ucl */ + *ext = '\0'; + } + } + if (prefix != NULL) { + /* This is a prefixed include */ + container = parser->stack->obj->value.ov; + + old_obj = __DECONST (ucl_object_t *, ucl_hash_search (container, prefix, strlen (prefix))); + + if (strcasecmp (target, "array") == 0 && old_obj == NULL) { + /* Create an array with key: prefix */ + old_obj = ucl_object_new_full (UCL_ARRAY, priority); + old_obj->key = prefix; + old_obj->keylen = strlen (prefix); + ucl_copy_key_trash(old_obj); + old_obj->prev = old_obj; + old_obj->next = NULL; + + container = ucl_hash_insert_object (container, old_obj, + parser->flags & UCL_PARSER_KEY_LOWERCASE); + parser->stack->obj->len ++; + + nest_obj = ucl_object_new_full (UCL_OBJECT, priority); + nest_obj->prev = nest_obj; + nest_obj->next = NULL; + + ucl_array_append (old_obj, nest_obj); + } + else if (old_obj == NULL) { + /* Create an object with key: prefix */ + nest_obj = ucl_object_new_full (UCL_OBJECT, priority); + nest_obj->key = prefix; + nest_obj->keylen = strlen (prefix); + ucl_copy_key_trash(nest_obj); + nest_obj->prev = nest_obj; + nest_obj->next = NULL; + + container = ucl_hash_insert_object (container, nest_obj, + parser->flags & UCL_PARSER_KEY_LOWERCASE); + parser->stack->obj->len ++; + } + else if (strcasecmp (target, "array") == 0 || ucl_object_type(old_obj) == UCL_ARRAY) { + if (ucl_object_type(old_obj) == UCL_ARRAY) { + /* Append to the existing array */ + nest_obj = ucl_object_new_full (UCL_OBJECT, priority); + nest_obj->prev = nest_obj; + nest_obj->next = NULL; + + ucl_array_append (old_obj, nest_obj); + } + else { + /* Convert the object to an array */ + new_obj = ucl_object_typed_new (UCL_ARRAY); + new_obj->key = old_obj->key; + new_obj->keylen = old_obj->keylen; + new_obj->flags |= UCL_OBJECT_MULTIVALUE; + new_obj->prev = new_obj; + new_obj->next = NULL; + + nest_obj = ucl_object_new_full (UCL_OBJECT, priority); + nest_obj->prev = nest_obj; + nest_obj->next = NULL; + + ucl_array_append (new_obj, old_obj); + ucl_array_append (new_obj, nest_obj); + ucl_hash_replace (container, old_obj, new_obj); + } + } + else { + if (ucl_object_type (old_obj) == UCL_OBJECT) { + /* Append to existing Object*/ + nest_obj = old_obj; + } + else { + /* The key is not an object */ + ucl_create_err (&parser->err, + "Conflicting type for key: %s", + prefix); + return false; + } + } + + /* Put all of the content of the include inside that object */ + parser->stack->obj->value.ov = container; + + if (nest_obj != NULL) { + st = UCL_ALLOC (sizeof (struct ucl_stack)); + if (st == NULL) { + ucl_create_err (&parser->err, "cannot allocate memory for an object"); + ucl_object_unref (nest_obj); + return NULL; + } + st->obj = nest_obj; + st->level = parser->stack->level; + LL_PREPEND (parser->stack, st); + parser->cur_obj = nest_obj; + } + } + res = ucl_parser_add_chunk_priority (parser, buf, buflen, priority); if (!res && !must_exist) { /* Free error */ @@ -928,6 +1084,12 @@ ucl_include_file_single (const unsigned char *data, size_t len, parser->state = UCL_STATE_AFTER_VALUE; } + /* Stop nesting the include, take 1 level off the stack */ + if (prefix != NULL && nest_obj != NULL) { + parser->stack = st->next; + UCL_FREE (sizeof (struct ucl_stack), st); + } + /* Remove chunk from the stack */ chunk = parser->chunks; if (chunk != NULL) { @@ -983,7 +1145,8 @@ ucl_include_file_single (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, bool must_exist, - bool allow_glob, unsigned priority) + bool allow_glob, bool use_prefix, const char *prefix, + const char *target, bool soft_fail, unsigned priority) { const unsigned char *p = data, *end = data + len; bool need_glob = false; @@ -994,7 +1157,7 @@ ucl_include_file (const unsigned char *data, size_t len, #ifndef _WIN32 if (!allow_glob) { return ucl_include_file_single (data, len, parser, check_signature, - must_exist, priority); + must_exist, use_prefix, prefix, target, soft_fail, priority); } else { /* Check for special symbols in a filename */ @@ -1008,14 +1171,18 @@ ucl_include_file (const unsigned char *data, size_t len, if (need_glob) { glob_t globbuf; memset (&globbuf, 0, sizeof (globbuf)); - ucl_strlcpy (glob_pattern, (const char *)data, sizeof (glob_pattern)); + ucl_strlcpy (glob_pattern, (const char *)data, + (len + 1 < sizeof (glob_pattern) ? len + 1 : sizeof (glob_pattern))); if (glob (glob_pattern, 0, NULL, &globbuf) != 0) { return (!must_exist || false); } for (i = 0; i < globbuf.gl_pathc; i ++) { if (!ucl_include_file_single ((unsigned char *)globbuf.gl_pathv[i], strlen (globbuf.gl_pathv[i]), parser, check_signature, - must_exist, priority)) { + must_exist, use_prefix, prefix, target, soft_fail, priority)) { + if (soft_fail) { + continue; + } globfree (&globbuf); return false; } @@ -1031,14 +1198,14 @@ ucl_include_file (const unsigned char *data, size_t len, } else { return ucl_include_file_single (data, len, parser, check_signature, - must_exist, priority); + must_exist, use_prefix, prefix, target, soft_fail, priority); } } #else /* Win32 compilers do not support globbing. Therefore, for Win32, treat allow_glob/need_glob as a NOOP and just return */ return ucl_include_file_single (data, len, parser, check_signature, - must_exist, priority); + must_exist, use_prefix, prefix, target, soft_fail, priority); #endif return true; @@ -1060,52 +1227,107 @@ ucl_include_common (const unsigned char *data, size_t len, bool default_try, bool default_sign) { - bool try_load, allow_glob, allow_url, need_sign; + bool try_load, allow_glob, allow_url, need_sign, use_prefix, search; + const char *prefix, *target; unsigned priority; const ucl_object_t *param; - ucl_object_iter_t it = NULL; + ucl_object_iter_t it = NULL, ip = NULL; + char ipath[PATH_MAX]; /* Default values */ try_load = default_try; allow_glob = false; allow_url = true; need_sign = default_sign; + use_prefix = false; + prefix = NULL; + target = "object"; priority = 0; + search = false; /* Process arguments */ if (args != NULL && args->type == UCL_OBJECT) { while ((param = ucl_iterate_object (args, &it, true)) != NULL) { if (param->type == UCL_BOOLEAN) { - if (strcmp (param->key, "try") == 0) { + if (strncmp (param->key, "try", param->keylen) == 0) { try_load = ucl_object_toboolean (param); } - else if (strcmp (param->key, "sign") == 0) { + else if (strncmp (param->key, "sign", param->keylen) == 0) { need_sign = ucl_object_toboolean (param); } - else if (strcmp (param->key, "glob") == 0) { - allow_glob = ucl_object_toboolean (param); + else if (strncmp (param->key, "glob", param->keylen) == 0) { + allow_glob = ucl_object_toboolean (param); + } + else if (strncmp (param->key, "url", param->keylen) == 0) { + allow_url = ucl_object_toboolean (param); } - else if (strcmp (param->key, "url") == 0) { - allow_url = ucl_object_toboolean (param); + else if (strncmp (param->key, "prefix", param->keylen) == 0) { + use_prefix = ucl_object_toboolean (param); + } + } + else if (param->type == UCL_STRING) { + if (strncmp (param->key, "key", param->keylen) == 0) { + prefix = ucl_object_tostring (param); + } + else if (strncmp (param->key, "target", param->keylen) == 0) { + target = ucl_object_tostring (param); + } + } + else if (param->type == UCL_ARRAY) { + if (strncmp (param->key, "path", param->keylen) == 0) { + ucl_set_include_path (parser, __DECONST(ucl_object_t *, param)); } } else if (param->type == UCL_INT) { - if (strcmp (param->key, "priority") == 0) { + if (strncmp (param->key, "priority", param->keylen) == 0) { priority = ucl_object_toint (param); } } } } - if (*data == '/' || *data == '.') { - /* Try to load a file */ - return ucl_include_file (data, len, parser, need_sign, !try_load, - allow_glob, priority); + if (parser->includepaths == NULL) { + if (allow_url && ucl_strnstr (data, "://", len) != NULL) { + /* Globbing is not used for URL's */ + return ucl_include_url (data, len, parser, need_sign, + !try_load, use_prefix, prefix, target, priority); + } + else if (data != NULL) { + /* Try to load a file */ + return ucl_include_file (data, len, parser, need_sign, !try_load, + allow_glob, use_prefix, prefix, target, false, priority); + } } - else if (allow_url) { - /* Globbing is not used for URL's */ - return ucl_include_url (data, len, parser, need_sign, !try_load, - priority); + else { + if (allow_url && ucl_strnstr (data, "://", len) != NULL) { + /* Globbing is not used for URL's */ + return ucl_include_url (data, len, parser, need_sign, + !try_load, use_prefix, prefix, target, priority); + } + + ip = ucl_object_iterate_new (parser->includepaths); + while ((param = ucl_object_iterate_safe (ip, true)) != NULL) { + if (ucl_object_type(param) == UCL_STRING) { + snprintf (ipath, sizeof (ipath), "%s/%.*s", ucl_object_tostring(param), + (int)len, data); + if ((search = ucl_include_file (ipath, strlen (ipath), parser, need_sign, + !try_load, allow_glob, use_prefix, prefix, target, true, priority))) { + if (!allow_glob) { + break; + } + } + } + } + ucl_object_iterate_free (ip); + if (search == true) { + return true; + } + else { + ucl_create_err (&parser->err, + "cannot find file: %.*s in search path", + (int)len, data); + return false; + } } return false; @@ -1115,11 +1337,11 @@ ucl_include_common (const unsigned char *data, size_t len, * Handle include macro * @param data include data * @param len length of data + * @param args UCL object representing arguments to the macro * @param ud user data - * @param err error ptr * @return */ -UCL_EXTERN bool +bool ucl_include_handler (const unsigned char *data, size_t len, const ucl_object_t *args, void* ud) { @@ -1132,11 +1354,11 @@ ucl_include_handler (const unsigned char *data, size_t len, * Handle includes macro * @param data include data * @param len length of data + * @param args UCL object representing arguments to the macro * @param ud user data - * @param err error ptr * @return */ -UCL_EXTERN bool +bool ucl_includes_handler (const unsigned char *data, size_t len, const ucl_object_t *args, void* ud) { @@ -1145,8 +1367,15 @@ ucl_includes_handler (const unsigned char *data, size_t len, return ucl_include_common (data, len, args, parser, false, true); } - -UCL_EXTERN bool +/** + * Handle tryinclude macro + * @param data include data + * @param len length of data + * @param args UCL object representing arguments to the macro + * @param ud user data + * @return + */ +bool ucl_try_include_handler (const unsigned char *data, size_t len, const ucl_object_t *args, void* ud) { @@ -1155,7 +1384,201 @@ ucl_try_include_handler (const unsigned char *data, size_t len, return ucl_include_common (data, len, args, parser, true, false); } -UCL_EXTERN bool +/** + * Handle priority macro + * @param data include data + * @param len length of data + * @param args UCL object representing arguments to the macro + * @param ud user data + * @return + */ +bool +ucl_priority_handler (const unsigned char *data, size_t len, + const ucl_object_t *args, void* ud) +{ + struct ucl_parser *parser = ud; + unsigned priority = 255; + const ucl_object_t *param; + bool found = false; + char *value = NULL, *leftover = NULL; + ucl_object_iter_t it = NULL; + + if (parser == NULL) { + return false; + } + + /* Process arguments */ + if (args != NULL && args->type == UCL_OBJECT) { + while ((param = ucl_iterate_object (args, &it, true)) != NULL) { + if (param->type == UCL_INT) { + if (strncmp (param->key, "priority", param->keylen) == 0) { + priority = ucl_object_toint (param); + found = true; + } + } + } + } + + if (len > 0) { + value = malloc(len + 1); + ucl_strlcpy(value, (const char *)data, len + 1); + priority = strtol(value, &leftover, 10); + if (*leftover != '\0') { + ucl_create_err (&parser->err, "Invalid priority value in macro: %s", + value); + free(value); + return false; + } + free(value); + found = true; + } + + if (found == true) { + parser->chunks->priority = priority; + return true; + } + + ucl_create_err (&parser->err, "Unable to parse priority macro"); + return false; +} + +/** + * Handle load macro + * @param data include data + * @param len length of data + * @param args UCL object representing arguments to the macro + * @param ud user data + * @return + */ +bool +ucl_load_handler (const unsigned char *data, size_t len, + const ucl_object_t *args, void* ud) +{ + struct ucl_parser *parser = ud; + const ucl_object_t *param; + ucl_object_t *obj, *old_obj; + ucl_object_iter_t it = NULL; + bool try_load, multiline, test; + const char *target, *prefix; + char *load_file, *tmp; + unsigned char *buf; + size_t buflen; + unsigned priority; + int64_t iv; + ucl_hash_t *container = NULL; + enum ucl_string_flags flags; + + /* Default values */ + try_load = false; + multiline = false; + test = false; + target = "string"; + prefix = NULL; + load_file = NULL; + buf = NULL; + buflen = 0; + priority = 0; + obj = NULL; + old_obj = NULL; + flags = 0; + + if (parser == NULL) { + return false; + } + + /* Process arguments */ + if (args != NULL && args->type == UCL_OBJECT) { + while ((param = ucl_iterate_object (args, &it, true)) != NULL) { + if (param->type == UCL_BOOLEAN) { + if (strncmp (param->key, "try", param->keylen) == 0) { + try_load = ucl_object_toboolean (param); + } + else if (strncmp (param->key, "multiline", param->keylen) == 0) { + multiline = ucl_object_toboolean (param); + } + else if (strncmp (param->key, "escape", param->keylen) == 0) { + test = ucl_object_toboolean (param); + if (test) { + flags |= UCL_STRING_ESCAPE; + } + } + else if (strncmp (param->key, "trim", param->keylen) == 0) { + test = ucl_object_toboolean (param); + if (test) { + flags |= UCL_STRING_TRIM; + } + } + } + else if (param->type == UCL_STRING) { + if (strncmp (param->key, "key", param->keylen) == 0) { + prefix = ucl_object_tostring (param); + } + else if (strncmp (param->key, "target", param->keylen) == 0) { + target = ucl_object_tostring (param); + } + } + else if (param->type == UCL_INT) { + if (strncmp (param->key, "priority", param->keylen) == 0) { + priority = ucl_object_toint (param); + } + } + } + } + + if (prefix == NULL || strlen(prefix) == 0) { + ucl_create_err (&parser->err, "No Key specified in load macro"); + return false; + } + + if (len > 0) { + asprintf (&load_file, "%.*s", (int)len, data); + if (!ucl_fetch_file (load_file, &buf, &buflen, &parser->err, !try_load)) { + return (try_load || false); + } + + container = parser->stack->obj->value.ov; + 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); + return false; + } + + if (strcasecmp (target, "string") == 0) { + obj = ucl_object_fromstring_common (buf, buflen, flags); + ucl_copy_value_trash (obj); + if (multiline) { + obj->flags |= UCL_OBJECT_MULTILINE; + } + } + else if (strcasecmp (target, "int") == 0) { + asprintf(&tmp, "%.*s", (int)buflen, buf); + iv = strtoll(tmp, NULL, 10); + obj = ucl_object_fromint(iv); + } + + if (buflen > 0) { + ucl_munmap (buf, buflen); + } + + if (obj != NULL) { + obj->key = prefix; + obj->keylen = strlen (prefix); + ucl_copy_key_trash(obj); + obj->prev = obj; + obj->next = NULL; + ucl_object_set_priority (obj, priority); + container = ucl_hash_insert_object (container, obj, + parser->flags & UCL_PARSER_KEY_LOWERCASE); + parser->stack->obj->value.ov = container; + } + return true; + } + + ucl_create_err (&parser->err, "Unable to parse load macro"); + return false; +} + +bool ucl_parser_set_filevars (struct ucl_parser *parser, const char *filename, bool need_expand) { char realbuf[PATH_MAX], *curdir; @@ -1185,8 +1608,9 @@ ucl_parser_set_filevars (struct ucl_parser *parser, const char *filename, bool n return true; } -UCL_EXTERN bool -ucl_parser_add_file (struct ucl_parser *parser, const char *filename) +bool +ucl_parser_add_file_priority (struct ucl_parser *parser, const char *filename, + unsigned priority) { unsigned char *buf; size_t len; @@ -1209,7 +1633,7 @@ ucl_parser_add_file (struct ucl_parser *parser, const char *filename) } parser->cur_file = strdup (realbuf); ucl_parser_set_filevars (parser, realbuf, false); - ret = ucl_parser_add_chunk (parser, buf, len); + ret = ucl_parser_add_chunk_priority (parser, buf, len, priority); if (len > 0) { ucl_munmap (buf, len); @@ -1218,8 +1642,20 @@ ucl_parser_add_file (struct ucl_parser *parser, const char *filename) return ret; } -UCL_EXTERN bool -ucl_parser_add_fd (struct ucl_parser *parser, int fd) +bool +ucl_parser_add_file (struct ucl_parser *parser, const char *filename) +{ + if (parser == NULL) { + return false; + } + + return ucl_parser_add_file_priority(parser, filename, + parser->default_priority); +} + +bool +ucl_parser_add_fd_priority (struct ucl_parser *parser, int fd, + unsigned priority) { unsigned char *buf; size_t len; @@ -1242,7 +1678,7 @@ ucl_parser_add_fd (struct ucl_parser *parser, int fd) } parser->cur_file = NULL; len = st.st_size; - ret = ucl_parser_add_chunk (parser, buf, len); + ret = ucl_parser_add_chunk_priority (parser, buf, len, priority); if (len > 0) { ucl_munmap (buf, len); @@ -1251,6 +1687,16 @@ ucl_parser_add_fd (struct ucl_parser *parser, int fd) return ret; } +bool +ucl_parser_add_fd (struct ucl_parser *parser, int fd) +{ + if (parser == NULL) { + return false; + } + + return ucl_parser_add_fd_priority(parser, fd, parser->default_priority); +} + size_t ucl_strlcpy (char *dst, const char *src, size_t siz) { @@ -1306,6 +1752,51 @@ ucl_strlcpy_tolower (char *dst, const char *src, size_t siz) return (s - src); /* count does not include NUL */ } +/* + * Find the first occurrence of find in s + */ +char * +ucl_strnstr (const char *s, const char *find, int len) +{ + char c, sc; + int mlen; + + if ((c = *find++) != 0) { + mlen = strlen (find); + do { + do { + if ((sc = *s++) == 0 || len-- == 0) + return (NULL); + } while (sc != c); + } while (strncmp (s, find, mlen) != 0); + s--; + } + return ((char *)s); +} + +/* + * Find the first occurrence of find in s, ignore case. + */ +char * +ucl_strncasestr (const char *s, const char *find, int len) +{ + char c, sc; + int mlen; + + if ((c = *find++) != 0) { + c = tolower (c); + mlen = strlen (find); + do { + do { + if ((sc = *s++) == 0 || len-- == 0) + return (NULL); + } while (tolower (sc) != c); + } while (strncasecmp (s, find, mlen) != 0); + s--; + } + return ((char *)s); +} + ucl_object_t * ucl_object_fromstring_common (const char *str, size_t len, enum ucl_string_flags flags) { @@ -1560,7 +2051,7 @@ ucl_object_delete_keyl (ucl_object_t *top, const char *key, size_t keylen) bool ucl_object_delete_key (ucl_object_t *top, const char *key) { - return ucl_object_delete_keyl (top, key, strlen(key)); + return ucl_object_delete_keyl (top, key, strlen (key)); } ucl_object_t* @@ -1585,7 +2076,7 @@ ucl_object_pop_keyl (ucl_object_t *top, const char *key, size_t keylen) ucl_object_t* ucl_object_pop_key (ucl_object_t *top, const char *key) { - return ucl_object_pop_keyl (top, key, strlen(key)); + return ucl_object_pop_keyl (top, key, strlen (key)); } bool @@ -1663,10 +2154,45 @@ ucl_object_find_keyl (const ucl_object_t *obj, const char *key, size_t klen) const ucl_object_t * ucl_object_find_key (const ucl_object_t *obj, const char *key) { - if (key == NULL) + if (key == NULL) { return NULL; + } - return ucl_object_find_keyl (obj, key, strlen(key)); + return ucl_object_find_keyl (obj, key, strlen (key)); +} + +const ucl_object_t* +ucl_object_find_any_key (const ucl_object_t *obj, + const char *key, ...) +{ + va_list ap; + const ucl_object_t *ret = NULL; + const char *nk = NULL; + + if (obj == NULL || key == NULL) { + return NULL; + } + + ret = ucl_object_find_keyl (obj, key, strlen (key)); + + if (ret == NULL) { + va_start (ap, key); + + while (ret == NULL) { + nk = va_arg (ap, const char *); + + if (nk == NULL) { + break; + } + else { + ret = ucl_object_find_keyl (obj, nk, strlen (nk)); + } + } + + va_end (ap); + } + + return ret; } const ucl_object_t* @@ -2012,6 +2538,11 @@ ucl_array_append (ucl_object_t *top, ucl_object_t *elt) if (vec == NULL) { vec = UCL_ALLOC (sizeof (*vec)); + + if (vec == NULL) { + return false; + } + kv_init (*vec); top->value.av = (void *)vec; } @@ -2052,14 +2583,23 @@ bool ucl_array_merge (ucl_object_t *top, ucl_object_t *elt, bool copy) { unsigned i; + ucl_object_t *cp = NULL; ucl_object_t **obj; - UCL_ARRAY_GET (v1, top); - UCL_ARRAY_GET (v2, elt); if (elt == NULL || top == NULL || top->type != UCL_ARRAY || elt->type != UCL_ARRAY) { return false; } + if (copy) { + cp = ucl_object_copy (elt); + } + else { + cp = ucl_object_ref (elt); + } + + UCL_ARRAY_GET (v1, top); + UCL_ARRAY_GET (v2, cp); + kv_concat (ucl_object_t *, *v1, *v2); for (i = v2->n; i < v1->n; i ++) { @@ -2067,14 +2607,7 @@ ucl_array_merge (ucl_object_t *top, ucl_object_t *elt, bool copy) if (*obj == NULL) { continue; } - top->len ++; - if (copy) { - *obj = ucl_object_copy (*obj); - } - else { - ucl_object_ref (*obj); - } } return true; @@ -2087,6 +2620,10 @@ ucl_array_delete (ucl_object_t *top, ucl_object_t *elt) ucl_object_t *ret = NULL; unsigned i; + if (vec == NULL) { + return NULL; + } + for (i = 0; i < vec->n; i ++) { if (kv_A (*vec, i) == elt) { kv_del (ucl_object_t *, *vec, i); @@ -2104,7 +2641,8 @@ ucl_array_head (const ucl_object_t *top) { UCL_ARRAY_GET (vec, top); - if (top == NULL || top->type != UCL_ARRAY || top->value.av == NULL) { + if (vec == NULL || top == NULL || top->type != UCL_ARRAY || + top->value.av == NULL) { return NULL; } @@ -2173,6 +2711,10 @@ ucl_array_index_of (ucl_object_t *top, ucl_object_t *elt) UCL_ARRAY_GET (vec, top); unsigned i; + if (vec == NULL) { + return (unsigned int)(-1); + } + for (i = 0; i < vec->n; i ++) { if (kv_A (*vec, i) == elt) { return i; @@ -2609,6 +3151,9 @@ ucl_object_set_priority (ucl_object_t *obj, { if (obj != NULL) { priority &= (0x1 << PRIOBITS) - 1; - obj->flags |= priority << ((sizeof (obj->flags) * NBBY) - PRIOBITS); + priority <<= ((sizeof (obj->flags) * NBBY) - PRIOBITS); + priority |= obj->flags & ((1 << ((sizeof (obj->flags) * NBBY) - + PRIOBITS)) - 1); + obj->flags = priority; } } |