Files
sics/hipadaba.c
zolliker b5b4da2776 - unified the 2 script context commands
- minor changes in hipadaba and ascon/devser
2008-05-30 09:29:44 +00:00

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 = &current->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;
}
}