[comp.sources.wanted] Core wars 1

sbarr@hawk.ulowell.edu (bot man) (05/31/90)

#!/bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #!/bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#	Makefile
#	READ_ME
#	bdwarf.rc
#	cw.6
#	cw.h
#	dwarf.rc
#	fibo.rc
#	gemini.rc
#	getopt.c
#	imp.rc
#	mars.c
#	movmem.c
#	msg.c
#	print.c
#	random.rc
#	rcasm.l
#	rcasm.l.old
#	rcasm.y
#	scheduler.c
#	stomper.rc
#	sum.c
#	unrc.c
#	vdisplay.c
#	vstatus.c
# This archive created: Tue Mar  3 18:14:02 1987
export PATH; PATH=/bin:$PATH
if test -f 'Makefile'
then
	echo shar: over-writing existing file "'Makefile'"
fi
cat << \SHAR_EOF > 'Makefile'
#
#	Makefile for Corewar system
#
#static	char	rcsid[] = "$Header: Makefile,v 7.0 85/12/28 14:35:38 ccohesh Dist $";
#
#	[cw by Peter Costantinidis, Jr. @ University of California at Davis]
#
#
#	If you are running under SysV, I am told that you would want to
#	uncomment the following commented lines.
#
#	.SUFFIXES: .rc
#	.rc:
#		rcasm $< $@

HDRS	=	Makefile cw.h
YSRC	=	rcasm.y
LSRC	=	rcasm.l
SRCS	=	getopt.c mars.c movmem.c msg.c print.c scheduler.c sum.c\
		vdisplay.c vstatus.c
OBJS	=	getopt.o mars.o movmem.o msg.o print.o scheduler.o sum.o\
		vdisplay.o vstatus.o
PROGS	=	bdwarf.rc dwarf.rc fibo.rc gemini.rc imp.rc\
		random.rc stomper.rc
#
# libs
#
CWLIB	=	cw.a
CRLIB	=	-lcurses
TERMLIB	=	-ltermlib
ALLLIBS	=	$(CWLIB) $(CRLIB) $(TERMLIB)

#
# It has been suggested that FLAGS should include "-DSYS5" when running
# under SYS5
#
FLAGS	=	#-DDEBUG
CFLAGS	=	-O $(FLAGS)
LDFLAGS =	-o $@
LINTARGS=	-ahxc $(DEFS) -DLINT
SHAR	=	shar
SHAROUT	=	cw.shar
ALLSRCS	=	$(HDRS) $(SRCS) unrc.c cw.6 $(YSRC) $(LSRC)
ALLEXES	=	rcasm unrc mars
ALL	=	READ_ME $(ALLSRCS) $(CWDOC)
CI	=	ci -u

NAME =		mars

ALLDEMOS=	imp dwarf gemini stomper

demo:		mars rcasm
#
#	You may want to comment out the "rcasm" lines if
#	running SysV.
#
		rcasm imp.rc imp
		rcasm dwarf.rc dwarf
		rcasm gemini.rc gemini
		rcasm stomper.rc stomper
		mars -p imp dwarf gemini stomper

install:	mars rcasm unrc cw.nr

cw.nr:		cw.6
		tbl cw.6 | nroff -man | col > cw.nr

mars:		$(CWLIB)
		cc $(LDFLAGS) $(ALLLIBS)

#
# RCS stuff
#
ci:		$(ALLSRCS)
		-$(CI) $?
		@touch ci
coall:
		co -l $(ALLSRCS)
update:
		ci -sDist -u -f$(VERS) $(ALLSRCS)
		@touch ci

all:		$(ALLEXES)

$(CWLIB):	$(OBJS)
		@ar rv $@ $?; ranlib $@

$(OBJS):	$(HDRS)

rcasm:		rcasm.o $(CWLIB) rcasm.h
		cc $(LDFLAGS) rcasm.o $(CWLIB) -ll

rcasm.o:	rcasm.c rcasm.h $(HDRS)

rcasm.h:	$(LSRC) $(HDRS)
		$(LEX) $(LFLAGS) $(LSRC)
		@mv lex.yy.c rcasm.h

rcasm.c:	$(YSRC) $(HDRS)
		$(YACC) $(YFLAGS) $(YSRC)
		@mv y.tab.c rcasm.c

unrc:		unrc.o $(CWLIB)
		cc -O $(LDFLAGS) unrc.o $(CWLIB)

unrc.o:		$(HDRS)

lint:
		lint $(LINTARGS) $(SRCS)

print:
		lpr -Pc -p Makefile $(ALLSRC)

tags:		$(HDRS) $(SRCS)
		ctags -u $?
		sort tags -o tags

wc:
		wc $(ALLSRCS)

export:
		$(SHAR) $(ALL) $(PROGS) > $(SHAROUT)

clean:
		rm -f $(OBJS) rcasm.c rcasm.h $(ALLDEMOS) $(ALLEXES)
SHAR_EOF
if test -f 'READ_ME'
then
	echo shar: over-writing existing file "'READ_ME'"
fi
cat << \SHAR_EOF > 'READ_ME'
This is the second source distribution of the Core Wars.

Some of the bugs that have been fixed:

	1. unrc.c has been modified to recognize the MUL, DIV
	   and RND instructions.
	2. cw.6 had some problems with the tables.  These have
	   been solved.
	3. The RND instruction no longer causes a job to halt.
	4. A bug in the lexical analyzer where the toggle variable
	   "toggle" wasn't being toggled has been corrected.

For further reading on the origins and purpose of this system,
please see the the "SEE ALSO" section of the documentation.

Please send all new bug reports to the author.
-------------------------------------------------------------------------------
Wed Dec 11 18:26:00 PST 1985

This is the first source distribution of the game of Core Wars.
This game has been tested on BSD4.2 UNIX.  It should run under
any UNIX system that has curses, lex and yacc and virtual memory
and whose compiler allows bitfields in structures.
If your system does not have virtual memory but does have separate
I and D space, you should insert the appropriate loader options in
the Makefile.  You may also have to decrease "MAX_MEM" and make the
corresponding changes to the bitfield widths.

I think that it would be great if we could have world wide competition
playing this game.  Perhaps people could post their best redcode code
to net.sources.games.  Perhaps an unbeatable program might evolve.

			Peter Costantinidis, Jr.
			...!ucbvax!ucdavis!deneb!ccohesh001
SHAR_EOF
if test -f 'bdwarf.rc'
then
	echo shar: over-writing existing file "'bdwarf.rc'"
fi
cat << \SHAR_EOF > 'bdwarf.rc'
/ bdwarf.rc	- backwards moving dwarf

$LOOP:	SUB	#8	 $WHERE		/ won't kill eachother
	MOV	#-3	@$WHERE
	JMP		 $LOOP
$WHERE:	DAT		 -8		/ change this to a 4 and dwarf's
SHAR_EOF
if test -f 'cw.6'
then
	echo shar: over-writing existing file "'cw.6'"
fi
cat << \SHAR_EOF > 'cw.6'
.\"	Documentation for Corewars system
.\"
.\"	static	char	rcsid[] = "$Header: cw.6,v 7.2 86/01/06 21:28:21 ccohesh Exp $";
.\"
.TH CW UCD "2 December 1985"
.SH NAME
mars, rcasm, unrc \- Core Wars simulation system
.SH SYNOPSIS
.B mars
[
.B \-dilpv
] [
.B \-rn
] [
.B \-sn
] [
.B \-cn
] file file ...
.br
.B rcasm
file [ofile]
.br
.B unrc
file
.SH OPTIONS
.TP
.B \-d
Do not print the status window if in visual display mode.
.TP
.B \-i
Print current instruction.  This turns on the
.B \-p
and the
.B \-v
options.
.TP
.B \-l
Print job size and load location during startup.
.TP
.B \-p
Print the current cycle number.
.TP
.B \-rn
Set the seed for the random number generator to
.B n.
If
.B n
is zero, then
.B mars
will create its own seed and print it.
.TP
.B \-sn
Set the minimum amount of memory initially separating jobs to
.B n
memory pages.  A memory page is 16 words.  This value must be less
than 511.  The default separation value is 8 pages.
.TP
.B \-cn
Set the maximum number of execution cycles to
.B n.
The default value is 1024.
.TP
.B \-v
Do not run in visual display mode.  This is useful to quickly
determine the outcome.  Also, the instruction display will not
work in visual display mode.
.TP
.SH DESCRIPTION
.I Mars
(an acronym for Memory Array Redcode Simulator) executes battle
programs created by
.I rcasm.
The battle programs are entered into the battlefield at randomly
chosen positions and executed in a simple version of time-sharing.
Execution continues until all but one program is left running or
the instruction cycle limit is reached.
Programs are halted when they attempt to execute an invalid instruction 
or an instruction with an illegal addressing mode.
When
.I mars
terminates it prints a summary of results of the battle indicating
how long each job ran and the reason (if any) for a job's termination.
.LP
By default
.I mars
will display the battle using a box of 512 periods ('.'), each representing
one memory page of 16 memory locations.  The position of each program's
program counter is marked by a capital letter and the areas affected by the
program executing the "MOV" instruction by the corresponding lowercase
letter.  An optional status window is displayed to the right of this box.
Each line in the window contains information for one program.
This information includes the letter representing the program, the `name'
of the program (via the command line argument) and the program's current
status.  If the
.B \-p
option is specified on the command line the bottom line of the status window
will indicate the number of cycles elapsed and the number of programs
still operational.
.LP
.I Rcasm
assembles the named
.I redcode
assembly language
.I file.
The output of the assembly is left on the file
.I ofile;
if that is ommitted,
.I rc.out
is used.
.LP
.I Unrc
dis-assembles the named
.I redcode
object file writing the
.I redcode
assembly instructions to the standard output.
However, be aware that since
.I rcasm
does not include comments in the object files that it creates, the output from
.I unrc
will not contain any comments that once might have been in the original
source core.
.SH DETAILS
The size of the memory into which the programs are loaded is 8192 words.
This is divided into 512 16 word pages.  Jobs are loaded on page
boundaries with the default minimum separation between programs being
8 pages.
Since jobs are loaded on page boundaries they can work in teams
(i.e. employ strategies such that if two jobs of the same type are
loaded they will only kill jobs of a different type).
This is obvious in the
.B dwarf
program.  If one
.B dwarf
job can not kill itself it will not be able to kill other
.B dwarfs.
This isn't necessarily true for programs that use the
.B RND
instruction.
.LP
None of the programs know where the other ones are, they do not
even know how many other programs exist.
Because a program can never refer to an absolute address, some addressing
modes for some operands do not make sense.
All memory addressing is relative to the current instruction.
Since memory is `circular', addressing location 8192 would be the same as
addressing location 0.
.LP
Since execution of a program starts on its first instruction, the user
is cautioned to not have any
.B DAT
instructions at this point.  If a user prefers to place all his
.B DAT
instructions at the beginning of his program, it is suggested that he
precede them with a
.B JMP
instruction to the appropriate address.
.SH REDCODE
.TS
center tab(:);
c s s s
c c s c.
Redcode Instruction Set
=
Mnemonic:Arguments:Action
Symbol::
_
.T&
lw(0.35i) cw(0.25i) cw(0.25i) lw(4i).
DAT::B:T{
Initialize location to value B.
T}
MOV:A:B:T{
Move A into location B.
T}
ADD:A:B:T{
Add operand A to contents of location B and store result in location B.
T}
SUB:A:B:T{
Subtract operand A from contents of location B and store result in location B.
T}
JMP::B:T{
Jump to location B.
T}
JMZ:A:B:T{
If operand A is 0, jump to location B; otherwise continue with next instruction.
T}
DJZ:A:B:T{
Decrement contants of location A by 1.  If location A now holds 0,
jump to location B; otherwise continue with next instruction.
T}
CMP:A:B:T{
Compare operand A with operand B.
If they are not equal, skip next instruction; otherwise continue with
next instruction.
T}
MUL:A:B:T{
Multiply operand B by operand A and store result in location B.
T}
DIV:A:B:T{
Divide operand B by operand A and store result in location B.
T}
RND::B:T{
Chose a random integer between 0 and the maximum memory size and store
it in location B.
T}
.TE
.sp 2
.TS
center tab(:);
c s s
c c c.
Redcode Addressing Modes
=
Mnemonic:Name:Meaning
Symbol::
_
.T&
c l lw(4.0i).
#:Immediate:T{
The number following this symbol is the operand.
T}
<none>:Relative:T{
The number specifies an offset from the current instruction.
Mars adds the offset to the address of the current instruction;
the number stored at the location reached in this was is the operand.
T}
@:Indirect:T{
The number following this symbol specifies an offset from the current
instruction to a location where the relative address of the operand is found.
Mars adds the offset to the address of the current instruction and retrieves
the number stored at the specified location; this number is the interpreted
as an offset from its own address.  The number found at this second location
is the operand.
T}
.TE
.LP
Labels are another feature of this assembly language.
Labels consist of alphanumerical characters witha maximum length of
six characters starting with a dollar sign ('$').
To declare a label, simply place the label with a colon (':') appended to it
at the beginning of an instruction.
Labels can be used anywhere where you would normally specify an integer address.
.SH EXAMPLES
.ta 1.5i 2.0i 2.25i
	JMP		$START
.br
$ADDR:	DAT		0
.br
$START:	ADD	#8	$ADDR
.br
	MOV	#0	@$ADDR
.br
	JMP		$START
.LP
This is a simple program, usually refered to as
.B Dwarf.
It works its way through memory bombarding every eighth memory
address with a zero.
.LP
An even simpler program,
.B imp,
simply copies itself throughout memory, one memory location at a time.
.br
$ME:	MOV	$ME	$AFTERME
$AFTERME:	DAT	0
.SH FILES
.ta 1.5i
rc.out	default resultant object file
.SH "SEE ALSO"
D. G. Jones and A. K. Dewdney, "CORE WAR GUIDELINES."
.br
A. K. Dewdney,
"Computer Recreations,"
.I Scientific American,
May, 1984, pp. 14-23
.SH DIAGNOSTICS
.B Rcasm
will complain if it discovers syntax errors in the input file.
.B Unrc
will complain if the input file contains invalid redcode instructions.
.B Mars
will complain about argument syntax errors and files that it cannot open.
.SH AUTHOR
Peter Costantinidis, Jr., University of California, Davis
.SH BUGS
None known at this time.  When they are discovered the author would
appreciate notification.
SHAR_EOF
if test -f 'cw.h'
then
	echo shar: over-writing existing file "'cw.h'"
fi
cat << \SHAR_EOF > 'cw.h'
/*
** cw.h	- misc. constants and macros used throughout corewar system
**
**	[cw by Peter Costantinidis, Jr. @ University of California at Davis]
*/

/*
**
static	char	rcsid[] = "$Header: cw.h,v 7.0 85/12/28 14:35:45 ccohesh Dist $";
**
*/
#include <sys/types.h>		/* necessary for void */

#ifdef	BSD42|BSD43
#	define	SETJMP	_setjmp
#	define	LONGJMP	_longjmp
#else
#	define	SETJMP	setjmp
#	define	LONGJMP	longjmp
#endif

/*
** curses conflicts
*/
#ifndef	WINDOW
#	define	TRUE	1
#	define	FALSE	0
#	undef	reg
#endif

#ifdef	DEBUG
#	define	reg
#else
#	define	reg	register
#endif

#ifndef	CTRL
#	define	CTRL(c)	('c'&037)
#endif
#ifndef	CINTR
#	define	CINTR	CTRL(?)
#endif
#define	min(a,b)	((a) < (b) ? (a) : (b))
#define	max(a,b)	((a) > (b) ? (a) : (b))
#define	abs(a)		((a) < 0 ? -(a) : (a))

/*
** Visual display related constants
*/
#define	MIN_LINES	24	/* minimum lines allowed in display */
#define	MIN_COLS	80	/* minimum columns allowed in display */

/*
** memory window
*/
#define	MLINES		16	/* # lines in memwin */
#define	MCOLS		(MAX_MEM/(MLINES*NUMMEM))/* # columns in memwin */
#define	MYBEGIN		1	/* y offset in stdscr of memwin */
#define	MXBEGIN		1	/* x offset in stdscr of memwin */

/*
** message window
*/
#define	MSGLINES	(MIN_LINES-MLINES-2)/* lines in status window */
#define	MSGCOLS		(MXBEGIN+MCOLS)/* columns in status window */
#define	MSGYBEGIN	(MYBEGIN+MLINES+1)/* y offset in stdscr of status win */
#define	MSGXBEGIN	0

/*
** status window
*/
#define	SLINES		MIN_LINES
#define	SCOLS		(MIN_COLS-MCOLS-2)
#define	SYBEGIN		0
#define	SXBEGIN		(MXBEGIN+MCOLS+1)

#define	NUMMEM		PAGESIZE/* # memwords per character in memwin */
#define	HORTBORDER	'-'	/* horizontal border char for memwin box */
#define	VERTBORDER	'|'	/* vertical border char for memwin box */

/*
** misc. characters in memory window
*/
#define	MEMPTY	'.'	/* nothing of note about memsect */
#define	MSHARE	'-'	/* more than one job writing */
#define	MHIT	'+'	/* hit near a PC */
#define	MFULL	'*'	/* >=10 PC's in memsect */

/*
** output controls
*/
#define	SIZE_START	0x0001L		/* print size and start of job */
#define	PASSNUM		0x0002L		/* print current cycle */
#define	PASSFREQ	10		/* print every n cycles */
#define	PINST		0x0004L		/* print current instruction */
#define	VISUAL		0x0008L		/* visual display */
#define	STATUS		0x0010L		/* status window for v.d. */
#define	DEF_CTRLS	(VISUAL|STATUS|PINST)

#define	ON(x)		(octrl&(x))
#define	TOGGLE(x)	octrl=(octrl&x)?(octrl&~x):(octrl|x)

#define	HALTED(j)	(j->pdied)
#define	PC	_pc

#define	uns		unsigned
#define	unss		unsigned short
#define	when		break;case
#define	otherwise	break;default

#define	RC_OUT		"rc.out"

/*
** memory constraints and other limits
*/
#define	PAGESIZE	16	/* jobs placed on page boundaries */
#define	MAX_PAGE	512	/* max. pages in mem. */
#define	MAX_MEM		(PAGESIZE*MAX_PAGE)/* size of mem. */
#define	JMAX_LEN	512	/* max. len for job */
#define	PAGESEP		8	/* min. job separation in pages */
#define	JOB_WIDTH	(JMAX_LEN+ (PAGESEP*PAGESIZE))
#define	CYCLES		1024	/* max. execution cycle limit */
#define	MAX_USERS	(SLINES-1)/* max. # jobs (some might not fit...) */
#define	MAX_LABELS	128	/* maximum number of labels allowed */
#define	LABEL_LEN	6	/* max. len of labels */

/*
** field bit-widths needed
*/
#define	OP_BITS		4
#define	MODE_BITS	2
#define	ADDR_BITS	13	/* # of bits needed to address all memory */

/*
** Redcode instruction set
*/
#define	DAT	0	/* initialize location to value B */
#define	MOV	1	/* move A into location B */
#define	ADD	2	/* add A to contents of B, results in B */
#define	SUB	3	/* subtract A from contents of B, results in B */
#define	JMP	4	/* jump to B */
#define	JMZ	5	/* if A == 0 then jump to B, otherwise continue */
#define	DJZ	6	/* --A; if A == 0 then jump to B */
#define	CMP	7	/* compare A with B; if != then skip next instruction */
#define	MUL	8	/* multiply B by A, results in B */
#define	DIV	9	/* divide B by A, results in B */
#define	RND	10	/* random number between 0 and MAX_MEM, results in B */

/*
** Addressing modes
*/
#define	IMM	0	/* number is operand */
#define	REL	1	/* number specifies offset from current instruction */
#define	IND	2	/* number specifies offset from current instruction */
			/* to location where relative address of operand is */
			/* found */

/*
** character and string constants representing the various modes
** and instructions
*/
#define	CIMM	'#'
#define	CREL	' '
#define	CIND	'@'
#define	SDAT	"DAT"
#define	SMOV	"MOV"
#define	SADD	"ADD"
#define	SSUB	"SUB"
#define	SJMP	"JMP"
#define	SJMZ	"JMZ"
#define	SDJZ	"DJZ"
#define	SCMP	"CMP"
#define SMUL	"MUL"
#define	SDIV	"DIV"
#define	SRND	"RND"

/*
** termination reasons for mars/processes
*/
#define	EALIVE		0	/* currently active */
#define	ECYCLE		1	/* max cycle limit exceeded */
#define	EWIN		2	/* normal termination (a winner) */
#define	EILLINST	3	/* illegal instruction */
#define	EBADMODE	4	/* invalid addressing mode */
#define	EINTERRUPT	5	/* process interrupted */

typedef	struct
{
	uns	op:OP_BITS,	/* opcode */
		moda:MODE_BITS,	/* mod argument A */
		modb:MODE_BITS,	/* mod argument B */
		arga:ADDR_BITS,	/* argument A */
		argb:ADDR_BITS;	/* argument B */
} memword;
#define	val	argb

typedef	struct
{
	char	*pname;		/* name of player (input file name) */
	int	pid;		/* process number */
	int	pc;		/* current program counter */
	int	psize;		/* # of instruction in program */
	int	picnt;		/* # of instructions executed at job halt */
	int	pdied;		/* non-zero if dead, if dead then reason */
	memword	*plstmem;	/* # of last memword modified */
} process;

extern	char	*argv0;
extern	int	jobcnt, jobsleft, min_sep;
extern	int	cycle, max_cyc;
extern	long	octrl;
extern	memword	memory[];

extern	char	*strcpy();

extern	char	*diedstr(), *punctrl();
extern	void	usage(), msg(), msgfini(), movmem(), statfini(),
		vfini(), vstatus(), vstajob();
extern	int	printit(), sum(), msginit(), statinit(), vupdate();
SHAR_EOF
if test -f 'dwarf.rc'
then
	echo shar: over-writing existing file "'dwarf.rc'"
fi
cat << \SHAR_EOF > 'dwarf.rc'
/ dwarf.rc

$BEGIN:	ADD	#8	 $WHERE		/ won't kill eachother
	MOV	#-3	@$WHERE
	JMP		 $BEGIN
$WHERE:	DAT		 -1		/ change this to a 0 and dwarf's
					/ will not kill eachother
SHAR_EOF
if test -f 'fibo.rc'
then
	echo shar: over-writing existing file "'fibo.rc'"
fi
cat << \SHAR_EOF > 'fibo.rc'
/ fibo.rc	-
/
/	f(0) = 0
/	f(1) = 1
/	f(n) = f(n-1) + f(n-2)
/

$START:	jmz	$TOG	$L2
$HERE:	mov	#$HERE	$TOG	/ toggle tog
	add	$1	$2
	mov	0	@$2
	jmp	$START
$L2:	mov	1	$TOG
	add	$2	$1
	mov	0	@$1
	jmp	$START
$TOG:	dat		0
$1:	dat		1
$2:	dat		1
SHAR_EOF
if test -f 'gemini.rc'
then
	echo shar: over-writing existing file "'gemini.rc'"
fi
cat << \SHAR_EOF > 'gemini.rc'
/ gemini.rc	- copy program and jump to new copy

	jmp		$START		/jump to start of program
$SRC:	dat		0		/pointer to source address
$DST:	dat		99		/pointer to dest. address
$START:	mov	@$SRC	@$DST		/copy source to dest.
	cmp	$SRC	#11		/if all 10 lines have been copied...
	jmp	$DONE			/...then leave the loop
	add	#1	$SRC		/otherwise, increment the source address
	add	#1	$DST		/...and the dest. address
	jmp 	$START			/...and return to the loop
$DONE:	mov	#99	93		/restore the starting dest. address
	jmp	93			/jump to the new copy
SHAR_EOF
if test -f 'getopt.c'
then
	echo shar: over-writing existing file "'getopt.c'"
fi
cat << \SHAR_EOF > 'getopt.c'
/*
** getopt.c	- argument parser
**
static	char	rcsid[] = "$HEADER$";
**
*/

#include "cw.h"

/*LINTLIBRARY*/
#ifndef	EOF
#	define	EOF	-1
#endif
#ifndef	SYSV
#	define	strchr	index
#endif
#define ERR(s, c)	if(opterr){\
		extern int strlen(), write();\
		char errbuf[2];\
		errbuf[0] = c; errbuf[1] = '\n';\
		(void) write(2, argv[0], (unsigned)strlen(argv[0]));\
		(void) write(2, s, (unsigned)strlen(s));\
		(void) write(2, errbuf, 2);}

extern	int	strcmp();
extern	char	*strchr();

static	int	opterr = 1;
int	optind = 1;
static	int	optopt;
char	*optarg;

int	getopt (argc, argv, opts)
int	argc;
char	**argv, *opts;
{
	static	int	sp = 1;
	reg	int	c;
	reg	char	*cp;

	if (sp == 1)
	{
		if (optind >= argc ||
		    argv[optind][0] != '-' ||
		    !argv[optind][1])
			return(EOF);
		if (!strcmp(argv[optind], "--"))
			return(optind++, EOF);
	}
	optopt = c = argv[optind][sp];
	if (c == ':' || !(cp=strchr(opts, c)))
	{
		ERR(": illegal option -- ", c);
		if (!argv[optind][++sp])
			optind++, sp = 1;
		return('?');
	}
	if (*++cp == ':')
	{
		if (argv[optind][sp+1])
			optarg = &argv[optind++][sp+1];
		else if (++optind >= argc)
		{
			ERR(": option requires an argument -- ", c);
			sp = 1;
			return('?');
		}
		else
			optarg = argv[optind++];
		sp = 1;
	}
	else
	{
		if (!argv[optind][++sp])
		{
			sp = 1;
			optind++;
		}
		optarg = (char *) 0;
	}
	return(c);
}
SHAR_EOF
if test -f 'imp.rc'
then
	echo shar: over-writing existing file "'imp.rc'"
fi
cat << \SHAR_EOF > 'imp.rc'
/ imp.rc	- move everywhere, one instruction at a time

$START:	mov	$START	$END
$END:	dat	0
SHAR_EOF
if test -f 'mars.c'
then
	echo shar: over-writing existing file "'mars.c'"
fi
cat << \SHAR_EOF > 'mars.c'
/*
** mars.c -	corewar machine interpreter
**
**	[cw by Peter Costantinidis, Jr. @ University of California at Davis]
*/

#include <stdio.h>
#include <setjmp.h>
#include <signal.h>
#include "cw.h"

static	char	rcsid[] = "$Header: mars.c,v 6.0 85/12/13 00:31:16 ccohesh001 Dist $";

char	*argv0;
int	jobcnt = 0;		/* # of jobs */
int	jobsleft;		/* # of jobs left running */
int	min_sep = PAGESEP;	/* initial min. dist. between jobs */
int	max_cyc = CYCLES;	/* min. # of process cycles */
int	cycle;			/* # of cycles */
static	process	pcs[MAX_USERS];

/*
** the following variables are used globally and rarely passed
** to any other functions
*/
long	octrl = DEF_CTRLS;	/* output control variable */
memword	memory[MAX_MEM+1];

extern	void	fini(), init(), randomize(), trap(), zeromem();
extern	int	pcscompar();
extern	char	*diedstr();

/*
** main()	- the main program
**		- parse arguments, call initialization routines, start game
**		  and call de-initialization routines
*/
main (argc, argv)
reg	int	argc;
reg	char	**argv;
{
	reg	int	i;
	auto	int	arg;
	extern	int	optind;

	argv0 = *argv;
	while ((arg = getopt(argc, argv, "s:c:dlipvr:")) != EOF)
	{
		switch (arg)
		{
			extern	char	*optarg;

			when 'r':	/* randomize */
				if (*optarg == '0')
					randomize(0);
				else
					randomize(atoi(optarg));
			when 's':	/* separation */
				if ((min_sep = atoi(optarg)) < 0)
					min_sep = 1;
				else if (min_sep > (MAX_PAGE-1))
				{
					fprintf(stderr, "%s: separation too large (must be < %d)\n", argv0, MAX_PAGE-1);
					usage();
				}
			when 'c':	/* cycles */
				max_cyc = atoi(optarg);
			when 'd':	/* status window display */
				TOGGLE(STATUS);
			when 'l':	/* print starting stats */
				TOGGLE(SIZE_START);
			when 'i':	/* print instructions */
				TOGGLE(PINST);
			when 'p':	/* don't print cycle # */
				TOGGLE(PASSNUM);
			when 'v':	/* visual display */
				TOGGLE(VISUAL);
			otherwise:
			case '?':
				usage();
		}
	}
	argc -= optind, argv += optind;
	if (argc < 2)
	{
		fprintf(stderr, "%s: missing file arguments\n", argv0);
		usage();
	}
	if (ON(VISUAL) && ON(PINST))
		TOGGLE(PINST);
	if (ON(PINST))
		octrl |= PASSNUM;
	zeromem();
	if (ON(SIZE_START))
		printf("%d words of memory available\n", MAX_MEM);
	if (argc > MAX_USERS)
	{
		fprintf(stderr, "%s: only %d jobs at once\n", argv0, MAX_USERS);
		exit(1);
	}
	for (i=jobcnt=0; *argv && i<argc; i++, argv++, jobcnt++)
	{
		pcs[i].pname = *argv;
		pcs[i].pdied = EALIVE;
		pcs[i].picnt = 0;
		pcs[i].plstmem = (memword *) NULL;
		pcs[i].pid = jobcnt;
		if ((pcs[i].pc = get_start()) < 0)
		{
			fprintf(stderr, "%s: not all jobs will fit\n", argv0);
			exit(1);
		}
		if (!(pcs[i].psize = load(pcs[i].pname, pcs[i].pc)))
		{
			fprintf(stderr, "%s: couldn't read in player \"%s\"\n",
				argv0, pcs[i].pname);
			exit(1);
		}
		if (ON(SIZE_START))
			printf("Player \"%s\" @ %4d, size: %d\n",
				pcs[i].pname, pcs[i].pc, pcs[i].psize);
	}
	if (ON(SIZE_START))
	{
		auto	char	buf[BUFSIZ];

		printf("Hit return to continue");
		gets(buf);
	}
	init();
	fini(scheduler(pcs));
	exit(0);
}

/*
** init()	- perform various initializations
*/
static	void	init ()
{
	jobsleft = jobcnt;
	if (ON(VISUAL))
	{
		if (vinit())
		{
			fprintf(stderr, "%s: visual not working\n", argv0);
			exit(1);
		}
		if (ON(STATUS) && statinit(pcs))
		{
			msg("Status window not working\n");
			TOGGLE(STATUS);
		}
	}
	trap(0);
	if (!ON(VISUAL))
	{
		auto	char	buf[BUFSIZ];

		printf("Press return to start ");
		(void) gets(buf);
		return;
	}
	msg("Press any key to start");
	getchar();
	vupdate(pcs);
}

/*
** trap()	- catches signals
**		- signum is zero for the initial call, non-zero
**		  when an interrupt is recieved
**		- when interrupt is received, call fini()
*/
static	void	trap (signum)
reg	int	signum;
{
#ifndef	LINT	/* keeps lint from complaining */
	signal(SIGINT, SIG_IGN);	/* i realize that these 2 statements */
	signal(SIGHUP, SIG_IGN);	/* could follow the if */
#endif
	if (!signum)
	{
#ifndef	LINT
		signal(SIGINT, trap);
		signal(SIGHUP, trap);
#endif
		return;
	}
	fini(EINTERRUPT);
	exit(1);
}

/*
** fini()	- misc. things to be done before termination
**		- print status at termination of processes
*/
void	fini (status)
reg	int	status;
{
	reg	int	i;
	auto	process	*spcs[MAX_USERS];

	if (ON(VISUAL))
	{
		msg("Hit return to continue");
		getchar();
		if (ON(STATUS))
			statfini();
		vfini();
	}
	printf("Halted: %s\n", diedstr(status));
	for (i=0; i < jobcnt; i++)
	{
		if (!pcs[i].pdied)
			pcs[i].picnt = cycle;
		spcs[i] = &(pcs[i]);
	}
	qsort(spcs, jobcnt, sizeof(spcs[0]), pcscompar);
	printf("%-20s\t#Inst\tPC\tReason for termination\n", "Process");
	for (i=0; i<jobcnt; i++)
		printf("%-20s\t%5d\t%4d\t%s\n",
			spcs[i]->pname, spcs[i]->picnt, spcs[i]->pc,
			diedstr(spcs[i]->pdied));
}

/*
** pcscompar()	- compare function used by qsort
*/
int	pcscompar (p1, p2)
reg	process	**p1, **p2;
{
	return((*p2)->picnt - (*p1)->picnt);
}

/*
** diedstr()	- return a string describing the reason for termination
*/
char	*diedstr (status)
reg	int	status;
{
	switch (status)
	{
		when EALIVE:
			return("Still alive");
		when ECYCLE:
			return("Cycle limit exceeded");
		when EWIN:
			return("Winner found");
		when EILLINST:
			return("Bad instruction");
		when EBADMODE:
			return("Bad addressing mode");
		when EINTERRUPT:
			return("Interrupted");
		otherwise:
			return("Unknown reason");
	}
	/*NOTREACHED*/
}

/*
** get_start()	- get a starting location for process
**		- starting locations on page boundaries
**		- return negative on error
**
**	Assumption:
**		If start location can't be found, then there are too many jobs.
*/
int	get_start ()
{
	reg	int	i;
	reg	int	start;

	start = rand() % MAX_MEM;
	start -= start % PAGESIZE;
	for (i = 0; i < MAX_USERS; i++)
	{
		if (!collision(start))
			return(start);
		start = sum(start, (min_sep * PAGESIZE));
	}
	return(-1);
}

/*
** collision()	- return TRUE if address is taken, else FALSE
*/
int	collision (addr)
reg	int	addr;
{
	reg	int	i;
	auto	int	ll,	/* lower limit to range */
			ul;	/* upper limit to range */

	for (i=0; i<jobcnt; i++)
	{
		ll = sum(pcs[i].pc, -min_sep);
		ul = sum(sum(pcs[i].pc, pcs[i].psize), min_sep);
		if (pcs[i].pc >= ul || pcs[i].pc <= ll)
		{	/* wrapped around memory */
			if (addr <= ul || addr >= ll)
				return(TRUE);
			continue;
		}
		if (addr >= ll && addr <= ul)
			return(TRUE);
	}
	return(FALSE);
}

/*
** load()	- load the player
**		- return the size of the player (in instructions), 0 on error
*/
int	load (fname, start)
char	*fname;
reg	int	start;
{
	reg	int	i, status;
	reg	FILE	*fp;

	if (!(fp = fopen(fname, "r")))
	{
		perror(fname);
		return(0);
	}
	for (i=start;
	     (status=fread(&(memory[i]),sizeof(memory[i]),1,fp)) == 1; i++)
		continue;
	fclose(fp);
	if (status < 0)
		return(0);
	return(i - start);
}

/*
** zeromem()	- set all memory locations to zero
*/
void	zeromem ()
{
	reg	int	i;

	for (i=0; i<MAX_MEM; i++)
		memory[i].op = memory[i].val = 0;
}

/*
** randomize()	- randomize the random number generator
*/
static	void	randomize (seed)
reg	int	seed;
{
	extern	long	getpid();
	extern	long	time();

	if (seed)
	{
		srand(seed);
		return;
	}
	srand(seed = (int) ((time(0) + getpid()) & 0x0000ffffL));
	printf("seed: %d\n", seed);
}

/*
** usage() -	print a usage message and exit
*/
static	void	usage ()
{
	fprintf(stderr, "Usage: %s [-dilpv] [-rn] [-sn] [-cn] file ...\n", argv0);
	exit(1);
}
SHAR_EOF
if test -f 'movmem.c'
then
	echo shar: over-writing existing file "'movmem.c'"
fi
cat << \SHAR_EOF > 'movmem.c'
/*
** movmem.c	-
**
static	char	rcsid[] = "$Header: movmem.c,v 7.0 85/12/28 14:35:55 ccohesh Dist $";
**
*/
#include "cw.h"

/*
** movmem()	- move contents of one location in `memory' to another
*/
void	movmem (m1, m2)
reg	memword	*m1, *m2;
{
	m1->op = m2->op;
	m1->moda = m2->moda;
	m1->modb = m2->modb;
	m1->arga = m2->arga;
	m1->argb = m2->argb;
}
SHAR_EOF
if test -f 'msg.c'
then
	echo shar: over-writing existing file "'msg.c'"
fi
cat << \SHAR_EOF > 'msg.c'
/*
** msg.c -	code dealing with the printing of messages
**
**	Routines:
**		msginit()	initialize the window
**		msgfini()	de-initialize the window
**		msg(fmt, args)	write message to window
**		msgclear()	clear the message window
**
**	[cw by Peter Costantinidis, Jr. @ University of California at Davis]
**
static	char	rcsid[] = "$Header: msg.c,v 7.0 85/12/28 14:36:01 ccohesh Dist $";
**
*/

#include <curses.h>
#include <ctype.h>
#include "cw.h"


static	WINDOW	*msgwin;	/* status window for msg's */

extern	void	doadd();

/*
** msginit()	- initialize the message window
**		- return non-zero on error
*/
int	msginit ()
{
	if (!(msgwin = subwin(stdscr, MSGLINES, MSGCOLS, MSGYBEGIN, MSGXBEGIN)))
	{
		fprintf(stderr, "%s: message screen initialization error\n",
			argv0);
		return(TRUE);
	}
	wclear(msgwin);
	scrollok(msgwin, TRUE);
	return(FALSE);
}

/*
** msgfini()	- re-initialize the message window
*/
void	msgfini ()
{
	wclear(msgwin);
	delwin(msgwin);
}

static char msgbuf[BUFSIZ];
/*
** msg()	- display message in message window using printf() like
**		  function
*/
/*VARARGS1*/
void	msg (fmt, args)
char	*fmt;
int	args;
{
	/*
	** if the string is "", just clear the line
	*/
	if (*fmt == '\0')
	{
		wclear(msgwin);
		wrefresh(msgwin);
		return;
	}
	/*
	** otherwise print the message and flush it out
	*/
	doadd(fmt, &args);
	waddch(msgwin, '\n');
	waddstr(msgwin, msgbuf);
	wrefresh(msgwin);
}

static	void	doadd (fmt, args)
char	**fmt;
int	***args;
{
	static	FILE	junk;

	/*
	** Do the printf into buf
	*/
#ifdef	_IOSTRG
	junk._flag = _IOWRT + _IOSTRG;
	junk._ptr = &msgbuf[0];
#else
 	junk._flag = _IOWRT;
 	junk._file = _NFILE;
 	junk._ptr = (unsigned char *) &msgbuf[0];
#endif
	junk._cnt = 32767;
	_doprnt(fmt, args, &junk);
	putc('\0', &junk);
}

/*
** punctrl()	- print a readable version of a certain character
**
**	Note:	Due to the inconsistent availability of a function to perform
**		this, my own version has been built in and used in place of
**		any pre-existing function.  I believe that this particular
**		version suts down on data space considerably from the versions
**		I have found on the Berkley systems.
*/
char	*punctrl (ch)
char	ch;
{
	static	char	*str = "^ ";

	ch &= 0177;
	if (ch >= ' ' && ch <= '~')
	{
		static	char	*str1 = " ";

		*str1 = ch;
		return(str1);
	}
	if (ch == CINTR)
		return("^?");
	*(str+1) = ch + '@';
	return(str);
}
SHAR_EOF
if test -f 'print.c'
then
	echo shar: over-writing existing file "'print.c'"
fi
cat << \SHAR_EOF > 'print.c'
/*
** print.c	- various printing routines
**
**	[cw by Peter Costantinidis, Jr. @ University of California at Davis]
**
static	char	rcsid[] = "$Header: print.c,v 7.0 85/12/28 14:36:14 ccohesh Dist $";
**
*/

#include <stdio.h>
#include "cw.h"

/*
** printit()	- print the given instruction
**		- return non-zero on error
*/
int	printit (fp, i)
FILE	*fp;
reg	memword	*i;
{
	reg	char	*inst, *fmt;
	auto	char	adda, addb;
	static	char	*fmt1 = "%3.3s\t\t%c%d\n",
			*fmt2 = "%3.3s\t%c%d\t%c%d\n";

	switch (i->op)
	{
		when DAT:
			inst = SDAT, fmt = fmt1;
		when MOV:
			inst = SMOV, fmt = fmt2;
		when ADD:
			inst = SADD, fmt = fmt2;
		when SUB:
			inst = SSUB, fmt = fmt2;
		when JMP:
			inst = SJMP, fmt = fmt1;
		when JMZ:
			inst = SJMZ, fmt = fmt2;
		when DJZ:
			inst = SDJZ, fmt = fmt2;
		when CMP:
			inst = SCMP, fmt = fmt2;
		when MUL:
			inst = SMUL, fmt = fmt2;
		when DIV:
			inst = SDIV, fmt = fmt2;
		when RND:
			inst = SRND, fmt = fmt1;
		otherwise:
			return(TRUE);
	}
	switch (i->moda)
	{
		when IMM:
			adda = CIMM;
		when REL:
			adda = CREL;
		when IND:
			adda = CIND;
		otherwise:
			adda = '?';
	}
	switch (i->modb)
	{
		when IMM:
			addb = CIMM;
		when REL:
			addb = CREL;
		when IND:
			addb = CIND;
		otherwise:
			addb = '?';
	}
	if (fmt == fmt1)
		fprintf(fp, fmt, inst, addb, rel_fix( i->argb ) ); /* budd */
	else
		fprintf(fp, fmt, inst,
			adda, rel_fix( i->arga ), /* budd */
			addb, rel_fix( i->argb )); /* budd */
	return(FALSE);
}

rel_fix( i )			/* make output relative - budd */
int i;
{
    if( i > MAX_MEM/2 )		/* addr over half of memory away? */
	return( i - MAX_MEM );	/* yes, display as behind us */
    else
	return( i );
}
SHAR_EOF
if test -f 'random.rc'
then
	echo shar: over-writing existing file "'random.rc'"
fi
cat << \SHAR_EOF > 'random.rc'
/ random.rc	- drop bombs in random places (slightly suicidal)

$START:	rnd		$WHERE		/ set bomber address
	mov	0	@$WHERE		/ drop bomb
	jmp		$START		/ let's do it again!
$WHERE:	dat		0		/ where to drop the bomb
SHAR_EOF
if test -f 'rcasm.l'
then
	echo shar: over-writing existing file "'rcasm.l'"
fi
cat << \SHAR_EOF > 'rcasm.l'
	/*
	**	lexical analyzer for input to Redcode Assembler
	**
	** [cw by Peter Costantinidis, Jr. @ University of California at Davis]
	**
	static	char	rcsid[] = "$Header: rcasm.l,v 7.0 85/12/28 14:37:16 ccohesh Dist $";
	**
	*/
	/* definitions */
I	-?[0-9]+
C	\/.*$
W	[" "\t]+
L	"$"[a-zA-Z0-9]+
%%
{C}	return(COMMENT);
dat|DAT	{ opcode=DAT; orc=1; return(OPCODE); }
mov|MOV	{ opcode=MOV; orc=2; return(OPCODE); }
add|ADD	{ opcode=ADD; orc=2; return(OPCODE); }
sub|SUB	{ opcode=SUB; orc=2; return(OPCODE); }
jmp|JMP	{ opcode=JMP; orc=1; return(OPCODE); }
jmz|JMZ	{ opcode=JMZ; orc=2; return(OPCODE); }
djz|DJZ	{ opcode=DJZ; orc=2; return(OPCODE); }
cmp|CMP	{ opcode=CMP; orc=2; return(OPCODE); }
mul|MUL	{ opcode=MUL; orc=2; return(OPCODE); }
div|DIV	{ opcode=DIV; orc=2; return(OPCODE); }
rnd|RND	{ opcode=RND; orc=1; return(OPCODE); }
"#"	return(OIMM);
"@"	return(OIND);
"\n"	return(NL);
{W}	;
^{L}":"	{
		static	char	buf[LABEL_LEN+1];
		auto	int	len = min(yyleng-2, LABEL_LEN);

		strncpy(buf, &(yytext[1]), len);
		buf[len] = '\0';
		dlabel = &(buf[0]);
		return(DLABEL);
	}
{L}	{
		static	char	bufs[2][LABEL_LEN+1];
		auto	int	len = min(yyleng+1, LABEL_LEN);
		auto	char	**ptr;

		if (orc == 1)
			ptr = &blabel;
		else
			ptr = (toggle ? &blabel : &alabel);
		strncpy(bufs[toggle], &(yytext[1]), len);
		bufs[toggle][len] = '\0';
		*ptr = bufs[toggle];
		toggle = (toggle ? 0 : 1);
		return(LABEL);
	}
{I}	{
		extern	int	yylval;

		if (sscanf(yytext, "%d", &yylval) != 1)
			return(ERROR);
		yylval = sum(yylval, 0);
		toggle = (toggle ? 0 : 1);
		return(INTEGER);
	}
.	
	{
		fprintf(stderr, "%s: unrecognized character in lex: %o\n",
			argv0, yytext[0]);
		return(ERROR);
	}
%%
SHAR_EOF
if test -f 'rcasm.l.old'
then
	echo shar: over-writing existing file "'rcasm.l.old'"
fi
cat << \SHAR_EOF > 'rcasm.l.old'
	/*
	**	lexical analyzer for input to Redcode Assembler
	**
	** [cw by Peter Costantinidis, Jr. @ University of California at Davis]
	**
	static	char	rcsid[] = "$Header: rcasm.l,v 7.0 85/12/28 14:37:16 ccohesh Dist $";
	**
	*/
	/* definitions */
I	-?[0-9]+
C	\/.*$
W	[" "\t]+
L	"$"[a-zA-Z0-9]+
%%
{C}	return(COMMENT);
dat|DAT	return(opcode=DAT, orc=1, OPCODE);
mov|MOV	return(opcode=MOV, orc=2, OPCODE);
add|ADD	return(opcode=ADD, orc=2, OPCODE);
sub|SUB	return(opcode=SUB, orc=2, OPCODE);
jmp|JMP	return(opcode=JMP, orc=1, OPCODE);
jmz|JMZ	return(opcode=JMZ, orc=2, OPCODE);
djz|DJZ	return(opcode=DJZ, orc=2, OPCODE);
cmp|CMP	return(opcode=CMP, orc=2, OPCODE);
mul|MUL	return(opcode=MUL, orc=2, OPCODE);
div|DIV	return(opcode=DIV, orc=2, OPCODE);
rnd|RND	return(opcode=RND, orc=1, OPCODE);
"#"	return(OIMM);
"@"	return(OIND);
"\n"	return(NL);
{W}	;
^{L}":"	{
		static	char	buf[LABEL_LEN+1];
		auto	int	len = min(yyleng-2, LABEL_LEN);

		strncpy(buf, &(yytext[1]), len);
		buf[len] = '\0';
		dlabel = &(buf[0]);
		return(DLABEL);
	}
{L}	{
		static	char	bufs[2][LABEL_LEN+1];
		auto	int	len = min(yyleng+1, LABEL_LEN);
		auto	char	**ptr;

		if (orc == 1)
			ptr = &blabel;
		else
			ptr = (toggle ? &blabel : &alabel);
		strncpy(bufs[toggle], &(yytext[1]), len);
		bufs[toggle][len] = '\0';
		*ptr = bufs[toggle];
		toggle = (toggle ? 0 : 1);
		return(LABEL);
	}
{I}	{
		extern	int	yylval;

		if (sscanf(yytext, "%d", &yylval) != 1)
			return(ERROR);
		yylval = sum(yylval, 0);
		toggle = (toggle ? 0 : 1);
		return(INTEGER);
	}
.	
	{
		fprintf(stderr, "%s: unrecognized character in lex: %o\n",
			argv0, yytext[0]);
		return(ERROR);
	}
%%
SHAR_EOF
if test -f 'rcasm.y'
then
	echo shar: over-writing existing file "'rcasm.y'"
fi
cat << \SHAR_EOF > 'rcasm.y'
	/*
	** grammar for the input to the Redcode Assembler
	**
	** [cw by Peter Costantinidis, Jr. @ University of California at Davis]
	**
	static	char	rcsid[] = "$Header: rcasm.y,v 7.0 85/12/28 14:37:04 ccohesh Dist $";
	**
	*/

	/* instructions */
%{
#include <stdio.h>
#include "cw.h"

typedef	struct	/* simple single purpose symbol table */
{
	int	sym_abs;	/* absolute address of symbol */
	char	*sym_nam;	/* symbols name */
} symtab;

memword	inst;		/* current instruction */
memword	memory[JMAX_LEN];
symtab	symbols[MAX_LABELS];	/* symbol table */
symtab	*unres[JMAX_LEN];	/* list of unresolved references */
uns	opcode;		/* set in lexical analyzer */
int	icnt = 0;	/* instruction count */
int	lcnt = 1;	/* line count */
int	ocnt = 0;	/* # of operands for current instruction */
int	toggle = 0;	/* for multi-arg inst.'s indicates which arg */
int	orc;		/* required # of operands for current inst. */
char	*dlabel, *alabel, *blabel;/* set in lexical analyzer */

extern	void	yyerror();
%}


	/* operand tokens */
%token	OIMM	/* number is operand					(#) */
%token	OREL	/* number specifies offset from current instruction	( ) */
%token	OIND	/* number specifies offset from current instruction	(@) */
		/* to location where relative address of operand is found   */

%token	OPCODE
%token	INTEGER	/* the operands */
%token	COMMENT	/* a comment */
%token	ERROR	/* error in lex */
%token	NL	/* new line */

%token	DLABEL	/* defining a label */
%token	LABEL	/* a label being used */

%start	program

%%	/* beginning of rules section */

program	:	/* empty */
	|	program line
	|	program error NL
		{
			toggle = 0;
			lcnt++;
			yyerrok;
		}
	;

line	:	comment NL
		{
			lcnt++;
		}
	|	label statement comment NL
		{
			inst.op = $2;
			lcnt++;
			toggle = 0;	/* a hack for labels */
			if (icnt > JMAX_LEN)
			{
				static	int	once = FALSE;

				if (!once)
				{
					once = TRUE;
					fprintf(stderr, "Maximum instruction limit of %d exceeded\n", JMAX_LEN);
					fprintf(stderr, "Will continue processing...\n");
				}
			}
			movmem(&(memory[icnt++]), &inst);
		}
	;

label	:
	|	DLABEL
		{
			if (addsym(dlabel))
				YYERROR;
		}
	;

comment	:
	|	COMMENT
	;

statement:	OPCODE arga argb
		{
			if (orc != 2)
			{
				yyerror("bad argument count");
				YYERROR;
			}
			if ((opcode == MOV && $3 == IMM) ||
			    (opcode == ADD && $3 == IMM) ||
			    (opcode == SUB && $3 == IMM) ||
			    (opcode == JMZ && $3 == IMM) ||
			    (opcode == DJZ && $3 == IMM) ||
			    (opcode == MUL && $3 == IMM) ||
			    (opcode == DIV && $3 == IMM))
			{
				yyerror("non-sensicle mode for operand");
				YYERROR;
			}
			$$ = opcode;
		}
	|	OPCODE argb
		{
			if (orc != 1)
			{
				yyerror("bad argument count");
				YYERROR;
			}
			if ((opcode == JMP && $2 == IMM) ||
			    (opcode == RND && $2 == IMM) ||
			    (opcode == DAT && $2 != REL))
			{
				yyerror("non-sensicle mode for operand");
				YYERROR;
			}
			$$ = opcode;
		}
	;

arga	:	addr INTEGER	/* returns addr */
		{
			$$ = $1;
			inst.moda = $1;
			inst.arga = $2;
		}
	|	addr LABEL
		{
			$$ = $1;
			inst.moda = $1;
			inst.arga = getsymval(alabel, 0);
		}
	;

argb	:	addr INTEGER	/* returns addr */
		{
			$$ = $1;
			inst.modb = $1;
			inst.argb = $2;
		}
	|	addr LABEL
		{
			$$ = $1;
			inst.modb = $1;
			inst.argb = getsymval(blabel, 1);
		}
	;

addr:	/* no operand (relative addressing mode) */
		{	$$=REL;		}
	|	OIMM
		{	$$=IMM;		}
	|	OIND
		{	$$=IND;		}
	;

%%

char	*argv0;

extern	void	fatal(), init();

/*
** main() -	the main program
*/
void	main (argc, argv)
reg	int	argc;
reg	char	**argv;
{
	auto	char	buf[BUFSIZ];
	reg	char	*ptr;
	auto	char	*ifname, *ofname;
	auto	int	error = 0;

	argv0 = *argv++, argc--;
	ofname = RC_OUT;
	if (argc < 1)
		usage();
	ifname = *argv++, argc--;
	if (argc > 1)
		usage();
	if (argc)
		ofname = *argv;
	if (!freopen(ptr = ifname, "r", stdin) ||
	    !freopen(ptr = ofname, "w", stdout))
	{
		perror(ptr);
		exit(1);
	}
	init();
	error = yyparse();
	fclose(stdin);
	if (error)
		fprintf(stderr, "%s: yyparse() error\n", argv0);
	if (error || fini())
	{
		fclose(stdout);
		unlink(ofname);
		exit(1);
	}
	exit(0);
}

/*
** fini()	- resolve any unresolved symbols
**		- write instructions
*/
int	fini ()
{
	reg	int	i;
	reg	symtab	**us = unres;
	auto	int	error = FALSE;

	for (us = unres; *us; us++)
	{
		reg	symtab	*s;
		auto	int	inum = abs((*us)->sym_abs)-1;
		extern	symtab	*getsym();

		if (!(s = getsym((*us)->sym_nam)) || s->sym_abs < 0)
		{
			fprintf(stderr, "Inst. %d: label \"%s\" not defined\n",
				inum, (*us)->sym_nam);
			error++;
			continue;
		}
		/*
		fprintf(stderr, "Us inum: %d, \"%s\", %d\n",
			inum, (*us)->sym_nam, (*us)->sym_abs);
		*/
		if ((*us)->sym_abs < 0)
			memory[inum].argb = s->sym_abs - inum;
		else
			memory[inum].arga = s->sym_abs - inum;
	}
	if (error)
	{
		fprintf(stderr, "%d unresolved labels\n", error);
		fprintf(stderr, "%s: object file not created\n", argv0);
		return(TRUE);
	}
	for (i=0; i<icnt; i++)
		if (fwrite(&(memory[i]), sizeof(memory[i]), 1, stdout) != 1)
		{
			fprintf(stderr, "%s: write error to output file\n",
				argv0);
			perror(argv0);
			return(TRUE);
		}
	return(FALSE);
}

/*
** init()	- perform various initializations
*/
void	init ()
{
	reg	int	i;

	for (i=0; i<MAX_LABELS; i++)
		symbols[i].sym_nam = (char *) 0;
	for (i=0; i<JMAX_LEN; i++)
		unres[i] = (symtab *) NULL;
}

/*
** usage() -	print a usage message and exit
*/
void	usage ()
{
	fprintf(stderr, "Usage: %s infile [outfile]\n", argv0);
	exit(1);
}

/*
** yyerror() -	yacc error routine
*/
void	yyerror (msg)
reg	char	*msg;
{
	fprintf(stderr, "%s: error on line %d (%s)\n", argv0, lcnt, msg);
}

static	int	sym_cnt = 0;	/* number of symbols in table */
extern	symtab	*_addsym(), *addunres(), *getsym();

/*
** getsymval()	- return the value of the specified symbol relative to
**		  the current instruction
**		- if symbol is undefined:
**			add it to symtab w/o a value
**			mark this instruction as having an unresolved symbol
**			return 0
**		- if which==0, then arga, else argb
*/
int	getsymval (sname, which)
reg	char	*sname;
reg	int	which;
{
	reg	symtab	*s;
	auto	int	len;

	if (s = getsym(sname))
	{
		if (s->sym_abs >= 0)
			return(s->sym_abs - icnt);
	}
	else
		s = _addsym(sname);
	s = addunres(s->sym_nam);
	s->sym_abs += 1;		/* must be >0 */
	if (which)
		s->sym_abs *= -1;	/* negative for argb */
	return(0);
}

/*
** addunres()	- add a symbol to the unresolved list
*/
symtab	*addunres (sname)
reg	char	*sname;
{
	static	int	index = 0;
	reg	symtab	**s = &(unres[index++]);

	if (index >= JMAX_LEN)
		fatal("Symbols used to often");
	if (!(*s = (symtab *) malloc(sizeof(symtab))))
		fatal("memory allocation failure");
	(*s)->sym_nam = sname;
	(*s)->sym_abs = icnt;
	return(*s);
}

/*
** addsym()	- add a symbol to the symbols[] list
*/
int	addsym (sname)
reg	char	*sname;
{
	reg	symtab	*s;
	auto	int	len;

	if ((s = getsym(sname)) && s->sym_abs >= 0)
	{
		fprintf(stderr, "label \"%s\" multiply defined\n", sname);
		return(TRUE);
	}
	if (s)
	{	/* previously used symbol is declared */
		s->sym_abs = icnt;
		return(FALSE);
	}
	s = _addsym(sname);
	s->sym_abs = icnt;
	return(FALSE);
}

/*
** _addsym()	- slightly lower lever function, used by both addsym()
**		  and getsymval()
*/
symtab	*_addsym (sname)
reg	char	*sname;
{
	reg	symtab	*s = &(symbols[sym_cnt++]);
	reg	int	len;

	if (!(s->sym_nam = (char *) malloc(len=(strlen(sname)+1))))
	{
		fprintf(stderr, "%s: can't malloc %d bytes\n", argv0, len);
		fatal("memory allocation failure");
	}
	strcpy(s->sym_nam, sname);
	s->sym_abs = -1;
	return(s);
}

/*
** getsym()	- return a pointer to the specified symbol in the symbol table
*/
symtab	*getsym (sname)
reg	char	*sname;
{
	reg	int	i;

	for (i=0; i<sym_cnt; i++)
		if (!strcmp(sname, symbols[i].sym_nam))
			return(&(symbols[i]));
	return((symtab *) NULL);
}

/*
** fatal()	- print an error message and exit
*/
void	fatal (mesg)
reg	char	*mesg;
{
	fprintf(stderr, "%s: FATAL error: %s\n", argv0);
	exit(1);
}

#include "rcasm.h"	/* the lexical analyzer */
SHAR_EOF
if test -f 'scheduler.c'
then
	echo shar: over-writing existing file "'scheduler.c'"
fi
cat << \SHAR_EOF > 'scheduler.c'
/*
** scheduler.c	- routines dealing with the running of the jobs
**
**	[cw by Peter Costantinidis, Jr. @ University of California at Davis]
**
static	char	rcsid[] = "$Header: scheduler.c,v 7.0 85/12/28 14:36:26 ccohesh Dist $";
**
*/

#include <stdio.h>
#include <setjmp.h>
#include "cw.h"


static	int	_pc;			/* current pc */
static	jmp_buf	haltit;

extern	void	halt(), run();
extern	memword	*getoperand();

/*
** scheduler()	- run the processes
**		- very simple algorithm to determine what job is scheduled next:
**			jobs are scheduled by thier order in the process table
**		- each job gets to execute one instruction during its scheduled
**		  period
*/
int	scheduler (pcs)
reg	process	*pcs;
{
	reg	int	flag;

	if (ON(VISUAL))
		return(vscheduler(pcs));
	for (cycle=0; jobsleft > 1 && cycle < max_cyc; cycle++)
	{
		reg	process	*j;

		if (ON(PASSNUM) && (!(cycle % PASSFREQ) || ON(PINST)))
			printf("Pass #%04d\t", cycle);
		if (!ON(PINST) && ON(PASSNUM) &&
		    (!(cycle % PASSFREQ) || ON(PINST)))
			putchar('\r'), fflush(stdout);
		for (flag=0, j=pcs; j < (pcs+jobcnt); j++, flag++)
		{
			if (ON(PINST) && ON(PASSNUM) && flag &&
			    (!(cycle % PASSFREQ) || ON(PINST)))
				printf("\t\t");
			if (!HALTED(j))
				run(j);
		}
	}
	if (cycle >= max_cyc)
		return(ECYCLE);
	return(EWIN);
}

/*
** vscheduler()	- the scheduler used for visual display mode
*/
int	vscheduler (pcs)
reg	process	*pcs;
{
	for (cycle=0; jobsleft > 1 && cycle < max_cyc; cycle++)
	{
		reg	process	*j;

		for (j=pcs; j < (pcs+jobcnt); j++)
			if (!HALTED(j))
				run(j);
		vupdate(pcs);
		if (ON(STATUS) && !(cycle % PASSFREQ) && ON(PASSNUM))
			vstatus();
	}
	if (cycle >= max_cyc)
		return(ECYCLE);
	return(EWIN);
}

/*
** run()	- execute one instruction of the given job
*/
static	void	run (j)
reg	process	*j;
{
	reg	memword	*w;
	reg	int	status;

	/* fetch pc (incremented at end of function or where appropriate) */
	PC = j->pc;
	/* fetch instruction */
	w = &(memory[j->pc]);
	/* remember this for halting processes */
	if (status = SETJMP(haltit))
	{
		halt(j, status);
		return;
	}
	if (ON(PINST))
	{
		printf("PC: %4d\t", PC);
		if (printit(stdout, w))
			fprintf(stderr, "%s: printit() error\n", argv0);
	}
	switch (w->op)
	{
		auto	int	tmp;

#define	A	w->moda, w->arga
#define	B	w->modb, w->argb
/*
** when modifying memory locations through arithmetic operations
** make sure the opcode gets reset
*/
#define	COREA	tmp=getaddr(w->moda, w->arga),memory[tmp].op=DAT,memory[tmp].val
#define	COREB	tmp=getaddr(w->modb, w->argb),memory[tmp].op=DAT,memory[tmp].val

		when MOV:/* move A into location B */
			movmem(j->plstmem=(&(memory[getaddr(B)])),
				getoperand(A));
		when ADD:/* add A to contents of B, results in B */
			COREB = sum((int) (getoperand(A))->val,(int) (getoperand(B))->val);
		when MUL:
		{
			reg	int	temp = (int) (getoperand(B))->val;

			temp *= (int) (getoperand(A))->val;
			COREB = sum(temp, 0);
		}
		when DIV:
		{
			reg	int	temp = (int) (getoperand(B))->val;

			temp /= (int) (getoperand(A))->val;
			COREB = sum(temp, 0);
		}
		when SUB:/* subtract A from contents of B, results in B */
			COREB = sum((int) -(getoperand(A))->val,(int) (getoperand(B))->val);
		when JMP:/* jump to B */
			j->pc = getaddr(B);
			return;
		when JMZ:/* if A == 0 then jump to B, otherwise continue */
			if (getoperand(A)->val == 0)
			{
				j->pc = getaddr(B);
				return;
			}
		when DJZ:/* --A; if A == 0 then jump to B */
			COREA = sum((int) getoperand(A)->val, -1);
			if (COREA == 0)
			{
				j->pc = getaddr(B);
				return;
			}
		when CMP:/* compare A with B; if != then skip next inst. */
			if (getoperand(A)->val != getoperand(B)->val)
			{
				j->pc = sum(j->pc, 2);
				return;
			}
		when RND:/* into A a random number between 0 and MAX_MEM */
			COREB = sum((int) rand(), 0);
		otherwise:
			halt(j, EILLINST);
#undef	A
#undef	B
#undef	COREA
#undef	COREB
	}
	if (!HALTED(j))
		j->pc = sum(j->pc, 1);		/* increment pc */
}

/*
** getoperand()	- return the operand
**		- since a pointer to static data is returned, care is
**		  taken to insure that this static data isn't corrupted
**		  due to two `simultaneous' calls.
*/
static	memword	*getoperand (m, a)
reg	uns	m, a;
{
	static	memword	mw1, mw2, *mw;

	mw = (mw == &mw1) ? &mw2 : &mw1;
	switch (m)
	{
		case IMM:
			mw->op = 0;
			mw->val = a;
			return(mw);
		case REL:
			return(&(memory[sum(PC, (int) a)]));
		case IND:
			return(&(memory[getaddr(m,a)]));
		default:
			LONGJMP(haltit, EBADMODE);
	}
	/*NOTREACHED*/
}

/*
** getaddr()	- return the address
*/
static	int	getaddr (m, a)
reg	uns	m, a;
{
	switch (m)
	{
		case REL:
			return(sum((int) PC, (int) a));
		case IND:
		{
			reg	int	tmp;

			tmp = sum(PC, (int) a);
			return(sum(tmp, (int) memory[tmp].val));
		}
		case IMM:
		default:
			LONGJMP(haltit, EBADMODE);
	}
	/*NOTREACHED*/
}

/*
** halt()	- halt the specified process
*/
static	void	halt (j, reason)
reg	process	*j;
reg	int	reason;
{
#ifdef	DEBUG
	fprintf(stderr, "%s: process \"%s\" halted\n", argv0, j->pname);
#endif
	j->pdied = reason;
	j->picnt = cycle;
	jobsleft--;
	if (ON(VISUAL) && ON(STATUS))
		vstajob(j);
}
SHAR_EOF
if test -f 'stomper.rc'
then
	echo shar: over-writing existing file "'stomper.rc'"
fi
cat << \SHAR_EOF > 'stomper.rc'
/
/ stomper.rc	- son of dwarf and gemini (he's a mover and he's aggressive)
/
	jmp		$START		/jump to start of program
$SRC:	dat		0		/pointer to source address
$DST:	dat		191		/pointer to destination address
$START:	mov	@$SRC	@$DST		/copy source to destination
	cmp	$SRC	#13		/if all 10 lines have been copied...
	jmp	$DONE			/...then leave the loop
	add	#1	$SRC		/otherwise, increment the source address
	add	#1	$DST		/...and the destination address
	add	#8	$BOMB		/increment bomber address
	mov	#0	@$BOMB		/drop bomb
	jmp 	$START			/...and return to the loop
$DONE:	mov	#4	@$DST		/reset bomber address
	mov	#191	182		/restore the starting destination address
	jmp	182			/jump to the new copy
$BOMB:	dat		4
SHAR_EOF
if test -f 'sum.c'
then
	echo shar: over-writing existing file "'sum.c'"
fi
cat << \SHAR_EOF > 'sum.c'
/*
** sum.c	- add two numbers, wrapping if sum is out-of-bounds
**
**	[cw by Peter Costantinidis, Jr. @ University of California at Davis]
**
static	char	rcsid[] = "$Header: sum.c,v 7.0 85/12/28 14:36:36 ccohesh Dist $";
**
*/

#include "cw.h"


/*
** sum()	- sum two integers w/ memory wrapping
*/
int	sum (x, y)
reg	int	x, y;
{
	reg	int	tot = x + y;

	if (tot < 0)
		return(sum(MAX_MEM + tot, 0));
	if (tot >= MAX_MEM)
		return(tot % MAX_MEM);
	return(tot);
}
SHAR_EOF
if test -f 'unrc.c'
then
	echo shar: over-writing existing file "'unrc.c'"
fi
cat << \SHAR_EOF > 'unrc.c'
/*
** unrc.c -	disassemble rc binaries
**
**	[cw by Peter Costantinidis, Jr. @ University of California at Davis]
**
static	char	rcsid[] = "$Header: unrc.c,v 7.0 85/12/28 14:36:48 ccohesh Dist $";
**
*/

#include <stdio.h>
#include "cw.h"


char	*argv0;

main (argc, argv)
reg	int	argc;
reg	char	**argv;
{
	auto	memword	i;

	argv0 = *argv++, argc--;
	if (argc == 0)
		*argv = RC_OUT;
	else if (argc != 1)
		usage();
	if (!freopen(*argv, "r", stdin))
	{
		perror(*argv);
		exit(1);
	}
	while (fread((char *) &i, sizeof(i), 1, stdin) == 1)
		unrc(&i);
	fclose(stdin);
}

/*
** unrc() -	unassemble the given instruction
*/
unrc (i)
reg	memword	*i;
{
	reg	int	incnt;
	static	int	icnt = 0;

	icnt++;
	switch (i->op)
	{
		when DAT:
		case JMP:
		case RND:
			incnt = 1;
		when MOV:
		case ADD:
		case SUB:
		case JMZ:
		case DJZ:
		case CMP:
		case MUL:
		case DIV:
			incnt = 2;
		otherwise:
			fprintf(stderr, "Inst. %d: bad opcode: %d\n",
				icnt, i->op);
			return;
	}
	switch (i->modb)
	{
		case IMM:
		case REL:
		case IND:
		otherwise:
			fprintf(stderr, "Inst. %d: bad address mode for B\n", icnt);
			return;
	}
	if (incnt == 1)
	{
		if (printit(stdout, i))
			fprintf(stderr, "Inst. %d: printit() problem\n", icnt);
		return;
	}
	switch (i->moda)
	{
		case IMM:
		case REL:
		case IND:
		otherwise:
			fprintf(stderr, "Inst. %d: bad address mode for A\n", icnt);
			return;
	}
	if (printit(stdout, i))
		fprintf(stderr, "Inst. %d: printit() problem\n", icnt);
}

/*
** usage() -	print a usage message and exit
*/
void	usage ()
{
	fprintf(stderr, "Usage: %s file\n", argv0);
	exit(1);
}
SHAR_EOF
if test -f 'vdisplay.c'
then
	echo shar: over-writing existing file "'vdisplay.c'"
fi
cat << \SHAR_EOF > 'vdisplay.c'
/*
** vdisplay.c	- routines dealing with the visual display of the
**		  Corewar game
**
**	[cw by Peter Costantinidis, Jr. @ University of California at Davis]
**
static	char	rcsid[] = "$Header: vdisplay.c,v 7.0 85/12/28 14:36:39 ccohesh Dist $";
**
*/

#include <curses.h>
#include <ctype.h>
#include "cw.h"


/*
** Strategy:
**
** 1.	Fill the screen with a rectangle of characters (MEMPTY).
**	Let each character represent 10 memory locations.
**	Since MAX_MEM is 10,000 (and I am afraid this value is
**	going to be rather hard coded into the display routines)
**	this will have to be a 50 column by 20 row box.
** 2.	Place an uppercase letter in the location corresponding to
**	the value of the job's PC.  If more than one job occupies the
**	same location, then place a digit representing the number of
**	jobs.
** 3.	Place a lowercase letter at the square corresponding to the
**	memory location that the job is modifying.  If more than one
**	job is modifying the same memory section, place MSHARE there.
** 4.	If a job is modifying a memsect that another job is modifying,
**	place a MHIT.
**
**	Therefore, we need routines to do the following:
**
**		initialize window
**			fill with MEMPTY's
**		update screen wrt PC values and delta mem locs
*/

#define	BOXS(p)		(p/NUMMEM)
#define	BOXX(p)		(BOXS(p) % MCOLS)
#define	BOXY(p)		(BOXS(p) / MCOLS)

static	WINDOW	*memwin;

extern	void	clearbox(), membox();

/*
** vupdate()	- update the memory display
*/
int	vupdate (ps)
reg	process	*ps;
{
	reg	process	*p;

	for (p = ps; (p - ps) < jobcnt; p++)
	{	/* update plstmem's	*/
		auto	int	addr = (p->plstmem - &(memory[0]));
		auto	int	y = BOXY(addr),		/* hides earlier def. */
				x = BOXX(addr);		/* hides earlier def. */
		auto	char	pch = (char) p->pid + 'a';
		reg	char	ch;

		if (!p->plstmem || p->pdied)
			continue;
		if ((addr/PAGESIZE) == (p->pc/PAGESIZE))
			continue;	/* writing to same mem page */
		if ((ch = mvwinch(memwin, y, x)) == MEMPTY)
			waddch(memwin, pch);
		else if (islower(ch))
			waddch(memwin, MSHARE);
		else
			msg("Unknown character in membox (%s) @ (%d,%d)",
				punctrl(ch), y, x);
	}
	for (p = ps; (p - ps) < jobcnt; p++)
	{	/* upate pc's	*/
		auto	int	y = BOXY(p->pc),	/* hides earlier def. */
				x = BOXX(p->pc);	/* hides earlier def. */
		auto	char	pch = (char) p->pid + 'A';
		reg	char	ch = mvwinch(memwin, y, x);

		if (p->pdied || ch == MFULL || ch == MHIT)
			continue;
		if (ch == MEMPTY)
			waddch(memwin, pch);
		else if (isupper(ch))
			waddch(memwin, '2');
		else if (isdigit(ch))
			waddch(memwin, (ch<'9') ? (ch + (char) 1) : MFULL);
		else if (ch == MSHARE)
			waddch(memwin, MHIT);
		else if (islower(ch))
		{
			if (ch == tolower(pch))
				waddch(memwin, pch);
			else
				waddch(memwin, MHIT);
		}
		else
			msg("unknown character in membox (%s) @ (%d,%d)",
				punctrl(ch), y, x);
	}
	wrefresh(memwin);
	for (p = ps; (p - ps) < jobcnt; p++)
	{	/* upate pc's	*/
		auto	int	addr = (p->plstmem - &(memory[0]));

		if (p->pdied)
			continue;
		mvwaddch(memwin, BOXY(p->pc), BOXX(p->pc), MEMPTY);
		if (!p->plstmem)
			continue;
		mvwaddch(memwin, BOXY(addr), BOXX(addr), MEMPTY);
	}
}

/*
** vinit()	- perform curses initializations
**		- initialize memory window
**		- return non-zero on error
*/
int	vinit ()
{
	if (initscr() == ERR)
	{
		fprintf(stderr, "%s: screen initialization error\n", argv0);
		perror(argv0);
		return(TRUE);
	}
	if (LINES < MIN_LINES || COLS < MIN_COLS)
	{
		fprintf(stderr, "%s: screen must be at least %d by %d\n",
			argv0, MIN_LINES, MIN_COLS);
		return(TRUE);
	}
	if (!(memwin = subwin(stdscr, MLINES, MCOLS, MYBEGIN, MXBEGIN)))
	{
		fprintf(stderr, "%s: can't create memory-window\n", argv0);
		return(TRUE);
	}
	if (msginit())
		return(TRUE);
	membox();
	clearbox();
	refresh();
	crmode();
	noecho();
	return(FALSE);
}

/*
** vfini()	- perform screen shutdown actions
*/
void	vfini ()
{
	msgfini();
	clear();
	refresh();
	delwin(memwin);
	endwin();
}

/*
** clearbox()	- fill the box with MEMPTY's
*/
static	void	clearbox ()
{
	reg	int	y, x;

	for (y=0; y<MLINES; y++)
		for (x=0; x<MCOLS; x++)
			mvwaddch(memwin, y, x, MEMPTY);
}

/*
** membox()	- draw a box around the memory window
*/
static	void	membox ()
{
	reg	int	y, x;

	for (x = MXBEGIN-1, y = MYBEGIN-1; x < (MXBEGIN+MCOLS+1); x++)
		mvaddch(y, x, HORTBORDER), mvaddch(y+MLINES+1, x, HORTBORDER);
	for (y = MYBEGIN, x = MXBEGIN-1; y < (MYBEGIN+MLINES); y++)
		mvaddch(y, x, VERTBORDER), mvaddch(y, x+MCOLS+1, VERTBORDER);
}
SHAR_EOF
if test -f 'vstatus.c'
then
	echo shar: over-writing existing file "'vstatus.c'"
fi
cat << \SHAR_EOF > 'vstatus.c'
/*
** vstatus.c	- manage the status window
**
**	[cw by Peter Costantinidis, Jr. @ University of California at Davis]
**
static	char	rcsid[] = "$Header: vstatus.c,v 7.0 85/12/28 14:36:44 ccohesh Dist $";
**
*/

#include <curses.h>
#include "cw.h"


static	WINDOW	*statwin;

/*
** statinit()	- initialize the status window
*/
int	statinit (jobs)
reg	process	*jobs;
{
	reg	int	i;

	if (!(statwin = subwin(stdscr, SLINES, SCOLS, SYBEGIN, SXBEGIN)))
	{
		fprintf(stderr, "%s: status screen initialization error\n",
			argv0);
		return(TRUE);
	}
	wclear(statwin);
	scrollok(statwin, FALSE);
	for (i=0; i<jobcnt && i < SLINES; i++)
		vstajob(jobs++);
	if (ON(PASSNUM))
		vstatus();
	return(FALSE);
}

/*
** statfini()	- de-initialize the status window
*/
void	statfini ()
{
	wclear(statwin);
	delwin(statwin);
}

/*
** vstatus()	- print the current cycle number and jobs left 
**		  in the status window
*/
void	vstatus ()
{
	wmove(statwin, SLINES-1, 0);
	wprintw(statwin, "Cycle: %04d  Jobs: %2d", cycle, jobsleft);
	wrefresh(statwin);
}

/*
** vstajob()	- update the entry for the given job in the status window
*/
void	vstajob (j)
reg	process	*j;
{
	wmove(statwin, j->pid, 0);
	wprintw(statwin,"%c. \"%.10s\" %4d %s",
		'A' + j->pid, j->pname, j->pc, diedstr(j->pdied));
	wrefresh(statwin);
}
SHAR_EOF
#	End of shell archive
exit 0