diff options
Diffstat (limited to 'src/ucl_util.c')
-rw-r--r-- | src/ucl_util.c | 393 |
1 files changed, 277 insertions, 116 deletions
diff --git a/src/ucl_util.c b/src/ucl_util.c index 41702e941f5b..41e012bf15bb 100644 --- a/src/ucl_util.c +++ b/src/ucl_util.c @@ -24,13 +24,21 @@ #include "ucl.h" #include "ucl_internal.h" #include "ucl_chartable.h" +#include "kvec.h" +#ifndef _WIN32 #include <glob.h> +#endif #ifdef HAVE_LIBGEN_H #include <libgen.h> /* For dirname */ #endif +typedef kvec_t(ucl_object_t *) ucl_array_t; + +#define UCL_ARRAY_GET(ar, obj) ucl_array_t *ar = \ + (ucl_array_t *)((obj) != NULL ? (obj)->value.av : NULL) + #ifdef HAVE_OPENSSL #include <openssl/err.h> #include <openssl/sha.h> @@ -68,6 +76,11 @@ #define MAP_FAILED ((void *) -1) #endif +#ifdef _WIN32 +#include <limits.h> +#define NBBY CHAR_BIT +#endif + static void *ucl_mmap(char *addr, size_t length, int prot, int access, int fd, off_t offset) { void *map = NULL; @@ -195,15 +208,27 @@ ucl_object_dtor_unref (ucl_object_t *obj) static void ucl_object_free_internal (ucl_object_t *obj, bool allow_rec, ucl_object_dtor dtor) { - ucl_object_t *sub, *tmp; + ucl_object_t *tmp, *sub; while (obj != NULL) { if (obj->type == UCL_ARRAY) { - sub = obj->value.av; - while (sub != NULL) { - tmp = sub->next; - dtor (sub); - sub = tmp; + UCL_ARRAY_GET (vec, obj); + unsigned int i; + + if (vec != NULL) { + for (i = 0; i < vec->n; i ++) { + sub = kv_A (*vec, i); + if (sub != NULL) { + tmp = sub; + while (sub) { + tmp = sub->next; + dtor (sub); + sub = tmp; + } + } + } + kv_destroy (*vec); + UCL_FREE (sizeof (*vec), vec); } } else if (obj->type == UCL_OBJECT) { @@ -455,6 +480,15 @@ ucl_parser_get_error(struct ucl_parser *parser) return utstring_body(parser->err); } +UCL_EXTERN void +ucl_parser_clear_error(struct ucl_parser *parser) +{ + if (parser != NULL && parser->err != NULL) { + utstring_free(parser->err); + parser->err = NULL; + } +} + UCL_EXTERN bool ucl_pubkey_add (struct ucl_parser *parser, const unsigned char *key, size_t len) { @@ -933,10 +967,10 @@ ucl_include_file (const unsigned char *data, size_t len, const unsigned char *p = data, *end = data + len; bool need_glob = false; int cnt = 0; - glob_t globbuf; char glob_pattern[PATH_MAX]; size_t i; +#ifndef _WIN32 if (!allow_glob) { return ucl_include_file_single (data, len, parser, check_signature, must_exist, priority); @@ -951,6 +985,7 @@ ucl_include_file (const unsigned char *data, size_t len, p ++; } if (need_glob) { + glob_t globbuf; memset (&globbuf, 0, sizeof (globbuf)); ucl_strlcpy (glob_pattern, (const char *)data, sizeof (glob_pattern)); if (glob (glob_pattern, 0, NULL, &globbuf) != 0) { @@ -978,7 +1013,13 @@ ucl_include_file (const unsigned char *data, size_t len, must_exist, priority); } } - +#else + /* Win32 compilers do not support globbing. Therefore, for Win32, + treat allow_glob/need_glob as a NOOP and just return */ + return ucl_include_file_single (data, len, parser, check_signature, + must_exist, priority); +#endif + return true; } @@ -1394,7 +1435,7 @@ ucl_object_insert_key_common (ucl_object_t *top, ucl_object_t *elt, } if (top->value.ov == NULL) { - top->value.ov = ucl_hash_create (); + top->value.ov = ucl_hash_create (false); } if (keylen == 0) { @@ -1427,7 +1468,7 @@ ucl_object_insert_key_common (ucl_object_t *top, ucl_object_t *elt, found = __DECONST (ucl_object_t *, ucl_hash_search_obj (top->value.ov, elt)); if (found == NULL) { - top->value.ov = ucl_hash_insert_object (top->value.ov, elt); + top->value.ov = ucl_hash_insert_object (top->value.ov, elt, false); top->len ++; if (replace) { ret = false; @@ -1444,7 +1485,7 @@ ucl_object_insert_key_common (ucl_object_t *top, ucl_object_t *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); + top->value.ov = ucl_hash_insert_object (top->value.ov, elt, false); } else if (found->type == UCL_OBJECT && elt->type != UCL_OBJECT) { /* Insert new to old */ @@ -1568,7 +1609,7 @@ ucl_object_merge (ucl_object_t *top, ucl_object_t *elt, bool copy) found = __DECONST(ucl_object_t *, ucl_hash_search (top->value.ov, cp->key, cp->keylen)); if (found == NULL) { /* The key does not exist */ - top->value.ov = ucl_hash_insert_object (top->value.ov, cp); + top->value.ov = ucl_hash_insert_object (top->value.ov, cp, false); top->len ++; } else { @@ -1610,7 +1651,7 @@ ucl_object_find_key (const ucl_object_t *obj, const char *key) const ucl_object_t* ucl_iterate_object (const ucl_object_t *obj, ucl_object_iter_t *iter, bool expand_values) { - const ucl_object_t *elt; + const ucl_object_t *elt = NULL; if (obj == NULL || iter == NULL) { return NULL; @@ -1621,19 +1662,25 @@ ucl_iterate_object (const ucl_object_t *obj, ucl_object_iter_t *iter, bool expan case UCL_OBJECT: return (const 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; + case UCL_ARRAY: { + unsigned int idx; + UCL_ARRAY_GET (vec, obj); + idx = (unsigned int)(uintptr_t)(*iter); + + if (vec != NULL) { + while (idx < kv_size (*vec)) { + if ((elt = kv_A (*vec, idx)) != NULL) { + idx ++; + break; + } + idx ++; } + *iter = (void *)(uintptr_t)idx; } - else if (elt == obj->value.av) { - return NULL; - } - *iter = elt->next ? elt->next : obj->value.av; + return elt; + break; + } default: /* Go to linear iteration */ break; @@ -1654,6 +1701,95 @@ ucl_iterate_object (const ucl_object_t *obj, ucl_object_iter_t *iter, bool expan return NULL; } +const char safe_iter_magic[4] = {'u', 'i', 't', 'e'}; +struct ucl_object_safe_iter { + char magic[4]; /* safety check */ + const ucl_object_t *impl_it; /* implicit object iteration */ + ucl_object_iter_t expl_it; /* explicit iteration */ +}; + +#define UCL_SAFE_ITER(ptr) (struct ucl_object_safe_iter *)(ptr) +#define UCL_SAFE_ITER_CHECK(it) do { \ + assert (it != NULL); \ + assert (memcmp (it->magic, safe_iter_magic, sizeof (it->magic)) == 0); \ + } while (0) + +ucl_object_iter_t +ucl_object_iterate_new (const ucl_object_t *obj) +{ + struct ucl_object_safe_iter *it; + + it = UCL_ALLOC (sizeof (*it)); + if (it != NULL) { + memcpy (it->magic, safe_iter_magic, sizeof (it->magic)); + it->expl_it = NULL; + it->impl_it = obj; + } + + return (ucl_object_iter_t)it; +} + + +ucl_object_iter_t +ucl_object_iterate_reset (ucl_object_iter_t it, const ucl_object_t *obj) +{ + struct ucl_object_safe_iter *rit = UCL_SAFE_ITER (it); + + UCL_SAFE_ITER_CHECK (rit); + + rit->impl_it = obj; + rit->expl_it = NULL; + + return it; +} + +const ucl_object_t* +ucl_object_iterate_safe (ucl_object_iter_t it, bool expand_values) +{ + struct ucl_object_safe_iter *rit = UCL_SAFE_ITER (it); + const ucl_object_t *ret = NULL; + + UCL_SAFE_ITER_CHECK (rit); + + if (rit->impl_it == NULL) { + return NULL; + } + + if (rit->impl_it->type == UCL_OBJECT || rit->impl_it->type == UCL_ARRAY) { + ret = ucl_iterate_object (rit->impl_it, &rit->expl_it, true); + + if (ret == NULL) { + /* Need to switch to another implicit object in chain */ + rit->impl_it = rit->impl_it->next; + rit->expl_it = NULL; + return ucl_object_iterate_safe (it, expand_values); + } + } + else { + /* Just iterate over the implicit array */ + ret = rit->impl_it; + rit->impl_it = rit->impl_it->next; + if (expand_values) { + /* We flatten objects if need to expand values */ + if (ret->type == UCL_OBJECT || ret->type == UCL_ARRAY) { + return ucl_object_iterate_safe (it, expand_values); + } + } + } + + return ret; +} + +void +ucl_object_iterate_free (ucl_object_iter_t it) +{ + struct ucl_object_safe_iter *rit = UCL_SAFE_ITER (it); + + UCL_SAFE_ITER_CHECK (rit); + + UCL_FREE (sizeof (*rit), it); +} + const ucl_object_t * ucl_lookup_path (const ucl_object_t *top, const char *path_in) { const ucl_object_t *o = NULL, *found; @@ -1733,6 +1869,17 @@ ucl_object_new_full (ucl_type_t type, unsigned priority) new->next = NULL; new->prev = new; ucl_object_set_priority (new, priority); + + if (type == UCL_ARRAY) { + new->value.av = UCL_ALLOC (sizeof (ucl_array_t)); + if (new->value.av) { + memset (new->value.av, 0, sizeof (ucl_array_t)); + UCL_ARRAY_GET (vec, new); + + /* Preallocate some space for arrays */ + kv_resize (ucl_object_t *, *vec, 8); + } + } } } else { @@ -1826,23 +1973,20 @@ ucl_object_frombool (bool bv) bool ucl_array_append (ucl_object_t *top, ucl_object_t *elt) { - ucl_object_t *head; + UCL_ARRAY_GET (vec, top); if (elt == NULL || top == NULL) { return false; } - head = top->value.av; - if (head == NULL) { - top->value.av = elt; - elt->prev = elt; + if (vec == NULL) { + vec = UCL_ALLOC (sizeof (*vec)); + kv_init (*vec); + top->value.av = (void *)vec; } - else { - elt->prev = head->prev; - head->prev->next = elt; - head->prev = elt; - } - elt->next = NULL; + + kv_push (ucl_object_t *, *vec, elt); + top->len ++; return true; @@ -1851,24 +1995,23 @@ ucl_array_append (ucl_object_t *top, ucl_object_t *elt) bool ucl_array_prepend (ucl_object_t *top, ucl_object_t *elt) { - ucl_object_t *head; + UCL_ARRAY_GET (vec, top); if (elt == NULL || top == NULL) { return false; } - - head = top->value.av; - if (head == NULL) { - top->value.av = elt; - elt->prev = elt; + if (vec == NULL) { + vec = UCL_ALLOC (sizeof (*vec)); + kv_init (*vec); + top->value.av = (void *)vec; + kv_push (ucl_object_t *, *vec, elt); } else { - elt->prev = head->prev; - head->prev = elt; + /* Slow O(n) algorithm */ + kv_prepend (ucl_object_t *, *vec, elt); } - elt->next = head; - top->value.av = elt; + top->len ++; return true; @@ -1877,21 +2020,29 @@ ucl_array_prepend (ucl_object_t *top, ucl_object_t *elt) bool ucl_array_merge (ucl_object_t *top, ucl_object_t *elt, bool copy) { - ucl_object_t *cur, *tmp, *cp; + unsigned i; + ucl_object_t **obj; + UCL_ARRAY_GET (v1, top); + UCL_ARRAY_GET (v2, elt); if (elt == NULL || top == NULL || top->type != UCL_ARRAY || elt->type != UCL_ARRAY) { return false; } - DL_FOREACH_SAFE (elt->value.av, cur, tmp) { + kv_concat (ucl_object_t *, *v1, *v2); + + for (i = v2->n; i < v1->n; i ++) { + obj = &kv_A (*v1, i); + if (*obj == NULL) { + continue; + } + + top->len ++; if (copy) { - cp = ucl_object_copy (cur); + *obj = ucl_object_copy (*obj); } else { - cp = ucl_object_ref (cur); - } - if (cp != NULL) { - ucl_array_append (top, cp); + ucl_object_ref (*obj); } } @@ -1901,82 +2052,85 @@ ucl_array_merge (ucl_object_t *top, ucl_object_t *elt, bool copy) ucl_object_t * ucl_array_delete (ucl_object_t *top, ucl_object_t *elt) { - ucl_object_t *head; - - if (top == NULL || top->type != UCL_ARRAY || top->value.av == NULL) { - return NULL; - } - head = top->value.av; + UCL_ARRAY_GET (vec, top); + ucl_object_t *ret = NULL; + unsigned i; - if (elt->prev == elt) { - top->value.av = NULL; - } - else if (elt == head) { - elt->next->prev = elt->prev; - top->value.av = elt->next; - } - else { - elt->prev->next = elt->next; - if (elt->next) { - elt->next->prev = elt->prev; - } - else { - head->prev = elt->prev; + for (i = 0; i < vec->n; i ++) { + if (kv_A (*vec, i) == elt) { + kv_del (ucl_object_t *, *vec, i); + ret = elt; + top->len --; + break; } } - elt->next = NULL; - elt->prev = elt; - top->len --; - return elt; + return ret; } const ucl_object_t * ucl_array_head (const ucl_object_t *top) { + UCL_ARRAY_GET (vec, top); + if (top == NULL || top->type != UCL_ARRAY || top->value.av == NULL) { return NULL; } - return top->value.av; + + return (vec->n > 0 ? vec->a[0] : NULL); } const ucl_object_t * ucl_array_tail (const ucl_object_t *top) { + UCL_ARRAY_GET (vec, top); + if (top == NULL || top->type != UCL_ARRAY || top->value.av == NULL) { return NULL; } - return top->value.av->prev; + + return (vec->n > 0 ? vec->a[vec->n - 1] : NULL); } ucl_object_t * ucl_array_pop_last (ucl_object_t *top) { - return ucl_array_delete (top, __DECONST(ucl_object_t *, ucl_array_tail (top))); + UCL_ARRAY_GET (vec, top); + ucl_object_t **obj, *ret = NULL; + + if (vec != NULL && vec->n > 0) { + obj = &kv_A (*vec, vec->n - 1); + ret = *obj; + kv_del (ucl_object_t *, *vec, vec->n - 1); + top->len --; + } + + return ret; } ucl_object_t * ucl_array_pop_first (ucl_object_t *top) { - return ucl_array_delete (top, __DECONST(ucl_object_t *, ucl_array_head (top))); + UCL_ARRAY_GET (vec, top); + ucl_object_t **obj, *ret = NULL; + + if (vec != NULL && vec->n > 0) { + obj = &kv_A (*vec, 0); + ret = *obj; + kv_del (ucl_object_t *, *vec, 0); + top->len --; + } + + return ret; } 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; - } + UCL_ARRAY_GET (vec, top); - while ((ret = ucl_iterate_object (top, &it, true)) != NULL) { - if (index == 0) { - return ret; - } - --index; + if (vec != NULL && vec->n > 0 && index < vec->n) { + return kv_A (*vec, index); } return NULL; @@ -1986,22 +2140,15 @@ ucl_object_t * ucl_array_replace_index (ucl_object_t *top, ucl_object_t *elt, unsigned int index) { - ucl_object_t *cur, *tmp; + UCL_ARRAY_GET (vec, top); + ucl_object_t *ret = NULL; - if (top == NULL || top->type != UCL_ARRAY || elt == NULL || - top->len == 0 || (index + 1) > top->len) { - return NULL; + if (vec != NULL && vec->n > 0 && index < vec->n) { + ret = kv_A (*vec, index); + kv_A (*vec, index) = elt; } - DL_FOREACH_SAFE (top->value.av, cur, tmp) { - if (index == 0) { - DL_REPLACE_ELEM (top->value.av, cur, elt); - return cur; - } - --index; - } - - return NULL; + return ret; } ucl_object_t * @@ -2314,7 +2461,7 @@ ucl_object_compare (const ucl_object_t *o1, const ucl_object_t *o2) switch (o1->type) { case UCL_STRING: - if (o1->len == o2->len) { + if (o1->len == o2->len && o1->len > 0) { ret = strcmp (ucl_object_tostring(o1), ucl_object_tostring(o2)); } else { @@ -2330,17 +2477,28 @@ ucl_object_compare (const ucl_object_t *o1, const ucl_object_t *o2) ret = ucl_object_toboolean (o1) - ucl_object_toboolean (o2); break; case UCL_ARRAY: - if (o1->len == o2->len) { - it1 = o1->value.av; - it2 = o2->value.av; + if (o1->len == o2->len && o1->len > 0) { + UCL_ARRAY_GET (vec1, o1); + UCL_ARRAY_GET (vec2, o2); + unsigned i; + /* Compare all elements in both arrays */ - while (it1 != NULL && it2 != NULL) { - ret = ucl_object_compare (it1, it2); - if (ret != 0) { - break; + for (i = 0; i < vec1->n; i ++) { + it1 = kv_A (*vec1, i); + it2 = kv_A (*vec2, i); + + if (it1 == NULL && it2 != NULL) { + return -1; + } + else if (it2 == NULL && it1 != NULL) { + return 1; + } + else if (it1 != NULL && it2 != NULL) { + ret = ucl_object_compare (it1, it2); + if (ret != 0) { + break; + } } - it1 = it1->next; - it2 = it2->next; } } else { @@ -2348,7 +2506,7 @@ ucl_object_compare (const ucl_object_t *o1, const ucl_object_t *o2) } break; case UCL_OBJECT: - if (o1->len == o2->len) { + if (o1->len == o2->len && o1->len > 0) { while ((it1 = ucl_iterate_object (o1, &iter, true)) != NULL) { it2 = ucl_object_find_key (o2, ucl_object_key (it1)); if (it2 == NULL) { @@ -2377,11 +2535,14 @@ void ucl_object_array_sort (ucl_object_t *ar, int (*cmp)(const ucl_object_t *o1, const ucl_object_t *o2)) { + UCL_ARRAY_GET (vec, ar); + if (cmp == NULL || ar == NULL || ar->type != UCL_ARRAY) { return; } - DL_SORT (ar->value.av, cmp); + qsort (vec->a, vec->n, sizeof (ucl_object_t *), + (int (*)(const void *, const void *))cmp); } #define PRIOBITS 4 |