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