Initial revision
This commit is contained in:
825
macro.c
Normal file
825
macro.c
Normal file
@@ -0,0 +1,825 @@
|
||||
/*--------------------------------------------------------------------------
|
||||
|
||||
All you need to evaluate macros with SICS.
|
||||
|
||||
The implmentation fo the macro stuff is complex and non intuitive.
|
||||
This is the price to pay for adding the extremly powerful and
|
||||
strong Tcl-interpreter to SICS. The problem is that Tcl does not
|
||||
know anything about connections and our error handling. We have
|
||||
to transport this around it. This is done via the unknown mechanism.
|
||||
The unknown-command is called any time Tcl does not find a command
|
||||
in its command list. Our unknown calls Sics-objects than and
|
||||
provides proper connection and Sics-information. As this unknown is
|
||||
going to hold the connection info, we need one interpreter per
|
||||
connection. In order to transport interrupt conditions (motor
|
||||
going bang) we need an interrupt code field in Connection.
|
||||
|
||||
Mark Koennecke, November 1996
|
||||
|
||||
Mark Koennecke, April 1999
|
||||
where code added.
|
||||
|
||||
Mark Koennecke, December 1999
|
||||
InternalFileEval added
|
||||
|
||||
|
||||
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.
|
||||
--------------------------------------------------------------------------*/
|
||||
#include "fortify.h"
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <tcl.h>
|
||||
#include "SCinter.h"
|
||||
#include "conman.h"
|
||||
#include "macro.h"
|
||||
#include "status.h"
|
||||
#include "obdes.h"
|
||||
#include "splitter.h"
|
||||
#include "ifile.h"
|
||||
#include "Dbg.h"
|
||||
#include "servlog.h"
|
||||
|
||||
#define SICSERROR "005567SICS"
|
||||
|
||||
/* in SCinter.c, but only used here */
|
||||
|
||||
extern Tcl_Interp *InterpGetTcl(SicsInterp *pSics);
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
SICS Macro uses the Tcl "unknown" mechanism to access the Sics-objects.
|
||||
The Tcl algorithm is to call a command called unknown when it cannot
|
||||
match a command with the Tcl-built ins. Sics will now define the unknown
|
||||
to call the Sics object invocation mechanism. In order to do this
|
||||
properly the unknown needs to know about the connection invoking the
|
||||
command and the SicsInterpreter to use. A suitable datastructure will
|
||||
be defined below. And a function which be planted into Tcl to do the
|
||||
trick.
|
||||
-----------------------------------------------------------------------------*/
|
||||
#define MAXSTACK 50
|
||||
|
||||
|
||||
struct __SicsUnknown {
|
||||
SConnection *pCon[MAXSTACK];
|
||||
int iStack;
|
||||
SicsInterp *pInter;
|
||||
};
|
||||
|
||||
static struct __SicsUnknown *pUnbekannt = NULL;
|
||||
/*---------------------------------------------------------------------------*/
|
||||
int MacroPush(SConnection *pCon)
|
||||
{
|
||||
assert(pUnbekannt);
|
||||
pUnbekannt->iStack++;
|
||||
if(pUnbekannt->iStack >= MAXSTACK)
|
||||
{
|
||||
SCWrite(pCon,"ERROR: Out of Stack in macro.c",eError);
|
||||
return 0;
|
||||
}
|
||||
pUnbekannt->pCon[pUnbekannt->iStack] = pCon;
|
||||
return 1;
|
||||
}
|
||||
/*-------------------------------------------------------------------------*/
|
||||
int MacroPop(void)
|
||||
{
|
||||
assert(pUnbekannt);
|
||||
pUnbekannt->iStack--;
|
||||
if(pUnbekannt->iStack < 1)
|
||||
{
|
||||
pUnbekannt->iStack = 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static int SicsUnknownProc(ClientData pData, Tcl_Interp *pInter,
|
||||
int argc, char *argv[])
|
||||
{
|
||||
struct __SicsUnknown *pSics = NULL;
|
||||
char **myarg = NULL;
|
||||
int margc;
|
||||
SicsInterp *pSinter = NULL;
|
||||
SConnection *pCon = NULL;
|
||||
CommandList *pCommand = NULL;
|
||||
int iRet,i;
|
||||
int iMacro;
|
||||
|
||||
/* get the datastructures */
|
||||
pSics = (struct __SicsUnknown *)pData;
|
||||
assert(pSics);
|
||||
pSinter = pSics->pInter;
|
||||
pCon = pSics->pCon[pSics->iStack];
|
||||
assert(pSinter);
|
||||
assert(pCon);
|
||||
|
||||
|
||||
/* shorten the argc, argv by one and invoke */
|
||||
margc = argc -1;
|
||||
myarg = &argv[1];
|
||||
|
||||
/* find object */
|
||||
if(margc < 1)
|
||||
{
|
||||
Tcl_SetResult(pInter,"No command found",TCL_VOLATILE);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
pCommand = FindCommand(pSinter,myarg[0]);
|
||||
if(!pCommand)
|
||||
{
|
||||
Tcl_AppendResult(pInter,"Object ",myarg[0]," not found",NULL);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
/* invoke */
|
||||
iMacro = SCinMacro(pCon);
|
||||
SCsetMacro(pCon,1);
|
||||
iRet = pCommand->OFunc(pCon,pSinter,pCommand->pData,margc, myarg);
|
||||
SCsetMacro(pCon,iMacro);
|
||||
|
||||
/* finish */
|
||||
if(iRet)
|
||||
{
|
||||
return TCL_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
Tcl_SetVar(pInter,SICSERROR,"yes",TCL_GLOBAL_ONLY);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------------------*/
|
||||
static void UnknownKill(ClientData pData)
|
||||
{
|
||||
struct __SicsUnknown *pU = NULL;
|
||||
|
||||
pU = (struct __SicsUnknown *)pData;
|
||||
if(pU->pCon[0])
|
||||
{
|
||||
SCDeleteConnection(pU->pCon[0]);
|
||||
}
|
||||
free(pData);
|
||||
pUnbekannt = NULL;
|
||||
}
|
||||
/*--------------------------------------------------------------------------
|
||||
initialises a Tcl-Interpreter, installs SICS unknown mechanism and kills
|
||||
a few dangerous commands from the normal Tcl command set
|
||||
*/
|
||||
extern int initcl_Init(Tcl_Interp *pInter);
|
||||
|
||||
Tcl_Interp *MacroInit(SicsInterp *pSics)
|
||||
{
|
||||
Tcl_Interp *pInter = NULL;
|
||||
struct __SicsUnknown *pUnknown = NULL;
|
||||
char *pPtr = NULL;
|
||||
char *pPtr2 = NULL;
|
||||
FILE *fp = NULL;
|
||||
char pBueffel[512];
|
||||
int iRet;
|
||||
|
||||
assert(pSics);
|
||||
|
||||
/* create interpreter and unknown */
|
||||
pInter = Tcl_CreateInterp();
|
||||
pUnknown = (struct __SicsUnknown *)malloc(sizeof(struct __SicsUnknown));
|
||||
if( (!pInter) || (!pUnknown) )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* install unknown command */
|
||||
memset(pUnknown,0,sizeof(struct __SicsUnknown));
|
||||
pUnknown->pCon[0] = SCCreateDummyConnection(pSics);
|
||||
pUnknown->iStack = 0;
|
||||
pUnknown->pInter = pSics;
|
||||
pUnbekannt = pUnknown;
|
||||
Tcl_CreateCommand(pInter,"SicsUnknown",SicsUnknownProc,pUnknown, UnknownKill);
|
||||
|
||||
/* delete dangers */
|
||||
Tcl_DeleteCommand(pInter,"exit");
|
||||
Tcl_DeleteCommand(pInter,"socket");
|
||||
Tcl_DeleteCommand(pInter,"vwait");
|
||||
Tcl_DeleteCommand(pInter,"exec");
|
||||
|
||||
/* default initialisation */
|
||||
Tcl_SetVar(pInter,"auto_path"," ",TCL_GLOBAL_ONLY);
|
||||
initcl_Init(pInter);
|
||||
|
||||
/* initialise Don Libber Tcl-debugger */
|
||||
/* Dbg_Init(pInter); */
|
||||
|
||||
return pInter;
|
||||
}
|
||||
/*--------------------------------------------------------------------------*/
|
||||
void MacroDelete(Tcl_Interp *pInter)
|
||||
{
|
||||
Tcl_DeleteInterp(pInter);
|
||||
}
|
||||
/*-------------------------------------------------------------------------
|
||||
Find the first word of a command string
|
||||
*/
|
||||
static void FirstWord(char *pSource, char *pTarget)
|
||||
{
|
||||
int i, iLength, iStart, iPos;
|
||||
|
||||
iLength = strlen(pSource);
|
||||
|
||||
/* find start */
|
||||
for(i = 0, iStart = 0; i < iLength; i++)
|
||||
{
|
||||
if(pSource[i] != ' ')
|
||||
{
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
iStart++;
|
||||
}
|
||||
}
|
||||
|
||||
/* do a quick check */
|
||||
if(iStart >= iLength - 2)
|
||||
{
|
||||
pTarget[0] = '\0';
|
||||
return;
|
||||
}
|
||||
|
||||
/* do the copy */
|
||||
for(i = iStart, iPos = 0; i < iLength; i++)
|
||||
{
|
||||
if(pSource[i] != ' ')
|
||||
{
|
||||
pTarget[iPos] = pSource[i];
|
||||
iPos++;
|
||||
}
|
||||
else
|
||||
{
|
||||
pTarget[iPos] = '\0';
|
||||
return;
|
||||
}
|
||||
}
|
||||
pTarget[iPos] = '\0';
|
||||
return;
|
||||
}
|
||||
/*-------------------------------------------------------------------------*/
|
||||
static char *pWhere = NULL;
|
||||
static char *pFile = NULL;
|
||||
|
||||
int MacroWhere(SConnection *pCon, SicsInterp *pInter, void *pData,
|
||||
int argc, char *argv[])
|
||||
{
|
||||
assert(pCon);
|
||||
|
||||
if(pWhere)
|
||||
{
|
||||
SCWrite(pCon,pWhere,eValue);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
/*-------------------------------------------------------------------------*/
|
||||
void WhereKill(void *pData)
|
||||
{
|
||||
|
||||
if(pWhere)
|
||||
{
|
||||
free(pWhere);
|
||||
pWhere = NULL;
|
||||
}
|
||||
if(pFile)
|
||||
{
|
||||
free(pFile);
|
||||
pFile = NULL;
|
||||
}
|
||||
|
||||
if(pData)
|
||||
KillDummy(pData);
|
||||
|
||||
}
|
||||
/*--------------------------------------------------------------------------*/
|
||||
int MacroFileEval(SConnection *pCon, SicsInterp *pInter, void *pData,
|
||||
int argc, char *argv[])
|
||||
{
|
||||
FILE *fp = NULL;
|
||||
char pBueffel[512];
|
||||
int iChar;
|
||||
int i, iRun;
|
||||
Tcl_DString command;
|
||||
char *pCom = NULL;
|
||||
int iRet;
|
||||
Status eOld;
|
||||
Tcl_Interp *pTcl = NULL;
|
||||
int iLine = 0;
|
||||
|
||||
assert(pCon);
|
||||
assert(pInter);
|
||||
pTcl = InterpGetTcl(pInter);
|
||||
|
||||
/* check authorisation: only users permitted here */
|
||||
if(!SCMatchRights(pCon,usUser))
|
||||
{
|
||||
SCWrite(pCon,"ERROR: Insufficient Privilege to do FileEval",eError);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* open filename */
|
||||
if( argc < 2)
|
||||
{
|
||||
SCWrite(pCon,"ERROR: No filename specified ",eError);
|
||||
return 0;
|
||||
}
|
||||
fp = fopen(argv[1],"r");
|
||||
if(!fp)
|
||||
{
|
||||
sprintf(pBueffel," Failed to open file -> %s <- ",argv[1]);
|
||||
SCWrite(pCon,pBueffel,eError);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* handle status first */
|
||||
eOld = GetStatus();
|
||||
SetStatus(eBatch);
|
||||
|
||||
SICSLogWrite("Evaluating in MacroFileEval",eValue);
|
||||
SICSLogWrite(argv[1],eValue);
|
||||
if(pFile)
|
||||
{
|
||||
free(pFile);
|
||||
}
|
||||
pFile = strdup(argv[1]);
|
||||
|
||||
/* cycle through file and execute complete commands */
|
||||
i = 0;
|
||||
Tcl_DStringInit(&command);
|
||||
iRun = 1;
|
||||
while(iRun)
|
||||
{
|
||||
iChar = fgetc(fp);
|
||||
if(iChar == EOF)
|
||||
{
|
||||
iChar = (int)'\n';
|
||||
iRun = 0;
|
||||
}
|
||||
if( iChar == (int)'\n' )
|
||||
{
|
||||
pBueffel[i] = (char)iChar;
|
||||
pBueffel[i+1] = '\0';
|
||||
Tcl_DStringAppend(&command,pBueffel,-1);
|
||||
pCom = Tcl_DStringValue(&command);
|
||||
if(Tcl_CommandComplete(pCom))
|
||||
{
|
||||
SetStatus(eEager);
|
||||
FirstWord(pCom,pBueffel);
|
||||
if(FindCommand(pInter,pBueffel) != NULL)
|
||||
{
|
||||
sprintf(pBueffel,"%s:%d>> %s",pFile,iLine,pCom);
|
||||
SCWrite(pCon,pBueffel,eValue);
|
||||
if(pWhere != NULL)
|
||||
{
|
||||
free(pWhere);
|
||||
}
|
||||
pWhere = strdup(pBueffel);
|
||||
iLine++;
|
||||
}
|
||||
iRet = Tcl_Eval(pTcl,pCom);
|
||||
SetStatus(eBatch);
|
||||
if(iRet != TCL_OK)
|
||||
{
|
||||
/* write TCL error and check for total interrupt */
|
||||
if(Tcl_GetVar(pTcl,SICSERROR,TCL_GLOBAL_ONLY) == NULL)
|
||||
{ /* Tcl error */
|
||||
if(strlen(pTcl->result) > 2)
|
||||
{
|
||||
SCWrite(pCon,pTcl->result,eError);
|
||||
}
|
||||
pCom = Tcl_DStringValue(&command);
|
||||
sprintf(pBueffel,"ERROR: in Tcl line: %s",pCom);
|
||||
SCWrite(pCon,pBueffel,eError);
|
||||
}
|
||||
else /* SICS error */
|
||||
{
|
||||
Tcl_UnsetVar(pTcl,SICSERROR,TCL_GLOBAL_ONLY);
|
||||
/* SCWrite(pCon,pTcl->result,eError); */
|
||||
}
|
||||
}
|
||||
if(SCGetInterrupt(pCon) >= eAbortBatch)
|
||||
{
|
||||
fclose(fp);
|
||||
Tcl_DStringFree(&command);
|
||||
SCWrite(pCon,"ERROR: batch processing interrupted",eError);
|
||||
SetStatus(eOld);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
SCSetInterrupt(pCon,eContinue);
|
||||
SCSetError(pCon,OKOK);
|
||||
}
|
||||
Tcl_DStringFree(&command);
|
||||
}
|
||||
i = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
pBueffel[i] = (char)iChar;
|
||||
i++;
|
||||
}
|
||||
} /* end while */
|
||||
|
||||
|
||||
/* clean up */
|
||||
fclose(fp);
|
||||
Tcl_DStringFree(&command);
|
||||
SetStatus(eOld);
|
||||
SCSendOK(pCon);
|
||||
return 1;
|
||||
}
|
||||
/*----------------------------------------------------------------------
|
||||
InternalFileEval evaluates a file but on a dummy connection which
|
||||
only writes log files. It also configures a log file for output
|
||||
which will be the name of the input file but with .log appended.
|
||||
This is here in order to support the evaluation of command files
|
||||
generated in a specific directory from the WWW-interface. If the latter
|
||||
does not get through, this can safely be deleted.
|
||||
*/
|
||||
|
||||
int InternalFileEval(SConnection *pCon, SicsInterp *pInter, void *pData,
|
||||
int argc, char *argv[])
|
||||
{
|
||||
SConnection *pIntern = NULL;
|
||||
int iRet;
|
||||
char *pFil = NULL, *pExt = NULL;
|
||||
|
||||
|
||||
/* we need a filename */
|
||||
if( argc < 2)
|
||||
{
|
||||
SCWrite(pCon,"ERROR: No filename specified ",eError);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* allocate a dummy connection for this */
|
||||
pIntern = SCCreateDummyConnection(pInter);
|
||||
if(!pInter)
|
||||
{
|
||||
SCWrite(pCon,"ERROR: out of memory in InternalFileEval",eError);
|
||||
return NULL;
|
||||
}
|
||||
SCnoSock(pIntern);
|
||||
|
||||
/* configure the log file */
|
||||
pFil = strdup(argv[1]);
|
||||
pExt = strrchr(pFil,(int)'.');
|
||||
if(!pExt)
|
||||
{
|
||||
SCWrite(pCon,"ERROR: no extension found in InternalFileEval",
|
||||
eError);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
strcpy(pExt,".log");
|
||||
SCAddLogFile(pIntern,pFil);
|
||||
free(pFil);
|
||||
}
|
||||
|
||||
/* invoke the fileeval */
|
||||
MacroPush(pIntern);
|
||||
iRet = MacroFileEval(pIntern,pInter,pData,argc,argv);
|
||||
MacroPop();
|
||||
|
||||
/* remove our internal connection */
|
||||
SCDeleteConnection(pIntern);
|
||||
return iRet;
|
||||
}
|
||||
/*--------------------------------------------------------------------------
|
||||
ClientPut is installed as a command to write data to the client from
|
||||
a server script. Syntax:
|
||||
ClientPut text outputcode
|
||||
The output code is optional and and defaults to eStatus.
|
||||
---------------------------------------------------------------------------*/
|
||||
|
||||
#include "outcode.c"
|
||||
|
||||
int ClientPut(SConnection *pCon, SicsInterp *pInter, void *pData,
|
||||
int argc, char *argv[])
|
||||
{
|
||||
OutCode eOut = eStatus;
|
||||
int i = 0, iCode, iLen;
|
||||
int iMacro;
|
||||
char *ppCode;
|
||||
char *pMessage = NULL;
|
||||
|
||||
assert(pCon);
|
||||
assert(pInter);
|
||||
|
||||
if(argc < 2)
|
||||
{
|
||||
SCWrite(pCon,"Insufficient arguments to ClientPut",eError);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* handle optional I/O codes */
|
||||
if(argc > 2)
|
||||
{
|
||||
/* the last one must be the code */
|
||||
iCode = argc - 1;
|
||||
ppCode = strdup(argv[iCode]);
|
||||
strtolower(ppCode);
|
||||
while(pCode[i] != NULL)
|
||||
{
|
||||
if(strcmp(pCode[i],ppCode)== NULL)
|
||||
{
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
if(ppCode)
|
||||
{
|
||||
free(ppCode);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
i = 10;
|
||||
iCode = argc;
|
||||
}
|
||||
|
||||
switch(i)
|
||||
{
|
||||
case 0:
|
||||
eOut = eInternal;
|
||||
break;
|
||||
case 1:
|
||||
eOut = eCommand;
|
||||
break;
|
||||
case 2:
|
||||
eOut = eHWError;
|
||||
break;
|
||||
case 3:
|
||||
eOut = eInError;
|
||||
break;
|
||||
case 4:
|
||||
eOut = eStatus;
|
||||
break;
|
||||
case 5:
|
||||
eOut = eValue;
|
||||
break;
|
||||
case 6:
|
||||
eOut = eWarning;
|
||||
break;
|
||||
case 7:
|
||||
eOut = eError;
|
||||
break;
|
||||
default:
|
||||
eOut = eStatus;
|
||||
iCode = argc;
|
||||
break;
|
||||
}
|
||||
|
||||
/* recombine the message */
|
||||
/* find length */
|
||||
iLen = 0;
|
||||
for(i = 1; i < iCode; i++)
|
||||
{
|
||||
iLen += strlen(argv[i]);
|
||||
}
|
||||
pMessage = (char *)malloc((iLen+100)*sizeof(char));
|
||||
if(!pMessage)
|
||||
{
|
||||
SCWrite(pCon,"ERROR: out of memory in clientput",eError);
|
||||
return 0;
|
||||
}
|
||||
memset(pMessage,0,(iLen+100)*sizeof(char));
|
||||
Arg2Text(iCode-1,&argv[1],pMessage,(iLen+100)*sizeof(char));
|
||||
|
||||
/* now write, thereby tunneling macro flag in order to get proper
|
||||
write to client and not into interpreter
|
||||
*/
|
||||
iMacro = SCinMacro(pCon);
|
||||
SCsetMacro(pCon,0);
|
||||
SCWrite(pCon,pMessage,eOut);
|
||||
SCsetMacro(pCon,iMacro);
|
||||
if(pMessage)
|
||||
{
|
||||
free(pMessage);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
/*---------------------------------------------------------------------------
|
||||
This implements a scheme to provide Tcl commands to Tcl. The Tcl commands
|
||||
(either procedures or objects) must be defined in a separate file. Than
|
||||
you call:
|
||||
Publish command UserRights
|
||||
This will make the command known to Sics, and user with user rights matching
|
||||
the rights initialized may use it.
|
||||
|
||||
Below the datastructure to hold for each command
|
||||
----------------------------------------------------------------------------*/
|
||||
typedef struct {
|
||||
pObjectDescriptor pDes;
|
||||
char *command;
|
||||
int iUser;
|
||||
} PubTcl, *pPubTcl;
|
||||
/*--------------------------------------------------------------------------*/
|
||||
static pPubTcl CreatePublish(char *name, int iUser)
|
||||
{
|
||||
pPubTcl pRes = NULL;
|
||||
|
||||
pRes = (pPubTcl)malloc(sizeof(PubTcl));
|
||||
if(!pRes)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pRes->pDes = CreateDescriptor("Macro");
|
||||
if(!pRes->pDes)
|
||||
{
|
||||
free(pRes);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pRes->command = strdup(name);
|
||||
pRes->iUser = iUser;
|
||||
return pRes;
|
||||
}
|
||||
/*-------------------------------------------------------------------------*/
|
||||
static void DeletePublish(void *pData)
|
||||
{
|
||||
pPubTcl self = NULL;
|
||||
|
||||
self = (pPubTcl)pData;
|
||||
assert(self);
|
||||
|
||||
if(self->pDes)
|
||||
{
|
||||
DeleteDescriptor(self->pDes);
|
||||
}
|
||||
if(self->command)
|
||||
{
|
||||
free(self->command);
|
||||
}
|
||||
free(self);
|
||||
}
|
||||
/*--------------------------------------------------------------------------
|
||||
TclAction checks the user rights and than invokes the arguments as a Tcl
|
||||
command
|
||||
*/
|
||||
|
||||
static int TclAction(SConnection *pCon,SicsInterp *pSics, void *pData,
|
||||
int argc, char *argv[])
|
||||
{
|
||||
char pBueffel[1024];
|
||||
pPubTcl self = NULL;
|
||||
int iRet;
|
||||
char *pPtr;
|
||||
Tcl_Interp *pTcl = NULL;
|
||||
|
||||
self = (pPubTcl)pData;
|
||||
assert(pCon);
|
||||
assert(pSics);
|
||||
assert(self);
|
||||
pTcl = InterpGetTcl(pSics);
|
||||
|
||||
if(!SCMatchRights(pCon,self->iUser))
|
||||
{
|
||||
sprintf(pBueffel,"ERROR: you are not authorised to invoke %s",
|
||||
argv[0]);
|
||||
SCWrite(pCon,pBueffel,eError);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* make a string */
|
||||
Arg2Text(argc,argv,pBueffel,1023);
|
||||
|
||||
|
||||
iRet = Tcl_Eval(pTcl,pBueffel);
|
||||
if(iRet == TCL_OK)
|
||||
{ /* possibly a bug here */
|
||||
SCWrite(pCon,pTcl->result,eStatus);
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(Tcl_GetVar(pTcl,SICSERROR,TCL_GLOBAL_ONLY) == NULL)
|
||||
{
|
||||
pPtr = strdup(pTcl->result);
|
||||
SCWrite(pCon,pPtr,eError);
|
||||
free(pPtr);
|
||||
}
|
||||
else
|
||||
{
|
||||
Tcl_UnsetVar(pTcl,SICSERROR,TCL_GLOBAL_ONLY);
|
||||
SCWrite(pCon,pTcl->result,eError);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return 1; /* not reached */
|
||||
}
|
||||
|
||||
#include "access.c"
|
||||
/*--------------------------------------------------------------------------*/
|
||||
int TclPublish(SConnection *pCon, SicsInterp *pSics, void *pData,
|
||||
int argc, char *argv[])
|
||||
{
|
||||
pPubTcl pNew = NULL;
|
||||
char pBueffel[132];
|
||||
int iUser, i, iRet;
|
||||
|
||||
/* check no of args */
|
||||
if(argc < 3)
|
||||
{
|
||||
sprintf(pBueffel,"ERROR: Insufficient no of arguments to %s",
|
||||
argv[0]);
|
||||
SCWrite(pCon,pBueffel,eError);
|
||||
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 = 0;
|
||||
strtolower(argv[2]);
|
||||
while(aCode[iUser] != NULL)
|
||||
{
|
||||
if(strcmp(aCode[iUser],argv[2]) == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
iUser++;
|
||||
}
|
||||
if(iUser > iCodes)
|
||||
{
|
||||
sprintf(pBueffel,"ERROR: cannot identify %s as a valid user code",
|
||||
argv[2]);
|
||||
SCWrite(pCon,pBueffel,eError);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* do a job !*/
|
||||
pNew = CreatePublish(argv[1],iUser);
|
||||
if(!pNew)
|
||||
{
|
||||
sprintf(pBueffel,"ERROR: memory error in %s",argv[0]);
|
||||
SCWrite(pCon,pBueffel,eError);
|
||||
return 0;
|
||||
}
|
||||
iRet = AddCommand(pSics,argv[1],TclAction,DeletePublish,(void *)pNew);
|
||||
if(!iRet)
|
||||
{
|
||||
sprintf(pBueffel,"ERROR: duplicate command %s not created",argv[1]);
|
||||
SCWrite(pCon,pBueffel,eError);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
|
||||
}
|
||||
/*-------------------------------------------------------------------------
|
||||
Transact executes a command and sends a TRANSACTIONFINISHED string
|
||||
at the end. This is to permit clients to search for this string in
|
||||
order to find out when a command has finished.
|
||||
*/
|
||||
int TransactAction(SConnection *pCon, SicsInterp *pSics, void *pData,
|
||||
int argc, char *argv[])
|
||||
{
|
||||
char pCommand[1024];
|
||||
int iRet;
|
||||
|
||||
Arg2Text(argc-1,&argv[1],pCommand,1023);
|
||||
iRet = InterpExecute(pSics,pCon,pCommand);
|
||||
SCWrite(pCon,"TRANSACTIONFINISHED",eError);
|
||||
return iRet;
|
||||
}
|
||||
Reference in New Issue
Block a user