[comp.sources.games] v03i086: cchess - corrispondence chess, Part01/05

games-request@tekred.TEK.COM (03/02/88)

Submitted by: Jan Wolter <janc@crim.eecs.umich.edu>
Comp.sources.games: Volume 3, Issue 86
Archive-name: cchess/Part01

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 1 (of 5)."
# Contents:  README MANIFEST misc.c scrn.c
# Wrapped by billr@tekred on Tue Jan 12 12:09:51 1988
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f README -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"README\"
else
echo shar: Extracting \"README\" \(2076 characters\)
sed "s/^X//" >README <<'END_OF_README'
XCCHESS version 1.00
X
XCorrispondence chess is a program which moderates chess games between two
Xplayers on the same system.  When run, it displays a representation of the
Xcurrent board and allows you to make a move.  It sends mail to the other
Xplayer telling him it is his turn to move.
X
XFEATURES:
X  - Enforces all rules of chess.
X  - Supports about a dozen standard Fairy Chess games, and lets you mix
X    up a staggering number of other varients by combining options and
X    editing the initial board positions.
X  - Choice of two formats for board display.
X  - Optional "computer kibitzer" warns you of incredibly stupid moves.
X  - Allows the display of playbacks and the printing of transcripts.
X  - Maintains a scorefile showing outcome of all past games.
X  - Works on just about any imaginable terminal, yet does a fairly nice
X    job of taking advantage of whatever smarts your terminal has.
X  - Much effort has been expended to make this code reasonably portable.
X    It has been tested on a large variety of systems.
X  - Does it's own screen motion.  Doesn't use curses.
X  - Optional "ccreap" utility reminds people to move, and deletes abandoned
X    games.
X
XNONFEATURES:
X  - Does not play over uucp-type nets, and would be difficult to adapt to
X    that job, because the game transcripts are kept in a local file.  NSF-
X    type nets work fine, of course.
X  - Different code for different unixes, different terminals, and different
X    fairy chess options leads to a truely boggling number of places bugs can
X    lurk.  I've put a lot of work into debugging, but I promise there are
X    plenty more bugs to find and fix.
X  - This is the exact opposite of an object-oriented program.  There are
X    zillions of global variables and even some goto's.  Hackers will love it.
X
XINSTALLATION:
X    See installation instructions in Makefile before compiling.
X
X				  ___                _     __  _
X				 (   >              ' )   /   // _/_
X				  __/___.  ____      / / / __|/  /  _  __
X				 / / (_/|_/ / <_    (_(_/ (_) \_<__</_/ (_
X				<_/
X				        janc@crim.eecs.umich.edu
END_OF_README
if test 2076 -ne `wc -c <README`; then
    echo shar: \"README\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f MANIFEST -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"MANIFEST\"
else
echo shar: Extracting \"MANIFEST\" \(534 characters\)
sed "s/^X//" >MANIFEST <<'END_OF_MANIFEST'
X   File Name		Archive #	Description
X-----------------------------------------------------------
X MANIFEST                  1	This shipping list
X Makefile                  4	
X README                    1	
X cchess.6                  4	
X cchess.h                  3	
X cmd.c                     2	
X def.h                     5	
X init.c                    3	
X main.c                    3	
X misc.c                    1	
X play.c                    2	
X reap.c                    5	
X scrn.c                    1	
X sys.c                     4	
END_OF_MANIFEST
if test 534 -ne `wc -c <MANIFEST`; then
    echo shar: \"MANIFEST\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f misc.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"misc.c\"
else
echo shar: Extracting \"misc.c\" \(31437 characters\)
sed "s/^X//" >misc.c <<'END_OF_misc.c'
X/* CCHESS MISCELLANEOUS STUFF. 					Version 1.00
X *   
X *   Mainly routines to display various stuff in various ways.
X *
X *   (C) Copyright Jan Wolter - Apr 1986.
X *
X */
X
X#include "cchess.h"
X
Xstatic int ind;		/* Indentation of current display */
Xstatic schar botcol;	/* Color on bottom of current display */
X#ifndef NOTERMCAP
Xextern char *CE;	/* So we can tell if there is a clear to end string */
X#endif NOTERMCAP
X
X#define usebigboard (bigboard && COLS >= 5*Cols+30)
X/* SAVEMOVE()
X *
X *   Send a mail message, saying a move has been made.  Ask for a comment,
X *   and store the entry of type <ch> and with move <mv> (a five character
X *   string) in the file.
X */
X
Xsavemove(ch,mv)
Xchar ch, *mv;
X{
Xchar spc;
X
X	/* Read in a comment */
X	if (ch != 'm')
X	{
X#ifndef LSIGNAL
X		setjmp(susp_env);
X		susp1_flg = TRUE;
X#endif LSIGNAL
X		wprint("Comment: ");
X		if (readstr(cbuffer,1,CB_LEN,FALSE))
X			cbuffer[0] = ' ';
X		else
X			cbuffer[0] = '\000';
X#ifndef LSIGNAL
X		susp1_flg = FALSE;
X#endif LSIGNAL
X	}
X	else
X		cbuffer[0] = '\000';
X
X	/* Set the space character for moves */
X	spc = ' ';
X	if (ch == 'M')
X	{
X		if (stripped)
X			spc = 'F';
X		else if (inmate)
X		{
X			if (incheck)
X				spc = 'M';
X			else
X				spc = 'S';
X		}
X		else
X		{
X			if (incheck)
X				spc = 'C';
X			else if (repeated)
X				spc = 'R';
X		}
X	}
X
X	/* Save the move in the gamefile */
X	fprintf(wfp,"%5ld:%c%c%5.5s%s\n",day(),ch,spc,mv,cbuffer);
X
X	if ((ch == 'M' || ch == 'm') && promote)
X	    fprintf(wfp,"%5ld:P %c%3.3s\n",day(),pc[PIECES-abs(promote)],mv+2);
X
X	/* Flush the output */
X	fflush(wfp);
X
X	/* Send Mail */
X	sprintf(cbuffer,"My chess move has been made.  Run \042%s %s\042.\n",
X		RUN_CMD,myid);
X	mesg("Cchess Move",cbuffer);
X}
X
X
X/* PRINTCOM()
X *
X *   Print the players comment under a board.
X */
X
Xprintcom()
X{
X	if (mbuffer[C_CMD] != 'A' && mbuffer[C_CMD] != 'C' && 
X	    mbuffer[C_FLG] == ' ')
X		cprintf("\"%s\"",mbuffer+C_COM);
X}
X
X
X
X/* PRINTMOV()
X *
X *   This displays the move in <mbuf>, along with the the mate status, and
X *   all that.  This is a partly a kludge.  <Ill> is the number of illegal moves
X *   made in a kriegspiel games.
X */
X
Xshort movelen = 0;
Xprintmov(mbuf,ill,id)
Xchar *mbuf;
Xint ill;
Xchar *id;
X{
Xchar buf[40];
Xchar tmp;
X#ifndef NOTERMCAP
Xshort n;
Xchar bug[40];
X#endif NOTERMCAP
X
X	switch(mbuf[C_CMD])
X	{
X	case 'M':
X	case 'm':
X		if (hidden)
X		{
X		    if (taken == SQ)
X			sprintf(buf,"%s: %d illegal moves tried",id,ill + 1);
X		    else
X			sprintf(buf,"%s: %d illegal moves tried - Captured %s",
X				id, ill+1, pman(taken));
X		}
X		else
X		{
X			tmp = mbuf[C_FLG];
X			mbuf[C_FLG] = 0;
X			sprintf(buf,"%s: %s",id,mbuf+C_MOV);
X			mbuf[C_FLG] = tmp;
X		}
X		break;
X	case 'K':
X		sprintf(buf,"%s proposed cancellation",id);
X		break;
X	case 'D':
X		sprintf(buf,"%s proposed draw",id);
X		break;
X	case 'N':
X		sprintf(buf,"%s rejected proposal",id);
X		break;
X	case 'Y':
X		sprintf(buf,"%s accepted proposal",id);
X		break;
X	case 'F':
X		sprintf(buf,"%s forfieted",id);
X		break;
X	case 'A':
X	case 'C':
X	case 'P':
X		buf[0] = 0;
X		break;
X	}
X
X	if (incheck)
X		if (inmate)
X			strcat(buf,(Language == LG_PERSIAN)?
X				" - SHAH-MAT":" - CHECKMATE");
X		else
X			strcat(buf,(Language == LG_PERSIAN)?
X				" - SHAH":" - CHECK");
X	else
X		if (inmate)
X			strcat(buf," - STALEMATE");
X#ifndef NOTERMCAP
X	if ((n =strlen(buf)) >= movelen)
X#endif NOTERMCAP
X		cprint(buf);
X#ifndef NOTERMCAP
X	else
X		if (CE)
X		{
X			if (cx != 1) wputchar('\n');
X			cline();
X			cprint(buf);
X		}
X		else  /* Here comes the kludge */
X		{
X			int i,j;
X			j = (movelen - n)/2 + 1;
X			for (i = 0; i < j; i++) 
X				bug[i] = ' ';
X			for (j = 0; buf[j] != 0; j++,i++)
X				bug[i] = buf[j];
X			for (j = 0; j < n; j++,i++)
X				bug[i] = ' ';
X			cprint(bug);
X		}
X	movelen = n;
X#endif NOTERMCAP
X}
X
X/* PRINTOPTS()
X *
X *   Print challenge options.  Colors, Privacy, Variant.  The argument
X *   is the print routine to use.  Normally this is "printf" or
X *   "mprintf" or "wprintf".
X */
X
Xprintopts(prtf)
Xint (*prtf)();
X{
Xregister int i;
X
X	(*prtf)("WHITE: %-8.8s   ", (mycolor == WHITE) ? myid : hisid);
X	(*prtf)("BLACK: %s\n", (mycolor == BLACK) ? myid : hisid);
X	if (Private)
X		(*prtf)("Privacy: Closed   ");
X	else
X		(*prtf)("Privacy: Open     ");
X
X	i = Game_type;
X	(*prtf)("Variant: %s",typename[i]);
X
X	if (Kriegspiel && !defopt[i][OP_VISIB])
X	    (*prtf)(" Kriegspiel");
X	if (Rows != defopt[i][OP_ROWS] || Cols != defopt[i][OP_COLS])
X	    (*prtf)("\nBoard: %dx%d",Cols+1,Rows+1);
X	if (Oldcastle != defopt[i][OP_CASTLE])
X	    (*prtf)("\nCastling: %s",Oldcastle?"Forbidden":"Permitted");
X	if (Oldpawn != defopt[i][OP_DPAWN])
X	    (*prtf)("\nDouble Pawn Move: %s",Oldpawn?"Forbidden":"Permitted");
X	if (Stripresult != defopt[i][OP_STRIP])
X	    (*prtf)("\nLoss of Forces: %s",resltname[Stripresult]);
X	if (Staleresult != defopt[i][OP_STALE])
X	    (*prtf)("\nStalemated: %s",resltname[Staleresult]);
X	if (Capture != defopt[i][OP_CAPTURE])
X	    (*prtf)("\nCapture Rule: %s",captname[Capture]);
X	if (Kcapture != defopt[i][OP_KCAPTURE])
X	{
X	    (*prtf)("\n");
X	    pkings(*prtf);
X	    (*prtf)("Capture Rule: %s",captname[Kcapture]);
X	}
X	if (Musttake != defopt[i][OP_MUSTTAKE])
X	    (*prtf)("\nCapture: %s",Musttake?"Required":"Optional");
X	if (Whiteking != defopt[i][OP_WHITEKING])
X	{
X	    (*prtf)("\nWhite mateable piece: ");
X	    if (Whiteking == SQ)
X		(*prtf)("None");
X	    else
X		(*prtf)(pman(Whiteking));
X	}
X	if (Blackking != defopt[i][OP_BLACKKING])
X	{
X	    (*prtf)("\nBlack mateable piece: ");
X	    if (Blackking == SQ)
X		(*prtf)("None");
X	    else
X		(*prtf)(pman(Blackking));
X	}
X	if (Promotion != defopt[i][OP_PROMOTE])
X	{
X	    (*prtf)("\nPromotion: ");
X	    switch(Promotion)
X	    {
X	    case PR_MINISTER:
X		(*prtf)("%s Only",piecename[WM]);
X		break;
X	    case PR_QRBN:
X		(*prtf)("%s, %s, %s or %s",
X		    piecename[WQ],piecename[WR],piecename[WB],piecename[WN]);
X		break;
X	    case PR_NONE:
X		(*prtf)("None");
X		break;
X	    }
X	}
X	if (Winitmoves != defopt[i][OP_WIMOVES] ||
X	    Whitemoves != defopt[i][OP_WMOVES])
X	{
X	    (*prtf)("\nWhite Moves: ");
X	    if (Whitemoves == 0 || Binitmoves == 0 || Blackmoves == 0)
X		(*prtf)("Progressive (%d on first turn)",Winitmoves);
X	    else
X	    {
X		(*prtf)("%d",Whitemoves);
X		if (Winitmoves != Whitemoves)
X		    (*prtf)(" (%d on first turn)",Winitmoves);
X	     }
X	}
X	if (Binitmoves != defopt[i][OP_BIMOVES] ||
X	    Blackmoves != defopt[i][OP_BMOVES])
X	{
X	    (*prtf)("\nBlack Moves: ");
X	    if (Whitemoves == 0 || Binitmoves == 0 || Blackmoves == 0)
X		(*prtf)("Progressive");
X	    else
X	    {
X		(*prtf)("%d",Blackmoves);
X		if (Binitmoves != Blackmoves)
X		    (*prtf)(" (%d on first turn)",Binitmoves);
X	    }
X	}
X	if (Tabiyat != defopt[i][OP_TABIYAT])
X	    (*prtf)("\nMay %scross center on first turn",Tabiyat?"not ":"");
X	if (Thrucheck != defopt[i][OP_THRUCHECK])
X	{
X	    (*prtf)("\n");
X	    pkings(*prtf);
X	    (*prtf)("may %smove thru check",Thrucheck?"":"not ");
X	}
X	if (Language != defopt[i][OP_NAMES])
X	    (*prtf)("\nPiecenames: %s",langname[Language]);
X
X	(*prtf)("\n");
X	if (!Help_me)
X	    (*prtf)("Computer Kibitzing: Off\n");
X}
X
X/* SCOREBOARD()
X *
X *   Print the score file in a slightly prettyed up format.  Variant games
X *   are listed separately from Chess games, for no special reason.  Visual
X *   mode not used here.  See the endgame() function for the format of the
X *   score file.
X */
X
Xscoreboard()
X{
XFILE *fp;
Xint n=0;
Xint i;
X
X	if ((fp = fopen(GAME_LIST,"r")) != NULL)
X	{
X		for (i = 1; i <= HI_GAME; i++)
X		{
X			n += listgames(fp,i);
X			rewind(fp);
X		}
X		n += listgames(fp,0);
X		fclose(fp);
X	}
X	if (n == 0)
X		printf("No games completed.\n");
X}
X
Xlistgames(fp,gametype)
XFILE *fp;
Xchar gametype;
X{
Xchar p1[10], p2[10];
Xchar *player1=p1, *player2=p2;
Xchar *tmp;
Xint count,i=0;
X
X	while (fgetl(mbuffer,MB_LEN,fp))
X		if (cti(mbuffer[26+OP_GAME]) == gametype)
X		{
X			sscanf(mbuffer+2,"%s %s %d",player1,player2,&count);
X			setopts(mbuffer+26);
X			if (++i == 1)
X				printf("\n%s Games:\n-----------------------------------------------------------\n",typename[gametype]);
X
X			if (mbuffer[0] == 'L')
X			{
X				tmp = player1; player1 = player2; player2 = tmp;
X				mbuffer[0] = 'W';
X				Firstwhite = !Firstwhite;
X			}
X
X			printf("%8s(%s) %s %s in %2d moves.\n",
X			    player1,
X			    (Firstwhite)?"white":"black",
X			    (mbuffer[0]=='W')?"mated":"drew ",
X			    player2, count);
X		}
X	return(i);
X}
X
X/* ENDGAME()
X *
X *   This routine wraps up a game.  The game file is removed, and the result
X *   is recorded in a scorefile.
X *
X *   The argument may be any of:  RE_WIN, RE_LOSE, RE_DRAW, RE_CANCEL
X *
X *    Scorefile entrys look like:
X *      W <name-1> <name-2> <cnt> <optlist>
X *      D <name-1> <name-2> <cnt> <optlist>
X *	^ ^        ^        ^     ^
X *      | |        |        |     |
X *      | |        |        |     +-- col 26 - Options in challenge line format.
X *      | |        |        |                  OP_COLOR is color of winner.
X *      | |        |        +-------- col 20 - Number of moves (5 digits).
X *      | |        +----------------- col 11 - Losers login name (8 columns).
X *      | +-------------------------- col  2 - Winners login name (8 columns).
X *      +---------------------------- col  0 - Win or Draw.
X */
X
Xendgame(type)
Xchar type;
X{
XFILE *gp;
Xchar tmpcolor;
X
X	/* Remove Game file */
X	unlink(fname);
X
X	/* Make an entry in the score file */
X	if (!solo && type != RE_CANCEL)
X	    if ((gp=fopen(GAME_LIST,"a"))==NULL)
X	    {
X		printf("Cchess error:  Unable to append to scorefile %s\n",
X			GAME_LIST);
X	    }
X	    else
X	    {
X		/* Temporarily change Firstcolor to Winnerscolor */
X		tmpcolor = Firstwhite;
X		if (type == RE_LOSE)
X		{
X			fprintf(gp,"W %8.8s %8.8s %5d ", hisid, myid, movecnt);
X			Firstwhite = (mycolor == BLACK);
X		}
X		else
X		{
X			fprintf(gp,"%c %8.8s %8.8s %5d ",
X			     (type==RE_WIN) ? 'W' : 'D',
X			     myid, hisid, movecnt);
X			Firstwhite = (mycolor == WHITE);
X		}
X		saveopts(gp);
X		Firstwhite = tmpcolor;
X		fclose(gp);
X	    }
X}
X
X/* DISP()
X *
X *   Display the board position, with the color <col> at the bottom.
X */
X
Xstatic char blacksquare;
X
Xdisp(bd,col)
Xschar bd[R_SIZE][C_SIZE];
Xschar col;
X{
X	blacksquare = (Plain) ? '-' : '*';
X
X	/* Use the bigboard option, if selected and there is room */
X	if (usebigboard)
X		dispbg(bd,col);
X	else
X		dispsm(bd,col);
X}
X
Xstatic char smtopline[] = "-------------------------+";
X
Xdispsm(bd,col)
Xschar bd[R_SIZE][C_SIZE];
Xschar col;
X{
Xint r,c;
Xint pac,pbc;
Xint par,pbr;
X
X	/* Save some numbers for showat() to use when updating board */
X	ind = (COLS - 1) / 2 - Cols - 4;
X	botcol = col;
X
X	/* Top Player's Name */
X	clr();
X	cprintf("%s (%s)", pcapcol(-col), (mycolor == col) ? hisid : myid);
X	
X	pac = lside(col);		/*  0 for white;  7 for black */
X	pbc = rside(col)+col;		/*  8 for white; -1 for black */
X	par = bside(col)-col;		/* -1 for white;  8 for black */
X	pbr = tside(col);		/*  7 for white;  0 for black */
X
X	/* Print the Letters across the Top */
X	indent(ind + 4);
X	for ( c=pac ; c != pbc ; c += col)
X	{
X		wputchar('A'+c);
X		wputchar(' ');
X	}
X
X	/* Print Top Line */
X	indent(ind + 2);
X	wputchar('+');
X	wprint(smtopline+22-2*Cols);
X
X	/* Print the Board */
X	for ( r=pbr ; r != par ; r -= col)
X	{
X		indent(ind);
X		wprintf("%c | ",r+'1');
X		for ( c=pac ; c != pbc ; c += col)
X		{
X			if (bd[r][c] && (!hidden || bd[r][c]*mycolor > 0))
X				piece(bd[r][c]);
X			else
X				wputchar(1&(r+c)?'-':blacksquare);
X			wputchar(' ');
X		}
X		if (commodore)
X			wputchar('|');
X		else
X			wprintf("| %c",r+'1');
X	}
X
X	/* Print Bottom Line */
X	indent(ind + 2);
X	wputchar('+');
X	wprint(smtopline+22-2*Cols);
X
X	/* Print the Letters across the Bottom */
X	indent(ind + 4);
X	for ( c=pac ; c != pbc ; c += col)
X	{
X		wputchar('A'+c);
X		wputchar(' ');
X	}
X
X	/* Bottom Player's Name */
X	cprintf("%s (%s)", pcapcol(col), (mycolor != col) ? hisid : myid);
X}
X
X
Xdispbg(bd,col)
Xschar bd[R_SIZE][C_SIZE];
Xschar col;
X{
Xint r,c;
Xint pac,pbc;
Xint par,pbr;
X
X	/* Save some numbers for showat() to use when updating board */
X	ind = (COLS - 5*Cols - 16) / 2;
X	botcol = col;
X
X	clr();
X
X	pac = lside(col);		/*  0 for white;  7 for black */
X	pbc = rside(col)+col;		/*  8 for white; -1 for black */
X	par = bside(col)-col;		/* -1 for white;  8 for black */
X	pbr = tside(col);		/*  7 for white;  0 for black */
X
X	/* Print the Letters across the Top */
X	indent(ind - 7);
X	wprintf("%-8.8s  +-",(mycolor == col) ? hisid : myid);
X	for ( c=pac ; c != pbc ; c += col)
X		wprintf("--%c--",'A'+c);
X	wprintf("-+  %8.8s", pcapcol(-col));
X
X	indent(ind + 3);
X	wputchar('|');
X#ifdef NOTERMCAP
X	wprint(blanks(5*Cols +7));
X#else
X	cursor(ind + 5*Cols + 12,cy);
X#endif NOTERMCAP
X	wputchar('|');
X
X	/* Print the Board */
X	for ( r=pbr ; r != par ; r -= col)
X	{
X		indent(ind);
X		wprintf("%c  | ",r+'1');
X		for ( c=pac ; c != pbc ; c += col)
X		{
X			if (bd[r][c] && (!hidden || bd[r][c]*mycolor > 0))
X			{
X				wputchar(' ');
X				piece(bd[r][c]);
X				wputchar(' ');
X			}
X			else
X				wprintf("  %c  ",1&(r+c)?'-':blacksquare);
X		}
X		wprintf(" |  %c",r+'1');
X
X		indent(ind + 3);
X		wputchar('|');
X#ifdef NOTERMCAP
X		wprint(blanks(5*Cols +7));
X#else
X		cursor(ind + 5*Cols + 12,cy);
X#endif NOTERMCAP
X		wputchar('|');
X	}
X
X	/* Print Bottom Line */
X	indent(ind - 7);
X	wprintf("%-8.8s  +-",(mycolor != col) ? hisid : myid);
X	for ( c=pac ; c != pbc ; c += col)
X		wprintf("--%c--",'A'+c);
X	wprintf("-+  %8.8s", pcapcol(col));
X
X}
X
X#ifndef NOTERMCAP
X/* UPDATE()
X *
X *   Change the currently displayed board <ob> to the new board <nb>.
X *   Only smart terminals should be in this routine.
X */
X
Xupdate(ob,nb)
Xschar ob[R_SIZE][C_SIZE];
Xschar nb[R_SIZE][C_SIZE];
X{
Xint r,c;
Xschar op,np;
X
X	for (r = 0; r <= Rows; r++)
X		for (c = 0; c <= Cols; c++)
X		{
X			if (hidden && !kibitz)
X			{
X				op = (ob[r][c]*mycolor < 0) ? SQ : ob[r][c];
X				np = (nb[r][c]*mycolor < 0) ? SQ : nb[r][c];
X			}
X			else
X			{
X				op = ob[r][c];
X				np = nb[r][c];
X			}
X			if (op != np)
X				showat(r,c,np);
X		}
X	if (usebigboard)
X		cursor(1,2*Rows+6);
X	else
X		cursor(1,Rows+8);
X}
X
X
X/* SHOWAT()
X *
X *   Show piece <p> at position <r> <c> on the currently displayed board.
X */
X
Xshowat(r,c,p)
XREGISTER int r,c;
Xschar p;
X{
Xregister int par;
X
X	if (botcol == BLACK)
X	{
X		c = Cols - c;
X		par = Cols;
X	}
X	else
X	{
X		r = Rows - r;
X		par = Rows;
X	}
X	if (usebigboard)
X	{
X		cursor(ind + 7 + 5*c, 2*r + 3);
X		if (p == SQ)
X			wprintf(" %c ", 1&(r+c+par)?'-':blacksquare);
X		else
X			piece(p); 
X	}
X	else
X	{
X		cursor(ind + 5 + 2*c, r + 4);
X		if (p == SQ)
X			wputchar(1&(r+c+par)?'-':blacksquare);
X		else
X			piece(p); 
X	}
X}
X#endif NOTERMCAP
X
X
X/* PIECE()
X *
X *	Draw a piece for the current board, with highlighting of white pieces.
X *	We don't highlight on the small board: it looks crummy.
X */
X
Xstatic char bgpc[] = "  ++**<>??][..xx><##++$$";
X
Xpiece(p)
X{
Xchar *c;
X
X	if (usebigboard)
X	{
X		c = bgpc + 2 * abs(p);
X		wputchar(*c++);
X		if (p > 0) beg_so();
X	}
X	wputchar(pc[p+PIECES]);
X	if (usebigboard)
X	{
X		if (p > 0) end_so();
X		wputchar(*c);
X	}
X}
X
X
X/* LIST()
X *
X *   List all existing game files.  Just reads in the directory and lists all
X *   the filenames.  Needs prettying up. Visual mode not used here.  If userid
X *   is positive, only games involving that user are printed.
X */
X   
Xlist(userid)
XREGISTER int userid;
X{
Xint uid1,uid2;
XDIR *fp;
Xint n;
Xchar *pwname;
Xregister struct direct *gfd;
X
X	if ((fp = opendir(CCDIR))== 0)
X	{
X		printf("Panic: unable to read %s directory\n",CCDIR);
X		return;
X	}
X	n = 0;
X	igpwuid();
X	while ((gfd = readdir(fp)) != NULL)
X		if (gfd->d_name[0] != '.' &&
X		   sscanf(gfd->d_name,"%d.%d",&uid1,&uid2)==2 &&
X		   (userid < 0 || uid1 == userid || uid2 == userid))
X		{
X			if ((pwname=gpwuid(uid1)) == 0)
X				printf("uid %d vs ",uid1);
X			else
X				printf("%s vs ",pwname);
X			if ((pwname=gpwuid(uid2)) == 0)
X				printf("uid %d\n",uid2);
X			else
X				printf("%s\n",pwname);
X			n++;
X		}
X	endpwent();  /* close the password file */
X	if (n == 0) printf("None\n");
X}
X
X
X/*	LDBOARD
X *
X *	This routine reads in the game file and puts the board into the
X *	current position.  The first line in the file should be the version
X *	line, which looks like:
X *
X *	#####:V 0.19
X *        ^   ^  ^
X *	  |   |  |
X *	  |   |  +----- version number.
X *        |   +-------- character "V" identifies this as a version line.
X *	  +------------ Day the challenge was issued.
X *
X *	The next lines in the file should be challenge lines, which are
X *	formatted as:
X *
X *	#####:C code-string...
X *	  ^   ^      ^
X *	  |   |      |
X *	  |   |      +------- The option[] array in ascii, one character per.
X *	  |   +-------------- Challenge line code letter 'C' in column one.
X *        +------------------ Day that the challenge was issued.
X *	
X *	Only the last Challenge line before an accept line is relevant.
X *	The accept line is simply a line with the letter 'A' in column
X *	one.  After the accept line, move lines may appear.  Move lines
X *	look like:
X *
X *      #####:M fr-to comments
X *        ^   ^^^     ^
X *        |   |||     |
X *        |   |||     +------ Any comments by the player.
X *        |   ||+------------ The move in a modified algebraic notation.
X *        |   |+------------- Space.  C=Check, M=Checkmate, S=Stalemate
X *        |   |                       R=Repeated Position, F=Stripped forces.
X *        |   +-------------- The 13th letter of the alphabet.
X *	  +------------------ Day that the move was made.
X *
X *      The first move line is for the white player, and thereafter they
X *      alternate.  The single space before the comment should be there only
X *      if the comment is non-null.  Moves which place a pawn into the other
X *      player's home row should be immediately followed by a place line
X *      specifying the promotion to be made.
X *
X *	Move lines of the same format as above, but with a lower-case
X *	'm' are used in variants where multiple moves are made in one
X *	player's turn.  Only the last move has a capitol 'M'.  The rest
X *	are lower case (and normally don't have comments on them).
X *
X *      Illegal move lines are only used in Kriegspiel.  One is entered for
X *      each illegal move attempted.  Their format is similar to legal moves,
X *      but they never have comments:
X *
X *      #####:I fr-to
X *        ^   ^ ^
X *        |   | |
X *        |   | +------------ The move in a modified algebraic notation.
X *        |   +-------------- The 9th letter of the alphabet.
X *        +------------------ Day that the move was made.
X *
X *      A place line may be anywhere.  They are used to add or delete a piece
X *      from the board.  This is used in variant setups, and in pawn promotion.
X *      Place lines should never have comments or trailing spaces.
X *
X *      #####:P p-rc
X *        ^   ^ ^ ^
X *        |   | | |
X *     	  |   | | +------- The coordinates the piece is to be put at
X *     	  |   | +--------- The name of the piece (or space to delete)
X *     	  |   +----------- The 16th letter of the alphabet.
X *	  +--------------- Day that the place line was entered.
X * 
X *      Five other types of lines may appear.  A line begining with 'D' means
X *      the player has proposed a draw.  A draw line must be followed by a 'N'
X *      (reject) line if the game is to continue, or an 'Y' (accept) line if
X *      the draw is accepted.  A line begining with a 'K' means the player
X *	has proposed that the game be cancelled.  A line begining with a 'F'
X *	means the player has forfeited.  All these lines may have a comment
X *      begining in the same column as in the 'M' line's comment, and a day
X *      in the usual place.
X *
X *      Besides these, there may be reminder lines.  These have nothing to
X *	do with the game, but are inserted by cchess each time that a reminder
X *	is sent to one of the players.  They are solely for internal use.
X */
X
Xldboard()
X{
Xregister schar corder;	/* -1 if odd number of challenges issued.  Else 1 */
Xint fr,fc,tr,tc;
Xchar probuf[15];
Xchar issetup=FALSE;
Xint ill;
Xregister char *tmb;
X	
X    corder = 1;
X    for (;;)
X    {
X	if (fgetl(sbuffer,MB_LEN,rfp)==NULL)
X	{
X		/* Was this from a compatible cchess version? */
X		if (    strcmp(file_version,version)
X#ifdef COMPAT018
X		     && strcmp(file_version,"0.18")
X#endif COMPAT018
X						     )
X		{
X			wprint("Format error:  Unknown game file version\n");
X			done(1);
X		}
X		return;
X	}
X	tmb = mbuffer; mbuffer = sbuffer; sbuffer = tmb;
X
X	switch (mbuffer[C_CMD])
X	{
X	case 'V':	/* version line */
X		strncpy(file_version,mbuffer+C_CMD+2,6);
X		file_version[5] = '\0';
X		break;
X	case 'R':	/* reminder line - ignore */
X		sbuffer = mbuffer; mbuffer = tmb;
X		break;
X
X	case 'C':	/* read challenge line */
X
X		if (status > 1)
X		{
X			wprint("Format error:  Challenge after accept.\n");
X			done(1);
X		}
X		status = 1;
X
X		/* Read the challenge line options in */
X		setopts(&mbuffer[C_CMD+2]);
X
X		mycolor = (Firstwhite) ? order : -order;
X		corder = -corder;
X		toplay = (corder == order) ? mycolor : -mycolor;
X
X		if (Oldcastle)
X			wccq = wcck = bccq = bcck = FALSE;
X
X		piecename = chessname[Language];
X
X		hidden = Kriegspiel;
X
X		/* Initialize board */
X		if (!issetup)
X		{
X			copy(ib,b);
X			issetup = TRUE;
X		}
X
X		lastday = atol(mbuffer+C_DAY);
X		break;
X
X	case 'A':	/* read accept line */
X		status = 3;
X		if (Private && kibitz)
X		{
X			wprintf("Game between %s and %s is private.\n",
X				myid,hisid);
X			done(0);
X		}
X
X		/* For debugging - make non-private kriegspiel visible */
X		if (kibitz) hidden = FALSE;
X
X		toplay = WHITE;
X		movecnt = 0;
X		playcnt = 0;
X		ill = 0;
X
X		if (Winitmoves == MO_PROGRESS || Binitmoves == MO_PROGRESS ||
X		    Whitemoves == MO_PROGRESS || Blackmoves == MO_PROGRESS )
X		{
X			consmoves = (Winitmoves == MO_PROGRESS)?1:Winitmoves;
X			Whitemoves = MO_PROGRESS;
X		}
X		else
X			consmoves = Winitmoves;
X
X		lastday = atol(mbuffer+C_DAY);
X		break;
X
X	case 'I':   /* Illegal move made */
X		ill++;
X		break;
X
X	case 'M':   /* Move made */
X	case 'm':
X		if (status != 3)
X		{
X			wprint("Format error:  Move out of sequence.\n");
X			done(1);
X		}
X		if (mconv(mbuffer+C_MOV,&fr,&fc,&tr,&tc))
X		{
X			makemove(b,toplay,fr,fc,tr,tc,TRUE);
X			if (istame)
X				tamemoves++;
X			else
X				tamemoves = 0;
X			if (promote)
X			{
X				if (fgetl(probuf,14,rfp)==NULL)
X				{
X				      wprint("Format error:  No promotion.\n");
X				      done(1);
X			        }
X				b[tr][tc] = promote =
X				  toplay*(PIECES-(index(pc,probuf[C_MOV])-pc));
X			}
X		}
X		else
X		{
X			wprint("Format error:  Bad move syntax.\n");
X			done(1);
X		}
X		incheck = (mbuffer[C_MAT] == 'C' || mbuffer[C_MAT] == 'M');
X		inmate  = (mbuffer[C_MAT] == 'M' || mbuffer[C_MAT] == 'S');
X		repeated = (mbuffer[C_MAT] == 'R');
X		stripped = (mbuffer[C_MAT] == 'F');
X		if (mbuffer[C_CMD] == 'M')
X		{
X			playcnt++;
X			movecnt++;
X			toplay = -toplay;	/* Other color plays next */
X
X			if (Whitemoves == MO_PROGRESS)
X				consmoves++;
X			else if (movecnt == 1)
X				consmoves = Binitmoves;
X			else if (toplay == WHITE)
X				consmoves = Whitemoves;
X			else
X				consmoves = Blackmoves;
X
X			consmade = 0;
X
X			illmoves = ill;
X			ill = 0;
X		}
X		else
X			consmade++;
X		lastday = atol(mbuffer+C_DAY);
X		break;
X
X	case 'P':  /* Place Piece */
X		issetup = FALSE;
X		if (!place(b,mbuffer[C_MOV],mbuffer+C_MOV+2))
X		{
X			wprint("Format error:  Bad place syntax.\n");
X			done(1);
X		}
X		break;
X
X	case 'D':  /* Draw Proposed */
X		if (status != 3)
X		{
X			wprint("Format error:  Draw at strange time.\n");
X			done(1);
X		}
X		status = 4;
X		playcnt++;
X		toplay = -toplay;
X		lastday = atol(mbuffer+C_DAY);
X		break;
X
X	case 'K':  /* Cancellation Proposed */
X		if (status != 3)
X		{
X		    wprint("Format error:  Cancellation at strange time.\n");
X		    done(1);
X		}
X		status = 7;
X		toplay = -toplay;
X		playcnt++;
X		lastday = atol(mbuffer+C_DAY);
X		break;
X
X	case 'N':  /* Draw or Cancellation Rejected */
X		if (status != 4 && status != 7)
X		{
X			wprint("Format error:  Unproposed draw rejected.\n");
X			done(1);
X		}
X		status = 3;
X		playcnt++;
X		toplay = -toplay;
X		lastday = atol(mbuffer+C_DAY);
X		break;
X
X	case 'Y':  /* Draw or Cancellation Accepted */
X		if (status != 4 && status != 7)
X		{
X			wprint("Format error:  Unproposed draw accepted.\n");
X			done(1);
X		}
X		status = status + 1;
X		playcnt++;
X		toplay = -toplay;
X		lastday = atol(mbuffer+C_DAY);
X		break;
X
X	case 'F':  /* Forfeit */
X		if (status != 3 )
X		{
X			wprint("Format error:  Forfeit out of sequence.\n");
X			done(1);
X		}
X		status = 6;
X		playcnt++;
X		toplay = -toplay;
X		lastday = atol(mbuffer+C_DAY);
X		break;
X	default:
X		wprint("Format error:  Weird line.\n");
X	}
X    }
X}
X
X/*  PLACEBOARD
X *
X * Find the differences between the initial board and the board <bd>
X * and add place lines to the gamefile to make it.
X */
X
Xplaceboard(bd)
Xschar bd[R_SIZE][C_SIZE];
X{
Xint i,j;
X
X	for (i=0; i <= Rows; i++)
X		for (j=0; j <= Cols; j++)
X			if (bd[i][j] != ib[i][j])
X				fprintf(wfp,"%5ld:P %c-%c%c\n", day(),
X				    pc[PIECES+bd[i][j]], j+'A', i+'1');
X}
X
X/* SETOPTS()
X *
X *    Set the game options based on the given string.  If the string ends
X *    prematurely, try to recover by using the default options for that
X *    game for the rest of the string.
X */
X
Xsetopts(s)
Xchar *s;
X{
Xint i;
X
X	for (i=0; i<OPTIONS; i++,s++)
X	{
X		option[i] = cti(*s);
X		
X		if (option[i] < 0 || option[i] > maxopt[i])
X			/*
X			 * If we reached the end of the line, then use the
X			 * default options for the rest.  This is so options
X			 * can be added in the future without having to fix
X			 * old game files.  Otherwise, print an error message.
X			 */
X			if (i > OP_GAME && (*s == '\0' || *s == '\n'))
X			{
X				for (; i<OPTIONS; i++)
X					option[i] = defopt[option[OP_GAME]][i];
X				break;
X			}
X			else
X			{
X				printf("Error - Option %d out of range\r\n",i);
X				done(1);
X			}
X	}
X#ifdef COMPAT018
X	if (!strcmp(file_version,"0.18") && Capture > 2) Capture++;
X#endif COMPAT018
X}
X
X/* SAVEOPTS
X *
X *    Write the current options to the file <fp>.  One character is used
X *    for each option and a newline is written last.
X */
X
Xsaveopts(fp)
XFILE *fp;
X{
Xint i;
Xchar ch;
X
X	for (i=0; i<OPTIONS; i++)
X	{
X		if (option[i] < 10)
X			ch = '0' + option[i];
X		else
X			ch = 'A' + option[i] - 10;
X		putc(ch,fp);
X	}
X	putc('\n',fp);
X}
X
Xcti(c)
Xchar c;
X{
X	if (c <= '9')
X		return(c-'0');
X	else
X		return(c-'A'+10);
X}
X
X
X/* PLACE()
X *
X *   Place a piece.  return TRUE if syntax is ok.
X */
X
Xboolean place(bd,type,coord)
Xschar bd[R_SIZE][C_SIZE];
Xchar type;
Xchar *coord;
X{
Xint i,r,c;
X
X	for (i=0; pc[i] != 0 && pc[i] != type; i++);
X	if (pc[i] == 0) return (FALSE);
X
X	c = coord[0] - ((coord[0] >= 'a') ? 'a' : 'A');
X	r = coord[1] - '1';
X
X	if ( r < 0 || c < 0 || r > Rows || c > Cols ) return(FALSE);
X
X	bd[r][c] = i - PIECES;
X	return(TRUE);
X}
X
X
X/* MCONV()
X *
X *   Convert a character string <buf> to a move.
X *   Return FALSE if the syntax is bad.
X */
X
Xmconv(buf,fr,fc,tr,tc)
Xchar *buf;
Xint *fr,*fc,*tr,*tc;		/* from (row, column) to (row, column) */
X{
X	if (buf[0] >= 'a')
X		*fc = buf[0] - 'a';
X	else	*fc = buf[0] - 'A';
X	*fr = buf[1] - '1';
X	if (buf[3] >= 'a')
X		*tc = buf[3] - 'a';
X	else	*tc = buf[3] - 'A';
X	*tr = (buf[4] - '1');
X
X	if ( (*fr > Rows) || (*tr > Rows) || (*tc > Cols) || (*fc > Cols) ||
X	     (*fr < 0) || (*tr < 0) || (*tc < 0) || (*fc < 0) )
X	{
X		errcode = E_SY;
X		return(FALSE);
X	}
X	
X	return(TRUE);
X}
X
X
X/* CCTRANS()
X *
X *   Print a cchess style transcript of the game to the output device
X *   <tfp>.  Include comments if the flag <comments> is TRUE.  ttymodes
X *   should be normal when this is called.
X */
X
Xstatic char tbuf[81];		/* Buffer for transcript line */
Xstatic int fc;			/* Field counter 1=white, 2=black, 3=comment */
Xstatic int omovecnt;		/* Last move printed */
X
Xcctrans(tfp,comments,masked)
XFILE *tfp;
Xboolean comments,masked;
X{
Xboolean private,illegal = FALSE;
X
X    fc = 0;
X    omovecnt = movecnt = -1;
X    rewind(rfp);
X
X    while (fgetl(mbuffer,MB_LEN,rfp)!=NULL)
X
X	switch (mbuffer[C_CMD])
X	{
X	case 'C':	/* read challenge line */
X
X		if (cti(mbuffer[C_MOV+OP_COLOR]))
X			mycolor = order * WHITE;
X		else
X			mycolor = order * BLACK;
X
X		piecename = chessname[cti(mbuffer[C_MOV+OP_NAMES])];
X		private = (boolean) cti(mbuffer[C_MOV+OP_PRIVATE]);
X		illegal = (boolean) cti(mbuffer[C_MOV+OP_VISIB]);
X		hidden = illegal && masked;
X
X		break;
X
X	case 'A':	/* read accept line */
X
X		/* Ask if illegal moves should be printed */
X		if (illegal)
X		{
X			wprint("Do you want illegal moves included? ");
X			illegal = enterdyn(FALSE);
X			
X		}
X		clr();
X		if (private && kibitz)
X		{
X			wprint("Sorry, that is a private game.\n");
X			return;
X		}
X
X		/* Return to normal tty modes */
X		resetty();
X
X		fprintf(tfp,"     WHITE    BLACK\n     %-8s %-8s\n",
X			mycolor==WHITE ? myid:hisid,
X			mycolor==BLACK ? myid:hisid);
X		if (comments)
X			fprintf(tfp,"------------------------------------------------------------------------------\n");
X		else
X			fprintf(tfp,"---------------------\n");
X			
X		toplay = WHITE;
X	        movecnt = 0;
X		break;
X
X	case 'P':
X		if (movecnt >= 0)
X		{
X			sprintf(sbuffer,"(Pawn promoted to %s)",
X			    piecename[PIECES-(index(pc,mbuffer[C_MOV])-pc)]);
X			ptfcom(tfp,sbuffer);
X		}
X		break;
X
X	case 'M':
X		/* Don't show other player moves in kriegspiel */
X		if (hidden && !kibitz && toplay != mycolor)
X		{
X			mbuffer[C_MOV+0] = '?'; mbuffer[C_MOV+1] = '?';
X			mbuffer[C_MOV+3] = '?'; mbuffer[C_MOV+4] = '?';
X		}
X	case 'F':
X	case 'D':
X	case 'Y':
X	case 'N':
X	case 'K':
X		if (!comments) mbuffer[C_FLG] = '\0';
X
X		ptfmove(tfp,toplay,mbuffer+C_MOV,FALSE);
X
X		if (mbuffer[C_FLG] != '\0')
X			ptfcom(tfp,mbuffer+C_COM);
X
X		++movecnt;
X		toplay = -toplay;	/* Other color plays next */
X		break;
X	case 'I':
X		if (!illegal || (hidden && !kibitz && toplay != mycolor))
X			break;
X	case 'm':
X		/* Don't show other player moves in kriegspiel */
X		if (hidden && !kibitz && toplay != mycolor)
X		{
X			mbuffer[C_MOV+0] = '?'; mbuffer[C_MOV+1] = '?';
X			mbuffer[C_MOV+3] = '?'; mbuffer[C_MOV+4] = '?';
X		}
X		/* Print the move */
X		ptfmove(tfp,toplay,mbuffer+C_MOV,mbuffer[C_CMD] == 'I');
X		break;
X	}
X	/* Flush last line out */
X	if (fc > 0)
X		fprintf(tfp,"%s\n",tbuf);
X}
X
Xptfmove(tfp,co,mv,ill)
XFILE *tfp;
Xschar co;
Xchar *mv;
Xboolean ill;
X{
Xchar *c;
X
X	/* Print previous line if new field doesn't fit on */
X	if (fc > (co == BLACK))
X	{
X		fprintf(tfp,"%s\n",tbuf);
X		fc = 0;
X	}
X
X	if (co == WHITE)
X	{
X		/* Print number if different from last number printed */
X		if (movecnt != omovecnt)
X			sprintf(tbuf,"%3d:",(omovecnt = movecnt)/2+1);
X		else
X			strcpy(tbuf,blanks(4));
X
X		c = tbuf+4;
X		fc = 1;
X	}
X	else
X	{
X		/* Pad with blanks if necessary */
X		if (fc < 1)
X			strcpy(tbuf,blanks(11));
X		tbuf[11] = tbuf[12] = ' ';
X		c = tbuf+13;
X		fc = 2;
X	}
X	/* punch the move into the buffer */
X	sprintf(c, ill ? "(%5.5s)" : " %5.5s ", mv);
X}
X
Xptfcom(tfp,com)
XFILE *tfp;
Xchar *com;
X{
Xregister int i,j;
X
X	/* Print previous line if new field doesn't fit on */
X	if (fc > 2)
X	{
X		fprintf(tfp,"%s\n",tbuf);
X		fc = 0;
X	}
X
X	/* Pad up to comments column with blanks */
X	i = (fc == 0) ? 22 : ((fc == 1) ? 11 : 2);
X	strcpy(tbuf+22-i,blanks(i));
X	fc = 3;
X
X	/* Put the comment in place */
X	if (strlen(com) > 56)
X	{
X		for (i = 56; i > 0 && com[i] != ' '; i--)
X			;
X		if (i == 0)
X		{
X			i = 56;
X			j = 0;
X		}
X		else
X			j = 1;
X		strncpy(tbuf+22,com,i);
X		tbuf[23+i] = '\0';
X		ptfcom(tfp,com+i+j);
X	}
X	else
X		strcpy(tbuf+22,com);
X}
X
X/* PCOL(), PMAN(), PCOLMAN()
X *
X * These are routines to write out the names of colors and men.
X */
X
Xchar *pcol(p)
Xschar p;
X{
X	if (p == 0)
X		return("");
X	else
X		return((p > 0)?"White":"Black");
X}
X
Xchar *pcapcol(p)
Xschar p;
X{
X	if (p == 0)
X		return("");
X	else
X		return((p > 0)?"white":"BLACK");
X}
X
Xchar *pman(p)
Xschar p;
X{
X	return (piecename[abs(p)]);
X}
X
Xchar *pcolman(p)
Xschar p;
X{
Xstatic char buf[18];
X
X	if (p == 0) return(piecename[p]);
X	sprintf(buf,"%s %s", ((p > 0)?"White":"Black"), piecename[abs(p)]);
X	return(buf);
X}
X
Xchar *yorn(f)
Xboolean f;
X{
X	return(f?"Yes":"No");
X}
END_OF_misc.c
if test 31437 -ne `wc -c <misc.c`; then
    echo shar: \"misc.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f scrn.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"scrn.c\"
else
echo shar: Extracting \"scrn.c\" \(17208 characters\)
sed "s/^X//" >scrn.c <<'END_OF_scrn.c'
X/* CCHESS SCREEN ROUTINES.					Version 1.00
X *
X *   This is mostly low level i/o stuff to interface to the TERMCAP library.
X *   In case you are planning to steal this code for another application, be
X *   careful of wputchar().  It has a lot of scrolling features custom made
X *   for cchess's screen handling style (i.e. the top of the screen held
X *   fixed, and the bottom half scrolled.
X *
X *   (C) Copyright Jan Wolter - Apr 1986.
X */
X
X#include "cchess.h"
X
X/* Stuff for the termcap library */
X
X#ifndef NOTERMCAP
Xextern short ospeed;		/* The output baud rate */
Xstatic char PC= '\000';		/* The pad characters (default ^@) */
Xstatic boolean AM;		/* Does terminal have automatic margins? */
Xstatic boolean BW;		/* Does terminal wrap on backspaces? */
Xstatic char area[1024];		/* Memory to store the following: */
Xstatic char *BC;		/* The backspace string (default `\b`) */
X       char *BL;		/* The bell character */
Xstatic char *CD;		/* The clear to bottom of screen string */
X       char *CE;		/* The clear to end of line string */
Xstatic char *CL;		/* The clear screen string */
Xstatic char *CM;		/* The cursor move string */
Xstatic char *CR;		/* The carriage return string */
X       char *DL;		/* The delete line string */
Xstatic char *DO;		/* The cursor down string */
Xstatic char *HO;		/* The home cursor string */
Xstatic char *ND;		/* The cursor right string */
Xstatic char *SE;		/* The end stand out mode string */
Xstatic char *SO;		/* The start stand out mode string */
Xstatic char *TE;		/* Terminal uninitialization string */
Xstatic char *TI;		/* Terminal initialization string */
Xstatic char *UP;		/* The cursor up string */
Xextern char *tgetstr(), *tgoto(), *getenv();
Xextern char *malloc();
X#endif NOTERMCAP
X
X
X/* READTERM()
X *
X *   Read in terminal capabilities description (termcap).  Terminal type is
X *   obtained from $TERM environment variable.  All sorts of funny stuff is
X *   set up here.
X */
X
Xreadterm()
X{
X#ifndef NOTERMCAP
Xregister char *bp, *pad;
Xchar *tp;
X#endif NOTERMCAP
X
X	/* Innocent until proven guilty */
X	issmart = FALSE;
X	erases = TRUE;
X	cleardown = FALSE;
X
X#ifndef NOTERMCAP
X	/* Get the termcap entry */
X	bp = (char *) malloc(1024);
X	if (tgetent(bp,getenv("TERM")) != 1)
X	{
X		/* No termcap: */
X		/* assume you can backspace with ^H, return with ^M */
X		free(bp);
X		area[0] = '\b'; area[1] = '\0'; area[2] = '\r'; area[3] = '\0';
X		area[4] = '\007'; area[5] = '\0';
X		BC = area;		/* Backspace with ^H */
X		CL = area+1;		/* Clear is null string */
X		CR = area+2;		/* Carraige return with ^M */
X		BL = area+4;		/* Ring with ^G */
X		BW = TRUE;		/* You wrap on left side */
X		AM = TRUE;		/* You wrap on right side */
X		return;
X	}
X
X	/* Load the pad character for tputs.  Default to null. */
X	tp = area;
X	if(pad = tgetstr("pc",&tp))
X		PC = *pad;
X
X	/* Get the clear screen string.  Null string if undefined. */
X	if (!(CL = tgetstr("cl",&tp)))
X	{
X		CL = tp;
X		*tp++ = '\000';
X	}
X
X	/* Don't absolutely need these, but they may prove useful */
X	SO = tgetstr("so",&tp);		/* Start standout mode */
X	SE = tgetstr("se",&tp);		/* End standout mode */
X	AM = tgetflag("am");		/* Automatic margins? */
X	BW = tgetflag("bw");		/* Backspace wraps? */
X	if(!SO || !SE) SO = SE = 0;
X
X	/* Get number of lines and columns. */
X#ifdef U43BSD
X	getwindow();
X	if (COLS == 0)
X	{
X#endif U43BSD
X	    LINES = tgetnum("li");
X	    if (LINES < 20) LINES = 0;  /* Treat short screens like teletypes */
X	    COLS = tgetnum("co");
X	    if (COLS < 0) COLS = 40;  /* Default to 40 if not defined. */
X#ifdef U43BSD
X	}
X#endif U43BSD
X	if (COLS < 22)
X	{
X		printf("Cchess requires at least a 22 column terminal.\n");
X		exit(1);
X	}
X	/* Believe it or not, there are 22 column terminals in the world. */
X	/* Do some special stuff to make them work.  24 and above is fine */
X	commodore = (COLS < 24);
X
X	/* Get the backspace string */
X	if (tgetflag("bs"))
X	{
X		BC = tp;
X		*tp++ = '\b';
X		*tp++ = '\000';
X	}
X	else if (!(BC = tgetstr("bc",&tp)))
X		BC = tgetstr("le",&tp);
X
X	/* Get the bell string, prefering visual bell if it is there */
X	if (!(BL = tgetstr("vb",&tp)) && !(BL = tgetstr("bl",&tp)))
X	{
X		BL = tp;
X		*tp++ = '\007';
X		*tp++ = '\000';
X	}
X
X	/* Get the carriage return string */
X	if (tgetflag("nc"))
X		CR = (char *) 0;
X	else if (!(CR = tgetstr("cr",&tp)))
X	{
X		CR = tp;
X		*tp++ = '\r';
X		*tp++ = '\000';
X	}
X
X	/* Does this critter backspace in a useful way? */
X	erases = BC && !tgetflag("os") && !tgetflag("hc");
X
X	/* If it's not obviously brain-damaged, see if it is smart */
X	if (LINES != 0 && erases && *CL != 0)
X	{
X		/* Get the strings we need to be smart */
X		CM = tgetstr("cm",&tp);		/* Cursor Addressing */
X		HO = tgetstr("ho",&tp);		/* Home Cursor */
X		DO = tgetstr("do",&tp);		/* Cursor Down */
X		ND = tgetstr("nd",&tp);		/* Cursor Right */
X		UP = tgetstr("up",&tp);		/* Move cursor up */
X		/* Are we smart? */
X		if (issmart = (CM || ((HO || UP) && DO && ND)))
X		{
X			/* Get strings we can use if we are smart */
X			CD = tgetstr("cd",&tp);	   /* Clear rest of screen */
X			CE = tgetstr("ce",&tp);	   /* Clear rest of line */
X			cleardown = CD || CE;
X			DL = tgetstr("dl",&tp);	   /* Delete line */
X			TI = tgetstr("ti",&tp);	   /* Initialize */
X			TE = tgetstr("te",&tp);	   /* Uninitialize */
X		}
X	}
X
X	/* Check if termcap buffer overflowed.  Free memory */
X	if (tp-area > sizeof(area))
X	{
X		printf("Panic: Termcap too big.  %d bytes.\n",tp-area);
X		exit(1);
X	}
X	free(bp);
X	term_init();
X#endif NOTERMCAP
X}
X
X/* TERM_INIT(), TERM_EXIT()
X *
X * Put the terminal in to or out of visual mode.
X */
X
Xterm_init()
X{
X#ifndef NOTERMCAP
X	if (TI) xputs(TI);
X#endif NOTERMCAP
X}
X
Xterm_exit()
X{
X#ifndef NOTERMCAP
X	if (TE) xputs(TE);
X#endif NOTERMCAP
X}
X
X
X#ifndef NOTERMCAP
X/* XPUTC()
X *
X *   putchar() is a macro.  We need a real subroutine to use with tputs.
X *   This is it.
X */
X
Xint xputc(ch)
Xchar ch;
X{
X	putchar(ch);
X}
X
X/* XPUTS()
X *
X *   send out a control sequence.
X */
Xxputs(s)
Xchar *s;
X{
X	(void) tputs(s, 1, xputc);
X}
X
X/* NXPUTS()
X *
X *   Put out the same control sequence <s> n times.
X */
X
Xnxputs(s,n)
Xchar *s;
XREGISTER int n;
X{
X	for ( ; n > 0; n--)
X		(void) tputs(s, 1, xputc);
X}
X
X/* CMMOVE()
X *
X * Use the "cm" string to do direct cursor motion.  Don't call this.  Use
X * calls to the higher level cursor() routine instead.
X */
X
Xcmmove(x,y)
XREGISTER int x,y;
X{
X	xputs(tgoto(CM,x-1,y-1));
X	cx = x;
X	cy = y;
X}
X
X/* CURSOR()
X *   Move the cursor to line <y> and column <x>.  If the current positions are
X *   negative, the cursor position is unknown, and an absolute move is made to
X *   locate them.  Otherwise, whichever of the availble capabilities gives the
X *   fastest move are used (well, almost).  If the move cannot be made, this
X *   routine returns FALSE.  If you have CM or (HO and DO and ND) all moves
X *   should be possible.  If the current position is always known, UP will
X *   substitute for HO.  A boolean is returned to indicate the success or
X *   failure of the move.
X */
X
Xcursor(x,y)
XREGISTER int x,y;
X{
X	/* If cursor position is unknown, put it in a known position */
X	if (cy < 0)
X	{
X		if (x < 3 && y < 3 && HO && DO && ND)
X			xputs(HO);
X		else if (CM)
X		{
X			cmmove(x,y);
X			return (TRUE);
X		}
X		else if (HO && DO && ND)
X			xputs(HO);
X		else
X			return(FALSE);
X	}
X	else if (cx < 0)
X	{
X		if (x < 3 && CR && ND)
X			xputs(CR);
X		else if (CM)
X		{
X			cmmove(x,y);
X			return (TRUE);
X		}
X		else if (CR && ND)
X			xputs(CR);
X		else
X			return (FALSE);
X		cx = 1;
X	}
X
X	/* Do the vertical movement */
X	if (vcursor(x,y))
X	{
X		/* Do the horizontal movement */
X
X		/* If we are already where we want, do nothing */
X		if (cx == x) return(TRUE);
X
X		/* Move cursor left */
X		if (cx > x)
X		{
X			if ((!CM || cx - x < 3) && BC)
X			{
X				nxputs(BC,cx - x);
X				cx = x;
X				return(TRUE);
X			}
X			if ((x < 3 || !CM) && ND && CR)
X			{
X				xputs(CR);
X				cx = 1;
X			}
X			else if (CM)
X			{
X				cmmove(x,y);
X				return(TRUE);
X			}
X			else
X				return(FALSE);
X		}
X		
X		/* Move cursor right */
X
X		if (cx < x)
X		{
X			if (ND && (x - cx < 3 || !CM))
X			{
X				nxputs(ND,x - cx);
X				cx = x;
X				return(TRUE);
X			}
X			if (CM)
X			{
X				cmmove(x,y);
X				return(TRUE);
X			}
X			return(FALSE);
X		}
X		return(TRUE);
X	}
X	else
X		return(FALSE);
X}
X
X/* VCURSOR()
X *
X *   Move the cursor into line <y>.  This routine trys it's best to make the
X *   best use of capabilities available, and to come up with reasonably
X *   efficient moves.  It ain't perfect.  Beware of convoluted logic.
X */
X
Xvcursor(x,y)
XREGISTER int x,y;
X{
X	/* If already in the goal line, return */
X	if (cy == y) return(TRUE);
X
X	/* Move upwards */
X	if (y < cy)
X	{
X		if (UP && cy - y < 3 && abs(cx - x) < 3)
X		{
X			nxputs(UP,cy - y);
X			cy = y;
X			return(TRUE);
X		}
X		if (HO && ((x<3 && y<3) || (!CM && !UP)))
X			xputs(HO);
X		else if (CM)
X		{
X			cmmove(x,y);
X			return (TRUE);
X		}
X		else if (UP)
X		{
X			nxputs(UP,cy - y);
X			cy = y;
X			return(TRUE);
X		}
X		else
X			return (FALSE);
X	}
X	
X	/* Move downwards */
X
X	if (y > cy)
X	{
X		if (DO && ((y - cy < 3 && abs(x-cx) < 3) || !CM))
X		{
X			nxputs(DO,y - cy);
X			cy = y;
X			return(TRUE);
X		}
X		if (CM)
X		{
X			cmmove(x,y);
X			return(TRUE);
X		}
X		return (FALSE);
X	}
X	return(TRUE);
X}
X
X
X/* CLINE()
X *
X *   Clear to the end of the line.  Leave the cursor where it was.  Should
X *   only be called if the CE string is defined, or the terminal erases.
X */
X
Xcline()
X{
Xshort ox;
X	if (CE)
X		xputs(CE);	/* Use the clear to end of line cmd */
X	else if (erases)
X	{
X		ox = cx;	/* Use overprinted spaces */
X		for ( ; cx < COLS; cx++)
X			putchar(' ');
X		cursor(ox,cy);
X	}
X}
X
X/* CLBOT()
X *
X *   Clear to the bottom of the display.  Leave the cursor where it was.  Should
X *   only be called if the CD string is defined, or the terminal is smart and
X *   erases.  If the CE and CD strings are both missing, this can be very slow,
X *   since it will then do the whole thing with spaces.
X */
X
Xclbot()
X{
Xregister short ox,oy;
X
X	if (CD)
X	{
X		if (cx == 1)
X			xputs(CD);
X		else
X		{
X			/* CD can only be used from the beginning of a line */
X			cline();
X			if (cy < LINES)
X			{
X				ox = cx;
X				oy = cy;
X				wputchar('\n');
X				xputs(CD);
X				cursor(ox,oy);
X			}
X		}
X	}
X	else if (issmart)
X	{
X		ox = cx;
X		oy = cy;
X		cline();
X		while (cy < LINES)
X		{
X			wputchar('\n');
X			cline();
X		}
X		cursor(ox,oy);
X	}
X}
X
X
X/* DELINE()
X *
X *   This deletes the line <n> from the display.  It should be called only if
X *   the DL string is defined, and the terminal is SMART (ie, can move it's
X *   cursors wherever necessary).  The cursor is returned to the place it came
X *   from afterwards.
X */
X
Xdeline(n)
Xshort n;
X{
Xshort ox=cx,oy=cy;		/* Save the old position */
X	vcursor(1,n);		/* Get the cursor into line n */
X	xputs(DL);		/* Delete the line */
X	if (oy == n) ox = 0;	/* If deleted current line */
X	else if (oy > n) oy--;	/* Old position may scroll up */
X	cursor(ox,oy);		/* Put the cursor back */
X}
X#endif NOTERMCAP
X
X
X/* BEG_SO(), END_SO()
X *
X *   Enter and exit standout mode.
X */
X
Xbeg_so()
X{
X#ifndef NOTERMCAP
X	if(SO) xputs(SO);
X#endif NOTERMCAP
X}
X
Xend_so()
X{
X#ifndef NOTERMCAP
X	if(SE) xputs(SE);
X#endif NOTERMCAP
X}
X
X
X/* INDENT()
X *
X *   This routine indents <n> spaces on the current line.  It works for any
X *   terminal.  It may use spaces.  <n> is assumed to be less than COLS and
X *   BLANK_LEN.  If cx > 1 before entry, the indent will be on the next line,
X *   not this line.
X */
X
Xindent(n)
Xint n;
X{
X#ifndef NOTERMCAP
X	if (n < 3 || !issmart)
X	{
X#endif
X		if (cx > 1) wputchar('\n');
X		printf(blanks(n));
X		cx = n+1;
X#ifndef NOTERMCAP
X	}
X	else
X		cursor(n+1, cy + (cx > 1));
X#endif NOTERMCAP
X}
X
X/* BACKSPACE()
X *
X *   This sends a backspace, and updates the current cursor position.
X *   It fixes terminals that don't wrap on backspace to do so, if possible.
X */
X
Xbackspace()
X{
X#ifndef NOTERMCAP
X	if (!BC)
X	{
X		wputchar('<');	/* Can't backspace.  Make a mark instead. */
X		return;
X	}
X	if (cx-- == 1)
X	{
X		if (cy > 1)
X		{
X			/* Wrap back to previous line */
X			if (BW)
X			{
X				xputs(BC);		/* use backspace */
X				cx = COLS;
X				--cy;
X			}
X			else if (issmart) 
X				cursor(COLS,cy-1);	/* use cursor motion */
X			else 
X				cx++;	     /* Can't backspace--do nothing */
X		}
X		else
X			cx = 1;		/* At home position.  Do nothing */
X	}
X	else
X		xputs(BC);		/* Ordinary backspacing */
X#else
X	putchar('\b');
X#endif NOTERMCAP
X}
X
Xbell()
X{
X#ifndef NOTERMCAP
X	xputs(BL);
X#else
X	putchar('\007');
X#endif NOTERMCAP
X}
X
X
X/* CLR()
X *
X *   Clear the screen.  If we have the termcap library, use tputs.
X *   Otherwise, just make a note to redraw next time we need to.
X */
X
Xextern short movelen;
Xclr()
X{
X#ifndef NOTERMCAP
X	tputs(CL,LINES,xputc);
X#endif NOTERMCAP
X	cx = cy = 1;
X	scrolled = FALSE;
X	movelen = 0;
X}
X
X
X/* WPUTCHAR()
X *
X *   This routine is like putchar(), but it updates the current cursor position.
X *   It doesn't know about tabs or returns, and should not be sent any.  It
X *   Does handle backspaces and newlines.  The latter are output as carriage-
X *   return-newline combinations.  If the terminal doesn't have automatic
X *   margins, it fakes them.
X */
X
Xwputchar(c)
Xchar c;
X{
X#ifdef NOTERMCAP
X	if (c == '\n')
X		putchar('\r');
X	putchar(c);
X#else
X	/* If a backspace, do it */
X	if (c == '\b')
X		backspace();
X	/* If newline or auto-newline due to typing past last column */
X	else if (c == '\n' || ++cx > COLS)
X	{
X		if (cy == LINES)	/* this should NOT be ">=" */
X		{
X			if (msgarea == 0)
X			{
X				scrolled = TRUE;
X				cy--;
X			}
X			else if (DL)
X				deline(msgarea);
X			else if (cleardown)
X			{
X				cursor(1,msgarea);
X				clbot();
X				return;
X			}
X			else
X			{
X				scrolled = TRUE;
X				cy--;
X			}
X		}
X
X		/* If autowrapping, send character first */
X		if (c != '\n')
X			putchar(c);
X		/* Send the newline, unless automatic margins do it for us */
X		if (c == '\n' || !AM)
X		{
X			if (CR)
X				xputs(CR);
X			else
X				cursor(1,cy);
X			putchar('\n');	/* Don't want to have DO here */
X		}
X		cx = 1;
X		cy++;
X	}
X	else
X		putchar(c);
X#endif NOTERMCAP
X}
X
X/* WPRINTF()
X *
X *   This routine is like printf(), but it updates the cursor position, and can
X *   take at most five arguments.  The wprint() routine is the same, but takes
X *   no arguments.
X */
X
X/*VARARGS1*/ wprintf(str,arg1,arg2,arg3,arg4,arg5)
Xchar *str,*arg1,*arg2,*arg3,*arg4,*arg5;
X{
Xchar buf[MB_LEN];
X
X	sprintf(buf,str,arg1,arg2,arg3,arg4,arg5);
X	wprint(buf);
X}
X
Xwprint(str)
Xchar *str;
X{
X	for ( ; *str != 0; str++)
X		wputchar(*str);
X}
X
X/* MPRINTF()
X *
X * This is like wprintf(), except it plays games kind of like more in
X * the message area.  To use it, first call initmore() to set up the
X * message area for moring.  Space, Newline and 'Q' are accepted at the
X * more prompt and do the usual things.  It erases the more prompts if
X * the terminal has any brains at all.
X */
X
Xstatic int morespace,morecount;
Xstatic boolean domore;
X
Xinitmore()
X{
X#ifndef NOTERMCAP
X	/* Try to make room in the message area */
X	if (!DL && cleardown)
X	{
X		cursor(1,msgarea);
X		clbot();
X	}
X	if (LINES)
X		morecount = morespace = LINES - msgarea;
X	else
X		morecount = -2;		/* Don't "more" on teletypes */
X	domore = FALSE;
X#endif NOTERMCAP
X}
X
X/*VARARGS1*/ mprintf(str,arg1,arg2,arg3,arg4)
Xchar *str,*arg1,*arg2,*arg3,*arg4;
X{
Xchar buf[MB_LEN];
X
X	sprintf(buf,str,arg1,arg2,arg3,arg4);
X	mprint(buf);
X}
X
Xmprint(str)
Xchar *str;
X{
X#ifndef NOTERMCAP
Xchar c,p;
X
X	if (morecount == -1) return;
X
X	while (*str != '\000')
X	{
X		if (cx == COLS)
X			c = '\n';
X		else
X			c = *str++;
X
X		if (domore)
X		{
X			beg_so();
X			wprint("--More--");
X			end_so();
X			p = xenter(" Q\n");
X			/* Erase More Prompt */
X			if (DL && (CE || erases))
X			{
X				cursor(1,cy);
X				cline();
X			}
X			else
X				wputchar('\n');
X
X			domore = FALSE;
X			if (p == 'Q')
X			{
X				/* Ignore mprint calls until next initmore */
X				morecount = -1;
X				return;
X			}
X			else if (DL && p == '\n')
X				morecount = 1;
X			else
X				morecount = morespace;
X		}
X
X		wputchar(c);
X
X		if (c == '\n' && --morecount == 0)
X			domore = TRUE;
X	}
X
X#else
X	while (*str != '\000')
X		wputchar(*str++);
X#endif NOTERMCAP
X}
X
X
X/* CPRINTF()
X *
X *   Print string <st> centered on the screen.  Up to five arguments can be used
X *   as in printf.  No newline is added at the end.  If the line is longer than
X *   the screen, is it is broken up as well as possible, and each chunk is
X *   centered.  This routine is weird.  Cprint is simlar, but takes no
X *   arguments.  Oh yes, if the first character is a *, the message is printed
X *   in standout mode.
X */
X
X/*VARARGS1*/ cprintf(str,arg1,arg2,arg3,arg4)
Xchar *str,*arg1,*arg2,*arg3,*arg4;
X{
Xchar buf[MB_LEN+10];
X
X	sprintf(buf,str,arg1,arg2,arg3,arg4);
X	cprint(buf);
X}
X
Xcprint(c)
XREGISTER char *c;
X{
Xchar pop = 0;
Xboolean standout;
Xregister int n;
X
X	if (standout = (*c == '*')) c++;
X		
X	for(;;)
X	{
X		if ((n = strlen(c)) > COLS)
X		{
X			n = findbreak(c,COLS-1);
X			pop = c[n];
X			c[n] = '\000';
X		}
X		indent((int)(COLS-n)/2);
X
X		if (standout) beg_so();
X		wprint(c);
X		if (standout) end_so();
X
X		if (pop == 0)
X			break;
X		else
X		{
X			c[n] = pop;
X			c = c + n;
X			while (*c != 0 && (*c == ' ' || *c == '\t')) c++;
X			pop = 0;
X		}
X	}
X}
X
X/* FINDBREAK()
X *
X *   Find a place for a word break just before column <n> of the string <s>.
X *   If no break is found within 20 characters, column n is returned.
X */
X
Xint findbreak(s,n)
Xchar *s;
XREGISTER int n;
X{
Xregister int i;
Xchar c;
X	for (i = 0; i < 20 && i < n ; i++)
X	{
X		if ((c = s[n-i]) == ' ' || c == '\t')
X			return(n-i);
X	}
X	return(n);
X}
END_OF_scrn.c
if test 17208 -ne `wc -c <scrn.c`; then
    echo shar: \"scrn.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
echo shar: End of archive 1 \(of 5\).
cp /dev/null ark1isdone
MISSING=""
for I in 1 2 3 4 5 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 5 archives.
    rm -f ark[1-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0