[submodule "interface"]
path = interface
url = git://github.com/vstakhov/rspamd-interface
+[submodule "src/ucl"]
+ path = src/ucl
+ url = git@github.com:vstakhov/libucl
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)
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)
#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
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})
-Subproject commit cc5f39ee1862df1e8bcd2a1bb65fa3fac538a420
+Subproject commit b1762224e9c8015abd195282ebd2f7728076e23d
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 ++;
--- /dev/null
+Subproject commit 8eb6d5601a8eec27cffa84479281207f726482d3
+++ /dev/null
-.cproject
-.project
-.settings
+++ /dev/null
-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
+++ /dev/null
-## 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 = <<EOD
-some text
-splitted to
-lines
-EOD
-```
-
-In this example `key` will be interpreted as the following string: `some text\nsplitted to\nlines`.
-Here are some rules for this syntax:
-
-* Multiline terminator must start just after `<<` symbols and it must consist of capital letters only (e.g. `<<eof` or `<< EOF` won't work);
-* Terminator must end with a single newline character (and no spaces are allowed between terminator and newline character);
-* To finish multiline string you need to include a terminator string just after newline and followed by a newline (no spaces or other characters are allowed as well);
-* The initial and the final newlines are not inserted to the resulting string, but you can still specify newlines at the begin and at the end of a value, for example:
-
-```
-key <<EOD
-
-some
-text
-
-EOD
-```
-
-## Emitter
-
-Each UCL object can be serialized to one of the three supported formats:
-
-* `JSON` - canonic json notation (with spaces indented structure);
-* `Compacted JSON` - compact json notation (without spaces or newlines);
-* `Configuration` - nginx like notation;
-* `YAML` - yaml inlined notation.
-
-## Performance
-
-Are UCL parser and emitter fast enough? Well, there are some numbers.
-I got a 19Mb file that consist of ~700 thousands lines of json (obtained via
-http://www.json-generator.com/). Then I checked jansson library that performs json
-parsing and emitting and compared it with UCL. Here are results:
-
-```
-jansson: parsed json in 1.3899 seconds
-jansson: emitted object in 0.2609 seconds
-
-ucl: parsed input in 0.6649 seconds
-ucl: emitted config in 0.2423 seconds
-ucl: emitted json in 0.2329 seconds
-ucl: emitted compact json in 0.1811 seconds
-ucl: emitted yaml in 0.2489 seconds
-```
-
-So far, UCL seems to be significantly faster than jansson on parsing and slightly faster on emitting. Moreover,
-UCL compiled with optimizations (-O3) performs significantly faster:
-```
-ucl: parsed input in 0.3002 seconds
-ucl: emitted config in 0.1174 seconds
-ucl: emitted json in 0.1174 seconds
-ucl: emitted compact json in 0.0991 seconds
-ucl: emitted yaml in 0.1354 seconds
-```
-
-You can do your own benchmarks by running `make test` in libucl top directory.
-
-## Conclusion
-
-UCL has clear design that should be very convenient for reading and writing. At the same time it is compatible with
-JSON language and therefore can be used as a simple JSON parser. Macroes logic provides an ability to extend configuration
-language (for example by including some lua code) and comments allows to disable or enable the parts of a configuration
-quickly.
+++ /dev/null
-/* 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_H_
-#define UCL_H_
-
-#include <string.h>
-#include <stddef.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include <stdbool.h>
-#include <stdarg.h>
-#include <stdio.h>
-#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_ */
+++ /dev/null
-/* 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_ */
+++ /dev/null
-/* 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 <float.h>
-#include <math.h>
-#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;
-}
+++ /dev/null
-/* 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);
- }
-}
+++ /dev/null
-/* 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
+++ /dev/null
-/* 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 <sys/types.h>
-#include <sys/mman.h>
-#include <sys/stat.h>
-#include <sys/param.h>
-
-#include <limits.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <unistd.h>
-#include <ctype.h>
-
-#include "utlist.h"
-#include "utstring.h"
-#include "uthash.h"
-#include "ucl.h"
-#include "ucl_hash.h"
-#include "xxhash.h"
-
-#ifdef HAVE_OPENSSL
-#include <openssl/evp.h>
-#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_ */
+++ /dev/null
-/* 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;
-}
+++ /dev/null
-/* 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 <libgen.h> /* For dirname */
-
-#ifdef HAVE_OPENSSL
-#include <openssl/err.h>
-#include <openssl/sha.h>
-#include <openssl/rsa.h>
-#include <openssl/ssl.h>
-#include <openssl/evp.h>
-#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;
-}
+++ /dev/null
-{
-"key1": value;
-"key1": value2;
-"key1": "value;"
-"key1": 1.0,
-"key1": -1e-10,
-"key1": 1
-"key1": true
-"key1": no
-"key1": yes
-}
+++ /dev/null
-key1 [
- "value",
- "value2",
- "value;",
- 1.0,
- -1e-10,
- 1,
- true,
- false,
- true,
-]
-
+++ /dev/null
-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"
+++ /dev/null
-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;
-
+++ /dev/null
-/*
- * 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
-]
+++ /dev/null
-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",
-]
-
+++ /dev/null
-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 : <<EOD
-test
-test
-test\n
-/* comment like */
-# Some invalid endings
- EOD
-EOD
-EOF
-# Valid ending + empty string
-
-EOD
-
-normal-key : <<EODnot
+++ /dev/null
-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 = "test\ntest\ntest\\n\n/* comment like */\n# Some invalid endings\n EOD\nEOD \nEOF\n# Valid ending + empty string\n";
-normal-key = "<<EODnot";
-
+++ /dev/null
-key1 = "test string";
-key2 = "test \\nstring";
-key3 = " test string \n";
-key4 [
- [
- 10,
- 10.100000,
- ],
- true,
-]
-key5 = "";
-key6 = "";
-key7 = " \\n";
-key8 = 1048576;
-key9 = 3.140000;
-key10 = true;
-key11 = false;
-key12 = "gslin@gslin.org";
-key13 = "#test";
-"k=3" = true;
-
+++ /dev/null
-#!/bin/sh
-
-if [ $# -lt 1 ] ; then
- echo 'Specify binary to run as the first argument'
- exit 1
-fi
-
-
-for _tin in ${TEST_DIR}/*.in ; do
- _t=`echo $_tin | sed -e 's/.in$//'`
- $1 $_t.in $_t.out
- if [ $? -ne 0 ] ; then
- echo "Test: $_t failed, output:"
- cat $_t.out
- rm $_t.out
- exit 1
- fi
- if [ -f $_t.res ] ; then
- diff -s $_t.out $_t.res -u 2>/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
-
+++ /dev/null
-/* 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 <stdio.h>
-#include <errno.h>
-#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;
-}
+++ /dev/null
-/* 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 <stdio.h>
-#include <errno.h>
-#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;
-}
+++ /dev/null
-/* 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 <sys/types.h>
-#include <sys/mman.h>
-#include <sys/stat.h>
-#include <sys/time.h>
-#include <stdio.h>
-#include <errno.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <time.h>
-
-#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;
-}
+++ /dev/null
-/* 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 <stdio.h>
-#include <ctype.h>
-#include <stdbool.h>
-
-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;
-}
+++ /dev/null
-/* 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 <stdio.h>
-#include <errno.h>
-
-#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;
-}