Files
sics/sicshipadaba.c
koennecke 6cf9add9ee - Installed json protocol
SKIPPED:
	psi/libpsi.a
	psi/tecs/libtecsl.a
2007-01-21 22:07:37 +00:00

2491 lines
75 KiB
C

/**
* This is a set of helper functions for SICS to work with the hierarchical parameter
* database hipadaba. In SICS, the calldata associated with any callback will always
* be the connection object.
*
* copyright: GPL
*
* Mark Koennecke, June 2006
*
* Introduced notification on tree changes, Mark Koennecke, November 2006
*
* Added property functions, Mark Koennecke, January 2007
*
* TODO: separate this into two modules: sicshipadaba proper and sicshipadabaint for the
* interpreter interface.
*/
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <ctype.h>
#include <sicshipadaba.h>
#include <sicshdbadapter.h>
#include "sicspoll.h"
#include <lld.h>
#include <stptok.h>
#include "protocol.h"
/*== there can be only hipadaba in SICS, some globals to care for that == */
static pHdb root = NULL;
static pSicsPoll poller = NULL;
/*=============== common callback functions used for SICS ===========================*/
static int SICSCheckPermissionCallback(void *userData, void *callData, pHdb node,
hdbValue v){
int *testPriv = NULL;
SConnection *pCon = NULL;
pCon = (SConnection *)callData;
testPriv = (int *)userData;
/*
* If pCon is NULL, then this is an internal call from some driver
* code where no permission check is necessary. However, when called
* through the hipadaba tree commands and other upper level code, the
* check will be honoured.
*/
if(pCon == NULL){
return 1;
}
assert(testPriv != NULL);
if(SCMatchRights(pCon,*testPriv) == 1){
return 1;
} else {
return SICSCBPERM;
}
}
/*--------------------------------------------------------------------------------------*/
pHdbCallback MakeCheckPermissionCallback(int priv){
int *testPriv = NULL;
testPriv = malloc(sizeof(int));
if(testPriv == NULL){
return NULL;
}
*testPriv = priv;
return MakeHipadabaCallback(SICSCheckPermissionCallback, testPriv,free,-1,-1);
}
/*-------------------------------------------------------------------------------------*/
static int SICSSetUpdateCallback(void *userData, void *callData, pHdb node,
hdbValue v){
return UpdateHipadabaPar(node,v,callData);
}
/*-------------------------------------------------------------------------------------*/
pHdbCallback MakeSetUpdateCallback(){
return MakeHipadabaCallback(SICSSetUpdateCallback, NULL,NULL,-1,-1);
}
/*---------------------------------------------------------------------------------------*/
static int SICSReadOnlyCallback(void *userData, void *callData, pHdb node,
hdbValue v){
SConnection *pCon = NULL;
pCon = (SConnection *)callData;
if(pCon != NULL){
SCWrite(pCon,"ERROR: parameter is READ-ONLY", eError);
}
return SICSCBRO;
}
/*-------------------------------------------------------------------------------------*/
pHdbCallback MakeReadOnlyCallback(){
return MakeHipadabaCallback(SICSReadOnlyCallback, NULL,NULL,-1,-1);
}
/*-------------------------------------------------------------------------------------*/
static int SICSDriveCallback(void *userData, void *callData, pHdb node,
hdbValue v){
SConnection *pCon = NULL;
pDummy dum = NULL;
pCon = (SConnection *)callData;
dum = (pDummy)userData;
assert(pCon != NULL && dum != NULL);
return StartDevice(pServ->pExecutor,node->name,dum->pDescriptor,
userData, pCon, (float)v.v.doubleValue);
}
/*---------------------------------------------------------------------------------------*/
pHdbCallback MakeSICSDriveCallback(void *sicsObject){
return MakeHipadabaCallback(SICSDriveCallback, sicsObject,NULL,-1,-1);
}
/*---------------------------------------------------------------------------------------*/
static int SICSReadDriveCallback(void *userData, void *callData, pHdb node,
hdbValue v){
static SConnection *defCon = NULL;
SConnection *pCon = NULL;
pDummy dum = NULL;
pIDrivable pDriv = NULL;
float value;
pCon = (SConnection *)callData;
dum = (pDummy)userData;
assert(dum != NULL);
if(defCon == NULL){
defCon = SCCreateDummyConnection(pServ->pSics);
}
pDriv = dum->pDescriptor->GetInterface(dum,DRIVEID);
assert(pDriv != NULL);
if(pCon != NULL){
value = pDriv->GetValue(dum,pCon);
node->value.v.doubleValue = (double)value;
v.v.doubleValue = (double)value;
} else {
if(defCon != NULL){
value = pDriv->GetValue(dum,defCon);
node->value.v.doubleValue = (double)value;
v.v.doubleValue = (double)value;
}
}
return 1;
}
/*--------------------------------------------------------------------------------------*/
pHdbCallback MakeSICSReadDriveCallback(void *sicsObject){
return MakeHipadabaCallback(SICSReadDriveCallback, sicsObject,NULL,-1,-1);
}
/*---------------------------------------------------------------------------------------*/
typedef struct {
SConnection *pCon;
commandContext context;
}HdbCBInfo;
static int isJSON(SConnection *pCon) {
char proName[128];
void *pData;
if(SCinMacro(pCon)){
return 0;
}
pData = FindCommandData(pServ->pSics, "protocol","Protocol");
ProtocolGet(pCon, pData, proName, 128);
if (strcmp(proName, "json") == 0)
return 1;
else
return 0;
}
int formatNameValue(int jsonSet, char *name, char *value, pDynString result) {
if (name == NULL) {
if (jsonSet) {
} else {
}
} else if (value == NULL) {
if (jsonSet) {
DynStringInsert(result,"\": ", 0);
DynStringInsert(result,name,0);
DynStringInsert(result,"{\"", 0);
DynStringConcat(result,"}");
} else {
DynStringInsert(result," =",0);
DynStringInsert(result,name,0);
}
} else {
if (jsonSet) {
DynStringCopy(result,"{\"");
DynStringConcat(result,name);
DynStringConcat(result,"\": ");
DynStringConcat(result,value);
DynStringConcat(result,"}");
} else {
DynStringCopy(result,name);
DynStringConcat(result," = ");
DynStringConcat(result,value);
}
}
return jsonSet;
}
/*----------------------------------------------------------------------------------------*/
static int SICSNotifyCallback(void *userData, void *callData, pHdb node,
hdbValue v){
HdbCBInfo *cbInfo = NULL;
pDynString printedData = NULL;
pDynString result = NULL;
char *pPath = NULL;
int protocol = 0, outCode;
cbInfo = (HdbCBInfo *)userData;
pPath = GetHipadabaPath(node);
result = CreateDynString(128,128);
if ((protocol = isJSON(cbInfo->pCon)) == 1)
outCode = eHdbEvent;
else
outCode = eEvent;
if(v.arrayLength < 100){
printedData = formatValue(v);
if(pPath == NULL || printedData == NULL || result == NULL){
SCWriteInContext(cbInfo->pCon,"ERROR: out of memory formatting data" ,
eEvent,cbInfo->context);
/*
* no need to interrupt something because writing data to a client does
* not work
*/
return 1;
}
formatNameValue(protocol, pPath, GetCharArray(printedData), result);
SCWriteInContext(cbInfo->pCon,GetCharArray(result),
outCode,cbInfo->context);
DeleteDynString(printedData);
} else {
formatNameValue(protocol,"!!datachange!!", pPath, result);
SCWriteInContext(cbInfo->pCon,GetCharArray(result),
outCode,cbInfo->context);
}
free(pPath);
DeleteDynString(result);
return 1;
}
/*-----------------------------------------------------------------------------------------*/
pHdbCallback MakeNotifyCallback(SConnection *pCon, int id){
HdbCBInfo *cbInfo = NULL;
cbInfo = malloc(sizeof(HdbCBInfo));
if(cbInfo == NULL){
return NULL;
}
cbInfo->pCon = pCon;
cbInfo->context = SCGetContext(pCon);
return MakeHipadabaCallback(SICSNotifyCallback, cbInfo,free,id,pCon->ident);
}
/*-------------------------------------------------------------------------*/
static int TreeChangeCallback(void *userData, void *callData, pHdb node,
hdbValue v){
char *path = NULL;
char buffer[1024];
pDynString result = NULL;
int protocol = 0, outCode;
result = CreateDynString(128,128);
HdbCBInfo *cbInfo = (HdbCBInfo *)userData;
if(cbInfo != NULL && cbInfo->pCon != NULL){
path = GetHipadabaPath(node);
if ((protocol = isJSON(cbInfo->pCon)) == 1)
outCode = eHdbEvent;
else
outCode = eEvent;
formatNameValue(protocol, "treechange", path, result);
SCWriteInContext(cbInfo->pCon,GetCharArray(result),outCode,cbInfo->context);
DeleteDynString(result);
free(path);
}
return 1;
}
/*-------------------------------------------------------------------------*/
pHdbCallback MakeTreeChangeCallback(SConnection *pCon, int id){
HdbCBInfo *cbInfo = NULL;
cbInfo = malloc(sizeof(HdbCBInfo));
if(cbInfo == NULL){
return NULL;
}
cbInfo->pCon = pCon;
cbInfo->context = SCGetContext(pCon);
return MakeHipadabaCallback(TreeChangeCallback, cbInfo,free,id,pCon->ident);
}
/*----------------------------------------------------------------------------------------*/
static int SICSScriptWriteCallback(void *userData, void *callData, pHdb node,
hdbValue v){
char *command = NULL;
SConnection *pCon = NULL;
pDynString newVal = NULL;
char error[1024];
int status;
command = (char *)userData;
pCon = (SConnection *)callData;
assert(command != NULL && pCon != NULL);
newVal = formatValue(v);
if(newVal == NULL){
SCWrite(pCon,"ERROR: out of memory setting parameter",eError);
return 0;
}
/**
* prepend command
*/
DynStringInsert(newVal," ", 0);
DynStringInsert(newVal,command,0);
/*
* evaluate
*/
status = Tcl_Eval(InterpGetTcl(pServ->pSics),GetCharArray(newVal));
if(status != TCL_OK){
snprintf(error,1023,"ERROR: tcl returned error: %s",
Tcl_GetStringResult(InterpGetTcl(pServ->pSics)));
SCWrite(pCon,error,eError);
status = 0;
} else {
status = 1;
}
DeleteDynString(newVal);
return status;
}
/*---------------------------------------------------------------------------------------*/
static pHdbCallback MakeSICSWriteScriptCallback(char *script){
return MakeHipadabaCallback(SICSScriptWriteCallback, strdup(script),free,-1,-1);
}
/*----------------------------------------------------------------------------------------*/
static int SICSScriptReadCallback(void *userData, void *callData, pHdb node,
hdbValue v){
char *command = NULL, *data = NULL, *equal = NULL;
SConnection *pCon = NULL;
pDynString newVal = NULL;
char error[1024];
int status;
command = (char *)userData;
pCon = (SConnection *)callData;
assert(command != NULL && pCon != NULL);
/*
* evaluate
*/
status = Tcl_Eval(InterpGetTcl(pServ->pSics),command);
if(status != TCL_OK){
snprintf(error,1023,"ERROR: Tcl returned error: %s",
Tcl_GetStringResult(InterpGetTcl(pServ->pSics)));
SCWrite(pCon,error,eError);
status = 0;
} else {
status = 1;
}
/*
* decode result. This handles both the case of the standard SICS answer
* something = anything
* as well as a plain value alone
*/
data = Tcl_GetStringResult(InterpGetTcl(pServ->pSics));
if(data == NULL){
SCWrite(pCon,"ERROR: no result returned from script",eError);
return 0;
}
equal = strchr(data,'=');
if(equal != NULL){
data = equal + 1;
}
strcpy(error,"ERROR: ");
status = readHdbValue(&node->value,data, error+7, 1024-7);
if(status != 1){
SCWrite(pCon,error,eError);
return 0;
}
return status;
}
/*----------------------------------------------------------------------------*/
static pHdbCallback MakeSICSReadScriptCallback(char *script){
return MakeHipadabaCallback(SICSScriptReadCallback, strdup(script),
free,-1,-1);
}
/*---------------------------------------------------------------------------*/
typedef struct {
int min;
int max;
}hdbIntRange, *pHdbIntRange;
/*---------------------------------------------------------------------------*/
static int SICSIntRangeCallback(void *userData, void *callData, pHdb node,
hdbValue v){
char buffer[256];
pHdbIntRange range = NULL;
SConnection *pCon = NULL;
int status = 1;
range = (pHdbIntRange)userData;
pCon = (SConnection *)callData;
assert(range != NULL);
if(v.v.intValue > range->max || v.v.intValue < range->min) {
status = SICSCBRANGE;
if(pCon != NULL){
snprintf(buffer,255,"ERROR: %d is not within permitted range: %d to %d",
(int)v.v.intValue, range->min, range->max);
SCWrite(pCon,buffer,eError);
}
}
return status;
}
/*---------------------------------------------------------------------------*/
pHdbCallback MakeIntRangeCallback(int min, int max){
pHdbIntRange range = NULL;
range = malloc(sizeof(hdbIntRange));
if(range == NULL){
return NULL;
}
range->min = min;
range->max = max;
return MakeHipadabaCallback(SICSIntRangeCallback, range,
free,-1,-1);
}
/*---------------------------------------------------------------------------*/
typedef struct {
double min;
double max;
}hdbFloatRange, *pHdbFloatRange;
/*---------------------------------------------------------------------------*/
static int SICSFloatRangeCallback(void *userData, void *callData, pHdb node,
hdbValue v){
char buffer[256];
pHdbFloatRange range = NULL;
SConnection *pCon = NULL;
int status = 1;
range = (pHdbFloatRange)userData;
pCon = (SConnection *)callData;
assert(range != NULL);
if(v.v.doubleValue > range->max || v.v.doubleValue < range->min) {
status = SICSCBRANGE;
if(pCon != NULL){
snprintf(buffer,255,"ERROR: %lf is not within permitted range: %lf to %lf",
v.v.doubleValue, range->min, range->max);
SCWrite(pCon,buffer,eError);
}
}
return status;
}
/*---------------------------------------------------------------------------*/
pHdbCallback MakeFloatRangeCallback(double min, double max){
pHdbFloatRange range = NULL;
range = malloc(sizeof(hdbFloatRange));
if(range == NULL){
return NULL;
}
range->min = min;
range->max = max;
return MakeHipadabaCallback(SICSFloatRangeCallback, range,
free,-1,-1);
}
/*-------------------------------------------------------------------------*/
static int MemReadCallback(void *userData, void *callData, pHdb node,
hdbValue v){
float *value = NULL;
value = (float *)userData;
if(value != NULL){
v.dataType = HIPFLOAT;
v.v.doubleValue = (float) *value;
node->value.v.doubleValue = (double)*value;
}
return 1;
}
/*------------------------------------------------------------------------*/
static int MemGenReadCallback(void *userData, void *callData, pHdb node,
hdbValue v){
switch(node->value.dataType){
case HIPINT:
node->value.v.intValue = *(int *)userData;
break;
case HIPFLOAT:
node->value.v.doubleValue = *(double *)userData;
break;
case HIPTEXT:
if(node->value.v.text != NULL){
free(node->value.v.text);
}
node->value.v.text = strdup((char *)userData);
break;
case HIPINTAR:
memcpy(&node->value.v.intArray,userData,
node->value.arrayLength *sizeof(int));
break;
case HIPFLOATAR:
memcpy(&node->value.v.floatArray,userData,
node->value.arrayLength *sizeof(double));
break;
default:
assert(0);
break;
}
return 1;
}
/*-------------------------------------------------------------------------*/
pHdbCallback MakeMemGenReadCallback(void *address){
return MakeHipadabaCallback(MemReadCallback, address,
NULL,-1,-1);
}
/*-------------------------------------------------------------------------*/
pHdbCallback MakeMemReadCallback(float *address){
return MakeHipadabaCallback(MemReadCallback, address,
NULL,-1,-1);
}
/*-------------------------------------------------------------------------*/
static int MemSetCallback(void *userData, void *callData, pHdb node,
hdbValue v){
float *value = NULL;
value = (float *)userData;
if(value != NULL){
*value = (float)v.v.doubleValue;
}
UpdateHipadabaPar(node,v,callData);
return 1;
}
/*-------------------------------------------------------------------------*/
static int MemGenSetCallback(void *userData, void *callData, pHdb node,
hdbValue v){
const char *pPtr = NULL;
if(v.dataType != node->value.dataType){
assert(0);
return 0;
}
switch(node->value.dataType){
case HIPINT:
memcpy(userData,&v.v.intValue,sizeof(int));
break;
case HIPFLOAT:
memcpy(userData,&v.v.doubleValue,sizeof(double));
break;
case HIPTEXT:
strncpy((char *)userData,(const char *)v.v.text,
node->value.arrayLength);
break;
case HIPINTAR:
memcpy(userData,&v.v.intArray,node->value.arrayLength*sizeof(int));
break;
case HIPFLOATAR:
memcpy(userData,&v.v.floatArray,
node->value.arrayLength*sizeof(double));
break;
default:
assert(0);
return 0;
break;
}
UpdateHipadabaPar(node,v,callData);
return 1;
}
/*-------------------------------------------------------------------------*/
pHdbCallback MakeMemSetCallback(float *address){
return MakeHipadabaCallback(MemSetCallback, address,
NULL,-1,-1);
}
/*-------------------------------------------------------------------------*/
pHdbCallback MakeMemGenSetCallback(void *address){
return MakeHipadabaCallback(MemSetCallback, address,
NULL,-1,-1);
}
/*--------------------------------------------------------------------------*/
static void killHdbValue(void *pData){
hdbValue *v = NULL;
v = (hdbValue *)pData;
if(v == NULL){
return;
}
ReleaseHdbValue(v);
free(v);
}
/*--------------------------------------------------------------------------*/
static int SICSIntFixedCallback(void *userData, void *callData, pHdb node,
hdbValue v){
hdbValue *allowed = NULL;
SConnection *pCon = NULL;
int i;
allowed = (hdbValue *)userData;
pCon = (SConnection *)callData;
assert(allowed != NULL && allowed->dataType == HIPINTAR);
for(i = 0; i < allowed->arrayLength; i++){
if(v.v.intValue == allowed->v.intArray[i]){
return 1;
}
}
if(pCon != NULL){
SCWrite(pCon,"ERROR: value is not in the list of allowed values",eError);
}
return SICSCBBADFIXED;
}
/*---------------------------------------------------------------------------*/
pHdbCallback MakeIntFixedCallback(int *data, int length){
pHdbCallback result = NULL;
hdbValue *v = NULL;
v = malloc(sizeof(hdbValue));
if(v == NULL){
return NULL;
}
v->dataType = HIPINTAR;
v->arrayLength = length;
v->v.intArray = malloc(length*sizeof(int));
if(v->v.intArray == NULL){
return NULL;
}
memcpy(v->v.intArray,data,length*sizeof(int));
return MakeHipadabaCallback(SICSIntFixedCallback, v,
killHdbValue,-1,-1);
}
/*============= Parameter Creation ===========================================*/
pHdb MakeSICSHdbPar(char *name, int priv, hdbValue v){
pHdb result = NULL;
pHdbCallback pHcb = NULL;
result = MakeHipadabaNode(name,v.dataType,v.arrayLength);
if(result == NULL){
return NULL;
}
copyHdbValue(&v,&result->value);
pHcb = MakeCheckPermissionCallback(priv);
if(pHcb == NULL){
DeleteHipadabaNode(result,NULL);
return NULL;
}
AppendHipadabaCallback(result,HCBSET,pHcb);
pHcb = MakeSetUpdateCallback();
if(pHcb == NULL){
DeleteHipadabaNode(result,NULL);
return NULL;
}
AppendHipadabaCallback(result,HCBSET,pHcb);
return result;
}
/*---------------------------------------------------------------------------*/
pHdb CreateSICSHdbPar(char *name, int priv, int dataType,
int length, void *data){
return MakeSICSHdbPar(name,priv,makeHdbData(dataType,
length,data));
}
/*----------------------------------------------------------------------------*/
pHdb MakeSICSHdbDriv(char *name, int priv, void *sicsObject, int dataType){
pHdb result = NULL;
pHdbCallback pHcb = NULL;
result = MakeHipadabaNode(name,dataType,0);
if(result == NULL){
return NULL;
}
pHcb = MakeCheckPermissionCallback(priv);
if(pHcb == NULL){
DeleteHipadabaNode(result,NULL);
return NULL;
}
AppendHipadabaCallback(result,HCBSET,pHcb);
pHcb = MakeSICSDriveCallback(sicsObject);
if(pHcb == NULL){
DeleteHipadabaNode(result,NULL);
return NULL;
}
AppendHipadabaCallback(result,HCBSET,pHcb);
pHcb = MakeSICSReadDriveCallback(sicsObject);
if(pHcb == NULL){
DeleteHipadabaNode(result,NULL);
return NULL;
}
AppendHipadabaCallback(result,HCBREAD,pHcb);
return result;
}
/*---------------------------------------------------------------------------*/
pHdb MakeSICSMemPar(char *name, int priv, float *address){
pHdb result = NULL;
pHdbCallback pHcb = NULL;
result = MakeHipadabaNode(name,HIPFLOAT,1);
if(result == NULL){
return NULL;
}
pHcb = MakeCheckPermissionCallback(priv);
if(pHcb == NULL){
DeleteHipadabaNode(result,NULL);
return NULL;
}
AppendHipadabaCallback(result,HCBSET,pHcb);
pHcb = MakeMemSetCallback(address);
if(pHcb == NULL){
DeleteHipadabaNode(result,NULL);
return NULL;
}
AppendHipadabaCallback(result,HCBSET,pHcb);
pHcb = MakeMemReadCallback(address);
if(pHcb == NULL){
DeleteHipadabaNode(result,NULL);
return NULL;
}
AppendHipadabaCallback(result,HCBREAD,pHcb);
return result;
}
/*----------------------------------------------------------------------------*/
pHdb MakeSICSROPar(char *name, hdbValue v){
pHdb result = NULL;
pHdbCallback pHcb = NULL;
result = MakeHipadabaNode(name,v.dataType,v.arrayLength);
if(result == NULL){
return NULL;
}
copyHdbValue(&v,&result->value);
pHcb = MakeReadOnlyCallback();
if(pHcb == NULL){
DeleteHipadabaNode(result,NULL);
return NULL;
}
AppendHipadabaCallback(result,HCBSET,pHcb);
return result;
}
/*---------------------------------------------------------------------------*/
pHdb MakeSICSScriptPar(char *name, char *setScript, char *readScript,
hdbValue v){
pHdb result = NULL;
pHdbCallback pHcb = NULL;
result = MakeHipadabaNode(name,v.dataType,v.arrayLength);
if(result == NULL){
return NULL;
}
copyHdbValue(&v,&result->value);
pHcb = MakeSICSWriteScriptCallback(setScript);
if(pHcb == NULL){
DeleteHipadabaNode(result,NULL);
return NULL;
}
AppendHipadabaCallback(result,HCBSET,pHcb);
pHcb = MakeSICSReadScriptCallback(readScript);
if(pHcb == NULL){
DeleteHipadabaNode(result,NULL);
return NULL;
}
AppendHipadabaCallback(result,HCBREAD,pHcb);
/**
* put into the list of nodes to check with the update task
*/
/* LLDnodeAppend(scriptUpdate,&result); */
return result;
}
/*-------------------------------------------------------------------------*/
pHdb CreateSICSScriptPar(char *name, char *setScript, char *readScript,
int dataType, int length, void *data){
return MakeSICSScriptPar(name,setScript,readScript,
makeHdbData(dataType, length,data));
}
/*--------------------------------------------------------------------------*/
static void removeNodeFromUpdateList(pHdb node){
pHdb current = NULL;
int status;
char *objName = NULL;
objName = GetHipadabaPath(node);
if(objName != NULL){
removePollObject(poller, objName);
free(objName);
}
}
/*-----------------------------------------------------------------------*/
static void SICSDeleteNodeData(pHdb node){
pHdb tmp = NULL;
if(node == NULL){
return;
}
removeNodeFromUpdateList(node);
while(node->child != NULL){
tmp = node->child;
node->child = node->child->next;
SICSDeleteNodeData(tmp);
}
if(node->properties != NULL){
DeleteStringDict(node->properties);
}
DeleteCallbackChain(node->writeCallbacks);
DeleteCallbackChain(node->updateCallbacks);
DeleteCallbackChain(node->readCallbacks);
if(node->name != NULL){
free(node->name);
}
ReleaseHdbValue(&node->value);
node->magic = 000000;
free(node);
}
/*--------------------------------------------------------------------------*/
void RemoveSICSPar(pHdb node, void *callData){
pHdb current = NULL, tmp = NULL;
if(node == NULL){
return;
}
RemoveHdbNodeFromParent(node,NULL);
SICSDeleteNodeData(node);
}
/*===================== add functions =======================================*/
int AddSICSHdbPar(pHdb node, char *name, int priv, hdbValue v){
pHdb child = NULL;
child = MakeSICSHdbPar(name,priv,v);
if(child == NULL){
return 0;
}
AddHipadabaChild(node,child,NULL);
return 1;
}
/*---------------------------------------------------------------------------*/
int AddSICSHdbROPar(pHdb node, char *name, hdbValue v){
pHdb child = NULL;
child = MakeSICSROPar(name,v);
if(child == NULL){
return 0;
}
AddHipadabaChild(node,child,NULL);
return 1;
}
/*--------------------------------------------------------------------------*/
int AddSICSHdbMemPar(pHdb node, char *name, int priv,
void *data, int datalength, int type, int length){
pHdb child = NULL;
pHdbCallback pHcb = NULL;
if(type == HIPINTVARAR || type == HIPFLOATVARAR){
assert(0);
return 0;
}
child = MakeHipadabaNode(name,type,length);
if(child == NULL){
return 0;
}
pHcb = MakeCheckPermissionCallback(priv);
if(pHcb == NULL){
DeleteHipadabaNode(child,NULL);
return 0;
}
AppendHipadabaCallback(child,HCBSET,pHcb);
pHcb = MakeMemGenSetCallback(data);
if(pHcb == NULL){
DeleteHipadabaNode(child,NULL);
return 0;
}
AppendHipadabaCallback(child,HCBSET,pHcb);
pHcb = MakeMemGenReadCallback(data);
if(pHcb == NULL){
DeleteHipadabaNode(child,NULL);
return 0;
}
AppendHipadabaCallback(child,HCBREAD,pHcb);
AddHipadabaChild(node,child,NULL);
return 1;
}
/*==================== access suport functions ==============================*/
int SICSHdbGetPar(void *obj, SConnection *pCon,
char *path, int dataType, void *data, int length){
pHdb par = NULL;
int status;
char buffer[256];
pDummy pDum;
pDum = (pDummy)obj;
if(pDum == NULL || pDum->pDescriptor->parNode == NULL){
if(pCon != NULL){
snprintf(buffer,255,"ERROR: parameter %s not found", path);
SCWrite(pCon,buffer,eError);
}
return SICSNOPAR;
}
par = GetHipadabaNode(pDum->pDescriptor->parNode,path);
if(par == NULL){
if(pCon != NULL){
snprintf(buffer,255,"ERROR: parameter %s not found", path);
SCWrite(pCon,buffer,eError);
}
return SICSNOPAR;
}
status = GetHdbPar(par,dataType,data,length,pCon);
if(status < 0){
return status;
}
return 1;
}
/*--------------------------------------------------------------------------*/
int SICSHdbUpdatePar(void *obj, SConnection *pCon,
char *path, int dataType,void *data, int dataLength ){
hdbValue v;
pHdb par = NULL;
int status;
char buffer[256];
pDummy pDum;
pDum = (pDummy)obj;
if(pDum == NULL || pDum->pDescriptor->parNode == NULL){
if(pCon != NULL){
snprintf(buffer,255,"ERROR: parameter %s not found", path);
SCWrite(pCon,buffer,eError);
}
return SICSNOPAR;
}
par = GetHipadabaNode(pDum->pDescriptor->parNode,path);
if(par == NULL){
if(pCon != NULL){
snprintf(buffer,255,"ERROR: parameter %s not found", path);
SCWrite(pCon,buffer,eError);
}
return SICSNOPAR;
}
status = UpdateHdbPar(par,dataType,data,dataLength,pCon);
if(status < 0){
return status;
}
return 1;
}
/*--------------------------------------------------------------------------*/
int SICSHdbSetPar(void *obj, SConnection *pCon,
char *path, int dataType,void *data, int dataLength ){
hdbValue v;
pHdb par = NULL;
int status;
char buffer[256];
pDummy pDum;
pDum = (pDummy)obj;
if(pDum == NULL || pDum->pDescriptor->parNode == NULL){
if(pCon != NULL){
snprintf(buffer,255,"ERROR: parameter %s not found", path);
SCWrite(pCon,buffer,eError);
}
return SICSNOPAR;
}
par = GetHipadabaNode(pDum->pDescriptor->parNode,path);
if(par == NULL){
if(pCon != NULL){
snprintf(buffer,255,"ERROR: parameter %s not found", path);
SCWrite(pCon,buffer,eError);
}
return SICSNOPAR;
}
status = SetHdbPar(par,dataType,data,dataLength,pCon);
if(status < 0){
return status;
}
return 1;
}
/*---------------------------------------------------------------------------*/
int InstallSICSNotify(pHdb node, SConnection *pCon, int id, int recurse){
pHdb currentChild = NULL;
pHdbCallback noty = NULL;
pHdbCallback treeChange = NULL;
treeChange = MakeTreeChangeCallback(pCon,id);
noty = MakeNotifyCallback(pCon,id);
if(noty == NULL || treeChange == NULL){
SCWrite(pCon,"ERROR: out of memory installing callback", eError);
return 0;
}
AppendHipadabaCallback(node, HCBUPDATE, noty);
AppendHipadabaCallback(node, HCBTREE, treeChange);
if(recurse == 1){
currentChild = node->child;
while(currentChild != NULL){
InstallSICSNotify(currentChild,pCon,id,recurse);
currentChild = currentChild->next;
}
}
return 1;
}
/*---------------------------------------------------------------------------*/
int ProcessSICSHdbPar(pHdb root, SConnection *pCon,
char *printPrefix, int argc, char *argv[]){
hdbValue input;
pHdb parNode = NULL;
pDynString parData = NULL;
char error[512];
int i, status;
assert(root != NULL && pCon != NULL);
if(argc < 1){
SCWrite(pCon,"ERROR: no parameter to treat specified",eError);
return -1;
}
parNode = GetHipadabaNode(root,argv[0]);
if(parNode == NULL){
/* no error reporting here, upper level code might wish to continue
* processing commands after having tested for parameters.
*/
return -1;
}
if(argc > 1) {
/*
* setting the value is attempted.
*/
memset(&input,0,sizeof(hdbValue));
input.dataType = parNode->value.dataType;
copyHdbValue(&parNode->value,&input);
parData = CreateDynString(64,64);
if(parData == NULL){
SCWrite(pCon,"ERROR: out of memory processing parameter",eError);
return 0;
}
for(i = 1; i < argc; i++){
DynStringConcat(parData," ");
DynStringConcat(parData, argv[i]);
}
strcpy(error,"ERROR: ");
if(!readHdbValue(&input, GetCharArray(parData),
error+7,512-7)){
SCWrite(pCon,error, eError);
return 0;
}
DeleteDynString(parData);
status = SetHipadabaPar(parNode,input,pCon);
ReleaseHdbValue(&input);
if(status == 1){
SCSendOK(pCon);
SCparChange(pCon);
}
return status;
} else {
/*
* reading is in demand
*/
status = GetHipadabaPar(parNode,&input, pCon);
if(status != 1){
return 0;
}
parData = formatValue(input);
if(parData == NULL){
SCWrite(pCon,"ERROR: out of memory reading parameter data",eError);
return 0;
}
DynStringInsert(parData," =", 0);
DynStringInsert(parData,argv[0],0);
if(printPrefix != NULL){
DynStringInsert(parData,printPrefix,0);
}
SCWrite(pCon,GetCharArray(parData),eValue);
DeleteDynString(parData);
ReleaseHdbValue(&input);
return 1;
}
}
/*--------------------------------------------------------------------------*/
void PrintSICSParList(pHdb node, SConnection *pCon, char *prefix){
char childPrefix[1024];
pHdb child = NULL;
pDynString value = NULL;
hdbValue v;
child = node->child;
while(child != NULL){
if(child->value.dataType != HIPNONE){
GetHipadabaPar(child,&v,pCon);
value = formatValue(child->value);
if(value != NULL){
SCPrintf(pCon,eValue,"%s%s = %s", prefix, child->name,
GetCharArray(value));
DeleteDynString(value);
}
}
if(child->child != NULL){
strncpy(childPrefix,prefix,1024);
strncat(childPrefix,child->name, 1024);
strncat(childPrefix,"/",1024);
PrintSICSParList(child, pCon,prefix);
}
child = child->next;
}
}
/*---------------------------------------------------------------------------*/
void SaveSICSHipadaba(FILE *fd, pHdb node, char *prefix){
pHdb currentChild = NULL;
pDynString data = NULL;
hdbValue v;
currentChild = node->child;
while(currentChild != NULL){
if(currentChild->value.dataType != HIPNONE && !isSICSHdbRO(currentChild)){
GetHipadabaPar(currentChild,&v,NULL);
data = formatValue(currentChild->value);
if(data != NULL){
fprintf(fd,"%s%s %s\n", prefix, currentChild->name, GetCharArray(data));
DeleteDynString(data);
}
}
if(currentChild->child != NULL){
/*
* build a new prefix string and recurse
*/
data = CreateDynString(64,64);
if(data != NULL){
DynStringCopy(data,prefix);
DynStringConcat(data,currentChild->name);
DynStringConcat(data,"/");
SaveSICSHipadaba(fd,currentChild,GetCharArray(data));
DeleteDynString(data);
}
}
currentChild = currentChild->next;
}
}
/*================ value helpers ============================================*/
pDynString formatValue(hdbValue v){
pDynString result = NULL;
int i;
char number[30];
result = CreateDynString(64,64);
if(result == NULL){
return NULL;
}
switch(v.dataType){
case HIPNONE:
break;
case HIPINT:
snprintf(number,30,"%d", v.v.intValue);
DynStringCopy(result,number);
break;
case HIPFLOAT:
snprintf(number,30,"%12.4f", v.v.doubleValue);
DynStringCopy(result,number);
break;
case HIPTEXT:
DynStringCopy(result,v.v.text);
break;
case HIPINTAR:
case HIPINTVARAR:
for(i = 0; i < v.arrayLength; i++){
snprintf(number,30," %d", v.v.intArray[i]);
DynStringConcat(result,number);
}
break;
case HIPFLOATAR:
case HIPFLOATVARAR:
for(i = 0; i < v.arrayLength; i++){
snprintf(number,30," %12.4f", v.v.floatArray[i]);
DynStringConcat(result,number);
}
break;
}
return result;
}
/*-------------------------------------------------------------------*/
static char *getNextHdbNumber(char *pStart, char pNumber[80]){
int charCount = 0;
pNumber[0] = '\0';
/* advance to first digit */
while(isspace(*pStart) && *pStart != '\0'){
pStart++;
}
if(*pStart == '\0'){
return NULL;
}
/* copy */
while(!isspace(*pStart) && *pStart != '\0' && charCount < 78){
pNumber[charCount] = *pStart;
pStart++;
charCount++;
}
pNumber[charCount] = '\0';
return pStart;
}
/*---------------------------------------------------------------------------------*/
static int adjustDataLength(hdbValue *v, char *data){
char number[80];
int count = 0;
char *pPtr = NULL;
pPtr = data;
while((pPtr = getNextHdbNumber(pPtr,number)) != NULL){
count++;
}
if(count != v->arrayLength){
v->arrayLength = count;
if(v->dataType == HIPINTVARAR){
if(v->v.intArray != NULL){
free(v->v.intArray);
}
v->v.intArray = malloc(count*sizeof(int));
if(v->v.intArray == NULL){
return 0;
}
memset(v->v.intArray,0,count*sizeof(int));
}
if(v->dataType == HIPFLOATVARAR){
if(v->v.floatArray != NULL){
free(v->v.floatArray);
}
v->v.floatArray = malloc(count*sizeof(double));
if(v->v.floatArray == NULL){
return 0;
}
memset(v->v.floatArray,0,count*sizeof(double));
}
}
return 1;
}
/*---------------------------------------------------------------------------------*/
int readHdbValue(hdbValue *v, char *data, char *error, int errlen){
int i, status;
int lValue;
double dValue;
char number[80];
char *pPtr = NULL;
switch(v->dataType){
case HIPNONE:
break;
case HIPINT:
getNextHdbNumber(data,number);
status = sscanf(number,"%d", &v->v.intValue);
if(status != 1){
snprintf(error,errlen,"Failed to convert %s to integer",
data);
return 0;
}
break;
case HIPFLOAT:
getNextHdbNumber(data,number);
status = sscanf(number,"%lf", &v->v.doubleValue);
if(status != 1){
snprintf(error,errlen,"Failed to convert %s to double",
data);
return 0;
}
break;
case HIPTEXT:
if(v->v.text != NULL){
free(v->v.text);
}
v->v.text = strdup(data);
break;
case HIPINTVARAR:
if(!adjustDataLength(v,data)){
snprintf(error,errlen,"Out of memory allocating variable length data");
return 0;
}
case HIPINTAR:
for(i = 0; i < v->arrayLength; i++){
data = getNextHdbNumber(data,number);
if(data == NULL){
snprintf(error,errlen,"Not enough values to parse, current index %d",
i);
return 0;
}
status = sscanf(number,"%d", &lValue);
if(status != 1){
snprintf(error,errlen,"Failed to convert %s to integer",
data);
return 0;
}
v->v.intArray[i] = lValue;
}
break;
case HIPFLOATVARAR:
if(!adjustDataLength(v,data)){
snprintf(error,errlen,"Out of memory allocating variable length data");
return 0;
}
case HIPFLOATAR:
for(i = 0; i < v->arrayLength; i++){
data = getNextHdbNumber(data,number);
if(data == NULL){
snprintf(error,errlen,"Not enough values to parse, current index %d",
i);
return 0;
}
status = sscanf(number,"%lf", &dValue);
if(status != 1){
snprintf(error,errlen,"Failed to convert %s to double",
data);
return 0;
}
v->v.floatArray[i] = dValue;
}
break;
default:
assert(0);
break;
}
return 1;
}
/*================ interpreter interface ==================================*/
pHdb GetHipadabaRoot(){
return root;
}
/*-------------------------------------------------------------------------*/
static char *hdbTypes[] = {"none",
"int",
"float",
"text",
"intar",
"floatar",
"intvarar",
"floatvarar",
NULL};
/*-------------------------------------------------------------------------*/
static int convertHdbType(char *text){
int type;
type = 0;
while(hdbTypes[type] != NULL){
if(strcmp(hdbTypes[type], text) == 0){
break;
}
type++;
}
type--; /* we start counting at -1 */
return type;
}
/*-------------------------------------------------------------------------*/
static char *hdbTypeToText(int type){
return hdbTypes[type+1];
}
/*--------------------------------------------------------------------------*/
static int MakeHdbNode(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]){
int type = 0, i, length = 0, priv = -1;
char *pPtr = NULL;
pHdb parent = NULL;
pHdb child = NULL;
char buffer[512], buffer2[512];
if(!SCMatchRights(pCon,usMugger)){
return 0;
}
if(argc < 4) {
SCWrite(pCon,"ERROR: not enough arguments to MakeHdbNode",eError);
return 0;
}
/*
* convert privilege
*/
priv = decodeSICSPriv(argv[2]);
/*
* convert datatype
*/
strtolower(argv[3]);
type = convertHdbType(argv[3]);
if(type >= 7){
SCWrite(pCon,
"ERROR: invalid type requested: none, int, float, text, intar, floatar, intvarar, floatvarar supported",
eError);
return 0;
}
if(type > 2){
if( argc < 5){
SCWrite(pCon,"ERROR: array length missing for array data type",
eError);
return 0;
} else {
length = atoi(argv[3]);
}
}
/* split off last path element */
strncpy(buffer,argv[1],511);
pPtr = strrchr(buffer,'/');
if(pPtr == NULL){
SCWrite(pCon,"ERROR: invalid path specification",
eError);
return 0;
}
*pPtr = '\0';
pPtr++;
if(strlen(pPtr) < 1) {
parent = root;
} else {
parent = GetHipadabaNode(root,buffer);
}
if(parent == NULL){
snprintf(buffer2,512,"ERROR: parent %s for new node does not exist",
buffer);
SCWrite(pCon,buffer2,eError);
return 0;
}
if(type != HIPNONE){
child = MakeSICSHdbPar(pPtr, priv, makeHdbValue(type,length));
} else {
child = MakeHipadabaNode(pPtr,type,length);
}
if(child == NULL){
SCWrite(pCon,"ERROR: out of memory creating node",eError);
return 0;
}
AddHipadabaChild(parent,child,pCon);
SCSendOK(pCon);
return 1;
}
/*--------------------------------------------------------------------------*/
static int MakeHdbScriptNode(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]){
int type = 0, i, length = 0;
char *pPtr = NULL;
pHdb parent = NULL;
pHdb child = NULL;
pHdb current = NULL;
char *urgv[] = {"5", NULL};
char driver[] = {"hdb"};
char buffer[512], buffer2[512];
if(!SCMatchRights(pCon,usMugger)){
return 0;
}
if(argc < 5) {
SCWrite(pCon,"ERROR: not enough arguments to MakeHdbNode",eError);
return 0;
}
/*
* convert datatype
*/
strtolower(argv[4]);
type = convertHdbType(argv[4]);
if(type >= 7){
SCWrite(pCon,
"ERROR: invalid type requested: none, int, float, text, intar, floatar, intvarar, floatvarar supported",
eError);
return 0;
}
if(type > 2){
if( argc < 6){
SCWrite(pCon,"ERROR: array length missing for array data type",
eError);
return 0;
} else {
length = atoi(argv[5]);
}
}
/* split off last path element */
strncpy(buffer,argv[1],511);
pPtr = strrchr(buffer,'/');
if(pPtr == NULL){
SCWrite(pCon,"ERROR: invalid path specification",
eError);
return 0;
}
*pPtr = '\0';
pPtr++;
if(strlen(pPtr) < 1) {
parent = root;
} else {
parent = GetHipadabaNode(root,buffer);
}
if(parent == NULL){
snprintf(buffer2,512,"ERROR: parent %s for new node does not exist",
buffer);
SCWrite(pCon,buffer2,eError);
return 0;
}
child = MakeSICSScriptPar(pPtr, argv[3], argv[2],
makeHdbValue(type,length));
if(child == NULL){
SCWrite(pCon,"ERROR: out of memory creating node",eError);
return 0;
}
AddHipadabaChild(parent,child,pCon);
/*
* have it polled automatically
*/
addPollObject(poller,pCon, GetHipadabaPath(child),driver,1,urgv);
SCSendOK(pCon);
return 1;
}
/*------------------------------------------------------------------------------*/
static int isNodeProtected(pHdb node){
pHdb current = NULL;
if(node->protected == 1){
return 1;
}
current = node->child;
while(current != NULL){
if(isNodeProtected(current)){
return 1;
}
current = current->next;
}
return 0;
}
/*-----------------------------------------------------------------------------------------*/
static int DeleteHdbNode(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]){
pHdb killNode = NULL;
if(!SCMatchRights(pCon,usMugger)){
return 0;
}
if(argc < 2){
SCWrite(pCon,"ERROR: need path to node to delete",eError);
return 0;
}
killNode = GetHipadabaNode(root,argv[1]);
if(killNode == NULL){
SCWrite(pCon,"ERROR: node to delete not found",eError);
return 0;
}
if(isNodeProtected(killNode)){
SCWrite(pCon,"ERROR: this node or one of its children is protected",
eError);
return 0;
}
RemoveSICSPar(killNode, pCon);
SCSendOK(pCon);
return 1;
}
/*---------------------------------------------------------------------------*/
static pHdb locateSICSNode(SicsInterp *pSics, SConnection *pCon, char *path){
pHdb result = NULL;
char *pPtr = NULL, sicsObj[128], error[256];
pDummy pDum = NULL;
CommandList *pCom = NULL;
if(strstr(path,"/sics/") != NULL){
pPtr = stptok(path,sicsObj,128,"/");
pPtr = stptok(pPtr,sicsObj,128,"/");
pPtr = stptok(pPtr,sicsObj,128,"/");
strtolower(sicsObj);
pCom = FindCommand(pSics,sicsObj);
if(pCom == NULL) {
snprintf(error,255,"ERROR: object %s not found",sicsObj);
SCWrite(pCon,error,eError);
return NULL;
}
pDum = (pDummy)pCom->pData;
if(pDum == NULL){
snprintf(error,255,"ERROR: object %s has no data",sicsObj);
SCWrite(pCon,error,eError);
return NULL;
}
if(pDum->pDescriptor->parNode == NULL){
snprintf(error,255,"ERROR: object %s does not use Hipadaba",sicsObj);
SCWrite(pCon,error,eError);
return NULL;
}
result = GetHipadabaNode(pDum->pDescriptor->parNode,pPtr);
} else {
result = GetHipadabaNode(root,path);
}
if(result == NULL){
snprintf(error,255,"ERROR: node %s NOT found",path);
SCWrite(pCon,error,eError);
}
return result;
}
/*---------------------------------------------------------------------------*/
static int SetHdbNode(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]){
pHdb targetNode = NULL;
hdbValue newValue;
pDynString parData = NULL;
char error[512];
int i, status;
if(!SCMatchRights(pCon,usUser)){
return 0;
}
if(argc < 3) {
SCWrite(pCon,"ERROR: insufficient number of arguments to SetHdbNode",
eError);
return 0;
}
targetNode = locateSICSNode(pSics,pCon,argv[1]);
if(targetNode == NULL){
return 0;
}
if(!cloneHdbValue(&targetNode->value,&newValue)){
SCWrite(pCon,"ERROR: out of mmeory cloning node",
eError);
return 0;
}
parData = CreateDynString(64,64);
if(parData == NULL){
SCWrite(pCon,"ERROR: out of memory reading parameter",eError);
return 0;
}
for(i = 2; i < argc; i++){
DynStringConcat(parData," ");
DynStringConcat(parData, argv[i]);
}
strcpy(error,"ERROR: ");
if(!readHdbValue(&newValue, GetCharArray(parData),
error+7,512-7)){
SCWrite(pCon,error, eError);
return 0;
}
DeleteDynString(parData);
status = SetHipadabaPar(targetNode,newValue,pCon);
ReleaseHdbValue(&newValue);
if(status == 1){
SCSendOK(pCon);
}
return status;
}
/*---------------------------------------------------------------------------*/
static int UpdateHdbNode(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]){
pHdb targetNode = NULL;
hdbValue newValue;
pDynString parData = NULL;
char error[512];
int i, status;
if(!SCMatchRights(pCon,usUser)){
return 0;
}
if(argc < 2) {
SCWrite(pCon,"ERROR: insufficient number of arguments to UpdateHdbNode",
eError);
return 0;
}
targetNode = locateSICSNode(pSics,pCon,argv[1]);
if(targetNode == NULL){
return 0;
}
if(argc > 2){
if(!cloneHdbValue(&targetNode->value,&newValue)){
SCWrite(pCon,"ERROR: out of mmeory cloning node",
eError);
return 0;
}
parData = CreateDynString(64,64);
if(parData == NULL){
SCWrite(pCon,"ERROR: out of memory reading parameter",eError);
return 0;
}
for(i = 2; i < argc; i++){
DynStringConcat(parData," ");
DynStringConcat(parData, argv[i]);
}
strcpy(error,"ERROR: ");
if(!readHdbValue(&newValue, GetCharArray(parData),
error+7,512-7)){
SCWrite(pCon,error, eError);
return 0;
}
} else {
GetHipadabaPar(targetNode,&newValue,pCon);
}
status = UpdateHipadabaPar(targetNode,newValue,pCon);
ReleaseHdbValue(&newValue);
if(status == 1){
SCSendOK(pCon);
}
return status;
}
/*-----------------------------------------------------------------------------*/
static int GetHdbNode(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]){
pHdb targetNode = NULL;
hdbValue newValue;
pDynString parData = NULL;
char error[512], oriPath[512];;
int i, status;
int protocol = 0, outCode;
if(argc < 2) {
SCWrite(pCon,"ERROR: need path to node to print",eError);
return 0;
}
strncpy(oriPath,argv[1], 511);
targetNode = locateSICSNode(pSics,pCon,argv[1]);
if(targetNode == NULL){
return 0;
}
memset(&newValue,0,sizeof(hdbValue));
GetHipadabaPar(targetNode, &newValue, pCon);
parData = formatValue(newValue);
if(parData == NULL){
SCWrite(pCon,"ERROR: out of memory formatting data",eError);
return 0;
}
if ((protocol = isJSON(pCon)) == 1)
outCode = eHdbEvent;
else
outCode = eEvent;
formatNameValue(protocol, oriPath, NULL, parData);
SCWrite(pCon,GetCharArray(parData),outCode);
DeleteDynString(parData);
ReleaseHdbValue(&newValue);
return 1;
}
/*-----------------------------------------------------------------------------*/
static int ZipGetHdbNode(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]){
pHdb targetNode = NULL;
hdbValue newValue;
char error[512], oriPath[512];
int i, status;
int *iData = NULL;
if(argc < 2) {
SCWrite(pCon,"ERROR: need path to node",eError);
return 0;
}
strncpy(oriPath,argv[1], 511);
targetNode = locateSICSNode(pSics,pCon,argv[1]);
if(targetNode == NULL){
return 0;
}
memset(&newValue,0,sizeof(hdbValue));
GetHipadabaPar(targetNode, &newValue, pCon);
switch(newValue.dataType){
case HIPINTAR:
case HIPINTVARAR:
for(i = 0; i < newValue.arrayLength; i++){
newValue.v.intArray[i] = htonl(newValue.v.intArray[i]);
}
SCWriteZipped(pCon,oriPath, newValue.v.intArray,
newValue.arrayLength*sizeof(int));
break;
case HIPFLOATAR:
case HIPFLOATVARAR:
iData = (int *)malloc(newValue.arrayLength*sizeof(int));
if(iData == NULL){
SCWrite(pCon,"ERROR: out of memory in ZipGetHdbNode",eError);
return 0;
}
memset(iData,0,newValue.arrayLength*sizeof(int));
for(i = 0; i < newValue.arrayLength; i++){
iData[i] = htonl((int)newValue.v.floatArray[i]*65536.);
}
SCWriteZipped(pCon,oriPath, iData,
newValue.arrayLength*sizeof(int));
free(iData);
break;
default:
SCWrite(pCon,"ERROR: zipped writing not supported for this datatype",
eError);
return 0;
}
ReleaseHdbValue(&newValue);
return 1;
}
/*--------------------------------------------------------------------------*/
static int countChildren(pHdb node){
pHdb current = NULL;
int count = 0;
current = node->child;
while(current != NULL){
count++;
current = current->next;
}
return count;
}
/*---------------------------------------------------------------------------*/
static int HdbNodeInfo(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]){
pHdb targetNode = NULL;
char error[512], oriPath[512], info[512];
int i, status, length;
if(argc < 2) {
SCWrite(pCon,"ERROR: need path to node to get info",eError);
return 0;
}
strncpy(oriPath,argv[1], 511);
targetNode = locateSICSNode(pSics,pCon,argv[1]);
if(targetNode == NULL){
return 0;
}
length = targetNode->value.arrayLength;
if(length == 0){
length = 1;
}
snprintf(info,511,"%s,%d,%d",hdbTypeToText(targetNode->value.dataType),
countChildren(targetNode), length);
SCWrite(pCon,info,eValue);
return 1;
}
/*---------------------------------------------------------------------------*/
static int HdbNodeVal(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]){
pHdb targetNode = NULL;
hdbValue newValue;
pDynString parData = NULL;
char error[512];
int i, status;
if(argc < 2) {
SCWrite(pCon,"ERROR: need path to node to print",eError);
return 0;
}
targetNode = locateSICSNode(pSics,pCon,argv[1]);
if(targetNode == NULL){
return 0;
}
memset(&newValue,0,sizeof(hdbValue));
GetHipadabaPar(targetNode, &newValue, pCon);
parData = formatValue(newValue);
if(parData == NULL){
SCWrite(pCon,"ERROR: out of memory formatting data",eError);
return 0;
}
SCWrite(pCon,GetCharArray(parData),eHdbValue);
DeleteDynString(parData);
ReleaseHdbValue(&newValue);
return 1;
}
/*---------------------------------------------------------------------------*/
int isSICSHdbRO(pHdb node){
pHdbCallback current = NULL;
current = node->writeCallbacks;
while(current != NULL){
if(current->userCallback == SICSReadOnlyCallback) {
return 1;
}
current = current->next;
}
return 0;
}
/*---------------------------------------------------------------------------*/
static pDynString formatPlainList(pHdb node){
pHdb current;
pDynString result = NULL;
result = CreateDynString(128,128);
if(result == NULL){
return NULL;
}
current = node->child;
while(current != NULL){
DynStringConcat(result,current->name);
DynStringConcat(result,"\n");
current = current->next;
}
return result;
}
/*---------------------------------------------------------------------------*/
static pDynString formatJSONList(pHdb node){
pHdb current;
pDynString result = NULL;
pDynString data = NULL;
if (node->child == NULL) return NULL;
result = CreateDynString(128,128);
if(result == NULL){
return NULL;
}
if(node->child->value.dataType == HIPNONE)
DynStringCopy(result,"[");
else
DynStringCopy(result,"{");
current = node->child;
while(current != NULL){
DynStringConcat(result,"\"");
DynStringConcat(result,current->name);
DynStringConcat(result,"\"");
if(current->value.dataType != HIPNONE){
data = formatValue(current->value);
if(data != NULL){
DynStringConcat(result,": ");
DynStringConcat(result,GetCharArray(data));
DeleteDynString(data);
}
}
if (current->next != NULL) DynStringConcat(result,", ");
current = current->next;
}
if(node->child->value.dataType == HIPNONE)
DynStringConcat(result,"]");
else
DynStringConcat(result,"}");
return result;
}
/*---------------------------------------------------------------------------*/
static pDynString formatListWithVal(pHdb node){
pHdb current;
pDynString result = NULL;
pDynString data = NULL;
result = CreateDynString(128,128);
if(result == NULL){
return NULL;
}
current = node->child;
while(current != NULL){
if(current->value.dataType != HIPNONE){
DynStringConcat(result,current->name);
data = formatValue(current->value);
if(data != NULL){
DynStringConcat(result," = ");
DynStringConcat(result,GetCharArray(data));
DeleteDynString(data);
}
DynStringConcat(result,"\n");
}
current = current->next;
}
return result;
}
/*---------------------------------------------------------------------------*/
static pDynString formatClientList(pHdb node){
pHdb current;
pDynString result = NULL;
int length;
int i;
char number[50];
result = CreateDynString(128,128);
if(result == NULL){
return NULL;
}
current = node->child;
while(current != NULL){
DynStringConcat(result,current->name);
DynStringConcat(result,",");
DynStringConcat(result,hdbTypeToText(current->value.dataType));
DynStringConcat(result,",");
snprintf(number,50,"%d",countChildren(current));
DynStringConcat(result,number);
DynStringConcat(result,",");
if(current->value.dataType >= 3){
length = current->value.arrayLength;
} else {
length = 1;
}
snprintf(number,50,"%d",length);
DynStringConcat(result,number);
DynStringConcat(result,",");
switch(current->value.dataType){
case HIPNONE:
break;
case HIPINT:
snprintf(number,50,"%d",current->value.v.intValue);
DynStringConcat(result,number);
break;
case HIPFLOAT:
snprintf(number,50,"%lf",current->value.v.doubleValue);
DynStringConcat(result,number);
break;
case HIPTEXT:
DynStringConcat(result,current->value.v.text);
break;
case HIPINTAR:
case HIPINTVARAR:
for(i = 0; i < length; i++){
snprintf(number,50,"%d",current->value.v.intArray[i]);
DynStringConcat(result,number);
if(i > length -1){
DynStringConcat(result,",");
}
}
break;
case HIPFLOATAR:
case HIPFLOATVARAR:
for(i = 0; i < length; i++){
snprintf(number,50,"%lf",current->value.v.floatArray[i]);
DynStringConcat(result,number);
if(i > length -1){
DynStringConcat(result,",");
}
}
break;
}
DynStringConcat(result,"\n");
current = current->next;
}
return result;
}
/*---------------------------------------------------------------------------*/
static int ListHdbNode(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]){
pHdb node = NULL;
int pathArg = 1;
pDynString listData = NULL;
int protocol = 0, outCode;
if(argc < 2) {
SCWrite(pCon,"ERROR: need path to node to print",eError);
return 0;
}
if(strchr(argv[1],'-') != NULL){
pathArg = 2;
if(argc < 3){
SCWrite(pCon,"ERROR: need path to node to print",eError);
return 0;
}
}
node = locateSICSNode(pSics,pCon,argv[pathArg]);
if(node == NULL){
return 0;
}
if(pathArg == 2) {
strtolower(argv[1]);
}
if(strcmp(argv[1],"-val") == 0){
listData = formatListWithVal(node);
} else if(strcmp(argv[1],"-cli") == 0){
listData = formatClientList(node);
} else {
if ((protocol = isJSON(pCon)) == 1) {
listData = formatJSONList(node);
outCode = eHdbEvent;
} else {
listData = formatPlainList(node);
outCode = eEvent;
}
}
if(listData == NULL){
SCWrite(pCon,"ERROR: failed to format list",
eError);
return 0;
}
if( (strcmp(argv[1],"-val") == 0) || (strcmp(argv[1],"-cli") == 0) ){
SCWrite(pCon,GetCharArray(listData),eValue);
} else {
SCWrite(pCon,GetCharArray(listData),outCode);
}
DeleteDynString(listData);
return 1;
}
/*---------------------------------------------------------------------------*/
static int AutoNotifyHdbNode(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]){
pHdb node = NULL;
int id, status;
if(argc < 3) {
SCWrite(pCon,"ERROR: need path and id in order to add notify",
eError);
return 0;
}
node = locateSICSNode(pSics,pCon,argv[1]);
if(node == NULL){
return 0;
}
id = atoi(argv[2]);
status = InstallSICSNotify(node, pCon, id, 1);
if(status == 1){
SCSendOK(pCon);
}
return status;
}
/*---------------------------------------------------------------------------*/
static int RemoveHdbCallback(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]){
int id;
if(argc < 2) {
SCWrite(pCon,"ERROR: need callback id to remove",
eError);
return 0;
}
id = atoi(argv[1]);
RemoveHipadabaCallback(root,id);
SCSendOK(pCon);
return 1;
}
/*---------------------------------------------------------------------------*/
static int LinkHdbNode(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]){
pHdb node = NULL;
char buffer[256];
CommandList *pCom = NULL;
pDummy pDum = NULL;
if(argc < 3) {
SCWrite(pCon,"ERROR: need path and object name to link",
eError);
return 0;
}
if(!SCMatchRights(pCon,usMugger)){
return 0;
}
node = GetHipadabaNode(root,argv[1]);
if(node == NULL){
snprintf(buffer,255,"ERROR: path %s NOT found!", argv[1]);
SCWrite(pCon,buffer,eError);
return 0;
}
pCom = FindCommand(pSics,argv[2]);
if(pCom == NULL){
snprintf(buffer,255,"ERROR: failed to find object %s", argv[2]);
SCWrite(pCon,buffer,eError);
return 0;
}
pDum = pCom->pData;
if(pDum == NULL || pDum->pDescriptor->parNode == NULL){
snprintf(buffer,255,
"ERROR: Object %s does not use Hipadaba natively and thus cannot be linked",
argv[2]);
SCWrite(pCon,buffer,eError);
return 0;
}
if(pDum->pDescriptor->parNode->mama != NULL){
snprintf(buffer,255,
"ERROR: Object %s is already linked somewhere else",
argv[2]);
SCWrite(pCon,buffer,eError);
return 0;
}
AddHipadabaChild(node,pDum->pDescriptor->parNode,pCon);
if(argc > 3){
if(pDum->pDescriptor->parNode->name != NULL){
free(pDum->pDescriptor->parNode->name);
}
pDum->pDescriptor->parNode->name = strdup(argv[3]);
}
SCSendOK(pCon);
return 1;
}
/*-------------------------------------------------------------------------*/
static int ChainCallback(void *userData, void *callData, pHdb node,
hdbValue v){
pHdb slave = (pHdb)userData;
hdbValue vv, old;
if(slave != NULL){
old = slave->value;
memset(&vv,0,sizeof(hdbValue));
GetHipadabaPar(slave,&vv,callData);
if(!compareHdbValue(old,vv)){
UpdateHipadabaPar(slave, vv, callData);
}
}
return 1;
}
/*--------------------------------------------------------------------------*/
static int ChainHdbNode(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]){
pHdb master = NULL, slave = NULL;
char buffer[512];
pHdbCallback kalle = NULL;
if(argc < 3) {
SCWrite(pCon,"ERROR: insufficent number of arguments to hchain",
eError);
}
if(!SCMatchRights(pCon,usMugger)){
return 0;
}
slave = GetHipadabaNode(root,argv[1]);
if(slave == NULL){
snprintf(buffer,511,"ERROR: slave %s not found",argv[1]);
SCWrite(pCon,buffer,eError);
return 0;
}
master = GetHipadabaNode(root,argv[2]);
if(master == NULL){
snprintf(buffer,511,"ERROR: master %s not found",argv[1]);
SCWrite(pCon,buffer,eError);
return 0;
}
kalle = MakeHipadabaCallback(ChainCallback,slave, NULL, -1,-1);
if(kalle == NULL){
SCWrite(pCon,"ERROR: out of memory creating callback",eError);
return 0;
}
AppendHipadabaCallback(master,HCBUPDATE, kalle);
SCSendOK(pCon);
return 1;
}
/*---------------------------------------------------------------------------*/
static int CommandSetCallback(void *userData, void *callData, pHdb node,
hdbValue v){
SConnection *pCon = (SConnection *)callData;
pDynString cmd = NULL, par = NULL;
pHdb current = NULL;
int status;
if(pCon == NULL){
printf("Cannot invoke command without connection\n");
return 0;
}
if(v.dataType == HIPTEXT){
if(strstr(v.v.text,"start") != NULL) {
cmd = CreateDynString(64,64);
if(cmd == 0){
SCWrite(pCon,"ERROR: out of memory in CommandSetCallback",eError);
return 0;
}
DynStringCopy(cmd, node->value.v.text);
DynStringConcat(cmd," ");
current = node->child;
while(current != NULL){
par = formatValue(current->value);
if(par != NULL){
DynStringConcat(cmd, GetCharArray(par));
DynStringConcat(cmd," ");
DeleteDynString(par);
}
current = current->next;
}
status = SCInvoke(pCon, pServ->pSics,GetCharArray(cmd));
DeleteDynString(cmd);
return status;
} else {
SCWrite(pCon,"ERROR: this node only understands start as value",eError);
return 0;
}
}
return 0;
}
/*---------------------------------------------------------------------------*/
static int CommandGetCallback(void *userData, void *callData, pHdb node,
hdbValue v){
hdbValue v2 = MakeHdbText("Nothing to get");
v = v2;
return 1;
}
/*--------------------------------------------------------------------------*/
static int SicsCommandNode(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]){
char buffer[512], buffer2[512], *pPtr = NULL;
pHdbCallback kalle = NULL;
pHdb parent = NULL, node = NULL;
if(argc < 3) {
SCWrite(pCon,"ERROR: insufficent number of arguments to hcommand",
eError);
}
if(!SCMatchRights(pCon,usMugger)){
return 0;
}
/* split off last path element */
strncpy(buffer,argv[1],511);
pPtr = strrchr(buffer,'/');
if(pPtr == NULL){
SCWrite(pCon,"ERROR: invalid path specification",
eError);
return 0;
}
*pPtr = '\0';
pPtr++;
if(strlen(pPtr) < 1) {
parent = root;
} else {
parent = GetHipadabaNode(root,buffer);
}
if(parent == NULL){
snprintf(buffer2,512,"ERROR: parent %s for new node does not exist",
buffer);
SCWrite(pCon,buffer2,eError);
return 0;
}
node = MakeHipadabaNode(pPtr, HIPTEXT, 1);
if(node == NULL){
SCWrite(pCon,"ERROR: out of memory in hcommand",eError);
return 0;
}
node->value.v.text = strdup(argv[2]);
node->value.arrayLength = strlen(argv[2]);
kalle = MakeHipadabaCallback(CommandSetCallback,NULL, NULL, -1,-1);
if(kalle == NULL){
SCWrite(pCon,"ERROR: out of memory in hcommand",eError);
return 0;
}
AppendHipadabaCallback(node,HCBSET, kalle);
kalle = MakeHipadabaCallback(CommandGetCallback,NULL, NULL, -1,-1);
if(kalle == NULL){
SCWrite(pCon,"ERROR: out of memory in hcommand",eError);
return 0;
}
AppendHipadabaCallback(node,HCBREAD, kalle);
AddHipadabaChild(parent,node,pCon);
SCSendOK(pCon);
return 1;
}
/*======================= Property Functions ================================*/
static int SetSICSHdbProperty(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]){
pHdb targetNode = NULL;
char buffer[512];
if(argc < 4) {
SCWrite(pCon,"ERROR: need path key value as parameters",eError);
return 0;
}
targetNode = locateSICSNode(pSics,pCon,argv[1]);
if(targetNode == NULL){
SCWrite(pCon,"ERROR: node not found",eError);
return 0;
}
Arg2Text(argc-3, &argv[3], buffer,512);
SetHdbProperty(targetNode,argv[2], buffer);
SCSendOK(pCon);
return 1;
}
/*--------------------------------------------------------------------------*/
static int GetSICSHdbProperty(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]){
pHdb targetNode = NULL;
char buffer[512];
int status;
if(argc < 3) {
SCWrite(pCon,"ERROR: need path key as parameters",eError);
return 0;
}
targetNode = locateSICSNode(pSics,pCon,argv[1]);
if(targetNode == NULL){
SCWrite(pCon,"ERROR: node not found",eValue);
return 0;
}
status = GetHdbProperty(targetNode,argv[2],buffer,511);
if(status != 1){
SCWrite(pCon,"ERROR: attribute not found",eValue);
return 0;
}
SCPrintf(pCon,eValue,"%s.%s = %s", argv[1], argv[2], buffer);
return 1;
}
/*--------------------------------------------------------------------------*/
static int ListSICSHdbProperty(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]){
pHdb targetNode = NULL;
char buffer[512];
const char *pKey = NULL;
pDynString data = NULL;
if(argc < 2) {
SCWrite(pCon,"ERROR: need path as parameter",eError);
return 0;
}
targetNode = locateSICSNode(pSics,pCon,argv[1]);
if(targetNode == NULL){
SCWrite(pCon,"ERROR: node not found",eError);
return 0;
}
data = CreateDynString(64,64);
if(data == NULL){
SCWrite(pCon,"ERROR: out of memory in ListSICSHdbProperty",eError);
return 0;
}
InitHdbPropertySearch(targetNode);
while((pKey = GetNextHdbProperty(targetNode, buffer, 511)) != NULL){
DynStringConcat(data,(char *)pKey);
DynStringConcat(data,"=");
DynStringConcat(data,buffer);
DynStringConcat(data,"\n");
}
SCWrite(pCon,GetCharArray(data), eValue);
DeleteDynString(data);
return 1;
}
/*======================= Factory Functions =================================*/
void killSICSHipadaba(){
if(root != NULL){
DeleteHipadabaNode(root,NULL);
}
root = NULL;
}
/*---------------------------------------------------------------------------*/
int InstallSICSHipadaba(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]){
root = MakeHipadabaNode("/",HIPNONE,0);
AddCommand(pSics,"hmake", MakeHdbNode, NULL, NULL);
AddCommand(pSics,"hmakescript", MakeHdbScriptNode, NULL, NULL);
AddCommand(pSics,"hattach", SICSHdbAdapter, NULL, NULL);
AddCommand(pSics,"hdel", DeleteHdbNode, NULL, NULL);
AddCommand(pSics,"hset", SetHdbNode, NULL, NULL);
AddCommand(pSics,"hupdate", UpdateHdbNode, NULL, NULL);
AddCommand(pSics,"hget", GetHdbNode, NULL, NULL);
AddCommand(pSics,"hzipget",ZipGetHdbNode, NULL, NULL);
AddCommand(pSics,"hlist", ListHdbNode, NULL, NULL);
AddCommand(pSics,"hnotify", AutoNotifyHdbNode, NULL, NULL);
AddCommand(pSics,"hdelcb", RemoveHdbCallback, NULL, NULL);
AddCommand(pSics,"hlink", LinkHdbNode, NULL, NULL);
AddCommand(pSics,"hinfo", HdbNodeInfo, NULL, NULL);
AddCommand(pSics,"hval", HdbNodeVal, NULL, NULL);
AddCommand(pSics,"hchain", ChainHdbNode, NULL, NULL);
AddCommand(pSics,"hcommand",SicsCommandNode, NULL, NULL);
AddCommand(pSics,"hsetprop",SetSICSHdbProperty, NULL, NULL);
AddCommand(pSics,"hgetprop",GetSICSHdbProperty, NULL, NULL);
AddCommand(pSics,"hlistprop",ListSICSHdbProperty, NULL, NULL);
InstallSICSPoll(pCon,pSics,pData,argc,argv);
poller = (pSicsPoll)FindCommandData(pSics,"sicspoll","SicsPoll");
return 1;
}