From: David I. Bell (dbell@pdact.pd.necisa.oz.au)
Date: Tue Mar 16 1993 - 06:30:24 UTC
#!/bin/sh
# this is LIFE.17 (part 17 of a multipart archive)
# do not concatenate these parts, unpack them in order with /bin/sh
# file life/mark.c continued
#
if touch 2>&1 | fgrep 'amc' > /dev/null
then TOUCH=touch
else TOUCH=true
fi
if test ! -r shar3_seq_.tmp; then
echo "Please unpack part 1 first!"
exit 1
fi
(read Scheck
if test "$Scheck" != 17; then
echo "Please unpack part $Scheck next!"
exit 1
else
exit 0
fi
) < shar3_seq_.tmp || exit 1
echo "x - Continuing file life/mark.c"
sed 's/^X//' << 'SHAR_EOF' >> life/mark.c &&
X * their position has been flipped around the horizontal axis.
X */
Xvoid
Xfliprowmarkedobject(obj, mark)
X OBJECT *obj;
X MARK mark;
X{
X register ROW *rp;
X register CELL *cp;
X COORD row;
X
X if (obj == tempobject)
X error("Using temp object");
X
X movemarkedobject(obj, tempobject, mark);
X
X for (rp = tempobject->o_firstrow; rp != termrow; rp = rp->r_next) {
X row = 2 * obj->o_currow - rp->r_row;
X for (cp = rp->r_firstcell; cp != termcell; cp = cp->c_next)
X addcell(obj, row, cp->c_col);
X }
X}
X
X/* END CODE */
SHAR_EOF
echo "File life/mark.c is complete" &&
$TOUCH -am 0316122993 life/mark.c &&
chmod 0644 life/mark.c ||
echo "restore of life/mark.c failed"
set `wc -c life/mark.c`;Wc_c=$1
if test "$Wc_c" != "9232"; then
echo original size 9232, current size $Wc_c
fi
# ============= life/object.c ==============
echo "x - extracting life/object.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > life/object.c &&
X/*
X * Copyright (c) 1993 David I. Bell
X * Permission is granted to use, distribute, or modify this source,
X * provided that this copyright notice remains intact.
X */
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 */
XOBJECT *
Xfindobject(str)
X char *str;
X{
X register OBJECT *obj;
X
X if (str[0] == '.') { /* check for "." or ".." */
X if (str[1] == '\0')
X return curobj;
X if ((str[1] == '.') && (str[2] == '\0'))
X return prevobj;
X }
X
X for (obj = objects; obj; obj = obj->o_next) {
X if (strcmp(obj->o_name, str) == 0)
X return obj;
X }
X
X return NULL;
X}
X
X
X/*
X * Create the given named object, or return it if it already exists.
X */
XOBJECT *
Xgetobject(str)
X char *str;
X{
X register OBJECT *obj;
X
X for (obj = objects; obj; obj = obj->o_next) {
X if (strcmp(obj->o_name, str) == 0)
X return obj;
X }
X
X if (strlen(str) > MAXNAME)
X error("Object name too long");
X if (!reserve && BADNAME(str))
X error("Cannot create reserved name");
X
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 */
Xvoid
Xsetobject(obj)
X register OBJECT *obj;
X{
X mode = M_MOVE;
X if (obj == curobj)
X return;
X prevobj = curobj;
X curobj = obj;
X update |= U_ALL;
X}
X
X
X/*
X * Delete all cells of an object.
X */
Xvoid
Xzeroobject(obj)
X register OBJECT *obj;
X{
X register ROW *rp;
X
X rp = obj->o_firstrow;
X if (rp == termrow)
X return;
X
X for (; rp != termrow; rp = rp->r_next) {
X if (rp->r_firstcell == termcell)
X continue;
X rp->r_lastcell->c_next = freecells;
X freecells = rp->r_firstcell;
X obj->o_count -= rp->r_count;
X }
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 */
Xvoid
Xdestroyobject(obj)
X register OBJECT *obj;
X{
X register OBJECT *pobj;
X
X if (obj == NULL)
X return;
X if (obj->o_reserved)
X error("Cannot destroy reserved object");
X if (obj == prevobj)
X prevobj = mainobject;
X
X if (obj == curobj) {
X curobj = prevobj;
X prevobj = mainobject;
X update |= U_ALL;
X }
X
X zeroobject(obj);
X
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
X for (pobj = objects; pobj->o_next != obj; pobj = pobj->o_next)
X ;
X
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 */
Xvoid
Xmoveobject(sobj, dobj)
X register OBJECT *sobj; /* source object */
X register OBJECT *dobj; /* destination object */
X{
X if (sobj == dobj)
X error("Moving object to itself");
X
X zeroobject(dobj);
X
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_frequency = sobj->o_frequency;
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 */
Xvoid
Xaddobject(sobj, dobj, disp)
X OBJECT *sobj; /* source object */
X OBJECT *dobj; /* destination object */
X COUNT disp;
X{
X register ROW *rp; /* current row */
X register CELL *cp; /* current cell */
X COORD newrow; /* new row number */
X COUNT rowdisp; /* displacements */
X COUNT coldisp;
X
X if (sobj == dobj)
X error("Adding object to itself");
X
X rowdisp = 0;
X coldisp = 0;
X
X if (disp == RELATIVE) {
X rowdisp = dobj->o_currow - sobj->o_currow;
X coldisp = dobj->o_curcol - sobj->o_curcol;
X }
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 */
Xvoid
Xcopyobject(sobj, dobj)
X register OBJECT *sobj; /* source object */
X register OBJECT *dobj; /* destination object */
X{
X if (sobj == dobj)
X error("Copying object to itself");
X
X zeroobject(dobj);
X addobject(sobj, dobj, ABSOLUTE);
X
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_frequency = sobj->o_frequency;
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 */
Xvoid
Xlistobjects(all)
X BOOL all;
X{
X register OBJECT *obj;
X int ch;
X COORD minrow;
X COORD maxrow;
X COORD mincol;
X COORD maxcol;
X char buf[80];
X
X showhelp("cells height width gen scale object\n");
X showhelp("----- ------ ----- --- ----- ------\n");
X
X for (obj = objects; obj; obj = obj->o_next) {
X if (!all && (obj->o_name[0] == '.'))
X continue;
X
X ch = ' ';
X if (obj == prevobj)
X ch = '+';
X if (obj == curobj)
X ch = '*';
X
X minmax(obj, &minrow, &maxrow, &mincol, &maxcol);
X
X sprintf(buf, "%ld\t%ld\t%ld\t%ld\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 showhelp(buf);
X }
X
X showhelp("\n\nin object column, '*' = current object, '+' = previous object\n");
X
X if (!all)
X showhelp("Use -a to show objects beginning with '.'\n");
X
X endhelp();
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 */
XBOOL
Xminmax(obj, minrow, maxrow, mincol, maxcol)
X OBJECT *obj;
X COORD *minrow;
X COORD *maxrow;
X COORD *mincol;
X COORD *maxcol;
X{
X register ROW *rp;
X COORD maxr;
X COORD minr;
X COORD maxc;
X COORD minc;
X BOOL err;
X
X minr = INFINITY;
X maxr = -INFINITY;
X minc = INFINITY;
X maxc = -INFINITY;
X err = TRUE;
X
X for (rp = obj->o_firstrow; rp != termrow; rp = rp->r_next) {
X if (rp->r_firstcell == termcell)
X continue;
X if (rp->r_row < minr)
X minr = rp->r_row;
X maxr = rp->r_row;
X if (rp->r_firstcell->c_col<minc)
X minc = rp->r_firstcell->c_col;
X if (rp->r_lastcell->c_col>maxc)
X maxc = rp->r_lastcell->c_col;
X err = FALSE;
X }
X
X if (err) { /* no cells in object */
X minr = 1;
X maxr = 0;
X minc = 1;
X maxc = 0;
X }
X
X *minrow = minr;
X *maxrow = maxr;
X *mincol = minc;
X *maxcol = maxc;
X
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 */
XBOOL
Xsearchobject(obj, count, all)
X OBJECT *obj;
X COUNT count;
X BOOL all;
X{
X register ROW *rp;
X register CELL *cp;
X COORD row;
X COORD col;
X
X if (all)
X clearmarks(obj, MARK_SRC);
X
X row = obj->o_currow;
X col = obj->o_curcol;
X
X for (rp = obj->o_firstrow; row > rp->r_row; rp = rp->r_next)
X ;
X
X for (cp = rp->r_firstcell; col > cp->c_col; cp = cp->c_next)
X ;
X
X if ((row == rp->r_row) && (col == cp->c_col) &&
X ((cp->c_marks & MARK_SRC) == 0))
X count++;
X
X while (TRUE) {
X if (stop)
X return FALSE;
X
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
X if ((cp->c_marks & MARK_SRC) == 0) {
X markobject(obj, rp->r_row, cp->c_col, 1, MARK_SRC);
X if (--count <= 0)
X break;
X }
X cp = cp->c_next;
X }
X
X obj->o_currow = rp->r_row;
X obj->o_curcol = cp->c_col;
X
X return FALSE;
X}
X
X/* END CODE */
SHAR_EOF
$TOUCH -am 0316122993 life/object.c &&
chmod 0644 life/object.c ||
echo "restore of life/object.c failed"
set `wc -c life/object.c`;Wc_c=$1
if test "$Wc_c" != "8587"; then
echo original size 8587, current size $Wc_c
fi
# ============= life/scan.c ==============
echo "x - extracting life/scan.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > life/scan.c &&
X/*
X * Copyright (c) 1993 David I. Bell
X * Permission is granted to use, distribute, or modify this source,
X * provided that this copyright notice remains intact.
X */
X
X#include "life.h"
X
X#ifdef TERMIOS
X#include <termios.h>
X#endif
X
X#ifdef SGTTY
X#include <sgtty.h>
X#endif
X
Xstatic int (*scanroutine)(); /* routine to read characters */
Xstatic jmp_buf *scanjumpbuf; /* jump buffer to use in scanchar */
Xstatic UCHAR *scanreadptr; /* current read pointer */
Xstatic UCHAR *scanwriteptr; /* current write pointer */
Xstatic UCHAR scanbuffer[SCAN_SIZE+1];/* storage for characters */
X
X
X/*
X * Initialize for later calls to scanchar.
X */
Xvoid
Xscaninit(routine, jumpbuf)
X int (*routine)(); /* routine to get characters */
X jmp_buf *jumpbuf; /* jump buffer to use later */
X{
X#ifdef TERMIOS
X struct termio term;
X#endif
X
X#ifdef SGTTY
X struct sgttyb sgbuf;
X struct ltchars ltbuf;
X#endif
X
X scanroutine = routine; /* init static variables */
X scanjumpbuf = jumpbuf;
X scanwriteptr = scanbuffer;
X scanreadptr = scanbuffer;
X
X /*
X * Ask the system for the settings of the editing characters.
X */
X#ifdef TERMIOS
X if (ioctl(STDIN, TCGETA, &term) == 0) {
X vkill = term.c_cc[VKILL];
X verase = term.c_cc[VERASE];
X veof = term.c_cc[VEOF];
X#ifdef VWERASE
X vwerase = term.c_cc[VWERASE];
X#endif
X#ifdef VLNEXT
X vlnext = term.c_cc[VLNEXT];
X#endif
X }
X#endif
X
X#ifdef SGTTY
X if (ioctl(STDIN, TIOCGETP, &sgbuf) == 0) {
X verase = sgbuf.sg_erase;
X vkill = sgbuf.sg_kill;
X }
X
X if (ioctl(STDIN, TIOCGLTC, <buf) == 0) {
X vwerase = ltbuf.t_werasc;
X vlnext = ltbuf.t_lnextc;
X }
X#endif
X /*
X * Now set some defaults if they weren't defined by the system.
X */
X if (!verase)
X verase = '\b';
X if (!vkill)
X vkill = 'U'-'@';
X if (!vwerase)
X vwerase = 'W'-'@';
X if (!vlnext)
X vlnext = 'V'-'@';
X if (!veof)
X veof = 'D'-'@';
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:
X if (scanreadptr < scanwriteptr) /* get saved char if have any */
X return *scanreadptr++;
X
X ch = (*scanroutine)(); /* get new character */
X
X if (ch == EOF) /* no character means eof */
X scaneof();
X
X if (ch == vlnext) { /* literal input */
X ch = (*scanroutine)();
X goto store;
X }
X
X if (ch == verase) { /* character erase */
X if (scanwriteptr <= scanbuffer) {
X beep();
X goto loop;
X }
X scanwriteptr--;
X scanreadptr = scanbuffer;
X longjmp(scanjumpbuf[0], SCAN_EDIT);
X }
X
X if (ch == vwerase) { /* word erase */
X if (scanwriteptr <= scanbuffer)
X goto loop;
X while ((--scanwriteptr >= scanbuffer) &&
X isblank(*scanwriteptr))
X ;
X scanwriteptr++;
X while ((--scanwriteptr >= scanbuffer) &&
X !isblank(*scanwriteptr))
X ;
X scanwriteptr++;
X scanreadptr = scanbuffer;
X longjmp(scanjumpbuf[0], SCAN_EDIT);
X }
X
X if (ch == vkill) { /* line erase */
X if (scanwriteptr <= scanbuffer)
X goto loop;
X scanwriteptr = scanbuffer;
X scanreadptr = scanbuffer;
X longjmp(scanjumpbuf[0], SCAN_EDIT);
X }
X
Xstore:
X if (scanwriteptr >= scanbuffer + SCAN_SIZE) {
X beep();
X goto loop;
X }
X *scanwriteptr++ = ch;
X return *scanreadptr++;
X}
X
X
X/* Abort reading of the current command */
Xvoid
Xscanabort()
X{
X scanreadptr = scanbuffer;
X scanwriteptr = scanbuffer;
X longjmp(scanjumpbuf[0], SCAN_ABORT);
X}
X
X
X/* Indicate no more characters ready yet */
Xvoid
Xscaneof()
X{
X scanreadptr = scanbuffer;
X longjmp(scanjumpbuf[0], SCAN_EOF);
X}
X
X
X/* Simply reset input and output pointers without longjmping */
Xvoid
Xscanreset()
X{
X scanreadptr = scanbuffer;
X scanwriteptr = scanbuffer;
X}
X
Xvoid
Xbeep()
X{
X fputc('\007', stderr);
X fflush(stderr);
X}
X
X/* END CODE */
SHAR_EOF
$TOUCH -am 0316123393 life/scan.c &&
chmod 0644 life/scan.c ||
echo "restore of life/scan.c failed"
set `wc -c life/scan.c`;Wc_c=$1
if test "$Wc_c" != "3924"; then
echo original size 3924, current size $Wc_c
fi
# ============= life/Makefile ==============
echo "x - extracting life/Makefile (Text)"
sed 's/^X//' << 'SHAR_EOF' > life/Makefile &&
X# You can define TERMIOS, SGTTY, or neither.
X# You don't have to define X11 if you don't want graphics.
XCFLAGS = -O -DX11 -DTERMIOS
X
XLIBS = -lX11 -lcurses
X
X
XBINS = main.o alloc.o cell.o cmd.o cmdl.o file.o gen.o io.o mark.o \
X object.o scan.o vars.o view.o ttydev.o x11dev.o
X
Xlife: $(BINS)
X cc -o life $(BINS) $(LIBS)
X
X$(BINS): life.h
X
Xclean:
X rm -rf *.o life
SHAR_EOF
$TOUCH -am 0316154793 life/Makefile &&
chmod 0600 life/Makefile ||
echo "restore of life/Makefile failed"
set `wc -c life/Makefile`;Wc_c=$1
if test "$Wc_c" != "360"; then
echo original size 360, current size $Wc_c
fi
# ============= life/vars.c ==============
echo "x - extracting life/vars.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > life/vars.c &&
X/*
X * Copyright (c) 1993 David I. Bell
X * Permission is granted to use, distribute, or modify this source,
X * provided that this copyright notice remains intact.
X */
X
X#include "life.h"
X
X
X/*
X * Variable enum.
X */
Xenum vars {
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_defscale, v_deffreq, v_endlist
X};
X
X
X/*
X * Table of multi-character variables.
X * This is arranged in listing order (three items per line).
X */
Xstatic struct vartab {
X char *v_name; /* name of variable */
X enum vars v_type; /* variable id */
X} vartab[] = {
X "cx", v_cx,
X "vx", v_vx,
X "px", v_px,
X
X "cy", v_cy,
X "vy", v_vy,
X "py", v_py,
X
X "minx", v_minx,
X "vminx", v_vminx,
X "sminx", v_sminx,
X
X "maxx", v_maxx,
X "vmaxx", v_vmaxx,
X "smaxx", v_smaxx,
X
X "maxy", v_maxy,
X "vmaxy", v_vmaxy,
X "smaxy", v_smaxy,
X
X "miny", v_miny,
X "vminy", v_vminy,
X "sminy", v_sminy,
X
X "cells", v_cells,
X "vcells", v_vcells,
X "scells", v_scells,
X
X "gen", v_gen,
X "born", v_born,
X "died", v_died,
X
X "scale", v_scale,
X "freq", v_freq,
X "dscale", v_defscale,
X
X "dfreq", v_deffreq,
X NULL, v_endlist
X};
X
X
Xstatic char *curcp; /* current character to parse */
Xstatic VALUE lowervars[26]; /* lower case single-char variable values */
Xstatic VALUE uppervars[26]; /* upper case single-char variable values */
X
X
Xstatic VALUE getvariablebytype();
Xstatic VALUE parsesum();
Xstatic VALUE parseproduct();
Xstatic VALUE parseterm();
Xstatic VALUE parsename();
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 */
XVALUE
Xgetvariable(cp)
X register char *cp;
X{
X register struct vartab *vp;
X
X if (*cp == '$')
X cp++;
X
X if (cp[1] == '\0')
X return getvariable1(*cp);
X
X if (!islower(*cp) && !isupper(*cp))
X error("Bad variable name");
X
X for (vp = vartab; ; vp++) {
X if (vp->v_name == NULL)
X error("Unknown variable");
X if (strcmp(vp->v_name, cp) == 0)
X break;
X }
X
X return getvariablebytype(vp->v_type);
X}
X
X
X/*
X * Return the value of a variable given its enum value.
X */
Xstatic VALUE
Xgetvariablebytype(type)
X enum vars type;
X{
X register OBJECT *obj;
X VALUE value;
X COORD *ptr;
X COORD *sptr;
X int sign;
X COORD minrow;
X COORD maxrow;
X COORD mincol;
X COORD maxcol;
X
X obj = curobj;
X value = 0;
X sign = 1;
X ptr = NULL;
X sptr = NULL;
X
X switch (type) {
X case v_cx:
X value = obj->o_curcol;
X break;
X
X case v_cy:
X value = -obj->o_currow;
X break;
X
X case v_px:
X value = obj->o_pcol;
X break;
X
X case v_py:
X value = -obj->o_prow;
X break;
X
X case v_vx:
X value = (obj->o_mincol + obj->o_maxcol) / 2;
X break;
X
X case v_vy:
X value = -(obj->o_minrow + obj->o_maxrow) / 2;
X break;
X
X case v_vminx:
X value = obj->o_mincol;
X break;
X
X case v_vmaxx:
X value = obj->o_maxcol;
X break;
X
X case v_vminy:
X value = -obj->o_maxrow;
X break;
X
X case v_vmaxy:
X value = -obj->o_minrow;
X break;
X
X case v_vcells:
X value = markregion(obj, MARK_ANY, obj->o_minrow,
X obj->o_maxrow, obj->o_mincol, obj->o_maxcol);
X break;
X
X case v_cells:
X value = obj->o_count;
X break;
X
X case v_gen:
X value = obj->o_gen;
X break;
X
X case v_born:
X value = obj->o_born;
X break;
X
X case v_died:
X value = obj->o_died;
X break;
X
X case v_freq:
X value = obj->o_frequency;
X break;
X
X case v_scale:
X value = obj->o_scale;
X break;
X
X case v_deffreq:
X value = defaultfrequency;
X break;
X
X case v_defscale:
X value = defaultscale;
X break;
X
X case v_minx:
X ptr = &mincol;
X break;
X
X case v_maxx:
X ptr = &maxcol;
X break;
X
X case v_miny:
X ptr = &maxrow;
X sign = -1;
X break;
X
X case v_maxy:
X ptr = &minrow;
X sign = -1;
X break;
X
X case v_scells:
X value = countmarks(obj, MARK_SEE);
X break;
X
X case v_sminx:
X sptr = &mincol;
X break;
X
X case v_smaxx:
X sptr = &maxcol;
X break;
X
X case v_sminy:
X sptr = &maxrow;
X sign = -1;
X break;
X
X case v_smaxy:
X sptr = &minrow;
X sign = -1;
X break;
X }
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
X if (sptr&&(markminmax(obj,MARK_SEE,&minrow,&maxrow,&mincol,&maxcol)==0))
X value = *sptr;
X
X return (sign * value);
X}
X
X
X/*
X * Return the value of a single character variable name (a-z or A-Z).
X */
XVALUE
Xgetvariable1(ch)
X register int ch;
X{
X if (islower(ch))
X return lowervars[ch - 'a'];
X
X if (isupper(ch))
X return lowervars[ch - 'A'];
X
X error("Bad variable name");
X}
X
X
X/*
X * Set the value of a variable name. Multi-character names cannot be set.
X */
Xvoid
Xsetvariable(cp, value)
X register char *cp;
X VALUE value;
X{
X if (*cp == '$')
X cp++;
X
X if (cp[1] != '\0')
X error("Cannot set multi-character variables");
X
X setvariable1(*cp, value);
X}
X
X
X/*
X * Set the value of a single-character variable (a-z or A-Z).
X */
Xvoid
Xsetvariable1(ch, value)
X int ch;
X VALUE value;
X{
X if (islower(ch)) {
X lowervars[ch - 'a'] = value;
X return;
X }
X
X if (isupper(ch)) {
X lowervars[ch - 'A'] = value;
X return;
X }
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 */
Xvoid
Xlistvariables()
X{
X struct vartab *vp;
X VALUE *var;
X int count;
X char buf[80];
X
X showhelp("Variable names and values:");
X
X count = 0;
X for (vp = vartab; vp->v_name; vp++) {
X sprintf(buf, "%s%s\t%ld", (count++ % 3) ? "\t\t" : "\n",
X vp->v_name, getvariablebytype(vp->v_type));
X
X showhelp(buf);
X }
X
X count = 0;
X for (var = uppervars; var < &uppervars[26]; var++) {
X if (*var == 0)
X continue;
X
X if (count == 0)
X showhelp("\n");
X
X sprintf(buf, "%s%c\t%ld", (count++ % 3) ? "\t\t" : "\n",
X 'A' + (var - uppervars), *var);
X
X showhelp(buf);
X }
X
X for (var = lowervars; var < &lowervars[26]; var++) {
X if (*var == 0)
X continue;
X
X if (count == 0)
X showhelp("\n");
X
X sprintf(buf, "%s%c\t%ld", (count++ % 3) ? "\t\t" : "\n",
X 'a' + (var - lowervars), *var);
X
X showhelp(buf);
X }
X
X showhelp("\n\nMany names starting with 'v' refer to visible cells\n");
X showhelp("Many names starting with 's' refer to selected cells\n");
X
X endhelp();
X}
X
X
X/*
X * Evaluate an expression and return its value. The expression can contain
X * numbers, variables, the normal arithmetic operators, and parenthesized
X * expressions. The usual precedence rules are used. The string must be
X * writable.
X */
XVALUE
Xgetexpression(str)
X register char *str;
X{
X VALUE value;
X
X while isblank(*str)
X str++;
X
X if (*str == '\0')
X error("Null expression");
X
X curcp = str;
X value = parsesum();
X if (*curcp != '\0')
X error("Bad expression");
X
X return value;
X}
X
X
X/*
X * Parse the sum of products
X */
Xstatic VALUE
Xparsesum()
X{
X VALUE value;
X
X while (isblank(*curcp))
X curcp++;
X
X switch (*curcp) {
X case '-':
X curcp++;
X value = -parseproduct();
X break;
X
X case '+':
X curcp++;
X /* proceed into default case */
X
X default:
X value = parseproduct();
X }
X
X while (TRUE) switch (*curcp++) {
X case '+': /* sum of products */
X value += parseproduct();
X continue;
X
X case '-': /* difference of products */
X value -= parseproduct();
X continue;
X
X case ' ': /* space */
X case '\t':
X continue;
X
X default: /* end of sum */
X curcp--;
X return value;
X }
X}
X
X
X/*
X * Parse the product of terms
X */
Xstatic VALUE
Xparseproduct()
X{
X VALUE value;
X VALUE value2;
X
X value = parseterm();
X
X while (TRUE) switch (*curcp++) {
X case '*': /* product of terms */
X value *= parseterm();
X continue;
X
X case '/': /* division of terms */
X value2 = parseterm();
X if (value2 == 0)
X error("division by zero");
X value /= value2;
X continue;
X
X case '%': /* modulo of terms */
X value2 = parseterm();
X if (value2 == 0)
X error("division by zero");
X value %= value2;
X continue;
X
X case ' ': /* space */
X case '\t':
X continue;
X
X default: /* end of product */
X curcp--;
X return value;
X }
X}
X
X
X/*
X * Parse a single term
X */
Xstatic VALUE
Xparseterm()
X{
X VALUE value;
X int ch;
X
X while (isblank(*curcp))
X curcp++;
X
X ch = *curcp;
X if (isdigit(ch)) { /* number */
X value = 0;
X do {
X value = (value * 10) + *curcp++ - '0';
X } while (isdigit(*curcp));
X
X return value;
X }
X
X if (ch == '(') { /* parenthesized expression */
X curcp++;
X while (isblank(*curcp))
X curcp++;
X
X if (*curcp == ')')
X error("Null expression");
X
X value = parsesum();
X
X while (isblank(*curcp))
X curcp++;
X
X if (*curcp != ')')
X error("Unmatched parenthesis");
X curcp++;
X
X return value;
X }
X
X if (ch == ')')
X error("Unmatched parenthesis");
X
X return parsename();
X}
X
X
X/*
X * Parse a variable name and return its value.
X */
Xstatic VALUE
Xparsename()
X{
X register char *cp;
X VALUE value;
X int oldch;
X
X cp = curcp;
X if (*cp == '$')
X cp++;
X
X while (islower(*cp) || isupper(*cp) || isdigit(*cp))
X cp++;
X
X oldch = *cp;
X *cp = '\0'; /* this requires writable strings */
X value = getvariable(curcp);
X *cp = oldch;
X curcp = cp;
X
X return value;
X}
X
X/* END CODE */
SHAR_EOF
$TOUCH -am 0316122993 life/vars.c &&
chmod 0644 life/vars.c ||
echo "restore of life/vars.c failed"
set `wc -c life/vars.c`;Wc_c=$1
if test "$Wc_c" != "9210"; then
echo original size 9210, current size $Wc_c
fi
# ============= life/view.c ==============
echo "x - extracting life/view.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > life/view.c &&
X/*
X * Copyright (c) 1993 David I. Bell
X * Permission is granted to use, distribute, or modify this source,
X * provided that this copyright notice remains intact.
X */
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. Positive scale factors
X * mean compress the view so that each displayed item represents multiple
X * cells. Negative scale factors mean use multiple displayed items to
X * represent individual cells.
X */
Xvoid
Xsetscale(obj, sf)
X register OBJECT *obj;
X SCALE sf;
X{
X COUNT newrows;
X COUNT newcols;
X
X if (sf < dev->minscale)
X sf = dev->minscale;
X if (sf > dev->maxscale)
X sf = dev->maxscale;
X if ((sf == 0) || (sf == -1))
X sf = 1;
X
X if (sf > 0) {
X newrows = dev->rows * sf;
X newcols = dev->cols * sf;
X } else {
X newrows = dev->rows / (-sf);
X newcols = dev->cols / (-sf);
X if (newrows <= 0)
X newrows = 1;
X if (newcols <= 0)
X newcols = 1;
X }
X
X obj->o_scale = sf;
X obj->o_minrow = obj->o_currow - (newrows / 2);
X obj->o_maxrow = obj->o_minrow + newrows - 1;
X obj->o_mincol = obj->o_curcol - (newcols / 2);
X obj->o_maxcol = obj->o_mincol + newcols - 1;
X
X if (obj == curobj) {
X viewrows = newrows;
X viewcols = newcols;
X update |= U_ALL;
X }
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 */
XSCALE
Xautoscale()
X{
X register OBJECT *obj;
X SCALE sf;
X COORD minrow;
X COORD maxrow;
X COORD mincol;
X COORD maxcol;
X
X obj = curobj;
X minmax(obj, &minrow, &maxrow, &mincol, &maxcol);
X sf = obj->o_scale;
X
X if (mincol > maxcol)
X return sf;
X
X while ((sf <= dev->maxscale) &&
X ((minrow < obj->o_minrow) || (maxrow > obj->o_maxrow) ||
X (mincol < obj->o_mincol) || (maxcol > obj->o_maxcol)))
X {
X sf++;
X if ((sf == -1) || (sf == 0))
X sf = 1;
X if (sf > 20)
X sf += (5 - (sf % 5));
X if (sf > 50)
X sf += (10 - (sf % 10));
X if (sf > 200)
X sf += (100 - (sf % 100));
X setscale(obj, sf);
X }
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 */
Xvoid
Xpositionview(minrow, maxrow, mincol, maxcol)
X COORD minrow;
X COORD maxrow;
X COORD mincol;
X COORD maxcol;
X{
X register OBJECT *obj;
X
X obj = curobj;
X
X if (minrow > obj->o_currow)
X minrow = obj->o_currow;
X if (maxrow < obj->o_currow)
X maxrow = obj->o_currow;
X if (mincol > obj->o_curcol)
X mincol = obj->o_curcol;
X if (maxcol < obj->o_curcol)
X maxcol = obj->o_curcol;
X
X if ((maxrow - minrow) >= viewrows) { /* too many rows */
X minrow = obj->o_currow;
X maxrow = obj->o_currow;
X }
X if ((maxcol - mincol) >= viewcols) { /* too many columns */
X mincol = obj->o_curcol;
X maxcol = obj->o_curcol;
X }
X
X if (minrow < obj->o_minrow) {
X obj->o_minrow = minrow;
X obj->o_maxrow = minrow + viewrows - 1;
X update |= U_ALL;
X }
X if (maxrow > obj->o_maxrow) {
X obj->o_maxrow = maxrow;
X obj->o_minrow = maxrow - viewrows + 1;
X update |= U_ALL;
X }
X if (mincol < obj->o_mincol) {
X obj->o_mincol = mincol;
X obj->o_maxcol = mincol + viewcols - 1;
X update |= U_ALL;
X }
X if (maxcol > obj->o_maxcol) {
X obj->o_maxcol = maxcol;
X obj->o_mincol = maxcol - viewcols + 1;
X update |= U_ALL;
X }
X}
X
X
X/*
X * Show the view around the current window location if the view has changed.
X * The update flag indicates what parts of the display needs updating.
X * This is any of U_POS, U_STAT, and U_VIEW.
X */
Xvoid
Xupdateview()
X{
X register OBJECT *obj;
X
X if ((interact | update) == 0)
X return;
X
X obj = curobj;
X positionview(obj->o_currow,obj->o_currow,obj->o_curcol,obj->o_curcol);
X if (obj->o_autoscale)
X autoscale();
X
X if (update & U_VIEW) {
X freqcount = obj->o_frequency;
X (*dev->showview)(dev);
X }
X
X if (update & (U_STAT | U_VIEW))
X viewstatus();
X
X if (update & (U_STAT | U_VIEW | U_POS)) {
X (*dev->movecursor)(dev, obj->o_scale,
X obj->o_currow - obj->o_minrow,
X obj->o_curcol - obj->o_mincol);
X (*dev->update)(dev, 0);
X }
X
X update = FALSE; /* no more updates until prodded */
X interact = FALSE;
X}
X
X
X/*
X * Update the status line for the object.
X */
Xvoid
Xviewstatus()
X{
X register OBJECT *obj;
X char *cp;
X char buf[132];
X
X if (errorstring) {
X (*dev->showstatus)(dev, errorstring);
X return;
X }
X
X obj = curobj;
X cp = buf;
X sprintf(cp, "Gen:%ld cells:%ld", obj->o_gen, obj->o_count);
X cp += strlen(cp);
X
X if (obj->o_count > seecount) {
X sprintf(cp, "(%ldu)", obj->o_count - seecount);
X cp += strlen(cp);
X }
X if (obj->o_born) {
X sprintf(cp, " born:%ld", obj->o_born);
X cp += strlen(cp);
X }
X if (obj->o_died) {
X sprintf(cp, " died:%ld", obj->o_died);
X cp += strlen(cp);
X }
X if (obj->o_frequency > 1) {
X sprintf(cp, " freq:%ld", obj->o_frequency);
X cp += strlen(cp);
X }
X if ((obj->o_scale != 1) || (obj->o_autoscale)) {
X sprintf(cp, " %scale:%d",
X (obj->o_autoscale ? "autos" : "s") , obj->o_scale);
X cp += strlen(cp);
X }
X if (strcmp(rulestring, "3,23")) {
X sprintf(cp, " rules:%s", rulestring);
X cp += strlen(cp);
X }
X if (curinput > inputs) {
X sprintf(cp, " cmd-nest:%d", curinput - inputs);
X cp += strlen(cp);
X }
X
X switch (curinput->i_type) {
X case INP_TTY: /* reading from terminal */
X if (curinput != inputs)
X strcpy(cp, " tty-wait");
X break;
X
X case INP_FILE: /* reading from file */
X strcpy(cp, " cmd-file");
X break;
X
X case INP_LOOP: /* reading from loop */
X if (curinput->i_macro) {
X sprintf(cp, " macro-define-%c",
X curinput->i_macro);
X break;
X }
X sprintf(cp, " loop%s (curval:%ld end:%ld)",
X curinput->i_first ? "-define" : "",
X curinput->i_curval, curinput->i_endval);
X break;
X
X case INP_MACRO: /* reading from macro */
X sprintf(cp, " macro-%c", curinput->i_macro);
X break;
X }
X cp += strlen(cp);
X
X if (mode == M_INSERT)
X strcpy(cp, " inserting");
X if (mode == M_DELETE)
X strcpy(cp, " deleting");
X cp += strlen(cp);
X
X if (curobj != mainobject) {
X sprintf(cp, " \"%s\"", curobj->o_name);
X cp += strlen(cp);
X }
X
X (*dev->showstatus)(dev, buf);
X}
X
X/* END CODE */
SHAR_EOF
$TOUCH -am 0316122993 life/view.c &&
chmod 0644 life/view.c ||
echo "restore of life/view.c failed"
set `wc -c life/view.c`;Wc_c=$1
if test "$Wc_c" != "6178"; then
echo original size 6178, current size $Wc_c
fi
# ============= life/ttydev.c ==============
echo "x - extracting life/ttydev.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > life/ttydev.c &&
X/*
X * Copyright (c) 1993 David I. Bell
X * Permission is granted to use, distribute, or modify this source,
X * provided that this copyright notice remains intact.
X */
X
X#include <fcntl.h>
X#include <curses.h>
X#include "life.h"
X
X
Xstatic int ttyopen();
Xstatic void ttyclose();
Xstatic void ttyupdate();
Xstatic void ttyrefresh();
Xstatic int ttyinputready();
Xstatic int ttyreadchar();
Xstatic void ttymovecursor();
Xstatic void ttyshowview();
Xstatic void ttyshowstatus();
Xstatic void ttyaddstatus();
Xstatic void ttyshowhelp();
Xstatic void ttyaddhelp();
Xstatic int ttyassign();
X
Xstatic void viewnormal();
Xstatic void viewscale();
X
X
XDEV ttydev = {
X ttyopen, ttyclose, ttyupdate, ttyrefresh, ttyinputready, ttyreadchar,
X ttymovecursor, ttyshowview, ttyshowstatus, ttyaddstatus,
X ttyshowhelp, ttyaddhelp, ttyassign, 0, 0, 0, 0, 1, MAXSCALE, 1
X};
X
X
Xstatic WINDOW *statwin;
Xstatic WINDOW *viewwin;
X
Xstatic BOOL havesavedchar;
Xstatic int savedchar;
Xstatic int ttyfd;
X
X
Xstatic int
Xttyopen(dev)
X DEV *dev;
X{
X#ifdef O_NONBLOCK
X ttyfd = open("/dev/tty", O_RDONLY | O_NONBLOCK);
X if (ttyfd < 0) {
X fprintf(stderr, "Cannot set tty mode\n");
X return -1;
X }
X#endif
X initscr();
X cbreak();
X noecho();
X statwin = newwin(1, COLS, 0, 0);
X viewwin = newwin(LINES - 1, COLS, 1, 0);
X
X dev->rows = LINES - 1;
X dev->cols = COLS - 1;
X dev->textrows = LINES - 1;
X dev->textcols = COLS - 1;
X
X return 0;
X}
X
X
Xstatic void
Xttyclose(dev)
X DEV *dev;
X{
X refresh();
X endwin();
X}
X
X
Xstatic void
Xttyupdate(dev, inputflag)
X DEV *dev;
X BOOL inputflag;
X{
X if (inputflag) {
X wrefresh(viewwin);
X wrefresh(statwin);
X } else {
X wrefresh(statwin);
X wrefresh(viewwin);
X }
X}
X
X
Xstatic void
Xttyrefresh(dev)
X DEV *dev;
X{
X wrefresh(curscr);
X}
X
X
X/*
X * Read the next character from the terminal, waiting if requested.
X * If not waiting and no character is ready, then EOF is returned.
X * When waiting and the read is interrupted, then also returns EOF.
X */
Xstatic int
Xttyreadchar(dev, wait)
X DEV *dev;
X{
X UCHAR ch;
X int n;
X
X if (!wait && !ttyinputready(dev))
X return EOF;
X
X if (havesavedchar) {
X havesavedchar = FALSE;
X return savedchar;
X }
X
X n = read(STDIN, &ch, 1);
X if (n <= 0)
X return EOF;
X
X if (ch == '\r')
X ch = '\n';
X
X return ch;
X}
X
X
X/*
X * See if input is ready from the terminal.
X */
Xstatic BOOL
Xttyinputready(dev)
X DEV *dev;
X{
X int n;
X UCHAR ch;
X
X#ifdef O_NONBLOCK
X n = read(ttyfd, &ch, 1);
X if (n <= 0)
X return FALSE;
X
X if (ch == '\r')
X ch = '\n';
X
X savedchar = ch;
X havesavedchar = TRUE;
X
X return TRUE;
X#endif
X
X#ifdef FIONREAD
X return ((ioctl(STDIN, FIONREAD, &n) == 0) && (n > 0));
X#endif
X
X#ifdef FIORDCHK
X return (ioctl(STDIN, FIORDCHK, &n) > 0);
X#endif
X
X error("Cannot do non-blocking reads!!!!");
X}
X
X
Xstatic int
Xttyassign(dev, button, macro)
X DEV *dev;
X VALUE button;
X UCHAR macro;
X{
X return -1;
X}
X
X
Xstatic void
Xttymovecursor(dev, sf, row, col)
X DEV *dev;
X SCALE sf;
X COORD row;
X COORD col;
X{
X if (sf < 1)
X sf = 1;
X wmove(viewwin, row / sf, col / sf);
X}
X
X
X/*
X * Show the view around the current window location.
X */
Xstatic void
Xttyshowview(dev)
X DEV *dev;
X{
X wmove(viewwin, 0, 0);
X if (curobj->o_scale <= 1)
X viewnormal();
X else
X viewscale(curobj->o_scale);
X wclrtobot(viewwin);
X}
X
X
X/*
X * Show the specified status line.
X */
Xstatic void
Xttyshowstatus(dev, str)
X DEV *dev;
X char *str;
X{
X wmove(statwin, 0, 0);
X wclrtobot(statwin);
X wmove(statwin, 0, 0);
X waddstr(statwin, str);
X}
X
X
X/*
X * Add the specified status to the status line.
X */
Xstatic void
Xttyaddstatus(dev, str)
X DEV *dev;
X char *str;
X{
X waddstr(statwin, str);
X}
X
X
X/*
X * Setup to show help.
X */
Xstatic void
Xttyshowhelp(dev)
X DEV *dev;
X{
X wmove(viewwin, 0, 0);
X wclrtobot(viewwin);
X wmove(viewwin, 0, 0);
X}
X
X
X/*
X * Add the specified information to the help display.
X */
Xstatic void
Xttyaddhelp(dev, str)
X DEV *dev;
X char *str;
X{
X waddstr(viewwin, str);
X}
X
X
X/*
X * Show the cells around the cursor normally (scale factor of 1).
X */
Xstatic void
Xviewnormal()
X{
X register ROW *rp; /* current row */
X register CELL *cp; /* current cell */
X OBJECT *obj; /* current object */
X COORD row; /* current row number */
X COORD col; /* current column number */
X char *str; /* characters for line */
X char *endstr; /* end of characters for line */
X
X obj = curobj;
X rp = obj->o_firstrow;
X row = obj->o_minrow;
X seecount = 0;
X while (row > rp->r_row)
X rp = rp->r_next;
X
X for (; row <= obj->o_maxrow; row++) {
X if (row != rp->r_row) { /* blank row */
X if (gridchar == ' ') {
X waddch(viewwin, '\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 *str = '\0';
X waddstr(viewwin, stringbuf);
X continue;
X }
X
X str = stringbuf;
X endstr = str;
X cp = rp->r_firstcell;
X col = obj->o_mincol;
X while (col > cp->c_col)
X cp = cp->c_next;
X
X for (; col <= obj->o_maxcol; col++) {
X if (col != cp->c_col) { /* blank cell */
X *str++ = gridchar;
X if (gridchar != ' ')
X endstr = str;
X continue;
X }
X *str = 'o';
X if ((cp->c_marks & MARK_SEE) == 0)
X *str = 'O';
X endstr = ++str;
X seecount++;
X cp = cp->c_next;
X }
X
X *endstr++ = '\n';
X *endstr = '\0';
X waddstr(viewwin, 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 */
Xstatic void
Xviewscale(sf)
X register SCALE sf;
X{
X register ROW *rp; /* row pointer */
X register CELL *cp; /* current cell structure */
X OBJECT *obj; /* current object */
X COORD row; /* current row number */
X COORD col; /* current column number */
X COUNT sum; /* number of cells in square */
X CELL **cpp; /* pointer into cell table */
X CELL **endcpp; /* end of cell table */
X char *str; /* buffer pointer */
X char *endstr; /* end of buffer */
X 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
X for (rp = curobj->o_firstrow; (rp->r_row < row); rp = rp->r_next)
X ;
X
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 waddch(viewwin, '\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 *str = '\0';
X waddstr(viewwin, stringbuf);
X row += sf;
X continue;
X }
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++)
X continue;
X *cpp = rp->r_firstcell;
X rp = rp->r_next;
X }
X str = stringbuf;
X endstr = str;
X
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)
X cp = cp->c_next;
X while ((col + sf) >= cp->c_col) {
X sum++;
X cp = cp->c_next;
X }
X *cpp = cp;
X }
X
X if (sum == 0) { /* no cells in square */
X *str++ = gridchar;
X if (gridchar != ' ')
X endstr = str;
X continue;
X }
X
X *str = '*'; /* show number of cells */
X if (sum <= 9)
X *str = '0' + sum;
X endstr = ++str;
X seecount += sum;
X }
X *endstr++ = '\n';
X *endstr = '\0';
X waddstr(viewwin, stringbuf);
X }
X}
X
X/* END CODE */
SHAR_EOF
$TOUCH -am 0316122993 life/ttydev.c &&
chmod 0644 life/ttydev.c ||
echo "restore of life/ttydev.c failed"
set `wc -c life/ttydev.c`;Wc_c=$1
if test "$Wc_c" != "7567"; then
echo original size 7567, current size $Wc_c
fi
# ============= life/file.c ==============
echo "x - extracting life/file.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > life/file.c &&
X/*
X * Copyright (c) 1993 David I. Bell
X * Permission is granted to use, distribute, or modify this source,
X * provided that this copyright notice remains intact.
X */
X
X#include "life.h"
X
X#define RLEMAX 75 /* maximum width of a line in rle format */
X
X
Xstatic BOOL readcoords();
Xstatic void writepicture();
Xstatic void writexlife();
Xstatic void writerle();
Xstatic void rleitem();
X
X
X/*
X * Read in a run-length encoded description from an opened file.
X */
Xvoid
Xreadrle(fp)
X FILE *fp;
X{
X COORD mincol;
X VALUE width;
X VALUE height;
X VALUE val;
X int ch;
X char *cp;
X char buf[40];
X
X val = 0;
X do {
X ch = fgetc(fp);
X if ((ch == EOF) || (val >= sizeof(buf)))
X goto badhead;
X buf[val++] = ch;
X } while (ch != '\n');
X
X cp = buf;
X if ((*cp++ != 'x') || (*cp++ != ' ') || (*cp++ != '=') ||
X (*cp++ != ' ') || !isdigit(*cp))
X goto badhead;
X width = 0;
X while (isdigit(*cp))
X width = width * 10 + *cp++ - '0';
X
X if ((*cp++ != ',') || (*cp++ != ' ') || (*cp++ != 'y') ||
X (*cp++ != ' ') || (*cp++ != '=') || (*cp++ != ' ') ||
X !isdigit(*cp))
X goto badhead;
X
X height = 0;
X while (isdigit(*cp))
X height = height * 10 + *cp++ - '0';
X
X if ((*cp != '\n') || (width <= 0) || (height <= 0)) {
Xbadhead: error("Bad header line in rle file");
X }
X
X crow -= height / 2;
X ccol -= width / 2;
X mincol = ccol;
X
X while (TRUE) {
X val = 1;
X ch = fgetc(fp);
X if (isdigit(ch)) {
X val = 0;
X while (isdigit(ch)) {
X val = val * 10 + ch - '0';
X ch = fgetc(fp);
X }
X }
X
X switch (ch) {
X case 'b':
X case 'B':
X ccol += val;
X break;
X
X case 'o':
X case 'O':
X while (val-- > 0)
X addcell(curobj, crow, ccol++);
X update |= U_ALL;
X break;
X
X case '$':
X crow += val;
X ccol = mincol;
X break;
X
X case ' ':
X case '\t':
X case '\n':
X break;
X
X case '!':
X return;
X
X case EOF:
X error("Unexpected end of file in rle file");
X
X default:
X error("Illegal character in rle file");
X }
X }
X}
X
X
X/*
X * Read in an object in xlife format from an opened file.
X * Absolute coordinates are converted to relative ones.
X * However, we don't handle indirect files.
X */
Xvoid
Xreadxlife(fp)
X FILE *fp;
X{
X VALUE row;
X VALUE col;
X BOOL inheader;
X int ch;
X
X inheader = TRUE;
X while (inheader) {
X ch = fgetc(fp);
X if (ch != '#')
X error("Directive expected in xlife file");
X
X ch = fgetc(fp);
X
X switch (ch) {
X case 'C':
X case 'N':
X case 'O':
X while ((ch != EOF) && (ch != '\n'))
X ch = fgetc(fp);
X break;
X
X case 'I':
X error("Indirect files not supported for xlife files");
X
X case 'A':
X case 'R':
X while ((ch != EOF) && (ch != '\n'))
X ch = fgetc(fp);
X
X while (readcoords(fp, &col, &row)) {
X addcell(curobj, crow + row, ccol + col);
X update |= U_ALL;
X }
X
X return;
X
X case 'P':
X if (!readcoords(fp, &col, &row))
X error("Unexpected EOF in xlife file");
X
X crow += row;
X ccol += col;
X
X readpicture(fp);
X
X return;
X
X default:
X error("Unknown directive in xlife file");
X }
X }
X}
X
X
X/*
X * Read in a picture of a life object from an opened file.
X */
Xvoid
Xreadpicture(fp)
X FILE *fp;
X{
X COORD mincol;
X int ch;
X
X mincol = ccol;
X
X while (TRUE)
X {
X ch = fgetc(fp);
X
X switch (ch) {
X case '.':
X case ' ':
X ccol++;
X break;
X
X case '*':
X case 'O':
X case 'o':
X addcell(curobj, crow, ccol++);
X update |= U_ALL;
X break;
X
X case '\t':
X do {
X ccol++;
X } while ((ccol - mincol) % 8);
X break;
X
X case '\n':
X ccol = mincol;
X crow++;
X break;
X
X case EOF:
X return;
X
X default:
X error("Illegal pictorial character in file");
X }
X }
X}
X
X
X/*
X * Read a pair of coordinates and the following end of line from a file.
X * The pair of values are returned indirectly through pointers. Extra
X * blanks are allowed. Returns TRUE if coordinates were read, or FALSE
X * if EOF was found.
X */
Xstatic BOOL
Xreadcoords(fp, num1, num2)
X FILE *fp;
X VALUE *num1;
X VALUE *num2;
X{
X VALUE val;
X BOOL isneg;
X int ch;
X char *cp;
X char buf[80];
X
X *num1 = 0;
X *num2 = 0;
X
X val = 0;
X do {
X ch = fgetc(fp);
X
X if (ch == EOF) {
X if (val == 0)
X return FALSE;
X goto badline;
X }
X
X if (val >= sizeof(buf))
X goto badline;
X
X buf[val++] = ch;
X } while (ch != '\n');
X
X cp = buf;
X while (isblank(*cp))
X cp++;
X
X isneg = (*cp == '-');
X if (isneg)
X cp++;
X val = 0;
X if (!isdigit(*cp))
X goto badline;
X while (isdigit(*cp))
X val = val * 10 + *cp++ - '0';
X if (isneg)
X val = -val;
X *num1 = val;
X
X if (!isblank(*cp))
X goto badline;
X while (isblank(*cp))
X cp++;
X
X isneg = (*cp == '-');
X if (isneg)
X cp++;
X val = 0;
X if (!isdigit(*cp))
X goto badline;
X while (isdigit(*cp))
X val = val * 10 + *cp++ - '0';
X if (isneg)
X val = -val;
X *num2 = val;
X
X while (isblank(*cp))
X cp++;
X
X if (*cp != '\n') {
Xbadline: error("Invalid coordinate value in file");
X }
X
X return TRUE;
X}
X
X
X/*
X * Write an object out to a file in one of several different methods, which
X * is one of picture, xlife, or rle. The maxrows and maxcols arguments are
X * used for limiting picture sizes.
X */
Xvoid
Xwriteobject(obj, method, name, maxrows, maxcols)
X OBJECT *obj;
X char *method;
X char *name;
X VALUE maxrows;
X VALUE maxcols;
X{
X FILE *fp;
X COORD minrow;
X COORD maxrow;
X COORD mincol;
X COORD maxcol;
X
X if (!abbrev(method, "picture") && !abbrev(method, "rle") &&
X !abbrev(method, "xlife"))
X error("Unknown file format specified");
X
X if (*name == '\0')
X error("No filename specified");
X
X minmax(obj, &minrow, &maxrow, &mincol, &maxcol);
X if (minrow > maxrow)
X error("Null object");
X
X fp = fopen(name, "w");
X if (fp == NULL)
X error("Cannot open output file");
X
X switch (*method) {
X case 'p':
X writepicture(fp, obj, minrow, maxrow, mincol, maxcol,
X maxrows, maxcols);
X break;
X
X case 'x':
X writexlife(fp, obj, minrow, maxrow, mincol, maxcol);
X break;
X
X case 'r':
X writerle(fp, obj, minrow, maxrow, mincol, maxcol);
X break;
X }
X
X fflush(fp);
X if (ferror(fp)) {
X fclose(fp);
X error("Write failed");
X }
X
X if (fclose(fp))
X error("Close failed");
X
X if (stop)
X error("Writing aborted");
X}
X
X
X/*
X * Write the current object out to the named file as a picture, with the
X * given maximum sizes for "pretty" output. If the size is exceeded, the
X * output is compressed. The file as written can be read in as commands
X * which will regenerate the object.
X */
Xstatic void
Xwritepicture(fp, obj, minrow, maxrow, mincol, maxcol, maxrows, maxcols)
X FILE *fp;
X OBJECT *obj;
X COORD minrow;
X COORD maxrow;
X COORD mincol;
X COORD maxcol;
X VALUE maxrows;
X VALUE maxcols;
X{
X register ROW *rp; /* current row structure */
X register CELL *cp; /* current cell */
X COORD row; /* current row value */
X COORD col; /* current column value */
X ROW *trp; /* temporary row structure */
X COORD curmin; /* current minimum column */
X COORD curmax; /* current maximum column */
X COORD testmin; /* test minimum column of rows */
X COORD testmax; /* test maximum column of rows */
X
X minmax(obj, &minrow, &maxrow, &mincol, &maxcol);
X if (minrow > maxrow) {
X fclose(fp);
X error("Null object");
X }
X
X fprintf(fp, "! \"%s\" (cells %ld length %ld width %ld generation %ld)\n",
X obj->o_name, obj->o_count, maxrow - minrow + 1,
X maxcol - mincol + 1, obj->o_gen);
X
X if (obj->o_currow > minrow)
SHAR_EOF
echo "End of part 17"
echo "File life/file.c is continued in part 18"
echo "18" > shar3_seq_.tmp
exit 0
This archive was generated by hypermail 2.1.7 : Tue Oct 14 2003 - 21:44:10 UTC