956 lines
27 KiB
C
956 lines
27 KiB
C
/*-------------------------------------------------------------------------
|
|
The hierarchical parameter database code. For more information, see
|
|
hipadaba.h
|
|
|
|
copyright: GPL
|
|
|
|
Mark Koennecke, June 2006
|
|
---------------------------------------------------------------------------*/
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <assert.h>
|
|
#include <ctype.h>
|
|
#include "hipadaba.h"
|
|
|
|
#define ABS(x) (x < 0 ? -(x) : (x))
|
|
#define HDBMAGICK 77119900
|
|
/*================== Message Stuff ========================================*/
|
|
static char set[] = {"set"};
|
|
static char get[] = {"get"};
|
|
static char update[] = {"update"};
|
|
static char treeChange[] = {"treeChange"};
|
|
static char dataSearch[] = {"dataSearch"};
|
|
static char killNode[] = {"killNode"};
|
|
/*------------------------------------------------------------------------*/
|
|
pHdbDataMessage GetHdbSetMessage(pHdbMessage toTest){
|
|
if(toTest->type == set){
|
|
return (pHdbDataMessage)toTest;
|
|
}
|
|
return NULL;
|
|
}
|
|
/*------------------------------------------------------------------------*/
|
|
pHdbDataMessage GetHdbGetMessage(pHdbMessage toTest){
|
|
if(toTest->type == get){
|
|
return (pHdbDataMessage)toTest;
|
|
}
|
|
return NULL;
|
|
}
|
|
/*------------------------------------------------------------------------*/
|
|
pHdbDataMessage GetHdbUpdateMessage(pHdbMessage toTest){
|
|
if(toTest->type == update){
|
|
return (pHdbDataMessage)toTest;
|
|
}
|
|
return NULL;
|
|
}
|
|
/*-------------------------------------------------------------------------*/
|
|
pHdbTreeChangeMessage GetHdbTreeChangeMessage(pHdbMessage toTest){
|
|
if(toTest->type == treeChange){
|
|
return (pHdbTreeChangeMessage)toTest;
|
|
}
|
|
return NULL;
|
|
}
|
|
/*-------------------------------------------------------------------------*/
|
|
pHdbDataSearch GetHdbDataSearchMessage(pHdbMessage toTest){
|
|
if(toTest->type == dataSearch){
|
|
return (pHdbDataSearch)toTest;
|
|
}
|
|
return NULL;
|
|
}
|
|
/*-------------------------------------------------------------------------*/
|
|
pHdbMessage GetHdbKillNodeMessage(pHdbMessage toTest){
|
|
if(toTest->type == killNode){
|
|
return toTest;
|
|
}
|
|
return NULL;
|
|
}
|
|
/*================== internal functions ===================================*/
|
|
void DeleteCallbackChain(pHdbCallback root){
|
|
pHdbCallback current = NULL, thisEntry;
|
|
|
|
current = root;
|
|
while(current != NULL){
|
|
if(current->killFunc != NULL){
|
|
current->killFunc(current->userData);
|
|
}
|
|
thisEntry = current;
|
|
current = (pHdbCallback)current->next;
|
|
free(thisEntry);
|
|
}
|
|
}
|
|
/*----------------------------------------------------------------------*/
|
|
void RecurseCallbackChains(pHdb node, pHdbMessage message){
|
|
pHdb current = NULL;
|
|
|
|
InvokeCallbackChain(node,message);
|
|
current = node->child;
|
|
while(current != NULL){
|
|
RecurseCallbackChains(current,message);
|
|
current = current->next;
|
|
}
|
|
}
|
|
/*-----------------------------------------------------------------------*/
|
|
void DeleteNodeData(pHdb node){
|
|
pHdb tmp = NULL;
|
|
|
|
if(node == NULL){
|
|
return;
|
|
}
|
|
DeleteCallbackChain(node->callBackChain);
|
|
if(node->properties != NULL){
|
|
DeleteStringDict(node->properties);
|
|
}
|
|
|
|
if(node->name != NULL){
|
|
free(node->name);
|
|
}
|
|
ReleaseHdbValue(&node->value);
|
|
node->magic = 000000;
|
|
|
|
while(node->child != NULL){
|
|
tmp = node->child;
|
|
node->child = node->child->next;
|
|
DeleteNodeData(tmp);
|
|
}
|
|
free(node);
|
|
}
|
|
/*------------------------------------------------------------------------*/
|
|
static pHdbCallback CleanCallbackChain(pHdbCallback head){
|
|
pHdbCallback current = head;
|
|
pHdbCallback next;
|
|
pHdbCallback *ptr2last = &head;
|
|
|
|
while(current != NULL){
|
|
if(current->killFlag == 1){
|
|
next = current->next;
|
|
/*
|
|
* unlink
|
|
*/
|
|
*ptr2last = next;
|
|
/*
|
|
* delete
|
|
*/
|
|
if(current->killFunc != NULL){
|
|
current->killFunc(current->userData);
|
|
}
|
|
free(current);
|
|
/*
|
|
* move on
|
|
*/
|
|
current = next;
|
|
} else {
|
|
ptr2last = ¤t->next;
|
|
current = current->next;
|
|
}
|
|
}
|
|
|
|
return head;
|
|
}
|
|
/*-------------------------------------------------------------------------*/
|
|
int InvokeCallbackChain(pHdb node, pHdbMessage message){
|
|
pHdbCallback current = node->callBackChain;
|
|
hdbCallbackReturn status;
|
|
int killFlag = 0;
|
|
|
|
while(current != NULL){
|
|
status = current->userCallback(node, current->userData,message);
|
|
switch(status){
|
|
case hdbAbort:
|
|
return 0;
|
|
break;
|
|
case hdbKill:
|
|
current->killFlag = 1;
|
|
killFlag = 1;
|
|
break;
|
|
case hdbContinue:
|
|
break;
|
|
}
|
|
current = current->next;
|
|
}
|
|
if(killFlag == 1){
|
|
node->callBackChain = CleanCallbackChain(node->callBackChain);
|
|
}
|
|
return 1;
|
|
}
|
|
/*-----------------------------------------------------------------------*/
|
|
static void SendTreeChangeMessage(pHdb node, void *callData){
|
|
hdbTreeChangeMessage treeChangeMes;
|
|
treeChangeMes.type = treeChange;
|
|
treeChangeMes.callData = callData;
|
|
InvokeCallbackChain(node, (pHdbMessage)&treeChangeMes);
|
|
}
|
|
/*------------------------------------------------------------------------*/
|
|
void RemoveHdbNodeFromParent(pHdb node, void *callData){
|
|
pHdb parent = NULL;
|
|
pHdb current = NULL;
|
|
hdbTreeChangeMessage treeChangeMes;
|
|
|
|
parent = node->mama;
|
|
if(parent != NULL){
|
|
if(parent->child == node){
|
|
parent->child = node->next;
|
|
} else {
|
|
current = parent->child;
|
|
while(current->next != node){
|
|
current = current->next;
|
|
}
|
|
current->next = current->next->next;
|
|
}
|
|
SendTreeChangeMessage(parent,callData);
|
|
node->mama = NULL;
|
|
}
|
|
}
|
|
/*----------------------------------------------------------------------*/
|
|
int CountHdbChildren(pHdb node){
|
|
int count = 0;
|
|
pHdb current = NULL;
|
|
current = node->child;
|
|
while(current != NULL){
|
|
current = current->next;
|
|
count++;
|
|
}
|
|
return count;
|
|
}
|
|
/*----------------------------------------------------------------------*/
|
|
char *hdbTrim(char *str)
|
|
{
|
|
char *ibuf = str, *obuf = str;
|
|
int i = 0, cnt = 0;
|
|
|
|
/*
|
|
** Trap NULL
|
|
*/
|
|
|
|
if (str)
|
|
{
|
|
/*
|
|
** Remove leading spaces (from RMLEAD.C)
|
|
*/
|
|
|
|
for (ibuf = str; *ibuf && isspace(*ibuf); ++ibuf)
|
|
;
|
|
if (str != ibuf)
|
|
memmove(str, ibuf, ibuf - str);
|
|
|
|
/*
|
|
** Collapse embedded spaces (from LV1WS.C)
|
|
*/
|
|
|
|
while (*ibuf)
|
|
{
|
|
if (isspace(*ibuf) && cnt)
|
|
ibuf++;
|
|
else
|
|
{
|
|
if (!isspace(*ibuf))
|
|
cnt = 0;
|
|
else
|
|
{
|
|
*ibuf = ' ';
|
|
cnt = 1;
|
|
}
|
|
obuf[i++] = *ibuf++;
|
|
}
|
|
}
|
|
obuf[i] = '\0';
|
|
|
|
/*
|
|
** Remove trailing spaces (from RMTRAIL.C)
|
|
*/
|
|
|
|
while (--i >= 0)
|
|
{
|
|
if (!isspace(obuf[i]))
|
|
break;
|
|
}
|
|
obuf[++i] = '\0';
|
|
}
|
|
return str;
|
|
}
|
|
/*------------------------------------------------------------------------*/
|
|
static pHdb locateChild(pHdb root, char *name){
|
|
pHdb current = NULL;
|
|
|
|
current = root->child;
|
|
while(current != NULL){
|
|
if(strcmp(current->name,name) == 0){
|
|
return current;
|
|
}
|
|
current = current->next;
|
|
}
|
|
return NULL;
|
|
}
|
|
/*================= data functions ========================================*/
|
|
hdbValue makeHdbValue(int datatype, int length){
|
|
hdbValue val;
|
|
|
|
memset(&val,0,sizeof(hdbValue));
|
|
val.dataType = datatype;
|
|
val.doNotFree = 0;
|
|
|
|
switch(datatype){
|
|
case HIPINTAR:
|
|
case HIPINTVARAR:
|
|
val.arrayLength = length;
|
|
val.v.intArray = malloc(length*sizeof(int));
|
|
if(val.v.intArray != NULL){
|
|
memset(val.v.intArray,0,length*sizeof(int));
|
|
}
|
|
break;
|
|
case HIPFLOATAR:
|
|
case HIPFLOATVARAR:
|
|
val.arrayLength = length;
|
|
val.v.floatArray = malloc(length*sizeof(double));
|
|
if(val.v.floatArray != NULL){
|
|
memset(val.v.floatArray,0,length*sizeof(double));
|
|
}
|
|
break;
|
|
case HIPTEXT:
|
|
val.v.text = strdup("UNKNOWN");
|
|
val.arrayLength = length;
|
|
break;
|
|
}
|
|
return val;
|
|
}
|
|
/*-------------------------------------------------------------------------*/
|
|
hdbValue MakeHdbInt(int initValue){
|
|
hdbValue result;
|
|
|
|
result.dataType = HIPINT;
|
|
result.arrayLength = 1;
|
|
result.v.intValue = initValue;
|
|
return result;
|
|
}
|
|
/*-------------------------------------------------------------------------*/
|
|
hdbValue MakeHdbFloat(double initValue){
|
|
hdbValue result;
|
|
|
|
result.dataType = HIPFLOAT;
|
|
result.arrayLength = 1;
|
|
result.v.doubleValue = initValue;
|
|
return result;
|
|
}
|
|
/*-------------------------------------------------------------------------*/
|
|
hdbValue MakeHdbText(char *initText){
|
|
hdbValue result;
|
|
|
|
result.dataType = HIPTEXT;
|
|
result.v.text = initText; /* no strdup here ! */
|
|
result.arrayLength = strlen(initText);
|
|
return result;
|
|
}
|
|
/*-------------------------------------------------------------------------*/
|
|
hdbValue MakeHdbIntArray(int length, int *data){
|
|
hdbValue result;
|
|
|
|
result.dataType = HIPINTAR;
|
|
result.arrayLength = length;
|
|
result.v.intArray = data;
|
|
return result;
|
|
}
|
|
/*-------------------------------------------------------------------------*/
|
|
hdbValue MakeHdbFloatArray(int length, double *data){
|
|
hdbValue result;
|
|
|
|
result.dataType = HIPFLOATAR;
|
|
result.arrayLength = length;
|
|
result.v.floatArray = data;
|
|
return result;
|
|
}
|
|
/*-------------------------------------------------------------------------*/
|
|
hdbValue MakeHdbFunc(voidFunc *func){
|
|
hdbValue result;
|
|
|
|
result.dataType = HIPFUNC;
|
|
result.v.func = func;
|
|
return result;
|
|
}
|
|
/*-------------------------------------------------------------------------*/
|
|
hdbValue MakeHdbObj(void *obj){
|
|
hdbValue result;
|
|
|
|
result.dataType = HIPOBJ;
|
|
result.v.obj = obj;
|
|
return result;
|
|
}
|
|
/*-------------------------------------------------------------------------*/
|
|
void ReleaseHdbValue(hdbValue *v){
|
|
|
|
if(v->doNotFree == 1){
|
|
return;
|
|
}
|
|
switch(v->dataType){
|
|
case HIPTEXT:
|
|
if(v->v.text != NULL){
|
|
free(v->v.text);
|
|
}
|
|
break;
|
|
case HIPINTAR:
|
|
case HIPINTVARAR:
|
|
if(v->v.intArray != NULL){
|
|
free(v->v.intArray);
|
|
}
|
|
break;
|
|
case HIPFLOATAR:
|
|
case HIPFLOATVARAR:
|
|
if(v->v.floatArray != NULL){
|
|
free(v->v.floatArray);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
/*------------------------------------------------------------------------*/
|
|
int compareHdbValue(hdbValue v1, hdbValue v2){
|
|
int i;
|
|
|
|
if(v1.dataType != v2.dataType){
|
|
return 0;
|
|
}
|
|
switch(v1.dataType){
|
|
case HIPNONE:
|
|
return 0;
|
|
break;
|
|
case HIPINT:
|
|
if(v1.v.intValue == v2.v.intValue){
|
|
return 1;
|
|
} else {
|
|
return 0;
|
|
}
|
|
break;
|
|
case HIPFLOAT:
|
|
if(ABS(v1.v.doubleValue - v2.v.doubleValue) < .01){
|
|
return 1;
|
|
} else {
|
|
return 0;
|
|
}
|
|
break;
|
|
case HIPTEXT:
|
|
if(v1.v.text == NULL || v2.v.text == NULL){
|
|
return 0;
|
|
}
|
|
if(strcmp(v1.v.text,v2.v.text) == 0){
|
|
return 1;
|
|
} else {
|
|
return 0;
|
|
}
|
|
break;
|
|
case HIPINTAR:
|
|
case HIPINTVARAR:
|
|
if(v1.arrayLength != v2.arrayLength){
|
|
return 0;
|
|
}
|
|
if(v1.v.intArray == NULL || v2.v.intArray == NULL){
|
|
return 0;
|
|
}
|
|
for(i = 0; i < v1.arrayLength; i++){
|
|
if(v1.v.intArray[i] != v2.v.intArray[i]){
|
|
return 0;
|
|
}
|
|
}
|
|
return 1;
|
|
break;
|
|
case HIPFLOATAR:
|
|
case HIPFLOATVARAR:
|
|
if(v1.arrayLength != v2.arrayLength){
|
|
return 0;
|
|
}
|
|
if(v1.v.floatArray == NULL || v2.v.floatArray == NULL){
|
|
return 0;
|
|
}
|
|
for(i = 0; i < v1.arrayLength; i++){
|
|
if(ABS(v1.v.floatArray[i] - v2.v.floatArray[i]) > .01){
|
|
return 0;
|
|
}
|
|
}
|
|
return 1;
|
|
break;
|
|
case HIPOBJ:
|
|
if(v2.v.obj == v1.v.obj) {
|
|
return 1;
|
|
} else {
|
|
return 0;
|
|
}
|
|
break;
|
|
case HIPFUNC:
|
|
if(v2.v.func == v1.v.func) {
|
|
return 1;
|
|
} else {
|
|
return 0;
|
|
}
|
|
break;
|
|
default:
|
|
assert(0);
|
|
break;
|
|
}
|
|
return 0;
|
|
}
|
|
/*-------------------------------------------------------------------------*/
|
|
int cloneHdbValue(hdbValue *source, hdbValue *clone){
|
|
|
|
memset(clone,0,sizeof(hdbValue));
|
|
clone->v.text = NULL; /* this sets all pointers in the union to NULL */
|
|
clone->dataType = source->dataType;
|
|
return copyHdbValue(source, clone);
|
|
}
|
|
/*-------------------------------------------------------------------------*/
|
|
int getHdbValueLength(hdbValue v){
|
|
int length = 0;
|
|
switch(v.dataType){
|
|
case HIPNONE:
|
|
break;
|
|
case HIPINT:
|
|
length = sizeof(int);
|
|
break;
|
|
case HIPFLOAT:
|
|
length = sizeof(double);
|
|
break;
|
|
case HIPINTAR:
|
|
case HIPINTVARAR:
|
|
length = v.arrayLength * sizeof(int);
|
|
break;
|
|
case HIPFLOATAR:
|
|
case HIPFLOATVARAR:
|
|
length = v.arrayLength * sizeof(double);
|
|
break;
|
|
case HIPTEXT:
|
|
length = strlen(v.v.text);
|
|
break;
|
|
case HIPOBJ:
|
|
length = sizeof(void *);
|
|
break;
|
|
case HIPFUNC:
|
|
length = sizeof(voidFunc *);
|
|
break;
|
|
}
|
|
return length;
|
|
}
|
|
/*================= node functions ========================================*/
|
|
pHdb MakeHipadabaNode(char *name, int datatype, int length){
|
|
pHdb pNew = NULL;
|
|
|
|
pNew = malloc(sizeof(Hdb));
|
|
if(pNew == NULL){
|
|
return NULL;
|
|
}
|
|
memset(pNew,0,sizeof(Hdb));
|
|
pNew->magic = HDBMAGICK;
|
|
pNew->name = strdup(name);
|
|
pNew->value.dataType = datatype;
|
|
pNew->properties = CreateStringDict();
|
|
if(pNew->properties == NULL || pNew->name == NULL){
|
|
return NULL;
|
|
}
|
|
switch(datatype){
|
|
case HIPINTAR:
|
|
case HIPINTVARAR:
|
|
pNew->value.arrayLength = length;
|
|
pNew->value.v.intArray = malloc(length*sizeof(int));
|
|
if(pNew->value.v.intArray == NULL){
|
|
return NULL;
|
|
}
|
|
memset(pNew->value.v.intArray,0,length*sizeof(int));
|
|
break;
|
|
case HIPFLOATAR:
|
|
case HIPFLOATVARAR:
|
|
pNew->value.arrayLength = length;
|
|
pNew->value.v.floatArray = malloc(length*sizeof(double));
|
|
if(pNew->value.v.floatArray == NULL){
|
|
return NULL;
|
|
}
|
|
memset(pNew->value.v.floatArray,0,length*sizeof(double));
|
|
break;
|
|
case HIPTEXT:
|
|
pNew->value.arrayLength = length;
|
|
pNew->value.v.text = strdup("UNKNOWN");
|
|
break;
|
|
}
|
|
return pNew;
|
|
}
|
|
/*-------------------------------------------------------------------------*/
|
|
void AddHipadabaChild(pHdb parent, pHdb child, void *callData){
|
|
pHdb current = NULL, prev = NULL;
|
|
|
|
assert(parent != NULL);
|
|
if(child == NULL){
|
|
return;
|
|
}
|
|
|
|
current = parent->child;
|
|
child->mama = parent;
|
|
if(current == NULL){
|
|
parent->child = child;
|
|
child->next = NULL;
|
|
} else {
|
|
/*
|
|
* step to end of child chain
|
|
*/
|
|
while(current != NULL){
|
|
prev = current;
|
|
current = current->next;
|
|
}
|
|
child->next = NULL;
|
|
prev->next = child;
|
|
}
|
|
SendTreeChangeMessage(parent,callData);
|
|
}
|
|
/*--------------------------------------------------------------------------*/
|
|
void DeleteHipadabaNode(pHdb node, void *callData){
|
|
pHdb current = NULL, tmp = NULL;
|
|
hdbMessage killNodeMsg;
|
|
|
|
if(node == NULL){
|
|
return;
|
|
}
|
|
|
|
killNodeMsg.type = killNode;
|
|
InvokeCallbackChain(node, &killNodeMsg);
|
|
|
|
RemoveHdbNodeFromParent(node, callData);
|
|
|
|
DeleteNodeData(node);
|
|
}
|
|
/*--------------------------------------------------------------------------*/
|
|
int isHdbNodeValid(pHdb node){
|
|
if(node == NULL){
|
|
return 0;
|
|
}
|
|
if(node->magic == HDBMAGICK){
|
|
return 1;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
/*--------------------------------------------------------------------------*/
|
|
pHdb GetHipadabaNode(pHdb root, char *puth){
|
|
pHdb resultNode = NULL;
|
|
char *separator = NULL;
|
|
char *path = NULL, *pathData;
|
|
|
|
/*
|
|
* I need to make a copy in order to get the path in writable memory.
|
|
* Otherwise we SEGFAULT in hdbTrim when this function is called with
|
|
* a string constant in puth
|
|
*/
|
|
pathData = strdup(puth);
|
|
path = pathData;
|
|
if(path == NULL){
|
|
return NULL;
|
|
}
|
|
path = hdbTrim(path);
|
|
|
|
if(strcmp(path,"/") == 0 || strlen(path) == 0){
|
|
free(pathData);
|
|
return root;
|
|
}
|
|
|
|
if(path[0] == '/'){
|
|
path++;
|
|
}
|
|
|
|
separator = strchr(path,'/');
|
|
if(separator == NULL){
|
|
resultNode = locateChild(root,path);
|
|
free(pathData);
|
|
return resultNode;
|
|
} else {
|
|
*separator = '\0';
|
|
resultNode = locateChild(root, path);
|
|
if(resultNode == NULL){
|
|
free(pathData);
|
|
return NULL;
|
|
} else {
|
|
separator++;
|
|
resultNode = GetHipadabaNode(resultNode,separator);
|
|
free(pathData);
|
|
return resultNode;
|
|
}
|
|
}
|
|
}
|
|
/*--------------------------------------------------------------------------*/
|
|
char *GetHipadabaPath(pHdb node){
|
|
pHdb nodeStack[64];
|
|
int depth = 0, length = 0, i;
|
|
pHdb current = NULL;
|
|
char *pPtr = NULL;
|
|
|
|
/**
|
|
* build a nodestack and find out required string length for path
|
|
*/
|
|
current = node;
|
|
while(current != NULL){
|
|
length += strlen(current->name) + 1;
|
|
nodeStack[depth] = current;
|
|
depth++;
|
|
assert(depth < 64);
|
|
current = current->mama;
|
|
}
|
|
|
|
pPtr = malloc(length*sizeof(char));
|
|
if(pPtr == NULL){
|
|
return NULL;
|
|
}
|
|
memset(pPtr,0,length*sizeof(char));
|
|
|
|
/*
|
|
* we wish to decremement by one because above loop
|
|
* increments one to many and we wish to ignore the
|
|
* root node
|
|
*/
|
|
for(i = depth - 2; i >= 0; i--){
|
|
strcat(pPtr,"/");
|
|
strcat(pPtr,nodeStack[i]->name);
|
|
}
|
|
return pPtr;
|
|
}
|
|
/*==================== Callback Functions ==================================*/
|
|
pHdbCallback MakeHipadabaCallback(hdbCallbackFunction func,
|
|
void *userData, killUserData killFunc){
|
|
pHdbCallback pNew = NULL;
|
|
|
|
assert(func != NULL);
|
|
|
|
pNew = malloc(sizeof(hdbCallback));
|
|
if(pNew == NULL){
|
|
return NULL;
|
|
}
|
|
memset(pNew,0,sizeof(hdbCallback));
|
|
|
|
pNew->userCallback = func;
|
|
pNew->userData = userData;
|
|
pNew->killFunc = killFunc;
|
|
return pNew;
|
|
}
|
|
/*-------------------------------------------------------------------*/
|
|
void AppendHipadabaCallback(pHdb node, pHdbCallback newCB){
|
|
pHdbCallback current = NULL;
|
|
|
|
assert(node);
|
|
current = node->callBackChain;
|
|
newCB->next = NULL;
|
|
if(current == NULL){
|
|
node->callBackChain = newCB;
|
|
return;
|
|
}
|
|
while(current->next != NULL){
|
|
current = (pHdbCallback)current->next;
|
|
}
|
|
current->next = newCB;
|
|
}
|
|
/*---------------------------------------------------------------------------*/
|
|
void PrependHipadabaCallback(pHdb node,pHdbCallback newCB){
|
|
assert(node != NULL);
|
|
|
|
newCB->next = node->callBackChain;
|
|
node->callBackChain = newCB;
|
|
}
|
|
/*----------------------------------------------------------------------------*/
|
|
void *FindHdbCallbackData(pHdb node, void *userPtr){
|
|
hdbDataSearch dsm;
|
|
|
|
dsm.type = dataSearch;
|
|
dsm.testPtr = userPtr;
|
|
dsm.result = NULL;
|
|
|
|
InvokeCallbackChain(node, (pHdbMessage)&dsm);
|
|
return dsm.result;
|
|
|
|
}
|
|
/*=================== parameter interface ====================================*/
|
|
static int canCopy(hdbValue *source, hdbValue *target){
|
|
if(target->dataType == HIPINTVARAR) {
|
|
if(source->dataType == HIPINTAR ||
|
|
source->dataType == HIPINTVARAR){
|
|
return 1;
|
|
}
|
|
}
|
|
if(target->dataType == HIPFLOATVARAR) {
|
|
if(source->dataType == HIPFLOATAR ||
|
|
source->dataType == HIPFLOATVARAR){
|
|
return 1;
|
|
}
|
|
}
|
|
if(source->dataType != target->dataType){
|
|
return 0;
|
|
} else {
|
|
return 1;
|
|
}
|
|
}
|
|
/*----------------------------------------------------------------------------*/
|
|
int copyHdbValue(hdbValue *source, hdbValue *target){
|
|
int i;
|
|
|
|
if(!canCopy(source,target)){
|
|
return 0;
|
|
}
|
|
|
|
switch(source->dataType){
|
|
case HIPNONE:
|
|
break;
|
|
case HIPINT:
|
|
target->v.intValue = source->v.intValue;
|
|
break;
|
|
case HIPFLOAT:
|
|
target->v.doubleValue = source->v.doubleValue;
|
|
break;
|
|
case HIPTEXT:
|
|
if(target->v.text != NULL){
|
|
free(target->v.text);
|
|
}
|
|
target->v.text = strdup(source->v.text);
|
|
break;
|
|
case HIPINTAR:
|
|
case HIPINTVARAR:
|
|
if(target->arrayLength != source->arrayLength || target->v.intArray == NULL){
|
|
if(target->v.intArray != NULL){
|
|
free(target->v.intArray);
|
|
}
|
|
target->v.intArray = malloc(source->arrayLength * sizeof(int));
|
|
if(target->v.intArray == NULL){
|
|
return 0;
|
|
}
|
|
memset(target->v.intArray,0,source->arrayLength
|
|
* sizeof(int));
|
|
target->arrayLength = source->arrayLength;
|
|
}
|
|
if(source->v.intArray != NULL){
|
|
for(i = 0; i < source->arrayLength; i++){
|
|
target->v.intArray[i] = source->v.intArray[i];
|
|
}
|
|
}
|
|
break;
|
|
case HIPFLOATAR:
|
|
case HIPFLOATVARAR:
|
|
if(target->arrayLength != source->arrayLength
|
|
|| target->v.floatArray == NULL){
|
|
if(target->v.floatArray != NULL){
|
|
free(target->v.floatArray);
|
|
}
|
|
target->v.floatArray =
|
|
malloc(source->arrayLength * sizeof(double));
|
|
if(target->v.floatArray == NULL){
|
|
return 0;
|
|
}
|
|
memset(target->v.floatArray,0,source->arrayLength *
|
|
sizeof(double));
|
|
target->arrayLength = source->arrayLength;
|
|
}
|
|
if(source->v.floatArray != NULL){
|
|
for(i = 0; i < source->arrayLength; i++){
|
|
target->v.floatArray[i] = source->v.floatArray[i];
|
|
}
|
|
}
|
|
break;
|
|
case HIPOBJ:
|
|
target->v.obj = source->v.obj;
|
|
break;
|
|
case HIPFUNC:
|
|
target->v.func = source->v.func;
|
|
break;
|
|
default:
|
|
/*
|
|
* unknown data type
|
|
*/
|
|
assert(0);
|
|
break;
|
|
}
|
|
return 1;
|
|
}
|
|
/*---------------------------------------------------------------------------*/
|
|
static int SendDataMessage(pHdb node, char *type,
|
|
hdbValue v, void *callData){
|
|
hdbDataMessage dataMes;
|
|
|
|
assert(type == set || type == get || type == update);
|
|
dataMes.type = type;
|
|
dataMes.v = &v;
|
|
dataMes.callData = callData;
|
|
return InvokeCallbackChain(node, (pHdbMessage)&dataMes);
|
|
}
|
|
/*----------------------------------------------------------------------------*/
|
|
int SetHipadabaPar(pHdb node, hdbValue v, void *callData){
|
|
return SendDataMessage(node, set, v,callData);
|
|
}
|
|
/*-----------------------------------------------------------------------------*/
|
|
int UpdateHipadabaPar(pHdb node, hdbValue v, void *callData){
|
|
int status;
|
|
|
|
status = SendDataMessage(node, update, v,callData);
|
|
if(status == 1){
|
|
copyHdbValue(&v,&node->value);
|
|
}
|
|
return status;
|
|
}
|
|
/*-----------------------------------------------------------------------------*/
|
|
int NotifyHipadabaPar(pHdb node,void *callData){
|
|
SendDataMessage(node, update, node->value,callData);
|
|
return 1;
|
|
}
|
|
/*-----------------------------------------------------------------------------*/
|
|
int GetHipadabaPar(pHdb node, hdbValue *v, void *callData){
|
|
int status;
|
|
|
|
v->dataType = node->value.dataType;
|
|
v->doNotFree = 0;
|
|
v->v.text = NULL; /* this sets all pointers in the union to NULL */
|
|
|
|
status = SendDataMessage(node, get, *v,callData);
|
|
if(status != 1 ){
|
|
return status;
|
|
}
|
|
copyHdbValue(&node->value,v);
|
|
return 1;
|
|
}
|
|
/*----------------------------------------------------------------------------*/
|
|
static int calcDataLength(pHdb node, int testLength){
|
|
int length = 0;
|
|
|
|
length = getHdbValueLength(node->value);
|
|
if(node->value.dataType == HIPFLOATVARAR ||
|
|
node->value.dataType == HIPINTVARAR ||
|
|
node->value.dataType == HIPTEXT){
|
|
length = testLength;
|
|
}
|
|
return length;
|
|
}
|
|
/*============================= Property Functions ==========================*/
|
|
void SetHdbProperty(pHdb node, char *key, char *value){
|
|
if(node != NULL && key != NULL && node->properties != NULL){
|
|
if (value == NULL) {
|
|
StringDictDelete(node->properties, key);
|
|
} else if(StringDictExists(node->properties, key)){
|
|
StringDictUpdate(node->properties,key,value);
|
|
} else {
|
|
StringDictAddPair(node->properties,key,value);
|
|
}
|
|
}
|
|
}
|
|
/*---------------------------------------------------------------------------*/
|
|
int GetHdbProperty(pHdb node, char *key, char *value, int len){
|
|
if(node != NULL && node->properties != NULL){
|
|
return StringDictGet(node->properties,key,value,len);
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
/*---------------------------------------------------------------------------*/
|
|
char *GetHdbProp(pHdb node, char *key){
|
|
if(node != NULL && node->properties != NULL){
|
|
return StringDictGetShort(node->properties,key);
|
|
} else {
|
|
return NULL;
|
|
}
|
|
}
|
|
/*---------------------------------------------------------------------------*/
|
|
void InitHdbPropertySearch(pHdb node){
|
|
if(node != NULL && node->properties != NULL){
|
|
StringDictKillScan(node->properties);
|
|
}
|
|
}
|
|
/*--------------------------------------------------------------------------*/
|
|
const char *GetNextHdbProperty(pHdb node, char *value ,int len){
|
|
if(node != NULL && node->properties != NULL) {
|
|
return StringDictGetNext(node->properties, value, len);
|
|
} else {
|
|
return NULL;
|
|
}
|
|
}
|