Files
cdev-1.7.2n/extensions/tclnew/tcl_cdev.cc
2022-12-13 12:44:04 +01:00

1335 lines
35 KiB
C++

// a CDEV access interface for tcl
// Johannes van Zeijts, March 95, first version
// May 95, second version, using Walt Akers callback example
// Dec 95, added arbitrary dimensional array output and context
// Jan 96, added handling of strings with spaces
// Aug 96, deleted callbackinfo when we are not monitoring
// Aug 96, converted to tcl7.5
// Nov 1, 96, moved to cdev 1.4
// March, 97, overhaul, allowed multiple devices
// Feb, 98 Make it work with select event handling
// For generic services this works only in cdev/1.6.2
// $id$
/* Output formatting
Attention given to 'Strings with spaces' which have special meaning in tcl
#devices = 1
#tags = 0 (only value tag)
dim = 0 1
String
String with spaces
dim = 1 1 1 1
St1 St2 St3
{St w sp1} {St w sp2} {St w sp3}
dim = 2 {11 12 13} {21 22 23}
{st1 st2 st3} {...}
{{st w sp1} {st w sp2} {st w sp3}} { ...}
#tags > 0 (value tag + other tags)
Each tag in its own list index
Result is always list of length (#tags + 1)
dim = 0
1
St1
{St w sp1}
dim = 1
{1 1 1}
{St1 St2 St3}
{{St w sp1} {St w sp2} {St w sp3}}
dim = 2
{{1 1 1} {1 1 1}}
{{{st w sp1} {st w sp2} {st w sp3}} {{st w sp1} {st w sp2} {st w sp3}}}
---------------------------------------------------------------------------------------
#devices > 1 ,
#tags = 0
dim = 0 1 1 1
{str w sp} {str w sp}
dim = 1 {1 1 1} {1 1 1}
{{str w sp} ..} { }
#tags > 0
dim = 0 {0 1 2} {0 1 2}
dim = 1 {{1 1 1} {1 1 1}}
*/
#include <stream.h>
#include <tcl.h>
#include <ctype.h>
#include <string.h>
#include <iostream.h>
#include <math.h>
//#include <dl.h>
// cdev includes
#include <cdevSystem.h>
#include <cdevRequestObject.h>
#include <cdevDevice.h>
#include <cdevGroup.h>
#include <cdevData.h>
static int VALUE_TAG_ID =- 1;
#define VALUE_TAG ((VALUE_TAG_ID<0 && cdevData::tagC2I("value", &VALUE_TAG_ID)!= CDEV_SUCCESS)?-1:VALUE_TAG_ID)
static int STATUS_TAG_ID =- 1;
#define STATUS_TAG ((STATUS_TAG_ID<0 && cdevData::tagC2I("status", &STATUS_TAG_ID)!= CDEV_SUCCESS)?-1:STATUS_TAG_ID)
static int SEVERITY_TAG_ID =- 1;
#define SEVERITY_TAG ((SEVERITY_TAG_ID<0 && cdevData::tagC2I("severity", &SEVERITY_TAG_ID)!= CDEV_SUCCESS)?-1:SEVERITY_TAG_ID)
static int cdevdebug = 0;
static char* cdevFormat;
static char* defaultFormat = "%.4g";
class tclCdevData {
public:
tclCdevData();
void parse(Tcl_Interp*, char* *, int);
~tclCdevData();
cdevData out, context;
int hascontext;
int tagn, *taglist;
char *callbacktag;
int filtersame;
int state, async;
int unroll;
private:
int getTag(char*);
};
tclCdevData::~tclCdevData() {
delete taglist;
}
tclCdevData::tclCdevData():hascontext(0), tagn(0), taglist(NULL), async(0), state(TCL_ERROR) {
filtersame = 1;
unroll = 0;
};
int tclCdevData::getTag(char * s) {
int TT=0;
if (cdevData::tagC2I(s, &TT) == CDEV_SUCCESS) {
return TT;
}
for (int i = 30; TT==0 && i<65534; i++) {
cdevData::insertTag(i,s); /// bug in cdev: this does not return status
if (cdevData::tagC2I(s, &TT) == CDEV_SUCCESS) break;
}
return TT;
}
// Parses command line, fills up the outgoing cdevData and the context (if any)
void tclCdevData::parse(Tcl_Interp *interp, char **argv, int argc) {
int i, c1, c2, tag;
cdevData *ptr;
char **s1 = NULL;
char **s2 = NULL;
// Point to 'out' cdevData until we hit the context (if any)
ptr = &out;
for(i = 3; i < argc; i++) {
// skip 'cdev' '$device' and '$message'
if(Tcl_SplitList(interp, argv[i], &c1, &s1) != TCL_OK) {
return;
}
if(c1 == 2) {
// {tag value} pair, check if the value is a scalar
if(Tcl_SplitList(interp, s1[1], &c2, &s2) != TCL_OK) {
free((char *) s1);
return;
}
tag = getTag(s1[0]);
if(c2 <= 1) {
// we have a scalar
if (c2 == 0) { // handle empty string
ptr->insert(tag,"");
} else {
ptr->insert(tag, s1[1]);
// insert scalar
}
}
else {
ptr->insert(tag, s2, c2);
// insert vector of scalars, does not handle matrices
}
free((char *) s2);
}
else if (c1 == 1) {
// can be one of "-context" , "-tags", "-filtersame" or a callbacktag
if(strcmp(argv[i], "-context") == 0) {
// all remaining 'tag value' pairs go in the context
ptr = &context;
hascontext = 1;
}
else if(strcmp(argv[i], "-tags") == 0) {
// get the list of tags to print out from the result data
i++;
// points to next entry in argv
if(i == argc) {
interp->result = "expected tag names";
free((char *) s1);
return;
}
if(Tcl_SplitList(interp, argv[i], &tagn, &s2) != TCL_OK) {
interp->result = "tag problem";
free((char *) s1);
return;
}
else {
taglist = new int[tagn];
for(int j = 0; j < tagn; j++) {
taglist[j] = getTag(s2[j]);
}
}
free((char *) s2);
} else if (strcmp(argv[i], "-filtersame") == 0) {
i++;
if (i == argc) {
interp->result = "expected boolean";
free((char*) s1);
return;
}
if (Tcl_GetBoolean(interp, argv[i], &filtersame) != TCL_OK) {
free((char*) s1);
return;
}
} else if (strcmp(argv[i], "-unroll") == 0) {
i++;
if (i == argc) {
interp->result = "expected number";
free((char*) s1);
return;
}
if (Tcl_GetInt(interp, argv[i], &unroll) != TCL_OK) {
free((char*) s1);
return;
}
} else {
// single entry, a callbacktag, better be at end of input
if(i != argc-1) {
interp->result = "expecting callbacktag at end";
free((char *) s1);
return;
}
// Here we have a callback tag, hence we want to send asynchronously
callbacktag = argv[i];
async = 1;
}
}
else {
// c1 > 2
// tag / string pair (i.e. "value this is a string with spaces embedded"
char **av = s1;
av++;
char *concat = Tcl_Concat(c1-1, av);
tag = getTag(s1[0]);
ptr->insert(tag, concat);
if(cdevdebug == 1) {
fprintf(stderr, "inserted: %s, with value: %s\n", s1[0], concat);
}
free(concat);
}
free((char *) s1);
}
state = TCL_OK;
}
class callbackInfo {
public:
callbackInfo(Tcl_Interp*, char *);
callbackInfo(Tcl_Interp*, char*, char *);
~callbackInfo();
Tcl_Interp *interp;
char *s;
char *value; // keep pointer to previous string to compare new result too.
int status, filtersame;
void addtags(int, int *);
int *tags, ntags;
char **devicetags;
int unroll, unrolllength;
char **unrolldata;
};
callbackInfo::callbackInfo(Tcl_Interp *e, char *arg) {
interp = e;
s = new char[strlen(arg)+1];
strcpy(s, arg);
ntags = 0;
tags = NULL;
value = NULL;
devicetags = NULL;
status = -999;
filtersame = 1;
unroll = 0;
unrolllength = 0;
unrolldata = NULL;
}
callbackInfo::callbackInfo(Tcl_Interp *e, char *arg1, char *arg2) {
interp = e;
s = new char[strlen(arg1)+strlen(arg2)+1];
strcpy(s, arg1);
strcat(s, arg2);
ntags = 0;
tags = NULL;
value = NULL;
status = -999;
devicetags = NULL;
filtersame = 1;
unroll = 0;
unrolllength = 0;
unrolldata = NULL;
}
callbackInfo::~callbackInfo() {
delete tags;
for (int i = 0; i < ntags; i++) {
delete devicetags[i];
}
delete unrolldata;
delete devicetags;
delete s;
}
void callbackInfo::addtags(int n, int *v) {
char *tagstring;
ntags = n;
tags = new int[n];
devicetags = new char*[ntags];
for(int i = 0; i < ntags; i++) {
tags[i] = v[i];
cdevData::tagI2C(tags[i],tagstring);
devicetags[i] = new char[strlen(s) + 2 + strlen(tagstring)];
strcpy(devicetags[i], s);
strcat(devicetags[i], ".");
strcat(devicetags[i], tagstring);
}
}
static char cs[512];
cdevBounds *Bounds;
int Dim;
static int K = 0;
void HandleLevel(char **in, int level, Tcl_DString &ds) {
int i;
for(i = 0; i < Bounds[level].length; i++) {
if(level >= Dim-1) {
Tcl_DStringAppendElement(&ds, in[K]);
K++;
}
else {
Tcl_DStringStartSublist(&ds);
HandleLevel(in, level+1, ds);
Tcl_DStringEndSublist(&ds);
}
}
}
// Format a cdevData tag result into a tcl result
// mode == #ntags
void HandleTag(int tag, cdevData &result, Tcl_DString &ds, int mode, int ndevices) {
int i, len;
size_t dim;
char **sp;
char *tagname = NULL;
if(cdevdebug == 1) {
if (cdevData::tagI2C(tag, tagname) != CDEV_SUCCESS) {
// cout << "HandleTag " << tag << " Could not convert" << endl;
printf("HandleTag: %d counld not convert\n",tag);
} else {
// cout << "HandleTag " << tag << " " << tagname << endl;
printf("HandleTag: %d %s\n",tag,tagname);
}
tagname = NULL;
}
if(result.getDim(tag, &dim) != CDEV_SUCCESS) {
if(cdevdebug == 1) {
printf("HandleTag: result.getDim failed\n");
}
cs[0] = (char)NULL;
if (ndevices == 1 && mode == 0) {
Tcl_DStringAppend(&ds, cs, -1); // append an empty string
} else {
Tcl_DStringAppendElement(&ds, cs); // append an empty list
}
return;
}
// Always retrieve the result as a char*, cdevData does the conversion for me!
// do special conversion for: DOUBLE and TIMESTAMP
if(cdevdebug == 1) {
printf("HandleTag: result.getDim ok : dim=%d\n",dim);
}
if(dim == 0) {
// put this in if we want format conversions.
int i = result.getType(tag);
if(cdevdebug == 1) {
printf("Type is %d \n",i);
}
if ((i == CDEV_FLOAT) || (i == CDEV_DOUBLE)) {
if(cdevdebug == 1) {
printf("HandleTag: is CDEV_DOUB\n");
}
double dres;
result.get(tag, &dres);
sprintf(cs, cdevFormat, dres);
} else if (i == CDEV_TIMESTAMP) {
unsigned long timeres;
result.get(tag, &timeres);
sprintf(cs, "%lu", timeres);
} else if(i== CDEV_BYTE) {
printf("CAN'T HANDLE CDEV_BYTE/n");
cs[0] = (char)NULL;
result.get(tag, cs, 255);
} else {
cs[0] = (char)NULL;
result.get(tag, cs, 255);
}
if (mode == 0 && ndevices == 1) {
Tcl_DStringAppend(&ds,cs,-1);
} else {
Tcl_DStringAppendElement(&ds,cs);
}
return;
} else if (dim==1) {
size_t elems;
if( (result.getElems(tag,&elems)) != 0){
printf("error geting number of elements in value\n");
exit(0);
}
int i = result.getType(tag);
if(cdevdebug == 1) {
printf("Type is %d \n",i);
}
if (i == CDEV_INT32) {
int *ival;
if(cdevdebug == 1) {
printf("HandleTag: is CDEV_INT32\n");
}
ival = (int *)malloc(elems*(size_t)sizeof(int));
result.get(tag,ival);
if(cdevdebug == 1) {
printf("cdev format = %s\n",cdevFormat);
}
for(i=0;i<elems;i++){
if(cdevdebug == 1) {
printf("value of element %d is %d\n",i,ival[i]);
}
/* sprintf(cs, cdevFormat, ival[i]);*/
sprintf(cs, "%d ", ival[i]);
Tcl_DStringAppendElement(&ds,cs);
}
free(ival);
} //end of if CDEV_INT32
if (i == CDEV_DOUBLE) {
double *dval;
if(cdevdebug == 1) {
printf("HandleTag: is CDEV_DOUB\n");
}
dval = (double *)malloc(elems*(size_t)sizeof(double));
result.get(tag,dval);
for(i=0;i<elems;i++){
if(cdevdebug == 1) {
printf("value of element %d is %f\n",i,dval[i]);
}
sprintf(cs, cdevFormat, dval[i]);
Tcl_DStringAppendElement(&ds,cs);
}
free(dval);
} //end of if CDEV_DOUBLE
else if (i == CDEV_FLOAT) {
float *fval;
if(cdevdebug == 1) {
printf("HandleTag: is CDEV_FLOAT\n");
}
fval = (float *)malloc(elems*(size_t)sizeof(float));
result.get(tag,fval);
for(i=0;i<elems;i++){
if(cdevdebug == 1) {
printf("value of element %d is %f\n",i,fval[i]);
}
sprintf(cs, cdevFormat, fval[i]);
Tcl_DStringAppendElement(&ds,cs);
}
free(fval);
} //end of if CDEV_FLOAT
else if(i== CDEV_BYTE) {
printf("CAN'T HANDLE CDEV_BYTE/n");
}
return;
} else {
// dim > 1
Dim = (int) dim;
K = 0;
Bounds = new cdevBounds[Dim];
result.getBounds(tag, Bounds, Dim);
len = 1;
for(i = 0; i < Dim; i++) {
if(cdevdebug == 1) {
printf("HandleT:Bounds[%d].offset = %d\n",i,Bounds[i].offset);
printf("HandleT:Bounds[%d].length = %d\n",i,Bounds[i].length);
}
len *= Bounds[i].length;
}
if(cdevdebug == 1) {
printf("HandleTag: len = %d\n",len);
int i = result.getType(tag);
if ((i == CDEV_FLOAT) || (i == CDEV_DOUBLE)) {
printf("HandleTag: is CDEV_DOUB\n");
}
}
sp = new char*[len];
result.get(tag, sp);
if (mode>0 || (mode==0&&ndevices>1)) {
if(cdevdebug == 1) {
printf("HandleTag: will Tcl_DStringStart..\n");
}
Tcl_DStringStartSublist(&ds);
}
if(cdevdebug == 1) {
printf("HandleTag: will call HandleLevel\n");
}
HandleLevel(sp, 0, ds);
if (mode>0 || (mode==0&&ndevices>1)) {
if(cdevdebug == 1) {
printf("HandleTag: will Tcl_DStringEnd...\n");
}
Tcl_DStringEndSublist(&ds);
}
// append the result to a Tcl_DString
}
if(cdevdebug == 1) {
printf("HandleTag: will delete bounds \n");
}
delete Bounds;
while(len > 0) {
len--;
delete sp[len];
}
if(cdevdebug == 1) {
printf("HandleTag: will delete sp \n");
}
delete [] sp;
if(cdevdebug == 1) {
printf("HandleTag: finished\n");
}
}
int Cdev_Handleresult(int *tags, int ntags, cdevData &result, Tcl_DString &ds, int ndevices) {
if(cdevdebug == 1) {
// cout << "Cdev_Handleresult" << endl;
printf("Cdev_Handleresult\n");
}
// assume we always return the "value" tag
if (ndevices>1 && ntags>0) Tcl_DStringStartSublist(&ds);
HandleTag(VALUE_TAG, result, ds, ntags, ndevices);
if(cdevdebug == 1) {
printf("CdevHandleresult: ntags = %d ndevices = %d\n",ntags,ndevices);
}
if(ntags > 0) {
for(int i = 0; i < ntags; i++) {
HandleTag(tags[i], result, ds, ntags, ndevices);
}
}
if (ndevices>1 && ntags>0) Tcl_DStringEndSublist(&ds);
return TCL_OK;
}
char* getCdevErrorCode(int);
//int cbcount = 0;
// executes inside poll() or pend(file) whenever 'file' is readable
void Cdev_CallbackFunction(int status, void *userarg, cdevRequestObject&, cdevData &result) {
Tcl_DString ds;
int i, j, t;
if(cdevdebug == 1) {
// cout << "Cdev_CallbackFunction" << endl;
}
callbackInfo *info = (callbackInfo *) userarg;
if(cdevdebug == 1) {
printf("callback: status = %d, done = %d\n", status, cdevCallback::isTransactionDone());
result.asciiDump();
// cout << "dumped cdevData" << endl;
}
if (info->status != status) {
info->status = status;
Tcl_SetVar2(info->interp, "CdevStatus", info->s, getCdevErrorCode(status), TCL_GLOBAL_ONLY);
}
if (cdevCallback::isTransactionDone() == 1) {
// Tcl_SetVar2(info->interp, "CdevDone", info->s, getCdevErrorCode(status), TCL_GLOBAL_ONLY);
delete info;
return;
}
// if ((status == CDEV_SUCCESS || status == CDEV_WARNING) && (result.getType(VALUE_TAG) != CDEV_INVALID))
if ((status == CDEV_SUCCESS || status == CDEV_WARNING)) {
if (info->unroll == 0) { // Do the old stuff
Tcl_DStringInit(&ds);
i = Cdev_Handleresult(info->tags, info->ntags, result, ds, 1);
if (info->filtersame) {
if (info->value != NULL) {
if (strcmp(info->value, Tcl_DStringValue(&ds)) != 0) { // only set if value is changed
info->value = Tcl_SetVar2(info->interp, "Control", info->s, Tcl_DStringValue(&ds), TCL_GLOBAL_ONLY);
}
} else {
info->value = Tcl_SetVar2(info->interp, "Control", info->s, Tcl_DStringValue(&ds), TCL_GLOBAL_ONLY);
}
} else {
info->value = Tcl_SetVar2(info->interp, "Control", info->s, Tcl_DStringValue(&ds), TCL_GLOBAL_ONLY);
}
Tcl_DStringFree(&ds);
} else if (info->unroll == 1) {
// First to the "value" tag, next loop through all the requested tags
Tcl_DStringInit(&ds);
HandleTag(VALUE_TAG, result, ds, 0, 1);
info->value = Tcl_SetVar2(info->interp, "Control", info->s, Tcl_DStringValue(&ds), TCL_GLOBAL_ONLY);
Tcl_DStringFree(&ds);
for (i = 0; i < info->ntags; i++) {
HandleTag(info->tags[i], result, ds, 0, 1);
info->value = Tcl_SetVar2(info->interp, "Control", info->devicetags[i], Tcl_DStringValue(&ds), TCL_GLOBAL_ONLY);
Tcl_DStringFree(&ds);
}
} else { // unroll > 1
// Loop through the cdevData since it is supposed to be vector valued.
Tcl_DStringInit(&ds);
// HandleTag(VALUE_TAG, result, ds, 0, 1);
// info->value = Tcl_SetVar2(info->interp, "Control", info->s, Tcl_DStringValue(&ds), TCL_GLOBAL_ONLY);
// Tcl_DStringFree(&ds);
size_t nElems;
result.getElems(VALUE_TAG, &nElems);
char** outString;
if (result.find(VALUE_TAG, (void*&) outString) != CDEV_SUCCESS) {
if (cdevdebug) {
// cout << "Could not find value tag" << endl;
}
return;
}
char *namePtr, name[512];
if ((info->unrolldata == NULL) || (nElems > info->unrolllength)) {
delete info->unrolldata;
info->unrolldata = new char*[nElems];
info->unrolllength = nElems;
}
double *dp;
unsigned long *lp;
for (j = 0; j < info->ntags; j++) {
t = result.getType(info->tags[i]);
if ((t == CDEV_FLOAT) || (t == CDEV_DOUBLE)) {
result.find(info->tags[i], (void* &) dp);
for (i = 0; i < nElems; i++) {
sprintf(cs, cdevFormat, dp[i]);
info->unrolldata[i] = new char[strlen(cs)+1];
strcpy(info->unrolldata[i],cs);
}
} else if (t == CDEV_TIMESTAMP) {
result.find(info->tags[i], (void* &)lp);
for (i = 0; i < nElems; i++) {
sprintf(cs, "%lu", lp[i]);
info->unrolldata[i] = new char[strlen(cs)+1];
strcpy(info->unrolldata[i],cs);
}
} else {
result.get(info->tags[i], info->unrolldata);
}
for (i = 0; i < nElems; i++) {
namePtr = name;
strcpy(namePtr, outString[i]);
strcat(namePtr, info->devicetags[i]);
Tcl_SetVar2(info->interp, "Control", name, info->unrolldata[i], TCL_GLOBAL_ONLY);
delete info->unrolldata[i];
}
}
}
}
}
// Old way of polling, superseded by FileHandler calls, but since FD's are not working yet, still in use
void Cdev_UpdateProc(ClientData dummy) {
if(cdevdebug == 1) {
// cout << "Cdev_UpdateProc" << endl;
}
cdevSystem::defaultSystem().poll();
Tcl_CreateTimerHandler(200, Cdev_UpdateProc, dummy);
}
void Cdev_FileProc(ClientData clientData, int mask) {
int fd = (int) clientData;
if (cdevdebug) {
// cout << "Cdev_FileProc: polling: " << fd << " mask = " << mask << endl;
}
if (mask == TCL_EXCEPTION) {
if (cdevdebug) {
// cout << "Cdev_FileProc: TCL_EXCEPTION" << endl;
}
// SMH Tcl_File f = Tcl_GetFile(clientData, TCL_UNIX_FD);
int f = (int) clientData;
Tcl_DeleteFileHandler(f);
return;
}
cdevSystem::defaultSystem().pend(0.0001, fd);
if (cdevdebug) {
// cout << "Cdev_FileProc: did pend " << endl;
}
// cdevSystem::defaultSystem().poll();
}
int CdevDebugCmd(ClientData, Tcl_Interp*, int, char* *) {
if(cdevdebug == 0) {
cdevdebug = 1;
}
else {
cdevdebug = 0;
}
return TCL_OK;
}
int CdevFormatCmd(ClientData, Tcl_Interp* interp, int argc, char** argv) {
if (argc == 1) {
sprintf(interp->result, "%s", cdevFormat);
return TCL_OK;
}
delete cdevFormat;
cdevFormat = new char[strlen(argv[1])+1];
strcpy(cdevFormat, argv[1]);
return TCL_OK;
}
int PutEnvCmd(ClientData, Tcl_Interp*, int argc, char** argv) {
if (argc == 1) {
return TCL_OK;
}
putenv(argv[1]);
return TCL_OK;
}
static int Finished = 0;
void Cdev_RegisterFD(int fd, int condition, void *) {
if (cdevdebug) {
// cout << "Register FD " << fd << " " << condition << " Finished = " << Finished << endl;
}
if (Finished == 1) {
return;
}
// SMH Tcl_File f = Tcl_GetFile((ClientData) fd, TCL_UNIX_FD);
int f = fd;
if (condition == 1) {
Tcl_CreateFileHandler(f, TCL_READABLE|TCL_EXCEPTION, Cdev_FileProc, (ClientData) fd);
} else {
Tcl_DeleteFileHandler(f);
}
}
void Cdev_ExitProc(ClientData) {
Finished = 1;
}
typedef cdevRequestObject *cdevRequestObjectPtr;
int CdevCmd(ClientData, Tcl_Interp *interp, int argc, char **argv) {
// cdev device message {tag value} {..} cb
// cdev device message {tag value} {..} -context (tag value} {..} cb
char **devices = NULL;
int i, n, ndevices;
Tcl_DString ds;
cdevData result;
cdevCallback *cb = NULL;
callbackInfo *info;
cdevRequestObjectPtr request, *requests;
tclCdevData data;
int delinfo = 0;
// printf("CdevCmd: \n");
if(argc < 3) {
Tcl_AppendResult(interp, "cdev: wrong # args", (char *) NULL);
return TCL_ERROR;
}
ndevices = 0;
if(Tcl_SplitList(interp, argv[1], &ndevices, &devices) != TCL_OK) {
return TCL_ERROR;
}
if(ndevices == 1) {
// printf("CdevCmd: ndevices=1 argv[1]= %s argv[2]=%s\n",argv[1],argv[2]);
if((request=cdevRequestObject::attachPtr(argv[1],argv[2]))==NULL){
if(cdevdebug == 1) {
printf("::attachPtr returned NULL\n");
}
return TCL_ERROR;
}
free((char*)devices);
}
else {
requests = new cdevRequestObjectPtr[ndevices];
for(n = 0; n < ndevices; n++) {
requests[n] = cdevRequestObject::attachPtr(devices[n], argv[2]);
}
}
// printf("have got request object\n");
data.parse(interp, argv, argc);
if(data.state != TCL_OK) {
return TCL_ERROR;
}
if(data.async) {
// we want to sent it async
// printf("data.async is true\n");
if(cdevdebug == 1) {
printf("data.async is true\n");
// cout << "data.async is true" << endl;
}
if(ndevices == 1) {
info = new callbackInfo(interp, data.callbacktag);
info->filtersame = data.filtersame;
info->unroll = data.unroll;
if(data.tagn != 0) {
info->addtags(data.tagn, data.taglist);
}
if(strncmp(argv[2], "monitorOff", 10) == 0) {
delinfo = 1;
cb = new cdevCallback(Cdev_CallbackFunction, NULL);
}
else {
cb = new cdevCallback(Cdev_CallbackFunction, (void *) info);
}
if(data.hascontext) {
if(cdevdebug == 1) {
// cout << "Context data: " << endl;
printf("Context data: \n");
data.context.asciiDump(stdout);
}
if(request->setContext(data.context) != CDEV_SUCCESS) {
interp->result = "setContext error";
delete info;
return TCL_ERROR;
}
}
if(cdevdebug == 1) {
// cout << argv[1] << " " << argv[2] << " OutBound data: " << endl;
data.out.asciiDump(stdout);
}
if(request->sendCallback(data.out, *cb) != 0) {
delete info;
delete cb;
return TCL_ERROR;
}
else {
if(delinfo) delete info;
delete cb;
cdevSystem::defaultSystem().flush();
return TCL_OK;
}
}
else {
// ndevices > 1, send each one separately
int j = 0;
if(strncmp(argv[2], "monitorOn", 9) == 0) {
j = 1;
}
else if(strncmp(argv[2], "monitorOff", 10) == 0) {
j = 2;
}
for(n = 0; n < ndevices; n++) {
info = new callbackInfo(interp, devices[n], data.callbacktag);
if(data.tagn != 0) {
info->addtags(data.tagn, data.taglist);
}
info->filtersame = data.filtersame;
info->unroll = data.unroll;
if(j == 1) {
cb = new cdevCallback(Cdev_CallbackFunction, (void *) info);
}
else if(j == 2) {
delinfo = 1;
cb = new cdevCallback(Cdev_CallbackFunction, NULL);
}
else {
cb = new cdevCallback(Cdev_CallbackFunction, (void *) info);
}
if(data.hascontext) {
if(requests[n]->setContext(data.context) != 0) {
interp->result = "setContext error";
delete requests;
free((char *) devices);
delete info;
return TCL_ERROR;
}
}
if(requests[n]->sendCallback(data.out, *cb) != CDEV_SUCCESS) {
delete requests;
delete info;
free((char *) devices);
delete cb;
return TCL_ERROR;
}
else {
if(delinfo) delete info;
delete cb;
}
}
delete requests;
free((char *) devices);
cdevSystem::defaultSystem().flush();
return TCL_OK;
}
}
// send it sync
if(cdevdebug == 1) {
// cout << "will send it sync " << endl;
printf("will send it sync\n ");
}
Tcl_DStringInit(&ds);
if(ndevices == 1) {
if(data.hascontext) {
if(cdevdebug == 1) {
// cout << "Context data: " << endl;
printf("ndevices=1, Context data:\n ");
data.context.asciiDump(stdout);
}
if(request->setContext(data.context) != CDEV_SUCCESS) {
interp->result = "setContext error";
return TCL_ERROR;
}
}
if(cdevdebug == 1) {
// cout << argv[1] << " " << argv[2] << " OutBound data: " << endl;
printf(" CdevCmd: sync: ndevices=1, OutBound data:\n ");
data.out.asciiDump(stdout);
}
if(request->send(data.out, result) != CDEV_SUCCESS) {
sprintf(interp->result, "Is an error in send: %s %s", argv[1], argv[2]);
return TCL_ERROR;
}
if(cdevdebug == 1) {
// cout << "Result data: " << endl;
printf("ndevices=1, send ok \n");
result.asciiDump(stdout);
printf("finished ascii-dump \n");
}
// if(STATUS_TAG !=- 1) {
// if(result.get(STATUS_TAG, &i) == CDEV_SUCCESS) {
// if(i != CDEV_SUCCESS) {
// if(SEVERITY_TAG !=- 1) {
// Tcl_DStringFree(&ds);
// result.get(SEVERITY_TAG, cs, 255);
// Tcl_DStringAppend(&ds, cs, -1);
// Tcl_DStringResult(interp, &ds);
// }
// else {
// interp->result = "cdev status != 0";
// }
// return TCL_ERROR;
// }
// }
// }
if(Cdev_Handleresult(data.taglist, data.tagn, result, ds, 1) != TCL_OK) {
interp->result = "cannot handle cdev result";
Tcl_DStringFree(&ds);
return TCL_ERROR;
}
if(cdevdebug == 1) {
// cout << "Cdev_Handleresult Done " << endl;
printf("Cdev_Handleresult Done \n");
}
Tcl_DStringResult(interp, &ds);
if(cdevdebug == 1) {
// cout << "will call interp->freeProc " << endl;
}
// interp->freeProc = TCL_DYNAMIC;
}
else {
// ndevices > 1
if(cdevdebug == 1) {
printf(" CdevCmd: sync: ndevices=%d:\n ",ndevices);
}
int addbraces = 0;
for(n = 0; n < ndevices; n++) {
if(cdevdebug == 1) {
printf(" doing device %d:\n ",n);
}
if(data.hascontext) {
if(requests[n]->setContext(data.context) != CDEV_SUCCESS) {
interp->result = "setContext error";
delete requests;
free((char *) devices);
return TCL_ERROR;
}
}
if(requests[n]->send(data.out, result) != CDEV_SUCCESS) {
sprintf(interp->result, "error in send: %s %s", devices[n], argv[2]);
delete requests;
free((char *) devices);
return TCL_ERROR;
}
if(cdevdebug == 1) {
printf(" send worked:\n");
result.asciiDump(stdout);
}
if(STATUS_TAG !=- 1) {
if(result.get(STATUS_TAG, &i) == CDEV_SUCCESS) {
if(i != CDEV_SUCCESS) {
if(SEVERITY_TAG !=- 1) {
Tcl_DStringFree(&ds);
result.get(SEVERITY_TAG, cs, 255);
Tcl_DStringAppend(&ds, cs, -1);
Tcl_DStringResult(interp, &ds);
}
else {
interp->result = "cdev status != 0";
}
delete requests;
free((char *) devices);
return TCL_ERROR;
}
}
}
if(Cdev_Handleresult(data.taglist, data.tagn, result, ds, ndevices) != TCL_OK) {
interp->result = "cannot handle cdev result";
Tcl_DStringFree(&ds);
return TCL_ERROR;
}
}
Tcl_DStringResult(interp, &ds);
// changed SMH : 13MAR98 : do not know why - but this line dumps core
// interp->freeProc = TCL_DYNAMIC;
delete requests;
free((char *) devices);
}
if(cdevdebug == 1) {
printf(" all fine - will return TCL_OK:\n");
}
return TCL_OK;
}
int CdevDirectoryCmd(ClientData, Tcl_Interp *interp, int argc, char **argv) {
int ndevices = 0;
cdevData result;
Tcl_DString ds;
cdevCallback *cb = NULL;
callbackInfo *info;
tclCdevData data;
int delinfo = 0;
if(cdevdebug == 1) {
printf("CdevDirectoryCmd \n");
}
if(argc < 3) {
Tcl_AppendResult(interp, "cdevDirectory: wrong # args", (char *) NULL);
return TCL_ERROR;
}
if(argc < 3) {
Tcl_AppendResult(interp, "cdevDirectory: wrong # args", (char *) NULL);
return TCL_ERROR;
}
cdevDevice &device = cdevDevice::attachRef("cdevDirectory");
data.parse(interp, argv-1, argc+1);
if(data.state != TCL_OK) {
return TCL_ERROR;
}
if(data.async) {
// we want to sent it async
info = new callbackInfo(interp, data.callbacktag);
if(data.tagn != 0) {
info->addtags(data.tagn, data.taglist);
}
if(strncmp(argv[2], "monitorOn", 9) == 0) {
cb = new cdevCallback(Cdev_CallbackFunction, (void *) info);
}
else if(strncmp(argv[2], "monitorOff", 10) == 0) {
delinfo = 1;
cb = new cdevCallback(Cdev_CallbackFunction, NULL);
}
else {
cb = new cdevCallback(Cdev_CallbackFunction, (void *) info);
}
if(cdevdebug == 1) {
// cout << argv[1] << " " << argv[2] << " OutBound data: " << endl;
data.out.asciiDump(stdout);
}
if(device.sendCallback(argv[1], data.out, *cb) != 0) {
delete info;
return TCL_ERROR;
}
else {
if(delinfo) delete info;
return TCL_OK;
}
}
// send it sync
Tcl_DStringInit(&ds);
if(cdevdebug == 1) {
// cout << argv[1] << " " << argv[2] << " OutBound data: " << endl;
data.out.asciiDump(stdout);
}
if(device.send(argv[1], data.out, result) != CDEV_SUCCESS) {
sprintf(interp->result, "error in send: %s", argv[1]);
return TCL_ERROR;
}
if(cdevdebug == 1) {
// cout << "Result data: " << endl;
result.asciiDump(stdout);
}
// if(STATUS_TAG !=- 1) {
// if(result.get(STATUS_TAG, &i) == CDEV_SUCCESS) {
// if(i != CDEV_SUCCESS) {
// if(SEVERITY_TAG !=- 1) {
// Tcl_DStringFree(&ds);
// result.get(SEVERITY_TAG, cs, 255);
// Tcl_DStringAppend(&ds, cs, -1);
// Tcl_DStringResult(interp, &ds);
// }
// else {
// interp->result = "cdev status != 0";
// }
// return TCL_ERROR;
// }
// }
// }
if(Cdev_Handleresult(data.taglist, data.tagn, result, ds, 1) != TCL_OK) {
interp->result = "cannot handle cdev result";
Tcl_DStringFree(&ds);
return TCL_ERROR;
}
Tcl_DStringResult(interp, &ds);
// interp->freeProc = TCL_DYNAMIC;
return TCL_OK;
}
char *getCdevErrorCode(int code) {
switch (code) {
case -2: return "CDEV_WARNING";
case -1: return "CDEV_ERROR";
case 0: return "CDEV_SUCCESS";
case 1: return "CDEV_INVALIDOBJ";
case 2: return "CDEV_INVALIDARG";
case 3: return "CDEV_INVALIDSVC";
case 4: return "CDEV_INVALIDOP";
case 5: return "CDEV_NOTCONNECTED";
case 6: return "CDEV_IOFAILED";
case 7: return "CDEV_CONFLICT";
case 8: return "CDEV_NOTFOUND";
case 9: return "CDEV_TIMEOUT";
case 10: return "CDEV_CONVERT";
case 11: return "CDEV_OUTOFRANGE";
case 12: return "CDEV_NOACCESS";
case 13: return "CDEV_ACCESSCHANGED";
case 60: return "CDEV_DISCONNECTED";
case 61: return "CDEV_RECONNECTED";
case 70: return "CDEV_DELETE_CALLBACK";
default: return "UNKNOWN";
}
}
int CdevErrorCodeCmd(ClientData, Tcl_Interp *interp, int argc, char **argv) {
// cdevconvertcode code
if(argc < 2) {
Tcl_AppendResult(interp, "cdevconvertcode: wrong # args", (char *) NULL);
return TCL_ERROR;
}
int code = atoi(argv[1]);
interp->result = getCdevErrorCode(code);
// switch (code) {
// case -2: interp->result = "CDEV_WARNING"; break;
// case -1: interp->result = "CDEV_ERROR"; break;
// case 0: interp->result = "CDEV_SUCCESS"; break;
// case 1: interp->result = "CDEV_INVALIDOBJ"; break;
// case 2: interp->result = "CDEV_INVALIDARG"; break;
// case 3: interp->result = "CDEV_INVALIDSVC"; break;
// case 4: interp->result = "CDEV_INVALIDOP"; break;
// case 5: interp->result = "CDEV_NOTCONNECTED"; break;
// case 6: interp->result = "CDEV_IOFAILED"; break;
// case 7: interp->result = "CDEV_CONFLICT"; break;
// case 8: interp->result = "CDEV_NOTFOUND"; break;
// case 9: interp->result = "CDEV_TIMEOUT"; break;
// case 10: interp->result = "CDEV_CONVERT"; break;
// case 11: interp->result = "CDEV_OUTOFRANGE"; break;
// case 12: interp->result = "CDEV_NOACCESS"; break;
// case 13: interp->result = "CDEV_ACCESSCHANGED"; break;
// case 60: interp->result = "CDEV_DISCONNECTED"; break;
// case 61: interp->result = "CDEV_RECONNECTED"; break;
// case 70: interp->result = "CDEV_DELETE_CALLBACK"; break;
// default: interp->result = "UNKNOWN";
// }
return TCL_OK;
}
// #define CDEV_WARNING -2 /* Failure of function is non-consequential */
// #define CDEV_ERROR -1 /* Errors that are not in any categories */
// #define CDEV_SUCCESS 0 /* cdev success */
// #define CDEV_INVALIDOBJ 1 /* invalid cdev objects */
// #define CDEV_INVALIDARG 2 /* invalid argument passed to cdev calls */
// #define CDEV_INVALIDSVC 3 /* wrong service during dynamic loading */
// #define CDEV_INVALIDOP 4 /* operation is unsupported (collection) */
// #define CDEV_NOTCONNECTED 5 /* not connected to low network service */
// #define CDEV_IOFAILED 6 /* low level network service IO failed */
// #define CDEV_CONFLICT 7 /* conflicts of data types or tags */
// #define CDEV_NOTFOUND 8 /* cdev cannot find user request (cdevData) */
// #define CDEV_TIMEOUT 9 /* time out */
// #define CDEV_CONVERT 10 /* cdevData conversion error */
// #define CDEV_OUTOFRANGE 11 /* value out of range for device attribute */
// #define CDEV_NOACCESS 12 /* insufficient access to perform request */
// #define CDEV_ACCESSCHANGED 13 /* change in access permission of device */
// #define CDEV_DISCONNECTED 60 /* channel has been disconnected */
// #define CDEV_RECONNECTED 61 /* channel has been reconnected */
// #define CDEV_DELETE_CALLBACK 70 /* the callback object will be deleted */
//
// /* Request object state values */
// #define CDEV_STATE_CONNECTED 0 /* request object is connected to device */
// #define CDEV_STATE_NOTCONNECTED 1 /* request object is not connected */
// #define CDEV_STATE_INVALID 2 /* request object is invalid */
//
// /* Request object access values */
// #define CDEV_ACCESS_NONE 0 /* no access to specified attribute */
// #define CDEV_ACCESS_READONLY 1 /* read-only access to attribute */
// #define CDEV_ACCESS_WRITE 2 /* read-write access to attribute */
//
// /* cdevError class severity codes */
// #define CDEV_SEVERITY_INFO 0 /* informative message */
// #define CDEV_SEVERITY_WARN 1 /* warning message */
// #define CDEV_SEVERITY_ERROR 2 /* error message */
// #define CDEV_SEVERITY_SEVERE 3 /* severe or fatal error message */
// SMH changed for tcl8.0
// extern"C"int Cdev_Init(Tcl_Interp *interp) {
extern"C"int Tclcdev_Init(Tcl_Interp *interp) {
// printf("This is Tclcdev_Init \n");
int i, numFD = 20;
int fds[20];
cdevSystem::defaultSystem().getFd(fds, numFD);
for (i=0;i<numFD;i++) {
// cout << " fd " << i << endl;
Cdev_RegisterFD(fds[i],1,NULL);
}
cdevSystem::defaultSystem().addFdChangedCallback(Cdev_RegisterFD, NULL);
if(Tcl_PkgProvide(interp, "Cdev", TCLCDEV_VERSION) != TCL_OK) {
return TCL_ERROR;
}
if(Tcl_PkgProvide(interp, "CdevFormat", TCLCDEV_VERSION) != TCL_OK) {
return TCL_ERROR;
}
cdevFormat = new char[strlen(defaultFormat)+1];
strcpy(cdevFormat, defaultFormat);
Tcl_CreateCommand(interp, "cdev", CdevCmd, (ClientData *) NULL, (Tcl_CmdDeleteProc *) NULL);
Tcl_CreateCommand(interp, "cdevDirectory", CdevDirectoryCmd, (ClientData *) NULL, (Tcl_CmdDeleteProc *) NULL);
Tcl_CreateCommand(interp, "cdevdebug", CdevDebugCmd, (ClientData *) NULL, (Tcl_CmdDeleteProc *) NULL);
Tcl_CreateCommand(interp, "cdevformat", CdevFormatCmd, (ClientData *) NULL, (Tcl_CmdDeleteProc *) NULL);
Tcl_CreateCommand(interp, "cdeverrorcode", CdevErrorCodeCmd, (ClientData *) NULL, (Tcl_CmdDeleteProc *) NULL);
Tcl_CreateCommand(interp, "putenv", PutEnvCmd, (ClientData *) NULL, (Tcl_CmdDeleteProc *) NULL);
Tcl_CreateExitHandler(Cdev_ExitProc, NULL);
// Cdev_UpdateProc(NULL);
// printf("end of Tclcdev_Init \n");
return TCL_OK;
}