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