|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T c
Length: 14613 (0x3915) Types: TextFile Names: »cmd.c«
└─⟦b20c6495f⟧ Bits:30007238 EUUGD18: Wien-båndet, efterår 1987 └─⟦this⟧ »EUUGD18/General/Life/cmd.c«
#ifdef SCCS static char *sccsid = "@(#)cmd.c 1.21 2/2/85"; static char *cpyrid = "@(#)Copyright (C) 1985 by D Bell"; #endif #include "life.h" /* * Read commands if available, and execute them. Since we call scanchar for * our characters, the code after the setjmp can be reentered many times in * order to finish any command. This allows commands to be typed without * stopping the computation of generations of an object, and allows editing * of partially completed commands. */ docommand() { register int defarg; /* first argument defaulted to one */ register int ch; /* character read */ register struct object *obj; /* object being manipulated */ int arg1; /* first command argument */ int arg2; /* second command argument */ int got1; /* got first argument flag */ int got2; /* got second argument flag */ char *saveloopptr; /* crock for loop definitions */ switch (setjmp(ttyjmp)) { case SCAN_EDIT: /* command edited before completion */ curinput->i_endptr = saveloopptr; break; case SCAN_EOF: /* not yet enough chars for a command */ curinput->i_endptr = saveloopptr; return; case SCAN_ABORT: /* normal command completion */ default: /* normal entry point */ saveloopptr = curinput->i_endptr; break; } if (stop) error("Command aborted"); obj = curobj; cmark = 0; arg2 = 0; got2 = 0; ch = readvalue(&arg1, &got1); if (ch == ',') ch = readvalue(&arg2, &got2); defarg = 1; if (got1) defarg = arg1; switch (ch) { #ifdef DEBUG case '\005': /* ^E - show debugging info */ dumpdata(); break; #endif DEBUG case '\004': /* ^D - end terminal input */ curinput->i_term(curinput); break; case '\014': /* refresh screen */ dpyredraw(); redraw = 1; break; case '\n': /* move to next "line" */ crow += defarg; ccol = pcol; update = 1; break; case '\t': /* move to next tab stop */ while ((++ccol - pcol) % 8) ; update = 1; break; case ESC: /* execute a macro command */ ch = scanchar(); if (ch == ESC) break; /* ignore double escape */ backup(); if (setmacro(arg1, arg2, ch)) error("Undefined macro"); update = 1; break; case ' ': /* move to right */ case '.': ccol += defarg; update = 1; break; case ':': /* execute line style command */ case ';': dolinecommand(arg1, arg2, got1, got2); break; case '<': /* begin loop or macro definition */ if (got1 || got2) { if (got2) setloop(defarg, arg2, NULL); else setloop(1, defarg, NULL); update = 1; break; } ch = scanchar(); /* defining macro */ if ((ch < 'a') || (ch > 'z')) { error("Bad macro character"); } setloop(1, 1, ch); update = 1; break; case '>': /* end loop */ endloop(); break; case '+': /* increment single char variable */ ch = scanchar(); if (ch == '$') ch = scanchar(); setvariable1(ch, getvariable1(ch) + defarg); break; case 'b': /* move lower left with action */ domove(defarg, -defarg); break; case 'B': /* shift to lower left */ doshift(defarg, -defarg); break; case 'c': /* pick cell as current location */ crow = prow + arg1; ccol = pcol + arg2; update = 1; break; case 'd': /* delete selection */ doselect(ch); backup(); movemarkedobject(obj, deleteobject, MARK_CMD); redraw = 1; break; case 'f': /* flip selection */ doselect(ch); cmark = MARK_USR; flipmarkedobject(obj, MARK_CMD); redraw = 1; break; case 'g': /* compute generations */ if (obj->o_lock) error("Object locked"); if (genleft <= 0) backup(); genleft = (genleft ? arg1 : defarg); freqcount = frequency; update = 1; break; case 'G': /* compute infinite generations */ if (obj->o_lock) error("Object locked"); if (genleft <= 0) backup(); genleft = INFINITY; freqcount = frequency; update = 1; break; case 'h': /* move left with action */ domove(0, -defarg); break; case 'H': /* shift left lots */ doshift(0, -defarg); break; case 'i': /* toggle insert mode */ checkrun(); if (mode == M_MOVE) mode = M_INSERT; else if (mode == M_INSERT) mode = M_DELETE; else mode = M_MOVE; update = 1; break; case 'j': /* move down with action */ domove(defarg, 0); break; case 'J': /* shift down lots */ doshift(defarg, 0); break; case 'k': /* move up with action */ domove(-defarg, 0); break; case 'K': /* shift up lots */ doshift(-defarg, 0); break; case 'l': /* move right with action */ domove(0, defarg); break; case 'L': /* shift right lots */ doshift(0, defarg); break; case 'm': /* mark current object */ doselect(ch); copymarks(obj, MARK_CMD, MARK_USR); redraw = 1; break; case 'M': /* remove all marks */ checkrun(); clearmarks(obj, MARK_SEE); redraw = 1; break; case 'n': /* move lower right with action */ domove(defarg, defarg); break; case 'N': /* shift down and right */ doshift(defarg, defarg); break; case 'o': /* insert new cells */ case 'O': checkrun(); backup(); while ((stop == 0) && (defarg-- > 0)) { addcell(obj, crow, ccol++); } redraw = 1; break; case 'p': /* place deleted object */ checkrun(); backup(); cmark = MARK_USR; addobject(deleteobject, obj, RELATIVE); redraw = 1; break; case 'r': /* rotate selection */ doselect(ch); cmark = MARK_USR; rotatemarkedobject(obj, MARK_CMD); redraw = 1; break; case 's': /* set scale factor and center object */ obj->o_autoscale = 0; if (got1 == 0) arg1 = obj->o_scale; setscale(obj, arg1); break; case 'S': /* perform auto-scaling */ if (got1 == 0) arg1 = obj->o_scale; setscale(obj, arg1); obj->o_autoscale = 1; redraw = 1; break; case 't': /* toggle current cell */ checkrun(); backup(); if (delcell(obj, crow, ccol)) addcell(obj, crow, ccol); redraw = 1; break; case 'u': /* move upper right with action */ domove(-defarg, defarg); break; case 'U': /* shift to upper right */ doshift(-defarg, defarg); break; case 'x': /* kill current cells */ checkrun(); backup(); while ((stop == 0) && (defarg-- > 0)) { delcell(obj, crow, ccol++); } redraw = 1; break; case 'y': /* move upper left with action */ domove(-defarg, -defarg); break; case 'Y': /* shift to upper left */ doshift(-defarg, -defarg); break; case 'z': /* clear or set generation number */ checkrun(); obj->o_gen = arg1; obj->o_born = 0; obj->o_died = 0; update = 1; break; case '/': /* search for next object */ { int minr, maxr, minc, maxc; checkrun(); if (searchobject(obj, defarg, 0)) error("Empty object"); clearmarks(obj, MARK_CMD); markobject(obj, crow, ccol, MARK_CMD); markminmax(obj, MARK_CMD, &minr, &maxr, &minc, &maxc); positionview(minr, maxr, minc, maxc); update = 1; } break; case '@': /* point at current location */ prow = crow; pcol = ccol; break; case '!': /* comment characters */ case '#': while (scanchar() != '\n') ; break; default: /* unknown commands */ error("Unknown command"); } scanabort(); /* completed command */ } /* * Read a numeric value (if any) to be used as an argument for a command. * Pointers to the returned value and returned flag are given. * The returned value is zero if no value is read. * The returned flag is nonzero if a value was read. * Return value is the first non-argument character read. */ readvalue(valueptr, flagptr) register int *valueptr; /* pointer to returned value */ register int *flagptr; /* pointer to got value flag */ { register int ch; /* character being read */ register struct input *ip; /* input structure */ int sign; /* sign of result */ *valueptr = 0; *flagptr = 0; sign = 1; ch = scanchar(); if (ch == '-') { /* negative value */ sign = -1; ch = scanchar(); } if (ch == '$') { /* get variable value */ *valueptr = sign * getvariable1(scanchar()); *flagptr = 1; return(scanchar()); } if (ch == '(') { /* get expression */ *valueptr = sign * scanexpr(); *flagptr = 1; return(scanchar()); } while ((ch >= '0') && (ch <= '9')) { /* get numeric value */ *valueptr = (*valueptr * 10) + ch - '0'; *flagptr = 1; ch = scanchar(); } if (ch == '%') { /* get loop value */ ch = 1; if (*flagptr) ch = *valueptr; if (ch <= 0) error("Bad nest value"); ip = curinput + 1; while (ch > 0) { if (--ip < inputs) error("Bad nest value"); if (ip->i_type == INP_LOOP) ch--; } *valueptr = ip->i_curval; *flagptr = 1; ch = scanchar(); } *valueptr *= sign; return(ch); } /* * Routine called from above to scan and evaluate a parenthesized expression. * This routines knows that one parenthesis has already been read. Stops * reading on the matching parenthesis. */ scanexpr() { register char *cp; /* current character */ register int nest; /* nesting depth */ char buf[100]; /* expression buffer */ cp = buf; *cp++ = '('; /* start with parenthesis */ nest = 1; while (nest > 0) { if (cp >= &buf[sizeof(buf)-2]) error("expression too long"); *cp = scanchar(); if (*cp == '(') nest++; if (*cp == ')') nest--; cp++; } *cp = '\0'; return(getexpression(buf)); } /* * Select a set of cells to be used for some command. This involves reading * the next character and marking cells based on that character. Repeating * the command character is equivilant to selecting the current object. On a * successful return, exactly those cells specified are marked with MARK_CMD. * If no cells are found, an error is generated. */ doselect(cmd) { register struct object *obj; /* object to examine */ register long minrow, maxrow, mincol, maxcol; /* range for marks */ register struct cell *cp; /* current cell */ int ch; /* character to select on */ checkrun(); ch = scanchar(); if (ch == cmd) ch = 'o'; /* repeated char is connected object */ minrow = -INFINITY; maxrow = -minrow; mincol = minrow; maxcol = maxrow; obj = curobj; clearmarks(obj, MARK_CMD); switch (ch) { case 'a': /* all of object */ break; case 'b': /* below and left of cursor */ minrow = crow; maxcol = ccol; break; case 'c': /* current cell */ cp = findcell(obj, crow, ccol); if (cp == NULL) error("No cell at current location"); cp->c_marks |= MARK_CMD; return; case 'h': /* left of cursor */ maxcol = ccol; break; case 'j': /* below cursor */ minrow = crow; break; case 'k': /* above cursor */ maxrow = crow; break; case 'l': /* right of cursor */ mincol = ccol; break; case 'm': /* marked cells */ if (copymarks(obj, MARK_USR, MARK_CMD)) error("No object marked"); return; case 'n': /* below and right of cursor */ minrow = crow; mincol = ccol; break; case 'o': /* connected object */ if (markobject(obj, crow, ccol, MARK_CMD)) error("No object at current location"); return; case 'p': /* rectangle to pointer */ minrow = crow; maxrow = prow; if (minrow > maxrow) { minrow = prow; maxrow = crow; } mincol = ccol; maxcol = pcol; if (mincol > maxcol) { mincol = pcol; maxcol = ccol; } break; case 'u': /* above and right of cursor */ maxrow = crow; mincol = ccol; break; case 'v': /* things visible in window */ minrow = obj->o_minrow; maxrow = obj->o_maxrow; mincol = obj->o_mincol; maxcol = obj->o_maxcol; break; case 'y': /* above and left of cursor */ maxrow = crow; maxcol = ccol; break; default: /* unknown */ error("Unknown selection command"); } if (markregion(obj, MARK_CMD, minrow, maxrow, mincol, maxcol) == 0) error("No cells in region"); } /* * Move the current position by the indicated deltas, performing the * current action to the configuration. The movement is scaled by * the current scaling factor. */ domove(rowdelta, coldelta) register int rowdelta; /* amount to change row by */ register int coldelta; /* amount to change column by */ { register int row1; /* increment for row */ register int col1; /* increment for column */ rowdelta *= curobj->o_scale; coldelta *= curobj->o_scale; if (mode == M_MOVE) { /* just want to move */ crow += rowdelta; ccol += coldelta; update = 1; return; } checkrun(); backup(); row1 = 0; /* need to loop for insert or delete */ col1 = 0; if (rowdelta > 0) row1 = 1; if (rowdelta < 0) row1 = -1; if (coldelta > 0) col1 = 1; if (coldelta < 0) col1 = -1; rowdelta += crow; coldelta += ccol; while ((stop == 0) && ((crow != rowdelta) || (ccol != coldelta))) { crow += row1; ccol += col1; switch (mode) { case M_INSERT: addcell(curobj, crow, ccol); break; case M_DELETE: delcell(curobj, crow, ccol); } } redraw = 1; } /* * Shift the window lots in the indicated direction, and also shift the * cursor location the same amount so that the cursor location on the * screen doesn't change. "Lots" is 1/4 of the screen width or height. * Special case: if both x and y are being shifted, we shift both by the * same amount, which is the minimum of the two shifts. */ doshift(rowdelta, coldelta) register int rowdelta; /* amount to change row by */ register int coldelta; /* amount to change column by */ { register struct object *obj; /* current object */ register int rowsign; /* sign of row */ register int colsign; /* sign of column */ obj = curobj; rowdelta *= ((rowradius * obj->o_scale) / 2); coldelta *= ((colradius * obj->o_scale) / 2); if (rowdelta && coldelta) { /* take minimums of absolute values */ rowsign = 1; colsign = 1; if (rowdelta < 0) { rowsign = -1; rowdelta = -rowdelta; } if (coldelta < 0) { colsign = -1; coldelta = -coldelta; } if (rowdelta > coldelta) rowdelta = coldelta; if (coldelta > rowdelta) coldelta = rowdelta; rowdelta *= rowsign; coldelta *= colsign; } obj->o_currow += rowdelta; obj->o_minrow += rowdelta; obj->o_maxrow += rowdelta; obj->o_curcol += coldelta; obj->o_mincol += coldelta; obj->o_maxcol += coldelta; redraw = 1; } /* * Perform a backup of the current object. This is only done if reading * from the terminal, since it is from the point of view of the user. */ backup() { if (curinput->i_type == INP_TTY) copyobject(curobj, backupobject); } /* * Check to see that generations are not being computed before proceeding * with the current command. */ checkrun() { if (genleft > 0) error("Illegal while running"); }