/** * 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 #include #include #include #include #include #include "sicspoll.h" #include #include #include "protocol.h" #include /*== there can be only hipadaba in SICS, some globals to care for that == */ static pHdb root = NULL; static pSicsPoll poller = NULL; typedef enum { normal_protocol, json_protocol, } Protocol; typedef enum { linefeed, space, } RecSep; char *trim(char *str); /*=============== 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 Protocol isJSON(SConnection *pCon) { char proName[128]; void *pData; if(SCinMacro(pCon)){ return normal_protocol; } pData = FindCommandData(pServ->pSics, "protocol","Protocol"); ProtocolGet(pCon, pData, proName, 128); if (strcmp(proName, "json") == 0) return json_protocol; else return normal_protocol; } /* Format a name,value pair according to the given protocol */ int formatNameValue(Protocol protocol, char *name, char *value, pDynString result, int hdtype) { char *char_arr, *ptr; switch(protocol) { case normal_protocol: DynStringCopy(result,name); DynStringConcat(result," = "); DynStringConcat(result,value); break; case json_protocol: switch(hdtype){ case HIPNONE: break; case HIPINT: case HIPFLOAT: DynStringCopy(result,"{\""); DynStringConcat(result,name); DynStringConcat(result,"\": "); DynStringConcat(result,value); DynStringConcat(result,"}"); break; case HIPTEXT: DynStringCopy(result,"{\""); DynStringConcat(result,name); DynStringConcat(result,"\": \""); DynStringConcat(result,value); DynStringConcat(result,"\"}"); break; case HIPINTAR: case HIPINTVARAR: case HIPFLOATAR: case HIPFLOATVARAR: char_arr = ptr = strdup(trim(value)); while(*ptr != '\0') { if (isspace(*ptr)) *ptr=','; ptr++; } DynStringCopy(result,"{\""); DynStringConcat(result,name); DynStringConcat(result,"\": [ "); DynStringConcat(result,char_arr); DynStringConcat(result," ]}"); if (char_arr != NULL ) free(char_arr); break; } } return protocol; } /*----------------------------------------------------------------------------------------*/ static int SICSNotifyCallback(void *userData, void *callData, pHdb node, hdbValue v){ HdbCBInfo *cbInfo = NULL; pDynString printedData = NULL; pDynString result = NULL; char *pPath = NULL; Protocol protocol = normal_protocol; int 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, v.dataType); SCWriteInContext(cbInfo->pCon,GetCharArray(result), outCode,cbInfo->context); DeleteDynString(printedData); } else { formatNameValue(protocol, pPath,"!!datachange!!", result, HIPTEXT); 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; Protocol protocol = normal_protocol; int 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, v.dataType); 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 = (char *)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; char pPriv[20]; 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); switch(priv){ case 0: strcpy(pPriv,"internal"); break; case 1: strcpy(pPriv,"manager"); break; case 2: strcpy(pPriv,"user"); break; case 3: strcpy(pPriv,"spy"); break; } SetHdbProperty(result,"priv",pPriv); 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)){ 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, result = NULL; char error[512], oriPath[512];; int i, status; Protocol protocol = normal_protocol; int 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; result = CreateDynString(128,128); formatNameValue(protocol, oriPath, GetCharArray(parData), result, newValue.dataType); SCWrite(pCon,GetCharArray(result),outCode); DeleteDynString(parData); DeleteDynString(result); 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, RecSep recsep){ pHdb current; pDynString result = NULL; result = CreateDynString(128,128); if(result == NULL){ return NULL; } current = node->child; while(current != NULL){ DynStringConcat(result,current->name); switch (recsep) { case space: DynStringConcat(result," "); break; case linefeed: default: 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; Protocol protocol = normal_protocol; int 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(strcmp(argv[1],"-space") == 0){ listData = formatPlainList(node, space); } else if(strcmp(argv[1],"-linefeed") == 0){ listData = formatPlainList(node, linefeed); } else { if ((protocol = isJSON(pCon)) == 1) { listData = formatJSONList(node); outCode = eHdbEvent; } else { listData = formatPlainList(node, linefeed); 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; }