Life program (part 16/18)

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


#!/bin/sh
# this is LIFE.16 (part 16 of a multipart archive)
# do not concatenate these parts, unpack them in order with /bin/sh
# file life/life.doc 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" != 16; then
	echo "Please unpack part $Scheck next!"
	exit 1
 else
	exit 0
 fi
) < shar3_seq_.tmp || exit 1
echo "x - Continuing file life/life.doc"
sed 's/^X//' << 'SHAR_EOF' >> life/life.doc &&
X
XA very useful feature is the use of marks.  You can select any group of
Xcells of an object, and handle them specially, leaving the rest of the cells
Xunchanged.  For example, you can save the marked cells as a different object,
Xor can move them around, or can delete them.  Marked cells appear differently
Xin the display so that you can recognize which cells are marked.  Marks are
Xset based on where the cursor is.  You can mark all the cells in any quadrant
Xor half-plane around the cursor.  You can also mark all the cells which are
Xking-wise connected to your cursor location, or which are connected with only
Xone cell gaps to your cursor location.  Each mark command adds to the set of
Xmarked cells.  The ';unmark' command removes all current marks so that you can
Xstart again.  There are several commands which act on the marked cells in
Xinteresting ways.  For example, if the cursor is on a glider, the command
X'dd' will delete just the glider.  The commands which flip or rotate marked
Xcells do so with respect to the current cursor location.
X
XCommand loops and macros can be defined using the '<' and '>' commands.  If
Xa numeric argument is specified, a loop is being defined.  If no argument is
Xgiven, a macro is being defined.  While defining a macro or loop, the commands
Xyou type are executed normally so that you can see how the definition will
Xexecute.  This is useful when you define a macro to create an object, since
Xyou can easily see how to create the object.  Loops and macros can contain
Xboth line mode and character mode commands.  While you are defining a loop
Xor macro, the status line will indicate this and give the current depth of
Xloop or macro nesting.
X
XWhen defining a macro, the next character after the '<' is the macro name to
Xdefine (which must be a lower case letter).  All of the commands between
Xthe '<' and the '>' (except for the macro name character) are saved.  Once a
Xmacro has been defined, it is used by typing the ESCAPE character followed by
Xthe macro letter.  As an example, the command string '<gththtuktntj>' defines
Xa macro named 'g' which causes a glider to be inserted at the current cursor
Xposition every time you type '<ESC>g'.  The ';dumpmacros' command writes out
Xthe definitions of all macros so that you can read them back in later.
X
XIf a loop is being defined, the loop is executed the number of times specified
Xby the argument to '<'.  If two arguments are specified, the loop runs from
Xthe first to the second argument (backwards if the second argument is less
Xthan the first argument).  The value of the loop counter is available in the
Xloop itself by using '%' as you would a number.  As an example of a loop,
Xthe command string '3,7<%o >' inserts five strings of cells spaced apart by
Xone cell, where the first string contains three cells, and the last string
Xcontains seven cells.  When nesting loops, supplying an argument to '%' can
Xobtain the loop counter values for the outside loops while in the inner loop.
XThus, '2%' obtains the loop value for the next-to-innermost loop level.
X
XWhile defining a loop or macro, you can request user intervention by using
Xthe ';ttyinput' command.  This will suspend the execution of the loop or macro
Xand notify the user that input is desired by displaying 'tty-input' in the
Xstatus line.  The user can then execute any commands of his choice.  When he
Xis ready to proceed, he uses the ';endinput' (or a control-D) command to
Xcontinue execution where it had paused.  Different commands can be given by
Xthe user each time the loop or macro asks for terminal input.  If the command
X;ttyinput -c' is used, terminal commands will only be asked for if there
Xis any terminal input available to be read.
X
XNormally, the screen is not updated while a macro or loop is executing.  Thus
Xa complicated command sequence can be executed without letting the user see
Xwhat is occuring until it is finished.  However, if you wish to update the
Xscreen in the middle of execution, then use the ';update' command.  Commands
Xgiven from the terminal automatically do an update whenever no more input is
Xavailable.
X
XWhen running using graphics, the mouse can be used to move the cursor to any
Xposition within the view, and can also automatically execute a command macro
Xof your choice.  The ';assign' command will assign a mouse button number to
Xa command macro letter.  When the mouse is positioned and the button is
Xpressed, then the cursor is moved to the selected cell and then the command
Xmacro is executed.  With the proper command macros being defined, this lets
Xyou use the mouse buttons for useful operations like toggling cells,
Xdeleting pieces of objects, or repositioning the view.  If no command macro
Xis assigned to a mouse button, then pressing the button simply moves the
Xcursor to the specified cell and does nothing else.  Mouse activity can be
Xreasonably used within a macro or loop definition since mouse events are
Xtranslated to the appropriate 'l' and 'j' relative movement commands.
X
XA few commands make use of a location called a pointer.  The pointer is a
Xlocation that is remembered in an object, independent of the current cursor
Xlocation.  It is used by the '\n' command, which moves to the next row and
Xback to the column of the pointer.  It is also used by the 'p' selection
Xarea option, and determines the far corner of a rectangular region to be
Xselected.  The '@' command sets the pointer to the current cursor location.
X
XWhen you are trying to count the number of cells between two parts of an
Xobject, then the ';grid' command is useful.  For terminal output, it changes
Xthe display of dead cells from blanks to another character (typically
Xperiods).  For graphics output, the grid is drawn using individual pixels.
X(The grid will not be displayed unless the scale factor is -4 or less,
Xotherwise it would be difficult to distinguish the grid from the cells.)
X
XThe program provides numeric variables which you can use to control your
Xcommands.  Variables are used as numeric arguments to commands.  Variables
Xcome in two kinds.  These are the user-defined single character variables,
Xand a set of predefined multi-character variables.
X
XThere are 52 single-character variables, whose names are the lower and upper
Xcase letters.  All of their values are initially zero.  When used for a
Xcharacter mode command (and without the use of parenthesis), variable
Xnames must be preceded by a dollar sign to distinguish them from commands.
XFor example, the command '$mo' inserts as many live cells in a row as is
Xcontained in the value of variable 'm'.
X
XWhen used within an expression for a line mode command, or within a set of
Xparenthesis in a character mode command, the dollar sign can be dropped
Xsince the parser knows to expect a variable name in these cases.  For
Xexample, the command ';type m' will display the value of variable 'm'.
XSimilarly, the command '(m*2)o' will set a number of live cells equal to
Xtwice the value of variable 'm'.
X
XSingle character variables are set by using the ';set' command, which
Xtakes a variable name followed by an expression.  For example, the value
Xof variable 'e' can be tripled by using the command ';set e e * 3'.
XAs a shortcut for a common operation, the '+c' character mode command
Xincrements variable c.  (Of course, a numeric argument can be given to
Xspecify an increment value other than than 1.)
X
XOne common use of variables is inside a macro in order to execute a command
Xstring over and over again with only small differences each time (such as
Xto vary the placement of two objects with respect to each other).  As an
Xexample of this, the command '<q$ao3+a>' will define a macro called 'q' which
Xwill insert a number of live cells in a row (as determined by variable 'a'),
Xand the number of cells inserted increases by 3 for each use of the macro.
X
XThe other kind of variables are the multi-character variables.  These are
Xa fixed set of names, and their values represent specific things which are
Xnot directly modifyable.  These things are values associated with the current
Xobject.  For example, the 'cx' variable returns the absolute x coordinate of
Xthe current cursor position.  You can see the complete set of variables by
Xusing the ';variables' command.
X
XSince the parser must be able to distinguish multi-character variable names
Xfrom command letters or single-letter variable names, you cannot use them in
Xcharacter mode commands without surrounding them with a pair of parenthesis.
XAs an example of multi-character variables used as an argument, the command
Xstring '((vmaxx-vminx)/2)h' shifts the cursor to the left by an amount
Xequal to half of the screen width.
X
XHere are some of the remaining useful line mode commands.  The ';quit' command
Xexits the program.  The ';zero' command clears all cells of an object and
Xresets the scaling factor and cursor position.  The ';copymarked name' and
X';movemarked name' commands copy or move marked cells to another object.
XThe ';advance' command takes the marked object, removes it, runs the Life
Xrules for the specified number of generations, then reinserts the result
Xback into the current object, marking it.  Finally, the ';undo' command
Xwill undo the most recent change to the current object.  This can undo
Xdeletions, insertions, and running of generations, among other things.
XBut you get only one level of backup.  (A related backup feature is the 'p'
Xcommand, which will reinsert the last deleted object to the current cursor
Xlocation.)
X
XThe rules of Life can be changed to some degree.  This allows you to explore
Xalternative Life universes.  You can specify how many live cells are required
Xfor a cell to be born, or to stay alive.  However, you cannot change the
Xneighborhood used for counting live cells (the program always counts all of
Xthe eight neighboring cells).  To change the cells needed for birth or death,
Xuse the ';rules <born> <live>' line mode command.  The <born> string lists
Xthose counts of neighbors which are required for a new cell to be born.  The
X<live> string lists those counts of neighbors which are required for an
Xexisting cell to stay alive.  The standard rules are thus described by the
Xcommand ';rules 3 23'.
X
XThe following table specifies the character mode commands, arranged in
Xuseful categories.  Many of these have been described in detail above.
X
X--- MOVEMENT COMMANDS ---
X
XSPACE	move right <arg1> cells
Xl	move right <arg1> cells
Xh	move left <arg1> cells
Xl	move right <arg1> cells
Xk	move up <arg1> cells
Xj	move down <arg1> cells
Xy	move upper left <arg1> cells
Xu	move upper right <arg1> cells
Xb	move lower left <arg1> cells
Xn	move lower right <arg1> cells
XLF	move to next row and to the column of the pointer
XTAB	move to next multiple of 8 from the pointer column
X@	remember current location as the pointer
Xc	move to location <arg1>, <arg2> relative to the pointer
X/	move cursor to next object
X
X--- SCREEN COMMANDS ---
X
Xs	set viewing scale to <arg1> and center view (default current scale)
XS	turn on auto-scaling and center view
XH	shift view left by width/4
XL	shift view right by width/4
XK	shift view up by height/4
XJ	shift view down by height/4
XY	shift view left and up
XU	shift view right and up
XB	shift view left and down
XN	shift view right and down
XFF	refresh the screen
X
X--- SINGLE CELL COMMANDS --
X
Xt	toggle cell at current location
Xo	insert <arg1> cells and move cursor right
XO	insert <arg1> cells and move cursor right
Xx	kill <arg1> cells and move cursor right
X
X--- MULTIPLE CELL COMMANDS ---
X
Xd<mark>	delete cells described by <mark>
Xp	place last deleted object at current location
Xfr<mark> flip cells around the current row as described by <mark>
Xfc<mark> flip cells around the current column as described by <mark>
Xr<mark>	rotate cells 90 degrees clockwise as described by <mark>
Xm<mark>	mark cells as described by <mark>
X
X--- LOOP, VARIABLE, AND MACRO COMMANDS ---
X
X<	begin loop which executes from <arg1> to <arg2> times (if <arg1> given)
X<<ch>	begin definition of macro named <ch> (if <arg1> not given)
X>	end loop or macro definition
XESC<ch>	execute a macro command named <ch>
X+<ch>	increment the value of the single-character variable <ch> by arg1
X
X--- MISCELLANEOUS COMMANDS ---
X
Xg	compute <arg1> generations (or stop if running)
XG	compute infinite generations
Xz	set generation number to <arg1> (default zero)
X!	ignore characters until end of line
X#	ignore character until end of line
X<line>	execute a line mode command
X<line>	execute a line mode command
X
XArguments specified above as <arg1> and <arg2> can be any of the following:
X<var>	value of variable <var>, where <var> is a lower or upper case letter
X(expr)	an arithmetic expression containing constants, variables, or operators
X%	current loop counter value
X<num>	explicit numeric value
X
XThose commands above referencing <mark> take one of the following letters.
XThe command affects only those cells marked.  As a special case, repeating
Xthe command letter is equivalent to marking 'o' (the connected object).
XExample: 'dd' deletes the connected object the cursor is on.
Xa    all cells
Xc    cell at current location
Xo    cells in the king-wise connected object at current location
Xe    cells in the king-wise connected object allowing one cell gaps
Xh    cells to left of cursor
Xl    cells to right of cursor
Xk    cells above cursor
Xj    cells below cursor
Xb    cells below and left of cursor
Xn    cells below and right of cursor
Xu    cells above and right of cursor
Xy    cells above and left of cursor
Xp    cells in rectangle determined by pointer and cursor
Xm    cells which are marked
Xv    cells visible in window
Xi    cells invisible in window
X
XWhile the program is doing something which can take a long time, such as
Xcomputing generations, defining or executing a macro or loop, or writing
Xout a large Life object, you can type the interrupt key and that action
Xwill be aborted at a convenient point and you will be returned to the top
Xcommand level.
X
XHere is a list of the possible options when starting the life program.
XAs mentioned previously, these options can also be specified in the LIFEOPTS
Xenvironment variable, and overwritten by the command line as needed.
X
X-t		use terminal output
X-g		use graphics output
X-s <arg>	initialize the default scale to the specified value
X-l <path>	set a personal library directory path
X
X
X			    APPENDIX
X
XThis is a short introduction to Conway's Game of Life.  Life is played on an
Xinfinitely large board divided into squares.  Each square is called a cell.
XEach cell can be either dead or alive.  Dead cells are seen as blanks, whereas
Xlive cells are seen as non-blanks.  You begin to play by choosing some
Xarbitrary set of live and dead cells.  This configuration is called generation
X0.  There is a set of rules which transforms this set of cells into another
Xset of cells, called generation 1.  These same rules are then reapplied to
Xgeneration 1 to produce generation 2.  This process continues indefinitely.
XThe 'purpose' of the game is to find starting patterns such that 'interesting
Xthings' result.
X
XThe rules which are applied are as follows.  Take any cell of a generation,
Xand call it the current cell.  Consider the eight cells immediately adjacent
Xto the current cell.  Count the number of these eight cells which are alive.
XIf the current cell is dead and the count is 3, then the current cell changes
Xto a live cell in the next generation.  If the current cell is alive and the
Xcount is NOT 2 or 3, then the current cell changes to a dead cell in the next
Xgeneration.  Otherwise the cell remains unchanged in the next generation.
XThis rule is applied to every cell of a generation SIMULTANEOUSLY.  Thus to
Xrephrase, 3 live neighbors causes a new cell to be born, whereas 2 or 3 live
Xneighbors keeps a cell alive.
X
XTo see how these rules work in practice, run the program and start with some
Xnumber of live cells in some arrangement, and watch the generations change.
XIf you can predict what the changes will be, then you understand the rules.
XThe following are some objects to try, along with some descriptive names.
XWarning: the last example gets complicated!!
X
X  O         O          O                  O             O          OO
X   O        O         OO       OO         OO             O          OO
X  O         O         O         O         O            OOO          O
X
Xdoomed   blinker   beehive   block   traffic lights   glider   r-pentomino
SHAR_EOF
echo "File life/life.doc is complete" &&
$TOUCH -am 0316154893 life/life.doc &&
chmod 0600 life/life.doc ||
echo "restore of life/life.doc failed"
set `wc -c life/life.doc`;Wc_c=$1
if test "$Wc_c" != "31040"; then
	echo original size 31040, current size $Wc_c
fi
# ============= life/life.h ==============
echo "x - extracting life/life.h (Text)"
sed 's/^X//' << 'SHAR_EOF' > life/life.h &&
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 * Program to play Conway's game of LIFE on an infinite board.
X */
X
X#include <stdio.h>
X#include <setjmp.h>
X#include <signal.h>
X
X
X#define	ESC	'\033'
X#define	FF	'\014'
X
X#define	isblank(ch)	(((ch) == ' ') || ((ch) == '\t'))
X#define	isdigit(ch)	(((ch) >= '0') && ((ch) <= '9'))
X#define	islower(ch)	(((ch) >= 'a') && ((ch) <= 'z'))
X#define	isupper(ch)	(((ch) >= 'A') && ((ch) <= 'Z'))
X#define	isletter(ch)	(islower(ch) || isupper(ch))
X
X
X#ifndef	LIFELIB
X#define	LIFELIB	"/usr/games/lib/life"	/* directory for general life library */
X#endif
X
X#define	LIFEOPTS	"LIFEOPTS"	/* environment name for options */
X#define	LIFEEXT		".l"		/* extension for life files */
X#define	MAXPATH		1024		/* maximum size of path names */
X#define	MAXFILE		18		/* maximum size of file name for list */
X#define	MAXLIST		5		/* maximum depth for listing files */
X#define	ALLOCOBJ	10		/* how many new objects to allocate */
X#define	ALLOCROW	50		/* how many new rows to allocate */
X#define	ALLOCCELL	500		/* how many new cells to allocate */
X#define	LISTARGSIZE	200		/* incremental arg size for lists */
X#define	LISTBUFSIZE	2000		/* incremental buffer size for lists */
X#define	STRINGSIZE	(1024*4)	/* temp string buffer size */
X#define	LOOPSIZE	5000		/* characters in command loops */
X#define	SCAN_SIZE	100		/* maximum command length */
X#define	MAXARGS		10		/* maximum command line arguments */
X#define	MAXINPUT	20		/* maximum nesting of command inputs */
X#define	MAXNAME		32		/* maximum object name size */
X#define	MAXSCALE	1000		/* maximum scale factor */
X#define	WRITEROWS	100		/* default maximum rows for writing */
X#define	WRITECOLS	79		/* default maximum cols for writing */
X#define	INFINITY	0x7fffffff	/* infinite value */
X#define	LIFE		9		/* value for live cell */
X
X#define	STDIN		0		/* standard input */
X#define	STDOUT		1		/* standard output */
X#define	STDERR		2		/* standard error */
X
X#define	RELATIVE	0		/* do object additions relatively */
X#define	ABSOLUTE	1		/* do object additions absolutely */
X
X#define	M_MOVE		0		/* movement mode */
X#define	M_INSERT	1		/* insertion mode */
X#define	M_DELETE	2		/* deletion mode */
X
X#define	MARK_ANY	0x1		/* mark always set */
X#define	MARK_USR	0x2		/* marked due to user specification */
X#define	MARK_CMD	0x4		/* marked only for current command */
X#define	MARK_SRC	0x8		/* marked by searching */
X#define	MARK_SEE	(MARK_USR)	/* marks seen by user */
X#define	MARK_ALL	(MARK_ANY|MARK_USR|MARK_CMD|MARK_SRC)	/* all non-null marks */
X
X#define	INP_TTY		0		/* input is terminal */
X#define	INP_FILE	1		/* input is file */
X#define	INP_LOOP	2		/* input is command loop */
X#define	INP_MACRO	3		/* input is command macro */
X
X#define	SCAN_ABORT	1		/* setjmp value for aborted command */
X#define	SCAN_EDIT	2		/* setjmp value for edited command */
X#define	SCAN_EOF	3		/* setjmp value for no command data */
X
X#define	NULL_CMD	0xff		/* null command character */
X
X#define	U_POS		0x01		/* update cursor position */
X#define	U_STAT		0x02		/* update status line */
X#define	U_VIEW		0x04		/* update view of cells */
X#define	U_ALL		(U_POS | U_STAT | U_VIEW)	/* any updating */
X
X#ifndef	TRUE
X#define	TRUE		((BOOL) 1)	/* booleans */
X#define	FALSE		((BOOL) 0)
X#endif
X
X#define	crow		curobj->o_currow	/* current row of current object */
X#define	ccol		curobj->o_curcol	/* current column of current object */
X#define	cmark		curobj->o_mark	/* current mark being applied */
X#define	cscale		curobj->o_scale	/* current scale of current object */
X#define	prow		curobj->o_prow	/* current pointer row */
X#define	pcol		curobj->o_pcol	/* current pointer column */
X
X
X/* macro to detect reserved names */
X#define	BADNAME(s)	((s[0] == '.') && ((s[1] == '\0') || (s[1] == '.')))
X
X
X/*
X * Basic typedefs
X */
Xtypedef	long		COORD;		/* coordinate of a cell */
Xtypedef	long		COUNT;		/* counts of things */
Xtypedef	long		VALUE;		/* value of an expression */
Xtypedef	int		MARK;		/* mark value */
Xtypedef	int		BOOL;		/* boolean value */
Xtypedef	int		SCALE;		/* scale factor */
Xtypedef	unsigned char	UCHAR;		/* for character handling */
X
X
X/*
X * Structure for each cell.
X */
Xtypedef	struct	cell	CELL;
Xstruct	cell	{
X	CELL	*c_next;		/* link to next cell */
X	COORD	c_col;			/* column number */
X	MARK	c_marks;		/* marking values for cell */
X};
X
X
X/*
X * Structure for each row of cells.
X */
Xtypedef	struct	row	ROW;
Xstruct	row	{
X	ROW	*r_next;		/* link to next row */
X	CELL	*r_firstcell;		/* link to first cell */
X	CELL	*r_lastcell;		/* link to last real cell */
X	COORD	r_row;			/* row number */
X	COUNT	r_count;		/* number of cells in this row */
X};
X
X
X/*
X * Structure for each object.
X */
Xtypedef	struct	object	OBJECT;
Xstruct	object	{
X	OBJECT	*o_next;		/* next object */
X	ROW	*o_firstrow;		/* first row */
X	ROW	*o_lastrow;		/* last row */
X	COUNT	o_count;		/* number of live cells */
X	COUNT	o_born;			/* number of cells born */
X	COUNT	o_died;			/* number of cells died */
X	COORD	o_currow;		/* current row */
X	COORD	o_curcol;		/* current column */
X	COORD	o_minrow;		/* minimum row seen in window */
X	COORD	o_maxrow;		/* maximum row seen in window */
X	COORD	o_mincol;		/* minimum column seen in window */
X	COORD	o_maxcol;		/* maximum column seen in window */
X	COORD	o_prow;			/* currently pointed at row */
X	COORD	o_pcol;			/* currently pointed at column */
X	MARK	o_mark;			/* mark value for new cells */
X	COUNT	o_gen;			/* current generation */
X	SCALE	o_scale;		/* current scaling factor for view */
X	COUNT	o_frequency;		/* frequency of output for object */
X	BOOL	o_autoscale;		/* doing autoscaling */
X	BOOL	o_reserved;		/* reserved object */
X	char	o_name[MAXNAME+1];	/* name of object */
X};
X
X
X/*
X * The following structure holds all data necessary for processing
X * characters from some source.
X */
Xtypedef	struct	input	INPUT;
Xstruct	input	{
X	int	(*i_getchar)();	/* routine to read next character */
X	void	(*i_term)();	/* routine to terminate reading */
X	int	i_type;		/* type of input */
X
X				/* following for file reading only */
X	FILE	*i_file;	/* file handle */
X	OBJECT	*i_obj;		/* object to restore on reentry */
X	COORD	i_row;		/* row to restore */
X	COORD	i_col;		/* column to restore */
X	COORD	i_prow;		/* pointer row to restore */
X	COORD	i_pcol;		/* pointer column to restore */
X
X				/* following for loop or macro reading only */
X	UCHAR	*i_begptr;	/* beginning of command data */
X	UCHAR	*i_endptr;	/* end of command data */
X	UCHAR	*i_curptr;	/* current character */
X	COUNT	i_curval;	/* current iteration value */
X	COUNT	i_endval;	/* ending iteration value */
X	BOOL	i_first;	/* processing new chars */
X	char	i_macro;	/* macro being defined */
X};
X
X
X/*
X * Structure for command macros.
X */
Xtypedef	struct	{
X	UCHAR	*m_begptr;	/* beginning of data (NULL if none) */
X	UCHAR	*m_endptr;	/* end of data */
X} MACRO;
X
X
X/*
X * Structure to interface to various input/output devices.
X * This supports both normal terminals and graphics output.
X */
Xtypedef	struct {
X	int	(*open)();		/* open device */
X	void	(*close)();		/* close device */
X	void	(*update)();		/* make sure display is up to date */
X	void	(*refresh)();		/* redraw whole display from scratch */
X	BOOL	(*inputready)();	/* check whether input is ready */
X	int	(*readchar)();		/* read character with optional wait */
X	void	(*movecursor)();	/* move position of cursor */
X	void	(*showview)();		/* show view of life cells */
X	void	(*showstatus)();	/* show status line */
X	void	(*addstatus)();		/* add to status line */
X	void	(*showhelp)();		/* show help information */
X	void	(*addhelp)();		/* add information to help */
X	int	(*assign)();		/* assign button to macro */
X
X	COUNT	rows;			/* rows available for life cells */
X	COUNT	cols;			/* columns available for life cells */
X	COUNT	textrows;		/* rows of text available for help */
X	COUNT	textcols;		/* columns of text available for help */
X	SCALE	minscale;		/* minimum legal scale value */
X	SCALE	maxscale;		/* maximum legal scale value */
X	SCALE	defaultscale;		/* desirable default scale */
X} DEV;
X
X
X/*
X * Structure to hold a list of strings allocated from a common buffer.
X * This is used for collecting file names for listing.
X */
Xtypedef	struct	{
X	char	**argv;			/* pointer to list of pointers */
X	char	*buf;			/* pointer to string storage */
X	int	argc;			/* number of pointers */
X	int	maxargc;		/* maximum number of pointers */
X	int	used;			/* chars used in string storage */
X	int	maxused;		/* maximum chars in string storage */
X} LIST;
X
X
X/*
X * Extern definitions for non-initialized data.
X * These are defined externally in all modules, except in main.
X */
X#ifdef	DEFINE_GLOBALS
X#define	EXTERN
X#else
X#define	EXTERN	extern
X#endif
X
X
XEXTERN	DEV	*dev;		/* device being used */
XEXTERN	OBJECT	*objects;	/* list of active objects */
XEXTERN	OBJECT	*curobj;	/* currently selected object */
XEXTERN	OBJECT	*prevobj;	/* previously selected object */
XEXTERN	OBJECT	*mainobject;	/* the main object */
XEXTERN	OBJECT	*deleteobject;	/* object last deleted */
XEXTERN	OBJECT	*backupobject;	/* backup object */
XEXTERN	OBJECT	*tempobject;	/* temporary object */
XEXTERN	OBJECT	*freeobjects;	/* list of free objects */
XEXTERN	OBJECT	*newobjects;	/* top of new object allocation */
XEXTERN	OBJECT	*endobjects;	/* end of new objects */
X
XEXTERN	ROW	*freerows;	/* list of free row structures */
XEXTERN	ROW	*newrows;	/* top of new row allocation */
XEXTERN	ROW	*endrows;	/* end of new rows */
XEXTERN	ROW	*termrow;	/* terminus row */
XEXTERN	ROW	initrow;	/* row to initialize list */
X
XEXTERN	CELL	*freecells;	/* list of free cell structures */
XEXTERN	CELL	*newcells;	/* top of new cell allocation */
XEXTERN	CELL	*endcells;	/* end of new cells */
XEXTERN	CELL	*termcell;	/* terminus cell */
XEXTERN	CELL	initcell;	/* cell to initialize list */
X
XEXTERN	INPUT	*curinput;	/* current input being read from */
XEXTERN	COUNT	seecount;	/* number of cells we can see */
XEXTERN	COUNT	freqcount;	/* current count */
XEXTERN	COUNT	genleft;	/* generations left before stopping */
XEXTERN	COUNT	viewrows;	/* how many rows of cells can be seen */
XEXTERN	COUNT	viewcols;	/* how many columns of cells can be seen */
XEXTERN	BOOL	reserve;	/* reserved object names allowed */
XEXTERN	BOOL	dowait;		/* must wait for input */
XEXTERN	BOOL	interact;	/* still being interactive */
XEXTERN	BOOL	stop;		/* user wants to stop current action */
XEXTERN	BOOL	intjmpok;	/* ok to use interrupt jump buffer */
XEXTERN	SCALE	defaultscale;	/* default scale value for new objects */
XEXTERN	COUNT	defaultfrequency;	/* default frequency for new objects */
XEXTERN	int	update;		/* flags for what needs updating */
XEXTERN	int	mode;		/* mode of movement */
XEXTERN	char	gridchar;	/* character to use for grid */
XEXTERN	char	*errorstring;	/* error string to type */
XEXTERN	char	*userlib;	/* user's life library if any */
XEXTERN	jmp_buf	ttyjmp;		/* jump buffer for terminal input */
XEXTERN	jmp_buf	intjmp;		/* jump buffer for interrupts */
XEXTERN	INPUT	inputs[MAXINPUT];	/* list of input environments */
XEXTERN	MACRO	macros[26];	/* list of macros */
XEXTERN	char	stringbuf[STRINGSIZE];	/* characters for string value */
XEXTERN	char	rulestring[20];	/* string describing rules */
X
XEXTERN	char	vkill;		/* line kill character */
XEXTERN	char	verase;		/* erase character */
XEXTERN	char	vwerase;	/* word erase character */
XEXTERN	char	veol;		/* end of line character */
XEXTERN	char	veof;		/* EOF character */
XEXTERN	char	vlnext;		/* literal next character */
X
X
X/*
X * Externs for data which is initialized.
X */
Xextern	char	rules[];	/* life rules */
Xextern	DEV	ttydev;		/* tty device */
X
X#if	defined(X11)
Xextern	DEV	x11dev;		/* graphics device */
X#endif
X
X
X/*
X * Procedures
X */
Xextern	OBJECT	*allocobject();		/* allocate new object */
Xextern	OBJECT	*findobject();		/* find object with certain name */
Xextern	OBJECT	*getobject();		/* get new object with certain name */
Xextern	ROW	*allocrow();		/* allocate new row */
Xextern	ROW	*findrow();		/* find a row */
Xextern	ROW	*getrow();		/* get a new row */
Xextern	CELL	*alloccell();		/* allocate new cell */
Xextern	CELL	*findcell();		/* find a cell */
Xextern	BOOL	addcell();		/* add a cell */
Xextern	BOOL	delcell();		/* delete a cell */
Xextern	char	*readstring();		/* read input line from user */
Xextern	void	listvariables();	/* list variables */
Xextern	VALUE	getvariable();		/* get value of variable */
Xextern	VALUE	getvariable1();		/* get value of single char variable */
Xextern	void	setvariable();		/* set value of variable */
Xextern	void	setvariable1();		/* set a single char variable */
Xextern	void	scaninit();		/* initialize for reading chars */
Xextern	void	scanabort();		/* abort reading current command */
Xextern	void	scaneof();		/* indicate no more chars ready */
Xextern	void	scanreset();		/* reset scanning pointers */
Xextern	void	setobject();		/* set object as current one */
Xextern	void	zeroobject();		/* delete all cells in object */
Xextern	void	destroyobject();	/* destroy object */
Xextern	void	moveobject();		/* move object to another */
Xextern	void	addobject();		/* add one object to another */
Xextern	void	copyobject();		/* copy object to another */
Xextern	void	listobjects();		/* list all objects */
Xextern	BOOL	minmax();		/* find min and max of object */
Xextern	BOOL	searchobject();		/* scan for next part of object */
Xextern	BOOL	markobject();		/* mark cells of an object */
Xextern	void	setmarks();		/* mark whole object */
Xextern	BOOL	copymarks();		/* copy marks in an object */
Xextern	void	clearmarks();		/* clear marks in an object */
Xextern	COUNT	markregion();		/* mark cells in a region */
Xextern	BOOL	markminmax();		/* find range of marked cells */
Xextern	COUNT	countmarks();		/* count marked cells */
Xextern	void	movemarkedobject();	/* move marked cells to object */
Xextern	void	copymarkedobject();	/* copy marked cells to object */
Xextern	void	rotatemarkedobject();	/* rotate marked cells */
Xextern	void	fliprowmarkedobject();	/* flip marked cells around a row */
Xextern	void	flipcolmarkedobject();	/* flip marked cells around a column */
Xextern	void	error();		/* error routine */
Xextern	int	readchar();		/* read next char from input */
Xextern	BOOL	abbrev();		/* check for abbreviation */
Xextern	BOOL	ttyisinput();		/* see if input is terminal */
Xextern	BOOL	settty();		/* setup to get input from tty */
Xextern	BOOL	setfile();		/* setup to get input from file */
Xextern	BOOL	setloop();		/* setup for execution of loop */
Xextern	void	endloop();		/* end the range of loop */
Xextern	BOOL	setmacro();		/* setup to define a macro */
Xextern	int	readline();		/* read line of input into buffer */
Xextern	BOOL	showhelp();		/* add some text to the help display */
Xextern	void	endhelp();		/* terminate the help display */
Xextern	void	readrle();		/* read rle format object */
Xextern	void	readxlife();		/* read xlife format object */
Xextern	void	readpicture();		/* read picture of object */
Xextern	void	writeobject();		/* write object to a file */
Xextern	void	writemacros();		/* write macros to file */
Xextern	void	dogeneration();		/* calculate one generation */
Xextern	void	dolinecommand();	/* read and execute line command */
Xextern	void	docommand();		/* read and execute command */
Xextern	void	backup();		/* backup state of object */
Xextern	void	checkrun();		/* see if doing generations */
Xextern	void	getfiles();		/* collect file names in a directory */
Xextern	void	listfiles();		/* list collected file names */
Xextern	void	setscale();		/* set scale for display */
Xextern	SCALE	autoscale();		/* do autoscale of object */
Xextern	void	positionview();		/* position view of object */
Xextern	void	updateview();		/* show view of object */
Xextern	void	viewstatus();		/* show status of object */
Xextern	void	beep();			/* ring terminal bell */
X
Xextern	char	*malloc();		/* allocate memory */
Xextern	char	*realloc();		/* reallocate memory */
Xextern	char	*getenv();		/* get environment variable */
Xextern	char	*strchr();		/* find character in string */
X
X/* END CODE */
SHAR_EOF
$TOUCH -am 0316122993 life/life.h &&
chmod 0600 life/life.h ||
echo "restore of life/life.h failed"
set `wc -c life/life.h`;Wc_c=$1
if test "$Wc_c" != "15837"; then
	echo original size 15837, current size $Wc_c
fi
# ============= life/main.c ==============
echo "x - extracting life/main.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > life/main.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 * Program to play Conway's Game of LIFE on an infinite board.
X */
X
X#define	DEFINE_GLOBALS
X
X#include "life.h"
X
X
Xstatic	void	defaults();
Xstatic	void	options();
Xstatic	void	intint();
X
Xstatic	BOOL	scaleset;
Xstatic	BOOL	inited;
X
X
Xmain(argc, argv)
X	char	**argv;
X{
X	strcpy(rulestring, "3,23");
X	termcell = alloccell();
X	termcell->c_next = termcell;
X	termcell->c_col = INFINITY;
X	termrow = allocrow();
X	termrow->r_next = termrow;
X	termrow->r_firstcell = termcell;
X	termrow->r_row = INFINITY;
X	mode = M_MOVE;
X	gridchar = ' ';
X	defaultscale = 1;
X	defaultfrequency = 1;
X	freqcount = 1;
X	viewrows = 1;
X	viewcols = 1;
X
X	reserve = TRUE;			/* creating special objects */
X	deleteobject = getobject("..delete");
X	tempobject = getobject("..temp");
X	backupobject = getobject("..backup");
X	mainobject = getobject("main");
X	curobj = mainobject;
X	prevobj = mainobject;
X	reserve = FALSE;		/* no more special objects */
X
X	curinput = &inputs[-1];		/* initialize for tty input */
X	settty();
X	dev = &ttydev;
X
X	defaults();
X	options(argc - 1, argv + 1);
X
X	if ((*dev->open)(dev) < 0)
X		exit(1);
X
X	viewrows = dev->rows;
X	viewcols = dev->cols;
X	if (!scaleset)
X		defaultscale = dev->defaultscale;
X
X	setscale(deleteobject, defaultscale);	/* fix scale factors now */
X	setscale(tempobject, defaultscale);
X	setscale(backupobject, defaultscale);
X	setscale(mainobject, defaultscale);
X
X	signal(SIGINT, intint);
X	scaninit(readchar, ttyjmp);
X
X	inited = TRUE;
X
X	while (TRUE) {
X		docommand();
X		dogeneration(curobj);
X		updateview();
X	}
X}
X
X
X/*
X * Parse the optional LIFEOPTS environment variable to define defaults.
X */
Xstatic void
Xdefaults()
X{
X	char	*env;
X	char	*cp;
X	int	argc;
X	char	**argv;
X	char	*argtable[MAXARGS];
X
X	env = getenv(LIFEOPTS);
X	if (env == NULL)
X		return;
X
X	cp = malloc(strlen(env) + 1);
X	if (cp == NULL) {
X		fprintf(stderr, "No memory\n");
X		exit(1);
X	}
X	strcpy(cp, env);
X
X	argc = 0;
X	argv = argtable;
X
X	while (*cp) {
X		while (isblank(*cp))
X			cp++;
X		if (*cp == '\0')
X			break;
X		if (++argc > MAXARGS) { 
X			fprintf(stderr, "Too many arguments in LIFEOPTS\n");
X			exit(1);
X		} 
X		*argv++ = cp;
X		while (*cp && !isblank(*cp))
X			cp++;
X		if (*cp)
X			*cp++ = '\0';
X	}
X
X	options(argc, argtable);
X}
X
X
X/*
X * Handle command line options.  Note: The first argument argv[0] is NOT
X * the usual program name, so that must have been removed if necessary.
X */
Xstatic void
Xoptions(argc, argv)
X	char	**argv;
X{
X	char	*str;
X	char	*cp;
X	VALUE	arg;
X	BOOL	neg;
X
X	while (argc-- > 0) {
X		str = *argv++;
X
X		/*
X		 * If no option letter is used, then this means
X		 * read from the specified file.
X		 */
X		if (*str != '-') {
X			if (setfile(str)) {
X				perror(str);
X				exit(1);
X			}
X			continue;
X		}
X
X		/*
X		 * This is an option argument.  Parse each character of
X		 * it, so that multiple options can be given at once.
X		 */
X		str++;
X		while (*str) switch (*str++) {
X			case 't':			/* use terminal */
X				dev = &ttydev;
X				break;
X
X			case 'g':			/* use graphics */
X#if defined(X11)
X				dev = &x11dev;
X#else
X				fprintf(stderr, "Graphics is not available\n");
X				exit(1);
X#endif
X				break;
X
X			case 'l':			/* set library path */
X				if ((argc <= 0) || (**argv == '-')) {
X					fprintf(stderr, "Missing library path\n");
X					exit(1);
X				}
X				userlib = *argv++;
X				argc--;
X				break;
X
X			case 's':			/* set default scale */
X				if (argc <= 0) {
X					fprintf(stderr, "Missing scale\n");
X					exit(1);
X				}
X				cp = *argv++;
X				argc--;
X				neg = FALSE;
X				if (*cp == '-') {
X					neg = TRUE;
X					cp++;
X				}
X				arg = 0;
X				while (isdigit(*cp))
X					arg = arg * 10 + *cp++ - '0';
X				if (*cp || (arg == 0)) {
X					fprintf(stderr, "Bad scale factor\n");
X					exit(1);
X				}
X				if (neg)
X					arg = -arg;
X				defaultscale = arg;
X				scaleset = TRUE;
X				break;
X
X			default:
X				fprintf(stderr, "Unknown option -%c\n", str[-1]);
X				exit(1);
X		}
X	}
X}
X
X
X/*
X * Here on an interrupt character.  Remember to stop what we are doing soon.
X * We cannot usually just longjmp away since things may be in an inconsistent
X * state.  The longjmp is only allowed if we are sitting in a terminal read.
X */
Xstatic void
Xintint()
X{
X	signal(SIGINT, intint);
X	genleft = 0;
X	stop = TRUE;
X	update |= U_ALL;
X
X	if (intjmpok) {			/* do longjmp only if set up */
X		intjmpok = FALSE;
X		longjmp(intjmp, 1);
X	}
X}
X
X
X/*
X * Here on an error.  Close all but the top input level, cancel the
X * current command, beep, and set up to display the indicated message.
X * The message will remain until the next command is typed by the user.
X */
Xvoid
Xerror(str)
X	char	*str;		/* message to type */
X{
X	if (!inited) {
X		fprintf(stderr, "%s\n", str);
X		exit(1);
X	}
X	while (curinput > inputs)
X		(*curinput->i_term)(curinput);
X	errorstring = str;
X	update |= U_ALL;
X	stop = FALSE;
X	dowait = FALSE;
X	write(STDERR, "\007", 1);
X	scanabort();
X}
X
X/* END CODE */
SHAR_EOF
$TOUCH -am 0316122993 life/main.c &&
chmod 0644 life/main.c ||
echo "restore of life/main.c failed"
set `wc -c life/main.c`;Wc_c=$1
if test "$Wc_c" != "4926"; then
	echo original size 4926, current size $Wc_c
fi
# ============= life/mark.c ==============
echo "x - extracting life/mark.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > life/mark.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 * Structure to hold row and column pairs
X */
Xtypedef struct	{
X	COORD	l_row;
X	COORD	l_col;
X} LOC;
X
X
X/*
X * Row deltas to walk a cell
X */
Xstatic	COUNT	rowwalk[24] = {
X	-1, 0, 1, 1, 0, 0, -1, -1,
X	-1, 0, 0, 0, 1, 1, 1, 1,
X	0, 0, 0, 0, -1, -1, -1, -1
X};
X
X
X/*
X * Col deltas to walk a cell
X */
Xstatic	COUNT	colwalk[24] = {
X	0, 1, 0, 0, -1, -1, 0, 0,
X	0, 1, 1, 1, 0, 0, 0, 0,
X	-1, -1, -1, -1, 0, 0, 0, 0
X};
X
Xstatic	void	markloop();
X
X
X/*
X * Mark the object at a given location as specified.  Returns nonzero if
X * no object exists there.  An object for this purpose is considered as a
X * king-wise connected set of live cells, or a set of cells separated by
X * gaps of only one squares.
X */
XBOOL
Xmarkobject(obj, row, col, gap, mark)
X	OBJECT	*obj;
X	COORD	row;
X	COORD	col;
X	VALUE	gap;
X	MARK	mark;
X{
X	CELL	*cp;
X
X	cp = findcell(obj, row, col);
X	if (cp == NULL)
X		return TRUE;
X	cp->c_marks |= mark;
X	markloop(obj, row, col, gap, mark);
X	return FALSE;
X}
X
X
X/*
X * Recursive subroutine called from markobject.
X */
Xstatic void
Xmarkloop(obj, row, col, gap, mark)
X	OBJECT	*obj;		/* object begin marked */
X	COORD	row;		/* current row */
X	COORD	col;		/* current column */
X	VALUE	gap;		/* gap for marking (0 or 1) */
X	MARK	mark;		/* marking value */
X{
X	register CELL	*cp;	/* current cell */
X	register LOC	*rp;	/* pointer into list table */
X	int	i;		/* to iterate over directions */
X	int	steps;		/* number of steps */
X	LOC	rclist[24];	/* row and column list */
X
X	if (gap)
X		steps = 24;
X	else
X		steps = 8;
X
X	while (TRUE) {
X		if (stop)
X			return;
X
X		rp = rclist;
X
X		for (i = 0; i < steps; i++) {	/* find neighbors */
X			row += rowwalk[i];
X			col += colwalk[i];
X			cp = findcell(obj, row, col);
X			if (cp == NULL)
X				continue;
X			if (cp->c_marks & mark)
X				continue;
X			cp->c_marks |= mark;
X			rp->l_row = row;
X			rp->l_col = col;
X			rp++;
X		}
X
X		if (--rp != rclist) {		/* recurse if more than one */
X			for (; rp >= rclist; rp--) {
X				markloop(obj, rp->l_row, rp->l_col, gap, mark);
X			}
X			return;
X		}
X
X		row = rp->l_row;		/* else follow single cell */
X		col = rp->l_col;
X	}
X}
X
X
X/*
X * Mark a whole object as specified.
X */
Xvoid
Xsetmarks(obj, mark)
X	OBJECT	*obj;
X	MARK	mark;
X{
X	register ROW	*rp;
X	register CELL	*cp;
X
X	mark |= MARK_ANY;
X	for (rp = obj->o_firstrow; rp != termrow; rp = rp->r_next) {
X		for (cp = rp->r_firstcell; cp != termcell; cp = cp->c_next) {
X			cp->c_marks |= mark;
X		}
X	}
X}
X
X
X/*
X * Copy the marks from one type to another for an object.
X * Returns nonzero if there were no cells with the given mark.
X */
XBOOL
Xcopymarks(obj, srcmark, destmark)
X	OBJECT	*obj;
X	MARK	srcmark;
X	MARK	destmark;
X{
X	register ROW	*rp;
X	register CELL	*cp;
X	BOOL		failed;
X
X	failed = TRUE;
X	for (rp = obj->o_firstrow; rp != termrow; rp = rp->r_next) {
X		for (cp = rp->r_firstcell; cp != termcell; cp = cp->c_next) {
X			if ((cp->c_marks & srcmark) == 0)
X				continue;
X			cp->c_marks |= destmark;
X			failed = FALSE;
X		}
X	}
X	return failed;
X}
X
X
X/*
X * Clear marks for a whole object as specified.
X */
Xvoid
Xclearmarks(obj, mark)
X	OBJECT	*obj;
X	MARK	mark;
X{
X	register ROW	*rp;
X	register CELL	*cp;
X
X	mark = ~mark;
X	mark |= MARK_ANY;
X	for (rp = obj->o_firstrow; rp != termrow; rp = rp->r_next) {
X		for (cp = rp->r_firstcell; cp != termcell; cp = cp->c_next) {
X			cp->c_marks &= mark;
X		}
X	}
X}
X
X
X/*
X * Mark the cells in a specified rectangular region as desired.
X * Returns the number of cells which were marked.
X */
XCOUNT
Xmarkregion(obj, mark, minrow, maxrow, mincol, maxcol)
X	OBJECT	*obj;
X	MARK	mark;
X	COORD	minrow;
X	COORD	maxrow;
X	COORD	mincol;
X	COORD	maxcol;
X{
X	register ROW	*rp;
X	register CELL	*cp;
X	COUNT		count;
X
X	count = 0;
X	for (rp = obj->o_firstrow; rp != termrow; rp = rp->r_next) {
X		if (rp->r_row < minrow)
X			continue;
X		if (rp->r_row > maxrow)
X			break;
X		for (cp = rp->r_firstcell; cp != termcell; cp = cp->c_next) {
X			if (cp->c_col < mincol)
X				continue;
X			if (cp->c_col > maxcol)
X				break;
X			cp->c_marks |= mark;
X			count++;
X		}
X	}
X	return count;
X}
X
X
X/*
X * Find the range of all marked cells for an object.  Returns nonzero if
X * no cells were marked.
X */
XBOOL
Xmarkminmax(obj, mark, minrow, maxrow, mincol, maxcol)
X	OBJECT	*obj;
X	MARK	mark;
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		minr;
X	COORD		maxr;
X	COORD		minc;
X	COORD		maxc;
X
X	minr = INFINITY;
X	maxr = -INFINITY;
X	minc = INFINITY;
X	maxc = -INFINITY;
X
X	for (rp = obj->o_firstrow; rp != termrow; rp = rp->r_next) {
X		row = rp->r_row;
X
X		for (cp = rp->r_firstcell; cp != termcell; cp = cp->c_next) {
X			if ((cp->c_marks & mark) == 0)
X				continue;
X			if (row < minr)
X				minr = row;
X			if (row > maxr)
X				maxr = row;
X			if (cp->c_col < minc)
X				minc = cp->c_col;
X			if (cp->c_col > maxc)
X				maxc = cp->c_col;
X		}
X	}
X
X	if (minr > maxr)
X		return TRUE;
X
X	*minrow = minr;
X	*maxrow = maxr;
X	*mincol = minc;
X	*maxcol = maxc;
X
X	return FALSE;
X}
X
X
X/*
X * Count the number of marked cells in an object
X */
XCOUNT
Xcountmarks(obj, mark)
X	OBJECT	*obj;
X	MARK	mark;
X{
X	register ROW	*rp;
X	register CELL	*cp;
X	COUNT		count;
X
X	count = 0;
X	for (rp = obj->o_firstrow; rp != termrow; rp = rp->r_next) {
X		for (cp = rp->r_firstcell; cp != termcell; cp = cp->c_next) {
X			if (cp->c_marks & mark)
X				count++;
X		}
X	}
X	return count;
X}
X
X
X/*
X * Move marked cells to another object.  If the destination object is NULL
X * the cells are just deleted.  The previous cells of the destination object
X * are deleted.
X */
Xvoid
Xmovemarkedobject(sobj, dobj, mark)
X	OBJECT	*sobj;
X	OBJECT	*dobj;
X	MARK	mark;
X{
X	ROW		*rp;
X	register CELL	*cp;		/* current cell pointer */
X	register CELL	*pcp;		/* previous cell pointer */
X	register CELL	*ncp;		/* next cell pointer */
X
X	if (sobj == dobj)
X		error("Moving object to itself");
X
X	if (dobj) {
X		zeroobject(dobj);
X		dobj->o_currow = sobj->o_currow;
X		dobj->o_curcol = sobj->o_curcol;
X	}
X
X	for (rp = sobj->o_firstrow; rp != termrow; rp = rp->r_next) {
X		pcp = NULL;
X		cp = rp->r_firstcell;
X		while (cp != termcell) {
X			if ((cp->c_marks & mark) == 0) {
X				pcp = cp;
X				cp = cp->c_next;
X				continue;
X			}
X			if (dobj)
X				addcell(dobj, rp->r_row, cp->c_col);
X			ncp = cp->c_next;
X			if (pcp == NULL)
X				rp->r_firstcell = ncp;
X			else
X				pcp->c_next = ncp;
X			if (ncp == termcell)
X				rp->r_lastcell = pcp;
X			cp->c_next = freecells;
X			freecells = cp;
X			cp = ncp;
X			rp->r_count--;
X			sobj->o_count--;
X		}
X	}
X}
X
X
X/*
X * Copy marked cells to another object. The previous cells of the destination
X * object are deleted.  The source object is unaffected.
X */
Xvoid
Xcopymarkedobject(sobj, dobj, mark)
X	OBJECT	*sobj;
X	OBJECT	*dobj;
X	MARK	mark;
X{
X	register ROW	*rp;
X	register CELL	*cp;
X
X	if (sobj == dobj)
X		error("Copying object to itself");
X
X	zeroobject(dobj);
X
X	dobj->o_currow = sobj->o_currow;
X	dobj->o_curcol = sobj->o_curcol;
X
X	for (rp = sobj->o_firstrow; rp != termrow; rp = rp->r_next) {
X		for (cp = rp->r_firstcell; cp != termcell; cp = cp->c_next) {
X			if ((cp->c_marks & mark) == 0)
X				continue;
X			addcell(dobj, rp->r_row, cp->c_col);
X		}
X	}
X}
X
X
X/*
X * Rotate the marked cells in the given object around the current cursor
X * location.  This deletes the marked cells, and reinserts them after
X * their position has been rotated by 90 degrees clockwise.
X */
Xvoid
Xrotatemarkedobject(obj, mark)
X	OBJECT	*obj;
X	MARK	mark;
X{
X	register ROW	*rp;
X	register CELL	*cp;
X	COORD		row;
X	COORD		col;
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 = rp->r_row - obj->o_currow;
X		for (cp = rp->r_firstcell; cp != termcell; cp = cp->c_next) {
X			col = cp->c_col - obj->o_curcol;
X			addcell(obj, obj->o_currow + col, obj->o_curcol - row);
X		}
X	}
X}
X
X
X/*
X * Flip the marked cells in the given object around the column of the current
X * cursor location.  This deletes the marked cells, and reinserts them after
X * their position has been flipped around the vertical axis.
X */
Xvoid
Xflipcolmarkedobject(obj, mark)
X	OBJECT	*obj;
X	MARK	mark;
X{
X	register ROW	*rp;
X	register CELL	*cp;
X	COORD		row;
X	COORD		col;
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 = rp->r_row;
X		for (cp = rp->r_firstcell; cp != termcell; cp = cp->c_next) {
X			col = cp->c_col - obj->o_curcol;
X			addcell(obj, row, obj->o_curcol - col);
X		}
X	}
X}
X
X
X/*
X * Flip the marked cells in the given object around the row of the current
X * cursor location.  This deletes the marked cells, and reinserts them after
SHAR_EOF
echo "End of  part 16"
echo "File life/mark.c is continued in part 17"
echo "17" > shar3_seq_.tmp
exit 0


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