/* * M A N D E L B R O T C O N S T R U C T I O N S E T * * (C) Copyright 1989 by Olaf Seibert. * Mandel may be freely distributed. See file 'doc/Notice' for details. * * Batch processing department. */ #include #include #include #include #include "mandel.h" #ifdef DEBUG # undef STATIC # define STATIC /* EMPTY */ #endif /* * QUIT * STOP * WAIT * FIXRAINBOW * COLOR pen r g b * DRAW * FILLIN * SHIFT hfraction vfraction * SAVEAS filename * OPEN filename * FIXDISPLAY * BATCH filename * SELECT depth pen * MODULO * RANGES * PROGRAM * PRELUDE * R * C * END * REG regno value * LEFTEDGE rval * RIGHTEDGE rval * TOPEDGE ival * BOTTOMEDGE ival * PIXELSTEP value * NUMCOLORS value * MAXDEPTH value * RANGEWIDTH value * BORDERLESS value * HIRES 0 or 1 * INTERLACE 0 or 1 * HALFBRITE 0 or 1 * FUNCTION 1 to 3 * IPLOT 1 to 2 * EPLOT 1 to 2 * DRAWPRI -128 to -1 * WBWIDTH value * WBHEIGHT value * RAINDIST value * RAINRMAX value * RAINGMAX value * RAINBMAX value */ extern void SetDrawingFunction(), SetIPlotFunction(), SetEPlotFunction(); #define BATCH_MAGIC_BUT_TRUE (-42) #define BATCH_COMMAND_NOT_FOUND (-1) #define BATCHLINESIZE 256 STATIC char BatchLine[BATCHLINESIZE]; /* Batch command line buffer */ #ifdef AREXX short BatchWaiting; /* Don't accept any commands */ #endif struct Program *SetPC; /* Where to place new instruction */ short ProgramPart; /* 0 = prelude, 1 = program */ STATIC bool SetDouble(), SetInt(), SetShort(), Cmd_quit(), Cmd_stop(), Cmd_wait(), Cmd_fixrainbow(), Cmd_color(), Cmd_draw(), Cmd_shift(), Cmd_loadsave(), Cmd_fixdisplay(), Cmd_borderless(), Cmd_viewmodes(), Cmd_function(), Cmd_batch(), Cmd_drawpri(), Cmd_select(), Cmd_pentablemode(), Cmd_program(), Cmd_r(), Cmd_end(), Cmd_reg(); bool GetLine(); STATIC struct BatchCmdDescription { char *keyword; /* command string to be matched */ int (*handler)(); /* handler to be called: (*handler)(harg [,args]) */ void *harg; /* special argument to pass to handler */ }; /* * The following commands take no arguments, or * do their own parsing of the command tail. */ STATIC struct BatchCmdDescription Batch_void[] = { "program", Cmd_program, (void *)1, "prelude", Cmd_program, (void *)0, "r", Cmd_r, (void *)'r', "c", Cmd_r, (void *)'c', "end", Cmd_end, NULL, "fixrainbow", Cmd_fixrainbow, NULL, "color", Cmd_color, NULL, "draw", Cmd_draw, (void *)(long)FALSE, "fillin", Cmd_draw, (void *)(long)TRUE, "shift", Cmd_shift, NULL, "fixdisplay", Cmd_fixdisplay, NULL, "batch", Cmd_batch, NULL, "select", Cmd_select, NULL, "modulo", Cmd_pentablemode, (void *)MODULO, "ranges", Cmd_pentablemode, (void *)RANGES, "reg", Cmd_reg, (void *)0, "saveas", Cmd_loadsave, (void *)SaveAs, "open", Cmd_loadsave, (void *)OpenAs, "stop", Cmd_stop, NULL, "wait", Cmd_wait, NULL, "quit", Cmd_quit, NULL, NULL, NULL, NULL }; /* * The following commands take 1 double %lf argument */ STATIC struct BatchCmdDescription Batch_lf[] = { "leftedge", SetDouble, &LeftEdge, "rightedge", SetDouble, &RightEdge, "topedge", SetDouble, &TopEdge, "bottomedge", SetDouble, &BottomEdge, NULL, NULL, NULL }; /* * The following commands take 1 int (decimal) %d argument */ STATIC struct BatchCmdDescription Batch_d[] = { "pixelstep", SetInt, &PixelStep, "numcolors", SetInt, &NumColors, "maxdepth", SetInt, &MaxDepth, "rangewidth", SetInt, &RangeWidth, "borderless", Cmd_borderless, NULL, "hires", Cmd_viewmodes, (void *)HIRES, "interlace", Cmd_viewmodes, (void *)LACE, "halfbrite", Cmd_viewmodes, (void *)EXTRA_HALFBRITE, "function", Cmd_function, (void *)SetDrawingFunction, "iplot", Cmd_function, (void *)SetIPlotFunction, "eplot", Cmd_function, (void *)SetEPlotFunction, "drawpri", Cmd_drawpri, NULL, NULL, NULL, NULL }; /* * The following commands take 1 short int (decimal) %hd argument */ STATIC struct BatchCmdDescription Batch_hd[] = { "wbwidth", SetShort, &WBWidth, "wbheight", SetShort, &WBHeight, "raindist", SetShort, &RainbowDistance, "rainrmax", SetShort, &RainbowRMax, "raingmax", SetShort, &RainbowGMax, "rainbmax", SetShort, &RainbowBMax, NULL, NULL, NULL }; /* * This is a simple function: * it just assigns a value to a variable of type double. */ STATIC bool SetDouble(harg, arg1) void *harg; double arg1; { *(double *)harg = arg1; return TRUE; } /* * This is a simple function: * it just assigns a value to a variable of type int. */ STATIC bool SetInt(harg, arg1) void *harg; int arg1; { *(int *)harg = arg1; UpdateOptDrawResCm(); return TRUE; } /* * This is a simple function: * it just assigns a value to a variable of type short. */ STATIC bool SetShort(harg, arg1) void *harg; short arg1; { *(short *)harg = arg1; return TRUE; } /* * Handle QUIT command. */ STATIC bool Cmd_quit() { finished = TRUE; return TRUE; } /* * Handle STOP command. */ STATIC bool Cmd_stop() { StopDrawing(); return TRUE; } STATIC bool Cmd_wait() { #ifdef AREXX /* * Halt all Arexx traffic as well... * This admittedly is a bit too rude, but as long as I can't test * better approaches... */ BatchWaiting = TRUE; #endif return BATCH_MAGIC_BUT_TRUE; } STATIC bool Cmd_fixrainbow() { extern SHORT RRMax; /* variable of the palette */ RRMax = -5; /* force color updating */ ModifyColors(); /* routine of the palette */ return TRUE; } STATIC bool Cmd_color(harg, tail) void *harg; char *tail; { ULONG color, newred, newgreen, newblue; if (sscanf(tail, "%ld %ld %ld %ld", &color, &newred, &newgreen, &newblue) == 4) { if (color < NumColors && color < MAXCOL) { struct ViewPort *vp = &MandelScreen->ViewPort; SetRGB4(vp, color, newred, newgreen, newblue); return TRUE; } } return FALSE; } STATIC bool Cmd_draw(fillin) void *fillin; { return DrawPicture((bool)(long)fillin); } STATIC bool Cmd_shift(harg, tail) void *harg; char *tail; { double HShift, VShift; double Width = RightEdge - LeftEdge, Height = BottomEdge - TopEdge; if (sscanf(tail, "%lf %lf", &HShift, &VShift) == 2) { LeftEdge = LeftEdge + HShift * Width; RightEdge = RightEdge + HShift * Width; TopEdge = TopEdge + VShift * Height; BottomEdge = BottomEdge + VShift * Height; return TRUE; } return FALSE; } STATIC char *ParseString(line) char *line; { static char tmp[80]; if (line[0] == '"' || line[0] == '\'') { /* Quoted ? */ char *end; strncpy(tmp, ++line, sizeof(tmp)-2); tmp[sizeof(tmp)-1] = '\0'; end = index(tmp, line[-1]); if (end == NULL) return NULL; *end = '\0'; return tmp; } return line; } STATIC bool Cmd_loadsave(harg, tail) void *harg; /* Either OpenAs or SaveAs */ register char *tail; { tail = ParseString(tail); /* * Cast harg into a pointer to a function returning bool * and call that function (OpenAs or SaveAs) with the name. */ return (* (bool (*)()) harg) (tail); } STATIC bool Cmd_borderless(harg, d) void *harg; int d; { if (d) DoBorderless(MainWindow, &borderinfo); else UndoBorderless(MainWindow, &borderinfo); UpdateOptViewResCm(); return TRUE; } STATIC bool Cmd_viewmodes(harg, d) void *harg; int d; { if (d) MandelNScreen.ViewModes |= (USHORT)(long)harg; else MandelNScreen.ViewModes &= ~(USHORT)(long)harg; UpdateOptViewResCm(); return TRUE; } STATIC bool Cmd_fixdisplay() { return !ReInitDisplay(); /* returns failure... */ } STATIC bool Cmd_function(harg, d) /* Numbered from 1 */ void *harg; int d; { (* (void (*)()) harg) (d - 1); UpdateDrwCm(); return TRUE; } STATIC bool Cmd_batch(harg, tail) void *harg; char *tail; { tail = ParseString(tail); return OpenBatch(tail); } STATIC bool Cmd_drawpri(harg, dpri) void *harg; int dpri; { SetDrawPri(dpri); UpdateOptPriCm(); return TRUE; } STATIC bool Cmd_select(harg, tail) void *harg; char *tail; { int depth, pen; if (sscanf(tail, "%d %d", &depth, &pen) == 2 && depth < MAXDEPTH && depth >= 0 ) { PenTable[depth] = pen; PenTableMode = SELECT; UpdateOptColorCm(); return TRUE; } return FALSE; } STATIC bool Cmd_pentablemode(harg) void *harg; { PenTableMode = (long) harg; InitPenTable(); UpdateOptColorCm(); return TRUE; } /*- * After the PROGRAM command, a small program of the following form * must follow: * * {"r", "c"} reg1 "=" reg2 [ {"i", "+", "-", "*"} reg3 ] * * This fits in the sscanf pattern * * "%1s %d = %d %1s %d" * * which should match either 3 or 5 arguments. * * This function only resets the program counter to the correct place. * The program lines with r or c are handled by Cmd_r(). -*/ STATIC bool Cmd_program(harg) void *harg; /* 1 for PROGRAM, 0 for PRELUDE */ { int match; register struct Program *pc = SetPC; /* Find where to begin this program */ pc = &Program[0]; ProgramPart = match = (long)harg; while (match--) { while (pc->pr_OpCode != End) { pc++; /* * This should not even be necessary since End == 0 and * uninitialized static arrays contain binary zeros. */ if (pc >= &Program[PROGRAMSIZE]) { pc = &Program[0]; Program[0].pr_OpCode = End; Program[1].pr_OpCode = End; goto break_loops; } } pc++; } break_loops: SetPC = pc; return TRUE; } STATIC bool Cmd_r(harg, tail) void *harg; /* 'r' or 'c' */ char *tail; { auto char op[2]; auto int reg1, reg2, reg3; int match; register struct Program *pc = SetPC; pc->pr_OpCode = End; /* safety */ pc->pr_Dest = ProgramPart; match = sscanf(tail, "%d = %d %1s %d", ®1, ®2, &op[0], ®3); pc->pr_Dest = reg1; pc->pr_Op1 = reg2; if (pc >= &Program[PROGRAMSIZE-1]) return FALSE; if (match == 2) { /* Must be an assignment */ pc->pr_OpCode = Rassign; } else if (match == 4) { pc->pr_Op2 = reg3; switch (op[0]) { case 'i': pc->pr_OpCode = Ri; break; case '+': pc->pr_OpCode = Rplus; break; case '-': pc->pr_OpCode = Rminus; break; case '*': pc->pr_OpCode = Rtimes; break; } } else { return FALSE; /* Parse errors are done rudely */ } if (tolower((char)(long)harg) == 'c') { pc->pr_OpCode++; /* Make the opertation complex */ } pc++; SetPC = pc; return TRUE; } STATIC bool Cmd_end(harg, tail) void *harg; char *tail; { register struct Program *pc = SetPC; pc->pr_OpCode = End; /* safety */ pc->pr_Dest = ProgramPart++; SetPC++; return TRUE; } STATIC bool Cmd_reg(harg, tail) void *harg; char *tail; { auto int regno; auto double value; if (sscanf(tail, "%d %lf", ®no, &value) == 2) { if (regno >= 0 && regno < 2*PROGRAMREGS) { PrgReg[regno] = value; return TRUE; } } return FALSE; } /*-----------------------------------------------------------------------*/ STATIC char *SkipNonWhite(line) register char *line; { if (line) while (*line && !isspace(*line)) line++; return line; } STATIC char *SkipWhite(line) register char *line; { if (line) while (*line && isspace(*line)) line++; return line; } /* * This is the function we use to see if the command matches * the command string. Not case sensitive. Make sure all commands * are given in lower case! [taken from MinRexx by Radical Eye Software] * 0 means equal enough, all other values mean not equal enough. */ STATIC int cmdcmp(c, m) register char *c, *m ; { while (*c && ((*c == *m) || (*c == *m + 32 && ('a' <= *c && *c <= 'z')))) { c++ ; m++ ; } if (*m && !isspace(*m)) return 1; return(*c) ; } /* * Search a table of BatchCmdDescriptions for a keyword. * When found, return a pointer to it. * Otherwise, return NULL. */ STATIC struct BatchCmdDescription *SearchTable(table, string) register struct BatchCmdDescription *table; register char *string; { while (table->keyword) { if (cmdcmp(table->keyword, string) == 0) return table; table++; } return NULL; } /* * This executes a batch command line. Return value indicates success. #ifdef AREXX * Can also be called from ARexx interface code. #endif */ bool ExecuteBatchCommand(command) register char *command; { char *tail; char *ptr; bool success; struct BatchCmdDescription *bcmdd; command = SkipWhite(command); if (command == NULL || command[0] == ';' || command[0] == '/' || command[0] == '#' ) return TRUE; tail = ptr = SkipNonWhite(command); if (*tail) tail = SkipWhite(tail); if (bcmdd = SearchTable(Batch_void, command)) { success = (*bcmdd->handler)(bcmdd->harg, tail); } else if (bcmdd = SearchTable(Batch_d, command)) { auto int d; success = (sscanf(tail, "%d", &d) == 1) && (*bcmdd->handler)(bcmdd->harg, d); } else if (bcmdd = SearchTable(Batch_hd, command)) { auto short hd; success = (sscanf(tail, "%hd", &hd) == 1) && (*bcmdd->handler)(bcmdd->harg, hd); } else if (bcmdd = SearchTable(Batch_lf, command)) { auto double lf; success = (sscanf(tail, "%lf", &lf) == 1) && (*bcmdd->handler)(bcmdd->harg, lf); } else success = BATCH_COMMAND_NOT_FOUND; return success; } void CloseBatch() { if (BatchFILE) { fclose(BatchFILE); BatchFILE = NULL; } OffMenu(MainWindow, MENU(BATMENU, BATCONT, NOSUB)); OffMenu(MainWindow, MENU(BATMENU, BATWAIT, NOSUB)); OffMenu(MainWindow, MENU(BATMENU, BATABORT, NOSUB)); } bool OpenBatch(name) register char *name; { CloseBatch(); #ifdef AREXX if (asyncRexxCmd(name)) return TRUE; #endif BatchFILE = fopen(name, "r"); OnMenu(MainWindow, MENU(BATMENU, BATABORT, NOSUB)); if (BatchFILE == NULL) { printf("Mandel: Cannot open batch file `%s'.\n", name); } else if (isatty(fileno(BatchFILE))) { printf("Mandel: Batch file `%s' is interactive.\n", name); CloseBatch(); } return BatchFILE != NULL; } STATIC bool GetLine() { if (fgets(BatchLine, BATCHLINESIZE, BatchFILE) != NULL) { register char *newline; if (newline = index(BatchLine, '\n')) { *newline = '\0'; } /* else silently truncate line */ return TRUE; } return FALSE; } /* * This is the main entry point into the batch system. * It fetches lines from the batch file (until EOF) and executes it. * It stops doing that if a routine returns the special value * BATCH_MAGIC_BUT_TRUE, or FALSE. * * Ideally, this should also run as a separate task. */ bool Batch() { bool result = TRUE; BatchWaiting = FALSE; if (BatchFILE != NULL) { OnMenu( MainWindow, MENU(BATMENU, BATWAIT, NOSUB)); OffMenu(MainWindow, MENU(BATMENU, BATCONT, NOSUB)); while (GetLine()) { result = ExecuteBatchCommand(BatchLine); if (result == FALSE) { printf("Batch command failed:\n%s\n", BatchLine); } else if (result == BATCH_COMMAND_NOT_FOUND) { printf("Unknown batch command:\n%s\n", BatchLine); break; } else if (result == BATCH_MAGIC_BUT_TRUE) { /* Give up volontarily (wait command) */ OnMenu(MainWindow, MENU(BATMENU, BATCONT, NOSUB)); break; } if (MainWindow->UserPort->mp_MsgList.lh_Head->ln_Succ) { /* * Give up because of an intui-message. Signal * ourselves to continue later on. This should not * be done when we just did a wait command (see above). */ Signal(MandelTask, DrawSigMask); break; } } OffMenu(MainWindow, MENU(BATMENU, BATWAIT, NOSUB)); if (feof(BatchFILE)) { CloseBatch(); } } return result; } /* * This routine checks command line options */ void Options(argc, argv) int argc; char **argv; { if (argc > 2 || (argc == 1) && argv[1][0] == '?') printf("Usage: %s [batchfile]\n", argv[0]); else if (argc == 2) { OpenBatch(argv[1]); } } /* * Batch menu handler */ void BatchMenu(Code) USHORT Code; { char Name[DNAME_SIZE + FNAME_SIZE + 3]; int Item = ITEMNUM(Code); switch(Item) { case BATFILE: NameValid = FALSE; if ( get_fname(MainWindow, "Select a BATCH file", FileName, DirName) == NULL ) break; CatFileComponents(Name, DirName, FileName); OpenBatch(Name); /* Fall through to start batch */ case BATCONT: Signal(MandelTask, DrawSigMask); /* Set the batch signal */ break; case BATWAIT: SetSignal(0L, DrawSigMask); /* Clear the batch signal */ OnMenu( MainWindow, MENU(BATMENU, BATCONT, NOSUB)); break; case BATABORT: CloseBatch(); break; } }