getdns_dict_remove_name with json pointers

+ improved json pointers symantics
This commit is contained in:
Willem Toorop 2015-10-05 17:18:32 +02:00
parent f6619d28d8
commit e3947d7110
3 changed files with 149 additions and 49 deletions

View File

@ -50,40 +50,85 @@
#include "gldns/wire2str.h"
static struct getdns_dict_item *
_find_dict_item(const getdns_dict *dict, const char *key)
static char *_json_ptr_first(const struct mem_funcs *mf,
const char *jptr, char *first, size_t first_sz)
{
const char *next_ref, *k;
char json_key_spc[1024], *json_key, *j;
struct getdns_dict_item *d;
char *j;
if (*key != '/')
return (struct getdns_dict_item *) _getdns_rbtree_search(
(_getdns_rbtree_t *)&(dict->root), key);
key++;
if (!(next_ref = strchr(key, '/')))
next_ref = key + strlen(key);
if (next_ref - key > sizeof(json_key_spc))
json_key = GETDNS_XMALLOC(dict->mf, char, next_ref - key + 1);
else
json_key = json_key_spc;
if (*jptr != '/')
return (char *)jptr;
jptr++;
if (!(next_ref = strchr(jptr, '/')))
next_ref = strchr(jptr, '\0');
for (j = json_key, k = key; k < next_ref; j++, k++)
if (next_ref - jptr > first_sz)
first = GETDNS_XMALLOC(*mf, char, next_ref - jptr + 1);
for (j = first, k = jptr; k < next_ref; j++, k++)
*j = k[0] == '~' && k[1] == '1' ? (k++, '/') : *k;
*j = '\0';
for (j = json_key, k = json_key; *k; j++, k++)
for (j = first, k = first; *k; j++, k++)
*j = k[0] == '~' && k[1] == '0' ? (k++, '~') : *k;
*j = '\0';
d = (struct getdns_dict_item *) _getdns_rbtree_search(
(_getdns_rbtree_t *)&(dict->root), json_key);
return first;
}
if (json_key != json_key_spc)
GETDNS_FREE(dict->mf, json_key);
static struct getdns_dict_item *
_find_dict_item(const getdns_dict *dict, const char *jptr)
{
char first_spc[1024], *first;
struct getdns_dict_item *d;
first = _json_ptr_first(&dict->mf, jptr,
first_spc, sizeof(first_spc));
d = (struct getdns_dict_item *) _getdns_rbtree_search(
(_getdns_rbtree_t *)&(dict->root), first);
if (first && first != jptr && first != first_spc)
GETDNS_FREE(dict->mf, first);
return d;
}
static struct getdns_dict_item *
_delete_dict_item(const getdns_dict *dict, const char *jptr)
{
char first_spc[1024], *first;
struct getdns_dict_item *d;
first = _json_ptr_first(&dict->mf, jptr,
first_spc, sizeof(first_spc));
d = (struct getdns_dict_item *) _getdns_rbtree_delete(
(_getdns_rbtree_t *)&(dict->root), first);
if (first && first != jptr && first != first_spc)
GETDNS_FREE(dict->mf, first);
return d;
}
static char *
_json_ptr_keydup(const struct mem_funcs *mf, const char *jptr)
{
char *first = _json_ptr_first(mf, jptr, NULL, 0);
if (first == jptr || first == jptr + 1) {
size_t sz = strlen(jptr);
if ((first = GETDNS_XMALLOC(*mf, char, sz)))
memcpy(first, jptr, sz);
}
return first;
}
getdns_return_t
_getdns_dict_find(const getdns_dict *dict, const char *key, getdns_item **item)
{
@ -93,16 +138,16 @@ _getdns_dict_find(const getdns_dict *dict, const char *key, getdns_item **item)
if (!(d = _find_dict_item(dict, key)))
return GETDNS_RETURN_NO_SUCH_DICT_NAME;
if (*key != '/' || !(next = strchr(key + 1, '/')))
if (*key != '/' || !(next = strchr(key + 1, '/'))) {
*item = &d->i;
return GETDNS_RETURN_GOOD;
else switch (d->i.dtype) {
} else switch (d->i.dtype) { /* Key was nested reference */
case t_dict: return _getdns_dict_find(d->i.data.dict, next, item);
case t_list: return _getdns_list_find(d->i.data.list, next, item);
default : *item = &d->i;
break;
default : /* Trying to dereference a non list or dict */
return GETDNS_RETURN_WRONG_TYPE_REQUESTED;
}
return GETDNS_RETURN_GOOD;
}
getdns_return_t
@ -115,7 +160,7 @@ _getdns_dict_find_and_add(
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->node.key = _json_ptr_keydup(&dict->mf, key);
_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));
@ -137,12 +182,13 @@ _getdns_dict_find_and_add(
*item = &d->i;
return GETDNS_RETURN_GOOD;
} else switch (d->i.dtype) {
} else switch (d->i.dtype) { /* Key was nested reference */
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;
default : /* Trying to dereference a non list or dict */
return GETDNS_RETURN_WRONG_TYPE_REQUESTED;
}
} /* getdns_dict_find_and_add */
@ -1159,17 +1205,23 @@ getdns_snprint_json_list(
getdns_return_t
getdns_dict_remove_name(getdns_dict *dict, const char *name)
{
_getdns_rbnode_t *n;
const char *next;
struct getdns_dict_item *d;
if (!dict || !name)
return GETDNS_RETURN_INVALID_PARAMETER;
if ((n = _getdns_rbtree_delete(&dict->root, name)))
getdns_dict_item_free(n, dict);
else
if (!(d = _find_dict_item(dict, name)))
return GETDNS_RETURN_NO_SUCH_DICT_NAME;
if (*name != '/' || !(next = strchr(name + 1, '/'))) {
d = _delete_dict_item(dict, name);
getdns_dict_item_free(&d->node, dict);
return GETDNS_RETURN_GOOD;
} else switch (d->i.dtype) {
case t_dict: return getdns_dict_remove_name(d->i.data.dict, next);
case t_list: return _getdns_list_remove_name(d->i.data.list, next);
default : /* Trying to dereference a non list or dict */
return GETDNS_RETURN_WRONG_TYPE_REQUESTED;
}
}
/* dict.c */

View File

@ -48,11 +48,11 @@ _getdns_list_find(const getdns_list *list, const char *key, getdns_item **item)
char *endptr;
size_t index;
if (*key == '/')
key += 1;
if (!(next = strchr(key + 1, '/')))
next = key + strlen(key);
if (*key == '/') {
if (!(next = strchr(++key, '/')))
next = strchr(key, '\0');
} else
next = strchr(key, '\0');
if (key[0] == '-' && (key[1] == '/' || key[1] == '\0'))
return GETDNS_RETURN_NO_SUCH_LIST_ITEM;
@ -71,7 +71,8 @@ _getdns_list_find(const getdns_list *list, const char *key, getdns_item **item)
list->items[index].data.dict, next, item);
case t_list: return _getdns_list_find(
list->items[index].data.list, next, item);
default : break;
default : /* Trying to dereference a non list or dict */
return GETDNS_RETURN_NO_SUCH_LIST_ITEM;
}
*item = &list->items[index];
return GETDNS_RETURN_GOOD;
@ -86,11 +87,11 @@ _getdns_list_find_and_add(
size_t index;
getdns_item *newlist;
if (*key == '/')
key += 1;
if (!(next = strchr(key + 1, '/')))
next = key + strlen(key);
if (*key == '/') {
if (!(next = strchr(++key, '/')))
next = strchr(key, '\0');
} else
next = strchr(key, '\0');
if (key[0] == '-' && key[1] == '/')
index = list->numinuse;
@ -133,13 +134,57 @@ _getdns_list_find_and_add(
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;
default : /* Trying to dereference a non list or dict */
return GETDNS_RETURN_WRONG_TYPE_REQUESTED;
}
*item = &list->items[index];
return GETDNS_RETURN_GOOD;
}
getdns_return_t
_getdns_list_remove_name(getdns_list *list, const char *name)
{
const char *next, *key = name;
char *endptr;
size_t index;
if (*key == '/') {
if (!(next = strchr(++key, '/')))
next = strchr(key, '\0');
} else
next = strchr(key, '\0');
if (key[0] == '-' && (key[1] == '/' || key[1] == '\0'))
return GETDNS_RETURN_NO_SUCH_LIST_ITEM;
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 (index >= list->numinuse)
return GETDNS_RETURN_NO_SUCH_LIST_ITEM;
if (*next)
switch (list->items[index].dtype) {
case t_dict: return getdns_dict_remove_name(
list->items[index].data.dict, next);
case t_list: return _getdns_list_remove_name(
list->items[index].data.list, next);
default : /* Trying to dereference a non list or dict */
return GETDNS_RETURN_WRONG_TYPE_REQUESTED;
}
if (index < list->numinuse - 1)
(void) memmove( &list->items[index]
, &list->items[index + 1]
, list->numinuse - index);
list->numinuse -= 1;
return GETDNS_RETURN_GOOD;
}
/*---------------------------------------- getdns_list_get_length */
getdns_return_t
getdns_list_get_length(const struct getdns_list * list, size_t * answer)

View File

@ -69,6 +69,9 @@ getdns_return_t _getdns_list_find(
getdns_return_t _getdns_list_find_and_add(
getdns_list *list, const char *key, getdns_item **item);
getdns_return_t _getdns_list_remove_name(
getdns_list *list, const char *name);
#endif
/* list.h */