aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBaptiste Daroussin <bapt@FreeBSD.org>2014-05-24 23:40:39 +0000
committerBaptiste Daroussin <bapt@FreeBSD.org>2014-05-24 23:40:39 +0000
commiteaa81a1805da0fde938c109a768e9c48471c3bb9 (patch)
tree11177c8667280f65b11e0c5d96830f43a8e5d860
parentd4fc17b1e5ff64ea70cfb02594ae87f599f81c29 (diff)
downloadsrc-eaa81a1805da0fde938c109a768e9c48471c3bb9.tar.gz
src-eaa81a1805da0fde938c109a768e9c48471c3bb9.zip
Import libucl version 2014-05-14 (almost 0.4.1)vendor/libucl/20140514
This bring ucl_lookup_path (xpath like for ucl objects)
Notes
Notes: svn path=/vendor/libucl/dist/; revision=266634 svn path=/vendor/libucl/20140514/; revision=266635; tag=vendor/libucl/20140514
-rw-r--r--configure.ac4
-rw-r--r--include/ucl.h48
-rw-r--r--src/ucl_internal.h2
-rw-r--r--src/ucl_parser.c55
-rw-r--r--src/ucl_util.c95
-rw-r--r--tests/test_generate.c18
6 files changed, 200 insertions, 22 deletions
diff --git a/configure.ac b/configure.ac
index 1f6e87d41ef0..de78e8b183aa 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,7 +1,7 @@
m4_define([maj_ver], [0])
m4_define([med_ver], [4])
-m4_define([min_ver], [0])
-m4_define([so_version], [maj_ver:med_ver])
+m4_define([min_ver], [1])
+m4_define([so_version], [1:0:0])
m4_define([ucl_version], [maj_ver.med_ver.min_ver])
AC_INIT([libucl],[ucl_version],[https://github.com/vstakhov/libucl],[libucl])
diff --git a/include/ucl.h b/include/ucl.h
index 08039b29001e..3eeea9a7df0e 100644
--- a/include/ucl.h
+++ b/include/ucl.h
@@ -236,7 +236,13 @@ UCL_EXTERN ucl_object_t* ucl_object_new (void) UCL_WARN_UNUSED_RESULT;
* @param type type of a new object
* @return new object
*/
-UCL_EXTERN ucl_object_t* ucl_object_typed_new (unsigned int type) UCL_WARN_UNUSED_RESULT;
+UCL_EXTERN ucl_object_t* ucl_object_typed_new (ucl_type_t type) UCL_WARN_UNUSED_RESULT;
+
+/**
+ * Return the type of an object
+ * @return the object type
+ */
+UCL_EXTERN ucl_type_t ucl_object_type (const ucl_object_t *obj);
/**
* Convert any string to an ucl object making the specified transformations
@@ -413,6 +419,15 @@ UCL_EXTERN const ucl_object_t* ucl_array_tail (const ucl_object_t *top);
UCL_EXTERN ucl_object_t* ucl_array_pop_last (ucl_object_t *top);
/**
+ * Return object identified by an index of the array `top`
+ * @param obj object to get a key from (must be of type UCL_ARRAY)
+ * @param index index to return
+ * @return object at the specified index or NULL if index is not found
+ */
+UCL_EXTERN const ucl_object_t* ucl_array_find_index (const ucl_object_t *top,
+ unsigned int index);
+
+/**
* Removes the first element from the array `top`. Caller must unref the returned object when it is not
* needed.
* @param top array ucl object
@@ -534,6 +549,15 @@ UCL_EXTERN const ucl_object_t* ucl_object_find_keyl (const ucl_object_t *obj,
const char *key, size_t klen);
/**
+ * Return object identified by dot notation string
+ * @param obj object to search in
+ * @param path dot.notation.path to the path to lookup. May use numeric .index on arrays
+ * @return object matched the specified path or NULL if path is not found
+ */
+UCL_EXTERN const ucl_object_t *ucl_lookup_path (const ucl_object_t *obj,
+ const char *path);
+
+/**
* Returns a key of an object as a NULL terminated string
* @param obj CL object
* @return key or NULL if there is no key
@@ -643,6 +667,19 @@ UCL_EXTERN void ucl_parser_register_macro (struct ucl_parser *parser, const char
ucl_macro_handler handler, void* ud);
/**
+ * Handler to detect unregistered variables
+ * @param data variable data
+ * @param len length of variable
+ * @param replace (out) replace value for variable
+ * @param replace_len (out) replace length for variable
+ * @param need_free (out) UCL will free `dest` after usage
+ * @param ud opaque userdata
+ * @return true if variable
+ */
+typedef bool (*ucl_variable_handler) (const unsigned char *data, size_t len,
+ unsigned char **replace, size_t *replace_len, bool *need_free, void* ud);
+
+/**
* Register new parser variable
* @param parser parser object
* @param var variable name
@@ -652,6 +689,15 @@ UCL_EXTERN void ucl_parser_register_variable (struct ucl_parser *parser, const c
const char *value);
/**
+ * Set handler for unknown variables
+ * @param parser parser structure
+ * @param handler desired handler
+ * @param ud opaque data for the handler
+ */
+UCL_EXTERN void ucl_parser_set_variables_handler (struct ucl_parser *parser,
+ ucl_variable_handler handler, void *ud);
+
+/**
* Load new chunk to a parser
* @param parser parser structure
* @param data the pointer to the beginning of a chunk
diff --git a/src/ucl_internal.h b/src/ucl_internal.h
index 9a35dcec40be..0e3ecd012cc7 100644
--- a/src/ucl_internal.h
+++ b/src/ucl_internal.h
@@ -197,6 +197,8 @@ struct ucl_parser {
struct ucl_chunk *chunks;
struct ucl_pubkey *keys;
struct ucl_variable *variables;
+ ucl_variable_handler var_handler;
+ void *var_data;
UT_string *err;
};
diff --git a/src/ucl_parser.c b/src/ucl_parser.c
index d5a085ebf829..b4fe5afc8246 100644
--- a/src/ucl_parser.c
+++ b/src/ucl_parser.c
@@ -236,6 +236,9 @@ ucl_check_variable_safe (struct ucl_parser *parser, const char *ptr, size_t rema
size_t *out_len, bool strict, bool *found)
{
struct ucl_variable *var;
+ unsigned char *dst;
+ size_t dstlen;
+ bool need_free = false;
LL_FOREACH (parser->variables, var) {
if (strict) {
@@ -258,6 +261,19 @@ ucl_check_variable_safe (struct ucl_parser *parser, const char *ptr, size_t rema
}
}
+ /* XXX: can only handle ${VAR} */
+ if (!(*found) && parser->var_handler != NULL && strict) {
+ /* Call generic handler */
+ if (parser->var_handler (ptr, remain, &dst, &dstlen, &need_free,
+ parser->var_data)) {
+ *found = true;
+ if (need_free) {
+ free (dst);
+ }
+ return (ptr + remain);
+ }
+ }
+
return ptr;
}
@@ -271,7 +287,8 @@ ucl_check_variable_safe (struct ucl_parser *parser, const char *ptr, size_t rema
* @return
*/
static const char *
-ucl_check_variable (struct ucl_parser *parser, const char *ptr, size_t remain, size_t *out_len, bool *vars_found)
+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;
@@ -282,7 +299,8 @@ ucl_check_variable (struct ucl_parser *parser, const char *ptr, size_t remain, s
end = ptr + remain;
while (p < end) {
if (*p == '}') {
- ret = ucl_check_variable_safe (parser, ptr + 1, p - ptr - 1, out_len, true, &found);
+ ret = ucl_check_variable_safe (parser, ptr + 1, p - ptr - 1,
+ out_len, true, &found);
if (found) {
/* {} must be excluded actually */
ret ++;
@@ -328,10 +346,13 @@ static const char *
ucl_expand_single_variable (struct ucl_parser *parser, const char *ptr,
size_t remain, unsigned char **dest)
{
- unsigned char *d = *dest;
+ unsigned char *d = *dest, *dst;
const char *p = ptr + 1, *ret;
struct ucl_variable *var;
+ size_t dstlen;
+ bool need_free = false;
bool found = false;
+ bool strict = false;
ret = ptr + 1;
remain --;
@@ -343,6 +364,7 @@ ucl_expand_single_variable (struct ucl_parser *parser, const char *ptr,
}
else if (*p == '{') {
p ++;
+ strict = true;
ret += 2;
remain -= 2;
}
@@ -359,9 +381,22 @@ ucl_expand_single_variable (struct ucl_parser *parser, const char *ptr,
}
}
if (!found) {
- memcpy (d, ptr, 2);
- d += 2;
- ret --;
+ if (strict && parser->var_handler != NULL) {
+ if (parser->var_handler (ptr, remain, &dst, &dstlen, &need_free,
+ parser->var_data)) {
+ memcpy (d, dst, dstlen);
+ ret += dstlen;
+ d += remain;
+ found = true;
+ }
+ }
+
+ /* Leave variable as is */
+ if (!found) {
+ memcpy (d, ptr, 2);
+ d += 2;
+ ret --;
+ }
}
*dest = d;
@@ -1873,6 +1908,14 @@ ucl_parser_register_variable (struct ucl_parser *parser, const char *var,
}
}
+void
+ucl_parser_set_variables_handler (struct ucl_parser *parser,
+ ucl_variable_handler handler, void *ud)
+{
+ parser->var_handler = handler;
+ parser->var_data = ud;
+}
+
bool
ucl_parser_add_chunk (struct ucl_parser *parser, const unsigned char *data,
size_t len)
diff --git a/src/ucl_util.c b/src/ucl_util.c
index 9178795d9446..63f5e629826f 100644
--- a/src/ucl_util.c
+++ b/src/ucl_util.c
@@ -1330,20 +1330,10 @@ ucl_object_find_keyl (const ucl_object_t *obj, const char *key, size_t klen)
const ucl_object_t *
ucl_object_find_key (const ucl_object_t *obj, const char *key)
{
- size_t klen;
- const ucl_object_t *ret;
- ucl_object_t srch;
-
- if (obj == NULL || obj->type != UCL_OBJECT || key == NULL) {
+ if (key == NULL)
return NULL;
- }
-
- klen = strlen (key);
- srch.key = key;
- srch.keylen = klen;
- ret = ucl_hash_search_obj (obj->value.ov, &srch);
- return ret;
+ return ucl_object_find_keyl (obj, key, strlen(key));
}
const ucl_object_t*
@@ -1396,6 +1386,58 @@ ucl_iterate_object (const ucl_object_t *obj, ucl_object_iter_t *iter, bool expan
return NULL;
}
+const ucl_object_t *
+ucl_lookup_path (const ucl_object_t *top, const char *path_in) {
+ const ucl_object_t *o = NULL, *found;
+ const char *p, *c;
+ char *err_str;
+ unsigned index;
+
+ if (path_in == NULL || top == NULL) {
+ return NULL;
+ }
+
+ found = NULL;
+ p = path_in;
+
+ /* Skip leading dots */
+ while (*p == '.') {
+ p ++;
+ }
+
+ c = p;
+ while (*p != '\0') {
+ p ++;
+ if (*p == '.' || *p == '\0') {
+ if (p > c) {
+ switch (top->type) {
+ case UCL_ARRAY:
+ /* Key should be an int */
+ index = strtoul (c, &err_str, 10);
+ if (err_str != NULL && (*err_str != '.' && *err_str != '\0')) {
+ return NULL;
+ }
+ o = ucl_array_find_index (top, index);
+ break;
+ default:
+ o = ucl_object_find_keyl (top, c, p - c);
+ break;
+ }
+ if (o == NULL) {
+ return NULL;
+ }
+ top = o;
+ }
+ if (*p != '\0') {
+ c = p + 1;
+ }
+ }
+ }
+ found = o;
+
+ return found;
+}
+
ucl_object_t *
ucl_object_new (void)
@@ -1411,7 +1453,7 @@ ucl_object_new (void)
}
ucl_object_t *
-ucl_object_typed_new (unsigned int type)
+ucl_object_typed_new (ucl_type_t type)
{
ucl_object_t *new;
new = malloc (sizeof (ucl_object_t));
@@ -1423,6 +1465,12 @@ ucl_object_typed_new (unsigned int type)
return new;
}
+ucl_type_t
+ucl_object_type (const ucl_object_t *obj)
+{
+ return obj->type;
+}
+
ucl_object_t*
ucl_object_fromstring (const char *str)
{
@@ -1591,6 +1639,27 @@ ucl_array_pop_first (ucl_object_t *top)
return ucl_array_delete (top, __DECONST(ucl_object_t *, ucl_array_head (top)));
}
+const ucl_object_t *
+ucl_array_find_index (const ucl_object_t *top, unsigned int index)
+{
+ ucl_object_iter_t it = NULL;
+ const ucl_object_t *ret;
+
+ if (top == NULL || top->type != UCL_ARRAY || top->len == 0 ||
+ (index + 1) > top->len) {
+ return NULL;
+ }
+
+ while ((ret = ucl_iterate_object (top, &it, true)) != NULL) {
+ if (index == 0) {
+ return ret;
+ }
+ --index;
+ }
+
+ return NULL;
+}
+
ucl_object_t *
ucl_elt_append (ucl_object_t *head, ucl_object_t *elt)
{
diff --git a/tests/test_generate.c b/tests/test_generate.c
index 2b1bf8d73a3f..5c130e67499a 100644
--- a/tests/test_generate.c
+++ b/tests/test_generate.c
@@ -30,6 +30,7 @@ int
main (int argc, char **argv)
{
ucl_object_t *obj, *cur, *ar, *ref;
+ const ucl_object_t *found;
FILE *out;
unsigned char *emitted;
const char *fname_out = NULL;
@@ -114,6 +115,23 @@ main (int argc, char **argv)
cur = ucl_object_frombool (true);
ucl_object_insert_key (obj, cur, "k=3", 0, false);
+ /* Try to find using path */
+ /* Should exist */
+ found = ucl_lookup_path (obj, "key4.1");
+ assert (found != NULL && ucl_object_toint (found) == 10);
+ /* . should be ignored */
+ found = ucl_lookup_path (obj, ".key4.1");
+ assert (found != NULL && ucl_object_toint (found) == 10);
+ /* moar dots... */
+ found = ucl_lookup_path (obj, ".key4........1...");
+ assert (found != NULL && ucl_object_toint (found) == 10);
+ /* No such index */
+ found = ucl_lookup_path (obj, ".key4.3");
+ assert (found == NULL);
+ /* No such key */
+ found = ucl_lookup_path (obj, "key9..key1");
+ assert (found == NULL);
+
emitted = ucl_object_emit (obj, UCL_EMIT_CONFIG);
fprintf (out, "%s\n", emitted);