- Added a means to overload or define drivable interfaces in tcl

This commit is contained in:
cvs
2003-09-03 14:01:02 +00:00
parent 790d5c217a
commit ee81bcc3b7
8 changed files with 846 additions and 10 deletions

View File

@ -26,13 +26,12 @@ SOBJ = network.o ifile.o conman.o SCinter.o splitter.o passwd.o \
simchop.o choco.o chadapter.o trim.o scaldate.o \
hklscan.o xytable.o \
circular.o maximize.o sicscron.o \
d_sign.o d_mod.o \
d_sign.o d_mod.o tcldrivable.o \
synchronize.o definealias.o \
hmcontrol.o userscan.o rs232controller.o lomax.o \
fourlib.o motreg.o motreglist.o anticollider.o \
s_rnge.o sig_die.o gpibcontroller.o $(NIOBJ) \
hmdata.o nxscript.o \
tclintimpl.o sicsdata.o
hmdata.o nxscript.o tclintimpl.o sicsdata.o
MOTOROBJ = motor.o simdriv.o
COUNTEROBJ = countdriv.o simcter.o counter.o

View File

@ -34,6 +34,7 @@
#include "ofac.h"
#include "telnet.h"
#include "site.h"
#include "tcldrivable.h"
#include "nserver.h"
int ServerSetupInterrupt(int iPort, pNetRead pNet, pTaskMan pTasker);
@ -360,9 +361,6 @@
/* Remove Status Callback */
KillStatus(NULL);
/* close the List system */
LLDsystemClose();
/*
kill the site data structure
*/
@ -372,6 +370,14 @@
site->KillSite(site);
}
/*
kill overloaded interfaces data
*/
killTclDrivable();
/* close the List system */
LLDsystemClose();
/* make fortify print his findings */
Fortify_DumpAllMemory(iFortifyScope);
Fortify_LeaveScope();

3
ofac.c
View File

@ -99,6 +99,7 @@
#include "gpibcontroller.h"
#include "nxscript.h"
#include "tclintimpl.h"
#include "tcldrivable.h"
#include "sicsdata.h"
#include "site.h"
/*----------------------- Server options creation -------------------------*/
@ -268,6 +269,8 @@
AddCommand(pInter,"MakeGPIB",MakeGPIB,NULL,NULL);
AddCommand(pInter,"MakeNXScript",MakeNXScript,NULL,NULL);
AddCommand(pInter,"MakeTclInt",MakeTclInt,NULL,NULL);
AddCommand(pInter,"TclReplaceDrivable",TclReplaceDrivable,NULL,NULL);
AddCommand(pInter,"DrivableInvoke", TclDrivableInvoke,NULL,NULL);
/*
install site specific commands

View File

@ -1,3 +0,0 @@
# Counter counter
counter SetPreset 100.000000
counter SetMode Monitor

638
tcldrivable.c Normal file
View File

@ -0,0 +1,638 @@
/*-----------------------------------------------------------------------
The code in this file allows to override or define Drivable
interfaces through tcl scripts. For more details, see
tcldrivable.tex
copyright: see file COPYRIGHT
Mark Koennecke, September 2003
----------------------------------------------------------------------*/
#include <stdio.h>
#include <assert.h>
#include "sics.h"
#include <tcl.h>
#include "fortify.h"
#include "lld.h"
#include "tcldrivable.h"
/*----------------------------------------------------------------------
The index of the list used for keeping the dictionary for mapping drivable
interface functions to scripts.
-------------------------------------------------------------------------*/
static int tclDrivableDictionary = -1;
/*=======================================================================
The structure used for keeping data associated with this scheme
--------------------------------------------------------------------------*/
typedef struct{
void *objectPointer;
char *tclName;
char *tclHalt;
char *tclCheckLimits;
char *tclSetValue;
char *tclCheckStatus;
char *tclGetValue;
}TclDrivable, *pTclDrivable;
/*=========================================================================
book keeping and search functions for the dictionary
-------------------------------------------------------------------------*/
static void clearTclDrivable(pTclDrivable pNew){
memset(pNew,0,sizeof(TclDrivable));
}
/*-----------------------------------------------------------------------*/
static void deleteTclDrivable(pTclDrivable target){
if(target->tclName != NULL){
free(target->tclName);
}
if(target->tclHalt != NULL){
free(target->tclHalt);
}
if(target->tclCheckLimits != NULL){
free(target->tclCheckLimits);
}
if(target->tclSetValue != NULL){
free(target->tclSetValue);
}
if(target->tclCheckStatus != NULL){
free(target->tclCheckStatus);
}
if(target->tclGetValue != NULL){
free(target->tclGetValue);
}
}
/*-------------- compare function for lld to find key in list
Function must return 0 if found --------*/
static int tclDrivableCompare(const void *p1, const void *p2){
pTclDrivable pt1, pt2;
pt1 = (pTclDrivable)p1;
pt2 = (pTclDrivable)p2;
if(pt1->objectPointer == pt2->objectPointer){
return 0;
}
return 1;
}
/*--------------- assignFunction --------------------------------------*/
static void assignFunction(pTclDrivable self, int functionIndex,
char *script){
switch(functionIndex){
case TCLHALT:
if(self->tclHalt != NULL){
free(self->tclHalt);
}
self->tclHalt = strdup(script);
break;
case TCLCHECK:
if(self->tclCheckLimits != NULL){
free(self->tclCheckLimits);
}
self->tclCheckLimits = strdup(script);
break;
case TCLSET:
if(self->tclSetValue != NULL){
free(self->tclSetValue);
}
self->tclSetValue = strdup(script);
break;
case TCLSTATUS:
if(self->tclCheckStatus != NULL){
free(self->tclCheckStatus);
}
self->tclCheckStatus = strdup(script);
break;
case TCLGET:
if(self->tclGetValue != NULL){
free(self->tclGetValue);
}
self->tclGetValue = strdup(script);
break;
default:
assert(0);
}
}
/*-----------------------------------------------------------------------*/
static int registerTclDrivableFunction(void *objectPointer,
int functionIndex,
char *script,
char *tclName){
TclDrivable entry;
/*
if no list: create it
*/
if(tclDrivableDictionary < 0){
tclDrivableDictionary = LLDcreate(sizeof(TclDrivable));
}
/*
find entry, or create a new one if it does not exist
*/
LLDnodePtr2First(tclDrivableDictionary);
entry.objectPointer = objectPointer;
if(LLDnodeFind(tclDrivableDictionary,tclDrivableCompare,
&entry) == 0){
LLDnodeDataTo(tclDrivableDictionary,&entry);
if(strcmp(tclName,entry.tclName) != 0){
return 0;
}
assignFunction(&entry,functionIndex,script);
LLDnodeDataFrom(tclDrivableDictionary,&entry);
} else {
clearTclDrivable(&entry);
entry.objectPointer = objectPointer;
entry.tclName = strdup(tclName);
assignFunction(&entry,functionIndex,script);
LLDnodeAppendFrom(tclDrivableDictionary,&entry);
}
return 1;
}
/*-----------------------------------------------------------------*/
static char *combine(char *t1, char *t2){
char *result = NULL;
int len;
len = strlen(t1) + strlen(t2) + 3;
result = (char *)malloc(len*sizeof(char));
if(!result){
return NULL;
}
memset(result,0,len);
strcpy(result,t1);
strcat(result," ");
strcat(result,t2);
return result;
}
/*------------------------------------------------------------------*/
static char *getTclDrivableCommand(void *objectPointer,
int functionIndex){
TclDrivable entry;
assert(tclDrivableDictionary > 0);
LLDnodePtr2First(tclDrivableDictionary);
entry.objectPointer = objectPointer;
if(LLDnodeFind(tclDrivableDictionary,tclDrivableCompare,&entry) == 0){
LLDnodeDataTo(tclDrivableDictionary,&entry);
switch(functionIndex){
case TCLHALT:
return combine(entry.tclHalt,entry.tclName);
break;
case TCLCHECK:
return combine(entry.tclCheckLimits,entry.tclName);
break;
case TCLSET:
return combine(entry.tclSetValue,entry.tclName);
break;
case TCLSTATUS:
return combine(entry.tclCheckStatus,entry.tclName);
break;
case TCLGET:
return combine(entry.tclGetValue,entry.tclName);
break;
default:
assert(0);
}
} else {
return NULL;
}
}
/*---------------------------------------------------------------------------*/
void killTclDrivable(){
TclDrivable entry;
int stat;
if(tclDrivableDictionary > 0){
stat = LLDnodePtr2First(tclDrivableDictionary);
while(stat != 0){
LLDnodeDataTo(tclDrivableDictionary,&entry);
deleteTclDrivable(&entry);
stat = LLDnodePtr2Next(tclDrivableDictionary);
}
LLDdelete(tclDrivableDictionary);
tclDrivableDictionary = -1;
}
}
/*--------------------------------------------------------------------------*/
int mapDrivableFunctionNames(char *name){
if(strcmp(name,"halt") == 0){
return TCLHALT;
}
if(strcmp(name,"checklimits") == 0){
return TCLCHECK;
}
if(strcmp(name,"setvalue") == 0){
return TCLSET;
}
if(strcmp(name,"checkstatus") == 0){
return TCLSTATUS;
}
if(strcmp(name,"getvalue") == 0){
return TCLGET;
}
return -1;
}
/*===========================================================================
The functions with which to overload the original functions
----------------------------------------------------------------------------*/
static int TclDrivableHalt(void *data){
char *command = NULL;
Tcl_Interp *pTcl;
int status;
pTcl = InterpGetTcl(pServ->pSics);
command = getTclDrivableCommand(data,TCLHALT);
if(command != NULL){
status = Tcl_Eval(pTcl,command);
if(status != TCL_OK){
fprintf(stderr,"Tcl ERROR: while invoking %s\n\tTcl reported %s\n",
command,pTcl->result);
status = 0 ;
} else {
status = 1;
}
free(command);
} else {
status = 0;
fprintf(stderr,"Tcl ERROR: trying to invoke non existent Tcl %s\n",
"drivable halt function");
}
return status;
}
/*--------------------------------------------------------------------*/
static int TclDrivableCheckLimits(void *data, float fVal,
char *error, int errlen){
char *commandPart1 = NULL;
char *command = NULL;
char pNum[30];
Tcl_Interp *pTcl;
int status;
pTcl = InterpGetTcl(pServ->pSics);
commandPart1 = getTclDrivableCommand(data,TCLCHECK);
if(commandPart1 != NULL){
sprintf(pNum,"%f",fVal);
command = combine(commandPart1,pNum);
if(command){
status = Tcl_Eval(pTcl,command);
if(status != TCL_OK){
strncpy(error,pTcl->result,errlen);
status = 0;
} else {
status = 1;
}
free(command);
} else {
fprintf(stderr,"Out of memory creating drivable command\n");
status = 0;
}
free(commandPart1);
} else {
status = 0;
fprintf(stderr,"Tcl ERROR: trying to invoke non existent Tcl %s\n",
"drivable CheckLimits function");
}
return status;
}
/*--------------------------------------------------------------------------*/
static long TclDrivableSetValue(void *data, SConnection *pCon, float fVal){
Tcl_Interp *pTcl;
int status;
char *commandHead = NULL, *command = NULL;
char pNum[30];
pTcl = InterpGetTcl(pServ->pSics);
/*
build and check command string
*/
sprintf(pNum,"%f", fVal);
commandHead = getTclDrivableCommand(data,TCLSET);
if(commandHead == NULL){
SCWrite(pCon,
"ERROR: trying to invoke non existent Tcl drivable function SetValue",
eError);
return HWFault;
}
command = combine(commandHead,pNum);
if(command == NULL){
SCWrite(pCon,"ERROR: out of memory creating tcl drivable SetValue command",
eError);
return HWFault;
}
/*
invoke
*/
status = Tcl_Eval(pTcl,command);
free(command);
free(commandHead);
if(status != TCL_OK){
SCWrite(pCon,"ERROR: Tcl drivable SetValue reported",eError);
SCWrite(pCon,pTcl->result,eError);
return HWFault;
}
status = atoi(pTcl->result);
return status;
}
/*--------------------------------------------------------------------------*/
static int TclDrivableCheckStatus(void *data, SConnection *pCon){
Tcl_Interp *pTcl;
int status;
char *command = NULL;
pTcl = InterpGetTcl(pServ->pSics);
/*
build and check command string
*/
command = getTclDrivableCommand(data,TCLSTATUS);
if(command == NULL){
SCWrite(pCon,
"ERROR: Tcl drivable CheckStatus not found!",
eError);
return HWFault;
}
/*
invoke
*/
status = Tcl_Eval(pTcl,command);
free(command);
if(status != TCL_OK){
SCWrite(pCon,"ERROR: Tcl drivable CheckStatus reported",eError);
SCWrite(pCon,pTcl->result,eError);
return HWFault;
}
status = atoi(pTcl->result);
return status;
}
/*--------------------------------------------------------------------------*/
static float TclDrivableGetValue(void *data, SConnection *pCon){
Tcl_Interp *pTcl;
int status;
char *command = NULL;
pTcl = InterpGetTcl(pServ->pSics);
/*
build and check command string
*/
command = getTclDrivableCommand(data,TCLGET);
if(command == NULL){
SCWrite(pCon,
"ERROR: Tcl drivable GetValue not found!",
eError);
return -999999.99;
}
/*
invoke
*/
status = Tcl_Eval(pTcl,command);
free(command);
if(status != TCL_OK){
SCWrite(pCon,"ERROR: Tcl drivable GetValue reported",eError);
SCWrite(pCon,pTcl->result,eError);
return -99999.99;
}
return atof(pTcl->result);
}
/*======================================================================
The function for doing it alltogether
------------------------------------------------------------------------*/
int replaceDrivableByTcl(void *commandData, int functionIndex,
char *script, char *tclName){
pIDrivable pDriv = NULL;
int status;
pDriv = GetDrivableInterface(commandData);
assert(pDriv != NULL);
/*
register the new script
*/
status = registerTclDrivableFunction(commandData,functionIndex,
script,tclName);
if(status <= 0){
return status;
}
/*
replace the appropriate Drivable function
*/
switch(functionIndex){
case TCLHALT:
pDriv->Halt = TclDrivableHalt;
break;
case TCLCHECK:
pDriv->CheckLimits = TclDrivableCheckLimits;
break;
case TCLSET:
pDriv->SetValue = TclDrivableSetValue;
break;
case TCLSTATUS:
pDriv->CheckStatus = TclDrivableCheckStatus;
break;
case TCLGET:
pDriv->GetValue = TclDrivableGetValue;
break;
default:
assert(0);
break;
}
return 1;
}
/*=========================================================================
Interpreter Interface
------------------------------------------------------------------------*/
int TclReplaceDrivable(SConnection *pCon, SicsInterp *pSics,
void *pData, int argc, char *argv[]){
pIDrivable pDriv = NULL;
void *commandData;
CommandList *pCom = NULL;
int functionIndex, status;
char pBueffel[256];
/*
only managers can do this!
*/
if(!SCMatchRights(pCon,usMugger)){
return 0;
}
/*
we need tons of arguments!
*/
if(argc < 5){
SCWrite(pCon,"ERROR: not enough arguments to TclReplaceDrivable",
eError);
return 0;
}
/*
get and check object
*/
strtolower(argv[1]);
pDriv = FindDrivable(pSics,argv[1]);
if(!pDriv){
snprintf(pBueffel,255,"ERROR: %s is not drivable!",argv[1]);
SCWrite(pCon,pBueffel,eError);
return 0;
}
/*
This must work as FindDrivable could not work else
*/
pCom = FindCommand(pSics,argv[1]);
commandData = pCom->pData;
/*
convert and check function name
*/
strtolower(argv[2]);
functionIndex = mapDrivableFunctionNames(argv[2]);
if(functionIndex <= 0){
snprintf(pBueffel,255,
"ERROR: %s is not a known function name for drivable",
argv[2]);
SCWrite(pCon,pBueffel,eError);
return 0;
}
status = replaceDrivableByTcl(commandData,functionIndex,argv[3],
argv[4]);
if(status <= 0){
SCWrite(pCon,"ERROR mismatch in parameter tclName",eError);
return 0;
}
SCSendOK(pCon);
return 1;
}
/*-----------------------------------------------------------------------*/
int TclDrivableInvoke(SConnection *pCon, SicsInterp *pSics,
void *pData, int argc, char *argv[]){
pIDrivable pDriv = NULL;
void *commandData;
CommandList *pCom = NULL;
int functionIndex, status;
char pBueffel[256], pError[132];
float fVal;
/*
we need tons of arguments!
*/
if(argc < 3){
SCWrite(pCon,"ERROR: not enough arguments to TclDrivableInvoke",
eError);
return 0;
}
/*
get and check object
*/
strtolower(argv[1]);
pDriv = FindDrivable(pSics,argv[1]);
if(!pDriv){
snprintf(pBueffel,255,"ERROR: %s is not drivable!",argv[1]);
SCWrite(pCon,pBueffel,eError);
return 0;
}
/*
This must work as FindDrivable could not work else
*/
pCom = FindCommand(pSics,argv[1]);
commandData = pCom->pData;
/*
convert and check function name
*/
strtolower(argv[2]);
functionIndex = mapDrivableFunctionNames(argv[2]);
if(functionIndex <= 0){
snprintf(pBueffel,255,
"ERROR: %s is not a known function name for drivable",
argv[2]);
SCWrite(pCon,pBueffel,eError);
return 0;
}
/*
invoke and report
*/
switch(functionIndex){
case TCLHALT:
if(!pDriv->Halt){
SCWrite(pCon,"ERROR: no drivable Halt function!",eError);
return 0;
}
status = pDriv->Halt(commandData);
snprintf(pBueffel,255,"Drivable Halt returned: %d",status);
SCWrite(pCon,pBueffel,eValue);
break;
case TCLCHECK:
if(!pDriv->CheckLimits){
SCWrite(pCon,"ERROR: no drivable CheckLimits function!",eError);
return 0;
}
if(argc < 4){
SCWrite(pCon,"ERROR: need drive target for CheckLimits",eError);
return 0;
}
status = pDriv->CheckLimits(commandData,atof(argv[3]),pError,131);
snprintf(pBueffel,255,"Drivable CheckLimits returned: %d, %s",
status,pError);
SCWrite(pCon,pBueffel,eValue);
break;
case TCLSET:
if(!pDriv->SetValue){
SCWrite(pCon,"ERROR: no drivable SetValue function!",eError);
return 0;
}
if(argc < 4){
SCWrite(pCon,"ERROR: need drive target for SetValue",eError);
return 0;
}
status = (int)pDriv->SetValue(commandData,pCon,atof(argv[3]));
snprintf(pBueffel,255,"Drivable SetValue returned %d", status);
SCWrite(pCon,pBueffel,eValue);
break;
case TCLSTATUS:
if(!pDriv->CheckStatus){
SCWrite(pCon,"ERROR: no drivable CheckStatus function!",eError);
return 0;
}
status = pDriv->CheckStatus(commandData,pCon);
snprintf(pBueffel,255,"Drivable CheckStatus returned %d", status);
SCWrite(pCon,pBueffel,eValue);
break;
case TCLGET:
if(!pDriv->GetValue){
SCWrite(pCon,"ERROR: no drivable GetValue function!",eError);
return 0;
}
fVal = pDriv->GetValue(commandData,pCon);
snprintf(pBueffel,255,"Drivable GetValue returned: %f", fVal);
SCWrite(pCon,pBueffel,eValue);
break;
default:
/*
do not know how I could get here
*/
assert(0);
}
return 1;
}

53
tcldrivable.h Normal file
View File

@ -0,0 +1,53 @@
/*-----------------------------------------------------------------------
The code in this file allows to override or define Drivable
interfaces through tcl scripts. More more details, see
tcldrivable.tex
copyright: see file COPYRIGHT
Mark Koennecke, September 2003
----------------------------------------------------------------------*/
#ifndef SICSTCLDRIVABLE
#define SICSTCLDRIVABLE
/*
Function codes for functionIndex
*/
#define TCLHALT 1
#define TCLCHECK 2
#define TCLSET 3
#define TCLSTATUS 4
#define TCLGET 5
/*
This installs a Tcl replacement for a drivable function
*/
int TclReplaceDrivable(SConnection *pCon, SicsInterp *pSics,
void *pData, int argc, char *argv[]);
/*
This allows to invoke a replaced function for debugging
purposes
*/
int TclDrivableInvoke(SConnection *pCon, SicsInterp *pSics,
void *pData, int argc, char *argv[]);
/*
This is for use from C
*/
int replaceDrivableByTcl(void *sicsObject, int functionIndex,
char *scriptName, char *tclName);
/*
map name to a functionIndex for use in replaceDrivableByTcl.
Returns 0 on failure, a usefule index > 0 in the case of success
*/
int mapDrivableFunctionNames(char *name);
/*
This is called from StopServer/nserver.c in order to remove
all memory related to this class
*/
void killTclDrivable(void);
#endif

119
tcldrivable.w Normal file
View File

@ -0,0 +1,119 @@
\subsection{Tcl Drivable Interface}
This is a module which allows to override or specify a drivable
interface through Tcl procedures. The corresponding member function
of the drivable interface will be replaced by a function which does
the following things:
\begin{itemize}
\item Given the object pointer as key, it will find a data structure
which holds the name of the Tcl procedure to invoke and a user
specified name (general to this interface) which the Tcl procedure can
use in order to locate instance specific data.
\item With this data, a Tcl command is constructed.
\item This Tcl command is then invoked.
\item Suitable Tcl commands return the numeric equivalents of the HW*
codes returned by the equivalent ANSII C functions.
\end{itemize}
Overrriding a drivable interface functions is done by a call like:
\begin{verbatim}
DrivableTclReplace objectName functionName tclReplaceProcedure tclName
\end{verbatim}
In order to implement a drivable completely in Tcl, create an empty
object with MakeTclInt and assign functions with
DrivableTclReplace. Please note that SICS will die if any of the
required functions is left out!
The first thing needed in order to implement this scheme is a data
structure holding the necessary information. This data structure also
doubles as an entry into the dictionary for mapping object pointers to
the corresponding data structure. This dictionary is implemented on
top of the general linked list package used within SICS. The index to
this linked list is kept as a module static within the implementation
file for this object. This is also where the original for this data
structure is placed.
\begin{verbatim}
struct{
void *objectPointer;
char *tclName;
char *tclHalt;
char *tclCheckLimits;
char *tclSetValue;
char *tclCheckStatus;
char *tclGetValue;
}TclDrivable, *pTclDrivable;
\end{verbatim}
The fields in this data structure:
\begin{description}
\item[objectPointer] A pointer to the SICS object this overloaded
interface belongs to. Also used as key in searches.
\item[tclName] The name passed over to the Tcl procedures in order to
allow them to find application specific data.
\item[tclHalt] A replacement Halt Tcl script.
\item[tclCheckLimits] A Tcl script for replacing the CheckLimits
function.
\item[tclSetvalue] A replacement for the Setvalue function.
\item[tclCheckStatus] a replacement for the CheckStatus function.
\item[tclGetValue] a replacement for the GetValue function.
\end{description}
The interface of this module to SICS is mainly its interpreter
functions. In order to allow for configuring Tcl functions from C a
function is provided.
@o tcldrivable.h @{
/*-----------------------------------------------------------------------
The code in this file allows to override or define Drivable
interfaces through tcl scripts. More more details, see
tcldrivable.tex
copyright: see file COPYRIGHT
Mark Koennecke, September 2003
----------------------------------------------------------------------*/
#ifndef SICSTCLDRIVABLE
#define SICSTCLDRIVABLE
/*
Function codes for functionIndex
*/
#define TCLHALT 1
#define TCLCHECK 2
#define TCLSET 3
#define TCLSTATUS 4
#define TCLGET 5
/*
This installs a Tcl replacement for a drivable function
*/
int TclReplaceDrivable(SConnection *pCon, SicsInterp *pSics,
void *pData, int argc, char *argv[]);
/*
This allows to invoke a replaced function for debugging
purposes
*/
int TclDrivableInvoke(SConnection *pCon, SicsInterp *pSics,
void *pData, int argc, char *argv[]);
/*
This is for use from C
*/
int replaceDrivableByTcl(void *sicsObject, int functionIndex,
char *scriptName, char *tclName);
/*
map name to a functionIndex for use in replaceDrivableByTcl.
Returns 0 on failure, a usefule index > 0 in the case of success
*/
int mapDrivableFunctionNames(char *name);
/*
This is called from StopServer/nserver.c in order to remove
all memory related to this class
*/
void killTclDrivable(void);
#endif
@}

View File

@ -19,6 +19,7 @@
/*================== our data structure ===================================*/
typedef struct {
pObjectDescriptor pDes;
pIDrivable pDriv;
char *saveScript;
FILE *fd;
} tclInt, *pTclInt;
@ -48,6 +49,20 @@ static int TclSaveStatus(void *pData, char *name, FILE *fd){
return 1;
}
/*-----------------------------------------------------------------------*/
static void *TclGetInterface(void *pData, int id){
pTclInt self = NULL;
self = (pTclInt)pData;
if(self == NULL){
return NULL;
}
if(id == DRIVEID){
return self->pDriv;
} else {
return NULL;
}
}
/*======================== data structure creation and deletion ==========*/
static pTclInt MakeTclIntData(void){
pTclInt pNew = NULL;
@ -59,7 +74,9 @@ static pTclInt MakeTclIntData(void){
memset(pNew,0,sizeof(tclInt));
pNew->pDes = CreateDescriptor("SICS Interfaces in Tcl");
pNew->pDes->SaveStatus = TclSaveStatus;
if(!pNew->pDes){
pNew->pDes->GetInterface = TclGetInterface;
pNew->pDriv = CreateDrivableInterface();
if(!pNew->pDes || !pNew->pDriv){
free(pNew);
return NULL;
}
@ -80,6 +97,9 @@ static void KillTclInt(void *pData){
if(self->saveScript != NULL){
free(self->saveScript);
}
if(self->pDriv){
free(self->pDriv);
}
free(self);
}
/*=============== interpreter interface + helper functions =============*/
@ -154,3 +174,4 @@ int TclIntAction(SConnection *pCon, SicsInterp *pSics, void *pData,
return 1;
}