diff --git a/ascon.c b/ascon.c index a017e1c8..a60b3fcd 100644 --- a/ascon.c +++ b/ascon.c @@ -75,9 +75,9 @@ static void AsconError(Ascon *a, char *msg, int errorno) { state = stateText[a->state]; } if (errorno != 0) { - ErrPutMsg(&a->errList, NULL, "%s %s (during %s)", msg, strerror(errorno), state); + ErrPutMsg(a->errList, "%s %s (during %s)", msg, strerror(errorno), state); } else { - ErrPutMsg(&a->errList, NULL, "%s (during %s)", msg, state); + ErrPutMsg(a->errList, "%s (during %s)", msg, state); } a->state |= AsconFailed; } @@ -400,7 +400,7 @@ Ascon *AsconMake(SConnection *con, int argc, char *argv[]) { } a->rdBuffer = CreateDynString(60, 63); a->wrBuffer = CreateDynString(60, 63); - a->errList.head = NULL; + a->errList = NULL; a->responseValid = 0; a->timeout = 2.0; a->reconnectInterval = 10; @@ -500,6 +500,6 @@ char *AsconRead(Ascon *a) { return NULL; } -ErrMsgList *AsconGetErrList(Ascon *a) { - return &a->errList; +ErrMsg *AsconGetErrList(Ascon *a) { + return a->errList; } diff --git a/ascon.h b/ascon.h index 75b417e8..fe6f4d32 100644 --- a/ascon.h +++ b/ascon.h @@ -64,7 +64,7 @@ char *AsconRead(Ascon *a); /** \brief get the connections error list * \return the error list */ -ErrMsgList *AsconGetErrList(Ascon *a); +ErrMsg *AsconGetErrList(Ascon *a); /** \brief a helper function * \param argc the number of args diff --git a/ascon.i b/ascon.i index 0bffb423..0d0f6f38 100644 --- a/ascon.i +++ b/ascon.i @@ -64,7 +64,7 @@ struct Ascon { int wrPos; /**< write buffer position */ double timeout; /**< read timeout (sec) */ char *hostport; /**< host:port to connect */ - ErrMsgList errList; /**< error message list */ + ErrMsg *errList; /**< error message list */ double start; /**< unix time when read was started */ void *private; /**< private data of protocol */ int noResponse; /**< no response expected */ diff --git a/devser.c b/devser.c index aa559ec1..569a398c 100644 --- a/devser.c +++ b/devser.c @@ -117,7 +117,8 @@ int DevQueueTask(void *ds) { while (action != NULL) { status = AsconTask(devser->asyncConn); if (status == AsconFailure) { - /* TODO: error handling */ + devser->errmsg = AsconGetErrList(devser->asyncConn); + return 1; } else if (status != AsconReady) { return 1; } diff --git a/errormsg.c b/errormsg.c index 488f26d8..cd45eda1 100644 --- a/errormsg.c +++ b/errormsg.c @@ -4,13 +4,30 @@ #include #include "errormsg.h" -/* ErrMsgList implementation */ -#define MC_NAME(T) ErrMsg##T -#define MC_IMPLEMENTATION -#include "mclist.c" +/* compare two strings for euqality, ignoring text within square brackets */ +int ErrEqual(char *str1, char *str2) { + char *p; + + while (*str1 != '\0' || *str2 != '\0') { + if (*str1 != *str2) { + return 0; + } + if (*str1 == '[') { + str1 = strchr(str1, ']'); + str2 = strchr(str2, ']'); + if (str1 == NULL || str2 == NULL) { + return str1 == str2; + } + str1++; + str2++; + } + } + return 1; +} -ErrMsg *ErrPutMsg(ErrMsgList *dump, char *data, char *fmt, ...) { - ErrMsg *m, *p; +ErrMsg *ErrPutMsg(ErrMsg *dump, char *fmt, ...) { + ErrMsg *m; + ErrMsg **last; va_list ap; char buf[256]; char *text; @@ -28,36 +45,23 @@ ErrMsg *ErrPutMsg(ErrMsgList *dump, char *data, char *fmt, ...) { vsnprintf(text, l, fmt, ap); va_end(ap); } - - m = NULL; - for (p = ErrMsgFirst(dump); p!= NULL; p = ErrMsgNext(dump)) { - if (strcmp(text, p->text) == 0) { - m = ErrMsgTake(dump); + for (last = &dump; *last != NULL; last = &m->next) { + m = *last; + if (ErrEqual(text, m->text)) { + *last = m->next; break; } } if (m == NULL) { + if (text == buf) text = strdup(buf); m = calloc(1, sizeof(*m)); - if (text == buf) { - m->text = strdup(text); - } else { - m->text = text; - } - m->data = NULL; + m->text = text; m->cnt = 1; } else { if (text != buf) free(text); m->cnt++; } - if (m->data) { - free(m->data); - m->data = NULL; - } - if (data) { - m->data = strdup(data); - } - ErrMsgFirst(dump); - ErrMsgInsert(dump, m); + m->next = dump; time(&m->last); return m; } diff --git a/errormsg.h b/errormsg.h index 70efc753..9c20ec64 100644 --- a/errormsg.h +++ b/errormsg.h @@ -11,20 +11,22 @@ typedef struct ErrMsg { struct ErrMsg *next; char *text; /**< the message text */ - char *data; /**< additional text which may be different for the same message */ + char *cmpr; /**< compressed message text */ int cnt; /**< count */ time_t last; /**< time of last message */ } ErrMsg; -/* define type ErrMsgList and functions ErrMsgAdd etc. */ -#define MC_NAME(T) ErrMsg##T -#include "mclist.h" - /** \brief Put a formatted message to the error message list + * + * The error message list contains only one entry for all messages + * with the same text, storing only the count and the last used time. + * Characters within sqaure brackets are not taken into account + * when comparing messages. + * * \param dump the error message list - * \param data some additional text (may be NULL) * \param fmt the format for the message + * \return the new error message list head */ -ErrMsg *ErrPutMsg(ErrMsgList *dump, char *data, char *fmt, ...); +ErrMsg *ErrPutMsg(ErrMsg *dump, char *fmt, ...); #endif diff --git a/hipadaba.c b/hipadaba.c index 2b4585b7..4a359a95 100644 --- a/hipadaba.c +++ b/hipadaba.c @@ -914,7 +914,9 @@ static int calcDataLength(pHdb node, int testLength){ /*============================= Property Functions ==========================*/ void SetHdbProperty(pHdb node, char *key, char *value){ if(node != NULL && key != NULL && node->properties != NULL){ - if(StringDictExists(node->properties, key)){ + if (value == NULL) { + StringDictDelete(node->properties, key); + } else if(StringDictExists(node->properties, key)){ StringDictUpdate(node->properties,key,value); } else { StringDictAddPair(node->properties,key,value); diff --git a/scriptcontext.c b/scriptcontext.c index 478eb529..186e373b 100644 --- a/scriptcontext.c +++ b/scriptcontext.c @@ -17,16 +17,19 @@ #define MAX_HDB_PATH 1024 +typedef struct ContextItem { + struct ContextItem *next; + Hdb *node; + Hdb *controllerNode; +} ContextItem; + typedef struct ScriptContext { ObjectDescriptor *desc; - Hdb *node; + ContextItem *nodes; + ContextItem *trash; + ContextItem *base; } ScriptContext; -typedef struct ContextStack { - struct ContextStack *next; - Hdb *node; -} ContextStack; - typedef struct SctController { DevSer *devser; Hdb *node; /* the controller node */ @@ -43,9 +46,7 @@ typedef struct SctData { Hdb *node; /* back link used by SctMatchWrite/SctMatchPoll */ } SctData; -static ScriptContext *nctx = NULL; /* the node context */ -static ScriptContext *cctx = NULL; /* the controller context */ -static ContextStack *stack, *stackTrash; +static ScriptContext *sct = NULL; static SCStore *currentCon = NULL; static struct { @@ -54,31 +55,60 @@ static struct { static char *mainCallback = "main callback"; -void PushContext(Hdb *node) { - ContextStack *new; +void PushContext(Hdb *node, Hdb *controllerNode) { + ContextItem *new; - if (stackTrash == NULL) { + if (sct->trash == NULL) { new = calloc(1, sizeof(*new)); } else { - new = stackTrash; - stackTrash = stackTrash->next; + new = sct->trash; + sct->trash = sct->trash->next; } - new->next = stack; + new->next = sct->nodes; + sct->nodes = new; new->node = node; - stack = new; + new->controllerNode = controllerNode; } -Hdb *PopContext(void) { - ContextStack *c; +void PopContext(void) { + ContextItem *c; - c = stack; - stack = stack->next; - c->next = stackTrash; - stackTrash = c; - return c->node; + c = sct->nodes; + assert(c); + sct->nodes = c->next; + c->next = sct->trash; + sct->trash = c; } -static void SetProp(Hdb *node, char *key, char *value) { +void CleanStack(Hdb *node) { + ContextItem *s; + + /* clean context from killed nodes */ + for (s = sct->nodes; s != NULL; s = s->next) { + if (s->node == node) { + s->node = NULL; + } + if (s->controllerNode == node) { + s->controllerNode = NULL; + } + } +} + +static void SetProp(Hdb *node, Hdb *cNode, char *key, char *value) { + char *val; + + if (node == NULL) { + if (cNode == NULL) return; + node = cNode; + } else { + val = GetHdbProp(node, key); + if (val == NULL && cNode != NULL) { + val = GetHdbProp(cNode, key); + if (val != NULL) { + node = cNode; + } + } + } if (value == NULL) { if (GetHdbProperty(node, key, NULL, 0) > 0) { SetHdbProperty(node, key, ""); @@ -88,14 +118,28 @@ static void SetProp(Hdb *node, char *key, char *value) { } } +static char *GetProp(Hdb *node, Hdb *cNode, char *key) { + char *val; + + if (node != NULL) { + val = GetHdbProp(node, key); + if (val != NULL) return val; + } + if (cNode != NULL) { + val = GetHdbProp(node, key); + } + return val; +} + int SctCommand(SConnection *con, SicsInterp *sics, void *object, int argc, char *argv[]) { - ScriptContext *ctx = object; static char value[1024]; char *val; - Hdb *node = ctx->node; + Hdb *node = sct->nodes->node; + Hdb *cNode = sct->nodes->controllerNode; - if (node == NULL) { + assert(sct == object); + if (node == NULL && cNode == NULL) { SCPrintf(con, eError, "ERROR: %s may be called only in proper context", argv[0]); return 0; @@ -106,7 +150,7 @@ int SctCommand(SConnection *con, SicsInterp *sics, void *object, return 1; } if (argc == 2) { /* get case */ - val = GetHdbProp(node, argv[1]); + val = GetProp(node, cNode, argv[1]); if (val == NULL) { SCPrintf(con, eError, "ERROR: %s %s not found", argv[0], argv[1]); return 0; @@ -114,10 +158,8 @@ int SctCommand(SConnection *con, SicsInterp *sics, void *object, SCWrite(con, val, eValue); } else { /* set case */ val = Arg2Tcl(argc-2, argv+2, value, sizeof value); - if (val != NULL) { - SetHdbProperty(node, argv[1], val); - if (val != value) free(val); - } + SetProp(node, cNode, argv[1], val); + if (val != NULL && val != value) free(val); } return 1; } @@ -130,10 +172,7 @@ int SctCallInContext(SConnection *con, char *script, Hdb *node, int iRet = 1; int verbose = controller->verbose; - PushContext(nctx->node); - PushContext(cctx->node); - nctx->node = node; - cctx->node = controller->node; + PushContext(node, controller->node); if (verbose) { SCPrintf(con, eInError, "\nscript: %s\n", script); } @@ -149,32 +188,11 @@ int SctCallInContext(SConnection *con, char *script, Hdb *node, } *resPtr = result; - cctx->node = PopContext(); - nctx->node = PopContext(); + PopContext(); + PopContext(); return iRet; } -void SctKill(void *object) { - ScriptContext *ctx = object; - if (ctx == nctx) nctx = NULL; - if (ctx == cctx) cctx = NULL; - if (ctx->desc != NULL) { - DeleteDescriptor(ctx->desc); - } - free(object); -} - -ScriptContext *SctMake(char *name) { - ScriptContext *ctx; - - ctx = calloc(1, sizeof(*ctx)); - assert(ctx); - ctx->desc = CreateDescriptor("ScriptContext"); - ctx->node = NULL; - AddCommand(pServ->pSics, name, SctCommand, SctKill, ctx); - return ctx; -} - static int SctMatch(void *data1, void *data2) { SctData *a = data1; SctData *b = data2; @@ -198,18 +216,18 @@ static char *SctActionHandler(void *actionData, char *lastReply) { } else { con = SCStorePush(controller->conn); } - SetProp(controller->node, "result", lastReply); + SetProp(node, controller->node, "result", lastReply); if (controller->verbose && lastReply != NULL && *lastReply != '\0') { SCPrintf(con, eWarning, "reply : %s", lastReply); } - state = GetHdbProp(controller->node, "state"); - if (state == NULL || state[0] == '\0') { + state = GetProp(node, controller->node, "state"); + if (state == NULL || strcasecmp(state, "idle") == 0) { state = data->name; - SetProp(controller->node, "state", state); + SetProp(node, controller->node, "state", state); } for (i = 0; i < 10; i++) { - SetProp(controller->node, "send", NULL); - script = GetHdbProp(node, state); + SetProp(node, controller->node, "send", NULL); + script = GetProp(node, controller->node, state); if (script == NULL) script = state; if (! SctCallInContext(con, script, node, data->controller, &result)) { @@ -227,8 +245,8 @@ static char *SctActionHandler(void *actionData, char *lastReply) { } goto finish; } - SetProp(controller->node, "state", state); - send = GetHdbProp(controller->node, "send"); + SetProp(node, controller->node, "state", state); + send = GetProp(node, controller->node, "send"); if (send != NULL && send[0] != '\0') { if (controller->verbose) { SCPrintf(con, eWarning, "send : %s", send); @@ -238,7 +256,7 @@ static char *SctActionHandler(void *actionData, char *lastReply) { } SCPrintf(con, eError, "ERROR: too many quick scripts chained"); finish: - SetProp(controller->node, "state", ""); + SetProp(node, controller->node, "state", "idle"); quit: if (currentCon) { SCStorePop(currentCon); @@ -267,7 +285,7 @@ static hdbCallbackReturn SctMainCallback(Hdb *node, void *userData, hdbDataMessage *mm; hdbPtrMessage *pm; hdbMessage *km; - ContextStack *s; + ContextItem *s; SConnection *con; char *geterror; @@ -288,14 +306,7 @@ static hdbCallbackReturn SctMainCallback(Hdb *node, void *userData, } km = GetHdbKillNodeMessage(msg); if (km != NULL) { - /* clean context from killed nodes */ - for (s = stack; s != NULL; s = s->next) { - if (s->node == node) { - s->node = NULL; - } - } - if (cctx->node == node) cctx->node = NULL; - if (nctx->node == node) nctx->node = NULL; + CleanStack(node); return hdbContinue; } mm = GetHdbGetMessage(msg); @@ -353,7 +364,7 @@ static hdbCallbackReturn SctActionCallback(Hdb *node, void *userData, con = mm->callData; /* call check script, if available */ - script = GetHdbProp(node, "check"); + script = GetProp(node, data->controller->node, "check"); if (script != NULL) { if (SctCallInContext(con, script, node, data->controller, &error) == 0) { SCPrintf(con, eError, "ERROR: %s", error); @@ -366,7 +377,7 @@ static hdbCallbackReturn SctActionCallback(Hdb *node, void *userData, SetHdbProperty(node, "target", GetCharArray(text)); /* enqueue write action */ - writeprio = GetHdbProp(node, "writeprio"); + writeprio = GetProp(node, data->controller->node, "writeprio"); if (writeprio != NULL) { prio = DevText2Prio(writeprio); if (prio < 0) prio = WritePRIO; @@ -492,9 +503,7 @@ static int SctPollCmd(pSICSOBJ ccmd, SConnection *con, SctAddPollNode(controller, node, interval, prio, action); - if (stack == NULL) { - nctx->node = node; - } + sct->base->node = node; return 1; } @@ -555,9 +564,7 @@ static int SctWriteCmd(pSICSOBJ ccmd, SConnection *con, return 0; } - if (stack == NULL) { - nctx->node = node; - } + sct->base->node = node; return 1; } @@ -642,6 +649,7 @@ static hdbCallbackReturn SctDebugCallback(Hdb *node, void *userData, static void SctKillController(void *c) { SctController *controller = c; + CleanStack(controller->node); RemoveSICSInternalCallback(controller); DevKill(controller->devser); } @@ -680,8 +688,6 @@ static int SctMakeController(SConnection *con, SicsInterp *sics, AddCommand(pServ->pSics, nodeName, InvokeSICSOBJ, KillSICSOBJ, ccmd); SetDescriptorKey(ccmd->pDes, "creationCommand", "0"); - SetProp(controller->node, "state", ""); - AddHipadabaChild(parent, controller->node, con); controller->devser = DevMake(con, argc - 2, argv + 2); @@ -710,16 +716,38 @@ static int SctMakeController(SConnection *con, SicsInterp *sics, cb = MakeHipadabaCallback(SctDebugCallback, controller, NULL); if (cb) AppendHipadabaCallback(par, cb); - if (stack == NULL) { - cctx->node = controller->node; - nctx->node = NULL; - } - + sct->base->controllerNode = controller->node; + sct->base->node = NULL; + return 1; } +void SctKill(void *object) { + assert(sct == object); + ContextItem *p, *q; + + for (p = sct->nodes; p != NULL; p = q) { + q = p->next; + free(p); + } + for (p = sct->trash; p != NULL; p = q) { + q = p->next; + free(p); + } + if (sct->desc != NULL) { + DeleteDescriptor(sct->desc); + } + free(sct); + sct = NULL; +} + void SctInit(void) { - nctx = SctMake("nctx"); - cctx = SctMake("cctx"); + if (sct) return; + sct = calloc(1, sizeof(*sct)); + assert(sct); + sct->desc = CreateDescriptor("ScriptContext"); + PushContext(NULL, NULL); + sct->base = sct->nodes; + AddCommand(pServ->pSics, "sct", SctCommand, SctKill, sct); AddCmd("makesctcontroller", SctMakeController); } diff --git a/sicshipadaba.c b/sicshipadaba.c index e501ccf4..6483176e 100644 --- a/sicshipadaba.c +++ b/sicshipadaba.c @@ -2932,6 +2932,7 @@ static int SetSICSHdbProperty(SConnection *pCon, SicsInterp *pSics, void *pData, int argc, char *argv[]){ pHdb targetNode = NULL; char buffer[512]; + char *val; if(argc < 4) { SCWrite(pCon,"ERROR: need path key value as parameters",eError); @@ -2942,8 +2943,11 @@ static int SetSICSHdbProperty(SConnection *pCon, SicsInterp *pSics, void *pData, SCWrite(pCon,"ERROR: node not found",eError); return 0; } - Arg2Tcl(argc-3, &argv[3], buffer,512); - SetHdbProperty(targetNode,argv[2], buffer); + val = Arg2Tcl(argc-3, &argv[3], buffer, sizeof buffer); + if (val) { + SetHdbProperty(targetNode,argv[2], val); + if (val != buffer) free(val); + } SCSendOK(pCon); return 1; }