Files
sics/SCinter.c
zolliker 1ab4723261 do not write status file when corrupted
unfortunately this is only a guess
2024-11-14 09:06:01 +01:00

1138 lines
30 KiB
C

/*---------------------------------------------------------------------------
Implementation file for the SICS-interpreter.
Mark Koennecke, November 1996
Made ListObjects more intelligent: list objects according to interface etc.
Mark Koennecke, December 2003
Copyright:
Labor fuer Neutronenstreuung
Paul Scherrer Institut
CH-5423 Villigen-PSI
The authors hereby grant permission to use, copy, modify, distribute,
and license this software and its documentation for any purpose, provided
that existing copyright notices are retained in all copies and that this
notice is included verbatim in any distributions. No written agreement,
license, or royalty fee is required for any of the authorized uses.
Modifications to this software may be copyrighted by their authors
and need not follow the licensing terms described here, provided that
the new terms are clearly indicated on the first page of each file where
they apply.
IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE
IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
MODIFICATIONS.
M. Zolliker, Sept 2000, introduced formal aliases, modifications marked M.Z
Mark Koennecke, August 2001, modified SicsWriteStatus to write motor
positions on demand.
Made ListObjects more intelligent: list objects according to interface etc.
Mark Koennecke, December 2003
Extended 'dir' command (function ListObjects) to list via typename from
object descriptor. For completeness, added function PrintAllTypes.
Paul Hathaway, May 2004
Modified printXXX functions to fix duplicate write of last buffer line.
Paul Hathaway, May 2004
Added FindAlias function, Mark Koennecke, January 2007
A new type of object function has been introduced ObjectFuncSelfParse. This
type of object function parses its command itself. As of now only one is
implemented for issuing Tcl commands from the command line, which will
stay a hidden feature. If more things of this type come along, then this
has to be expanded to become a full infrastructure.
Mark Koennecke, January 2010
---------------------------------------------------------------------------*/
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <assert.h>
#include <string.h>
#include <tcl.h>
#include <time.h>
#include <limits.h>
#include "fortify.h"
#include "sics.h"
#include "splitter.h"
#include "macro.h"
#include "interface.h"
#include "motor.h"
#include "obdes.h"
#include "lld.h"
#include "dynstring.h"
/* M.Z. */
#include "definealias.h"
/* pvh */
#include "lld_str.h"
static void printList(SConnection * pCon, int listID);
static void freeList(int listID);
#define MAXLEN 256
#define MAXPAR 100
#define MAXBUF 128
/*--------------------------------------------------------------------------*/
SicsInterp *InitInterp(void)
{
SicsInterp *pInter = NULL;
int i;
pInter = (SicsInterp *) malloc(sizeof(SicsInterp));
if (!pInter) {
Log(FATAL,"sys","Error allocating memory for Interpreter");
return NULL;
}
memset(pInter, 0, sizeof(SicsInterp));
pInter->pCList = NULL;
pInter->AList.pFirst = NULL; /* M.Z. */
pInter->pTcl = (void *) MacroInit(pInter);
if (!pInter->pTcl) {
free(pInter);
return NULL;
}
pInter->iDeleting = 0;
return pInter;
}
/*------------------------------------------------------------------------*/
int AddCommandWithFlag(SicsInterp * pInterp, char *pName, ObjectFunc pFunc,
KillFunc pKFunc, void *pData, int startupOnly)
{
CommandList *pNew = NULL;
CommandList *p, *tail;
char pBueffel[512];
assert(pName);
assert(pFunc);
assert(pInterp);
strlcpy(pBueffel, pName,511);
strtolower(pBueffel);
RemoveAlias(&pInterp->AList, pBueffel); /* M.Z. */
if (FindCommand(pInterp, pBueffel) != NULL) {
return 0;
}
/* new memory */
pNew = (CommandList *) malloc(sizeof(CommandList));
if (!pNew) {
snprintf(pBueffel,sizeof(pBueffel)-1, "Out of memory creating command - %s -", pName);
Log(ERROR,"sys","%s",pBueffel);
return 0;
}
memset(pNew, 0, sizeof(CommandList));
/* if no data given, initialise with Dummy struct */
if (!pData) {
pData = (void *) CreateDummy(pBueffel);
if (!pKFunc) {
pKFunc = KillDummy;
}
}
/* initialise datastructures */
pNew->pName = strdup(pBueffel);
pNew->OFunc = pFunc;
pNew->KFunc = pKFunc;
pNew->pData = pData;
pNew->pNext = NULL;
pNew->startupOnly = startupOnly;
pNew->stat = StatisticsNew(pBueffel);
/* find end of list */
tail = NULL;
p = pInterp->pCList;
while (p != NULL) {
tail = p;
p = p->pNext;
}
if (tail == NULL) { /* first entry */
pInterp->pCList = pNew;
} else { /* insert at tail */
tail->pNext = pNew;
}
pNew->pPrevious = tail;
return 1;
}
/*------------------------------------------------------------------------*/
int AddCommand(SicsInterp * pInterp, char *pName, ObjectFunc pFunc,
KillFunc pKFunc, void *pData)
{
return AddCommandWithFlag(pInterp, pName, pFunc, pKFunc, pData, 0);
}
/*------------------------------------------------------------------------*/
int AddIniCmd(char *pName, ObjectFunc pFunc)
{
return AddCommandWithFlag(pServ->pSics, pName, pFunc, NULL, NULL, 1);
}
/*------------------------------------------------------------------------*/
int AddCmd(char *pName, ObjectFunc pFunc)
{
return AddCommandWithFlag(pServ->pSics, pName, pFunc, NULL, NULL, 0);
}
/*------------------------------------------------------------------------*/
int RemoveCommand(SicsInterp * pInterp, char *pName)
{
CommandList *pVictim = NULL;
char pBueffel[256];
assert(pInterp);
assert(pName);
strlcpy(pBueffel, pName,255);
strtolower(pBueffel);
if (pInterp->iDeleting) {
return 0;
}
/* find our victim */
pVictim = FindCommand(pInterp, pBueffel);
if (!pVictim)
return 0;
/* found, remove it */
/* kall KillFunction first */
if (pVictim->KFunc) {
void *data = pVictim->pData;
pVictim->pData = NULL; /* make data unreachable by FindCommandData before killing */
pVictim->KFunc(data);
}
/* delete and unlink data */
if (pVictim->pName) {
free(pVictim->pName);
}
if (pVictim->pPrevious) {
pVictim->pPrevious->pNext = pVictim->pNext;
}
if (pVictim->pNext) {
pVictim->pNext->pPrevious = pVictim->pPrevious;
}
/* adjust headpointer if necessary */
if (pVictim == pInterp->pCList) {
pInterp->pCList = pVictim->pNext;
}
if (pVictim->stat) {
StatisticsKill(pVictim->stat);
}
free(pVictim);
return 1;
}
#define MAXLEN 256
#define MAXCOM 50
extern char *stptok(char *s, char *tok, unsigned int toklen, char *brk);
extern char *SkipSpace(char *pPtr);
/*-----------------------------------------------------------------------*/
static char tclescape[] = "tcl:";
static int TclExecFunc(SConnection *pCon, SicsInterp *pInter, void *data,
char *command)
{
int status;
char *realcommand;
if(!SCMatchRights(pCon,usMugger)){
return 0;
}
realcommand = command + strlen(tclescape);
MacroPush(pCon);
status = Tcl_Eval(InterpGetTcl(pInter), realcommand);
MacroPop();
if(status == TCL_OK){
SCWrite(pCon,(char *)Tcl_GetStringResult(InterpGetTcl(pInter)), eValue );
return 1;
} else {
SCWrite(pCon,(char *)Tcl_GetStringResult(InterpGetTcl(pInter)), eError );
return 0;
}
return 0;
}
/*-----------------------------------------------------------------------*/
int InterpExecute(SicsInterp * self, SConnection * pCon, char *pText)
{
int iCount = 0;
int iRet;
int i, argc;
char pBueffel[1024];
CommandList *pCommand = NULL;
char pBrk[] = { " \r\n\0" };
char *pPtr;
char **argv = NULL;
commandContext comCon;
Statistics *old;
assert(self);
assert(pCon);
if(strstr(pText,tclescape) == pText){
return TclExecFunc(pCon,self,NULL,pText);
}
/* convert to argc, argv */
/* use Tcl_SplitList instead of Text2Arg, is needed for complicated Tcl syntax. M.Z. 8.2011 */
iRet = Tcl_SplitList(self->pTcl, pText, &argc, (const char ***)&argv);
if (iRet != TCL_OK) {
SCWrite(pCon, "ERROR: illegal tcl syntax", eError);
return -1;
}
/* the first one must be the target object. If not given an empty
command string was given which will be silently ignored */
if (argc < 1) {
iRet = 1;
goto deleteArgv;
}
if (argv[0] == NULL) {
SCWrite(pCon, "ERROR: failed to parse command", eError);
iRet = -1;
goto deleteArgv;
}
/* find it */
pCommand = FindCommand(self, argv[0]);
if (!pCommand) {
snprintf(pBueffel,sizeof(pBueffel)-1, "ERROR: Object -> %s <- NOT found", argv[0]);
SCWrite(pCon, pBueffel, eError);
iRet = -1;
goto deleteArgv;
}
/* invoke the command */
self->eOut = eValue;
Tcl_ResetResult((Tcl_Interp *) self->pTcl);
MacroPush(pCon);
SCSetConStatus(pCon,0);
old = StatisticsBegin(pCommand->stat);
iRet = pCommand->OFunc(pCon, self, pCommand->pData, argc, argv);
StatisticsEnd(old);
/* If a task is registered with the dev exec then conStatus is HWBusy */
if (SCGetConStatus(pCon) != HWBusy) {
/*comCon = SCGetContext(pCon); */
if (0 != strcmp("contextdo", SCGetDeviceID(pCon)))
SCWrite(pCon, "", eFinish);
}
MacroPop();
/*
* log in history if succesfull
*/
if(iRet == 1){
Log(DEBUG,"history","%s",pText);
}
deleteArgv:
Tcl_Free((char *)argv);
return iRet;
}
/*------------------------------------------------------------------------*/
CommandList *FindCommand(SicsInterp * self, char *pName)
{
CommandList *pCurrent = NULL;
char pBuffer[1024], *pCmd, *pBueffel = NULL;
assert(self);
if (self->iDeleting) {
return NULL;
}
if(strlen(pName) > sizeof(pBuffer)){
pBueffel = malloc((strlen(pName)+1)*sizeof(char));
if(pBueffel == NULL){
return NULL;
}
memset(pBueffel,0,strlen(pName)+1);
} else {
pBueffel = pBuffer;
}
memset(pBueffel,0,1024);
strlcpy(pBueffel, pName,1023);
strtolower(pBueffel);
pCmd = TranslateAlias(&self->AList, pBueffel); /* M.Z. */
pCurrent = self->pCList;
while (pCurrent) {
if (pCurrent->pName != NULL) {
if (strcmp(pCurrent->pName, pCmd) == 0) { /* M.Z. */
if(pBueffel != pBuffer){
free(pBueffel);
}
return pCurrent;
}
}
pCurrent = pCurrent->pNext;
}
if(pBueffel != pBuffer){
free(pBueffel);
}
return NULL;
}
/*------------------------------------------------------------------------*/
int WriteSicsStatus(SicsInterp * self, char *file, int iMot)
{
CommandList *pCurrent = NULL;
FILE *fd = NULL;
Dummy *pDum = NULL;
float fVal;
pIDrivable pDriv = NULL;
void *pTest = NULL;
char tmpfile[PATH_MAX];
char buf[PATH_MAX];
int l;
static int minStatusFileLength = 0;
static int firstbad = 1;
assert(self);
assert(file);
/* make sure that status file is always valid M.Z. Apr 2005 */
/* create a temporary file first */
l = strlen(file);
if (l >= sizeof tmpfile - 2) {
return 0;
}
strcpy(tmpfile, file);
tmpfile[l] = '.';
tmpfile[l + 1] = '\0';
remove(tmpfile); /* remove already existing file */
fd = fopen(tmpfile, "w");
if (!fd) {
return 0;
}
/* cycle through the list */
pCurrent = self->pCList;
while (pCurrent) {
pDum = (Dummy *) pCurrent->pData;
if (pDum) {
pDum->pDescriptor->SaveStatus(pCurrent->pData, pCurrent->pName, fd);
if (iMot) {
/*
save values of motors but not of environment devices as they
may not be present the next time round
*/
pDriv = pDum->pDescriptor->GetInterface(pDum, DRIVEID);
pTest = pDum->pDescriptor->GetInterface(pDum, ENVIRINTERFACE);
if (pDriv && !pTest) {
if (strcmp(pDum->pDescriptor->name, "Motor") == 0) {
MotorGetSoftPosition((pMotor) pDum, pServ->dummyCon, &fVal);
} else {
fVal = pDriv->GetValue(pDum, pServ->dummyCon);
}
if (fVal > -990.) {
fprintf(fd, "syncdrive %s %f\n", pCurrent->pName, fVal);
}
}
}
}
pCurrent = pCurrent->pNext;
}
if (iMot) {
fprintf(fd, "Success \n");
}
l = ftell(fd);
if (l <= minStatusFileLength) {
/* do not rename file, if length is short (this seems to happen when the computer crashes, why?)*/
snprintf(buf, sizeof buf, "do not write status file with length only %d", l);
Log(FATAL,"sys", buf);
fclose(fd);
strcpy(buf, tmpfile);
l = strlen(buf);
if (firstbad) {
if (l < sizeof buf - 12) {
firstbad = 0;
snprintf(buf + l, 12, "%ld", time(NULL));
rename(tmpfile, buf);
}
} else {
buf[l-1] = '_';
rename(tmpfile, buf);
}
return 1;
}
minStatusFileLength = l / 2;
fclose(fd);
/* rename temporary to final file (this is an atomic action) */
if (0 > rename(tmpfile, file)) {
return 0;
}
return 1;
}
/*------------------------------------------------------------------------*/
void DeleteInterp(SicsInterp * self)
{
CommandList *pCurrent = NULL;
CommandList *pTemp, *tail;
Tcl_Interp *pTcl = NULL;
int i;
assert(self);
self->iDeleting = 1;
/* find end of list */
tail = NULL;
pCurrent = self->pCList;
while (pCurrent != NULL) {
tail = pCurrent;
pCurrent = pCurrent->pNext;
}
/* delete Commandlist (reversed order) */
if (tail) {
pCurrent = tail;
while (pCurrent) {
pCurrent->pNext = NULL; /* inhibit access to killed commands by FindCommandData */
if (pCurrent->KFunc) {
void *data = pCurrent->pData;
pCurrent->pData = NULL; /* make data unreachable by FindCommandData before killing */
pCurrent->KFunc(data);
}
if (pCurrent->pName) {
/* printf("Deleting %s\n",pCurrent->pName); */
free(pCurrent->pName);
}
if (pCurrent->stat) {
StatisticsKill(pCurrent->stat);
}
pTemp = pCurrent->pPrevious;
free(pCurrent);
pCurrent = pTemp;
}
}
FreeAliasList(&self->AList); /* M.Z. */
/* clear Tcl_Interpreter. Must be AFTER deleting command list because
some devices may have Tcl drivers which need to be accessed for
proper closing of devices.
*/
pTcl = (Tcl_Interp *) self->pTcl;
if (pTcl) {
/*
uncommented: the current versions of Tcl (8.3,4) dump core with a
memory problem deep in the Tcl library. This causes a core dump on
each SICS restart and breaks the use of external tools.
Tcl_DeleteInterp(pTcl);
call KillSicsUnknown instead to clean up all memory properly. M.Z., Apr 05
*/
Tcl_DeleteInterp(pTcl);
KillSicsUnknown();
}
free(self);
}
/*------------------------------------------------------------------------*/
static void printAll(SicsInterp * pSics, SConnection * pCon)
{
CommandList *pCurrent;
char pBueffel[256];
int iNum = 0;
assert(pSics);
assert(pCon);
pCurrent = pSics->pCList;
while (pCurrent) {
if (iNum == 0) {
strlcpy(pBueffel, pCurrent->pName,255);
iNum++;
} else if (iNum < 4) {
strlcat(pBueffel, " ",255);
strlcat(pBueffel, pCurrent->pName,255);
iNum++;
} else {
strlcat(pBueffel, " ",255);
strlcat(pBueffel, pCurrent->pName,255);
strcat(pBueffel, "\r\n");
SCWrite(pCon, pBueffel, eValue);
iNum = 0;
pBueffel[0] = '\0';
}
pCurrent = pCurrent->pNext;
}
/* write final entries */
if (strlen(pBueffel) > 2) {
strlcat(pBueffel, "\r\n",255);
SCWrite(pCon, pBueffel, eValue);
}
}
/*------------------------------------------------------------------------*/
/* compareStringNode wraps strcmp for use in findNode(LLD module) calls */
int compareStringNode(const void *pStr1, const void *ppStr2)
{
return strcmp((char *) pStr1, *(char **) ppStr2);
}
/*------------------------------------------------------------------------
printAllTypes prints the list of types of objects instantiated on the
CommandList.
iFiltered=0 gives all objects including interpreter command objects
iFiltered=1 gives types where object name is not the same as its type
-------------------------------------------------------------------------*/
static void printAllTypes(SicsInterp * pSics, SConnection * pCon,
int iFiltered)
{
CommandList *pCurrent = NULL;
char pBueffel[256];
char pName_lc[256];
char pType_lc[256];
char *pType;
Dummy *pTest;
int typeListID;
assert(pSics);
assert(pCon);
pBueffel[0] = '\0';
typeListID = LLDstringCreate();
if (-1 == typeListID) {
strcpy(pBueffel, "ERROR: Cannot generate list of object types\r\n");
SCWrite(pCon, pBueffel, eValue);
return;
}
pCurrent = pSics->pCList;
while (pCurrent) {
if (NULL != pCurrent->pData) {
pTest = (pDummy) pCurrent->pData;
if (NULL != pTest->pDescriptor) {
pType = pTest->pDescriptor->name;
strlcpy(pType_lc, pType,255);
strtolower(pType_lc);
LLDnodePtr2First(typeListID);
/* int LLDnodeFind( int List, CompFunPtr Compare, void * DataPtr ); */
/* */
/* Find *DataPtr in the List using the *Compare function. */
/* Returns the return value of *Compare. */
/* 0 == equal == found. */
/* non-zero == not found. Current node is set to found node. */
/* Returns 2 for an empty list. */
/* NB: First checked node is current node, then search to end of list */
if (0 != LLDnodeFind(typeListID, compareStringNode, (void *) pType)) { /* empty list or 'typename' not found */
strlcpy(pName_lc, pCurrent->pName,255);
strtolower(pName_lc);
if ((0 == iFiltered) || ((1 == iFiltered) && (0 != strcmp(pType_lc, pName_lc)))) { /*ie Add if unfiltered or pass filter(name!=typename) */
LLDstringAdd(typeListID, pType);
}
}
}
}
pCurrent = pCurrent->pNext;
}
printList(pCon, typeListID);
freeList(typeListID);
}
/*-----------------------------------------------------------------------
printInterface prints only those objects which implement an interface
as specified bi the id given
-------------------------------------------------------------------------*/
static void printInterface(SicsInterp * pSics, SConnection * pCon, int id)
{
CommandList *pCurrent;
char pBueffel[256];
int iNum = 0;
pObjectDescriptor pObj = NULL;
assert(pSics);
assert(pCon);
pBueffel[0] = '\0';
pCurrent = pSics->pCList;
while (pCurrent) {
pObj = FindDescriptor(pCurrent->pData);
if (pObj != NULL) {
if (pObj->GetInterface(pObj, id) != NULL) {
if (iNum == 0) {
strlcpy(pBueffel, pCurrent->pName,255);
iNum++;
} else if (iNum < 4) {
strlcat(pBueffel, " ",255);
strlcat(pBueffel, pCurrent->pName,255);
iNum++;
} else {
strlcat(pBueffel, " ",255);
strlcat(pBueffel, pCurrent->pName,255);
strlcat(pBueffel, "\r\n",255);
SCWrite(pCon, pBueffel, eValue);
iNum = 0;
pBueffel[0] = '\0';
}
}
}
pCurrent = pCurrent->pNext;
}
/* write final entries */
strcat(pBueffel, "\r\n");
SCWrite(pCon, pBueffel, eValue);
}
/*-----------------------------------------------------------------------
printMatch prints only those objects which match the wildcard string given
-------------------------------------------------------------------------*/
extern int match(const char *mask, const char *name); /* from wwildcard.c */
static void printMatch(SicsInterp * pSics, SConnection * pCon, char *mask)
{
CommandList *pCurrent;
char pBueffel[256];
int iNum = 0;
pObjectDescriptor pObj = NULL;
assert(pSics);
assert(pCon);
pBueffel[0] = '\0';
pCurrent = pSics->pCList;
while (pCurrent) {
pObj = FindDescriptor(pCurrent->pData);
if (pObj != NULL) {
if (!match(mask, pObj->name)) {
if (iNum == 0) {
strlcpy(pBueffel, pCurrent->pName,255);
iNum++;
} else if (iNum < 4) {
strlcat(pBueffel, " ",255);
strlcat(pBueffel, pCurrent->pName,255);
iNum++;
} else {
strlcat(pBueffel, " ",255);
strlcat(pBueffel, pCurrent->pName,255);
strlcat(pBueffel, "\r\n",255);
SCWrite(pCon, pBueffel, eValue);
pBueffel[0] = '\0';
iNum = 0;
}
}
}
pCurrent = pCurrent->pNext;
}
/* write final entries */
strlcat(pBueffel, "\r\n",255);
SCWrite(pCon, pBueffel, eValue);
}
/*-----------------------------------------------------------------------
printType prints only those objects whose descriptor match the type given
-------------------------------------------------------------------------*/
static void printType(SicsInterp * pSics, SConnection * pCon,
char *typeName)
{
CommandList *pCurrent;
Tcl_DString txt;
char pBueffel[256];
int iNum = 0;
assert(pSics);
assert(pCon);
Tcl_DStringInit(&txt);
pBueffel[0] = '\0';
pCurrent = pSics->pCList;
while (pCurrent) {
if (pCurrent->pData != NULL) {
if (iHasType(pCurrent->pData, typeName)) {
if (iNum == 0) {
strlcpy(pBueffel, pCurrent->pName,255);
iNum++;
} else if (iNum < 4) {
strlcat(pBueffel, " ",255);
strlcat(pBueffel, pCurrent->pName,255);
iNum++;
} else {
strlcat(pBueffel, " ",255);
strlcat(pBueffel, pCurrent->pName,255);
strlcat(pBueffel, "\r\n",255);
Tcl_DStringAppend(&txt, pBueffel, -1);
pBueffel[0] = '\0';
iNum = 0;
}
}
}
pCurrent = pCurrent->pNext;
}
/* write final entries */
strlcat(pBueffel, "\r\n",255);
SCWrite(pCon, Tcl_DStringValue(&txt), eValue);
Tcl_DStringFree(&txt);
}
/*--------------------------------------------------------------------------*/
int ListObjects(SConnection * pCon, SicsInterp * pSics, void *pData,
int argc, char *argv[])
{
char pType[256];
int i;
if (argc < 2) {
printAll(pSics, pCon);
return 1;
}
strtolower(argv[1]);
/*
stand alone subcommands
*/
if (strstr(argv[1], "var") != NULL) {
printType(pSics, pCon, "SicsVariable");
return 1;
}
if (strstr(argv[1], "mot") != NULL) {
printType(pSics, pCon, "Motor");
return 1;
}
/* Start Mod by Paul Hathaway May 2004 */
if (0 == strcmp(argv[1], "types")) {
printAllTypes(pSics, pCon, 1);
return 1;
}
/* End Mod by Paul Hathaway May 2004 */
/*
subcommand with three args
*/
if (argc < 3) {
SCWrite(pCon, "ERROR: missing parameter to command or bad subcommand",
eError);
return 0;
}
/*
interface
*/
if (strcmp(argv[1], "inter") == 0) {
strtolower(argv[2]);
if (strstr(argv[2], "driv") != NULL) {
printInterface(pSics, pCon, DRIVEID);
return 1;
}
if (strstr(argv[2], "coun") != NULL) {
printInterface(pSics, pCon, COUNTID);
return 1;
}
if (strstr(argv[2], "env") != NULL) {
printInterface(pSics, pCon, ENVIRINTERFACE);
return 1;
}
SCWrite(pCon, "ERROR: interface description not recognized", eError);
return 0;
}
/*
match
*/
if (strcmp(argv[1], "match") == 0) {
printMatch(pSics, pCon, argv[2]);
return 1;
}
/* Start Mod by Paul Hathaway May 2004 */
/*
* type-based dir
*/
if (0 == strcmp(argv[1], "type")) {
if (0 == strcmp(argv[2], "*")) {
printAllTypes(pSics, pCon, 0);
return 1;
}
strlcpy(pType, argv[2],255);
/* Cater for multi-word types eg 'Environment Monitor' */
if (argc > 3) {
for (i = 3; i < argc; i++) {
strlcat(pType, " ",255);
strlcat(pType, argv[i],255);
}
}
printType(pSics, pCon, pType);
return 1;
}
/* End Mod by Paul Hathaway May 2004 */
return 1;
}
/*---------------------------------------------------------------------------*/
int InterpWrite(SicsInterp * pSics, char *buffer)
{
Tcl_Interp *pTcl = NULL;
assert(pSics);
pTcl = (Tcl_Interp *) pSics->pTcl;
if(Tcl_GetStringResult(pTcl) != buffer){
Tcl_SetResult(pTcl, buffer, TCL_VOLATILE);
}
return 1;
}
/*---------------------------------------------------------------------------*/
Tcl_Interp *InterpGetTcl(SicsInterp * pSics)
{
Tcl_Interp *pTcl = NULL;
pTcl = (Tcl_Interp *) pSics->pTcl;
return pTcl;
}
/*---------------------------------------------------------------------------*/
void strtolower(char *pText)
{
assert(pText);
while (*pText != '\0') {
*pText = tolower(*pText);
pText++;
}
}
/*---------------------------------------------------------------------------*/
void argtolower(int argc, char *argv[])
{
int i;
for (i = 0; i < argc; i++) {
strtolower(argv[i]);
}
}
/*------------------------------------------------------------------------*/
char *FindAlias(SicsInterp * self, void *pData)
{
CommandList *pCurrent = NULL;
assert(self);
if (self->iDeleting) {
return NULL;
}
pCurrent = self->pCList;
while (pCurrent) {
if (pCurrent->pData == pData) {
return pCurrent->pName;
}
pCurrent = pCurrent->pNext;
}
return NULL;
}
/*---------------------------------------------------------------------------*/
void *FindCommandData(SicsInterp * pSics, char *name, char *cclass)
{
CommandList *pCom;
pDummy pDum = NULL;
pCom = FindCommand(pSics, name);
if (!pCom) {
return NULL;
}
if (!pCom->pData)
return NULL;
if (cclass == NULL) {
return pCom->pData;
}
pDum = (pDummy) pCom->pData;
if (strcmp(pDum->pDescriptor->name, cclass) == 0) {
return pCom->pData;
}
return NULL;
}
/*---------------------------------------------------------------------------*/
pObjectDescriptor FindCommandDescriptor(SicsInterp * pSics, char *name)
{
CommandList *pCom;
pCom = FindCommand(pSics, name);
if (pCom == NULL || pCom->pData == NULL) {
return NULL;
}
return ((pDummy) pCom->pData)->pDescriptor;
}
/*------------------------------------------------------------------------*/
void *FindDrivable(SicsInterp * pSics, char *name)
{
pIDrivable pDriv;
pDummy pDum = NULL;
CommandList *pCom = NULL;
pCom = FindCommand(pSics, name);
if (pCom != NULL) {
pDum = (pDummy) pCom->pData;
if (pDum != NULL) {
return pDum->pDescriptor->GetInterface(pDum, DRIVEID);
}
}
return NULL;
}
/*------------------------------------------------------------------------*/
/* printList: Print contents of an LLDstring list
* Envisaged to be used by other extensions/refactoring utilising dynamic
* linked list module. May extend toallow different output formats
* (eg multi/single column) via switches
*/
static void printList(SConnection * pCon, int listID)
{
char pBueffel[MAXBUF];
int retCode;
if (0 != LLDnodePtr2First(listID)) {
do {
retCode = LLDstringData(listID, NULL);
if ((MAXBUF - 3) > retCode) {
retCode = LLDstringData(listID, pBueffel);
strcat(pBueffel, "\r\n");
SCWrite(pCon, pBueffel, eValue);
}
} while (0 != LLDnodePtr2Next(listID));
}
}
/*------------------------------------------------------------------------*/
static void freeList(int listID)
{
do {
LLDdeleteString(listID);
} while (0 != LLDnodePtr2First(listID));
LLDdelete(listID);
}
/*------------------------------------------------------------------------*/
void RemoveStartupCommands(void)
{
CommandList *pCurrent, *pNext;
pCurrent = pServ->pSics->pCList;
while (pCurrent) {
pNext = pCurrent->pNext;
if (pCurrent->startupOnly) {
RemoveCommand(pServ->pSics, pCurrent->pName);
}
pCurrent = pNext;
}
}
/*---------------------------------------------------------------------*/
char *FindAliases(SicsInterp * pSics, char *name)
{
pDynString result = NULL;
CommandList *pOri = NULL, *pCom = NULL;
char *pTrans = NULL, *charResult = NULL;
int first;
pOri = FindCommand(pSics, name);
if (pOri == NULL) {
return NULL;
}
if (pOri->pData == NULL) {
return NULL;
}
result = CreateDynString(64, 64);
if (result == NULL) {
return NULL;
}
/* try first to locate Markus style aliases */
pTrans = TranslateAlias(&pSics->AList, name);
if (strcmp(pTrans, name) != 0) {
DynStringCopy(result, pTrans);
charResult = strdup(GetCharArray(result));
DeleteDynString(result);
return charResult;
}
/*
* locate SicsAlias style aliases by comparing the original
* data pointer with the data pointers of other commands
*/
first = 1;
pCom = pSics->pCList;
while (pCom != NULL) {
if (pCom != pOri && pCom->pData == pOri->pData) {
if (first) {
DynStringCopy(result, pCom->pName);
first = 0;
} else {
DynStringConcat(result, ",");
DynStringConcat(result, pCom->pName);
}
}
pCom = pCom->pNext;
}
charResult = strdup(GetCharArray(result));
DeleteDynString(result);
return charResult;
}
/*---------------------------------------------------------------------*/
void ForEachCommand(int (*scanFunction)
(char *name, pDummy object, void *userData)
, void *userData)
{
CommandList *pCurrent;
for (pCurrent = pServ->pSics->pCList;
pCurrent != NULL; pCurrent = pCurrent->pNext) {
if (scanFunction(pCurrent->pName, pCurrent->pData, userData) == 0) {
return;
}
}
}