aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBaptiste Daroussin <bapt@FreeBSD.org>2014-03-10 10:23:43 +0000
committerBaptiste Daroussin <bapt@FreeBSD.org>2014-03-10 10:23:43 +0000
commit2ae6de7c252d1781a158740c2481220dfdd6cc77 (patch)
tree44e99c17cbb39524d859345699343791cbc999d7
parent337c43ffbe4b39c23f85d4ad6413da1070457d63 (diff)
downloadsrc-2ae6de7c252d1781a158740c2481220dfdd6cc77.tar.gz
src-2ae6de7c252d1781a158740c2481220dfdd6cc77.zip
Update libucl to 2014-03-02 version which fixes an important bug when parsing empty arraysvendor/libucl/20140302
Notes
Notes: svn path=/vendor/libucl/dist/; revision=262973 svn path=/vendor/libucl/20140302/; revision=262974; tag=vendor/libucl/20140302
-rw-r--r--Makefile.unix (renamed from Makefile)2
-rw-r--r--Makefile.w3279
-rw-r--r--doc/api.md87
-rw-r--r--include/ucl.h65
-rw-r--r--src/ucl_internal.h2
-rw-r--r--src/ucl_parser.c79
-rw-r--r--src/ucl_util.c114
-rw-r--r--tests/10.in1
-rw-r--r--tests/8.in2
-rw-r--r--tests/8.res2
10 files changed, 371 insertions, 62 deletions
diff --git a/Makefile b/Makefile.unix
index 82c7057166d2..71c7540f7cfe 100644
--- a/Makefile
+++ b/Makefile.unix
@@ -20,7 +20,7 @@ LN ?= ln
LD_SHARED_FLAGS ?= -Wl,-soname,$(SONAME) -shared -lm
LD_UCL_FLAGS ?= -L$(OBJDIR) -Wl,-rpath,$(OBJDIR) -lucl
LD_ADD ?= -lrt
-COPT_FLAGS ?= -g -O0
+COPT_FLAGS ?= -O2
HDEPS = $(SRCDIR)/ucl_hash.h $(SRCDIR)/ucl_chartable.h $(SRCDIR)/ucl_internal.h $(INCLUDEDIR)/ucl.h $(SRCDIR)/xxhash.h
OBJECTS = $(OBJDIR)/ucl_hash.o $(OBJDIR)/ucl_util.o $(OBJDIR)/ucl_parser.o $(OBJDIR)/ucl_emitter.o $(OBJDIR)/xxhash.o
diff --git a/Makefile.w32 b/Makefile.w32
new file mode 100644
index 000000000000..895db1d0d961
--- /dev/null
+++ b/Makefile.w32
@@ -0,0 +1,79 @@
+CC ?= gcc
+DESTDIR ?= /usr/local
+LD ?= gcc
+C_COMMON_FLAGS ?= -fPIC -Wall -W -Wno-unused-parameter -Wno-pointer-sign -I./include -I./uthash -I./src
+MAJOR_VERSION = 0
+MINOR_VERSION = 2
+PATCH_VERSION = 8
+VERSION = "$(MAJOR_VERSION).$(MINOR_VERSION).$(PATCH_VERSION)"
+SONAME = libucl.dll
+OBJDIR ?= .obj
+TESTDIR ?= tests
+SRCDIR ?= src
+INCLUDEDIR ?= include
+MKDIR ?= mkdir
+INSTALL ?= install
+RM ?= rm
+RMDIR ?= rmdir
+ifeq (Windows_NT, $(OS))
+LN ?= ln
+else
+LN ?= rem ln
+endif
+LD_SHARED_FLAGS ?= -Wl,-soname,$(SONAME) -shared -lm
+LD_UCL_FLAGS ?= -L$(OBJDIR) -Wl,-rpath,$(OBJDIR) -lucl
+LD_ADD ?= -lrt
+COPT_FLAGS ?= -O2
+HDEPS = $(SRCDIR)/ucl_hash.h $(SRCDIR)/ucl_chartable.h $(SRCDIR)/ucl_internal.h $(INCLUDEDIR)/ucl.h $(SRCDIR)/xxhash.h
+OBJECTS = $(OBJDIR)/ucl_hash.o $(OBJDIR)/ucl_util.o $(OBJDIR)/ucl_parser.o $(OBJDIR)/ucl_emitter.o $(OBJDIR)/xxhash.o
+
+all: $(OBJDIR) $(OBJDIR)/$(SONAME)
+
+$(OBJDIR)/$(SONAME): $(OBJECTS)
+ $(CC) -o $(OBJDIR)/$(SONAME) $(OBJECTS) $(LD_SHARED_FLAGS) $(LDFLAGS) $(SSL_LIBS) $(FETCH_LIBS)
+
+$(OBJDIR):
+ @$(MKDIR) -p $(OBJDIR)
+
+# Compile rules
+$(OBJDIR)/ucl_util.o: $(SRCDIR)/ucl_util.c $(HDEPS)
+ $(CC) -o $(OBJDIR)/ucl_util.o $(CPPFLAGS) $(COPT_FLAGS) $(CFLAGS) $(C_COMMON_FLAGS) $(SSL_CFLAGS) $(FETCH_FLAGS) -c $(SRCDIR)/ucl_util.c
+$(OBJDIR)/ucl_parser.o: $(SRCDIR)/ucl_parser.c $(HDEPS)
+ $(CC) -o $(OBJDIR)/ucl_parser.o $(CPPFLAGS) $(COPT_FLAGS) $(CFLAGS) $(C_COMMON_FLAGS) $(SSL_CFLAGS) $(FETCH_FLAGS) -c $(SRCDIR)/ucl_parser.c
+$(OBJDIR)/ucl_emitter.o: $(SRCDIR)/ucl_emitter.c $(HDEPS)
+ $(CC) -o $(OBJDIR)/ucl_emitter.o $(CPPFLAGS) $(COPT_FLAGS) $(CFLAGS) $(C_COMMON_FLAGS) $(SSL_CFLAGS) $(FETCH_FLAGS) -c $(SRCDIR)/ucl_emitter.c
+$(OBJDIR)/ucl_hash.o: $(SRCDIR)/ucl_hash.c $(HDEPS)
+ $(CC) -o $(OBJDIR)/ucl_hash.o $(CPPFLAGS) $(COPT_FLAGS) $(CFLAGS) $(C_COMMON_FLAGS) $(SSL_CFLAGS) $(FETCH_FLAGS) -c $(SRCDIR)/ucl_hash.c
+$(OBJDIR)/xxhash.o: $(SRCDIR)/xxhash.c $(HDEPS)
+ $(CC) -o $(OBJDIR)/xxhash.o $(CPPFLAGS) $(COPT_FLAGS) $(CFLAGS) $(C_COMMON_FLAGS) $(SSL_CFLAGS) $(FETCH_FLAGS) -c $(SRCDIR)/xxhash.c
+
+clean:
+ $(RM) $(OBJDIR)/*.o $(OBJDIR)/$(SONAME) $(OBJDIR)/$(SONAME) $(OBJDIR)/chargen $(OBJDIR)/test_basic $(OBJDIR)/test_speed $(OBJDIR)/objdump $(OBJDIR)/test_generate
+ $(RMDIR) $(OBJDIR)
+
+# Utils
+
+chargen: utils/chargen.c $(OBJDIR)/$(SONAME)
+ $(CC) -o $(OBJDIR)/chargen $(CPPFLAGS) $(COPT_FLAGS) $(CFLAGS) $(C_COMMON_FLAGS) $(SSL_CFLAGS) $(FETCH_FLAGS) $(LDFLAGS) utils/chargen.c
+objdump: utils/objdump.c $(OBJDIR)/$(SONAME)
+ $(CC) -o $(OBJDIR)/objdump $(CPPFLAGS) $(COPT_FLAGS) $(CFLAGS) $(C_COMMON_FLAGS) $(SSL_CFLAGS) $(FETCH_FLAGS) $(LDFLAGS) utils/objdump.c $(LD_UCL_FLAGS)
+
+# Tests
+
+test: $(OBJDIR) $(OBJDIR)/$(SONAME) $(OBJDIR)/test_basic $(OBJDIR)/test_speed $(OBJDIR)/test_generate
+
+run-test: test
+ TEST_DIR=$(TESTDIR) $(TESTDIR)/run_tests.sh $(OBJDIR)/test_basic $(OBJDIR)/test_speed $(OBJDIR)/test_generate
+
+$(OBJDIR)/test_basic: $(TESTDIR)/test_basic.c $(OBJDIR)/$(SONAME)
+ $(CC) -o $(OBJDIR)/test_basic $(CPPFLAGS) $(COPT_FLAGS) $(CFLAGS) $(C_COMMON_FLAGS) $(SSL_CFLAGS) $(FETCH_FLAGS) $(LDFLAGS) $(TESTDIR)/test_basic.c $(LD_UCL_FLAGS)
+$(OBJDIR)/test_speed: $(TESTDIR)/test_speed.c $(OBJDIR)/$(SONAME)
+ $(CC) -o $(OBJDIR)/test_speed $(CPPFLAGS) $(COPT_FLAGS) $(CFLAGS) $(C_COMMON_FLAGS) $(SSL_CFLAGS) $(FETCH_FLAGS) $(LDFLAGS) $(TESTDIR)/test_speed.c $(LD_UCL_FLAGS) $(LD_ADD)
+$(OBJDIR)/test_generate: $(TESTDIR)/test_generate.c $(OBJDIR)/$(SONAME)
+ $(CC) -o $(OBJDIR)/test_generate $(CPPFLAGS) $(COPT_FLAGS) $(CFLAGS) $(C_COMMON_FLAGS) $(SSL_CFLAGS) $(FETCH_FLAGS) $(LDFLAGS) $(TESTDIR)/test_generate.c $(LD_UCL_FLAGS) $(LD_ADD)
+
+install: $(OBJDIR)/$(SONAME)
+ $(INSTALL) -m0755 $(SONAME) $(DESTDIR)/lib/$(SONAME)
+ $(INSTALL) -m0644 include/ucl.h $(DESTDIR)/include/ucl.h
+
+.PHONY: clean $(OBJDIR)
diff --git a/doc/api.md b/doc/api.md
index a85f8513a040..0523f53624ef 100644
--- a/doc/api.md
+++ b/doc/api.md
@@ -260,4 +260,89 @@ Here is a list of all conversion functions:
- `ucl_object_tolstring` - returns `const char *` and `size_t` len of UCL object (string can be not NULL terminated)
- `ucl_object_tostring_forced` - returns string representation of any UCL object
-Strings returned by these pointers are associated with the UCL object and exist over its lifetime. A caller should not free this memory. \ No newline at end of file
+Strings returned by these pointers are associated with the UCL object and exist over its lifetime. A caller should not free this memory.
+
+# Generation functions
+
+It is possible to generate UCL objects from C primitive types. Moreover, libucl permits to create and modify complex UCL objects, such as arrays or associative objects.
+
+## ucl_object_new
+~~~C
+ucl_object_t * ucl_object_new (void)
+~~~
+
+Creates new object of type `UCL_NULL`. This object should be released by caller.
+
+## ucl_object_typed_new
+~~~C
+ucl_object_t * ucl_object_typed_new (unsigned int type)
+~~~
+
+Create an object of a specified type:
+- `UCL_OBJECT` - 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
+
+This object should be released by caller.
+
+## Primitive objects generation
+Libucl provides the functions similar to inverse conversion functions called with the specific C type:
+- `ucl_object_fromint` - converts `int64_t` to UCL object
+- `ucl_object_fromdouble` - converts `double` to UCL object
+- `ucl_object_fromboolean` - converts `bool` to UCL object
+- `ucl_object_fromstring` - converts `const char *` to UCL object (this string is NULL terminated)
+- `ucl_object_fromlstring` - converts `const char *` and `size_t` len to UCL object (string can be not NULL terminated)
+
+Also there is a function to generate UCL object from a string performing various parsing or conversion operations called `ucl_object_fromstring_common`.
+
+## ucl_object_fromstring_common
+~~~C
+ucl_object_t * ucl_object_fromstring_common (const char *str,
+ size_t len, enum ucl_string_flags flags)
+~~~
+
+This function is used to convert a string `str` of size `len` to an UCL objects applying `flags` conversions. If `len` is equal to zero then a `str` is assumed as NULL-terminated. This function supports the following flags (a set of flags can be specified using logical `OR` operation):
+
+- `UCL_STRING_ESCAPE` - perform JSON escape
+- `UCL_STRING_TRIM` - trim leading and trailing whitespaces
+- `UCL_STRING_PARSE_BOOLEAN` - parse passed string and detect boolean
+- `UCL_STRING_PARSE_INT` - parse passed string and detect integer number
+- `UCL_STRING_PARSE_DOUBLE` - parse passed string and detect integer or float number
+- `UCL_STRING_PARSE_NUMBER` - parse passed string and detect number (both float or integer types)
+- `UCL_STRING_PARSE` - parse passed string (and detect booleans and numbers)
+- `UCL_STRING_PARSE_BYTES` - assume that numeric multipliers are in bytes notation, for example `10k` means `10*1024` and not `10*1000` as assumed without this flag
+
+If parsing operations fail then the resulting UCL object will be a `UCL_STRING`. A caller should always check the type of the returned object and release it after using.
+
+# Iteration function
+
+Iteration are used to iterate over UCL compound types: arrays and objects. Moreover, iterations could be performed over the keys with multiple values (implicit arrays). To iterate over an object, an array or a key with multiple values there is a function `ucl_iterate_object`.
+
+## ucl_iterate_object
+~~~C
+ucl_object_t* ucl_iterate_object (ucl_object_t *obj,
+ ucl_object_iter_t *iter, bool expand_values);
+~~~
+
+This function accept opaque iterator pointer `iter`. In the first call this iterator *must* be initialized to `NULL`. Iterator is changed by this function call. `ucl_iterate_object` returns the next UCL object in the compound object `obj` or `NULL` if all objects have been iterated. The reference count of the object returned is not increased, so a caller should not unref the object or modify its content (e.g. by inserting to another compound object). The object `obj` should not be changed during the iteration process as well. `expand_values` flag speicifies whether `ucl_iterate_object` should expand keys with multiple values. The general rule is that if you need to iterate throught the *object* or *explicit array*, then you always need to set this flag to `true`. However, if you get some key in the object and want to extract all its values then you should set `expand_values` to `false`. Mixing of iteration types are not permitted since the iterator is set according to the iteration type and cannot be reused. Here is an example of iteration over the objects using libucl API (assuming that `top` is `UCL_OBJECT` in this example):
+
+~~~C
+ucl_object_iter_t it = NULL, it_obj = NULL;
+ucl_object_t *cur, *tmp;
+
+/* Iterate over the object */
+while ((obj = ucl_iterate_object (top, &it, true))) {
+ printf ("key: \"%s\"\n", ucl_object_key (obj));
+ /* Iterate over the values of a key */
+ while ((cur = ucl_iterate_object (obj, &it_obj, false))) {
+ printf ("value: \"%s\"\n",
+ ucl_object_tostring_forced (cur));
+ }
+}
+~~~ \ No newline at end of file
diff --git a/include/ucl.h b/include/ucl.h
index 8376b8adc462..a464a006ef78 100644
--- a/include/ucl.h
+++ b/include/ucl.h
@@ -32,6 +32,12 @@
#include <stdarg.h>
#include <stdio.h>
+#ifdef _WIN32
+# define UCL_EXTERN __declspec(dllexport)
+#else
+# define UCL_EXTERN
+#endif
+
/**
* @mainpage
* This is a reference manual for UCL API. You may find the description of UCL format by following this
@@ -200,14 +206,14 @@ typedef struct ucl_object_s {
* @param obj CL object
* @return zero terminated key
*/
-char* ucl_copy_key_trash (ucl_object_t *obj);
+UCL_EXTERN 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);
+UCL_EXTERN char* ucl_copy_value_trash (ucl_object_t *obj);
/**
* Creates a new object
@@ -253,7 +259,7 @@ ucl_object_typed_new (unsigned int type)
* @param flags conversion flags
* @return new object
*/
-ucl_object_t * ucl_object_fromstring_common (const char *str, size_t len,
+UCL_EXTERN ucl_object_t * ucl_object_fromstring_common (const char *str, size_t len,
enum ucl_string_flags flags) UCL_WARN_UNUSED_RESULT;
/**
@@ -345,7 +351,7 @@ ucl_object_frombool (bool bv)
* @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,
+UCL_EXTERN 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;
/**
@@ -358,10 +364,25 @@ ucl_object_t* ucl_object_insert_key (ucl_object_t *top, ucl_object_t *elt,
* @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,
+UCL_EXTERN 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;
/**
+ * Delete a object associated with key 'key', old object will be unrefered,
+ * @param top object
+ * @param key key associated to the object to remove
+ * @param keylen length of the key (or 0 for NULL terminated keys)
+ */
+UCL_EXTERN bool ucl_object_delete_keyl (ucl_object_t *top, const char *key, size_t keylen);
+
+/**
+ * Delete a object associated with key 'key', old object will be unrefered,
+ * @param top object
+ * @param key key associated to the object to remove
+ */
+UCL_EXTERN bool ucl_object_delete_key (ucl_object_t *top, const char *key);
+
+/**
* 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)
@@ -371,7 +392,7 @@ ucl_object_t* ucl_object_replace_key (ucl_object_t *top, ucl_object_t *elt,
* @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,
+UCL_EXTERN 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;
/**
@@ -791,7 +812,7 @@ ucl_object_tolstring (ucl_object_t *obj, size_t *tlen)
* @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);
+UCL_EXTERN 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
@@ -800,7 +821,7 @@ ucl_object_t * ucl_object_find_key (ucl_object_t *obj, const char *key);
* @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);
+UCL_EXTERN 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
@@ -830,7 +851,7 @@ ucl_object_keyl (ucl_object_t *obj, size_t *len)
* Free ucl object
* @param obj ucl object to free
*/
-void ucl_object_free (ucl_object_t *obj);
+UCL_EXTERN void ucl_object_free (ucl_object_t *obj);
/**
* Increase reference count for an object
@@ -865,7 +886,7 @@ typedef void* ucl_object_iter_t;
* 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);
+UCL_EXTERN ucl_object_t* ucl_iterate_object (ucl_object_t *obj, ucl_object_iter_t *iter, bool expand_values);
/** @} */
@@ -894,7 +915,7 @@ struct ucl_parser;
* @param pool pool to allocate memory from
* @return new parser object
*/
-struct ucl_parser* ucl_parser_new (int flags);
+UCL_EXTERN struct ucl_parser* ucl_parser_new (int flags);
/**
* Register new handler for a macro
@@ -903,7 +924,7 @@ struct ucl_parser* ucl_parser_new (int flags);
* @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_EXTERN void ucl_parser_register_macro (struct ucl_parser *parser, const char *macro,
ucl_macro_handler handler, void* ud);
/**
@@ -912,7 +933,7 @@ void ucl_parser_register_macro (struct ucl_parser *parser, const char *macro,
* @param var variable name
* @param value variable value
*/
-void ucl_parser_register_variable (struct ucl_parser *parser, const char *var,
+UCL_EXTERN void ucl_parser_register_variable (struct ucl_parser *parser, const char *var,
const char *value);
/**
@@ -923,7 +944,7 @@ void ucl_parser_register_variable (struct ucl_parser *parser, const char *var,
* @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);
+UCL_EXTERN bool ucl_parser_add_chunk (struct ucl_parser *parser, const unsigned char *data, size_t len);
/**
* Load and add data from a file
@@ -932,7 +953,7 @@ bool ucl_parser_add_chunk (struct ucl_parser *parser, const unsigned char *data,
* @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);
+UCL_EXTERN bool ucl_parser_add_file (struct ucl_parser *parser, const char *filename);
/**
* Get a top object for a parser
@@ -940,18 +961,18 @@ bool ucl_parser_add_file (struct ucl_parser *parser, const char *filename);
* @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);
+UCL_EXTERN 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);
+UCL_EXTERN 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);
+UCL_EXTERN void ucl_parser_free (struct ucl_parser *parser);
/**
* Add new public key to parser for signatures check
@@ -961,7 +982,7 @@ void ucl_parser_free (struct ucl_parser *parser);
* @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);
+UCL_EXTERN bool ucl_pubkey_add (struct ucl_parser *parser, const unsigned char *key, size_t len);
/**
* Set FILENAME and CURDIR variables in parser
@@ -970,7 +991,7 @@ bool ucl_pubkey_add (struct ucl_parser *parser, const unsigned char *key, size_t
* @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,
+UCL_EXTERN bool ucl_parser_set_filevars (struct ucl_parser *parser, const char *filename,
bool need_expand);
/** @} */
@@ -1005,7 +1026,7 @@ struct ucl_emitter_functions {
* #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);
+UCL_EXTERN unsigned char *ucl_object_emit (ucl_object_t *obj, enum ucl_emitter emit_type);
/**
* Emit object to a string
@@ -1014,7 +1035,7 @@ unsigned char *ucl_object_emit (ucl_object_t *obj, enum ucl_emitter emit_type);
* #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,
+UCL_EXTERN bool ucl_object_emit_full (ucl_object_t *obj, enum ucl_emitter emit_type,
struct ucl_emitter_functions *emitter);
/** @} */
diff --git a/src/ucl_internal.h b/src/ucl_internal.h
index e2a6d52fa677..49c4aae5d046 100644
--- a/src/ucl_internal.h
+++ b/src/ucl_internal.h
@@ -25,7 +25,9 @@
#define UCL_INTERNAL_H_
#include <sys/types.h>
+#ifndef _WIN32
#include <sys/mman.h>
+#endif
#include <sys/stat.h>
#include <sys/param.h>
diff --git a/src/ucl_parser.c b/src/ucl_parser.c
index 7aa218152cd1..12ebad274141 100644
--- a/src/ucl_parser.c
+++ b/src/ucl_parser.c
@@ -1233,6 +1233,28 @@ ucl_parse_multiline_string (struct ucl_parser *parser,
return len;
}
+static ucl_object_t*
+ucl_get_value_object (struct ucl_parser *parser)
+{
+ ucl_object_t *t, *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;
+ }
+
+ return obj;
+}
+
/**
* Handle value data
* @param parser
@@ -1243,32 +1265,30 @@ static bool
ucl_parse_value (struct ucl_parser *parser, struct ucl_chunk *chunk)
{
const unsigned char *p, *c;
- ucl_object_t *obj = NULL, *t;
+ ucl_object_t *obj = NULL;
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;
- }
+ /* 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;
+ }
+
+ while (p < chunk->end) {
c = p;
switch (*p) {
case '"':
+ obj = ucl_get_value_object (parser);
ucl_chunk_skipc (chunk, p);
if (!ucl_lex_json_string (parser, chunk, &need_unescape, &ucl_escape, &var_expand)) {
return false;
@@ -1285,6 +1305,7 @@ ucl_parse_value (struct ucl_parser *parser, struct ucl_chunk *chunk)
return true;
break;
case '{':
+ obj = ucl_get_value_object (parser);
/* We have a new object */
obj = ucl_add_parser_stack (obj, parser, false, parser->stack->level);
@@ -1292,13 +1313,25 @@ ucl_parse_value (struct ucl_parser *parser, struct ucl_chunk *chunk)
return true;
break;
case '[':
+ obj = ucl_get_value_object (parser);
/* 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 the array ending */
+ if (parser->stack && parser->stack->obj->type == UCL_ARRAY) {
+ parser->state = UCL_STATE_AFTER_VALUE;
+ return true;
+ }
+ else {
+ goto parse_string;
+ }
+ break;
case '<':
+ obj = ucl_get_value_object (parser);
/* We have something like multiline value, which must be <<[A-Z]+\n */
if (chunk->end - p > 3) {
if (memcmp (p, "<<", 2) == 0) {
@@ -1332,17 +1365,9 @@ ucl_parse_value (struct ucl_parser *parser, struct ucl_chunk *chunk)
}
/* 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_string:
+ if (obj == NULL) {
+ obj = ucl_get_value_object (parser);
}
/* Parse atom */
if (ucl_test_character (*p, UCL_CHARACTER_VALUE_DIGIT_START)) {
diff --git a/src/ucl_util.c b/src/ucl_util.c
index 6ab1d38e7252..34080d441492 100644
--- a/src/ucl_util.c
+++ b/src/ucl_util.c
@@ -35,6 +35,75 @@
#include <openssl/evp.h>
#endif
+#ifdef _WIN32
+#include <windows.h>
+
+#define PROT_READ 1
+#define PROT_WRITE 2
+#define PROT_READWRITE 3
+#define MAP_SHARED 1
+#define MAP_PRIVATE 2
+#define MAP_FAILED ((void *) -1)
+
+static void *mmap(char *addr, size_t length, int prot, int access, int fd, off_t offset)
+{
+ void *map = NULL;
+ HANDLE handle = INVALID_HANDLE_VALUE;
+
+ switch (prot) {
+ default:
+ case PROT_READ:
+ {
+ handle = CreateFileMapping((HANDLE) _get_osfhandle(fd), 0, PAGE_READONLY, 0, length, 0);
+ if (!handle) break;
+ map = (void *) MapViewOfFile(handle, FILE_MAP_READ, 0, 0, length);
+ CloseHandle(handle);
+ break;
+ }
+ case PROT_WRITE:
+ {
+ handle = CreateFileMapping((HANDLE) _get_osfhandle(fd), 0, PAGE_READWRITE, 0, length, 0);
+ if (!handle) break;
+ map = (void *) MapViewOfFile(handle, FILE_MAP_WRITE, 0, 0, length);
+ CloseHandle(handle);
+ break;
+ }
+ case PROT_READWRITE:
+ {
+ handle = CreateFileMapping((HANDLE) _get_osfhandle(fd), 0, PAGE_READWRITE, 0, length, 0);
+ if (!handle) break;
+ map = (void *) MapViewOfFile(handle, FILE_MAP_ALL_ACCESS, 0, 0, length);
+ CloseHandle(handle);
+ break;
+ }
+ }
+ if (map == (void *) NULL) {
+ return (void *) MAP_FAILED;
+ }
+ return (void *) ((char *) map + offset);
+}
+
+static int munmap(void *map,size_t length)
+{
+ if (!UnmapViewOfFile(map)) {
+ return(-1);
+ }
+ return(0);
+}
+
+static char* realpath(const char *path, char *resolved_path) {
+ char *p;
+ char tmp[MAX_PATH + 1];
+ strncpy(tmp, path, sizeof(tmp)-1);
+ p = tmp;
+ while(*p) {
+ if (*p == '/') *p = '\\';
+ p++;
+ }
+ return _fullpath(resolved_path, tmp, MAX_PATH);
+}
+#endif
+
/**
* @file rcl_util.c
* Utilities for rcl parsing
@@ -177,7 +246,7 @@ ucl_unescape_json_string (char *str, size_t len)
return (t - str);
}
-char *
+UCL_EXTERN char *
ucl_copy_key_trash (ucl_object_t *obj)
{
if (obj->trash_stack[UCL_TRASH_KEY] == NULL && obj->key != NULL) {
@@ -193,7 +262,7 @@ ucl_copy_key_trash (ucl_object_t *obj)
return obj->trash_stack[UCL_TRASH_KEY];
}
-char *
+UCL_EXTERN char *
ucl_copy_value_trash (ucl_object_t *obj)
{
if (obj->trash_stack[UCL_TRASH_VALUE] == NULL) {
@@ -216,7 +285,7 @@ ucl_copy_value_trash (ucl_object_t *obj)
return obj->trash_stack[UCL_TRASH_VALUE];
}
-ucl_object_t*
+UCL_EXTERN ucl_object_t*
ucl_parser_get_object (struct ucl_parser *parser)
{
if (parser->state != UCL_STATE_ERROR && parser->top_obj != NULL) {
@@ -226,7 +295,7 @@ ucl_parser_get_object (struct ucl_parser *parser)
return NULL;
}
-void
+UCL_EXTERN void
ucl_parser_free (struct ucl_parser *parser)
{
struct ucl_stack *stack, *stmp;
@@ -266,7 +335,7 @@ ucl_parser_free (struct ucl_parser *parser)
UCL_FREE (sizeof (struct ucl_parser), parser);
}
-const char *
+UCL_EXTERN const char *
ucl_parser_get_error(struct ucl_parser *parser)
{
if (parser->err == NULL)
@@ -275,7 +344,7 @@ ucl_parser_get_error(struct ucl_parser *parser)
return utstring_body(parser->err);
}
-bool
+UCL_EXTERN bool
ucl_pubkey_add (struct ucl_parser *parser, const unsigned char *key, size_t len)
{
#ifndef HAVE_OPENSSL
@@ -679,7 +748,7 @@ ucl_include_file (const unsigned char *data, size_t len,
* @param err error ptr
* @return
*/
-bool
+UCL_EXTERN bool
ucl_include_handler (const unsigned char *data, size_t len, void* ud)
{
struct ucl_parser *parser = ud;
@@ -700,7 +769,7 @@ ucl_include_handler (const unsigned char *data, size_t len, void* ud)
* @param err error ptr
* @return
*/
-bool
+UCL_EXTERN bool
ucl_includes_handler (const unsigned char *data, size_t len, void* ud)
{
struct ucl_parser *parser = ud;
@@ -714,7 +783,7 @@ ucl_includes_handler (const unsigned char *data, size_t len, void* ud)
}
-bool
+UCL_EXTERN bool
ucl_try_include_handler (const unsigned char *data, size_t len, void* ud)
{
struct ucl_parser *parser = ud;
@@ -727,7 +796,7 @@ ucl_try_include_handler (const unsigned char *data, size_t len, void* ud)
return ucl_include_url (data, len, parser, false, false);
}
-bool
+UCL_EXTERN bool
ucl_parser_set_filevars (struct ucl_parser *parser, const char *filename, bool need_expand)
{
char realbuf[PATH_MAX], *curdir;
@@ -757,7 +826,7 @@ ucl_parser_set_filevars (struct ucl_parser *parser, const char *filename, bool n
return true;
}
-bool
+UCL_EXTERN bool
ucl_parser_add_file (struct ucl_parser *parser, const char *filename)
{
unsigned char *buf;
@@ -1055,6 +1124,29 @@ ucl_object_insert_key_common (ucl_object_t *top, ucl_object_t *elt,
return top;
}
+bool
+ucl_object_delete_keyl(ucl_object_t *top, const char *key, size_t keylen)
+{
+ ucl_object_t *found;
+
+ found = ucl_object_find_keyl(top, key, keylen);
+
+ if (found == NULL)
+ return false;
+
+ ucl_hash_delete(top->value.ov, found);
+ ucl_object_unref (found);
+ top->len --;
+
+ return true;
+}
+
+bool
+ucl_object_delete_key(ucl_object_t *top, const char *key)
+{
+ return ucl_object_delete_keyl(top, key, 0);
+}
+
ucl_object_t *
ucl_object_insert_key (ucl_object_t *top, ucl_object_t *elt,
const char *key, size_t keylen, bool copy_key)
diff --git a/tests/10.in b/tests/10.in
new file mode 100644
index 000000000000..560150cb3d4d
--- /dev/null
+++ b/tests/10.in
@@ -0,0 +1 @@
+a []
diff --git a/tests/8.in b/tests/8.in
index 5559b3c9ef7a..605c0c9a4ad9 100644
--- a/tests/8.in
+++ b/tests/8.in
@@ -19,3 +19,5 @@ section test {
section foo { # test
param = 123.2;
}
+
+array = []
diff --git a/tests/8.res b/tests/8.res
index 36eb39a44e70..54c904e545e0 100644
--- a/tests/8.res
+++ b/tests/8.res
@@ -33,4 +33,6 @@ section {
param = 123.200000;
}
}
+array [
+]