/* * cfortran prototypes for the needed fortran calls. */ #define MAXFIL 500 #define XPARSE_EOF -1 #ifdef __cplusplus extern "C" { #endif /* * Fakeit command implementation * Ben Dorman, Raytheon ITSS April 1999 * * xs_fakeit -- prompt user for information needed for creating * fake data and create it. * */ #define LOGICAL_STRICT #include #include #include #include #include #include #include #include "xstcl.h" #include "xscf.h" /* for file status checking */ #include #include int getFakeitInput(char* promptString, char** batchString, char** batchLine); #ifdef __cplusplus } #endif int xs_fakeit(ClientData cdata,Tcl_Interp* interp,int objc, Tcl_Obj* CONST objv[] ) { int newFiles[MAXFIL]; int newFakeType[MAXFIL]; int dontFake = 0; int i = 0; unsigned int parsePosn = 0; /* xparse parse position */ int fileno = 1; /* ifile - dataset number */ int status = 0; int inputStatus = 0; int ndata = 0; /* holder for number of datasets */ char* arg = NULL; /* arguments returned by fortran routines through Tcl result string*/ char* command = NULL; /* command string */ unsigned int ncommand = 0; /* length of command, excluding subsequent lines passed to routine by command script */ char* tmpString = NULL;/* temporary holder for entire input string */ char* outString = NULL;/* place to write result strings from fortran routines passed through the tcl interp token */ char* outStrPtr = NULL; /* placeholder for garbage collection */ char* promptString = NULL; /* place to write prompt strings */ char* batch = NULL; /* batch string, delimited by "&" characters */ char* batchPtr = NULL; char* buffer = NULL; /* input buffer from terminal prompts */ char* tmpBuf = NULL; char* tmpBufPtr = NULL; char* type = NULL; /* type character required for processing filenames */ char* prefix = NULL; char* ckPref = NULL; float time = 0; float crnm = 0; int cmdlen = 0; char none[] = "none"; char* fakeFileName = NULL; struct stat* statBuf = NULL; Tcl_Obj* cmdlineObj; /* statistics reporting */ int dataEnd = 0; float statistic = 0.; int fakeNone = 0; int newFilesForFake = 0; int* numFiles; /* declarations for use with regular expression handling */ int invalidFile = 0; int ival = 0; float rval = 0; Tcl_RegExp FakeitExp; char* start = NULL; char* end = NULL; char* bufEnd = NULL; char* dum = NULL; /* to cope with non-interactive (script) processing, split the input into command and batch substrings */ if ( (ndata = numberOfDataSets()) == 0 && objc == 1) { char* msg = "Error: no responses defined (perhaps \"fakeit none\" was intended?)"; xs_tcl_write(msg,5); return TCL_OK; } if ( objc > 1 && !strcmp(Tcl_GetString(objv[1]), none) ) fakeNone = 1; cmdlineObj = Tcl_ConcatObj(objc,objv); dum = Tcl_GetStringFromObj(cmdlineObj,&cmdlen); command = (char *)malloc((cmdlen+1)*sizeof(char)); ncommand = strcspn(dum,"&"); strncpy(command,dum,ncommand); *(command + ncommand) = (char)NULL; /* strncpy doesn't null-terminate strings */ parsePosn = strcspn(command," "); if (ncommand < cmdlen ) { batch = (char *)malloc((cmdlen+1)*sizeof(char)); strcpy(batch,strchr(dum,'&')); batchPtr = batch; batch++; /* strip leading "&" */ } else { batch = (char *)malloc(sizeof(char)); batchPtr = batch; strcpy(batch,""); } for (i = 0; i < MAXFIL; i++) { newFiles[i] = 0; newFakeType[i] = 0; } /* call gtfkfl... */ getFakeFile(command,parsePosn,newFiles,newFakeType, &dontFake); free(command); command = NULL; /* process response file names */ /* dontFake is non-zero if there are no datasets defined or arguments to fakeit. In this case, quietly exit */ if (dontFake == 0 ) { promptString = (char *)malloc(256*sizeof(char)); if ( strlen(Tcl_GetStringResult(interp)) > 0 ) { outString = (char *)malloc((strlen(Tcl_GetStringResult(interp))+1)*sizeof(char)); strcpy(outString, Tcl_GetStringResult(interp)); } else { outString = (char *)malloc(2*sizeof(char)); strcpy(outString, " "); } outStrPtr = outString; arg = returnDelimitedArgument(&outString," \n"); } else { free (batchPtr); return TCL_ERROR; } while (arg != NULL) { char r[] = "r"; /* removes warning generated from cfortran call */ char a[] = "a"; status = sscanf(arg ,"%d",&fileno); assert (status == 1 ); /* if input is "/*" (inputStatus == XPARSE_EOF) we must delete datasets and exit since gtfkfl has already deleted all previous data and set up pointers for the fake data. On the other hand, '/' uses default for this value */ sprintf(promptString, "For fake data, file #%4d needs response file: ",fileno); inputStatus = getFakeitInput(promptString,&batch,&buffer); if( inputStatus == XPARSE_EOF) break; FPAUXF(fileno,buffer,r,inputStatus); if ( (*buffer == '/' && strlen(buffer) <= 2) || strlen(buffer) == 0 ) { strcpy(buffer,"none"); invalidFile = 1; FPAUXF( fileno,none,r,inputStatus); } else { newFilesForFake++; invalidFile = 0; } if (!invalidFile) { sprintf(promptString, " ... and ancillary response file: "); inputStatus = getFakeitInput(promptString,&batch,&buffer); if (inputStatus == XPARSE_EOF) break; if ( (*buffer == '/' && strlen(buffer) <= 2) || strlen(buffer) == 0) { FPAUXF( fileno,none,a,inputStatus); } else { FPAUXF(fileno,buffer,a,inputStatus); } } free(arg); arg = returnDelimitedArgument(&outString," \n"); fileno++; } if (inputStatus == XPARSE_EOF || invalidFile ) { /* user changed mind and decided not to do this. clear all datasets and exit quietly after tidying up.*/ free(batchPtr); free(command); free(promptString); free (buffer); Tcl_Eval(interp,"data none"); return TCL_OK; } /* otherwise, setup the newFiles and newFakeType array for the number of valid responses that can be used for fake data */ numFiles = (int *)malloc(sizeof(int)); setFakeFile(newFiles,newFakeType, *numFiles); /* now process names. If we got here with no command line arguments, then the existing dataset response files should be used. Otherwise, they will have been set up with setFakeFile */ Tcl_ResetResult(interp); strcpy(outString,""); if (*numFiles > 0) { char* tmpPtr = NULL; unsigned int lp = 0; outString = setFake(newFakeType); /* if existing datasets are to be used, need to allocate memory for the prompt string & return buffer, since the loop earlier was skipped */ if ( promptString == NULL ) { promptString = (char *)malloc(65*sizeof(char)); } /* arg should never be null if we are here, because there must be at least one dataset to provide a response matrix for fake data. */ free(arg); arg = returnDelimitedArgument(&outString," \n"); /* we can also get here with arg = "" if the only data set is a dummy response, which would return a blank string here */ if ( arg == NULL ) { char* msg = "Error: only a dummy response is present (perhaps \"fakeit none\" was intended?)"; xs_tcl_write(msg,5); return TCL_OK; } assert (arg != NULL); /* process the results from the randomization question */ sprintf(promptString,"Use randomization in creating fake data? (y) "); inputStatus = getFakeitInput(promptString,&batch,&buffer); if (inputStatus == XPARSE_EOF) goto reset; while (1) { if ( strchr("/yY",*buffer) != NULL || strlen(buffer) == 0) { DPQFST(1,inputStatus); break; } else { if (strchr("nN",*buffer) != NULL ) { DPQFST(0, inputStatus ); break; } else inputStatus = getFakeitInput( "Answer yes (/Yy) or no (Nn):",&batch,&buffer); if (inputStatus == XPARSE_EOF) goto reset; } } /* prompt user for prefix for fakeit simulation data. The filename is limited to 15 characters, which affects the length of the prefix. */ type = (char *)malloc(2*sizeof(char)); status = sscanf(arg,"%d:%s", &fileno, type); if (!strcmp(type,"d") ) tmpPtr = dataFilename(fileno); else tmpPtr = auxFilename(fileno,type); i = strcspn(tmpPtr,"."); /* however, if we happen to be given a long response filename, give the user a 4 character identifier. */ lp = MAX(12 - i,4); /* so we get <= 15 char filenames, i = length of /* datafile stem + .xxx for the extension == 15 - (i+4) /* ... plus one for the terminator. = 15 - i /* process the name string arguments */ sprintf(promptString,"Input optional fake file prefix (max %d chars): ",lp); inputStatus = getFakeitInput(promptString,&batch,&buffer); if (inputStatus == XPARSE_EOF) goto reset; if ( strchr("/\n",*buffer) == NULL) { prefix = (char* )malloc((lp+1)*sizeof(char)); strcpy(prefix,""); ckPref = buffer; while ( ckPref < (buffer + lp) && (*ckPref != '\0') ) { if ( !isdigit(*ckPref) && !isalpha(*ckPref) ) { xs_tcl_write("Prefix must consist of alphanumeric string",5); inputStatus = getFakeitInput("Prefix:",&batch,&buffer); ckPref = buffer; } else ckPref++; } lp = MIN(strlen(buffer),lp); strncpy(prefix,buffer,lp); *(prefix + lp) = '\0'; } else { prefix = (char *)malloc(sizeof(char)); strcpy(prefix,""); } while (arg != NULL) { fakeFileName = (char *)malloc(256*sizeof(char)); strcpy(fakeFileName,prefix); strncat(fakeFileName,tmpPtr,i); strcat(fakeFileName,".fak"); /* fakefileName defaults to the value generated in NAMFAK */ while (1) { sprintf(promptString, " Fake data filename (%s) [/ to use default]: ",fakeFileName); inputStatus = getFakeitInput(promptString,&batch,&buffer); if (inputStatus == XPARSE_EOF) goto reset; /* * Set the name of the fake data output file if they chose not to * use the default. */ if ( ! (strlen(buffer)==0 || (strlen(buffer)==1 && buffer[0] == '/')) ) { if (checkForFileOpen(buffer,"w")) { strcpy(fakeFileName,buffer); } else { tmpString = (char* )malloc(256*sizeof(char)); sprintf(tmpString, "File %s is not writeable: using default: %s\n", buffer,fakeFileName); XWRITE(tmpString,5); free(tmpString); } } FPFLNM(fileno,fakeFileName,inputStatus); /* note for future reference: stat call is system dependent. It is correct for Unix. Windows NT requires _stat(). But both behave the same way: they return 0 if the file exists or ENOENT if not - plus other retcodes for file writing problems Bypass this test if we are executing a script, in which case XSPEC will always overwrite the existing file. */ if ( !executingScript ) { struct stat* test = (struct stat*) malloc(sizeof(struct stat)); if ( !stat(fakeFileName,test) ) { sprintf(promptString, "File %s exists - overwrite? (yY/) or (nN)", fakeFileName); inputStatus = getFakeitInput(promptString,&batch,&buffer); if (inputStatus == XPARSE_EOF) break; if ( strchr("yY/",*buffer) != NULL) { break; } else { sprintf(promptString,"Enter new name: "); inputStatus = getFakeitInput(promptString, &batch,&buffer); if (inputStatus == XPARSE_EOF) break; strcpy(fakeFileName,buffer); FPFLNM(fileno,fakeFileName,inputStatus); } } free(test); } break; } if (inputStatus == XPARSE_EOF) goto reset; DWTIME(time, fileno); DWCRNM(crnm, fileno); sprintf(promptString," Exposure time, correction norm (%g, %g): ", time,crnm); inputStatus = getFakeitInput(promptString,&batch,&buffer); if (inputStatus == XPARSE_EOF) break; tmpBuf = (char*)malloc(strlen(buffer)+1); strcpy (tmpBuf,buffer); tmpBufPtr = tmpBuf; ival = 1; if ( strchr("/",*tmpBuf) == NULL && strlen(tmpBuf) != 0) /* if a '/' wasn't entered to indicate default */ /* values are requested, process the input */ { while (strlen(tmpBuf) > 0) { start = returnDelimitedArgument(&tmpBuf,",\t"); if ( sscanf(start,"%g",&rval)) { switch(ival) { case 1: DPTIME(fileno,rval,inputStatus); break; case 2: DPCRNM(fileno,rval,inputStatus); break; } } else { tmpString = (char *)malloc(256*sizeof(char)); sprintf(tmpString, "Unable to parse \"%s\" as a number. Default used", start); xs_tcl_write(tmpString,5); free(tmpString); } free(start); ival++; } } free (tmpBufPtr); free(fakeFileName); free(arg); arg = returnDelimitedArgument(&outString," \n"); if (arg != NULL) { status = sscanf(arg,"%d:%s", &fileno, type); if (!strcmp(type,"d") ) tmpPtr = dataFilename(fileno); else tmpPtr = auxFilename(fileno,type); } } /* while arg != NULL */ if (inputStatus == XPARSE_EOF) goto reset; dataEnd = endBin(ndata); makeFakeData(newFiles,newFakeType, statistic, MAXFIL); XPFSTT(statistic, inputStatus); writeStat(); } /* if ndata > 0 */ free (buffer); free(statBuf); free(prefix); free (promptString); free (outStrPtr); free (batchPtr); return TCL_OK; reset: XWRITE("Error: insufficient arguments supplied to fakeit command\n",5); free(statBuf); free(prefix); free (outStrPtr); free (promptString); free (buffer); free (batchPtr); Tcl_Eval(interp,"data none"); return TCL_ERROR; } /* return buffer string either from the terminal prompt or a string */ int getFakeitInput(char* promptString, char** batchString, char** buffer) { int status = 0; if (executingScript && strlen(*batchString) == 0) return XPARSE_EOF; if ( executingScript || (strlen(*batchString) > 0) ) { char* bufTmp = NULL; char* bufTmpPtr = NULL; int nc = 0; free(*buffer); *buffer = 0; bufTmp = returnDelimitedArgument(batchString,"&\n"); bufTmpPtr = bufTmp; if (bufTmp == NULL || strlen(bufTmp) == 0) { bufTmp = (char *)malloc(sizeof(char)); strcpy(bufTmp,""); } else { while (strchr (" \t",*bufTmp) != NULL ) bufTmp++; } nc = strcspn(bufTmp," \t"); *buffer = (char*) malloc((nc+1)*sizeof(char)); strncpy(*buffer,bufTmp,nc); (*buffer)[nc] = '\0'; free(bufTmpPtr); if ( executingScript) { bufTmp = (char *)malloc((strlen(*buffer)+1)*sizeof(char)); strcpy(bufTmp,*buffer); xs_tcl_read(promptString,bufTmp,&status); free(bufTmp); } else { char* outStr = NULL; outStr = (char*) malloc(strlen(promptString)+strlen(*buffer)+4); sprintf(outStr,"!%s %s",promptString,*buffer); XWRITE(outStr,5); free(outStr); outStr = NULL; } } else { *buffer = (char *)malloc((XCM_LEN+1)*sizeof(char)); xs_tcl_read(promptString,*buffer,&status); } return status; }