Life program (part 17/18)

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, &ltbuf) == 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