- allow scriptcontext objects to be dynamic

- enhancements in scriptcontext (error messages stored as properties)
This commit is contained in:
zolliker
2009-02-19 13:30:32 +00:00
parent 981534624f
commit 35f2b6b810
33 changed files with 753 additions and 310 deletions

View File

@ -213,7 +213,9 @@ int RemoveCommand(SicsInterp * pInterp, char *pName)
/* found, remove it */
/* kall KillFunction first */
if (pVictim->KFunc) {
pVictim->KFunc(pVictim->pData);
void *data = pVictim->pData;
pVictim->pData = NULL; /* make data unreachable by FindCommandData before killing */
pVictim->KFunc(data);
}
/* delete and unlink data */
@ -237,7 +239,6 @@ int RemoveCommand(SicsInterp * pInterp, char *pName)
return 1;
}
#define MAXLEN 256
#define MAXCOM 50
extern char *stptok(char *s, char *tok, unsigned int toklen, char *brk);
@ -1047,10 +1048,9 @@ char *FindAliases(SicsInterp * pSics, char *name)
}
/*---------------------------------------------------------------------*/
void
ForEachCommand(int (*scanFunction)
(char *name, pDummy object, void *userData)
, void *userData)
void ForEachCommand(int (*scanFunction)
(char *name, pDummy object, void *userData)
, void *userData)
{
CommandList *pCurrent;

162
ascon.c
View File

@ -14,6 +14,8 @@
#include "ascon.i"
#include "uselect.h"
static double lastClose = 0; /* time of last close operation */
/*
CreateSocketAdress stolen from Tcl. Thanks to John Ousterhout
*/
@ -60,10 +62,10 @@ double DoubleTime(void)
return now.tv_sec + now.tv_usec / 1e6;
}
void AsconError(Ascon * a, char *msg, int errorno)
void AsconError(Ascon *a, char *msg, int errorno)
{
static char *stateText[] = {
"state 0", "kill", "state 2", "notConnected",
static char *stateText[]={
"state 0", "state 1", "state 2", "notConnected",
"connect", "start connect", "connect finished", "connect failed",
"write", "start write", "write finished", "write failed",
"read", "start read", "read finished", "read failed",
@ -76,13 +78,19 @@ void AsconError(Ascon * a, char *msg, int errorno)
} else {
state = stateText[a->state];
}
if (errorno != 0) {
a->errList =
ErrPutMsg(a->errList, "ASCERR: %s %s (during %s)", msg,
strerror(errorno), state);
DynStringCopy(a->errmsg, "ASCERR: ");
if (errorno == 0) {
DynStringConcat(a->errmsg, msg);
DynStringConcat(a->errmsg, " (");
DynStringConcat(a->errmsg, state);
DynStringConcat(a->errmsg, " state)");
} else {
a->errList =
ErrPutMsg(a->errList, "ASCERR: %s (during %s)", msg, state);
DynStringConcat(a->errmsg, strerror(errorno));
DynStringConcat(a->errmsg, " (");
DynStringConcat(a->errmsg, state);
DynStringConcat(a->errmsg, " state, ");
DynStringConcat(a->errmsg, msg);
DynStringConcat(a->errmsg, ")");
}
a->state |= AsconFailed;
}
@ -97,10 +105,22 @@ static void AsconConnect(Ascon * a)
int port;
int oldopts;
/* wait 0.5 sec before connecting again after a close
2 reasons for that:
- it seems that connecting immediately to a closed port fails.
We will avoid some "Connection refused" error messages.
- a bug in the lantronix terminal: if a channel is closed and reopened
within short time the connect may be succesful, but a message will be
sent on the channel!
In principle we need only to wait when connecting to the same address
and port, but bookkeeping would be too complicated.
*/
if (DoubleTime() < lastClose + 0.5) return;
if (a->fd < 0) {
a->fd = socket(AF_INET, SOCK_STREAM, 0);
if (a->fd < 0) {
AsconError(a, "socket failed:", errno);
AsconError(a, "ASC1", errno);
return;
}
}
@ -119,20 +139,19 @@ static void AsconConnect(Ascon * a)
AsconError(a, "bad host specification", 0);
return;
}
/* should we insert the workaround for lantronix server ? see network.c */
oldopts = fcntl(a->fd, F_GETFL, 0);
fcntl(a->fd, F_SETFL, oldopts | O_NONBLOCK);
ret =
connect(a->fd, (struct sockaddr *) &adr, sizeof(struct sockaddr_in));
if (ret < 0) {
switch (errno) {
switch(errno) {
case EINPROGRESS:
case EALREADY:
case EISCONN:
a->state = AsconConnecting;
break;
default:
AsconError(a, "connect failed:", errno);
AsconError(a, "ASC2", errno);
return;
}
}
@ -140,11 +159,10 @@ static void AsconConnect(Ascon * a)
return;
}
int AsconStdInit(Ascon * a, SConnection * con, int argc, char *argv[])
int AsconStdInit(Ascon *a, SConnection *con, int argc, char *argv[])
{
a->fd = -1;
a->state = AsconConnectStart;
a->reconnectInterval = 10;
a->hostport = strdup(argv[1]);
if (argc > 2) {
a->sendTerminator = strdup(argv[2]);
@ -154,7 +172,11 @@ int AsconStdInit(Ascon * a, SConnection * con, int argc, char *argv[])
if (argc > 3) {
a->timeout = atof(argv[3]);
} else {
a->timeout = 2.0; /* sec */
a->timeout = 2.0; /* sec */
}
a->replyTerminator == NULL;
if (argc > 4 && argv[4][0] != '\0') {
a->replyTerminator = strdup(argv[4]);
}
return 1;
}
@ -172,9 +194,11 @@ int AsconReadGarbage(int fd)
FD_SET(fd, &rmask);
ret = uselect(fd + 1, &rmask, NULL, NULL, &tmo);
if (ret > 0) {
l = recv(fd, garbage, sizeof garbage, 0);
l = recv(fd, garbage, sizeof garbage - 1, 0);
if (l > 0) {
/* swallow */
garbage[l] = '\0';
printf("(((%s)))\n", garbage);
result += l;
} else if (l == 0) {
errno = ECONNRESET;
@ -307,7 +331,7 @@ int AsconStdHandler(Ascon * a)
} else if (ret > 0) {
a->state = AsconConnectDone; /* success */
} else if (ret < 0) {
AsconError(a, "AsconConnectSuccess failed:", errno);
AsconError(a, "ASC3", errno);
}
break;
case AsconWriteStart:
@ -320,13 +344,22 @@ int AsconStdHandler(Ascon * a)
}
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);
if (ret < 0) {
if (errno != EINTR && errno != EAGAIN) {
AsconError(a, "send failed:", errno);
}
AsconError(a, "ASC4", errno);
/*
* Ooops: which state shall we go to after a write fail?
* This seems to retry.
@ -348,22 +381,32 @@ int AsconStdHandler(Ascon * a)
while (ret > 0) {
a->start = DoubleTime();
if (chr == '\n') {
if (a->readState) {
/* swallow LF after CR */
DynStringClear(a->rdBuffer);
a->readState = 0;
} else {
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 == '\r') {
a->readState = 1;
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 (chr != 0) {
if (DynStringConcatChar(a->rdBuffer, chr) == 0) {
AsconError(a, "DynStringConcatChar failed:", ENOMEM);
break;
@ -375,7 +418,7 @@ int AsconStdHandler(Ascon * a)
if (ret < 0) {
/* EINTR means we shall retry */
if (errno != EINTR && errno != EAGAIN) {
AsconError(a, "AsconReadChar failed:", errno);
AsconError(a, "ASC5", errno);
}
return 1;
}
@ -384,30 +427,26 @@ int AsconStdHandler(Ascon * a)
} else {
if (a->timeout > 0) {
if (DoubleTime() - a->start > a->timeout) {
AsconError(a, "read timeout", 0);
AsconError(a, "no response", 0);
a->state = AsconTimeout;
}
}
}
break;
default:
return 1;
break;
}
return 1;
}
/* define type AsconProtocolList and functions AsconProtocolAdd etc. */
#define MC_NAME(T) AsconProtocol##T
#include "mclist.c"
static AsconProtocol *protocols = NULL;
static AsconProtocolList protocols = { 0 };
void AsconInsertProtocol(AsconProtocol * protocol)
{
AsconProtocolAdd(&protocols, protocol);
void AsconInsertProtocol(AsconProtocol *protocol) {
protocol->next = protocols;
protocols = protocol;
}
AsconHandler AsconSetHandler(Ascon * a, SConnection * con,
AsconHandler AsconSetHandler(Ascon *a, SConnection *con,
int argc, char *argv[])
{
AsconProtocol *p;
@ -420,7 +459,7 @@ AsconHandler AsconSetHandler(Ascon * a, SConnection * con,
AsconStdInit(a, con, argc, argv);
return AsconStdHandler;
}
for (p = protocols.head; p != NULL; p = p->next) {
for (p = protocols; p!= NULL; p=p->next) {
if (strcasecmp(p->name, argv[0]) == 0) {
if (p->init(a, con, argc, argv)) {
return p->handler;
@ -460,10 +499,8 @@ Ascon *AsconMake(SConnection * con, int argc, char *argv[])
}
a->rdBuffer = CreateDynString(60, 63);
a->wrBuffer = CreateDynString(60, 63);
a->errList = NULL;
a->errmsg = CreateDynString(60, 63);
a->responseValid = 0;
a->reconnectInterval = 10;
a->lastReconnect = 0;
return a;
}
@ -471,15 +508,20 @@ void AsconKill(Ascon * a)
{
if (a->fd > 0) {
close(a->fd);
lastClose = DoubleTime();
}
DeleteDynString(a->rdBuffer);
DeleteDynString(a->wrBuffer);
DeleteDynString(a->errmsg);
if (a->hostport) {
free(a->hostport);
}
if (a->sendTerminator) {
if(a->sendTerminator){
free(a->sendTerminator);
}
if(a->replyTerminator){
free(a->replyTerminator);
}
if (a->private != NULL && a->killPrivate != NULL) {
a->killPrivate(a->private);
}
@ -528,17 +570,15 @@ AsconStatus AsconTask(Ascon * a)
case AsconStart:
return AsconPending;
case AsconFailed:
if (a->state != AsconTimeout) {
now = DoubleTime();
if (now > a->lastReconnect + a->reconnectInterval) {
a->lastReconnect = now;
close(a->fd);
/* allow the system to cleanup the socket, otherwise a reconnect will fail */
sleep(1);
a->fd = -1;
a->state = AsconConnectStart;
}
if (a->state == AsconTimeout) {
a->state = AsconIdle;
} else {
close(a->fd);
lastClose = DoubleTime();
a->fd = -1;
a->state = AsconConnectStart;
}
return AsconFailure;
case AsconFinished:
if (a->state < AsconConnectFailed) {
@ -580,7 +620,7 @@ char *AsconRead(Ascon * a)
return NULL;
}
ErrMsg *AsconGetErrList(Ascon * a)
char *AsconGetError(Ascon *a)
{
return a->errList;
return GetCharArray(a->errmsg);
}

15
ascon.h
View File

@ -2,7 +2,6 @@
#define ASCON_H
#include "sics.h"
#include "errormsg.h"
/** \file
* \brief Asynchronous connection handling for devices controlled over tcp-ip
@ -60,15 +59,17 @@ int AsconWrite(Ascon * a, char *command, int noResponse);
* \return the response when a response is ready
* NULL when the command has not completed and the response is not yet finished
* "" when the command has completed, but no response was expected.
* The result is only valid until the next call to other AsconXxx functions
* and has to be duplicated if needed later.
* The result is only valid until the next call to any AsconXxx function
* with the same connection and has to be duplicated if needed later.
*/
char *AsconRead(Ascon * a);
/** \brief get the connections error list
* \return the error list
/** \brief get the last error message
* \return the error message
* The result is only valid until the next call to any AsconXxx function
* with the same connection and has to be duplicated if needed later.
*/
ErrMsg *AsconGetErrList(Ascon * a);
char *AsconGetError(Ascon *a);
/** \brief a helper function
* \param argc the number of args
@ -78,7 +79,7 @@ ErrMsg *AsconGetErrList(Ascon * a);
*/
char *ConcatArgs(int argc, char *argv[]);
/** \brief function for dealing with times with musec resolution
/** \brief function for dealing with times with microsec resolution
* \return absolute time as double value
*/
double DoubleTime(void);

14
ascon.i
View File

@ -12,7 +12,7 @@
* For the implementation of a custom protocol, you have to implement
* the handler function and the init function, declare the protocol
* of type AsconProtocol and call AsconInsertProtocol on startup.
* The handler and init functions are normally be a wrapper around AsconStdHandler
* The handler and init functions are normally a wrapper around AsconStdHandler
* and AsconStdInit
*
* The functions with fd as the first argument are utility functions with
@ -64,8 +64,9 @@ struct Ascon {
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 */
ErrMsg *errList; /**< error message list */
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 */
@ -73,7 +74,6 @@ struct Ascon {
int responseValid; /**< a valid response is ready */
AsconHandler handler; /**< handler function */
double reconnectInterval; /**< reconnect interval */
double lastReconnect; /**< last connect try */
};
#define ASCON_SELECT_ERROR -1
@ -92,7 +92,13 @@ int AsconStdHandler(Ascon *a);
/** \brief initialize a standard connection
* \param a the connection
* \param con A connection to print errors too.
* \param hostport the tcp/ip address (syntax: host:port)
* \param argc number of arguments
* \param argv arguments ("<host>:<port>" [sendTerminator] [timeout] [replyTerminators])
* sendTerminator is a character or string sent at the end of a command
* timoeut 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
*
* In most cases a custom init function may be a wrapper around AsconStdInit
*/

View File

@ -89,7 +89,6 @@ void WriteToCommandLogId(char *prompt, int id, char *text)
return;
strncpy(pCopy, text, l);
pCopy[l] = '\0';
if (prompt == cmdPrompt && iCompact) {
pPtr = strstr(pCopy, "fulltransact ");
if (pPtr && pPtr < pCopy + 3) {
@ -101,17 +100,30 @@ void WriteToCommandLogId(char *prompt, int id, char *text)
}
}
now = time(NULL);
/* create tail buffer as needed */
if (!pTail) {
pTail = createCircular(MAXTAIL, free);
}
now = time(NULL);
doStamp = 0;
doStampId = 0;
if (id == NOID) {
if (iCompact == 1) {
nowTm = localtime(&now);
strftime(stamp1, sizeof stamp1, "%H:%M:%S", nowTm);
if (prompt == NULL)
prompt = "";
if (id == NOID) {
if (!prompt)
prompt = " ";
snprintf(buffer, sizeof buffer, "%s %s ", stamp1, prompt);
} else {
snprintf(buffer, sizeof buffer, "%s %2.0d| ", stamp1, id);
}
prompt = buffer;
} else if (id == NOID) {
if (!prompt) {
prompt = "";
} else {
@ -125,7 +137,7 @@ void WriteToCommandLogId(char *prompt, int id, char *text)
snprintf(buffer, sizeof buffer, "sock %d>%s ", id, prompt);
}
prompt = buffer;
} else {
} else if (iCompact > 1) {
if (id != lastId) {
lastId = id;
doStampId = 1;
@ -138,7 +150,7 @@ void WriteToCommandLogId(char *prompt, int id, char *text)
}
}
if (iCompact > 0) { /* write time stamp */
if (iCompact > 1) { /* write time stamp */
if (now / iCompact != lastStamp / iCompact) {
doStamp = 1;
doStampId = 1;

View File

@ -788,6 +788,40 @@ int StopExe(pExeList self, char *name)
return 0;
}
/*-------------------------------------------------------------------------*/
int StopByData(pExeList self, void *data)
{
int iRet;
pDevEntry pDev = NULL;
pIDrivable pDrivInt = NULL;
pICountable pCountInt = NULL;
iRet = LLDnodePtr2First(self->iList);
while (iRet != 0) {
pDev = (pDevEntry) LLDnodePtr(self->iList);
if (pDev) {
if (pDev->pData == data) {
pDrivInt = pDev->pDescriptor->GetInterface(pDev->pData, DRIVEID);
pCountInt = pDev->pDescriptor->GetInterface(pDev->pData, COUNTID);
if (pDrivInt) {
pDrivInt->Halt(pDev->pData);
} else if (pCountInt) {
pCountInt->Halt(pDev->pData);
}
ExeInterest(self, pDev, "finished");
DevexecLog("FINISHED", pDev->name);
DeleteDevEntry(pDev);
LLDnodeDelete(self->iList);
self->iStatus = DEVDONE;
SCWrite(self->pOwner, "", eFinish);
return 1;
}
}
iRet = LLDnodePtr2Next(self->iList);
}
return 0;
}
/*-------------------------------------------------------------------------*/
int StopExeWait(pExeList self)
{
@ -795,7 +829,6 @@ int StopExeWait(pExeList self)
Wait4Success(self);
return 1;
}
/*--------------------------------------------------------------------------*/
int PauseExecution(pExeList self)
{
@ -1006,7 +1039,6 @@ int SicsIdle(SConnection * pCon, SicsInterp * pSics, void *pData,
Usage:
Success
*/
int Success(SConnection * pCon, SicsInterp * pSics, void *pData,
int argc, char *argv[])
{
@ -1020,6 +1052,8 @@ int Success(SConnection * pCon, SicsInterp * pSics, void *pData,
if (SCGetInterrupt(pCon) == eAbortOperation) {
SCSetInterrupt(pCon, eContinue);
iRet = 0;
} else {
iRet = 1;
}
} else if (iRet == DEVDONE) {
SCWrite(pCon, "All done", eValue);
@ -1031,7 +1065,6 @@ int Success(SConnection * pCon, SicsInterp * pSics, void *pData,
SetStatus(eEager);
return iRet;
}
/*-------------------------------------------------------------------------*/
int PauseAction(SConnection * pCon, SicsInterp * pSics, void *pData,
int argc, char *argv[])

View File

@ -1,5 +1,5 @@
#line 195 "devexec.w"
#line 197 "devexec.w"
/*----------------------------------------------------------------------------
@ -54,7 +54,7 @@ int StartMotor(pExeList self, SicsInterp * pSics, SConnection * pCon,
int StartCounter(pExeList self, SicsInterp * pSics, SConnection * pCon,
char *name);
#line 239 "devexec.w"
#line 241 "devexec.w"
/*------------------------------------------------------------------------*/
@ -73,7 +73,7 @@ int DevExecTask(void *pEL);
void DevExecSignal(void *pEL, int iSignal, void *pSigData);
#line 241 "devexec.w"
#line 243 "devexec.w"
/*
@ -104,6 +104,9 @@ int StopExeWait(pExeList self);
StopExeWait will stop all running things and wait for the stop
to complete.
*/
int StopByData(pExeList self, void *data);
/* stop the entry with the given data from execution */
/*------------------------------------------------------------------------*/
void ClearExecutor(pExeList self);
/*
@ -115,7 +118,7 @@ int PauseExecution(pExeList self);
int ContinueExecution(pExeList self);
#line 259 "devexec.w"
#line 261 "devexec.w"
/*-------------------------- Commands ------------------------------------*/
int DevexecAction(SConnection * pCon, SicsInterp * pSics, void *pData,
@ -157,16 +160,15 @@ int ContinueAction(SConnection * pCon, SicsInterp * pSics, void *pData,
/*--------------------------- Locking ---------------------------------*/
#line 183 "devexec.w"
#line 185 "devexec.w"
void LockDeviceExecutor(pExeList self);
void UnlockDeviceExecutor(pExeList self);
#line 299 "devexec.w"
#line 301 "devexec.w"
/* -------------------------- Executor management -------------------------*/
pExeList GetExecutor(void);
void SetExecutor(pExeList pExe);
/*----------------------- Logging -----------------------------------------*/

View File

@ -52,7 +52,7 @@ $\langle$devreg {\footnotesize ?}$\rangle\equiv$
\mbox{}\verb@ char *name, float fNew);@\\
\mbox{}\verb@ int StartCounter(pExeList self, SicsInterp *pSics, SConnection *pCon,@\\
\mbox{}\verb@ char *name); @\\
\mbox{}\verb@@$\diamond$
\mbox{}\verb@@$\Diamond$
\end{list}
\vspace{-1ex}
\footnotesize\addtolength{\baselineskip}{-1ex}
@ -115,7 +115,7 @@ $\langle$devcheck {\footnotesize ?}$\rangle\equiv$
\mbox{}\verb@ int DevExecTask(void *pEL);@\\
\mbox{}\verb@ void DevExecSignal(void *pEL, int iSignal, void *pSigData);@\\
\mbox{}\verb@@\\
\mbox{}\verb@@$\diamond$
\mbox{}\verb@@$\Diamond$
\end{list}
\vspace{-1ex}
\footnotesize\addtolength{\baselineskip}{-1ex}
@ -174,6 +174,8 @@ $\langle$devstop {\footnotesize ?}$\rangle\equiv$
\mbox{}\verb@ StopExeWait will stop all running things and wait for the stop@\\
\mbox{}\verb@ to complete.@\\
\mbox{}\verb@ */@\\
\mbox{}\verb@ int StopByData(pExeList self, void *data);@\\
\mbox{}\verb@ /* stop the entry with the given data from execution */@\\
\mbox{}\verb@/*------------------------------------------------------------------------*/@\\
\mbox{}\verb@ void ClearExecutor(pExeList self);@\\
\mbox{}\verb@ /*@\\
@ -184,7 +186,7 @@ $\langle$devstop {\footnotesize ?}$\rangle\equiv$
\mbox{}\verb@ int PauseExecution(pExeList self);@\\
\mbox{}\verb@ int ContinueExecution(pExeList self);@\\
\mbox{}\verb@@\\
\mbox{}\verb@@$\diamond$
\mbox{}\verb@@$\Diamond$
\end{list}
\vspace{-1ex}
\footnotesize\addtolength{\baselineskip}{-1ex}
@ -226,7 +228,7 @@ $\langle$devlock {\footnotesize ?}$\rangle\equiv$
\mbox{}\verb@ void LockDeviceExecutor(pExeList self);@\\
\mbox{}\verb@ void UnlockDeviceExecutor(pExeList self);@\\
\mbox{}\verb@@\\
\mbox{}\verb@@$\diamond$
\mbox{}\verb@@$\Diamond$
\end{list}
\vspace{-1ex}
\footnotesize\addtolength{\baselineskip}{-1ex}
@ -358,7 +360,7 @@ to the global SICS device executor.
\mbox{}\verb@/*----------------------- Logging -----------------------------------------*/@\\
\mbox{}\verb@ void DevexecLog(char *op, char *device); @\\
\mbox{}\verb@#endif @\\
\mbox{}\verb@@$\diamond$
\mbox{}\verb@@$\Diamond$
\end{list}
\vspace{-2ex}
\end{minipage}\\[4ex]

View File

@ -144,6 +144,8 @@ This is done via the following interface.
StopExeWait will stop all running things and wait for the stop
to complete.
*/
int StopByData(pExeList self, void *data);
/* stop the entry with the given data from execution */
/*------------------------------------------------------------------------*/
void ClearExecutor(pExeList self);
/*

View File

@ -24,14 +24,14 @@ struct DevSer {
DevAction *current;
int killCurrent;
DevAction *actions; /* the action queue */
DevAction *toKill; /* list of actions to be killed */
SchedHeader *headers;
ErrMsg *errmsg;
int steps;
int stopTask;
};
static char *devPrio[NumberOfPRIO] = {
"null", "slow", "read", "progress", "write", "halt"
"null", "slow", "read", "progress", "write", "halt", "start"
};
char *DevPrio2Text(DevPrio prio)
@ -100,6 +100,9 @@ DevAction *DevNextAction(DevSer * devser)
header->timeDue = (floor(now / header->interval) + 1)
* header->interval;
}
} else if (header->prio == StartPRIO && header->actions != NULL) {
/* special case: poll with StartPRIO pending: block all other actions */
return devser->current;
}
}
if (header->followingAction != NULL) {
@ -123,13 +126,18 @@ int DevQueueTask(void *ds)
AsconStatus status;
DevAction *action;
char *sendData;
char *replyData;
char *replyData = NULL;
if (devser->steps == 0)
return 1;
if (devser->stopTask) {
return 0;
}
/* deferred deallocation of removed actions */
DevFreeActionList(devser->toKill);
devser->toKill = NULL;
action = devser->current;
if (action == NULL) {
action = DevNextAction(devser);
@ -138,19 +146,16 @@ int DevQueueTask(void *ds)
while (action != NULL) {
status = AsconTask(devser->asyncConn);
if (status == AsconFailure) {
devser->errmsg = AsconGetErrList(devser->asyncConn);
} else if (status != AsconReady) {
replyData = AsconGetError(devser->asyncConn);
} else if (status == AsconReady) {
replyData = AsconRead(devser->asyncConn);
} else {
return 1;
}
if (devser->steps > 0) { /* debugging mode */
devser->steps--;
}
if (status == AsconFailure) {
replyData = devser->errmsg->text;
} else {
replyData = AsconRead(devser->asyncConn);
}
sendData = action->hdl(action->data, replyData);
sendData = action->hdl(action->data, replyData, (status == AsconFailure));
if (sendData != NULL) {
AsconWrite(devser->asyncConn, sendData, 0);
return 1;
@ -184,6 +189,7 @@ DevSer *DevMake(SConnection * con, int argc, char *argv[])
devser->actions = NULL;
devser->headers = NULL;
devser->stopTask = 0;
devser->toKill = NULL;
devser->steps = -1; /* no debugging by default */
TaskRegister(pServ->pTasker, DevQueueTask, NULL, DevKillTask, devser, 0);
return devser;
@ -216,6 +222,7 @@ void DevKill(DevSer * devser)
AsconKill(devser->asyncConn);
}
DevFreeActionList(devser->actions);
DevFreeActionList(devser->toKill);
h = devser->headers;
while (h != NULL) {
victim = h;
@ -223,6 +230,11 @@ void DevKill(DevSer * devser)
DevFreeActionList(victim->actions);
free(victim);
}
if (devser->killCurrent) {
if (devser->current->kill != NULL) devser->current->kill(devser->current);
devser->killCurrent = 0;
free(devser->current);
}
if (devser->stopTask) {
free(devser);
} else {
@ -286,9 +298,9 @@ int DevUnschedule(DevSer * devser, void *actionData,
cnt++;
/* remove from list */
*ptr2Last = action->next;
if (action->kill != NULL)
action->kill(action->data);
free(action);
/* add to kill list */
action->next = devser->toKill;
devser->toKill = action;
} else {
ptr2Last = &action->next;
}
@ -364,8 +376,9 @@ int DevRemoveAction(DevSer * devser, void *actionData)
int cnt = 0;
/* Remove current action, if matched. If a reply is pending, the next action will
get the reply. But as in the inital state no reply is expected, this should not harm. */
/* Remove current action, if matched. If a reply is pending, the next
action will get the reply. But as in the inital state no reply is
expected, this should not harm. */
action = devser->current;
if (action != NULL && actionData == action->data) {
if (devser->killCurrent) {
@ -378,7 +391,7 @@ int DevRemoveAction(DevSer * devser, void *actionData)
}
/* remove from queue */
ptr2Last = &devser->actions;
for (action = devser->actions; action != NULL; action = action->next) {
for (action = devser->actions; action != NULL; action = *ptr2Last) {
if (actionData == action->data) {
cnt++;
/* remove from list */

View File

@ -10,10 +10,12 @@ typedef struct DevSer DevSer;
/** \brief The action handler to be called
* \param actionData the data stored with the action
* \param lastReply the last reply or NULL when no command was
* sent in the last action
* sent in the last action, or the error message (when commError == 1)
* \param commError 0: ok, 1: there was a communication error
* \return the command to be sent or NULL if no command has to be sent
*/
typedef char *DevActionHandler(void *actionData, char *lastReply);
typedef char *DevActionHandler(void *actionData, char *lastReply,
int commError);
/** \brief Check if an action matches the call data
* \param callData the callers data
@ -29,10 +31,12 @@ typedef void DevKillActionData(void *actionData);
/** \brief possible priorities.
* NullPRIO and NumberOfPRIO must not be used as priority
* if an action with StartPRIO is scheduled, all other activities
* are blocked until the action is unscheduled
*/
typedef enum {
NullPRIO, SlowPRIO, ReadPRIO, ProgressPRIO, WritePRIO, HaltPRIO,
NumberOfPRIO
StartPRIO, NumberOfPRIO
} DevPrio;
/** \brief Make a new device serializer and async connection.
@ -100,7 +104,7 @@ int DevSchedule(DevSer * devser, void *actionData,
/** \brief Unschedule matching actions
* \param devser the device serializer
* \param callData the callers data to be as first argument of the match function
* \param actionData the callers data to be used as first argument of the match function
* \param hdl the action handler
* \param matchFunc the match function (callData does not need to have the same type as actionData)
* \return the number of unscheduled actions
@ -114,6 +118,7 @@ int DevUnschedule(DevSer * devser, void *actionData,
*/
int DevRemoveAction(DevSer * devser, void *actionData);
/** \brief Convert integer priority to text
* \param prio
* \return text
@ -126,5 +131,4 @@ char *DevPrio2Text(DevPrio prio);
*/
DevPrio DevText2Prio(char *text);
#endif

View File

@ -26,7 +26,7 @@ int ErrEqual(char *str1, char *str2)
return 1;
}
ErrMsg *ErrPutMsg(ErrMsg * dump, char *fmt, ...)
void ErrPutMsg(ErrList *list, char *fmt, ...)
{
ErrMsg *m = NULL;
ErrMsg **last = NULL;
@ -34,6 +34,7 @@ ErrMsg *ErrPutMsg(ErrMsg * dump, char *fmt, ...)
char buf[256];
char *text = NULL;
int l;
static long id = 0;
va_start(ap, fmt);
l = vsnprintf(buf, sizeof buf, fmt, ap);
@ -43,12 +44,13 @@ ErrMsg *ErrPutMsg(ErrMsg * dump, char *fmt, ...)
} else {
/* assuming we have a C99 conforming snprintf and need a larger buffer */
text = calloc(l, 1);
if (!text) return;
va_start(ap, fmt);
vsnprintf(text, l, fmt, ap);
va_end(ap);
}
last = &dump;
for (m = dump; m != NULL; m = m->next) {
last = &list->current;
for (m = list->current; m != NULL; m = m->next) {
if (ErrEqual(text, m->text)) {
*last = m->next; /* remove found item from list */
break;
@ -61,12 +63,21 @@ ErrMsg *ErrPutMsg(ErrMsg * dump, char *fmt, ...)
m = calloc(1, sizeof(*m));
m->text = text;
m->cnt = 1;
m->dirty = 0;
id++;
m->id = id;
} else {
if (text != buf)
free(text);
m->cnt++;
}
m->next = dump;
m->next = list->current;
time(&m->last);
return m;
list->current = m;
}
char *ErrGetLastMsg(ErrList *list) {
if (list == NULL) return "";
if (list->current == NULL) return "";
return list->current->text;
}

View File

@ -11,10 +11,17 @@
typedef struct ErrMsg {
struct ErrMsg *next;
char *text; /**< the message text */
int cnt; /**< count */
long cnt; /**< count */
time_t last; /**< time of last message */
long dirty; /**< count since last reset */
char *itemId; /**< an id for the item where the error occured */
long id;
} ErrMsg;
typedef struct {
ErrMsg *current;
} ErrList;
/** \brief Put a formatted message to the error message list
*
* The error message list contains only one entry for all messages
@ -23,10 +30,17 @@ typedef struct ErrMsg {
* when comparing messages.
* The new message is always at the head of the list.
*
* \param dump the error message list
* \param list the error message list
* \param fmt the format for the message
* \return the new error message list head
*/
ErrMsg *ErrPutMsg(ErrMsg * dump, char *fmt, ...);
void ErrPutMsg(ErrList *list, char *fmt, ...);
/** \brief Get the most recent error message
* \param list the error list
* \return the most recent error message
*/
char *ErrGetLastMsg(ErrList *list);
#endif

View File

@ -86,6 +86,7 @@ void DeleteCallbackChain(pHdb node)
InvokeCallbackChain(node, &killNodeMsg);
current = node->callBackChain;
node->callBackChain = NULL;
while (current != NULL) {
if (current->killFunc != NULL) {
current->killFunc(current->userData);

25
macro.c
View File

@ -982,14 +982,6 @@ int TclPublish(SConnection * pCon, SicsInterp * pSics, void *pData,
return 0;
}
/* check user rights */
if (!SCMatchRights(pCon, usMugger)) {
sprintf(pBueffel, "ERROR: you are not authorised to use %s", argv[0]);
SCWrite(pCon, pBueffel, eError);
return 0;
}
/* try convert last parameter to user code */
iUser = decodeSICSPriv(argv[2]);
if (iUser < 0) {
@ -1002,9 +994,26 @@ int TclPublish(SConnection * pCon, SicsInterp * pSics, void *pData,
/* check if the macro already exists */
pNew = FindCommandData(pSics, argv[1], "Macro");
if (pNew) { /* yes -> overwrite access code */
if (pNew->iUser == iUser) {
return 1;
}
/* check user rights */
if (!SCMatchRights(pCon, usMugger)) {
sprintf(pBueffel, "ERROR: you are not authorised to use %s", argv[0]);
SCWrite(pCon, pBueffel, eError);
return 0;
}
pNew->iUser = iUser;
return 1;
}
/* check user rights */
if (!SCMatchRights(pCon, usMugger)) {
sprintf(pBueffel, "ERROR: you are not authorised to use %s", argv[0]);
SCWrite(pCon, pBueffel, eError);
return 0;
}
/* do a job ! */
pNew = CreatePublish(argv[1], iUser);
if (!pNew) {

View File

@ -31,7 +31,7 @@ SOBJ = network.o ifile.o conman.o SCinter.o splitter.o passwd.o \
hmdata.o nxscript.o tclintimpl.o sicsdata.o mcstascounter.o \
mcstashm.o initializer.o remob.o tclmotdriv.o protocol.o \
sinfox.o sicslist.o cone.o hipadaba.o sicshipadaba.o statistics.o \
ascon.o errormsg.o scriptcontext.o logger.o logreader.o logsetup.o \
ascon.o scriptcontext.o logger.o logreader.o logsetup.o \
savehdb.o statusfile.o sicshdbfactory.o proxy.o devser.o \
moregress.o multicounter.o regresscter.o histregress.o \
sicshdbadapter.o polldriv.o sicspoll.o statemon.o hmslave.o \
@ -63,7 +63,7 @@ full: purge all
SICServer: $(SOBJ) $(MOTOROBJ) $(COUNTEROBJ) \
$(VELOOBJ) $(DIFIL) $(EXTRA) \
$(SUBLIBS)
$(CC) -g -o SICServer \
$(CC) -g -o SICServer \
$(SOBJ) $(MOTOROBJ) $(COUNTEROBJ) \
$(VELOOBJ) $(DIFOBJ) $(EXTRA) $(LIBS)

27
motor.c
View File

@ -128,28 +128,25 @@ static int MotorCheckBoundaryImpl(pMotor self, float fVal, float *fNew,
{
float fHard;
float fZero;
char pBueffel[512];
float fLim;
assert(self);
/* check for fixed */
if (ObVal(self->ParArray, FIX) >= 0) {
sprintf(pBueffel, "Motor %s is Fixed", self->name);
strncpy(pError, pBueffel, iErrLen);
snprintf(pError, iErrLen, "Motor %s is Fixed", self->name);
return 0; /* is this an error? */
}
/* check against software boundaries */
if (fVal > ObVal(self->ParArray, SUPP)) {
sprintf(pBueffel, "%f violates upper software limit %f on %s",
fVal, ObVal(self->ParArray, SUPP), self->name);
strncpy(pError, pBueffel, iErrLen);
snprintf(pError, iErrLen, "%g violates upper software limit %g on %s",
fVal, ObVal(self->ParArray, SUPP), self->name);
return 0;
}
if (fVal < ObVal(self->ParArray, SLOW)) {
sprintf(pBueffel, "%f violates lower software limit %f on %s",
snprintf(pError, iErrLen, "%g violates lower software limit %g on %s",
fVal, ObVal(self->ParArray, SLOW), self->name);
strncpy(pError, pBueffel, iErrLen);
return 0;
}
@ -163,15 +160,17 @@ static int MotorCheckBoundaryImpl(pMotor self, float fVal, float *fNew,
/* check for hardware limits */
if (fHard > self->pDriver->fUpper) {
sprintf(pBueffel, "%f violates upper hardware limit %f on %s",
fVal, self->pDriver->fUpper, self->name);
strncpy(pError, pBueffel, iErrLen);
fLim = self->pDriver->fUpper * ObVal(self->ParArray,SIGN) + fZero;
snprintf(pError, iErrLen,
"%g violates upper hardware limit %g (%g) on %s",
fVal, fLim, self->pDriver->fUpper, self->name);
return 0;
}
if (fHard < self->pDriver->fLower) {
sprintf(pBueffel, "%f violates lower hardware limit %f on %s",
fVal, self->pDriver->fLower, self->name);
strncpy(pError, pBueffel, iErrLen);
fLim = self->pDriver->fLower * ObVal(self->ParArray,SIGN) + fZero;
snprintf(pError, iErrLen,
"%g violates lower hardware limit %g (%g) on %s",
fVal, fLim, self->pDriver->fLower, self->name);
return 0;
}

View File

@ -51,6 +51,8 @@
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include "sics.h"
#include "commandlog.h"
#include "uselect.h"
#define PORT 1
@ -65,11 +67,6 @@ struct timeval lastclose = { -1, 0 };
/*-----------------------------------------------------------------------
Redefine this function if another means of error reporting is necessary.
*/
#include "Scommon.h"
extern void SICSLogWrite(char *pText, OutCode eCode); /* servlog.c */
void WriteToCommandLog(char *p, char *t);
static void NetError(char *pText)
{
/*
@ -674,8 +671,44 @@ int NETReadTillTerm(mkChannel * self, long timeout,
status = NETAvailable(self, timeout - dif);
};
};
assert(bufPtr > 0);
return bufPtr;
return status;
}
/*-------------------------------------------------------------------------*/
int NETReadRemob(mkChannel * self, long timeout, long timeout2,
char term, char *pBuffer, int iBufLen)
{
struct timeval start, now;
int bufPtr = 0, status, i, length, matchIndex = 1;
char c;
long dif;
if (!VerifyChannel(self)) {
return -1;
}
memset(pBuffer, 0, iBufLen);
status = NETAvailable(self, timeout);
while (status > 0) {
status = recv(self->sockid, &c, 1, 0);
if (status <= 0) {
return status;
}
if (c == term) {
return bufPtr + 1;
}
if (bufPtr >= iBufLen - 1) {
return -1; /* overflow */
}
pBuffer[bufPtr] = c;
bufPtr++;
/*
wait for more data
*/
status = NETAvailable(self, timeout2);
};
return status;
}
/*---------------------------------------------------------------------------*/
@ -701,7 +734,7 @@ int NETClosePort(mkChannel * self)
/*---------------------------------------------------------------------------*/
int NETReconnectWithFlags(mkChannel * self, int flags)
{
int iRet;
int iRet = 0;
int sock;
int oldopts;
@ -709,7 +742,9 @@ int NETReconnectWithFlags(mkChannel * self, int flags)
* Get the flags and close the old socket
*/
oldopts = fcntl(self->sockid, F_GETFL, 0);
close(self->sockid);
if (self->sockid != 0) {
close(self->sockid);
}
/* Reopen and try to get it on the olf fd */
sock = socket(AF_INET, SOCK_STREAM, 0);
if (self->sockid != sock) {

View File

@ -63,7 +63,7 @@ mkChannel *NETConnectWithFlags(char *name, int port, int flags);
if (flags & 1): do not block on connect (use NETConnectFinished
to check success)
if (flags & 2): wait 1000 ms after last close (workaround for
a bug in Lantronix terminal server
a bug in the Lantronix terminal server)
*/
int NETConnectFinished(mkChannel * self);
@ -91,8 +91,8 @@ int NETReconnectWithFlags(mkChannel * self, int flags);
/* *********************** DATA TRANSFER ******************************** */
int NETWrite(mkChannel * self, char *buffer, long lLen);
/* writes data to socket self, returns True if success,
false otherwise.
/* writes data to socket self, returns 1 if success,
0 otherwise.
*/
long NETRead(mkChannel * self, char *buffer, long lLen, long timeout);
@ -122,6 +122,9 @@ int NETReadTillTerm(mkChannel * self, long timeout,
If no terminator is given, the routine waits for iBufLen characters
or timeout.
*/
int NETReadRemob(mkChannel *self, long timeout, long timeout2,
char term, char *pBuffer, int iBufLen);
/* special version for remob */
/* ********************* KILLING FIELD ******************************** */
int NETClosePort(mkChannel * self);
/* closes a port, do not forget to free the channel data-

View File

@ -448,7 +448,7 @@ int UserWait(SConnection * pCon, SicsInterp * pSics, void *pData,
if (i < 1) {
sprintf(pBueffel, "Expected numeric argument to %s, got %s",
argv[0], argv[1]);
SCWrite(pCon, pBueffel, eInError);
SCWrite(pCon, pBueffel, eError);
return 0;
}

5
ofac.c
View File

@ -236,6 +236,7 @@ static void InitIniCommands(SicsInterp * pInter, pTaskMan pTask)
AddCommand(pInter, "SICSStatus", SICSStatus, NULL, NULL);
AddCommand(pInter, "sicstime", SICSTime, NULL, NULL);
AddCommand(pInter, "sicsdescriptor", SICSDescriptor, NULL, NULL);
AddCommand(pInter, "silent", SICSSilent, NULL, NULL);
AddCommand(pInter, "SetStatus", SetSICSStatus, NULL, NULL);
AddCommand(pInter, "db", SICSDebug, NULL, NULL);
AddCommand(pInter, "EVFactory", EVControlFactory, NULL, NULL);
@ -439,7 +440,9 @@ void InitGeneral(void)
INIT(InitializerInit);
INIT(SaveHdbInit); /* must be after InitializerInit */
INIT(SctInit);
INIT(SctDriveInit);
INIT(SctDriveAdapterInit);
INIT(SctDriveObjInit);
INIT(SctDriveAdapterInit);
INIT(LogReaderInit);
INIT(LogSetupInit);
INIT(StatusFileInit);

View File

@ -485,7 +485,6 @@ int SicsPrompt(SConnection * pCon, SicsInterp * pSics, void *pData,
/*----------------------- get object descriptor name -------------------------------
get the name of the object descriptor
*/
int SICSDescriptor(SConnection * pCon, SicsInterp * pSics, void *pData,
int argc, char *argv[])
{
@ -517,3 +516,44 @@ int SICSDescriptor(SConnection * pCon, SicsInterp * pSics, void *pData,
SCWrite(pCon, "notfound", eValue);
return 1;
}
/*------------------------------------------------------------------------*/
int SICSSilent(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]) {
Tcl_Interp *pTcl = NULL;
int iRet;
char *cmd;
char *result;
writeFunc oldWrite;
assert(pCon);
assert(pSics);
if (!SCinMacro(pCon)) {
SCPrintf(pCon, eError,
"ERROR: %s may only be called in scripts", argv[0]);
return 0;
}
pTcl = InterpGetTcl(pSics);
assert(pTcl);
if (argc < 3) {
SCWrite(pCon, "ERROR: should be: silent <error-value> <tcl-command>", eError);
return 0;
}
cmd = Arg2Tcl(argc-2,&argv[2],NULL,0);
assert(cmd);
oldWrite = SCGetWriteFunc(pCon);
SCSetWriteFunc(pCon,SCNotWrite);
iRet = Tcl_EvalEx(pTcl, cmd, strlen(cmd), 0);
SCSetWriteFunc(pCon,oldWrite);
if (iRet == TCL_OK) {
result = strdup((char *)Tcl_GetStringResult(pTcl));
SCWrite(pCon, result, eValue);
free(result);
} else {
SCWrite(pCon, argv[1], eValue);
}
free(cmd);
return 1;
}

View File

@ -48,4 +48,7 @@ int SicsPrompt(SConnection * pCon, SicsInterp * pSics, void *pData,
/*----------------------------------------------------------------------*/
int SICSDescriptor(SConnection * pCon, SicsInterp * pSics, void *pData,
int argc, char *argv[]);
/*----------------------------------------------------------------------*/
int SICSSilent(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]);
#endif

View File

@ -47,7 +47,7 @@ typedef struct SctData {
} SctData;
static ScriptContext *sct = NULL;
static SConnection *currentCon = NULL;
static SctData *queueData = NULL;
static struct {
char *name;
@ -179,6 +179,7 @@ int SctCommand(SConnection * con, SicsInterp * sics, void *object,
return 0;
}
UpdateHipadabaPar(node, v, con);
ReleaseHdbValue(&v);
SetHdbProperty(node, "geterror", NULL);
return 1;
}
@ -187,6 +188,9 @@ int SctCommand(SConnection * con, SicsInterp * sics, void *object,
* print
*/
if (strcmp(argv[1], "print") == 0) {
if (queueData != NULL) {
queueData->answered = 1;
}
Arg2Text(argc - 2, argv + 2, value, sizeof value);
SCWrite(con, value, eLog);
return 1;
@ -201,7 +205,7 @@ int SctCommand(SConnection * con, SicsInterp * sics, void *object,
}
/*
* time stamping
* time stamping (obsolete ? -> see SctActionHandler: timeKey, timeVal)
*/
if (strcmp(argv[1], "utime") == 0) {
if (argc < 3) {
@ -248,7 +252,7 @@ int SctCallInContext(SConnection * con, char *script, Hdb * node,
PushContext(node, controller->node);
if (verbose) {
SCPrintf(con, eLog, "\nscript: %s\n", script);
SCPrintf(con, eLog, "script: %s", script);
}
MacroPush(con);
@ -257,7 +261,7 @@ int SctCallInContext(SConnection * con, char *script, Hdb * node,
result = (char *) Tcl_GetStringResult(pTcl);
if (ret != TCL_OK && result[0] != '\0') {
if (verbose) {
SCPrintf(con, eLog, "\nerror: %s\n", result);
SCPrintf(con, eLog, "error: %s", result);
}
iRet = 0;
}
@ -276,26 +280,38 @@ static int SctMatch(void *data1, void *data2)
return a->node == b->node && strcasecmp(a->name, b->name) == 0;
}
static char *SctActionHandler(void *actionData, char *lastReply)
static char *SctActionHandler(void *actionData, char *lastReply,
int commError)
{
SctData *data = actionData;
Hdb *node = data->node;
SctController *controller = data->controller;
char *state;
char *result;
char *script;
char *script = NULL;
char *errorScript = NULL;
char *send = NULL;
int i;
SConnection *con;
char eprop[80];
char msg[1024];
char path[1024];
char origScript[80];
char *blank;
char *emsg;
size_t l;
int cnt;
char timeKey[50], timeVal[50];
if (currentCon) {
con = currentCon;
if (queueData != NULL && queueData->conCtx != NULL) {
con = queueData->conCtx;
} else {
con = controller->conn;
}
SetProp(node, controller->node, "result", lastReply);
if (controller->verbose && lastReply != NULL && *lastReply != '\0') {
script = NULL;
if (!commError && controller->verbose && lastReply != NULL
&& *lastReply != '\0') {
SCPrintf(con, eLog, "reply : %s", lastReply);
}
state = GetProp(node, controller->node, "state");
@ -304,29 +320,75 @@ 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;
snprintf(origScript, sizeof origScript, "%s", script);
if (commError) {
errorScript = GetProp(node, controller->node, "commerror");
if (errorScript != NULL)
script = errorScript;
commError = 0;
}
script = strdup(script);
if (!SctCallInContext(con, script, node, data->controller, &result)) {
SCPrintf(con, eError, "ERROR: %s", result);
snprintf(eprop, sizeof eprop, "error_during_%s", data->name);
if (strncmp(result, "ERROR: ", 7) == 0) {
result += 7;
}
emsg = GetHdbProp(node, eprop);
if (emsg == NULL) {
GetHdbPath(node, path, sizeof path);
SCPrintf(con, eError,
"ERROR: action <%s> in {%s} node %s:\nERROR: %s",
data->name, origScript, path, result);
}
snprintf(msg, sizeof msg, "<%s> %s", origScript, result);
SetHdbProperty(node, eprop, msg);
blank = strchr(origScript, ' ');
if (blank != NULL) {
l = blank - origScript;
} else {
l = strlen(origScript);
}
snprintf(eprop, sizeof eprop, "error_in_%.*s", l, origScript);
emsg = GetHdbProp(node, eprop);
cnt = 0;
if (emsg != NULL) {
sscanf(emsg, "%d", &cnt);
}
cnt++;
snprintf(msg, sizeof msg, "%dx {%s} %s", cnt, origScript, result);
SetHdbProperty(node, eprop, msg);
send = NULL;
goto finish;
}
state = result;
if (strcasecmp(state, "idle") == 0) {
if (currentCon && !data->answered) {
SCWrite(con, "o.k.", eValue);
if (strcasecmp(state, "idle") == 0 || strcasecmp(state, "unpoll") == 0) {
if (queueData == data && !data->answered) {
SCWrite(con, "o.k.", eStatus);
}
if (strcmp(data->name, "write") == 0) {
SetHdbProperty(data->node, "writestatus", "commandsent");
snprintf(eprop, sizeof eprop, "error_during_%s", data->name);
emsg = GetHdbProp(node, eprop);
if (emsg != NULL) {
GetHdbPath(node, path, sizeof path);
SCPrintf(con, eError,
"action <%s>: success after error message (%s)\n %s",
data->name, path, emsg);
SetHdbProperty(node, eprop, NULL);
}
snprintf(timeKey, 50, "%s_time", data->name);
snprintf(timeVal, 50, "%.3f", DoubleTime());
snprintf(timeKey, sizeof timeKey, "%s_time", data->name);
snprintf(timeVal, sizeof timeVal, "%.3f", DoubleTime());
SetHdbProperty(data->node, timeKey, timeVal);
send = NULL;
goto finish;
}
SetProp(node, controller->node, "state", state);
free(script);
script = NULL;
send = GetProp(node, controller->node, "send");
if (send != NULL && send[0] != '\0') {
if (controller->verbose) {
@ -337,6 +399,16 @@ static char *SctActionHandler(void *actionData, char *lastReply)
}
SCPrintf(con, eLogError, "ERROR: too many quick scripts chained");
finish:
if (strcmp(data->name, "write") == 0) {
/* check if it would be ok to do this only when writestatus property exists:
GetHdbProp(data->node, "writestatus") != NULL
*/
SetHdbProperty(data->node, "writestatus", "commandsent");
}
if (strcasecmp(state, "unpoll") == 0) {
DevUnschedule(controller->devser, data, SctActionHandler, SctMatch);
send = NULL;
}
SetProp(node, controller->node, "state", "idle");
if (data->conCtx != NULL) {
SCDeleteConnection(data->conCtx);
@ -345,16 +417,17 @@ finish:
return send;
}
static char *SctWriteHandler(void *actionData, char *lastReply)
static char *SctWriteHandler(void *actionData, char *lastReply,
int commError)
{
SctData *data = actionData;
SConnection *old;
SctData *old;
char *result;
old = currentCon;
currentCon = data->conCtx;
result = SctActionHandler(data, lastReply);
currentCon = old;
old = queueData;
queueData = data;
result = SctActionHandler(data, lastReply, commError);
queueData = old;
return result;
}
@ -379,6 +452,10 @@ static hdbCallbackReturn SctMainCallback(Hdb * node, void *userData,
char *geterror;
char error[256];
if (controller->devser == NULL) {
/* defunct controller */
return hdbContinue;
}
pm = GetKillPtrMessage(msg);
if (pm != NULL) {
if (controller == pm->pPtr) {
@ -440,7 +517,6 @@ static hdbCallbackReturn SctActionCallback(Hdb * node, void *userData,
char *writeprio;
char *error;
SConnection *con;
SConnection *con2;
char path[MAX_HDB_PATH];
pm = GetKillPtrMessage(msg);
@ -510,16 +586,16 @@ static hdbCallbackReturn SctActionCallback(Hdb * node, void *userData,
mm = GetHdbUpdateMessage(msg);
if (mm != NULL) {
if (currentCon) { /* update called from a write action */
if (queueData != NULL && queueData->conCtx != NULL && !data->answered) {
/* update called from a write action */
data->answered = 1;
GetHdbPath(node, path, sizeof path);
con = currentCon;
text = formatValue(*(mm->v), node);
/* Markus: who is receiving this message?
It gave unwanted output to me. MK
SCPrintf(con, eLog, "%s = %s", path, GetCharArray(text));
Answer: a commandline client -> outcode eStatus correct?
*/
SCPrintf(queueData->conCtx, eStatus, "%s = %s", path, GetCharArray(text));
DeleteDynString(text);
}
return hdbContinue;
@ -577,7 +653,9 @@ static void SctKillCBData(void *d)
{
SctData *data = d;
DevRemoveAction(data->controller->devser, data);
if (data->controller->devser != NULL) {
DevRemoveAction(data->controller->devser, data);
}
SctKillData(d);
}
@ -866,7 +944,8 @@ static void KillSctTransact(void *data)
free(self);
}
static char *TransactionHandler(void *actionData, char *lastReply)
static char *TransactionHandler(void *actionData, char *lastReply,
int commError)
{
pSctTransact st = (pSctTransact) actionData;
@ -976,6 +1055,12 @@ static hdbCallbackReturn SctDebugCallback(Hdb * node, void *userData,
return hdbContinue;
}
static int SctDeferredFree(void *data)
{
free(data);
return 0;
}
static void SctKillController(void *c)
{
SctController *controller = c;
@ -987,7 +1072,13 @@ static void SctKillController(void *c)
SCDeleteConnection(controller->conn);
}
DevKill(controller->devser);
free(controller);
controller->devser = NULL;
if (pServ->pTasker) {
TaskRegister(pServ->pTasker, SctDeferredFree, NULL, NULL, controller,
0);
} else {
free(controller);
}
}
static int SctMakeController(SConnection * con, SicsInterp * sics,
@ -995,33 +1086,33 @@ static int SctMakeController(SConnection * con, SicsInterp * sics,
{
SICSOBJ *ccmd;
Hdb *parent, *par, *cmd;
char *nodeName;
char *objName;
hdbCallback *cb;
SctController *controller;
if (argc < 2) {
SCPrintf(con, eError,
"ERROR: should be %s <path> <protocol args> ...", argv[0]);
"ERROR: should be %s <path or objectname> <protocol args> ...",
argv[0]);
return 0;
}
/*
* Install into the Hipadaba when full path given
*/
if(strstr(argv[1],"/") != NULL){
parent = FindHdbParent(NULL, argv[1], &nodeName, con);
if (parent == NULL)
return 0; /* error message already written */
if (strchr(argv[1], '/') == NULL) {
/* object name only -> do not anchor in tree */
parent = NULL;
objName = argv[1];
} else {
nodeName = argv[1];
parent = NULL;
/* full path given -> install into the hipadaba */
parent = FindHdbParent(NULL, argv[1], &objName, con);
if (parent == NULL)
return 0; /* error message already written */
}
controller = calloc(1, sizeof(*controller));
assert(controller);
controller->verbose = 0;
ccmd = MakeSICSOBJv(nodeName, "SctController", HIPNONE, usSpy);
ccmd = MakeSICSOBJv(objName, "SctController", HIPNONE, usSpy);
controller->node = ccmd->objectNode;
controller->conn = SCCreateDummyConnection(pServ->pSics);
@ -1030,15 +1121,16 @@ static int SctMakeController(SConnection * con, SicsInterp * sics,
ccmd->pPrivate = controller;
ccmd->KillPrivate = SctKillController;
if(parent != NULL){
AddHipadabaChild(parent, controller->node, con);
if (parent != NULL) {
AddHipadabaChild(parent, controller->node, con);
}
controller->devser = DevMake(con, argc - 2, argv + 2);
if (!controller->devser)
return 0;
AddCommand(pServ->pSics, nodeName, InvokeSICSOBJ, KillSICSOBJ, ccmd);
AddCommand(pServ->pSics, objName, InterInvokeSICSOBJ, KillSICSOBJ, ccmd);
RegisterSICSOBJKillCmd(ccmd, objName);
SetDescriptorKey(ccmd->pDes, "creationCommand", "0");
cmd = AddSICSHdbPar(controller->node,

View File

@ -306,8 +306,9 @@ int SctMakeDriveAdapter(SConnection * pCon, SicsInterp * pSics,
}
if (argc < 4) {
SCWrite(pCon, "ERROR: not enough arguments for SctMakeDriveAdapter",
eError);
SCPrintf(pCon, eError,
"ERROR: should be %s <object name> <existing-node> <controller>",
argv[0]);
return 0;
}
@ -335,12 +336,8 @@ int SctMakeDriveAdapter(SConnection * pCon, SicsInterp * pSics,
}
/*---------------------------------------------------------------*/
int SctMakeDriveObject(SConnection * pCon, SicsInterp * pSics,
void *object, int argc, char *argv[]);
void SctDriveInit(void)
void SctDriveAdapterInit(void)
{
AddCmd("makesctdrive", SctMakeDriveAdapter);
AddCmd("dynsctdrive", SctMakeDriveAdapter);
AddCmd("makesctdriveobj", SctMakeDriveObject);
}

View File

@ -3,6 +3,19 @@
* scriptcontext to control the actual driving operation. This can also
* serve as a drivable adapter to nodes in other objects.
*
* Some cooperation from the node is required: It has to provide
* certain properties the value of which define scripts which
* have to be called at various stages. These are:
*
* checklimits, for limits checking
* checkstatus, for evaluating progress
* halt , for halting things
*
* If no checklimits script is given, nothing is checked.
* If no checkstatus scripts is given, the value of the status property is
* returned. In that case the status value should be updated by some poll script.
* If no halt script is given, the status is set to idle. M.Z. Sept. 08
*
* copyright: see file COPYRIGHT
*
* Mark Koennecke, June-July 2008
@ -22,18 +35,19 @@ typedef struct {
/*--------------------------------------------------------------*/
static void KillDrivePriv(void *data)
{
pDrivObjPriv priv = (pDrivObjPriv)data;
if(priv == NULL){
pDrivObjPriv priv = (pDrivObjPriv) data;
if (priv == NULL) {
return;
}
if(priv->pDriv != NULL){
if (priv->pDriv != NULL) {
free(priv->pDriv);
}
if(priv->pCon != NULL){
if (priv->pCon != NULL) {
SCDeleteConnection(priv->pCon);
}
free(priv);
}
/*---------------------------------------------------------------*/
static void *SCTDRIVGetInterface(void *data, int iD)
{
@ -66,7 +80,7 @@ static int SCTDRIVHalt(void *data)
pPriv = (pDrivObjPriv) self->pPrivate;
if (GetHdbProperty(self->objectNode, "halt", dummy, sizeof dummy)) {
SctQueueNode(pPriv->c, self->objectNode, HaltPRIO, "halt",
pPriv->pCon);
pPriv->pCon);
} else
if (GetHdbProperty(self->objectNode, "status", dummy, sizeof dummy))
{
@ -128,11 +142,13 @@ static long SCTDRIVSetValue(void *data, SConnection * pCon, float val)
self = (pSICSOBJ) data;
pPriv = (pDrivObjPriv) self->pPrivate;
if(pPriv->pCon != NULL){
if (pPriv->pCon != NULL) {
SCDeleteConnection(pPriv->pCon);
}
pPriv->pCon = SCCopyConnection(pCon);
StopByData(pServ->pExecutor, data);
v.dataType = HIPFLOAT;
v.v.doubleValue = (double) val;
SetHdbProperty(self->objectNode, "writestatus", "start");
@ -258,24 +274,17 @@ static void KillDriveOBJ(void *data)
}
pPriv = (pDrivObjPriv) self->pPrivate;
if (pPriv->doNotKillNode && self->pDes != NULL) {
if (self->pDes->name)
free(self->pDes->name);
if (self->pDes->pKeys)
IFDeleteOptions(self->pDes->pKeys);
free(self->pDes);
} else {
DeleteDescriptor(self->pDes); /* kill descriptor including node */
if (pPriv->doNotKillNode && GetDescriptorKey(self->pDes, "creationCommand") == NULL /* it's not a dynamic object */
&& self->pDes != NULL) {
self->objectNode = NULL; /* do not call RemoveHdbNodeFromParent in KillSICSOBJ */
self->pDes->parNode = NULL; /* do not kill the node in KillSICSOBJ/DeleteDescriptor */
}
if (self->KillPrivate != NULL && self->pPrivate != NULL) {
self->KillPrivate(self->pPrivate);
}
RemoveHdbNodeFromParent(self->objectNode, pServ->dummyCon);
free(self);
KillSICSOBJ(self);
}
/*-----------------------------------------------------------------------------*/
pSICSOBJ MakeSctDriveObj(pHdb node, char *class, SctController * c)
pSICSOBJ MakeSctDriveObj(pHdb node, char *class, SctController * c,
int doNotKillNode)
{
pSICSOBJ pNew = NULL;
pDrivObjPriv pPriv = NULL;
@ -299,6 +308,7 @@ pSICSOBJ MakeSctDriveObj(pHdb node, char *class, SctController * c)
pNew->objectNode = node;
AssignSctDrive(pPriv->pDriv);
pPriv->c = c;
pPriv->doNotKillNode = doNotKillNode;
pNew->pDes->parNode = pNew->objectNode;
pNew->pDes->GetInterface = SCTDRIVGetInterface;
pNew->pPrivate = pPriv;
@ -309,7 +319,7 @@ pSICSOBJ MakeSctDriveObj(pHdb node, char *class, SctController * c)
/*--------------------------------------------------------------------------
* This actually has two syntaxes:
* makesctdrive name path-to-existing-node class SctController
* makesctdrive name type priv class SctController
* makesctdrive name float priv class SctController
*--------------------------------------------------------------------------*/
int SctMakeDriveObject(SConnection * pCon, SicsInterp * pSics,
void *object, int argc, char *argv[])
@ -319,54 +329,58 @@ int SctMakeDriveObject(SConnection * pCon, SicsInterp * pSics,
pSICSOBJ pNew = NULL;
pSICSOBJ pSct = NULL;
SctController *c = NULL;
int priv, type, status;
int priv, type, status, doNotKillNode;
hdbValue val;
char *sctName;
char *class;
if (argc < 5) {
SCWrite(pCon, "ERROR: not enough arguments to SctMakeDriveObject",
eError);
return 0;
}
if (argc < 5)
goto Usage;
node = FindHdbNode(NULL, argv[2], pCon);
if (node != NULL) {
pSct = FindCommandData(pSics, argv[4], "SctController");
if (pSct == NULL) {
SCPrintf(pCon, eError, "ERROR: SctController %s not found", argv[4]);
return 0;
if (argc == 5) {
node = FindHdbNode(NULL, argv[2], pCon);
if (node == NULL) {
SCPrintf(pCon, eError, "ERROR: node %s not found", argv[2]);
goto Usage;
}
c = (SctController *) pSct->pPrivate;
pNew = MakeSctDriveObj(node, argv[3], c);
pPriv = (pDrivObjPriv) pNew->pPrivate;
pPriv->doNotKillNode = 1; /* the node is owned by someone else */
sctName = argv[4];
class = argv[3];
doNotKillNode = 1; /* the node is owned by someone else */
} else {
/* convert datatype */
type = convertHdbType(argv[2]);
/* convert privilege */
priv = decodeSICSPriv(argv[3]);
/* convert datatype */
strtolower(argv[4]);
type = convertHdbType(argv[2]);
if (type == HIPNONE) {
node = MakeHipadabaNode(argv[1], HIPNONE, 1);
} else {
val = makeHdbValue(type, 0);
node = MakeSICSHdbPar(argv[1], priv, val);
ReleaseHdbValue(&val);
}
if (priv < 0 || type != HIPFLOAT)
goto Usage;
node = MakeSICSHdbPar(argv[1], priv, MakeHdbFloat(0.0));
if (node == NULL) {
SCWrite(pCon, "ERROR: node creation failed", eError);
return 0;
}
c = FindCommandData(pSics, argv[5], "SctController");
if (c == NULL) {
SCPrintf(pCon, eError, "ERROR: SctController %s not found", argv[4]);
return 0;
}
pNew = MakeSctDriveObj(node, argv[3], c);
sctName = argv[5];
class = argv[4];
doNotKillNode = 0; /* kill the node with the command */
}
pSct = FindCommandData(pSics, sctName, "SctController");
if (pSct == NULL) {
SCPrintf(pCon, eError, "ERROR: SctController %s not found", sctName);
goto Usage;
}
c = (SctController *) pSct->pPrivate;
pNew = MakeSctDriveObj(node, class, c, doNotKillNode);
SetHdbProperty(node, "objectName", argv[1]);
if (pNew == NULL) {
SCWrite(pCon, "ERROR: failed to create drive object", eError);
return 0;
}
if (strcasecmp(argv[0], "dynsctdriveobj") == 0) {
/* make object dynamic by defining a creation command */
SetDescriptorKey(pNew->pDes, "creationCommand", "0");
RegisterSICSOBJKillCmd(pNew, argv[1]);
}
status = AddCommand(pSics,
argv[1], InterInvokeSICSOBJ, KillDriveOBJ, pNew);
if (status != 1) {
@ -376,4 +390,18 @@ int SctMakeDriveObject(SConnection * pCon, SicsInterp * pSics,
return 0;
}
return 1;
Usage:
SCPrintf(pCon, eError,
"ERROR: should be %s <object name> <existing node> <class> <controller>",
argv[0]);
SCPrintf(pCon, eError,
"ERROR: or %s <object name> <type> <priv> <class> <controller>",
argv[0]);
return 0;
}
/*---------------------------------------------------------------*/
void SctDriveObjInit(void)
{
AddCmd("makesctdriveobj", SctMakeDriveObject);
AddCmd("dynsctdriveobj", SctMakeDriveObject);
}

View File

@ -1346,6 +1346,7 @@ static void SICSDeleteNodeData(pHdb node)
}
removeNodeFromUpdateList(node);
DeleteCallbackChain(node);
while (node->child != NULL) {
tmp = node->child;
node->child = node->child->next;
@ -1354,7 +1355,6 @@ static void SICSDeleteNodeData(pHdb node)
if (node->properties != NULL) {
DeleteStringDict(node->properties);
}
DeleteCallbackChain(node);
if (node->name != NULL) {
free(node->name);
@ -1616,7 +1616,7 @@ static int RemoveParNodeCallback(char *name, pDummy object,
m.type = killPtr;
m.pPtr = internalID;
if (object->pDescriptor->parNode) {
if (object && object->pDescriptor->parNode) {
RecurseCallbackChains(object->pDescriptor->parNode, (pHdbMessage) & m);
}
return 1;
@ -1805,7 +1805,8 @@ int ProcessSICSHdbPar(pHdb root, SConnection * pCon,
SCWrite(pCon, "ERROR: out of memory processing parameter", eError);
return 0;
}
for (i = 1; i < argc; i++) {
DynStringConcat(parData, argv[1]);
for (i = 2; i < argc; i++) {
DynStringConcat(parData, " ");
DynStringConcat(parData, argv[i]);
}
@ -2048,7 +2049,7 @@ int readHdbValue(hdbValue * v, char *data, char *error, int errlen)
getNextHdbNumber(data, number);
status = sscanf(number, "%d", &v->v.intValue);
if (status != 1) {
snprintf(error, errlen, "Failed to convert %s to integer", data);
snprintf(error, errlen, "Failed to convert [%.32s] to integer", data);
return 0;
}
break;
@ -2056,7 +2057,7 @@ int readHdbValue(hdbValue * v, char *data, char *error, int errlen)
getNextHdbNumber(data, number);
status = sscanf(number, "%lf", &v->v.doubleValue);
if (status != 1) {
snprintf(error, errlen, "Failed to convert %s to double", data);
snprintf(error, errlen, "Failed to convert [%.32s] to double", data);
return 0;
}
break;
@ -2082,7 +2083,7 @@ int readHdbValue(hdbValue * v, char *data, char *error, int errlen)
}
status = sscanf(number, "%d", &lValue);
if (status != 1) {
snprintf(error, errlen, "Failed to convert %s to integer", data);
snprintf(error, errlen, "Failed to convert [%.32s] to integer", data);
return 0;
}
v->v.intArray[i] = lValue;
@ -2104,7 +2105,7 @@ int readHdbValue(hdbValue * v, char *data, char *error, int errlen)
}
status = sscanf(number, "%lf", &dValue);
if (status != 1) {
snprintf(error, errlen, "Failed to convert %s to double", data);
snprintf(error, errlen, "Failed to convert [%.32s] to double", data);
return 0;
}
v->v.floatArray[i] = dValue;
@ -2154,7 +2155,7 @@ int convertHdbType(char *text)
type = 0;
while (hdbTypes[type] != NULL) {
if (strcmp(hdbTypes[type], text) == 0) {
if (strcasecmp(hdbTypes[type], text) == 0) {
break;
}
type++;
@ -2196,7 +2197,6 @@ static int MakeHdbNode(SConnection * pCon, SicsInterp * pSics, void *pData,
/*
* convert datatype
*/
strtolower(argv[3]);
type = convertHdbType(argv[3]);
if (type > HIPFLOATVARAR) {
SCWrite(pCon,
@ -2210,7 +2210,7 @@ static int MakeHdbNode(SConnection * pCon, SicsInterp * pSics, void *pData,
eError);
return 0;
} else {
length = atoi(argv[3]);
length = atoi(argv[4]);
}
}
@ -2439,7 +2439,8 @@ static int UpdateHdbNode(SConnection * pCon, SicsInterp * pSics,
SCWrite(pCon, "ERROR: out of memory reading parameter", eError);
return 0;
}
for (i = 2; i < argc; i++) {
DynStringConcat(parData, argv[2]);
for (i = 3; i < argc; i++) {
DynStringConcat(parData, " ");
DynStringConcat(parData, argv[i]);
}
@ -3310,7 +3311,7 @@ static int GetSICSHdbProperty(SConnection * pCon, SicsInterp * pSics,
}
status = GetHdbProperty(targetNode, argv[2], buffer, 511);
if (status != 1) {
SCPrintf(pCon, eError, "ERROR: property %s not found", argv[2]);
SCPrintf(pCon, eError, "ERROR: %s has no property %s", argv[1], argv[2]);
return 0;
}
SCPrintf(pCon, eValue, "%s.%s = %s", argv[1], argv[2], buffer);
@ -3331,12 +3332,12 @@ static int GetSICSHdbPropertyVal(SConnection * pCon, SicsInterp * pSics,
}
targetNode = FindHdbNode(NULL, argv[1], pCon);
if (targetNode == NULL) {
SCWrite(pCon, "ERROR: node not found", eValue);
SCWrite(pCon, "ERROR: node not found", eError);
return 0;
}
status = GetHdbProperty(targetNode, argv[2], buffer, 511);
if (status != 1) {
SCWrite(pCon, "ERROR: attribute not found", eValue);
SCPrintf(pCon, eError, "ERROR: %s has no property %s", argv[1], argv[2]);
return 0;
}
SCPrintf(pCon, eValue, "%s", buffer);

View File

@ -284,6 +284,10 @@ int GetHdbPath(pHdb nodeArg, char *path, size_t pathlen);
* @param internalID the internalID to be looked for
*/
void RemoveSICSInternalCallback(void *internalID);
/** Remove all Callbacks rooted in the node
* @param internalID the internalID to be looked for
*/
void RemoveSICSInternalCallbackFrom(pHdb node, void *internalID);
/**
* SICSHdbGetPar returns the value of a parameter.
* @param obj The object for which to get a parameter.

View File

@ -17,7 +17,11 @@
#include "initializer.h"
#include "splitter.h"
extern int decodeSICSPriv(char *txt); /* from access.c */
typedef struct {
char *name;
char *class;
} NameClass;
/*--------------------------------------------------------------------------*/
void DefaultKill(void *data)
{
@ -74,6 +78,42 @@ int SaveSICSOBJ(void *data, char *name, FILE * fd)
return 1;
}
/*---------------------------------------------------------------------------*/
static void KillSICSOBJfromNode(void *userData)
{
NameClass *nameClass = userData;
SICSOBJ *sicsobj;
sicsobj = FindCommandData(pServ->pSics, nameClass->name, nameClass->class);
if (sicsobj) {
sicsobj->objectNode = NULL; /* do not call RemoveHdbNodeFromParent in KillSICSOBJ */
sicsobj->pDes->parNode = NULL; /* do not free the node twice in KillSICSOBJ/DeleteDescriptor */
RemoveCommand(pServ->pSics, nameClass->name);
}
free(nameClass->name);
free(nameClass->class);
free(nameClass);
}
/*---------------------------------------------------------------------------*/
static hdbCallbackReturn DummyCallback(Hdb *node, void *userData,
hdbMessage *msg)
{
return hdbContinue;
}
/*---------------------------------------------------------------------------*/
void RegisterSICSOBJKillCmd(pSICSOBJ sicsobj, char *name)
{
hdbCallback *cb;
NameClass *nameClass;
nameClass = calloc(1, sizeof(*nameClass));
nameClass->name = strdup(name);
nameClass->class = strdup(sicsobj->pDes->name);
/* use only the kill function */
cb = MakeHipadabaCallback(DummyCallback, nameClass, KillSICSOBJfromNode);
assert(cb);
AppendHipadabaCallback(sicsobj->objectNode, cb);
}
/*---------------------------------------------------------------------------*/
pSICSOBJ MakeSICSOBJv(char *name, char *class, int type, int priv)
{
@ -119,8 +159,11 @@ void KillSICSOBJ(void *data)
if (self->KillPrivate != NULL && self->pPrivate != NULL) {
self->KillPrivate(self->pPrivate);
}
RemoveHdbNodeFromParent(self->objectNode, pServ->dummyCon);
if (self->objectNode != NULL) {
RemoveHdbNodeFromParent(self->objectNode, pServ->dummyCon);
}
if (self->pDes != NULL) {
self->objectNode = NULL; /* inhibit SICSOBJcallback from deleting twice */
DeleteDescriptor(self->pDes); /* kill descriptor including node */
}
free(self);
@ -412,11 +455,11 @@ int InterInvokeSICSOBJ(SConnection * pCon, SicsInterp * pSics, void *pData,
if (status == -1) {
status = 0;
if (argc > 1) {
snprintf(buffer, 131,
"ERROR: no command or parameter found for key: %s",
argv[1]);
snprintf(buffer, sizeof buffer,
"ERROR: %s %s not found",
argv[0], argv[1]);
} else {
snprintf(buffer, 131, "ERROR: no argument found");
snprintf(buffer, sizeof buffer, "ERROR: no argument found");
}
SCWrite(pCon, buffer, eError);
status = 0;
@ -444,7 +487,6 @@ pSICSOBJ SetupSICSOBJ(SConnection * pCon, SicsInterp * pSics, void *pData,
/* convert privilege */
priv = decodeSICSPriv(argv[3]);
/* convert datatype */
strtolower(argv[4]);
type = convertHdbType(argv[4]);
if (type > HIPFLOAT) {
SCWrite(pCon,
@ -464,6 +506,7 @@ pSICSOBJ SetupSICSOBJ(SConnection * pCon, SicsInterp * pSics, void *pData,
SetDescriptorKey(pNew->pDes, "creationCommand", "0");
}
SetHdbProperty(pNew->objectNode, "objectName", argv[1]);
status = AddCommand(pSics,
argv[1], InterInvokeSICSOBJ, KillSICSOBJ, pNew);
if (status != 1) {

View File

@ -31,6 +31,9 @@ void KillSICSOBJ(void *data);
void DefaultKill(void *data);
void DefaultFree(void *data);
/* register a callback for killing the command when the node is killed */
void RegisterSICSOBJKillCmd(pSICSOBJ sicsobj, char *name);
int SaveSICSOBJ(void *data, char *name, FILE * fd);
/**

View File

@ -259,6 +259,12 @@ const char *StringDictGetNext(pStringDict self, char *pValue, int iValLen)
} else {
LLDnodeDataTo(self->iList, &sVal);
strncpy(pValue, sVal.value, iValLen);
/* strncpy is not guaranteed to be '\0' terminated */
if (iValLen > 0 && pValue[iValLen-1] != '\0') {
/* overflow */
pValue[iValLen-1] = '\0';
}
return sVal.name;
}
} else { /* start a new one */
@ -270,6 +276,11 @@ const char *StringDictGetNext(pStringDict self, char *pValue, int iValLen)
self->iTraverse = 1;
LLDnodeDataTo(self->iList, &sVal);
strncpy(pValue, sVal.value, iValLen);
/* strncpy is not guaranteed to be '\0' terminated */
if (iValLen > 0 && pValue[iValLen-1] != '\0') {
/* overflow */
pValue[iValLen-1] = '\0';
}
return sVal.name;
}
}

27
task.c
View File

@ -344,3 +344,30 @@ int TaskContinue(pTaskMan self)
self->iStop = 0;
return 1;
}
/*--------------------------------------------------------------------------*/
void TaskRemove(pTaskMan self, TaskFunc pTaskRun, void *pData)
{
int iRet;
pTaskHead pCurrent, pNext;
assert(self);
assert(self->iID == TASKERID);
pNext = self->pHead->pNext; /* skip dummy task */
while (pNext != NULL) {
pCurrent = pNext;
pNext = pCurrent->pNext;
if (pCurrent->pRun == pTaskRun && pCurrent->pData == pData) {
/* unlink */
if (pCurrent->pPrevious != NULL) {
pCurrent->pPrevious->pNext = pCurrent->pNext;
}
if (pCurrent->pNext != NULL) {
pCurrent->pNext->pPrevious = pCurrent->pPrevious;
}
free(pCurrent);
}
}
return;
}

4
task.h
View File

@ -113,5 +113,9 @@ int TaskSignal(pTaskMan self, int iSignal, void *pSigData);
pSigData.
*/
/*-------------------------------------------------------------------------*/
void TaskRemove(pTaskMan self, TaskFunc pTaskRun, void *pData);
/*
remove the task with the given task function and the given data pointer
*/
#endif