diff options
Diffstat (limited to 'src/ucl_util.c')
-rw-r--r-- | src/ucl_util.c | 320 |
1 files changed, 187 insertions, 133 deletions
diff --git a/src/ucl_util.c b/src/ucl_util.c index f96c23cd6129..9178795d9446 100644 --- a/src/ucl_util.c +++ b/src/ucl_util.c @@ -134,35 +134,76 @@ static char* ucl_realpath(const char *path, char *resolved_path) { * Utilities for rcl parsing */ +typedef void (*ucl_object_dtor) (ucl_object_t *obj); +static void ucl_object_free_internal (ucl_object_t *obj, bool allow_rec, + ucl_object_dtor dtor); +static void ucl_object_dtor_unref (ucl_object_t *obj); static void -ucl_object_free_internal (ucl_object_t *obj, bool allow_rec) +ucl_object_dtor_free (ucl_object_t *obj) { - ucl_object_t *sub, *tmp; + 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]); + } + UCL_FREE (sizeof (ucl_object_t), obj); +} - 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]); +/* + * This is a helper function that performs exactly the same as + * `ucl_object_unref` but it doesn't iterate over elements allowing + * to use it for individual elements of arrays and multiple values + */ +static void +ucl_object_dtor_unref_single (ucl_object_t *obj) +{ + if (obj != NULL) { +#ifdef HAVE_ATOMIC_BUILTINS + unsigned int rc = __sync_sub_and_fetch (&obj->ref, 1); + if (rc == 0) { +#else + if (--obj->ref == 0) { +#endif + ucl_object_free_internal (obj, false, ucl_object_dtor_unref); } + } +} + +static void +ucl_object_dtor_unref (ucl_object_t *obj) +{ + if (obj->ref == 0) { + ucl_object_dtor_free (obj); + } + else { + /* This may cause dtor unref being called one more time */ + ucl_object_dtor_unref_single (obj); + } +} + +static void +ucl_object_free_internal (ucl_object_t *obj, bool allow_rec, ucl_object_dtor dtor) +{ + ucl_object_t *sub, *tmp; + while (obj != NULL) { if (obj->type == UCL_ARRAY) { sub = obj->value.av; while (sub != NULL) { tmp = sub->next; - ucl_object_free_internal (sub, false); + dtor (sub); 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); + ucl_hash_destroy (obj->value.ov, (ucl_hash_free_func *)dtor); } } tmp = obj->next; - UCL_FREE (sizeof (ucl_object_t), obj); + dtor (obj); obj = tmp; if (!allow_rec) { @@ -174,7 +215,7 @@ ucl_object_free_internal (ucl_object_t *obj, bool allow_rec) void ucl_object_free (ucl_object_t *obj) { - ucl_object_free_internal (obj, true); + ucl_object_free_internal (obj, true, ucl_object_dtor_free); } size_t @@ -282,47 +323,54 @@ ucl_unescape_json_string (char *str, size_t len) return (t - str); } -UCL_EXTERN char * -ucl_copy_key_trash (ucl_object_t *obj) +char * +ucl_copy_key_trash (const ucl_object_t *obj) { + ucl_object_t *deconst; + if (obj == NULL) { return NULL; } 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'; + deconst = __DECONST (ucl_object_t *, obj); + deconst->trash_stack[UCL_TRASH_KEY] = malloc (obj->keylen + 1); + if (deconst->trash_stack[UCL_TRASH_KEY] != NULL) { + memcpy (deconst->trash_stack[UCL_TRASH_KEY], obj->key, obj->keylen); + deconst->trash_stack[UCL_TRASH_KEY][obj->keylen] = '\0'; } - obj->key = obj->trash_stack[UCL_TRASH_KEY]; - obj->flags |= UCL_OBJECT_ALLOCATED_KEY; + deconst->key = obj->trash_stack[UCL_TRASH_KEY]; + deconst->flags |= UCL_OBJECT_ALLOCATED_KEY; } return obj->trash_stack[UCL_TRASH_KEY]; } -UCL_EXTERN char * -ucl_copy_value_trash (ucl_object_t *obj) +char * +ucl_copy_value_trash (const ucl_object_t *obj) { + ucl_object_t *deconst; + if (obj == NULL) { return NULL; } if (obj->trash_stack[UCL_TRASH_VALUE] == NULL) { + deconst = __DECONST (ucl_object_t *, obj); 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]; + deconst->trash_stack[UCL_TRASH_VALUE] = malloc (obj->len + 1); + if (deconst->trash_stack[UCL_TRASH_VALUE] != NULL) { + memcpy (deconst->trash_stack[UCL_TRASH_VALUE], obj->value.sv, obj->len); + deconst->trash_stack[UCL_TRASH_VALUE][obj->len] = '\0'; + deconst->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]); + deconst->trash_stack[UCL_TRASH_VALUE] = ucl_object_emit_single_json (obj); + deconst->len = strlen (obj->trash_stack[UCL_TRASH_VALUE]); } - obj->flags |= UCL_OBJECT_ALLOCATED_VALUE; + deconst->flags |= UCL_OBJECT_ALLOCATED_VALUE; } return obj->trash_stack[UCL_TRASH_VALUE]; } @@ -1084,21 +1132,22 @@ ucl_object_fromstring_common (const char *str, size_t len, enum ucl_string_flags return obj; } -static ucl_object_t * +static bool 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_t *found, *tmp; + const ucl_object_t *cur; ucl_object_iter_t it = NULL; const char *p; + int ret = true; if (elt == NULL || key == NULL) { - return NULL; + return false; } if (top == NULL) { - top = ucl_object_new (); - top->type = UCL_OBJECT; + return false; } if (top->type != UCL_OBJECT) { @@ -1108,7 +1157,7 @@ ucl_object_insert_key_common (ucl_object_t *top, ucl_object_t *elt, } else { /* Refuse converting of other object types */ - return top; + return false; } } @@ -1134,12 +1183,15 @@ ucl_object_insert_key_common (ucl_object_t *top, ucl_object_t *elt, ucl_copy_key_trash (elt); } - found = ucl_hash_search_obj (top->value.ov, elt); + found = __DECONST (ucl_object_t *, 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); top->len ++; + if (replace) { + ret = false; + } } else { if (replace) { @@ -1152,19 +1204,22 @@ ucl_object_insert_key_common (ucl_object_t *top, ucl_object_t *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_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); + 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); + tmp = ucl_object_ref (cur); + ucl_object_insert_key_common (found, tmp, cur->key, + cur->keylen, copy_key, false, false); } ucl_object_unref (elt); } @@ -1178,11 +1233,11 @@ ucl_object_insert_key_common (ucl_object_t *top, ucl_object_t *elt, } } - return top; + return ret; } bool -ucl_object_delete_keyl(ucl_object_t *top, const char *key, size_t keylen) +ucl_object_delete_keyl (ucl_object_t *top, const char *key, size_t keylen) { ucl_object_t *found; @@ -1190,13 +1245,13 @@ ucl_object_delete_keyl(ucl_object_t *top, const char *key, size_t keylen) return false; } - found = ucl_object_find_keyl(top, key, keylen); + found = __DECONST (ucl_object_t *, ucl_object_find_keyl (top, key, keylen)); if (found == NULL) { return false; } - ucl_hash_delete(top->value.ov, found); + ucl_hash_delete (top->value.ov, found); ucl_object_unref (found); top->len --; @@ -1204,61 +1259,62 @@ ucl_object_delete_keyl(ucl_object_t *top, const char *key, size_t keylen) } bool -ucl_object_delete_key(ucl_object_t *top, const char *key) +ucl_object_delete_key (ucl_object_t *top, const char *key) { - return ucl_object_delete_keyl(top, key, 0); + return ucl_object_delete_keyl (top, key, strlen(key)); } ucl_object_t* ucl_object_pop_keyl (ucl_object_t *top, const char *key, size_t keylen) { - ucl_object_t *found; + const ucl_object_t *found; if (top == NULL || key == NULL) { return false; } - found = ucl_object_find_keyl(top, key, keylen); + found = ucl_object_find_keyl (top, key, keylen); if (found == NULL) { return NULL; } - ucl_hash_delete(top->value.ov, found); + ucl_hash_delete (top->value.ov, found); top->len --; - return found; + return __DECONST (ucl_object_t *, found); } ucl_object_t* ucl_object_pop_key (ucl_object_t *top, const char *key) { - return ucl_object_pop_keyl (top, key, 0); + return ucl_object_pop_keyl (top, key, strlen(key)); } -ucl_object_t * +bool 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 * +bool 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 * +bool 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) +const ucl_object_t * +ucl_object_find_keyl (const ucl_object_t *obj, const char *key, size_t klen) { - ucl_object_t *ret, srch; + const ucl_object_t *ret; + ucl_object_t srch; if (obj == NULL || obj->type != UCL_OBJECT || key == NULL) { return NULL; @@ -1271,11 +1327,12 @@ ucl_object_find_keyl (ucl_object_t *obj, const char *key, size_t klen) return ret; } -ucl_object_t * -ucl_object_find_key (ucl_object_t *obj, const char *key) +const ucl_object_t * +ucl_object_find_key (const ucl_object_t *obj, const char *key) { size_t klen; - ucl_object_t *ret, srch; + const ucl_object_t *ret; + ucl_object_t srch; if (obj == NULL || obj->type != UCL_OBJECT || key == NULL) { return NULL; @@ -1289,10 +1346,10 @@ ucl_object_find_key (ucl_object_t *obj, const char *key) return ret; } -ucl_object_t* -ucl_iterate_object (ucl_object_t *obj, ucl_object_iter_t *iter, bool expand_values) +const ucl_object_t* +ucl_iterate_object (const ucl_object_t *obj, ucl_object_iter_t *iter, bool expand_values) { - ucl_object_t *elt; + const ucl_object_t *elt; if (obj == NULL || iter == NULL) { return NULL; @@ -1301,7 +1358,7 @@ ucl_iterate_object (ucl_object_t *obj, ucl_object_iter_t *iter, bool expand_valu if (expand_values) { switch (obj->type) { case UCL_OBJECT: - return (ucl_object_t*)ucl_hash_iterate (obj->value.ov, iter); + return (const ucl_object_t*)ucl_hash_iterate (obj->value.ov, iter); break; case UCL_ARRAY: elt = *iter; @@ -1332,7 +1389,7 @@ ucl_iterate_object (ucl_object_t *obj, ucl_object_iter_t *iter, bool expand_valu else if (elt == obj) { return NULL; } - *iter = elt->next ? elt->next : obj; + *iter = __DECONST (void *, elt->next ? elt->next : obj); return elt; /* Not reached */ @@ -1420,72 +1477,55 @@ ucl_object_frombool (bool bv) return obj; } -ucl_object_t * +bool ucl_array_append (ucl_object_t *top, ucl_object_t *elt) { ucl_object_t *head; - if (elt == NULL) { - return NULL; + if (elt == NULL || top == NULL) { + return false; } - if (top == NULL) { - top = ucl_object_typed_new (UCL_ARRAY); + head = top->value.av; + if (head == NULL) { 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 ++; + elt->prev = head->prev; + head->prev->next = elt; + head->prev = elt; } + elt->next = NULL; + top->len ++; - return top; + return true; } -ucl_object_t * +bool ucl_array_prepend (ucl_object_t *top, ucl_object_t *elt) { ucl_object_t *head; - if (elt == NULL) { - return NULL; + if (elt == NULL || top == NULL) { + return false; } - if (top == NULL) { - top = ucl_object_typed_new (UCL_ARRAY); + + head = top->value.av; + if (head == NULL) { 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 = elt; - } - elt->next = head; - top->value.av = elt; - top->len ++; + elt->prev = head->prev; + head->prev = elt; } + elt->next = head; + top->value.av = elt; + top->len ++; - return top; + return true; } ucl_object_t * @@ -1521,8 +1561,8 @@ ucl_array_delete (ucl_object_t *top, ucl_object_t *elt) return elt; } -ucl_object_t * -ucl_array_head (ucl_object_t *top) +const ucl_object_t * +ucl_array_head (const ucl_object_t *top) { if (top == NULL || top->type != UCL_ARRAY || top->value.av == NULL) { return NULL; @@ -1530,8 +1570,8 @@ ucl_array_head (ucl_object_t *top) return top->value.av; } -ucl_object_t * -ucl_array_tail (ucl_object_t *top) +const ucl_object_t * +ucl_array_tail (const ucl_object_t *top) { if (top == NULL || top->type != UCL_ARRAY || top->value.av == NULL) { return NULL; @@ -1542,13 +1582,13 @@ ucl_array_tail (ucl_object_t *top) ucl_object_t * ucl_array_pop_last (ucl_object_t *top) { - return ucl_array_delete (top, ucl_array_tail (top)); + return ucl_array_delete (top, __DECONST(ucl_object_t *, ucl_array_tail (top))); } ucl_object_t * ucl_array_pop_first (ucl_object_t *top) { - return ucl_array_delete (top, ucl_array_head (top)); + return ucl_array_delete (top, __DECONST(ucl_object_t *, ucl_array_head (top))); } ucl_object_t * @@ -1571,7 +1611,7 @@ ucl_elt_append (ucl_object_t *head, ucl_object_t *elt) } bool -ucl_object_todouble_safe (ucl_object_t *obj, double *target) +ucl_object_todouble_safe (const ucl_object_t *obj, double *target) { if (obj == NULL || target == NULL) { return false; @@ -1592,7 +1632,7 @@ ucl_object_todouble_safe (ucl_object_t *obj, double *target) } double -ucl_object_todouble (ucl_object_t *obj) +ucl_object_todouble (const ucl_object_t *obj) { double result = 0.; @@ -1601,7 +1641,7 @@ ucl_object_todouble (ucl_object_t *obj) } bool -ucl_object_toint_safe (ucl_object_t *obj, int64_t *target) +ucl_object_toint_safe (const ucl_object_t *obj, int64_t *target) { if (obj == NULL || target == NULL) { return false; @@ -1622,7 +1662,7 @@ ucl_object_toint_safe (ucl_object_t *obj, int64_t *target) } int64_t -ucl_object_toint (ucl_object_t *obj) +ucl_object_toint (const ucl_object_t *obj) { int64_t result = 0; @@ -1631,7 +1671,7 @@ ucl_object_toint (ucl_object_t *obj) } bool -ucl_object_toboolean_safe (ucl_object_t *obj, bool *target) +ucl_object_toboolean_safe (const ucl_object_t *obj, bool *target) { if (obj == NULL || target == NULL) { return false; @@ -1648,7 +1688,7 @@ ucl_object_toboolean_safe (ucl_object_t *obj, bool *target) } bool -ucl_object_toboolean (ucl_object_t *obj) +ucl_object_toboolean (const ucl_object_t *obj) { bool result = false; @@ -1657,7 +1697,7 @@ ucl_object_toboolean (ucl_object_t *obj) } bool -ucl_object_tostring_safe (ucl_object_t *obj, const char **target) +ucl_object_tostring_safe (const ucl_object_t *obj, const char **target) { if (obj == NULL || target == NULL) { return false; @@ -1675,7 +1715,7 @@ ucl_object_tostring_safe (ucl_object_t *obj, const char **target) } const char * -ucl_object_tostring (ucl_object_t *obj) +ucl_object_tostring (const ucl_object_t *obj) { const char *result = NULL; @@ -1684,13 +1724,13 @@ ucl_object_tostring (ucl_object_t *obj) } const char * -ucl_object_tostring_forced (ucl_object_t *obj) +ucl_object_tostring_forced (const ucl_object_t *obj) { return ucl_copy_value_trash (obj); } bool -ucl_object_tolstring_safe (ucl_object_t *obj, const char **target, size_t *tlen) +ucl_object_tolstring_safe (const ucl_object_t *obj, const char **target, size_t *tlen) { if (obj == NULL || target == NULL) { return false; @@ -1710,7 +1750,7 @@ ucl_object_tolstring_safe (ucl_object_t *obj, const char **target, size_t *tlen) } const char * -ucl_object_tolstring (ucl_object_t *obj, size_t *tlen) +ucl_object_tolstring (const ucl_object_t *obj, size_t *tlen) { const char *result = NULL; @@ -1719,13 +1759,13 @@ ucl_object_tolstring (ucl_object_t *obj, size_t *tlen) } const char * -ucl_object_key (ucl_object_t *obj) +ucl_object_key (const ucl_object_t *obj) { return ucl_copy_key_trash (obj); } const char * -ucl_object_keyl (ucl_object_t *obj, size_t *len) +ucl_object_keyl (const ucl_object_t *obj, size_t *len) { if (len == NULL || obj == NULL) { return NULL; @@ -1735,26 +1775,40 @@ ucl_object_keyl (ucl_object_t *obj, size_t *len) } ucl_object_t * -ucl_object_ref (ucl_object_t *obj) +ucl_object_ref (const ucl_object_t *obj) { + ucl_object_t *res = NULL; + if (obj != NULL) { - obj->ref ++; + res = __DECONST (ucl_object_t *, obj); +#ifdef HAVE_ATOMIC_BUILTINS + (void)__sync_add_and_fetch (&res->ref, 1); +#else + res->ref ++; +#endif } - return obj; + return res; } void ucl_object_unref (ucl_object_t *obj) { - if (obj != NULL && --obj->ref <= 0) { - ucl_object_free (obj); + if (obj != NULL) { +#ifdef HAVE_ATOMIC_BUILTINS + unsigned int rc = __sync_sub_and_fetch (&obj->ref, 1); + if (rc == 0) { +#else + if (--obj->ref == 0) { +#endif + ucl_object_free_internal (obj, true, ucl_object_dtor_unref); + } } } int -ucl_object_compare (ucl_object_t *o1, ucl_object_t *o2) +ucl_object_compare (const ucl_object_t *o1, const ucl_object_t *o2) { - ucl_object_t *it1, *it2; + const ucl_object_t *it1, *it2; ucl_object_iter_t iter = NULL; int ret = 0; @@ -1825,7 +1879,7 @@ ucl_object_compare (ucl_object_t *o1, ucl_object_t *o2) void ucl_object_array_sort (ucl_object_t *ar, - int (*cmp)(ucl_object_t *o1, ucl_object_t *o2)) + int (*cmp)(const ucl_object_t *o1, const ucl_object_t *o2)) { if (cmp == NULL || ar == NULL || ar->type != UCL_ARRAY) { return; |