[comp.sources.games] v03i092: cchess - corrispondence chess, Part04/05

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

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


#! /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 4 (of 5)."
# Contents:  Makefile cchess.6 sys.c
# Wrapped by billr@tekred on Tue Jan 12 12:09:55 1988
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f Makefile -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"Makefile\"
else
echo shar: Extracting \"Makefile\" \(12650 characters\)
sed "s/^X//" >Makefile <<'END_OF_Makefile'
X# Cchess Version 1.00
X#
X# (C) Copyright - Jan D. Wolter - Dec 1987.
X#
X# INTRODUCTION
X# Cchess is a corrispondence chess program.  It doesn't play chess, it only
X# moderates games between human players.  A transcript of the game to date
X# is saved in a file in a private directory.  Each time a player makes a
X# move, the other player is notified via system mail.  There are options
X# to play several variant games, to watch replays, and to print transcripts.
X#
X# This program has been written to be as portable as possible without
X# compromising on plain out-right fanciness.  Configuration is supposed to
X# be done mainly by defining a suitable subset of the following flags.  For
X# very non-standard systems it may be necessary to make changes to the code,
X# primarily in the sys.c file, but I hope not.  I have expended quite a bit
X# of trouble trying to make this as simple to port as possible.
X#
X# CCHESS INSTALLATION INSTRUCTIONS:
X# (1) Read the contents of this file to determine what definitions should be
X#     used for your system.  It's not as hard as the size of this file tends
X#     to suggest.  There are sample definitions for several systems where
X#     cchess has been run further below.  Put your defines in with them.
X# (2) Compile cchess with the "make cchess" command.
X# (3) Create the chess transcript directory whose name is given by the
X#     CCDIR definition.  This should be owned by the same uid that will
X#     own the cchess program, and should be permitted "drwx------" (i.e.
X#     to the owner only).
X# (4) Move the compiled cchess program to the place given in RUN_CMD, and
X#     make sure that it is permitted "-rws--x--x".
X# (5) Read the directions below to decide what you want to do about installing
X#     the ccreap utility, if anything.
X#     
X# CCREAP NOTES
X#
X# WARNING:  Ccreap is still somewhat experimental in this release.  Bugs are
X# likely.  Use at your own risk.
X#
X# Ccreap is a program which can be run to remind users to move in old games,
X# and finally delete the games if they have been abandoned long enough.  It
X# also deletes games involving user id's that no longer exist on the system.
X# If your system has plenty of disk space or few cchess players, you may opt
X# to dispense with ccreap entirely.  Ideally a cron table entry should be
X# made to run ccreap once a day (though running it as root is only a good idea
X# if you trust whoever owns the ccreap file a lot).  If this is impractical,
X# ccreap can be run manually by the person administering cchess.  Running it
X# more often than once a day will do neither harm nor good.  Running it less
X# often may lengthen the time between reminders.  Ccreap normally generates
X# no output, so putting the command "/usr/games/lib/ccreap &" in your .login
X# or .profile file may be convenient.   Letting ccreap be run by other users
X# would have the disadvantage that the mail it sends appears to come from
X# whatever person ran the program, which tends to cause confusion.  In any
X# case, if ccreap is to be run by anyone other than root or the account that
X# owns cchess, it should have it's suid bit set.
X#
X# As distributed, ccreap will send a reminder message if 4 days have elapsed
X# with no move made.  7 days later, it will send another.  Then 7 days later
X# it sends a warning to both players that the game will be deleted in 5 days.
X# If 5 days later there has still been no move made, it deletes the game.
X# To alter this schedule, see the comments at the beginning of reap.c.
X#
X# CCHESS CONFIGURATION DEFINITIONS
X# All three of the following must be defined for cchess to compile:
X#
X#   CCDIR	A string giving the full pathname to the cchess transcript
X#		directory.  This is where cchess keeps its game files.
X#		Cchess should have full access.  Other folks should have
X#		neither read nor write access.
X#
X#   GAME_LIST	A string giving the full pathname to the cchess scorefile.
X#		This is where a perminant record of the outcome of all
X#		games is kept.  Normally it is inside the CCDIR, but you
X#		can put it anywhere you please.  Cchess should have read/
X#		write access.  Other folks should not have write access.
X#
X#   RUN_CMD	A string giving the command a user should type to run
X#		the cchess program.  This is used in the mail messages
X#		sent by cchess to tell the recipient how to respond.  If
X#		cchess is being installed in a directory in the normal path
X#		this should just be "cchess".  Otherwise, it should the the
X#		full path to the binary.
X#
X# One of the next six should be defined, depending on the version of Unix you
X# are running:
X#
X#   U43BSD	Define this for Unix 4.3bsd.  Signal handling is done with
X#		the sigvec system.  Sigvec would include signal(),
X#		sigblock(), and sigsetmask().  This also indicates that
X#		directories have the fancier 4.3bsd format, and that the
X#		gettimeofday() call should be used instead of time().  The
X#		default MAILER is the /usr/lib/sendmail program.  The default
X#		tty interface is TSTTY (see below), though TIOCTL could also
X#		be used.  Window sizes are obtained from the kernal instead of
X#		termcaps and the screen is redrawn with new size if SIGWINCH
X#		is recieved.  This should be used for Suns, even if they
X#		claim to be 4.2bsd.
X#
X#   U42BSD	Define this for Unix 4.2bsd.  Currently this has exactly
X#		the same effect as the U43BSD definition, except that it
X#		gets window sizes from the termcaps, not the kernel and
X#		doesn't know about SIGWINCH.  Suns should use U43BSD.
X#
X#   U41BSD	Define this if you have Unix 4.1bsd.  If it is defined,
X#		the default MAILER is /etc/delivermail program.  Also,
X#		signals are handled by the sigsys library.  This would
X#		include sigset(), sigrelse(), sighold(), and sigpause().
X#		If this is defined, then the program should be linked
X#		with the -ljobs option.  The default tty interface is TSTTY,
X#		but TIOCTL can also be used (see below).  Many versions have
X#		elapsed since cchess ran on a 4.1bsd system, but it should
X#		still work.
X#
X#   USYS_5	Define this if you have Unix System V or a better Bell Unix.
X#		If it is defined, the routine to find a character in a
X#		string is called strchr() instead of index().  Signals are
X#		handled with the signal() call, and the default MAILER is
X#		/bin/mail.  The default tty interface is TTERMIO (see below).
X#		The dup2() call is replaced with an fcntl() call.  If you
X#		have SCO Xenix, also define SCO (see below).
X#
X#   USYS_3	Define this if you have Unix System III.  Signals are handled
X#		with the signal() call and the default MAILER is /bin/mail.
X#		The default tty interface is TSTTY (see below), but TTERMIO
X#		can also be used.  USYS_3 is the default if none of the
X#		above are defined.
X#
X# The following may be defined to take care of local oddities.  For normal
X# systems, none of the following should be needed, since the defaults should
X# work.
X#
X#   SCO		Define this flag for SCO Xenix system V.  It does a few
X#		strange things to avoid compiler bugs that existed in the
X#		Release 2.2.1 SCO.  It is unlikely to do any good for any
X#		other unix.
X#
X#   UNCHAR	Define this flag if characters are unsigned on your machine.
X#		If this is the case, shorts will be used for signed
X#		characters.  Most machines don't need this.  Cchess will
X#		get real confused about colors of players and what moves
X#		are legal if this is needed, but not defined.  Cchess will
X#		work fine if it is defined unnecessarily, but will use a
X#		wee bit more memory than necessary.  It is automatically
X#		set when running lint on cchess.
X#
X#   NOTERMCAP	Unless this is defined cchess will use the termcap library
X#		to update the screen.   Most Unixes seem to have this or
X#		termlib, which works equally well for the purposes of cchess.
X#		Termcap contains the routines tgetent(), tgetnum(),
X#		tgetflag(), tgetstr(), tgoto(), and tputs().  These normally
X#		require adding the -ltermcap or -ltermlib flags to compile
X#		command.  Without termcaps, cchess will still work, but nearly
X#		all the fancy display handling will be lost.
X#
X#   MAILER	If the full pathname of the mailer is different than the
X#		default described above for your version of Unix, set this
X#		to the full pathname (e.g. "/usr/bin/mail").
X#
X#   NODUP2	If this is defined, the dup2() call is avoided.  This is the
X#		default for USYS_V, where that seems to be missing.
X#
X#   TSTTY	If this is defined, cchess will use the call gtty() and
X#		stty() to set cbreak mode and noecho.  This is the default
X#		for all systems except USYS_V, where stty() has been phased
X#		out in favor of the TTERMIO ioctl calls.
X#
X#   TTERMIO	If this is defined and TSTTY is not defined, cchess attempts
X#		to set cbreak and noecho with System V style ioctl() calls.
X#		This is the default for USYS_V.
X#
X#   TIOCTL	If this is set and neither TSTTY nor TTERMIO are, then cchess
X#		attempts to set cbreak and noecho mode with version 6 style
X#		ioctl() calls.  This should work with Version 6, Version 7,
X#		and Berkeley unixes.
X#
X#   COMPAT018	Defining this includes code to allow cchess to handle game
X#		files created under cchess version 0.18.  If not defined,
X#		cchess will choke on such files.  You only need this if you
X#		are upgrading an installation that already has a previous
X#		version of cchess, and even then you may prefer to edit the
X#		old files into the new format.
X#
X#	All externals variables are unique in the first seven characters.
X#	There are several cases where the first six characters are nonunique.
X#	You'll have to change these if your linker is that brain damaged.
X#
X#	There should be no problems for systems with short 16-bit integers.
X#
X#	The following option is intended only for debugging, and should not
X#	be included in the installed game.
X#
X#   DEBUG	If DEBUG is defined cchess recognizes the -d option.  Two
X#		player names must be given with the -d option.  The program
X#		runs (for most purposes) as if you are the second person
X#		named, playing against the first person named.  Mail is sent
X#		to the person whose name DEBUG is set to.
X#
X#---------------------------------------------------------------------------
X# The following are sample definitions.  It should be noted that some are
X# largely fictional, since I don't have much access to some of these.  Make
X# a copy of the one nearest your system, delete the #'s and change the
X# CCDIR, GAME_LIST, and RUN_CMD to something appropriate.
X#
X# Unix System III.  Altos 68000.  (short integers)
X#LIBS   = -ltermcap
X#CFLAGS = -DRUN_CMD='"cchess"'\
X#         -DGAME_LIST='"/usr/games/lib/chessboard/gamelist"'\
X#         -DCCDIR='"/usr/games/lib/chessboard"'\
X#         -DUSYS_3
X#
X# Unix 4.1bsd.  Vax 11/780.
X#LIBS   = -ltermcap -ljobs
X#CFLAGS = -DRUN_CMD='"cchess"'\
X#         -DGAME_LIST='"/usr/games/lib/chessboard/gamelist"'\
X#         -DCCDIR='"/usr/games/lib/chessboard"'\
X#         -DU41BSD
X#
X# Unix 4.2bsd.  Vax 11/780.  (for Suns, use 4.3bsd definition)
X#LIBS   = -ltermcap
X#CFLAGS = -DRUN_CMD='"\~janc/bin/cchess"'\
X#         -DGAME_LIST='"/e/janc/bin/src/cchess/boards/gamelist"'\
X#         -DCCDIR='"/e/janc/bin/src/cchess/boards"'\
X#         -DU42BSD
X#
X# Unix 4.3bsd.  Vax 11/780.  (or Sun 3/50 running 4.2bsd)
X#LIBS   = -ltermcap
X#CFLAGS = -DRUN_CMD='"\~janc/bin/cchess"'\
X#         -DGAME_LIST='"/n/logan/u/janc/bin/src/cchess/boards/gamelist"'\
X#         -DCCDIR='"/n/logan/u/janc/bin/src/cchess/boards"'\
X#         -DU43BSD
X#
X# IBM PC/AT running SCO Xenix System V Rel 2.2.1.  Uses Large Memory Model.
X#LIBS   = -ltermcap
X#CFLAGS = -Ml\
X#         -DRUN_CMD='"/u/guest/janc/cchess"'\
X#         -DGAME_LIST='"/u/guest/janc/Cchess/boards/gamelist"'\
X#         -DCCDIR='"/u/guest/janc/Cchess/boards"'\
X#         -DMAILER='"/usr/bin/mail"'\
X#         -DUSYS_5\
X#         -DSCO
X#
X# IBM PC/AT running Microport System V.  Uses Large Memory Model.
X#     Thanks to John Sucilla for this.
X#LIBS   = -lcurses
X#CFLAGS = -Ml\
X#         -DRUN_CMD='"/usr/lbin/cchess"'\
X#         -DGAME_LIST='"/usr/lbin/Cchess/boards/gamelist"'\
X#         -DCCDIR='"/usr/lbin/Cchess/boards"'\
X#         -DUSYS_5
X#
X
XOBJ = main.o cmd.o init.o play.o misc.o scrn.o sys.o
XSRC = main.c cmd.c init.c play.c misc.c scrn.c sys.c 
X
X# NOTE:  If the make command gives an error message about missing separators
X# in the following lines, it may be because the tabs have gotten expanded into
X# spaces during file transfer.  Turn them back into tabs to fix this.
X
Xcchess:	$(OBJ)
X	cc $(CFLAGS) -o cchess $(OBJ) $(LIBS)
X	chmod 4711 cchess
X
Xccreap: reap.o
X	cc -o ccreap reap.o $(LIBS)
X	chmod 4711 ccreap
X
Xtags: $(SRC) cchess.h def.h
X	ctags $(SRC) cchess.h def.h
X
Xlint:
X	lint -cha $(CFLAGS) $(SRC) $(LIBS)
X
Xcchess.doc: cchess.6
X	nroff -man cchess.6 | uniq > cchess.doc
END_OF_Makefile
if test 12650 -ne `wc -c <Makefile`; then
    echo shar: \"Makefile\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f cchess.6 -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"cchess.6\"
else
echo shar: Extracting \"cchess.6\" \(16656 characters\)
sed "s/^X//" >cchess.6 <<'END_OF_cchess.6'
X.TH CCHESS 6 12/26/84
X.UC 4
X.SH NAME
Xcchess \- Correspondence Chess Game
X.SH SYNOPSIS
X.B cchess
X[
X.B \-a
X]
X[
X[
X.B \-t
X]
X[
X.B \-b
X]
X.B player1
X[
X.B player2
X]
X]
X[
X.B \-s
X]
X[
X.B \-g
X[
X.B player
X]
X]
X.SH DESCRIPTION
X.I  Cchess
Xis a correspondence chess game moderator.
XIt allows players on a Unix system to challenge each other to chess games,
Xwith notification of moves sent by mail.
XIt does not allow for play across uucp-type networks.
X.PP
XTo challenge another user, or to continue a game already begun,
X.I cchess
Xshould be run with a single argument:  the userid of the other player.
XTo experiment, you may challenge yourself to a game of chess.
XNote that in this case, no notification of moves is sent by mail.
XIf run with two userid as arguments,
X.I cchess
Xwill allow you to view a game between the two players named, if the game
Xis not a private one.
X.PP
XThe command line options are:
X.TP
X.B \-s
XPrint a scoreboard showing the outcome of all games completed on the system.
X.TP
X.B \-g
XPrint a list of all games currently in progress on the system.  If a user
Xid is given after the -g option, only games involving that player are
Xprinted.
X.TP
X.B \-a
XIf no player names are given with the -a flag, cchess finds all games in
Xwhich it is your turn to move, and runs the program on each one.  If one
Xplayer name is given, it gives you a chance to view all non-private
Xgames involving the named player.
X.TP
X.B \-b
XDisplay chessboards in a larger format with highlighted pieces.
XA terminal with 24 lines and 80 columns is just adequate for standard chess.
XIf you are playing the Courier variant game, you need 90 columns.
XIf your screen is plainly too small, this option will be ignored.
X.TP
X.B \-t
XPrint a transcript of a game between the user and one named player, or
Xbetween two other users, if two names are given.  Transcripts
Xof private games cannot be printed, unless the user is one of the players.
XThis may be used with the -a flag.
X.PP
XWhen you make a challenge, you will be asked to choose from several options.
XYou can choose which color you want, whether you want the game to be private,
Xand whether you want to play a variant game.
XA large number of variant games are supported, and it is possible to combine
Xthe various standard variants to create entirely new games.
XThe standard variants will be described below.
X.PP
XYou may also choose if you want computer kibitzing.
XThis option is intended as a compensation for the poor board graphics.
XIt causes the computer to warn you
Xif it looks like you might be throwing a piece away.
XHowever, the algorithm is deliberately stupid -- 
Xit will overlook anything that is even vaguely subtle.
XIt doesn't know about checks or look ahead more than one move,
Xmuch less appreciate the potential of a sacrifice.
XI recommend its use, since the only kind of mistakes it catches are those
Xof such incredible stupidity that they tend to spoil the game for both
Xplayers.
X.PP
XThe person you have challenged will receive a message in the mail telling
Xhim he has been challenged, and describing how to respond to the challenge.
XHe does this by running
X.I cchess
Xwith your login name as an argument.  He will be given the choice of
Xaccepting your challenge, counter-challenging you (with different options),
Xor rejecting your challenge.  If he accepts and is white, he will be asked
Xfor his opening move.  In any case, you will be notified of the result by
Xmail.
X.PP
XWhen moving you will be shown a (rather crude) representation of the
Xboard, and will be asked if you wish to move, forfeit, propose a draw,
Xor watch a playback of the last few positions.  Moves are entered in a
Xmodified algebraic notation (e.g. "E2-E4" for a king pawn opening).  To
Xcastle, move the king two spaces to his left or right.  En passaunt 
Xand pawn promotion are fully supported.  You
Xwill be given one chance to take back your move before it is saved.
XAlso, you can attach a short comment to each move.
XThis will be displayed for the other player along with your move.
X.PP
XSome of the legal commands are given in the prompt,
Xbut there are a several others that may be issued.
X"H" can be entered to ask for help,
X"Q" can be entered to quit,
Xor "^L" can be entered to redraw the screen.
XUnfortunately, these don't work everywhere.
XAlso "V" prints the current
X.I cchess
Xversion number, "O" prints the
Xcurrent game options.
XFinally, the "C" command may be used to propose that the game be cancelled
X(that is ended without recording a win for either player).
XThe other player will have to agree to this before it takes affect.
X.PP
X.I Cchess
Xwill detect checks, checkmates and stalemates in which a player cannot move.
XIf a position is repeated for the third time, or if fifty moves elapse
Xwithout a pawn move or a capture, players have the option of declaring the
Xgame a draw unilaterally.
XPerpetual check is not detected.
XWhen a game is over, both players will be given a chance to see a playback
Xand save a transcript of the game.
X.PP
X.I Cchess
Xlooks in the file
X.I /etc/termcap
Xto determine terminal characteristics,
Xbut does not really need a smart terminal.  It is designed to be
Xrunnable on virtually any terminal including hard copy terminals
X(extremely small displays could be a problem), while still taking
Xmaximum advantage of the capabilities which are available.
XIf the TERM variable is not set, it assumes you have a 40 column dumb terminal.
X.PP
XIf the "ccreap" program has been installed, it will send mail to remind
Xpeople to move in games if they haven't moved for a while.
XIt will eventually delete games that appear to have been abandoned.
X.PP
XThe variant games supported by
X.I cchess
Xare listed below:
X.SH KRIEGSPIEL
X.PP
XKriegspiel was invented by W. H. Temple sometime around 1900.
XIn the Kriegspiel variant game, you will not be shown the other player's
Xpieces, nor will you be told his moves.
XYou will only be told if the moves you try are legal.
XOnce you propose a legal move, you cannot take the move back.
XYou will be told when you take a piece, and your opponent
Xwill be told how many illegal moves you tried before finding a legal move.
XNote that in Kriegspiel once you propose a move,
Xyou will not be allowed to exit the program until you make a legal one.
XThe current implementation of Kriegspiel gets some of the rules wrong.
XOne of these days I'll correct this.
X.SH SHATRANJ
X.PP
XThe Shatranj variant game is one of the oldest known versions of chess.
XIt originated in Persia around the 6th century AD, and
Xis almost identical to chaturanga, an older Hindi game.
XIt is the version of chess first introduced in Europe around the 10th century
Xwhere it prevailed until the 15th century.
XIt plays slower than modern chess, and has more of the tone of a wargame.
X.PP
XThe board is the same as the modern board, but is not checkered.
XThe pieces are given their Persian names,
Xbut only two are actually different from the modern pieces.
XReplacing the queen, there is a much weaker piece called the minister
X(firz).
XThe minister can move one square along any of the four diagonals.
XInstead of bishops, there are elephants (fil) which move exactly
Xtwo squares along any diagonal, and can jump over any piece on the
Xintervening square.
XIn addition, the rules which allow
Xpawns (baidaq) to move two squares on their first move,
Xand the king (shah) to castle with a rook (ruhk) were not yet introduced.
XA stalemate is counted a win for the player who can not move.
XIf a player loses all his forces except his king (shah),
Xhe loses the game, even if his opponent lacks mating material.
XCchess adopts the common practice of allowing players to move ten
Xpieces on their first turn, with the restriction that no piece may
Xcross the centerline of the board.  The position reached by these opening
Xmoves is called the Ta'biyat.
X.SH COURIER
X.PP
XCourier is a 13th century European development of shatranj.
XIt is played on a oversized chess board having 12 columns and 8 rows.
XEach player has 12 pawns and 12 miscellaneous major pieces.
XTo minimize confusion,
Xthe names of many of the pieces have been altered in this implementation.
XThe pawn, rook, knight, and king move like their counterparts in both
Xshatranj and modern chess.  The elephant and minister move exactly
Xas in shatranj.  There are also two bishops, which are
Xthe "couriers" after whom the game is named.
XFurthermore, there is a duke (or sneak) which can move one
Xsquare forward, backward, left or right, and there is a jester (or man)
Xwho moves exactly like a king, but, unlike the king, has no special value.
XNeither castling, nor double moves for pawns are allowed, these being
Xrecent innovations.
XStalemates and the loss of forces are treated as in shatranj.
XEach player is allowed to move 12 pieces on his first turn.
X.PP
XActually, several references describe various other peculiar rules
Xwhich cchess does not support.
XFor example,
Xinstead of allowing multiple moves on the first turn,
Xthe minister, the minister pawn and both rook pawns were sometimes
Xallowed to leap two space forward on the first move.
XPawn promotion may have required the pawn to move back to it's starting
Xrank two squares at a time before being promoted.
X.SH RIFLE CHESS
X.PP
XThis modern variant was devised by W. J. Seabrook in 1921.
XWhen a capture is made, the captured piece is removed,
Xbut the capturing piece remains on its original square, having,
Xin affect, shot the enemy from afar.
XOtherwise, play is as usual.
X.SH KAMIKAZI CHESS
X.PP
XThis variant game was devised by Pierre Monreal in 1965.
XWhen a capture is made, both pieces capturing and captured piece are removed.
XThe king is not allowed to make captures, even to escape mate.
XPossibly, the king should be allowed to capture with impunity;
Xmy source didn't specify this.
X.SH KARMA CHESS
X.PP
XThis variant game arose entirely from the author's fevered imagination.
XIt is played exactly as regular chess, except that when a piece captures
Xanother, it is transformed to a piece of the same rank as the captured piece.
XFor example, if a black pawn should succeed in capturing a white queen,
Xit is immediately reincarnated as a black queen.
XOn the other hand, if a queen should stoop so low as to slay a pawn,
Xshe will immediately be demoted to a pawn.
XThis holds for all pieces except, of course, the King, who, as the
XEmbodiment of the Law, may take any piece without loss of rank.
XThe dynamics of attack and defense are very different in Karma
XChess.  In fact, the computer kibitzer is badly confused by Karma
XChess, and is therefore not available.
X.SH CONVERSION CHESS
X.PP
XThis variant was invented and originally implemented in cchess by
XKenneth Larimer.  It is played like regular chess, but when a piece
Xcaptures it remains in it's original square, and the attacked piece
Xis converted to the attacker's color.  However, if the converted piece
Xis attacked again by the other player in the next turn it is destroyed
Xas in rifle chess.  It may thus be considered a combination of rifle
Xand karma chess.  It seems to play quite well.
X.SH HALFBOARD CHESS
X.PP
XHalfboard chess is played on a 4 by 8 board, with each player having only
Xa king, a bishop, a knight, a rook, and four pawns.  It normally leads to
Xa shorter game than standard chess.
X.SH DOUBLE CHESS
X.PP
XIn double chess (or Marselles) each player makes two moves in each turn.
XPlayers may not impose check until the last move of the turn, nor must a
Xplayer's king be moved out of check until his last move.  Checkmate and
Xstalemate detection don't work in double chess.  If you're checkmated,
Xforfiet.
X.SH STEAMROLLER
X.PP
XIn the Steamroller variant, Black's pieces are as in normal chess, but White
Xhas only a king and his four center pawns.  As compensation, white may move
Xtwice in each turn.  White may not apply check until his second move.  It
Xis legal for white to be in check at the end of his first move.
X. I Cchess
Xwill not annouce checkmate or stalemate against the white player.  It is
Xup to the white player to forfiet if he is checkmated or stalemated.
XI understand white has the advantage in this variant.
X.SH PROGRESSIVE CHESS
X.PP
XIn Progressive chess, the White moves once on his first move, then Black
Xmoves twice, then White moves three times, then Black moves four times,
Xand so on, with each player making one more move than the last player did.
XAs in double chess and steamroller, check may not be applied till the
Xlast move of a players turn.  I've never found a really satisfactory way to
Xset up the mating rules.  Allowing the king to move through check makes it
Ximpossible to checkmate him before very many moves.  Not allowing him to
Xmove through check makes it too easy to mate him (I think there might be
Xa sure win for one player in this version).  Currently the default rule is
Xthat the king is just a normal piece, and you must capture all enemy pieces
Xto win.  Games seem to be quite short.
X.SH MAHARAJAH
X.PP
XIn Maharajah (a.k.a. Maharajah and the Savoys),
Xwhite has only one piece: a maharajah.  The maharajah can
Xmove along ranks, files and diagonals like a queen plus it can jump like
Xa knight.  Black has the normal complement of chess pieces.  It seems that
Xthis game can normally be won by the black player, if he is sufficiently
Xcareful.
X.SH LOSING CHESS
X.PP
XIn losing chess, the winner is the player who first gets stalemated or
Xloses all his pieces. 
XIf a player can make a capture, he is required to do so.
XThere are no checks or checkmates.
XThe king is treated just like any other piece.
X.SH MIXED GAMES
X.PP
XThe above games are actually just standard combinations of a wide variety
Xof low-level game options.  It is possible to brew up games of your own by
Xcombining these options in new ways, and by editting the initial set up
Xof the board.  The board editor has a 'H' help command that should be clear
Xenough.
XMost of the low-level options are easily understood if you are familiar with
Xthe variant games above.  Cchess makes some attempt to suppress combinations
Xthat will confuse it badly, but it's not really thorough about it.  A few
Xnotes are in order.
X.PP
XEach player can have a "mateable piece" defined.  This is normally the king,
Xbut in the Maharajah variant, the white mateable piece is the Maharajah.
XA player is considered to be in check if his mateable piece is being attacked.
XIn some variants, there are no mateable pieces (e.g. Hexapawn and Losing
XGames).  The board editor insists that each player who has a mateable piece
Xdefined have exactly one on the board.  Another option allows the capture
Xrules to be selected.  These may be different for normal pieces and mateable
Xpieces.  If multiple moves are allowed, you must specify whether the
Xmateable pieces may move through check (they may never be left in check
Xafter the players last move).  If they are allowed to move through check,
Xthe automatic checkmate detection code will not operate.  Regardless of
Xwhat your mateable piece is, only kings & rooks can castle.  Even if you
Xallow castling, it will only work if there is rook on the edge of the
Xboard in the same row as a king.  If you have multiple kings, only one
Xis allowed to castle in the course of a game.  Jesters differ from kings
Xonly in that they can't castle.  There are three options for pawn promotion.
XThe option that normally allows promotion to either a Queen, a Rook, a Knight
Xor a Bishop, also allows promotion to a King.
XIt is, however, never legal to promote to a mateable piece.
XThe option that disallows promotion is automatically used if the pawn is
Xa mateable piece.
X.SH BUGS
X.PP
XThe board is hard to see at first
Xbecause of the limited graphics capability.
XIt may help to set up a real board to figure out your moves on.
X.I Cchess
Xwon't work over intersystem mail, because all transcripts
Xare kept in a local game file.
XThe rules for variant games are disputable.
XPawn promotion is not announced for kriegspiel players.
XThe scoreboard should be sorted in some intelligent order.
XBeyond this, the wide variety of options which can be combined in Mixed
XGames undoubtedly lead to more bugs than the author cares to think about.
X.PP
XAlso note that while
X.I cchess
Xwill work with just about any terminal, it is
Xmore picky than many other programs about the strict correctness of the
Xtermcap.  For example, if neither the "bs" nor the "bc" field is defined
Xin the termcap,
X.I cchess
Xwill refuse to backspace.
X.PP
XIt is also hard to tell if your opponent is using a chess program to generate
Xhis moves.  This is one of the advantages of playing variant games.
X.SH AUTHOR
XJan Wolter (janc@crim.eecs.umich.edu)
X.SH FILES
X.DT
X/etc/termcap	Terminal data base.
X.br
X/usr/games/lib/chessboards	Directory for games in progress.
X.br
X/usr/games/lib/chessboards/gamelist	Record of past games.
END_OF_cchess.6
if test 16656 -ne `wc -c <cchess.6`; then
    echo shar: \"cchess.6\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f sys.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"sys.c\"
else
echo shar: Extracting \"sys.c\" \(17055 characters\)
sed "s/^X//" >sys.c <<'END_OF_sys.c'
X/* CCHESS SYSTEM ROUTINES.					Version 1.00
X *
X *   This is mostly low level i/o stuff and machine dependent routines.
X *
X *   (C) Copyright Jan Wolter - Apr 1986.
X */
X
X#include "cchess.h"
X#ifdef U42BSD
X#  include <sys/time.h>
X#  include <sys/types.h>
X#else
X   long time();
X#endif U42BSD
X#ifdef NODUP2
X#  include <fcntl.h>
X#endif NODUP2
X
X/* Default mode setting systems */
X
X#ifndef TSTTY
X#  ifndef TTERMIO
X#    ifndef TIOCTL
X#      ifdef USYS_5
X#        define TTERMIO
X#      else
X#        define TSTTY
X#      endif USYS_5
X#    endif TIOCTL
X#  endif TTERMIO
X#endif TSTTY
X
X/* Make sure at most one of the mode setting variables is defined */
X
X#ifndef TSTTY
X#  ifndef TTERMIO
X#    ifdef TIOCTL
X#      define TSTTY
X#      define setmode(x) ioctl(0,TIOCSETN,&x);
X#      define getmode(x) ioctl(2,TIOCGETP,&x);
X#    endif TIOCTL
X#  endif TTERMIO
X#else TSTTY
X#  undef TTERMIO
X#  define setmode(x) stty(0,&x);
X#  define getmode(x) gtty(2,&x);
X#endif TSTTY
X
X
X/* Names for the signal definition routine in various signal handlers */
X
X#ifdef LSIGNAL
X#  define sigdef signal
X#endif LSIGNAL
X#ifdef LSIGSYS
X#  define sigdef sigset
X#endif LSIGSYS
X#ifdef LSIGVEC
X#  define sigdef signal
X#endif LSIGVEC
X
X#ifndef NOTERMCAP
Xshort ospeed;			/* The output baud rate */
X#endif NOTERMCAP
X
X/* Stuff for the stty or old style ioctl() command */
X
Xstatic boolean funnymodes = FALSE;
X
X#ifdef TSTTY
X#include <sgtty.h>
Xstatic struct sgttyb p;
Xstatic short tpf;
X#endif TSTTY
X
X#ifdef TTERMIO
X#include <termio.h>
Xstatic struct termio tio;
Xstatic tofg,tlfg;
Xstatic tcc4;
Xstatic tcc5;
X#endif TTERMIO
X
X/* ENTER()
X *
X *   These routines get a character from the keyboard.  Characters are converted
X *   to upper case, and only those appearing in <string> are accepted.  All
X *   other characters are received with a bell, and ignored.  If the character
X *   happens to be ^L, then it isn't echoed.  xenter() is the same as enter,
X *   but never echos the character.  While reading input, it maps the backspace
X *   character defined by the user via the "stty erase" command to '\b'.
X *   Thus routines calling these don't have to worry about what the backspace
X *   character really is. xenterd() and enterd() are the same as xenter and
X *   enter, only if the character input is a `\n', it returns the given default
X *   value instead.
X */
X
Xchar enter(string)
Xchar *string;
X{
Xregister char ch;
X	ch = xenter(string);
X	if (ch != '\014')
X		wputchar(ch);
X	return(ch);
X}
X
Xchar enterd(string,def)
Xchar *string;
Xchar def;
X{
Xregister char ch;
X	wputchar(ch = xenterd(string,def));
X	return(ch);
X}
X
Xchar xenter(string)
Xchar *string;
X{
Xregister char ch;
X
X	for (;;)
X	{
X#ifdef LSIGNAL
X		ch = getchar();
X#else
X		if (susp1_flg)
X			ch = getchar();
X		else
X		{
X			if ((susp2_flg || setjmp(susp_env)) &&
X				index(string,'\014') != 0)
X			{
X				susp2_flg = FALSE;
X				return('\014');
X			}
X			susp1_flg = TRUE;
X			ch = getchar();
X			susp1_flg = FALSE;
X		}
X#endif LSIGNAL
X		if (ch == bs_char)
X			ch = '\b';
X#ifdef TSTTY
X		/* Map CR to NL on input, because we had to turn it off */
X		else if (ch == '\r')
X			ch = '\n';
X#endif TSTTY
X		else if (ch >= 'a' && ch <= 'z')
X			ch -= 'a'-'A';
X		if (index(string,ch) != 0)
X			return(ch);
X		bell();
X	}
X}
X
Xchar xenterd(string,def)
Xchar *string;
Xchar def;
X{
Xregister char ch;
X
X	for (;;)
X	{
X#ifdef LSIGNAL
X		ch = getchar();
X#else
X		if (susp1_flg)
X			ch = getchar();
X		else
X		{
X			if ((susp2_flg || setjmp(susp_env)) &&
X				index(string,'\014') != 0)
X			{
X				susp2_flg = FALSE;
X				return('\014');
X			}
X			susp1_flg = TRUE;
X			ch = getchar();
X			susp1_flg = FALSE;
X		}
X#endif LSIGNAL
X		if (ch == '\n' || ch == '\r')
X			return(def);
X
X		if (ch == bs_char)
X			ch = '\b';
X		else if (ch >= 'a' && ch <= 'z')
X			ch -= 'a'-'A';
X
X		if (index(string,ch) != 0)
X			return(ch);
X		bell();
X	}
X}
X
X
X/* ENTERYN()
X *
X *   Enter Yes or No - Just like (enter("YN")=='Y' but it completes the word
X *   "Yes" or "No" with a linefeed at the end.  Enterdyn() uses the given
X *   default if return is entered.
X */
X
Xchar enteryn()
X{
Xregister boolean f;
X
X	f = (xenter("YN") == 'Y');
X	wprint(yorn(f));
X	wputchar('\n');
X	return(f);
X}
X
Xboolean enterdyn(def)
Xboolean def;
X{
Xregister char ch;
Xregister boolean f;
X
X	f = ((ch = xenter("YN\n")) == 'Y' || (ch == '\n' && def));
X	wprint(yorn(f));
X	wputchar('\n');
X	return(f);
X}
X
X/* FGETL()
X *
X *   This is fgets() fixed to throw away the reminants of lines that are too
X *   long for the input buffer.  It does not include the newline on the end
X *   of the line.
X */
X
Xchar *fgetl(buf,len,fp)
XREGISTER char *buf;
XREGISTER int len;
XFILE *fp;
X{
Xregister int c,i;
X
X	i=0;
X	while((c=getc(fp)) != '\n')
X	{
X		if (c == EOF) return(NULL);
X		if (i < len) buf[i++] = c;
X	}
X	buf[i] = '\0';
X	return(buf);
X}
X
X/* READSTR()
X *
X *   This routine reads a string into <buffer> starting at character index <a>
X *   and with the last character not beyond the <l>th character.  It returns the
X *   index of the null at the end of the string.  If the flag <isfile> is set,
X *   ~'s are expanded out automatically in the first column and spaces are
X *   turned into underscores.  Neither leading nor tailing spaces are allowed.
X */
X
Xint readstr(buffer,a,l,isfile)
XREGISTER char *buffer;
Xint a,l;
X{
Xregister int i = a;
X
X	while((buffer[i] = getchar()) != '\n' && buffer[i] != '\r')
X	{
X		if (i == a )
X		{
X			/* No leading spaces or backspaces */
X			if (buffer[a] == ' ' || buffer[a] == bs_char) continue;
X
X			/* Expand a tilde into the home directory name */
X			if (isfile && buffer[a] == '~')
X			{
X				strcpy(buffer+a,getenv("HOME"));
X				while(buffer[i] != 0)
X					wputchar(buffer[i++]);
X				continue;
X			}
X		}
X
X		/* Do backspaces */
X		if (buffer[i]==bs_char)
X		{
X			i--;
X			if (erases)
X			{
X				backspace();
X				wputchar(' ');
X				backspace();
X			}
X			else wputchar(buffer[i]);
X		}
X		else if (i < l && !iscntrl(buffer[i]))
X		{
X			if (isfile && buffer[i] == ' ')
X				buffer[i] = '_';
X			wputchar(buffer[i++]);
X		}
X		else
X			/* Bell all other nonprintables */
X			bell();
X	}
X	/* delete trailing spaces */
X	while(i > 0 && buffer[--i] == (isfile ? '_' : ' '))
X		;
X	if (i > 0) i++;
X	buffer[i] = '\0';
X	wputchar('\n');
X	return(i);
X}
X
X/* READDINT()
X *
X *   This is like readint(), but it prints and returns the default value
X *   given if the person doesn't type anything.
X */
X
Xint readdint(max,def)
Xint max,def;
X{
Xint x;
X	if (x = readint(max)) return(x);
X	wprintf("%d",def);
X	return(def);
X}
X
X/* READINT()
X *
X *   This routine reads an integer between 1 and <max> from the user.  It
X *   fights desparately to keep him from entering anything out of range.
X *   It returns 0 if the user doesn't type anything.
X */
X
Xstatic char digitstr[] = "0123456789\b\n";
X
Xint readint(max)
Xint max;
X{
Xregister int i,j;
Xchar ch;
Xshort ox=cx;
X
X	i = 0;
X	while ((ch=xenter(digitstr))!='\n')
X	{
X		if ((ch == '0') && (i == 0))
X		{
X			bell();
X			continue;
X		}
X		if (ch == '\b')
X		{
X			if (i == 0)
X				bell();
X			else
X			{
X				i /= 10;
X				if (erases)
X				{
X					backspace();
X					wputchar(' ');
X					backspace();
X				}
X				else
X				{
X					indent(ox-1);
X					if (i>0) wprintf("%d",i);
X				}
X			}
X			continue;
X		}
X		j = i*10 + ch - '0';
X		if (j > max)
X			bell();
X		else
X		{
X			i = j;
X			wputchar(ch);
X		}
X	}
X	return(i);
X}
X
X/* RESETTY
X *
X * Return ttymodes to normal.
X *
X */
X
Xresetty()
X{
X	if (funnymodes)
X	{
X		term_exit();
X		funnymodes = FALSE;
X#ifdef TSTTY
X		p.sg_flags = tpf;
X		setmode(p);
X#endif TSTTY
X#ifdef TTERMIO
X		tio.c_lflag = tlfg;
X		tio.c_oflag = tofg;
X		tio.c_cc[4] = tcc4;
X		tio.c_cc[5] = tcc5;
X		ioctl(0,TCSETA,&tio);
X#endif TTERMIO
X	}
X}
X
X/* DONE()
X *
X *   This is used as the exit routine after we are in cbreak mode.
X *   It resets to whatever mode we were in originally before exiting
X *   with the error code in the arguement.
X */
X
Xdone(code)
Xint code;
X{
X	/* If we are doing each game, go on to the next */
X	if (eachgame)
X	{
X		fclose(wfp);
X		fclose(rfp);
X		longjmp(jmpenv,code?code:10);
X	}
X
X	/* restore modes */
X	resetty();
X	exit(code);
X}
X
X/* INTR()
X *
X *   This is the BREAK interupt service routine.  It refuses to do anything
X *   if the interupt flag is not set true.
X */
X
Xintr()
X{
X	if (interupt)
X	{
X		resetty();
X		sigdef(SIGINT,SIG_DFL);
X		kill(getpid(),SIGINT);
X#ifdef LSIGNAL
X		pause(SIGINT);
X#endif LSIGNAL
X#ifdef LSIGSYS
X		sigpause(SIGINT);
X#endif LSIGSYS
X#ifdef LSIGVEC
X		sigpause(0);
X#endif LSIGVEC
X	}
X}
X
X#ifndef LSIGNAL
X
X/* SUSP()
X *
X *   This is the suspend interupt service routine.  It's a kludge but it works
X *   real well.  Resets fancy modes before exiting, and puts them back on
X *   restart.
X */
Xsusp()
X{
X#ifdef LSIGVEC
Xint mask;
X#endif LSIGVEC
X#ifdef TSTTY
Xshort tpf2;
X#endif TSTTY
X#ifdef TTERMIO
Xshort tofg2,tlfg2;
X#endif TTERMIO
X
X	if (interupt)
X	{
X#ifdef LSIGVEC
X		/* record current signal mask */
X		mask = sigblock(sigmask(SIGTSTP));
X#endif LSIGVEC
X		/* reset modes before suspending */
X		term_exit();
X#ifdef TSTTY
X		tpf2 = p.sg_flags;
X		p.sg_flags = tpf;
X		setmode(p);
X#endif TSTTY
X#ifdef TTERMIO
X		tlfg2 = tio.c_lflag;
X		tofg2 = tio.c_oflag;
X		tio.c_lflag = tlfg;
X		tio.c_lflag = tofg;
X		ioctl(0,TCSETA,&tio);
X#endif TTERMIO
X#ifdef LSIGSYS
X		/* The sigsys way: */
X		sigset(SIGTSTP,SIG_DFL);
X		kill(getpid(),SIGTSTP);
X		sigrelse(SIGTSTP);
X
X		/* STOP HERE */
X
X		/* put modes back before resuming */
X		sighold(SIGTSTP);
X		sigset(SIGTSTP,susp);
X		sigset(SIGINT,intr);
X#endif LSIGSYS
X#ifdef LSIGVEC
X		/* The sigvec way: */
X		sigdef(SIGTSTP,SIG_DFL);
X		sigsetmask(0);
X		kill(getpid(),SIGTSTP);
X
X		/* STOP HERE */
X
X		sigsetmask(mask);
X		sigdef(SIGTSTP,susp);
X		sigdef(SIGINT,intr);
X#endif LSIGVEC
X#ifdef TSTTY
X		p.sg_flags = tpf2;
X		setmode(p);
X#endif TSTTY
X#ifdef TTERMIO
X		tio.c_lflag = tlfg2;
X		tio.c_oflag = tofg2;
X		tio.c_cc[4] = 1;
X		tio.c_cc[5] = 0;
X		ioctl(0,TCSETA,&tio);
X#endif TTERMIO
X		term_init();
X		susp2_flg = TRUE;
X		if (susp1_flg) longjmp(susp_env,1);
X	}
X}
X#endif LSIGNAL
X
X#ifdef U43BSD
X/* This is to sort of handle the Berkeley window size change interupt */
Xwindow_change()
X{
Xint oldcols=COLS, oldlines=LINES;
X
X	getwindow();
X	if (oldcols != COLS || oldlines != LINES)
X	{
X		susp2_flg = TRUE;
X		if (susp1_flg) longjmp(susp_env,1);
X	}
X}
X#endif U43BSD
X
X/* MESG()
X *
X *   Send Mail to the other player.  Use the the given text and subject
X *   heading.  Making this come out right may take some fooling around on
X *   any given system.
X */
X
X#ifdef DEBUG
X# define SENDTO (debugon ? DEBUG : hisid)
X#else
X# define SENDTO hisid
X#endif DEBUG
X
X/* Choose default mailer */
X#ifndef MAILER
X#  ifdef U41BSD
X#    define MAILER "/etc/delivermail"
X#  else
X#    ifdef U42BSD
X#      define MAILER "/usr/lib/sendmail"
X#    else
X#      define MAILER "/bin/mail"
X#    endif U42BSD
X#  endif U41BSD
X#endif MAILER
X
Xmesg(subj,text)
Xchar *subj, *text;
X{
Xstatic boolean sent = FALSE;
Xchar cmd[60];
XFILE *cmdfd;
X	
X	/* No mail on solo games, and no more than one message per run */
X	if (solo || sent) return;
X	sent = TRUE;
X
X	/* Turn off interupts */
X	sigdef(SIGINT,SIG_IGN);
X	sigdef(SIGQUIT,SIG_IGN);
X
X	sprintf(cmd,"%s %s",MAILER,SENDTO);
X	cmdfd = upopen(cmd,"w");
X
X#ifdef UBERK
X	fprintf(cmdfd,"To: %s\n",SENDTO);
X#endif UBERK
X
X	fprintf(cmdfd,"Subject: %s\n\n",subj);
X	fprintf(cmdfd,"%s",text);
X
X	fclose(cmdfd);		/* Don't use pclose -- don't want to wait */
X
X	/* Replace signal handlers */
X	sigdef(SIGINT,intr);
X	sigdef(SIGQUIT,SIG_DFL);
X}
X
X
X/* INITTERM()
X *
X *   This routine Sets cbreak and no echo mode, and it reads in the termcap.
X *   It also sets the interupt routines up.
X */
X
Xinitterm()
X{
X	readterm();			/* Get terminal IQ */
X#ifdef TSTTY
X	getmode(p);			/* Get tty driver mode */
X	tpf = p.sg_flags;		/* Save old settings */
X	bs_char = p.sg_erase;		/* Get backspace character */
X#ifndef NOTERMCAP
X	ospeed = p.sg_ospeed;		/* Terminal speed for tputs */
X#endif NOTERMCAP
X#endif TSTTY
X#ifdef TTERMIO
X	ioctl(2,TCGETA,&tio);		/* Get termio driver mode */
X	tlfg = tio.c_lflag;		/* Save old settings */
X	tofg = tio.c_oflag;		/* Save old settings */
X	bs_char = tio.c_cc[2];		/* Get user's backspace character */
X	tcc4 = tio.c_cc[4];		/* Save EOF character */
X	tcc5 = tio.c_cc[5];		/* Save EOL character */
X#ifndef NOTERMCAP
X	ospeed = tio.c_cflag & CBAUD;	/* Terminal speed for tputs */
X#endif NOTERMCAP
X#endif TTERMIO
X
X	/* Trap interupts from now on */
X	sigdef(SIGINT,intr);		/* Fix cbreak/echo on interupt */
X#ifndef LSIGNAL
X	sigdef(SIGTSTP,susp);		/* Fix cbreak/echo on suspend */
X#endif LSIGNAL
X#ifdef U43BSD
X	sigdef(SIGWINCH,window_change);
X#endif U43BSD
X
X	/* set cbreak and no echo */
X	funnymodes = TRUE;
X#ifdef TSTTY
X	p.sg_flags |= CBREAK;		/* Turn on cbreak mode */
X	p.sg_flags &= ~ECHO;		/* Turn off echo mode */
X	p.sg_flags &= ~CRMOD;		/* Turn off nl to cr-nl mapping */
X	setmode(p);			/* Set new modes */
X#endif TSTTY
X#ifdef TTERMIO
X	tio.c_lflag &= ~(ICANON | ECHO); /* Turn off icanon and echo */
X	tio.c_oflag &= ~(ONLCR | OCRNL); /* Turn off output nl mapping */
X	tio.c_cc[4] = 1;		  /* Wait for only one character */
X	tio.c_cc[5] = 0;		  /* No minimum delay */
X	ioctl(0,TCSETA,&tio);		  /* Set new termio driver modes */
X#endif TTERMIO
X}
X
X
X/* UPOPEN - Run command on a pipe
X *
X *    This is just like the Unix popen() call, except it runs the command
X *    with the original user id.  This is done for the same reasons mentioned
X *    in the usystem routine.
X */
X
XFILE *upopen(cmd,mode)
Xchar *cmd;
XREGISTER char *mode;
X{
Xint pip[2];
Xregister int chd_pipe,par_pipe;
XFILE *fdopen();
X#ifdef NODUP2
Xint t;
X#endif NODUP2
X
X	/* Make a pipe */
X	if (pipe(pip)) return((FILE *)0);
X
X	/* Choose ends */
X	par_pipe = (*mode == 'r') ? pip[0] : pip[1];
X	chd_pipe = (*mode == 'r') ? pip[1] : pip[0];
X
X	switch (fork())
X	{
X	case 0:
X		/* Child - run command */
X		close(par_pipe);
X		if (chd_pipe != (*mode == 'r'?1:0))
X		{
X#ifdef NODUP2
X			close(t = (*mode == 'r'?1:0));
X			if (fcntl(chd_pipe,F_DUPFD,t) != t)
X			{
X				printf("Panic: can dup pipe\n");
X				exit(1);
X			}
X#else
X			dup2(chd_pipe,(*mode == 'r'?1:0));
X#endif NODUP2
X			close(chd_pipe);
X		}
X		setuid(getuid());
X		setgid(getgid());
X		execl("/bin/sh","sh","-c",cmd,NULL);
X		exit(1);
X	case -1:
X		close(chd_pipe);
X		close(par_pipe);
X		return((FILE *)0);
X	default:
X		close(chd_pipe);
X		return(fdopen(par_pipe,mode));
X	}
X}
X
X
X/* DAY()
X *
X * Return today's date, in the form of the number of days since Jan 1, 1970.
X * Actually, the 4.2bsd could use the time() call too, but gettimeofday()
X * seems to be prefered.
X */
X
Xlong day()
X{
X#define SECSPERDAY 86400L
X#ifdef U42BSD
Xstruct timeval tp;
Xstruct timezone tzp;
X	gettimeofday(&tp,&tzp);
X	return(tp.tv_sec/SECSPERDAY);
X#else
X	return(time((long *)0)/SECSPERDAY);
X#endif U42BSD
X}
X
X/* CDAY
X *
X * Find ascii date corrisponding to day number <dy> which was generated by
X * the day() routine.
X */
X
Xchar *cday(dy)
Xlong dy;
X{
Xregister char *db,*dp;
Xchar *ctime();
X
X	dy = dy * SECSPERDAY + SECSPERDAY/2;
X	db = ctime(&dy);
X	dp = db+10;
X	*(dp++) = ',';
X	*(dp++) = ' ';
X	*(dp++) = db[20];
X	*(dp++) = db[21];
X	*(dp++) = db[22];
X	*(dp++) = db[23];
X	*dp = '\0';
X
X	return(db);
X}
X
X#ifndef U42BSD
X/* READDIR
X *
X *	Here we fake 4.2bsd's readdir() command for older bsd's and at&t
X *	unixs.  The "direct" structure on those systems returned isn't the
X *	same the bsd one, but we do ensure that the file name is null
X *	terminated.  It would be easy enough to add the d_namlen and d_reclen
X *	records and extend d_ino to a long named d_fileno, but I don't
X *	really need that here.
X */
X
Xstruct direct *readdir(fp)
XDIR *fp;
X{
X/* We allocate one extra byte on the end of the structure for the null */
Xstatic char dent[ sizeof(struct direct) + 1 ];
X
X	do
X		if (fread(dent,sizeof(struct direct),1,fp) == 0)
X			return(NULL);
X	while (((struct direct *)dent)->d_ino == 0);
X	((struct direct *)dent)->d_name[DIRSIZ] = '\0';
X	return((struct direct *)dent);
X}
X#endif U42BSD
X
X/* GPWUID()
X *
X *   This routine looks up login names for the given uid.  It is designed
X *   to be fast for doing a number of lookups.  It does not close the
X *   password file, and it keeps a lookaside-buffer of the most recently
X *   found names.  You should call igpwuid() before calling this, and
X *   endpwent() after you are done.
X *
X *   WARNING:  The lookaside buffer is kept in the global "mbuffer".
X */
X
Xstruct pwlab {
X	char name[10];
X	int uid;
X	} *pwlab1,*pwt,*pwlab2,*pwo;
X
Xchar *gpwuid(uid)
XREGISTER int uid;
X{
Xregister struct passwd *pwd;
Xregister struct pwlab *l;
X
X	/* First search the look-aside buffer */
X	for (l = pwlab1; l < pwt; l++)
X		if (uid == l->uid) return(l->name);
X
X	/* Then search the password file */
X	while ((pwd = getpwent()) != (struct passwd *) 0 && pwd->pw_uid != uid)
X		;
X	setpwent();   /* rewind the password file */
X
X	if (pwd == (struct passwd *)0)
X		return (NULL);
X
X	/* Add the name to the look-aside buffer */
X	if (pwt < pwlab2)
X	{
X		pwt->uid = uid;
X		strcpy(pwt->name,pwd->pw_name);
X		pwt++;
X	}
X	else
X	{
X		pwo->uid = uid;
X		strcpy(pwo->name,pwd->pw_name);
X		if (pwo++ == pwlab2)
X			pwo = pwlab1;
X	}
X	return (pwd->pw_name);
X}
X
Xigpwuid()
X{
X	setpwent();   /* rewind the password file */
X	pwo = pwlab1 = pwt = (struct pwlab *) mbuffer;
X	pwlab2 = pwlab1 + sizeof(mbuffer)/sizeof(struct pwlab);
X}
X
X#ifdef U43BSD
Xgetwindow()
X{
Xstruct winsize x;
X
X	ioctl(2,TIOCGWINSZ,&x);
X	LINES = x.ws_row;
X	COLS = x.ws_col;
X}
X#endif U43BSD
END_OF_sys.c
if test 17055 -ne `wc -c <sys.c`; then
    echo shar: \"sys.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
echo shar: End of archive 4 \(of 5\).
cp /dev/null ark4isdone
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