- design improvements in scriptcontext (sct send) and ascon (AsconBaseHandler)

- bug fixes
This commit is contained in:
zolliker
2009-03-03 14:07:43 +00:00
parent 0dc196becb
commit 2e060ccf73
8 changed files with 292 additions and 172 deletions

207
ascon.c
View File

@ -15,6 +15,7 @@
#include "uselect.h" #include "uselect.h"
static double lastClose = 0; /* time of last close operation */ static double lastClose = 0; /* time of last close operation */
static AsconProtocol *protocols = NULL;
/* /*
CreateSocketAdress stolen from Tcl. Thanks to John Ousterhout CreateSocketAdress stolen from Tcl. Thanks to John Ousterhout
@ -132,6 +133,10 @@ static void AsconConnect(Ascon * a)
return; return;
} }
} }
if (a->hostport == NULL) {
AsconError(a, "no host:port given", 0);
return;
}
colon = strchr(a->hostport, ':'); colon = strchr(a->hostport, ':');
if (colon == NULL) if (colon == NULL)
return; return;
@ -167,28 +172,6 @@ static void AsconConnect(Ascon * a)
return; 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) int AsconReadGarbage(int fd)
{ {
fd_set rmask; fd_set rmask;
@ -315,14 +298,14 @@ int AsconWriteChars(int fd, char *data, int length)
static double lastCall = 0; static double lastCall = 0;
int AsconStdHandler(Ascon * a) int AsconBaseHandler(Ascon * a)
{ {
int ret; int ret;
int l; int l;
char chr; char chr;
double now = DoubleTime(); 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) */ if (lastCall != 0) { /* extend timeout time (for debugging purposes) */
a->start += now - lastCall - 0.5; a->start += now - lastCall - 0.5;
} }
@ -343,26 +326,13 @@ int AsconStdHandler(Ascon * a)
} }
break; break;
case AsconWriteStart: case AsconWriteStart:
if (strstr(GetCharArray(a->wrBuffer), "@@NOSEND@@") != NULL) { if (a->sendTerminator) {
a->state = AsconWriteDone;
} else {
DynStringConcat(a->wrBuffer, a->sendTerminator); DynStringConcat(a->wrBuffer, a->sendTerminator);
a->wrPos = 0;
a->state = AsconWriting;
} }
a->wrPos = 0;
a->state = AsconWriting;
break; break;
case AsconWriting: 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); AsconReadGarbage(a->fd);
l = GetDynStringLength(a->wrBuffer) - a->wrPos; l = GetDynStringLength(a->wrBuffer) - a->wrPos;
ret = AsconWriteChars(a->fd, GetCharArray(a->wrBuffer) + a->wrPos, l); ret = AsconWriteChars(a->fd, GetCharArray(a->wrBuffer) + a->wrPos, l);
@ -382,56 +352,24 @@ int AsconStdHandler(Ascon * a)
break; break;
case AsconReading: case AsconReading:
ret = AsconReadChar(a->fd, &chr); ret = AsconReadChar(a->fd, &chr);
if (ret > 0) { if (ret <= 0) {
a->start = DoubleTime(); if (ret < 0) {
AsconError(a, "ASC5", errno);
if (a->replyTerminator != NULL) { return 0;
if (strchr(a->replyTerminator, chr) != NULL) { }
DynStringConcatChar(a->rdBuffer, chr); if (a->timeout > 0) {
DynStringConcatChar(a->rdBuffer, '\0'); if (DoubleTime() - a->start > a->timeout) {
a->state = AsconReadDone; AsconError(a, "no response", 0);
break; a->state = AsconTimeout;
}
} 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 (chr != 0) { return 0;
if (DynStringConcatChar(a->rdBuffer, chr) == 0) {
AsconError(a, "DynStringConcatChar failed:", ENOMEM);
break;
}
a->readState = 0;
}
} }
if (ret < 0) { a->lastChar = chr;
AsconError(a, "ASC5", errno); a->start = DoubleTime();
return 1; if (DynStringConcatChar(a->rdBuffer, chr) == 0) {
} AsconError(a, "ASC6", errno);
if (a->state == AsconReadDone) { return 0;
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;
}
} }
break; break;
default: default:
@ -440,8 +378,6 @@ int AsconStdHandler(Ascon * a)
return 1; return 1;
} }
static AsconProtocol *protocols = NULL;
void AsconInsertProtocol(AsconProtocol *protocol) { void AsconInsertProtocol(AsconProtocol *protocol) {
protocol->next = protocols; protocol->next = protocols;
protocols = protocol; protocols = protocol;
@ -472,6 +408,88 @@ AsconHandler AsconSetHandler(Ascon *a, SConnection *con,
return NULL; 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 ---- */ /* --- implementation of higher level interface ---- */
char *ConcatArgs(int argc, char *argv[]) char *ConcatArgs(int argc, char *argv[])
@ -489,6 +507,15 @@ Ascon *AsconMake(SConnection * con, int argc, char *argv[])
SCWrite(con, "ERROR: no memory", eError); SCWrite(con, "ERROR: no memory", eError);
return NULL; 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); a->handler = AsconSetHandler(a, con, argc, argv);
if (a->handler == NULL) { if (a->handler == NULL) {
args = ConcatArgs(argc, argv); args = ConcatArgs(argc, argv);
@ -501,7 +528,7 @@ Ascon *AsconMake(SConnection * con, int argc, char *argv[])
a->rdBuffer = CreateDynString(60, 63); a->rdBuffer = CreateDynString(60, 63);
a->wrBuffer = CreateDynString(60, 63); a->wrBuffer = CreateDynString(60, 63);
a->errmsg = CreateDynString(60, 63); a->errmsg = CreateDynString(60, 63);
a->responseValid = 0;
return a; return a;
} }

65
ascon.i
View File

@ -51,25 +51,26 @@ typedef int (* AsconHandler)(Ascon *connection);
* all members are public, allowing access by handler wrappers * all members are public, allowing access by handler wrappers
*/ */
struct Ascon { struct Ascon {
AsconState state; /**< the current state */ AsconState state; /**< the current state */
int fd; /**< socket */ int fd; /**< socket */
int readState; /**< default implementation: 'was cr' */ int readState; /**< default implementation: 'was cr' */
pDynString rdBuffer;/**< read buffer */ pDynString rdBuffer; /**< read buffer */
pDynString wrBuffer;/**< write buffer */ pDynString wrBuffer; /**< write buffer */
int wrPos; /**< write buffer position */ int wrPos; /**< write buffer position */
double timeout; /**< read timeout (sec) */ double timeout; /**< read timeout (sec) */
char *sendTerminator; /**< terminator for sending messages */ char *sendTerminator; /**< terminator for sending messages */
char *replyTerminator; /**< terminator list for reply. NULL is the special case CR, LF or CR/LF */ char *replyTerminator; /**< terminator list for reply. NULL is the special case CR, LF or CR/LF */
char *hostport; /**< host:port to connect */ char *hostport; /**< host:port to connect */
pDynString errmsg; /**< error message */ pDynString errmsg; /**< error message */
double start; /**< unix time when read was started */ double start; /**< unix time when read was started */
void *private; /**< private data of protocol */ void *private; /**< private data of protocol */
void (*killPrivate)(void *); /** < kill function for private */ void (*killPrivate)(void *); /** < kill function for private */
int noResponse; /**< no response expected */ int noResponse; /**< no response expected */
int responseValid; /**< a valid response is ready */ int responseValid; /**< a valid response is ready */
AsconHandler handler; /**< handler function */ AsconHandler handler; /**< handler function */
double reconnectInterval; /**< reconnect interval */ double reconnectInterval; /**< reconnect interval */
double lastReconnect; /**< last reconnect try */ double lastReconnect; /**< last reconnect try */
char lastChar; /**< last char read */
}; };
#define ASCON_SELECT_ERROR -1 #define ASCON_SELECT_ERROR -1
@ -77,14 +78,25 @@ struct Ascon {
#define ASCON_SEND_ERROR -3 #define ASCON_SEND_ERROR -3
#define ASCON_DISCONNECTED -4 #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. /** \brief the standard handler routine.
* \param a the connection * \param a the connection
* \return 0 when it makes sense to call the handler again immediately * \return see AsconBaseHandler
* (for example while reading, after a character was read, as
* there may be more chars in the buffer)
* 1 else
* *
* In most cases a custom handler may be a wrapper around AsconStdHandler * features: see description of AsconStdInit
*/ */
int AsconStdHandler(Ascon *a); int AsconStdHandler(Ascon *a);
@ -94,12 +106,13 @@ int AsconStdHandler(Ascon *a);
* \param argc number of arguments * \param argc number of arguments
* \param argv arguments ("<host>:<port>" [sendTerminator] [timeout] [replyTerminators]) * \param argv arguments ("<host>:<port>" [sendTerminator] [timeout] [replyTerminators])
* sendTerminator is a character or string sent at the end of a command * 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 * 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 * 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[]); int AsconStdInit(Ascon *a, SConnection *con, int argc, char *argv[]);

View File

@ -233,15 +233,13 @@ int exeBufProcess(pExeBuf self, SicsInterp * pSics,
SCPrintf(pCon, eLogError, "ERROR: Tcl reported: %s", SCPrintf(pCon, eLogError, "ERROR: Tcl reported: %s",
pTcl->result); 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 { } else {
if(strstr(pTcl->result, "ERROR") != NULL){ SCWrite(pCon, pTcl->result, eError);
SCPrintf(pCon,eError,"%s occurred in %s", pTcl->result, cmd );
}
pCon->sicsError = 0; 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); DeleteDynString(command);
if (SCGetInterrupt(pCon) >= eAbortBatch) { if (SCGetInterrupt(pCon) >= eAbortBatch) {

2
lld.c
View File

@ -69,7 +69,7 @@ static int ListInit(int List, int ItemSize)
if (0 != ItemSize) { if (0 != ItemSize) {
/* create dummy head node /* create dummy head node
*/ */
Fortify_CheckAllMemory(); (void)Fortify_CheckAllMemory();
Tmp = NODE_MALLOC(List); Tmp = NODE_MALLOC(List);
if (NULL == Tmp) { if (NULL == Tmp) {
return ERR_MEMORY; return ERR_MEMORY;

View File

@ -28,6 +28,8 @@ typedef struct ScriptContext {
ObjectDescriptor *desc; ObjectDescriptor *desc;
ContextItem *nodes; ContextItem *nodes;
ContextItem *trash; ContextItem *trash;
Hdb *sendNode;
int sendCalled;
} ScriptContext; } ScriptContext;
struct SctController { struct SctController {
@ -152,7 +154,6 @@ int SctCommand(SConnection * con, SicsInterp * sics, void *object,
Hdb *cNode = NULL; Hdb *cNode = NULL;
hdbValue v; hdbValue v;
double dtime; double dtime;
int iMacro;
assert(sct == object); assert(sct == object);
if (sct->nodes != NULL) { if (sct->nodes != NULL) {
@ -190,14 +191,13 @@ int SctCommand(SConnection * con, SicsInterp * sics, void *object,
* print * print
*/ */
if (strcmp(argv[1], "print") == 0) { if (strcmp(argv[1], "print") == 0) {
iMacro = con->iMacro;
if (queueData != NULL) { if (queueData != NULL) {
queueData->answered = 1; 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); Arg2Text(argc - 2, argv + 2, value, sizeof value);
SCWrite(con, value, eWarning); SCWrite(con, value, eWarning);
con->iMacro = iMacro; SCsetMacro(con, 1); /* where are always in Macro */
return 1; return 1;
} }
@ -223,6 +223,19 @@ int SctCommand(SConnection * con, SicsInterp * sics, void *object,
return 1; 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 * property handling
*/ */
@ -265,6 +278,13 @@ int SctCallInContext(SConnection * con, char *script, Hdb * node,
ret = Tcl_EvalEx(pTcl, script, l, 0); ret = Tcl_EvalEx(pTcl, script, l, 0);
result = (char *) Tcl_GetStringResult(pTcl); result = (char *) Tcl_GetStringResult(pTcl);
if (ret != TCL_OK && result[0] != '\0') { 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) { if (verbose) {
SCPrintf(con, eLog, "error: %s", result); SCPrintf(con, eLog, "error: %s", result);
} }
@ -306,7 +326,9 @@ static char *SctActionHandler(void *actionData, char *lastReply,
char *emsg; char *emsg;
size_t l; size_t l;
int cnt; int cnt;
int ret;
char timeKey[50], timeVal[50]; char timeKey[50], timeVal[50];
int iMacro;
if (queueData != NULL && queueData->conCtx != NULL) { if (queueData != NULL && queueData->conCtx != NULL) {
con = queueData->conCtx; con = queueData->conCtx;
@ -325,9 +347,6 @@ static char *SctActionHandler(void *actionData, char *lastReply,
SetProp(node, controller->node, "state", state); SetProp(node, controller->node, "state", state);
} }
for (i = 0; i < 10; i++) { 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); script = GetProp(node, controller->node, state);
if (script == NULL) if (script == NULL)
script = state; script = state;
@ -339,11 +358,12 @@ static char *SctActionHandler(void *actionData, char *lastReply,
commError = 0; commError = 0;
} }
script = strdup(script); 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); snprintf(eprop, sizeof eprop, "error_during_%s", data->name);
if (strncmp(result, "ERROR: ", 7) == 0) {
result += 7;
}
emsg = GetHdbProp(node, eprop); emsg = GetHdbProp(node, eprop);
if (emsg == NULL || con != controller->conn) { if (emsg == NULL || con != controller->conn) {
GetHdbPath(node, path, sizeof path); GetHdbPath(node, path, sizeof path);
@ -366,7 +386,7 @@ static char *SctActionHandler(void *actionData, char *lastReply,
sscanf(emsg, "%d", &cnt); sscanf(emsg, "%d", &cnt);
} }
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); SetHdbProperty(node, eprop, msg);
send = NULL; send = NULL;
free(script); free(script);
@ -375,7 +395,12 @@ static char *SctActionHandler(void *actionData, char *lastReply,
state = result; state = result;
if (strcasecmp(state, "idle") == 0 || strcasecmp(state, "unpoll") == 0) { if (strcasecmp(state, "idle") == 0 || strcasecmp(state, "unpoll") == 0) {
if (queueData == data && !data->answered) { 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); snprintf(eprop, sizeof eprop, "error_during_%s", data->name);
emsg = GetHdbProp(node, eprop); emsg = GetHdbProp(node, eprop);
@ -396,8 +421,10 @@ static char *SctActionHandler(void *actionData, char *lastReply,
SetProp(node, controller->node, "state", state); SetProp(node, controller->node, "state", state);
free(script); free(script);
script = NULL; script = NULL;
send = GetProp(node, controller->node, "send"); if (sct->sendCalled) {
if (send != NULL && send[0] != '\0') { send = GetProp(node, controller->node, "send");
if (send == NULL)
send = "";
if (controller->verbose) { if (controller->verbose) {
SCPrintf(con, eLog, "send : %s", send); SCPrintf(con, eLog, "send : %s", send);
} }
@ -522,6 +549,8 @@ static hdbCallbackReturn SctActionCallback(Hdb * node, void *userData,
char *error; char *error;
SConnection *con; SConnection *con;
char path[MAX_HDB_PATH]; char path[MAX_HDB_PATH];
char *sicsCommand;
int iMacro;
pm = GetKillPtrMessage(msg); pm = GetKillPtrMessage(msg);
if (pm != NULL) { if (pm != NULL) {
@ -554,7 +583,7 @@ static hdbCallbackReturn SctActionCallback(Hdb * node, void *userData,
if (script != NULL) { if (script != NULL) {
if (SctCallInContext(con, script, node, data->controller, &error) == if (SctCallInContext(con, script, node, data->controller, &error) ==
0) { 0) {
SCPrintf(con, eError, "ERROR: %s", error); SCPrintf(con, eError, "ERROR: in {%s}: %s", script, error);
SetHdbProperty(node, "target", NULL); SetHdbProperty(node, "target", NULL);
return hdbAbort; return hdbAbort;
} }
@ -574,16 +603,19 @@ static hdbCallbackReturn SctActionCallback(Hdb * node, void *userData,
} }
if (data->conCtx != NULL) { if (data->conCtx != NULL) {
GetHdbPath(node, path, sizeof path); if (data->inMacro == 0) {
SCPrintf(data->conCtx, eWarning, GetHdbPath(node, path, sizeof path);
"%s target changed to %s before completion", path, SCsetMacro(data->conCtx, 0);
GetCharArray(text)); SCPrintf(data->conCtx, eWarning,
"%s target changed to %s before completion", path,
GetCharArray(text));
}
SCDeleteConnection(data->conCtx); SCDeleteConnection(data->conCtx);
} }
DeleteDynString(text); DeleteDynString(text);
data->conCtx = SCCopyConnection(con); data->conCtx = SCCopyConnection(con);
data->answered = 0; data->answered = 0;
data->inMacro = con->iMacro; data->inMacro = SCinMacro(con);
DevQueue(data->controller->devser, data, prio, DevQueue(data->controller->devser, data, prio,
SctWriteHandler, SctMatch, NULL); SctWriteHandler, SctMatch, NULL);
/* no kill function in DevQueue: data is owned by the node (callback list) */ /* 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 (mm != NULL) {
if (queueData != NULL && queueData->conCtx != NULL && !data->answered) { if (queueData != NULL && queueData->conCtx != NULL && !data->answered) {
/* update called from a write action */ /* update called from a write action */
data->answered = 1;
GetHdbPath(node, path, sizeof path);
text = formatValue(*(mm->v), node); 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); DeleteDynString(text);
} }
return hdbContinue; return hdbContinue;
@ -1137,6 +1179,7 @@ static int SctMakeController(SConnection * con, SicsInterp * sics,
return 0; return 0;
SetHdbProperty(controller->node, "controllerName", objName); SetHdbProperty(controller->node, "controllerName", objName);
SetHdbProperty(controller->node, "sicsdev", objName);
AddCommand(pServ->pSics, objName, InterInvokeSICSOBJ, KillSICSOBJ, ccmd); AddCommand(pServ->pSics, objName, InterInvokeSICSOBJ, KillSICSOBJ, ccmd);
RegisterSICSOBJKillCmd(ccmd, objName); RegisterSICSOBJKillCmd(ccmd, objName);

View File

@ -381,6 +381,7 @@ int SctMakeDriveObject(SConnection * pCon, SicsInterp * pSics,
SetDescriptorKey(pNew->pDes, "creationCommand", "0"); SetDescriptorKey(pNew->pDes, "creationCommand", "0");
RegisterSICSOBJKillCmd(pNew, argv[1]); RegisterSICSOBJKillCmd(pNew, argv[1]);
} }
SetHdbProperty(pNew->objectNode, "sicsdev", argv[1]);
status = AddCommand(pSics, status = AddCommand(pSics,
argv[1], InterInvokeSICSOBJ, KillDriveOBJ, pNew); argv[1], InterInvokeSICSOBJ, KillDriveOBJ, pNew);
if (status != 1) { if (status != 1) {

View File

@ -12,12 +12,38 @@
#define MAX_HDB_PATH 1024 #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, static int MakePlainNode(pHdb parent, char *name, SConnection * pCon,
int argc, char *argv[]) int argc, char *argv[])
{ {
pHdb child = NULL; pHdb child = NULL;
int type = 0, length = 0, priv = -1; int type = 0, length = 0, priv = -1;
hdbValue val; hdbValue val;
pDynString sicsCommand = NULL;
if (argc < 5) { if (argc < 5) {
SCWrite(pCon, "ERROR: not enough arguments to create plain node", SCWrite(pCon, "ERROR: not enough arguments to create plain node",
@ -68,6 +94,13 @@ static int MakePlainNode(pHdb parent, char *name, SConnection * pCon,
} }
AddHipadabaChild(parent, child, pCon); AddHipadabaChild(parent, child, pCon);
if (type != HIPNONE) {
sicsCommand = ComposeSicsCommand(child);
if (sicsCommand) {
SetHdbProperty(child, "sicscommand", GetCharArray(sicsCommand));
DeleteDynString(sicsCommand);
}
}
SCSendOK(pCon); SCSendOK(pCon);
return 1; return 1;
} }

View File

@ -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]; char par[128];
pDynString val = NULL; pDynString dyn = NULL;
int i;
pHdb child;
char *vis;
snprintf(par, 40, "%-20s = ", node->name); snprintf(par, sizeof par, "%-20s = ", prefix);
DynStringConcat(data, par); DynStringConcat(data, par);
val = formatValue(node->value, node); dyn = formatValue(node->value, node);
if (val != NULL) { if (dyn != NULL) {
DynStringConcat(data, GetCharArray(val)); DynStringConcat(data, GetCharArray(dyn));
DynStringConcatChar(data, '\n'); } else {
DeleteDynString(val); 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, static int ListObj(pSICSOBJ self, SConnection * pCon, int argc,
char *argv[]) char *argv[])
{ {
pHdb node = NULL;
pDynString data; pDynString data;
data = CreateDynString(128, 128); data = CreateDynString(128, 128);
if (data == NULL) { if (data == NULL) {
return 0; return 0;
} }
node = self->pDes->parNode; if (self->pDes->parNode != NULL) {
if (node != NULL) { objFormatNode(self->pDes->parNode, ' ', argv[0], data);
objFormatNode(node, data);
node = node->child;
while (node != NULL) {
objFormatNode(node, data);
node = node->next;
}
} }
SCWrite(pCon, GetCharArray(data), eValue); SCWrite(pCon, GetCharArray(data), eValue);
DeleteDynString(data); DeleteDynString(data);
@ -440,7 +445,7 @@ int InvokeSICSOBJ(SConnection * pCon, SicsInterp * pSics, void *pData,
} else if (strcmp(argv[1], "list") == 0) { } else if (strcmp(argv[1], "list") == 0) {
return ListObj(self, pCon, argc, argv); 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; return status;
@ -508,7 +513,7 @@ pSICSOBJ SetupSICSOBJ(SConnection * pCon, SicsInterp * pSics, void *pData,
SetDescriptorKey(pNew->pDes, "creationCommand", "0"); SetDescriptorKey(pNew->pDes, "creationCommand", "0");
} }
SetHdbProperty(pNew->objectNode, "objectName", argv[1]); SetHdbProperty(pNew->objectNode, "sicsdev", argv[1]);
status = AddCommand(pSics, status = AddCommand(pSics,
argv[1], InterInvokeSICSOBJ, KillSICSOBJ, pNew); argv[1], InterInvokeSICSOBJ, KillSICSOBJ, pNew);
if (status != 1) { if (status != 1) {