Life program (part 18/18)

From: David I. Bell (dbell@pdact.pd.necisa.oz.au)
Date: Tue Mar 16 1993 - 06:31:09 UTC


#!/bin/sh
# this is LIFE.18 (part 18 of a multipart archive)
# do not concatenate these parts, unpack them in order with /bin/sh
# file life/file.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" != 18; then
	echo "Please unpack part $Scheck next!"
	exit 1
 else
	exit 0
 fi
) < shar3_seq_.tmp || exit 1
echo "x - Continuing file life/file.c"
sed 's/^X//' << 'SHAR_EOF' >> life/file.c &&
X		fprintf(fp, "%ldk", obj->o_currow - minrow);
X	if (obj->o_currow < minrow)
X		fprintf(fp, "%ldj", minrow - obj->o_currow);
X	if (obj->o_curcol > mincol)
X		fprintf(fp, "%ldh", obj->o_curcol - mincol);
X	if (obj->o_curcol < mincol)
X		fprintf(fp, "%ldl", mincol - obj->o_curcol);
X	fprintf(fp, "@!\n");
X
X	curmin = INFINITY;
X	curmax = -INFINITY;
X	rp = obj->o_firstrow;
X	row = minrow;
X
X	for (; rp != termrow; rp = rp->r_next) {
X		if (stop)
X			return;
X
X		/*
X		 * Skip down to the next row with something in it.
X		 */
X		if (rp->r_firstcell == termcell)
X			continue;
X		if (rp->r_row > (row + maxrows)) {	/* skip to right row */
X			fprintf(fp, "%ld\n", rp->r_row - row);
X			row = rp->r_row;
X		}
X		while (rp->r_row > row) {
X			fputs(".\n", fp);
X			row++;
X		}
X
X		/*
X		 * Output the current row, compressing if it is too wide.
X		 */
X		col = mincol;
X		cp = rp->r_firstcell;
X		if ((cp->c_col + maxcols) < rp->r_lastcell->c_col) {
X			while (cp != termcell) {
X				/*
X				 * Write all adjacent blanks.
X				 */
X				if (cp->c_col > col + 2) {
X					fprintf(fp, "%ld.", cp->c_col - col);
X					col = cp->c_col;
X				}
X				while (cp->c_col > col) {
X					fputc('.', fp);
X					col++;
X				}
X
X				/*
X				 * Write all adjacent cells.
X				 */
X				while ((cp->c_col + 1) == cp->c_next->c_col) {
X					cp = cp->c_next;
X				}
X				if (cp->c_col >= col + 2) {
X					fprintf(fp, "%ldO", cp->c_col - col + 1);
X					col = cp->c_col + 1;
X				}
X				while (col <= cp->c_col) {
X					fputc('O', fp);
X					col++;
X				}
X				cp = cp->c_next;
X			}
X
X			fputc('\n', fp);
X			row++;
X			curmin = INFINITY;
X			curmax = -INFINITY;
X			continue;
X		}
X
X		/*
X		 * Here if the row doesn't need compressing.  See if several
X		 * rows from this one on can all fit in the same range.  If
X		 * so, set things up so they will align themselves nicely.
X		 */
X		if ((cp->c_col < curmin) || (rp->r_lastcell->c_col > curmax)) {
X			curmin = cp->c_col;
X			curmax = rp->r_lastcell->c_col;
X			trp = rp;
X			for (; rp != termrow; rp = rp->r_next) {
X				if (rp->r_firstcell == termcell)
X					continue;
X				testmin = rp->r_firstcell->c_col;
X				if (testmin > curmin)
X					testmin = curmin;
X				testmax = rp->r_lastcell->c_col;
X				if (testmax < curmax)
X					testmax = curmax;
X				if ((testmax - testmin) >= maxcols)
X					break;
X				curmin = testmin;
X				curmax = testmax;
X			}
X			rp = trp;
X		}
X
X		/*
X 		 * Type the row, with the initial shift if necessary.
X		 */
X		if (curmin != mincol) {
X			fprintf(fp, "%ld.", curmin - mincol);
X			col = curmin;
X		}
X		for (cp = rp->r_firstcell; cp != termcell; cp = cp->c_next) {
X			while (cp->c_col > col) {
X				fputc('.', fp);
X				col++;
X			}
X			fputc('O', fp);
X			col++;
X		}
X		fputc('\n', fp);
X		row++;
X	}
X}
X
X
X/*
X * Write an object out to a file in xlife format.
X * This is just a list of coordinates.
X */
Xstatic void
Xwritexlife(fp, obj, minrow, maxrow, mincol, maxcol)
X	FILE	*fp;
X	OBJECT	*obj;
X	COORD	minrow;
X	COORD	maxrow;
X	COORD	mincol;
X	COORD	maxcol;
X{
X	register ROW	*rp;
X	register CELL	*cp;
X
X	fprintf(fp, "#C \"%s\" (cells %ld width %ld height %ld generation %ld)\n",
X		obj->o_name, obj->o_count, maxcol - mincol + 1,
X		maxrow - minrow + 1, obj->o_gen);
X
X	fputs("#R\n", fp);
X
X	for (rp = obj->o_firstrow; rp != termrow; rp = rp->r_next) {
X		if (stop)
X			return;
X
X		for (cp = rp->r_firstcell; cp != termcell; cp = cp->c_next)
X			fprintf(fp, "%ld %ld\n", cp->c_col - ccol,
X				rp->r_row - crow);
X	}
X}
X
X
X/*
X * Write an object out to a file in rle format.
X */
Xstatic void
Xwriterle(fp, obj, minrow, maxrow, mincol, maxcol)
X	FILE	*fp;
X	OBJECT	*obj;
X	COORD	minrow;
X	COORD	maxrow;
X	COORD	mincol;
X	COORD	maxcol;
X{
X	register ROW	*rp;
X	register CELL	*cp;
X	COORD	row;
X	COORD	col;
X	VALUE	count;
X	int	pos;
X
X	fprintf(fp, "x = %ld, y = %ld\n", maxcol - mincol + 1,
X		maxrow - minrow + 1);
X
X	row = minrow;
X	col = mincol;
X	pos = 0;
X
X	for (rp = obj->o_firstrow; rp != termrow; rp = rp->r_next) {
X		if (stop)
X			return;
X
X		if (rp->r_firstcell == termcell)
X			continue;
X
X		if (row != rp->r_row)
X			rleitem(fp, &pos, rp->r_row - row, '$');
X		row = rp->r_row;
X
X		col = mincol;
X
X		for (cp = rp->r_firstcell; cp != termcell; cp = cp->c_next) {
X			if (cp->c_col != col) {
X				rleitem(fp, &pos, cp->c_col - col, 'b');
X				col = cp->c_col;
X			}
X			count = 1;
X			while (cp->c_next->c_col == cp->c_col + 1) {
X				cp = cp->c_next;
X				count++;
X			}
X			rleitem(fp, &pos, count, 'o');
X			col = cp->c_col + 1;
X		}
X	}
X
X	rleitem(fp, &pos, (VALUE) 1, '!');
X	fputc('\n', fp);
X}
X
X
X/*
X * Convert the specified count and action character to an rle string,
X * and write it to the specified file.  This adds the character count to
X * the specified line position, and if it would exceed RLEMAX, then inserts
X * a newline first.  The character position for the line is updated.
X */
Xstatic void
Xrleitem(fp, pos, count, action)
X	FILE	*fp;
X	int	*pos;
X	VALUE	count;
X{
X	int	len;
X	char	buf[16];
X
X	if (count == 0)
X		return;
X
X	if (count == 1) {
X		buf[0] = action;
X		buf[1] = '\0';
X		len = 1;
X	} else if (count == 2) {
X		buf[0] = action;
X		buf[1] = action;
X		buf[2] = '\0';
X		len = 2;
X	} else if ((count < 0) || (count > 99)) {
X		sprintf(buf, "%ld%c", count, action);
X		len = strlen(buf);
X	} else if (count < 10) {
X		buf[0] = count + '0';
X		buf[1] = action;
X		buf[2] = '\0';
X		len = 2;
X	} else {
X		buf[0] = (count / 10) + '0';
X		buf[1] = (count % 10) + '0';
X		buf[2] = action;
X		buf[3] = '\0';
X		len = 3;
X	}
X
X	if (*pos + len > RLEMAX) {
X		fputc('\n', fp);
X		*pos = 0;
X	}
X
X	fputs(buf, fp);
X	*pos += len;
X}
X
X/* END CODE */
SHAR_EOF
echo "File life/file.c is complete" &&
$TOUCH -am 0316122993 life/file.c &&
chmod 0644 life/file.c ||
echo "restore of life/file.c failed"
set `wc -c life/file.c`;Wc_c=$1
if test "$Wc_c" != "12560"; then
	echo original size 12560, current size $Wc_c
fi
# ============= life/README ==============
echo "x - extracting life/README (Text)"
sed 's/^X//' << 'SHAR_EOF' > life/README &&
XThis is my own version of a Life program, along with a library of some
Xinteresting Life objects.  It was written in C over a period of many years.
XIt runs using either curses or X11.  Other output devices should be easy
Xto add.
X
XThis program is not meant to be incredibly fast (use xlife for that:-).
XBut it IS meant to allow the easy editing and viewing of Life objects.
XIt can handle very large Life objects, and handles multiple objects at
Xthe same time.
X
XThe commands are documented in life.doc.  The documentation is terse and
Xjumps around a bit, but it does cover all the essential ideas.
X
XThe Makefile will probably need changing to load the X11 libraries correctly
Xfor your machine.  Also, you can define one of the values TERMIOS or SGTTY
Xto match your machine (or neither if you just want a standard set of default
Xline editing characters).  These are only used in scan.c.
X
XI hope you enjoy playing with this program.  Suggestions for improvements
Xare welcome, as are new interesting Life objects.
X
XDavid I. Bell
Xdbell@pdact.pd.necisa.oz.au
SHAR_EOF
$TOUCH -am 0316143293 life/README &&
chmod 0644 life/README ||
echo "restore of life/README failed"
set `wc -c life/README`;Wc_c=$1
if test "$Wc_c" != "1051"; then
	echo original size 1051, current size $Wc_c
fi
# ============= life/x11dev.c ==============
echo "x - extracting life/x11dev.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > life/x11dev.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#ifdef	X11
X
X#include <X11/Xlib.h>
X#include <X11/Xutil.h>
X#include <X11/keysym.h>
X#include <X11/StringDefs.h>
X
X#include "life.h"
X
X
X#define	WMRESX		20	/* X pixels to reserve for window manager */
X#define	WMRESY		30	/* Y pixels to reserve for window manager */
X#define	MINSCALE	-30	/* minimum scale */
X#define	DEFAULTSCALE	-8	/* default scale */
X#define	GRIDMAG		4	/* magnification when grid can be shown */
X#define	TEXTOFF		2	/* pixels for offsetting text from edges */
X
X
Xstatic	int	gropen();
Xstatic	void	grclose();
Xstatic	void	grupdate();
Xstatic	void	grrefresh();
Xstatic	int	grinputready();
Xstatic	int	grreadchar();
Xstatic	void	grmovecursor();
Xstatic	void	grshowview();
Xstatic	void	grshowstatus();
Xstatic	void	graddstatus();
Xstatic	void	grshowhelp();
Xstatic	void	graddhelp();
Xstatic	int	grassign();
X
X
XDEV	x11dev = {
X	gropen, grclose, grupdate, grrefresh, grinputready, grreadchar,
X	grmovecursor, grshowview, grshowstatus, graddstatus, grshowhelp,
X	graddhelp, grassign, 0, 0, 0, 0, MINSCALE, MAXSCALE, DEFAULTSCALE
X};
X
X
X/*
X * Other variables.
X */
Xstatic	Display		*display;	/* display for X */
Xstatic	int		screen;		/* screen number */
Xstatic	Window		rootwid;	/* top level window id */
Xstatic	Window		mainwid;	/* main window id */
Xstatic	Window		viewwid;	/* window id for view of cells */
Xstatic	Window		statwid;	/* window id for status line */
Xstatic	GC		statgc;		/* GC used for status line */
Xstatic	GC		viewgc;		/* GC used for view of cells */
Xstatic	GC		viewselectgc;	/* GC used for view of selected cells */
Xstatic	GC		viewgridgc;	/* GC used for view of grid */
Xstatic	GC		cursorgc;	/* GC used for cursor */
Xstatic	XFontStruct	*font;		/* font for text */
Xstatic	Colormap	cmap;		/* default color map */
Xstatic	long		black;		/* black pixel value */
Xstatic	long		white;		/* white pixel value */
Xstatic	long		red;		/* red pixel value */
Xstatic	long		blue;		/* blue pixel value */
Xstatic	long		grey;		/* grey pixel value */
Xstatic	int		charheight;	/* height of characters */
Xstatic	int		charascent;	/* ascent of characters */
Xstatic	int		spacewidth;	/* width of a space */
Xstatic	int		statwidth;	/* width of status window */
Xstatic	int		statheight;	/* height of status window */
Xstatic	int		viewwidth;	/* width of view window */
Xstatic	int		viewheight;	/* height of view window */
Xstatic	int		usedstatus;	/* space used in status line so far */
Xstatic	int		cursorx;	/* current cursor x location */
Xstatic	int		cursory;	/* current cursor y location */
Xstatic	int		helpx;		/* x position for new help text */
Xstatic	int		helpy;		/* y position for new help text */
Xstatic	int		helpcol;	/* column number for new help text */
Xstatic	BOOL		cursorshown;	/* TRUE if cursor is being shown */
Xstatic	BOOL		mapped;		/* TRUE if main window is mapped */
Xstatic	UCHAR		*genstr;	/* current char of generated string */
Xstatic	UCHAR		genstrbuf[32];	/* generated string to return */
Xstatic	UCHAR		assigns[4];	/* macro assignments for buttons */
X
X
Xstatic	int	doevent();
Xstatic	int	dokeydown();
Xstatic	void	doexposure();
Xstatic	int	dobuttondown();
Xstatic	void	viewnormal();
Xstatic	void	viewscale();
Xstatic	void	drawcursor();
Xstatic	void	clearrows();
X
X
X/*
X * Open the graphics device.
X */
Xstatic int
Xgropen(dev)
X	DEV	*dev;
X{
X	XColor		cellcolor;
X	XColor		namecolor;
X	XSizeHints	sizehints;
X	XWMHints	wmhints;
X
X	display = XOpenDisplay(NULL);
X	if (display == NULL) {
X		fprintf(stderr, "Cannot open graphics\n");
X		return -1;
X	}
X	screen = DefaultScreen(display);
X
X	font = XLoadQueryFont(display, "fixed");
X	if (font == NULL) {
X		fprintf(stderr, "Cannot load \"fixed\" font\n");
X		return -1;
X	}
X	charascent = font->ascent;
X	charheight = charascent + font->descent;
X	spacewidth = font->max_bounds.width;
X
X	/*
X	 * Allocate colors, defaulting them if they are not available.
X	 */
X	black = BlackPixel(display, screen);
X	white = WhitePixel(display, screen);
X	cmap = DefaultColormap(display, screen);
X
X	red = white;
X	blue = black;
X	grey = black;
X
X	if (XAllocNamedColor(display, cmap, "red", &cellcolor, &namecolor)) {
X		if (cellcolor.pixel != black)
X			red = cellcolor.pixel;
X	}
X
X	if (XAllocNamedColor(display, cmap, "blue", &cellcolor, &namecolor)) {
X		if (cellcolor.pixel != white)
X			blue = cellcolor.pixel;
X	}
X
X	if (XAllocNamedColor(display, cmap, "grey", &cellcolor, &namecolor)) {
X		if (cellcolor.pixel != white)
X			grey = cellcolor.pixel;
X	}
X
X	viewwidth = DisplayWidth(display, screen) - WMRESX;
X	statwidth = viewwidth;
X	statheight = charheight + TEXTOFF * 2;
X	viewheight = DisplayHeight(display, screen) - statheight - WMRESY;
X
X	rootwid = RootWindow(display, screen);
X
X	mainwid = XCreateSimpleWindow(display, rootwid,
X		0, 0, viewwidth, viewheight + statheight,
X		0, 0, 0);
X
X	statwid = XCreateSimpleWindow(display, mainwid,
X		0, 0, viewwidth, statheight,
X		0, 0, grey);
X
X	viewwid = XCreateSimpleWindow(display, mainwid,
X		0, statheight, viewwidth, viewheight,
X		0, 0, blue);
X
X	XSelectInput(display, mainwid, KeyPressMask | StructureNotifyMask);
X
X	XSelectInput(display, statwid, ExposureMask | KeyPressMask);
X
X	XSelectInput(display, viewwid, ExposureMask | KeyPressMask |
X		ButtonPressMask);
X
X	sizehints.flags = PSize | PMinSize | PMaxSize;
X	sizehints.width = viewwidth;
X	sizehints.min_width = sizehints.width;
X	sizehints.max_width = sizehints.width;
X	sizehints.height = viewheight + statheight;
X	sizehints.min_height = sizehints.height;
X	sizehints.max_height = sizehints.height;
X
X	XSetStandardProperties(display, mainwid, "life", "life", None,
X		(char **) "", 0, &sizehints);
X
X	wmhints.flags = InputHint;
X	wmhints.input = True;
X
X	XSetWMHints(display, mainwid, &wmhints);
X
X	XMapWindow(display, mainwid);
X	XMapWindow(display, statwid);
X	XMapWindow(display, viewwid);
X
X	statgc = XCreateGC(display, statwid, 0, NULL);
X	viewgc = XCreateGC(display, viewwid, 0, NULL);
X	viewgridgc = XCreateGC(display, viewwid, 0, NULL);
X	viewselectgc = XCreateGC(display, viewwid, 0, NULL);
X	cursorgc = XCreateGC(display, viewwid, 0, NULL);
X
X	XSetForeground(display, viewgc, white);
X	XSetForeground(display, statgc, blue);
X	XSetForeground(display, viewgridgc, (grey != black) ? grey : white);
X	XSetForeground(display, viewselectgc, red);
X	XSetForeground(display, cursorgc, white ^ blue);
X	XSetFunction(display, cursorgc, GXxor);
X	XSetFont(display, statgc, font->fid);
X
X	dev->rows = viewheight;
X	dev->cols = viewwidth;
X	dev->textrows = (viewheight - TEXTOFF * 2) / charheight;
X	dev->textcols = (viewwidth - TEXTOFF * 2) / spacewidth;
X
X	genstr = genstrbuf;
X	mapped = FALSE;
X
X	return 0;
X}
X
X
Xstatic void
Xgrclose(dev)
X	DEV	*dev;
X{
X	if (display)
X		XCloseDisplay(display);
X}
X
X
Xstatic void
Xgrupdate(dev, inputflag)
X	DEV	*dev;
X{
X	XSync(display, False);
X}
X
X
Xstatic void
Xgrrefresh(dev)
X	DEV	*dev;
X{
X	XSync(display, False);
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 * Returns characters from a generated string first, if present.
X */
Xstatic int
Xgrreadchar(dev, wait)
X	DEV	*dev;
X{
X	XEvent	event;
X	int	ch;
X
X	if (*genstr)
X		return *genstr++;
X
X	do {
X		if (!wait && (XEventsQueued(display, QueuedAfterFlush) <= 0))
X			return EOF;
X		XNextEvent(display, &event);
X		ch = doevent(&event);
X	} while (ch == EOF);
X
X	return ch;
X}
X
X
X/*
X * See if input is ready from the terminal.
X */
Xstatic BOOL
Xgrinputready(dev)
X	DEV	*dev;
X{
X	XEvent	event;
X
X	if (*genstr)
X		return TRUE;
X
X	while (TRUE) {
X		if (XEventsQueued(display, QueuedAfterFlush) <= 0)
X			return FALSE;
X		XPeekEvent(display, &event);
X		if (event.type == KeyPress)
X			return TRUE;
X		if (event.type == ButtonPress)
X			return TRUE;
X		XNextEvent(display, &event);
X		doevent(&event);
X	}
X}
X
X
X/*
X * Assign a macro to be automatically executed by a mouse button.
X * Returns nonzero if the button is illegal.
X */
Xstatic int
Xgrassign(dev, button, macro)
X	DEV	*dev;
X	VALUE	button;
X	UCHAR	macro;
X{
X	if ((button <= 0) || (button > 3))
X		return -1;
X	assigns[button] = macro;
X	return 0;
X}
X
X
X/*
X * Move the cursor to the specified location using the specified scale factor.
X * This is easy to do because we use XOR to draw it.
X */
Xstatic void
Xgrmovecursor(dev, sf, row, col)
X	DEV	*dev;
X	SCALE	sf;
X	COORD	row;
X	COORD	col;
X{
X	if (!mapped)
X		return;
X	if (cursorshown) {
X		drawcursor(sf, cursorx, cursory);
X		cursorshown = FALSE;
X	}
X	if ((sf == 0) || (sf == -1))
X		sf = 1;
X	if (sf < 0) {
X		sf = -sf;
X		row = row * sf + ((sf - 1) / 2);
X		col = col * sf + ((sf - 1) / 2);
X		sf = -sf;
X	} else {
X		row /= sf;
X		col /= sf;
X	}
X
X	cursorx = col;
X	cursory = row;
X	drawcursor(sf, cursorx, cursory);
X	cursorshown = TRUE;
X}
X
X
X/*
X * Draw the cursor at the specified location.  If the scale factor is
X * large enough, then the cursor is made larger.
X */
Xstatic void
Xdrawcursor(sf, x, y)
X	SCALE	sf;
X	COORD	x;
X	COORD	y;
X{
X	if (sf > -GRIDMAG) {
X		XDrawPoint(display, viewwid, cursorgc, x, y);
X		return;
X	}
X
X	XDrawPoint(display, viewwid, cursorgc, x, y);
X	XDrawPoint(display, viewwid, cursorgc, x - 1, y);
X	XDrawPoint(display, viewwid, cursorgc, x + 1, y);
X	XDrawPoint(display, viewwid, cursorgc, x, y - 1);
X	XDrawPoint(display, viewwid, cursorgc, x, y + 1);
X}
X
X
X/*
X * Show the view around the current window location.
X */
Xstatic void
Xgrshowview(dev)
X	DEV	*dev;
X{
X	if (!mapped)
X		return;
X	if (curobj->o_scale > 1)
X		viewscale(curobj->o_scale);
X	else if (curobj->o_scale >= -1)
X		viewnormal(1);
X	else
X		viewnormal(-curobj->o_scale);
X}
X
X
X/*
X * Update the status line.
X */
Xstatic void
Xgrshowstatus(dev, str)
X	DEV	*dev;
X	char	*str;
X{
X	int	len;
X	int	width;
X
X	if (!mapped)
X		return;
X	len = strlen(str);
X	XClearWindow(display, statwid);
X	width = XTextWidth(font, str, len);
X	XDrawString(display, statwid, statgc, TEXTOFF, charascent + TEXTOFF, str, len);
X	usedstatus = width + TEXTOFF;
X}
X
X
X/*
X * Add to the status line.
X * The assumption is made that this routine is used only for input,
X * and thus the text is ended with an underscore as a prompt.
X */
Xstatic void
Xgraddstatus(dev, str)
X	DEV	*dev;
X	char	*str;
X{
X	int		len;
X	static	int	uswidth;
X
X	len = strlen(str);
X	if (uswidth == 0)
X		uswidth = XTextWidth(font, "_", 1);
X
X	XClearArea(display, statwid, usedstatus, 0, uswidth, 0, False);
X	XDrawString(display, statwid, statgc, usedstatus, charascent + TEXTOFF,
X		str, len);
X	usedstatus += XTextWidth(font, str, len);
X	XDrawString(display, statwid, statgc, usedstatus, charascent + TEXTOFF,
X		"_", 1);
X}
X
X
X/*
X * Begin to show help information.
X * We use the view window for this.
X */
Xstatic void
Xgrshowhelp(dev)
X	DEV	*dev;
X{
X	XClearWindow(display, viewwid);
X	helpcol = 0;
X	helpx = TEXTOFF;
X	helpy = charascent + TEXTOFF;
X}
X
X
X/*
X * Add information to the help display.
X * We must interpret certain control codes.
X */
Xstatic void
Xgraddhelp(dev, str)
X	DEV	*dev;
X	char	*str;
X{
X	char	*cp;
X	int	len;
X
X	cp = str;
X	for (;;) {
X		while (*cp >= ' ')
X			cp++;
X
X		len = cp - str;
X		if (len > 0) {
X			XDrawString(display, viewwid, viewgc, helpx, helpy,
X				str, len);
X			helpcol += len;
X			helpx += XTextWidth(font, str, len);
X		}
X
X		switch (*cp++) {
X			case '\0':
X				return;
X
X			case '\n':
X				helpcol = 0;
X				helpx = TEXTOFF;
X				helpy += charheight;
X				break;
X
X			case '\t':
X				len = 8 - (helpcol + 1) % 8;
X				XDrawString(display, viewwid, viewgc,
X					helpx, helpy, "        ", len);
X				helpcol += len;
X				helpx += spacewidth * len;
X				break;
X		}
X		str = cp;
X	}
X}
X
X
X/*
X * Handle the specified event.
X * Returns a character generated by the event, or else EOF if
X * the event does not produce a character.
X */
Xstatic int
Xdoevent(event)
X	XEvent	*event;
X{
X	switch (event->type) {
X		case Expose:
X			mapped = TRUE;
X			doexposure(&event->xexpose);
X			return NULL_CMD;
X		case ButtonPress:
X			return dobuttondown(&event->xbutton);
X			break;
X		case KeyPress:
X			return dokeydown(&event->xkey);
X		case MapNotify:
X			mapped = TRUE;
X			break;
X		case UnmapNotify:
X			mapped = FALSE;
X			break;
X	}
X	return EOF;
X}
X
X
Xstatic void
Xdoexposure(ep)
X	XExposeEvent	*ep;
X{
X	if (ep->window == statwid)
X		update |= U_STAT;
X
X	if (ep->window == viewwid)
X		update |= U_ALL;
X}
X
X
X/*
X * Handle a button down event.
X * This fakes up a string which moves the pointer to the mouse position,
X * and possibly executes a macro.
X */
Xstatic int
Xdobuttondown(bp)
X	XButtonEvent	*bp;
X{
X	char	*cp;
X	SCALE	sf;
X	COORD	buttonrow;
X	COORD	buttoncol;
X	COUNT	deltarow;
X	COUNT	deltacol;
X
X	if (bp->window != viewwid)
X		return -1;
X
X	sf = curobj->o_scale;
X	if (sf >= 0) {
X		buttonrow = bp->y * sf;
X		buttoncol = bp->x * sf;
X	} else {
X		buttonrow = bp->y / (-sf);
X		buttoncol = bp->x / (-sf);
X	}
X
X	deltarow = buttonrow - (curobj->o_currow - curobj->o_minrow);
X	deltacol = buttoncol - (curobj->o_curcol - curobj->o_mincol);
X
X	if (sf > 1) {
X		deltarow /= sf;
X		deltacol /= sf;
X	}
X
X	sprintf(genstrbuf, "%ldj%ldl", deltarow, deltacol);
X
X	/*
X	 * If a macro has been assigned to the button, then add the
X	 * sequence to execute the macro.
X	 */
X	cp = genstrbuf + strlen(genstrbuf);
X	if ((bp->button == Button1) && assigns[1]) {
X		*cp++ = ESC;
X		*cp++ = assigns[1];
X	}
X	if ((bp->button == Button2) && assigns[2]) {
X		*cp++ = ESC;
X		*cp++ = assigns[2];
X	}
X	if ((bp->button == Button3) && assigns[3]) {
X		*cp++ = ESC;
X		*cp++ = assigns[3];
X	}
X	*cp = '\0';
X
X	genstr = genstrbuf;
X
X	return NULL_CMD;
X}
X
X
X/*
X * Return a key typed in our window, or EOF if no such key was typed.
X */
Xstatic int
Xdokeydown(kp)
X	XKeyEvent	*kp;
X{
X	KeySym	keysym;
X	int	len;
X	int	ch;
X	UCHAR	buf[12];
X
X	len = XLookupString(kp, buf, sizeof(buf), &keysym, NULL);
X	if ((len != 1) || IsModifierKey(keysym))
X		return EOF;
X
X	ch = buf[0];
X	if (ch == '\r')
X		ch = '\n';
X
X	return ch;
X}
X
X
X/*
X * Show the cells around the cursor normally (showing each cell).
X * The specified magnification factor is applied.
X */
Xstatic void
Xviewnormal(mag)
X{
X	register ROW	*rp;		/* current row */
X	register CELL	*cp;		/* current cell */
X	COORD		row;		/* current row number */
X	COORD		col;		/* current column number */
X	OBJECT		*obj;		/* current object */
X	COUNT		blankrows;	/* number of blank rows */
X	COORD		screenrow;	/* row on screen */
X	COORD		screencol;	/* column on screen */
X	BOOL		cleared;	/* TRUE is line has been cleared */
X	GC		gc;		/* GC for points */
X
X	obj = curobj;
X	rp = obj->o_firstrow;
X	row = obj->o_minrow;
X	while (row > rp->r_row)
X		rp = rp->r_next;
X
X	screenrow = 0;
X	blankrows = 0;
X	seecount = 0;
X
X	for (; row <= obj->o_maxrow; row++) {
X		if (row != rp->r_row) {			/* blank row */
X			blankrows++;
X			screenrow++;
X			continue;
X		}
X
X		cp = rp->r_firstcell;
X		col = obj->o_mincol;
X		while (col > cp->c_col)
X			cp = cp->c_next;
X
X		screencol = 0;
X		cleared = FALSE;
X
X		for (; col <= obj->o_maxcol; col++) {
X			if (col != cp->c_col) {		/* blank cell */
X				screencol++;
X				continue;
X			}
X
X			if (!cleared) {
X				clearrows((screenrow - blankrows) * mag,
X					(blankrows + 1) * mag, mag);
X				blankrows = 0;
X				cleared = TRUE;
X			}
X
X			gc = viewgc;
X			if (cp->c_marks & MARK_SEE)
X				gc = viewselectgc;
X
X			if (mag == 1) {
X				XDrawPoint(display, viewwid, gc, screencol, screenrow);
X			} else if (mag == 2) {
X				XDrawPoint(display, viewwid, gc, screencol*2, screenrow*2);
X				XDrawPoint(display, viewwid, gc, screencol*2+1, screenrow*2);
X				XDrawPoint(display, viewwid, gc, screencol*2, screenrow*2+1);
X				XDrawPoint(display, viewwid, gc, screencol*2+1, screenrow*2+1);
X			} else {
X				XFillRectangle(display, viewwid, gc,
X					screencol * mag, screenrow * mag,
X					mag - 1, mag - 1);
X			}
X
X			seecount++;
X			screencol++;
X			cp = cp->c_next;
X		}
X
X		if (!cleared)
X			blankrows++;
X		screenrow++;
X		rp = rp->r_next;
X	}
X
X	clearrows((screenrow - blankrows) * mag,
X		dev->rows - (screenrow - blankrows) * mag, mag);
X
X	cursorshown = FALSE;
X}
X
X
X/*
X * Show the view around the cursor with an arbitrary scale factor.
X * Each pixel then represents one or more live cells in an N by N area.
X * If any of those cells are marked, then the pixel will show it.
X */
Xstatic void
Xviewscale(sf)
X	SCALE	sf;
X{
X	register CELL	*cp;		/* current cell structure */
X	COORD		row;		/* current row number */
X	COORD		col;		/* current column number */
X	int		sum;		/* number of cells in square */
X	OBJECT		*obj;		/* current object */
X	CELL		**cpp;		/* pointer into cell table */
X	CELL		**endcpp;	/* end of cell table */
X	ROW		*rp;		/* row pointer */
X	COUNT		blankrows;	/* number of blank rows */
X	COORD		screenrow;	/* row on screen */
X	COORD		screencol;	/* column on screen */
X	BOOL		cleared;	/* TRUE is line has been cleared */
X	GC		gc;		/* GC for points */
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	screenrow = 0;
X	blankrows = 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 graphics line is empty.
X		 */
X		if (rp->r_row >= (row + sf)) {	/* no rows here */
X			row += sf;
X			blankrows++;
X			screenrow++;
X			continue;
X		}
X
X		/*
X		 * Collect the rows to be searched for one graphics 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
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		screencol = 0;
X		cleared = FALSE;
X
X		for (col = obj->o_mincol; col <= obj->o_maxcol; col += sf) {
X			gc = viewgc;
X			sum = 0;
X
X			for (cpp = cptab; cpp < endcpp; cpp++) {
X				cp = *cpp;
X				while (col > cp->c_col)
X					cp = cp->c_next;
X
X				while ((col + sf) >= cp->c_col) {
X					sum++;
X					if (cp->c_marks & MARK_SEE)
X						gc = viewselectgc;
X					cp = cp->c_next;
X				}
X				*cpp = cp;
X			}
X
X			if (sum == 0) {		/* no cells in square */
X				screencol++;
X				continue;
X			}
X
X			if (!cleared) {
X				XClearArea(display, viewwid, 0,
X					screenrow - blankrows, viewwidth,
X					blankrows + 1, False);
X				blankrows = 0;
X				cleared = TRUE;
X			}
X
X			XDrawPoint(display, viewwid, gc, screencol, screenrow);
X
X			seecount += sum;
X			screencol++;
X		}
X
X		if (!cleared)
X			blankrows++;
X		screenrow++;
X	}
X
X	XClearArea(display, viewwid, 0, screenrow - blankrows, 
X		viewwidth, dev->rows - (screenrow - blankrows), False);
X
X	cursorshown = FALSE;
X}
X
X
X/*
X * Clear the specified number of rows on the screen, taking into account
X * the specified magnification factor.  If the magnification is large
X * enough and a grid has been specified, then some dots will be drawn
X * in the cleared rows to indicate the position of each cell.  The row
X * number and row counts are in pixels.
X */
Xstatic void
Xclearrows(row, rowcount, mag)
X	COORD	row;
X	COUNT	rowcount;
X	SCALE	mag;
X{
X	COUNT	colcount;
X	COORD	col;
X	COUNT	offset;
X
X	if ((mag < GRIDMAG) || (gridchar == ' ')) {
X		XClearArea(display, viewwid, 0,  row,
X			viewwidth, rowcount, False);
X		return;
X	}
X
X	/*
X	 * For each row, clear it and then draw one pixel in the center of
X	 * each cell of the row.  The whole area isn't cleared at once for
X	 * this case so as to make the graphics look nicer as it is drawn.
X	 */
X	offset = (mag - 1) / 2;
X	rowcount /= mag;
X
X	while (rowcount-- > 0) {
X		XClearArea(display, viewwid, 0,  row,
X			viewwidth, mag, False);
X		col = offset;
X		colcount = viewwidth / mag;
X		while (colcount-- > 0) {
X			XDrawPoint(display, viewwid, viewgridgc, col, row + offset);
X			col += mag;
X		}
X		row += mag;
X	}
X}
X
X#endif
X
X/* END CODE */
SHAR_EOF
$TOUCH -am 0316122993 life/x11dev.c &&
chmod 0644 life/x11dev.c ||
echo "restore of life/x11dev.c failed"
set `wc -c life/x11dev.c`;Wc_c=$1
if test "$Wc_c" != "19386"; then
	echo original size 19386, current size $Wc_c
fi
rm -f shar3_seq_.tmp
echo "You have unpacked the last part"
exit 0


This archive was generated by hypermail 2.1.7 : Tue Oct 14 2003 - 21:44:08 UTC