From b8fea0bc387be174ff0284bb0962d7414f68e2de Mon Sep 17 00:00:00 2001 From: koennecke Date: Wed, 16 Mar 2005 07:58:52 +0000 Subject: [PATCH] - Reworked mesure for four circle to new specifications * reworked table * added psd mode - exe now allows absolute paths - added getRS232Timeout to rs232controller - Fixed a couple of "guessed" return values --- conman.c | 12 +- diffscan.c | 3 + exeman.c | 17 +- fourtable.c | 106 +- fourtable.h | 1 + mesure.c | 203 +++- motor.c | 63 +- mumo.c | 4 +- nxdict.c | 3 +- nxdict.h | 1 + nxdict.w | 2537 --------------------------------------------- nxscript.c | 4 +- o2t.c | 2 +- rs232controller.c | 4 + rs232controller.h | 2 +- rs232controller.w | 2 +- 16 files changed, 331 insertions(+), 2633 deletions(-) delete mode 100644 nxdict.w diff --git a/conman.c b/conman.c index bdd07942..222a07e3 100644 --- a/conman.c +++ b/conman.c @@ -408,7 +408,10 @@ extern pServer pServ; } for(i = 0; i < pVictim->iFiles; i++) { - fclose(pVictim->pFiles[i]); + if(pVictim->pFiles[i] != NULL) + { + fclose(pVictim->pFiles[i]); + } } RemoveCommand(pServ->pSics,ConName(pVictim->ident)); @@ -1664,12 +1667,7 @@ static void writeToLogFiles(SConnection *self, char *buffer) } return 1; } -/*-------------------------------------------------------------------------- - The only command currently understood is: put args - writes the args to the client -*/ - - +/*--------------------------------------------------------------------------*/ int ConSicsAction(SConnection *pCon, SicsInterp *pSics, void *pData, int argc, char *argv[]) { diff --git a/diffscan.c b/diffscan.c index 604cbf65..597edb90 100644 --- a/diffscan.c +++ b/diffscan.c @@ -336,6 +336,9 @@ static int DiffScanTask(void *pData){ check for interrupt */ if(SCGetInterrupt(self->scanObject->pCon) >= eAbortScan){ + pCount->pDriv->Halt(pCount->pDriv); + pVar->pInter->Halt(pVar->pObject); + SicsWait(1); finish = 0; } diff --git a/exeman.c b/exeman.c index c29443a2..f26b4b91 100644 --- a/exeman.c +++ b/exeman.c @@ -139,6 +139,18 @@ static pDynString locateBatchBuffer(pExeMan self, char *name){ return NULL; } + /* + do not try to convert absolute paths + */ + if(name[0] == '/'){ + DynStringCopy(result,name); + if(fileExists(GetCharArray(result))){ + return result; + } else { + return NULL; + } + } + pPtr = self->batchPath; while((pPtr = stptok(pPtr,pPath,131,":")) != NULL){ DynStringCopy(result,pPath); @@ -540,7 +552,8 @@ static int infoHandler(pExeMan self, SConnection *pCon, return 1; } } - return 1; /* statement inserted, guessed return value M.Z. */ + SCWrite(pCon,"Nothing to execute",eValue); + return 1; } else { strtolower(argv[2]); if(strcmp(argv[2],"stack") == 0){ @@ -554,7 +567,7 @@ static int infoHandler(pExeMan self, SConnection *pCon, return 1; } else { SCWrite(pCon,"ERROR: subcommand to info unknown",eError); - return 0; /* statement inserted, guessed return value M.Z. */ + return 0; } } } diff --git a/fourtable.c b/fourtable.c index a5fe4bd0..d5624bf1 100644 --- a/fourtable.c +++ b/fourtable.c @@ -17,10 +17,10 @@ #include "fourtable.h" /*====================== table entry ===================================*/ typedef struct { - double twoThetaStart; double twoThetaEnd; - double step; char scanVar[30]; + double step; + int np; }FourTableEntry, *pFourTableEntry; /*==================== functions =======================================*/ int MakeFourCircleTable(){ @@ -51,8 +51,8 @@ static void printList(int handle, SConnection *pCon){ status = LLDnodePtr2First(handle); while(status == 1) { LLDnodeDataTo(handle,&entry); - snprintf(pBueffel,131,"%8.3f %8.3f %s %8.3f\n", entry.twoThetaStart, entry.twoThetaEnd, - entry.scanVar,entry.step); + snprintf(pBueffel,131,"%8.3f %s %8.3f %d\n", entry.twoThetaEnd, + entry.scanVar,entry.step, entry.np); Tcl_DStringAppend(&list,pBueffel,-1); printed = 1; status = LLDnodePtr2Next(handle); @@ -63,6 +63,58 @@ static void printList(int handle, SConnection *pCon){ SCWrite(pCon,Tcl_DStringValue(&list), eValue); Tcl_DStringFree(&list); } +/*--------------------------------------------------------------------- + Make sure that the entry is added in a sorted way according to two_theta + ----------------------------------------------------------------------*/ +static void insertEntry(int list, FourTableEntry newEntry){ + int status, count = 0, pos; + FourTableEntry test; + + /* + locate the last entry bigger then us + */ + status = LLDnodePtr2First(list); + while(status == 1){ + LLDnodeDataTo(list,&test); + count++; + if(test.twoThetaEnd == newEntry.twoThetaEnd){ + LLDnodeDataFrom(list,&newEntry); + return; + } + if(test.twoThetaEnd > newEntry.twoThetaEnd){ + break; + } + status = LLDnodePtr2Next(list); + } + /* + special case: empty list + */ + if(count == 0){ + LLDnodeAppendFrom(list,&newEntry); + return; + } + /* + special case: append after last + */ + LLDnodePtr2Last(list); + LLDnodeDataTo(list,&test); + if(newEntry.twoThetaEnd > test.twoThetaEnd){ + LLDnodeAppendFrom(list,&newEntry); + return; + } + + status = LLDnodePtr2First(list); + pos = 0; + while(status == 1){ + LLDnodeDataTo(list,&test); + pos++; + if(pos == count){ + LLDnodeInsertFrom(list,&newEntry); + return; + } + status = LLDnodePtr2Next(list); + } +} /*-----------------------------------------------------------------------*/ static int addToList(int handle, SConnection *pCon, int argc, char *argv[]){ FourTableEntry entry; @@ -74,29 +126,33 @@ static int addToList(int handle, SConnection *pCon, int argc, char *argv[]){ } if(isNumeric(argv[3])){ - entry.twoThetaStart = atof(argv[3]); + entry.twoThetaEnd = atof(argv[3]); } else { snprintf(pBueffel,131,"ERROR: expected numeric argument, received %s", argv[3]); SCWrite(pCon,pBueffel,eError); return 0; } - if(isNumeric(argv[4])){ - entry.twoThetaEnd = atof(argv[4]); + strncpy(entry.scanVar,argv[4],29); + strtolower(entry.scanVar); + if(strcmp(entry.scanVar,"om") != 0 && strcmp(entry.scanVar,"o2t") != 0){ + SCWrite(pCon,"ERROR: Invalied scan variable specified, only om, o2t allowed",eError); + return 0; + } + if(isNumeric(argv[5])){ + entry.step = atof(argv[5]); } else { snprintf(pBueffel,131,"ERROR: expected numeric argument, received %s", argv[4]); SCWrite(pCon,pBueffel,eError); return 0; } - strncpy(entry.scanVar,argv[5],29); if(isNumeric(argv[6])){ - entry.step = atof(argv[6]); + entry.np = atoi(argv[6]); } else { snprintf(pBueffel,131,"ERROR: expected numeric argument, received %s", argv[6]); SCWrite(pCon,pBueffel,eError); return 0; } - LLDnodePrependFrom(handle,&entry); - + insertEntry(handle,entry); return 1; } /*-----------------------------------------------------------------------*/ @@ -141,6 +197,7 @@ int HandleFourCircleCommands(int handle, SConnection *pCon, return 1; } clearTable(handle); + SCparChange(pCon); SCSendOK(pCon); } else if (strcmp(argv[2],"list") == 0){ printList(handle,pCon); @@ -152,6 +209,7 @@ int HandleFourCircleCommands(int handle, SConnection *pCon, *err = addToList(handle,pCon,argc,argv); if(*err != 0) { + SCparChange(pCon); SCSendOK(pCon); } } else if(strcmp(argv[2],"del") == 0){ @@ -165,6 +223,7 @@ int HandleFourCircleCommands(int handle, SConnection *pCon, } else { if(isNumeric(argv[3])){ delEntry(handle, atoi(argv[3])); + SCparChange(pCon); SCSendOK(pCon); } else { SCWrite(pCon,"ERROR: bad argument: expected numeric argument to table del",eError); @@ -181,15 +240,17 @@ int HandleFourCircleCommands(int handle, SConnection *pCon, /*-----------------------------------------------------------------------*/ static FourTableEntry findEntry(int handle, double two_theta){ int status; - FourTableEntry entry; + FourTableEntry entry, prevEntry; status = LLDnodePtr2First(handle); + LLDnodeDataTo(handle,&prevEntry); while(status == 1) { LLDnodeDataTo(handle,&entry); - if(two_theta > entry.twoThetaStart && two_theta <= entry.twoThetaEnd){ - return entry; + if(entry.twoThetaEnd > two_theta){ + return prevEntry; } status = LLDnodePtr2Next(handle); + prevEntry = entry; } strcpy(entry.scanVar,"NOT FOUND"); return entry; @@ -213,6 +274,17 @@ double GetFourCircleStep(int handle, double two_theta){ } } /*------------------------------------------------------------------------*/ +int GetFourCircleScanNP(int handle, double two_theta){ + FourTableEntry entry; + + entry = findEntry(handle,two_theta); + if(strcmp(entry.scanVar,"NOT FOUND") == 0){ + return -999; + } else { + return entry.np; + } +} +/*------------------------------------------------------------------------*/ int SaveFourCircleTable(int handle, char *objName, FILE *fd){ FourTableEntry entry; int status; @@ -221,9 +293,9 @@ int SaveFourCircleTable(int handle, char *objName, FILE *fd){ status = LLDnodePtr2Last(handle); while(status != 0) { LLDnodeDataTo(handle,&entry); - fprintf(fd,"%s table add %f %f %s %f\n",objName, - entry.twoThetaStart, entry.twoThetaEnd,entry.scanVar, - entry.step); + fprintf(fd,"%s table add %f %s %f %d\n",objName, + entry.twoThetaEnd,entry.scanVar, + entry.step,entry.np); status = LLDnodePtr2Prev(handle); } return 1; diff --git a/fourtable.h b/fourtable.h index 6824728a..e1a787d3 100644 --- a/fourtable.h +++ b/fourtable.h @@ -16,6 +16,7 @@ int HandleFourCircleCommands(int handle, SConnection *pCon, int argc, char *argv[], int *err); char *GetFourCircleScanVar(int handle, double two_theta); + int GetFourCircleScanNP(int handle, double two_theta); double GetFourCircleStep(int handle, double two_theta); int SaveFourCircleTable(int handle, char *objName, FILE *fd); diff --git a/mesure.c b/mesure.c index 493431af..1ff4b413 100644 --- a/mesure.c +++ b/mesure.c @@ -74,6 +74,7 @@ remeasured */ int fastScan; /* flag for using fastscans for scanning reflections */ int psiMode; /* 1 for psi scan mode, 0 else */ + int psd; /* a flag for making 2D detector scans */ int stepTable; /* mapping of two theta ranges to step width and variable to scan */ } Mesure; @@ -96,6 +97,7 @@ static int SaveMesure(void *pData, char *name, FILE *fd) fprintf(fd,"%s step %f\n", name, self->fStep); fprintf(fd,"%s weakthreshold %ld\n", name, self->weakThreshold); fprintf(fd,"%s compact %d\n", name, self->iCompact); + fprintf(fd,"%s psd %d\n", name, self->psd); fprintf(fd,"%s weak %d\n", name, self->weak); fprintf(fd,"%s fastscan %d\n", name, self->fastScan); SaveFourCircleTable(self->stepTable,name,fd); @@ -127,6 +129,8 @@ static void ListMesure(pMesure self, char *name, SConnection *pCon) Tcl_DStringAppend(&list,pBuffer,-1); snprintf(pBuffer,131,"%s.compact %d\n", name, self->iCompact); Tcl_DStringAppend(&list,pBuffer,-1); + snprintf(pBuffer,131,"%s.psd %d\n", name, self->psd); + Tcl_DStringAppend(&list,pBuffer,-1); snprintf(pBuffer,131,"%s.weak %d\n", name, self->weak); Tcl_DStringAppend(&list,pBuffer,-1); snprintf(pBuffer,131,"%s.fastscan %d\n", name, self->fastScan); @@ -177,7 +181,8 @@ static void ListMesure(pMesure self, char *name, SConnection *pCon) pNew->fStep = 0.05; pNew->fPreset = 2; pNew->iCompact = 1; - pNew->weak = 0; + pNew->psd = 0; + pNew->weak = 0; pNew->weakThreshold = 99999; pNew->fastScan = 0; pNew->psiMode = 0; @@ -395,6 +400,16 @@ static void ListMesure(pMesure self, char *name, SConnection *pCon) return 1; } +/*------------------------------------------------------------------------*/ +static int getMesureNP(pMesure self, double twoTheta) +{ + int np; + np = GetFourCircleScanNP(self->stepTable,twoTheta); + if(np < -800){ + np = self->np; + } + return np; +} /*------------------------------------------------------------------------- This is slightly tricky: the crystallography module has a scan tolerance. This is supposed to be automatically set. In order to do so, I need @@ -406,7 +421,7 @@ static void ListMesure(pMesure self, char *name, SConnection *pCon) static int MesureCalculateSettings(pMesure self, float fHKL[3], float fSet[4], float fPsi, SConnection *pCon) { - int status; + int status, np; float step, tolerance; SetHKLScanTolerance(self->pCryst,.0); @@ -419,7 +434,8 @@ static int MesureCalculateSettings(pMesure self, float fHKL[3], float fSet[4], if(step < -900.){ step = self->fStep; } - tolerance = (step * (float)self->np)/2. + .2; + np = getMesureNP(self,(double)fSet[0]); + tolerance = (step * (float)np)/2. + .2; SetHKLScanTolerance(self->pCryst,tolerance); return CalculateSettings(self->pCryst,fHKL,fPsi,0,fSet,pCon); } @@ -481,19 +497,21 @@ static int DriveToReflection(pMesure self, float fSet[4], SConnection *pCon) /*----------------------------------------------------------------------- test if this scan has to be remeasured because it is weak ------------------------------------------------------------------------*/ -int weakScan(pMesure self) +int weakScan(pMesure self, double twoTheta) { - int i; + int i, np; long low = 99999, high = -99999; /* - ths scan is always OK if we do not test for weak conditions + the scan is always OK if we do not test for weak conditions or we are in psd mode */ - if(self->weak == 0){ + if(self->weak == 0 || self->psd == 1){ return 0; } - GetScanCounts(self->pScanner,self->lCounts,self->np); - for(i = 0; i < self->np; i++) + + np = getMesureNP(self,twoTheta); + GetScanCounts(self->pScanner,self->lCounts,np); + for(i = 0; i < np; i++) { if(self->lCounts[i] < low) { @@ -517,11 +535,43 @@ int weakScan(pMesure self) return 1; } } +/*-----------------------------------------------------------------------*/ +static int PerformPSDScan(pMesure self, char *scanVar, float fStart, float step, int np) +{ + int status; + char pCommand[1024]; + char countMode[20]; + Tcl_Interp *pTcl; + + /* + PSD scans are done by calling the routine Tcl procedure tricsscan with the + appropriate parameters. tricsscan does only omega scans! + */ + if(self->CountMode == eTimer) + { + strcpy(countMode,"timer"); + } + else + { + strcpy(countMode,"monitor"); + } + snprintf(pCommand,1023,"tricsscan %f %f %d %s %f", fStart, step, np,countMode,self->fPreset); + pTcl = InterpGetTcl(pServ->pSics); + status = Tcl_Eval(pTcl,pCommand); + if(status != TCL_OK) + { + return 0; + } + else + { + return 1; + } +} /*------------------------------------------------------------------------*/ static int ScanReflection(pMesure self, float twoTheta, SConnection *pCon) { float fStart, stepWidth; - int iRet; + int iRet, np; char pBueffel[132]; char *scanVar = NULL; @@ -540,21 +590,54 @@ static int ScanReflection(pMesure self, float twoTheta, SConnection *pCon) } else { stepWidth = GetFourCircleStep(self->stepTable,(double)twoTheta); } + np = getMesureNP(self,(double)twoTheta); if(stepWidth != self->fStep) { - snprintf(pBueffel,130,"Using stepwidth %f",stepWidth); + snprintf(pBueffel,130,"Using stepwidth %f, %d points",stepWidth,np); SCWrite(pCon,pBueffel,eWarning); } - fStart -= (self->np/2)*stepWidth; + fStart -= (np/2)*stepWidth; - /* set the scan up */ + /* + spcial case: psd mode + */ + if(self->psd == 1) + { + iRet = PerformPSDScan(self,scanVar,fStart, stepWidth, np); + free(scanVar); + return iRet; + } + + /* + below is the code for a single counter scan. + TODO: (maybe) make this clearer and separte this into another subroutine + + Set the scan up + */ ClearScanVar(self->pScanner); AddScanVar(self->pScanner, pServ->pSics,pCon,scanVar, fStart, stepWidth); - free(scanVar); + + /* + as np can change, we have to reallocate enough space + */ + if(self->lCounts != NULL){ + free(self->lCounts); + self->lCounts = (long *)malloc(np*sizeof(long)); + if(self->lCounts == NULL){ + SCWrite(pCon,"ERROR: out of memory for scan scan data",eError); + SCSetInterrupt(pCon,eAbortScan); + return 0; + } + memset(self->lCounts,0,np*sizeof(long)); + } /* do the scan */ + snprintf(pBueffel,131,"Scanning %s, step %f, np = %d",scanVar, stepWidth, np); + SCWrite(pCon,pBueffel,eWarning); + free(scanVar); + if(self->iCompact) { self->pScanner->CollectScanData = CompactScanData; @@ -563,9 +646,9 @@ static int ScanReflection(pMesure self, float twoTheta, SConnection *pCon) { self->pScanner->ScanDrive = ScanFastDrive; } - iRet = SilentScan(self->pScanner,self->np,self->CountMode, + iRet = SilentScan(self->pScanner,np,self->CountMode, self->fPreset,pServ->pSics,pCon); - if(weakScan(self)) + if(weakScan(self,twoTheta)) { /* look for interrupts before restarting scan @@ -585,7 +668,7 @@ static int ScanReflection(pMesure self, float twoTheta, SConnection *pCon) redo scan with preset * 5 */ SCWrite(pCon,"Remeasuring weak reflection",eWarning); - iRet = SilentScan(self->pScanner,self->np,self->CountMode, + iRet = SilentScan(self->pScanner,np,self->CountMode, self->fPreset*5.,pServ->pSics,pCon); } @@ -651,10 +734,20 @@ static int ScanReflection(pMesure self, float twoTheta, SConnection *pCon) strcat(pFilename,"log"); self->iLogFile = SCAddLogFile(pCon,pFilename); self->pCon = pCon; - sprintf(pBueffel,"Writing to %s.log, .ccl, .rfl",pRoot); - SCWrite(pCon,pBueffel,eValue); + + /* + we do not need reflection files when doing a PSD scan + */ + if(self->psd == 1) + { + sprintf(pBueffel,"Logging to %s.log", pRoot); + SCWrite(pCon,pBueffel,eValue); + return 1; + } /* open the reflection file */ + sprintf(pBueffel,"Writing to %s.log, .ccl, .rfl",pRoot); + SCWrite(pCon,pBueffel,eValue); strcpy(pFilename,pRoot); strcat(pFilename,"ccl"); self->fRefl = fopen(pFilename,"w"); @@ -666,10 +759,6 @@ static int ScanReflection(pMesure self, float twoTheta, SConnection *pCon) SCSetInterrupt(pCon,eAbortBatch); return 0; } -/* put filename - fputs(pFilename,self->fRefl); - fputs("\n",self->fRefl); -*/ /* open hkl-data file */ strcpy(pFilename,pRoot); @@ -688,15 +777,10 @@ static int ScanReflection(pMesure self, float twoTheta, SConnection *pCon) /* write some header data */ SNXFormatTime(pBueffel,1024); - /* fprintf(self->fRefl,"filetime = %s\n",pBueffel); */ fprintf(self->fHKL,"filetime = %s\n",pBueffel); GetLambda(self->pCryst,&fVal); -/* fprintf(self->fRefl,"lambda = %f Angstroem\n",fVal); */ fprintf(self->fHKL,"lambda = %f Angstroem\n",fVal); GetUB(self->pCryst,fUB); -/* fprintf(self->fRefl, - "UB = %7.6f %7.6f %7.6f %7.6f %7.6f %7.6f %7.6f %7.6f %7.6f\n", - fUB[0], fUB[1],fUB[2],fUB[3],fUB[4],fUB[5],fUB[6],fUB[7],fUB[8]); */ fprintf(self->fHKL, "UB = %7.6f %7.6f %7.6f %7.6f %7.6f %7.6f %7.6f %7.6f %7.6f\n", fUB[0], fUB[1],fUB[2],fUB[3],fUB[4],fUB[5],fUB[6],fUB[7],fUB[8]); @@ -737,6 +821,22 @@ static int ScanReflection(pMesure self, float twoTheta, SConnection *pCon) { MesureClose(self); } + + /* log file */ + strcpy(pFile,self->pFileRoot); + strcat(pFile,"/"); + strcat(pFile,fileroot); + strcat(pFile,".log"); + self->iLogFile = SCAddLogFile(pCon,pFile); + self->pCon = pCon; + + /* + No reopening of reflection files in psd mode + */ + if(self->psd == 1) + { + return 1; + } /* check if this is possible */ strcpy(pFile,self->pFileRoot); @@ -764,13 +864,6 @@ static int ScanReflection(pMesure self, float twoTheta, SConnection *pCon) strcat(pFile,".rfl"); self->fHKL = fopen(pFile,"a"); - /* log file */ - strcpy(pFile,self->pFileRoot); - strcat(pFile,"/"); - strcat(pFile,fileroot); - strcat(pFile,".log"); - self->iLogFile = SCAddLogFile(pCon,pFile); - self->pCon = pCon; return 1; } @@ -779,6 +872,16 @@ static int ScanReflection(pMesure self, float twoTheta, SConnection *pCon) { assert(self); + SCDelLogFile(self->pCon,self->iLogFile); + if(self->psd == 1) + { + self->pCon = NULL; + self->iLogFile = -1; + if(self->pCurrentFile) + free(self->pCurrentFile); + return 1; + } + if(self->fRefl) { fclose(self->fRefl); @@ -789,7 +892,6 @@ static int ScanReflection(pMesure self, float twoTheta, SConnection *pCon) fclose(self->fHKL); self->fHKL = NULL; } - SCDelLogFile(self->pCon,self->iLogFile); self->pCon = NULL; self->iLogFile = -1; if(self->pCurrentFile) @@ -819,6 +921,14 @@ static int ScanReflection(pMesure self, float twoTheta, SConnection *pCon) } #endif + /* + no writing in PSD mode + */ + if(self->psd == 1) + { + return 1; + } + /* get necessary data */ fSum = 0.; fSigma = 0.; @@ -850,7 +960,8 @@ static int ScanReflection(pMesure self, float twoTheta, SConnection *pCon) } SCWrite(pCon,pBueffel,eWarning); } - GetScanCounts(self->pScanner,self->lCounts,self->np); + iNP = GetScanNP(self->pScanner); + GetScanCounts(self->pScanner,self->lCounts,iNP); /* write it */ if(self->fRefl) @@ -891,7 +1002,6 @@ static int ScanReflection(pMesure self, float twoTheta, SConnection *pCon) /* collect data */ SNXFormatTime(pBueffel,512); GetScanVarStep(self->pScanner,0,&fStep); - iNP = GetScanNP(self->pScanner); fPreset = GetScanPreset(self->pScanner); fprintf(self->fRefl,"%3d %7.3f %9.0f %7.3f %s\n",iNP,fStep, fPreset,fTemp,pBueffel); @@ -1226,6 +1336,18 @@ static int ScanReflection(pMesure self, float twoTheta, SConnection *pCon) } return 1; } + else if(strcmp(name,"psd") == 0) + { + if(fVal >= 1.) + { + self->psd = 1; + } + else + { + self->psd = 0; + } + return 1; + } else if(strcmp(name,"weak") == 0) { if(fVal >= 1.) @@ -1307,6 +1429,11 @@ static int ScanReflection(pMesure self, float twoTheta, SConnection *pCon) *fVal = self->iCompact; return 1; } + else if(strcmp(name,"psd") == 0) + { + *fVal = self->psd; + return 1; + } else if(strcmp(name,"fastscan") == 0) { *fVal = (float)self->fastScan; diff --git a/motor.c b/motor.c index 41187f10..e33360b8 100644 --- a/motor.c +++ b/motor.c @@ -62,20 +62,18 @@ #define INTBATCH 2. #define INTHALT 3. -#define HLOW 0 -#define HUPP 1 -#define SLOW 2 -#define SUPP 3 -#define SZERO 4 -#define FIX 5 -#define INT 6 -#define PREC 7 -#define USRIGHTS 8 -#define SIGN 9 -#define ECOUNT 10 -#define POSCOUNT 11 -#define IGNOREFAULT 12 -#define MOVECOUNT 13 +#define SLOW 0 +#define SUPP 1 +#define SZERO 2 +#define FIX 3 +#define INT 4 +#define PREC 5 +#define USRIGHTS 6 +#define SIGN 7 +#define ECOUNT 8 +#define POSCOUNT 9 +#define IGNOREFAULT 10 +#define MOVECOUNT 11 /*------------------------------------------------------------------------ a tiny structure used in CallBack work @@ -327,6 +325,10 @@ static int evaluateStatus(pMotor self, SConnection *pCon) { newStatus = HWPosFault; } + if(newStatus == HWIdle || newStatus == OKOK) + { + finishDriving(self,pCon); + } break; case HWBusy: newStatus = HWBusy; @@ -398,14 +400,12 @@ static void handleMoveCallback(pMotor self, SConnection *pCon) /* create and initialize parameters */ - pM->ParArray = ObParCreate(14); + pM->ParArray = ObParCreate(12); if(!pM->ParArray) { free(pM); return NULL; } - ObParInit(pM->ParArray,HLOW,"hardlowerlim",pDriv->fLower,usMugger); - ObParInit(pM->ParArray,HUPP,"hardupperlim",pDriv->fUpper,usMugger); ObParInit(pM->ParArray,SLOW,"softlowerlim",pDriv->fLower,usUser); ObParInit(pM->ParArray,SUPP,"softupperlim",pDriv->fUpper,usUser); ObParInit(pM->ParArray,SZERO,"softzero",ZEROINACTIVE,usUser); @@ -521,7 +521,18 @@ extern void KillPiPiezo(void *pData); { ObPar *pPar = NULL; assert(self); - + + if(strcmp(name,"hardupperlim") == 0) + { + *fVal = self->pDriver->fUpper; + return 1; + } + if(strcmp(name,"hardlowerlim") == 0) + { + *fVal = self->pDriver->fLower; + return 1; + } + pPar = ObParFind(self->ParArray,name); if(pPar) { @@ -674,17 +685,17 @@ extern void KillPiPiezo(void *pData); fHard = fHard*ObVal(self->ParArray,SIGN); /* check for hardware limits */ - if(fHard > ObVal(self->ParArray,HUPP)) + if(fHard > self->pDriver->fUpper) { sprintf(pBueffel,"%f violates upper hardware limit %f on %s", - fVal,ObVal(self->ParArray,HUPP),self->name); + fVal,self->pDriver->fUpper,self->name); strncpy(pError,pBueffel,iErrLen); return 0; } - if(fHard < ObVal(self->ParArray,HLOW)) + if(fHard < self->pDriver->fLower) { sprintf(pBueffel,"%f violates lower hardware limit %f on %s", - fVal,ObVal(self->ParArray,HLOW),self->name); + fVal,self->pDriver->fLower,self->name); strncpy(pError,pBueffel,iErrLen); return 0; } @@ -980,8 +991,6 @@ extern MotorDriver *MakePiPiezo(Tcl_Interp *pTcl, char *pArray); SCWrite(pCon,pBueffel,eError); return 0; } - pNew->ParArray[HLOW].iCode = usUser; - pNew->ParArray[HUPP].iCode = usUser; } else { @@ -1018,6 +1027,12 @@ extern MotorDriver *MakePiPiezo(Tcl_Interp *pTcl, char *pArray); iLen = ObParLength(self->ParArray); sprintf(pBueffel,"Parameter Listing for motor %s\n",self->name); SCWrite(pCon,pBueffel,eStatus); + snprintf(pBueffel,511,"%s.hardupperlim = %f",self->name, + self->pDriver->fUpper); + SCWrite(pCon,pBueffel,eValue); + snprintf(pBueffel,511,"%s.hardlowerlim = %f",self->name, + self->pDriver->fLower); + SCWrite(pCon,pBueffel,eValue); for(i = 0; i < iLen; i++) { sprintf(pBueffel,"%s.%s = %f\n",self->name, diff --git a/mumo.c b/mumo.c index 3311b032..77396b35 100644 --- a/mumo.c +++ b/mumo.c @@ -452,7 +452,7 @@ static int SaveMumo(void *pData, char *name, FILE *fd) SCWrite(pCon,"ERROR: Incomplete command",eError); return 0; } - return 1; /* inserted return statement, guessed return value M.Z.*/ + return 1; } /*-------------------------------------------------------------------------- @@ -619,7 +619,7 @@ static int SaveMumo(void *pData, char *name, FILE *fd) return 0; } } - return 1; /* inserted return statement, guessed return value M.Z */ + return 1; } /*-------------------------------------------------------------------------*/ static int CheckPermission(SConnection *pCon, pMulMot self) diff --git a/nxdict.c b/nxdict.c index c7e2af95..b053cc2e 100644 --- a/nxdict.c +++ b/nxdict.c @@ -596,6 +596,7 @@ char *pText; int iCode; } TokDat; + #define TERMSDS 100 #define TERMVG 200 #define TERMLINK 300 @@ -719,7 +720,7 @@ sStat->pToken[i] = '\0'; /*--------- try to find word in Tokenlist */ - for(i = 0; i < 10; i++) + for(i = 0; i < 11; i++) { if(strcmp(sStat->pToken,TokenList[i].pText) == 0) { diff --git a/nxdict.h b/nxdict.h index 17dc1a0f..197a26a7 100644 --- a/nxdict.h +++ b/nxdict.h @@ -48,6 +48,7 @@ NXstatus NXDgetalias(NXhandle file, NXdict dict, char *alias, void *pData); NXstatus NXDgetdef(NXhandle file, NXdict dict, char *pDefString, void *pData); + NXstatus NXDdefget(NXdict handle, char *pKey, char *pBuffer, int iBufLen); NXstatus NXDaliaslink(NXhandle file, NXdict dict, char *pAlias1, char *pAlias2); diff --git a/nxdict.w b/nxdict.w deleted file mode 100644 index 10e1c1fb..00000000 --- a/nxdict.w +++ /dev/null @@ -1,2537 +0,0 @@ -% -% -% This software 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 General Public License for more details. -% -% You may already have a copy of the GNU General Public License; if -% not, write to the Free Software Foundation, Inc., 675 Mass Ave, -% Cambridge, MA 02139, USA. -% - -\documentclass[12pt]{article} - -\setlength{\oddsidemargin}{-.1in} -\setlength{\evensidemargin}{0in} -\setlength{\topmargin}{0in} -\addtolength{\topmargin}{-\headheight} -\addtolength{\topmargin}{-\headsep} -\setlength{\textheight}{8.9in} -\setlength{\textwidth}{6.2in} -\setlength{\marginparwidth}{0.5in} - -\begin{document} -\title{The NEXUS Dictionary API} - -\author{Mark K\"onnecke\\ - Labor f\"ur Neutronenstreuung\\ - Paul Scherrer Institut\\ - CH-5232 Villigen PSI\\ - Switzerland\\ - Mark.Koennecke@@psi.ch \\ -} - - - -\maketitle - -\vskip.3in -\centerline{\large\bf Abstract} -\vskip.2in -\begin{center} -\parbox{.8\textwidth}{ - There is a proposed portable data exchange format for neutron and - X-ray scattering communities, NEXUS (described in a separate - publication). Another document describes an application programmers - interface to NEXUS. This is a base level API which hides many of the - hideous details of the HDF interface from the NeXus programmer. The - present document introduces a higher level application programmers - interface sitting on top of the NeXus API. This API (the NEXDICT-API), - reads all file structure data from a dictionary data file and creates - the structure automatically from that information. The NEXDICT user only - needs to specify the data to write or read. -} -\end{center} - -\clearpage - -\section{Introduction} - There exists a proposal for a portable data exchange format for neutron and - X--ray scattering communities, NeXus. NeXus is fully described - elsewhere$^{1}$. NeXus sits on top of the hierarchical data format (HDF) as - defined and specified by the National Center for Supercomputer Applications, - NCSA, USA. HDF comes with a library of access functions. On top of the - HDF-library an application programmers interface (API) for NeXus was - defined which hides many of the low level details and ideosyncracies of - the HDF interface form the NeXus programmer. However, writing NeXus files stays - hideous even with this interface due to the amount of repetitive code - required to implement the NeXus structure. Now, repetitive tasks is one - area a computer is good at. So, why not have the computer take care of all - the structure associated with the NeXus format? Such an approach has the -additional benefit that changes in the file structure just require to edit -the dictionary data file with no changes to the source code writing or -reading the data. In order to do all this two - components are needed: -\begin{itemize} -\item A language which describes the NeXus file structure to the computer. - This language will be called the NeXus Data Definition Language (NXDDL). - NXDLL might also be used as a tool for discussing and defining NeXus - data structures. -\item A application programmers interface which works with the NeXus Data - Definition Language. -\end{itemize} -Both of the above will be detailed in this document. - -\section{The NeXus Data Definition Language} -The NeXus Data Definition Language's(NXDDL) purpose is to define the structure -and data items in a NeXus file in a form which can be understood by a human -programmer and which can be parsed by the computer in order to create the -structure. -For this a dictionary based approach will be used. This dictionary -will contain pairs of short aliases for data items and definition strings -which hold the structure information. This dictionary will -be initialized from a data file, the NXDDL-file. Such a dictionary can be -used in the following way: Given an appropriate API function, a NXDICT -programmer needs to specify only the alias and the data to write and -everything else is taken care of by the API: vGroup creation, opening, -SDS definition etc. Another use may involve the creation of definition -strings -completely or partly at run time which can then be used by an API function -in order to create the structures defined by the definition string. The same -holds for writing as well. - - -A NXDDL dictionary is preferably initialized from a file. -Such a NXDDL file has to follow these general structure guidelines: -\begin{itemize} -\item All input is in US--ASCII. -\item The first line must read: ##NXDICT-1.0. This is in order to -automatically identify the file. -\item A \verb+#+ in the first column denotes a comment and will be ignored. -\item A \verb+\+ at the end of the line means that the current text will be - continued with the next non-blank character for the next line. -\item All other entries follow the form: alias = definition string. - This defines \verb+alias+ as a short form for the definition string after the - equality sign. -\item There is a text replacement facility similar to shell variables under -Unix: The sequence $(alias) anywhere in a definition string will be replaced - by the value of the alias specified between the braces. This scheme allows -to cater for multiple entries in a file or changing data descriptions as a -function of instrument modes. -\end{itemize} -It might be considered to add a special global vGroup of class NXdict to the -NexUs API which holds the dictionary information within a NeXus file. - - The next thing to define is the content of the definition string. A - definition string will have the general form: \\ -\centerline{\bf PATH/TerminalSymbol} - This means a definition string will consist of a path specifier which - describes the position of a data item in the vGroup hierarchy and a - terminal symbol which describes the nature of the data item. - - The path through the vGroup hierarchy to a data item will be described in a - manner analog to a Unix directory hierarchy. However, NeXus requires two - pieces of data in order to fully qualify a vGroup. This is it's name and - class. Consequently, both name and classname will be given for each vGroup, - separated by a komma. A valid path string then looks like: \\ -\begin{verbatim} - /scan1,NXentry/DMC,NXinstrument/big_detector,NXdetector/TerminalSymbol -\end{verbatim} - This translates into: TerminalSymbol in vGroup big\_detector, class - NXdetector, which resides in vGroup DMC of class NXinstrument, which in - turn is situated in the vGroup scan1 of class NXentry. - - The terminal symbol in a definition string is used to define the data item - at the end of the definition. NeXus currently supports only three types of - data items at the end of the chain: these are scientific data sets (SDS), - vGroups and links to other data items or vGroups. The terminal symbol for a link - is specified by the keyword \verb+NXLINK+ - followed - by a valid alias of another data item or vGroup. For example the terminal - symbol: \\ - \centerline{\bf SDS counts} - would define a SDS with name counts. - - A vGroup would be denoted by the keyword VGROUP. By then, the vGroup has - already been defined by the path string. This form of alias is only useful - for the definition of links to vGroups. - - A SDS is more involved. The definition of an SDS starts with the keyword - \verb+SDS+. This keyword must then be followed by the name of the SDS. - Following the name there are option value pairs which define the - details of the SDS. The following option exist: - \begin{itemize} - \item {\bf -rank} defines the rank of the SDS. - \item {\bf -dim \{dim0,dim1,dim2,...., dimn\} } defines the dimensions of the - SDS. Exactly the number of rank numbers defining the dimensions - length is required inside the curly braces. - \item {\bf -type} defines the data type of the SDS as a string corresponding - to the HDF data types. - \item {\bf -attr \{name,value\} } defines an attribute. In the curly braces - there must be the name and value of the attribute separated by a comma. - \end{itemize} - If no options are given a default is used. This will be a single floating - point number, as this is the most frequently written data item. As an - example see the definition of a 3d array of 32 bit integers: - \begin{verbatim} - PATHSTRING/SDS counts -rank 3 -dim {64,64,712} -type DFNT_INT32 \ - -attr {Units,Counts} - - \end{verbatim} - - \section{The NXDICT--API} - In order to interface with the NeXus dictionary API a set of - API--functions is needed. All functions and data types belonging to - this API start with the letters: NXD. The functions belonging to this API - fall into three groups: - \begin{itemize} - \item Dictionary maintainance functions. - \item Data writing and reading functions. - \item Utility functions. - \end{itemize} - - One additional data type is needed for this API: -@d tata @{ - typedef struct __NXdict *NXdict; -@} - NXdict will be used as a handle for the dictionary currently in use. - -\subsubsection{Dictionary Maintainance Function} -@d dicman @{ - NXstatus NXDinitfromfile(char *filename, NXdict *pDict); - NXstatus NXDclose(NXdict handle, char *filename); - - NXstatus NXDadd(NXdict handle, char *alias, char *DefString); - NXstatus NXDget(NXdict handle, char *alias, char *pBuffer, int iBufLen); - NXstatus NXDupdate(NXdict handle, char *alias, char *pNewVal); - NXstatus NXDtextreplace(NXdict handle, char *pDefString, char *pBuffer, - int iBuflen); -@} - - {\bf NXDinitfromfile} creates a new NeXus dictionary. If filename is NULL, this - is all that happens. If filename is not NULL, it will be opened and the - dictionary will be initialized from the file specified. The return value - is either 0 for failure or non zero for success. - - {\bf NXDclose} deletes and writes a NeXus dictionary. If filename is not NULL, - the dictionary specified by handle is written to the file specified by - filename. In any case the dictionary specified by handle will be deleted. - - {\bf NXDadd} adds a new alias -- Definition String pair to the dictionary - specified by handle. - - {\bf NXDget} retrieves the definition string for the alias specified as - the second parameter from the dictionary handle. The definition string - is copied to pBuffer. Maximum iBufLen characters will be copied. - - {\bf NXDupdate} replaces the definition for the alias specified as second - parameter with the new value supplied as last parameter. - - If a special dictionary vGroup as extension to NeXus would be accepted, - two more functions need to be defined which read and write the dictionary - from the NeXus file. - - {\bf NXDtextreplace} resolves any text replacements in the definition - string pDefString. Maximum iBuflen characters of replacement results will - be copied into the buffer variable. - -\subsubsection{Data Handling functions} -@d dicdata @{ - NXstatus NXDputalias(NXhandle file, NXdict dict, - char *alias, void *pData); - NXstatus NXDputdef(NXhandle file, NXdict dict, char *pDefString, void *pData); - - NXstatus NXDgetalias(NXhandle file, NXdict dict, - char *alias, void *pData); - NXstatus NXDgetdef(NXhandle file, NXdict dict, char *pDefString, void *pData); - - NXstatus NXDaliaslink(NXhandle file, NXdict dict, - char *pAlias1, char *pAlias2); - NXstatus NXDdeflink(NXhandle file, NXdict dict, - char *pDef1, char *pDef2); - - NXstatus NXDopenalias(NXhandle file, NXdict dict, - char *alias); - NXstatus NXDopendef(NXhandle file, NXdict dict, char *pDefString); - -@} - The NXDICT data handling functions go in pairs. The version ending in - alias expects an NXdict and an alias as input. These routines work - out the pass from that. These routines also resolve all text replacement - operations automatically. The other version ending on def acts upon - a definition string specified as second parameter. Using this scheme - both full dictionary operation is possible, as well as operation with - program generated definition strings. All routines return the - usual NeXus status returns. All these routines start at the current vGroup - level and return back to it. - - NXDputalias, NXDputdef write the data element specified by the alias or - the definition string to the NeXus file specified as first parameter. - pData is a pointer to the data to be written. These routines will check for - the existence of all vGroups required in the path part of the definition - string. If a vGroup is missing it will be created. These routines step - back to the same vGroup level from which they were called. - - NXDgetalias, NXDgetdef read a data item from file. pData MUST point to a - data area large enough to hold the data read. If a vGroup is missing in - the path for one of these routines an error is generated because it is - assumed that the data is present if a program wants to read it. These - routines step - back to the same vGroup level from which they were called. - - NXDaliaslink, NXDdeflink links the alias or definition given as fourth - parameter to the vGroup specified by the third parameter. pAlias1 or - pDef1 MUST refer to a vGroup (we cannot link to a SDS, can't we?). The - item being linked against MUST exist, otherwise the software will complain. - The vGroup into which the link is installed will be created on the fly, - if not present. - Please note, that bot aliases or definition strings specified need to - start from the same vGroup position. These routines step - back to the same vGroup level from which they were called. - - NXDopenalias, NXDopendef open the specified data items specified by the - alias or the definition string. Then the usual NeXus functions can be - used to interact with the data. These routines use the same scheme for - creating vGroups on the fly as the put routines above. The status in the - vGroup hierarchy after this call is dependent on the nature of the terminal - symbol. If it is a SDS, the vGroup hierarchy will be stepped back to the - level from which the call occurred. The SDS will be left open. If the - terminal symbol is a vGroup, then the this vGroup will be made the current - vGroup. No back stepping occurs. - - - - \subsection{NeXus Utility Functions} - This section list a couple of functions which either perform common - tasks on NeXus files or relate - to aspects of error handling and debugging. - -@d dicutil @{ - NXstatus NXUwriteglobals(NXhandle file, - char *filename, - char *owner, - char *adress, - char *phone, - char *email, - char *fax, - char *thing); - - - NXstatus NXUentergroup(NXhandle hFil, char *name, char *class); - NXstatus NXUenterdata (NXhandle fileid, char* label, int datatype, - int rank, int dim[], char *pUnits); - - NXstatus NXUallocSDS(NXhandle hFil, void **pData); - NXstatus NXUfreeSDS(void **pData); - -@} - - {\bf NXUwriteglobals} writes the global attributes to a newly opened - NeXus file. The parameters should be self explaining. In addition - the file creation date is automatically written. - - - {\bf NXUentergroup} tries to open the group specified by name and class. - If it not present, it will be created and opened. - - {\bf NXUenterdata} tries to open the SDS specified by label. - If it not present, it will be created and opened. - - {\bf NXUallocSDS} allocates enough space for the currently open SDS. The - pointer created is returned in pData. - - {\bf NXUfreeSDS} returns memory allocated by NXUallocSDS to the system. - - -\section{Implementation} -\subsection{The NXDICT Data Structure} -The NXDICT--API is based on a dictionary which maps an alias to a definition -string in NXDDL. Clearly, the first thing needed is a dictionary which maps -key string to value strings. It was chosen to use an existing string -dictionary (developed for SICS) as the dictionary for the NXDICT--API. This -is realised and documented in files stringdict.*. This string dictionary is -based on a linked list implementation available in the public domain (Files -lld.*). This is not the most efficient approach as any search requires -searching at maximum the whole linked list via strcmp. More efficient -dictionaries would use hash tables or binary trees. However, implementation -of a more efficient dictionary will be delayed until it is proven that -the current approach poses a serious performance problem. - -Thus, the NXdict data structure looks like this: -@d dicdat @{ - typedef struct __NXdict - { - int iID; - pStringDict pDictionary; - } sNXdict; -/*------------------ verbosity level -------------------------------------*/ - static int iVerbosity = 0 ; -@} -The first data member is a magic ID number which will be used for testing -pointers passed in as NXdict pointers. C permits any pointer to be passed -here. But only those with the correct magic number will be accepted. The -next data member is a pointer to the string dictionary used for implementing -the dictionary. - -Another feature is the verbosity level. This one is declared as a file -static in order to be available generally. - -\subsection{The Dictionary Maintainance Functions} -\subsubsection{NXDinitfromfile} -This routine starts off by creating and initializing a new NXdict structure: -@d iniini @{ - /* allocate a new NXdict structure */ - if(iVerbosity == NXalot) - { - NXIReportError(NXpData, "Allocating new NXdict structure "); - } - pNew = (NXdict)malloc(sizeof(sNXdict)); - if(!pNew) - { - NXIReportError(NXpData, "Insufficient memory for creation of NXdict"); - return NX_ERROR; - } - - /* initialise it */ - pNew->iID = NXDMAGIC; - pNew->pDictionary = CreateStringDict(); - if(!pNew->pDictionary) - { - NXIReportError(NXpData, "Insufficient memory for creation of NXdict"); - free(pNew); - return NX_ERROR; - } - -@} - -The next step is to check for the existence of a filename. If filename is -NULL we are done: -@d inicheck @{ - /* is there a file name argument */ - if(filename == NULL) - { - if(iVerbosity == NXalot) - { - NXIReportError(NXpData, "NXDinitfrom file finished without data"); - } - *pData = pNew; - return NX_OK; - } -@} - -The next step is to open the file: -@d inifil @{ - fd = fopen(filename,"rb"); - if(!fd) - { - sprintf(pError,"ERROR: file %s NOT found ",filename); - NXIReportError(NXpData, pError); - NXIReportError(NXpData, "NXDinitfrom file finished without data"); - *pData = pNew; - return NX_ERROR; - } - - -@} - -Now this file needs to be parsed and the alias -- definition string pairs to -be extracted. This is done in two steps: First the file contents is copied -in a buffer. Then this buffer is parsed. This aproach has the advantage that -the parsing code can be reused if another source for the dictionary -definition shows up. For instance if it is decided to include it with the -NeXus file in a special vGroup. -@d iniparse @{ - /* read the file contents */ - if(iVerbosity == NXalot) - { - NXIReportError(NXpData, "NXDinitfrom: reading file"); - } - pBuffer = NXDIReadFile(fd); - fclose(fd); /* we are done with it then */ - if(!pBuffer) - { - sprintf(pError,"ERROR: reading file %s or no memory",filename); - NXIReportError(NXpData, pError); - NXIReportError(NXpData, "NXDinitfrom file finished without data"); - *pData = pNew; - return NX_ERROR; - } - - /* parse it */ - if(iVerbosity == NXalot) - { - NXIReportError(NXpData, "NXDinitfrom: parsing dictionary definitions"); - } - NXDIParse(pBuffer, pNew->pDictionary); -@} -Once this has been done, the task left is to clean up and exit. - -\paragraph{NXDIReadFile} -This is an internal function which determines the length of the file, -allocates a suitable buffer for it and then reads the file in the buffer. -Please note, that the code for determining the length of the file works -nicely on a Unix or DOS. On a VMS however, there might be a few rubbish -characters at the end of the buffer. This is due to the record structure of -files under VMS. - -\paragraph{NXDIParse} -NXDIParse is an internal function which parses a buffer into aliases and -values. It is one of two parsers in the nxdict system. Later on there will -be a definition string parser. This file reading parser uses a -Tokenizer. - -The Tokenizer does not need to recognize a lot of -tokens, so it is rather simple. NXDIfNextToken returns a pointer pointing to -the character after the last token read. pPtr is the current position in -the buffer. The value of the last token read will be returned in the buffer -pToken. iToken will be set to the type of token recognized. - -@d ftoken @{ -#define FWORD 1 -#define FHASH 2 -#define FEOL 3 -#define FEOB 4 -#define FEQUAL 5 -#define FSLASH 6 - - static char *NXDIfNextToken(char *pPtr, char *pToken, int *iToken) - { - pToken[0] = '\0'; - /* skip whitespace */ - while( (*pPtr == ' ') || (*pPtr == '\t') ) - { - pPtr++; - } - - /* check for special characters */ - if(*pPtr == '#') - { - *iToken = FHASH; - pToken[0] = *pPtr; - pPtr++; - return pPtr; - } - else if(*pPtr == '\n') - { - *iToken = FEOL; - pToken[0] = *pPtr; - pPtr++; - return pPtr; - } - else if(*pPtr == '\0') - { - *iToken = FEOB; - pToken[0] = *pPtr; - pPtr++; - return pPtr; - } - else if(*pPtr == '=') - { - *iToken = FEQUAL; - pToken[0] = *pPtr; - pPtr++; - return pPtr; - } - else if(*pPtr == '\\') - { - *iToken = FSLASH; - pToken[0] = *pPtr; - pPtr++; - return pPtr; - } - else - { - *iToken = FWORD; - /* copy word to pToken */ - while( (*pPtr != ' ') && (*pPtr != '\t') && - (*pPtr != '\n') && (*pPtr != '\0') && (*pPtr != '=') ) - { - *pToken = *pPtr; - pPtr++; - pToken++; - } - *pToken = '\0'; - return pPtr; - } - /* not reached */ - return pPtr; - } - -@} - - -NXDIParse has two modes: parsing an alias or parsing a definition string. - -@d fparse @{ -#define AMODE 0 -#define DMODE 1 - - static void NXDIParse(char *pBuffer, pStringDict pDict) - { - char *pPtr; - int iToken; - int iMode; - char pAlias[132]; - char pDefinition[1024]; /* this is > 10 lines of definition */ - char pWord[132]; - - assert(pBuffer); - assert(pDict); - - iMode = AMODE; - pPtr = pBuffer; - iToken = -1; - pDefinition[0] = '\0'; - pAlias[0] = '\0'; - pWord[0] = '\0'; - - while(iToken != FEOB) - { - pPtr = NXDIfNextToken(pPtr,pWord,&iToken); - switch(iToken) - { - case FHASH: - case FSLASH: /* skip over \n to next non blank */ - while(*pPtr != '\n') - { - pPtr++; - /* check for end of file */ - if(*pPtr == '\0') - { - return; - } - } - pPtr++; - break; - case FEQUAL: /* do a mode change */ - iMode = DMODE; - pDefinition[0] = '\0'; - break; - - case FWORD: - if(iMode == AMODE) - { - strcpy(pAlias,pWord); - } - else - { - strcat(pDefinition,pWord); - strcat(pDefinition," "); - } - break; - case FEOL: - if(iMode == DMODE) - { - /* enter in dictionary */ - StringDictAddPair(pDict,pAlias,pDefinition); - iMode = AMODE; - pAlias[0] = '\0'; - } - break; - case FEOB: - if(iMode == AMODE) - { - /* empty line or a problem */ - } - else - { - /* enter in dictionary */ - StringDictAddPair(pDict,pAlias,pDefinition); - iMode = AMODE; - pAlias[0] = '\0'; - } - return; - default: - assert(0); /* unrecognized token is a programming - error - */ - break; - } - } - } -@} - -\subsubsection{NXDClose} -This routine will just write the dictionary to file if requested and clean -up afterwards. Prior to defining NXDClose anohter internal function is -needed which checks the validity of the handle passed into the routine. - -@d dassert @{ - NXdict NXDIAssert(NXdict handle) - { - NXdict self = NULL; - assert(handle); - self = (NXdict)handle; - assert(self->iID == NXDMAGIC); - return self; - } -@} - -@d dclose @{ - NXstatus NXDclose(NXdict handle, char *filename) - { - NXdict self; - const char *pKey = NULL; - char pValue[1024]; - FILE *fd = NULL; - - self = NXDIAssert(handle); - - if(filename) /* we must write a file */ - { - if(iVerbosity == NXalot) - { - sprintf(pValue,"Writing file %s",filename); - NXIReportError(NXpData, pValue); - } - fd = fopen(filename,"w"); - if(!fd) - { - sprintf(pValue,"ERROR: opening file %s for write",filename); - NXIReportError(NXpData, pValue); - return NX_ERROR; - } - - /* write our magic recognition header */ - fprintf(fd,"##NXDICT-1.0\n"); - - /* write all our keys */ - pKey = StringDictGetNext(self->pDictionary, pValue,1023); - while(pKey != NULL) - { - fprintf(fd,"%s = %s\n",pKey,pValue); - pKey = StringDictGetNext(self->pDictionary,pValue,1023); - } - fclose(fd); - if(iVerbosity == NXalot) - { - sprintf(pValue,"File %s written",filename); - NXIReportError(NXpData, pValue); - } - } - - /* now we send the cleaners in */ - DeleteStringDict(self->pDictionary); - free(self); - return NX_OK; - } -@} - -\subsubsection{NXDadd, NXDget, NXDupdate} -These are very much only wrapper function around the corresponding functions -for maintaining StringDicts. Accordingly, they are fairly simple. -@d dmaintain @{ - NXstatus NXDadd(NXdict handle, char *alias, char *pDef) - { - NXdict self; - int iRet; - - self = NXDIAssert(handle); - iRet = StringDictAddPair(self->pDictionary,alias,pDef); - if(!iRet) - { - return NX_ERROR; - } - return NX_OK; - } -/*---------------------------------------------------------------------------*/ - NXstatus NXDget(NXdict handle, char *pKey, char *pBuffer, int iBufLen) - { - NXdict self; - int iRet; - - self = NXDIAssert(handle); - iRet = StringDictGet(self->pDictionary,pKey,pBuffer,iBufLen); - if(!iRet) - { - return NX_ERROR; - } -#ifdef DEFDEBUG - printf("Resolved: %s to %s\n",pKey,pBuffer); -#endif - return NX_OK; - } -/*-------------------------------------------------------------------------*/ - NXstatus NXDupdate(NXdict handle, char *pKey, char *pNewVal) - { - NXdict self; - int iRet; - - self = NXDIAssert(handle); - iRet = StringDictUpdate(self->pDictionary,pKey,pNewVal); - if(!iRet) - { - return NX_ERROR; - } - return NX_OK; - } - -@} -\subsubsection{Text replacement} -A definition string as retrieved from the string dictionary may still -contain text replacement items. The next function, NXDtextreplace resolves -these text replacements. - -@d textrep @{ -#define NORMAL 1 -#define ALIAS 2 - pDynString NXDItextreplace(NXdict handle, char *pDefString) - { - NXdict self; - int iRet, iPos, i; - pDynString pReplaced = NULL; - char pBueffel[1024]; - char pBuffer2[1024]; - char *pPtr; - int iState; - - self = NXDIAssert(handle); - - /* create a dynamic string */ - pReplaced = CreateDynString(strlen(pDefString),512); - if(!pReplaced) - { - NXIReportError(NXpData,"ERROR: out of memory in NXDtextreplace"); - return NULL; - } - - /* the loop */ - iState = NORMAL; - for(i = 0, pPtr = pDefString; i < strlen(pDefString); i++,pPtr++) - { - if(iState == NORMAL) - { - if(*pPtr == '$') - { - iState = ALIAS; - memset(pBueffel,0,1024); - iPos = 0; - } - else - { - DynStringConcatChar(pReplaced,*pPtr); - } - } - else if(iState == ALIAS) - { - switch(*pPtr) - { - case '(': /* ignore */ - break; - case ')': - /* do the replacement */ - memset(pBuffer2,0,1023); - iRet = NXDget(handle, pBueffel,pBuffer2,1023); - if(iRet != NX_OK) - { - DeleteDynString(pReplaced); - return NULL; - } - DynStringConcat(pReplaced,pBuffer2); - iState = NORMAL; - break; - default: - pBueffel[iPos] = *pPtr; - iPos++; - if(iPos >= 1024) - { - NXIReportError(NXpData, - "ERROR: buffer overrun in NXDItextreplace"); - DeleteDynString(pReplaced); - return NULL; - } - break; - } - } - } -#ifdef DEFDEBUG - printf("Replacement result: %s\n",GetCharArray(pReplaced)); -#endif - return pReplaced; - } -/*--------------------------------------------------------------------------*/ - NXstatus NXDtextreplace(NXdict handle, char *pDefString, - char *pBuffer, int iBufLen) - { - pDynString pResult = NULL; - char *pPtr = NULL; - - pResult = NXDItextreplace(handle,pDefString); - if(!pResult) - { - return NX_ERROR; - } - - /* copy results home */ - pPtr = GetCharArray(pResult); - strncpy(pBuffer,pPtr,iBufLen); - DeleteDynString(pResult); - return NX_OK; - } -@} - -\subsection{Dictionary Added Data Transfer} -The heart of these routines is the NXDopendef function which opens the data -item specified. Most of the other routines can be defined as wrappers to -this one. That is why it is discussed as the first function. Again a parser -is needed for parsing and interpreting the definition string. - -\subsubsection{The Definition String Parser} -The definition string parser is implemented as a classic recursive descent -parser. And once -more again a Tokenizer is needed. The Tokenizer has an own datastructure for -holding token information in a static array: - -@d tokdat @{ - typedef struct { - char pText[20]; - int iCode; - } TokDat; -@} - -In order to do the parsing a data structure for holding parsing information -is necessary: - -@d padef @{ -#define TERMSDS 100 -#define TERMVG 200 -#define TERMLINK 300 - - typedef struct { - char *pPtr; - char pToken[256]; - int iToken; - int iDepth; - int iMayCreate; - int iTerminal; - } ParDat; -@} -In this structure pPtr is the current position in the buffer, iToken the ID -of the current token, pToken the text of the current token, iDepth gets -incremented whenever a vGroup is opened. This is needed in order to roll the -vGroups back in the hierarchy after finishing operations. iMayCreate will be -set if the path parsing function may create new vGroups if the one requested -can not be found. - -This is the tokenizer: -@d deftok @{ -/*---------------- Token name defines ---------------------------*/ -#define DSLASH 0 -#define DKOMMA 1 -#define DSDS 2 -#define DLINK 3 -#define DGROUP 4 -#define DRANK 5 -#define DDIM 6 -#define DTYPE 7 -#define DWORD 9 -#define DOPEN 10 -#define DCLOSE 11 -#define DATTR 12 -#define DEND 13 - -/*----------------- Keywords ----------------------------------------*/ - - static TokDat TokenList[8] = { - {"SDS",DSDS}, - {"NXLINK",DLINK}, - {"NXVGROUP",DGROUP}, - {"-dim",DDIM}, - {"-type",DTYPE}, - {"-rank",DRANK}, - {"-attr",DATTR}, - {"",0} }; - -/*-----------------------------------------------------------------------*/ - static void NXDIDefToken(ParDat *sStat) - { - int i; - - - sStat->pToken[0] = '\0'; - - /* skip whitespace */ - while( (*(sStat->pPtr) == ' ') || (*(sStat->pPtr) == '\t') ) - { - sStat->pPtr++; - } - - /* check for special characters */ - if(*(sStat->pPtr) == '/') - { - sStat->iToken = DSLASH; - sStat->pToken[0] = *(sStat->pPtr); - sStat->pPtr++; - return; - } - else if(*(sStat->pPtr) == ',') - { - sStat->iToken = DKOMMA; - sStat->pToken[0] = *(sStat->pPtr); - sStat->pPtr++; - return; - } - else if(*(sStat->pPtr) == '\0') - { - sStat->iToken = DEND; - sStat->pToken[0] = *(sStat->pPtr); - sStat->pPtr++; - return; - } - else if(*(sStat->pPtr) == '{') - { - sStat->iToken = DOPEN; - sStat->pToken[0] = *(sStat->pPtr); - sStat->pPtr++; - return; - } - else if(*(sStat->pPtr) == '}') - { - sStat->iToken = DCLOSE; - sStat->pToken[0] = *(sStat->pPtr); - sStat->pPtr++; - return; - } - else - { - sStat->iToken = DWORD; - /* copy word to pToken */ - i = 0; - while( (*(sStat->pPtr) != ' ') && (*(sStat->pPtr) != '\t') && - (*(sStat->pPtr) != '/') && (*(sStat->pPtr) != '\0') && - (*(sStat->pPtr) != ',') && (*(sStat->pPtr) != '}') ) - { - sStat->pToken[i] = *(sStat->pPtr); - sStat->pPtr++; - i++; - } - sStat->pToken[i] = '\0'; - - /*--------- try to find word in Tokenlist */ - for(i = 0; i < 7; i++) - { - if(strcmp(sStat->pToken,TokenList[i].pText) == 0) - { - sStat->iToken = TokenList[i].iCode; - break; - } - } - return; - } - /* not reached */ - return; - } - -@} - -Now, finally we can define the parser! This parser is universally used by -all the data transfer functions. Input is the file handle of the NeXus file -and a pointer to an initialised ParDat structure. It is expected, that the -pPtr field points to the start of the definition string, that iMayCreate is -properly defined and that iDepth is 0. - -@d defpar @{ - static int NXDIDefParse(NXhandle hFil, NXdict pDict, ParDat *pParse) - { - int iRet; - char pError[256]; - - pParse->iToken = -1; - while(pParse->iToken != DEND) - { - NXDIDefToken(pParse); /* next token */ - switch(pParse->iToken) - { - case DEND: - break; - case DSLASH: - iRet = NXDIParsePath(hFil, pParse); - if(iRet == NX_ERROR) - { - return NX_ERROR; - } - break; - case DSDS: - iRet = NXDIParseSDS(hFil, pParse); - if(iRet == NX_ERROR) - { - return NX_ERROR; - } - pParse->iTerminal = TERMSDS; - break; - case DLINK: - iRet = NXDIParseLink(hFil,pDict, pParse); - if(iRet == NX_ERROR) - { - return NX_ERROR; - } - pParse->iTerminal = TERMLINK; - break; - case DGROUP: - pParse->iTerminal = TERMVG; - return NX_OK; - default: - sprintf(pError, - "ERROR: Definition String parse error: %s not permitted here", - pParse->pToken); - NXIReportError(NXpData,pError); - return NX_ERROR; - break; - } - } - return NX_OK; - } -@} - -The next thing to do is to implement ParsePath. This will try to interpret a -path string and initiate the apropriate actions, i.e. opening vGroups or -creating them. However, there is a small problem here. The code needs to -know if the vGroup exists. This can be checked by trying to open the group -with NXopengroup. This will return an error if this group does not exist. -NXopengroup will also print an error message saying so. This is not what is -wanted here, as we might choose to create the missing group silently. - In order to suppress -that one, it is needed to replace the current error handler by a dummy which -just prints nothing anywhere and to step back to the original handler once -we are done. The other option would be to use internals of the NeXus API -implementation. However, the aim is to keep the original NeXus API and this -as independent as possible. Consequently, here is the definition of the -dummy error handler: -@d dummyerr @{ - static void DummyError(void *pData, char *pError) - { - return; - } -@} - - -When NXDIParsePath has been called the / has already been read. -NXDIParsePath has to read the name and class of the vGroup separated by a -komma. Then it has either to open the vGroup, and if this fails create it if -the create flag in pParse is set. - -@d defpath @{ - int NXDIParsePath(NXhandle hfil, ParDat *pParse) - { - int iRet, iToken; - void (*ErrFunc)(void *pData, char *pErr); - char pName[132], pClass[132]; - char pError[256]; - - /* get the name */ - NXDIDefToken(pParse); /* next token */ - if( (pParse->iToken == DSDS) || (pParse->iToken == DGROUP) - || (pParse->iToken == DLINK) ) - { - /* put back & OK */ - pParse->pPtr -= strlen(pParse->pToken); - return NX_OK; - } - if(pParse->iToken != DWORD) - { - sprintf(pError,"ERROR: parse error at %s, expected vGroup name", - pParse->pToken); - NXIReportError(NXpData, pError); - return NX_ERROR; - } - strcpy(pName,pParse->pToken); - - /* now we expect a komma */ - NXDIDefToken(pParse); /* next token */ - if(pParse->iToken != DKOMMA) - { - sprintf(pError,"ERROR: parse error at %s, expected komma", - pParse->pToken); - NXIReportError(NXpData, pError); - return NX_ERROR; - } - - /* next must be the class */ - NXDIDefToken(pParse); /* next token */ - if(pParse->iToken != DWORD) - { - sprintf(pError,"ERROR: parse error at %s, expected vGroup class", - pParse->pToken); - NXIReportError(NXpData, pError); - return NX_ERROR; - } - strcpy(pClass,pParse->pToken); - - /* done reading, ACTION, first install dummy error handler */ - ErrFunc = NXIReportError; - NXMSetError(NXpData, DummyError); - - /* try opening vGroup */ - iRet = NXopengroup(hfil, pName, pClass); - NXMSetError(NXpData,ErrFunc); - if(iRet == NX_OK) - { - pParse->iDepth++; - return NX_OK; - } - else - { - /* we need to create it, if we may */ - if(pParse->iMayCreate) - { - iRet = NXmakegroup(hfil,pName,pClass); - if(iRet != NX_OK) - { - /* a comment on this one has already been written! */ - return iRet; - } - iRet = NXopengroup(hfil,pName,pClass); - if(iRet != NX_OK) - { - /* a comment on this one has already been written! */ - return iRet; - } - pParse->iDepth++; - return NX_OK; - } - else - { - /* this is an error */ - sprintf(pError,"ERROR: vGroup %s, %s NOT found",pName, pClass); - NXIReportError(NXpData,pError); - return NX_ERROR; - } - } - /* not reached */ - return NX_ERROR; - } -@} - - -NXDIParseSDS is more involved, as we have to deal with all the extras an SDS -can have: dimensions, types etc. Each of these options can be present or -not, and these options can go in any order. Particularly troublesome are -attributes which can only be written after opening or creating an SDS. this -implies that attributes have to be stored in a list during parsing in order -to have them available after creation or opening of the SDS. This requires -another private data structure for holding attribute information during -parsing: -@d attitem @{ - typedef struct { - char name[256]; - char value[256]; - }AttItem; -@} - - -@d nxpasds @{ - static int NXDIParseSDS(NXhandle hfil, ParDat *pParse) - { - int iType = DFNT_FLOAT32; - int iRank = 1; - int32 iDim[MAX_VAR_DIMS]; - int iList; - int iRet, iStat; - char pError[256]; - char pName[MAX_NC_NAME]; - void (*ErrFunc)(void *pData, char *pErr); - AttItem sAtt; - - - iDim[0] = 1; - /* first find the name */ - NXDIDefToken(pParse); - if(pParse->iToken != DWORD) - { - sprintf(pError,"ERROR: parsing, expected name, got %s", - pParse->pToken); - NXIReportError(NXpData,pError); - return NX_ERROR; - } - strcpy(pName,pParse->pToken); - - /* create the attribute list */ - iList = LLDcreate(sizeof(AttItem)); - if(iList < 0) - { - NXIReportError(NXpData, "ERROR: cannot create list in NXDIParseSDS"); - return NX_ERROR; - } - - NXDIDefToken(pParse); - while(pParse->iToken != DEND) - { - switch(pParse->iToken) - { - case DRANK: /* rank */ - NXDIDefToken(pParse); /* advance */ - if(pParse->iToken != DWORD) - { - sprintf(pError, - "ERROR: expected int, got %s", pParse->pToken); - NXIReportError(NXpData,pError); - LLDdelete(iList); - return NX_ERROR; - } - iRank = atoi(pParse->pToken); - break; - case DDIM: - iRet = NXDIParseDim (pParse, (int *) iDim); - if(iRet == NX_ERROR) - { - LLDdelete(iList); - return iRet; - } - break; - case DTYPE: - iRet = NXDIParseType(pParse, &iType); - if(iRet == NX_ERROR) - { - LLDdelete(iList); - return iRet; - } - break; - case DATTR: - iRet = NXDIParseAttr(pParse, iList); - if(iRet == NX_ERROR) - { - LLDdelete(iList); - return iRet; - } - break; - case DEND: - break; - default: - sprintf(pError,"ERROR: cannot identify token %s", - pParse->pToken); - NXIReportError(NXpData, pError); - LLDdelete(iList); - return NX_ERROR; - - } - NXDIDefToken(pParse); - } - - /* whew! got all information for doing the SDS */ - /* first install dummy error handler, try open it, then - deinstall again and create if allowed - */ - ErrFunc = NXIReportError; - NXMSetError(NXpData, DummyError); - - /* try opening SDS */ - iRet = NXopendata(hfil, pName); - NXMSetError(NXpData,ErrFunc); - if(iRet == NX_OK) - { - LLDdelete(iList); - return NX_OK; - } - else - { - /* we need to create it, if we may */ - if(pParse->iMayCreate) - { - iRet = NXmakedata (hfil, pName, iType, iRank, (int *) iDim); - if(iRet != NX_OK) - { - /* a comment on this one has already been written! */ - LLDdelete(iList); - return iRet; - } - iRet = NXopendata(hfil,pName); - if(iRet != NX_OK) - { - /* a comment on this one has already been written! */ - LLDdelete(iList); - return iRet; - } - /* put attributes in */ - iRet = LLDnodePtr2First(iList); - while(iRet != 0) - { - LLDnodeDataTo(iList,&sAtt); - iStat = NXputattr(hfil,sAtt.name, - sAtt.value,strlen(sAtt.value),NX_CHAR); - if(iStat != NX_OK) - { - /* NeXus already complained bitterly */ - LLDdelete(iList); - return iStat; - } - iRet = LLDnodePtr2Next(iList); - } - LLDdelete(iList); - return NX_OK; - } - else - { - /* this is an error */ - sprintf(pError,"ERROR: SDS %s NOT found",pName); - NXIReportError(NXpData,pError); - LLDdelete(iList); - return NX_ERROR; - } - } - return NX_OK; - } -@} - -NXDIParseType is fairly straightforward: read a word and try to interpret it -as one of the standard NeXus data types. - -@d parsetype @{ - static TokDat tDatType[] = { - {"DFNT_FLOAT32",DFNT_FLOAT32}, - {"DFNT_FLOAT64",DFNT_FLOAT64}, - {"DFNT_INT8",DFNT_INT8}, - {"DFNT_UINT8",DFNT_UINT8}, - {"DFNT_INT16",DFNT_INT16}, - {"DFNT_UINT16",DFNT_UINT16}, - {"DFNT_INT32",DFNT_INT32}, - {"DFNT_UINT32",DFNT_UINT32}, - {"",0} }; - - - - static int NXDIParseType(ParDat *pParse, int *iType) - { - char pError[256]; - int i = 0; - - NXDIDefToken(pParse); - if(pParse->iToken != DWORD) - { - sprintf(pError,"ERROR: expected data type, got %s", pParse->pToken); - NXIReportError(NXpData,pError); - return NX_ERROR; - } - - /* try to interpret data type */ - while(tDatType[i].iCode > 0) { - if(strcmp(tDatType[i].pText,pParse->pToken) == 0) - { - *iType = tDatType[i].iCode; - return NX_OK; - } - i++; - } - /* if we are here, the data type has not been recognized. Reason for - some boring error reporting code - */ - sprintf(pError,"ERROR: %s not recognized as valid data type", - pParse->pToken); - NXIReportError(NXpData,pError); - return NX_ERROR; - } -@} - -NXDIParseDim tries to read dimension information. This starts with a { -followed by numbers and kommas until there is a closing curly brace. - -@d parsedim @{ - static int NXDIParseDim(ParDat *pParse, int *iDim) - { - char pError[256]; - int iRet, i; - - /* initialise dimensions to 0 */ - for(i = 0; i < MAX_VAR_DIMS; i++) - { - iDim[i] = 0; - } - - NXDIDefToken(pParse); - if(pParse->iToken != DOPEN) - { - sprintf(pError,"ERROR: expected {, got %s",pParse->pToken); - NXIReportError(NXpData,pError); - return NX_ERROR; - } - - i = 0; - while(pParse->iToken != DCLOSE) - { - /* get a number */ - NXDIDefToken(pParse); - if(pParse->iToken != DWORD) - { - sprintf(pError,"ERROR: expected number, got %s",pParse->pToken); - NXIReportError(NXpData,pError); - return NX_ERROR; - } - iDim[i] = atoi(pParse->pToken); - i++; - /* next must be close of komma */ - NXDIDefToken(pParse); - if( (pParse->iToken != DKOMMA) && (pParse->iToken != DCLOSE) ) - { - sprintf(pError,"ERROR: expected , or }, got %s",pParse->pToken); - NXIReportError(NXpData,pError); - return NX_ERROR; - } - if(pParse->iToken == DCLOSE) - { - break; - } - } - return NX_OK; - } -@} - -NXDIParseAttr tries to parse an attribute and enters it into the attribute -list. - -@d parseatt @{ - static int NXDIParseAttr(ParDat *pParse, int iList) - { - char pError[256]; - int iRet; - AttItem sAtt; - - /* a { is expected */ - NXDIDefToken(pParse); - if(pParse->iToken != DOPEN) - { - sprintf(pError,"ERROR: expected {, got %s",pParse->pToken); - NXIReportError(NXpData,pError); - return NX_ERROR; - } - - /* a word is expected */ - NXDIDefToken(pParse); - if(pParse->iToken != DWORD) - { - sprintf(pError,"ERROR: expected attribute name, got %s",pParse->pToken); - NXIReportError(NXpData,pError); - return NX_ERROR; - } - strcpy(sAtt.name,pParse->pToken); - - /* a , is expected */ - NXDIDefToken(pParse); - if(pParse->iToken != DKOMMA) - { - sprintf(pError,"ERROR: expected , , got %s",pParse->pToken); - NXIReportError(NXpData,pError); - return NX_ERROR; - } - - /* a word is expected */ - NXDIDefToken(pParse); - if(pParse->iToken != DWORD) - { - sprintf(pError,"ERROR: expected attribute value, got %s",pParse->pToken); - NXIReportError(NXpData,pError); - return NX_ERROR; - } - strcpy(sAtt.value,pParse->pToken); - - /* a } is expected */ - NXDIDefToken(pParse); - if(pParse->iToken != DCLOSE) - { - sprintf(pError,"ERROR: expected }, got %s",pParse->pToken); - NXIReportError(NXpData,pError); - return NX_ERROR; - } - - /* enter into list */ - LLDnodeAppendFrom(iList,&sAtt); - return NX_OK; - } -@} - -The last part of the definition string parser is NXDIParseLink. This -function parses and handles a link to another data item in the file. - -@d parselink @{ - static int NXDIParseLink(NXhandle hfil, NXdict pDict,ParDat *pParse) - { - char pError[256]; - int i, iRet; - - /* need one word of alias */ - NXDIDefToken(pParse); - if(pParse->iToken != DCLOSE) - { - sprintf(pError,"ERROR: expected alias , got %s",pParse->pToken); - NXIReportError(NXpData,pError); - return NX_ERROR; - } - - /* move back in hierarchy */ - for(i = 0; i < pParse->iDepth; i++) - { - iRet = NXclosegroup(hfil); - if(iRet == NX_ERROR) - { - return NX_ERROR; - } - } - - /* open the link instead */ - return NXDopenalias(hfil, pDict, pParse->pToken); - - } -@} - -Another helper function unwinds the vGroup hierarchy. -@d unwind @{ - static NXstatus NXDIUnwind(NXhandle hFil, int iDepth) - { - int i, iRet; - - for(i = 0; i < iDepth; i++) - { - iRet = NXclosegroup(hFil); - if(iRet != NX_OK) - { - return NX_ERROR; - } - } - return NX_OK; - } -@} - -\subsubsection{NXDopendef} -NXDopendef calls the definiton string parser and then just steps back in the -vGroup hierarchy and stays there. - -@d nxddefopen @{ - NXstatus NXDopendef(NXhandle hfil, NXdict dict, char *pDef) - { - NXdict pDict; - ParDat pParse; - int iRet, i, iStat; - - pDict = NXDIAssert(dict); - - /* parse and act on definition string */ - pParse.iMayCreate = 1; - pParse.pPtr = pDef; - pParse.iDepth = 0; - iRet = NXDIDefParse(hfil,pDict,&pParse); - if(iRet == NX_ERROR) - { - /* unwind and throw up */ - iRet = NXDIUnwind(hfil,pParse.iDepth); - return NX_ERROR; - } - - - /* try rewinding the hierarchy */ - if(pParse.iTerminal == TERMSDS) - { - iStat = NXDIUnwind(hfil,pParse.iDepth); - if(iStat != NX_OK) - { - return NX_ERROR; - } - } - /* do not rewind on links */ - return iRet; - } -@} - -\subsubsection{NXDopenalias} -NXDOpenalias is just a wrapper around NXDopendef which retrieves a -definition string from the directory first. - -@d nxdaliasopen @{ - NXstatus NXDopenalias(NXhandle hfil, NXdict dict, char *pAlias) - { - NXdict pDict; - int iRet; - char pDefinition[1024]; - pDynString pReplaced = NULL; - - pDict = NXDIAssert(dict); - - /* get Definition String */ - iRet = NXDget(pDict,pAlias,pDefinition,1023); - if(iRet != NX_OK) - { - sprintf(pDefinition,"ERROR: alias %s not recognized",pAlias); - NXIReportError(NXpData,pDefinition); - return NX_ERROR; - } - - /* do the text replacement */ - pReplaced = NXDItextreplace(dict,pDefinition); - if(!pReplaced) - { - return NX_ERROR; - } - - /* call NXDopendef */ - iRet = NXDopendef(hfil,dict,GetCharArray(pReplaced)); - DeleteDynString(pReplaced); - return iRet; - } -@} - -\subsubsection{NXDputdef} -This routine puts a data item into a NeXus file using a definition string. -This naturally can work only, if there is an SDS at the end. - -@d nxput @{ - NXstatus NXDputdef(NXhandle hFil, NXdict dict, char *pDef, void *pData) - { - NXdict pDict; - ParDat pParse; - int iRet, i, iStat; - - pDict = NXDIAssert(dict); - - /* parse and act on definition string */ - pParse.iMayCreate = 1; - pParse.pPtr = pDef; - pParse.iDepth = 0; -#ifdef DEFDEBUG - printf("Putting: %s\n",pDef); -#endif - iRet = NXDIDefParse(hFil,pDict,&pParse); - if(iRet == NX_ERROR) - { - NXDIUnwind(hFil,pParse.iDepth); - return NX_ERROR; - } - - - /* only SDS can be written */ - if(pParse.iTerminal != TERMSDS) - { - NXIReportError(NXpData, - "ERROR: can only write to an SDS!"); - iStat = NX_ERROR; - } - else - { - /* the SDS should be open by now, write it */ - iStat = NXputdata(hFil, pData); - iRet = NXclosedata(hFil); - } - - - /* rewind the hierarchy */ - iRet = NXDIUnwind(hFil,pParse.iDepth); - if(iRet != NX_OK) - { - return NX_ERROR; - } - return iStat; - } -@} - -\subsubsection{NXDputalias} -Just finds the definition string and calls NXputdef then. -@d nxdputalias @{ - NXstatus NXDputalias(NXhandle hFil, NXdict dict, char *pAlias, void *pData) - { - NXdict pDict; - int iRet; - char pDefinition[1024]; - pDynString pReplaced = NULL; - - pDict = NXDIAssert(dict); - - /* get Definition String */ - iRet = NXDget(pDict,pAlias,pDefinition,1023); - if(iRet != NX_OK) - { - sprintf(pDefinition,"ERROR: alias %s not recognized",pAlias); - NXIReportError(NXpData,pDefinition); - return NX_ERROR; - } - - /* do text replacement */ - pReplaced = NXDItextreplace(dict,pDefinition); - if(!pReplaced) - { - return NX_ERROR; - } - - /* call NXDputdef */ - iRet = NXDputdef(hFil,dict,GetCharArray(pReplaced),pData); - DeleteDynString(pReplaced); - return iRet; - } -@} - -\subsubsection{NXDgetdef} - -@d nxget @{ - NXstatus NXDgetdef(NXhandle hFil, NXdict dict, char *pDef, void *pData) - { - NXdict pDict; - ParDat pParse; - int iRet, i, iStat; - - pDict = NXDIAssert(dict); - - /* parse and act on definition string */ - pParse.iMayCreate = 0; - pParse.pPtr = pDef; - pParse.iDepth = 0; -#ifdef DEFDEBUG - printf("Getting: %s\n",pDef); -#endif - iRet = NXDIDefParse(hFil,pDict,&pParse); - if(iRet == NX_ERROR) - { - /* unwind and throw up */ - NXDIUnwind(hFil,pParse.iDepth); - return NX_ERROR; - } - - - /* only SDS can be written */ - if(pParse.iTerminal != TERMSDS) - { - NXIReportError(NXpData, - "ERROR: can only write to an SDS!"); - iStat = NX_ERROR; - } - else - { - /* the SDS should be open by now, read it */ - iStat = NXgetdata(hFil, pData); - iRet = NXclosedata(hFil); - } - - - /* rewind the hierarchy */ - iRet = NXDIUnwind(hFil,pParse.iDepth); - if(iRet != NX_OK) - { - return NX_ERROR; - } - return iStat; - } -@} - -\subsubsection{NXgetalias} -Just finds the definition string and calls NXgetdef then. -@d nxdgetalias @{ - NXstatus NXDgetalias(NXhandle hFil, NXdict dict, char *pAlias, void *pData) - { - NXdict pDict; - int iRet; - char pDefinition[1024]; - pDynString pReplaced = NULL; - - pDict = NXDIAssert(dict); - - /* get Definition String */ - iRet = NXDget(pDict,pAlias,pDefinition,1023); - if(iRet != NX_OK) - { - sprintf(pDefinition,"ERROR: alias %s not recognized",pAlias); - NXIReportError(NXpData,pDefinition); - return NX_ERROR; - } - - /* do text replacement */ - pReplaced = NXDItextreplace(dict,pDefinition); - if(!pReplaced) - { - return NX_ERROR; - } - - /* call NXDgetdef */ - iRet = NXDgetdef(hFil,dict,GetCharArray(pReplaced),pData); - DeleteDynString(pReplaced); - return iRet; - } -@} - -\subsubsection{NXDdeflink, NXDaliaslink} -The first alias/definition string must be a vGroup, the other can be a -vGroup or a SDS. - -@d nxlink @{ - NXstatus NXDdeflink(NXhandle hFil, NXdict dict, - char *pTarget, char *pVictim) - { - NXdict pDict; - ParDat pParseT, pParseV; - int iRet, i, iStat; - NXlink sLink; - - pDict = NXDIAssert(dict); - - -#ifdef DEFDEBUG - printf("Linking: %s\n",pVictim); - printf("To: %s\n", pTarget); -#endif - - - /* parse Victim */ - pParseV.iMayCreate = 0; - pParseV.pPtr = pVictim; - pParseV.iDepth = 0; - iRet = NXDIDefParse(hFil,pDict,&pParseV); - if(iRet == NX_ERROR) - { - /* unwind and throw up */ - NXDIUnwind(hFil,pParseV.iDepth); - return NX_ERROR; - } - /* get link data */ - if(pParseV.iTerminal == TERMSDS) - { - NXgetdataID(hFil,&sLink); - iRet = NXclosedata(hFil); - if(iRet != NX_OK) - { - /* unwind and throw up */ - NXDIUnwind(hFil,pParseV.iDepth); - return NX_ERROR; - } - } - else if(pParseV.iTerminal == TERMVG) - { - NXgetgroupID(hFil,&sLink); - } - else - { - assert(0); /* serious programming error */ - } - /* Unwind */ - iRet = NXDIUnwind(hFil,pParseV.iDepth); - if(iRet != NX_OK) - { - return NX_ERROR; - } - - /* parse Target */ - pParseT.iMayCreate = 1; - pParseT.pPtr = pTarget; - pParseT.iDepth = 0; - iRet = NXDIDefParse(hFil,pDict,&pParseT); - if(iRet == NX_ERROR) - { - /* unwind and throw up */ - NXDIUnwind(hFil,pParseT.iDepth); - return NX_ERROR; - } - /* check it being a vGroup! */ - if(pParseT.iTerminal != TERMVG) - { - NXIReportError(NXpData,"ERROR: can link only into a vGroup"); - NXDIUnwind(hFil,pParseT.iDepth); - return NX_ERROR; - } - - /* link, finally */ - iRet = NXmakelink(hFil,&sLink); - /* Unwind anyway */ - iStat = NXDIUnwind(hFil,pParseT.iDepth); - if(iStat != NX_OK) - { - return NX_ERROR; - } - return iStat; - } -/*--------------------------------------------------------------------------*/ - NXstatus NXDaliaslink(NXhandle hFil, NXdict dict, - char *pTarget, char *pVictim) - { - char pTargetDef[1024], pVictimDef[1024]; - int iRet; - NXdict pDict; - pDynString pRep1 = NULL, pRep2 = NULL; - - pDict = NXDIAssert(dict); - - /* get Target Definition String */ - iRet = NXDget(pDict,pTarget,pTargetDef,1023); - if(iRet != NX_OK) - { - sprintf(pTargetDef,"ERROR: alias %s not recognized",pTarget); - NXIReportError(NXpData,pTargetDef); - return NX_ERROR; - } - - /* get Victim definition string */ - iRet = NXDget(pDict,pVictim,pVictimDef,1023); - if(iRet != NX_OK) - { - sprintf(pTargetDef,"ERROR: alias %s not recognized",pTarget); - NXIReportError(NXpData,pTargetDef); - return NX_ERROR; - } - - /* do replacements */ - pRep1 = NXDItextreplace(dict,pTargetDef); - pRep2 = NXDItextreplace(dict,pVictimDef); - if( (!pRep1) || (!pRep2) ) - { - if(pRep1) - DeleteDynString(pRep1); - if(pRep2) - DeleteDynString(pRep2); - return NX_ERROR; - } - - /* call NXdeflin */ - iRet = NXDdeflink(hFil,pDict,GetCharArray(pRep1),GetCharArray(pRep2)); - DeleteDynString(pRep1); - DeleteDynString(pRep2); - return iRet; - } - -@} - -\subsection{Utility functions} -\subsubsection{NXUwriteglobals} -@d global @{ -/*-------------------------------------------------------------------------*/ - static void SNXFormatTime(char *pBuffer, int iBufLen) - { - time_t iDate; - struct tm *psTime; - - /* make time string */ - iDate = time(NULL); - psTime = localtime(&iDate); - memset(pBuffer,0,iBufLen); - strftime(pBuffer,iBufLen,"%Y-%d-%m %H:%M:%S",psTime); - } -/*--------------------------------------------------------------------------*/ - NXstatus NXUwriteglobals(NXhandle pFile, - char *filename, - char *owner, - char *adress, - char *phone, - char *email, - char *fax, - char *instrument) - { - char pBueffel[512]; - int iStat; - - /* store global attributes */ - iStat = NXputattr(pFile,"file_name",filename, - strlen(filename)+1,DFNT_INT8); - if(iStat == NX_ERROR) - { - return NX_ERROR; - } - - /* write creation time */ - SNXFormatTime(pBueffel,512); - iStat = NXputattr(pFile,"file_time",pBueffel, - strlen(pBueffel)+1,DFNT_INT8); - if(iStat == NX_ERROR) - { - return NX_ERROR; - } - - /* instrument name */ - iStat = NXputattr(pFile,"instrument",instrument, - strlen(instrument)+1,DFNT_INT8); - if(iStat == NX_ERROR) - { - return iStat; - } - - /* owner */ - iStat = NXputattr(pFile,"owner",owner, - strlen(owner)+1,DFNT_INT8); - if(iStat == NX_ERROR) - { - return iStat; - } - - /* Adress */ - iStat = NXputattr(pFile,"owner_adress",adress, - strlen(adress)+1,DFNT_INT8); - if(iStat == NX_ERROR) - { - return iStat; - } - - /* phone */ - iStat = NXputattr(pFile,"owner_telephone_number",phone, - strlen(phone)+1,DFNT_INT8); - if(iStat == NX_ERROR) - { - return iStat; - } - - /* fax */ - iStat = NXputattr(pFile,"owner_fax_number",fax, - strlen(fax)+1,DFNT_INT8); - if(iStat == NX_ERROR) - { - return iStat; - } - - /* email */ - iStat = NXputattr(pFile,"owner_email",email, - strlen(email)+1,DFNT_INT8); - if(iStat == NX_ERROR) - { - return iStat; - } - return NX_OK; - } -@} - -\subsubsection{NXUentergroup} - -@d enterg @{ - NXstatus NXUentergroup(NXhandle hFil, char *name, char *class) - { - void (*ErrFunc)(void *pData, char *pErr); - int iRet; - - /* ACTION, first install dummy error handler */ - ErrFunc = NXIReportError; - NXMSetError(NXpData, DummyError); - - /* try opening vGroup */ - iRet = NXopengroup(hFil, name, class); - NXMSetError(NXpData,ErrFunc); - if(iRet == NX_OK) - { - return NX_OK; - } - else - { - /* we need to create it */ - iRet = NXmakegroup(hFil,name,class); - if(iRet != NX_OK) - { - /* a comment on this one has already been written! */ - return iRet; - } - iRet = NXopengroup(hFil,name,class); - if(iRet != NX_OK) - { - /* a comment on this one has already been written! */ - return iRet; - } - } - return NX_OK; - } -@} -\subsubsection{NXUenterdata} -@d enterd @{ - NXstatus NXUenterdata(NXhandle hFil, char *label, int datatype, - int rank, int dim[], char *pUnits) - { - void (*ErrFunc)(void *pData, char *pErr); - int iRet; - - /* ACTION, first install dummy error handler */ - ErrFunc = NXIReportError; - NXMSetError(NXpData, DummyError); - - /* try opening SDS */ - iRet = NXopendata(hFil, label); - NXMSetError(NXpData,ErrFunc); - if(iRet == NX_OK) - { - return NX_OK; - } - else - { - /* we need to create it */ - iRet = NXmakedata(hFil,label, datatype, rank,dim); - if(iRet != NX_OK) - { - /* a comment on this one has already been written! */ - return iRet; - } - iRet = NXopendata(hFil,label); - if(iRet != NX_OK) - { - /* a comment on this one has already been written! */ - return iRet; - } - iRet = NXputattr(hFil, "Units",pUnits, - strlen(pUnits) + 1,DFNT_INT8); - if(iRet != NX_OK) - { - /* a comment on this one has already been written! */ - return iRet; - } - } - return NX_OK; - } -@} - -\subsubsection{NXUallocSDS} -@d allocs @{ - NXstatus NXUallocSDS(NXhandle hFil, void **pData) - { - int iDIM[MAX_VAR_DIMS]; - int iRank,iType; - int iRet, i; - long lLength; - - /* get info */ - iRet = NXgetinfo(hFil,&iRank, iDIM, &iType); - if(iRet != NX_OK) - { - return iRet; - } - - /* calculate Size */ - lLength = iDIM[0]; - for(i = 1; i < iRank; i++) - { - lLength *= iDIM[i]; - } - switch(iType) - { - case DFNT_FLOAT32: - lLength *= sizeof(float32); - break; - case DFNT_FLOAT64: - lLength *= sizeof(float64); - break; - case DFNT_INT8: - lLength *= sizeof(int8); - break; - case DFNT_UINT8: - lLength *= sizeof(uint8); - break; - case DFNT_INT16: - lLength *= sizeof(int16); - break; - case DFNT_UINT16: - lLength *= sizeof(uint16); - break; - case DFNT_INT32: - lLength *= sizeof(int32); - break; - case DFNT_UINT32: - lLength *= sizeof(uint32); - break; - default: - NXIReportError(NXpData,"ERROR: Internal: number type not recoginized"); - return NX_ERROR; - } - - /* time to malloc */ - *pData = NULL; - *pData = malloc(lLength); - if(*pData == NULL) - { - NXIReportError(NXpData,"ERROR: memory exhausted in NXUallocSDS"); - return NX_ERROR; - } - return NX_OK; - } -@} - -@d free @{ - NXstatus NXUfreeSDS(void **pData) - { - free(*pData); - *pData = NULL; - return NX_OK; - } -@} - -\section{Files} -@o nxdict.h -d @{ -/*--------------------------------------------------------------------------- - NXDICT API header file - - copyleft: Mark Koennecke, March 1997 at LNS,PSI, Switzerland - - No warranties of any kind taken. -----------------------------------------------------------------------------*/ -#ifndef NXDICTAPI -#define NXDICTAPI -#include "napi.h" /* make sure, napi is included */ - -/*-------------------- NXDict data types & defines ----------------------*/ -@ -#define NXquiet 0 -#define NXalot 1 -/*-------------------- Dictionary Maintainance ----------------------------*/ -@ -/*----------------- Dictionary added data transfer -----------------------*/ -@ -/*-------------------- Utility Functions --------------------------------*/ -@ -#endif -@} - -@o nxdict.c -d @{ -/*--------------------------------------------------------------------------- - Nexus Dictionary API implementation file. - - For documentation see the nxdict.tex file which comes with this - distribution. - - copyleft: Mark Koennecke - Labor fuer Neutronenstreuung - Paul Scherrer Institut - CH-5232 Villigen-PSI - Switzerland - Mark.Koennecke@@psi.ch - - No warranties of any kind, whether explicit or implied, taken. - Distributed under the GNU copyleft license as documented elsewhere. - - August, 1997 - - Version: 1.0 ------------------------------------------------------------------------------*/ - -#include -#include -#include -#include -#include -#include -#include "lld.h" -#include "napi.h" -#include "stringdict.h" -#include "dynstring.h" -#include "nxdict.h" -/*------------------ The magic number used for pointer checking */ -#define NXDMAGIC 260558 -/*-------------------------------------------------------------------------- - Things defined in napi.c for error reporting ----------------------------------------------------------------------------*/ - extern void *NXpData; - extern void (*NXIReportError)(void *pData, char *pBuffer); -/*--------------------------------------------------------------------------*/ -#define DEFDEBUG 1 -/* define DEFDEBUG when you wish to print your definition strings before - action. This can help a lot to resolve mysteries when working with - dictionaries. -*/ -/*-------------------------------------------------------------------------*/ -@ -/*-------------------------------------------------------------------------*/ - static char *NXDIReadFile(FILE *fd) - { - char *pNew = NULL; - long lLength = 0; - - assert(fd); - - /* determine length of file */ - fseek(fd,0L,SEEK_END); - lLength = ftell(fd); - if(lLength <= 0) - { - return NULL; - } - fseek(fd,0L,SEEK_SET); - - /* allocate buffer */ - lLength += 3; - pNew = (char *)malloc(lLength*sizeof(char)); - if(!pNew) - { - return NULL; - } - memset(pNew,0,lLength); /* this ensures a 0 at the end */ - - /* read file */ - fread(pNew,sizeof(char),lLength-3,fd); - - /* check for existence of the NXDICT string in the file */ - if(strncmp(pNew,"##NXDICT-1.0",12) != 0 ) - { - NXIReportError(NXpData,"ERROR: This is NO NXdict file"); - free(pNew); - return NULL; - } - return pNew; - } -/*--------------------------------------------------------------------------*/ -@ -/*------------------------------------------------------------------------*/ -@ -/*--------------------------------------------------------------------------*/ - NXstatus NXDinitfromfile(char *filename, NXdict *pData) - { - NXdict pNew = NULL; - FILE *fd = NULL; - char *pBuffer = NULL; - char pError[512]; - -@ -@ -@ -@ - - if(iVerbosity == NXalot) - { - NXIReportError(NXpData, "NXDinitfrom: performed successfully"); - } - free(pBuffer); - *pData = pNew; - return NX_OK; - } -/*--------------------------------------------------------------------------*/ -@ -/*-------------------------------------------------------------------------*/ -@ -/*------------------------------------------------------------------------*/ -@ -/*-----------------------------------------------------------------------*/ -@ -/*------------------- The Defintion String Parser -----------------------*/ -/*------- Data structures */ -@ -@ -@ -@ -/*------------------------------------------------------------------------*/ -@ -/*------------------------------------------------------------------------*/ -@ -/*------------------------------------------------------------------------*/ -@ -/*------------------------------------------------------------------------*/ -@ -/*------------------------------------------------------------------------*/ -@ -/*-------------------------------------------------------------------------*/ -@ -/*------------------------------------------------------------------------*/ -@ -/*------------------------------------------------------------------------*/ -@ -/*----------------------------------------------------------------------*/ -@ -/*-------------------- The Data Transfer Functions ----------------------*/ -@ -/*------------------------------------------------------------------------*/ -@ -/*------------------------------------------------------------------------*/ -@ -/*------------------------------------------------------------------------*/ -@ -/*------------------------------------------------------------------------*/ -@ -/*------------------------------------------------------------------------*/ -@ -/*------------------------------------------------------------------------*/ -@ -/*-----------------------------------------------------------------------*/ -@ -/*-----------------------------------------------------------------------*/ -@ -/*-----------------------------------------------------------------------*/ -@ -/*-----------------------------------------------------------------------*/ -@ -/*----------------------------------------------------------------------*/ -@ -@} - -@o dict.c @{ -/*-------------------------------------------------------------------------- - D I C T - - This file exercises some of the NXDICT functionality for test purposes. - It can also serve as an example for the usage of the API. - - Mark Koennecke, August 1997 - - Upgraded to support file idetification and text replacement - - Mark Koennecke, April 1998 -----------------------------------------------------------------------------*/ -#include -#include -#include -#include -#include "dynstring.h" -#include "napi.h" -#include "nxdict.h" - - int main(int argc, char *argv[]) - { - NXdict pDict = NULL; - NXhandle hfil; - void *pData = NULL; - float fTina[3] = { 0.123, 0.234, 0.456}; - float fTest[3], fDelta; - float fTust[20*20]; - char pBuffer[132]; - int i; - - /* test nxdict */ - NXDinitfromfile("test.dict",&pDict); - NXopen("test.hdf",NXACC_CREATE,&hfil); - NXDadd(pDict,"Gundula", - "/entry1,NXentry/SphereOmeter,NXinstrument/SDS"); - NXDupdate(pDict,"Bea","/entry1,NXentry/SDS"); - NXDget(pDict,"Bea",pBuffer,131); - printf("Bea = %s\n",pBuffer); - NXDget(pDict,"Linda",pBuffer,131); - NXDopendef(hfil,pDict,pBuffer); - NXDputalias(hfil,pDict,"Tina",fTina); - NXDputalias(hfil,pDict,"Gina",fTina); - NXDgetalias(hfil,pDict,"Tina",fTest); - NXDgetalias(hfil,pDict,"Gina",fTest); - NXDputalias(hfil,pDict,"Linda",fTust); - NXDaliaslink(hfil,pDict,"Eva","Linda"); - NXDclose(pDict,"close.dict"); - NXclose(&hfil); - printf("NXDICT seemed to have worked \n"); - - /* test Utility functions */ - printf(" Proceeding to test of utility functions \n"); - NXopen("test2.hdf",NXACC_CREATE,&hfil); - NXUwriteglobals(hfil, - "test2.hdf", - "Willibald Wuergehals", - "Rue des Martyrs, 26505 Timbuktu, Legoland ", - "+41-56-3102512", - "Nobody@@nowhere.edu", - " 755-898767", - "Dingsbums"); - NXUentergroup(hfil, "TestGroup", "NXtest"); - NXclosegroup(hfil); - NXUentergroup(hfil, "TestGroup", "NXtest"); - - i = 120; - NXUenterdata(hfil,"TestData",DFNT_INT8, 1,&i,"Testis"); - NXclosedata(hfil); - NXUenterdata(hfil,"TestData",DFNT_INT8, 1,&i,"Testis"); - - NXUallocSDS(hfil,&pData); - NXUfreeSDS(&pData); - NXclose(&hfil); - printf("All tests seem to have worked OK, %s %s\n", - "but the test is pathetic\n", - "Do not rely, in any circumstances, on this test alone"); - - - } -@} -@o test.dict @{ -##NXDICT-1.0 -#---------------------------------------------------------------------------- -# A dictionary file for test purposes -# Mark Koennecke, August 1997 -#---------------------------------------------------------------------------- - -Linda = /entry1,NXentry/Wuerfelometer,NXinstrument/SDS Counts \ - -type DFNT_INT32 -rank 2 -dim {20,20} -attr {Units,Wuerfel} \ - -attr {axis,1} -Eva = \ - /entry1,NXentry/NXVGROUP -Chloe = /entry1,NXentry/NXLINK Linda -Bea = -Tina = /entry1,NXentry/InvertedTOPSI,NXinstrument/SDS Tina \ - -type DFNT_FLOAT32 -rank 1 -dim {3} -attr {Units,Fahrenheit} -Reptil = Alligator,NXanimal/ -Gina = /entry1,NXentry/$(Reptil)SDS Tina \ - -type DFNT_FLOAT32 -rank 1 -dim {3} -attr {Units,Fahrenheit} - -@} - -\end{document} diff --git a/nxscript.c b/nxscript.c index cbc75442..d555d90a 100644 --- a/nxscript.c +++ b/nxscript.c @@ -664,7 +664,7 @@ static void putArray(SConnection *pCon, SicsInterp *pSics, get array length */ status = Tcl_GetInt(tcl,argv[4],&length); - if(status == TCL_OK){ + if(status != TCL_OK){ sprintf(buffer,"ERROR: failed to convert %s to integer",argv[4]); SCWrite(pCon,buffer,eError); return; @@ -690,7 +690,7 @@ static void putArray(SConnection *pCon, SicsInterp *pSics, varData = (char *)Tcl_GetVar2(tcl,argv[3],num,0); if(varData != NULL){ status = Tcl_GetDouble(tcl,varData,&dVal); - if(status == TCL_OK){ + if(status != TCL_OK){ sprintf(buffer,"ERROR: failed to convert %s to double", varData); SCWrite(pCon,buffer,eError); diff --git a/o2t.c b/o2t.c index 4e166d6e..6359936c 100644 --- a/o2t.c +++ b/o2t.c @@ -144,7 +144,7 @@ iRet = pDrivInt->SetValue(self->pTheta,pCon, fVal); return iRet; } - return 0; /* inserted statement, guessed return value M.Z. */ + return 0; } /*-------------------------------------------------------------------------*/ static int O2TCheckStatus(void *pData, SConnection *pCon) diff --git a/rs232controller.c b/rs232controller.c index c472c809..0413a98a 100644 --- a/rs232controller.c +++ b/rs232controller.c @@ -403,6 +403,10 @@ void getRS232Error(int iCode, char *errorBuffer, } } /*--------------------------------------------------------------------*/ +int getRS232Timeout(prs232 self){ + return self->timeout; +} +/*--------------------------------------------------------------------*/ int initRS232(prs232 self) { int iRet; diff --git a/rs232controller.h b/rs232controller.h index 130babc0..074a4294 100644 --- a/rs232controller.h +++ b/rs232controller.h @@ -63,7 +63,7 @@ void getRS232Error(int iCode, char *errorBuffer, int errorBufferLen); - + int getRS232Timeout(prs232 self); int initRS232(prs232 self); void closeRS232(prs232 self); prs232 createRS232(char *host, int iPort); diff --git a/rs232controller.w b/rs232controller.w index 420560c0..a06cb5ca 100644 --- a/rs232controller.w +++ b/rs232controller.w @@ -67,7 +67,7 @@ The following interface functions are provided: void getRS232Error(int iCode, char *errorBuffer, int errorBufferLen); - + int getRS232Timeout(prs232 self); int initRS232(prs232 self); void closeRS232(prs232 self); prs232 createRS232(char *host, int iPort);