LIFE - fancy new version (part 3 of 4)
David I. Bell
dbell at daisy.UUCP
Sun Feb 3 14:51:31 AEST 1985
This is the last part of the actual life sources. The final article just
contains life objects.
#---Cut here and place in it's own directory, then feed to Bourne shell---
# This is a shell archive. Remove anything before this line, then
# unpack it by saving it in a file and typing "sh file". (Files
# unpacked will be owned by you and have default permissions.)
# This archive contains:
# main.c (2817 chars)
# mark.c (9268 chars)
# object.c (8845 chars)
# scan.c (3526 chars)
# vars.c (9419 chars)
# view.c (9535 chars)
#
echo x - main.c
sed -e 's/^X//' > "main.c" << '//E*O*F main.c//'
Xstatic char *sccsid = "@(#)main.c 1.12 2/2/85";
Xstatic char *cpyrid = "@(#)Copyright (C) 1985 by D Bell";
X
X/*
X * The game of life on an infinite board (by David I. Bell).
X * These life sources are in the public domain, and can be copied
X * or used as desired, with the following restrictions:
X * 1. All copyright notices (and this notice) must be preserved.
X * 2. The life sources (even if modified) cannot be sold for profit.
X * 3. If any sources are modified, a sentence must exist by the
X * copyright notice of each modified source file which says that
X * the file has been modified.
X */
X
X#include "life.h"
X#include <sgtty.h>
X
Xint intint(), readchar(); /* routines */
Xchar *getenv(); /* another one */
X
X
Xmain(argc, argv)
X char **argv; /* argument is a life object */
X{
X userlib = getenv(LIFEVAR);
X strcpy(rulestring, "3,23");
X termcell = alloccell();
X termcell->c_next = termcell;
X termcell->c_col = INFINITY;
X termrow = allocrow();
X termrow->r_next = termrow;
X termrow->r_firstcell = termcell;
X termrow->r_row = INFINITY;
X mode = M_MOVE;
X gridchar = ' ';
X frequency = 1;
X freqcount = 1;
X rowradius = 1; /* temp until find real sizes */
X colradius = 1;
X reserve = 1; /* creating special objects */
X deleteobject = getobject("..delete");
X tempobject = getobject("..temp");
X backupobject = getobject("..backup");
X mainobject = getobject("main");
X curobj = mainobject;
X prevobj = mainobject;
X reserve = 0; /* no more special objects */
X curinput = &inputs[-1]; /* initialize for tty input */
X settty();
X if ((argc > 1) && setfile(argv[1])) { /* set to get input file */
X perror(argv[1]);
X exit(1);
X }
X if (dpyinit(NULL, CBREAK, ECHO)) { /* home up and clear screen */
X exit(1);
X }
X dpymove(-1, -1); /* get screen size */
X rowradius = (dpygetrow() - 1) / 2;
X colradius = (dpygetcol() - 1) / 2;
X setscale(deleteobject, 1); /* fix scale factors now */
X setscale(tempobject, 1);
X setscale(backupobject, 1);
X setscale(mainobject, 1);
X signal(SIGINT, intint);
X scaninit(readchar, ttyjmp);
X while (1) {
X docommand();
X dogeneration(curobj);
X updateview();
X }
X}
X
X
X/*
X * Here on an interrupt character. Remember to stop what we are doing soon.
X * We cannot just longjmp away since things may be in an inconsistent state.
X */
Xintint()
X{
X signal(SIGINT, intint); /* not needed in 4.2, but so what */
X genleft = 0;
X stop = 1;
X redraw = 1;
X#ifdef DEBUG
X dumpdata();
X#endif DEBUG
X}
X
X
X/*
X * Here on an error. Close all but the top input level, cancel the
X * current command, beep, and set up to display the indicated message.
X * The message will remain until the next command is typed by the user.
X */
Xerror(str)
X char *str; /* message to type */
X{
X while (curinput > inputs) curinput->i_term(curinput);
X errorstring = str;
X redraw = 1;
X stop = 0;
X dowait = 0;
X write(STDERR, "\007", 1);
X scanabort();
X}
//E*O*F main.c//
echo x - mark.c
sed -e 's/^X//' > "mark.c" << '//E*O*F mark.c//'
X#ifdef SCCS
Xstatic char *sccsid = "@(#)mark.c 1.7 2/2/85";
Xstatic char *cpyrid = "@(#)Copyright (C) 1985 by D Bell";
X#endif
X
X#include "life.h"
X
Xstruct loc { /* structure to hold row and column pairs */
X long l_row;
X long l_col;
X};
X
Xchar rowwalk[9] = {-1,0,0,1,1,0,0,-1,0}; /* row deltas to walk a cell */
Xchar colwalk[9] = {-1,1,1,0,0,-1,-1,0,1}; /* col deltas to walk a cell */
X
X
X/*
X * Mark the object at a given location as specified. Returns nonzero if
X * no object exists there. An object for this purpose is considered as a
X * king-wise connected set of live cells.
X */
Xmarkobject(obj, row, col, mark)
X register struct object *obj; /* object to mark up */
X{
X register struct cell *cp; /* object being marked */
X
X cp = findcell(obj, row, col);
X if (cp == NULL) return(1);
X cp->c_marks |= mark;
X markloop(obj, row, col, mark);
X return(0);
X}
X
X
X/* Recursive subroutine called from markobject */
Xmarkloop(obj, row, col, mark)
X struct object *obj; /* object begin marked */
X register int row; /* current row */
X register int col; /* current column */
X register int mark; /* marking value */
X{
X register struct cell *cp; /* current cell */
X register struct loc *rp; /* pointer into list table */
X int i; /* to iterate over directions */
X struct loc rclist[8]; /* row and column list */
X
X while (1) {
X if (stop) return;
X rp = rclist;
X for (i = 0; i < 8; i++) { /* find neighbors */
X row += rowwalk[i];
X col += colwalk[i];
X cp = findcell(obj, row, col);
X if (cp == NULL) continue;
X if (cp->c_marks & mark) continue;
X cp->c_marks |= mark;
X rp->l_row = row;
X rp->l_col = col;
X rp++;
X }
X if (--rp != rclist) { /* recurse if more than one */
X for (; rp >= rclist; rp--) {
X markloop(obj, rp->l_row, rp->l_col, mark);
X }
X return;
X }
X row = rp->l_row; /* else follow single cell */
X col = rp->l_col;
X }
X}
X
X
X/* Mark a whole object as specified. */
Xsetmarks(obj, mark)
X struct object *obj; /* object to mark */
X register int mark; /* mark to be applied */
X{
X register struct row *rp; /* row pointer */
X register struct cell *cp; /* cell pointer */
X
X mark |= MARK_ANY;
X for (rp = obj->o_firstrow; rp != termrow; rp = rp->r_next) {
X for (cp = rp->r_firstcell; cp != termcell; cp = cp->c_next) {
X cp->c_marks |= mark;
X }
X }
X}
X
X
X/*
X * Copy the marks from one type to another for an object. Returns nonzero
X * if there were no cells with the given mark.
X */
Xcopymarks(obj, srcmark, destmark)
X struct object *obj; /* object to mark */
X register int srcmark; /* mark to be found */
X register int destmark; /* mark to be set */
X{
X register struct row *rp; /* row pointer */
X register struct cell *cp; /* cell pointer */
X int error;
X
X error = 1;
X for (rp = obj->o_firstrow; rp != termrow; rp = rp->r_next) {
X for (cp = rp->r_firstcell; cp != termcell; cp = cp->c_next) {
X if ((cp->c_marks & srcmark) == 0) continue;
X cp->c_marks |= destmark;
X error = 0;
X }
X }
X return(error);
X}
X
X
X/* Clear marks for a whole object as specified. */
Xclearmarks(obj, mark)
X struct object *obj; /* object to mark */
X register int mark; /* mark to be cleared */
X{
X register struct row *rp; /* row pointer */
X register struct cell *cp; /* cell pointer */
X
X mark = ~mark;
X mark |= MARK_ANY;
X for (rp = obj->o_firstrow; rp != termrow; rp = rp->r_next) {
X for (cp = rp->r_firstcell; cp != termcell; cp = cp->c_next) {
X cp->c_marks &= mark;
X }
X }
X}
X
X
X/*
X * Mark the cells in a specified rectangular region as desired.
X * Returns the number of cells which were marked.
X */
Xmarkregion(obj, mark, minrow, maxrow, mincol, maxcol)
X struct object *obj; /* object to mark */
X register int mark; /* value to mark with */
X long minrow, maxrow, mincol, maxcol; /* range to mark */
X{
X register struct row *rp; /* current row */
X register struct cell *cp; /* current cell */
X register long count; /* count of cells */
X
X count = 0;
X for (rp = obj->o_firstrow; rp != termrow; rp = rp->r_next) {
X if (rp->r_row < minrow) continue;
X if (rp->r_row > maxrow) break;
X for (cp = rp->r_firstcell; cp != termcell; cp = cp->c_next) {
X if (cp->c_col < mincol) continue;
X if (cp->c_col > maxcol) break;
X cp->c_marks |= mark;
X count++;
X }
X }
X return(count);
X}
X
X
X/*
X * Find the range of all marked cells for an object. Returns nonzero if
X * no cells were marked.
X */
Xmarkminmax(obj, mark, minrow, maxrow, mincol, maxcol)
X struct object *obj; /* object to search */
X register int mark; /* mark to search for */
X long *minrow, *maxrow, *mincol, *maxcol; /* results */
X{
X register struct row *rp; /* current row */
X register struct cell *cp; /* current cell */
X register int row; /* current row */
X long minr, maxr, minc, maxc; /* temp variables */
X
X minr = INFINITY;
X maxr = -INFINITY;
X minc = INFINITY;
X maxc = -INFINITY;
X for (rp = obj->o_firstrow; rp != termrow; rp = rp->r_next) {
X row = rp->r_row;
X for (cp = rp->r_firstcell; cp != termcell; cp = cp->c_next) {
X if ((cp->c_marks & mark) == 0) continue;
X if (row < minr) minr = row;
X if (row > maxr) maxr = row;
X if (cp->c_col < minc) minc = cp->c_col;
X if (cp->c_col > maxc) maxc = cp->c_col;
X }
X }
X if (minr > maxr) return(1);
X *minrow = minr;
X *maxrow = maxr;
X *mincol = minc;
X *maxcol = maxc;
X return(0);
X}
X
X
X/* Count the number of marked cells in an object */
Xcountmarks(obj, mark)
X struct object *obj; /* object to check */
X register int mark; /* mark to be counted */
X{
X register struct row *rp; /* row pointer */
X register struct cell *cp; /* cell pointer */
X register long count; /* number of cells */
X
X count = 0;
X for (rp = obj->o_firstrow; rp != termrow; rp = rp->r_next) {
X for (cp = rp->r_firstcell; cp != termcell; cp = cp->c_next) {
X if (cp->c_marks & mark) count++;
X }
X }
X return(count);
X}
X
X
X/*
X * Move marked cells to another object. If the destination object is NULL
X * the cells are just deleted. The previous cells of the destination object
X * are deleted.
X */
Xmovemarkedobject(sobj, dobj, mark)
X register struct object *sobj; /* source object */
X struct object *dobj; /* destination object */
X{
X register struct row *rp; /* row pointer */
X register struct cell *cp; /* current cell pointer */
X register struct cell *pcp; /* previous cell pointer */
X register struct cell *ncp; /* next cell pointer */
X
X if (sobj == dobj) error("Moving object to itself");
X if (dobj) {
X zeroobject(dobj);
X dobj->o_currow = sobj->o_currow;
X dobj->o_curcol = sobj->o_curcol;
X }
X for (rp = sobj->o_firstrow; rp != termrow; rp = rp->r_next) {
X pcp = NULL;
X cp = rp->r_firstcell;
X while (cp != termcell) {
X if ((cp->c_marks & mark) == 0) {
X pcp = cp;
X cp = cp->c_next;
X continue;
X }
X if (dobj) addcell(dobj, rp->r_row, cp->c_col);
X ncp = cp->c_next;
X if (pcp == NULL)
X rp->r_firstcell = ncp;
X else
X pcp->c_next = ncp;
X if (ncp == termcell) rp->r_lastcell = pcp;
X cp->c_next = freecells;
X freecells = cp;
X cp = ncp;
X rp->r_count--;
X sobj->o_count--;
X }
X }
X}
X
X
X/*
X * Copy marked cells to another object. The previous cells of the destination
X * object are deleted. The source object is unaffected.
X */
Xcopymarkedobject(sobj, dobj, mark)
X register struct object *sobj; /* source object */
X register struct object *dobj; /* destination object */
X register int mark; /* mark value */
X{
X register struct row *rp; /* row pointer */
X register struct cell *cp; /* current cell */
X
X if (sobj == dobj) error("Copying object to itself");
X zeroobject(dobj);
X dobj->o_currow = sobj->o_currow;
X dobj->o_curcol = sobj->o_curcol;
X for (rp = sobj->o_firstrow; rp != termrow; rp = rp->r_next) {
X for (cp = rp->r_firstcell; cp != termcell; cp = cp->c_next) {
X if ((cp->c_marks & mark) == 0) continue;
X addcell(dobj, rp->r_row, cp->c_col);
X }
X }
X}
X
X
X/*
X * Rotate the marked cells in the given object around the current cursor
X * location. This deletes the marked cells, and reinserts them after
X * their position has been rotated by 90 degrees clockwise.
X */
Xrotatemarkedobject(obj, mark)
X register struct object *obj; /* current object */
X{
X register struct row *rp; /* current row */
X register struct cell *cp; /* current cell */
X register int row, col; /* current row and column */
X
X if (obj == tempobject) error("Using temp object");
X movemarkedobject(obj, tempobject, mark);
X for (rp = tempobject->o_firstrow; rp != termrow; rp = rp->r_next) {
X row = rp->r_row - obj->o_currow;
X for (cp = rp->r_firstcell; cp != termcell; cp = cp->c_next) {
X col = cp->c_col - obj->o_curcol;
X addcell(obj, obj->o_currow + col, obj->o_curcol - row);
X }
X }
X}
X
X
X/*
X * Flip the marked cells in the given object around the column of the current
X * cursor location. This deletes the marked cells, and reinserts them after
X * their position has been flipped around the vertical axis.
X */
Xflipmarkedobject(obj, mark)
X register struct object *obj; /* current object */
X{
X register struct row *rp; /* current row */
X register struct cell *cp; /* current cell */
X register int row, col; /* current row and column */
X
X if (obj == tempobject) error("Using temp object");
X movemarkedobject(obj, tempobject, mark);
X for (rp = tempobject->o_firstrow; rp != termrow; rp = rp->r_next) {
X row = rp->r_row;
X for (cp = rp->r_firstcell; cp != termcell; cp = cp->c_next) {
X col = cp->c_col - obj->o_curcol;
X addcell(obj, row, obj->o_curcol - col);
X }
X }
X}
//E*O*F mark.c//
echo x - object.c
sed -e 's/^X//' > "object.c" << '//E*O*F object.c//'
X#ifdef SCCS
Xstatic char *sccsid = "@(#)object.c 1.17 2/2/85";
Xstatic char *cpyrid = "@(#)Copyright (C) 1985 by D Bell";
X#endif
X
X#include "life.h"
X
X
X/*
X * Find the given named object. Returns NULL if nonexistant. The special
X * name of "." means the current object. The special name of ".." means
X * the previous object.
X */
Xstruct object *
Xfindobject(str)
X register char *str; /* name to find */
X{
X register struct object *obj; /* current object */
X
X if (str[0] == '.') { /* check for "." or ".." */
X if (str[1] == '\0') return(curobj);
X if ((str[1] == '.') && (str[2] == '\0')) return(prevobj);
X }
X for (obj = objects; obj; obj = obj->o_next) {
X if (strcmp(obj->o_name, str) == 0) return(obj);
X }
X return(NULL);
X}
X
X
X/* Create the given named object, or return it if it already exists. */
Xstruct object *
Xgetobject(str)
X register char *str; /* name to find */
X{
X register struct object *obj; /* current object */
X
X for (obj = objects; obj; obj = obj->o_next) {
X if (strcmp(obj->o_name, str) == 0) return(obj);
X }
X if (strlen(str) > MAXNAME) error("Object name too long");
X if ((reserve==0) && BADNAME(str)) error("Cannot create reserved name");
X obj = allocobject();
X obj->o_next = objects;
X objects = obj;
X strcpy(obj->o_name, str);
X return(obj);
X}
X
X
X/*
X * Set an object as the current one. The old current object is remembered
X * so that it can be referenced using "..". This cancels any insert mode.
X */
Xsetobject(obj)
X register struct object *obj; /* new object to set */
X{
X mode = M_MOVE;
X if (obj == curobj) return;
X prevobj = curobj;
X curobj = obj;
X redraw = 1;
X}
X
X
X/* Delete all cells of an object */
Xzeroobject(obj)
X register struct object *obj;
X{
X register struct row *rp;
X
X rp = obj->o_firstrow;
X if (rp == termrow) return;
X for (; rp != termrow; rp = rp->r_next) {
X if (rp->r_firstcell == termcell) continue;
X rp->r_lastcell->c_next = freecells;
X freecells = rp->r_firstcell;
X obj->o_count -= rp->r_count;
X }
X obj->o_lastrow->r_next = freerows;
X freerows = obj->o_firstrow;
X obj->o_firstrow = termrow;
X obj->o_lastrow = NULL;
X}
X
X
X/*
X * Destroy the existence of an object. If it is the current object,
X * switch the current object back to the previous object.
X */
Xdestroyobject(obj)
X register struct object *obj; /* object to delete */
X{
X register struct object *pobj; /* previous object */
X
X if (obj == NULL) return;
X if (obj->o_reserved) error("Cannot destroy reserved object");
X if (obj == prevobj) prevobj = mainobject;
X if (obj == curobj) {
X curobj = prevobj;
X prevobj = mainobject;
X redraw = 1;
X }
X zeroobject(obj);
X if (objects == obj) { /* first object in list */
X objects = obj->o_next;
X obj->o_next = freeobjects;
X freeobjects = obj;
X return;
X }
X for (pobj = objects; pobj->o_next != obj; pobj = pobj->o_next) ;
X pobj->o_next = obj->o_next;
X obj->o_next = freeobjects;
X freeobjects = obj;
X}
X
X
X/*
X * Move one object to another. The source object is zeroed, and the
X * previous contents of the destination object are lost.
X */
Xmoveobject(sobj, dobj)
X register struct object *sobj; /* source object */
X register struct object *dobj; /* destination object */
X{
X if (sobj == dobj) error("Moving object to itself");
X zeroobject(dobj);
X dobj->o_currow = sobj->o_currow;
X dobj->o_curcol = sobj->o_curcol;
X dobj->o_minrow = sobj->o_minrow;
X dobj->o_maxrow = sobj->o_maxrow;
X dobj->o_mincol = sobj->o_mincol;
X dobj->o_maxcol = sobj->o_maxcol;
X dobj->o_scale = sobj->o_scale;
X dobj->o_autoscale = sobj->o_autoscale;
X dobj->o_prow = sobj->o_prow;
X dobj->o_pcol = sobj->o_pcol;
X dobj->o_firstrow = sobj->o_firstrow;
X dobj->o_lastrow = sobj->o_lastrow;
X dobj->o_count = sobj->o_count;
X sobj->o_firstrow = termrow;
X sobj->o_lastrow = NULL;
X sobj->o_count = 0;
X}
X
X
X/*
X * Add one object to another. The source object is unchanged. The
X * destination object will get all cells from both objects. If disp is
X * RELATIVE, the object is displaced as specified by the two object's cursor
X * positions. Otherwise, the addition is performed with absolute coordinates.
X */
Xaddobject(sobj, dobj, disp)
X register struct object *sobj; /* source object */
X register struct object *dobj; /* destination object */
X{
X register struct row *rp; /* current row */
X register struct cell *cp; /* current cell */
X register int newrow; /* new row number */
X int rowdisp, coldisp; /* displacements */
X
X if (sobj == dobj) error("Adding object to itself");
X rowdisp = 0;
X coldisp = 0;
X if (disp == RELATIVE) {
X rowdisp = dobj->o_currow - sobj->o_currow;
X coldisp = dobj->o_curcol - sobj->o_curcol;
X }
X for (rp = sobj->o_firstrow; rp != termrow; rp = rp->r_next) {
X newrow = rp->r_row + rowdisp;
X for (cp = rp->r_firstcell; cp != termcell; cp = cp->c_next) {
X addcell(dobj, newrow, cp->c_col + coldisp);
X }
X }
X}
X
X
X/*
X * Copy one object to another. The source object is unchanged.
X * The current contents of the destination object are lost.
X */
Xcopyobject(sobj, dobj)
X register struct object *sobj; /* source object */
X register struct object *dobj; /* destination object */
X{
X if (sobj == dobj) error("Copying object to itself");
X zeroobject(dobj);
X addobject(sobj, dobj, ABSOLUTE);
X dobj->o_currow = sobj->o_currow;
X dobj->o_curcol = sobj->o_curcol;
X dobj->o_minrow = sobj->o_minrow;
X dobj->o_maxrow = sobj->o_maxrow;
X dobj->o_mincol = sobj->o_mincol;
X dobj->o_maxcol = sobj->o_maxcol;
X dobj->o_scale = sobj->o_scale;
X dobj->o_autoscale = sobj->o_autoscale;
X dobj->o_prow = sobj->o_prow;
X dobj->o_pcol = sobj->o_pcol;
X}
X
X
X/*
X * Show the list of objects. If all is nonzero, all objects will be
X * shown. Otherwise, only objects not starting with a period are shown.
X */
Xlistobjects(all)
X{
X register struct object *obj; /* current object */
X register int ch; /* current character */
X int minrow, maxrow, mincol, maxcol; /* current bounds */
X
X dpywindow(0, -1, 0, -1);
X dpystr("cells height width gen scale object\n");
X dpystr("----- ------ ----- --- ----- ------\n");
X for (obj = objects; obj; obj = obj->o_next) {
X if ((all == 0) && (obj->o_name[0] == '.')) continue;
X ch = ' ';
X if (obj == prevobj) ch = '+';
X if (obj == curobj) ch = '*';
X minmax(obj, &minrow, &maxrow, &mincol, &maxcol);
X dpyprintf("%d\t%d\t%d\t%d\t%d\t%c %s\n",
X obj->o_count, (maxrow - minrow + 1),
X (maxcol - mincol + 1), obj->o_gen,
X obj->o_scale, ch, obj->o_name);
X }
X dpyprintf("\n\
XIn object column, '*' = current object, '+' = previous object\n");
X if (all == 0)
X dpyprintf("Use -a to show objects beginning with '.'\n");
X spacewait();
X}
X
X
X/*
X * Find the minimum and maximum row and column numbers for an object.
X * If there are no cells in the object, the mins will be one more than
X * the maxes. Returns nonzero if the object has no cells.
X */
Xminmax(obj, minrow, maxrow, mincol, maxcol)
X struct object *obj; /* object to examine */
X long *minrow, *maxrow, *mincol, *maxcol; /* pointers to result */
X{
X register struct row *rp; /* current row */
X register int maxr, minr, maxc, minc; /* current results */
X int err; /* return value */
X
X minr = INFINITY;
X maxr = -INFINITY;
X minc = INFINITY;
X maxc = -INFINITY;
X err = 1;
X for (rp = obj->o_firstrow; rp != termrow; rp = rp->r_next) {
X if (rp->r_firstcell == termcell) continue;
X if (rp->r_row < minr) minr = rp->r_row;
X maxr = rp->r_row;
X if (rp->r_firstcell->c_col<minc) minc = rp->r_firstcell->c_col;
X if (rp->r_lastcell->c_col>maxc) maxc = rp->r_lastcell->c_col;
X err = 0;
X }
X if (err) { /* no cells in object */
X minr = 1;
X maxr = 0;
X minc = 1;
X maxc = 0;
X }
X *minrow = minr;
X *maxrow = maxr;
X *mincol = minc;
X *maxcol = maxc;
X return(err);
X}
X
X
X/*
X * Search forwards for the nth next object, restarting at the top if necessary.
X * If all is nonzero, or if wrap around occurs, the search will be over all
X * objects. Otherwise, objects found in previous searches will be skipped.
X * Returns nonzero if nothing was found.
X */
Xsearchobject(obj, count, all)
X register struct object *obj; /* object to search through */
X{
X register struct row *rp; /* current row being examined */
X register struct cell *cp; /* current cell begin examined */
X register long row; /* current row */
X register long col; /* current column */
X
X if (all) clearmarks(obj, MARK_SRC);
X row = obj->o_currow;
X col = obj->o_curcol;
X for (rp = obj->o_firstrow; row > rp->r_row; rp = rp->r_next) ;
X for (cp = rp->r_firstcell; col > cp->c_col; cp = cp->c_next) ;
X if ((row == rp->r_row) && (col == cp->c_col) &&
X ((cp->c_marks & MARK_SRC) == 0)) count++;
X while (1) {
X if (stop) return(0);
X if (cp == termcell) {
X rp = rp->r_next;
X if (rp == termrow) {
X clearmarks(obj, MARK_SRC);
X rp = obj->o_firstrow;
X }
X cp = rp->r_firstcell;
X continue;
X }
X if ((cp->c_marks & MARK_SRC) == 0) {
X markobject(obj, rp->r_row, cp->c_col, MARK_SRC);
X if (--count <= 0) break;
X }
X cp = cp->c_next;
X }
X obj->o_currow = rp->r_row;
X obj->o_curcol = cp->c_col;
X return(0);
X}
//E*O*F object.c//
echo x - scan.c
sed -e 's/^X//' > "scan.c" << '//E*O*F scan.c//'
X#ifdef SCCS
Xstatic char *sccsid = "@(#)scan.c 1.4 1/27/85";
Xstatic char *cpyrid = "@(#)Copyright (C) 1985 by D Bell";
X#endif
X
X/* Module to read self-terminating input while allowing editing of the input */
X
X#include <sgtty.h>
X#include "life.h"
X
Xjmp_buf *scanjumpbuf; /* jump buffer to use in scanchar */
Xchar scanbuffer[SCAN_SIZE+1]; /* storage for characters */
Xchar *scanreadptr; /* current read pointer */
Xchar *scanwriteptr; /* current write pointer */
Xchar (*scanroutine)(); /* routine to read characters */
Xstatic char rubchar; /* erase letter character */
Xstatic char rubword; /* erase word character */
Xstatic char rubline; /* erase line character */
Xstatic char litchar; /* literal input */
X
X
X/*
X * Initialize for later calls to scanchar.
X */
Xscaninit(routine, jumpbuf)
X char (*routine)(); /* routine to get characters */
X jmp_buf *jumpbuf; /* jump buffer to use later */
X{
X struct sgttyb sgbuf; /* basic tty structure */
X struct ltchars ltbuf; /* local tty structure */
X
X scanroutine = routine; /* init static variables */
X scanjumpbuf = jumpbuf;
X scanwriteptr = scanbuffer;
X scanreadptr = scanbuffer;
X sgbuf.sg_erase = CERASE; /* set defaults in case ioctls fail */
X sgbuf.sg_kill = CKILL;
X ltbuf.t_werasc = CWERASE;
X ltbuf.t_lnextc = CLNEXT;
X ioctl(STDIN, TIOCGETP, &sgbuf); /* get and save editing characters */
X ioctl(STDIN, TIOCGLTC, <buf);
X rubchar = sgbuf.sg_erase;
X rubline = sgbuf.sg_kill;
X rubword = ltbuf.t_werasc;
X litchar = ltbuf.t_lnextc;
X}
X
X
X/*
X * Read the next input character. If it is an editing character,
X * abort the current context and longjmp back to the last setjmp.
X * NOTE: for proper results, the caller should not alter the global
X * state until the full command has been read in. This includes such
X * things as prompting for input or saving values. Otherwise, improper
X * results will occur if the user edits the command.
X */
Xscanchar()
X{
X register int ch; /* current character */
X
Xloop: if (scanreadptr < scanwriteptr) /* get saved char if have any */
X return(*scanreadptr++);
X ch = scanroutine() & 0x7f; /* get new character */
X if (ch == litchar) { /* literal input */
X ch = scanroutine() & 0x7f;
X goto store;
X }
X if (ch == rubchar) { /* character erase */
X if (scanwriteptr <= scanbuffer) {
X write(STDERR, "\007", 1);
X goto loop;
X }
X scanwriteptr--;
X scanreadptr = scanbuffer;
X longjmp(scanjumpbuf, SCAN_EDIT);
X }
X if (ch == rubword) { /* word erase */
X if (scanwriteptr <= scanbuffer) goto loop;
X while ((--scanwriteptr >= scanbuffer) &&
X ((*scanwriteptr == ' ') || (*scanwriteptr == '\t'))) ;
X scanwriteptr++;
X while ((--scanwriteptr >= scanbuffer) &&
X ((*scanwriteptr != ' ') && (*scanwriteptr != '\t'))) ;
X scanwriteptr++;
X scanreadptr = scanbuffer;
X longjmp(scanjumpbuf, SCAN_EDIT);
X }
X if (ch == rubline) { /* line erase */
X if (scanwriteptr <= scanbuffer) goto loop;
X scanwriteptr = scanbuffer;
X scanreadptr = scanbuffer;
X longjmp(scanjumpbuf, SCAN_EDIT);
X }
X
Xstore: if (scanwriteptr >= scanbuffer + SCAN_SIZE) {
X write(STDERR, "\007", 1);
X goto loop;
X }
X *scanwriteptr++ = ch;
X return(*scanreadptr++);
X}
X
X
X/* Abort reading of the current command */
Xscanabort()
X{
X scanreadptr = scanbuffer;
X scanwriteptr = scanbuffer;
X longjmp(scanjumpbuf, SCAN_ABORT);
X}
X
X
X/* Indicate no more characters ready yet */
Xscaneof()
X{
X scanreadptr = scanbuffer;
X longjmp(scanjumpbuf, SCAN_EOF);
X}
X
X
X/* Simply reset input and output pointers without longjmping */
Xscanreset()
X{
X scanreadptr = scanbuffer;
X scanwriteptr = scanbuffer;
X}
//E*O*F scan.c//
echo x - vars.c
sed -e 's/^X//' > "vars.c" << '//E*O*F vars.c//'
X#ifdef SCCS
Xstatic char *sccsid = "@(#)vars.c 1.11 2/2/85";
Xstatic char *cpyrid = "@(#)Copyright (C) 1985 by D Bell";
X#endif
X
X#include "life.h"
X
Xenum vars { /* ordering of variables */
X v_minx, v_miny, v_maxx, v_maxy, v_cells, v_cx, v_cy, v_px, v_py,
X v_vminx, v_vmaxx, v_vminy, v_vmaxy, v_vcells, v_vx, v_vy,
X v_sminx, v_smaxx, v_sminy, v_smaxy, v_scells, v_gen, v_scale,
X v_freq, v_born, v_died, v_endlist
X};
X
X
X/*
X * Table of multi-character variables. These are arranged in this table
X * in rows of 3 so that you can see what the display will look like for
X * the listvariables routine.
X */
Xstruct vartab {
X char *v_name; /* name of variable */
X enum vars v_type; /* variable id */
X} vartab[] = {
X "cx", v_cx, "vx", v_vx, "px", v_px,
X "cy", v_cy, "vy", v_vy, "py", v_py,
X "minx", v_minx, "vminx", v_vminx, "sminx", v_sminx,
X "maxx", v_maxx, "vmaxx", v_vmaxx, "smaxx", v_smaxx,
X "maxy", v_maxy, "vmaxy", v_vmaxy, "smaxy", v_smaxy,
X "miny", v_miny, "vminy", v_vminy, "sminy", v_sminy,
X "cells", v_cells, "vcells", v_vcells, "scells", v_scells,
X "gen", v_gen, "born", v_born, "died", v_died,
X "scale", v_scale, "freq", v_freq, NULL, v_endlist
X};
X
X
Xstatic char *curcp; /* current character to parse */
Xstatic long lowervars[26]; /* lower case single-char variable values */
Xstatic long uppervars[26]; /* upper case single-char variable values */
X
X
X/*
X * Return the value of a multiple character variable name. This can be
X * either a single character name, or else one of a fixed set of multi-
X * character names. All variable names must start with either a letter
X * or a dollar sign followed by a letter.
X */
Xgetvariable(cp)
X register char *cp; /* name of variable */
X{
X register struct vartab *vp; /* variable pointer */
X
X if (*cp == '$') cp++; /* skip any dollar sign */
X if (cp[1] == '\0') { /* single character name */
X return(getvariable1(*cp));
X }
X if (((*cp < 'a') || (*cp > 'z')) && ((*cp < 'A') || (*cp > 'Z'))) {
X error("Bad variable name");
X }
X for (vp = vartab; ; vp++) { /* find name in table */
X if (vp->v_name == NULL) error("Unknown variable");
X if (strcmp(vp->v_name, cp) == 0) break;
X }
X return(getvariablebytype(vp->v_type)); /* get value */
X}
X
X
X/*
X * Return the value of a variable given its enum value.
X */
Xgetvariablebytype(type)
X enum vars type; /* variable type to get */
X{
X register struct object *obj; /* current object */
X register long value; /* value to return */
X register long *ptr; /* pointer to minmax value */
X register long *sptr; /* another one */
X long sign; /* sign for result */
X long minrow, maxrow, mincol, maxcol; /* results of minmax */
X
X obj = curobj;
X value = 0;
X sign = 1;
X ptr = NULL;
X sptr = NULL;
X
X switch (type) { /* collect value */
X case v_cx: value = obj->o_curcol; break;
X case v_cy: value = -obj->o_currow; break;
X case v_px: value = obj->o_pcol; break;
X case v_py: value = -obj->o_prow; break;
X case v_vx: value = (obj->o_mincol + obj->o_maxcol) / 2; break;
X case v_vy: value = -(obj->o_minrow + obj->o_maxrow) / 2; break;
X case v_vminx: value = obj->o_mincol; break;
X case v_vmaxx: value = obj->o_maxcol; break;
X case v_vminy: value = -obj->o_maxrow; break;
X case v_vmaxy: value = -obj->o_minrow; break;
X case v_vcells: value = markregion(obj, MARK_ANY, obj->o_minrow,
X obj->o_maxrow, obj->o_mincol, obj->o_maxcol);
X break;
X case v_cells: value = obj->o_count; break;
X case v_gen: value = obj->o_gen; break;
X case v_born: value = obj->o_born; break;
X case v_died: value = obj->o_died; break;
X case v_freq: value = frequency; break;
X case v_scale: value = obj->o_scale; break;
X case v_minx: ptr = &mincol; break;
X case v_maxx: ptr = &maxcol; break;
X case v_miny: ptr = &maxrow; sign = -1; break;
X case v_maxy: ptr = &minrow; sign = -1; break;
X case v_scells: value = countmarks(obj, MARK_SEE); break;
X case v_sminx: sptr = &mincol; break;
X case v_smaxx: sptr = &maxcol; break;
X case v_sminy: sptr = &maxrow; sign = -1; break;
X case v_smaxy: sptr = &minrow; sign = -1; break;
X }
X /*
X * Call proper minmax routines if we need to
X */
X if (ptr && (minmax(obj, &minrow, &maxrow, &mincol, &maxcol) == 0))
X value = *ptr;
X if (sptr&&(markminmax(obj,MARK_SEE,&minrow,&maxrow,&mincol,&maxcol)==0))
X value = *sptr;
X return(sign * value);
X}
X
X
X/*
X * Return the value of a single character variable name (a-z or A-Z).
X */
Xgetvariable1(ch)
X register int ch; /* variable character */
X{
X if ((ch >= 'a') && (ch <= 'z'))
X return(lowervars[ch - 'a']);
X if ((ch >= 'A') && (ch <= 'Z'))
X return(lowervars[ch - 'A']);
X error("Bad variable name");
X}
X
X
X/*
X * Set the value of a variable name. Multi-character names cannot be set.
X */
Xsetvariable(cp, value)
X register char *cp; /* name of variable to set */
X{
X if (*cp == '$') cp++; /* skip any dollar sign */
X if (cp[1] != '\0') {
X error("Cannot set multi-character variables");
X }
X setvariable1(*cp, value); /* do it */
X}
X
X
X/*
X * Set the value of a single-character variable (a-z or A-Z).
X */
Xsetvariable1(ch, value)
X register int ch; /* variable character */
X{
X if ((ch >= 'a') && (ch <= 'z')) {
X lowervars[ch - 'a'] = value;
X return;
X }
X if ((ch >= 'A') && (ch <= 'Z')) {
X lowervars[ch - 'A'] = value;
X return;
X }
X error("Bad variable name");
X}
X
X
X/*
X * Display the current values of the variables. Show all multi-character
X * variable values, and those single character variables which have a
X * nonzero value. The output is given three variables per line.
X */
Xlistvariables()
X{
X register struct vartab *vp; /* variable table pointer */
X register long *var; /* simple variable pointer */
X register int count; /* counter for formatting */
X
X dpywindow(0, -1, 0, -1);
X dpyprintf("Variable names and values:");
X count = 0;
X for (vp = vartab; vp->v_name; vp++) {
X dpyprintf("%s%s\t%d", (count++ % 3) ? "\t\t" : "\n",
X vp->v_name, getvariablebytype(vp->v_type));
X }
X count = 0; /* create blank line */
X for (var = uppervars; var < &uppervars[26]; var++) {
X if (*var == 0) continue;
X if (count == 0) dpychar('\n');
X dpyprintf("%s%c\t%d", (count++ % 3) ? "\t\t" : "\n",
X 'A' + (var - uppervars), *var);
X }
X for (var = lowervars; var < &lowervars[26]; var++) {
X if (*var == 0) continue;
X if (count == 0) dpychar('\n');
X dpyprintf("%s%c\t%d", (count++ % 3) ? "\t\t" : "\n",
X 'a' + (var - lowervars), *var);
X }
X dpyprintf("\n\nMany names starting with 'v' refer to visible cells\n");
X dpyprintf("Many names starting with 's' refer to selected cells\n");
X spacewait(); /* wait for space before clearing */
X}
X
X
X/*
X * Evaluate an expression and return its value. The expression can
X * contain numbers, variables, the normal arithmetic operators, and
X * parenthesized expressions. The usual precedence rules are used.
X */
Xgetexpression(str)
X register char *str; /* string to parse */
X{
X long value; /* resulting value */
X
X while (*str == ' ') str++;
X if (*str == '\0') error("Null expression");
X curcp = str;
X value = parsesum();
X if (*curcp != '\0') error("Bad expression");
X return(value);
X}
X
X
X/* Parse the sum of products */
Xparsesum()
X{
X register long value; /* value to return */
X
X while (*curcp == ' ') curcp++;
X switch (*curcp) { /* check for uninary operators */
X case '-':
X curcp++;
X value = -parseproduct();
X break;
X case '+':
X curcp++;
X /* proceed into default case */
X default:
X value = parseproduct();
X }
X while (1) switch (*curcp++) {
X case '+': /* sum of products */
X value += parseproduct();
X continue;
X case '-': /* difference of products */
X value -= parseproduct();
X continue;
X case ' ': /* space */
X continue;
X default: /* end of sum */
X curcp--;
X return(value);
X }
X}
X
X
X/* Parse the product of terms */
Xparseproduct()
X{
X register long value; /* value to return */
X register long value2; /* temporary value */
X
X value = parseterm();
X while (1) switch (*curcp++) {
X case '*': /* product of terms */
X value *= parseterm();
X continue;
X case '/': /* division of terms */
X value2 = parseterm();
X if (value2 == 0) error("division by zero");
X value /= value2;
X continue;
X case '%': /* modulo of terms */
X value2 = parseterm();
X if (value2 == 0) error("division by zero");
X value %= value2;
X continue;
X case ' ': /* space */
X continue;
X default: /* end of product */
X curcp--;
X return(value);
X }
X}
X
X
X/* Parse a single term */
Xparseterm()
X{
X register long value; /* value to return */
X register int ch; /* current character */
X
X while (*curcp == ' ') curcp++;
X ch = *curcp;
X if ((ch >= '0') && (ch <= '9')) { /* number */
X value = 0;
X do
X value = (value * 10) + *curcp++ - '0';
X while ((*curcp >= '0') && (*curcp <= '9'));
X return(value);
X }
X if (ch == '(') { /* parenthesized expression */
X curcp++;
X while (*curcp == ' ') curcp++;
X if (*curcp == ')') error("Null expression");
X value = parsesum();
X while (*curcp == ' ') curcp++;
X if (*curcp != ')') error("Unmatched parenthesis");
X *curcp++;
X return(value);
X }
X if (ch == ')') error("Unmatched parenthesis");
X return(parsename());
X}
X
X
X/*
X * Parse a variable name and return its value.
X */
Xparsename()
X{
X register char *cp; /* current character */
X register long value; /* value of variable */
X char oldch; /* old character after name */
X
X cp = curcp;
X if (*cp == '$') cp++;
X while (((*cp >= 'a') && (*cp <= 'z')) ||
X ((*cp >= 'A') && (*cp <= 'Z')) ||
X ((*cp >= '0') && (*cp <= '9'))) cp++;
X oldch = *cp;
X *cp = '\0';
X value = getvariable(curcp);
X *cp = oldch;
X curcp = cp;
X return(value);
X}
//E*O*F vars.c//
echo x - view.c
sed -e 's/^X//' > "view.c" << '//E*O*F view.c//'
X#ifdef SCCS
Xstatic char *sccsid = "@(#)view.c 1.5 2/2/85";
Xstatic char *cpyrid = "@(#)Copyright (C) 1985 by D Bell";
X#endif
X
X#include "life.h"
X
X
X/*
X * Set the scaling factor for the specified object. This also centers
X * the view around the current cursor location.
X */
Xsetscale(obj, sf)
X register struct object *obj; /* object to set scale of */
X register int sf; /* scaling factor */
X{
X if (sf <= 0) sf = 1;
X if (sf > MAXSCALE) sf = MAXSCALE;
X obj->o_scale = sf;
X obj->o_minrow = obj->o_currow - (rowradius * sf) + (sf / 2);
X obj->o_maxrow = obj->o_minrow + (2 * rowradius * sf);
X obj->o_mincol = obj->o_curcol - (colradius * sf) + (sf / 2);
X obj->o_maxcol = obj->o_mincol + (2 * colradius * sf);
X if (obj == curobj) redraw = 1; /* update if object visible */
X}
X
X
X/*
X * Perform auto-scaling of the current object. This implies picking a
X * scaling factor such that the whole object fits in the screen. The
X * scale factor is never decreased. When the scale factor is large,
X * convenient ones are picked. Returns the new scale factor.
X */
Xautoscale()
X{
X register struct object *obj; /* current object */
X register int sf; /* scaling factor */
X int minrow, maxrow, mincol, maxcol; /* limits of object */
X
X obj = curobj;
X minmax(obj, &minrow, &maxrow, &mincol, &maxcol);
X sf = obj->o_scale;
X if (mincol > maxcol) return(sf);
X while ((sf <= MAXSCALE) &&
X ((minrow < obj->o_minrow) || (maxrow > obj->o_maxrow) ||
X (mincol < obj->o_mincol) || (maxcol > obj->o_maxcol))) {
X sf++;
X if (sf > 20) sf += (5 - (sf % 5));
X if (sf > 50) sf += (10 - (sf % 10));
X if (sf > 200) sf += (100 - (sf % 100));
X setscale(obj, sf);
X }
X return(obj->o_scale);
X}
X
X
X/*
X * Position the view of the current object to show both the given region and
X * the current cursor location. If this is impossible, just the cursor
X * location will be positioned.
X */
Xpositionview(minrow, maxrow, mincol, maxcol)
X register long minrow, maxrow, mincol, maxcol; /* region to show */
X{
X register struct object *obj; /* current object */
X register int sf; /* current scale factor */
X
X obj = curobj;
X sf = obj->o_scale;
X if (minrow > obj->o_currow) minrow = obj->o_currow;
X if (maxrow < obj->o_currow) maxrow = obj->o_currow;
X if (mincol > obj->o_curcol) mincol = obj->o_curcol;
X if (maxcol < obj->o_curcol) maxcol = obj->o_curcol;
X if ((maxrow - minrow) > (2 * sf * rowradius)) { /* too many rows */
X minrow = obj->o_currow;
X maxrow = obj->o_currow;
X }
X if ((maxcol - mincol) > (2 * sf * colradius)) { /* too many columns */
X mincol = obj->o_curcol;
X maxcol = obj->o_curcol;
X }
X if (minrow < obj->o_minrow) {
X obj->o_minrow = minrow;
X obj->o_maxrow = minrow + (rowradius * sf * 2) + sf - 1;
X redraw = 1;
X }
X if (maxrow > obj->o_maxrow) {
X obj->o_maxrow = maxrow;
X obj->o_minrow = maxrow - (rowradius * sf * 2) + sf - 1;
X redraw = 1;
X }
X if (mincol < obj->o_mincol) {
X obj->o_mincol = mincol;
X obj->o_maxcol = mincol + (colradius * sf * 2) + sf - 1;
X redraw = 1;
X }
X if (maxcol > obj->o_maxcol) {
X obj->o_maxcol = maxcol;
X obj->o_mincol = maxcol - (colradius * sf * 2) + sf - 1;
X redraw = 1;
X }
X}
X
X
X/*
X * Show the view around the current window location if the view has changed.
X * The update flag indicates that the status line and cursor need updating.
X * The redraw flag indicates that the view of the cells also needs updating.
X */
Xupdateview()
X{
X register struct object *obj; /* current object */
X
X if ((interact | redraw | update) == 0) return;
X obj = curobj;
X positionview(obj->o_currow,obj->o_currow,obj->o_curcol,obj->o_curcol);
X if (obj->o_autoscale) autoscale();
X if (redraw) { /* show visible cells */
X freqcount = frequency;
X dpywindow(1, -1, 0, -1);
X if (obj->o_scale <= 1)
X viewnormal();
X else
X viewscale(obj->o_scale);
X dpyclearwindow();
X }
X if (redraw || update) { /* show status and position cursor */
X viewstatus();
X dpywindow(1, -1, 0, -1);
X dpymove((obj->o_currow - obj->o_minrow) / obj->o_scale,
X (obj->o_curcol - obj->o_mincol) / obj->o_scale);
X dpyupdate();
X }
X update = 0; /* no more updates until prodded */
X redraw = 0;
X interact = 0;
X}
X
X
X
X/*
X * Update the status line for the object.
X */
Xviewstatus()
X{
X register struct object *obj; /* current object */
X
X dpywindow(0, 0, 0, -1); /* output in top line */
X if (errorstring) { /* show error string if present */
X dpystr(errorstring);
X dpyclearline();
X return;
X }
X obj = curobj;
X dpyprintf("Gen:%d cells:%d", obj->o_gen, obj->o_count);
X if (obj->o_count > seecount)
X dpyprintf("(%du)", obj->o_count - seecount);
X if (obj->o_born) dpyprintf(" born:%d", obj->o_born);
X if (obj->o_died) dpyprintf(" died:%d", obj->o_died);
X if (frequency > 1) dpyprintf(" freq:%d", frequency);
X if ((obj->o_scale > 1) || (obj->o_autoscale))
X dpyprintf(" %scale:%d",
X (obj->o_autoscale ? "autos" : "s") , obj->o_scale);
X if (strcmp(rulestring, "3,23")) dpyprintf(" rules:%s", rulestring);
X if (obj->o_lock) dpystr(" locked");
X if (curinput > inputs) dpyprintf(" cmd-nest:%d", curinput - inputs);
X switch (curinput->i_type) {
X case INP_TTY: /* reading from terminal */
X if (curinput != inputs) dpystr(" tty-wait");
X break;
X case INP_FILE: /* reading from file */
X dpystr(" cmd-file");
X break;
X case INP_LOOP: /* reading from loop */
X if (curinput->i_macro) {
X dpyprintf(" macro-define-%c",curinput->i_macro);
X break;
X }
X dpyprintf(" loop%s (curval:%d end:%d)",
X curinput->i_first ? "-define" : "",
X curinput->i_curval, curinput->i_endval);
X break;
X case INP_MACRO: /* reading from macro */
X dpyprintf(" macro-%c", curinput->i_macro);
X break;
X }
X if (mode == M_INSERT) dpystr(" inserting");
X if (mode == M_DELETE) dpystr(" deleting");
X if (curobj != mainobject) dpyprintf(" \"%s\"", curobj->o_name);
X dpyclearwindow();
X}
X
X
X/* Show the cells around the cursor normally (scale factor of 1) */
Xviewnormal()
X{
X register struct row *rp; /* current row */
X register struct cell *cp; /* current cell */
X register int row; /* current row number */
X register int col; /* current column number */
X register char *str; /* characters for line */
X register char *endstr; /* end of characters for line */
X register struct object *obj; /* current object */
X
X obj = curobj;
X rp = obj->o_firstrow;
X row = obj->o_minrow;
X seecount = 0;
X while (row > rp->r_row) rp = rp->r_next;
X for (; row <= obj->o_maxrow; row++) {
X if (row != rp->r_row) { /* blank row */
X if (gridchar == ' ') {
X dpychar('\n');
X continue;
X }
X str = stringbuf;
X for (col = obj->o_mincol; col <= obj->o_maxcol; col++) {
X *str++ = gridchar;
X }
X *str++ = '\n';
X dpywrite(stringbuf, str - stringbuf);
X continue;
X }
X str = stringbuf;
X endstr = str;
X cp = rp->r_firstcell;
X col = obj->o_mincol;
X while (col > cp->c_col) cp = cp->c_next;
X for (; col <= obj->o_maxcol; col++) {
X if (col != cp->c_col) { /* blank cell */
X *str++ = gridchar;
X if (gridchar != ' ') endstr = str;
X continue;
X }
X *str = '#';
X if ((cp->c_marks & MARK_SEE) == 0) *str = 'O';
X endstr = ++str;
X seecount++;
X cp = cp->c_next;
X }
X *endstr++ = '\n';
X dpywrite(stringbuf, endstr - stringbuf);
X rp = rp->r_next;
X }
X}
X
X
X/*
X * Show the view around the cursor with an arbitrary scale factor.
X * When in this mode, characters from 1 to 9 (or * if 10 or more)
X * are used to indicate how many cells are in each n by n square.
X */
Xviewscale(sf)
X register int sf; /* scale factor */
X{
X register int row; /* current row number */
X register int col; /* current column number */
X register int sum; /* number of cells in square */
X register struct cell *cp; /* current cell structure */
X register struct object *obj; /* current object */
X struct cell **cpp; /* pointer into cell table */
X struct cell **endcpp; /* end of cell table */
X struct row *rp; /* row pointer */
X char *str; /* buffer pointer */
X char *endstr; /* end of buffer */
X struct cell *cptab[MAXSCALE]; /* table of rows */
X
X obj = curobj;
X row = obj->o_minrow;
X col = obj->o_mincol;
X endcpp = &cptab[sf];
X seecount = 0;
X for (rp = curobj->o_firstrow; (rp->r_row < row); rp = rp->r_next) ;
X while (row <= obj->o_maxrow) {
X /*
X * If there is a large gap to the next row number then
X * the terminal line is empty.
X */
X if (rp->r_row >= (row + sf)) { /* no rows here */
X if (gridchar == ' ') {
X dpychar('\n');
X row += sf;
X continue;
X }
X str = stringbuf;
X for (col=obj->o_mincol; col<=obj->o_maxcol; col+=sf) {
X *str++ = gridchar;
X }
X *str++ = '\n';
X dpywrite(stringbuf, str - stringbuf);
X row += sf;
X continue;
X }
X /*
X * Collect the rows to be searched for one terminal line.
X * Dummy up empty rows if necessary.
X */
X for (cpp = cptab; cpp < endcpp; cpp++) {
X *cpp = termcell;
X if (rp->r_row > row++) continue;
X *cpp = rp->r_firstcell;
X rp = rp->r_next;
X }
X str = stringbuf;
X endstr = str;
X /*
X * Advance along each row to the next range of columns,
X * adding cells found to get the result for each square.
X */
X for (col = obj->o_mincol; col <= obj->o_maxcol; col += sf) {
X sum = 0;
X for (cpp = cptab; cpp < endcpp; cpp++) {
X cp = *cpp;
X while (col > cp->c_col) cp = cp->c_next;
X while ((col + sf) >= cp->c_col) {
X sum++;
X cp = cp->c_next;
X }
X *cpp = cp;
X }
X if (sum == 0) { /* no cells in square */
X *str++ = gridchar;
X if (gridchar != ' ') endstr = str;
X continue;
X }
X *str = '*'; /* show number of cells */
X if (sum <= 9) *str = '0' + sum;
X endstr = ++str;
X seecount += sum;
X }
X *endstr++ = '\n';
X dpywrite(stringbuf, endstr - stringbuf);
X }
X}
//E*O*F view.c//
echo done
More information about the Comp.sources.unix
mailing list