[comp.sources.games] v02i095: nchess - network chess game for Suns

games-request@tekred.TEK.COM (11/25/87)

Submitted by: (Tom Anderson) toma@tc.fluke.com
Comp.sources.games: Volume 2, Issue 95
Archive-name: nchess/Part03a

#! /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 3 (of 4)."
# Contents:  Icons/bishopStencil.icon Icons/knightStencil.icon
#   Icons/queenStencil.icon Icons/rookStencil.icon chessprocess.c
#   controlsw.c daemon.c decls.h ipc.c main.c msgsw.c tool.c
# Wrapped by billr@tekred on Thu Nov 19 10:49:22 1987
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f Icons/bishopStencil.icon -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"Icons/bishopStencil.icon\"
else
echo shar: Extracting \"Icons/bishopStencil.icon\" \(1933 characters\)
sed "s/^X//" >Icons/bishopStencil.icon <<'END_OF_Icons/bishopStencil.icon'
X/* Format_version=1, Width=64, Height=64, Depth=1, Valid_bits_per_item=16
X */
X	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
X	0x0000,0x0000,0x0000,0x0000,0x0000,0x000C,0x3000,0x0000,
X	0x0000,0x001E,0x7800,0x0000,0x0000,0x001E,0x7800,0x0000,
X	0x0000,0x003F,0xFC00,0x0000,0x0000,0x007F,0xFE00,0x0000,
X	0x0000,0x007F,0xFE00,0x0000,0x0000,0x00FF,0xFF00,0x0000,
X	0x0000,0x00FF,0xFF00,0x0000,0x0000,0x01FF,0xFF80,0x0000,
X	0x0000,0x03FF,0xFFC0,0x0000,0x0000,0x03FF,0xFFC0,0x0000,
X	0x0000,0x07FF,0xFFE0,0x0000,0x0000,0x07FF,0xFFE0,0x0000,
X	0x0000,0x0FFF,0xFFF0,0x0000,0x0000,0x0FFF,0xFFF0,0x0000,
X	0x0000,0x1FFF,0xFFF8,0x0000,0x0000,0x1FFF,0xFFF8,0x0000,
X	0x0000,0x3FFF,0xFFFC,0x0000,0x0000,0x3FFF,0xFFFC,0x0000,
X	0x0000,0x3FFF,0xFFFC,0x0000,0x0000,0x3FFF,0xFFFC,0x0000,
X	0x0000,0x7FFF,0xFFFE,0x0000,0x0000,0x7FFF,0xFFFE,0x0000,
X	0x0000,0x7FFF,0xFFFE,0x0000,0x0000,0x7FFF,0xFFFE,0x0000,
X	0x0000,0x7FFF,0xFFFE,0x0000,0x0000,0x7FFF,0xFFFE,0x0000,
X	0x0000,0x7FFF,0xFFFE,0x0000,0x0000,0x7FFF,0xFFFE,0x0000,
X	0x0000,0x7FFF,0xFFFE,0x0000,0x0000,0x7FFF,0xFFFE,0x0000,
X	0x0000,0x7FFF,0xFFFE,0x0000,0x0000,0x3FFF,0xFFFC,0x0000,
X	0x0000,0x3FFF,0xFFFC,0x0000,0x0000,0x3FFF,0xFFFC,0x0000,
X	0x0000,0x3FFF,0xFFFC,0x0000,0x0000,0x3FFF,0xFFFC,0x0000,
X	0x0000,0x1FFF,0xFFF8,0x0000,0x0000,0x1FFF,0xFFF8,0x0000,
X	0x0000,0x1FFF,0xFFF8,0x0000,0x0000,0x0FFF,0xFFF0,0x0000,
X	0x0000,0x0FFF,0xFFF0,0x0000,0x0000,0x0FFF,0xFFF0,0x0000,
X	0x0000,0x07FF,0xFFE0,0x0000,0x0000,0x07FF,0xFFE0,0x0000,
X	0x0000,0x07FF,0xFFE0,0x0000,0x0000,0x07FF,0xFFE0,0x0000,
X	0x0000,0x07FF,0xFFE0,0x0000,0x0000,0xFFFF,0xFFFF,0x0000,
X	0x0001,0xFFFF,0xFFFF,0x8000,0x0003,0xFFFF,0xFFFF,0xC000,
X	0x0003,0xFFFF,0xFFFF,0xC000,0x0003,0xFFFF,0xFFFF,0xC000,
X	0x0003,0xFFFF,0xFFFF,0xC000,0x0003,0xFFFF,0xFFFF,0xC000,
X	0x0003,0xFFFF,0xFFFF,0xC000,0x0003,0xFFFF,0xFFFF,0xC000,
X	0x0001,0xFFFF,0xFFFF,0x8000,0x0000,0xFFFF,0xFFFF,0x0000,
X	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000
END_OF_Icons/bishopStencil.icon
if test 1933 -ne `wc -c <Icons/bishopStencil.icon`; then
    echo shar: \"Icons/bishopStencil.icon\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f Icons/knightStencil.icon -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"Icons/knightStencil.icon\"
else
echo shar: Extracting \"Icons/knightStencil.icon\" \(1933 characters\)
sed "s/^X//" >Icons/knightStencil.icon <<'END_OF_Icons/knightStencil.icon'
X/* Format_version=1, Width=64, Height=64, Depth=1, Valid_bits_per_item=16
X */
X	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
X	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
X	0x0000,0x0DB6,0xC000,0x0000,0x0000,0x1FFF,0xE01C,0x0000,
X	0x0001,0x7FFF,0xF8FC,0x0000,0x0001,0xFFFF,0xFBFC,0x0000,
X	0x0002,0xFFFF,0xFFF8,0x0000,0x0005,0xFFFF,0xFFF0,0x0000,
X	0x000F,0xFFFF,0xFFE0,0x0000,0x0017,0xFFFF,0xFFC0,0x0000,
X	0x000F,0xFFFF,0xFFE0,0x0000,0x002F,0xFFFF,0xFFF0,0x0000,
X	0x005F,0xFFFF,0xFFF8,0x0000,0x00BF,0xFFFF,0xFFFC,0x0000,
X	0x00FF,0xFFFF,0xFFFE,0x0000,0x007F,0xFFFF,0xFFFF,0x0000,
X	0x00FF,0xFFFF,0xFFFE,0x0000,0x007F,0xFFFF,0xFFFE,0x0000,
X	0x00FF,0xFFFF,0xFFFE,0x0000,0x017F,0xFFFF,0xFFFF,0x0000,
X	0x00FF,0xFFFF,0xFFFF,0x8000,0x01FF,0xFFFF,0xFFFF,0xC000,
X	0x007F,0xFFFF,0xFFFF,0xE000,0x01FF,0xFFFF,0xFFFF,0xF000,
X	0x00FF,0xFFFF,0xFFFF,0xF800,0x01FF,0xFFFF,0xFFFF,0xF800,
X	0x01FF,0xFFFF,0xFFFF,0xFC00,0x00FF,0xFFFF,0x7FFF,0xFC00,
X	0x01FF,0xFFFF,0x9FFF,0xFC00,0x01FF,0xFFFF,0xC07F,0xFC00,
X	0x00FF,0xFFFF,0xC01F,0xF800,0x01FF,0xFFFF,0xE00F,0xF000,
X	0x01FF,0xFFFF,0xE007,0xC000,0x00FF,0xFFFF,0xF003,0x8000,
X	0x01FF,0xFFFF,0xF800,0x0000,0x01FF,0xFFFF,0xFC00,0x0000,
X	0x00FF,0xFFFF,0xFE00,0x0000,0x01FF,0xFFFF,0xFE00,0x0000,
X	0x01FF,0xFFFF,0xFF00,0x0000,0x00FF,0xFFFF,0xFF80,0x0000,
X	0x00BF,0xFFFF,0xFF80,0x0000,0x007F,0xFFFF,0xFFC0,0x0000,
X	0x003F,0xFFFF,0xFFC0,0x0000,0x002F,0xFFFF,0xFFE0,0x0000,
X	0x003F,0xFFFF,0xFFF0,0x0000,0x000F,0xFFFF,0xFFF8,0x0000,
X	0x001F,0xFFFF,0xFFF8,0x0000,0x001F,0xFFFF,0xFFFC,0x0000,
X	0x0007,0xFFFF,0xFFFE,0x0000,0x0000,0xFFFF,0xFFFF,0x0000,
X	0x0001,0xFFFF,0xFFFF,0x8000,0x0003,0xFFFF,0xFFFF,0xC000,
X	0x0003,0xFFFF,0xFFFF,0xC000,0x0003,0xFFFF,0xFFFF,0xC000,
X	0x0003,0xFFFF,0xFFFF,0xC000,0x0003,0xFFFF,0xFFFF,0xC000,
X	0x0003,0xFFFF,0xFFFF,0xC000,0x0003,0xFFFF,0xFFFF,0xC000,
X	0x0001,0xFFFF,0xFFFF,0x8000,0x0000,0xFFFF,0xFFFF,0x0000,
X	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000
END_OF_Icons/knightStencil.icon
if test 1933 -ne `wc -c <Icons/knightStencil.icon`; then
    echo shar: \"Icons/knightStencil.icon\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f Icons/queenStencil.icon -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"Icons/queenStencil.icon\"
else
echo shar: Extracting \"Icons/queenStencil.icon\" \(1933 characters\)
sed "s/^X//" >Icons/queenStencil.icon <<'END_OF_Icons/queenStencil.icon'
X/* Format_version=1, Width=64, Height=64, Depth=1, Valid_bits_per_item=16
X */
X	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
X	0x0000,0x0000,0x0000,0x0000,0x0000,0x0001,0x8000,0x0000,
X	0x0000,0x0003,0xC000,0x0000,0x0000,0x0003,0xC000,0x0000,
X	0x0000,0x0007,0xE000,0x0000,0x0000,0x0007,0xE000,0x0000,
X	0x0000,0x000F,0xF000,0x0000,0x0000,0x000F,0xF000,0x0000,
X	0x0000,0x001F,0xF800,0x0000,0x0000,0x001F,0xF800,0x0000,
X	0x0000,0x003F,0xFC00,0x0000,0x0000,0x003F,0xFC00,0x0000,
X	0x0000,0x007F,0xFE00,0x0000,0x0000,0x007F,0xFE00,0x0000,
X	0x0000,0x00FF,0xFF00,0x0000,0x0040,0x00FF,0xFF00,0x0200,
X	0x0060,0x01FF,0xFF80,0x0600,0x0070,0x01FF,0xFF80,0x0E00,
X	0x0078,0x03FF,0xFFC0,0x1E00,0x007C,0x03FF,0xFFC0,0x3E00,
X	0x007E,0x07FF,0xFFE0,0x7E00,0x007E,0x07FF,0xFFE0,0x7E00,
X	0x003F,0x0FFF,0xFFF0,0xFC00,0x003F,0x8FFF,0xFFF1,0xFC00,
X	0x003F,0xDFFF,0xFFFB,0xFC00,0x003F,0xDFFF,0xFFFB,0xFC00,
X	0x001F,0xFFFF,0xFFFF,0xF800,0x001F,0xFFFF,0xFFFF,0xF800,
X	0x001F,0xFFFF,0xFFFF,0xF800,0x001F,0xFFFF,0xFFFF,0xF800,
X	0x000F,0xFFFF,0xFFFF,0xF000,0x000F,0xFFFF,0xFFFF,0xF000,
X	0x000F,0xFFFF,0xFFFF,0xF000,0x000F,0xFFFF,0xFFFF,0xF000,
X	0x000F,0xFFFF,0xFFFF,0xF000,0x0007,0xFFFF,0xFFFF,0xE000,
X	0x0007,0xFFFF,0xFFFF,0xE000,0x0007,0xFFFF,0xFFFF,0xE000,
X	0x0007,0xFFFF,0xFFFF,0xE000,0x0003,0xFFFF,0xFFFF,0xC000,
X	0x0003,0xFFFF,0xFFFF,0xC000,0x0003,0xFFFF,0xFFFF,0xC000,
X	0x0003,0xFFFF,0xFFFF,0xC000,0x0001,0xFFFF,0xFFFF,0x8000,
X	0x0001,0xFFFF,0xFFFF,0x8000,0x0001,0xFFFF,0xFFFF,0x8000,
X	0x0001,0xFFFF,0xFFFF,0x8000,0x0000,0xFFFF,0xFFFF,0x0000,
X	0x0000,0xFFFF,0xFFFF,0x0000,0x0000,0xFFFF,0xFFFF,0x0000,
X	0x0001,0xFFFF,0xFFFF,0x8000,0x0003,0xFFFF,0xFFFF,0xC000,
X	0x0003,0xFFFF,0xFFFF,0xC000,0x0003,0xFFFF,0xFFFF,0xC000,
X	0x0003,0xFFFF,0xFFFF,0xC000,0x0003,0xFFFF,0xFFFF,0xC000,
X	0x0003,0xFFFF,0xFFFF,0xC000,0x0003,0xFFFF,0xFFFF,0xC000,
X	0x0001,0xFFFF,0xFFFF,0x8000,0x0000,0xFFFF,0xFFFF,0x0000,
X	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000
END_OF_Icons/queenStencil.icon
if test 1933 -ne `wc -c <Icons/queenStencil.icon`; then
    echo shar: \"Icons/queenStencil.icon\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f Icons/rookStencil.icon -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"Icons/rookStencil.icon\"
else
echo shar: Extracting \"Icons/rookStencil.icon\" \(1933 characters\)
sed "s/^X//" >Icons/rookStencil.icon <<'END_OF_Icons/rookStencil.icon'
X/* Format_version=1, Width=64, Height=64, Depth=1, Valid_bits_per_item=16
X */
X	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
X	0x0000,0x0000,0x0000,0x0000,0x0000,0x001F,0xF800,0x0000,
X	0x0000,0x003F,0xFC00,0x0000,0x0000,0x787F,0xFE1E,0x0000,
X	0x0001,0xFC7F,0xFE3F,0x8000,0x0003,0xFC7F,0xFE3F,0xC000,
X	0x0007,0xFC7F,0xFE3F,0xE000,0x000F,0xFC7F,0xFE3F,0xF000,
X	0x000F,0xFC7F,0xFE3F,0xF000,0x000F,0xFDFF,0xFFBF,0xF000,
X	0x000F,0xFFFF,0xFFFF,0xF000,0x000F,0xFFFF,0xFFFF,0xF000,
X	0x000F,0xFFFF,0xFFFF,0xF000,0x000F,0xFFFF,0xFFFF,0xF000,
X	0x000F,0xFFFF,0xFFFF,0xF000,0x000F,0xFFFF,0xFFFF,0xF000,
X	0x0007,0xFFFF,0xFFFF,0xE000,0x0001,0xFFFF,0xFFFF,0x8000,
X	0x0000,0x7FFF,0xFFFE,0x0000,0x0000,0x1FFF,0xFFF8,0x0000,
X	0x0000,0x1FFF,0xFFF8,0x0000,0x0000,0x1FFF,0xFFF8,0x0000,
X	0x0000,0x1FFF,0xFFF8,0x0000,0x0000,0x1FFF,0xFFF8,0x0000,
X	0x0000,0x1FFF,0xFFF8,0x0000,0x0000,0x1FFF,0xFFF8,0x0000,
X	0x0000,0x1FFF,0xFFF8,0x0000,0x0000,0x1FFF,0xFFF8,0x0000,
X	0x0000,0x1FFF,0xFFF8,0x0000,0x0000,0x1FFF,0xFFF8,0x0000,
X	0x0000,0x1FFF,0xFFF8,0x0000,0x0000,0x1FFF,0xFFF8,0x0000,
X	0x0000,0x1FFF,0xFFF8,0x0000,0x0000,0x1FFF,0xFFF8,0x0000,
X	0x0000,0x1FFF,0xFFF8,0x0000,0x0000,0x1FFF,0xFFF8,0x0000,
X	0x0000,0x1FFF,0xFFF8,0x0000,0x0000,0x1FFF,0xFFF8,0x0000,
X	0x0000,0x1FFF,0xFFF8,0x0000,0x0000,0x1FFF,0xFFF8,0x0000,
X	0x0000,0x1FFF,0xFFF8,0x0000,0x0000,0x1FFF,0xFFF8,0x0000,
X	0x0000,0x1FFF,0xFFF8,0x0000,0x0000,0x1FFF,0xFFF8,0x0000,
X	0x0000,0x1FFF,0xFFF8,0x0000,0x0000,0x1FFF,0xFFF8,0x0000,
X	0x0000,0x1FFF,0xFFF8,0x0000,0x0000,0x3FFF,0xFFFC,0x0000,
X	0x0000,0x7FFF,0xFFFE,0x0000,0x0000,0xFFFF,0xFFFF,0x0000,
X	0x0001,0xFFFF,0xFFFF,0x8000,0x0003,0xFFFF,0xFFFF,0xC000,
X	0x0003,0xFFFF,0xFFFF,0xC000,0x0003,0xFFFF,0xFFFF,0xC000,
X	0x0003,0xFFFF,0xFFFF,0xC000,0x0003,0xFFFF,0xFFFF,0xC000,
X	0x0003,0xFFFF,0xFFFF,0xC000,0x0003,0xFFFF,0xFFFF,0xC000,
X	0x0001,0xFFFF,0xFFFF,0x8000,0x0000,0xFFFF,0xFFFF,0x0000,
X	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000
END_OF_Icons/rookStencil.icon
if test 1933 -ne `wc -c <Icons/rookStencil.icon`; then
    echo shar: \"Icons/rookStencil.icon\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f chessprocess.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"chessprocess.c\"
else
echo shar: Extracting \"chessprocess.c\" \(9812 characters\)
sed "s/^X//" >chessprocess.c <<'END_OF_chessprocess.c'
X/*
X * Copyright 1987 Tom Anderson; 20831 Frank Waters Road;
X * Stanwood, WA  98282.   All rights reserved.
X */
X
X/*
X * manage one or two chess game processes
X */
X
X#include <sys/types.h>
X#include <sys/socket.h>
X#include <sys/wait.h>
X#include <sys/stat.h>
X#include <sys/time.h>
X#include <sys/resource.h>
X#include <signal.h>
X#include <stdio.h>
X#include <strings.h>
X#include <ctype.h>
X
X#include "nchess.h"
X
Xextern char * gets();
X
Xint ChessPid[2],
X    ChessProcessFDs[2];
XFILE * ReadChessProcess[2], * WriteChessProcess[2];
XBOOL SigChildInterceptOn = FALSE;
XBOOL MachineDebug = FALSE;
Xchar * colorStrings[] = { "black", "white" };
X
X/*
X * intercept SIGCHLD
X *
X * print a message for the first chess process that dies and abort the 
X * game.  (note: any change in child status is interpreted as death).
X */
XhandleSigChild()
X{
X    int pid;
X    union wait status;
X
X    while(1) {
X	pid = wait3(&status, WNOHANG, (struct rusage *) 0);
X	if (pid <= 0)
X	    return;
X	if ( ! GameOver && (pid == ChessPid[BLACK] || pid == ChessPid[WHITE])) {
X	    Message (pid == ChessPid[WHITE] ?
X		"White's process died" :
X		"Black's process died" );
X	    KillMouseActivity();
X	    GameOver = TRUE;
X	    Mouse = LOCKED;
X	}
X    }
X}
X
X/*
X * have a chess process make the first move.
X *
X * note: with the wonderful unix chess program, "first" also implies
X * playing the white pieces.  nonetheless, color is an argument to this
X * function in case we ever find out how to get around this problem.
X */
Xvoid
XMachineFirst(color)
X    int color;
X{
X    fputs("first\n", WriteChessProcess[color]);
X    fflush(WriteChessProcess[color]);
X    if (MachineDebug)
X	fprintf(stderr, "sent to %s: first\n", colorStrings[color]);
X}
X
X/*
X * open a pipe to a chess game process
X *
X * startIt indicates whether the process should be sent the "first"
X * command.
X */
Xvoid
XInitChessProcess(cp, color, startIt)
X    char ** cp;
X    int color;
X    BOOL startIt;
X{
X    int sv[2];
X    char c[128];
X
X    if (socketpair(AF_UNIX, SOCK_STREAM, 0, sv) < 0) {
X	fputs("socketpair failed\n", stderr);
X	exit(1);
X    }
X    if ((ChessPid[color] = fork()) == 0) {
X	dup2(sv[0], 0);
X	dup2(sv[0], 1); 
X	chdir("/tmp");		/* so that "chess.out" can always be written */
X	execvp(cp[0], cp);
X	puts("exec");
X	fflush(stdout);
X	_exit(1);
X    }
X/*    dup2(sv[1], 0);
X    dup2(sv[1], 1); */
X    /* want to intercept SIGCHLD */
X    if ( ! SigChildInterceptOn) {
X	SigChildInterceptOn = TRUE;
X	signal(SIGCHLD, handleSigChild);
X    }
X    ChessProcessFDs[color] = (1 << sv[1]);
X    ReadChessProcess[color] = fdopen(sv[1], "r");
X    WriteChessProcess[color] = fdopen(sv[1], "w");
X    setbuf(ReadChessProcess[color], (char *) 0);
X    /* 
X     * eat the "Chess" prompt 
X     * note: if the child's exec failed,
X     * catch the "exec" prompt and give up
X     */
X    fgets(c, sizeof(c), ReadChessProcess[color]);
X    if (strcmp(c, "exec\n") == 0) {
X	KillChessProcesses();
X	fprintf(stderr, "exec of %s failed\n", cp[0]);
X	exit(1);
X    }
X    /* set algebraic notation mode */
X    fputs("alg\n", WriteChessProcess[color]);
X    fflush(WriteChessProcess[color]);
X    if (MachineDebug)
X	fprintf(stderr, "sent to %s: alg\n", colorStrings[color]);
X    if (startIt)
X	MachineFirst(color);
X}
X 
X
X/*
X * reap one or more chess process
X */
Xvoid
XReapChessProcesses()
X{
X    union wait status;
X
X    while (wait3(&status, WNOHANG, (struct rusage *) 0) >= 0)
X	;
X}
X
X/*
X * kill any and all chess processes
X */
Xvoid
XKillChessProcesses()
X{
X    signal(SIGCHLD, SIG_IGN);
X    if (ChessPid[BLACK])
X	kill(ChessPid[BLACK], SIGKILL);
X    if (ChessPid[WHITE])
X	kill(ChessPid[WHITE], SIGKILL);
X    ReapChessProcesses();
X}
X
X/*
X * get a move from a chess process 
X * 
X * return 1 if a move was successfully obtained, 0 if not.
X */
Xint
XGetMachineMove(move, color)
X    Move * move;
X    int color;
X{
X    char c[256], c2[256];
X    char file1, file2;
X    int rank1, rank2;
X
X    if (fgets(c, sizeof(c), ReadChessProcess[color]) == (char *) 0) 
X	return(0);
X    if (MachineDebug)
X	fprintf(stderr, "rec'd from %s: %s", colorStrings[color], c);
X    /* look for special announcements */
X    if (strcmp(c, "Forced mate\n") == 0) {
X	Message(color == WHITE ? 
X	    "White announces forced mate" :
X	    "Black announces forced mate");
X	return(0);
X    } 
X    if (strcmp(c, "Resign\n") == 0) {
X	Message(color == WHITE ? "White resigns" : "Black resigns");
X	DoResignation(color);
X	Mouse = LOCKED;
X	return(0);
X    } 
X    if (strcmp(c, "Illegal move\n") == 0) {
X	Message("Internal botch - illegal move detected");
X	return(0);
X    } 
X    if (strncmp(c, "done", 4) == 0) {
X	return(0);
X    }
X    if (strncmp(c, "White wins", 10) == 0
X    || strncmp(c, "Black wins", 10) == 0) {
X	c[10] = '\0';
X	Message(c);
X	GameOver = TRUE;
X	Mouse = LOCKED;
X	return(0);
X    }
X    /* e.g., 1. d2d4 */
X    if (sscanf(c, "%*d. %c%d%c%d", &file1, &rank1, &file2, &rank2) == 4
X    /* e.g., 1. ... d2d4 */
X    || sscanf(c, "%*d. ... %c%d%c%d", &file1, &rank1, &file2, &rank2) == 4) {
X	move->x1 = file1 - (isupper(file1) ? 'A' : 'a');
X	move->y1 = 8 - rank1;
X	move->x2 = file2 - (isupper(file2) ? 'A' : 'a');
X	move->y2 = 8 - rank2;
X	/* TBD: possible non-queen pawn promotion 
X	 * (the existing chess program doesn't implement this) */
X	move->newPieceType = (int) QUEEN;
X	return(1);
X    } else {
X	strcpy(c2, color == WHITE ? "White announces: " : "Black announces: ");
X	Message(strncat(c2, c, sizeof(c2) - strlen(c2) - 2));
X	if (strncmp(c, "Draw", 4) == 0) {
X	    GameOver = TRUE;
X	    Mouse = LOCKED;
X	}
X	return(0);
X    }
X}
X
X/*
X * send a move to a chess process
X *
X * note: if the process responds with a move too quickly, we won't 
X * get another select() trigger to get its move.  thus, we need to
X * check for the availability of a move when the echo is received.
X */
Xvoid
XSendMachineMove(move, color)
X    Move * move;
X    int color;
X{
X    char c[128];
X
X    if (move->x1 != move->x2
X    && GetSquare(move->x1, move->y1)->type == PAWN
X    && GetSquare(move->x2, move->y2)->type == NULLPC) {
X	/* re-encode en passant captures as horizontal moves */
X	fprintf(WriteChessProcess[color], "%c%d%c%d\n", 
X	    move->x1 + 'a', 8 - move->y1, 
X	    move->x2 + 'a', 8 - move->y1);
X	if (MachineDebug)
X	    fprintf(stderr, "sent move to %s: %c%d%c%d\n", 
X		colorStrings[color],
X		move->x1 + 'a', 8 - move->y1, 
X		move->x2 + 'a', 8 - move->y1);
X    } else {
X	fprintf(WriteChessProcess[color], "%c%d%c%d\n", 
X	    move->x1 + 'a', 8 - move->y1, 
X	    move->x2 + 'a', 8 - move->y2);
X	if (MachineDebug)
X	    fprintf(stderr, "sent move to %s: %c%d%c%d\n", 
X		colorStrings[color],
X		move->x1 + 'a', 8 - move->y1, 
X		move->x2 + 'a', 8 - move->y2);
X    }
X    fflush(WriteChessProcess[color]);
X    fgets(c, sizeof(c), ReadChessProcess[color]); /* eat the move echo */
X    if (MachineDebug)
X	fprintf(stderr, "rec'd from %s: %s", colorStrings[color], c);
X}
X
X/*
X * undo the last machine move and our move 
X */
Xvoid
XMachineUndo(color)
X{
X    fputs("remove\n", WriteChessProcess[color]);
X    fflush(WriteChessProcess[color]);
X    if (MachineDebug)
X	fprintf(stderr, "sent to %s: remove\n", colorStrings[color]);
X    UnDoMove();
X    UnDoMove();
X}
X
X/*
X * set up the board 
X * (as noted above: with the existing unix chess program, there is no 
X * apparent way (short of deciphering the chess.out format, which is 
X * totally un-fun) to inform the chess program whose turn it is and 
X * which color it is supposed to play - it assumes that white always 
X * is the first to move.  
X */
X
Xchar whitePieceChars[] = { 'p', 'n', 'b', 'r', 'q', 'k', ' ' };
Xchar blackPieceChars[] = { 'P', 'N', 'B', 'R', 'Q', 'K', ' ' };
X
X/*
X * set up a board state against the machine.
X * returns TRUE if successful, FALSE otherwise
X */
XBOOL
XMachineSetup(color)
X    int color;
X{
X    register int x, y;
X    Square * sqp;
X    char c[128];
X
X    fputs("setup\n", WriteChessProcess[color]);
X    if (MachineDebug)
X	fprintf(stderr, "sent to %s:\nsetup\n", colorStrings[color]);
X    for (y = 0 ; y < 8 ; y++) {
X	for (x = 0 ; x < 8 ; x++) {
X	    sqp = GetSquare(x, y);
X	    putc(sqp->color == WHITE ? 
X		whitePieceChars[(int) sqp->type] :
X		blackPieceChars[(int) sqp->type], 
X		WriteChessProcess[color]);
X	    if (MachineDebug)
X		fputc(sqp->color == WHITE ? 
X		    whitePieceChars[(int) sqp->type] :
X		    blackPieceChars[(int) sqp->type], 
X		    stderr);
X	}
X	putc('\n', WriteChessProcess[color]);
X	if (MachineDebug)
X	    fputc('\n', stderr);
X    }
X    fflush(WriteChessProcess[color]);
X    fgets(c, sizeof(c), ReadChessProcess[color]);
X    if (MachineDebug)
X	fprintf(stderr, "rec'd from %s: %s", colorStrings[color], c);
X    return(strcmp(c, "Setup successful\n") == 0);
X}
X
X/*
X * have a chess process save the game as "/tmp/chess.out".
X * return the size of chess.out.
X */
Xint
XMachineSave(color)
X    int color;
X{
X    FILE * saveFile;
X    struct stat saveFileStatus;
X    int saveFileSize;
X    int retryCount = 0;
X
X    fputs("save\n", WriteChessProcess[color]);
X    fflush(WriteChessProcess[color]);
X    if (MachineDebug)
X	fprintf(stderr, "sent to %s: save\n", colorStrings[color]);
X    sleep((unsigned) 1);
X    /* wait for the chess process to create chess.out */
X    do {
X	if ((saveFile = fopen("/tmp/chess.out", "r")) == (FILE *) 0) 
X	    sleep((unsigned) 2); 
X    } while(saveFile == (FILE *) 0 && ++retryCount < 10);
X    if (saveFile == (FILE *) 0) {
X	Message("Can't open chess.out!");
X	return(-1);
X    }
X    saveFileStatus.st_size = -1;
X    /* wait until chess.out stops growing */
X    do {
X	sleep((unsigned) 1);
X	saveFileSize = saveFileStatus.st_size;
X	fstat(fileno(saveFile), &saveFileStatus);
X    } while (saveFileSize != saveFileStatus.st_size);
X    fclose(saveFile);
X    return(saveFileSize);
X}
X
X/*
X * restore the game 
X */
Xvoid
XMachineRestore(color)
X    int color;
X{
X    fputs("restore\n", WriteChessProcess[color]);
X    fflush(WriteChessProcess[color]);
X    if (MachineDebug)
X	fprintf(stderr, "sent to %s: restore\n", colorStrings[color]);
X}
X
END_OF_chessprocess.c
if test 9812 -ne `wc -c <chessprocess.c`; then
    echo shar: \"chessprocess.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f controlsw.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"controlsw.c\"
else
echo shar: Extracting \"controlsw.c\" \(3122 characters\)
sed "s/^X//" >controlsw.c <<'END_OF_controlsw.c'
X/*
X * Copyright 1987 Tom Anderson; 20831 Frank Waters Road;
X * Stanwood, WA  98282.   All rights reserved.
X */
X
X/*
X * control panel subwindow handling
X */
X
X#include <stdio.h>
X#include <suntool/tool_hs.h>
X#include <suntool/panel.h>
X#include <suntool/menu.h>
X
X#include "nchess.h"
X
XBOOL SaveWanted = FALSE;		/* machine opponent and game save deferred */
X
Xstruct toolsw * ControlPanelSW;
XPanel ControlPanel;
X
X/* button items */
XPanel_item UndoButton;
XPanel_item LastPlayButton;
XPanel_item ResignButton;
XPanel_item TranscriptButton;
XPanel_item SaveButton;
X
X/*
X * undo move button event handler
X */
X/*ARGSUSED*/
XundoProc(item, event)
X    Panel_item item;
X    struct inputevent * event;
X{
X    if ( ! IHaveMoved()) {
X	Message("You haven't moved yet!");
X    } else if (Mouse == IDLE) {
X	UndoWanted = TRUE;
X	Mouse = LOCKED;		/* lock the mouse until the reply arrives */
X	SendUndoRequest(PeerColor);
X    }
X}
X
X/*
X * last play button event handler 
X */
X/*ARGSUSED*/
XlastPlayProc(item, event)
X    Panel_item item;
X    struct inputevent * event;
X{
X    ShowLastPlay();
X}
X
X/*
X * resign button event handler 
X */
X/*ARGSUSED*/
XresignProc(item, event)
X    Panel_item item;
X    struct inputevent * event;
X{
X    /* make sure this is what the user wants to do */
X    if (Mouse == IDLE) {
X	ConfirmResignation();
X    }
X}
X
X/*
X * write a transcript 
X */
X/*ARGSUSED*/
XtranscriptProc(item, event)
X    Panel_item item;
X    struct inputevent * event;
X{
X    WriteTranscript(TranscriptFileName, TranscriptType);
X}
X
X/*
X * save the game
X */
X/*ARGSUSED*/
XsaveProc(item, event)
X    Panel_item item;
X    struct inputevent * event;
X{
X    /*
X     * caveats: can't save games while we're still setting them up,
X     * and cannot save a game involving machines after the game is over.
X     */
X    if (SetupMode 
X    || GameOver && (IsMachine[WHITE] || IsMachine[BLACK]))
X	return;
X    if (IsMachine[WHITE] && IsMachine[BLACK]
X    || IsMachine[PeerColor] && Turn != MyColor) {
X	Message("Will save game when machine finishes move...");
X	SaveWanted = TRUE;
X    } else {
X	SaveGame(SaveFileName);
X    }
X}
X
X/*
X * set up the control subwindow
X */
Xvoid
XInitControlSW()
X{
X    if ((ControlPanelSW = panel_create(NchessTool, 0)) == NULL) {
X	fprintf(stderr, "Can't create control panel\n");
X	exit(1);
X    }
X    ControlPanel = ControlPanelSW->ts_data;
X    /* set up the buttons */
X    if ( ! IsMachine[WHITE] || ! IsMachine[BLACK]) {
X	ResignButton = panel_create_item(ControlPanel, PANEL_BUTTON,
X	    PANEL_LABEL_STRING, "(Resign)",
X	    PANEL_NOTIFY_PROC, resignProc,
X	    0);
X	UndoButton = panel_create_item(ControlPanel, PANEL_BUTTON,
X	    PANEL_LABEL_STRING, "(Undo)",
X	    PANEL_NOTIFY_PROC, undoProc,
X	    0);
X    }
X    LastPlayButton = panel_create_item(ControlPanel, PANEL_BUTTON,
X	PANEL_LABEL_STRING, "(Last Play)",
X	PANEL_NOTIFY_PROC, lastPlayProc,
X	0);
X    TranscriptButton = panel_create_item(ControlPanel, PANEL_BUTTON,
X	PANEL_LABEL_STRING, "(Transcript)",
X	PANEL_NOTIFY_PROC, transcriptProc,
X	0);
X    SaveButton = panel_create_item(ControlPanel, PANEL_BUTTON,
X	PANEL_LABEL_STRING, "(Save)",
X	PANEL_NOTIFY_PROC, saveProc,
X	0);
X    panel_fit_height(ControlPanel);
X}
END_OF_controlsw.c
if test 3122 -ne `wc -c <controlsw.c`; then
    echo shar: \"controlsw.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f daemon.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"daemon.c\"
else
echo shar: Extracting \"daemon.c\" \(4613 characters\)
sed "s/^X//" >daemon.c <<'END_OF_daemon.c'
X/*
X * Copyright 1987 Tom Anderson; 20831 Frank Waters Road;
X * Stanwood, WA  98282.   All rights reserved.
X */
X
X/*
X * chess invitation rendezvous server
X *
X * there are three entry points: 
X * 	- request a game 
X *	- reply to a request
X *	- cancel a request
X */
X
X#include <stdio.h>
X#include <rpc/rpc.h>
X#include <sys/time.h>
X#include <strings.h>
X
X#include "nchess.h"
X
Xchar LocalHostName[256];		/* local host name string */
X
X#define	MAXINVITES	32
Xtypedef struct {			/* registered invitations with call-back information */
X    GameRequest gr;			/* call-back information */
X    BOOL active;			/* is this slot active? */
X    unsigned long time;			/* time invitation was registered */
X} Invitation;
X
XInvitation Invitations[MAXINVITES];
X
X/*
X * register a game invitation and print a message on the console.
X */
Xvoid
XgameRequest(gameReq)
X    GameRequest * gameReq;
X{
X    struct timeval tv;
X    struct tm * timep;
X    register int i, oldSlot, oldTime;
X    register Invitation * invp;
X    int avail = -1;
X    FILE * console;
X
X
X    (void) gettimeofday(&tv, (struct timezone *) 0);
X    timep = localtime((long *) &tv.tv_sec);
X    oldTime = tv.tv_sec;
X    /* find an empty invitation slot, keeping track of the oldest active one */
X    for (i = 0 ; i < MAXINVITES ; i++) {
X	invp = &Invitations[i];
X	if ( ! invp->active) {
X	    avail = i;
X	    break;
X	} else if (invp->time < oldTime) {
X	    oldSlot = i;
X	    oldTime = invp->time;
X	}
X    }
X    /* if no slots are empty, re-use the oldest one */
X    if (avail < 0) 
X	avail = oldSlot;
X    /* fill out the invitation slot */
X    invp = &Invitations[avail];
X    invp->active = TRUE;
X    invp->time = tv.tv_sec;
X    invp->gr.progNum = gameReq->progNum;
X    invp->gr.color = gameReq->color;
X    invp->gr.resumeGame = gameReq->resumeGame;
X    strncpy(invp->gr.hostName, gameReq->hostName, sizeof(gameReq->hostName));
X    strncpy(invp->gr.userName, gameReq->userName, sizeof(gameReq->userName));
X    /* 
X     * print the invitation message on the local console 
X     */
X    if ((console = fopen("/dev/console", "w")) != (FILE *) 0) {
X	fprintf(console, "\n\007\007\007Message from Chess Daemon@%s at %d:%02d ...\n", 
X	    LocalHostName, timep->tm_hour, timep->tm_min);
X	if (gameReq->resumeGame) 
X	    fprintf(console, "%s wants to resume a game of chess.\n", 
X		gameReq->userName);
X	else
X	    fprintf(console, "%s wants to play a game of chess.\n", 
X		gameReq->userName);
X	fprintf(console, "reply with: nchess %s@%s\n", 
X	    gameReq->userName, gameReq->hostName);
X	fflush (console);
X	fclose(console);
X    }
X}
X
X/*
X * attempt to respond to a game invitation 
X */
XGameRequest *
XgameAcknowledge(gameAck)
X    GameRequest * gameAck;
X{
X    static GameRequest gr;
X    register int i, newestTime = 0, newestIndex = -1;
X    
X    /* 
X     * look for the most recently registered invitation
X     * if one exists, return the prog. number and the color,
X     *		then remove the entry.
X     * else return an entry with a program number of zero.
X     */
X    gr.progNum = 0;
X    for (i = 0 ; i < MAXINVITES && Invitations[i].active ; i++) {
X	if (strcmp(Invitations[i].gr.hostName, gameAck->hostName) == 0
X	&& strcmp(Invitations[i].gr.userName, gameAck->userName) == 0
X	&& Invitations[i].time > newestTime) {
X	    newestIndex = i;
X	    newestTime = Invitations[i].time;
X	}
X    }
X    if (newestIndex >= 0) {
X	gr.progNum = Invitations[newestIndex].gr.progNum;
X	gr.color = Invitations[newestIndex].gr.color;
X	gr.resumeGame = Invitations[newestIndex].gr.resumeGame;
X	Invitations[newestIndex].active = FALSE;
X    }
X    return(&gr);
X}
X
X/*
X * cancel a game invitation 
X */
Xvoid
XcancelRequest(gr)
X    GameRequest * gr;
X{
X    register int i;
X    
X    for (i = 0 ; i < MAXINVITES && Invitations[i].active ; i++) {
X	if (strcmp(Invitations[i].gr.hostName, gr->hostName) == 0
X	&& strcmp(Invitations[i].gr.userName, gr->userName) == 0
X	&& Invitations[i].gr.progNum == gr->progNum) {
X	    Invitations[i].active = FALSE;
X	    break;
X	}
X    }
X}
X
X/*ARGSUSED*/
Xmain(argc, argv)
X    int argc;
X    char ** argv;
X{
X    if (gethostname(LocalHostName, sizeof(LocalHostName)) != 0) {
X	fprintf(stderr, "%s: can't determine the local host name\n", argv[0]);
X	exit(1);
X    }
X    pmap_unset(SERVERPROGNUM, VERSNUM);
X    /* register the entry points */
X    registerrpc(SERVERPROGNUM, VERSNUM, REQPROCNUM, 
X	gameRequest, XdrGameReq, xdr_void);
X    registerrpc(SERVERPROGNUM, VERSNUM, ACKPROCNUM, 
X	gameAcknowledge, XdrGameReq, XdrGameReq);
X    registerrpc(SERVERPROGNUM, VERSNUM, CANCELPROCNUM, 
X	cancelRequest, XdrGameReq, xdr_void);
X    svc_run();
X    fprintf(stderr, "%s: exiting - svc_run returned\n", argv[0]);
X    exit(1);
X}
X
END_OF_daemon.c
if test 4613 -ne `wc -c <daemon.c`; then
    echo shar: \"daemon.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f decls.h -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"decls.h\"
else
echo shar: Extracting \"decls.h\" \(2262 characters\)
sed "s/^X//" >decls.h <<'END_OF_decls.h'
X/*
X * Copyright 1987 Tom Anderson; 20831 Frank Waters Road;
X * Stanwood, WA  98282.   All rights reserved.
X */
X
X/*
X * global declarations 
X */
X
X/* board.c */
X
Xextern void InitBoard(), DoMove(), UnDoMove(), ShowLastPlay(), 
X    SaveGame(), WriteTranscript(), RestoreGame(), DoSetupChange(),
X    DoResignation();
Xextern BOOL InitialTurn, IsOurPieceAt(), IsSrcPieceAt(), 
X    IsMoveLegal(), IHaveMoved(), InCheck(), GameOver;
Xextern Square * GetSquare(), * GetSrcSquare();
Xextern int PromotePawn(), Turn;
X
X/* boardsw.c */
X
Xextern void InitBoardSW(), DrawBoard(), DrawSquare(), AddVictim(),
X    DeleteVictim(), KillMouseActivity(), RequestUndo();
Xextern MouseState Mouse;
Xextern BOOL Flashing;
X
X/* chessprocess.c */
X
Xextern void InitChessProcess(), ReapChessProcesses(), KillChessProcesses(),
X    SendMachineMove(), MachineUndo(), MachineRestore(), MachineFirst();
Xextern BOOL MachineSetup(), MachineDebug;
Xextern int GetMachineMove(), MachineSave(), ChessProcessFDs[];
X
X/* controlsw.c */
X
Xextern void InitControlSW();
Xextern BOOL SaveWanted;
X
X/* ipc.c */
X
Xextern int MyColor, PeerColor;
Xextern unsigned long PeerProgNum; 
Xextern void InitRPC(), SendResignation(), SendUndoRequest(), SendTalkMsg(),
X    SendRestoreMove(), SendEndRestore(), SendSetupChange(),
X    SendUndoAcknowledgement();
Xextern BOOL UndoWanted, SendMove(), RestoringGame;
Xextern char * PeerUserName;
X
X/* main.c */
X
X#ifdef FILE
Xextern FILE * RestoreFile;
X#endif
Xextern int errno, TranscriptType;
Xextern char * TranscriptFileName, * SaveFileName, * PlayerName[];
Xextern BOOL SetupMode, IsMachine[2];
Xextern struct passwd * UserPWEntry;
X
X/* msgsw.c */
X
Xextern void InitMsgSW(), Message(), ClearMessage(), WhoseMoveMessage();
X
X/* rpcsw.c */
X
Xextern void AddRPCSubwindow(), DeleteRPCSubwindow();
X
X/* select.c */
X
Xextern void SelectAll();
X
X/* talksw.c */
X
Xextern void RecvTalkMsg(), InitTalkSW();
X
X/* tool.c */
X
X/* the following is a kludge, but hides enormous organizational problems
X * with Sun's headers */
X#ifdef TOOL_NULL
Xextern Tool * NchessTool;
X#endif
Xextern void RunTool(), InitTool(), ParseToolArgs();
X
X/* xdr.c */
X
Xextern int XdrGameReq(), XdrMove(), XdrString(), XdrSetup();
X
X/* undeclared system calls and library fxns */
X
Xextern int getpid();
Xextern long random();
Xextern char * malloc();
END_OF_decls.h
if test 2262 -ne `wc -c <decls.h`; then
    echo shar: \"decls.h\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f ipc.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"ipc.c\"
else
echo shar: Extracting \"ipc.c\" \(15504 characters\)
sed "s/^X//" >ipc.c <<'END_OF_ipc.c'
X/*
X * Copyright 1987 Tom Anderson; 20831 Frank Waters Road;
X * Stanwood, WA  98282.   All rights reserved.
X */
X
X/*
X * manage communication with the peer chess tool, if one exists.
X * some communication functions with a background chess process are
X * relayed by functions in this file.
X */
X
X#include <stdio.h>
X#include <rpc/rpc.h>
X#include <strings.h>
X#include <errno.h>
X#include <sys/time.h>
X#include <sys/socket.h>
X#include <pwd.h>
X#include <signal.h>
X
X#include "nchess.h"
X
Xunsigned long MyProgNum = (u_long) 0;	/* my program number */
Xunsigned long PeerProgNum;		/* program number of peer */
Xchar * PeerHostName;			/* host name of peer */
Xchar * PeerUserName;			/* user name of peer */
XBOOL peerDead = FALSE;			/* peer connection lost or chess program died */
X
XBOOL UndoWanted = FALSE;		/* undo was requested locally */
XBOOL RestoringGame = FALSE;		/* restoring a saved game via the peer */
XSVCXPRT * Xprt;				/* RPC service transport handle */
X
X/* 
X * get a transient program number 
X */
Xunsigned long
XgetTransient(vers, sockp)
X    unsigned long vers; 
X    int * sockp;
X{
X    unsigned long progNum = 0x52000000L;
X    int s, len;
X    struct sockaddr_in addr;
X
X    /* create a socket */
X    if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
X	fprintf(stderr, "can't create a socket\n");
X	exit(1);
X    }
X    * sockp = s;
X    addr.sin_addr.s_addr = 0;
X    addr.sin_family = AF_INET;
X    addr.sin_port = 0;
X    len = sizeof(addr);
X    bind(s, (struct sockaddr *) &addr, len);
X    if (getsockname(s, (caddr_t) &addr, &len) < 0) {
X	fprintf(stderr, "getsockname failed\n");
X	exit(1);
X    }
X    /* now find and reserve an available transient program number */
X    while ( ! pmap_set(progNum++, vers, IPPROTO_UDP, addr.sin_port))
X	continue;
X    return(progNum - 1);
X}
X
X/*
X * timed out the peer
X */
Xvoid 
XpeerDied()
X{
X    Message("Lost connection to your opponent");
X    peerDead = GameOver = TRUE;
X    Mouse = LOCKED;
X}
X
X/*
X * RPC procedure dispatch routine
X */
Xvoid
Xdispatch(request, xprt)
X    struct svc_req * request;
X    SVCXPRT * xprt;
X{
X    Move move;
X    SetupChange setup;
X    GameRequest gr;
X    char ans[80];
X    int isUndoOK;
X
X    switch (request->rq_proc) {
X    /* 
X     * are you there? 
X     */
X    case NULLPROC:
X	if ( ! svc_sendreply(xprt, xdr_void, (caddr_t) 0)) {
X	    fprintf(stderr, "can't reply to remote peer\n");
X	    exit(1);
X	}
X	break;
X    /*  
X     * game invitation accepted 
X     */
X    case ACCEPTPROCNUM:
X	if ( ! svc_getargs(xprt, XdrGameReq, &gr)) {
X	    svcerr_decode(xprt);
X	    exit(1);
X	}
X	if ( ! svc_sendreply(xprt, xdr_void, (caddr_t) 0)) {
X	    fprintf(stderr, "can't reply to remote peer\n");
X	    exit(1);
X	}
X	PeerProgNum = gr.progNum;
X	PeerColor = gr.color;
X	if (MyColor + PeerColor != WANTSWHITE + WANTSBLACK) {
X	    switch(MyColor) {
X	    /* I don't care - pick a color based on what the peer wants */
X	    case EITHERCOLOR:
X		switch(PeerColor) {
X		case WANTSBLACK:
X		    MyColor = WANTSWHITE;
X		    break;
X		case WANTSWHITE:
X		    MyColor = WANTSBLACK;
X		    break;
X		default:
X		    fprintf(stderr, "color arbitration botch\n");
X		    exit(1);
X		}
X		break;
X	    case WANTSBLACK:
X		if (PeerColor == WANTSBLACK) {
X		    printf("Your opponent insists on playing black - is that OK? ");
X		    scanf("%s", ans);
X		    if (ans[0] == 'y' || ans[0] == 'Y') 
X			MyColor = WANTSWHITE;
X		    else {
X			fprintf(stderr, "couldn't agree on colors - bye\n");
X			(void) callrpc(PeerHostName, PeerProgNum, VERSNUM, COLORFAILPROCNUM,
X			    xdr_void, (caddr_t) 0,
X			    xdr_void, (caddr_t) 0);
X			exit(1);
X		    }
X		}
X		break;
X	    case WANTSWHITE:
X		if (PeerColor == WANTSWHITE) {
X		    printf("Your opponent insists on playing white - is that OK? ");
X		    scanf("%s", ans);
X		    if (ans[0] == 'y' || ans[0] == 'Y') 
X			MyColor = WANTSBLACK;
X		    else {
X			fprintf(stderr, "couldn't agree on colors - bye\n");
X			(void) callrpc(PeerHostName, PeerProgNum, VERSNUM, COLORFAILPROCNUM,
X			    xdr_void, (caddr_t) 0,
X			    xdr_void, (caddr_t) 0);
X			exit(1);
X		    }
X		}
X		break;
X	    }
X	}
X	break;
X    /* 
X     * the other player didn't ameliorate our insistence on color 
X     */
X    case COLORFAILPROCNUM:
X	fprintf(stderr, "couldn't agree on colors - bye\n");
X	(void) svc_sendreply(xprt, xdr_void, (caddr_t) 0);
X	exit(1);
X    /* 
X     * receive a move from the other player 
X     */
X    case MOVEPROCNUM:
X	if ( ! svc_getargs(xprt, XdrMove, &move)) {
X	    fprintf(stderr, "can't get RPC args\n");
X	    exit(1);
X	}
X	if ( ! svc_sendreply(xprt, xdr_void, (caddr_t) 0)) {
X	    peerDied();
X	} else {
X	    DoMove(&move, TRUE); 
X	    Turn = MyColor;
X	    Flashing = TRUE;
X	    if (Mouse != CONFIRMING)
X		WhoseMoveMessage((char *) 0);
X	}
X	break;
X    /* 
X     * receive a setup change from the other player 
X     */
X    case SETUPPROCNUM:
X	if ( ! svc_getargs(xprt, XdrSetup, &setup)) {
X	    fprintf(stderr, "can't get RPC args\n");
X	    exit(1);
X	}
X	if ( ! svc_sendreply(xprt, xdr_void, (caddr_t) 0)) {
X	    peerDied();
X	} else {
X	    DoSetupChange(&setup);
X	}
X	break;
X    /* 
X     * receive a restoration move from the other player's process
X     */
X    case RESTOREMOVEPROCNUM:
X	if ( ! svc_getargs(xprt, XdrMove, &move)) {
X	    fprintf(stderr, "can't get RPC args\n");
X	    exit(1);
X	}
X	if ( ! svc_sendreply(xprt, xdr_void, (caddr_t) 0)) {
X	    peerDied();
X	} else {
X	    DoMove(&move, TRUE); 
X	    Turn = OTHERCOLOR(Turn);
X	}
X	break;
X    /*
X     * restoration complete 
X     */
X    case ENDRESTOREPROCNUM:
X	if ( ! svc_getargs(xprt, xdr_int, &Turn)) {
X	    fprintf(stderr, "can't get RPC args\n");
X	    exit(1);
X	}
X	if ( ! svc_sendreply(xprt, xdr_void, (caddr_t) 0)) {
X	    peerDied();
X	} else {
X	    WhoseMoveMessage((char *) 0);
X	    RestoringGame = FALSE;
X	    Mouse = IDLE;	/* unlock the mouse */
X	    Flashing = (Turn == MyColor);
X	}
X	break;
X    /* 
X     * other player wants to undo his previous move 
X     */
X    case UNDOPROCNUM:
X	if ( ! svc_sendreply(xprt, xdr_void, (caddr_t) 0)) {
X	    peerDied();
X	} else {
X	    RequestUndo();
X	    Flashing = TRUE;
X	}
X	break;
X    /*
X     * the other player blew away his tool.
X     */
X    case GOODBYEPROCNUM:
X	svc_sendreply(xprt, xdr_void, (caddr_t) 0);
X	KillMouseActivity();
X	peerDead = GameOver = TRUE;
X	Mouse = LOCKED;
X	Message("Your opponent killed his tool process");
X	break;
X    /*
X     * other player is acknowledging our request to undo.
X     */
X    case UNDOACKPROCNUM:
X	if ( ! svc_getargs(xprt, xdr_int, &isUndoOK)) {
X	    fprintf(stderr, "can't get RPC args\n");
X	    exit(1);
X	}
X	if ( ! svc_sendreply(xprt, xdr_void, (caddr_t) 0)) {
X	    peerDied();
X	} else {
X	    if (isUndoOK) {
X		UnDoMove();
X		if (Turn == MyColor)
X		    UnDoMove();
X		else
X		    Turn = MyColor;
X		WhoseMoveMessage("Undo accepted");
X	    } else {
X		WhoseMoveMessage("Undo refused");
X	    }
X	    UndoWanted = FALSE;
X	    Mouse = IDLE;
X	    Flashing = TRUE;
X	}
X	break;
X    /*
X     * other player resigned 
X     */
X    case RESIGNPROCNUM:
X	if ( ! svc_sendreply(xprt, xdr_void, (caddr_t) 0))
X	    peerDead = TRUE;
X	Message(PeerColor == BLACK ? "Black resigns" : "White resigns");
X	KillMouseActivity();
X	Mouse = LOCKED;		/* game is over */
X	DoResignation(OTHERCOLOR(MyColor));
X	Flashing = TRUE;
X	break;
X    case MSGPROCNUM:
X	if ( ! svc_getargs(xprt, XdrString, ans)) {
X	    fprintf(stderr, "can't get RPC args\n");
X	    exit(1);
X	}
X	if ( ! svc_sendreply(xprt, xdr_void, (caddr_t) 0)) {
X	    peerDied();
X	} else {
X	    RecvTalkMsg(ans);
X	    Flashing = TRUE;
X	}
X	break;
X    }
X}
X
X
X/*
X * outstanding invitation - shared by InitRPC() and quitEarly().
X */
XGameRequest gr;
X
X/*
X * cancel our invitation with the remote daemon if we receive a signal
X * before the invitee responds.
X */
XquitEarly()
X{
X    callrpc(PeerHostName, SERVERPROGNUM, VERSNUM, CANCELPROCNUM, 
X	XdrGameReq, (caddr_t) &gr, 
X	xdr_void, (caddr_t) 0);
X    exit(1);
X}
X
X/*
X * initialize the RPC connection, using the user's "user@host" arg.
X */
Xvoid
XInitRPC(cp, progName)
X    char * cp, * progName;
X{
X    GameRequest gr2;
X    int sock, rfds; 
X    char localHostName[256], ans[80];
X    BOOL resumeGame = FALSE;
X
X    /*
X     * decipher the remote host and user strings 
X     */
X    if (cp == (char *) 0 || (PeerHostName = index(cp, '@')) == (char *) 0) {
X	fprintf(stderr, "%s: illegal/non-existent user@host arg\n", progName);
X	exit(1);
X    }
X    *PeerHostName++ = '\0';
X    PeerUserName = cp;
X    /* 
X     * determine the local host and user names 
X     */
X    if (gethostname(localHostName, sizeof(localHostName)) != 0) {
X	fprintf(stderr, "%s: can't determine local host name\n", progName);
X	exit(1);
X    }
X    /*
X     * generate the transient RPC program number used by this player.
X     */
X    MyProgNum = getTransient(VERSNUM, &sock);
X    if ((Xprt = svcudp_create(sock)) == (SVCXPRT *) 0) {
X	fprintf(stderr, "svcudp_create failed\n");
X	exit(1);
X    }
X    /*
X     * register the peer-to-peer RPC dispatch procedure
X     */
X    (void) svc_register(Xprt, MyProgNum, VERSNUM, dispatch, 0L);
X    /*
X     * check for an invitation registered with the local chess
X     * daemon, indicating that we are responding to an invitation.
X     */
X    (void) strcpy(gr.userName, PeerUserName);
X    (void) strcpy(gr.hostName, PeerHostName);
X    if (callrpc(localHostName, SERVERPROGNUM, VERSNUM, ACKPROCNUM,
X	XdrGameReq, (caddr_t) &gr, 
X	XdrGameReq, (caddr_t) &gr2) != 0) 
X    {
X	fprintf(stderr, "error: callrpc of local daemon (%s)\n", localHostName);
X	exit(1);
X    }
X    PeerProgNum = gr2.progNum;
X    PeerColor = gr2.color;
X    resumeGame = gr2.resumeGame;
X    do {
X	/* 
X	 * if no invitation was registered or the remote program 
X	 * is no longer running,
X	 * 	 then register an invitation with the remote daemon.
X	 */
X	if (PeerProgNum == 0L
X	|| callrpc(PeerHostName, PeerProgNum, VERSNUM, NULLPROC, 
X	    xdr_void, (caddr_t) 0, 
X	    xdr_void, (caddr_t) 0) != 0) 
X	{
X	    gr.progNum = MyProgNum;
X	    gr.color = MyColor;
X	    gr.resumeGame = (RestoreFile != (FILE *) 0 || SetupMode);
X	    (void) strcpy(gr.userName, UserPWEntry->pw_name);
X	    (void) strcpy(gr.hostName, localHostName);
X	    signal(SIGINT, quitEarly);
X	    signal(SIGQUIT, quitEarly);
X	    signal(SIGHUP, quitEarly);
X	    if (callrpc(PeerHostName, SERVERPROGNUM, VERSNUM, REQPROCNUM, 
X		XdrGameReq, (caddr_t) &gr, 
X		xdr_void, (caddr_t) 0) != 0) 
X	    {
X		fprintf(stderr, "error: callrpc of remote daemon\n");
X		exit(1);
X	    }
X	    printf("waiting for %s to respond...\n", PeerUserName);
X	    /* 
X	     * wait for the remote peer to send us his program number and color 
X	     */
X	    do {
X		rfds = svc_fds;
X		switch(select(32, &rfds, (int *) 0, (int *) 0, (struct timeval *) 0)) {
X		case -1:
X		    if (errno == EINTR)
X			continue;
X		    fprintf(stderr, "RPC select botch\n");
X		    exit(1);
X		case 0:
X		    break;
X		default:
X		    svc_getreq(rfds);
X		    break;
X		}
X	    } while(PeerProgNum == 0L);
X	    signal(SIGINT, SIG_DFL);
X	    signal(SIGQUIT, SIG_DFL);
X	    signal(SIGHUP, SIG_DFL);
X	}
X	/*
X	 * else accept the invitation, sending the remote program 
X	 * our program number and color.
X	 */
X	else {
X	    if (resumeGame) {
X		MyColor = EITHERCOLOR;
X		RestoringGame = TRUE;
X		SetupMode = FALSE;
X	    }
X	    /* try to pre-arrange colors */
X	    if (MyColor + PeerColor != WANTSWHITE + WANTSBLACK) {
X		switch(MyColor) {
X		/* I don't care - pick a color based on what the peer wants */
X		case EITHERCOLOR:
X		    switch(PeerColor) {
X		    case EITHERCOLOR:
X			MyColor = (random() & 0x01) ? WANTSBLACK : WANTSWHITE;
X			break;
X		    case WANTSBLACK:
X			MyColor = WANTSWHITE;
X			break;
X		    case WANTSWHITE:
X			MyColor = WANTSBLACK;
X			break;
X		    }
X		    break;
X		case WANTSBLACK:
X		    if (PeerColor == WANTSBLACK) {
X			printf("%s also wants to play black - is that OK? ", PeerUserName);
X			scanf("%s", ans);
X			if (ans[0] == 'y' || ans[0] == 'Y') 
X			    MyColor = WANTSWHITE;
X		    }
X		    break;
X		case WANTSWHITE:
X		    if (PeerColor == WANTSWHITE) {
X			printf("%s also wants to play white - is that OK? ", PeerUserName);
X			scanf("%s", ans);
X			if (ans[0] == 'y' || ans[0] == 'Y') 
X			    MyColor = WANTSBLACK;
X		    }
X		    break;
X		}
X	    }
X	    gr.progNum = MyProgNum;
X	    gr.color = MyColor;
X	    if (callrpc(PeerHostName, PeerProgNum, VERSNUM, ACCEPTPROCNUM, 
X		XdrGameReq, (caddr_t) &gr, 
X		xdr_void, (caddr_t) 0) != 0)
X	    {
X		PeerProgNum = 0L;
X	    }
X	}
X    } while(PeerProgNum == 0L);
X    PeerColor = OTHERCOLOR(MyColor);
X    PlayerName[MyColor] = UserPWEntry->pw_name;
X    PlayerName[PeerColor] = PeerUserName;
X    /*
X     * if the other player is shipping us the game state, lock the
X     * mouse in the meantime.
X     */
X    if (RestoringGame)
X	Mouse = LOCKED;
X}
X
X/*
X * send a move to the 'color' player
X */
XBOOL
XSendMove(move, color)
X    Move * move;
X    int color;
X{
X    if ( ! peerDead) {
X	if (IsMachine[color]) {
X	    SendMachineMove(move, color);
X	} else if (callrpc(PeerHostName, PeerProgNum, VERSNUM, MOVEPROCNUM,
X	    XdrMove, (caddr_t) move, 
X	    xdr_void, (caddr_t) 0) != 0) 
X	{
X	    peerDied();
X	}
X    }
X    return( ! peerDead);
X}
X
Xvoid
XSendRestoreMove(move, color)
X    Move * move;
X    int color;
X{
X    if ( ! IsMachine[color] 
X    && ! peerDead
X    && callrpc(PeerHostName, PeerProgNum, VERSNUM, RESTOREMOVEPROCNUM,
X	XdrMove, (caddr_t) move, 
X	xdr_void, (caddr_t) 0) != 0)
X    {
X	peerDied();
X    }
X}
X
Xvoid
XSendEndRestore()
X{
X    if ( ! peerDead
X    && callrpc(PeerHostName, PeerProgNum, VERSNUM, ENDRESTOREPROCNUM,
X	xdr_int, (caddr_t) &Turn, 
X	xdr_void, (caddr_t) 0) != 0)
X    {
X	peerDied();
X    }
X}
X
Xvoid
XSendUndoRequest(color)
X    int color;
X{
X    if ( ! peerDead) {
X	if (IsMachine[color]) {
X	    if (Turn != MyColor) {
X		Message("Will undo after machine moves...");
X	    } else {
X		MachineUndo(color);
X		UndoWanted = FALSE;
X		Mouse = IDLE;
X	    }
X	} else {
X	    Message("Sending undo request to your opponent (please wait)...");
X	    if (callrpc(PeerHostName, PeerProgNum, VERSNUM, UNDOPROCNUM,
X		xdr_void, (caddr_t) 0, 
X		xdr_void, (caddr_t) 0) != 0)
X	    {
X		peerDied();
X	    }
X	}
X    }
X}
X
Xvoid
XSendResignation(color)
X    int color;
X{
X    if ( ! peerDead) {
X	if (IsMachine[color]) {
X	    KillChessProcesses();
X	} else if (callrpc(PeerHostName, PeerProgNum, VERSNUM, RESIGNPROCNUM,
X	    xdr_void, (caddr_t) 0, 
X	    xdr_void, (caddr_t) 0) != 0)
X	{
X	    peerDied();
X	}
X    }
X}
X
Xvoid
XSendTalkMsg(cp)
X    char * cp;
X{
X    if ( ! peerDead
X    && callrpc(PeerHostName, PeerProgNum, VERSNUM, MSGPROCNUM,
X	XdrString, (caddr_t) cp, 
X	xdr_void, (caddr_t) 0) != 0)
X    {
X	peerDied();
X    }
X}
X
Xvoid
XSendSetupChange(setup, color)
X    SetupChange * setup;
X    int color;
X{
X    if ( ! IsMachine[color] 
X    && ! peerDead
X    && callrpc(PeerHostName, PeerProgNum, VERSNUM, SETUPPROCNUM,
X	XdrSetup, (caddr_t) setup, 
X	xdr_void, (caddr_t) 0) != 0)
X    {
X	peerDied();
X    }
X}
X
Xvoid
XSendUndoAcknowledgement(isUndoOK)
X    int isUndoOK;
X{
X    if (callrpc(PeerHostName, PeerProgNum, VERSNUM, UNDOACKPROCNUM,
X	xdr_int, (caddr_t) &isUndoOK, 
X	xdr_void, (caddr_t) 0) != 0)
X    {
X	peerDied();
X    } else if (isUndoOK) {
X	UnDoMove();
X	if (Turn == MyColor) 
X	    Turn = OTHERCOLOR(MyColor);
X	else 
X	    UnDoMove();
X	Message(MyColor == WHITE ?
X	    "Waiting for black to re-play..." :
X	    "Waiting for white to re-play...");
X    } else 
X	WhoseMoveMessage((char *) 0);
X}
X
Xvoid
XSendGoodbye()
X{
X    if ( ! IsMachine[PeerColor] && ! peerDead) {
X	callrpc(PeerHostName, PeerProgNum, VERSNUM, GOODBYEPROCNUM,
X	    xdr_void, (caddr_t) 0,
X	    xdr_void, (caddr_t) 0);
X    }
X    if (MyProgNum != 0) {
X	/* unregister the RPC transport handle */
X	xprt_unregister(Xprt);
X	/* release my program number for re-use */
X	pmap_unset(MyProgNum, VERSNUM);
X    }
X}
END_OF_ipc.c
if test 15504 -ne `wc -c <ipc.c`; then
    echo shar: \"ipc.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f main.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"main.c\"
else
echo shar: Extracting \"main.c\" \(6364 characters\)
sed "s/^X//" >main.c <<'END_OF_main.c'
X/*
X * Copyright 1987 Tom Anderson; 20831 Frank Waters Road;
X * Stanwood, WA  98282.   All rights reserved.
X */
X
X/*
X * main client part of network chess.
X */
X
X#include <stdio.h>
X#include <strings.h>
X#include <errno.h>
X#include <suntool/tool_hs.h>
X#include <pwd.h>
X
X#include "nchess.h"
X
Xint errno;				/* global error number */
X
Xchar * TranscriptFileName = "nchess.transcript";
Xint TranscriptType = TR_MIN_NORMAL;
Xchar * SaveFileName = "nchess.save";
Xchar * PlayerName[2];
XBOOL SetupMode = FALSE;
XBOOL IsMachine[2] = { FALSE, FALSE };
XFILE * RestoreFile;			/* restoration file */
Xstruct passwd * UserPWEntry;
X
X#define	MAXCHESSPROCARGS	16
Xchar * ChessProcessArgs[2][MAXCHESSPROCARGS];
X
X/*
X * walk away from the game in the middle on receipt of an appropriate
X * signal
X */
XbobbyFischer()
X{
X    /* kill any and all chess processes */
X    KillChessProcesses();
X    /* send a goodbye to the peer */
X    SendGoodbye();
X    exit(1);
X}
X
Xmain(argc, argv)
X    int argc;
X    char ** argv;
X{
X    register int i, j;
X    char * cp = (char *) 0, * iconDirectory = (char *) 0;
X    int chessArgIndex[2];
X    BOOL useRetained = TRUE;
X
X    if ((UserPWEntry = getpwuid(getuid())) == (struct passwd *) 0) {
X	fputs("Can't determine who you are\n", stderr);
X	exit(1);
X    }
X    chessArgIndex[BLACK] = chessArgIndex[WHITE] = 0;
X    /* randomize things a bit */
X    (void) srandom((long) getpid());
X    /* parse and strip out the tool-related arguments */
X    ParseToolArgs(&argc, argv);
X    /* scan the remaining argument list */
X    for (i = 1 ; i < argc ; i++) {
X	if (argv[i][0] == '-') {
X	    switch (argv[i][1]) {
X	    case 'c':
X		useRetained = FALSE;	/* use a retained pixrect for the board */
X		break;
X	    case 'v':
X		MachineDebug = TRUE;	/* turn on chess program i/f debugging */
X		break;
X	    case 'd':			/* custom piece icon directory name */
X		if (argv[i][j=2] == '\0' && (j = 0 , ++i >= argc)) {
X		    fprintf(stderr, "%s: bad piece icon directory name arg\n", argv[0]);
X		    exit(1);
X		} 
X		iconDirectory = &argv[i][j];
X		break;
X	    case 'b':			/* wants to play the black pieces */
X		MyColor = WANTSBLACK;
X		break;
X	    case 'w':			/* wants to play the white pieces */
X		MyColor = WANTSWHITE;
X		break;
X	    case 'x':			/* specify transcript notation type */
X		if (argv[i][j=2] == '\0' && (j = 0 , ++i >= argc)
X		|| sscanf(&argv[i][j], "%d", &TranscriptType) != 1
X		|| TranscriptType < TR_MIN_TYPE
X		|| TranscriptType > TR_MAX_TYPE) {
X		    fprintf(stderr, "%s: bad transcript mode arg\n", argv[0]);
X		    exit(1);
X		}
X		break;
X	    case 't':			/* specify transcript file name */
X		if (argv[i][j=2] == '\0' && (j = 0 , ++i >= argc)) {
X		    fprintf(stderr, "%s: bad transcript filename arg\n", argv[0]);
X		    exit(1);
X		} 
X		TranscriptFileName = &argv[i][j];
X		break;
X	    case 's':			/* specify save file name */
X		if (argv[i][j=2] == '\0' && (j = 0 , ++i >= argc)) {
X		    fprintf(stderr, "%s: bad save filename arg\n", argv[0]);
X		    exit(1);
X		} 
X		SaveFileName = &argv[i][j];
X		break;
X	    case 'r':
X		if (argv[i][j=2] == '\0' && (j = 0 , ++i >= argc)
X		|| ((RestoreFile = fopen(&argv[i][j], "r")) == (FILE *) 0)) {
X		    fprintf(stderr, "%s: bad restore file arg\n", argv[0]);
X		    exit(1);
X		}
X		if (fread((caddr_t) &MyColor, sizeof(MyColor), 1, RestoreFile) != 1) {
X		    fputs("Bad save file\n", stderr);
X		    exit(1);
X		}
X		break;
X	    case 'e':
X		SetupMode = TRUE;
X		Mouse = SETUP;
X		break;
X	    case 'm':
X		IsMachine[WHITE] = TRUE;
X		if (argv[i][j=2] == '\0' && (j = 0 , ++i >= argc)) {
X		    fprintf(stderr, "%s: bad chess program arg\n", argv[0]);
X		    exit(1);
X		}
X		if (chessArgIndex[WHITE] >= MAXCHESSPROCARGS - 1) {
X		    fprintf(stderr, "%s: too many chess program args\n", argv[0]);
X		    exit(1);
X		}
X		ChessProcessArgs[WHITE][chessArgIndex[WHITE]++] = &argv[i][j];
X		ChessProcessArgs[WHITE][chessArgIndex[WHITE]] = (char *) 0;
X		break;
X	    case 'n':
X		IsMachine[BLACK] = TRUE;
X		if (argv[i][j=2] == '\0' && (j = 0 , ++i >= argc)) {
X		    fprintf(stderr, "%s: bad chess program arg\n", argv[0]);
X		    exit(1);
X		}
X		if (chessArgIndex[BLACK] >= MAXCHESSPROCARGS - 1) {
X		    fprintf(stderr, "%s: too many chess program args\n", argv[0]);
X		    exit(1);
X		}
X		ChessProcessArgs[BLACK][chessArgIndex[BLACK]++] = &argv[i][j];
X		ChessProcessArgs[BLACK][chessArgIndex[BLACK]] = (char *) 0;
X		break;
X	    }
X	} else 
X	    cp = argv[i];
X    }
X    if (SetupMode && RestoreFile != (FILE *) 0) {
X	fprintf(stderr, "%s: can only specify one of -r and -s\n", argv[0]);
X	exit(1);
X    }
X    /*
X     * if white is a machine, start up the white chess process and
X     * force us to play the black pieces (if we get to play at all)
X     */
X    if (IsMachine[WHITE]) {
X	InitChessProcess(ChessProcessArgs[WHITE], WHITE, 
X	    ! SetupMode && RestoreFile == (FILE *) 0);
X	PlayerName[WHITE] = ChessProcessArgs[WHITE][0];
X	MyColor = BLACK;
X    }
X    /*
X     * if black is a machine, start up the black chess process and
X     * force us to play the white pieces (if we get to play at all)
X     */
X    if (IsMachine[BLACK]) {
X	InitChessProcess(ChessProcessArgs[BLACK], BLACK, FALSE);
X	PlayerName[BLACK] = ChessProcessArgs[BLACK][0];
X	MyColor = WHITE;
X    }
X    /*
X     * if both players are human, initialize the peer-to-peer RPC 
X     * "connection" 
X     */
X    if ( ! IsMachine[WHITE] && ! IsMachine[BLACK]) {
X	InitRPC(cp, argv[0]);
X    /*
X     * else if both players are machines, lock the mouse to avoid
X     * spectator interference (unless the spectator is going to set
X     * up the cannon fodder first)
X     */
X    } else if (IsMachine[WHITE] && IsMachine[BLACK]) {
X	if ( ! SetupMode)
X	    Mouse = LOCKED;			/* lock out the mouse */
X    /*
X     * else the user is playing a machine
X     */
X    } else {
X	PlayerName[MyColor] = UserPWEntry->pw_name;
X	PeerColor = OTHERCOLOR(MyColor);
X    }
X    signal(SIGINT, bobbyFischer);
X    signal(SIGQUIT, bobbyFischer);
X    signal(SIGHUP, bobbyFischer);
X    /* initialize the board state */
X    InitBoard();
X    /* 
X     * if we want to restore the game and our opponent hasn't beaten
X     * us to it, try to do it now 
X     */
X    if (RestoreFile != (FILE *) 0 && ! RestoringGame)
X	RestoreGame();
X    /* initialize and install the tool */
X    InitTool(useRetained, iconDirectory);
X    tool_install(NchessTool);
X    /* now play the game */
X    RunTool();
X    /* post-game cleanup */
X    KillChessProcesses();
X    SendGoodbye();
X}
X
END_OF_main.c
if test 6364 -ne `wc -c <main.c`; then
    echo shar: \"main.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f msgsw.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"msgsw.c\"
else
echo shar: Extracting \"msgsw.c\" \(1793 characters\)
sed "s/^X//" >msgsw.c <<'END_OF_msgsw.c'
X/*
X * Copyright 1987 Tom Anderson; 20831 Frank Waters Road;
X * Stanwood, WA  98282.   All rights reserved.
X */
X
X/*
X * message subwindow handling
X */
X
X#include <stdio.h>
X#include <ctype.h>
X#include <suntool/tool_hs.h>
X#include <suntool/panel.h>
X#include <strings.h>
X
X#include "nchess.h"
X
Xstruct toolsw * MessageSW;
XPanel MessagePanel;
X
XPanel_item MessageItem;
X
X/*
X * set up the message subwindow
X */
Xvoid
XInitMsgSW()
X{
X    if ((MessageSW = panel_create(NchessTool, 0)) == NULL) {
X	fprintf(stderr, "Can't create message panel\n");
X	exit(1);
X    }
X    MessagePanel = MessageSW->ts_data;
X    /* create the message panel item */
X    MessageItem = panel_create_item(MessagePanel, PANEL_MESSAGE,
X	PANEL_LABEL_STRING, 
X	    RestoringGame ? "Please wait..." :
X	    SetupMode ? "Setup: left - source, middle - delete, right - end" :
X	    IsMachine[Turn] || Turn != MyColor ? 
X		(Turn == WHITE ?
X		    "Waiting for white to play..." : 
X		    "Waiting for black to play...") :
X		"Your move" ,
X	PANEL_SHOW_ITEM, TRUE,
X	0);
X    panel_fit_height(MessagePanel); 
X}
X
Xvoid 
XMessage(cp)
X    char * cp;
X{
X    panel_set(MessageItem,
X	PANEL_LABEL_STRING, cp,
X	PANEL_SHOW_ITEM, TRUE,
X	0);
X}
X
X/*
X * write the standard "your move", "waiting ..." message
X * pre-pended with the passed string (if non-null)
X */
Xvoid
XWhoseMoveMessage(cp)
X    char * cp;
X{
X    char c1[256], c2[256];
X
X    if (GameOver) 
X	strcpy(c2, "Game over");
X    else if (IsMachine[Turn] || Turn != MyColor)
X	strcpy(c2, Turn == WHITE ? 
X	    "Waiting for white to play..." :
X	    "Waiting for black to play...");
X    else if (InCheck())
X	strcpy(c2, "Your move (check)");
X    else
X	strcpy(c2, "Your move");
X
X    if (cp != (char *) 0) {
X	c2[0] = tolower(c2[0]);
X	strcpy(c1, cp);
X	strcat(c1, " - ");
X	Message(strcat(c1, c2));
X    } else 
X	Message(c2);
X}
X
END_OF_msgsw.c
if test 1793 -ne `wc -c <msgsw.c`; then
    echo shar: \"msgsw.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f tool.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"tool.c\"
else
echo shar: Extracting \"tool.c\" \(3131 characters\)
sed "s/^X//" >tool.c <<'END_OF_tool.c'
X/*
X * Copyright 1987 Tom Anderson; 20831 Frank Waters Road;
X * Stanwood, WA  98282.   All rights reserved.
X */
X
X/*
X * handle the tool environment 
X */
X
X#include <stdio.h>
X#include <suntool/tool_hs.h>
X#include <suntool/panel.h>
X#include <suntool/gfxsw.h>
X#include <sys/resource.h>
X#include <sys/ioctl.h>
X#include <strings.h>
X
X#include "nchess.h"
X
XTool * NchessTool;
Xchar ** ToolAttrs = (char **) NULL;
Xchar * ToolName;
X
X/*
X * iconic form of window
X */
Xunsigned short IconImage[] = {
X#include "Icons/nchess.icon"
X};
X
XDEFINE_ICON_FROM_IMAGE(WindowIcon, IconImage);
X
Xsigwinched()
X{
X    tool_sigwinch(NchessTool);
X}
X
X/*
X * parse the tool args.
X */
Xvoid 
XParseToolArgs(argc, argv)
X    int *argc;
X    char **argv;
X{
X    ToolName = argv[0];
X    (*argc)--;
X    argv++;
X    if (tool_parse_all(argc, argv, &ToolAttrs, ToolName) == -1) {
X	tool_usage(ToolName);
X	exit(1);
X    }
X    (*argc)++;
X}
X
X/*
X * set up the tool environment
X */
Xvoid
XInitTool(useRetained, iconDirectory)
X    BOOL useRetained;		/* use a retained pixrect for the board */
X    char * iconDirectory;	/* custom piece icon directory */
X{
X    register unsigned int height;
X    register Toolsw * twsp;
X    char c[256];
X
X    /* create the tool marquee */
X    strcpy(c, " ");
X    strcat(c, PlayerName[WHITE]);
X    strcat(c, " vs. ");
X    strcat(c, PlayerName[BLACK]);
X    if ((NchessTool = tool_make( 
X	WIN_LABEL, c, 
X	WIN_ICON, &WindowIcon, 
X	WIN_ATTR_LIST, ToolAttrs,
X	WIN_WIDTH, 8 * (SQUARE_WIDTH-1) + 2 * tool_borderwidth(NchessTool) - 1,
X	/*
X	 * NOTE: The following line was unnecessary in Sun release 2.2,
X	 * but is necessary in release 3.0.  For some unknown reason, the
X	 * call to tool_set_attributes following the call to InitBoardSW
X	 * now fails to uncover the board area that was obscured by the 
X	 * default tool height being too small (note that the tool has not 
X	 * been installed yet).
X	 */
X	WIN_HEIGHT, 2000,
X	0)) == (Tool *) NULL) 
X    {
X	fputs("Can't make tool\n", stderr);
X	exit(1);
X    }
X    tool_free_attribute_list(ToolAttrs);
X    /* initialize the subwindows */
X    InitTalkSW();
X    InitMsgSW();
X    InitControlSW();
X    InitBoardSW(useRetained, iconDirectory);
X    /* 
X     * add up subwindow heights and force the tool to the resulting size 
X     */
X    height = tool_stripeheight(NchessTool) + tool_borderwidth(NchessTool) - tool_subwindowspacing(NchessTool);
X    for (twsp = NchessTool->tl_sw ; twsp != (Toolsw *) 0 ; twsp = twsp->ts_next) 
X	height += twsp->ts_height + tool_subwindowspacing(NchessTool);
X    /*
X     * NOTE: under 2.2, the above calculation yielded the correct height.
X     * under 3.0, we need to add a few pixels to make it come out right (the
X     * reason is not yet known).
X     */
X    height += 2;
X    tool_set_attributes(NchessTool, WIN_HEIGHT, height, 0); 
X    signal(SIGWINCH, sigwinched);
X}
X
Xvoid
XRunTool()
X{
X    /*
X     * NOTE: this is another difference between release 2.2 and 3.0:
X     * in release 2.2, the SIGWINCH handler would get called once at the
X     * outset to draw the board area; in release 3.0, this doesn't happen.
X     */
X    DrawBoard();
X    tool_select(NchessTool, 0);
X    tool_destroy(NchessTool);
X}
X
END_OF_tool.c
if test 3131 -ne `wc -c <tool.c`; then
    echo shar: \"tool.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
echo shar: End of archive 3 \(of 4\).
cp /dev/null ark3isdone
MISSING=""
for I in 1 2 3 4 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 4 archives.
    rm -f ark[1-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archivelor;;
Xcp