From a17cfff9927ed129286be81c05990973139573d1 Mon Sep 17 00:00:00 2001 From: Vsevolod Stakhov Date: Thu, 10 Apr 2014 15:21:59 -0700 Subject: [PATCH] Use libucl as git submodule. --- .gitmodules | 3 + CMakeLists.txt | 5 +- config.h.in | 2 + src/CMakeLists.txt | 6 +- src/rdns | 2 +- src/smtp_proxy.c | 7 +- src/ucl | 1 + src/ucl/.gitignore | 3 - src/ucl/CMakeLists.txt | 26 - src/ucl/README.md | 236 ----- src/ucl/include/ucl.h | 912 ---------------- src/ucl/src/ucl_chartable.h | 267 ----- src/ucl/src/ucl_emitter.c | 829 --------------- src/ucl/src/ucl_hash.c | 120 --- src/ucl/src/ucl_hash.h | 91 -- src/ucl/src/ucl_internal.h | 292 ----- src/ucl/src/ucl_parser.c | 1869 --------------------------------- src/ucl/src/ucl_util.c | 1157 -------------------- src/ucl/tests/1.in | 11 - src/ucl/tests/1.res | 12 - src/ucl/tests/2.in | 18 - src/ucl/tests/2.res | 45 - src/ucl/tests/3.in | 31 - src/ucl/tests/3.res | 27 - src/ucl/tests/4.in | 47 - src/ucl/tests/4.res | 36 - src/ucl/tests/generate.res | 21 - src/ucl/tests/run_tests.sh | 57 - src/ucl/tests/test_basic.c | 113 -- src/ucl/tests/test_generate.c | 105 -- src/ucl/tests/test_speed.c | 127 --- src/ucl/utils/chargen.c | 128 --- src/ucl/utils/objdump.c | 157 --- 33 files changed, 21 insertions(+), 6742 deletions(-) create mode 160000 src/ucl delete mode 100644 src/ucl/.gitignore delete mode 100644 src/ucl/CMakeLists.txt delete mode 100644 src/ucl/README.md delete mode 100644 src/ucl/include/ucl.h delete mode 100644 src/ucl/src/ucl_chartable.h delete mode 100644 src/ucl/src/ucl_emitter.c delete mode 100644 src/ucl/src/ucl_hash.c delete mode 100644 src/ucl/src/ucl_hash.h delete mode 100644 src/ucl/src/ucl_internal.h delete mode 100644 src/ucl/src/ucl_parser.c delete mode 100644 src/ucl/src/ucl_util.c delete mode 100644 src/ucl/tests/1.in delete mode 100644 src/ucl/tests/1.res delete mode 100644 src/ucl/tests/2.in delete mode 100644 src/ucl/tests/2.res delete mode 100644 src/ucl/tests/3.in delete mode 100644 src/ucl/tests/3.res delete mode 100644 src/ucl/tests/4.in delete mode 100644 src/ucl/tests/4.res delete mode 100644 src/ucl/tests/generate.res delete mode 100755 src/ucl/tests/run_tests.sh delete mode 100644 src/ucl/tests/test_basic.c delete mode 100644 src/ucl/tests/test_generate.c delete mode 100644 src/ucl/tests/test_speed.c delete mode 100644 src/ucl/utils/chargen.c delete mode 100644 src/ucl/utils/objdump.c diff --git a/.gitmodules b/.gitmodules index 921583a78..b7bbb0be6 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,3 +4,6 @@ [submodule "interface"] path = interface url = git://github.com/vstakhov/rspamd-interface +[submodule "src/ucl"] + path = src/ucl + url = git@github.com:vstakhov/libucl diff --git a/CMakeLists.txt b/CMakeLists.txt index 48357714a..4a5eb0f9a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -723,6 +723,7 @@ CHECK_INCLUDE_FILES(poll.h HAVE_POLL_H) CHECK_INCLUDE_FILES(readpassphrase.h HAVE_READPASSPHRASE_H) CHECK_INCLUDE_FILES(termios.h HAVE_TERMIOS_H) CHECK_INCLUDE_FILES(paths.h HAVE_PATHS_H) +CHECK_INCLUDE_FILES(ctype.h HAVE_CTYPE_H) CHECK_INCLUDE_FILES(sys/sendfile.h HAVE_SYS_SENDFILE_H) CHECK_INCLUDE_FILES(linux/falloc.h HAVE_LINUX_FALLOC_H) CHECK_INCLUDE_FILES(sys/eventfd.h HAVE_SYS_EVENTFD_H) @@ -893,13 +894,15 @@ IF(NOT HIREDIS_FOUND) INCLUDE_DIRECTORIES("${CMAKE_CURRENT_SOURCE_DIR}/contrib/hiredis") ENDIF(NOT HIREDIS_FOUND) +ADD_DEFINITIONS(-DHAVE_CONFIG_H) + ADD_SUBDIRECTORY(contrib/xxhash) ADD_SUBDIRECTORY(contrib/http-parser) ADD_SUBDIRECTORY(contrib/libottery) ADD_SUBDIRECTORY(src/lua) ADD_SUBDIRECTORY(src/json) ADD_SUBDIRECTORY(src/cdb) -ADD_SUBDIRECTORY(src/ucl) +ADD_SUBDIRECTORY(src/ucl/cmake) ADD_SUBDIRECTORY(src) ADD_SUBDIRECTORY(src/client) diff --git a/config.h.in b/config.h.in index 2148ebd58..1598f51e1 100644 --- a/config.h.in +++ b/config.h.in @@ -209,6 +209,8 @@ #cmakedefine HAVE_IPV6_V6ONLY 1 +#cmakedefine HAVE_CTYPE_H 1 + #if (defined(__i386__) || defined(__x86_64__) || defined(_M_IX86)) /* Use murmur hash for UTHash for these platforms */ #define HASH_FUNCTION HASH_MUR diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b6a0731dd..c8eeed516 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -64,13 +64,17 @@ IF(CMAKE_COMPILER_IS_GNUCC) SET_TARGET_PROPERTIES(rspamd-util PROPERTIES COMPILE_FLAGS "-fno-strict-aliasing") ENDIF(CMAKE_COMPILER_IS_GNUCC) + TARGET_LINK_LIBRARIES(rspamd-util ${RSPAMD_REQUIRED_LIBRARIES}) TARGET_LINK_LIBRARIES(rspamd-util pcre) -TARGET_LINK_LIBRARIES(rspamd-util rspamd-ucl) +TARGET_LINK_LIBRARIES(rspamd-util ucl) TARGET_LINK_LIBRARIES(rspamd-util ottery) TARGET_LINK_LIBRARIES(rspamd-util rspamd-http-parser) TARGET_LINK_LIBRARIES(rspamd-util event) TARGET_LINK_LIBRARIES(rspamd-util xxhash) +IF(OPENSSL_FOUND) + TARGET_LINK_LIBRARIES(rspamd-util ${OPENSSL_LIBRARIES}) +ENDIF(OPENSSL_FOUND) IF(NOT DEBIAN_BUILD) SET_TARGET_PROPERTIES(rspamd-util PROPERTIES VERSION ${RSPAMD_VERSION}) diff --git a/src/rdns b/src/rdns index cc5f39ee1..b1762224e 160000 --- a/src/rdns +++ b/src/rdns @@ -1 +1 @@ -Subproject commit cc5f39ee1862df1e8bcd2a1bb65fa3fac538a420 +Subproject commit b1762224e9c8015abd195282ebd2f7728076e23d diff --git a/src/smtp_proxy.c b/src/smtp_proxy.c index eecc50048..4d4bcf593 100644 --- a/src/smtp_proxy.c +++ b/src/smtp_proxy.c @@ -485,16 +485,19 @@ smtp_dnsbl_cb (struct rdns_reply *reply, void *arg) struct smtp_proxy_session *session = arg; const gchar *p; gint dots = 0; + const struct rdns_request_name *req_name; session->rbl_requests --; - msg_debug ("got reply for %s: %s", rdns_request_get_name (reply->request), rdns_strerror (reply->code)); + req_name = rdns_request_get_name (reply->request, NULL); + + msg_debug ("got reply for %s: %s", req_name[0].name, rdns_strerror (reply->code)); if (session->state != SMTP_PROXY_STATE_REJECT) { if (reply->code == RDNS_RC_NOERROR) { /* This means that address is in dnsbl */ - p = rdns_request_get_name (reply->request); + p = req_name[0].name; while (*p) { if (*p == '.') { dots ++; diff --git a/src/ucl b/src/ucl new file mode 160000 index 000000000..8eb6d5601 --- /dev/null +++ b/src/ucl @@ -0,0 +1 @@ +Subproject commit 8eb6d5601a8eec27cffa84479281207f726482d3 diff --git a/src/ucl/.gitignore b/src/ucl/.gitignore deleted file mode 100644 index ea72388b3..000000000 --- a/src/ucl/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -.cproject -.project -.settings diff --git a/src/ucl/CMakeLists.txt b/src/ucl/CMakeLists.txt deleted file mode 100644 index e1df6890e..000000000 --- a/src/ucl/CMakeLists.txt +++ /dev/null @@ -1,26 +0,0 @@ -SET(UCLSRC src/ucl_util.c - src/ucl_parser.c - src/ucl_emitter.c - src/ucl_hash.c) - -ADD_LIBRARY(rspamd-ucl ${LINK_TYPE} ${UCLSRC}) -SET_TARGET_PROPERTIES(rspamd-ucl PROPERTIES VERSION ${RSPAMD_VERSION}) -SET_TARGET_PROPERTIES(rspamd-ucl PROPERTIES COMPILE_FLAGS "-DRSPAMD_LIB") - -TARGET_LINK_LIBRARIES(rspamd-ucl xxhash) -IF(HAVE_FETCH_H) - TARGET_LINK_LIBRARIES(rspamd-ucl fetch) -ELSE(HAVE_FETCH_H) - IF(CURL_FOUND) - TARGET_LINK_LIBRARIES(rspamd-ucl ${CURL_LIBRARIES}) - ENDIF(CURL_FOUND) -ENDIF(HAVE_FETCH_H) -IF(OPENSSL_FOUND) - TARGET_LINK_LIBRARIES(rspamd-ucl ${OPENSSL_LIBRARIES}) -ENDIF(OPENSSL_FOUND) -TARGET_LINK_LIBRARIES(rspamd-ucl ${GLIB2_LIBRARIES}) -IF(NO_SHARED MATCHES "OFF") - INSTALL(TARGETS rspamd-ucl - LIBRARY DESTINATION ${LIBDIR} - PUBLIC_HEADER DESTINATION ${INCLUDEDIR}) -ENDIF(NO_SHARED MATCHES "OFF") \ No newline at end of file diff --git a/src/ucl/README.md b/src/ucl/README.md deleted file mode 100644 index 18779a835..000000000 --- a/src/ucl/README.md +++ /dev/null @@ -1,236 +0,0 @@ -## Introduction - -This document describes the main features and principles of the configuration -language called `UCL` - universal configuration language. - -## Basic structure - -UCL is heavily infused by `nginx` configuration as the example of a convenient configuration -system. However, UCL is fully compatible with `JSON` format and is able to parse json files. -For example, you can write the same configuration in the following ways: - -* in nginx like: - -```nginx -param = value; -section { - param = value; - param1 = value1; - flag = true; - number = 10k; - time = 0.2s; - string = "something"; - subsection { - host = { - host = "hostname"; - port = 900; - } - host = { - host = "hostname"; - port = 901; - } - } -} -``` - -* or in JSON: - -```json -{ - "param": "value", - "param1": "value1", - "flag": true, - "subsection": { - "host": [ - { - "host": "hostname", - "port": 900 - }, - { - "host": "hostname", - "port": 901 - } - ] - } -} -``` - -## Improvements to the json notation. - -There are various things that make ucl configuration more convenient for editing than strict json: - -### General syntax sugar - -* Braces are not necessary to enclose a top object: it is automatically treated as an object: - -```json -"key": "value" -``` -is equal to: -```json -{"key": "value"} -``` - -* There is no requirement of quotes for strings and keys, moreover, `:` may be replaced `=` or even be skipped for objects: - -```nginx -key = value; -section { - key = value; -} -``` -is equal to: -```json -{ - "key": "value", - "section": { - "key": "value" - } -} -``` - -* No commas mess: you can safely place a comma or semicolon for the last element in an array or an object: - -```json -{ - "key1": "value", - "key2": "value", -} -``` -### Automatic arrays creation - -* Non-unique keys in an object are allowed and are automatically converted to the arrays internally: - -```json -{ - "key": "value1", - "key": "value2" -} -``` -is converted to: -```json -{ - "key": ["value1", "value2"] -} -``` - -### Convenient numbers and booleans - -* Numbers can have suffixes to specify standard multipliers: - + `[kKmMgG]` - standard 10 base multipliers (so `1k` is translated to 1000) - + `[kKmMgG]b` - 2 power multipliers (so `1kb` is translated to 1024) - + `[s|min|d|w|y]` - time multipliers, all time values are translated to float number of seconds, for example `10min` is translated to 600.0 and `10ms` is translated to 0.01 -* Booleans can be specified as `true` or `yes` or `on` and `false` or `no` or `off`. -* It is still possible to treat numbers and booleans as strings by enclosing them in double quotes. - -## General improvements - -### Commments - -UCL supports different style of comments: - -* single line: `#` -* multiline: `/* ... */` - -Multiline comments may be nested: -```c -# Sample single line comment -/* - some comment - /* nested comment */ - end of comment -*/ -``` - -### Macros support - -UCL supports external macros both multiline and single line ones: -```nginx -.macro "sometext"; -.macro { - Some long text - .... -}; -``` -There are two internal macros provided by UCL: - -* `include` - read a file `/path/to/file` or an url `http://example.com/file` and include it to the current place of -UCL configuration; -* `includes` - read a file or an url like the previous macro, but fetch and check the signature file (which is obtained -by `.sig` suffix appending). - -Public keys which are used for the last command are specified by the concrete UCL user. - -### Multiline strings - -UCL can handle multiline strings as well as single line ones. It uses shell/perl like notation for such objects: -``` -key = < -#include -#include -#include -#include -#include -#include -#include "config.h" - -/** - * @mainpage - * This is a reference manual for UCL API. You may find the description of UCL format by following this - * [github repository](https://github.com/vstakhov/libucl). - * - * This manual has several main sections: - * - @ref structures - * - @ref utils - * - @ref parser - * - @ref emitter - */ - -/** - * @file ucl.h - * @brief UCL parsing and emitting functions - * - * UCL is universal configuration language, which is a form of - * JSON with less strict rules that make it more comfortable for - * using as a configuration language - */ -#ifdef __cplusplus -extern "C" { -#endif -/* - * Memory allocation utilities - * UCL_ALLOC(size) - allocate memory for UCL - * UCL_FREE(size, ptr) - free memory of specified size at ptr - * Default: malloc and free - */ -#ifndef UCL_ALLOC -#define UCL_ALLOC(size) malloc(size) -#endif -#ifndef UCL_FREE -#define UCL_FREE(size, ptr) free(ptr) -#endif - -#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) -#define UCL_WARN_UNUSED_RESULT \ - __attribute__((warn_unused_result)) -#else -#define UCL_WARN_UNUSED_RESULT -#endif - -/** - * @defgroup structures Structures and types - * UCL defines several enumeration types used for error reporting or specifying flags and attributes. - * - * @{ - */ - -/** - * The common error codes returned by ucl parser - */ -typedef enum ucl_error { - UCL_EOK = 0, /**< No error */ - UCL_ESYNTAX, /**< Syntax error occurred during parsing */ - UCL_EIO, /**< IO error occurred during parsing */ - UCL_ESTATE, /**< Invalid state machine state */ - UCL_ENESTED, /**< Input has too many recursion levels */ - UCL_EMACRO, /**< Error processing a macro */ - UCL_EINTERNAL, /**< Internal unclassified error */ - UCL_ESSL /**< SSL error */ -} ucl_error_t; - -/** - * #ucl_object_t may have one of specified types, some types are compatible with each other and some are not. - * For example, you can always convert #UCL_TIME to #UCL_FLOAT. Also you can convert #UCL_FLOAT to #UCL_INTEGER - * by loosing floating point. Every object may be converted to a string by #ucl_object_tostring_forced() function. - * - */ -typedef enum ucl_type { - UCL_OBJECT = 0, /**< UCL object - key/value pairs */ - UCL_ARRAY, /**< UCL array */ - UCL_INT, /**< Integer number */ - UCL_FLOAT, /**< Floating point number */ - UCL_STRING, /**< Null terminated string */ - UCL_BOOLEAN, /**< Boolean value */ - UCL_TIME, /**< Time value (floating point number of seconds) */ - UCL_USERDATA, /**< Opaque userdata pointer (may be used in macros) */ - UCL_NULL /**< Null value */ -} ucl_type_t; - -/** - * You can use one of these types to serialise #ucl_object_t by using ucl_object_emit(). - */ -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_emitter_t; - -/** - * These flags defines parser behaviour. If you specify #UCL_PARSER_ZEROCOPY you must ensure - * that the input memory is not freed if an object is in use. Moreover, if you want to use - * zero-terminated keys and string values then you should not use zero-copy mode, as in this case - * UCL still has to perform copying implicitly. - */ -typedef enum ucl_parser_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_flags_t; - -/** - * String conversion flags, that are used in #ucl_object_fromstring_common function. - */ -typedef enum ucl_string_flags { - 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_NUMBER = UCL_STRING_PARSE_INT|UCL_STRING_PARSE_DOUBLE , /**< - 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 = 0x20 /**< Treat numbers as bytes */ -} ucl_string_flags_t; - -/** - * Basic flags for an object - */ -typedef enum ucl_object_flags { - UCL_OBJECT_ALLOCATED_KEY = 1, /**< An object has key allocated internally */ - UCL_OBJECT_ALLOCATED_VALUE = 2, /**< An object has a string value allocated internally */ - UCL_OBJECT_NEED_KEY_ESCAPE = 4 /**< The key of an object need to be escaped on output */ -} ucl_object_flags_t; - -/** - * UCL object structure. Please mention that the most of fields should not be touched by - * UCL users. In future, this structure may be converted to private one. - */ -typedef struct ucl_object_s { - /** - * Variant value type - */ - union { - int64_t iv; /**< Int value of an object */ - const char *sv; /**< String value of an object */ - double dv; /**< Double value of an object */ - struct ucl_object_s *av; /**< Array */ - void *ov; /**< Object */ - void* ud; /**< Opaque user data */ - } value; - const char *key; /**< Key of an object */ - struct ucl_object_s *next; /**< Array handle */ - struct ucl_object_s *prev; /**< Array handle */ - unsigned char* trash_stack[2]; /**< Pointer to allocated chunks */ - unsigned keylen; /**< Lenght of a key */ - unsigned len; /**< Size of an object */ - enum ucl_type type; /**< Real type */ - uint16_t ref; /**< Reference count */ - uint16_t flags; /**< Object flags */ -} ucl_object_t; - -/** @} */ - -/** - * @defgroup utils Utility functions - * A number of utility functions simplify handling of UCL objects - * - * @{ - */ -/** - * Copy and return a key of an object, returned key is zero-terminated - * @param obj CL object - * @return zero terminated key - */ -char* ucl_copy_key_trash (ucl_object_t *obj); - -/** - * Copy and return a string value of an object, returned key is zero-terminated - * @param obj CL object - * @return zero terminated string representation of object value - */ -char* ucl_copy_value_trash (ucl_object_t *obj); - -/** - * Creates a new object - * @return new object - */ -static inline ucl_object_t* ucl_object_new (void) UCL_WARN_UNUSED_RESULT; -static inline ucl_object_t * -ucl_object_new (void) -{ - ucl_object_t *new; - new = malloc (sizeof (ucl_object_t)); - if (new != NULL) { - memset (new, 0, sizeof (ucl_object_t)); - new->ref = 1; - new->type = UCL_NULL; - } - return new; -} - -/** - * Create new object with type specified - * @param type type of a new object - * @return new object - */ -static inline ucl_object_t* ucl_object_typed_new (unsigned int type) UCL_WARN_UNUSED_RESULT; -static inline ucl_object_t * -ucl_object_typed_new (unsigned int type) -{ - ucl_object_t *new; - new = malloc (sizeof (ucl_object_t)); - if (new != NULL) { - memset (new, 0, sizeof (ucl_object_t)); - new->ref = 1; - new->type = (type <= UCL_NULL ? type : UCL_NULL); - } - return new; -} - -/** - * 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) - * @param flags conversion flags - * @return new object - */ -ucl_object_t * ucl_object_fromstring_common (const char *str, size_t len, - enum ucl_string_flags flags) UCL_WARN_UNUSED_RESULT; - -/** - * Create a UCL object from the specified string - * @param str NULL terminated string, will be json escaped - * @return new object - */ -static inline ucl_object_t * -ucl_object_fromstring (const char *str) -{ - return ucl_object_fromstring_common (str, 0, UCL_STRING_ESCAPE); -} - -/** - * Create a UCL object from the specified string - * @param str fixed size string, will be json escaped - * @param len length of a string - * @return new object - */ -static inline ucl_object_t * -ucl_object_fromlstring (const char *str, size_t len) -{ - return ucl_object_fromstring_common (str, len, UCL_STRING_ESCAPE); -} - -/** - * Create an object from an integer number - * @param iv number - * @return new object - */ -static inline ucl_object_t * -ucl_object_fromint (int64_t iv) -{ - ucl_object_t *obj; - - obj = ucl_object_new (); - if (obj != NULL) { - obj->type = UCL_INT; - obj->value.iv = iv; - } - - return obj; -} - -/** - * Create an object from a float number - * @param dv number - * @return new object - */ -static inline ucl_object_t * -ucl_object_fromdouble (double dv) -{ - ucl_object_t *obj; - - obj = ucl_object_new (); - if (obj != NULL) { - obj->type = UCL_FLOAT; - obj->value.dv = dv; - } - - return obj; -} - -/** - * Create an object from a boolean - * @param bv bool value - * @return new object - */ -static inline ucl_object_t * -ucl_object_frombool (bool bv) -{ - ucl_object_t *obj; - - obj = ucl_object_new (); - if (obj != NULL) { - obj->type = UCL_BOOLEAN; - obj->value.iv = bv; - } - - return obj; -} - -/** - * Insert a object 'elt' to the hash 'top' and associate it with key 'key' - * @param top destination object (will be created automatically if top is NULL) - * @param elt element to insert (must NOT be NULL) - * @param key key to associate with this object (either const or preallocated) - * @param keylen length of the key (or 0 for NULL terminated keys) - * @param copy_key make an internal copy of key - * @return new value of top object - */ -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_WARN_UNUSED_RESULT; - -/** - * Replace a object 'elt' to the hash 'top' and associate it with key 'key', old object will be unrefed, - * if no object has been found this function works like ucl_object_insert_key() - * @param top destination object (will be created automatically if top is NULL) - * @param elt element to insert (must NOT be NULL) - * @param key key to associate with this object (either const or preallocated) - * @param keylen length of the key (or 0 for NULL terminated keys) - * @param copy_key make an internal copy of key - * @return new value of top object - */ -ucl_object_t* ucl_object_replace_key (ucl_object_t *top, ucl_object_t *elt, - const char *key, size_t keylen, bool copy_key) UCL_WARN_UNUSED_RESULT; - -/** - * Insert a object 'elt' to the hash 'top' and associate it with key 'key', if the specified key exist, - * try to merge its content - * @param top destination object (will be created automatically if top is NULL) - * @param elt element to insert (must NOT be NULL) - * @param key key to associate with this object (either const or preallocated) - * @param keylen length of the key (or 0 for NULL terminated keys) - * @param copy_key make an internal copy of key - * @return new value of top object - */ -ucl_object_t* ucl_object_insert_key_merged (ucl_object_t *top, ucl_object_t *elt, - const char *key, size_t keylen, bool copy_key) UCL_WARN_UNUSED_RESULT; - -/** - * Append an element to the array object - * @param top destination object (will be created automatically if top is NULL) - * @param elt element to append (must NOT be NULL) - * @return new value of top object - */ -static inline ucl_object_t * ucl_array_append (ucl_object_t *top, - ucl_object_t *elt) UCL_WARN_UNUSED_RESULT; -static inline ucl_object_t * -ucl_array_append (ucl_object_t *top, ucl_object_t *elt) -{ - ucl_object_t *head; - - if (elt == NULL) { - return NULL; - } - - if (top == NULL) { - top = ucl_object_typed_new (UCL_ARRAY); - top->value.av = elt; - elt->next = NULL; - elt->prev = elt; - top->len = 1; - } - else { - head = top->value.av; - if (head == NULL) { - top->value.av = elt; - elt->prev = elt; - } - else { - elt->prev = head->prev; - head->prev->next = elt; - head->prev = elt; - } - elt->next = NULL; - top->len ++; - } - - return top; -} - -/** - * Append a element to another element forming an implicit array - * @param head head to append (may be NULL) - * @param elt new element - * @return new head if applicable - */ -static inline ucl_object_t * ucl_elt_append (ucl_object_t *head, - ucl_object_t *elt) UCL_WARN_UNUSED_RESULT; -static inline ucl_object_t * -ucl_elt_append (ucl_object_t *head, ucl_object_t *elt) -{ - - if (head == NULL) { - elt->next = NULL; - elt->prev = elt; - head = elt; - } - else { - elt->prev = head->prev; - head->prev->next = elt; - head->prev = elt; - elt->next = NULL; - } - - return head; -} - -/** - * Converts an object to double value - * @param obj CL object - * @param target target double variable - * @return true if conversion was successful - */ -static inline bool -ucl_object_todouble_safe (ucl_object_t *obj, double *target) -{ - if (obj == NULL) { - return false; - } - switch (obj->type) { - case UCL_INT: - *target = obj->value.iv; /* Probaly could cause overflow */ - break; - case UCL_FLOAT: - case UCL_TIME: - *target = obj->value.dv; - break; - default: - return false; - } - - return true; -} - -/** - * Unsafe version of \ref ucl_obj_todouble_safe - * @param obj CL object - * @return double value - */ -static inline double -ucl_object_todouble (ucl_object_t *obj) -{ - double result = 0.; - - ucl_object_todouble_safe (obj, &result); - return result; -} - -/** - * Converts an object to integer value - * @param obj CL object - * @param target target integer variable - * @return true if conversion was successful - */ -static inline bool -ucl_object_toint_safe (ucl_object_t *obj, int64_t *target) -{ - if (obj == NULL) { - return false; - } - switch (obj->type) { - case UCL_INT: - *target = obj->value.iv; - break; - case UCL_FLOAT: - case UCL_TIME: - *target = obj->value.dv; /* Loosing of decimal points */ - break; - default: - return false; - } - - return true; -} - -/** - * Unsafe version of \ref ucl_obj_toint_safe - * @param obj CL object - * @return int value - */ -static inline int64_t -ucl_object_toint (ucl_object_t *obj) -{ - int64_t result = 0; - - ucl_object_toint_safe (obj, &result); - return result; -} - -/** - * Converts an object to boolean value - * @param obj CL object - * @param target target boolean variable - * @return true if conversion was successful - */ -static inline bool -ucl_object_toboolean_safe (ucl_object_t *obj, bool *target) -{ - if (obj == NULL) { - return false; - } - switch (obj->type) { - case UCL_BOOLEAN: - *target = (obj->value.iv == true); - break; - default: - return false; - } - - return true; -} - -/** - * Unsafe version of \ref ucl_obj_toboolean_safe - * @param obj CL object - * @return boolean value - */ -static inline bool -ucl_object_toboolean (ucl_object_t *obj) -{ - bool result = false; - - ucl_object_toboolean_safe (obj, &result); - return result; -} - -/** - * Converts an object to string value - * @param obj CL object - * @param target target string variable, no need to free value - * @return true if conversion was successful - */ -static inline bool -ucl_object_tostring_safe (ucl_object_t *obj, const char **target) -{ - if (obj == NULL) { - return false; - } - - switch (obj->type) { - case UCL_STRING: - *target = ucl_copy_value_trash (obj); - break; - default: - return false; - } - - return true; -} - -/** - * Unsafe version of \ref ucl_obj_tostring_safe - * @param obj CL object - * @return string value - */ -static inline const char * -ucl_object_tostring (ucl_object_t *obj) -{ - const char *result = NULL; - - ucl_object_tostring_safe (obj, &result); - return result; -} - -/** - * Convert any object to a string in JSON notation if needed - * @param obj CL object - * @return string value - */ -static inline const char * -ucl_object_tostring_forced (ucl_object_t *obj) -{ - return ucl_copy_value_trash (obj); -} - -/** - * Return string as char * and len, string may be not zero terminated, more efficient that \ref ucl_obj_tostring as it - * allows zero-copy (if #UCL_PARSER_ZEROCOPY has been used during parsing) - * @param obj CL object - * @param target target string variable, no need to free value - * @param tlen target length - * @return true if conversion was successful - */ -static inline bool -ucl_object_tolstring_safe (ucl_object_t *obj, const char **target, size_t *tlen) -{ - if (obj == NULL) { - return false; - } - switch (obj->type) { - case UCL_STRING: - *target = obj->value.sv; - *tlen = obj->len; - break; - default: - return false; - } - - return true; -} - -/** - * Unsafe version of \ref ucl_obj_tolstring_safe - * @param obj CL object - * @return string value - */ -static inline const char * -ucl_object_tolstring (ucl_object_t *obj, size_t *tlen) -{ - const char *result = NULL; - - ucl_object_tolstring_safe (obj, &result, tlen); - return result; -} - -/** - * Return object identified by a key in the specified object - * @param obj object to get a key from (must be of type UCL_OBJECT) - * @param key key to search - * @return object matched the specified key or NULL if key is not found - */ -ucl_object_t * ucl_object_find_key (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 - * @param klen length of a key - * @return object matched the specified key or NULL if key is not found - */ -ucl_object_t *ucl_object_find_keyl (ucl_object_t *obj, const char *key, size_t klen); - -/** - * Returns a key of an object as a NULL terminated string - * @param obj CL object - * @return key or NULL if there is no key - */ -static inline const char * -ucl_object_key (ucl_object_t *obj) -{ - return ucl_copy_key_trash (obj); -} - -/** - * Returns a key of an object as a fixed size string (may be more efficient) - * @param obj CL object - * @param len target key length - * @return key pointer - */ -static inline const char * -ucl_object_keyl (ucl_object_t *obj, size_t *len) -{ - *len = obj->keylen; - return obj->key; -} - -/** - * Free ucl object - * @param obj ucl object to free - */ -void ucl_object_free (ucl_object_t *obj); - -/** - * Increase reference count for an object - * @param obj object to ref - */ -static inline ucl_object_t * -ucl_object_ref (ucl_object_t *obj) { - obj->ref ++; - return obj; -} - -/** - * Decrease reference count for an object - * @param obj object to unref - */ -static inline void -ucl_object_unref (ucl_object_t *obj) { - if (--obj->ref <= 0) { - ucl_object_free (obj); - } -} -/** - * Opaque iterator object - */ -typedef void* ucl_object_iter_t; - -/** - * Get next key from an object - * @param obj object to iterate - * @param iter opaque iterator, must be set to NULL on the first call: - * ucl_object_iter_t it = NULL; - * while ((cur = ucl_iterate_object (obj, &it)) != NULL) ... - * @return the next object or NULL - */ -ucl_object_t* ucl_iterate_object (ucl_object_t *obj, ucl_object_iter_t *iter, bool expand_values); -/** @} */ - - -/** - * @defgroup parser Parsing functions - * These functions are used to parse UCL objects - * - * @{ - */ - -/** - * Macro handler for a parser - * @param data the content of macro - * @param len the length of content - * @param ud opaque user data - * @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); - -/* Opaque parser */ -struct ucl_parser; - -/** - * Creates new parser object - * @param pool pool to allocate memory from - * @return new parser object - */ -struct ucl_parser* ucl_parser_new (int flags); - -/** - * Register new handler for a macro - * @param parser parser object - * @param macro macro name (without leading dot) - * @param handler handler (it is called immediately after macro is parsed) - * @param ud opaque user data for a handler - */ -void ucl_parser_register_macro (struct ucl_parser *parser, const char *macro, - ucl_macro_handler handler, void* ud); - -/** - * Register new parser variable - * @param parser parser object - * @param var variable name - * @param value variable value - */ -void ucl_parser_register_variable (struct ucl_parser *parser, const char *var, - const char *value); - -/** - * Load new chunk to a 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 added and false in case of error - */ -bool ucl_parser_add_chunk (struct ucl_parser *parser, const unsigned char *data, size_t len); - -/** - * 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 - * @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); - -/** - * Get a top object for a parser - * @param parser parser structure - * @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); - -/** - * Get the error string if failing - * @param parser parser object - */ -const char *ucl_parser_get_error(struct ucl_parser *parser); -/** - * Free ucl parser object - * @param parser parser object - */ -void ucl_parser_free (struct ucl_parser *parser); - -/** - * Add new public key to parser for signatures check - * @param parser parser object - * @param key PEM representation of a key - * @param len length of the key - * @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); - -/** - * Set FILENAME and CURDIR variables in parser - * @param parser parser object - * @param filename filename to set or NULL to set FILENAME to "undef" and CURDIR to getcwd() - * @param need_expand perform realpath() if this variable is true and filename is not NULL - * @return true if variables has been set - */ -bool ucl_parser_set_filevars (struct ucl_parser *parser, const char *filename, - bool need_expand); - -/** @} */ - -/** - * @defgroup emitter Emitting functions - * These functions are used to serialise UCL objects to some string representation. - * - * @{ - */ - -/** - * Structure using for emitter callbacks - */ -struct ucl_emitter_functions { - /** Append a single character */ - int (*ucl_emitter_append_character) (unsigned char c, size_t nchars, void *ud); - /** Append a string of a specified length */ - int (*ucl_emitter_append_len) (unsigned const char *str, size_t len, void *ud); - /** Append a 64 bit integer */ - int (*ucl_emitter_append_int) (int64_t elt, void *ud); - /** Append floating point element */ - int (*ucl_emitter_append_double) (double elt, void *ud); - /** Opaque userdata pointer */ - void *ud; -}; - -/** - * Emit object to a string - * @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 - * @return dump of an object (must be freed after using) or NULL in case of error - */ -unsigned char *ucl_object_emit (ucl_object_t *obj, enum ucl_emitter emit_type); - -/** - * Emit object to a string - * @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 - * @return dump of an object (must be freed after using) or NULL in case of error - */ -bool ucl_object_emit_full (ucl_object_t *obj, enum ucl_emitter emit_type, - struct ucl_emitter_functions *emitter); -/** @} */ - -#ifdef __cplusplus -} -#endif -/* - * XXX: Poorly named API functions, need to replace them with the appropriate - * named function. All API functions *must* use naming ucl_object_*. Usage of - * ucl_obj* should be avoided. - */ -#define ucl_obj_todouble_safe ucl_object_todouble_safe -#define ucl_obj_todouble ucl_object_todouble -#define ucl_obj_tostring ucl_object_tostring -#define ucl_obj_tostring_safe ucl_object_tostring_safe -#define ucl_obj_tolstring ucl_object_tolstring -#define ucl_obj_tolstring_safe ucl_object_tolstring_safe -#define ucl_obj_toint ucl_object_toint -#define ucl_obj_toint_safe ucl_object_toint_safe -#define ucl_obj_toboolean ucl_object_toboolean -#define ucl_obj_toboolean_safe ucl_object_toboolean_safe -#define ucl_obj_get_key ucl_object_find_key -#define ucl_obj_get_keyl ucl_object_find_keyl -#define ucl_obj_unref ucl_object_unref -#define ucl_obj_ref ucl_object_ref -#define ucl_obj_free ucl_object_free - -#endif /* UCL_H_ */ diff --git a/src/ucl/src/ucl_chartable.h b/src/ucl/src/ucl_chartable.h deleted file mode 100644 index 5248e117c..000000000 --- a/src/ucl/src/ucl_chartable.h +++ /dev/null @@ -1,267 +0,0 @@ -/* Copyright (c) 2013, 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 ''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. - */ - -#ifndef UCL_CHARTABLE_H_ -#define UCL_CHARTABLE_H_ - -#include "ucl_internal.h" - -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_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_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_UCL_UNSAFE /* */, -UCL_CHARACTER_VALUE_STR /* ! */, -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 /* ( */, -UCL_CHARACTER_VALUE_STR /* ) */, UCL_CHARACTER_VALUE_STR /* * */, -UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* + */, -UCL_CHARACTER_VALUE_END /* , */, -UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT_START|UCL_CHARACTER_VALUE_DIGIT /* - */, -UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* . */, -UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_ESCAPE /* / */, -UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT_START|UCL_CHARACTER_VALUE_DIGIT /* 0 */, -UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT_START|UCL_CHARACTER_VALUE_DIGIT /* 1 */, -UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT_START|UCL_CHARACTER_VALUE_DIGIT /* 2 */, -UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT_START|UCL_CHARACTER_VALUE_DIGIT /* 3 */, -UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT_START|UCL_CHARACTER_VALUE_DIGIT /* 4 */, -UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT_START|UCL_CHARACTER_VALUE_DIGIT /* 5 */, -UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT_START|UCL_CHARACTER_VALUE_DIGIT /* 6 */, -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_UCL_UNSAFE /* : */, -UCL_CHARACTER_VALUE_END /* ; */, UCL_CHARACTER_VALUE_STR /* < */, -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 */, -UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* B */, -UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* C */, -UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* D */, -UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* E */, -UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* F */, -UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* G */, -UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* H */, -UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* I */, -UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* J */, -UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* K */, -UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* L */, -UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* M */, -UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* N */, -UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* O */, -UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* P */, -UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* Q */, -UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* R */, -UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* S */, -UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* T */, -UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* U */, -UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* V */, -UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* W */, -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_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 /* ` */, -UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* a */, -UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT|UCL_CHARACTER_ESCAPE /* b */, -UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* c */, -UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* d */, -UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* e */, -UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT|UCL_CHARACTER_ESCAPE /* f */, -UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* g */, -UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* h */, -UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* i */, -UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* j */, -UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* k */, -UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* l */, -UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* m */, -UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT|UCL_CHARACTER_ESCAPE /* n */, -UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* o */, -UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* p */, -UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* q */, -UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT|UCL_CHARACTER_ESCAPE /* r */, -UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* s */, -UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT|UCL_CHARACTER_ESCAPE /* t */, -UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT|UCL_CHARACTER_ESCAPE /* u */, -UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* v */, -UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* w */, -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_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, -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, -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, -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, -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, -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, -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, -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, -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, -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, -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, -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, -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, -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, -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, -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, -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, -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, -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, -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, -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, -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, -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, -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, -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, -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, -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, -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, -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, -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, -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, -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, -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, -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, -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, -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, -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, -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, -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, -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, -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, -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, -UCL_CHARACTER_KEY_START|UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR -}; - -static inline bool -ucl_test_character (unsigned char c, int type_flags) -{ - return (ucl_chartable[c] & type_flags) != 0; -} - -#endif /* UCL_CHARTABLE_H_ */ diff --git a/src/ucl/src/ucl_emitter.c b/src/ucl/src/ucl_emitter.c deleted file mode 100644 index 51bb09aad..000000000 --- a/src/ucl/src/ucl_emitter.c +++ /dev/null @@ -1,829 +0,0 @@ -/* Copyright (c) 2013, 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 ''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. - */ - -#include -#include -#include "ucl.h" -#include "ucl_internal.h" -#include "ucl_chartable.h" - -/** - * @file rcl_emitter.c - * Serialise UCL object to various of output formats - */ - - -static void ucl_obj_write_json (ucl_object_t *obj, - struct ucl_emitter_functions *func, - unsigned int tabs, - bool start_tabs, - bool compact); -static void ucl_elt_write_json (ucl_object_t *obj, - struct ucl_emitter_functions *func, - unsigned int tabs, - bool start_tabs, - bool compact); -static void ucl_elt_write_config (ucl_object_t *obj, - struct ucl_emitter_functions *func, - unsigned int tabs, - bool start_tabs, - bool is_top, - bool expand_array); -static void ucl_elt_write_yaml (ucl_object_t *obj, - struct ucl_emitter_functions *func, - unsigned int tabs, - bool start_tabs, - bool compact, - bool expand_array); -static void ucl_elt_array_write_yaml (ucl_object_t *obj, - struct ucl_emitter_functions *func, - unsigned int tabs, - bool start_tabs, - bool is_top); - -/** - * Add tabulation to the output buffer - * @param buf target buffer - * @param tabs number of tabs to add - */ -static inline void -ucl_add_tabs (struct ucl_emitter_functions *func, unsigned int tabs, bool compact) -{ - if (!compact) { - func->ucl_emitter_append_character (' ', tabs * 4, func->ud); - } -} - -/** - * Serialise string - * @param str string to emit - * @param buf target buffer - */ -static void -ucl_elt_string_write_json (const char *str, size_t size, - struct ucl_emitter_functions *func) -{ - const char *p = str, *c = str; - size_t len = 0; - - func->ucl_emitter_append_character ('"', 1, func->ud); - while (size) { - if (ucl_test_character (*p, UCL_CHARACTER_JSON_UNSAFE)) { - if (len > 0) { - func->ucl_emitter_append_len (c, len, func->ud); - } - switch (*p) { - case '\n': - func->ucl_emitter_append_len ("\\n", 2, func->ud); - break; - case '\r': - func->ucl_emitter_append_len ("\\r", 2, func->ud); - break; - case '\b': - func->ucl_emitter_append_len ("\\b", 2, func->ud); - break; - case '\t': - func->ucl_emitter_append_len ("\\t", 2, func->ud); - break; - case '\f': - func->ucl_emitter_append_len ("\\f", 2, func->ud); - break; - case '\\': - func->ucl_emitter_append_len ("\\\\", 2, func->ud); - break; - case '"': - func->ucl_emitter_append_len ("\\\"", 2, func->ud); - break; - } - len = 0; - c = ++p; - } - else { - p ++; - len ++; - } - size --; - } - if (len > 0) { - func->ucl_emitter_append_len (c, len, func->ud); - } - func->ucl_emitter_append_character ('"', 1, func->ud); -} - -/** - * Write a single object to the buffer - * @param obj object to write - * @param buf target buffer - */ -static void -ucl_elt_obj_write_json (ucl_object_t *obj, struct ucl_emitter_functions *func, - unsigned int tabs, bool start_tabs, bool compact) -{ - ucl_object_t *cur; - ucl_hash_iter_t it = NULL; - - if (start_tabs) { - ucl_add_tabs (func, tabs, compact); - } - if (compact) { - func->ucl_emitter_append_character ('{', 1, func->ud); - } - else { - func->ucl_emitter_append_len ("{\n", 2, func->ud); - } - while ((cur = ucl_hash_iterate (obj->value.ov, &it))) { - ucl_add_tabs (func, tabs + 1, compact); - if (cur->keylen > 0) { - ucl_elt_string_write_json (cur->key, cur->keylen, func); - } - else { - func->ucl_emitter_append_len ("null", 4, func->ud); - } - if (compact) { - func->ucl_emitter_append_character (':', 1, func->ud); - } - else { - func->ucl_emitter_append_len (": ", 2, func->ud); - } - ucl_obj_write_json (cur, func, tabs + 1, false, compact); - if (ucl_hash_iter_has_next (it)) { - if (compact) { - func->ucl_emitter_append_character (',', 1, func->ud); - } - else { - func->ucl_emitter_append_len (",\n", 2, func->ud); - } - } - else if (!compact) { - func->ucl_emitter_append_character ('\n', 1, func->ud); - } - } - ucl_add_tabs (func, tabs, compact); - func->ucl_emitter_append_character ('}', 1, func->ud); -} - -/** - * Write a single array to the buffer - * @param obj array to write - * @param buf target buffer - */ -static void -ucl_elt_array_write_json (ucl_object_t *obj, struct ucl_emitter_functions *func, - unsigned int tabs, bool start_tabs, bool compact) -{ - ucl_object_t *cur = obj; - - if (start_tabs) { - ucl_add_tabs (func, tabs, compact); - } - if (compact) { - func->ucl_emitter_append_character ('[', 1, func->ud); - } - else { - func->ucl_emitter_append_len ("[\n", 2, func->ud); - } - while (cur) { - ucl_elt_write_json (cur, func, tabs + 1, true, compact); - if (cur->next != NULL) { - if (compact) { - func->ucl_emitter_append_character (',', 1, func->ud); - } - else { - func->ucl_emitter_append_len (",\n", 2, func->ud); - } - } - else if (!compact) { - func->ucl_emitter_append_character ('\n', 1, func->ud); - } - cur = cur->next; - } - ucl_add_tabs (func, tabs, compact); - func->ucl_emitter_append_character (']', 1, func->ud); -} - -/** - * Emit a single element - * @param obj object - * @param buf buffer - */ -static void -ucl_elt_write_json (ucl_object_t *obj, struct ucl_emitter_functions *func, - unsigned int tabs, bool start_tabs, bool compact) -{ - bool flag; - - switch (obj->type) { - case UCL_INT: - if (start_tabs) { - ucl_add_tabs (func, tabs, compact); - } - func->ucl_emitter_append_int (ucl_object_toint (obj), func->ud); - break; - case UCL_FLOAT: - case UCL_TIME: - if (start_tabs) { - ucl_add_tabs (func, tabs, compact); - } - func->ucl_emitter_append_double (ucl_object_todouble (obj), func->ud); - break; - case UCL_BOOLEAN: - if (start_tabs) { - ucl_add_tabs (func, tabs, compact); - } - flag = ucl_object_toboolean (obj); - if (flag) { - func->ucl_emitter_append_len ("true", 4, func->ud); - } - else { - func->ucl_emitter_append_len ("false", 5, func->ud); - } - break; - case UCL_STRING: - if (start_tabs) { - ucl_add_tabs (func, tabs, compact); - } - ucl_elt_string_write_json (obj->value.sv, obj->len, func); - break; - case UCL_NULL: - if (start_tabs) { - ucl_add_tabs (func, tabs, compact); - } - func->ucl_emitter_append_len ("null", 4, func->ud); - break; - case UCL_OBJECT: - ucl_elt_obj_write_json (obj, func, tabs, start_tabs, compact); - break; - case UCL_ARRAY: - ucl_elt_array_write_json (obj->value.av, func, tabs, start_tabs, compact); - break; - case UCL_USERDATA: - break; - } -} - -/** - * Write a single object to the buffer - * @param obj object - * @param buf target buffer - */ -static void -ucl_obj_write_json (ucl_object_t *obj, struct ucl_emitter_functions *func, - unsigned int tabs, bool start_tabs, bool compact) -{ - ucl_object_t *cur; - bool is_array = (obj->next != NULL); - - if (is_array) { - /* This is an array actually */ - if (start_tabs) { - ucl_add_tabs (func, tabs, compact); - } - - if (compact) { - func->ucl_emitter_append_character ('[', 1, func->ud); - } - else { - func->ucl_emitter_append_len ("[\n", 2, func->ud); - } - cur = obj; - while (cur != NULL) { - ucl_elt_write_json (cur, func, tabs + 1, true, compact); - if (cur->next) { - func->ucl_emitter_append_character (',', 1, func->ud); - } - if (!compact) { - func->ucl_emitter_append_character ('\n', 1, func->ud); - } - cur = cur->next; - } - ucl_add_tabs (func, tabs, compact); - func->ucl_emitter_append_character (']', 1, func->ud); - } - else { - ucl_elt_write_json (obj, func, tabs, start_tabs, compact); - } - -} - -/** - * Emit an object to json - * @param obj object - * @return json output (should be freed after using) - */ -static void -ucl_object_emit_json (ucl_object_t *obj, bool compact, struct ucl_emitter_functions *func) -{ - ucl_obj_write_json (obj, func, 0, false, compact); -} - -/** - * Write a single object to the buffer - * @param obj object to write - * @param buf target buffer - */ -static void -ucl_elt_obj_write_config (ucl_object_t *obj, struct ucl_emitter_functions *func, - unsigned int tabs, bool start_tabs, bool is_top) -{ - ucl_object_t *cur, *cur_obj; - ucl_hash_iter_t it = NULL; - - if (start_tabs) { - ucl_add_tabs (func, tabs, is_top); - } - if (!is_top) { - func->ucl_emitter_append_len ("{\n", 2, func->ud); - } - - while ((cur = ucl_hash_iterate (obj->value.ov, &it))) { - LL_FOREACH (cur, cur_obj) { - ucl_add_tabs (func, tabs + 1, is_top); - if (cur_obj->flags & UCL_OBJECT_NEED_KEY_ESCAPE) { - ucl_elt_string_write_json (cur_obj->key, cur_obj->keylen, func); - } - else { - func->ucl_emitter_append_len (cur_obj->key, cur_obj->keylen, func->ud); - } - if (cur_obj->type != UCL_OBJECT && cur_obj->type != UCL_ARRAY) { - func->ucl_emitter_append_len (" = ", 3, func->ud); - } - else { - func->ucl_emitter_append_character (' ', 1, func->ud); - } - ucl_elt_write_config (cur_obj, func, - is_top ? tabs : tabs + 1, - false, false, false); - if (cur_obj->type != UCL_OBJECT && cur_obj->type != UCL_ARRAY) { - func->ucl_emitter_append_len (";\n", 2, func->ud); - } - else { - func->ucl_emitter_append_character ('\n', 1, func->ud); - } - } - } - - ucl_add_tabs (func, tabs, is_top); - if (!is_top) { - func->ucl_emitter_append_character ('}', 1, func->ud); - } -} - -/** - * Write a single array to the buffer - * @param obj array to write - * @param buf target buffer - */ -static void -ucl_elt_array_write_config (ucl_object_t *obj, struct ucl_emitter_functions *func, - unsigned int tabs, bool start_tabs, bool is_top) -{ - ucl_object_t *cur = obj; - - if (start_tabs) { - ucl_add_tabs (func, tabs, false); - } - - func->ucl_emitter_append_len ("[\n", 2, func->ud); - while (cur) { - ucl_elt_write_config (cur, func, tabs + 1, true, false, false); - func->ucl_emitter_append_len (",\n", 2, func->ud); - cur = cur->next; - } - ucl_add_tabs (func, tabs, false); - func->ucl_emitter_append_character (']', 1, func->ud); -} - -/** - * Emit a single element - * @param obj object - * @param buf buffer - */ -static void -ucl_elt_write_config (ucl_object_t *obj, struct ucl_emitter_functions *func, - unsigned int tabs, bool start_tabs, bool is_top, bool expand_array) -{ - bool flag; - - if (expand_array && obj->next != NULL) { - ucl_elt_array_write_config (obj, func, tabs, start_tabs, is_top); - } - else { - switch (obj->type) { - case UCL_INT: - if (start_tabs) { - ucl_add_tabs (func, tabs, false); - } - func->ucl_emitter_append_int (ucl_object_toint (obj), func->ud); - break; - case UCL_FLOAT: - case UCL_TIME: - if (start_tabs) { - ucl_add_tabs (func, tabs, false); - } - func->ucl_emitter_append_double (ucl_object_todouble (obj), func->ud); - break; - case UCL_BOOLEAN: - if (start_tabs) { - ucl_add_tabs (func, tabs, false); - } - flag = ucl_object_toboolean (obj); - if (flag) { - func->ucl_emitter_append_len ("true", 4, func->ud); - } - else { - func->ucl_emitter_append_len ("false", 5, func->ud); - } - break; - case UCL_STRING: - if (start_tabs) { - ucl_add_tabs (func, tabs, false); - } - ucl_elt_string_write_json (obj->value.sv, obj->len, func); - break; - case UCL_NULL: - if (start_tabs) { - ucl_add_tabs (func, tabs, false); - } - func->ucl_emitter_append_len ("null", 4, func->ud); - break; - case UCL_OBJECT: - ucl_elt_obj_write_config (obj, func, tabs, start_tabs, is_top); - break; - case UCL_ARRAY: - ucl_elt_array_write_config (obj->value.av, func, tabs, start_tabs, is_top); - break; - case UCL_USERDATA: - break; - } - } -} - -/** - * Emit an object to rcl - * @param obj object - * @return rcl output (should be freed after using) - */ -static void -ucl_object_emit_config (ucl_object_t *obj, struct ucl_emitter_functions *func) -{ - ucl_elt_write_config (obj, func, 0, false, true, true); -} - - -static void -ucl_obj_write_yaml (ucl_object_t *obj, struct ucl_emitter_functions *func, - unsigned int tabs, bool start_tabs) -{ - bool is_array = (obj->next != NULL); - - if (is_array) { - ucl_elt_array_write_yaml (obj, func, tabs, start_tabs, false); - } - else { - ucl_elt_write_yaml (obj, func, tabs, start_tabs, false, true); - } -} - -/** - * Write a single object to the buffer - * @param obj object to write - * @param buf target buffer - */ -static void -ucl_elt_obj_write_yaml (ucl_object_t *obj, struct ucl_emitter_functions *func, - unsigned int tabs, bool start_tabs, bool is_top) -{ - ucl_object_t *cur; - ucl_hash_iter_t it = NULL; - - if (start_tabs) { - ucl_add_tabs (func, tabs, is_top); - } - if (!is_top) { - func->ucl_emitter_append_len ("{\n", 2, func->ud); - } - - while ((cur = ucl_hash_iterate (obj->value.ov, &it))) { - ucl_add_tabs (func, tabs + 1, is_top); - if (cur->keylen > 0) { - ucl_elt_string_write_json (cur->key, cur->keylen, func); - } - else { - func->ucl_emitter_append_len ("null", 4, func->ud); - } - func->ucl_emitter_append_len (": ", 2, func->ud); - ucl_obj_write_yaml (cur, func, is_top ? tabs : tabs + 1, false); - if (ucl_hash_iter_has_next(it)) { - if (!is_top) { - func->ucl_emitter_append_len (",\n", 2, func->ud); - } - else { - func->ucl_emitter_append_character ('\n', 1, func->ud); - } - } - else { - func->ucl_emitter_append_character ('\n', 1, func->ud); - } - } - - ucl_add_tabs (func, tabs, is_top); - if (!is_top) { - func->ucl_emitter_append_character ('}', 1, func->ud); - } -} - -/** - * Write a single array to the buffer - * @param obj array to write - * @param buf target buffer - */ -static void -ucl_elt_array_write_yaml (ucl_object_t *obj, struct ucl_emitter_functions *func, - unsigned int tabs, bool start_tabs, bool is_top) -{ - ucl_object_t *cur = obj; - - if (start_tabs) { - ucl_add_tabs (func, tabs, false); - } - - func->ucl_emitter_append_len ("[\n", 2, func->ud); - while (cur) { - ucl_elt_write_yaml (cur, func, tabs + 1, true, false, false); - func->ucl_emitter_append_len (",\n", 2, func->ud); - cur = cur->next; - } - ucl_add_tabs (func, tabs, false); - func->ucl_emitter_append_character (']', 1, func->ud); -} - -/** - * Emit a single element - * @param obj object - * @param buf buffer - */ -static void -ucl_elt_write_yaml (ucl_object_t *obj, struct ucl_emitter_functions *func, - unsigned int tabs, bool start_tabs, bool is_top, bool expand_array) -{ - bool flag; - - if (expand_array && obj->next != NULL ) { - ucl_elt_array_write_yaml (obj, func, tabs, start_tabs, is_top); - } - else { - switch (obj->type) { - case UCL_INT: - if (start_tabs) { - ucl_add_tabs (func, tabs, false); - } - func->ucl_emitter_append_int (ucl_object_toint (obj), func->ud); - break; - case UCL_FLOAT: - case UCL_TIME: - if (start_tabs) { - ucl_add_tabs (func, tabs, false); - } - func->ucl_emitter_append_double (ucl_object_todouble (obj), func->ud); - break; - case UCL_BOOLEAN: - if (start_tabs) { - ucl_add_tabs (func, tabs, false); - } - flag = ucl_object_toboolean (obj); - if (flag) { - func->ucl_emitter_append_len ("true", 4, func->ud); - } - else { - func->ucl_emitter_append_len ("false", 5, func->ud); - } - break; - case UCL_STRING: - if (start_tabs) { - ucl_add_tabs (func, tabs, false); - } - ucl_elt_string_write_json (obj->value.sv, obj->len, func); - break; - case UCL_NULL: - if (start_tabs) { - ucl_add_tabs (func, tabs, false); - } - func->ucl_emitter_append_len ("null", 4, func->ud); - break; - case UCL_OBJECT: - ucl_elt_obj_write_yaml (obj, func, tabs, start_tabs, is_top); - break; - case UCL_ARRAY: - ucl_elt_array_write_yaml (obj->value.av, func, tabs, start_tabs, is_top); - break; - case UCL_USERDATA: - break; - } - } -} - -/** - * Emit an object to rcl - * @param obj object - * @return rcl output (should be freed after using) - */ -static void -ucl_object_emit_yaml (ucl_object_t *obj, struct ucl_emitter_functions *func) -{ - ucl_elt_write_yaml (obj, func, 0, false, true, true); -} - -/* - * Generic utstring output - */ -static int -ucl_utstring_append_character (unsigned char c, size_t len, void *ud) -{ - UT_string *buf = ud; - - if (len == 1) { - utstring_append_c (buf, c); - } - else { - utstring_reserve (buf, len); - memset (&buf->d[buf->i], c, len); - buf->i += len; - buf->d[buf->i] = '\0'; - } - - return 0; -} - -static int -ucl_utstring_append_len (const unsigned char *str, size_t len, void *ud) -{ - UT_string *buf = ud; - - utstring_append_len (buf, str, len); - - return 0; -} - -static int -ucl_utstring_append_int (int64_t val, void *ud) -{ - UT_string *buf = ud; - - utstring_printf (buf, "%jd", (intmax_t)val); - return 0; -} - -static int -ucl_utstring_append_double (double val, void *ud) -{ - UT_string *buf = ud; - const double delta = 0.0000001; - - if (val == (double)(int)val) { - utstring_printf (buf, "%.1lf", val); - } - else if (fabs (val - (double)(int)val) < delta) { - /* Write at maximum precision */ - utstring_printf (buf, "%.*lg", DBL_DIG, val); - } - else { - utstring_printf (buf, "%lf", val); - } - - return 0; -} - - -unsigned char * -ucl_object_emit (ucl_object_t *obj, enum ucl_emitter emit_type) -{ - UT_string *buf = NULL; - unsigned char *res = NULL; - struct ucl_emitter_functions func = { - .ucl_emitter_append_character = ucl_utstring_append_character, - .ucl_emitter_append_len = ucl_utstring_append_len, - .ucl_emitter_append_int = ucl_utstring_append_int, - .ucl_emitter_append_double = ucl_utstring_append_double - }; - - if (obj == NULL) { - return NULL; - } - - utstring_new (buf); - func.ud = buf; - - if (buf != NULL) { - if (emit_type == UCL_EMIT_JSON) { - ucl_object_emit_json (obj, false, &func); - } - else if (emit_type == UCL_EMIT_JSON_COMPACT) { - ucl_object_emit_json (obj, true, &func); - } - else if (emit_type == UCL_EMIT_YAML) { - ucl_object_emit_yaml (obj, &func); - } - else { - ucl_object_emit_config (obj, &func); - } - - res = utstring_body (buf); - free (buf); - } - - return res; -} - -bool -ucl_object_emit_full (ucl_object_t *obj, enum ucl_emitter emit_type, - struct ucl_emitter_functions *emitter) -{ - if (emit_type == UCL_EMIT_JSON) { - ucl_object_emit_json (obj, false, emitter); - } - else if (emit_type == UCL_EMIT_JSON_COMPACT) { - ucl_object_emit_json (obj, true, emitter); - } - else if (emit_type == UCL_EMIT_YAML) { - ucl_object_emit_yaml (obj, emitter); - } - else { - ucl_object_emit_config (obj, emitter); - } - - /* XXX: need some error checks here */ - return true; -} - - -unsigned char * -ucl_object_emit_single_json (ucl_object_t *obj) -{ - UT_string *buf = NULL; - unsigned char *res = NULL; - - if (obj == NULL) { - return NULL; - } - - utstring_new (buf); - - if (buf != NULL) { - switch (obj->type) { - case UCL_OBJECT: - ucl_utstring_append_len ("object", 6, buf); - break; - case UCL_ARRAY: - ucl_utstring_append_len ("array", 5, buf); - break; - case UCL_INT: - ucl_utstring_append_int (obj->value.iv, buf); - break; - case UCL_FLOAT: - case UCL_TIME: - ucl_utstring_append_double (obj->value.dv, buf); - break; - case UCL_NULL: - ucl_utstring_append_len ("null", 4, buf); - break; - case UCL_BOOLEAN: - if (obj->value.iv) { - ucl_utstring_append_len ("true", 4, buf); - } - else { - ucl_utstring_append_len ("false", 5, buf); - } - break; - case UCL_STRING: - ucl_utstring_append_len (obj->value.sv, obj->len, buf); - break; - case UCL_USERDATA: - ucl_utstring_append_len ("userdata", 8, buf); - break; - } - res = utstring_body (buf); - free (buf); - } - - return res; -} diff --git a/src/ucl/src/ucl_hash.c b/src/ucl/src/ucl_hash.c deleted file mode 100644 index a3711deb8..000000000 --- a/src/ucl/src/ucl_hash.c +++ /dev/null @@ -1,120 +0,0 @@ -/* Copyright (c) 2013, 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 ''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. - */ - -#include "ucl_hash.h" -#include "utlist.h" - -ucl_hash_t* -ucl_hash_create (void) -{ - ucl_hash_t *new; - - new = UCL_ALLOC (sizeof (ucl_hash_t)); - if (new != NULL) { - new->buckets = NULL; - } - return new; -} - -void ucl_hash_destroy (ucl_hash_t* hashlin, ucl_hash_free_func *func) -{ - ucl_hash_node_t *elt, *tmp; - - HASH_ITER (hh, hashlin->buckets, elt, tmp) { - HASH_DELETE (hh, hashlin->buckets, elt); - if (func) { - func (elt->data); - } - UCL_FREE (sizeof (ucl_hash_node_t), elt); - } - UCL_FREE (sizeof (ucl_hash_t), hashlin); -} - -void -ucl_hash_insert (ucl_hash_t* hashlin, ucl_object_t *obj, const char *key, unsigned keylen) -{ - ucl_hash_node_t *node; - - node = UCL_ALLOC (sizeof (ucl_hash_node_t)); - node->data = obj; - HASH_ADD_KEYPTR (hh, hashlin->buckets, key, keylen, node); -} - -void* -ucl_hash_iterate (ucl_hash_t *hashlin, ucl_hash_iter_t *iter) -{ - ucl_hash_node_t *elt = *iter; - - if (elt == NULL) { - if (hashlin == NULL || hashlin->buckets == NULL) { - return NULL; - } - elt = hashlin->buckets; - if (elt == NULL) { - return NULL; - } - } - else if (elt == hashlin->buckets) { - return NULL; - } - - *iter = elt->hh.next ? elt->hh.next : hashlin->buckets; - return elt->data; -} - -bool -ucl_hash_iter_has_next (ucl_hash_iter_t iter) -{ - ucl_hash_node_t *elt = iter; - - return (elt == NULL || elt->hh.prev != NULL); -} - - -ucl_object_t* -ucl_hash_search (ucl_hash_t* hashlin, const char *key, unsigned keylen) -{ - ucl_hash_node_t *found; - - if (hashlin == NULL) { - return NULL; - } - HASH_FIND (hh, hashlin->buckets, key, keylen, found); - - if (found) { - return found->data; - } - return NULL; -} - -void -ucl_hash_delete (ucl_hash_t* hashlin, ucl_object_t *obj) -{ - ucl_hash_node_t *found; - - HASH_FIND (hh, hashlin->buckets, obj->key, obj->keylen, found); - - if (found) { - HASH_DELETE (hh, hashlin->buckets, found); - } -} diff --git a/src/ucl/src/ucl_hash.h b/src/ucl/src/ucl_hash.h deleted file mode 100644 index 5c9b851b9..000000000 --- a/src/ucl/src/ucl_hash.h +++ /dev/null @@ -1,91 +0,0 @@ -/* Copyright (c) 2013, 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 ''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. - */ - -#ifndef __UCL_HASH_H -#define __UCL_HASH_H - -#include "ucl.h" -#include "uthash.h" - -/******************************************************************************/ - -typedef struct ucl_hash_node_s -{ - ucl_object_t *data; - UT_hash_handle hh; -} 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 void* ucl_hash_iter_t; - - -/** - * Linear chained hashtable. - */ -typedef struct ucl_hash_struct -{ - ucl_hash_node_t *buckets; /**< array of hash buckets. One list for each hash modulus. */ -} ucl_hash_t; - - -/** - * Initializes the hashtable. - */ -ucl_hash_t* ucl_hash_create (void); - -/** - * Deinitializes the hashtable. - */ -void ucl_hash_destroy (ucl_hash_t* hashlin, ucl_hash_free_func *func); - -/** - * Inserts an element in the the hashtable. - */ -void ucl_hash_insert (ucl_hash_t* hashlin, ucl_object_t *obj, const char *key, unsigned keylen); - -/** - * Delete an element from the the hashtable. - */ -void ucl_hash_delete (ucl_hash_t* hashlin, ucl_object_t *obj); - -/** - * Searches an element in the hashtable. - */ -ucl_object_t* ucl_hash_search (ucl_hash_t* hashlin, const char *key, unsigned keylen); - - -/** - * Iterate over hash table - * @param hashlin hash - * @param iter iterator (must be NULL on first iteration) - * @return the next object - */ -void* ucl_hash_iterate (ucl_hash_t *hashlin, ucl_hash_iter_t *iter); - -/** - * Check whether an iterator has next element - */ -bool ucl_hash_iter_has_next (ucl_hash_iter_t iter); - -#endif diff --git a/src/ucl/src/ucl_internal.h b/src/ucl/src/ucl_internal.h deleted file mode 100644 index e2a6d52fa..000000000 --- a/src/ucl/src/ucl_internal.h +++ /dev/null @@ -1,292 +0,0 @@ -/* Copyright (c) 2013, 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 ''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. - */ - -#ifndef UCL_INTERNAL_H_ -#define UCL_INTERNAL_H_ - -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "utlist.h" -#include "utstring.h" -#include "uthash.h" -#include "ucl.h" -#include "ucl_hash.h" -#include "xxhash.h" - -#ifdef HAVE_OPENSSL -#include -#endif - -/** - * @file rcl_internal.h - * Internal structures and functions of UCL library - */ - -#define UCL_MAX_RECURSION 16 -#define UCL_TRASH_KEY 0 -#define UCL_TRASH_VALUE 1 - -enum ucl_parser_state { - UCL_STATE_INIT = 0, - UCL_STATE_OBJECT, - UCL_STATE_ARRAY, - UCL_STATE_KEY, - UCL_STATE_VALUE, - UCL_STATE_AFTER_VALUE, - UCL_STATE_ARRAY_VALUE, - UCL_STATE_SCOMMENT, - UCL_STATE_MCOMMENT, - UCL_STATE_MACRO_NAME, - UCL_STATE_MACRO, - UCL_STATE_ERROR -}; - -enum ucl_character_type { - UCL_CHARACTER_DENIED = 0, - UCL_CHARACTER_KEY = 1, - UCL_CHARACTER_KEY_START = 1 << 1, - UCL_CHARACTER_WHITESPACE = 1 << 2, - UCL_CHARACTER_WHITESPACE_UNSAFE = 1 << 3, - UCL_CHARACTER_VALUE_END = 1 << 4, - UCL_CHARACTER_VALUE_STR = 1 << 5, - UCL_CHARACTER_VALUE_DIGIT = 1 << 6, - 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_UCL_UNSAFE = 1 << 11 -}; - -struct ucl_macro { - char *name; - ucl_macro_handler handler; - void* ud; - UT_hash_handle hh; -}; - -struct ucl_stack { - ucl_object_t *obj; - struct ucl_stack *next; - int level; -}; - -struct ucl_chunk { - const unsigned char *begin; - const unsigned char *end; - const unsigned char *pos; - size_t remain; - unsigned int line; - unsigned int column; - struct ucl_chunk *next; -}; - -#ifdef HAVE_OPENSSL -struct ucl_pubkey { - EVP_PKEY *key; - struct ucl_pubkey *next; -}; -#else -struct ucl_pubkey { - struct ucl_pubkey *next; -}; -#endif - -struct ucl_variable { - char *var; - char *value; - size_t var_len; - size_t value_len; - struct ucl_variable *next; -}; - -struct ucl_parser { - enum ucl_parser_state state; - enum ucl_parser_state prev_state; - unsigned int recursion; - int flags; - ucl_object_t *top_obj; - ucl_object_t *cur_obj; - struct ucl_macro *macroes; - struct ucl_stack *stack; - struct ucl_chunk *chunks; - struct ucl_pubkey *keys; - struct ucl_variable *variables; - UT_string *err; -}; - -/** - * Unescape json string inplace - * @param str - */ -size_t ucl_unescape_json_string (char *str, size_t len); - -/** - * Handle include macro - * @param data include data - * @param len length of data - * @param ud user data - * @param err error ptr - * @return - */ -bool ucl_include_handler (const unsigned char *data, size_t len, void* ud); - -bool ucl_try_include_handler (const unsigned char *data, size_t len, void* ud); - -/** - * Handle includes macro - * @param data include data - * @param len length of data - * @param ud user data - * @param err error ptr - * @return - */ -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); -size_t ucl_strlcpy_tolower (char *dst, const char *src, size_t siz); - - -#ifdef __GNUC__ -static inline void -ucl_create_err (UT_string **err, const char *fmt, ...) -__attribute__ (( format( printf, 2, 3) )); -#endif - -static inline void -ucl_create_err (UT_string **err, const char *fmt, ...) - -{ - if (*err == NULL) { - utstring_new (*err); - va_list ap; - va_start (ap, fmt); - utstring_printf_va (*err, fmt, ap); - va_end (ap); - } -} - -/** - * Check whether a given string contains a boolean value - * @param obj object to set - * @param start start of a string - * @param len length of a string - * @return true if a string is a boolean value - */ -static inline bool -ucl_maybe_parse_boolean (ucl_object_t *obj, const unsigned char *start, size_t len) -{ - const unsigned char *p = start; - bool ret = false, val = false; - - if (len == 5) { - if ((p[0] == 'f' || p[0] == 'F') && strncasecmp (p, "false", 5) == 0) { - ret = true; - val = false; - } - } - else if (len == 4) { - if ((p[0] == 't' || p[0] == 'T') && strncasecmp (p, "true", 4) == 0) { - ret = true; - val = true; - } - } - else if (len == 3) { - if ((p[0] == 'y' || p[0] == 'Y') && strncasecmp (p, "yes", 3) == 0) { - ret = true; - val = true; - } - else if ((p[0] == 'o' || p[0] == 'O') && strncasecmp (p, "off", 3) == 0) { - ret = true; - val = false; - } - } - else if (len == 2) { - if ((p[0] == 'n' || p[0] == 'N') && strncasecmp (p, "no", 2) == 0) { - ret = true; - val = false; - } - else if ((p[0] == 'o' || p[0] == 'O') && strncasecmp (p, "on", 2) == 0) { - ret = true; - val = true; - } - } - - if (ret) { - obj->type = UCL_BOOLEAN; - obj->value.iv = val; - } - - return ret; -} - -/** - * Check numeric string - * @param obj object to set if a string is numeric - * @param start start of string - * @param end end of string - * @param pos position where parsing has stopped - * @param allow_double allow parsing of floating point values - * @return 0 if string is numeric and error code (EINVAL or ERANGE) in case of conversion error - */ -int ucl_maybe_parse_number (ucl_object_t *obj, - const char *start, const char *end, const char **pos, bool allow_double, bool number_bytes); - - -static inline ucl_object_t * -ucl_hash_search_obj (ucl_hash_t* hashlin, ucl_object_t *obj) -{ - return (ucl_object_t *)ucl_hash_search (hashlin, obj->key, obj->keylen); -} - -static inline ucl_hash_t * -ucl_hash_insert_object (ucl_hash_t *hashlin, ucl_object_t *obj) UCL_WARN_UNUSED_RESULT; - -static inline ucl_hash_t * -ucl_hash_insert_object (ucl_hash_t *hashlin, ucl_object_t *obj) -{ - if (hashlin == NULL) { - hashlin = ucl_hash_create (); - } - ucl_hash_insert (hashlin, obj, obj->key, obj->keylen); - - return hashlin; -} - -/** - * Emit a single object to string - * @param obj - * @return - */ -unsigned char * ucl_object_emit_single_json (ucl_object_t *obj); - -#endif /* UCL_INTERNAL_H_ */ diff --git a/src/ucl/src/ucl_parser.c b/src/ucl/src/ucl_parser.c deleted file mode 100644 index b0662aeb4..000000000 --- a/src/ucl/src/ucl_parser.c +++ /dev/null @@ -1,1869 +0,0 @@ -/* Copyright (c) 2013, 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 ''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. - */ - -#include "ucl.h" -#include "ucl_internal.h" -#include "ucl_chartable.h" - -/** - * @file rcl_parser.c - * The implementation of rcl parser - */ - -struct ucl_parser_saved_state { - unsigned int line; - unsigned int column; - size_t remain; - const unsigned char *pos; -}; - -/** - * Move up to len characters - * @param parser - * @param begin - * @param len - * @return new position in chunk - */ -#define ucl_chunk_skipc(chunk, p) do{ \ - if (*(p) == '\n') { \ - (chunk)->line ++; \ - (chunk)->column = 0; \ - } \ - else (chunk)->column ++; \ - (p++); \ - (chunk)->pos ++; \ - (chunk)->remain --; \ - } while (0) - -/** - * Save parser state - * @param chunk - * @param s - */ -static inline void -ucl_chunk_save_state (struct ucl_chunk *chunk, struct ucl_parser_saved_state *s) -{ - s->column = chunk->column; - s->pos = chunk->pos; - s->line = chunk->line; - s->remain = chunk->remain; -} - -/** - * Restore parser state - * @param chunk - * @param s - */ -static inline void -ucl_chunk_restore_state (struct ucl_chunk *chunk, struct ucl_parser_saved_state *s) -{ - chunk->column = s->column; - chunk->pos = s->pos; - chunk->line = s->line; - chunk->remain = s->remain; -} - -static inline void -ucl_set_err (struct ucl_chunk *chunk, int code, const char *str, UT_string **err) -{ - if (chunk->pos < chunk->end) { - if (isgraph (*chunk->pos)) { - ucl_create_err (err, "error on line %d at column %d: '%s', character: '%c'", - chunk->line, chunk->column, str, *chunk->pos); - } - else { - ucl_create_err (err, "error on line %d at column %d: '%s', character: '0x%02x'", - chunk->line, chunk->column, str, (int)*chunk->pos); - } - } - else { - ucl_create_err (err, "error at the end of chunk: %s", str); - } -} - -/** - * Skip all comments from the current pos resolving nested and multiline comments - * @param parser - * @return - */ -static bool -ucl_skip_comments (struct ucl_parser *parser) -{ - struct ucl_chunk *chunk = parser->chunks; - const unsigned char *p; - int comments_nested = 0; - - p = chunk->pos; - -start: - if (*p == '#') { - if (parser->state != UCL_STATE_SCOMMENT && - parser->state != UCL_STATE_MCOMMENT) { - while (p < chunk->end) { - if (*p == '\n') { - ucl_chunk_skipc (chunk, p); - goto start; - } - ucl_chunk_skipc (chunk, p); - } - } - } - else if (*p == '/' && chunk->remain >= 2) { - if (p[1] == '*') { - ucl_chunk_skipc (chunk, p); - comments_nested ++; - ucl_chunk_skipc (chunk, p); - - while (p < chunk->end) { - if (*p == '*') { - ucl_chunk_skipc (chunk, p); - if (*p == '/') { - comments_nested --; - if (comments_nested == 0) { - ucl_chunk_skipc (chunk, p); - goto start; - } - } - ucl_chunk_skipc (chunk, p); - } - else if (p[0] == '/' && chunk->remain >= 2 && p[1] == '*') { - comments_nested ++; - ucl_chunk_skipc (chunk, p); - ucl_chunk_skipc (chunk, p); - continue; - } - ucl_chunk_skipc (chunk, p); - } - if (comments_nested != 0) { - ucl_set_err (chunk, UCL_ENESTED, "unfinished multiline comment", &parser->err); - return false; - } - } - } - - return true; -} - -/** - * Return multiplier for a character - * @param c multiplier character - * @param is_bytes if true use 1024 multiplier - * @return multiplier - */ -static inline unsigned long -ucl_lex_num_multiplier (const unsigned char c, bool is_bytes) { - const struct { - char c; - long mult_normal; - long mult_bytes; - } multipliers[] = { - {'m', 1000 * 1000, 1024 * 1024}, - {'k', 1000, 1024}, - {'g', 1000 * 1000 * 1000, 1024 * 1024 * 1024} - }; - int i; - - for (i = 0; i < 3; i ++) { - if (tolower (c) == multipliers[i].c) { - if (is_bytes) { - return multipliers[i].mult_bytes; - } - return multipliers[i].mult_normal; - } - } - - return 1; -} - - -/** - * Return multiplier for time scaling - * @param c - * @return - */ -static inline double -ucl_lex_time_multiplier (const unsigned char c) { - const struct { - char c; - double mult; - } multipliers[] = { - {'m', 60}, - {'h', 60 * 60}, - {'d', 60 * 60 * 24}, - {'w', 60 * 60 * 24 * 7}, - {'y', 60 * 60 * 24 * 7 * 365} - }; - int i; - - for (i = 0; i < 5; i ++) { - if (tolower (c) == multipliers[i].c) { - return multipliers[i].mult; - } - } - - return 1; -} - -/** - * Return true if a character is a end of an atom - * @param c - * @return - */ -static inline bool -ucl_lex_is_atom_end (const unsigned char c) -{ - return ucl_test_character (c, UCL_CHARACTER_VALUE_END); -} - -static inline bool -ucl_lex_is_comment (const unsigned char c1, const unsigned char c2) -{ - if (c1 == '/') { - if (c2 == '*') { - return true; - } - } - else if (c1 == '#') { - return true; - } - return false; -} - -/** - * Check variable found - * @param parser - * @param ptr - * @param remain - * @param out_len - * @param strict - * @param found - * @return - */ -static inline const char * -ucl_check_variable_safe (struct ucl_parser *parser, const char *ptr, size_t remain, - size_t *out_len, bool strict, bool *found) -{ - struct ucl_variable *var; - - LL_FOREACH (parser->variables, var) { - if (strict) { - if (remain == var->var_len) { - if (memcmp (ptr, var->var, var->var_len) == 0) { - *out_len += var->value_len; - *found = true; - return (ptr + var->var_len); - } - } - } - else { - if (remain >= var->var_len) { - if (memcmp (ptr, var->var, var->var_len) == 0) { - *out_len += var->value_len; - *found = true; - return (ptr + var->var_len); - } - } - } - } - - return ptr; -} - -/** - * Check for a variable in a given string - * @param parser - * @param ptr - * @param remain - * @param out_len - * @param vars_found - * @return - */ -static const char * -ucl_check_variable (struct ucl_parser *parser, const char *ptr, size_t remain, size_t *out_len, bool *vars_found) -{ - const char *p, *end, *ret = ptr; - bool found = false; - - if (*ptr == '{') { - /* We need to match the variable enclosed in braces */ - p = ptr + 1; - end = ptr + remain; - while (p < end) { - if (*p == '}') { - ret = ucl_check_variable_safe (parser, ptr + 1, p - ptr - 1, out_len, true, &found); - if (found) { - /* {} must be excluded actually */ - ret ++; - if (!*vars_found) { - *vars_found = true; - } - } - else { - *out_len += 2; - } - break; - } - p ++; - } - } - else if (*ptr != '$') { - /* Not count escaped dollar sign */ - ret = ucl_check_variable_safe (parser, ptr, remain, out_len, false, &found); - if (found && !*vars_found) { - *vars_found = true; - } - if (!found) { - (*out_len) ++; - } - } - else { - ret ++; - (*out_len) ++; - } - - return ret; -} - -/** - * Expand a single variable - * @param parser - * @param ptr - * @param remain - * @param dest - * @return - */ -static const char * -ucl_expand_single_variable (struct ucl_parser *parser, const char *ptr, - size_t remain, unsigned char **dest) -{ - unsigned char *d = *dest; - const char *p = ptr + 1, *ret; - struct ucl_variable *var; - bool found = false; - - ret = ptr + 1; - remain --; - - if (*p == '$') { - *d++ = *p++; - *dest = d; - return p; - } - else if (*p == '{') { - p ++; - ret += 2; - remain -= 2; - } - - LL_FOREACH (parser->variables, var) { - if (remain >= var->var_len) { - if (memcmp (p, var->var, var->var_len) == 0) { - memcpy (d, var->value, var->value_len); - ret += var->var_len; - d += var->value_len; - found = true; - break; - } - } - } - if (!found) { - memcpy (d, ptr, 2); - d += 2; - ret --; - } - - *dest = d; - return ret; -} - -/** - * Expand variables in string - * @param parser - * @param dst - * @param src - * @param in_len - * @return - */ -static ssize_t -ucl_expand_variable (struct ucl_parser *parser, unsigned char **dst, - const char *src, size_t in_len) -{ - const char *p, *end = src + in_len; - unsigned char *d; - size_t out_len = 0; - bool vars_found = false; - - p = src; - while (p != end) { - if (*p == '$') { - p = ucl_check_variable (parser, p + 1, end - p - 1, &out_len, &vars_found); - } - else { - p ++; - out_len ++; - } - } - - if (!vars_found) { - /* Trivial case */ - *dst = NULL; - return in_len; - } - - *dst = UCL_ALLOC (out_len + 1); - if (*dst == NULL) { - return in_len; - } - - d = *dst; - p = src; - while (p != end) { - if (*p == '$') { - p = ucl_expand_single_variable (parser, p, end - p, &d); - } - else { - *d++ = *p++; - } - } - - *d = '\0'; - - return out_len; -} - -/** - * Store or copy pointer to the trash stack - * @param parser parser object - * @param src src string - * @param dst destination buffer (trash stack pointer) - * @param dst_const const destination pointer (e.g. value of object) - * @param in_len input length - * @param need_unescape need to unescape source (and copy it) - * @param need_lowercase need to lowercase value (and copy) - * @param need_expand need to expand variables (and copy as well) - * @return output length (excluding \0 symbol) - */ -static inline ssize_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, bool need_expand) -{ - ssize_t ret = -1, tret; - unsigned char *tmp; - - if (need_unescape || need_lowercase || - (need_expand && parser->variables != NULL) || - !(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", &parser->err); - return false; - } - if (need_lowercase) { - ret = ucl_strlcpy_tolower (*dst, src, in_len + 1); - } - else { - ret = ucl_strlcpy_unsafe (*dst, src, in_len + 1); - } - - if (need_unescape) { - ret = ucl_unescape_json_string (*dst, ret); - } - if (need_expand) { - tmp = *dst; - tret = ret; - ret = ucl_expand_variable (parser, dst, tmp, ret); - if (*dst == NULL) { - /* Nothing to expand */ - *dst = tmp; - ret = tret; - } - } - *dst_const = *dst; - } - else { - *dst_const = src; - ret = in_len; - } - - return ret; -} - -/** - * Create and append an object at the specified level - * @param parser - * @param is_array - * @param level - * @return - */ -static inline ucl_object_t * -ucl_add_parser_stack (ucl_object_t *obj, struct ucl_parser *parser, bool is_array, int level) -{ - struct ucl_stack *st; - - if (!is_array) { - if (obj == NULL) { - obj = ucl_object_typed_new (UCL_OBJECT); - } - else { - obj->type = UCL_OBJECT; - } - obj->value.ov = ucl_hash_create (); - parser->state = UCL_STATE_KEY; - } - else { - if (obj == NULL) { - obj = ucl_object_typed_new (UCL_ARRAY); - } - else { - obj->type = UCL_ARRAY; - } - parser->state = UCL_STATE_VALUE; - } - - st = UCL_ALLOC (sizeof (struct ucl_stack)); - st->obj = obj; - st->level = level; - LL_PREPEND (parser->stack, st); - parser->cur_obj = obj; - - return obj; -} - -int -ucl_maybe_parse_number (ucl_object_t *obj, - const char *start, const char *end, const char **pos, bool allow_double, bool number_bytes) -{ - const char *p = start, *c = start; - char *endptr; - bool got_dot = false, got_exp = false, need_double = false, - is_date = false, valid_start = false, is_hex = false, - is_neg = false; - double dv = 0; - int64_t lv = 0; - - if (*p == '-') { - is_neg = true; - c ++; - p ++; - } - while (p < end) { - if (is_hex && isxdigit (*p)) { - p ++; - } - else if (isdigit (*p)) { - valid_start = true; - p ++; - } - else if (!is_hex && (*p == 'x' || *p == 'X')) { - is_hex = true; - allow_double = false; - c = p + 1; - } - else if (allow_double) { - if (p == c) { - /* Empty digits sequence, not a number */ - *pos = start; - return EINVAL; - } - else if (*p == '.') { - if (got_dot) { - /* Double dots, not a number */ - *pos = start; - return EINVAL; - } - else { - got_dot = true; - need_double = true; - p ++; - } - } - else if (*p == 'e' || *p == 'E') { - if (got_exp) { - /* Double exp, not a number */ - *pos = start; - return EINVAL; - } - else { - got_exp = true; - need_double = true; - p ++; - if (p >= end) { - *pos = start; - return EINVAL; - } - if (!isdigit (*p) && *p != '+' && *p != '-') { - /* Wrong exponent sign */ - *pos = start; - return EINVAL; - } - else { - p ++; - } - } - } - else { - /* Got the end of the number, need to check */ - break; - } - } - else { - break; - } - } - - if (!valid_start) { - *pos = start; - return EINVAL; - } - - errno = 0; - if (need_double) { - dv = strtod (c, &endptr); - } - else { - if (is_hex) { - lv = strtoimax (c, &endptr, 16); - } - else { - lv = strtoimax (c, &endptr, 10); - } - } - if (errno == ERANGE) { - *pos = start; - return ERANGE; - } - - /* Now check endptr */ - if (endptr == NULL || ucl_lex_is_atom_end (*endptr) || *endptr == '\0') { - p = endptr; - goto set_obj; - } - - if (endptr < end && endptr != start) { - p = endptr; - switch (*p) { - case 'm': - case 'M': - case 'g': - case 'G': - case 'k': - case 'K': - if (end - p >= 2) { - if (p[1] == 's' || p[1] == 'S') { - /* Milliseconds */ - if (!need_double) { - need_double = true; - dv = lv; - } - is_date = true; - if (p[0] == 'm' || p[0] == 'M') { - dv /= 1000.; - } - else { - dv *= ucl_lex_num_multiplier (*p, false); - } - p += 2; - goto set_obj; - } - else if (number_bytes || (p[1] == 'b' || p[1] == 'B')) { - /* Bytes */ - if (need_double) { - need_double = false; - lv = dv; - } - lv *= ucl_lex_num_multiplier (*p, true); - p += 2; - goto set_obj; - } - else if (ucl_lex_is_atom_end (p[1])) { - if (need_double) { - dv *= ucl_lex_num_multiplier (*p, false); - } - else { - lv *= ucl_lex_num_multiplier (*p, number_bytes); - } - p ++; - goto set_obj; - } - else if (end - p >= 3) { - if (tolower (p[0]) == 'm' && - tolower (p[1]) == 'i' && - tolower (p[2]) == 'n') { - /* Minutes */ - if (!need_double) { - need_double = true; - dv = lv; - } - is_date = true; - dv *= 60.; - p += 3; - goto set_obj; - } - } - } - else { - if (need_double) { - dv *= ucl_lex_num_multiplier (*p, false); - } - else { - lv *= ucl_lex_num_multiplier (*p, number_bytes); - } - p ++; - goto set_obj; - } - break; - case 'S': - case 's': - if (p == end - 1 || ucl_lex_is_atom_end (p[1])) { - if (!need_double) { - need_double = true; - dv = lv; - } - p ++; - is_date = true; - goto set_obj; - } - break; - case 'h': - case 'H': - case 'd': - case 'D': - case 'w': - case 'W': - case 'Y': - case 'y': - if (p == end - 1 || ucl_lex_is_atom_end (p[1])) { - if (!need_double) { - need_double = true; - dv = lv; - } - is_date = true; - dv *= ucl_lex_time_multiplier (*p); - p ++; - goto set_obj; - } - break; - } - } - - *pos = c; - return EINVAL; - - set_obj: - if (allow_double && (need_double || is_date)) { - if (!is_date) { - obj->type = UCL_FLOAT; - } - else { - obj->type = UCL_TIME; - } - obj->value.dv = is_neg ? (-dv) : dv; - } - else { - obj->type = UCL_INT; - obj->value.iv = is_neg ? (-lv) : lv; - } - *pos = p; - return 0; -} - -/** - * Parse possible number - * @param parser - * @param chunk - * @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) -{ - const unsigned char *pos; - int ret; - - ret = ucl_maybe_parse_number (obj, chunk->pos, chunk->end, (const char **)&pos, true, false); - - if (ret == 0) { - chunk->remain -= pos - chunk->pos; - chunk->column += pos - chunk->pos; - chunk->pos = pos; - return true; - } - else if (ret == ERANGE) { - ucl_set_err (chunk, ERANGE, "numeric value out of range", &parser->err); - } - - return false; -} - -/** - * Parse quoted string with possible escapes - * @param parser - * @param chunk - * @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, bool *ucl_escape, bool *var_expand) -{ - const unsigned char *p = chunk->pos; - unsigned char c; - int i; - - while (p < chunk->end) { - c = *p; - if (c < 0x1F) { - /* Unmasked control character */ - if (c == '\n') { - ucl_set_err (chunk, UCL_ESYNTAX, "unexpected newline", &parser->err); - } - else { - ucl_set_err (chunk, UCL_ESYNTAX, "unexpected control character", &parser->err); - } - return false; - } - else if (c == '\\') { - ucl_chunk_skipc (chunk, p); - c = *p; - if (p >= chunk->end) { - ucl_set_err (chunk, UCL_ESYNTAX, "unfinished escape character", &parser->err); - return false; - } - else if (ucl_test_character (c, UCL_CHARACTER_ESCAPE)) { - if (c == 'u') { - 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", &parser->err); - return false; - } - ucl_chunk_skipc (chunk, p); - } - if (p >= chunk->end) { - ucl_set_err (chunk, UCL_ESYNTAX, "unfinished escape character", &parser->err); - return false; - } - } - else { - ucl_chunk_skipc (chunk, p); - } - } - *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; - } - else if (c == '$') { - *var_expand = true; - } - ucl_chunk_skipc (chunk, p); - } - - ucl_set_err (chunk, UCL_ESYNTAX, "no quote at the end of json string", &parser->err); - return false; -} - -/** - * Parse a key in an object - * @param parser - * @param chunk - * @return true if a key has been parsed - */ -static bool -ucl_parse_key (struct ucl_parser *parser, struct ucl_chunk *chunk, bool *next_key, bool *end_of_object) -{ - const unsigned char *p, *c = NULL, *end, *t; - const char *key; - bool got_quote = false, got_eq = false, got_semicolon = false, - need_unescape = false, ucl_escape = false, var_expand = false, - got_content = false, got_sep = false; - ucl_object_t *nobj, *tobj; - ucl_hash_t *container; - ssize_t keylen; - - p = chunk->pos; - - if (*p == '.') { - /* It is macro actually */ - ucl_chunk_skipc (chunk, p); - parser->prev_state = parser->state; - parser->state = UCL_STATE_MACRO_NAME; - return true; - } - while (p < chunk->end) { - /* - * A key must start with alpha, number, '/' or '_' and end with space character - */ - if (c == NULL) { - if (chunk->remain >= 2 && ucl_lex_is_comment (p[0], p[1])) { - if (!ucl_skip_comments (parser)) { - return false; - } - p = chunk->pos; - } - else if (ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE)) { - ucl_chunk_skipc (chunk, p); - } - else if (ucl_test_character (*p, UCL_CHARACTER_KEY_START)) { - /* The first symbol */ - c = p; - ucl_chunk_skipc (chunk, p); - got_content = true; - } - else if (*p == '"') { - /* JSON style key */ - c = p + 1; - got_quote = true; - got_content = true; - ucl_chunk_skipc (chunk, p); - } - else if (*p == '}') { - /* We have actually end of an object */ - *end_of_object = true; - return true; - } - else if (*p == '.') { - ucl_chunk_skipc (chunk, p); - parser->prev_state = parser->state; - parser->state = UCL_STATE_MACRO_NAME; - return true; - } - else { - /* Invalid identifier */ - ucl_set_err (chunk, UCL_ESYNTAX, "key must begin with a letter", &parser->err); - return false; - } - } - else { - /* Parse the body of a key */ - if (!got_quote) { - if (ucl_test_character (*p, UCL_CHARACTER_KEY)) { - got_content = true; - ucl_chunk_skipc (chunk, p); - } - else if (ucl_test_character (*p, UCL_CHARACTER_KEY_SEP)) { - end = p; - break; - } - else { - 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, &ucl_escape, &var_expand)) { - return false; - } - /* Always escape keys obtained via json */ - end = chunk->pos - 1; - p = chunk->pos; - break; - } - } - } - - if (p >= chunk->end && got_content) { - ucl_set_err (chunk, UCL_ESYNTAX, "unfinished key", &parser->err); - return false; - } - else if (!got_content) { - return true; - } - *end_of_object = false; - /* We are now at the end of the key, need to parse the rest */ - while (p < chunk->end) { - if (ucl_test_character (*p, UCL_CHARACTER_WHITESPACE)) { - ucl_chunk_skipc (chunk, p); - } - else if (*p == '=') { - if (!got_eq && !got_semicolon) { - ucl_chunk_skipc (chunk, p); - got_eq = true; - } - else { - ucl_set_err (chunk, UCL_ESYNTAX, "unexpected '=' character", &parser->err); - return false; - } - } - else if (*p == ':') { - if (!got_eq && !got_semicolon) { - ucl_chunk_skipc (chunk, p); - got_semicolon = true; - } - else { - ucl_set_err (chunk, UCL_ESYNTAX, "unexpected ':' character", &parser->err); - return false; - } - } - else if (chunk->remain >= 2 && ucl_lex_is_comment (p[0], p[1])) { - /* Check for comment */ - if (!ucl_skip_comments (parser)) { - return false; - } - p = chunk->pos; - } - else { - /* Start value */ - break; - } - } - - if (p >= chunk->end && got_content) { - ucl_set_err (chunk, UCL_ESYNTAX, "unfinished key", &parser->err); - return false; - } - - got_sep = got_semicolon || got_eq; - - if (!got_sep) { - /* - * Maybe we have more keys nested, so search for termination character. - * Possible choices: - * 1) key1 key2 ... keyN [:=] value <- we treat that as error - * 2) key1 ... keyN {} or [] <- we treat that as nested objects - * 3) key1 value[;,\n] <- we treat that as linear object - */ - t = p; - *next_key = false; - while (ucl_test_character (*t, UCL_CHARACTER_WHITESPACE)) { - t ++; - } - /* Check first non-space character after a key */ - if (*t != '{' && *t != '[') { - while (t < chunk->end) { - if (*t == ',' || *t == ';' || *t == '\n' || *t == '\r') { - break; - } - else if (*t == '{' || *t == '[') { - *next_key = true; - break; - } - t ++; - } - } - } - - /* 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_PARSER_KEY_LOWERCASE, false); - if (keylen == -1) { - return false; - } - else if (keylen == 0) { - ucl_set_err (chunk, UCL_ESYNTAX, "empty keys are not allowed", &parser->err); - return false; - } - - container = parser->stack->obj->value.ov; - nobj->key = key; - nobj->keylen = keylen; - tobj = ucl_hash_search_obj (container, nobj); - if (tobj == NULL) { - container = ucl_hash_insert_object (container, nobj); - nobj->prev = nobj; - nobj->next = NULL; - parser->stack->obj->len ++; - } - else { - DL_APPEND (tobj, nobj); - } - - if (ucl_escape) { - nobj->flags |= UCL_OBJECT_NEED_KEY_ESCAPE; - } - parser->stack->obj->value.ov = container; - - parser->cur_obj = nobj; - - return true; -} - -/** - * Parse a cl string - * @param parser - * @param chunk - * @return true if a key has been parsed - */ -static bool -ucl_parse_string_value (struct ucl_parser *parser, - struct ucl_chunk *chunk, bool *var_expand, bool *need_unescape) -{ - const unsigned char *p; - enum { - UCL_BRACE_ROUND = 0, - UCL_BRACE_SQUARE, - UCL_BRACE_FIGURE - }; - int braces[3][2] = {{0, 0}, {0, 0}, {0, 0}}; - - p = chunk->pos; - - while (p < chunk->end) { - - /* Skip pairs of figure braces */ - if (*p == '{') { - braces[UCL_BRACE_FIGURE][0] ++; - } - else if (*p == '}') { - braces[UCL_BRACE_FIGURE][1] ++; - if (braces[UCL_BRACE_FIGURE][1] <= braces[UCL_BRACE_FIGURE][0]) { - /* This is not a termination symbol, continue */ - ucl_chunk_skipc (chunk, p); - continue; - } - } - /* Skip pairs of square braces */ - else if (*p == '[') { - braces[UCL_BRACE_SQUARE][0] ++; - } - else if (*p == ']') { - braces[UCL_BRACE_SQUARE][1] ++; - if (braces[UCL_BRACE_SQUARE][1] <= braces[UCL_BRACE_SQUARE][0]) { - /* This is not a termination symbol, continue */ - ucl_chunk_skipc (chunk, p); - continue; - } - } - else if (*p == '$') { - *var_expand = true; - } - else if (*p == '\\') { - *need_unescape = true; - ucl_chunk_skipc (chunk, p); - if (p < chunk->end) { - ucl_chunk_skipc (chunk, p); - } - continue; - } - - if (ucl_lex_is_atom_end (*p) || (chunk->remain >= 2 && ucl_lex_is_comment (p[0], p[1]))) { - break; - } - ucl_chunk_skipc (chunk, p); - } - - if (p >= chunk->end) { - ucl_set_err (chunk, UCL_ESYNTAX, "unfinished value", &parser->err); - return false; - } - - return true; -} - -/** - * Parse multiline string ending with \n{term}\n - * @param parser - * @param chunk - * @param term - * @param term_len - * @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, - bool *var_expand) -{ - const unsigned char *p, *c; - bool newline = false; - int len = 0; - - p = chunk->pos; - - c = p; - - while (p < chunk->end) { - if (newline) { - if (chunk->end - p < term_len) { - return 0; - } - else if (memcmp (p, term, term_len) == 0 && (p[term_len] == '\n' || p[term_len] == '\r')) { - len = p - c; - chunk->remain -= term_len; - chunk->pos = p + term_len; - chunk->column = term_len; - *beg = c; - break; - } - } - if (*p == '\n') { - newline = true; - } - else { - if (*p == '$') { - *var_expand = true; - } - newline = false; - } - ucl_chunk_skipc (chunk, p); - } - - return len; -} - -/** - * Handle value data - * @param parser - * @param chunk - * @return - */ -static bool -ucl_parse_value (struct ucl_parser *parser, struct ucl_chunk *chunk) -{ - const unsigned char *p, *c; - ucl_object_t *obj = NULL, *t; - unsigned int stripped_spaces; - int str_len; - bool need_unescape = false, ucl_escape = false, var_expand = false; - - p = chunk->pos; - - while (p < chunk->end) { - if (obj == NULL) { - if (parser->stack->obj->type == UCL_ARRAY) { - /* Object must be allocated */ - obj = ucl_object_new (); - t = parser->stack->obj->value.av; - DL_APPEND (t, obj); - parser->cur_obj = obj; - parser->stack->obj->value.av = t; - parser->stack->obj->len ++; - } - else { - /* Object has been already allocated */ - obj = parser->cur_obj; - } - } - c = p; - switch (*p) { - case '"': - ucl_chunk_skipc (chunk, p); - if (!ucl_lex_json_string (parser, chunk, &need_unescape, &ucl_escape, &var_expand)) { - 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, var_expand)) == -1) { - return false; - } - obj->len = str_len; - parser->state = UCL_STATE_AFTER_VALUE; - p = chunk->pos; - return true; - break; - case '{': - /* We have a new object */ - obj = ucl_add_parser_stack (obj, parser, false, parser->stack->level); - - ucl_chunk_skipc (chunk, p); - return true; - break; - case '[': - /* We have a new array */ - obj = ucl_add_parser_stack (obj, parser, true, parser->stack->level); - - ucl_chunk_skipc (chunk, p); - return true; - break; - case '<': - /* We have something like multiline value, which must be <<[A-Z]+\n */ - if (chunk->end - p > 3) { - if (memcmp (p, "<<", 2) == 0) { - p += 2; - /* We allow only uppercase characters in multiline definitions */ - while (p < chunk->end && *p >= 'A' && *p <= 'Z') { - p ++; - } - if (*p =='\n') { - /* Set chunk positions and start multiline parsing */ - c += 2; - chunk->remain -= p - c; - chunk->pos = p + 1; - chunk->column = 0; - chunk->line ++; - if ((str_len = ucl_parse_multiline_string (parser, chunk, c, - p - c, &c, &var_expand)) == 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, var_expand)) == -1) { - return false; - } - obj->len = str_len; - parser->state = UCL_STATE_AFTER_VALUE; - return true; - } - } - } - /* Fallback to ordinary strings */ - default: - /* Skip any spaces and comments */ - if (ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE) || - (chunk->remain >= 2 && ucl_lex_is_comment (p[0], p[1]))) { - while (p < chunk->end && ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE)) { - ucl_chunk_skipc (chunk, p); - } - if (!ucl_skip_comments (parser)) { - return false; - } - p = chunk->pos; - continue; - } - /* Parse atom */ - if (ucl_test_character (*p, UCL_CHARACTER_VALUE_DIGIT_START)) { - if (!ucl_lex_number (parser, chunk, obj)) { - if (parser->state == UCL_STATE_ERROR) { - return false; - } - } - else { - parser->state = UCL_STATE_AFTER_VALUE; - return true; - } - /* Fallback to normal string */ - } - - if (!ucl_parse_string_value (parser, chunk, &var_expand, &need_unescape)) { - return false; - } - /* Cut trailing spaces */ - stripped_spaces = 0; - while (ucl_test_character (*(chunk->pos - 1 - stripped_spaces), - UCL_CHARACTER_WHITESPACE)) { - stripped_spaces ++; - } - str_len = chunk->pos - c - stripped_spaces; - if (str_len <= 0) { - ucl_set_err (chunk, 0, "string value must not be empty", &parser->err); - return false; - } - else if (str_len == 4 && memcmp (c, "null", 4) == 0) { - obj->len = 0; - obj->type = UCL_NULL; - } - else if (!ucl_maybe_parse_boolean (obj, c, str_len)) { - 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, need_unescape, - false, var_expand)) == -1) { - return false; - } - obj->len = str_len; - } - parser->state = UCL_STATE_AFTER_VALUE; - p = chunk->pos; - - return true; - break; - } - } - - return true; -} - -/** - * Handle after value data - * @param parser - * @param chunk - * @return - */ -static bool -ucl_parse_after_value (struct ucl_parser *parser, struct ucl_chunk *chunk) -{ - const unsigned char *p; - bool got_sep = false; - struct ucl_stack *st; - - p = chunk->pos; - - while (p < chunk->end) { - if (ucl_test_character (*p, UCL_CHARACTER_WHITESPACE)) { - /* Skip whitespaces */ - ucl_chunk_skipc (chunk, p); - } - else if (chunk->remain >= 2 && ucl_lex_is_comment (p[0], p[1])) { - /* Skip comment */ - if (!ucl_skip_comments (parser)) { - return false; - } - /* Treat comment as a separator */ - got_sep = true; - p = chunk->pos; - } - else if (ucl_test_character (*p, UCL_CHARACTER_VALUE_END)) { - if (*p == '}' || *p == ']') { - if (parser->stack == NULL) { - ucl_set_err (chunk, UCL_ESYNTAX, "end of array or object detected without corresponding start", &parser->err); - return false; - } - if ((*p == '}' && parser->stack->obj->type == UCL_OBJECT) || - (*p == ']' && parser->stack->obj->type == UCL_ARRAY)) { - - /* Pop all nested objects from a stack */ - st = parser->stack; - parser->stack = st->next; - UCL_FREE (sizeof (struct ucl_stack), st); - - while (parser->stack != NULL) { - st = parser->stack; - if (st->next == NULL || st->next->level == st->level) { - break; - } - parser->stack = st->next; - UCL_FREE (sizeof (struct ucl_stack), st); - } - } - else { - ucl_set_err (chunk, UCL_ESYNTAX, "unexpected terminating symbol detected", &parser->err); - return false; - } - - if (parser->stack == NULL) { - /* Ignore everything after a top object */ - return true; - } - else { - ucl_chunk_skipc (chunk, p); - } - got_sep = true; - } - else { - /* Got a separator */ - got_sep = true; - ucl_chunk_skipc (chunk, p); - } - } - else { - /* Anything else */ - if (!got_sep) { - ucl_set_err (chunk, UCL_ESYNTAX, "delimiter is missing", &parser->err); - return false; - } - return true; - } - } - - return true; -} - -/** - * Handle macro data - * @param parser - * @param chunk - * @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) -{ - const unsigned char *p, *c; - bool need_unescape = false, ucl_escape = false, var_expand = false; - - p = chunk->pos; - - switch (*p) { - case '"': - /* We have macro value encoded in quotes */ - c = p; - ucl_chunk_skipc (chunk, p); - if (!ucl_lex_json_string (parser, chunk, &need_unescape, &ucl_escape, &var_expand)) { - return false; - } - - *macro_start = c + 1; - *macro_len = chunk->pos - c - 2; - p = chunk->pos; - break; - case '{': - /* We got a multiline macro body */ - ucl_chunk_skipc (chunk, p); - /* Skip spaces at the beginning */ - while (p < chunk->end) { - if (ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE)) { - ucl_chunk_skipc (chunk, p); - } - else { - break; - } - } - c = p; - while (p < chunk->end) { - if (*p == '}') { - break; - } - ucl_chunk_skipc (chunk, p); - } - *macro_start = c; - *macro_len = p - c; - ucl_chunk_skipc (chunk, p); - break; - default: - /* Macro is not enclosed in quotes or braces */ - c = p; - while (p < chunk->end) { - if (ucl_lex_is_atom_end (*p)) { - break; - } - ucl_chunk_skipc (chunk, p); - } - *macro_start = c; - *macro_len = p - c; - break; - } - - /* We are at the end of a macro */ - /* Skip ';' and space characters and return to previous state */ - while (p < chunk->end) { - if (!ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE) && *p != ';') { - break; - } - ucl_chunk_skipc (chunk, p); - } - return true; -} - -/** - * 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 -ucl_state_machine (struct ucl_parser *parser) -{ - ucl_object_t *obj; - struct ucl_chunk *chunk = parser->chunks; - const unsigned char *p, *c = NULL, *macro_start = NULL; - unsigned char *macro_escaped; - size_t macro_len = 0; - struct ucl_macro *macro = NULL; - bool next_key = false, end_of_object = false; - - if (parser->top_obj == NULL) { - if (*chunk->pos == '[') { - obj = ucl_add_parser_stack (NULL, parser, true, 0); - } - else { - obj = ucl_add_parser_stack (NULL, parser, false, 0); - } - parser->top_obj = obj; - parser->cur_obj = obj; - parser->state = UCL_STATE_INIT; - } - - p = chunk->pos; - while (chunk->pos < chunk->end) { - switch (parser->state) { - case UCL_STATE_INIT: - /* - * At the init state we can either go to the parse array or object - * if we got [ or { correspondingly or can just treat new data as - * a key of newly created object - */ - obj = parser->cur_obj; - if (!ucl_skip_comments (parser)) { - parser->prev_state = parser->state; - parser->state = UCL_STATE_ERROR; - return false; - } - else { - p = chunk->pos; - if (*p == '[') { - parser->state = UCL_STATE_VALUE; - ucl_chunk_skipc (chunk, p); - } - else { - parser->state = UCL_STATE_KEY; - if (*p == '{') { - ucl_chunk_skipc (chunk, p); - } - } - } - break; - case UCL_STATE_KEY: - /* Skip any spaces */ - while (p < chunk->end && ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE)) { - ucl_chunk_skipc (chunk, p); - } - if (*p == '}') { - /* We have the end of an object */ - parser->state = UCL_STATE_AFTER_VALUE; - continue; - } - if (parser->stack == NULL) { - /* No objects are on stack, but we want to parse a key */ - ucl_set_err (chunk, UCL_ESYNTAX, "top object is finished but the parser " - "expects a key", &parser->err); - parser->prev_state = parser->state; - parser->state = UCL_STATE_ERROR; - return false; - } - if (!ucl_parse_key (parser, chunk, &next_key, &end_of_object)) { - parser->prev_state = parser->state; - parser->state = UCL_STATE_ERROR; - return false; - } - if (end_of_object) { - p = chunk->pos; - parser->state = UCL_STATE_AFTER_VALUE; - continue; - } - else if (parser->state != UCL_STATE_MACRO_NAME) { - if (next_key && parser->stack->obj->type == UCL_OBJECT) { - /* Parse more keys and nest objects accordingly */ - obj = ucl_add_parser_stack (parser->cur_obj, parser, false, parser->stack->level + 1); - } - else { - parser->state = UCL_STATE_VALUE; - } - } - else { - c = chunk->pos; - } - p = chunk->pos; - break; - case UCL_STATE_VALUE: - /* We need to check what we do have */ - if (!ucl_parse_value (parser, chunk)) { - parser->prev_state = parser->state; - parser->state = UCL_STATE_ERROR; - return false; - } - /* State is set in ucl_parse_value call */ - p = chunk->pos; - break; - case UCL_STATE_AFTER_VALUE: - if (!ucl_parse_after_value (parser, chunk)) { - parser->prev_state = parser->state; - parser->state = UCL_STATE_ERROR; - return false; - } - if (parser->stack != NULL) { - if (parser->stack->obj->type == UCL_OBJECT) { - parser->state = UCL_STATE_KEY; - } - else { - /* Array */ - parser->state = UCL_STATE_VALUE; - } - } - else { - /* 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)) { - ucl_chunk_skipc (chunk, p); - } - else if (p - c > 0) { - /* We got macro name */ - HASH_FIND (hh, parser->macroes, c, (p - c), 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 */ - while (p < chunk->end) { - if (!ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE)) { - if (chunk->remain >= 2 && ucl_lex_is_comment (p[0], p[1])) { - /* Skip comment */ - if (!ucl_skip_comments (parser)) { - return false; - } - p = chunk->pos; - } - break; - } - ucl_chunk_skipc (chunk, p); - } - parser->state = UCL_STATE_MACRO; - } - break; - case UCL_STATE_MACRO: - if (!ucl_parse_macro_value (parser, chunk, macro, - ¯o_start, ¯o_len)) { - parser->prev_state = parser->state; - parser->state = UCL_STATE_ERROR; - return false; - } - macro_len = ucl_expand_variable (parser, ¯o_escaped, macro_start, macro_len); - parser->state = parser->prev_state; - if (macro_escaped == NULL) { - if (!macro->handler (macro_start, macro_len, macro->ud)) { - return false; - } - } - else { - if (!macro->handler (macro_escaped, macro_len, macro->ud)) { - UCL_FREE (macro_len + 1, macro_escaped); - return false; - } - UCL_FREE (macro_len + 1, macro_escaped); - } - p = chunk->pos; - break; - default: - /* TODO: add all states */ - ucl_set_err (chunk, UCL_EINTERNAL, "internal error: parser is in an unknown state", &parser->err); - parser->state = UCL_STATE_ERROR; - return false; - } - } - - return true; -} - -struct ucl_parser* -ucl_parser_new (int flags) -{ - struct ucl_parser *new; - - new = UCL_ALLOC (sizeof (struct ucl_parser)); - memset (new, 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); - - new->flags = flags; - - /* Initial assumption about filevars */ - ucl_parser_set_filevars (new, NULL, false); - - return new; -} - - -void -ucl_parser_register_macro (struct ucl_parser *parser, const char *macro, - ucl_macro_handler handler, void* ud) -{ - struct ucl_macro *new; - - new = UCL_ALLOC (sizeof (struct ucl_macro)); - memset (new, 0, sizeof (struct ucl_macro)); - new->handler = handler; - new->name = strdup (macro); - new->ud = ud; - HASH_ADD_KEYPTR (hh, parser->macroes, new->name, strlen (new->name), new); -} - -void -ucl_parser_register_variable (struct ucl_parser *parser, const char *var, - const char *value) -{ - struct ucl_variable *new = NULL, *cur; - - if (var == NULL) { - return; - } - - /* Find whether a variable already exists */ - LL_FOREACH (parser->variables, cur) { - if (strcmp (cur->var, var) == 0) { - new = cur; - break; - } - } - - if (value == NULL) { - - if (new != NULL) { - /* Remove variable */ - LL_DELETE (parser->variables, new); - free (new->var); - free (new->value); - UCL_FREE (sizeof (struct ucl_variable), new); - } - else { - /* Do nothing */ - return; - } - } - else { - if (new == NULL) { - new = UCL_ALLOC (sizeof (struct ucl_variable)); - memset (new, 0, sizeof (struct ucl_variable)); - new->var = strdup (var); - new->var_len = strlen (var); - new->value = strdup (value); - new->value_len = strlen (value); - - LL_PREPEND (parser->variables, new); - } - else { - free (new->value); - new->value = strdup (value); - new->value_len = strlen (value); - } - } -} - -bool -ucl_parser_add_chunk (struct ucl_parser *parser, const unsigned char *data, - size_t len) -{ - struct ucl_chunk *chunk; - - if (parser->state != UCL_STATE_ERROR) { - chunk = UCL_ALLOC (sizeof (struct ucl_chunk)); - chunk->begin = data; - chunk->remain = len; - chunk->pos = chunk->begin; - chunk->end = chunk->begin + len; - chunk->line = 1; - chunk->column = 0; - LL_PREPEND (parser->chunks, chunk); - parser->recursion ++; - if (parser->recursion > UCL_MAX_RECURSION) { - ucl_create_err (&parser->err, "maximum include nesting limit is reached: %d", - parser->recursion); - return false; - } - return ucl_state_machine (parser); - } - - 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 deleted file mode 100644 index 7dad6f32d..000000000 --- a/src/ucl/src/ucl_util.c +++ /dev/null @@ -1,1157 +0,0 @@ -/* Copyright (c) 2013, 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 ''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. - */ - -#include "ucl.h" -#include "ucl_internal.h" -#include "ucl_chartable.h" - -#include /* For dirname */ - -#ifdef HAVE_OPENSSL -#include -#include -#include -#include -#include -#endif - -/** - * @file rcl_util.c - * Utilities for rcl parsing - */ - - -static void -ucl_object_free_internal (ucl_object_t *obj, bool allow_rec) -{ - ucl_object_t *sub, *tmp; - - while (obj != NULL) { - if (obj->trash_stack[UCL_TRASH_KEY] != NULL) { - UCL_FREE (obj->hh.keylen, obj->trash_stack[UCL_TRASH_KEY]); - } - if (obj->trash_stack[UCL_TRASH_VALUE] != NULL) { - UCL_FREE (obj->len, obj->trash_stack[UCL_TRASH_VALUE]); - } - - if (obj->type == UCL_ARRAY) { - sub = obj->value.av; - while (sub != NULL) { - tmp = sub->next; - ucl_object_free_internal (sub, false); - sub = tmp; - } - } - else if (obj->type == UCL_OBJECT) { - if (obj->value.ov != NULL) { - ucl_hash_destroy (obj->value.ov, (ucl_hash_free_func *)ucl_object_unref); - } - } - tmp = obj->next; - UCL_FREE (sizeof (ucl_object_t), obj); - obj = tmp; - - if (!allow_rec) { - break; - } - } -} - -void -ucl_object_free (ucl_object_t *obj) -{ - ucl_object_free_internal (obj, true); -} - -size_t -ucl_unescape_json_string (char *str, size_t len) -{ - char *t = str, *h = str; - int i, uval; - - /* t is target (tortoise), h is source (hare) */ - - while (len) { - if (*h == '\\') { - h ++; - switch (*h) { - case 'n': - *t++ = '\n'; - break; - case 'r': - *t++ = '\r'; - break; - case 'b': - *t++ = '\b'; - break; - case 't': - *t++ = '\t'; - break; - case 'f': - *t++ = '\f'; - break; - case '\\': - *t++ = '\\'; - break; - case '"': - *t++ = '"'; - break; - case 'u': - /* Unicode escape */ - uval = 0; - for (i = 0; i < 4; i++) { - uval <<= 4; - if (isdigit (h[i])) { - uval += h[i] - '0'; - } - else if (h[i] >= 'a' && h[i] <= 'f') { - uval += h[i] - 'a' + 10; - } - else if (h[i] >= 'A' && h[i] <= 'F') { - uval += h[i] - 'A' + 10; - } - } - h += 3; - len -= 3; - /* Encode */ - if(uval < 0x80) { - t[0] = (char)uval; - t ++; - } - else if(uval < 0x800) { - t[0] = 0xC0 + ((uval & 0x7C0) >> 6); - t[1] = 0x80 + ((uval & 0x03F)); - t += 2; - } - else if(uval < 0x10000) { - t[0] = 0xE0 + ((uval & 0xF000) >> 12); - t[1] = 0x80 + ((uval & 0x0FC0) >> 6); - t[2] = 0x80 + ((uval & 0x003F)); - t += 3; - } - else if(uval <= 0x10FFFF) { - t[0] = 0xF0 + ((uval & 0x1C0000) >> 18); - t[1] = 0x80 + ((uval & 0x03F000) >> 12); - t[2] = 0x80 + ((uval & 0x000FC0) >> 6); - t[3] = 0x80 + ((uval & 0x00003F)); - t += 4; - } - else { - *t++ = '?'; - } - break; - default: - *t++ = *h; - break; - } - h ++; - len --; - } - else { - *t++ = *h++; - } - len --; - } - *t = '\0'; - - return (t - str); -} - -char * -ucl_copy_key_trash (ucl_object_t *obj) -{ - if (obj->trash_stack[UCL_TRASH_KEY] == NULL && obj->key != NULL) { - obj->trash_stack[UCL_TRASH_KEY] = malloc (obj->keylen + 1); - if (obj->trash_stack[UCL_TRASH_KEY] != NULL) { - memcpy (obj->trash_stack[UCL_TRASH_KEY], obj->key, obj->keylen); - obj->trash_stack[UCL_TRASH_KEY][obj->keylen] = '\0'; - } - obj->key = obj->trash_stack[UCL_TRASH_KEY]; - obj->flags |= UCL_OBJECT_ALLOCATED_KEY; - } - - return obj->trash_stack[UCL_TRASH_KEY]; -} - -char * -ucl_copy_value_trash (ucl_object_t *obj) -{ - if (obj->trash_stack[UCL_TRASH_VALUE] == NULL) { - if (obj->type == UCL_STRING) { - /* Special case for strings */ - obj->trash_stack[UCL_TRASH_VALUE] = malloc (obj->len + 1); - 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 { - /* Just emit value in json notation */ - obj->trash_stack[UCL_TRASH_VALUE] = ucl_object_emit_single_json (obj); - obj->len = strlen (obj->trash_stack[UCL_TRASH_VALUE]); - } - obj->flags |= UCL_OBJECT_ALLOCATED_VALUE; - } - return obj->trash_stack[UCL_TRASH_VALUE]; -} - -ucl_object_t* -ucl_parser_get_object (struct ucl_parser *parser) -{ - if (parser->state != UCL_STATE_ERROR) { - return ucl_object_ref (parser->top_obj); - } - - return NULL; -} - -void -ucl_parser_free (struct ucl_parser *parser) -{ - struct ucl_stack *stack, *stmp; - struct ucl_macro *macro, *mtmp; - struct ucl_chunk *chunk, *ctmp; - struct ucl_pubkey *key, *ktmp; - struct ucl_variable *var, *vtmp; - - if (parser->top_obj != NULL) { - ucl_object_unref (parser->top_obj); - } - - LL_FOREACH_SAFE (parser->stack, stack, stmp) { - free (stack); - } - HASH_ITER (hh, parser->macroes, macro, mtmp) { - free (macro->name); - HASH_DEL (parser->macroes, macro); - UCL_FREE (sizeof (struct ucl_macro), macro); - } - LL_FOREACH_SAFE (parser->chunks, chunk, ctmp) { - UCL_FREE (sizeof (struct ucl_chunk), chunk); - } - LL_FOREACH_SAFE (parser->keys, key, ktmp) { - UCL_FREE (sizeof (struct ucl_pubkey), key); - } - LL_FOREACH_SAFE (parser->variables, var, vtmp) { - free (var->value); - free (var->var); - UCL_FREE (sizeof (struct ucl_variable), var); - } - - 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) -{ -#ifndef HAVE_OPENSSL - ucl_create_err (&parser->err, "cannot check signatures without openssl"); - return false; -#else -# if (OPENSSL_VERSION_NUMBER < 0x10000000L) - ucl_create_err (&parser->err, "cannot check signatures, openssl version is unsupported"); - return EXIT_FAILURE; -# else - struct ucl_pubkey *nkey; - BIO *mem; - - mem = BIO_new_mem_buf ((void *)key, len); - nkey = UCL_ALLOC (sizeof (struct ucl_pubkey)); - nkey->key = PEM_read_bio_PUBKEY (mem, &nkey->key, NULL, NULL); - BIO_free (mem); - if (nkey->key == NULL) { - UCL_FREE (sizeof (struct ucl_pubkey), nkey); - ucl_create_err (&parser->err, "%s", - ERR_error_string (ERR_get_error (), NULL)); - return false; - } - LL_PREPEND (parser->keys, nkey); -# endif -#endif - return true; -} - -#ifdef CURL_FOUND -struct ucl_curl_cbdata { - unsigned char *buf; - size_t buflen; -}; - -static size_t -ucl_curl_write_callback (void* contents, size_t size, size_t nmemb, void* ud) -{ - struct ucl_curl_cbdata *cbdata = ud; - size_t realsize = size * nmemb; - - cbdata->buf = realloc (cbdata->buf, cbdata->buflen + realsize + 1); - if (cbdata->buf == NULL) { - return 0; - } - - memcpy (&(cbdata->buf[cbdata->buflen]), contents, realsize); - cbdata->buflen += realsize; - cbdata->buf[cbdata->buflen] = 0; - - return realsize; -} -#endif - -/** - * Fetch a url and save results to the memory buffer - * @param url url to fetch - * @param len length of url - * @param buf target buffer - * @param buflen target length - * @return - */ -static bool -ucl_fetch_url (const unsigned char *url, unsigned char **buf, size_t *buflen, - UT_string **err, bool must_exist) -{ - -#ifdef HAVE_FETCH_H - struct url *fetch_url; - struct url_stat us; - FILE *in; - - fetch_url = fetchParseURL (url); - if (fetch_url == NULL) { - ucl_create_err (err, "invalid URL %s: %s", - url, strerror (errno)); - return false; - } - if ((in = fetchXGet (fetch_url, &us, "")) == NULL) { - if (!must_exist) { - ucl_create_err (err, "cannot fetch URL %s: %s", - url, strerror (errno)); - } - fetchFreeURL (fetch_url); - return false; - } - - *buflen = us.size; - *buf = malloc (*buflen); - if (*buf == NULL) { - ucl_create_err (err, "cannot allocate buffer for URL %s: %s", - url, strerror (errno)); - fclose (in); - fetchFreeURL (fetch_url); - return false; - } - - if (fread (*buf, *buflen, 1, in) != 1) { - ucl_create_err (err, "cannot read URL %s: %s", - url, strerror (errno)); - fclose (in); - fetchFreeURL (fetch_url); - return false; - } - - fetchFreeURL (fetch_url); - return true; -#elif defined(CURL_FOUND) - CURL *curl; - int r; - struct ucl_curl_cbdata cbdata; - - curl = curl_easy_init (); - if (curl == NULL) { - ucl_create_err (err, "CURL interface is broken"); - return false; - } - if ((r = curl_easy_setopt (curl, CURLOPT_URL, url)) != CURLE_OK) { - ucl_create_err (err, "invalid URL %s: %s", - url, curl_easy_strerror (r)); - curl_easy_cleanup (curl); - return false; - } - curl_easy_setopt (curl, CURLOPT_WRITEFUNCTION, ucl_curl_write_callback); - cbdata.buf = *buf; - cbdata.buflen = *buflen; - curl_easy_setopt (curl, CURLOPT_WRITEDATA, &cbdata); - - if ((r = curl_easy_perform (curl)) != CURLE_OK) { - if (!must_exist) { - ucl_create_err (err, "error fetching URL %s: %s", - url, curl_easy_strerror (r)); - } - curl_easy_cleanup (curl); - if (cbdata.buf) { - free (cbdata.buf); - } - return false; - } - *buf = cbdata.buf; - *buflen = cbdata.buflen; - - return true; -#else - ucl_create_err (err, "URL support is disabled"); - return false; -#endif -} - -/** - * Fetch a file and save results to the memory buffer - * @param filename filename to fetch - * @param len length of filename - * @param buf target buffer - * @param buflen target length - * @return - */ -static bool -ucl_fetch_file (const unsigned char *filename, unsigned char **buf, size_t *buflen, - UT_string **err, bool must_exist) -{ - int fd; - struct stat st; - - if (stat (filename, &st) == -1 || !S_ISREG (st.st_mode)) { - if (must_exist) { - ucl_create_err (err, "cannot stat file %s: %s", - filename, strerror (errno)); - } - return false; - } - if (st.st_size == 0) { - /* Do not map empty files */ - *buf = ""; - *buflen = 0; - } - else { - if ((fd = open (filename, O_RDONLY)) == -1) { - ucl_create_err (err, "cannot open file %s: %s", - filename, strerror (errno)); - return false; - } - if ((*buf = mmap (NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED) { - close (fd); - ucl_create_err (err, "cannot mmap file %s: %s", - filename, strerror (errno)); - return false; - } - *buflen = st.st_size; - close (fd); - } - - return true; -} - - -#if (defined(HAVE_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10000000L) -static inline bool -ucl_sig_check (const unsigned char *data, size_t datalen, - const unsigned char *sig, size_t siglen, struct ucl_parser *parser) -{ - struct ucl_pubkey *key; - char dig[EVP_MAX_MD_SIZE]; - unsigned int diglen; - EVP_PKEY_CTX *key_ctx; - EVP_MD_CTX *sign_ctx = NULL; - - sign_ctx = EVP_MD_CTX_create (); - - LL_FOREACH (parser->keys, key) { - key_ctx = EVP_PKEY_CTX_new (key->key, NULL); - if (key_ctx != NULL) { - if (EVP_PKEY_verify_init (key_ctx) <= 0) { - EVP_PKEY_CTX_free (key_ctx); - continue; - } - if (EVP_PKEY_CTX_set_rsa_padding (key_ctx, RSA_PKCS1_PADDING) <= 0) { - EVP_PKEY_CTX_free (key_ctx); - continue; - } - if (EVP_PKEY_CTX_set_signature_md (key_ctx, EVP_sha256 ()) <= 0) { - EVP_PKEY_CTX_free (key_ctx); - continue; - } - EVP_DigestInit (sign_ctx, EVP_sha256 ()); - EVP_DigestUpdate (sign_ctx, data, datalen); - EVP_DigestFinal (sign_ctx, dig, &diglen); - - if (EVP_PKEY_verify (key_ctx, sig, siglen, dig, diglen) == 1) { - EVP_MD_CTX_destroy (sign_ctx); - EVP_PKEY_CTX_free (key_ctx); - return true; - } - - EVP_PKEY_CTX_free (key_ctx); - } - } - - EVP_MD_CTX_destroy (sign_ctx); - - return false; -} -#endif - -/** - * Include an url to configuration - * @param data - * @param len - * @param parser - * @param err - * @return - */ -static bool -ucl_include_url (const unsigned char *data, size_t len, - struct ucl_parser *parser, bool check_signature, bool must_exist) -{ - - bool res; - unsigned char *buf = NULL; - size_t buflen = 0; - struct ucl_chunk *chunk; - char urlbuf[PATH_MAX]; - int prev_state; - - snprintf (urlbuf, sizeof (urlbuf), "%.*s", (int)len, data); - - if (!ucl_fetch_url (urlbuf, &buf, &buflen, &parser->err, must_exist)) { - return (!must_exist || false); - } - - if (check_signature) { -#if (defined(HAVE_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10000000L) - unsigned char *sigbuf = NULL; - size_t siglen = 0; - /* We need to check signature first */ - snprintf (urlbuf, sizeof (urlbuf), "%.*s.sig", (int)len, data); - if (!ucl_fetch_url (urlbuf, &sigbuf, &siglen, &parser->err, true)) { - return false; - } - if (!ucl_sig_check (buf, buflen, sigbuf, siglen, parser)) { - ucl_create_err (&parser->err, "cannot verify url %s: %s", - urlbuf, - ERR_error_string (ERR_get_error (), NULL)); - if (siglen > 0) { - munmap (sigbuf, siglen); - } - return false; - } - if (siglen > 0) { - munmap (sigbuf, siglen); - } -#endif - } - - prev_state = parser->state; - parser->state = UCL_STATE_INIT; - - res = ucl_parser_add_chunk (parser, buf, buflen); - if (res == true) { - /* Remove chunk from the stack */ - chunk = parser->chunks; - if (chunk != NULL) { - parser->chunks = chunk->next; - UCL_FREE (sizeof (struct ucl_chunk), chunk); - } - } - - parser->state = prev_state; - free (buf); - - return res; -} - -/** - * Include a file to configuration - * @param data - * @param len - * @param parser - * @param err - * @return - */ -static bool -ucl_include_file (const unsigned char *data, size_t len, - struct ucl_parser *parser, bool check_signature, bool must_exist) -{ - bool res; - struct ucl_chunk *chunk; - unsigned char *buf = NULL; - size_t buflen; - char filebuf[PATH_MAX], realbuf[PATH_MAX]; - int prev_state; - - snprintf (filebuf, sizeof (filebuf), "%.*s", (int)len, data); - if (realpath (filebuf, realbuf) == NULL) { - if (!must_exist) { - return true; - } - ucl_create_err (&parser->err, "cannot open file %s: %s", - filebuf, - strerror (errno)); - return false; - } - - if (!ucl_fetch_file (realbuf, &buf, &buflen, &parser->err, must_exist)) { - return (!must_exist || false); - } - - if (check_signature) { -#if (defined(HAVE_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10000000L) - unsigned char *sigbuf = NULL; - size_t siglen = 0; - /* We need to check signature first */ - snprintf (filebuf, sizeof (filebuf), "%s.sig", realbuf); - if (!ucl_fetch_file (filebuf, &sigbuf, &siglen, &parser->err, true)) { - return false; - } - if (!ucl_sig_check (buf, buflen, sigbuf, siglen, parser)) { - ucl_create_err (&parser->err, "cannot verify file %s: %s", - filebuf, - ERR_error_string (ERR_get_error (), NULL)); - if (siglen > 0) { - munmap (sigbuf, siglen); - } - return false; - } - if (siglen > 0) { - munmap (sigbuf, siglen); - } -#endif - } - - ucl_parser_set_filevars (parser, realbuf, false); - - prev_state = parser->state; - parser->state = UCL_STATE_INIT; - - res = ucl_parser_add_chunk (parser, buf, buflen); - if (res == true) { - /* Remove chunk from the stack */ - chunk = parser->chunks; - if (chunk != NULL) { - parser->chunks = chunk->next; - UCL_FREE (sizeof (struct ucl_chunk), chunk); - } - } - - parser->state = prev_state; - - if (buflen > 0) { - munmap (buf, buflen); - } - - return res; -} - -/** - * Handle include macro - * @param data include data - * @param len length of data - * @param ud user data - * @param err error ptr - * @return - */ -bool -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, true); - } - - return ucl_include_url (data, len, parser, false, true); -} - -/** - * Handle includes macro - * @param data include data - * @param len length of data - * @param ud user data - * @param err error ptr - * @return - */ -bool -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, true); - } - - return ucl_include_url (data, len, parser, true, true); -} - - -bool -ucl_try_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, false); - } - - return ucl_include_url (data, len, parser, false, false); -} - -bool -ucl_parser_set_filevars (struct ucl_parser *parser, const char *filename, bool need_expand) -{ - char realbuf[PATH_MAX], *curdir; - - if (filename != NULL) { - if (need_expand) { - if (realpath (filename, realbuf) == NULL) { - return false; - } - } - else { - ucl_strlcpy (realbuf, filename, sizeof (realbuf)); - } - - /* Define variables */ - ucl_parser_register_variable (parser, "FILENAME", realbuf); - curdir = dirname (realbuf); - ucl_parser_register_variable (parser, "CURDIR", curdir); - } - else { - /* Set everything from the current dir */ - curdir = getcwd (realbuf, sizeof (realbuf)); - ucl_parser_register_variable (parser, "FILENAME", "undef"); - ucl_parser_register_variable (parser, "CURDIR", curdir); - } - - return true; -} - -bool -ucl_parser_add_file (struct ucl_parser *parser, const char *filename) -{ - unsigned char *buf; - size_t len; - bool ret; - char realbuf[PATH_MAX]; - - if (realpath (filename, realbuf) == NULL) { - ucl_create_err (&parser->err, "cannot open file %s: %s", - filename, - strerror (errno)); - return false; - } - - if (!ucl_fetch_file (realbuf, &buf, &len, &parser->err, true)) { - return false; - } - - ucl_parser_set_filevars (parser, realbuf, false); - ret = ucl_parser_add_chunk (parser, buf, len); - - if (len > 0) { - munmap (buf, len); - } - - return ret; -} - -size_t -ucl_strlcpy (char *dst, const char *src, size_t siz) -{ - char *d = dst; - const char *s = src; - size_t n = siz; - - /* Copy as many bytes as will fit */ - if (n != 0) { - while (--n != 0) { - if ((*d++ = *s++) == '\0') { - break; - } - } - } - - if (n == 0 && siz != 0) { - *d = '\0'; - } - - return (s - src - 1); /* count does not include NUL */ -} - -size_t -ucl_strlcpy_unsafe (char *dst, const char *src, size_t siz) -{ - memcpy (dst, src, siz - 1); - dst[siz - 1] = '\0'; - - return siz - 1; -} - -size_t -ucl_strlcpy_tolower (char *dst, const char *src, size_t siz) -{ - char *d = dst; - const char *s = src; - size_t n = siz; - - /* Copy as many bytes as will fit */ - if (n != 0) { - while (--n != 0) { - if ((*d++ = tolower (*s++)) == '\0') { - break; - } - } - } - - if (n == 0 && siz != 0) { - *d = '\0'; - } - - return (s - src); /* count does not include NUL */ -} - -ucl_object_t * -ucl_object_fromstring_common (const char *str, size_t len, enum ucl_string_flags flags) -{ - ucl_object_t *obj; - const char *start, *end, *p, *pos; - char *dst, *d; - size_t escaped_len; - - if (str == NULL) { - return NULL; - } - - obj = ucl_object_new (); - if (obj) { - if (len == 0) { - len = strlen (str); - } - if (flags & UCL_STRING_TRIM) { - /* Skip leading spaces */ - for (start = str; (size_t)(start - str) < len; start ++) { - if (!ucl_test_character (*start, UCL_CHARACTER_WHITESPACE_UNSAFE)) { - break; - } - } - /* Skip trailing spaces */ - for (end = str + len - 1; end > start; end --) { - if (!ucl_test_character (*end, UCL_CHARACTER_WHITESPACE_UNSAFE)) { - break; - } - } - end ++; - } - else { - start = str; - end = str + len; - } - - obj->type = UCL_STRING; - if (flags & UCL_STRING_ESCAPE) { - for (p = start, escaped_len = 0; p < end; p ++, escaped_len ++) { - if (ucl_test_character (*p, UCL_CHARACTER_JSON_UNSAFE)) { - escaped_len ++; - } - } - dst = malloc (escaped_len + 1); - if (dst != NULL) { - for (p = start, d = dst; p < end; p ++, d ++) { - if (ucl_test_character (*p, UCL_CHARACTER_JSON_UNSAFE)) { - switch (*p) { - case '\n': - *d++ = '\\'; - *d = 'n'; - break; - case '\r': - *d++ = '\\'; - *d = 'r'; - break; - case '\b': - *d++ = '\\'; - *d = 'b'; - break; - case '\t': - *d++ = '\\'; - *d = 't'; - break; - case '\f': - *d++ = '\\'; - *d = 'f'; - break; - case '\\': - *d++ = '\\'; - *d = '\\'; - break; - case '"': - *d++ = '\\'; - *d = '"'; - break; - } - } - else { - *d = *p; - } - } - *d = '\0'; - obj->value.sv = dst; - obj->trash_stack[UCL_TRASH_VALUE] = dst; - obj->len = escaped_len; - } - } - else { - dst = malloc (end - start + 1); - if (dst != NULL) { - ucl_strlcpy_unsafe (dst, start, end - start + 1); - obj->value.sv = dst; - obj->trash_stack[UCL_TRASH_VALUE] = dst; - obj->len = end - start; - } - } - if ((flags & UCL_STRING_PARSE) && dst != NULL) { - /* Parse what we have */ - if (flags & UCL_STRING_PARSE_BOOLEAN) { - if (!ucl_maybe_parse_boolean (obj, dst, obj->len) && (flags & UCL_STRING_PARSE_NUMBER)) { - ucl_maybe_parse_number (obj, dst, dst + obj->len, &pos, - flags & UCL_STRING_PARSE_DOUBLE, - flags & UCL_STRING_PARSE_BYTES); - } - } - else { - ucl_maybe_parse_number (obj, dst, dst + obj->len, &pos, - flags & UCL_STRING_PARSE_DOUBLE, - flags & UCL_STRING_PARSE_BYTES); - } - } - } - - return obj; -} - -static ucl_object_t * -ucl_object_insert_key_common (ucl_object_t *top, ucl_object_t *elt, - const char *key, size_t keylen, bool copy_key, bool merge, bool replace) -{ - ucl_object_t *found, *cur; - ucl_object_iter_t it = NULL; - const char *p; - - if (elt == NULL || key == NULL) { - return NULL; - } - - if (top == NULL) { - top = ucl_object_new (); - top->type = UCL_OBJECT; - } - - if (top->type != UCL_OBJECT) { - /* It is possible to convert NULL type to an object */ - if (top->type == UCL_NULL) { - top->type = UCL_OBJECT; - } - else { - /* Refuse converting of other object types */ - return top; - } - } - - if (top->value.ov == NULL) { - top->value.ov = ucl_hash_create (); - } - - 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; - } - } - - elt->key = key; - elt->keylen = keylen; - - if (copy_key) { - ucl_copy_key_trash (elt); - } - - found = ucl_hash_search_obj (top->value.ov, elt); - - if (!found) { - top->value.ov = ucl_hash_insert_object (top->value.ov, elt); - DL_APPEND (found, elt); - } - else { - if (replace) { - ucl_hash_delete (top->value.ov, found); - ucl_object_unref (found); - top->value.ov = ucl_hash_insert_object (top->value.ov, elt); - found = NULL; - DL_APPEND (found, elt); - } - else if (merge) { - if (found->type != UCL_OBJECT && elt->type == UCL_OBJECT) { - /* Insert old elt to new one */ - elt = ucl_object_insert_key_common (elt, found, found->key, found->keylen, copy_key, false, false); - ucl_hash_delete (top->value.ov, found); - top->value.ov = ucl_hash_insert_object (top->value.ov, elt); - } - else if (found->type == UCL_OBJECT && elt->type != UCL_OBJECT) { - /* Insert new to old */ - found = ucl_object_insert_key_common (found, elt, elt->key, elt->keylen, copy_key, false, false); - } - else if (found->type == UCL_OBJECT && elt->type == UCL_OBJECT) { - /* Mix two hashes */ - while ((cur = ucl_iterate_object (elt, &it, true)) != NULL) { - ucl_object_ref (cur); - found = ucl_object_insert_key_common (found, cur, cur->key, cur->keylen, copy_key, false, false); - } - ucl_object_unref (elt); - } - else { - /* Just make a list of scalars */ - DL_APPEND (found, elt); - } - } - else { - DL_APPEND (found, 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) -{ - return ucl_object_insert_key_common (top, elt, key, keylen, copy_key, false, false); -} - -ucl_object_t * -ucl_object_insert_key_merged (ucl_object_t *top, ucl_object_t *elt, - const char *key, size_t keylen, bool copy_key) -{ - return ucl_object_insert_key_common (top, elt, key, keylen, copy_key, true, false); -} - -ucl_object_t * -ucl_object_replace_key (ucl_object_t *top, ucl_object_t *elt, - const char *key, size_t keylen, bool copy_key) -{ - return ucl_object_insert_key_common (top, elt, key, keylen, copy_key, false, true); -} - -ucl_object_t * -ucl_object_find_keyl (ucl_object_t *obj, const char *key, size_t klen) -{ - ucl_object_t *ret, srch; - - if (obj == NULL || obj->type != UCL_OBJECT || key == NULL) { - return NULL; - } - - srch.key = key; - srch.keylen = klen; - ret = ucl_hash_search_obj (obj->value.ov, &srch); - - return ret; -} - -ucl_object_t * -ucl_object_find_key (ucl_object_t *obj, const char *key) -{ - size_t klen; - ucl_object_t *ret, srch; - - if (obj == NULL || obj->type != UCL_OBJECT || key == NULL) { - return NULL; - } - - klen = strlen (key); - srch.key = key; - srch.keylen = klen; - ret = ucl_hash_search_obj (obj->value.ov, &srch); - - return ret; -} - -ucl_object_t* -ucl_iterate_object (ucl_object_t *obj, ucl_object_iter_t *iter, bool expand_values) -{ - ucl_object_t *elt; - - if (expand_values) { - switch (obj->type) { - case UCL_OBJECT: - return (ucl_object_t*)ucl_hash_iterate (obj->value.ov, iter); - break; - case UCL_ARRAY: - elt = *iter; - if (elt == NULL) { - elt = obj->value.av; - if (elt == NULL) { - return NULL; - } - } - else if (elt == obj->value.av) { - return NULL; - } - *iter = elt->next ? elt->next : obj->value.av; - return elt; - default: - /* Go to linear iteration */ - break; - } - } - /* Treat everything as a linear list */ - elt = *iter; - if (elt == NULL) { - elt = obj; - if (elt == NULL) { - return NULL; - } - } - else if (elt == obj) { - return NULL; - } - *iter = elt->next ? elt->next : obj; - return elt; - - /* Not reached */ - return NULL; -} diff --git a/src/ucl/tests/1.in b/src/ucl/tests/1.in deleted file mode 100644 index 41b0cfb3c..000000000 --- a/src/ucl/tests/1.in +++ /dev/null @@ -1,11 +0,0 @@ -{ -"key1": value; -"key1": value2; -"key1": "value;" -"key1": 1.0, -"key1": -1e-10, -"key1": 1 -"key1": true -"key1": no -"key1": yes -} diff --git a/src/ucl/tests/1.res b/src/ucl/tests/1.res deleted file mode 100644 index 789c82769..000000000 --- a/src/ucl/tests/1.res +++ /dev/null @@ -1,12 +0,0 @@ -key1 [ - "value", - "value2", - "value;", - 1.0, - -1e-10, - 1, - true, - false, - true, -] - diff --git a/src/ucl/tests/2.in b/src/ucl/tests/2.in deleted file mode 100644 index 59a4d0c38..000000000 --- a/src/ucl/tests/2.in +++ /dev/null @@ -1,18 +0,0 @@ -section1 { param1 = value; param2 = value, -section3 {param = value; param2 = value, param3 = ["value1", value2, 100500]}} -section2 { param1 = {key = value}, param1 = ["key"]} - -# Numbers -key1 = 1s -key2 = 1min -key3 = 1kb -key4 = 5M -key5 = 10mS -key6 = 10y - -# Strings -key1 = "some string"; -key2 = /some/path; -key3 = 111some, -key4: s1, -"key5": "\n\r123" diff --git a/src/ucl/tests/2.res b/src/ucl/tests/2.res deleted file mode 100644 index 3a8966f65..000000000 --- a/src/ucl/tests/2.res +++ /dev/null @@ -1,45 +0,0 @@ -section1 { - param1 = "value"; - param2 = "value"; - section3 { - param = "value"; - param2 = "value"; - param3 [ - "value1", - "value2", - 100500, - ] - } -} -section2 { - param1 [ - { - key = "value"; - }, - [ - "key", - ], - ] -} -key1 [ - 1.0, - "some string", -] -key2 [ - 60.0, - "/some/path", -] -key3 [ - 1024, - "111some", -] -key4 [ - 5000000, - "s1", -] -key5 [ - 0.010000, - "\n\r123", -] -key6 = 2207520000.000000; - diff --git a/src/ucl/tests/3.in b/src/ucl/tests/3.in deleted file mode 100644 index b3e369670..000000000 --- a/src/ucl/tests/3.in +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Pkg conf - */ - -#packagesite http//pkg.freebsd.org/freebsd-9-amd64/latest -#packagesite http//pkg.freebsd.org/freebsd-9-amd64/latest -packagesite: http://pkg-test.freebsd.org/pkg-test/${ABI}/latest -squaretest: some[]value -ALIAS : { - all-depends: query %dn-%dv, - annotations: info -A, - build-depends: info -qd, - download: fetch, - iinfo: info -i -g -x, - isearch: search -i -g -x, - leaf: query -e '%a == 0' '%n-%v', - leaf: query -e '%a == 0' '%n-%v', - list: info -ql, - origin: info -qo, - provided-depends: info -qb, - raw: info -R, - required-depends: info -qr, - shared-depends: info -qB, - show: info -f -k, - size: info -sq, - } - -repo_dirs : [ - /home/bapt, - /usr/local/etc -] diff --git a/src/ucl/tests/3.res b/src/ucl/tests/3.res deleted file mode 100644 index 2f84ed69e..000000000 --- a/src/ucl/tests/3.res +++ /dev/null @@ -1,27 +0,0 @@ -packagesite = "http://pkg-test.freebsd.org/pkg-test/${ABI}/latest"; -squaretest = "some[]value"; -alias { - all-depends = "query %dn-%dv"; - annotations = "info -A"; - build-depends = "info -qd"; - download = "fetch"; - iinfo = "info -i -g -x"; - isearch = "search -i -g -x"; - leaf [ - "query -e '%a == 0' '%n-%v'", - "query -e '%a == 0' '%n-%v'", - ] - list = "info -ql"; - origin = "info -qo"; - provided-depends = "info -qb"; - raw = "info -R"; - required-depends = "info -qr"; - shared-depends = "info -qB"; - show = "info -f -k"; - size = "info -sq"; -} -repo_dirs [ - "/home/bapt", - "/usr/local/etc", -] - diff --git a/src/ucl/tests/4.in b/src/ucl/tests/4.in deleted file mode 100644 index 2b296efff..000000000 --- a/src/ucl/tests/4.in +++ /dev/null @@ -1,47 +0,0 @@ -name : "pkgconf" -version : "0.9.3" -origin : "devel/pkgconf" -comment : "Utility to help to configure compiler and linker flags" -arch : "freebsd:9:x86:64" -maintainer : "bapt@FreeBSD.org" -prefix : "/usr/local" -licenselogic : "single" -licenses : [ - "BSD", -] -flatsize : 60523 -desc : "pkgconf is a program which helps to configure compiler and linker flags for\ndevelopment frameworks. It is similar to pkg-config, but was written from\nscratch in Summer of 2011 to replace pkg-config, which now needs itself to build\nitself.\n\nWWW: https://github.com/pkgconf/pkgconf" -categories : [ - "devel", -] -files : { - /usr/local/bin/pkg-config : "-", - /usr/local/bin/pkgconf : "4a0fc53e5ad64e8085da2e61652d61c50b192a086421d865703f1de9f724da38", - /usr/local/share/aclocal/pkg.m4 : "cffab33d659adfe36497ec57665eec36fa6fb7b007e578e6ac2434cc28be8820", - /usr/local/share/licenses/pkgconf-0.9.3/BSD : "85e7a53b5e2d3e350e2d084fed2f94b7f63005f8e1168740e1e84aa9fa5d48ce", - /usr/local/share/licenses/pkgconf-0.9.3/LICENSE : "d9cce0db43502eb1bd8fbef7e960cfaa43b5647186f7f7379923b336209fd77b", - /usr/local/share/licenses/pkgconf-0.9.3/catalog.mk : "e7b131acce7c3d3c61f2214607b11b34526e03b05afe89a608f50586a898e2ef", -} -directories : { - /usr/local/share/licenses/pkgconf-0.9.3/ : false, - /usr/local/share/licenses/ : true, -} -scripts : { - post-install : "cd /usr/local\nn", - pre-deinstall : "cd /usr/local\nn", - post-deinstall : "cd /usr/local\nn", -} -multiline-key : </dev/null - if [ $? -ne 0 ] ; then - rm $_t.out - echo "Test: $_t output missmatch" - exit 1 - fi - fi - rm $_t.out -done - -if [ $# -gt 2 ] ; then - $3 ${TEST_DIR}/generate.out - diff -s ${TEST_DIR}/generate.out ${TEST_DIR}/generate.res -u 2>/dev/null - if [ $? -ne 0 ] ; then - rm ${TEST_DIR}/generate.out - echo "Test: generate.res output missmatch" - exit 1 - fi - rm ${TEST_DIR}/generate.out -fi - -if [ $# -gt 1 -a -x "/usr/bin/xz" ] ; then - echo 'Running speed tests' - for _tin in ${TEST_DIR}/*.xz ; do - echo "Unpacking $_tin..." - xz -cd < $_tin > ${TEST_DIR}/test_file - # Preread file to cheat benchmark! - cat ${TEST_DIR}/test_file > /dev/null - echo "Starting benchmarking for $_tin..." - $2 ${TEST_DIR}/test_file - if [ $? -ne 0 ] ; then - echo "Test: $_tin failed" - rm ${TEST_DIR}/test_file - exit 1 - fi - rm ${TEST_DIR}/test_file - done -fi - diff --git a/src/ucl/tests/test_basic.c b/src/ucl/tests/test_basic.c deleted file mode 100644 index 7444d901b..000000000 --- a/src/ucl/tests/test_basic.c +++ /dev/null @@ -1,113 +0,0 @@ -/* Copyright (c) 2013, 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 ''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. - */ - -#include -#include -#include "ucl.h" - -int -main (int argc, char **argv) -{ - char inbuf[8192]; - struct ucl_parser *parser, *parser2; - ucl_object_t *obj; - FILE *in, *out; - unsigned char *emitted; - const char *fname_in = NULL, *fname_out = NULL; - int ret = 0; - - switch (argc) { - case 2: - fname_in = argv[1]; - break; - case 3: - fname_in = argv[1]; - fname_out = argv[2]; - break; - } - - if (fname_in != NULL) { - in = fopen (fname_in, "r"); - if (in == NULL) { - exit (-errno); - } - } - else { - in = stdin; - } - 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)); - } - fclose (in); - - if (fname_out != NULL) { - out = fopen (fname_out, "w"); - if (out == NULL) { - exit (-errno); - } - } - else { - out = stdout; - } - 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); - emitted = ucl_object_emit (obj, UCL_EMIT_CONFIG); - ucl_parser_free (parser); - ucl_object_unref (obj); - parser2 = ucl_parser_new (UCL_PARSER_KEY_LOWERCASE); - ucl_parser_add_chunk (parser2, emitted, strlen (emitted)); - - 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; - } - if (emitted != NULL) { - free (emitted); - } - obj = ucl_parser_get_object (parser2); - emitted = ucl_object_emit (obj, UCL_EMIT_CONFIG); - - fprintf (out, "%s\n", emitted); - ucl_object_unref (obj); - -end: - if (emitted != NULL) { - free (emitted); - } - 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 deleted file mode 100644 index f269e00dc..000000000 --- a/src/ucl/tests/test_generate.c +++ /dev/null @@ -1,105 +0,0 @@ -/* Copyright (c) 2013, 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 ''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. - */ - -#include -#include -#include "ucl.h" - -int -main (int argc, char **argv) -{ - ucl_object_t *obj, *cur, *ar; - FILE *out; - unsigned char *emitted; - const char *fname_out = NULL; - int ret = 0; - - switch (argc) { - case 2: - fname_out = argv[1]; - break; - } - - - if (fname_out != NULL) { - out = fopen (fname_out, "w"); - if (out == NULL) { - exit (-errno); - } - } - else { - out = stdout; - } - - obj = ucl_object_new (); - /* Create some strings */ - cur = ucl_object_fromstring_common (" test string ", 0, UCL_STRING_TRIM); - obj = ucl_object_insert_key (obj, cur, "key1", 0, false); - cur = ucl_object_fromstring_common (" test \nstring\n ", 0, UCL_STRING_TRIM | UCL_STRING_ESCAPE); - obj = ucl_object_insert_key (obj, cur, "key2", 0, false); - cur = ucl_object_fromstring_common (" test string \n", 0, 0); - obj = ucl_object_insert_key (obj, cur, "key3", 0, false); - /* Array of numbers */ - cur = ucl_object_fromint (10); - ar = ucl_array_append (NULL, cur); - cur = ucl_object_fromdouble (10.1); - ar = ucl_array_append (ar, cur); - obj = ucl_object_insert_key (obj, ar, "key4", 0, false); - cur = ucl_object_frombool (true); - obj = ucl_object_insert_key (obj, cur, "key4", 0, false); - /* Empty strings */ - cur = ucl_object_fromstring_common (" ", 0, UCL_STRING_TRIM); - obj = ucl_object_insert_key (obj, cur, "key5", 0, false); - cur = ucl_object_fromstring_common ("", 0, UCL_STRING_ESCAPE); - obj = ucl_object_insert_key (obj, cur, "key6", 0, false); - cur = ucl_object_fromstring_common (" \n", 0, UCL_STRING_ESCAPE); - obj = ucl_object_insert_key (obj, cur, "key7", 0, false); - /* Numbers and booleans */ - cur = ucl_object_fromstring_common ("1mb", 0, UCL_STRING_ESCAPE | UCL_STRING_PARSE); - obj = ucl_object_insert_key (obj, cur, "key8", 0, false); - cur = ucl_object_fromstring_common ("3.14", 0, UCL_STRING_PARSE); - obj = ucl_object_insert_key (obj, cur, "key9", 0, false); - cur = ucl_object_fromstring_common ("true", 0, UCL_STRING_PARSE); - 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); - - fprintf (out, "%s\n", emitted); - ucl_object_unref (obj); - - if (emitted != NULL) { - free (emitted); - } - fclose (out); - - return ret; -} diff --git a/src/ucl/tests/test_speed.c b/src/ucl/tests/test_speed.c deleted file mode 100644 index 39229becb..000000000 --- a/src/ucl/tests/test_speed.c +++ /dev/null @@ -1,127 +0,0 @@ -/* Copyright (c) 2013, 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 ''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. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "ucl.h" - -int -main (int argc, char **argv) -{ - void *map; - struct ucl_parser *parser; - ucl_object_t *obj; - int fin; - unsigned char *emitted; - struct stat st; - const char *fname_in = NULL; - int ret = 0; - struct timespec start, end; - double seconds; - - switch (argc) { - case 2: - fname_in = argv[1]; - break; - } - - fin = open (fname_in, O_RDONLY); - if (fin == -1) { - perror ("open failed"); - exit (EXIT_FAILURE); - } - parser = ucl_parser_new (UCL_PARSER_ZEROCOPY); - - (void)fstat (fin, &st); - map = mmap (NULL, st.st_size, PROT_READ, MAP_SHARED, fin, 0); - if (map == MAP_FAILED) { - perror ("mmap failed"); - exit (EXIT_FAILURE); - } - - close (fin); - - clock_gettime (CLOCK_MONOTONIC, &start); - ucl_parser_add_chunk (parser, map, st.st_size); - - 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 (ucl_parser_get_error(parser)) { - printf ("Error occurred: %s\n", ucl_parser_get_error(parser)); - ret = 1; - } - - clock_gettime (CLOCK_MONOTONIC, &start); - emitted = ucl_object_emit (obj, UCL_EMIT_CONFIG); - clock_gettime (CLOCK_MONOTONIC, &end); - - seconds = (end.tv_sec - start.tv_sec) + (end.tv_nsec - start.tv_nsec) / 1000000000.; - printf ("ucl: emitted config in %.4f seconds\n", seconds); - - free (emitted); - - clock_gettime (CLOCK_MONOTONIC, &start); - emitted = ucl_object_emit (obj, UCL_EMIT_JSON); - clock_gettime (CLOCK_MONOTONIC, &end); - - seconds = (end.tv_sec - start.tv_sec) + (end.tv_nsec - start.tv_nsec) / 1000000000.; - printf ("ucl: emitted json in %.4f seconds\n", seconds); - - free (emitted); - - clock_gettime (CLOCK_MONOTONIC, &start); - emitted = ucl_object_emit (obj, UCL_EMIT_JSON_COMPACT); - clock_gettime (CLOCK_MONOTONIC, &end); - - seconds = (end.tv_sec - start.tv_sec) + (end.tv_nsec - start.tv_nsec) / 1000000000.; - printf ("ucl: emitted compact json in %.4f seconds\n", seconds); - - free (emitted); - - clock_gettime (CLOCK_MONOTONIC, &start); - emitted = ucl_object_emit (obj, UCL_EMIT_YAML); - clock_gettime (CLOCK_MONOTONIC, &end); - - seconds = (end.tv_sec - start.tv_sec) + (end.tv_nsec - start.tv_nsec) / 1000000000.; - printf ("ucl: emitted yaml in %.4f seconds\n", seconds); - - free (emitted); - - ucl_parser_free (parser); - ucl_object_unref (obj); - - munmap (map, st.st_size); - - return ret; -} diff --git a/src/ucl/utils/chargen.c b/src/ucl/utils/chargen.c deleted file mode 100644 index d6fa86a20..000000000 --- a/src/ucl/utils/chargen.c +++ /dev/null @@ -1,128 +0,0 @@ -/* Copyright (c) 2013, 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 ''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. - */ - -/** - * @file this utility generates character table for ucl - */ - -#include -#include -#include - -static inline int -print_flag (const char *flag, bool *need_or, char *val) -{ - int res; - res = sprintf (val, "%s%s", *need_or ? "|" : "", flag); - - *need_or |= true; - - return res; -} - -int -main (int argc, char **argv) -{ - int i, col, r; - const char *name = "ucl_chartable"; - bool need_or; - char valbuf[2048]; - - col = 0; - - if (argc > 1) { - name = argv[1]; - } - - printf ("static const unsigned int %s[255] = {\n", name); - - for (i = 0; i < 255; i ++) { - need_or = false; - r = 0; - /* UCL_CHARACTER_VALUE_END */ - - if (i == ' ' || i == '\t') { - r += print_flag ("UCL_CHARACTER_WHITESPACE", &need_or, valbuf + r); - } - if (isspace (i)) { - r += print_flag ("UCL_CHARACTER_WHITESPACE_UNSAFE", &need_or, valbuf + r); - } - if (isalnum (i) || i >= 0x80 || i == '/' || i == '_') { - r += print_flag ("UCL_CHARACTER_KEY_START", &need_or, valbuf + r); - } - if (isalnum (i) || i == '-' || i == '_' || i == '/' || i == '.' || i >= 0x80) { - r += print_flag ("UCL_CHARACTER_KEY", &need_or, valbuf + r); - } - if (i == 0 || i == '\r' || i == '\n' || i == ']' || i == '}' || i == ';' || i == ',' || i == '#') { - r += print_flag ("UCL_CHARACTER_VALUE_END", &need_or, valbuf + r); - } - else { - if (isprint (i) || i >= 0x80) { - r += print_flag ("UCL_CHARACTER_VALUE_STR", &need_or, valbuf + r); - } - if (isdigit (i) || i == '-') { - r += print_flag ("UCL_CHARACTER_VALUE_DIGIT_START", &need_or, valbuf + r); - } - if (isalnum (i) || i == '.' || i == '-' || i == '+') { - r += print_flag ("UCL_CHARACTER_VALUE_DIGIT", &need_or, valbuf + r); - } - } - if (i == '"' || i == '\\' || i == '/' || i == 'b' || - i == 'f' || i == 'n' || i == 'r' || i == 't' || i == 'u') { - r += print_flag ("UCL_CHARACTER_ESCAPE", &need_or, valbuf + r); - } - if (i == ' ' || i == '\t' || i == ':' || i == '=') { - r += print_flag ("UCL_CHARACTER_KEY_SEP", &need_or, valbuf + r); - } - if (i == '\n' || i == '\r' || i == '\\' || i == '\b' || i == '\t' || - i == '"' || i == '\f') { - r += print_flag ("UCL_CHARACTER_JSON_UNSAFE", &need_or, valbuf + r); - } - if (i == '\n' || i == '\r' || i == '\\' || i == '\b' || i == '\t' || - i == '"' || i == '\f' || i == '=' || i == ':' || i == '{' || i == '[' || i == ' ') { - r += print_flag ("UCL_CHARACTER_UCL_UNSAFE", &need_or, valbuf + r); - } - - if (!need_or) { - r += print_flag ("UCL_CHARACTER_DENIED", &need_or, valbuf + r); - } - - if (isprint (i)) { - r += sprintf (valbuf + r, " /* %c */", i); - } - if (i != 254) { - r += sprintf (valbuf + r, ", "); - } - col += r; - if (col > 80) { - printf ("\n%s", valbuf); - col = r; - } - else { - printf ("%s", valbuf); - } - } - printf ("\n}\n"); - - return 0; -} diff --git a/src/ucl/utils/objdump.c b/src/ucl/utils/objdump.c deleted file mode 100644 index 8ba0ac261..000000000 --- a/src/ucl/utils/objdump.c +++ /dev/null @@ -1,157 +0,0 @@ -/* Copyright (c) 2013, Dmitriy V. Reshetnikov - * Copyright (c) 2013, 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 ''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. - */ - -#include -#include - -#include "ucl.h" - -void -ucl_obj_dump(ucl_object_t *obj, unsigned int shift) -{ - int num = shift * 4 + 5; - char *pre = (char *) malloc (num * sizeof(char)); - ucl_object_t *cur, *tmp; - - pre[--num] = 0x00; - while (num--) - pre[num] = 0x20; - - while (obj != NULL ) { - printf ("%sucl object address: %p\n", pre + 4, obj); - if (obj->hh.key != NULL) { - printf ("%skey: \"%s\"\n", pre, ucl_object_key (obj)); - } - printf ("%sref: %d\n", pre, obj->ref); - printf ("%slen: %zd\n", pre, obj->len); - printf ("%sprev: %p\n", pre, obj->prev); - printf ("%snext: %p\n", pre, obj->next); - if (obj->type == UCL_OBJECT) { - printf ("%stype: UCL_OBJECT\n", pre); - printf ("%svalue: %p\n", pre, obj->value.ov); - HASH_ITER (hh, obj->value.ov, cur, tmp) { - ucl_obj_dump (cur, shift + 2); - } - } - else if (obj->type == UCL_ARRAY) { - printf ("%stype: UCL_ARRAY\n", pre); - printf ("%svalue: %p\n", pre, obj->value.ov); - ucl_obj_dump (obj->value.ov, shift + 2); - } - else if (obj->type == UCL_INT) { - printf ("%stype: UCL_INT\n", pre); - printf ("%svalue: %ld\n", pre, obj->value.iv); - } - else if (obj->type == UCL_FLOAT) { - printf ("%stype: UCL_FLOAT\n", pre); - printf ("%svalue: %f\n", pre, obj->value.dv); - } - else if (obj->type == UCL_STRING) { - printf ("%stype: UCL_STRING\n", pre); - printf ("%svalue: \"%s\"\n", pre, ucl_obj_tostring (obj)); - } - else if (obj->type == UCL_BOOLEAN) { - printf ("%stype: UCL_BOOLEAN\n", pre); - printf ("%svalue: %s\n", pre, (obj->value.iv) ? "true" : "false"); - } - else if (obj->type == UCL_TIME) { - printf ("%stype: UCL_TIME\n", pre); - printf ("%svalue: %f\n", pre, obj->value.dv); - } - else if (obj->type == UCL_USERDATA) { - printf ("%stype: UCL_USERDATA\n", pre); - printf ("%svalue: %p\n", pre, obj->value.ud); - } - obj = obj->next; - } - - free (pre); -} - -int -main(int argc, char **argv) -{ - const char *fn = NULL; - char inbuf[8192]; - struct ucl_parser *parser; - int k, ret = 0; - ucl_object_t *obj = NULL; - ucl_object_t *par; - FILE *in; - - if (argc > 1) { - fn = argv[1]; - } - - if (fn != NULL) { - in = fopen (fn, "r"); - if (in == NULL) { - exit (-errno); - } - } - else { - in = stdin; - } - - parser = ucl_parser_new (0); - while (!feof (in)) { - fread (inbuf, sizeof (inbuf), 1, in); - ucl_parser_add_chunk (parser, inbuf, strlen (inbuf)); - } - fclose (in); - if (ucl_parser_get_error(parser) ) { - printf ("Error occured: %s\n", ucl_parser_get_error(parser)); - ret = 1; - goto end; - } - - obj = ucl_parser_get_object (parser); - if (ucl_parser_get_error(parser)) { - printf ("Error occured: %s\n", ucl_parser_get_error(parser)); - ret = 1; - goto end; - } - - if (argc > 2) { - for (k = 2; k < argc; k++) { - printf ("search for \"%s\"... ", argv[k]); - par = ucl_obj_get_key (obj, argv[k]); - printf ("%sfound\n", (par == NULL )?"not ":""); - ucl_obj_dump (par, 0); - } - } - else { - ucl_obj_dump (obj, 0); - } - -end: - if (parser != NULL ) { - ucl_parser_free (parser); - } - if (obj != NULL ) { - ucl_obj_unref (obj); - } - - return ret; -} -- 2.39.5