diff --git a/HistDriv.i b/HistDriv.i index 1e033d86..b9fad721 100644 --- a/HistDriv.i +++ b/HistDriv.i @@ -1,5 +1,5 @@ -#line 465 "histogram.w" +#line 467 "histogram.w" /*--------------------------------------------------------------------------- H I S T D R I V @@ -72,7 +72,7 @@ void *pPriv; } HistDriver; -#line 477 "histogram.w" +#line 479 "histogram.w" #line 232 "histogram.w" @@ -81,8 +81,10 @@ void DeleteHistDriver(pHistDriver self); int HistDriverConfig(pHistDriver self, pStringDict pOpt, SConnection *pCon); + HistInt *DefaultSubSample(pHistDriver self, SConnection *pCon, + int bank, char *command); -#line 478 "histogram.w" +#line 480 "histogram.w" #endif diff --git a/HistMem.h b/HistMem.h index b0872505..6ffc568b 100644 --- a/HistMem.h +++ b/HistMem.h @@ -1,5 +1,5 @@ -#line 438 "histogram.w" +#line 440 "histogram.w" /*-------------------------------------------------------------------------- H I S T M E M @@ -42,22 +42,22 @@ eReflect } OverFlowMode; -#line 458 "histogram.w" +#line 460 "histogram.w" /*--------------------------------------------------------------------------*/ -#line 290 "histogram.w" +#line 292 "histogram.w" pHistMem CreateHistMemory(char *drivername); void DeleteHistMemory(void *self); -#line 306 "histogram.w" +#line 308 "histogram.w" int HistGetOption(pHistMem self, char *name, char *result, int iResultLen); int HistSetOption(pHistMem self, char *name, char *value); int HistConfigure(pHistMem self, SConnection *pCon, SicsInterp *pSics); -#line 334 "histogram.w" +#line 336 "histogram.w" float GetHistPreset(pHistMem self); int SetHistPreset(pHistMem self, float fVal); @@ -73,7 +73,7 @@ void HistDirty(pHistMem self); -#line 364 "histogram.w" +#line 366 "histogram.w" int SetHistogram(pHistMem self, SConnection *pCon, int i,int iStart, int iEnd, HistInt *lData); @@ -85,7 +85,7 @@ HistInt *lData, int iDataLen); int PresetHistogram(pHistMem self, SConnection *pCon, HistInt lVal); -#line 407 "histogram.w" +#line 409 "histogram.w" int MakeHistMemory(SConnection *pCon, SicsInterp *pSics, void *pData, int argc, char *argv[]); @@ -94,7 +94,7 @@ int argc, char *argv[]); -#line 460 "histogram.w" +#line 462 "histogram.w" #endif diff --git a/HistMem.i b/HistMem.i index 8ff674ed..5c6b98d0 100644 --- a/HistMem.i +++ b/HistMem.i @@ -1,5 +1,5 @@ -#line 483 "histogram.w" +#line 485 "histogram.w" /*--------------------------------------------------------------------------- H I S T M E M -- Internal @@ -11,7 +11,7 @@ #ifndef SICSHISTMEMINT #define SICSHISTMEMINT -#line 254 "histogram.w" +#line 256 "histogram.w" typedef struct __HistMem { pObjectDescriptor pDes; @@ -23,7 +23,7 @@ pICallBack pCall; } HistMem; -#line 493 "histogram.w" +#line 495 "histogram.w" #endif diff --git a/README b/README new file mode 100644 index 00000000..570f8e6a --- /dev/null +++ b/README @@ -0,0 +1,70 @@ + + SICS README + + Requirements + + - hdf-4, hdf5- libraries: http://hdf.ncsa.uiuc.edu + - szlib : same place as HDF + - Mini XML library : http://www.minixml.org/software.php + - libghttp : + http://ftp.gnome.org/pub/GNOME/source/libghttp/1.0/libghttp-1.0.9.tar.gz + - json-c : http://oss.metaparadigm.com/json-c + - tcl : any version from 8.0, package tcl-devel on most + modern linux distros + + + Building + + Install the libraries stated above, preferably to a common place. + Then edit the suplied makefile, instance makefile_linux, and change: + - uncomment all the NI, NIOBJ, NILIB stuff, except if you want support + for the NI enet100 GPIB/TCP/IP converter. + - Edit linux_def and set HDFROOT to where you installed your libraries + - Review the CFLAGS and LIBS to match your setup. Consider file format + format support: + ** HDF-4 required -DHDF4 in CFLAGS and -lmfdf -ldf in LIBS + ** HDF-5 support requires: -DHDF5 in CFLAGS and -lhdf5 in LIBS + ** XML support requires: -DNXXML -n CFLAGS and -lmxml in LIBS + - build with make -f makefile_linux + - Good Luck!! + Sorry, no configure script here. There are so few people building SICS + that it is not worth the effort. The effort really is to build the + libraries. + + + Running + + In the sim directory there are startup scripts for a number of different + instruments. To run any of them: + - edit the instrument file and change the home or root variable at the + top to match your setup. + - run with: SICServer path-to-instrument-file + For example: SICServer sim/topsi/morpheus.tcl + - Common issues: + ** tmp directory missing: create one + ** SicsDataNumber file missing: create a file with a single 0 in it + + + Trying it out with telnet + + - telnet host-where-sics-runs 2911 + - type username and password: Spy 007 is a good idea for the supplied sims + - type SICS commands + + + Directories + + sics : root directory containing the SICS kernel + sics/psi : psi specific drivers and stuff + sics/site_ansto : ANSTO specific stuff. Currently empty, ANSTO has its + own cvs + sics/dummy : example kit for defining an own site + sics/doc/user : user documentation + sics/doc/manager : manager documentation + sics/doc/programmer : programmer documentation + sics/matrix : matrix library used within SICS + sics/mcstas : code for virtual McStas instruments + sics/sim : control files for various instruments + sics/test : a sort of regression test for the SICS server + + \ No newline at end of file diff --git a/SCinter.c b/SCinter.c index 1ba7f178..611fca13 100644 --- a/SCinter.c +++ b/SCinter.c @@ -60,6 +60,7 @@ #include #include #include +#include #include "fortify.h" #include "sics.h" #include "splitter.h" @@ -478,6 +479,10 @@ extern char *SkipSpace(char *pPtr); pCurrent = tail; while(pCurrent) { + /* the line below fixes problems with kill functions + * traversing the command list + */ + pCurrent->pNext = NULL; if(pCurrent->KFunc) { pCurrent->KFunc(pCurrent->pData); @@ -487,6 +492,9 @@ extern char *SkipSpace(char *pPtr); /* printf("Deleting %s\n",pCurrent->pName); */ free(pCurrent->pName); } + if (pCurrent->stat) { + StatisticsKill(pCurrent->stat); + } pTemp = pCurrent->pPrevious; free(pCurrent); pCurrent = pTemp; @@ -973,6 +981,11 @@ static void printType(SicsInterp *pSics, SConnection *pCon, char *typeName) if(!pCom->pData) return NULL; + if (cclass == NULL) + { + return pCom->pData; + } + pDum = (pDummy)pCom->pData; if(strcmp(pDum->pDescriptor->name,cclass) == 0) { @@ -980,6 +993,19 @@ static void printType(SicsInterp *pSics, SConnection *pCon, char *typeName) } 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; @@ -1106,3 +1132,19 @@ char *FindAliases(SicsInterp *pSics, char *name) 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; + } + } +} diff --git a/SCinter.h b/SCinter.h index 3c60dea8..1b24ce24 100644 --- a/SCinter.h +++ b/SCinter.h @@ -9,6 +9,7 @@ ---------------------------------------------------------------------------*/ #ifndef SICSINTERPRETER #define SICSINTERPRETER +#include "obdes.h" #include "Scommon.h" #include "statistics.h" #include @@ -142,19 +143,31 @@ typedef struct __SINTER /*------------------------------------------------------------------------- FindCommandData finds a command with the name given. It tests the name in the ObjectDescriptor to be of name class. If all this succeeds a pointer - to the commands data structure is retuned. Else NULL + to the commands data structure is retuned. Else NULL. + Do not test the Object Descriptor name when comclass == NULL. */ void *FindCommandData(SicsInterp *pSics, char *name, char *comclass); +/*------------------------------------------------------------------------- + FindCommandDescriptor finds the descriptor of a command with the name given. +*/ + pObjectDescriptor FindCommandDescriptor(SicsInterp *pSics, char *name); + /*------------------------------------------------------------------------ FindDrivable tries to find Drivable object by the name given. Returns a pointer to the drivable interface in the case of success, NULL in case of failure. In order to save me fixing header files the pointer must be cast to the drivable interface pointer. - ------------------------------------------------------------------------*/ - +*/ void *FindDrivable(SicsInterp *pics, char *name); +/*------------------------------------------------------------------------ + Go through the command list and call scanFunction for every command + until the return value is 0. +*/ +void ForEachCommand(int (*scanFunction)(char *name, pDummy object, void *userData) + , void *userData); + /*----------------------------------------------------------------------- Get a copy of the Tcl interpreter ------------------------------------------------------------------------*/ diff --git a/SICSmain.c b/SICSmain.c index 300dad15..c069629d 100644 --- a/SICSmain.c +++ b/SICSmain.c @@ -22,6 +22,7 @@ #include #include #include "nserver.h" +#include "servlog.h" /***************************** Necessary Globals ****************************/ @@ -41,37 +42,36 @@ { int iRet; int debug = 0; - const char* filename = NULL; + char *file=NULL; + int i, firstArg=1; - /* initialise, will die on you if problems */ - if(argc >= 2) - { - if (strcasecmp(argv[1], "-d") == 0) - { + /* initialise, will die on you if problems */ + if (strcasecmp(argv[1], "-d") == 0) { debug = 1; - if (argc > 2) - filename = argv[2]; - } - else - { - filename = argv[1]; - } - } - iRet = InitServer(filename, &pServ); - if(!iRet) - { - printf("Unrecoverable error on server startup, exiting.........\n"); - exit(1); - } - if (debug == 0) - daemon(1,1); - - - RunServer(pServ); - - StopServer(pServ); - pServ = NULL; - exit(0); + firstArg=2; + } + for (i=firstArg; i +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "sics.h" +#include "splitter.h" +#include "ascon.i" + +/* + CreateSocketAdress stolen from Tcl. Thanks to John Ousterhout +*/ + +static int CreateSocketAdress( + struct sockaddr_in *sockaddrPtr, /* Socket address */ + char *host, /* Host. NULL implies INADDR_ANY */ + int port) /* Port number */ +{ + struct hostent *hostent; /* Host database entry */ + struct in_addr addr; /* For 64/32 bit madness */ + + (void) memset((char *) sockaddrPtr, '\0', sizeof(struct sockaddr_in)); + sockaddrPtr->sin_family = AF_INET; + sockaddrPtr->sin_port = htons((unsigned short) (port & 0xFFFF)); + if (host == NULL) { + addr.s_addr = INADDR_ANY; + } else { + hostent = gethostbyname(host); + if (hostent != NULL) { + memcpy((char *) &addr, + (char *) hostent->h_addr_list[0], (size_t) hostent->h_length); + } else { + addr.s_addr = inet_addr(host); + if (addr.s_addr == (unsigned long)-1) { + return 0; /* error */ + } + } + } + /* + * There is a rumor that this assignment may require care on + * some 64 bit machines. + */ + sockaddrPtr->sin_addr.s_addr = addr.s_addr; + return 1; +} + +double DoubleTime(void) { + struct timeval now; + /* the resolution of this function is usec, if the machine supports this + and the mantissa of a double is 51 bits or more (31 for sec and 20 for micro) + */ + gettimeofday(&now, NULL); + return now.tv_sec + now.tv_usec / 1e6; +} + +void AsconError(Ascon *a, char *msg, int errorno) { + static char *stateText[]={ + "state 0", "kill", "state 2", "notConnected", + "connect", "start connect", "connect finished", "connect failed", + "write", "start write", "write finished", "write failed", + "read", "start read", "read finished", "read failed", + "state 16", "state 17", "state 18", "idle" + }; + char *state; + + if (a->state < 0 || a->state > 19) { + state = "bad state"; + } else { + state = stateText[a->state]; + } + if (errorno != 0) { + a->errList = ErrPutMsg(a->errList, "ASCERR: %s %s (during %s)", msg, strerror(errorno), state); + } else { + a->errList = ErrPutMsg(a->errList, "ASCERR: %s (during %s)", msg, state); + } + a->state |= AsconFailed; +} + +static void AsconConnect(Ascon *a) { + /* input state: AsconConnectStart + output state: AsconFailed or AsconConnecting */ + int ret; + struct sockaddr_in adr; + char *colon; + int port; + int oldopts; + + if (a->fd < 0) { + a->fd = socket(AF_INET,SOCK_STREAM,0); + if (a->fd < 0) { + AsconError(a, "socket failed:", errno); + return; + } + } + colon = strchr(a->hostport, ':'); + if (colon == NULL) return; + port = atoi(colon+1); + if (port <= 0) { + AsconError(a, "bad port number", 0); + return; + } + *colon = '\0'; + ret = CreateSocketAdress(&adr, a->hostport, port); + *colon = ':'; + if (ret == 0) { + AsconError(a, "bad host specification", 0); + return; + } + /* should we insert the workaround for lantronix server ? see network.c */ + oldopts = fcntl(a->fd, F_GETFL, 0); + fcntl(a->fd, F_SETFL, oldopts | O_NONBLOCK); + ret = connect(a->fd, (struct sockaddr *)&adr, sizeof(struct sockaddr_in)); + if (ret < 0) { + switch(errno) { + case EINPROGRESS: + case EALREADY: + case EISCONN: + a->state = AsconConnecting; + break; + default: + AsconError(a, "connect failed:", errno); + return; + } + } + a->state = AsconConnecting; + return; +} + +int AsconStdInit(Ascon *a, SConnection *con, + int argc, char *argv[]) { + a->fd = -1; + a->state = AsconConnectStart; + a->reconnectInterval = 10; + a->hostport = strdup(argv[1]); + if(argc > 2){ + a->sendTerminator = strdup(argv[2]); + } else { + a->sendTerminator = strdup("\n"); + } + if(argc > 3){ + a->timeout = atof(argv[3]); + } else { + a->timeout = 2.0; /* sec */ + } + return 1; +} + +int AsconReadGarbage(int fd) { + fd_set rmask; + struct timeval tmo = {0,0}; + int l, ret, result; + char garbage[100]; + + FD_ZERO(&rmask); + result = 0; + do { + FD_SET(fd, &rmask); + ret = select(fd + 1, &rmask, NULL, NULL, &tmo); + if (ret > 0) { + l = recv(fd, garbage, sizeof garbage, 0); + if (l > 0) { + /* swallow */ + result += l; + } else if (l == 0) { + errno = ECONNRESET; + return -2; + } else if (l < 0) { + return -2; + } + } + } while (ret > 0); + return result; +} + +void PrintChar(char chr) { + if (chr <= 32 || chr >= 127) { + printf("%2.2x ", chr); + } else { + printf(" %c ", chr); + } +} + +int AsconConnectSuccess(int fd) { + fd_set wmask, rmask; + struct timeval tmo = {0,0}; + int oldopts; + int ret; + + oldopts = fcntl(fd, F_GETFL, 0); + assert(oldopts | O_NONBLOCK); /* fd must be in non-blocking mode */ + + FD_ZERO(&wmask); + FD_ZERO(&rmask); + FD_SET(fd, &wmask); + FD_SET(fd, &rmask); + ret = select(fd + 1, &rmask, &wmask, NULL, &tmo); + if (ret > 0) { + assert(FD_ISSET(fd, &wmask)); + if (FD_ISSET(fd, &rmask)) { /* there may already be data for read */ + if (recv(fd, NULL, 0, 0) < 0) { /* zero length, check only return value */ + ret = ASCON_RECV_ERROR; /* first recv failed */ + } + } else { + if (send(fd, NULL, 0, 0) < 0) { /* zero length, check only return value */ + ret = ASCON_SEND_ERROR; /* first send failed */ + } + } + } + fcntl(fd, F_SETFL, oldopts & ~ O_NONBLOCK); /* reset to blocking mode */ + return ret; +} + +int AsconReadChar(int fd, char *chr) { + fd_set rmask; + struct timeval tmo = {0,0}; + int ret; + + FD_ZERO(&rmask); + FD_SET(fd, &rmask); + ret = select(fd + 1, &rmask, NULL, NULL, &tmo); + if (ret <= 0) return ret; + ret = recv(fd, chr, 1, 0); + /* PrintChar(*chr); */ + fflush(stdout); + if (ret > 0) return 1; + if (ret == 0) { + errno = ECONNRESET; + return ASCON_DISCONNECTED; + } + return ASCON_RECV_ERROR; +} + +int AsconWriteChars(int fd, char *data, int length) { + fd_set wmask; + struct timeval tmo = {0,0}; + int ret; + + if (length <= 0) return 0; + /* + { int i; + for (i=0; i 0) return ret; + if (ret == 0) { + errno = ECONNRESET; + return ASCON_DISCONNECTED; + } + return ASCON_SEND_ERROR; +} + +static double lastCall = 0; + +int AsconStdHandler(Ascon *a) { + int ret; + int l; + char chr; + double now = DoubleTime(); + + if (now > lastCall + 0.5) { /* AsconStdHandler was not called since a long time (0.5 sec) */ + if (lastCall != 0) { /* extend timeout time (for debugging purposes) */ + a->start += now - lastCall - 0.5; + } + } + lastCall = now; + switch (a->state) { + case AsconConnectStart: + AsconConnect(a); + break; + case AsconConnecting: + ret = AsconConnectSuccess(a->fd); + if (ret == 0) { + /* in progress */ + } else if (ret > 0) { + a->state = AsconConnectDone; /* success */ + } else if (ret < 0) { + AsconError(a, "AsconConnectSuccess failed:", errno); + } + break; + case AsconWriteStart: + DynStringConcat(a->wrBuffer, a->sendTerminator); + a->wrPos = 0; + a->state = AsconWriting; + if(strstr(GetCharArray(a->wrBuffer),"@@NOSEND@@") != NULL){ + a->state = AsconWriteDone; + } + break; + case AsconWriting: + AsconReadGarbage(a->fd); + l = GetDynStringLength(a->wrBuffer) - a->wrPos; + ret = AsconWriteChars(a->fd, GetCharArray(a->wrBuffer) + a->wrPos, l); + if (ret < 0) { + AsconError(a, "send failed:", errno); + /* + * Ooops: which state shall we go to after a write fail? + * This seems to retry. + */ + } else { + a->wrPos += ret; + if (a->wrPos >= GetDynStringLength(a->wrBuffer)) { + a->state = AsconWriteDone; + } + } + break; + case AsconReadStart: + DynStringClear(a->rdBuffer); + a->start = DoubleTime(); + a->state = AsconReading; + break; + case AsconReading: + ret = AsconReadChar(a->fd, &chr); + while (ret > 0) { + a->start = DoubleTime(); + + if (chr == '\n') { + if (a->readState) { + /* swallow LF after CR */ + DynStringClear(a->rdBuffer); + a->readState = 0; + } else { + DynStringConcatChar(a->rdBuffer, '\0'); + a->state = AsconReadDone; + break; + } + } else if (chr == '\r') { + a->readState = 1; + DynStringConcatChar(a->rdBuffer, '\0'); + a->state = AsconReadDone; + break; + } else { + if (DynStringConcatChar(a->rdBuffer, chr) == 0) { + AsconError(a, "DynStringConcatChar failed:", ENOMEM); + break; + } + a->readState = 0; + } + ret = AsconReadChar(a->fd, &chr); + } + if (ret < 0) { + AsconError(a, "AsconReadChar failed:", errno); + return 1; + } + if (a->state == AsconReadDone) { + DynStringConcatChar(a->rdBuffer, '\0'); + } else { + if (a->timeout > 0) { + if (DoubleTime() - a->start > a->timeout) { + AsconError(a, "read timeout", 0); + a->state = AsconTimeout; + } + } + } + break; + default: + return 1; + } + return 1; +} + +/* define type AsconProtocolList and functions AsconProtocolAdd etc. */ +#define MC_NAME(T) AsconProtocol##T +#include "mclist.c" + +static AsconProtocolList protocols={0}; + +void AsconInsertProtocol(AsconProtocol *protocol) { + AsconProtocolAdd(&protocols, protocol); +} + +AsconHandler AsconSetHandler(Ascon *a, SConnection *con, + int argc, char *argv[]) { + AsconProtocol *p; + + if (argc < 1) return NULL; + if (strcasecmp(argv[0], "std") == 0) { + if (argc < 2) return NULL; + AsconStdInit(a, con, argc, argv); + return AsconStdHandler; + } + for (p = protocols.head; p!= NULL; p=p->next) { + if (strcasecmp(p->name, argv[0]) == 0) { + if(p->init(a, con, argc, argv)){ + return p->handler; + } else { + return NULL; + } + } + } + return NULL; +} + +/* --- implementation of higher level interface ---- */ + +char *ConcatArgs(int argc, char *argv[]) { + return Arg2Tcl(argc, argv, NULL, -1); +} + +Ascon *AsconMake(SConnection *con, int argc, char *argv[]) { + Ascon *a; + char *args; + + a = calloc(1, sizeof(*a)); + if (a == NULL) { + SCWrite(con, "ERROR: no memory", eError); + return NULL; + } + a->handler = AsconSetHandler(a, con, argc, argv); + if (a->handler == NULL) { + args = ConcatArgs(argc, argv); + if (!args) return NULL; + SCPrintf(con, eError, "ERROR: illegal protocol: %s", args); + free(args); + return NULL; + } + a->rdBuffer = CreateDynString(60, 63); + a->wrBuffer = CreateDynString(60, 63); + a->errList = NULL; + a->responseValid = 0; + a->reconnectInterval = 10; + a->lastReconnect = 0; + return a; +} + +void AsconKill(Ascon *a) { + if (a->fd > 0) { + close(a->fd); + } + DeleteDynString(a->rdBuffer); + DeleteDynString(a->wrBuffer); + if (a->hostport) { + free(a->hostport); + } + if(a->sendTerminator){ + free(a->sendTerminator); + } + if(a->private != NULL && a->killPrivate != NULL){ + a->killPrivate(a->private); + } + free(a); +} + +AsconStatus AsconTask(Ascon *a) { + double now; + + while (a->handler(a)) { + switch (a->state) { + case AsconReading: + case AsconWriting: + return AsconPending; + case AsconNotConnected: + return AsconOffline; + break; + case AsconConnectDone: + a->state = AsconIdle; + return AsconReady; + case AsconWriteDone: + if (a->noResponse) { + return AsconReady; + } + a->state = AsconReadStart; + break; + case AsconReadDone: + a->state = AsconIdle; + a->responseValid = 1; + return AsconReady; + case AsconConnecting: + return AsconUnconnected; + default: + switch (a->state % 4) { + case AsconOnTheWay: + case AsconStart: + return AsconPending; + case AsconFailed: + if (a->state != AsconTimeout) { + now = DoubleTime(); + if (now > a->lastReconnect + a->reconnectInterval) { + a->lastReconnect = now; + close(a->fd); + a->fd = -1; + a->state = AsconConnectStart; + } + } + return AsconFailure; + case AsconFinished: + if (a->state < AsconConnectFailed) { + return AsconUnconnected; + } + return AsconReady; + } + } + } + return AsconIdle; +} + +int AsconWrite(Ascon *a, char *command, int noResponse) { + if (a->state <= AsconConnectFailed || a->state % 4 < AsconFinished) return 0; + DynStringCopy(a->wrBuffer, command); + a->noResponse = noResponse; + a->state = AsconWriteStart; + a->responseValid = 0; + AsconTask(a); + return 1; +} + +char *AsconRead(Ascon *a) { + if (a->noResponse) { + a->noResponse=0; + return ""; + } + if (a->state % 4 == AsconFailed) { + a->state = AsconIdle; + return ""; + } + if (a->responseValid) { + a->responseValid = 0; + return GetCharArray(a->rdBuffer); + } + return NULL; +} + +ErrMsg *AsconGetErrList(Ascon *a) { + return a->errList; +} diff --git a/ascon.h b/ascon.h new file mode 100644 index 00000000..fe6f4d32 --- /dev/null +++ b/ascon.h @@ -0,0 +1,82 @@ +#ifndef ASCON_H +#define ASCON_H + +#include "sics.h" +#include "errormsg.h" + +/** \file + * \brief Asynchronous connection handling for devices controlled over tcp-ip + * connections. Interface for higher level modules. + */ + +/** \brief the asynchronous connection + */ +typedef struct Ascon Ascon; + +/** \brief the possible results of AsconTask + */ +typedef enum { + AsconOffline, + AsconUnconnected, + AsconPending, + AsconReady, + AsconFailure +} AsconStatus; + +/** \brief make a new asynchronous connection + * \param con the SICS connection + * \param argc number of arguments + * \param argv the arguments. argv[0] must be the protocol name, the other arguments + * are protocol specific, but argv[1] is usually host::port + * \return the created connection or NULL on failure + */ +Ascon *AsconMake(SConnection *con, int argc, char *argv[]); + +/** \brief kill function + * \param a the connection to be killed + */ +void AsconKill(Ascon *a); + +/** \brief the task handler. To be called repeatedly. + * \param a the connection + * \return the state of the connection + */ +AsconStatus AsconTask(Ascon *a); + +/** \brief write to the connection. allowed only when the state is AsconReady + * \param a the connection + * \param command the command to be sent + * \param noResponse 0 normally, 1 if no reponse is expected + * \return 1 on success, 0 when not ready + */ +int AsconWrite(Ascon *a, char *command, int noResponse); + +/** \brief read from the connection. allowed only when a response is available + * \param a the connection + * \return the response when a response is ready + * NULL when the command has not completed and the response is not yet finished + * "" when the command has completed, but no response was expected. + * The result is only valid until the next call to other AsconXxx functions + * and has to be duplicated if needed later. + */ +char *AsconRead(Ascon *a); + +/** \brief get the connections error list + * \return the error list + */ +ErrMsg *AsconGetErrList(Ascon *a); + +/** \brief a helper function + * \param argc the number of args + * \param argv the args to be concatenated + * \result a allocated string containing the concatenated arguments + * the args are properly quoted to be used as tcl proc arguments + */ +char *ConcatArgs(int argc, char *argv[]); + +/** \brief function for dealing with times with musec resolution + * \return absolute time as double value + */ +double DoubleTime(void); + +#endif diff --git a/ascon.i b/ascon.i new file mode 100644 index 00000000..25f01eaa --- /dev/null +++ b/ascon.i @@ -0,0 +1,156 @@ +#ifndef ASCON_I +#define ASCON_I + +#include +#include "ascon.h" +#include "dynstring.h" + +/** \file + * \brief Asynchronous connection handling for devices controlled over tcp-ip + * connections. Interface for the implementation of custom protocols. + * + * For the implementation of a custom protocol, you have to implement + * the handler function and the init function, declare the protocol + * of type AsconProtocol and call AsconInsertProtocol on startup. + * The handler and init functions are normally be a wrapper around AsconStdHandler + * and AsconStdInit + * + * The functions with fd as the first argument are utility functions with + * may be used in handler wrapper functions. + * On error, the return value may be one of the defined macros ASCON_xxx, + * and errno will give more details about the error. + */ + +/** + * A sub-state of the connection. Only states with sub-state AsconStart may + * be set by the caller, and only when the sub-state is not AsconOnTheWay + */ +typedef enum { AsconOnTheWay=0, AsconStart=1, AsconFinished=2, AsconFailed=3 } AsconMode; + +/** + * The state of the connection. The sub-state is state % 4. + */ +typedef enum { + AsconNotConnected=0+AsconFinished, + AsconConnecting=4+AsconOnTheWay, + AsconConnectStart=AsconConnecting+AsconStart, + AsconConnectDone=AsconConnecting+AsconFinished, + AsconConnectFailed=AsconConnecting+AsconFailed, + AsconWriting=8+AsconOnTheWay, + AsconWriteStart=AsconWriting+AsconStart, + AsconWriteDone=AsconWriting+AsconFinished, + AsconReading=12+AsconOnTheWay, + AsconReadStart=AsconReading+AsconStart, + AsconReadDone=AsconReading+AsconFinished, + AsconIdle=16+AsconFinished, + AsconTimeout=20 + AsconFailed +} AsconState; + +/** \brief the task handler function prototype + * + * custom handlers must have this prototype + */ +typedef int (* AsconHandler)(Ascon *connection); + +/** Ascon struct + * all members are public, allowing access by handler wrappers + */ +struct Ascon { + AsconState state; /**< the current state */ + int fd; /**< socket */ + int readState; /**< default implementation: 'was cr' */ + pDynString rdBuffer;/**< read buffer */ + pDynString wrBuffer;/**< write buffer */ + int wrPos; /**< write buffer position */ + double timeout; /**< read timeout (sec) */ + char *sendTerminator; /**< terminator for sending messages */ + char *hostport; /**< host:port to connect */ + ErrMsg *errList; /**< error message list */ + double start; /**< unix time when read was started */ + void *private; /**< private data of protocol */ + void (*killPrivate)(void *); /** < kill function for private */ + int noResponse; /**< no response expected */ + int responseValid; /**< a valid response is ready */ + AsconHandler handler; /**< handler function */ + double reconnectInterval; /**< reconnect interval */ + double lastReconnect; /**< last connect try */ +}; + +#define ASCON_SELECT_ERROR -1 +#define ASCON_RECV_ERROR -2 +#define ASCON_SEND_ERROR -3 +#define ASCON_DISCONNECTED -4 + +/** \brief the standard handler routine. + * \param a the connection + * \return 0 when task has finished (connection to be closed), 1 when active + * + * In most cases a custom handler may be a wrapper around AsconStdHandler + */ +int AsconStdHandler(Ascon *a); + +/** \brief initialize a standard connection + * \param a the connection + * \param con A connection to print errors too. + * \param hostport the tcp/ip address (syntax: host:port) + * + * In most cases a custom init function may be a wrapper around AsconStdInit + */ +int AsconStdInit(Ascon *a, SConnection *con, int argc, char *argv[]); + +/** The Ascon Protocol + */ +typedef struct AsconProtocol { + struct AsconProtocol *next; + char *name; + AsconHandler handler; + int (*init)(Ascon *s, SConnection *con, int argc, char *argv[]); +} AsconProtocol; + +/** \brief Insert a new protocol into the protocol list + * protocol the protocol (must be allocated by the caller, may be statically) + */ +void AsconInsertProtocol(AsconProtocol *protocol); + +/** \brief close the connection and free internal used memory + * \param a the connection to be closed + * remark: the connection struct itself has to be freed manually + */ +void AsconClose(Ascon *a); + +/** \brief swallow garbage (utility function) + * \param fd the socket + * \return >=0: number of chars swallowed, else error + */ +int AsconReadGarbage(int fd); + +/** \brief check if a connection has succeded (utility function) + * \param fd the socket + * \return 1: connection succesful, 0: connection in progress, <0: error + */ +int AsconConnectSuccess(int fd); + +/** \brief read one character, if available (utility function) + * \param fd the socket + * \param chr the result + * \return 1: succes, 0: no data available, <0: error + */ +int AsconReadChar(int fd, char *chr); + +/** \brief non blocking write (utility function) + * \param fd the socket + * \param data the data (not nul-terminated, may contain nul) + * \param length the length of the data + * \return >0: number of written chars,0: write not yet possible, <0: error + */ +int AsconWriteChars(int fd, char *data, int length); + +/** \brief store an error + * \param a The asynchronous I/O structure to store the + * error with + * \param msg The error message + * \param errorno The error number + */ +void AsconError(Ascon *a, char *msg, int errorno); + +#endif diff --git a/asyncprotocol.c b/asyncprotocol.c index 3c1eb14e..d7d941b6 100644 --- a/asyncprotocol.c +++ b/asyncprotocol.c @@ -96,6 +96,9 @@ int defaultPrepareTxn(pAsyncProtocol p, pAsyncTxn txn, const char* cmd, int cmd_ } txn->out_len = cmd_len; txn->out_idx = 0; + if(txn->inp_buf != NULL){ + free(txn->inp_buf); + } txn->inp_buf = malloc(rsp_len); if (txn->inp_buf == NULL) { SICSLogWrite("Out of memory in AsyncProtocol::defaultPrepareTxn", eError); diff --git a/asyncprotocol.h b/asyncprotocol.h index 7e7246f4..ebbb07f7 100644 --- a/asyncprotocol.h +++ b/asyncprotocol.h @@ -21,7 +21,8 @@ typedef enum { ATX_NULL=0, ATX_TIMEOUT=-1, ATX_ACTIVE=1, - ATX_COMPLETE=2 + ATX_COMPLETE=2, + ATX_DISCO=3 } ATX_STATUS; struct __async_txn { diff --git a/asyncqueue.c b/asyncqueue.c index a392604e..30c3b92d 100644 --- a/asyncqueue.c +++ b/asyncqueue.c @@ -23,7 +23,6 @@ #include "nwatch.h" #include -typedef struct __AsyncQueue AsyncQueue, *pAsyncQueue; typedef struct __async_command AQ_Cmd, *pAQ_Cmd; @@ -361,7 +360,7 @@ static int MyCallback(void* context, int mode) return 1; } -int AsyncUnitEnqueHead(pAsyncUnit unit, pAsyncTxn context) +int AsyncUnitEnqueueHead(pAsyncUnit unit, pAsyncTxn context) { pAQ_Cmd myCmd = NULL; @@ -1074,6 +1073,18 @@ int AsyncUnitDestroy(pAsyncUnit unit) return 1; } +pAsyncUnit AsyncUnitFromQueue(pAsyncQueue queue){ + pAsyncUnit result = NULL; + + result = malloc(sizeof(AsyncUnit)); + if(result == NULL){ + return NULL; + } + memset(result,0,sizeof(AsyncUnit)); + result->queue = queue; + return result; +} + void* AsyncUnitSetQueueContext(pAsyncUnit unit, void* cntx) { void* hold; assert(unit); diff --git a/asyncqueue.h b/asyncqueue.h index d9223979..d91cdda2 100644 --- a/asyncqueue.h +++ b/asyncqueue.h @@ -17,6 +17,9 @@ #define AQU_RETRY_CMD -4 #define AQU_POP_CMD -5 +typedef struct __AsyncQueue AsyncQueue, *pAsyncQueue; + + /** \brief create an AsyncUnit attached to a named AsyncQueue. * * \param queueName the name of the AsyncQueue to be used @@ -24,6 +27,11 @@ * \return positive if successful */ int AsyncUnitCreate(const char* queueName, pAsyncUnit* unit); +/** \brief Get an AsyncUnit from a given AsyncQueue + * \param queue The AsyncQueue for which this AsyncUnit is valid + * \return a new AsyncUnit or NULL on error + */ +pAsyncUnit AsyncUnitFromQueue(pAsyncQueue queue); /** \brief create an AsyncUnit attached to an anonymous AsyncQueue. * diff --git a/commandlog.c b/commandlog.c index f1825126..1f315529 100644 --- a/commandlog.c +++ b/commandlog.c @@ -11,6 +11,11 @@ Added a tail facility Mark Koennecke, October 1999 + + Added compact mode: + - timestamps look different and are omitted if no other text is written + - socket number information is written on the timestamp line + --------------------------------------------------------------------------*/ #include #include @@ -34,118 +39,170 @@ /*-------------------- the tail buffer ---------------------------------*/ static pCircular pTail = NULL; #define MAXTAIL 1000 -/*----------------------------------------------------------------------*/ +#define NOID -1964 + static time_t lastStamp = 0; + static time_t iCompact = 0; static time_t tLastWrite = 0; + char *cmdPrompt=">"; + static int lastId=NOID; + + static time_t tLogfile = 0; + static time_t tStamp = 0; + static int iEnd = 1; + static int iAutoActive = 0; + static int iIntervall = 60; /*----------------------------------------------------------------------*/ - void WriteToCommandLog(char *prompt,char *text) + void WriteToCommandLogId(char *prompt, int id, char *text) { - int iNL = 0, iPos; - char *pPtr = NULL, *pCopy = NULL, *pText = NULL; - char myBuffer[1024]; + int l, iPos; + char *pPtr = NULL, *pCopy = NULL, *strippedText = text; + struct tm *nowTm; + time_t now; + char stamp1[32], stamp2[32], buffer[80]; + int doStamp, doStampId; + + /* suppress status messages */ + if (strstr(text,"status =") != NULL) { + return; + } - /* - we change the text, so we need to make a local copy. A copy - is dynamically allocated only if it does not fit into - myBuffer. - */ - if(strlen(text) > 1023){ - pCopy = (char *)malloc((strlen(text)+2)*sizeof(char)); - if(pCopy == NULL){ - return; - } - memset(pCopy,0,(strlen(text)+2)*sizeof(char)); - strcpy(pCopy,text); - pText = pCopy; - } else { - strcpy(myBuffer,text); - pText = myBuffer; - } + /* suppress TRANSACTIONFINISHED as well in order to make the WWW + commandlog work and TRANSACTIONSTART in order to make the logfiles + shorter + */ + if (strstr(text,"TRANSACTIONSTART") != NULL) { + return; + } + if (strstr(text,"TRANSACTIONFINISHED") != NULL) { + return; + } + + /* we make a local copy, stripping off the newline at the + end. We anyway need a copy later for the circular buffer */ + l = strlen(text); + pPtr = strrchr(text,'\n'); + if (pPtr != NULL && (pPtr[1]=='\0' || pPtr[2] == '\0')) { + l = pPtr - text; + } + pCopy = malloc(l+1); + if (pCopy == NULL) return; + strncpy(pCopy, text, l); + pCopy[l]='\0'; - /* figure out if we have to do a newline with pText as well */ - pPtr = strrchr(pText,'\n'); - if(pPtr != NULL) - { - iPos = pPtr - pText; - if(iPos >= (strlen(pText) - 2) ) - { - iNL = 1; - } - } + if (prompt == cmdPrompt && iCompact) { + pPtr = strstr(pCopy, "fulltransact "); + if (pPtr && pPtr < pCopy+3) { + strippedText = pPtr + 13; + } + pPtr = strstr(pCopy, "transact "); + if (pPtr && pPtr < pCopy+3) { + strippedText = pPtr + 9; + } + } - /* supress status messages */ - if(strstr(pText,"status =") != NULL) - { - if(pCopy != NULL){ - free(pCopy); - } - return; - } - - /* suppress TRANSACTIONFINISHED as well in order to make the WWW - commandlog work and TRANSACTIONSTART in order to make the logfiles - shorter - */ - if(strstr(pText,"TRANSACTIONFINISHED") != NULL || - strstr(pText,"TRANSACTIONSTART") != NULL) - { - if(pCopy != NULL){ - free(pCopy); - } - return; - } + /* create tail buffer as needed */ + if (!pTail) { + pTail = createCircular(MAXTAIL,free); + } - /* create tail buffer as needed */ - if(!pTail) - { - pTail = createCircular(MAXTAIL,free); - } + now = time(NULL); + + doStamp = 0; + doStampId = 0; + + if (id == NOID) { + if (!prompt) { + prompt=""; + } else { + snprintf(buffer, sizeof buffer, "%s ", prompt); + prompt = buffer; + } + } else if (iCompact == 0) { + if (!prompt) { + snprintf(buffer, sizeof buffer, "To sock %d : ", id); + } else { + snprintf(buffer, sizeof buffer, "sock %d>%s ", id, prompt); + } + prompt = buffer; + } else { + if (id != lastId) { + lastId = id; + doStampId = 1; + } + if (!prompt) { + prompt=""; + } else { + snprintf(buffer, sizeof buffer, "%s ", prompt); + prompt = buffer; + } + } + + if (iCompact > 0) { /* write time stamp */ + if (now/iCompact != lastStamp/iCompact) { + doStamp = 1; + doStampId = 1; + } + if (doStampId) { + lastStamp = now; + nowTm = localtime(&now); + strftime(stamp1, sizeof stamp1, "=== %H:%M:%S ===", nowTm); + if (id != NOID) { + snprintf(stamp2, sizeof stamp2, " socket %d ===", id); + } else { + stamp2[0] = '\0'; + } + } + } /* user file */ - if(fd != NULL) - { - if(iNL) - { - fprintf(fd,"%s %s",prompt, pText); - } - else - { - fprintf(fd,"%s %s\n",prompt, pText); - } + if (fd != NULL) { + if (doStampId) { + fprintf(fd,"%s %s\n", stamp1, stamp2); + } + fprintf(fd,"%s%s\n", prompt, pCopy); } + /* automatic file */ - if(fauto != NULL) - { - time(&tLastWrite); - if(iNL) - { - fprintf(fauto,"%s %s",prompt, pText); - } - else - { - fprintf(fauto,"%s %s\n",prompt, pText); - } + if (fauto != NULL) { + tLastWrite = now; + if (doStampId) { + fprintf(fauto,"%s%s\n", stamp1, stamp2); + } + fprintf(fauto,"%s%s\n", prompt, strippedText); } /* to all listening sockets. The check is necessary to resolve a shutdown problem */ - if(pServ->pTasker != NULL) - { - TaskSignal(pServ->pTasker,COMLOG,pText); + if (pServ->pTasker != NULL) { + if (doStamp) { + TaskSignal(pServ->pTasker,COMLOG,stamp1); + } + TaskSignal(pServ->pTasker,COMLOG,pCopy); } /* tail buffer */ - if(pTail != NULL) - { - if(iNL) - { - pPtr = strrchr(pText,'\n'); - *pPtr = ' '; - } - setCircular(pTail,strdup(pText)); - nextCircular(pTail); + if (pTail != NULL) { + if (doStamp) { + setCircular(pTail,strdup(stamp1)); + nextCircular(pTail); + } + setCircular(pTail,pCopy); + nextCircular(pTail); } - if(pCopy != NULL){ - free(pCopy); - } + lastId = id; + } +/*------------------------------------------------------------------------*/ + void WriteToCommandLog(char *prompt, char *text) + { + WriteToCommandLogId(prompt, NOID, text); + } +/*------------------------------------------------------------------------*/ + void WriteToCommandLogCmd(int id, char *text) + { + WriteToCommandLogId(cmdPrompt, id, text); + } +/*------------------------------------------------------------------------*/ + int CompactCommandLog(void) { + return iCompact > 0; } /*------------------------------------------------------------------------*/ static void PrintTail(int iNum, SConnection *pCon) @@ -233,9 +290,9 @@ pInst = FindVariable(pServ->pSics,"instrument"); if(pInst) { - sprintf(pBueffel,"Logfile started at instument %s at %s", + sprintf(pBueffel,"Logfile started at instrument %s at %s", pInst->text,pTime); - WriteToCommandLog("SYS>> ", pBueffel); + WriteToCommandLog("SYS>>", pBueffel); } /* if a file to execute is configured, execute it */ @@ -259,12 +316,6 @@ AutoTask puts a time stamp into the auto log file any hour and creates a new log file any 24 hours */ - static time_t tLogfile = 0; - static time_t tStamp = 0; - static int iEnd = 1; - static int iAutoActive = 0; - static int iIntervall = 60; - static int AutoTask(void *pData) { time_t tNow; @@ -296,7 +347,7 @@ if(tLogfile < 0) tLogfile = tNow + 60*60*24; } - if(tNow > tStamp) + if(tNow > tStamp && iIntervall > 0) { CLFormatTime(pTime,79); WriteToCommandLog("TIMESTAMP>> ",pTime); @@ -319,11 +370,10 @@ fflush(fauto); } - if (fauto && tLastWrite != 0 && tNow > tLastWrite) { + if (fauto && tLastWrite > 0 && tNow > tLastWrite) { fflush(fauto); tLastWrite = 0; - } - + } return iEnd; } /*----------- a command to configure the log --------------------------*/ @@ -450,15 +500,19 @@ return 0; } iIntervall = iVal; - SCSendOK(pCon); - return 1; } - else + SCPrintf(pCon,eValue,"%s.intervall [min] = %d", argv[0], iIntervall); + return 1; + } + else if(strcmp(argv[1],"compact") == 0) + { + if(argc > 2) { - sprintf(pBueffel,"autolog.intervall = %d", iIntervall); - SCWrite(pCon,pBueffel,eValue); - return 1; + iCompact = atoi(argv[2]); + if (iCompact > 0) iIntervall = 0; } + SCPrintf(pCon,eValue,"%s.compact [sec] = %d", argv[0], iCompact); + return 1; } else if(strcmp(argv[1],"close") == 0) /* close command */ { diff --git a/commandlog.h b/commandlog.h index 9e4472d3..704a264a 100644 --- a/commandlog.h +++ b/commandlog.h @@ -10,6 +10,9 @@ #ifndef COMMANDLOG #define COMMANDLOG void WriteToCommandLog(char *prompt,char *pText); + void WriteToCommandLogId(char *prompt, int id, char *text); + void WriteToCommandLogCmd(int id, char *text); + int CompactCommandLog(void); int CommandLog(SConnection *pCon, SicsInterp *pSics, void *pData, int argc, char *argv[]); diff --git a/confvirtualmot.c b/confvirtualmot.c index 55c13a73..e94fe9bd 100644 --- a/confvirtualmot.c +++ b/confvirtualmot.c @@ -335,6 +335,7 @@ static float invokeReadScript(pConfigurableVirtualMotor self, if(status != TCL_OK){ snprintf(self->scriptError,510,"ERROR: Tcl subsystem reported %s", Tcl_GetStringResult(pTcl)); + SCWrite(pCon,self->scriptError,eError); } return atof(Tcl_GetStringResult(pTcl)); } diff --git a/conman.c b/conman.c index f19c715a..e981cd39 100644 --- a/conman.c +++ b/conman.c @@ -67,8 +67,9 @@ #include "uubuffer.h" #include "commandlog.h" #include "stptok.h" +#include "statusfile.h" #include "sicshipadaba.h" - +#include "protocol.h" /* #define UUDEB 1 define UUDEB , for buffer writing for checking encoding */ @@ -79,7 +80,7 @@ extern pServer pServ; /*------ Max Size of Command Stack */ -#define MAXSTACK 100 +#define MAXSTACK 1024 /*---------- Magic ID Header */ #define CONMAGIC 26051958 /*------------------------------------------------------------------------- @@ -96,6 +97,14 @@ extern pServer pServ; static long lastIdent = 0; /*------------- sending connection (prevent double write when listening) ----*/ static SConnection *sendingConnection = NULL; +/*------------- storing connection and context for later use ----*/ + struct SCStore { + SConnection *pCon; + long ident; + int inMacro; + long macroStack; + commandContext cc; + }; /*===========================================================================*/ static char *ConName(long ident) { static char name[32]; @@ -357,6 +366,7 @@ extern pServer pServ; } assert( (iMode == 0) || (iMode == 1)); self->iMacro = iMode; +/* SCPrintf(self,eError, "SCsetMacro = %lx, %d\n", (long int)self, iMode); */ return 1; } /*---------------------------------------------------------------------------*/ @@ -383,7 +393,7 @@ extern pServer pServ; free(pVictim->pSock); pVictim->pSock = NULL; } - WriteToCommandLog("SYS> ", + WriteToCommandLog("SYS>", "ERROR: Erraneous deletion of used Connection stopped"); return; } @@ -400,7 +410,7 @@ extern pServer pServ; root = GetHipadabaRoot(); if(root != NULL) { - InternalRemoveHipadabaCallback(root,pVictim->ident); + RemoveConnectionCallbacks(root,pVictim); } /* @@ -416,7 +426,8 @@ extern pServer pServ; } /* log the kill */ - if(pVictim->pSock && pVictim->iLogin == 1) + if(pVictim->pSock && pVictim->iLogin == 1 && + (pVictim->iUserRights < 3 || !CompactCommandLog()) ) { sprintf(pBueffel,"Deleting connection %d",pVictim->pSock->sockid); WriteToCommandLog("SYS>",pBueffel); @@ -640,8 +651,10 @@ static int doSockWrite(SConnection *self, char *buffer) if(!iRet) { SCnoSock(self); - if(!self->listening && self->iLogin == 1){ - WriteToCommandLog("SYS> ","Connection broken on send"); + if(!self->listening && self->iLogin == 1 && + (self->iUserRights < 3 || !CompactCommandLog()) ) + { + WriteToCommandLog("SYS>","Connection broken on send"); } } } @@ -683,7 +696,7 @@ static void writeToLogFiles(SConnection *self, char *buffer) return 0; } - if (buffer[0] == '\0' && iOut == eFinish) { + if (buffer[0] == '\0' && iOut >= eStart && iOut <= eEvent) { return 1; /* do not write empty line */ } @@ -712,18 +725,16 @@ static void writeToLogFiles(SConnection *self, char *buffer) { if(self->iMacro != 1) { - sprintf(pBueffel,"To sock %d :",iRet); sendingConnection = self; - WriteToCommandLog(pBueffel,buffer); + WriteToCommandLogId(NULL,iRet,buffer); sendingConnection = NULL; } else { if(iOut == eError || iOut == eWarning) { - sprintf(pBueffel,"To sock %d :",iRet); sendingConnection = self; - WriteToCommandLog(pBueffel,buffer); + WriteToCommandLogId(NULL,iRet,buffer); sendingConnection = NULL; } } @@ -752,6 +763,92 @@ static void writeToLogFiles(SConnection *self, char *buffer) } return 1; } +/*--------------------------------------------------------------------------*/ + int SCACTWrite(SConnection *self, char *buffer, int iOut) + { + int i, iPtr, iRet; + char pBueffel[1024]; + char *pPtr = pBueffel; + commandContext cx; + + if(!VerifyConnection(self)) + { + return 0; + } + + if (buffer[0] == '\0' && iOut >= eStart && iOut <= eEvent) { + return 1; /* do not write empty line */ + } + + /* log it for any case */ + if(self->pSock) + { + iRet = self->pSock->sockid; + } + else + { + iRet = 0; + } + sprintf(pBueffel,"Next line intended for socket: %d",iRet); + SICSLogWrite(pBueffel,eInternal); + SICSLogWrite(buffer,iOut); + + /* write to commandlog if user or manager privilege */ + if(SCGetRights(self) <= usUser) + { + if(self->iMacro != 1) + { + sendingConnection = self; + WriteToCommandLogId(NULL,iRet,buffer); + sendingConnection = NULL; + } + else + { + if(iOut == eError || iOut == eWarning) + { + sendingConnection = self; + WriteToCommandLogId(NULL,iRet,buffer); + sendingConnection = NULL; + } + } + } + + /* + * copy in ACT + */ + if(strlen(buffer) + 30 > 1024){ + pPtr = (char *)malloc((strlen(buffer)+30)*sizeof(char)); + memset(pPtr,0,strlen(buffer)+20); + } + cx = SCGetContext(self); + sprintf(pPtr,"%d::>%s<::", cx.transID, buffer); + + /* put it into the interpreter if present */ + if(SCinMacro(self)) + { + InterpWrite(pServ->pSics,buffer); + /* print it to client if error message */ + if((iOut== eError) || (iOut == eWarning) ) + { + iRet = doSockWrite(self,pPtr); + } + } + else /* not in interpreter, normal logic */ + { + /* is this really to be printed ? */ + if(iOut < self->iOutput) + return 0; + + /* first the socket */ + iRet = doSockWrite(self,pPtr); + + writeToLogFiles(self,buffer); + } + if(pPtr != pBueffel){ + free(pPtr); + } + return 1; + } /*--------------------------------------------------------------------------*/ int SCWriteWithOutcode(SConnection *self, char *buffer, int iOut) { @@ -764,7 +861,7 @@ static void writeToLogFiles(SConnection *self, char *buffer) return 0; } - if (buffer[0] == '\0' && iOut == eFinish) { + if (buffer[0] == '\0' && iOut >= eStart && iOut <= eEvent) { return 1; /* do not write empty line */ } @@ -784,9 +881,8 @@ static void writeToLogFiles(SConnection *self, char *buffer) /* write to commandlog if user or manager privilege */ if(SCGetRights(self) <= usUser && self->iMacro != 1) { - sprintf(pBueffel,"To sock %d :",iRet); sendingConnection = self; - WriteToCommandLog(pBueffel,buffer); + WriteToCommandLogId(NULL,iRet,buffer); sendingConnection = NULL; } @@ -952,6 +1048,11 @@ pDynString SCEndBuffering(SConnection *pCon) SICSLogWrite(pBueffel,eInternal); SICSLogWrite(buffer,iOut); + /* put it into the interpreter if present */ + if(SCinMacro(self)) + { + InterpWrite(pServ->pSics,buffer); + } return 1; } /*-------------------------------------------------------------------------- @@ -968,16 +1069,40 @@ pDynString SCEndBuffering(SConnection *pCon) return 0; } - /* put into Serverlog */ - sprintf(pBueffel,"Next line intended for socket(5): %d",-10); + /* log it for any case */ + if(self->pSock) + { + iRet = self->pSock->sockid; + } + else + { + iRet = -10; + } + + /* put into Serverlog */ + sprintf(pBueffel,"Next line intended for socket: %d",iRet); SICSLogWrite(pBueffel,eInternal); + SICSLogWrite(buffer,iOut); /* write to commandlog if user or manager privilege */ - if(SCGetRights(self) <= usUser && self->iMacro != 1) + if(SCGetRights(self) <= usUser) { - sprintf(pBueffel,"To sock %d :",-10); - WriteToCommandLog(pBueffel,buffer); + if(self->iMacro != 1) + { + sendingConnection = self; + WriteToCommandLogId(NULL,iRet,buffer); + sendingConnection = NULL; + } + else + { + if(iOut == eError || iOut == eWarning) + { + sendingConnection = self; + WriteToCommandLogId(NULL,iRet,buffer); + sendingConnection = NULL; + } + } } /* put it into the interpreter if present */ @@ -1047,8 +1172,9 @@ pDynString SCEndBuffering(SConnection *pCon) int SCWriteZipped(SConnection *self, char *pName, void *pData, int iDataLen) { char outBuf[65546], *pBuf = NULL, noutBuf[ZIPBUF], *pHeader = NULL; - int compressedLength, iRet, iRet2, iCount; + int compressedLength, iRet, iRet2, iCount, protocolID; z_stream compStream; + commandContext cc; /* check for a valid connection */ if(!VerifyConnection(self)) @@ -1123,7 +1249,15 @@ pDynString SCEndBuffering(SConnection *pCon) /* write header line */ memset(outBuf,0,65536); - sprintf(outBuf,"SICSBIN ZIP %s %d\r\n",pName,compressedLength); + + protocolID = GetProtocolID(self); + if(protocolID == 5){ + cc = SCGetContext(self); + sprintf(outBuf,"SICSBIN ZIP %s %d %d\r\n",pName, + compressedLength, cc.transID); + } else { + sprintf(outBuf,"SICSBIN ZIP %s %d \r\n",pName,compressedLength); + } pHeader = strdup(outBuf); if(pHeader == NULL) { @@ -1348,8 +1482,7 @@ pDynString SCEndBuffering(SConnection *pCon) SetStatus(eOld); CostaLock(pCon->pStack); strncpy(pResult,pPtr,iLen); - sprintf(pFrom,"Prompted from sock %2.2d: ", pCon->pSock->sockid); - WriteToCommandLog(pFrom,pPtr); + WriteToCommandLogId(" prompted>", pCon->pSock->sockid, pPtr); return 1; } } @@ -1449,14 +1582,6 @@ pDynString SCEndBuffering(SConnection *pCon) /* print to command log if user or manager */ if(SCGetRights(self) <= usUser) { - if(self->pSock != NULL) - { - sprintf(pBueffel,"sock %d>>",self->pSock->sockid); - } - else - { - strcat(pBueffel,"CONT or CRON>> "); - } /* * This is a fix to suppress cron messages in the success * case @@ -1464,7 +1589,12 @@ pDynString SCEndBuffering(SConnection *pCon) if(SCGetWriteFunc(self) != SCNotWrite) { sendingConnection = self; - WriteToCommandLog(pBueffel,pCommand); + if(self->pSock != NULL) + { + WriteToCommandLogCmd(self->pSock->sockid, pCommand); + } else { + WriteToCommandLog("CRON>>",pCommand); + } sendingConnection = NULL; } } @@ -1472,7 +1602,6 @@ pDynString SCEndBuffering(SConnection *pCon) /* invoke */ self->inUse++; self->eInterrupt = eContinue; - self->parameterChange = 0; /* get first word of command */ @@ -1481,18 +1610,8 @@ pDynString SCEndBuffering(SConnection *pCon) SCAdvanceContext(self,pBueffel); iRet = InterpExecute(pInter,self,pCommand); SCPopContext(self); - if(self->parameterChange == 1) - { - /* - automatically save changed parameters - */ - pFile = IFindOption(pSICSOptions,"statusfile"); - if(pFile != NULL) - { - WriteSicsStatus(pInter,pFile,0); - self->parameterChange = 0; - } - } + StatusFileTask(NULL); /* save changed parameters */ + self->inUse--; return iRet; } @@ -1501,7 +1620,7 @@ pDynString SCEndBuffering(SConnection *pCon) config OutCode val sets an new output code config Rights User Password sets and verifies new user rights config File Filename Logs to another file - config output normal | withcode Sets output mode + config output normal | withcode | ACT Sets output mode config listen 0 | 1 enables commandlog listen mode ---------------------------------------------------------------------------*/ @@ -1509,6 +1628,7 @@ pDynString SCEndBuffering(SConnection *pCon) int argc, char *argv[]) { char pBueffel[512]; + char pHost[132]; int i, iRet; int iNum; @@ -1640,6 +1760,10 @@ pDynString SCEndBuffering(SConnection *pCon) { SCSetWriteFunc(pCon,SCWriteWithOutcode); } + else if(strcmp(argv[2],"act") == 0) + { + SCSetWriteFunc(pCon,SCACTWrite); + } else { SCWrite(pCon,"ERROT: output mode not recognised",eError); @@ -1664,10 +1788,19 @@ pDynString SCEndBuffering(SConnection *pCon) SCWrite(pCon,pBueffel,eError); return 0; } + if (CompactCommandLog()) { + if (pCon->iUserRights < 3 || i < 3) { + NETInfo(pCon->pSock,pHost,sizeof pHost); + sprintf(pBueffel,"User %s from %s switched to %d privilege", + argv[2],pHost,i); + WriteToCommandLogId("SYS>",pCon->pSock->sockid,pBueffel); + } + } else { + sprintf(pBueffel,"User %s socket %d switched to %d privilege", + argv[2],pCon->pSock->sockid,i); + WriteToCommandLog("SYS>",pBueffel); + } pCon->iUserRights = i; - sprintf(pBueffel,"User %s socket %d switched to %d privilege", - argv[2],pCon->pSock->sockid,i); - WriteToCommandLog("SYS>",pBueffel); SCWrite(pCon,"Change of Authorisation Acknowledged",eWarning); return 1; } @@ -1920,6 +2053,11 @@ pDynString SCEndBuffering(SConnection *pCon) { return 0; } + if(self->pSock->iType == 0) + { + NetReadRemove(pServ->pReader,self->pSock); + self->iEnd = 1; + } if(self->iEnd) { @@ -1987,11 +2125,21 @@ pDynString SCEndBuffering(SConnection *pCon) self->iLogin = 1; SCSetRights(self,iRet); pHost[0] = '\0'; - NETInfo(self->pSock,pHost,131); - sprintf(pBueffel,"Accepted connection %s on socket %d from %s", - ConName(self->ident), self->pSock->sockid, pHost); - SICSLogWrite(pBueffel,eInternal); - WriteToCommandLog("SYS >", pBueffel); + if (CompactCommandLog()) { + if (iRet < 3) { + NETInfo(self->pSock,pHost,131); + sprintf(pBueffel,"Accepted connection %s from %s as %s", + ConName(self->ident), pHost, pUser); + SICSLogWrite(pBueffel,eInternal); + WriteToCommandLogId("SYS>", self->pSock->sockid, pBueffel); + } + } else { + NETInfo(self->pSock,pHost,131); + sprintf(pBueffel,"Accepted connection %s on socket %d from %s", + ConName(self->ident), self->pSock->sockid, pHost); + SICSLogWrite(pBueffel,eInternal); + WriteToCommandLog("SYS >", pBueffel); + } free(pPtr); return 1; } @@ -2070,11 +2218,7 @@ pDynString SCEndBuffering(SConnection *pCon) /*-----------------------------------------------------------------------*/ void SCparChange(SConnection *self) { - if(!VerifyConnection(self)) - { - return; - } - self->parameterChange = 1; + StatusFileDirty(); } /*------------------------------------------------------------------------*/ int SCActive(SConnection *self) @@ -2093,25 +2237,75 @@ int SCActive(SConnection *self) return 0; } /*--------------------------------------------------------------------------*/ -void SCSave(SCStore *con, SConnection *pCon) { - con->pCon = pCon; - if (pCon) { - con->ident = pCon->ident; +SCStore *SCSave(SConnection *pCon, SCStore *oldStore) { + commandContext cc; + + if (oldStore == NULL) { + oldStore = calloc(1,sizeof(*oldStore)); + assert(oldStore); } + oldStore->pCon = pCon; + if (pCon) { + oldStore->ident = pCon->ident; + oldStore->inMacro = pCon->iMacro; + oldStore->cc = SCGetContext(pCon); + oldStore->macroStack = 0; + } + return oldStore; } /*--------------------------------------------------------------------------*/ -SConnection *SCLoad(SCStore *con) { - SConnection *pCon; - - pCon = con->pCon; +SConnection *SCLoad(SCStore *conStore) { + SConnection *pCon = NULL; + commandContext old; + + if (conStore) { + pCon = conStore->pCon; + } if (pCon) { - if (con->ident != pCon->ident) { - con->pCon = NULL; /* connection is dead */ + if (conStore->ident != pCon->ident) { + conStore->pCon = NULL; /* connection is dead */ pCon = NULL; } } + if (pCon) { + return pCon; + } + return pServ->dummyCon; +} +/*--------------------------------------------------------------------------*/ +SConnection *SCStorePush(SCStore *conStore) { + SConnection *pCon; + + pCon = SCLoad(conStore); + /* push macro flag on stack */ + conStore->macroStack <<= 1; + conStore->macroStack |= (pCon->iMacro != 0); + SCsetMacro(pCon, conStore->inMacro); + SCPushContext2(pCon, conStore->cc); return pCon; } +/*--------------------------------------------------------------------------*/ +void SCStorePop(SCStore *conStore) { + SConnection *pCon; + + pCon = SCLoad(conStore); + SCPopContext(pCon); + /* pop macro flag from stack + SCsetMacro(pCon,conStore->macroStack); + */ + SCsetMacro(pCon, (conStore->macroStack & 1)); + conStore->macroStack >>= 1; +} +/*--------------------------------------------------------------------------*/ +int SCStoreConnected(SCStore *conStore) { + return (conStore && + conStore->pCon && + conStore->pCon->ident == conStore->ident); +} +/*--------------------------------------------------------------------------*/ +void SCStoreFree(SCStore *conStore) { + free(conStore); +} /* --------------------------------------------------------------------------*/ long SCTagContext(SConnection *self, char *tagName) { diff --git a/conman.h b/conman.h index af9fd299..aaf0e006 100644 --- a/conman.h +++ b/conman.h @@ -58,7 +58,6 @@ typedef int (*writeFunc)(struct __SConnection *pCon, int iUserRights; int inUse; int iGrab; /* grab flag for token*/ - int parameterChange; int sicsError; /* @@ -123,6 +122,7 @@ typedef int (*writeFunc)(struct __SConnection *pCon, int SCNotWrite(SConnection *self, char *buffer, int iOut); int SCNormalWrite(SConnection *self, char *buffer, int iOut); int SCWriteWithOutcode(SConnection *self, char *buffer, int iOut); + int SCACTWrite(SConnection *self, char *buffer, int iOut); /*********************** I/O Buffering ***********************************/ int SCStartBuffering(SConnection *pCon); pDynString SCEndBuffering(SConnection *pCon); @@ -168,16 +168,25 @@ typedef int (*writeFunc)(struct __SConnection *pCon, int ConSicsAction(SConnection *pCon, SicsInterp *pSics, void *pData, int argc, char *argv[]); /******************************** Store ************************************/ -typedef struct { - SConnection *pCon; - long ident; -} SCStore; +typedef struct SCStore SCStore; -void SCSave(SCStore *con, SConnection *pCon); -/* save a connection for later use. */ +SCStore *SCSave(SConnection *pCon, SCStore *oldStore); +/* save a connection and its context for later use. */ -SConnection *SCLoad(SCStore *con); -/* check con and return SConnection if still valid or NULL otherwise. */ +SConnection *SCLoad(SCStore *conStore); +/* check con and return SConnection if still valid or a dummy connection otherwise. */ + +SConnection *SCStorePush(SCStore *conStore); +/* load connection and push stored context. Must be paired with an SCStorePop command */ + +void SCStorePop(SCStore *conStore); +/* pop context */ + +int SCStoreConnected(SCStore *conStore); +/* check if a stored connection is not closed */ + +void SCStoreFree(SCStore *conStore); +/* free an SCStore */ void KillFreeConnections(void); diff --git a/danu.c b/danu.c index 314146b5..e1978362 100644 --- a/danu.c +++ b/danu.c @@ -363,8 +363,9 @@ int NewThousand(pDataNumber self) if(SCMatchRights(pCon,usMugger)) { - DecrementDataNumber(self); - SCWrite(pCon,"Data file killed",eWarning); + iNum = DecrementDataNumber(self); + snprintf(pBueffel,511,"Data file %d killed", iNum+1); + SCWrite(pCon,pBueffel,eWarning); return 1; } else diff --git a/devexec.c b/devexec.c index 571634f8..f59ffb2b 100644 --- a/devexec.c +++ b/devexec.c @@ -103,7 +103,7 @@ void DevexecLog(char *operation, char *device) { if(devLog != NULL){ gettimeofday(&tv,&tm); fprintf(devLog, "DEVEXEC:%s:%s:%ld:%ld\n",operation,device, - tv.tv_sec, tv.tv_usec); + (long)tv.tv_sec, (long)tv.tv_usec); fflush(devLog); } } @@ -170,6 +170,7 @@ typedef struct { pICallBack pCall; time_t lastRun; int paused; + int taskRunning; } ExeList; static pExeList pExecutor = NULL; @@ -220,6 +221,7 @@ typedef struct { pRes->iLock = 0; pRes->drivePrint = 0; pRes->paused = 0; + pRes->taskRunning = 0; pRes->pCall = CreateCallBackInterface(); pRes->lastRun = time(NULL); pRes->pDes->GetInterface = DevexecInterface; @@ -650,7 +652,7 @@ static int checkInterrupt(pCheckContext pCheck, int targetStatus){ } /*--------------------------------------------------------------------------*/ static int initializeCheck(pCheckContext pCheck, pDevEntry pDev){ - int eCode; + int eCode = HWFault; SCPushContext(pCheck->self->pOwner, pDev->comCon.transID, pDev->comCon.deviceID); @@ -1364,8 +1366,20 @@ static int testFinish(pExeList self){ return 0; } - self->lastRun = time(NULL); + if(self->taskRunning == 1){ + printf("DevexecTask reentrant protection triggered\n"); + return 1; + } + /* + * CheckExeList may cause waits and thus reentrant calls to + * this. Which can cause trouble + */ + self->taskRunning = 1; iRet = CheckExeList(self); + self->taskRunning = 0; + + + self->lastRun = time(NULL); switch(iRet) { case -1: /* some problem */ @@ -1374,7 +1388,9 @@ static int testFinish(pExeList self){ { if(iInterrupt > 1) { + self->taskRunning = 1; StopExe(self,"all"); + self->taskRunning = 0; } #ifdef DEBUG printf("DevExecTask found an error\n"); diff --git a/devser.c b/devser.c new file mode 100644 index 00000000..af7da49b --- /dev/null +++ b/devser.c @@ -0,0 +1,361 @@ +#include +#include "ascon.h" +#include "devser.h" + +typedef struct DevAction { + struct DevAction *next; + void *data; + DevActionHandler *hdl; + DevPrio prio; + DevKillActionData *kill; +} DevAction; + +typedef struct SchedHeader { + struct SchedHeader *next; + DevAction *actions; /* list of actions for given interval and prio */ + DevAction *followingAction; + double interval; + double timeDue; + DevPrio prio; +} SchedHeader; + +struct DevSer { + Ascon *asyncConn; /* connection */ + DevAction *current; + int killCurrent; + DevAction *actions; /* the action queue */ + SchedHeader *headers; + ErrMsg *errmsg; + int steps; + int stopTask; +}; + +static char *devPrio[NumberOfPRIO] = { + "null", "slow", "read", "progress", "write", "halt" +}; + +char *DevPrio2Text(DevPrio prio) { + if (prio <= 0 || prio >= NumberOfPRIO) { + prio = NullPRIO; + } + return devPrio[prio]; +} + +DevPrio DevText2Prio(char *text) { + DevPrio prio; + for (prio = 0; prio < NumberOfPRIO; prio++) { + if (strcasecmp(text, devPrio[prio]) == 0) return prio; + } + return NullPRIO; +} + +static void DevFreeActionList(DevAction *actions) { + DevAction *victim; + while (actions != NULL) { + victim = actions; + actions = victim->next; + if (victim->kill != NULL) victim->kill(victim->data); + free(victim); + } +} + +static void DevKillTask(void *ds) { + DevSer *devser = ds; + + if (devser->stopTask) { + free(devser); + } else { + devser->stopTask = 1; + } +} + +DevAction *DevNextAction(DevSer *devser) { + DevPrio prio; + double now; + SchedHeader *header; + + + devser->current = NULL; + if (devser->actions) { + prio = devser->actions->prio; + } else { + prio = NullPRIO; + } + now = DoubleTime(); + for (header = devser->headers; + header != NULL && header->prio > prio; + header = header->next) { + if (header->followingAction == NULL) { + if (now >= header->timeDue) { + header->followingAction = header->actions; + if (header->interval <= 0) { + header->timeDue = now; + } else { + header->timeDue = (floor(now / header->interval) + 1) + * header->interval; + } + } + } + if (header->followingAction != NULL) { + devser->current = header->followingAction; + devser->killCurrent = 0; + header->followingAction = header->followingAction->next; + return devser->current; + } + } + if (devser->actions) { + devser->current = devser->actions; + devser->killCurrent = 1; + devser->actions = devser->actions->next; + } + return devser->current; +} + +int DevQueueTask(void *ds) { + DevSer *devser = ds; + AsconStatus status; + DevAction *action; + char *sendData; + char *replyData; + + if (devser->steps == 0) return 1; + if (devser->stopTask) { + return 0; + } + action = devser->current; + if (action == NULL) { + action = DevNextAction(devser); + } + + while (action != NULL) { + status = AsconTask(devser->asyncConn); + if (status == AsconFailure) { + devser->errmsg = AsconGetErrList(devser->asyncConn); + } else if (status != AsconReady) { + return 1; + } + if (devser->steps > 0) { /* debugging mode */ + devser->steps--; + } + if(status == AsconFailure){ + replyData = devser->errmsg->text; + } else { + replyData = AsconRead(devser->asyncConn); + } + sendData = action->hdl(action->data, replyData); + if (sendData != NULL) { + AsconWrite(devser->asyncConn, sendData, 0); + return 1; + } + if (devser->killCurrent) { + if (action->kill != NULL) action->kill(action->data); + devser->killCurrent = 0; + free(action); + devser->current = NULL; + } + action = DevNextAction(devser); + } + return 1; +} + +DevSer *DevMake(SConnection *con, int argc, char *argv[]) { + DevSer *devser = NULL; + Ascon *asyncConn = NULL; + + asyncConn = AsconMake(con, argc, argv); + if (!asyncConn) { + return NULL; + } + devser = calloc(1, sizeof(*devser)); + assert(devser); + devser->asyncConn = asyncConn; + devser->current = NULL; + devser->killCurrent = 0; + devser->actions = NULL; + devser->headers = NULL; + devser->stopTask = 0; + devser->steps = -1; /* no debugging by default */ + TaskRegister(pServ->pTasker, DevQueueTask, NULL, DevKillTask, devser, 0); + return devser; +} + +void DevDebugMode(DevSer *devser, int steps) { + devser->steps = steps; +} + +DevAction *DevNewAction(void *data, DevActionHandler hdl, + DevKillActionData *killFunc, DevPrio prio) { + DevAction *action; + action = calloc(1, sizeof(*action)); + assert(action); + action->data = data; + action->hdl = hdl; + action->kill = killFunc; + action->prio = prio; + action->next = NULL; + return action; +} + +void DevKill(DevSer *devser) { + SchedHeader *h, *victim; + + if (devser->asyncConn) { + AsconKill(devser->asyncConn); + } + DevFreeActionList(devser->actions); + h = devser->headers; + while (h != NULL) { + victim = h; + h = victim->next; + DevFreeActionList(victim->actions); + free(victim); + } + if (devser->stopTask) { + free(devser); + } else { + devser->stopTask = 1; + } +} + +void DevQueue(DevSer *devser, void *actionData, DevPrio prio, + DevActionHandler hdl, DevActionMatch *matchFunc, + DevKillActionData *killFunc) { + DevAction *action, **ptr2Last; + DevAction *new; + + if (prio <= NullPRIO) prio = NullPRIO + 1; + if (prio >= NumberOfPRIO) prio = NumberOfPRIO - 1; + ptr2Last = &devser->actions; + for (action = devser->actions; action != NULL && action->prio >= prio; action = action->next) { + if (action->hdl == hdl && matchFunc(actionData, action->data)) { + return; /* there is already an identical action */ + } + ptr2Last = &action->next; + } + new = DevNewAction(actionData, hdl, killFunc, prio); + new->next = action; + *ptr2Last = new; +} + +int DevUnschedule(DevSer *devser, void *actionData, + DevActionHandler hdl, DevActionMatch *matchFunc) { + SchedHeader *header = NULL; + DevAction **ptr2Last = NULL; + DevAction *action = NULL; + int cnt=0; + + /* scan through all headers */ + for (header = devser->headers; header != NULL; header = header->next) { + ptr2Last = &header->actions; + for (action = header->actions; action != NULL; action = *ptr2Last) { + if (action->hdl == hdl && matchFunc(actionData, action->data)) { + if (action == header->followingAction) { + /* advance followingAction if equal*/ + header->followingAction = action->next; + } + if (action == devser->current) { + devser->current = NULL; + devser->killCurrent = 0; /* should already be 0 */ + } + cnt++; + /* remove from list */ + *ptr2Last = action->next; + if (action->kill != NULL) action->kill(action->data); + free(action); + } else { + ptr2Last = &action->next; + } + } + } + return cnt; +} + +int DevSchedule(DevSer *devser, void *actionData, + DevPrio prio, double interval, + DevActionHandler hdl, DevActionMatch *matchFunc, + DevKillActionData *killFunc) { + SchedHeader *header = NULL; + SchedHeader **ptr2LastHeader = NULL; + SchedHeader *newHeader; + DevAction *action = NULL; + DevAction **ptr2Last = NULL; + DevAction *newAction; + int ret; + + if (prio <= NullPRIO) prio = NullPRIO + 1; + if (prio >= NumberOfPRIO) prio = NumberOfPRIO - 1; + ret = DevUnschedule(devser, actionData, hdl, matchFunc); + + newAction = DevNewAction(actionData, hdl, killFunc, prio); + /* find matching header */ + ptr2LastHeader = &devser->headers; + for (header = devser->headers; header != NULL; header = *ptr2LastHeader) { + if (header->prio == newAction->prio && header->interval == interval) { + /* append new action at the tail */ + ptr2Last = &header->actions; + for (action = header->actions; action != NULL; action=action->next) { + ptr2Last = &action->next; + } + *ptr2Last = newAction; + assert(newAction->next == NULL); + return ret; + } else if (header->prio < newAction->prio || + (header->prio == newAction->prio + && header->interval > interval)) { + break; + } + if (header->actions == NULL) { + /* remove empty header */ + *ptr2LastHeader = header->next; + free(header); + } else { + ptr2LastHeader = &header->next; + } + } + + /* insert new header */ + newHeader = calloc(1, sizeof(*newHeader)); + assert(newHeader); + newHeader->actions = newAction; + newHeader->followingAction = NULL; + newHeader->prio = newAction->prio; + newHeader->interval = interval; + newHeader->next = header; + newHeader->timeDue = DoubleTime() + interval; + *ptr2LastHeader = newHeader; + return ret; +} + +int DevRemoveAction(DevSer *devser, void *actionData) { + SchedHeader *header = NULL; + DevAction **ptr2Last = NULL; + DevAction *action = NULL; + int cnt=0; + + + /* Remove current action, if matched. If a reply is pending, the next action will + get the reply. But as in the inital state no reply is expected, this should not harm. */ + action = devser->current; + if (action != NULL && actionData == action->data) { + if (devser->killCurrent) { + if (action->kill != NULL) action->kill(action->data); + devser->killCurrent = 0; + free(action); + } + devser->current = NULL; + } + /* remove from queue */ + ptr2Last = &devser->actions; + for (action = devser->actions; action != NULL; action = action->next) { + if (actionData == action->data) { + cnt++; + /* remove from list */ + *ptr2Last = action->next; + if (action->kill != NULL) action->kill(action->data); + free(action); + } else { + ptr2Last = &action->next; + } + } + return cnt++; +} diff --git a/devser.h b/devser.h new file mode 100644 index 00000000..95f29a8a --- /dev/null +++ b/devser.h @@ -0,0 +1,123 @@ +#ifndef DEVSER_H +#define DEVSER_H + +/** \file + * \brief Device Serializer + */ + +typedef struct DevSer DevSer; + +/** \brief The action handler to be called + * \param actionData the data stored with the action + * \param lastReply the last reply or NULL when no command was + * sent in the last action + * \return the command to be sent or NULL if no command has to be sent + */ +typedef char *DevActionHandler(void *actionData, char *lastReply); + +/** \brief Check if an action matches the call data + * \param callData the callers data + * \param actionData the action data + * \return 1 on a match, 0 on no match + */ +typedef int DevActionMatch(void *callData, void *actionData); + +/** \brief Kill ActionData + * \param actionData action data + */ +typedef void DevKillActionData(void *actionData); + +/** \brief possible priorities. + * NullPRIO and NumberOfPRIO must not be used as priority + */ +typedef enum { + NullPRIO, SlowPRIO, ReadPRIO, ProgressPRIO, WritePRIO, HaltPRIO, NumberOfPRIO +} DevPrio; + +/** \brief Make a new device serializer and async connection. + * \param con the SICS connection (for error messages) + * \param argc the number of args for specifying the protocol + * \param argv the args + * \return the created device serializer or NULL on failure + */ +DevSer *DevMake(SConnection *con, int argc, char *argv[]); + +/** \brief put the device serializer into debug mode + * \param devser the device serializer + * \param steps the number of steps to be executed or -1 for disable debugging mode + */ +void DevDebugMode(DevSer *devser, int steps); + +/** \brief Kill the contents of the device serializer and its async connection. + * + * The data structure itself is killed at some time later + * \param devser the device serializer + */ +void DevKill(DevSer *devser); + +/** \brief Queue an action + * + * If a matching action with the same action handler + * exists already, no new action is queued. + * \param devser the device serializer + * \param actionData the action data + * \param prio the priority + * \param hdl the action handler + * \param matchFunc the match function + * \param killFunc the action data kill function (called from DevKill and + * after the action has finished, i.e. when hdl returned NULL) + * or NULL if no kill function is needed. + */ +void DevQueue(DevSer *devser, void *actionData, DevPrio prio, + DevActionHandler hdl, DevActionMatch *matchFunc, + DevKillActionData *killFunc) ; + +/** \brief Schedule a periodic action + * + * If a matching action exists already, + * it is overwritten with a possibly changed interval and priority. + * \param devser the device serializer + * \param actionData the action data + * \param prio the priority + * \param interval the interval in seconds (0 is allowed) + * \param hdl the action handler + * \param matchFunc the match function (callData must be of the same type as actionData) + * \param killFunc the action data kill function (called from DevKill and + * from DevUnschedule) or NULL if no kill function is needed. + * \return 0 when this was a new action, > 0 when an action was overwritten + */ +int DevSchedule(DevSer *devser, void *actionData, + DevPrio prio, double interval, + DevActionHandler hdl, DevActionMatch *matchFunc, + DevKillActionData *killFunc); + +/** \brief Unschedule matching actions + * \param devser the device serializer + * \param callData the callers data to be as first argument of the match function + * \param hdl the action handler + * \param matchFunc the match function (callData does not need to have the same type as actionData) + * \return the number of unscheduled actions + */ +int DevUnschedule(DevSer *devser, void *actionData, + DevActionHandler hdl, DevActionMatch *matchFunc); + +/** \brief remove action from the serializer + * \param devser the device serializer + * \param actionData the action data to be compared for a match + */ +int DevRemoveAction(DevSer *devser, void *actionData); + +/** \brief Convert integer priority to text + * \param prio + * \return text + */ +char *DevPrio2Text(DevPrio prio); + +/** \brief Convert text priority to integer + * \param text + * \return prio + */ +DevPrio DevText2Prio(char *text); + + +#endif diff --git a/diffscan.c b/diffscan.c index 22cf3b74..08fd95d3 100644 --- a/diffscan.c +++ b/diffscan.c @@ -336,7 +336,7 @@ static int DiffScanTask(void *pData){ check for interrupt */ if(SCGetInterrupt(self->scanObject->pCon) >= eAbortScan){ - pCount->pDriv->Halt(pCount->pDriv); + pCount->pCountInt->Halt(pCount); pVar->pInter->Halt(pVar->pObject); SicsWait(1); finish = 0; diff --git a/doc/user/system.htm b/doc/user/system.htm index b260aed6..7212dea5 100644 --- a/doc/user/system.htm +++ b/doc/user/system.htm @@ -66,6 +66,10 @@ above and restores SICS to the state it was in when the status was saved with read.

+restore listerr prints the list of lines which caused errors during the + last restore. +

+

killfile decrements the data number used for SICS file writing and thus consequently overwrites the last datafile. This is useful when useless data files have been created during tests. As this is diff --git a/doc/user/tasub.htm b/doc/user/tasub.htm index 9d506f5e..130cb29e 100644 --- a/doc/user/tasub.htm +++ b/doc/user/tasub.htm @@ -94,15 +94,23 @@ In order to calculate a UB matrix a list of reflections must be maintained. This This section covers the parameters and commands to use to make the module do calculations for you.

-
tasbub const ki | kf +
tasbub const ki | kf | elastic
Sets a parameter to determine if KI or KF is fixed when the energy transfer en is - being driven. Allowed values: ki, kf + being driven. Allowed values: ki, kf, elastic. In elastic mode the analyzer is + disregarded. This is useful for two circle diffractometers.
tasub const
Prints if ki or kf is fixed.
tasub ss
Prints the sample scattering sense.
tasub ss 1 | -1
Sets the sample scattering sense. Allowed values are either 1 or -1. +
tasub silent 0 | 1 +
Prints or sets the silent flag. If this is 0, the messages Driving motor .. + from .. to .. are suppressed.
+
tasub outofplane 0 | 1 +
Prints or sets the outofplane flag. If this flag is 0, the instrument will stay + in the scattering plane and not move out of it. This is here in order to protect those + bloody magnets which cannot be tilted.
tasub makeub r1 r2
Calculate a new UB matrix from the current cell constants and the entries r1 and r2 in the reflection list. r1 and r2 are integer numbers. This command will not only print the @@ -143,7 +151,7 @@ The virtual motor qm implements powder mode. In this mode, only the sampl respective positions. THis is commonly used to analyze the energy transfer of powder samples.

-There is another important command: +There are other important command:

tasub update
This command will force a recalculation of the current Q-E position for the virtual @@ -151,6 +159,9 @@ motors from angles. Normally tasub will take care of this. However, if any of th motors are moved directly or manualy, this command might be required. The SICS dr wrapper command, however, even takes care of this.
+
tasub updatetargets +
This command makes the QE targets macth the current position. This is +useful after initialization in the instrument.tcl file.

Internal Commands

diff --git a/errormsg.c b/errormsg.c new file mode 100644 index 00000000..d50cb3d6 --- /dev/null +++ b/errormsg.c @@ -0,0 +1,68 @@ +#include +#include +#include +#include +#include "errormsg.h" + +/* compare two strings for euqality, ignoring text within square brackets */ +int ErrEqual(char *str1, char *str2) { + char *p; + + while (*str1 != '\0' || *str2 != '\0') { + if (*str1 != *str2) { + return 0; + } + if (*str1 == '[') { + str1 = strchr(str1, ']'); + str2 = strchr(str2, ']'); + if (str1 == NULL || str2 == NULL) { + return str1 == str2; + } + } + str1++; + str2++; + } + return 1; +} + +ErrMsg *ErrPutMsg(ErrMsg *dump, char *fmt, ...) { + ErrMsg *m = NULL; + ErrMsg **last = NULL; + va_list ap; + char buf[256]; + char *text = NULL; + int l; + + va_start(ap, fmt); + l = vsnprintf(buf, sizeof buf, fmt, ap); + va_end(ap); + if (l < sizeof buf) { + text = buf; + } else { + /* assuming we have a C99 conforming snprintf and need a larger buffer */ + text = calloc(l, 1); + va_start(ap, fmt); + vsnprintf(text, l, fmt, ap); + va_end(ap); + } + last = &dump; + for (m = dump; m != NULL; m = m->next) { + if (ErrEqual(text, m->text)) { + *last = m->next; /* remove found item from list */ + break; + } + last = &m->next; + } + if (m == NULL) { /* make a new item */ + if (text == buf) text = strdup(buf); + m = calloc(1, sizeof(*m)); + m->text = text; + m->cnt = 1; + } else { + if (text != buf) free(text); + m->cnt++; + } + m->next = dump; + time(&m->last); + return m; +} diff --git a/errormsg.h b/errormsg.h new file mode 100644 index 00000000..470ebd5e --- /dev/null +++ b/errormsg.h @@ -0,0 +1,32 @@ +#ifndef ERRORMSG_H +#define ERRORMSG_H + +#include + +/** \file + * \brief Error message collection + */ +/** \brief Error message item + */ +typedef struct ErrMsg { + struct ErrMsg *next; + char *text; /**< the message text */ + int cnt; /**< count */ + time_t last; /**< time of last message */ +} ErrMsg; + +/** \brief Put a formatted message to the error message list + * + * The error message list contains only one entry for all messages + * with the same text, storing only the count and the last used time. + * Characters within square brackets are not taken into account + * when comparing messages. + * The new message is always at the head of the list. + * + * \param dump the error message list + * \param fmt the format for the message + * \return the new error message list head + */ +ErrMsg *ErrPutMsg(ErrMsg *dump, char *fmt, ...); + +#endif diff --git a/evcontroller.c b/evcontroller.c index b1bb0406..ba3bdc6c 100644 --- a/evcontroller.c +++ b/evcontroller.c @@ -100,7 +100,7 @@ self->start = time(NULL); self->lastt = 0; self->iWarned = 0; - SCSave(&self->conn, pCon); + self->conn = SCSave(pCon, self->conn); /* try at least three times to do it */ for(i = 0; i < 3; i++) @@ -292,9 +292,9 @@ if (self->lastt > 0) { /* increase tol for hysteresis */ tol=tol*1.1001; } + tmo = (int)(ObVal(self->pParam, SETTLE)); if(fDelta <= tol) /* inside tolerance */ { - tmo = (int)(ObVal(self->pParam, SETTLE)); if (self->lastt <= 0) /* lastt negative: -seconds already waited */ { self->lastt += now; @@ -319,9 +319,11 @@ else { if (self->lastt > 0) { /* save time already waited */ - sprintf(pBueffel,"%s outside tolerance, settling time suspended", - self->pName); - SCWrite(pCon,pBueffel,eWarning); + if (tmo > 0) { + sprintf(pBueffel,"%s outside tolerance, settling time suspended", + self->pName); + SCWrite(pCon,pBueffel,eWarning); + } self->lastt -= now; } notifyStatus(self, pCon, HWBusy); @@ -382,17 +384,15 @@ static void ErrWrite(char *txt, SCStore *conn) pExe = GetExecutor(); pCon = GetExeOwner(pExe); - if (!pCon) + if (pCon) { - pCon = SCLoad(conn); + SCWrite(pCon,txt,eWarning); } - if(pCon) - { - SCWrite(pCon,txt,eWarning); - } else { - ServerWriteGlobal(txt,eWarning); + pCon = SCStorePush(conn); + SCWrite(pCon, txt, eWarning); + SCStorePop(conn); } } /*-----------------------------------------------------------------------*/ @@ -406,7 +406,7 @@ static void ErrReport(pEVControl self) { sprintf(pBueffel,"WARNING: %s is out of range by %g", self->pName,fDelta); - ErrWrite(pBueffel, &self->conn); + ErrWrite(pBueffel, self->conn); self->iWarned = 1; } } @@ -479,7 +479,7 @@ static void ErrReport(pEVControl self) snprintf(pBueffel,255, "ERROR: %s while processing errorscript for %s", pTcl->result,self->pName); - ErrWrite(pBueffel, &self->conn); + ErrWrite(pBueffel, self->conn); } /* assume that everything is fine again after the script @@ -493,7 +493,7 @@ static void ErrReport(pEVControl self) snprintf(pBueffel,255, "ERROR: script error handling requested for %s, but no script given", self->pName); - ErrWrite(pBueffel, &self->conn); + ErrWrite(pBueffel, self->conn); } return 1; @@ -523,7 +523,7 @@ static void ErrReport(pEVControl self) ErrReport(self); - ErrWrite("Running to safe value", &self->conn); + ErrWrite("Running to safe value", self->conn); self->pDriv->SetValue(self->pDriv, ObVal(self->pParam,SAFEVALUE)); self->eMode = EVIdle; self->iWarned = 0; @@ -615,7 +615,7 @@ static void ErrReport(pEVControl self) { sprintf(pBueffel,"Environment device %s back in tolerances again", self->pName); - ErrWrite(pBueffel, &self->conn); + ErrWrite(pBueffel, self->conn); self->iWarned = 0; } return 1; @@ -796,6 +796,7 @@ static void ErrReport(pEVControl self) pRes->pName = strdup(pName); pRes->eMode = EVIdle; pRes->iWarned = 0; + pRes->conn = NULL; /* a terminal error gives a -1 in iRet */ if(iRet < 0) @@ -868,6 +869,10 @@ static void ErrReport(pEVControl self) { free(self->runScript); } + if (self->conn != NULL) + { + SCStoreFree(self->conn); + } free(self); } /*--------------------------------------------------------------------------*/ diff --git a/evcontroller.i b/evcontroller.i index d10a59f5..ad57cdbc 100644 --- a/evcontroller.i +++ b/evcontroller.i @@ -41,7 +41,7 @@ int iWarned; int iTcl; int iStop; - SCStore conn; + SCStore *conn; char *creationArgs; char *runScript; void *pPrivate; diff --git a/evcontroller.tex b/evcontroller.tex index 3514e5c8..c51b8ee5 100644 --- a/evcontroller.tex +++ b/evcontroller.tex @@ -52,13 +52,13 @@ $\langle$evdata {\footnotesize ?}$\rangle\equiv$ \mbox{}\verb@ int iWarned;@\\ \mbox{}\verb@ int iTcl;@\\ \mbox{}\verb@ int iStop;@\\ -\mbox{}\verb@ SCStore conn;@\\ +\mbox{}\verb@ SCStore *conn;@\\ \mbox{}\verb@ char *creationArgs;@\\ \mbox{}\verb@ char *runScript;@\\ \mbox{}\verb@ void *pPrivate;@\\ \mbox{}\verb@ void (*KillPrivate)(void *pData);@\\ \mbox{}\verb@ } EVControl;@\\ -\mbox{}\verb@@$\diamond$ +\mbox{}\verb@@$\Diamond$ \end{list} \vspace{-1ex} \footnotesize\addtolength{\baselineskip}{-1ex} @@ -123,7 +123,7 @@ $\langle$evdriv {\footnotesize ?}$\rangle\equiv$ \mbox{}\verb@ void *pPrivate;@\\ \mbox{}\verb@ void (*KillPrivate)(void *pData);@\\ \mbox{}\verb@ } EVDriver;@\\ -\mbox{}\verb@@$\diamond$ +\mbox{}\verb@@$\Diamond$ \end{list} \vspace{-1ex} \footnotesize\addtolength{\baselineskip}{-1ex} @@ -208,7 +208,7 @@ $\langle$dvfunc {\footnotesize ?}$\rangle\equiv$ \mbox{}\verb@ int argc, char *argv[]);@\\ \mbox{}\verb@ @\\ \mbox{}\verb@@\\ -\mbox{}\verb@@$\diamond$ +\mbox{}\verb@@$\Diamond$ \end{list} \vspace{-1ex} \footnotesize\addtolength{\baselineskip}{-1ex} @@ -286,7 +286,7 @@ See the documentation for commands understood. \mbox{}\verb@#include "varlog.h"@\\ \mbox{}\verb@@$\langle$dvfunc {\footnotesize ?}$\rangle$\verb@@\\ \mbox{}\verb@#endif@\\ -\mbox{}\verb@@$\diamond$ +\mbox{}\verb@@$\Diamond$ \end{list} \vspace{-2ex} \end{minipage}\\[4ex] @@ -315,7 +315,7 @@ See the documentation for commands understood. \mbox{}\verb@#define SETTLE 8@\\ \mbox{}\verb@@\\ \mbox{}\verb@@$\langle$evdata {\footnotesize ?}$\rangle$\verb@@\\ -\mbox{}\verb@@$\diamond$ +\mbox{}\verb@@$\Diamond$ \end{list} \vspace{-2ex} \end{minipage}\\[4ex] @@ -340,7 +340,7 @@ See the documentation for commands understood. \mbox{}\verb@/*-------------------- life & death of a driver --------------------------*/@\\ \mbox{}\verb@ pEVDriver CreateEVDriver(int argc, char *argv[]);@\\ \mbox{}\verb@ void DeleteEVDriver(pEVDriver pDriv);@\\ -\mbox{}\verb@@$\diamond$ +\mbox{}\verb@@$\Diamond$ \end{list} \vspace{-2ex} \end{minipage}\\[4ex] diff --git a/evcontroller.w b/evcontroller.w index e9e4aeb6..0146f28f 100644 --- a/evcontroller.w +++ b/evcontroller.w @@ -47,7 +47,7 @@ used by EVControl: int iWarned; int iTcl; int iStop; - SCStore conn; + SCStore *conn; char *creationArgs; char *runScript; void *pPrivate; diff --git a/event.h b/event.h index eb8f9f18..ee92c179 100644 --- a/event.h +++ b/event.h @@ -1,5 +1,5 @@ -#line 103 "event.w" +#line 100 "event.w" /*---------------------------------------------------------------------------- E V E N T @@ -14,15 +14,15 @@ #ifndef SICSEVENT #define SICSEVENT -#line 14 "event.w" +#line 13 "event.w" int Text2Event(char *pText); -#line 116 "event.w" +#line 113 "event.w" -#line 21 "event.w" +#line 20 "event.w" #define VALUECHANGE 0 #define MOTDRIVE 1 @@ -48,19 +48,20 @@ #define STSTART 21 #define STEND 22 -#line 118 "event.w" +#line 115 "event.w" /*--------------- Signals for the Signalfunction of each task ------------*/ -#line 87 "event.w" +#line 82 "event.w" #define SICSINT 300 #define SICSBROADCAST 301 #define TOKENGRAB 302 #define TOKENRELEASE 303 #define COMLOG 304 +#define CRONLIST 305 -#line 121 "event.w" +#line 118 "event.w" #endif diff --git a/event.tex b/event.tex index 5e0b5264..c3856e01 100644 --- a/event.tex +++ b/event.tex @@ -17,7 +17,7 @@ $\langle$eFunc {\footnotesize ?}$\rangle\equiv$ \begin{list}{}{} \item \mbox{}\verb@@\\ \mbox{}\verb@ int Text2Event(char *pText);@\\ -\mbox{}\verb@@$\diamond$ +\mbox{}\verb@@$\Diamond$ \end{list} \vspace{-1ex} \footnotesize\addtolength{\baselineskip}{-1ex} @@ -56,7 +56,9 @@ $\langle$VE {\footnotesize ?}$\rangle\equiv$ \mbox{}\verb@#define STATUS 18@\\ \mbox{}\verb@#define POSITION 19@\\ \mbox{}\verb@#define HDBVAL 20@\\ -\mbox{}\verb@@$\diamond$ +\mbox{}\verb@#define STSTART 21@\\ +\mbox{}\verb@#define STEND 22@\\ +\mbox{}\verb@@$\Diamond$ \end{list} \vspace{-1ex} \footnotesize\addtolength{\baselineskip}{-1ex} @@ -113,7 +115,8 @@ $\langle$VSIG {\footnotesize ?}$\rangle\equiv$ \mbox{}\verb@#define TOKENGRAB 302@\\ \mbox{}\verb@#define TOKENRELEASE 303@\\ \mbox{}\verb@#define COMLOG 304@\\ -\mbox{}\verb@@$\diamond$ +\mbox{}\verb@#define CRONLIST 305@\\ +\mbox{}\verb@@$\Diamond$ \end{list} \vspace{-1ex} \footnotesize\addtolength{\baselineskip}{-1ex} @@ -130,6 +133,7 @@ data is the string to send. \item[TOKENGRAB] A connection has successfully grabbed the control token. \item[TOKENRELEASE] A connection has released the control token. \item[COMLOG] A command log message. This is to implement listen mode to the command log. +\item[CRONLIST] Tell the cron tasks to inform about themselves. \end{description} \begin{flushleft} \small \begin{minipage}{\linewidth} \label{scrap4} @@ -156,7 +160,7 @@ data is the string to send. \mbox{}\verb@/*--------------- Signals for the Signalfunction of each task ------------*/@\\ \mbox{}\verb@@$\langle$VSIG {\footnotesize ?}$\rangle$\verb@ @\\ \mbox{}\verb@#endif@\\ -\mbox{}\verb@@$\diamond$ +\mbox{}\verb@@$\Diamond$ \end{list} \vspace{-2ex} \end{minipage}\\[4ex] diff --git a/event.w b/event.w index de1946b9..fc8e584d 100644 --- a/event.w +++ b/event.w @@ -39,6 +39,8 @@ if the event code is not known, else the apropriate event code. #define STATUS 18 #define POSITION 19 #define HDBVAL 20 +#define STSTART 21 +#define STEND 22 @} \begin{description} \item[VALUECHANGE] This is a variable changing its value. As event data a pointer to the @@ -83,6 +85,7 @@ possible codes are defined. #define TOKENGRAB 302 #define TOKENRELEASE 303 #define COMLOG 304 +#define CRONLIST 305 @} \begin{description} \item[SICSINT] An interrupt has ocurred. The signal data is the interrupt @@ -92,6 +95,7 @@ data is the string to send. \item[TOKENGRAB] A connection has successfully grabbed the control token. \item[TOKENRELEASE] A connection has released the control token. \item[COMLOG] A command log message. This is to implement listen mode to the command log. +\item[CRONLIST] Tell the cron tasks to inform about themselves. \end{description} @o event.h -d @{ /*---------------------------------------------------------------------------- diff --git a/exe.w b/exe.w index 58c62057..cd01232c 100644 --- a/exe.w +++ b/exe.w @@ -89,6 +89,19 @@ The interface to this buffer system comprises: */ int exeBufProcess(pExeBuf self, SicsInterp *pSics, SConnection *pCon, pICallBack pCall, int echo); + /** + * Process an exe buffer, but store commands causing errors in a list. + * This is used for restoring status files. + * @@param self The exe buffer to process + * @@param pSics The SICS interpreter to use for processing + * @@param pCon The connection object providing the environment for + * processing this buffer. + * @@param errCommandList A lld string list for storing commands which + * had errors. + * @@return 1 on success, 0 on error + */ + int exeBufProcessErrList(pExeBuf self, SicsInterp *pSics, + SConnection *pCon, int errCommandList); /** * retrieves the executing range * @@param self The exe buffer to query @@ -174,6 +187,9 @@ int ExeManagerWrapper(SConnection *pCon, SicsInterp *pSics, void *pData, int runExeBatchBuffer(void *pData, SConnection *pCon, SicsInterp *pSics, char *name); pDynString findBatchFile(SicsInterp *pSics, char *name); +int exeHdbBuffer(SConnection *pCon, + SicsInterp *pSics, char *name); +int exeHdbNode(pHdb exeNode, SConnection *pCon); @} @o exeman.i -d @{ diff --git a/exebuf.c b/exebuf.c index b38dfd7a..7ee47eb7 100644 --- a/exebuf.c +++ b/exebuf.c @@ -11,6 +11,7 @@ #include #include #include +#include "lld_str.h" #include "fortify.h" #include "sics.h" #include "exebuf.h" @@ -90,7 +91,9 @@ int exeBufLoad(pExeBuf self, char *filename){ return 0; } while(fgets(line,255,fd) != NULL){ - status = exeBufAppend(self,line); + /* Do not use exeBufAppend here. Lines longer than 255 would get + newline characters within the line */ + status = DynStringConcat(self->bufferContent,line); if(status != 1){ fclose(fd); return 0; @@ -166,13 +169,17 @@ int exeBufProcess(pExeBuf self, SicsInterp *pSics, self->lineno = 0; pTcl = InterpGetTcl(pSics); - InvokeCallBack(pCall,BATCHSTART,self->name); - + if(pCall != NULL){ + InvokeCallBack(pCall,BATCHSTART,self->name); + } + if (echo) { SCsetMacro(pCon,0); } while((command = findBlockEnd(self)) != NULL){ - InvokeCallBack(pCall,BATCHAREA,NULL); + if(pCall != NULL){ + InvokeCallBack(pCall,BATCHAREA,NULL); + } cmd = GetCharArray(command); if (echo) { @@ -223,7 +230,53 @@ int exeBufProcess(pExeBuf self, SicsInterp *pSics, SCSetInterrupt(pCon,eContinue); } } - InvokeCallBack(pCall,BATCHEND,self->name); + if(pCall != NULL){ + InvokeCallBack(pCall,BATCHEND,self->name); + } + return 1; +} +/*---------------------------------------------------------------------*/ +int exeBufProcessErrList(pExeBuf self, SicsInterp *pSics, + SConnection *pCon, int errList){ + pDynString command = NULL; + Tcl_Interp *pTcl = NULL; + int status; + + static int weWantLogging = 1; + char *cmd; + char cmdName[128]; + char *error; + char msg[132]; + char *ende; + int l; + + assert(self); + assert(pSics); + + self->start = 0; + self->end = -1; + self->lineno = 0; + pTcl = InterpGetTcl(pSics); + + while((command = findBlockEnd(self)) != NULL){ + cmd = GetCharArray(command); + + status = Tcl_Eval(pTcl,cmd); + if(status != TCL_OK){ + LLDstringAppend(errList,cmd); + error = (char *)Tcl_GetStringResult(pTcl); + snprintf(msg, sizeof msg, "#ERR: %s\n", error); + LLDstringAppend(errList,msg); + } + DeleteDynString(command); + if(SCGetInterrupt(pCon) >= eAbortBatch){ + SCWrite(pCon,"ERROR: batch processing interrupted",eError); + SetStatus(eEager); + return 0; + } else { + SCSetInterrupt(pCon,eContinue); + } + } return 1; } /*------------------------------------------------------------------------*/ diff --git a/exebuf.h b/exebuf.h index 026a9730..bb1edba4 100644 --- a/exebuf.h +++ b/exebuf.h @@ -1,5 +1,5 @@ -#line 210 "exe.w" +#line 226 "exe.w" /** * Buffer handling code for the Exe Buffer batch file processing @@ -63,6 +63,19 @@ */ int exeBufProcess(pExeBuf self, SicsInterp *pSics, SConnection *pCon, pICallBack pCall, int echo); + /** + * Process an exe buffer, but store commands causing errors in a list. + * This is used for restoring status files. + * @param self The exe buffer to process + * @param pSics The SICS interpreter to use for processing + * @param pCon The connection object providing the environment for + * processing this buffer. + * @param errCommandList A lld string list for storing commands which + * had errors. + * @return 1 on success, 0 on error + */ + int exeBufProcessErrList(pExeBuf self, SicsInterp *pSics, + SConnection *pCon, int errCommandList); /** * retrieves the executing range * @param self The exe buffer to query @@ -89,7 +102,7 @@ */ char *exeBufName(pExeBuf self); -#line 223 "exe.w" +#line 239 "exe.w" #endif diff --git a/exebuf.i b/exebuf.i index 62a15a24..32da477f 100644 --- a/exebuf.i +++ b/exebuf.i @@ -1,5 +1,5 @@ -#line 201 "exe.w" +#line 217 "exe.w" /*-------------------------------------------------------------------- Internal header file for the exe buffer module. Do not edit. This is @@ -16,6 +16,6 @@ typedef struct __EXEBUF{ int lineno; } ExeBuf; -#line 206 "exe.w" +#line 222 "exe.w" diff --git a/exeman.c b/exeman.c index 177c8c2f..d5415592 100644 --- a/exeman.c +++ b/exeman.c @@ -22,7 +22,9 @@ #include "exebuf.h" #include "exeman.i" #include "exeman.h" - +#include "sicshipadaba.h" +#include "commandlog.h" +#include "protocol.h" /*-------------------------------------------------------------------*/ static void KillExeMan(void *data){ pExeMan self = (pExeMan)data; @@ -252,6 +254,210 @@ static int runBatchBuffer(pExeMan self, SConnection *pCon, return status; } /*-------------------------------------------------------------------*/ +static char bufferNode[512]; + +static int SCHdbWrite(SConnection *self, char *message, int outCode){ + pHdb node = NULL; + char pBueffel[512]; + commandContext cc; + hdbValue v; + pDynString val = NULL; + writeFunc defWrite = NULL; + + + cc = SCGetContext(self); + node = GetHipadabaNode(GetHipadabaRoot(),cc.deviceID); + if(node == NULL || strstr(cc.deviceID,bufferNode) == NULL){ + /* + * this means the deviceId is wrong and the output is for another + * operation. + */ + defWrite = GetProtocolWriteFunc(self); + if(defWrite == NULL){ + defWrite = SCNormalWrite; + } + defWrite(self,message,outCode); + return 1; + } + + SCFileWrite(self,message,outCode); + + if(SCinMacro(self) && (outCode != eError && outCode != eWarning) ){ + return 1; + } + + v = MakeHdbText(strdup("")); + GetHipadabaPar(node,&v,NULL); + v.dataType = HIPTEXT; + val = CreateDynString(128,128); + if(val == NULL){ + WriteToCommandLog("INTERNAL ERROR>>", + "No memory to append to log in SCHdbWrite"); + return 0; + } + if(v.v.text != NULL){ + DynStringConcat(val,v.v.text); + if(strrchr(v.v.text,(int)'\n') == NULL && strlen(v.v.text) > 1){ + DynStringConcatChar(val,'\n'); + } + } + DynStringConcat(val,message); + if(strrchr(message,(int)'\n') == NULL && strlen(message) > 1){ + DynStringConcatChar(val,'\n'); + } + if(v.v.text != NULL){ + free(v.v.text); + } + v.v.text = GetCharArray(val); + UpdateHipadabaPar(node,v,NULL); + DeleteDynString(val); + return 1; +} +/*--------------------------------------------------------------------*/ +int exeHdbNode(pHdb exeNode, SConnection *pCon){ + char pBueffel[512], *name = NULL; + pHdb node = NULL, log = NULL; + pExeBuf buffer = NULL; + hdbValue v; + int status; + commandContext cc; + writeFunc oldWrite; + + /* + * clear log buffer + */ + log = GetHipadabaNode(exeNode,"log"); + if(log == NULL){ + SCWrite(pCon,"ERROR: Hdb node not found or in wrong format",eError); + return 0; + } + v = MakeHdbText(strdup("")); + UpdateHipadabaPar(log,v,pCon); + /* + * prepare context + */ + name = GetHipadabaPath(log); + cc = SCGetContext(pCon); + strncpy(cc.deviceID, name,255); + strncpy(bufferNode,name,511); + + /* + * load commands into buffer + */ + node = GetHipadabaNode(exeNode,"commands"); + if(node == NULL){ + SCWrite(pCon,"ERROR: Hdb node not found or in wrong format",eError); + return 0; + } + + GetHipadabaPar(node,&v,pCon); + if(v.dataType != HIPTEXT || v.v.text == NULL){ + SCWrite(pCon,"ERROR: Hdb node is of wrong type or contains no data",eError); + return 0; + + } + + buffer = exeBufCreate(name); + if(!buffer){ + SCWrite(pCon,"ERROR: out of memory creating batch buffer",eError); + return 0; + } + exeBufAppend(buffer,v.v.text); + + strncpy(bufferNode,name,511); + oldWrite = SCGetWriteFunc(pCon); + SCSetWriteFunc(pCon,SCHdbWrite); + SCPushContext2(pCon,cc); + status = exeBufProcess(buffer,pServ->pSics,pCon,NULL,0); + SCSetWriteFunc(pCon,oldWrite); + SCPopContext(pCon); + exeBufDelete(buffer); + free(name); + if(strlen(log->value.v.text) < 2){ + v = MakeHdbText(strdup("OK\n")); + UpdateHipadabaPar(log,v,pCon); + ReleaseHdbValue(&v); + } + return status; +} +/*--------------------------------------------------------------------*/ +static int runHdbBuffer(pExeMan self, SConnection *pCon, + SicsInterp *pSics, char *name){ + char pBueffel[512]; + pExeBuf buffer = NULL; + pHdb node = NULL; + hdbValue v; + int status; + commandContext cc; + writeFunc oldWrite; + + if(!SCMatchRights(pCon,usUser)) { + return 0; + } + + /* + * clear log buffer + */ + snprintf(pBueffel,511,"%s/log",name); + node = GetHipadabaNode(GetHipadabaRoot(),pBueffel); + if(node == NULL){ + SCWrite(pCon,"ERROR: Hdb node not found or in wrong format",eError); + return 0; + } + v = MakeHdbText(strdup("")); + UpdateHipadabaPar(node,v,pCon); + /* + * prepare context + */ + cc = SCGetContext(pCon); + strcpy(cc.deviceID, pBueffel); + + /* + * load commands into buffer + */ + snprintf(pBueffel,511,"%s/commands",name); + node = GetHipadabaNode(GetHipadabaRoot(),pBueffel); + if(node == NULL){ + SCWrite(pCon,"ERROR: Hdb node not found or in wrong format",eError); + return 0; + } + + GetHipadabaPar(node,&v,pCon); + if(v.dataType != HIPTEXT || v.v.text == NULL){ + SCWrite(pCon,"ERROR: Hdb node is of wrong type or contains no data",eError); + return 0; + + } + + buffer = exeBufCreate(name); + if(!buffer){ + SCWrite(pCon,"ERROR: out of memory creating batch buffer",eError); + return 0; + } + exeBufAppend(buffer,v.v.text); + + strncpy(bufferNode,name,511); + oldWrite = SCGetWriteFunc(pCon); + SCSetWriteFunc(pCon,SCHdbWrite); + SCPushContext2(pCon,cc); + self->exeStackPtr++; + DynarPut(self->exeStack,self->exeStackPtr,buffer); + status = exeBufProcess(buffer,pSics,pCon,self->pCall,self->echo); + self->exeStackPtr--; + SCSetWriteFunc(pCon,oldWrite); + SCPopContext(pCon); + return status; +} +/*--------------------------------------------------------------------*/ +int exeHdbBuffer(SConnection *pCon, + SicsInterp *pSics, char *name){ + pExeMan self = (pExeMan)FindCommandData(pSics,"exe","ExeManager"); + if(self != NULL){ + return runHdbBuffer(self,pCon,pSics,name); + } + return 0; +} +/*-------------------------------------------------------------------*/ int runExeBatchBuffer(void *pData, SConnection *pCon, SicsInterp *pSics, char *name){ int status, oldEcho; @@ -863,11 +1069,14 @@ static int printBuffer(pExeMan self, SConnection *pCon, DeleteDynString(filePath); return 0; } + DeleteDynString(filePath); + SCStartBuffering(pCon); while(fgets(pLine,511,fd) != NULL){ SCWrite(pCon,pLine,eValue); } fclose(fd); - DeleteDynString(filePath); + filePath = SCEndBuffering(pCon); + SCWrite(pCon,GetCharArray(filePath),eValue); return 1; } /*========================== run stack ===============================*/ @@ -1090,10 +1299,20 @@ int ExeManagerWrapper(SConnection *pCon, SicsInterp *pSics, void *pData, SCPrintf(pCon, eValue, "exe echo = %d", self->echo); } return 1; + }else if(strcmp(argv[1],"runhdb") == 0){ + if (argc < 2) { + SCWrite(pCon,"ERROR: require path to root of queue node",eError); + SCSendOK(pCon); + } + status = runHdbBuffer(self,pCon,pSics,argv[2]); + if(self->exeStackPtr < 0){ + SCWrite(pCon,"EXE TERMINATED",eWarning); + } + return status; } else { status = runBatchBuffer(self,pCon,pSics,pBufferName); if(self->exeStackPtr < 0){ - SCWrite(pCon,"EXE TERMINATED",eWarning); + SCWrite(pCon,"EXE TERMINATED",eWarning); } return status; } diff --git a/exeman.h b/exeman.h index 479c5087..ddee48dd 100644 --- a/exeman.h +++ b/exeman.h @@ -16,5 +16,8 @@ int ExeManagerWrapper(SConnection *pCon, SicsInterp *pSics, void *pData, int runExeBatchBuffer(void *pData, SConnection *pCon, SicsInterp *pSics, char *name); pDynString findBatchFile(SicsInterp *pSics, char *name); +int exeHdbBuffer(SConnection *pCon, + SicsInterp *pSics, char *name); +int exeHdbNode(pHdb exeNode, SConnection *pCon); #endif diff --git a/exeman.i b/exeman.i index c5436d01..8b8512fb 100644 --- a/exeman.i +++ b/exeman.i @@ -1,12 +1,12 @@ -#line 179 "exe.w" +#line 195 "exe.w" /*------------------------------------------------------------------- Internal header file for the exe manager module. Do not edit. This is automatically generated from exe.w -------------------------------------------------------------------*/ -#line 138 "exe.w" +#line 151 "exe.w" typedef struct __EXEMAN{ pObjectDescriptor pDes; @@ -20,5 +20,5 @@ typedef struct __EXEMAN{ int echo; }ExeMan, *pExeMan; -#line 184 "exe.w" +#line 200 "exe.w" diff --git a/fomerge.c b/fomerge.c index 99629336..b6dc9d20 100644 --- a/fomerge.c +++ b/fomerge.c @@ -17,6 +17,8 @@ Mark Koennecke, March 2000 extended to support nxscripted file writing: Mark Koennecke, May 2004 + + extended to support GTSE, Mark Koennecke, May 2008 --------------------------------------------------------------------------*/ #include #include @@ -27,6 +29,7 @@ #include "fortify.h" #include "scan.h" #include "fitcenter.h" +#include "sicsdata.h" static pFit fitter = NULL; @@ -594,10 +597,100 @@ static int putSum(SicsInterp *pSics, SConnection *pCon, return status; } /*---------------------------------------------------------------------*/ -static int putElastic(SicsInterp *pSics, SConnection *pCon, - pNXScript pNexus, char *alias, float fElastic) -{ +static int TOFLambda(SicsInterp *pSics, SConnection *pCon, + int argc, char *argv[]){ + int status, iTime, iDet, i; + const float *fTimeBin = NULL; + int *sum = NULL; + long *lSum = NULL; + pHistMem pMem = NULL; + float fCenter, fFWHM, fStdDev, fVal; + float fMon, fData, distMonoDet, distFermiDet, tdiff, lambda; + pMem = (pHistMem)FindCommandData(pSics,"hm1","HistMem"); + if(pMem == NULL) + { + SCWrite(pCon, + "ERROR: need lower detector bank for lambda calculation", + eError); + return 0; + } + + /** + * locate elastic position in data + */ + fTimeBin = GetHistTimeBin(pMem,&iTime); + iDet = getFMdim(LOWER); + sum = calculateTimeSum(GetHistogramPointer(pMem,pCon),iDet,iTime); + if(!sum) + { + SCWrite(pCon,"ERROR: out of memory calculating lambda", + eError); + return 0; + } + if(fitter == NULL) + { + fitter = CreateFitCenter(NULL); + if(!fitter) + { + SCWrite(pCon,"ERROR: cannot allocate fitting structure",eError); + return 0; + } + } + /* + copy sum to make compiler happy + */ + lSum = (long *)malloc(iTime*sizeof(long)); + if(lSum == NULL) + { + SCWrite(pCon,"ERROR: out of memory in TOFLambda",eError); + free(sum); + return 0; + } + for(i = 0; i < iTime; i++) + { + lSum[i] = sum[i]; + } + status = CalculateFitFromData(fitter,(float *)fTimeBin,lSum,iTime); + if(status < 0) + { + SCWrite(pCon,"ERROR: no peak in data",eError); + free(sum); + free(lSum); + return 0; + } + GetFitResults(fitter,&fCenter,&fStdDev,&fFWHM,&fVal); + fData = fCenter; + + /* + * locate elastic position in tofmon + */ + GetHistogram(pMem, pCon, 0, iTime*iDet, iTime*(iDet+1), + sum, iTime*sizeof(HistInt)); + for(i = 0; i < iTime; i++) + { + lSum[i] = sum[i]; + } + status = CalculateFitFromData(fitter,(float *)fTimeBin,lSum,iTime); + GetFitResults(fitter,&fCenter,&fStdDev,&fFWHM,&fVal); + fMon = fCenter; + free(sum); + free(lSum); + + /* + * calculate + */ + distFermiDet = 3000.; + distMonoDet = distFermiDet - 215.7; + tdiff = fData - fMon; + lambda = tdiff/(252.78*distMonoDet*.001); + SCPrintf(pCon,eValue, "toflambda = %f", lambda); + + return 1; +} +/*---------------------------------------------------------------------*/ +static float calcElastic(SicsInterp *pSics, SConnection *pCon) +{ int status, iTime, iDet, i; const float *fTimeBin = NULL; int *sum = NULL; @@ -611,7 +704,7 @@ static int putElastic(SicsInterp *pSics, SConnection *pCon, SCWrite(pCon, "ERROR: need middle detector bank for elastic peak calculation", eError); - return NX_ERROR; + return -1.; } fTimeBin = GetHistTimeBin(pMem,&iTime); iDet = getFMdim(MIDDLE); @@ -620,7 +713,7 @@ static int putElastic(SicsInterp *pSics, SConnection *pCon, { SCWrite(pCon,"ERROR: out of memory calculating elastic peak position", eError); - return NX_ERROR; + return -1; } if(fitter == NULL) { @@ -628,7 +721,7 @@ static int putElastic(SicsInterp *pSics, SConnection *pCon, if(!fitter) { SCWrite(pCon,"ERROR: cannot allocate fitting structure",eError); - return NX_ERROR; + return -1.; } } /* @@ -639,7 +732,7 @@ static int putElastic(SicsInterp *pSics, SConnection *pCon, { SCWrite(pCon,"ERROR: out of memory in putElastic",eError); free(sum); - return NX_ERROR; + return -1.; } for(i = 0; i < iTime; i++) { @@ -647,38 +740,180 @@ static int putElastic(SicsInterp *pSics, SConnection *pCon, } status = CalculateFitFromData(fitter,(float *)fTimeBin,lSum,iTime); free(lSum); - if(status != 1) - { - SCWrite(pCon,"WARNING: problem locating elastic peak",eWarning); - } GetFitResults(fitter,&fCenter,&fStdDev,&fFWHM,&fVal); - fVal = fCenter - fElastic; - if(fVal < 0.) - fVal = - fVal; - /* bad value, leave at theoretical value */ - if(fVal > 10.) - { - SCWrite(pCon, - "WARNING: bad fit result, using theoretical elastic peak position", - eWarning); - } - else - { - fElastic = fCenter; - } free(sum); - - status = NXDputalias(pNexus->fileHandle, pNexus->dictHandle,alias, - &fElastic); - return status; + return fCenter; +} +/*---------------------------------------------------------------------*/ +#define ABS(x) (x < 0 ? -(x) : (x)) +static int putElastic(SicsInterp *pSics, SConnection *pCon, + pNXScript pNexus, char *alias, float fElastic) +{ + float fCalc; + int status; + + fCalc = calcElastic(pSics,pCon); + if(ABS(fElastic -fCalc) < 20) { + fElastic = fCalc; + } + + status = NXDputalias(pNexus->fileHandle, pNexus->dictHandle,alias, + &fElastic); + return status; +} +/*----------------------------------------------------------------------*/ +static int FMputTTH(SConnection *pCon, int argc, char *argv[]){ + pSICSData data = NULL; + int length = -1, i; + float *tthData = NULL; + + if(argc < 4){ + SCWrite(pCon,"ERROR: insufficient no of arguments to FMputTTH", + eError); + return 0; + } + + data = (pSICSData)FindCommandData(pServ->pSics,argv[3],"SICSData"); + if(data == NULL){ + SCWrite(pCon,"ERROR: SICSData object not found", eError); + return 0; + } + if(strcmp(argv[2],"upper") == 0) + { + length = getFMdim(UPPER); + tthData = getFMBankTheta(UPPER); + } + else if(strcmp(argv[2],"middle") == 0) + { + length = getFMdim(MIDDLE); + tthData = getFMBankTheta(MIDDLE); + } + else if(strcmp(argv[2],"lower") == 0) + { + length = getFMdim(LOWER); + tthData = getFMBankTheta(LOWER); + } + else if(strcmp(argv[2],"merged") == 0) + { + length = getFMdim(MERGED); + tthData = getFMBankTheta(MERGED); + } + else + { + SCWrite(pCon,"ERROR: requested two_theta for invalid detector bank", + eError); + return 0; + } + if(length < 0 || tthData == NULL){ + SCWrite(pCon,"ERROR: requested two_theta for invalid detector bank", + eError); + return 0; + } + clearSICSData(data); + for(i = 0; i < length; i++){ + setSICSDataFloat(data,i,tthData[i]); + } + SCSendOK(pCon); + return 1; +} +/*---------------------------------------------------------------------*/ +static int FMcopyMerged(SConnection *pCon, int argc, char *argv[]){ + pSICSData data = NULL; + int i, length; + HistInt *hmData = NULL; + + if(argc < 3){ + SCWrite(pCon,"ERROR: insufficient no of arguments to FMcopyMerged", + eError); + return 0; + } + + data = (pSICSData)FindCommandData(pServ->pSics,argv[2],"SICSData"); + if(data == NULL){ + SCWrite(pCon,"ERROR: SICSData object not found", eError); + return 0; + } + if(!updateHMFMData(pServ->pSics, pCon)){ + SCWrite(pCon,"ERROR: not enough HM's to merge or bad names in fomerge.c", + eError); + return 0; + } + + clearSICSData(data); + length = getFMdim(MERGED)*getFMdim(TIMEBIN); + hmData = getFMBankPointer(MERGED); + if(hmData == NULL){ + SCWrite(pCon,"ERROR: merged data not available", eError); + return 0; + } + for(i = 0; i < length; i++){ + setSICSDataInt(data,i,hmData[i]); + } + SCSendOK(pCon); + return 1; +} +/*---------------------------------------------------------------------*/ +static int FMcopyMergedSum(SConnection *pCon, int argc, char *argv[]){ + pSICSData data = NULL; + int i, length, tbin, j, row; + HistInt *hmData = NULL, *sumData = NULL; + + if(argc < 3){ + SCWrite(pCon,"ERROR: insufficient no of arguments to FMcopyMerged", + eError); + return 0; + } + + data = (pSICSData)FindCommandData(pServ->pSics,argv[2],"SICSData"); + if(data == NULL){ + SCWrite(pCon,"ERROR: SICSData object not found", eError); + return 0; + } + if(!updateHMFMData(pServ->pSics, pCon)){ + SCWrite(pCon,"ERROR: not enough HM's to merge or bad names in fomerge.c", + eError); + return 0; + } + + clearSICSData(data); + length = getFMdim(MERGED); + tbin = getFMdim(TIMEBIN); + hmData = getFMBankPointer(MERGED); + if(hmData == NULL){ + SCWrite(pCon,"ERROR: merged data not available", eError); + return 0; + } + sumData = malloc(tbin*sizeof(int)); + if(sumData == NULL){ + SCWrite(pCon,"ERROR: out-of-memory in FMcopyMergedSum", eError); + return 0; + } + memset(sumData,0,tbin*sizeof(int)); + for(j = 0; j < length; j++){ + row = j*tbin; + for(i = 0; i < tbin; i++){ + sumData[i] += hmData[row+i]; + } + } + for(i = 0; i < tbin; i++){ + setSICSDataInt(data,i,sumData[i]); + } + free(sumData); + SCSendOK(pCon); + return 1; } /*----------------------------------------------------------------------- Usage: focusmerge puttwotheta nxscriptmod bankname alias + focusmerge puttth bankname sicsdataname + focusmerge copymerged sicsdataname + focusmerge copymergedsum sicsdataname focusmerge putmerged nxscriptmod alias focusmerge putsum nxscriptmod bankname alias focusmerge putelastic nxscriptmod alias theoelastic + focusmerge toflambda + focusmerge elastic nxscriptmod = name of the nxscript module used for writing, must be open alias = The alias under which to write the data item @@ -700,6 +935,26 @@ int FocusMergeAction(SConnection *pCon, SicsInterp *pSics, void *pData, } strtolower(argv[1]); + + if(strcmp(argv[1],"puttth") == 0){ + return FMputTTH(pCon,argc,argv); + } + + if(strcmp(argv[1],"copymerged") == 0){ + return FMcopyMerged(pCon,argc,argv); + } + if(strcmp(argv[1],"copymergedsum") == 0){ + return FMcopyMergedSum(pCon,argc,argv); + } + if(strcmp(argv[1],"toflambda") == 0){ + return TOFLambda(pSics, pCon,argc,argv); + } + if(strcmp(argv[1],"elastic") == 0){ + fElastic = calcElastic(pSics,pCon); + SCPrintf(pCon,eValue,"tofelastic = %f", fElastic); + return 1; + } + if(strcmp(argv[1],"puttwotheta") == 0) { if(argc < 4) diff --git a/genericcontroller.c b/genericcontroller.c new file mode 100644 index 00000000..75586942 --- /dev/null +++ b/genericcontroller.c @@ -0,0 +1,622 @@ +/** + * This is a generic controller for devices in SICS. It is configurable via Tcl + * scripts. + * + * copyright: see file COPYRIGHT + * + * Mark Koennecke, November 2007 + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +/*--------------------------------------------------------------------------*/ +static hdbCallbackReturn GenConSetCallback(pHdb node, void *userData, + pHdbMessage message){ + pSICSOBJ self = (pSICSOBJ)userData; + SConnection *pCon = NULL; + pGenController priv = NULL; + char command[1024]; + char value[80]; + int status, privilege; + pDynString data; + pHdbDataMessage mm = NULL; + + assert(self != NULL); + + if((mm = GetHdbSetMessage(message)) == NULL){ + return hdbContinue; + } + + priv = (pGenController)self->pPrivate; + pCon = mm->callData; + + /* + * check rights + */ + memset(value,0,80); + if(GetHdbProperty(node,"priv",value,80) && pCon != NULL){ + privilege = usInternal; + if(strcmp(value,"manager") == 0){ + privilege = usMugger; + } + if(strcmp(value,"user") == 0){ + privilege = usUser; + } + if(!SCMatchRights(pCon,privilege)){ + return hdbAbort; + } + } + + /* + * check writeCommand + */ + memset(value,0,80); + GetHdbProperty(node,"writeCommand",value,80); + if(strlen(value) < 2){ + if(pCon != NULL){ + SCWrite(pCon,"ERROR: parameter is read-only",eError); + return hdbAbort; + } + return hdbAbort; + } + + /* + * check status + */ + memset(value,0,80); + GetHdbProperty(node,"status",value,80); + if(strstr(value,"idle") == NULL){ + return hdbAbort; + } + SetHdbProperty(node,"status","setting"); + data = formatValue(*(mm->v), node); + if(data != NULL){ + SetHdbProperty(node,"target",GetCharArray(data)); + DeleteDynString(data); + } + + /* + * issue command + */ + if(priv->enqueueNodeHead != NULL){ + priv->enqueueNodeHead(self,pCon,node); + } else { + if(pCon != NULL){ + SCWrite(pCon,"ERROR: generic controller NOT configured", + eError); + } + return hdbAbort; + } + + return hdbContinue; +} +/*--------------------------------------------------------------------------*/ +static hdbCallbackReturn GenConGetCallback(pHdb node, void *userData, + pHdbMessage message){ + pSICSOBJ self = (pSICSOBJ)userData; + SConnection *pCon = NULL; + pGenController priv = NULL; + char command[1024]; + char value[256]; + int status, privilege; + pHdbDataMessage mm = NULL; + + assert(self != NULL); + + if((mm = GetHdbGetMessage(message)) == NULL){ + return hdbContinue; + } + pCon = mm->callData; + + priv = (pGenController)self->pPrivate; + + /* + * check status + */ + memset(value,0,80); + GetHdbProperty(node,"status",value,80); + if(strstr(value,"idle") == NULL){ + return hdbContinue; + } + SetHdbProperty(node,"status","getting"); + + /* + * check readCommand + */ + memset(value,0,256); + GetHdbProperty(node,"readCommand",value,255); + if(strlen(value) < 2){ + return hdbAbort; + } else { + if(priv->enqueueNode != NULL){ + priv->enqueueNode(self,pCon, node); + } else { + if(pCon != NULL){ + SCWrite(pCon,"ERROR: generic controller connection NOT configured", + eError); + } + return hdbAbort; + } + } + + /* + * Upper Level GetHipadabaPar will automatically return the + * node value. Which should have been updated through an update + * during the execution of enqueueNode + */ + + return hdbContinue; +} +/*---------------------------------------------------------------------------*/ +static pHdb MakeGenConPar(pSICSOBJ self, char *name, int type, int length){ + pHdb result = NULL; + pHdbCallback kalle = NULL; + + result = MakeHipadabaNode(name,type,length); + if(result == NULL){ + return NULL; + } + + kalle = MakeHipadabaCallback(GenConSetCallback, + self, + NULL); + if(kalle == NULL){ + return NULL; + } + AppendHipadabaCallback(result,kalle); + + kalle = MakeHipadabaCallback(GenConGetCallback, + self, + NULL); + + if(kalle == NULL){ + return NULL; + } + AppendHipadabaCallback(result,kalle); + + SetHdbProperty(result,"priv","manager"); + SetHdbProperty(result,"readCommand",""); + SetHdbProperty(result,"writeCommand",""); + SetHdbProperty(result,"replyCommand",""); + SetHdbProperty(result,"status","idle"); + + return result; +} +/*---------------------------------------------------------------------------*/ +static int MakeGenPar(pSICSOBJ self, SConnection *pCon, + char *argv[], int argc){ + char buffer[2048]; + int type, length = 1; + pHdb node = NULL , parent; + char *pPtr = NULL; + + if(argc < 5){ + snprintf(buffer,2048,"ERROR: insufficient arguments to %s makepar", + argv[0]); + SCWrite(pCon,buffer, eError); + return 0; + } + type = convertHdbType(argv[4]); + if(argc > 5){ + length = atoi(argv[5]); + } + strncpy(buffer,argv[3],2047); + pPtr = strrchr(buffer,'/'); + if(pPtr == NULL){ + node = MakeGenConPar(self, argv[3], type, length); + parent = self->objectNode; + } else { + *pPtr = '\0'; + pPtr++; + node = MakeGenConPar(self, pPtr, type, length); + parent = GetHipadabaNode(self->objectNode,buffer); + } + if(node == NULL || parent == NULL){ + SCWrite(pCon,"ERROR: failed to create node or parent not found", + eError); + return 0; + } + AddHipadabaChild(parent, node, pCon); + SCSendOK(pCon); + return 1; +} +/*=============================== ========================================== + * This stuff is for the Tcl - AsynQueue implementation of GenericController + * ==========================================================================*/ + typedef struct { + pHdb node; + pSICSOBJ obj; + SConnection *pCon; + pGenController priv; + pAsyncUnit assi; + pAsyncTxn trans; + commandContext comCon; + char replyCommand[2048]; + } GenContext, *pGenContext; + /*-------------------------------------------------------------------------- + * This is called by AsyncQueue when a reply has been received. + * -------------------------------------------------------------------------*/ + static int GenConTxnHandler(pAsyncTxn pTxn){ + pGenContext genCon = NULL; + char reply[10240]; + + genCon = (pGenContext)pTxn->cntx; + assert(genCon != NULL); + + memset(reply,0,10240*sizeof(char)); + switch(pTxn->txn_state){ + case ATX_NULL: + case ATX_ACTIVE: + return 1; + break; + case ATX_TIMEOUT: + strcpy(reply,"TIMEOUT"); + break; + case ATX_DISCO: + strcpy(reply,"DISCONNECTED"); + break; + case ATX_COMPLETE: + strncpy(reply,pTxn->inp_buf,10240); + break; + } + + if(genCon->pCon != NULL){ + SCPushContext2(genCon->pCon, genCon->comCon); + } + genCon->priv->replyCallback(genCon->obj, genCon->pCon, + genCon->node, genCon->replyCommand, reply, strlen(reply)); + if(genCon->pCon != NULL){ + SCPopContext(genCon->pCon); + } + free(genCon); + + return 1; + } +/*--------------------------------------------------------------------------*/ +static char *formatCommand(pHdb node, SConnection *pCon){ + pDynString com = NULL; + char value[512]; + Tcl_Interp *pTcl = NULL; + int status; + + com = CreateDynString(256,128); + if(com == NULL){ + return NULL; + } + + memset(value,0,512); + GetHdbProperty(node,"status",value,512); + if(strstr(value,"set") != NULL){ + memset(value,0,512); + GetHdbProperty(node,"writeCommand",value,512); + DynStringConcat(com,value); + DynStringConcatChar(com,' '); + memset(value,0,512); + GetHdbProperty(node,"target",value,512); + DynStringConcat(com,value); + } else { + memset(value,0,512); + GetHdbProperty(node,"readCommand",value,512); + DynStringConcat(com,value); + } + pTcl = InterpGetTcl(pServ->pSics); + if(pCon != NULL){ + MacroPush(pCon); + } + status = Tcl_Eval(pTcl, GetCharArray(com)); + if(pCon != NULL){ + MacroPop(); + } + DeleteDynString(com); + if(status != TCL_OK){ + SetHdbProperty(node,"result", (char *)Tcl_GetStringResult(pTcl)); + return NULL; + } + return strdup(Tcl_GetStringResult(pTcl)); +} +/*--------------------------------------------------------------------------*/ +static pGenContext PrepareToEnque(pSICSOBJ self, SConnection *pCon, pHdb node){ + pGenContext result = NULL; + char *command = NULL; + pGenController priv = NULL; + + priv = (pGenController)self->pPrivate; + assert(priv != NULL); + + command = formatCommand(node, pCon); + if(command == NULL){ + return NULL; + } + + result = malloc(sizeof(GenContext)); + if(result == NULL){ + return NULL; + } + memset(result,0,sizeof(GenContext)); + if(!GetHdbProperty(node,"replyCommand",result->replyCommand,2048)){ + if(pCon != NULL){ + SCWrite(pCon,"ERROR: no replyCommand found",eError); + } + free(result); + return NULL; + } + + result->assi = AsyncUnitFromQueue((pAsyncQueue)priv->comContext); + if(result->assi == NULL){ + return NULL; + } + result->trans = AsyncUnitPrepareTxn(result->assi, + command,strlen(command), + GenConTxnHandler, + result, + 2048); + if(result->trans == NULL){ + return NULL; + } + result->node = node; + result->priv = priv; + result->obj = self; + result->pCon = pCon; + priv->comError = GCOK; + result->comCon = SCGetContext(pCon); + free(command); + + return result; +} +/*---------------------------------------------------------------------------*/ +static int AsyncEnqueueNode(pSICSOBJ self, SConnection *pCon, pHdb node){ + pGenContext genCon = NULL; + + genCon = PrepareToEnque(self, pCon, node); + if(genCon == NULL){ + return 0; + } + return AsyncUnitEnqueueTxn(genCon->assi, genCon->trans); +} +/*---------------------------------------------------------------------------*/ +static int AsyncEnqueueNodeHead(pSICSOBJ self, SConnection *pCon, pHdb node){ + pGenContext genCon = NULL; + + genCon = PrepareToEnque(self, pCon, node); + if(genCon == NULL){ + return 0; + } + return AsyncUnitEnqueueHead(genCon->assi, genCon->trans); +} +/*---------------------------------------------------------------------------*/ +static int AsyncReply(pSICSOBJ self, SConnection *pCon, pHdb node, + char *replyCommand, char *reply, int replylen){ + pDynString com = NULL; + Tcl_Interp *pTcl; + int status; + + SetHdbProperty(node,"result",reply); + + com = CreateDynString(256,128); + if(com == NULL){ + return 0; + } + DynStringConcat(com, replyCommand); + DynStringConcat(com," \""); + DynStringConcat(com, reply); + DynStringConcat(com,"\"\0"); + if(pCon != NULL){ + MacroPush(pCon); + } + pTcl = InterpGetTcl(pServ->pSics); + status = Tcl_Eval(pTcl,GetCharArray(com)); + if(pCon != NULL){ + MacroPop(); + } + DeleteDynString(com); + if(status != TCL_OK){ + SetHdbProperty(node,"lastError",(char *)Tcl_GetStringResult(pTcl)); + } + return status; +} +/*============= GenController Object Functions ==============================*/ +static int ConnectAsync(pSICSOBJ self, SConnection *pCon, + char *argv[], int argc){ + pGenController priv = NULL; + pAsyncQueue assi = NULL; + char buffer[2048]; + pAsyncUnit uni = NULL; + + priv = (pGenController)self->pPrivate; + assert(priv != NULL); + + if(argc < 4){ + snprintf(buffer,2048,"ERROR: insufficient arguments to %s asynconnect", + argv[0]); + SCWrite(pCon,buffer, eError); + return 0; + } + + assi = (pAsyncQueue)FindCommandData(pServ->pSics, argv[3],"AsyncQueue"); + if(assi == NULL){ + snprintf(buffer,2048,"ERROR: %s not found or no AsyncQueue", argv[3]); + SCWrite(pCon,buffer,eError); + return 0; + } + + priv->comContext = assi; + priv->killComContext = NULL; /* not ours, cleaned up by AsyncQueue module */ + priv->enqueueNode = AsyncEnqueueNode; + priv->enqueueNodeHead = AsyncEnqueueNodeHead; + priv->replyCallback = AsyncReply; + priv->comError = GCOK; + + /* + * This unit is solely for the purpose of receiving event notifications + */ + uni = AsyncUnitFromQueue(assi); + + SCSendOK(pCon); + return 1; +} +/*---------------------------------------------------------------------------*/ +int GenControllerConfigure(SConnection *pCon, SicsInterp *pSics, + void *pData, int argc, char *argv[]){ + pSICSOBJ controller = NULL; + pGenController self = NULL; + char buffer[2048]; + + if(argc < 3){ + snprintf(buffer,2048,"ERROR: insufficient arguments to %s", argv[0]); + SCWrite(pCon,buffer,eError); + return 0; + } + + controller = (pSICSOBJ)FindCommandData(pSics,argv[2], "GenericController"); + if(controller == NULL){ + snprintf(buffer,2048,"ERROR: controller %s not found", argv[2]); + SCWrite(pCon,buffer,eError); + return 0; + } + + strtolower(argv[1]); + if(strcmp(argv[1],"makepar") == 0){ + return MakeGenPar(controller,pCon,argv,argc); + } else if(strcmp(argv[1],"asynconnect") == 0){ + return ConnectAsync(controller, pCon, argv, argc); + } else { + SCWrite(pCon,"ERROR: argument to GenControllerConfigure not found", + eError); + return 0; + } + + return 1; +} +/*---------------------------------------------------------------------------*/ +static void killGeneric(void *data){ + pGenController self = (pGenController)data; + + if(self == NULL){ + return; + } + if(self->comContext != NULL && self->killComContext != NULL){ + self->killComContext(self->comContext); + } + free(self); +} +/*---------------------------------------------------------------------------*/ +static int EnqueFunc(pSICSOBJ self, SConnection *pCon, pHdb commandNode, + pHdb par[], int nPar){ + pGenController priv = NULL; + pHdb node = NULL; + char buffer[512]; + + priv = (pGenController)self->pPrivate; + assert(priv != NULL); + assert(nPar >= 1); + + node = GetHipadabaNode(self->objectNode,par[0]->value.v.text); + if(node == NULL){ + snprintf(buffer,511,"ERROR: node %s to enqueue not found", + par[0]->value.v.text); + SCWrite(pCon,buffer,eError); + return 0; + } + + if(priv->enqueueNode != NULL){ + priv->enqueueNode(self, pCon, node); + } else { + SCWrite(pCon,"ERROR: GenController NOT configured",eError); + return 0; + } + return 1; +} +/*---------------------------------------------------------------------------*/ +static int EnqueHeadFunc(pSICSOBJ self, SConnection *pCon, Hdb commandNode, + pHdb par[], int nPar){ + pGenController priv = NULL; + pHdb node = NULL; + char buffer[512]; + + priv = (pGenController)self->pPrivate; + assert(priv != NULL); + assert(nPar >= 1); + + node = GetHipadabaNode(self->objectNode,par[0]->value.v.text); + if(node == NULL){ + snprintf(buffer,511,"ERROR: node %s to enqueue not found", + par[0]->value.v.text); + SCWrite(pCon,buffer,eError); + return 0; + } + + if(priv->enqueueNodeHead != NULL){ + priv->enqueueNodeHead(self, pCon, node); + } else { + SCWrite(pCon,"ERROR: GenController NOT configured",eError); + return 0; + } + return 1; +} +/*---------------------------------------------------------------------------*/ +int GenControllerFactory(SConnection *pCon, SicsInterp *pSics, + void *pData, int argc, char *argv[]){ + pSICSOBJ pNew = NULL; + pGenController priv = NULL; + hdbValue funcValue, textValue; + pHdb node = NULL; + char line[132]; + int status; + + if(argc < 2){ + SCWrite(pCon, + "ERROR: insufficient number of arguments to GenControllerFactrory", + eError); + return 0; + } + priv = malloc(sizeof(GenController)); + if(priv == NULL){ + SCWrite(pCon,"ERROR: out of memory in GenControllerFactory", + eError); + return 0; + } + memset(priv,0,sizeof(GenController)); + + pNew = MakeSICSOBJ(argv[1],"GenericController"); + if(pNew == NULL){ + SCWrite(pCon,"ERROR: out of memory in GenControllerFactory", + eError); + return 0; + } + pNew->pPrivate = priv; + pNew->KillPrivate = killGeneric; + + textValue = MakeHdbText("Undefined"); + funcValue = MakeHdbFunc((voidFunc *)EnqueFunc); + node = MakeSICSHdbPar("enqueue",usUser, funcValue); + AddSICSHdbPar(node,"node",usUser,textValue); + AppendHipadabaCallback(node,MakeSICSFuncCallback(pNew)); + AddHipadabaChild(pNew->objectNode,node,NULL); + + funcValue = MakeHdbFunc((voidFunc *)EnqueHeadFunc); + node = MakeSICSHdbPar("enqueuehead",usUser, funcValue); + AddSICSHdbPar(node,"node",usUser,textValue); + AppendHipadabaCallback(node,MakeSICSFuncCallback(pNew)); + AddHipadabaChild(pNew->objectNode,node,NULL); + + status = AddCommand(pSics, + argv[1], + InvokeSICSOBJ, + KillSICSOBJ, + pNew); + if(status != 1){ + KillSICSOBJ(pNew); + SCPrintf(pCon,eError,"ERROR: failed create duplicate command %s", argv[1]); + return 0; + } + SCSendOK(pCon); + + return 1; +} + diff --git a/genericcontroller.h b/genericcontroller.h new file mode 100644 index 00000000..2ba805a7 --- /dev/null +++ b/genericcontroller.h @@ -0,0 +1,37 @@ +/** + * This is a generic controller for devices in SICS. In its default configuration it + * will be configurable via Tcl scripts and used AsynqQueue for communication. But + * it is suitably generic to support other mechanisms as well. + * + * copyright: see file COPYRIGHT + * + * Mark Koennecke, November 2007 + */ +#ifndef GENERICCONTROLLER_H_ +#define GENERICCONTROLLER_H_ +#include +#include + +#define GCTIMEOUT 5001 +#define GCDISCONNECT 5002 +#define GCOK 5000 +#define GCRECONNECT 5003 +#define GCRETRY 5004 + +typedef struct { + int (*enqueueNode)(pSICSOBJ self, SConnection *pCon, pHdb node); + int (*enqueueNodeHead)(pSICSOBJ self, SConnection *pCon, pHdb node); + int (*replyCallback)(pSICSOBJ self, SConnection *pCon, pHdb node, + char *replyCommand, char *reply, int replylen); + void *comContext; + void (*killComContext)(void *data); + int comError; +}GenController, *pGenController; +/*---------------------------------------------------------------------------*/ +int GenControllerFactory(SConnection *pCon, SicsInterp *pSics, + void *pData, int argc, char *argv[]); +/*---------------------------------------------------------------------------*/ +int GenControllerConfigure(SConnection *pCon, SicsInterp *pSics, + void *pData, int argc, char *argv[]); + +#endif /*GENERICCONTROLLER_H_*/ diff --git a/geninter.c b/geninter.c new file mode 100644 index 00000000..0567494b --- /dev/null +++ b/geninter.c @@ -0,0 +1,19 @@ +/** + * This is the implementation of various SICS internal interfaces based on + * parameters in a generic controller. + * + * copyright: see file COPYRIGHT + * + * Mark Koennecke, November 2007 + */ +#include +#include +#include +#include + +/*---------------------------------------------------------------------------*/ +int GenDrivableFactory(SConnection *pCon, SicsInterp *pSics, + void *pData, int argc, char *argv[]){ + + return 1; +} diff --git a/geninter.h b/geninter.h new file mode 100644 index 00000000..05a469cd --- /dev/null +++ b/geninter.h @@ -0,0 +1,19 @@ +/** + * This is the implementation of various SICS internal interfaces based on + * parameters in a generic controller. + * + * copyright: see file COPYRIGHT + * + * Mark Koennecke, November 2007 + */ +#ifndef GENINTER_H_ +#define GENINTER_H_ +/** + * make a drivable parameter: + * Usage: + * MakeGenDrivable name par-node control-node + */ +int GenDrivableFactory(SConnection *pCon, SicsInterp *pSics, + void *pData, int argc, char *argv[]); + +#endif /*GENINTER_H_*/ diff --git a/hdbqueue.c b/hdbqueue.c new file mode 100644 index 00000000..88757825 --- /dev/null +++ b/hdbqueue.c @@ -0,0 +1,497 @@ +/** + * This is the new Hipadaba based queuing system in support of the MountainGum + * user interface. + * + * copyright: see file COPYRIGHT + * + * Mark Koennecke, July 2007 + */ +#include +#include +#include +#include "sicsobj.h" +#include "hdbqueue.h" +#include "sicshipadaba.h" +#include "dynstring.h" +#include "exeman.h" +#include "macro.h" +/*--------------------------------------------------------------------------*/ +typedef struct { + int iStop; + int isRunning; + SConnection *pCon; +}HdbQueue, *pHdbQueue; +/*--------------------------------------------------------------------------*/ +static pHdbCallback CopyCallbackChain(pHdbCallback source){ + pHdbCallback current = NULL; + pHdbCallback result = NULL; + pHdbCallback head = NULL; + pHdbCallback tail = NULL; + + current = source; + while(current != NULL){ + result = MakeHipadabaCallback(current->userCallback, + current->userData, + NULL, + current->id, + current->internalID); + if(head == NULL){ + head = result; + tail = result; + } else { + tail->next = result; + result->previous = tail; + tail = result; + } + current = current->next; + } + return head; +} +/*---------------------------------------------------------------------------*/ +static pHdb MakeNewEntry(char *name, pHdbCallback update){ + pHdb entry = NULL, child = NULL; + hdbValue v; + + v = MakeHdbText("Undefined"); + entry = MakeHipadabaNode(name,HIPNONE, 1); + entry->updateCallbacks = CopyCallbackChain(update); + child = MakeSICSHdbPar("description",usUser,v); + child->updateCallbacks = CopyCallbackChain(update); + AddHipadabaChild(entry,child,NULL); + child = MakeSICSHdbPar("commands",usUser,v); + child->updateCallbacks = CopyCallbackChain(update); + AddHipadabaChild(entry,child,NULL); + child = MakeSICSHdbPar("log",usUser,v); + child->updateCallbacks = CopyCallbackChain(update); + AddHipadabaChild(entry,child,NULL); + + return entry; +} +/*---------------------------------------------------------------------------*/ +static int EnqueFunc(pSICSOBJ self, SConnection *pCon, Hdb commandNode, + pHdb par[], int nPar){ + pHdb entry = NULL; + pHdb work = NULL; + char name[80]; + hdbValue v; + + if(nPar < 1){ + SCWrite(pCon,"ERROR: internal: not enough parameters to EnqueFunc",eError); + return 0; + } + + /* + * new entry + */ + memset(&v,0,sizeof(hdbValue)); + work = GetHipadabaNode(self->objectNode,"control/maxEntry"); + assert(work != NULL); + snprintf(name,80,"%3.3d", work->value.v.intValue); + entry = MakeNewEntry(name, work->updateCallbacks); + if(entry == NULL){ + SCWrite(pCon,"ERROR: out of memory in EnqueFunc",eError); + return 0; + } + /* + * Update maxEntry + */ + cloneHdbValue(&work->value,&v); + v.v.intValue++; + UpdateHipadabaPar(work,v,pCon); + + work = GetHipadabaNode(self->objectNode,"queue"); + assert(work != NULL); + AddHipadabaChild(work, entry, pCon); + + /* + * save description + */ + work = GetHipadabaNode(entry,"description"); + assert(work != NULL); + UpdateHipadabaPar(work,par[0]->value,pCon); + + + return 1; +} +/*---------------------------------------------------------------------------*/ +static int AddCmdData(pSICSOBJ self, SConnection *pCon, Hdb comNode, + pHdb par[], int nPar){ + pHdb work = NULL; + pHdb commandNode = NULL; + char name[80]; + pDynString txt = NULL; + + if(nPar < 1){ + SCWrite(pCon,"ERROR: internal: not enough parameters to AddCmdData",eError); + return 0; + } + + work = GetHipadabaNode(self->objectNode,"control/maxEntry"); + assert(work != NULL); + snprintf(name,80,"queue/%3.3d/commands", work->value.v.intValue-1); + commandNode = GetHipadabaNode(self->objectNode,name); + if(commandNode == NULL){ + SCWrite(pCon,"ERROR: Internal error in AddCommand",eError); + return 0; + } + txt = CreateDynString(80,80); + if(strstr(commandNode->value.v.text,"Undefined") == NULL){ + DynStringCopy(txt,commandNode->value.v.text); + } + DynStringConcat(txt,par[0]->value.v.text); + DynStringConcat(txt,"\n"); + free(commandNode->value.v.text); + commandNode->value.v.text = strdup(GetCharArray(txt)); + NotifyHipadabaPar(commandNode,pCon); + DeleteDynString(txt); + return 1; +} +/*--------------------------------------------------------------------------*/ +static void sequentialNames(pHdb obj,SConnection *pCon){ + pHdb work = NULL; + pHdb current = NULL; + int count = 0; + char name[80]; + + work = GetHipadabaNode(obj,"queue"); + assert(work != NULL); + current = work->child; + while(current != NULL){ + snprintf(name,80,"%3.3d",count); + if(current->name != NULL){ + free(current->name); + } + current->name = strdup(name); + count++; + current = current->next; + } + InvokeCallbackChain(work->treeChangeCallbacks,work,pCon,work->value); + + work = GetHipadabaNode(obj,"control/maxEntry"); + assert(work != NULL); + work->value.v.intValue = count; + NotifyHipadabaPar(work,pCon); +} +/*---------------------------------------------------------------------------*/ +static int Dequeue(pSICSOBJ self, SConnection *pCon, pHdb commandNode, + pHdb par[], int nPar){ + pHdb work = NULL; + char name[80]; + pHdbQueue priv = (pHdbQueue)self->pPrivate; + + if(priv->isRunning == 1){ + SCWrite(pCon,"ERROR: cannot dequeue while running",eError); + return 0; + } + + + if(nPar < 1){ + SCWrite(pCon,"ERROR: internal: not enough parameters to Dequeue",eError); + return 0; + } + + snprintf(name,80,"queue/%3.3d", par[0]->value.v.intValue); + work = GetHipadabaNode(self->objectNode,name); + if(work != NULL){ + DeleteHipadabaNode(work,pCon); + sequentialNames(self->objectNode, pCon); + return 1; + } + + return 0; +} +/*---------------------------------------------------------------------------*/ +static int Clean(pSICSOBJ self, SConnection *pCon,Hdb commandNode, + pHdb par[], int nPar){ + int i; + pHdb current = NULL, queue = NULL; + pHdb currentEntry = NULL, tmp = NULL; + pHdbQueue priv = (pHdbQueue)self->pPrivate; + + if(priv->isRunning == 1){ + SCWrite(pCon,"ERROR: cannot clean while running",eError); + return 0; + } + currentEntry = GetHipadabaNode(self->objectNode,"control/currentEntry"); + queue = GetHipadabaNode(self->objectNode,"queue"); + current = queue->child; + for(i = 0; i < currentEntry->value.v.intValue; i++){ + if(current != NULL){ + tmp = current->next; + DeleteNodeData(current); + current = tmp; + } + } + queue->child = tmp; + currentEntry->value.v.intValue = 0; + sequentialNames(self->objectNode, pCon); + NotifyHipadabaPar(currentEntry,pCon); + return 1; +} +/*---------------------------------------------------------------------------*/ +static int CleanAll(pSICSOBJ self, SConnection *pCon, pHdb commandNode, + pHdb par[], int nPar){ + int i; + pHdb current = NULL, queue = NULL; + pHdb currentEntry = NULL, tmp; + pHdbQueue priv = (pHdbQueue)self->pPrivate; + + if(priv->isRunning == 1){ + SCWrite(pCon,"ERROR: cannot clear queue while executing",eError); + return 0; + } + currentEntry = GetHipadabaNode(self->objectNode,"control/currentEntry"); + queue = GetHipadabaNode(self->objectNode,"queue"); + current = queue->child; + while(current != NULL){ + tmp = current->next; + DeleteNodeData(current); + current = tmp; + } + queue->child = NULL; + currentEntry->value.v.intValue = 0; + sequentialNames(self->objectNode, pCon); + NotifyHipadabaPar(currentEntry,pCon); + return 1; +} +/*----------------------------------------------------------------------------*/ +static int QueueTask(void *pData){ + pSICSOBJ self = (pSICSOBJ)pData; + int status, pos; + pHdb work = NULL; + pHdb exeNode = NULL; + pHdb max = NULL; + char name[80]; + pHdbQueue priv = (pHdbQueue)self->pPrivate; + + if(priv->iStop == 1){ + priv->isRunning = 0; + return 0; + } + + work = GetHipadabaNode(self->objectNode,"control/currentEntry"); + max = GetHipadabaNode(self->objectNode,"control/maxEntry"); + assert(work != NULL && max != NULL); + pos = work->value.v.intValue; + snprintf(name,80,"queue/%3.3d", pos); + + exeNode = GetHipadabaNode(self->objectNode,name); + if(exeNode != NULL){ + MacroPush(priv->pCon); + exeHdbNode(exeNode, priv->pCon); + MacroPop(); + } + if(priv->iStop == 1 || SCGetInterrupt(priv->pCon) != eContinue){ + priv->isRunning = 0; + return 0; + } + + pos++; + work->value.v.intValue = pos; + NotifyHipadabaPar(work,priv->pCon); + if(pos >= max->value.v.intValue){ + priv->isRunning = 0; + return 0; + } + + return 1; +} +/*---------------------------------------------------------------------------*/ +static int Start(pSICSOBJ self, SConnection *pCon, pHdb commandNode, + pHdb par[], int nPar){ + pHdbQueue priv = (pHdbQueue)self->pPrivate; + + priv->iStop = 0; + priv->pCon = pCon; + + if(priv->isRunning == 1){ + SCWrite(pCon,"ERROR: Hdbqueue is already running",eError); + return 0; + } + priv->isRunning = 1; + + TaskRegister(pServ->pTasker, + QueueTask, + NULL, + NULL, + self, + 10); + return 1; +} +/*---------------------------------------------------------------------------*/ +static int Restart(pSICSOBJ self, SConnection *pCon, pHdb commandNode, + pHdb par[], int nPar){ + pHdbQueue priv = (pHdbQueue)self->pPrivate; + pHdb maxCurrent = NULL; + + maxCurrent = GetHipadabaNode(self->objectNode,"control/currentEntry"); + if(maxCurrent != NULL){ + maxCurrent->value.v.intValue = 0; + NotifyHipadabaPar(maxCurrent,pCon); + } + + return Start(self,pCon,commandNode,par,nPar); +} +/*---------------------------------------------------------------------------*/ +static int Stop(pSICSOBJ self, SConnection *pCon, pHdb commandNode, + pHdb par[], int nPar){ + pHdbQueue priv = (pHdbQueue)self->pPrivate; + + priv->iStop = 1; + return 1; +} +/*----------------------------------------------------------------------------*/ +static int Move(pSICSOBJ self, SConnection *pCon, pHdb commandNode, + pHdb par[], int nPar){ + pHdb moveNode = NULL; + pHdb insertNode = NULL; + pHdb prevNode = NULL, queueNode = NULL; + pHdb tmp; + char name[80]; + pHdbQueue priv = (pHdbQueue)self->pPrivate; + + if(priv->isRunning == 1){ + SCWrite(pCon,"ERROR: cannot move while running",eError); + return 0; + } + + if(nPar < 2){ + SCWrite(pCon,"ERROR: internal: not enough parameters to Move",eError); + return 1; + } + + if(par[1]->value.v.intValue == par[0]->value.v.intValue + 1){ + /* + * already in right sequence, nothing to do + */ + return 1; + } + + snprintf(name,80,"queue/%3.3d", par[1]->value.v.intValue); + moveNode = GetHipadabaNode(self->objectNode,name); + + snprintf(name,80,"queue/%3.3d", par[0]->value.v.intValue); + insertNode = GetHipadabaNode(self->objectNode,name); + if(moveNode == NULL || insertNode == NULL){ + SCWrite(pCon,"ERROR: move not possible, participating nodes not found", + eError); + return 0; + } + queueNode = GetHipadabaNode(self->objectNode,"queue"); + + if(moveNode == queueNode->child){ + queueNode->child = queueNode->child->next; + moveNode->next = insertNode->next; + insertNode->next = moveNode; + } else { + prevNode = queueNode->child; + while(prevNode != NULL && prevNode->next != moveNode){ + prevNode = prevNode->next; + } + if(insertNode == queueNode->child ){ + /* + * insert at top + */ + tmp = queueNode->child; + queueNode->child = moveNode; + prevNode->next = moveNode->next; + moveNode->next = tmp; + } else { + tmp = insertNode->next; + insertNode->next = moveNode; + prevNode->next = moveNode->next; + moveNode->next = tmp; + } + } + sequentialNames(self->objectNode, pCon); + + return 1; +} +/*---------------------------------------------------------------------------*/ +static void Configure(pSICSOBJ self){ + pHdb n = NULL, par = NULL; + hdbValue intValue, textValue, funcValue; + pHdb obj = self->objectNode; + + intValue = MakeHdbInt(0); + textValue = MakeHdbText("Undefined"); + + n = MakeHipadabaNode("control",HIPNONE,1); + AddHipadabaChild(obj,n,NULL); + AddSICSHdbPar(n,"maxEntry",usInternal,intValue); + AddSICSHdbPar(n,"currentEntry",usInternal,intValue); + + + n = MakeHipadabaNode("queue",HIPNONE,1); + AddHipadabaChild(obj,n, NULL); + + funcValue = MakeSICSFunc(EnqueFunc); + n = MakeSICSHdbPar("enqueue",usUser, funcValue); + AddSICSHdbPar(n,"description",usUser,textValue); + AddHipadabaChild(obj,n,NULL); + AppendHipadabaCallback(n,HCBSET,MakeSICSFuncCallback(self)); + + funcValue = MakeSICSFunc(AddCmdData); + n = MakeSICSHdbPar("addcommand",usUser, funcValue); + AddSICSHdbPar(n,"command",usUser,textValue); + AddHipadabaChild(obj,n,NULL); + AppendHipadabaCallback(n,HCBSET,MakeSICSFuncCallback(self)); + + + funcValue = MakeSICSFunc(Dequeue); + n = MakeSICSHdbPar("dequeue",usUser,funcValue); + AddHipadabaChild(obj,n,NULL); + AddSICSHdbPar(n,"index",usUser,intValue); + AppendHipadabaCallback(n,HCBSET,MakeSICSFuncCallback(self)); + + + funcValue = MakeSICSFunc(Clean); + n = MakeSICSHdbPar("clean",usUser, funcValue); + AddHipadabaChild(obj,n,NULL); + AppendHipadabaCallback(n,HCBSET,MakeSICSFuncCallback(self)); + + funcValue = MakeSICSFunc(CleanAll); + n = MakeSICSHdbPar("cleanall",usUser, funcValue); + AddHipadabaChild(obj,n,NULL); + AppendHipadabaCallback(n,HCBSET,MakeSICSFuncCallback(self)); + + funcValue = MakeSICSFunc(Start); + n = MakeSICSHdbPar("start",usUser, funcValue); + AddHipadabaChild(obj,n,NULL); + AppendHipadabaCallback(n,HCBSET,MakeSICSFuncCallback(self)); + + funcValue = MakeSICSFunc(Restart); + n = MakeSICSHdbPar("restart",usUser, funcValue); + AddHipadabaChild(obj,n,NULL); + AppendHipadabaCallback(n,HCBSET,MakeSICSFuncCallback(self)); + + funcValue = MakeSICSFunc(Stop); + n = MakeSICSHdbPar("stop",usUser, funcValue); + AddHipadabaChild(obj,n,NULL); + AppendHipadabaCallback(n,HCBSET,MakeSICSFuncCallback(self)); + + funcValue = MakeSICSFunc(Move); + n = MakeSICSHdbPar("move",usUser,funcValue); + AddHipadabaChild(obj,n,NULL); + AddSICSHdbPar(n,"moveindex",usUser,intValue); + AddSICSHdbPar(n,"insertindex",usUser,intValue); + AppendHipadabaCallback(n,HCBSET,MakeSICSFuncCallback(self)); + +} +/*---------------------------------------------------------------------------*/ +int MakeHDBQueue(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]){ + pSICSOBJ self = NULL; + pHdbQueue priv = NULL; + + priv = (pHdbQueue)malloc(sizeof(HdbQueue)); + self = SetupSICSOBJ(pCon,pSics, pData,argc, argv); + if(self == NULL || priv == NULL){ + return 0; + } + Configure(self); + memset(priv,0,sizeof(HdbQueue)); + self->pPrivate = priv; + self->KillPrivate = free; + return 1; +} diff --git a/hdbqueue.h b/hdbqueue.h new file mode 100644 index 00000000..a1663da8 --- /dev/null +++ b/hdbqueue.h @@ -0,0 +1,15 @@ +/** + * This is the new Hipadab based queuing system in support of the MountainGum + * user interface. + * + * copyright: see file COPYRIGHT + * + * Mark Koennecke, July 2007 + */ +#ifndef HDBQUEUE_H_ +#define HDBQUEUE_H_ + +int MakeHDBQueue(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]); + +#endif /*HDBQUEUE_H_*/ diff --git a/hipadaba.c b/hipadaba.c index 181c2765..88c1cd28 100644 --- a/hipadaba.c +++ b/hipadaba.c @@ -14,11 +14,64 @@ #define ABS(x) (x < 0 ? -(x) : (x)) #define HDBMAGICK 77119900 +/*================== Message Stuff ========================================*/ +static char set[] = {"set"}; +static char get[] = {"get"}; +static char update[] = {"update"}; +static char treeChange[] = {"treeChange"}; +static char dataSearch[] = {"dataSearch"}; +static char killNode[] = {"killNode"}; +/*------------------------------------------------------------------------*/ +pHdbDataMessage GetHdbSetMessage(pHdbMessage toTest){ + if(toTest->type == set){ + return (pHdbDataMessage)toTest; + } + return NULL; +} +/*------------------------------------------------------------------------*/ +pHdbDataMessage GetHdbGetMessage(pHdbMessage toTest){ + if(toTest->type == get){ + return (pHdbDataMessage)toTest; + } + return NULL; +} +/*------------------------------------------------------------------------*/ +pHdbDataMessage GetHdbUpdateMessage(pHdbMessage toTest){ + if(toTest->type == update){ + return (pHdbDataMessage)toTest; + } + return NULL; +} +/*-------------------------------------------------------------------------*/ +pHdbTreeChangeMessage GetHdbTreeChangeMessage(pHdbMessage toTest){ + if(toTest->type == treeChange){ + return (pHdbTreeChangeMessage)toTest; + } + return NULL; +} +/*-------------------------------------------------------------------------*/ +pHdbDataSearch GetHdbDataSearchMessage(pHdbMessage toTest){ + if(toTest->type == dataSearch){ + return (pHdbDataSearch)toTest; + } + return NULL; +} +/*-------------------------------------------------------------------------*/ +pHdbMessage GetHdbKillNodeMessage(pHdbMessage toTest){ + if(toTest->type == killNode){ + return toTest; + } + return NULL; +} /*================== internal functions ===================================*/ -void DeleteCallbackChain(pHdbCallback root){ +void DeleteCallbackChain(pHdb node){ pHdbCallback current = NULL, thisEntry; + hdbMessage killNodeMsg; - current = root; + killNodeMsg.type = killNode; + InvokeCallbackChain(node, &killNodeMsg); + + current = node->callBackChain; while(current != NULL){ if(current->killFunc != NULL){ current->killFunc(current->userData); @@ -28,17 +81,26 @@ void DeleteCallbackChain(pHdbCallback root){ free(thisEntry); } } +/*----------------------------------------------------------------------*/ +void RecurseCallbackChains(pHdb node, pHdbMessage message){ + pHdb current = NULL; + + InvokeCallbackChain(node,message); + current = node->child; + while(current != NULL){ + RecurseCallbackChains(current,message); + current = current->next; + } +} /*-----------------------------------------------------------------------*/ -static void DeleteNodeData(pHdb node){ +void DeleteNodeData(pHdb node){ pHdb tmp = NULL; if(node == NULL){ return; } - DeleteCallbackChain(node->writeCallbacks); - DeleteCallbackChain(node->updateCallbacks); - DeleteCallbackChain(node->readCallbacks); - DeleteCallbackChain(node->treeChangeCallbacks); + + DeleteCallbackChain(node); if(node->properties != NULL){ DeleteStringDict(node->properties); } @@ -59,145 +121,102 @@ static void DeleteNodeData(pHdb node){ } free(node); } +/*------------------------------------------------------------------------*/ +static pHdbCallback CleanCallbackChain(pHdbCallback head){ + pHdbCallback current = head; + pHdbCallback next; + pHdbCallback *ptr2last = &head; + + while(current != NULL){ + if(current->killFlag == 1){ + next = current->next; + /* + * unlink + */ + *ptr2last = next; + /* + * delete + */ + if(current->killFunc != NULL){ + current->killFunc(current->userData); + } + free(current); + /* + * move on + */ + current = next; + } else { + ptr2last = ¤t->next; + current = current->next; + } + } + + return head; +} /*-------------------------------------------------------------------------*/ -static int InvokeCallbackChain(pHdbCallback root, pHdb node, - void *callData, hdbValue v){ - pHdbCallback current = root; - int status; +int InvokeCallbackChain(pHdb node, pHdbMessage message){ + pHdbCallback current = node->callBackChain; + hdbCallbackReturn status; + int killFlag = 0; while(current != NULL){ - status = current->userCallback(current->userData,callData, - node,v); - if(status != 1){ - return status; + status = current->userCallback(node, current->userData,message); + switch(status){ + case hdbAbort: + return 0; + break; + case hdbKill: + current->killFlag = 1; + killFlag = 1; + break; + case hdbContinue: + break; } current = current->next; } + if(killFlag == 1){ + node->callBackChain = CleanCallbackChain(node->callBackChain); + } return 1; -} +} +/*-----------------------------------------------------------------------*/ +static void SendTreeChangeMessage(pHdb node, void *callData){ + hdbTreeChangeMessage treeChangeMes; + treeChangeMes.type = treeChange; + treeChangeMes.callData = callData; + InvokeCallbackChain(node, (pHdbMessage)&treeChangeMes); +} /*------------------------------------------------------------------------*/ void RemoveHdbNodeFromParent(pHdb node, void *callData){ pHdb parent = NULL; pHdb current = NULL; + hdbTreeChangeMessage treeChangeMes; parent = node->mama; if(parent != NULL){ if(parent->child == node){ parent->child = node->next; - return; - } - current = parent->child; - while(current->next != node){ - current = current->next; - } - current->next = current->next->next; - InvokeCallbackChain(parent->treeChangeCallbacks, - parent,callData,parent->value); - } -} -/*-----------------------------------------------------------------------*/ -static void RemoveCallbackNode(pHdbCallback victim){ - if(victim->previous != NULL) { - victim->previous->next = victim->next; - } - if(victim->next != NULL){ - victim->next->previous = victim->previous; - } - if(victim->killFunc != NULL){ - victim->killFunc(victim->userData); - } - free(victim); -} -/*----------------------------------------------------------------------- - * This code is ugly: the problem is fixing up the start of the chain. - * Think about it and improve - * ----------------------------------------------------------------------*/ -static pHdbCallback DeleteForID(pHdbCallback root, int id){ - pHdbCallback current = root; - pHdbCallback tmp = NULL; - pHdbCallback result = NULL; - - if(root == NULL){ - return NULL; - } - - /* - * delete at the start of the chain - */ - result = root; - while(result->id == id){ - tmp = result; - result = result->next; - RemoveCallbackNode(tmp); - if(result == NULL){ - return NULL; - } - } - - /* - * delete nodes in the middle of the chain - */ - current = result; - while(current != NULL){ - if(current->id == id){ - tmp = current; - current = (pHdbCallback)current->next; - RemoveCallbackNode(tmp); - } else { - current = (pHdbCallback)current->next; - } - } - return result; -} -/*-----------------------------------------------------------------------*/ -static pHdbCallback DeleteForInternalID(pHdbCallback root, int id){ - pHdbCallback current = root; - pHdbCallback tmp = NULL; - pHdbCallback result = NULL; - - if(root == NULL){ - return NULL; - } - - /* - * delete at the start of the chain - */ - result = root; - while(result->internalID == id){ - tmp = result; - result = result->next; - if(tmp->killFunc != NULL){ - tmp->killFunc(tmp->userData); - } - free(tmp); - if(result == NULL){ - return NULL; - } - } - - /* - * delete nodes in the middle of the chain - */ - current = result; - while(current != NULL){ - if(current->internalID == id){ - if(current->next != NULL){ - current->next->previous = current->previous; + } else { + current = parent->child; + while(current->next != node){ + current = current->next; } - if(current->previous != NULL){ - current->previous->next = current->next; - } - tmp = current; - current = (pHdbCallback)current->next; - if(tmp->killFunc != NULL){ - tmp->killFunc(tmp->userData); - } - free(tmp); - } else { - current = (pHdbCallback)current->next; - } + current->next = current->next->next; + } + SendTreeChangeMessage(parent,callData); + node->mama = NULL; } - return result; +} +/*----------------------------------------------------------------------*/ +int CountHdbChildren(pHdb node){ + int count = 0; + pHdb current = NULL; + current = node->child; + while(current != NULL){ + current = current->next; + count++; + } + return count; } /*----------------------------------------------------------------------*/ char *hdbTrim(char *str) @@ -274,6 +293,7 @@ hdbValue makeHdbValue(int datatype, int length){ memset(&val,0,sizeof(hdbValue)); val.dataType = datatype; + val.doNotFree = 0; switch(datatype){ case HIPINTAR: @@ -299,60 +319,6 @@ hdbValue makeHdbValue(int datatype, int length){ } return val; } -/*------------------------------------------------------------------------*/ -hdbValue makeHdbData(int datatype, int length, void *data){ - hdbValue val; - - memset(&val,0,sizeof(hdbValue)); - val.dataType = datatype; - - switch(datatype){ - case HIPINT: - if(data != NULL){ - memcpy(&val.v.intValue,data,sizeof(int)); - } - break; - case HIPFLOAT: - if(data != NULL){ - memcpy(&val.v.doubleValue,data,sizeof(double)); - } - break; - case HIPINTAR: - case HIPINTVARAR: - val.arrayLength = length; - val.v.intArray = malloc(length*sizeof(int)); - if(val.v.intArray != NULL){ - memset(val.v.intArray,0,length*sizeof(int)); - } - if(data != NULL){ - memcpy(val.v.intArray,data,length*sizeof(int)); - } - break; - case HIPFLOATAR: - case HIPFLOATVARAR: - val.arrayLength = length; - val.v.floatArray = malloc(length*sizeof(double)); - if(val.v.floatArray != NULL){ - memset(val.v.floatArray,0,length*sizeof(double)); - } - if(data != NULL){ - memcpy(val.v.floatArray,data,length*sizeof(double)); - } - break; - case HIPTEXT: - if(data != NULL){ - val.v.text = strdup((char *)data); - } else { - val.v.text = strdup("UNKNOWN"); - } - val.arrayLength = strlen(val.v.text); - break; - case HIPOBJ: - val.v.obj = data; - break; - } - return val; -} /*-------------------------------------------------------------------------*/ hdbValue MakeHdbInt(int initValue){ hdbValue result; @@ -376,7 +342,7 @@ hdbValue MakeHdbText(char *initText){ hdbValue result; result.dataType = HIPTEXT; - result.v.text = initText; + result.v.text = initText; /* no strdup here ! */ result.arrayLength = strlen(initText); return result; } @@ -390,7 +356,7 @@ hdbValue MakeHdbIntArray(int length, int *data){ return result; } /*-------------------------------------------------------------------------*/ -hdbValue MakeHdbFloatArrray(int length, double *data){ +hdbValue MakeHdbFloatArray(int length, double *data){ hdbValue result; result.dataType = HIPFLOATAR; @@ -399,7 +365,27 @@ hdbValue MakeHdbFloatArrray(int length, double *data){ return result; } /*-------------------------------------------------------------------------*/ +hdbValue MakeHdbFunc(voidFunc *func){ + hdbValue result; + + result.dataType = HIPFUNC; + result.v.func = func; + return result; +} +/*-------------------------------------------------------------------------*/ +hdbValue MakeHdbObj(void *obj){ + hdbValue result; + + result.dataType = HIPOBJ; + result.v.obj = obj; + return result; +} +/*-------------------------------------------------------------------------*/ void ReleaseHdbValue(hdbValue *v){ + + if(v->doNotFree == 1){ + return; + } switch(v->dataType){ case HIPTEXT: if(v->v.text != NULL){ @@ -447,6 +433,9 @@ int compareHdbValue(hdbValue v1, hdbValue v2){ } break; case HIPTEXT: + if(v1.v.text == NULL || v2.v.text == NULL){ + return 0; + } if(strcmp(v1.v.text,v2.v.text) == 0){ return 1; } else { @@ -458,6 +447,9 @@ int compareHdbValue(hdbValue v1, hdbValue v2){ if(v1.arrayLength != v2.arrayLength){ return 0; } + if(v1.v.intArray == NULL || v2.v.intArray == NULL){ + return 0; + } for(i = 0; i < v1.arrayLength; i++){ if(v1.v.intArray[i] != v2.v.intArray[i]){ return 0; @@ -470,6 +462,9 @@ int compareHdbValue(hdbValue v1, hdbValue v2){ if(v1.arrayLength != v2.arrayLength){ return 0; } + if(v1.v.floatArray == NULL || v2.v.floatArray == NULL){ + return 0; + } for(i = 0; i < v1.arrayLength; i++){ if(ABS(v1.v.floatArray[i] - v2.v.floatArray[i]) > .01){ return 0; @@ -484,6 +479,13 @@ int compareHdbValue(hdbValue v1, hdbValue v2){ return 0; } break; + case HIPFUNC: + if(v2.v.func == v1.v.func) { + return 1; + } else { + return 0; + } + break; default: assert(0); break; @@ -494,6 +496,7 @@ int compareHdbValue(hdbValue v1, hdbValue v2){ int cloneHdbValue(hdbValue *source, hdbValue *clone){ memset(clone,0,sizeof(hdbValue)); + clone->v.text = NULL; /* this sets all pointers in the union to NULL */ clone->dataType = source->dataType; return copyHdbValue(source, clone); } @@ -523,6 +526,9 @@ int getHdbValueLength(hdbValue v){ case HIPOBJ: length = sizeof(void *); break; + case HIPFUNC: + length = sizeof(voidFunc *); + break; } return length; } @@ -594,8 +600,7 @@ void AddHipadabaChild(pHdb parent, pHdb child, void *callData){ child->next = NULL; prev->next = child; } - InvokeCallbackChain(parent->treeChangeCallbacks, - parent,callData,parent->value); + SendTreeChangeMessage(parent,callData); } /*--------------------------------------------------------------------------*/ void DeleteHipadabaNode(pHdb node, void *callData){ @@ -705,8 +710,7 @@ char *GetHipadabaPath(pHdb node){ } /*==================== Callback Functions ==================================*/ pHdbCallback MakeHipadabaCallback(hdbCallbackFunction func, - void *userData, killUserData killFunc, - int id, int internalID){ + void *userData, killUserData killFunc){ pHdbCallback pNew = NULL; assert(func != NULL); @@ -720,142 +724,68 @@ pHdbCallback MakeHipadabaCallback(hdbCallbackFunction func, pNew->userCallback = func; pNew->userData = userData; pNew->killFunc = killFunc; - pNew->id = id; - pNew->internalID = internalID; return pNew; } /*-------------------------------------------------------------------*/ -void AppendHipadabaCallback(pHdb node, int type, pHdbCallback newCB){ +void AppendHipadabaCallback(pHdb node, pHdbCallback newCB){ pHdbCallback current = NULL; - switch(type){ - case HCBSET: - if(node->writeCallbacks == NULL){ - node->writeCallbacks = newCB; - return; - } else { - current = node->writeCallbacks; - } - break; - case HCBUPDATE: - if(node->updateCallbacks == NULL){ - node->updateCallbacks = newCB; - return; - } else { - current = node->updateCallbacks; - } - break; - case HCBREAD: - if(node->readCallbacks == NULL){ - node->readCallbacks = newCB; - return; - } else { - current = node->readCallbacks; - } - break; - case HCBTREE: - if(node->treeChangeCallbacks == NULL){ - node->treeChangeCallbacks = newCB; - return; - } else { - current = node->treeChangeCallbacks; - } - break; - default: - assert(0); - break; + assert(node); + current = node->callBackChain; + newCB->next = NULL; + if(current == NULL){ + node->callBackChain = newCB; + return; } - if(current != NULL){ - while(current->next != NULL){ - current = (pHdbCallback)current->next; - } - current->next= newCB; - newCB->previous = current; + while(current->next != NULL){ + current = (pHdbCallback)current->next; } + current->next = newCB; } /*---------------------------------------------------------------------------*/ -void PrependHipadabaCallback(pHdb node, int type, pHdbCallback newCB){ - switch(type){ - case HCBSET: - if(node->writeCallbacks == NULL){ - node->writeCallbacks = newCB; - return; - } else { - newCB->next = node->writeCallbacks; - node->writeCallbacks->previous = newCB; - node->writeCallbacks = newCB; - } - break; - case HCBUPDATE: - if(node->updateCallbacks == NULL){ - node->updateCallbacks = newCB; - return; - } else { - newCB->next = node->updateCallbacks; - node->updateCallbacks->previous = newCB; - node->updateCallbacks = newCB; - } - break; - case HCBREAD: - if(node->readCallbacks == NULL){ - node->readCallbacks = newCB; - return; - } else { - newCB->next = node->readCallbacks; - node->readCallbacks->previous = newCB; - node->readCallbacks = newCB; - } - break; - case HCBTREE: - if(node->treeChangeCallbacks == NULL){ - node->treeChangeCallbacks = newCB; - return; - } else { - newCB->next = node->treeChangeCallbacks; - node->treeChangeCallbacks->previous = newCB; - node->treeChangeCallbacks = newCB; - } - break; - default: - assert(0); - break; - } +void PrependHipadabaCallback(pHdb node,pHdbCallback newCB){ + assert(node != NULL); + + newCB->next = node->callBackChain; + node->callBackChain = newCB; } /*----------------------------------------------------------------------------*/ -void RemoveHipadabaCallback(pHdb root, int id){ - pHdb current = NULL; - - root->writeCallbacks = DeleteForID(root->writeCallbacks,id); - root->updateCallbacks = DeleteForID(root->updateCallbacks,id); - root->readCallbacks = DeleteForID(root->readCallbacks,id); - root->treeChangeCallbacks = DeleteForID(root->treeChangeCallbacks,id); - - current = root->child; - while(current != NULL){ - RemoveHipadabaCallback(current,id); - current = current->next; - } -} -/*----------------------------------------------------------------------------*/ -void InternalRemoveHipadabaCallback(pHdb root, int internalID){ - pHdb current = NULL; - - root->writeCallbacks = DeleteForInternalID(root->writeCallbacks,internalID); - root->updateCallbacks = DeleteForInternalID(root->updateCallbacks,internalID); - root->readCallbacks = DeleteForInternalID(root->readCallbacks,internalID); - root->treeChangeCallbacks = DeleteForInternalID(root->treeChangeCallbacks,internalID); - - current = root->child; - while(current != NULL){ - InternalRemoveHipadabaCallback(current,internalID); - current = current->next; - } +void *FindHdbCallbackData(pHdb node, void *userPtr){ + hdbDataSearch dsm; + + dsm.type = dataSearch; + dsm.testPtr = userPtr; + dsm.result = NULL; + + InvokeCallbackChain(node, (pHdbMessage)&dsm); + return dsm.result; + } /*=================== parameter interface ====================================*/ +static int canCopy(hdbValue *source, hdbValue *target){ + if(target->dataType == HIPINTVARAR) { + if(source->dataType == HIPINTAR || + source->dataType == HIPINTVARAR){ + return 1; + } + } + if(target->dataType == HIPFLOATVARAR) { + if(source->dataType == HIPFLOATAR || + source->dataType == HIPFLOATVARAR){ + return 1; + } + } + if(source->dataType != target->dataType){ + return 0; + } else { + return 1; + } +} +/*----------------------------------------------------------------------------*/ int copyHdbValue(hdbValue *source, hdbValue *target){ int i; - if(source->dataType != target->dataType){ + if(!canCopy(source,target)){ return 0; } @@ -884,7 +814,8 @@ int copyHdbValue(hdbValue *source, hdbValue *target){ if(target->v.intArray == NULL){ return 0; } - memset(target->v.intArray,0,source->arrayLength * sizeof(int)); + memset(target->v.intArray,0,source->arrayLength + * sizeof(int)); target->arrayLength = source->arrayLength; } if(source->v.intArray != NULL){ @@ -895,15 +826,18 @@ int copyHdbValue(hdbValue *source, hdbValue *target){ break; case HIPFLOATAR: case HIPFLOATVARAR: - if(target->arrayLength != source->arrayLength || target->v.floatArray == NULL){ + if(target->arrayLength != source->arrayLength + || target->v.floatArray == NULL){ if(target->v.floatArray != NULL){ free(target->v.floatArray); } - target->v.floatArray = malloc(source->arrayLength * sizeof(double)); + target->v.floatArray = + malloc(source->arrayLength * sizeof(double)); if(target->v.floatArray == NULL){ return 0; } - memset(target->v.floatArray,0,source->arrayLength * sizeof(double)); + memset(target->v.floatArray,0,source->arrayLength * + sizeof(double)); target->arrayLength = source->arrayLength; } if(source->v.floatArray != NULL){ @@ -915,6 +849,9 @@ int copyHdbValue(hdbValue *source, hdbValue *target){ case HIPOBJ: target->v.obj = source->v.obj; break; + case HIPFUNC: + target->v.func = source->v.func; + break; default: /* * unknown data type @@ -924,33 +861,48 @@ int copyHdbValue(hdbValue *source, hdbValue *target){ } return 1; } +/*---------------------------------------------------------------------------*/ +static int SendDataMessage(pHdb node, char *type, + hdbValue v, void *callData){ + hdbDataMessage dataMes; + + assert(type == set || type == get || type == update); + dataMes.type = type; + dataMes.v = &v; + dataMes.callData = callData; + return InvokeCallbackChain(node, (pHdbMessage)&dataMes); +} /*----------------------------------------------------------------------------*/ int SetHipadabaPar(pHdb node, hdbValue v, void *callData){ - int status; - - status = InvokeCallbackChain(node->writeCallbacks, node, callData, v); - return status; + return SendDataMessage(node, set, v,callData); } /*-----------------------------------------------------------------------------*/ int UpdateHipadabaPar(pHdb node, hdbValue v, void *callData){ - int status; - - status = InvokeCallbackChain(node->updateCallbacks, node, callData, v); - if(status != 1 ){ - return status; - } - copyHdbValue(&v,&node->value); + int status; + + status = SendDataMessage(node, update, v,callData); + if(status == 1){ + copyHdbValue(&v,&node->value); + } + return status; +} +/*-----------------------------------------------------------------------------*/ +int NotifyHipadabaPar(pHdb node,void *callData){ + SendDataMessage(node, update, node->value,callData); return 1; } /*-----------------------------------------------------------------------------*/ int GetHipadabaPar(pHdb node, hdbValue *v, void *callData){ int status; - status = InvokeCallbackChain(node->readCallbacks, node, callData, *v); + v->dataType = node->value.dataType; + v->doNotFree = 0; + v->v.text = NULL; /* this sets all pointers in the union to NULL */ + + status = SendDataMessage(node, get, *v,callData); if(status != 1 ){ return status; } - v->dataType = node->value.dataType; copyHdbValue(&node->value,v); return 1; } @@ -966,112 +918,12 @@ static int calcDataLength(pHdb node, int testLength){ } return length; } -/*--------------------------------------------------------------------------*/ -int SetHdbPar(pHdb node, int dataType, void *data, int length, - void *callData){ - int status; - hdbValue v; - - if(node->value.dataType == HIPNONE){ - return 1; - } - - if(dataType != node->value.dataType){ - return HDBTYPEMISMATCH; - } - if(length != calcDataLength(node,length)){ - return HDBLENGTHMISMATCH; - } - - v = makeHdbData(dataType, length, data); - status = InvokeCallbackChain(node->writeCallbacks, node, callData, v); - if(status == 1) { - copyHdbValue(&v,&node->value); - } - return status; -} -/*--------------------------------------------------------------------------*/ -int UpdateHdbPar(pHdb node, int dataType, void *data, int length, - void *callData){ - int status; - hdbValue v; - - if(node->value.dataType == HIPNONE){ - return 1; - } - - if(dataType != node->value.dataType){ - return HDBTYPEMISMATCH; - } - if(length != calcDataLength(node,length)){ - return HDBLENGTHMISMATCH; - } - - v = makeHdbData(dataType,length,data); - - status = InvokeCallbackChain(node->updateCallbacks, node, callData, v); - if(status == 1) { - copyHdbValue(&v,&node->value); - } - return status; -} -/*-----------------------------------------------------------------------------*/ -int GetHdbPar(pHdb node, int dataType, void *data, int length, - void *callData){ - int status, toCopy; - hdbValue v; - - if(dataType != node->value.dataType){ - return HDBTYPEMISMATCH; - } - - if(length != calcDataLength(node,length)){ - return HDBLENGTHMISMATCH; - } - - status = InvokeCallbackChain(node->readCallbacks, node, callData, v); - if(status != 1 ){ - return status; - } - switch(dataType){ - case HIPNONE: - break; - case HIPINT: - memcpy(data,&node->value.v.intValue,sizeof(int)); - break; - case HIPFLOAT: - memcpy(data,&node->value.v.doubleValue,sizeof(double)); - break; - case HIPINTAR: - case HIPINTVARAR: - memcpy(data,node->value.v.intArray, - node->value.arrayLength*sizeof(int)); - break; - case HIPTEXT: - toCopy = strlen(node->value.v.text); - if(toCopy > length){ - toCopy = length; - } - memcpy(data,&node->value.v.text, toCopy); - break; - case HIPFLOATAR: - case HIPFLOATVARAR: - memcpy(data,node->value.v.floatArray, - node->value.arrayLength*sizeof(double)); - break; - case HIPOBJ: - memcpy(data,&node->value.v.obj,sizeof(void *)); - break; - default: - assert(0); - break; - } - return 1; -} /*============================= Property Functions ==========================*/ void SetHdbProperty(pHdb node, char *key, char *value){ if(node != NULL && key != NULL && node->properties != NULL){ - if(StringDictExists(node->properties, key)){ + if (value == NULL) { + StringDictDelete(node->properties, key); + } else if(StringDictExists(node->properties, key)){ StringDictUpdate(node->properties,key,value); } else { StringDictAddPair(node->properties,key,value); @@ -1087,6 +939,14 @@ int GetHdbProperty(pHdb node, char *key, char *value, int len){ } } /*---------------------------------------------------------------------------*/ +char *GetHdbProp(pHdb node, char *key){ + if(node != NULL && node->properties != NULL){ + return StringDictGetShort(node->properties,key); + } else { + return NULL; + } +} +/*---------------------------------------------------------------------------*/ void InitHdbPropertySearch(pHdb node){ if(node != NULL && node->properties != NULL){ StringDictKillScan(node->properties); diff --git a/hipadaba.h b/hipadaba.h index 944efa81..22c7a745 100644 --- a/hipadaba.h +++ b/hipadaba.h @@ -1,4 +1,4 @@ -/** +/** @file * Hipadaba is a hierarchical database of parameters. Parameters can be of * various types. What happens when a parameter is being set, updated or read * is largely determined through callbacks which can be registered on @@ -24,6 +24,8 @@ * Added treeChange callback, Mark Koennecke, November 2006 * * Added support for properties, Mark Koennecke, January 2007 + * + * Refactored callback handling, Markus Zolliker, Mark Koennecke, March 2008 */ #ifndef HIPADABA #define HIPADABA @@ -39,24 +41,24 @@ #define HIPINTVARAR 5 #define HIPFLOATVARAR 6 #define HIPOBJ 7 -/* -------- callback types */ -#define HCBSET 0 -#define HCBUPDATE 1 -#define HCBREAD 2 -#define HCBTREE 3 +#define HIPFUNC 8 /*--------- error codes */ #define HDBTYPEMISMATCH -7701 #define HDBLENGTHMISMATCH -7702 /*===================== structure definitions ===================================*/ +typedef void voidFunc(void); + typedef struct __hdbValue { int dataType; int arrayLength; + int doNotFree; union __value { - int intValue; + int intValue; double doubleValue; char *text; int *intArray; double *floatArray; + voidFunc *func; void *obj; }v; }hdbValue; @@ -66,41 +68,103 @@ typedef struct __hipadaba { struct __hipadaba *mama; struct __hipadaba *child; struct __hipadaba *next; - struct __hdbcallback *writeCallbacks; - struct __hdbcallback *updateCallbacks; - struct __hdbcallback *readCallbacks; - struct __hdbcallback *treeChangeCallbacks; + struct __hdbcallback *callBackChain; char *name; char *path; hdbValue value; int protected; pStringDict properties; }Hdb, *pHdb; +/*-------------- return values for callback functions -------------------------*/ +typedef enum {hdbContinue, + hdbAbort, + hdbKill } hdbCallbackReturn; +/*======================== Messages ===========================================*/ +typedef struct __hdbMessage { + char *type; +} hdbMessage, *pHdbMessage; +/*-----------------------------------------------------------------------------*/ +typedef struct { + char *type; + hdbValue *v; + void *callData; +}hdbDataMessage, *pHdbDataMessage; /*-------------------------------------------------------------------------------*/ -typedef int (*hdbCallbackFunction)(void *userData, void *callData, - pHdb currentNode, hdbValue v); +typedef struct { + char *type; + void *callData; +}hdbTreeChangeMessage, *pHdbTreeChangeMessage; +/*-------------------------------------------------------------------------------*/ +typedef struct { + char *type; + void *testPtr; + void *result; +}hdbDataSearch, *pHdbDataSearch; +/*-------------------------------------------------------------------------------*/ +typedef hdbCallbackReturn (*hdbCallbackFunction)(pHdb currentNode, + void *userData, + pHdbMessage message); + typedef void (*killUserData)(void *data); /*-------------------------------------------------------------------------------*/ typedef struct __hdbcallback { void *userData; killUserData killFunc; hdbCallbackFunction userCallback; - int id; - int internalID; + int killFlag; struct __hdbcallback *next; struct __hdbcallback *previous; }hdbCallback, *pHdbCallback; -/*======================== Function protoypes: hdbData ========================*/ -hdbValue makeHdbValue(int datatype, int length); +/*============= Message Test Functions ==========================================*/ /** - * make a hdbValue and initailize it with the data in the void - * pointer. Do not initialise when data = NULL. - * @param dataType The datatype of the hdbValue - * @param The array length of the hdbValue - * @param data Initialisation data for hdbValue + * Test a message if it is a set message + * @param toTest The message to test. + * @return NULL if the message is no set message or a message pointer if it is. + */ +pHdbDataMessage GetHdbSetMessage(pHdbMessage toTest); +/** + * Test a message if it is a set message + * @param toTest The message to test. + * @return NULL if the message is no set message or a message pointer if it is. + */ +pHdbDataMessage GetHdbGetMessage(pHdbMessage toTest); +/** + * Test a message if it is a update message + * @param toTest The message to test. + * @return NULL if the message is no update message or a message pointer if + * it is. + */ +pHdbDataMessage GetHdbUpdateMessage(pHdbMessage toTest); +/** + * Test a message if it is a tree change message + * @param toTest The message to test. + * @return NULL if the message is no tree change message or a message + * pointer if it is. + */ +pHdbTreeChangeMessage GetHdbTreeChangeMessage(pHdbMessage toTest); +/** + * Test a message if it is a data search message + * @param toTest The message to test. + * @return NULL if the message is no data search message or a message + * pointer if it is. + */ +pHdbDataSearch GetHdbDataSearchMessage(pHdbMessage toTest); +/** + * Test a message if it is a kill node message + * @param toTest The message to test. + * @return NULL if the message is no kill node message or a message + * pointer if it is. + */ +pHdbMessage GetHdbKillNodeMessage(pHdbMessage toTest); +/*======================== Function protoypes: hdbData ========================*/ +/** + * make a hdbValue with the given datatype and length + * Do not initialise + * @param datatype The datatype of the hdbValue + * @param length The array length of the hdbValue * @return a suitably defined hdbValue */ -hdbValue makeHdbData(int datatype, int length, void *data); +hdbValue makeHdbValue(int datatype, int length); /** * wrap an integer as an hdbValue * @param initValue the initial value of the int @@ -142,6 +206,18 @@ hdbValue MakeHdbIntArray(int length, int *data); * @return: A properly initialized hdbValue structure */ hdbValue MakeHdbFloatArray(int length, double *data); +/** + * wrap a function as an hdbValue + * @param func the function + * @return: A properly initialized hdbValue structure + */ +hdbValue MakeHdbFunc(voidFunc *func); +/** + * wrap an object as an hdbValue + * @param obj the object + * @return: A properly initialized hdbValue structure + */ +hdbValue MakeHdbObj(void *obj); /** * release any dynamic memory associated with v * @param v The hdbValue to check for dynamic memory allocation to be @@ -182,6 +258,7 @@ int getHdbValueLength(hdbValue v); * make a new hipadaba node * @param name The name of the new node * @param datatype The datatype of the new node + * @param length the array length * @return a new node or NULL when out of memory */ pHdb MakeHipadabaNode(char *name, int datatype, int length); @@ -193,8 +270,14 @@ pHdb MakeHipadabaNode(char *name, int datatype, int length); */ void AddHipadabaChild(pHdb parent, pHdb child, void *callData); /** - * delete a hipadaba node and all its children - * @parma node The node to delete + * Delete only the node data, without invoking any callbacks + * @param node The node to delete. + */ +void DeleteNodeData(pHdb node); +/** + * delete a hipadaba node and all its children. Then invoke the tree + * change callback to notify listeners. + * @param node The node to delete * @param callData User data for the tree change callback */ void DeleteHipadabaNode(pHdb node, void *callData); @@ -220,15 +303,16 @@ pHdb GetHipadabaNode(pHdb root, char *path); char *GetHipadabaPath(pHdb node); /** * removes a node from the parents child list. - * @node the node to remove + * @param node the node to remove * @param callData User data for the tree change callback */ void RemoveHdbNodeFromParent(pHdb node, void *callData); /** - * delete a callback chain - * @param root The callback chain to delete + * count the numbers of children in thie Hdb node + * @param node The node to count children for + * @return The number of children */ -void DeleteCallbackChain(pHdbCallback root); +int CountHdbChildren(pHdb node); /*===================== function protoypes: Callbacks ========================*/ /** * make a new hipdaba callback @@ -236,42 +320,50 @@ void DeleteCallbackChain(pHdbCallback root); * @param userData userData to be associated with this callback. Can be NULL. * @param killFunc A function for freeing the userData. Can be NULL, then it will * not be invoked - * @param id An ID associated with this callback - * @param internalID Another ID to be associated with this callback. ID's come in - * useful when callbacks have to be deleted in a later stage. - * @return A new suitabvly initialised callback structure or NULL when required elements + * @return A new suitabaly initialised callback structure or NULL when required elements * are missing or there is nor memory. */ pHdbCallback MakeHipadabaCallback(hdbCallbackFunction func, - void *userData, killUserData killFunc, - int id, int internalID); + void *userData, killUserData killFunc); /** * add a callback at the end of the callback chain * @param node The node to which to append the callback - * @param type the type of the callback to append * @param newCB The callback to append */ -void AppendHipadabaCallback(pHdb node,int type, pHdbCallback newCB); +void AppendHipadabaCallback(pHdb node,pHdbCallback newCB); /** * add a callback at the head of the callback chain * @param node The node to which to append the callback - * @param type the type of the callback to append * @param newCB The callback prepend */ -void PrependHipadabaCallback(pHdb node, int type, pHdbCallback newCB); +void PrependHipadabaCallback(pHdb node,pHdbCallback newCB); /** - * remove recursively all callbacks witch match the id - * @param root The starting node from where to start removing callbacks - * @param id The ID callbacks have to match in order to be removed. + * find the callback data + * @param node the node from where callbacks have to be searched + * @param userPtr A pointer to some user data which the callback + * uses to determine if it is the right one. + * @return the found callback user data or NULL on failure */ -void RemoveHipadabaCallback(pHdb root, int id); +void *FindHdbCallbackData(pHdb node, void *userPtr); /** - * remove recursively all callbacks witch match the internal id - * @param root The starting node from where to start removing callbacks - * @param internalID The internal ID callbacks have to match in order to be removed. + * invoke a callback chain. + * @param node The node reponsible for this callback chain + * @param message the message to send + * @return 1 on success, 0 on failure */ -void InternalRemoveHipadabaCallback(pHdb root, int internalID); - +int InvokeCallbackChain(pHdb node, pHdbMessage message); +/** + * Deletes the callback chain of a node. This is internal, normal users + * should not use this function. Or you create a mess! + * @param node The node + */ +void DeleteCallbackChain(pHdb node); +/** + * apply message to the node and all its children + * @param node Th node where to start recursing + * @param message The message to send + */ +void RecurseCallbackChains(pHdb node, pHdbMessage message); /*============== Parameter Handling ===============================*/ /** * Set a hipadaba parameter. This is an external set for a parameter. It may cause @@ -291,6 +383,14 @@ int SetHipadabaPar(pHdb node, hdbValue v, void *callData); * @return 0 on failure, 1 on success */ int UpdateHipadabaPar(pHdb node, hdbValue v, void *callData); +/** + * notify any update listeners that this node has been internally modifed. + * @param node The node modified + * @param callData Addtional data for the callback + * @return 1 on success, 0 on failure + */ +int NotifyHipadabaPar(pHdb node,void *callData); + /** * Read a hipadaba parameter * @param node The node for which to read the parameter @@ -299,42 +399,6 @@ int UpdateHipadabaPar(pHdb node, hdbValue v, void *callData); * @return 0 on failure, 1 on success */ int GetHipadabaPar(pHdb node, hdbValue *v, void *callData); -/** - * Set a hipadaba parameter. This is an external set for a parameter. It may cause - * motors to start driving etc. - * @param node The node for which to set the parameter - * param dataType The datatype the value ought to have - * @param data A pointer to the data to set. - * @param length The length of data - * @param callData Additonal context data to be passed to the callback functions - * @return 0 on failure, a negative error code on failure - */ -int SetHdbPar(pHdb node, int dataType, void *data, int length, - void *callData); -/** - * Updates a hipadaba parameter. This does not cause an active parameter to - * start driving but invokes all notifications which may be registered on - * this parameter. - * @param node The node for which to set the parameter - * param dataType The datatype the value ought to have - * @param data A pointer to the data to set. - * @param length The length of data - * @param callData Additonal context data to be passed to the callback functions - * @return 0 on failure, a negative error code on failure - */ -int UpdateHdbPar(pHdb node, int dataType, void *data, int length, - void *callData); -/** - * Read a hipadaba parameter - * @param node The node for which to read the parameter - * @param dataType The expected type of the data - * @param data A pointer to which data will be copied - * @param length The length of data. - * @param callData Additonal context data to be passed to the callback functions - * @return 0 on failure, a negative error code on failures. - */ -int GetHdbPar(pHdb node, int dataType, void *data, int length, - void *callData); /*================================ Property Interface ==============================================*/ /** * set a property @@ -352,6 +416,14 @@ int GetHdbPar(pHdb node, int dataType, void *data, int length, * @return 0 on failure, 1 on success */ int GetHdbProperty(pHdb node, char *key, char *value, int len); + /** + * get the value of a property + * @param node The node to get the property from + * @param key The properties key + * @return the property or NULL on failure. Warning: the string is + * only valid as long as the property has not changed + */ + char *GetHdbProp(pHdb node, char *key); /** * initialize a property scan on this node * @param node The node for which to scan properties diff --git a/histmem.c b/histmem.c index ab8386c7..510b882e 100644 --- a/histmem.c +++ b/histmem.c @@ -834,7 +834,7 @@ void HistDirty(pHistMem self) return 0; } - if(iEnd > iDataLen/sizeof(HistInt)) + if( (iEnd -iStart) > iDataLen/sizeof(HistInt)) { SCWrite(pCon,"WARNING: truncating request to fit data space",eWarning); iEnd = (iDataLen/sizeof(HistInt)) - 1; @@ -1138,7 +1138,7 @@ static int checkHMEnd(pHistMem self, char *text){ return 0; } memset(pBuf,0,iRet+60); - HistGetOption(self,argv[2],pBuf,iRet); + HistGetOption(self,argv[2],pBuf,iRet+60); sprintf(pBueffel,"%s.%s = %s",argv[0],argv[2],pBuf); SCWrite(pCon,pBueffel,eValue); free(pBuf); diff --git a/histogram.tex b/histogram.tex index ce8e30ab..564af499 100644 --- a/histogram.tex +++ b/histogram.tex @@ -21,7 +21,7 @@ $\langle$Modes {\footnotesize ?}$\rangle\equiv$ \mbox{}\verb@ ePSD,@\\ \mbox{}\verb@ eSANSTOF@\\ \mbox{}\verb@ } HistMode;@\\ -\mbox{}\verb@@$\diamond$ +\mbox{}\verb@@$\Diamond$ \end{list} \vspace{-1ex} \footnotesize\addtolength{\baselineskip}{-1ex} @@ -59,7 +59,7 @@ $\langle$Modes {\footnotesize ?}$\rangle\equiv$ \mbox{}\verb@ eOCount,@\\ \mbox{}\verb@ eReflect@\\ \mbox{}\verb@ } OverFlowMode;@\\ -\mbox{}\verb@@$\diamond$ +\mbox{}\verb@@$\Diamond$ \end{list} \vspace{-1ex} \footnotesize\addtolength{\baselineskip}{-1ex} @@ -176,7 +176,7 @@ $\langle$HistType {\footnotesize ?}$\rangle\equiv$ \mbox{}\verb@ int (*FreePrivate)(pHistDriver self);@\\ \mbox{}\verb@ void *pPriv;@\\ \mbox{}\verb@ } HistDriver;@\\ -\mbox{}\verb@@$\diamond$ +\mbox{}\verb@@$\Diamond$ \end{list} \vspace{-1ex} \footnotesize\addtolength{\baselineskip}{-1ex} @@ -279,7 +279,9 @@ $\langle$HistDrivProt {\footnotesize ?}$\rangle\equiv$ \mbox{}\verb@ void DeleteHistDriver(pHistDriver self);@\\ \mbox{}\verb@ int HistDriverConfig(pHistDriver self, pStringDict pOpt,@\\ \mbox{}\verb@ SConnection *pCon);@\\ -\mbox{}\verb@@$\diamond$ +\mbox{}\verb@ HistInt *DefaultSubSample(pHistDriver self, SConnection *pCon, @\\ +\mbox{}\verb@ int bank, char *command); @\\ +\mbox{}\verb@@$\Diamond$ \end{list} \vspace{-1ex} \footnotesize\addtolength{\baselineskip}{-1ex} @@ -318,7 +320,7 @@ $\langle$HistST {\footnotesize ?}$\rangle\equiv$ \mbox{}\verb@ pICountable pCountInt;@\\ \mbox{}\verb@ pICallBack pCall;@\\ \mbox{}\verb@ } HistMem;@\\ -\mbox{}\verb@@$\diamond$ +\mbox{}\verb@@$\Diamond$ \end{list} \vspace{-1ex} \footnotesize\addtolength{\baselineskip}{-1ex} @@ -360,7 +362,7 @@ $\langle$Protos {\footnotesize ?}$\rangle\equiv$ \mbox{}\verb@@\\ \mbox{}\verb@ pHistMem CreateHistMemory(char *drivername);@\\ \mbox{}\verb@ void DeleteHistMemory(void *self);@\\ -\mbox{}\verb@@$\diamond$ +\mbox{}\verb@@$\Diamond$ \end{list} \vspace{-1ex} \footnotesize\addtolength{\baselineskip}{-1ex} @@ -390,7 +392,7 @@ $\langle$Protos {\footnotesize ?}$\rangle\equiv$ \mbox{}\verb@ int HistGetOption(pHistMem self, char *name, char *result, int iResultLen);@\\ \mbox{}\verb@ int HistSetOption(pHistMem self, char *name, char *value);@\\ \mbox{}\verb@ int HistConfigure(pHistMem self, SConnection *pCon, SicsInterp *pSics);@\\ -\mbox{}\verb@@$\diamond$ +\mbox{}\verb@@$\Diamond$ \end{list} \vspace{-1ex} \footnotesize\addtolength{\baselineskip}{-1ex} @@ -441,7 +443,7 @@ $\langle$Protos {\footnotesize ?}$\rangle\equiv$ \mbox{}\verb@ int HistBlockCount(pHistMem self, SConnection *pCon);@\\ \mbox{}\verb@ void HistDirty(pHistMem self); @\\ \mbox{}\verb@@\\ -\mbox{}\verb@@$\diamond$ +\mbox{}\verb@@$\Diamond$ \end{list} \vspace{-1ex} \footnotesize\addtolength{\baselineskip}{-1ex} @@ -481,7 +483,7 @@ $\langle$Protos {\footnotesize ?}$\rangle\equiv$ \mbox{}\verb@ int i, int iStart, int iEnd, @\\ \mbox{}\verb@ HistInt *lData, int iDataLen);@\\ \mbox{}\verb@ int PresetHistogram(pHistMem self, SConnection *pCon, HistInt lVal);@\\ -\mbox{}\verb@@$\diamond$ +\mbox{}\verb@@$\Diamond$ \end{list} \vspace{-1ex} \footnotesize\addtolength{\baselineskip}{-1ex} @@ -535,7 +537,7 @@ $\langle$Protos {\footnotesize ?}$\rangle\equiv$ \mbox{}\verb@ int HistAction(SConnection *pCon, SicsInterp *pSics, void *pData,@\\ \mbox{}\verb@ int argc, char *argv[]);@\\ \mbox{}\verb@ @\\ -\mbox{}\verb@@$\diamond$ +\mbox{}\verb@@$\Diamond$ \end{list} \vspace{-1ex} \footnotesize\addtolength{\baselineskip}{-1ex} @@ -597,7 +599,7 @@ following. \mbox{}\verb@@$\langle$Protos {\footnotesize ?, \ldots\ }$\rangle$\verb@@\\ \mbox{}\verb@@\\ \mbox{}\verb@#endif@\\ -\mbox{}\verb@@$\diamond$ +\mbox{}\verb@@$\Diamond$ \end{list} \vspace{-2ex} \end{minipage}\\[4ex] @@ -623,7 +625,7 @@ following. \mbox{}\verb@@$\langle$HistDrivProt {\footnotesize ?}$\rangle$\verb@@\\ \mbox{}\verb@@\\ \mbox{}\verb@#endif@\\ -\mbox{}\verb@@$\diamond$ +\mbox{}\verb@@$\Diamond$ \end{list} \vspace{-2ex} \end{minipage}\\[4ex] @@ -646,7 +648,7 @@ following. \mbox{}\verb@@$\langle$HistST {\footnotesize ?}$\rangle$\verb@@\\ \mbox{}\verb@@\\ \mbox{}\verb@#endif@\\ -\mbox{}\verb@@$\diamond$ +\mbox{}\verb@@$\Diamond$ \end{list} \vspace{-2ex} \end{minipage}\\[4ex] diff --git a/histogram.w b/histogram.w index d59edabf..a5bed0e9 100644 --- a/histogram.w +++ b/histogram.w @@ -234,6 +234,8 @@ only these few functions operate on histogram memory drivers in general: void DeleteHistDriver(pHistDriver self); int HistDriverConfig(pHistDriver self, pStringDict pOpt, SConnection *pCon); + HistInt *DefaultSubSample(pHistDriver self, SConnection *pCon, + int bank, char *command); @} CreateHistDriver creates a new HistDriver data structure and returns it. Or diff --git a/histsim.c b/histsim.c index 5ddc574f..98eab3df 100644 --- a/histsim.c +++ b/histsim.c @@ -204,7 +204,13 @@ int i, int iStart, int iEnd, HistInt *lData) { iSet = 2; + if(self->data->localBuffer == NULL){ + resizeBuffer(self->data); + } iSetVal = lData[0]; + if(iEnd <= getHMDataLength(self->data)){ + memcpy(self->data->localBuffer+iStart,lData,(iEnd - iStart)*sizeof(HistInt)); + } return 1; } @@ -244,6 +250,21 @@ return pDriv->fTime; } +/*-------------------------------------------------------------------------*/ +HistInt *DefaultSubSample(pHistDriver self, SConnection *pCon, + int bank, char *command){ + HistInt *data = NULL; + char error[132]; + + assert(bank == 0); /* no bank handling yet.. */ + + memset(error,0,132*sizeof(char)); + data = subSample(self->data, command, error, 132); + if(data == NULL){ + SCWrite(pCon,error,eError); + } + return data; +} /*-------------------------------------------------------------------------*/ pHistDriver CreateSIMHM(pStringDict pOpt) { @@ -280,6 +301,7 @@ pNew->FreePrivate = SimFreePrivate; pNew->Pause = SimPause; pNew->Continue = SimContinue; + pNew->SubSample = DefaultSubSample; StringDictAddPair(pOpt,"failrate","-1"); return pNew; diff --git a/hkl.c b/hkl.c index d40176d9..4351f20c 100644 --- a/hkl.c +++ b/hkl.c @@ -52,7 +52,10 @@ return 1; } fprintf(fd,"#Crystallographic Settings\n"); - fprintf(fd,"%s lambda %f\n",name, self->fLambda); + if(self->iManual == 1) + { + fprintf(fd,"%s lambda %f\n",name, self->fLambda); + } fprintf(fd, "%s setub %8.6f %8.6f %8.6f %8.6f %8.6f %8.6f %8.6f %8.6f %8.6f\n", name, @@ -1296,6 +1299,9 @@ ente: double z1[3]; int i; + if(self->UBinv == NULL){ + return 0; + } z1FromAngles(self->fLambda,tth,om,chi,phi,z1); z1m = vectorToMatrix(z1); /* multiply with UBinv in order to yield HKL */ diff --git a/hmdata.c b/hmdata.c index bd514289..627fae56 100644 --- a/hmdata.c +++ b/hmdata.c @@ -16,10 +16,12 @@ #include "splitter.h" #include "fortify.h" #include "hmdata.h" +#include #include "HistMem.h" #include "HistMem.i" #include "HistDriv.i" #include "countdriv.h" +#include "stptok.h" /*----------------------------------------------------------------------*/ pHMdata makeHMData(void) { pHMdata self = NULL; @@ -484,4 +486,155 @@ int loadHMData(pHMdata self, SConnection *pCon, char *filename){ fclose(fd); return 1; } +/*========================================================================== + * subsampling was stolen from the SinqHTTP histogram memory code and + * thus contains some additional indirections. + * =========================================================================*/ +static pNXDS hmDataToNXDataset(pHMdata self){ + pNXDS result = NULL; + int i; + + result = malloc(sizeof(NXDS)); + if(result == NULL){ + return NULL; + } + memset(result,0,sizeof(NXDS)); + result->magic = MAGIC; + result->type = NX_INT32; + result->rank = self->rank; + if(isInTOFMode(self)){ + result->rank++; + } + result->dim = malloc(self->rank*sizeof(int)); + if(result->dim == NULL){ + free(result); + return NULL; + } + for(i = 0; i < self->rank; i++){ + result->dim[i] = self->iDim[i]; + } + if(isInTOFMode(self)){ + result->dim[result->rank-1] = getNoOfTimebins(self); + } + if(self->localBuffer == NULL){ + resizeBuffer(self); + } + result->u.iPtr = self->localBuffer; + return result; +} +/*---------------------------------------------------------------------------*/ +static pNXDS subSampleCommand(pNXDS source, char *command, + char *error, int errLen){ + int startDim[NX_MAXRANK], endDim[NX_MAXRANK]; + int dim = 0, start = 0, i; + char *pPtr = NULL, token[80]; + + pPtr = stptok(command,token,79,":\0"); + while((pPtr = stptok(pPtr,token,79,":\0")) != NULL){ + if(start == 0){ + startDim[dim] = atoi(token); + start = 1; + } else { + endDim[dim] = atoi(token); + start = 0; + dim++; + } + } + + if(dim < source->rank - 1){ + strncpy(error,"ERROR: Not enough border values specified for subsampling",errLen); + return NULL; + } + for(i = 0; i < source->rank; i++){ + if(startDim[i] < 0 || startDim[i] >= source->dim[i]){ + snprintf(error,errLen,"ERROR: invalid start value %d for dimension %d", startDim[1], i); + return NULL; + } + if(endDim[i] < startDim[i] || endDim[i] >= source->dim[i]){ + snprintf(error,errLen,"ERROR: invalid end value %d for dimension %d", endDim[1], i); + return NULL; + } + } + + return cutNXDataset(source,startDim,endDim); +} +/*-----------------------------------------------------------------------------*/ +static pNXDS sumCommand(pNXDS source, char *command, char *error, int errlen){ + int dimNo = -1, start = -1, end = -1; + char *pPtr = NULL; + char token[80]; + + pPtr = stptok(command,token,79,":\0"); + pPtr = stptok(pPtr,token,79,":\0"); + if(pPtr != NULL){ + dimNo = atoi(token); + } + pPtr = stptok(pPtr,token,79,":\0"); + if(pPtr != NULL){ + start = atoi(token); + } + pPtr = stptok(pPtr,token,79,":\0"); + if(pPtr != NULL){ + end = atoi(token); + } + if(dimNo < 0 || dimNo > source->rank - 1){ + snprintf(error,errlen,"ERROR: invalid dimension %d requestd to sum", dimNo); + return NULL; + } + if(end < 0 || end > source->dim[dimNo] || start < 0 || start > end){ + snprintf(error,errlen,"ERROR: invalid summing limits %d to %d requested", start,end); + return NULL; + } + + return sumNXDataset(source,dimNo, start, end); + } +/*--------------------------------------------------------------------------*/ +HistInt *subSample(pHMdata self, char *command, + char *error, int errLen){ + pNXDS source = NULL, start = NULL; + pNXDS result = NULL; + char *pPtr = NULL; + char subCommand[132]; + HistInt *data = NULL; + int length; + + + start = hmDataToNXDataset(self); + if(start == NULL){ + strncpy(error,"Out-Of-Memory or no data while subsampling ", + errLen); + return NULL; + } + + source = start; + pPtr = command; + while((pPtr = stptok(pPtr,subCommand,131,";\0\r\n")) != NULL){ + if(strstr(subCommand,"sample") != NULL){ + result = subSampleCommand(source,subCommand,error, errLen); + } else if(strstr(subCommand,"sum") != NULL){ + result = sumCommand(source,subCommand,error, errLen); + } else { + strncpy(error,"ERROR: invalid subcommand to process requested",errLen); + return NULL; + } + if(result == NULL){ + return NULL; + } + if(source != start){ + dropNXDataset(source); + } + source = result; + } + length = getNXDatasetLength(result); + data = malloc((length+1)*sizeof(int)); + if(data == NULL){ + strncpy(error,"Out-Of-Mmeory in Subsample", errLen); + dropNXDataset(result); + return NULL; + } + data[0] = length; + memcpy(data+1,result->u.iPtr, length*sizeof(int)); + dropNXDataset(result); + return data; +} diff --git a/hmdata.h b/hmdata.h index 2352b407..ebacd051 100644 --- a/hmdata.h +++ b/hmdata.h @@ -60,6 +60,8 @@ int start[MAXDIM], int end[MAXDIM]); int loadHMData(pHMdata self, SConnection *pCon, char *filename); + HistInt *subSample(pHMdata self, char *command, + char *error, int errLen); #endif diff --git a/hmslave.c b/hmslave.c new file mode 100644 index 00000000..0a59538f --- /dev/null +++ b/hmslave.c @@ -0,0 +1,293 @@ +/** + * This is a histogram memory driver for a slave histogram. This is for + * supporting multiple banks of histogram memory data in one physical + * histogram memory, possibly with different dimensions. On HM will connect + * to the physical histogram memory server and configure and control it and + * also handle bank 0. Other HM's may use this slave drive to to connect to + * the main HM for retrieving further banks. Thus this HM just becomes a + * data container for bank data. And this is the driver for such slave HM's. + * It mostly implements empty functions as control is through the main HM. The + * execption is data loading which will load the associated bank from the + * main HM. + * + * This is as of March 2007 defunct. The reason is that there are problems + * with buffering the data. + * + * copyright: see file COPYRIGHT + * + * Mark Koennecke, March 2007 + */ +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct { + pHistMem master; + int bank; + }*HMSlave, sHMSlave; +/*------------------------------------------------------------------- + Configures the HM from the options in pOpt and the HM data structure + Returns 1 on success, 0 on failure +---------------------------------------------------------------------*/ +static int HMSlaveConfigure(pHistDriver self, SConnection *pCon, + pStringDict pOpt, SicsInterp *pSics){ + HMSlave pPriv = NULL; + char buffer[80], error[256]; + + pPriv =(HMSlave)self->pPriv; + + if(StringDictGet(pOpt,"master",buffer, 79) == 1){ + pPriv->master = (pHistMem)FindCommandData(pServ->pSics,buffer,"HistMem"); + if(pPriv->master == NULL){ + snprintf(error,255,"ERROR: failed to find master HM %s", buffer); + SCWrite(pCon,error,eError); + return 0; + } + } else { + SCWrite(pCon,"ERROR: required configuration option master missing", + eError); + return 0; + } + + if(StringDictGet(pOpt,"bank",buffer, 79) == 1){ + pPriv->bank = atoi(buffer); + } else { + SCWrite(pCon,"ERROR: required configuration option bank missing", + eError); + return 0; + } + + return 1; +} +/*-------------------------------------------------------------------- + Start histogramming, Returns HWFault on failure, 1 on success +----------------------------------------------------------------------*/ +static int HMSlaveStart(pHistDriver self,SConnection *pCon){ + HMSlave pPriv = NULL; + + pPriv =(HMSlave)self->pPriv; + return 1; +} +/*-------------------------------------------------------------------- + Stops histogramming, Returns HWFault on failure, 1 on success +----------------------------------------------------------------------*/ +static int HMSlaveHalt(pHistDriver self){ + HMSlave pPriv = NULL; + + pPriv =(HMSlave)self->pPriv; + return 1; +} +/*-------------------------------------------------------------------- + Checks histogramming status, Returns HWFault on failure, + HWIdle when finished, HWBusy when counting +----------------------------------------------------------------------*/ +static int HMSlaveCountStatus(pHistDriver self,SConnection *pCon){ + HMSlave pPriv = NULL; + + pPriv =(HMSlave)self->pPriv; + return HWIdle; +} +/*-------------------------------------------------------------------- + Get info on error after last HWFault, returns 1 always. + Puts an int error code into *code and errLen chars of + error description into error +----------------------------------------------------------------------*/ +static int HMSlaveGetError(pHistDriver self,int *code, + char *error, int errLen){ + HMSlave pPriv = NULL; + + pPriv =(HMSlave)self->pPriv; + strncpy(error,"Weird status: slaves do not err..",errLen); + *code = -77; + return 1; +} +/*-------------------------------------------------------------------- + Try to fix the HM error in code. Returns COREDO when the last + operation needs to be redone, COTERM when the error cannot be + fixed. +----------------------------------------------------------------------*/ +static int HMSlaveFixIt(pHistDriver self,int code){ + HMSlave pPriv = NULL; + + pPriv =(HMSlave)self->pPriv; + return COTERM; +} +/*-------------------------------------------------------------------- + GetData reads updates the internal cache of monitor values + from the hardware, Returns 1 or HWFault +----------------------------------------------------------------------*/ +static int HMSlaveGetData(pHistDriver self,SConnection *pCon){ + HMSlave pPriv = NULL; + + pPriv =(HMSlave)self->pPriv; + return 1; +} +/*-------------------------------------------------------------------- + GetMonitor reads the monitor value i. Returns either the monitor + value or -9999 if no such monitor exists or an error occurred +----------------------------------------------------------------------*/ +static long HMSlaveGetMonitor(pHistDriver self,int i, SConnection *pCon){ + HMSlave pPriv = NULL; + + pPriv =(HMSlave)self->pPriv; + return -9999; +} +/*-------------------------------------------------------------------- + GetTime reads the total counting time. Returns either the + value or -9999.99 if no such value exists or an error occurred +----------------------------------------------------------------------*/ +static float HMSlaveGetTime(pHistDriver self,SConnection *pCon){ + HMSlave pPriv = NULL; + + pPriv =(HMSlave)self->pPriv; + return -9999.99; +} +/*-------------------------------------------------------------------- + Pause histogramming, Returns HWFault on failure, 1 on success +----------------------------------------------------------------------*/ +static int HMSlavePause(pHistDriver self,SConnection *pCon){ + HMSlave pPriv = NULL; + + pPriv =(HMSlave)self->pPriv; + return 1; +} +/*-------------------------------------------------------------------- + Continue histogramming, Returns HWFault on failure, 1 on success +----------------------------------------------------------------------*/ +static int HMSlaveContinue(pHistDriver self,SConnection *pCon){ + HMSlave pPriv = NULL; + + pPriv =(HMSlave)self->pPriv; + return 1; +} +/*-------------------------------------------------------------------- + Free the data associated with the private data structure of the driver +----------------------------------------------------------------------*/ +static int HMSlaveFree(pHistDriver self){ + HMSlave pPriv = NULL; + + pPriv =(HMSlave)self->pPriv; + if(pPriv != NULL){ + free(pPriv); + } + self->pPriv = NULL; + return 1; +} +/*------------------------------------------------------------------- + * fixTimebinning assures that our time binning dn the masters + * time binning are the same. So that diemsnions are right + * ------------------------------------------------------------------*/ + static int fixTimeBinning(pHistDriver self, SConnection *pCon){ + HMSlave pPriv = NULL; + + pPriv =(HMSlave)self->pPriv; + if(isInTOFMode(pPriv->master->pDriv->data) && + getNoOfTimebins(pPriv->master->pDriv->data) != + getNoOfTimebins(self->data)){ + self->data->tofMode = 1; + self->data->nTimeChan = getNoOfTimebins(pPriv->master->pDriv->data); + if(!resizeBuffer(self->data)) { + SCWrite(pCon, + "ERROR: out of memory allocating HMData for slave", + eError); + return 0; + } + } + return 1; + } +/*-------------------------------------------------------------------- + Set The HM data or a subset of it. Returns HWFault or 1 +----------------------------------------------------------------------*/ +static int HMSlaveSetHistogram(pHistDriver self, + SConnection *pCon, + int i, int iStart, int iEnd, HistInt *pData){ + HMSlave pPriv = NULL; + HistInt *start = NULL; + + pPriv =(HMSlave)self->pPriv; + if(fixTimeBinning(self,pCon) == 1){ + start = self->data->localBuffer + iStart; + memcpy(start,pData,(iEnd - iStart)*sizeof(HistInt)); + return 1; + } else { + return 0; + } +} +/*-------------------------------------------------------------------- + Set HM to a preset value, Returns HWFault on failure, 1 on success +----------------------------------------------------------------------*/ +static int HMSlavePreset(pHistDriver self,SConnection *pCon, + HistInt value){ + HMSlave pPriv = NULL; + int i; + + pPriv =(HMSlave)self->pPriv; + if(fixTimeBinning(self,pCon) == 1){ + for(i = 0; i < getHMDataLength(self->data); i++){ + self->data->localBuffer[i] = value; + } + return 1; + } else { + return 0; + } +} +/*-------------------------------------------------------------------- + get The HM data or a subset of it. Returns HWFault or 1 +----------------------------------------------------------------------*/ +static int HMSlaveGetHistogram(pHistDriver self, + SConnection *pCon, + int i, int iStart, int iEnd, HistInt *pData){ + HMSlave pPriv = NULL; + + pPriv = (HMSlave)self->pPriv; + return pPriv->master->pDriv->GetHistogram(pPriv->master->pDriv, + pCon, pPriv->bank, iStart, iEnd, pData); +} +/*-------------------------------------------------------------------- + Make the HMDriver, returns a driver or NULL on failure +----------------------------------------------------------------------*/ +pHistDriver MakeHMSlaveHM(pStringDict pOption){ + pHistDriver pNew = NULL; + HMSlave pPriv = NULL; + + /* create the general driver */ + pNew = CreateHistDriver(pOption); + if(!pNew){ + return NULL; + } + + /*Create private data structure*/ + pPriv = (HMSlave)malloc(sizeof(sHMSlave)); + if(pPriv == NULL){ + return NULL; + } + pNew->pPriv = pPriv; + + /* add our options */ + StringDictAddPair(pOption,"master","unknown"); + StringDictAddPair(pOption,"bank","1"); + + /* configure all those functions */ + pNew->Configure = HMSlaveConfigure; + pNew->Start = HMSlaveStart; + pNew->Halt = HMSlaveHalt; + pNew->GetCountStatus = HMSlaveCountStatus; + pNew->GetError = HMSlaveGetError; + pNew->TryAndFixIt = HMSlaveFixIt; + pNew->GetData = HMSlaveGetData; + pNew->GetHistogram = HMSlaveGetHistogram; + pNew->SetHistogram = HMSlaveSetHistogram; + pNew->GetMonitor = HMSlaveGetMonitor; + pNew->GetTime = HMSlaveGetTime; + pNew->Preset = HMSlavePreset; + pNew->FreePrivate = HMSlaveFree; + pNew->Pause = HMSlavePause; + pNew->Continue = HMSlaveContinue; + + return pNew; +} diff --git a/ifile.c b/ifile.c index 458d41b0..04640f5e 100644 --- a/ifile.c +++ b/ifile.c @@ -49,11 +49,12 @@ static IPair *CreateNewEntry(char *name, char *val, IPair *pN) { - IPair *pRes; + IPair *pRes = NULL; pRes = (IPair *)malloc(sizeof(IPair)); if(!pRes) return NULL; + memset(pRes,0,sizeof(IPair)); if(name) pRes->name = strdup(name); if(val) diff --git a/initializer.c b/initializer.c index 813b884b..4c8ee024 100644 --- a/initializer.c +++ b/initializer.c @@ -9,12 +9,13 @@ Markus Zolliker, March 2005 #include "sics.h" #include "initializer.h" +#include "splitter.h" typedef struct Item { struct Item *next; - char *type; - char *name; - char *desc; + char *type; /* "Object" for all commands created by makeobject, else something more general */ + char *name; /* the name for identifying an initializer */ + char *desc; /* a description of the initializer. not the same as pObjectDescriptor->name */ Initializer maker; int startupOnly; } Item; @@ -39,8 +40,8 @@ void MakeInitializer(const char *type, const char *name, Initializer maker, Initializer GetInitializer(const char *type, const char *name) { Item *p, **last; - - if (startup && pServ->pReader != NULL) { + + if (startup && !ServerIsStarting(pServ)) { /* pServ->pReader exists: startup finished */ startup = 0; /* remove startup initializers */ @@ -57,12 +58,10 @@ Initializer GetInitializer(const char *type, const char *name) { } } } - p = list; - while (p != NULL && (strcasecmp(p->name, name) != 0 || strcasecmp(p->type, type) != 0)) { - p = p->next; - } - if (p) { - return p->maker; + for (p = list; p != NULL; p = p->next) { + if (strcasecmp(p->name, name) == 0 && strcasecmp(p->type, type) == 0) { + return p->maker; + } } return NULL; } @@ -70,17 +69,15 @@ Initializer GetInitializer(const char *type, const char *name) { static int MakeObject(SConnection *con, SicsInterp *sics, void *data, int argc, char *argv[]) { CmdInitializer cmdin; - CommandList *command; - char *className; if (argc < 3) { - SCPrintf(con, eError, "%s needs more arguments", argv[0]); + SCPrintf(con, eError, "ERROR: should be: %s ...", argv[0]); return 0; } cmdin = (CmdInitializer)GetInitializer("Object", argv[2]); if (cmdin) { - return cmdin(con, argc, argv, ! startup); + return cmdin(con, argc, argv, strcasecmp(argv[0],"makeobject") == 0); } else { SCPrintf(con, eError, "do not know how to make a %s object", argv[2]); return 0; @@ -124,23 +121,43 @@ static int DriverList(SConnection *con, SicsInterp *sics, static int RemoveObject(SConnection *con, SicsInterp *sics, void *data, int argc, char *argv[]) { CmdInitializer cmdin; - CommandList *command; + ObjectDescriptor *desc; char *className; + char shortClassName[32]; + char *p; + int removeAllowed; + char *creationCommand; if (argc != 2) { - SCPrintf(con, eError, "%s needs 1 argument", argv[0]); + SCPrintf(con, eError, "ERROR: should be: %s ", argv[0]); return 0; } - command = FindCommand(sics, argv[1]); - if (!command) { + desc = FindCommandDescriptor(sics, argv[1]); + if (!desc) { SCPrintf(con, eError, "ERROR: %s not found", argv[1]); return 0; } - className = ((pDummy)command->pData)->pDescriptor->name; - cmdin = (CmdInitializer)GetInitializer("Object", className); - if (cmdin) { - /* if we have an initializer, we are allowed to remove */ + + creationCommand = GetDescriptorKey(desc, "creationCommand"); + if (creationCommand != NULL) { + /* if there is a creationCommand, we are allowed to remove */ + removeAllowed = 1; + } else { + /* if we have an initializer: we are also allowed to remove */ + className = desc->name; + cmdin = (CmdInitializer)GetInitializer("Object", className); + if (cmdin == 0) { + /* allow also a longer descriptor starting with the initializer name and a blank */ + p = strchr(className, ' '); + if (p) { + snprintf(shortClassName, sizeof shortClassName, "%.*s", p - className, className); + cmdin = (CmdInitializer)GetInitializer("Object", shortClassName); + } + } + removeAllowed = (cmdin != NULL); + } + if (removeAllowed) { if (pServ->pExecutor && isInRunMode(pServ->pExecutor)) { SCPrintf(con, eError, "ERROR: cannot remove %s while running", argv[1]); return 0; @@ -154,6 +171,82 @@ static int RemoveObject(SConnection *con, SicsInterp *sics, } } +typedef struct { + int printHeader; + FILE *fil; +} SaveData; + +static int SaveCreationCommand(char *name, pDummy object, void *userData) { + SaveData *saveData = userData; + char *creationCommand; + + creationCommand = GetDescriptorKey(object->pDescriptor, "creationCommand"); + if (creationCommand && strcmp(creationCommand, "0") != 0) { + if (saveData->printHeader == 0) { + saveData->printHeader = 1; + fprintf(saveData->fil, "\n#--- BEGIN creation commands\n"); + } + fprintf(saveData->fil, "%s\n", creationCommand); + } + return 1; +} + +static int SaveCreationCommands(void *object, char *name, FILE *fil) { + SaveData saveData; + + saveData.fil = fil; + saveData.printHeader = 0; + ForEachCommand(SaveCreationCommand, &saveData); + if (saveData.printHeader == 1) { + fprintf(fil, "#--- END creation commands\n\n"); + } + return 1; +} + +static int CreationCommand(SConnection *con, SicsInterp *sics, + void *data, int argc, char *argv[]) { + CmdInitializer cmdin; + char *className; + char shortClassName[32]; + char *p; + int removeAllowed; + ObjectDescriptor *desc; + char *creationCommand; + char buf[256]; + + if (argc < 2) { + SCPrintf(con, eError, "ERROR: should be: %s []", argv[0]); + return 0; + } + + desc = FindCommandDescriptor(sics, argv[1]); + if (!desc) { + SCPrintf(con, eError, "ERROR: %s not found", argv[1]); + return 0; + } + creationCommand = GetDescriptorKey(desc, "creationCommand"); + if (argc < 3) { + if (creationCommand != NULL) { + SCPrintf(con, eValue, "%s", creationCommand); + } else { + SCPrintf(con, eValue, ""); + } + } else { + if (!creationCommand) { + SCPrintf(con, eValue, "ERROR: %s is a static object", argv[1]); + return 0; + } + creationCommand = Arg2Tcl(argc - 2, argv + 2, buf, sizeof buf); + if (creationCommand) { + SetDescriptorKey(desc, "creationCommand", creationCommand); + if (creationCommand != buf) free(creationCommand); + } else { + SetDescriptorKey(desc, "creationCommand", "0"); + } + } + return 1; +} + static void KillInitializers(void *data) { KillDummy(data); Item *item, *next; @@ -171,10 +264,17 @@ static void KillInitializers(void *data) { } void MakeDriver(const char *driver, CmdInitializer maker, int startupOnly, const char *desc) { - if (! FindCommand(pServ->pSics, "MakeObject")) { - AddCommandWithFlag(pServ->pSics, "MakeObject", MakeObject, KillInitializers, NULL, 0); - AddCommandWithFlag(pServ->pSics, "RemoveObject", RemoveObject, NULL, NULL, 0); - AddCommandWithFlag(pServ->pSics, "DriverList", DriverList, NULL, NULL, 0); - } MakeInitializer("Object", driver, (Initializer)maker, startupOnly, desc); } + +void InitializerInit(void) { + pDummy cc = NULL; + AddCommandWithFlag(pServ->pSics, "MakeObject", MakeObject, KillInitializers, NULL, 0); + AddCommandWithFlag(pServ->pSics, "MakeStaticObject", MakeObject, NULL, NULL, 0); + AddCommandWithFlag(pServ->pSics, "RemoveObject", RemoveObject, NULL, NULL, 0); + AddCommandWithFlag(pServ->pSics, "DriverList", DriverList, NULL, NULL, 0); + cc = CreateDummy("creation commands"); + cc->pDescriptor->SaveStatus = SaveCreationCommands; + AddCommandWithFlag(pServ->pSics, "CreationCommand", CreationCommand, + KillDummy, cc, 0); +} diff --git a/initializer.h b/initializer.h index 593f0d24..036a15a6 100644 --- a/initializer.h +++ b/initializer.h @@ -33,16 +33,19 @@ Initializer GetInitializer(const char *type, const char *name); type. */ +/* static int MakeObject(SConnection *con, SicsInterp *sics, void *data, int argc, char *argv[]); -/* + MakeObject has the following syntax: MakeObject objectName driver [ args ... ] It executes the initializer with the type "Object" and and the driver given as name. The found initalizer should use the given arguments - to create a driver. + to create a driver. Objects should be dynamic, i.e. there should be + a creation command in the status file, except when the creation command + was MakeStaticObject instead of MakeObject. */ @@ -52,7 +55,8 @@ typedef int (*CmdInitializer) (SConnection *pCon, int argc, char *argv[], int dy - pCon: the sics connection calling this initializer - argc: the total number of args - argv: the args (argv[0]: "MakeObject", argv[1]: object name, argv[3]: driver ...) - - dynamic: the initializer was called _after_ startup + - dynamic: 1, if the creation command was MakeObject, + 0, if the creation command was MakeStaticObject */ void MakeDriver(const char *driver, CmdInitializer maker, int startupOnly, diff --git a/lld_blob.c b/lld_blob.c index 1db5bafc..99e560bb 100644 --- a/lld_blob.c +++ b/lld_blob.c @@ -28,6 +28,21 @@ int LLDblobCreate( void ) return LLDcreate( sizeof( struct BlobDesc )); } +/*---------------------------------------------------------------------*/ +int LLDdeleteBlob(int List) +{ + struct BlobDesc Blob ; + int status; + + status = LLDnodePtr2First(List); + while(status == 1){ + LLDnodeDataTo( List, & Blob ); + free(Blob.data); + status = LLDnodePtr2Next(List); + } + LLDdelete(List); + return 1; +} /* ---- LL blob node mangement ---------------------------------------- */ int LLDblobInsert( int List, void * Source, unsigned Size ) diff --git a/lld_blob.h b/lld_blob.h index 56386eb8..56ceab06 100644 --- a/lld_blob.h +++ b/lld_blob.h @@ -20,7 +20,8 @@ int LLDblobCreate( void ); /* returns list number to use or -1 on failure. */ /* MUST be called before using a list of blobs. */ - +int LLDdeleteBlob(int List); + /* deletes a list and all its data */ /* ---- Node management -------------------------------------------------- Functions changing current node pointer to the new node. A return value of -1 indicates a memory allocation problem. diff --git a/logger.c b/logger.c new file mode 100644 index 00000000..1f9eed5f --- /dev/null +++ b/logger.c @@ -0,0 +1,369 @@ +/*--------------------------------------------------------------------------- +logger.c + +Markus Zolliker, Sept 2004 +---------------------------------------------------------------------------- +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "logger.h" + +struct Logger { + char *name; + char *old; + int oldsize; + int period; + time_t last, lastWrite; + int numeric; + int exact; + Logger *next; +}; + +static char *dir = NULL; +static Logger *list; +static time_t lastLife = 0; +static time_t lastWritten = 0; +/*--------------------------------------------------------------------------*/ +char *LoggerName(Logger *log) { + return log->name; +} +/*--------------------------------------------------------------------------*/ +void LoggerSetNumeric(Logger *log, int numeric) { + if (log) { + log->numeric = numeric; + } +} +/*--------------------------------------------------------------------------*/ +Logger *LoggerFind(const char *name) { + Logger *p; + p = list; + while (p != NULL) { + if (0==strcasecmp(name, p->name)) { + return p; + } + p = p->next; + } + return NULL; +} +/*--------------------------------------------------------------------------*/ +#define LASTLOGTXT "#last logging entry at:\n" + +time_t LoggerGetLastLife(char *dirarg) { + char path[256], line[32]; + FILE *fil; + time_t t = 0; + + if (dirarg == NULL) { + return lastWritten; + } + snprintf(path, sizeof path, "%s/lastlife.dat", dirarg); + fil = fopen(path, "r"); + if (fil) { + fgets(line, sizeof line, fil); + if (strcmp(line, LASTLOGTXT) == 0) { + fgets(line, sizeof line, fil); + t = atol(line); + if (t < 1000000000) { + printf("bad lastLife %ld\n", (long)t); + } + } + fclose(fil); + } else { + /* printf("can not read %s\n", path); */ + } + return t; +} + +/*--------------------------------------------------------------------------*/ +time_t LoggerSetDir(char *dirarg) { + dir = dirarg; + lastLife = LoggerGetLastLife(dir); + return lastLife; +} +/*--------------------------------------------------------------------------*/ +char *LoggerGetDir(void) { + char path[256]; + FILE *fil; + static time_t last; + + lastWritten = time(NULL); + if (lastWritten != last) { /* do not write more than once per second */ + snprintf(path, sizeof path, "%s/lastlife.dat", dir); + fil = fopen(path, "w"); + if (fil) { + fprintf(fil, "%s%ld\n", LASTLOGTXT, (long)lastWritten); + fclose(fil); + } else { + printf("can not write %s\n", path); + } + last = lastWritten; + } + return dir; +} +/*--------------------------------------------------------------------------*/ +int LoggerVarPath(char *dir, char *path, int pathLen, char *name, struct tm *t) { + int l; + + l = strlen(dir); + if (l + strlen(name) + 8 >= pathLen) { + path[0]='\0'; + return 0; + } + strcpy(path, dir); + strftime(path + l, pathLen - l, "/%Y/", t); + l += 6; + for (;*name != '\0'; name++, l++) { + path[l] = tolower(*name); + } + path[l] = '/'; l++; + path[l] = '\0'; + return l; +} +/*--------------------------------------------------------------------------*/ +int LoggerWrite0(Logger *log, time_t now, int period, char *value) { + char path[256], stim[32], buf[32]; + struct tm tm, lasttm; + int l, ext, writeInfo; + FILE *fil; + time_t beforenow; + + LoggerGetDir(); + if (dir == NULL) return 0; + if (now == 0) { + printf("now==0\n"); + } + lasttm = *localtime(&log->last); + tm = *localtime(&now); + l = LoggerVarPath(dir, path, sizeof path, log->name, &tm); + + strftime(path + l, sizeof path - l, "%m-%d.log", &tm); + strftime(stim, sizeof stim, "#%Y-%m-%d %H:%M:%S", &tm); + + if (period <= 0) period = 1; + writeInfo = (tm.tm_isdst != lasttm.tm_isdst || + tm.tm_yday != lasttm.tm_yday || + (period != log->period && log->numeric)); + if (strcmp(value, log->old) != 0 || writeInfo) { + + fil = fopen(path, "r+"); + if (fil == NULL) { /* create new file */ + fil = fopen(path, "w+"); + if (fil == NULL) return 0; + fprintf(fil, "%s isdst %d period %d exact %d\n", stim, tm.tm_isdst, period, log->exact); + } else { /* check if file is from today */ + fgets(buf, sizeof buf, fil); + if (0 != strncmp(buf, stim, 11)) { + fclose(fil); /* it was file from an earlier year */ + fil=fopen(path, "w+"); /* overwrite old logfile */ + if (fil == NULL) return 0; + fprintf(fil, "%s isdst %d period %d exact %d\n", stim, tm.tm_isdst, period, log->exact); + } else { + fseek(fil, 0, SEEK_END); /* set position to end */ + if (writeInfo) { + fprintf(fil, "#isdst %d period %d exact %d\n", tm.tm_isdst, period, log->exact); + } + if (log->lastWrite != 0 && now >= log->lastWrite + 2 * period) { + /* this is only useful for direct access of the log files */ + beforenow = now - period; + lasttm = *localtime(&beforenow); + if (lasttm.tm_yday == tm.tm_yday) { + strftime(stim, sizeof stim,"%H:%M:%S", &lasttm); + } else { + snprintf(stim, sizeof stim, "00:00:00"); + } + fprintf(fil, "%s\t%s\n", stim, log->old); + } + } + } + strftime(stim, sizeof stim,"%H:%M:%S", &tm); + fprintf(fil, "%s\t%s\n", stim, value); + log->lastWrite = now; + fclose(fil); + + } + log->period = period; + + l = strlen(value); + if (l >= log->oldsize) { /* increase log->old size, optimized for linux/i386 */ + ext = ((l - log->oldsize)/16 + 1) * 16; + if (ext < log->oldsize / 4) ext += (log->oldsize / 64) * 16; + log->oldsize += ext; + free(log->old); + log->old = calloc(1, log->oldsize); + } + assert(log->old); + assert(l < log->oldsize); + strcpy(log->old, value); + assert(log->old[l] == '\0'); + log->last = now; + return 1; +} +/*--------------------------------------------------------------------------*/ +int LoggerWrite(Logger *log, time_t now, int period, char *value) { + Logger *p; + time_t h0; + static int yday = -1; + struct tm *tm; + + int l; + FILE *fil; + char path[256]; + char tim[256]; + + tm = localtime(&now); + if (tm->tm_yday != yday) { + tm->tm_hour = 0; + tm->tm_min = 0; + tm->tm_sec = 0; + h0 = mktime(tm); + + yday = tm->tm_yday; + + /* -- debug logging if dir/debug exists */ + l = LoggerVarPath(dir, path, sizeof path, "debug", tm); + strftime(path + l, sizeof path - l, "%m-%d.log", tm); + fil=fopen(path, "a"); + if (fil) { + strftime(tim, sizeof tim, "h0 %m-%d %H:%M:%S\n", localtime(&h0)); + fputs(tim, fil); + } + + /* log old values (forced midnight log) */ + p = list; + while (p != NULL) { + + if (fil) { /* debug logging */ + strftime(tim, sizeof tim, "last %m-%d %H:%M:%S, ", localtime(&p->last)); + fputs(tim, fil); + fprintf(fil, "period %d, name %s, old %s\n", p->period, p->name, p->old); + } + + if (p->last < h0 && p->last != 0 && + p->period >= 0 && p->old[0] != '\0') { + LoggerWrite0(p, h0, p->period, p->old); + } + p = p->next; + } + if (fil) fclose(fil); + } + return LoggerWrite0(log, now, period, value); +} +/*--------------------------------------------------------------------------*/ +time_t LoggerLastTime(Logger *log) { + if (log->last != 0 && log->period > 0) { + return log->last; + } + return 0; +} +/*--------------------------------------------------------------------------*/ +int LoggerPeriod(Logger *log) { + return log->period; +} +/*--------------------------------------------------------------------------*/ +void LoggerSetPeriod(Logger *log, int period) { + LoggerWrite0(log, time(NULL), period, log->old); +} +/*--------------------------------------------------------------------------*/ +void LoggerKill(Logger *log) { + /* we do not really free the logger, it might be reused + for the same variable later. We set the value to undefined */ + + if (list != NULL) { /* LoggerFreeAll not yet called */ + LoggerWrite(log, time(NULL), 0, ""); + } +} +/*--------------------------------------------------------------------------*/ +static int LoggerMakeDir(char *path) { + static char buffer[4096]; + struct stat st; + int i, lpath, l; + char *slash; + + i = stat(path, &st); + if (i >= 0) { + if (((st.st_mode >> 12) & 15) != 4) { /* exists, but is no directory */ + return 0; + } + return 1; + } + i = mkdir(path, S_IRWXU+S_IRGRP+S_IXGRP+S_IROTH+S_IXOTH); + if (i < 0) { + if (errno != ENOENT) return 0; /* mkdir failed */ + snprintf(buffer, sizeof buffer, "%s", path); + lpath = strlen(buffer); + do { + slash = strrchr(buffer, '/'); + if (!slash) return 0; + *slash='\0'; + i = mkdir(buffer, S_IRWXU+S_IRGRP+S_IXGRP+S_IROTH+S_IXOTH); + } while (i < 0 && errno == ENOENT); + l = strlen(buffer); + while (lname = strdup(name); + if (log->name == NULL) { + free(log); + return NULL; + } + log->period = -1; + log->exact = exact; + log->old = calloc(1,12); + log->oldsize = 12; + log->last = 0; + log->lastWrite = 0; + log->numeric = 1; + log->next = list; + list = log; + t = time(NULL) -1; + if (lastLife != 0 && lastLife + period < t) { + t = lastLife + period; + } + LoggerWrite(log, t, period, ""); /* value was undefined since last life of server */ + } + return log; +} +/*--------------------------------------------------------------------------*/ +void LoggerFreeAll(void) { + Logger *p, *next; + + p = list; + while (p != NULL) { + next = p->next; + if (p->name) free(p->name); + if (p->old) free(p->old); + free(p); + p = next; + } + list = NULL; +} diff --git a/logger.h b/logger.h new file mode 100644 index 00000000..276a5494 --- /dev/null +++ b/logger.h @@ -0,0 +1,29 @@ +/*--------------------------------------------------------------------------- +logger.h + +Markus Zolliker, Sept 2004 +---------------------------------------------------------------------------- +*/ + +#ifndef LOGGER_H +#define LOGGER_H + +#include + +typedef struct Logger Logger; + +Logger *LoggerMake(char *name, int period, int exact); +void LoggerKill(Logger *log); +int LoggerWrite(Logger *log, time_t now, int period, char *value); +char *LoggerName(Logger *log); +void LoggerSetNumeric(Logger *log, int numeric); +time_t LoggerSetDir(char *dirarg); +time_t LoggerGetLastLife(char *dirarg); +void LoggerWriteOld(Logger *log, time_t now); +time_t LoggerLastTime(Logger *log); +int LoggerPeriod(Logger *log); +void LoggerSetPeriod(Logger *log, int period); +int LoggerVarPath(char *dir, char *path, int pathLen, char *name, struct tm *t); +void LoggerFreeAll(void); + +#endif diff --git a/logreader.c b/logreader.c new file mode 100644 index 00000000..cfa8b618 --- /dev/null +++ b/logreader.c @@ -0,0 +1,524 @@ +#include +#include +#include +#include +#include +#include +#include +#include "logger.h" +#include "sics.h" + +#define LOGGER_NAN -999999. +#define ONE_YEAR (366*24*3600) +#define LLEN 1024 +/* max. number of dirs in path */ +#define MAX_DIRS 16 + +typedef enum { NUMERIC, TEXT } CompType; + +typedef struct { + time_t t; + float y; +} Point; + +typedef struct { + SConnection *pCon; + int exact; + CompType type; + time_t step; + time_t tlim; /* 0: initial state */ + Point best; /* best point, to be written if tlim > 0 */ + Point written; /* last written point */ + Point last; /* last point */ + char buf[LLEN]; + int np; + char *none; + char *header; + time_t period; + int omitEqual; +} Compressor; + +static char *dirs[MAX_DIRS] = {NULL}; +static int ndirs=0; + +static void InitCompressor(Compressor *c, SConnection *pCon, time_t step) { + c->pCon = pCon; + c->step = step; + c->tlim = 0; + c->last.y = LOGGER_NAN; + c->last.t = 0; + c->buf[0]='\0'; + c->written.t = 0; + c->written.y = LOGGER_NAN; + c->omitEqual = 1; +} + +static void OutFloat(Compressor *c, Point p) { + char *value; + + if (p.y == LOGGER_NAN) { + if (c->omitEqual && c->written.y == LOGGER_NAN) return; + if (c->none) { + value = c->none; + } else { + value = ""; + } + } else { + if (c->omitEqual && c->written.y == p.y) return; + snprintf(c->buf, sizeof(c->buf), "%g", p.y); + value = c->buf; + } + SCPrintf(c->pCon, eWarning, "%ld %s", (long)(p.t - c->written.t), value); + c->written = p; + c->np--; +} + +static void WriteHeader(Compressor *c) { + if (c->header) { + SCPrintf(c->pCon, eWarning, "*%s period %ld\n", c->header, c->period); + c->header = NULL; + } +} + +static void PutValue(Compressor *c, time_t t, char *value) { + char *p; + Point new; + + WriteHeader(c); + if (c->type == NUMERIC) { + new.y = strtod(value, &p); + if (p == value) { + new.y = LOGGER_NAN; + } else { + if (new.y == LOGGER_NAN) new.y *= 1.0000002; + } + new.t = t; + if (t >= c->tlim) { /* a new interval starts */ + if (c->tlim == 0) { + c->tlim = t; + } else if (c->best.y != c->written.y) { + OutFloat(c, c->best); + } + c->best = new; + c->tlim += c->step; + if (t > c->tlim) { + if (c->last.y != c->written.y) { + OutFloat(c, c->last); + } + c->tlim = t + c->step; + } + } else { /* not the first point */ + if (fabs(new.y - c->best.y) > fabs(c->written.y - c->best.y)) { + c->best = new; + } + } + c->last = new; + } else if (c->type == TEXT) { + if (0 != strncmp(value, c->buf, sizeof(c->buf)-1)) { + snprintf(c->buf, sizeof(c->buf), "%s", value); + SCPrintf(c->pCon, eWarning, "%ld %s\n", (long)(t - c->written.t), value); + c->written.t = t; + c->np--; + } + } +} + +static void PutFinish(Compressor *c, time_t now) { + char value[32]; + + if (c->tlim != 0) { /* there is data already */ + c->omitEqual = 0; + if (c->type == NUMERIC) { + if (now > c->last.t + c->period) { /* copy last value to the actual time */ + if (c->last.y != LOGGER_NAN) { + snprintf(value, sizeof value, "%g", c->last.y); + PutValue(c, now, value); + } + if (c->best.t > c->written.t) { + OutFloat(c, c->best); /* write last buffered value */ + } + } + } if (now > c->last.t) { + PutValue(c, now, c->buf); + } + } +} +/*--------------------------------------------------------------------------*/ +static long getOpt(char *line, int *isdst, int *exact) { + long lxs; + char *opt; + + opt = strstr(line, "isdst"); + if (opt) { + sscanf(opt, "isdst %d", isdst); + } + opt = strstr(line, "exact"); + if (opt) { + sscanf(opt, "exact %d", exact); + } + opt = strstr(line, "period"); + if (opt) { + sscanf(opt, "period %ld", &lxs); + return lxs; + } else { + return -1; + } +} +/*--------------------------------------------------------------------------*/ +static int LogReader(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]) { + /* Usage: + graph [ none ] np [ ...] + graph text + graph [ ...] + + and are seconds since epoch (unix time) or, if the value + is below one day, a time relative to the actual time + + The is optional. if not given, unknown values are returned as empty strings + + is the maximal number of points to be returned. If more values + are present and the values are numeric, the data is reduced. If the data is not + numeric, the last values may be skipped in order to avoid overflow. + + is the name of a variable (several vaiables may be given). + Note that slashes are converted to dots, and that the first slash is ignored. + + The seconds variant is for text values, which can not be reduced. In any case, all values + are returned. + + The third variant is old style and can be replaced by the first variant, where + = ( - ) / + 2 + + + Output format: + First line: returning the actual time on the server (this time is used for relative times) + + For each variable which has data in the given interval, + the variable name is returned preceeded by a '*', followed by some infos* separated with + blanks. + After the header line for every data point a line follows with + a time relative to the last point and the value. + The first time value relative to zero, e.g. absolute. + The data value is valid until the next datapoint. Empty values are returned as an + empty string or as the . + + At the very end * is returned. + is 1, when the data had to be reduced, 0 else + is 1, when overflow occured, 0 else. Overflow may happen only + when np is given and a text variable was demanded. + + *actually only one info exists: period . This is the update rate in seconds. + As equal values are not transmitted, two points (t1,y1) and (t2,y2) with a distance + (t2 - t1) > period should not be connected directly. The plot software should generate + an intermediate point at (t2-period,y1). + + */ + time_t from, to, step, xs, lastt; + char *p, *varp; + int i, j, iarg, pathLen, iret, loss, np; + int inRange; + int yday=0; + time_t t, startim; + struct tm tm; + char stim[32], path[LLEN], line[LLEN], lastval[LLEN]; + char *lin, *val, *stp; + FILE *fil; + Compressor c={0}; + float yy, lasty; + CompType type0; + DIR *dr; + char *opt; + int isdst; + int overflow; + time_t now, nows[MAX_DIRS], nowi; + char var[256]; + char dirPathBuffer[1024]; + char *dirPath; + int idir; + char *colon; + + /* argtolower(argc, argv); */ + if (argc < 4) goto illarg; + now = time(NULL); + from = strtol(argv[1], &p, 0); /* unix time, not year 2038 safe */ + if (p == argv[1]) goto illarg; + to = strtol(argv[2], &p, 0); + if (p == argv[2]) goto illarg; + if (from < ONE_YEAR) { + from += now; + } + if (to < ONE_YEAR) { + to += now; + } + iarg = 3; + while (1) { + if (iarg>=argc) goto illarg; + if (strcasecmp(argv[iarg],"text") == 0) { /* non-numeric values */ + iarg++; + step = 1; + type0 = TEXT; + np = to - from + 2; + break; + } else if (strcasecmp(argv[iarg],"none") == 0) { /* none */ + iarg++; + if (iarg >= argc) goto illarg; + c.none = argv[iarg]; + iarg++; + } else if (strcasecmp(argv[iarg],"np") == 0) { /* max. number of points */ + iarg++; + if (iarg >= argc) goto illarg; + type0 = NUMERIC; + np = strtol(argv[iarg], &p, 0); + if (p == argv[iarg]) goto illarg; + iarg++; + if (to <= from) { + step = 1; + } else if (np <= 2) { + step = to - from; + } else { + step = (to - from) / (np - 2) + 1; + } + break; + } else { + step = strtol(argv[iarg], &p, 0); + if (p == argv[iarg]) goto illarg; + iarg++; + if (step <= 0) step = 1; + type0 = NUMERIC; + np = (from - to) / step + 2; + } + } + if (step <= 0) step = 1; + + snprintf(line, sizeof line, "%ld\n", (long)now); + SCWrite(pCon, line, eWarning); + + dirPath = IFindOption(pSICSOptions, "LogReaderPath"); + if (dirPath == NULL) { /* for compatibility, check */ + dirs[0] = IFindOption(pSICSOptions, "LoggerDir"); + if (dirs[0] == NULL) { + SCWrite(pCon, "ERROR: LoggerPath not found", eError); + return 0; + } + nows[0] = LoggerGetLastLife(NULL); + if (dirs[1] == NULL) { + dirs[1] = IFindOption(pSICSOptions, "LoggerDir2"); + nows[1] = LoggerGetLastLife(dirs[1]); + } + } else { + snprintf(dirPathBuffer, sizeof dirPathBuffer, "%s", dirPath); + dirPath = dirPathBuffer; + for (ndirs = 0; ndirs < MAX_DIRS; ndirs++) { + dirs[ndirs] = dirPath; + colon = strchr(dirPath, ':'); + if (colon != NULL) { + *colon = '\0'; + } + if (ndirs == 0) { + nows[0] = LoggerGetLastLife(NULL); + } else { + nows[ndirs] = LoggerGetLastLife(dirPath); + } + if (colon == NULL) { + ndirs++; + break; + } + dirPath = colon + 1; + } + } + + loss = 0; + overflow = 0; + for (i=iarg; i= 0) { + if (c.period == 0) { + c.type = TEXT; + } else { + c.type = type0; + xs = c.period; + } + if (xs < step) { + loss = 1; + xs = step; + } + } + } + } + } + if (fil == NULL) { + lin = NULL; + } else { + do { + lin = fgets(line, sizeof line, fil); + /* printf("%s\n", line); */ + if (lin == NULL) break; + if (line[0] == '#') { + c.period = getOpt(line, &isdst, &c.exact); + if (c.period >= 0) { + if (c.period == 0) { + c.type = TEXT; + } else { + c.type = type0; + xs = c.period; + } + if (xs < step) { + loss = 1; + xs = step; + } + } + lin[0]='\0'; + } else { + p = strchr(line, '\n'); if (p) *p='\0'; + p = strchr(line, '#'); if (p) *p='\0'; + } + } while (lin[0] == '\0'); + } + if (lin != NULL) { + /* printf(" %s\n", line); */ + p = strchr(line, '\t'); + if (p) { + *p='\0'; + val = p+1; + } else { + val = ""; + } + p = strchr(val, '\t'); + if (p) { + stp = p+1; + *p='\0'; + iret = sscanf(stp, "%ld", &c.period); + if (iret == 1) { + if (c.period == 0) { + c.type = TEXT; + } else { + c.type = type0; + xs = c.period; + } + if (xs < step) { + loss = 1; + xs = step; + } + } + } + iret = sscanf(line, "%d:%d:%d", &tm.tm_hour, &tm.tm_min, &tm.tm_sec); + if (iret != 3) { + lin = NULL; + } else { + tm.tm_isdst = isdst; + t=mktime(&tm); + if (!inRange) { + if (t < startim) { + lastval[0]='\0'; + strncat(lastval, val, sizeof lastval - 1); + lastt = t; + } else { + inRange=1; + if (lastt != 0) { + PutValue(&c, lastt, lastval); + } + PutValue(&c, t, val); + } + } else { + PutValue(&c, t, val); + } + } + } + if (lin == NULL) { + tm.tm_hour = 24; /* try next day */ + tm.tm_min = 0; + tm.tm_sec = 0; + tm.tm_isdst = -1; + startim=mktime(&tm); + continue; + } + } + if (!inRange) { + if (lastt != 0) { + PutValue(&c, lastt, lastval); + } + } + WriteHeader(&c); /* write header, if not already done */ + PutFinish(&c, nowi); + if (fil) { + fclose(fil); + fil = NULL; + } + if (c.np < 0) overflow = 1; + } + snprintf(line, sizeof line, "*%d %d\n", loss, overflow); + SCWrite(pCon, line, eWarning); + return 1; +illarg: + SCWrite(pCon, "illegal argument(s)", eError); + return 0; +} +/*--------------------------------------------------------------------------*/ +static void KillLogReader(void *data) { + Logger *p, *next; + + KillDummy(data); + LoggerFreeAll(); +} +/*--------------------------------------------------------------------------*/ +void LogReaderInit(void) { + AddCommand(pServ->pSics,"Graph",LogReader,KillLogReader,NULL); +} diff --git a/logsetup.c b/logsetup.c new file mode 100644 index 00000000..46059917 --- /dev/null +++ b/logsetup.c @@ -0,0 +1,113 @@ +#include "logger.h" +#include "sics.h" +#include "sicshipadaba.h" + +static char *loggerID = "loggerID"; + +static hdbCallbackReturn LoggerUpdateCallback(pHdb node, + void *userData, pHdbMessage message) { + Logger *logger = userData; + pDynString str; + SConnection *conn = NULL; + hdbValue value; + pHdbDataMessage mm = NULL; + pHdbDataSearch dsm = NULL; + + if ((dsm = GetHdbDataSearchMessage(message)) != NULL) { + if (dsm->testPtr == loggerID) { + dsm->result = userData; + return hdbAbort; + } + return hdbContinue; + } + + if((mm = GetHdbUpdateMessage(message)) == NULL){ + return hdbContinue; + } + + value = *(mm->v); + + str = formatValue(value, node); + LoggerWrite(logger, time(NULL), LoggerPeriod(logger), GetCharArray(str)); + DeleteDynString(str); + return hdbContinue; +} + +static int LogSetup(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]) { + pHdb node; + pHdbCallback cb; + static char basepath[1024]="/"; + char buf[1024]; + char *p, *name; + static char *loggerDir=NULL; + int numeric, period; + Logger *logger; + + if (argc < 2) { + SCPrintf(pCon, eError, "ERROR: should be: logsetup [ []]"); + return 0; + } + if (strcasecmp(argv[1], "basepath") == 0) { + if (argc > 2) { + snprintf(basepath, sizeof basepath, "%s", argv[2]); + } + SCPrintf(pCon, eValue, "%s", basepath); + return 1; + } + if (loggerDir == NULL) { + loggerDir = IFindOption(pSICSOptions, "LoggerDir"); + if (loggerDir == NULL) loggerDir="./"; + LoggerSetDir(loggerDir); + } + if (strcasecmp(argv[1], "directory") == 0) { + if (argc > 2) { + loggerDir = strdup(argv[2]); + } + SCPrintf(pCon, eValue, "%s", loggerDir); + return 1; + } + node = FindHdbNode(basepath, argv[1], pCon); + if (node == NULL) { + SCPrintf(pCon, eError, "ERROR: %s not found", argv[1]); + return 0; + } + period = 0; + if (argc > 2) { + period = atoi(argv[2]); + } + if (argc > 3) { + snprintf(buf, sizeof buf, "%s", argv[3]); + } else { + snprintf(buf, sizeof buf, "%s", argv[1]); + } + for (p = buf; *p != '\0'; p++) { + if (*p =='/') *p = '.'; + } + if (buf[0] == '.') { + name = buf+1; + } else { + name = buf; + } + if (node->value.dataType == HIPFLOAT) { + numeric = 1; + } else { + numeric = 0; + } + logger = FindHdbCallbackData(node, loggerID); + if (logger != 0) { /* logger exists already, changed only period */ + LoggerSetPeriod(logger, period); + } else { + logger = LoggerMake(name, period, !numeric); + LoggerSetNumeric(logger, numeric); + cb = MakeHipadabaCallback(LoggerUpdateCallback, logger, (void (*)(void *))LoggerKill); + assert(cb); + AppendHipadabaCallback(node, cb); + } + + return 1; +} + +void LogSetupInit(void) { + AddCmd("LogSetup",LogSetup); +} diff --git a/macosx_def b/macosx_def new file mode 100644 index 00000000..0085c42a --- /dev/null +++ b/macosx_def @@ -0,0 +1,13 @@ +#-------------------------------------------------------------------------- +# general defines used within the PSI makefile hierarchy +# +# Mark Koennecke, July 2003 +#------------------------------------------------------------------------- + +#DFORTIFY= -DFORTIFY +#FORTIFYOBJ= fortify.o strdup.o +#DFORTIFY= -pg + +MFLAGS=-f makefile_linux$(DUMMY) + +HDFROOT=/Users/Shared diff --git a/macro.c b/macro.c index ced502fe..bc3a10e5 100644 --- a/macro.c +++ b/macro.c @@ -70,6 +70,7 @@ #include "servlog.h" #include "stringdict.h" #include "exeman.h" +#include "nxcopy.h" #define SICSERROR "005567SICS" /*---------------------------------------------------------------------------- @@ -301,7 +302,8 @@ static int ProtectedExec(ClientData clientData, Tcl_Interp *interp, /*-------------------------------------------------------------------------- initialises a Tcl-Interpreter, installs SICS unknown mechanism and kills a few dangerous commands from the normal Tcl command set -*/ +----------------------------------------------------------------------------*/ +extern int Nxinter_SafeInit(Tcl_Interp *pTcl); /* from Swig NeXus Tcl interface */ Tcl_Interp *MacroInit(SicsInterp *pSics) { @@ -345,6 +347,9 @@ static int ProtectedExec(ClientData clientData, Tcl_Interp *interp, */ Tcl_CreateObjCommand(pInter,"exec",ProtectedExec,NULL,KillExec); + Nxinter_SafeInit(pInter); + NXcopy_Init(pInter); + return pInter; } /*--------------------------------------------------------------------------*/ @@ -1035,7 +1040,7 @@ static int ProtectedExec(ClientData clientData, Tcl_Interp *interp, pPubTcl pNew = NULL; char pBueffel[132]; int iUser, i, iRet; - + /* check no of args */ if(argc < 3) { @@ -1054,6 +1059,7 @@ static int ProtectedExec(ClientData clientData, Tcl_Interp *interp, return 0; } + /* try convert last parameter to user code */ iUser = decodeSICSPriv(argv[2]); if(iUser < 0) @@ -1069,7 +1075,7 @@ static int ProtectedExec(ClientData clientData, Tcl_Interp *interp, if (pNew) { /* yes -> overwrite access code */ pNew->iUser = iUser; - return 0; + return 1; } /* do a job !*/ pNew = CreatePublish(argv[1],iUser); diff --git a/make_gen b/make_gen index 2b55a90c..4d986c81 100644 --- a/make_gen +++ b/make_gen @@ -11,7 +11,7 @@ SOBJ = network.o ifile.o conman.o SCinter.o splitter.o passwd.o \ sicsexit.o costa.o task.o $(FORTIFYOBJ) access.o\ macro.o ofac.o obpar.o obdes.o drive.o status.o intserv.o \ devexec.o mumo.o mumoconf.o selector.o selvar.o fupa.o lld.o \ - lld_blob.o strrepl.o lin2ang.o fomerge.o napi4.o napi5.o \ + lld_blob.o strrepl.o lin2ang.o fomerge.o napi5.o napi4.o\ script.o o2t.o alias.o napi.o nxdata.o stringdict.o sdynar.o \ histmem.o histdriv.o histsim.o interface.o callback.o nxio.o \ event.o emon.o evcontroller.o evdriver.o simev.o perfmon.o \ @@ -31,8 +31,13 @@ SOBJ = network.o ifile.o conman.o SCinter.o splitter.o passwd.o \ hmdata.o nxscript.o tclintimpl.o sicsdata.o mcstascounter.o \ mcstashm.o initializer.o remob.o tclmotdriv.o protocol.o \ sinfox.o sicslist.o cone.o hipadaba.o sicshipadaba.o statistics.o \ - moregress.o hdbcommand.o multicounter.o regresscter.o histregress.o \ - sicshdbadapter.o polldriv.o sicspoll.o statemon.o hmslave.o + ascon.o errormsg.o scriptcontext.o logger.o logreader.o logsetup.o \ + savehdb.o statusfile.o sicshdbfactory.o proxy.o devser.o \ + moregress.o multicounter.o regresscter.o histregress.o \ + sicshdbadapter.o polldriv.o sicspoll.o statemon.o hmslave.o \ + nwatch.o asyncqueue.o asyncprotocol.o sicsobj.o \ + nxcopy.o nxinterhelper.o nxinter_wrap.o genericcontroller.o nxstack.o \ + sctdriveadapter.o sctdriveobj.o MOTOROBJ = motor.o simdriv.o COUNTEROBJ = countdriv.o simcter.o counter.o @@ -55,7 +60,7 @@ full: purge all SICServer: $(SOBJ) $(MOTOROBJ) $(COUNTEROBJ) \ $(VELOOBJ) $(DIFIL) $(EXTRA) \ $(SUBLIBS) - $(CC) -g -o SICServer \ + $(CC) -g -pg -o SICServer \ $(SOBJ) $(MOTOROBJ) $(COUNTEROBJ) \ $(VELOOBJ) $(DIFOBJ) $(EXTRA) $(LIBS) diff --git a/makefile_macosx b/makefile_macosx new file mode 100644 index 00000000..2dc98c99 --- /dev/null +++ b/makefile_macosx @@ -0,0 +1,42 @@ +#--------------------------------------------------------------------------- +# Makefile for SICS +# machine-dependent part for Mac OS X +# +# Mark Koennecke 1996-2001 +# Markus Zolliker, March 2003 +# Mark Koennecke, July 2008 +#========================================================================== +# assign if the National Instrument GPIB driver is available +SINQDIR=/Users/Shared +#NI= -DHAVENI +#NIOBJ= nigpib.o +#NILIB=$(SINQDIR)/sl5/lib/cib.o + +include macosx_def + +CC = gcc +CFLAGS = -I$(HDFROOT)/include -I/sw/include -DNXXML -DHDF5 -DHDF4 $(NI) -DMACOSX \ + -Ipsi/hardsup -I. \ + -Werror -DNONINTF -g $(DFORTIFY) \ + -Wall -Wno-unused -Wno-comment -Wno-switch + +BINTARGET = bin +EXTRA=nintf.o +SUBLIBS = psi/libpsi.a psi/hardsup/libhlib.a matrix/libmatrix.a \ + psi/tecs/libtecsl.a +LIBS = -L$(HDFROOT)/lib -L/sw/lib $(SUBLIBS) $(NILIB)\ + -ltcl $(HDFROOT)/lib/libhdf5.a -lmfhdf -ldf \ + $(HDFROOT)/lib/libsz.a \ + $(HDFROOT)/lib/libjson.a -ljpeg \ + -ldl -lz -lmxml $(HDFROOT)/lib/libghttp.a -lm -lc + +include make_gen + + + + + + + + + diff --git a/makefile_slinux b/makefile_slinux index e25194fe..f5955672 100644 --- a/makefile_slinux +++ b/makefile_slinux @@ -9,13 +9,13 @@ SINQDIR=/afs/psi.ch/project/sinq NI= -DHAVENI NIOBJ= nigpib.o -NILIB=$(SINQDIR)/sl-linux/lib/cib.o +NILIB=$(SINQDIR)/sl5/lib/cib.o include sllinux_def CC = gcc -CFLAGS = -I$(HDFROOT)/include -DHDF4 -DHDF5 -DNXXML $(NI) \ - -Ipsi/hardsup -I. \ +CFLAGS = -I$(HDFROOT)/include -DNXXML -DHDF4 -DHDF5 $(NI) \ + -Ipsi/hardsup -I. \ -Werror -DCYGNUS -DNONINTF -g $(DFORTIFY) \ -Wall -Wno-unused -Wno-comment -Wno-switch @@ -23,11 +23,12 @@ BINTARGET = bin EXTRA=nintf.o SUBLIBS = psi/libpsi.a psi/hardsup/libhlib.a matrix/libmatrix.a \ psi/tecs/libtecsl.a -LIBS = -L$(HDFROOT)/lib $(SUBLIBS) $(NILIB)\ - -ltcl8.3 $(HDFROOT)/lib/libhdf5.a \ +LIBS = -L$(HDFROOT)/lib $(SUBLIBS) $(NILIB)\ + -ltcl $(HDFROOT)/lib/libhdf5.a \ $(HDFROOT)/lib/libmfhdf.a $(HDFROOT)/lib/libdf.a \ - $(HDFROOT)/lib/libjpeg.a -lsz $(HDFROOT)/lib/libjson.a \ - -ldl -lz -lmxml -lghttp -lm -lc + $(HDFROOT)/lib/libjpeg.a $(HDFROOT)/lib/libsz.a \ + $(HDFROOT)/lib/libjson.a \ + -ldl -lz -lmxml $(HDFROOT)/lib/libghttp.a -lm -lc include make_gen diff --git a/matrix/matcreat.c b/matrix/matcreat.c index 50812345..f2a539f7 100644 --- a/matrix/matcreat.c +++ b/matrix/matcreat.c @@ -20,7 +20,7 @@ #ifdef __TURBOC__ #include #else -#include +#include #endif #include "matrix.h" diff --git a/matrix/materr.c b/matrix/materr.c index 827b73ac..26bc3174 100644 --- a/matrix/materr.c +++ b/matrix/materr.c @@ -19,7 +19,7 @@ #ifdef __TURBOC__ #include #else -#include +#include #endif #include "matrix.h" diff --git a/matrix/matinv.c b/matrix/matinv.c index 645d3798..ca344186 100644 --- a/matrix/matinv.c +++ b/matrix/matinv.c @@ -20,7 +20,7 @@ #ifdef __TURBOC__ #include #else -#include +#include #endif #include "matrix.h" diff --git a/matrix/matsolve.c b/matrix/matsolve.c index 9a2f61e8..9972ff2a 100644 --- a/matrix/matsolve.c +++ b/matrix/matsolve.c @@ -20,7 +20,7 @@ #ifdef __TURBOC__ #include #else -#include +#include #endif #include "matrix.h" diff --git a/mclist.c b/mclist.c new file mode 100644 index 00000000..f67badf0 --- /dev/null +++ b/mclist.c @@ -0,0 +1,116 @@ +#ifndef MC_List_TYPE +#define MC_List_TYPE MC_NAME(List) +#define MC_First_FUN MC_NAME(First) +#define MC_This_FUN MC_NAME(This) +#define MC_Next_FUN MC_NAME(Next) +#define MC_End_FUN MC_NAME(End) +#define MC_Insert_FUN MC_NAME(Insert) +#define MC_Add_FUN MC_NAME(Add) +#define MC_Take_FUN MC_NAME(Take) +#endif + +#ifdef MC_IMPLEMENTATION + +#undef MC_IMPLEMENTATION +#ifndef MC_TYPE +#define MC_TYPE MC_NAME()* +#endif + +#else + +#define MC_DO_NOT_UNDEF +#include "mclist.h" +#undef MC_DO_NOT_UNDEF + +#endif + +#ifndef MC_NEXT +#define MC_NEXT next +#endif + +MC_TYPE MC_First_FUN(MC_List_TYPE *list) { + list->ptr = &list->head; + return list->head; +} + +MC_TYPE MC_This_FUN(MC_List_TYPE *list) { + if (list->head == NULL) { + list->ptr = &list->head; + return NULL; + } + return *list->ptr; + } + +MC_TYPE MC_Next_FUN(MC_List_TYPE *list) { + MC_TYPE node; + if (list->head == NULL) { + list->ptr = &list->head; + return NULL; + } + node = *list->ptr; + if (node) { + list->ptr = &node->MC_NEXT; + } + return *list->ptr; +} + +void MC_End_FUN(MC_List_TYPE *list) { + MC_TYPE node; + if (list->head == NULL) { + list->ptr = &list->head; + } + node = *list->ptr; + if (node) { + while (node->MC_NEXT != NULL) { + node = node->MC_NEXT; + } + list->ptr = &node->MC_NEXT; + } +} + +void MC_Insert_FUN(MC_List_TYPE *list, MC_TYPE node) { + if (list->head == NULL) { + list->ptr = &list->head; + } + node->MC_NEXT = *list->ptr; + *list->ptr = node; +} + +void MC_Add_FUN(MC_List_TYPE *list, MC_TYPE node) { + node->MC_NEXT = NULL; + if (list->head == NULL) { + list->head = node; + list->ptr = &list->head; + } else { + if (*list->ptr != NULL) { + MC_End_FUN(list); + } + *list->ptr = node; + } +} + +MC_TYPE MC_Take_FUN(MC_List_TYPE *list) { + MC_TYPE node; + node = *list->ptr; + if (node != NULL) { + *list->ptr = node->MC_NEXT; + } + return node; +} + +void MC_Delete_FUN(MC_List_TYPE *list, void (*deleteFunc)(MC_TYPE n)) { + MC_TYPE node; + MC_TYPE victim; + node = list->head; + while (node != NULL) { + victim = node; + node = node->next; + deleteFunc(victim); + } + list->head = NULL; + list->ptr = &list->head; +} + +#undef MC_NAME +#undef MC_TYPE +#undef MC_NEXT diff --git a/mclist.h b/mclist.h new file mode 100644 index 00000000..889a6737 --- /dev/null +++ b/mclist.h @@ -0,0 +1,177 @@ +/** \file + * \brief Type safe list handling + * + * The definition and implementation make use of macros extensively to create + * a list type and related functions for any node type. + * However, accessing the list does not use macros. + * The list is implemented as a singly linked list. Sequential appending + * to the tail is fast, because the list structure contains + * a pointer to the anchor of the last accessed node. + * + * For a local list, mclist.c must be included after + * the declaration of the node type and after defining the macro MC_NAME + * and optionally MC_TYPE and MC_NEXT. + * + * For a public list, in the header file mclist.h must be included after + * the declaration of the node type and after defining the macro MC_NAME + * and optionally MC_TYPE. In the implementation mclist.c + * must be included after defining the macro MC_NAME and MC_IMPLEMENTATION + * and optionally MC_TYPE and MC_NEXT. + * + * MC_NAME has one parameter and describes how to combine the list name + * with the function names. + * + * MC_TYPE defines the node type. If undeclared it defaults to a pointer + * to the name. + * + * MC_NEXT indicates the name of the link. It defaults to 'next'. + * + * MC_IMPLEMENTATION has no value and must be defined when the list type + * was already declared. Typically this is done in a header file including mclist.h. + * + * The macros MC_NAME, MC_TYPE, MC_NEXT and MC_IMPLEMENTATION are undefined + * within mclist.c and mclist.h and must be redefined for every list. + * + * \par Usage example + * \code + * // declare the Node type + * typedef struct Node { + * struct Node *next; + * char *name; + * } Node; + * + * // this declaration leads to a list type 'NodeList' and fucntions names 'Node' + * #define MC_NAME(T) Node##T + * // the following line is not needed as 'next' is the default for the link + * #define MC_NEXT next + * // the following line is not needed as 'Node *' is the default for the type in this case + * #define MC_TYPE Node * + * // inside mclist.c, the list type is declared and the related functions are implemented + * #include "mclist.c" + * + * int main(void) { + * // declare and init the list + * NodeList list={NULL}; + * + * // create a node + * Node *node; + * node = malloc(sizeof(*node)); + * node->name = "First"; + * + * // add node at the end of the list + * NodeAdd(&list, node); + * + * // print the names of all list nodes + * for (node = NodeFirst(&list); node != NULL; node = NodeNext(&list)) { + * printf("%s\n", node->name); + * } + * + * // alternative form not touching the list position + * // only for the case, where no insert or take function is used inside the loop + * for (node = list.head; node != NULL; node = node->next) { + * printf("%s\n", node->name); + * } + * + * // remove the node with the name "First" + * for (node = NodeFirst(&list); node != NULL; node = NodeNext(&list)) { + * if (strcmp(node->name, "First") == 0) { + * free(NodeTake(&list)); + * } + * } + * } + * \endcode + */ +#ifndef MC_TYPE +/** \brief default node type + */ +#define MC_TYPE MC_NAME()* +#endif + +#ifndef MC_List_TYPE +#define MC_List_TYPE MC_NAME(List) +#define MC_First_FUN MC_NAME(First) +#define MC_This_FUN MC_NAME(This) +#define MC_Next_FUN MC_NAME(Next) +#define MC_End_FUN MC_NAME(End) +#define MC_Insert_FUN MC_NAME(Insert) +#define MC_Add_FUN MC_NAME(Add) +#define MC_Take_FUN MC_NAME(Take) +#define MC_Delete_FUN MC_NAME(Delete) +#endif + +typedef struct MC_List_TYPE { + MC_TYPE head; + MC_TYPE *ptr; +} MC_List_TYPE; + +/** \brief move to first node and get it + * \param list the list + * \return the node or NULL when the list is empty + * + * Actual position on return: at the first node + */ +MC_TYPE MC_First_FUN(MC_List_TYPE *list); + +/** \brief get the node at the current position + * \param list the list + * \return the node or NULL when the list is empty or the position is at end + * + * Actual position on return: not changed (= at the returned node) + */ +MC_TYPE MC_This_FUN(MC_List_TYPE *list); + +/** \brief get the node after the current node + * \param list the list + * \return the node or NULL when the list is empty or the position is at end + * + * Actual position on return: incremented (= at the returned node or at end) + */ +MC_TYPE MC_Next_FUN(MC_List_TYPE *list); + +/** \brief move the position to the end + * \param list the list + * + * Actual position on return: at end + */ +void MC_End_FUN(MC_List_TYPE *list); + +/** \brief insert at the current position, i.e. before the current node + * \param list the list + * \param node the node to be inserted + * + * Actual position on return: at the inserted node + */ +void MC_Insert_FUN(MC_List_TYPE *list, MC_TYPE node); + +/** \brief add at the end of the list + * \param list the list + * \param node the node to be added + * + * Actual position on return: at the inserted node (before the last node, not at end!) + */ +void MC_Add_FUN(MC_List_TYPE *list, MC_TYPE node); + +/** \brief remove the node at the current position + * \param list the list + * \return the removed node or NULL when the list is empty or the position is at end + * + * Actual position on return: after the taken node + * + * Note: it is the responsibility of the caller to free the node if it is not used + * anymore + */ +MC_TYPE MC_Take_FUN(MC_List_TYPE *list); + +/** \brief remove and delete all nodes + * \param list the list + * \param deleteFunc the kill function of the node + * + * Calls the kill function for every node. The list is + * empty on return. + */ +void MC_Delete_FUN(MC_List_TYPE *list, void (*deleteFunc)(MC_TYPE node)); + +#ifndef MC_DO_NOT_UNDEF +#undef MC_NAME +#undef MC_TYPE +#endif diff --git a/mcreader.c b/mcreader.c index 4470ac59..d2d6c48d 100644 --- a/mcreader.c +++ b/mcreader.c @@ -178,6 +178,7 @@ static int insertMonitor(pMcStasReader self, SConnection *pCon, return 0; } + memset(pBueffel,0,512); status = NXgetdata(self->handle,pBueffel); if(status != NX_OK){ snprintf(pBueffel,511,"ERROR: Nexus error %s while reading %s", diff --git a/mcstas/dmc/DataNumber b/mcstas/dmc/DataNumber index 5c58528e..b4495070 100644 --- a/mcstas/dmc/DataNumber +++ b/mcstas/dmc/DataNumber @@ -1,3 +1,3 @@ - 133 + 230 NEVER, EVER modify or delete this file You'll risk eternal damnation and a reincarnation as a cockroach!|n \ No newline at end of file diff --git a/mcstas/dmc/gumibatch.tcl b/mcstas/dmc/gumibatch.tcl new file mode 100644 index 00000000..050ff63c --- /dev/null +++ b/mcstas/dmc/gumibatch.tcl @@ -0,0 +1,174 @@ +#------------------------------------------------------------- +# This is a set of Tcl procedures which try to convert an old +# batch file into a batch file suitable for Mountaingum. +# +# copyright: GPL +# +# Mark Koennecke, February 2008 +#------------------------------------------------------------- +if {[string first tmp $home] < 0} { + set tmppath $home/tmp +} else { + set tmppath $home +} +#------------------------------------------------------------- +proc searchPathForDrivable {name} { + set path [string trim [hmatchprop / sicsdev $name]] + if {[string compare $path NONE] != 0} { + return $path + } + set txt [findalias $name] + if {[string compare $txt NONE] == 0} { + return NONE + } + set l1 [split $txt =] + set l [split [lindex $l1 1] ,] + foreach alias $l { + set alias [string trim $alias] + set path [string trim [hmatchprop / sicsdev $alias]] + if {[string compare $path NONE] != 0} { + return $path + } + } + return NONE +} +#---------------------------------------------------------------- +proc searchForCommand {name} { + return [string trim [hmatchprop / sicscommand $name]] +} +#---------------------------------------------------------------- +proc treatsscan {scanpath command out} { + set l [split $command] + set len [llength $l] + set noVar [expr ($len-2)/3] + set np [lindex $l [expr $len -2]] + set preset [lindex $l [expr $len -1]] + for {set i 0} {$i < $noVar} {incr i} { + set start [expr $i * 3] + set scanVar [lindex $l [expr 1 + $start]] + set scanStart [lindex $l [expr 2 + $start]] + set scanEnd [lindex $l [expr 3 + $start]] + set scanStep [expr ($scanEnd*1. - $scanStart*1.)/$np*1.] + append hdbVar $scanVar , + append hdbStart $scanStart , + append hdbStep $scanStep , + } + set hdbVar [string trim $hdbVar ,] + set hdbStart [string trim $hdbStart ,] + set hdbStep [string trim $hdbStep ,] + puts $out "\#NODE: $scanpath" + puts $out "clientput BatchPos = 1" + puts $out "hdbscan $hdbVar $hdbStart $hdbStep $np monitor $preset" +} +#---------------------------------------------------------------- +proc treatcscan {scanpath command out} { + set l [split $command] + set scanVar [lindex $l 1] + set scanCenter [lindex $l 2] + set scanStep [lindex $l 3] + set np [lindex $l 4] + set preset [lindex $l 5] + set hdbStart [expr $scanCenter - ($np*1.0)/2. * $scanStep*1.0] + puts $out "\#NODE: $scanpath" + puts $out "clientput BatchPos = 1" + puts $out "hdbscan $scanVar $hdbStart $scanStep $np monitor $preset" +} +#---------------------------------------------------------------- +proc translateCommand {command out} { + set drivelist [list drive dr run] + set textList [list for while source if] +# clientput "Translating: $command" + set command [string trim $command] + if {[string length $command] < 2} { + return + } + set l [split $command] + set obj [string trim [lindex $l 0]] +#------- check for drive commands + set idx [lsearch $drivelist $obj] + if {$idx >= 0} { + set dev [lindex $l 1] + set path [searchPathForDrivable $dev] + if {[string compare $path NONE] != 0} { + set realTxt [hgetprop $path sicsdev] + set realL [split $realTxt =] + set realDev [lindex $realL 1] + set mapList [list $dev $realDev] + set newCom [string map $mapList $command] + puts $out "\#NODE: $path" + puts $out "clientput BatchPos = 1" + puts $out $newCom + return + } + } +#------ check for well known broken commands + set idx [lsearch $textList $obj] + if {$idx >= 0} { + puts $out "\#NODE: /batch/commandtext" + puts $out "clientput BatchPos = 1" + set buffer [string map {\n @nl@} $command] + puts $out "hset /batch/commandtext $buffer" + return + } +#--------- check for simple commands + set path [searchForCommand $command] + if {[string compare $path NONE] != 0} { + puts $out "\#NODE: $path" + puts $out "clientput BatchPos = 1" + puts $out $command + return + } + set scancom [searchForCommand hdbscan] +#---------- deal with scans + if {[string first sscan $obj] >= 0} { + if {[catch {treatsscan $scancom $command $out}] == 0} { + return + } + } + if {[string first cscan $obj] >= 0} { + if {[catch {treatsscan $scancom $command $out}] == 0} { + return + } + } +#--------- give up: output as a text node + puts $out "\#NODE: /batch/commandtext" + puts $out "clientput BatchPos = 1" + set buffer [string map {\n @nl@} $command] + puts $out "hset /batch/commandtext $buffer" +} +#---------------------------------------------------------------- +proc mgbatch {filename} { + global tmppath + set f [open $filename r] + gets $f line + close $f + if {[string first MOUNTAINBATCH $line] > 0} { +#--------- This is a mountaingum batch file which does not need +# to be massaged + return $filename + } + set f [open $filename r] + set realfilename [file tail $filename] + set out [open $tmppath/$realfilename w] + puts $out \#MOUNTAINBATCH + while {[gets $f line] >= 0} { + append buffer $line + if {[info complete $buffer] == 1} { + translateCommand $buffer $out + unset buffer + } else { + append buffer \n + } + } + close $out + return $tmppath/$realfilename +} +#---------------------------------------------------------------- +proc loadmgbatch {filename} { + set txt [exe fullpath $filename] + set l [split $txt =] + set realf [lindex $l 1] + set realf [mgbatch $realf] + return [exe print $realf] +} + diff --git a/mcstas/dmc/gumxml.tcl b/mcstas/dmc/gumxml.tcl new file mode 100644 index 00000000..bb9e538b --- /dev/null +++ b/mcstas/dmc/gumxml.tcl @@ -0,0 +1,80 @@ +proc getdataType {path} { + return [lindex [split [hinfo $path] ,] 0] +} + + +proc make_nodes {path result indent} { +set nodename [file tail $path]; +set type [getdataType $path] +set prefix [string repeat " " $indent] +set newIndent [expr $indent + 2] +#array set prop_list [ string trim [join [split [hlistprop $path] =]] ] + set prop_list(control) true + set we_have_control [info exists prop_list(control)] + if {$we_have_control == 0 || $we_have_control && $prop_list(control) == "true"} { + append result "$prefix\n" + foreach p [property_elements $path $newIndent] { + append result $p + } + foreach x [hlist $path] { + set result [make_nodes [string map {// /} "$path/$x"] $result $newIndent] + } + append result "$prefix\n" + } + return $result +} + +proc property_elements_old {path indent} { + set prefix [string repeat " " $indent] + foreach {key value} [string map {= " "} [hlistprop $path]] { + if {[string compare -nocase $key "control"] == 0} {continue} + lappend proplist "$prefix\n" +# foreach v [split $value ,] { +# lappend proplist "$prefix$prefix$v\n" +# } + lappend proplist "$prefix$prefix$value\n" + lappend proplist "$prefix\n" + } + if [info exists proplist] {return $proplist} +} + +proc property_elements {path indent} { + set prefix [string repeat " " $indent] + set data [hlistprop $path] + set propList [split $data \n] + foreach prop $propList { + set pl [split $prop =] + set key [string trim [lindex $pl 0]] + set value [string trim [lindex $pl 1]] + if {[string length $key] < 1} { + continue + } + lappend proplist "$prefix\n" + lappend proplist "$prefix$prefix$value\n" + lappend proplist "$prefix\n" + } + if [info exists proplist] {return $proplist} +} + +proc getgumtreexml {path} { + append result "\n" + append result "\n" + + if {[string compare $path "/" ] == 0} { + foreach n [hlist $path] { + set result [make_nodes $n $result 2] + } + } else { +# set result [make_nodes $path $result 2] + foreach n [hlist $path] { + set result [make_nodes $path/$n $result 2] + } + } + + append result "\n" +} + +if {[info exists guminit] == 0} { + set guminit 1 + Publish getgumtreexml Spy +} diff --git a/mcstas/dmc/mcsupport.tcl b/mcstas/dmc/mcsupport.tcl index 029a2a77..eba8dd15 100644 --- a/mcstas/dmc/mcsupport.tcl +++ b/mcstas/dmc/mcsupport.tcl @@ -30,7 +30,7 @@ proc washsimfile {name} { # dump its data. Otherwise we observe that data reading fails. # mcwaittime is used for this. Increase if you see problems #-------------------------------------------------------------------- -set mcwaittime 7 +set mcwaittime 2 #---------------------------------------------------------------------- proc mcstasdump {pid} { global mcwaittime diff --git a/mcstas/dmc/vdmc.tcl b/mcstas/dmc/vdmc.tcl index 0b746baa..2d7b9049 100644 --- a/mcstas/dmc/vdmc.tcl +++ b/mcstas/dmc/vdmc.tcl @@ -12,6 +12,7 @@ if {$wwwMode == 1} { set datahome /home/lnswww/www/vinstrument } else { set home $env(HOME)/src/workspace/sics/mcstas/dmc + ServerOption LoggerDir $env(HOME)/src/workspace/sics/mcstas/dmc/samenv } #--------------------------------- first all the server options are set #ServerOption RedirectFile $home/stdcdmc @@ -31,21 +32,22 @@ SicsUser lnsmanager lnsSICSlns 1 SicsUser Manager Manager 1 SicsUser user looser 2 SicsUser Spy 007 1 +SicsUser User 07lns1 2 #-------------------------------------------------------------------------- # D E V I C E S : M O T O R S #--------------------------------------------------------------------------- ClientPut "Installing Motors" -Motor OmegaM SIM 0 120 -.1 2. -Motor TwoThetaM SIM 30 100 -.1 1. -Motor MonoX SIM -30 30 -.1 3.0 -Motor MonoY SIM -30 30 -.1 3.0 -Motor CurveM SIM 0 20 -.1 3.0 -Motor MonoPhi SIM -30 30 -.1 3.0 -Motor MonoChi SIM -30 30 -.1 3.0 +Motor OmegaM SIM 0 120 .0000001 2. +Motor TwoThetaM SIM 30 100 .0000001 1. +Motor MonoX SIM -30 30 .00000001 3.0 +Motor MonoY SIM -30 30 .000000001 3.0 +Motor CurveM SIM 0 20 .000000001 3.0 +Motor MonoPhi SIM -30 30 .00000001 3.0 +Motor MonoChi SIM -30 30 .00000001 3.0 # sample Table -Motor Table SIM -180 360 -.1 2. -Motor TwoThetaD SIM -10 120 -.1 1. +Motor Table SIM -180 360 .0000001 2. +Motor TwoThetaD SIM -10 120 .0000001 1. #------------------------------------------------------------- # Monochromator #------------------------------------------------------------- @@ -66,6 +68,7 @@ allowexec $home/dmcafter allowexec $home/dmc_sics05 ClientPut "Installing counter" + MakeCounter counter mcstas counter SetExponent 1 MakeHM banana mcstas @@ -79,7 +82,7 @@ banana CountMode Timer banana configure Counter counter banana configure init 0 banana init -banana exponent 3 +#banana exponent 3 #------------------------------------------------------------------------- # Aliases #------------------------------------------------------------------------- @@ -122,6 +125,7 @@ VarMake starttime Text User starttime "" VarMake SicsDataPrefix Text Internal SicsDataPrefix vdmc + #--------- make data number MakeDataNumber SicsDataNumber $home/DataNumber VarMake SicsDataPostFix Text Internal @@ -132,6 +136,8 @@ VarMake fax Text User VarMake email Text User VarMake sample_mur Float User VarMake lastdatafile Text User +VarMake lastscancommand Text User +lastscancommand "unknown scan" #-------------------------------------------------------------------------- # P R O C E D U R E S #-------------------------------------------------------------------------- @@ -139,21 +145,44 @@ MakeDrive MakeBatchManager MakeNXScript MakeRuenBuffer +#------------------------------------------------------------------------ +# simulated scanning for demo purposes +#----------------------------------------------------------------------- +MakeCounter lieselotte SIM -1 +MakeMultiCounter scanCter lieselotte +#------------------------------ +proc SICSValue {command} { + set txt [eval $command] + set l [split $txt =] + return [string trim [lindex $l 1]] +} +#----------------------------------------------------------------------- +proc scantransfer {} { + set FWHM 1.5 + set pos 5.33 + set height 700 + set stddev [expr $FWHM/2.354] + set ftmp [expr ([SICSValue a3] - $pos)/$stddev] + set count [expr 10 + $height*0.4*exp(-.5*$ftmp*$ftmp)] + set counti [expr int($count)] + append res [SICSValue "lieselotte gettime"] " " + append res $counti " " + for {set i 1} {$i < 7} {incr i} { + append res [SICSValue "lieselotte getmonitor $i"] " " + } + return $res +} +scancter transferscript scantransfer + +MakeScanCommand xxxscan scancter $home/dmc.hdd $home/recover.bin +MakePeakCenter xxxscan + #-------------------- initialize scripted commands source $home/vdmccom.tcl #-------------------- configure commandlog commandlog auto commandlog intervall 5 -#----------- enable sycamore -#InstallSinfox -#source sycFormat.tcl -#source /usr/lib/tcllib1.6.1/stooop/stooop.tcl -#namespace import stooop::* -#source sinfo.tcl -#source sycamore.tcl -#Publish sinfo Spy - #==================== install Hipadaba proc hdbReadOnly {} { error "Parameter is READ ONLY" @@ -169,82 +198,178 @@ proc maketwotheta {} { return $result } #------------------------------------- -InstallProtocolHandler InstallHdb MakeStateMon -hmake /dmc spy none -hsetprop /dmc type instrument +MakeHdbQueue hdbqueue HdbQueue +hmake /instrument spy none +hsetprop /instrument type instrument #-------- experiment -hmake /dmc/experiment spy none -hattach /dmc/experiment title title -hattach /dmc/experiment user user -hattach /dmc/experiment starttime starttime -hattach /dmc/experiment user user -hattach /dmc/experiment/user adress address -hattach /dmc/experiment/user phone phone -hattach /dmc/experiment/user email email -hattach /dmc/experiment comment1 comment1 -hattach /dmc/experiment comment2 comment2 -hattach /dmc/experiment comment3 comment3 +hmake /instrument/experiment spy none +hattach /instrument/experiment title title +hattach /instrument/experiment starttime starttime +hattach /instrument/experiment user user +hattach /instrument/experiment/user adress address +hattach /instrument/experiment/user phone phone +hattach /instrument/experiment/user email email +hattach /instrument/experiment comment1 comment1 +hattach /instrument/experiment comment2 comment2 +hattach /instrument/experiment comment3 comment3 #------- SINQ -hmake /dmc/sinq spy none -hmakescript /dmc/sinq/proton_monitor "counter getmonitor 4" hdbReadOnly int -sicspoll /dmc/sinq/proton_monitor hdb 10 +hmake /instrument/sinq spy none +hmake /instrument/sinq/proton_monitor internal int +hattach /instrument/sinq/proton_monitor counter 4 #-------- monochromator -hmake /dmc/monochromator spy none -hattach /dmc/monochromator lambda wavelength -hattach /dmc/monochromator OmegaM theta -hattach /dmc/monochromator TwoThetaM two_theta -hattach /dmc/monochromator MonoX x_translation -hattach /dmc/monochromator MonoY y_translation -hattach /dmc/monochromator MonoChi chi -hattach /dmc/monochromator MonoPhi phi -hattach /dmc/monochromator CurveM vertical_focusing -hmakescript /dmc/monochromator/d_value "mono dd" "mono dd" float -hsetprop /dmc/monochromator/d_value priv manager -hmakescript /dmc/monochromator/scattering_sense "mono ss" "mono ss" int -hsetprop /dmc/monochromator/scattering_sense priv manager +hmake /instrument/monochromator spy none +hattach /instrument/monochromator lambda wavelength +hsetprop /instrument/monochromator/wavelength priv user +hattach /instrument/monochromator OmegaM theta +hattach /instrument/monochromator TwoThetaM two_theta +hchain /instrument/monochromator/wavelength /instrument/monochromator/two_theta +hattach /instrument/monochromator MonoX x_translation +hattach /instrument/monochromator MonoY y_translation +hattach /instrument/monochromator MonoChi chi +hattach /instrument/monochromator MonoPhi phi +hattach /instrument/monochromator CurveM vertical_focusing +hmakescript /instrument/monochromator/d_value "mono dd" "mono dd" float +hsetprop /instrument/monochromator/d_value priv manager +hmakescript /instrument/monochromator/scattering_sense "mono ss" "mono ss" int +hsetprop /instrument/monochromator/scattering_sense priv manager #----------- sample -hmake /dmc/sample spy none -hmakescript /dmc/sample/name sample sample Text -hattach /dmc/sample Table rotation -hmakescript /dmc/sample/monitor "counter getmonitor 1" hdbReadOnly int -hsetprop /dmc/sample/monitor priv internal +hmake /instrument/sample spy none +hmakescript /instrument/sample/name sample sample Text +hattach /instrument/sample Table rotation +hmake /instrument/sample/monitor internal int +hattach /instrument/sample/monitor counter 1 +hsetprop /instrument/sample/monitor priv internal +hsetprop /instrument/sample/monitor sicsdev histogrammemory #---------- detector -hmake /dmc/detector spy none -hattach /dmc/detector TwoThetaD two_theta -hmakescript /dmc/detector/preset "counter getpreset" hdbReadOnly float -hsetprop /dmc/detector/preset priv internal -hmakescript /dmc/detector/countmode "counter getmode" hdbReadOnly text -hsetprop /dmc/detector/countmode priv internal -sicspoll add /dmc/detector/preset hdb 30 -sicspoll add /dmc/detector/countmode hdb 30 +hmake /instrument/detector spy none +hattach /instrument/detector TwoThetaD two_theta +hmakescript /instrument/detector/preset "banana preset" hdbReadOnly float +hsetprop /instrument/detector/preset priv internal +hmakescript /instrument/detector/countmode "banana countmode" hdbReadOnly text +hsetprop /instrument/detector/countmode priv internal +sicspoll add /instrument/detector/preset hdb 30 +sicspoll add /instrument/detector/countmode hdb 30 +hmake /instrument/detector/count_time internal float +hattach /instrument/detector/count_time counter -1 #------------ commands -hmake /commands spy none -hcommand /commands/count count -hsetprop /commands/count type command -hmake /commands/count/mode user text -hmake /commands/count/preset user float -hset /commands/count/preset 5 -hset /commands/count/mode timer +hmake /instrument/commands spy none +hcommand /instrument/commands/count count +hsetprop /instrument/commands/count type command +hsetprop /instrument/commands/count priv user +hmake /instrument/commands/count/mode user text +hsetprop /instrument/commands/count/mode values "monitor,timer" +hmake /instrument/commands/count/preset user float +hset /instrument/commands/count/preset 60000 +hset /instrument/commands/count/mode monitor +hcommand /instrument/commands/killfile killfile +hsetprop /instrument/commands/killfile type command +hsetprop /instrument/commands/killfile priv manager + +#------------- scan command +hcommand /instrument/commands/scan hdbscan +hsetprop /instrument/commands/scan type command +hsetprop /instrument/commands/scan priv user +hsetprop /instrument/commands/scan viewer mountaingumui.ScanEditor +hmake /instrument/commands/scan/scan_variables user text +hsetprop /instrument/commands/scan/scan_variables argtype drivable +hmake /instrument/commands/scan/scan_start user text +hmake /instrument/commands/scan/scan_increments user text +hmake /instrument/commands/scan/NP user int +hmake /instrument/commands/scan/mode user text +hsetprop /instrument/commands/scan/mode values "timer,monitor" +hmake /instrument/commands/scan/preset user float +hset /instrument/commands/scan/mode timer +hset /instrument/commands/scan/scan_start 2. +hset /instrument/commands/scan/scan_increments .3 +hset /instrument/commands/scan/NP 25 +hset /instrument/commands/scan/preset 2 + +hcommand /instrument/commands/wait wait +hsetprop /instrument/commands/wait type command +hsetprop /instrument/commands/wait priv user +hmake /instrument/commands/wait/time user int + #---------------- graphics -hmake /Graphics spy none -hmake /Graphics/powder_diagram spy none -hsetprop /Graphics/powder_diagram type graphdata -hsetprop /Graphics/powder_diagram viewer default -hmake /Graphics/powder_diagram/rank internal int -hset /Graphics/powder_diagram/rank 1 -hmake /Graphics/powder_diagram/dim internal intar 1 -hset /Graphics/powder_diagram/dim 400 -hmakescript /Graphics/powder_diagram/two_theta maketwotheta hdbReadOnly floatar 400 -sicspoll add /Graphics/powder_diagram/two_theta hdb 30 -hsetprop /Graphics/powder_diagram/two_theta type axis -hsetprop /Graphics/powder_diagram/two_theta dim 0 -hattach /Graphics/powder_diagram banana counts -hsetprop /Graphics/powder_diagram/counts type data -hsetprop /Graphics/powder_diagram/counts priv internal -sicspoll add /Graphics/powder_diagram/counts hdb 60 +hmake /graphics spy none +hmake /graphics/powder_diagram spy none +hattach /graphics/powder_diagram title title +hsetprop /graphics/powder_diagram type graphdata +hsetprop /graphics/powder_diagram viewer default +hmake /graphics/powder_diagram/rank internal int +hset /graphics/powder_diagram/rank 1 +hmake /graphics/powder_diagram/dim internal intar 1 +hset /graphics/powder_diagram/dim 400 +hmakescript /graphics/powder_diagram/two_theta maketwotheta hdbReadOnly floatar 400 +hchain /graphics/powder_diagram/two_theta /instrument/detector/two_theta +hsetprop /graphics/powder_diagram/two_theta type axis +hsetprop /graphics/powder_diagram/two_theta transfer zip +hsetprop /graphics/powder_diagram/two_theta dim 0 +hattach /graphics/powder_diagram banana counts +hsetprop /graphics/powder_diagram/counts type data +hsetprop /graphics/powder_diagram/counts transfer zip +hsetprop /graphics/powder_diagram/counts priv internal +sicspoll add /graphics/powder_diagram/counts hdb 60 + +hmake /graphics/scan_data spy none +hsetprop /graphics/scan_data type graphdata +hsetprop /graphics/scan_data viewer default +hmake /graphics/scan_data/rank mugger int +hset /graphics/scan_data/rank 1 +hsetprop /graphics/scan_data/rank priv internal +hmakescript /graphics/scan_data/dim "xxxscan np" hdbReadOnly intar 1 +hsetprop /graphics/scan_data/dim priv internal +hmakescript /graphics/scan_data/scan_variable "gethdbscanvardata 0" hdbReadOnly floatvarar 1 +hsetprop /graphics/scan_data/scan_variable type axis +hsetprop /graphics/scan_data/scan_variable dim 0 +hsetprop /graphics/scan_data/scan_variable transfer zip +hsetprop /graphics/scan_data/scan_variable priv internal +hmakescript /graphics/scan_data/counts "gethdbscancounts" hdbReadOnly intvarar 1 +hsetprop /graphics/scan_data/counts type data +hsetprop /graphics/scan_data/counts transfer zip +hsetprop /graphics/scan_data/counts priv internal + +hmake /graphics/samenv spy none +hsetprop /graphics/samenv type graphdata +hsetprop /graphics/samenv viewer mountaingumui.TimeSeries +hmake /graphics/samenv/vars user text +hset /graphics/samenv/vars tomato +hmake /graphics/samenv/rank user int +hset /graphics/samenv/rank 1 +hmake /graphics/samenv/dim user intar 1 +hset /graphics/samenv/dim 300 +hmake /graphics/samenv/getdata user text +hsetprop /graphics/samenv/getdata type logcommand +hsetprop /graphics/samenv/getdata datacom true +hmake /graphics/samenv/getdata/starttime spy text +hmake /graphics/samenv/getdata/endtime spy text + +hmake /batch spy none +hmakescript /batch/bufferlist listbatchfiles hdbReadOnly text +sicspoll add /batch/bufferlist hdb 30 +hmake /batch/commandtext spy text +hsetprop /batch/commandtext viewer mountaingumui.TextEdit +hsetprop /batch/commandtext commandtext true + + +hmake /gui spy none +hmake /gui/status internal text +status hdbinterest /gui/status + +proc makeQuickPar {name path} { + hmake /quickview/$name mugger text + hset /quickview/$name $path +} + +hmake /quickview spy none +makeQuickPar title /instrument/experiment/title +makeQuickPar sample /instrument/sample/name +makeQuickPar lambda /instrument/monochromator/wavelength +makeQuickPar two-theta /instrument/detector/two_theta +makeQuickPar preset /instrument/detector/preset +makeQuickPar monitor /instrument/sample/monitor restore diff --git a/mcstas/dmc/vdmccom.tcl b/mcstas/dmc/vdmccom.tcl index a78a78f1..00c2b020 100644 --- a/mcstas/dmc/vdmccom.tcl +++ b/mcstas/dmc/vdmccom.tcl @@ -18,10 +18,18 @@ if { [info exists vdmcinit] == 0 } { Publish wwwfilefornumber Spy mcinstall Publish gethm Spy + Publish hdbscan User + Publish hdbprepare User + Publish hdbcollect User + Publish mgbatch Spy + Publish loadmgbatch Spy + Publish listbatchfiles Spy } source $home/log.tcl source $home/nxsupport.tcl source $home/nxdmc.tcl +source $home/gumxml.tcl +source $home/gumibatch.tcl #------------------------------------------------------------------------ proc SplitReply { text } { set l [split $text =] @@ -193,8 +201,17 @@ proc copydmcdataold { } { proc copydmcdata { } { global home set mcversion "McStas 1.8 - Mar. 05, 2004" - washsimfile $home/dmc.xml - mcreader open $home/dmc.xml +#---- loop till the file can be opened + for {set i 0} {$i < 20} {incr i} { + washsimfile $home/dmc.xml + set stat [catch {mcreader open $home/dmc.xml} msg] + if {$stat == 0} { + break + } else { + file copy -force $home/dmc.xml $home/brokenfile.xml + wait 1 + } + } mcreader insertmon \ "/$mcversion/DMC_diff/dmc.xml/PSD_sample/values" \ counter 1 [expr 1./350] @@ -260,6 +277,7 @@ proc count { {mode NULL } { preset NULL } } { #------- count banana InitVal 0 wait 1 + hupdate /graphics/powder_diagram/counts banana count set ret [catch {Success} msg] #------- StoreData @@ -395,5 +413,92 @@ proc wwwfilefornumber {num} { proc gethm {} { banana uuget 0 } - - +#-------------------------------------------------------------------- +proc hdbscan {scanvars scanstart scanincr np mode preset} { + xxxscan clear + xxxscan configure script + xxxscan function prepare hdbprepare + xxxscan function collect hdbcollect + set varlist [split $scanvars ,] + set startlist [split $scanstart ,] + set incrlist [split $scanincr ,] + set count 0 + foreach var $varlist { + if {[string first / $var] >= 0} { + set var [string trim [SplitReply [hgetprop $var sicsdev]]] + } + xxxscan add $var [lindex $startlist $count] [lindex $incrlist $count] + incr count + } + set status [catch {xxxscan run $np $mode $preset} msg] + if {$status == 0} { + return $msg + } else { + error $msg + } +} +#------------------------------------------------------------------------------ +proc hdbprepare {obj userdata } { + stdscan prepare $obj userdata + hupdate /graphics/scan_data/dim +} +#------------------------------------------------------------------------------ +proc hdbcollect {obj userobj np} { + stdscan collect $obj $userobj $np + hupdate /graphics/scan_data/scan_variable + hupdate /graphics/scan_data/counts +} +#----------------------------------------------------------------------------- +proc gethdbscanvardata {no} { + set np [string trim [SplitReply [xxxscan np]]] + if {$np == 0} { + return ".0 .0 .0" + } + set status [catch {SplitReply [xxxscan getvardata $no]} txt] + if {$status == 0} { + return [join $txt] + } else { + return ".0 .0 .0" + } +} +#---------------------------------------------------------------------------- +proc gethdbscancounts {} { + set np [string trim [SplitReply [xxxscan np]]] + if {$np == 0} { + return "0 0 0" + } + set status [catch {SplitReply [xxxscan getcounts]} txt] + if {$status == 0} { + return [join $txt] + } else { + return "0 0 0" + } +} +#================= helper to get the list of batch files ================= +proc listbatchfiles {} { + set ext [list *.tcl *.job] + set txt [SplitReply [exe batchpath]] + set dirlist [split $txt :] + set txt [SplitReply [exe syspath]] + set dirlist [concat $dirlist [split $txt :]] + set result [list ""] + foreach dir $dirlist { + foreach e $ext { + set status [catch {glob [string trim $dir]/$e} filetxt] + if {$status == 0} { + set filelist [split $filetxt] + foreach f $filelist { + set nam [file tail $f] + if { [lsearch $result $nam] < 0} { + lappend result $nam + } + } + } + } + } + foreach bf $result { + append resulttxt $bf , + } + return [string trim $resulttxt ,] +} +#----------------------------------------------------------------------- diff --git a/mcstas/dmc/vdmcstatus.tcl b/mcstas/dmc/vdmcstatus.tcl index 382c0055..1b9a1bb9 100644 --- a/mcstas/dmc/vdmcstatus.tcl +++ b/mcstas/dmc/vdmcstatus.tcl @@ -1,5 +1,9 @@ -exe batchpath ./ +exe batchpath tmp exe syspath ./ + +#--- BEGIN (commands producing errors on last restore) +#--- END (commands producing errors on last restore) + # Motor omegam omegam sign 1.000000 omegam SoftZero 0.000000 @@ -10,17 +14,21 @@ omegam InterruptMode 0.000000 omegam precision 0.010000 omegam ignorefault 0.000000 omegam AccessCode 2.000000 +omegam failafter 3.000000 +omegam maxretry 3.000000 omegam movecount 10.000000 # Motor twothetam twothetam sign 1.000000 twothetam SoftZero 0.000000 -twothetam SoftLowerLim 30.000000 +twothetam SoftLowerLim 35.000000 twothetam SoftUpperLim 100.000000 twothetam Fixed -1.000000 twothetam InterruptMode 0.000000 twothetam precision 0.010000 twothetam ignorefault 0.000000 twothetam AccessCode 2.000000 +twothetam failafter 3.000000 +twothetam maxretry 3.000000 twothetam movecount 10.000000 # Motor monox monox sign 1.000000 @@ -32,6 +40,8 @@ monox InterruptMode 0.000000 monox precision 0.010000 monox ignorefault 0.000000 monox AccessCode 2.000000 +monox failafter 3.000000 +monox maxretry 3.000000 monox movecount 10.000000 # Motor monoy monoy sign 1.000000 @@ -43,6 +53,8 @@ monoy InterruptMode 0.000000 monoy precision 0.010000 monoy ignorefault 0.000000 monoy AccessCode 2.000000 +monoy failafter 3.000000 +monoy maxretry 3.000000 monoy movecount 10.000000 # Motor curvem curvem sign 1.000000 @@ -54,6 +66,8 @@ curvem InterruptMode 0.000000 curvem precision 0.010000 curvem ignorefault 0.000000 curvem AccessCode 2.000000 +curvem failafter 3.000000 +curvem maxretry 3.000000 curvem movecount 10.000000 # Motor monophi monophi sign 1.000000 @@ -65,6 +79,8 @@ monophi InterruptMode 0.000000 monophi precision 0.010000 monophi ignorefault 0.000000 monophi AccessCode 2.000000 +monophi failafter 3.000000 +monophi maxretry 3.000000 monophi movecount 10.000000 # Motor monochi monochi sign 1.000000 @@ -76,17 +92,21 @@ monochi InterruptMode 0.000000 monochi precision 0.010000 monochi ignorefault 0.000000 monochi AccessCode 2.000000 +monochi failafter 3.000000 +monochi maxretry 3.000000 monochi movecount 10.000000 # Motor table table sign 1.000000 table SoftZero 0.000000 -table SoftLowerLim -180.000000 +table SoftLowerLim -360.000000 table SoftUpperLim 360.000000 table Fixed -1.000000 table InterruptMode 0.000000 table precision 0.010000 table ignorefault 0.000000 table AccessCode 2.000000 +table failafter 3.000000 +table maxretry 3.000000 table movecount 10.000000 # Motor twothetad twothetad sign 1.000000 @@ -98,12 +118,14 @@ twothetad InterruptMode 0.000000 twothetad precision 0.010000 twothetad ignorefault 0.000000 twothetad AccessCode 2.000000 +twothetad failafter 3.000000 +twothetad maxretry 3.000000 twothetad movecount 10.000000 # Counter counter -counter SetPreset 30000000.000000 +counter SetPreset 60000.000000 counter SetMode Monitor banana CountMode monitor -banana preset 300.000000 +banana preset 60000.000000 # Motor a1 a1 sign 1.000000 a1 SoftZero 0.000000 @@ -114,28 +136,34 @@ a1 InterruptMode 0.000000 a1 precision 0.010000 a1 ignorefault 0.000000 a1 AccessCode 2.000000 +a1 failafter 3.000000 +a1 maxretry 3.000000 a1 movecount 10.000000 # Motor a2 a2 sign 1.000000 a2 SoftZero 0.000000 -a2 SoftLowerLim 30.000000 +a2 SoftLowerLim 35.000000 a2 SoftUpperLim 100.000000 a2 Fixed -1.000000 a2 InterruptMode 0.000000 a2 precision 0.010000 a2 ignorefault 0.000000 a2 AccessCode 2.000000 +a2 failafter 3.000000 +a2 maxretry 3.000000 a2 movecount 10.000000 # Motor a3 a3 sign 1.000000 a3 SoftZero 0.000000 -a3 SoftLowerLim -180.000000 +a3 SoftLowerLim -360.000000 a3 SoftUpperLim 360.000000 a3 Fixed -1.000000 a3 InterruptMode 0.000000 a3 precision 0.010000 a3 ignorefault 0.000000 a3 AccessCode 2.000000 +a3 failafter 3.000000 +a3 maxretry 3.000000 a3 movecount 10.000000 # Motor a4 a4 sign 1.000000 @@ -147,6 +175,8 @@ a4 InterruptMode 0.000000 a4 precision 0.010000 a4 ignorefault 0.000000 a4 AccessCode 2.000000 +a4 failafter 3.000000 +a4 maxretry 3.000000 a4 movecount 10.000000 # Motor a5 a5 sign 1.000000 @@ -158,6 +188,8 @@ a5 InterruptMode 0.000000 a5 precision 0.010000 a5 ignorefault 0.000000 a5 AccessCode 2.000000 +a5 failafter 3.000000 +a5 maxretry 3.000000 a5 movecount 10.000000 # Motor a6 a6 sign 1.000000 @@ -169,6 +201,8 @@ a6 InterruptMode 0.000000 a6 precision 0.010000 a6 ignorefault 0.000000 a6 AccessCode 2.000000 +a6 failafter 3.000000 +a6 maxretry 3.000000 a6 movecount 10.000000 # Motor a7 a7 sign 1.000000 @@ -180,6 +214,8 @@ a7 InterruptMode 0.000000 a7 precision 0.010000 a7 ignorefault 0.000000 a7 AccessCode 2.000000 +a7 failafter 3.000000 +a7 maxretry 3.000000 a7 movecount 10.000000 # Motor a8 a8 sign 1.000000 @@ -191,6 +227,8 @@ a8 InterruptMode 0.000000 a8 precision 0.010000 a8 ignorefault 0.000000 a8 AccessCode 2.000000 +a8 failafter 3.000000 +a8 maxretry 3.000000 a8 movecount 10.000000 # Motor a9 a9 sign 1.000000 @@ -202,10 +240,12 @@ a9 InterruptMode 0.000000 a9 precision 0.010000 a9 ignorefault 0.000000 a9 AccessCode 2.000000 +a9 failafter 3.000000 +a9 maxretry 3.000000 a9 movecount 10.000000 -title D3C in Senfsosse +title Lieselotte Nass title setAccess 2 -user UNKNOWN +user Lukas user setAccess 2 collimation UNKNOWN collimation setAccess 2 @@ -217,17 +257,25 @@ comment2 UNKNOWN comment2 setAccess 2 comment3 UNKNOWN comment3 setAccess 2 -starttime 2007-02-20 11:27:09 +starttime 2008-03-18 13:09:23 starttime setAccess 2 -adress UNKNOWN +adress 2223 Luketown, 33 Luke Drive adress setAccess 2 phone UNKNOWN phone setAccess 2 fax UNKNOWN fax setAccess 2 -email UNKNOWN +email Luke@luke.ch email setAccess 2 sample_mur 0.000000 sample_mur setAccess 2 -lastdatafile /afs/psi.ch/user/k/koennecke/src/workspace/sics/mcstas/dmc/000/vdmc2007n000133.xml +lastdatafile /afs/psi.ch/user/k/koennecke/src/workspace/sics/mcstas/dmc/000/vdmc2008n000230.xml lastdatafile setAccess 2 +lastscancommand unknown scan +lastscancommand setAccess 2 +# Counter lieselotte +lieselotte SetPreset 2.000000 +lieselotte SetMode Timer +# Counter scancter +scancter SetPreset 2.000000 +scancter SetMode Timer diff --git a/mcstascounter.c b/mcstascounter.c index e7f07269..adbf2c02 100644 --- a/mcstascounter.c +++ b/mcstascounter.c @@ -8,6 +8,7 @@ -----------------------------------------------------------------------------*/ #include #include +#include #include "sics.h" #include "countdriv.h" #include "mccontrol.h" @@ -76,6 +77,7 @@ static int McReadValues(struct __COUNTER *self){ if(status == HWFault){ self->iErrorCode = SCRIPTERROR; } + self->fTime = time(NULL) - pMcStas->startTime; return status; } /*--------------------------------------------------------------------------*/ diff --git a/mesure.c b/mesure.c index 7d3a2820..cb69ba3b 100644 --- a/mesure.c +++ b/mesure.c @@ -987,10 +987,28 @@ static int ScanReflection(pMesure self, float twoTheta, SConnection *pCon) return 1; } +/*---------------------------------------------------------------------------*/ +static double getProtonAverage(pMesure self){ + int np, i; + long *lData = NULL, lSum = 0; + + np = GetScanNP(self->pScanner); + lData = (long *)malloc((np+1)*sizeof(long)); + if(lData == NULL || np == 0){ + return 0.; + } + memset(lData,0,(np+1)*sizeof(long)); + GetScanMonitor(self->pScanner,2,lData, np); + for(i = 0; i < np; i++){ + lSum += lData[i]; + } + return (double)lSum/(double)np; +} /*---------------------------------------------------------------------------*/ static int WriteReflection(pMesure self, float fHKL[3],SConnection *pCon) { float fSum, fSigma, fSet[4], fTemp, fPreset, fStep; + double prot; static float fMax = 10.; int iRet, i,ii, iLF, iNP; char pBueffel[512], pNum[10], pTime[132]; @@ -1107,8 +1125,9 @@ static int ScanReflection(pMesure self, float twoTheta, SConnection *pCon) SNXFormatTime(pBueffel,512); GetScanVarStep(self->pScanner,0,&fStep); fPreset = GetScanPreset(self->pScanner); - fprintf(self->fRefl,"%3d %7.4f %9.0f %7.3f %s\n",iNP,fStep, - fPreset,fTemp,pBueffel); + prot = getProtonAverage(self); + fprintf(self->fRefl,"%3d %7.4f %9.0f %7.3f %12f %s\n",iNP,fStep, + fPreset,fTemp,prot, pBueffel); for(i = 0; i < iNP; i++) { for(ii = 0; ii < 10 && i < iNP; ii++) diff --git a/motor.c b/motor.c index 04071e71..d410e44f 100644 --- a/motor.c +++ b/motor.c @@ -171,8 +171,10 @@ fputs(pBueffel,fd); sprintf(pBueffel,"%s AccessCode %f\n",name,ObVal(self->ParArray,USRIGHTS)); fputs(pBueffel,fd); - sprintf(pBueffel,"%s poscount %f\n",name, - ObVal(self->ParArray,POSCOUNT)); + sprintf(pBueffel,"%s failafter %f\n",name,ObVal(self->ParArray,ECOUNT)); + fputs(pBueffel,fd); + sprintf(pBueffel,"%s maxretry %f\n",name,ObVal(self->ParArray,POSCOUNT)); + fputs(pBueffel,fd); sprintf(pBueffel,"%s movecount %f\n",name, ObVal(self->ParArray,MOVECOUNT)); fputs(pBueffel,fd); @@ -256,6 +258,8 @@ void finishDriving(pMotor self, SConnection *pCon) MotCallback sCall; MotorGetSoftPosition(self,pCon,&sCall.fVal); sCall.pName = self->name; + self->fPosition = sCall.fVal; + self->fPosition = sCall.fVal; InvokeCallBack(self->pCall, MOTDRIVE, &sCall); /* send also very last position */ InvokeCallBack(self->pCall, MOTEND, &sCall); } @@ -330,7 +334,7 @@ static int evaluateStatus(pMotor self, SConnection *pCon) newStatus = checkPosition(self,pCon); if(newStatus != HWBusy) { - finishDriving(self,pCon); + finishDriving(self,pCon); } } break; @@ -351,6 +355,7 @@ static int evaluateStatus(pMotor self, SConnection *pCon) } if(newStatus == HWFault) { + finishDriving(self,pCon); MotorInterrupt(pCon,ObVal(self->ParArray,INT)); self->retryCount = 0; } diff --git a/multicounter.c b/multicounter.c index 88463805..d2e40555 100644 --- a/multicounter.c +++ b/multicounter.c @@ -298,13 +298,11 @@ static int MultiCounterSend(struct __COUNTER *self, char *pText, return 0; } /*---------------------------------------------------------------------*/ -static int MultiCounterError(struct __COUNTER *pData, int *iCode, +static int MultiCounterError(struct __COUNTER *pDriv, int *iCode, char *error, int errlen){ - pCounter pCount = NULL; + - pCount = (pCounter)pData; - - if(pCount->pDriv->iErrorCode == NOCOUNTERS){ + if(pDriv->iErrorCode == NOCOUNTERS){ strncpy(error,"NO counters configured!",errlen); } else { strncpy(error,"Not Implemented", errlen); diff --git a/mumo.c b/mumo.c index 3fbb3ad8..d3b8c406 100644 --- a/mumo.c +++ b/mumo.c @@ -872,6 +872,7 @@ static void RecoverNamPos(pMulMot self, int argc, char *argv[]) sprintf(pBueffel,"%s list of known named positions \n", argv[0]); Tcl_DStringAppend(&tString,pBueffel,strlen(pBueffel)); + StringDictKillScan(self->pNamPos); pPtr = StringDictGetNext(self->pNamPos,pError,131); while(pPtr != NULL) { diff --git a/napi.c b/napi.c index 8271a3ef..3de6d75a 100644 --- a/napi.c +++ b/napi.c @@ -3,7 +3,7 @@ Application Program Interface Routines - Copyright (C) 1997-2000 Mark Koennecke, Przemek Klosowski + Copyright (C) 1997-2006 Mark Koennecke, Przemek Klosowski This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -23,7 +23,7 @@ ----------------------------------------------------------------------------*/ -static const char* rscid = "$Id: napi.c,v 1.13 2006/03/03 15:30:55 koennecke Exp $"; /* Revision interted by CVS */ +static const char* rscid = "$Id$"; /* Revision inserted by CVS */ #include #include @@ -33,8 +33,81 @@ static const char* rscid = "$Id: napi.c,v 1.13 2006/03/03 15:30:55 koennecke Exp #include #include #include "napi.h" +#include "nxstack.h" +/*--------------------------------------------------------------------- + Recognized and handled napimount URLS + -----------------------------------------------------------------------*/ +#define NXBADURL 0 +#define NXFILE 1 + +/*--------------------------------------------------------------------*/ static int iFortifyScope; +/*---------------------------------------------------------------------- + This is a section with code for searching the NX_LOAD_PATH + -----------------------------------------------------------------------*/ +#ifdef _WIN32 +#define LIBSEP ";" +#define PATHSEP "\\" +#else +#define LIBSEP ":" +#define PATHSEP "/" +#endif +extern char *stptok(char *s, char *tok, size_t toklen, char *brk); +/*--------------------------------------------------------------------- + wrapper for getenv. This is a future proofing thing for porting to OS + which have different ways of accessing environment variables + --------------------------------------------------------------------*/ +static char *nxgetenv(const char *name){ + return getenv(name); +} +/*----------------------------------------------------------------------*/ +static int canOpen(char *filename){ + FILE *fd = NULL; + + fd = fopen(filename,"r"); + if(fd != NULL){ + fclose(fd); + return 1; + } else { + return 0; + } +} +/*--------------------------------------------------------------------*/ +static char *locateNexusFileInPath(char *startName){ + char *loadPath = NULL, *testPath = NULL, *pPtr = NULL; + char pathPrefix[256]; + int length; + + if(canOpen(startName)){ + return strdup(startName); + } + + loadPath = nxgetenv("NX_LOAD_PATH"); + if(loadPath == NULL){ + /* file not found will be issued by upper level code */ + return strdup(startName); + } + + pPtr = stptok(loadPath,pathPrefix,255,LIBSEP); + while(pPtr != NULL){ + length = strlen(pathPrefix) + strlen(startName) + strlen(PATHSEP) + 2; + testPath = malloc(length*sizeof(char)); + if(testPath == NULL){ + return strdup(startName); + } + memset(testPath,0,length*sizeof(char)); + strcpy(testPath, pathPrefix); + strcat(testPath,PATHSEP); + strcat(testPath,startName); + if(canOpen(testPath)){ + return(testPath); + } + free(testPath); + pPtr = stptok(pPtr,pathPrefix,255,LIBSEP); + } + return strdup(startName); +} /*------------------------------------------------------------------------ HDF-5 cache size special stuff -------------------------------------------------------------------------*/ @@ -49,7 +122,6 @@ NXstatus NXsetcache(long newVal) } return NX_ERROR; } - /*-----------------------------------------------------------------------*/ static NXstatus NXisXML(CONSTCHAR *filename) @@ -69,22 +141,14 @@ static NXstatus NXisXML(CONSTCHAR *filename) } /*-------------------------------------------------------------------------*/ - - - /*---------------------------------------------------------------------*/ - - void NXNXNXReportError(void *pData, char *string) + static void NXNXNXReportError(void *pData, char *string) { printf("%s \n",string); } - /*---------------------------------------------------------------------*/ - void *NXpData = NULL; void (*NXIReportError)(void *pData, char *string) = NXNXNXReportError; - /*---------------------------------------------------------------------*/ - extern void NXMSetError(void *pData, void (*NewError)(void *pD, char *text)) { @@ -95,7 +159,27 @@ static NXstatus NXisXML(CONSTCHAR *filename) extern ErrFunc NXMGetError(){ return NXIReportError; } - + +/*----------------------------------------------------------------------*/ +void NXNXNoReport(void *pData, char *string){ + /* do nothing */ +} +/*----------------------------------------------------------------------*/ + +static ErrFunc last_errfunc = NXNXNXReportError; + +extern void NXMDisableErrorReporting() +{ + last_errfunc = NXMGetError(); + NXMSetError(NXpData, NXNXNoReport); +} + +extern void NXMEnableErrorReporting() +{ + NXMSetError(NXpData, last_errfunc); +} + +/*----------------------------------------------------------------------*/ #ifdef HDF5 #include "napi5.h" #endif @@ -105,7 +189,6 @@ extern ErrFunc NXMGetError(){ #ifdef NXXML #include "nxxml.h" #endif - /* ---------------------------------------------------------------------- Definition of NeXus API @@ -148,17 +231,49 @@ static int determineFileType(CONSTCHAR *filename) */ return 0; } +/*---------------------------------------------------------------------*/ +static pNexusFunction handleToNexusFunc(NXhandle fid){ + pFileStack fileStack = NULL; + fileStack = (pFileStack)fid; + if(fileStack != NULL){ + return peekFileOnStack(fileStack); + } else { + return NULL; + } +} +/*--------------------------------------------------------------------*/ +static NXstatus NXinternalopen(CONSTCHAR *userfilename, NXaccess am, + pFileStack fileStack); +/*----------------------------------------------------------------------*/ +NXstatus NXopen(CONSTCHAR *userfilename, NXaccess am, NXhandle *gHandle){ + int status; + pFileStack fileStack = NULL; + NXhandle hfile; + + fileStack = makeFileStack(); + if(fileStack == NULL){ + NXIReportError (NXpData,"ERROR: no memory to create filestack"); + return NX_ERROR; + } + status = NXinternalopen(userfilename,am,fileStack); + if(status == NX_OK){ + *gHandle = fileStack; + } + + return status; +} /*-----------------------------------------------------------------------*/ - NXstatus NXopen(CONSTCHAR *filename, NXaccess am, NXhandle *gHandle) +static NXstatus NXinternalopen(CONSTCHAR *userfilename, NXaccess am, pFileStack fileStack) { int hdf_type=0; int iRet=0; - NXhandle hdf5_handle; - NXhandle hdf4_handle; - NXhandle xmlHandle; - pNexusFunction fHandle; - NXstatus retstat; + NXhandle hdf5_handle = NULL; + NXhandle hdf4_handle = NULL; + NXhandle xmlHandle = NULL; + pNexusFunction fHandle = NULL; + NXstatus retstat = NX_ERROR; char error[1024]; + char *filename = NULL; /* configure fortify iFortifyScope = Fortify_EnterScope(); @@ -168,13 +283,12 @@ static int determineFileType(CONSTCHAR *filename) /* allocate data */ - *gHandle = NULL; fHandle = (pNexusFunction)malloc(sizeof(NexusFunction)); if (fHandle == NULL) { NXIReportError (NXpData,"ERROR: no memory to create Function structure"); return NX_ERROR; - } - memset(fHandle, 0, sizeof(NexusFunction)); /* so any functions we miss are NULL */ + } + memset(fHandle, 0, sizeof(NexusFunction)); /* so any functions we miss are NULL */ /* test the strip flag. Elimnate it for the rest of the tests to work @@ -188,49 +302,68 @@ static int determineFileType(CONSTCHAR *filename) if (am==NXACC_CREATE) { /* HDF4 will be used ! */ hdf_type=1; + filename = strdup(userfilename); } else if (am==NXACC_CREATE4) { /* HDF4 will be used ! */ hdf_type=1; + filename = strdup(userfilename); } else if (am==NXACC_CREATE5) { /* HDF5 will be used ! */ hdf_type=2; + filename = strdup(userfilename); } else if (am==NXACC_CREATEXML) { /* XML will be used ! */ hdf_type=3; + filename = strdup(userfilename); } else { + filename = locateNexusFileInPath((char *)userfilename); + if(filename == NULL){ + NXIReportError(NXpData,"Out of memory in NeXus-API"); + free(fHandle); + return NX_ERROR; + } /* check file type hdf4/hdf5/XML for reading */ iRet = determineFileType(filename); if(iRet < 0) { snprintf(error,1023,"failed to open %s for reading", filename); NXIReportError(NXpData,error); + free(filename); return NX_ERROR; } if(iRet == 0){ - snprintf(error,1023,"failed to detrmine filetype for %s ", + snprintf(error,1023,"failed to determine filetype for %s ", filename); NXIReportError(NXpData,error); + free(filename); + free(fHandle); return NX_ERROR; } hdf_type = iRet; } + if(filename == NULL){ + NXIReportError(NXpData,"Out of memory in NeXus-API"); + return NX_ERROR; + } + if (hdf_type==1) { /* HDF4 type */ #ifdef HDF4 retstat = NX4open((const char *)filename,am,&hdf4_handle); if(retstat != NX_OK){ free(fHandle); + free(filename); return retstat; } - fHandle->pNexusData=hdf4_handle; - NX4assignFunctions(fHandle); - *gHandle = fHandle; + fHandle->pNexusData=hdf4_handle; + NX4assignFunctions(fHandle); + pushFileStack(fileStack,fHandle,filename); #else NXIReportError (NXpData, "ERROR: Attempt to create HDF4 file when not linked with HDF4"); - *gHandle = NULL; retstat = NX_ERROR; #endif /* HDF4 */ + free(filename); return retstat; } else if (hdf_type==2) { /* HDF5 type */ @@ -238,17 +371,18 @@ static int determineFileType(CONSTCHAR *filename) retstat = NX5open(filename,am,&hdf5_handle); if(retstat != NX_OK){ free(fHandle); + free(filename); return retstat; } - fHandle->pNexusData=hdf5_handle; - NX5assignFunctions(fHandle); - *gHandle = fHandle; + fHandle->pNexusData=hdf5_handle; + NX5assignFunctions(fHandle); + pushFileStack(fileStack,fHandle, filename); #else NXIReportError (NXpData, "ERROR: Attempt to create HDF5 file when not linked with HDF5"); - *gHandle = NULL; retstat = NX_ERROR; #endif /* HDF5 */ + free(filename); return retstat; } else if(hdf_type == 3){ /* @@ -258,24 +392,26 @@ static int determineFileType(CONSTCHAR *filename) retstat = NXXopen(filename,am,&xmlHandle); if(retstat != NX_OK){ free(fHandle); + free(filename); return retstat; } fHandle->pNexusData=xmlHandle; NXXassignFunctions(fHandle); - *gHandle = fHandle; + pushFileStack(fileStack,fHandle, filename); #else NXIReportError (NXpData, "ERROR: Attempt to create XML file when not linked with XML"); - *gHandle = NULL; retstat = NX_ERROR; #endif } else { NXIReportError (NXpData, "ERROR: Format not readable by this NeXus library"); - *gHandle = NULL; - return NX_ERROR; + retstat = NX_ERROR; } - return NX_OK; + if (filename != NULL) { + free(filename); + } + return retstat; } /* ------------------------------------------------------------------------- */ @@ -284,13 +420,19 @@ static int determineFileType(CONSTCHAR *filename) { NXhandle hfil; int status; + pFileStack fileStack = NULL; pNexusFunction pFunc=NULL; - pFunc = (pNexusFunction)*fid; + fileStack = (pFileStack)*fid; + pFunc = peekFileOnStack(fileStack); hfil = pFunc->pNexusData; status = pFunc->nxclose(&hfil); pFunc->pNexusData = hfil; free(pFunc); + popFileStack(fileStack); + if(fileStackDepth(fileStack) < 0){ + killFileStack(fileStack); + } /* Fortify_CheckAllMemory(); */ @@ -301,24 +443,113 @@ static int determineFileType(CONSTCHAR *filename) NXstatus NXmakegroup (NXhandle fid, CONSTCHAR *name, CONSTCHAR *nxclass) { - pNexusFunction pFunc = (pNexusFunction)fid; + pNexusFunction pFunc = handleToNexusFunc(fid); return pFunc->nxmakegroup(pFunc->pNexusData, name, nxclass); } + /*------------------------------------------------------------------------*/ +static int analyzeNapimount(char *napiMount, char *extFile, int extFileLen, + char *extPath, int extPathLen){ + char *pPtr = NULL, *path = NULL; + int length; + memset(extFile,0,extFileLen); + memset(extPath,0,extPathLen); + pPtr = strstr(napiMount,"nxfile://"); + if(pPtr == NULL){ + return NXBADURL; + } + path = strrchr(napiMount,'#'); + if(path == NULL){ + length = strlen(napiMount) - 9; + if(length > extFileLen){ + NXIReportError(NXpData,"ERROR: internal errro with external linking"); + return NXBADURL; + } + memcpy(extFile,pPtr+9,length); + strcpy(extPath,"/"); + return NXFILE; + } else { + pPtr += 9; + length = path - pPtr; + if(length > extFileLen){ + NXIReportError(NXpData,"ERROR: internal errro with external linking"); + return NXBADURL; + } + memcpy(extFile,pPtr,length); + length = strlen(path-1); + if(length > extPathLen){ + NXIReportError(NXpData,"ERROR: internal error with external linking"); + return NXBADURL; + } + strcpy(extPath,path+1); + return NXFILE; + } + return NXBADURL; +} /*------------------------------------------------------------------------*/ NXstatus NXopengroup (NXhandle fid, CONSTCHAR *name, CONSTCHAR *nxclass) { - pNexusFunction pFunc = (pNexusFunction)fid; - return pFunc->nxopengroup(pFunc->pNexusData, name, nxclass); + int status, attStatus, type = NX_CHAR, length = 1023; + NXaccess access = NXACC_RDWR; + NXlink breakID; + pFileStack fileStack; + char nxurl[1024], exfile[512], expath[512]; + ErrFunc oldError; + pNexusFunction pFunc = NULL; + + fileStack = (pFileStack)fid; + pFunc = handleToNexusFunc(fid); + + status = pFunc->nxopengroup(pFunc->pNexusData, name, nxclass); + oldError = NXMGetError(); + NXIReportError = NXNXNoReport; + attStatus = NXgetattr(fid,"napimount",nxurl,&length, &type); + NXIReportError = oldError; + if(attStatus == NX_OK){ + /* + this is an external linking group + */ + status = analyzeNapimount(nxurl,exfile,511,expath,511); + if(status == NXBADURL){ + return NX_ERROR; + } + status = NXinternalopen(exfile,access, fileStack); + if(status == NX_ERROR){ + return status; + } + status = NXopenpath(fid,expath); + NXgetgroupID(fid,&breakID); + setCloseID(fileStack,breakID); + } + + return status; } /* ------------------------------------------------------------------- */ NXstatus NXclosegroup (NXhandle fid) { - pNexusFunction pFunc = (pNexusFunction)fid; - return pFunc->nxclosegroup(pFunc->pNexusData); + int status; + pFileStack fileStack = NULL; + NXlink closeID, currentID; + + pNexusFunction pFunc = handleToNexusFunc(fid); + fileStack = (pFileStack)fid; + if(fileStackDepth(fileStack) == 0){ + return pFunc->nxclosegroup(pFunc->pNexusData); + } else { + /* we have to check for leaving an external file */ + NXgetgroupID(fid,¤tID); + peekIDOnStack(fileStack,&closeID); + if(NXsameID(fid,&closeID,¤tID) == NX_OK){ + NXclose(&fid); + status = NXclosegroup(fid); + } else { + status = pFunc->nxclosegroup(pFunc->pNexusData); + } + return status; + } } /* --------------------------------------------------------------------- */ @@ -326,17 +557,8 @@ static int determineFileType(CONSTCHAR *filename) NXstatus NXmakedata (NXhandle fid, CONSTCHAR *name, int datatype, int rank, int dimensions[]) { - pNexusFunction pFunc = (pNexusFunction)fid; - if ( (datatype == NX_CHAR) && (rank > 1) ) - { - NXIReportError (NXpData, - "ERROR: multi-dimensional NX_CHAR arrays are not supported by the NeXus library"); - return NX_ERROR; - } - else - { - return pFunc->nxmakedata(pFunc->pNexusData, name, datatype, rank, dimensions); - } + pNexusFunction pFunc = handleToNexusFunc(fid); + return pFunc->nxmakedata(pFunc->pNexusData, name, datatype, rank, dimensions); } @@ -345,17 +567,8 @@ static int determineFileType(CONSTCHAR *filename) NXstatus NXcompmakedata (NXhandle fid, CONSTCHAR *name, int datatype, int rank, int dimensions[],int compress_type, int chunk_size[]) { - pNexusFunction pFunc = (pNexusFunction)fid; - if ( (datatype == NX_CHAR) && (rank > 1) ) - { - NXIReportError (NXpData, - "ERROR: multi-dimensional NX_CHAR arrays are not supported by the NeXus library"); - return NX_ERROR; - } - else - { - return pFunc->nxcompmakedata (pFunc->pNexusData, name, datatype, rank, dimensions, compress_type, chunk_size); - } + pNexusFunction pFunc = handleToNexusFunc(fid); + return pFunc->nxcompmakedata (pFunc->pNexusData, name, datatype, rank, dimensions, compress_type, chunk_size); } @@ -363,7 +576,7 @@ static int determineFileType(CONSTCHAR *filename) NXstatus NXcompress (NXhandle fid, int compress_type) { - pNexusFunction pFunc = (pNexusFunction)fid; + pNexusFunction pFunc = handleToNexusFunc(fid); return pFunc->nxcompress (pFunc->pNexusData, compress_type); } @@ -372,7 +585,7 @@ static int determineFileType(CONSTCHAR *filename) NXstatus NXopendata (NXhandle fid, CONSTCHAR *name) { - pNexusFunction pFunc = (pNexusFunction)fid; + pNexusFunction pFunc = handleToNexusFunc(fid); return pFunc->nxopendata(pFunc->pNexusData, name); } @@ -381,7 +594,7 @@ static int determineFileType(CONSTCHAR *filename) NXstatus NXclosedata (NXhandle fid) { - pNexusFunction pFunc = (pNexusFunction)fid; + pNexusFunction pFunc = handleToNexusFunc(fid); return pFunc->nxclosedata(pFunc->pNexusData); } @@ -389,7 +602,7 @@ static int determineFileType(CONSTCHAR *filename) NXstatus NXputdata (NXhandle fid, void *data) { - pNexusFunction pFunc = (pNexusFunction)fid; + pNexusFunction pFunc = handleToNexusFunc(fid); return pFunc->nxputdata(pFunc->pNexusData, data); } @@ -398,7 +611,7 @@ static int determineFileType(CONSTCHAR *filename) NXstatus NXputattr (NXhandle fid, CONSTCHAR *name, void *data, int datalen, int iType) { - pNexusFunction pFunc = (pNexusFunction)fid; + pNexusFunction pFunc = handleToNexusFunc(fid); return pFunc->nxputattr(pFunc->pNexusData, name, data, datalen, iType); } @@ -406,7 +619,7 @@ static int determineFileType(CONSTCHAR *filename) NXstatus NXputslab (NXhandle fid, void *data, int iStart[], int iSize[]) { - pNexusFunction pFunc = (pNexusFunction)fid; + pNexusFunction pFunc = handleToNexusFunc(fid); return pFunc->nxputslab(pFunc->pNexusData, data, iStart, iSize); } @@ -414,7 +627,7 @@ static int determineFileType(CONSTCHAR *filename) NXstatus NXgetdataID (NXhandle fid, NXlink* sRes) { - pNexusFunction pFunc = (pNexusFunction)fid; + pNexusFunction pFunc = handleToNexusFunc(fid); return pFunc->nxgetdataID(pFunc->pNexusData, sRes); } @@ -423,9 +636,16 @@ static int determineFileType(CONSTCHAR *filename) NXstatus NXmakelink (NXhandle fid, NXlink* sLink) { - pNexusFunction pFunc = (pNexusFunction)fid; + pNexusFunction pFunc = handleToNexusFunc(fid); return pFunc->nxmakelink(pFunc->pNexusData, sLink); } + /* ------------------------------------------------------------------- */ + + NXstatus NXmakenamedlink (NXhandle fid, CONSTCHAR *newname, NXlink* sLink) + { + pNexusFunction pFunc = handleToNexusFunc(fid); + return pFunc->nxmakenamedlink(pFunc->pNexusData, newname, sLink); + } /* --------------------------------------------------------------------*/ NXstatus NXopensourcegroup(NXhandle fid) { @@ -445,10 +665,12 @@ static int determineFileType(CONSTCHAR *filename) NXstatus NXflush(NXhandle *pHandle) { NXhandle hfil; + pFileStack fileStack = NULL; int status; pNexusFunction pFunc=NULL; - pFunc = (pNexusFunction)*pHandle; + fileStack = (pFileStack)*pHandle; + pFunc = peekFileOnStack(fileStack); hfil = pFunc->pNexusData; status = pFunc->nxflush(&hfil); pFunc->pNexusData = hfil; @@ -469,7 +691,7 @@ static int determineFileType(CONSTCHAR *filename) if ((datatype == NX_CHAR) || (datatype == NX_INT8) || (datatype == NX_UINT8)) { /* allow for terminating \0 */ - size += 1; + size += 2; } else if ((datatype == NX_INT16) || (datatype == NX_UINT16)) { size *= 2; @@ -478,6 +700,9 @@ static int determineFileType(CONSTCHAR *filename) || (datatype == NX_FLOAT32)) { size *= 4; } + else if ((datatype == NX_INT64) || (datatype == NX_UINT64)){ + size *= 8; + } else if (datatype == NX_FLOAT64) { size *= 8; } @@ -513,7 +738,7 @@ static int determineFileType(CONSTCHAR *filename) NXstatus NXgetnextentry (NXhandle fid, NXname name, NXname nxclass, int *datatype) { - pNexusFunction pFunc = (pNexusFunction)fid; + pNexusFunction pFunc = handleToNexusFunc(fid); return pFunc->nxgetnextentry(pFunc->pNexusData, name, nxclass, datatype); } /*----------------------------------------------------------------------*/ @@ -524,7 +749,7 @@ static int determineFileType(CONSTCHAR *filename) */ #define NUL '\0' -static char *nxitrim(char *str) +char *nxitrim(char *str) { char *ibuf = str, *obuf = str; int i = 0, cnt = 0; @@ -563,12 +788,13 @@ static char *nxitrim(char *str) int status, type, rank, iDim[NX_MAXRANK]; char *pPtr, *pPtr2; - pNexusFunction pFunc = (pNexusFunction)fid; + pNexusFunction pFunc = handleToNexusFunc(fid); status = pFunc->nxgetinfo(pFunc->pNexusData, &rank, iDim, &type); /* unstripped size if string */ - if ( (type == NX_CHAR) && (pFunc->stripFlag == 1) ) + /* only strip one dimensional strings */ + if ( (type == NX_CHAR) && (pFunc->stripFlag == 1) && (rank == 1) ) { - pPtr = (char*)malloc(iDim[0]+1); - memset(pPtr, 0, iDim[0]+1); + pPtr = (char*)malloc(iDim[0]+5); + memset(pPtr, 0, iDim[0]+5); status = pFunc->nxgetdata(pFunc->pNexusData, pPtr); pPtr2 = nxitrim(pPtr); strncpy((char*)data, pPtr2, strlen(pPtr2)); /* not NULL terminated by default */ @@ -589,12 +815,13 @@ static char *nxitrim(char *str) int status; char *pPtr = NULL; - pNexusFunction pFunc = (pNexusFunction)fid; + pNexusFunction pFunc = handleToNexusFunc(fid); status = pFunc->nxgetinfo(pFunc->pNexusData, rank, dimension, iType); /* the length of a string may be trimmed.... */ - if(*iType == NX_CHAR && pFunc->stripFlag == 1){ + /* only strip one dimensional strings */ + if((*iType == NX_CHAR) && (pFunc->stripFlag == 1) && (*rank == 1)){ pPtr = (char *)malloc((dimension[0]+1)*sizeof(char)); if(pPtr != NULL){ memset(pPtr,0,(dimension[0]+1)*sizeof(char)); @@ -603,11 +830,6 @@ static char *nxitrim(char *str) free(pPtr); } } - if ( (*iType == NX_CHAR) && (*rank > 1) ) - { - NXIReportError(NXpData, - "WARNING: multi-dimensional character arrays are not really supported"); - } return status; } @@ -616,7 +838,7 @@ static char *nxitrim(char *str) NXstatus NXgetslab (NXhandle fid, void *data, int iStart[], int iSize[]) { - pNexusFunction pFunc = (pNexusFunction)fid; + pNexusFunction pFunc = handleToNexusFunc(fid); return pFunc->nxgetslab(pFunc->pNexusData, data, iStart, iSize); } @@ -626,7 +848,7 @@ static char *nxitrim(char *str) NXstatus NXgetnextattr (NXhandle fileid, NXname pName, int *iLength, int *iType) { - pNexusFunction pFunc = (pNexusFunction)fileid; + pNexusFunction pFunc = handleToNexusFunc(fileid); return pFunc->nxgetnextattr(pFunc->pNexusData, pName, iLength, iType); } @@ -635,7 +857,7 @@ static char *nxitrim(char *str) NXstatus NXgetattr (NXhandle fid, char *name, void *data, int* datalen, int* iType) { - pNexusFunction pFunc = (pNexusFunction)fid; + pNexusFunction pFunc = handleToNexusFunc(fid); return pFunc->nxgetattr(pFunc->pNexusData, name, data, datalen, iType); } @@ -644,7 +866,7 @@ static char *nxitrim(char *str) NXstatus NXgetattrinfo (NXhandle fid, int *iN) { - pNexusFunction pFunc = (pNexusFunction)fid; + pNexusFunction pFunc = handleToNexusFunc(fid); return pFunc->nxgetattrinfo(pFunc->pNexusData, iN); } @@ -653,7 +875,7 @@ static char *nxitrim(char *str) NXstatus NXgetgroupID (NXhandle fileid, NXlink* sRes) { - pNexusFunction pFunc = (pNexusFunction)fileid; + pNexusFunction pFunc = handleToNexusFunc(fileid); return pFunc->nxgetgroupID(pFunc->pNexusData, sRes); } @@ -661,7 +883,7 @@ static char *nxitrim(char *str) NXstatus NXgetgroupinfo (NXhandle fid, int *iN, NXname pName, NXname pClass) { - pNexusFunction pFunc = (pNexusFunction)fid; + pNexusFunction pFunc = handleToNexusFunc(fid); return pFunc->nxgetgroupinfo(pFunc->pNexusData, iN, pName, pClass); } @@ -670,7 +892,7 @@ static char *nxitrim(char *str) NXstatus NXsameID (NXhandle fileid, NXlink* pFirstID, NXlink* pSecondID) { - pNexusFunction pFunc = (pNexusFunction)fileid; + pNexusFunction pFunc = handleToNexusFunc(fileid); return pFunc->nxsameID(pFunc->pNexusData, pFirstID, pSecondID); } @@ -678,7 +900,7 @@ static char *nxitrim(char *str) NXstatus NXinitattrdir (NXhandle fid) { - pNexusFunction pFunc = (pNexusFunction)fid; + pNexusFunction pFunc = handleToNexusFunc(fid); return pFunc->nxinitattrdir(pFunc->pNexusData); } /*-------------------------------------------------------------------------*/ @@ -686,7 +908,7 @@ static char *nxitrim(char *str) NXstatus NXsetnumberformat (NXhandle fid, int type, char *format) { - pNexusFunction pFunc = (pNexusFunction)fid; + pNexusFunction pFunc = handleToNexusFunc(fid); if(pFunc->nxsetnumberformat != NULL) { return pFunc->nxsetnumberformat(pFunc->pNexusData,type,format); @@ -706,10 +928,78 @@ static char *nxitrim(char *str) NXstatus NXinitgroupdir (NXhandle fid) { - pNexusFunction pFunc = (pNexusFunction)fid; + pNexusFunction pFunc = handleToNexusFunc(fid); return pFunc->nxinitgroupdir(pFunc->pNexusData); - } - + } +/*----------------------------------------------------------------------*/ + NXstatus NXinquirefile(NXhandle handle, char *filename, + int filenameBufferLength){ + pFileStack fileStack; + char *pPtr = NULL; + int length; + + fileStack = (pFileStack)handle; + pPtr = peekFilenameOnStack(fileStack); + if(pPtr != NULL){ + length = strlen(pPtr); + if(length > filenameBufferLength){ + length = filenameBufferLength -1; + } + memset(filename,0,filenameBufferLength); + memcpy(filename,pPtr, length); + return NX_OK; + } else { + return NX_ERROR; + } +} +/*------------------------------------------------------------------------*/ +NXstatus NXisexternalgroup(NXhandle fid, CONSTCHAR *name, CONSTCHAR *class, + char *url, int urlLen){ + int status, attStatus, length = 1023, type = NX_CHAR; + ErrFunc oldError; + char nxurl[1024]; + + pNexusFunction pFunc = handleToNexusFunc(fid); + + status = pFunc->nxopengroup(pFunc->pNexusData, name,class); + if(status != NX_OK){ + return status; + } + oldError = NXMGetError(); + NXIReportError = NXNXNoReport; + attStatus = NXgetattr(fid,"napimount",nxurl,&length, &type); + NXIReportError = oldError; + pFunc->nxclosegroup(pFunc->pNexusData); + if(attStatus == NX_OK){ + length = strlen(nxurl); + if(length > urlLen){ + length = urlLen - 1; + } + memset(url,0,urlLen); + memcpy(url,nxurl,length); + return attStatus; + } else { + return NX_ERROR; + } +} +/*------------------------------------------------------------------------*/ +NXstatus NXlinkexternal(NXhandle fid, CONSTCHAR *name, CONSTCHAR *class, + CONSTCHAR *url){ + int status, type = NX_CHAR, length; + pNexusFunction pFunc = handleToNexusFunc(fid); + + status = pFunc->nxopengroup(pFunc->pNexusData,name,class); + if(status != NX_OK){ + return status; + } + length = strlen(url); + status = NXputattr(fid, "napimount",(void *)url,length, type); + if(status != NX_OK){ + return status; + } + pFunc->nxclosegroup(pFunc->pNexusData); + return NX_OK; +} /*------------------------------------------------------------------------ Implementation of NXopenpath. --------------------------------------------------------------------------*/ @@ -1009,7 +1299,7 @@ NXstatus NXopengrouppath(NXhandle hfil, CONSTCHAR *path) NXstatus NXIprintlink(NXhandle fid, NXlink* link) { - pNexusFunction pFunc = (pNexusFunction)fid; + pNexusFunction pFunc = handleToNexusFunc(fid); return pFunc->nxprintlink(pFunc->pNexusData, link); } @@ -1228,241 +1518,3 @@ char *NXIformatNeXusTime(){ return ret; } -/* - * windows stdcall aliases - */ -#ifdef _WIN32 - -NXstatus __stdcall NXISETCACHE(long newVal) -{ - return NXsetcache(newVal); -} - -void __stdcall NXNXNXREPORTERROR(void *pData, char *string) -{ - NXNXNXReportError(pData, string); -} - -NXstatus __stdcall NXIOPEN(CONSTCHAR *filename, NXaccess am, NXhandle *gHandle) -{ - return NXopen(filename, am, gHandle); -} - -NXstatus __stdcall NXICLOSE(NXhandle *fid) -{ - return NXclose(fid); -} - -NXstatus __stdcall NXIFLUSH(NXhandle* pHandle) -{ - return NXflush(pHandle); -} - -NXstatus __stdcall NXIMAKEGROUP(NXhandle handle, CONSTCHAR *name, CONSTCHAR* NXclass) -{ - return NXmakegroup(handle, name, NXclass); -} - -NXstatus __stdcall NXIOPENGROUP(NXhandle handle, CONSTCHAR *name, CONSTCHAR* NXclass) -{ - return NXopengroup(handle, name, NXclass); -} - -NXstatus __stdcall NXIOPENPATH(NXhandle handle, CONSTCHAR *path) -{ - return NXopenpath(handle, path); -} - -NXstatus __stdcall NXIOPENGROUPPATH (NXhandle handle, CONSTCHAR *path) -{ - return NXopengrouppath(handle, path); -} - -NXstatus __stdcall NXICLOSEGROUP(NXhandle handle) -{ - return NXclosegroup(handle); -} - -NXstatus __stdcall NXIMAKEDATA (NXhandle handle, CONSTCHAR* label, int datatype, int rank, int dim[]) -{ - return NXmakedata (handle, label, datatype, rank, dim); -} - -NXstatus __stdcall NXICOMPMAKEDATA (NXhandle handle, CONSTCHAR* label, int datatype, int rank, int dim[], int comp_typ, int bufsize[]) -{ - return NXcompmakedata (handle, label, datatype, rank, dim, comp_typ, bufsize); -} - -NXstatus __stdcall NXICOMPRESS (NXhandle handle, int compr_type) -{ - return NXcompress (handle, compr_type); -} - -NXstatus __stdcall NXIOPENDATA (NXhandle handle, CONSTCHAR* label) -{ - return NXopendata (handle, label); -} - -NXstatus __stdcall NXICLOSEDATA(NXhandle handle) -{ - return NXclosedata(handle); -} - -NXstatus __stdcall NXIPUTDATA(NXhandle handle, void* data) -{ - return NXputdata(handle, data); -} - -NXstatus __stdcall NXIPUTATTR(NXhandle handle, CONSTCHAR* name, void* data, int iDataLen, int iType) -{ - return NXputattr(handle, name, data, iDataLen, iType); -} - -NXstatus __stdcall NXIPUTSLAB(NXhandle handle, void* data, int start[], int size[]) -{ - return NXputslab(handle, data, start, size); -} - -NXstatus __stdcall NXIGETDATAID(NXhandle handle, NXlink* pLink) -{ - return NXgetdataID(handle, pLink); -} - -NXstatus __stdcall NXIMAKELINK(NXhandle handle, NXlink* pLink) -{ - return NXmakelink(handle, pLink); -} - -NXstatus __stdcall NXIOPENSOURCEGROUP(NXhandle handle) -{ - return NXopensourcegroup(handle); -} - -NXstatus __stdcall NXIGETDATA(NXhandle handle, void* data) -{ - return NXgetdata(handle, data); -} - -NXstatus __stdcall NXIGETINFO(NXhandle handle, int* rank, int dimension[], int* datatype) -{ - return NXgetinfo(handle, rank, dimension, datatype); -} - -NXstatus __stdcall NXIGETNEXTENTRY(NXhandle handle, NXname name, NXname nxclass, int* datatype) -{ - return NXgetnextentry(handle, name, nxclass, datatype); -} - -NXstatus __stdcall NXIGETSLAB(NXhandle handle, void* data, int start[], int size[]) -{ - return NXgetslab(handle, data, start, size); -} - -NXstatus __stdcall NXIGETNEXTATTR(NXhandle handle, NXname pName, int *iLength, int *iType) -{ - return NXgetnextattr(handle, pName, iLength, iType); -} - -NXstatus __stdcall NXIGETATTR(NXhandle handle, char* name, void* data, int* iDataLen, int* iType) -{ - return NXgetattr(handle, name, data, iDataLen, iType); -} - -NXstatus __stdcall NXIGETATTRINFO(NXhandle handle, int* no_items) -{ - return NXgetattrinfo(handle, no_items); -} - -NXstatus __stdcall NXIGETGROUPID(NXhandle handle, NXlink* pLink) -{ - return NXgetgroupID(handle, pLink); -} - -NXstatus __stdcall NXIGETGROUPINFO(NXhandle handle, int* no_items, NXname name, NXname nxclass) -{ - return NXgetgroupinfo(handle, no_items, name, nxclass); -} - -NXstatus __stdcall NXISAMEID(NXhandle handle, NXlink* pFirstID, NXlink* pSecondID) -{ - return NXsameID(handle, pFirstID, pSecondID); -} - -NXstatus __stdcall NXIINITGROUPDIR(NXhandle handle) -{ - return NXinitgroupdir(handle); -} -NXstatus __stdcall NXIINITATTRDIR(NXhandle handle) -{ - return NXinitattrdir(handle); -} -NXstatus __stdcall NXISETNUMBERFORMAT(NXhandle handle, int type, char *format) -{ - return NXsetnumberformat(handle,type, format); -} - -NXstatus __stdcall NXIMALLOC(void** data, int rank, int dimensions[], int datatype) -{ - return NXmalloc(data, rank, dimensions, datatype); -} - -NXstatus __stdcall NXIFREE(void** data) -{ - return NXfree(data); -} - -#if 0 -/*----------------------------------------------------------------------- - NAPI internals -------------------------------------------------------------------------*/ -extern void NXMSetError(void *pData, void (*ErrFunc)(void *pD, char *text)); -extern void (*NXIReportError)(void *pData,char *text); -extern void *NXpData; -extern char *NXIformatNeXusTime(); -#endif - -/* FORTRAN internals */ - -NXstatus __stdcall NXIFOPEN(char * filename, NXaccess* am, - NexusFunction* pHandle) -{ - return NXfopen(filename, am, pHandle); -} - -NXstatus __stdcall NXIFCLOSE (NexusFunction* pHandle) -{ - return NXfclose (pHandle); -} - -NXstatus __stdcall NXIFPUTATTR(NXhandle fid, char *name, void *data, - int *pDatalen, int *pIType) -{ - return NXfputattr(fid, name, data, pDatalen, pIType); -} - -NXstatus __stdcall NXIFCOMPRESS(NXhandle fid, int *compr_type) -{ - return NXfcompress(fid, compr_type); -} - -NXstatus __stdcall NXIFCOMPMAKEDATA(NXhandle fid, char *name, - int *pDatatype, - int *pRank, int dimensions[], - int *compression_type, int chunk[]) -{ - return NXfcompmakedata(fid, name, pDatatype, pRank, dimensions, - compression_type, chunk); -} - -NXstatus __stdcall NXIFMAKEDATA(NXhandle fid, char *name, int *pDatatype, - int *pRank, int dimensions[]) -{ - return NXfmakedata(fid, name, pDatatype, pRank, dimensions); -} - -NXstatus __stdcall NXIFFLUSH(NexusFunction* pHandle) -{ - return NXfflush(pHandle); -} - -#endif /* _WIN32 */ diff --git a/napi.h b/napi.h index f27b05b7..50536245 100644 --- a/napi.h +++ b/napi.h @@ -3,7 +3,7 @@ Application Program Interface Header File - Copyright (C) 2000-2005 Mark Koennecke, Uwe Filges + Copyright (C) 2000-2007 Mark Koennecke, Uwe Filges This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -19,9 +19,9 @@ License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - For further information, see + For further information, see - $Id: napi.h,v 1.10 2006/03/03 15:30:55 koennecke Exp $ + $Id$ ----------------------------------------------------------------------------*/ @@ -29,14 +29,14 @@ #define NEXUSAPI /* NeXus HDF45 */ -#define NEXUS_VERSION "3.0.0" /* major.minor.patch */ +#define NEXUS_VERSION "4.1.0" /* major.minor.patch */ #define CONSTCHAR const char -#ifdef _WIN32 -//#define snprintf nxisnprintf +#ifdef _MSC_VER +#define snprintf nxisnprintf extern int nxisnprintf(char* buffer, int len, const char* format, ... ); -#endif /* _WIN32 */ +#endif /* _MSC_VER */ typedef void* NXhandle; /* really a pointer to a NexusFile structure */ typedef int NXstatus; @@ -101,6 +101,8 @@ typedef struct { #define NX_UINT16 23 #define NX_INT32 24 #define NX_UINT32 25 +#define NX_INT64 26 +#define NX_UINT64 27 #define NX_CHAR 4 #define NX_BINARY 21 @@ -113,10 +115,8 @@ typedef struct { typedef struct { long iTag; /* HDF4 variable */ long iRef; /* HDF4 variable */ - char iTag5[1024]; /* HDF5 variable */ - char iRef5[1024]; /* HDF5 variable */ - char iRefd[1024]; /* HDF5 variable */ - char targetPath[1024]; /* XML path */ + char targetPath[1024]; /* path to item to link */ + int linkType; /* HDF5: 0 for group link, 1 for SDS link */ } NXlink; #define NXMAXSTACK 50 @@ -146,6 +146,7 @@ typedef struct { # define NXputattr MANGLE(nxiputattr) # define NXgetdataID MANGLE(nxigetdataid) # define NXmakelink MANGLE(nximakelink) +# define NXmakenamedlink MANGLE(nximakenamedlink) # define NXopensourcegroup MANGLE(nxiopensourcegroup) # define NXmalloc MANGLE(nximalloc) # define NXfree MANGLE(nxifree) @@ -164,8 +165,11 @@ typedef struct { # define NXsameID MANGLE(nxisameid) # define NXinitgroupdir MANGLE(nxiinitgroupdir) # define NXinitattrdir MANGLE(nxiinitattrdir) -# define NXsetnumberformat MANGLE(nxisetnumberformat) +# define NXsetnumberformat MANGLE(nxisetnumberformat) # define NXsetcache MANGLE(nxisetcache) +# define NXinquirefile MANGLE(nxiinquirefile) +# define NXisexternalgroup MANGLE(nxiisexternalgroup) +# define NXlinkexternal MANGLE(nxilinkexternal) /* * FORTRAN helpers - for NeXus internal use only @@ -181,6 +185,11 @@ typedef struct { /* * Standard interface + * + * Functions added here are not automatically exported from + * a shared library/dll - the symbol name must also be added + * to the file src/nexus_symbols.txt + * */ #ifdef __cplusplus @@ -209,6 +218,7 @@ extern NXstatus NXputslab(NXhandle handle, void* data, int start[], int size[] extern NXstatus NXgetdataID(NXhandle handle, NXlink* pLink); extern NXstatus NXmakelink(NXhandle handle, NXlink* pLink); +extern NXstatus NXmakenamedlink(NXhandle handle, CONSTCHAR* newname, NXlink* pLink); extern NXstatus NXopensourcegroup(NXhandle handle); extern NXstatus NXgetdata(NXhandle handle, void* data); @@ -226,7 +236,11 @@ extern NXstatus NXsameID(NXhandle handle, NXlink* pFirstID, NXlink* pSecondID) extern NXstatus NXinitgroupdir(NXhandle handle); extern NXstatus NXinitattrdir(NXhandle handle); extern NXstatus NXsetnumberformat(NXhandle handle, - int type, char *format); + int type, char *format); + +extern NXstatus NXinquirefile(NXhandle handle, char *filename, int filenameBufferLength); +extern NXstatus NXisexternalgroup(NXhandle fid, CONSTCHAR *name, CONSTCHAR *nxclass, char *url, int urlLen); +extern NXstatus NXlinkexternal(NXhandle fid, CONSTCHAR *name, CONSTCHAR *nxclass, CONSTCHAR *url); extern NXstatus NXmalloc(void** data, int rank, int dimensions[], int datatype); extern NXstatus NXfree(void** data); @@ -238,6 +252,8 @@ extern NXstatus NXfree(void** data); typedef void (*ErrFunc)(void *data, char *text); extern void NXMSetError(void *pData, ErrFunc); extern ErrFunc NXMGetError(); +extern void NXMDisableErrorReporting(); +extern void NXMEnableErrorReporting(); extern void (*NXIReportError)(void *pData,char *text); extern void *NXpData; extern char *NXIformatNeXusTime(); @@ -266,6 +282,7 @@ extern NXstatus NXsetcache(long newVal); NXstatus ( *nxputslab)(NXhandle handle, void* data, int start[], int size[]); NXstatus ( *nxgetdataID)(NXhandle handle, NXlink* pLink); NXstatus ( *nxmakelink)(NXhandle handle, NXlink* pLink); + NXstatus ( *nxmakenamedlink)(NXhandle handle, CONSTCHAR *newname, NXlink* pLink); NXstatus ( *nxgetdata)(NXhandle handle, void* data); NXstatus ( *nxgetinfo)(NXhandle handle, int* rank, int dimension[], int* datatype); NXstatus ( *nxgetnextentry)(NXhandle handle, NXname name, NXname nxclass, int* datatype); diff --git a/napi4.c b/napi4.c index 1dd21969..ff9f8b79 100644 --- a/napi4.c +++ b/napi4.c @@ -3,7 +3,7 @@ Application Program Interface (HDF4) Routines - Copyright (C) 1997-2002 Mark Koennecke, Przemek Klosowski + Copyright (C) 1997-2006 Mark Koennecke, Przemek Klosowski This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -21,7 +21,7 @@ For further information, see - $Id: napi4.c,v 1.8 2006/03/31 15:24:53 koennecke Exp $ + $Id$ ----------------------------------------------------------------------------*/ #include @@ -64,13 +64,50 @@ extern void *NXpData; assert(pRes->iNXID == NXSIGNATURE); return pRes; } - + /*----------------------------------------------------------------------*/ +static int findNapiClass(pNexusFile pFile, int groupRef, NXname nxclass) +{ + NXname classText, linkClass; + int32 tags[2], attID, linkID, groupID; + + groupID = Vattach(pFile->iVID,groupRef,"r"); + Vgetclass(groupID, classText); + if(strcmp(classText,"NAPIlink") != 0) + { + /* normal group */ + strcpy(nxclass,classText); + Vdetach(groupID); + return groupRef; + } + else + { + /* code for linked renamed groups */ + attID = Vfindattr(groupID,"NAPIlink"); + if(attID >= 0) + { + Vgetattr(groupID,attID, tags); + linkID = Vattach(pFile->iVID,tags[1],"r"); + Vgetclass(linkID, linkClass); + Vdetach(groupID); + Vdetach(linkID); + strcpy(nxclass,linkClass); + return tags[1]; + } + else + { + /* this allows for finding the NAPIlink group in NXmakenamedlink */ + strcpy(nxclass,classText); + Vdetach(groupID); + return groupRef; + } + } +} /* --------------------------------------------------------------------- */ static int32 NXIFindVgroup (pNexusFile pFile, CONSTCHAR *name, CONSTCHAR *nxclass) { int32 iNew, iRef, iTag; - int iN, i; + int iN, i, status; int32 *pArray = NULL; NXname pText; @@ -93,17 +130,16 @@ extern void *NXpData; for (i = 0; i < iN; i++) { iNew = Vattach (pFile->iVID, pArray[i], "r"); Vgetname (iNew, pText); + Vdetach(iNew); if (strcmp (pText, name) == 0) { - Vgetclass (iNew, pText); + pArray[i] = findNapiClass(pFile,pArray[i],pText); if (strcmp (pText, nxclass) == 0) { /* found ! */ - Vdetach (iNew); iNew = pArray[i]; free (pArray); return iNew; } } - Vdetach (iNew); } /* nothing found */ free (pArray); @@ -115,15 +151,13 @@ extern void *NXpData; if (iTag == DFTAG_VG) { iNew = Vattach (pFile->iVID, iRef, "r"); Vgetname (iNew, pText); + Vdetach(iNew); if (strcmp (pText, name) == 0) { - Vgetclass (iNew, pText); + iRef = findNapiClass(pFile,iRef, pText); if (strcmp (pText, nxclass) == 0) { - /* found ! */ - Vdetach (iNew); return iRef; } } - Vdetach (iNew); } } /* end for */ } /* end else */ @@ -264,8 +298,15 @@ extern void *NXpData; if (pFile->iCurrentSDS != 0) { /* SDS level */ iRet = SDgetinfo (pFile->iCurrentSDS, pNam, &iRank, iDim, &iType, &iAtt); - } else { /* global level */ - iRet = SDfileinfo (pFile->iSID, &iData, &iAtt); + } else { + if(pFile->iCurrentVG == 0){ + /* global level */ + iRet = SDfileinfo (pFile->iSID, &iData, &iAtt); + } else { + /* group attribute */ + iRet = Vnattrs(pFile->iCurrentVG); + iAtt = iRet; + } } if (iRet < 0) { NXIReportError (NXpData, "ERROR: HDF cannot read attribute numbers"); @@ -325,7 +366,7 @@ extern void *NXpData; { pNexusFile pNew = NULL; char pBuffer[512]; - char *time_puffer; + char *time_puffer = NULL; char HDF_VERSION[64]; uint32 lmajor, lminor, lrelease; int32 am1=0; @@ -350,8 +391,6 @@ extern void *NXpData; } memset (pNew, 0, sizeof (NexusFile)); - time_puffer = NXIformatNeXusTime(); - #if WRITE_OLD_IDENT /* not used at moment */ /* * write something that can be used by OLE @@ -402,6 +441,8 @@ extern void *NXpData; return NX_ERROR; } } + + time_puffer = NXIformatNeXusTime(); if (am == NXACC_CREATE || am == NXACC_CREATE4) { if (SDsetattr(pNew->iSID, "file_name", DFNT_CHAR8, strlen(filename), (char*)filename) < 0) { NXIReportError (NXpData, "ERROR: HDF failed to store file_name attribute "); @@ -415,9 +456,11 @@ extern void *NXpData; free(time_puffer); return NX_ERROR; } - free(time_puffer); } } + if (time_puffer != NULL) { + free(time_puffer); + } /* * Otherwise we try to create the file two times which makes HDF @@ -534,8 +577,6 @@ extern void *NXpData; /*------------------------------------------------------------------------*/ - - NXstatus NX4opengroup (NXhandle fid, CONSTCHAR *name, CONSTCHAR *nxclass) { pNexusFile pFile; @@ -566,7 +607,6 @@ extern void *NXpData; NXIKillDir (pFile); return NX_OK; } - /* ------------------------------------------------------------------- */ @@ -661,6 +701,11 @@ extern void *NXpData; { type=DFNT_FLOAT64; } + else + { + NXIReportError (NXpData, "ERROR: invalid type in NX4makedata"); + return NX_ERROR; + } if (rank <= 0) { sprintf (pBuffer, "ERROR: invalid rank specified for SDS %s", @@ -787,6 +832,11 @@ extern void *NXpData; { type=DFNT_FLOAT64; } + else + { + NXIReportError (NXpData, "ERROR: invalid datatype in NX4compmakedata"); + return NX_ERROR; + } if (rank <= 0) { sprintf (pBuffer, "ERROR: invalid rank specified for SDS %s", @@ -877,7 +927,7 @@ extern void *NXpData; else { NXIReportError (NXpData, "Unknown compression method!"); - NX_ERROR; + return NX_ERROR; } /* link into Vgroup, if in one */ if (pFile->iCurrentVG != 0) { @@ -900,7 +950,7 @@ extern void *NXpData; pNexusFile pFile; int32 iRank, iAtt, iType, iRet; int32 iSize[MAX_VAR_DIMS]; - int compress_typei; + int compress_typei = COMP_CODE_NONE; NXname pBuffer; char pError[512]; comp_info compstruct; @@ -962,7 +1012,7 @@ extern void *NXpData; NXstatus NX4opendata (NXhandle fid, CONSTCHAR *name) { pNexusFile pFile; - int32 iNew; + int32 iNew, attID, tags[2]; char pBuffer[256]; int iRet; @@ -986,10 +1036,19 @@ extern void *NXpData; } /* clear pending attribute directories first */ NXIKillAttDir (pFile); - - /* open the SDS */ + + /* open the SDS, thereby watching for linked SDS under a different name */ iNew = SDreftoindex (pFile->iSID, iNew); pFile->iCurrentSDS = SDselect (pFile->iSID, iNew); + attID = SDfindattr(pFile->iCurrentSDS,"NAPIlink"); + if(attID >= 0) + { + SDreadattr(pFile->iCurrentSDS,attID, tags); + SDendaccess(pFile->iCurrentSDS); + iNew = SDreftoindex (pFile->iSID, tags[1]); + pFile->iCurrentSDS = SDselect (pFile->iSID, iNew); + } + if (pFile->iCurrentSDS < 0) { NXIReportError (NXpData, "ERROR: HDF error opening SDS"); pFile->iCurrentSDS = 0; @@ -1105,15 +1164,25 @@ extern void *NXpData; { type=DFNT_FLOAT64; } + else + { + NXIReportError (NXpData, "ERROR: Invalid data type for HDF attribute"); + return NX_ERROR; + } if (pFile->iCurrentSDS != 0) { /* SDS attribute */ iRet = SDsetattr (pFile->iCurrentSDS, (char*)name, (int32)type, (int32)datalen, data); } else { - /* global attribute */ - iRet = SDsetattr (pFile->iSID, (char*)name, (int32)type, - (int32)datalen, data); - + if(pFile->iCurrentVG == 0){ + /* global attribute */ + iRet = SDsetattr (pFile->iSID, (char*)name, (int32)type, + (int32)datalen, data); + } else { + /* group attribute */ + iRet = Vsetattr(pFile->iCurrentVG, (char *)name, (int32) type, + (int32)datalen,data); + } } iType = type; if (iRet < 0) { @@ -1218,15 +1287,66 @@ extern void *NXpData; return NX_ERROR; } Vaddtagref(pFile->iCurrentVG, sLink->iTag, sLink->iRef); + length = strlen(sLink->targetPath); if(sLink->iTag == DFTAG_SDG || sLink->iTag == DFTAG_NDG || sLink->iTag == DFTAG_SDS) { dataID = SDreftoindex(pFile->iSID,sLink->iRef); dataID = SDselect(pFile->iSID,dataID); - length = strlen(sLink->targetPath); SDsetattr(dataID,name,type,length,sLink->targetPath); SDendaccess(dataID); } + else + { + dataID = Vattach(pFile->iVID,sLink->iRef,"w"); + Vsetattr(dataID, (char *)name, type, (int32) length, sLink->targetPath); + Vdetach(dataID); + } + return NX_OK; + } + /* ------------------------------------------------------------------- */ + + + NXstatus NX4makenamedlink (NXhandle fid, CONSTCHAR* newname, NXlink* sLink) + { + pNexusFile pFile; + int32 iVG, iRet, dataID, type = DFNT_CHAR8, length, dataType = NX_CHAR, + rank = 1, attType = NX_INT32; + int iDim[1]; + char name[] = "target"; + int tags[2]; + + pFile = NXIassert (fid); + + if (pFile->iCurrentVG == 0) { /* root level, can not link here */ + return NX_ERROR; + } + + tags[0] = sLink->iTag; + tags[1] = sLink->iRef; + + length = strlen(sLink->targetPath); + if(sLink->iTag == DFTAG_SDG || sLink->iTag == DFTAG_NDG || + sLink->iTag == DFTAG_SDS) + { + iDim[0] = 1; + NX4makedata(fid,newname, dataType,rank,iDim); + NX4opendata(fid,newname); + NX4putattr(fid,"NAPIlink",tags, 2, attType); + NX4closedata(fid); + dataID = SDreftoindex(pFile->iSID,sLink->iRef); + dataID = SDselect(pFile->iSID,dataID); + SDsetattr(dataID,name,type,length,sLink->targetPath); + SDendaccess(dataID); + } else { + NX4makegroup(fid,newname,"NAPIlink"); + NX4opengroup(fid,newname,"NAPIlink"); + NX4putattr(fid,"NAPIlink",tags, 2, attType); + NX4closegroup(fid); + dataID = Vattach(pFile->iVID,sLink->iRef,"w"); + Vsetattr(dataID, (char *)name, type, (int32) length, sLink->targetPath); + Vdetach(dataID); + } return NX_OK; } @@ -1236,8 +1356,7 @@ extern void *NXpData; { pNexusFile pFile; pFile = NXIassert (fid); - printf("HDF4 link: iTag = %ld, iRef = %ld, target=\"%s\"\n", - sLink->iTag, sLink->iRef, sLink->targetPath); + printf("HDF4 link: iTag = %ld, iRef = %ld, target=\"%s\"\n", sLink->iTag, sLink->iRef, sLink->targetPath); return NX_OK; } @@ -1272,6 +1391,10 @@ extern void *NXpData; ac = NXACC_READ; }else if(pFile->iAccess[0] == 'w') { ac = NXACC_RDWR; + } else { + NXIReportError (NXpData, + "ERROR: NX4flush failed to determine file access mode"); + return NX_ERROR; } pCopy = (char *)malloc((strlen(pFileName)+10)*sizeof(char)); if(!pCopy) { @@ -1345,11 +1468,13 @@ extern void *NXpData; return NX_EOD; } } + /* Next case: end of directory */ if (iCurDir >= pFile->iStack[pFile->iStackPtr].iNDir) { NXIKillDir (pFile); return NX_EOD; } + /* Next case: we have data! supply it and increment counter */ if (pFile->iCurrentVG == 0) { /* root level */ iTemp = Vattach (pFile->iVID, @@ -1359,10 +1484,10 @@ extern void *NXpData; return NX_ERROR; } Vgetname (iTemp, name); - Vgetclass (iTemp, nxclass); + Vdetach (iTemp); + findNapiClass(pFile, pFile->iStack[pFile->iStackPtr].iRefDir[iCurDir], nxclass); *datatype = DFTAG_VG; pFile->iStack[pFile->iStackPtr].iCurDir++; - Vdetach (iTemp); return NX_OK; } else { /* in Vgroup */ if (pFile->iStack[iStackPtr].iTagDir[iCurDir] == DFTAG_VG) {/* Vgroup */ @@ -1373,7 +1498,8 @@ extern void *NXpData; return NX_ERROR; } Vgetname (iTemp, name); - Vgetclass (iTemp, nxclass); + Vdetach(iTemp); + findNapiClass(pFile, pFile->iStack[pFile->iStackPtr].iRefDir[iCurDir], nxclass); *datatype = DFTAG_VG; pFile->iStack[pFile->iStackPtr].iCurDir++; Vdetach (iTemp); @@ -1511,7 +1637,7 @@ extern void *NXpData; { pNexusFile pFile; int iRet; - int32 iPType, iCount; + int32 iPType, iCount, count; pFile = NXIassert (fileid); @@ -1528,9 +1654,16 @@ extern void *NXpData; return NX_EOD; } /* well, there must be data to copy */ - if (pFile->iCurrentSDS == 0) { /* global attribute */ - iRet = SDattrinfo (pFile->iSID, pFile->iAtt.iCurDir, - pName, &iPType, &iCount); + if (pFile->iCurrentSDS == 0) { + if(pFile->iCurrentVG == 0) { + /* global attribute */ + iRet = SDattrinfo (pFile->iSID, pFile->iAtt.iCurDir, + pName, &iPType, &iCount); + }else { + /* group attribute */ + iRet = Vattrinfo(pFile->iCurrentVG, pFile->iAtt.iCurDir, + pName, &iPType, &iCount, &count); + } } else { iRet = SDattrinfo (pFile->iCurrentSDS, pFile->iAtt.iCurDir, pName, &iPType, &iCount); @@ -1552,7 +1685,7 @@ extern void *NXpData; NXstatus NX4getattr (NXhandle fid, char *name, void *data, int* datalen, int* iType) { pNexusFile pFile; - int32 iNew, iType32; + int32 iNew, iType32, count; void *pData = NULL; int32 iLen, iRet; int type; @@ -1604,8 +1737,13 @@ extern void *NXpData; /* SDS attribute */ iNew = SDfindattr (pFile->iCurrentSDS, name); } else { - /* global attribute */ - iNew = SDfindattr (pFile->iSID, name); + if(pFile->iCurrentVG == 0){ + /* global attribute */ + iNew = SDfindattr (pFile->iSID, name); + } else { + /* group attribute */ + iNew = Vfindattr(pFile->iCurrentVG, name); + } } if (iNew < 0) { sprintf (pBuffer, "ERROR: attribute %s not found", name); @@ -1617,7 +1755,12 @@ extern void *NXpData; if (pFile->iCurrentSDS != 0) { iRet = SDattrinfo (pFile->iCurrentSDS, iNew, pNam, &iType32, &iLen); } else { - iRet = SDattrinfo (pFile->iSID, iNew, pNam, &iType32, &iLen); + if(pFile->iCurrentVG == 0){ + iRet = SDattrinfo (pFile->iSID, iNew, pNam, &iType32, &iLen); + } else { + iRet = Vattrinfo(pFile->iCurrentVG,iNew,pNam,&iType32,&count, + &iLen); + } } if (iRet < 0) { sprintf (pBuffer, "ERROR: HDF could not read attribute info"); @@ -1637,7 +1780,11 @@ extern void *NXpData; if (pFile->iCurrentSDS != 0) { iRet = SDreadattr (pFile->iCurrentSDS, iNew, pData); } else { - iRet = SDreadattr (pFile->iSID, iNew, pData); + if(pFile->iCurrentVG == 0){ + iRet = SDreadattr (pFile->iSID, iNew, pData); + } else { + iRet = Vgetattr(pFile->iCurrentVG, iNew, pData); + } } if (iRet < 0) { sprintf (pBuffer, "ERROR: HDF could not read attribute data"); @@ -1646,7 +1793,8 @@ extern void *NXpData; } /* copy data to caller */ memset (data, 0, *datalen); - if ((*datalen <= iLen) && (*iType == DFNT_UINT8 || *iType == DFNT_CHAR8 || *iType == DFNT_UCHAR8)) { + if ((*datalen <= iLen) && + (*iType == DFNT_UINT8 || *iType == DFNT_CHAR8 || *iType == DFNT_UCHAR8)) { iLen = *datalen - 1; } memcpy (data, pData, iLen); @@ -1670,8 +1818,14 @@ extern void *NXpData; if (pFile->iCurrentSDS != 0) { /* SDS level */ iRet = SDgetinfo (pFile->iCurrentSDS, pNam, &iRank, iDim, &iType, &iAtt); - } else { /* global level */ - iRet = SDfileinfo (pFile->iSID, &iData, &iAtt); + } else { + if(pFile->iCurrentVG == 0){ + /* global level */ + iRet = SDfileinfo (pFile->iSID, &iData, &iAtt); + } else { + iRet = Vnattrs(pFile->iCurrentVG); + iAtt = iRet; + } } if (iRet < 0) { NXIReportError (NXpData, "NX_ERROR: HDF cannot read attribute numbers"); @@ -1793,6 +1947,7 @@ void NX4assignFunctions(pNexusFunction fHandle) fHandle->nxputslab=NX4putslab; fHandle->nxgetdataID=NX4getdataID; fHandle->nxmakelink=NX4makelink; + fHandle->nxmakenamedlink=NX4makenamedlink; fHandle->nxgetdata=NX4getdata; fHandle->nxgetinfo=NX4getinfo; fHandle->nxgetnextentry=NX4getnextentry; diff --git a/napi5.c b/napi5.c index 4e40f2d4..939b9972 100644 --- a/napi5.c +++ b/napi5.c @@ -3,7 +3,7 @@ Application Program Interface (HDF5) Routines - Copyright (C) 1997-2002 Mark Koennecke, Przemek Klosowski + Copyright (C) 1997-2006 Mark Koennecke, Przemek Klosowski This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -30,18 +30,17 @@ #include "napi.h" #include "napi5.h" +#define NX_UNKNOWN_GROUP "" /* for when no NX_class attr */ + extern void *NXpData; typedef struct __NexusFile5 { struct iStack5 { - int *iRefDir; - int *iTagDir; char irefn[1024]; int iVref; int iCurrentIDX; } iStack5[NXMAXSTACK]; struct iStack5 iAtt5; - int iVID; int iFID; int iCurrentG; int iCurrentD; @@ -82,14 +81,6 @@ static void ignoreError(void *data, char *text){ static void NXI5KillDir (pNexusFile5 self) { - if (self->iStack5[self->iStackPtr].iRefDir) { - free (self->iStack5[self->iStackPtr].iRefDir); - self->iStack5[self->iStackPtr].iRefDir = NULL; - } - if (self->iStack5[self->iStackPtr].iTagDir) { - free (self->iStack5[self->iStackPtr].iTagDir); - self->iStack5[self->iStackPtr].iTagDir = NULL; - } self->iStack5[self->iStackPtr].iCurrentIDX = 0; } @@ -97,17 +88,27 @@ static void ignoreError(void *data, char *text){ static void NXI5KillAttDir (pNexusFile5 self) { - if (self->iAtt5.iRefDir) { - free (self->iAtt5.iRefDir); - self->iAtt5.iRefDir = NULL; - } - if (self->iAtt5.iTagDir) { - free (self->iAtt5.iTagDir); - self->iAtt5.iTagDir = NULL; - } self->iAtt5.iCurrentIDX = 0; } +/*---------------------------------------------------------------------*/ +static void buildCurrentPath(pNexusFile5 self, char *pathBuffer, + int pathBufferLen){ + int length; + memset(pathBuffer,0,pathBufferLen); + if(self->iCurrentG != 0) { + strcpy(pathBuffer,"/"); + if(strlen(self->name_ref) + 1 < pathBufferLen){ + strcat(pathBuffer, self->name_ref); + } + } + if(self->iCurrentD != 0){ + strcat(pathBuffer,"/"); + if(strlen(self->iCurrentLD) + strlen(pathBuffer) < pathBufferLen){ + strcat(pathBuffer,self->iCurrentLD); + } + } +} /* ---------------------------------------------------------------------- Definition of NeXus API @@ -117,14 +118,14 @@ static void ignoreError(void *data, char *text){ NXstatus NX5open(CONSTCHAR *filename, NXaccess am, NXhandle* pHandle) { - hid_t attr1,aid1, aid2; + hid_t attr1,aid1, aid2, iVID; pNexusFile5 pNew = NULL; char pBuffer[512]; - char *time_buffer; + char *time_buffer = NULL; char version_nr[10]; int iRet; unsigned int vers_major, vers_minor, vers_release, am1 ; - hid_t fapl; + hid_t fapl = -1; int mdc_nelmts; #ifdef H5_WANT_H5_V1_4_COMPAT int rdcc_nelmts; @@ -149,7 +150,6 @@ static void ignoreError(void *data, char *text){ } memset (pNew, 0, sizeof (NexusFile5)); - time_buffer = NXIformatNeXusTime(); /* start HDF5 interface */ if (am == NXACC_CREATE5) { @@ -181,6 +181,9 @@ static void ignoreError(void *data, char *text){ free (pNew); return NX_ERROR; } + if(fapl != -1) { + H5Pclose(fapl); + } /* * need to create global attributes file_name file_time NeXus_version @@ -188,15 +191,15 @@ static void ignoreError(void *data, char *text){ */ if (am1 != H5F_ACC_RDONLY) { - pNew->iVID=H5Gopen(pNew->iFID,"/"); + iVID=H5Gopen(pNew->iFID,"/"); aid2 = H5Screate(H5S_SCALAR); aid1 = H5Tcopy(H5T_C_S1); H5Tset_size(aid1, strlen(NEXUS_VERSION)); if (am1 == H5F_ACC_RDWR) { - H5Adelete(pNew->iVID, "NeXus_version"); + H5Adelete(iVID, "NeXus_version"); } - attr1= H5Acreate(pNew->iVID, "NeXus_version", aid1, aid2, H5P_DEFAULT); + attr1= H5Acreate(iVID, "NeXus_version", aid1, aid2, H5P_DEFAULT); if (attr1<0) { NXIReportError (NXpData, @@ -214,15 +217,15 @@ static void ignoreError(void *data, char *text){ iRet = H5Sclose(aid2); /* Close attribute */ iRet = H5Aclose(attr1); - H5Gclose(pNew->iVID); + H5Gclose(iVID); } if (am1 == H5F_ACC_TRUNC) { - pNew->iVID=H5Gopen(pNew->iFID,"/"); + iVID=H5Gopen(pNew->iFID,"/"); aid2=H5Screate(H5S_SCALAR); aid1 = H5Tcopy(H5T_C_S1); H5Tset_size(aid1, strlen(filename)); - attr1= H5Acreate(pNew->iVID, "file_name", aid1, aid2, H5P_DEFAULT); + attr1= H5Acreate(iVID, "file_name", aid1, aid2, H5P_DEFAULT); if (attr1 < 0) { NXIReportError (NXpData, @@ -244,7 +247,7 @@ static void ignoreError(void *data, char *text){ aid2=H5Screate(H5S_SCALAR); aid1 = H5Tcopy(H5T_C_S1); H5Tset_size(aid1, strlen(version_nr)); - attr1= H5Acreate(pNew->iVID, "HDF5_Version", aid1, aid2, H5P_DEFAULT); + attr1= H5Acreate(iVID, "HDF5_Version", aid1, aid2, H5P_DEFAULT); if (attr1 < 0) { NXIReportError (NXpData, @@ -261,11 +264,12 @@ static void ignoreError(void *data, char *text){ iRet = H5Sclose(aid2); iRet = H5Aclose(attr1); /*----------- file time */ + time_buffer = NXIformatNeXusTime(); if(time_buffer != NULL){ aid2=H5Screate(H5S_SCALAR); aid1 = H5Tcopy(H5T_C_S1); H5Tset_size(aid1, strlen(time_buffer)); - attr1=H5Acreate(pNew->iVID, "file_time", aid1, aid2, H5P_DEFAULT); + attr1=H5Acreate(iVID, "file_time", aid1, aid2, H5P_DEFAULT); if (attr1 < 0) { NXIReportError (NXpData, @@ -287,7 +291,7 @@ static void ignoreError(void *data, char *text){ iRet = H5Aclose(attr1); free(time_buffer); } - H5Gclose(pNew->iVID); + H5Gclose(iVID); } /* Set HDFgroup access mode */ if (am1 == H5F_ACC_RDONLY) { @@ -316,9 +320,9 @@ static void ignoreError(void *data, char *text){ H5Fget_obj_count(pFile->iFID,H5F_OBJ_ALL)); */ iRet = H5Fclose(pFile->iFID); - - /* - Please leave this here, it helps debugging HDF5 resource leakages + + /* + leave this here: it helps in debugging leakage problems printf("HDF5 object count after close: %d\n", H5Fget_obj_count(H5F_OBJ_ALL,H5F_OBJ_ALL)); printf("HDF5 dataset count after close: %d\n", @@ -353,7 +357,7 @@ static void ignoreError(void *data, char *text){ NXstatus NX5makegroup (NXhandle fid, CONSTCHAR *name, CONSTCHAR *nxclass) { pNexusFile5 pFile; - hid_t iRet; + hid_t iRet, iVID; hid_t attr1,aid1, aid2; char pBuffer[1024] = ""; @@ -372,12 +376,12 @@ static void ignoreError(void *data, char *text){ NXIReportError (NXpData, "ERROR: HDF could not create Group"); return NX_ERROR; } - pFile->iVID = iRet; + iVID = iRet; strncpy(pFile->name_ref,pBuffer,1023); aid2 = H5Screate(H5S_SCALAR); aid1 = H5Tcopy(H5T_C_S1); H5Tset_size(aid1, strlen(nxclass)); - attr1= H5Acreate(pFile->iVID, "NX_class", aid1, aid2, H5P_DEFAULT); + attr1= H5Acreate(iVID, "NX_class", aid1, aid2, H5P_DEFAULT); if (attr1 < 0) { NXIReportError (NXpData, "ERROR: HDF failed to store class name!"); @@ -392,7 +396,7 @@ static void ignoreError(void *data, char *text){ iRet=H5Sclose(aid2); iRet=H5Tclose(aid1); iRet=H5Aclose(attr1); - iRet=H5Gclose(pFile->iVID); + iRet=H5Gclose(iVID); return NX_OK; } @@ -405,7 +409,7 @@ static void ignoreError(void *data, char *text){ strcpy(attr_name,"NX_class"); return strstr(member_name, attr_name) ? 1 : 0; } - + /*------------------------------------------------------------------------*/ NXstatus NX5opengroup (NXhandle fid, CONSTCHAR *name, CONSTCHAR *nxclass) { @@ -417,93 +421,59 @@ static void ignoreError(void *data, char *text){ pFile = NXI5assert (fid); if (pFile->iCurrentG == 0) { - iRet = H5Gopen (pFile->iFID, (const char *)name); - if (iRet < 0) { - sprintf (pBuffer, "ERROR: Group %s does not exist!", name); - NXIReportError (NXpData, pBuffer); - return NX_ERROR; - } - pFile->iCurrentG = iRet; - /* check group attribute */ - iRet = H5Aiterate(pFile->iCurrentG,NULL,attr_check,NULL); - if (iRet < 0) { - NXIReportError (NXpData, "ERROR iterating through group!"); - return NX_ERROR; - } else if (iRet == 1) { - /* group attribute was found */ - } else { - /* no group attribute available */ - NXIReportError (NXpData, "No group attribute available"); - return NX_ERROR; - } - /* check contents of group attribute */ - attr1 = H5Aopen_name(pFile->iCurrentG, "NX_class"); - if (attr1 < 0) - { - NXIReportError (NXpData, "Error opening group attribute!"); - return NX_ERROR; - } - atype=H5Tcopy(H5T_C_S1); - H5Tset_size(atype,128); - iRet = H5Aread(attr1, atype, data); - if (strcmp(data, nxclass) == 0) { - /* test OK */ - } else { - NXIReportError (NXpData, "Group class is not identical!"); - iRet = H5Tclose(atype); - iRet = H5Aclose(attr1); - return NX_ERROR; - } - iRet = H5Tclose(atype); - iRet = H5Aclose(attr1); - pFile->iStack5[pFile->iStackPtr].iVref=0; - strcpy(pFile->iStack5[pFile->iStackPtr].irefn,""); - strcpy(pFile->name_ref,name); - strcpy(pFile->name_tmp,name); - } else { + strcpy(pBuffer,name); + } + else + { sprintf(pBuffer,"%s/%s",pFile->name_tmp,name); - iRet = H5Gopen (pFile->iFID,(const char *)pBuffer); - if (iRet < 0) { - sprintf (pBuffer, "ERROR: Group %s does not exist!", pFile->name_tmp); - NXIReportError (NXpData, pBuffer); - return NX_ERROR; - } - pFile->iCurrentG = iRet; - strcpy(pFile->name_tmp,pBuffer); - strcpy(pFile->name_ref,pBuffer); - /* check group attribute */ - iRet=H5Aiterate(pFile->iCurrentG,NULL,attr_check,NULL); - if (iRet < 0) { + } + iRet = H5Gopen (pFile->iFID,(const char *)pBuffer); + if (iRet < 0) { + sprintf (pBuffer, "ERROR: Group %s does not exist!", pFile->name_tmp); + NXIReportError (NXpData, pBuffer); + return NX_ERROR; + } + pFile->iCurrentG = iRet; + strcpy(pFile->name_tmp,pBuffer); + strcpy(pFile->name_ref,pBuffer); + + if ((nxclass != NULL) && (strcmp(nxclass, NX_UNKNOWN_GROUP) != 0)) + { + /* check group attribute */ + iRet=H5Aiterate(pFile->iCurrentG,NULL,attr_check,NULL); + if (iRet < 0) { NXIReportError (NXpData, "ERROR iterating through group!"); return NX_ERROR; - } else if (iRet == 1) { + } else if (iRet == 1) { /* group attribute was found */ - } else { + } else { /* no group attribute available */ NXIReportError (NXpData, "No group attribute available"); return NX_ERROR; - } - /* check contains of group attribute */ - attr1 = H5Aopen_name(pFile->iCurrentG, "NX_class"); - if (attr1 < 0) - { - NXIReportError (NXpData, "Error opening group attribute!"); - return NX_ERROR; - } - atype=H5Tcopy(H5T_C_S1); - H5Tset_size(atype,128); - iRet = H5Aread(attr1, atype, data); - if (strcmp(data, nxclass) == 0) { - /* test OK */ - } else { - NXIReportError (NXpData, "Group class is not identical!"); - iRet = H5Tclose(atype); - iRet = H5Aclose(attr1); - return NX_ERROR; - } - iRet = H5Tclose(atype); - iRet = H5Aclose(attr1); + } + /* check contents of group attribute */ + attr1 = H5Aopen_name(pFile->iCurrentG, "NX_class"); + if (attr1 < 0) + { + NXIReportError (NXpData, "Error opening NX_class group attribute!"); + return NX_ERROR; + } + atype=H5Tcopy(H5T_C_S1); + H5Tset_size(atype,128); + iRet = H5Aread(attr1, atype, data); + if (strcmp(data, nxclass) == 0) { + /* test OK */ + } else { + NXIReportError (NXpData, "Group class is not identical!"); + iRet = H5Tclose(atype); + iRet = H5Aclose(attr1); + return NX_ERROR; + } + iRet = H5Tclose(atype); + iRet = H5Aclose(attr1); } + + /* maintain stack */ pFile->iStackPtr++; pFile->iStack5[pFile->iStackPtr].iVref=pFile->iCurrentG; strcpy(pFile->iStack5[pFile->iStackPtr].irefn,name); @@ -573,30 +543,10 @@ static void ignoreError(void *data, char *text){ } return NX_OK; } - - /* --------------------------------------------------------------------- */ - - NXstatus NX5compmakedata (NXhandle fid, CONSTCHAR *name, - int datatype, - int rank, int dimensions[], - int compress_type, int chunk_size[]) - { - hid_t datatype1, dataspace, iNew, iRet; - hid_t type,cparms; - pNexusFile5 pFile; - char pBuffer[256]; - int i, byte_zahl; - hsize_t chunkdims[H5S_MAX_RANK]; - hsize_t mydim[H5S_MAX_RANK], mydim1[H5S_MAX_RANK]; - hsize_t size[2]; - hsize_t maxdims[H5S_MAX_RANK]; - - pFile = NXI5assert (fid); - - for (i = 0; i < rank; i++) - { - chunkdims[i]=chunk_size[i]; - } +/*-----------------------------------------------------------------------*/ +static int nxToHDF5Type(int datatype) +{ + int type; if (datatype == NX_CHAR) { type=H5T_C_S1; @@ -625,6 +575,14 @@ static void ignoreError(void *data, char *text){ { type=H5T_NATIVE_UINT; } + else if (datatype == NX_INT64) + { + type = H5T_NATIVE_INT64; + } + else if (datatype == NX_UINT64) + { + type = H5T_NATIVE_UINT64; + } else if (datatype == NX_FLOAT32) { type=H5T_NATIVE_FLOAT; @@ -633,6 +591,43 @@ static void ignoreError(void *data, char *text){ { type=H5T_NATIVE_DOUBLE; } + else + { + NXIReportError (NXpData, "ERROR: nxToHDF5Type: unknown type"); + type = -1; + } + return type; +} + + /* --------------------------------------------------------------------- */ + + NXstatus NX5compmakedata (NXhandle fid, CONSTCHAR *name, + int datatype, + int rank, int dimensions[], + int compress_type, int chunk_size[]) + { + hid_t datatype1, dataspace, iNew, iRet; + hid_t type, cparms = -1; + pNexusFile5 pFile; + char pBuffer[256]; + int i, byte_zahl = 0; + hsize_t chunkdims[H5S_MAX_RANK]; + hsize_t mydim[H5S_MAX_RANK], mydim1[H5S_MAX_RANK]; + hsize_t size[H5S_MAX_RANK]; + hsize_t maxdims[H5S_MAX_RANK]; + + pFile = NXI5assert (fid); + + for (i = 0; i < rank; i++) + { + chunkdims[i]=chunk_size[i]; + mydim[i] = dimensions[i]; + maxdims[i] = dimensions[i]; + size[i] = dimensions[i]; + } + + type = nxToHDF5Type(datatype); + if (rank <= 0) { sprintf (pBuffer, "ERROR: invalid rank specified %s", name); @@ -640,7 +635,7 @@ static void ignoreError(void *data, char *text){ return NX_ERROR; } /* - Check dimensions for consistency. The first dimension may be 0 + Check dimensions for consistency. The first dimension may be -1 thus denoting an unlimited dimension. */ for (i = 1; i < rank; i++) { @@ -651,30 +646,42 @@ static void ignoreError(void *data, char *text){ NXIReportError (NXpData, pBuffer); return NX_ERROR; } - mydim[i] = dimensions[i]; - maxdims[i] = dimensions[i]; } if (datatype == NX_CHAR) { - byte_zahl=dimensions[0]; - dimensions[0]=rank; +/* + * This assumes string lenght is in the last dimensions and + * the logic must be the same as used in NX5getslab and NX5getinfo + * + * search for tests on H5T_STRING + */ + byte_zahl=dimensions[rank-1]; for(i = 0; i < rank; i++) { mydim1[i] = dimensions[i]; } - dimensions[0] = byte_zahl; - dataspace=H5Screate_simple(rank,mydim1,NULL); + mydim1[rank-1] = 1; + if (dimensions[rank-1] > 1) + { + mydim[rank-1] = maxdims[rank-1] = size[rank-1] = 1; + } + if (chunkdims[rank-1] > 1) + { + chunkdims[rank-1] = 1; + } + if (dimensions[0] == NX_UNLIMITED) + { + mydim1[0] = 1; + maxdims[0] = H5S_UNLIMITED; + } + dataspace=H5Screate_simple(rank,mydim1,maxdims); } else { if (dimensions[0] == NX_UNLIMITED) { - mydim[0]=1; + mydim[0] = 1; maxdims[0] = H5S_UNLIMITED; dataspace=H5Screate_simple(rank, mydim, maxdims); } else { - for(i = 0; i < rank; i++) - { - mydim[i] = dimensions[i]; - } /* dataset creation */ dataspace=H5Screate_simple(rank, mydim, NULL); } @@ -683,6 +690,7 @@ static void ignoreError(void *data, char *text){ if (datatype == NX_CHAR) { H5Tset_size(datatype1, byte_zahl); +/* H5Tset_strpad(H5T_STR_SPACEPAD); */ } if(compress_type == NX_COMP_LZW) { @@ -724,10 +732,7 @@ static void ignoreError(void *data, char *text){ } if (dimensions[0] == NX_UNLIMITED) { - for(i = 0; i < rank; i++){ - size[i] = dimensions[i]; - } - size[0] = 1; + size[0] = 1; iNew = H5Dextend (pFile->iCurrentD, size); if (iNew < 0) { sprintf (pBuffer, "ERROR: cannot create Dataset %s, check arguments", @@ -736,6 +741,9 @@ static void ignoreError(void *data, char *text){ return NX_ERROR; } } + if (cparms != -1) { + iRet = H5Pclose(cparms); + } iRet = H5Sclose(dataspace); iRet = H5Tclose(datatype1); iRet = H5Dclose(pFile->iCurrentD); @@ -865,7 +873,27 @@ static void ignoreError(void *data, char *text){ } return NX_OK; } - +/*------------------------------------------------------------------*/ +static int getAttVID(pNexusFile5 pFile){ + int vid; + if(pFile->iCurrentG == 0 && pFile->iCurrentD == 0){ + /* global attribute */ + vid = H5Gopen(pFile->iFID,"/"); + } else if(pFile->iCurrentD != 0) { + /* dataset attribute */ + vid = pFile->iCurrentD; + } else { + /* group attribute */; + vid = pFile->iCurrentG; + } + return vid; +} +/*---------------------------------------------------------------*/ +static void killAttVID(pNexusFile5 pFile, int vid){ + if(pFile->iCurrentG == 0 && pFile->iCurrentD == 0){ + H5Gclose(vid); + } +} /* ------------------------------------------------------------------- */ NXstatus NX5putattr (NXhandle fid, CONSTCHAR *name, void *data, @@ -875,111 +903,46 @@ static void ignoreError(void *data, char *text){ hid_t attr1, aid1, aid2; hid_t type; int iRet; - + int vid; + pFile = NXI5assert (fid); - if (iType == NX_CHAR) - { - type=H5T_C_S1; - } - else if (iType == NX_INT8) - { - type=H5T_NATIVE_CHAR; - } - else if (iType == NX_UINT8) - { - type=H5T_NATIVE_UCHAR; - } - else if (iType == NX_INT16) - { - type=H5T_NATIVE_SHORT; - } - else if (iType == NX_UINT16) - { - type=H5T_NATIVE_USHORT; - } - else if (iType == NX_INT32) - { - type=H5T_NATIVE_INT; - } - else if (iType == NX_UINT32) - { - type=H5T_NATIVE_UINT; - } - else if (iType == NX_FLOAT32) - { - type=H5T_NATIVE_FLOAT; - } - else if (iType == NX_FLOAT64) - { - type=H5T_NATIVE_DOUBLE; - } - if (pFile->iCurrentD != 0) { - /* Dataset attribute */ - aid2=H5Screate(H5S_SCALAR); - aid1=H5Tcopy(type); - if (iType == NX_CHAR) - { - H5Tset_size(aid1,datalen); - } - iRet = H5Aopen_name(pFile->iCurrentD, name); - if (iRet>0) { - H5Aclose(iRet); - iRet=H5Adelete(pFile->iCurrentD,name); - if (iRet<0) { - NXIReportError (NXpData, "ERROR: Old attribute cannot removed! "); - return NX_ERROR; - } - } - attr1 = H5Acreate(pFile->iCurrentD, name, aid1, aid2, H5P_DEFAULT); - if (attr1 < 0) { - NXIReportError (NXpData, "ERROR: Attribute cannot created! "); - return NX_ERROR; - } - if (H5Awrite(attr1,aid1,data) < 0) - { - NXIReportError (NXpData, "ERROR: HDF failed to store attribute "); - return NX_ERROR; - } - /* Close attribute dataspace */ - iRet=H5Tclose(aid1); - iRet=H5Sclose(aid2); - /* Close attribute */ - iRet=H5Aclose(attr1); - } else { - /* global attribute */ - pFile->iVID=H5Gopen(pFile->iFID,"/"); - aid2=H5Screate(H5S_SCALAR); - aid1=H5Tcopy(type); - if (iType == NX_CHAR) - { - H5Tset_size(aid1,datalen); - } - iRet = H5Aopen_name(pFile->iVID, name); - if (iRet>0) { - H5Aclose(iRet); - iRet=H5Adelete(pFile->iVID,name); - if (iRet<0) { - NXIReportError (NXpData, "ERROR: Old attribute cannot removed! "); - return NX_ERROR; - } - } - attr1 = H5Acreate(pFile->iVID, name, aid1, aid2, H5P_DEFAULT); - if (attr1 < 0) { - NXIReportError (NXpData, "ERROR: Attribute cannot created! "); - return NX_ERROR; - } - if (H5Awrite(attr1,aid1,data) < 0) - { - NXIReportError (NXpData, "ERROR: HDf failed to store attribute "); - return NX_ERROR; - } - /* Close attribute dataspace */ - iRet=H5Tclose(aid1); - iRet=H5Sclose(aid2); - /* Close attribute */ - iRet=H5Aclose(attr1); - H5Gclose(pFile->iVID); + + type = nxToHDF5Type(iType); + + /* determine vid */ + vid = getAttVID(pFile); + aid2=H5Screate(H5S_SCALAR); + aid1=H5Tcopy(type); + if (iType == NX_CHAR){ + H5Tset_size(aid1,datalen); + } + iRet = H5Aopen_name(vid, name); + if (iRet>0) { + H5Aclose(iRet); + iRet=H5Adelete(vid,name); + if (iRet<0) { + NXIReportError (NXpData, "ERROR: Old attribute cannot removed! "); + killAttVID(pFile,vid); + return NX_ERROR; + } + } + attr1 = H5Acreate(vid, name, aid1, aid2, H5P_DEFAULT); + if (attr1 < 0) { + NXIReportError (NXpData, "ERROR: Attribute cannot created! "); + killAttVID(pFile,vid); + return NX_ERROR; + } + if (H5Awrite(attr1,aid1,data) < 0) { + NXIReportError (NXpData, "ERROR: HDF failed to store attribute "); + killAttVID(pFile,vid); + return NX_ERROR; } + /* Close attribute dataspace */ + iRet=H5Tclose(aid1); + iRet=H5Sclose(aid2); + /* Close attribute */ + iRet=H5Aclose(attr1); + killAttVID(pFile,vid); return NX_OK; } @@ -990,7 +953,7 @@ static void ignoreError(void *data, char *text){ pNexusFile5 pFile; int iRet, i; int rank; - hssize_t myStart[H5S_MAX_RANK]; + hsize_t myStart[H5S_MAX_RANK]; hsize_t mySize[H5S_MAX_RANK]; hsize_t size[H5S_MAX_RANK],maxdims[H5S_MAX_RANK]; hid_t filespace,dataspace; @@ -1002,43 +965,49 @@ static void ignoreError(void *data, char *text){ return NX_ERROR; } rank = H5Sget_simple_extent_ndims(pFile->iCurrentS); + iRet = H5Sget_simple_extent_dims(pFile->iCurrentS, NULL, maxdims); for(i = 0; i < rank; i++) { myStart[i] = iStart[i]; mySize[i] = iSize[i]; + size[i] = iSize[i]; } - iRet = H5Sget_simple_extent_dims(pFile->iCurrentS, NULL, maxdims); -//XXX This limits you to one unlimited dimension - if (maxdims[0] == H5S_UNLIMITED) + if (H5Tget_class(pFile->iCurrentT) == H5T_STRING) { - dataspace = H5Screate_simple (rank, mySize, maxdims); - for(i = 0; i < rank; i++) - { - size[i]=iStart[i] + iSize[i]; - } - iRet = H5Dextend(pFile->iCurrentD, size); - filespace = H5Dget_space(pFile->iCurrentD); - - /* define slab */ - iRet = H5Sselect_hyperslab(filespace, H5S_SELECT_SET, myStart, - NULL, mySize, NULL); - /* deal with HDF errors */ - if (iRet < 0) - { - NXIReportError (NXpData, "ERROR: selecting slab failed"); - return NX_ERROR; - } - /* write slab */ - iRet = H5Dwrite(pFile->iCurrentD, pFile->iCurrentT, dataspace, - filespace, H5P_DEFAULT,data); - if (iRet < 0) - { - NXIReportError (NXpData, "ERROR: writing slab failed"); - return NX_ERROR; - } - iRet = H5Sclose(filespace); - } else { + mySize[rank - 1] = 1; + myStart[rank - 1] = 0; + } dataspace = H5Screate_simple (rank, mySize, NULL); + if (maxdims[0] == NX_UNLIMITED) + { + size[0]=iStart[0] + iSize[0]; + iRet = H5Dextend(pFile->iCurrentD, size); + if (iRet < 0) + { + NXIReportError (NXpData, "ERROR: extend slab failed"); + return NX_ERROR; + } + + filespace = H5Dget_space(pFile->iCurrentD); + + /* define slab */ + iRet = H5Sselect_hyperslab(filespace, H5S_SELECT_SET, myStart, + NULL, mySize, NULL); + /* deal with HDF errors */ + if (iRet < 0) + { + NXIReportError (NXpData, "ERROR: selecting slab failed"); + return NX_ERROR; + } + /* write slab */ + iRet = H5Dwrite(pFile->iCurrentD, pFile->iCurrentT, dataspace, + filespace, H5P_DEFAULT,data); + if (iRet < 0) + { + NXIReportError (NXpData, "ERROR: writing slab failed"); + } + iRet = H5Sclose(filespace); + } else { /* define slab */ iRet = H5Sselect_hyperslab(pFile->iCurrentS, H5S_SELECT_SET, myStart, NULL, mySize, NULL); @@ -1051,12 +1020,16 @@ static void ignoreError(void *data, char *text){ /* write slab */ iRet = H5Dwrite(pFile->iCurrentD, pFile->iCurrentT, dataspace, pFile->iCurrentS, H5P_DEFAULT,data); + if (iRet < 0) + { + NXIReportError (NXpData, "ERROR: writing slab failed"); + } } /* deal with HDF errors */ iRet = H5Sclose(dataspace); if (iRet < 0) { - NXIReportError (NXpData, "ERROR: writing slab failed"); + NXIReportError (NXpData, "ERROR: closing slab failed"); return NX_ERROR; } return NX_OK; @@ -1078,15 +1051,21 @@ static void ignoreError(void *data, char *text){ if(pFile->iCurrentD <= 0){ return NX_ERROR; } - strcpy(sRes->iTag5,""); - strcpy(sRes->iRef5,"/"); - strcat(sRes->iRef5,pFile->name_ref); - strcpy(sRes->iRefd,pFile->iCurrentLD); + + /* + this means: if the item is already linked: use the target attribute else, + the path to the current node + */ oldErr = NXMGetError(); NXMSetError(NXpData, ignoreError); datalen = 1024; memset(&sRes->targetPath,0,datalen*sizeof(char)); - NX5getattr(fid,"target",&sRes->targetPath,&datalen,&type); + if(NX5getattr(fid,"target",&sRes->targetPath,&datalen,&type) != NX_OK) + { + buildCurrentPath(pFile, sRes->targetPath, 1024); + } + NXMSetError(NXpData,oldErr); + sRes->linkType = 1; return NX_OK; } @@ -1096,79 +1075,139 @@ static void ignoreError(void *data, char *text){ { pNexusFile5 pFile; pFile = NXI5assert (fid); - printf("HDF5 link: iTag5 = \"%s\", iRef5 = \"%s\", iRefd = \"%s\"\n", sLink->iTag5, sLink->iRef5, sLink->iRefd); + printf("HDF5 link: targetPath = \"%s\", linkType = \"%d\"\n", sLink->targetPath, sLink->linkType); return NX_OK; } +/*--------------------------------------------------------------------*/ +static NXstatus NX5settargetattribute(pNexusFile5 pFile, NXlink *sLink) +{ + herr_t length, dataID, status, aid2, aid1, attID; + int type = NX_CHAR; + char name[] = "target"; - /* ------------------------------------------------------------------- */ - - NXstatus NX5makelink (NXhandle fid, NXlink* sLink) - { + length = strlen(sLink->targetPath); + /* + set the target attribute + */ + if(sLink->linkType > 0) + { + dataID = H5Dopen(pFile->iFID,sLink->targetPath); + } else { + dataID = H5Gopen(pFile->iFID,sLink->targetPath); + } + if(dataID < 0) + { + NXIReportError(NXpData,"Internal error, path to link does not exist"); + return NX_ERROR; + } + status = H5Aopen_name(dataID,name); + if(status > 0) + { + H5Aclose(status); + status = H5Adelete(dataID,name); + if(status < 0) + { + return NX_OK; + } + } + aid2 = H5Screate(H5S_SCALAR); + aid1 = H5Tcopy(H5T_C_S1); + H5Tset_size(aid1,strlen(sLink->targetPath)); + attID = H5Acreate(dataID,name,aid1,aid2,H5P_DEFAULT); + if(attID < 0) + { + return NX_OK; + } + status = H5Awrite(attID,aid1,sLink->targetPath); + H5Tclose(aid1); + H5Sclose(aid2); + H5Aclose(attID); + if(sLink->linkType > 0){ + H5Dclose(dataID); + } else { + H5Gclose(dataID); + } + return NX_OK; +} +/*---------------------------------------------------------------------*/ +NXstatus NX5makenamedlink(NXhandle fid, CONSTCHAR *name, NXlink *sLink) +{ pNexusFile5 pFile; -/* int iRet; */ - herr_t status, dataID, aid1, aid2, attID; - int size_type; - char buffer[1024]; - char name[] = "target"; + char linkTarget[1024]; + int type = NX_CHAR, length; + int status; pFile = NXI5assert (fid); if (pFile->iCurrentG == 0) { /* root level, can not link here */ return NX_ERROR; } - size_type = strlen(sLink->iRefd); - if (size_type > 0) + + /* + build pathname to link from our current group and the name + of the thing to link + */ + if(strlen(pFile->name_ref) + strlen(name) + 2 < 1024) { - /* dataset link */ - strcpy(sLink->iTag5,pFile->name_ref); - } else { - /* group link */ - strcpy(buffer,pFile->name_ref); - strcat(buffer, sLink->iTag5); - strcpy(sLink->iTag5,"/"); - strcat(sLink->iTag5,buffer); + strcpy(linkTarget,"/"); + strcat(linkTarget,pFile->name_ref); + strcat(linkTarget,"/"); + strcat(linkTarget,name); } - if (size_type>0) + else { - strcat(sLink->iRef5,"/"); - strcat(sLink->iRef5,sLink->iRefd); + NXIReportError(NXpData,"Path string to long"); + return NX_ERROR; + } + + status = H5Glink(pFile->iFID, H5G_LINK_HARD, sLink->targetPath, linkTarget); + + return NX5settargetattribute(pFile,sLink); +} + /* ------------------------------------------------------------------- */ + + NXstatus NX5makelink (NXhandle fid, NXlink* sLink) + { + pNexusFile5 pFile; + char linkTarget[1024]; + int type = NX_CHAR, length; + char *itemName = NULL; + int status; + + pFile = NXI5assert (fid); + if (pFile->iCurrentG == 0) { /* root level, can not link here */ + return NX_ERROR; } - if (size_type>0) + + /* + locate name of the element to link + */ + itemName = strrchr(sLink->targetPath,'/'); + if(itemName == NULL){ + NXIReportError(NXpData,"Bad link structure"); + return NX_ERROR; + } + itemName++; + + /* + build pathname to link from our current group and the name + of the thing to link + */ + if(strlen(pFile->name_ref) + strlen(itemName) + 2 < 1024) { - strcat(sLink->iTag5,"/"); - strcat(sLink->iTag5,sLink->iRefd); + strcpy(linkTarget,"/"); + strcat(linkTarget,pFile->name_ref); + strcat(linkTarget,"/"); + strcat(linkTarget,itemName); } - status = H5Glink(pFile->iFID, H5G_LINK_HARD, sLink->iRef5, sLink->iTag5); - if(size_type > 0) + else { - dataID = H5Dopen(pFile->iFID,sLink->iRef5); - /* - remove old attribute if existing - */ - status = H5Aopen_name(dataID,name); - if(status > 0) - { - H5Aclose(status); - status = H5Adelete(dataID,name); - if(status < 0) - { - return NX_OK; - } - } - aid2 = H5Screate(H5S_SCALAR); - aid1 = H5Tcopy(H5T_C_S1); - H5Tset_size(aid1,strlen(sLink->iRef5)); - attID = H5Acreate(dataID,name,aid1,aid2,H5P_DEFAULT); - if(attID < 0) - { - return NX_OK; - } - H5Awrite(attID,aid1,sLink->iRef5); - H5Tclose(aid1); - H5Sclose(aid2); - H5Aclose(attID); - H5Dclose(dataID); - } - return NX_OK; + NXIReportError(NXpData,"Path string to long"); + return NX_ERROR; + } + + status = H5Glink(pFile->iFID, H5G_LINK_HARD, sLink->targetPath, linkTarget); + + return NX5settargetattribute(pFile,sLink); } /*----------------------------------------------------------------------*/ @@ -1246,6 +1285,8 @@ static void ignoreError(void *data, char *text){ self.iNX++; *((int*)opdata)=self.iNX; break; + default: + break; } return 0; } @@ -1272,7 +1313,7 @@ static void ignoreError(void *data, char *text){ strcpy (pName,pFile->name_ref); attr_id = H5Aopen_name(pFile->iCurrentG,"NX_class"); if (attr_id<0) { - strcpy(pClass,"non"); + strcpy(pClass, NX_UNKNOWN_GROUP); } else { atype=H5Tcopy(H5T_C_S1); H5Tset_size(atype,64); @@ -1286,87 +1327,13 @@ static void ignoreError(void *data, char *text){ } return NX_OK; } - - /*-------------------------------------------------------------------------*/ - NXstatus NX5getnextentry (NXhandle fid,NXname name, NXname nxclass, int *datatype) - { - pNexusFile5 pFile; - hid_t grp, attr1,type,atype; - int iRet,iPtype, i; - int idx,data_id,size_id, sign_id; - char data[128]; - char ph_name[1024]; - info_type op_data; - int iRet_iNX=-1; - char pBuffer[256]; - - pFile = NXI5assert (fid); - op_data.iname = NULL; - idx=pFile->iStack5[pFile->iStackPtr].iCurrentIDX; - if (strlen(pFile->name_ref) == 0) { - /* root group */ - strcpy(pFile->name_ref,"/"); - } - iRet=H5Giterate(pFile->iFID,pFile->name_ref,&idx,nxgroup_info,&op_data); - strcpy(nxclass,""); - - if (pFile->iCurrentG == 0) { - pFile->iNX=0; - iRet_iNX = H5Giterate(pFile->iFID,"/",0,group_info1,&pFile->iNX); - } else { - pFile->iNX=0; - iRet_iNX = H5Giterate(pFile->iFID,pFile->name_ref,0,group_info1, &pFile->iNX); - } - if (idx == pFile->iNX) { - iRet_iNX = 2; - } - - if (iRet > 0) - { - pFile->iStack5[pFile->iStackPtr].iCurrentIDX++; - if (op_data.iname != NULL) { - strcpy(name,op_data.iname); - free(op_data.iname); - } else { - pFile->iStack5[pFile->iStackPtr].iCurrentIDX = 0; - return NX_EOD; - } - if (op_data.type == H5G_GROUP) - { - strcpy(ph_name,""); - for(i = 1; i < (pFile->iStackPtr + 1); i++) - { - strcat(ph_name,pFile->iStack5[i].irefn); - strcat(ph_name,"/"); - } - strcat(ph_name,name); - grp=H5Gopen(pFile->iFID,ph_name); - if (grp < 0) { - sprintf (pBuffer, "ERROR: Group %s does not exist!", ph_name); - NXIReportError (NXpData, pBuffer); - return NX_ERROR; - } - attr1 = H5Aopen_name(grp, "NX_class"); - if (attr1 < 0) { - H5Gclose(grp); - NXIReportError (NXpData, "Error opening group class"); - return NX_ERROR; - } - type=H5T_C_S1; - atype=H5Tcopy(type); - H5Tset_size(atype,128); - iRet = H5Aread(attr1, atype, data); - strcpy(nxclass,data); - H5Tclose(atype); - H5Gclose(grp); - H5Aclose(attr1); - } else if (op_data.type==H5G_DATASET) - { - grp=H5Dopen(pFile->iCurrentG,name); - type=H5Dget_type(grp); - atype=H5Tcopy(type); - data_id = H5Tget_class(atype); +/*------------------------------------------------------------------------*/ +static int hdf5ToNXType(int data_id, hid_t atype) +{ + int iPtype = -1; + hid_t sign_id, size_id; + if (data_id==H5T_STRING) { iPtype=NX_CHAR; @@ -1401,6 +1368,15 @@ static void ignoreError(void *data, char *text){ } else { iPtype=NX_UINT32; } + } + else if(size_id == 8) + { + if (sign_id==H5T_SGN_2) + { + iPtype=NX_INT64; + } else { + iPtype=NX_UINT64; + } } } else if (data_id==H5T_FLOAT) { @@ -1414,6 +1390,170 @@ static void ignoreError(void *data, char *text){ iPtype=NX_FLOAT64; } } + if (iPtype == -1) + { + NXIReportError (NXpData, "ERROR: hdf5ToNXtype: invalid type"); + } + + return iPtype; +} +/*--------------------------------------------------------------------------*/ +static int h5MemType(hid_t atype) +{ + hid_t data_id, size_id, sign_id, memtype_id = -1; + + data_id = H5Tget_class(atype); + + if (data_id==H5T_INTEGER) + { + size_id=H5Tget_size(atype); + sign_id=H5Tget_sign(atype); + if (size_id==1) + { + if (sign_id==H5T_SGN_2) + { + memtype_id = H5T_NATIVE_INT8; + } else { + memtype_id = H5T_NATIVE_UINT8; + } + } + else if (size_id==2) + { + if (sign_id==H5T_SGN_2) + { + memtype_id = H5T_NATIVE_INT16; + } else { + memtype_id = H5T_NATIVE_UINT16; + } + } + else if (size_id==4) + { + if (sign_id==H5T_SGN_2) + { + memtype_id = H5T_NATIVE_INT32; + } else { + memtype_id = H5T_NATIVE_UINT32; + } + } + else if (size_id==8) + { + if (sign_id==H5T_SGN_2) + { + memtype_id = H5T_NATIVE_INT64; + } else { + memtype_id = H5T_NATIVE_UINT64; + } + } + } else if (data_id==H5T_FLOAT) + { + size_id=H5Tget_size(atype); + if (size_id==4) + { + memtype_id = H5T_NATIVE_FLOAT; + } else if (size_id==8) { + memtype_id = H5T_NATIVE_DOUBLE; + } + } + if (memtype_id == -1) + { + NXIReportError (NXpData, "ERROR: h5MemType: invalid type"); + } + return memtype_id; +} + /*-------------------------------------------------------------------------*/ + + NXstatus NX5getnextentry (NXhandle fid,NXname name, NXname nxclass, int *datatype) + { + pNexusFile5 pFile; + hid_t grp, attr1,type,atype; + int iRet,iPtype, i; + int idx,data_id,size_id, sign_id; + char data[128]; + char ph_name[1024]; + info_type op_data; + int iRet_iNX=-1; + char pBuffer[256]; + + pFile = NXI5assert (fid); + op_data.iname = NULL; + + /* + iterate to next entry in group list + */ + idx=pFile->iStack5[pFile->iStackPtr].iCurrentIDX; + if (strlen(pFile->name_ref) == 0) { + /* root group */ + strcpy(pFile->name_ref,"/"); + } + iRet=H5Giterate(pFile->iFID,pFile->name_ref,&idx,nxgroup_info,&op_data); + strcpy(nxclass, NX_UNKNOWN_GROUP); + + /* + figure out the number of items in the current group. We need this in order to + find out if we are at the end of the search. + */ + if (pFile->iCurrentG == 0) { + pFile->iNX=0; + iRet_iNX = H5Giterate(pFile->iFID,"/",0,group_info1,&pFile->iNX); + } else { + pFile->iNX=0; + iRet_iNX = H5Giterate(pFile->iFID,pFile->name_ref,0,group_info1, &pFile->iNX); + } + if (idx == pFile->iNX) { + iRet_iNX = 2; + } + + if (iRet > 0) + { + pFile->iStack5[pFile->iStackPtr].iCurrentIDX++; + if (op_data.iname != NULL) { + strcpy(name,op_data.iname); + free(op_data.iname); + } else { + pFile->iStack5[pFile->iStackPtr].iCurrentIDX = 0; + return NX_EOD; + } + if (op_data.type == H5G_GROUP) + { + /* + open group and find class name attribute + */ + strcpy(ph_name,""); + for(i = 1; i < (pFile->iStackPtr + 1); i++) + { + strcat(ph_name,pFile->iStack5[i].irefn); + strcat(ph_name,"/"); + } + strcat(ph_name,name); + grp=H5Gopen(pFile->iFID,ph_name); + if (grp < 0) { + sprintf (pBuffer, "ERROR: Group %s does not exist!", ph_name); + NXIReportError (NXpData, pBuffer); + return NX_ERROR; + } + attr1 = H5Aopen_name(grp, "NX_class"); + if (attr1 < 0) { + strcpy(nxclass, NX_UNKNOWN_GROUP); + } else { + type=H5T_C_S1; + atype=H5Tcopy(type); + H5Tset_size(atype,128); + iRet = H5Aread(attr1, atype, data); + strcpy(nxclass,data); + H5Tclose(atype); + H5Aclose(attr1); + } + H5Gclose(grp); + } else if (op_data.type==H5G_DATASET) + { + /* + open dataset and find type + */ + grp=H5Dopen(pFile->iCurrentG,name); + type=H5Dget_type(grp); + atype=H5Tcopy(type); + data_id = H5Tget_class(atype); + iPtype = hdf5ToNXType(data_id, atype); *datatype=iPtype; strcpy(nxclass, "SDS"); H5Tclose(atype); @@ -1424,6 +1564,10 @@ static void ignoreError(void *data, char *text){ } else { + /* + we are at the end of the search: clear the data structure and reset + iCurrentIDX to 0 + */ if (iRet_iNX == 2) { if (op_data.iname != NULL) { free(op_data.iname); @@ -1465,47 +1609,10 @@ static void ignoreError(void *data, char *text){ memtype_id = H5Tcopy(H5T_C_S1); H5Tset_size(memtype_id, dims); } - if (data_id==H5T_INTEGER) + else { - size_id=H5Tget_size(pFile->iCurrentT); - sign_id=H5Tget_sign(pFile->iCurrentT); - if (size_id==1) - { - if (sign_id==H5T_SGN_2) - { - memtype_id = H5T_NATIVE_INT8; - } else { - memtype_id = H5T_NATIVE_UINT8; - } - } - else if (size_id==2) - { - if (sign_id==H5T_SGN_2) - { - memtype_id = H5T_NATIVE_INT16; - } else { - memtype_id = H5T_NATIVE_UINT16; - } - } - else if (size_id==4) - { - if (sign_id==H5T_SGN_2) - { - memtype_id = H5T_NATIVE_INT32; - } else { - memtype_id = H5T_NATIVE_UINT32; - } - } - } else if (data_id==H5T_FLOAT) - { - size_id=H5Tget_size(pFile->iCurrentT); - if (size_id==4) - { - memtype_id = H5T_NATIVE_FLOAT; - } else if (size_id==8) { - memtype_id = H5T_NATIVE_DOUBLE; - } - } + memtype_id = h5MemType(pFile->iCurrentT); + } /* actually read */ status = H5Dread (pFile->iCurrentD, memtype_id, @@ -1541,62 +1648,13 @@ static void ignoreError(void *data, char *text){ /* read information */ data_id = H5Tget_class(pFile->iCurrentT); - if (data_id==H5T_STRING) - { - mType=NX_CHAR; - } - if (data_id==H5T_INTEGER) - { - size_id=H5Tget_size(pFile->iCurrentT); - sign_id=H5Tget_sign(pFile->iCurrentT); - if (size_id==1) - { - if (sign_id==H5T_SGN_2) - { - mType=NX_INT8; - } else { - mType=NX_UINT8; - } - } - else if (size_id==2) - { - if (sign_id==H5T_SGN_2) - { - mType=NX_INT16; - } else { - mType=NX_UINT16; - } - } - else if (size_id==4) - { - if (sign_id==H5T_SGN_2) - { - mType=NX_INT32; - } else { - mType=NX_UINT32; - } - } - } else if (data_id==H5T_FLOAT) - { - size_id=H5Tget_size(pFile->iCurrentT); - if (size_id==4) - { - mType=NX_FLOAT32; - } - else if (size_id==8) - { - mType=NX_FLOAT64; - } - } + mType = hdf5ToNXType(data_id,pFile->iCurrentT); iRank = H5Sget_simple_extent_ndims(pFile->iCurrentS); iRet = H5Sget_simple_extent_dims(pFile->iCurrentS, myDim, NULL); /* conversion to proper ints for the platform */ *iType = (int)mType; - if (data_id==H5T_STRING) { - for (i = 0; i < iRank; i++) - { - myDim[i] = H5Tget_size(pFile->iCurrentT); - } + if (data_id==H5T_STRING && myDim[iRank-1] == 1) { + myDim[iRank-1] = H5Tget_size(pFile->iCurrentT); } *rank = (int)iRank; for (i = 0; i < iRank; i++) @@ -1611,12 +1669,12 @@ static void ignoreError(void *data, char *text){ NXstatus NX5getslab (NXhandle fid, void *data, int iStart[], int iSize[]) { pNexusFile5 pFile; - hssize_t myStart[H5S_MAX_RANK]; + hsize_t myStart[H5S_MAX_RANK]; hsize_t mySize[H5S_MAX_RANK]; - hssize_t mStart[H5S_MAX_RANK]; + hsize_t mStart[H5S_MAX_RANK]; hid_t memspace, iRet, data_id; hid_t memtype_id, size_id, sign_id; - char *tmp_data; + char *tmp_data = NULL; char *data1; int i, dims, iRank, mtype = 0; @@ -1636,6 +1694,11 @@ static void ignoreError(void *data, char *text){ } data_id = H5Tget_class(pFile->iCurrentT); if (data_id == H5T_STRING) { +/* + * FAA 24/1/2007: I don't think this will work for multidimensional + * string arrays. + * MK 23/7/2007: You are right Freddie. +*/ mtype = NX_CHAR; if (mySize[0] == 1) { mySize[0] = H5Tget_size(pFile->iCurrentT); @@ -1671,47 +1734,10 @@ static void ignoreError(void *data, char *text){ memtype_id = H5Tcopy(H5T_C_S1); H5Tset_size(memtype_id, dims); } - if (data_id==H5T_INTEGER) + else { - size_id=H5Tget_size(pFile->iCurrentT); - sign_id=H5Tget_sign(pFile->iCurrentT); - if (size_id==1) - { - if (sign_id==H5T_SGN_2) - { - memtype_id = H5T_NATIVE_INT8; - } else { - memtype_id = H5T_NATIVE_UINT8; - } - } - else if (size_id==2) - { - if (sign_id==H5T_SGN_2) - { - memtype_id = H5T_NATIVE_INT16; - } else { - memtype_id = H5T_NATIVE_UINT16; - } - } - else if (size_id==4) - { - if (sign_id==H5T_SGN_2) - { - memtype_id = H5T_NATIVE_INT32; - } else { - memtype_id = H5T_NATIVE_UINT32; - } - } - } else if (data_id==H5T_FLOAT) - { - size_id=H5Tget_size(pFile->iCurrentT); - if (size_id==4) - { - memtype_id = H5T_NATIVE_FLOAT; - } else if (size_id==8) { - memtype_id = H5T_NATIVE_DOUBLE; - } - } + memtype_id = h5MemType(pFile->iCurrentT); + } /* read slab */ if (mtype == NX_CHAR) { @@ -1753,217 +1779,92 @@ static void ignoreError(void *data, char *text){ char *iname = NULL; unsigned int idx; int intern_idx=-1; + int vid; + pFile = NXI5assert (fileid); + + vid = getAttVID(pFile); + idx=pFile->iAtt5.iCurrentIDX; iRet=0; - if ((pFile->iCurrentD == 0) && (pFile->iCurrentG==0)) - { - /* global attribute */ - pFile->iVID=H5Gopen(pFile->iFID,"/"); - intern_idx=H5Aget_num_attrs(pFile->iVID); - if (intern_idx > idx) { - iRet=H5Aiterate(pFile->iVID,&idx,attr_info,&iname); - } - else - { - iRet=0; - } - intern_idx=-1; - if (iRet < 0) { - NXIReportError (NXpData, "ERROR iterating through ROOT Attr. list!"); - return NX_ERROR; - } - } else if (pFile->iCurrentD > 0) { - intern_idx=H5Aget_num_attrs(pFile->iCurrentD); - if (intern_idx > idx) { - iRet=H5Aiterate(pFile->iCurrentD,&idx,attr_info,&iname); - } - else - { - iRet=0; - } - intern_idx=-1; - if (iRet < 0) { - NXIReportError (NXpData, "ERROR iterating through data Attr. list!"); - return NX_ERROR; - } + intern_idx=H5Aget_num_attrs(vid); + if(intern_idx == idx) { + killAttVID(pFile,vid); + return NX_EOD; } - else - { - pFile->iAtt5.iCurrentIDX = 0; - return NX_EOD; /* no group attributes */ - } - if (iRet>0) - { - pFile->iAtt5.iCurrentIDX++; - strcpy(pName, iname); - if (iname != NULL) { - free(iname); - } - if ((pFile->iCurrentD == 0) && (pFile->iCurrentG==0)) { - /* global attribute */ - pFile->iCurrentA = H5Aopen_name(pFile->iVID, pName); - } else { - pFile->iCurrentA = H5Aopen_name(pFile->iCurrentD, pName); - } - atype = H5Aget_type(pFile->iCurrentA); - aspace = H5Aget_space(pFile->iCurrentA); - rank = H5Sget_simple_extent_ndims(aspace); - attr_id = H5Tget_class(atype); - if (attr_id==H5T_STRING) { - iPType=NX_CHAR; - rank = H5Tget_size(atype); - } - if (rank == 0) { - rank++; - } - if (attr_id==H5T_INTEGER) - { - size_id=H5Tget_size(atype); - sign_id=H5Tget_sign(atype); - if (size_id==1) - { - if (sign_id==H5T_SGN_2) - { - iPType=NX_INT8; - } else { - iPType=NX_UINT8; - } - } - else if (size_id==2) - { - if (sign_id==H5T_SGN_2) - { - iPType=NX_INT16; - } else { - iPType=NX_UINT16; - } - } - else if (size_id==4) - { - if (sign_id==H5T_SGN_2) - { - iPType=NX_INT32; - } else { - iPType=NX_UINT32; - } - } - } else if (attr_id==H5T_FLOAT) - { - size_id=H5Tget_size(atype); - if (size_id==4) - { - iPType=NX_FLOAT32; - } - else if (size_id==8) - { - iPType=NX_FLOAT64; - } - } - *iType=iPType; - *iLength=rank; - H5Tclose(atype); - H5Sclose(aspace); - H5Aclose(pFile->iCurrentA); - return NX_OK; - } - else - { - if ((pFile->iCurrentD == 0) && (pFile->iCurrentG==0)) - { - /* global attribute */ - intern_idx=H5Aget_num_attrs(pFile->iVID); - } else { - if (pFile->iCurrentD>0){ - intern_idx=H5Aget_num_attrs(pFile->iCurrentD); - } else { - intern_idx=H5Aget_num_attrs(pFile->iCurrentG); - } - } - if ((intern_idx == 0)||(intern_idx == idx)) { - pFile->iAtt5.iCurrentIDX = 0; - if (iname != NULL) { - free(iname); - } - return NX_EOD; - } - NXIReportError (NXpData, - "ERROR: Iteration was not successful"); - return NX_ERROR; + + if (intern_idx > idx) { + iRet=H5Aiterate(vid,&idx,attr_info,&iname); + } else { + iRet=0; + } + intern_idx=-1; + if (iRet < 0) { + NXIReportError (NXpData, "ERROR iterating through attribute list!"); + killAttVID(pFile,vid); + return NX_ERROR; + } + pFile->iAtt5.iCurrentIDX++; + if (iname != NULL) { + if(strcmp(iname, "NX_class") == 0 && pFile->iCurrentG != 0) { + /* + skip NXclass attribute which is internal + */ + killAttVID(pFile, vid); + return NX5getnextattr(fileid, pName, iLength, iType); } + strcpy(pName, iname); + free(iname); + iname = NULL; + } else { + strcpy(pName,"What is this?"); + } + pFile->iCurrentA = H5Aopen_name(vid, pName); + atype = H5Aget_type(pFile->iCurrentA); + aspace = H5Aget_space(pFile->iCurrentA); + rank = H5Sget_simple_extent_ndims(aspace); + attr_id = H5Tget_class(atype); + if (attr_id==H5T_STRING) { + iPType=NX_CHAR; + rank = H5Tget_size(atype); + } + if (rank == 0) { + rank++; + } + iPType = hdf5ToNXType(attr_id,atype); + *iType=iPType; + *iLength=rank; + H5Tclose(atype); + H5Sclose(aspace); + H5Aclose(pFile->iCurrentA); + + intern_idx=H5Aget_num_attrs(vid); + + killAttVID(pFile,vid); + return NX_OK; } + /*-------------------------------------------------------------------------*/ - - - /*-------------------------------------------------------------------------*/ - - NXstatus NX5getattr (NXhandle fid, char *name, void *data, int* datalen, int* iType) + NXstatus NX5getattr (NXhandle fid, char *name, + void *data, int* datalen, int* iType) { pNexusFile5 pFile; - int iNew, iRet; - hid_t type, atype, glob; + int iNew, iRet, vid; + hid_t type, atype = -1, glob; char pBuffer[256]; pFile = NXI5assert (fid); type = *iType; glob = 0; - if (type == NX_CHAR) - { - type=H5T_C_S1; - } - else if (type == NX_INT8) - { - type=H5T_NATIVE_CHAR; - } - else if (type == NX_UINT8) - { - type=H5T_NATIVE_UCHAR; - } - else if (type == NX_INT16) - { - type=H5T_NATIVE_SHORT; - } - else if (type == NX_UINT16) - { - type=H5T_NATIVE_USHORT; - } - else if (type == NX_INT32) - { - type=H5T_NATIVE_INT; - } - else if (type == NX_UINT32) - { - type=H5T_NATIVE_UINT; - } - else if (type == NX_FLOAT32) - { - type=H5T_NATIVE_FLOAT; - } - else if (type == NX_FLOAT64) - { - type=H5T_NATIVE_DOUBLE; - } - /* find attribute */ - if (pFile->iCurrentD != 0) - { - /* Dataset attribute */ - iNew = H5Aopen_name(pFile->iCurrentD, name); - } - else - { - /* globale and group attributes */ - if (pFile->iCurrentG != 0) { - /* group attribute */ - iNew = H5Aopen_name(pFile->iCurrentG, name); - } else { - /* global attributes */ - glob=H5Gopen(pFile->iFID,"/"); - iNew = H5Aopen_name(glob, name); - } - } + + type = nxToHDF5Type(type); + + vid = getAttVID(pFile); + iNew = H5Aopen_name(vid, name); if (iNew < 0) { sprintf (pBuffer, "ERROR: attribute %s not found", name); + killAttVID(pFile,vid); NXIReportError (NXpData, pBuffer); return NX_ERROR; } @@ -1983,14 +1884,13 @@ static void ignoreError(void *data, char *text){ if (iRet < 0) { sprintf (pBuffer, "ERROR: HDF could not read attribute data"); NXIReportError (NXpData, pBuffer); + killAttVID(pFile,vid); return NX_ERROR; } iRet = H5Aclose(pFile->iCurrentA); - if (glob > 0) - { - H5Gclose(glob); - } + + killAttVID(pFile,vid); if (type==H5T_C_S1) { H5Tclose(atype); @@ -2005,59 +1905,27 @@ static void ignoreError(void *data, char *text){ pNexusFile5 pFile; char *iname = NULL; unsigned int idx; + int vid; herr_t iRet; pFile = NXI5assert (fid); idx=0; *iN = idx; - if (pFile->iCurrentD == 0 && pFile->iCurrentG == 0) { - /* - global attribute - */ - pFile->iVID=H5Gopen(pFile->iFID,"/"); - iRet = H5Aiterate(pFile->iVID,&idx,attr_info,&iname); - if (iRet < 0) { - NXIReportError (NXpData, "iterating ERROR!"); - return NX_ERROR; - } - idx=H5Aget_num_attrs(pFile->iVID); - if (idx > 0) { - *iN = idx; - } else { - *iN = 1; - } - /* - if (iname != NULL) { - free(iname); - } - */ - return NX_OK; - } - else - { - if (pFile->iCurrentD>0) { - iRet=H5Aiterate(pFile->iCurrentD,&idx,attr_info,&iname); + vid = getAttVID(pFile); + + idx=H5Aget_num_attrs(vid); + if (idx > 0) { + if(pFile->iCurrentG > 0 && pFile->iCurrentD == 0){ + *iN = idx -1; } else { - iRet=H5Aiterate(pFile->iCurrentG,&idx,attr_info,&iname); + *iN = idx; } + } else { + *iN = 0; } - if (iRet<0) { - NXIReportError (NXpData, "Attribute number cannot be fixed!"); - return NX_ERROR; - } - if ((idx==0) && (iRet==0)) { - *iN=idx; - return NX_OK; - } - idx=H5Aget_num_attrs(pFile->iCurrentD); - if (idx > 0) { - *iN = idx; - } else { - *iN = 1; - } + killAttVID(pFile,vid); return NX_OK; - } @@ -2065,25 +1933,28 @@ static void ignoreError(void *data, char *text){ NXstatus NX5getgroupID (NXhandle fileid, NXlink* sRes) { pNexusFile5 pFile; - int u; + int u, datalen, type = NX_CHAR; char group_name[64], class_name[64]; + ErrFunc oldErr; pFile = NXI5assert (fileid); if (pFile->iCurrentG == 0) { return NX_ERROR; } else { - strcpy(sRes->iRef5,"/"); - NX5getgroupinfo(fileid, &u, group_name,class_name); - strcat(sRes->iRef5,group_name); - strcpy(sRes->iTag5,"/"); - strcat(sRes->iTag5, pFile->iCurrentLGG); - strcpy(sRes->iRefd,""); /* - TODO: once we have group attributes, this should be set to - the groups target attribute + this means: if the item is already linked: use the target attribute, else + the path to the current node */ - strcpy(sRes->targetPath, sRes->iTag5); + oldErr = NXMGetError(); + NXMSetError(NXpData, ignoreError); + datalen = 1024; + memset(sRes->targetPath,0,datalen*sizeof(char)); + if(NX5getattr(fileid,"target",sRes->targetPath,&datalen,&type) != NX_OK){ + buildCurrentPath(pFile,sRes->targetPath,1024); + } + NXMSetError(NXpData,oldErr); + sRes->linkType = 0; return NX_OK; } /* not reached */ @@ -2144,6 +2015,7 @@ void NX5assignFunctions(pNexusFunction fHandle) fHandle->nxputslab=NX5putslab; fHandle->nxgetdataID=NX5getdataID; fHandle->nxmakelink=NX5makelink; + fHandle->nxmakenamedlink=NX5makenamedlink; fHandle->nxgetdata=NX5getdata; fHandle->nxgetinfo=NX5getinfo; fHandle->nxgetnextentry=NX5getnextentry; diff --git a/napiconfig.h b/napiconfig.h new file mode 100755 index 00000000..5b238331 --- /dev/null +++ b/napiconfig.h @@ -0,0 +1,22 @@ +#ifndef NAPICONFIG_H +#define NAPICONFIG_H + +#include + +/* + * Type definitions + */ +#ifdef HAVE_STDINT_H +#include +#else +typedef signed char int8_t; +typedef short int int16_t; +typedef int int32_t; +typedef long int64_t; +typedef unsigned char uint8_t; +typedef unsigned short int uint16_t; +typedef unsigned int uint32_t; +typedef unsigned long uint64_t; + +#endif /* HAVE_STDINT_H */ +#endif /* NAPICONFIG_H */ diff --git a/napiu.c b/napiu.c index 635b0cd9..4cb02093 100644 --- a/napiu.c +++ b/napiu.c @@ -21,10 +21,10 @@ For further information, see - $Id: napiu.c,v 1.1 2005/10/05 07:20:18 koennecke Exp $ + $Id$ ----------------------------------------------------------------------------*/ -static const char* rscid = "$Id: napiu.c,v 1.1 2005/10/05 07:20:18 koennecke Exp $"; /* Revision interted by CVS */ +static const char* rscid = "$Id$"; /* Revision interted by CVS */ #include #include @@ -41,7 +41,7 @@ static const char* rscid = "$Id: napiu.c,v 1.1 2005/10/05 07:20:18 koennecke Exp } \ } - NXstatus CALLING_STYLE NXUwriteglobals(NXhandle file_id, const char* user, const char* affiliation, const char* address, const char* telephone_number, const char* fax_number, const char* email) + NXstatus NXUwriteglobals(NXhandle file_id, const char* user, const char* affiliation, const char* address, const char* telephone_number, const char* fax_number, const char* email) { DO_GLOBAL(user); DO_GLOBAL(affiliation); @@ -53,7 +53,7 @@ static const char* rscid = "$Id: napiu.c,v 1.1 2005/10/05 07:20:18 koennecke Exp } /* NXUwritegroup creates and leaves open a group */ - NXstatus CALLING_STYLE NXUwritegroup(NXhandle file_id, const char* group_name, const char* group_class) + NXstatus NXUwritegroup(NXhandle file_id, const char* group_name, const char* group_class) { int status; status = NXmakegroup(file_id, group_name, group_class); @@ -64,22 +64,22 @@ static const char* rscid = "$Id: napiu.c,v 1.1 2005/10/05 07:20:18 koennecke Exp return status; } - NXstatus CALLING_STYLE NXUwritedata(NXhandle file_id, const char* data_name, const void* data, int data_type, int rank, const int dim[], const char* units, const int start[], const int size[]) + NXstatus NXUwritedata(NXhandle file_id, const char* data_name, const void* data, int data_type, int rank, const int dim[], const char* units, const int start[], const int size[]) { return NX_OK; } - NXstatus CALLING_STYLE NXUreaddata(NXhandle file_id, const char* data_name, void* data, char* units, const int start[], const int size[]) + NXstatus NXUreaddata(NXhandle file_id, const char* data_name, void* data, char* units, const int start[], const int size[]) { return NX_OK; } - NXstatus CALLING_STYLE NXUwritehistogram(NXhandle file_id, const char* data_name, const void* data, const char* units) + NXstatus NXUwritehistogram(NXhandle file_id, const char* data_name, const void* data, const char* units) { return NX_OK; } - NXstatus CALLING_STYLE NXUreadhistogram(NXhandle file_id, const char* data_name, void* data, char* units) + NXstatus NXUreadhistogram(NXhandle file_id, const char* data_name, void* data, char* units) { return NX_OK; } @@ -88,7 +88,7 @@ static int NXcompress_type = 0; static int NXcompress_size = 0; /* NXUsetcompress sets the default compression type and minimum size */ - NXstatus CALLING_STYLE NXUsetcompress(NXhandle file_id, int comp_type, int comp_size) + NXstatus NXUsetcompress(NXhandle file_id, int comp_type, int comp_size) { int status; if (comp_type == NX_COMP_LZW || comp_type == NX_COMP_HUF || @@ -110,7 +110,7 @@ static int NXcompress_size = 0; } /* !NXUfindgroup finds if a NeXus group of the specified name exists */ - NXstatus CALLING_STYLE NXUfindgroup(NXhandle file_id, const char* group_name, char* group_class) + NXstatus NXUfindgroup(NXhandle file_id, const char* group_name, char* group_class) { int status, n; NXname vname, vclass; @@ -122,38 +122,38 @@ static int NXcompress_size = 0; return NX_OK; } - NXstatus CALLING_STYLE NXUfindclass(NXhandle file_id, const char* group_class, char* group_name, int find_index) + NXstatus NXUfindclass(NXhandle file_id, const char* group_class, char* group_name, int find_index) { return NX_OK; } /* NXUfinddata finds if a NeXus data item is in the current group */ - NXstatus CALLING_STYLE NXUfinddata(NXhandle file_id, const char* data_name) + NXstatus NXUfinddata(NXhandle file_id, const char* data_name) { return NX_OK; } - NXstatus CALLING_STYLE NXUfindattr(NXhandle file_id, const char* attr_name) + NXstatus NXUfindattr(NXhandle file_id, const char* attr_name) { return NX_OK; } - NXstatus CALLING_STYLE NXUfindsignal(NXhandle file_id, int signal, char* data_name, int* data_rank, int* data_type, int data_dimensions[]) + NXstatus NXUfindsignal(NXhandle file_id, int signal, char* data_name, int* data_rank, int* data_type, int data_dimensions[]) { return NX_OK; } - NXstatus CALLING_STYLE NXUfindaxis(NXhandle file_id, int axis, int primary, char* data_name, int* data_rank, int* data_type, int data_dimensions[]) + NXstatus NXUfindaxis(NXhandle file_id, int axis, int primary, char* data_name, int* data_rank, int* data_type, int data_dimensions[]) { return NX_OK; } - NXstatus CALLING_STYLE NXUfindlink(NXhandle file_id, NXlink* group_id, const char* group_class) + NXstatus NXUfindlink(NXhandle file_id, NXlink* group_id, const char* group_class) { return NX_OK; } - NXstatus CALLING_STYLE NXUresumelink(NXhandle file_id, NXlink group_id) + NXstatus NXUresumelink(NXhandle file_id, NXlink group_id) { return NX_OK; } diff --git a/napiu.h b/napiu.h index d57915b3..efc223f8 100644 --- a/napiu.h +++ b/napiu.h @@ -21,7 +21,7 @@ For further information, see - $Id: napiu.h,v 1.1 2005/10/05 07:20:18 koennecke Exp $ + $Id$ ----------------------------------------------------------------------------*/ @@ -34,35 +34,35 @@ extern "C" { #endif /* __cplusplus */ -NX_EXTERNAL NXstatus CALLING_STYLE NXUwriteglobals(NXhandle file_id, const char* user, const char* affiliation, const char* address, const char* phone, const char* fax, const char* email); +extern NXstatus NXUwriteglobals(NXhandle file_id, const char* user, const char* affiliation, const char* address, const char* phone, const char* fax, const char* email); -NX_EXTERNAL NXstatus CALLING_STYLE NXUwritegroup(NXhandle file_id, const char* group_name, const char* group_class); +extern NXstatus NXUwritegroup(NXhandle file_id, const char* group_name, const char* group_class); -NX_EXTERNAL NXstatus CALLING_STYLE NXUwritedata(NXhandle file_id, const char* data_name, const void* data, int data_type, int rank, const int dim[], const char* units, const int start[], const int size[]); +extern NXstatus NXUwritedata(NXhandle file_id, const char* data_name, const void* data, int data_type, int rank, const int dim[], const char* units, const int start[], const int size[]); -NX_EXTERNAL NXstatus CALLING_STYLE NXUreaddata(NXhandle file_id, const char* data_name, void* data, char* units, const int start[], const int size[]); +extern NXstatus NXUreaddata(NXhandle file_id, const char* data_name, void* data, char* units, const int start[], const int size[]); -NX_EXTERNAL NXstatus CALLING_STYLE NXUwritehistogram(NXhandle file_id, const char* data_name, const void* data, const char* units); +extern NXstatus NXUwritehistogram(NXhandle file_id, const char* data_name, const void* data, const char* units); -NX_EXTERNAL NXstatus CALLING_STYLE NXUreadhistogram(NXhandle file_id, const char* data_name, void* data, char* units); +extern NXstatus NXUreadhistogram(NXhandle file_id, const char* data_name, void* data, char* units); -NX_EXTERNAL NXstatus CALLING_STYLE NXUsetcompress(NXhandle file_id, int comp_type, int comp_size); +extern NXstatus NXUsetcompress(NXhandle file_id, int comp_type, int comp_size); -NX_EXTERNAL NXstatus CALLING_STYLE NXUfindgroup(NXhandle file_id, const char* group_name, char* group_class); +extern NXstatus NXUfindgroup(NXhandle file_id, const char* group_name, char* group_class); -NX_EXTERNAL NXstatus CALLING_STYLE NXUfindclass(NXhandle file_id, const char* group_class, char* group_name, int find_index); +extern NXstatus NXUfindclass(NXhandle file_id, const char* group_class, char* group_name, int find_index); -NX_EXTERNAL NXstatus CALLING_STYLE NXUfinddata(NXhandle file_id, const char* data_name); +extern NXstatus NXUfinddata(NXhandle file_id, const char* data_name); -NX_EXTERNAL NXstatus CALLING_STYLE NXUfindattr(NXhandle file_id, const char* attr_name); +extern NXstatus NXUfindattr(NXhandle file_id, const char* attr_name); -NX_EXTERNAL NXstatus CALLING_STYLE NXUfindsignal(NXhandle file_id, int signal, char* data_name, int* data_rank, int* data_type, int data_dimensions[]); +extern NXstatus NXUfindsignal(NXhandle file_id, int signal, char* data_name, int* data_rank, int* data_type, int data_dimensions[]); -NX_EXTERNAL NXstatus CALLING_STYLE NXUfindaxis(NXhandle file_id, int axis, int primary, char* data_name, int* data_rank, int* data_type, int data_dimensions[]); +extern NXstatus NXUfindaxis(NXhandle file_id, int axis, int primary, char* data_name, int* data_rank, int* data_type, int data_dimensions[]); -NX_EXTERNAL NXstatus CALLING_STYLE NXUfindlink(NXhandle file_id, NXlink* group_id, const char* group_class); +extern NXstatus NXUfindlink(NXhandle file_id, NXlink* group_id, const char* group_class); -NX_EXTERNAL NXstatus CALLING_STYLE NXUresumelink(NXhandle file_id, NXlink group_id); +extern NXstatus NXUresumelink(NXhandle file_id, NXlink group_id); #ifdef __cplusplus } diff --git a/network.c b/network.c index e04ca4cf..36915e99 100644 --- a/network.c +++ b/network.c @@ -39,6 +39,7 @@ ----------------------------------------------------------------------------*/ #include "fortify.h" #include "network.h" +#include #include #include #include @@ -64,10 +65,15 @@ struct timeval lastclose={-1,0}; */ #include "Scommon.h" extern void SICSLogWrite(char *pText, OutCode eCode); /* servlog.c */ + + void WriteToCommandLog(char *p, char *t); static void NetError(char *pText) { +/* SICSLogWrite(pText,eError); +*/ + WriteToCommandLog("NET>", pText); } /* ---------------------------- Local ------------------------------------ @@ -170,7 +176,8 @@ CreateSocketAdress( int iRet; fd_set lMask; struct timeval tmo = {1,0}; - unsigned int iLen, i; + int i; + socklen_t iLen; struct linger lili; assert(self != NULL); @@ -378,7 +385,7 @@ CreateSocketAdress( { int t; - unsigned int len; + socklen_t len; struct sockaddr_in sin; struct hostent *host; @@ -403,6 +410,7 @@ CreateSocketAdress( else { strncpy(pCompost,host->h_name,iBufLen); + pCompost[iBufLen-1]='\0'; } } return 1; @@ -410,11 +418,15 @@ CreateSocketAdress( /*--------------------------------------------------------------------------*/ int NETWrite(mkChannel *self, char *buffer, long lLen) { - int iRet; + long iRet; fd_set lMask; - struct timeval tmo ={0,1}; - - + struct timeval tmo; + char buf[256]; + time_t expire, delta; + char *pos; + long l; + int disconnected; + if(!VerifyChannel(self)) { return 0; @@ -428,48 +440,83 @@ CreateSocketAdress( * Check if the we can write to the socket first.... * Well, this how it should be. However, on linux I observe that * there is a problem with Java clients not reliably receiving data when - * this is active. + * this is active. */ -#ifndef CYGNUS - tmo.tv_usec = 10; - FD_ZERO(&lMask); - FD_SET(self->sockid,&lMask); if((self->sockid >= FD_SETSIZE) || (self->sockid < 0) ) - /* invalid descriptor */ { - return -1; /* eof */ + /* invalid descriptor */ + return 0; } - iRet = select( (self->sockid + 1),NULL, &lMask, NULL,&tmo); - if( iRet <= 0) - { - /* failure, or no data */ - return -1; - } - /* blocking on write */ - if(!FD_ISSET(self->sockid,&lMask)) - { - return -2; - } -#endif - +#ifdef DO_NOT_SELECT_BEFORE_SEND iRet = send(self->sockid,buffer,lLen,0); - if(iRet != lLen) - { - if(iRet < 0) - { - if (errno != EPIPE) { /* do not write "broken pipe" error */ - printf("System error: %s\n",strerror(errno)); - } - } else { - printf("Incomplete send: %d to %ld\n",iRet,lLen); - } + if (iRet != lLen) { + self->iType = 0; + if (iRet < 0) { + if (errno == EPIPE) { /* do not write "broken pipe" error */ return 0; - } - else - { - return 1; + } + snprintf(buf, sizeof buf, "NETWrite: send system error: %s (socket %d)", + strerror(errno), self->sockid); + } else { + snprintf(buf, sizeof buf, "NETWrite: only %ld of %ld bytes sent (socket %d)", + iRet, lLen, self->sockid); + } + NetError(buf); + return 0; + } else { + return 1; } - +#endif + pos = buffer; + l = lLen; + FD_ZERO(&lMask); + disconnected = 0; + +#define TIMEOUT 10 + expire = time(NULL) + TIMEOUT; + while (l > 0) { + delta = expire - time(NULL); + if (delta <= 0) break; + FD_SET(self->sockid,&lMask); + tmo.tv_usec = 0; + tmo.tv_sec = delta; + iRet = select( (self->sockid + 1),NULL, &lMask, NULL,&tmo); + if (iRet < 0) { + /* failure, or no data */ + self->iType = 0; + snprintf(buf, sizeof buf, + "NETWrite: failure on select before send: %s (socket %d)", + strerror(errno), self->sockid); + NetError(buf); + return 0; + } + if (!FD_ISSET(self->sockid,&lMask)) break; + + iRet = send(self->sockid,pos,l,0); + disconnected = (iRet == 0); + if (iRet < 0) { + self->iType = 0; + if (errno == EPIPE || errno == ECONNRESET) { /* do not write these errors */ + return 0; + } + snprintf(buf, sizeof buf, "NETWrite: send system error: %s (socket %d)", + strerror(errno), self->sockid); + NetError(buf); + return 0; + } + l -= iRet; + pos += iRet; + } + if (l > 0) { + self->iType = 0; + if (!disconnected) { /* do not write an error message on disconnect */ + snprintf(buf, sizeof buf, "NETWrite: timeout, only %ld of %ld bytes sent (socket %d) %ld.%6.6ld", + lLen - l, lLen, self->sockid, (long)tmo.tv_sec, (long)tmo.tv_usec); + NetError(buf); + } + return 0; + } + return 1; } /* -------------------------------------------------------------------------*/ long NETRead(mkChannel *self, char *buffer, long lLen, long timeout) @@ -855,7 +902,7 @@ int NETReconnect(mkChannel* self) long lMask = 0L; struct timeval tmo ={0,1}; long iRet; - unsigned int iLang; + socklen_t iLang; if(!VerifyChannel(self)) { diff --git a/nread.c b/nread.c index 8d917de7..4c337baf 100644 --- a/nread.c +++ b/nread.c @@ -126,8 +126,10 @@ extern int VerifyChannel(mkChannel *self); /* defined in network.c */ int NetReadRegister(pNetRead self, mkChannel *pSock, eNRType eType, SConnection *pCon) { - NetItem sItem; - + NetItem sItem, sEntry; + char buffer[80]; + int iRet; + assert(self); if(!VerifyChannel(pSock)) { @@ -142,6 +144,20 @@ extern int VerifyChannel(mkChannel *self); /* defined in network.c */ sItem.iReadable = 0; memset(sItem.pHold,0,511); + /* check if the entry is already there */ + iRet = LLDnodePtr2First(self->iList); + while(iRet != 0) + { + LLDnodeDataTo(self->iList,&sEntry); + if(sEntry.pSock->sockid == pSock->sockid) + { + snprintf(buffer, sizeof buffer, "NetReadRegister twice %d type %d", pSock->sockid, eType); + WriteToCommandLog("SYS>",buffer); + return 1; + } + iRet = LLDnodePtr2Next(self->iList); + } + LLDnodeAppendFrom(self->iList, &sItem); return 1; } @@ -265,7 +281,7 @@ extern int VerifyChannel(mkChannel *self); /* defined in network.c */ "ERROR: insufficient privilege to invoke Interrupt", eError); } - return 1; + return 0; } /* split into command lines @@ -704,6 +720,9 @@ extern int VerifyChannel(mkChannel *self); /* defined in network.c */ int conCount = 0; char num[50]; IPair *options = NULL; + char buffer[1024]; + int bufferLen; + static int bufferFull=0; self = (pNetRead)pData; assert(self); @@ -717,11 +736,13 @@ extern int VerifyChannel(mkChannel *self); /* defined in network.c */ { return 0; } - + /* build the select mask */ FD_ZERO(&lMask); iRet = LLDnodePtr2First(self->iList); iCount = 0; + buffer[0] = '\0'; + bufferLen = 0; while(iRet != 0) { LLDnodeDataTo(self->iList,&NItem); @@ -729,6 +750,15 @@ extern int VerifyChannel(mkChannel *self); /* defined in network.c */ { break; } + snprintf(num,sizeof num, "%d, type %d:", NItem.pSock->sockid, NItem.eType); + if (bufferLen + strlen(num) < sizeof buffer) { + strcpy(buffer + bufferLen, num); + bufferLen += strlen(num); + } else { + if (bufferFull == 0) { + bufferFull = 1; + } + } FD_SET(NItem.pSock->sockid,&lMask); if(NItem.pSock->sockid > iCount) { @@ -738,8 +768,14 @@ extern int VerifyChannel(mkChannel *self); /* defined in network.c */ iRet = LLDnodePtr2Next(self->iList); } - snprintf(num,50,"%d", conCount); + snprintf(num,sizeof num,"%d", conCount); IFSetOption(pSICSOptions,"ConnectionCount",num); + IFSetOption(pSICSOptions,"ConMask",buffer); + + if (bufferFull == 1) { + bufferFull = 2; + WriteToCommandLog("BUFFERFULL>",buffer); + } /* the select itself */ tmo.tv_usec = self->iReadTimeout; diff --git a/nserver.c b/nserver.c index 51c27bad..de27ba07 100644 --- a/nserver.c +++ b/nserver.c @@ -24,6 +24,7 @@ #include "network.h" #include "ifile.h" #include "status.h" +#include "statusfile.h" #include "devexec.h" #include "passwd.h" #include "lld.h" @@ -45,6 +46,8 @@ extern void StopExit(void); /* in SICSmain.c */ extern int openDevexecLog(); /* in devexec.c */ + + extern void NetWatchInit(void); /* in nwatch.c */ /* ========================= Less dreadful file statics =================== */ #define DEFAULTINIFILE "servo.tcl" @@ -110,6 +113,10 @@ assert(TaskerInit(&self->pTasker)); pSICSOptions = IFAddOption(pSICSOptions, "ConnectionCount","0"); + pSICSOptions = IFAddOption(pSICSOptions, "ConMask","0"); + + /* initialize the network watcher */ + NetWatchInit(); /* initialise the server from script */ if(file == NULL) @@ -267,6 +274,13 @@ /* install telnet port */ InstallTelnet(); + /* If the restore file has not been loaded, do so now */ + if(!hasRestored()) + { + strcpy(pBueffel,"restore"); + SCInvoke(self->dummyCon,self->pSics,pBueffel); + } + /* exit handlers need to be installed here */ atexit(StopExit); Fortify_CheckAllMemory(); @@ -551,4 +565,8 @@ TaskSignal(pTasker,SICSBROADCAST,pMessage); } - +/*-------------------------------------------------------------------------*/ + int ServerIsStarting(pServer self) + { + return self->pReader == NULL; + } diff --git a/nserver.h b/nserver.h index 2b9551ed..3c644041 100644 --- a/nserver.h +++ b/nserver.h @@ -50,4 +50,5 @@ int argc, char *argv[]); int SicsWait(long lTime); + int ServerIsStarting(pServer self); #endif diff --git a/nxconfig.h b/nxconfig.h index 2e5df705..b532efd6 100644 --- a/nxconfig.h +++ b/nxconfig.h @@ -14,16 +14,22 @@ #define HAVE_INTTYPES_H 1 /* Define to 1 if you have the `df' library (-ldf). */ -#define HAVE_LIBDF 1 +/* #undef HAVE_LIBDF */ + +/* Define to 1 if you have the `dl' library (-ldl). */ +#define HAVE_LIBDL 1 /* Define to 1 if you have the `hdf5' library (-lhdf5). */ -#define HAVE_LIBHDF5 1 +/* #undef HAVE_LIBHDF5 */ /* Define to 1 if you have the `jpeg' library (-ljpeg). */ #define HAVE_LIBJPEG 1 +/* Define to 1 if you have the `m' library (-lm). */ +#define HAVE_LIBM 1 + /* Define to 1 if you have the `mfhdf' library (-lmfhdf). */ -#define HAVE_LIBMFHDF 1 +/* #undef HAVE_LIBMFHDF */ /* Define to 1 if you have the `rpc' library (-lrpc). */ /* #undef HAVE_LIBRPC */ @@ -32,7 +38,7 @@ /* #undef HAVE_LIBSYSTEMSTUBS */ /* Define to 1 if you have the `sz' library (-lsz). */ -#define HAVE_LIBSZ 1 +/* #undef HAVE_LIBSZ */ /* Define to 1 if you have the `xml2' library (-lxml2). */ #define HAVE_LIBXML2 1 @@ -96,19 +102,25 @@ #define PACKAGE "nexus" /* Define to the address where bug reports for this package should be sent. */ -#define PACKAGE_BUGREPORT "nexus-developers@anl.gov" +#define PACKAGE_BUGREPORT "nexus-developers@nexusformat.org" /* Define to the full name of this package. */ #define PACKAGE_NAME "NeXus Library" /* Define to the full name and version of this package. */ -#define PACKAGE_STRING "NeXus Library 3.0.1" +#define PACKAGE_STRING "NeXus Library 4.1.0" /* Define to the one symbol short name of this package. */ #define PACKAGE_TARNAME "nexus" /* Define to the version of this package. */ -#define PACKAGE_VERSION "3.0.1" +#define PACKAGE_VERSION "4.1.0" + +/* Set to printf format for int64_t */ +#define PRINTF_INT64 "lld" + +/* Set to printf format for uint64_t */ +#define PRINTF_UINT64 "llu" /* Define to 1 if you have the ANSI C header files. */ #define STDC_HEADERS 1 @@ -120,7 +132,7 @@ /* #undef TM_IN_SYS_TIME */ /* Version number of package */ -#define VERSION "3.0.1" +#define VERSION "4.1.0" /* Define to empty if `const' does not conform to ANSI C. */ /* #undef const */ diff --git a/nxcopy.c b/nxcopy.c new file mode 100644 index 00000000..116b00b1 --- /dev/null +++ b/nxcopy.c @@ -0,0 +1,294 @@ +/** + * This defines a couple of Tcl functions which allow to copy data from the + * nxdataset's returned from the swig Tcl interface to NeXus files into + * SICS data structures. + * + * copyright: see file COPYRIGHT + * + * Mark Koennecke, October 2007 + */ +#include +#include "nxdataset.h" +#include "sicshipadaba.h" +#include "sicsdata.h" +#include "nxcopy.h" +#include "HistMem.h" +/*------------------------------------------------------------------------------- + * decode a SWIG style pointer into the real pointer value. + * Stolen from SWIG generated code. + --------------------------------------------------------------------------------*/ +static const char *SWIG_UnpackData(const char *c, void *ptr, size_t sz) { + register unsigned char *u = (unsigned char *) ptr; + register const unsigned char *eu = u + sz; + for (; u != eu; ++u) { + register char d = *(c++); + register unsigned char uu; + if ((d >= '0') && (d <= '9')) + uu = ((d - '0') << 4); + else if ((d >= 'a') && (d <= 'f')) + uu = ((d - ('a'-10)) << 4); + else + return (char *) 0; + d = *(c++); + if ((d >= '0') && (d <= '9')) + uu |= (d - '0'); + else if ((d >= 'a') && (d <= 'f')) + uu |= (d - ('a'-10)); + else + return (char *) 0; + *u = uu; + } + return c; +} +/*-------------------------------------------------------------------------------*/ +int isTypeAllowed(int type){ + switch(type){ + case NX_INT32: + case NX_UINT32: + case NX_FLOAT32: + return 1; + break; + default: + return 0; + break; + } +} +/*-------------------------------------------------------------------------------- + * copy an nxdataset to a sicsdata object + --------------------------------------------------------------------------------*/ +static int NXDataToSicsdata(ClientData clientData, Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[]){ + Tcl_Obj *resultPtr; + const char *text; + pNXDS data = NULL; + pSICSData sicsData; + int length, i; + + if(objc < 3) { + Tcl_WrongNumArgs(interp,objc,objv,"Usage: nxdatatosicsdata nxdata sicsdata"); + return TCL_ERROR; + } + resultPtr = Tcl_GetObjResult(interp); + + /* + * get nxdataset pointer + */ + text = Tcl_GetStringFromObj(objv[1],NULL); + if(strstr(text,"NULL") != NULL){ + Tcl_SetStringObj(resultPtr,"nxdata argument is NULL pointer",38); + return TCL_ERROR; + } + text++; + SWIG_UnpackData(text,&data,sizeof(void *)); + + if(data->magic != MAGIC){ + Tcl_SetStringObj(resultPtr,"nxdata argument is no valid nxdataset", + strlen("nxdata argument is no valid nxdataset")); + return TCL_ERROR; + } + length = getNXDatasetLength(data); + if(!isTypeAllowed(data->type)){ + Tcl_SetStringObj(resultPtr,"can only copy int and float types", + strlen("can only copy int and float types")); + return TCL_ERROR; + } + + /* + * locate sicsdata + */ + text = Tcl_GetStringFromObj(objv[2],NULL); + sicsData = (pSICSData)FindCommandData(pServ->pSics,(char *)text,"SICSData"); + if(sicsData == NULL){ + Tcl_SetStringObj(resultPtr,"sicsdata argument is no valid SICSData", + strlen("sicsdata argument is no valid SICSData")); + return TCL_ERROR; + } + + /* + * copy the data + */ + if(data->type == NX_FLOAT32){ + for(i = 0; i < length; i++){ + setSICSDataFloat(sicsData,i,data->u.fPtr[i]); + } + } else { + for(i = 0; i < length; i++){ + setSICSDataInt(sicsData,i,data->u.iPtr[i]); + } + } + + return TCL_OK; +} +/*--------------------------------------------------------------------------*/ +static hdbValue NXDatasetToHdbValue(pNXDS data){ + hdbValue val; + int length, i; + + length = getNXDatasetLength(data); + switch(getNXDatasetType(data)){ + case NX_INT32: + case NX_UINT32: + if(length == 1){ + val = MakeHdbInt(data->u.iPtr[0]); + } else { + val = MakeHdbIntArray(length,data->u.iPtr); + val.dataType = HIPINTVARAR; + } + break; + case NX_FLOAT32: + if(length == 1){ + val = MakeHdbFloat((double)data->u.fPtr[0]); + } else { + val = makeHdbValue(HIPFLOATAR,length); + for(i = 0; i < length; i++){ + val.v.floatArray[i] = (double)data->u.fPtr[i]; + } + val.dataType = HIPFLOATVARAR; + } + break; + case NX_FLOAT64: + if(length == 1){ + val = MakeHdbFloat(data->u.dPtr[0]); + } else { + val = MakeHdbFloatArray(length,data->u.dPtr); + } + break; + case NX_CHAR: + case NX_INT8: + case NX_UINT8: + val = MakeHdbText(data->u.cPtr); + break; + case NX_INT16: + case NX_UINT16: + if(length == 1){ + val = MakeHdbInt((int)data->u.sPtr[0]); + } else { + val = makeHdbValue(HIPINTAR,length); + for(i = 0; i < length; i++){ + val.v.intArray[i] = (int)data->u.sPtr[i]; + } + } + break; + } + return val; +} +/*--------------------------------------------------------------------------- + * copy the content of an nxdataset onto a Hipadaba node + *---------------------------------------------------------------------------*/ +static int NXDataToHdbNode(ClientData clientData, Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[]){ + pNXDS data = NULL; + Tcl_Obj *resultPtr; + int length, status; + const char *text; + pHdb node = NULL; + hdbValue val; + + if(objc < 3) { + Tcl_WrongNumArgs(interp,objc,objv,"Usage: nxdatatohdb nxdata path"); + return TCL_ERROR; + } + resultPtr = Tcl_GetObjResult(interp); + + /* + * get nxdataset pointer + */ + text = Tcl_GetStringFromObj(objv[1],NULL); + if(strstr(text,"NULL") != NULL){ + Tcl_SetStringObj(resultPtr,"nxdata argument is NULL pointer",38); + return TCL_ERROR; + } + text++; + SWIG_UnpackData(text,&data,sizeof(void *)); + + if(data->magic != MAGIC){ + Tcl_SetStringObj(resultPtr,"nxdata argument is no valid nxdataset", + strlen("nxdata argument is no valid nxdataset")); + return TCL_ERROR; + } + length = getNXDatasetLength(data); + + /* + * locate node + */ + text = Tcl_GetStringFromObj(objv[2],NULL); + node = GetHipadabaNode(GetHipadabaRoot(),(char *)text); + if(node == NULL){ + Tcl_SetStringObj(resultPtr,"path does not point to a valid node", + strlen("path does not point to a valid node")); + return TCL_ERROR; + } + + val = NXDatasetToHdbValue(data); + status = UpdateHipadabaPar(node,val,NULL); + if(status != 1){ + Tcl_SetStringObj(resultPtr,"data type mismatch", + strlen("data type mismatch")); + return TCL_ERROR; + } + return TCL_OK; +} +/*---------------------------------------------------------------------------*/ +static int NXDataToHM(ClientData clientData, Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[]){ + pNXDS data = NULL; + Tcl_Obj *resultPtr; + int length, status; + const char *text; + pHistMem pHM = NULL; + SConnection *pCon = NULL; + + if(objc < 3) { + Tcl_WrongNumArgs(interp,objc,objv,"Usage: nxdatatohdb nxdata path"); + return TCL_ERROR; + } + resultPtr = Tcl_GetObjResult(interp); + + /* + * get nxdataset pointer + */ + text = Tcl_GetStringFromObj(objv[1],NULL); + if(strstr(text,"NULL") != NULL){ + Tcl_SetStringObj(resultPtr,"nxdata argument is NULL pointer",38); + return TCL_ERROR; + } + text++; + SWIG_UnpackData(text,&data,sizeof(void *)); + + if(data->magic != MAGIC){ + Tcl_SetStringObj(resultPtr,"nxdata argument is no valid nxdataset", + strlen("nxdata argument is no valid nxdataset")); + return TCL_ERROR; + } + length = getNXDatasetLength(data); + + /* + * get HM + */ + text = Tcl_GetStringFromObj(objv[2],NULL); + pHM = (pHistMem)FindCommandData(pServ->pSics,(char *)text,"HistMem"); + if(pHM == NULL){ + Tcl_SetStringObj(resultPtr,"hm argument is not histogram memory", + strlen("hm argument is not histogram memory")); + return TCL_ERROR; + } + + if(getNXDatasetType(data) != NX_INT32 || GetHistLength(pHM) < length){ + Tcl_SetStringObj(resultPtr,"data to hm type or length mismatch", + strlen("data to hm type or length mismatch")); + return TCL_ERROR; + } + + pCon = SCCreateDummyConnection(pServ->pSics); + SetHistogram(pHM, pCon, 0,0,length, data->u.iPtr); + SCDeleteConnection(pCon); + + return TCL_OK; +} +/*---------------------------------------------------------------------------*/ +int NXcopy_Init(Tcl_Interp *pInter){ + Tcl_CreateObjCommand(pInter,"nxToSicsData",NXDataToSicsdata,NULL,NULL); + Tcl_CreateObjCommand(pInter,"nxToHdb",NXDataToHdbNode,NULL,NULL); + Tcl_CreateObjCommand(pInter,"nxToHM",NXDataToHM,NULL,NULL); + return 1; +} diff --git a/nxcopy.h b/nxcopy.h new file mode 100644 index 00000000..539fae36 --- /dev/null +++ b/nxcopy.h @@ -0,0 +1,16 @@ +/** + * This defines a couple of Tcl functions which allow to copy data from the + * nxdataset's returned from the swig Tcl interface to NeXus files into + * SICS data structures. + * + * copyright: see file COPYRIGHT + * + * Mark Koennecke, October 2007 + */ +#ifndef NXCOPY_H_ +#define NXCOPY_H_ +#include + +int NXcopy_Init(Tcl_Interp *pTcl); + +#endif /*NXCOPY_H_*/ diff --git a/nxdataset.c b/nxdataset.c index c64c1321..6d419196 100644 --- a/nxdataset.c +++ b/nxdataset.c @@ -7,6 +7,7 @@ Mark Koennecke, October 2002 */ #include +#include #include #include "nxdataset.h" @@ -19,6 +20,8 @@ static int getTypeSize(int typecode){ return 4; break; case NX_FLOAT64: + case NX_INT64: + case NX_UINT64: return 8; break; case NX_INT16: @@ -208,6 +211,10 @@ double getNXDatasetValueAt(pNXDS dataset, int address){ case NX_UINT32: value = (double)dataset->u.iPtr[address]; break; + case NX_INT64: + case NX_UINT64: + value = (double)dataset->u.lPtr[address]; + break; case NX_INT16: case NX_UINT16: value = (double)dataset->u.sPtr[address]; @@ -224,10 +231,10 @@ char *getNXDatasetText(pNXDS dataset){ int length, status = 1; if(dataset == NULL){ - status = 0; + return strdup("NULL"); } if(dataset->magic != MAGIC){ - status = 0; + return strdup("NULL"); } if(dataset->rank > 1){ status = 0; @@ -236,6 +243,8 @@ char *getNXDatasetText(pNXDS dataset){ dataset->type == NX_FLOAT64 || dataset->type == NX_INT32 || dataset->type == NX_UINT32 || + dataset->type == NX_INT64 || + dataset->type == NX_UINT64 || dataset->type == NX_INT16 || dataset->type == NX_UINT16 ) { status = 0; @@ -284,6 +293,10 @@ int putNXDatasetValueAt(pNXDS dataset, int address, double value){ case NX_UINT32: dataset->u.iPtr[address] = (int)value; break; + case NX_INT64: + case NX_UINT64: + dataset->u.lPtr[address] = (int64_t)value; + break; case NX_INT16: case NX_UINT16: dataset->u.sPtr[address] = (short int)value; @@ -294,6 +307,140 @@ int putNXDatasetValueAt(pNXDS dataset, int address, double value){ } return 1; } +/*---------------------------------------------------------------------- + This is working recursively through the dimensions. When at the last: + actual copying takes place. + -----------------------------------------------------------------------*/ +static void copyCutData(pNXDS source, pNXDS target, int sourceDim[], + int targetDim[], int start[], int end[], + int dim){ + int i, length; + double val; + targetDim[dim] = 0; + length = end[dim] - start[dim]; + if(dim == source->rank -1){ + for(i = 0; i < length; i++){ + sourceDim[dim] = start[dim] + i; + val = getNXDatasetValue(source,sourceDim); + targetDim[dim] = i; + putNXDatasetValue(target, targetDim, val); + } + } else { + for(i = 0; i < length; i++){ + sourceDim[dim] = start[dim] + i; + targetDim[dim] = i; + copyCutData(source,target, sourceDim, targetDim, start, end, dim+1); + } + } +} +/*-----------------------------------------------------------------------*/ +pNXDS cutNXDataset(pNXDS source, int start[], int end[]){ + pNXDS result = NULL; + int newDim[NX_MAXRANK], i; + int sourceDim[NX_MAXRANK], targetDim[NX_MAXRANK]; + for(i = 0; i < source->rank; i++){ + if(start[i] < 0 || end[i] > source->dim[i]){ + fprintf(stderr,"ERROR: invalid boundaries specified for cutting"); + return NULL; + } + newDim[i] = end[i] - start[i]; + if(newDim[i] <= 0){ + fprintf(stderr,"ERROR: invalid cut limits specified for cutting dataset"); + return NULL; + } + } + result = createNXDataset(source->rank, source->type, newDim); + if(result == NULL){ + fprintf(stderr,"ERROR: out of memory creating result dataset"); + return NULL; + } + + copyCutData(source, result, sourceDim, targetDim, start, end, 0); + return result; +} +/*---------------------------------------------------------------------- + This recurses through all dimesnions, thereby skipping the summed one. + At the end of the rescusion the actual summing is performed. + ----------------------------------------------------------------------*/ +static void sumData(pNXDS source, pNXDS target, int sourceDim[], + int targetDim[], int targetDimCount, int dimNo, + int start, int end, int currentDim){ + int i, length; + double val, sumVal; + + /* + when we have recursed through all dimensions + we actually do the sums... + */ + if(currentDim == source->rank){ + length = end - start; + sumVal = getNXDatasetValue(target, targetDim); + for(i = 0; i < length; i++){ + sourceDim[dimNo] = start + i; + val = getNXDatasetValue(source,sourceDim); + sumVal += val; + } + putNXDatasetValue(target, targetDim, sumVal); + } else { + /* + jump over the summed dimension while recursing + through the dimensions + */ + if(currentDim == dimNo){ + sumData(source,target,sourceDim, + targetDim,targetDimCount, + dimNo,start,end,currentDim+1); + } else { + /* + loop over all values of the non summed dimension + */ + for(i = 0; i < source->dim[currentDim]; i++){ + /* + the problem here is that we have to jump over the summed + dimension here. This why we have to maintain a separate + dimension count for the target array. Jumping is done + above. + */ + targetDim[targetDimCount] = i; + targetDimCount++; + + sourceDim[currentDim] = i; + sumData(source,target,sourceDim,targetDim,targetDimCount, + dimNo,start,end,currentDim+1); + targetDimCount--; + } + } + } +} +/*-----------------------------------------------------------------------*/ +pNXDS sumNXDataset(pNXDS source, int dimNo, int start, int end){ + int newDim[NX_MAXRANK], targetDim[NX_MAXRANK], sourceDim[NX_MAXRANK]; + pNXDS result = NULL; + int i, count; + + if(dimNo < 0 || dimNo > source->rank-1) { + fprintf(stderr,"ERROR: invalid dimension for summing requested"); + return NULL; + } + + /* + make result dataset with missing summed dimension + */ + for(i = 0, count = 0; i < source->rank; i++){ + if(i != dimNo){ + newDim[count] = source->dim[i]; + count++; + } + } + result = createNXDataset(source->rank-1, source->type, newDim); + if(result == NULL){ + fprintf(stderr,"ERROR: out of memory creating result dataset"); + return NULL; + } + sumData(source,result,sourceDim,targetDim,0, + dimNo, start, end, 0); + return result; +} diff --git a/nxdataset.h b/nxdataset.h index c8613aa1..ab5d33a9 100644 --- a/nxdataset.h +++ b/nxdataset.h @@ -12,6 +12,8 @@ #define MAGIC 7776622 +#include "napiconfig.h" + typedef struct { int magic; int rank; @@ -25,6 +27,7 @@ typedef struct { int *iPtr; short int *sPtr; char *cPtr; + int64_t *lPtr; } u; }*pNXDS, NXDS; @@ -41,6 +44,8 @@ typedef struct { #define NX_UINT16 23 #define NX_INT32 24 #define NX_UINT32 25 +#define NX_INT64 26 +#define NX_UINT64 27 #define NX_CHAR 4 #define NX_MAXRANK 32 @@ -66,4 +71,7 @@ char *getNXDatasetText(pNXDS dataset); int putNXDatasetValue(pNXDS dataset, int pos[], double value); int putNXDatasetValueAt(pNXDS dataset, int address, double value); +pNXDS cutNXDataset(pNXDS source, int start[], int end[]); +pNXDS sumNXDataset(pNXDS source, int dimNo, int start, int end); + #endif diff --git a/nxinter_wrap.c b/nxinter_wrap.c new file mode 100644 index 00000000..a2dda998 --- /dev/null +++ b/nxinter_wrap.c @@ -0,0 +1,3516 @@ +/* ---------------------------------------------------------------------------- + * This file was automatically generated by SWIG (http://www.swig.org). + * Version 1.3.31 + * + * This file is not intended to be easily readable and contains a number of + * coding conventions designed to improve portability and efficiency. Do not make + * changes to this file unless you know what you are doing--modify the SWIG + * interface file instead. + * ----------------------------------------------------------------------------- */ + +/* ----------------------------------------------------------------------------- + * This section contains generic SWIG labels for method/variable + * declarations/attributes, and other compiler dependent labels. + * ----------------------------------------------------------------------------- */ + +/* template workaround for compilers that cannot correctly implement the C++ standard */ +#ifndef SWIGTEMPLATEDISAMBIGUATOR +# if defined(__SUNPRO_CC) +# if (__SUNPRO_CC <= 0x560) +# define SWIGTEMPLATEDISAMBIGUATOR template +# else +# define SWIGTEMPLATEDISAMBIGUATOR +# endif +# else +# define SWIGTEMPLATEDISAMBIGUATOR +# endif +#endif + +/* inline attribute */ +#ifndef SWIGINLINE +# if defined(__cplusplus) || (defined(__GNUC__) && !defined(__STRICT_ANSI__)) +# define SWIGINLINE inline +# else +# define SWIGINLINE +# endif +#endif + +/* attribute recognised by some compilers to avoid 'unused' warnings */ +#ifndef SWIGUNUSED +# if defined(__GNUC__) +# if !(defined(__cplusplus)) || (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) +# define SWIGUNUSED __attribute__ ((__unused__)) +# else +# define SWIGUNUSED +# endif +# elif defined(__ICC) +# define SWIGUNUSED __attribute__ ((__unused__)) +# else +# define SWIGUNUSED +# endif +#endif + +#ifndef SWIGUNUSEDPARM +# ifdef __cplusplus +# define SWIGUNUSEDPARM(p) +# else +# define SWIGUNUSEDPARM(p) p SWIGUNUSED +# endif +#endif + +/* internal SWIG method */ +#ifndef SWIGINTERN +# define SWIGINTERN static SWIGUNUSED +#endif + +/* internal inline SWIG method */ +#ifndef SWIGINTERNINLINE +# define SWIGINTERNINLINE SWIGINTERN SWIGINLINE +#endif + +/* exporting methods */ +#if (__GNUC__ >= 4) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) +# ifndef GCC_HASCLASSVISIBILITY +# define GCC_HASCLASSVISIBILITY +# endif +#endif + +#ifndef SWIGEXPORT +# if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) +# if defined(STATIC_LINKED) +# define SWIGEXPORT +# else +# define SWIGEXPORT __declspec(dllexport) +# endif +# else +# if defined(__GNUC__) && defined(GCC_HASCLASSVISIBILITY) +# define SWIGEXPORT __attribute__ ((visibility("default"))) +# else +# define SWIGEXPORT +# endif +# endif +#endif + +/* calling conventions for Windows */ +#ifndef SWIGSTDCALL +# if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) +# define SWIGSTDCALL __stdcall +# else +# define SWIGSTDCALL +# endif +#endif + +/* Deal with Microsoft's attempt at deprecating C standard runtime functions */ +#if !defined(SWIG_NO_CRT_SECURE_NO_DEPRECATE) && defined(_MSC_VER) && !defined(_CRT_SECURE_NO_DEPRECATE) +# define _CRT_SECURE_NO_DEPRECATE +#endif + + +#include +#include +#include +#include +#include +#include + +/* ----------------------------------------------------------------------------- + * swigrun.swg + * + * This file contains generic CAPI SWIG runtime support for pointer + * type checking. + * ----------------------------------------------------------------------------- */ + +/* This should only be incremented when either the layout of swig_type_info changes, + or for whatever reason, the runtime changes incompatibly */ +#define SWIG_RUNTIME_VERSION "3" + +/* define SWIG_TYPE_TABLE_NAME as "SWIG_TYPE_TABLE" */ +#ifdef SWIG_TYPE_TABLE +# define SWIG_QUOTE_STRING(x) #x +# define SWIG_EXPAND_AND_QUOTE_STRING(x) SWIG_QUOTE_STRING(x) +# define SWIG_TYPE_TABLE_NAME SWIG_EXPAND_AND_QUOTE_STRING(SWIG_TYPE_TABLE) +#else +# define SWIG_TYPE_TABLE_NAME +#endif + +/* + You can use the SWIGRUNTIME and SWIGRUNTIMEINLINE macros for + creating a static or dynamic library from the swig runtime code. + In 99.9% of the cases, swig just needs to declare them as 'static'. + + But only do this if is strictly necessary, ie, if you have problems + with your compiler or so. +*/ + +#ifndef SWIGRUNTIME +# define SWIGRUNTIME SWIGINTERN +#endif + +#ifndef SWIGRUNTIMEINLINE +# define SWIGRUNTIMEINLINE SWIGRUNTIME SWIGINLINE +#endif + +/* Generic buffer size */ +#ifndef SWIG_BUFFER_SIZE +# define SWIG_BUFFER_SIZE 1024 +#endif + +/* Flags for pointer conversions */ +#define SWIG_POINTER_DISOWN 0x1 + +/* Flags for new pointer objects */ +#define SWIG_POINTER_OWN 0x1 + + +/* + Flags/methods for returning states. + + The swig conversion methods, as ConvertPtr, return and integer + that tells if the conversion was successful or not. And if not, + an error code can be returned (see swigerrors.swg for the codes). + + Use the following macros/flags to set or process the returning + states. + + In old swig versions, you usually write code as: + + if (SWIG_ConvertPtr(obj,vptr,ty.flags) != -1) { + // success code + } else { + //fail code + } + + Now you can be more explicit as: + + int res = SWIG_ConvertPtr(obj,vptr,ty.flags); + if (SWIG_IsOK(res)) { + // success code + } else { + // fail code + } + + that seems to be the same, but now you can also do + + Type *ptr; + int res = SWIG_ConvertPtr(obj,(void **)(&ptr),ty.flags); + if (SWIG_IsOK(res)) { + // success code + if (SWIG_IsNewObj(res) { + ... + delete *ptr; + } else { + ... + } + } else { + // fail code + } + + I.e., now SWIG_ConvertPtr can return new objects and you can + identify the case and take care of the deallocation. Of course that + requires also to SWIG_ConvertPtr to return new result values, as + + int SWIG_ConvertPtr(obj, ptr,...) { + if () { + if () { + *ptr = ; + return SWIG_NEWOBJ; + } else { + *ptr = ; + return SWIG_OLDOBJ; + } + } else { + return SWIG_BADOBJ; + } + } + + Of course, returning the plain '0(success)/-1(fail)' still works, but you can be + more explicit by returning SWIG_BADOBJ, SWIG_ERROR or any of the + swig errors code. + + Finally, if the SWIG_CASTRANK_MODE is enabled, the result code + allows to return the 'cast rank', for example, if you have this + + int food(double) + int fooi(int); + + and you call + + food(1) // cast rank '1' (1 -> 1.0) + fooi(1) // cast rank '0' + + just use the SWIG_AddCast()/SWIG_CheckState() + + + */ +#define SWIG_OK (0) +#define SWIG_ERROR (-1) +#define SWIG_IsOK(r) (r >= 0) +#define SWIG_ArgError(r) ((r != SWIG_ERROR) ? r : SWIG_TypeError) + +/* The CastRankLimit says how many bits are used for the cast rank */ +#define SWIG_CASTRANKLIMIT (1 << 8) +/* The NewMask denotes the object was created (using new/malloc) */ +#define SWIG_NEWOBJMASK (SWIG_CASTRANKLIMIT << 1) +/* The TmpMask is for in/out typemaps that use temporal objects */ +#define SWIG_TMPOBJMASK (SWIG_NEWOBJMASK << 1) +/* Simple returning values */ +#define SWIG_BADOBJ (SWIG_ERROR) +#define SWIG_OLDOBJ (SWIG_OK) +#define SWIG_NEWOBJ (SWIG_OK | SWIG_NEWOBJMASK) +#define SWIG_TMPOBJ (SWIG_OK | SWIG_TMPOBJMASK) +/* Check, add and del mask methods */ +#define SWIG_AddNewMask(r) (SWIG_IsOK(r) ? (r | SWIG_NEWOBJMASK) : r) +#define SWIG_DelNewMask(r) (SWIG_IsOK(r) ? (r & ~SWIG_NEWOBJMASK) : r) +#define SWIG_IsNewObj(r) (SWIG_IsOK(r) && (r & SWIG_NEWOBJMASK)) +#define SWIG_AddTmpMask(r) (SWIG_IsOK(r) ? (r | SWIG_TMPOBJMASK) : r) +#define SWIG_DelTmpMask(r) (SWIG_IsOK(r) ? (r & ~SWIG_TMPOBJMASK) : r) +#define SWIG_IsTmpObj(r) (SWIG_IsOK(r) && (r & SWIG_TMPOBJMASK)) + + +/* Cast-Rank Mode */ +#if defined(SWIG_CASTRANK_MODE) +# ifndef SWIG_TypeRank +# define SWIG_TypeRank unsigned long +# endif +# ifndef SWIG_MAXCASTRANK /* Default cast allowed */ +# define SWIG_MAXCASTRANK (2) +# endif +# define SWIG_CASTRANKMASK ((SWIG_CASTRANKLIMIT) -1) +# define SWIG_CastRank(r) (r & SWIG_CASTRANKMASK) +SWIGINTERNINLINE int SWIG_AddCast(int r) { + return SWIG_IsOK(r) ? ((SWIG_CastRank(r) < SWIG_MAXCASTRANK) ? (r + 1) : SWIG_ERROR) : r; +} +SWIGINTERNINLINE int SWIG_CheckState(int r) { + return SWIG_IsOK(r) ? SWIG_CastRank(r) + 1 : 0; +} +#else /* no cast-rank mode */ +# define SWIG_AddCast +# define SWIG_CheckState(r) (SWIG_IsOK(r) ? 1 : 0) +#endif + + + + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void *(*swig_converter_func)(void *); +typedef struct swig_type_info *(*swig_dycast_func)(void **); + +/* Structure to store inforomation on one type */ +typedef struct swig_type_info { + const char *name; /* mangled name of this type */ + const char *str; /* human readable name of this type */ + swig_dycast_func dcast; /* dynamic cast function down a hierarchy */ + struct swig_cast_info *cast; /* linked list of types that can cast into this type */ + void *clientdata; /* language specific type data */ + int owndata; /* flag if the structure owns the clientdata */ +} swig_type_info; + +/* Structure to store a type and conversion function used for casting */ +typedef struct swig_cast_info { + swig_type_info *type; /* pointer to type that is equivalent to this type */ + swig_converter_func converter; /* function to cast the void pointers */ + struct swig_cast_info *next; /* pointer to next cast in linked list */ + struct swig_cast_info *prev; /* pointer to the previous cast */ +} swig_cast_info; + +/* Structure used to store module information + * Each module generates one structure like this, and the runtime collects + * all of these structures and stores them in a circularly linked list.*/ +typedef struct swig_module_info { + swig_type_info **types; /* Array of pointers to swig_type_info structures that are in this module */ + size_t size; /* Number of types in this module */ + struct swig_module_info *next; /* Pointer to next element in circularly linked list */ + swig_type_info **type_initial; /* Array of initially generated type structures */ + swig_cast_info **cast_initial; /* Array of initially generated casting structures */ + void *clientdata; /* Language specific module data */ +} swig_module_info; + +/* + Compare two type names skipping the space characters, therefore + "char*" == "char *" and "Class" == "Class", etc. + + Return 0 when the two name types are equivalent, as in + strncmp, but skipping ' '. +*/ +SWIGRUNTIME int +SWIG_TypeNameComp(const char *f1, const char *l1, + const char *f2, const char *l2) { + for (;(f1 != l1) && (f2 != l2); ++f1, ++f2) { + while ((*f1 == ' ') && (f1 != l1)) ++f1; + while ((*f2 == ' ') && (f2 != l2)) ++f2; + if (*f1 != *f2) return (*f1 > *f2) ? 1 : -1; + } + return (l1 - f1) - (l2 - f2); +} + +/* + Check type equivalence in a name list like ||... + Return 0 if not equal, 1 if equal +*/ +SWIGRUNTIME int +SWIG_TypeEquiv(const char *nb, const char *tb) { + int equiv = 0; + const char* te = tb + strlen(tb); + const char* ne = nb; + while (!equiv && *ne) { + for (nb = ne; *ne; ++ne) { + if (*ne == '|') break; + } + equiv = (SWIG_TypeNameComp(nb, ne, tb, te) == 0) ? 1 : 0; + if (*ne) ++ne; + } + return equiv; +} + +/* + Check type equivalence in a name list like ||... + Return 0 if equal, -1 if nb < tb, 1 if nb > tb +*/ +SWIGRUNTIME int +SWIG_TypeCompare(const char *nb, const char *tb) { + int equiv = 0; + const char* te = tb + strlen(tb); + const char* ne = nb; + while (!equiv && *ne) { + for (nb = ne; *ne; ++ne) { + if (*ne == '|') break; + } + equiv = (SWIG_TypeNameComp(nb, ne, tb, te) == 0) ? 1 : 0; + if (*ne) ++ne; + } + return equiv; +} + + +/* think of this as a c++ template<> or a scheme macro */ +#define SWIG_TypeCheck_Template(comparison, ty) \ + if (ty) { \ + swig_cast_info *iter = ty->cast; \ + while (iter) { \ + if (comparison) { \ + if (iter == ty->cast) return iter; \ + /* Move iter to the top of the linked list */ \ + iter->prev->next = iter->next; \ + if (iter->next) \ + iter->next->prev = iter->prev; \ + iter->next = ty->cast; \ + iter->prev = 0; \ + if (ty->cast) ty->cast->prev = iter; \ + ty->cast = iter; \ + return iter; \ + } \ + iter = iter->next; \ + } \ + } \ + return 0 + +/* + Check the typename +*/ +SWIGRUNTIME swig_cast_info * +SWIG_TypeCheck(const char *c, swig_type_info *ty) { + SWIG_TypeCheck_Template(strcmp(iter->type->name, c) == 0, ty); +} + +/* Same as previous function, except strcmp is replaced with a pointer comparison */ +SWIGRUNTIME swig_cast_info * +SWIG_TypeCheckStruct(swig_type_info *from, swig_type_info *into) { + SWIG_TypeCheck_Template(iter->type == from, into); +} + +/* + Cast a pointer up an inheritance hierarchy +*/ +SWIGRUNTIMEINLINE void * +SWIG_TypeCast(swig_cast_info *ty, void *ptr) { + return ((!ty) || (!ty->converter)) ? ptr : (*ty->converter)(ptr); +} + +/* + Dynamic pointer casting. Down an inheritance hierarchy +*/ +SWIGRUNTIME swig_type_info * +SWIG_TypeDynamicCast(swig_type_info *ty, void **ptr) { + swig_type_info *lastty = ty; + if (!ty || !ty->dcast) return ty; + while (ty && (ty->dcast)) { + ty = (*ty->dcast)(ptr); + if (ty) lastty = ty; + } + return lastty; +} + +/* + Return the name associated with this type +*/ +SWIGRUNTIMEINLINE const char * +SWIG_TypeName(const swig_type_info *ty) { + return ty->name; +} + +/* + Return the pretty name associated with this type, + that is an unmangled type name in a form presentable to the user. +*/ +SWIGRUNTIME const char * +SWIG_TypePrettyName(const swig_type_info *type) { + /* The "str" field contains the equivalent pretty names of the + type, separated by vertical-bar characters. We choose + to print the last name, as it is often (?) the most + specific. */ + if (!type) return NULL; + if (type->str != NULL) { + const char *last_name = type->str; + const char *s; + for (s = type->str; *s; s++) + if (*s == '|') last_name = s+1; + return last_name; + } + else + return type->name; +} + +/* + Set the clientdata field for a type +*/ +SWIGRUNTIME void +SWIG_TypeClientData(swig_type_info *ti, void *clientdata) { + swig_cast_info *cast = ti->cast; + /* if (ti->clientdata == clientdata) return; */ + ti->clientdata = clientdata; + + while (cast) { + if (!cast->converter) { + swig_type_info *tc = cast->type; + if (!tc->clientdata) { + SWIG_TypeClientData(tc, clientdata); + } + } + cast = cast->next; + } +} +SWIGRUNTIME void +SWIG_TypeNewClientData(swig_type_info *ti, void *clientdata) { + SWIG_TypeClientData(ti, clientdata); + ti->owndata = 1; +} + +/* + Search for a swig_type_info structure only by mangled name + Search is a O(log #types) + + We start searching at module start, and finish searching when start == end. + Note: if start == end at the beginning of the function, we go all the way around + the circular list. +*/ +SWIGRUNTIME swig_type_info * +SWIG_MangledTypeQueryModule(swig_module_info *start, + swig_module_info *end, + const char *name) { + swig_module_info *iter = start; + do { + if (iter->size) { + register size_t l = 0; + register size_t r = iter->size - 1; + do { + /* since l+r >= 0, we can (>> 1) instead (/ 2) */ + register size_t i = (l + r) >> 1; + const char *iname = iter->types[i]->name; + if (iname) { + register int compare = strcmp(name, iname); + if (compare == 0) { + return iter->types[i]; + } else if (compare < 0) { + if (i) { + r = i - 1; + } else { + break; + } + } else if (compare > 0) { + l = i + 1; + } + } else { + break; /* should never happen */ + } + } while (l <= r); + } + iter = iter->next; + } while (iter != end); + return 0; +} + +/* + Search for a swig_type_info structure for either a mangled name or a human readable name. + It first searches the mangled names of the types, which is a O(log #types) + If a type is not found it then searches the human readable names, which is O(#types). + + We start searching at module start, and finish searching when start == end. + Note: if start == end at the beginning of the function, we go all the way around + the circular list. +*/ +SWIGRUNTIME swig_type_info * +SWIG_TypeQueryModule(swig_module_info *start, + swig_module_info *end, + const char *name) { + /* STEP 1: Search the name field using binary search */ + swig_type_info *ret = SWIG_MangledTypeQueryModule(start, end, name); + if (ret) { + return ret; + } else { + /* STEP 2: If the type hasn't been found, do a complete search + of the str field (the human readable name) */ + swig_module_info *iter = start; + do { + register size_t i = 0; + for (; i < iter->size; ++i) { + if (iter->types[i]->str && (SWIG_TypeEquiv(iter->types[i]->str, name))) + return iter->types[i]; + } + iter = iter->next; + } while (iter != end); + } + + /* neither found a match */ + return 0; +} + +/* + Pack binary data into a string +*/ +SWIGRUNTIME char * +SWIG_PackData(char *c, void *ptr, size_t sz) { + static const char hex[17] = "0123456789abcdef"; + register const unsigned char *u = (unsigned char *) ptr; + register const unsigned char *eu = u + sz; + for (; u != eu; ++u) { + register unsigned char uu = *u; + *(c++) = hex[(uu & 0xf0) >> 4]; + *(c++) = hex[uu & 0xf]; + } + return c; +} + +/* + Unpack binary data from a string +*/ +SWIGRUNTIME const char * +SWIG_UnpackData(const char *c, void *ptr, size_t sz) { + register unsigned char *u = (unsigned char *) ptr; + register const unsigned char *eu = u + sz; + for (; u != eu; ++u) { + register char d = *(c++); + register unsigned char uu; + if ((d >= '0') && (d <= '9')) + uu = ((d - '0') << 4); + else if ((d >= 'a') && (d <= 'f')) + uu = ((d - ('a'-10)) << 4); + else + return (char *) 0; + d = *(c++); + if ((d >= '0') && (d <= '9')) + uu |= (d - '0'); + else if ((d >= 'a') && (d <= 'f')) + uu |= (d - ('a'-10)); + else + return (char *) 0; + *u = uu; + } + return c; +} + +/* + Pack 'void *' into a string buffer. +*/ +SWIGRUNTIME char * +SWIG_PackVoidPtr(char *buff, void *ptr, const char *name, size_t bsz) { + char *r = buff; + if ((2*sizeof(void *) + 2) > bsz) return 0; + *(r++) = '_'; + r = SWIG_PackData(r,&ptr,sizeof(void *)); + if (strlen(name) + 1 > (bsz - (r - buff))) return 0; + strcpy(r,name); + return buff; +} + +SWIGRUNTIME const char * +SWIG_UnpackVoidPtr(const char *c, void **ptr, const char *name) { + if (*c != '_') { + if (strcmp(c,"NULL") == 0) { + *ptr = (void *) 0; + return name; + } else { + return 0; + } + } + return SWIG_UnpackData(++c,ptr,sizeof(void *)); +} + +SWIGRUNTIME char * +SWIG_PackDataName(char *buff, void *ptr, size_t sz, const char *name, size_t bsz) { + char *r = buff; + size_t lname = (name ? strlen(name) : 0); + if ((2*sz + 2 + lname) > bsz) return 0; + *(r++) = '_'; + r = SWIG_PackData(r,ptr,sz); + if (lname) { + strncpy(r,name,lname+1); + } else { + *r = 0; + } + return buff; +} + +SWIGRUNTIME const char * +SWIG_UnpackDataName(const char *c, void *ptr, size_t sz, const char *name) { + if (*c != '_') { + if (strcmp(c,"NULL") == 0) { + memset(ptr,0,sz); + return name; + } else { + return 0; + } + } + return SWIG_UnpackData(++c,ptr,sz); +} + +#ifdef __cplusplus +} +#endif + +/* Errors in SWIG */ +#define SWIG_UnknownError -1 +#define SWIG_IOError -2 +#define SWIG_RuntimeError -3 +#define SWIG_IndexError -4 +#define SWIG_TypeError -5 +#define SWIG_DivisionByZero -6 +#define SWIG_OverflowError -7 +#define SWIG_SyntaxError -8 +#define SWIG_ValueError -9 +#define SWIG_SystemError -10 +#define SWIG_AttributeError -11 +#define SWIG_MemoryError -12 +#define SWIG_NullReferenceError -13 + + + +/* ----------------------------------------------------------------------------- + * error manipulation + * ----------------------------------------------------------------------------- */ + +SWIGINTERN const char* +SWIG_Tcl_ErrorType(int code) { + const char* type = 0; + switch(code) { + case SWIG_MemoryError: + type = "MemoryError"; + break; + case SWIG_IOError: + type = "IOError"; + break; + case SWIG_RuntimeError: + type = "RuntimeError"; + break; + case SWIG_IndexError: + type = "IndexError"; + break; + case SWIG_TypeError: + type = "TypeError"; + break; + case SWIG_DivisionByZero: + type = "ZeroDivisionError"; + break; + case SWIG_OverflowError: + type = "OverflowError"; + break; + case SWIG_SyntaxError: + type = "SyntaxError"; + break; + case SWIG_ValueError: + type = "ValueError"; + break; + case SWIG_SystemError: + type = "SystemError"; + break; + case SWIG_AttributeError: + type = "AttributeError"; + break; + default: + type = "RuntimeError"; + } + return type; +} + + +SWIGINTERN void +SWIG_Tcl_SetErrorObj(Tcl_Interp *interp, const char *ctype, Tcl_Obj *obj) +{ + Tcl_ResetResult(interp); + Tcl_SetObjResult(interp, obj); + Tcl_SetErrorCode(interp, "SWIG", ctype, NULL); +} + +SWIGINTERN void +SWIG_Tcl_SetErrorMsg(Tcl_Interp *interp, const char *ctype, const char *mesg) +{ + Tcl_ResetResult(interp); + Tcl_SetErrorCode(interp, "SWIG", ctype, NULL); + Tcl_AppendResult(interp, ctype, " ", mesg, NULL); + /* + Tcl_AddErrorInfo(interp, ctype); + Tcl_AddErrorInfo(interp, " "); + Tcl_AddErrorInfo(interp, mesg); + */ +} + +SWIGINTERNINLINE void +SWIG_Tcl_AddErrorMsg(Tcl_Interp *interp, const char* mesg) +{ + Tcl_AddErrorInfo(interp, mesg); +} + + + +/* ----------------------------------------------------------------------------- + * SWIG API. Portion that goes into the runtime + * ----------------------------------------------------------------------------- */ +#ifdef __cplusplus +extern "C" { +#endif + +/* ----------------------------------------------------------------------------- + * Constant declarations + * ----------------------------------------------------------------------------- */ + +/* Constant Types */ +#define SWIG_TCL_POINTER 4 +#define SWIG_TCL_BINARY 5 + +/* Constant information structure */ +typedef struct swig_const_info { + int type; + char *name; + long lvalue; + double dvalue; + void *pvalue; + swig_type_info **ptype; +} swig_const_info; + +typedef int (*swig_wrapper)(ClientData, Tcl_Interp *, int, Tcl_Obj *CONST []); +typedef int (*swig_wrapper_func)(ClientData, Tcl_Interp *, int, Tcl_Obj *CONST []); +typedef char *(*swig_variable_func)(ClientData, Tcl_Interp *, char *, char *, int); +typedef void (*swig_delete_func)(ClientData); + +typedef struct swig_method { + const char *name; + swig_wrapper method; +} swig_method; + +typedef struct swig_attribute { + const char *name; + swig_wrapper getmethod; + swig_wrapper setmethod; +} swig_attribute; + +typedef struct swig_class { + const char *name; + swig_type_info **type; + swig_wrapper constructor; + void (*destructor)(void *); + swig_method *methods; + swig_attribute *attributes; + struct swig_class **bases; + char **base_names; + swig_module_info *module; +} swig_class; + +typedef struct swig_instance { + Tcl_Obj *thisptr; + void *thisvalue; + swig_class *classptr; + int destroy; + Tcl_Command cmdtok; +} swig_instance; + +/* Structure for command table */ +typedef struct { + const char *name; + int (*wrapper)(ClientData, Tcl_Interp *, int, Tcl_Obj *CONST []); + ClientData clientdata; +} swig_command_info; + +/* Structure for variable linking table */ +typedef struct { + const char *name; + void *addr; + char * (*get)(ClientData, Tcl_Interp *, char *, char *, int); + char * (*set)(ClientData, Tcl_Interp *, char *, char *, int); +} swig_var_info; + + +/* -----------------------------------------------------------------------------* + * Install a constant object + * -----------------------------------------------------------------------------*/ + +static Tcl_HashTable swigconstTable; +static int swigconstTableinit = 0; + +SWIGINTERN void +SWIG_Tcl_SetConstantObj(Tcl_Interp *interp, const char* name, Tcl_Obj *obj) { + int newobj; + Tcl_ObjSetVar2(interp,Tcl_NewStringObj(name,-1), NULL, obj, TCL_GLOBAL_ONLY); + Tcl_SetHashValue(Tcl_CreateHashEntry(&swigconstTable, name, &newobj), (ClientData) obj); +} + +SWIGINTERN Tcl_Obj * +SWIG_Tcl_GetConstantObj(const char *key) { + Tcl_HashEntry *entryPtr; + if (!swigconstTableinit) return 0; + entryPtr = Tcl_FindHashEntry(&swigconstTable, key); + if (entryPtr) { + return (Tcl_Obj *) Tcl_GetHashValue(entryPtr); + } + return 0; +} + +#ifdef __cplusplus +} +#endif + + + +/* ----------------------------------------------------------------------------- + * See the LICENSE file for information on copyright, usage and redistribution + * of SWIG, and the README file for authors - http://www.swig.org/release.html. + * + * tclrun.swg + * + * This file contains the runtime support for Tcl modules and includes + * code for managing global variables and pointer type checking. + * ----------------------------------------------------------------------------- */ + +/* Common SWIG API */ + +/* for raw pointers */ +#define SWIG_ConvertPtr(oc, ptr, ty, flags) SWIG_Tcl_ConvertPtr(interp, oc, ptr, ty, flags) +#define SWIG_NewPointerObj(ptr, type, flags) SWIG_Tcl_NewPointerObj(ptr, type, flags) + +/* for raw packed data */ +#define SWIG_ConvertPacked(obj, ptr, sz, ty) SWIG_Tcl_ConvertPacked(interp, obj, ptr, sz, ty) +#define SWIG_NewPackedObj(ptr, sz, type) SWIG_Tcl_NewPackedObj(ptr, sz, type) + +/* for class or struct pointers */ +#define SWIG_ConvertInstance(obj, pptr, type, flags) SWIG_Tcl_ConvertPtr(interp, obj, pptr, type, flags) +#define SWIG_NewInstanceObj(thisvalue, type, flags) SWIG_Tcl_NewInstanceObj(interp, thisvalue, type, flags) + +/* for C or C++ function pointers */ +#define SWIG_ConvertFunctionPtr(obj, pptr, type) SWIG_Tcl_ConvertPtr(interp, obj, pptr, type, 0) +#define SWIG_NewFunctionPtrObj(ptr, type) SWIG_Tcl_NewPointerObj(ptr, type, 0) + +/* for C++ member pointers, ie, member methods */ +#define SWIG_ConvertMember(obj, ptr, sz, ty) SWIG_Tcl_ConvertPacked(interp,obj, ptr, sz, ty) +#define SWIG_NewMemberObj(ptr, sz, type) SWIG_Tcl_NewPackedObj(ptr, sz, type) + + +/* Runtime API */ + +#define SWIG_GetModule(clientdata) SWIG_Tcl_GetModule((Tcl_Interp *) (clientdata)) +#define SWIG_SetModule(clientdata, pointer) SWIG_Tcl_SetModule((Tcl_Interp *) (clientdata), pointer) + + +/* Error manipulation */ + +#define SWIG_ErrorType(code) SWIG_Tcl_ErrorType(code) +#define SWIG_Error(code, msg) SWIG_Tcl_SetErrorMsg(interp, SWIG_Tcl_ErrorType(code), msg) +#define SWIG_fail goto fail + + +/* Tcl-specific SWIG API */ + +#define SWIG_Acquire(ptr) SWIG_Tcl_Acquire(ptr) +#define SWIG_MethodCommand SWIG_Tcl_MethodCommand +#define SWIG_Disown(ptr) SWIG_Tcl_Disown(ptr) +#define SWIG_ConvertPtrFromString(c, ptr, ty, flags) SWIG_Tcl_ConvertPtrFromString(interp, c, ptr, ty, flags) +#define SWIG_MakePtr(c, ptr, ty, flags) SWIG_Tcl_MakePtr(c, ptr, ty, flags) +#define SWIG_PointerTypeFromString(c) SWIG_Tcl_PointerTypeFromString(c) +#define SWIG_GetArgs SWIG_Tcl_GetArgs +#define SWIG_GetConstantObj(key) SWIG_Tcl_GetConstantObj(key) +#define SWIG_ObjectConstructor SWIG_Tcl_ObjectConstructor +#define SWIG_Thisown(ptr) SWIG_Tcl_Thisown(ptr) +#define SWIG_ObjectDelete SWIG_Tcl_ObjectDelete + + +#define SWIG_TCL_DECL_ARGS_2(arg1, arg2) (Tcl_Interp *interp SWIGUNUSED, arg1, arg2) +#define SWIG_TCL_CALL_ARGS_2(arg1, arg2) (interp, arg1, arg2) +/* ----------------------------------------------------------------------------- + * pointers/data manipulation + * ----------------------------------------------------------------------------- */ + +/* For backward compatibility only */ +#define SWIG_POINTER_EXCEPTION 0 +#define SWIG_GetConstant SWIG_GetConstantObj +#define SWIG_Tcl_GetConstant SWIG_Tcl_GetConstantObj + + +#ifdef __cplusplus +extern "C" { +#if 0 +} /* cc-mode */ +#endif +#endif + +/* Object support */ + +SWIGRUNTIME Tcl_HashTable* +SWIG_Tcl_ObjectTable(void) { + static Tcl_HashTable swigobjectTable; + static int swigobjectTableinit = 0; + if (!swigobjectTableinit) { + Tcl_InitHashTable(&swigobjectTable, TCL_ONE_WORD_KEYS); + swigobjectTableinit = 1; + } + return &swigobjectTable; +} + +/* Acquire ownership of a pointer */ +SWIGRUNTIME void +SWIG_Tcl_Acquire(void *ptr) { + int newobj; + Tcl_CreateHashEntry(SWIG_Tcl_ObjectTable(), (char *) ptr, &newobj); +} + +SWIGRUNTIME int +SWIG_Tcl_Thisown(void *ptr) { + if (Tcl_FindHashEntry(SWIG_Tcl_ObjectTable(), (char *) ptr)) { + return 1; + } + return 0; +} + +/* Disown a pointer. Returns 1 if we owned it to begin with */ +SWIGRUNTIME int +SWIG_Tcl_Disown(void *ptr) { + Tcl_HashEntry *entryPtr = Tcl_FindHashEntry(SWIG_Tcl_ObjectTable(), (char *) ptr); + if (entryPtr) { + Tcl_DeleteHashEntry(entryPtr); + return 1; + } + return 0; +} + +/* Convert a pointer value */ +SWIGRUNTIME int +SWIG_Tcl_ConvertPtrFromString(Tcl_Interp *interp, const char *c, void **ptr, swig_type_info *ty, int flags) { + swig_cast_info *tc; + /* Pointer values must start with leading underscore */ + while (*c != '_') { + *ptr = (void *) 0; + if (strcmp(c,"NULL") == 0) return SWIG_OK; + /* Hmmm. It could be an object name. */ + if (Tcl_VarEval(interp,c," cget -this", (char *) NULL) == TCL_OK) { + Tcl_Obj *result = Tcl_GetObjResult(interp); + c = Tcl_GetStringFromObj(result, NULL); + continue; + } + Tcl_ResetResult(interp); + return SWIG_ERROR; + } + c++; + c = SWIG_UnpackData(c,ptr,sizeof(void *)); + if (ty) { + tc = c ? SWIG_TypeCheck(c,ty) : 0; + if (!tc) { + return SWIG_ERROR; + } + if (flags & SWIG_POINTER_DISOWN) { + SWIG_Disown((void *) *ptr); + } + *ptr = SWIG_TypeCast(tc,(void *) *ptr); + } + return SWIG_OK; +} + +/* Convert a pointer value */ +SWIGRUNTIMEINLINE int +SWIG_Tcl_ConvertPtr(Tcl_Interp *interp, Tcl_Obj *oc, void **ptr, swig_type_info *ty, int flags) { + return SWIG_Tcl_ConvertPtrFromString(interp, Tcl_GetStringFromObj(oc,NULL), ptr, ty, flags); +} + +/* Convert a pointer value */ +SWIGRUNTIME char * +SWIG_Tcl_PointerTypeFromString(char *c) { + char d; + /* Pointer values must start with leading underscore. NULL has no type */ + if (*c != '_') { + return 0; + } + c++; + /* Extract hex value from pointer */ + while ((d = *c)) { + if (!(((d >= '0') && (d <= '9')) || ((d >= 'a') && (d <= 'f')))) break; + c++; + } + return c; +} + +/* Convert a packed value value */ +SWIGRUNTIME int +SWIG_Tcl_ConvertPacked(Tcl_Interp *SWIGUNUSEDPARM(interp) , Tcl_Obj *obj, void *ptr, int sz, swig_type_info *ty) { + swig_cast_info *tc; + const char *c; + + if (!obj) goto type_error; + c = Tcl_GetStringFromObj(obj,NULL); + /* Pointer values must start with leading underscore */ + if (*c != '_') goto type_error; + c++; + c = SWIG_UnpackData(c,ptr,sz); + if (ty) { + tc = SWIG_TypeCheck(c,ty); + if (!tc) goto type_error; + } + return SWIG_OK; + + type_error: + + return SWIG_ERROR; +} + + +/* Take a pointer and convert it to a string */ +SWIGRUNTIME void +SWIG_Tcl_MakePtr(char *c, void *ptr, swig_type_info *ty, int flags) { + if (ptr) { + *(c++) = '_'; + c = SWIG_PackData(c,&ptr,sizeof(void *)); + strcpy(c,ty->name); + } else { + strcpy(c,(char *)"NULL"); + } + flags = 0; +} + +/* Create a new pointer object */ +SWIGRUNTIMEINLINE Tcl_Obj * +SWIG_Tcl_NewPointerObj(void *ptr, swig_type_info *type, int flags) { + Tcl_Obj *robj; + char result[SWIG_BUFFER_SIZE]; + SWIG_MakePtr(result,ptr,type,flags); + robj = Tcl_NewStringObj(result,-1); + return robj; +} + +SWIGRUNTIME Tcl_Obj * +SWIG_Tcl_NewPackedObj(void *ptr, int sz, swig_type_info *type) { + char result[1024]; + char *r = result; + if ((2*sz + 1 + strlen(type->name)) > 1000) return 0; + *(r++) = '_'; + r = SWIG_PackData(r,ptr,sz); + strcpy(r,type->name); + return Tcl_NewStringObj(result,-1); +} + +/* -----------------------------------------------------------------------------* + * Get type list + * -----------------------------------------------------------------------------*/ + +SWIGRUNTIME swig_module_info * +SWIG_Tcl_GetModule(Tcl_Interp *interp) { + const char *data; + swig_module_info *ret = 0; + + /* first check if pointer already created */ + data = Tcl_GetVar(interp, (char *)"swig_runtime_data_type_pointer" SWIG_RUNTIME_VERSION SWIG_TYPE_TABLE_NAME, TCL_GLOBAL_ONLY); + if (data) { + SWIG_UnpackData(data, &ret, sizeof(swig_type_info **)); + } + + return ret; +} + +SWIGRUNTIME void +SWIG_Tcl_SetModule(Tcl_Interp *interp, swig_module_info *module) { + char buf[SWIG_BUFFER_SIZE]; + char *data; + + /* create a new pointer */ + data = SWIG_PackData(buf, &module, sizeof(swig_type_info **)); + *data = 0; + Tcl_SetVar(interp, (char *)"swig_runtime_data_type_pointer" SWIG_RUNTIME_VERSION SWIG_TYPE_TABLE_NAME, buf, 0); +} + +/* -----------------------------------------------------------------------------* + * Object auxiliars + * -----------------------------------------------------------------------------*/ + + +SWIGRUNTIME void +SWIG_Tcl_ObjectDelete(ClientData clientData) { + swig_instance *si = (swig_instance *) clientData; + if ((si) && (si->destroy) && (SWIG_Disown(si->thisvalue))) { + if (si->classptr->destructor) { + (si->classptr->destructor)(si->thisvalue); + } + } + Tcl_DecrRefCount(si->thisptr); + free(si); +} + +/* Function to invoke object methods given an instance */ +SWIGRUNTIME int +SWIG_Tcl_MethodCommand(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST _objv[]) { + char *method, *attrname; + swig_instance *inst = (swig_instance *) clientData; + swig_method *meth; + swig_attribute *attr; + Tcl_Obj *oldarg; + Tcl_Obj **objv; + int rcode; + swig_class *cls; + swig_class *cls_stack[64]; + int cls_stack_bi[64]; + int cls_stack_top = 0; + int numconf = 2; + int bi; + + objv = (Tcl_Obj **) _objv; + if (objc < 2) { + Tcl_SetResult(interp, (char *) "wrong # args.", TCL_STATIC); + return TCL_ERROR; + } + method = Tcl_GetStringFromObj(objv[1],NULL); + if (strcmp(method,"-acquire") == 0) { + inst->destroy = 1; + SWIG_Acquire(inst->thisvalue); + return TCL_OK; + } + if (strcmp(method,"-disown") == 0) { + if (inst->destroy) { + SWIG_Disown(inst->thisvalue); + } + inst->destroy = 0; + return TCL_OK; + } + if (strcmp(method,"-delete") == 0) { + Tcl_DeleteCommandFromToken(interp,inst->cmdtok); + return TCL_OK; + } + cls_stack[cls_stack_top] = inst->classptr; + cls_stack_bi[cls_stack_top] = -1; + cls = inst->classptr; + while (1) { + bi = cls_stack_bi[cls_stack_top]; + cls = cls_stack[cls_stack_top]; + if (bi != -1) { + if (!cls->bases[bi] && cls->base_names[bi]) { + /* lookup and cache the base class */ + swig_type_info *info = SWIG_TypeQueryModule(cls->module, cls->module, cls->base_names[bi]); + if (info) cls->bases[bi] = (swig_class *) info->clientdata; + } + cls = cls->bases[bi]; + if (cls) { + cls_stack_bi[cls_stack_top]++; + cls_stack_top++; + cls_stack[cls_stack_top] = cls; + cls_stack_bi[cls_stack_top] = -1; + continue; + } + } + if (!cls) { + cls_stack_top--; + if (cls_stack_top < 0) break; + else continue; + } + cls_stack_bi[cls_stack_top]++; + + meth = cls->methods; + /* Check for methods */ + while (meth && meth->name) { + if (strcmp(meth->name,method) == 0) { + oldarg = objv[1]; + objv[1] = inst->thisptr; + Tcl_IncrRefCount(inst->thisptr); + rcode = (*meth->method)(clientData,interp,objc,objv); + objv[1] = oldarg; + Tcl_DecrRefCount(inst->thisptr); + return rcode; + } + meth++; + } + /* Check class methods for a match */ + if (strcmp(method,"cget") == 0) { + if (objc < 3) { + Tcl_SetResult(interp, (char *) "wrong # args.", TCL_STATIC); + return TCL_ERROR; + } + attrname = Tcl_GetStringFromObj(objv[2],NULL); + attr = cls->attributes; + while (attr && attr->name) { + if ((strcmp(attr->name, attrname) == 0) && (attr->getmethod)) { + oldarg = objv[1]; + objv[1] = inst->thisptr; + Tcl_IncrRefCount(inst->thisptr); + rcode = (*attr->getmethod)(clientData,interp,2, objv); + objv[1] = oldarg; + Tcl_DecrRefCount(inst->thisptr); + return rcode; + } + attr++; + } + if (strcmp(attrname, "-this") == 0) { + Tcl_SetObjResult(interp, Tcl_DuplicateObj(inst->thisptr)); + return TCL_OK; + } + if (strcmp(attrname, "-thisown") == 0) { + if (SWIG_Thisown(inst->thisvalue)) { + Tcl_SetResult(interp,(char*)"1",TCL_STATIC); + } else { + Tcl_SetResult(interp,(char*)"0",TCL_STATIC); + } + return TCL_OK; + } + } else if (strcmp(method, "configure") == 0) { + int i; + if (objc < 4) { + Tcl_SetResult(interp, (char *) "wrong # args.", TCL_STATIC); + return TCL_ERROR; + } + i = 2; + while (i < objc) { + attrname = Tcl_GetStringFromObj(objv[i],NULL); + attr = cls->attributes; + while (attr && attr->name) { + if ((strcmp(attr->name, attrname) == 0) && (attr->setmethod)) { + oldarg = objv[i]; + objv[i] = inst->thisptr; + Tcl_IncrRefCount(inst->thisptr); + rcode = (*attr->setmethod)(clientData,interp,3, &objv[i-1]); + objv[i] = oldarg; + Tcl_DecrRefCount(inst->thisptr); + if (rcode != TCL_OK) return rcode; + numconf += 2; + } + attr++; + } + i+=2; + } + } + } + if (strcmp(method,"configure") == 0) { + if (numconf >= objc) { + return TCL_OK; + } else { + Tcl_SetResult(interp,(char *) "Invalid attribute name.", TCL_STATIC); + return TCL_ERROR; + } + } + if (strcmp(method,"cget") == 0) { + Tcl_SetResult(interp,(char *) "Invalid attribute name.", TCL_STATIC); + return TCL_ERROR; + } + Tcl_SetResult(interp, (char *) "Invalid method. Must be one of: configure cget -acquire -disown -delete", TCL_STATIC); + cls = inst->classptr; + bi = 0; + while (cls) { + meth = cls->methods; + while (meth && meth->name) { + char *cr = (char *) Tcl_GetStringResult(interp); + int meth_len = strlen(meth->name); + char* where = strchr(cr,':'); + while(where) { + where = strstr(where, meth->name); + if(where) { + if(where[-1] == ' ' && (where[meth_len] == ' ' || where[meth_len]==0)) { + break; + } else { + where++; + } + } + } + + if (!where) + Tcl_AppendElement(interp, (char *) meth->name); + meth++; + } + cls = inst->classptr->bases[bi++]; + } + return TCL_ERROR; +} + +/* This function takes the current result and turns it into an object command */ +SWIGRUNTIME Tcl_Obj * +SWIG_Tcl_NewInstanceObj(Tcl_Interp *interp, void *thisvalue, swig_type_info *type, int flags) { + Tcl_Obj *robj = SWIG_NewPointerObj(thisvalue, type,0); + /* Check to see if this pointer belongs to a class or not */ + if ((type->clientdata) && (interp)) { + Tcl_CmdInfo ci; + char *name; + name = Tcl_GetStringFromObj(robj,NULL); + if (!Tcl_GetCommandInfo(interp,name, &ci) || (flags)) { + swig_instance *newinst = (swig_instance *) malloc(sizeof(swig_instance)); + newinst->thisptr = Tcl_DuplicateObj(robj); + Tcl_IncrRefCount(newinst->thisptr); + newinst->thisvalue = thisvalue; + newinst->classptr = (swig_class *) type->clientdata; + newinst->destroy = flags; + newinst->cmdtok = Tcl_CreateObjCommand(interp, Tcl_GetStringFromObj(robj,NULL), (swig_wrapper_func) SWIG_MethodCommand, (ClientData) newinst, (swig_delete_func) SWIG_ObjectDelete); + if (flags) { + SWIG_Acquire(thisvalue); + } + } + } + return robj; +} + +/* Function to create objects */ +SWIGRUNTIME int +SWIG_Tcl_ObjectConstructor(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { + Tcl_Obj *newObj = 0; + void *thisvalue = 0; + swig_instance *newinst = 0; + swig_class *classptr = (swig_class *) clientData; + swig_wrapper cons = 0; + char *name = 0; + int firstarg = 0; + int thisarg = 0; + int destroy = 1; + + if (!classptr) { + Tcl_SetResult(interp, (char *) "swig: internal runtime error. No class object defined.", TCL_STATIC); + return TCL_ERROR; + } + cons = classptr->constructor; + if (objc > 1) { + char *s = Tcl_GetStringFromObj(objv[1],NULL); + if (strcmp(s,"-this") == 0) { + thisarg = 2; + cons = 0; + } else if (strcmp(s,"-args") == 0) { + firstarg = 1; + } else if (objc == 2) { + firstarg = 1; + name = s; + } else if (objc >= 3) { + char *s1; + name = s; + s1 = Tcl_GetStringFromObj(objv[2],NULL); + if (strcmp(s1,"-this") == 0) { + thisarg = 3; + cons = 0; + } else { + firstarg = 1; + } + } + } + if (cons) { + int result; + result = (*cons)(0, interp, objc-firstarg, &objv[firstarg]); + if (result != TCL_OK) { + return result; + } + newObj = Tcl_DuplicateObj(Tcl_GetObjResult(interp)); + if (!name) name = Tcl_GetStringFromObj(newObj,NULL); + } else if (thisarg > 0) { + if (thisarg < objc) { + destroy = 0; + newObj = Tcl_DuplicateObj(objv[thisarg]); + if (!name) name = Tcl_GetStringFromObj(newObj,NULL); + } else { + Tcl_SetResult(interp, (char *) "wrong # args.", TCL_STATIC); + return TCL_ERROR; + } + } else { + Tcl_SetResult(interp, (char *) "No constructor available.", TCL_STATIC); + return TCL_ERROR; + } + if (SWIG_Tcl_ConvertPtr(interp,newObj, (void **) &thisvalue, *(classptr->type), 0) != SWIG_OK) { + Tcl_DecrRefCount(newObj); + return TCL_ERROR; + } + newinst = (swig_instance *) malloc(sizeof(swig_instance)); + newinst->thisptr = newObj; + Tcl_IncrRefCount(newObj); + newinst->thisvalue = thisvalue; + newinst->classptr = classptr; + newinst->destroy = destroy; + if (destroy) { + SWIG_Acquire(thisvalue); + } + newinst->cmdtok = Tcl_CreateObjCommand(interp,name, (swig_wrapper) SWIG_MethodCommand, (ClientData) newinst, (swig_delete_func) SWIG_ObjectDelete); + return TCL_OK; +} + +/* -----------------------------------------------------------------------------* + * Get arguments + * -----------------------------------------------------------------------------*/ +SWIGRUNTIME int +SWIG_Tcl_GetArgs(Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[], const char *fmt, ...) { + int argno = 0, opt = 0; + long tempi; + double tempd; + const char *c; + va_list ap; + void *vptr; + Tcl_Obj *obj = 0; + swig_type_info *ty; + + va_start(ap,fmt); + for (c = fmt; (*c && (*c != ':') && (*c != ';')); c++,argno++) { + if (*c == '|') { + opt = 1; + c++; + } + if (argno >= (objc-1)) { + if (!opt) { + Tcl_SetResult(interp, (char *) "Wrong number of arguments ", TCL_STATIC); + goto argerror; + } else { + va_end(ap); + return TCL_OK; + } + } + + vptr = va_arg(ap,void *); + if (vptr) { + if (isupper(*c)) { + obj = SWIG_Tcl_GetConstantObj(Tcl_GetStringFromObj(objv[argno+1],0)); + if (!obj) obj = objv[argno+1]; + } else { + obj = objv[argno+1]; + } + switch(*c) { + case 'i': case 'I': + case 'l': case 'L': + case 'h': case 'H': + case 'b': case 'B': + if (Tcl_GetLongFromObj(interp,obj,&tempi) != TCL_OK) goto argerror; + if ((*c == 'i') || (*c == 'I')) *((int *)vptr) = (int)tempi; + else if ((*c == 'l') || (*c == 'L')) *((long *)vptr) = (long)tempi; + else if ((*c == 'h') || (*c == 'H')) *((short*)vptr) = (short)tempi; + else if ((*c == 'b') || (*c == 'B')) *((unsigned char *)vptr) = (unsigned char)tempi; + break; + case 'f': case 'F': + case 'd': case 'D': + if (Tcl_GetDoubleFromObj(interp,obj,&tempd) != TCL_OK) goto argerror; + if ((*c == 'f') || (*c == 'F')) *((float *) vptr) = (float)tempd; + else if ((*c == 'd') || (*c == 'D')) *((double*) vptr) = tempd; + break; + case 's': case 'S': + if (*(c+1) == '#') { + int *vlptr = (int *) va_arg(ap, void *); + *((char **) vptr) = Tcl_GetStringFromObj(obj, vlptr); + c++; + } else { + *((char **)vptr) = Tcl_GetStringFromObj(obj,NULL); + } + break; + case 'c': case 'C': + *((char *)vptr) = *(Tcl_GetStringFromObj(obj,NULL)); + break; + case 'p': case 'P': + ty = (swig_type_info *) va_arg(ap, void *); + if (SWIG_Tcl_ConvertPtr(interp, obj, (void **) vptr, ty, 0) != SWIG_OK) goto argerror; + break; + case 'o': case 'O': + *((Tcl_Obj **)vptr) = objv[argno+1]; + break; + default: + break; + } + } + } + + if ((*c != ';') && ((objc-1) > argno)) { + Tcl_SetResult(interp, (char *) "Wrong # args.", TCL_STATIC); + goto argerror; + } + va_end(ap); + return TCL_OK; + + argerror: + { + char temp[32]; + sprintf(temp,"%d", argno+1); + c = strchr(fmt,':'); + if (!c) c = strchr(fmt,';'); + if (!c) c = (char *)""; + Tcl_AppendResult(interp,c," argument ", temp, NULL); + va_end(ap); + return TCL_ERROR; + } +} + +#ifdef __cplusplus +#if 0 +{ /* cc-mode */ +#endif +} +#endif + + + +#define SWIG_exception_fail(code, msg) do { SWIG_Error(code, msg); SWIG_fail; } while(0) + +#define SWIG_contract_assert(expr, msg) if (!(expr)) { SWIG_Error(SWIG_RuntimeError, msg); SWIG_fail; } else + + + +/* -------- TYPES TABLE (BEGIN) -------- */ + +#define SWIGTYPE_p_char swig_types[0] +#define SWIGTYPE_p_void swig_types[1] +static swig_type_info *swig_types[3]; +static swig_module_info swig_module = {swig_types, 2, 0, 0, 0, 0}; +#define SWIG_TypeQuery(name) SWIG_TypeQueryModule(&swig_module, &swig_module, name) +#define SWIG_MangledTypeQuery(name) SWIG_MangledTypeQueryModule(&swig_module, &swig_module, name) + +/* -------- TYPES TABLE (END) -------- */ + +#define SWIG_init Nxinter_Init +#define SWIG_name "nxinter" +#define SWIG_prefix "" +#define SWIG_version "0.0" + +#define SWIGVERSION 0x010331 +#define SWIG_VERSION SWIGVERSION + + +#define SWIG_as_voidptr(a) (void *)((const void *)(a)) +#define SWIG_as_voidptrptr(a) ((void)SWIG_as_voidptr(*a),(void**)(a)) + + + +#ifdef __cplusplus +extern "C" { +#endif +#ifdef MAC_TCL +#pragma export on +#endif +SWIGEXPORT int SWIG_init(Tcl_Interp *); +#ifdef MAC_TCL +#pragma export off +#endif +#ifdef __cplusplus +} +#endif + + + +#include "nxinterhelper.h" + + + +#include +#ifndef LLONG_MIN +# define LLONG_MIN LONG_LONG_MIN +#endif +#ifndef LLONG_MAX +# define LLONG_MAX LONG_LONG_MAX +#endif +#ifndef ULLONG_MAX +# define ULLONG_MAX ULONG_LONG_MAX +#endif + + +SWIGINTERNINLINE Tcl_Obj* +SWIG_From_long (long value) +{ + if (((long) INT_MIN <= value) && (value <= (long) INT_MAX)) { + return Tcl_NewIntObj((int)(value)); + } else { + return Tcl_NewLongObj(value); + } +} + + +SWIGINTERNINLINE Tcl_Obj * +SWIG_From_int (int value) +{ + return SWIG_From_long (value); +} + + +#include "nxdataset.h" + +#define MAXDIM 7 + +void *create_nxds(int rank, int type, int dim0, int dim1, int dim2, + int dim3, int dim4, int dim5,int dim6){ + int dim[MAXDIM],i; + + dim[0] = dim0; + dim[1] = dim1; + dim[2] = dim2; + dim[3] = dim3; + dim[4] = dim4; + dim[5] = dim5; + dim[6] = dim6; + + return createNXDataset(rank,type,dim); +} +void *create_text_nxds(char *name){ + return (void *)createTextNXDataset(name); +} + +void drop_nxds(void *ptr){ + dropNXDataset( (pNXDS) ptr); +} + +int get_nxds_rank(void *ptr){ + return getNXDatasetRank((pNXDS) ptr); +} + +int get_nxds_type(void *ptr){ + return getNXDatasetType((pNXDS) ptr); +} + +int get_nxds_dim(void *ptr, int which){ + return getNXDatasetDim((pNXDS) ptr, which); +} + +double get_nxds_value(void *ptr,int dim0, int dim1, int dim2, + int dim3, int dim4, int dim5,int dim6){ + int dim[MAXDIM]; + + dim[0] = dim0; + dim[1] = dim1; + dim[2] = dim2; + dim[3] = dim3; + dim[4] = dim4; + dim[5] = dim5; + dim[6] = dim6; + + return getNXDatasetValue((pNXDS)ptr,dim); +} + +char *get_nxds_text(void *ptr){ + return getNXDatasetText((pNXDS) ptr); +} + +int put_nxds_value(void *ptr, double value, int dim0, int dim1, int dim2, + int dim3, int dim4, int dim5,int dim6){ + int dim[MAXDIM]; + + dim[0] = dim0; + dim[1] = dim1; + dim[2] = dim2; + dim[3] = dim3; + dim[4] = dim4; + dim[5] = dim5; + dim[6] = dim6; + + return putNXDatasetValue((pNXDS)ptr,dim,value); +} + + + + +SWIGINTERN int +SWIG_AsVal_long SWIG_TCL_DECL_ARGS_2(Tcl_Obj *obj, long* val) +{ + long v; + if (Tcl_GetLongFromObj(0,obj, &v) == TCL_OK) { + if (val) *val = (long) v; + return SWIG_OK; + } + return SWIG_TypeError; +} + + +SWIGINTERN int +SWIG_AsVal_int SWIG_TCL_DECL_ARGS_2(Tcl_Obj * obj, int *val) +{ + long v; + int res = SWIG_AsVal_long SWIG_TCL_CALL_ARGS_2(obj, &v); + if (SWIG_IsOK(res)) { + if ((v < INT_MIN || v > INT_MAX)) { + return SWIG_OverflowError; + } else { + if (val) *val = (int)(v); + } + } + return res; +} + + +SWIGINTERN int +SWIG_AsCharPtrAndSize(Tcl_Obj *obj, char** cptr, size_t* psize, int *alloc) +{ + int len = 0; + char *cstr = Tcl_GetStringFromObj(obj, &len); + if (cstr) { + if (cptr) *cptr = cstr; + if (psize) *psize = len + 1; + if (alloc) *alloc = SWIG_OLDOBJ; + return SWIG_OK; + } + return SWIG_TypeError; +} + + + + + + #define SWIG_From_double Tcl_NewDoubleObj + + +SWIGINTERNINLINE Tcl_Obj * +SWIG_FromCharPtrAndSize(const char* carray, size_t size) +{ + return (size < INT_MAX) ? Tcl_NewStringObj(carray, (int)(size)) : NULL; +} + + +SWIGINTERNINLINE Tcl_Obj * +SWIG_FromCharPtr(const char *cptr) +{ + return SWIG_FromCharPtrAndSize(cptr, (cptr ? strlen(cptr) : 0)); +} + + +SWIGINTERN int +SWIG_AsVal_double SWIG_TCL_DECL_ARGS_2(Tcl_Obj *obj, double *val) +{ + double v; + if (Tcl_GetDoubleFromObj(0, obj, &v) == TCL_OK) { + if (val) *val = v; + return SWIG_OK; + } + return SWIG_TypeError; +} + + +SWIGINTERN int +SWIG_AsCharArray(Tcl_Obj * obj, char *val, size_t size) +{ + char* cptr = 0; size_t csize = 0; int alloc = SWIG_OLDOBJ; + int res = SWIG_AsCharPtrAndSize(obj, &cptr, &csize, &alloc); + if (SWIG_IsOK(res)) { + if ((csize == size + 1) && cptr && !(cptr[csize-1])) --csize; + if (csize <= size) { + if (val) { + if (csize) memcpy(val, cptr, csize*sizeof(char)); + if (csize < size) memset(val + csize, 0, (size - csize)*sizeof(char)); + } + if (alloc == SWIG_NEWOBJ) { + free((char*)cptr); + res = SWIG_DelNewMask(res); + } + return res; + } + if (alloc == SWIG_NEWOBJ) free((char*)cptr); + } + return SWIG_TypeError; +} + + +SWIGINTERN int +SWIG_AsVal_char SWIG_TCL_DECL_ARGS_2(Tcl_Obj * obj, char *val) +{ + int res = SWIG_AsCharArray(obj, val, 1); + if (!SWIG_IsOK(res)) { + long v; + res = SWIG_AddCast(SWIG_AsVal_long SWIG_TCL_CALL_ARGS_2(obj, &v)); + if (SWIG_IsOK(res)) { + if ((CHAR_MIN <= v) && (v <= CHAR_MAX)) { + if (val) *val = (char)(v); + } else { + res = SWIG_OverflowError; + } + } + } + return res; +} + + + +/* A TCL_AppInit() function that lets you build a new copy + * of tclsh. + * + * The macro SWIG_init contains the name of the initialization + * function in the wrapper file. + */ + +#ifndef SWIG_RcFileName +char *SWIG_RcFileName = "~/.myapprc"; +#endif + + +#ifdef MAC_TCL +extern int MacintoshInit _ANSI_ARGS_((void)); +#endif + +int Tcl_AppInit(Tcl_Interp *interp){ + + if (Tcl_Init(interp) == TCL_ERROR) + return TCL_ERROR; + + /* Now initialize our functions */ + + if (SWIG_init(interp) == TCL_ERROR) + return TCL_ERROR; +#if TCL_MAJOR_VERSION > 7 || TCL_MAJOR_VERSION == 7 && TCL_MINOR_VERSION >= 5 + Tcl_SetVar(interp, (char *) "tcl_rcFileName",SWIG_RcFileName,TCL_GLOBAL_ONLY); +#else + tcl_RcFileName = SWIG_RcFileName; +#endif +#ifdef SWIG_RcRsrcName + Tcl_SetVar(interp, (char *) "tcl_rcRsrcName",SWIG_RcRsrcName,TCL_GLOBAL); +#endif + + return TCL_OK; +} + + +#ifdef __cplusplus +extern "C" { +#endif +SWIGINTERN int +_wrap_create_nxds(ClientData clientData SWIGUNUSED, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { + int arg1 ; + int arg2 ; + int arg3 = (int) 0 ; + int arg4 = (int) 0 ; + int arg5 = (int) 0 ; + int arg6 = (int) 0 ; + int arg7 = (int) 0 ; + int arg8 = (int) 0 ; + int arg9 = (int) 0 ; + void *result = 0 ; + int val1 ; + int ecode1 = 0 ; + int val2 ; + int ecode2 = 0 ; + int val3 ; + int ecode3 = 0 ; + int val4 ; + int ecode4 = 0 ; + int val5 ; + int ecode5 = 0 ; + int val6 ; + int ecode6 = 0 ; + int val7 ; + int ecode7 = 0 ; + int val8 ; + int ecode8 = 0 ; + int val9 ; + int ecode9 = 0 ; + + if (SWIG_GetArgs(interp, objc, objv,"oo|ooooooo:create_nxds rank type ?dim0? ?dim1? ?dim2? ?dim3? ?dim4? ?dim5? ?dim6? ",(void *)0,(void *)0,(void *)0,(void *)0,(void *)0,(void *)0,(void *)0,(void *)0,(void *)0) == TCL_ERROR) SWIG_fail; + ecode1 = SWIG_AsVal_int SWIG_TCL_CALL_ARGS_2(objv[1], &val1); + if (!SWIG_IsOK(ecode1)) { + SWIG_exception_fail(SWIG_ArgError(ecode1), "in method '" "create_nxds" "', argument " "1"" of type '" "int""'"); + } + arg1 = (int)(val1); + ecode2 = SWIG_AsVal_int SWIG_TCL_CALL_ARGS_2(objv[2], &val2); + if (!SWIG_IsOK(ecode2)) { + SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "create_nxds" "', argument " "2"" of type '" "int""'"); + } + arg2 = (int)(val2); + if (objc > 3) { + ecode3 = SWIG_AsVal_int SWIG_TCL_CALL_ARGS_2(objv[3], &val3); + if (!SWIG_IsOK(ecode3)) { + SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "create_nxds" "', argument " "3"" of type '" "int""'"); + } + arg3 = (int)(val3); + } + if (objc > 4) { + ecode4 = SWIG_AsVal_int SWIG_TCL_CALL_ARGS_2(objv[4], &val4); + if (!SWIG_IsOK(ecode4)) { + SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "create_nxds" "', argument " "4"" of type '" "int""'"); + } + arg4 = (int)(val4); + } + if (objc > 5) { + ecode5 = SWIG_AsVal_int SWIG_TCL_CALL_ARGS_2(objv[5], &val5); + if (!SWIG_IsOK(ecode5)) { + SWIG_exception_fail(SWIG_ArgError(ecode5), "in method '" "create_nxds" "', argument " "5"" of type '" "int""'"); + } + arg5 = (int)(val5); + } + if (objc > 6) { + ecode6 = SWIG_AsVal_int SWIG_TCL_CALL_ARGS_2(objv[6], &val6); + if (!SWIG_IsOK(ecode6)) { + SWIG_exception_fail(SWIG_ArgError(ecode6), "in method '" "create_nxds" "', argument " "6"" of type '" "int""'"); + } + arg6 = (int)(val6); + } + if (objc > 7) { + ecode7 = SWIG_AsVal_int SWIG_TCL_CALL_ARGS_2(objv[7], &val7); + if (!SWIG_IsOK(ecode7)) { + SWIG_exception_fail(SWIG_ArgError(ecode7), "in method '" "create_nxds" "', argument " "7"" of type '" "int""'"); + } + arg7 = (int)(val7); + } + if (objc > 8) { + ecode8 = SWIG_AsVal_int SWIG_TCL_CALL_ARGS_2(objv[8], &val8); + if (!SWIG_IsOK(ecode8)) { + SWIG_exception_fail(SWIG_ArgError(ecode8), "in method '" "create_nxds" "', argument " "8"" of type '" "int""'"); + } + arg8 = (int)(val8); + } + if (objc > 9) { + ecode9 = SWIG_AsVal_int SWIG_TCL_CALL_ARGS_2(objv[9], &val9); + if (!SWIG_IsOK(ecode9)) { + SWIG_exception_fail(SWIG_ArgError(ecode9), "in method '" "create_nxds" "', argument " "9"" of type '" "int""'"); + } + arg9 = (int)(val9); + } + result = (void *)create_nxds(arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9); + Tcl_SetObjResult(interp, SWIG_NewInstanceObj( SWIG_as_voidptr(result), SWIGTYPE_p_void,0)); + return TCL_OK; +fail: + return TCL_ERROR; +} + + +SWIGINTERN int +_wrap_create_text_nxds(ClientData clientData SWIGUNUSED, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { + char *arg1 = (char *) 0 ; + void *result = 0 ; + int res1 ; + char *buf1 = 0 ; + int alloc1 = 0 ; + + if (SWIG_GetArgs(interp, objc, objv,"o:create_text_nxds name ",(void *)0) == TCL_ERROR) SWIG_fail; + res1 = SWIG_AsCharPtrAndSize(objv[1], &buf1, NULL, &alloc1); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "create_text_nxds" "', argument " "1"" of type '" "char *""'"); + } + arg1 = (char *)(buf1); + result = (void *)create_text_nxds(arg1); + Tcl_SetObjResult(interp, SWIG_NewInstanceObj( SWIG_as_voidptr(result), SWIGTYPE_p_void,0)); + if (alloc1 == SWIG_NEWOBJ) free((char*)buf1); + return TCL_OK; +fail: + if (alloc1 == SWIG_NEWOBJ) free((char*)buf1); + return TCL_ERROR; +} + + +SWIGINTERN int +_wrap_drop_nxds(ClientData clientData SWIGUNUSED, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { + void *arg1 = (void *) 0 ; + int res1 ; + + if (SWIG_GetArgs(interp, objc, objv,"o:drop_nxds ptr ",(void *)0) == TCL_ERROR) SWIG_fail; + res1 = SWIG_ConvertPtr(objv[1],SWIG_as_voidptrptr(&arg1), 0, 0); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "drop_nxds" "', argument " "1"" of type '" "void *""'"); + } + drop_nxds(arg1); + + return TCL_OK; +fail: + return TCL_ERROR; +} + + +SWIGINTERN int +_wrap_get_nxds_rank(ClientData clientData SWIGUNUSED, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { + void *arg1 = (void *) 0 ; + int result; + int res1 ; + + if (SWIG_GetArgs(interp, objc, objv,"o:get_nxds_rank ptr ",(void *)0) == TCL_ERROR) SWIG_fail; + res1 = SWIG_ConvertPtr(objv[1],SWIG_as_voidptrptr(&arg1), 0, 0); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "get_nxds_rank" "', argument " "1"" of type '" "void *""'"); + } + result = (int)get_nxds_rank(arg1); + Tcl_SetObjResult(interp,SWIG_From_int((int)(result))); + return TCL_OK; +fail: + return TCL_ERROR; +} + + +SWIGINTERN int +_wrap_get_nxds_type(ClientData clientData SWIGUNUSED, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { + void *arg1 = (void *) 0 ; + int result; + int res1 ; + + if (SWIG_GetArgs(interp, objc, objv,"o:get_nxds_type ptr ",(void *)0) == TCL_ERROR) SWIG_fail; + res1 = SWIG_ConvertPtr(objv[1],SWIG_as_voidptrptr(&arg1), 0, 0); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "get_nxds_type" "', argument " "1"" of type '" "void *""'"); + } + result = (int)get_nxds_type(arg1); + Tcl_SetObjResult(interp,SWIG_From_int((int)(result))); + return TCL_OK; +fail: + return TCL_ERROR; +} + + +SWIGINTERN int +_wrap_get_nxds_dim(ClientData clientData SWIGUNUSED, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { + void *arg1 = (void *) 0 ; + int arg2 ; + int result; + int res1 ; + int val2 ; + int ecode2 = 0 ; + + if (SWIG_GetArgs(interp, objc, objv,"oo:get_nxds_dim ptr which ",(void *)0,(void *)0) == TCL_ERROR) SWIG_fail; + res1 = SWIG_ConvertPtr(objv[1],SWIG_as_voidptrptr(&arg1), 0, 0); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "get_nxds_dim" "', argument " "1"" of type '" "void *""'"); + } + ecode2 = SWIG_AsVal_int SWIG_TCL_CALL_ARGS_2(objv[2], &val2); + if (!SWIG_IsOK(ecode2)) { + SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "get_nxds_dim" "', argument " "2"" of type '" "int""'"); + } + arg2 = (int)(val2); + result = (int)get_nxds_dim(arg1,arg2); + Tcl_SetObjResult(interp,SWIG_From_int((int)(result))); + return TCL_OK; +fail: + return TCL_ERROR; +} + + +SWIGINTERN int +_wrap_get_nxds_value(ClientData clientData SWIGUNUSED, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { + void *arg1 = (void *) 0 ; + int arg2 = (int) 0 ; + int arg3 = (int) 0 ; + int arg4 = (int) 0 ; + int arg5 = (int) 0 ; + int arg6 = (int) 0 ; + int arg7 = (int) 0 ; + int arg8 = (int) 0 ; + double result; + int res1 ; + int val2 ; + int ecode2 = 0 ; + int val3 ; + int ecode3 = 0 ; + int val4 ; + int ecode4 = 0 ; + int val5 ; + int ecode5 = 0 ; + int val6 ; + int ecode6 = 0 ; + int val7 ; + int ecode7 = 0 ; + int val8 ; + int ecode8 = 0 ; + + if (SWIG_GetArgs(interp, objc, objv,"o|ooooooo:get_nxds_value ptr ?dim0? ?dim1? ?dim2? ?dim3? ?dim4? ?dim5? ?dim6? ",(void *)0,(void *)0,(void *)0,(void *)0,(void *)0,(void *)0,(void *)0,(void *)0) == TCL_ERROR) SWIG_fail; + res1 = SWIG_ConvertPtr(objv[1],SWIG_as_voidptrptr(&arg1), 0, 0); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "get_nxds_value" "', argument " "1"" of type '" "void *""'"); + } + if (objc > 2) { + ecode2 = SWIG_AsVal_int SWIG_TCL_CALL_ARGS_2(objv[2], &val2); + if (!SWIG_IsOK(ecode2)) { + SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "get_nxds_value" "', argument " "2"" of type '" "int""'"); + } + arg2 = (int)(val2); + } + if (objc > 3) { + ecode3 = SWIG_AsVal_int SWIG_TCL_CALL_ARGS_2(objv[3], &val3); + if (!SWIG_IsOK(ecode3)) { + SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "get_nxds_value" "', argument " "3"" of type '" "int""'"); + } + arg3 = (int)(val3); + } + if (objc > 4) { + ecode4 = SWIG_AsVal_int SWIG_TCL_CALL_ARGS_2(objv[4], &val4); + if (!SWIG_IsOK(ecode4)) { + SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "get_nxds_value" "', argument " "4"" of type '" "int""'"); + } + arg4 = (int)(val4); + } + if (objc > 5) { + ecode5 = SWIG_AsVal_int SWIG_TCL_CALL_ARGS_2(objv[5], &val5); + if (!SWIG_IsOK(ecode5)) { + SWIG_exception_fail(SWIG_ArgError(ecode5), "in method '" "get_nxds_value" "', argument " "5"" of type '" "int""'"); + } + arg5 = (int)(val5); + } + if (objc > 6) { + ecode6 = SWIG_AsVal_int SWIG_TCL_CALL_ARGS_2(objv[6], &val6); + if (!SWIG_IsOK(ecode6)) { + SWIG_exception_fail(SWIG_ArgError(ecode6), "in method '" "get_nxds_value" "', argument " "6"" of type '" "int""'"); + } + arg6 = (int)(val6); + } + if (objc > 7) { + ecode7 = SWIG_AsVal_int SWIG_TCL_CALL_ARGS_2(objv[7], &val7); + if (!SWIG_IsOK(ecode7)) { + SWIG_exception_fail(SWIG_ArgError(ecode7), "in method '" "get_nxds_value" "', argument " "7"" of type '" "int""'"); + } + arg7 = (int)(val7); + } + if (objc > 8) { + ecode8 = SWIG_AsVal_int SWIG_TCL_CALL_ARGS_2(objv[8], &val8); + if (!SWIG_IsOK(ecode8)) { + SWIG_exception_fail(SWIG_ArgError(ecode8), "in method '" "get_nxds_value" "', argument " "8"" of type '" "int""'"); + } + arg8 = (int)(val8); + } + result = (double)get_nxds_value(arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8); + Tcl_SetObjResult(interp,SWIG_From_double((double)(result))); + return TCL_OK; +fail: + return TCL_ERROR; +} + + +SWIGINTERN int +_wrap_get_nxds_text(ClientData clientData SWIGUNUSED, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { + void *arg1 = (void *) 0 ; + char *result = 0 ; + int res1 ; + + if (SWIG_GetArgs(interp, objc, objv,"o:get_nxds_text ptr ",(void *)0) == TCL_ERROR) SWIG_fail; + res1 = SWIG_ConvertPtr(objv[1],SWIG_as_voidptrptr(&arg1), 0, 0); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "get_nxds_text" "', argument " "1"" of type '" "void *""'"); + } + result = (char *)get_nxds_text(arg1); + Tcl_SetObjResult(interp,SWIG_FromCharPtr((const char *)result)); + return TCL_OK; +fail: + return TCL_ERROR; +} + + +SWIGINTERN int +_wrap_put_nxds_value(ClientData clientData SWIGUNUSED, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { + void *arg1 = (void *) 0 ; + double arg2 ; + int arg3 = (int) 0 ; + int arg4 = (int) 0 ; + int arg5 = (int) 0 ; + int arg6 = (int) 0 ; + int arg7 = (int) 0 ; + int arg8 = (int) 0 ; + int arg9 = (int) 0 ; + int result; + int res1 ; + double val2 ; + int ecode2 = 0 ; + int val3 ; + int ecode3 = 0 ; + int val4 ; + int ecode4 = 0 ; + int val5 ; + int ecode5 = 0 ; + int val6 ; + int ecode6 = 0 ; + int val7 ; + int ecode7 = 0 ; + int val8 ; + int ecode8 = 0 ; + int val9 ; + int ecode9 = 0 ; + + if (SWIG_GetArgs(interp, objc, objv,"oo|ooooooo:put_nxds_value ptr value ?dim0? ?dim1? ?dim2? ?dim3? ?dim4? ?dim5? ?dim6? ",(void *)0,(void *)0,(void *)0,(void *)0,(void *)0,(void *)0,(void *)0,(void *)0,(void *)0) == TCL_ERROR) SWIG_fail; + res1 = SWIG_ConvertPtr(objv[1],SWIG_as_voidptrptr(&arg1), 0, 0); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "put_nxds_value" "', argument " "1"" of type '" "void *""'"); + } + ecode2 = SWIG_AsVal_double SWIG_TCL_CALL_ARGS_2(objv[2], &val2); + if (!SWIG_IsOK(ecode2)) { + SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "put_nxds_value" "', argument " "2"" of type '" "double""'"); + } + arg2 = (double)(val2); + if (objc > 3) { + ecode3 = SWIG_AsVal_int SWIG_TCL_CALL_ARGS_2(objv[3], &val3); + if (!SWIG_IsOK(ecode3)) { + SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "put_nxds_value" "', argument " "3"" of type '" "int""'"); + } + arg3 = (int)(val3); + } + if (objc > 4) { + ecode4 = SWIG_AsVal_int SWIG_TCL_CALL_ARGS_2(objv[4], &val4); + if (!SWIG_IsOK(ecode4)) { + SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "put_nxds_value" "', argument " "4"" of type '" "int""'"); + } + arg4 = (int)(val4); + } + if (objc > 5) { + ecode5 = SWIG_AsVal_int SWIG_TCL_CALL_ARGS_2(objv[5], &val5); + if (!SWIG_IsOK(ecode5)) { + SWIG_exception_fail(SWIG_ArgError(ecode5), "in method '" "put_nxds_value" "', argument " "5"" of type '" "int""'"); + } + arg5 = (int)(val5); + } + if (objc > 6) { + ecode6 = SWIG_AsVal_int SWIG_TCL_CALL_ARGS_2(objv[6], &val6); + if (!SWIG_IsOK(ecode6)) { + SWIG_exception_fail(SWIG_ArgError(ecode6), "in method '" "put_nxds_value" "', argument " "6"" of type '" "int""'"); + } + arg6 = (int)(val6); + } + if (objc > 7) { + ecode7 = SWIG_AsVal_int SWIG_TCL_CALL_ARGS_2(objv[7], &val7); + if (!SWIG_IsOK(ecode7)) { + SWIG_exception_fail(SWIG_ArgError(ecode7), "in method '" "put_nxds_value" "', argument " "7"" of type '" "int""'"); + } + arg7 = (int)(val7); + } + if (objc > 8) { + ecode8 = SWIG_AsVal_int SWIG_TCL_CALL_ARGS_2(objv[8], &val8); + if (!SWIG_IsOK(ecode8)) { + SWIG_exception_fail(SWIG_ArgError(ecode8), "in method '" "put_nxds_value" "', argument " "8"" of type '" "int""'"); + } + arg8 = (int)(val8); + } + if (objc > 9) { + ecode9 = SWIG_AsVal_int SWIG_TCL_CALL_ARGS_2(objv[9], &val9); + if (!SWIG_IsOK(ecode9)) { + SWIG_exception_fail(SWIG_ArgError(ecode9), "in method '" "put_nxds_value" "', argument " "9"" of type '" "int""'"); + } + arg9 = (int)(val9); + } + result = (int)put_nxds_value(arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9); + Tcl_SetObjResult(interp,SWIG_From_int((int)(result))); + return TCL_OK; +fail: + return TCL_ERROR; +} + + +SWIGINTERN int +_wrap_nx_getlasterror(ClientData clientData SWIGUNUSED, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { + char *result = 0 ; + + if (SWIG_GetArgs(interp, objc, objv,":nx_getlasterror ") == TCL_ERROR) SWIG_fail; + result = (char *)nx_getlasterror(); + Tcl_SetObjResult(interp,SWIG_FromCharPtr((const char *)result)); + return TCL_OK; +fail: + return TCL_ERROR; +} + + +SWIGINTERN int +_wrap_nx_open(ClientData clientData SWIGUNUSED, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { + char *arg1 = (char *) 0 ; + int arg2 ; + void *result = 0 ; + int res1 ; + char *buf1 = 0 ; + int alloc1 = 0 ; + int val2 ; + int ecode2 = 0 ; + + if (SWIG_GetArgs(interp, objc, objv,"oo:nx_open filename accessCode ",(void *)0,(void *)0) == TCL_ERROR) SWIG_fail; + res1 = SWIG_AsCharPtrAndSize(objv[1], &buf1, NULL, &alloc1); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "nx_open" "', argument " "1"" of type '" "char *""'"); + } + arg1 = (char *)(buf1); + ecode2 = SWIG_AsVal_int SWIG_TCL_CALL_ARGS_2(objv[2], &val2); + if (!SWIG_IsOK(ecode2)) { + SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "nx_open" "', argument " "2"" of type '" "int""'"); + } + arg2 = (int)(val2); + result = (void *)nx_open(arg1,arg2); + Tcl_SetObjResult(interp, SWIG_NewInstanceObj( SWIG_as_voidptr(result), SWIGTYPE_p_void,0)); + if (alloc1 == SWIG_NEWOBJ) free((char*)buf1); + return TCL_OK; +fail: + if (alloc1 == SWIG_NEWOBJ) free((char*)buf1); + return TCL_ERROR; +} + + +SWIGINTERN int +_wrap_nx_flush(ClientData clientData SWIGUNUSED, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { + void *arg1 = (void *) 0 ; + void *result = 0 ; + int res1 ; + + if (SWIG_GetArgs(interp, objc, objv,"o:nx_flush handle ",(void *)0) == TCL_ERROR) SWIG_fail; + res1 = SWIG_ConvertPtr(objv[1],SWIG_as_voidptrptr(&arg1), 0, 0); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "nx_flush" "', argument " "1"" of type '" "void *""'"); + } + result = (void *)nx_flush(arg1); + Tcl_SetObjResult(interp, SWIG_NewInstanceObj( SWIG_as_voidptr(result), SWIGTYPE_p_void,0)); + return TCL_OK; +fail: + return TCL_ERROR; +} + + +SWIGINTERN int +_wrap_nx_close(ClientData clientData SWIGUNUSED, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { + void *arg1 = (void *) 0 ; + int res1 ; + + if (SWIG_GetArgs(interp, objc, objv,"o:nx_close handle ",(void *)0) == TCL_ERROR) SWIG_fail; + res1 = SWIG_ConvertPtr(objv[1],SWIG_as_voidptrptr(&arg1), 0, 0); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "nx_close" "', argument " "1"" of type '" "void *""'"); + } + nx_close(arg1); + + return TCL_OK; +fail: + return TCL_ERROR; +} + + +SWIGINTERN int +_wrap_nx_makegroup(ClientData clientData SWIGUNUSED, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { + void *arg1 = (void *) 0 ; + char *arg2 = (char *) 0 ; + char *arg3 = (char *) 0 ; + int result; + int res1 ; + int res2 ; + char *buf2 = 0 ; + int alloc2 = 0 ; + int res3 ; + char *buf3 = 0 ; + int alloc3 = 0 ; + + if (SWIG_GetArgs(interp, objc, objv,"ooo:nx_makegroup handle name nxclass ",(void *)0,(void *)0,(void *)0) == TCL_ERROR) SWIG_fail; + res1 = SWIG_ConvertPtr(objv[1],SWIG_as_voidptrptr(&arg1), 0, 0); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "nx_makegroup" "', argument " "1"" of type '" "void *""'"); + } + res2 = SWIG_AsCharPtrAndSize(objv[2], &buf2, NULL, &alloc2); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "nx_makegroup" "', argument " "2"" of type '" "char *""'"); + } + arg2 = (char *)(buf2); + res3 = SWIG_AsCharPtrAndSize(objv[3], &buf3, NULL, &alloc3); + if (!SWIG_IsOK(res3)) { + SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "nx_makegroup" "', argument " "3"" of type '" "char *""'"); + } + arg3 = (char *)(buf3); + result = (int)nx_makegroup(arg1,arg2,arg3); + Tcl_SetObjResult(interp,SWIG_From_int((int)(result))); + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + if (alloc3 == SWIG_NEWOBJ) free((char*)buf3); + return TCL_OK; +fail: + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + if (alloc3 == SWIG_NEWOBJ) free((char*)buf3); + return TCL_ERROR; +} + + +SWIGINTERN int +_wrap_nx_opengroup(ClientData clientData SWIGUNUSED, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { + void *arg1 = (void *) 0 ; + char *arg2 = (char *) 0 ; + char *arg3 = (char *) 0 ; + int result; + int res1 ; + int res2 ; + char *buf2 = 0 ; + int alloc2 = 0 ; + int res3 ; + char *buf3 = 0 ; + int alloc3 = 0 ; + + if (SWIG_GetArgs(interp, objc, objv,"ooo:nx_opengroup handle name nxclass ",(void *)0,(void *)0,(void *)0) == TCL_ERROR) SWIG_fail; + res1 = SWIG_ConvertPtr(objv[1],SWIG_as_voidptrptr(&arg1), 0, 0); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "nx_opengroup" "', argument " "1"" of type '" "void *""'"); + } + res2 = SWIG_AsCharPtrAndSize(objv[2], &buf2, NULL, &alloc2); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "nx_opengroup" "', argument " "2"" of type '" "char *""'"); + } + arg2 = (char *)(buf2); + res3 = SWIG_AsCharPtrAndSize(objv[3], &buf3, NULL, &alloc3); + if (!SWIG_IsOK(res3)) { + SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "nx_opengroup" "', argument " "3"" of type '" "char *""'"); + } + arg3 = (char *)(buf3); + result = (int)nx_opengroup(arg1,arg2,arg3); + Tcl_SetObjResult(interp,SWIG_From_int((int)(result))); + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + if (alloc3 == SWIG_NEWOBJ) free((char*)buf3); + return TCL_OK; +fail: + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + if (alloc3 == SWIG_NEWOBJ) free((char*)buf3); + return TCL_ERROR; +} + + +SWIGINTERN int +_wrap_nx_openpath(ClientData clientData SWIGUNUSED, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { + void *arg1 = (void *) 0 ; + char *arg2 = (char *) 0 ; + int result; + int res1 ; + int res2 ; + char *buf2 = 0 ; + int alloc2 = 0 ; + + if (SWIG_GetArgs(interp, objc, objv,"oo:nx_openpath handle path ",(void *)0,(void *)0) == TCL_ERROR) SWIG_fail; + res1 = SWIG_ConvertPtr(objv[1],SWIG_as_voidptrptr(&arg1), 0, 0); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "nx_openpath" "', argument " "1"" of type '" "void *""'"); + } + res2 = SWIG_AsCharPtrAndSize(objv[2], &buf2, NULL, &alloc2); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "nx_openpath" "', argument " "2"" of type '" "char *""'"); + } + arg2 = (char *)(buf2); + result = (int)nx_openpath(arg1,arg2); + Tcl_SetObjResult(interp,SWIG_From_int((int)(result))); + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + return TCL_OK; +fail: + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + return TCL_ERROR; +} + + +SWIGINTERN int +_wrap_nx_opengrouppath(ClientData clientData SWIGUNUSED, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { + void *arg1 = (void *) 0 ; + char *arg2 = (char *) 0 ; + int result; + int res1 ; + int res2 ; + char *buf2 = 0 ; + int alloc2 = 0 ; + + if (SWIG_GetArgs(interp, objc, objv,"oo:nx_opengrouppath handle path ",(void *)0,(void *)0) == TCL_ERROR) SWIG_fail; + res1 = SWIG_ConvertPtr(objv[1],SWIG_as_voidptrptr(&arg1), 0, 0); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "nx_opengrouppath" "', argument " "1"" of type '" "void *""'"); + } + res2 = SWIG_AsCharPtrAndSize(objv[2], &buf2, NULL, &alloc2); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "nx_opengrouppath" "', argument " "2"" of type '" "char *""'"); + } + arg2 = (char *)(buf2); + result = (int)nx_opengrouppath(arg1,arg2); + Tcl_SetObjResult(interp,SWIG_From_int((int)(result))); + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + return TCL_OK; +fail: + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + return TCL_ERROR; +} + + +SWIGINTERN int +_wrap_nx_closegroup(ClientData clientData SWIGUNUSED, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { + void *arg1 = (void *) 0 ; + int result; + int res1 ; + + if (SWIG_GetArgs(interp, objc, objv,"o:nx_closegroup handle ",(void *)0) == TCL_ERROR) SWIG_fail; + res1 = SWIG_ConvertPtr(objv[1],SWIG_as_voidptrptr(&arg1), 0, 0); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "nx_closegroup" "', argument " "1"" of type '" "void *""'"); + } + result = (int)nx_closegroup(arg1); + Tcl_SetObjResult(interp,SWIG_From_int((int)(result))); + return TCL_OK; +fail: + return TCL_ERROR; +} + + +SWIGINTERN int +_wrap_nx_getnextentry(ClientData clientData SWIGUNUSED, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { + void *arg1 = (void *) 0 ; + char arg2 ; + char *result = 0 ; + int res1 ; + char val2 ; + int ecode2 = 0 ; + + if (SWIG_GetArgs(interp, objc, objv,"oo:nx_getnextentry handle separator ",(void *)0,(void *)0) == TCL_ERROR) SWIG_fail; + res1 = SWIG_ConvertPtr(objv[1],SWIG_as_voidptrptr(&arg1), 0, 0); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "nx_getnextentry" "', argument " "1"" of type '" "void *""'"); + } + ecode2 = SWIG_AsVal_char SWIG_TCL_CALL_ARGS_2(objv[2], &val2); + if (!SWIG_IsOK(ecode2)) { + SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "nx_getnextentry" "', argument " "2"" of type '" "char""'"); + } + arg2 = (char)(val2); + result = (char *)nx_getnextentry(arg1,arg2); + Tcl_SetObjResult(interp,SWIG_FromCharPtr((const char *)result)); + return TCL_OK; +fail: + return TCL_ERROR; +} + + +SWIGINTERN int +_wrap_nx_getgroupID(ClientData clientData SWIGUNUSED, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { + void *arg1 = (void *) 0 ; + void *result = 0 ; + int res1 ; + + if (SWIG_GetArgs(interp, objc, objv,"o:nx_getgroupID handle ",(void *)0) == TCL_ERROR) SWIG_fail; + res1 = SWIG_ConvertPtr(objv[1],SWIG_as_voidptrptr(&arg1), 0, 0); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "nx_getgroupID" "', argument " "1"" of type '" "void *""'"); + } + result = (void *)nx_getgroupID(arg1); + Tcl_SetObjResult(interp, SWIG_NewInstanceObj( SWIG_as_voidptr(result), SWIGTYPE_p_void,0)); + return TCL_OK; +fail: + return TCL_ERROR; +} + + +SWIGINTERN int +_wrap_nx_initgroupdir(ClientData clientData SWIGUNUSED, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { + void *arg1 = (void *) 0 ; + int result; + int res1 ; + + if (SWIG_GetArgs(interp, objc, objv,"o:nx_initgroupdir handle ",(void *)0) == TCL_ERROR) SWIG_fail; + res1 = SWIG_ConvertPtr(objv[1],SWIG_as_voidptrptr(&arg1), 0, 0); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "nx_initgroupdir" "', argument " "1"" of type '" "void *""'"); + } + result = (int)nx_initgroupdir(arg1); + Tcl_SetObjResult(interp,SWIG_From_int((int)(result))); + return TCL_OK; +fail: + return TCL_ERROR; +} + + +SWIGINTERN int +_wrap_nx_makedata(ClientData clientData SWIGUNUSED, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { + void *arg1 = (void *) 0 ; + char *arg2 = (char *) 0 ; + int arg3 ; + int arg4 ; + void *arg5 = (void *) 0 ; + int result; + int res1 ; + int res2 ; + char *buf2 = 0 ; + int alloc2 = 0 ; + int val3 ; + int ecode3 = 0 ; + int val4 ; + int ecode4 = 0 ; + int res5 ; + + if (SWIG_GetArgs(interp, objc, objv,"ooooo:nx_makedata handle name rank type dimPtr ",(void *)0,(void *)0,(void *)0,(void *)0,(void *)0) == TCL_ERROR) SWIG_fail; + res1 = SWIG_ConvertPtr(objv[1],SWIG_as_voidptrptr(&arg1), 0, 0); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "nx_makedata" "', argument " "1"" of type '" "void *""'"); + } + res2 = SWIG_AsCharPtrAndSize(objv[2], &buf2, NULL, &alloc2); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "nx_makedata" "', argument " "2"" of type '" "char *""'"); + } + arg2 = (char *)(buf2); + ecode3 = SWIG_AsVal_int SWIG_TCL_CALL_ARGS_2(objv[3], &val3); + if (!SWIG_IsOK(ecode3)) { + SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "nx_makedata" "', argument " "3"" of type '" "int""'"); + } + arg3 = (int)(val3); + ecode4 = SWIG_AsVal_int SWIG_TCL_CALL_ARGS_2(objv[4], &val4); + if (!SWIG_IsOK(ecode4)) { + SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "nx_makedata" "', argument " "4"" of type '" "int""'"); + } + arg4 = (int)(val4); + res5 = SWIG_ConvertPtr(objv[5],SWIG_as_voidptrptr(&arg5), 0, 0); + if (!SWIG_IsOK(res5)) { + SWIG_exception_fail(SWIG_ArgError(res5), "in method '" "nx_makedata" "', argument " "5"" of type '" "void *""'"); + } + result = (int)nx_makedata(arg1,arg2,arg3,arg4,arg5); + Tcl_SetObjResult(interp,SWIG_From_int((int)(result))); + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + return TCL_OK; +fail: + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + return TCL_ERROR; +} + + +SWIGINTERN int +_wrap_nx_compmakedata(ClientData clientData SWIGUNUSED, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { + void *arg1 = (void *) 0 ; + char *arg2 = (char *) 0 ; + int arg3 ; + int arg4 ; + void *arg5 = (void *) 0 ; + void *arg6 = (void *) 0 ; + int result; + int res1 ; + int res2 ; + char *buf2 = 0 ; + int alloc2 = 0 ; + int val3 ; + int ecode3 = 0 ; + int val4 ; + int ecode4 = 0 ; + int res5 ; + int res6 ; + + if (SWIG_GetArgs(interp, objc, objv,"oooooo:nx_compmakedata handle name rank type dimPtr bufPtr ",(void *)0,(void *)0,(void *)0,(void *)0,(void *)0,(void *)0) == TCL_ERROR) SWIG_fail; + res1 = SWIG_ConvertPtr(objv[1],SWIG_as_voidptrptr(&arg1), 0, 0); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "nx_compmakedata" "', argument " "1"" of type '" "void *""'"); + } + res2 = SWIG_AsCharPtrAndSize(objv[2], &buf2, NULL, &alloc2); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "nx_compmakedata" "', argument " "2"" of type '" "char *""'"); + } + arg2 = (char *)(buf2); + ecode3 = SWIG_AsVal_int SWIG_TCL_CALL_ARGS_2(objv[3], &val3); + if (!SWIG_IsOK(ecode3)) { + SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "nx_compmakedata" "', argument " "3"" of type '" "int""'"); + } + arg3 = (int)(val3); + ecode4 = SWIG_AsVal_int SWIG_TCL_CALL_ARGS_2(objv[4], &val4); + if (!SWIG_IsOK(ecode4)) { + SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "nx_compmakedata" "', argument " "4"" of type '" "int""'"); + } + arg4 = (int)(val4); + res5 = SWIG_ConvertPtr(objv[5],SWIG_as_voidptrptr(&arg5), 0, 0); + if (!SWIG_IsOK(res5)) { + SWIG_exception_fail(SWIG_ArgError(res5), "in method '" "nx_compmakedata" "', argument " "5"" of type '" "void *""'"); + } + res6 = SWIG_ConvertPtr(objv[6],SWIG_as_voidptrptr(&arg6), 0, 0); + if (!SWIG_IsOK(res6)) { + SWIG_exception_fail(SWIG_ArgError(res6), "in method '" "nx_compmakedata" "', argument " "6"" of type '" "void *""'"); + } + result = (int)nx_compmakedata(arg1,arg2,arg3,arg4,arg5,arg6); + Tcl_SetObjResult(interp,SWIG_From_int((int)(result))); + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + return TCL_OK; +fail: + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + return TCL_ERROR; +} + + +SWIGINTERN int +_wrap_nx_opendata(ClientData clientData SWIGUNUSED, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { + void *arg1 = (void *) 0 ; + char *arg2 = (char *) 0 ; + int result; + int res1 ; + int res2 ; + char *buf2 = 0 ; + int alloc2 = 0 ; + + if (SWIG_GetArgs(interp, objc, objv,"oo:nx_opendata handle name ",(void *)0,(void *)0) == TCL_ERROR) SWIG_fail; + res1 = SWIG_ConvertPtr(objv[1],SWIG_as_voidptrptr(&arg1), 0, 0); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "nx_opendata" "', argument " "1"" of type '" "void *""'"); + } + res2 = SWIG_AsCharPtrAndSize(objv[2], &buf2, NULL, &alloc2); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "nx_opendata" "', argument " "2"" of type '" "char *""'"); + } + arg2 = (char *)(buf2); + result = (int)nx_opendata(arg1,arg2); + Tcl_SetObjResult(interp,SWIG_From_int((int)(result))); + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + return TCL_OK; +fail: + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + return TCL_ERROR; +} + + +SWIGINTERN int +_wrap_nx_closedata(ClientData clientData SWIGUNUSED, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { + void *arg1 = (void *) 0 ; + int result; + int res1 ; + + if (SWIG_GetArgs(interp, objc, objv,"o:nx_closedata handle ",(void *)0) == TCL_ERROR) SWIG_fail; + res1 = SWIG_ConvertPtr(objv[1],SWIG_as_voidptrptr(&arg1), 0, 0); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "nx_closedata" "', argument " "1"" of type '" "void *""'"); + } + result = (int)nx_closedata(arg1); + Tcl_SetObjResult(interp,SWIG_From_int((int)(result))); + return TCL_OK; +fail: + return TCL_ERROR; +} + + +SWIGINTERN int +_wrap_nx_putslab(ClientData clientData SWIGUNUSED, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { + void *arg1 = (void *) 0 ; + void *arg2 = (void *) 0 ; + void *arg3 = (void *) 0 ; + int result; + int res1 ; + int res2 ; + int res3 ; + + if (SWIG_GetArgs(interp, objc, objv,"ooo:nx_putslab handle dataset startDim ",(void *)0,(void *)0,(void *)0) == TCL_ERROR) SWIG_fail; + res1 = SWIG_ConvertPtr(objv[1],SWIG_as_voidptrptr(&arg1), 0, 0); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "nx_putslab" "', argument " "1"" of type '" "void *""'"); + } + res2 = SWIG_ConvertPtr(objv[2],SWIG_as_voidptrptr(&arg2), 0, 0); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "nx_putslab" "', argument " "2"" of type '" "void *""'"); + } + res3 = SWIG_ConvertPtr(objv[3],SWIG_as_voidptrptr(&arg3), 0, 0); + if (!SWIG_IsOK(res3)) { + SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "nx_putslab" "', argument " "3"" of type '" "void *""'"); + } + result = (int)nx_putslab(arg1,arg2,arg3); + Tcl_SetObjResult(interp,SWIG_From_int((int)(result))); + return TCL_OK; +fail: + return TCL_ERROR; +} + + +SWIGINTERN int +_wrap_nx_getslab(ClientData clientData SWIGUNUSED, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { + void *arg1 = (void *) 0 ; + void *arg2 = (void *) 0 ; + void *arg3 = (void *) 0 ; + void *result = 0 ; + int res1 ; + int res2 ; + int res3 ; + + if (SWIG_GetArgs(interp, objc, objv,"ooo:nx_getslab handle startdim size ",(void *)0,(void *)0,(void *)0) == TCL_ERROR) SWIG_fail; + res1 = SWIG_ConvertPtr(objv[1],SWIG_as_voidptrptr(&arg1), 0, 0); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "nx_getslab" "', argument " "1"" of type '" "void *""'"); + } + res2 = SWIG_ConvertPtr(objv[2],SWIG_as_voidptrptr(&arg2), 0, 0); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "nx_getslab" "', argument " "2"" of type '" "void *""'"); + } + res3 = SWIG_ConvertPtr(objv[3],SWIG_as_voidptrptr(&arg3), 0, 0); + if (!SWIG_IsOK(res3)) { + SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "nx_getslab" "', argument " "3"" of type '" "void *""'"); + } + result = (void *)nx_getslab(arg1,arg2,arg3); + Tcl_SetObjResult(interp, SWIG_NewInstanceObj( SWIG_as_voidptr(result), SWIGTYPE_p_void,0)); + return TCL_OK; +fail: + return TCL_ERROR; +} + + +SWIGINTERN int +_wrap_nx_getds(ClientData clientData SWIGUNUSED, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { + void *arg1 = (void *) 0 ; + char *arg2 = (char *) 0 ; + void *result = 0 ; + int res1 ; + int res2 ; + char *buf2 = 0 ; + int alloc2 = 0 ; + + if (SWIG_GetArgs(interp, objc, objv,"oo:nx_getds handle name ",(void *)0,(void *)0) == TCL_ERROR) SWIG_fail; + res1 = SWIG_ConvertPtr(objv[1],SWIG_as_voidptrptr(&arg1), 0, 0); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "nx_getds" "', argument " "1"" of type '" "void *""'"); + } + res2 = SWIG_AsCharPtrAndSize(objv[2], &buf2, NULL, &alloc2); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "nx_getds" "', argument " "2"" of type '" "char *""'"); + } + arg2 = (char *)(buf2); + result = (void *)nx_getds(arg1,arg2); + Tcl_SetObjResult(interp, SWIG_NewInstanceObj( SWIG_as_voidptr(result), SWIGTYPE_p_void,0)); + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + return TCL_OK; +fail: + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + return TCL_ERROR; +} + + +SWIGINTERN int +_wrap_nx_putds(ClientData clientData SWIGUNUSED, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { + void *arg1 = (void *) 0 ; + char *arg2 = (char *) 0 ; + void *arg3 = (void *) 0 ; + int result; + int res1 ; + int res2 ; + char *buf2 = 0 ; + int alloc2 = 0 ; + int res3 ; + + if (SWIG_GetArgs(interp, objc, objv,"ooo:nx_putds handle name dataset ",(void *)0,(void *)0,(void *)0) == TCL_ERROR) SWIG_fail; + res1 = SWIG_ConvertPtr(objv[1],SWIG_as_voidptrptr(&arg1), 0, 0); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "nx_putds" "', argument " "1"" of type '" "void *""'"); + } + res2 = SWIG_AsCharPtrAndSize(objv[2], &buf2, NULL, &alloc2); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "nx_putds" "', argument " "2"" of type '" "char *""'"); + } + arg2 = (char *)(buf2); + res3 = SWIG_ConvertPtr(objv[3],SWIG_as_voidptrptr(&arg3), 0, 0); + if (!SWIG_IsOK(res3)) { + SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "nx_putds" "', argument " "3"" of type '" "void *""'"); + } + result = (int)nx_putds(arg1,arg2,arg3); + Tcl_SetObjResult(interp,SWIG_From_int((int)(result))); + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + return TCL_OK; +fail: + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + return TCL_ERROR; +} + + +SWIGINTERN int +_wrap_nx_getdata(ClientData clientData SWIGUNUSED, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { + void *arg1 = (void *) 0 ; + void *result = 0 ; + int res1 ; + + if (SWIG_GetArgs(interp, objc, objv,"o:nx_getdata handle ",(void *)0) == TCL_ERROR) SWIG_fail; + res1 = SWIG_ConvertPtr(objv[1],SWIG_as_voidptrptr(&arg1), 0, 0); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "nx_getdata" "', argument " "1"" of type '" "void *""'"); + } + result = (void *)nx_getdata(arg1); + Tcl_SetObjResult(interp, SWIG_NewInstanceObj( SWIG_as_voidptr(result), SWIGTYPE_p_void,0)); + return TCL_OK; +fail: + return TCL_ERROR; +} + + +SWIGINTERN int +_wrap_nx_putdata(ClientData clientData SWIGUNUSED, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { + void *arg1 = (void *) 0 ; + void *arg2 = (void *) 0 ; + int result; + int res1 ; + int res2 ; + + if (SWIG_GetArgs(interp, objc, objv,"oo:nx_putdata handle dataset ",(void *)0,(void *)0) == TCL_ERROR) SWIG_fail; + res1 = SWIG_ConvertPtr(objv[1],SWIG_as_voidptrptr(&arg1), 0, 0); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "nx_putdata" "', argument " "1"" of type '" "void *""'"); + } + res2 = SWIG_ConvertPtr(objv[2],SWIG_as_voidptrptr(&arg2), 0, 0); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "nx_putdata" "', argument " "2"" of type '" "void *""'"); + } + result = (int)nx_putdata(arg1,arg2); + Tcl_SetObjResult(interp,SWIG_From_int((int)(result))); + return TCL_OK; +fail: + return TCL_ERROR; +} + + +SWIGINTERN int +_wrap_nx_getinfo(ClientData clientData SWIGUNUSED, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { + void *arg1 = (void *) 0 ; + void *result = 0 ; + int res1 ; + + if (SWIG_GetArgs(interp, objc, objv,"o:nx_getinfo handle ",(void *)0) == TCL_ERROR) SWIG_fail; + res1 = SWIG_ConvertPtr(objv[1],SWIG_as_voidptrptr(&arg1), 0, 0); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "nx_getinfo" "', argument " "1"" of type '" "void *""'"); + } + result = (void *)nx_getinfo(arg1); + Tcl_SetObjResult(interp, SWIG_NewInstanceObj( SWIG_as_voidptr(result), SWIGTYPE_p_void,0)); + return TCL_OK; +fail: + return TCL_ERROR; +} + + +SWIGINTERN int +_wrap_nx_getdataID(ClientData clientData SWIGUNUSED, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { + void *arg1 = (void *) 0 ; + void *result = 0 ; + int res1 ; + + if (SWIG_GetArgs(interp, objc, objv,"o:nx_getdataID handle ",(void *)0) == TCL_ERROR) SWIG_fail; + res1 = SWIG_ConvertPtr(objv[1],SWIG_as_voidptrptr(&arg1), 0, 0); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "nx_getdataID" "', argument " "1"" of type '" "void *""'"); + } + result = (void *)nx_getdataID(arg1); + Tcl_SetObjResult(interp, SWIG_NewInstanceObj( SWIG_as_voidptr(result), SWIGTYPE_p_void,0)); + return TCL_OK; +fail: + return TCL_ERROR; +} + + +SWIGINTERN int +_wrap_nx_getnextattr(ClientData clientData SWIGUNUSED, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { + void *arg1 = (void *) 0 ; + char arg2 ; + char *result = 0 ; + int res1 ; + char val2 ; + int ecode2 = 0 ; + + if (SWIG_GetArgs(interp, objc, objv,"oo:nx_getnextattr handle separator ",(void *)0,(void *)0) == TCL_ERROR) SWIG_fail; + res1 = SWIG_ConvertPtr(objv[1],SWIG_as_voidptrptr(&arg1), 0, 0); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "nx_getnextattr" "', argument " "1"" of type '" "void *""'"); + } + ecode2 = SWIG_AsVal_char SWIG_TCL_CALL_ARGS_2(objv[2], &val2); + if (!SWIG_IsOK(ecode2)) { + SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "nx_getnextattr" "', argument " "2"" of type '" "char""'"); + } + arg2 = (char)(val2); + result = (char *)nx_getnextattr(arg1,arg2); + Tcl_SetObjResult(interp,SWIG_FromCharPtr((const char *)result)); + return TCL_OK; +fail: + return TCL_ERROR; +} + + +SWIGINTERN int +_wrap_nx_putattr(ClientData clientData SWIGUNUSED, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { + void *arg1 = (void *) 0 ; + char *arg2 = (char *) 0 ; + void *arg3 = (void *) 0 ; + int result; + int res1 ; + int res2 ; + char *buf2 = 0 ; + int alloc2 = 0 ; + int res3 ; + + if (SWIG_GetArgs(interp, objc, objv,"ooo:nx_putattr handle name ds ",(void *)0,(void *)0,(void *)0) == TCL_ERROR) SWIG_fail; + res1 = SWIG_ConvertPtr(objv[1],SWIG_as_voidptrptr(&arg1), 0, 0); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "nx_putattr" "', argument " "1"" of type '" "void *""'"); + } + res2 = SWIG_AsCharPtrAndSize(objv[2], &buf2, NULL, &alloc2); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "nx_putattr" "', argument " "2"" of type '" "char *""'"); + } + arg2 = (char *)(buf2); + res3 = SWIG_ConvertPtr(objv[3],SWIG_as_voidptrptr(&arg3), 0, 0); + if (!SWIG_IsOK(res3)) { + SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "nx_putattr" "', argument " "3"" of type '" "void *""'"); + } + result = (int)nx_putattr(arg1,arg2,arg3); + Tcl_SetObjResult(interp,SWIG_From_int((int)(result))); + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + return TCL_OK; +fail: + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + return TCL_ERROR; +} + + +SWIGINTERN int +_wrap_nx_getattr(ClientData clientData SWIGUNUSED, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { + void *arg1 = (void *) 0 ; + char *arg2 = (char *) 0 ; + int arg3 ; + int arg4 ; + void *result = 0 ; + int res1 ; + int res2 ; + char *buf2 = 0 ; + int alloc2 = 0 ; + int val3 ; + int ecode3 = 0 ; + int val4 ; + int ecode4 = 0 ; + + if (SWIG_GetArgs(interp, objc, objv,"oooo:nx_getattr handle name type length ",(void *)0,(void *)0,(void *)0,(void *)0) == TCL_ERROR) SWIG_fail; + res1 = SWIG_ConvertPtr(objv[1],SWIG_as_voidptrptr(&arg1), 0, 0); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "nx_getattr" "', argument " "1"" of type '" "void *""'"); + } + res2 = SWIG_AsCharPtrAndSize(objv[2], &buf2, NULL, &alloc2); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "nx_getattr" "', argument " "2"" of type '" "char *""'"); + } + arg2 = (char *)(buf2); + ecode3 = SWIG_AsVal_int SWIG_TCL_CALL_ARGS_2(objv[3], &val3); + if (!SWIG_IsOK(ecode3)) { + SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "nx_getattr" "', argument " "3"" of type '" "int""'"); + } + arg3 = (int)(val3); + ecode4 = SWIG_AsVal_int SWIG_TCL_CALL_ARGS_2(objv[4], &val4); + if (!SWIG_IsOK(ecode4)) { + SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "nx_getattr" "', argument " "4"" of type '" "int""'"); + } + arg4 = (int)(val4); + result = (void *)nx_getattr(arg1,arg2,arg3,arg4); + Tcl_SetObjResult(interp, SWIG_NewInstanceObj( SWIG_as_voidptr(result), SWIGTYPE_p_void,0)); + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + return TCL_OK; +fail: + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + return TCL_ERROR; +} + + +SWIGINTERN int +_wrap_nx_makelink(ClientData clientData SWIGUNUSED, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { + void *arg1 = (void *) 0 ; + void *arg2 = (void *) 0 ; + int result; + int res1 ; + int res2 ; + + if (SWIG_GetArgs(interp, objc, objv,"oo:nx_makelink handle link ",(void *)0,(void *)0) == TCL_ERROR) SWIG_fail; + res1 = SWIG_ConvertPtr(objv[1],SWIG_as_voidptrptr(&arg1), 0, 0); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "nx_makelink" "', argument " "1"" of type '" "void *""'"); + } + res2 = SWIG_ConvertPtr(objv[2],SWIG_as_voidptrptr(&arg2), 0, 0); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "nx_makelink" "', argument " "2"" of type '" "void *""'"); + } + result = (int)nx_makelink(arg1,arg2); + Tcl_SetObjResult(interp,SWIG_From_int((int)(result))); + return TCL_OK; +fail: + return TCL_ERROR; +} + + +SWIGINTERN int +_wrap_nx_opensourcegroup(ClientData clientData SWIGUNUSED, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { + void *arg1 = (void *) 0 ; + int result; + int res1 ; + + if (SWIG_GetArgs(interp, objc, objv,"o:nx_opensourcegroup handle ",(void *)0) == TCL_ERROR) SWIG_fail; + res1 = SWIG_ConvertPtr(objv[1],SWIG_as_voidptrptr(&arg1), 0, 0); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "nx_opensourcegroup" "', argument " "1"" of type '" "void *""'"); + } + result = (int)nx_opensourcegroup(arg1); + Tcl_SetObjResult(interp,SWIG_From_int((int)(result))); + return TCL_OK; +fail: + return TCL_ERROR; +} + + + +static swig_command_info swig_commands[] = { + { SWIG_prefix "create_nxds", (swig_wrapper_func) _wrap_create_nxds, NULL}, + { SWIG_prefix "create_text_nxds", (swig_wrapper_func) _wrap_create_text_nxds, NULL}, + { SWIG_prefix "drop_nxds", (swig_wrapper_func) _wrap_drop_nxds, NULL}, + { SWIG_prefix "get_nxds_rank", (swig_wrapper_func) _wrap_get_nxds_rank, NULL}, + { SWIG_prefix "get_nxds_type", (swig_wrapper_func) _wrap_get_nxds_type, NULL}, + { SWIG_prefix "get_nxds_dim", (swig_wrapper_func) _wrap_get_nxds_dim, NULL}, + { SWIG_prefix "get_nxds_value", (swig_wrapper_func) _wrap_get_nxds_value, NULL}, + { SWIG_prefix "get_nxds_text", (swig_wrapper_func) _wrap_get_nxds_text, NULL}, + { SWIG_prefix "put_nxds_value", (swig_wrapper_func) _wrap_put_nxds_value, NULL}, + { SWIG_prefix "nx_getlasterror", (swig_wrapper_func) _wrap_nx_getlasterror, NULL}, + { SWIG_prefix "nx_open", (swig_wrapper_func) _wrap_nx_open, NULL}, + { SWIG_prefix "nx_flush", (swig_wrapper_func) _wrap_nx_flush, NULL}, + { SWIG_prefix "nx_close", (swig_wrapper_func) _wrap_nx_close, NULL}, + { SWIG_prefix "nx_makegroup", (swig_wrapper_func) _wrap_nx_makegroup, NULL}, + { SWIG_prefix "nx_opengroup", (swig_wrapper_func) _wrap_nx_opengroup, NULL}, + { SWIG_prefix "nx_openpath", (swig_wrapper_func) _wrap_nx_openpath, NULL}, + { SWIG_prefix "nx_opengrouppath", (swig_wrapper_func) _wrap_nx_opengrouppath, NULL}, + { SWIG_prefix "nx_closegroup", (swig_wrapper_func) _wrap_nx_closegroup, NULL}, + { SWIG_prefix "nx_getnextentry", (swig_wrapper_func) _wrap_nx_getnextentry, NULL}, + { SWIG_prefix "nx_getgroupID", (swig_wrapper_func) _wrap_nx_getgroupID, NULL}, + { SWIG_prefix "nx_initgroupdir", (swig_wrapper_func) _wrap_nx_initgroupdir, NULL}, + { SWIG_prefix "nx_makedata", (swig_wrapper_func) _wrap_nx_makedata, NULL}, + { SWIG_prefix "nx_compmakedata", (swig_wrapper_func) _wrap_nx_compmakedata, NULL}, + { SWIG_prefix "nx_opendata", (swig_wrapper_func) _wrap_nx_opendata, NULL}, + { SWIG_prefix "nx_closedata", (swig_wrapper_func) _wrap_nx_closedata, NULL}, + { SWIG_prefix "nx_putslab", (swig_wrapper_func) _wrap_nx_putslab, NULL}, + { SWIG_prefix "nx_getslab", (swig_wrapper_func) _wrap_nx_getslab, NULL}, + { SWIG_prefix "nx_getds", (swig_wrapper_func) _wrap_nx_getds, NULL}, + { SWIG_prefix "nx_putds", (swig_wrapper_func) _wrap_nx_putds, NULL}, + { SWIG_prefix "nx_getdata", (swig_wrapper_func) _wrap_nx_getdata, NULL}, + { SWIG_prefix "nx_putdata", (swig_wrapper_func) _wrap_nx_putdata, NULL}, + { SWIG_prefix "nx_getinfo", (swig_wrapper_func) _wrap_nx_getinfo, NULL}, + { SWIG_prefix "nx_getdataID", (swig_wrapper_func) _wrap_nx_getdataID, NULL}, + { SWIG_prefix "nx_getnextattr", (swig_wrapper_func) _wrap_nx_getnextattr, NULL}, + { SWIG_prefix "nx_putattr", (swig_wrapper_func) _wrap_nx_putattr, NULL}, + { SWIG_prefix "nx_getattr", (swig_wrapper_func) _wrap_nx_getattr, NULL}, + { SWIG_prefix "nx_makelink", (swig_wrapper_func) _wrap_nx_makelink, NULL}, + { SWIG_prefix "nx_opensourcegroup", (swig_wrapper_func) _wrap_nx_opensourcegroup, NULL}, + {0, 0, 0} +}; + +static swig_var_info swig_variables[] = { + {0,0,0,0} +}; + +static swig_const_info swig_constants[] = { + {0,0,0,0,0,0} +}; + +/* -------- TYPE CONVERSION AND EQUIVALENCE RULES (BEGIN) -------- */ + +static swig_type_info _swigt__p_char = {"_p_char", "char *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_void = {"_p_void", "void *", 0, 0, (void*)0, 0}; + +static swig_type_info *swig_type_initial[] = { + &_swigt__p_char, + &_swigt__p_void, +}; + +static swig_cast_info _swigc__p_char[] = { {&_swigt__p_char, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_void[] = { {&_swigt__p_void, 0, 0, 0},{0, 0, 0, 0}}; + +static swig_cast_info *swig_cast_initial[] = { + _swigc__p_char, + _swigc__p_void, +}; + + +/* -------- TYPE CONVERSION AND EQUIVALENCE RULES (END) -------- */ + +#ifdef __cplusplus +} +#endif +/* ----------------------------------------------------------------------------- + * Type initialization: + * This problem is tough by the requirement that no dynamic + * memory is used. Also, since swig_type_info structures store pointers to + * swig_cast_info structures and swig_cast_info structures store pointers back + * to swig_type_info structures, we need some lookup code at initialization. + * The idea is that swig generates all the structures that are needed. + * The runtime then collects these partially filled structures. + * The SWIG_InitializeModule function takes these initial arrays out of + * swig_module, and does all the lookup, filling in the swig_module.types + * array with the correct data and linking the correct swig_cast_info + * structures together. + * + * The generated swig_type_info structures are assigned staticly to an initial + * array. We just loop through that array, and handle each type individually. + * First we lookup if this type has been already loaded, and if so, use the + * loaded structure instead of the generated one. Then we have to fill in the + * cast linked list. The cast data is initially stored in something like a + * two-dimensional array. Each row corresponds to a type (there are the same + * number of rows as there are in the swig_type_initial array). Each entry in + * a column is one of the swig_cast_info structures for that type. + * The cast_initial array is actually an array of arrays, because each row has + * a variable number of columns. So to actually build the cast linked list, + * we find the array of casts associated with the type, and loop through it + * adding the casts to the list. The one last trick we need to do is making + * sure the type pointer in the swig_cast_info struct is correct. + * + * First off, we lookup the cast->type name to see if it is already loaded. + * There are three cases to handle: + * 1) If the cast->type has already been loaded AND the type we are adding + * casting info to has not been loaded (it is in this module), THEN we + * replace the cast->type pointer with the type pointer that has already + * been loaded. + * 2) If BOTH types (the one we are adding casting info to, and the + * cast->type) are loaded, THEN the cast info has already been loaded by + * the previous module so we just ignore it. + * 3) Finally, if cast->type has not already been loaded, then we add that + * swig_cast_info to the linked list (because the cast->type) pointer will + * be correct. + * ----------------------------------------------------------------------------- */ + +#ifdef __cplusplus +extern "C" { +#if 0 +} /* c-mode */ +#endif +#endif + +#if 0 +#define SWIGRUNTIME_DEBUG +#endif + + +SWIGRUNTIME void +SWIG_InitializeModule(void *clientdata) { + size_t i; + swig_module_info *module_head, *iter; + int found; + + clientdata = clientdata; + + /* check to see if the circular list has been setup, if not, set it up */ + if (swig_module.next==0) { + /* Initialize the swig_module */ + swig_module.type_initial = swig_type_initial; + swig_module.cast_initial = swig_cast_initial; + swig_module.next = &swig_module; + } + + /* Try and load any already created modules */ + module_head = SWIG_GetModule(clientdata); + if (!module_head) { + /* This is the first module loaded for this interpreter */ + /* so set the swig module into the interpreter */ + SWIG_SetModule(clientdata, &swig_module); + module_head = &swig_module; + } else { + /* the interpreter has loaded a SWIG module, but has it loaded this one? */ + found=0; + iter=module_head; + do { + if (iter==&swig_module) { + found=1; + break; + } + iter=iter->next; + } while (iter!= module_head); + + /* if the is found in the list, then all is done and we may leave */ + if (found) return; + /* otherwise we must add out module into the list */ + swig_module.next = module_head->next; + module_head->next = &swig_module; + } + + /* Now work on filling in swig_module.types */ +#ifdef SWIGRUNTIME_DEBUG + printf("SWIG_InitializeModule: size %d\n", swig_module.size); +#endif + for (i = 0; i < swig_module.size; ++i) { + swig_type_info *type = 0; + swig_type_info *ret; + swig_cast_info *cast; + +#ifdef SWIGRUNTIME_DEBUG + printf("SWIG_InitializeModule: type %d %s\n", i, swig_module.type_initial[i]->name); +#endif + + /* if there is another module already loaded */ + if (swig_module.next != &swig_module) { + type = SWIG_MangledTypeQueryModule(swig_module.next, &swig_module, swig_module.type_initial[i]->name); + } + if (type) { + /* Overwrite clientdata field */ +#ifdef SWIGRUNTIME_DEBUG + printf("SWIG_InitializeModule: found type %s\n", type->name); +#endif + if (swig_module.type_initial[i]->clientdata) { + type->clientdata = swig_module.type_initial[i]->clientdata; +#ifdef SWIGRUNTIME_DEBUG + printf("SWIG_InitializeModule: found and overwrite type %s \n", type->name); +#endif + } + } else { + type = swig_module.type_initial[i]; + } + + /* Insert casting types */ + cast = swig_module.cast_initial[i]; + while (cast->type) { + /* Don't need to add information already in the list */ + ret = 0; +#ifdef SWIGRUNTIME_DEBUG + printf("SWIG_InitializeModule: look cast %s\n", cast->type->name); +#endif + if (swig_module.next != &swig_module) { + ret = SWIG_MangledTypeQueryModule(swig_module.next, &swig_module, cast->type->name); +#ifdef SWIGRUNTIME_DEBUG + if (ret) printf("SWIG_InitializeModule: found cast %s\n", ret->name); +#endif + } + if (ret) { + if (type == swig_module.type_initial[i]) { +#ifdef SWIGRUNTIME_DEBUG + printf("SWIG_InitializeModule: skip old type %s\n", ret->name); +#endif + cast->type = ret; + ret = 0; + } else { + /* Check for casting already in the list */ + swig_cast_info *ocast = SWIG_TypeCheck(ret->name, type); +#ifdef SWIGRUNTIME_DEBUG + if (ocast) printf("SWIG_InitializeModule: skip old cast %s\n", ret->name); +#endif + if (!ocast) ret = 0; + } + } + + if (!ret) { +#ifdef SWIGRUNTIME_DEBUG + printf("SWIG_InitializeModule: adding cast %s\n", cast->type->name); +#endif + if (type->cast) { + type->cast->prev = cast; + cast->next = type->cast; + } + type->cast = cast; + } + cast++; + } + /* Set entry in modules->types array equal to the type */ + swig_module.types[i] = type; + } + swig_module.types[i] = 0; + +#ifdef SWIGRUNTIME_DEBUG + printf("**** SWIG_InitializeModule: Cast List ******\n"); + for (i = 0; i < swig_module.size; ++i) { + int j = 0; + swig_cast_info *cast = swig_module.cast_initial[i]; + printf("SWIG_InitializeModule: type %d %s\n", i, swig_module.type_initial[i]->name); + while (cast->type) { + printf("SWIG_InitializeModule: cast type %s\n", cast->type->name); + cast++; + ++j; + } + printf("---- Total casts: %d\n",j); + } + printf("**** SWIG_InitializeModule: Cast List ******\n"); +#endif +} + +/* This function will propagate the clientdata field of type to +* any new swig_type_info structures that have been added into the list +* of equivalent types. It is like calling +* SWIG_TypeClientData(type, clientdata) a second time. +*/ +SWIGRUNTIME void +SWIG_PropagateClientData(void) { + size_t i; + swig_cast_info *equiv; + static int init_run = 0; + + if (init_run) return; + init_run = 1; + + for (i = 0; i < swig_module.size; i++) { + if (swig_module.types[i]->clientdata) { + equiv = swig_module.types[i]->cast; + while (equiv) { + if (!equiv->converter) { + if (equiv->type && !equiv->type->clientdata) + SWIG_TypeClientData(equiv->type, swig_module.types[i]->clientdata); + } + equiv = equiv->next; + } + } + } +} + +#ifdef __cplusplus +#if 0 +{ + /* c-mode */ +#endif +} +#endif + + +#ifdef __cplusplus +extern "C" { +#endif + + /* ----------------------------------------------------------------------------- + * constants/methods manipulation + * ----------------------------------------------------------------------------- */ + + /* Install Constants */ + + SWIGINTERN void + SWIG_Tcl_InstallConstants(Tcl_Interp *interp, swig_const_info constants[]) { + int i; + Tcl_Obj *obj; + + if (!swigconstTableinit) { + Tcl_InitHashTable(&swigconstTable, TCL_STRING_KEYS); + swigconstTableinit = 1; + } + for (i = 0; constants[i].type; i++) { + switch(constants[i].type) { + case SWIG_TCL_POINTER: + obj = SWIG_NewPointerObj(constants[i].pvalue, *(constants[i]).ptype,0); + break; + case SWIG_TCL_BINARY: + obj = SWIG_NewPackedObj(constants[i].pvalue, constants[i].lvalue, *(constants[i].ptype)); + break; + default: + obj = 0; + break; + } + if (obj) { + SWIG_Tcl_SetConstantObj(interp, constants[i].name, obj); + } + } + } + +#ifdef __cplusplus +} +#endif + +/* -----------------------------------------------------------------------------* + * Partial Init method + * -----------------------------------------------------------------------------*/ + +SWIGEXPORT int SWIG_init(Tcl_Interp *interp) { + int i; + if (interp == 0) return TCL_ERROR; +#ifdef USE_TCL_STUBS + if (Tcl_InitStubs(interp, (char*)"8.1", 0) == NULL) { + return TCL_ERROR; + } +#endif + Tcl_PkgProvide(interp, (char*)SWIG_name, (char*)SWIG_version); + +#ifdef SWIG_namespace + Tcl_Eval(interp, "namespace eval " SWIG_namespace " { }"); +#endif + + SWIG_InitializeModule((void *) interp); + SWIG_PropagateClientData(); + + for (i = 0; swig_commands[i].name; i++) { + Tcl_CreateObjCommand(interp, (char *) swig_commands[i].name, (swig_wrapper_func) swig_commands[i].wrapper, + swig_commands[i].clientdata, NULL); + } + for (i = 0; swig_variables[i].name; i++) { + Tcl_SetVar(interp, (char *) swig_variables[i].name, (char *) "", TCL_GLOBAL_ONLY); + Tcl_TraceVar(interp, (char *) swig_variables[i].name, TCL_TRACE_READS | TCL_GLOBAL_ONLY, + (Tcl_VarTraceProc *) swig_variables[i].get, (ClientData) swig_variables[i].addr); + Tcl_TraceVar(interp, (char *) swig_variables[i].name, TCL_TRACE_WRITES | TCL_GLOBAL_ONLY, + (Tcl_VarTraceProc *) swig_variables[i].set, (ClientData) swig_variables[i].addr); + } + + SWIG_Tcl_InstallConstants(interp, swig_constants); + + + SWIG_Tcl_SetConstantObj(interp, "NXACC_READ", SWIG_From_int((int)(1))); + SWIG_Tcl_SetConstantObj(interp, "NXACC_RDWR", SWIG_From_int((int)(2))); + SWIG_Tcl_SetConstantObj(interp, "NXACC_CREATE", SWIG_From_int((int)(3))); + SWIG_Tcl_SetConstantObj(interp, "NXACC_CREATE4", SWIG_From_int((int)(4))); + SWIG_Tcl_SetConstantObj(interp, "NXACC_CREATE5", SWIG_From_int((int)(5))); + SWIG_Tcl_SetConstantObj(interp, "NX_FLOAT32", SWIG_From_int((int)(5))); + SWIG_Tcl_SetConstantObj(interp, "NX_FLOAT64", SWIG_From_int((int)(6))); + SWIG_Tcl_SetConstantObj(interp, "NX_INT8", SWIG_From_int((int)(20))); + SWIG_Tcl_SetConstantObj(interp, "NX_UINT8", SWIG_From_int((int)(21))); + SWIG_Tcl_SetConstantObj(interp, "NX_BOOLEAN", SWIG_From_int((int)(21))); + SWIG_Tcl_SetConstantObj(interp, "NX_INT16", SWIG_From_int((int)(22))); + SWIG_Tcl_SetConstantObj(interp, "NX_UINT16", SWIG_From_int((int)(23))); + SWIG_Tcl_SetConstantObj(interp, "NX_INT32", SWIG_From_int((int)(24))); + SWIG_Tcl_SetConstantObj(interp, "NX_UINT32", SWIG_From_int((int)(25))); + SWIG_Tcl_SetConstantObj(interp, "NX_CHAR", SWIG_From_int((int)(4))); + return TCL_OK; +} +SWIGEXPORT int Nxinter_SafeInit(Tcl_Interp *interp) { + return SWIG_init(interp); +} + diff --git a/nxinterhelper.c b/nxinterhelper.c new file mode 100644 index 00000000..723e0adf --- /dev/null +++ b/nxinterhelper.c @@ -0,0 +1,561 @@ +/* + This is a library of support functions and data structures which can be + used in order to create interfaces between the NeXus-API and scripting + languages or data analysis systems with a native code interface. + + copyright: GPL + + Mark Koennecke, October 2002 + Mark Koennecke, November 2002 +*/ +#include +#include +#include +#include +#include "nxinterhelper.h" +#include "nxdataset.h" +/*----------------------------------------------------------------- + An own error handler. nx_getlasterror will return the test of + the last NeXus error. + --------------------------------------------------------------------*/ +static char errorText[256]= ""; + +static void nxinterError(void *pData, char *error){ + strncpy(errorText,error,255); +} +/*-----------------------------------------------------------------------*/ +char *nx_getlasterror(void){ + return strdup(errorText); +} +/*-------------------- opening and closing -------------------------------*/ +void *nx_open(char *filename, int accessMethod){ + NXhandle handle = NULL; + int status; + + NXMSetError(NULL,nxinterError); + status = NXopen(filename,(NXaccess)accessMethod, &handle); + if(status == NX_OK){ + return handle; + }else{ + return NULL; + } +} +/*------------------------------------------------------------------------*/ +void *nx_flush(void *hundle){ + NXhandle handle; + int status; + + handle = (NXhandle)hundle; + status = NXflush(&handle); + if(status == NX_OK){ + return handle; + } else { + return NULL; + } +} +/*-----------------------------------------------------------------------*/ +void nx_close(void *hundle){ + NXhandle handle; + + handle = (NXhandle)hundle; + NXclose(&handle); +} +/*=================== group handling functions ========================*/ +int nx_makegroup(void *handle, char *name, char *nxclass){ + int status; + NXhandle hfil; + + hfil = (NXhandle)handle; + status = NXmakegroup(hfil,name, nxclass); + if(status == NX_OK){ + return 1; + } else { + return 0; + } +} +/*---------------------------------------------------------------------*/ +int nx_opengroup(void *handle, char *name, char *nxclass){ + int status; + NXhandle hfil; + + hfil = (NXhandle)handle; + status = NXopengroup(hfil,name, nxclass); + if(status == NX_OK){ + return 1; + } else { + return 0; + } +} +/*---------------------------------------------------------------------*/ +int nx_openpath(void *handle, char *path){ + int status; + NXhandle hfil; + + hfil = (NXhandle)handle; + status = NXopenpath(hfil,path); + if(status == NX_OK){ + return 1; + } else { + return 0; + } +} +/*---------------------------------------------------------------------*/ +int nx_opengrouppath(void *handle, char *path){ + int status; + NXhandle hfil; + + hfil = (NXhandle)handle; + status = NXopengrouppath(hfil,path); + if(status == NX_OK){ + return 1; + } else { + return 0; + } +} +/*--------------------------------------------------------------------*/ +int nx_closegroup(void *handle){ + int status; + NXhandle hfil; + + hfil = (NXhandle)handle; + status = NXclosegroup(hfil); + if(status == NX_OK){ + return 1; + } else { + return 0; + } +} +/*-------------------------------------------------------------------*/ +char *nx_getnextentry(void *handle, char separator){ + int status, length, type; + NXhandle hfil; + char *resultBuffer = NULL; + NXname group,nxclass; + + hfil = (NXhandle)handle; + status = NXgetnextentry(hfil,group, nxclass,&type); + if(status == NX_OK){ + length = 30 + strlen(group) + strlen(nxclass); + /* + This introduces a memory leak. I had hoped, that swig would + kill it for me after use, but I'am afraid, this is not the + case. Unfortately I do not know how to fix the issue. + */ + resultBuffer = (char *)malloc(length*sizeof(char)); + if(resultBuffer == NULL){ + return NULL; + } + sprintf(resultBuffer,"%s%c%s%c%d",group,separator,nxclass, + separator,type); + return resultBuffer; + } else { + return NULL; + } +} +/*-------------------------------------------------------------------*/ +void *nx_getgroupID(void *handle){ + int status; + NXhandle hfil; + NXlink *linki; + + linki = (NXlink *)malloc(sizeof(NXlink)); + if(linki == NULL){ + return NULL; + } + hfil = (NXhandle)handle; + status = NXgetgroupID(hfil,linki); + if(status == NX_OK){ + return linki; + } else { + return NULL; + } +} +/*------------------------------------------------------------------*/ +int nx_initgroupdir(void *handle){ + int status; + NXhandle hfil; + + hfil = (NXhandle)handle; + status = NXinitgroupdir(hfil); + if(status == NX_OK){ + return 1; + } else { + return 0; + } +} +/*========================== dataset handling =======================*/ +int nx_makedata(void *ptr, char *name, int rank, int type, + void *dimPtr){ + int status; + NXhandle hfil; + pNXDS dimData; + + hfil = (NXhandle)ptr; + dimData = (pNXDS)dimPtr; + if(dimData->type != NX_INT32){ + NXIReportError(NULL,"ERROR: dimension data not integer"); + return 0; + } + status = NXmakedata(hfil, name, type, rank, + dimData->u.iPtr); + if(status == NX_OK){ + return 1; + } else { + return 0; + } +} +/*--------------------------------------------------------------------*/ +int nx_compmakedata(void *ptr, char *name, int rank, int type, + void *dimPtr, void *bufPtr){ + int status; + NXhandle hfil; + pNXDS dimData, bufData; + + hfil = (NXhandle)ptr; + dimData = (pNXDS)dimPtr; + if(dimData->type != NX_INT32){ + NXIReportError(NULL,"ERROR: dimension data not integer"); + return 0; + } + bufData = (pNXDS)bufPtr; + status = NXcompmakedata(hfil, name, type, rank, + dimData->u.iPtr, NX_COMP_LZW,bufData->u.iPtr); + if(status == NX_OK){ + return 1; + } else { + return 0; + } +} +/*----------------------------------------------------------------------*/ +int nx_opendata(void *handle, char *name){ + int status; + NXhandle hfil; + + hfil = (NXhandle)handle; + status = NXopendata(hfil,name); + if(status == NX_OK){ + return 1; + } else { + return 0; + } +} +/*----------------------------------------------------------------------*/ +int nx_closedata(void *handle){ + int status; + NXhandle hfil; + + hfil = (NXhandle)handle; + status = NXclosedata(hfil); + if(status == NX_OK){ + return 1; + } else { + return 0; + } +} +/*------------------------------------------------------------------------*/ +int nx_putslab(void *handle, void *dataset, void *startDim){ + int status; + NXhandle hfil; + pNXDS data; + pNXDS start; + int end[NX_MAXRANK], i; + + hfil = (NXhandle)handle; + data = (pNXDS)dataset; + start = (pNXDS)startDim; + for(i = 0; i < data->rank;i++){ + end[i] = data->dim[i]; + } + + status = NXputslab(hfil,data->u.ptr,start->u.iPtr,end); + if(status == NX_OK){ + return 1; + } else { + return 0; + } +} +/*-----------------------------------------------------------------------*/ +void *nx_getslab(void *handle, void *startdim, void *sizedim){ + pNXDS resultdata; + pNXDS start, size; + int status, rank, type, dim[NX_MAXRANK]; + NXhandle hfil; + + hfil = (NXhandle)handle; + start = (pNXDS)startdim; + size = (pNXDS)sizedim; + + /* + get info first, then allocate data + */ + status = NXgetinfo(hfil, &rank,dim,&type); + if(status != NX_OK){ + return NULL; + } + + resultdata = createNXDataset(rank,type,size->u.iPtr); + if(resultdata == NULL){ + return NULL; + } + + status = NXgetslab(hfil,resultdata->u.ptr,start->u.iPtr, + size->u.iPtr); + if(status == NX_OK){ + return resultdata; + }else{ + dropNXDataset(resultdata); + return NULL; + } +} +/*------------------------------------------------------------------------*/ +void *nx_getds(void *handle, char *name){ + pNXDS result = NULL; + int rank, type,dim[NX_MAXRANK],status; + NXhandle hfil; + + hfil = (NXhandle)handle; + status = NXopendata(hfil,name); + if(status != NX_OK){ + return NULL; + } + + status = NXgetinfo(hfil,&rank,dim,&type); + if(status != NX_OK){ + return NULL; + } + + result = createNXDataset(rank,type,dim); + if(result == NULL){ + NXclosedata(hfil); + return NULL; + } + + status = NXgetdata(hfil,result->u.ptr); + if(result == NULL){ + NXclosedata(hfil); + dropNXDataset(result); + return NULL; + } + NXclosedata(hfil); + return result; +} +/*----------------------------------------------------------------------*/ +int nx_putds(void *handle, char *name, void *dataset){ + NXhandle hfil; + int status; + pNXDS data; + + hfil = (NXhandle)handle; + data = (pNXDS)dataset; + + status = NXopendata(hfil,name); + if(status != NX_OK){ + status = NXmakedata(hfil,name,data->type,data->rank,data->dim); + if(status != NX_OK){ + return 0; + } + NXopendata(hfil,name); + } + + status = NXputdata(hfil,data->u.ptr); + NXclosedata(hfil); + if(status != NX_OK){ + return 0; + }else{ + return 1; + } +} +/*------------------------------------------------------------------------*/ +void *nx_getdata(void *handle){ + pNXDS result = NULL; + int rank, type,dim[NX_MAXRANK],status; + NXhandle hfil; + + + hfil = (NXhandle)handle; + status = NXgetinfo(hfil,&rank,dim,&type); + if(status != NX_OK){ + return NULL; + } + + result = createNXDataset(rank,type,dim); + if(result == NULL){ + NXclosedata(hfil); + return NULL; + } + + status = NXgetdata(hfil,result->u.ptr); + if(result == NULL){ + dropNXDataset(result); + return NULL; + } + return result; +} +/*----------------------------------------------------------------------*/ +int nx_putdata(void *handle, void *dataset){ + NXhandle hfil; + int status; + pNXDS data; + + hfil = (NXhandle)handle; + data = (pNXDS)dataset; + + if(data == NULL){ + NXIReportError(NULL,"ERROR: NULL data pointer in nx_putdata"); + return 0; + } + + status = NXputdata(hfil,data->u.ptr); + if(status != NX_OK){ + return 0; + }else{ + return 1; + } +} +/*----------------------------------------------------------------------*/ +void *nx_getinfo(void *handle){ + NXhandle hfil; + int status, type, rank, dim[NX_MAXRANK], rdim[1], i; + pNXDS data = NULL; + + hfil = (NXhandle)handle; + + status = NXgetinfo(handle,&rank,dim,&type); + if(status != NX_OK){ + return NULL; + } + rdim[0] = 2 + rank; + data = createNXDataset(1,NX_INT32,rdim); + data->u.iPtr[0] = type; + data->u.iPtr[1] = rank; + for(i = 0; i < rank; i++){ + data->u.iPtr[2+i] = dim[i]; + } + return data; +} +/*----------------------------------------------------------------------*/ +void *nx_getdataID(void *handle){ + NXhandle hfil; + int status; + NXlink *linki; + + linki = (NXlink *)malloc(sizeof(NXlink)); + if(linki == NULL){ + return NULL; + } + + hfil = (NXhandle)handle; + status = NXgetdataID(hfil,linki); + if(status == NX_OK){ + return linki; + } else { + free(linki); + return NULL; + } +} +/*-------------------------------------------------------------------*/ +char *nx_getnextattr(void *handle, char separator){ + int status, length, type; + char *result; + NXhandle hfil; + NXname aName; + + hfil = (NXhandle)handle; + status = NXgetnextattr(hfil,aName, &length, &type); + if(status == NX_OK){ + /* + This introduces a memory leak. I had hoped, that swig would + kill it for me after use, but I'am afraid, this is not the + case. Unfortately I do not know how to fix the issue. + */ + result = (char *)malloc((20+strlen(aName))*sizeof(char)); + if(result == NULL){ + return NULL; + } + memset(result,0,(20+strlen(aName))*sizeof(char)); + sprintf(result,"%s%c%d%c%d", aName,separator, + length,separator,type); + return result; + } else { + return NULL; + } +} +/*-------------------------------------------------------------------*/ +int nx_putattr(void *handle, char *name, void *ds){ + int status; + NXhandle hfil; + pNXDS data; + + hfil = (NXhandle)handle; + data = (pNXDS)ds; + status = NXputattr(hfil,name,data->u.ptr,data->dim[0],data->type); + if(status == NX_OK){ + return 1; + }else{ + return 0; + } +} +/*-------------------------------------------------------------------*/ +void *nx_getattr(void *handle, char *name, int type, int length){ + NXhandle hfil; + int status, tp, ll, dim[1]; + pNXDS data = NULL; + + + hfil = (NXhandle)handle; + + /* + prepare dataset + */ + dim[0] = length+1; + data = createNXDataset(1,type,dim); + if(data == NULL){ + return NULL; + } + + /* + finally read the real data + */ + ll = length; + tp = type; + status = NXgetattr(hfil,name,data->u.ptr,&ll,&tp); + if(status != NX_OK){ + dropNXDataset(data); + return NULL; + } + + return data; +} +/*-----------------------------------------------------------------------*/ +int nx_makelink(void *handle, void *link){ + NXhandle hfil; + NXlink* lk; + int status; + + hfil = (NXhandle)handle; + lk = (NXlink *)link; + + status = NXmakelink(hfil,lk); + if(status == NX_OK){ + return 1; + }else{ + return 0; + } +} +/*-----------------------------------------------------------------------*/ +int nx_opensourcegroup(void *handle){ + NXhandle hfil; + int status; + + hfil = (NXhandle)handle; + + status = NXopensourcegroup(hfil); + if(status == NX_OK){ + return 1; + }else{ + return 0; + } +} + + + diff --git a/nxinterhelper.h b/nxinterhelper.h new file mode 100644 index 00000000..7c2e280c --- /dev/null +++ b/nxinterhelper.h @@ -0,0 +1,68 @@ +/* + This is a library of support functions and data structures which can be + used in order to create interfaces between the NeXus-API and scripting + languages or data analysis systems with a native code interface. + + copyright: GPL + + Mark Koennecke, October 2002 +*/ + +#ifndef NXINTERHELPER +#define NXINTERHELPER + +#include + +/*------------- opening and closing section ---------------------*/ +void *nx_open(char *filename, int accessMethod); +void *nx_flush(void *handle); +void nx_close(void *handle); +/*--------------- group handling section ------------------------*/ +int nx_makegroup(void *handle, char *name, char *nxclass); +int nx_opengroup(void *handle, char *name, char *nxclass); +int nx_opengrouppath(void *handle, char *path); +int nx_openpath(void *handle, char *path); +int nx_closegroup(void *handle); +char *nx_getnextentry(void *handle, char separator); +void *nx_getgroupID(void *handle); +int nx_initgroupdir(void *handle); + +/*---------------- dataset handling -----------------------------*/ +int nx_makedata(void *ptr, char *name, int rank, int type, void *dimPtr); +int nx_compmakedata(void *ptr, char *name, int rank, int type, + void *dimPtr, void *bufPtr); + +int nx_opendata(void *handle, char *name); +int nx_closedata(void *handle); + +int nx_putslab(void *handle, void *dataset, void *startDim); +void *nx_getslab(void *handle, void *startdim, void *size); + +void *nx_getds(void *handle, char *name); +int nx_putds(void *handle, char *name, void *dataset); + +void *nx_getdata(void *handle); +int nx_putdata(void *handle,void *dataset); + +void *nx_getinfo(void *handle); +void *nx_getdataID(void *handle); + +/*-------------------- attributes --------------------------------*/ +char *nx_getnextattr(void *handle, char separator); +int nx_putattr(void *handle, char *name, void *ds); +void *nx_getattr(void *handle, char *name, int type, int length); + + +/*---------------------- link -----------------------------------*/ +int nx_makelink(void *handle, void *link); +int nx_opensourcegroup(void *handle); +/*----------------- error handling -----------------------------*/ +char *nx_getlasterror(void); + +#endif + + + + + + diff --git a/nxio.c b/nxio.c index ca5be754..a74145e9 100644 --- a/nxio.c +++ b/nxio.c @@ -25,8 +25,15 @@ */ #include #include +#include "napi.h" #include "nxio.h" #include "nxdataset.h" +#include "napiconfig.h" + +/* fix for mxml-2.3 */ +#ifndef MXML_WRAP +#define MXML_WRAP 79 +#endif /* #define TESTMAIN 1 */ /*=================== type code handling ================================= */ @@ -36,7 +43,8 @@ typedef struct { int nx_type; }type_code; -static type_code typecode[9]; +#define NTYPECODE 11 +static type_code typecode[NTYPECODE]; /*-----------------------------------------------------------------------*/ void initializeNumberFormats(){ type_code myCode; @@ -76,21 +84,31 @@ void initializeNumberFormats(){ myCode.nx_type = NX_INT32; typecode[6] = myCode; - strcpy(myCode.name,"NX_UNIT32"); + strcpy(myCode.name,"NX_UINT32"); strcpy(myCode.format,"%12d"); myCode.nx_type = NX_UINT32; typecode[7] = myCode; + strcpy(myCode.name,"NX_INT64"); + strcpy(myCode.format,"%24" PRINTF_INT64 ); + myCode.nx_type = NX_INT64; + typecode[8] = myCode; + + strcpy(myCode.name,"NX_UINT64"); + strcpy(myCode.format,"%24" PRINTF_UINT64); + myCode.nx_type = NX_UINT64; + typecode[9] = myCode; + strcpy(myCode.name,"NX_CHAR"); strcpy(myCode.format,"%c"); myCode.nx_type = NX_CHAR; - typecode[8] = myCode; + typecode[10] = myCode; } /*----------------------------------------------------------------------*/ void setNumberFormat(int nx_type, char *format){ int i; - for(i = 0; i < 9; i++){ + for(i = 0; i < NTYPECODE; i++){ if(typecode[i].nx_type == nx_type){ strncpy(typecode[i].format,format,29); } @@ -100,7 +118,7 @@ void setNumberFormat(int nx_type, char *format){ static void getNumberFormat(int nx_type, char format[30]){ int i; - for(i = 0; i < 9; i++){ + for(i = 0; i < NTYPECODE; i++){ if(typecode[i].nx_type == nx_type){ strncpy(format,typecode[i].format,29); } @@ -110,7 +128,7 @@ static void getNumberFormat(int nx_type, char format[30]){ void getNumberText(int nx_type, char *typestring, int typeLen){ int i; - for(i = 0; i < 9; i++){ + for(i = 0; i < NTYPECODE; i++){ if(typecode[i].nx_type == nx_type){ strncpy(typestring,typecode[i].name,typeLen); } @@ -138,9 +156,14 @@ myxml_add_char(int ch, /* I - Character to add */ */ if (*bufsize < 1024) + { (*bufsize) *= 2; + } else - (*bufsize) += 1024; + { + (*bufsize) *= 3; + (*bufsize) /= 2; + } newbuffer = (char *)malloc(*bufsize*sizeof(char)); if(!newbuffer){ @@ -204,7 +227,7 @@ extern char *stptok(char *s, char *tok, size_t toklen, char *brk); /*===================================================================== actual stuff for implementing the callback functions =====================================================================*/ -static void analyzeDim(const char *typeString, int *rank, +void analyzeDim(const char *typeString, int *rank, int *iDim, int *type){ char dimString[132]; char dim[20]; @@ -219,6 +242,8 @@ static void analyzeDim(const char *typeString, int *rank, case NX_UINT16: case NX_INT32: case NX_UINT32: + case NX_INT64: + case NX_UINT64: case NX_FLOAT32: case NX_FLOAT64: iDim[0] = 1; @@ -258,7 +283,7 @@ static void analyzeDim(const char *typeString, int *rank, int translateTypeCode(char *code){ int i, result = -1; - for(i = 0; i < 9; i++){ + for(i = 0; i < NTYPECODE; i++){ if(strstr(code,typecode[i].name) != NULL){ result = typecode[i].nx_type; break; @@ -346,7 +371,11 @@ mxml_type_t nexusTypeCallback(mxml_node_t *parent){ */ return MXML_OPAQUE; } else{ - return MXML_CUSTOM; + if(strstr(typeString,"NX_CHAR") != NULL){ + return MXML_OPAQUE; + } else { + return MXML_CUSTOM; + } } } } @@ -411,12 +440,19 @@ static void formatNumber(double value, char *txt, int txtLen, case NX_UINT32: snprintf(txt,txtLen,format,(int)value); break; + case NX_INT64: + snprintf(txt,txtLen,format,(int64_t)value); + break; + case NX_UINT64: + snprintf(txt,txtLen,format,(uint64_t)value); + break; case NX_FLOAT32: case NX_FLOAT64: snprintf(txt,txtLen,format,value); break; default: - assert(0); /* something is very wrong here */ + /*assert(0); something is very wrong here */ + printf("Problem\n"); break; } } @@ -534,8 +570,12 @@ static int isTextData(mxml_node_t *node){ } } /*---------------------------------------------------------------------*/ + +/* + * note: not reentrant or thead safe; returns pointer to static storage + */ const char *NXwhitespaceCallback(mxml_node_t *node, int where){ - char *indent; + static char *indent = NULL; int len; if(strstr(node->value.element.name,"?xml") != NULL){ @@ -545,6 +585,11 @@ const char *NXwhitespaceCallback(mxml_node_t *node, int where){ if(isTextData(node)){ if(where == MXML_WS_BEFORE_OPEN){ len = countDepth(node)*2 + 2; + if (indent != NULL) + { + free(indent); + indent = NULL; + } indent = (char *)malloc(len*sizeof(char)); if(indent != NULL){ memset(indent,' ',len); @@ -558,6 +603,11 @@ const char *NXwhitespaceCallback(mxml_node_t *node, int where){ if(where == MXML_WS_BEFORE_OPEN || where == MXML_WS_BEFORE_CLOSE){ len = countDepth(node)*2 + 2; + if (indent != NULL) + { + free(indent); + indent = NULL; + } indent = (char *)malloc(len*sizeof(char)); if(indent != NULL){ memset(indent,' ',len); diff --git a/nxio.h b/nxio.h index 98283779..0de80474 100644 --- a/nxio.h +++ b/nxio.h @@ -40,6 +40,8 @@ void getNumberText(int nx_type, char *typestring, int typeLen); void destroyDataset(void *data); int translateTypeCode(char *code); int isDataNode(mxml_node_t *node); +void analyzeDim(const char *typeString, int *rank, + int *iDim, int *type); #endif diff --git a/nxscript.c b/nxscript.c index f04b73df..a97178d2 100644 --- a/nxscript.c +++ b/nxscript.c @@ -668,7 +668,6 @@ static int listToArray(SicsInterp *pSics, char *list, return TCL_OK; } /*----------------------------------------------------------------------*/ -#define HANUM 3 static void putSlab(SConnection *pCon, SicsInterp *pSics, pNXScript self, int argc, char *argv[]){ int start[NX_MAXRANK], size[NX_MAXRANK]; @@ -676,16 +675,13 @@ static void putSlab(SConnection *pCon, SicsInterp *pSics, pNXScript self, pHistMem mem = NULL; HistInt *histData = NULL; pSICSData data = NULL; - char buffer[256]; - enum histargs {haStart, haLength, haBank}; - int i, haIndex, hpars[HANUM], haFirst=6; if(argc < 6){ SCWrite(pCon,"ERROR: insufficient number of arguments to putslab", eError); return; } - + status = NXDopenalias(self->fileHandle, self->dictHandle,argv[2]); if(status != NX_OK){ SCPrintf(pCon,eError,"ERROR: failed to open alias %s", argv[2]); @@ -709,37 +705,13 @@ static void putSlab(SConnection *pCon, SicsInterp *pSics, pNXScript self, */ mem = (pHistMem)FindCommandData(pSics,argv[5],"HistMem"); if(mem != NULL){ - if (argc == 6) { histData = GetHistogramPointer(mem,pCon); - } else if (argc > 6) { - for (i=0, haIndex=haFirst; i < HANUM; i++, haIndex++) { - status = Tcl_GetInt(InterpGetTcl(pSics),argv[haIndex],&hpars[i]); - if(status != TCL_OK){ - sprintf(buffer,"ERROR: failed to convert %s to integer", - argv[haIndex]); - SCWrite(pCon,buffer,eError); - return; - } + if(histData){ + status = NXputslab(self->fileHandle, histData, start, size); + if(status == NX_OK){ + written = 1; + } } - histData = (HistInt *)malloc(hpars[haLength]*sizeof(HistInt)); - if(!histData){ - SCWrite(pCon,"ERROR: out of memory for reading histogram memory", - eError); - return; - } - memset(histData,0,hpars[haLength]*sizeof(HistInt)); - status = GetHistogramDirect(mem,pCon,hpars[haBank], - hpars[haStart],hpars[haStart]+hpars[haLength],histData, - hpars[haLength]*sizeof(HistInt)); - } - if(histData){ - status = NXputslab(self->fileHandle, histData, start, size); - if(status == NX_OK){ - written = 1; - } - if (argc > 6) - free(histData); - } } /* @@ -917,125 +889,6 @@ static void putArray(SConnection *pCon, SicsInterp *pSics, free(data); SCSendOK(pCon); } -/* ANSTO MOD1 START */ -/**\brief Calculates polar angles on a 2D grid for cylindrical detectors. - * - * param angsep angular separation between detector columns in radians - * param active_height_mm of a detector in mm - * param det_rot_rad detector rotation in radians - * param col_zero horizontal pixel at beam centre for detector rotation of zero. - * param rownum number of detector rows - * param colnum number of detector columns - * - * Detector pixel layout uses display coordinates viewed from the sample. - * ie If you stand at the sample and face the detector the (0,0) is at the - * top left corner. - */ -float *G_TwoThetaArr=NULL; -void polar_angle(double angsep, double active_height_mm, double det_rot_rad, double col_zero, double rownum, double colnum) { - - int col; - double rowsep, alpha; - double deg_per_rad = 57.29578; - - if (G_TwoThetaArr != NULL) - free(G_TwoThetaArr); - - G_TwoThetaArr = (float *)malloc(colnum*sizeof(float)); - - - rowsep = active_height_mm/(rownum-1); - - for (col=0; col < colnum; col++) { - alpha = (col_zero - col)*angsep + det_rot_rad; - G_TwoThetaArr[col]=(float)(alpha*deg_per_rad); - } -} - -static void putPolarArray(SConnection *pCon, SicsInterp *pSics, - pNXScript self, - int argc, char *argv[]){ - int status, written=0; - int start[NX_MAXRANK], size[NX_MAXRANK]; - char buffer[256]; - Tcl_Interp *tcl = NULL; - - double angsep, det_rot_rad, active_height_mm; - double col_zero; - double rownum, colnum; - - if(argc < 11){ - SCWrite(pCon,"ERROR: insufficient number of arguments to array", - eError); - return; - } - tcl = InterpGetTcl(pSics); - assert(tcl != NULL); - - - status = listToArray(pSics,argv[3],start); - if(status != TCL_OK){ - SCWrite(pCon,"ERROR: failed to convert start value list", eError); - return; - } - - status = listToArray(pSics,argv[4],size); - if(status != TCL_OK){ - SCWrite(pCon,"ERROR: failed to convert size value list", eError); - return; - } - status = Tcl_GetDouble(tcl,argv[5],&angsep); - if(status != TCL_OK){ - sprintf(buffer,"ERROR: failed to convert %s to double",argv[5]); - SCWrite(pCon,buffer,eError); - return; - } - status = Tcl_GetDouble(tcl,argv[6],&active_height_mm); - if(status != TCL_OK){ - sprintf(buffer,"ERROR: failed to convert %s to double",argv[6]); - SCWrite(pCon,buffer,eError); - return; - } - status = Tcl_GetDouble(tcl,argv[7],&det_rot_rad); - if(status != TCL_OK){ - sprintf(buffer,"ERROR: failed to convert %s to double",argv[7]); - SCWrite(pCon,buffer,eError); - return; - } - status = Tcl_GetDouble(tcl,argv[8],&col_zero); - if(status != TCL_OK){ - sprintf(buffer,"ERROR: failed to convert %s to double",argv[8]); - SCWrite(pCon,buffer,eError); - return; - } - status = Tcl_GetDouble(tcl,argv[9],&rownum); - if(status != TCL_OK){ - sprintf(buffer,"ERROR: failed to convert %s to double",argv[9]); - SCWrite(pCon,buffer,eError); - return; - } - status = Tcl_GetDouble(tcl,argv[10],&colnum); - if(status != TCL_OK){ - sprintf(buffer,"ERROR: failed to convert %s to double",argv[10]); - SCWrite(pCon,buffer,eError); - return; - } - polar_angle(angsep, active_height_mm, det_rot_rad, col_zero, rownum, colnum); - -// status = NXDputalias(self->fileHandle, self->dictHandle,argv[2],G_TwoThetaArr); - status = NXDopenalias(self->fileHandle, self->dictHandle,argv[2]); - status = NXputslab(self->fileHandle, G_TwoThetaArr, start, size); - if(status == NX_OK){ - written = 1; - } - NXopenpath(self->fileHandle,"/"); - if(written != 1){ - sprintf(buffer,"ERROR: failed to write array"); - SCWrite(pCon,buffer,eError); - } - SCSendOK(pCon); -} -/* ANSTO MOD1 END */ /*----------------------------------------------------------------------*/ static void putIntArray(SConnection *pCon, SicsInterp *pSics, pNXScript self, @@ -1212,7 +1065,7 @@ static int handlePut(SConnection *pCon, SicsInterp *pSics, pNXScript self, } if(strlen(defString) < 900){ strcat(defString," -dim {"); - sprintf(numBuf,"%d",strlen(buffer)+1); + sprintf(numBuf,"%d",(int)strlen(buffer)+1); strcat(defString,numBuf); strcat(defString," }"); } else { @@ -1249,9 +1102,6 @@ static int handlePut(SConnection *pCon, SicsInterp *pSics, pNXScript self, }else if(strcmp(argv[1],"putintarray") == 0){ /*================*/ putIntArray(pCon,pSics,self,argc,argv); - }else if(strcmp(argv[1],"putpolararray") == 0){ - /*================*/ - putPolarArray(pCon,pSics,self,argc,argv); }else if(strcmp(argv[1],"putglobal") == 0){ /*===============*/ putGlobal(pCon,pSics,self,argc,argv); diff --git a/nxstack.c b/nxstack.c new file mode 100644 index 00000000..bd2f492c --- /dev/null +++ b/nxstack.c @@ -0,0 +1,100 @@ +/* + This is some code to handle a stack of NeXus files. This is used to implement + external linking within the NeXus-API + + Copyright (C) 1997-2006 Mark Koennecke + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + For further information, see +*/ +#include +#include +#include +#include "nxstack.h" + +/*----------------------------------------------------------------------- + Data definitions +---------------------------------------------------------------------*/ + +typedef struct { + pNexusFunction pDriver; + NXlink closeID; + char filename[1024]; +}fileStackEntry; + + +typedef struct __fileStack { + int fileStackPointer; + fileStackEntry fileStack[MAXEXTERNALDEPTH]; +}fileStack; +/*---------------------------------------------------------------------*/ +pFileStack makeFileStack(){ + pFileStack pNew = NULL; + + pNew = malloc(sizeof(fileStack)); + if(pNew == NULL){ + return NULL; + } + memset(pNew,0,sizeof(fileStack)); + pNew->fileStackPointer = -1; + return pNew; +} +/*---------------------------------------------------------------------*/ +void killFileStack(pFileStack self){ + if(self != NULL){ + free(self); + } +} +/*----------------------------------------------------------------------*/ +void pushFileStack(pFileStack self, pNexusFunction pDriv, char *file){ + int length; + + self->fileStackPointer++; + self->fileStack[self->fileStackPointer].pDriver = pDriv; + memset(&self->fileStack[self->fileStackPointer].closeID,0,sizeof(NXlink)); + length = strlen(file); + if(length >= 1024){ + length = 1023; + } + memcpy(&self->fileStack[self->fileStackPointer].filename,file,length); +} +/*----------------------------------------------------------------------*/ +void popFileStack(pFileStack self){ + self->fileStackPointer--; + if(self->fileStackPointer < -1){ + self->fileStackPointer = -1; + } +} +/*----------------------------------------------------------------------*/ +pNexusFunction peekFileOnStack(pFileStack self){ + return self->fileStack[self->fileStackPointer].pDriver; +} +/*---------------------------------------------------------------------*/ +char *peekFilenameOnStack(pFileStack self){ + return self->fileStack[self->fileStackPointer].filename; +} +/*----------------------------------------------------------------------*/ +void peekIDOnStack(pFileStack self, NXlink *id){ + memcpy(id, &self->fileStack[self->fileStackPointer].closeID, sizeof(NXlink)); +} +/*---------------------------------------------------------------------*/ +void setCloseID(pFileStack self, NXlink id){ + memcpy(&self->fileStack[self->fileStackPointer].closeID, &id, sizeof(NXlink)); +} +/*----------------------------------------------------------------------*/ +int fileStackDepth(pFileStack self){ + return self->fileStackPointer; +} diff --git a/nxstack.h b/nxstack.h new file mode 100755 index 00000000..e7a9568b --- /dev/null +++ b/nxstack.h @@ -0,0 +1,43 @@ +/* + This is some code to handle a stack of NeXus files. This is used to implement + external linking within the NeXus-API + + Copyright (C) 1997-2006 Mark Koennecke + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + For further information, see +*/ +#ifndef NEXUSFILESTACK +#define NEXUSFILESTACK + +typedef struct __fileStack *pFileStack; +#define MAXEXTERNALDEPTH 16 + +pFileStack makeFileStack(); +void killFileStack(pFileStack self); + +void pushFileStack(pFileStack self, pNexusFunction pDriv, char *filename); +void popFileStack(pFileStack self); + +pNexusFunction peekFileOnStack(pFileStack self); +char *peekFilenameOnStack(pFileStack self); +void peekIDOnStack(pFileStack self, NXlink *id); +void setCloseID(pFileStack self, NXlink id); + +int fileStackDepth(pFileStack self); + +#endif + diff --git a/nxutil.c b/nxutil.c index 82a4edc4..07c74429 100644 --- a/nxutil.c +++ b/nxutil.c @@ -115,7 +115,9 @@ VarGetText(pVar,&pText); if(pText != NULL) { - iRet = NXDputalias(hFil,pDict,pAlias,pText); + memset(pBueffel,0,511); + strncpy(pBueffel,pText,511); + iRet = NXDputalias(hFil,pDict,pAlias,pBueffel); free(pText); return iRet; } diff --git a/nxxml.c b/nxxml.c index 36f84ac5..e1ab96aa 100644 --- a/nxxml.c +++ b/nxxml.c @@ -31,6 +31,7 @@ extern void *NXpData; +char *nxitrim(char *str); /* from napi.c */ /*----------------------- our data structures -------------------------- One might wonder why a node stack is still needed even if this API @@ -388,28 +389,24 @@ NXstatus NXXmakedata (NXhandle fid, if(dimensions[0] < 0){ dimensions[0] = 1; } - if ((datatype == NX_CHAR) && (rank > 1)) { - NXIReportError(NXpData,"NeXus XML-API does not yet support multi-dimensional character arrays"); - return NX_ERROR; - } current = xmlHandle->stack[xmlHandle->stackPointer].current; + dataNode = mxmlNewElement(current,name); + typestring = buildTypeString(datatype,rank,dimensions); + if(typestring != NULL){ + mxmlElementSetAttr(dataNode,TYPENAME,typestring); + free(typestring); + } else { + NXIReportError(NXpData,"Failed to allocate typestring"); + return NX_ERROR; + } /* NX_CHAR maps to MXML_OPAQUE datasets */ - dataNode = mxmlNewElement(current,name); if(datatype == NX_CHAR){ newData = mxmlNewOpaque(dataNode,""); return NX_OK; } else { - typestring = buildTypeString(datatype,rank,dimensions); - if(typestring != NULL){ - mxmlElementSetAttr(dataNode,TYPENAME,typestring); - free(typestring); - } else { - NXIReportError(NXpData,"Failed to allocate typestring"); - return NX_ERROR; - } newData = (mxml_node_t *)malloc(sizeof(mxml_node_t)); if(!newData){ NXIReportError(NXpData,"Failed to allocate space for dataset"); @@ -458,24 +455,6 @@ static mxml_node_t *searchSDSLinks(pXMLNexus xmlHandle, CONSTCHAR *name){ } return NULL; } -/*-------------------------------------------------------------------*/ -static int strtrimcr(char *szStr, char *szSet) -{ - int i, j; /* Locale counters */ - - /*-------------------------------------------------*/ - - j = i = strlen(szStr) - 1; /* Find length of string */ - - while (strrchr(szSet, szStr[ i ]) - && (0 <= i)) - { - /* While string is terminated by one of the specified characters */ - szStr[ i-- ] = '\0'; /*- Replace character with '\0' */ - } - - return(j - i); /* Return the difference between old and new length */ -} /*-----------------------------------------------------------------------*/ NXstatus NXXopendata (NXhandle fid, CONSTCHAR *name){ pXMLNexus xmlHandle = NULL; @@ -547,7 +526,8 @@ NXstatus NXXputdata (NXhandle fid, void *data){ mxml_node_t *userData = NULL; mxml_node_t *current = NULL; pNXDS dataset; - int length; + int i, length, type, rank, dim[NX_MAXRANK]; + char *pPtr = NULL; xmlHandle = (pXMLNexus)fid; assert(xmlHandle); @@ -562,9 +542,28 @@ NXstatus NXXputdata (NXhandle fid, void *data){ assert(userData != NULL); if(userData->type == MXML_OPAQUE){ /* - text data + Text data. We have to make sure that the text is \0 terminated. + Some language bindings do not ensure that this is the case. */ - mxmlSetOpaque(userData,(const char *)data); + if(NXXgetinfo(fid,&rank, dim, &type) == NX_OK){ + length = 1; + for(i=0; ivalue.custom.data; assert(dataset); @@ -579,7 +578,7 @@ NXstatus NXXgetdata (NXhandle fid, void *data){ mxml_node_t *userData = NULL; mxml_node_t *current = NULL; pNXDS dataset; - int length; + int i, length, type, rank, dim[NX_MAXRANK]; xmlHandle = (pXMLNexus)fid; assert(xmlHandle); @@ -596,7 +595,17 @@ NXstatus NXXgetdata (NXhandle fid, void *data){ /* text data */ - strcpy((char *)data,userData->value.opaque); + if(NXXgetinfo(fid,&rank, dim, &type) == NX_OK){ + length = 1; + for(i=0; ivalue.opaque,length); + } else { + strcpy((char *)data,nxitrim(userData->value.opaque)); + } + } else { dataset = (pNXDS)userData->value.custom.data; assert(dataset); @@ -613,6 +622,7 @@ NXstatus NXXgetinfo (NXhandle fid, int *rank, mxml_node_t *current = NULL; pNXDS dataset; int myRank, i; + const char *attr = NULL; xmlHandle = (pXMLNexus)fid; assert(xmlHandle); @@ -629,9 +639,15 @@ NXstatus NXXgetinfo (NXhandle fid, int *rank, /* text data */ - *rank = 1; - *iType = NX_CHAR; - dimension[0]= strlen(userData->value.opaque); + attr = mxmlElementGetAttr(current, TYPENAME); + if(attr == NULL){ + *rank = 1; + *iType = NX_CHAR; + dimension[0]= strlen(userData->value.opaque); + } else { + analyzeDim(attr,rank,dimension,iType); + *iType = NX_CHAR; + } } else { dataset = (pNXDS)userData->value.custom.data; assert(dataset); @@ -868,14 +884,18 @@ static NXstatus NXXsetnumberformat(NXhandle fid, /*============================ Attributes ============================*/ static char *formatAttributeData(void *data, int datalen, int iType){ int intData = 0; - long iValue; - double dValue; + long iValue = -99999; + double dValue = -1e38; char type[20]; char *number; if(iType == NX_CHAR){ - return strdup((char *)data); +/* data may not be NULL terminated */ + number = (char*)malloc((datalen+1) * sizeof(char)); + memcpy(number, data, datalen * sizeof(char)); + number[datalen] = '\0'; + return number; } number = (char *)malloc(132*sizeof(char)); @@ -1454,7 +1474,7 @@ NXstatus NXXmakelink (NXhandle fid, NXlink* sLink){ } /*-----------------------------------------------------------------------*/ -NXstatus NXXmakenamedlink (NXhandle fid, char *name, NXlink* sLink){ +NXstatus NXXmakenamedlink (NXhandle fid, CONSTCHAR *name, NXlink* sLink){ pXMLNexus xmlHandle = NULL; mxml_node_t *current = NULL, *linkNode = NULL; mxml_node_t *linkedNode = NULL; @@ -1511,6 +1531,7 @@ void NXXassignFunctions(pNexusFunction fHandle){ fHandle->nxputslab=NXXputslab; fHandle->nxgetdataID=NXXgetdataID; fHandle->nxmakelink=NXXmakelink; + fHandle->nxmakenamedlink=NXXmakenamedlink; fHandle->nxgetdata=NXXgetdata; fHandle->nxgetinfo=NXXgetinfo; fHandle->nxgetnextentry=NXXgetnextentry; diff --git a/obdes.c b/obdes.c index b94c717e..127e56bc 100644 --- a/obdes.c +++ b/obdes.c @@ -156,7 +156,7 @@ { if(NULL!=self) { - IFSetOption(self->pKeys,keyName,eltValue); + self->pKeys = IFSetOption(self->pKeys,keyName,eltValue); } } /*--------------------------------------------------------------------------*/ @@ -166,7 +166,7 @@ { return; } - IFSetOption(self->pKeys,"group",group); + self->pKeys = IFSetOption(self->pKeys,"group",group); } /*--------------------------------------------------------------------------*/ void SetDescriptorDescription(pObjectDescriptor self, char *description) @@ -175,7 +175,7 @@ { return; } - IFSetOption(self->pKeys,"description", description); + self->pKeys = IFSetOption(self->pKeys,"description", description); } /*--------------------------------------------------------------------------*/ char * GetDescriptorKey(pObjectDescriptor self, char *keyName) diff --git a/ofac.c b/ofac.c index 547da591..3619f211 100644 --- a/ofac.c +++ b/ofac.c @@ -56,6 +56,7 @@ #include "servlog.h" #include "nserver.h" #include "status.h" +#include "statusfile.h" #include "configfu.h" #include "devexec.h" #include "mumo.h" @@ -122,6 +123,12 @@ #include "multicounter.h" #include "sicspoll.h" #include "statemon.h" +#include "asyncqueue.h" +#include "asyncprotocol.h" +#include "sicsobj.h" +#include "hdbqueue.h" +#include "genericcontroller.h" +#include "proxy.h" /*----------------------- Server options creation -------------------------*/ static int IFServerOption(SConnection *pCon, SicsInterp *pSics, void *pData, int argc, char *argv[]) @@ -227,8 +234,6 @@ AddCommand(pInter,"status", UserStatus,NULL,NULL); AddCommand(pInter,"ResetServer",ResetStatus,NULL,NULL); AddCommand(pInter,"Dir",ListObjects,NULL,NULL); - AddCommand(pInter,"Backup",BackupStatus,NULL,NULL); - AddCommand(pInter,"Restore",RestoreStatus,NULL,NULL); AddCommand(pInter,"SetInt", SetSICSInterrupt,NULL,NULL); AddCommand(pInter,"GetInt",GetSICSInterrupt,NULL,NULL); AddCommand(pInter,"SICSType",SICSType,NULL,NULL); @@ -243,6 +248,7 @@ AddCommand(pInter,"commandlog",CommandLog,CommandLogClose,NULL); AddCommand(pInter,"udpquieck",QuieckAction,KillQuieck,NULL); AddCommand(pInter,"alias",MakeAlias,NULL,NULL); + AddCommand(pInter,"findalias",LocateAliasAction,NULL,NULL); AddCommand(pInter,"sicscron",MakeCron,NULL,NULL); AddCommand(pInter,"dolater",MakeCron,NULL,NULL); AddCommand(pInter,"sicsdatafactory",SICSDataFactory,NULL,NULL); @@ -250,6 +256,7 @@ AddCommand(pInter,"help",SicsHelp,KillHelp,NULL); AddCommand(pInter,"sicslist",SicsList,NULL,NULL); AddCommand(pInter,"InstallHdb",InstallSICSHipadaba,NULL,NULL); + MakeProtocol(pInter); /* commands to do with the executor. Only StopExe carries the DeleteFunction in order to avoid double deletion. All the @@ -277,7 +284,6 @@ AddCommand(pInter,"MakeCounter",MakeCounter,NULL,NULL); AddCommand(pInter,"MakeO2T",CreateO2T,NULL,NULL); AddCommand(pInter,"SicsAlias",SicsAlias,NULL,NULL); - AddCommand(pInter,"SicsAlias",DefineAlias,NULL,NULL); AddCommand(pInter,"DefineAlias",DefineAlias,NULL,NULL); /* M.Z. */ AddCommand(pInter,"MakeHM",MakeHistMemory,NULL,NULL); AddCommand(pInter,"VelocitySelector",VelSelFactory,NULL,NULL); @@ -326,8 +332,6 @@ McStasReaderFactory,NULL,NULL); AddCommand(pInter,"MakeMcStasController", McStasControllerFactory,NULL,NULL); - AddCommand(pInter,"InstallProtocolHandler", - InstallProtocol,NULL,NULL); AddCommand(pInter,"InstallSinfox", InstallSinfox,NULL,NULL); AddCommand(pInter,"MakeCone", @@ -338,6 +342,14 @@ InstallSICSPoll,NULL,NULL); AddCommand(pInter,"MakeStateMon", StateMonFactory,NULL,NULL); + AddCommand(pInter,"MakeAsyncProtocol",AsyncProtocolFactory,NULL,NULL); + AddCommand(pInter,"MakeAsyncQueue",AsyncQueueFactory,NULL,NULL); + AddCommand(pInter,"MakeSicsObj",InstallSICSOBJ,NULL,NULL); + AddCommand(pInter,"DynSicsObj",InstallSICSOBJ,NULL,NULL); +/* AddCommand(pInter,"MakeHdbQueue",MakeHDBQueue,NULL,NULL); */ + AddCommand(pInter,"MakeGenController",GenControllerFactory,NULL,NULL); + AddCommand(pInter,"genconfigure",GenControllerConfigure,NULL,NULL); + AddCommand(pInter,"MakeProxy",ProxyFactory,NULL,NULL); /* install site specific commands @@ -403,11 +415,16 @@ RemoveCommand(pSics,"MakeTasUB"); RemoveCommand(pSics,"MakeTasScan"); RemoveCommand(pSics,"MakemcStasReader"); - RemoveCommand(pSics,"InstallProtocolHandler"); RemoveCommand(pSics,"InstallSinfox"); RemoveCommand(pSics,"MakeCone"); RemoveCommand(pSics,"MakeMultiCounter"); RemoveCommand(pSics,"MakeStateMon"); + RemoveCommand(pSics,"MakeAsyncQueue"); + RemoveCommand(pSics,"MakeAsyncProtocol"); + RemoveCommand(pSics,"MakeSicsObject"); + RemoveCommand(pSics,"MakeGenController"); + RemoveCommand(pSics,"genconfigure"); + RemoveCommand(pSics,"MakeProxy"); /* remove site specific installation commands */ @@ -423,10 +440,17 @@ /* insert here initialization routines ... */ - INIT(SiteInit); /* site specific initializations */ INIT(StatisticsInit); + INIT(InitializerInit); + INIT(SaveHdbInit); /* must be after InitializerInit */ + INIT(SctInit); + INIT(SctDriveInit); + INIT(LogReaderInit); + INIT(LogSetupInit); + INIT(StatusFileInit); - } + INIT(SiteInit); /* site specific initializations */ + } /*--------------------------------------------------------------------------*/ int InitObjectCommands(pServer pServ, char *file) { @@ -449,6 +473,7 @@ } MakeExeManager(pCon,pSics,NULL,1, NULL); InitIniCommands(pSics,pServ->pTasker); + InstallBckRestore(pCon,pSics); pCon->iFiles = 0; diff --git a/polldriv.c b/polldriv.c index fcd23df9..da2f5119 100644 --- a/polldriv.c +++ b/polldriv.c @@ -13,7 +13,7 @@ #include #include "polldriv.h" -#include "splitter.h" +#include "macro.h" #include "sicshipadaba.h" /*================ actual driver implementation =========================*/ static int timeDue(struct __POLLDRIV *self, time_t now, SConnection *pCon){ @@ -47,12 +47,10 @@ static int pollHdb(struct __POLLDRIV *self, SConnection *pCon){ /*-----------------------------------------------------------------------*/ static pPollDriv makeHdbDriver(SConnection *pCon, char *objectIdentifier, int argc, char *argv[]){ - pHdb root = NULL, node = NULL; + pHdb node = NULL; pPollDriv pNew = NULL; - root = GetHipadabaRoot(); - assert(root != NULL); - node = GetHipadabaNode(root,objectIdentifier); + node = FindHdbNode(NULL,objectIdentifier,pCon); if(node == NULL){ SCWrite(pCon,"ERROR: object to poll not found",eError); return 0; @@ -75,6 +73,58 @@ static pPollDriv makeHdbDriver(SConnection *pCon, char *objectIdentifier, pNew->pollIntervall = 10; } + return pNew; +} +/*==================== script poll driver ========================*/ +static int pollScript(struct __POLLDRIV *self, SConnection *pCon){ + int status; + Tcl_Interp *pTcl = InterpGetTcl(pServ->pSics); + + self->nextPoll = time(NULL) + self->pollIntervall; + + MacroPush(pCon); + status = Tcl_Eval(pTcl,(char *)self->objPointer); + MacroPop(); + if(status == 0){ + return 1; + } else { + return 0; + } +} +/*-----------------------------------------------------------------------*/ +static void killScriptObj(void *data){ + if(data != NULL){ + free(data); + } +} +/*-----------------------------------------------------------------------*/ +static pPollDriv makeScriptDriver(SConnection *pCon, char *objectIdentifier, + int argc, char *argv[]){ + pPollDriv pNew = NULL; + char scriptBuffer[512]; + + if(argc < 2){ + SCWrite(pCon, + "ERROR: need intervall and script parameter for script polling driver", eError); + return NULL; + } + + pNew = malloc(sizeof(PollDriv)); + if(pNew == NULL){ + return NULL; + } + memset(pNew,0,sizeof(PollDriv)); + + pNew->pollIntervall = atoi(argv[0]); + memset(scriptBuffer,0,512); + Arg2Text(argc-1, &argv[1],scriptBuffer,511); + + pNew->objectIdentifier = strdup(objectIdentifier); + pNew->objPointer = strdup(scriptBuffer); + pNew->isDue = timeDue; + pNew->poll = pollScript; + pNew->killObjPointer = killScriptObj; + return pNew; } /*================ external interface ====================================*/ @@ -83,7 +133,9 @@ pPollDriv makePollDriver(SConnection *pCon, char *driver, strtolower(driver); if(strcmp(driver,"hdb") == 0) { - return makeHdbDriver(pCon,objectIdentifier, argc, argv); + return makeHdbDriver(pCon,objectIdentifier, argc, argv); + } else if(strcmp(driver,"script") == 0){ + return makeScriptDriver(pCon,objectIdentifier, argc, argv); } else { SCWrite(pCon,"ERROR: polling driver type unknown",eError); return NULL; @@ -94,5 +146,8 @@ void deletePollDriv(pPollDriv self){ if(self->objectIdentifier != NULL){ free(self->objectIdentifier); } + if(self->objPointer != NULL && self->killObjPointer != NULL){ + self->killObjPointer(self->objPointer); + } free(self); } diff --git a/polldriv.h b/polldriv.h index c5a22f13..409afb2d 100644 --- a/polldriv.h +++ b/polldriv.h @@ -20,6 +20,8 @@ typedef struct __POLLDRIV{ /* function called to determine if this object must be polled */ int (*poll)(struct __POLLDRIV *self, SConnection *pCon); /* the actual polling function */ + void (*killObjPointer)(void *data); + /* a function to possibly kill the objPointer. Can be NULL */ }PollDriv, *pPollDriv; /*==================== the interface =====================================*/ /* diff --git a/polldriv.tc b/polldriv.tc index 2337eda8..42b82fcb 100644 --- a/polldriv.tc +++ b/polldriv.tc @@ -43,12 +43,10 @@ static int pollHdb(struct __POLLDRIV *self, SConnection *pCon){ /*-----------------------------------------------------------------------*/ static pPollDriv makeHdbDriver(SConnection *pCon, char *objectIdentifier, int argc, char *argv[]){ - pHdb root = NULL, node = NULL; + pHdb node = NULL; pPollDriv pNew = NULL; - root = GetHipadabaRoot(); - assert(root != NULL); - node = GetHipadabaNode(root,objectIdentifier); + node = locateSICSNode(pServ->pSics,pCon,objectIdentifier); if(node == NULL){ SCWrite(pCon,"ERROR: object to poll not found",eError); return 0; diff --git a/protocol.c b/protocol.c index 8c006ac4..909ac1ca 100644 --- a/protocol.c +++ b/protocol.c @@ -21,8 +21,8 @@ #define MAXMSG 1024 #define INIT_STR_SIZE 256 #define STR_RESIZE_LENGTH 256 -#define NUMPROS 5 -#define PROLISTLEN 6 +#define NUMPROS 6 +#define PROLISTLEN 7 typedef struct __Protocol { pObjectDescriptor pDes; /* required as first field */ char *name; /* protocol handler name */ @@ -106,6 +106,7 @@ pProtocol CreateProtocol(void) "withcode", "sycamore", "json", + "act", NULL }; pProtocol pNew = NULL; @@ -184,8 +185,8 @@ static int ContextDo(SConnection *pCon, SicsInterp *pSics, void *pData, status = Tcl_GetInt(pSics->pTcl,argv[1],&comCon.transID); if(status != TCL_OK){ - snprintf(command,1023,"ERROR: failed to convert %s to transaction ID", argv[1]); - SCWrite(pCon,command,eError); + snprintf(buffer,1023,"ERROR: failed to convert %s to transaction ID", argv[1]); + SCWrite(pCon,buffer,eError); return 0; } strncpy(comCon.deviceID,argv[2],SCDEVIDLEN); @@ -217,7 +218,16 @@ int InstallProtocol(SConnection *pCon, SicsInterp *pSics, void *pData, SCSendOK(pCon); return 1; } - +/*------------------------------------------------------------------------*/ +void MakeProtocol(SicsInterp *pSics){ + pProtocol pNew = NULL; + pNew = CreateProtocol(); + if(NULL!= pNew) + { + AddCommand(pSics,"Protocol",ProtocolAction,DeleteProtocol,pNew); + AddCommand(pSics,"contextdo",ContextDo,NULL,NULL); + } +} /*------------------------------------------------------------------------*/ static int ProtocolOptions(SConnection* pCon, pProtocol pPro) { @@ -281,6 +291,9 @@ static int ProtocolSet(SConnection* pCon, Protocol* pPro, char *pProName) case 4: /* json */ SCSetWriteFunc(pCon,SCWriteJSON_String); break; + case 5: + SCSetWriteFunc(pCon,SCACTWrite); + break; case 0: /* default = psi_sics */ default: SCSetWriteFunc(pCon,pPro->defaultWriter); @@ -301,6 +314,12 @@ int ProtocolGet(SConnection* pCon, void* pData, char *pProName, int len) return 0; } + if(pData == NULL) + { + pCon->iProtocolID = 0; + return 1; + } + /* lazy initialisation of defaultWriter since connection is verified */ if(0==pPro->isDefaultSet) { @@ -321,6 +340,7 @@ int ProtocolGet(SConnection* pCon, void* pData, char *pProName, int len) case 2: /* outcodes */ case 3: /* sycamore */ case 4: /* json */ + case 5: /* act */ pProName = pPro->pProList[Index]; return 1; break; @@ -494,8 +514,7 @@ int SCWriteSycamore(SConnection *pCon, char *pBuffer, int iOut) /* write to commandlog if user or manager privilege */ if(SCGetRights(pCon) <= usUser) { - sprintf(pBueffel,"To sock %d :",iRet); - WriteToCommandLog(pBueffel,pBuffer); + WriteToCommandLogId(NULL,iRet,pBuffer); } /* put it into the interpreter if present */ @@ -693,15 +712,13 @@ int SCWriteJSON_String(SConnection *pCon, char *pBuffer, int iOut) { if(pCon->iMacro != 1) { - sprintf(pBueffel,"To sock %d :",iRet); - WriteToCommandLog(pBueffel,pBuffer); + WriteToCommandLogId(NULL,iRet,pBuffer); } else { if(iOut == eError || iOut == eWarning) { - sprintf(pBueffel,"To sock %d :",iRet); - WriteToCommandLog(pBueffel,pBuffer); + WriteToCommandLogId(NULL,iRet,pBuffer); } } } @@ -779,3 +796,26 @@ int GetProtocolID(SConnection* pCon) } return -1; } +/*---------------------------------------------------------------------------*/ +writeFunc GetProtocolWriteFunc(SConnection *pCon){ + if(pCon != NULL){ + switch(pCon->iProtocolID){ + case 2: /* outcodes */ + return SCWriteWithOutcode; + break; + case 3: /* sycamore */ + return SCWriteSycamore; + break; + case 4: /* json */ + return SCWriteJSON_String; + break; + case 5: + return SCACTWrite; + break; + default: + return SCNormalWrite; + break; + } + } + return SCNormalWrite; +} diff --git a/protocol.h b/protocol.h index ff00e813..24d51d72 100644 --- a/protocol.h +++ b/protocol.h @@ -19,11 +19,11 @@ static char *pProTags[3] = { int InstallProtocol(SConnection *pCon, SicsInterp *pSics, void *pData, int argc, char *argv[]); void DeleteProtocol(void *pSelf); +void MakeProtocol(SicsInterp *pSics); /*--------------------- operations --------------------------------------*/ int ProtocolAction(SConnection *pCon, SicsInterp *pSics, void *pData, int argc, char *argv[]); - /*--------------------- implement protocol sycamore ---------------------*/ int SCWriteSycamore(SConnection *pCon, char *pBuffer, int iOut); @@ -31,5 +31,6 @@ int SCWriteSycamore(SConnection *pCon, char *pBuffer, int iOut); char * GetProtocolName(SConnection *pCon); int GetProtocolID(SConnection *pCon); int ProtocolGet(SConnection* pCon, void* pData, char *pProName, int len); +writeFunc GetProtocolWriteFunc(SConnection *pCon); /*-----------------------------------------------------------------------*/ #endif diff --git a/proxy.c b/proxy.c new file mode 100644 index 00000000..a30a5dd8 --- /dev/null +++ b/proxy.c @@ -0,0 +1,476 @@ +/** + * This is the implementation of a SICS object which really is a placeholder + * for another one. It shall be used in Hipadaba for sample enviornment + * devices. This is also the reason why the objectNode is supposed to be + * double. + * + * copyright: see file COPYRIGHT + * + * Mark Koennecke, March 2008 + * + */ +#include +#include +#include +/*-----------------------------------------------------------------------*/ +typedef struct { + pIDrivable pDriv; + pEVInterface pEnv; + pIDrivable pSlaveDriv; + void *slaveData; + pEVInterface pEnvSlave; +} ProxyInt, *pProxyInt; +/*------------------------------------------------------------------------*/ +static void KillProxyInt(void *data){ + pProxyInt proxy = (pProxyInt)data; + + if(proxy == NULL){ + return; + } + if(proxy->pDriv != NULL){ + free(proxy->pDriv); + } + if(proxy->pEnv != NULL){ + free(proxy->pEnv); + } + free(proxy); +} +/*===================== Drivable Interfaces ================================*/ +static int testDrivProxy(pSICSOBJ self){ + pProxyInt proxy = self->pPrivate; + + if(proxy->pSlaveDriv != NULL && proxy->slaveData != NULL){ + return 1; + } + return 0; +} +/*-----------------------------------------------------------------------*/ +static int ProxyHalt(void *data){ + pSICSOBJ self = (pSICSOBJ)data; + pProxyInt proxy = NULL; + + assert(self != NULL); + proxy = self->pPrivate; + assert(self != NULL); + + if(testDrivProxy(self)){ + return proxy->pSlaveDriv->Halt(proxy->slaveData); + } else { + return 0; + } +} +/*------------------------------------------------------------------------*/ +static int ProxyLimits(void *data, float fval, + char *error, int iErrLen){ + pSICSOBJ self = (pSICSOBJ)data; + pProxyInt proxy = NULL; + + assert(self != NULL); + proxy = self->pPrivate; + assert(self != NULL); + + if(testDrivProxy(self)){ + return proxy->pSlaveDriv->CheckLimits(proxy->slaveData, fval, + error, iErrLen); + } else { + strncpy(error,"ERROR: device not configured",iErrLen); + return 0; + } +} +/*-----------------------------------------------------------------------*/ +static long ProxySet(void *data, SConnection *pCon, float fVal){ + pSICSOBJ self = (pSICSOBJ)data; + pProxyInt proxy = NULL; + + assert(self != NULL); + proxy = self->pPrivate; + assert(self != NULL); + + if(testDrivProxy(self)){ + return proxy->pSlaveDriv->SetValue(proxy->slaveData, + pCon, fVal); + } else { + SCWrite(pCon,"ERROR: device not configured", eError); + return 0; + } +} +/*-----------------------------------------------------------------------*/ +static int ProxyStatus(void *data, SConnection *pCon){ + pSICSOBJ self = (pSICSOBJ)data; + pProxyInt proxy = NULL; + + assert(self != NULL); + proxy = self->pPrivate; + assert(self != NULL); + + if(testDrivProxy(self)){ + return proxy->pSlaveDriv->CheckStatus(proxy->slaveData, + pCon); + } else { + SCWrite(pCon,"ERROR: device not configured", eError); + return HWFault; + } +} +/*-----------------------------------------------------------------------*/ +static float ProxyGet(void *data, SConnection *pCon){ + pSICSOBJ self = (pSICSOBJ)data; + pProxyInt proxy = NULL; + + assert(self != NULL); + proxy = self->pPrivate; + assert(self != NULL); + + if(testDrivProxy(self)){ + return proxy->pSlaveDriv->GetValue(proxy->slaveData, pCon); + } else { + SCWrite(pCon,"ERROR: device not configured", eError); + return HWFault; + } +} +/*===================== environment interface ==========================*/ +static int testEnvProxy(pSICSOBJ self){ + pProxyInt proxy = self->pPrivate; + + if(proxy->pEnvSlave != NULL && proxy->slaveData != NULL){ + return 1; + } + return 0; +} +/*-----------------------------------------------------------------------*/ +static EVMode ProxyMode(void *data){ + pSICSOBJ self = (pSICSOBJ)data; + pProxyInt proxy = NULL; + + assert(self != NULL); + proxy = self->pPrivate; + assert(self != NULL); + + if(testEnvProxy(self)){ + return proxy->pEnvSlave->GetMode(proxy->slaveData); + } else { + return EVError; + } +} +/*------------------------------------------------------------------------*/ +static int ProxyTolerance(void *data){ + pSICSOBJ self = (pSICSOBJ)data; + pProxyInt proxy = NULL; + + assert(self != NULL); + proxy = self->pPrivate; + assert(self != NULL); + + if(testEnvProxy(self)){ + return proxy->pEnvSlave->IsInTolerance(proxy->slaveData); + } else { + return 0; + } +} +/*-------------------------------------------------------------------------*/ +static int ProxyError(void *data){ + pSICSOBJ self = (pSICSOBJ)data; + pProxyInt proxy = NULL; + + assert(self != NULL); + proxy = self->pPrivate; + assert(self != NULL); + + if(testEnvProxy(self)){ + return proxy->pEnvSlave->HandleError(proxy->slaveData); + } else { + return 0; + } +} +/*-----------------------------------------------------------------------*/ +static void *findRealDev(pHdb node){ + char realDevice[80]; + CommandList *pCom = NULL; + + GetHdbProperty(node,"proxy",realDevice,80); + pCom = FindCommand(pServ->pSics,realDevice); + if(pCom != NULL){ + return pCom->pData; + } else { + return NULL; + } +} +/*-----------------------------------------------------------------------*/ +static void *ProxyGetInterface(void *pData, int iID){ + pSICSOBJ self = (pSICSOBJ)pData; + pDummy other = NULL; + void *inter = NULL; + pProxyInt proxy = NULL; + + assert(self != NULL); + proxy = self->pPrivate; + + if(self != NULL){ + other = (pDummy)findRealDev(self->objectNode); + if(other != NULL){ + inter = other->pDescriptor->GetInterface(other, iID); + if(inter == NULL && + (iID == DRIVEID || iID == ENVIRINTERFACE) ){ + proxy->pEnvSlave = NULL; + proxy->pSlaveDriv = NULL; + proxy->slaveData = NULL; + return NULL; + } else { + if(iID == DRIVEID){ + proxy->pSlaveDriv = inter; + proxy->slaveData = other; + return proxy->pDriv; + } else if(iID == ENVIRINTERFACE){ + proxy->pEnvSlave = inter; + proxy->slaveData = other; + return proxy->pEnv; + } + } + return inter; + } + } + return NULL; +} +/*------------------------------------------------------------------------*/ +static hdbCallbackReturn ProxyCallback(pHdb node, void *userData, + pHdbMessage message){ + pHdbDataMessage get = NULL, set = NULL; + pDummy other = NULL; + pIDrivable pDriv = NULL; + float fval; + int status; + SConnection *pCon = NULL; + pSICSOBJ self = (pSICSOBJ)userData; + char proxyDev[80]; + + get = GetHdbGetMessage(message); + if(get != NULL){ + pCon = (SConnection *)get->callData; + other = (pDummy)findRealDev(node); + if(other != NULL){ + pDriv = other->pDescriptor->GetInterface(other,DRIVEID); + if(pDriv != NULL && pCon != NULL){ + fval = pDriv->GetValue(other, pCon); + get->v->v.doubleValue = (double)fval; + node->value.v.doubleValue = (double)fval; + return hdbContinue; + } + } + get->v->v.doubleValue = .0; + } + + set = GetHdbSetMessage(message); + if(set != NULL){ + pCon = (SConnection *)set->callData; + other = (pDummy)findRealDev(node); + if(other == NULL){ + if(pCon != NULL){ + SCWrite(pCon,"ERROR: device not configured", eError); + return hdbAbort; + } + } + GetHdbProperty(node,"proxy", proxyDev,80); + status = StartDevice(pServ->pExecutor, proxyDev, + self->pDes, self, pCon, (float)set->v->v.doubleValue); + if(status == 1){ + return hdbContinue; + } else { + return hdbAbort; + } + } + + return hdbContinue; +} +/*----------------------------------------------------------------------------*/ +static hdbCallbackReturn MapParCallback(pHdb node, void *userData, + pHdbMessage message){ + pHdbDataMessage get = NULL, set = NULL; + CommandList *pCom = NULL; + SConnection *pCon = NULL; + char mapPar[80], proxyDev[80], *pData = NULL; + char command[1024]; + pDynString data = NULL; + + if(GetHdbKillNodeMessage(message) != NULL ){ + return hdbContinue; + } + + GetHdbProperty(node->mama, "proxy", proxyDev,80); + pCom = FindCommand(pServ->pSics, proxyDev); + if(pCom == NULL){ + if(pCon != NULL){ + SCWrite(pCon,"ERROR: device not configured", eError); + } + return hdbContinue; + } + GetHdbProperty(node,"mappar", mapPar, 80); + + get = GetHdbGetMessage(message); + if(get != NULL){ + pCon = (SConnection *)get->callData; snprintf(command,1024,"%s %s", proxyDev, mapPar); + if(pCon != NULL){ + SCStartBuffering(pCon); + InterpExecute(pServ->pSics, pCon,command); + data = SCEndBuffering(pCon); + if(data != NULL){ + pData = GetCharArray(data); + if(strstr(pData,"ERROR") != NULL){ + SCWrite(pCon,pData,eError); + } else { + pData = strchr(pData,(int)'='); + if(pData != NULL){ + pData++; + if(!readHdbValue(get->v, pData, command, 1024)){ + SCWrite(pCon, command, eError); + } + copyHdbValue(get->v, &node->value); + return hdbContinue; + } + } + } + } + } + + set = GetHdbSetMessage(message); + if(set != NULL){ + pCon = (SConnection *)set->callData; + data = formatValue(*(set->v), node); + if(data != NULL){ + snprintf(command,1024,"%s %s %s", proxyDev, mapPar, + GetCharArray(data)); + DeleteDynString(data); + InterpExecute(pServ->pSics, pCon, command); + } + } + + return hdbContinue; +} +/*-------------------------------------------------------------------------*/ +static int MapFunc(pSICSOBJ self, SConnection *pCon, pHdb commandNode, + pHdb par[], int nPar){ + pHdb node = NULL; + int type; + + if(nPar < 4){ + SCWrite(pCon,"ERROR: not enough arguments to MapFunc", eError); + return 0; + } + + type = convertHdbType(par[2]->value.v.text); + node = MakeHipadabaNode(par[0]->value.v.text, type, 1); + if(node == NULL){ + SCWrite(pCon,"ERROR: out of memory in MapFunc", eError); + return 0; + } + SetHdbProperty(node,"mappar", par[1]->value.v.text); + SetHdbProperty(node,"priv", par[3]->value.v.text); + AppendHipadabaCallback(node, + MakeHipadabaCallback(MapParCallback, NULL, NULL)); + AddHipadabaChild(self->objectNode, node, pCon); + + return 1; +} +/*--------------------------------------------------------------------------*/ +static int ProxyAction(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]){ + int status; + pSICSOBJ self = (pSICSOBJ)pData; + CommandList *pCom = NULL; + char proxyObj[80]; + + assert(self != NULL); + + /* + * do parameters and object functions + */ + if(argc > 1){ + status = InvokeSICSOBJ(pCon, pSics, pData, argc, argv); + if(status != -1 ){ + return status; + } + } + + /* + * try the interpreter function of the proxy object + */ + GetHdbProperty(self->objectNode,"proxy", proxyObj, 80); + pCom = FindCommand(pSics, proxyObj); + if(pCom != NULL){ + return pCom->OFunc(pCon,pSics,pCom->pData, argc, argv); + } else { + SCWrite(pCon,"ERROR: device not configured", eError); + return 0; + } +} +/*--------------------------------------------------------------------------*/ +int ProxyFactory(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]){ + int type; + pSICSOBJ pNew = NULL; + pHdb mapFunc = NULL; + hdbValue v; + pProxyInt proxy = NULL; + + if(argc < 4){ + SCWrite(pCon,"ERROR: not enough arguments for ProxyFactory", + eError); + return 0; + } + + type = convertHdbType(argv[3]); + pNew = MakeSICSOBJv(argv[1], "ProxyObject", type, usSpy); + if(pNew == NULL){ + SCWrite(pCon,"ERROR: out of memory in ProxyFactory", + eError); + return 0; + } + + proxy = malloc(sizeof(ProxyInt)); + if(proxy == NULL){ + SCWrite(pCon,"ERROR: out of memory in ProxyFactory", + eError); + return 0; + } + memset(proxy,0,sizeof(ProxyInt)); + proxy->pDriv = CreateDrivableInterface(); + proxy->pEnv = CreateEVInterface(); + if(proxy->pDriv == NULL && proxy->pEnv == NULL){ + SCWrite(pCon,"ERROR: out of memory in ProxyFactory", + eError); + return 0; + } + proxy->pDriv->CheckLimits = ProxyLimits; + proxy->pDriv->CheckStatus = ProxyStatus; + proxy->pDriv->GetValue = ProxyGet; + proxy->pDriv->Halt = ProxyHalt; + proxy->pDriv->SetValue = ProxySet; + + proxy->pEnv->GetMode = ProxyMode; + proxy->pEnv->HandleError = ProxyError; + proxy->pEnv->IsInTolerance = ProxyTolerance; + + pNew->KillPrivate = KillProxyInt; + pNew->pPrivate = proxy; + + pNew->pDes->GetInterface = ProxyGetInterface; + SetHdbProperty(pNew->objectNode, "proxy", argv[2]); + AppendHipadabaCallback(pNew->objectNode, + MakeHipadabaCallback(ProxyCallback, pNew,NULL)); + + v = MakeSICSFunc(MapFunc); + mapFunc = MakeSICSHdbPar("map", usMugger, v); + SetHdbProperty(mapFunc,"visible","false"); + v = MakeHdbText("Undefined"); + AddSICSHdbPar(mapFunc,"name",usMugger,v); + AddSICSHdbPar(mapFunc,"target",usMugger,v); + AddSICSHdbPar(mapFunc,"type",usMugger,v); + AddSICSHdbPar(mapFunc,"priv",usMugger,v); + AddHipadabaChild(pNew->objectNode, mapFunc, pCon); + + AddCommand(pSics,argv[1], + ProxyAction, + KillSICSOBJ, + pNew); + + return 1; +} + diff --git a/proxy.h b/proxy.h new file mode 100644 index 00000000..4afc22cc --- /dev/null +++ b/proxy.h @@ -0,0 +1,17 @@ +/** + * This is the implementation of a SICS object which really is a placeholder + * for another one. It shall be used in Hipadaba for sample enviornment + * devices. This is also the reason why the objectNode is supposed to be + * double. + * + * copyright: see file COPYRIGHT + * + * Mark Koennecke, March 2008 + * + */ +#ifndef PROXY_H_ +#define PROXY_H_ +int ProxyFactory(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]); + +#endif /*PROXY_H_*/ diff --git a/remob.c b/remob.c index ddc7a19b..e0308028 100644 --- a/remob.c +++ b/remob.c @@ -45,7 +45,7 @@ typedef struct RemServer { int taskActive; int interestActive; int forwardMessages; - SCStore conn; + SCStore *conn; } RemServer; struct Remob { @@ -261,9 +261,10 @@ static int RemServerTask(void *data) { if (remserver->forwardMessages) { /* forward all other messages */ - pCon = SCLoad(&remserver->conn); - if (pCon) { + if (SCStoreConnected(remserver->conn)) { + pCon = SCStorePush(remserver->conn); RemCopy(rc, pCon); + SCStorePop(remserver->conn); } } } @@ -397,7 +398,7 @@ static float RemobGetValue(void *pData, SConnection *pCon) { assert(remob); - SCSave(&remserver->conn, pCon); + remserver->conn = SCSave(pCon, remserver->conn); none = -1.25e6; value= none; snprintf(buf, sizeof(buf), "<%s", remob->name); @@ -448,7 +449,7 @@ static int RemobStatus(void *pData, SConnection *pCon) { assert(remob); - SCSave(&remob->server->conn, pCon); + remob->server->conn = SCSave(pCon, remob->server->conn); return remob->status; } /*---------------------------------------------------------------------------*/ @@ -467,7 +468,7 @@ static long RemobRun(void *self, SConnection *pCon, float fNew) { int nChan; remserver = remob->server; - SCSave(&remserver->conn, pCon); + remserver->conn = SCSave(pCon, remserver->conn); assert(remob); assert(pCon); @@ -563,10 +564,13 @@ int RemobAction(SConnection *pCon, SicsInterp *pSics, void *pData, nChan = (rights <= usUser); rc = &remserver->rc[nChan]; if (rights >= usUser) { - SCSave(&remserver->conn, pCon); + remserver->conn = SCSave(pCon, remserver->conn); } if (argc == 1) { - iRet = RemTransact(remserver, nChan, pCon, argv[0], ">", NULL); + iRet = RemTransact(remserver, nChan, pCon, remob->name, ">", NULL); + } else if (strcasecmp(argv[1],"interest") == 0) { + /* ignore interest commands, as they would not work properly */ + iRet=1; } else if (strcasecmp(argv[1],"list") == 0) { /* snprintf(acce, sizeof(acce), "!%s.accesscode", remob->name); @@ -633,7 +637,7 @@ int RemServerAction(SConnection *pCon, SicsInterp *pSics, void *pData, TokenList *pCurrent; TokenList *pName; int iRet; - int i; + socklen_t i; int pos; float fValue; long lID; @@ -652,7 +656,7 @@ int RemServerAction(SConnection *pCon, SicsInterp *pSics, void *pData, nChan = (rights <= usUser); rc = &remserver->rc[nChan]; if (nChan) { - SCSave(&remserver->conn, pCon); + remserver->conn = SCSave(pCon, remserver->conn); } if (argc == 1) { serverport = IFindOption(pSICSOptions,"ServerPort"); @@ -730,6 +734,7 @@ static void RemServerKill(void *self) { DeleteDescriptor(remserver->desc); if (remserver->name) free(remserver->name); if (remserver->host) free(remserver->host); + SCStoreFree(remserver->conn); free(remserver); } /*-----------------------------------------------------------------------*/ @@ -830,6 +835,7 @@ static RemServer *RemServerInit(char *name, char *host, int port) { rc->timeout = 0; } remserver->objList = NULL; + remserver->conn = NULL; if (!remserver->name || !remserver->host || !remserver->port) { diff --git a/rs232controller.c b/rs232controller.c index fec0586e..544a54f9 100644 --- a/rs232controller.c +++ b/rs232controller.c @@ -460,7 +460,7 @@ int fixRS232Error(prs232 self, int iCode){ case BADSEND: closeRS232(self); status = initRS232(self); - if(status){ + if(status > 0){ return 1; } else { return 0; diff --git a/savehdb.c b/savehdb.c new file mode 100644 index 00000000..b4b29523 --- /dev/null +++ b/savehdb.c @@ -0,0 +1,80 @@ +#include +#include "dynstring.h" +#include "statusfile.h" +#include "sicshipadaba.h" + +static void SaveHdbBranch(pHdb node, FILE *fil) { + pHdb child; + char prop[16]; + pDynString dyn; + char path[1024]; + + if (GetHdbProperty(node, "save", prop, sizeof prop)) { + if (strcmp(prop, "me") == 0) { + dyn = formatValue(node->value, node); + GetHdbPath(node, path, sizeof path); + fprintf(fil, "hupdate %s %s\n", path, GetCharArray(dyn)); + DeleteDynString(dyn); + } + for (child = node->child; child != NULL; child = child->next) { + SaveHdbBranch(child, fil); + } + } +} + +static int SaveHdbTree(void *object, char *name, FILE *fil) { + pHdb node; + + SaveHdbBranch(GetHipadabaRoot(), fil); + return 1; +} + +static hdbCallbackReturn SaveHdbCallback(pHdb node, void *userData, + pHdbMessage message) { + pHdbDataMessage mm = NULL; + + if((mm = GetHdbUpdateMessage(message)) == NULL){ + return hdbContinue; + } + + StatusFileDirty(); + return hdbContinue;; +} + +static int SaveHdbEnable(SConnection *con, SicsInterp *sics, + void *data, int argc, char *argv[]) { + pHdb node; + char prop[16]; + pHdbCallback cb; + + if (argc < 2) { + SCPrintf(con, eError, "ERROR: should be: %s ", argv[0]); + return 0; + } + + node = FindHdbNode(NULL, argv[1], con); + if (!node) { + SCPrintf(con, eError, "ERROR: %s not found", argv[1]); + return 0; + } + cb = MakeHipadabaCallback(SaveHdbCallback, NULL, NULL); + assert(cb); + AppendHipadabaCallback(node,cb); + + SetHdbProperty(node, "save", "me"); + for (node = node->mama; node != NULL; node = node->mama) { + if (!GetHdbProperty(node, "save", prop, sizeof prop)) { + SetHdbProperty(node, "save", "kids"); + } + } + StatusFileDirty(); + return 1; +} + +void SaveHdbInit(void) { + pDummy hs = NULL; + + hs = CreateDummy("hdb saver"); + hs->pDescriptor->SaveStatus = SaveHdbTree; + AddCommandWithFlag(pServ->pSics, "hsave", SaveHdbEnable, KillDummy, hs, 0); +} diff --git a/scriptcontext.c b/scriptcontext.c new file mode 100644 index 00000000..4f8524de --- /dev/null +++ b/scriptcontext.c @@ -0,0 +1,1035 @@ +#include +#include +#include +#include +#include "sics.h" +#include "sicsobj.h" +#include "splitter.h" +#include "initializer.h" +#include "commandlog.h" +#include "hipadaba.h" +#include "sicshipadaba.h" +#include "dynstring.h" +#include "devser.h" +#include "ascon.h" +#include "macro.h" +#include "scriptcontext.h" + + +#define MAX_HDB_PATH 1024 + +typedef struct ContextItem { + struct ContextItem *next; + Hdb *node; + Hdb *controllerNode; +} ContextItem; + +typedef struct ScriptContext { + ObjectDescriptor *desc; + ContextItem *nodes; + ContextItem *trash; +} ScriptContext; + +struct SctController { + DevSer *devser; + Hdb *node; /* the controller node */ + SCStore *conn; + int verbose; +}; + +/* action data and write callback data */ +typedef struct SctData { + char *name; + SctController *controller; + SCStore *conCtx; + int answered; + Hdb *node; +} SctData; + +static ScriptContext *sct = NULL; +static SCStore *currentCon = NULL; + +static struct { + char *name; +} actionCallback; + +static char *mainCallback = "main callback"; + +void PushContext(Hdb *node, Hdb *controllerNode) { + ContextItem *new; + + if (sct->trash == NULL) { + new = calloc(1, sizeof(*new)); + } else { + new = sct->trash; + sct->trash = sct->trash->next; + } + new->next = sct->nodes; + sct->nodes = new; + new->node = node; + new->controllerNode = controllerNode; +} + +void PopContext(void) { + ContextItem *c; + + c = sct->nodes; + assert(c); + sct->nodes = c->next; + c->next = sct->trash; + sct->trash = c; +} + +void CleanStack(Hdb *node) { + ContextItem *s; + + /* clean context from killed nodes */ + for (s = sct->nodes; s != NULL; s = s->next) { + if (s->node == node) { + s->node = NULL; + } + if (s->controllerNode == node) { + s->controllerNode = NULL; + } + } +} + +static void SetProp(Hdb *node, Hdb *cNode, char *key, char *value) { + char *val; + + if (node == NULL) { + if (cNode == NULL) return; + node = cNode; + } else { + val = GetHdbProp(node, key); + if (val == NULL && cNode != NULL) { + val = GetHdbProp(cNode, key); + if (val != NULL) { + node = cNode; + } + } + } + if (value == NULL) { + if (GetHdbProperty(node, key, NULL, 0) > 0) { + SetHdbProperty(node, key, ""); + } + } else { + SetHdbProperty(node, key, value); + } +} + +static char *GetProp(Hdb *node, Hdb *cNode, char *key) { + char *val; + + if (node != NULL) { + val = GetHdbProp(node, key); + if (val != NULL) return val; + } + if (cNode != NULL) { + val = GetHdbProp(cNode, key); + } + return val; +} + +/* + * This is the actual sct command available in scripts. + */ +int SctCommand(SConnection *con, SicsInterp *sics, void *object, + int argc, char *argv[]) { + static char value[1024]; + char *val; + char error[512]; + Hdb *node = NULL; + Hdb *cNode = NULL; + hdbValue v; + double dtime; + + assert(sct == object); + if (sct->nodes != NULL) { + node = sct->nodes->node; + cNode = sct->nodes->controllerNode; + } + if (node == NULL && cNode == NULL) { + SCPrintf(con, eError, "ERROR: %s may be called only in proper context", + argv[0]); + return 0; + } + if (argc <= 1) { + GetHdbPath(node, value, sizeof value); + SCWrite(con, value, eValue); + return 1; + } + + /* + * update command + */ + if(strcmp(argv[1],"update") == 0){ + cloneHdbValue(&node->value, &v); + Arg2Text(argc-2, argv+2, value, sizeof value); + if(!readHdbValue(&v, value, error, 512)){ + SCWrite(con, error, eError); + return 0; + } + UpdateHipadabaPar(node,v,con); + SetHdbProperty(node,"geterror", NULL); + return 1; + } + + /* + * print + */ + if(strcmp(argv[1],"print") == 0){ + Arg2Text(argc-2, argv+2, value, sizeof value); + SCWrite(con,value,eWarning); + return 1; + } + + /* + * time stamping + */ + if(strcmp(argv[1],"utime") == 0){ + if(argc < 3){ + SCWrite(con,"ERROR: need property to write time stamp too", + eError); + return 0; + } + dtime = DoubleTime(); + snprintf(value,1024,"%.3f",dtime); + SetHdbProperty(node,argv[2], value); + return 1; + } + + /* + * property handling + */ + if (argc == 2) { /* get case */ + val = GetProp(node, cNode, argv[1]); + if (val == NULL) { + SCPrintf(con, eError, "ERROR: %s %s not found", argv[0], argv[1]); + return 0; + } + SCWrite(con, val, eValue); + } else { /* set case */ + if (argc == 3) { + SetProp(node, cNode, argv[1], argv[2]); + } else { + val = Arg2Tcl(argc-2, argv+2, value, sizeof value); + SetProp(node, cNode, argv[1], val); + if (val != NULL && val != value) free(val); + } + } + return 1; +} + +int SctCallInContext(SConnection *con, char *script, Hdb *node, + SctController *controller, char **resPtr) { + Tcl_Interp *pTcl = InterpGetTcl(pServ->pSics); + int ret, l; + char *result = NULL; + int iRet = 1; + int verbose = controller->verbose; + + PushContext(node, controller->node); + if (verbose) { + SCPrintf(con, eInError, "\nscript: %s\n", script); + } + + MacroPush(con); + l = strlen(script); + ret = Tcl_EvalEx(pTcl, script, l, 0); + result = (char *)Tcl_GetStringResult(pTcl); + if (ret != TCL_OK && result[0]!='\0') { + if (verbose) { + SCPrintf(con, eInError, "\nerror: %s\n", result); + } + iRet = 0; + } + *resPtr = result; + + MacroPop(); + PopContext(); + return iRet; +} + +static int SctMatch(void *data1, void *data2) { + SctData *a = data1; + SctData *b = data2; + + return a->node == b->node && strcasecmp(a->name, b->name) == 0; +} + +static char *SctActionHandler(void *actionData, char *lastReply) { + SctData *data = actionData; + Hdb *node = data->node; + SctController *controller = data->controller; + char *state; + char *result; + char *script; + char *send = NULL; + int i; + SConnection *con; + char timeKey[50], timeVal[50]; + + if (currentCon) { + con = SCStorePush(currentCon); + } else { + con = SCStorePush(controller->conn); + } + SetProp(node, controller->node, "result", lastReply); + if (controller->verbose && lastReply != NULL && *lastReply != '\0') { + SCPrintf(con, eWarning, "reply : %s", lastReply); + } + state = GetProp(node, controller->node, "state"); + if (state == NULL || strcasecmp(state, "idle") == 0) { + state = data->name; + SetProp(node, controller->node, "state", state); + } + for (i = 0; i < 10; i++) { + SetProp(node, controller->node, "send", NULL); + script = GetProp(node, controller->node, state); + if (script == NULL) script = state; + + if (! SctCallInContext(con, script, node, data->controller, &result)) { + SCPrintf(con, eError, "ERROR: %s", result); + goto finish; + } + state = result; + if (strcasecmp(state, "idle") == 0) { + if (currentCon && ! data->answered) { + SCWrite(con, "o.k.", eValue); + } + if(strcmp(data->name,"write") == 0){ + SetHdbProperty(data->node,"writestatus","commandsent"); + } + snprintf(timeKey,50,"%s_time",data->name); + snprintf(timeVal,50,"%.3f", DoubleTime()); + SetHdbProperty(data->node,timeKey,timeVal); + goto finish; + } + SetProp(node, controller->node, "state", state); + send = GetProp(node, controller->node, "send"); + if (send != NULL && send[0] != '\0') { + if (controller->verbose) { + SCPrintf(con, eWarning, "send : %s", send); + } + if (currentCon) { + SCStorePop(currentCon); + } else { + SCStorePop(controller->conn); + } + return send; + } + } + SCPrintf(con, eError, "ERROR: too many quick scripts chained"); +finish: + SetProp(node, controller->node, "state", "idle"); + if (currentCon) { + SCStorePop(currentCon); + } else { + SCStorePop(controller->conn); + } + if (data->conCtx != NULL) { + SCStoreFree(data->conCtx); + data->conCtx = NULL; + } + return send; +} + +static char *SctWriteHandler(void *actionData, char *lastReply) { + SctData *data = actionData; + SCStore *old; + char *result; + + old = currentCon; + currentCon = data->conCtx; + result = SctActionHandler(data, lastReply); + currentCon = old; + return result; +} + +static int SctMatchNode(void *vNode, void *vData) { + Hdb *node = vNode; + SctData *d = vData; + + return node == d->node; +} + +static hdbCallbackReturn SctMainCallback(Hdb *node, void *userData, + hdbMessage *msg) { + SctController *controller = userData; + hdbDataSearch *dsm; + hdbDataMessage *mm; + hdbPtrMessage *pm; + hdbMessage *km; + ContextItem *s; + SConnection *con; + char *geterror; + + pm = GetKillPtrMessage(msg); + if (pm != NULL) { + if (controller == pm->pPtr) { + return hdbKill; + } + return hdbContinue; + } + dsm = GetHdbDataSearchMessage(msg); + if (dsm != NULL) { + if (dsm->testPtr == controller) { + dsm->result = controller; + return hdbAbort; + } + return hdbContinue; + } + km = GetHdbKillNodeMessage(msg); + if (km != NULL) { + /* unschedule all actions related to this node */ + DevUnschedule(controller->devser, node, SctActionHandler, SctMatchNode); + CleanStack(node); + return hdbContinue; + } + mm = GetHdbGetMessage(msg); + if (mm != NULL) { + con = mm->callData; + geterror = GetHdbProp(node, "geterror"); + if (geterror != NULL) { + SCPrintf(con, eError, "ERROR: %s", geterror); + return hdbAbort; + } + return hdbContinue; + } + + return hdbContinue; +} + +static hdbCallbackReturn SctActionCallback(Hdb *node, void *userData, + hdbMessage *msg) { + hdbDataSearch *dsm; + hdbDataMessage *mm; + hdbPtrMessage *pm; + hdbMessage *km; + SctData *data = userData; + Hdb *target; + char *script; + int l; + int iRet; + pDynString text; + DevPrio prio; + char *writeprio; + char *error; + SConnection *con; + SConnection *con2; + char path[MAX_HDB_PATH]; + + pm = GetKillPtrMessage(msg); + if (pm != NULL) { + if (data->controller == pm->pPtr) { + return hdbKill; + } + return hdbContinue; + } + dsm = GetHdbDataSearchMessage(msg); + if (dsm != NULL) { + if (dsm->testPtr == &actionCallback) { + if (strcasecmp(data->name, actionCallback.name) == 0) { + dsm->result = data; + } + return hdbAbort; + } + return hdbContinue; + } + + mm = GetHdbSetMessage(msg); + if (mm != NULL) { + con = mm->callData; + + /* set target value */ + text = formatValue(*(mm->v), node); + SetHdbProperty(node, "target", GetCharArray(text)); + + /* call check script, if available */ + script = GetProp(node, data->controller->node, "check"); + if (script != NULL) { + if (SctCallInContext(con, script, node, data->controller, &error) == 0) { + SCPrintf(con, eError, "ERROR: %s", error); + SetHdbProperty(node,"target", NULL); + return hdbAbort; + } + } + + + /* enqueue write action */ + writeprio = GetProp(node, data->controller->node, "writeprio"); + if (writeprio != NULL) { + prio = DevText2Prio(writeprio); + if (prio == NullPRIO) { + SCPrintf(con, eError, "ERROR: unknown priority: %s", writeprio); + prio = WritePRIO; + } + } else { + prio = WritePRIO; + } + + if (data->conCtx != NULL) { + con2 = SCStorePush(data->conCtx); + GetHdbPath(node, path, sizeof path); + SCPrintf(con2, eValue, "%s target changed to %s before completion", + path, GetCharArray(text)); + SCStorePop(data->conCtx); + } + DeleteDynString(text); + data->conCtx = SCSave(con, data->conCtx); + data->answered = 0; + DevQueue(data->controller->devser, data, prio, + SctWriteHandler, SctMatch, NULL); + /* no kill function in DevQueue: data is owned by the node (callback list) */ + return hdbContinue; + } + + mm = GetHdbUpdateMessage(msg); + if (mm != NULL) { + if (currentCon) { /* update called from a write action */ + data->answered = 1; + GetHdbPath(node, path, sizeof path); + con = SCStorePush(currentCon); + text = formatValue(*(mm->v), node); + SCPrintf(con, eStatus, "%s = %s", path, + GetCharArray(text)); + DeleteDynString(text); + SCStorePop(currentCon); + } + return hdbContinue; + } + return hdbContinue; +} + +static char *ParText(Hdb *cmdNode, char *name, + int nPar, char *defaultValue) { + Hdb *par; + + for (par = cmdNode->child; nPar > 0 && par != NULL; + par = par->next, nPar--) { + if (strcasecmp(par->name, name) == 0) { + if (par->value.dataType == HIPTEXT) { + return par->value.v.text; + } + } + } + return defaultValue; +} + +static double ParValue(Hdb *cmdNode, char *name, + int nPar, double defaultValue) { + Hdb *par; + + for (par = cmdNode->child; nPar > 0 && par != NULL; + par = par->next, nPar--) { + if (strcasecmp(par->name, name) == 0) { + switch (par->value.dataType) { + case HIPINT: return par->value.v.intValue; + case HIPFLOAT: return par->value.v.doubleValue; + } + } + } + return defaultValue; +} + +static void SctKillData(void *d) { + SctData *data = d; + + if (data->name) free(data->name); + if (data->conCtx) SCStoreFree(data->conCtx); + free(data); +} + +static void SctKillCBData(void *d) { + SctData *data = d; + + DevRemoveAction(data->controller->devser, data); + SctKillData(d); +} + +int SctAddPollNode(SctController *controller, Hdb *node, double interval, + DevPrio prio, char *action) { + SctData *data; + hdbCallback *cb; + + if (! FindHdbCallbackData(node, controller)) { + cb = MakeHipadabaCallback(SctMainCallback, controller, NULL); + assert(cb); + AppendHipadabaCallback(node, cb); + SetHdbProperty(node,"geterror","Not read yet"); + } + + data = calloc(1, sizeof(*data)); + assert(data); + data->controller = controller; + data->node = node; + data->conCtx = NULL; + data->name = strdup(action); + + return DevSchedule(controller->devser, data, prio, interval, + SctActionHandler, SctMatch, SctKillData); + +} + +static int SctPollCmd(pSICSOBJ ccmd, SConnection *con, + Hdb *cmdNode, Hdb *par[], int nPar) { + Hdb *node; + SctController *controller; + double interval; + char *path; + DevPrio prio; + char *action; + char *prioText; + + if(nPar < 1){ + SCPrintf(con,eError, + "ERROR: should be: %s poll ( )", + ccmd->objectNode->name); + return 0; + } + controller = ccmd->pPrivate; + path = ParText(cmdNode, "node", nPar, ""); + node = FindHdbNode(NULL, path, con); + if (node == NULL) { + SCPrintf(con, eError, "ERROR: %s not found", path); + return 0; + } + interval = ParValue(cmdNode, "interval", nPar, 5); + prioText = ParText(cmdNode, "prio", nPar, "read"); + prio = DevText2Prio(prioText); + if (prio == NullPRIO) { + SCPrintf(con,eError, "ERROR: unknown priority: %s", prioText); + return 0; + } + action = ParText(cmdNode, "action", nPar, "read"); + + if (SctAddPollNode(controller, node, interval, prio, action) > 0) { + SCPrintf(con, eValue, + "%s poll on %s changed to %g sec, %s prio", + action, path, interval, prioText); + } else { + SCPrintf(con, eValue, + "%s poll registered on %s (%g sec, %s prio)", + action, path, interval, prioText); + } + return 1; +} + +static int SctUnpollCmd(pSICSOBJ ccmd, SConnection *con, + Hdb *cmdNode, Hdb *par[], int nPar) { + SctController *controller; + double interval; + char *path; + DevPrio prio; + char *prioText; + SctData data; + + if(nPar < 1){ + SCPrintf(con,eError, + "ERROR: should be: %s poll ()", + ccmd->objectNode->name); + return 0; + } + controller = ccmd->pPrivate; + path = ParText(cmdNode, "node", nPar, ""); + data.node = FindHdbNode(NULL, path, con); + if (data.node == NULL) { + SCPrintf(con, eError, "ERROR: %s not found", path); + return 0; + } + data.name = ParText(cmdNode, "action", nPar, "read"); + if (DevUnschedule(controller->devser, &data, SctActionHandler, SctMatch) == 0) { + SCPrintf(con, eValue, + "%s poll not found on %s", data.name, path); + } else { + SCSendOK(con); + } + return 1; +} + +static int SctConnectCmd(pSICSOBJ ccmd, SConnection *con, + Hdb *cmdNode, Hdb *par[], int nPar) { + Hdb *node; + SctController *controller; + char *path; + hdbCallback *cb; + + if(nPar < 1){ + SCPrintf(con,eError, + "ERROR: should be: %s connect ", + ccmd->objectNode->name); + return 0; + } + controller = ccmd->pPrivate; + path = ParText(cmdNode, "node", nPar, ""); + node = FindHdbNode(NULL, path, con); + if (node == NULL) { + SCPrintf(con, eError, "ERROR: %s not found", path); + return 0; + } + + if (! FindHdbCallbackData(node, controller)) { + cb = MakeHipadabaCallback(SctMainCallback, controller, NULL); + assert(cb); + AppendHipadabaCallback(node, cb); + } + SCSendOK(con); + return 1; +} + +int SctAddWriteNode(SctController *controller, Hdb *node) { + hdbCallback *cb; + SctData *data; + + if (! FindHdbCallbackData(node, controller)) { + cb = MakeHipadabaCallback(SctMainCallback, controller, NULL); + assert(cb); + AppendHipadabaCallback(node, cb); + } + + actionCallback.name = "write"; /* local, so no strdup here */ + data = FindHdbCallbackData(node, &actionCallback); + if (data != NULL) { + return 0; + } + data = calloc(1, sizeof(*data)); + assert(data); + data->controller = controller; + data->node = node; + data->conCtx = NULL; + data->name = strdup("write"); + + cb = MakeHipadabaCallback(SctActionCallback, data, SctKillCBData); + assert(cb); + data->node = node; + AppendHipadabaCallback(node, cb); + RemoveSetUpdateCallback(node); + return 1; +} + +static int SctWriteCmd(pSICSOBJ ccmd, SConnection *con, + Hdb *cmdNode, Hdb *par[], int nPar) { + Hdb *node; + SctController *controller; + double interval; + char *path; + + if(nPar < 1){ + SCPrintf(con, eError, "ERROR: should be: %s write ", + ccmd->objectNode->name); + return 0; + } + controller = ccmd->pPrivate; + path = ParText(cmdNode, "node", nPar, ""); + node = FindHdbNode(NULL, path, con); + if (node == NULL) { + SCPrintf(con, eError, "ERROR: %s not found", path); + return 0; + } + if (SctAddWriteNode(controller, node) == 0) { + SCPrintf(con, eError, + "ERROR: %s has already a write action", path); + return 0; + } + + SCSendOK(con); + return 1; +} + +void SctQueueNode(SctController *controller, Hdb *node, + DevPrio prio, char *action, SConnection *con) { + SctData *data; + hdbCallback *cb; + + if (! FindHdbCallbackData(node, controller)) { + cb = MakeHipadabaCallback(SctMainCallback, controller, NULL); + assert(cb); + AppendHipadabaCallback(node, cb); + } + + data = calloc(1, sizeof(*data)); + assert(data); + data->controller = controller; + data->node = node; + data->name = strdup(action); + data->conCtx = NULL; + + DevQueue(data->controller->devser, data, prio, + SctWriteHandler, SctMatch, SctKillData); + if (con != NULL) { + data->conCtx = SCSave(con, NULL); + } + return; +} + +static int SctQueueCmd(pSICSOBJ ccmd, SConnection *con, + Hdb *cmdNode, Hdb *par[], int nPar) { + Hdb *node; + SctController *controller; + double interval; + char *path; + char *action; + DevPrio prio; + SctData *data; + char *prioText; + + if(nPar < 2){ + SCPrintf(con,eError, + "ERROR: should be: %s queue ", + ccmd->objectNode->name); + return 0; + } + controller = ccmd->pPrivate; + path = ParText(cmdNode, "node", nPar, ""); + node = FindHdbNode(NULL, path, con); + if (node == NULL) { + SCPrintf(con, eError, "ERROR: %s not found", path); + return 0; + } + prioText = ParText(cmdNode, "prio", nPar, "write"); + prio = DevText2Prio(prioText); + if (prio == NullPRIO) { + SCPrintf(con,eError, "ERROR: unknown priority: %s", prioText); + return 0; + } + action = ParText(cmdNode, "action", nPar, "write"); + + SctQueueNode(controller, node, prio, action, con); + return 1; +} + +typedef struct SctTransact { + char *command; + int sent; + SConnection *con; +}SctTransact, *pSctTransact; + +static void KillSctTransact(void *data){ + pSctTransact self = (pSctTransact)data; + if(self == NULL){ + return; + } + if(self->command){ + free(self->command); + } + free(self); +} + +static char *TransactionHandler(void *actionData, char *lastReply){ + pSctTransact st = (pSctTransact)actionData; + + if(st->sent == 0){ + st->sent = 1; + return st->command; + } else { + st->sent = 2; + SCWrite(st->con,lastReply, eValue); + return NULL; + } +} +static int SctTransactMatch(void *d1, void *d2){ + return d1 == d2; +} + +static int SctTransactCmd(pSICSOBJ ccmd, SConnection *con, + Hdb *cmdNode, Hdb *par[], int nPar) { + pSctTransact st = NULL; + SctController *c; + + c = (SctController *)ccmd->pPrivate; + + st = calloc(sizeof(SctTransact),1); + if(st == NULL){ + SCWrite(con,"ERROR: out of memory in SctTransactCommand", eError); + return 0; + } + st->con = con; + st->command = strdup(par[0]->value.v.text); + + DevQueue(c->devser, st, WritePRIO, + TransactionHandler, SctTransactMatch, NULL); + while(st->sent != 2){ + TaskYield(pServ->pTasker); + if(SCGetInterrupt(con) != eContinue){ + break; + } + } + KillSctTransact(st); + return 1; +} + +static int SctSendCmd(pSICSOBJ ccmd, SConnection *con, + Hdb *cmdNode, Hdb *par[], int nPar) { + pSctTransact st = NULL; + SctController *c; + + c = (SctController *)ccmd->pPrivate; + + st = calloc(sizeof(SctTransact),1); + if(st == NULL){ + SCWrite(con,"ERROR: out of memory in SctSendCmd", eError); + return 0; + } + st->con = con; + st->command = strdup(par[0]->value.v.text); + + DevQueue(c->devser, st, WritePRIO, + TransactionHandler, SctTransactMatch, KillSctTransact); + return 1; +} + + +static hdbCallbackReturn SctDebugCallback(Hdb *node, void *userData, + hdbMessage *msg) { + hdbDataMessage *mm; + SctController *controller = userData; + SConnection *con; + int i; + + mm = GetHdbSetMessage(msg); + if (mm != NULL) { + i = mm->v->v.intValue; + if (i < 0) { + controller->verbose = 0; + DevDebugMode(controller->devser, -1); + } else if (i == 0) { + controller->verbose = 1; + DevDebugMode(controller->devser, -1); + } else { + controller->verbose = 1; + DevDebugMode(controller->devser, i); + } + } + return hdbContinue; +} + +static void SctKillController(void *c) { + SctController *controller = c; + SConnection *con; + + CleanStack(controller->node); + RemoveSICSInternalCallback(controller); + if (controller->conn) { + con = SCLoad(controller->conn); + SCDeleteConnection(con); + SCStoreFree(controller->conn); + } + DevKill(controller->devser); + free(controller); +} + +static int SctMakeController(SConnection *con, SicsInterp *sics, + void *object, int argc, char *argv[]) { + SICSOBJ *ccmd; + Hdb *parent, *par, *cmd; + char *nodeName; + hdbCallback *cb; + SctController *controller; + + if (argc < 2) { + SCPrintf(con, eError, + "ERROR: should be %s ...", + argv[0]); + return 0; + } + + parent = FindHdbParent(NULL, argv[1], &nodeName, con); + if (parent == NULL) return 0; /* error message already written */ + + controller = calloc(1, sizeof(*controller)); + assert(controller); + controller->verbose = 0; + + ccmd = MakeSICSOBJv(nodeName, "SctController", HIPNONE, usSpy); + controller->node = ccmd->objectNode; + controller->conn = SCSave(SCCreateDummyConnection(pServ->pSics), NULL); + + assert(ccmd); + assert(controller->node->mama == NULL); + ccmd->pPrivate = controller; + ccmd->KillPrivate = SctKillController; + + AddHipadabaChild(parent, controller->node, con); + + controller->devser = DevMake(con, argc - 2, argv + 2); + if (!controller->devser) return 0; + + AddCommand(pServ->pSics, nodeName, InvokeSICSOBJ, KillSICSOBJ, ccmd); + SetDescriptorKey(ccmd->pDes, "creationCommand", "0"); + + cmd = AddSICSHdbPar(controller->node, + "poll", usMugger, MakeSICSFunc(SctPollCmd)); + AddSICSHdbPar(cmd, "node", usMugger, MakeHdbText("")); + AddSICSHdbPar(cmd, "interval", usMugger, MakeHdbFloat(5.0)); + AddSICSHdbPar(cmd, "prio", usMugger, MakeHdbText("read")); + AddSICSHdbPar(cmd, "action", usMugger, MakeHdbText("read")); + + cmd = AddSICSHdbPar(controller->node, + "unpoll", usMugger, MakeSICSFunc(SctUnpollCmd)); + AddSICSHdbPar(cmd, "node", usMugger, MakeHdbText("")); + AddSICSHdbPar(cmd, "action", usMugger, MakeHdbText("read")); + + cmd = AddSICSHdbPar(controller->node, + "connect", usMugger, MakeSICSFunc(SctConnectCmd)); + AddSICSHdbPar(cmd, "node", usMugger, MakeHdbText("")); + + cmd = AddSICSHdbPar(controller->node, + "write", usMugger, MakeSICSFunc(SctWriteCmd)); + AddSICSHdbPar(cmd, "node", usMugger, MakeHdbText("")); + + + cmd = AddSICSHdbPar(controller->node, + "queue", usMugger, MakeSICSFunc(SctQueueCmd)); + AddSICSHdbPar(cmd, "node", usMugger, MakeHdbText("")); + AddSICSHdbPar(cmd, "prio", usMugger, MakeHdbText("write")); + AddSICSHdbPar(cmd, "action", usMugger, MakeHdbText("write")); + + cmd = AddSICSHdbPar(controller->node, + "transact", usMugger, MakeSICSFunc(SctTransactCmd)); + AddSICSHdbPar(cmd, "data", usMugger, MakeHdbText("")); + + cmd = AddSICSHdbPar(controller->node, + "send", usMugger, MakeSICSFunc(SctSendCmd)); + AddSICSHdbPar(cmd, "data", usMugger, MakeHdbText("")); + + + par = AddSICSHdbPar(controller->node, "debug", usUser, MakeHdbInt(-1)); + + cb = MakeHipadabaCallback(SctDebugCallback, controller, NULL); + if (cb) AppendHipadabaCallback(par, cb); + + return 1; +} + +void SctKill(void *object) { + assert(sct == object); + ContextItem *p, *q; + + for (p = sct->nodes; p != NULL; p = q) { + q = p->next; + free(p); + } + for (p = sct->trash; p != NULL; p = q) { + q = p->next; + free(p); + } + if (sct->desc != NULL) { + DeleteDescriptor(sct->desc); + } + free(sct); + sct = NULL; +} + +void SctInit(void) { + if (sct) return; + sct = calloc(1, sizeof(*sct)); + assert(sct); + sct->desc = CreateDescriptor("ScriptContext"); + AddCommand(pServ->pSics, "sct", SctCommand, SctKill, sct); + AddCmd("makesctcontroller", SctMakeController); +} + +int SctVerbose(SctController *c){ + return c->verbose; +} diff --git a/scriptcontext.h b/scriptcontext.h new file mode 100644 index 00000000..30c5bc87 --- /dev/null +++ b/scriptcontext.h @@ -0,0 +1,38 @@ +#ifndef SCRIPTCONTEXT_H +#define SCRIPTCONTEXT_H + +#include "sics.h" +#include "devser.h" + +/* \brief an sct controller + */ +typedef struct SctController SctController; + +/** \brief queue node action to a controller + * + * \param controller the controller + * \param node the node + * \param prio the priority + * \param action the initial state + * \param con an optional connection to be used by the action scripts + */ +void SctQueueNode(SctController *controller, Hdb *node, + DevPrio prio, char *action, SConnection *con); + +/** \brief call a script and configure the sct command to be used + * in connection with the given node and controller + * + * \param con the connection + * \param script a tcl script + * \param the node to which the sct command + * \return 0 when this was a new action, > 0 when an action was overwritten + */ +int SctCallInContext(SConnection *con, char *script, Hdb *node, + SctController *controller, char **resPtr); +/** + * test the controller verbose flag + * \param c The SctController to test + * \return 1 for verbose, 0 for silent + */ +int SctVerbose(SctController *c); +#endif diff --git a/sctdriveadapter.c b/sctdriveadapter.c new file mode 100644 index 00000000..6b496fee --- /dev/null +++ b/sctdriveadapter.c @@ -0,0 +1,322 @@ +/** + * This is an adapter to a node under the control of the new + * scriptcontext generic device model. This is a wrapper around + * such a node which implements the drivable interface. + * + * Some cooperation from the node is required: It has to provide + * certain properties the value of which define scripts which + * have to be called at various stages. These are: + * + * checklimits, for limits checking + * checkstatus, for evaluating progress + * halt , for halting things + * + * copyright: see file COPYRIGHT + * + * Mark Koennecke, June 2008 + * --------------------------------------------------------------*/ +#include +#include +#include +#include +#include +#include +#include "scriptcontext.h" +/*---------------------------------------------------------------*/ +typedef struct { + pObjectDescriptor pDes; + pIDrivable pDriv; + pHdb node; + SctController *c; +}SctDrive, *pSctDrive; +/*---------------------------------------------------------------*/ +static void *SCTDRIVGetInterface(void *data, int iD){ + pSctDrive self = NULL; + + self = (pSctDrive)data; + if(self != NULL && iD == DRIVEID){ + if (self->node == NULL) return NULL; + return self->pDriv; + } else { + return NULL; + } + return NULL; +} +/*---------------------------------------------------------------- + This routine can return either OKOK or HWFault when thing + go wrong. However, the return value of Halt is usually ignored! +------------------------------------------------------------------*/ +static int SCTDRIVHalt(void *data) { + pSctDrive self = NULL; + char dummy[16]; + + self = (pSctDrive)data; + if (GetHdbProperty(self->node,"halt", dummy, sizeof dummy)) { + SctQueueNode(self->c, self->node, HaltPRIO, "halt", NULL); + } else if (GetHdbProperty(self->node, "status", dummy, sizeof dummy)) { + SetHdbProperty(self->node, "status", "idle"); + } + return OKOK; +} +/*---------------------------------------------------------------- + This routine can return either 1 or 0. 1 means the position can + be reached, 0 NOT + If 0, error shall contain up to errlen characters of information + about which limit was violated +------------------------------------------------------------------*/ +static int SCTDRIVCheckLimits(void *data, float val, + char *error, int errlen){ + pSctDrive self = NULL; + char script[1024]; + int status; + Tcl_Interp *pTcl = NULL; + char *result; + + self = (pSctDrive)data; + snprintf(script,1024,"%f", val); + SetHdbProperty(self->node,"target", script); + if(GetHdbProperty(self->node,"checklimits",script,1024)){ + status = SctCallInContext(pServ->dummyCon, script, + self->node, self->c, &result); + if(SctVerbose(self->c)){ + SCPrintf(pServ->dummyCon, eWarning, "script %s called with result %s\n ", + script, result); + } + if(status == 0){ + strncpy(error,result,errlen); + return 0; + } + } + return 1; +} +/*---------------------------------------------------------------- + This routine can return 0 when a limit problem occurred + OKOK when the motor was successfully started + HWFault when a problem occured starting the device + Possible errors shall be printed to pCon + For real motors, this is supposed to try at least three times + to start the motor in question + val is the value to drive the motor too +------------------------------------------------------------------*/ +static long SCTDRIVSetValue(void *data, SConnection *pCon, float val){ + pSctDrive self = NULL; + int status; + hdbValue v; + + self = (pSctDrive)data; + v.dataType = HIPFLOAT; + v.v.doubleValue = (double)val; + SetHdbProperty(self->node,"writestatus", "start"); + status = SetHipadabaPar(self->node, v, pCon); + if(status == 1){ + return OKOK; + } else { + return HWFault; + } +} +/*---------------------------------------------------------------- + Checks the status of a running motor. Possible return values + HWBusy The motor is still running + OKOK or HWIdle when the motor finished driving + HWFault when a hardware problem ocurred + HWPosFault when the hardware cannot reach a position + Errors are duly to be printed to pCon + For real motors CheckStatus again shall try hard to fix any + issues with the motor +------------------------------------------------------------------*/ +static int SCTDRIVCheckStatus(void *data, SConnection *pCon){ + pSctDrive self = NULL; + char script[1024]; + int status; + Tcl_Interp *pTcl = NULL; + char *result; + SConnection *con; + + self = (pSctDrive)data; + + /* + * check if the write command has gone through + */ + if(GetHdbProperty(self->node,"writestatus", script,1024)){ + if(strcmp(script,"start") == 0){ + return HWBusy; + } + } + + /* + * run the checkstatus script + */ + if(!GetHdbProperty(self->node,"checkstatus",script,1024)){ + if (!GetHdbProperty(self->node,"status",script,1024)){ + SCWrite(pCon, + "ERROR: configuration problem: no checkstatus script!", eError); + return HWFault; + } + result = script; + } else { + status = SctCallInContext(pCon,script, self->node, + self->c, &result); + if (status == 0) { + SCPrintf(pCon,eError," script %s returned %s", + script, result); + return HWFault; + } + if(SctVerbose(self->c)){ + SCPrintf(pCon,eError," script %s returned %s", + script, result); + } + } + if(strstr(result,"busy") != NULL){ + return HWBusy; + } else if(strstr(result,"posfault") != NULL){ + return HWPosFault; + } else if(strstr(result,"fault") != NULL){ + return HWFault; + } else if(strstr(result,"idle") != NULL){ + return HWIdle; + } else { + SCPrintf(pCon,eError, + "ERROR: invalid status code %s returned from checkstatus script", + result); + return HWFault; + } + return HWFault; +} +/*---------------------------------------------------------------- + GetValue is supposed to read a motor position + On errors, -99999999.99 is returned and messages printed to pCon +------------------------------------------------------------------*/ +static float SCTDRIVGetValue(void *data, SConnection *pCon){ + pSctDrive self = NULL; + float val = -99999999.99; + int status; + char error[256]; + hdbValue v; + + self = (pSctDrive)data; + if(GetHdbProperty(self->node,"geterror", error, 256)){ + SCWrite(pCon,error, eError); + return val; + } + return (float)self->node->value.v.doubleValue; +} +/*---------------------------------------------------------------- + returns NULL on failure, a new datastructure else +------------------------------------------------------------------*/ +static pSctDrive SCTDRIVMakeObject(){ + pSctDrive self = NULL; + + self = calloc(sizeof(SctDrive),1); + if(self == NULL){ + return NULL; + } + self->pDes = CreateDescriptor("SctDriveAdapter"); + self->pDriv = CreateDrivableInterface(); + if(self->pDes == NULL || self->pDriv == NULL){ + free(self); + return NULL; + } + + self->pDes->GetInterface = SCTDRIVGetInterface; + self->pDriv->Halt = SCTDRIVHalt; + self->pDriv->CheckLimits = SCTDRIVCheckLimits; + self->pDriv->SetValue = SCTDRIVSetValue; + self->pDriv->CheckStatus = SCTDRIVCheckStatus; + self->pDriv->GetValue = SCTDRIVGetValue; + + return self; +} +/*-----------------------------------------------------------------*/ +static int SctDriveCommand(SConnection *pCon, SicsInterp *sics, void *object, + int argc, char *argv[]) { + pSctDrive self = (pSctDrive)object; + float val; + + assert(self != NULL); + + if (self->node == NULL) { + SCWrite(pCon, "ERROR: defunct object", eError); + return 0; + } + /* + * only action: print value + */ + val = self->pDriv->GetValue(self,pCon); + SCPrintf(pCon,eValue,"%s = %f", argv[0], val); + return 1; +} +/*----------------------------------------------------------------*/ +static void SctDriveKill(void *data){ + pSctDrive self = (pSctDrive)data; + + if(self == NULL){ + return; + } + if(self->pDriv != NULL){ + free(self->pDriv); + } + if(self->pDes != NULL){ + DeleteDescriptor(self->pDes); + } + free(self); +} +/*----------------------------------------------------------------*/ +static hdbCallbackReturn SctDummyCallback(Hdb *node, void *userData, + hdbMessage *msg) { + return hdbContinue; +} +/*----------------------------------------------------------------*/ +static void SctDriveDeleteNode(void *data) { + pSctDrive self = (pSctDrive)data; + self->node = NULL; +} +/*---------------------------------------------------------------*/ +int SctMakeDriveAdapter(SConnection *pCon, SicsInterp *pSics, void *object, + int argc, char *argv[]) { + pSctDrive pNew = NULL; + pSICSOBJ obj = NULL; + hdbCallback *cb; + + pNew = SCTDRIVMakeObject(); + if(pNew == NULL){ + SCWrite(pCon,"ERROR: out of memory in SctMakeDriveAdapter", + eError); + return 0; + } + + if(argc < 4){ + SCWrite(pCon,"ERROR: not enough arguments for SctMakeDriveAdapter", eError); + return 0; + } + + pNew->node = FindHdbNode(NULL,argv[2], pCon); + obj = FindCommandData(pSics,argv[3], "SctController"); + if(pNew->node == NULL || obj == NULL){ + SCWrite(pCon,"ERROR: node or controller not found", eError); + SctDriveKill(pNew); + return 0; + } + pNew->c =(SctController *)obj->pPrivate; + + if (strcasecmp(argv[0],"dynsctdrive") == 0) { + /* make object dynamic by defining a descriptor command */ + SetDescriptorKey(pNew->pDes, "creationCommand", "0"); + } + AddCommand(pSics, argv[1], SctDriveCommand, SctDriveKill, pNew); + SetHdbProperty(pNew->node,"sicsdev",argv[1]); + + cb = MakeHipadabaCallback(SctDummyCallback, pNew, SctDriveDeleteNode); + assert(cb); + AppendHipadabaCallback(pNew->node, cb); + + return 1; +} +/*---------------------------------------------------------------*/ +int SctMakeDriveObject(SConnection *pCon, SicsInterp *pSics, void *object, + int argc, char *argv[]); + +void SctDriveInit(void) { + AddCmd("makesctdrive", SctMakeDriveAdapter); + AddCmd("dynsctdrive", SctMakeDriveAdapter); + AddCmd("makesctdriveobj",SctMakeDriveObject); +} diff --git a/sctdriveobj.c b/sctdriveobj.c new file mode 100644 index 00000000..e747a863 --- /dev/null +++ b/sctdriveobj.c @@ -0,0 +1,337 @@ +/** + * This is a base class for any drivable object which uses the new + * scriptcontext to control the actual driving operation. This can also + * serve as a drivable adapter to nodes in other objects. + * + * copyright: see file COPYRIGHT + * + * Mark Koennecke, June-July 2008 + */ +#include +#include +#include +#include +#include + +typedef struct { + pIDrivable pDriv; + SctController *c; + int doNotKillNode; +} DrivObjPriv, *pDrivObjPriv; +/*---------------------------------------------------------------*/ +static void *SCTDRIVGetInterface(void *data, int iD){ + pSICSOBJ self = NULL; + pDrivObjPriv pPriv; + + self = (pSICSOBJ)data; + pPriv = (pDrivObjPriv)self->pPrivate; + if(self != NULL && pPriv != NULL && iD == DRIVEID){ + if (self->objectNode == NULL) return NULL; + return pPriv->pDriv; + } else { + return NULL; + } + return NULL; +} +/*---------------------------------------------------------------- + This routine can return either OKOK or HWFault when thing + go wrong. However, the return value of Halt is usually ignored! +------------------------------------------------------------------*/ +static int SCTDRIVHalt(void *data) { + pSICSOBJ self = NULL; + pDrivObjPriv pPriv; + char dummy[16]; + + self = (pSICSOBJ)data; + pPriv = (pDrivObjPriv)self->pPrivate; + if (GetHdbProperty(self->objectNode,"halt", dummy, sizeof dummy)) { + SctQueueNode(pPriv->c, self->objectNode, HaltPRIO, "halt", NULL); + } else if (GetHdbProperty(self->objectNode, "status", dummy, sizeof dummy)) { + SetHdbProperty(self->objectNode, "status", "idle"); + } + return OKOK; +} +/*---------------------------------------------------------------- + This routine can return either 1 or 0. 1 means the position can + be reached, 0 NOT + If 0, error shall contain up to errlen characters of information + about which limit was violated +------------------------------------------------------------------*/ +static int SCTDRIVCheckLimits(void *data, float val, + char *error, int errlen){ + pSICSOBJ self = NULL; + pDrivObjPriv pPriv; + char script[1024]; + int status; + Tcl_Interp *pTcl = NULL; + char *result; + + self = (pSICSOBJ)data; + pPriv = (pDrivObjPriv)self->pPrivate; + snprintf(script,1024,"%f", val); + SetHdbProperty(self->objectNode,"target", script); + if(GetHdbProperty(self->objectNode,"checklimits",script,1024)){ + status = SctCallInContext(pServ->dummyCon, script, + self->objectNode, pPriv->c, &result); + if(SctVerbose(pPriv->c)){ + SCPrintf(pServ->dummyCon, eWarning, "script %s called with result %s\n ", + script, result); + } + if(status == 0){ + strncpy(error,result,errlen); + return 0; + } + } + return 1; +} +/*---------------------------------------------------------------- + This routine can return 0 when a limit problem occurred + OKOK when the motor was successfully started + HWFault when a problem occured starting the device + Possible errors shall be printed to pCon + For real motors, this is supposed to try at least three times + to start the motor in question + val is the value to drive the motor too +------------------------------------------------------------------*/ +static long SCTDRIVSetValue(void *data, SConnection *pCon, float val){ + pSICSOBJ self = NULL; + pDrivObjPriv pPriv; + int status; + hdbValue v; + + self = (pSICSOBJ)data; + pPriv = (pDrivObjPriv)self->pPrivate; + + v.dataType = HIPFLOAT; + v.v.doubleValue = (double)val; + SetHdbProperty(self->objectNode,"writestatus", "start"); + status = SetHipadabaPar(self->objectNode, v, pCon); + if(status == 1){ + return OKOK; + } else { + return HWFault; + } +} +/*---------------------------------------------------------------- + Checks the status of a running motor. Possible return values + HWBusy The motor is still running + OKOK or HWIdle when the motor finished driving + HWFault when a hardware problem ocurred + HWPosFault when the hardware cannot reach a position + Errors are duly to be printed to pCon + For real motors CheckStatus again shall try hard to fix any + issues with the motor +------------------------------------------------------------------*/ +static int SCTDRIVCheckStatus(void *data, SConnection *pCon){ + pSICSOBJ self = NULL; + pDrivObjPriv pPriv; + char script[1024]; + int status; + Tcl_Interp *pTcl = NULL; + char *result; + SConnection *con; + + self = (pSICSOBJ)data; + pPriv = (pDrivObjPriv)self->pPrivate; + + /* + * check if the write command has gone through + */ + if(GetHdbProperty(self->objectNode,"writestatus", script,1024)){ + if(strcmp(script,"start") == 0){ + return HWBusy; + } + } + + /* + * run the checkstatus script + */ + if(!GetHdbProperty(self->objectNode,"checkstatus",script,1024)){ + if (!GetHdbProperty(self->objectNode,"status",script,1024)){ + SCWrite(pCon, + "ERROR: configuration problem: no checkstatus script!", eError); + return HWFault; + } + result = script; + } else { + status = SctCallInContext(pCon,script, self->objectNode, + pPriv->c, &result); + if (status == 0) { + SCPrintf(pCon,eError," script %s returned %s", + script, result); + return HWFault; + } + if(SctVerbose(pPriv->c)){ + SCPrintf(pCon,eError," script %s returned %s", + script, result); + } + } + if(strstr(result,"busy") != NULL){ + return HWBusy; + } else if(strstr(result,"posfault") != NULL){ + return HWPosFault; + } else if(strstr(result,"fault") != NULL){ + return HWFault; + } else if(strstr(result,"idle") != NULL){ + return HWIdle; + } else { + SCPrintf(pCon,eError, + "ERROR: invalid status code %s returned from checkstatus script", + result); + return HWFault; + } + return HWFault; +} +/*---------------------------------------------------------------- + GetValue is supposed to read a motor position + On errors, -99999999.99 is returned and messages printed to pCon +------------------------------------------------------------------*/ +static float SCTDRIVGetValue(void *data, SConnection *pCon){ + pSICSOBJ self = NULL; + pDrivObjPriv pPriv; + float val = -99999999.99; + int status; + char error[256]; + hdbValue v; + + self = (pSICSOBJ)data; + pPriv = (pDrivObjPriv)self->pPrivate; + if(GetHdbProperty(self->objectNode,"geterror", error, 256)){ + SCWrite(pCon,error, eError); + return val; + } + return (float)self->objectNode->value.v.doubleValue; +} +/*-----------------------------------------------------------------*/ +void AssignSctDrive(pIDrivable pDriv){ + pDriv->Halt = SCTDRIVHalt; + pDriv->CheckLimits = SCTDRIVCheckLimits; + pDriv->SetValue = SCTDRIVSetValue; + pDriv->CheckStatus = SCTDRIVCheckStatus; + pDriv->GetValue = SCTDRIVGetValue; +} +/*---------------------------------------------------------------------------*/ +static void KillDriveOBJ(void *data){ + pSICSOBJ self = (pSICSOBJ)data; + pDrivObjPriv pPriv; + + if(self == NULL){ + return; + } + + pPriv = (pDrivObjPriv)self->pPrivate; + if(pPriv->doNotKillNode && self->pDes != NULL){ + if(self->pDes->name) free(self->pDes->name); + if(self->pDes->pKeys) IFDeleteOptions(self->pDes->pKeys); + free(self->pDes); + } else { + DeleteDescriptor(self->pDes); /* kill descriptor including node */ + } + if(self->KillPrivate != NULL && self->pPrivate != NULL){ + self->KillPrivate(self->pPrivate); + } + RemoveHdbNodeFromParent(self->objectNode, pServ->dummyCon); + free(self); +} +/*-----------------------------------------------------------------------------*/ +pSICSOBJ MakeSctDriveObj(pHdb node, char *class, SctController *c){ + pSICSOBJ pNew = NULL; + pDrivObjPriv pPriv = NULL; + hdbValue val; + + pNew = (pSICSOBJ)malloc(sizeof(SICSOBJ)); + pPriv = (pDrivObjPriv)malloc(sizeof(DrivObjPriv)); + if(pNew == NULL || pPriv == NULL){ + return NULL; + } + memset(pNew,0,sizeof(SICSOBJ)); + memset(pPriv,0,sizeof(DrivObjPriv)); + + pNew->pDes = CreateDescriptor(class); + pPriv->pDriv = CreateDrivableInterface(); + if(pNew->pDes == NULL || pPriv->pDriv == NULL){ + free(pNew); + free(pPriv); + return(NULL); + } + pNew->objectNode = node; + AssignSctDrive(pPriv->pDriv); + pPriv->c = c; + pNew->pDes->parNode = pNew->objectNode; + pNew->pDes->GetInterface = SCTDRIVGetInterface; + pNew->pPrivate = pPriv; + pNew->KillPrivate = DefaultKill; + return pNew; +} +/*-------------------------------------------------------------------------- + * This actually has two syntaxes: + * makesctdrive name path-to-existing-node class SctController + * makesctdrive name type priv class SctController + *--------------------------------------------------------------------------*/ +int SctMakeDriveObject(SConnection *pCon, SicsInterp *pSics, void *object, + int argc, char *argv[]) { + pHdb node = NULL; + pDrivObjPriv pPriv = NULL; + pSICSOBJ pNew = NULL; + pSICSOBJ pSct = NULL; + SctController *c = NULL; + int priv, type, status; + hdbValue val; + + if(argc < 5){ + SCWrite(pCon,"ERROR: not enough arguments to SctMakeDriveObject", eError); + return 0; + } + + node = FindHdbNode(NULL,argv[2], pCon); + if(node != NULL){ + pSct = FindCommandData(pSics,argv[4], "SctController"); + if(pSct == NULL){ + SCPrintf(pCon,eError, "ERROR: SctController %s not found", argv[4]); + return 0; + } + c = (SctController *)pSct->pPrivate; + pNew = MakeSctDriveObj(node,argv[3],c); + pPriv = (pDrivObjPriv)pNew->pPrivate; + pPriv->doNotKillNode = 1; /* the node is owned by someone else*/ + } else { + /* convert privilege */ + priv = decodeSICSPriv(argv[3]); + /* convert datatype */ + strtolower(argv[4]); + type = convertHdbType(argv[2]); + if (type == HIPNONE) { + node = MakeHipadabaNode(argv[1], HIPNONE, 1); + } else { + val = makeHdbValue(type,0); + node = MakeSICSHdbPar(argv[1], priv, val); + ReleaseHdbValue(&val); + } + if(node == NULL){ + SCWrite(pCon,"ERROR: node creation failed", eError); + return 0; + } + c = FindCommandData(pSics,argv[5], "SctController"); + if(c == NULL){ + SCPrintf(pCon,eError, "ERROR: SctController %s not found", argv[4]); + return 0; + } + pNew = MakeSctDriveObj(node,argv[3],c); + } + if(pNew == NULL){ + SCWrite(pCon,"ERROR: failed to create drive object", eError); + return 0; + } + status = AddCommand(pSics, + argv[1], + InterInvokeSICSOBJ, + KillDriveOBJ, + pNew); + if(status != 1){ + KillSICSOBJ(pNew); + SCPrintf(pCon,eError,"ERROR: failed create duplicate command %s", argv[1]); + return 0; + } + return 1; +} + diff --git a/selvar.c b/selvar.c index 492dec11..a8533910 100644 --- a/selvar.c +++ b/selvar.c @@ -163,6 +163,7 @@ static int CheckVal(void *pSelf, SConnection *pCon ) { pSelVar self = NULL; + int status; self = (pSelVar)pSelf; assert(self); @@ -173,7 +174,12 @@ self->pCon = pCon; InvokeCallBack(self->pCall, WLCHANGE, self); - return MonoCheck(self->pSel,pCon); + status = MonoCheck(self->pSel,pCon); + if(status != HWBusy) + { + InvokeCallBack(self->pCall, WLCHANGE, self); + } + return status; } /*------------------------------------------------------------------------*/ static int HaltSelVar(void *pSelf) diff --git a/servlog.c b/servlog.c index 12654af9..1f3406db 100644 --- a/servlog.c +++ b/servlog.c @@ -253,6 +253,7 @@ static const char* timestamp(struct timeval *tp) { int OpenVerifyLogFile() { char pFile[256]; + char filnam[512]; char *pChar = NULL; pChar = IFindOption(pSICSOptions,"LogFileBaseName"); @@ -262,10 +263,10 @@ static const char* timestamp(struct timeval *tp) { } else { - strcpy(pFile,pChar); + strncpy(pFile,pChar,255); } - sprintf(pFile,"%s%2.2d.log",pFile, iFile); - fLogFile = fopen(pFile,"w"); + snprintf(filnam,511,"%s%2.2d.log",pFile, iFile); + fLogFile = fopen(filnam,"w"); if(!fLogFile) { fprintf(stderr,"ERROR: Cannot open logfile %s for writing\n",pFile); @@ -278,6 +279,10 @@ static const char* timestamp(struct timeval *tp) { } } +/*---------------------------------------------------------------------------*/ + void SICSLogEnable(int flag) { + iLogUsable=flag; + } /*---------------------------------------------------------------------------*/ void SICSLogWriteTime(char *pText, OutCode eOut, struct timeval *tp) { diff --git a/servlog.h b/servlog.h index 2b345d0b..bea78378 100644 --- a/servlog.h +++ b/servlog.h @@ -17,6 +17,7 @@ #include "Scommon.h" void SICSLogWrite(char *ptext, OutCode eOut ); void SICSLogWriteTime(char *ptext, OutCode eOut, struct timeval *tp ); + void SICSLogEnable(int flag); int KillCapture(SConnection *pCon); int LogCapture(SConnection *pCon, SicsInterp *pInter, void *pData, diff --git a/sicscron.c b/sicscron.c index 76536b5c..38585f38 100644 --- a/sicscron.c +++ b/sicscron.c @@ -27,6 +27,11 @@ Statistics *stat; } Cron, *pCron; + typedef struct { + SConnection *pCon; + int dolater; + } CronListData; + /*------------------------------------------------------------------------*/ static void KillCron(void *pData) { @@ -92,15 +97,32 @@ { pCron self = (pCron)pData; int *iInt; - + struct tm tm; + char datim[24]; + CronListData *data; + if(iID == SICSINT) { iInt = (int *)pSigData; if(*iInt >= eEndServer) - { + { self->iEnd = 0; } } + if(iID == CRONLIST) { + data = pSigData; + if (self->iEnd == 2 && data->dolater) { + tm = *localtime(&self->tNext); + strftime(datim, sizeof datim, "%Y-%m-%d %T", &tm); + SCPrintf(data->pCon, eStatus, "%s %s", datim, + self->pCommand); + } else if (self->iEnd == 1 && !data->dolater) { + tm = *localtime(&self->tNext); + strftime(datim, sizeof datim, "%Y-%m-%d %T", &tm); + SCPrintf(data->pCon, eStatus, "%s %8d %s", datim, + self->iInterval, self->pCommand); + } + } } /*-----------------------------------------------------------------------*/ int MakeCron(SConnection *pCon, SicsInterp *pSics, void *pData, @@ -109,6 +131,7 @@ pCron pNew = NULL; int iVal, iRet, rights; char *cmd; + CronListData data; /* need user priv. */ if(!SCMatchRights(pCon,usUser)) @@ -116,6 +139,19 @@ return 0; } + if (argc == 2 && strcasecmp(argv[1], "list") == 0) { + if (strcasecmp(argv[0], "dolater") == 0) { + data.dolater = 1; + SCPrintf(pCon, eError, "Date Time Command"); + } else { + data.dolater = 0; + SCPrintf(pCon, eError, "Date Time Interval Command"); + } + data.pCon = pCon; + TaskSignal(pServ->pTasker, CRONLIST, &data); + return 1; + } + /* enough arguments? */ if(argc < 3) { @@ -153,12 +189,13 @@ /* transfer the rights to the dummy connection */ SCSetRights(pNew->pCon, rights); } - pNew->iInterval = iVal; pNew->pCommand = cmd; pNew->tNext = time(NULL) + iVal; if (strcasecmp(argv[0], "dolater") == 0) { + pNew->iInterval = -1; pNew->iEnd = 2; } else { + pNew->iInterval = iVal; pNew->iEnd = 1; } pNew->stat = StatisticsNew(cmd); diff --git a/sicsdata.c b/sicsdata.c index 4e2e0d67..6c1d12a9 100644 --- a/sicsdata.c +++ b/sicsdata.c @@ -13,6 +13,7 @@ #include #include #include +#include #include "fortify.h" #include "sics.h" #include "splitter.h" @@ -179,8 +180,16 @@ static void netEncode(pSICSData self){ /*---------------------------------------------------------------------*/ void clearSICSData(pSICSData self){ assert(self); + int clearSize = 8192; self->dataUsed = 0; + if(self->currentDataSize > clearSize){ + free(self->data); + free(self->dataType); + self->data = (int *)malloc(clearSize*sizeof(int)); + self->dataType = (char *)malloc(clearSize*sizeof(char)); + self->currentDataSize = clearSize; + } memset(self->data,0,self->currentDataSize*sizeof(int)); memset(self->dataType,0,self->currentDataSize*sizeof(char)); } @@ -375,6 +384,23 @@ static int divideSicsData(pSICSData self, SicsInterp *pSics, } return 1; } +/*------------------------------------------------------------------*/ +static int scaleSicsData(pSICSData self, SicsInterp *pSics, + SConnection *pCon, float scale){ + int i; + float div; + + for(i = 0; i < self->dataUsed; i++){ + div = getDataPos(self,i); + div *= scale; + if(self->dataType[i] == INTTYPE){ + self->data[i] = (int)fabsf(div); + } else { + memcpy(&self->data[i],&div,sizeof(float)); + } + } + return 1; +} /*-------------------------------------------------------------------*/ static int copyScanCounts(pSICSData self, int argc, char *argv[], SConnection *pCon, SicsInterp *pSics){ @@ -551,8 +577,7 @@ static int copyTimeBin(pSICSData self, int argc, char *argv[], return 0; } for(i = 0; i < noTimeBin; i++){ - memcpy(iData + pos + i, fTimeBin + i, sizeof(float)); - self->dataType[pos+i] = FLOATTYPE; + setSICSDataInt(self,pos+i,(int)(fTimeBin[i])); } SCSendOK(pCon); return 1; @@ -703,6 +728,7 @@ int SICSDataAction(SConnection *pCon, SicsInterp *pSics, void *pData, pSICSData self = NULL; char pBueffel[132]; int pos; + float scale; self = (pSICSData)pData; assert(self); @@ -750,6 +776,12 @@ int SICSDataAction(SConnection *pCon, SicsInterp *pSics, void *pData, return 0; } return divideSicsData(self,pSics,pCon,argv[2]); + } else if(strcmp(argv[1],"scale") == 0){ + if(argc < 3){ + SCWrite(pCon,"ERROR: need a scale factor to apply",eError); + return 0; + } + return scaleSicsData(self,pSics,pCon,atof(argv[2])); } else if(strcmp(argv[1],"copydata") == 0){ return copyData(self,pSics,pCon,argc, argv); } else if(strcmp(argv[1],"putint") == 0){ diff --git a/sicshdbadapter.c b/sicshdbadapter.c index 45bb1f0b..4ff4ccbd 100644 --- a/sicshdbadapter.c +++ b/sicshdbadapter.c @@ -20,9 +20,14 @@ #include "stptok.h" #include "motor.h" #include "HistMem.h" +#include "HistMem.i" +#include "HistDriv.i" #include "sicsvar.h" +#include "counter.h" +#include "lld.h" #include "sicshipadaba.h" #include "sicshdbadapter.h" +#include "sicsdata.h" #define PRIVNAM "privilege" /*==================== support code ====================================*/ @@ -91,45 +96,68 @@ static int MotorValueCallback(int iEvent, void *eventData, void *userData, return 1; } /*---------------------------------------------------------------------*/ -static int MotorParSetCallback(void *userData, void *callData, - pHdb currentNode, hdbValue v){ +static hdbCallbackReturn MotorParSetCallback(pHdb currentNode, void *userData, + pHdbMessage message){ pMotor pMot = (pMotor)userData; - SConnection *pCon = (SConnection *)callData; + SConnection *pCon = NULL; int status; + pHdbDataMessage mm = NULL; + + if((mm = GetHdbSetMessage(message)) == NULL){ + return hdbContinue; + } + pCon = mm->callData; assert(pMot != NULL && pCon != NULL); - status = MotorSetPar(pMot,pCon,currentNode->name, (float)v.v.doubleValue); - return status; + status = MotorSetPar(pMot,pCon,currentNode->name, + (float)mm->v->v.doubleValue); + if(status == 1){ + return hdbContinue; + } else { + return hdbAbort; + } } /*----------------------------------------------------------------------*/ -static int MotorParGetCallback(void *userData, void *callData, - pHdb currentNode, hdbValue v){ +static hdbCallbackReturn MotorParGetCallback(pHdb currentNode, void *userData, + pHdbMessage message){ pMotor pMot = (pMotor)userData; float fVal; int status; - + pHdbDataMessage mm = NULL; + + if((mm = GetHdbGetMessage(message)) == NULL){ + return hdbContinue; + } + assert(pMot != NULL); status = MotorGetPar(pMot,currentNode->name,&fVal); currentNode->value.v.doubleValue = fVal; - return status; + if(status == 1){ + return hdbContinue; + } else { + return hdbAbort; + } } /*---------------------------------------------------------------------*/ static pHdb MakeMotParNode(char *name, pMotor pMot){ pHdb node = NULL; pHdbCallback pCall = NULL; + char command[1024]; node = MakeHipadabaNode(name, HIPFLOAT, 1); if(node != NULL) { - pCall = MakeHipadabaCallback(MotorParSetCallback,pMot,NULL,-1,-1); + pCall = MakeHipadabaCallback(MotorParSetCallback,pMot,NULL); if(pCall == NULL){ return NULL; } - AppendHipadabaCallback(node,HCBSET,pCall); - pCall = MakeHipadabaCallback(MotorParGetCallback,pMot,NULL,-1,-1); + AppendHipadabaCallback(node,pCall); + pCall = MakeHipadabaCallback(MotorParGetCallback,pMot,NULL); if(pCall == NULL){ return NULL; } - AppendHipadabaCallback(node,HCBREAD,pCall); + AppendHipadabaCallback(node,pCall); + snprintf(command,1023,"%s %s ", pMot->name, name); + SetHdbProperty(node,"sicscommand", command); } return node; } @@ -284,50 +312,70 @@ static long totalSum(int *data, int length){ return result; } /*----------------------------------------------------------------------*/ -static int HMDataGetCallback(void *userData, void *callData, - pHdb currentNode, hdbValue v){ - pHistMem pHM = (pHistMem)userData; - SConnection *pCon = (SConnection *)callData; - long sum1, sum2; +typedef struct { + pHistMem pHM; + long oldSum; +} HMAdapter, *pHMAdapter; +/*-------------------------------------------------------------------------*/ +static hdbCallbackReturn HMDataGetCallback(pHdb currentNode, void *userData, + pHdbMessage message){ + pHMAdapter pHMA = (pHMAdapter)userData; + SConnection *pCon = NULL; + long sum1; + pHdbDataMessage mm = NULL; - assert(pHM != NULL); + if((mm = GetHdbGetMessage(message)) == NULL){ + return hdbContinue; + } + pCon = mm->callData; + assert(pHMA != NULL && pHMA->pHM != NULL); if(pCon == NULL){ - return 0; + return hdbAbort; } + currentNode->value.arrayLength = GetHistLength(pHMA->pHM); + currentNode->value.v.intArray = (int *)GetHistogramPointer(pHMA->pHM,pCon); sum1 = totalSum(currentNode->value.v.intArray, currentNode->value.arrayLength); - currentNode->value.arrayLength = GetHistLength(pHM); - currentNode->value.v.intArray = (int *)GetHistogramPointer(pHM,pCon); - sum2 = totalSum(currentNode->value.v.intArray, currentNode->value.arrayLength); - if(sum1 != sum2){ + if(sum1 != pHMA->oldSum){ UpdateHipadabaPar(currentNode,currentNode->value,NULL); + pHMA->oldSum = sum1; } - return 1; + return hdbContinue; } /*----------------------------------------------------------------------*/ static pHdb MakeHMDataNode(pHistMem pHM, char *name){ pHdb node = NULL; pHdbCallback pCall = NULL; - + pHMAdapter pHMA = NULL; node = MakeHipadabaNode(name,HIPINTVARAR,2); - if(node == NULL){ + pHMA = malloc(sizeof(HMAdapter)); + if(node == NULL || pHMA == NULL){ return NULL; } - pCall = MakeHipadabaCallback(HMDataGetCallback,pHM,NULL,-1,-1); + pHMA->pHM = pHM; + pHMA->oldSum = 0; + node->value.doNotFree = 1; + pCall = MakeHipadabaCallback(HMDataGetCallback,pHMA,free); if(pCall == NULL){ return NULL; } - AppendHipadabaCallback(node,HCBREAD,pCall); - AppendHipadabaCallback(node,HCBSET,MakeReadOnlyCallback()); + AppendHipadabaCallback(node,pCall); + AppendHipadabaCallback(node,MakeReadOnlyCallback()); return node; } /*================ SICS Variable ======================================*/ -static int SicsVarSetCallback(void *userData, void *callData, - pHdb currentNode, hdbValue v){ +static hdbCallbackReturn SicsVarSetCallback(pHdb currentNode, void *userData, + pHdbMessage message){ pSicsVariable pVar = (pSicsVariable)userData; - SConnection *pCon = (SConnection *)callData; + SConnection *pCon = NULL; int userRights = usMugger; + pHdbDataMessage mm = NULL; + + if((mm = GetHdbSetMessage(message)) == NULL){ + return hdbContinue; + } + pCon = mm->callData; assert(pVar != NULL); @@ -336,16 +384,16 @@ static int SicsVarSetCallback(void *userData, void *callData, } switch(currentNode->value.dataType){ case HIPINT: - VarSetInt(pVar, v.v.intValue, userRights); + VarSetInt(pVar, mm->v->v.intValue, userRights); break; case HIPFLOAT: - VarSetFloat(pVar, (float)v.v.doubleValue, userRights); + VarSetFloat(pVar, (float)mm->v->v.doubleValue, userRights); break; case HIPTEXT: - VarSetText(pVar, v.v.text, userRights); + VarSetText(pVar, mm->v->v.text, userRights); break; } - return 1; + return hdbContinue; } /*----------------------------------------------------------------------*/ static int ValueCallback(int iEvent, void *eventData, void *userData, @@ -399,13 +447,13 @@ static pHdb MakeSicsVarNode(pSicsVariable pVar, char *name){ } else { AddPrivProperty(node,pVar->iAccessCode); } - pCall = MakeHipadabaCallback(SicsVarSetCallback,pVar,NULL,-1,-1); + pCall = MakeHipadabaCallback(SicsVarSetCallback,pVar,NULL); if(pCall == NULL){ return NULL; } strncpy(comCom.deviceID,name,255); comCom.transID = -77; - AppendHipadabaCallback(node,HCBSET,pCall); + AppendHipadabaCallback(node,pCall); RegisterCallback(pVar->pCall,comCom, VALUECHANGE, ValueCallback, node,NULL); switch(pVar->eType){ @@ -424,10 +472,156 @@ static pHdb MakeSicsVarNode(pSicsVariable pVar, char *name){ node->protected = 1; return node; } +/*================ counter =============================================*/ +typedef struct { + pHdb node; + int monitor; /* -1 == time */ + pCounter counter; +} CountEntry; +static int countList = -10; +/*---------------------------------------------------------------------*/ +static void updateCountList(){ + int status; + hdbValue v; + CountEntry hugo; + long monitor; + float time; + SConnection *pDummy = NULL; + + if(countList < 0){ + return; + } + pDummy = SCCreateDummyConnection(pServ->pSics); + if(pDummy == NULL){ + return; + } + + status = LLDnodePtr2First(countList); + while(status != 0){ + LLDnodeDataTo(countList,&hugo); + if(hugo.monitor < 0){ + time = GetCountTime(hugo.counter,pDummy); + v = MakeHdbFloat((double)time); + UpdateHipadabaPar(hugo.node,v, NULL); + } else { + monitor = GetMonitor(hugo.counter, hugo.monitor, pDummy); + v = MakeHdbInt((int)monitor); + UpdateHipadabaPar(hugo.node,v, NULL); + } + status = LLDnodePtr2Next(countList); + } + SCDeleteConnection(pDummy); +} +/*---------------------------------------------------------------------------*/ +static int CounterCallback(int iEvent, void *eventData, void *userData, + commandContext cc){ + if(iEvent == MONITOR || iEvent == COUNTEND){ + updateCountList(); + } + return 1; +}/*=================== SICSData ========================================*/ +static void copyIntSicsData(pHdb node, pSICSData data){ + if(node->value.arrayLength != data->dataUsed){ + if(node->value.v.intArray != NULL){ + free(node->value.v.intArray); + } + node->value.arrayLength = data->dataUsed; + node->value.v.intArray = malloc(data->dataUsed*sizeof(int)); + if(node->value.v.intArray == NULL){ + node->value.arrayLength = 0; + return; + } + } + memcpy(node->value.v.intArray, data->data, + data->dataUsed*sizeof(int)); +} +/*-----------------------------------------------------------------------*/ +static void copyFloatSicsData(pHdb node, pSICSData data){ + int i; + float val; + + if(node->value.arrayLength != data->dataUsed){ + if(node->value.v.floatArray != NULL){ + free(node->value.v.floatArray); + } + node->value.arrayLength = data->dataUsed; + node->value.v.floatArray = malloc(data->dataUsed*sizeof(double)); + if(node->value.v.floatArray == NULL){ + node->value.arrayLength = 0; + return; + } + } + for(i = 0; i < data->dataUsed; i++){ + getSICSDataFloat(data,i,&val); + node->value.v.floatArray[i] = val; + } +} +/*----------------------------------------------------------------------*/ +static hdbCallbackReturn SICSDataCallback(pHdb node, void *userData, + pHdbMessage message){ + pSICSData self = (pSICSData)userData; + pHdbDataMessage mm = NULL; + int i, status; + char script[256], error[1024]; + + assert(self != NULL); + + /* + * I have to make copies because the floats in SICSData + * are floats but doubles in Hipdaba. Siiiigggghhhh! + * But it is cleaner in some way anyway. + */ + if((mm = GetHdbGetMessage(message)) != NULL){ + memset(script,0,256); + if(GetHdbProperty(node,"readscript", script,256) == 1){ + status = Tcl_Eval(InterpGetTcl(pServ->pSics),script); + if(status != TCL_OK){ + snprintf(error,1023,"ERROR: Tcl returned error: %s", + Tcl_GetStringResult(InterpGetTcl(pServ->pSics))); + if(mm->callData != NULL){ + SCWrite((SConnection *)mm->callData, error, eError); + return hdbAbort; + } + } + } + if(node->value.dataType == HIPINTVARAR){ + copyIntSicsData(node, self); + } else if(node->value.dataType == HIPFLOATVARAR){ + copyFloatSicsData(node, self); + } + return hdbContinue; + } + + if((mm = GetHdbSetMessage(message)) != NULL){ + if(node->value.dataType == HIPINTVARAR){ + for(i = 0; i < mm->v->arrayLength; i++){ + setSICSDataInt(self,i,mm->v->v.intArray[i]); + } + } else if(node->value.dataType == HIPFLOATVARAR){ + for(i = 0; i < mm->v->arrayLength; i++){ + setSICSDataFloat(self,i,(float)mm->v->v.floatArray[i]); + } + } + memset(script,0,256); + if(GetHdbProperty(node,"writescript", script,256) == 1){ + status = Tcl_Eval(InterpGetTcl(pServ->pSics),script); + if(status != TCL_OK){ + snprintf(error,1023,"ERROR: Tcl returned error: %s", + Tcl_GetStringResult(InterpGetTcl(pServ->pSics))); + if(mm->callData != NULL){ + SCWrite((SConnection *)mm->callData, error, eError); + return hdbAbort; + } + } + } + return hdbContinue; + } + + return hdbContinue; +} /*============== interpreter function ==================================*/ int SICSHdbAdapter(SConnection *pCon, SicsInterp *pSics, void *pData, int argc, char *argv[]){ - pHdb root = NULL; pHdb path = NULL; pHdb node = NULL; pMotor pMot = NULL; @@ -436,9 +630,11 @@ int SICSHdbAdapter(SConnection *pCon, SicsInterp *pSics, void *pData, pIDrivable pDriv = NULL; pSicsVariable pVar = NULL; char buffer[512]; - - root = GetHipadabaRoot(); - assert(root != NULL); + pCounter pCount = NULL; + CountEntry hugo; + pSICSData data = NULL; + int type; + pHdbCallback pCall = NULL; if(!SCMatchRights(pCon,usMugger)){ return 0; @@ -448,7 +644,7 @@ int SICSHdbAdapter(SConnection *pCon, SicsInterp *pSics, void *pData, return 0; } - path = GetHipadabaNode(root,argv[1]); + path = FindHdbNode(NULL,argv[1],pCon); if(path == NULL){ SCWrite(pCon,"ERROR: path to attach object too not found",eError); return 0; @@ -518,9 +714,116 @@ int SICSHdbAdapter(SConnection *pCon, SicsInterp *pSics, void *pData, return 1; } + /** + * look for counters + */ + pCount = (pCounter)FindCommandData(pSics,argv[2],"SingleCounter"); + if(pCount != NULL){ + hugo.monitor = atoi(argv[3]); + hugo.counter = pCount; + hugo.node = path; + if(countList < 0){ + countList = LLDcreate(sizeof(CountEntry)); + RegisterCallback(pCount->pCall, SCGetContext(pCon), + COUNTSTART, CounterCallback, + NULL, NULL); + RegisterCallback(pCount->pCall, SCGetContext(pCon), + COUNTEND, CounterCallback, + NULL, NULL); + RegisterCallback(pCount->pCall, SCGetContext(pCon), + MONITOR, CounterCallback, + NULL, NULL); + } + LLDnodeAppendFrom(countList,&hugo); + SCSendOK(pCon); + return 1; + } + + /** + * look for SICSData + */ + data = (pSICSData)FindCommandData(pSics,argv[2],"SICSData"); + if(data != NULL){ + if(argc < 5){ + SCWrite(pCon,"ERROR: need type and name to create SICSData adapter", + eError); + return 0; + } + type = convertHdbType(argv[3]); + if(type != HIPINTVARAR && type != HIPFLOATVARAR ){ + SCWrite(pCon, + "ERROR: need intvarar or floatvarar type for SICSData adapter", + eError); + return 0; + } + node = MakeHipadabaNode(argv[4],type,0); + if(node == NULL){ + SCWrite(pCon,"ERROR: out of memory in SICSHdbAdapter", eError); + return 0; + } + pCall = MakeHipadabaCallback(SICSDataCallback,data,NULL); + if(pCall == NULL){ + SCWrite(pCon,"ERROR: out of memory in SICSHdbAdapter", eError); + return 0; + } + AppendHipadabaCallback(node,pCall); + AddHipadabaChild(path,node,pCon); + SCSendOK(pCon); + return 1; + } + snprintf(buffer,511, "ERROR: attaching this type of object: %s at %s not implemented", argv[2], argv[1]); SCWrite(pCon,buffer,eError); return 0; } +/*====================== SubSample =========================================*/ +int HdbSubSample(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]){ + pHistMem pHM = NULL; + pHdb node = NULL; + int bank = 0, length = -1, status; + HistInt *data = NULL; + char *pPtr = NULL; + hdbValue v; + + if(argc < 4){ + SCWrite(pCon,"ERROR: insufficient number of arguments to HdbSubSample", + eError); + return 0; + } + + pPtr = strchr(argv[1],':'); + if(pPtr != NULL){ + *pPtr = '\0'; + pPtr++; + sscanf(pPtr,"%d",&bank); + } + pHM = (pHistMem)FindCommandData(pSics,argv[1],"HistMem"); + node = FindHdbNode(NULL,argv[2], pCon); + if(pHM == NULL || node == NULL){ + SCWrite(pCon,"ERROR: either histogram memory or node not found!", + eError); + return 0; + } + + if(pHM->pDriv->SubSample == NULL){ + SCWrite(pCon,"ERROR: hm does not support subsampling", eError); + return 0; + } + data = pHM->pDriv->SubSample(pHM->pDriv, pCon, bank, argv[3]); + if(data == NULL){ + SCWrite(pCon,"ERROR: sub sampling failed", eError); + return 0; + } + + v.dataType = HIPINTVARAR; + v.arrayLength = data[0]; + v.v.intArray = data+1; + + UpdateHipadabaPar(node,v,pCon); + free(data); + SCSendOK(pCon); + return 1; +} diff --git a/sicshdbadapter.h b/sicshdbadapter.h index 9b8e54d2..563b95f9 100644 --- a/sicshdbadapter.h +++ b/sicshdbadapter.h @@ -19,5 +19,7 @@ int SICSHdbAdapter(SConnection *pCon, SicsInterp *pSics, void *pData, int argc, char *argv[]); +int HdbSubSample(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]); #endif /*SICSHDBADAPTER_H_*/ diff --git a/sicshdbfactory.c b/sicshdbfactory.c new file mode 100644 index 00000000..aca0ed08 --- /dev/null +++ b/sicshdbfactory.c @@ -0,0 +1,348 @@ +/** + * This implements the hfactory command which is used to create + * hipadaba nodes. + * + * copyright: see file COPYRIGHT + * + * Mark Koennecke, March 2008, + * reusing code from former separate node creation functions. + */ +#include +#include "statusfile.h" + +#define MAX_HDB_PATH 1024 +/*-------------------------------------------------------------------------*/ +static int MakePlainNode(pHdb parent, char *name, SConnection *pCon, + int argc, char *argv[]){ + pHdb child = NULL; + int type = 0, length = 0, priv = -1; + hdbValue val; + + if(argc < 5){ + SCWrite(pCon,"ERROR: not enough arguments to create plain node", + eError); + return 0; + } + + /* + * convert privilege + */ + priv = decodeSICSPriv(argv[3]); + if(priv < 0){ + SCPrintf(pCon,eError,"ERROR: %s is no valid privilege code", argv[3]); + return 0; + } + /* + * convert datatype + */ + strtolower(argv[4]); + type = convertHdbType(argv[4]); + if(type > HIPFLOATVARAR){ + SCWrite(pCon, + "ERROR: invalid type requested: none, int, float, text, intar, floatar, intvarar, floatvarar supported", + eError); + return 0; + } + if(type >= HIPINTAR){ + if( argc < 6){ + SCWrite(pCon,"ERROR: array length missing for array data type", + eError); + return 0; + } else { + length = atoi(argv[5]); + } + } + + if(type != HIPNONE){ + val = makeHdbValue(type,length); + child = MakeSICSHdbPar(name, priv, val); + ReleaseHdbValue(&val); + } else { + child = MakeHipadabaNode(name,type,length); + } + if(child == NULL){ + SCWrite(pCon,"ERROR: out of memory creating node",eError); + return 0; + } + + AddHipadabaChild(parent,child,pCon); + SCSendOK(pCon); + return 1; +} +/*--------------------------------------------------------------------------*/ +static int MakeScriptNode(pHdb parent, char *name, SConnection *pCon, + int argc, char *argv[]){ + int type, length; + pHdb child = NULL; + hdbValue v; + + if(argc < 5){ + SCWrite(pCon, + "ERROR: not enough arguments to create script parameter node", + eError); + return 0; + } + + /* + * convert datatype + */ + strtolower(argv[5]); + type = convertHdbType(argv[5]); + if(type >= 7){ + SCWrite(pCon, + "ERROR: invalid type requested: none, int, float, text, intar, floatar, intvarar, floatvarar supported", + eError); + return 0; + } + if(type > 2){ + if( argc < 7){ + SCWrite(pCon,"ERROR: array length missing for array data type", + eError); + return 0; + } else { + length = atoi(argv[6]); + } + } + + v = makeHdbValue(type,length); + child = MakeSICSScriptPar(name, argv[4], argv[3], v); + ReleaseHdbValue(&v); + if(child == NULL){ + SCWrite(pCon,"ERROR: out of memory creating node",eError); + return 0; + } + + AddHipadabaChild(parent,child,pCon); + SCSendOK(pCon); + return 1; +} +/*-------------------------------------------------------------------------*/ +static int MakeLinkNode(pHdb parent, char *name, SConnection *pCon, + int argc, char *argv[]){ + pHdb node = NULL; + pObjectDescriptor pDes = NULL; + char buffer[256]; + + if(argc < 4){ + SCWrite(pCon,"ERROR: not enough arguments to create script node", + eError); + return 0; + } + pDes = FindCommandDescriptor(pServ->pSics,argv[3]); + if(pDes == NULL){ + snprintf(buffer,255,"ERROR: failed to find object %s", argv[3]); + SCWrite(pCon,buffer,eError); + return 0; + } + if(pDes->parNode == NULL){ + snprintf(buffer,255, + "ERROR: Object %s does not use Hipadaba natively and thus cannot be linked", + argv[3]); + SCWrite(pCon,buffer,eError); + return 0; + } + + if(pDes->parNode->mama != NULL){ + snprintf(buffer,255, + "ERROR: Object %s is already linked somewhere else", + argv[3]); + SCWrite(pCon,buffer,eError); + return 0; + } + + AddHipadabaChild(parent,pDes->parNode,pCon); + if(pDes->parNode->name != NULL){ + free(pDes->parNode->name); + } + pDes->parNode->name = strdup(name); + SCSendOK(pCon); + return 1; +} +/* -------------------------------------------------------------------------- + * This is actually SCInvoke but without advancing the context. I think this + * is only of local use. It makes sure that commands executed as Hipadaba + * commands get logged properly. + ---------------------------------------------------------------------------*/ + static int HDBInvoke(SConnection *self, SicsInterp *pInter, char *pCommand) + { + int iRet; + long lLen; + const char *pResult = NULL; + char *pBuffer = NULL, *pFile = NULL; + char pBueffel[80]; + int i, iSpace; + + assert(pInter); + + /* print command to log files */ + for( i = 0; i < self->iFiles; i++) + { + if(self->pFiles[i]) + { + fprintf(self->pFiles[i],"SICS>> %s\n",pCommand); + } + } + + /* print to command log if user or manager */ + if(SCGetRights(self) <= usUser) + { + if(self->pSock != NULL) + { + sprintf(pBueffel,"sock %d>>",self->pSock->sockid); + } + } + + /* invoke */ + self->inUse++; + self->eInterrupt = eContinue; + /* + get first word of command + */ + iRet = InterpExecute(pInter,self,pCommand); + + StatusFileTask(NULL); /* save changed parameters */ + + self->inUse--; + return iRet; + } +/*---------------------------------------------------------------------------*/ +static hdbCallbackReturn CommandSetCallback(pHdb node, void *userData, + pHdbMessage message){ + SConnection *pCon = NULL; + pDynString cmd = NULL, par = NULL; + pHdb current = NULL; + int status; + pHdbDataMessage mm = NULL; + hdbValue v; + + if((mm = GetHdbSetMessage(message)) == NULL){ + return hdbContinue; + } + pCon = (SConnection *)pCon; + v = *(mm->v); + + if(pCon == NULL){ + printf("Cannot invoke command without connection\n"); + return hdbAbort; + } + + if(v.dataType == HIPTEXT){ + if(strstr(v.v.text,"start") != NULL) { + cmd = CreateDynString(64,64); + if(cmd == 0){ + SCWrite(pCon,"ERROR: out of memory in CommandSetCallback",eError); + return 0; + } + DynStringCopy(cmd, node->value.v.text); + DynStringConcat(cmd," "); + current = node->child; + while(current != NULL){ + par = formatValue(current->value, current); + if(par != NULL){ + DynStringConcat(cmd, GetCharArray(par)); + DynStringConcat(cmd," "); + DeleteDynString(par); + } + current = current->next; + } + status = HDBInvoke(pCon,pServ->pSics, GetCharArray(cmd)); + DeleteDynString(cmd); + if(status == 1){ + return hdbContinue; + } else { + return hdbAbort; + } + } else { + SCWrite(pCon,"ERROR: this node only understands start as value",eError); + return hdbAbort; + } + } + return hdbContinue; +} +/*---------------------------------------------------------------------------*/ +static hdbCallbackReturn CommandGetCallback(pHdb node, void *userData, + pHdbMessage message){ + pHdbDataMessage mm = NULL; + + if((mm = GetHdbGetMessage(message)) == NULL){ + return hdbContinue; + } + + hdbValue v2 = MakeHdbText(strdup("Nothing to get")); + copyHdbValue(&v2, mm->v); + return hdbContinue; +} +/*--------------------------------------------------------------------------*/ +static int MakeCommandNode(pHdb parent, char *name, SConnection *pCon, + int argc, char *argv[]){ + pHdb node = NULL; + pHdbCallback kalle = NULL; + + if(argc < 4){ + SCWrite(pCon,"ERROR: not enough arguments to create command node", + eError); + return 0; + } + node = MakeHipadabaNode(name, HIPTEXT, 1); + if(node == NULL){ + SCWrite(pCon,"ERROR: out of memory in hcommand",eError); + return 0; + } + node->value.v.text = strdup(argv[3]); + node->value.arrayLength = strlen(argv[3]); + SetHdbProperty(node,"sicscommand", argv[3]); + + kalle = MakeHipadabaCallback(CommandSetCallback,NULL, NULL); + if(kalle == NULL){ + SCWrite(pCon,"ERROR: out of memory in hcommand",eError); + return 0; + } + AppendHipadabaCallback(node,kalle); + + kalle = MakeHipadabaCallback(CommandGetCallback,NULL, NULL); + if(kalle == NULL){ + SCWrite(pCon,"ERROR: out of memory in hcommand",eError); + return 0; + } + AppendHipadabaCallback(node,kalle); + + AddHipadabaChild(parent,node,pCon); + + SCSendOK(pCon); + return 1; +} +/*--------------------------------------------------------------------------*/ +int HdbNodeFactory(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]){ + char *name = NULL; + pHdb parent = NULL; + + if(!SCMatchRights(pCon,usMugger)){ + return 0; + } + + if(argc < 3) { + SCWrite(pCon,"ERROR: not enough arguments to hfactory",eError); + return 0; + } + + parent = FindHdbParent(NULL, argv[1], &name, pCon); + if (parent == NULL) { + return 0; /* error messages written inside FindHdbParent */ + } + + strtolower(argv[2]); + if(strcmp(argv[2],"plain") == 0){ + return MakePlainNode(parent,name,pCon,argc,argv); + } else if(strcmp(argv[2],"script") == 0){ + return MakeScriptNode(parent,name,pCon,argc,argv); + } else if(strcmp(argv[2],"link") == 0){ + return MakeLinkNode(parent,name,pCon,argc,argv); + } else if(strcmp(argv[2],"command") == 0){ + return MakeCommandNode(parent,name,pCon,argc,argv); + } else { + SCWrite(pCon,"ERROR: node type not recognised", eError); + return 0; + } + return 0; +} diff --git a/sicshipadaba.c b/sicshipadaba.c index 2fcba9d8..075d0237 100644 --- a/sicshipadaba.c +++ b/sicshipadaba.c @@ -11,8 +11,12 @@ * * Added property functions, Mark Koennecke, January 2007 * + * Added hmatchprop function. Mark Koennecke, February 2008 + * * TODO: separate this into two modules: sicshipadaba proper and sicshipadabaint for the * interpreter interface. + * + * Refactored to new callback system, Markus Zolliker, Mark Koennecke, March 2008 */ #include #include @@ -24,9 +28,14 @@ #include #include #include "protocol.h" +#include "statusfile.h" #include +#include "sicsobj.h" +#include -/*== there can be only hipadaba in SICS, some globals to care for that == */ +#define MAX_HDB_PATH 1024 + +/*== there can be only one hipadaba in SICS, some globals to care for that == */ static pHdb root = NULL; static pSicsPoll poller = NULL; typedef enum { @@ -40,15 +49,47 @@ typedef enum { } RecSep; char *trim(char *str); +/*====================== Messages ==================================================*/ +static char killID[] = {"killID"}; +static char killInternalID[] = {"killInternalID"}; +static char killPtr[] = {"killPtr"}; +/*----------------------------------------------------------------------------------*/ +pHdbIDMessage GetKillIDMessage(pHdbMessage message){ + if(message->type == killID){ + return (pHdbIDMessage)message; + } + return NULL; +} +/*-----------------------------------------------------------------------------------*/ +pHdbIDMessage GetKillInternalIDMessage(pHdbMessage message){ + if(message->type == killInternalID){ + return (pHdbIDMessage)message; + } + return NULL; +} +/*-----------------------------------------------------------------------------------*/ +pHdbPtrMessage GetKillPtrMessage(pHdbMessage message){ + if(message->type == killPtr){ + return (pHdbPtrMessage)message; + } + return NULL; +} + /*=============== common callback functions used for SICS ===========================*/ -static int SICSCheckPermissionCallback(void *userData, void *callData, pHdb node, - hdbValue v){ +static hdbCallbackReturn SICSCheckPermissionCallback(pHdb node, void *userData, + pHdbMessage message){ int *testPriv = NULL; SConnection *pCon = NULL; + pHdbDataMessage mm = NULL; - pCon = (SConnection *)callData; testPriv = (int *)userData; + mm = GetHdbSetMessage(message); + if(mm == NULL){ + return hdbContinue; + } + pCon = (SConnection *)mm->callData; + /* * If pCon is NULL, then this is an internal call from some driver * code where no permission check is necessary. However, when called @@ -56,15 +97,15 @@ static int SICSCheckPermissionCallback(void *userData, void *callData, pHdb node * check will be honoured. */ if(pCon == NULL){ - return 1; + return hdbContinue; } assert(testPriv != NULL); if(SCMatchRights(pCon,*testPriv) == 1){ - return 1; + return hdbContinue; } else { - return SICSCBPERM; + return hdbAbort; } } /*--------------------------------------------------------------------------------------*/ @@ -76,60 +117,120 @@ pHdbCallback MakeCheckPermissionCallback(int priv){ return NULL; } *testPriv = priv; - return MakeHipadabaCallback(SICSCheckPermissionCallback, testPriv,free,-1,-1); + return MakeHipadabaCallback(SICSCheckPermissionCallback, testPriv,free); } /*-------------------------------------------------------------------------------------*/ -static int SICSSetUpdateCallback(void *userData, void *callData, pHdb node, - hdbValue v){ - return UpdateHipadabaPar(node,v,callData); +static char *removeSetUpdateID = "removeSetUpdate"; + +void RemoveSetUpdateCallback(pHdb node) { + hdbPtrMessage m; + + m.type = killPtr; + m.pPtr = removeSetUpdateID; + InvokeCallbackChain(node, (pHdbMessage)&m); +} +/*-------------------------------------------------------------------------------------*/ +static hdbCallbackReturn SICSSetUpdateCallback(pHdb node, void *userData, + pHdbMessage message){ + pHdbDataMessage mm = NULL; + pHdbPtrMessage pm = NULL; + int status; + + pm = GetKillPtrMessage(message); + if (pm != NULL) { + if (pm->pPtr == removeSetUpdateID) { + return hdbKill; + } + return hdbContinue; + } + mm = GetHdbSetMessage(message); + if(mm == NULL){ + return hdbContinue; + } + status = UpdateHipadabaPar(node,*(mm->v),mm->callData); + if (status) { + SCSendOK(mm->callData); + } + return hdbContinue; } /*-------------------------------------------------------------------------------------*/ pHdbCallback MakeSetUpdateCallback(){ - return MakeHipadabaCallback(SICSSetUpdateCallback, NULL,NULL,-1,-1); + return MakeHipadabaCallback(SICSSetUpdateCallback, NULL,NULL); } /*---------------------------------------------------------------------------------------*/ -static int SICSReadOnlyCallback(void *userData, void *callData, pHdb node, - hdbValue v){ +static hdbCallbackReturn SICSReadOnlyCallback(pHdb node, void *userData, pHdbMessage message){ SConnection *pCon = NULL; + pHdbDataMessage mm = NULL; - pCon = (SConnection *)callData; + mm = GetHdbSetMessage(message); + if(mm == NULL){ + return hdbContinue; + } + pCon = (SConnection *)mm->callData; if(pCon != NULL){ SCWrite(pCon,"ERROR: parameter is READ-ONLY", eError); } - return SICSCBRO; + return hdbAbort; } /*-------------------------------------------------------------------------------------*/ pHdbCallback MakeReadOnlyCallback(){ - return MakeHipadabaCallback(SICSReadOnlyCallback, NULL,NULL,-1,-1); + return MakeHipadabaCallback(SICSReadOnlyCallback, NULL,NULL); } /*-------------------------------------------------------------------------------------*/ -static int SICSDriveCallback(void *userData, void *callData, pHdb node, - hdbValue v){ +static hdbCallbackReturn SICSDriveCallback(pHdb node, void *userData, + pHdbMessage message){ SConnection *pCon = NULL; pDummy dum = NULL; + char pSicsdev[80]; + int status; + pHdbDataMessage mm = NULL; + hdbValue v; + + mm = GetHdbSetMessage(message); + if(mm == NULL){ + return hdbContinue; + } + + pCon = (SConnection *)mm->callData; + v = *(mm->v); - pCon = (SConnection *)callData; dum = (pDummy)userData; assert(pCon != NULL && dum != NULL); GetHipadabaPath(node); - return StartDevice(pServ->pExecutor,node->path,dum->pDescriptor, + if(GetHdbProperty(node,"sicsdev",pSicsdev,79)){ + status = StartDevice(pServ->pExecutor,node->path,dum->pDescriptor, userData, pCon, (float)v.v.doubleValue); + } else { + status = StartDevice(pServ->pExecutor,node->path,dum->pDescriptor, + userData, pCon, (float)v.v.doubleValue); + } + if(status == 1){ + return hdbContinue; + } else { + return hdbAbort; + } } /*---------------------------------------------------------------------------------------*/ pHdbCallback MakeSICSDriveCallback(void *sicsObject){ - return MakeHipadabaCallback(SICSDriveCallback, sicsObject,NULL,-1,-1); + return MakeHipadabaCallback(SICSDriveCallback, sicsObject,NULL); } /*---------------------------------------------------------------------------------------*/ -static int SICSReadDriveCallback(void *userData, void *callData, pHdb node, - hdbValue v){ +static hdbCallbackReturn SICSReadDriveCallback(pHdb node, void *userData, + pHdbMessage message){ static SConnection *defCon = NULL; SConnection *pCon = NULL; pDummy dum = NULL; pIDrivable pDriv = NULL; float value; + pHdbDataMessage mm = NULL; - pCon = (SConnection *)callData; + mm = GetHdbGetMessage(message); + if(mm == NULL){ + return hdbContinue; + } + + pCon = (SConnection *)mm->callData; dum = (pDummy)userData; assert(dum != NULL); @@ -142,24 +243,70 @@ static int SICSReadDriveCallback(void *userData, void *callData, pHdb node, if(pCon != NULL){ value = pDriv->GetValue(dum,pCon); node->value.v.doubleValue = (double)value; - v.v.doubleValue = (double)value; + mm->v->v.doubleValue = (double)value; } else { if(defCon != NULL){ value = pDriv->GetValue(dum,defCon); node->value.v.doubleValue = (double)value; - v.v.doubleValue = (double)value; + mm->v->v.doubleValue = (double)value; } } - return 1; + return hdbContinue; +} +/*--------------------------------------------------------------------------*/ +static hdbCallbackReturn SICSFuncCallback(pHdb node, void *userData, + pHdbMessage message){ + pHdb par[64], current = NULL; + int nPar = 0; + SICSOBJFunc func = NULL; + pHdbDataMessage mm = NULL; + int status; + + mm = GetHdbSetMessage(message); + if(mm == NULL){ + return hdbContinue; + } + + assert(node->value.dataType == HIPFUNC); + if(userData == NULL || mm->callData == NULL){ + printf("Great Badness in calling SICSFuncCallback\n"); + return hdbAbort; + } + + current = node->child; + while(current != NULL){ + par[nPar] = current; + nPar++; + current = current->next; + } + func = (SICSOBJFunc)node->value.v.func; + if(func != NULL){ + status = func((pSICSOBJ)userData,(SConnection *)mm->callData, + node, par,nPar); + } else { + printf("Great Badness in calling SICSFuncCallback\n"); + return hdbAbort; + } + if(status == 1){ + return hdbContinue; + } else { + return hdbAbort; + } +} +/*---------------------------------------------------------------------------*/ +pHdbCallback MakeSICSFuncCallback(void *obj){ + return MakeHipadabaCallback(SICSFuncCallback, obj,NULL); } /*--------------------------------------------------------------------------------------*/ pHdbCallback MakeSICSReadDriveCallback(void *sicsObject){ - return MakeHipadabaCallback(SICSReadDriveCallback, sicsObject,NULL,-1,-1); + return MakeHipadabaCallback(SICSReadDriveCallback, sicsObject,NULL); } /*---------------------------------------------------------------------------------------*/ typedef struct { SConnection *pCon; commandContext context; + int ID; + int internalID; }HdbCBInfo; static Protocol isJSON(SConnection *pCon) { @@ -227,18 +374,112 @@ int formatNameValue(Protocol protocol, char *name, char *value, pDynString resul } return protocol; } - +/*----------------------------------------------------------------------------*/ +static int sendZippedNodeData(pHdb node, SConnection *pCon){ + hdbValue newValue; + int i, *iData = NULL; + char *path = NULL; + + newValue = node->value; + path = GetHipadabaPath(node); + switch(newValue.dataType){ + case HIPINTAR: + case HIPINTVARAR: + if(newValue.v.intArray == NULL){ + free(path); + return 0; + } + iData = (int *)malloc(newValue.arrayLength*sizeof(int)); + if(iData == NULL){ + SCWrite(pCon,"ERROR: out of memory in sendZippedData",eError); + free(path); + return 0; + } + memset(iData,0,newValue.arrayLength*sizeof(int)); + for(i = 0; i < newValue.arrayLength; i++){ + iData[i] = htonl(newValue.v.intArray[i]); + } + SCWriteZipped(pCon,path, iData, + newValue.arrayLength*sizeof(int)); + free(iData); + break; + case HIPFLOATAR: + case HIPFLOATVARAR: + if(newValue.v.floatArray == NULL){ + free(path); + return 0; + } + iData = (int *)malloc(newValue.arrayLength*sizeof(int)); + if(iData == NULL){ + SCWrite(pCon,"ERROR: out of memory in sendZippedData",eError); + free(path); + return 0; + } + memset(iData,0,newValue.arrayLength*sizeof(int)); + for(i = 0; i < newValue.arrayLength; i++){ + iData[i] = htonl((int)(newValue.v.floatArray[i]*65536.)); + } + SCWriteZipped(pCon,path, iData, + newValue.arrayLength*sizeof(int)); + free(iData); + break; + default: + SCWrite(pCon,"ERROR: zipped writing not supported for this datatype", + eError); + free(path); + return 0; + } + free(path); + return 1; +} /*----------------------------------------------------------------------------------------*/ -static int SICSNotifyCallback(void *userData, void *callData, pHdb node, - hdbValue v){ +static hdbCallbackReturn SICSNotifyCallback(pHdb node, void *userData, + pHdbMessage message ){ HdbCBInfo *cbInfo = NULL; pDynString printedData = NULL; pDynString result = NULL; char *pPath = NULL; Protocol protocol = normal_protocol; - int outCode; - + int outCode, macro, status; + char value[80]; + pHdbIDMessage idm = NULL; + pHdbPtrMessage cmm = NULL; + pHdbDataMessage mm = NULL; + cbInfo = (HdbCBInfo *)userData; + + /* + * handle kills first + */ + if((idm = GetKillIDMessage(message)) != NULL){ + if(idm->ID == cbInfo->ID){ + return hdbKill; + } else { + return hdbContinue; + } + } + if((idm = GetKillInternalIDMessage(message)) != NULL){ + if(idm->ID == cbInfo->internalID){ + return hdbKill; + } else { + return hdbContinue; + } + } + if((cmm = GetKillPtrMessage(message)) != NULL){ + if(cmm->pPtr == cbInfo->pCon){ + return hdbKill; + } else { + return hdbContinue; + } + } + + /* + * react only on update messages + */ + if((mm = GetHdbUpdateMessage(message)) == NULL){ + return hdbContinue; + } + pPath = GetHipadabaPath(node); result = CreateDynString(128,128); if ((protocol = isJSON(cbInfo->pCon)) == 1) @@ -246,18 +487,40 @@ static int SICSNotifyCallback(void *userData, void *callData, pHdb node, else outCode = eEvent; - if(v.arrayLength < 100){ - printedData = formatValue(v); + + /* + * we want our notifications to come even when called from a macro + */ + macro = SCinMacro(cbInfo->pCon); + SCsetMacro(cbInfo->pCon,0); + /** + * if transfer = zip always transfer data in zipped form + */ + if(GetHdbProperty(node,"transfer",value,80) == 1){ + if(strstr(value,"zip") != NULL){ + SCPushContext2(cbInfo->pCon,cbInfo->context); + status = sendZippedNodeData(node, cbInfo->pCon); + SCPopContext(cbInfo->pCon); + SCsetMacro(cbInfo->pCon,macro); + free(pPath); + DeleteDynString(result); + return hdbContinue; + } + } + if(mm->v->arrayLength < 100){ + printedData = formatValue(*(mm->v), node); if(pPath == NULL || printedData == NULL || result == NULL){ SCWriteInContext(cbInfo->pCon,"ERROR: out of memory formatting data" , eEvent,cbInfo->context); + SCsetMacro(cbInfo->pCon,macro); /* * no need to interrupt something because writing data to a client does * not work */ - return 1; + return hdbContinue; } - formatNameValue(protocol, pPath, GetCharArray(printedData), result, v.dataType); + formatNameValue(protocol, pPath, GetCharArray(printedData), result, + mm->v->dataType); SCWriteInContext(cbInfo->pCon,GetCharArray(result), outCode,cbInfo->context); DeleteDynString(printedData); @@ -266,10 +529,11 @@ static int SICSNotifyCallback(void *userData, void *callData, pHdb node, SCWriteInContext(cbInfo->pCon,GetCharArray(result), outCode,cbInfo->context); } + SCsetMacro(cbInfo->pCon,macro); free(pPath); DeleteDynString(result); - return 1; + return hdbContinue; } /*-----------------------------------------------------------------------------------------*/ pHdbCallback MakeNotifyCallback(SConnection *pCon, int id){ @@ -281,32 +545,70 @@ pHdbCallback MakeNotifyCallback(SConnection *pCon, int id){ } cbInfo->pCon = pCon; cbInfo->context = SCGetContext(pCon); - return MakeHipadabaCallback(SICSNotifyCallback, cbInfo,free,id,pCon->ident); + cbInfo->ID = id; + cbInfo->internalID = -1; + return MakeHipadabaCallback(SICSNotifyCallback, cbInfo,free); } /*-------------------------------------------------------------------------*/ -static int TreeChangeCallback(void *userData, void *callData, pHdb node, - hdbValue v){ +static hdbCallbackReturn TreeChangeCallback(pHdb node, void *userData, + pHdbMessage message){ char *path = NULL; char buffer[1024]; pDynString result = NULL; Protocol protocol = normal_protocol; int outCode; - - result = CreateDynString(128,128); + pHdbIDMessage idm = NULL; + pHdbPtrMessage cmm = NULL; + pHdbTreeChangeMessage tm = NULL; + HdbCBInfo *cbInfo = (HdbCBInfo *)userData; + /* + * handle kills first + */ + if((idm = GetKillIDMessage(message)) != NULL){ + if(idm->ID == cbInfo->ID){ + return hdbKill; + } else { + return hdbContinue; + } + } + if((idm = GetKillInternalIDMessage(message)) != NULL){ + if(idm->ID == cbInfo->internalID){ + return hdbKill; + } else { + return hdbContinue; + } + } + if((cmm = GetKillPtrMessage(message)) != NULL){ + if(cmm->pPtr == cbInfo->pCon){ + return hdbKill; + } else { + return hdbContinue; + } + } + + if((tm = GetHdbTreeChangeMessage(message)) == NULL){ + return hdbContinue; + } + if(cbInfo != NULL && cbInfo->pCon != NULL){ + result = CreateDynString(128,128); + if(result == NULL){ + SCWriteInContext(cbInfo->pCon,"ERROR: out of memory in TreeChangeCallback",outCode,cbInfo->context); + return hdbAbort; + } path = GetHipadabaPath(node); if ((protocol = isJSON(cbInfo->pCon)) == 1) outCode = eHdbEvent; else outCode = eEvent; - formatNameValue(protocol, "treechange", path, result, v.dataType); + formatNameValue(protocol, "treechange", path, result, node->value.dataType); SCWriteInContext(cbInfo->pCon,GetCharArray(result),outCode,cbInfo->context); DeleteDynString(result); free(path); } - return 1; + return hdbContinue; } /*-------------------------------------------------------------------------*/ pHdbCallback MakeTreeChangeCallback(SConnection *pCon, int id){ @@ -318,26 +620,32 @@ pHdbCallback MakeTreeChangeCallback(SConnection *pCon, int id){ } cbInfo->pCon = pCon; cbInfo->context = SCGetContext(pCon); - return MakeHipadabaCallback(TreeChangeCallback, cbInfo,free,id,pCon->ident); + cbInfo->ID = id; + return MakeHipadabaCallback(TreeChangeCallback, cbInfo,free); } /*----------------------------------------------------------------------------------------*/ -static int SICSScriptWriteCallback(void *userData, void *callData, pHdb node, - hdbValue v){ +static hdbCallbackReturn SICSScriptWriteCallback(pHdb node, void *userData, + pHdbMessage message){ char *command = NULL; SConnection *pCon = NULL; pDynString newVal = NULL; char error[1024]; int status; + pHdbDataMessage mm = NULL; + + if((mm = GetHdbSetMessage(message)) == NULL){ + return hdbContinue; + } command = (char *)userData; - pCon = (SConnection *)callData; + pCon = (SConnection *)mm->callData; assert(command != NULL && pCon != NULL); - newVal = formatValue(v); + newVal = formatValue(*(mm->v), node); if(newVal == NULL){ SCWrite(pCon,"ERROR: out of memory setting parameter",eError); - return 0; + return hdbAbort; } /** @@ -359,34 +667,51 @@ static int SICSScriptWriteCallback(void *userData, void *callData, pHdb node, status = 1; } DeleteDynString(newVal); - return status; + if(status == 1){ + return hdbContinue; + } else{ + return hdbAbort; + } } /*---------------------------------------------------------------------------------------*/ static pHdbCallback MakeSICSWriteScriptCallback(char *script){ - return MakeHipadabaCallback(SICSScriptWriteCallback, strdup(script),free,-1,-1); + return MakeHipadabaCallback(SICSScriptWriteCallback, strdup(script),free); } /*----------------------------------------------------------------------------------------*/ -static int SICSScriptReadCallback(void *userData, void *callData, pHdb node, - hdbValue v){ +static hdbCallbackReturn SICSScriptReadCallback(pHdb node, void *userData, + pHdbMessage message){ char *command = NULL, *data = NULL, *equal = NULL; SConnection *pCon = NULL; pDynString newVal = NULL; char error[1024]; int status; + pHdbDataMessage mm = NULL; + + if((mm = GetHdbGetMessage(message)) == NULL){ + return hdbContinue; + } command = (char *)userData; - pCon = (SConnection *)callData; + pCon = (SConnection *)mm->callData; - assert(command != NULL && pCon != NULL); + assert(command != NULL); /* * evaluate */ + if(pCon != NULL){ + MacroPush(pCon); + } status = Tcl_Eval(InterpGetTcl(pServ->pSics),command); - if(status != TCL_OK){ + if(pCon != NULL){ + MacroPop(); + } + if(status != TCL_OK){ snprintf(error,1023,"ERROR: Tcl returned error: %s", Tcl_GetStringResult(InterpGetTcl(pServ->pSics))); - SCWrite(pCon,error,eError); + if(pCon != NULL){ + SCWrite(pCon,error,eError); + } status = 0; } else { status = 1; @@ -399,9 +724,22 @@ static int SICSScriptReadCallback(void *userData, void *callData, pHdb node, */ data = (char *)Tcl_GetStringResult(InterpGetTcl(pServ->pSics)); if(data == NULL){ - SCWrite(pCon,"ERROR: no result returned from script",eError); - return 0; + if(pCon != NULL){ + SCWrite(pCon,"ERROR: no result returned from script",eError); + } + return hdbAbort; } + + /* + * do we need to copy? + */ + if(strstr(data,"@@NOCOPY@@") != NULL){ + return hdbContinue; + } + + /* + * we need to copy: do it + */ equal = strchr(data,'='); if(equal != NULL){ data = equal + 1; @@ -409,15 +747,21 @@ static int SICSScriptReadCallback(void *userData, void *callData, pHdb node, strcpy(error,"ERROR: "); status = readHdbValue(&node->value,data, error+7, 1024-7); if(status != 1){ - SCWrite(pCon,error,eError); - return 0; + if(pCon != NULL){ + SCWrite(pCon,error,eError); + } + return hdbAbort; } - return status; -} + if(status == 1){ + return hdbContinue; + } else { + return hdbAbort; + } +} /*----------------------------------------------------------------------------*/ static pHdbCallback MakeSICSReadScriptCallback(char *script){ return MakeHipadabaCallback(SICSScriptReadCallback, strdup(script), - free,-1,-1); + free); } /*---------------------------------------------------------------------------*/ typedef struct { @@ -425,27 +769,33 @@ typedef struct { int max; }hdbIntRange, *pHdbIntRange; /*---------------------------------------------------------------------------*/ -static int SICSIntRangeCallback(void *userData, void *callData, pHdb node, - hdbValue v){ +static hdbCallbackReturn SICSIntRangeCallback(pHdb node, void *userData, + pHdbMessage message){ char buffer[256]; pHdbIntRange range = NULL; SConnection *pCon = NULL; int status = 1; + pHdbDataMessage mm = NULL; + + if((mm = GetHdbSetMessage(message)) == NULL){ + return hdbContinue; + } range = (pHdbIntRange)userData; - pCon = (SConnection *)callData; + pCon = (SConnection *)mm->callData; assert(range != NULL); - if(v.v.intValue > range->max || v.v.intValue < range->min) { + if(mm->v->v.intValue > range->max || mm->v->v.intValue < range->min) { status = SICSCBRANGE; if(pCon != NULL){ snprintf(buffer,255,"ERROR: %d is not within permitted range: %d to %d", - (int)v.v.intValue, range->min, range->max); + (int)mm->v->v.intValue, range->min, range->max); SCWrite(pCon,buffer,eError); } + return hdbAbort; } - return status; + return hdbContinue; } /*---------------------------------------------------------------------------*/ pHdbCallback MakeIntRangeCallback(int min, int max){ @@ -458,7 +808,7 @@ pHdbCallback MakeIntRangeCallback(int min, int max){ range->min = min; range->max = max; return MakeHipadabaCallback(SICSIntRangeCallback, range, - free,-1,-1); + free); } /*---------------------------------------------------------------------------*/ typedef struct { @@ -466,27 +816,33 @@ typedef struct { double max; }hdbFloatRange, *pHdbFloatRange; /*---------------------------------------------------------------------------*/ -static int SICSFloatRangeCallback(void *userData, void *callData, pHdb node, - hdbValue v){ +static hdbCallbackReturn SICSFloatRangeCallback(pHdb node, void *userData, + pHdbMessage message){ char buffer[256]; pHdbFloatRange range = NULL; SConnection *pCon = NULL; int status = 1; + pHdbDataMessage mm = NULL; + + if((mm = GetHdbSetMessage(message)) == NULL){ + return hdbContinue; + } range = (pHdbFloatRange)userData; - pCon = (SConnection *)callData; + pCon = (SConnection *)mm->callData; assert(range != NULL); - if(v.v.doubleValue > range->max || v.v.doubleValue < range->min) { + if(mm->v->v.doubleValue > range->max || mm->v->v.doubleValue < range->min) { status = SICSCBRANGE; if(pCon != NULL){ snprintf(buffer,255,"ERROR: %lf is not within permitted range: %lf to %lf", - v.v.doubleValue, range->min, range->max); + mm->v->v.doubleValue, range->min, range->max); SCWrite(pCon,buffer,eError); } + return hdbAbort; } - return status; + return hdbContinue; } /*---------------------------------------------------------------------------*/ pHdbCallback MakeFloatRangeCallback(double min, double max){ @@ -499,24 +855,17 @@ pHdbCallback MakeFloatRangeCallback(double min, double max){ range->min = min; range->max = max; return MakeHipadabaCallback(SICSFloatRangeCallback, range, - free,-1,-1); -} -/*-------------------------------------------------------------------------*/ -static int MemReadCallback(void *userData, void *callData, pHdb node, - hdbValue v){ - float *value = NULL; - - value = (float *)userData; - if(value != NULL){ - v.dataType = HIPFLOAT; - v.v.doubleValue = (float) *value; - node->value.v.doubleValue = (double)*value; - } - return 1; + free); } /*------------------------------------------------------------------------*/ -static int MemGenReadCallback(void *userData, void *callData, pHdb node, - hdbValue v){ +static hdbCallbackReturn MemGenReadCallback(pHdb node, void *userData, + pHdbMessage message){ + pHdbDataMessage mm = NULL; + + if((mm = GetHdbGetMessage(message)) == NULL){ + return hdbContinue; + } + switch(node->value.dataType){ case HIPINT: node->value.v.intValue = *(int *)userData; @@ -542,56 +891,45 @@ static int MemGenReadCallback(void *userData, void *callData, pHdb node, assert(0); break; } - return 1; + return hdbContinue; } /*-------------------------------------------------------------------------*/ pHdbCallback MakeMemGenReadCallback(void *address){ - return MakeHipadabaCallback(MemReadCallback, address, - NULL,-1,-1); + return MakeHipadabaCallback(MemGenReadCallback, address, + NULL); } /*-------------------------------------------------------------------------*/ -pHdbCallback MakeMemReadCallback(float *address){ - return MakeHipadabaCallback(MemReadCallback, address, - NULL,-1,-1); -} -/*-------------------------------------------------------------------------*/ -static int MemSetCallback(void *userData, void *callData, pHdb node, - hdbValue v){ - float *value = NULL; - - value = (float *)userData; - if(value != NULL){ - *value = (float)v.v.doubleValue; - } - UpdateHipadabaPar(node,v,callData); - return 1; -} -/*-------------------------------------------------------------------------*/ -static int MemGenSetCallback(void *userData, void *callData, pHdb node, - hdbValue v){ +static hdbCallbackReturn MemGenSetCallback(pHdb node, void *userData, + pHdbMessage message){ const char *pPtr = NULL; - - if(v.dataType != node->value.dataType){ + pHdbDataMessage mm = NULL; + + if((mm = GetHdbSetMessage(message)) == NULL){ + return hdbContinue; + } + + + if(mm->v->dataType != node->value.dataType){ assert(0); return 0; } switch(node->value.dataType){ case HIPINT: - memcpy(userData,&v.v.intValue,sizeof(int)); + memcpy(userData,&mm->v->v.intValue,sizeof(int)); break; case HIPFLOAT: - memcpy(userData,&v.v.doubleValue,sizeof(double)); + memcpy(userData,&mm->v->v.doubleValue,sizeof(double)); break; case HIPTEXT: - strncpy((char *)userData,(const char *)v.v.text, + strncpy((char *)userData,(const char *)mm->v->v.text, node->value.arrayLength); break; case HIPINTAR: - memcpy(userData,&v.v.intArray,node->value.arrayLength*sizeof(int)); + memcpy(userData,&mm->v->v.intArray,node->value.arrayLength*sizeof(int)); break; case HIPFLOATAR: - memcpy(userData,&v.v.floatArray, + memcpy(userData,&mm->v->v.floatArray, node->value.arrayLength*sizeof(double)); break; default: @@ -599,18 +937,13 @@ static int MemGenSetCallback(void *userData, void *callData, pHdb node, return 0; break; } - UpdateHipadabaPar(node,v,callData); - return 1; -} -/*-------------------------------------------------------------------------*/ -pHdbCallback MakeMemSetCallback(float *address){ - return MakeHipadabaCallback(MemSetCallback, address, - NULL,-1,-1); + UpdateHipadabaPar(node,*(mm->v),mm->callData); + return hdbContinue; } /*-------------------------------------------------------------------------*/ pHdbCallback MakeMemGenSetCallback(void *address){ - return MakeHipadabaCallback(MemSetCallback, address, - NULL,-1,-1); + return MakeHipadabaCallback(MemGenSetCallback, address, + NULL); } /*--------------------------------------------------------------------------*/ static void killHdbValue(void *pData){ @@ -624,24 +957,29 @@ static void killHdbValue(void *pData){ free(v); } /*--------------------------------------------------------------------------*/ -static int SICSIntFixedCallback(void *userData, void *callData, pHdb node, - hdbValue v){ +static hdbCallbackReturn SICSIntFixedCallback(pHdb node, void *userData, + pHdbMessage message){ hdbValue *allowed = NULL; SConnection *pCon = NULL; int i; + pHdbDataMessage mm = NULL; + + if((mm = GetHdbSetMessage(message)) == NULL){ + return hdbContinue; + } allowed = (hdbValue *)userData; - pCon = (SConnection *)callData; + pCon = (SConnection *)mm->callData; assert(allowed != NULL && allowed->dataType == HIPINTAR); for(i = 0; i < allowed->arrayLength; i++){ - if(v.v.intValue == allowed->v.intArray[i]){ - return 1; + if(mm->v->v.intValue == allowed->v.intArray[i]){ + return hdbContinue; } } if(pCon != NULL){ SCWrite(pCon,"ERROR: value is not in the list of allowed values",eError); } - return SICSCBBADFIXED; + return hdbAbort; } /*---------------------------------------------------------------------------*/ pHdbCallback MakeIntFixedCallback(int *data, int length){ @@ -660,7 +998,7 @@ pHdbCallback MakeIntFixedCallback(int *data, int length){ } memcpy(v->v.intArray,data,length*sizeof(int)); return MakeHipadabaCallback(SICSIntFixedCallback, v, - killHdbValue,-1,-1); + killHdbValue); } /*============= Parameter Creation ===========================================*/ pHdb MakeSICSHdbPar(char *name, int priv, hdbValue v){ @@ -679,14 +1017,14 @@ pHdb MakeSICSHdbPar(char *name, int priv, hdbValue v){ DeleteHipadabaNode(result,NULL); return NULL; } - AppendHipadabaCallback(result,HCBSET,pHcb); + AppendHipadabaCallback(result,pHcb); pHcb = MakeSetUpdateCallback(); if(pHcb == NULL){ DeleteHipadabaNode(result,NULL); return NULL; } - AppendHipadabaCallback(result,HCBSET,pHcb); + AppendHipadabaCallback(result,pHcb); switch(priv){ case 0: strcpy(pPriv,"internal"); @@ -705,12 +1043,6 @@ pHdb MakeSICSHdbPar(char *name, int priv, hdbValue v){ return result; } -/*---------------------------------------------------------------------------*/ -pHdb CreateSICSHdbPar(char *name, int priv, int dataType, - int length, void *data){ - return MakeSICSHdbPar(name,priv,makeHdbData(dataType, - length,data)); -} /*----------------------------------------------------------------------------*/ pHdb MakeSICSHdbDriv(char *name, int priv, void *sicsObject, int dataType){ pHdb result = NULL; @@ -726,21 +1058,21 @@ pHdb MakeSICSHdbDriv(char *name, int priv, void *sicsObject, int dataType){ DeleteHipadabaNode(result,NULL); return NULL; } - AppendHipadabaCallback(result,HCBSET,pHcb); + AppendHipadabaCallback(result,pHcb); pHcb = MakeSICSDriveCallback(sicsObject); if(pHcb == NULL){ DeleteHipadabaNode(result,NULL); return NULL; } - AppendHipadabaCallback(result,HCBSET,pHcb); + AppendHipadabaCallback(result,pHcb); pHcb = MakeSICSReadDriveCallback(sicsObject); if(pHcb == NULL){ DeleteHipadabaNode(result,NULL); return NULL; } - AppendHipadabaCallback(result,HCBREAD,pHcb); + AppendHipadabaCallback(result,pHcb); return result; } @@ -759,21 +1091,21 @@ pHdb MakeSICSMemPar(char *name, int priv, float *address){ DeleteHipadabaNode(result,NULL); return NULL; } - AppendHipadabaCallback(result,HCBSET,pHcb); + AppendHipadabaCallback(result,pHcb); - pHcb = MakeMemSetCallback(address); + pHcb = MakeMemGenSetCallback(address); if(pHcb == NULL){ DeleteHipadabaNode(result,NULL); return NULL; } - AppendHipadabaCallback(result,HCBSET,pHcb); + AppendHipadabaCallback(result,pHcb); - pHcb = MakeMemReadCallback(address); + pHcb = MakeMemGenReadCallback(address); if(pHcb == NULL){ DeleteHipadabaNode(result,NULL); return NULL; } - AppendHipadabaCallback(result,HCBREAD,pHcb); + AppendHipadabaCallback(result,pHcb); return result; } @@ -793,7 +1125,7 @@ pHdb MakeSICSROPar(char *name, hdbValue v){ DeleteHipadabaNode(result,NULL); return NULL; } - AppendHipadabaCallback(result,HCBSET,pHcb); + AppendHipadabaCallback(result,pHcb); return result; } @@ -814,29 +1146,23 @@ pHdb MakeSICSScriptPar(char *name, char *setScript, char *readScript, DeleteHipadabaNode(result,NULL); return NULL; } - AppendHipadabaCallback(result,HCBSET,pHcb); + AppendHipadabaCallback(result,pHcb); pHcb = MakeSICSReadScriptCallback(readScript); if(pHcb == NULL){ DeleteHipadabaNode(result,NULL); return NULL; } - AppendHipadabaCallback(result,HCBREAD,pHcb); + AppendHipadabaCallback(result,pHcb); /** * put into the list of nodes to check with the update task */ /* LLDnodeAppend(scriptUpdate,&result); */ - + SetHdbProperty(result,"sicscommand",setScript); return result; } -/*-------------------------------------------------------------------------*/ -pHdb CreateSICSScriptPar(char *name, char *setScript, char *readScript, - int dataType, int length, void *data){ - return MakeSICSScriptPar(name,setScript,readScript, - makeHdbData(dataType, length,data)); -} /*--------------------------------------------------------------------------*/ -static void removeNodeFromUpdateList(pHdb node){ +static void removeNodeFromUpdateList(pHdb node){ pHdb current = NULL; int status; char *objName = NULL; @@ -864,9 +1190,7 @@ static void SICSDeleteNodeData(pHdb node){ if(node->properties != NULL){ DeleteStringDict(node->properties); } - DeleteCallbackChain(node->writeCallbacks); - DeleteCallbackChain(node->updateCallbacks); - DeleteCallbackChain(node->readCallbacks); + DeleteCallbackChain(node); if(node->name != NULL){ free(node->name); @@ -892,70 +1216,234 @@ void RemoveSICSPar(pHdb node, void *callData){ SICSDeleteNodeData(node); } /*===================== add functions =======================================*/ -int AddSICSHdbPar(pHdb node, char *name, int priv, hdbValue v){ +pHdb AddSICSHdbPar(pHdb parent, char *name, int priv, hdbValue v){ pHdb child = NULL; child = MakeSICSHdbPar(name,priv,v); - if(child == NULL){ - return 0; + if(child != NULL){ + AddHipadabaChild(parent,child,NULL); } - AddHipadabaChild(node,child,NULL); - return 1; + return child; } /*---------------------------------------------------------------------------*/ -int AddSICSHdbROPar(pHdb node, char *name, hdbValue v){ +pHdb AddSICSHdbROPar(pHdb parent, char *name, hdbValue v){ pHdb child = NULL; child = MakeSICSROPar(name,v); - if(child == NULL){ - return 0; + if(child != NULL){ + AddHipadabaChild(parent,child,NULL); } - AddHipadabaChild(node,child,NULL); - return 1; + return child; } /*--------------------------------------------------------------------------*/ -int AddSICSHdbMemPar(pHdb node, char *name, int priv, +pHdb AddSICSHdbMemPar(pHdb parent, char *name, int priv, void *data, int datalength, int type, int length){ pHdb child = NULL; pHdbCallback pHcb = NULL; if(type == HIPINTVARAR || type == HIPFLOATVARAR){ assert(0); - return 0; + return NULL; } child = MakeHipadabaNode(name,type,length); if(child == NULL){ - return 0; + return NULL; } pHcb = MakeCheckPermissionCallback(priv); if(pHcb == NULL){ DeleteHipadabaNode(child,NULL); - return 0; + return NULL; } - AppendHipadabaCallback(child,HCBSET,pHcb); + AppendHipadabaCallback(child,pHcb); pHcb = MakeMemGenSetCallback(data); if(pHcb == NULL){ DeleteHipadabaNode(child,NULL); - return 0; + return NULL; } - AppendHipadabaCallback(child,HCBSET,pHcb); + AppendHipadabaCallback(child,pHcb); pHcb = MakeMemGenReadCallback(data); if(pHcb == NULL){ DeleteHipadabaNode(child,NULL); - return 0; + return NULL; } - AppendHipadabaCallback(child,HCBREAD,pHcb); - AddHipadabaChild(node,child,NULL); + AppendHipadabaCallback(child,pHcb); + AddHipadabaChild(parent,child,NULL); - return 1; + return child; } -/*==================== access suport functions ==============================*/ -int SICSHdbGetPar(void *obj, SConnection *pCon, - char *path, int dataType, void *data, int length){ +/*==================== access support functions ==============================*/ +pHdb FindHdbParent(char *rootpath, char *relpath, char **namePtr, SConnection *pCon) { + /* for namePtr == NULL, implements also "find node" */ + char *element; + char buffer[MAX_HDB_PATH]; + pHdb node = NULL; + pHdb parent = NULL; + char *name; + char *slash; + pObjectDescriptor pDes; + int iret; + + if (relpath[0] == '/' || rootpath == NULL) { /* absolute path */ + iret = snprintf(buffer, sizeof buffer, "%s", relpath); + } else { + iret = snprintf(buffer, sizeof buffer, "%s/%s", rootpath, relpath); + } + if (iret < 0 || iret >= sizeof(buffer)) { + SCWrite(pCon,"ERROR: path too long",eError); + return NULL; + } + element = buffer; + if (strncmp(element, "/sics/", 6) == 0) { + /* sics object case */ + slash = strchr(element+6, '/'); + if (slash != NULL) *slash = '\0'; /* split off object name */ + + pDes = FindCommandDescriptor(pServ->pSics, element+6); + if (pDes == NULL) { + SCPrintf(pCon, eError, "ERROR: object %s not found", element); + return NULL; + } + node = pDes->parNode; + if (node == NULL) { + SCPrintf(pCon, eError, "ERROR: object %s does not use hipadaba", element); + return NULL; + } + if (slash == NULL) goto nodeFound; + *slash = '/'; + element = slash+1; + parent = node; + /* parent is sics object, path is relative to it */ + } else { + /* normal path */ + parent = GetHipadabaRoot(); + } + while (1) { + slash = strchr(element, '/'); + if (slash != NULL) *slash = '\0'; /* split off next path element */ + if (strcmp(element, "") == 0 || strcmp(element, ".") == 0) { + /* cases "//" and "/./" : do not move in tree */ + if (slash == NULL) { + node = parent; + goto nodeFound; + } + *slash = '/'; + element = slash + 1; + } else { + for (node = parent->child; node != NULL; node = node->next) { + if (strcasecmp(element, node->name) == 0) { + break; + } + } + if (node == NULL) { + if (namePtr) { /* "find parent" case */ + if (slash != NULL) { /* element is not the last in path */ + *slash = '/'; + SCPrintf(pCon, eError, "ERROR: parent of %s not found", buffer); + return NULL; + } + /* the name must be taken from the end of relpath, as element is no longer valid */ + *namePtr = relpath + (element - buffer); + return parent; /* parent found, and node does not yet exist */ + } + /* "find node" case */ + if (slash != NULL) *slash = '/'; + SCPrintf(pCon, eError, "ERROR: node %s not found", buffer); + return NULL; + } + /* node found */ + if (slash == NULL) goto nodeFound; + parent = node; + *slash = '/'; + element = slash + 1; + } + } +nodeFound: + if (namePtr) { /* "find parent" case */ + *namePtr = node->name; + SCPrintf(pCon, eError, "ERROR: node %s exists already", buffer); + return NULL; + } + return node; /* node found */ +} +/*--------------------------------------------------------------------------*/ +pHdb FindHdbNode(char *rootpath, char *relpath, SConnection *pCon) { + return FindHdbParent(rootpath, relpath, NULL, pCon); +} +/*--------------------------------------------------------------------------*/ +int GetHdbPath(pHdb nodeArg, char *path, size_t pathlen) { + pHdb node, parent; + int len, pos, l; + static char *sics="/sics"; + pObjectDescriptor pDes; + + path[0]='\0'; + if (nodeArg == NULL) { + return 0; + } + /* determine path length and root node */ + parent = nodeArg; + len = 0; + for (node = nodeArg; node != NULL && node != root; node = node->mama) { + len += strlen(node->name) + 1; + if (len >= pathlen) return 0; /* buffer overflow (recursive path?) */ + parent = node; + } + + /* check root and add prefix */ + if (parent->mama != root) { /* not anchored in root */ + pDes = FindCommandDescriptor(pServ->pSics, parent->name); + if (!pDes) { + return 0; /* not a sics object */ + } + if (pDes->parNode != parent) { + /* node named as a sics object, but command is not related to node */ + return 0; + } + l= strlen(sics); + len += l; + if (len > pathlen) return 0; /* buffer overflow */ + strncpy(path, sics, l); + } + + /* build the path backwards */ + path[len]='\0'; + pos = len; + for (node = nodeArg; node != NULL && node != root; node = node->mama) { + len = strlen(node->name); + pos -= len; + assert(pos>0); + strncpy(path+pos, node->name, len); + pos--; + path[pos]='/'; + } + return 1; +} +/*--------------------------------------------------------------------------*/ +static int RemoveParNodeCallback(char *name, pDummy object, void *internalID) { + hdbPtrMessage m; + + m.type = killPtr; + m.pPtr = internalID; + if (object->pDescriptor->parNode) { + RecurseCallbackChains(object->pDescriptor->parNode,(pHdbMessage)&m); + } + return 1; +} +/*--------------------------------------------------------------------------*/ +void RemoveSICSInternalCallback(void *internalID) { + hdbPtrMessage m; + + m.type = killPtr; + m.pPtr = internalID; + RecurseCallbackChains(GetHipadabaRoot(),(pHdbMessage)&m); + ForEachCommand(RemoveParNodeCallback, internalID); +} +/*--------------------------------------------------------------------------*/ +int SICSHdbGetPar(void *obj, SConnection *pCon, char *path, hdbValue *v){ pHdb par = NULL; int status; char buffer[256]; @@ -979,16 +1467,14 @@ int SICSHdbGetPar(void *obj, SConnection *pCon, return SICSNOPAR; } - status = GetHdbPar(par,dataType,data,length,pCon); + status = GetHipadabaPar(par,v,pCon); if(status < 0){ return status; } return 1; } /*--------------------------------------------------------------------------*/ -int SICSHdbUpdatePar(void *obj, SConnection *pCon, - char *path, int dataType,void *data, int dataLength ){ - hdbValue v; +int SICSHdbUpdatePar(void *obj, SConnection *pCon, char *path, hdbValue v){ pHdb par = NULL; int status; char buffer[256]; @@ -1012,16 +1498,14 @@ int SICSHdbUpdatePar(void *obj, SConnection *pCon, return SICSNOPAR; } - status = UpdateHdbPar(par,dataType,data,dataLength,pCon); + status = UpdateHipadabaPar(par,v,pCon); if(status < 0){ return status; } return 1; } /*--------------------------------------------------------------------------*/ -int SICSHdbSetPar(void *obj, SConnection *pCon, - char *path, int dataType,void *data, int dataLength ){ - hdbValue v; +int SICSHdbSetPar(void *obj, SConnection *pCon, char *path, hdbValue v){ pHdb par = NULL; int status; char buffer[256]; @@ -1045,8 +1529,8 @@ int SICSHdbSetPar(void *obj, SConnection *pCon, return SICSNOPAR; } - status = SetHdbPar(par,dataType,data,dataLength,pCon); - if(status < 0){ + status = SetHipadabaPar(par,v,pCon); + if(status <= 0){ return status; } return 1; @@ -1063,8 +1547,8 @@ int InstallSICSNotify(pHdb node, SConnection *pCon, int id, int recurse){ SCWrite(pCon,"ERROR: out of memory installing callback", eError); return 0; } - AppendHipadabaCallback(node, HCBUPDATE, noty); - AppendHipadabaCallback(node, HCBTREE, treeChange); + AppendHipadabaCallback(node, noty); + AppendHipadabaCallback(node, treeChange); if(recurse == 1){ currentChild = node->child; @@ -1076,6 +1560,14 @@ int InstallSICSNotify(pHdb node, SConnection *pCon, int id, int recurse){ return 1; } /*---------------------------------------------------------------------------*/ +void RemoveConnectionCallbacks(pHdb root, SConnection *pCon){ + hdbPtrMessage dsm; + + dsm.type = killPtr; + dsm.pPtr = pCon; + RecurseCallbackChains(root,(pHdbMessage)&dsm); +} +/*---------------------------------------------------------------------------*/ int ProcessSICSHdbPar(pHdb root, SConnection *pCon, char *printPrefix, int argc, char *argv[]){ hdbValue input; @@ -1125,7 +1617,7 @@ int ProcessSICSHdbPar(pHdb root, SConnection *pCon, status = SetHipadabaPar(parNode,input,pCon); ReleaseHdbValue(&input); if(status == 1){ - SCSendOK(pCon); + /* SCSendOK(pCon); do not send OK. this has to be done by the callback */ SCparChange(pCon); } return status; @@ -1137,12 +1629,12 @@ int ProcessSICSHdbPar(pHdb root, SConnection *pCon, if(status != 1){ return 0; } - parData = formatValue(input); + parData = formatValue(input, parNode); if(parData == NULL){ SCWrite(pCon,"ERROR: out of memory reading parameter data",eError); return 0; } - DynStringInsert(parData," =", 0); + DynStringInsert(parData," = ", 0); DynStringInsert(parData,argv[0],0); if(printPrefix != NULL){ DynStringInsert(parData,printPrefix,0); @@ -1164,7 +1656,7 @@ void PrintSICSParList(pHdb node, SConnection *pCon, char *prefix){ while(child != NULL){ if(child->value.dataType != HIPNONE){ GetHipadabaPar(child,&v,pCon); - value = formatValue(child->value); + value = formatValue(child->value, child); if(value != NULL){ SCPrintf(pCon,eValue,"%s%s = %s", prefix, child->name, GetCharArray(value)); @@ -1189,7 +1681,7 @@ void SaveSICSHipadaba(FILE *fd, pHdb node, char *prefix){ currentChild = node->child; while(currentChild != NULL){ if(currentChild->value.dataType != HIPNONE && !isSICSHdbRO(currentChild)){ - data = formatValue(currentChild->value); + data = formatValue(currentChild->value, currentChild); if(data != NULL){ fprintf(fd,"%s%s %s\n", prefix, currentChild->name, GetCharArray(data)); DeleteDynString(data); @@ -1212,10 +1704,11 @@ void SaveSICSHipadaba(FILE *fd, pHdb node, char *prefix){ } } /*================ value helpers ============================================*/ -pDynString formatValue(hdbValue v){ +pDynString formatValue(hdbValue v, pHdb node){ pDynString result = NULL; int i; char number[30]; + char format[16]; result = CreateDynString(64,64); if(result == NULL){ @@ -1229,7 +1722,11 @@ pDynString formatValue(hdbValue v){ DynStringCopy(result,number); break; case HIPFLOAT: - snprintf(number,30,"%12.4f", v.v.doubleValue); + if (GetHdbProperty(node, "fmt", format, sizeof format -1)) { + snprintf(number,30,format, v.v.doubleValue); + } else { + snprintf(number,30,"%.6g", v.v.doubleValue); + } DynStringCopy(result,number); break; case HIPTEXT: @@ -1244,8 +1741,13 @@ pDynString formatValue(hdbValue v){ break; case HIPFLOATAR: case HIPFLOATVARAR: + if (GetHdbProperty(node, "fmt", format+1, sizeof format -2)) { + format[0]=' '; + } else { + strcpy(format, " %.6g"); + } for(i = 0; i < v.arrayLength; i++){ - snprintf(number,30," %12.4f", v.v.floatArray[i]); + snprintf(number,30,format, v.v.floatArray[i]); DynStringConcat(result,number); } break; @@ -1316,6 +1818,7 @@ int readHdbValue(hdbValue *v, char *data, char *error, int errlen){ double dValue; char number[80]; char *pPtr = NULL; + void *objData; switch(v->dataType){ case HIPNONE: @@ -1388,12 +1891,20 @@ int readHdbValue(hdbValue *v, char *data, char *error, int errlen){ v->v.floatArray[i] = dValue; } break; + case HIPOBJ: + break; + case HIPFUNC: + break; default: assert(0); break; } return 1; } +/*-------------------------------------------------------------------------*/ +hdbValue MakeSICSFunc(SICSOBJFunc func) { + return MakeHdbFunc((voidFunc *)func); +} /*================ interpreter interface ==================================*/ pHdb GetHipadabaRoot(){ return root; @@ -1407,9 +1918,11 @@ static char *hdbTypes[] = {"none", "floatar", "intvarar", "floatvarar", + "object", + "func", NULL}; /*-------------------------------------------------------------------------*/ -static int convertHdbType(char *text){ +int convertHdbType(char *text){ int type; type = 0; @@ -1430,11 +1943,12 @@ static char *hdbTypeToText(int type){ static int MakeHdbNode(SConnection *pCon, SicsInterp *pSics, void *pData, int argc, char *argv[]){ int type = 0, i, length = 0, priv = -1; - char *pPtr = NULL; + char *name = NULL; pHdb parent = NULL; pHdb child = NULL; char buffer[512], buffer2[512]; - + hdbValue val; + if(!SCMatchRights(pCon,usMugger)){ return 0; } @@ -1453,13 +1967,13 @@ static int MakeHdbNode(SConnection *pCon, SicsInterp *pSics, void *pData, */ strtolower(argv[3]); type = convertHdbType(argv[3]); - if(type >= 7){ + if(type > HIPFLOATVARAR){ SCWrite(pCon, "ERROR: invalid type requested: none, int, float, text, intar, floatar, intvarar, floatvarar supported", eError); return 0; } - if(type > 2){ + if(type >= HIPINTAR){ if( argc < 5){ SCWrite(pCon,"ERROR: array length missing for array data type", eError); @@ -1469,31 +1983,16 @@ static int MakeHdbNode(SConnection *pCon, SicsInterp *pSics, void *pData, } } - /* split off last path element */ - strncpy(buffer,argv[1],511); - pPtr = strrchr(buffer,'/'); - if(pPtr == NULL){ - SCWrite(pCon,"ERROR: invalid path specification", - eError); - return 0; - } - *pPtr = '\0'; - pPtr++; - if(strlen(pPtr) < 1) { - parent = root; - } else { - parent = GetHipadabaNode(root,buffer); - } - if(parent == NULL){ - snprintf(buffer2,512,"ERROR: parent %s for new node does not exist", - buffer); - SCWrite(pCon,buffer2,eError); - return 0; + parent = FindHdbParent(NULL, argv[1], &name, pCon); + if (parent == NULL) { + return 0; /* error messages written inside FindHdbParent */ } if(type != HIPNONE){ - child = MakeSICSHdbPar(pPtr, priv, makeHdbValue(type,length)); + val = makeHdbValue(type,length); + child = MakeSICSHdbPar(name, priv, val); + ReleaseHdbValue(&val); } else { - child = MakeHipadabaNode(pPtr,type,length); + child = MakeHipadabaNode(name,type,length); } if(child == NULL){ SCWrite(pCon,"ERROR: out of memory creating node",eError); @@ -1508,7 +2007,7 @@ static int MakeHdbNode(SConnection *pCon, SicsInterp *pSics, void *pData, static int MakeHdbScriptNode(SConnection *pCon, SicsInterp *pSics, void *pData, int argc, char *argv[]){ int type = 0, i, length = 0; - char *pPtr = NULL; + char *name = NULL; pHdb parent = NULL; pHdb child = NULL; pHdb current = NULL; @@ -1547,28 +2046,11 @@ static int MakeHdbScriptNode(SConnection *pCon, SicsInterp *pSics, void *pData, } } - /* split off last path element */ - strncpy(buffer,argv[1],511); - pPtr = strrchr(buffer,'/'); - if(pPtr == NULL){ - SCWrite(pCon,"ERROR: invalid path specification", - eError); - return 0; + parent = FindHdbParent(NULL, argv[1], &name, pCon); + if (parent == NULL) { + return 0; /* error messages written inside FindHdbParent */ } - *pPtr = '\0'; - pPtr++; - if(strlen(pPtr) < 1) { - parent = root; - } else { - parent = GetHipadabaNode(root,buffer); - } - if(parent == NULL){ - snprintf(buffer2,512,"ERROR: parent %s for new node does not exist", - buffer); - SCWrite(pCon,buffer2,eError); - return 0; - } - child = MakeSICSScriptPar(pPtr, argv[3], argv[2], + child = MakeSICSScriptPar(name, argv[3], argv[2], makeHdbValue(type,length)); if(child == NULL){ SCWrite(pCon,"ERROR: out of memory creating node",eError); @@ -1614,7 +2096,7 @@ static int DeleteHdbNode(SConnection *pCon, SicsInterp *pSics, void *pData, SCWrite(pCon,"ERROR: need path to node to delete",eError); return 0; } - killNode = GetHipadabaNode(root,argv[1]); + killNode = FindHdbNode(NULL, argv[1], pCon); if(killNode == NULL){ SCWrite(pCon,"ERROR: node to delete not found",eError); return 0; @@ -1630,45 +2112,6 @@ static int DeleteHdbNode(SConnection *pCon, SicsInterp *pSics, void *pData, return 1; } /*---------------------------------------------------------------------------*/ -static pHdb locateSICSNode(SicsInterp *pSics, SConnection *pCon, char *path){ - pHdb result = NULL; - char *pPtr = NULL, sicsObj[128], error[256]; - pDummy pDum = NULL; - CommandList *pCom = NULL; - - if(strstr(path,"/sics/") != NULL){ - pPtr = stptok(path,sicsObj,128,"/"); - pPtr = stptok(pPtr,sicsObj,128,"/"); - pPtr = stptok(pPtr,sicsObj,128,"/"); - strtolower(sicsObj); - pCom = FindCommand(pSics,sicsObj); - if(pCom == NULL) { - snprintf(error,255,"ERROR: object %s not found",sicsObj); - SCWrite(pCon,error,eError); - return NULL; - } - pDum = (pDummy)pCom->pData; - if(pDum == NULL){ - snprintf(error,255,"ERROR: object %s has no data",sicsObj); - SCWrite(pCon,error,eError); - return NULL; - } - if(pDum->pDescriptor->parNode == NULL){ - snprintf(error,255,"ERROR: object %s does not use Hipadaba",sicsObj); - SCWrite(pCon,error,eError); - return NULL; - } - result = GetHipadabaNode(pDum->pDescriptor->parNode,pPtr); - } else { - result = GetHipadabaNode(root,path); - } - if(result == NULL){ - snprintf(error,255,"ERROR: node %s NOT found",path); - SCWrite(pCon,error,eError); - } - return result; -} -/*---------------------------------------------------------------------------*/ static int SetHdbNode(SConnection *pCon, SicsInterp *pSics, void *pData, int argc, char *argv[]){ pHdb targetNode = NULL; @@ -1676,7 +2119,7 @@ static int SetHdbNode(SConnection *pCon, SicsInterp *pSics, void *pData, pDynString parData = NULL; char error[512]; int i, status; - + if(!SCMatchRights(pCon,usUser)){ return 0; } @@ -1687,12 +2130,13 @@ static int SetHdbNode(SConnection *pCon, SicsInterp *pSics, void *pData, return 0; } - targetNode = locateSICSNode(pSics,pCon,argv[1]); + + targetNode = FindHdbNode(NULL,argv[1],pCon); if(targetNode == NULL){ return 0; } if(!cloneHdbValue(&targetNode->value,&newValue)){ - SCWrite(pCon,"ERROR: out of mmeory cloning node", + SCWrite(pCon,"ERROR: out of memory cloning node", eError); return 0; } @@ -1701,7 +2145,8 @@ static int SetHdbNode(SConnection *pCon, SicsInterp *pSics, void *pData, SCWrite(pCon,"ERROR: out of memory reading parameter",eError); return 0; } - for(i = 2; i < argc; i++){ + DynStringConcat(parData, argv[2]); + for(i = 3; i < argc; i++){ DynStringConcat(parData," "); DynStringConcat(parData, argv[i]); } @@ -1715,7 +2160,7 @@ static int SetHdbNode(SConnection *pCon, SicsInterp *pSics, void *pData, status = SetHipadabaPar(targetNode,newValue,pCon); ReleaseHdbValue(&newValue); if(status == 1){ - SCSendOK(pCon); + /* SCSendOK(pCon); sending ok has to be done by the callback. */ } return status; } @@ -1728,9 +2173,11 @@ static int UpdateHdbNode(SConnection *pCon, SicsInterp *pSics, void *pData, char error[512]; int i, status; + /* if(!SCMatchRights(pCon,usUser)){ return 0; } + */ if(argc < 2) { SCWrite(pCon,"ERROR: insufficient number of arguments to UpdateHdbNode", @@ -1738,13 +2185,13 @@ static int UpdateHdbNode(SConnection *pCon, SicsInterp *pSics, void *pData, return 0; } - targetNode = locateSICSNode(pSics,pCon,argv[1]); + targetNode = FindHdbNode(NULL,argv[1],pCon); if(targetNode == NULL){ return 0; } if(argc > 2){ if(!cloneHdbValue(&targetNode->value,&newValue)){ - SCWrite(pCon,"ERROR: out of mmeory cloning node", + SCWrite(pCon,"ERROR: out of memory cloning node", eError); return 0; } @@ -1763,7 +2210,9 @@ static int UpdateHdbNode(SConnection *pCon, SicsInterp *pSics, void *pData, SCWrite(pCon,error, eError); return 0; } + DeleteDynString(parData); } else { + memset(&newValue,0,sizeof(hdbValue)); GetHipadabaPar(targetNode,&newValue,pCon); } status = UpdateHipadabaPar(targetNode,newValue,pCon); @@ -1774,6 +2223,29 @@ static int UpdateHdbNode(SConnection *pCon, SicsInterp *pSics, void *pData, return status; } /*-----------------------------------------------------------------------------*/ +static int ZipGetHdbNode(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]){ + pHdb targetNode = NULL; + char error[512], oriPath[512]; + int status; + hdbValue newValue; + + if(argc < 2) { + SCWrite(pCon,"ERROR: need path to node",eError); + return 0; + } + + strncpy(oriPath,argv[1], 511); + targetNode = FindHdbNode(NULL,argv[1],pCon); + if(targetNode == NULL){ + return 0; + } + memset(&newValue,0,sizeof(hdbValue)); + GetHipadabaPar(targetNode, &newValue, pCon); + ReleaseHdbValue(&newValue); + return sendZippedNodeData(targetNode,pCon); +} +/*---------------------------------------------------------------------------*/ static int GetHdbNode(SConnection *pCon, SicsInterp *pSics, void *pData, int argc, char *argv[]){ pHdb targetNode = NULL; @@ -1783,20 +2255,35 @@ static int GetHdbNode(SConnection *pCon, SicsInterp *pSics, void *pData, int i, status; Protocol protocol = normal_protocol; int outCode; + char value[80]; + /* + if(strstr(argv[1],"values") != NULL){ + printf("Found!!\n"); + } + */ + if(argc < 2) { SCWrite(pCon,"ERROR: need path to node to print",eError); return 0; } strncpy(oriPath,argv[1], 511); - targetNode = locateSICSNode(pSics,pCon,argv[1]); + targetNode = FindHdbNode(NULL,argv[1],pCon); if(targetNode == NULL){ return 0; } + /* + * if transfer = zip, redirect to zip + */ + if(GetHdbProperty(targetNode,"transfer", value,80) == 1){ + if(strstr(value,"zip") != NULL){ + return ZipGetHdbNode(pCon,pSics,pData,argc,argv); + } + } memset(&newValue,0,sizeof(hdbValue)); GetHipadabaPar(targetNode, &newValue, pCon); - parData = formatValue(newValue); + parData = formatValue(newValue, targetNode); if(parData == NULL){ SCWrite(pCon,"ERROR: out of memory formatting data",eError); return 0; @@ -1815,57 +2302,42 @@ static int GetHdbNode(SConnection *pCon, SicsInterp *pSics, void *pData, return 1; } -/*-----------------------------------------------------------------------------*/ -static int ZipGetHdbNode(SConnection *pCon, SicsInterp *pSics, void *pData, +/*---------------------------------------------------------------------------*/ +static int GetHdbVal(SConnection *pCon, SicsInterp *pSics, void *pData, int argc, char *argv[]){ pHdb targetNode = NULL; hdbValue newValue; + pDynString parData = NULL; char error[512], oriPath[512]; - int i, status; - int *iData = NULL; + int i, status, protocol, outCode; + char value[80]; if(argc < 2) { - SCWrite(pCon,"ERROR: need path to node",eError); + SCWrite(pCon,"ERROR: need path to node to print",eError); return 0; } strncpy(oriPath,argv[1], 511); - targetNode = locateSICSNode(pSics,pCon,argv[1]); + targetNode = FindHdbNode(NULL,argv[1],pCon); if(targetNode == NULL){ return 0; } memset(&newValue,0,sizeof(hdbValue)); GetHipadabaPar(targetNode, &newValue, pCon); - switch(newValue.dataType){ - case HIPINTAR: - case HIPINTVARAR: - for(i = 0; i < newValue.arrayLength; i++){ - newValue.v.intArray[i] = htonl(newValue.v.intArray[i]); - } - SCWriteZipped(pCon,oriPath, newValue.v.intArray, - newValue.arrayLength*sizeof(int)); - break; - case HIPFLOATAR: - case HIPFLOATVARAR: - iData = (int *)malloc(newValue.arrayLength*sizeof(int)); - if(iData == NULL){ - SCWrite(pCon,"ERROR: out of memory in ZipGetHdbNode",eError); - return 0; - } - memset(iData,0,newValue.arrayLength*sizeof(int)); - for(i = 0; i < newValue.arrayLength; i++){ - iData[i] = htonl((int)newValue.v.floatArray[i]*65536.); - } - SCWriteZipped(pCon,oriPath, iData, - newValue.arrayLength*sizeof(int)); - free(iData); - break; - default: - SCWrite(pCon,"ERROR: zipped writing not supported for this datatype", - eError); - return 0; - } - ReleaseHdbValue(&newValue); + parData = formatValue(newValue, targetNode); + if(parData == NULL){ + SCWrite(pCon,"ERROR: out of memory formatting data",eError); + return 0; + } else { + if ((protocol = isJSON(pCon)) == 1) + outCode = eHdbEvent; + else + outCode = eEvent; + SCWrite(pCon,GetCharArray(parData), outCode); + DeleteDynString(parData); + ReleaseHdbValue(&newValue); + return 1; + } return 1; } /*--------------------------------------------------------------------------*/ @@ -1893,7 +2365,7 @@ static int HdbNodeInfo(SConnection *pCon, SicsInterp *pSics, void *pData, } strncpy(oriPath,argv[1], 511); - targetNode = locateSICSNode(pSics,pCon,argv[1]); + targetNode = FindHdbNode(NULL,argv[1],pCon); if(targetNode == NULL){ return 0; } @@ -1921,13 +2393,13 @@ static int HdbNodeVal(SConnection *pCon, SicsInterp *pSics, void *pData, return 0; } - targetNode = locateSICSNode(pSics,pCon,argv[1]); + targetNode = FindHdbNode(NULL,argv[1],pCon); if(targetNode == NULL){ return 0; } memset(&newValue,0,sizeof(hdbValue)); GetHipadabaPar(targetNode, &newValue, pCon); - parData = formatValue(newValue); + parData = formatValue(newValue, targetNode); if(parData == NULL){ SCWrite(pCon,"ERROR: out of memory formatting data",eError); return 0; @@ -1943,7 +2415,7 @@ static int HdbNodeVal(SConnection *pCon, SicsInterp *pSics, void *pData, int isSICSHdbRO(pHdb node){ pHdbCallback current = NULL; - current = node->writeCallbacks; + current = node->callBackChain; while(current != NULL){ if(current->userCallback == SICSReadOnlyCallback) { return 1; @@ -2000,7 +2472,7 @@ static pDynString formatJSONList(pHdb node){ DynStringConcat(result,current->name); DynStringConcat(result,"\""); if(current->value.dataType != HIPNONE){ - data = formatValue(current->value); + data = formatValue(current->value, current); if(data != NULL){ DynStringConcat(result,": "); DynStringConcat(result,GetCharArray(data)); @@ -2033,7 +2505,7 @@ static pDynString formatListWithVal(pHdb node){ while(current != NULL){ if(current->value.dataType != HIPNONE){ DynStringConcat(result,current->name); - data = formatValue(current->value); + data = formatValue(current->value, current); if(data != NULL){ DynStringConcat(result," = "); DynStringConcat(result,GetCharArray(data)); @@ -2083,7 +2555,7 @@ static pDynString formatClientList(pHdb node){ DynStringConcat(result,number); break; case HIPFLOAT: - snprintf(number,50,"%lf",current->value.v.doubleValue); + snprintf(number,50,"%lg",current->value.v.doubleValue); DynStringConcat(result,number); break; case HIPTEXT: @@ -2129,7 +2601,7 @@ static int ListHdbNode(SConnection *pCon, SicsInterp *pSics, void *pData, return 0; } - if(strchr(argv[1],'-') != NULL){ + if(argv[1][0] == '-'){ pathArg = 2; if(argc < 3){ SCWrite(pCon,"ERROR: need path to node to print",eError); @@ -2137,7 +2609,7 @@ static int ListHdbNode(SConnection *pCon, SicsInterp *pSics, void *pData, } } - node = locateSICSNode(pSics,pCon,argv[pathArg]); + node = FindHdbNode(NULL,argv[pathArg],pCon); if(node == NULL){ return 0; } @@ -2187,7 +2659,7 @@ static int AutoNotifyHdbNode(SConnection *pCon, SicsInterp *pSics, void *pData, return 0; } - node = locateSICSNode(pSics,pCon,argv[1]); + node = FindHdbNode(NULL,argv[1],pCon); if(node == NULL){ return 0; } @@ -2205,6 +2677,7 @@ static int AutoNotifyHdbNode(SConnection *pCon, SicsInterp *pSics, void *pData, static int RemoveHdbCallback(SConnection *pCon, SicsInterp *pSics, void *pData, int argc, char *argv[]){ int id; + hdbIDMessage m; if(argc < 2) { SCWrite(pCon,"ERROR: need callback id to remove", @@ -2212,7 +2685,9 @@ static int RemoveHdbCallback(SConnection *pCon, SicsInterp *pSics, void *pData, return 0; } id = atoi(argv[1]); - RemoveHipadabaCallback(root,id); + m.type = killID; + m.ID = id; + RecurseCallbackChains(root,(pHdbMessage)&m); SCSendOK(pCon); return 1; } @@ -2221,9 +2696,7 @@ static int LinkHdbNode(SConnection *pCon, SicsInterp *pSics, void *pData, int argc, char *argv[]){ pHdb node = NULL; char buffer[256]; - CommandList *pCom = NULL; - pDummy pDum = NULL; - + pObjectDescriptor pDes = NULL; if(argc < 3) { SCWrite(pCon,"ERROR: need path and object name to link", @@ -2241,14 +2714,13 @@ static int LinkHdbNode(SConnection *pCon, SicsInterp *pSics, void *pData, return 0; } - pCom = FindCommand(pSics,argv[2]); - if(pCom == NULL){ + pDes = FindCommandDescriptor(pSics,argv[2]); + if(pDes == NULL){ snprintf(buffer,255,"ERROR: failed to find object %s", argv[2]); SCWrite(pCon,buffer,eError); return 0; } - pDum = pCom->pData; - if(pDum == NULL || pDum->pDescriptor->parNode == NULL){ + if(pDes->parNode == NULL){ snprintf(buffer,255, "ERROR: Object %s does not use Hipadaba natively and thus cannot be linked", argv[2]); @@ -2256,7 +2728,7 @@ static int LinkHdbNode(SConnection *pCon, SicsInterp *pSics, void *pData, return 0; } - if(pDum->pDescriptor->parNode->mama != NULL){ + if(pDes->parNode->mama != NULL){ snprintf(buffer,255, "ERROR: Object %s is already linked somewhere else", argv[2]); @@ -2264,33 +2736,36 @@ static int LinkHdbNode(SConnection *pCon, SicsInterp *pSics, void *pData, return 0; } - AddHipadabaChild(node,pDum->pDescriptor->parNode,pCon); + AddHipadabaChild(node,pDes->parNode,pCon); if(argc > 3){ - if(pDum->pDescriptor->parNode->name != NULL){ - free(pDum->pDescriptor->parNode->name); + if(pDes->parNode->name != NULL){ + free(pDes->parNode->name); } - pDum->pDescriptor->parNode->name = strdup(argv[3]); + pDes->parNode->name = strdup(argv[3]); } SCSendOK(pCon); return 1; } /*-------------------------------------------------------------------------*/ -static int ChainCallback(void *userData, void *callData, pHdb node, - hdbValue v){ +static hdbCallbackReturn ChainCallback(pHdb node, void *userData, + pHdbMessage message){ pHdb slave = (pHdb)userData; hdbValue vv, old; + pHdbDataMessage mm = NULL; + + if((mm = GetHdbUpdateMessage(message)) == NULL){ + return hdbContinue; + } if(slave != NULL){ - old = slave->value; memset(&vv,0,sizeof(hdbValue)); - GetHipadabaPar(slave,&vv,callData); - if(!compareHdbValue(old,vv)){ - UpdateHipadabaPar(slave, vv, callData); - } + GetHipadabaPar(slave,&vv,mm->callData); + UpdateHipadabaPar(slave, vv, mm->callData); + ReleaseHdbValue(&vv); } - return 1; + return hdbContinue; } /*--------------------------------------------------------------------------*/ static int ChainHdbNode(SConnection *pCon, SicsInterp *pSics, void *pData, @@ -2321,26 +2796,81 @@ static int ChainHdbNode(SConnection *pCon, SicsInterp *pSics, void *pData, return 0; } - kalle = MakeHipadabaCallback(ChainCallback,slave, NULL, -1,-1); + kalle = MakeHipadabaCallback(ChainCallback,slave, NULL); if(kalle == NULL){ SCWrite(pCon,"ERROR: out of memory creating callback",eError); return 0; } - AppendHipadabaCallback(master,HCBUPDATE, kalle); + AppendHipadabaCallback(master,kalle); SCSendOK(pCon); return 1; } +/* -------------------------------------------------------------------------- + * This is actually SCInvoke but without advancing the context. I think this + * is only of local use. It makes sure that commands executed as Hipadaba + * commands get logged properly. + */ + static int HDBInvoke(SConnection *self, SicsInterp *pInter, char *pCommand) + { + int iRet; + long lLen; + const char *pResult = NULL; + char *pBuffer = NULL, *pFile = NULL; + char pBueffel[80]; + int i, iSpace; + + assert(pInter); + + /* print command to log files */ + for( i = 0; i < self->iFiles; i++) + { + if(self->pFiles[i]) + { + fprintf(self->pFiles[i],"SICS>> %s\n",pCommand); + } + } + + /* print to command log if user or manager */ + if(SCGetRights(self) <= usUser) + { + if(self->pSock != NULL) + { + sprintf(pBueffel,"sock %d>>",self->pSock->sockid); + } + } + + /* invoke */ + self->inUse++; + self->eInterrupt = eContinue; + /* + get first word of command + */ + iRet = InterpExecute(pInter,self,pCommand); + + StatusFileTask(NULL); /* save changed parameters */ + + self->inUse--; + return iRet; + } /*---------------------------------------------------------------------------*/ -static int CommandSetCallback(void *userData, void *callData, pHdb node, - hdbValue v){ - SConnection *pCon = (SConnection *)callData; +static hdbCallbackReturn CommandSetCallback(pHdb node, void *userData, + pHdbMessage message){ + SConnection *pCon = NULL; pDynString cmd = NULL, par = NULL; pHdb current = NULL; int status; + pHdbDataMessage mm = NULL; + hdbValue v; + + if((mm = GetHdbSetMessage(message)) == NULL){ + return hdbContinue; + } + pCon = (SConnection *)pCon; + v = *(mm->v); if(pCon == NULL){ printf("Cannot invoke command without connection\n"); - return 0; + return hdbAbort; } if(v.dataType == HIPTEXT){ @@ -2354,7 +2884,7 @@ static int CommandSetCallback(void *userData, void *callData, pHdb node, DynStringConcat(cmd," "); current = node->child; while(current != NULL){ - par = formatValue(current->value); + par = formatValue(current->value, current); if(par != NULL){ DynStringConcat(cmd, GetCharArray(par)); DynStringConcat(cmd," "); @@ -2362,27 +2892,37 @@ static int CommandSetCallback(void *userData, void *callData, pHdb node, } current = current->next; } - status = SCInvoke(pCon, pServ->pSics,GetCharArray(cmd)); + status = HDBInvoke(pCon,pServ->pSics, GetCharArray(cmd)); DeleteDynString(cmd); - return status; + if(status == 1){ + return hdbContinue; + } else { + return hdbAbort; + } } else { SCWrite(pCon,"ERROR: this node only understands start as value",eError); - return 0; + return hdbAbort; } } - return 0; + return hdbContinue; } /*---------------------------------------------------------------------------*/ -static int CommandGetCallback(void *userData, void *callData, pHdb node, - hdbValue v){ +static hdbCallbackReturn CommandGetCallback(pHdb node, void *userData, + pHdbMessage message){ + pHdbDataMessage mm = NULL; + + if((mm = GetHdbGetMessage(message)) == NULL){ + return hdbContinue; + } + hdbValue v2 = MakeHdbText("Nothing to get"); - v = v2; - return 1; + copyHdbValue(&v2, mm->v); /* MakeHdbText makes no strdup ! */ + return hdbContinue; } /*--------------------------------------------------------------------------*/ static int SicsCommandNode(SConnection *pCon, SicsInterp *pSics, void *pData, int argc, char *argv[]){ - char buffer[512], buffer2[512], *pPtr = NULL; + char *name = NULL; pHdbCallback kalle = NULL; pHdb parent = NULL, node = NULL; @@ -2394,48 +2934,32 @@ static int SicsCommandNode(SConnection *pCon, SicsInterp *pSics, void *pData, return 0; } - /* split off last path element */ - strncpy(buffer,argv[1],511); - pPtr = strrchr(buffer,'/'); - if(pPtr == NULL){ - SCWrite(pCon,"ERROR: invalid path specification", - eError); - return 0; - } - *pPtr = '\0'; - pPtr++; - if(strlen(pPtr) < 1) { - parent = root; - } else { - parent = GetHipadabaNode(root,buffer); - } + parent = FindHdbParent(NULL, argv[1], &name, pCon); if(parent == NULL){ - snprintf(buffer2,512,"ERROR: parent %s for new node does not exist", - buffer); - SCWrite(pCon,buffer2,eError); - return 0; + return 0; /* error message already written */ } - node = MakeHipadabaNode(pPtr, HIPTEXT, 1); + node = MakeHipadabaNode(name, HIPTEXT, 1); if(node == NULL){ SCWrite(pCon,"ERROR: out of memory in hcommand",eError); return 0; } node->value.v.text = strdup(argv[2]); node->value.arrayLength = strlen(argv[2]); + SetHdbProperty(node,"sicscommand", argv[2]); - kalle = MakeHipadabaCallback(CommandSetCallback,NULL, NULL, -1,-1); + kalle = MakeHipadabaCallback(CommandSetCallback,NULL, NULL); if(kalle == NULL){ SCWrite(pCon,"ERROR: out of memory in hcommand",eError); return 0; } - AppendHipadabaCallback(node,HCBSET, kalle); + AppendHipadabaCallback(node,kalle); - kalle = MakeHipadabaCallback(CommandGetCallback,NULL, NULL, -1,-1); + kalle = MakeHipadabaCallback(CommandGetCallback,NULL, NULL); if(kalle == NULL){ SCWrite(pCon,"ERROR: out of memory in hcommand",eError); return 0; } - AppendHipadabaCallback(node,HCBREAD, kalle); + AppendHipadabaCallback(node,kalle); AddHipadabaChild(parent,node,pCon); @@ -2447,22 +2971,44 @@ static int SetSICSHdbProperty(SConnection *pCon, SicsInterp *pSics, void *pData, int argc, char *argv[]){ pHdb targetNode = NULL; char buffer[512]; + char *val; if(argc < 4) { SCWrite(pCon,"ERROR: need path key value as parameters",eError); return 0; } - targetNode = locateSICSNode(pSics,pCon,argv[1]); + targetNode = FindHdbNode(NULL,argv[1],pCon); if(targetNode == NULL){ SCWrite(pCon,"ERROR: node not found",eError); return 0; } - Arg2Text(argc-3, &argv[3], buffer,512); - SetHdbProperty(targetNode,argv[2], buffer); + val = Arg2Tcl(argc-3, &argv[3], buffer, sizeof buffer); + if (val) { + SetHdbProperty(targetNode,argv[2], val); + if (val != buffer) free(val); + } SCSendOK(pCon); return 1; } - /*--------------------------------------------------------------------------*/ +/*-------------------------------------------------------------------------------*/ +static int DelSICSHdbProperty(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]){ + pHdb targetNode = NULL; + + if(argc < 3) { + SCWrite(pCon,"ERROR: need path key as parameters",eError); + return 0; + } + targetNode = FindHdbNode(NULL,argv[1],pCon); + if(targetNode == NULL){ + SCWrite(pCon,"ERROR: node not found",eError); + return 0; + } + SetHdbProperty(targetNode,argv[2], NULL); + SCSendOK(pCon); + return 1; + } +/*--------------------------------------------------------------------------*/ static int GetSICSHdbProperty(SConnection *pCon, SicsInterp *pSics, void *pData, int argc, char *argv[]){ pHdb targetNode = NULL; @@ -2473,20 +3019,44 @@ static int GetSICSHdbProperty(SConnection *pCon, SicsInterp *pSics, void *pData, SCWrite(pCon,"ERROR: need path key as parameters",eError); return 0; } - targetNode = locateSICSNode(pSics,pCon,argv[1]); + targetNode = FindHdbNode(NULL,argv[1],pCon); if(targetNode == NULL){ - SCWrite(pCon,"ERROR: node not found",eValue); + SCWrite(pCon,"ERROR: node not found",eValue); return 0; } status = GetHdbProperty(targetNode,argv[2],buffer,511); if(status != 1){ - SCWrite(pCon,"ERROR: attribute not found",eValue); - return 0; + SCPrintf(pCon,eValue,"ERROR: property %s not found", argv[2]); + return 0; } SCPrintf(pCon,eValue,"%s.%s = %s", argv[1], argv[2], buffer); return 1; } /*--------------------------------------------------------------------------*/ +static int GetSICSHdbPropertyVal(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]){ + pHdb targetNode = NULL; + char buffer[512]; + int status; + + if(argc < 3) { + SCWrite(pCon,"ERROR: need path key as parameters",eError); + return 0; + } + targetNode = FindHdbNode(NULL,argv[1],pCon); + if(targetNode == NULL){ + SCWrite(pCon,"ERROR: node not found",eValue); + return 0; + } + status = GetHdbProperty(targetNode,argv[2],buffer,511); + if(status != 1){ + SCWrite(pCon,"ERROR: attribute not found",eValue); + return 0; + } + SCPrintf(pCon,eValue,"%s", buffer); + return 1; + } + /*--------------------------------------------------------------------------*/ static int ListSICSHdbProperty(SConnection *pCon, SicsInterp *pSics, void *pData, int argc, char *argv[]){ pHdb targetNode = NULL; @@ -2498,7 +3068,7 @@ static int ListSICSHdbProperty(SConnection *pCon, SicsInterp *pSics, void *pData SCWrite(pCon,"ERROR: need path as parameter",eError); return 0; } - targetNode = locateSICSNode(pSics,pCon,argv[1]); + targetNode = FindHdbNode(NULL,argv[1],pCon); if(targetNode == NULL){ SCWrite(pCon,"ERROR: node not found",eError); return 0; @@ -2519,6 +3089,61 @@ static int ListSICSHdbProperty(SConnection *pCon, SicsInterp *pSics, void *pData DeleteDynString(data); return 1; } +/*---------------------------------------------------------------------------*/ +static pHdb matchHdbProp(pHdb root, char *propname, char *buffer){ + char value[1024]; + pHdb current = NULL, search; + + memset(value,0,1024); + if(GetHdbProperty(root,propname,value,1023) == 1){ + if(strstr(buffer,value) != NULL){ + return root; + } + } + current = root->child; + while(current != NULL){ + search = matchHdbProp(current,propname,buffer); + if(search != NULL){ + return search; + } + current = current->next; + } + + return NULL; +} +/*---------------------------------------------------------------------------*/ +static int MatchHdbProperty(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]){ + pHdb root = NULL; + pHdb foundNode = NULL; + char buffer[1024], *path = NULL; + + if(argc < 4){ + SCWrite(pCon,"ERROR: need root, property name and target string for search", + eError); + return 0; + } + memset(buffer,0,1024); + Arg2Text(argc-3,&argv[3],buffer,1023); + root = GetHipadabaNode(GetHipadabaRoot(), argv[1]); + if(root == NULL){ + SCWrite(pCon,"ERROR: start node for search not found",eError); + return 0; + } + + strtolower(argv[2]); + strtolower(buffer); + foundNode = matchHdbProp(root,argv[2],buffer); + + if(foundNode == NULL){ + SCWrite(pCon,"NONE", eValue); + } else { + path = GetHipadabaPath(foundNode); + SCWrite(pCon,path,eValue); + free(path); + } + return 1; +} /*======================= Factory Functions =================================*/ void killSICSHipadaba(){ if(root != NULL){ @@ -2527,17 +3152,23 @@ void killSICSHipadaba(){ root = NULL; } /*---------------------------------------------------------------------------*/ +extern int HdbNodeFactory(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]); /* from sicshdbfactory.c */ +/*---------------------------------------------------------------------------*/ int InstallSICSHipadaba(SConnection *pCon, SicsInterp *pSics, void *pData, int argc, char *argv[]){ root = MakeHipadabaNode("/",HIPNONE,0); AddCommand(pSics,"hmake", MakeHdbNode, NULL, NULL); + AddCommand(pSics,"hfactory", HdbNodeFactory, NULL, NULL); AddCommand(pSics,"hmakescript", MakeHdbScriptNode, NULL, NULL); AddCommand(pSics,"hattach", SICSHdbAdapter, NULL, NULL); + AddCommand(pSics,"hsubsamplehm", HdbSubSample, NULL, NULL); AddCommand(pSics,"hdel", DeleteHdbNode, NULL, NULL); AddCommand(pSics,"hset", SetHdbNode, NULL, NULL); AddCommand(pSics,"hupdate", UpdateHdbNode, NULL, NULL); AddCommand(pSics,"hget", GetHdbNode, NULL, NULL); + AddCommand(pSics,"hval", GetHdbVal, NULL, NULL); AddCommand(pSics,"hzipget",ZipGetHdbNode, NULL, NULL); AddCommand(pSics,"hlist", ListHdbNode, NULL, NULL); AddCommand(pSics,"hnotify", AutoNotifyHdbNode, NULL, NULL); @@ -2548,7 +3179,10 @@ int InstallSICSHipadaba(SConnection *pCon, SicsInterp *pSics, void *pData, AddCommand(pSics,"hchain", ChainHdbNode, NULL, NULL); AddCommand(pSics,"hcommand",SicsCommandNode, NULL, NULL); AddCommand(pSics,"hsetprop",SetSICSHdbProperty, NULL, NULL); + AddCommand(pSics,"hdelprop",DelSICSHdbProperty, NULL, NULL); AddCommand(pSics,"hgetprop",GetSICSHdbProperty, NULL, NULL); + AddCommand(pSics,"hgetpropval",GetSICSHdbPropertyVal, NULL, NULL); + AddCommand(pSics,"hmatchprop",MatchHdbProperty, NULL, NULL); AddCommand(pSics,"hlistprop",ListSICSHdbProperty, NULL, NULL); InstallSICSPoll(pCon,pSics,pData,argc,argv); diff --git a/sicshipadaba.h b/sicshipadaba.h index 29724ee7..e998a1e3 100644 --- a/sicshipadaba.h +++ b/sicshipadaba.h @@ -1,4 +1,4 @@ -/** +/** @file * This is a set of helper functions for SICS to work with the hierarchical parameter * database hipadaba. In SICS, the calldata associated with any callback will always * be the connection object. @@ -12,12 +12,28 @@ #include #include #include +#include /*======================== callback error codes ===============================*/ #define SICSCBRO -607 #define SICSCBPERM -608 #define SICSCBRANGE -609 #define SICSCBBADFIXED -610 #define SICSNOPAR -611 +/*======================== SICS Messages ======================================*/ +typedef struct { + char *type; + int ID; +}hdbIDMessage, *pHdbIDMessage; +/*------------------------------------------------------------------------------*/ +pHdbIDMessage GetKillIDMessage(pHdbMessage message); +pHdbIDMessage GetKillInternalIDMessage(pHdbMessage message); +/*-----------------------------------------------------------------------------*/ +typedef struct { + char *type; + void *pPtr; +}hdbPtrMessage, *pHdbPtrMessage; +/*-----------------------------------------------------------------------------*/ +pHdbPtrMessage GetKillPtrMessage(pHdbMessage message); /*======================== data structure for automatic parameter update =======*/ typedef struct { SConnection *pCon; @@ -39,11 +55,17 @@ pHdbCallback MakeReadOnlyCallback(); pHdbCallback MakeCheckPermissionCallback(int priv); /** * make a callback which directly updates a - * paramter after setting. Usefule for program parameters. + * paramter after setting. Useful for program parameters. * @return a suitably initialized callback structure setting * program parameters */ pHdbCallback MakeSetUpdateCallback(); +/** + * Remove a SetUpdate callback. This is useful for chaning the + * behaviour of a node created with the hmake command + * @param node the node + */ +void RemoveSetUpdateCallback(pHdb node); /** * make a callback which starts a parameter driving. * @param sicsObject The SICS object to drive. @@ -115,10 +137,15 @@ pHdbCallback MakeMemSetCallback(float *address); /** * make a tree chnage callback * @param pCon The connection to notfy on tree chnages - * @id The ID of this callback + * @param id The ID of this callback * @return a suitable callback for notififications about tree changes. */ pHdbCallback MakeTreeChangeCallback(SConnection *pCon, int id); + /** + * make a clalback to invoke a function node + */ + pHdbCallback MakeSICSFuncCallback(void *obj); + /*======================== parameter creation ===================================*/ /** * make a simple SICS hdb parameter. Setting it will call update immediately. Use @@ -129,19 +156,6 @@ pHdbCallback MakeMemSetCallback(float *address); * @return A new suitably configured Hdb parameter or NULL when out of memory. */ pHdb MakeSICSHdbPar(char *name, int priv, hdbValue v); -/** - * make a simple SICS hdb parameter. Setting it will call update immediately. Use - * this for program parameters. - * @param name The name of the parameter - * @param priv The privilege required to change that parameter - * @param dataType The datatype for the new parameter. - * @param length The length of any arrays - * @param data Data to initalise the parameter with. Can be NULL, then - * no initialisation takes place. - * @return A new suitably configured Hdb parameter or NULL when out of memory. - */ -pHdb CreateSICSHdbPar(char *name, int priv, int dataType, - int length, void *data); /** * make a SICS hdb drivable parameter. Setting it will start the motor, * virtual motor or environment parameter. This will call StartDevice @@ -149,7 +163,7 @@ pHdb CreateSICSHdbPar(char *name, int priv, int dataType, * @param name The name of the parameter * @param priv The privilege required to change that parameter * @param sicsObject The object corresponding to this parameter. - * @param dataType The datatype of this variable + * @param datatype The datatype of this variable * @return A new suitably configured Hdb parameter or NULL when out of memory. */ pHdb MakeSICSHdbDriv(char *name, int priv,void *sicsObject, int datatype); @@ -178,18 +192,6 @@ pHdb MakeSICSROPar(char *name, hdbValue v); * @return A new suitably configured Hdb parameter or NULL when out of memory. */ pHdb MakeSICSScriptPar(char *name, char *setScript, char *readScript, hdbValue v); -/** - * make a SICS scriptable parameter. I.e. when this parameter is set or read, - * appropriate scripts are invoked. - * @param name The name of the parameter - * @param dataType The datatype for the new parameter. - * @param length The length of any arrays - * @param data Data to initalise the parameter with. Can be NULL, then - * no initialisation takes place. - * @return A new suitably configured Hdb parameter or NULL when out of memory. - */ -pHdb CreateSICSScriptPar(char *name, char *setScript, char *readScript, - int dataType, int length, void *data); /** * remove a SICS paramameter node and its children. In contrast to the @@ -202,72 +204,108 @@ void RemoveSICSPar(pHdb node, void *callData); /*=============== Add par functions =======================================*/ /** * add a new simple hdb parameter as child to node - * @param node The node to add the new node too. + * @param parent The parent node to add the new node to. + * @param name The name of the new node * @param priv The privilege required to change that parameter * @param v The initial value and datatype of this parameter - * @return 1 on success, 0 else + * @return the created node on success, NULL else */ -int AddSICSHdbPar(pHdb node, char *name, int priv, hdbValue v); +pHdb AddSICSHdbPar(pHdb parent, char *name, int priv, hdbValue v); /** * add a new read only hdb parameter as child to node - * @param node The node to add the new node too. + * @param parent The parent node to add the new node to. + * @param name The name of the new node * @param v The initial value and datatype of this parameter - * @return 1 on success, 0 else + * @return the created node on success, NULL else */ -int AddSICSHdbROPar(pHdb node, char *name, hdbValue v); +pHdb AddSICSHdbROPar(pHdb parent, char *name, hdbValue v); /** * Add a new hdb parameter as child to node. Updates are synced * to the memory location data. This works for simple variables, fixed size * arrays and fixed sized strings. This does not work for dynamically sized * arrays or strings. - * @param node The node to add the new node too. + * @param parent The parent node to add the new node to. + * @param name The name of the new node * @param priv The privilege required to change that parameter - * @param data The pointer to map this parameter too. This must be in + * @param data The pointer to map this parameter to. This must be in * dynamically allocated memory. * @param datalength The length of the data area pointed to by data. * @param type The data type of the parameter * @param length The length of the type. Used for array types. - * @return 1 on success, 0 else + * @return the created node on success, NULL else */ -int AddSICSHdbMemPar(pHdb node, char *name, int priv, +pHdb AddSICSHdbMemPar(pHdb parent, char *name, int priv, void *data, int datalength, int type, int length); /*============== access support functions =================================*/ +/** Find the parent of a node to be created + * @param rootpath the root path (where to start). May be NULL for absolute paths + * @param relpath an absolute or relative path + * @param namePtr (output) a pointer to a name. Will be the last element of + * the path if the parent was found. If namePtr is NULL, the routine does + * the same as FindHdbNode(root, relpath, pCon) + * @param pCon a connection for writing the error messages (may be NULL) + * @return the parent node or NULL on failure + * + * An abolute path starts with a slash, else it is a relative path. + * If the node exists already, an error message is emitted (node exists already) + * and NULL is returned. + * + * Nodes anchored in the sics object list are also found when + * the path starts with "/sics/" + */ +pHdb FindHdbParent(char *rootpath, char *relpath, char **namePtr, SConnection *pCon); +/** FindHdbNode finds a node + * @param rootpath the root path (where to start). May be NULL for absolute paths. + * @param relpath an absolute or relative path + * @param pCon a connection for writing the error messages (may be NULL) + * @return the found node or NULL on failure + * + * An abolute path starts with a slash, else it is a relative path. + * If relpath if a single dot ('.') root is returned. + * + * Nodes anchored in the sics object list are also found when + * the path starts with "/sics/" + */ +pHdb FindHdbNode(char *rootpath, char *relpath, SConnection *pCon); +/** Get the absolute path of a node anchored in the + * Hipadaba root or in a sics object + * @param nodeArg the input node + * @param path the result + * @param pathlen length of the result + * @return 1 on success, 0 on failure + */ +int GetHdbPath(pHdb nodeArg, char *path, size_t pathlen); +/** Remove all Callbacks rooted in the main root _and_ in sics objects + * @param internalID the internalID to be looked for + */ +void RemoveSICSInternalCallback(void *internalID); /** * SICSHdbGetPar returns the value of a parameter. * @param obj The object for which to get a parameter. * @param pCon The optional connection object to use for reporting errors. * @param path The path to the parameter. - * @param dataType The datatype for the parameter. - * @param data Target pointer to which to copy data too. - * @param length The length of data + * @param v the value * @return 1 on success, a negative error code else. */ -int SICSHdbGetPar(void *obj, SConnection *pCon, - char *path, int dataType, void *data, int length); +int SICSHdbGetPar(void *obj, SConnection *pCon, char *path, hdbValue *v); /** * SICSHdbUpdatePar updates the value of a parameter. * @param obj The object for which to get a parameter. * @param pCon The optional connection object to use for reporting errors. * @param path The path to the parameter. - * @param dataType The datatype for the parameter. - * @param data Pointer from which to copy data. - * @param length The length of data + * @param v the value * @return 1 on success, a negative error code else. */ -int SICSHdbUpdatePar(void *obj, SConnection *pCon, - char *path, int dataType, void *data, int length); +int SICSHdbUpdatePar(void *obj, SConnection *pCon, char *path, hdbValue v); /** * SICSHdbSetPar sets the value of a parameter. * @param obj The object for which to get a parameter. * @param pCon The optional connection object to use for reporting errors. * @param path The path to the parameter. - * @param dataType The datatype for the parameter. - * @param data Pointer from which to copy data. - * @param length The length of data - * @return 1 on success, a negative error code else. + * @param v the value + * @return positive on success, a negative error code else. */ -int SICSHdbSetPar(void *obj, SConnection *pCon, - char *path, int dataType, void *data, int length); +int SICSHdbSetPar(void *obj, SConnection *pCon, char *path, hdbValue v); /** * query function if a parameter is read only. * @param node The ndoe to query @@ -288,6 +326,12 @@ int isSICSHdbRO(pHdb node); * @return 1 on success, 0 when out of memory. */ int InstallSICSNotify(pHdb node, SConnection *pCon, int id, int recurse); +/** + * remove all Callbacks associated with a given conenction + * @param root Where to start removing callbacks + * @param pCon The connection for which to remove callbacks + */ +void RemoveConnectionCallbacks(pHdb root, SConnection *pCon); /** * handles the common task of checking for, and processing a SICS parameter. * @param root The node at which to search for parameters @@ -304,9 +348,9 @@ int ProcessSICSHdbPar(pHdb root, SConnection *pCon, char *printPrefix, /** * print a listing of the parameters of node to pCon, using the * specified prefix. - * @param The node to print - * @pCon The connection to print too - * @prefix The prefix to use for printing + * @param node The node to print + * @param pCon The connection to print to + * @param prefix The prefix to use for printing */ void PrintSICSParList(pHdb node, SConnection *pCon, char *prefix); /** @@ -332,21 +376,35 @@ void SICSHipadabaSignal(void *pData, int iSignal, void *pSigData); /** * format a Hdb Value into a string using SICS defaults. * @param v The Hdb value to format + * @param node The Hdb node (for format property) * @return a dynamic string holding the formatted data. NULL when * out of memory */ -pDynString formatValue(hdbValue v); +pDynString formatValue(hdbValue v, pHdb node); /** * read values for a Hdb value from a string. * @param v The hdbValue to read data into. Datatype and arraylength must * already have been initialised before this call in order to allow for * checks. Arrays should also have been allocated in the right size. * @param data The string to parse and convert. - * @param error A string to copy failure reasons too + * @param error A string to copy failure reasons to * @param errlen The length of the error string * @return 0 on failure, 1 on success */ int readHdbValue(hdbValue *v, char *data, char *error, int errlen); +/** + * convert from test to a Hipadaba type + * @param text The type text + * @return The converted Hipadaba type + */ +int convertHdbType(char *text); +/** + * wrap a SICSOBJFunc function as an hdbValue + * @param func the function + * @return: A properly initialized hdbValue structure + */ +hdbValue MakeSICSFunc(SICSOBJFunc func); + /*================= SICS Interpreter Interface ===========================*/ /** * InstallHipadaba installs the Hipadaba commands into the SICS interpreter. diff --git a/sicsobj.c b/sicsobj.c new file mode 100644 index 00000000..0eaabcdd --- /dev/null +++ b/sicsobj.c @@ -0,0 +1,354 @@ +/** + * This is the header file for the new (as of 2007) style SICS objects + * + * copyright: see file COPYRIGHT + * + * Mark Koennecke, July 2007 + */ +#include +#include +#include "assert.h" +#include "ifile.h" +#include "sicsobj.h" +#include "dynstring.h" +#include "macro.h" +#include "sicshipadaba.h" +#include "initializer.h" +#include "splitter.h" + +extern int decodeSICSPriv(char *txt); /* from access.c */ +/*--------------------------------------------------------------------------*/ +void DefaultKill(void *data){ + return; +} +/*---------------------------------------------------------------------------*/ +pSICSOBJ MakeSICSOBJv(char *name, char *class, int type, int priv){ + pSICSOBJ pNew = NULL; + hdbValue val; + + pNew = (pSICSOBJ)malloc(sizeof(SICSOBJ)); + if(pNew == NULL){ + return NULL; + } + memset(pNew,0,sizeof(SICSOBJ)); + pNew->pDes = CreateDescriptor(class); + if (type == HIPNONE) { + pNew->objectNode = MakeHipadabaNode(name, HIPNONE, 1); + } else { + val = makeHdbValue(type,0); + pNew->objectNode = MakeSICSHdbPar(name, priv, val); + ReleaseHdbValue(&val); + } + if(pNew->pDes == NULL || pNew->objectNode == NULL){ + free(pNew); + return(NULL); + } + pNew->pDes->parNode = pNew->objectNode; + pNew->KillPrivate = DefaultKill; + return pNew; +} +/*---------------------------------------------------------------------------*/ +pSICSOBJ MakeSICSOBJ(char *name, char *class){ + return MakeSICSOBJv(name, class, HIPNONE, 0); +} +/*---------------------------------------------------------------------------*/ +void KillSICSOBJ(void *data){ + pSICSOBJ self = (pSICSOBJ)data; + if(self == NULL){ + return; + } + if(self->KillPrivate != NULL && self->pPrivate != NULL){ + self->KillPrivate(self->pPrivate); + } + RemoveHdbNodeFromParent(self->objectNode, pServ->dummyCon); + if(self->pDes != NULL){ + DeleteDescriptor(self->pDes); /* kill descriptor including node */ + } + free(self); +} +/*===========================================================================*/ +static int assignPar(pHdb node, SConnection *pCon, char *data){ + char error[132], buffer[256]; + int status; + + status = readHdbValue(&node->value,data, error, 132); + if(status != 1){ + snprintf(buffer,255,"ERROR: error parsing %s: %s", + node->name, error); + SCWrite(pCon,buffer,eError); + return 0; + } + return 1; +} +/*---------------------------------------------------------------------------*/ +static int invokeOBJFunction(pSICSOBJ object, pHdb commandNode, SConnection *pCon, + int argc, char *argv[]){ + int status, i, count = 0; + pHdb currentPar = NULL; + SICSOBJFunc pFunc = NULL; + pHdb parArray[64]; + + /* + * assign parameters and fill parameter array for function at the same + * time. Be lenient about missing parameters: Then the old values will + * be used. + */ + for(i = 0, currentPar = commandNode->child; + i < argc && currentPar != NULL; + i++, currentPar = currentPar->next){ + if(argv[i] != NULL){ + status = assignPar(currentPar,pCon, argv[i]); + } + if(status != 1){ + return status; + } + parArray[i] = currentPar; + count++; + } + + pFunc = (SICSOBJFunc)commandNode->value.v.func; + if(pFunc == NULL){ + SCWrite(pCon,"ERROR: internal error, function not found",eError); + return 0; + } + status = pFunc(object, pCon, commandNode, parArray,count); + return status; +} +/*---------------------------------------------------------------------------*/ +static int ScriptObjFunc(pSICSOBJ obj, SConnection *pCon, pHdb commandNode, + pHdb par[], int nCount){ + int status, i; + Tcl_Interp *pTcl = NULL; + Tcl_DString com; + char value[256]; + pDynString val = NULL; + char *pPtr = NULL; + + memset(value,0,256); + GetHdbProperty(commandNode,"priv",value,256); + status = decodeSICSPriv(value); + if(!SCMatchRights(pCon,status)){ + return 0; + } + + if(GetHdbProperty(commandNode,"script",value,256) != 1){ + SCWrite(pCon,"ERROR: script property not configured on this node", + eError); + return 0; + } + + Tcl_DStringInit(&com); + Tcl_DStringAppend(&com,value,strlen(value)); + for(i = 0; i < nCount; i++){ + val = formatValue(par[i]->value, par[i]); + if(val != NULL){ + Tcl_DStringAppend(&com," ", 1); + pPtr = GetCharArray(val); + Tcl_DStringAppend(&com,pPtr,strlen(pPtr)); + DeleteDynString(val); + } + } + + MacroPush(pCon); + pTcl = InterpGetTcl(pServ->pSics); + status = Tcl_Eval(pTcl,Tcl_DStringValue(&com)); + Tcl_DStringFree(&com); + MacroPop(); + + if(status == TCL_OK){ + SCWrite(pCon,Tcl_GetStringResult(pTcl),eValue); + return 1; + } else { + SCWrite(pCon,Tcl_GetStringResult(pTcl),eError); + return 0; + } + return 1; +} +/*--------------------------------------------------------------------------*/ +static int MakeScriptFunc(pSICSOBJ self, SConnection *pCon, + int argc, char *argv[]){ + char path[512], *pPtr = NULL; + pHdb parent = NULL, node = NULL; + hdbValue func; + + if(argc < 5){ + SCWrite(pCon, + "ERROR: not enough arguments: obj makescriptfunc path script priv", + eError); + return 0; + } + + if(!SCMatchRights(pCon,usMugger)){ + return 0; + } + + + strncpy(path,argv[2],511); + pPtr = strrchr(path,'/'); + if(pPtr == NULL){ + /* no hierarchy */ + parent = self->objectNode; + node = MakeHipadabaNode(path,HIPFUNC,1); + } else { + /* hierarchy */ + *pPtr = '\0'; + parent = GetHipadabaNode(self->objectNode,path); + pPtr++; + node = MakeHipadabaNode(pPtr,HIPFUNC,1); + } + if(parent == NULL || node == NULL){ + SCWrite(pCon,"ERROR: root path error or out of memory",eError); + return 0; + } + node->value = MakeSICSFunc(ScriptObjFunc); + SetHdbProperty(node,"script",argv[3]); + SetHdbProperty(node,"priv",argv[4]); + AppendHipadabaCallback(node,MakeSICSFuncCallback(self)); + AddHipadabaChild(parent,node,pCon); + SCSendOK(pCon); + return 1; +} +/*---------------------------------------------------------------------------*/ +static int isNodePrintable(pHdb node){ + switch(node->value.dataType){ + case HIPNONE: + case HIPFUNC: + return 0; + default: + return 1; + } +} +/*---------------------------------------------------------------------------*/ +int InvokeSICSOBJ(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]){ + pSICSOBJ self = NULL; + int status; + pHdb parNode; + char buffer[132]; + hdbValue data; + pDynString parData; + + self = (pSICSOBJ)pData; + assert(self != NULL); + + if (argc == 1) { + parNode = self->objectNode; + if(parNode != NULL && isNodePrintable(parNode) ){ + status = GetHipadabaPar(parNode,&data,pCon); + if(status != 1){ + return 0; + } + parData = formatValue(data, parNode); + if(parData == NULL){ + SCWrite(pCon,"ERROR: failed to format data", eError); + return 0; + } + SCPrintf(pCon,eValue,"%s = %s", argv[0], GetCharArray(parData)); + DeleteDynString(parData); + return 1; + } else { + SCWrite(pCon,"ERROR: nothing to print", eError); + return 0; + } + } else { + parNode = GetHipadabaNode(self->objectNode,argv[1]); + } + if(parNode != NULL && parNode->value.dataType == HIPFUNC){ + status = invokeOBJFunction(self, parNode, pCon, argc-2, &argv[2]); + } else { + snprintf(buffer, sizeof buffer, "%s ", argv[0]); + status = ProcessSICSHdbPar(self->objectNode,pCon, buffer, + argc-1,&argv[1]); + } + if(status == -1){ + if(strcmp(argv[1],"makescriptfunc") == 0) { + return MakeScriptFunc(self,pCon,argc,argv); + } + SCPrintf(pCon, eError, "ERROR: %s %s not found", argv[0], argv[1]); + } + + return status; +} +/*---------------------------------------------------------------------------*/ +int InterInvokeSICSOBJ(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]){ + int status; + char buffer[132]; + + status = InvokeSICSOBJ(pCon,pSics,pData,argc,argv); + if(status == -1){ + status = 0; + if(argc > 1){ + snprintf(buffer,131,"ERROR: no command or parameter found for key: %s", + argv[1]); + } else { + snprintf(buffer,131,"ERROR: no argument found"); + } + SCWrite(pCon,buffer,eError); + status = 0; + } + return status; +} +/*---------------------------------------------------------------------------*/ +pSICSOBJ SetupSICSOBJ(SConnection *pCon,SicsInterp *pSics, void *pData, + int argc, char *argv[]){ + pSICSOBJ pNew = NULL; + int status; + int type; + int priv; + + if(argc < 3){ + SCWrite(pCon,"ERROR: not enough arguments to InstallSICSOBJ",eError); + return NULL; + } + if (argc < 5) { + type = HIPNONE; + priv = usInternal; + } else { + /* convert privilege */ + priv = decodeSICSPriv(argv[3]); + /* convert datatype */ + strtolower(argv[4]); + type = convertHdbType(argv[4]); + if(type > HIPFLOAT){ + SCWrite(pCon, + "ERROR: invalid type requested: none, int, float supported", + eError); + return 0; + } + } + + pNew = MakeSICSOBJv(argv[1], argv[2], type, priv); + if(pNew == NULL){ + SCWrite(pCon,"ERROR: out of memory creating new SICS object",eError); + return NULL; + } + if (strcasecmp(argv[0],"DynSicsObj") == 0) { + /* make object dynamic by defining a descriptor command */ + SetDescriptorKey(pNew->pDes, "creationCommand", "0"); + } + + status = AddCommand(pSics, + argv[1], + InterInvokeSICSOBJ, + KillSICSOBJ, + pNew); + if(status != 1){ + KillSICSOBJ(pNew); + SCPrintf(pCon,eError,"ERROR: failed create duplicate command %s", argv[1]); + return NULL; + } + return pNew; + } +/*---------------------------------------------------------------------------*/ +int InstallSICSOBJ(SConnection *pCon,SicsInterp *pSics, void *pData, + int argc, char *argv[]){ + pSICSOBJ pNew = NULL; + + pNew = SetupSICSOBJ(pCon, pSics, pData, argc, argv); + if(pNew == NULL){ + return 0; + } else { + return 1; + } +} diff --git a/sicsobj.h b/sicsobj.h new file mode 100644 index 00000000..a095d52a --- /dev/null +++ b/sicsobj.h @@ -0,0 +1,54 @@ +/** + * This is the header file for the new (as of 2007) style SICS objects + * + * copyright: see file COPYRIGHT + * + * Mark Koennecke, July 2007 + */ +#ifndef SICSOBJ2_H_ +#define SICSOBJ2_H_ +#include +#include +/*====================================================================== + * Be careful when changing this data structure. It has to be compatible + * in its first fields with the SICS object descriptor as defined in + * obdes.h in order to achieve backwards compatibility with old style + * SICS objects. + * =====================================================================*/ +typedef struct { + pObjectDescriptor pDes; + pHdb objectNode; + void *pPrivate; + void (*KillPrivate)(void *pPrivate); +}SICSOBJ, *pSICSOBJ; +/*-----------------------------------------------------------------------*/ +typedef int (*SICSOBJFunc)(pSICSOBJ self, SConnection *pCon, + pHdb commandNode, pHdb par[], int nPar); +/*======================= Live & Death =================================*/ +pSICSOBJ MakeSICSOBJ(char *name, char *class); +pSICSOBJ MakeSICSOBJv(char *name, char *class, int type, int priv); +void KillSICSOBJ(void *data); +void DefaultKill(void *data); + + +/** + * This creates a new SICS object and installs it in the interpreter. It returns + * the newly created SICS object such that the caller can continue + * configuring it. + */ +pSICSOBJ SetupSICSOBJ(SConnection *pCon,SicsInterp *pSics, void *pData, + int argc, char *argv[]); +/*====================== Interpreter Interface =========================== + * InvokeSICSObj is special in that it returns -1 if it cannot handle + * the command. This leaves calling code the opportunity to process + * further commands.It returns 1 on success and 0 on failures though. + * ------------------------------------------------------------------------*/ +int InvokeSICSOBJ(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]); +int InterInvokeSICSOBJ(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]); +int InstallSICSOBJ(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]); + + +#endif /*SICSOBJ2_H_*/ diff --git a/sicsstat.tcl b/sicsstat.tcl index 4dbf048e..c4461394 100644 --- a/sicsstat.tcl +++ b/sicsstat.tcl @@ -1,7 +1,60 @@ exe batchpath ./ exe syspath ./ +sample +sample setAccess 2 +title +title setAccess 2 +user +user setAccess 2 +email unknown +email setAccess 2 +address unknown +address setAccess 2 +fax unknown +fax setAccess 2 +phone unknown +phone setAccess 2 +# Motor som +som sign 1.000000 +som SoftZero 0.000000 +som SoftLowerLim -180.000000 +som SoftUpperLim 180.000000 +som Fixed -1.000000 +som InterruptMode 0.000000 +som precision 0.010000 +som ignorefault 0.000000 +som AccessCode 2.000000 +som failafter 3.000000 +som maxretry 3.000000 +som movecount 10.000000 +# Motor stt +stt sign 1.000000 +stt SoftZero 0.000000 +stt SoftLowerLim 0.000000 +stt SoftUpperLim 120.000000 +stt Fixed -1.000000 +stt InterruptMode 0.000000 +stt precision 0.010000 +stt ignorefault 0.000000 +stt AccessCode 2.000000 +stt failafter 3.000000 +stt maxretry 3.000000 +stt movecount 10.000000 +# Motor dth +dth sign 1.000000 +dth SoftZero 0.000000 +dth SoftLowerLim 0.000000 +dth SoftUpperLim 200.000000 +dth Fixed -1.000000 +dth InterruptMode 0.000000 +dth precision 0.010000 +dth ignorefault 0.000000 +dth AccessCode 2.000000 +dth failafter 3.000000 +dth maxretry 3.000000 +dth movecount 10.000000 # Counter counter -counter SetPreset 3.000000 +counter SetPreset 1000.000000 counter SetMode Timer hm CountMode timer hm preset 3.000000 diff --git a/simcter.c b/simcter.c index 9963c191..821cc0a4 100644 --- a/simcter.c +++ b/simcter.c @@ -259,7 +259,7 @@ static float FAILRATE; { for(i = 0; i < MAXCOUNT; i++) { - self->lCounts[i] = (long)rand(); + self->lCounts[i] = (long)(SimRandom()*100); } self->lCounts[1] = self->fPreset; return OKOK; @@ -272,7 +272,7 @@ static float FAILRATE; for(i = 0; i < MAXCOUNT; i++) { - self->lCounts[i] = (long)rand(); + self->lCounts[i] = (long)(SimRandom()*100); } self->lCounts[1] = self->fPreset; return OKOK; diff --git a/sinfox.c b/sinfox.c index 75cfc21e..e4c6b449 100644 --- a/sinfox.c +++ b/sinfox.c @@ -439,7 +439,7 @@ static int SinfoxList(pSinfox pSin, SicsInterp* pSics, SConnection *pCon, iRet = EnumChoice(pIFaces,iNumIFaces,objName); if(-1 < iRet) { - if((0==strcmp(keyName,"device")) || (0==strcmp(keyName,NULL))) + if((0==strcmp(keyName,"device")) || keyName == NULL ) { /* format as sinfox list server interface interfaceName */ setOKE(objName,keyName,eltName,"server","interface",objName); } else if(0==strcmp(keyName,"command")) diff --git a/site_ansto/instrument/hipd/config/motors/motor_configuration.tcl b/site_ansto/instrument/hipd/config/motors/motor_configuration.tcl index 77d23f9c..a23950c8 100644 --- a/site_ansto/instrument/hipd/config/motors/motor_configuration.tcl +++ b/site_ansto/instrument/hipd/config/motors/motor_configuration.tcl @@ -111,6 +111,28 @@ set move_count 10 #:TP at HOME # +# Dummy motor based on Monochromator phi, Tilt 1, upper +Motor dummy_motor asim [params \ + asyncqueue mc1\ + axis A\ + units degrees\ + hardlowerlim -169\ + hardupperlim 169\ + maxSpeed 1\ + maxAccel 1\ + maxDecel 1\ + stepsPerX -25000\ + absEnc 1\ + absEncHome $mphi_Home\ + cntsPerX -8192] +setHomeandRange -motor dummy_motor -home 0 -lowrange 169 -uprange 169 +dummy_motor speed 1 +dummy_motor movecount $move_count +dummy_motor precision 0.01 +dummy_motor part crystal +dummy_motor long_name dummy_motor + + # Monochromator phi, Tilt 1, upper Motor mphi $motor_driver_type [params \ asyncqueue mc1\ diff --git a/site_ansto/instrument/hrpd/config/hmm/hmm_configuration.tcl b/site_ansto/instrument/hrpd/config/hmm/hmm_configuration.tcl index 1c504bed..8d9cd12b 100644 --- a/site_ansto/instrument/hrpd/config/hmm/hmm_configuration.tcl +++ b/site_ansto/instrument/hrpd/config/hmm/hmm_configuration.tcl @@ -13,7 +13,7 @@ proc ::histogram_memory::init_OAT_TABLE {} { OAT_TABLE Y -setdata BMIN -0.5 OAT_TABLE Y -setdata BMAX 511.5 - OAT_TABLE -set X { 127.5 126.5 } NXC 128 Y { -0.5 3.5 } NYC 128 T { 0 100000 } NTC 1 + OAT_TABLE -set X { 127.5 126.5 } NXC 128 Y { -0.5 3.5 } NYC 128 T { 0 20000 } NTC 1 } message ] { if {$::errorCode=="NONE"} {return $message} return -code error $message diff --git a/site_ansto/instrument/reflectometer/config/motors/motor_configuration.tcl b/site_ansto/instrument/reflectometer/config/motors/motor_configuration.tcl index a8975634..32ca1ba8 100644 --- a/site_ansto/instrument/reflectometer/config/motors/motor_configuration.tcl +++ b/site_ansto/instrument/reflectometer/config/motors/motor_configuration.tcl @@ -200,6 +200,31 @@ set move_count 100 #:TP at HOME # +# Dummy motor based on Sample Tilt 1, upper (1 degree/turn) +Motor dummy_motor asim [params \ + asyncqueue mc2\ + axis A\ + units degrees\ + hardlowerlim -169\ + hardupperlim 169\ + maxSpeed 1\ + maxAccel 1\ + maxDecel 1\ + stepsPerX 25000\ + backlash_offset -0.25\ + absEnc 1\ + absEncHome $sth_home\ + cntsPerX 8192] +dummy_motor part sample +dummy_motor long_name dummy_motor +setHomeandRange -motor dummy_motor -home 0 -lowrange 169 -uprange 169 +dummy_motor speed 1 +dummy_motor backlash_offset -0.1 +dummy_motor creep_offset 0.05 +dummy_motor creep_precision 0.0005 +dummy_motor precision 0.001 + + # Beam Shade Vertical Translation (6mm/T double helix, 500mm) Motor bz $motor_driver_type [params \ asyncqueue mc1\ diff --git a/site_ansto/instrument/rsd/config/motors/motor_configuration.tcl b/site_ansto/instrument/rsd/config/motors/motor_configuration.tcl index a11e83cb..4e035627 100644 --- a/site_ansto/instrument/rsd/config/motors/motor_configuration.tcl +++ b/site_ansto/instrument/rsd/config/motors/motor_configuration.tcl @@ -120,6 +120,28 @@ set echi_Home 8919319 #:TP at HOME # :TP 7830625, 7492855, 7432174, 7894708, 28473827, 11465496, 0, 0 +# Dummy motor based on Monochromator phi, Tilt 1, upper +Motor dummy_motor asim [params \ + asyncqueue mc1\ + axis A\ + units degrees\ + hardlowerlim -169\ + hardupperlim 169\ + maxSpeed 1\ + maxAccel 1\ + maxDecel 1\ + stepsPerX 25000\ + absEnc 1\ + absEncHome $mphi_Home\ + cntsPerX 8192] +setHomeandRange -motor dummy_motor -home 0 -lowrange 169 uprange 169 +dummy_motor speed 1 +dummy_motor movecount $move_count +dummy_motor precision 0.01 +dummy_motor part crystal +dummy_motor long_name dummy_motor + + # Monochromator phi, Tilt 1, upper Motor mphi $motor_driver_type [params \ asyncqueue mc1\ diff --git a/site_ansto/instrument/util/extra_utility.tcl b/site_ansto/instrument/util/extra_utility.tcl index e0f89ab7..eb275246 100644 --- a/site_ansto/instrument/util/extra_utility.tcl +++ b/site_ansto/instrument/util/extra_utility.tcl @@ -63,9 +63,18 @@ proc errorInfowrite {args} { } } -trace add variable errorInfo write errorInfowrite -trace add execution catch enter entercatch -trace add execution catch leave leavecatch +proc callStack {enable} { + if {$enable} { + set trace_opt "add" + } else { + set trace_opt "remove" + } + trace $trace_opt variable errorInfo write errorInfowrite + trace $trace_opt execution catch enter entercatch + trace $trace_opt execution catch leave leavecatch +} +publish callStack mugger +callStack true # LIST FUNCTIONS diff --git a/site_ansto/instrument/util/utility.tcl b/site_ansto/instrument/util/utility.tcl index c1f1b5d9..70a5471d 100644 --- a/site_ansto/instrument/util/utility.tcl +++ b/site_ansto/instrument/util/utility.tcl @@ -1,7 +1,7 @@ # Some useful functions for SICS configuration. -# $Revision: 1.18 $ -# $Date: 2008-10-01 04:10:50 $ +# $Revision: 1.19 $ +# $Date: 2008-10-13 04:40:06 $ # Author: Ferdi Franceschini (ffr@ansto.gov.au) # Last revision by $Author: ffr $ @@ -512,7 +512,7 @@ proc ::utility::hgetplainprop {hpath prop} { } proc ::utility::hlistplainprop {hpath} { if [ catch { - return [string trim [join [split [hlistprop $hpath] =] ]] + return [string trim [join [split [string map {" " _} [hlistprop $hpath]] =] ]] } message ] { if {$::errorCode=="NONE"} {return $message} return -code error $message diff --git a/site_ansto/make_gen_variables b/site_ansto/make_gen_variables index 379f266b..dd0ffaff 100644 --- a/site_ansto/make_gen_variables +++ b/site_ansto/make_gen_variables @@ -1,33 +1,30 @@ # vim: ft=make ts=4 sw=4 noet cindent COBJ = Sclient.o network.o ifile.o intcli.o $(FORTIFYOBJ) -SOBJ = network.o ifile.o conman.o SCinter.o splitter.o passwd.o \ - servlog.o sicvar.o nserver.o SICSmain.o motorlist.o\ - sicsexit.o costa.o task.o $(FORTIFYOBJ) access.o\ - macro.o ofac.o obpar.o obdes.o drive.o status.o intserv.o \ - devexec.o mumo.o mumoconf.o selector.o selvar.o fupa.o lld.o \ - lld_blob.o strrepl.o lin2ang.o fomerge.o \ - script.o o2t.o alias.o napi.o napi5.o nxdata.o stringdict.o sdynar.o \ - histmem.o histdriv.o histsim.o interface.o callback.o nxio.o \ - event.o emon.o evcontroller.o evdriver.o simev.o perfmon.o \ - danu.o nxdict.o varlog.o stptok.o nread.o nwatch.o trigd.o cell.o\ - scan.o fitcenter.o telnet.o token.o wwildcard.o hklmot.o\ - tclev.o hkl.o integrate.o optimise.o dynstring.o nxutil.o \ - mesure.o uubuffer.o commandlog.o udpquieck.o fourtable.o\ - rmtrail.o help.o nxupdate.o confvirtualmot.o vector.o\ - simchop.o choco.o chadapter.o trim.o scaldate.o tasub.o\ - hklscan.o xytable.o exebuf.o exeman.o ubfour.o ubcalc.o\ - circular.o maximize.o sicscron.o scanvar.o tasublib.o\ - d_sign.o d_mod.o tcldrivable.o stdscan.o diffscan.o nxxml.o\ - synchronize.o definealias.o oscillate.o tasdrive.o \ - hmcontrol.o userscan.o rs232controller.o lomax.o tasscanub.o \ - fourlib.o motreg.o motreglist.o anticollider.o nxdataset.o \ - s_rnge.o sig_die.o gpibcontroller.o $(NIOBJ) mcreader.o mccontrol.o\ - hmdata.o nxscript.o tclintimpl.o sicsdata.o mcstascounter.o \ - mcstashm.o initializer.o remob.o tclmotdriv.o protocol.o \ - sinfox.o sicslist.o cone.o hipadaba.o sicshipadaba.o statistics.o \ - moregress.o hdbcommand.o multicounter.o regresscter.o histregress.o \ - sicshdbadapter.o polldriv.o sicspoll.o statemon.o \ - asyncqueue.o asyncprotocol.o +SOBJ = access.o alias.o anticollider.o ascon.o asyncprotocol.o asyncqueue.o callback.o \ + cell.o chadapter.o choco.o circular.o commandlog.o cone.o confvirtualmot.o \ + conman.o costa.o danu.o definealias.o devexec.o devser.o diffscan.o d_mod.o \ + drive.o d_sign.o dynstring.o emon.o errormsg.o evcontroller.o evdriver.o \ + event.o exebuf.o exeman.o fitcenter.o fomerge.o $(FORTIFYOBJ) fourlib.o \ + fourtable.o fupa.o genericcontroller.o gpibcontroller.o help.o hipadaba.o \ + histdriv.o histmem.o histregress.o histsim.o hklmot.o hkl.o hklscan.o \ + hmcontrol.o hmdata.o hmslave.o ifile.o initializer.o integrate.o interface.o \ + intserv.o lin2ang.o lld_blob.o lld.o logger.o logreader.o logsetup.o lomax.o \ + macro.o maximize.o mccontrol.o mcreader.o mcstascounter.o mcstashm.o mesure.o \ + moregress.o motorlist.o motreglist.o motreg.o multicounter.o mumoconf.o mumo.o \ + napi5.o napi.o network.o $(NIOBJ) nread.o nserver.o nwatch.o nxcopy.o nxdata.o \ + nxdataset.o nxdict.o nxinterhelper.o nxinter_wrap.o nxio.o nxscript.o nxstack.o \ + nxupdate.o nxutil.o nxxml.o o2t.o obdes.o obpar.o ofac.o optimise.o oscillate.o \ + passwd.o perfmon.o polldriv.o protocol.o proxy.o regresscter.o remob.o \ + rmtrail.o rs232controller.o savehdb.o scaldate.o scan.o scanvar.o SCinter.o \ + scriptcontext.o script.o sctdriveadapter.o sctdriveobj.o sdynar.o selector.o \ + selvar.o servlog.o sicscron.o sicsdata.o sicsexit.o sicshdbadapter.o \ + sicshdbfactory.o sicshipadaba.o sicslist.o SICSmain.o sicsobj.o sicspoll.o \ + sicvar.o sig_die.o simchop.o simev.o sinfox.o splitter.o s_rnge.o statemon.o \ + statistics.o statusfile.o status.o stdscan.o stptok.o stringdict.o strrepl.o \ + synchronize.o tasdrive.o task.o tasscanub.o tasublib.o tasub.o tcldrivable.o \ + tclev.o tclintimpl.o tclmotdriv.o telnet.o token.o trigd.o trim.o ubcalc.o \ + ubfour.o udpquieck.o userscan.o uubuffer.o varlog.o vector.o wwildcard.o \ + xytable.o # These are intermediate files generated from .tc files, marking # them as SECONDARY prevents make from removing them. diff --git a/site_ansto/motor_asim.c b/site_ansto/motor_asim.c index 0a2fae30..4fc3194c 100644 --- a/site_ansto/motor_asim.c +++ b/site_ansto/motor_asim.c @@ -664,6 +664,17 @@ int SimAction(SConnection *pCon, SicsInterp *pSics, void *pData, else if(strcasecmp("reset", argv[1]) == 0) { } else if(strcasecmp("state", argv[1]) == 0) { } else if(strcasecmp("trace", argv[1]) == 0) { } + else if(strcasecmp("thread0", argv[1]) == 0) { + char line[132]; + snprintf(line, 132, "%s.thread0 = %d", argv[0], 1); + SCWrite(pCon, line, eStatus); + return 1; + } else if(strcasecmp("posit", argv[1]) == 0) { + char line[132]; + snprintf(line, 132, "%s.posit = %f", argv[0], 1.0); + SCWrite(pCon, line, eStatus); + return 1; + } } return MotorAction(pCon, pSics, pData, argc, argv); } diff --git a/site_ansto/site_ansto.c b/site_ansto/site_ansto.c index b149b1d2..3702dc6a 100644 --- a/site_ansto/site_ansto.c +++ b/site_ansto/site_ansto.c @@ -20,6 +20,7 @@ #include #include +#include "protocol.h" /* site-specific driver header files */ #include "motor_dmc2280.h" #include "motor_asim.h" @@ -73,6 +74,7 @@ static void AddCommands(SicsInterp *pInter) NHQ200InitProtocol(pInter); ORHVPSInitProtocol(pInter); LS340InitProtocol(pInter); + AddCommand(pInter,"InstallProtocolHandler", InstallProtocol,NULL,NULL); AddCommand(pInter,"MakeTCPSelector",VelSelTcpFactory,NULL,NULL); AddCommand(pInter,"portnum",portNumCmd,NULL,NULL); AddCommand(pInter,"abortbatch",AbortBatch,NULL,NULL); diff --git a/sllinux_def b/sllinux_def index ea98bcdb..fdd1cc2a 100644 --- a/sllinux_def +++ b/sllinux_def @@ -6,7 +6,8 @@ #DFORTIFY= -DFORTIFY #FORTIFYOBJ= fortify.o strdup.o +DFORTIFY= -pg MFLAGS=-f makefile_linux$(DUMMY) -HDFROOT=/afs/psi.ch/project/sinq/sl-linux +HDFROOT=/afs/psi.ch/project/sinq/sl5 diff --git a/statemon.c b/statemon.c index cb56f00d..a2ff6ab0 100644 --- a/statemon.c +++ b/statemon.c @@ -154,24 +154,26 @@ static pHdb recurseInterestNode(pHdb current, char *pDevice){ */ alias = FindAliases(pServ->pSics,pSicsdev); pPtr = alias; - while((pPtr = stptok(pPtr,pAlias,131,",")) != NULL){ - if(strcmp(pAlias,pDevice) == 0){ - return current; - } - } - if(alias != NULL){ - free(alias); - } - } + if(pPtr != NULL){ + while((pPtr = stptok(pPtr,pAlias,131,",")) != NULL){ + if(strcmp(pAlias,pDevice) == 0){ + return current; + } + } + if(alias != NULL){ + free(alias); + } + } + } current = current->child; while(current != NULL){ - result = recurseInterestNode(current, pDevice); + result = recurseInterestNode(current, pDevice); if(result != NULL){ - return result; - } - current = current->next; - } - } + return result; + } + current = current->next; + } + } return NULL; } /*--------------------------------------------------------------------------*/ @@ -214,6 +216,9 @@ static int StateHdbInterest(int iEvent, void *pEvent, void *pUser, snprintf(buffer,1024,"%s FINISH", path); SCWriteInContext(pCon,buffer,eWarning,cc); } + if(path != NULL){ + free(path); + } } return 1; } @@ -350,7 +355,21 @@ int StateMonAction(SConnection *pCon, SicsInterp *pSics, void *pData, SCRegister(pCon,pSics, self->pCall,lID); SCSendOK(pCon); return 1; - } + } else if(strcmp(argv[1],"start") == 0) { + if(argc > 2){ + InvokeCallBack(self->pCall,STSTART,argv[2]); + SCSendOK(pCon); + return 1; + } + return 0; + } else if(strcmp(argv[1],"stop") == 0) { + if(argc > 2){ + InvokeCallBack(self->pCall,STEND,argv[2]); + SCSendOK(pCon); + return 1; + } + return 0; + } SCWrite(pCon,"ERROR: keyword not recognized",eError); return 0; diff --git a/status.c b/status.c index 2aaaca2e..b88b60ca 100644 --- a/status.c +++ b/status.c @@ -9,6 +9,9 @@ Updated in order to prevent status floods Mark Koennecke, July 2004 + + Reworked restore to keep parameters from uninitialized devices + Mark Koennecke, November 2007 Copyright: @@ -48,7 +51,7 @@ #include "sics.h" #include "status.h" #include "interrupt.h" -#include "devexec.h" +#include "sicshipadaba.h" #undef VALUECHANGE #define VALUECHANGE 2 @@ -197,13 +200,29 @@ SCPopContext(pCon); return 1; } - +/*------------------- The CallBack function for interest ------------------*/ + static int StatusHDBCallback(int iEvent, void *pEvent, void *pUser, + commandContext cc) + { + pHdb node = NULL; + hdbValue v; + + assert(pUser); + + node = (pHdb)pUser; + v = MakeHdbText(strdup(pText[eCode])); + if(node != NULL && iEvent == VALUECHANGE){ + UpdateHipadabaPar(node,v,NULL); + } + return 1; + } /*-----------------------------------------------------------------------*/ int UserStatus(SConnection *pCon, SicsInterp *pSics, void *pData, int argc, char *argv[]) { char pBueffel[512]; long lID; + pHdb node = NULL; assert(pSics); assert(pCon); @@ -221,12 +240,33 @@ if(strcmp(argv[1],"interest") == 0) { lID = RegisterCallback(pCall, SCGetContext(pCon), - VALUECHANGE, StatusCallback, + VALUECHANGE, StatusCallback, pCon, NULL); SCRegister(pCon,pSics, pCall,lID); SCSendOK(pCon); return 1; } + else if(strcmp(argv[1],"hdbinterest") == 0) + { + if(argc > 2){ + node = GetHipadabaNode(GetHipadabaRoot(),argv[2]); + if(node != NULL){ + lID = RegisterCallback(pCall, SCGetContext(pCon), + VALUECHANGE, StatusHDBCallback, + node, NULL); + /* SCRegister(pCon,pSics, pCall,lID); */ + SCSendOK(pCon); + return 1; + } else { + SCWrite(pCon,"ERROR: Hipadaba node not found",eError); + return 0; + } + } + } else { + SCWrite(pCon,"ERROR: require node parameter to register status callback", + eError); + return 0; + } } /* else just print value */ @@ -249,6 +289,7 @@ SetStatus(eEager); SetInterrupt(eContinue); ClearExecutor(GetExecutor()); + SCsetMacro(pCon,0); return 1; } /* ===================== Control Connection Management ====================*/ @@ -304,106 +345,3 @@ pOwner->pSock = pCon->pSock; return 1; } -/*---------------------------------------------------------------------*/ -static int motorSave = 0; -/*-----------------------------------------------------------------------*/ - int BackupStatus(SConnection *pCon, SicsInterp *pSics, void *pData, - int argc, char *argv[]) - { - int iRet; - char pBueffel[512]; - char *pFile = NULL; - - assert(pSics); - assert(pCon); - - if(argc < 2) - { - pFile = IFindOption(pSICSOptions,"statusfile"); - if(pFile) - { - iRet = WriteSicsStatus(pSics,pFile,motorSave); - } - else - { - SCWrite(pCon,"ERROR: No filename given for backup, Aborted.", - eError); - return 0; - } - } - else - { - if(strcmp(argv[1],"motorSave") == 0) - { - if(motorSave== 1) - motorSave= 0; - else - motorSave= 1; - sprintf(pBueffel,"New Value of motorSave= %d\n",motorSave); - SCWrite(pCon,pBueffel,eValue); - return 1; - } - else - { - iRet = WriteSicsStatus(pSics,argv[1],motorSave); - } - } - - if(!iRet) - { - sprintf(pBueffel,"ERROR: could not open file %s\n", argv[1]); - SCWrite(pCon,pBueffel,eError); - return 0; - } - SCSendOK(pCon); - return 1; - } -/*-----------------------------------------------------------------------*/ - int RestoreStatus(SConnection *pCon, SicsInterp *pSics, void *pData, - int argc, char *argv[]) - { - char pBueffel[512]; - int iRights; - int iRet; - char *pFile = NULL; - writeFunc oldWrite; - - assert(pSics); - assert(pCon); - - if(argc < 2) - { - pFile = IFindOption(pSICSOptions,"statusfile"); - if(pFile) - { - sprintf(pBueffel,"FileEval %s",pFile); - } - else - { - SCWrite(pCon,"ERROR: No filename given for backup, Aborted.", - eError); - return 0; - } - } - else - { - sprintf(pBueffel,"FileEval %s",argv[1]); - } - - iRights = SCGetRights(pCon); - pCon->iUserRights = usInternal; - oldWrite = SCGetWriteFunc(pCon); - SCSetWriteFunc(pCon,SCNotWrite); - iRet = InterpExecute(pSics,pCon,pBueffel); - SCSetWriteFunc(pCon,oldWrite); - pCon->iUserRights = iRights; - /* - if we do not override parameterChange here, the backup file - would be overwritten after each restore... Not the right thing - to do! - */ - pCon->parameterChange = 0; - SCSendOK(pCon); - return iRet; - } - diff --git a/status.h b/status.h index 1d9dca09..f80774da 100644 --- a/status.h +++ b/status.h @@ -50,11 +50,4 @@ int ResetStatus(SConnection *pCon, SicsInterp *pSics, void *pData, int argc, char *argv[]); - int BackupStatus(SConnection *pCon, SicsInterp *pSics, void *pData, - int argc, char *argv[]); - int RestoreStatus(SConnection *pCon, SicsInterp *pSics, void *pData, - int argc, char *argv[]); - - - #endif diff --git a/statusfile.c b/statusfile.c new file mode 100644 index 00000000..85371cbb --- /dev/null +++ b/statusfile.c @@ -0,0 +1,296 @@ +/*-------------------------------------------------------------------------- + + Handling of status files + + + Mark Koennecke, November 1996 + + Updated in order to prevent status floods + Mark Koennecke, July 2004 + + Reworked restore to keep parameters from uninitialized devices + Mark Koennecke, November 2007 + + 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 +#include +#include +#include "fortify.h" +#include +#include "sics.h" +#include "statusfile.h" +#include "lld_str.h" +#include "lld.h" +#include "exebuf.h" + +static int parameterChange = 0; +/*-----------------------------------------------------------------------*/ +int StatusFileTask(void *data) { + char *pFile = NULL; + + if (parameterChange) { + parameterChange = 0; + + assert(pServ->pSics); + pFile = IFindOption(pSICSOptions,"statusfile"); + if (pFile) { + WriteSicsStatus(pServ->pSics,pFile,0); + } + } + return 1; +} +/*---------------------------------------------------------------------*/ +static int motorSave = 0; +/*-----------------------------------------------------------------------*/ + int BackupStatus(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]) + { + int iRet; + char pBueffel[512]; + char *pFile = NULL; + + assert(pSics); + assert(pCon); + + if(argc < 2) + { + pFile = IFindOption(pSICSOptions,"statusfile"); + if(pFile) + { + iRet = WriteSicsStatus(pSics,pFile,motorSave); + } + else + { + SCWrite(pCon,"ERROR: No filename given for backup, Aborted.", + eError); + return 0; + } + } + else + { + if(strcmp(argv[1],"motorSave") == 0) + { + if(motorSave== 1) + motorSave= 0; + else + motorSave= 1; + sprintf(pBueffel,"New Value of motorSave= %d\n",motorSave); + SCWrite(pCon,pBueffel,eValue); + return 1; + } + else + { + iRet = WriteSicsStatus(pSics,argv[1],motorSave); + } + } + + if(!iRet) + { + sprintf(pBueffel,"ERROR: could not open file %s\n", argv[1]); + SCWrite(pCon,pBueffel,eError); + return 0; + } + SCSendOK(pCon); + return 1; + } +/*---------------------------------------------------------------------*/ +static int restoreOccurred = 0; +int hasRestored(){ + return restoreOccurred; +} +/*---------------------------------------------------------------------------*/ +typedef struct { + pObjectDescriptor pDes; + int errList; +}RestoreObj, *pRestoreObj; +/*---------------------------------------------------------------------------*/ +static void killRestore(void *data){ + pRestoreObj self = (pRestoreObj)data; + if(self == NULL){ + return; + } + if(self->errList >= 0){ + LLDdeleteBlob(self->errList); + } + if(self->pDes != NULL){ + DeleteDescriptor(self->pDes); + } + free(self); +} +/*--------------------------------------------------------------------------*/ +static int SaveRestore(void *obj, char *name, FILE *fd){ + int status; + char buffer[1024]; + + pRestoreObj self = (pRestoreObj)obj; + if(self == NULL){ + return 0; + } + fprintf(fd,"\n#--- BEGIN (commands producing errors on last restore)\n"); + status = LLDnodePtr2First(self->errList); + while(status == 1){ + LLDstringData(self->errList,buffer); + fprintf(fd,"%s", buffer); + status = LLDnodePtr2Next(self->errList); + } + fprintf(fd,"#--- END (commands producing errors on last restore)\n\n"); + return 1; +} +/*---------------------------------------------------------------------------*/ +int InstallBckRestore(SConnection *pCon, SicsInterp *pSics){ + pRestoreObj pNew = NULL; + + pNew = malloc(sizeof(RestoreObj)); + if(pNew == NULL){ + SCWrite(pCon,"ERROR: no memory to create restore object! This is SERIOUS!!!", + eError); + return 0; + } + pNew->pDes = CreateDescriptor("BckRestore"); + pNew->errList = LLDstringCreate(); + if(pNew->pDes == NULL || pNew->errList < 0){ + SCWrite(pCon,"ERROR: no memory to create restore object! This is SERIOUS!!!", + eError); + return 0; + } + pNew->pDes->SaveStatus = SaveRestore; + AddCommand(pSics,"Backup",BackupStatus,NULL,NULL); + AddCommand(pSics,"Restore",RestoreStatus,killRestore,pNew); + + return 1; +} +/*-----------------------------------------------------------------------*/ +static int listRestoreErr(pRestoreObj self, SConnection *pCon){ + char buffer[1024]; + int status; + pDynString data = NULL; + + SCStartBuffering(pCon); + status = LLDnodePtr2First(self->errList); + while(status == 1){ + LLDstringData(self->errList,buffer); + SCWrite(pCon,buffer,eValue); + status = LLDnodePtr2Next(self->errList); + } + data = SCEndBuffering(pCon); + if(data != NULL){ + SCWrite(pCon,GetCharArray(data),eValue); + } + return 1; +} +/*-----------------------------------------------------------------------*/ + int RestoreStatus(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]) + { + char pBueffel[512]; + int iRights; + int iRet; + char *pFile = NULL; + writeFunc oldWrite; + pExeBuf buffi = NULL; + pRestoreObj self = (pRestoreObj)pData; + + assert(pSics); + assert(pCon); + assert(self != NULL); + + if(argc < 2) + { + pFile = IFindOption(pSICSOptions,"statusfile"); + if(pFile) + { + sprintf(pBueffel,"%s",pFile); + } + else + { + SCWrite(pCon,"ERROR: No filename given for backup, Aborted.", + eError); + return 0; + } + } + else + { + if(strcasecmp(argv[1],"listerr") == 0){ + return listRestoreErr(self,pCon); + } else if(strcasecmp(argv[1],"killerr") == 0){ + if(self->errList >= 0){ + LLDdeleteBlob(self->errList); + } + self->errList = LLDstringCreate(); + StatusFileDirty(); + SCSendOK(pCon); + return 1; + } else { + sprintf(pBueffel,"%s",argv[1]); + } + } + + buffi = exeBufCreate("restore"); + if(buffi == NULL){ + SCWrite(pCon,"ERROR: failed to allocate buffer for restore",eError); + return 0; + } + iRet = exeBufLoad(buffi,pBueffel); + if(iRet != 1){ + exeBufDelete(buffi); + SCWrite(pCon,"ERROR: failed open status file",eError); + return 0; + } + LLDdeleteBlob(self->errList); + self->errList = LLDstringCreate(); + iRights = SCGetRights(pCon); + pCon->iUserRights = usInternal; + oldWrite = SCGetWriteFunc(pCon); + SCSetWriteFunc(pCon,SCNotWrite); + iRet = exeBufProcessErrList(buffi,pSics,pCon,self->errList); + restoreOccurred = 1; + SCSetWriteFunc(pCon,oldWrite); + pCon->iUserRights = iRights; + exeBufDelete(buffi); + /* + if we do not override parameterChange here, the backup file + would be overwritten after each restore... Not the right thing + to do! + */ + parameterChange = 0; + SCSendOK(pCon); + return iRet; + } +/*-----------------------------------------------------------------------*/ +void StatusFileDirty(void) { + parameterChange = 1; +} +/*-----------------------------------------------------------------------*/ +void StatusFileInit(void) { + TaskRegister(pServ->pTasker, StatusFileTask, NULL, NULL, NULL, 0); +} + diff --git a/statusfile.h b/statusfile.h new file mode 100644 index 00000000..39976d8b --- /dev/null +++ b/statusfile.h @@ -0,0 +1,24 @@ +/*-------------------------------------------------------------------------- + Status files + + Mark Koennecke, November 1996 + copyright: see implementation file +----------------------------------------------------------------------------*/ +#ifndef STATUSFILE_H +#define STATUSFILE_H + +#include + + int InstallBckRestore(SConnection *pCon, SicsInterp *pSics); + int BackupStatus(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]); + + int RestoreStatus(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]); + int hasRestored(); + + int StatusFileTask(void *data); /* saves status file if parameters have changed */ + + void StatusFileDirty(void); /* indicate that the status file has to be rewritten */ +#endif + diff --git a/stdscan.c b/stdscan.c index 6587b352..8013564b 100644 --- a/stdscan.c +++ b/stdscan.c @@ -610,7 +610,7 @@ int prepareDataFile(pScanData self){ char pBueffel[512]; /* allocate a new data file */ - pPtr = ScanMakeFileName(self->pSics,self->pCon); + pPtr = ScanMakeFileName(pServ->pSics,self->pCon); if(!pPtr) { SCWrite(self->pCon, @@ -637,7 +637,6 @@ int prepareDataFile(pScanData self){ char pMessage[1024]; assert(self); - assert(self->iNP > 0); assert(self->pCon); /* check boundaries of scan variables and allocate storage */ @@ -766,8 +765,8 @@ int prepareDataFile(pScanData self){ pVarEntry pVar = NULL; void *pDings; int i, iRet, status; - char pStatus[512], pItem[20]; - char pHead[512]; + char pStatus[2024], pItem[20]; + char pHead[2024]; float fVal; CountEntry sCount; @@ -821,8 +820,10 @@ int prepareDataFile(pScanData self){ strcat(pStatus,pItem); /* write progress */ - strcat(pHead,"\n"); - strcat(pStatus,"\n"); + /* + strcat(pHead,"\r\n"); + strcat(pStatus,"\r\n"); + */ SCWrite(self->pCon,pHead,eWarning); SCWrite(self->pCon,pStatus,eWarning); @@ -1124,6 +1125,10 @@ int StandardScanWrapper(SConnection *pCon, SicsInterp *pSics, void *pData, return 0; } + if(self->pCon == NULL){ + self->pCon = pCon; + } + if(strcmp(argv[1],"writeheader") == 0){ return WriteHeader(self); } else if(strcmp(argv[1],"prepare") == 0){ diff --git a/stptok.c b/stptok.c index e7da5a51..7000e83b 100644 --- a/stptok.c +++ b/stptok.c @@ -1,64 +1,64 @@ -/* -** stptok() -- public domain by Ray Gardner, modified by Bob Stout -** -** You pass this function a string to parse, a buffer to receive the -** "token" that gets scanned, the length of the buffer, and a string of -** "break" characters that stop the scan. It will copy the string into -** the buffer up to any of the break characters, or until the buffer is -** full, and will always leave the buffer null-terminated. It will -** return a pointer to the first non-breaking character after the one -** that stopped the scan. -*/ - -#include -#include - -char *stptok(const char *s, char *tok, size_t toklen, char *brk) -{ - char *lim, *b; - - if (!*s) - return NULL; - - lim = tok + toklen - 1; - while ( *s && tok < lim ) - { - for ( b = brk; *b; b++ ) - { - if ( *s == *b ) - { - *tok = 0; - return (char *)(s+1); - } - } - *tok++ = *s++; - } - *tok = 0; - return (char *)s; -} -/*---------------------------------------------------------------------------*/ - char *SkipSpace(char *pText) - { - char *pRes; - - pRes = pText; - while(*pRes) - { - if( (*pRes != ' ') && (*pRes != '\t') && (*pRes != '\r') ) - { - return pRes; - } - pRes++; - } - return NULL; - } - - - - - - - - - - +/* +** stptok() -- public domain by Ray Gardner, modified by Bob Stout +** +** You pass this function a string to parse, a buffer to receive the +** "token" that gets scanned, the length of the buffer, and a string of +** "break" characters that stop the scan. It will copy the string into +** the buffer up to any of the break characters, or until the buffer is +** full, and will always leave the buffer null-terminated. It will +** return a pointer to the first non-breaking character after the one +** that stopped the scan. +*/ + +#include +#include + +char *stptok(const char *s, char *tok, size_t toklen, char *brk) +{ + char *lim, *b; + + if (!*s) + return NULL; + + lim = tok + toklen - 1; + while ( *s && tok < lim ) + { + for ( b = brk; *b; b++ ) + { + if ( *s == *b ) + { + *tok = 0; + return (char *)(s+1); + } + } + *tok++ = *s++; + } + *tok = 0; + return (char *)s; +} +/*---------------------------------------------------------------------------*/ + char *SkipSpace(char *pText) + { + char *pRes; + + pRes = pText; + while(*pRes) + { + if( (*pRes != ' ') && (*pRes != '\t') && (*pRes != '\r') ) + { + return pRes; + } + pRes++; + } + return NULL; + } + + + + + + + + + + diff --git a/stringdict.c b/stringdict.c index 9cbf0c0a..16767163 100644 --- a/stringdict.c +++ b/stringdict.c @@ -174,11 +174,16 @@ { if(pResult == NULL) { - return strlen(sVal.value); + return strlen(sVal.value) + 1; /* for \0 */ } else { strncpy(pResult,sVal.value,iLen); + /* strncpy is not guaranteed to be '\0' terminated */ + if (iLen > 0 && pResult[iLen-1] != '\0') { + /* overflow */ + pResult[iLen-1] = '\0'; + } return 1; } } @@ -186,6 +191,24 @@ } return 0; } +/*--------------------------------------------------------------------------*/ + char *StringDictGetShort(pStringDict self, char *name) + { + SDE sVal; + int iRet; + + iRet = LLDnodePtr2First(self->iList); + while(iRet != 0) + { + LLDnodeDataTo(self->iList,&sVal); + if(strcmp(sVal.name,name) == 0) + { + return sVal.value; + } + iRet = LLDnodePtr2Next(self->iList); + } + return NULL; + } /*------------------------------------------------------------------------*/ int StringDictDelete(pStringDict self, char *name) { diff --git a/stringdict.h b/stringdict.h index 6a5d5d0c..9d20ce9b 100644 --- a/stringdict.h +++ b/stringdict.h @@ -25,6 +25,10 @@ int StringDictExists(pStringDict self, char *name); int StringDictUpdate(pStringDict self, char *name, char *value); int StringDictGet(pStringDict self, char *name, char *pResult, int iLen); + + /* the result of StringDictGetShort is only valid as long that the entry is not changed */ + char *StringDictGetShort(pStringDict self, char *name); + int StringDictGetAsNumber(pStringDict self, char *name, float *fVal); int StringDictDelete(pStringDict self, char *name); diff --git a/tasdrive.c b/tasdrive.c index 572f2e26..833bdd1c 100644 --- a/tasdrive.c +++ b/tasdrive.c @@ -4,6 +4,9 @@ copyright: see file COPYRIGHT Mark Koennecke, May 2005 + + In the long run it might be useful to switch all this to the more + general motor list driving code. --------------------------------------------------------------------*/ #include #include "sics.h" @@ -217,127 +220,106 @@ static float getMotorValue(pMotor mot, SConnection *pCon){ MotorGetSoftPosition(mot,pCon,&val); return val; -} +} +/*--------------------------------------------------------------------------*/ +static int startTASMotor(pMotor mot, SConnection *pCon, char *name, + double target, int silent){ + float val, fixed; + int status = OKOK; + char buffer[132]; + + val = getMotorValue(mot,pCon); + MotorGetPar(mot,"fixed",&fixed); + if(ABS(fixed - 1.0) < .1) { + snprintf(buffer,131,"WARNING: %s is FIXED", name); + SCWrite(pCon,buffer,eWarning); + return OKOK; + } + if(ABS(val - target) > MOTPREC){ + status = mot->pDrivInt->SetValue(mot,pCon,(float)target); + if(status != OKOK){ + return status; + } + } + writeMotPos(pCon,silent,name,val, target); + return status; +} /*---------------------------------------------------------------------------*/ static int startMotors(ptasMot self, tasAngles angles, SConnection *pCon, int driveQ, int driveTilt){ - float val; double curve; int status, silent; silent = self->math->silent; + self->math->mustRecalculate = 1; /* monochromator */ - val = getMotorValue(self->math->motors[A1],pCon); - if(ABS(val - angles.monochromator_two_theta/2.) > MOTPREC){ - status = self->math->motors[A1]->pDrivInt->SetValue(self->math->motors[A1], - pCon, - angles.monochromator_two_theta/2.); - if(status != OKOK){ - return status; - } + status = startTASMotor(self->math->motors[A1],pCon, "a1", + angles.monochromator_two_theta/2.,silent); + if(status != OKOK){ + return status; } - writeMotPos(pCon,silent,"a1",val, angles.monochromator_two_theta/2.); - - val = getMotorValue(self->math->motors[A2],pCon); - if(ABS(val - angles.monochromator_two_theta) > MOTPREC){ - status = self->math->motors[A2]->pDrivInt->SetValue(self->math->motors[A2], - pCon, - angles.monochromator_two_theta); - if(status != OKOK){ - return status; - } + status = startTASMotor(self->math->motors[A2],pCon, "a2", + angles.monochromator_two_theta,silent); + if(status != OKOK){ + return status; } - writeMotPos(pCon,silent,"a2",val, angles.monochromator_two_theta); - + if(self->math->motors[MCV] != NULL){ curve = maCalcVerticalCurvature(self->math->machine.monochromator, angles.monochromator_two_theta); - - val = getMotorValue(self->math->motors[MCV],pCon); - if(ABS(val - curve) > MOTPREC){ - status = self->math->motors[MCV]->pDrivInt->SetValue(self->math->motors[MCV], - pCon, - curve); - if(status != OKOK){ - return status; - } + status = startTASMotor(self->math->motors[MCV],pCon, "mcv", + curve,silent); + if(status != OKOK){ + return status; } - writeMotPos(pCon,silent,"mcv",val, curve); - } - + } + if(self->math->motors[MCH] != NULL){ curve = maCalcHorizontalCurvature(self->math->machine.monochromator, - angles.monochromator_two_theta); - - val = getMotorValue(self->math->motors[MCH],pCon); - if(ABS(val - curve) > MOTPREC){ - status = self->math->motors[MCH]->pDrivInt->SetValue(self->math->motors[MCH], - pCon, - curve); - if(status != OKOK){ - return status; - } + angles.monochromator_two_theta); + status = startTASMotor(self->math->motors[MCH],pCon, "mch", + curve,silent); + if(status != OKOK){ + return status; } - writeMotPos(pCon,silent,"mch",val, curve); } + /* analyzer */ if(self->math->tasMode != ELASTIC){ - val = getMotorValue(self->math->motors[A5],pCon); - if(ABS(val - angles.analyzer_two_theta/2.) > MOTPREC){ - status = self->math->motors[A5]->pDrivInt->SetValue(self->math->motors[A5], - pCon, - angles.analyzer_two_theta/2.); - if(status != OKOK){ - return status; - } - } - writeMotPos(pCon,silent,self->math->motors[A5]->name, - val, angles.analyzer_two_theta/2.); - - val = getMotorValue(self->math->motors[A6],pCon); - if(ABS(val - angles.analyzer_two_theta) > MOTPREC){ - status = self->math->motors[A6]->pDrivInt->SetValue(self->math->motors[A6], - pCon, - angles.analyzer_two_theta); - if(status != OKOK){ - return status; - } - } - writeMotPos(pCon,silent,"a6",val, angles.analyzer_two_theta); + status = startTASMotor(self->math->motors[A5],pCon, "a5", + angles.analyzer_two_theta/2.0,silent); + if(status != OKOK){ + return status; + } + status = startTASMotor(self->math->motors[A6],pCon, "a6", + angles.analyzer_two_theta,silent); + if(status != OKOK){ + return status; + } if(self->math->motors[ACV] != NULL){ curve = maCalcVerticalCurvature(self->math->machine.analyzer, angles.analyzer_two_theta); - val = getMotorValue(self->math->motors[ACV],pCon); - if(ABS(val - curve) > MOTPREC){ - status = self->math->motors[ACV]->pDrivInt->SetValue(self->math->motors[ACV], - pCon, - curve); - if(status != OKOK){ - return status; - } - } - writeMotPos(pCon,silent,"acv",val, curve); - } + status = startTASMotor(self->math->motors[ACV],pCon, "acv", + curve,silent); + if(status != OKOK){ + return status; + } + } if(self->math->motors[ACH] != NULL){ curve = maCalcHorizontalCurvature(self->math->machine.analyzer, angles.analyzer_two_theta); - val = getMotorValue(self->math->motors[ACH],pCon); - if(ABS(val - curve) > MOTPREC){ - status = self->math->motors[ACH]->pDrivInt->SetValue(self->math->motors[ACH], - pCon, - curve); - if(status != OKOK){ - return status; - } - } - writeMotPos(pCon,silent,"ach",val, curve); - } + status = startTASMotor(self->math->motors[ACH],pCon, "ach", + curve,silent); + if(status != OKOK){ + return status; + } + } } if(driveQ == 0){ @@ -347,50 +329,28 @@ static int startMotors(ptasMot self, tasAngles angles, /* crystal */ - val = getMotorValue(self->math->motors[A3],pCon); - if(ABS(val - angles.a3) > MOTPREC){ - status = self->math->motors[A3]->pDrivInt->SetValue(self->math->motors[A3], - pCon, - angles.a3); - if(status != OKOK){ - return status; - } + status = startTASMotor(self->math->motors[A3],pCon, "a3", + angles.a3,silent); + if(status != OKOK){ + return status; } - writeMotPos(pCon,silent,"a3",val, angles.a3); - - val = getMotorValue(self->math->motors[A4],pCon); - if(ABS(val - angles.sample_two_theta) > MOTPREC){ - status = self->math->motors[A4]->pDrivInt->SetValue(self->math->motors[A4], - pCon, - angles.sample_two_theta); - if(status != OKOK){ - return status; - } + status = startTASMotor(self->math->motors[A4],pCon, "a4", + angles.sample_two_theta,silent); + if(status != OKOK){ + return status; } - writeMotPos(pCon,silent,"a4",val, angles.sample_two_theta); - + if(driveTilt == 1){ - val = getMotorValue(self->math->motors[SGL],pCon); - if(ABS(val - angles.sgl) > MOTPREC){ - status = self->math->motors[SGL]->pDrivInt->SetValue(self->math->motors[SGL], - pCon, - angles.sgl); - if(status != OKOK){ - return status; - } - } - writeMotPos(pCon,silent,"sgl",val, angles.sgl); - - val = getMotorValue(self->math->motors[SGU],pCon); - if(ABS(val - angles.sgu) > MOTPREC){ - status = self->math->motors[SGU]->pDrivInt->SetValue(self->math->motors[SGU], - pCon, - angles.sgu); - if(status != OKOK){ - return status; - } - } - writeMotPos(pCon,silent,"sgu",val, angles.sgu); + status = startTASMotor(self->math->motors[SGL],pCon, "sgl", + angles.sgl,silent); + if(status != OKOK){ + return status; + } + status = startTASMotor(self->math->motors[SGU],pCon, "sgu", + angles.sgu,silent); + if(status != OKOK){ + return status; + } } self->math->mustDrive = 0; return OKOK; @@ -401,17 +361,21 @@ static int checkQMotorLimits(ptasMot self, SConnection *pCon, int status, retVal = 1; char error[131]; char pBueffel[256]; + float val; - status = self->math->motors[A3]->pDrivInt->CheckLimits(self->math->motors[A3], - angles.a3, - error, - 131); - if(status != 1) { - retVal = 0; - snprintf(pBueffel,256,"ERROR: limit violation an a3: %s", error); - SCWrite(pCon,pBueffel,eError); + MotorGetPar(self->math->motors[A3],"fixed",&val); + if((int)val != 1){ + status = self->math->motors[A3]->pDrivInt->CheckLimits(self->math->motors[A3], + angles.a3, + error, + 131); + if(status != 1) { + retVal = 0; + snprintf(pBueffel,256,"ERROR: limit violation an a3: %s", error); + SCWrite(pCon,pBueffel,eError); + } } - + status = self->math->motors[A4]->pDrivInt->CheckLimits(self->math->motors[A4], angles.sample_two_theta, error, @@ -512,13 +476,23 @@ static int calculateAndDrive(ptasMot self, SConnection *pCon){ /*-----------------------------------------------------------------------------*/ static int checkMotors(ptasMot self, SConnection *pCon){ int i, status, length = 12; + int mask[12]; self->math->mustRecalculate = 1; if(self->math->tasMode == ELASTIC){ length = 8; } + memset(mask,0,12*sizeof(int)); + for(i = 0; i < length; i++){ + mask[i] = 1; + } + if(self->math->outOfPlaneAllowed != 0){ + mask[SGU] = 0; + mask[SGL] = 0; + } + for(i = 0; i < 12; i++){ - if(self->math->motors[i] != NULL){ + if(self->math->motors[i] != NULL && mask[i] != 0){ status = self->math->motors[i]->pDrivInt->CheckStatus(self->math->motors[i], pCon); if(status != HWIdle && status != OKOK){ @@ -550,117 +524,86 @@ static int startQMMotors(ptasMot self, tasAngles angles, SConnection *pCon){ float val; double curve; - int status; + int status, silent; + silent = self->math->silent; /* monochromator */ - val = self->math->motors[A1]->pDrivInt->GetValue(self->math->motors[A1],pCon); - if(ABS(val - angles.monochromator_two_theta/2.) > MOTPREC){ - status = self->math->motors[A1]->pDrivInt->SetValue(self->math->motors[A1], - pCon, - angles.monochromator_two_theta/2.); - if(status != OKOK){ - return status; - } + status = startTASMotor(self->math->motors[A1],pCon, "a1", + angles.monochromator_two_theta/2.,silent); + if(status != OKOK){ + return status; } - val = self->math->motors[A2]->pDrivInt->GetValue(self->math->motors[A2],pCon); - if(ABS(val - angles.monochromator_two_theta) > MOTPREC){ - status = self->math->motors[A2]->pDrivInt->SetValue(self->math->motors[A2], - pCon, - angles.monochromator_two_theta); - if(status != OKOK){ - return status; - } + status = startTASMotor(self->math->motors[A2],pCon, "a2", + angles.monochromator_two_theta,silent); + if(status != OKOK){ + return status; } + if(self->math->motors[MCV] != NULL){ curve = maCalcVerticalCurvature(self->math->machine.monochromator, - angles.monochromator_two_theta); - val = self->math->motors[MCV]->pDrivInt->GetValue(self->math->motors[MCV],pCon); - if(ABS(val - curve) > MOTPREC){ - status = self->math->motors[MCV]->pDrivInt->SetValue(self->math->motors[MCV], - pCon, - curve); - if(status != OKOK){ - return status; - } + angles.monochromator_two_theta); + status = startTASMotor(self->math->motors[MCV],pCon, "mcv", + curve,silent); + if(status != OKOK){ + return status; } } + if(self->math->motors[MCH] != NULL){ curve = maCalcHorizontalCurvature(self->math->machine.monochromator, - angles.monochromator_two_theta); - val = self->math->motors[MCH]->pDrivInt->GetValue(self->math->motors[MCH],pCon); - if(ABS(val - curve) > MOTPREC){ - status = self->math->motors[MCH]->pDrivInt->SetValue(self->math->motors[MCH], - pCon, - curve); - if(status != OKOK){ - return status; - } + angles.monochromator_two_theta); + status = startTASMotor(self->math->motors[MCH],pCon, "mch", + curve,silent); + if(status != OKOK){ + return status; } } + /* analyzer */ - val = self->math->motors[A5]->pDrivInt->GetValue(self->math->motors[A5],pCon); - if(ABS(val - angles.analyzer_two_theta/2.) > MOTPREC){ - status = self->math->motors[A5]->pDrivInt->SetValue(self->math->motors[A5], - pCon, - angles.analyzer_two_theta/2.); + status = startTASMotor(self->math->motors[A5],pCon, "a5", + angles.analyzer_two_theta/2.0,silent); if(status != OKOK){ - return status; + return status; } - } - val = self->math->motors[A6]->pDrivInt->GetValue(self->math->motors[A6],pCon); - if(ABS(val - angles.analyzer_two_theta) > MOTPREC){ - status = self->math->motors[A6]->pDrivInt->SetValue(self->math->motors[A6], - pCon, - angles.analyzer_two_theta); + status = startTASMotor(self->math->motors[A6],pCon, "a6", + angles.analyzer_two_theta,silent); if(status != OKOK){ - return status; + return status; } - } - if(self->math->motors[ACV] != NULL){ - curve = maCalcVerticalCurvature(self->math->machine.analyzer, - angles.analyzer_two_theta); - val = self->math->motors[ACV]->pDrivInt->GetValue(self->math->motors[ACV],pCon); - if(ABS(val - curve) > MOTPREC){ - status = self->math->motors[ACV]->pDrivInt->SetValue(self->math->motors[ACV], - pCon, - curve); - if(status != OKOK){ - return status; - } + + if(self->math->motors[ACV] != NULL){ + curve = maCalcVerticalCurvature(self->math->machine.analyzer, + angles.analyzer_two_theta); + status = startTASMotor(self->math->motors[ACV],pCon, "acv", + curve,silent); + if(status != OKOK){ + return status; + } } - } - if(self->math->motors[ACH] != NULL){ - curve = maCalcHorizontalCurvature(self->math->machine.analyzer, - angles.analyzer_two_theta); - val = self->math->motors[ACH]->pDrivInt->GetValue(self->math->motors[ACH],pCon); - if(ABS(val - curve) > MOTPREC){ - status = self->math->motors[ACH]->pDrivInt->SetValue(self->math->motors[ACH], - pCon, - curve); - if(status != OKOK){ - return status; - } + if(self->math->motors[ACH] != NULL){ + curve = maCalcHorizontalCurvature(self->math->machine.analyzer, + angles.analyzer_two_theta); + status = startTASMotor(self->math->motors[ACH],pCon, "ach", + curve,silent); + if(status != OKOK){ + return status; + } } - } /* crystal */ - val = self->math->motors[A4]->pDrivInt->GetValue(self->math->motors[A4],pCon); - if(ABS(val - angles.sample_two_theta) > MOTPREC){ - status = self->math->motors[A4]->pDrivInt->SetValue(self->math->motors[A4], - pCon, - angles.sample_two_theta); - if(status != OKOK){ - return status; - } + status = startTASMotor(self->math->motors[A4],pCon, "a4", + angles.sample_two_theta,silent); + if(status != OKOK){ + return status; } - + self->math->mustDrive = 0; return OKOK; } diff --git a/task.c b/task.c index e41b99d7..177ebdaa 100644 --- a/task.c +++ b/task.c @@ -243,7 +243,8 @@ IncrTaskPointer(self); while(self->iStop == 0) { - if((self->pCurrent != pEnd) && (self->pCurrent->iStatus == READY)) + if((self->pCurrent != pEnd) && (self->pCurrent->iStatus == READY) + && self->pCurrent != NULL) /* omit ourselves! */ { iRet = self->pCurrent->pRun(self->pCurrent->pData); diff --git a/tasscanub.c b/tasscanub.c index 6be8bf4f..e8b8e24d 100644 --- a/tasscanub.c +++ b/tasscanub.c @@ -1023,7 +1023,7 @@ int TASUBPrepare(pScanData self) /*---------------------------------------------------------------------*/ static void TASUBDump(pTASdata self, SicsInterp *pSics, SConnection *pCon, int argc, char *argv[]){ - float v[3], ub[3][3], cell[6]; + float v[9], ub[3][3], cell[6]; int status, i, j; pNXScript nxscript = NULL; char pBueffel[256]; @@ -1083,7 +1083,13 @@ static void TASUBDump(pTASdata self, SicsInterp *pSics, SConnection *pCon, v[0] = r.qe.qh; v[1] = r.qe.qk; v[2] = r.qe.ql; - status = NXDputalias(nxscript->fileHandle,nxscript->dictHandle,pBueffel,v); + v[3] = r.angles.a3; + v[4] = r.angles.sample_two_theta; + v[5] = r.angles.sgl; + v[6] = r.angles.sgu; + v[7] = KtoEnergy(r.qe.ki); + v[8] = KtoEnergy(r.qe.kf); + status = NXDputalias(nxscript->fileHandle,nxscript->dictHandle,pBueffel,v); if(status != NX_OK){ snprintf(pBueffel,255,"ERROR: failed to write plane vector 1 to %s_vec1",argv[3]); SCWrite(pCon,pBueffel,eWarning); @@ -1093,6 +1099,12 @@ static void TASUBDump(pTASdata self, SicsInterp *pSics, SConnection *pCon, v[0] = r.qe.qh; v[1] = r.qe.qk; v[2] = r.qe.ql; + v[3] = r.angles.a3; + v[4] = r.angles.sample_two_theta; + v[5] = r.angles.sgl; + v[6] = r.angles.sgu; + v[7] = KtoEnergy(r.qe.ki); + v[8] = KtoEnergy(r.qe.kf); status = NXDputalias(nxscript->fileHandle,nxscript->dictHandle,pBueffel,v); if(status != NX_OK){ snprintf(pBueffel,255,"ERROR: failed to write plane vector 2 to %s_vec2",argv[3]); diff --git a/tasub.c b/tasub.c index 48b0ad0f..7822128d 100644 --- a/tasub.c +++ b/tasub.c @@ -227,6 +227,13 @@ static int testMotor(ptasUB pNew, SConnection *pCon, char *name, int idx){ return 1; } } +/*-------------------------------------------------------------------*/ +static void updateTargets(ptasUB pNew, SConnection *pCon){ + tasAngles ang; + + readTASAngles(pNew,pCon,&ang); + calcTasQEPosition(&pNew->machine, ang, &pNew->target); +} /*--------------------------------------------------------------------*/ int TasUBFactory(SConnection *pCon,SicsInterp *pSics, void *pData, int argc, char *argv[]){ @@ -303,7 +310,7 @@ int TasUBFactory(SConnection *pCon,SicsInterp *pSics, void *pData, SCWrite(pCon,"ERROR: a required motor is mssing, tasub NOT installed",eError); return 0; } - + status = AddCommand(pSics,argv[1], TasUBWrapper, KillTasUB, @@ -1151,7 +1158,7 @@ static int calcUBFromCell(ptasUB self, SConnection *pCon){ return 0; } if(mat_det(UB) < .000001){ - SCWrite(pCon,"ERROR: invalid UB matrix, check reflections",eError); + SCWrite(pCon,"ERROR: invalid UB matrix, check cell",eError); return 0; } if(self->machine.UB != NULL){ @@ -1438,6 +1445,21 @@ static int setUB(SConnection *pCon, SicsInterp *pSics, ptasUB self, return 1; } /*------------------------------------------------------------------*/ +static int getUB(SConnection *pCon, SicsInterp *pSics, ptasUB self, + int argc, char *argv[]){ + double value; + char pBueffel[512]; + int status; + + snprintf(pBueffel,511,"tasub.ub = %f %f %f %f %f %f %f %f %f", + self->machine.UB[0][0], self->machine.UB[0][1], self->machine.UB[0][2], + self->machine.UB[1][0], self->machine.UB[1][1], self->machine.UB[1][2], + self->machine.UB[2][0], self->machine.UB[2][1], self->machine.UB[2][2]); + SCWrite(pCon,pBueffel,eValue); + + return 1; +} +/*------------------------------------------------------------------*/ static int setNormal(SConnection *pCon, SicsInterp *pSics, ptasUB self, int argc, char *argv[]){ double value; @@ -1652,6 +1674,8 @@ int TasUBWrapper(SConnection *pCon,SicsInterp *pSics, void *pData, return calcQFromAngles(self,pCon,pSics,argc,argv); } else if(strcmp(argv[1],"setub") == 0){ return setUB(pCon,pSics,self,argc,argv); + } else if(strcmp(argv[1],"getub") == 0){ + return getUB(pCon,pSics,self,argc,argv); } else if(strcmp(argv[1],"setnormal") == 0){ return setNormal(pCon,pSics,self,argc,argv); } else if(strcmp(argv[1],"settarget") == 0){ @@ -1664,6 +1688,10 @@ int TasUBWrapper(SConnection *pCon,SicsInterp *pSics, void *pData, return readReflection(pCon,pSics,&self->r1,argc,argv); } else if(strcmp(argv[1],"r2") == 0){ return readReflection(pCon,pSics,&self->r2,argc,argv); + } else if(strcmp(argv[1],"updatetargets") == 0){ + updateTargets(self,pCon); + SCSendOK(pCon); + return 1; } else if(strcmp(argv[1],"const") == 0){ if(argc > 2){ strtolower(argv[2]); diff --git a/tcl/gumxml.tcl b/tcl/gumxml.tcl index c51065ef..bb9e538b 100644 --- a/tcl/gumxml.tcl +++ b/tcl/gumxml.tcl @@ -2,29 +2,55 @@ proc getdataType {path} { return [lindex [split [hinfo $path] ,] 0] } + proc make_nodes {path result indent} { set nodename [file tail $path]; set type [getdataType $path] set prefix [string repeat " " $indent] set newIndent [expr $indent + 2] +#array set prop_list [ string trim [join [split [hlistprop $path] =]] ] + set prop_list(control) true + set we_have_control [info exists prop_list(control)] + if {$we_have_control == 0 || $we_have_control && $prop_list(control) == "true"} { + append result "$prefix\n" + foreach p [property_elements $path $newIndent] { + append result $p + } + foreach x [hlist $path] { + set result [make_nodes [string map {// /} "$path/$x"] $result $newIndent] + } + append result "$prefix\n" + } + return $result +} - append result "$prefix\n" - foreach p [property_elements $path $newIndent] { - append result $p +proc property_elements_old {path indent} { + set prefix [string repeat " " $indent] + foreach {key value} [string map {= " "} [hlistprop $path]] { + if {[string compare -nocase $key "control"] == 0} {continue} + lappend proplist "$prefix\n" +# foreach v [split $value ,] { +# lappend proplist "$prefix$prefix$v\n" +# } + lappend proplist "$prefix$prefix$value\n" + lappend proplist "$prefix\n" } - foreach x [hlist $path] { - set result [make_nodes [string map {// /} "$path/$x"] $result $newIndent] - } - append result "$prefix\n" + if [info exists proplist] {return $proplist} } proc property_elements {path indent} { set prefix [string repeat " " $indent] - foreach {key value} [string map {= " "} [hlistprop $path]] { - lappend proplist "$prefix\n" - foreach v [split $value ,] { - lappend proplist "$prefix$prefix$v\n" + set data [hlistprop $path] + set propList [split $data \n] + foreach prop $propList { + set pl [split $prop =] + set key [string trim [lindex $pl 0]] + set value [string trim [lindex $pl 1]] + if {[string length $key] < 1} { + continue } + lappend proplist "$prefix\n" + lappend proplist "$prefix$prefix$value\n" lappend proplist "$prefix\n" } if [info exists proplist] {return $proplist} @@ -39,7 +65,10 @@ proc getgumtreexml {path} { set result [make_nodes $n $result 2] } } else { - set result [make_nodes $path $result 2] +# set result [make_nodes $path $result 2] + foreach n [hlist $path] { + set result [make_nodes $path/$n $result 2] + } } append result "\n" diff --git a/tcl/hdbutil.tcl b/tcl/hdbutil.tcl new file mode 100644 index 00000000..dde7e9fb --- /dev/null +++ b/tcl/hdbutil.tcl @@ -0,0 +1,690 @@ +#----------------------------------------------------------------------- +# This is a collection of utility procedures to help with Hipadaba and +# Gumtree Swiss Edition. This file is supposed to be sourced by any +# instrument using Hipadaba. +# +# Copyright: see file COPYRIGHT +# +# Collected from various files: Mark Koennecke, March 2008 +# +# Requirements: +# * the internal scan command xxxscan +# * scan data to live /graphics/scan_data +#---------------------------------------------------------------------- +if { [info exists hdbinit] == 0 } { + set hdbinit 1 + InstallHdb + MakeStateMon + Publish getgumtreexml Spy + if {[string first tmp $home] < 0} { + set tmppath $home/tmp + } else { + set tmppath $home + } + Publish mgbatch Spy + Publish loadmgbatch Spy + Publish hsearchprop Spy + Publish hdbscan User + Publish hdbprepare User + Publish hdbcollect User + Publish listbatchfiles Spy + Publish makemumopos User + Publish dropmumo User + Publish hdbbatchpath User +# Publish hmake Mugger +# Publish hmakescript Mugger +# Publish hlink Mugger +# Publish hcommand Mugger +} +#=================================================================== +# Configuration commands provided: +# hdbReadOnly +# makesampleenv path +# makestdscan path +# makestdscangraphics path +# makestdbatch +# makeQuickPar name path +# makeslit path left right upper lower +# configures a slit. Missing motors can be indicated with NONE +# makestdadmin +# makecount path +# makerepeat path +# makekillfile path +# makesuccess path +# makestdgui +# makewait path +# makeevproxy rootpath hdbname devicename +# makemumo rootpath mumoname +# makeexe +#===================== hfactory adapters ========================== +proc hmake {path priv type {len 1}} { + hfactory $path plain $priv $type $len +} +#-------------------------------------------------------------------- +proc hmakescript {path readscript writescript type {len 1}} { + hfactory $path script $readscript $writescript $type $len +} +#------------------------------------------------------------------- +proc hlink {path obj {treename NONE} } { + if {[string equal $treename NONE]} { + set treename $ob + } + append realpath $path / $treename + hfactory $realpath link $obj +} +#------------------------------------------------------------------- +proc hcommand {path script} { + hfactory $path command $script +} +#================ make XML tree ===================================== +proc getdataType {path} { + return [lindex [split [hinfo $path] ,] 0] +} +#---------------------------------------------------------------------- +proc make_nodes {path result indent} { +set nodename [file tail $path]; +set type [getdataType $path] +set prefix [string repeat " " $indent] +set newIndent [expr $indent + 2] +#array set prop_list [ string trim [join [split [hlistprop $path] =]] ] + set prop_list(control) true + set we_have_control [info exists prop_list(control)] + if {$we_have_control == 0 || $we_have_control && $prop_list(control) == "true"} { + append result "$prefix\n" + foreach p [property_elements $path $newIndent] { + append result $p + } + foreach x [hlist $path] { + set result [make_nodes [string map {// /} "$path/$x"] $result $newIndent] + } + append result "$prefix\n" + } + return $result +} +#------------------------------------------------------------------- +proc property_elements_old {path indent} { + set prefix [string repeat " " $indent] + foreach {key value} [string map {= " "} [hlistprop $path]] { + if {[string compare -nocase $key "control"] == 0} {continue} + lappend proplist "$prefix\n" +# foreach v [split $value ,] { +# lappend proplist "$prefix$prefix$v\n" +# } + lappend proplist "$prefix$prefix$value\n" + lappend proplist "$prefix\n" + } + if [info exists proplist] {return $proplist} +} +#----------------------------------------------------------------------- +proc property_elements {path indent} { + set prefix [string repeat " " $indent] + set data [hlistprop $path] + set propList [split $data \n] + foreach prop $propList { + set pl [split $prop =] + set key [string trim [lindex $pl 0]] + set value [string trim [lindex $pl 1]] + if {[string length $key] < 1} { + continue + } + lappend proplist "$prefix\n" + lappend proplist "$prefix$prefix$value\n" + lappend proplist "$prefix\n" + } + if [info exists proplist] {return $proplist} +} +#-------------------------------------------------------------------------- +proc getgumtreexml {path} { + append result "\n" + append result "\n" + + if {[string compare $path "/" ] == 0} { + foreach n [hlist $path] { + set result [make_nodes $n $result 2] + } + } else { +# set result [make_nodes $path $result 2] + foreach n [hlist $path] { + set result [make_nodes $path/$n $result 2] + } + } + + append result "\n" +} +#==================== Gumtree batch ========================================= +proc searchPathForDrivable {name} { + set path [string trim [hmatchprop / sicsdev $name]] + if {[string compare $path NONE] != 0} { + return $path + } + set txt [findalias $name] + if {[string compare $txt NONE] == 0} { + return NONE + } + set l1 [split $txt =] + set l [split [lindex $l1 1] ,] + foreach alias $l { + set alias [string trim $alias] + set path [string trim [hmatchprop / sicsdev $alias]] + if {[string compare $path NONE] != 0} { + return $path + } + } + return NONE +} +#---------------------------------------------------------------- +proc searchForCommand {name} { + return [string trim [hmatchprop / sicscommand $name]] +} +#---------------------------------------------------------------- +proc treatsscan {scanpath command out} { + set l [split $command] + set len [llength $l] + set noVar [expr ($len-2)/3] + set np [lindex $l [expr $len -2]] + set preset [lindex $l [expr $len -1]] + for {set i 0} {$i < $noVar} {incr i} { + set start [expr $i * 3] + set scanVar [lindex $l [expr 1 + $start]] + set scanStart [lindex $l [expr 2 + $start]] + set scanEnd [lindex $l [expr 3 + $start]] + set scanStep [expr ($scanEnd*1. - $scanStart*1.)/$np*1.] + append hdbVar $scanVar , + append hdbStart $scanStart , + append hdbStep $scanStep , + } + set hdbVar [string trim $hdbVar ,] + set hdbStart [string trim $hdbStart ,] + set hdbStep [string trim $hdbStep ,] + puts $out "\#NODE: $scanpath" + puts $out "clientput BatchPos = 1" + puts $out "hdbscan $hdbVar $hdbStart $hdbStep $np monitor $preset" +} +#---------------------------------------------------------------- +proc treatcscan {scanpath command out} { + set l [split $command] + set scanVar [lindex $l 1] + set scanCenter [lindex $l 2] + set scanStep [lindex $l 3] + set np [lindex $l 4] + set preset [lindex $l 5] + set hdbStart [expr $scanCenter - ($np*1.0)/2. * $scanStep*1.0] + puts $out "\#NODE: $scanpath" + puts $out "clientput BatchPos = 1" + puts $out "hdbscan $scanVar $hdbStart $scanStep $np monitor $preset" +} +#---------------------------------------------------------------- +proc translateCommand {command out} { + set drivelist [list drive dr run] + set textList [list for while source if] +# clientput "Translating: $command" + set command [string trim $command] + if {[string length $command] < 2} { + return + } + set l [split $command] + set obj [string trim [lindex $l 0]] +#------- check for drive commands + set idx [lsearch $drivelist $obj] + if {$idx >= 0} { + set dev [lindex $l 1] + set path [searchPathForDrivable $dev] + if {[string compare $path NONE] != 0} { + set realTxt [hgetprop $path sicsdev] + set realL [split $realTxt =] + set realDev [lindex $realL 1] + set mapList [list $dev $realDev] + set newCom [string map $mapList $command] + puts $out "\#NODE: $path" + puts $out "clientput BatchPos = 1" + puts $out $newCom + return + } + } +#------ check for well known broken commands + set idx [lsearch $textList $obj] + if {$idx >= 0} { + puts $out "\#NODE: /batch/commandtext" + puts $out "clientput BatchPos = 1" + set buffer [string map {\n @nl@} $command] + puts $out "hset /batch/commandtext $buffer" + return + } +#--------- check for simple commands + set path [searchForCommand $command] + if {[string compare $path NONE] != 0} { + puts $out "\#NODE: $path" + puts $out "clientput BatchPos = 1" + puts $out $command + return + } + set scancom [searchForCommand hdbscan] +#---------- deal with scans + if {[string first sscan $obj] >= 0} { + if {[catch {treatsscan $scancom $command $out}] == 0} { + return + } + } + if {[string first cscan $obj] >= 0} { + if {[catch {treatsscan $scancom $command $out}] == 0} { + return + } + } +#--------- give up: output as a text node + puts $out "\#NODE: /batch/commandtext" + puts $out "clientput BatchPos = 1" + set buffer [string map {\n @nl@} $command] + puts $out "hset /batch/commandtext $buffer" +} +#---------------------------------------------------------------- +proc mgbatch {filename} { + global tmppath + set f [open $filename r] + gets $f line + close $f + if {[string first MOUNTAINBATCH $line] > 0} { +#--------- This is a mountaingum batch file which does not need +# to be massaged + return $filename + } + set f [open $filename r] + set realfilename [file tail $filename] + set out [open $tmppath/$realfilename w] + puts $out \#MOUNTAINBATCH + while {[gets $f line] >= 0} { + append buffer $line + if {[info complete $buffer] == 1} { + translateCommand $buffer $out + unset buffer + } else { + append buffer \n + } + } + close $out + return $tmppath/$realfilename +} +#---------------------------------------------------------------- +proc loadmgbatch {filename} { + set txt [exe fullpath $filename] + set l [split $txt =] + set realf [lindex $l 1] + set realf [mgbatch $realf] + return [exe print $realf] +} +#============== hdbscan ========================================= +proc hdbscan {scanvars scanstart scanincr np mode preset} { + global stdscangraph hdbscanactive + xxxscan clear + xxxscan configure script + xxxscan function prepare hdbprepare + xxxscan function collect hdbcollect + set varlist [split $scanvars ,] + set startlist [split $scanstart ,] + set incrlist [split $scanincr ,] + hset $stdscangraph/scan_variable/name [lindex $varlist 0] + set count 0 + foreach var $varlist { + if {[string first / $var] >= 0} { + set var [string trim [SplitReply [hgetprop $var sicsdev]]] + } + xxxscan add $var [lindex $startlist $count] [lindex $incrlist $count] + incr count + } + set hdbscanactive 1 + set status [catch {xxxscan run $np $mode $preset} msg] + set hdbscanactive 0 + if {$status == 0} { + return $msg + } else { + error $msg + } +} +#------------------------------------------------------------------------------ +proc hdbprepare {obj userdata } { + global stdscangraph + stdscan prepare $obj userdata + hupdate $stdscangraph/dim +} +#------------------------------------------------------------------------------ +proc hdbcollect {obj userobj np} { + global stdscangraph + stdscan collect $obj $userobj $np + hupdate $stdscangraph/scan_variable + hupdate $stdscangraph/counts +} +#----------------------------------------------------------------------------- +proc gethdbscanvardata {no} { + set np [string trim [SplitReply [xxxscan np]]] + if {$np == 0} { + return ".0 .0 .0" + } + set status [catch {SplitReply [xxxscan getvardata $no]} txt] + if {$status == 0} { + return [join $txt] + } else { + return ".0 .0 .0" + } +} +#---------------------------------------------------------------------------- +proc gethdbscancounts {} { + set np [string trim [SplitReply [xxxscan np]]] + if {$np == 0} { + return "0 0 0" + } + set status [catch {SplitReply [xxxscan getcounts]} txt] + if {$status == 0} { + return [join $txt] + } else { + return "0 0 0" + } +} +#================= helper to get the list of batch files ================= +proc listbatchfiles {} { + set ext [list *.tcl *.job *.run] + set txt [SplitReply [exe batchpath]] + set dirlist [split $txt :] + set txt [SplitReply [exe syspath]] + set dirlist [concat $dirlist [split $txt :]] +# clientput $dirlist + set result [list ""] + foreach dir $dirlist { + foreach e $ext { + set status [catch {glob [string trim $dir]/$e} filetxt] + if {$status == 0} { + set filelist [split $filetxt] + foreach f $filelist { +# clientput "Working at $f" + set nam [file tail $f] + if { [lsearch $result $nam] < 0} { +# clientput "Adding $nam" + lappend result $nam + } + } + } else { +# clientput "ERROR: $filetxt" + } + } + } + foreach bf $result { + append resulttxt $bf , + } + return [string trim $resulttxt ,] +} +#------------------------------------------------------------------------- +proc hsearchprop {root prop val} { + set children [hlist $root] + set childlist [split $children \n] + if {[llength $childlist] <= 0} { + error "No children" + } + foreach child $childlist { + if {[string length $child] < 1} { + continue + } + catch {hgetprop $root/$child $prop} msg + if { [string first ERROR $msg] < 0} { + set value [string trim [SplitReply $msg]] + if { [string equal -nocase $value $val] == 1} { + return $root/$child + } + } + set status [catch {hsearchprop $root/$child $prop $val} node] + if {$status == 0} { + return $node + } + } + error "Not found" +} +#============ various utility routines ===================================== +proc hdbReadOnly {} { + error "Parameter is READ ONLY" +} +#--------------------------------------------------------------------------- +proc makesampleenv {path} { + hfactory $path plain spy none + hsetprop $path type graphdata + hsetprop $path viewer mountaingumui.TimeSeries + hfactory $path/vars plain user text + hset $path/vars tomato + hfactory $path/rank plain user int + hset $path/rank 1 + hfactory $path/dim plain user intar 1 + hset $path/dim 300 + hfactory $path/getdata plain user text + hsetprop $path/getdata type logcommand + hfactory $path/getdata/starttime plain spy text + hfactory $path/getdata/endtime plain spy text +} +#-------------------------------------------------- +proc makestdscan {path} { + hfactory $path command hdbscan + hsetprop $path type command + hsetprop $path viewer mountaingumui.ScanEditor + hsetprop $path priv user + hfactory $path/scan_variables plain user text + hsetprop $path/scan_variables argtype drivable + hfactory $path/scan_start plain user text + hfactory $path/scan_increments plain user text + hfactory $path/NP plain user int + hfactory $path/mode plain user text + hsetprop $path/mode values "monitor,timer" + hfactory $path/preset plain user float +} +#--------------------------------------------------- +proc makestdscangraphics {path} { + global stdscangraph + + set stdscangraph $path + + hfactory $path plain spy none + hsetprop $path type graphdata + hsetprop $path viewer default + hattach $path title title + hfactory $path/rank plain mugger int + hset $path/rank 1 + hsetprop $path/rank priv internal + hfactory $path/dim script "xxxscan np" hdbReadOnly intar 1 + hsetprop $path/dim priv internal + hfactory $path/scan_variable script "gethdbscanvardata 0" hdbReadOnly floatvarar 1 + hsetprop $path/scan_variable type axis + hsetprop $path/scan_variable dim 0 + hsetprop $path/scan_variable transfer zip + hsetprop $path/scan_variable priv internal + hfactory $path/scan_variable/name plain user text + hfactory $path/counts script "gethdbscancounts" hdbReadOnly intvarar 1 + hsetprop $path/counts type data + hsetprop $path/counts transfer zip + hsetprop $path/counts priv internal +} +#---------------------------------------------------- +proc makeQuickPar {name path} { + hfactory /quickview/$name plain mugger text + hset /quickview/$name $path +} +#--------------------------------------------------- +proc makestdbatch {} { + hfactory /batch plain spy none + hfactory /batch/bufferlist script listbatchfiles hdbReadOnly text + sicspoll add /batch/bufferlist hdb 30 + hfactory /batch/commandtext plain spy text + hsetprop /batch/commandtext viewer mountaingumui.TextEdit + hsetprop /batch/commandtext commandtext true + hfactory /batch/currentline plain user int +} +#----------------------------------------------------- +proc makeslit {path left right upper bottom} { + hfactory $path plain spy none + hsetprop $path type part + if {![string equal $left NONE]} { + hattach $path $left left + } + if {![string equal $right NONE]} { + hattach $path $right right + } + if {![string equal $upper NONE]} { + hattach $path $upper upper + } + if {![string equal $bottom NONE]} { + hattach $path $bottom bottom + } +} +#--------------------------------------------------------- +proc makestdadmin {} { + hfactory /instrument/experiment plain spy none + hattach /instrument/experiment title title + hattach /instrument/experiment user user + hattach /instrument/experiment/user adress address + hattach /instrument/experiment/user phone phone + hattach /instrument/experiment/user email email + hfactory /instrument/experiment/datafilenumber script sicsdatanumber \ + hdbReadOnly int + hsetprop /instrument/experiment/datafilenumber priv internal + hfactory /instrument/experiment/batchpath script "exe batchpath" \ + "exe batchpath" text + hsetprop /instrument/experiment/batchpath priv user +} +#---------------------------------------------------------- +proc makecount {path} { + hfactory $path command count + hsetprop $path type command + hsetprop $path priv user + hfactory $path/mode plain user text + hsetprop $path/mode values "monitor,timer" + hfactory $path/preset plain user float + hset $path/preset 60000 + hset $path/mode monitor +} +#---------------------------------------------------------- +proc makerepeat {path} { + hfactory $path command repeat + hsetprop $path type command + hsetprop $path priv user + hfactory $path/num plain user int + hfactory $path/mode plain user text + hsetprop $path/mode values "monitor,timer" + hfactory $path/preset plain user float + hset $path/preset 60000 + hset $path/mode monitor +} +#---------------------------------------------------------- +proc makekillfile {path} { + hcommand $path killfile + hsetprop $path type command + hsetprop $path priv manager +} +#---------------------------------------------------------- +proc makesuccess {path} { + hcommand $path success + hsetprop $path type command + hsetprop $path priv user +} +#----------------------------------------------------------- +proc makestdgui {} { + hfactory /gui plain spy none + hfactory /gui/status plain internal text + status hdbinterest /gui/status +} +#------------------------------------------------------------ +proc makewait {path} { + hfactory $path command wait + hsetprop $path type command + hsetprop $path priv user + hfactory $path/time plain user int +} +#------------------------------------------------------------ +proc makeevproxy {rootpath hdbname devicename} { + MakeProxy p${devicename} $devicename float + p${devicename} map upperlimit upperlimit float user + p${devicename} map lowerlimit lowerlimit float user + hlink $rootpath p${devicename} $hdbname + hsetprop $rootpath/$hdbname sicsdev $devicename + hsetprop $rootpath/$hdbname type drivable + sicspoll add $rootpath/$hdbname hdb 30 +} +#================== multi motor stuff ======================= +proc getNamposList {mumo} { + set txt [$mumo list] + set l [split $txt "\n"] + set lala [llength $l] + for {set i 1} {$i < [llength $l]} {incr i} { + set pos [lindex $l $i] + if {[string length $pos] > 1} { + append result [lindex $l $i] "," + } + } + if { ![info exists result] } { +# clientput "nampos = $txt" + append result UNKNOWN + } + return [string trimright $result ","] +} +#------------------------------------------------------------ +proc getNamPos {mumo} { + set txt [$mumo find] + set l [split $txt =] + return [string trim [lindex $l 1]] +} +#----------------------------------------------------------- +proc updateNamePosValues {rootpath} { + hupdate $rootpath/namedposition/values + hupdate $rootpath/dropnamedposition/name/values +} +#------------------------------------------------------------ +proc makemumopos {mumo rootpath name} { + $mumo pos $name + updateNamePosValues $rootpath +} +#----------------------------------------------------------- +proc dropmumo {mumo rootpath name} { + $mumo drop $name + updateNamePosValues $rootpath +} +#------------------------------------------------------------ +proc getDropList {mumo} { + set txt [getNamposList $mumo] + append txt ",all" + return $txt +} +#------------------------------------------------------------- +proc makemumo {rootpath mumoname} { + hfactory $rootpath/namedposition script "getNamPos $mumoname" \ + $mumoname text + hsetprop $rootpath/namedposition priv user + hfactory $rootpath/namedposition/values script \ + "getNamposList $mumoname" hdbReadOnly text + hsetprop $rootpath/namedposition/values visible false + hupdate $rootpath/namedposition/values + hfactory $rootpath/assignname2current command \ + "makemumopos $mumoname $rootpath" + hsetprop $rootpath/assignname2current priv user + hsetprop $rootpath/assignname2current type command + hfactory $rootpath/assignname2current/name plain user text + hset $rootpath/assignname2current/name "Undefined" + hfactory $rootpath/dropnamedposition command \ + "dropmumo $mumoname $rootpath" + hsetprop $rootpath/dropnamedposition priv user + hsetprop $rootpath/dropnamedposition type command + hfactory $rootpath/dropnamedposition/name plain user text + hfactory $rootpath/dropnamedposition/name/values script \ + "getDropList $mumoname" hdbReadOnly text + hsetprop $rootpath/dropnamedposition/name/values visible false + hupdate $rootpath/dropnamedposition/name/values +} +#----------------------------------------------------------------- +proc hdbbatchpath {pathstring} { + exe batchpath $pathstring + hupdate /instrument/commands/batch/execute/file/values +} +#------------------------------------------------------------------ +proc makeexe {} { + set path /instrument/commands/batch + hfactory $path plain spy none + hfactory $path/batchpath script "exe batchpath" hdbbatchpath text + hsetprop $path/batchpath priv user + hfactory $path/execute command exe + hsetprop $path/execute type command + hsetprop $path/execute priv user + hfactory $path/execute/file plain user text + hfactory $path/execute/file/values script listbatchfiles hdbReadOnly text + sicspoll add $path/execute/file/values hdb 60 +} diff --git a/tcl/sicstcldebug.tcl b/tcl/sicstcldebug.tcl index 9f6e4856..1139e8fc 100644 --- a/tcl/sicstcldebug.tcl +++ b/tcl/sicstcldebug.tcl @@ -7,20 +7,50 @@ # Thus is should be possible to debug SICS Tcl scripts in a normal # standalone interpreter without the overhead of restarting SICS # all the time. It may even be possible to use one of the normal -# Tcl debugfgers then.... +# Tcl debuggers then.... # # Mark Koennecke, February 2006 +# +# Revamped for use in testing SICS instruments. +# Mark Koennecke, November 2006 #------------------------------------------------------------------ - -set socke [socket localhost 2911] -gets $socke -puts $socke "Spy 007" -flush $socke -gets $socke +set host(amor) amor.psi.ch +set host(dmc) dmc.psi.ch +set host(focus) focus.psi.ch +set host(hrpt) hrpt.psi.ch +set host(mars) mars.psi.ch +set host(morpheus) morpheus.psi.ch +set host(narziss) narziss.psi.ch +set host(poldi) poldi.psi.ch +set host(rita2) rita2.psi.ch +set host(sans) sans.psi.ch +set host(sansli) sans2.psi.ch +set host(tasp) tasp.psi.ch +set host(trics) trics.psi.ch +set host(local) localhost + +#------------------------------------------------------------------- +# initialize the socket before debugging. If local == 1, then a +# connection to localhost is built #------------------------------------------------------------------ -proc unknown args { - global socke - append com "transact " [join $args] +proc initSicsDebug {instrument} { + global socke host + catch {close $socke} + set status [catch {set compi $host($instrument)} msg] + if {$status != 0} { + error "Host for $instrument not found" + } + set socke [socket $compi 2911] + gets $socke + puts $socke "Spy 007" + flush $socke + gets $socke +} +#---------------------------------------------------------------- +proc sicscommand args { + global socke + append com "transact " [join $args] + puts stdout "Sending: $com" puts $socke $com flush $socke set reply "" @@ -29,11 +59,16 @@ proc unknown args { if {[string first TRANSACTIONFINISHED $line] >= 0} { return $reply } else { - append reply $line + append reply $line "\n" } } } #------------------------------------------------------------------ +proc unknown args { + return [sicscommand $args] +} +#------------------------------------------------------------------ proc clientput args { puts stdout [join $args] } +#------------------------------------------------------------------ diff --git a/tclintimpl.c b/tclintimpl.c index ec3b16f5..3b340f25 100644 --- a/tclintimpl.c +++ b/tclintimpl.c @@ -136,13 +136,21 @@ int TclIntAction(SConnection *pCon, SicsInterp *pSics, void *pData, pTclInt self = NULL; char pBuffer[1024]; char *cmd; + float val; self = (pTclInt)pData; assert(self); if(argc < 2){ - sprintf(pBuffer,"ERROR: %s expects at least one argument!", argv[0]); - SCWrite(pCon,pBuffer,eError); - return 0; + if(self->pDriv->GetValue != NULL){ + val = self->pDriv->GetValue(self,pCon); + snprintf(pBuffer,1024,"%s = %f", argv[0], val); + SCWrite(pCon,pBuffer,eValue); + return 1; + } else { + sprintf(pBuffer,"ERROR: %s expects at least one argument!", argv[0]); + SCWrite(pCon,pBuffer,eError); + return 0; + } } strtolower(argv[1]); diff --git a/test/DataNumber b/test/DataNumber index 4556e033..75148a66 100644 --- a/test/DataNumber +++ b/test/DataNumber @@ -1,3 +1,3 @@ - 83 + 131 NEVER, EVER modify or delete this file You'll risk eternal damnation and a reincarnation as a cockroach!|n \ No newline at end of file diff --git a/test/sicsstat.tcl b/test/sicsstat.tcl index f9c6d419..01fca9a5 100644 --- a/test/sicsstat.tcl +++ b/test/sicsstat.tcl @@ -1,6 +1,10 @@ exe batchpath ./ exe syspath ./ -lotte Wuergehals was here + +#--- BEGIN (commands producing errors on last restore) +#--- END (commands producing errors on last restore) + +lotte UNKNOWN lotte setAccess 2 # Motor brumm brumm sign 1.000000 @@ -12,6 +16,8 @@ brumm InterruptMode 0.000000 brumm precision 0.010000 brumm ignorefault 0.000000 brumm AccessCode 2.000000 +brumm failafter 3.000000 +brumm maxretry 3.000000 brumm movecount 10.000000 # Motor miau miau sign 1.000000 @@ -23,9 +29,11 @@ miau InterruptMode 0.000000 miau precision 0.010000 miau ignorefault 0.000000 miau AccessCode 2.000000 +miau failafter 3.000000 +miau maxretry 3.000000 miau movecount 10.000000 # Counter aba -aba SetPreset 10.000000 +aba SetPreset 1000.000000 aba SetMode Timer # Counter hugo hugo SetPreset 1000.000000 @@ -46,6 +54,8 @@ a1 InterruptMode 0.000000 a1 precision 0.010000 a1 ignorefault 0.000000 a1 AccessCode 2.000000 +a1 failafter 3.000000 +a1 maxretry 3.000000 a1 movecount 10.000000 # Motor a2 a2 sign 1.000000 @@ -57,6 +67,8 @@ a2 InterruptMode 0.000000 a2 precision 0.010000 a2 ignorefault 0.000000 a2 AccessCode 2.000000 +a2 failafter 3.000000 +a2 maxretry 3.000000 a2 movecount 10.000000 # Motor a3 a3 sign 1.000000 @@ -68,6 +80,8 @@ a3 InterruptMode 0.000000 a3 precision 0.010000 a3 ignorefault 0.000000 a3 AccessCode 2.000000 +a3 failafter 3.000000 +a3 maxretry 3.000000 a3 movecount 10.000000 # Motor a4 a4 sign 1.000000 @@ -79,6 +93,8 @@ a4 InterruptMode 0.000000 a4 precision 0.010000 a4 ignorefault 0.000000 a4 AccessCode 2.000000 +a4 failafter 3.000000 +a4 maxretry 3.000000 a4 movecount 10.000000 # Motor a5 a5 sign 1.000000 @@ -90,6 +106,8 @@ a5 InterruptMode 0.000000 a5 precision 0.010000 a5 ignorefault 0.000000 a5 AccessCode 2.000000 +a5 failafter 3.000000 +a5 maxretry 3.000000 a5 movecount 10.000000 # Motor a6 a6 sign 1.000000 @@ -101,6 +119,8 @@ a6 InterruptMode 0.000000 a6 precision 0.010000 a6 ignorefault 0.000000 a6 AccessCode 2.000000 +a6 failafter 3.000000 +a6 maxretry 3.000000 a6 movecount 10.000000 # Motor sgu sgu sign 1.000000 @@ -112,6 +132,8 @@ sgu InterruptMode 0.000000 sgu precision 0.010000 sgu ignorefault 0.000000 sgu AccessCode 2.000000 +sgu failafter 3.000000 +sgu maxretry 3.000000 sgu movecount 10.000000 # Motor sgl sgl sign 1.000000 @@ -123,6 +145,8 @@ sgl InterruptMode 0.000000 sgl precision 0.010000 sgl ignorefault 0.000000 sgl AccessCode 2.000000 +sgl failafter 3.000000 +sgl maxretry 3.000000 sgl movecount 10.000000 # Counter scancter scancter SetPreset 0.000000 @@ -131,33 +155,31 @@ hm CountMode timer hm preset 10.000000 tof CountMode timer tof preset 10.000000 -tof genbin 500.000000 300.000000 20 +tof genbin 10.000000 12.000000 100 tof init #---- tasUB module tasub -tasub mono dd 3.354610 +tasub mono dd 3.350000 tasub mono hb1 1.000000 tasub mono hb2 1.000000 tasub mono vb1 1.000000 tasub mono vb2 1.000000 tasub mono ss 1 -tasub ana dd 3.354610 +tasub ana dd 3.350000 tasub ana hb1 1.000000 tasub ana hb2 1.000000 tasub ana vb1 1.000000 tasub ana vb2 1.000000 -tasub ana ss -1 -tasub cell 9.950000 9.950000 22.240000 90.000000 90.000000 90.000000 +tasub ana ss 1 +tasub cell 1.000000 1.000000 1.000000 90.000000 90.000000 90.000000 tasub clear -tasub addref 1.00 0.00 0.00 168.27 -23.46 0.00 0.00 5.00 5.00 -tasub addref 0.00 0.00 1.00 84.78 -10.44 0.00 0.00 5.00 5.00 tasub outofplane 1 -tasub const kf -tasub ss -1 - tasub setub -0.100503 -0.000000 -0.000000 0.000000 -0.000000 -0.044964 0.000000 -0.100503 -0.000000 - tasub setnormal 0.000000 0.000000 1.000000 -tasub settarget 1.200000 0.000000 1.000000 0.000000 1.553424 1.553424 -tasub r1 1.00 0.00 0.00 168.27 -23.46 0.00 0.00 5.00 5.00 -tasub r2 0.00 0.00 1.00 84.78 -10.44 0.00 0.00 5.00 5.00 +tasub const ki +tasub ss 1 + tasub setub 1.000000 0.000000 0.000000 0.000000 1.000000 0.000000 0.000000 0.000000 1.000000 + tasub setnormal 0.000000 0.000000 0.000000 +tasub settarget 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 +tasub r1 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 +tasub r2 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 tasub update #----- MultiMotor sa -sa recovernampos noeff a3 24 a4 48 +sa recovernampos noeff a3 24 a4 48 diff --git a/test/test.dic b/test/test.dic index 433bcee4..27f2dafa 100644 --- a/test/test.dic +++ b/test/test.dic @@ -10,7 +10,7 @@ testint=/entry1,NXentry/SDS testint -type NX_INT32 testmot=/entry1,NXentry/SDS position testmot_null=/entry1,NXentry/SDS position_zeropoint testcter_preset=/entry1,NXentry/control,NXmonitor/SDS preset -testcter_mode=/entry1,NXentry/control,NXmonitor/SDS mode -type NX_CHAR +testcter_mode=/entry1,NXentry/control,NXmonitor/SDS mode -type NX_CHAR -dim {132} testcter_time=/entry1,NXentry/control,NXmonitor/SDS time testcter_00=/entry1,NXentry/control,NXmonitor/SDS counts0 -type NX_INT32 testcter_01=/entry1,NXentry/control,NXmonitor/SDS counts1 -type NX_INT32 diff --git a/test/testini.tcl b/test/testini.tcl index be1af806..56c567c9 100644 --- a/test/testini.tcl +++ b/test/testini.tcl @@ -38,8 +38,8 @@ ServerOption InterruptPort 2913 # Syntax: SicsUser name password userRightsCode SicsUser Mugger Mugger 1 SicsUser User User 2 -SicsUser Spy Spy 3 -#SicsUser Spy 007 1 +#SicsUser Spy Spy 3 +SicsUser Spy 007 1 #----------------- SICS Variable VarMake lotte Text User @@ -196,3 +196,318 @@ hattach /instrument/detector hm data hattach /instrument lotte title restore + +#------------------------------------------------- +proc farmFormat {par num} { + hsetprop /sics/farm/$par lastError none + return [format "$par %d" [string trim $num]] +} +#----------------------------------------------- +proc farmRead {par } { + hsetprop /sics/farm/$par lastError none + hsetprop /sics/farm/$par replyCommand "farmReply $par" + return $par +} +#----------------------------------------------- +proc farmReply {par reply} { + set action [string trim [hgetpropval /sics/farm/$par status]] + hsetprop /sics/farm/$par status idle + if {[string first OK $reply] >= 0} { + if {[string first get $action] >= 0} { + set idx [string first : $reply] + if {$idx > 0} { + set val [string trim [string range $reply [expr $idx +1] end]] + hupdate /sics/farm/$par $val + } + } else { + hget /sics/farm/$par + } + } else { + if {[string first ERROR $reply] < 0} { + set reply "ERROR: $reply" + } + clientPut $reply + error $reply + } +} +#============================================= +proc schconset {val} { + set com [farmFormat schnegge $val] + hsetprop /sics/farm/schneggecon replyCommand schreply + return $com +} +#---------------------------------------------- +proc schreply {reply} { + clientput "schreply $reply" + if {[string first OK $reply] >= 0} { + hsetprop /sics/farm/schneggerunning readCommand schrunget + hget /sics/farm/schneggerunning + hsetprop /sics/farm/schneggerunning readCommand \ + "farmReply schneggerunning" + } else { + hsetprop /sics/farm/schneggecon status idle + hsetprop /sics/farm/schneggecon lastError $reply + clientput "ERROR: $reply on schnegge" + } +} +#----------------------------------------------- +proc schrun {reply} { + clientput "schrun $reply" + hsetprop /sics/farm/schneggerunning status idle + if {[string first OK $reply] >= 0} { + set idx [string first : $reply] + if {$idx > 0} { + set val [string trim [string range $reply [expr $idx +1] end]] + hupdate /sics/farm/schneggerunning $val + if {$val == 1} { + clientput "schnegge creeping" + hsetprop /sics/farm/schneggerunning readCommand schrunget + hget /sics/farm/schneggerunning + hsetprop /sics/farm/schneggerunning readCommand \ + "farmReply schneggerunning" + } else { + clientput "schnegge finished" + hsetprop /sics/farm/schneggerunning readCommand \ + "farmRead schneggerunning" + hsetprop /sics/farm/schneggecon status idle + } + } + } else { + clientput "schnegge has error: $reply" + hsetprop /sics/farm/schneggerunning readCommand \ + "farmRead schneggerunning" + hsetprop /sics/farm/schneggecon status idle + hsetprop /sics/farm/schneggecon lastError $reply + hsetprop /sics/farm/schneggerunning lastError $reply + } +} +#---------------------------------------------- +proc schget {} { + hsetprop /sics/farm/schneggecon lastError none + hsetprop /sics/farm/schneggecon replyCommand "farmReply schneggecon" + return schnegge +} +#---------------------------------------------- +proc schrunget {} { + hsetprop /sics/farm/schneggerunning lastError none + hsetprop /sics/farm/schneggerunning replyCommand schrun + return schneggerunning +} +#----------------------------------------------- +set farm 0 +if {$farm == 1} { +# Generic Controller +#------------------------------------------------------------------- +MakeAsyncProtocol norma +MakeAsyncQueue farmQueue norma localhost 9090 +MakeGenController farm +genconfigure asynconnect farm farmQueue +#------------------------------------------------ +genconfigure makepar farm hase int +hsetprop /sics/farm/hase priv user +hsetprop /sics/farm/hase writeCommand "farmFormat hase" +hsetprop /sics/farm/hase readCommand "farmRead hase" +hsetprop /sics/farm/hase replyCommand "farmReply hase" + +genconfigure makepar farm schnegge int +hsetprop /sics/farm/schnegge priv user +hsetprop /sics/farm/schnegge writeCommand "farmFormat schnegge" +hsetprop /sics/farm/schnegge readCommand "farmRead schnegge" +hsetprop /sics/farm/schnegge replyCommand "farmReply schnegge" + +genconfigure makepar farm schneggerunning int +hsetprop /sics/farm/schneggerunning priv internal +hsetprop /sics/farm/schneggerunning readCommand "farmRead schneggerunning" +hsetprop /sics/farm/schneggerunning replyCommand "farmReply schneggerunning" + +genconfigure makepar farm schneggecon int +hsetprop /sics/farm/schneggecon priv user +hsetprop /sics/farm/schneggecon writeCommand schconset +hsetprop /sics/farm/schneggecon readCommand schget +hsetprop /sics/farm/schneggecon replyCommand schreply +} + +set farm 0 + +if {$farm == 1} { +#-------------- Test new async protocol controller +makesctcontroller farmser std localhost:7070 +MakeSICSObj farm TestObj +#--------------------------- +proc farmparcom {par} { + sct send $par + return parread +} +#------------------------ +proc farmparread {} { + set rply [sct result] + if {[string first ERR $rply] >= 0} { + sct geterror $rply + return idle + } + set data [string range $rply 3 end] + set node [sct] + sct update $data + return idle +} +#-------------------------- +proc farmcheck {} { + set val [sct target] + if {$val < -100 || $val > 100} { + error "Value out of range" + } + return OK +} +#--------------------------- +proc farmset {par} { + set val [sct target] + sct send "$par $val" + return setreply +} +#------------------------- +proc farmsetreply {} { + set rply [sct result] + if {[string first ERR $rply] >= 0} { + sct print $rply + } + return idle +} +#-------------------------- +hfactory /sics/farm/hase plain spy int +hsetprop /sics/farm/hase read farmparcom hase +hsetprop /sics/farm/hase parread farmparread + +hsetprop /sics/farm/hase check farmcheck +hsetprop /sics/farm/hase write farmset hase +hsetprop /sics/farm/hase setreply farmsetreply + +farmser poll /sics/farm/hase +farmser write /sics/farm/hase + +hfactory /sics/farm/hugo plain spy int +hsetprop /sics/farm/hugo read farmparcom hugo +hsetprop /sics/farm/hugo parread farmparread + +hsetprop /sics/farm/hugo check farmcheck +hsetprop /sics/farm/hugo write farmset hugo +hsetprop /sics/farm/hugo setreply farmsetreply + +farmser poll /sics/farm/hugo +farmser write /sics/farm/hugo + +hfactory /sics/farm/schnegge plain spy float +hsetprop /sics/farm/schnegge read farmparcom schnegge +hsetprop /sics/farm/schnegge parread farmparread + +hsetprop /sics/farm/schnegge check farmcheck +hsetprop /sics/farm/schnegge write farmset schnegge +hsetprop /sics/farm/schnegge setreply farmsetreply + +farmser poll /sics/farm/schnegge +farmser write /sics/farm/schnegge + +hfactory /sics/farm/schneggerunning plain spy int +hsetprop /sics/farm/schneggerunning read farmparcom schneggerunning +hsetprop /sics/farm/schneggerunning parread farmparread +farmser poll /sics/farm/schneggerunning + +hfactory /sics/farm/stone plain spy int +hsetprop /sics/farm/stone read farmparcom stone +hsetprop /sics/farm/stone parread farmparread +#farmser poll /sics/farm/stone + +farmser debug -1 + +#----------------- drivable scriptcontext adapter +proc schneggechecklimits {} { + return [farmcheck] +} +#----------------------------- +proc schneggestatus {} { + farmser queue /sics/farm/schneggerunning progress read + set status [sct writestatus] + switch $status { + commandsent { + set runtime [SICSValue "hgetprop /sics/farm/schneggerunning read_time"] + set starttime [sct write_time] + if {$runtime > $starttime} { + sct writestatus evalcheck + } + return busy + } + evalcheck { + set tst [hval /sics/farm/schneggerunning] + if {$tst == 1} { + return busy + } else { + return idle + } + } + default { + error "schneggestatus called in bad state $status" + } + } +} +#--------------------------------------------- +hsetprop /sics/farm/schnegge checklimits schneggechecklimits +hsetprop /sics/farm/schnegge checkstatus schneggestatus +#makesctdrive schnecke /sics/farm/schnegge farmser +makesctdriveobj schnecke /sics/farm/schnegge DriveAdapter farmser + +} + +#---------- test http +set httptest 1 + +if {$httptest == 1} { +makesctcontroller amorhmsct sinqhttp amorhm data 180 spy 007 +#makesctcontroller amorhmsct sinqhttp localhost:8080 data 60 spy 007 +MakeSICSObj amorhm HttpTest +amorhmsct debug -1 +#------------------ +proc statget {} { + sct send "admin/textstatus.egi" + return statrepl +} +#----------------- +proc statreply {} { + sct update [sct result] + sct utime readtime + return idle +} +#----------------- +proc readcollapse {} { + sct send "admin/processhmdata.egi?bank=0&command=sum:2:0:400" + return colread +} +#----------------- +proc colreply {} { + sct utime readtime + set data [sct result] + return idle +} +#------------------------- +hfactory /sics/amorhm/status plain spy text +hsetprop /sics/amorhm/status read statget +hsetprop /sics/amorhm/status statrepl statreply +amorhmsct poll /sics/amorhm/status 10 + +hattach /sics/amorhm data intvarar collapse +hsetprop /sics/amorhm/collapse read readcollapse +hsetprop /sics/amorhm/collapse colread colreply +amorhmsct poll /sics/amorhm/collapse 20 + +} + +#source sansdruck.tcl + + +#MakeRS232Controller sadu pc4639 4168 +#MakeRS232Controller sadu localhost 4168 +#sadu replyterminator 0x04 +#sadu sendterminator 0x04 +#sadu timeout 1000 + +#source ../sim/mars/julcho.tcl + + diff --git a/test/testsics b/test/testsics index f3e2ea0b..5fabdb39 100755 --- a/test/testsics +++ b/test/testsics @@ -18,41 +18,41 @@ source testutil.tcl source sicstcldebug.tcl #--------------- Test Miscellaneous stuff -#source testmisc.tcl +source testmisc.tcl #-------------- Test for motors -#source mottest.tcl +source mottest.tcl #-------------- Test Counter set countername aba set errorname aba -#source countertest.tcl +source countertest.tcl #-------------- Test Multi Counter set countername multi -#source countertest.tcl +source countertest.tcl #-------------- Test batch processing -#source batchtest.tcl +source batchtest.tcl #-------------- Test scans -#source scantest.tcl +source scantest.tcl #------------ Test peak optimization -#source optitest.tcl +source optitest.tcl #----------- test histogram memory -#source histtest.tcl +source histtest.tcl #----------- test sics data -#source testsicsdata.tcl +source testsicsdata.tcl #----------- test nxscript source nxscripttest.tcl #------------ test SANS MultiMotor -#source testmumo.tcl +source testmumo.tcl #------------ print test summary cleanupTests