From a3191bd7b34d3373d151827a6e6592ea82084747 Mon Sep 17 00:00:00 2001 From: Vsevolod Stakhov Date: Sat, 5 May 2018 14:58:37 +0100 Subject: [PATCH] [Feture] Allow external preprocessors in libucl --- contrib/libucl/ucl.h | 28 ++++++++++++++++++++++++++++ contrib/libucl/ucl_internal.h | 10 +++++++++- contrib/libucl/ucl_parser.c | 30 +++++++++++++++++++++++++++--- contrib/libucl/ucl_util.c | 32 +++++++++++++++++++++++++++++--- 4 files changed, 93 insertions(+), 7 deletions(-) diff --git a/contrib/libucl/ucl.h b/contrib/libucl/ucl.h index 812b89477..f0dbeca84 100644 --- a/contrib/libucl/ucl.h +++ b/contrib/libucl/ucl.h @@ -1278,6 +1278,34 @@ UCL_EXTERN bool ucl_parser_pubkey_add (struct ucl_parser *parser, UCL_EXTERN bool ucl_parser_set_filevars (struct ucl_parser *parser, const char *filename, bool need_expand); +/** + * Defines special handler for certain types of data (identified by magic) + */ +typedef bool (*ucl_parser_special_handler_t) (struct ucl_parser *parser, + const unsigned char *source, size_t source_len, + unsigned char **destination, size_t *dest_len, + void *user_data); + +/** + * Special handler structure + */ +struct ucl_parser_special_handler { + unsigned char *magic; + size_t magic_len; + ucl_parser_special_handler_t handler; + void (*free_function) (unsigned char *data, size_t len, void *user_data); + void *user_data; + struct ucl_parser_special_handler *next; /* Used internally */ +}; + +/** + * Add special handler for a parser + * @param parser parser structure + * @param handler handler structure + */ +UCL_EXTERN void ucl_parser_add_special_handler (struct ucl_parser *parser, + struct ucl_parser_special_handler *handler); + /** @} */ /** diff --git a/contrib/libucl/ucl_internal.h b/contrib/libucl/ucl_internal.h index d60581037..4ddc713b5 100644 --- a/contrib/libucl/ucl_internal.h +++ b/contrib/libucl/ucl_internal.h @@ -176,7 +176,7 @@ enum ucl_character_type { struct ucl_macro { char *name; - union { + union _ucl_macro { ucl_macro_handler handler; ucl_context_macro_handler context_handler; } h; @@ -201,6 +201,7 @@ struct ucl_chunk { unsigned priority; enum ucl_duplicate_strategy strategy; enum ucl_parse_type parse_type; + struct ucl_parser_special_handler *special_handler; struct ucl_chunk *next; }; @@ -239,6 +240,7 @@ struct ucl_parser { struct ucl_stack *stack; struct ucl_chunk *chunks; struct ucl_pubkey *keys; + struct ucl_parser_special_handler *special_handlers; struct ucl_variable *variables; ucl_variable_handler var_handler; void *var_data; @@ -619,4 +621,10 @@ bool ucl_parse_msgpack (struct ucl_parser *parser); bool ucl_parse_csexp (struct ucl_parser *parser); +/** + * Free ucl chunk + * @param chunk + */ +void ucl_chunk_free (struct ucl_chunk *chunk); + #endif /* UCL_INTERNAL_H_ */ diff --git a/contrib/libucl/ucl_parser.c b/contrib/libucl/ucl_parser.c index 339b93dff..631bc7412 100644 --- a/contrib/libucl/ucl_parser.c +++ b/contrib/libucl/ucl_parser.c @@ -2726,6 +2726,7 @@ ucl_parser_add_chunk_full (struct ucl_parser *parser, const unsigned char *data, enum ucl_parse_type parse_type) { struct ucl_chunk *chunk; + struct ucl_parser_special_handler *special_handler; if (parser == NULL) { return false; @@ -2743,6 +2744,28 @@ ucl_parser_add_chunk_full (struct ucl_parser *parser, const unsigned char *data, return false; } + memset (chunk, 0, sizeof (*chunk)); + + LL_FOREACH (parser->special_handlers, special_handler) { + if (len >= special_handler->magic_len && + memcmp (data, special_handler->magic, special_handler->magic_len) == 0) { + unsigned char *ndata = NULL; + size_t nlen = 0; + + if (!special_handler->handler (parser, data, len, &ndata, &nlen, + special_handler->user_data)) { + ucl_create_err (&parser->err, "call for external handler failed"); + return false; + } + + data = ndata; + len = nlen; + chunk->special_handler = special_handler; + + break; + } + } + if (parse_type == UCL_PARSE_AUTO && len > 0) { /* We need to detect parse type by the first symbol */ if ((*data & 0x80) == 0x80 && (*data >= 0xdc && *data <= 0xdf)) { @@ -2832,7 +2855,7 @@ ucl_parser_add_chunk (struct ucl_parser *parser, const unsigned char *data, bool ucl_parser_insert_chunk (struct ucl_parser *parser, const unsigned char *data, - size_t len) + size_t len) { if (parser == NULL || parser->top_obj == NULL) { return false; @@ -2854,7 +2877,7 @@ ucl_parser_insert_chunk (struct ucl_parser *parser, const unsigned char *data, chunk = parser->chunks; if (chunk != NULL) { parser->chunks = chunk->next; - UCL_FREE (sizeof (struct ucl_chunk), chunk); + ucl_chunk_free (chunk); parser->recursion --; } @@ -2936,7 +2959,8 @@ bool ucl_parser_chunk_skip (struct ucl_parser *parser) return false; } -ucl_object_t* ucl_parser_get_current_stack_object (struct ucl_parser *parser, unsigned int depth) +ucl_object_t* +ucl_parser_get_current_stack_object (struct ucl_parser *parser, unsigned int depth) { ucl_object_t *obj; diff --git a/contrib/libucl/ucl_util.c b/contrib/libucl/ucl_util.c index c6c07ba87..95878109b 100644 --- a/contrib/libucl/ucl_util.c +++ b/contrib/libucl/ucl_util.c @@ -516,6 +516,26 @@ ucl_copy_key_trash (const ucl_object_t *obj) return obj->trash_stack[UCL_TRASH_KEY]; } +void +ucl_chunk_free (struct ucl_chunk *chunk) +{ + if (chunk) { + if (chunk->special_handler) { + if (chunk->special_handler->free_function) { + chunk->special_handler->free_function ( + (unsigned char *) chunk->begin, + chunk->end - chunk->begin, + chunk->special_handler->user_data); + } else { + UCL_FREE (chunk->end - chunk->begin, + (unsigned char *) chunk->begin); + } + } + + UCL_FREE (sizeof (*chunk), chunk); + } +} + char * ucl_copy_value_trash (const ucl_object_t *obj) { @@ -601,7 +621,7 @@ ucl_parser_free (struct ucl_parser *parser) UCL_FREE (sizeof (struct ucl_macro), macro); } LL_FOREACH_SAFE (parser->chunks, chunk, ctmp) { - UCL_FREE (sizeof (struct ucl_chunk), chunk); + ucl_chunk_free (chunk); } LL_FOREACH_SAFE (parser->keys, key, ktmp) { UCL_FREE (sizeof (struct ucl_pubkey), key); @@ -718,6 +738,12 @@ ucl_pubkey_add (struct ucl_parser *parser, const unsigned char *key, size_t len) return true; } +void ucl_parser_add_special_handler (struct ucl_parser *parser, + struct ucl_parser_special_handler *handler) +{ + LL_APPEND (parser->special_handlers, handler); +} + #ifdef CURL_FOUND struct ucl_curl_cbdata { unsigned char *buf; @@ -1017,7 +1043,7 @@ ucl_include_url (const unsigned char *data, size_t len, chunk = parser->chunks; if (chunk != NULL) { parser->chunks = chunk->next; - UCL_FREE (sizeof (struct ucl_chunk), chunk); + ucl_chunk_free (chunk); } } @@ -1319,7 +1345,7 @@ ucl_include_file_single (const unsigned char *data, size_t len, chunk = parser->chunks; if (chunk != NULL) { parser->chunks = chunk->next; - UCL_FREE (sizeof (struct ucl_chunk), chunk); + ucl_chunk_free (chunk); parser->recursion --; } -- 2.39.5