|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T m
Length: 25282 (0x62c2) Types: TextFile Names: »main.c«
└─⟦b20c6495f⟧ Bits:30007238 EUUGD18: Wien-båndet, efterår 1987 └─⟦this⟧ »EUUGD18/General/Cchess/main.c«
/* C O R R E S P O N D E N C E C H E S S version 1.00 * * Play chess with another player, with notification of moves by mail. * * (C) Copyright - Dec 1987 - Jan Dithmar Wolter. * * This source code may be freely used, but not for purposes of profit * without the permission of the author. This copyright notice should * not be removed. * * I would be very interested in hearing about suggestions, bug reports, * and porting problems with cchess. I can be mailed on usenet at * janc@crim.eecs.umich.edu. Better yet, dial into M-Net at * (313)994-6333, give yourself an account and join the "ugames" * conference. This is a free public bbs and cchess's development site. * * Any programmer who wishes to make improvements should be warned that * this is a sadly unmodular program. There are tons of global variables * and subroutines have curious side-effects. The arrays containing the * board (b and bc) and the input buffers (mbuffer and sbuffer) are * particularly strange this way, being used for just about everything. * Sorry. That's what happens when what was originally supposed to be a * "quicky" project grows for five years. * * version 0.10: * First pre-release version. * version 0.11: * Added Unix 4.2bsd support. * Rationalized version dependent signal handlers as much as * possible with three different signal handling libraries. * Added Computer Kibitzing option to help make up for poor * graphics. * version 0.12: * Save illegal moves in kriegspeil games. * Added Big Board option on Ron Theriault's suggestion. * Solidified Forfiet/Draw code. (Finally). * Touched up transcripts. * Added help command. * version 0.13: * Added support for 22 column terminals (Commodores). * Pawn promotion noted on transcripts. * Redraw and Version work at "Not your move prompt" * Solidified Challenge/Accept code. (Finally). * version 0.14: * Cosmetic changes to Exit command. * Fix system() calls to protect them from dirty tricks. * Let Kriegspielers replay the game after it is over. * Improve castling code so it will work for halfboard games. * Kriegspiel only counts some kinds of illegal moves. * Time stamp added to each line of game file. * Version and Redraw commands work at accept draw prompt. * Replay renamed Playback, and dodraw() integrated with domove(). * White pieces displayed with highlighting on the big board. * Divided sys.c file into sys.c and scrn.c. * Fixed a bug that caused moves to get lost during playbacks. * version 0.15: * Fixed a pawn promotion bug that appeared in 0.14. * Added Shatranj and Courier game variations. * Added Karma, Rifle & Kamikazi Chess capture variations. * Version 6 style ioctl() calls now understood by sys.c * version 0.16 * Repeated position detection code kludged in. * Fifty move rule enforcement installed. * Game cancellation command added. * Minor bug fixes to Karma chess, Kriegspiel and Scoreboard. * version 0.17 * Big changes in the way options are represented internally * and in game files and in score file. * Addition of Maharajah piece. * Multiple moves for variant games. * Steamroller, Double Chess and Progressive variants added. * Initial board set-up specified in transcript file. * O command to display current game options added. * mprint() for "--More--" on Help and Options. * Board editor for custom chess boards. * Further generalization of castling code. * No spaces allowed in transcript file names. * Bug fixes to mate detection. * Redraw works at "Are you sure" and "Move:" prompts. * Use user defined backspace character from stty calls. * Mailer is run in background. * Clarification of format of comments under board. * version 0.18 * May name a user with -g option. * Speedup of -g option with lookaside buffer for passwd lookups. * Auto-redraw after suspend (sort of) made to work. * Addition of French and German piece names. * Various small bug fixes for system V. * Added -a option to move in all possible games. * Fixed printing of cancellation requests in transcripts. * Illegal moves optionally printed in kriegspiel transcripts. * Enter kibitz mode only if you are neither of the players. * Changes to allow no king, or some other mateable piece. * Fixes to the computer kibitzer (rooks don't cover themselves). * Bug Fixes to playback of multimove games. * Broke cmd.c file into cmd.c and init.c. * Added Last command to display date of last move. * Redesign of challenge and accept subsystems. * Maharajah and Losing chess variant games added. * Many fixes to mate detection. * Tab'iyat option for sped up openings. * version 0.19 * Turned off nl to crnl mapping and fixed stuff to work that way. * Rewrote directory reading to use clone of 4.2bsd readdir(). * Fix things so display isn't confused by R lines in gamefile. * Close files when -a option is used. * Fix queen moves in mate detection. * Simplification of compile time definitions. * Rewrite to simplify cctrans() routine. * Innumerable minor fixes and clean up work all over. * Conversion Chess added with thanks to Kenneth Larimer. * Version numbers added to game files. * Crude support of 4.3bsd windowing interupt. * version 1.00 * Cleaned up for posting to USENET. */ #include "cchess.h" /* String identifying current version */ char *version = "0.19"; char *copyright = "(c) 1987 Jan Wolter"; /* Characters and Names for pieces (some foreign name sets are incomplete) */ char pc[] = "HJDEMIRNBQK kqbnrimedjh"; char *chessname[HI_NAMES+1][PIECES+1] = { { "Empty Square", "King", "Queen", "Bishop", "Knight", "Rook", "Pawn", "Minister", "Elephant", "Duke", "Jester", "Maharajah"}, { "Empty Square", "Shah", "Queen", "Bishop", "Faras", "Rukh", "Baidaq", "Firz", "Fil", "Duke", "Jester", "Maharajah"}, { "Empty Square", "Roi", "Dame", "Fou", "Cavaler", "Tour", "Pion", "Ministre", "Elephant", "Duc", "Jester", "Maharajah"}, { "Empty Square", "Konig", "Dame", "Laufer", "Springer", "Turm", "Bauer", "Minister", "Elefant", "Herzog", "Jester", "Maharajah"} }; char **piecename; short wfr,wfc,wtr,wtc; /* last white move - used for en paussant legality */ short bfr,bfc,btr,btc; /* last black move - used for en paussant legality */ schar promote = 0; /* Character to promote pawn to - 0 if no promotion */ /* Have the Kings or the Rooks been moved? */ boolean wcck = TRUE; /* White can castle king-side */ boolean wccq = TRUE; /* White can castle queen-side */ boolean bcck = TRUE; /* Black can castle king-side */ boolean bccq = TRUE; /* Black can castle queen-side */ /* Initial board layout */ /* Last four columns */ schar ib[R_SIZE][C_SIZE] = { /* for Courier only. */ WR, WN, WB, WQ, WK, WB, WN, WR, WB, WE, WN, WR, WP, WP, WP, WP, WP, WP, WP, WP, WP, WP, WP, WP, SQ, SQ, SQ, SQ, SQ, SQ, SQ, SQ, SQ, SQ, SQ, SQ, SQ, SQ, SQ, SQ, SQ, SQ, SQ, SQ, SQ, SQ, SQ, SQ, SQ, SQ, SQ, SQ, SQ, SQ, SQ, SQ, SQ, SQ, SQ, SQ, SQ, SQ, SQ, SQ, SQ, SQ, SQ, SQ, SQ, SQ, SQ, SQ, BP, BP, BP, BP, BP, BP, BP, BP, BP, BP, BP, BP, BR, BN, BB, BQ, BK, BB, BN, BR, BB, BE, BN, BR, }; schar bc[R_SIZE][C_SIZE]; /* Copy of the board, so moves can be taken back */ schar b[R_SIZE][C_SIZE]; /* Main board */ int errcode; /* Move error code */ int hisuid; /* Opponent user id number */ int myuid; /* Player user id number */ char hisid[20]; /* Opponent login name */ char myid[20]; /* Player login name */ #ifdef COMPAT018 char file_version[6] = "0.18"; /* Version of cchess that produced game file */ /* If no version line, assume 0.18 */ #else char file_version[6] = ""; /* Version of cchess that produced game file */ #endif COMPAT018 int movecnt; /* Number of moves made so far in game */ int playcnt; /* Number of moves including proposals */ int mvssize; /* Number of moves on the move stack */ int tamemoves; /* Number of tame moves made */ int consmoves; /* Number of consecutive moves allowed */ int consmade; /* Number of consecutive moves made */ char fname[50]; /* Name of the gameboardfile */ FILE *rfp; /* File pointer for reading from boardfile */ FILE *wfp; /* File pointer for writing to boardfile */ /* Game status code: * 0 -> No challenge made. * 1 -> Challenge has been sent. * 2 -> (not used) * 3 -> Ready to move. * 4 -> A draw has been proposed. * 5 -> A draw has been accepted. * 6 -> Player has forfeited. * 7 -> cancellation has been proposed. * 8 -> cancellation has been accepted. */ char status; /* General Purpose Global Flags */ boolean newgame; /* Are we starting a new game file? */ boolean moveok = TRUE; /* Allow player to move? */ boolean solo; /* Is he playing himself? */ boolean kibitz = FALSE; /* Is this a kibitzing session? */ boolean bigboard = FALSE; /* Display board in large format? */ boolean hidden = FALSE; /* Should enemy moves be shown? */ boolean incheck = FALSE; /* Is player in check (or mate)? */ boolean inmate = FALSE; /* Is plater (check or stale) mated */ boolean repeated = FALSE; /* Is this a thrice repeated position? */ boolean stripped = FALSE; /* Have we just stripped the other player? */ boolean istame; /* Was the last move a tame one? */ boolean interupt; /* OK to interupt out of program? */ boolean eachgame = FALSE; /* Play each playable game? */ boolean must_take = FALSE; /* Allow only moves which capture? */ schar toplay=WHITE; /* color to play next */ schar order; /* -1 if other player named first, else 1 */ schar mycolor; /* What color am I? */ schar taken; /* Piece taken in last move. SQ for none. */ long lastday; /* Day number on which last move was made. */ boolean erases=TRUE; /* Can terminal erase properly? */ boolean issmart=FALSE; /* Can address cursor and erase? */ boolean cleardown=FALSE; /* Can clear screen below cursor and smart? */ boolean commodore=FALSE; /* Do we have a 22 column terminal? */ boolean scrolled=FALSE; /* Has the screen scrolled? */ int illmoves; /* Count of illegal Kriegspiel moves */ int myillmoves; /* Count of my illegal Kriegspiel moves */ short cx,cy; /* Current Cursor position (used by TERMCAP) */ short msgarea = 0; /* Line below screen where prompts begin */ int LINES = 0; /* Number of lines per screen */ int COLS = 40; /* Number of columns per screen */ char bs_char = '\b'; /* User definable backspace character */ #ifdef DEBUG boolean debugon = FALSE; /* Debugging flag */ #endif DEBUG /* Names of standard variant games */ char *typename[HI_GAME+1] = { "Mixed", "Chess", "Kriegspiel", "Shatranj", "Courier", "Halfboard Chess", "Karma Chess", "Rifle Chess", "Kamikazi Chess", "Double Chess", "Steamroller", "Progressive Chess", "Maharajah", "Losing Chess", "Conversion Chess"}; char *langname[HI_NAMES+1] = { "English","Persian","French","German"}; /* Names of game results */ char *resltname[4] = {"Draw","Win","Lose","Continue"}; /* Names of Capture rules */ char *captname[HI_CAPTURE+1] = {"Standard","No","Rifle","Conversion","Karma","Kamikazi"}; /* Current game options */ char option[OPTIONS]; /* Maximum legal values for the options */ char maxopt[OPTIONS] = { HI_COLOR, HI_PRIVATE, HI_KIBITZ, HI_GAME, HI_ROWS, HI_COLS, HI_BOARD, HI_NAMES, HI_VISIB, HI_CASTLE, HI_DPAWN, HI_STRIP, HI_STALE, HI_CAPTURE, HI_KCAPTURE, HI_PROMOTE, HI_WIMOVES, HI_BIMOVES, HI_WMOVES, HI_BMOVES, HI_THRUCHECK, HI_WHITEKING, HI_BLACKKING, HI_MUSTTAKE, HI_TABIYAT }; /* Variant game default options */ char defopt[HI_GAME+1][OPTIONS] = { /* Customized game */ { FALSE, FALSE, TRUE, TY_MIXED, 7, 7, FALSE, 0, FALSE, FALSE, FALSE, RE_NONE, RE_DRAW, CA_NORMAL, CA_NORMAL, PR_QRBN, 1, 1, 1, 1, FALSE, WK, WK, FALSE, FALSE }, /* Standard Chess */ { FALSE, FALSE, TRUE, TY_CHESS, 7, 7, FALSE, 0, FALSE, FALSE, FALSE, RE_NONE, RE_DRAW, CA_NORMAL, CA_NORMAL, PR_QRBN, 1, 1, 1, 1, FALSE, WK, WK, FALSE, FALSE }, /* Kriegspiel */ { FALSE, FALSE, TRUE, TY_KRIEGSPIEL, 7, 7, FALSE, 0, TRUE, FALSE, FALSE, RE_NONE, RE_DRAW, CA_NORMAL, CA_NORMAL, PR_QRBN, 1, 1, 1, 1, FALSE, WK, WK, FALSE, FALSE }, /* Shatranj */ { FALSE, FALSE, TRUE, TY_SHATRANJ, 7, 7, TRUE, 1, FALSE, TRUE, TRUE, RE_LOSE, RE_WIN, CA_NORMAL, CA_NORMAL, PR_MINISTER, 10, 10, 1, 1, FALSE, WK, WK, FALSE, TRUE }, /* Courier */ { FALSE, FALSE, TRUE, TY_COURIER, 7, 11, TRUE, 0, FALSE, TRUE, TRUE, RE_LOSE, RE_WIN, CA_NORMAL, CA_NORMAL, PR_MINISTER, 12, 12, 1, 1, FALSE, WK, WK, FALSE, TRUE }, /* Halfboard */ { FALSE, FALSE, TRUE, TY_HALFBOARD, 7, 3, FALSE, 0, FALSE, FALSE, FALSE, RE_NONE, RE_DRAW, CA_NORMAL, CA_NORMAL, PR_QRBN, 1, 1, 1, 1, FALSE, WK, WK, FALSE, FALSE }, /* Karma Chess */ { FALSE, FALSE, TRUE, TY_KARMA, 7, 7, FALSE, 0, FALSE, FALSE, FALSE, RE_NONE, RE_DRAW, CA_KARMA, CA_NORMAL, PR_QRBN, 1, 1, 1, 1, FALSE, WK, WK, FALSE, FALSE }, /* Rifle Chess */ { FALSE, FALSE, TRUE, TY_RIFLE, 7, 7, FALSE, 0, FALSE, FALSE, FALSE, RE_NONE, RE_DRAW, CA_RIFLE, CA_RIFLE, PR_QRBN, 1, 1, 1, 1, FALSE, WK, WK, FALSE, FALSE }, /* Kamikazi Chess */ { FALSE, FALSE, TRUE, TY_KAMIKAZI, 7, 7, FALSE, 0, FALSE, FALSE, FALSE, RE_NONE, RE_DRAW, CA_KAMIKAZI, CA_NONE, PR_QRBN, 1, 1, 1, 1, FALSE, WK, WK, FALSE, FALSE }, /* Double Move Chess */ { FALSE, FALSE, TRUE, TY_DOUBLE, 7, 7, FALSE, 0, FALSE, FALSE, FALSE, RE_NONE, RE_DRAW, CA_NORMAL, CA_NORMAL, PR_QRBN, 2, 2, 2, 2, TRUE, WK, WK, FALSE, FALSE }, /* Steamroller */ { FALSE, FALSE, TRUE, TY_STEAMROLLER, 7, 7, FALSE, 0, FALSE, FALSE, FALSE, RE_NONE, RE_DRAW, CA_NORMAL, CA_NORMAL, PR_QRBN, 2, 1, 2, 1, TRUE, WK, WK, FALSE, FALSE }, /* Progressive Chess */ { FALSE, FALSE, TRUE, TY_PROGRESSIVE, 7, 7, FALSE, 0, FALSE, FALSE, FALSE, RE_LOSE, RE_DRAW, CA_NORMAL, CA_NORMAL, PR_QRBN, 1, MO_PROGRESS, MO_PROGRESS, MO_PROGRESS, FALSE, SQ, SQ, FALSE, FALSE }, /* Maharajah */ { FALSE, FALSE, TRUE, TY_MAHARAJAH, 7, 7, FALSE, 0, FALSE, FALSE, FALSE, RE_NONE, RE_DRAW, CA_NORMAL, CA_NORMAL, PR_QRBN, 1, 1, 1, 1, FALSE, WH, WK, FALSE, FALSE }, /* Losing Chess */ { FALSE, FALSE, FALSE, TY_LOSING, 7, 7, FALSE, 0, FALSE, FALSE, FALSE, RE_WIN, RE_WIN, CA_NORMAL, CA_NORMAL, PR_QRBN, 1, 1, 1, 1, FALSE, SQ, SQ, FALSE, FALSE }, /* Conversion Chess */ { FALSE, FALSE, TRUE, TY_CONVERSION, 7, 7, FALSE, 0, FALSE, FALSE, FALSE, RE_NONE, RE_DRAW, CA_CONVERSION,CA_CONVERSION,PR_QRBN, 1, 1, 1, 1, FALSE, WK, WK, FALSE, FALSE } }; char cbuffer[CB_LEN+1]; /* Comment Buffer */ char mb1[MB_LEN+1]; /* Move Buffer One. */ char mb2[MB_LEN+1]; /* Move Buffer Two. */ char *mbuffer=mb1; /* Pointer to current move buffer */ char *sbuffer=mb2; /* Pointer to spare move buffer */ jmp_buf jmpenv; /* Long jump buffer */ /* Some really weird things used to sort of recover from suspends: */ /* susp1_flg is set if susp_env contains a place to jump to after */ /* we've been suspended. susp2_flg is turned on if we got suspended */ /* while there was no susp_env defined */ #ifndef LSIGNAL jmp_buf susp_env; boolean susp1_flg = FALSE, susp2_flg = FALSE; #endif LSIGNAL /* String of spaces used when arbitary strings of spaces are needed */ char blankstr[BLANK_LEN+1] /* Must be exactly BLANK_LEN spaces */ = " "; char transcript = FALSE; /* Should we just print the transcript? */ int realuid; boolean activeonly = FALSE; main(argc,argv) int argc; char *argv[]; { struct passwd *pwd; /* Password file entry */ register int players,i,j; /* check legality of arguments */ players = 0; for (i=1;i<argc;i++) if (argv[i][0] == '-') for (j = 1; argv[i][j]; j++) switch (argv[i][j]) { case 'a': eachgame = TRUE; break; case 's': scoreboard(); exit(0); case 'b': bigboard = TRUE; break; case 'g': if (++i < argc) { if ((pwd = getpwnam(argv[i])) == 0) { printf("No user %s on this system\n",argv[i]); exit(1); } printf("%s's games in progress\n-----------------------------\n", argv[i]); list(pwd->pw_uid); } else { printf("Games in progress\n-----------------\n"); list(-1); } exit(0); case 't': transcript = TRUE; break; #ifdef DEBUG case 'd': debugon = TRUE; break; #endif DEBUG default: printf("Illegal %s option: -%c\n",argv[0],argv[i][j]); usage(argv[0]); } else if (++players == 1) strcpy(hisid,argv[i]); else if (players == 2) strcpy(myid,argv[i]); else { printf("Too many options for %s\n",argv[0]); usage(argv[0]); } /* Look up the two players */ realuid = getuid(); if (players >= 1) { /* does opponent exist? */ if ((pwd = getpwnam(hisid)) == 0) { printf("No user %s on this system\n",hisid); exit(1); } hisuid = pwd->pw_uid; } if (players == 2) { /* does second name exist? */ if ((pwd = getpwnam(myid)) == 0) { printf("No user %s on this system\n",myid); exit(1); } myuid = pwd->pw_uid; /* If one of the named players is me, ignore it */ #ifdef DEBUG if (!eachgame && !debugon) #else if (!eachgame) #endif DEBUG { if (myuid == realuid) players = 1; else if (hisuid == realuid) { players = 1; /* Swap names */ strcpy(myid,hisid); strcpy(hisid,pwd->pw_name); hisuid = myuid; myuid = realuid; } } } else if (players == 1) { /* Get my name */ if ((pwd = getpwuid(realuid)) == 0) { printf("Panic: Can't get your password entry\n"); exit(1); } strcpy(myid,pwd->pw_name); myuid = realuid; } /* If -a flag and less than two names, do all matching games */ if (eachgame) { if (players < 2) { activeonly = (players == 0); scangames(); /* Doesn't return */ } else eachgame = FALSE; } /* If no -a flag, must have at least one player name */ if (players == 0) { printf("Must specify name of opponent.\n"); usage(argv[0]); } /* Are we kibitzing? */ if (players == 2) kibitz = TRUE; #ifdef DEBUG if (debugon) { if (players == 2) kibitz = FALSE; else { printf("Debug option requires two names.\n"); exit(1); } } #endif DEBUG /* Get termcap, set cbreak, noecho, trap interupts */ initterm(); run(); exit(-1); } /* myid, myuid, hisid and hisuid must be set before calling this */ /* this never returns. It always calls done() instead. */ run() { /* Initialize various globals */ wcck = wccq = bcck = bccq = TRUE; interupt = TRUE; errcode = E_OK; status = 0; taken = SQ; /* As he playing himself? */ solo = (hisuid == myuid); /* See if the Move File Exists */ order = -1; sprintf(fname,"%s/%d.%d",CCDIR,hisuid,myuid); if ((rfp=fopen(fname,"r"))==NULL) { order = 1; sprintf(fname,"%s/%d.%d",CCDIR,myuid,hisuid); if ((rfp=fopen(fname,"r"))==NULL) { clr(); wprintf("No game in progress between %s and %s\n", myid,hisid); if (eachgame || kibitz || transcript) done(0); wprintf("Would you like to challenge %s (Y/N)? ", hisid); if (enterdyn(TRUE)) { newgame = TRUE; status = 0; dochallenge(FALSE); } done(0); } } /* Open the Game file to write */ if ((wfp=fopen(fname,"a"))==NULL) { wprintf("Cchess error: Unable to write to gamefile %s\n", fname); done(1); } /* Just print a transcript, if that option was selected */ if (transcript) { if (eachgame) { if (activeonly) wprintf("Transcript of game against %s? ",hisid); else wprintf("Transcript of game between %s and %s? ", myid,hisid); if (!enterdyn(FALSE)) done(0); } trans(TRUE); done(0); } newgame = FALSE; /* read in the game to date */ ldboard(); if (solo) mycolor = toplay; if (mycolor != toplay) moveok = FALSE; else moveok = !kibitz; if (eachgame) { if (activeonly) { if (mycolor == toplay) { wprintf("Move against %s? ",hisid); if (!enterdyn(FALSE)) done(0); } else done(0); } else { wprintf("Game between %s and %s? ",myid,hisid); if (!enterdyn(FALSE)) done(0); } } switch (status) { case 0: /* no challenge made */ wprintf("Cchess Error: No Challenge after load.\n"); done(1); case 1: /* challenge made */ doaccept(); /* if white accepted, let him move */ if (status != 3 || (mycolor != WHITE && !solo)) break; toplay = WHITE; if (Winitmoves == MO_PROGRESS) consmoves = 1; else consmoves = Winitmoves; case 3: /* make move */ if (stripped) domate(Stripresult,EV_FORCES); else if (inmate) { if (incheck) domate(RE_LOSE,EV_CHECKMATE); else domate(Staleresult,EV_STALEMATE); } else if (repeated) domate(RE_DRAW,EV_REPEATED); else domove(RE_NONE); /* Make a move */ break; case 4: /* draw proposal made */ if (tamemoves >= MAXTAME) domate(RE_DRAW,EV_FIFTYMOVES); /* Draw is final */ else domove(RE_DRAW); /* Answer a draw proposal */ break; case 5: /* other player accepted draw */ domate(RE_DRAW,EV_AGREEMENT); break; case 6: /* other player forfeited */ domate(RE_WIN,EV_FORFIET); break; case 7: /* cancellation proposal made */ domove(RE_CANCEL); /* Answer a cancellation proposal */ break; case 8: /* other player accepted cancellation */ domate(RE_CANCEL,EV_AGREEMENT); break; default: wprintf("Cchess Error: Weird status %d\n",status); done(1); } done(0); } /* SCANGAMES() * * If activeonly is set, list all games the user can move in. If activeonly * is not set, list all games that hisuid is in. For each one, prompt if * he wants to move in it. Run the program if he does. Visual mode * not used here. */ scangames() { register struct direct *gfd; register char *pwname; register int n; int uid1,uid2; DIR *fp; if ((fp = opendir(CCDIR))== 0) { printf("Panic: unable to read %s directory\n",CCDIR); exit(1); } n = 0; igpwuid(); /* Get name and uid to search for */ if (activeonly) { if ((pwname = gpwuid(myuid = realuid)) == 0) { printf("Panic: Can't get your password entry\n"); exit(1); } strcpy(myid,pwname); } else { strcpy(myid,hisid); myuid = hisuid; kibitz = TRUE; } while ((gfd = readdir(fp)) != NULL) if (gfd->d_name[0] != '.' && sscanf(gfd->d_name,"%d.%d",&uid1,&uid2)==2) { /* Does this game involve me? */ if (uid1 == myuid) hisuid = uid2; else if (uid2 == myuid) hisuid = uid1; else continue; /* Look up the other person's id */ if ((pwname=gpwuid(hisuid)) == 0) continue; strcpy(hisid,pwname); if (n == 0) { initterm(); clr(); } /* Play the game */ if (!setjmp(jmpenv)) run(); n++; } endpwent(); /* close the password file */ if (n == 0) printf("No games\n"); /* Turn off eachgame flag so done() will really exit us */ eachgame = FALSE; closedir(fp); done(0); } /* USAGE * * Print a rather long winded usage message. This doesn't return. */ usage(name) char *name; { printf("To play: %s [-a] [-b] opponent\n",name); printf("To peek: %s [-b] player player\n",name); printf("For transcript: %s [-a] -t player [player]\n",name); printf("For scoreboard: %s -s\n",name); printf("For game list: %s -g [player]\n",name); exit(1); }