/** * 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 */ #include #include #include #include #include #include #include /*== there can be only hipadaba in SICS, some globals to care for that == */ static pHdb root = NULL; static int scriptUpdate = -1; static hdbUpdateTask taskData; enum formatStyle {plain, cli, json}; char *formatName[] = {"plain", "cli", "json"}; static enum formatStyle currFmtStyle=json; pDynString formatClientValue(char *name, hdbValue hVal, int children); pDynString formatJSONValue(char *name, hdbValue hVal, int children); /*=============== 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; } 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; } /*-------------------------------------------------------------------------------------*/ static 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){ SConnection *pCon = NULL; pDummy dum = NULL; pIDrivable pDriv = NULL; float value; pCon = (SConnection *)callData; dum = (pDummy)userData; assert(pCon != NULL && dum != NULL); 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; } return 1; } /*--------------------------------------------------------------------------------------*/ pHdbCallback MakeSICSReadDriveCallback(void *sicsObject){ return MakeHipadabaCallback(SICSReadDriveCallback, sicsObject,NULL,-1,-1); } /*---------------------------------------------------------------------------------------*/ typedef struct { SConnection *pCon; commandContext context; }HdbCBInfo; /*----------------------------------------------------------------------------------------*/ static int SICSNotifyCallback(void *userData, void *callData, pHdb node, hdbValue v){ HdbCBInfo *cbInfo = NULL; pDynString printedData = NULL; pDynString result = NULL; char *pPath = NULL; cbInfo = (HdbCBInfo *)userData; pPath = GetHipadabaPath(node); switch (currFmtStyle) { case cli: printedData = formatClientValue(pPath,v,0); break; case json: printedData = formatJSONValue(pPath,v,0); break; case plain: default: printedData = formatValue(v); } result = CreateDynString(128,128); if(pPath == NULL || printedData == NULL || result == NULL){ SCWriteInContext(cbInfo->pCon,"ERROR: out of memory formatting data" , eError,cbInfo->context); /* * no need to interrupt something because writing data to a client does * not work */ return 1; } switch (currFmtStyle) { case cli: DynStringConcat(result,GetCharArray(printedData)); break; case json: DynStringConcat(result,"{"); DynStringConcat(result,GetCharArray(printedData)); DynStringConcat(result,"}"); break; case plain: default: DynStringCopy(result,pPath); DynStringConcat(result," = "); DynStringConcat(result,GetCharArray(printedData)); } SCWriteInContext(cbInfo->pCon,GetCharArray(result), eHdb,cbInfo->context); free(pPath); DeleteDynString(result); DeleteDynString(printedData); 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 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 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(long *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(long)); if(v->v.intArray == NULL){ return NULL; } memcpy(v->v.intArray,data,length*sizeof(long)); 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); return NULL; } AppendHipadabaCallback(result,HCBSET,pHcb); pHcb = MakeSetUpdateCallback(); if(pHcb == NULL){ DeleteHipadabaNode(result); return NULL; } AppendHipadabaCallback(result,HCBSET,pHcb); return result; } /*----------------------------------------------------------------------------*/ 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); return NULL; } AppendHipadabaCallback(result,HCBSET,pHcb); pHcb = MakeSICSDriveCallback(sicsObject); if(pHcb == NULL){ DeleteHipadabaNode(result); return NULL; } AppendHipadabaCallback(result,HCBSET,pHcb); pHcb = MakeSICSReadDriveCallback(sicsObject); if(pHcb == NULL){ DeleteHipadabaNode(result); 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); 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); return NULL; } AppendHipadabaCallback(result,HCBSET,pHcb); pHcb = MakeSICSReadScriptCallback(readScript); if(pHcb == NULL){ DeleteHipadabaNode(result); return NULL; } AppendHipadabaCallback(result,HCBREAD,pHcb); /** * put into the list of nodes to check with the update task */ LLDnodeAppend(scriptUpdate,&result); return result; } /*--------------------------------------------------------------------------*/ static void removeNodeFromUpdateList(pHdb node){ pHdb current = NULL; int status; status = LLDnodePtr2First(scriptUpdate); while(status != 0){ current = LLDnodePtr(scriptUpdate); if(current == node){ LLDnodeDelete(scriptUpdate); return; } status = LLDnodePtr2Next(scriptUpdate); } } /*-----------------------------------------------------------------------*/ static void SICSDeleteNodeData(pHdb node){ pHdb tmp = NULL; if(node == NULL){ return; } DeleteCallbackChain(node->writeCallbacks); DeleteCallbackChain(node->updateCallbacks); DeleteCallbackChain(node->readCallbacks); if(node->name != NULL){ free(node->name); } ReleaseHdbValue(&node->value); node->magic = 000000; while(node->child != NULL){ tmp = node->child; node->child = node->child->next; SICSDeleteNodeData(tmp); } removeNodeFromUpdateList(node); free(node); } /*--------------------------------------------------------------------------*/ void RemoveSICSPar(pHdb node){ pHdb current = NULL, tmp = NULL; if(node == NULL){ return; } RemoveHdbNodeFromParent(node); SICSDeleteNodeData(node); } /*==================== access suport functions ==============================*/ int SICSHdbGetFloat(pHdb parent, SConnection *pCon, char *path, float *value){ hdbValue v; pHdb par = NULL; int status; char buffer[256]; par = GetHipadabaNode(parent,path); if(par == NULL){ if(pCon != NULL){ snprintf(buffer,255,"ERROR: parameter %s not found", path); SCWrite(pCon,buffer,eError); } return SICSNOPAR; } status = GetHipadabaPar(par,&v,pCon); if(status < 0){ return status; } if(v.dataType == HIPFLOAT){ *value = (float)v.v.doubleValue; } else if(v.dataType == HIPINT){ *value = (float)v.v.intValue; } else { /* * it is an error to call this for array dada types */ assert(0); } return 1; } /*--------------------------------------------------------------------------*/ int SICSHdbSetFloat(pHdb parent, SConnection *pCon, char *path, float value){ hdbValue v; pHdb par = NULL; int status; char buffer[256]; par = GetHipadabaNode(parent,path); if(par == NULL){ if(pCon != NULL){ snprintf(buffer,255,"ERROR: parameter %s not found", path); SCWrite(pCon,buffer,eError); } return SICSNOPAR; } v.dataType = par->value.dataType; if(v.dataType == HIPFLOAT){ v.v.doubleValue = (double)value; } else if(v.dataType == HIPINT){ v.v.intValue = (long)value; } else { /* * it is an error to call this for array dada types */ assert(0); } status = SetHipadabaPar(par,v,pCon); if(status < 0){ return status; } return 1; } /*---------------------------------------------------------------------------*/ int InstallSICSNotify(pHdb node, SConnection *pCon, int id, int recurse){ pHdb currentChild = NULL; pHdbCallback noty = NULL; noty = MakeNotifyCallback(pCon,id); if(noty == NULL){ SCWrite(pCon,"ERROR: out of memory installing callback", eError); return 0; } AppendHipadabaCallback(node, HCBUPDATE, noty); 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: nor 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); 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),eHdb); DeleteDynString(parData); ReleaseHdbValue(&input); return 1; } } /*---------------------------------------------------------------------------*/ int SICSHipadabaTask(void *pData){ pHdbUpdateTask self = NULL; hdbValue old, newValue; pHdb currentNode = NULL; int status; self = (pHdbUpdateTask)pData; assert(self != NULL); if(self->iEnd == 1){ return 0; } if(LLDcheck(self->updateList) == LIST_EMPTY){ return 1; } memset(&old,0,sizeof(hdbValue)); memset(&newValue,0,sizeof(hdbValue)); currentNode = (pHdb)LLDnodePtr(self->updateList); if(currentNode != NULL){ old.dataType = currentNode->value.dataType; copyHdbValue(¤tNode->value,&old); if(GetHipadabaPar(currentNode,&newValue, self->pCon) == 1){ if(!compareHdbValue(old,newValue)){ UpdateHipadabaPar(currentNode,newValue,self->pCon); } } ReleaseHdbValue(&old); ReleaseHdbValue(&newValue); } status = LLDnodePtr2Next(self->updateList); if(status == 0){ LLDnodePtr2First(self->updateList); } return 1; } /*---------------------------------------------------------------------------*/ void SICSHipadabaSignal(void *pData, int iSignal, void *pSigData){ pHdbUpdateTask self = NULL; int *iInt; self = (pHdbUpdateTask)pData; if(iSignal == SICSINT){ iInt = (int *)pSigData; if(*iInt == eEndServer){ self->iEnd = 1; } } } /*================ 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,"%ld", 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," %ld", 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; while(getNextHdbNumber(data,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(long)); if(v->v.intArray == NULL){ return 0; } memset(v->v.intArray,0,count*sizeof(long)); } 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; long lValue; double dValue; char number[80]; char *pPtr = NULL; switch(v->dataType){ case HIPNONE: break; case HIPINT: getNextHdbNumber(data,number); status = sscanf(number,"%ld", &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,"%ld", &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]; } /*-------------------------------------------------------------------------*/ pDynString formatJSONValue(char *name, hdbValue hVal, int children) { pDynString result = NULL; int i,length; char number[50]; result = CreateDynString(128,128); if(result == NULL){ return NULL; } DynStringConcat(result,"\""); DynStringConcat(result,name); DynStringConcat(result,"\""); if (hVal.dataType != HIPNONE) DynStringConcat(result,":"); switch(hVal.dataType){ case HIPNONE: break; case HIPINT: snprintf(number,50,"%ld",hVal.v.intValue); DynStringConcat(result,number); break; case HIPFLOAT: snprintf(number,50,"%lf",hVal.v.doubleValue); DynStringConcat(result,number); break; case HIPTEXT: DynStringConcat(result,hVal.v.text); break; case HIPINTAR: case HIPINTVARAR: for(i = 0; i < length; i++){ snprintf(number,50,"%ld",hVal.v.intArray[i]); DynStringConcat(result,number); if(i > length -1){ DynStringConcat(result,","); } } break; case HIPFLOATAR: case HIPFLOATVARAR: DynStringConcat(result,"["); for(i = 0; i < length; i++){ snprintf(number,50,"%lf",hVal.v.floatArray[i]); DynStringConcat(result,number); if(i > length -1){ DynStringConcat(result,","); } DynStringConcat(result,"]"); } break; } return result; } /*-------------------------------------------------------------------------*/ pDynString formatClientValue(char *name, hdbValue hVal, int children) { pDynString result = NULL; int i,length; char number[50]; result = CreateDynString(128,128); if(result == NULL){ return NULL; } DynStringConcat(result,name); DynStringConcat(result,","); DynStringConcat(result,hdbTypeToText(hVal.dataType)); DynStringConcat(result,","); snprintf(number,50,"%d",children); DynStringConcat(result,number); DynStringConcat(result,","); if(hVal.dataType >= 3){ length = hVal.arrayLength; } else { length = 1; } snprintf(number,50,"%d",length); DynStringConcat(result,number); DynStringConcat(result,","); switch(hVal.dataType){ case HIPNONE: break; case HIPINT: snprintf(number,50,"%ld",hVal.v.intValue); DynStringConcat(result,number); break; case HIPFLOAT: snprintf(number,50,"%lf",hVal.v.doubleValue); DynStringConcat(result,number); break; case HIPTEXT: DynStringConcat(result,hVal.v.text); break; case HIPINTAR: case HIPINTVARAR: for(i = 0; i < length; i++){ snprintf(number,50,"%ld",hVal.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",hVal.v.floatArray[i]); DynStringConcat(result,number); if(i > length -1){ DynStringConcat(result,","); } } break; } DynStringConcat(result,"\n"); return result; } /*--------------------------------------------------------------------------*/ 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; 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 */ pPtr = strrchr(argv[1],'/'); 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,argv[1]); } if(parent == NULL){ SCWrite(pCon,"ERROR: parent for new node does not exist",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); 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; 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 */ pPtr = strrchr(argv[1],'/'); 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,argv[1]); } if(parent == NULL){ SCWrite(pCon,"ERROR: parent for new node does not exist",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); SCSendOK(pCon); return 1; } /*-----------------------------------------------------------------------------------------*/ 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; } RemoveSICSPar(killNode); 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 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 pathArg = 1; char *usage ="ERROR: Requires argument"; switch (argc) { case 2: pathArg = 1; break; default: SCWrite(pCon,usage,eError); return 0; break; } strncpy(oriPath,argv[pathArg], 511); targetNode = locateSICSNode(pSics,pCon,argv[pathArg]); if(targetNode == NULL){ return 0; } memset(&newValue,0,sizeof(hdbValue)); GetHipadabaPar(targetNode, &newValue, pCon); parData = formatJSONValue(oriPath,newValue,0); if(parData == NULL){ SCWrite(pCon,"ERROR: out of memory formatting data",eError); return 0; } DynStringInsert(parData,"{", 0); DynStringConcat(parData,"}"); SCWrite(pCon,GetCharArray(parData),eHdb); DeleteDynString(parData); ReleaseHdbValue(&newValue); return 1; } /*---------------------------------------------------------------------------*/ 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 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){ 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 int countChildren(pHdb node){ pHdb current = NULL; int count = 0; current = node->child; while(current != NULL){ count++; current = current->next; } return count; } /*---------------------------------------------------------------------------*/ 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,"%ld",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,"%ld",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 pDynString formatJSONList(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, GetCharArray(formatJSONValue(current->name,current->value,0))); if (current->next != NULL) DynStringConcat(result, ","); current = current->next; } if (node->child->value.dataType == HIPNONE) { DynStringInsert(result,"[", 0); DynStringConcat(result,"]"); } else { DynStringInsert(result,"{", 0); DynStringConcat(result,"}"); } return result; } /*---------------------------------------------------------------------------*/ static int ListHdbNode(SConnection *pCon, SicsInterp *pSics, void *pData, int argc, char *argv[]){ pHdb node = NULL; pDynString listData = NULL; int pathArg = 1; char *usage ="ERROR: Requires argument"; switch (argc) { case 2: pathArg = 1; break; default: SCWrite(pCon,usage,eError); return 0; break; } node = locateSICSNode(pSics,pCon,argv[pathArg]); if(node == NULL){ return 0; } strtolower(argv[pathArg]); listData = formatJSONList(node); if(listData == NULL){ SCWrite(pCon,"ERROR: failed to format list", eError); return 0; } SCWrite(pCon,GetCharArray(listData),eHdb); DeleteDynString(listData); return 1; } /*---------------------------------------------------------------------------*/ static int setFormatStyle(SConnection *pCon, SicsInterp *pSics, void *pData, int argc, char *argv[]) { if(strcmp(argv[1],formatName[json]) == 0){ currFmtStyle = json; } else if(strcmp(argv[1],formatName[cli]) == 0){ currFmtStyle = cli; } else if(strcmp(argv[1],formatName[plain]) == 0){ currFmtStyle = plain; } } /*---------------------------------------------------------------------------*/ static int AutoNotifyHdbNode(SConnection *pCon, SicsInterp *pSics, void *pData, int argc, char *argv[]){ pHdb node = NULL; int id, status; int pathArg = 1, idArg=2; char *usage ="ERROR:valid arguments are "; switch (argc) { case 3: pathArg = 1; idArg = 2; break; default: SCWrite(pCon,usage,eError); return 0; break; } node = locateSICSNode(pSics,pCon,argv[pathArg]); if(node == NULL){ return 0; } id = atoi(argv[idArg]); 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; } /*---------------------------------------------------------------------------*/ void killSICSHipadaba(){ if(root != NULL){ DeleteHipadabaNode(root); } root = NULL; /** * children have already been removed when killing the * main tree */ if(scriptUpdate > 0 && LLDcheck(scriptUpdate) != LIST_EMPTY){ LLDdelete(scriptUpdate); } } /*---------------------------------------------------------------------------*/ int InstallSICSHipadaba(SConnection *pCon, SicsInterp *pSics, void *pData, int argc, char *argv[]){ root = MakeHipadabaNode("/",HIPNONE,0); scriptUpdate = LLDcreate(sizeof(void *)); taskData.updateList = scriptUpdate; taskData.iEnd = 0; taskData.pCon = SCCreateDummyConnection(pSics); if(taskData.pCon == NULL){ SCWrite(pCon,"ERROR: out of memory creating Hipadaba",eError); return 0; } TaskRegister(pServ->pTasker, SICSHipadabaTask, SICSHipadabaSignal, NULL, &taskData,1); AddCommand(pSics,"hmake", MakeHdbNode, NULL, NULL); AddCommand(pSics,"hmakescript", MakeHdbScriptNode, NULL, NULL); AddCommand(pSics,"hdel", DeleteHdbNode, NULL, NULL); AddCommand(pSics,"hset", SetHdbNode, NULL, NULL); AddCommand(pSics,"hget", GetHdbNode, NULL, NULL); AddCommand(pSics,"hlist", ListHdbNode, NULL, NULL); AddCommand(pSics,"hnotify", AutoNotifyHdbNode, NULL, NULL); AddCommand(pSics,"hdelcb", RemoveHdbCallback, NULL, NULL); AddCommand(pSics,"hstyle", setFormatStyle, NULL, NULL); return 1; }