From 2e060ccf734f5795e9f845c84d116174e409d31c Mon Sep 17 00:00:00 2001 From: zolliker Date: Tue, 3 Mar 2009 14:07:43 +0000 Subject: [PATCH] - design improvements in scriptcontext (sct send) and ascon (AsconBaseHandler) - bug fixes --- ascon.c | 207 ++++++++++++++++++++++++++--------------------- ascon.i | 65 +++++++++------ exebuf.c | 10 +-- lld.c | 2 +- scriptcontext.c | 97 +++++++++++++++------- sctdriveobj.c | 1 + sicshdbfactory.c | 35 +++++++- sicsobj.c | 47 ++++++----- 8 files changed, 292 insertions(+), 172 deletions(-) diff --git a/ascon.c b/ascon.c index bd74575a..b64c914d 100644 --- a/ascon.c +++ b/ascon.c @@ -15,6 +15,7 @@ #include "uselect.h" static double lastClose = 0; /* time of last close operation */ +static AsconProtocol *protocols = NULL; /* CreateSocketAdress stolen from Tcl. Thanks to John Ousterhout @@ -132,6 +133,10 @@ static void AsconConnect(Ascon * a) return; } } + if (a->hostport == NULL) { + AsconError(a, "no host:port given", 0); + return; + } colon = strchr(a->hostport, ':'); if (colon == NULL) return; @@ -167,28 +172,6 @@ static void AsconConnect(Ascon * a) return; } -int AsconStdInit(Ascon *a, SConnection *con, int argc, char *argv[]) -{ - a->fd = -1; - a->state = AsconConnectStart; - a->hostport = strdup(argv[1]); - if (argc > 2) { - a->sendTerminator = strdup(argv[2]); - } else { - a->sendTerminator = strdup("\n"); - } - if (argc > 3) { - a->timeout = atof(argv[3]); - } else { - a->timeout = 2.0; /* sec */ - } - a->replyTerminator == NULL; - if (argc > 4 && argv[4][0] != '\0') { - a->replyTerminator = strdup(argv[4]); - } - return 1; -} - int AsconReadGarbage(int fd) { fd_set rmask; @@ -315,14 +298,14 @@ int AsconWriteChars(int fd, char *data, int length) static double lastCall = 0; -int AsconStdHandler(Ascon * a) +int AsconBaseHandler(Ascon * a) { int ret; int l; char chr; double now = DoubleTime(); - if (now > lastCall + 0.5) { /* AsconStdHandler was not called since a long time (0.5 sec) */ + if (now > lastCall + 0.5) { /* AsconBaseHandler was not called since a long time (0.5 sec) */ if (lastCall != 0) { /* extend timeout time (for debugging purposes) */ a->start += now - lastCall - 0.5; } @@ -343,26 +326,13 @@ int AsconStdHandler(Ascon * a) } break; case AsconWriteStart: - if (strstr(GetCharArray(a->wrBuffer), "@@NOSEND@@") != NULL) { - a->state = AsconWriteDone; - } else { + if (a->sendTerminator) { DynStringConcat(a->wrBuffer, a->sendTerminator); - a->wrPos = 0; - a->state = AsconWriting; } + a->wrPos = 0; + a->state = AsconWriting; break; case AsconWriting: - if (a->readState) { /* last char was CR */ - ret = AsconReadChar(a->fd, &chr); - if (ret > 0) { - if (chr == '\n') { - /* swallow LF after CR */ - a->readState = 0; - } else { - /* garbage character found */ - } - } - } AsconReadGarbage(a->fd); l = GetDynStringLength(a->wrBuffer) - a->wrPos; ret = AsconWriteChars(a->fd, GetCharArray(a->wrBuffer) + a->wrPos, l); @@ -382,56 +352,24 @@ int AsconStdHandler(Ascon * a) break; case AsconReading: ret = AsconReadChar(a->fd, &chr); - if (ret > 0) { - a->start = DoubleTime(); - - if (a->replyTerminator != NULL) { - if (strchr(a->replyTerminator, chr) != NULL) { - DynStringConcatChar(a->rdBuffer, chr); - DynStringConcatChar(a->rdBuffer, '\0'); - a->state = AsconReadDone; - break; - } - } else { - if (chr == '\n') { - if (a->readState) { /* last char was CR */ - /* swallow LF after CR */ - a->readState = 0; - chr = 0; - } else { - DynStringConcatChar(a->rdBuffer, '\0'); - a->state = AsconReadDone; - break; - } - } else if (chr == '\r') { - a->readState = 1; /* set 'last char was CR' */ - DynStringConcatChar(a->rdBuffer, '\0'); - a->state = AsconReadDone; - break; + if (ret <= 0) { + if (ret < 0) { + AsconError(a, "ASC5", errno); + return 0; + } + if (a->timeout > 0) { + if (DoubleTime() - a->start > a->timeout) { + AsconError(a, "no response", 0); + a->state = AsconTimeout; } } - if (chr != 0) { - if (DynStringConcatChar(a->rdBuffer, chr) == 0) { - AsconError(a, "DynStringConcatChar failed:", ENOMEM); - break; - } - a->readState = 0; - } + return 0; } - if (ret < 0) { - AsconError(a, "ASC5", errno); - return 1; - } - if (a->state == AsconReadDone) { - DynStringConcatChar(a->rdBuffer, '\0'); - } else if (ret > 0) { - return 0; /* characater read: recycle */ - } - if (a->timeout > 0) { - if (DoubleTime() - a->start > a->timeout) { - AsconError(a, "no response", 0); - a->state = AsconTimeout; - } + a->lastChar = chr; + a->start = DoubleTime(); + if (DynStringConcatChar(a->rdBuffer, chr) == 0) { + AsconError(a, "ASC6", errno); + return 0; } break; default: @@ -440,8 +378,6 @@ int AsconStdHandler(Ascon * a) return 1; } -static AsconProtocol *protocols = NULL; - void AsconInsertProtocol(AsconProtocol *protocol) { protocol->next = protocols; protocols = protocol; @@ -472,6 +408,88 @@ AsconHandler AsconSetHandler(Ascon *a, SConnection *con, return NULL; } +/* --- standard handler ---- */ + +int AsconStdHandler(Ascon * a) +{ + int result; + char chr; + int ret; + + switch (a->state) { + case AsconWriteStart: + if (strstr(GetCharArray(a->wrBuffer), "@@NOSEND@@") != NULL) { + a->state = AsconWriteDone; + return 1; + } + break; /* go to the base handler */ + case AsconWriting: + if (a->readState) { /* last char was CR */ + ret = AsconReadChar(a->fd, &chr); + if (ret > 0) { + if (chr == '\n') { + /* swallow LF after CR */ + a->readState = 0; + } else { + /* garbage character found -> swallow */ + } + } + } + break; /* go to the base handler */ + case AsconReading: + result = AsconBaseHandler(a); + if (result == 0) + return 0; + chr = a->lastChar; + if (a->replyTerminator != NULL) { + if (strchr(a->replyTerminator, chr) != NULL) { + DynStringConcatChar(a->rdBuffer, '\0'); + a->state = AsconReadDone; + } + } else { + if (chr == '\n') { + if (a->readState) { /* last char was CR */ + /* swallow LF after CR */ + a->readState = 0; + } else { + DynStringBackspace(a->rdBuffer); /* remove LF */ + DynStringConcatChar(a->rdBuffer, '\0'); + a->state = AsconReadDone; + } + } else if (chr == '\r') { + a->readState = 1; /* set 'last char was CR' */ + DynStringBackspace(a->rdBuffer); /* remove CR */ + DynStringConcatChar(a->rdBuffer, '\0'); + a->state = AsconReadDone; + } + } + return 1; /* base handler was already called */ + default: + break; + } + return AsconBaseHandler(a); +} + +int AsconStdInit(Ascon *a, SConnection *con, int argc, char *argv[]) +{ + a->hostport = strdup(argv[1]); + if (argc > 2) { + a->sendTerminator = strdup(argv[2]); + } else { + a->sendTerminator = strdup("\n"); + } + if (argc > 3) { + a->timeout = atof(argv[3]); + } else { + a->timeout = 2.0; /* sec */ + } + a->replyTerminator = NULL; + if (argc > 4 && argv[4][0] != '\0') { + a->replyTerminator = strdup(argv[4]); + } + return 1; +} + /* --- implementation of higher level interface ---- */ char *ConcatArgs(int argc, char *argv[]) @@ -489,6 +507,15 @@ Ascon *AsconMake(SConnection * con, int argc, char *argv[]) SCWrite(con, "ERROR: no memory", eError); return NULL; } + a->fd = -1; + a->state = AsconConnectStart; + a->timeout = 2.0; /* 2 sec default */ + a->reconnectInterval = 10; /* 10 sec default */ + a->replyTerminator = NULL; + a->sendTerminator = NULL; + a->hostport = NULL; + a->responseValid = 0; + a->handler = AsconSetHandler(a, con, argc, argv); if (a->handler == NULL) { args = ConcatArgs(argc, argv); @@ -501,7 +528,7 @@ Ascon *AsconMake(SConnection * con, int argc, char *argv[]) a->rdBuffer = CreateDynString(60, 63); a->wrBuffer = CreateDynString(60, 63); a->errmsg = CreateDynString(60, 63); - a->responseValid = 0; + return a; } diff --git a/ascon.i b/ascon.i index 18a8fb16..e8bdd0ef 100644 --- a/ascon.i +++ b/ascon.i @@ -51,25 +51,26 @@ typedef int (* AsconHandler)(Ascon *connection); * all members are public, allowing access by handler wrappers */ struct Ascon { - AsconState state; /**< the current state */ - int fd; /**< socket */ - int readState; /**< default implementation: 'was cr' */ - pDynString rdBuffer;/**< read buffer */ - pDynString wrBuffer;/**< write buffer */ - int wrPos; /**< write buffer position */ - double timeout; /**< read timeout (sec) */ - char *sendTerminator; /**< terminator for sending messages */ - char *replyTerminator; /**< terminator list for reply. NULL is the special case CR, LF or CR/LF */ - char *hostport; /**< host:port to connect */ - pDynString errmsg; /**< error message */ - double start; /**< unix time when read was started */ - void *private; /**< private data of protocol */ + AsconState state; /**< the current state */ + int fd; /**< socket */ + int readState; /**< default implementation: 'was cr' */ + pDynString rdBuffer; /**< read buffer */ + pDynString wrBuffer; /**< write buffer */ + int wrPos; /**< write buffer position */ + double timeout; /**< read timeout (sec) */ + char *sendTerminator; /**< terminator for sending messages */ + char *replyTerminator; /**< terminator list for reply. NULL is the special case CR, LF or CR/LF */ + char *hostport; /**< host:port to connect */ + pDynString errmsg; /**< error message */ + double start; /**< unix time when read was started */ + void *private; /**< private data of protocol */ void (*killPrivate)(void *); /** < kill function for private */ - int noResponse; /**< no response expected */ - int responseValid; /**< a valid response is ready */ - AsconHandler handler; /**< handler function */ - double reconnectInterval; /**< reconnect interval */ - double lastReconnect; /**< last reconnect try */ + int noResponse; /**< no response expected */ + int responseValid; /**< a valid response is ready */ + AsconHandler handler; /**< handler function */ + double reconnectInterval; /**< reconnect interval */ + double lastReconnect; /**< last reconnect try */ + char lastChar; /**< last char read */ }; #define ASCON_SELECT_ERROR -1 @@ -77,14 +78,25 @@ struct Ascon { #define ASCON_SEND_ERROR -3 #define ASCON_DISCONNECTED -4 +/** \brief the basic handler routine. + * \param a the connection + * \return when the state before the call was not AsconReading, the return + * value should be 1 + * when the state was AsconReading, a 1 indicates that a character was read + * and the character is stored in the lastChar field. A 0 indicates + * that no charater was read. + * + * + * In most cases a custom handler may be a wrapper around AsconBaseHandler + * or around AsconStdHandler + */ +int AsconBaseHandler(Ascon *a); + /** \brief the standard handler routine. * \param a the connection - * \return 0 when it makes sense to call the handler again immediately - * (for example while reading, after a character was read, as - * there may be more chars in the buffer) - * 1 else + * \return see AsconBaseHandler * - * In most cases a custom handler may be a wrapper around AsconStdHandler + * features: see description of AsconStdInit */ int AsconStdHandler(Ascon *a); @@ -94,12 +106,13 @@ int AsconStdHandler(Ascon *a); * \param argc number of arguments * \param argv arguments (":" [sendTerminator] [timeout] [replyTerminators]) * sendTerminator is a character or string sent at the end of a command - * timoeut is in seconds + * timeout is in seconds * replyTerminator is a string, meant as a list of terminator characters * if not replyTerminator is given, CR, LF or CR/LF all are detected as - * terminators + * terminators. In this case the terminator is removed from the result, + * where in the case before, the terminator stays in the result. * - * In most cases a custom init function may be a wrapper around AsconStdInit + * In many cases a custom init function may be a wrapper around AsconStdInit */ int AsconStdInit(Ascon *a, SConnection *con, int argc, char *argv[]); diff --git a/exebuf.c b/exebuf.c index dfe34d2e..635f5c7b 100644 --- a/exebuf.c +++ b/exebuf.c @@ -233,15 +233,13 @@ int exeBufProcess(pExeBuf self, SicsInterp * pSics, SCPrintf(pCon, eLogError, "ERROR: Tcl reported: %s", pTcl->result); } - SCWrite(pCon, "ERROR: Tcl error in block:", eLogError); - SCWrite(pCon, GetCharArray(command), eError); - SCWrite(pCon, "ERROR: end of Tcl error block", eLogError); } else { - if(strstr(pTcl->result, "ERROR") != NULL){ - SCPrintf(pCon,eError,"%s occurred in %s", pTcl->result, cmd ); - } + SCWrite(pCon, pTcl->result, eError); pCon->sicsError = 0; } + SCWrite(pCon, "ERROR: above error was in block:", eError); + SCWrite(pCon, cmd, eError); + SCWrite(pCon, "ERROR: end of Tcl error block", eError); } DeleteDynString(command); if (SCGetInterrupt(pCon) >= eAbortBatch) { diff --git a/lld.c b/lld.c index 63f295ba..30f74d7b 100644 --- a/lld.c +++ b/lld.c @@ -69,7 +69,7 @@ static int ListInit(int List, int ItemSize) if (0 != ItemSize) { /* create dummy head node */ - Fortify_CheckAllMemory(); + (void)Fortify_CheckAllMemory(); Tmp = NODE_MALLOC(List); if (NULL == Tmp) { return ERR_MEMORY; diff --git a/scriptcontext.c b/scriptcontext.c index 4c1641f0..58c963ae 100644 --- a/scriptcontext.c +++ b/scriptcontext.c @@ -28,6 +28,8 @@ typedef struct ScriptContext { ObjectDescriptor *desc; ContextItem *nodes; ContextItem *trash; + Hdb *sendNode; + int sendCalled; } ScriptContext; struct SctController { @@ -152,7 +154,6 @@ int SctCommand(SConnection * con, SicsInterp * sics, void *object, Hdb *cNode = NULL; hdbValue v; double dtime; - int iMacro; assert(sct == object); if (sct->nodes != NULL) { @@ -190,14 +191,13 @@ int SctCommand(SConnection * con, SicsInterp * sics, void *object, * print */ if (strcmp(argv[1], "print") == 0) { - iMacro = con->iMacro; if (queueData != NULL) { queueData->answered = 1; - con->iMacro = queueData->inMacro; /* take macro flag stored at set callback */ + SCsetMacro(con, queueData->inMacro); /* take macro flag stored at set callback */ } Arg2Text(argc - 2, argv + 2, value, sizeof value); SCWrite(con, value, eWarning); - con->iMacro = iMacro; + SCsetMacro(con, 1); /* where are always in Macro */ return 1; } @@ -223,6 +223,19 @@ int SctCommand(SConnection * con, SicsInterp * sics, void *object, return 1; } + /* + * send command + */ + if (strcmp(argv[1], "send") == 0 && argc > 2) { + if (sct->sendNode != node) { + SCPrintf(con, eError, "ERROR: %s may be called only in action scripts", + argv[0]); + return 0; + } + sct->sendCalled = 1; + /* continue with property handling */ + } + /* * property handling */ @@ -265,6 +278,13 @@ int SctCallInContext(SConnection * con, char *script, Hdb * node, ret = Tcl_EvalEx(pTcl, script, l, 0); result = (char *) Tcl_GetStringResult(pTcl); if (ret != TCL_OK && result[0] != '\0') { + if (strncmp(result, "ERROR:", 6) == 0) { + /* remove "ERROR:", as it will be added later */ + result += 6; + if (result[0] == ' ') { + result++; + } + } if (verbose) { SCPrintf(con, eLog, "error: %s", result); } @@ -306,8 +326,10 @@ static char *SctActionHandler(void *actionData, char *lastReply, char *emsg; size_t l; int cnt; + int ret; char timeKey[50], timeVal[50]; - + int iMacro; + if (queueData != NULL && queueData->conCtx != NULL) { con = queueData->conCtx; } else { @@ -325,9 +347,6 @@ static char *SctActionHandler(void *actionData, char *lastReply, SetProp(node, controller->node, "state", state); } for (i = 0; i < 10; i++) { - SetProp(node, controller->node, "sent", - GetProp(node, controller->node, "send")); - SetProp(node, controller->node, "send", NULL); script = GetProp(node, controller->node, state); if (script == NULL) script = state; @@ -339,11 +358,12 @@ static char *SctActionHandler(void *actionData, char *lastReply, commError = 0; } script = strdup(script); - if (!SctCallInContext(con, script, node, controller, &result)) { + sct->sendNode = node; + sct->sendCalled = 0; + ret = SctCallInContext(con, script, node, controller, &result); + sct->sendNode = NULL; + if (ret == 0) { snprintf(eprop, sizeof eprop, "error_during_%s", data->name); - if (strncmp(result, "ERROR: ", 7) == 0) { - result += 7; - } emsg = GetHdbProp(node, eprop); if (emsg == NULL || con != controller->conn) { GetHdbPath(node, path, sizeof path); @@ -366,7 +386,7 @@ static char *SctActionHandler(void *actionData, char *lastReply, sscanf(emsg, "%d", &cnt); } cnt++; - snprintf(msg, sizeof msg, "%dx {%s} %s", cnt, origScript, result); + snprintf(msg, sizeof msg, "%dx {%s}: %s", cnt, origScript, result); SetHdbProperty(node, eprop, msg); send = NULL; free(script); @@ -375,7 +395,12 @@ static char *SctActionHandler(void *actionData, char *lastReply, state = result; if (strcasecmp(state, "idle") == 0 || strcasecmp(state, "unpoll") == 0) { if (queueData == data && !data->answered) { - SCWrite(con, "o.k.", eWarning); + if (queueData->inMacro == 0) { + iMacro = SCinMacro(con); + con->iMacro = 0; + SCWrite(con, "o.k.", eWarning); + SCsetMacro(con, iMacro); + } } snprintf(eprop, sizeof eprop, "error_during_%s", data->name); emsg = GetHdbProp(node, eprop); @@ -396,8 +421,10 @@ static char *SctActionHandler(void *actionData, char *lastReply, SetProp(node, controller->node, "state", state); free(script); script = NULL; - send = GetProp(node, controller->node, "send"); - if (send != NULL && send[0] != '\0') { + if (sct->sendCalled) { + send = GetProp(node, controller->node, "send"); + if (send == NULL) + send = ""; if (controller->verbose) { SCPrintf(con, eLog, "send : %s", send); } @@ -522,7 +549,9 @@ static hdbCallbackReturn SctActionCallback(Hdb * node, void *userData, char *error; SConnection *con; char path[MAX_HDB_PATH]; - + char *sicsCommand; + int iMacro; + pm = GetKillPtrMessage(msg); if (pm != NULL) { if (data->controller == pm->pPtr) { @@ -554,7 +583,7 @@ static hdbCallbackReturn SctActionCallback(Hdb * node, void *userData, if (script != NULL) { if (SctCallInContext(con, script, node, data->controller, &error) == 0) { - SCPrintf(con, eError, "ERROR: %s", error); + SCPrintf(con, eError, "ERROR: in {%s}: %s", script, error); SetHdbProperty(node, "target", NULL); return hdbAbort; } @@ -574,16 +603,19 @@ static hdbCallbackReturn SctActionCallback(Hdb * node, void *userData, } if (data->conCtx != NULL) { - GetHdbPath(node, path, sizeof path); - SCPrintf(data->conCtx, eWarning, - "%s target changed to %s before completion", path, - GetCharArray(text)); + if (data->inMacro == 0) { + GetHdbPath(node, path, sizeof path); + SCsetMacro(data->conCtx, 0); + SCPrintf(data->conCtx, eWarning, + "%s target changed to %s before completion", path, + GetCharArray(text)); + } SCDeleteConnection(data->conCtx); } DeleteDynString(text); data->conCtx = SCCopyConnection(con); data->answered = 0; - data->inMacro = con->iMacro; + data->inMacro = SCinMacro(con); DevQueue(data->controller->devser, data, prio, SctWriteHandler, SctMatch, NULL); /* no kill function in DevQueue: data is owned by the node (callback list) */ @@ -594,10 +626,20 @@ static hdbCallbackReturn SctActionCallback(Hdb * node, void *userData, if (mm != NULL) { if (queueData != NULL && queueData->conCtx != NULL && !data->answered) { /* update called from a write action */ - data->answered = 1; - GetHdbPath(node, path, sizeof path); text = formatValue(*(mm->v), node); - SCPrintf(queueData->conCtx, eWarning, "OK: %s set to: %s", path, GetCharArray(text)); + if (queueData->inMacro == 0 && queueData->node == node) { + data->answered = 1; + iMacro = SCinMacro(queueData->conCtx); + SCsetMacro(queueData->conCtx, 0); + sicsCommand = GetHdbProp(node, "sicscommand"); + if (sicsCommand) { + SCPrintf(queueData->conCtx, eWarning, "OK: %s %s", sicsCommand, GetCharArray(text)); + } else { + GetHdbPath(node, path, sizeof path); + SCPrintf(queueData->conCtx, eWarning, "OK: hset %s %s", path, GetCharArray(text)); + } + SCsetMacro(queueData->conCtx, iMacro); + } DeleteDynString(text); } return hdbContinue; @@ -1137,7 +1179,8 @@ static int SctMakeController(SConnection * con, SicsInterp * sics, return 0; SetHdbProperty(controller->node, "controllerName", objName); - + SetHdbProperty(controller->node, "sicsdev", objName); + AddCommand(pServ->pSics, objName, InterInvokeSICSOBJ, KillSICSOBJ, ccmd); RegisterSICSOBJKillCmd(ccmd, objName); SetDescriptorKey(ccmd->pDes, "creationCommand", "0"); diff --git a/sctdriveobj.c b/sctdriveobj.c index 9b69bc8e..ebc9ba37 100644 --- a/sctdriveobj.c +++ b/sctdriveobj.c @@ -381,6 +381,7 @@ int SctMakeDriveObject(SConnection * pCon, SicsInterp * pSics, SetDescriptorKey(pNew->pDes, "creationCommand", "0"); RegisterSICSOBJKillCmd(pNew, argv[1]); } + SetHdbProperty(pNew->objectNode, "sicsdev", argv[1]); status = AddCommand(pSics, argv[1], InterInvokeSICSOBJ, KillDriveOBJ, pNew); if (status != 1) { diff --git a/sicshdbfactory.c b/sicshdbfactory.c index cdc17cfc..d921f455 100644 --- a/sicshdbfactory.c +++ b/sicshdbfactory.c @@ -12,13 +12,39 @@ #define MAX_HDB_PATH 1024 /*-------------------------------------------------------------------------*/ +static pDynString ComposeSicsCommand(pHdb node) +{ + char *sicsdev; + pDynString sicsCommand; + + if (node == NULL) + return NULL; + sicsdev = GetHdbProp(node, "sicsdev"); + if (sicsdev != NULL) { + sicsCommand = CreateDynString(60,63); + DynStringConcat(sicsCommand, sicsdev); + return sicsCommand; + } + sicsCommand = ComposeSicsCommand(node->mama); + if (sicsCommand) { + if (strchr(GetCharArray(sicsCommand), ' ') == NULL) { + DynStringConcatChar(sicsCommand, ' '); + } else { + DynStringConcatChar(sicsCommand, '/'); + } + DynStringConcat(sicsCommand, node->name); + } + return sicsCommand; +} +/*-------------------------------------------------------------------------*/ static int MakePlainNode(pHdb parent, char *name, SConnection * pCon, int argc, char *argv[]) { pHdb child = NULL; int type = 0, length = 0, priv = -1; hdbValue val; - + pDynString sicsCommand = NULL; + if (argc < 5) { SCWrite(pCon, "ERROR: not enough arguments to create plain node", eError); @@ -68,6 +94,13 @@ static int MakePlainNode(pHdb parent, char *name, SConnection * pCon, } AddHipadabaChild(parent, child, pCon); + if (type != HIPNONE) { + sicsCommand = ComposeSicsCommand(child); + if (sicsCommand) { + SetHdbProperty(child, "sicscommand", GetCharArray(sicsCommand)); + DeleteDynString(sicsCommand); + } + } SCSendOK(pCon); return 1; } diff --git a/sicsobj.c b/sicsobj.c index 6a3a5a4a..393268c7 100644 --- a/sicsobj.c +++ b/sicsobj.c @@ -351,40 +351,45 @@ static int isNodePrintable(pHdb node) } /*---------------------------------------------------------------------------*/ -static void objFormatNode(pHdb node, pDynString data) +static void objFormatNode(pHdb node, char separator, + char *prefix, pDynString data) { - char par[40]; - pDynString val = NULL; - - snprintf(par, 40, "%-20s = ", node->name); + char par[128]; + pDynString dyn = NULL; + int i; + pHdb child; + char *vis; + + snprintf(par, sizeof par, "%-20s = ", prefix); DynStringConcat(data, par); - val = formatValue(node->value, node); - if (val != NULL) { - DynStringConcat(data, GetCharArray(val)); - DynStringConcatChar(data, '\n'); - DeleteDynString(val); + dyn = formatValue(node->value, node); + if (dyn != NULL) { + DynStringConcat(data, GetCharArray(dyn)); + } else { + dyn = CreateDynString(60, 63); } + DynStringConcatChar(data, '\n'); + for (child = node->child; child != NULL; child = child->next) { + DynStringCopy(dyn, prefix); + DynStringConcatChar(dyn, separator); + DynStringConcat(dyn, child->name); + objFormatNode(child, '/', GetCharArray(dyn), data); + } + DeleteDynString(dyn); } /*---------------------------------------------------------------------------*/ static int ListObj(pSICSOBJ self, SConnection * pCon, int argc, char *argv[]) { - pHdb node = NULL; pDynString data; data = CreateDynString(128, 128); if (data == NULL) { return 0; } - node = self->pDes->parNode; - if (node != NULL) { - objFormatNode(node, data); - node = node->child; - while (node != NULL) { - objFormatNode(node, data); - node = node->next; - } + if (self->pDes->parNode != NULL) { + objFormatNode(self->pDes->parNode, ' ', argv[0], data); } SCWrite(pCon, GetCharArray(data), eValue); DeleteDynString(data); @@ -440,7 +445,7 @@ int InvokeSICSOBJ(SConnection * pCon, SicsInterp * pSics, void *pData, } else if (strcmp(argv[1], "list") == 0) { return ListObj(self, pCon, argc, argv); } - SCPrintf(pCon, eError, "ERROR: %s %s not found", argv[0], argv[1]); + /* error message written by the caller */ } return status; @@ -508,7 +513,7 @@ pSICSOBJ SetupSICSOBJ(SConnection * pCon, SicsInterp * pSics, void *pData, SetDescriptorKey(pNew->pDes, "creationCommand", "0"); } - SetHdbProperty(pNew->objectNode, "objectName", argv[1]); + SetHdbProperty(pNew->objectNode, "sicsdev", argv[1]); status = AddCommand(pSics, argv[1], InterInvokeSICSOBJ, KillSICSOBJ, pNew); if (status != 1) {