From owner-svn-src-all@FreeBSD.ORG Sat May 24 23:46:43 2014 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) (using TLSv1 with cipher ADH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id 9682693C; Sat, 24 May 2014 23:46:43 +0000 (UTC) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 83960285B; Sat, 24 May 2014 23:46:43 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.8/8.14.8) with ESMTP id s4ONkhiX080330; Sat, 24 May 2014 23:46:43 GMT (envelope-from bapt@svn.freebsd.org) Received: (from bapt@localhost) by svn.freebsd.org (8.14.8/8.14.8/Submit) id s4ONkg8s080321; Sat, 24 May 2014 23:46:42 GMT (envelope-from bapt@svn.freebsd.org) Message-Id: <201405242346.s4ONkg8s080321@svn.freebsd.org> From: Baptiste Daroussin Date: Sat, 24 May 2014 23:46:42 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r266636 - in head/contrib/libucl: . include src tests X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 24 May 2014 23:46:43 -0000 Author: bapt Date: Sat May 24 23:46:41 2014 New Revision: 266636 URL: http://svnweb.freebsd.org/changeset/base/266636 Log: merge libucl 20140514 this version brings xpath-like interface for ucl objects Modified: head/contrib/libucl/configure.ac head/contrib/libucl/include/ucl.h head/contrib/libucl/src/ucl_internal.h head/contrib/libucl/src/ucl_parser.c head/contrib/libucl/src/ucl_util.c head/contrib/libucl/tests/test_generate.c Directory Properties: head/contrib/libucl/ (props changed) Modified: head/contrib/libucl/configure.ac ============================================================================== --- head/contrib/libucl/configure.ac Sat May 24 23:42:44 2014 (r266635) +++ head/contrib/libucl/configure.ac Sat May 24 23:46:41 2014 (r266636) @@ -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]) Modified: head/contrib/libucl/include/ucl.h ============================================================================== --- head/contrib/libucl/include/ucl.h Sat May 24 23:42:44 2014 (r266635) +++ head/contrib/libucl/include/ucl.h Sat May 24 23:46:41 2014 (r266636) @@ -236,7 +236,13 @@ UCL_EXTERN ucl_object_t* ucl_object_new * @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 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_objec 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_macr 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_vari 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 Modified: head/contrib/libucl/src/ucl_internal.h ============================================================================== --- head/contrib/libucl/src/ucl_internal.h Sat May 24 23:42:44 2014 (r266635) +++ head/contrib/libucl/src/ucl_internal.h Sat May 24 23:46:41 2014 (r266636) @@ -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; }; Modified: head/contrib/libucl/src/ucl_parser.c ============================================================================== --- head/contrib/libucl/src/ucl_parser.c Sat May 24 23:42:44 2014 (r266635) +++ head/contrib/libucl/src/ucl_parser.c Sat May 24 23:46:41 2014 (r266636) @@ -236,6 +236,9 @@ ucl_check_variable_safe (struct ucl_pars 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_pars } } + /* 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_pars * @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 *p 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_p } else if (*p == '{') { p ++; + strict = true; ret += 2; remain -= 2; } @@ -359,9 +381,22 @@ ucl_expand_single_variable (struct ucl_p } } 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 } } +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) Modified: head/contrib/libucl/src/ucl_util.c ============================================================================== --- head/contrib/libucl/src/ucl_util.c Sat May 24 23:42:44 2014 (r266635) +++ head/contrib/libucl/src/ucl_util.c Sat May 24 23:46:41 2014 (r266636) @@ -1330,20 +1330,10 @@ ucl_object_find_keyl (const ucl_object_t 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 * 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) { Modified: head/contrib/libucl/tests/test_generate.c ============================================================================== --- head/contrib/libucl/tests/test_generate.c Sat May 24 23:42:44 2014 (r266635) +++ head/contrib/libucl/tests/test_generate.c Sat May 24 23:46:41 2014 (r266636) @@ -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);