/*ScianScripts.c Stuff for scripts in scian Eric Pepke */ #include "Scian.h" #include "ScianTypes.h" #include "ScianArrays.h" #include "ScianIDs.h" #include "ScianEvents.h" #include "ScianRecorders.h" #include "ScianColors.h" #include "ScianWindows.h" #include "ScianObjWindows.h" #include "ScianDialogs.h" #include "ScianVisWindows.h" #include "ScianScripts.h" #include "ScianSliders.h" #include "ScianTimers.h" #include "ScianMethods.h" #include "ScianLists.h" #include "ScianErrors.h" #include "ScianGarbageMan.h" #include "ScianSpaces.h" #include "ScianIcons.h" #include "ScianSockets.h" #include "ScianObjFunctions.h" #include "ScianHelp.h" #include "ScianStyle.h" #include "ScianNames.h" #define SCRIPTALLOCBATCH 200 /*Batch to allocate script*/ Bool runningScript = false; /*True iff running script*/ Bool settingUp = false; /*True iff setting up*/ WinInfoPtr scriptWindow = 0; /*The current window of the script*/ extern ObjPtr perspecControlClass; /*Class of perspecive controls*/ long framesLeft = 0; /*Frames left to record*/ Bool abortScript = false; /*Abort script*/ FILE *curScript = 0; /*Current script being read, if any*/ char *scriptLine = 0; /*Current line of the script*/ int nScriptCharsAllocated = 0; /*Number of script characters allocated*/ Bool lineAccepted = true; /*True iff last script line was accepted*/ /*IDs for running tasks*/ #define RT_NONE 0 /*No running task*/ #define RT_RECORDING 1 /*Recording some time*/ int runningTask = RT_NONE; /*Current running task*/ #define MAXSTACKDEPTH 100 /*Maximum depth of block stack*/ /*Block in a stack*/ typedef struct { int command; /*The command*/ ObjPtr object; /*The (optional) object this is about*/ } Block; Block commandStack[MAXSTACKDEPTH]; /*Stack of commands*/ int nextStackElement = 0; /*Next element on the stack*/ typedef struct /*Element of file logging stack*/ { FILE *logFile; /*File pointer for logging*/ int logInhibit; /*Counter to inhibit logging*/ WinInfoPtr logWindow; /*Current window set in log*/ } LogElement; #define MAXLOGFILES 50 /*Maximum number of log files open*/ LogElement logStack[MAXLOGFILES]; /*Stack of log files*/ int nextLogElement = 0; /*Next element on the stack*/ #define KWBEGIN 0 /*Begin a block*/ #define KWEND 1 /*End current modal command*/ #define KWRECORDER 2 /*(set) recorder*/ #define KWDESELECT 3 /*Deselect an icon*/ #define KWSELECT 4 /*Select an icon*/ #define KWSHELL 5 /*Shell escape*/ #define KWALIGNMENT 6 /*(Set) alignment*/ #define KWLOCATION 7 /*(Set) location*/ #define KWVIDEOSCREEN 8 /*Resize current window to video screen*/ #define KWFULLSCREEN 9 /*Resize current window to full screen*/ #define KWROTATE 10 /*Rotate space*/ #define KWSHOW 11 /*Show something*/ #define KWPANEL 12 /*(Show/Hide) the panel of icons*/ #define KWRECORDING 13 /*(Begin/End) recording*/ #define KWSNAP 14 /*Snap a single frame*/ #define KWWINDOW 15 /*Select a new window*/ #define KWSET 16 /*Set something*/ #define KWCONTROLS 17 /*(Show) controls for a vis object*/ #define KWPUSHWINDOW 18 /*Push a window behind all others*/ #define KWQUIT 19 /*Quit*/ #define KWSHEAR 20 /*Shear the matrix*/ #define KWFPS 21 /*(Set) fps*/ #define KWEYEPOSN 22 /*Eye position*/ #define KWROLL 23 /*Roll of eyeball*/ #define KWPITCH 24 /*Pitch of eyeball*/ #define KWYAW 25 /*Yaw of eyeball*/ #define KWRECTANGLE 26 /*Rectangle*/ #define KWHIDE 27 /*Hide the frame of a window*/ #define KWEXIT 28 /*Exit on next loop*/ #define KWVALUE 29 /*(Set) value of a something*/ #define KWFONT 30 /*(Set) the font of something*/ #define KWSIZE 31 /*(Set) the size of something's font*/ #define KWCLOSE 32 /*Closes a window*/ #define KWENDPOINTS 33 /*(Set) endpoints*/ #define KWDROP 34 /*Drops whatever is in the drag buffer*/ #define KWBOUNDS 35 /*(Set) the bounds of an object*/ #define KWTILE 36 /*Tile to a certain width and height*/ #define KWANNOTATION 37 /*Add annotation*/ #define KWFRAME 38 /*(Show/Hide) the frame of a window*/ #define KWLOCATE 39 /*Locate a window*/ #define KWDELETE 40 /*Delete stuff*/ #define KWSCRSAVE 41 /*Save the screen*/ #define KWRECORD 42 /*Record some number of seconds*/ #define KWSCREEN 43 /*(Set) screen*/ #define KWCOLOR 44 /*(Set) color*/ #define KWPREFERENCES 45 /*(Show) preferences*/ #define KWTIME 46 /*Time*/ #define KWOFF 47 /*(Turn) off*/ #define KWTURN 48 /*Turn (on/off)*/ #define KWON 49 /*(Turn) on*/ #define KWLINE 50 /*Make a new line*/ #define KWFUNCTIONBOX 51 /*(Set) Function box*/ #define KWFILESWINDOW 52 /*(Show) FilesWindow*/ #define KWSELECTALL 53 /*Selectall*/ #define KWDESELECTALL 54 /*Deselectall*/ #define KWHELP 55 /*(Show) help*/ #define KWFILEREADERS 56 /*(Show) fileReaders*/ #define KWDATASETS 57 /*(Show) datasets*/ #define KWROTATION 58 /*(Set) rotation*/ #define KWVERSION 59 /*Version*/ #define KWFRONT 60 /*(Show) front (panel controls)*/ #define KWBACK 61 /*(Show) back (panel controls)*/ #define KWSETUP 62 /*(Begin/End) setup*/ #define KWSAVE 63 /*Save something*/ #define KWTIMEREADOUT 64 /*Make a time readout*/ #define KWSPACE 65 /*(Show) space (controls)*/ #define KWEFFECT 66 /*Color special effect*/ #define KWKEEP 67 /*Keep changes to palette*/ #define KWREVERT 68 /*Revert to last saved palette*/ #define KWMODEL 69 /*Color model*/ #define KWSNAPSHOT 70 /*(Begin) Snapshot*/ #define KWOBSERVER 71 /*(Begin Snapshot) Observer*/ #define KWVARIABLE 72 /*(set) Variable */ #define KWOBJECT 73 /*(Begin Snapshot) */Object #define NKEYWORDS 74 /*Number of keywords*/ char *keywords[NKEYWORDS] = { "begin", "end", "recorder", "deselect", "select", "shell", "alignment", "location", "videoscreen", "fullscreen", "rotate", "show", "panel", "recording", "snap", "window", "set", "controls", "pushwindow", "quit", "shear", "fps", "eyeposn", "roll", "pitch", "yaw", "rectangle", "hide", "exit", "value", "font", "size", "close", "endpoints", "drop", "bounds", "tile", "annotation", "frame", "locate", "delete", "scrsave", "record", "screen", "color", "preferences", "time", "off", "turn", "on", "line", "functionbox", "fileswindow", "selectall", "deselectall", "help", "filereaders", "datasets", "rotation", "version", "front", "back", "setup", "save", "timereadout", "space", "effect", "keep", "revert", "model", "snapshot", "observer", "variable", "object" }; char *wholeLine; /*Pointer to the whole line for error*/ char *begToken, *endToken; /*Beginning and ending of current token*/ #ifdef PROTO Bool BeginCommand(char *); Bool EndCommand(char *); #else Bool BeginCommand(); Bool EndCommand(); #endif FILE *OpenLogFile(name) char *name; /*Opens a log file named name in the current directory. OpenLogFile and CloseLogFile may be nested. If !name, it's stdout*/ { struct timeval date; if (name) { logStack[nextLogElement] . logFile = fopen(name, "w"); } else { logStack[nextLogElement] . logFile = stdout; } if (logStack[nextLogElement] . logFile) { logStack[nextLogElement] . logInhibit = 0; logStack[nextLogElement] . logWindow = 0; } else { WinInfoPtr alertWindow; char msg[300]; getcwd(tempStr, TEMPSTRSIZE); sprintf(msg, "File %s cannot be saved in directory %s.", name, tempStr); alertWindow = AlertUser(UIERRORALERT, (WinInfoPtr) NULLOBJ, msg, (FuncTyp) 0, 1, "Oh Well"); SetVar((ObjPtr) alertWindow, HELPSTRING, NewString("A file cannot be saved in the specified directory. \ This is probably because the permissions on the directory are not set up to allow \ you to write to it. Check the permissions on the directory and try again.")); return 0; } /*Write out a version number as first line in file*/ fprintf(logStack[nextLogElement] . logFile, "%s\n", SCIANVERSION); /*And a time stamp*/ gettimeofday(&date, (struct timezone *)0); fprintf(logStack[nextLogElement] . logFile, "time %s\n", ctime(&date.tv_sec)); ++nextLogElement; } void CloseLogFile() /*Closes a log file opened by OpenLogFile.*/ { if (!nextLogElement) return; --nextLogElement; if (logStack[nextLogElement] . logFile != stdout) { fclose(logStack[nextLogElement] . logFile); } } Bool logBeginning = true; /*True iff it's at the beginning of a log line*/ Bool AnyLogging() /*Returns true iff any logging is to be done*/ { if (!logging) { return false; } if (logStack[nextLogElement - 1] . logInhibit) { return false; } return true; } void Log(s) char *s; /*Logs command s to all the open log files*/ { int whichLog; char *t; if (selWinInfo && GetPredicate((ObjPtr) selWinInfo, INHIBITLOGGING)) { return; } for (whichLog = nextLogElement - 1; whichLog >= 0; --whichLog) { if (logStack[whichLog] . logInhibit) { /*Done; don't do no more.*/ break; } if (logBeginning && selWinInfo && logStack[whichLog] . logWindow != selWinInfo) { /*Make a window command*/ char windowName[256]; int k; /*Copy window title*/ t = selWinInfo -> winTitle; k = 0; while (*t) { if (*t == ' ') { windowName[k++] = '_'; ++t; } else { if (!isalpha(*t) && ((k == 0) || !isdigit(*t))) { windowName[k++] = '\\'; } windowName[k++] = *t++; } } windowName[k] = 0; fprintf(logStack[whichLog] . logFile, "window %s\n", windowName); logStack[whichLog] . logWindow = selWinInfo; } fputs(s, logStack[whichLog] . logFile); } /*Determine if it's in a line*/ t = s; if (*t) { while (*t) ++t; --t; if (*t == '\n') { logBeginning = true; } else { logBeginning = false; } } } #ifdef PROTO void InhibitLogging(Bool whether) #else void InhibitLogging(whether) Bool whether; #endif /*Inhibits or disinhibits logging based on whether*/ { if (nextLogElement) { if (whether) { ++logStack[nextLogElement - 1] . logInhibit; } else { --logStack[nextLogElement - 1] . logInhibit; } } } #ifdef PROTO void LogVariable(ObjPtr object, NameTyp variable) #else void LogVariable(object, variable) ObjPtr object; NameTyp variable; #endif /*Logs a variable*/ { if (AnyLogging() && !GetPredicate(object, INHIBITLOGGING)) { char cmd[256]; char *s; sprintf(cmd, " set variable %s ", GetInternalString(variable)); s = &(cmd[0]); while (*s) ++s; PrintScriptObject(s, GetVar(object, variable)); while (*s) ++s; *s++ = '\n'; *s = 0; Log(cmd); } } void LogControl(object) ObjPtr object; { if (AnyLogging() && !GetPredicate(object, INHIBITLOGGING)) { char cmd[256]; char *s; sprintf(cmd, "set value "); s = &(cmd[0]); while (*s) ++s; MakeObjectName(s, object); while (*s) ++s; *s++ = ' '; PrintScriptObject(s, GetVar(object, VALUE)); while (*s) ++s; *s++ = '\n'; *s = 0; Log(cmd); } } void LogObjectName(object) ObjPtr object; /*Logs the name of an object*/ { char objName[400]; MakeObjectName(objName, object); Log(objName); } void ScriptError(e) char *e; /*Prints out an error e*/ { char *runner; fprintf(stderr, "%s\n", wholeLine); runner = wholeLine; while (runner < begToken) { fprintf(stderr, *runner == '\t' ? "\t" : " "); ++runner; } if (runner < endToken) { while (runner < endToken) { fprintf(stderr, "-"); ++runner; } } else { fprintf(stderr, "^"); } fprintf(stderr, "\n"); fprintf(stderr, "%s\n", e); if (abortScriptP) { abortScript = true; } } void SelectNamedWindow(name) char *name; /*Selects a window by name name*/ { WinInfoPtr namedWindow; namedWindow = GetWinFromTitle(name); if (!namedWindow) { ScriptError("Cannot find a unique window by that name."); return; } SelWindow(namedWindow); scriptWindow = namedWindow; } static ObjPtr testObj; static WinInfoPtr repWindow; static ObjPtr globalRep; void TestWindowOnObject(window) WinInfoPtr window; /*Tests to see if window has an object which represents testObj*/ { ObjPtr rep; if (rep = ObjectWhichRepresents(window, testObj)) { repWindow = window; globalRep = rep; } } void MakeObjectName(dest, object) char *dest; ObjPtr object; /*Makes a long object name from object and puts it into dest*/ { register char *s; ObjPtr name; ObjPtr representative = NULLOBJ; if (!IsWindow(object) && ((!IsValidWindow(selWinInfo)) || (!(representative = ObjectWhichRepresents(selWinInfo, object))))) { /*Must find a window that knows about the object*/ testObj = object; repWindow = (WinInfoPtr) 0; ForAllWindows(TestWindowOnObject); if (repWindow) { representative = globalRep; MakeObjectName(dest, (ObjPtr) repWindow); while (*dest) ++dest; } else { *dest++ = '?'; } *dest++ = ':'; } if (representative) { object = representative; } name = GetStringVar("MakeObjectName", object, NAME); if (!name) { *dest = 0; return; } /*Copy name*/ s = GetString(name); if (isdigit(*s)) { *dest++ = '\\'; } while (*s) { if (*s == ' ') { *dest++ = '_'; ++s; } else { if (!isalpha(*s) && !isdigit(*s)) { *dest++ = '\\'; } *dest++ = *s++; } } *dest = 0; } int ParseKeyword(s, l, n) char *s; char *l[]; int n; /*Parses keyword s in list l with number of elements n.Returns its number or -1 == not found, -2 == ambiguious.*/ { int match = -1; /*Last found match*/ int i, k; /*Counters*/ /*Seek an exact match*/ for (k = 0; k < n; ++k) { for (i = 0; s[i]; ++i) { if (tolower(s[i]) != tolower(l[k][i])) { break; } } if (!s[i] && !keywords[k][i]) { /*It's a match!*/ return k; } } /*Seek a partial match*/ for (k = 0; k < n; ++k) { for (i = 0; s[i]; ++i) { if (tolower(s[i]) != tolower(l[k][i])) { break; } } if (!s[i]) { /*It's a match!*/ if (match >= 0) { /*Double match*/ return -2; } match = k; } } return match; } #ifdef PROTO char *ParseArray(char *s, ObjPtr *o) #else char *ParseArray(s, o) char *s; ObjPtr *o; #endif /* Parses an array at s Returns s if the object was syntactically bad or null the first character after the object if it was OK. Puts in o the object if it was semantically valid Leavs o alone if it was not Generates a script error if syntactically or semantically invalid. Doesn't yet do arrays of higher order than vectors by recursion */ { char *r; r = s; SKIPBLANKS(r); if (*r != '[') { ScriptError("This is not a valid array"); return s; } ++r; SKIPBLANKS(r); /*Now, it's either some subvectors or a number*/ if (*r == '[') { /*Subvector*/ ScriptError("Arrays of higher order than vectors are not supported yet"); return s; } else { /*Simple numerical vector.*/ real *numBuf; /*Temporary buffer for holding real numbers*/ long bufSize; /*Size of temporary buffer*/ long vecSize; /*Size of the vector so far*/ char num[256]; /*Temporary number space*/ /*Allocate some storage*/ bufSize = 1000; vecSize = 0; numBuf = malloc(sizeof(real) * bufSize); if (!numBuf) { OMErr(); return s; } while (*r != ']') { SHIFTNUM(num, r); if (1 != sscanf(num, "%g", numBuf + vecSize)) { ScriptError("This cannot be read as a number"); free(numBuf); return s; } ++vecSize; if (vecSize > bufSize) { bufSize += 1000; numBuf = realloc(numBuf, bufSize); if (!numBuf) { OMErr(); return s; } } SKIPBLANKS(r); } ++r; /*Now make it into a vector*/ *o = NewRealArray(1, vecSize); if (!o) { free(numBuf); return s; } CArray2Array(*o, numBuf); free(numBuf); return r; } } #ifdef PROTO char *ParseObjectArg(char *s, ObjPtr *o) #else char *ParseObjectArg(s, o) char *s; ObjPtr *o; #endif /* Parses an object at s Returns s if the object was syntactically bad or null the first character after the object if it was OK. Puts in o the object if it was semantically valid Leavs o alone if it was not Generates a script error if syntactically or semantically invalid. */ { char arg[256]; char *r; r = s; /*Get to the first character*/ SKIPBLANKS(r); /*Based on one-char lookahead, parse the argument*/ if (*r == '-' || *r == '+' || *r == '.' || isdigit(*r)) { double val; /*It's a number*/ SHIFTNUM(arg, r); if (1 == sscanf(arg, "%lg", &val)) { *o = NewReal((real) val); } else { ScriptError("This number has bad syntax"); return s; } } else if (isalpha(*r) || (*r == '\\')) { /*It's an object name or NULLOBJ*/ SHIFTKW(arg, r); if (0 == strcmp2(arg, "NULLOBJ")) { *o = NULLOBJ; } else { ObjPtr list = NULLOBJ; if (*r == ':') { char arg2[256]; WinInfoPtr window; /*Compound name*/ ++r; SHIFTKW(arg2, r); if (strlen(arg2)) { window = GetWinFromTitle(arg); if (window) { list = FindNamedObject((ObjPtr) window, arg2); } else { ScriptError("Cannot find a unique window by that name."); return s; } } else { ScriptError("An object name is expected after the window name."); return s; } } else { if (scriptWindow && IsValidWindow(scriptWindow)) { list = FindNamedObject((ObjPtr) scriptWindow, arg); } else { ScriptError("There is no currently selected window."); } } if (!list || !LISTOF(list)) { ScriptError("There is no object by that name."); } else if (LISTOF(list) -> next) { ScriptError("That name is not unique."); } else { *o = LISTOF(list) -> thing; } } } else if (*r == '[') { return ParseArray(r, o); } else if (*r == '"') { int k; /*It's a string*/ begToken = r; ++r; k = 0; while (*r && *r != '"') { if (*r == '\\') { ++r; if (isdigit(*r)) { int nDigits, value; value = 0; nDigits = 0; do { value *= 8; value += *r - '0'; ++nDigits; ++r; } while (isdigit(*r) && nDigits < 3); tempStr[k++] = value; } else switch (*r) { case 'n': case 'N': tempStr[k++] = '\n'; ++r; break; case 't': case 'T': tempStr[k++] = '\t'; ++r; break; case 'r': case 'R': tempStr[k++] = '\r'; ++r; break; default: tempStr[k++] = *r++; } } else { tempStr[k++] = *r++; } } if (*r == '"') ++r; endToken = r; tempStr[k] = 0; *o = NewString(tempStr); } else switch(*r) { case 0: /*End of string, null object*/ *o = NULLOBJ; break; default: /*Who knows? Error*/ ScriptError("This is an unrecognized object"); return s; } return r; } char *PrintScriptString(dest, s) char *dest, *s; /*Prints a script string from s into dest*/ { *dest++ = '"'; while (*s) { if (*s == '"') { *dest++ = '\\'; } if (*s == '\n') { *dest++ = '\\'; *dest++ = 'n'; } else if (*s == '\t') { *dest++ = '\\'; *dest++ = 't'; } else if (*s == '\r') { *dest++ = '\\'; *dest++ = 'r'; } else if (*s < ' ') { *dest++ = '\\'; sprintf(tempStr, "%3o", *s); *dest++ = tempStr[0]; *dest++ = tempStr[1]; *dest++ = tempStr[2]; } else { *dest++ = *s; } ++s; } *dest++ = '"'; *dest = 0; return dest; } char *PrintScriptObject(s, object) char *s; ObjPtr object; /*Prints object into s as for inclusion into a script. Returns a pointer to the null afterward*/ { char *retVal; retVal = s; if (object == 0) { sprintf(retVal, "NULLOBJ"); while (*retVal) ++retVal; } else if (IsReal(object)) { /*Real number*/ sprintf(retVal, "%g", (float) GetReal(object)); while (*retVal) ++retVal; } else if (IsInt(object)) { sprintf(retVal, "%ld", (long) GetInt(object)); while (*retVal) ++retVal; } else if (IsRealArray(object) && RANK(object) == 1) { /*Vector*/ int k; real *meat; *retVal++ = '['; meat = ArrayMeat(object); for (k = 0; k < DIMS(object)[0]; ++k) { sprintf(retVal, "%g", *meat++); while (*retVal) ++retVal; if (k < DIMS(object)[0] - 1) *retVal++ = ' '; } *retVal++ = ']'; } else if (IsString(object)) { /*String*/ retVal = PrintScriptString(retVal, GetString(object)); } *retVal = 0; return retVal; } int FindCommandInStack(command) int command; /*Finds the topmost command command in the stack. Returns it's index or -1 if not found.*/ { int k; for (k = nextStackElement - 1; k >= 0; --k) { if (commandStack[k] . command == command) { break; } } return k; } Bool BeginCommand(args) char *args; /*Begins a begin-end block with command in args.*/ { char cmdNum; char arg[256]; if (nextStackElement >= MAXSTACKDEPTH) { ScriptError("There are too many nested begin-end blocks."); return true; } SHIFTKW(arg, args); if (strlen(arg)) { cmdNum = ParseKeyword(arg, keywords, NKEYWORDS); if (cmdNum == -1) { ScriptError("This command is unknown."); return true; } else if (cmdNum == -2) { ScriptError("This command is ambiguous."); return true; } } else { /*It's an anonymous block*/ cmdNum = KWBEGIN; } commandStack[nextStackElement] . command = cmdNum; commandStack[nextStackElement] . object = NULLOBJ; switch (cmdNum) { case KWBEGIN: Log("begin\n"); break; case KWRECORDING: Log("begin recording\n"); if (FindCommandInStack(KWRECORDING) >= 0) { ScriptError("The begin recording command cannot be nested."); return true; } else { real nSeconds; SHIFTNUM(arg, args); if (1 != sscanf(arg, "%g", &nSeconds)) { ScriptError("A maximum time in seconds is expected here."); return true; } if (nSeconds < 0.0) nSeconds = -nSeconds; if (ConnectRecorder()) { int nFrames; nFrames = (int) (nSeconds * 30.0); if (!PrepareToRecord(nFrames)) { ScriptError("There is a problem recording that many frames."); return true; } } else { ScriptError("Could not connect to the recorder."); return true; } } break; case KWSETUP: Log("begin setup\n"); settingUp = true; break; case KWSNAPSHOT: /*Beginning of an object snapshot*/ { ObjPtr value; value = ERROBJ; SKIPBLANKS(args); Log("begin snapshot "); Log(args); Log("\n"); args = ParseObjectArg(args, &value); if (value != ERROBJ) { commandStack[nextStackElement] . object = value; } else { ScriptError("An object for the snapshot is expected here"); commandStack[nextStackElement] . object = NULLOBJ; } } break; default: ScriptError("This command may not start a begin-end block"); return true; } ++nextStackElement; return true; } Bool EndCommand(args) char *args; /*Ends the top command on the stack, or up to command in args*/ { char arg[256]; if (!nextStackElement) { ScriptError("There are too many ends and not enough begins."); return true; } SHIFTKW(arg, args); if (strlen(arg)) { int cmdNum, cmdWhere; cmdNum = ParseKeyword(arg, keywords, NKEYWORDS); cmdWhere = FindCommandInStack(cmdNum); if (cmdWhere < 0) { ScriptError("There is no such block in force."); return true; } else { do { EndCommand(""); } while (commandStack[nextStackElement] . command != cmdNum); } } else { /*End the top command*/ --nextStackElement; switch(commandStack[nextStackElement] . command) { case KWBEGIN: Log("end\n"); break; case KWRECORDING: Log("end recording\n"); StopRecording(); DisconnectRecorder(); break; case KWSNAPSHOT: Log("end snapshot\n"); if (commandStack[nextStackElement] . object) { ImInvalid(commandStack[nextStackElement] . object); } break; case KWSETUP: Log("end setup\n"); settingUp = false; break; } } return true; } Bool DoSetCommand(kwn, args) int kwn; char *args; /*Does a set command*/ { char arg[256]; switch(kwn) { case KWVARIABLE: /*Set a variable within a snapshot*/ { int element; /*DIKEO put in type checking*/ element = FindCommandInStack(KWSNAPSHOT); if (element >= 0) { /*Do a setvar, just like it says*/ NameTyp internalID; ObjPtr value; SHIFTKW(arg, args); internalID = GetInternalID(arg); value = ERROBJ; args = ParseObjectArg(args, &value); if (value != ERROBJ) { if (commandStack[element] . object) { SetVar(commandStack[element] . object, internalID, value); LogVariable(commandStack[element] . object, internalID); } } else { ScriptError("A valid value is expected here"); } } else { ScriptError("A set variable command can only occur within a snapshot"); } } break; case KWRECORDER: { ObjPtr object; if (FindCommandInStack(KWRECORDING) >= 0) { ScriptError("You can't set the recorder while recording"); break; } object = ERROBJ; args = ParseObjectArg(args, &object); if (object != ERROBJ) { if (IsString(object)) { if (!SetRecorder(GetString(object))) { ScriptError("This recorder does not exist"); } } else { ScriptError("A quoted name of a recorder is expected here"); } } } break; case KWVALUE: /*Set the value of a control*/ { ObjPtr object, value; object = ERROBJ; args = ParseObjectArg(args, &object); if (object != ERROBJ) { if (object && IsObject(object)) { value = ERROBJ; args = ParseObjectArg(args, &value); if (value != ERROBJ) { SetValue(object, value); } else { ScriptError("A valid value is expected here"); } } else { ScriptError("An object name is expected here"); } } } break; case KWROTATION: { ObjPtr rotation, axis; rotation = ERROBJ; args = ParseObjectArg(args, &rotation); if (rotation != ERROBJ) { if (rotation && IsReal(rotation)) { axis = ERROBJ; args = ParseObjectArg(args, &axis); if (axis != ERROBJ && axis && IsRealArray(axis) && RANK(axis) == 1 && DIMS(axis)[0] == 3) { real *elements; real degrees; elements = ELEMENTS(axis); degrees = GetReal(rotation); SetRotationMotor(degrees * M_PI / 180.0, elements[0], elements[1], elements[2]); } else { ScriptError("A rotation axis is expected here"); } } else { ScriptError("A rotation speed is expected here"); } } } break; case KWFUNCTIONBOX: { ObjPtr object, functionBox; object = ERROBJ; args = ParseObjectArg(args, &object); if (object != ERROBJ) { if (IsObject(object)) { functionBox = ERROBJ; args = ParseObjectArg(args, &functionBox); if (functionBox != ERROBJ) { SetFunctionBox(object, functionBox); InhibitLogging(true); ImposeColorFunction(object); ForAllVisWindows(ImInvalid); InhibitLogging(false); } else { ScriptError("A valid function box is expected here"); } } else { ScriptError("An object name is expected here"); } } } break; case KWCOLOR: { ObjPtr object; int which, r, g, b; object = ERROBJ; args = ParseObjectArg(args, &object); if (object != ERROBJ) { if (IsObject(object)) { if (4 == sscanf(args, " %d %d %d %d \n", &which, &r, &g, &b)) { SetColorBarColor(object, which, r, g, b); } else { ScriptError("A color number and components are expected here"); } } else { ScriptError("An object name is expected here"); } } } break; case KWFONT: { ObjPtr object, value; object = ERROBJ; args = ParseObjectArg(args, &object); if (object != ERROBJ) { if (IsObject(object)) { SHIFTKW(arg, args); SetFont(object, arg); } else { ScriptError("An object name is expected here"); } } } break; case KWSIZE: { ObjPtr object, value; object = ERROBJ; args = ParseObjectArg(args, &object); if (object != ERROBJ) { if (IsObject(object)) { int size; SHIFTNUM(arg, args); if (1 == sscanf(arg, "%d", &size)) { SetSize(object, size); } else { ScriptError("A font size is expected here"); } } else { ScriptError("An object name is expected here"); } } } break; case KWALIGNMENT: { ObjPtr object, value; object = ERROBJ; args = ParseObjectArg(args, &object); if (object != ERROBJ) { if (IsObject(object)) { int alignment; SHIFTNUM(arg, args); if (1 == sscanf(arg, "%d", &alignment)) { SetAlignment(object, alignment); } else { ScriptError("An integer text alignment is expected here"); } } else { ScriptError("An object name is expected here"); } } } break; case KWLOCATION: { ObjPtr object, value; object = ERROBJ; args = ParseObjectArg(args, &object); if (object != ERROBJ) { if (IsObject(object)) { real location[3]; if (3 == sscanf(args, " [%g %g %g]", &(location[0]), &(location[1]), &(location[2]))) { ObjPtr var; var = NewRealArray(1, 3L); CArray2Array(var, location); SetVar(object, LOCATION, var); ImInvalid(object); if (logging) { char cmd[300]; char *s; sprintf(cmd, "set location "); s = &(cmd[0]); while (*s) ++s; MakeObjectName(s, object); while (*s) ++s; sprintf(s, " [%g %g %g]\n", location[0], location[1], location[2]); Log(cmd); } } else { ScriptError("A vector location is expected here"); } } else { ScriptError("An object name is expected here"); } } } break; case KWBOUNDS: { ObjPtr object; ObjPtr bounds; char *oldArgs; object = ERROBJ; oldArgs = args; args = ParseObjectArg(args, &object); if (object != ERROBJ) { if (IsObject(object)) { bounds = ERROBJ; args = ParseObjectArg(args, &bounds); if (bounds != ERROBJ) { if (IsRealArray(bounds) && RANK(bounds) == 1) { ObjPtr testBounds; testBounds = GetVar(object, BOUNDS); if (!testBounds || (IsRealArray(testBounds) && RANK(testBounds) == 1 && DIMS(testBounds)[0] == DIMS(bounds)[0])) { if (logging) { char cmd[256]; sprintf(cmd, "set bounds %s\n", oldArgs); Log(cmd); } SetVar(object, BOUNDS, bounds); ImInvalid(object); } else { ScriptError("These bounds are of wrong size for the object"); } } else { ScriptError("A vector is expected here"); } } } else { ScriptError("An object name is expected here"); } } } break; case KWENDPOINTS: { ObjPtr object; int x1, y1, x2, y2; char *oldArgs; object = ERROBJ; oldArgs = args; args = ParseObjectArg(args, &object); if (object != ERROBJ) { if (IsObject(object)) { if (4 == sscanf(args, " %d %d %d %d", &x1, &y1, &x2, &y2)) { SetEndpoints(object, x1, y1, x2, y2); ImInvalid(object); } else { ScriptError("Four endpoint coordinates are expected here"); } } else { ScriptError("An object name is expected here"); } } } break; case KWSCREEN: { /*Set the size of the recording screen*/ int x, y; if (2 != sscanf(args, " %d %d", &x, &y)) { ScriptError("A width and height of the recording screen is expected here"); break; } recScrWidth = x; recScrHeight = y; } break; case KWFPS: { /*Set the frames per second*/ real fps; if (1 != sscanf(args, " %g", &fps)) { ScriptError("A number of frames per second is expected here"); break; } SetFPS(fps); } break; default: ScriptError("This is not a paramater that can be set"); break; } return true; } Bool DoSaveCommand(kwn, args) int kwn; char *args; /*Does a save command*/ { char arg[256]; switch(kwn) { case KWCONTROLS: DoSaveObject(); break; default: ScriptError("This is not something that can be saved"); return; break; } return true; } Bool DoShowHideCommand(showp, kwn, args) Bool showp; int kwn; char *args; /*Does a show or hide command, showp is true iff it's show*/ { char arg[256]; switch(kwn) { case KWPANEL: if (showp) { DoShowPanel(); } else { DoHidePanel(); } break; case KWPREFERENCES: if (showp) { DoShowPreferences(); } else { ScriptError("You can't hide preferences this way. Close the window instead"); } break; case KWHELP: if (showp) { DoShowHelp(); } else { ScriptError("You can't hide help this way. Close the window instead"); } break; case KWDATASETS: if (showp) { PopDatasetsWindow(); } else { ScriptError("You can't hide the datasets window this way. Close the window instead"); } break; case KWFILEREADERS: if (showp) { PopFileReadersWindow(); } else { ScriptError("You can't hide the file readers window this way. Close the window instead"); } break; case KWFILESWINDOW: if (showp) { DoNewFileWindow(); } else { ScriptError("You can't hide the file window this way. Close the window instead"); } break; case KWFRAME: if (showp) { DoShowFrame(); } else { DoHideFrame(); } break; case KWFRONT: if (showp) { DoShowFrontPanelControls(); } else { ScriptError("You can't hide the front panel controls this way. Close the window instead"); } break; case KWBACK: if (showp) { DoShowBackPanelControls(); } else { ScriptError("You can't hide the back panel controls this way. Close the window instead"); } break; case KWSPACE: if (showp) { DoShowSpaceControls(); } else { ScriptError("You can't hide the space controls this way. Close the window instead"); } break; default: ScriptError("This keyword is not a settable parameter"); break; } return true; } #ifdef PROTO void ShowScriptControlPanels(Bool whether) #else void ShowScriptControlPanels(whether) Bool whether; #endif /*Turns subsequent showing of control panels within a script on or off*/ { showControlPanels = whether; Log(whether ? "turn show controls on\n" : "turn show controls off"); } void VersionCommand(args) char *args; /*Does a version command*/ { char arg[256]; float scianVersion, scriptVersion; SHIFTNUM(arg, args); if (1 != sscanf(arg, "%g", &scriptVersion)) { ScriptError("A number is expected here"); return; } if (1 != sscanf(SCIANVERSION, "Version %g", &scianVersion)) { ReportError("VersionCommand", "Internal error: cannot parse SciAn version"); return; } if (scianVersion < scriptVersion) { ScriptError("The script is newer than this version of SciAn"); if (abortScriptP) { abortScript = true; } } if (scianVersion > scriptVersion) { #if 0 ScriptError("The script is older than this version of SciAn"); if (abortScriptP) { abortScript = true; } #endif } } #ifdef PROTO void SelectCommand(char *args, Bool selectP) #else void SelectCommand(args, selectP) char *args; Bool selectP; #endif /*Does select or deselect depending on selectP*/ { ObjPtr object; object = ERROBJ; args = ParseObjectArg(args, &object); if (object != ERROBJ) { if (IsObject(object)) { Select(object, selectP); } else { ScriptError("An object name is expected here"); } } } #ifdef PROTO void TurnCommand(char *args) #else void TurnCommand(args) char *args; #endif /*Does turn show controls on/off. Normal turn on/off done by obj functions.*/ { char arg[256]; int kwn; SHIFTKW(arg, args); kwn = ParseKeyword(arg, keywords, NKEYWORDS); if (kwn == KWSHOW) { SHIFTKW(arg, args); kwn = ParseKeyword(arg, keywords, NKEYWORDS); if (kwn == KWCONTROLS) { SHIFTKW(arg, args); kwn = ParseKeyword(arg, keywords, NKEYWORDS); if (kwn == KWON) { ShowScriptControlPanels(true); } else if (kwn == KWOFF) { ShowScriptControlPanels(false); } } else { ScriptError("'Controls' is expected here"); } } else { ScriptError("Either 'on' or 'off' is expected here"); } } Bool DoScriptCommand(kwn, args) int kwn; char *args; /*Does command kwn with args*/ { char arg[256]; switch(kwn) { case KWVERSION: VersionCommand(args); break; case KWTIME: break; case KWDELETE: DoDelete(); break; case KWTURN: /*Turn show controls on/off. Turn on/off handled by objfunctions*/ TurnCommand(args); break; case KWSELECT: SelectCommand(args, true); break; case KWDESELECT: SelectCommand(args, false); break; case KWSELECTALL: DoSelectAllIcons(); break; case KWDESELECTALL: DeselectAll(); break; case KWANNOTATION: case KWTIMEREADOUT: case KWRECTANGLE: { char name[256]; ObjPtr bounds; SHIFTKW(name, args); if (strlen(name)) { bounds = ERROBJ; args = ParseObjectArg(args, &bounds); if (bounds != ERROBJ) { if (IsRealArray(bounds) && RANK(bounds) == 1 && DIMS(bounds)[0] == 4) { switch(kwn) { case KWANNOTATION: AddAnnotation(name, ArrayMeat(bounds)); break; case KWTIMEREADOUT: AddTimeReadout(name, ArrayMeat(bounds)); break; case KWRECTANGLE: AddRectangle(name, ArrayMeat(bounds)); break; } } else { ScriptError("A 4-vector is expected here"); } } } else { ScriptError("A name is expected here"); } } break; case KWLINE: { char name[256]; int x1, y1, x2, y2; SHIFTKW(name, args); if (strlen(name)) { if (4 == sscanf(args, " %d %d %d %d", &x1, &y1, &x2, &y2)) { AddLine(name, x1, y1, x2, y2); } else { ScriptError("Four endpoint coordinates are expected here"); } } else { ScriptError("A name is expected here"); } } break; case KWSET: /*Set something or other*/ { int k; SHIFTKW(arg, args); /*Find out what to set*/ kwn = ParseKeyword(arg, keywords, NKEYWORDS); if (kwn == -1) { ScriptError("This parameter is unknown."); break; } else if (kwn == -2) { ScriptError("This parameter is ambiguous."); break; } else { return DoSetCommand(kwn, args); } } break; case KWSAVE: /*Save something or other*/ { int k; SHIFTKW(arg, args); /*Find out what to set*/ kwn = ParseKeyword(arg, keywords, NKEYWORDS); if (kwn == -1) { ScriptError("This parameter is unknown."); break; } else if (kwn == -2) { ScriptError("This parameter is ambiguous."); break; } else { return DoSaveCommand(kwn, args); } } break; case KWSHOW: /*Show something or other*/ { int k; SHIFTKW(arg, args); /*Find out what to set*/ kwn = ParseKeyword(arg, keywords, NKEYWORDS); if (kwn == -1) { ScriptError("This parameter is unknown."); break; } else if (kwn == -2) { ScriptError("This parameter is ambiguous."); break; } else { return DoShowHideCommand(true, kwn, args); } } break; case KWHIDE: /*Hide something or other*/ { int k; SHIFTKW(arg, args); /*Find out what to set*/ kwn = ParseKeyword(arg, keywords, NKEYWORDS); if (kwn == -1) { ScriptError("This parameter is unknown."); break; } else if (kwn == -2) { ScriptError("This parameter is ambiguous."); break; } else { return DoShowHideCommand(false, kwn, args); } } break; case KWDROP: { int dropX, dropY; SHIFTNUM(arg, args); if (1 != sscanf(arg, "%d", &dropX)) { ScriptError("A number is expected here"); break; } SHIFTNUM(arg, args); if (1 != sscanf(arg, "%d", &dropY)) { ScriptError("A number is expected here"); break; } if (scriptWindow && dragBuffer) { FuncTyp method; /*Drop*/ method = GetMethod((ObjPtr) scriptWindow, DROPOBJECTS); if (method) { iconXOff = 0; iconYOff = 0; if (logging) { char cmd[256]; sprintf(cmd, "drop %d %d\n", dropX, dropY); Log(cmd); InhibitLogging(true); } (*method)(scriptWindow, dragBuffer, dropX, dropY); DeleteThing(dragBuffer); dragBuffer = NULLOBJ; if (logging) { InhibitLogging(false); } } } else { ScriptError("There is no selected window"); } } break; case KWVIDEOSCREEN: DoVideoScreen(); break; case KWFULLSCREEN: DoMaxScreen(); break; case KWTILE: { int width, height; SHIFTNUM(arg, args); if (1 != sscanf(arg, "%d", &width)) { ScriptError("A width is expected here"); break; } SHIFTNUM(arg, args); if (1 != sscanf(arg, "%d", &height)) { ScriptError("A height is expected here"); break; } Tile(width, height); } break; case KWLOCATE: { int l, r, b, t; if (4 != sscanf(args, " %d %d %d %d", &l, &r, &b, &t)) { ScriptError("The bounds of the window are expected here."); return true; } LocateWindow(l, r, b, t); } break; case KWEYEPOSN: { if (scriptWindow) { ObjPtr array, observer /*, observers*/; array = ERROBJ; args = ParseObjectArg(args, &array); if (array != ERROBJ) { observer = FindObserver(scriptWindow); if (!observer) break; if (IsArray(array) && RANK(array) == 1 && DIMS(array)[0] == 3) { real *p; SetVar(observer, LOCATION, array); ImInvalid(observer); p = ELEMENTS(array); if (logging) { char cmd[256]; sprintf(cmd, "eyeposn [%g %g %g]\n", p[0], p[1], p[2]); Log(cmd); } } else { ScriptError("A 3-vector is expected here"); } } } } break; case KWROLL: { float value; SHIFTKW(arg, args); if (strlen(arg) && 1 == sscanf(arg, " %g", &value)) { if (scriptWindow) { ObjPtr observer /*, observers*/; observer = FindObserver(scriptWindow); if (!observer) break; SetVar(observer, ROLL, NewReal(value)); } } else { ScriptError("An amount to roll is expected here."); } } break; case KWPITCH: { float value; SHIFTKW(arg, args); if (strlen(arg) && 1 == sscanf(arg, " %g", &value)) { if (scriptWindow) { ObjPtr observer/*, observers*/; observer = FindObserver(scriptWindow); if (!observer) break; SetVar(observer, PITCH, NewReal(value)); } } else { ScriptError("An amount to pitch is expected here."); } } break; case KWYAW: { ScriptError("YAW is no longer supported."); } break; case KWROTATE: { char axis; float amount; SHIFTKW(arg, args); if (strlen(arg) == 1 && (*arg == 'x' || *arg == 'y' || *arg == 'z')) { axis = *arg; SHIFTNUM(arg, args); if (!strlen(arg) || 1 != sscanf(arg, "%f", &amount)) { ScriptError("An amount to rotate is expected here."); return true; } if (scriptWindow) { RotateOrthoWindow(scriptWindow, axis, amount); } } else { ScriptError("Unrecognized keyword. An axis (x, y, or z) is expected."); } return true; } break; case KWSHEAR: ScriptError("Shearing is no longer supported."); return true; break; case KWRECORD: if (FindCommandInStack(KWRECORDING) < 0) { ScriptError("This command can only exist within a BEGIN RECORDING block."); return true; } else { real nSecs; if (1 != sscanf(args, " %g", &nSecs)) { ScriptError("A number of seconds to record is expected here."); } else { runningTask = RT_RECORDING; framesLeft = nSecs * 30 + 0.5; } return false; } case KWBEGIN: return BeginCommand(args); case KWEND: return EndCommand(args); case KWSNAP: if (FindCommandInStack(KWRECORDING) < 0) { ScriptError("This command can only exist within a BEGIN RECORDING block."); return true; } if (!SnapOneFrame()) { ScriptError("Could not snap a single frame."); } ++TrashDayFlag; break; case KWWINDOW: SHIFTKW(arg, args); if (!strlen(arg)) { ScriptError("The name of a window is expected here"); return true; } SelectNamedWindow(arg); break; case KWEXIT: case KWQUIT: DoQuit(); break; case KWCLOSE: CloseWindow(scriptWindow); SelWindow(0); scriptWindow = 0; break; case KWPUSHWINDOW: if (scriptWindow) { PushWindow(scriptWindow); } else { ScriptError("There is no current window"); } break; case KWSHELL: /*Shell escape*/ SKIPBLANKS(args); if ((getuid() == geteuid()) && (getgid() == getegid())) { system(args); } break; case KWSCRSAVE: { char fileName[256]; int l, r, b, t; int n; n = sscanf(args, " %s %d %d %d %d", fileName, &l, &r, &b, &t); if (n == 5) { sprintf(tempStr, "scrsave %s %d %d %d %d", fileName, l, r, b, t); if ((getuid() == geteuid()) && (getgid() == getegid())) { system(tempStr); } } else if (n == 1) { sprintf(tempStr, "scrsave %s", fileName); if ((getuid() == geteuid()) && (getgid() == getegid())) { system(tempStr); } } else { ScriptError("A filename and four sides are expected here"); return true; } } break; case KWEFFECT: { /*Color effect*/ int whichFunc; SHIFTKW(arg, args); whichFunc = ParseKeyword(arg, spfNames, NPALETTEFUNCS); if (whichFunc >= 0) { #ifdef MENUSFROM0 SimpleFuncFromMenu(whichFunc); #else SimpleFuncFromMenu(whichFunc + 1); #endif } else { ScriptError("This special effect is not defined"); } } break; case KWMODEL: { /*Color model*/ int whichFunc; SHIFTKW(arg, args); whichFunc = ParseKeyword(arg, colorModelNames, NCOLORMODELS); if (whichFunc >= 0) { #ifdef MENUSFROM0 ColorModelFromMenu(whichFunc); #else ColorModelFromMenu(whichFunc + 1); #endif } else { ScriptError("This color model is not defined"); } } break; case KWKEEP: DoKeepPalette(); break; case KWREVERT: DoRevertPalette(); break; default: ScriptError("This keyword is not a command"); break; } return true; } #ifdef PROTO void BeginScript(char *name) #else void BeginScript(name) char *name; #endif /*Begins a new script opened from file name*/ { curScript = fopen(name, "r"); if (curScript) { runningScript = true; abortScript = false; } else { fprintf(stderr, "BeginScript: Cannot open script file %s.\n", name); } } void EndScript() /*Ends a script*/ { if (curScript) { while (nextStackElement) { EndCommand(""); } /*Make control panels shown*/ ShowScriptControlPanels(true); fclose(curScript); curScript = 0; runningScript = false; MySetCursor(0); } } Bool ReadScriptLine() /*Reads and does a script line*/ { if (curScript) { int k, c; if (!lineAccepted) { lineAccepted = InterpretScriptLine(scriptLine); return true; } if (abortScript) { fprintf(stderr, "Aborting script.\n"); EndScript(); return false; } /*Read a script line*/ k = 0; while((c = fgetc(curScript)) != EOF && c != '\n') { if (k >= nScriptCharsAllocated) { if (nScriptCharsAllocated) { nScriptCharsAllocated += SCRIPTALLOCBATCH; scriptLine = realloc(scriptLine, nScriptCharsAllocated + 1); } else { nScriptCharsAllocated = SCRIPTALLOCBATCH; scriptLine = malloc(nScriptCharsAllocated + 1); } } scriptLine[k] = c; ++k; } if (k == 0 && c == EOF) { EndScript(); return false; } else if (k != 0) { scriptLine[k] = 0; lineAccepted = InterpretScriptLine(scriptLine); return true; } } return true; } static Bool ScriptTask() /*Run the current script task*/ { switch(runningTask) { case RT_RECORDING: if (framesLeft <= 0) { runningTask = 0; return true; } if (!SnapOneFrame()) { ScriptError("Could not snap a single frame."); } ++TrashDayFlag; --framesLeft; break; } return false; } Bool InterpretScriptLine(s) char *s; /*Interprets a script line in character string s. Returns true iff the script line needs to be thrown away*/ { char curKeyword[256]; int kwn; Bool retVal; if (runningTask != RT_NONE) { /*There's a running task*/ return ScriptTask(); } /*Set up whole line for script stuff*/ wholeLine = s; /*Look at first keyword*/ SKIPBLANKS(s); if (*s == '#') { if (logging) { Log(wholeLine); } return true; } if (scriptWindow && IsValidWindow(scriptWindow)) { SelWindow(scriptWindow); } else { SelWindow((WinInfoPtr) 0); } if (ObjFunctionScriptLine(s)) { retVal = true; } else { SHIFTKW(curKeyword, s); if (!strlen(curKeyword)) { retVal = true; } else { /*Find out what it is*/ kwn = ParseKeyword(curKeyword, keywords, NKEYWORDS); if (kwn == -1) { ScriptError("This command is unknown."); retVal = true; } else if (kwn == -2) { ScriptError("This command is ambiguous."); retVal = true; } else { retVal = DoScriptCommand(kwn, s); } } } return retVal; }