/*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 "ScianWindows.h" #include "ScianObjWindows.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" Bool runningScript = false; /*True iff running script*/ WinInfoPtr scriptWindow = 0; /*The current window of the script*/ extern ObjPtr perspecControlClass; /*Class of perspecive controls*/ FILE *logFile = 0; /*File that we're logging to*/ Bool logging = false; /*True iff logging*/ long framesLeft = 0; /*Frames left to record*/ Bool abortScript = false; /*Abort script*/ /*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*/ #define ERROBJ ((ObjPtr) -1) /*Evil Satanic test value*/ typedef struct { int command; } Block; Block commandStack[MAXSTACKDEPTH]; /*Stack of commands*/ int nextStackElement = 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 KWVISUALIZE 5 /*Do the visualize menu item*/ #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 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 KWCLONE 26 /*Clone an icon*/ #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 KWDRAG 33 /*Drags something*/ #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 KWDUPLICATE 46 /*Duplicate an icon, just like clone*/ #define KWOFF 47 /*(Turn) off*/ #define KWTURN 48 /*Turn (on/off)*/ #define KWON 49 /*(Turn) on*/ #define KWVISOBJECTSAS 50 /*Visualize objects as*/ #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 KWLOCALCOPY 59 /*Make a local copy*/ #define KWFRONT 60 /*(Show) front (panel controls)*/ #define KWBACK 61 /*(Show) back (panel controls)*/ #define NKEYWORDS 62 /*Number of keywords*/ char *keywords[NKEYWORDS] = { "begin", "end", "recorder", "deselect", "select", "visualize", "alignment", "location", "videoscreen", "fullscreen", "rotate", "show", "panel", "recording", "snap", "window", "set", "controls", "pushwindow", "quit", "shear", "fps", "eyeposn", "roll", "pitch", "yaw", "clone", "hide", "exit", "value", "font", "size", "close", "drag", "drop", "bounds", "tile", "annotation", "frame", "locate", "delete", "scrsave", "record", "screen", "color", "preferences", "duplicate", "off", "turn", "on", "visobjectsas", "functionbox", "fileswindow", "selectall", "deselectall", "help", "filereaders", "datasets", "rotation", "localcopy", "front", "back" }; char *wholeLine; /*Pointer to the whole line for error*/ char *begToken, *endToken; /*Beginning and ending of current token*/ WinInfoPtr logWindow = 0; /*Current log window*/ int logInhibit = 0; /*Counter to inhibit log*/ #ifdef PROTO Bool BeginCommand(char *); Bool EndCommand(char *); #else Bool BeginCommand(); Bool EndCommand(); #endif void Log(s) char *s; /*Logs command s*/ { if (logging && (logInhibit == 0)) { if (selWinInfo && (logWindow != selWinInfo)) { /*Make a window command*/ char windowName[256]; int k; char *s; /*Copy window title*/ s = selWinInfo -> winTitle; k = 0; while (*s) { if (!isalpha(*s) && ((k == 0) || !isdigit(*s))) { windowName[k++] = '\\'; } windowName[k++] = *s++; } windowName[k] = 0; fprintf(logFile, "window %s\n", windowName); logWindow = selWinInfo; } fputs(s, logFile); } } #ifdef PROTO void InhibitLogging(Bool whether) #else void InhibitLogging(whether) Bool whether; #endif /*Inhibits or disinhibits logging based on whether*/ { if (whether) { ++logInhibit; } else { --logInhibit; } } void LogControl(object) ObjPtr object; { if (logging) { 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 ScriptError(e) char *e; /*Prints out an error e*/ { char *runner; fprintf(stderr, "%s", 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); 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; } SelectWindow(namedWindow -> id); scriptWindow = namedWindow; } void MakeObjectName(dest, object) char *dest; ObjPtr object; /*Makes a short object name from object and puts it into dest*/ { register char *s; ObjPtr name; name = GetStringVar("MakeObjectName", object, NAME); if (!name) { *dest = 0; return; } /*Copy name*/ s = GetString(name); if (isdigit(*s)) { *dest++ = '\\'; } while (*s) { if (!isalpha(*s) && !isdigit(*s)) { *dest++ = '\\'; } *dest++ = *s++; } *dest = 0; } void MakeFullObjectName(dest, window, object) char *dest; ObjPtr window, object; /*Makes a full name for object within window and puts it into dest*/ { register char *s; ObjPtr name; name = GetStringVar("MakeFullObjectName", object, NAME); if (!name) { *dest = 0; return; } /*Copy title*/ s = ((WinInfoPtr) window) -> winTitle; if (!isalpha(*s)) { *dest++ = '\\'; } while (*s) { if (!isalpha(*s) && !isdigit(*s)) { *dest++ = '\\'; } *dest++ = *s++; } /*Add a colon*/ *dest++ = ':'; /*Copy name*/ s = GetString(name); if (!isalpha(*s)) { *dest++ = '\\'; } while (*s) { if (!isalpha(*s) && !isdigit(*s)) { *dest++ = '\\'; } *dest++ = *s++; } *dest = 0; } ObjPtr FindFullNamedObject(name) char *name; /*Finds the object with name name. Syntax for name is [:] Does a complete depth-first search of the window for a single object with that name. As a side effect, selects the window. */ { char littleName[256]; int k; WinInfoPtr namedWindow; ObjPtr retVal, list; k = 0; while (*name && *name != ':') { if (*name == '\\') { ++name; } littleName[k++] = *name++; } littleName[k] = 0; if (*name) { /*It's a full name Skip over colon*/ ++name; /*Find the window*/ namedWindow = GetWinFromTitle(littleName); if (!namedWindow) { ScriptError("Cannot find a unique window by that name."); return NULLOBJ; } /*Select it*/ SelectWindow(namedWindow -> id); scriptWindow = namedWindow; k = 0; while (*name && !isspace(*name)) { if (*name == '\\') { ++name; } littleName[k++] = *name++; } littleName[k] = 0; } else { /*It's only an object name. Assume selected window*/ namedWindow = scriptWindow; if (!namedWindow) { ScriptError("There is no currently selected window."); return ERROBJ; } } if (!strlen(littleName)) { ScriptError("An object name is expected after the window name."); return ERROBJ; } list = FindNamedObject((ObjPtr) namedWindow, littleName); if (!list) { ScriptError("There is no object by that name in that window."); retVal = 0; } else { if (LISTOF(list) && !(LISTOF(list) -> next)) { retVal = LISTOF(list) -> thing; } else { ScriptError("That name is not unique."); retVal = 0; } } return retVal; } int ParseKeyword(s) char *s; /*Parses keyword s. 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 < NKEYWORDS; ++k) { for (i = 0; s[i]; ++i) { if (tolower(s[i]) != tolower(keywords[k][i])) { break; } } if (!s[i] && !keywords[k][i]) { /*It's a match!*/ return k; } } /*Seek a partial match*/ for (k = 0; k < NKEYWORDS; ++k) { for (i = 0; s[i]; ++i) { if (tolower(s[i]) != tolower(keywords[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 == '+' || isdigit(*r)) { double val; /*It's a number*/ SHIFTFN(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*/ ObjPtr tempObj; SHIFTFN(arg, r); if (0 == strcmp2(arg, "NULLOBJ")) { *o = NULLOBJ; } else { tempObj = FindFullNamedObject(arg); if (tempObj) *o = tempObj; } } 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; switch (*r) { case 'n': case 'N': *r = '\n'; break; case 't': case 'T': *r = '\t'; break; } } 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; } Bool MatrixToText(s, m) char *s; Matrix m; /*Converts matrix in m to text in s*/ { sprintf(s, "[[%g %g %g %g][%g %g %g %g][%g %g %g %g][%g %g %g %g]]", m[0][0], m[0][1], m[0][2], m[0][3], m[1][0], m[1][1], m[1][2], m[1][3], m[2][0], m[2][1], m[2][2], m[2][3], m[3][0], m[3][1], m[3][2], m[3][3]); } 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 { *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 (IsArray(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); 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; } switch (cmdNum) { case KWBEGIN: break; case KWRECORDING: if (FindCommandInStack(KWRECORDING) >= 0) { ScriptError("The begin recording command cannot be nested."); return true; } else { real nSeconds; SHIFTKW(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; default: ScriptError("This command may not start a begin-end block."); break; } commandStack[nextStackElement] . command = cmdNum; ++nextStackElement; return; } 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); 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 KWRECORDING: StopRecording(); DisconnectRecorder(); } } return true; } Bool DoSetCommand(kwn, args) int kwn; char *args; /*Does a set command*/ { char arg[256]; switch(kwn) { 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: { 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 && IsArray(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, 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)) { SHIFTFN(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) && (object = GetVar(object, REPOBJ))) { 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); if (InClass(object, controllerClass)) { ResolveController(object); } else { 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 (IsArray(bounds) && RANK(bounds) == 1) { ObjPtr testBounds; testBounds = GetVar(object, BOUNDS); if (!testBounds || (IsArray(testBounds) && RANK(testBounds) == 1 && DIMS(testBounds)[0] == DIMS(bounds)[0])) { if (logging) { char cmd[256]; sprintf(cmd, "set bounds %s", 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 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 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 KWCONTROLS: if (showp) { DoShowControls(); } else { ScriptError("You can't hide controls this way. Close the window instead"); } 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; default: ScriptError("This keyword is not a settable parameter"); break; } return true; } Bool DoScriptCommand(kwn, args) int kwn; char *args; /*Does command kwn with args*/ { char arg[256]; switch(kwn) { case KWDELETE: DoDelete(); break; case KWTURN: /*Turn on/off*/ { int kwn; SHIFTKW(arg, args); kwn = ParseKeyword(arg); if (kwn == KWON) { DoTurnOn(); } else if (kwn == KWOFF) { DoTurnOff(); } else { ScriptError("Either 'on' or 'off' is expected here"); } } break; case KWSELECT: { ObjPtr object; object = ERROBJ; args = ParseObjectArg(args, &object); if (object != ERROBJ) { if (IsObject(object)) { FuncTyp method; method = GetMethod(object, SELECT); if (method) { (*method)(object, true); } else { ScriptError("This object has no SELECT method"); } } else { ScriptError("An object name is expected here"); } } } break; case KWDESELECT: { ObjPtr object; object = ERROBJ; args = ParseObjectArg(args, &object); if (object != ERROBJ) { if (IsObject(object)) { FuncTyp method; method = GetMethod(object, SELECT); if (method) { (*method)(object, false); } else { ScriptError("This object has no SELECT method"); } } else { ScriptError("An object name is expected here"); } } } break; case KWSELECTALL: DoSelectAllIcons(); break; case KWDESELECTALL: DoDeselectAllIcons(); break; case KWANNOTATION: { char name[256]; ObjPtr bounds; SHIFTKW(name, args); if (strlen(name)) { bounds = ERROBJ; args = ParseObjectArg(args, &bounds); if (bounds != ERROBJ) { if (IsArray(bounds) && RANK(bounds) == 1 && DIMS(bounds)[0] == 4) { AddAnnotation(name, ArrayMeat(bounds)); } else { ScriptError("A 4-vector is expected here"); } } } else { ScriptError("A name is expected here"); } } break; case KWDRAG: { ObjPtr object; ObjPtr list; list = NewList(); do { object = ERROBJ; args = ParseObjectArg(args, &object); if (object != ERROBJ) { if (object && IsObject(object)) { PostfixList(list, object); } } else { ScriptError("An object name is expected here"); break; } } while (object); dragBuffer = list; AddToReferenceList(list); if (logging) { char cmd[400]; char *s; ThingListPtr runner; sprintf(cmd, "drag "); s = &(cmd[0]); while (*s) ++s; runner = LISTOF(list); while (runner) { *s++ = ' '; MakeObjectName(s, runner -> thing); while (*s) ++s; runner = runner -> next; } *s++ = '\n'; *s = 0; Log(cmd); } } break; case KWSET: /*Set something or other*/ { int k; SHIFTKW(arg, args); /*Find out what to set*/ kwn = ParseKeyword(arg); 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 KWSHOW: /*Show something or other*/ { int k; SHIFTKW(arg, args); /*Find out what to set*/ kwn = ParseKeyword(arg); 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); 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 KWVISUALIZE: VisObjects(); break; case KWVISOBJECTSAS: VisObjectsAs(); break; #if 0 case KWRGBMODE: { ObjPtr radio = NULLOBJ; if (scriptWindow) { radio = GetVar((ObjPtr) scriptWindow, CMODERADIO); } if (radio) { SetValue(radio, NewInt(1)); } else { ScriptError("Only a visualization window can be changed to RGB mode"); } } break; case KWCMAPMODE: { ObjPtr radio = NULLOBJ; if (scriptWindow) { radio = GetVar((ObjPtr) scriptWindow, CMODERADIO); } if (radio) { SetValue(radio, NewInt(0)); } else { ScriptError("Only a visualization window can be changed to color map mode"); } } break; #endif 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: { real p[3]; if (3 != sscanf(args, " [%g %g %g]", &(p[0]), &(p[1]), &(p[2]))) { ScriptError("Syntax error in matrix."); return true; } if (scriptWindow) { ObjPtr array, observer /*, observers*/; observer = FindObserver(scriptWindow); if (!observer) break; array = NewRealArray(1, 3L); CArray2Array(array, p); SetVar(observer, LOCATION, array); if (logging) { char cmd[256]; sprintf(cmd, "eyeposn [%g %g %g]\n", p[0], p[1], p[2]); Log(cmd); } ChangeFocus(observer); } } 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)); ChangeFocus(observer); } } 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)); ChangeFocus(observer); } } else { ScriptError("An amount to pitchis expected here."); } } break; case KWYAW: { float value; SHIFTKW(arg, args); if (strlen(arg) && 1 == sscanf(arg, " %g", &value)) { if (scriptWindow) { ObjPtr observer/*, observers*/; observer = FindObserver(scriptWindow); if (!observer) break; if (!observer) break; SetVar(observer, YAW, NewReal(value)); ChangeFocus(observer); } } else { ScriptError("An amount to yaw is expected here."); } } break; case KWROTATE: { char axis; float amount; SHIFTKW(arg, args); if (strlen(arg) == 1 && (*arg == 'x' || *arg == 'y' || *arg == 'z')) { axis = *arg; SHIFTKW(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 if (0 == strcmp2(arg, "to")) { /*Rotate to a matrix*/ Matrix m; if (16 != sscanf(args, " [[%g %g %g %g][%g %g %g %g][%g %g %g %g][%g %g %g %g]]", &(m[0][0]), &(m[0][1]), &(m[0][2]), &(m[0][3]), &(m[1][0]), &(m[1][1]), &(m[1][2]), &(m[1][3]), &(m[2][0]), &(m[2][1]), &(m[2][2]), &(m[2][3]), &(m[3][0]), &(m[3][1]), &(m[3][2]), &(m[3][3]))) { ScriptError("Syntax error in matrix."); return true; } if (scriptWindow) { RotateWindowTo(scriptWindow, m); } else { ScriptError("No current window."); } } else { ScriptError("Unrecognized keyword. An axis or 'to' is expected."); } return true; } break; case KWSHEAR: { char axis; float amount; SHIFTKW(arg, args); if (!strlen(arg) || 1 != sscanf(arg, "%f", &amount)) { ScriptError("An amount to shear is expected here."); return true; } if (scriptWindow) { ShearOrthoWindow(scriptWindow, amount); } } break; case KWRECORD: { 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 (!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 KWCLONE: case KWDUPLICATE: DoCloneIcon(); break; case KWLOCALCOPY: DoMakeLocalCopy(); break; case KWEXIT: case KWQUIT: DoQuit(); break; case KWCLOSE: DisposeWindow(scriptWindow -> id); SelectWindow(0); scriptWindow = 0; break; case KWPUSHWINDOW: if (scriptWindow && scriptWindow -> id) { winset(scriptWindow -> id); winpush(); } else { ScriptError("There is no current window"); } 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); system(tempStr); } else if (n == 1) { sprintf(tempStr, "scrsave %s", fileName); system(tempStr); } else { ScriptError("A filename and four sides are expected here"); return true; } } break; default: ScriptError("This keyword is not a command"); break; } return true; } void BeginScript() /*Begins a new script*/ { if (nextStackElement) { EndScript(); } } void EndScript() /*Ends a script*/ { while (nextStackElement) { EndCommand(""); } } 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; } SHIFTKW(curKeyword, s); if (!strlen(curKeyword)) { retVal = true; } else { runningScript = true; if (scriptWindow) { SelectWindow(scriptWindow -> id); } /*Find out what it is*/ kwn = ParseKeyword(curKeyword); 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); } runningScript = false; } return retVal; }