From f6619d28d8d822cb3ff0f8b46b070bba61ba7585 Mon Sep 17 00:00:00 2001 From: Willem Toorop Date: Fri, 2 Oct 2015 15:26:05 +0200 Subject: [PATCH] JSON pointer setters --- src/dict.c | 104 +++++++++++++++++++++++++++++++---------------------- src/dict.h | 3 ++ src/list.c | 65 ++++++++++++++++++++++++++++++++- src/list.h | 3 ++ 4 files changed, 131 insertions(+), 44 deletions(-) diff --git a/src/dict.c b/src/dict.c index a6339cd2..b4c24cab 100644 --- a/src/dict.c +++ b/src/dict.c @@ -105,21 +105,45 @@ _getdns_dict_find(const getdns_dict *dict, const char *key, getdns_item **item) return GETDNS_RETURN_GOOD; } -static getdns_item * -getdns_dict_find_and_add(struct getdns_dict *dict, const char *key) +getdns_return_t +_getdns_dict_find_and_add( + getdns_dict *dict, const char *key, getdns_item **item) { + const char *next; struct getdns_dict_item *d; - d = _find_dict_item(dict, key); - - if (!d) { + if (!(d = _find_dict_item(dict, key))) { /* add a node */ d = GETDNS_MALLOC(dict->mf, struct getdns_dict_item); d->node.key = _getdns_strdup(&dict->mf, key); - d->i.data.n = 0; _getdns_rbtree_insert(&(dict->root), (_getdns_rbnode_t *) d); + if (*key != '/' || !(next = strchr(key + 1, '/'))) { + (void) memset(&d->i.data, 0, sizeof(d->i.data)); + *item = &d->i; + return GETDNS_RETURN_GOOD; + } + if ((next[1] == '0' || next[1] == '-') && + (next[2] == '/' || next[2] == '\0')) { + + d->i.data.list =_getdns_list_create_with_mf(&dict->mf); + return _getdns_list_find_and_add( + d->i.data.list, next, item); + } + d->i.data.dict = _getdns_dict_create_with_mf(&dict->mf); + return _getdns_dict_find_and_add( + d->i.data.dict, next, item); + } + if (*key != '/' || !(next = strchr(key + 1, '/'))) { + *item = &d->i; + return GETDNS_RETURN_GOOD; + + } else switch (d->i.dtype) { + case t_dict: return _getdns_dict_find_and_add( + d->i.data.dict, next, item); + case t_list: return _getdns_list_find_and_add( + d->i.data.list, next, item); + default : return GETDNS_RETURN_WRONG_TYPE_REQUESTED; } - return &d->i; } /* getdns_dict_find_and_add */ @@ -429,19 +453,17 @@ getdns_dict_set_dict( { getdns_item *item; getdns_dict *newdict; - getdns_return_t retval; + getdns_return_t r; if (!dict || !name || !child_dict) return GETDNS_RETURN_INVALID_PARAMETER; - retval = _getdns_dict_copy(child_dict, &newdict); - if (retval != GETDNS_RETURN_GOOD) - return retval; + if ((r = _getdns_dict_copy(child_dict, &newdict))) + return r; - item = getdns_dict_find_and_add(dict, name); - if (!item) { + if ((r = _getdns_dict_find_and_add(dict, name, &item))) { getdns_dict_destroy(newdict); - return GETDNS_RETURN_NO_SUCH_DICT_NAME; + return r; } item->dtype = t_dict; item->data.dict = newdict; @@ -455,19 +477,17 @@ getdns_dict_set_list( { getdns_item *item; getdns_list *newlist; - getdns_return_t retval; + getdns_return_t r; if (!dict || !name || !child_list) return GETDNS_RETURN_INVALID_PARAMETER; - retval = _getdns_list_copy(child_list, &newlist); - if (retval != GETDNS_RETURN_GOOD) - return retval; + if ((r = _getdns_list_copy(child_list, &newlist))) + return r; - item = getdns_dict_find_and_add(dict, name); - if (!item) { + if ((r = _getdns_dict_find_and_add(dict, name, &item))) { getdns_list_destroy(newlist); - return GETDNS_RETURN_NO_SUCH_DICT_NAME; + return r; } item->dtype = t_list; item->data.list = newlist; @@ -481,18 +501,17 @@ getdns_dict_set_bindata( { getdns_item *item; getdns_bindata *newbindata; + getdns_return_t r; if (!dict || !name || !child_bindata) return GETDNS_RETURN_INVALID_PARAMETER; - newbindata = _getdns_bindata_copy(&dict->mf, child_bindata); - if (!newbindata) - return GETDNS_RETURN_NO_SUCH_DICT_NAME; + if (!(newbindata = _getdns_bindata_copy(&dict->mf, child_bindata))) + return GETDNS_RETURN_MEMORY_ERROR; - item = getdns_dict_find_and_add(dict, name); - if (!item) { + if ((r = _getdns_dict_find_and_add(dict, name, &item))) { _getdns_bindata_destroy(&dict->mf, newbindata); - return GETDNS_RETURN_NO_SUCH_DICT_NAME; + return r; } item->dtype = t_bindata; item->data.bindata = newbindata; @@ -505,6 +524,7 @@ getdns_dict_util_set_string(getdns_dict *dict, char *name, const char *value) { getdns_item *item; getdns_bindata *newbindata; + getdns_return_t r; if (!dict || !name || !value) return GETDNS_RETURN_INVALID_PARAMETER; @@ -513,33 +533,31 @@ getdns_dict_util_set_string(getdns_dict *dict, char *name, const char *value) return GETDNS_RETURN_MEMORY_ERROR; newbindata->size = strlen(value); - if (!(newbindata->data = (void *)_getdns_strdup(&dict->mf, value))) - goto error_free_bindata; - - if ((item = getdns_dict_find_and_add(dict, name))) { - - item->dtype = t_bindata; - item->data.bindata = newbindata; - return GETDNS_RETURN_GOOD; + if (!(newbindata->data = (void *)_getdns_strdup(&dict->mf, value))) { + GETDNS_FREE(dict->mf, newbindata); + return GETDNS_RETURN_MEMORY_ERROR; } - GETDNS_FREE(dict->mf, newbindata->data); -error_free_bindata: - GETDNS_FREE(dict->mf, newbindata); - return GETDNS_RETURN_MEMORY_ERROR; + if ((r = _getdns_dict_find_and_add(dict, name, &item))) { + _getdns_bindata_destroy(&dict->mf, newbindata); + return r; + } + item->dtype = t_bindata; + item->data.bindata = newbindata; + return GETDNS_RETURN_GOOD; } /* getdns_dict_util_set_dict */ /*---------------------------------------- getdns_dict_set_int */ getdns_return_t getdns_dict_set_int(getdns_dict *dict, const char *name, uint32_t child_uint32) { - getdns_item *item; + getdns_item *item; + getdns_return_t r; if (!dict || !name) return GETDNS_RETURN_INVALID_PARAMETER; - item = getdns_dict_find_and_add(dict, name); - if (!item) - return GETDNS_RETURN_NO_SUCH_DICT_NAME; + if ((r = _getdns_dict_find_and_add(dict, name, &item))) + return r; item->dtype = t_int; item->data.n = child_uint32; diff --git a/src/dict.h b/src/dict.h index 8c8ebf9c..c10a2bd8 100644 --- a/src/dict.h +++ b/src/dict.h @@ -68,6 +68,9 @@ inline static getdns_dict *_getdns_dict_create_with_mf(struct mem_funcs *mf) getdns_return_t _getdns_dict_find( const getdns_dict *dict, const char *key, getdns_item **item); +getdns_return_t _getdns_dict_find_and_add( + getdns_dict *dict, const char *key, getdns_item **item); + #endif /* dict.h */ diff --git a/src/list.c b/src/list.c index 0d6dea7e..f81b9f19 100644 --- a/src/list.c +++ b/src/list.c @@ -54,7 +54,7 @@ _getdns_list_find(const getdns_list *list, const char *key, getdns_item **item) if (!(next = strchr(key + 1, '/'))) next = key + strlen(key); - if (*key == '-') + if (key[0] == '-' && (key[1] == '/' || key[1] == '\0')) return GETDNS_RETURN_NO_SUCH_LIST_ITEM; index = strtoul(key, &endptr, 10); @@ -77,6 +77,69 @@ _getdns_list_find(const getdns_list *list, const char *key, getdns_item **item) return GETDNS_RETURN_GOOD; } +getdns_return_t +_getdns_list_find_and_add( + getdns_list *list, const char *key, getdns_item **item) +{ + const char *next; + char *endptr; + size_t index; + getdns_item *newlist; + + if (*key == '/') + key += 1; + + if (!(next = strchr(key + 1, '/'))) + next = key + strlen(key); + + if (key[0] == '-' && key[1] == '/') + index = list->numinuse; + else { + index = strtoul(key, &endptr, 10); + if (!isdigit((int)*key) || endptr != next) + /* Not a list index, so it was assumed */ + return GETDNS_RETURN_WRONG_TYPE_REQUESTED; + } + if (*next && index == list->numinuse) { + + if (list->numalloc < list->numinuse) { + if (!(newlist = GETDNS_XREALLOC(list->mf, list->items, + getdns_item, list->numalloc+GETDNS_LIST_BLOCKSZ))) + return GETDNS_RETURN_MEMORY_ERROR; + list->items = newlist; + list->numalloc += GETDNS_LIST_BLOCKSZ; + } + list->numinuse++; + + if ((next[1] == '0' || next[1] == '-') && + (next[2] == '/' || next[2] == '\0')) { + + list->items[index].data.list = + _getdns_list_create_with_mf(&list->mf); + return _getdns_list_find_and_add( + list->items[index].data.list, next, item); + } + list->items[index].data.dict = + _getdns_dict_create_with_mf(&list->mf); + return _getdns_dict_find_and_add( + list->items[index].data.dict, next, item); + } + if (index >= list->numinuse) + return GETDNS_RETURN_NO_SUCH_LIST_ITEM; + + if (*next) + switch (list->items[index].dtype) { + case t_dict: return _getdns_dict_find( + list->items[index].data.dict, next, item); + case t_list: return _getdns_list_find( + list->items[index].data.list, next, item); + default : return GETDNS_RETURN_WRONG_TYPE_REQUESTED; + } + *item = &list->items[index]; + return GETDNS_RETURN_GOOD; +} + + /*---------------------------------------- getdns_list_get_length */ getdns_return_t getdns_list_get_length(const struct getdns_list * list, size_t * answer) diff --git a/src/list.h b/src/list.h index 45a57667..79e4ee7b 100644 --- a/src/list.h +++ b/src/list.h @@ -66,6 +66,9 @@ inline static getdns_list *_getdns_list_create_with_mf(struct mem_funcs *mf) getdns_return_t _getdns_list_find( const getdns_list *dict, const char *key, getdns_item **item); +getdns_return_t _getdns_list_find_and_add( + getdns_list *list, const char *key, getdns_item **item); + #endif /* list.h */