2013-07-15 17:43:30 -05:00
|
|
|
/**
|
|
|
|
*
|
2013-07-30 16:36:14 -05:00
|
|
|
* getdns list management functions, note that the internal storage is
|
|
|
|
* accomplished via the libc binary search tree implementation so your
|
|
|
|
* pointer foo needs to be keen to digest some of the internal semantics
|
2013-07-15 17:43:30 -05:00
|
|
|
*
|
2013-07-30 16:36:14 -05:00
|
|
|
* Interfaces originally taken from the getdns API description pseudo implementation.
|
2013-07-15 17:43:30 -05:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
/* The MIT License (MIT)
|
|
|
|
* Copyright (c) 2013 Verisign, Inc.
|
|
|
|
*
|
|
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
|
|
* in the Software without restriction, including without limitation the rights
|
|
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
|
|
* furnished to do so, subject to the following conditions:
|
|
|
|
*
|
|
|
|
* The above copyright notice and this permission notice shall be included in
|
|
|
|
* all copies or substantial portions of the Software.
|
|
|
|
*
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
|
|
* THE SOFTWARE.
|
|
|
|
*/
|
|
|
|
|
2013-08-09 16:04:25 -05:00
|
|
|
#include <stdio.h>
|
2013-07-30 16:36:14 -05:00
|
|
|
#include <search.h>
|
|
|
|
#include <string.h>
|
2013-10-29 15:02:21 -05:00
|
|
|
#include "dict.h"
|
2013-07-15 17:43:30 -05:00
|
|
|
|
2013-07-31 15:21:42 -05:00
|
|
|
/* TODO: change this to make the walk safe for reentrant/multi-thread calls */
|
|
|
|
struct getdns_list *walkresultlist;
|
|
|
|
struct getdns_dict *walkresultdict;
|
|
|
|
char *walkresultchar;
|
|
|
|
int walkresultcharlen;
|
2013-07-15 17:43:30 -05:00
|
|
|
|
2013-07-30 16:36:14 -05:00
|
|
|
/*---------------------------------------- getdns_dict_cmp */
|
|
|
|
/**
|
|
|
|
* private function used by the t*() functions for managing binary trees
|
|
|
|
* behaves similar to strcmp()
|
2013-10-10 15:35:29 -05:00
|
|
|
* @param item1 pointer to pointer to getdns_dict_item to compare
|
|
|
|
* @param item2 pointer to pointer to getdns_dict_item to compare
|
2013-07-30 16:36:14 -05:00
|
|
|
* @return results of lexicographic comparison between item1->key and item2->key
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
getdns_dict_cmp(const void *item1, const void *item2)
|
|
|
|
{
|
|
|
|
int retval = 0;
|
|
|
|
|
|
|
|
if(item1 == NULL)
|
|
|
|
{
|
|
|
|
if(item2 == NULL)
|
|
|
|
retval = 0;
|
|
|
|
else
|
|
|
|
retval = -1;
|
|
|
|
}
|
|
|
|
else if(item2 == NULL)
|
|
|
|
retval = 1;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
retval = strcmp(((struct getdns_dict_item *) item1)->key
|
|
|
|
, ((struct getdns_dict_item *) item2)->key);
|
|
|
|
}
|
|
|
|
|
|
|
|
return retval;
|
|
|
|
} /* getdns_dict_comp */
|
|
|
|
|
|
|
|
/*---------------------------------------- getdns_dict_find */
|
|
|
|
/**
|
|
|
|
* private function used to locate a key in a dictionary
|
|
|
|
* @param dict dicitonary to search
|
|
|
|
* @param key key to search for
|
|
|
|
* @param addifnotfnd if TRUE then an item will be added if the key is not found
|
|
|
|
* @return pointer to dictionary item, caller must not free storage associated with item
|
|
|
|
* @return NULL if additnotfnd == FALSE and key is not in dictionary
|
|
|
|
*/
|
|
|
|
struct getdns_dict_item *
|
|
|
|
getdns_dict_find(struct getdns_dict *dict, char *key, bool addifnotfnd)
|
|
|
|
{
|
|
|
|
struct getdns_dict_item keyitem;
|
|
|
|
struct getdns_dict_item **item;
|
|
|
|
struct getdns_dict_item *newitem;
|
|
|
|
struct getdns_dict_item *ret = NULL;
|
|
|
|
|
|
|
|
if(dict != NULL && key != NULL)
|
|
|
|
{
|
|
|
|
/* we try to find it first, if we do then clear the existing data */
|
|
|
|
keyitem.key = key;
|
|
|
|
keyitem.dtype = t_invalid;
|
|
|
|
keyitem.data.n = 0;
|
|
|
|
item = tfind(&keyitem, &(dict->rootp), getdns_dict_cmp);
|
|
|
|
if(addifnotfnd == true && (item == NULL || *item == NULL))
|
|
|
|
{
|
|
|
|
/* tsearch will add a node automatically for us */
|
|
|
|
newitem = (struct getdns_dict_item *) malloc(sizeof(struct getdns_dict_item));
|
|
|
|
newitem->key = strdup(key);
|
|
|
|
newitem->dtype = t_invalid;
|
|
|
|
newitem->data.n = 0;
|
|
|
|
item = tsearch(newitem, &(dict->rootp), getdns_dict_cmp);
|
|
|
|
}
|
|
|
|
if(item != NULL)
|
|
|
|
ret = *item;
|
|
|
|
}
|
|
|
|
|
2013-07-31 15:21:42 -05:00
|
|
|
return ret;
|
|
|
|
} /* getdns_dict_find */
|
|
|
|
|
|
|
|
/*---------------------------------------- getdns_dict_visit */
|
|
|
|
/**
|
|
|
|
* private function called by the tree walk function invoked by getdns_dict_get_names
|
|
|
|
* it is called as each node is visited. twalk() calls 3x for each node and passes order
|
|
|
|
* to tell us whether it is a pre/in/post order
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
getdns_dict_visit(const void *node, VISIT order, int level)
|
|
|
|
{
|
|
|
|
struct getdns_dict_item *item;
|
|
|
|
size_t index;
|
2013-07-30 16:36:14 -05:00
|
|
|
|
2013-07-31 15:21:42 -05:00
|
|
|
item = *(struct getdns_dict_item **) node;
|
|
|
|
/* postorder is mis-named - it results in in-order traversal */
|
|
|
|
if(order == postorder || order == leaf)
|
|
|
|
{
|
|
|
|
if(getdns_list_add_item(walkresultlist, &index) == GETDNS_RETURN_GOOD)
|
|
|
|
{
|
|
|
|
switch(item->dtype)
|
|
|
|
{
|
|
|
|
case t_bindata:
|
|
|
|
getdns_list_set_bindata(walkresultlist, index, item->data.bindata);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case t_dict:
|
|
|
|
getdns_list_set_dict(walkresultlist, index, item->data.dict);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case t_int:
|
|
|
|
getdns_list_set_int(walkresultlist, index, item->data.n);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case t_list:
|
|
|
|
getdns_list_set_list(walkresultlist, index, item->data.list);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case t_invalid:
|
|
|
|
default:
|
|
|
|
// TODO: this is a fault of some kind, for now ignore it
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
} /* getdns_dict_visit */
|
|
|
|
|
|
|
|
/*---------------------------------------- getdns_dict_get_names
|
|
|
|
TODO: this needs to be made thread safe by creating a thread specific list
|
|
|
|
the binary search tree implementation in the
|
|
|
|
*/
|
|
|
|
getdns_return_t
|
|
|
|
getdns_dict_get_names(struct getdns_dict *dict, struct getdns_list **answer)
|
|
|
|
{
|
|
|
|
getdns_return_t retval = GETDNS_RETURN_NO_SUCH_DICT_NAME;
|
|
|
|
|
|
|
|
if(dict != NULL && answer != NULL)
|
|
|
|
{
|
|
|
|
*answer = getdns_list_create();
|
|
|
|
walkresultlist = *answer;
|
|
|
|
|
|
|
|
twalk(dict->rootp, getdns_dict_visit);
|
|
|
|
|
|
|
|
retval = GETDNS_RETURN_GOOD;
|
|
|
|
}
|
|
|
|
|
|
|
|
return retval;
|
|
|
|
} /* getdns_dict_get_names */
|
2013-07-15 17:43:30 -05:00
|
|
|
|
2013-07-30 16:36:14 -05:00
|
|
|
/*---------------------------------------- getdns_dict_get_data_type */
|
|
|
|
getdns_return_t
|
|
|
|
getdns_dict_get_data_type(struct getdns_dict *dict, char *name, getdns_data_type *answer)
|
|
|
|
{
|
2013-07-31 15:21:42 -05:00
|
|
|
struct getdns_dict_item *item;
|
2013-07-30 16:36:14 -05:00
|
|
|
getdns_return_t retval = GETDNS_RETURN_NO_SUCH_DICT_NAME;
|
|
|
|
|
|
|
|
if(dict != NULL && name != NULL && answer != NULL)
|
|
|
|
{
|
2013-07-31 15:21:42 -05:00
|
|
|
item = getdns_dict_find(dict, name, false);
|
|
|
|
if(item != NULL)
|
2013-07-30 16:36:14 -05:00
|
|
|
{
|
2013-07-31 15:21:42 -05:00
|
|
|
*answer = item->dtype;
|
2013-07-30 16:36:14 -05:00
|
|
|
retval = GETDNS_RETURN_GOOD;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return retval;
|
|
|
|
} /* getdns_dict_get_data_type */
|
|
|
|
|
|
|
|
/*---------------------------------------- getdns_dict_get_dict */
|
|
|
|
getdns_return_t
|
|
|
|
getdns_dict_get_dict(struct getdns_dict *dict, char *name, struct getdns_dict **answer)
|
|
|
|
{
|
2013-07-31 15:21:42 -05:00
|
|
|
struct getdns_dict_item *item;
|
2013-07-30 16:36:14 -05:00
|
|
|
getdns_return_t retval = GETDNS_RETURN_NO_SUCH_DICT_NAME;
|
|
|
|
|
|
|
|
if(dict != NULL && name != NULL && answer != NULL)
|
|
|
|
{
|
2013-07-31 15:21:42 -05:00
|
|
|
item = getdns_dict_find(dict, name, false);
|
|
|
|
if(item != NULL)
|
2013-07-30 16:36:14 -05:00
|
|
|
{
|
2013-07-31 15:21:42 -05:00
|
|
|
if(item->dtype != t_dict)
|
2013-07-30 16:36:14 -05:00
|
|
|
retval = GETDNS_RETURN_WRONG_TYPE_REQUESTED;
|
|
|
|
else
|
|
|
|
{
|
2013-07-31 15:21:42 -05:00
|
|
|
*answer = item->data.dict;
|
2013-07-30 16:36:14 -05:00
|
|
|
retval = GETDNS_RETURN_GOOD;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return retval;
|
|
|
|
} /* getdns_dict_get_dict */
|
|
|
|
|
|
|
|
/*---------------------------------------- getdns_dict_get_list */
|
|
|
|
getdns_return_t
|
|
|
|
getdns_dict_get_list(struct getdns_dict *dict, char *name, struct getdns_list **answer)
|
|
|
|
{
|
2013-07-31 15:21:42 -05:00
|
|
|
struct getdns_dict_item *item;
|
2013-07-30 16:36:14 -05:00
|
|
|
getdns_return_t retval = GETDNS_RETURN_NO_SUCH_DICT_NAME;
|
|
|
|
|
|
|
|
if(dict != NULL && name != NULL && answer != NULL)
|
|
|
|
{
|
2013-07-31 15:21:42 -05:00
|
|
|
item = getdns_dict_find(dict, name, false);
|
|
|
|
if(item != NULL)
|
2013-07-30 16:36:14 -05:00
|
|
|
{
|
2013-07-31 15:21:42 -05:00
|
|
|
if(item->dtype != t_list)
|
2013-07-30 16:36:14 -05:00
|
|
|
retval = GETDNS_RETURN_WRONG_TYPE_REQUESTED;
|
|
|
|
else
|
|
|
|
{
|
2013-07-31 15:21:42 -05:00
|
|
|
*answer = item->data.list;
|
2013-07-30 16:36:14 -05:00
|
|
|
retval = GETDNS_RETURN_GOOD;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return retval;
|
|
|
|
} /* getdns_dict_get_list */
|
|
|
|
|
|
|
|
/*---------------------------------------- getdns_dict_get_bindata */
|
|
|
|
getdns_return_t
|
|
|
|
getdns_dict_get_bindata(struct getdns_dict *dict, char *name, struct getdns_bindata **answer)
|
|
|
|
{
|
2013-07-31 15:21:42 -05:00
|
|
|
struct getdns_dict_item *item;
|
2013-07-30 16:36:14 -05:00
|
|
|
getdns_return_t retval = GETDNS_RETURN_NO_SUCH_DICT_NAME;
|
2013-07-15 17:43:30 -05:00
|
|
|
|
2013-07-30 16:36:14 -05:00
|
|
|
if(dict != NULL && name != NULL && answer != NULL)
|
|
|
|
{
|
2013-07-31 15:21:42 -05:00
|
|
|
item = getdns_dict_find(dict, name, false);
|
|
|
|
if(item != NULL)
|
2013-07-30 16:36:14 -05:00
|
|
|
{
|
2013-07-31 15:21:42 -05:00
|
|
|
if(item->dtype != t_bindata)
|
2013-07-30 16:36:14 -05:00
|
|
|
retval = GETDNS_RETURN_WRONG_TYPE_REQUESTED;
|
|
|
|
else
|
|
|
|
{
|
2013-07-31 15:21:42 -05:00
|
|
|
*answer = item->data.bindata;
|
2013-07-30 16:36:14 -05:00
|
|
|
retval = GETDNS_RETURN_GOOD;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-07-15 17:43:30 -05:00
|
|
|
|
2013-07-30 16:36:14 -05:00
|
|
|
return retval;
|
|
|
|
} /* getdns_dict_get_bindata */
|
2013-07-15 17:43:30 -05:00
|
|
|
|
2013-07-30 16:36:14 -05:00
|
|
|
/*---------------------------------------- getdns_dict_get_int */
|
|
|
|
getdns_return_t
|
|
|
|
getdns_dict_get_int(struct getdns_dict *dict, char *name, uint32_t *answer)
|
|
|
|
{
|
2013-07-31 15:21:42 -05:00
|
|
|
struct getdns_dict_item *item;
|
2013-07-30 16:36:14 -05:00
|
|
|
getdns_return_t retval = GETDNS_RETURN_NO_SUCH_DICT_NAME;
|
2013-07-15 17:43:30 -05:00
|
|
|
|
2013-07-30 16:36:14 -05:00
|
|
|
if(dict != NULL && name != NULL && answer != NULL)
|
|
|
|
{
|
2013-07-31 15:21:42 -05:00
|
|
|
item = getdns_dict_find(dict, name, false);
|
|
|
|
if(item != NULL)
|
2013-07-30 16:36:14 -05:00
|
|
|
{
|
2013-07-31 15:21:42 -05:00
|
|
|
if(item->dtype != t_int)
|
2013-07-30 16:36:14 -05:00
|
|
|
retval = GETDNS_RETURN_WRONG_TYPE_REQUESTED;
|
|
|
|
else
|
|
|
|
{
|
2013-07-31 15:21:42 -05:00
|
|
|
*answer = item->data.n;
|
2013-07-30 16:36:14 -05:00
|
|
|
retval = GETDNS_RETURN_GOOD;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-07-15 17:43:30 -05:00
|
|
|
|
2013-07-30 16:36:14 -05:00
|
|
|
return retval;
|
|
|
|
} /* getdns_dict_get_int */
|
2013-07-15 17:43:30 -05:00
|
|
|
|
2013-07-30 16:36:14 -05:00
|
|
|
/*---------------------------------------- getdns_dict_create */
|
|
|
|
struct getdns_dict *
|
|
|
|
getdns_dict_create()
|
|
|
|
{
|
|
|
|
struct getdns_dict *dict;
|
2013-07-15 17:43:30 -05:00
|
|
|
|
2013-07-30 16:36:14 -05:00
|
|
|
dict = (struct getdns_dict *) malloc(sizeof(struct getdns_dict));
|
|
|
|
dict->rootp = NULL;
|
|
|
|
|
|
|
|
return dict;
|
|
|
|
} /* getdns_dict_create */
|
|
|
|
|
2013-07-31 15:21:42 -05:00
|
|
|
/*---------------------------------------- getdns_dict_visit_copyitem */
|
|
|
|
/**
|
|
|
|
* private function called by getdns_dict_copy() through the tree walk function
|
|
|
|
* is called as each node is visited. twalk() calls 3x for each node and passes order
|
|
|
|
* to tell us whether it is a pre/in/post order. We use this to copy the dictionary one item at
|
|
|
|
* a time - this could be sped up
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
getdns_dict_visit_copyitem(const void *node, VISIT order, int level)
|
|
|
|
{
|
|
|
|
struct getdns_dict_item *item;
|
|
|
|
|
|
|
|
item = *(struct getdns_dict_item **) node;
|
|
|
|
/* postorder is mis-named - it results in in-order traversal */
|
|
|
|
if(order == postorder || order == leaf)
|
|
|
|
{
|
|
|
|
switch(item->dtype)
|
|
|
|
{
|
|
|
|
case t_bindata:
|
|
|
|
getdns_dict_set_bindata(walkresultdict, item->key, item->data.bindata);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case t_dict:
|
|
|
|
getdns_dict_set_dict(walkresultdict, item->key, item->data.dict);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case t_int:
|
|
|
|
getdns_dict_set_int(walkresultdict, item->key, item->data.n);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case t_list:
|
|
|
|
getdns_dict_set_list(walkresultdict, item->key, item->data.list);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case t_invalid:
|
|
|
|
default:
|
|
|
|
// TODO: this is a fault of some kind, for now ignore it
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
} /* getdns_dict_visit_copyitem */
|
|
|
|
|
2013-07-30 16:36:14 -05:00
|
|
|
/*---------------------------------------- getdns_dict_copy */
|
|
|
|
/**
|
2013-07-31 15:21:42 -05:00
|
|
|
* private function used to make a copy of a dict structure, the caller is responsible
|
|
|
|
* for freeing storage allocated to returned value
|
|
|
|
* NOTE: not thread safe - this needs to be fixed to be thread safe
|
2013-07-30 16:36:14 -05:00
|
|
|
* @param srcdict the dictionary structure to copy
|
2013-10-10 15:35:29 -05:00
|
|
|
* @param dstdict the copy destination
|
2013-07-30 16:36:14 -05:00
|
|
|
* @return the address of the copy of the dictionary structure on success
|
|
|
|
* @return NULL on error (out of memory, invalid srcdict)
|
|
|
|
*/
|
2013-07-31 15:21:42 -05:00
|
|
|
getdns_return_t
|
|
|
|
getdns_dict_copy(struct getdns_dict *srcdict, struct getdns_dict **dstdict)
|
2013-07-30 16:36:14 -05:00
|
|
|
{
|
2013-07-31 15:21:42 -05:00
|
|
|
getdns_return_t retval = GETDNS_RETURN_NO_SUCH_DICT_NAME;
|
2013-07-30 16:36:14 -05:00
|
|
|
|
2013-07-31 15:21:42 -05:00
|
|
|
if(srcdict != NULL && dstdict != NULL)
|
2013-07-30 16:36:14 -05:00
|
|
|
{
|
2013-07-31 15:21:42 -05:00
|
|
|
*dstdict = getdns_dict_create();
|
|
|
|
walkresultdict = *dstdict;
|
|
|
|
|
|
|
|
twalk(srcdict->rootp, getdns_dict_visit_copyitem);
|
|
|
|
|
|
|
|
retval = GETDNS_RETURN_GOOD;
|
2013-07-30 16:36:14 -05:00
|
|
|
}
|
|
|
|
|
2013-07-31 15:21:42 -05:00
|
|
|
return retval;
|
2013-07-30 16:36:14 -05:00
|
|
|
} /* getdns_dict_copy */
|
|
|
|
|
|
|
|
/*---------------------------------------- getdns_dict_item_free */
|
|
|
|
/**
|
|
|
|
* private function used to release storage associated with a dictionary item
|
2013-10-10 15:35:29 -05:00
|
|
|
* @param item all memory in this structure and its children will be freed
|
2013-07-30 16:36:14 -05:00
|
|
|
* @return void
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
getdns_dict_item_free(struct getdns_dict_item *item)
|
|
|
|
{
|
|
|
|
if(item != NULL)
|
|
|
|
{
|
|
|
|
if(item->dtype == t_bindata)
|
|
|
|
{
|
|
|
|
if(item->data.bindata->size > 0)
|
|
|
|
free(item->data.bindata->data);
|
|
|
|
free(item->data.bindata);
|
|
|
|
}
|
|
|
|
else if(item->dtype == t_dict)
|
|
|
|
{
|
|
|
|
getdns_dict_destroy(item->data.dict);
|
|
|
|
}
|
|
|
|
else if(item->dtype == t_list)
|
|
|
|
{
|
|
|
|
getdns_list_destroy(item->data.list);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(item->key != NULL)
|
|
|
|
free(item->key);
|
|
|
|
free(item);
|
|
|
|
}
|
|
|
|
} /* getdns_dict_item_free */
|
|
|
|
|
|
|
|
/*---------------------------------------- getdns_dict_destroy */
|
|
|
|
void
|
|
|
|
getdns_dict_destroy(struct getdns_dict *dict)
|
|
|
|
{
|
|
|
|
struct getdns_dict_item keyitem;
|
|
|
|
struct getdns_dict_item *item;
|
|
|
|
|
|
|
|
if(dict != NULL && dict->rootp != NULL)
|
|
|
|
{
|
|
|
|
while(dict->rootp != NULL)
|
|
|
|
{
|
|
|
|
item = *((struct getdns_dict_item **) dict->rootp);
|
|
|
|
keyitem.key = item->key;
|
|
|
|
tdelete(&keyitem, &(dict->rootp), getdns_dict_cmp);
|
|
|
|
getdns_dict_item_free(item);
|
|
|
|
}
|
|
|
|
|
|
|
|
free(dict);
|
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
} /* getdns_dict_destroy */
|
|
|
|
|
|
|
|
/*---------------------------------------- getdns_dict_set_dict */
|
|
|
|
getdns_return_t
|
|
|
|
getdns_dict_set_dict(struct getdns_dict *dict, char *name, struct getdns_dict *child_dict)
|
|
|
|
{
|
2013-07-31 15:21:42 -05:00
|
|
|
struct getdns_dict_item *item;
|
|
|
|
struct getdns_dict *newdict;
|
2013-07-30 16:36:14 -05:00
|
|
|
getdns_return_t retval = GETDNS_RETURN_NO_SUCH_DICT_NAME;
|
|
|
|
|
2013-07-31 15:21:42 -05:00
|
|
|
if(dict != NULL && name != NULL)
|
2013-07-30 16:36:14 -05:00
|
|
|
{
|
2013-07-31 15:21:42 -05:00
|
|
|
item = getdns_dict_find(dict, name, true);
|
|
|
|
if(item != NULL)
|
2013-07-30 16:36:14 -05:00
|
|
|
{
|
2013-07-31 15:21:42 -05:00
|
|
|
retval = getdns_dict_copy(child_dict, &newdict);
|
|
|
|
if(retval == GETDNS_RETURN_GOOD)
|
|
|
|
{
|
|
|
|
item->dtype = t_dict;
|
|
|
|
item->data.dict = newdict;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
item->dtype = t_invalid;
|
2013-07-30 16:36:14 -05:00
|
|
|
}
|
2013-07-31 15:21:42 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
return retval;
|
|
|
|
} /* getdns_dict_set_dict */
|
|
|
|
|
|
|
|
/*---------------------------------------- getdns_dict_set_list */
|
|
|
|
getdns_return_t
|
|
|
|
getdns_dict_set_list(struct getdns_dict *dict, char *name, struct getdns_list *child_list)
|
|
|
|
{
|
|
|
|
struct getdns_dict_item *item;
|
|
|
|
struct getdns_list *newlist;
|
|
|
|
getdns_return_t retval = GETDNS_RETURN_NO_SUCH_DICT_NAME;
|
|
|
|
|
|
|
|
if(dict != NULL && name != NULL)
|
|
|
|
{
|
|
|
|
item = getdns_dict_find(dict, name, true);
|
|
|
|
if(item != NULL)
|
2013-07-30 16:36:14 -05:00
|
|
|
{
|
2013-07-31 15:21:42 -05:00
|
|
|
retval = getdns_list_copy(child_list, &newlist);
|
|
|
|
if(retval == GETDNS_RETURN_GOOD)
|
|
|
|
{
|
|
|
|
item->dtype = t_list;
|
|
|
|
item->data.list = newlist;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
item->dtype = t_invalid;
|
2013-07-30 16:36:14 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return retval;
|
2013-07-31 15:21:42 -05:00
|
|
|
} /* getdns_dict_set_list */
|
2013-07-15 17:43:30 -05:00
|
|
|
|
2013-07-31 15:21:42 -05:00
|
|
|
/*---------------------------------------- getdns_dict_set_bindata */
|
|
|
|
getdns_return_t
|
|
|
|
getdns_dict_set_bindata(struct getdns_dict *dict, char *name, struct getdns_bindata *child_bindata)
|
|
|
|
{
|
|
|
|
struct getdns_dict_item *item;
|
|
|
|
getdns_return_t retval = GETDNS_RETURN_NO_SUCH_DICT_NAME;
|
|
|
|
|
|
|
|
if(dict != NULL && name != NULL && child_bindata != NULL)
|
|
|
|
{
|
|
|
|
item = getdns_dict_find(dict, name, true);
|
|
|
|
if(item != NULL)
|
|
|
|
{
|
|
|
|
item->dtype = t_bindata;
|
|
|
|
item->data.bindata = (struct getdns_bindata *) malloc(sizeof(struct getdns_bindata));
|
|
|
|
if(item->data.bindata != NULL)
|
|
|
|
{
|
2013-08-15 16:51:26 -05:00
|
|
|
item->data.bindata->data = (void *) malloc(child_bindata->size);
|
2013-07-31 15:21:42 -05:00
|
|
|
if(item->data.bindata->data != NULL)
|
|
|
|
{
|
|
|
|
item->data.bindata->size = child_bindata->size;
|
|
|
|
memcpy(item->data.bindata->data, child_bindata->data, child_bindata->size);
|
|
|
|
retval = GETDNS_RETURN_GOOD;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-07-15 17:43:30 -05:00
|
|
|
|
2013-07-31 15:21:42 -05:00
|
|
|
return retval;
|
|
|
|
} /* getdns_dict_set_bindata */
|
2013-07-15 17:43:30 -05:00
|
|
|
|
2013-07-30 16:36:14 -05:00
|
|
|
/*---------------------------------------- getdns_dict_set_int */
|
|
|
|
getdns_return_t
|
|
|
|
getdns_dict_set_int(struct getdns_dict *dict, char *name, uint32_t child_uint32)
|
|
|
|
{
|
|
|
|
struct getdns_dict_item *item;
|
|
|
|
getdns_return_t retval = GETDNS_RETURN_NO_SUCH_DICT_NAME;
|
|
|
|
|
|
|
|
if(dict != NULL && name != NULL)
|
|
|
|
{
|
2013-07-31 15:21:42 -05:00
|
|
|
item = getdns_dict_find(dict, name, true);
|
|
|
|
if(item != NULL)
|
|
|
|
{
|
|
|
|
item->dtype = t_int;
|
|
|
|
item->data.n = child_uint32;
|
|
|
|
retval = GETDNS_RETURN_GOOD;
|
|
|
|
}
|
2013-07-30 16:36:14 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
return retval;
|
|
|
|
} /* getdns_dict_set_int */
|
2013-07-15 17:43:30 -05:00
|
|
|
|
2013-07-31 15:21:42 -05:00
|
|
|
/*---------------------------------------- getdns_dict_visit_print */
|
|
|
|
/**
|
|
|
|
* private function called by the tree walk function invoked by getdns_pretty_print_dict
|
|
|
|
* it is called as each node is visited. twalk() calls 3x for each node and passes order
|
|
|
|
* to tell us whether it is a pre/in/post order
|
|
|
|
* TODO: need to handle nested non-trivial data types
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
getdns_dict_visit_print(const void *node, VISIT order, int level)
|
|
|
|
{
|
|
|
|
struct getdns_dict_item *item;
|
|
|
|
int newlen;
|
|
|
|
char *dtypestr = NULL;
|
|
|
|
char *valstr = NULL;
|
|
|
|
char *itemstr = NULL;
|
|
|
|
|
|
|
|
item = *(struct getdns_dict_item **) node;
|
|
|
|
/* postorder is mis-named - it results in in-order traversal */
|
|
|
|
if(order == postorder || order == leaf)
|
|
|
|
{
|
|
|
|
switch(item->dtype)
|
|
|
|
{
|
|
|
|
case t_bindata:
|
|
|
|
dtypestr = "bindata";
|
|
|
|
valstr = strdup("NOT IMPLEMENTED");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case t_dict:
|
|
|
|
dtypestr = "dict";
|
|
|
|
valstr = strdup("NOT IMPLEMENTED");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case t_int:
|
|
|
|
dtypestr = "int";
|
|
|
|
asprintf(&valstr, "%d", item->data.n);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case t_list:
|
|
|
|
dtypestr = "list";
|
|
|
|
valstr = strdup("NOT IMPLEMENTED");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case t_invalid:
|
|
|
|
default:
|
|
|
|
dtypestr = "invalid";
|
|
|
|
valstr = strdup("");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
newlen = asprintf(&itemstr, "key=\"%s\", type=\"%s\", value=\"%s\"\n", item->key, dtypestr, valstr);
|
|
|
|
if(newlen != -1)
|
|
|
|
{
|
|
|
|
walkresultchar = (char *) realloc(walkresultchar, walkresultcharlen + newlen + 1);
|
|
|
|
memcpy(walkresultchar + walkresultcharlen, itemstr, newlen);
|
|
|
|
walkresultcharlen += newlen;
|
|
|
|
walkresultchar[walkresultcharlen] = '\0';
|
|
|
|
}
|
|
|
|
// else
|
|
|
|
// TODO: this is a fault - do something
|
|
|
|
|
|
|
|
free(valstr);
|
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
} /* getdns_dict_visit_print */
|
|
|
|
|
|
|
|
/*---------------------------------------- getdns_pretty_print_dict */
|
2013-07-15 17:43:30 -05:00
|
|
|
char *
|
2013-07-31 15:21:42 -05:00
|
|
|
getdns_pretty_print_dict(struct getdns_dict *dict)
|
|
|
|
{
|
|
|
|
char *retval = NULL;
|
|
|
|
|
|
|
|
walkresultcharlen = 0;
|
|
|
|
walkresultchar = NULL;
|
|
|
|
|
|
|
|
if(dict != NULL && dict->rootp != NULL)
|
|
|
|
{
|
|
|
|
twalk(dict->rootp, getdns_dict_visit_print);
|
|
|
|
if(walkresultcharlen > 0)
|
|
|
|
{
|
|
|
|
retval = strdup(walkresultchar);
|
|
|
|
free(walkresultchar);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return retval;
|
|
|
|
} /* getdns_pretty_print_dict */
|
2013-07-15 17:43:30 -05:00
|
|
|
|
|
|
|
/* getdns_dict.c */
|