From: Daniel Mehrmann Date: Tue, 13 Jan 2004 19:57:48 +0000 (+0000) Subject: mehrmann wb extensions X-Git-Tag: v4.2.8~59 X-Git-Url: http://hgm.nubati.net/cgi-bin/gitweb.cgi?p=xboard.git;a=commitdiff_plain;h=8de20911a5b2cc7c7c92a0f6fdd158e169b1fad8 mehrmann wb extensions --- diff --git a/winboard-dm-beta4/Makefile b/winboard-dm-beta4/Makefile new file mode 100755 index 00000000..1c1816d3 --- /dev/null +++ b/winboard-dm-beta4/Makefile @@ -0,0 +1,118 @@ +OS=NT +ENV=WIN32 +CPU=i386 + +!include <$(OS)$(ENV).MAK> + +proj = winboard +allobj = winboard.obj backend.obj parser.obj moves.obj lists.obj \ + gamelist.obj pgntags.obj wedittags.obj wgamelist.obj zippy.obj \ + wsockerr.obj wclipbrd.obj woptions.obj + +#### old stuff - disable by Daniel Mehrmann +#cvars = $(cvars) -I. -DWINVER=0x0400 +#cflags = $(cflags) /FR + +# delete .mak file We don't need that ! + +################ Mehrmann stuff ########################### + +### EDIT HERE for compile optimze or debug ;-) + +# new stuff by Daniel Mehrmann + +# need this for a nomal run +# DO NOT CHANGE !! +cflags = -c -W3 -DCRTAPI1=_cdecl -DCRTAPI2=_cdecl -nologo -D_X86_=1 -D_WINNT -D_WIN32_WINNT=0x0400 -D_WIN32_IE=0x0300 -DWINVER=0x0400 /FRwinboard.bsc -DWIN32 + +# optimize here ! +# standard fast und pentium +cflags = $(cflags) -O2 -G5 + + +#!!! disable debug !!! +# comment this out if you want debug ! +cdebug = +linkdebug = + + +############### Mehrmann stuff end ########################## + +all: $(proj).exe + +# Update the help file if necessary +$(proj).hlp : $(proj).rtf + $(hc) $(proj).hpj + cat $(proj).err + +# Update the resource if necessary +$(proj).rbj: $(proj).rc $(proj).h $(proj).res resource.h + $(rc) $(rcvars) -r -fo $(proj).res $(cvars) $(proj).rc + cvtres -$(CPU) $(proj).res -o $(proj).rbj + +# Update the object files if necessary +winboard.obj: winboard.c config.h winboard.h common.h frontend.h backend.h \ + moves.h wgamelist.h defaults.h resource.h wclipbrd.h wedittags.h \ + wsockerr.h lists.h + $(cc) $(cflags) $(cvars) $(cdebug) winboard.c + +backend.obj: backend.c config.h common.h frontend.h backend.h parser.h \ + moves.h zippy.h backendz.h lists.h + $(cc) $(cflags) $(cvars) $(cdebug) backend.c + +parser.obj: parser.c config.h common.h backend.h parser.h frontend.h moves.h \ + lists.h + $(cc) $(cflags) $(cvars) $(cdebug) parser.c + +parser.c: parser.l + flex -L parser.l + del parser.c + rename lex.yy.c parser.c + +moves.obj: moves.c config.h backend.h common.h parser.h moves.h lists.h \ + frontend.h + $(cc) $(cflags) $(cvars) $(cdebug) moves.c + +lists.obj: lists.c config.h lists.h common.h + $(cc) $(cflags) $(cvars) $(cdebug) lists.c + +gamelist.obj: gamelist.c config.h lists.h common.h frontend.h backend.h \ + parser.h lists.h + $(cc) $(cflags) $(cvars) $(cdebug) gamelist.c + +pgntags.obj: pgntags.c config.h common.h frontend.h backend.h parser.h lists.h + $(cc) $(cflags) $(cvars) $(cdebug) pgntags.c + +wclipbrd.obj: wclipbrd.c config.h common.h frontend.h backend.h winboard.h \ + wclipbrd.h lists.h resource.h + $(cc) $(cflags) $(cvars) $(cdebug) wclipbrd.c + +wedittags.obj: wedittags.c config.h common.h winboard.h frontend.h backend.h \ + lists.h resource.h + $(cc) $(cflags) $(cvars) $(cdebug) wedittags.c + +wgamelist.obj: wgamelist.c config.h. common.h winboard.h frontend.h backend.h \ + wgamelist.h lists.h resource.h + $(cc) $(cflags) $(cvars) $(cdebug) wgamelist.c + +woptions.obj: woptions.c config.h common.h frontend.h backend.h lists.h + $(cc) $(cflags) $(cvars) $(cdebug) woptions.c + +wsockerr.obj: wsockerr.c wsockerr.h + $(cc) $(cflags) $(cvars) $(cdebug) wsockerr.c + +zippy.obj: zippy.c config.h common.h zippy.h frontend.h backend.h backendz.h \ + lists.h + $(cc) $(cflags) $(cvars) $(cdebug) zippy.c + +$(proj).exe: $(allobj) $(proj).rbj $(proj).def $(proj).hlp $(proj).rc + $(link) $(linkdebug) $(guiflags) $(allobj) \ + wsock32.lib shell32.lib comctl32.lib winmm.lib libc.lib oldnames.lib kernel32.lib \ + advapi32.lib user32.lib gdi32.lib comdlg32.lib winspool.lib \ + $(proj).rbj -out:$(proj).exe + bscmake *.sbr + +test.exe: test.c + $(cc) $(cflags) $(cvars) $(cdebug) test.c + $(link) $(linkdebug) $(conflags) test.obj $(conlibs) -out:test.exe + diff --git a/winboard-dm-beta4/backend.c b/winboard-dm-beta4/backend.c new file mode 100755 index 00000000..a08ba329 --- /dev/null +++ b/winboard-dm-beta4/backend.c @@ -0,0 +1,11298 @@ +/* + * backend.c -- Common back end for X and Windows NT versions of + * XBoard $Id$ + * + * Copyright 1991 by Digital Equipment Corporation, Maynard, Massachusetts. + * Enhancements Copyright 1992-2001 Free Software Foundation, Inc. + * + * The following terms apply to Digital Equipment Corporation's copyright + * interest in XBoard: + * ------------------------------------------------------------------------ + * All Rights Reserved + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appear in all copies and that + * both that copyright notice and this permission notice appear in + * supporting documentation, and that the name of Digital not be + * used in advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. + * + * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING + * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL + * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR + * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, + * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + * ------------------------------------------------------------------------ + * + * The following terms apply to the enhanced version of XBoard distributed + * by the Free Software Foundation: + * ------------------------------------------------------------------------ + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * ------------------------------------------------------------------------ + * + * See the file ChangeLog for a revision history. */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include +/* daniel */ +#include + +#if STDC_HEADERS +# include +# include +#else /* not STDC_HEADERS */ +# if HAVE_STRING_H +# include +# else /* not HAVE_STRING_H */ +# include +# endif /* not HAVE_STRING_H */ +#endif /* not STDC_HEADERS */ + +#if HAVE_SYS_FCNTL_H +# include +#else /* not HAVE_SYS_FCNTL_H */ +# if HAVE_FCNTL_H +# include +# endif /* HAVE_FCNTL_H */ +#endif /* not HAVE_SYS_FCNTL_H */ + +#if TIME_WITH_SYS_TIME +# include +# include +#else +# if HAVE_SYS_TIME_H +# include +# else +# include +# endif +#endif + +#if defined(_amigados) && !defined(__GNUC__) +struct timezone { + int tz_minuteswest; + int tz_dsttime; +}; +extern int gettimeofday(struct timeval *, struct timezone *); +#endif + +#if HAVE_UNISTD_H +# include +#endif + +#include "common.h" +#include "frontend.h" +#include "backend.h" +#include "parser.h" +#include "moves.h" +#if ZIPPY +# include "zippy.h" +#endif +#include "backendz.h" +#include "winboard.h" + +/* A point in time */ +typedef struct { + long sec; /* Assuming this is >= 32 bits */ + int ms; /* Assuming this is >= 16 bits */ +} TimeMark; + +int establish P((void)); +void read_from_player P((InputSourceRef isr, VOIDSTAR closure, + char *buf, int count, int error)); +void read_from_ics P((InputSourceRef isr, VOIDSTAR closure, + char *buf, int count, int error)); +void SendToICS P((char *s)); +void SendToICSDelayed P((char *s, long msdelay)); +void SendMoveToICS P((ChessMove moveType, int fromX, int fromY, + int toX, int toY)); +void InitPosition P((int redraw)); +void HandleMachineMove P((char *message, ChessProgramState *cps)); +int AutoPlayOneMove P((void)); +int LoadGameOneMove P((ChessMove readAhead)); +int LoadGameFromFile P((char *filename, int n, char *title, int useList)); +int LoadPositionFromFile P((char *filename, int n, char *title)); +int SavePositionToFile P((char *filename)); +void ApplyMove P((int fromX, int fromY, int toX, int toY, int promoChar, + Board board)); +void MakeMove P((int fromX, int fromY, int toX, int toY, int promoChar)); +void ShowMove P((int fromX, int fromY, int toX, int toY)); +void FinishMove P((ChessMove moveType, int fromX, int fromY, int toX, int toY, + /*char*/int promoChar)); +void BackwardInner P((int target)); +void ForwardInner P((int target)); +void GameEnds P((ChessMove result, char *resultDetails, int whosays)); +void EditPositionDone P((void)); +void PrintOpponents P((FILE *fp)); +void PrintPosition P((FILE *fp, int move)); +void StartChessProgram P((ChessProgramState *cps)); +void GuiCommand P((int command, int param)); +void IcsAnalyzeOutPut P((ChessProgramState *cps, int endThink)); +int SwitchGames P((void)); +void SendToProgram P((char *message, ChessProgramState *cps)); +void SendMoveToProgram P((int moveNum, ChessProgramState *cps)); +void ReceiveFromProgram P((InputSourceRef isr, VOIDSTAR closure, + char *buf, int count, int error)); +void SendTimeControl P((ChessProgramState *cps, + int mps, long tc, int inc, int sd, int st)); +char *TimeControlTagValue P((void)); +void Attention P((ChessProgramState *cps)); +void FeedMovesToProgram P((ChessProgramState *cps, int upto)); +void ResurrectChessProgram P((void)); +void DisplayComment P((int moveNumber, char *text)); +void DisplayMove P((int moveNumber)); +void GetTimeMark P((TimeMark *)); +void ParseGameHistory P((char *game)); +void ParseBoard12 P((char *string)); +void StartClocks P((void)); +void SwitchClocks P((void)); +void StopClocks P((void)); +void ResetClocks P((void)); +char *PGNDate P((void)); +void SetGameInfo P((void)); +Boolean ParseFEN P((Board board, int *blackPlaysFirst, char *fen)); +int RegisterMove P((void)); +void MakeRegisteredMove P((void)); +void TruncateGame P((void)); +int looking_at P((char *, int *, char *)); +void CopyPlayerNameIntoFileName P((char **, char *)); +char *SavePart P((char *)); +int SaveGameOldStyle P((FILE *)); +int SaveGamePGN P((FILE *)); + +long SubtractTimeMarks P((TimeMark *, TimeMark *)); +int CheckFlags P((void)); +long NextTickLength P((long)); +void CheckTimeControl P((void)); +void show_bytes P((FILE *, char *, int)); +int string_to_rating P((char *str)); +void ParseFeatures P((char* args, ChessProgramState *cps)); +void InitBackEnd3 P((void)); +void FeatureDone P((ChessProgramState* cps, int val)); +void InitChessProgram P((ChessProgramState *cps)); +extern int tinyLayout, smallLayout; + +void ParseZippyP3 P((char* data, char* player)); + +/* States for ics_getting_history */ +#define H_FALSE 0 +#define H_REQUESTED 1 +#define H_GOT_REQ_HEADER 2 +#define H_GOT_UNREQ_HEADER 3 +#define H_GETTING_MOVES 4 +#define H_GOT_UNWANTED_HEADER 5 + +/* whosays values for GameEnds */ +#define GE_ICS 0 +#define GE_ENGINE 1 +#define GE_PLAYER 2 +#define GE_FILE 3 +#define GE_XBOARD 4 + +/* Maximum number of games in a cmail message */ +#define CMAIL_MAX_GAMES 20 + +/* Different types of move when calling RegisterMove */ +#define CMAIL_MOVE 0 +#define CMAIL_RESIGN 1 +#define CMAIL_DRAW 2 +#define CMAIL_ACCEPT 3 + +/* Different types of result to remember for each game */ +#define CMAIL_NOT_RESULT 0 +#define CMAIL_OLD_RESULT 1 +#define CMAIL_NEW_RESULT 2 + +/* Telnet protocol constants */ +#define TN_WILL 0373 +#define TN_WONT 0374 +#define TN_DO 0375 +#define TN_DONT 0376 +#define TN_IAC 0377 +#define TN_ECHO 0001 +#define TN_SGA 0003 +#define TN_PORT 23 + +/* Fake up flags for now, as we aren't keeping track of castling + availability yet */ +int +PosFlags(index) +{ + int flags = F_ALL_CASTLE_OK; + if ((index % 2) == 0) flags |= F_WHITE_ON_MOVE; + switch (gameInfo.variant) { + case VariantSuicide: + case VariantGiveaway: + flags |= F_IGNORE_CHECK; + flags &= ~F_ALL_CASTLE_OK; + break; + case VariantAtomic: + flags |= F_IGNORE_CHECK | F_ATOMIC_CAPTURE; + break; + case VariantKriegspiel: + flags |= F_KRIEGSPIEL_CAPTURE; + break; + case VariantNoCastle: + flags &= ~F_ALL_CASTLE_OK; + break; + default: + break; + } + return flags; +} + +FILE *gameFileFP, *debugFP; + +char cmailMove[CMAIL_MAX_GAMES][MOVE_LEN], cmailMsg[MSG_SIZ]; +char bookOutput[MSG_SIZ*10], thinkOutput[MSG_SIZ*10], lastHint[MSG_SIZ]; +char thinkOutput1[MSG_SIZ*10]; + +/*ChessProgramState first, second; */ + +/* premove variables */ +int premoveToX = 0; +int premoveToY = 0; +int premoveFromX = 0; +int premoveFromY = 0; +int premovePromoChar = 0; +int gotPremove = 0; +Boolean alarmSounded; +/* end premove variables */ + +#define ICS_GENERIC 0 +#define ICS_ICC 1 +#define ICS_FICS 2 +#define ICS_CHESSNET 3 /* not really supported */ +int ics_type = ICS_GENERIC; +char *ics_prefix = "$"; + +int currentMove = 0, forwardMostMove = 0, backwardMostMove = 0; +int pauseExamForwardMostMove = 0; +int nCmailGames = 0, nCmailResults = 0, nCmailMovesRegistered = 0; +int cmailMoveRegistered[CMAIL_MAX_GAMES], cmailResult[CMAIL_MAX_GAMES]; +int cmailMsgLoaded = FALSE, cmailMailedMove = FALSE; +int cmailOldMove = -1, firstMove = TRUE, flipView = FALSE; +int blackPlaysFirst = FALSE, startedFromSetupPosition = FALSE; +int searchTime = 0, pausing = FALSE, pauseExamInvalid = FALSE; +int whiteFlag = FALSE, blackFlag = FALSE; +int userOfferedDraw = FALSE; +int ics_user_moved = 0, ics_getting_history = H_FALSE, ics_gamenum = -1; +int matchMode = FALSE, hintRequested = FALSE, bookRequested = FALSE; +int cmailMoveType[CMAIL_MAX_GAMES]; +prefixHint = 0; /* PonderMove true/false */ +long ics_clock_paused = 0; +ProcRef icsPR = NoProc, cmailPR = NoProc; +InputSourceRef telnetISR = NULL, fromUserISR = NULL, cmailISR = NULL; +gameMode = BeginningOfGame; +char moveList[MAX_MOVES][MOVE_LEN], parseList[MAX_MOVES][MOVE_LEN * 2]; +char *commentList[MAX_MOVES], *cmailCommentList[CMAIL_MAX_GAMES]; +char white_holding[64], black_holding[64]; +TimeMark lastNodeCountTime; +long lastNodeCount = 0; +int have_sent_ICS_logon = 0; +int movesPerSession; +long whiteTimeRemaining, blackTimeRemaining, timeControl, timeIncrement; +long timeRemaining[2][MAX_MOVES]; +int matchGame = 0; +TimeMark programStartTime; +char ics_handle[MSG_SIZ]; +int have_set_title = 0; +smartQueue icsQueue[max_gamenum]; + +/* zippypassword3 */ +typedef struct { + char string[512]; +} value[6]; +value command; + +/* Search stats from chessprogram */ +typedef struct { + char movelist[MSG_SIZ]; /* Last PV we were sent */ + char ponderMove[12]; /* Current ponder move */ + int depth; /* Current search depth */ + int nr_moves; /* Total nr of root moves */ + int moves_left; /* Moves remaining to be searched */ + char move_name[MOVE_LEN]; /* Current move being searched, if provided */ + unsigned long nodes; /* # of nodes searched */ + int time; /* Search time (centiseconds) */ + int score; /* Score (centipawns) */ + int got_only_move; /* If last msg was "(only move)" */ + int got_fail; /* 0 - nothing, 1 - got "--", 2 - got "++" */ + int ok_to_send; /* handshaking between send & recv */ + int line_is_book; /* 1 if movelist is book moves */ + int seen_stat; /* 1 if we've seen the stat01: line */ + int GUI_time; /* Time from EngineRoom */ +} ChessProgramStats; + +static ChessProgramStats programStats; + +/* animateTraining preserves the state of appData.animate + * when Training mode is activated. This allows the + * response to be animated when appData.animate == TRUE and + * appData.animateDragging == TRUE. + */ +Boolean animateTraining; + +GameInfo gameInfo; + +AppData appData; + +Board boards[MAX_MOVES]; +Board initialPosition = { + { WhiteRook, WhiteKnight, WhiteBishop, WhiteQueen, + WhiteKing, WhiteBishop, WhiteKnight, WhiteRook }, + { WhitePawn, WhitePawn, WhitePawn, WhitePawn, + WhitePawn, WhitePawn, WhitePawn, WhitePawn }, + { EmptySquare, EmptySquare, EmptySquare, EmptySquare, + EmptySquare, EmptySquare, EmptySquare, EmptySquare }, + { EmptySquare, EmptySquare, EmptySquare, EmptySquare, + EmptySquare, EmptySquare, EmptySquare, EmptySquare }, + { EmptySquare, EmptySquare, EmptySquare, EmptySquare, + EmptySquare, EmptySquare, EmptySquare, EmptySquare }, + { EmptySquare, EmptySquare, EmptySquare, EmptySquare, + EmptySquare, EmptySquare, EmptySquare, EmptySquare }, + { BlackPawn, BlackPawn, BlackPawn, BlackPawn, + BlackPawn, BlackPawn, BlackPawn, BlackPawn }, + { BlackRook, BlackKnight, BlackBishop, BlackQueen, + BlackKing, BlackBishop, BlackKnight, BlackRook } +}; +Board twoKingsPosition = { + { WhiteRook, WhiteKnight, WhiteBishop, WhiteQueen, + WhiteKing, WhiteKing, WhiteKnight, WhiteRook }, + { WhitePawn, WhitePawn, WhitePawn, WhitePawn, + WhitePawn, WhitePawn, WhitePawn, WhitePawn }, + { EmptySquare, EmptySquare, EmptySquare, EmptySquare, + EmptySquare, EmptySquare, EmptySquare, EmptySquare }, + { EmptySquare, EmptySquare, EmptySquare, EmptySquare, + EmptySquare, EmptySquare, EmptySquare, EmptySquare }, + { EmptySquare, EmptySquare, EmptySquare, EmptySquare, + EmptySquare, EmptySquare, EmptySquare, EmptySquare }, + { EmptySquare, EmptySquare, EmptySquare, EmptySquare, + EmptySquare, EmptySquare, EmptySquare, EmptySquare }, + { BlackPawn, BlackPawn, BlackPawn, BlackPawn, + BlackPawn, BlackPawn, BlackPawn, BlackPawn }, + { BlackRook, BlackKnight, BlackBishop, BlackQueen, + BlackKing, BlackKing, BlackKnight, BlackRook } +}; + +/* Convert str to a rating. Checks for special cases of "----", + "++++", etc. Also strips ()'s */ +int +string_to_rating(str) + char *str; +{ + while(*str && !isdigit(*str)) ++str; + if (!*str) + return 0; /* One of the special "no rating" cases */ + else + return atoi(str); +} + +void +ClearProgramStats() +{ + /* Init programStats */ + programStats.movelist[0] = NULLCHAR; + programStats.ponderMove[0] = 0; + programStats.depth = 0; + programStats.nr_moves = 0; + programStats.moves_left = 0; + programStats.nodes = 0; + programStats.time = 100; + programStats.score = 0; + programStats.got_only_move = 0; + programStats.got_fail = 0; + programStats.line_is_book = 0; +} + +void +InitBackEnd1() +{ + int matched, min, sec; + + GetTimeMark(&programStartTime); + + ClearProgramStats(); + programStats.ok_to_send = 1; + programStats.seen_stat = 0; + supportStat = 0; + + /* + * Initialize game list + */ + ListNew(&gameList); + + + /* + * Internet chess server status + */ + if (appData.icsActive) { + appData.matchMode = FALSE; + appData.matchGames = 0; +#if ZIPPY + appData.noChessProgram = !appData.zippyPlay; +#else + appData.zippyPlay = FALSE; + appData.zippyTalk = FALSE; + appData.noChessProgram = TRUE; +#endif + if (*appData.icsHelper != NULLCHAR) { + appData.useTelnet = TRUE; + appData.telnetProgram = appData.icsHelper; + } + } else { + appData.zippyTalk = appData.zippyPlay = FALSE; + } + + /* + * Parse timeControl resource + */ + if (!ParseTimeControl(appData.timeControl, appData.timeIncrement, + appData.movesPerSession)) { + char buf[MSG_SIZ]; + sprintf(buf, "bad timeControl option %s", appData.timeControl); + DisplayFatalError(buf, 0, 2); + } + + /* + * Parse searchTime resource + */ + if (*appData.searchTime != NULLCHAR) { + matched = sscanf(appData.searchTime, "%d:%d", &min, &sec); + if (matched == 1) { + searchTime = min * 60; + } else if (matched == 2) { + searchTime = min * 60 + sec; + } else { + char buf[MSG_SIZ]; + sprintf(buf, "bad searchTime option %s", appData.searchTime); + DisplayFatalError(buf, 0, 2); + } + } + + first.which = "first"; + second.which = "second"; + first.maybeThinking = second.maybeThinking = FALSE; + first.pr = second.pr = NoProc; + first.isr = second.isr = NULL; + first.sendTime = second.sendTime = 2; + first.sendDrawOffers = 1; + if (appData.firstPlaysBlack) { + first.twoMachinesColor = "black\n"; + second.twoMachinesColor = "white\n"; + } else { + first.twoMachinesColor = "white\n"; + second.twoMachinesColor = "black\n"; + } + first.program = appData.firstChessProgram; + second.program = appData.secondChessProgram; + first.host = appData.firstHost; + second.host = appData.secondHost; + first.dir = appData.firstDirectory; + second.dir = appData.secondDirectory; + first.other = &second; + second.other = &first; + first.initString = appData.initString; + second.initString = appData.secondInitString; + first.computerString = appData.firstComputerString; + second.computerString = appData.secondComputerString; + first.useSigint = second.useSigint = TRUE; + first.useSigterm = second.useSigterm = TRUE; + first.reuse = appData.reuseFirst; + second.reuse = appData.reuseSecond; + first.useSetboard = second.useSetboard = FALSE; + first.useSAN = second.useSAN = FALSE; + first.usePing = second.usePing = FALSE; + first.lastPing = second.lastPing = 0; + first.lastPong = second.lastPong = 0; + first.usePlayother = second.usePlayother = FALSE; + first.useColors = second.useColors = TRUE; + first.useUsermove = second.useUsermove = FALSE; + first.sendICS = second.sendICS = FALSE; + first.sendName = second.sendName = appData.icsActive; + first.sdKludge = second.sdKludge = FALSE; + first.stKludge = second.stKludge = FALSE; + TidyProgramName(first.program, first.host, first.tidy); + TidyProgramName(second.program, second.host, second.tidy); + first.matchWins = second.matchWins = 0; + strcpy(first.variants, appData.variant); + strcpy(second.variants, appData.variant); + first.analysisSupport = second.analysisSupport = 2; /* detect */ + first.analyzing = second.analyzing = FALSE; + first.initDone = second.initDone = FALSE; + + if (appData.firstProtocolVersion > PROTOVER || + appData.firstProtocolVersion < 1) { + char buf[MSG_SIZ]; + sprintf(buf, "protocol version %d not supported", + appData.firstProtocolVersion); + DisplayFatalError(buf, 0, 2); + } else { + first.protocolVersion = appData.firstProtocolVersion; + } + + if (appData.secondProtocolVersion > PROTOVER || + appData.secondProtocolVersion < 1) { + char buf[MSG_SIZ]; + sprintf(buf, "protocol version %d not supported", + appData.secondProtocolVersion); + DisplayFatalError(buf, 0, 2); + } else { + second.protocolVersion = appData.secondProtocolVersion; + } + + if (appData.icsActive) { + appData.clockMode = TRUE; /* changes dynamically in ICS mode */ + } else if (*appData.searchTime != NULLCHAR || appData.noChessProgram) { + appData.clockMode = FALSE; + first.sendTime = second.sendTime = 0; + } + +#if ZIPPY + /* Override some settings from environment variables, for backward + compatibility. Unfortunately it's not feasible to have the env + vars just set defaults, at least in xboard. Ugh. + */ + if (appData.icsActive && (appData.zippyPlay || appData.zippyTalk)) { + ZippyInit(); + } +#endif + + if (appData.noChessProgram) { + programVersion = (char*) malloc(5 + strlen(PRODUCT) + strlen(VERSION) + + strlen(PATCHLEVEL)); + sprintf(programVersion, "%s %s.%s", PRODUCT, VERSION, PATCHLEVEL); + } else { + char *p, *q; + q = first.program; + while (*q != ' ' && *q != NULLCHAR) q++; + p = q; + while (p > first.program && *(p-1) != '/') p--; + programVersion = (char*) malloc(8 + strlen(PRODUCT) + strlen(VERSION) + + strlen(PATCHLEVEL) + (q - p)); + sprintf(programVersion, "%s %s.%s + ", PRODUCT, VERSION, PATCHLEVEL); + strncat(programVersion, p, q - p); + } + + if (!appData.icsActive) { + char buf[MSG_SIZ]; + /* Check for variants that are supported only in ICS mode, + or not at all. Some that are accepted here nevertheless + have bugs; see comments below. + */ + VariantClass variant = StringToVariant(appData.variant); + switch (variant) { + case VariantBughouse: /* need four players and two boards */ + case VariantKriegspiel: /* need to hide pieces and move details */ + case VariantFischeRandom: /* castling doesn't work, shuffle not done */ + sprintf(buf, "Variant %s supported only in ICS mode", appData.variant); + DisplayFatalError(buf, 0, 2); + return; + + case VariantUnknown: + case VariantLoadable: + case Variant29: + case Variant30: + case Variant31: + case Variant32: + case Variant33: + case Variant34: + case Variant35: + case Variant36: + default: + sprintf(buf, "Unknown variant name %s", appData.variant); + DisplayFatalError(buf, 0, 2); + return; + + case VariantNormal: /* definitely works! */ + case VariantWildCastle: /* pieces not automatically shuffled */ + case VariantNoCastle: /* pieces not automatically shuffled */ + case VariantCrazyhouse: /* holdings not shown, + offboard interposition not understood */ + case VariantLosers: /* should work except for win condition, + and doesn't know captures are mandatory */ + case VariantSuicide: /* should work except for win condition, + and doesn't know captures are mandatory */ + case VariantGiveaway: /* should work except for win condition, + and doesn't know captures are mandatory */ + case VariantTwoKings: /* should work */ + case VariantAtomic: /* should work except for win condition */ + case Variant3Check: /* should work except for win condition */ + case VariantShatranj: /* might work if TestLegality is off */ + break; + } + } +} + +int +ParseTimeControl(tc, ti, mps) + char *tc; + int ti; + int mps; +{ + int matched, min, sec; + + matched = sscanf(tc, "%d:%d", &min, &sec); + if (matched == 1) { + timeControl = min * 60 * 1000; + } else if (matched == 2) { + timeControl = (min * 60 + sec) * 1000; + } else { + return FALSE; + } + + if (ti >= 0) { + timeIncrement = ti * 1000; /* convert to ms */ + movesPerSession = 0; + } else { + timeIncrement = 0; + movesPerSession = mps; + } + return TRUE; +} + +void +InitBackEnd2() +{ + if (appData.debugMode) { + fprintf(debugFP, "%s\n", programVersion); + } + + if (appData.matchGames > 0) { + appData.matchMode = TRUE; + } else if (appData.matchMode) { + appData.matchGames = 1; + } + Reset(TRUE, FALSE); + if (appData.noChessProgram || first.protocolVersion == 1) { + InitBackEnd3(); + } else { + /* kludge: allow timeout for initial "feature" commands */ + FreezeUI(); + if (appData.icsActive) { + DisplayMessage("", "ICS-Mode: Waiting for chessprogram..."); + } else { + DisplayMessage("", "Starting chessprogram"); + } + ScheduleDelayedEvent(InitBackEnd3, FEATURE_TIMEOUT); + } +} + +void +InitBackEnd3 P((void)) +{ + GameMode initialMode; + char buf[MSG_SIZ]; + int err; + + InitChessProgram(&first); + + /* Make a console window if needed */ + if (appData.icsActive) { + ConsoleCreate(); + } + /* engine Room */ + supportStat = 0; + + if (appData.icsActive) { + err = establish(); + if (err != 0) { + if (*appData.icsCommPort != NULLCHAR) { + sprintf(buf, "Could not open comm port %s", + appData.icsCommPort); + } else { + sprintf(buf, "Could not connect to host %s, port %s", + appData.icsHost, appData.icsPort); + } + DisplayFatalError(buf, err, 1); + return; + } + SetICSMode(); + telnetISR = + AddInputSource(icsPR, FALSE, read_from_ics, &telnetISR); + fromUserISR = + AddInputSource(NoProc, FALSE, read_from_player, &fromUserISR); + } else if (appData.noChessProgram) { + SetNCPMode(); + } else { + SetGNUMode(); + } + + if (*appData.cmailGameName != NULLCHAR) { + SetCmailMode(); + OpenLoopback(&cmailPR); + cmailISR = + AddInputSource(cmailPR, FALSE, CmailSigHandlerCallBack, &cmailISR); + } + + ThawUI(); + DisplayMessage("", ""); + if (StrCaseCmp(appData.initialMode, "") == 0) { + initialMode = BeginningOfGame; + } else if (StrCaseCmp(appData.initialMode, "TwoMachines") == 0) { + initialMode = TwoMachinesPlay; + } else if (StrCaseCmp(appData.initialMode, "AnalyzeFile") == 0) { + initialMode = AnalyzeFile; + } else if (StrCaseCmp(appData.initialMode, "Analysis") == 0) { + initialMode = AnalyzeMode; + } else if (StrCaseCmp(appData.initialMode, "MachineWhite") == 0) { + initialMode = MachinePlaysWhite; + } else if (StrCaseCmp(appData.initialMode, "MachineBlack") == 0) { + initialMode = MachinePlaysBlack; + } else if (StrCaseCmp(appData.initialMode, "EditGame") == 0) { + initialMode = EditGame; + } else if (StrCaseCmp(appData.initialMode, "EditPosition") == 0) { + initialMode = EditPosition; + } else if (StrCaseCmp(appData.initialMode, "Training") == 0) { + initialMode = Training; + } else { + sprintf(buf, "Unknown initialMode %s", appData.initialMode); + DisplayFatalError(buf, 0, 2); + return; + } + + if (appData.matchMode) { + /* Set up machine vs. machine match */ + if (appData.noChessProgram) { + DisplayFatalError("Can't have a match with no chess programs", + 0, 2); + return; + } + matchMode = TRUE; + matchGame = 1; + if (*appData.loadGameFile != NULLCHAR) { + if (!LoadGameFromFile(appData.loadGameFile, + appData.loadGameIndex, + appData.loadGameFile, FALSE)) { + DisplayFatalError("Bad game file", 0, 1); + return; + } + } else if (*appData.loadPositionFile != NULLCHAR) { + if (!LoadPositionFromFile(appData.loadPositionFile, + appData.loadPositionIndex, + appData.loadPositionFile)) { + DisplayFatalError("Bad position file", 0, 1); + return; + } + } + TwoMachinesEvent(); + } else if (*appData.cmailGameName != NULLCHAR) { + /* Set up cmail mode */ + ReloadCmailMsgEvent(TRUE); + } else { + /* Set up other modes */ + if (initialMode == AnalyzeFile) { + if (*appData.loadGameFile == NULLCHAR) { + DisplayFatalError("AnalyzeFile mode requires a game file", 0, 1); + return; + } + } + if (*appData.loadGameFile != NULLCHAR) { + (void) LoadGameFromFile(appData.loadGameFile, + appData.loadGameIndex, + appData.loadGameFile, TRUE); + } else if (*appData.loadPositionFile != NULLCHAR) { + (void) LoadPositionFromFile(appData.loadPositionFile, + appData.loadPositionIndex, + appData.loadPositionFile); + } + if (initialMode == AnalyzeMode) { + if (appData.noChessProgram) { + DisplayFatalError("Analysis mode requires a chess engine", 0, 2); + return; + } + if (appData.icsActive) { + DisplayFatalError("Analysis mode does not work with ICS mode",0,2); + return; + } + AnalyzeModeEvent(); + } else if (initialMode == AnalyzeFile) { + ShowThinkingEvent(TRUE); + AnalyzeFileEvent(); + AnalysisPeriodicEvent(1); + } else if (initialMode == MachinePlaysWhite) { + if (appData.noChessProgram) { + DisplayFatalError("MachineWhite mode requires a chess engine", + 0, 2); + return; + } + if (appData.icsActive) { + DisplayFatalError("MachineWhite mode does not work with ICS mode", + 0, 2); + return; + } + MachineWhiteEvent(); + } else if (initialMode == MachinePlaysBlack) { + if (appData.noChessProgram) { + DisplayFatalError("MachineBlack mode requires a chess engine", + 0, 2); + return; + } + if (appData.icsActive) { + DisplayFatalError("MachineBlack mode does not work with ICS mode", + 0, 2); + return; + } + MachineBlackEvent(); + } else if (initialMode == TwoMachinesPlay) { + if (appData.noChessProgram) { + DisplayFatalError("TwoMachines mode requires a chess engine", + 0, 2); + return; + } + if (appData.icsActive) { + DisplayFatalError("TwoMachines mode does not work with ICS mode", + 0, 2); + return; + } + TwoMachinesEvent(); + } else if (initialMode == EditGame) { + EditGameEvent(); + } else if (initialMode == EditPosition) { + EditPositionEvent(); + } else if (initialMode == Training) { + if (*appData.loadGameFile == NULLCHAR) { + DisplayFatalError("Training mode requires a game file", 0, 2); + return; + } + TrainingEvent(); + } + } + /* If EngineRoom TRUE start */ + if (appData.AnalysisWindow && appData.showThinking && + !appData.noChessProgram) { + if (appData.icsActive && appData.zippyPlay) { + AnalysisPopUp(0,0,0,0,0,0,0,5); + } + if (!appData.icsActive) AnalysisPopUp(0,0,0,0,0,0,0,5); + StartAnalysisClock(); + } +} + +/* + * Establish will establish a contact to a remote host.port. + * Sets icsPR to a ProcRef for a process (or pseudo-process) + * used to talk to the host. + * Returns 0 if okay, error code if not. + */ +int +establish() +{ + char buf[MSG_SIZ]; + + if (*appData.icsCommPort != NULLCHAR) { + /* Talk to the host through a serial comm port */ + return OpenCommPort(appData.icsCommPort, &icsPR); + + } else if (*appData.gateway != NULLCHAR) { + if (*appData.remoteShell == NULLCHAR) { + /* Use the rcmd protocol to run telnet program on a gateway host */ + sprintf(buf, "%s %s %s", + appData.telnetProgram, appData.icsHost, appData.icsPort); + return OpenRcmd(appData.gateway, appData.remoteUser, buf, &icsPR); + + } else { + /* Use the rsh program to run telnet program on a gateway host */ + if (*appData.remoteUser == NULLCHAR) { + sprintf(buf, "%s %s %s %s %s", appData.remoteShell, + appData.gateway, appData.telnetProgram, + appData.icsHost, appData.icsPort); + } else { + sprintf(buf, "%s %s -l %s %s %s %s", + appData.remoteShell, appData.gateway, + appData.remoteUser, appData.telnetProgram, + appData.icsHost, appData.icsPort); + } + return StartChildProcess(buf, "", &icsPR); + + } + } else if (appData.useTelnet) { + return OpenTelnet(appData.icsHost, appData.icsPort, &icsPR); + + } else { + /* TCP socket interface differs somewhat between + Unix and NT; handle details in the front end. + */ + return OpenTCP(appData.icsHost, appData.icsPort, &icsPR); + } +} + +void +show_bytes(fp, buf, count) + FILE *fp; + char *buf; + int count; +{ + while (count--) { + if (*buf < 040 || *(unsigned char *) buf > 0177) { + fprintf(fp, "\\%03o", *buf & 0xff); + } else { + putc(*buf, fp); + } + buf++; + } + fflush(fp); +} + +/* Returns an errno value */ +int +OutputMaybeTelnet(pr, message, count, outError) + ProcRef pr; + char *message; + int count; + int *outError; +{ + char buf[8192], *p, *q, *buflim; + int left, newcount, outcount; + + if (*appData.icsCommPort != NULLCHAR || appData.useTelnet || + *appData.gateway != NULLCHAR) { + if (appData.debugMode) { + fprintf(debugFP, ">ICS: "); + show_bytes(debugFP, message, count); + fprintf(debugFP, "\n"); + } + return OutputToProcess(pr, message, count, outError); + } + + buflim = &buf[sizeof(buf)-1]; /* allow 1 byte for expanding last char */ + p = message; + q = buf; + left = count; + newcount = 0; + while (left) { + if (q >= buflim) { + if (appData.debugMode) { + fprintf(debugFP, ">ICS: "); + show_bytes(debugFP, buf, newcount); + fprintf(debugFP, "\n"); + } + outcount = OutputToProcess(pr, buf, newcount, outError); + if (outcount < newcount) return -1; /* to be sure */ + q = buf; + newcount = 0; + } + if (*p == '\n') { + *q++ = '\r'; + newcount++; + } else if (((unsigned char) *p) == TN_IAC) { + *q++ = (char) TN_IAC; + newcount ++; + } + *q++ = *p++; + newcount++; + left--; + } + if (appData.debugMode) { + fprintf(debugFP, ">ICS: "); + show_bytes(debugFP, buf, newcount); + fprintf(debugFP, "\n"); + } + outcount = OutputToProcess(pr, buf, newcount, outError); + if (outcount < newcount) return -1; /* to be sure */ + return count; +} + +void +read_from_player(isr, closure, message, count, error) + InputSourceRef isr; + VOIDSTAR closure; + char *message; + int count; + int error; +{ + int outError, outCount; + static int gotEof = 0; + + /* Pass data read from player on to ICS */ + if (count > 0) { + gotEof = 0; + outCount = OutputMaybeTelnet(icsPR, message, count, &outError); + if (outCount < count) { + DisplayFatalError("Error writing to ICS", outError, 1); + } + } else if (count < 0) { + RemoveInputSource(isr); + DisplayFatalError("Error reading from keyboard", error, 1); + } else if (gotEof++ > 0) { + RemoveInputSource(isr); + DisplayFatalError("Got end of file from keyboard", 0, 0); + } +} + +void +SendToICS(s) + char *s; +{ + int count, outCount, outError; + + if (icsPR == NULL) return; + + count = strlen(s); + outCount = OutputMaybeTelnet(icsPR, s, count, &outError); + if (outCount < count) { + DisplayFatalError("Error writing to ICS", outError, 1); + } +} + +/* This is used for sending logon scripts to the ICS. Sending + without a delay causes problems when using timestamp on ICC + (at least on my machine). */ +void +SendToICSDelayed(s,msdelay) + char *s; + long msdelay; +{ + int count, outCount, outError; + + if (icsPR == NULL) return; + + count = strlen(s); + if (appData.debugMode) { + fprintf(debugFP, ">ICS: "); + show_bytes(debugFP, s, count); + fprintf(debugFP, "\n"); + } + outCount = OutputToProcessDelayed(icsPR, s, count, &outError, + msdelay); + if (outCount < count) { + DisplayFatalError("Error writing to ICS", outError, 1); + } +} + + +/* Remove all highlighting escape sequences in s + Also deletes any suffix starting with '(' + */ +char * +StripHighlightAndTitle(s) + char *s; +{ + static char retbuf[MSG_SIZ]; + char *p = retbuf; + + while (*s != NULLCHAR) { + while (*s == '\033') { + while (*s != NULLCHAR && !isalpha(*s)) s++; + if (*s != NULLCHAR) s++; + } + while (*s != NULLCHAR && *s != '\033') { + if (*s == '(' || *s == '[') { + *p = NULLCHAR; + return retbuf; + } + *p++ = *s++; + } + } + *p = NULLCHAR; + return retbuf; +} + +/* Remove all highlighting escape sequences in s */ +char * +StripHighlight(s) + char *s; +{ + static char retbuf[MSG_SIZ]; + char *p = retbuf; + + while (*s != NULLCHAR) { + while (*s == '\033') { + while (*s != NULLCHAR && !isalpha(*s)) s++; + if (*s != NULLCHAR) s++; + } + while (*s != NULLCHAR && *s != '\033') { + *p++ = *s++; + } + } + *p = NULLCHAR; + return retbuf; +} + +char *variantNames[] = VARIANT_NAMES; +char * +VariantName(v) + VariantClass v; +{ + return variantNames[v]; +} + + +/* Identify a variant from the strings the chess servers use or the + PGN Variant tag names we use. */ +VariantClass +StringToVariant(e) + char *e; +{ + char *p; + int wnum = -1; + VariantClass v = VariantNormal; + int i, found = FALSE; + char buf[MSG_SIZ]; + + if (!e) return v; + + for (i=0; i%s %s ", ddwwStr, optionStr); + } + msg[0] = TN_IAC; + msg[1] = ddww; + msg[2] = option; + outCount = OutputToProcess(icsPR, (char *)msg, 3, &outError); + if (outCount < 3) { + DisplayFatalError("Error writing to ICS", outError, 1); + } +} + +void +DoEcho() +{ + if (!appData.icsActive) return; + TelnetRequest(TN_DO, TN_ECHO); +} + +void +DontEcho() +{ + if (!appData.icsActive) return; + TelnetRequest(TN_DONT, TN_ECHO); +} + +static int loggedOn = FALSE; + +/*-- Game start info cache: --*/ +int gs_gamenum; +char gs_kind[MSG_SIZ]; +static char player1Name[128] = ""; +static char player2Name[128] = ""; +static int player1Rating = -1; +static int player2Rating = -1; +/*----------------------------*/ + + +/* ICC user send showinfo und we send latest pv */ +/* If username beginn with guest* send advertisement ;-) */ +void +showInfo(data, player) +char* data; +char* player; +{ + char *ptr = data; + char temp[MSG_SIZ]; + char buf[MSG_SIZ]; + int i; + + /* this feature is only for ICC admins or chessprogramer */ + /* You must set commandline /icc to use this */ + if (appData.userVersion == TRUE) return; + if (appData.ICC_feature == FALSE || ics_type != ICS_ICC) return; + while (*ptr == ' ') ptr++; + if (*ptr == 0 || (sizeof(ptr) > MSG_SIZ)) return; + sscanf(ptr, "%s", buf); + + /* showgames command */ + if (strncmp(buf, "showgames", 9) == 0) { + { + int counter; + for (counter = 1; counter <= max_gamenum; counter++) { + if (icsQueue[counter].killPv > 0) { + sprintf(temp, "tell %s I analyze game %d (%s/%s)\n", player, counter, + icsQueue[counter].white, icsQueue[counter].black); + SendToICS(temp); + } + } + return; + } + } + i = atoi(buf); /* security first - user could try to buffer overflow data ! */ + if (i > max_gamenum || icsQueue[i].killPv == 0) { + sprintf(temp, "tell %s I don't analysis this game\n", player); + SendToICS(temp); + sprintf(temp, "tell %s \"tell %s showgames\" to see which games are currently analyzed.\n", player, ics_handle); + SendToICS(temp); + } else if (icsQueue[i].killPv > 0) { + sprintf(temp, "tell %s Hello %s from Winboard-DM\n", player, player); + SendToICS(temp); + /* pos after "Depth " */ + if (icsQueue[i].lastpv[0]) { + sprintf(temp, "tell %s Last analyze of game %d (%s/%s): (%s) Depth=%s\n", + player, i, icsQueue[i].white, icsQueue[i].black, first.tidy, icsQueue[i].lastpv); + } else { + sprintf(temp, "tell %s Sorry, no analysis avaible from game %d at the moment. Please try it later again.\n", + player, i); + } + SendToICS(temp); + /* for ICC guest send member and register info */ + if (strncmp(player, "guest", 5) == 0) { + sprintf(temp, "tell %s Be member of ICC. Get a free 7-days trial membership: \"http://www.chessclub.com/register/english.html\" For more information type: \"help reg\"\n", player); + SendToICS(temp); + } + } +} + +/* ICS-Analyze: + Call this to see if we have a game where we not send a message + for the current move + */ + +int +SwitchGames() +{ + int counter; + char buf[32]; + + for (counter = 1; counter <= max_gamenum; counter++) { + if (icsQueue[counter].killPv > 0 && icsQueue[counter].CurrentMove >= + icsQueue[counter].MessageMove && icsQueue[counter].flag == 0) { + if (appData.debugMode) fprintf(debugFP, "ICS-Analyze: We switch to game %d \n", counter); + sprintf(buf, "refresh %d \n", counter); + SendToICS(buf); + return 0; + break; + } + } + return 1; +} + +/* parse and action from zippy password3 */ +void +ParseZippyP3(data, player) +char* data; +char* player; +{ + int counter = 0; + int forward = 0; + int i, j; + char *ptr = data; + char temp[MSG_SIZ]; + + if (appData.userVersion == TRUE) return; + + for (;;) { + if (counter > 6) { + sprintf(temp, "tell %s Sorry, to many values. Max 6 values each line. Try again.\n", player); + SendToICS(temp); + sprintf(temp, "tell %s Or try send me \"help\"\n", player); + SendToICS(temp); + return; + } + while (*ptr == ' ') ptr++; + if (*ptr == 0) break; + sscanf(ptr, "%s", command[counter].string); + if (appData.debugMode) fprintf(debugFP, "zp3: %s\n", command[counter].string); + ptr = ptr + strlen(command[counter].string); + counter++; + } + if(strncmp(command[forward].string, "help", 4) == 0) { + /* icc don't accept text after new line :((( */ + /* So, we must write every line */ + sprintf(temp, "tell %s Hello %s from %s %s%s\n", player, player, PRODUCT, VERSION, PATCHLEVEL); + SendToICS(temp); + sprintf(temp, "tell %s analyze \n", player); + SendToICS(temp); + sprintf(temp, "tell %s analyze \n", player); + SendToICS(temp); + sprintf(temp, "tell %s analyze output if tell \n", player); + SendToICS(temp); + sprintf(temp, "tell %s analyze killpv \n", player); + SendToICS(temp); + sprintf(temp, "tell %s if you are setup killpv you enable it automaticly\n", player); + SendToICS(temp); + sprintf(temp, "tell %s analyze smartqueue <1|0>\n", player); + SendToICS(temp); + sprintf(temp, "tell %s analyze show \n", player); + SendToICS(temp); + sprintf(temp, "tell %s engine reset\n", player); + SendToICS(temp); + sprintf(temp, "tell %s \n", player); + SendToICS(temp); + return; + } + + if (strncmp(command[forward].string, "engine", 6) == 0) { + if (strncmp(command[forward+1].string, "reset", 5) == 0) { + sprintf(temp, "tell %s reset engine...\n", player); + SendToICS(temp); + ResurrectChessProgram(); + } + return; + } + /* + if (strncmp(command[forward].string, "whisper", 7) == 0) { + sprintf(temp, "tell %s GUI = whisper\n", player); + SendToICS(temp); + appData.SendOutPutToICS = 1; + return; + } else if (trncmp(command[forward].string, "kibitz", 6) == 0) { + sprintf(temp, "tell %s GUI = kibitz\n", player); + SendToICS(temp); + appData.SendOutPutToICS = 2; + return; + } + */ + if(gameMode == IcsPlayingWhite || gameMode == IcsPlayingBlack) { + sprintf(temp, "tell %s Sorry, i'm playing a game!\n", player); + SendToICS(temp); + return; + } + if (strncmp(command[forward].string, "analyze", 10) == 0) { + if (strncmp(command[forward+1].string, "observe", 7) == 0 || + strncmp(command[forward+1].string, "follow", 6) == 0 || + strncmp(command[forward+1].string, "unobserve", 9) == 0 || + strncmp(command[forward+1].string, "unfollow", 8) == 0) { + + /* reset Queue if leave */ + if (strncmp(command[forward+1].string, "unobserve", 9) == 0 || + strncmp(command[forward+1].string, "unfollow", 8) == 0) ResetIcsQueue(ics_gamenum); + + /* secure */ + if(gameMode != IcsPlayingWhite || gameMode != IcsPlayingBlack) { + sprintf(temp, "%s %s\n", command[forward+1].string, + command[forward+2].string); + SendToICS(temp); + sprintf(temp, "tell %s action: %s %s\n", player, command[forward+1].string, + command[forward+2].string); + if (strncmp(command[forward+1].string, "observe", 7) == 0 || + strncmp(command[forward+1].string, "follow", 6) == 0) { + + if (ics_gamenum > max_gamenum) { + sprintf(temp, "tell %s gamenumber to high\n", player); + SendToICS(temp); + return; + } + } + } else { + sprintf(temp, "tell %s Sorry, i'm playing\n", player); + } + SendToICS(temp); + return; + } + + if (strncmp(command[forward+1].string, "start", 5) == 0) { + if (gameMode != IcsObserving) { + sprintf(temp, "tell %s I must observe a game\n", player); + } else if (gameMode == IcsObserving) { + sprintf(temp, "tell %s Starting ICS analyze...\n", player); + appData.icsAnalyze = TRUE; + IcsAnalyze(TRUE); + } + SendToICS(temp); + return; + } + if (strncmp(command[forward+1].string, "stop", 4) == 0) { + if (gameMode != IcsObserving) { + sprintf(temp, "tell %s I must observe a game\n", player); + } else if (gameMode == IcsObserving) { + sprintf(temp, "tell %s Stopping ICS analyze...\n", player); + IcsAnalyze(FALSE); + } + SendToICS(temp); + return; + } + if (strncmp(command[forward+1].string, "output", 6) == 0) { + if(strncmp(command[forward+2].string, "whisper", 7) == 0) { + appData.icsAnalyzeOutPut = 1; + sprintf(temp, "tell %s analyze output is whisper\n", player); + } else if (strncmp(command[forward+2].string, "kibitz", 6) == 0) { + appData.icsAnalyzeOutPut = 2; + sprintf(temp, "tell %s analyze output is kibitz\n", player); + } else if (strncmp(command[forward+2].string, "tell", 4) == 0) { + appData.icsAnalyzeOutPut = 3; + if (command[forward+3].string[0] != NULLCHAR) { + if (strncmp(command[forward+3].string, "none", 4) == 0) { + appData.icsAnalyzeOutPut = 4; + sprintf(temp, "tell %s analyze output is: none\n", player); + SendToICS(temp); + return; + } + strcpy(appData.icsTells, command[forward+3].string); + sprintf(temp, "tell %s analyze output is tell: %s\n", player, + appData.icsTells); + } else { + sprintf(temp, "tell %s Error: I don't know where i should send my analysis\n", player); + appData.icsAnalyzeOutPut = 4; + } + } + SendToICS(temp); + } + if (strncmp(command[forward+1].string, "killpv", 6) == 0) { + i = atoi(command[forward+3].string); + j = atoi(command[forward+2].string); + if (i <= max_gamenum && i != 0) { + if (icsQueue[i].killPv == 0) { + sprintf(temp, "tell %s Error: Mh, killpv is zero. Wrong gamenumber?\n", player); + SendToICS(temp); + } else { + if ( j > 20 || j < 1) { + sprintf(temp, "tell %s Error: killpv must be 1-20\n", player); + } else { + sprintf(temp, "tell %s killpv for game %d is now %d\n", player, i, j); + icsQueue[i].killPv = j; + appData.icsEngineKillPV = TRUE; + } + SendToICS(temp); + } + } else { + sprintf(temp, "tell %s Error: not possible gamenumber\n", player); + SendToICS(temp); + } + return; + } + if (strncmp(command[forward+1].string, "smartqueue", 10) == 0) { + j = atoi(command[forward+2].string); + if (j == 0 || j == 1) { + appData.smartQueue = j; + sprintf(temp, "tell %s smartqueue is now: %d", player, appData.smartQueue); + } else { + sprintf(temp, "tell %s Error: not possible smartquere value\n", player); + } + SendToICS(temp); + return; + } + if (strncmp(command[forward+1].string, "show", 4) == 0) { + i = atoi(command[forward+2].string); + if (i <= max_gamenum && i != 0) { + if (icsQueue[i].killPv == 0) { + sprintf(temp, "tell %s Error: emtpy game slot. Wrong gamenumber?\n", player); + SendToICS(temp); + } else { + sprintf(temp, "tell %s summary information about game: %d\n", player, i); + SendToICS(temp); + sprintf(temp, "tell %s enable killpv: %d, killpv value = %d\n", player, + appData.icsEngineKillPV, icsQueue[i].killPv); + SendToICS(temp); + sprintf(temp, "tell %s enable smartqueue (all games): %d\n", player, appData.smartQueue); + SendToICS(temp); + sprintf(temp, "tell %s analyze output (all games) is %d\n", player, + appData.icsAnalyzeOutPut); + SendToICS(temp); + } + } else { + sprintf(temp, "tell %s Error: not possible gamenumber\n", player); + SendToICS(temp); + } + return; + } + } +} + +void +read_from_ics(isr, closure, data, count, error) + InputSourceRef isr; + VOIDSTAR closure; + char *data; + int count; + int error; +{ +#define BUF_SIZE 8192 +#define STARTED_NONE 0 +#define STARTED_MOVES 1 +#define STARTED_BOARD 2 +#define STARTED_OBSERVE 3 +#define STARTED_HOLDINGS 4 +#define STARTED_CHATTER 5 +#define STARTED_COMMENT 6 +#define STARTED_MOVES_NOHIDE 7 + + static int started = STARTED_NONE; + static char parse[20000]; + static int parse_pos = 0; + static char buf[BUF_SIZE + 1]; + static int firstTime = TRUE, intfSet = FALSE; + static ColorClass curColor = ColorNormal; + static ColorClass prevColor = ColorNormal; + static int savingComment = FALSE; + char str[512]; + int i, oldi; + int buf_len; + int next_out; + int tkind; + /* extra zippy vars */ + int save; + char *q; + char *p = 0; + char *player; + char reply[MSG_SIZ]; + + if (count > 0) { + /* If last read ended with a partial line that we couldn't parse, + prepend it to the new read and try again. */ + if (leftover_len > 0) { + for (i=0; i= 3 && (unsigned char) buf[i] == TN_IAC) { + static int remoteEchoOption = FALSE; /* telnet ECHO option */ + unsigned char option; + oldi = i; + switch ((unsigned char) buf[++i]) { + case TN_WILL: + if (appData.debugMode) + fprintf(debugFP, "\n next_out) + SendToPlayer(&buf[next_out], oldi - next_out); + if (++i > next_out) + next_out = i; + continue; + } + + /* OK, this at least will *usually* work */ + if (!loggedOn && looking_at(buf, &i, "ics%")) { + loggedOn = TRUE; + } + + if (loggedOn && !intfSet) { + if (ics_type == ICS_ICC) { + sprintf(str, + "/set-quietly interface %s\n/set-quietly style 12\n", + programVersion); + + } else if (ics_type == ICS_CHESSNET) { + sprintf(str, "/style 12\n"); + } else { + strcpy(str, "alias $ @\n$set interface "); + strcat(str, programVersion); + strcat(str, "\n$iset startpos 1\n$iset ms 1\n"); +#ifdef WIN32 + strcat(str, "$iset nohighlight 1\n"); +#endif + strcat(str, "$iset lock 1\n$style 12\n"); + } + SendToICS(str); + intfSet = TRUE; + } + + if (started == STARTED_COMMENT) { + /* Accumulate characters in comment */ + parse[parse_pos++] = buf[i]; + if (buf[i] == '\n') { + parse[parse_pos] = NULLCHAR; + AppendComment(forwardMostMove, StripHighlight(parse)); + started = STARTED_NONE; + } else { + /* Don't match patterns against characters in chatter */ + i++; + continue; + } + } + if (started == STARTED_CHATTER) { + if (buf[i] != '\n') { + /* Don't match patterns against characters in chatter */ + i++; + continue; + } + started = STARTED_NONE; + } + + /* Kludge to deal with rcmd protocol */ + if (firstTime && looking_at(buf, &i, "\001*")) { + DisplayFatalError(&buf[1], 0, 1); + continue; + } else { + firstTime = FALSE; + } + + if (!loggedOn && looking_at(buf, &i, "chessclub.com")) { + ics_type = ICS_ICC; + ics_prefix = "/"; + if (appData.debugMode) + fprintf(debugFP, "ics_type %d\n", ics_type); + continue; + } + if (!loggedOn && looking_at(buf, &i, "freechess.org")) { + ics_type = ICS_FICS; + ics_prefix = "$"; + if (appData.debugMode) + fprintf(debugFP, "ics_type %d\n", ics_type); + continue; + } + if (!loggedOn && looking_at(buf, &i, "chess.net")) { + ics_type = ICS_CHESSNET; + ics_prefix = "/"; + if (appData.debugMode) + fprintf(debugFP, "ics_type %d\n", ics_type); + continue; + } + + if (!loggedOn && + (looking_at(buf, &i, "\"*\" is *a registered name") || + looking_at(buf, &i, "Logging you in as \"*\"") || + looking_at(buf, &i, "will be \"*\""))) { + strcpy(ics_handle, star_match[0]); + continue; + } + + if (loggedOn && !have_set_title && ics_handle[0] != NULLCHAR) { + char buf[MSG_SIZ]; + sprintf(buf, "%s@%s", ics_handle, appData.icsHost); + DisplayIcsInteractionTitle(buf); + have_set_title = TRUE; + } + + /* skip finger notes */ + if (started == STARTED_NONE && + ((buf[i] == ' ' && isdigit(buf[i+1])) || + (buf[i] == '1' && buf[i+1] == '0')) && + buf[i+2] == ':' && buf[i+3] == ' ') { + started = STARTED_CHATTER; + i += 3; + continue; + } + + /* skip formula vars */ + if (started == STARTED_NONE && + buf[i] == 'f' && isdigit(buf[i+1]) && buf[i+2] == ':') { + started = STARTED_CHATTER; + i += 3; + continue; + } + oldi = i; + + /* save position of char array pointer for zippy */ + save = i; + /* Try found special things that never works with color */ + /* I really don't know why - code is ok. */ + q = p; + + if (appData.zippyTalk || appData.zippyPlay) { + if (looking_at(buf, &save, "* tells you: *") || + looking_at(buf, &save, "* says: *")) { + player = StripHighlightAndTitle(star_match[0]); + if (appData.zippyPassword[0] != NULLCHAR && + strncmp(star_match[1], appData.zippyPassword, + strlen(appData.zippyPassword)) == 0) { + q = star_match[1] + strlen(appData.zippyPassword); + while (*q == ' ') q++; + fprintf(debugFP, "zippy 1 %s \n", q); + SendToICS(q); + SendToICS("\n"); + } else if(appData.zippyPassword2[0] != NULLCHAR && first.initDone && + strncmp(star_match[1], appData.zippyPassword2, + strlen(appData.zippyPassword2)) == 0) { + fprintf(debugFP, "zippy2vor: %s \n", q); + q = star_match[1] + strlen(appData.zippyPassword2); + while (*q == ' ') q++; + SendToProgram(q, &first); + SendToProgram("\n", &first); + + } else if (appData.zippyPassword3[0] != NULLCHAR && first.initDone && + strncmp(star_match[1], appData.zippyPassword3, + strlen(appData.zippyPassword3)) == 0 && + appData.userVersion == FALSE) { + q = star_match[1] + strlen(appData.zippyPassword3); + ParseZippyP3(q, player); + + } else if (strncmp(star_match[1], "showinfo", 8) == 0 && + appData.userVersion == FALSE && appData.icsAnalyze == TRUE && + appData.icsAnalyzeOutPut == 3 && appData.ICC_feature == TRUE) { + q = star_match[1] + strlen("showinfo"); + showInfo(q, player); + } else if (strncmp(star_match[1], "showgames", 9) == 0 && + appData.userVersion == FALSE && appData.icsAnalyze == TRUE && + appData.icsAnalyzeOutPut == 3 && appData.ICC_feature == TRUE) { + q = star_match[1]; + showInfo(q, player); + + } else if (appData.zippyWrongPassword[0] != NULLCHAR && + strncmp(star_match[1], appData.zippyWrongPassword, + strlen(appData.zippyWrongPassword)) == 0) { + q = star_match[1] + strlen(appData.zippyWrongPassword); + while (*q == ' ') q++; + sprintf(reply, "wrong %s\n", player); + SendToICS(reply); + } + } + /* workaround for icc and freechess.org */ + if (looking_at(buf, &save, "Your opponent offers you a draw") || + looking_at(buf, &save, "offers you a draw") || + looking_at(buf, &save, "* offers you a draw")) { + if (first.sendDrawOffers && first.initDone) { + SendToProgram("draw\n", &first); + /* Handling zippy Draw */ + } else if (appData.zippyDraw && first.initDone) { + //ZippyDraw(1, programStats.score, programStats.depth); + } + } + if (appData.zippyPlay && first.initDone && loggedOn == TRUE) ZippyMatch(buf, &save, player); + } + + /* Make color for all and for zippy */ + if (/* Don't color "message" or "messages" output */ + (tkind = 5, looking_at(buf, &i, "*. * (*:*): ")) || + looking_at(buf, &i, "*. * at *:*: ") || + looking_at(buf, &i, "--* (*:*): ") || + /* Regular tells and says */ + (tkind = 1, looking_at(buf, &i, "* tells you: ")) || + looking_at(buf, &i, "* (your partner) tells you: ") || + looking_at(buf, &i, "* says: ") || + /* Message notifications (same color as tells) */ + looking_at(buf, &i, "* has left a message ") || + looking_at(buf, &i, "* just sent you a message:\n") || + /* Whispers and kibitzes */ + (tkind = 2, looking_at(buf, &i, "* whispers: ")) || + looking_at(buf, &i, "* kibitzes: ") || + /* Channel tells */ + (tkind = 3, looking_at(buf, &i, "*(*: "))) { + + if (tkind == 1 && strchr(star_match[0], ':')) { + /* Avoid "tells you:" spoofs in channels */ + tkind = 3; + } + if (star_match[0][0] == NULLCHAR || + strchr(star_match[0], ' ') || + (tkind == 3 && strchr(star_match[1], ' '))) { + /* Reject bogus matches */ + i = oldi; + } else { + if (appData.colorize) { + if (oldi > next_out) { + SendToPlayer(&buf[next_out], oldi - next_out); + next_out = oldi; + } + switch (tkind) { + case 1: + Colorize(ColorTell, FALSE); + curColor = ColorTell; + break; + case 2: + Colorize(ColorKibitz, FALSE); + curColor = ColorKibitz; + break; + case 3: + p = strrchr(star_match[1], '('); + if (p == NULL) { + p = star_match[1]; + } else { + p++; + } + if (atoi(p) == 1) { + Colorize(ColorChannel1, FALSE); + curColor = ColorChannel1; + } else { + Colorize(ColorChannel, FALSE); + curColor = ColorChannel; + } + break; + case 5: + curColor = ColorNormal; + break; + } + } + if (started == STARTED_NONE && appData.autoComment && + (gameMode == IcsObserving || + gameMode == IcsPlayingWhite || + gameMode == IcsPlayingBlack)) { + parse_pos = i - oldi; + memcpy(parse, &buf[oldi], parse_pos); + parse[parse_pos] = NULLCHAR; + started = STARTED_COMMENT; + savingComment = TRUE; + } else { + started = STARTED_CHATTER; + savingComment = FALSE; + } + loggedOn = TRUE; + continue; + } + } + + if (looking_at(buf, &i, "* s-shouts: ") || + looking_at(buf, &i, "* c-shouts: ")) { + if (appData.colorize) { + if (oldi > next_out) { + SendToPlayer(&buf[next_out], oldi - next_out); + next_out = oldi; + } + Colorize(ColorSShout, FALSE); + curColor = ColorSShout; + } + loggedOn = TRUE; + started = STARTED_CHATTER; + continue; + } + + if (looking_at(buf, &i, "--->")) { + loggedOn = TRUE; + continue; + } + + if (looking_at(buf, &i, "* shouts: ") || + looking_at(buf, &i, "--> ")) { + if (appData.colorize) { + if (oldi > next_out) { + SendToPlayer(&buf[next_out], oldi - next_out); + next_out = oldi; + } + Colorize(ColorShout, FALSE); + curColor = ColorShout; + } + loggedOn = TRUE; + started = STARTED_CHATTER; + continue; + } + + if (looking_at( buf, &i, "Challenge:")) { + if (appData.colorize) { + if (oldi > next_out) { + SendToPlayer(&buf[next_out], oldi - next_out); + next_out = oldi; + } + Colorize(ColorChallenge, FALSE); + curColor = ColorChallenge; + } + loggedOn = TRUE; + continue; + } + + if (looking_at(buf, &i, "* offers you") || + looking_at(buf, &i, "* offers to be") || + looking_at(buf, &i, "* would like to") || + looking_at(buf, &i, "* requests to") || + looking_at(buf, &i, "Your opponent offers") || + looking_at(buf, &i, "Your opponent requests")) { + + if (appData.colorize) { + if (oldi > next_out) { + SendToPlayer(&buf[next_out], oldi - next_out); + next_out = oldi; + } + Colorize(ColorRequest, FALSE); + curColor = ColorRequest; + } + continue; + } + + if (looking_at(buf, &i, "* (*) seeking")) { + if (appData.colorize) { + if (oldi > next_out) { + SendToPlayer(&buf[next_out], oldi - next_out); + next_out = oldi; + } + Colorize(ColorSeek, FALSE); + curColor = ColorSeek; + } + continue; + } + + + if (looking_at(buf, &i, "\\ ")) { + if (prevColor != ColorNormal) { + if (oldi > next_out) { + SendToPlayer(&buf[next_out], oldi - next_out); + next_out = oldi; + } + Colorize(prevColor, TRUE); + curColor = prevColor; + } + if (savingComment) { + parse_pos = i - oldi; + memcpy(parse, &buf[oldi], parse_pos); + parse[parse_pos] = NULLCHAR; + started = STARTED_COMMENT; + } else { + started = STARTED_CHATTER; + } + continue; + } + + if (looking_at(buf, &i, "Black Strength :") || + looking_at(buf, &i, "<<< style 10 board >>>") || + looking_at(buf, &i, "<10>") || + looking_at(buf, &i, "#@#")) { + /* Wrong board style */ + loggedOn = TRUE; + SendToICS(ics_prefix); + SendToICS("set style 12\n"); + SendToICS(ics_prefix); + SendToICS("refresh\n"); + continue; + } + + if (!have_sent_ICS_logon && looking_at(buf, &i, "login:")) { + ICSInitScript(); + have_sent_ICS_logon = 1; + continue; + } + + if (ics_getting_history != H_GETTING_MOVES /*smpos kludge*/ && + (looking_at(buf, &i, "\n<12> ") || + looking_at(buf, &i, "<12> "))) { + loggedOn = TRUE; + if (oldi > next_out) { + SendToPlayer(&buf[next_out], oldi - next_out); + } + next_out = i; + started = STARTED_BOARD; + parse_pos = 0; + continue; + } + + if ((started == STARTED_NONE && looking_at(buf, &i, "\n ")) || + looking_at(buf, &i, " ")) { + if (oldi > next_out) { + SendToPlayer(&buf[next_out], oldi - next_out); + } + next_out = i; + started = STARTED_HOLDINGS; + parse_pos = 0; + continue; + } + + /* Send buf now to zippy */ + if (appData.zippyTalk || appData.zippyPlay) { +#if ZIPPY + if (ZippyControl(buf, &save) || ZippyConverse(buf, &save)) { + loggedOn = TRUE; + continue; + } +#endif + } + + /* ICS: init icsQueue */ + if (appData.zippyPlay && first.initDone && gameMode == IcsObserving) { + if (ics_gamenum > max_gamenum || ics_gamenum == -1) { + if (appData.debugMode) fprintf(debugFP, "To high gamenumber or gamenumber -1 !\n"); + return; + } + if (icsQueue[ics_gamenum].killPv == 0) { + icsQueue[ics_gamenum].move = currentMove; + icsQueue[ics_gamenum].killPv = appData.icsKillPVs; + icsQueue[ics_gamenum].counter = 0; + strcpy(icsQueue[ics_gamenum].white, gameInfo.white); + strcpy(icsQueue[ics_gamenum].black, gameInfo.black); + } + } + + if (looking_at(buf, &i, "* *vs. * *--- *")) { + loggedOn = TRUE; + /* Header for a move list -- first line */ + switch (ics_getting_history) { + case H_FALSE: + switch (gameMode) { + case IcsIdle: + case BeginningOfGame: + /* User typed "moves" or "oldmoves" while we + were idle. Pretend we asked for these + moves and soak them up so user can step + through them and/or save them. + */ + Reset(FALSE, TRUE); + gameMode = IcsObserving; + ModeHighlight(); + ics_gamenum = -1; + ics_getting_history = H_GOT_UNREQ_HEADER; + break; + case EditGame: /*?*/ + case EditPosition: /*?*/ + /* Should above feature work in these modes too? */ + /* For now it doesn't */ + ics_getting_history = H_GOT_UNWANTED_HEADER; + break; + default: + ics_getting_history = H_GOT_UNWANTED_HEADER; + break; + } + break; + case H_REQUESTED: + /* Is this the right one? */ + if (gameInfo.white && gameInfo.black && + strcmp(gameInfo.white, star_match[0]) == 0 && + strcmp(gameInfo.black, star_match[2]) == 0) { + /* All is well */ + ics_getting_history = H_GOT_REQ_HEADER; + } + break; + case H_GOT_REQ_HEADER: + case H_GOT_UNREQ_HEADER: + case H_GOT_UNWANTED_HEADER: + case H_GETTING_MOVES: + /* Should not happen */ + DisplayError("Error gathering move list: two headers", 0); + ics_getting_history = H_FALSE; + break; + } + + /* Save player ratings into gameInfo if needed */ + if ((ics_getting_history == H_GOT_REQ_HEADER || + ics_getting_history == H_GOT_UNREQ_HEADER) && + (gameInfo.whiteRating == -1 || + gameInfo.blackRating == -1)) { + + gameInfo.whiteRating = string_to_rating(star_match[1]); + gameInfo.blackRating = string_to_rating(star_match[3]); + if (appData.debugMode) + fprintf(debugFP, "Ratings from header: W %d, B %d\n", + gameInfo.whiteRating, gameInfo.blackRating); + } + continue; + } + + if (looking_at(buf, &i, + "* * match, initial time: * minute*, increment: * second")) { + /* Header for a move list -- second line */ + /* Initial board will follow if this is a wild game */ + + if (gameInfo.event != NULL) free(gameInfo.event); + sprintf(str, "ICS %s %s match", star_match[0], star_match[1]); + gameInfo.event = StrSave(str); + gameInfo.variant = StringToVariant(gameInfo.event); + continue; + } + + if (looking_at(buf, &i, "Move ")) { + /* Beginning of a move list */ + switch (ics_getting_history) { + case H_FALSE: + /* Normally should not happen */ + /* Maybe user hit reset while we were parsing */ + break; + case H_REQUESTED: + /* Happens if we are ignoring a move list that is not + * the one we just requested. Common if the user + * tries to observe two games without turning off + * getMoveList */ + break; + case H_GETTING_MOVES: + /* Should not happen */ + DisplayError("Error gathering move list: nested", 0); + ics_getting_history = H_FALSE; + break; + case H_GOT_REQ_HEADER: + ics_getting_history = H_GETTING_MOVES; + started = STARTED_MOVES; + parse_pos = 0; + if (oldi > next_out) { + SendToPlayer(&buf[next_out], oldi - next_out); + } + break; + case H_GOT_UNREQ_HEADER: + ics_getting_history = H_GETTING_MOVES; + started = STARTED_MOVES_NOHIDE; + parse_pos = 0; + break; + case H_GOT_UNWANTED_HEADER: + ics_getting_history = H_FALSE; + break; + } + continue; + } + + if (looking_at(buf, &i, "% ") || + ((started == STARTED_MOVES || started == STARTED_MOVES_NOHIDE) + && looking_at(buf, &i, "}*"))) { + savingComment = FALSE; + switch (started) { + case STARTED_MOVES: + case STARTED_MOVES_NOHIDE: + memcpy(&parse[parse_pos], &buf[oldi], i - oldi); + parse[parse_pos + i - oldi] = NULLCHAR; + ParseGameHistory(parse); +#if ZIPPY + if (appData.zippyPlay && first.initDone) { + if (appData.icsAnalyze && gameMode == IcsObserving) { + IcsAnalyze(TRUE); + } + /* icsAnalyze send the moves to engine if we start new */ + if (!appData.icsAnalyze) FeedMovesToProgram(&first, forwardMostMove); + /* Bug 4.2.6: Engine want play, skip that */ + if (gameMode == IcsExamining) { + /* set idle mode */ + SendToProgram("force\n", &first); + } + if (gameMode == IcsPlayingWhite) { + if (appData.icsAnalyze) { + IcsAnalyze(FALSE); + appData.icsAnalyze = FALSE; + + } + if (WhiteOnMove(forwardMostMove)) { + if (first.sendTime) { + if (first.useColors) { + SendToProgram("black\n", &first); + } + SendTimeRemaining(&first, TRUE); + } + if (first.useColors) { + SendToProgram("white\ngo\n", &first); + } else { + SendToProgram("go\n", &first); + } + first.maybeThinking = TRUE; + } else { + if (first.usePlayother) { + if (first.sendTime) { + SendTimeRemaining(&first, TRUE); + } + SendToProgram("playother\n", &first); + firstMove = FALSE; + } else { + firstMove = TRUE; + } + } + } else if (gameMode == IcsPlayingBlack) { + if (appData.icsAnalyze) { + IcsAnalyze(FALSE); + appData.icsAnalyze = FALSE; + SendToICS("refresh\n"); + } + /* engineRoom stay forever */ + if (!WhiteOnMove(forwardMostMove)) { + if (first.sendTime) { + if (first.useColors) { + SendToProgram("white\n", &first); + } + SendTimeRemaining(&first, FALSE); + } + if (first.useColors) { + SendToProgram("black\ngo\n", &first); + } else { + SendToProgram("go\n", &first); + } + first.maybeThinking = TRUE; + } else { + if (first.usePlayother) { + if (first.sendTime) { + SendTimeRemaining(&first, FALSE); + } + SendToProgram("playother\n", &first); + firstMove = FALSE; + } else { + firstMove = TRUE; + } + } + } + +#endif ZIPPY + + } + if (gameMode == IcsObserving && ics_gamenum == -1) { + /* Moves came from oldmoves or moves command + while we weren't doing anything else. + */ + currentMove = forwardMostMove; + ClearHighlights();/*!!could figure this out*/ + flipView = appData.flipView; + DrawPosition(FALSE, boards[currentMove]); + DisplayBothClocks(); + sprintf(str, "%s vs. %s", + gameInfo.white, gameInfo.black); + DisplayTitle(str); + gameMode = IcsIdle; + } else { + /* Moves were history of an active game */ + if (gameInfo.resultDetails != NULL) { + free(gameInfo.resultDetails); + gameInfo.resultDetails = NULL; + } + } + HistorySet(parseList, backwardMostMove, + forwardMostMove, currentMove-1); + DisplayMove(currentMove - 1); + if (started == STARTED_MOVES) next_out = i; + started = STARTED_NONE; + ics_getting_history = H_FALSE; + break; + + case STARTED_OBSERVE: + started = STARTED_NONE; + SendToICS(ics_prefix); + SendToICS("refresh\n"); + break; + + default: + break; + } + continue; + } + + if ((started == STARTED_MOVES || started == STARTED_BOARD || + started == STARTED_HOLDINGS || + started == STARTED_MOVES_NOHIDE) && i >= leftover_len) { + /* Accumulate characters in move list or board */ + parse[parse_pos++] = buf[i]; + } + + /* Start of game messages. Mostly we detect start of game + when the first board image arrives. On some versions + of the ICS, though, we need to do a "refresh" after starting + to observe in order to get the current board right away. */ + if (looking_at(buf, &i, "Adding game * to observation list")) { + started = STARTED_OBSERVE; + continue; + } + + /* Handle auto-observe */ + if (appData.autoObserve && + (gameMode == IcsIdle || gameMode == BeginningOfGame) && + looking_at(buf, &i, "Game notification: * (*) vs. * (*)")) { + char *player; + /* Choose the player that was highlighted, if any. */ + if (star_match[0][0] == '\033' || + star_match[1][0] != '\033') { + player = star_match[0]; + } else { + player = star_match[2]; + } + sprintf(str, "%sobserve %s\n", + ics_prefix, StripHighlightAndTitle(player)); + SendToICS(str); + + /* Save ratings from notify string */ + strcpy(player1Name, star_match[0]); + player1Rating = string_to_rating(star_match[1]); + strcpy(player2Name, star_match[2]); + player2Rating = string_to_rating(star_match[3]); + + if (appData.debugMode) + fprintf(debugFP, + "Ratings from 'Game notification:' %s %d, %s %d\n", + player1Name, player1Rating, + player2Name, player2Rating); + + continue; + } + + /* Deal with automatic examine mode after a game, + and with IcsObserving -> IcsExamining transition */ + if (looking_at(buf, &i, "Entering examine mode for game *") || + looking_at(buf, &i, "has made you an examiner of game *")) { + + int gamenum = atoi(star_match[0]); + if ((gameMode == IcsIdle || gameMode == IcsObserving) && + gamenum == ics_gamenum) { + /* We were already playing or observing this game; + no need to refetch history */ + gameMode = IcsExamining; + if (pausing) { + pauseExamForwardMostMove = forwardMostMove; + } else if (currentMove < forwardMostMove) { + ForwardInner(forwardMostMove); + } + } else { + /* I don't think this case really can happen */ + SendToICS(ics_prefix); + SendToICS("refresh\n"); + } + continue; + } + + /* Error messages */ + if (ics_user_moved) { + if (looking_at(buf, &i, "Illegal move") || + looking_at(buf, &i, "Not a legal move") || + looking_at(buf, &i, "Your king is in check") || + looking_at(buf, &i, "It isn't your turn") || + looking_at(buf, &i, "It is not your move")) { + /* Illegal move */ + ics_user_moved = 0; + if (forwardMostMove > backwardMostMove) { + currentMove = --forwardMostMove; + DisplayMove(currentMove - 1); /* before DMError */ + DisplayMoveError("Illegal move (rejected by ICS)"); + DrawPosition(FALSE, boards[currentMove]); + SwitchClocks(); + DisplayBothClocks(); + } + continue; + } + } + + if (looking_at(buf, &i, "still have time") || + looking_at(buf, &i, "not out of time") || + looking_at(buf, &i, "either player is out of time") || + looking_at(buf, &i, "has timeseal; checking")) { + /* We must have called his flag a little too soon */ + whiteFlag = blackFlag = FALSE; + continue; + } + + if (looking_at(buf, &i, "added * seconds to") || + looking_at(buf, &i, "seconds were added to")) { + /* Update the clocks */ + SendToICS(ics_prefix); + SendToICS("refresh\n"); + continue; + } + + if (!ics_clock_paused && looking_at(buf, &i, "clock paused")) { + ics_clock_paused = TRUE; + StopClocks(); + continue; + } + + if (ics_clock_paused && looking_at(buf, &i, "clock resumed")) { + ics_clock_paused = FALSE; + StartClocks(); + continue; + } + + /* Grab player ratings from the Creating: message. + Note we have to check for the special case when + the ICS inserts things like [white] or [black]. */ + if (looking_at(buf, &i, "Creating: * (*)* * (*)") || + looking_at(buf, &i, "Creating: * (*) [*] * (*)")) { + /* star_matches: + 0 player 1 name (not necessarily white) + 1 player 1 rating + 2 empty, white, or black (IGNORED) + 3 player 2 name (not necessarily black) + 4 player 2 rating + + The names/ratings are sorted out when the game + actually starts (below). + */ + strcpy(player1Name, StripHighlightAndTitle(star_match[0])); + player1Rating = string_to_rating(star_match[1]); + strcpy(player2Name, StripHighlightAndTitle(star_match[3])); + player2Rating = string_to_rating(star_match[4]); + + if (appData.debugMode) + fprintf(debugFP, + "Ratings from 'Creating:' %s %d, %s %d\n", + player1Name, player1Rating, + player2Name, player2Rating); + + continue; + } + + /* Improved generic start/end-of-game messages */ + if (looking_at(buf, &i, "{Game * (* vs. *) *}*")) { + /* star_match[0] is the game number */ + /* [1] is the white player's name */ + /* [2] is the black player's name */ + /* For end-of-game: */ + /* [3] is the reason for the game end */ + /* [4] is a PGN end game-token, preceded by " " */ + /* For start-of-game: */ + /* [3] begins with "Creating" or "Continuing" */ + /* [4] is " *" or empty (don't care). */ + int gamenum = atoi(star_match[0]); + char *why = star_match[3]; + char *endtoken = star_match[4]; + ChessMove endtype = (ChessMove) 0; + + /* Game start messages */ + if (strncmp(why, "Creating ", 9) == 0 || + strncmp(why, "Continuing ", 11) == 0) { + gs_gamenum = gamenum; + strcpy(gs_kind, strchr(why, ' ') + 1); +#if ZIPPY + if (appData.zippyPlay) { + ZippyGameStart(star_match[1], star_match[2]); + } +#endif /*ZIPPY*/ + continue; + } + + /* Game end messages */ + if (gameMode == IcsIdle || gameMode == BeginningOfGame || + ics_gamenum != gamenum) { + continue; + } + while (endtoken[0] == ' ') endtoken++; + switch (endtoken[0]) { + case '*': + default: + endtype = GameUnfinished; + break; + case '0': + endtype = BlackWins; + break; + case '1': + if (endtoken[1] == '/') + endtype = GameIsDrawn; + else + endtype = WhiteWins; + break; + } + GameEnds(endtype, why, GE_ICS); +#if ZIPPY + if (appData.zippyPlay && first.initDone) { + ZippyGameEnd(endtype, why); + if (first.pr == NULL) { + /* Start the next process early so that we'll + be ready for the next challenge */ + StartChessProgram(&first); + } + /* Send "new" early, in case this command takes + a long time to finish, so that we'll be ready + for the next challenge. */ + Reset(TRUE, TRUE); + } +#endif /*ZIPPY*/ + continue; + } + + if (looking_at(buf, &i, "Removing game * from observation") || + looking_at(buf, &i, "no longer observing game *") || + looking_at(buf, &i, "Game * (*) has no examiners")) { + if (gameMode == IcsObserving && + atoi(star_match[0]) == ics_gamenum) + { + if (appData.icsAnalyze) IcsAnalyze(FALSE); + ResetIcsQueue(ics_gamenum); + StopClocks(); + gameMode = IcsIdle; + ics_gamenum = -1; + ics_user_moved = FALSE; + } + continue; + } + + if (looking_at(buf, &i, "no longer examining game *")) { + if (gameMode == IcsExamining && + atoi(star_match[0]) == ics_gamenum) + { + if (appData.icsAnalyze) IcsAnalyze(FALSE); + ResetIcsQueue(ics_gamenum); + gameMode = IcsIdle; + ics_gamenum = -1; + ics_user_moved = FALSE; + } + continue; + } + + /* Advance leftover_start past any newlines we find, + so only partial lines can get reparsed */ + if (looking_at(buf, &i, "\n")) { + prevColor = curColor; + if (curColor != ColorNormal) { + if (oldi > next_out) { + SendToPlayer(&buf[next_out], oldi - next_out); + next_out = oldi; + } + Colorize(ColorNormal, FALSE); + curColor = ColorNormal; + } + if (started == STARTED_BOARD) { + started = STARTED_NONE; + parse[parse_pos] = NULLCHAR; + ParseBoard12(parse); + ics_user_moved = 0; + + /* Send premove here */ + if (appData.premove) { + char str[MSG_SIZ]; + if (currentMove == 0 && + gameMode == IcsPlayingWhite && + appData.premoveWhite) { + sprintf(str, "%s%s\n", ics_prefix, + appData.premoveWhiteText); + if (appData.debugMode) + fprintf(debugFP, "Sending premove:\n"); + SendToICS(str); + } else if (currentMove == 1 && + gameMode == IcsPlayingBlack && + appData.premoveBlack) { + sprintf(str, "%s%s\n", ics_prefix, + appData.premoveBlackText); + if (appData.debugMode) + fprintf(debugFP, "Sending premove:\n"); + SendToICS(str); + } else if (gotPremove) { + gotPremove = 0; + ClearPremoveHighlights(); + if (appData.debugMode) + fprintf(debugFP, "Sending premove:\n"); + UserMoveEvent(premoveFromX, premoveFromY, + premoveToX, premoveToY, + premovePromoChar); + } + } + + /* Usually suppress following prompt */ + if (!(forwardMostMove == 0 && gameMode == IcsExamining)) { + if (looking_at(buf, &i, "*% ")) { + savingComment = FALSE; + } + } + next_out = i; + } else if (started == STARTED_HOLDINGS) { + int gamenum; + char new_piece[MSG_SIZ]; + started = STARTED_NONE; + parse[parse_pos] = NULLCHAR; + if (appData.debugMode) + fprintf(debugFP, "Parsing holdings: %s\n", parse); + if (sscanf(parse, " game %d", &gamenum) == 1 && + gamenum == ics_gamenum) { + if (gameInfo.variant == VariantNormal) { + gameInfo.variant = VariantCrazyhouse; /*temp guess*/ + /* Get a move list just to see the header, which + will tell us whether this is really bug or zh */ + if (ics_getting_history == H_FALSE) { + ics_getting_history = H_REQUESTED; + sprintf(str, "%smoves %d\n", ics_prefix, gamenum); + SendToICS(str); + } + } + new_piece[0] = NULLCHAR; + sscanf(parse, "game %d white [%s black [%s <- %s", + &gamenum, white_holding, black_holding, + new_piece); + white_holding[strlen(white_holding)-1] = NULLCHAR; + black_holding[strlen(black_holding)-1] = NULLCHAR; +#if ZIPPY + if (appData.zippyPlay && first.initDone) { + ZippyHoldings(white_holding, black_holding, + new_piece); + } +#endif /*ZIPPY*/ + if (tinyLayout || smallLayout) { + char wh[16], bh[16]; + PackHolding(wh, white_holding); + PackHolding(bh, black_holding); + sprintf(str, "[%s-%s] %s-%s", wh, bh, + gameInfo.white, gameInfo.black); + } else { + sprintf(str, "%s [%s] vs. %s [%s]", + gameInfo.white, white_holding, + gameInfo.black, black_holding); + } + DrawPosition(FALSE, NULL); + DisplayTitle(str); + } + /* Suppress following prompt */ + if (looking_at(buf, &i, "*% ")) { + savingComment = FALSE; + } + next_out = i; + } + continue; + } + + i++; /* skip unparsed character and loop back */ + } + + if (started != STARTED_MOVES && started != STARTED_BOARD && + started != STARTED_HOLDINGS && i > next_out) { + SendToPlayer(&buf[next_out], i - next_out); + next_out = i; + } + + leftover_len = buf_len - leftover_start; + /* if buffer ends with something we couldn't parse, + reparse it after appending the next read */ + + } else if (count == 0) { + RemoveInputSource(isr); + DisplayFatalError("Connection closed by ICS", 0, 0); + } else { + DisplayFatalError("Error reading from ICS", error, 1); + } +} + + +/* Board style 12 looks like this: + + <12> r-b---k- pp----pp ---bP--- ---p---- q------- ------P- P--Q--BP -----R-K W -1 0 0 0 0 0 0 paf MaxII 0 2 12 21 25 234 174 24 Q/d7-a4 (0:06) Qxa4 0 0 + + * The "<12> " is stripped before it gets to this routine. The two + * trailing 0's (flip state and clock ticking) are later addition, and + * some chess servers may not have them, or may have only the first. + * Additional trailing fields may be added in the future. + */ + +#define PATTERN "%72c%c%d%d%d%d%d%d%d%s%s%d%d%d%d%d%d%d%d%s%s%s%d%d" + +#define RELATION_OBSERVING_PLAYED 0 +#define RELATION_OBSERVING_STATIC -2 /* examined, oldmoves, or smoves */ +#define RELATION_PLAYING_MYMOVE 1 +#define RELATION_PLAYING_NOTMYMOVE -1 +#define RELATION_EXAMINING 2 +#define RELATION_ISOLATED_BOARD -3 +#define RELATION_STARTING_POSITION -4 /* FICS only */ + +void +ParseBoard12(string) + char *string; +{ + GameMode newGameMode; + int gamenum, newGame, newMove, relation, basetime, increment, ics_flip = 0; + int j, k, n, moveNum, white_stren, black_stren, white_time, black_time; + int double_push, castle_ws, castle_wl, castle_bs, castle_bl, irrev_count; + int takeback, i; + char to_play, board_chars[72]; + char move_str[500], str[500], elapsed_time[500]; + char black[32], white[32]; + Board board; + int prevMove = currentMove; + int ticking = 2; + ChessMove moveType; + int fromX, fromY, toX, toY; + char promoChar; + + fromX = fromY = toX = toY = -1; + + newGame = FALSE; + + if (appData.debugMode) + fprintf(debugFP, "Parsing board: %s\n", string); + + move_str[0] = NULLCHAR; + elapsed_time[0] = NULLCHAR; + n = sscanf(string, PATTERN, board_chars, &to_play, &double_push, + &castle_ws, &castle_wl, &castle_bs, &castle_bl, &irrev_count, + &gamenum, white, black, &relation, &basetime, &increment, + &white_stren, &black_stren, &white_time, &black_time, + &moveNum, str, elapsed_time, move_str, &ics_flip, + &ticking); + + if (n < 22) { + sprintf(str, "Failed to parse board string:\n\"%s\"", string); + DisplayError(str, 0); + return; + } + + /* Convert the move number to internal form */ + moveNum = (moveNum - 1) * 2; + if (to_play == 'B') moveNum++; + if (moveNum >= MAX_MOVES) { + DisplayFatalError("Game too long; increase MAX_MOVES and recompile", + 0, 1); + return; + } + + switch (relation) { + case RELATION_OBSERVING_PLAYED: + case RELATION_OBSERVING_STATIC: + if (gamenum == -1) { + /* Old ICC buglet */ + relation = RELATION_OBSERVING_STATIC; + } + newGameMode = IcsObserving; + break; + case RELATION_PLAYING_MYMOVE: + case RELATION_PLAYING_NOTMYMOVE: + newGameMode = + ((relation == RELATION_PLAYING_MYMOVE) == (to_play == 'W')) ? + IcsPlayingWhite : IcsPlayingBlack; + break; + case RELATION_EXAMINING: + newGameMode = IcsExamining; + break; + case RELATION_ISOLATED_BOARD: + default: + /* Just display this board. If user was doing something else, + we will forget about it until the next board comes. */ + newGameMode = IcsIdle; + break; + case RELATION_STARTING_POSITION: + newGameMode = gameMode; + /* if we switch to a new board start IcsAnalyze */ + if(appData.icsAnalyze) IcsAnalyze(TRUE); + break; + } + + /* Modify behavior for initial board display on move listing + of wild games. + */ + switch (ics_getting_history) { + case H_FALSE: + case H_REQUESTED: + break; + case H_GOT_REQ_HEADER: + case H_GOT_UNREQ_HEADER: + /* This is the initial position of the current game */ + gamenum = ics_gamenum; + moveNum = 0; /* old ICS bug workaround */ + if (to_play == 'B') { + startedFromSetupPosition = TRUE; + blackPlaysFirst = TRUE; + moveNum = 1; + if (forwardMostMove == 0) forwardMostMove = 1; + if (backwardMostMove == 0) backwardMostMove = 1; + if (currentMove == 0) currentMove = 1; + } + newGameMode = gameMode; + relation = RELATION_STARTING_POSITION; /* ICC needs this */ + break; + case H_GOT_UNWANTED_HEADER: + /* This is an initial board that we don't want */ + return; + case H_GETTING_MOVES: + /* Should not happen */ + DisplayError("Error gathering move list: extra board", 0); + ics_getting_history = H_FALSE; + return; + } + + /* Take action if this is the first board of a new game, or of a + different game than is currently being displayed. */ + if (gamenum != ics_gamenum || newGameMode != gameMode || + relation == RELATION_ISOLATED_BOARD) { + + /* Forget the old game and get the history (if any) of the new one */ + if (gameMode != BeginningOfGame) { + Reset(FALSE, TRUE); + } + newGame = TRUE; + if (appData.autoRaiseBoard) BoardToTop(); + prevMove = -3; + if (gamenum == -1) { + newGameMode = IcsIdle; + } else if (moveNum > 0 && newGameMode != IcsIdle && + appData.getMoveList) { + /* Need to get game history */ + ics_getting_history = H_REQUESTED; + sprintf(str, "%smoves %d\n", ics_prefix, gamenum); + SendToICS(str); + } + + + /* Initially flip the board to have black on the bottom if playing + black or if the ICS flip flag is set, but let the user change + it with the Flip View button. */ + flipView = appData.autoFlipView ? + (newGameMode == IcsPlayingBlack) || ics_flip : + appData.flipView; + + /* Done with values from previous mode; copy in new ones */ + gameMode = newGameMode; + ModeHighlight(); + ics_gamenum = gamenum; + if (gamenum == gs_gamenum) { + int klen = strlen(gs_kind); + if (gs_kind[klen - 1] == '.') gs_kind[klen - 1] = NULLCHAR; + sprintf(str, "ICS %s", gs_kind); + gameInfo.event = StrSave(str); + } else { + gameInfo.event = StrSave("ICS game"); + } + gameInfo.site = StrSave(appData.icsHost); + gameInfo.date = PGNDate(); + gameInfo.round = StrSave("-"); + gameInfo.white = StrSave(white); + gameInfo.black = StrSave(black); + timeControl = basetime * 60 * 1000; + timeIncrement = increment * 1000; + movesPerSession = 0; + gameInfo.timeControl = TimeControlTagValue(); + gameInfo.variant = StringToVariant(gameInfo.event); + + /* Do we have the ratings? */ + if (strcmp(player1Name, white) == 0 && + strcmp(player2Name, black) == 0) { + if (appData.debugMode) + fprintf(debugFP, "Remembered ratings: W %d, B %d\n", + player1Rating, player2Rating); + gameInfo.whiteRating = player1Rating; + gameInfo.blackRating = player2Rating; + } else if (strcmp(player2Name, white) == 0 && + strcmp(player1Name, black) == 0) { + if (appData.debugMode) + fprintf(debugFP, "Remembered ratings: W %d, B %d\n", + player2Rating, player1Rating); + gameInfo.whiteRating = player2Rating; + gameInfo.blackRating = player1Rating; + } + player1Name[0] = player2Name[0] = NULLCHAR; + + /* Silence shouts if requested */ + if (appData.quietPlay && + (gameMode == IcsPlayingWhite || gameMode == IcsPlayingBlack)) { + SendToICS(ics_prefix); + SendToICS("set shout 0\n"); + } + } + + /* Deal with midgame name changes */ + if (!newGame) { + if (!gameInfo.white || strcmp(gameInfo.white, white) != 0) { + if (gameInfo.white) free(gameInfo.white); + gameInfo.white = StrSave(white); + } + if (!gameInfo.black || strcmp(gameInfo.black, black) != 0) { + if (gameInfo.black) free(gameInfo.black); + gameInfo.black = StrSave(black); + } + } + + /* Throw away game result if anything actually changes in examine mode */ + if (gameMode == IcsExamining && !newGame) { + gameInfo.result = GameUnfinished; + if (gameInfo.resultDetails != NULL) { + free(gameInfo.resultDetails); + gameInfo.resultDetails = NULL; + } + } + + /* In pausing && IcsExamining mode, we ignore boards coming + in if they are in a different variation than we are. */ + if (pauseExamInvalid) return; + if (pausing && gameMode == IcsExamining) { + if (moveNum <= pauseExamForwardMostMove) { + pauseExamInvalid = TRUE; + forwardMostMove = pauseExamForwardMostMove; + return; + } + } + + /* Parse the board */ + for (k = 0; k < 8; k++) + for (j = 0; j < 8; j++) + board[k][j] = CharToPiece(board_chars[(7-k)*9 + j]); + CopyBoard(boards[moveNum], board); + if (moveNum == 0) { + startedFromSetupPosition = + !CompareBoards(board, initialPosition); + } + + if (ics_getting_history == H_GOT_REQ_HEADER || + ics_getting_history == H_GOT_UNREQ_HEADER) { + /* This was an initial position from a move list, not + the current position */ + return; + } + + /* Update currentMove and known move number limits */ + newMove = newGame || moveNum > forwardMostMove; + + + /* If we found takebacks during IcsAnalyze try send to engine */ + if (!newGame && appData.icsAnalyze && first.analyzing && + moveNum < forwardMostMove) { + if (appData.debugMode) fprintf(debugFP, "take back move\n"); + takeback = forwardMostMove - moveNum; + if (!appData.icsWBprotoAgr) { + /* safty first */ + SendToProgram("exit\n", &first); + SendToProgram("force\n", &first); + for (i = 0; i < takeback; i++) { + SendToProgram("undo\n", &first); + /* Some engine need analyze and stat again */ + } + SendToProgram("analyze\n", &first); + } else { + /* hard */ + IcsAnalyze(FALSE); + IcsAnalyze(TRUE); + } + } + if (newGame) { + forwardMostMove = backwardMostMove = currentMove = moveNum; + if (gameMode == IcsExamining && moveNum == 0) { + /* Workaround for ICS limitation: we are not told the wild + type when starting to examine a game. But if we ask for + the move list, the move list header will tell us */ + ics_getting_history = H_REQUESTED; + sprintf(str, "%smoves %d\n", ics_prefix, gamenum); + SendToICS(str); + } + } else if (moveNum == forwardMostMove + 1 || moveNum == forwardMostMove + || (moveNum < forwardMostMove && moveNum >= backwardMostMove)) { + forwardMostMove = moveNum; + if (!pausing || currentMove > forwardMostMove) + currentMove = forwardMostMove; + } else { + /* New part of history that is not contiguous with old part */ + if (pausing && gameMode == IcsExamining) { + pauseExamInvalid = TRUE; + forwardMostMove = pauseExamForwardMostMove; + return; + } + forwardMostMove = backwardMostMove = currentMove = moveNum; + if (gameMode == IcsExamining && moveNum > 0 && appData.getMoveList) { + ics_getting_history = H_REQUESTED; + sprintf(str, "%smoves %d\n", ics_prefix, gamenum); + SendToICS(str); + } + } + + { + int i = 0; + /* Update the clocks */ + if (strchr(elapsed_time, '.')) { + /* Time is in ms */ + timeRemaining[0][moveNum] = whiteTimeRemaining = white_time; + timeRemaining[1][moveNum] = blackTimeRemaining = black_time; + } else { + /* Time is in seconds */ + i = 1; + timeRemaining[0][moveNum] = whiteTimeRemaining = white_time * 1000; + timeRemaining[1][moveNum] = blackTimeRemaining = black_time * 1000; + } + } + + /* Time workaround for ICC - send only sec :( */ + if (ics_type == ICS_ICC) { + if (timeRemaining[0][moveNum] >= 1500) timeRemaining[0][moveNum] = timeRemaining[0][moveNum] - 1500; + if (timeRemaining[1][moveNum] >= 1500) timeRemaining[1][moveNum] = timeRemaining[1][moveNum] - 1500; + + if (timeRemaining[0][moveNum] == 1000) timeRemaining[0][moveNum] = timeRemaining[0][moveNum] - 950; + if (timeRemaining[0][moveNum] == 1000) timeRemaining[1][moveNum] = timeRemaining[1][moveNum] - 950; + + } + +#if ZIPPY + if (appData.zippyPlay && newGame && + gameMode != IcsObserving && gameMode != IcsIdle && + gameMode != IcsExamining) + ZippyFirstBoard(moveNum, basetime, increment); +#endif + + /* Put the move on the move list, first converting + to canonical algebraic form. */ + if (moveNum > 0) { + if (moveNum <= backwardMostMove) { + /* We don't know what the board looked like before + this move. Punt. */ + strcpy(parseList[moveNum - 1], move_str); + strcat(parseList[moveNum - 1], " "); + strcat(parseList[moveNum - 1], elapsed_time); + moveList[moveNum - 1][0] = NULLCHAR; + } else if (ParseOneMove(move_str, moveNum - 1, &moveType, + &fromX, &fromY, &toX, &toY, &promoChar)) { + (void) CoordsToAlgebraic(boards[moveNum - 1], + PosFlags(moveNum - 1), EP_UNKNOWN, + fromY, fromX, toY, toX, promoChar, + parseList[moveNum-1]); + switch (MateTest(boards[moveNum], PosFlags(moveNum), EP_UNKNOWN)){ + case MT_NONE: + case MT_STALEMATE: + default: + break; + case MT_CHECK: + strcat(parseList[moveNum - 1], "+"); + break; + case MT_CHECKMATE: + strcat(parseList[moveNum - 1], "#"); + break; + } + strcat(parseList[moveNum - 1], " "); + strcat(parseList[moveNum - 1], elapsed_time); + /* currentMoveString is set as a side-effect of ParseOneMove */ + strcpy(moveList[moveNum - 1], currentMoveString); + strcat(moveList[moveNum - 1], "\n"); + } else if (strcmp(move_str, "none") == 0) { + /* Again, we don't know what the board looked like; + this is really the start of the game. */ + parseList[moveNum - 1][0] = NULLCHAR; + moveList[moveNum - 1][0] = NULLCHAR; + backwardMostMove = moveNum; + startedFromSetupPosition = TRUE; + fromX = fromY = toX = toY = -1; + } else { + /* Move from ICS was illegal!? Punt. */ +#if 0 + if (appData.testLegality && appData.debugMode) { + sprintf(str, "Illegal move \"%s\" from ICS", move_str); + DisplayError(str, 0); + } +#endif + strcpy(parseList[moveNum - 1], move_str); + strcat(parseList[moveNum - 1], " "); + strcat(parseList[moveNum - 1], elapsed_time); + moveList[moveNum - 1][0] = NULLCHAR; + fromX = fromY = toX = toY = -1; + } + +#if ZIPPY + /* Send move to chess program (BEFORE animating it). */ + if (appData.zippyPlay && !newGame && newMove && + (!appData.getMoveList || backwardMostMove == 0) && first.initDone) { + + if ((gameMode == IcsPlayingWhite && WhiteOnMove(moveNum)) || + (gameMode == IcsPlayingBlack && !WhiteOnMove(moveNum))) { + if (moveList[moveNum - 1][0] == NULLCHAR) { + sprintf(str, "Couldn't parse move \"%s\" from ICS", + move_str); + DisplayError(str, 0); + } else { + if (first.sendTime) { + SendTimeRemaining(&first, gameMode == IcsPlayingWhite); + } + SendMoveToProgram(moveNum - 1, &first); + if (firstMove) { + firstMove = FALSE; + if (first.useColors) { + SendToProgram(gameMode == IcsPlayingWhite ? + "white\ngo\n" : + "black\ngo\n", &first); + } else { + SendToProgram("go\n", &first); + } + first.maybeThinking = TRUE; + } + } + } else if (gameMode == IcsObserving || gameMode == IcsExamining) { + if (moveList[moveNum - 1][0] == NULLCHAR) { + sprintf(str, "Couldn't parse move \"%s\" from ICS", move_str); + DisplayError(str, 0); + } else { + SendMoveToProgram(moveNum - 1, &first); + } + } + } +#endif + } + + if (moveNum > 0 && !gotPremove) { + /* If move comes from a remote source, animate it. If it + isn't remote, it will have already been animated. */ + if (!pausing && !ics_user_moved && prevMove == moveNum - 1) { + AnimateMove(boards[moveNum - 1], fromX, fromY, toX, toY); + } + if (!pausing && appData.highlightLastMove) { + SetHighlights(fromX, fromY, toX, toY); + } + } + + /* Start the clocks */ + whiteFlag = blackFlag = FALSE; + appData.clockMode = !(basetime == 0 && increment == 0); + if (ticking == 0) { + ics_clock_paused = TRUE; + StopClocks(); + } else if (ticking == 1) { + ics_clock_paused = FALSE; + } + if (gameMode == IcsIdle || + relation == RELATION_OBSERVING_STATIC || + relation == RELATION_EXAMINING || + ics_clock_paused) + DisplayBothClocks(); + else + StartClocks(); + + /* Display opponents and material strengths */ + if (gameInfo.variant != VariantBughouse && + gameInfo.variant != VariantCrazyhouse) { + if (tinyLayout || smallLayout) { + sprintf(str, "%s(%d) %s(%d) {%d %d}", + gameInfo.white, white_stren, gameInfo.black, black_stren, + basetime, increment); + } else { + sprintf(str, "%s (%d) vs. %s (%d) {%d %d}", + gameInfo.white, white_stren, gameInfo.black, black_stren, + basetime, increment); + } + DisplayTitle(str); + } + + + /* Display the board */ + if (!pausing) { + + if (appData.premove) + if (!gotPremove || + ((gameMode == IcsPlayingWhite) && (WhiteOnMove(currentMove))) || + ((gameMode == IcsPlayingBlack) && (!WhiteOnMove(currentMove)))) + ClearPremoveHighlights(); + + DrawPosition(FALSE, boards[currentMove]); + DisplayMove(moveNum - 1); + if (appData.ringBellAfterMoves && !ics_user_moved) + RingBell(); + } + + HistorySet(parseList, backwardMostMove, forwardMostMove, currentMove-1); +} + +void +GetMoveListEvent() +{ + char buf[MSG_SIZ]; + if (appData.icsActive && gameMode != IcsIdle && ics_gamenum > 0) { + ics_getting_history = H_REQUESTED; + sprintf(buf, "%smoves %d\n", ics_prefix, ics_gamenum); + SendToICS(buf); + } +} + +void +AnalysisPeriodicEvent(force) + int force; +{ + /* WB engine room */ + if (appData.AnalysisWindow && programStats.depth > 2) { + /* GUI disable send stat ? */ + if (!appData.engineStatLine) SendToProgram(".\n", &first); + /* don't support Stats on game ?*/ + if (supportStat == 0) { + /* call Display every sec for time and nodes */ + DisplayAnalysis(1,0); + } else { + /* GUI makes time ???? */ + /* at the moment: yes! */ + DisplayAnalysis(1,0); + } + } else if (appData.icsAnalyze && programStats.depth > 2) { + SendToProgram(".\n", &first); + DisplayAnalysis(1,0); + } else if (((programStats.ok_to_send == 0 || programStats.line_is_book) + && !force) || !appData.periodicUpdates) + return; + + /* Send . command to Crafty to collect stats */ + if (!appData.AnalysisWindow && (gameMode == AnalyzeMode || + gameMode == AnalyzeFile)) SendToProgram(".\n", &first); + + /* Don't send another until we get a response (this makes + us stop sending to old Crafty's which don't understand + the "." command (sending illegal cmds resets node count & time, + which looks bad)) */ + programStats.ok_to_send = 0; +} + +void +SendMoveToProgram(moveNum, cps) + int moveNum; + ChessProgramState *cps; +{ + char buf[MSG_SIZ]; + if (cps->useUsermove) { + SendToProgram("usermove ", cps); + } + if (cps->useSAN) { + char *space; + if ((space = strchr(parseList[moveNum], ' ')) != NULL) { + int len = space - parseList[moveNum]; + memcpy(buf, parseList[moveNum], len); + buf[len++] = '\n'; + buf[len] = NULLCHAR; + } else { + sprintf(buf, "%s\n", parseList[moveNum]); + } + SendToProgram(buf, cps); + } else { + SendToProgram(moveList[moveNum], cps); + } +} + +void +SendMoveToICS(moveType, fromX, fromY, toX, toY) + ChessMove moveType; + int fromX, fromY, toX, toY; +{ + char user_move[MSG_SIZ]; + + switch (moveType) { + default: + sprintf(user_move, "say Internal error; bad moveType %d (%d,%d-%d,%d)", + (int)moveType, fromX, fromY, toX, toY); + DisplayError(user_move + strlen("say "), 0); + break; + case WhiteKingSideCastle: + case BlackKingSideCastle: + case WhiteQueenSideCastleWild: + case BlackQueenSideCastleWild: + sprintf(user_move, "o-o\n"); + break; + case WhiteQueenSideCastle: + case BlackQueenSideCastle: + case WhiteKingSideCastleWild: + case BlackKingSideCastleWild: + sprintf(user_move, "o-o-o\n"); + break; + case WhitePromotionQueen: + case BlackPromotionQueen: + case WhitePromotionRook: + case BlackPromotionRook: + case WhitePromotionBishop: + case BlackPromotionBishop: + case WhitePromotionKnight: + case BlackPromotionKnight: + case WhitePromotionKing: + case BlackPromotionKing: + sprintf(user_move, "%c%c%c%c=%c\n", + 'a' + fromX, '1' + fromY, 'a' + toX, '1' + toY, + PieceToChar(PromoPiece(moveType))); + break; + case WhiteDrop: + case BlackDrop: + sprintf(user_move, "%c@%c%c\n", + ToUpper(PieceToChar((ChessSquare) fromX)), + 'a' + toX, '1' + toY); + break; + case NormalMove: + case WhiteCapturesEnPassant: + case BlackCapturesEnPassant: + case IllegalMove: /* could be a variant we don't quite understand */ + sprintf(user_move, "%c%c%c%c\n", + 'a' + fromX, '1' + fromY, 'a' + toX, '1' + toY); + break; + } + SendToICS(user_move); +} + +void +CoordsToComputerAlgebraic(rf, ff, rt, ft, promoChar, move) + int rf, ff, rt, ft; + char promoChar; + char move[7]; +{ + if (rf == DROP_RANK) { + sprintf(move, "%c@%c%c\n", + ToUpper(PieceToChar((ChessSquare) ff)), 'a' + ft, '1' + rt); + } else { + if (promoChar == 'x' || promoChar == NULLCHAR) { + sprintf(move, "%c%c%c%c\n", + 'a' + ff, '1' + rf, 'a' + ft, '1' + rt); + } else { + sprintf(move, "%c%c%c%c%c\n", + 'a' + ff, '1' + rf, 'a' + ft, '1' + rt, promoChar); + } + } +} + +void +ProcessICSInitScript(f) + FILE *f; +{ + char buf[MSG_SIZ]; + + while (fgets(buf, MSG_SIZ, f)) { + SendToICSDelayed(buf,(long)appData.msLoginDelay); + } + + fclose(f); +} + + +/* Parser for moves from gnuchess, ICS, or user typein box */ +Boolean +ParseOneMove(move, moveNum, moveType, fromX, fromY, toX, toY, promoChar) + char *move; + int moveNum; + ChessMove *moveType; + int *fromX, *fromY, *toX, *toY; + char *promoChar; +{ + *moveType = yylexstr(moveNum, move); + switch (*moveType) { + case WhitePromotionQueen: + case BlackPromotionQueen: + case WhitePromotionRook: + case BlackPromotionRook: + case WhitePromotionBishop: + case BlackPromotionBishop: + case WhitePromotionKnight: + case BlackPromotionKnight: + case WhitePromotionKing: + case BlackPromotionKing: + case NormalMove: + case WhiteCapturesEnPassant: + case BlackCapturesEnPassant: + case WhiteKingSideCastle: + case WhiteQueenSideCastle: + case BlackKingSideCastle: + case BlackQueenSideCastle: + case WhiteKingSideCastleWild: + case WhiteQueenSideCastleWild: + case BlackKingSideCastleWild: + case BlackQueenSideCastleWild: + case IllegalMove: /* bug or odd chess variant */ + *fromX = currentMoveString[0] - 'a'; + *fromY = currentMoveString[1] - '1'; + *toX = currentMoveString[2] - 'a'; + *toY = currentMoveString[3] - '1'; + *promoChar = currentMoveString[4]; + if (*fromX < 0 || *fromX > 7 || *fromY < 0 || *fromY > 7 || + *toX < 0 || *toX > 7 || *toY < 0 || *toY > 7) { + *fromX = *fromY = *toX = *toY = 0; + return FALSE; + } + if (appData.testLegality) { + return (*moveType != IllegalMove); + } else { + return !(fromX == fromY && toX == toY); + } + + case WhiteDrop: + case BlackDrop: + *fromX = *moveType == WhiteDrop ? + (int) CharToPiece(ToUpper(currentMoveString[0])) : + (int) CharToPiece(ToLower(currentMoveString[0])); + *fromY = DROP_RANK; + *toX = currentMoveString[2] - 'a'; + *toY = currentMoveString[3] - '1'; + *promoChar = NULLCHAR; + return TRUE; + + case AmbiguousMove: + case ImpossibleMove: + case (ChessMove) 0: /* end of file */ + case ElapsedTime: + case Comment: + case PGNTag: + case NAG: + case WhiteWins: + case BlackWins: + case GameIsDrawn: + default: + /* bug? */ + *fromX = *fromY = *toX = *toY = 0; + *promoChar = NULLCHAR; + return FALSE; + } +} + + +void +InitPosition(redraw) + int redraw; +{ + currentMove = forwardMostMove = backwardMostMove = 0; + switch (gameInfo.variant) { + default: + CopyBoard(boards[0], initialPosition); + break; + case VariantTwoKings: + CopyBoard(boards[0], twoKingsPosition); + startedFromSetupPosition = TRUE; + break; + case VariantWildCastle: + CopyBoard(boards[0], initialPosition); + /* !!?shuffle with kings guaranteed to be on d or e file */ + break; + case VariantNoCastle: + CopyBoard(boards[0], initialPosition); + /* !!?unconstrained back-rank shuffle */ + break; + case VariantFischeRandom: + CopyBoard(boards[0], initialPosition); + /* !!shuffle according to FR rules */ + break; + } + if (redraw) + DrawPosition(FALSE, boards[currentMove]); +} + +void +SendBoard(cps, moveNum) + ChessProgramState *cps; + int moveNum; +{ + char message[MSG_SIZ]; + + if (cps->useSetboard) { + char* fen = PositionToFEN(moveNum); + sprintf(message, "setboard %s\n", fen); + SendToProgram(message, cps); + free(fen); + + } else { + ChessSquare *bp; + int i, j; + /* Kludge to set black to move, avoiding the troublesome and now + * deprecated "black" command. + */ + if (!WhiteOnMove(moveNum)) SendToProgram("a2a3\n", cps); + + SendToProgram("edit\n", cps); + SendToProgram("#\n", cps); + for (i = BOARD_SIZE - 1; i >= 0; i--) { + bp = &boards[moveNum][i][0]; + for (j = 0; j < BOARD_SIZE; j++, bp++) { + if ((int) *bp < (int) BlackPawn) { + sprintf(message, "%c%c%c\n", PieceToChar(*bp), + 'a' + j, '1' + i); + SendToProgram(message, cps); + } + } + } + + SendToProgram("c\n", cps); + for (i = BOARD_SIZE - 1; i >= 0; i--) { + bp = &boards[moveNum][i][0]; + for (j = 0; j < BOARD_SIZE; j++, bp++) { + if (((int) *bp != (int) EmptySquare) + && ((int) *bp >= (int) BlackPawn)) { + sprintf(message, "%c%c%c\n", ToUpper(PieceToChar(*bp)), + 'a' + j, '1' + i); + SendToProgram(message, cps); + } + } + } + + SendToProgram(".\n", cps); + } +} + +int +IsPromotion(fromX, fromY, toX, toY) + int fromX, fromY, toX, toY; +{ + return gameMode != EditPosition && + fromX >=0 && fromY >= 0 && toX >= 0 && toY >= 0 && + ((boards[currentMove][fromY][fromX] == WhitePawn && toY == 7) || + (boards[currentMove][fromY][fromX] == BlackPawn && toY == 0)); +} + + +int +PieceForSquare (x, y) + int x; + int y; +{ + if (x < 0 || x >= BOARD_SIZE || y < 0 || y >= BOARD_SIZE) + return -1; + else + return boards[currentMove][y][x]; +} + +int +OKToStartUserMove(x, y) + int x, y; +{ + ChessSquare from_piece; + int white_piece; + + if (matchMode) return FALSE; + if (gameMode == EditPosition) return TRUE; + + if (x >= 0 && y >= 0) + from_piece = boards[currentMove][y][x]; + else + from_piece = EmptySquare; + + if (from_piece == EmptySquare) return FALSE; + + white_piece = (int)from_piece >= (int)WhitePawn && + (int)from_piece <= (int)WhiteKing; + + switch (gameMode) { + case PlayFromGameFile: + case AnalyzeFile: + case TwoMachinesPlay: + case EndOfGame: + return FALSE; + + case IcsObserving: + case IcsIdle: + return FALSE; + + case MachinePlaysWhite: + case IcsPlayingBlack: + if (appData.zippyPlay) return FALSE; + if (white_piece) { + DisplayMoveError("You are playing Black"); + return FALSE; + } + break; + + case MachinePlaysBlack: + case IcsPlayingWhite: + if (appData.zippyPlay) return FALSE; + if (!white_piece) { + DisplayMoveError("You are playing White"); + return FALSE; + } + break; + + case EditGame: + if (!white_piece && WhiteOnMove(currentMove)) { + DisplayMoveError("It is White's turn"); + return FALSE; + } + if (white_piece && !WhiteOnMove(currentMove)) { + DisplayMoveError("It is Black's turn"); + return FALSE; + } + if (cmailMsgLoaded && (currentMove < cmailOldMove)) { + /* Editing correspondence game history */ + /* Could disallow this or prompt for confirmation */ + cmailOldMove = -1; + } + if (currentMove < forwardMostMove) { + /* Discarding moves */ + /* Could prompt for confirmation here, + but I don't think that's such a good idea */ + forwardMostMove = currentMove; + } + break; + + case BeginningOfGame: + if (appData.icsActive) return FALSE; + if (!appData.noChessProgram) { + if (!white_piece) { + DisplayMoveError("You are playing White"); + return FALSE; + } + } + break; + + case Training: + if (!white_piece && WhiteOnMove(currentMove)) { + DisplayMoveError("It is White's turn"); + return FALSE; + } + if (white_piece && !WhiteOnMove(currentMove)) { + DisplayMoveError("It is Black's turn"); + return FALSE; + } + break; + + default: + case IcsExamining: + break; + } + if (currentMove != forwardMostMove && gameMode != AnalyzeMode + && gameMode != AnalyzeFile && gameMode != Training) { + DisplayMoveError("Displayed position is not current"); + return FALSE; + } + return TRUE; +} + +FILE *lastLoadGameFP = NULL, *lastLoadPositionFP = NULL; +int lastLoadGameNumber = 0, lastLoadPositionNumber = 0; +int lastLoadGameUseList = FALSE; +char lastLoadGameTitle[MSG_SIZ], lastLoadPositionTitle[MSG_SIZ]; +ChessMove lastLoadGameStart = (ChessMove) 0; + + +void +UserMoveEvent(fromX, fromY, toX, toY, promoChar) + int fromX, fromY, toX, toY; + int promoChar; +{ + ChessMove moveType; + + if (fromX < 0 || fromY < 0) return; + if ((fromX == toX) && (fromY == toY)) { + return; + } + + /* Check if the user is playing in turn. This is complicated because we + let the user "pick up" a piece before it is his turn. So the piece he + tried to pick up may have been captured by the time he puts it down! + Therefore we use the color the user is supposed to be playing in this + test, not the color of the piece that is currently on the starting + square---except in EditGame mode, where the user is playing both + sides; fortunately there the capture race can't happen. (It can + now happen in IcsExamining mode, but that's just too bad. The user + will get a somewhat confusing message in that case.) + */ + + switch (gameMode) { + case PlayFromGameFile: + case AnalyzeFile: + case TwoMachinesPlay: + case EndOfGame: + case IcsObserving: + case IcsIdle: + /* We switched into a game mode where moves are not accepted, + perhaps while the mouse button was down. */ + return; + + case MachinePlaysWhite: + /* User is moving for Black */ + if (WhiteOnMove(currentMove)) { + DisplayMoveError("It is White's turn"); + return; + } + break; + + case MachinePlaysBlack: + /* User is moving for White */ + if (!WhiteOnMove(currentMove)) { + DisplayMoveError("It is Black's turn"); + return; + } + break; + + case EditGame: + case IcsExamining: + case BeginningOfGame: + case AnalyzeMode: + case Training: + if ((int) boards[currentMove][fromY][fromX] >= (int) BlackPawn && + (int) boards[currentMove][fromY][fromX] <= (int) BlackKing) { + /* User is moving for Black */ + if (WhiteOnMove(currentMove)) { + DisplayMoveError("It is White's turn"); + return; + } + } else { + /* User is moving for White */ + if (!WhiteOnMove(currentMove)) { + DisplayMoveError("It is Black's turn"); + return; + } + } + break; + + case IcsPlayingBlack: + /* User is moving for Black */ + if (WhiteOnMove(currentMove)) { + if (!appData.premove) { + DisplayMoveError("It is White's turn"); + } else if (toX >= 0 && toY >= 0) { + premoveToX = toX; + premoveToY = toY; + premoveFromX = fromX; + premoveFromY = fromY; + premovePromoChar = promoChar; + gotPremove = 1; + if (appData.debugMode) + fprintf(debugFP, "Got premove: fromX %d," + "fromY %d, toX %d, toY %d\n", + fromX, fromY, toX, toY); + } + return; + } + break; + + case IcsPlayingWhite: + /* User is moving for White */ + if (!WhiteOnMove(currentMove)) { + if (!appData.premove) { + DisplayMoveError("It is Black's turn"); + } else if (toX >= 0 && toY >= 0) { + premoveToX = toX; + premoveToY = toY; + premoveFromX = fromX; + premoveFromY = fromY; + premovePromoChar = promoChar; + gotPremove = 1; + if (appData.debugMode) + fprintf(debugFP, "Got premove: fromX %d," + "fromY %d, toX %d, toY %d\n", + fromX, fromY, toX, toY); + } + return; + } + break; + + default: + break; + + case EditPosition: + if (toX == -2 || toY == -2) { + boards[0][fromY][fromX] = EmptySquare; + DrawPosition(FALSE, boards[currentMove]); + } else if (toX >= 0 && toY >= 0) { + boards[0][toY][toX] = boards[0][fromY][fromX]; + boards[0][fromY][fromX] = EmptySquare; + DrawPosition(FALSE, boards[currentMove]); + } + return; + } + + if (toX < 0 || toY < 0) return; + userOfferedDraw = FALSE; + + if (appData.testLegality) { + moveType = LegalityTest(boards[currentMove], PosFlags(currentMove), + EP_UNKNOWN, fromY, fromX, toY, toX, promoChar); + if (moveType == IllegalMove || moveType == ImpossibleMove) { + DisplayMoveError("Illegal move"); + return; + } + } else { + moveType = PromoCharToMoveType(WhiteOnMove(currentMove), promoChar); + } + + if (gameMode == Training) { + /* compare the move played on the board to the next move in the + * game. If they match, display the move and the opponent's response. + * If they don't match, display an error message. + */ + int saveAnimate; + Board testBoard; + CopyBoard(testBoard, boards[currentMove]); + ApplyMove(fromX, fromY, toX, toY, promoChar, testBoard); + + if (CompareBoards(testBoard, boards[currentMove+1])) { + ForwardInner(currentMove+1); + + /* Autoplay the opponent's response. + * if appData.animate was TRUE when Training mode was entered, + * the response will be animated. + */ + saveAnimate = appData.animate; + appData.animate = animateTraining; + ForwardInner(currentMove+1); + appData.animate = saveAnimate; + + /* check for the end of the game */ + if (currentMove >= forwardMostMove) { + gameMode = PlayFromGameFile; + ModeHighlight(); + SetTrainingModeOff(); + DisplayInformation("End of game"); + } + } else { + DisplayError("Incorrect move", 0); + } + return; + } + + FinishMove(moveType, fromX, fromY, toX, toY, promoChar); +} + +/* Common tail of UserMoveEvent and DropMenuEvent */ +void +FinishMove(moveType, fromX, fromY, toX, toY, promoChar) + ChessMove moveType; + int fromX, fromY, toX, toY; + /*char*/int promoChar; +{ + /* Ok, now we know that the move is good, so we can kill + the previous line in Analysis Mode */ + if (gameMode == AnalyzeMode && currentMove < forwardMostMove) { + forwardMostMove = currentMove; + } + + /* If we need the chess program but it's dead, restart it */ + ResurrectChessProgram(); + + /* A user move restarts a paused game*/ + if (pausing) + PauseEvent(); + + thinkOutput[0] = NULLCHAR; + + MakeMove(fromX, fromY, toX, toY, promoChar); /*updates forwardMostMove*/ + + if (gameMode == BeginningOfGame) { + if (appData.noChessProgram) { + gameMode = EditGame; + SetGameInfo(); + } else { + char buf[MSG_SIZ]; + gameMode = MachinePlaysBlack; + SetGameInfo(); + sprintf(buf, "%s vs. %s", gameInfo.white, gameInfo.black); + DisplayTitle(buf); + if (first.sendName) { + sprintf(buf, "name %s\n", gameInfo.white); + SendToProgram(buf, &first); + } + } + ModeHighlight(); + } + + /* Relay move to ICS or chess engine */ + if (appData.icsActive) { + if (gameMode == IcsPlayingWhite || gameMode == IcsPlayingBlack || + gameMode == IcsExamining) { + SendMoveToICS(moveType, fromX, fromY, toX, toY); + ics_user_moved = 1; + } + } else { + if (first.sendTime && (gameMode == BeginningOfGame || + gameMode == MachinePlaysWhite || + gameMode == MachinePlaysBlack)) { + SendTimeRemaining(&first, gameMode != MachinePlaysBlack); + } + + SendMoveToProgram(forwardMostMove-1, &first); + if (gameMode != EditGame && gameMode != PlayFromGameFile) { + first.maybeThinking = TRUE; + } + if (currentMove == cmailOldMove + 1) { + cmailMoveType[lastLoadGameNumber - 1] = CMAIL_MOVE; + } + } + + ShowMove(fromX, fromY, toX, toY); /*updates currentMove*/ + + switch (gameMode) { + case EditGame: + switch (MateTest(boards[currentMove], PosFlags(currentMove), + EP_UNKNOWN)) { + case MT_NONE: + case MT_CHECK: + break; + case MT_CHECKMATE: + if (WhiteOnMove(currentMove)) { + GameEnds(BlackWins, "Black mates", GE_PLAYER); + } else { + GameEnds(WhiteWins, "White mates", GE_PLAYER); + } + break; + case MT_STALEMATE: + GameEnds(GameIsDrawn, "Stalemate", GE_PLAYER); + break; + } + break; + + case MachinePlaysBlack: + case MachinePlaysWhite: + /* disable certain menu options while machine is thinking */ + SetMachineThinkingEnables(); + break; + + default: + break; + } +} + +void +HandleMachineMove(message, cps) + char *message; + ChessProgramState *cps; +{ + char machineMove[MSG_SIZ], buf1[MSG_SIZ*10], buf2[MSG_SIZ]; + char realname[MSG_SIZ]; + int fromX, fromY, toX, toY; + ChessMove moveType; + char promoChar; + char *p; + int machineWhite; + + /* + * Kludge to ignore BEL characters + */ + while (*message == '\007') message++; + + /* + * Look for book output + */ + if (cps == &first && bookRequested) { + if (message[0] == '\t' || message[0] == ' ') { + /* Part of the book output is here; append it */ + strcat(bookOutput, message); + strcat(bookOutput, " \n"); + return; + } else if (bookOutput[0] != NULLCHAR) { + /* All of book output has arrived; display it */ + char *p = bookOutput; + while (*p != NULLCHAR) { + if (*p == '\t') *p = ' '; + p++; + } + DisplayInformation(bookOutput); + bookRequested = FALSE; + /* Fall through to parse the current output */ + } + } + + /* + * Look for machine move. + */ + if ((sscanf(message, "%s %s %s", buf1, buf2, machineMove) == 3 && + strcmp(buf2, "...") == 0) || + (sscanf(message, "%s %s", buf1, machineMove) == 2 && + strcmp(buf1, "move") == 0)) { + /* Save last score befor move for zippy draw handling */ + if (appData.icsActive && appData.zippyDraw) { + // ZippyDraw(0, programStats.score, programStats.depth); + } + /* This method is only useful on engines that support ping */ + if (cps->lastPing != cps->lastPong) { + if (gameMode == BeginningOfGame) { + /* Extra move from before last new; ignore */ + if (appData.debugMode) { + fprintf(debugFP, "Ignoring extra move from %s\n", cps->which); + } + } else { + if (appData.debugMode) { + fprintf(debugFP, "Undoing extra move from %s, gameMode %d\n", + cps->which, gameMode); + } + SendToProgram("undo\n", cps); + } + return; + } + + switch (gameMode) { + case BeginningOfGame: + /* Extra move from before last reset; ignore */ + if (appData.debugMode) { + fprintf(debugFP, "Ignoring extra move from %s\n", cps->which); + } + return; + + case EndOfGame: + case IcsIdle: + default: + /* Extra move after we tried to stop. The mode test is + not a reliable way of detecting this problem, but it's + the best we can do on engines that don't support ping. + */ + if (appData.debugMode) { + fprintf(debugFP, "Undoing extra move from %s, gameMode %d\n", + cps->which, gameMode); + } + SendToProgram("undo\n", cps); + return; + + case MachinePlaysWhite: + case IcsPlayingWhite: + machineWhite = TRUE; + break; + + case MachinePlaysBlack: + case IcsPlayingBlack: + machineWhite = FALSE; + break; + + case TwoMachinesPlay: + machineWhite = (cps->twoMachinesColor[0] == 'w'); + break; + } + if (WhiteOnMove(forwardMostMove) != machineWhite) { + if (appData.debugMode) { + fprintf(debugFP, + "Ignoring move out of turn by %s, gameMode %d" + ", forwardMost %d\n", + cps->which, gameMode, forwardMostMove); + } + return; + } + + if (!ParseOneMove(machineMove, forwardMostMove, &moveType, + &fromX, &fromY, &toX, &toY, &promoChar)) { + /* Machine move could not be parsed; ignore it. */ + sprintf(buf1, "Illegal move \"%s\" from %s machine", + machineMove, cps->which); + /*!!if (appData.debugMode)*/ DisplayError(buf1, 0); + return; + } + + hintRequested = FALSE; + lastHint[0] = NULLCHAR; + bookRequested = FALSE; + /* Program may be pondering now */ + cps->maybeThinking = TRUE; + if (cps->sendTime == 2) cps->sendTime = 1; + if (cps->offeredDraw) cps->offeredDraw--; + +#if ZIPPY + if ((gameMode == IcsPlayingWhite || gameMode == IcsPlayingBlack) && + first.initDone) { + SendMoveToICS(moveType, fromX, fromY, toX, toY); + ics_user_moved = 1; + } +#endif + /* currentMoveString is set as a side-effect of ParseOneMove */ + strcpy(machineMove, currentMoveString); + strcat(machineMove, "\n"); + strcpy(moveList[forwardMostMove], machineMove); + + MakeMove(fromX, fromY, toX, toY, promoChar);/*updates forwardMostMove*/ + + if (gameMode == TwoMachinesPlay) { + if (cps->other->sendTime) { + SendTimeRemaining(cps->other, + cps->other->twoMachinesColor[0] == 'w'); + } + SendMoveToProgram(forwardMostMove-1, cps->other); + if (firstMove) { + firstMove = FALSE; + if (cps->other->useColors) { + SendToProgram(cps->other->twoMachinesColor, cps->other); + } + SendToProgram("go\n", cps->other); + } + cps->other->maybeThinking = TRUE; + } + + ShowMove(fromX, fromY, toX, toY); /*updates currentMove*/ + if (!pausing && appData.ringBellAfterMoves) { + RingBell(); + } + + /* + * Reenable menu items that were disabled while + * machine was thinking + */ + if (gameMode != TwoMachinesPlay) + SetUserThinkingEnables(); + return; + } + + + /* Set special modes for chess engines. Later something general + * could be added here; for now there is just one kludge feature, + * needed because Crafty 15.10 and earlier don't ignore SIGINT + * when "xboard" is given as an interactive command. + */ + if (strncmp(message, "kibitz Hello from Crafty", 24) == 0) { + cps->useSigint = FALSE; + cps->useSigterm = FALSE; + } + + /* + * Look for communication commands + */ + if (!strncmp(message, "telluser ", 9)) { + DisplayInformation(message + 9); + return; + } + if (!strncmp(message, "tellusererror ", 14)) { + DisplayError(message + 14, 0); + return; + } + if (!strncmp(message, "tellopponent ", 13)) { + if (appData.icsActive) { + if (loggedOn) { + sprintf(buf1, "%ssay %s\n", ics_prefix, message + 13); + SendToICS(buf1); + } + } else { + DisplayInformation(message + 13); + } + return; + } + if (!strncmp(message, "tellothers ", 11)) { + if (appData.icsActive) { + if (loggedOn) { + sprintf(buf1, "%swhisper %s\n", ics_prefix, message + 11); + SendToICS(buf1); + } + } + return; + } + if (!strncmp(message, "tellall ", 8)) { + if (appData.icsActive) { + /* daniel*/ + if (loggedOn && !appData.icsAnalyze) { + sprintf(buf1, "%skibitz %s\n", ics_prefix, message + 8); + SendToICS(buf1); + } + } else { + DisplayInformation(message + 8); + } + return; + } + if (strncmp(message, "warning", 7) == 0) { + /* Undocumented feature, use tellusererror in new code */ + DisplayError(message, 0); + return; + } + if (sscanf(message, "askuser %s %[^\n]", buf1, buf2) == 2) { + strcpy(realname, cps->tidy); + strcat(realname, " query"); + AskQuestion(realname, buf2, buf1, cps->pr); + return; + } + /* Commands from the engine directly to ICS. We don't allow these to be + * sent until we are logged on. Crafty kibitzes have been known to + * interfere with the login process. + */ + if (loggedOn) { + if (!strncmp(message, "tellics ", 8)) { + SendToICS(message + 8); + SendToICS("\n"); + return; + } + if (!strncmp(message, "tellicsnoalias ", 15)) { + SendToICS(ics_prefix); + SendToICS(message + 15); + SendToICS("\n"); + return; + } + /* The following are for backward compatibility only */ + if (!strncmp(message,"whisper",7) || !strncmp(message,"kibitz",6) || + !strncmp(message,"draw",4) || !strncmp(message,"tell",3)) { + SendToICS(ics_prefix); + SendToICS(message); + SendToICS("\n"); + return; + } + } + if (strncmp(message, "feature ", 8) == 0) { + ParseFeatures(message+8, cps); + } + if (sscanf(message, "pong %d", &cps->lastPong) == 1) { + return; + } + /* + * If the move is illegal, cancel it and redraw the board. + * Also deal with other error cases. Matching is rather loose + * here to accommodate engines written before the spec. + */ + if (strncmp(message + 1, "llegal move", 11) == 0 || + strncmp(message, "Error", 5) == 0) { + if (StrStr(message, "name") || + StrStr(message, "rating") || StrStr(message, "?") || + StrStr(message, "result") || StrStr(message, "board") || + StrStr(message, "bk") || StrStr(message, "computer") || + StrStr(message, "variant") || StrStr(message, "hint") || + StrStr(message, "random") || StrStr(message, "depth") || + StrStr(message, "accepted")) { + return; + } + if (StrStr(message, "protover")) { + /* Program is responding to input, so it's apparently done + initializing, and this error message indicates it is + protocol version 1. So we don't need to wait any longer + for it to initialize and send feature commands. */ + FeatureDone(cps, 1); + cps->protocolVersion = 1; + return; + } + cps->maybeThinking = FALSE; + + if (StrStr(message, "draw")) { + /* Program doesn't have "draw" command */ + cps->sendDrawOffers = 0; + return; + } + if (cps->sendTime != 1 && + (StrStr(message, "time") || StrStr(message, "otim"))) { + /* Program apparently doesn't have "time" or "otim" command */ + cps->sendTime = 0; + return; + } + if (StrStr(message, "analyze")) { + cps->analysisSupport = FALSE; + cps->analyzing = FALSE; + Reset(FALSE, TRUE); + sprintf(buf2, "%s does not support analysis", cps->tidy); + DisplayError(buf2, 0); + return; + } + if (StrStr(message, "st")) { + cps->stKludge = TRUE; + SendTimeControl(cps, movesPerSession, timeControl, + timeIncrement, appData.searchDepth, + searchTime); + return; + } + if (StrStr(message, "sd")) { + cps->sdKludge = TRUE; + SendTimeControl(cps, movesPerSession, timeControl, + timeIncrement, appData.searchDepth, + searchTime); + return; + } + if (!StrStr(message, "llegal")) return; + if (gameMode == BeginningOfGame || gameMode == EndOfGame || + gameMode == IcsIdle) return; + if (forwardMostMove <= backwardMostMove) return; + if (cps == &first && programStats.ok_to_send == 0) { + /* Bogus message from Crafty responding to "." This filtering + can miss some of the bad messages, but fortunately the bug + is fixed in current Crafty versions, so it doesn't matter. */ + return; + } + if (pausing) PauseEvent(); + if (gameMode == PlayFromGameFile) { + /* Stop reading this game file */ + gameMode = EditGame; + ModeHighlight(); + } + + + currentMove = --forwardMostMove; + DisplayMove(currentMove-1); /* before DisplayMoveError */ + SwitchClocks(); + DisplayBothClocks(); + sprintf(buf1, "Illegal move \"%s\" (rejected by %s chess program)", + parseList[currentMove], cps->which); + DisplayMoveError(buf1); + DrawPosition(FALSE, boards[currentMove]); + return; + } + if (strncmp(message, "time", 4) == 0 && StrStr(message, "Illegal")) { + /* Program has a broken "time" command that + outputs a string not ending in newline. + Don't use it. */ + cps->sendTime = 0; + } + + /* + * If chess program startup fails, exit with an error message. + * Attempts to recover here are futile. + */ + if ((StrStr(message, "unknown host") != NULL) + || (StrStr(message, "No remote directory") != NULL) + || (StrStr(message, "not found") != NULL) + || (StrStr(message, "No such file") != NULL) + || (StrStr(message, "can't alloc") != NULL) + || (StrStr(message, "Permission denied") != NULL)) { + + cps->maybeThinking = FALSE; + sprintf(buf1, "Failed to start %s chess program %s on %s: %s\n", + cps->which, cps->program, cps->host, message); + RemoveInputSource(cps->isr); + DisplayFatalError(buf1, 0, 1); + return; + } + + /* + * Look for hint output + */ + if (sscanf(message, "Hint: %s", buf1) == 1) { + switch (gameMode) { + case IcsPlayingWhite: + case IcsPlayingBlack: + case MachinePlaysWhite: + case MachinePlaysBlack: + strcpy(programStats.ponderMove, buf1); + break; + default: + programStats.ponderMove[0] = NULLCHAR; + break; + } + if (cps == &first && hintRequested) { + hintRequested = FALSE; + if (ParseOneMove(buf1, forwardMostMove, &moveType, + &fromX, &fromY, &toX, &toY, &promoChar)) { + (void) CoordsToAlgebraic(boards[forwardMostMove], + PosFlags(forwardMostMove), EP_UNKNOWN, + fromY, fromX, toY, toX, promoChar, buf1); + sprintf(buf2, "Hint: %s", buf1); + DisplayInformation(buf2); + } else { + /* Hint move could not be parsed!? */ + sprintf(buf2, + "Illegal hint move \"%s\"\nfrom %s chess program", + buf1, cps->which); + DisplayError(buf2, 0); + } + } else { + /* Copy ponder move */ + strcpy(lastHint, buf1); + } + return; + } + + /* + * Ignore other messages if game is not in progress + */ + if (gameMode == BeginningOfGame || gameMode == EndOfGame || + gameMode == IcsIdle || cps->lastPing != cps->lastPong) return; + + /* + * look for win, lose, draw, or draw offer + */ + if (strncmp(message, "1-0", 3) == 0) { + char *p, *q, *r = ""; + p = strchr(message, '{'); + if (p) { + q = strchr(p, '}'); + if (q) { + *q = NULLCHAR; + r = p + 1; + } + } + GameEnds(WhiteWins, r, GE_ENGINE); + return; + } else if (strncmp(message, "0-1", 3) == 0) { + char *p, *q, *r = ""; + p = strchr(message, '{'); + if (p) { + q = strchr(p, '}'); + if (q) { + *q = NULLCHAR; + r = p + 1; + } + } + /* Kludge for Arasan 4.1 bug */ + if (strcmp(r, "Black resigns") == 0) { + GameEnds(WhiteWins, r, GE_ENGINE); + return; + } + GameEnds(BlackWins, r, GE_ENGINE); + return; + } else if (strncmp(message, "1/2", 3) == 0) { + char *p, *q, *r = ""; + p = strchr(message, '{'); + if (p) { + q = strchr(p, '}'); + if (q) { + *q = NULLCHAR; + r = p + 1; + } + } + GameEnds(GameIsDrawn, r, GE_ENGINE); + return; + + } else if (strncmp(message, "White resign", 12) == 0) { + GameEnds(BlackWins, "White resigns", GE_ENGINE); + return; + } else if (strncmp(message, "Black resign", 12) == 0) { + GameEnds(WhiteWins, "Black resigns", GE_ENGINE); + return; + } else if (strncmp(message, "White", 5) == 0 && + message[5] != '(' && + StrStr(message, "Black") == NULL) { + GameEnds(WhiteWins, "White mates", GE_ENGINE); + return; + } else if (strncmp(message, "Black", 5) == 0 && + message[5] != '(') { + GameEnds(BlackWins, "Black mates", GE_ENGINE); + return; + } else if (strcmp(message, "resign") == 0 || + strcmp(message, "computer resigns") == 0) { + switch (gameMode) { + case MachinePlaysBlack: + case IcsPlayingBlack: + GameEnds(WhiteWins, "Black resigns", GE_ENGINE); + break; + case MachinePlaysWhite: + case IcsPlayingWhite: + GameEnds(BlackWins, "White resigns", GE_ENGINE); + break; + case TwoMachinesPlay: + if (cps->twoMachinesColor[0] == 'w') + GameEnds(BlackWins, "White resigns", GE_ENGINE); + else + GameEnds(WhiteWins, "Black resigns", GE_ENGINE); + break; + default: + /* can't happen */ + break; + } + return; + } else if (strncmp(message, "opponent mates", 14) == 0) { + switch (gameMode) { + case MachinePlaysBlack: + case IcsPlayingBlack: + GameEnds(WhiteWins, "White mates", GE_ENGINE); + break; + case MachinePlaysWhite: + case IcsPlayingWhite: + GameEnds(BlackWins, "Black mates", GE_ENGINE); + break; + case TwoMachinesPlay: + if (cps->twoMachinesColor[0] == 'w') + GameEnds(BlackWins, "Black mates", GE_ENGINE); + else + GameEnds(WhiteWins, "White mates", GE_ENGINE); + break; + default: + /* can't happen */ + break; + } + return; + } else if (strncmp(message, "computer mates", 14) == 0) { + switch (gameMode) { + case MachinePlaysBlack: + case IcsPlayingBlack: + GameEnds(BlackWins, "Black mates", GE_ENGINE); + break; + case MachinePlaysWhite: + case IcsPlayingWhite: + GameEnds(WhiteWins, "White mates", GE_ENGINE); + break; + case TwoMachinesPlay: + if (cps->twoMachinesColor[0] == 'w') + GameEnds(WhiteWins, "White mates", GE_ENGINE); + else + GameEnds(BlackWins, "Black mates", GE_ENGINE); + break; + default: + /* can't happen */ + break; + } + return; + } else if (strncmp(message, "checkmate", 9) == 0) { + if (WhiteOnMove(forwardMostMove)) { + GameEnds(BlackWins, "Black mates", GE_ENGINE); + } else { + GameEnds(WhiteWins, "White mates", GE_ENGINE); + } + return; + } else if (strstr(message, "Draw") != NULL || + strstr(message, "game is a draw") != NULL) { + GameEnds(GameIsDrawn, "Draw", GE_ENGINE); + return; + } else if (strstr(message, "offer") != NULL && + strstr(message, "draw") != NULL) { +#if ZIPPY + if (appData.zippyPlay && first.initDone) { + /* Relay offer to ICS */ + SendToICS(ics_prefix); + SendToICS("draw\n"); + } +#endif + cps->offeredDraw = 2; /* valid until this engine moves twice */ + if (gameMode == TwoMachinesPlay) { + if (cps->other->offeredDraw) { + GameEnds(GameIsDrawn, "Draw agreed", GE_XBOARD); + } else { + if (cps->other->sendDrawOffers) { + SendToProgram("draw\n", cps->other); + } + } + } else if (gameMode == MachinePlaysWhite || + gameMode == MachinePlaysBlack) { + if (userOfferedDraw) { + DisplayInformation("Machine accepts your draw offer"); + GameEnds(GameIsDrawn, "Draw agreed", GE_XBOARD); + } else { + DisplayInformation("Machine offers a draw\nSelect Action / Draw to agree"); + } + } + } + + + /* + * Look for thinking output + */ + /* Using icsAnalyze for future function */ + if (appData.showThinking || appData.icsAnalyze) { + int plylev, mvleft, mvtot, curscore, time; + char mvname[MOVE_LEN]; + unsigned long nodes; + char plyext; + int ignore = FALSE; + prefixHint = FALSE; + mvname[0] = NULLCHAR; + + /* reset thinkoutput */ + thinkOutput[0] = NULLCHAR; + + switch (gameMode) { + case MachinePlaysBlack: + case IcsPlayingBlack: + if (WhiteOnMove(forwardMostMove)) prefixHint = TRUE; + break; + case MachinePlaysWhite: + case IcsPlayingWhite: + if (!WhiteOnMove(forwardMostMove)) prefixHint = TRUE; + break; + case AnalyzeMode: + case AnalyzeFile: + break; + case IcsObserving: + ignore = FALSE; + break; + case TwoMachinesPlay: + if ((cps->twoMachinesColor[0] == 'w') != + WhiteOnMove(forwardMostMove)) { + ignore = TRUE; + } + break; + default: + ignore = TRUE; + break; + } + + if (!ignore) { + /* reset ponder move display */ + buf1[0] = NULLCHAR; + if (sscanf(message, "%d%c %d %d %lu %[^\n]\n", + &plylev, &plyext, &curscore, &time, &nodes, buf1) >= 5) { + + if (plyext != ' ' && plyext != '\t') { + time *= 100; + } + programStats.depth = plylev; + programStats.nodes = nodes; + programStats.time = time; + programStats.score = curscore; + programStats.got_only_move = 0; + + /* Buffer overflow protection */ + if (buf1[0] != NULLCHAR) { + if (strlen(buf1) >= MSG_SIZ) { + if (appData.debugMode) fprintf(debugFP, "PV is to long. I use the first %d bytes. \n", MSG_SIZ); + strncpy(programStats.movelist, buf1, MSG_SIZ); + } else { + strcpy(programStats.movelist, buf1); + } + } else { + sprintf(programStats.movelist, " no PV \n"); + if (appData.debugMode) fprintf(debugFP, "I found no PV \n"); + } + + if (programStats.seen_stat) { + programStats.ok_to_send = 1; + } + + if (strchr(programStats.movelist, '(') != NULL) { + programStats.line_is_book = 1; + programStats.nr_moves = 0; + programStats.moves_left = 0; + } else { + programStats.line_is_book = 0; + } + + sprintf(thinkOutput, "%d %c%+.2f %s%s%s", + plylev, + (gameMode == TwoMachinesPlay ? + ToUpper(cps->twoMachinesColor[0]) : ' '), + ((double) programStats.score) / 100.0, + prefixHint ? lastHint : "", + prefixHint ? " " : "", buf1); + /* Using icsAnalyze for future function */ + if (currentMove == forwardMostMove || gameMode==AnalyzeMode || + appData.icsAnalyzeWindow || appData.AnalysisWindow || + gameMode == AnalyzeFile) { + if (appData.icsAnalyzeWindow || + appData.AnalysisWindow) DisplayAnalysis(0,1); + DisplayMove(currentMove - 1); + } else { + if (appData.showThinking) DisplayMove(currentMove - 1); + } + return; + + } else if ((p=StrStr(message, "(only move)")) != NULL) { + /* crafty (9.25+) says "(only move) " + * if there is only 1 legal move + */ + sscanf(p, "(only move) %s", buf1); + sprintf(thinkOutput, "%s (only move)", buf1); + sprintf(programStats.movelist, "%s (only move)", buf1); + programStats.depth = 2; /* don't use 0 or 1 it's book depth */ + programStats.nr_moves = 1; + programStats.moves_left = 1; + programStats.nodes = 1; + programStats.time = 1; + programStats.got_only_move = 1; + + /* Not really, but we also use this member to + mean "line isn't going to change" (Crafty + isn't searching, so stats won't change) */ + programStats.line_is_book = 1; + if (currentMove == forwardMostMove || gameMode==AnalyzeMode || + appData.icsAnalyzeWindow || appData.AnalysisWindow || + gameMode == AnalyzeFile) { + if (appData.icsAnalyzeWindow || + appData.AnalysisWindow) DisplayAnalysis(0,1); + DisplayMove(currentMove - 1); + } else { + if (appData.showThinking) DisplayMove(currentMove - 1); + } + return; + + } else if (sscanf(message,"stat01: %d %lu %d %d %d %s", + &time, &nodes, &plylev, &mvleft, + &mvtot, mvname) >= 5) { + /* The stat01: line is from Crafty (9.29+) in response + to the "." command */ + programStats.seen_stat = 1; + /* for display engine room */ + supportStat = 1; + cps->maybeThinking = TRUE; + + if (programStats.got_only_move || !appData.periodicUpdates) return; + + programStats.depth = plylev; + programStats.time = time; + programStats.nodes = nodes; + programStats.moves_left = mvleft; + programStats.nr_moves = mvtot; + strcpy(programStats.move_name, mvname); + programStats.ok_to_send = 1; + if (appData.icsAnalyzeWindow || + appData.AnalysisWindow) DisplayAnalysis(0,0); + return; + + } else if (strncmp(message,"++",2) == 0) { + /* Crafty 9.29+ outputs this */ + programStats.got_fail = 2; + return; + + } else if (strncmp(message,"--",2) == 0) { + /* Crafty 9.29+ outputs this */ + programStats.got_fail = 1; + return; + + } else if (thinkOutput[0] != NULLCHAR && + strncmp(message, " ", 4) == 0) { + p = message; + while (*p && *p == ' ') p++; + strcat(thinkOutput, " "); + strcat(thinkOutput, p); + strcat(programStats.movelist, " "); + strcat(programStats.movelist, p); + + if (currentMove == forwardMostMove || gameMode==AnalyzeMode || + appData.icsAnalyzeWindow || appData.AnalysisWindow || + gameMode == AnalyzeFile) { + if (appData.icsAnalyzeWindow || + appData.AnalysisWindow) DisplayAnalysis(0,1); + DisplayMove(currentMove - 1); + } else { + if (appData.showThinking) DisplayMove(currentMove - 1); + } + return; + + } + } + } +} + + +/* Parse a game score from the character string "game", and + record it as the history of the current game. The game + score is NOT assumed to start from the standard position. + The display is not updated in any way. + */ +void +ParseGameHistory(game) + char *game; +{ + ChessMove moveType; + int fromX, fromY, toX, toY, boardIndex; + char promoChar; + char *p, *q; + char buf[MSG_SIZ]; + + if (appData.debugMode) + fprintf(debugFP, "Parsing game history: %s\n", game); + + if (gameInfo.event == NULL) gameInfo.event = StrSave("ICS game"); + gameInfo.site = StrSave(appData.icsHost); + gameInfo.date = PGNDate(); + gameInfo.round = StrSave("-"); + + /* Parse out names of players */ + while (*game == ' ') game++; + p = buf; + while (*game != ' ') *p++ = *game++; + *p = NULLCHAR; + gameInfo.white = StrSave(buf); + while (*game == ' ') game++; + p = buf; + while (*game != ' ' && *game != '\n') *p++ = *game++; + *p = NULLCHAR; + gameInfo.black = StrSave(buf); + + /* Parse moves */ + boardIndex = blackPlaysFirst ? 1 : 0; + yynewstr(game); + for (;;) { + yyboardindex = boardIndex; + moveType = (ChessMove) yylex(); + switch (moveType) { + case WhitePromotionQueen: + case BlackPromotionQueen: + case WhitePromotionRook: + case BlackPromotionRook: + case WhitePromotionBishop: + case BlackPromotionBishop: + case WhitePromotionKnight: + case BlackPromotionKnight: + case WhitePromotionKing: + case BlackPromotionKing: + case NormalMove: + case WhiteCapturesEnPassant: + case BlackCapturesEnPassant: + case WhiteKingSideCastle: + case WhiteQueenSideCastle: + case BlackKingSideCastle: + case BlackQueenSideCastle: + case WhiteKingSideCastleWild: + case WhiteQueenSideCastleWild: + case BlackKingSideCastleWild: + case BlackQueenSideCastleWild: + case IllegalMove: /* maybe suicide chess, etc. */ + fromX = currentMoveString[0] - 'a'; + fromY = currentMoveString[1] - '1'; + toX = currentMoveString[2] - 'a'; + toY = currentMoveString[3] - '1'; + promoChar = currentMoveString[4]; + break; + case WhiteDrop: + case BlackDrop: + fromX = moveType == WhiteDrop ? + (int) CharToPiece(ToUpper(currentMoveString[0])) : + (int) CharToPiece(ToLower(currentMoveString[0])); + fromY = DROP_RANK; + toX = currentMoveString[2] - 'a'; + toY = currentMoveString[3] - '1'; + promoChar = NULLCHAR; + break; + case AmbiguousMove: + /* bug? */ + sprintf(buf, "Ambiguous move in ICS output: \"%s\"", yy_text); + DisplayError(buf, 0); + return; + case ImpossibleMove: + /* bug? */ + sprintf(buf, "Illegal move in ICS output: \"%s\"", yy_text); + DisplayError(buf, 0); + return; + case (ChessMove) 0: /* end of file */ + if (boardIndex < backwardMostMove) { + /* Oops, gap. How did that happen? */ + DisplayError("Gap in move list", 0); + return; + } + backwardMostMove = blackPlaysFirst ? 1 : 0; + if (boardIndex > forwardMostMove) { + forwardMostMove = boardIndex; + } + return; + case ElapsedTime: + if (boardIndex > 0) { + strcat(parseList[boardIndex-1], " "); + strcat(parseList[boardIndex-1], yy_text); + } + continue; + case Comment: + case PGNTag: + case NAG: + default: + /* ignore */ + continue; + case WhiteWins: + case BlackWins: + case GameIsDrawn: + case GameUnfinished: + if (gameMode == IcsExamining) { + if (boardIndex < backwardMostMove) { + /* Oops, gap. How did that happen? */ + return; + } + backwardMostMove = blackPlaysFirst ? 1 : 0; + return; + } + gameInfo.result = moveType; + p = strchr(yy_text, '{'); + if (p == NULL) p = strchr(yy_text, '('); + if (p == NULL) { + p = yy_text; + if (p[0] == '0' || p[0] == '1' || p[0] == '*') p = ""; + } else { + q = strchr(p, *p == '{' ? '}' : ')'); + if (q != NULL) *q = NULLCHAR; + p++; + } + gameInfo.resultDetails = StrSave(p); + continue; + } + if (boardIndex >= forwardMostMove && + !(gameMode == IcsObserving && ics_gamenum == -1)) { + backwardMostMove = blackPlaysFirst ? 1 : 0; + return; + } + (void) CoordsToAlgebraic(boards[boardIndex], PosFlags(boardIndex), + EP_UNKNOWN, fromY, fromX, toY, toX, promoChar, + parseList[boardIndex]); + CopyBoard(boards[boardIndex + 1], boards[boardIndex]); + /* currentMoveString is set as a side-effect of yylex */ + strcpy(moveList[boardIndex], currentMoveString); + strcat(moveList[boardIndex], "\n"); + boardIndex++; + ApplyMove(fromX, fromY, toX, toY, promoChar, boards[boardIndex]); + switch (MateTest(boards[boardIndex], + PosFlags(boardIndex), EP_UNKNOWN)) { + case MT_NONE: + case MT_STALEMATE: + default: + break; + case MT_CHECK: + strcat(parseList[boardIndex - 1], "+"); + break; + case MT_CHECKMATE: + strcat(parseList[boardIndex - 1], "#"); + break; + } + } +} + + +/* Apply a move to the given board */ +void +ApplyMove(fromX, fromY, toX, toY, promoChar, board) + int fromX, fromY, toX, toY; + int promoChar; + Board board; +{ + ChessSquare captured = board[toY][toX]; + if (fromY == DROP_RANK) { + /* must be first */ + board[toY][toX] = (ChessSquare) fromX; + } else if (fromX == toX && fromY == toY) { + return; + } else if (fromY == 0 && fromX == 4 + && board[fromY][fromX] == WhiteKing + && toY == 0 && toX == 6) { + board[fromY][fromX] = EmptySquare; + board[toY][toX] = WhiteKing; + board[fromY][7] = EmptySquare; + board[toY][5] = WhiteRook; + } else if (fromY == 0 && fromX == 4 + && board[fromY][fromX] == WhiteKing + && toY == 0 && toX == 2) { + board[fromY][fromX] = EmptySquare; + board[toY][toX] = WhiteKing; + board[fromY][0] = EmptySquare; + board[toY][3] = WhiteRook; + } else if (fromY == 0 && fromX == 3 + && board[fromY][fromX] == WhiteKing + && toY == 0 && toX == 5) { + board[fromY][fromX] = EmptySquare; + board[toY][toX] = WhiteKing; + board[fromY][7] = EmptySquare; + board[toY][4] = WhiteRook; + } else if (fromY == 0 && fromX == 3 + && board[fromY][fromX] == WhiteKing + && toY == 0 && toX == 1) { + board[fromY][fromX] = EmptySquare; + board[toY][toX] = WhiteKing; + board[fromY][0] = EmptySquare; + board[toY][2] = WhiteRook; + } else if (board[fromY][fromX] == WhitePawn + && toY == 7) { + /* white pawn promotion */ + board[7][toX] = CharToPiece(ToUpper(promoChar)); + if (board[7][toX] == EmptySquare) { + board[7][toX] = WhiteQueen; + } + board[fromY][fromX] = EmptySquare; + } else if ((fromY == 4) + && (toX != fromX) + && (board[fromY][fromX] == WhitePawn) + && (board[toY][toX] == EmptySquare)) { + board[fromY][fromX] = EmptySquare; + board[toY][toX] = WhitePawn; + captured = board[toY - 1][toX]; + board[toY - 1][toX] = EmptySquare; + } else if (fromY == 7 && fromX == 4 + && board[fromY][fromX] == BlackKing + && toY == 7 && toX == 6) { + board[fromY][fromX] = EmptySquare; + board[toY][toX] = BlackKing; + board[fromY][7] = EmptySquare; + board[toY][5] = BlackRook; + } else if (fromY == 7 && fromX == 4 + && board[fromY][fromX] == BlackKing + && toY == 7 && toX == 2) { + board[fromY][fromX] = EmptySquare; + board[toY][toX] = BlackKing; + board[fromY][0] = EmptySquare; + board[toY][3] = BlackRook; + } else if (fromY == 7 && fromX == 3 + && board[fromY][fromX] == BlackKing + && toY == 7 && toX == 5) { + board[fromY][fromX] = EmptySquare; + board[toY][toX] = BlackKing; + board[fromY][7] = EmptySquare; + board[toY][4] = BlackRook; + } else if (fromY == 7 && fromX == 3 + && board[fromY][fromX] == BlackKing + && toY == 7 && toX == 1) { + board[fromY][fromX] = EmptySquare; + board[toY][toX] = BlackKing; + board[fromY][0] = EmptySquare; + board[toY][2] = BlackRook; + } else if (board[fromY][fromX] == BlackPawn + && toY == 0) { + /* black pawn promotion */ + board[0][toX] = CharToPiece(ToLower(promoChar)); + if (board[0][toX] == EmptySquare) { + board[0][toX] = BlackQueen; + } + board[fromY][fromX] = EmptySquare; + } else if ((fromY == 3) + && (toX != fromX) + && (board[fromY][fromX] == BlackPawn) + && (board[toY][toX] == EmptySquare)) { + board[fromY][fromX] = EmptySquare; + board[toY][toX] = BlackPawn; + captured = board[toY + 1][toX]; + board[toY + 1][toX] = EmptySquare; + } else { + board[toY][toX] = board[fromY][fromX]; + board[fromY][fromX] = EmptySquare; + } + if (gameInfo.variant == VariantCrazyhouse) { +#if 0 + /* !!A lot more code needs to be written to support holdings */ + if (fromY == DROP_RANK) { + /* Delete from holdings */ + if (holdings[(int) fromX] > 0) holdings[(int) fromX]--; + } + if (captured != EmptySquare) { + /* Add to holdings */ + if (captured < BlackPawn) { + holdings[(int)captured - (int)BlackPawn + (int)WhitePawn]++; + } else { + holdings[(int)captured - (int)WhitePawn + (int)BlackPawn]++; + } + } +#endif + } else if (gameInfo.variant == VariantAtomic) { + if (captured != EmptySquare) { + int y, x; + for (y = toY-1; y <= toY+1; y++) { + for (x = toX-1; x <= toX+1; x++) { + if (y >= 0 && y <= 7 && x >= 0 && x <= 7 && + board[y][x] != WhitePawn && board[y][x] != BlackPawn) { + board[y][x] = EmptySquare; + } + } + } + board[toY][toX] = EmptySquare; + } + } +} + +/* Updates forwardMostMove */ +void +MakeMove(fromX, fromY, toX, toY, promoChar) + int fromX, fromY, toX, toY; + int promoChar; +{ + forwardMostMove++; + if (forwardMostMove >= MAX_MOVES) { + DisplayFatalError("Game too long; increase MAX_MOVES and recompile", + 0, 1); + return; + } + SwitchClocks(); + timeRemaining[0][forwardMostMove] = whiteTimeRemaining; + timeRemaining[1][forwardMostMove] = blackTimeRemaining; + if (commentList[forwardMostMove] != NULL) { + free(commentList[forwardMostMove]); + commentList[forwardMostMove] = NULL; + } + CopyBoard(boards[forwardMostMove], boards[forwardMostMove - 1]); + ApplyMove(fromX, fromY, toX, toY, promoChar, boards[forwardMostMove]); + gameInfo.result = GameUnfinished; + if (gameInfo.resultDetails != NULL) { + free(gameInfo.resultDetails); + gameInfo.resultDetails = NULL; + } + CoordsToComputerAlgebraic(fromY, fromX, toY, toX, promoChar, + moveList[forwardMostMove - 1]); + (void) CoordsToAlgebraic(boards[forwardMostMove - 1], + PosFlags(forwardMostMove - 1), EP_UNKNOWN, + fromY, fromX, toY, toX, promoChar, + parseList[forwardMostMove - 1]); + switch (MateTest(boards[forwardMostMove], + PosFlags(forwardMostMove), EP_UNKNOWN)){ + case MT_NONE: + case MT_STALEMATE: + default: + break; + case MT_CHECK: + strcat(parseList[forwardMostMove - 1], "+"); + break; + case MT_CHECKMATE: + strcat(parseList[forwardMostMove - 1], "#"); + break; + } +} + +/* Updates currentMove if not pausing */ +void +ShowMove(fromX, fromY, toX, toY) +{ + int instant = (gameMode == PlayFromGameFile) ? + (matchMode || (appData.timeDelay == 0 && !pausing)) : pausing; + if (!pausing || gameMode == PlayFromGameFile || gameMode == AnalyzeFile) { + if (!instant) { + if (forwardMostMove == currentMove + 1) { + AnimateMove(boards[forwardMostMove - 1], + fromX, fromY, toX, toY); + } + if (appData.highlightLastMove) { + SetHighlights(fromX, fromY, toX, toY); + } + } + currentMove = forwardMostMove; + } + + if (instant) return; + DisplayMove(currentMove - 1); + DrawPosition(FALSE, boards[currentMove]); + DisplayBothClocks(); + HistorySet(parseList,backwardMostMove,forwardMostMove,currentMove-1); +} + + +void +InitChessProgram(cps) + ChessProgramState *cps; +{ + char buf[MSG_SIZ]; + if (appData.noChessProgram) return; + hintRequested = FALSE; + bookRequested = FALSE; + SendToProgram(cps->initString, cps); + if (gameInfo.variant != VariantNormal && + gameInfo.variant != VariantLoadable) { + char *v = VariantName(gameInfo.variant); + if (StrStr(cps->variants, v) == NULL) { + sprintf(buf, "Variant %s not supported by %s", v, cps->tidy); + DisplayFatalError(buf, 0, 1); + return; + } + sprintf(buf, "variant %s\n", VariantName(gameInfo.variant)); + SendToProgram(buf, cps); + } + if (cps->sendICS) { + sprintf(buf, "ics %s\n", appData.icsActive ? appData.icsHost : "-"); + SendToProgram(buf, cps); + } + cps->maybeThinking = FALSE; + cps->offeredDraw = 0; + if (!appData.icsActive) { + SendTimeControl(cps, movesPerSession, timeControl, + timeIncrement, appData.searchDepth, + searchTime); + } + if (appData.showThinking) { + SendToProgram("post\n", cps); + } + SendToProgram("hard\n", cps); + if (!appData.ponderNextMove) { + /* Warning: "easy" is a toggle in GNU Chess, so don't send + it without being sure what state we are in first. "hard" + is not a toggle, so that one is OK. + */ + SendToProgram("easy\n", cps); + } + if (cps->usePing) { + sprintf(buf, "ping %d\n", ++cps->lastPing); + SendToProgram(buf, cps); + } + cps->initDone = TRUE; +} + + +void +StartChessProgram(cps) + ChessProgramState *cps; +{ + char buf[MSG_SIZ]; + int err; + + if (appData.noChessProgram) return; + cps->initDone = FALSE; + + if (strcmp(cps->host, "localhost") == 0) { + err = StartChildProcess(cps->program, cps->dir, &cps->pr); + } else if (*appData.remoteShell == NULLCHAR) { + err = OpenRcmd(cps->host, appData.remoteUser, cps->program, &cps->pr); + } else { + if (*appData.remoteUser == NULLCHAR) { + sprintf(buf, "%s %s %s", appData.remoteShell, cps->host, + cps->program); + } else { + sprintf(buf, "%s %s -l %s %s", appData.remoteShell, + cps->host, appData.remoteUser, cps->program); + } + err = StartChildProcess(buf, "", &cps->pr); + } + + if (err != 0) { + sprintf(buf, "Startup failure on '%s'", cps->program); + DisplayFatalError(buf, err, 1); + cps->pr = NoProc; + cps->isr = NULL; + return; + } + + cps->isr = AddInputSource(cps->pr, TRUE, ReceiveFromProgram, cps); + if (cps->protocolVersion > 1) { + sprintf(buf, "xboard\nprotover %d\n", cps->protocolVersion); + SendToProgram(buf, cps); + } else { + SendToProgram("xboard\n", cps); + } +} + + +void +TwoMachinesEventIfReady P((void)) +{ + if (first.lastPing != first.lastPong) { + DisplayMessage("", "Waiting for first chess program"); + ScheduleDelayedEvent(TwoMachinesEventIfReady, 1000); + return; + } + if (second.lastPing != second.lastPong) { + DisplayMessage("", "Waiting for second chess program"); + ScheduleDelayedEvent(TwoMachinesEventIfReady, 1000); + return; + } + ThawUI(); + TwoMachinesEvent(); +} + +void +NextMatchGame P((void)) +{ + Reset(FALSE, TRUE); + if (*appData.loadGameFile != NULLCHAR) { + LoadGameFromFile(appData.loadGameFile, + appData.loadGameIndex, + appData.loadGameFile, FALSE); + } else if (*appData.loadPositionFile != NULLCHAR) { + LoadPositionFromFile(appData.loadPositionFile, + appData.loadPositionIndex, + appData.loadPositionFile); + } + TwoMachinesEventIfReady(); +} + +void +GameEnds(result, resultDetails, whosays) + ChessMove result; + char *resultDetails; + int whosays; +{ + GameMode nextGameMode; + int isIcsGame; + + if (appData.debugMode) { + fprintf(debugFP, "GameEnds(%d, %s, %d)\n", + result, resultDetails ? resultDetails : "(null)", whosays); + } + + if (appData.icsAnalyze && gameMode == IcsObserving) ResetIcsQueue(ics_gamenum); + + if (appData.icsActive && whosays == GE_ENGINE) { + /* If we are playing on ICS, the server decides when the + game is over, but the engine can offer to draw, claim + a draw, or resign. + */ +#if ZIPPY + if (appData.zippyPlay && first.initDone) { + if (result == GameIsDrawn) { + /* In case draw still needs to be claimed */ + SendToICS(ics_prefix); + SendToICS("draw\n"); + } else if (StrCaseStr(resultDetails, "resign")) { + SendToICS(ics_prefix); + SendToICS("resign\n"); + } + } +#endif + return; + } + + /* If we're loading the game from a file, stop */ + if (whosays == GE_FILE) { + (void) StopLoadGameTimer(); + gameFileFP = NULL; + } + + /* Cancel draw offers */ + first.offeredDraw = second.offeredDraw = 0; + + /* If this is an ICS game, only ICS can really say it's done; + if not, anyone can. */ + isIcsGame = (gameMode == IcsPlayingWhite || + gameMode == IcsPlayingBlack || + gameMode == IcsObserving || + gameMode == IcsExamining); + + if (!isIcsGame || whosays == GE_ICS) { + /* OK -- not an ICS game, or ICS said it was done */ + StopClocks(); + if (!isIcsGame && !appData.noChessProgram) + SetUserThinkingEnables(); + + if (resultDetails != NULL) { + gameInfo.result = result; + gameInfo.resultDetails = StrSave(resultDetails); + + /* Tell program how game ended in case it is learning */ + if (gameMode == MachinePlaysWhite || + gameMode == MachinePlaysBlack || + gameMode == TwoMachinesPlay || + gameMode == IcsPlayingWhite || + gameMode == IcsPlayingBlack || + gameMode == BeginningOfGame) { + char buf[MSG_SIZ]; + sprintf(buf, "result %s {%s}\n", PGNResult(result), + resultDetails); + if (first.pr != NoProc) { + SendToProgram(buf, &first); + } + if (second.pr != NoProc && + gameMode == TwoMachinesPlay) { + SendToProgram(buf, &second); + } + } + + /* display last move only if game was not loaded from file */ + if ((whosays != GE_FILE) && (currentMove == forwardMostMove)) + DisplayMove(currentMove - 1); + + if (forwardMostMove != 0) { + if (gameMode != PlayFromGameFile && gameMode != EditGame) { + if (*appData.saveGameFile != NULLCHAR) { + SaveGameToFile(appData.saveGameFile, TRUE); + } else if (appData.autoSaveGames) { + AutoSaveGame(); + } + if (*appData.savePositionFile != NULLCHAR) { + SavePositionToFile(appData.savePositionFile); + } + } + } + } + + if (appData.icsActive) { + if (appData.quietPlay && + (gameMode == IcsPlayingWhite || + gameMode == IcsPlayingBlack)) { + SendToICS(ics_prefix); + SendToICS("set shout 1\n"); + } + nextGameMode = IcsIdle; + ics_user_moved = FALSE; + /* clean up premove. It's ugly when the game has ended and the + * premove highlights are still on the board. + */ + if (gotPremove) { + gotPremove = FALSE; + ClearPremoveHighlights(); + DrawPosition(FALSE, boards[currentMove]); + } + if (whosays == GE_ICS) { + switch (result) { + case WhiteWins: + if (gameMode == IcsPlayingWhite) + PlayIcsWinSound(); + else if(gameMode == IcsPlayingBlack) + PlayIcsLossSound(); + break; + case BlackWins: + if (gameMode == IcsPlayingBlack) + PlayIcsWinSound(); + else if(gameMode == IcsPlayingWhite) + PlayIcsLossSound(); + break; + case GameIsDrawn: + PlayIcsDrawSound(); + break; + default: + PlayIcsUnfinishedSound(); + } + } + } else if (gameMode == EditGame || + gameMode == PlayFromGameFile || + gameMode == AnalyzeMode || + gameMode == AnalyzeFile) { + nextGameMode = gameMode; + } else { + nextGameMode = EndOfGame; + } + pausing = FALSE; + ModeHighlight(); + } else { + nextGameMode = gameMode; + } + + if (appData.noChessProgram) { + gameMode = nextGameMode; + ModeHighlight(); + return; + } + + if (first.reuse) { + /* Put first chess program into idle state */ + if (first.pr != NoProc && + (gameMode == MachinePlaysWhite || + gameMode == MachinePlaysBlack || + gameMode == TwoMachinesPlay || + gameMode == IcsPlayingWhite || + gameMode == IcsPlayingBlack || + gameMode == BeginningOfGame)) { + SendToProgram("force\n", &first); + if (first.usePing) { + char buf[MSG_SIZ]; + sprintf(buf, "ping %d\n", ++first.lastPing); + SendToProgram(buf, &first); + } + } + } else if (result != GameUnfinished || nextGameMode == IcsIdle) { + /* Kill off first chess program */ + if (first.isr != NULL) + RemoveInputSource(first.isr); + first.isr = NULL; + + if (first.pr != NoProc) { + ExitAnalyzeMode(); + SendToProgram("quit\n", &first); + DestroyChildProcess(first.pr, first.useSigterm); + } + first.pr = NoProc; + } + if (second.reuse) { + /* Put second chess program into idle state */ + if (second.pr != NoProc && + gameMode == TwoMachinesPlay) { + SendToProgram("force\n", &second); + if (second.usePing) { + char buf[MSG_SIZ]; + sprintf(buf, "ping %d\n", ++second.lastPing); + SendToProgram(buf, &second); + } + } + } else if (result != GameUnfinished || nextGameMode == IcsIdle) { + /* Kill off second chess program */ + if (second.isr != NULL) + RemoveInputSource(second.isr); + second.isr = NULL; + + if (second.pr != NoProc) { + SendToProgram("quit\n", &second); + DestroyChildProcess(second.pr, second.useSigterm); + } + second.pr = NoProc; + } + + if (matchMode && gameMode == TwoMachinesPlay) { + switch (result) { + case WhiteWins: + if (first.twoMachinesColor[0] == 'w') { + first.matchWins++; + } else { + second.matchWins++; + } + break; + case BlackWins: + if (first.twoMachinesColor[0] == 'b') { + first.matchWins++; + } else { + second.matchWins++; + } + break; + default: + break; + } + if (matchGame < appData.matchGames) { + char *tmp; + tmp = first.twoMachinesColor; + first.twoMachinesColor = second.twoMachinesColor; + second.twoMachinesColor = tmp; + gameMode = nextGameMode; + matchGame++; + ScheduleDelayedEvent(NextMatchGame, 10000); + return; + } else { + char buf[MSG_SIZ]; + gameMode = nextGameMode; + sprintf(buf, "Match %s vs. %s: final score %d-%d-%d", + first.tidy, second.tidy, + first.matchWins, second.matchWins, + appData.matchGames - (first.matchWins + second.matchWins)); + DisplayFatalError(buf, 0, 0); + } + } + if ((gameMode == AnalyzeMode || gameMode == AnalyzeFile) && + !(nextGameMode == AnalyzeMode || nextGameMode == AnalyzeFile)) + ExitAnalyzeMode(); + gameMode = nextGameMode; + ModeHighlight(); +} + +/* Assumes program was just initialized (initString sent). + Leaves program in force mode. */ +void +FeedMovesToProgram(cps, upto) + ChessProgramState *cps; + int upto; + +{ + int i; + if (appData.debugMode) + fprintf(debugFP, "Feeding %smoves %d through %d to %s chess program\n", + startedFromSetupPosition ? "position and " : "", + backwardMostMove, upto, cps->which); + /* daniel */ + if(!appData.icsAnalyze) SendToProgram("force\n", cps); + if (startedFromSetupPosition) { + SendBoard(cps, backwardMostMove); + } + for (i = backwardMostMove; i < upto; i++) { + + SendMoveToProgram(i, cps); + } +} + + +void +ResurrectChessProgram() +{ + /* The chess program may have exited. + If so, restart it and feed it all the moves made so far. */ + + if (appData.noChessProgram || first.pr != NoProc) return; + + StartChessProgram(&first); + InitChessProgram(&first); + FeedMovesToProgram(&first, currentMove); + + if (!first.sendTime) { + /* can't tell gnuchess what its clock should read, + so we bow to its notion. */ + ResetClocks(); + timeRemaining[0][currentMove] = whiteTimeRemaining; + timeRemaining[1][currentMove] = blackTimeRemaining; + } + + if ((gameMode == AnalyzeMode || gameMode == AnalyzeFile) && + first.analysisSupport) { + SendToProgram("analyze\n", &first); + first.analyzing = TRUE; + } +} + +/* + * Button procedures + */ +void +Reset(redraw, init) + int redraw, init; +{ + int i; + + if (appData.debugMode) { + fprintf(debugFP, "Reset(%d, %d) from gameMode %d\n", + redraw, init, gameMode); + } + + /* reset send engine output to ics */ + appData.SendOutPutToICS = 1; + + pausing = pauseExamInvalid = FALSE; + startedFromSetupPosition = blackPlaysFirst = FALSE; + firstMove = TRUE; + whiteFlag = blackFlag = FALSE; + userOfferedDraw = FALSE; + hintRequested = bookRequested = FALSE; + first.maybeThinking = FALSE; + second.maybeThinking = FALSE; + thinkOutput[0] = NULLCHAR; + lastHint[0] = NULLCHAR; + ClearGameInfo(&gameInfo); + gameInfo.variant = StringToVariant(appData.variant); + ics_user_moved = ics_clock_paused = FALSE; + ics_getting_history = H_FALSE; + ics_gamenum = -1; + white_holding[0] = black_holding[0] = NULLCHAR; + ClearProgramStats(); + + ResetFrontEnd(); + ClearHighlights(); + flipView = appData.flipView; + ClearPremoveHighlights(); + gotPremove = FALSE; + alarmSounded = FALSE; + + GameEnds((ChessMove) 0, NULL, GE_PLAYER); + ExitAnalyzeMode(); + gameMode = BeginningOfGame; + ModeHighlight(); + InitPosition(redraw); + for (i = 0; i < MAX_MOVES; i++) { + if (commentList[i] != NULL) { + free(commentList[i]); + commentList[i] = NULL; + } + } + ResetClocks(); + timeRemaining[0][0] = whiteTimeRemaining; + timeRemaining[1][0] = blackTimeRemaining; + if (first.pr == NULL) { + StartChessProgram(&first); + } + if (init) InitChessProgram(&first); + DisplayTitle(""); + DisplayMessage("", ""); + HistorySet(parseList, backwardMostMove, forwardMostMove, currentMove-1); +} + +void +AutoPlayGameLoop() +{ + for (;;) { + if (!AutoPlayOneMove()) + return; + if (matchMode || appData.timeDelay == 0) + continue; + if (appData.timeDelay < 0 || gameMode == AnalyzeFile) + return; + StartLoadGameTimer((long)(1000.0 * appData.timeDelay)); + break; + } +} + + +int +AutoPlayOneMove() +{ + int fromX, fromY, toX, toY; + + if (appData.debugMode) { + fprintf(debugFP, "AutoPlayOneMove(): current %d\n", currentMove); + } + + if (gameMode != PlayFromGameFile) + return FALSE; + + if (currentMove >= forwardMostMove) { + gameMode = EditGame; + ModeHighlight(); + return FALSE; + } + + toX = moveList[currentMove][2] - 'a'; + toY = moveList[currentMove][3] - '1'; + + if (moveList[currentMove][1] == '@') { + if (appData.highlightLastMove) { + SetHighlights(-1, -1, toX, toY); + } + } else { + fromX = moveList[currentMove][0] - 'a'; + fromY = moveList[currentMove][1] - '1'; + AnimateMove(boards[currentMove], fromX, fromY, toX, toY); + + if (appData.highlightLastMove) { + SetHighlights(fromX, fromY, toX, toY); + } + } + DisplayMove(currentMove); + SendMoveToProgram(currentMove++, &first); + DisplayBothClocks(); + DrawPosition(FALSE, boards[currentMove]); + if (commentList[currentMove] != NULL) { + DisplayComment(currentMove - 1, commentList[currentMove]); + } + return TRUE; +} + + +int +LoadGameOneMove(readAhead) + ChessMove readAhead; +{ + int fromX = 0, fromY = 0, toX = 0, toY = 0, done; + char promoChar = NULLCHAR; + ChessMove moveType; + char move[MSG_SIZ]; + char *p, *q; + + if (gameMode != PlayFromGameFile && gameMode != AnalyzeFile && + gameMode != AnalyzeMode && gameMode != Training) { + gameFileFP = NULL; + return FALSE; + } + + yyboardindex = forwardMostMove; + if (readAhead != (ChessMove)0) { + moveType = readAhead; + } else { + if (gameFileFP == NULL) + return FALSE; + moveType = (ChessMove) yylex(); + } + + done = FALSE; + switch (moveType) { + case Comment: + if (appData.debugMode) + fprintf(debugFP, "Parsed Comment: %s\n", yy_text); + p = yy_text; + if (*p == '{' || *p == '[' || *p == '(') { + p[strlen(p) - 1] = NULLCHAR; + p++; + } + + /* append the comment but don't display it */ + while (*p == '\n') p++; + AppendComment(currentMove, p); + return TRUE; + + case WhiteCapturesEnPassant: + case BlackCapturesEnPassant: + case WhitePromotionQueen: + case BlackPromotionQueen: + case WhitePromotionRook: + case BlackPromotionRook: + case WhitePromotionBishop: + case BlackPromotionBishop: + case WhitePromotionKnight: + case BlackPromotionKnight: + case WhitePromotionKing: + case BlackPromotionKing: + case NormalMove: + case WhiteKingSideCastle: + case WhiteQueenSideCastle: + case BlackKingSideCastle: + case BlackQueenSideCastle: + case WhiteKingSideCastleWild: + case WhiteQueenSideCastleWild: + case BlackKingSideCastleWild: + case BlackQueenSideCastleWild: + if (appData.debugMode) + fprintf(debugFP, "Parsed %s into %s\n", yy_text, currentMoveString); + fromX = currentMoveString[0] - 'a'; + fromY = currentMoveString[1] - '1'; + toX = currentMoveString[2] - 'a'; + toY = currentMoveString[3] - '1'; + promoChar = currentMoveString[4]; + break; + + case WhiteDrop: + case BlackDrop: + if (appData.debugMode) + fprintf(debugFP, "Parsed %s into %s\n", yy_text, currentMoveString); + fromX = moveType == WhiteDrop ? + (int) CharToPiece(ToUpper(currentMoveString[0])) : + (int) CharToPiece(ToLower(currentMoveString[0])); + fromY = DROP_RANK; + toX = currentMoveString[2] - 'a'; + toY = currentMoveString[3] - '1'; + break; + + case WhiteWins: + case BlackWins: + case GameIsDrawn: + case GameUnfinished: + if (appData.debugMode) + fprintf(debugFP, "Parsed game end: %s\n", yy_text); + p = strchr(yy_text, '{'); + if (p == NULL) p = strchr(yy_text, '('); + if (p == NULL) { + p = yy_text; + if (p[0] == '0' || p[0] == '1' || p[0] == '*') p = ""; + } else { + q = strchr(p, *p == '{' ? '}' : ')'); + if (q != NULL) *q = NULLCHAR; + p++; + } + GameEnds(moveType, p, GE_FILE); + done = TRUE; + if (cmailMsgLoaded) { + ClearHighlights(); + flipView = WhiteOnMove(currentMove); + if (moveType == GameUnfinished) flipView = !flipView; + if (appData.debugMode) + fprintf(debugFP, "Setting flipView to %d\n", flipView) ; + } + break; + + case (ChessMove) 0: /* end of file */ + if (appData.debugMode) + fprintf(debugFP, "Parser hit end of file\n"); + switch (MateTest(boards[currentMove], PosFlags(currentMove), + EP_UNKNOWN)) { + case MT_NONE: + case MT_CHECK: + break; + case MT_CHECKMATE: + if (WhiteOnMove(currentMove)) { + GameEnds(BlackWins, "Black mates", GE_FILE); + } else { + GameEnds(WhiteWins, "White mates", GE_FILE); + } + break; + case MT_STALEMATE: + GameEnds(GameIsDrawn, "Stalemate", GE_FILE); + break; + } + done = TRUE; + break; + + case MoveNumberOne: + if (lastLoadGameStart == GNUChessGame) { + /* GNUChessGames have numbers, but they aren't move numbers */ + if (appData.debugMode) + fprintf(debugFP, "Parser ignoring: '%s' (%d)\n", + yy_text, (int) moveType); + return LoadGameOneMove((ChessMove)0); /* tail recursion */ + } + /* else fall thru */ + + case XBoardGame: + case GNUChessGame: + case PGNTag: + /* Reached start of next game in file */ + if (appData.debugMode) + fprintf(debugFP, "Parsed start of next game: %s\n", yy_text); + switch (MateTest(boards[currentMove], PosFlags(currentMove), + EP_UNKNOWN)) { + case MT_NONE: + case MT_CHECK: + break; + case MT_CHECKMATE: + if (WhiteOnMove(currentMove)) { + GameEnds(BlackWins, "Black mates", GE_FILE); + } else { + GameEnds(WhiteWins, "White mates", GE_FILE); + } + break; + case MT_STALEMATE: + GameEnds(GameIsDrawn, "Stalemate", GE_FILE); + break; + } + done = TRUE; + break; + + case PositionDiagram: /* should not happen; ignore */ + case ElapsedTime: /* ignore */ + case NAG: /* ignore */ + if (appData.debugMode) + fprintf(debugFP, "Parser ignoring: '%s' (%d)\n", + yy_text, (int) moveType); + return LoadGameOneMove((ChessMove)0); /* tail recursion */ + + case IllegalMove: + if (appData.testLegality) { + if (appData.debugMode) + fprintf(debugFP, "Parsed IllegalMove: %s\n", yy_text); + sprintf(move, "Illegal move: %d.%s%s", + (forwardMostMove / 2) + 1, + WhiteOnMove(forwardMostMove) ? " " : ".. ", yy_text); + DisplayError(move, 0); + done = TRUE; + } else { + if (appData.debugMode) + fprintf(debugFP, "Parsed %s into IllegalMove %s\n", + yy_text, currentMoveString); + fromX = currentMoveString[0] - 'a'; + fromY = currentMoveString[1] - '1'; + toX = currentMoveString[2] - 'a'; + toY = currentMoveString[3] - '1'; + promoChar = currentMoveString[4]; + } + break; + + case AmbiguousMove: + if (appData.debugMode) + fprintf(debugFP, "Parsed AmbiguousMove: %s\n", yy_text); + sprintf(move, "Ambiguous move: %d.%s%s", + (forwardMostMove / 2) + 1, + WhiteOnMove(forwardMostMove) ? " " : ".. ", yy_text); + DisplayError(move, 0); + done = TRUE; + break; + + default: + case ImpossibleMove: + if (appData.debugMode) + fprintf(debugFP, "Parsed ImpossibleMove: %s\n", yy_text); + sprintf(move, "Illegal move: %d.%s%s", + (forwardMostMove / 2) + 1, + WhiteOnMove(forwardMostMove) ? " " : ".. ", yy_text); + DisplayError(move, 0); + done = TRUE; + break; + } + + if (done) { + if (appData.matchMode || (appData.timeDelay == 0 && !pausing)) { + DrawPosition(FALSE, boards[currentMove]); + DisplayBothClocks(); + if (!appData.matchMode && commentList[currentMove] != NULL) + DisplayComment(currentMove - 1, commentList[currentMove]); + } + (void) StopLoadGameTimer(); + gameFileFP = NULL; + cmailOldMove = forwardMostMove; + return FALSE; + } else { + /* currentMoveString is set as a side-effect of yylex */ + strcat(currentMoveString, "\n"); + strcpy(moveList[forwardMostMove], currentMoveString); + + thinkOutput[0] = NULLCHAR; + MakeMove(fromX, fromY, toX, toY, promoChar); + currentMove = forwardMostMove; + return TRUE; + } +} + +/* Load the nth game from the given file */ +int +LoadGameFromFile(filename, n, title, useList) + char *filename; + int n; + char *title; + /*Boolean*/ int useList; +{ + FILE *f; + char buf[MSG_SIZ]; + + if (strcmp(filename, "-") == 0) { + f = stdin; + title = "stdin"; + } else { + f = fopen(filename, "rb"); + if (f == NULL) { + sprintf(buf, "Can't open \"%s\"", filename); + DisplayError(buf, errno); + return FALSE; + } + } + if (fseek(f, 0, 0) == -1) { + /* f is not seekable; probably a pipe */ + useList = FALSE; + } + if (useList && n == 0) { + int error = GameListBuild(f); + if (error) { + DisplayError("Cannot build game list", error); + } else if (!ListEmpty(&gameList) && + ((ListGame *) gameList.tailPred)->number > 1) { + GameListPopUp(f, title); + return TRUE; + } + GameListDestroy(); + n = 1; + } + if (n == 0) n = 1; + return LoadGame(f, n, title, FALSE); +} + + +void +MakeRegisteredMove() +{ + int fromX, fromY, toX, toY; + char promoChar; + if (cmailMoveRegistered[lastLoadGameNumber - 1]) { + switch (cmailMoveType[lastLoadGameNumber - 1]) { + case CMAIL_MOVE: + case CMAIL_DRAW: + if (appData.debugMode) + fprintf(debugFP, "Restoring %s for game %d\n", + cmailMove[lastLoadGameNumber - 1], lastLoadGameNumber); + + thinkOutput[0] = NULLCHAR; + strcpy(moveList[currentMove], cmailMove[lastLoadGameNumber - 1]); + fromX = cmailMove[lastLoadGameNumber - 1][0] - 'a'; + fromY = cmailMove[lastLoadGameNumber - 1][1] - '1'; + toX = cmailMove[lastLoadGameNumber - 1][2] - 'a'; + toY = cmailMove[lastLoadGameNumber - 1][3] - '1'; + promoChar = cmailMove[lastLoadGameNumber - 1][4]; + MakeMove(fromX, fromY, toX, toY, promoChar); + ShowMove(fromX, fromY, toX, toY); + + switch (MateTest(boards[currentMove], PosFlags(currentMove), + EP_UNKNOWN)) { + case MT_NONE: + case MT_CHECK: + break; + + case MT_CHECKMATE: + if (WhiteOnMove(currentMove)) { + GameEnds(BlackWins, "Black mates", GE_PLAYER); + } else { + GameEnds(WhiteWins, "White mates", GE_PLAYER); + } + break; + + case MT_STALEMATE: + GameEnds(GameIsDrawn, "Stalemate", GE_PLAYER); + break; + } + + break; + + case CMAIL_RESIGN: + if (WhiteOnMove(currentMove)) { + GameEnds(BlackWins, "White resigns", GE_PLAYER); + } else { + GameEnds(WhiteWins, "Black resigns", GE_PLAYER); + } + break; + + case CMAIL_ACCEPT: + GameEnds(GameIsDrawn, "Draw agreed", GE_PLAYER); + break; + + default: + break; + } + } + + return; +} + +/* Wrapper around LoadGame for use when a Cmail message is loaded */ +int +CmailLoadGame(f, gameNumber, title, useList) + FILE *f; + int gameNumber; + char *title; + int useList; +{ + int retVal; + + if (gameNumber > nCmailGames) { + DisplayError("No more games in this message", 0); + return FALSE; + } + if (f == lastLoadGameFP) { + int offset = gameNumber - lastLoadGameNumber; + if (offset == 0) { + cmailMsg[0] = NULLCHAR; + if (cmailMoveRegistered[lastLoadGameNumber - 1]) { + cmailMoveRegistered[lastLoadGameNumber - 1] = FALSE; + nCmailMovesRegistered--; + } + cmailMoveType[lastLoadGameNumber - 1] = CMAIL_MOVE; + if (cmailResult[lastLoadGameNumber - 1] == CMAIL_NEW_RESULT) { + cmailResult[lastLoadGameNumber - 1] = CMAIL_NOT_RESULT; + } + } else { + if (! RegisterMove()) return FALSE; + } + } + + retVal = LoadGame(f, gameNumber, title, useList); + + /* Make move registered during previous look at this game, if any */ + MakeRegisteredMove(); + + if (cmailCommentList[lastLoadGameNumber - 1] != NULL) { + commentList[currentMove] + = StrSave(cmailCommentList[lastLoadGameNumber - 1]); + DisplayComment(currentMove - 1, commentList[currentMove]); + } + + return retVal; +} + +/* Support for LoadNextGame, LoadPreviousGame, ReloadSameGame */ +int +ReloadGame(offset) + int offset; +{ + int gameNumber = lastLoadGameNumber + offset; + if (lastLoadGameFP == NULL) { + DisplayError("No game has been loaded yet", 0); + return FALSE; + } + if (gameNumber <= 0) { + DisplayError("Can't back up any further", 0); + return FALSE; + } + if (cmailMsgLoaded) { + return CmailLoadGame(lastLoadGameFP, gameNumber, + lastLoadGameTitle, lastLoadGameUseList); + } else { + return LoadGame(lastLoadGameFP, gameNumber, + lastLoadGameTitle, lastLoadGameUseList); + } +} + + + +/* Load the nth game from open file f */ +int +LoadGame(f, gameNumber, title, useList) + FILE *f; + int gameNumber; + char *title; + int useList; +{ + ChessMove cm; + char buf[MSG_SIZ]; + int gn = gameNumber; + ListGame *lg = NULL; + int numPGNTags = 0; + int err; + GameMode oldGameMode; + + if (appData.debugMode) + fprintf(debugFP, "LoadGame(): on entry, gameMode %d\n", gameMode); + + if (gameMode == Training ) + SetTrainingModeOff(); + + oldGameMode = gameMode; + if (gameMode != BeginningOfGame) { + Reset(FALSE, TRUE); + } + + gameFileFP = f; + if (lastLoadGameFP != NULL && lastLoadGameFP != f) { + fclose(lastLoadGameFP); + } + + if (useList) { + lg = (ListGame *) ListElem(&gameList, gameNumber-1); + + if (lg) { + fseek(f, lg->offset, 0); + GameListHighlight(gameNumber); + gn = 1; + } + else { + DisplayError("Game number out of range", 0); + return FALSE; + } + } else { + GameListDestroy(); + if (fseek(f, 0, 0) == -1) { + if (f == lastLoadGameFP ? + gameNumber == lastLoadGameNumber + 1 : + gameNumber == 1) { + gn = 1; + } else { + DisplayError("Can't seek on game file", 0); + return FALSE; + } + } + } + lastLoadGameFP = f; + lastLoadGameNumber = gameNumber; + strcpy(lastLoadGameTitle, title); + lastLoadGameUseList = useList; + + yynewfile(f); + + + if (lg && lg->gameInfo.white && lg->gameInfo.black) { + sprintf(buf, "%s vs. %s", lg->gameInfo.white, + lg->gameInfo.black); + DisplayTitle(buf); + } else if (*title != NULLCHAR) { + if (gameNumber > 1) { + sprintf(buf, "%s %d", title, gameNumber); + DisplayTitle(buf); + } else { + DisplayTitle(title); + } + } + + if (gameMode != AnalyzeFile && gameMode != AnalyzeMode) { + gameMode = PlayFromGameFile; + ModeHighlight(); + } + + currentMove = forwardMostMove = backwardMostMove = 0; + CopyBoard(boards[0], initialPosition); + StopClocks(); + + /* + * Skip the first gn-1 games in the file. + * Also skip over anything that precedes an identifiable + * start of game marker, to avoid being confused by + * garbage at the start of the file. Currently + * recognized start of game markers are the move number "1", + * the pattern "gnuchess .* game", the pattern + * "^[#;%] [^ ]* game file", and a PGN tag block. + * A game that starts with one of the latter two patterns + * will also have a move number 1, possibly + * following a position diagram. + */ + cm = lastLoadGameStart = (ChessMove) 0; + yyskipmoves = TRUE; + while (gn > 0) { + yyboardindex = forwardMostMove; + cm = (ChessMove) yylex(); + yyskipmoves = FALSE; + switch (cm) { + case (ChessMove) 0: + if (cmailMsgLoaded) { + nCmailGames = CMAIL_MAX_GAMES - gn; + } else { + Reset(TRUE, TRUE); + DisplayError("Game not found in file", 0); + } + yyskipmoves = FALSE; + return FALSE; + + case GNUChessGame: + case XBoardGame: + gn--; + lastLoadGameStart = cm; + break; + + case MoveNumberOne: + switch (lastLoadGameStart) { + case GNUChessGame: + case XBoardGame: + case PGNTag: + break; + case MoveNumberOne: + case (ChessMove) 0: + gn--; /* count this game */ + lastLoadGameStart = cm; + break; + default: + /* impossible */ + break; + } + break; + + case PGNTag: + switch (lastLoadGameStart) { + case GNUChessGame: + case PGNTag: + case MoveNumberOne: + case (ChessMove) 0: + gn--; /* count this game */ + lastLoadGameStart = cm; + break; + case XBoardGame: + lastLoadGameStart = cm; /* game counted already */ + break; + default: + /* impossible */ + break; + } + if (gn > 0) { + do { + yyboardindex = forwardMostMove; + cm = (ChessMove) yylex(); + } while (cm == PGNTag || cm == Comment); + } + break; + + case WhiteWins: + case BlackWins: + case GameIsDrawn: + if (cmailMsgLoaded && (CMAIL_MAX_GAMES == lastLoadGameNumber)) { + if ( cmailResult[CMAIL_MAX_GAMES - gn - 1] + != CMAIL_OLD_RESULT) { + nCmailResults ++ ; + cmailResult[ CMAIL_MAX_GAMES + - gn - 1] = CMAIL_OLD_RESULT; + } + } + break; + + default: + break; + } + } + yyskipmoves = FALSE; + + if (appData.debugMode) + fprintf(debugFP, "Parsed game start '%s' (%d)\n", yy_text, (int) cm); + + if (cm == XBoardGame) { + /* Skip any header junk before position diagram and/or move 1 */ + for (;;) { + yyboardindex = forwardMostMove; + cm = (ChessMove) yylex(); + + if (cm == (ChessMove) 0 || + cm == GNUChessGame || cm == XBoardGame) { + /* Empty game; pretend end-of-file and handle later */ + cm = (ChessMove) 0; + break; + } + + if (cm == MoveNumberOne || cm == PositionDiagram || + cm == PGNTag || cm == Comment) + break; + } + } else if (cm == GNUChessGame) { + if (gameInfo.event != NULL) { + free(gameInfo.event); + } + gameInfo.event = StrSave(yy_text); + } + + startedFromSetupPosition = FALSE; + while (cm == PGNTag) { + if (appData.debugMode) + fprintf(debugFP, "Parsed PGNTag: %s\n", yy_text); + err = ParsePGNTag(yy_text, &gameInfo); + if (!err) numPGNTags++; + + if (gameInfo.fen != NULL) { + Board initial_position; + startedFromSetupPosition = TRUE; + if (!ParseFEN(initial_position, &blackPlaysFirst, gameInfo.fen)) { + Reset(TRUE, TRUE); + DisplayError("Bad FEN position in file", 0); + return FALSE; + } + CopyBoard(boards[0], initial_position); + if (blackPlaysFirst) { + currentMove = forwardMostMove = backwardMostMove = 1; + CopyBoard(boards[1], initial_position); + strcpy(moveList[0], ""); + strcpy(parseList[0], ""); + timeRemaining[0][1] = whiteTimeRemaining; + timeRemaining[1][1] = blackTimeRemaining; + if (commentList[0] != NULL) { + commentList[1] = commentList[0]; + commentList[0] = NULL; + } + } else { + currentMove = forwardMostMove = backwardMostMove = 0; + } + yyboardindex = forwardMostMove; + free(gameInfo.fen); + gameInfo.fen = NULL; + } + + yyboardindex = forwardMostMove; + cm = (ChessMove) yylex(); + + /* Handle comments interspersed among the tags */ + while (cm == Comment) { + char *p; + if (appData.debugMode) + fprintf(debugFP, "Parsed Comment: %s\n", yy_text); + p = yy_text; + if (*p == '{' || *p == '[' || *p == '(') { + p[strlen(p) - 1] = NULLCHAR; + p++; + } + while (*p == '\n') p++; + AppendComment(currentMove, p); + yyboardindex = forwardMostMove; + cm = (ChessMove) yylex(); + } + } + + /* don't rely on existence of Event tag since if game was + * pasted from clipboard the Event tag may not exist + */ + if (numPGNTags > 0){ + char *tags; + if (gameInfo.variant == VariantNormal) { + gameInfo.variant = StringToVariant(gameInfo.event); + } + if (!matchMode) { + tags = PGNTags(&gameInfo); + TagsPopUp(tags, CmailMsg()); + free(tags); + } + } else { + /* Make something up, but don't display it now */ + SetGameInfo(); + TagsPopDown(); + } + + if (cm == PositionDiagram) { + int i, j; + char *p; + Board initial_position; + + if (appData.debugMode) + fprintf(debugFP, "Parsed PositionDiagram: %s\n", yy_text); + + if (!startedFromSetupPosition) { + p = yy_text; + for (i = BOARD_SIZE - 1; i >= 0; i--) + for (j = 0; j < BOARD_SIZE; p++) + switch (*p) { + case '[': + case '-': + case ' ': + case '\t': + case '\n': + case '\r': + break; + default: + initial_position[i][j++] = CharToPiece(*p); + break; + } + while (*p == ' ' || *p == '\t' || + *p == '\n' || *p == '\r') p++; + + if (strncmp(p, "black", strlen("black"))==0) + blackPlaysFirst = TRUE; + else + blackPlaysFirst = FALSE; + startedFromSetupPosition = TRUE; + + CopyBoard(boards[0], initial_position); + if (blackPlaysFirst) { + currentMove = forwardMostMove = backwardMostMove = 1; + CopyBoard(boards[1], initial_position); + strcpy(moveList[0], ""); + strcpy(parseList[0], ""); + timeRemaining[0][1] = whiteTimeRemaining; + timeRemaining[1][1] = blackTimeRemaining; + if (commentList[0] != NULL) { + commentList[1] = commentList[0]; + commentList[0] = NULL; + } + } else { + currentMove = forwardMostMove = backwardMostMove = 0; + } + } + yyboardindex = forwardMostMove; + cm = (ChessMove) yylex(); + } + + if (first.pr == NoProc) { + StartChessProgram(&first); + } + InitChessProgram(&first); + SendToProgram("force\n", &first); + if (startedFromSetupPosition) { + SendBoard(&first, forwardMostMove); + DisplayBothClocks(); + } + + while (cm == Comment) { + char *p; + if (appData.debugMode) + fprintf(debugFP, "Parsed Comment: %s\n", yy_text); + p = yy_text; + if (*p == '{' || *p == '[' || *p == '(') { + p[strlen(p) - 1] = NULLCHAR; + p++; + } + while (*p == '\n') p++; + AppendComment(currentMove, p); + yyboardindex = forwardMostMove; + cm = (ChessMove) yylex(); + } + + if (cm == (ChessMove) 0 || cm == WhiteWins || cm == BlackWins || + cm == GameIsDrawn || cm == GameUnfinished) { + DisplayMessage("", "No moves in game"); + if (cmailMsgLoaded) { + if (appData.debugMode) + fprintf(debugFP, "Setting flipView to %d.\n", FALSE); + ClearHighlights(); + flipView = FALSE; + } + DrawPosition(FALSE, boards[currentMove]); + DisplayBothClocks(); + gameMode = EditGame; + ModeHighlight(); + gameFileFP = NULL; + cmailOldMove = 0; + return TRUE; + } + + if (commentList[currentMove] != NULL) { + if (!matchMode && (pausing || appData.timeDelay != 0)) { + DisplayComment(currentMove - 1, commentList[currentMove]); + } + } + if (!matchMode && appData.timeDelay != 0) + DrawPosition(FALSE, boards[currentMove]); + + if (gameMode == AnalyzeFile || gameMode == AnalyzeMode) { + programStats.ok_to_send = 1; + } + + /* if the first token after the PGN tags is a move + * and not move number 1, retrieve it from the parser + */ + if (cm != MoveNumberOne) + LoadGameOneMove(cm); + + /* load the remaining moves from the file */ + while (LoadGameOneMove((ChessMove)0)) { + timeRemaining[0][forwardMostMove] = whiteTimeRemaining; + timeRemaining[1][forwardMostMove] = blackTimeRemaining; + } + + /* rewind to the start of the game */ + currentMove = backwardMostMove; + + HistorySet(parseList, backwardMostMove, forwardMostMove, currentMove-1); + + if (oldGameMode == AnalyzeFile || + oldGameMode == AnalyzeMode) { + AnalyzeFileEvent(); + } + + if (matchMode || appData.timeDelay == 0) { + ToEndEvent(); + gameMode = EditGame; + ModeHighlight(); + } else if (appData.timeDelay > 0) { + AutoPlayGameLoop(); + } + + if (appData.debugMode) + fprintf(debugFP, "LoadGame(): on exit, gameMode %d\n", gameMode); + return TRUE; +} + +/* Support for LoadNextPosition, LoadPreviousPosition, ReloadSamePosition */ +int +ReloadPosition(offset) + int offset; +{ + int positionNumber = lastLoadPositionNumber + offset; + if (lastLoadPositionFP == NULL) { + DisplayError("No position has been loaded yet", 0); + return FALSE; + } + if (positionNumber <= 0) { + DisplayError("Can't back up any further", 0); + return FALSE; + } + return LoadPosition(lastLoadPositionFP, positionNumber, + lastLoadPositionTitle); +} + +/* Load the nth position from the given file */ +int +LoadPositionFromFile(filename, n, title) + char *filename; + int n; + char *title; +{ + FILE *f; + char buf[MSG_SIZ]; + + if (strcmp(filename, "-") == 0) { + return LoadPosition(stdin, n, "stdin"); + } else { + f = fopen(filename, "rb"); + if (f == NULL) { + sprintf(buf, "Can't open \"%s\"", filename); + DisplayError(buf, errno); + return FALSE; + } else { + return LoadPosition(f, n, title); + } + } +} + +/* Load the nth position from the given open file, and close it */ +int +LoadPosition(f, positionNumber, title) + FILE *f; + int positionNumber; + char *title; +{ + char *p, line[MSG_SIZ]; + Board initial_position; + int i, j, fenMode, pn; + + if (gameMode == Training ) + SetTrainingModeOff(); + + if (gameMode != BeginningOfGame) { + Reset(FALSE, TRUE); + } + if (lastLoadPositionFP != NULL && lastLoadPositionFP != f) { + fclose(lastLoadPositionFP); + } + if (positionNumber == 0) positionNumber = 1; + lastLoadPositionFP = f; + lastLoadPositionNumber = positionNumber; + strcpy(lastLoadPositionTitle, title); + if (first.pr == NoProc) { + StartChessProgram(&first); + InitChessProgram(&first); + } + pn = positionNumber; + if (positionNumber < 0) { + /* Negative position number means to seek to that byte offset */ + if (fseek(f, -positionNumber, 0) == -1) { + DisplayError("Can't seek on position file", 0); + return FALSE; + }; + pn = 1; + } else { + if (fseek(f, 0, 0) == -1) { + if (f == lastLoadPositionFP ? + positionNumber == lastLoadPositionNumber + 1 : + positionNumber == 1) { + pn = 1; + } else { + DisplayError("Can't seek on position file", 0); + return FALSE; + } + } + } + /* See if this file is FEN or old-style xboard */ + if (fgets(line, MSG_SIZ, f) == NULL) { + DisplayError("Position not found in file", 0); + return FALSE; + } + switch (line[0]) { + case '#': case 'x': + default: + fenMode = FALSE; + break; + case 'p': case 'n': case 'b': case 'r': case 'q': case 'k': + case 'P': case 'N': case 'B': case 'R': case 'Q': case 'K': + case '1': case '2': case '3': case '4': case '5': case '6': + case '7': case '8': + fenMode = TRUE; + break; + } + + if (pn >= 2) { + if (fenMode || line[0] == '#') pn--; + while (pn > 0) { + /* skip postions before number pn */ + if (fgets(line, MSG_SIZ, f) == NULL) { + DisplayError("Position not found in file", 0); + return FALSE; + } + if (fenMode || line[0] == '#') pn--; + } + } + + if (fenMode) { + if (!ParseFEN(initial_position, &blackPlaysFirst, line)) { + DisplayError("Bad FEN position in file", 0); + return FALSE; + } + } else { + (void) fgets(line, MSG_SIZ, f); + (void) fgets(line, MSG_SIZ, f); + + for (i = BOARD_SIZE - 1; i >= 0; i--) { + (void) fgets(line, MSG_SIZ, f); + for (p = line, j = 0; j < BOARD_SIZE; p++) { + if (*p == ' ') + continue; + initial_position[i][j++] = CharToPiece(*p); + } + } + + blackPlaysFirst = FALSE; + if (!feof(f)) { + (void) fgets(line, MSG_SIZ, f); + if (strncmp(line, "black", strlen("black"))==0) + blackPlaysFirst = TRUE; + } + } + startedFromSetupPosition = TRUE; + + SendToProgram("force\n", &first); + CopyBoard(boards[0], initial_position); + if (blackPlaysFirst) { + currentMove = forwardMostMove = backwardMostMove = 1; + strcpy(moveList[0], ""); + strcpy(parseList[0], ""); + CopyBoard(boards[1], initial_position); + DisplayMessage("", "Black to play"); + } else { + currentMove = forwardMostMove = backwardMostMove = 0; + DisplayMessage("", "White to play"); + } + SendBoard(&first, forwardMostMove); + + if (positionNumber > 1) { + sprintf(line, "%s %d", title, positionNumber); + DisplayTitle(line); + } else { + DisplayTitle(title); + } + gameMode = EditGame; + ModeHighlight(); + ResetClocks(); + timeRemaining[0][1] = whiteTimeRemaining; + timeRemaining[1][1] = blackTimeRemaining; + DrawPosition(FALSE, boards[currentMove]); + + return TRUE; +} + + +void +CopyPlayerNameIntoFileName(dest, src) + char **dest, *src; +{ + while (*src != NULLCHAR && *src != ',') { + if (*src == ' ') { + *(*dest)++ = '_'; + src++; + } else { + *(*dest)++ = *src++; + } + } +} + +char *DefaultFileName(ext) + char *ext; +{ + static char def[MSG_SIZ]; + char *p; + + if (gameInfo.white != NULL && gameInfo.white[0] != '-') { + p = def; + CopyPlayerNameIntoFileName(&p, gameInfo.white); + *p++ = '-'; + CopyPlayerNameIntoFileName(&p, gameInfo.black); + *p++ = '.'; + strcpy(p, ext); + } else { + def[0] = NULLCHAR; + } + return def; +} + +/* Save the current game to the given file */ +int +SaveGameToFile(filename, append) + char *filename; + int append; +{ + FILE *f; + char buf[MSG_SIZ]; + + if (strcmp(filename, "-") == 0) { + return SaveGame(stdout, 0, NULL); + } else { + f = fopen(filename, append ? "a" : "w"); + if (f == NULL) { + sprintf(buf, "Can't open \"%s\"", filename); + DisplayError(buf, errno); + return FALSE; + } else { + return SaveGame(f, 0, NULL); + } + } +} + +char * +SavePart(str) + char *str; +{ + static char buf[MSG_SIZ]; + char *p; + + p = strchr(str, ' '); + if (p == NULL) return str; + strncpy(buf, str, p - str); + buf[p - str] = NULLCHAR; + return buf; +} + +#define PGN_MAX_LINE 75 + +/* Save game in PGN style and close the file */ +int +SaveGamePGN(f) + FILE *f; +{ + int i, offset, linelen, newblock; + time_t tm; + char *movetext; + char numtext[32]; + int movelen, numlen, blank; + + tm = time((time_t *) NULL); + + PrintPGNTags(f, &gameInfo); + + if (backwardMostMove > 0 || startedFromSetupPosition) { + char *fen = PositionToFEN(backwardMostMove); + fprintf(f, "[FEN \"%s\"]\n[SetUp \"1\"]\n", fen); + fprintf(f, "\n{--------------\n"); + PrintPosition(f, backwardMostMove); + fprintf(f, "--------------}\n"); + free(fen); + } else { + fprintf(f, "\n"); + } + + i = backwardMostMove; + offset = backwardMostMove & (~1L); /* output move numbers start at 1 */ + linelen = 0; + newblock = TRUE; + + while (i < forwardMostMove) { + /* Print comments preceding this move */ + if (commentList[i] != NULL) { + if (linelen > 0) fprintf(f, "\n"); + fprintf(f, "{\n%s}\n", commentList[i]); + linelen = 0; + newblock = TRUE; + } + + /* Format move number */ + if ((i % 2) == 0) { + sprintf(numtext, "%d.", (i - offset)/2 + 1); + } else { + if (newblock) { + sprintf(numtext, "%d...", (i - offset)/2 + 1); + } else { + numtext[0] = NULLCHAR; + } + } + numlen = strlen(numtext); + newblock = FALSE; + + /* Print move number */ + blank = linelen > 0 && numlen > 0; + if (linelen + (blank ? 1 : 0) + numlen > PGN_MAX_LINE) { + fprintf(f, "\n"); + linelen = 0; + blank = 0; + } + if (blank) { + fprintf(f, " "); + linelen++; + } + fprintf(f, numtext); + linelen += numlen; + + /* Get move */ + movetext = SavePart(parseList[i]); + movelen = strlen(movetext); + + /* Print move */ + blank = linelen > 0 && movelen > 0; + if (linelen + (blank ? 1 : 0) + movelen > PGN_MAX_LINE) { + fprintf(f, "\n"); + linelen = 0; + blank = 0; + } + if (blank) { + fprintf(f, " "); + linelen++; + } + fprintf(f, movetext); + linelen += movelen; + + i++; + } + + /* Start a new line */ + if (linelen > 0) fprintf(f, "\n"); + + /* Print comments after last move */ + if (commentList[i] != NULL) { + fprintf(f, "{\n%s}\n", commentList[i]); + } + + /* Print result */ + if (gameInfo.resultDetails != NULL && + gameInfo.resultDetails[0] != NULLCHAR) { + fprintf(f, "{%s} %s\n\n", gameInfo.resultDetails, + PGNResult(gameInfo.result)); + } else { + fprintf(f, "%s\n\n", PGNResult(gameInfo.result)); + } + + fclose(f); + return TRUE; +} + +/* Save game in old style and close the file */ +int +SaveGameOldStyle(f) + FILE *f; +{ + int i, offset; + time_t tm; + + tm = time((time_t *) NULL); + + fprintf(f, "# %s game file -- %s", programName, ctime(&tm)); + PrintOpponents(f); + + if (backwardMostMove > 0 || startedFromSetupPosition) { + fprintf(f, "\n[--------------\n"); + PrintPosition(f, backwardMostMove); + fprintf(f, "--------------]\n"); + } else { + fprintf(f, "\n"); + } + + i = backwardMostMove; + offset = backwardMostMove & (~1L); /* output move numbers start at 1 */ + + while (i < forwardMostMove) { + if (commentList[i] != NULL) { + fprintf(f, "[%s]\n", commentList[i]); + } + + if ((i % 2) == 1) { + fprintf(f, "%d. ... %s\n", (i - offset)/2 + 1, parseList[i]); + i++; + } else { + fprintf(f, "%d. %s ", (i - offset)/2 + 1, parseList[i]); + i++; + if (commentList[i] != NULL) { + fprintf(f, "\n"); + continue; + } + if (i >= forwardMostMove) { + fprintf(f, "\n"); + break; + } + fprintf(f, "%s\n", parseList[i]); + i++; + } + } + + if (commentList[i] != NULL) { + fprintf(f, "[%s]\n", commentList[i]); + } + + /* This isn't really the old style, but it's close enough */ + if (gameInfo.resultDetails != NULL && + gameInfo.resultDetails[0] != NULLCHAR) { + fprintf(f, "%s (%s)\n\n", PGNResult(gameInfo.result), + gameInfo.resultDetails); + } else { + fprintf(f, "%s\n\n", PGNResult(gameInfo.result)); + } + + fclose(f); + return TRUE; +} + +/* Save the current game to open file f and close the file */ +int +SaveGame(f, dummy, dummy2) + FILE *f; + int dummy; + char *dummy2; +{ + if (gameMode == EditPosition) EditPositionDone(); + if (appData.oldSaveStyle) + return SaveGameOldStyle(f); + else + return SaveGamePGN(f); +} + +/* Save the current position to the given file */ +int +SavePositionToFile(filename) + char *filename; +{ + FILE *f; + char buf[MSG_SIZ]; + + if (strcmp(filename, "-") == 0) { + return SavePosition(stdout, 0, NULL); + } else { + f = fopen(filename, "a"); + if (f == NULL) { + sprintf(buf, "Can't open \"%s\"", filename); + DisplayError(buf, errno); + return FALSE; + } else { + SavePosition(f, 0, NULL); + return TRUE; + } + } +} + +/* Save the current position to the given open file and close the file */ +int +SavePosition(f, dummy, dummy2) + FILE *f; + int dummy; + char *dummy2; +{ + time_t tm; + char *fen; + + if (appData.oldSaveStyle) { + tm = time((time_t *) NULL); + + fprintf(f, "# %s position file -- %s", programName, ctime(&tm)); + PrintOpponents(f); + fprintf(f, "[--------------\n"); + PrintPosition(f, currentMove); + fprintf(f, "--------------]\n"); + } else { + fen = PositionToFEN(currentMove); + fprintf(f, "%s\n", fen); + free(fen); + } + fclose(f); + return TRUE; +} + +void +ReloadCmailMsgEvent(unregister) + int unregister; +{ + static char *inFilename = NULL; + static char *outFilename; + int i; + struct stat inbuf, outbuf; + int status; + + /* Any registered moves are unregistered if unregister is set, */ + /* i.e. invoked by the signal handler */ + if (unregister) { + for (i = 0; i < CMAIL_MAX_GAMES; i ++) { + cmailMoveRegistered[i] = FALSE; + if (cmailCommentList[i] != NULL) { + free(cmailCommentList[i]); + cmailCommentList[i] = NULL; + } + } + nCmailMovesRegistered = 0; + } + + for (i = 0; i < CMAIL_MAX_GAMES; i ++) { + cmailResult[i] = CMAIL_NOT_RESULT; + } + nCmailResults = 0; + + if (inFilename == NULL) { + /* Because the filenames are static they only get malloced once */ + /* and they never get freed */ + inFilename = (char *) malloc(strlen(appData.cmailGameName) + 9); + sprintf(inFilename, "%s.game.in", appData.cmailGameName); + + outFilename = (char *) malloc(strlen(appData.cmailGameName) + 5); + sprintf(outFilename, "%s.out", appData.cmailGameName); + } + + status = stat(outFilename, &outbuf); + if (status < 0) { + cmailMailedMove = FALSE; + } else { + status = stat(inFilename, &inbuf); + cmailMailedMove = (inbuf.st_mtime < outbuf.st_mtime); + } + + /* LoadGameFromFile(CMAIL_MAX_GAMES) with cmailMsgLoaded == TRUE + counts the games, notes how each one terminated, etc. + + It would be nice to remove this kludge and instead gather all + the information while building the game list. (And to keep it + in the game list nodes instead of having a bunch of fixed-size + parallel arrays.) Note this will require getting each game's + termination from the PGN tags, as the game list builder does + not process the game moves. --mann + */ + cmailMsgLoaded = TRUE; + LoadGameFromFile(inFilename, CMAIL_MAX_GAMES, "", FALSE); + + /* Load first game in the file or popup game menu */ + LoadGameFromFile(inFilename, 0, appData.cmailGameName, TRUE); + + return; +} + +int +RegisterMove() +{ + FILE *f; + char string[MSG_SIZ]; + + if ( cmailMailedMove + || (cmailResult[lastLoadGameNumber - 1] == CMAIL_OLD_RESULT)) { + return TRUE; /* Allow free viewing */ + } + + /* Unregister move to ensure that we don't leave RegisterMove */ + /* with the move registered when the conditions for registering no */ + /* longer hold */ + if (cmailMoveRegistered[lastLoadGameNumber - 1]) { + cmailMoveRegistered[lastLoadGameNumber - 1] = FALSE; + nCmailMovesRegistered --; + + if (cmailCommentList[lastLoadGameNumber - 1] != NULL) + { + free(cmailCommentList[lastLoadGameNumber - 1]); + cmailCommentList[lastLoadGameNumber - 1] = NULL; + } + } + + if (cmailOldMove == -1) { + DisplayError("You have edited the game history.\nUse Reload Same Game and make your move again.", 0); + return FALSE; + } + + if (currentMove > cmailOldMove + 1) { + DisplayError("You have entered too many moves.\nBack up to the correct position and try again.", 0); + return FALSE; + } + + if (currentMove < cmailOldMove) { + DisplayError("Displayed position is not current.\nStep forward to the correct position and try again.", 0); + return FALSE; + } + + if (forwardMostMove > currentMove) { + /* Silently truncate extra moves */ + TruncateGame(); + } + + if ( (currentMove == cmailOldMove + 1) + || ( (currentMove == cmailOldMove) + && ( (cmailMoveType[lastLoadGameNumber - 1] == CMAIL_ACCEPT) + || (cmailMoveType[lastLoadGameNumber - 1] == CMAIL_RESIGN)))) { + if (gameInfo.result != GameUnfinished) { + cmailResult[lastLoadGameNumber - 1] = CMAIL_NEW_RESULT; + } + + if (commentList[currentMove] != NULL) { + cmailCommentList[lastLoadGameNumber - 1] + = StrSave(commentList[currentMove]); + } + strcpy(cmailMove[lastLoadGameNumber - 1], moveList[currentMove - 1]); + + if (appData.debugMode) + fprintf(debugFP, "Saving %s for game %d\n", + cmailMove[lastLoadGameNumber - 1], lastLoadGameNumber); + + sprintf(string, + "%s.game.out.%d", appData.cmailGameName, lastLoadGameNumber); + + f = fopen(string, "w"); + if (appData.oldSaveStyle) { + SaveGameOldStyle(f); /* also closes the file */ + + sprintf(string, "%s.pos.out", appData.cmailGameName); + f = fopen(string, "w"); + SavePosition(f, 0, NULL); /* also closes the file */ + } else { + fprintf(f, "{--------------\n"); + PrintPosition(f, currentMove); + fprintf(f, "--------------}\n\n"); + + SaveGame(f, 0, NULL); /* also closes the file*/ + } + + cmailMoveRegistered[lastLoadGameNumber - 1] = TRUE; + nCmailMovesRegistered ++; + } else if (nCmailGames == 1) { + DisplayError("You have not made a move yet", 0); + return FALSE; + } + + return TRUE; +} + +void +MailMoveEvent() +{ + static char *partCommandString = "cmail -xv%s -remail -game %s 2>&1"; + FILE *commandOutput; + char buffer[MSG_SIZ], msg[MSG_SIZ], string[MSG_SIZ]; + int nBytes = 0; /* Suppress warnings on uninitialized variables */ + int nBuffers; + int i; + int archived; + char *arcDir; + + if (! cmailMsgLoaded) { + DisplayError("The cmail message is not loaded.\nUse Reload CMail Message and make your move again.", 0); + return; + } + + if (nCmailGames == nCmailResults) { + DisplayError("No unfinished games", 0); + return; + } + +#if CMAIL_PROHIBIT_REMAIL + if (cmailMailedMove) { + sprintf(msg, "You have already mailed a move.\nWait until a move arrives from your opponent.\nTo resend the same move, type\n\"cmail -remail -game %s\"\non the command line.", appData.cmailGameName); + DisplayError(msg, 0); + return; + } +#endif + + if (! (cmailMailedMove || RegisterMove())) return; + + if ( cmailMailedMove + || (nCmailMovesRegistered + nCmailResults == nCmailGames)) { + sprintf(string, partCommandString, + appData.debugMode ? " -v" : "", appData.cmailGameName); + commandOutput = popen(string, "r"); + + if (commandOutput == NULL) { + DisplayError("Failed to invoke cmail", 0); + } else { + for (nBuffers = 0; (! feof(commandOutput)); nBuffers ++) { + nBytes = fread(buffer, 1, MSG_SIZ - 1, commandOutput); + } + if (nBuffers > 1) { + (void) memcpy(msg, buffer + nBytes, MSG_SIZ - nBytes - 1); + (void) memcpy(msg + MSG_SIZ - nBytes - 1, buffer, nBytes); + nBytes = MSG_SIZ - 1; + } else { + (void) memcpy(msg, buffer, nBytes); + } + *(msg + nBytes) = '\0'; /* \0 for end-of-string*/ + + if(StrStr(msg, "Mailed cmail message to ") != NULL) { + cmailMailedMove = TRUE; /* Prevent >1 moves */ + + archived = TRUE; + for (i = 0; i < nCmailGames; i ++) { + if (cmailResult[i] == CMAIL_NOT_RESULT) { + archived = FALSE; + } + } + if ( archived + && ( (arcDir = (char *) getenv("CMAIL_ARCDIR")) + != NULL)) { + sprintf(buffer, "%s/%s.%s.archive", + arcDir, + appData.cmailGameName, + gameInfo.date); + LoadGameFromFile(buffer, 1, buffer, FALSE); + cmailMsgLoaded = FALSE; + } + } + + DisplayInformation(msg); + pclose(commandOutput); + } + } else { + if ((*cmailMsg) != '\0') { + DisplayInformation(cmailMsg); + } + } + + return; +} + +char * +CmailMsg() +{ + int prependComma = 0; + char number[5]; + char string[MSG_SIZ]; /* Space for game-list */ + int i; + + if (!cmailMsgLoaded) return ""; + + if (cmailMailedMove) { + sprintf(cmailMsg, "Waiting for reply from opponent\n"); + } else { + /* Create a list of games left */ + sprintf(string, "["); + for (i = 0; i < nCmailGames; i ++) { + if (! ( cmailMoveRegistered[i] + || (cmailResult[i] == CMAIL_OLD_RESULT))) { + if (prependComma) { + sprintf(number, ",%d", i + 1); + } else { + sprintf(number, "%d", i + 1); + prependComma = 1; + } + + strcat(string, number); + } + } + strcat(string, "]"); + + if (nCmailMovesRegistered + nCmailResults == 0) { + switch (nCmailGames) { + case 1: + sprintf(cmailMsg, + "Still need to make move for game\n"); + break; + + case 2: + sprintf(cmailMsg, + "Still need to make moves for both games\n"); + break; + + default: + sprintf(cmailMsg, + "Still need to make moves for all %d games\n", + nCmailGames); + break; + } + } else { + switch (nCmailGames - nCmailMovesRegistered - nCmailResults) { + case 1: + sprintf(cmailMsg, + "Still need to make a move for game %s\n", + string); + break; + + case 0: + if (nCmailResults == nCmailGames) { + sprintf(cmailMsg, "No unfinished games\n"); + } else { + sprintf(cmailMsg, "Ready to send mail\n"); + } + break; + + default: + sprintf(cmailMsg, + "Still need to make moves for games %s\n", + string); + } + } + } + + return cmailMsg; +} + +void +ResetGameEvent() +{ + if (gameMode == Training) + SetTrainingModeOff(); + + Reset(TRUE, TRUE); + cmailMsgLoaded = FALSE; + if (appData.icsActive) { + SendToICS(ics_prefix); + SendToICS("refresh\n"); + } +} + +static int exiting = 0; + +void +ExitEvent(status) + int status; +{ + exiting++; + if (exiting > 2) { + /* Give up on clean exit */ + exit(status); + } + if (exiting > 1) { + /* Keep trying for clean exit */ + return; + } + + if (appData.icsActive && appData.colorize) Colorize(ColorNone, FALSE); + + if (telnetISR != NULL) { + RemoveInputSource(telnetISR); + } + if (icsPR != NoProc) { + DestroyChildProcess(icsPR, TRUE); + } + /* Save game if resource set and not already saved by GameEnds() */ + if (gameInfo.resultDetails == NULL && forwardMostMove > 0) { + if (*appData.saveGameFile != NULLCHAR) { + SaveGameToFile(appData.saveGameFile, TRUE); + } else if (appData.autoSaveGames) { + AutoSaveGame(); + } + if (*appData.savePositionFile != NULLCHAR) { + SavePositionToFile(appData.savePositionFile); + } + } + GameEnds((ChessMove) 0, NULL, GE_PLAYER); + + /* Kill off chess programs */ + if (first.pr != NoProc) { + ExitAnalyzeMode(); + SendToProgram("quit\n", &first); + DestroyChildProcess(first.pr, first.useSigterm); + } + if (second.pr != NoProc) { + SendToProgram("quit\n", &second); + DestroyChildProcess(second.pr, second.useSigterm); + } + if (first.isr != NULL) { + RemoveInputSource(first.isr); + } + if (second.isr != NULL) { + RemoveInputSource(second.isr); + } + + ShutDownFrontEnd(); + exit(status); +} + +void +PauseEvent() +{ + if (appData.debugMode) + fprintf(debugFP, "PauseEvent(): pausing %d\n", pausing); + if (pausing) { + pausing = FALSE; + ModeHighlight(); + if (gameMode == MachinePlaysWhite || + gameMode == MachinePlaysBlack) { + StartClocks(); + } else { + DisplayBothClocks(); + } + if (gameMode == PlayFromGameFile) { + if (appData.timeDelay >= 0) + AutoPlayGameLoop(); + } else if (gameMode == IcsExamining && pauseExamInvalid) { + Reset(FALSE, TRUE); + SendToICS(ics_prefix); + SendToICS("refresh\n"); + } else if (currentMove < forwardMostMove) { + ForwardInner(forwardMostMove); + } + pauseExamInvalid = FALSE; + } else { + switch (gameMode) { + default: + return; + case IcsExamining: + pauseExamForwardMostMove = forwardMostMove; + pauseExamInvalid = FALSE; + /* fall through */ + case IcsObserving: + case IcsPlayingWhite: + case IcsPlayingBlack: + pausing = TRUE; + ModeHighlight(); + return; + case PlayFromGameFile: + (void) StopLoadGameTimer(); + pausing = TRUE; + ModeHighlight(); + break; + case BeginningOfGame: + if (appData.icsActive) return; + /* else fall through */ + case MachinePlaysWhite: + case MachinePlaysBlack: + case TwoMachinesPlay: + if (forwardMostMove == 0) + return; /* don't pause if no one has moved */ + if ((gameMode == MachinePlaysWhite && + !WhiteOnMove(forwardMostMove)) || + (gameMode == MachinePlaysBlack && + WhiteOnMove(forwardMostMove))) { + StopClocks(); + } + pausing = TRUE; + ModeHighlight(); + break; + } + } +} + +void +EditCommentEvent() +{ + char title[MSG_SIZ]; + + if (currentMove < 1 || parseList[currentMove - 1][0] == NULLCHAR) { + strcpy(title, "Edit comment"); + } else { + sprintf(title, "Edit comment on %d.%s%s", (currentMove - 1) / 2 + 1, + WhiteOnMove(currentMove - 1) ? " " : ".. ", + parseList[currentMove - 1]); + } + + EditCommentPopUp(currentMove, title, commentList[currentMove]); +} + + +void +EditTagsEvent() +{ + char *tags = PGNTags(&gameInfo); + EditTagsPopUp(tags); + free(tags); +} + +void +AnalyzeModeEvent() +{ + if (appData.noChessProgram || gameMode == AnalyzeMode) + return; + + /* Engine Room enable */ + /* We need a AnalysisDisplay(TRUE) for timer */ + appData.AnalysisWindow = TRUE; + + if (gameMode != AnalyzeFile) { + EditGameEvent(); + if (gameMode != EditGame) return; + ResurrectChessProgram(); + SendToProgram("analyze\n", &first); + first.analyzing = TRUE; + /*first.maybeThinking = TRUE;*/ + first.maybeThinking = FALSE; /* avoid killing GNU Chess */ + } + gameMode = AnalyzeMode; + pausing = FALSE; + ModeHighlight(); + SetGameInfo(); + StartAnalysisClock(); + GetTimeMark(&lastNodeCountTime); + lastNodeCount = 0; + PeriodicUpdatesEvent(TRUE); +} + +/* daniel */ +void IcsAnalyze(newState) +int newState; + +{ + if (appData.noChessProgram) { + DisplayFatalError("ICS-Analysis requires a chess engine", 0, 1); + return; + } + + if (!newState && first.analyzing) { + if (appData.debugMode) fprintf(debugFP, "ICS-Analyze: Shutting down engine\n"); + ExitAnalyzeMode(); + DisplayMessage("","Close ICS engine analyse..."); + return; + } + + if (gameMode != IcsObserving) { + MessageBox(0,"You are not observing a game", + "ICS Engine Analyse", MB_OK); + appData.icsAnalyze = FALSE; + /* Set state for GUI */ + appData.icsEngineNone = TRUE; + appData.icsEngineWhisper = FALSE; + appData.icsEngineKibitz = FALSE; + appData.icsEngineTell = FALSE; + appData.icsAnalyzeOutPut = 4; + return; + } + + if (first.analysisSupport == FALSE) { + MessageBox(0,"Sorry, this engine does not support analyze", + "ICS Engine Analyse", MB_OK); + return; + } + + if (newState) { + if (appData.debugMode) fprintf(debugFP, "Starting ICS analyze\n"); + DisplayMessage("","Starting ICS engine analyse"); + if (!appData.icsWBprotoAgr) { + /* safty */ + /* Wo do that only if we start new or have a problem */ + SendToProgram("new\n", &first); + SendToProgram("post\n", &first); + SendToProgram("force\n", &first); + FeedMovesToProgram(&first, currentMove); + SendToProgram("analyze\n", &first); + } else { + /* hard */ + SendToProgram("exit\n", &first); + SendToProgram("new\n", &first); + SendToProgram("post\n", &first); + SendToProgram("hart\n", &first); + SendToProgram("force\n", &first); + FeedMovesToProgram(&first, currentMove); + SendToProgram("analyze\n", &first); + SendToProgram(".\n", &first); + } + PeriodicUpdatesEvent(TRUE); /* appData.periodicUpdates */ + first.analyzing = TRUE; /* Used for GUI and other ways */ + } +} + +void +IcsAnalyzeWindowUp() +{ + /* Using allso for startup Engine Room + * So function name looks like mismatch + * Change it for a better program style - + * but this is not crirical + */ + + if (appData.AnalysisWindow) { + ClearProgramStats(); + DisplayAnalysis(0,0); + PeriodicUpdatesEvent(TRUE); + } + /* StartAnalysisClock check gameMode */ + if (gameMode == AnalyzeMode || gameMode == AnalyzeFile || + appData.icsAnalyze || appData.AnalysisWindow) { + StartAnalysisClock(); + } + GetTimeMark(&lastNodeCountTime); + lastNodeCount = 0; /* importent */ +} + +void +AnalyzeFileEvent() +{ + if (appData.noChessProgram || gameMode == AnalyzeFile) + return; + + /* Engine Room */ + /* We need a DisplayAnalysis(TRUE); */ + appData.AnalysisWindow = TRUE; + + if (gameMode != AnalyzeMode) { + EditGameEvent(); + if (gameMode != EditGame) return; + ResurrectChessProgram(); + SendToProgram("analyze\n", &first); + first.analyzing = TRUE; + /*first.maybeThinking = TRUE;*/ + first.maybeThinking = FALSE; /* avoid killing GNU Chess */ + } + gameMode = AnalyzeFile; + pausing = FALSE; + ModeHighlight(); + SetGameInfo(); + + StartAnalysisClock(); + GetTimeMark(&lastNodeCountTime); + lastNodeCount = 0; +} + +void +MachineWhiteEvent() +{ + char buf[MSG_SIZ]; + + if (appData.noChessProgram || (gameMode == MachinePlaysWhite)) + return; + + + if (gameMode == PlayFromGameFile || + gameMode == TwoMachinesPlay || + gameMode == Training || + gameMode == AnalyzeMode || + gameMode == EndOfGame) + EditGameEvent(); + + if (gameMode == EditPosition) + EditPositionDone(); + + if (!WhiteOnMove(currentMove)) { + DisplayError("It is not White's turn", 0); + return; + } + + if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) + ExitAnalyzeMode(); + + + if (gameMode == EditGame || gameMode == AnalyzeMode || + gameMode == AnalyzeFile) + TruncateGame(); + + ResurrectChessProgram(); /* in case it isn't running */ + gameMode = MachinePlaysWhite; + pausing = FALSE; + ModeHighlight(); + SetGameInfo(); + sprintf(buf, "%s vs. %s", gameInfo.white, gameInfo.black); + DisplayTitle(buf); + if (first.sendName) { + sprintf(buf, "name %s\n", gameInfo.black); + SendToProgram(buf, &first); + } + if (first.sendTime) { + if (first.useColors) { + SendToProgram("black\n", &first); /*gnu kludge*/ + } + SendTimeRemaining(&first, TRUE); + } + if (first.useColors) { + SendToProgram("white\ngo\n", &first); + } else { + SendToProgram("go\n", &first); + } + SetMachineThinkingEnables(); + first.maybeThinking = TRUE; + StartClocks(); + + if (appData.autoFlipView && !flipView) { + flipView = !flipView; + DrawPosition(FALSE, NULL); + } + if (appData.AnalysisWindow) appData.periodicUpdates = TRUE; +} + +void +MachineBlackEvent() +{ + char buf[MSG_SIZ]; + + if (appData.noChessProgram || (gameMode == MachinePlaysBlack)) + return; + + + if (gameMode == PlayFromGameFile || + gameMode == TwoMachinesPlay || + gameMode == Training || + gameMode == AnalyzeMode || + gameMode == EndOfGame) + EditGameEvent(); + + if (gameMode == EditPosition) + EditPositionDone(); + + if (WhiteOnMove(currentMove)) { + DisplayError("It is not Black's turn", 0); + return; + } + + if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) + ExitAnalyzeMode(); + + if (gameMode == EditGame || gameMode == AnalyzeMode || + gameMode == AnalyzeFile) + TruncateGame(); + + ResurrectChessProgram(); /* in case it isn't running */ + gameMode = MachinePlaysBlack; + pausing = FALSE; + ModeHighlight(); + SetGameInfo(); + sprintf(buf, "%s vs. %s", gameInfo.white, gameInfo.black); + DisplayTitle(buf); + if (first.sendName) { + sprintf(buf, "name %s\n", gameInfo.white); + SendToProgram(buf, &first); + } + if (first.sendTime) { + if (first.useColors) { + SendToProgram("white\n", &first); /*gnu kludge*/ + } + SendTimeRemaining(&first, FALSE); + } + if (first.useColors) { + SendToProgram("black\ngo\n", &first); + } else { + SendToProgram("go\n", &first); + } + SetMachineThinkingEnables(); + first.maybeThinking = TRUE; + StartClocks(); + + if (appData.autoFlipView && flipView) { + flipView = !flipView; + DrawPosition(FALSE, NULL); + } + if (appData.AnalysisWindow) appData.periodicUpdates = TRUE; +} + + +void +DisplayTwoMachinesTitle() +{ + char buf[MSG_SIZ]; + if (appData.matchGames > 0) { + if (first.twoMachinesColor[0] == 'w') { + sprintf(buf, "%s vs. %s (%d-%d-%d)", + gameInfo.white, gameInfo.black, + first.matchWins, second.matchWins, + matchGame - 1 - (first.matchWins + second.matchWins)); + } else { + sprintf(buf, "%s vs. %s (%d-%d-%d)", + gameInfo.white, gameInfo.black, + second.matchWins, first.matchWins, + matchGame - 1 - (first.matchWins + second.matchWins)); + } + } else { + sprintf(buf, "%s vs. %s", gameInfo.white, gameInfo.black); + } + DisplayTitle(buf); +} + +void +TwoMachinesEvent P((void)) +{ + int i; + char buf[MSG_SIZ]; + ChessProgramState *onmove; + + if (appData.noChessProgram) return; + + switch (gameMode) { + case TwoMachinesPlay: + return; + case MachinePlaysWhite: + case MachinePlaysBlack: + if (WhiteOnMove(forwardMostMove) == (gameMode == MachinePlaysWhite)) { + DisplayError("Wait until your turn,\nor select Move Now", 0); + return; + } + /* fall through */ + case BeginningOfGame: + case PlayFromGameFile: + case EndOfGame: + EditGameEvent(); + if (gameMode != EditGame) return; + break; + case EditPosition: + EditPositionDone(); + break; + case AnalyzeMode: + case AnalyzeFile: + ExitAnalyzeMode(); + break; + case EditGame: + default: + break; + } + + forwardMostMove = currentMove; + ResurrectChessProgram(); /* in case first program isn't running */ + + if (second.pr == NULL) { + StartChessProgram(&second); + if (second.protocolVersion == 1) { + TwoMachinesEventIfReady(); + } else { + /* kludge: allow timeout for initial "feature" command */ + FreezeUI(); + DisplayMessage("", "Starting second chess program"); + ScheduleDelayedEvent(TwoMachinesEventIfReady, FEATURE_TIMEOUT); + } + return; + } + DisplayMessage("", ""); + InitChessProgram(&second); + SendToProgram("force\n", &second); + if (startedFromSetupPosition) { + SendBoard(&second, backwardMostMove); + } + for (i = backwardMostMove; i < forwardMostMove; i++) { + SendMoveToProgram(i, &second); + } + + gameMode = TwoMachinesPlay; + pausing = FALSE; + ModeHighlight(); + SetGameInfo(); + DisplayTwoMachinesTitle(); + firstMove = TRUE; + if ((first.twoMachinesColor[0] == 'w') == WhiteOnMove(forwardMostMove)) { + onmove = &first; + } else { + onmove = &second; + } + + SendToProgram(first.computerString, &first); + if (first.sendName) { + sprintf(buf, "name %s\n", second.tidy); + SendToProgram(buf, &first); + } + SendToProgram(second.computerString, &second); + if (second.sendName) { + sprintf(buf, "name %s\n", first.tidy); + SendToProgram(buf, &second); + } + + if (!first.sendTime || !second.sendTime) { + ResetClocks(); + timeRemaining[0][forwardMostMove] = whiteTimeRemaining; + timeRemaining[1][forwardMostMove] = blackTimeRemaining; + } + if (onmove->sendTime) { + if (onmove->useColors) { + SendToProgram(onmove->other->twoMachinesColor, onmove); /*gnu kludge*/ + } + SendTimeRemaining(onmove, WhiteOnMove(forwardMostMove)); + } + if (onmove->useColors) { + SendToProgram(onmove->twoMachinesColor, onmove); + } + SendToProgram("go\n", onmove); + onmove->maybeThinking = TRUE; + SetMachineThinkingEnables(); + + StartClocks(); +} + +void +TrainingEvent() +{ + if (gameMode == Training) { + SetTrainingModeOff(); + gameMode = PlayFromGameFile; + DisplayMessage("", "Training mode off"); + } else { + gameMode = Training; + animateTraining = appData.animate; + + /* make sure we are not already at the end of the game */ + if (currentMove < forwardMostMove) { + SetTrainingModeOn(); + DisplayMessage("", "Training mode on"); + } else { + gameMode = PlayFromGameFile; + DisplayError("Already at end of game", 0); + } + } + ModeHighlight(); +} + +void +IcsClientEvent() +{ + if (!appData.icsActive) return; + switch (gameMode) { + case IcsPlayingWhite: + case IcsPlayingBlack: + case IcsObserving: + case IcsIdle: + case BeginningOfGame: + case IcsExamining: + return; + + case EditGame: + break; + + case EditPosition: + EditPositionDone(); + break; + + case AnalyzeMode: + case AnalyzeFile: + ExitAnalyzeMode(); + break; + + default: + EditGameEvent(); + break; + } + + gameMode = IcsIdle; + ModeHighlight(); + return; +} + + +void +EditGameEvent() +{ + int i; + + switch (gameMode) { + case Training: + SetTrainingModeOff(); + break; + case MachinePlaysWhite: + case MachinePlaysBlack: + case BeginningOfGame: + SendToProgram("force\n", &first); + SetUserThinkingEnables(); + break; + case PlayFromGameFile: + (void) StopLoadGameTimer(); + if (gameFileFP != NULL) { + gameFileFP = NULL; + } + break; + case EditPosition: + EditPositionDone(); + break; + case AnalyzeMode: + case AnalyzeFile: + ExitAnalyzeMode(); + SendToProgram("force\n", &first); + break; + case TwoMachinesPlay: + GameEnds((ChessMove) 0, NULL, GE_PLAYER); + ResurrectChessProgram(); + SetUserThinkingEnables(); + break; + case EndOfGame: + ResurrectChessProgram(); + break; + case IcsPlayingBlack: + case IcsPlayingWhite: + DisplayError("Warning: You are still playing a game", 0); + break; + case IcsObserving: + break; + case IcsExamining: + DisplayError("Warning: You are still examining a game", 0); + break; + case IcsIdle: + break; + case EditGame: + default: + return; + } + + pausing = FALSE; + /* daniel */ + if (gameMode != IcsObserving) StopClocks(); + + first.offeredDraw = second.offeredDraw = 0; + + if (gameMode == PlayFromGameFile) { + whiteTimeRemaining = timeRemaining[0][currentMove]; + blackTimeRemaining = timeRemaining[1][currentMove]; + DisplayTitle(""); + } + + if (gameMode == MachinePlaysWhite || + gameMode == MachinePlaysBlack || + gameMode == TwoMachinesPlay || + gameMode == EndOfGame) { + i = forwardMostMove; + while (i > currentMove) { + SendToProgram("undo\n", &first); + i--; + } + whiteTimeRemaining = timeRemaining[0][currentMove]; + blackTimeRemaining = timeRemaining[1][currentMove]; + DisplayBothClocks(); + if (whiteFlag || blackFlag) { + whiteFlag = blackFlag = 0; + } + DisplayTitle(""); + } + + gameMode = EditGame; + ModeHighlight(); + SetGameInfo(); +} + + +void +EditPositionEvent() +{ + if (gameMode == EditPosition) { + EditGameEvent(); + return; + } + + EditGameEvent(); + if (gameMode != EditGame) return; + + gameMode = EditPosition; + ModeHighlight(); + SetGameInfo(); + if (currentMove > 0) + CopyBoard(boards[0], boards[currentMove]); + + blackPlaysFirst = !WhiteOnMove(currentMove); + ResetClocks(); + currentMove = forwardMostMove = backwardMostMove = 0; + HistorySet(parseList, backwardMostMove, forwardMostMove, currentMove-1); + DisplayMove(-1); +} + +void +ExitAnalyzeMode() +{ + if (first.analysisSupport && first.analyzing) { + SendToProgram("exit\n", &first); + first.analyzing = FALSE; + } + AnalysisPopDown(); + thinkOutput[0] = NULLCHAR; +} + +void +EditPositionDone() +{ + startedFromSetupPosition = TRUE; + InitChessProgram(&first); + SendToProgram("force\n", &first); + if (blackPlaysFirst) { + strcpy(moveList[0], ""); + strcpy(parseList[0], ""); + currentMove = forwardMostMove = backwardMostMove = 1; + CopyBoard(boards[1], boards[0]); + } else { + currentMove = forwardMostMove = backwardMostMove = 0; + } + SendBoard(&first, forwardMostMove); + DisplayTitle(""); + timeRemaining[0][forwardMostMove] = whiteTimeRemaining; + timeRemaining[1][forwardMostMove] = blackTimeRemaining; + gameMode = EditGame; + ModeHighlight(); + HistorySet(parseList, backwardMostMove, forwardMostMove, currentMove-1); +} + +/* Pause for `ms' milliseconds */ +/* !! Ugh, this is a kludge. Fix it sometime. --tpm */ +void +TimeDelay(ms) + long ms; +{ + TimeMark m1, m2; + + GetTimeMark(&m1); + do { + GetTimeMark(&m2); + } while (SubtractTimeMarks(&m2, &m1) < ms); +} + +/* !! Ugh, this is a kludge. Fix it sometime. --tpm */ +void +SendMultiLineToICS(buf) + char *buf; +{ + char temp[MSG_SIZ+1], *p; + int len; + + len = strlen(buf); + if (len > MSG_SIZ) + len = MSG_SIZ; + + strncpy(temp, buf, len); + temp[len] = 0; + + p = temp; + while (*p) { + if (*p == '\n' || *p == '\r') + *p = ' '; + ++p; + } + + strcat(temp, "\n"); + SendToICS(temp); + SendToPlayer(temp, strlen(temp)); +} + +void +SetWhiteToPlayEvent() +{ + if (gameMode == EditPosition) { + blackPlaysFirst = FALSE; + DisplayBothClocks(); /* works because currentMove is 0 */ + } else if (gameMode == IcsExamining) { + SendToICS(ics_prefix); + SendToICS("tomove white\n"); + } +} + +void +SetBlackToPlayEvent() +{ + if (gameMode == EditPosition) { + blackPlaysFirst = TRUE; + currentMove = 1; /* kludge */ + DisplayBothClocks(); + currentMove = 0; + } else if (gameMode == IcsExamining) { + SendToICS(ics_prefix); + SendToICS("tomove black\n"); + } +} + +void +EditPositionMenuEvent(selection, x, y) + ChessSquare selection; + int x, y; +{ + char buf[MSG_SIZ]; + + if (gameMode != EditPosition && gameMode != IcsExamining) return; + + switch (selection) { + case ClearBoard: + if (gameMode == IcsExamining && ics_type == ICS_FICS) { + SendToICS(ics_prefix); + SendToICS("bsetup clear\n"); + } else if (gameMode == IcsExamining && ics_type == ICS_ICC) { + SendToICS(ics_prefix); + SendToICS("clearboard\n"); + } else { + for (x = 0; x < BOARD_SIZE; x++) { + for (y = 0; y < BOARD_SIZE; y++) { + if (gameMode == IcsExamining) { + if (boards[currentMove][y][x] != EmptySquare) { + sprintf(buf, "%sx@%c%c\n", ics_prefix, + 'a' + x, '1' + y); + SendToICS(buf); + } + } else { + boards[0][y][x] = EmptySquare; + } + } + } + } + if (gameMode == EditPosition) { + DrawPosition(FALSE, boards[0]); + } + break; + + case WhitePlay: + SetWhiteToPlayEvent(); + break; + + case BlackPlay: + SetBlackToPlayEvent(); + break; + + case EmptySquare: + if (gameMode == IcsExamining) { + sprintf(buf, "%sx@%c%c\n", ics_prefix, 'a' + x, '1' + y); + SendToICS(buf); + } else { + boards[0][y][x] = EmptySquare; + DrawPosition(FALSE, boards[0]); + } + break; + + default: + if (gameMode == IcsExamining) { + sprintf(buf, "%s%c@%c%c\n", ics_prefix, + PieceToChar(selection), 'a' + x, '1' + y); + SendToICS(buf); + } else { + boards[0][y][x] = selection; + DrawPosition(FALSE, boards[0]); + } + break; + } +} + + +void +DropMenuEvent(selection, x, y) + ChessSquare selection; + int x, y; +{ + ChessMove moveType; + + switch (gameMode) { + case IcsPlayingWhite: + case MachinePlaysBlack: + if (!WhiteOnMove(currentMove)) { + DisplayMoveError("It is Black's turn"); + return; + } + moveType = WhiteDrop; + break; + case IcsPlayingBlack: + case MachinePlaysWhite: + if (WhiteOnMove(currentMove)) { + DisplayMoveError("It is White's turn"); + return; + } + moveType = BlackDrop; + break; + case EditGame: + moveType = WhiteOnMove(currentMove) ? WhiteDrop : BlackDrop; + break; + default: + return; + } + + if (moveType == BlackDrop && selection < BlackPawn) { + selection = (ChessSquare) ((int) selection + + (int) BlackPawn - (int) WhitePawn); + } + if (boards[currentMove][y][x] != EmptySquare) { + DisplayMoveError("That square is occupied"); + return; + } + + FinishMove(moveType, (int) selection, DROP_RANK, x, y, NULLCHAR); +} + +void +AcceptEvent() +{ + /* Accept a pending offer of any kind from opponent */ + + if (appData.icsActive) { + SendToICS(ics_prefix); + SendToICS("accept\n"); + } else if (cmailMsgLoaded) { + if (currentMove == cmailOldMove && + commentList[cmailOldMove] != NULL && + StrStr(commentList[cmailOldMove], WhiteOnMove(cmailOldMove) ? + "Black offers a draw" : "White offers a draw")) { + TruncateGame(); + GameEnds(GameIsDrawn, "Draw agreed", GE_PLAYER); + cmailMoveType[lastLoadGameNumber - 1] = CMAIL_ACCEPT; + } else { + DisplayError("There is no pending offer on this move", 0); + cmailMoveType[lastLoadGameNumber - 1] = CMAIL_MOVE; + } + } else { + /* Not used for offers from chess program */ + } +} + +void +DeclineEvent() +{ + /* Decline a pending offer of any kind from opponent */ + + if (appData.icsActive) { + SendToICS(ics_prefix); + SendToICS("decline\n"); + } else if (cmailMsgLoaded) { + if (currentMove == cmailOldMove && + commentList[cmailOldMove] != NULL && + StrStr(commentList[cmailOldMove], WhiteOnMove(cmailOldMove) ? + "Black offers a draw" : "White offers a draw")) { +#ifdef NOTDEF + AppendComment(cmailOldMove, "Draw declined"); + DisplayComment(cmailOldMove - 1, "Draw declined"); +#endif /*NOTDEF*/ + } else { + DisplayError("There is no pending offer on this move", 0); + } + } else { + /* Not used for offers from chess program */ + } +} + +void +RematchEvent() +{ + /* Issue ICS rematch command */ + if (appData.icsActive) { + SendToICS(ics_prefix); + SendToICS("rematch\n"); + } +} + +void +CallFlagEvent() +{ + /* Call your opponent's flag (claim a win on time) */ + if (appData.icsActive) { + SendToICS(ics_prefix); + SendToICS("flag\n"); + } else { + switch (gameMode) { + default: + return; + case MachinePlaysWhite: + if (whiteFlag) { + if (blackFlag) + GameEnds(GameIsDrawn, "Both players ran out of time", + GE_PLAYER); + else + GameEnds(BlackWins, "Black wins on time", GE_PLAYER); + } else { + DisplayError("Your opponent is not out of time", 0); + } + break; + case MachinePlaysBlack: + if (blackFlag) { + if (whiteFlag) + GameEnds(GameIsDrawn, "Both players ran out of time", + GE_PLAYER); + else + GameEnds(WhiteWins, "White wins on time", GE_PLAYER); + } else { + DisplayError("Your opponent is not out of time", 0); + } + break; + } + } +} + +void +DrawEvent() +{ + /* Offer draw or accept pending draw offer from opponent */ + + if (appData.icsActive) { + /* Note: tournament rules require draw offers to be + made after you make your move but before you punch + your clock. Currently ICS doesn't let you do that; + instead, you immediately punch your clock after making + a move, but you can offer a draw at any time. */ + + SendToICS(ics_prefix); + SendToICS("draw\n"); + } else if (cmailMsgLoaded) { + if (currentMove == cmailOldMove && + commentList[cmailOldMove] != NULL && + StrStr(commentList[cmailOldMove], WhiteOnMove(cmailOldMove) ? + "Black offers a draw" : "White offers a draw")) { + GameEnds(GameIsDrawn, "Draw agreed", GE_PLAYER); + cmailMoveType[lastLoadGameNumber - 1] = CMAIL_ACCEPT; + } else if (currentMove == cmailOldMove + 1) { + char *offer = WhiteOnMove(cmailOldMove) ? + "White offers a draw" : "Black offers a draw"; + AppendComment(currentMove, offer); + DisplayComment(currentMove - 1, offer); + cmailMoveType[lastLoadGameNumber - 1] = CMAIL_DRAW; + } else { + DisplayError("You must make your move before offering a draw", 0); + cmailMoveType[lastLoadGameNumber - 1] = CMAIL_MOVE; + } + } else if (first.offeredDraw) { + GameEnds(GameIsDrawn, "Draw agreed", GE_XBOARD); + } else { + if (first.sendDrawOffers) { + SendToProgram("draw\n", &first); + userOfferedDraw = TRUE; + } + } +} + +void +AdjournEvent() +{ + /* Offer Adjourn or accept pending Adjourn offer from opponent */ + + if (appData.icsActive) { + SendToICS(ics_prefix); + SendToICS("adjourn\n"); + } else { + /* Currently GNU Chess doesn't offer or accept Adjourns */ + } +} + + +void +AbortEvent() +{ + /* Offer Abort or accept pending Abort offer from opponent */ + + if (appData.icsActive) { + SendToICS(ics_prefix); + SendToICS("abort\n"); + } else { + GameEnds(GameUnfinished, "Game aborted", GE_PLAYER); + } +} + +void +ResignEvent() +{ + /* Resign. You can do this even if it's not your turn. */ + + if (appData.icsActive) { + SendToICS(ics_prefix); + SendToICS("resign\n"); + } else { + switch (gameMode) { + case MachinePlaysWhite: + GameEnds(WhiteWins, "Black resigns", GE_PLAYER); + break; + case MachinePlaysBlack: + GameEnds(BlackWins, "White resigns", GE_PLAYER); + break; + case EditGame: + if (cmailMsgLoaded) { + TruncateGame(); + if (WhiteOnMove(cmailOldMove)) { + GameEnds(BlackWins, "White resigns", GE_PLAYER); + } else { + GameEnds(WhiteWins, "Black resigns", GE_PLAYER); + } + cmailMoveType[lastLoadGameNumber - 1] = CMAIL_RESIGN; + } + break; + default: + break; + } + } +} + + +void +StopObservingEvent() +{ + /* Stop observing current games */ + SendToICS(ics_prefix); + SendToICS("unobserve\n"); +} + +void +StopExaminingEvent() +{ + /* Stop observing current game */ + SendToICS(ics_prefix); + SendToICS("unexamine\n"); +} + +void +ForwardInner(target) + int target; +{ + int limit; + + if (appData.debugMode) + fprintf(debugFP, "ForwardInner(%d), current %d, forward %d\n", + target, currentMove, forwardMostMove); + + if (gameMode == EditPosition) + return; + + if (gameMode == PlayFromGameFile && !pausing) + PauseEvent(); + + if (gameMode == IcsExamining && pausing) + limit = pauseExamForwardMostMove; + else + limit = forwardMostMove; + + if (target > limit) target = limit; + + if (target > 0 && moveList[target - 1][0]) { + int fromX, fromY, toX, toY; + toX = moveList[target - 1][2] - 'a'; + toY = moveList[target - 1][3] - '1'; + if (moveList[target - 1][1] == '@') { + if (appData.highlightLastMove) { + SetHighlights(-1, -1, toX, toY); + } + } else { + fromX = moveList[target - 1][0] - 'a'; + fromY = moveList[target - 1][1] - '1'; + if (target == currentMove + 1) { + AnimateMove(boards[currentMove], fromX, fromY, toX, toY); + } + if (appData.highlightLastMove) { + SetHighlights(fromX, fromY, toX, toY); + } + } + } + if (gameMode == EditGame || gameMode == AnalyzeMode || + gameMode == Training || gameMode == PlayFromGameFile || + gameMode == AnalyzeFile) { + while (currentMove < target) { + SendMoveToProgram(currentMove++, &first); + } + } else { + currentMove = target; + } + + if (gameMode == EditGame || gameMode == EndOfGame) { + whiteTimeRemaining = timeRemaining[0][currentMove]; + blackTimeRemaining = timeRemaining[1][currentMove]; + } + DisplayBothClocks(); + DisplayMove(currentMove - 1); + DrawPosition(FALSE, boards[currentMove]); + HistorySet(parseList,backwardMostMove,forwardMostMove,currentMove-1); + if (commentList[currentMove] && !matchMode && gameMode != Training) { + DisplayComment(currentMove - 1, commentList[currentMove]); + } +} + + +void +ForwardEvent() +{ + if (gameMode == IcsExamining && !pausing) { + SendToICS(ics_prefix); + SendToICS("forward\n"); + } else { + ForwardInner(currentMove + 1); + } +} + +void +ToEndEvent() +{ + if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) { + /* to optimze, we temporarily turn off analysis mode while we feed + * the remaining moves to the engine. Otherwise we get analysis output + * after each move. + */ + if (first.analysisSupport) { + SendToProgram("exit\nforce\n", &first); + first.analyzing = FALSE; + } + } + + if (gameMode == IcsExamining && !pausing) { + SendToICS(ics_prefix); + SendToICS("forward 999999\n"); + } else { + ForwardInner(forwardMostMove); + } + + if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) { + /* we have fed all the moves, so reactivate analysis mode */ + SendToProgram("analyze\n", &first); + first.analyzing = TRUE; + /*first.maybeThinking = TRUE;*/ + first.maybeThinking = FALSE; /* avoid killing GNU Chess */ + } +} + +void +BackwardInner(target) + int target; +{ + if (appData.debugMode) + fprintf(debugFP, "BackwardInner(%d), current %d, forward %d\n", + target, currentMove, forwardMostMove); + + if (gameMode == EditPosition) return; + if (currentMove <= backwardMostMove) { + ClearHighlights(); + DrawPosition(FALSE, boards[currentMove]); + return; + } + if (gameMode == PlayFromGameFile && !pausing) + PauseEvent(); + + if (moveList[target][0]) { + int fromX, fromY, toX, toY; + toX = moveList[target][2] - 'a'; + toY = moveList[target][3] - '1'; + if (moveList[target][1] == '@') { + if (appData.highlightLastMove) { + SetHighlights(-1, -1, toX, toY); + } + } else { + fromX = moveList[target][0] - 'a'; + fromY = moveList[target][1] - '1'; + if (target == currentMove - 1) { + AnimateMove(boards[currentMove], toX, toY, fromX, fromY); + } + if (appData.highlightLastMove) { + SetHighlights(fromX, fromY, toX, toY); + } + } + } + if (gameMode == EditGame || gameMode==AnalyzeMode || + gameMode == PlayFromGameFile || gameMode == AnalyzeFile) { + while (currentMove > target) { + SendToProgram("undo\n", &first); + currentMove--; + } + } else { + currentMove = target; + } + + if (gameMode == EditGame || gameMode == EndOfGame) { + whiteTimeRemaining = timeRemaining[0][currentMove]; + blackTimeRemaining = timeRemaining[1][currentMove]; + } + DisplayBothClocks(); + DisplayMove(currentMove - 1); + DrawPosition(FALSE, boards[currentMove]); + HistorySet(parseList,backwardMostMove,forwardMostMove,currentMove-1); + if (commentList[currentMove] != NULL) { + DisplayComment(currentMove - 1, commentList[currentMove]); + } +} + +void +BackwardEvent() +{ + if (gameMode == IcsExamining && !pausing) { + SendToICS(ics_prefix); + SendToICS("backward\n"); + } else { + BackwardInner(currentMove - 1); + } +} + +void +ToStartEvent() +{ + if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) { + /* to optimze, we temporarily turn off analysis mode while we undo + * all the moves. Otherwise we get analysis output after each undo. + */ + if (first.analysisSupport) { + SendToProgram("exit\nforce\n", &first); + first.analyzing = FALSE; + } + } + + if (gameMode == IcsExamining && !pausing) { + SendToICS(ics_prefix); + SendToICS("backward 999999\n"); + } else { + BackwardInner(backwardMostMove); + } + + if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) { + /* we have fed all the moves, so reactivate analysis mode */ + SendToProgram("analyze\n", &first); + first.analyzing = TRUE; + /*first.maybeThinking = TRUE;*/ + first.maybeThinking = FALSE; /* avoid killing GNU Chess */ + } +} + +void +ToNrEvent(int to) +{ + if (gameMode == PlayFromGameFile && !pausing) PauseEvent(); + if (to >= forwardMostMove) to = forwardMostMove; + if (to <= backwardMostMove) to = backwardMostMove; + if (to < currentMove) { + BackwardInner(to); + } else { + ForwardInner(to); + } +} + +void +RevertEvent() +{ + if (gameMode != IcsExamining) { + DisplayError("You are not examining a game", 0); + return; + } + if (pausing) { + DisplayError("You can't revert while pausing", 0); + return; + } + SendToICS(ics_prefix); + SendToICS("revert\n"); +} + +void +RetractMoveEvent() +{ + switch (gameMode) { + case MachinePlaysWhite: + case MachinePlaysBlack: + if (WhiteOnMove(forwardMostMove) == (gameMode == MachinePlaysWhite)) { + DisplayError("Wait until your turn,\nor select Move Now", 0); + return; + } + if (forwardMostMove < 2) return; + currentMove = forwardMostMove = forwardMostMove - 2; + whiteTimeRemaining = timeRemaining[0][currentMove]; + blackTimeRemaining = timeRemaining[1][currentMove]; + DisplayBothClocks(); + DisplayMove(currentMove - 1); + ClearHighlights();/*!! could figure this out*/ + DrawPosition(FALSE, boards[currentMove]); + SendToProgram("remove\n", &first); + /*first.maybeThinking = TRUE;*/ /* GNU Chess does not ponder here */ + break; + + case BeginningOfGame: + default: + break; + + case IcsPlayingWhite: + case IcsPlayingBlack: + if (WhiteOnMove(forwardMostMove) == (gameMode == IcsPlayingWhite)) { + SendToICS(ics_prefix); + SendToICS("takeback 2\n"); + } else { + SendToICS(ics_prefix); + SendToICS("takeback 1\n"); + } + break; + } +} + +void +MoveNowEvent() +{ + ChessProgramState *cps; + + switch (gameMode) { + case MachinePlaysWhite: + if (!WhiteOnMove(forwardMostMove)) { + DisplayError("It is your turn", 0); + return; + } + cps = &first; + break; + case MachinePlaysBlack: + if (WhiteOnMove(forwardMostMove)) { + DisplayError("It is your turn", 0); + return; + } + cps = &first; + break; + case TwoMachinesPlay: + if (WhiteOnMove(forwardMostMove) == + (first.twoMachinesColor[0] == 'w')) { + cps = &first; + } else { + cps = &second; + } + break; + case BeginningOfGame: + default: + return; + } + SendToProgram("?\n", cps); +} + +void +TruncateGameEvent() +{ + EditGameEvent(); + if (gameMode != EditGame) return; + TruncateGame(); +} + +void +TruncateGame() +{ + if (forwardMostMove > currentMove) { + if (gameInfo.resultDetails != NULL) { + free(gameInfo.resultDetails); + gameInfo.resultDetails = NULL; + gameInfo.result = GameUnfinished; + } + forwardMostMove = currentMove; + HistorySet(parseList, backwardMostMove, forwardMostMove, + currentMove-1); + } +} + +void +HintEvent() +{ + if (appData.noChessProgram) return; + switch (gameMode) { + case MachinePlaysWhite: + if (WhiteOnMove(forwardMostMove)) { + DisplayError("Wait until your turn", 0); + return; + } + break; + case BeginningOfGame: + case MachinePlaysBlack: + if (!WhiteOnMove(forwardMostMove)) { + DisplayError("Wait until your turn", 0); + return; + } + break; + default: + DisplayError("No hint available", 0); + return; + } + SendToProgram("hint\n", &first); + hintRequested = TRUE; +} + +void +BookEvent() +{ + if (appData.noChessProgram) return; + switch (gameMode) { + case MachinePlaysWhite: + if (WhiteOnMove(forwardMostMove)) { + DisplayError("Wait until your turn", 0); + return; + } + break; + case BeginningOfGame: + case MachinePlaysBlack: + if (!WhiteOnMove(forwardMostMove)) { + DisplayError("Wait until your turn", 0); + return; + } + break; + case EditPosition: + EditPositionDone(); + break; + case TwoMachinesPlay: + return; + default: + break; + } + SendToProgram("bk\n", &first); + bookOutput[0] = NULLCHAR; + bookRequested = TRUE; +} + +void +AboutGameEvent() +{ + char *tags = PGNTags(&gameInfo); + TagsPopUp(tags, CmailMsg()); + free(tags); +} + +/* end button procedures */ + +void +PrintPosition(fp, move) + FILE *fp; + int move; +{ + int i, j; + + for (i = BOARD_SIZE - 1; i >= 0; i--) { + for (j = 0; j < BOARD_SIZE; j++) { + char c = PieceToChar(boards[move][i][j]); + fputc(c == 'x' ? '.' : c, fp); + fputc(j == BOARD_SIZE - 1 ? '\n' : ' ', fp); + } + } + if ((gameMode == EditPosition) ? !blackPlaysFirst : (move % 2 == 0)) + fprintf(fp, "white to play\n"); + else + fprintf(fp, "black to play\n"); +} + +void +PrintOpponents(fp) + FILE *fp; +{ + if (gameInfo.white != NULL) { + fprintf(fp, "\t%s vs. %s\n", gameInfo.white, gameInfo.black); + } else { + fprintf(fp, "\n"); + } +} + +/* Find last component of program's own name, using some heuristics */ +void +TidyProgramName(prog, host, buf) + char *prog, *host, buf[MSG_SIZ]; +{ + char *p, *q; + int local = (strcmp(host, "localhost") == 0); + while (!local && (p = strchr(prog, ';')) != NULL) { + p++; + while (*p == ' ') p++; + prog = p; + } + if (*prog == '"' || *prog == '\'') { + q = strchr(prog + 1, *prog); + } else { + q = strchr(prog, ' '); + } + if (q == NULL) q = prog + strlen(prog); + p = q; + while (p >= prog && *p != '/' && *p != '\\') p--; + p++; + if (q - p >= 4 && StrCaseCmp(q - 4, ".exe") == 0) q -= 4; + memcpy(buf, p, q - p); + buf[q - p] = NULLCHAR; + if (!local) { + strcat(buf, "@"); + strcat(buf, host); + } +} + +char * +TimeControlTagValue() +{ + char buf[MSG_SIZ]; + if (!appData.clockMode) { + strcpy(buf, "-"); + } else if (movesPerSession > 0) { + sprintf(buf, "%d/%ld", movesPerSession, timeControl/1000); + } else if (timeIncrement == 0) { + sprintf(buf, "%ld", timeControl/1000); + } else { + sprintf(buf, "%ld+%ld", timeControl/1000, timeIncrement/1000); + } + return StrSave(buf); +} + +void +SetGameInfo() +{ + /* This routine is used only for certain modes */ + VariantClass v = gameInfo.variant; + ClearGameInfo(&gameInfo); + gameInfo.variant = v; + + switch (gameMode) { + case MachinePlaysWhite: + gameInfo.event = StrSave("Computer chess game"); + gameInfo.site = StrSave(HostName()); + gameInfo.date = PGNDate(); + gameInfo.round = StrSave("-"); + gameInfo.white = StrSave(first.tidy); + gameInfo.black = StrSave(UserName()); + gameInfo.timeControl = TimeControlTagValue(); + break; + + case MachinePlaysBlack: + gameInfo.event = StrSave("Computer chess game"); + gameInfo.site = StrSave(HostName()); + gameInfo.date = PGNDate(); + gameInfo.round = StrSave("-"); + gameInfo.white = StrSave(UserName()); + gameInfo.black = StrSave(first.tidy); + gameInfo.timeControl = TimeControlTagValue(); + break; + + case TwoMachinesPlay: + gameInfo.event = StrSave("Computer chess game"); + gameInfo.site = StrSave(HostName()); + gameInfo.date = PGNDate(); + if (matchGame > 0) { + char buf[MSG_SIZ]; + sprintf(buf, "%d", matchGame); + gameInfo.round = StrSave(buf); + } else { + gameInfo.round = StrSave("-"); + } + if (first.twoMachinesColor[0] == 'w') { + gameInfo.white = StrSave(first.tidy); + gameInfo.black = StrSave(second.tidy); + } else { + gameInfo.white = StrSave(second.tidy); + gameInfo.black = StrSave(first.tidy); + } + gameInfo.timeControl = TimeControlTagValue(); + break; + + case EditGame: + gameInfo.event = StrSave("Edited game"); + gameInfo.site = StrSave(HostName()); + gameInfo.date = PGNDate(); + gameInfo.round = StrSave("-"); + gameInfo.white = StrSave("-"); + gameInfo.black = StrSave("-"); + break; + + case EditPosition: + gameInfo.event = StrSave("Edited position"); + gameInfo.site = StrSave(HostName()); + gameInfo.date = PGNDate(); + gameInfo.round = StrSave("-"); + gameInfo.white = StrSave("-"); + gameInfo.black = StrSave("-"); + break; + + case IcsPlayingWhite: + case IcsPlayingBlack: + case IcsObserving: + case IcsExamining: + break; + + case PlayFromGameFile: + gameInfo.event = StrSave("Game from non-PGN file"); + gameInfo.site = StrSave(HostName()); + gameInfo.date = PGNDate(); + gameInfo.round = StrSave("-"); + gameInfo.white = StrSave("?"); + gameInfo.black = StrSave("?"); + break; + + default: + break; + } +} + +void +ReplaceComment(index, text) + int index; + char *text; +{ + int len; + + while (*text == '\n') text++; + len = strlen(text); + while (len > 0 && text[len - 1] == '\n') len--; + + if (commentList[index] != NULL) + free(commentList[index]); + + if (len == 0) { + commentList[index] = NULL; + return; + } + commentList[index] = (char *) malloc(len + 2); + strncpy(commentList[index], text, len); + commentList[index][len] = '\n'; + commentList[index][len + 1] = NULLCHAR; +} + +void +AppendComment(index, text) + int index; + char *text; +{ + int oldlen, len; + char *old; + + while (*text == '\n') text++; + len = strlen(text); + while (len > 0 && text[len - 1] == '\n') len--; + + if (len == 0) return; + + if (commentList[index] != NULL) { + old = commentList[index]; + oldlen = strlen(old); + commentList[index] = (char *) malloc(oldlen + len + 2); + strcpy(commentList[index], old); + free(old); + strncpy(&commentList[index][oldlen], text, len); + commentList[index][oldlen + len] = '\n'; + commentList[index][oldlen + len + 1] = NULLCHAR; + } else { + commentList[index] = (char *) malloc(len + 2); + strncpy(commentList[index], text, len); + commentList[index][len] = '\n'; + commentList[index][len + 1] = NULLCHAR; + } +} + +void +SendToProgram(message, cps) + char *message; + ChessProgramState *cps; +{ + int count, outCount, error; + char buf[MSG_SIZ]; + + if (cps->pr == NULL) return; + Attention(cps); + + if (appData.debugMode) { + TimeMark now; + GetTimeMark(&now); + fprintf(debugFP, "%ld >%-6s: %s", + SubtractTimeMarks(&now, &programStartTime), + cps->which, message); + } + + count = strlen(message); + outCount = OutputToProcess(cps->pr, message, count, &error); + if (outCount < count && !exiting) { + sprintf(buf, "Error writing to %s chess program", cps->which); + DisplayFatalError(buf, error, 1); + } +} + +void +ReceiveFromProgram(isr, closure, message, count, error) + InputSourceRef isr; + VOIDSTAR closure; + char *message; + int count; + int error; +{ + char *end_str; + char buf[MSG_SIZ]; + ChessProgramState *cps = (ChessProgramState *)closure; + + if (isr != cps->isr) return; /* Killed intentionally */ + if (count <= 0) { + if (count == 0) { + sprintf(buf, + "Error: %s chess program (%s) exited unexpectedly", + cps->which, cps->program); + RemoveInputSource(cps->isr); + DisplayFatalError(buf, 0, 1); + } else { + sprintf(buf, + "Error reading from %s chess program (%s)", + cps->which, cps->program); + RemoveInputSource(cps->isr); + DisplayFatalError(buf, error, 1); + } + GameEnds((ChessMove) 0, NULL, GE_PLAYER); + return; + } + + if ((end_str = strchr(message, '\r')) != NULL) + *end_str = NULLCHAR; + if ((end_str = strchr(message, '\n')) != NULL) + *end_str = NULLCHAR; + + if (appData.debugMode) { + TimeMark now; + GetTimeMark(&now); + fprintf(debugFP, "%ld <%-6s: %s\n", + SubtractTimeMarks(&now, &programStartTime), + cps->which, message); + } + + if (appData.icsAnalyze) { + /* wb2 - can reset a setting - we are in possible ics mode - drop */ + if (strstr(message, "whisper") != NULL || + strstr(message, "kibitz") != NULL || + strstr(message, "set 1") != NULL) { + if (appData.debugMode) fprintf(debugFP, "ICS Analyze: Drop engine output\n"); + } else { + HandleMachineMove(message, cps); + } + } else { + HandleMachineMove(message, cps); + } +} + + +void +SendTimeControl(cps, mps, tc, inc, sd, st) + ChessProgramState *cps; + int mps, inc, sd, st; + long tc; +{ + char buf[MSG_SIZ]; + int seconds = (tc / 1000) % 60; + + if (st > 0) { + /* Set exact time per move, normally using st command */ + if (cps->stKludge) { + /* GNU Chess 4 has no st command; uses level in a nonstandard way */ + seconds = st % 60; + if (seconds == 0) { + sprintf(buf, "level 1 %d\n", st/60); + } else { + sprintf(buf, "level 1 %d:%02d\n", st/60, seconds); + } + } else { + sprintf(buf, "st %d\n", st); + } + } else { + /* Set conventional or incremental time control, using level command */ + if (seconds == 0) { + /* Note old gnuchess bug -- minutes:seconds used to not work. + Fixed in later versions, but still avoid :seconds + when seconds is 0. */ + sprintf(buf, "level %d %ld %d\n", mps, tc/60000, inc/1000); + } else { + sprintf(buf, "level %d %ld:%02d %d\n", mps, tc/60000, + seconds, inc/1000); + } + } + SendToProgram(buf, cps); + + /* Orthoganally (except for GNU Chess 4), limit time to st seconds */ + /* Orthogonally, limit search to given depth */ + if (sd > 0) { + if (cps->sdKludge) { + sprintf(buf, "depth\n%d\n", sd); + } else { + sprintf(buf, "sd %d\n", sd); + } + SendToProgram(buf, cps); + } +} + +void +SendTimeRemaining(cps, machineWhite) + ChessProgramState *cps; + int /*boolean*/ machineWhite; +{ + char message[MSG_SIZ]; + long time, otime; + + /* Note: this routine must be called when the clocks are stopped + or when they have *just* been set or switched; otherwise + it will be off by the time since the current tick started. + */ + if (machineWhite) { + time = whiteTimeRemaining / 10; + otime = blackTimeRemaining / 10; + } else { + time = blackTimeRemaining / 10; + otime = whiteTimeRemaining / 10; + } + if (time <= 0) time = 1; + if (otime <= 0) otime = 1; + + sprintf(message, "time %ld\notim %ld\n", time, otime); + SendToProgram(message, cps); +} + +int +BoolFeature(p, name, loc, cps) + char **p; + char *name; + int *loc; + ChessProgramState *cps; +{ + char buf[MSG_SIZ]; + int len = strlen(name); + int val; + if (strncmp((*p), name, len) == 0 && (*p)[len] == '=') { + (*p) += len + 1; + sscanf(*p, "%d", &val); + *loc = (val != 0); + while (**p && **p != ' ') (*p)++; + sprintf(buf, "accepted %s\n", name); + SendToProgram(buf, cps); + return TRUE; + } + return FALSE; +} + +int +IntFeature(p, name, loc, cps) + char **p; + char *name; + int *loc; + ChessProgramState *cps; +{ + char buf[MSG_SIZ]; + int len = strlen(name); + if (strncmp((*p), name, len) == 0 && (*p)[len] == '=') { + (*p) += len + 1; + sscanf(*p, "%d", loc); + while (**p && **p != ' ') (*p)++; + sprintf(buf, "accepted %s\n", name); + SendToProgram(buf, cps); + return TRUE; + } + return FALSE; +} + +int +StringFeature(p, name, loc, cps) + char **p; + char *name; + char loc[]; + ChessProgramState *cps; +{ + char buf[MSG_SIZ]; + int len = strlen(name); + if (strncmp((*p), name, len) == 0 + && (*p)[len] == '=' && (*p)[len+1] == '\"') { + (*p) += len + 2; + sscanf(*p, "%[^\"]", loc); + while (**p && **p != '\"') (*p)++; + if (**p == '\"') (*p)++; + sprintf(buf, "accepted %s\n", name); + SendToProgram(buf, cps); + return TRUE; + } + return FALSE; +} + +void +FeatureDone(cps, val) + ChessProgramState* cps; + int val; +{ + DelayedEventCallback cb = GetDelayedEvent(); + if ((cb == InitBackEnd3 && cps == &first) || + (cb == TwoMachinesEventIfReady && cps == &second)) { + CancelDelayedEvent(); + ScheduleDelayedEvent(cb, val ? 1 : 3600000); + } + cps->initDone = val; +} + +/* Parse feature command from engine */ +void +ParseFeatures(args, cps) + char* args; + ChessProgramState *cps; +{ + char *p = args; + char *q; + int val; + char buf[MSG_SIZ]; + + for (;;) { + while (*p == ' ') p++; + if (*p == NULLCHAR) return; + + if (BoolFeature(&p, "setboard", &cps->useSetboard, cps)) continue; + if (BoolFeature(&p, "time", &cps->sendTime, cps)) continue; + if (BoolFeature(&p, "draw", &cps->sendDrawOffers, cps)) continue; + if (BoolFeature(&p, "sigint", &cps->useSigint, cps)) continue; + if (BoolFeature(&p, "sigterm", &cps->useSigterm, cps)) continue; + if (BoolFeature(&p, "reuse", &val, cps)) { + /* Engine can disable reuse, but can't enable it if user said no */ + if (!val) cps->reuse = FALSE; + continue; + } + if (BoolFeature(&p, "analyze", &cps->analysisSupport, cps)) continue; + if (StringFeature(&p, "myname", &cps->tidy, cps)) { + if (gameMode == TwoMachinesPlay) { + DisplayTwoMachinesTitle(); + } else { + DisplayTitle(""); + } + continue; + } + if (StringFeature(&p, "variants", &cps->variants, cps)) continue; + if (BoolFeature(&p, "san", &cps->useSAN, cps)) continue; + if (BoolFeature(&p, "ping", &cps->usePing, cps)) continue; + if (BoolFeature(&p, "playother", &cps->usePlayother, cps)) continue; + if (BoolFeature(&p, "colors", &cps->useColors, cps)) continue; + if (BoolFeature(&p, "usermove", &cps->useUsermove, cps)) continue; + if (BoolFeature(&p, "ics", &cps->sendICS, cps)) continue; + if (BoolFeature(&p, "name", &cps->sendName, cps)) continue; + if (BoolFeature(&p, "pause", &val, cps)) continue; /* unused at present */ + if (IntFeature(&p, "done", &val, cps)) { + FeatureDone(cps, val); + continue; + } + + /* unknown feature: complain and skip */ + q = p; + while (*q && *q != '=') q++; + sprintf(buf, "rejected %.*s\n", q-p, p); + SendToProgram(buf, cps); + p = q; + if (*p == '=') { + p++; + if (*p == '\"') { + p++; + while (*p && *p != '\"') p++; + if (*p == '\"') p++; + } else { + while (*p && *p != ' ') p++; + } + } + } + +} + +void +PeriodicUpdatesEvent(newState) + int newState; +{ + if (newState == appData.periodicUpdates) + return; + + appData.periodicUpdates=newState; + + /* Display type changes, so update it now */ + DisplayAnalysis(0,0); + + /* Get the ball rolling again... */ + if (newState) { + if (gameMode == AnalyzeMode || gameMode == AnalyzeFile || + appData.icsAnalyze || appData.AnalysisWindow) { + AnalysisPeriodicEvent(1); + StartAnalysisClock(); + } + } +} + +void +PonderNextMoveEvent(newState) + int newState; +{ + if (newState == appData.ponderNextMove) return; + if (gameMode == EditPosition) EditPositionDone(); + if (newState) { + SendToProgram("hard\n", &first); + if (gameMode == TwoMachinesPlay) { + SendToProgram("hard\n", &second); + } + } else { + SendToProgram("easy\n", &first); + thinkOutput[0] = NULLCHAR; + if (gameMode == TwoMachinesPlay) { + SendToProgram("easy\n", &second); + } + } + appData.ponderNextMove = newState; +} + +void +ShowThinkingEvent(newState) + int newState; +{ + if (newState == appData.showThinking) return; + if (gameMode == EditPosition) EditPositionDone(); + if (newState) { + SendToProgram("post\n", &first); + if (gameMode == TwoMachinesPlay) { + SendToProgram("post\n", &second); + } + } else { + if (appData.AnalysisWindow) { + AnalysisPopDown(); + appData.AnalysisWindow = FALSE; + } + SendToProgram("nopost\n", &first); + thinkOutput[0] = NULLCHAR; + if (gameMode == TwoMachinesPlay) { + SendToProgram("nopost\n", &second); + } + } + appData.showThinking = newState; +} + +void +AskQuestionEvent(title, question, replyPrefix, which) + char *title; char *question; char *replyPrefix; char *which; +{ + ProcRef pr = (which[0] == '1') ? first.pr : second.pr; + if (pr == NoProc) return; + AskQuestion(title, question, replyPrefix, pr); +} + +void +DisplayMove(moveNumber) + int moveNumber; +{ + char message[MSG_SIZ]; + char res[MSG_SIZ]; + char cpThinkOutput[MSG_SIZ]; + static char last[1024]; + + int i = 0; + + if (moveNumber == forwardMostMove - 1 || + gameMode == AnalyzeMode || gameMode == AnalyzeFile) { + + strcpy(cpThinkOutput, thinkOutput); + if (strchr(cpThinkOutput, '\n')) + *strchr(cpThinkOutput, '\n') = NULLCHAR; + } else { + *cpThinkOutput = NULLCHAR; + } + + if (moveNumber == forwardMostMove - 1 && + gameInfo.resultDetails != NULL) { + if (gameInfo.resultDetails[0] == NULLCHAR) { + sprintf(res, " %s", PGNResult(gameInfo.result)); + } else { + sprintf(res, " {%s} %s", + gameInfo.resultDetails, PGNResult(gameInfo.result)); + } + + } else { + res[0] = NULLCHAR; + } + + if (moveNumber < 0 || parseList[moveNumber][0] == NULLCHAR) { + /* Output to ICC if IcsAnalyze */ + if(appData.icsAnalyze) IcsAnalyzeOutPut(&first, TRUE); + DisplayMessage(res, cpThinkOutput); + } else { + sprintf(message, "%d.%s%s%s", moveNumber / 2 + 1, + WhiteOnMove(moveNumber) ? " " : ".. ", + parseList[moveNumber], res); + if(appData.icsAnalyze) IcsAnalyzeOutPut(&first, FALSE); + DisplayMessage(message, cpThinkOutput); + } + + /* Send Engine output to ICS */ + if (appData.icsActive && appData.ButtonSendOutPutToICS + && appData.AnalysisWindow) { + + /* only send on move */ + switch (gameMode) { + case IcsPlayingWhite: + if(WhiteOnMove(currentMove)) i = 1; + break; + case IcsPlayingBlack: + if(!WhiteOnMove(currentMove)) i = 1; + break; + } + + if (i == 0 || programStats.depth <= 1 || programStats.depth >= 30 || + programStats.GUI_time <= 3) return; + + if (strcmp(programStats.movelist, last) == 0) return; + strcpy(last, programStats.movelist); + + switch (appData.SendOutPutToICS) { + + case 1: + sprintf(res, "whisper time: %d sec %+.2f/%d %s \n", programStats.GUI_time, + (((float)programStats.score)/100.0), programStats.depth, programStats.movelist); + SendToICS(res); + break; + case 2: + sprintf(res, "kibitz time: %d sec %+.2f/%d %s \n", programStats.GUI_time, + (((float)programStats.score)/100.0), programStats.depth, programStats.movelist); + SendToICS(res); + break; + + default: + break; + } + } +} + + +void +IcsAnalyzeOutPut(cps, endThink) +ChessProgramState *cps; +int endThink; +{ + char cpIcsThinkOutput[MSG_SIZ], icsOutput[32], str[8192]; + static char last[MSG_SIZ]; + long currentTime; + int diff, s, h, m, wait, info; + static int lastGame, lastMove, firstRun, say, lastdepth, sec; + double nps; + + if (appData.icsAnalyzeOutPut == 4 || !appData.icsAnalyze || + gameMode != IcsObserving) return; + + if (appData.icsSmartQueue == 0) { + wait = 60; + } else { + wait = 5; + } + + currentTime = programStats.time; + + /* calculate some infos */ + s = currentTime / 100; + sec = s; /* save complete sec */ + h = (s / (60*60)); + s = s - h*60*60; + m = (s/60); + s = s - m*60; + if (programStats.time == 0) programStats.time = 1; + nps = ((((double)programStats.nodes) / + (((double)programStats.time)/100.0)) /1000); + + if (ics_gamenum > max_gamenum || ics_gamenum == -1) { + DisplayFatalError("ICS-Analysis: Fatal array error - Please make a bugreport.", 0, 1); + return; + } + + /* init ICS gamequeue - safty */ + /* normaly we do that with read_from_ics() */ + if (icsQueue[ics_gamenum].killPv == 0) { + icsQueue[ics_gamenum].move = currentMove; + icsQueue[ics_gamenum].killPv = appData.icsKillPVs; + icsQueue[ics_gamenum].counter = 0; + icsQueue[ics_gamenum].lastpv[0] = NULLCHAR; + } + + /* for chess.fm on ICC we must copy player names each move */ + strcpy(icsQueue[ics_gamenum].white, gameInfo.white); + strcpy(icsQueue[ics_gamenum].black, gameInfo.black); + + if (appData.smartQueue) { + if (lastGame == 0) lastGame = ics_gamenum; + if (lastMove == 0) lastMove = currentMove; + if (ics_gamenum != lastGame || lastMove != currentMove) { + firstRun = 1; + icsQueue[ics_gamenum].counter = 0; + } + } + + /* checking other games - only for live broadcasting */ + /* init on a new move */ + if (appData.icsAnalyzeOutPut != 4) { + if (icsQueue[ics_gamenum].CurrentMove != currentMove) { + icsQueue[ics_gamenum].CurrentMove = currentMove; + icsQueue[ics_gamenum].flag = 0; /* we have not send */ + icsQueue[ics_gamenum].counter = 0; + } + } + + strcpy(cpIcsThinkOutput, thinkOutput); + if (strchr(cpIcsThinkOutput, '\n')) { + *strchr(cpIcsThinkOutput, '\n') = NULLCHAR; + } + if (cpIcsThinkOutput[0] == NULLCHAR) return; + + /* Special ICC fetures - works only with param /icc */ + if (ics_type == ICS_ICC && appData.ICC_feature == TRUE && + appData.userVersion == FALSE) { + if (appData.icsAnalyzeOutPut == 3) { + /* If we start a new broadcast analyse we inform user */ + if (icsQueue[ics_gamenum].lastpv[0] == NULLCHAR) { + sprintf(str, "whisperto %d Hello from Winboard-DM \n", ics_gamenum); + SendToICS(str); + } + + /* If long tourney games >= 120 0 */ + if (appData.icsSmartQueue == 0) { + switch (currentMove) { + case 20: case 40: case 60: case 80: case 100: case 135: case 160: + if (icsQueue[ics_gamenum].event == 0) { + sprintf(str, "whisperto %d Hello, i'm an analysis engine.\n", ics_gamenum); + SendToICS(str); + sprintf(str, "whisperto %d If you want my last analysis of this game, just type \"tell %s showinfo %d\"\n", + ics_gamenum, ics_handle, ics_gamenum); + SendToICS(str); + if (strcmp(appData.icsTells, "211") == 0) { + sprintf(str, "whisperto %d and/or type \"+ch 211\" for a ICC channel analysis\n", ics_gamenum); + SendToICS(str); + } + icsQueue[ics_gamenum].event = 1; + + /* channel 165 on ICC */ + if (currentMove == 20 && chessfm == 0) { + info = 1; + chessfm = 1; + } else if (currentMove == 40 && (chessfm == 1 || chessfm == 0)) { + info = 1; + chessfm = 2; + } else if (currentMove == 60 && (chessfm == 2 || chessfm == 0)) { + info = 1; + chessfm = 3; + } else if (currentMove == 80 && (chessfm == 3 || chessfm == 0)) { + info = 1; + chessfm = 4; + } else if (currentMove == 100 && (chessfm == 4 || chessfm == 0)) { + info = 1; + chessfm = 5; + } else { + info = 0; + } + + if (info == 1) { + sprintf(str, "tell 165 Hi, i'm analyzing live broadcast games. \"tell %s showgames \" to see which games are currently analyzed.\n", ics_handle); + SendToICS(str); + sprintf(str, "tell 165 \"finger %s\" and \"finger live\" for more details \n", ics_handle); + SendToICS(str); + } + } + break; + default: + icsQueue[ics_gamenum].event = 0; + } + } else { + switch (currentMove) { + case 20: case 60: case 100: + if (icsQueue[ics_gamenum].event == 0) { + sprintf(str, "whisperto %d Hello, i'm an analysis engine.\n", ics_gamenum); + SendToICS(str); + sprintf(str, "whisperto %d If you want my last analysis of this game, just type \"tell %s showinfo %d\"\n", + ics_gamenum, ics_handle, ics_gamenum); + SendToICS(str); + if (strcmp(appData.icsTells, "211") == 0) { + sprintf(str, "whisperto %d and/or type \"+ch 211\" for a ICC channel analysis\n", ics_gamenum); + SendToICS(str); + } + icsQueue[ics_gamenum].event = 1; + } + break; + default: + icsQueue[ics_gamenum].event = 0; + } + + } + /* save last game pv for user request */ + sprintf(icsQueue[ics_gamenum].lastpv, "%s time: %02d:%02d min nps: %dK \n", cpIcsThinkOutput, m, s, (int)nps); + } + } + + switch(appData.icsAnalyzeOutPut) { + case 1: + switch (ics_type) { + case ICS_ICC: strcpy(icsOutput, "whisperto"); + break; + case ICS_FICS: strcpy(icsOutput, "xwhisper"); + break; + case ICS_GENERIC: + case ICS_CHESSNET: + default: + DisplayFatalError("ICS-Analysis: Sorry, this Serverprotocoll is not supported",0,2); + break; + } + break; + case 2: + switch (ics_type) { + case ICS_ICC: strcpy(icsOutput, "kibitzto"); + break; + case ICS_FICS: strcpy(icsOutput, "xkibitz"); + break; + case ICS_GENERIC: + case ICS_CHESSNET: + default: + DisplayFatalError("ICS-Analysis: Sorry, this Serverprotocoll is not supported",0,2); + break; + } + break; + case 3: + strcpy(icsOutput, "tell"); + break; + default: + /* could't happen */ + return; + } + + /* Drop double output - example Crafty */ + if (strcmp(cpIcsThinkOutput, last) == 0) { + /* Check again if we can switch game - that will be faster as we wait for next ply */ + if (icsQueue[ics_gamenum].flag == 1) { + if (SwitchGames() == 0) return; + } + /* special crafty feature - let interation pass */ + if (strncmp(cps->tidy, "Crafty", 6) != 0) return; + } + + /* if skip high/fail low active we only send every complete interation from engine */ + if (lastdepth == 0 || lastdepth > programStats.depth) lastdepth = programStats.depth; + + + /* Drop all about 25 plys - could be egtb output */ + if (programStats.depth > 25) { + if (appData.icsAnalyzeOutPut == 3) { + /* We don't stay longer on this game - just try to switching other games */ + icsQueue[ics_gamenum].flag = 1; /* done */ + icsQueue[ics_gamenum].MessageMove = currentMove; + if (SwitchGames() == 0) return; + } + return; + } + + /* Drop score above 10.0 - many engines send to many lines if mate */ + if ((programStats.score / 100) > 10 || (programStats.score / 100) < -10) { + if (appData.icsAnalyzeOutPut == 3) { + /* We don't stay longer on this game - just switching to other games */ + icsQueue[ics_gamenum].flag = 1; /* done */ + icsQueue[ics_gamenum].MessageMove = currentMove; + if (SwitchGames() == 0) return; + } + return; + } + /* tell ICC fail high move if possible */ + if (ics_type == ICS_ICC && appData.ICC_feature == TRUE && appData.userVersion == FALSE && + appData.icsAnalyzeOutPut == 3 && programStats.depth >= icsQueue[ics_gamenum].killPv) { + //if (strchr(cpIcsThinkOutput, '!!') != NULL && strncmp(cps->tidy, "Yace" , 4) != 0) { + //sprintf(str, "whisperto %d Analysis: Something happened - Side on move maybe looks better as before. \n", ics_gamenum); + //SendToICS(str); + //} else if (strchr(cpIcsThinkOutput, '(++)') != NULL && strncmp(cps->tidy, "Yace" , 4) == 0) { + //sprintf(str, "whisperto %d Analysis: Something happened - Side on move maybe looks better as before. \n", ics_gamenum); + //SendToICS(str); + //} + } + + /* Drop fail high/low moves from engines */ + if (appData.windowMove) { + if (strchr(cpIcsThinkOutput, '?') != NULL || strchr(cpIcsThinkOutput, '!') != NULL || + strchr(cpIcsThinkOutput, 't') != NULL || strchr(cpIcsThinkOutput, 'u') != NULL) { + if (appData.debugMode) fprintf(debugFP, "ICS-Analyze: Drop move with string \n"); + return; + } + } + + /* smart Queue fast down handling */ + if (sec > wait && programStats.depth <= (icsQueue[ics_gamenum].killPv - 1) && + appData.smartQueue) { + if (icsQueue[ics_gamenum].killPv > 8) { + if (!appData.icsEngineKillPV) appData.icsEngineKillPV = TRUE; + if (lastMove == currentMove) icsQueue[ics_gamenum].killPv--; + if (appData.debugMode) fprintf(debugFP, "icsQueue[%d].killPv-- \n", + icsQueue[ics_gamenum].killPv); + } + } + /* smart Queue fast up handling */ + if (sec < 30 && programStats.depth >= icsQueue[ics_gamenum].killPv && + appData.smartQueue) { + if (!appData.icsEngineKillPV) appData.icsEngineKillPV = TRUE; + if (lastMove == currentMove ) { + /* Crafty send 2x string so this is a importent reason */ + if (strncmp(cps->tidy, "Crafty", 6) == 0 && + strcmp(cpIcsThinkOutput, last) != 0) { + icsQueue[ics_gamenum].killPv++; + } else if (strncmp(cps->tidy, "Crafty", 6) != 0) { + /* other programs */ + icsQueue[ics_gamenum].killPv++; + } + } + if (appData.debugMode) fprintf(debugFP, "icsQueue[%d].killPv++ \n", + icsQueue[ics_gamenum].killPv); + } + /* smart Queue handling */ + if (appData.smartQueue && programStats.depth >= icsQueue[ics_gamenum].killPv) { + diff = ((int)currentTime / 100) - ((int)icsQueue[ics_gamenum].time / 100); + if ((diff < 7 && diff != 0) && icsQueue[ics_gamenum].counter > 3 && + icsQueue[ics_gamenum].move <= currentMove) { + if (!appData.icsEngineKillPV) appData.icsEngineKillPV = TRUE; + appData.icsEngineKillPV = TRUE; + icsQueue[ics_gamenum].killPv++; + icsQueue[ics_gamenum].move = currentMove + 1; + icsQueue[ics_gamenum].counter = 0; + if (appData.debugMode) fprintf(debugFP, "icsQueue[%d].killPv++ \n", + icsQueue[ics_gamenum].killPv); + /* normal down */ + } else if (diff > wait && icsQueue[ics_gamenum].counter < 2 && + icsQueue[ics_gamenum].move <= currentMove && firstRun == 1 && + lastMove != currentMove) { + if(icsQueue[ics_gamenum].killPv > 8) { + if (!appData.icsEngineKillPV) appData.icsEngineKillPV = TRUE; + if (lastMove == currentMove) icsQueue[ics_gamenum].killPv--; + firstRun = 0; + if (appData.debugMode) fprintf(debugFP, "icsQueue[%d].killPv-- \n", + icsQueue[ics_gamenum].killPv); + } + icsQueue[ics_gamenum].move = currentMove + 1; + icsQueue[ics_gamenum].counter = 0; + } else { + icsQueue[ics_gamenum].counter++; + lastGame = ics_gamenum; + lastMove = currentMove; + } + } + icsQueue[ics_gamenum].time = currentTime; + + /* Check other games part 2 */ + if (appData.icsAnalyzeOutPut != 4) { + /* if no other games avaible we coming back */ + if (icsQueue[ics_gamenum].flag == 1) { + if (SwitchGames() == 0) return; + } + } + + /* kill PV here */ + if (programStats.line_is_book != 1 || programStats.depth != 0) { + if (appData.icsEngineKillPV || appData.smartQueue) { + if(programStats.depth < icsQueue[ics_gamenum].killPv || + programStats.depth < appData.icsKillPVs && programStats.depth != 0) return; + } + } + + /* send information */ + if (programStats.line_is_book == 1 && programStats.depth < 2 || + programStats.depth == 0) { + if (appData.icsAnalyzeOutPut != 3) { + /* We must whisperto if we follow someone */ + /* on FCIS we need xwhisper */ + sprintf(str, "%s %d %s: Book depth=%s \n", icsOutput, ics_gamenum, + cps->tidy, cpIcsThinkOutput); + } else { + if (currentMove > -1) { + sprintf(str, "%s %s %s: (%s/%s) Book %d.%s depth=%s (game \"observe %d\")\n", icsOutput, + appData.icsTells, cps->tidy, gameInfo.white, gameInfo.black, + currentMove / 2 + 1, WhiteOnMove(currentMove) ? " " : "... ", + cpIcsThinkOutput, ics_gamenum); + + icsQueue[ics_gamenum].MessageMove = currentMove; + } + icsQueue[ics_gamenum].flag = 1; /* we send */ + } + SendToICS(str); + } else { + /* interation check */ + /* special crafty interation */ + if (appData.windowMove && strncmp(cps->tidy, "Crafty" , 6) == 0 && + strcmp(cpIcsThinkOutput, last) != 0) { + strcpy(last,cpIcsThinkOutput); + return; + } + /* normal interation check */ + if (appData.windowMove && programStats.depth <= lastdepth) return; + + if (appData.icsAnalyzeOutPut != 3) { + if (endThink == TRUE) { + sprintf(str, "%s %d %s: first move (Depth=%s time: %02d:%02d min nps: %dK \n", icsOutput, + ics_gamenum, cps->tidy, cpIcsThinkOutput, m, s, (int)nps); + } else { + sprintf(str, "%s %d %s: Depth=%s time: %02d:%02d min nps: %dK \n", icsOutput, ics_gamenum, + cps->tidy, cpIcsThinkOutput, m, s, (int)nps); + } + icsQueue[ics_gamenum].flag = 1; /* we send */ + SendToICS(str); + } else { + if (endThink == TRUE) { + sprintf(str, "%s %s %s: (%s/%s) first move (Depth=%s time: %02d:%02d min nps: %dK (game \"observe %d\")\n", icsOutput, + appData.icsTells, cps->tidy, gameInfo.white, gameInfo.black, + cpIcsThinkOutput, m, s, (int)nps, ics_gamenum); + } else { + sprintf(str, "%s %s %s: (%s/%s) Depth=%s time: %02d:%02d min nps: %dK (game \"observe %d\")\n", icsOutput, + appData.icsTells, cps->tidy, gameInfo.white, gameInfo.black, + cpIcsThinkOutput, m, s, (int)nps, ics_gamenum); + } + icsQueue[ics_gamenum].flag = 1; /* we send */ + icsQueue[ics_gamenum].MessageMove = currentMove; + SendToICS(str); + } + } + strcpy(last,cpIcsThinkOutput); + lastdepth = programStats.depth; + + /* At least we search for a open game once more */ + if (icsQueue[ics_gamenum].flag == 1) { + if (SwitchGames() == 0 && appData.debugMode) { + fprintf(debugFP, "Switch was at end of produce \n"); + } + } +} + + +/* Reset icsGameQueue if game ends or user abort */ +void +ResetIcsQueue(gamenumber) +{ + icsQueue[gamenumber].black[0] = NULLCHAR; + icsQueue[gamenumber].white[0] = NULLCHAR; + icsQueue[gamenumber].counter = 0; + icsQueue[gamenumber].currentGame = 0; + icsQueue[gamenumber].CurrentMove = 0; + icsQueue[gamenumber].event = 0; + icsQueue[gamenumber].killPv = 0; + icsQueue[gamenumber].lastpv[0] = NULLCHAR; + icsQueue[gamenumber].MessageMove = 0; + icsQueue[gamenumber].move = 0; + icsQueue[gamenumber].time = 0; +} + +/* GUI -> engine */ +void +GuiCommand(command, param) +int command; +int param; /* reserved */ +{ + switch (command) { + case 1: + switch (gameMode) { + case MachinePlaysWhite: + case MachinePlaysBlack: + SendToProgram("?\n", &first); + break; + } + break; + case 2: + switch (gameMode) { + case AnalyzeMode: + case AnalyzeFile: + if (first.analyzing == TRUE) { + /* don't send stat */ + appData.engineStatLine = TRUE; + SendToProgram("exit\n", &first); + SendToProgram("force\n", &first); + first.analyzing = FALSE; + PeriodicUpdatesEvent(FALSE); + DisplayAnalysis(6,0); + } else { + /* safty with force */ + /* send stat */ + appData.engineStatLine = FALSE; + SendToProgram("analyze\n", &first); + first.analyzing = TRUE; + PeriodicUpdatesEvent(TRUE); + } + break; + /* a lot of engine makes probs if we switch from + * normal Mode to analyzeMode :( */ + case MachinePlaysWhite: + case MachinePlaysBlack: + case EditGame: + if (first.maybeThinking == TRUE) { + /* don't send stat */ + appData.engineStatLine = TRUE; + EditGameEvent(); + first.maybeThinking = FALSE; + } else { + /* get latest state */ + if (supportStat == 1) appData.engineStatLine = FALSE; + if (WhiteOnMove(currentMove)) { + MachineWhiteEvent(); + } else { + MachineBlackEvent(); + } + } + break; + case BeginningOfGame: + MachineWhiteEvent(); + break; + default: + break; + } + } +} + +static int +only_one_move(str) + char *str; +{ + while (*str && isspace(*str)) ++str; + while (*str && !isspace(*str)) ++str; + if (!*str) return 1; + while (*str && isspace(*str)) ++str; + if (!*str) return 1; + return 0; +} + +void +DisplayAnalysis(newState, pv) +int newState; /* int newState: + * 1 = timer++ + * 0 = do nothing + * --- WB bootup (start) --- + * 5 = WB startup if EngineRoom true: popup + * --- GUI Action --- + * 6 = Start button + * hold/reset time + * 7 = Stop button */ + + +int pv; /* only pv comes 1 = TRUE */ +{ + /* newState True = call from timer - see dirty hack */ + char buf[2048]; + char buf2[32]; + char buf3[32]; + char buf4[32]; + char buf5[32]; + static char buf6[64]; /* static need if pv only */ + static char lastline[1024]; + static int lastdepth, last_icsgamenum; + int currentdepth; + char currentline[1024]; + char buf7[128]; + double nps; + int h, m, s; + static char *xtra[] = { "", " (--)", " (++)" }; + static int oldGameMode; /* on the fly switch gameMode ? */ + static int StatLine_autodetect; /* Autodetect only first move out of book */ + /* 0 = should detect + * 1 = done + */ + int diff; + int state; /* Using for ponder, opponent time action and + * using for color engine name + * --- move statment (adv color)--- + * 0 = we have the move and stanard color + * 1 = opponent have the move and opponent color + * --- only color statement--- + * 2 = AnalyzeMode + * 3 = IcsObserving + * --- special things ---- + * 4 = Two engines - we don't support that + */ + static long timer; /* hack without a stat line */ + static int move; /* detect new move */ + + strcpy(currentline, programStats.movelist); + currentdepth = programStats.depth; + + if (appData.noChessProgram) return; + /* if goes up to the end of this function */ + if (appData.icsAnalyzeWindow || appData.AnalysisWindow + || gameMode == AnalyzeMode || gameMode == AnalyzeFile) { + /* stop analysis */ + if (newState == 6) timer = 0; + + /* use for no stat support */ + /* If user switch on the fly gameMode we must know that */ + if (move != currentMove || oldGameMode != gameMode) { + timer = 0; + if (oldGameMode != gameMode) { + /* clear pv screen */ + sprintf(buf, "changing mode..."); + sprintf(buf2, "wait"); + sprintf(buf3, "0kN/s"); + sprintf(buf4, "Nodes=0"); + sprintf(buf5, "0.00"); + sprintf(buf6, "wait..."); + sprintf(buf7, "------------ "); + AnalysisPopUp(buf, buf2, buf3, buf4, buf5, buf6, buf7, 0); + oldGameMode = gameMode; + } + if (move > currentMove) { + supportStat = 0; /* new Game ? */ + StatLine_autodetect = 0; + } + move = currentMove; + lastdepth = 0; + } + + /* ICS Analyze more then one game - check if new game */ + if (appData.icsActive && ics_gamenum != last_icsgamenum) { + timer = 0; + last_icsgamenum = ics_gamenum; + } + + if (gameMode == EditGame) timer = 0; /* no clock if edit */ + + /* hope a lot of programmer will add a stat line - easy to make */ + /* at the moment a dirty(!!) hack with time_id */ + /* calculate some infos */ + if (programStats.time == 0) programStats.time = 1; + if (newState && gameMode != EditGame) timer++; + s = timer; + h = (s / (60*60)); + s = s - h*60*60; + m = (s/60); + s = s - m*60; + + /* save time */ + programStats.GUI_time = timer; + + /* Who is on move or which mode ?*/ + /* Need for colorize EngineName */ + /* Check gameMode for Stat support */ + switch (gameMode) { + case MachinePlaysWhite: + case IcsPlayingWhite: + if (WhiteOnMove(currentMove)) state = 0; + if (!WhiteOnMove(currentMove)) state = 1; + break; + case MachinePlaysBlack: + case IcsPlayingBlack: + if (WhiteOnMove(currentMove)) state = 1; + if (!WhiteOnMove(currentMove)) state = 0; + break; + case AnalyzeMode: + case AnalyzeFile: + appData.engineStatLine = FALSE; + StatLine_autodetect = 0; /* switch back to play is a prob */ + state = 2; + break; + case IcsObserving: + state = 3; + break; + /* not really a support for engine war - wait for war room */ + case TwoMachinesPlay: + state = 4; + break; + default: + appData.engineStatLine = FALSE; + state = 0; /* green */ + } + nps = ((((double)programStats.nodes) / + (((double)programStats.time)/100.0)) /1000); + + if (programStats.nodes > 0 && pv == 1) { + if (strcmp(lastline, currentline) != 0) { + if (prefixHint == TRUE && programStats.ponderMove[0] != NULLCHAR) { + if (programStats.score == 0 || programStats.score > 0) { + /* format arial set */ + sprintf(buf, " d->%02d %+.2f (%s) %s", programStats.depth, + (((float)programStats.score)/100.0), + programStats.ponderMove, currentline); + } else if (programStats.score < 0) { + sprintf(buf, " d->%02d %+.2f (%s) %s", programStats.depth, + (((float)programStats.score)/100.0), + programStats.ponderMove, currentline); + } + strcpy(lastline, currentline); + } else { + /* format arial set */ + if (programStats.score == 0 || programStats.score > 0) { + sprintf(buf, " d->%02d %+.2f %s", programStats.depth, + (((float)programStats.score)/100.0), currentline); + } else if (programStats.score < 0) { + sprintf(buf, " d->%02d %+.2f %s", programStats.depth, + (((float)programStats.score)/100.0), currentline); + } + strcpy(lastline, currentline); + } + lastdepth = currentdepth; + } else { + if (lastdepth < currentdepth) { + if (prefixHint == TRUE && programStats.ponderMove[0] != NULLCHAR) { + if (programStats.score == 0 || programStats.score > 0) { + /* format arial set */ + sprintf(buf, " d->%02d %+.2f (%s) %s", programStats.depth, + (((float)programStats.score)/100.0), + programStats.ponderMove, currentline); + } else if (programStats.score < 0) { + sprintf(buf, " d->%02d %+.2f (%s) %s", programStats.depth, + (((float)programStats.score)/100.0), + programStats.ponderMove, currentline); + } + } else { + /* format arial set */ + if (programStats.score == 0 || programStats.score > 0) { + sprintf(buf, " d->%02d %+.2f %s", programStats.depth, + (((float)programStats.score)/100.0), currentline); + } else if (programStats.score < 0) { + sprintf(buf, " d->%02d %+.2f %s", programStats.depth, + (((float)programStats.score)/100.0), currentline); + } + } + lastdepth = currentdepth; + } else { + buf[0] = NULLCHAR; + } + } + } else { + buf[0] = NULLCHAR; + } + + /* remove Bookline - never works correct */ + /* dirty hack with wb2 proto :((*/ + if (programStats.depth == 0 || programStats.depth == 1) { + sprintf(buf2, "Book"); + sprintf(buf3, "0kN/s"); + sprintf(buf4, "Nodes=0"); + sprintf(buf5, "0.00"); + sprintf(buf6, "wait..."); + } else { + sprintf(buf2, "Depth=%d", programStats.depth); + sprintf(buf3, "%dkN/s", (int)nps); + sprintf(buf4, "Nodes=%lu", programStats.nodes); + sprintf(buf5, "%+.2f", (((float)programStats.score)/100.0)); + } + sprintf(buf7, "%02d:%02d:%02d ", h, m, s); + /* only pv */ + if (pv == 1 && strcmp(lastline, currentline) != 0) { + AnalysisPopUp(buf, buf2, buf3, buf4, buf5, buf6, buf7, state); + return; + } else if (pv == 1 && strcmp(lastline, currentline) == 0 && + lastdepth < currentdepth) { + AnalysisPopUp(buf, buf2, buf3, buf4, buf5, buf6, buf7, state); + return; + } + + /* remove Bookline - never works correct */ + if (programStats.depth == 0 || programStats.depth == 1) { + sprintf(buf6, "wait..."); + } else { + if (supportStat == 0 && StatLine_autodetect == 0 && + timer > 20) { + /* we should disable sending "." now and tell GUI */ + /* Do that here only after first move out of book */ + appData.engineStatLine = TRUE; /* enable checkbox */ + StatLine_autodetect = 1; /* done */ + } + if (programStats.depth > 1) { + if (supportStat == 0) { + sprintf(buf6, "no support"); + } else { + diff = (programStats.nr_moves-programStats.moves_left); + if (diff < 0) { + sprintf(buf6, "Error!"); + } else { + if (programStats.moves_left > 0) { + if (programStats.move_name[0] != NULLCHAR) { + sprintf(buf6, "%d/%d %s", diff, + programStats.nr_moves, programStats.move_name); + } else { + /* without move. e.g. crafty */ + sprintf(buf6, "%d/%d", diff, + programStats.nr_moves, only_one_move(programStats.movelist)? + xtra[programStats.got_fail] : ""); + } + } + } + } + } + } + AnalysisPopUp(buf, buf2, buf3, buf4, buf5, buf6, buf7, state); + + } +} + +void +DisplayComment(moveNumber, text) + int moveNumber; + char *text; +{ + char title[MSG_SIZ]; + + if (moveNumber < 0 || parseList[moveNumber][0] == NULLCHAR) { + strcpy(title, "Comment"); + } else { + sprintf(title, "Comment on %d.%s%s", moveNumber / 2 + 1, + WhiteOnMove(moveNumber) ? " " : ".. ", + parseList[moveNumber]); + } + + CommentPopUp(title, text); +} + +/* This routine sends a ^C interrupt to gnuchess, to awaken it if it + * might be busy thinking or pondering. It can be omitted if your + * gnuchess is configured to stop thinking immediately on any user + * input. However, that gnuchess feature depends on the FIONREAD + * ioctl, which does not work properly on some flavors of Unix. + */ +void +Attention(cps) + ChessProgramState *cps; +{ +#if ATTENTION + if (!cps->useSigint) return; + if (appData.noChessProgram || (cps->pr == NoProc)) return; + switch (gameMode) { + case MachinePlaysWhite: + case MachinePlaysBlack: + case TwoMachinesPlay: + case IcsPlayingWhite: + case IcsPlayingBlack: + case AnalyzeMode: + case AnalyzeFile: + /* Skip if we know it isn't thinking */ + if (!cps->maybeThinking) return; + if (appData.debugMode) + fprintf(debugFP, "Interrupting %s\n", cps->which); + InterruptChildProcess(cps->pr); + cps->maybeThinking = FALSE; + break; + default: + break; + } +#endif /*ATTENTION*/ +} + +int +CheckFlags() +{ + if (whiteTimeRemaining <= 0) { + if (!whiteFlag) { + whiteFlag = TRUE; + if (appData.icsActive) { + if (appData.autoCallFlag && + gameMode == IcsPlayingBlack && !blackFlag) { + SendToICS(ics_prefix); + SendToICS("flag\n"); + } + } else { + if (blackFlag) { + DisplayTitle("Both flags fell"); + } else { + DisplayTitle("White's flag fell"); + if (appData.autoCallFlag) { + GameEnds(BlackWins, "Black wins on time", GE_XBOARD); + return TRUE; + } + } + } + } + } + if (blackTimeRemaining <= 0) { + if (!blackFlag) { + blackFlag = TRUE; + if (appData.icsActive) { + if (appData.autoCallFlag && + gameMode == IcsPlayingWhite && !whiteFlag) { + SendToICS(ics_prefix); + SendToICS("flag\n"); + } + } else { + if (whiteFlag) { + DisplayTitle("Both flags fell"); + } else { + DisplayTitle("Black's flag fell"); + if (appData.autoCallFlag) { + GameEnds(WhiteWins, "White wins on time", GE_XBOARD); + return TRUE; + } + } + } + } + } + return FALSE; +} + +void +CheckTimeControl() +{ + if (!appData.clockMode || appData.icsActive || + gameMode == PlayFromGameFile || forwardMostMove == 0) return; + + if (timeIncrement >= 0) { + if (WhiteOnMove(forwardMostMove)) { + blackTimeRemaining += timeIncrement; + } else { + whiteTimeRemaining += timeIncrement; + } + } + /* + * add time to clocks when time control is achieved + */ + if (movesPerSession) { + switch ((forwardMostMove + 1) % (movesPerSession * 2)) { + case 0: + /* White made time control */ + whiteTimeRemaining += timeControl; + break; + case 1: + /* Black made time control */ + blackTimeRemaining += timeControl; + break; + default: + break; + } + } +} + +void +DisplayBothClocks() +{ + int wom = gameMode == EditPosition ? + !blackPlaysFirst : WhiteOnMove(currentMove); + DisplayWhiteClock(whiteTimeRemaining, wom); + DisplayBlackClock(blackTimeRemaining, !wom); +} + + +/* Timekeeping seems to be a portability nightmare. I think everyone + has ftime(), but I'm really not sure, so I'm including some ifdefs + to use other calls if you don't. Clocks will be less accurate if + you have neither ftime nor gettimeofday. +*/ + +/* Get the current time as a TimeMark */ +void +GetTimeMark(tm) + TimeMark *tm; +{ +#if HAVE_GETTIMEOFDAY + + struct timeval timeVal; + struct timezone timeZone; + + gettimeofday(&timeVal, &timeZone); + tm->sec = (long) timeVal.tv_sec; + tm->ms = (int) (timeVal.tv_usec / 1000L); + +#else /*!HAVE_GETTIMEOFDAY*/ +#if HAVE_FTIME + +#include + struct timeb timeB; + + ftime(&timeB); + tm->sec = (long) timeB.time; + tm->ms = (int) timeB.millitm; + +#else /*!HAVE_FTIME && !HAVE_GETTIMEOFDAY*/ + tm->sec = (long) time(NULL); + tm->ms = 0; +#endif +#endif +} + +/* Return the difference in milliseconds between two + time marks. We assume the difference will fit in a long! +*/ +long +SubtractTimeMarks(tm2, tm1) + TimeMark *tm2, *tm1; +{ + return 1000L*(tm2->sec - tm1->sec) + + (long) (tm2->ms - tm1->ms); +} + + +/* + * Code to manage the game clocks. + * + * In tournament play, black starts the clock and then white makes a move. + * We give the human user a slight advantage if he is playing white---the + * clocks don't run until he makes his first move, so it takes zero time. + * Also, we don't account for network lag, so we could get out of sync + * with GNU Chess's clock -- but then, referees are always right. + */ + +static TimeMark tickStartTM; +static long intendedTickLength; + +long +NextTickLength(timeRemaining) + long timeRemaining; +{ + long nominalTickLength, nextTickLength; + + if (timeRemaining > 0L && timeRemaining <= 10000L) + nominalTickLength = 100L; + else + nominalTickLength = 1000L; + nextTickLength = timeRemaining % nominalTickLength; + if (nextTickLength <= 0) nextTickLength += nominalTickLength; + + return nextTickLength; +} + +/* Stop clocks and reset to a fresh time control */ +void +ResetClocks() +{ + (void) StopClockTimer(); + if (appData.icsActive) { + whiteTimeRemaining = blackTimeRemaining = 0; + } else { + whiteTimeRemaining = blackTimeRemaining = timeControl; + } + if (whiteFlag || blackFlag) { + DisplayTitle(""); + whiteFlag = blackFlag = FALSE; + } + DisplayBothClocks(); +} + +#define FUDGE 25 /* 25ms = 1/40 sec; should be plenty even for 50 Hz clocks */ + +/* Decrement running clock by amount of time that has passed */ +void +DecrementClocks() +{ + long timeRemaining; + long lastTickLength, fudge; + TimeMark now; + + if (!appData.clockMode) return; + if (gameMode==AnalyzeMode || gameMode == AnalyzeFile) return; + + GetTimeMark(&now); + + lastTickLength = SubtractTimeMarks(&now, &tickStartTM); + + /* Fudge if we woke up a little too soon */ + fudge = intendedTickLength - lastTickLength; + if (fudge < 0 || fudge > FUDGE) fudge = 0; + + if (WhiteOnMove(forwardMostMove)) { + timeRemaining = whiteTimeRemaining -= lastTickLength; + DisplayWhiteClock(whiteTimeRemaining - fudge, + WhiteOnMove(currentMove)); + } else { + timeRemaining = blackTimeRemaining -= lastTickLength; + DisplayBlackClock(blackTimeRemaining - fudge, + !WhiteOnMove(currentMove)); + } + + if (CheckFlags()) return; + + tickStartTM = now; + intendedTickLength = NextTickLength(timeRemaining - fudge) + fudge; + StartClockTimer(intendedTickLength); + + /* if the time remaining has fallen below the alarm threshold, sound the + * alarm. if the alarm has sounded and (due to a takeback or time control + * with increment) the time remaining has increased to a level above the + * threshold, reset the alarm so it can sound again. + */ + + if (appData.icsActive && appData.icsAlarm) { + + /* make sure we are dealing with the user's clock */ + if (!( ((gameMode == IcsPlayingWhite) && WhiteOnMove(currentMove)) || + ((gameMode == IcsPlayingBlack) && !WhiteOnMove(currentMove)) + )) return; + + if (alarmSounded && (timeRemaining > appData.icsAlarmTime)) { + alarmSounded = FALSE; + } else if (!alarmSounded && (timeRemaining <= appData.icsAlarmTime)) { + PlayAlarmSound(); + alarmSounded = TRUE; + } + } +} + + +/* A player has just moved, so stop the previously running + clock and (if in clock mode) start the other one. + We redisplay both clocks in case we're in ICS mode, because + ICS gives us an update to both clocks after every move. + Note that this routine is called *after* forwardMostMove + is updated, so the last fractional tick must be subtracted + from the color that is *not* on move now. +*/ +void +SwitchClocks() +{ + long lastTickLength; + TimeMark now; + int flagged = FALSE; + + GetTimeMark(&now); + + if (StopClockTimer() && appData.clockMode) { + lastTickLength = SubtractTimeMarks(&now, &tickStartTM); + if (WhiteOnMove(forwardMostMove)) { + blackTimeRemaining -= lastTickLength; + } else { + whiteTimeRemaining -= lastTickLength; + } + flagged = CheckFlags(); + } + CheckTimeControl(); + + if (flagged || !appData.clockMode) return; + + switch (gameMode) { + case MachinePlaysBlack: + case MachinePlaysWhite: + case BeginningOfGame: + if (pausing) return; + break; + + case EditGame: + case PlayFromGameFile: + case IcsExamining: + return; + + default: + break; + } + + tickStartTM = now; + intendedTickLength = NextTickLength(WhiteOnMove(forwardMostMove) ? + whiteTimeRemaining : blackTimeRemaining); + StartClockTimer(intendedTickLength); +} + + +/* Stop both clocks */ +void +StopClocks() +{ + long lastTickLength; + TimeMark now; + + if (!StopClockTimer()) return; + if (!appData.clockMode) return; + + GetTimeMark(&now); + + lastTickLength = SubtractTimeMarks(&now, &tickStartTM); + if (WhiteOnMove(forwardMostMove)) { + whiteTimeRemaining -= lastTickLength; + DisplayWhiteClock(whiteTimeRemaining, WhiteOnMove(currentMove)); + } else { + blackTimeRemaining -= lastTickLength; + DisplayBlackClock(blackTimeRemaining, !WhiteOnMove(currentMove)); + } + CheckFlags(); +} + +/* Start clock of player on move. Time may have been reset, so + if clock is already running, stop and restart it. */ +void +StartClocks() +{ + (void) StopClockTimer(); /* in case it was running already */ + DisplayBothClocks(); + if (CheckFlags()) return; + + if (!appData.clockMode) return; + if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) return; + + GetTimeMark(&tickStartTM); + intendedTickLength = NextTickLength(WhiteOnMove(forwardMostMove) ? + whiteTimeRemaining : blackTimeRemaining); + StartClockTimer(intendedTickLength); +} + +char * +TimeString(ms) + long ms; +{ + long second, minute, hour, day; + char *sign = ""; + static char buf[32]; + + if (ms > 0 && ms <= 9900) { + /* convert milliseconds to tenths, rounding up */ + double tenths = floor( ((double)(ms + 99L)) / 100.00 ); + + sprintf(buf, " %03.1f ", tenths/10.0); + return buf; + } + + /* convert milliseconds to seconds, rounding up */ + /* use floating point to avoid strangeness of integer division + with negative dividends on many machines */ + second = (long) floor(((double) (ms + 999L)) / 1000.0); + + if (second < 0) { + sign = "-"; + second = -second; + } + + day = second / (60 * 60 * 24); + second = second % (60 * 60 * 24); + hour = second / (60 * 60); + second = second % (60 * 60); + minute = second / 60; + second = second % 60; + + if (day > 0) + sprintf(buf, " %s%ld:%02ld:%02ld:%02ld ", + sign, day, hour, minute, second); + else if (hour > 0) + sprintf(buf, " %s%ld:%02ld:%02ld ", sign, hour, minute, second); + else + sprintf(buf, " %s%2ld:%02ld ", sign, minute, second); + + return buf; +} + + +/* + * This is necessary because some C libraries aren't ANSI C compliant yet. + */ +char * +StrStr(string, match) + char *string, *match; +{ + int i, length; + + length = strlen(match); + + for (i = strlen(string) - length; i >= 0; i--, string++) + if (!strncmp(match, string, length)) + return string; + + return NULL; +} + +char * +StrCaseStr(string, match) + char *string, *match; +{ + int i, j, length; + + length = strlen(match); + + for (i = strlen(string) - length; i >= 0; i--, string++) { + for (j = 0; j < length; j++) { + if (ToLower(match[j]) != ToLower(string[j])) + break; + } + if (j == length) return string; + } + + return NULL; +} + +#ifndef _amigados +int +StrCaseCmp(s1, s2) + char *s1, *s2; +{ + char c1, c2; + + for (;;) { + c1 = ToLower(*s1++); + c2 = ToLower(*s2++); + if (c1 > c2) return 1; + if (c1 < c2) return -1; + if (c1 == NULLCHAR) return 0; + } +} + + +int +ToLower(c) + int c; +{ + return isupper(c) ? tolower(c) : c; +} + + +int +ToUpper(c) + int c; +{ + return islower(c) ? toupper(c) : c; +} +#endif /* !_amigados */ + +char * +StrSave(s) + char *s; +{ + char *ret; + + if ((ret = (char *) malloc(strlen(s) + 1))) { + strcpy(ret, s); + } + return ret; +} + +char * +StrSavePtr(s, savePtr) + char *s, **savePtr; +{ + if (*savePtr) { + free(*savePtr); + } + if ((*savePtr = (char *) malloc(strlen(s) + 1))) { + strcpy(*savePtr, s); + } + return(*savePtr); +} + +char * +PGNDate() +{ + time_t clock; + struct tm *tm; + char buf[MSG_SIZ]; + + clock = time((time_t *)NULL); + tm = localtime(&clock); + sprintf(buf, "%04d.%02d.%02d", + tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday); + return StrSave(buf); +} + + +char * +PositionToFEN(move) + int move; +{ + int i, j, fromX, fromY, toX, toY; + int whiteToPlay; + char buf[128]; + char *p, *q; + int emptycount; + + whiteToPlay = (gameMode == EditPosition) ? + !blackPlaysFirst : (move % 2 == 0); + p = buf; + + /* Piece placement data */ + for (i = BOARD_SIZE - 1; i >= 0; i--) { + emptycount = 0; + for (j = 0; j < BOARD_SIZE; j++) { + if (boards[move][i][j] == EmptySquare) { + emptycount++; + } else { + if (emptycount > 0) { + *p++ = '0' + emptycount; + emptycount = 0; + } + *p++ = PieceToChar(boards[move][i][j]); + } + } + if (emptycount > 0) { + *p++ = '0' + emptycount; + emptycount = 0; + } + *p++ = '/'; + } + *(p - 1) = ' '; + + /* Active color */ + *p++ = whiteToPlay ? 'w' : 'b'; + *p++ = ' '; + + /* !!We don't keep track of castling availability, so fake it */ + q = p; + if (boards[move][0][4] == WhiteKing) { + if (boards[move][0][7] == WhiteRook) *p++ = 'K'; + if (boards[move][0][0] == WhiteRook) *p++ = 'Q'; + } + if (boards[move][7][4] == BlackKing) { + if (boards[move][7][7] == BlackRook) *p++ = 'k'; + if (boards[move][7][0] == BlackRook) *p++ = 'q'; + } + if (q == p) *p++ = '-'; + *p++ = ' '; + + /* En passant target square */ + if (move > backwardMostMove) { + fromX = moveList[move - 1][0] - 'a'; + fromY = moveList[move - 1][1] - '1'; + toX = moveList[move - 1][2] - 'a'; + toY = moveList[move - 1][3] - '1'; + if (fromY == (whiteToPlay ? 6 : 1) && + toY == (whiteToPlay ? 4 : 3) && + boards[move][toY][toX] == (whiteToPlay ? BlackPawn : WhitePawn) && + fromX == toX) { + /* 2-square pawn move just happened */ + *p++ = toX + 'a'; + *p++ = whiteToPlay ? '6' : '3'; + } else { + *p++ = '-'; + } + } else { + *p++ = '-'; + } + + /* !!We don't keep track of halfmove clock for 50-move rule */ + strcpy(p, " 0 "); + p += 3; + + /* Fullmove number */ + sprintf(p, "%d", (move / 2) + 1); + + return StrSave(buf); +} + +Boolean +ParseFEN(board, blackPlaysFirst, fen) + Board board; + int *blackPlaysFirst; + char *fen; +{ + int i, j; + char *p; + int emptycount; + + p = fen; + + /* Piece placement data */ + for (i = BOARD_SIZE - 1; i >= 0; i--) { + j = 0; + for (;;) { + if (*p == '/' || *p == ' ') { + if (*p == '/') p++; + emptycount = BOARD_SIZE - j; + while (emptycount--) board[i][j++] = EmptySquare; + break; + } else if (isdigit(*p)) { + emptycount = *p++ - '0'; + if (j + emptycount > BOARD_SIZE) return FALSE; + while (emptycount--) board[i][j++] = EmptySquare; + } else if (isalpha(*p)) { + if (j >= BOARD_SIZE) return FALSE; + board[i][j++] = CharToPiece(*p++); + } else { + return FALSE; + } + } + } + while (*p == '/' || *p == ' ') p++; + + /* Active color */ + switch (*p) { + case 'w': + *blackPlaysFirst = FALSE; + break; + case 'b': + *blackPlaysFirst = TRUE; + break; + default: + return FALSE; + } + /* !!We ignore the rest of the FEN notation */ + return TRUE; +} + +void +EditPositionPasteFEN(char *fen) +{ + if (fen != NULL) { + Board initial_position; + + if (!ParseFEN(initial_position, &blackPlaysFirst, fen)) { + DisplayError("Bad FEN position in clipboard", 0); + return ; + } else { + int savedBlackPlaysFirst = blackPlaysFirst; + EditPositionEvent(); + blackPlaysFirst = savedBlackPlaysFirst; + CopyBoard(boards[0], initial_position); + EditPositionDone(); + DisplayBothClocks(); + DrawPosition(FALSE, boards[currentMove]); + } + } +} diff --git a/winboard-dm-beta4/backend.h b/winboard-dm-beta4/backend.h new file mode 100755 index 00000000..6e6aee23 --- /dev/null +++ b/winboard-dm-beta4/backend.h @@ -0,0 +1,288 @@ +/* + * backend.h -- Interface exported by XBoard back end + * $Id$ + * + * Copyright 1991 by Digital Equipment Corporation, Maynard, Massachusetts. + * Enhancements Copyright 1992-95 Free Software Foundation, Inc. + * + * The following terms apply to Digital Equipment Corporation's copyright + * interest in XBoard: + * ------------------------------------------------------------------------ + * All Rights Reserved + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appear in all copies and that + * both that copyright notice and this permission notice appear in + * supporting documentation, and that the name of Digital not be + * used in advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. + * + * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING + * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL + * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR + * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, + * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + * ------------------------------------------------------------------------ + * + * The following terms apply to the enhanced version of XBoard distributed + * by the Free Software Foundation: + * ------------------------------------------------------------------------ + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * ------------------------------------------------------------------------ + */ +#ifndef _BACKEND +#define _BACKEND + +#include "lists.h" +#include "frontend.h" + +extern int gotPremove; +extern int pausing, cmailMsgLoaded, flipView; +extern char white_holding[], black_holding[]; +extern int currentMove, backwardMostMove, forwardMostMove; +extern int blackPlaysFirst; +extern FILE *debugFP; +extern char* programVersion; +extern ProcRef firstProgramPR, secondProgramPR; +extern Board boards[]; + +char *CmailMsg P((void)); +char *PositionToFEN P((int move)); +void EditPositionPasteFEN P((char *fen)); +void TimeDelay P((long ms)); +void SendMultiLineToICS P(( char *text )); +void AnalysisPeriodicEvent P((int force)); +void SetWhiteToPlayEvent P((void)); +void SetBlackToPlayEvent P((void)); +void InitBackEnd1 P((void)); +void InitBackEnd2 P((void)); +void ConsoleCreate P((void)); +void DisplayAnalysis P((int NewState, int pv)); +int IsPromotion P((int fromX, int fromY, int toX, int toY)); +int PieceForSquare P((int x, int y)); +int OKToStartUserMove P((int x, int y)); +void Reset P((int redraw, int init)); +void ResetGameEvent P((void)); +int LoadGame P((FILE *f, int n, char *title, int useList)); +int LoadGameFromFile P((char *filename, int n, char *title, int useList)); +int CmailLoadGame P((FILE *f, int n, char *title, int useList)); +int ReloadGame P((int offset)); +int SaveGame P((FILE *f, int dummy, char *dummy2)); +int SaveGameToFile P((char *filename, int append)); +int LoadPosition P((FILE *f, int n, char *title)); +int ReloadPosition P((int offset)); +int SavePosition P((FILE *f, int dummy, char *dummy2)); +void EditPositionEvent P((void)); +void FlipViewEvent P((void)); +void MachineWhiteEvent P((void)); +void MachineBlackEvent P((void)); +void TwoMachinesEvent P((void)); +void EditGameEvent P((void)); +void TrainingEvent P((void)); +void IcsClientEvent P((void)); +void ForwardEvent P((void)); +void BackwardEvent P((void)); +void ToEndEvent P((void)); +void ToStartEvent P((void)); +void ToNrEvent P((int to)); +void RevertEvent P((void)); +void RetractMoveEvent P((void)); +void MoveNowEvent P((void)); +void TruncateGameEvent P((void)); +void ResetIcsQueue P((int gamenumber)); +void PauseEvent P((void)); +void CallFlagEvent P((void)); +void AcceptEvent P((void)); +void DeclineEvent P((void)); +void RematchEvent P((void)); +void DrawEvent P((void)); +void AbortEvent P((void)); +void AdjournEvent P((void)); +void ResignEvent P((void)); +void StopObservingEvent P((void)); +void StopExaminingEvent P((void)); +void PonderNextMoveEvent P((int newState)); +void ShowThinkingEvent P((int newState)); +void IcsAnalyze P((int newState)); +void IcsAnalyzeWindowUp P((void)); +void PeriodicUpdatesEvent P((int newState)); +void HintEvent P((void)); +void BookEvent P((void)); +void AboutGameEvent P((void)); +void ExitEvent P((int status)); +char *DefaultFileName P((char *)); +void UserMoveEvent P((int fromX, int fromY, int toX, int toY, int promoChar)); +void DecrementClocks P((void)); +char *TimeString P((long millisec)); +void AutoPlayGameLoop P((void)); +void DisplayBothClocks P((void)); +void EditPositionMenuEvent P((ChessSquare selection, int x, int y)); +void DropMenuEvent P((ChessSquare selection, int x, int y)); +int ParseTimeControl P((char *tc, int ti, int mps)); +void ProcessICSInitScript P((FILE * f)); +void EditCommentEvent P((void)); +void ReplaceComment P((int index, char *text)); +int ReplaceTags P((char *tags, GameInfo *gi));/* returns nonzero on error */ +void AppendComment P((int index, char *text)); +void ReloadCmailMsgEvent P((int unregister)); +void MailMoveEvent P((void)); +void EditTagsEvent P((void)); +void GetMoveListEvent P((void)); +void ExitAnalyzeMode P((void)); +void AnalyzeModeEvent P((void)); +void AnalyzeFileEvent P((void)); +void DoEcho P((void)); +void DontEcho P((void)); +void TidyProgramName P((char *prog, char *host, char *buf)); +void AskQuestionEvent P((char *title, char *question, + char *replyPrefix, char *which)); +Boolean ParseOneMove P((char *move, int moveNum, + ChessMove *moveType, int *fromX, int *fromY, + int *toX, int *toY, char *promoChar)); +char *VariantName P((VariantClass v)); +VariantClass StringToVariant P((char *e)); + +char *StrStr P((char *string, char *match)); +char *StrCaseStr P((char *string, char *match)); +char *StrSave P((char *s)); +char *StrSavePtr P((char *s, char **savePtr)); + +#ifndef _amigados +int StrCaseCmp P((char *s1, char *s2)); +int ToLower P((int c)); +int ToUpper P((int c)); +#else +#define StrCaseCmp Stricmp /* Use utility.library functions */ +#include +#endif + +extern GameInfo gameInfo; + + +/* pgntags.c prototypes + */ +char *PGNTags P((GameInfo *)); +void PrintPGNTags P((FILE *f, GameInfo *)); +int ParsePGNTag P((char *, GameInfo *)); +char *PGNResult P((ChessMove result)); + + +/* gamelist.c prototypes + */ +/* A game node in the double linked list of games. + */ +typedef struct _ListGame { + ListNode node; + int number; + unsigned long offset; /* Byte offset of game within file. */ + GameInfo gameInfo; /* Note that some entries may be NULL. */ +} ListGame; + +extern List gameList; +void ClearGameInfo P((GameInfo *)); +int GameListBuild P((FILE *)); +void GameListInitGameInfo P((GameInfo *)); +char *GameListLine P((int, GameInfo *)); + +extern char* StripHighlight P((char *)); /* returns static data */ +extern char* StripHighlightAndTitle P((char *)); /* returns static data */ + + +typedef struct _CPS { + char *which; + int maybeThinking; + ProcRef pr; + InputSourceRef isr; + char *twoMachinesColor; /* "white\n" or "black\n" */ + char *program; + char *host; + char *dir; + struct _CPS *other; + char *initString; + char *computerString; + int sendTime; /* 0=don't, 1=do, 2=test */ + int sendDrawOffers; + int useSigint; + int useSigterm; + int offeredDraw; /* countdown */ + int reuse; + int useSetboard; /* 0=use "edit"; 1=use "setboard" */ + int useSAN; /* 0=use coordinate notation; 1=use SAN */ + int usePing; /* 0=not OK to use ping; 1=OK */ + int lastPing; + int lastPong; + int usePlayother;/* 0=not OK to use playother; 1=OK */ + int useColors; /* 0=avoid obsolete white/black commands; 1=use them */ + int useUsermove; /* 0=just send move; 1=send "usermove move" */ + int sendICS; /* 0=don't use "ics" command; 1=do */ + int sendName; /* 0=don't use "name" command; 1=do */ + int sdKludge; /* 0=use "sd DEPTH" command; 1=use "depth\nDEPTH" */ + int stKludge; /* 0=use "st TIME" command; 1=use "level 1 TIME" */ + char tidy[MSG_SIZ]; + int matchWins; + char variants[MSG_SIZ]; + int analysisSupport; + int analyzing; + int protocolVersion; + int initDone; +} ChessProgramState; + +ChessProgramState first, second; + +/* max gamenumber on ICS + * i don't know the real value + * but i think 1500 is enought + * edit here if you want change + * if we over max value we break all + * action and make a fatal error + */ +#define max_gamenum 1500 + +/* Smart ICS outut Queue */ +typedef struct { + int counter; + long time; + int killPv; + int move; /* only for for killpv++ and -- + give not the realstic move number back !! + */ + int MessageMove; /* Last played move where we send a message */ + int CurrentMove; /* current movenumber on observing board */ + int flag; /* 0= we never send a message for this move 1= We send it */ + int event; /* Send event message to board "Hello, i'm..." */ + int gameNum; /* reserved */ + int currentGame; /* reserved */ + char lastpv[1024]; /* save last pv */ + char white[128]; /* white player name */ + char black[128]; /* black player name */ +} smartQueue; + +extern smartQueue icsQueue[max_gamenum]; + +int chessfm; + +/* rember if engine send a "stat01:" line for display */ +static int supportStat; /* 0 = false 1 = true */ + +/* save pv - reserved for future */ +typedef struct { + char mainline[1024]; +} PV[512]; +PV engineRoom, *er; + +#endif /* _BACKEND */ diff --git a/winboard-dm-beta4/backendz.h b/winboard-dm-beta4/backendz.h new file mode 100755 index 00000000..3bab93fb --- /dev/null +++ b/winboard-dm-beta4/backendz.h @@ -0,0 +1,72 @@ +/* + * backendz.h -- Internal interface exported by XBoard backend.c to zippy.c + * $Id$ + * + * Copyright 1991 by Digital Equipment Corporation, Maynard, Massachusetts. + * Enhancements Copyright 1992-95 Free Software Foundation, Inc. + * + * The following terms apply to Digital Equipment Corporation's copyright + * interest in XBoard: + * ------------------------------------------------------------------------ + * All Rights Reserved + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appear in all copies and that + * both that copyright notice and this permission notice appear in + * supporting documentation, and that the name of Digital not be + * used in advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. + * + * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING + * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL + * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR + * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, + * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + * ------------------------------------------------------------------------ + * + * The following terms apply to the enhanced version of XBoard distributed + * by the Free Software Foundation: + * ------------------------------------------------------------------------ + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * ------------------------------------------------------------------------ + */ + +#ifndef _BACKENDZ +#define _BACKENDZ + +#include "common.h" +#include "frontend.h" + +extern long whiteTimeRemaining, blackTimeRemaining; +extern int forwardMostMove; +extern char star_match[STAR_MATCH_N][MSG_SIZ]; +extern ProcRef firstProgramPR; +extern int startedFromSetupPosition; +extern int firstMove; +extern GameInfo gameInfo; +extern void SendToICS P((char *s)); +extern int looking_at P((char *, int *, char *)); +extern void SendToProgram P((char *message, ChessProgramState *cps)); +extern void SendBoard P((ChessProgramState *cps, int moveNum)); +void SendTimeRemaining P((ChessProgramState *cps, + int/*boolean*/ machineWhite)); + +extern char ics_handle[]; +extern char *ics_prefix; + +#endif diff --git a/winboard-dm-beta4/common.h b/winboard-dm-beta4/common.h new file mode 100755 index 00000000..1a0e6581 --- /dev/null +++ b/winboard-dm-beta4/common.h @@ -0,0 +1,488 @@ +/* + * common.h -- Common definitions for X and Windows NT versions of XBoard + * $Id$ + * + * Copyright 1991 by Digital Equipment Corporation, Maynard, Massachusetts. + * Enhancements Copyright 1992-95 Free Software Foundation, Inc. + * + * The following terms apply to Digital Equipment Corporation's copyright + * interest in XBoard: + * ------------------------------------------------------------------------ + * All Rights Reserved + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appear in all copies and that + * both that copyright notice and this permission notice appear in + * supporting documentation, and that the name of Digital not be + * used in advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. + * + * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING + * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL + * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR + * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, + * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + * ------------------------------------------------------------------------ + * + * The following terms apply to the enhanced version of XBoard distributed + * by the Free Software Foundation: + * ------------------------------------------------------------------------ + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * ------------------------------------------------------------------------ + */ + +#ifndef _COMMON +#define _COMMON + +/* Begin compatibility grunge */ + +#if defined(__STDC__) || defined(WIN32) || defined(_amigados) +#define P(args) args +typedef void *VOIDSTAR; +#else +#define P(args) () +typedef char *VOIDSTAR; +#endif + +#ifdef WIN32 +typedef char Boolean; +typedef char *String; +#define popen _popen +#define pclose _pclose + +#else +#ifdef _amigados /* It is important, that these types have */ +typedef int Boolean; /* a length of 4 bytes each, as we are */ +typedef char *String; /* using ReadArgs() for argument parsing. */ +#ifdef _DCC +FILE *popen(const char *, const char *); +int pclose(FILE *); +#endif + +#else +#include +#endif +#endif + + +#ifndef TRUE +#define TRUE 1 +#define FALSE 0 +#endif + +#if !HAVE_RANDOM +# if HAVE_RAND48 +# define srandom srand48 +# define random lrand48 +# else /* not HAVE_RAND48 */ +# define srandom srand +# define random rand +# endif /* not HAVE_RAND48 */ +#endif /* !HAVE_RANDOM */ + +/* End compatibility grunge */ + +#define PROTOVER 2 /* engine protocol version */ + +#define BOARD_SIZE 8 +#define DROP_RANK -3 +#define MAX_MOVES 1000 +#define MSG_SIZ 2048 +#define DIALOG_SIZE 256 +#define STAR_MATCH_N 16 +#define MOVE_LEN 32 +#define TIME_CONTROL "5" /* in minutes */ +#define TIME_DELAY_QUOTE "1.0" /* seconds between moves */ +#define TIME_DELAY ((float) 1.0) +#define MOVES_PER_SESSION 40 /* moves per TIME_CONTROL */ +#define TIME_INCREMENT -1 /* if >= 0, MOVES_PER_SESSION unused */ +#define WhiteOnMove(move) (((move) % 2) == 0) +#define ICS_HOST "chessclub.com" +#define ICS_PORT "5000" +#define ICS_COMM_PORT "" +#define FIRST_HOST "localhost" +#define SECOND_HOST "localhost" +#define TELNET_PROGRAM "telnet" +#define MATCH_MODE "False" +#define INIT_STRING "new\nrandom\n" +#define WHITE_STRING "white\ngo\n" +#define BLACK_STRING "black\ngo\n" +#define COMPUTER_STRING "computer\n" +#define REUSE_CHESS_PROGRAMS 1 +#define WHITE_PIECE_COLOR "#FFFFCC" +#define BLACK_PIECE_COLOR "#202020" +#define LIGHT_SQUARE_COLOR "#C8C365" +#define DARK_SQUARE_COLOR "#77A26D" +#define JAIL_SQUARE_COLOR "#808080" +#define HIGHLIGHT_SQUARE_COLOR "#FFFF00" +#define PREMOVE_HIGHLIGHT_COLOR "#FF0000" +#define BELLCHAR '\007' +#define NULLCHAR '\000' +#define FEATURE_TIMEOUT 10000 /*ms*/ + +/* Zippy defaults */ +#define ZIPPY_TALK FALSE +#define ZIPPY_PLAY FALSE +#define ZIPPY_LINES "yow.lines" +#define ZIPPY_PINHEAD "" +#define ZIPPY_PASSWORD "" +#define ZIPPY_PASSWORD2 "" +#define ZIPPY_PASSWORD3 "" +#define ZIPPY_WRONG_PASSWORD "" +#define ZIPPY_ACCEPT_ONLY "" +#define ZIPPY_USE_I TRUE +#define ZIPPY_BUGHOUSE 0 +#define ZIPPY_NOPLAY_CRAFTY FALSE +#define ZIPPY_GAME_END "gameend\n" +#define ZIPPY_GAME_START "" +#define ZIPPY_ADJOURN FALSE +#define ZIPPY_ABORT FALSE +#define ZIPPY_VARIANTS "normal" +#define ZIPPY_MAX_GAMES 0 +#define ZIPPY_REPLAY_TIMEOUT 120 + +typedef enum { + BeginningOfGame, MachinePlaysWhite, MachinePlaysBlack, + AnalyzeMode, AnalyzeFile, TwoMachinesPlay, + EditGame, PlayFromGameFile, EndOfGame, EditPosition, Training, + IcsIdle, IcsPlayingWhite, IcsPlayingBlack, IcsObserving, + IcsExamining + } GameMode; + +GameMode gameMode; + +typedef enum { + WhitePawn, WhiteKnight, WhiteBishop, WhiteRook, WhiteQueen, WhiteKing, + BlackPawn, BlackKnight, BlackBishop, BlackRook, BlackQueen, BlackKing, + EmptySquare, + ClearBoard, WhitePlay, BlackPlay /*for use on EditPosition menus*/ + } ChessSquare; + +typedef ChessSquare Board[BOARD_SIZE][BOARD_SIZE]; + +typedef enum { + WhiteKingSideCastle = 1, WhiteQueenSideCastle, + WhiteKingSideCastleWild, WhiteQueenSideCastleWild, + WhiteHSideCastleFR, WhiteASideCastleFR, + BlackKingSideCastle, BlackQueenSideCastle, + BlackKingSideCastleWild, BlackQueenSideCastleWild, + BlackHSideCastleFR, BlackASideCastleFR, + WhitePromotionKnight, WhitePromotionBishop, + WhitePromotionRook, WhitePromotionQueen, WhitePromotionKing, + BlackPromotionKnight, BlackPromotionBishop, + BlackPromotionRook, BlackPromotionQueen, BlackPromotionKing, + WhiteCapturesEnPassant, BlackCapturesEnPassant, + WhiteDrop, BlackDrop, + NormalMove, AmbiguousMove, IllegalMove, ImpossibleMove, + WhiteWins, BlackWins, GameIsDrawn, GameUnfinished, + GNUChessGame, XBoardGame, MoveNumberOne, + Comment, PositionDiagram, ElapsedTime, PGNTag, NAG + } ChessMove; + +typedef enum { + ColorShout, ColorSShout, ColorChannel1, ColorChannel, ColorKibitz, + ColorTell, ColorChallenge, ColorRequest, ColorSeek, ColorNormal, + ColorNone, NColorClasses +} ColorClass; + +typedef enum { + SoundMove, SoundBell, SoundAlarm, SoundIcsWin, SoundIcsLoss, + SoundIcsDraw, SoundIcsUnfinished, NSoundClasses +} SoundClass; + +/* Names for chess variants, not necessarily supported */ +typedef enum { + VariantNormal, /* Normal chess */ + VariantLoadable, /* "loadgame" command allowed (not really a variant)*/ + VariantWildCastle, /* Shuffle chess where king can castle from d file */ + VariantNoCastle, /* Shuffle chess with no castling at all */ + VariantFischeRandom, /* FischeRandom */ + VariantBughouse, /* Bughouse, ICC/FICS rules */ + VariantCrazyhouse, /* Crazyhouse, ICC/FICS rules */ + VariantLosers, /* Try to lose all pieces or get mated (ICC wild 17)*/ + VariantSuicide, /* Try to lose all pieces incl. king (FICS) */ + VariantGiveaway, /* Try to have no legal moves left (ICC wild 26) */ + VariantTwoKings, /* Weird ICC wild 9 */ + VariantKriegspiel, /* Kriegspiel; pawns can capture invisible pieces */ + VariantAtomic, /* Capturing piece explodes (ICC wild 27) */ + Variant3Check, /* Win by giving check 3 times (ICC wild 25) */ + VariantShatranj, /* Unsupported (ICC wild 28) */ + Variant29, /* Temporary name for possible future ICC wild 29 */ + Variant30, /* Temporary name for possible future ICC wild 30 */ + Variant31, /* Temporary name for possible future ICC wild 31 */ + Variant32, /* Temporary name for possible future ICC wild 32 */ + Variant33, /* Temporary name for possible future ICC wild 33 */ + Variant34, /* Temporary name for possible future ICC wild 34 */ + Variant35, /* Temporary name for possible future ICC wild 35 */ + Variant36, /* Temporary name for possible future ICC wild 36 */ + VariantUnknown /* Catchall for other unknown variants */ +} VariantClass; + +#define VARIANT_NAMES { \ + "normal", \ + "normal", \ + "wildcastle", \ + "nocastle", \ + "fischerandom", \ + "bughouse", \ + "crazyhouse", \ + "losers", \ + "suicide", \ + "giveaway", \ + "twokings", \ + "kriegspiel", \ + "atomic", \ + "3check", \ + "shatranj", \ + "wild29", \ + "wild30", \ + "wild31", \ + "wild32", \ + "wild33", \ + "wild34", \ + "wild35", \ + "wild36", \ + "unknown" \ +} + +typedef struct { +#if !defined(_amigados) + char *whitePieceColor; + char *blackPieceColor; + char *lightSquareColor; + char *darkSquareColor; + char *jailSquareColor; + char *highlightSquareColor; + char *premoveHighlightColor; +#else + int whitePieceColor; + int blackPieceColor; + int lightSquareColor; + int darkSquareColor; + int jailSquareColor; + int highlightSquareColor; + int premoveHighlightColor; +#endif + int movesPerSession; + int timeIncrement; + char *initString; + char *secondInitString; + char *firstComputerString; + char *secondComputerString; + char *firstChessProgram; + char *secondChessProgram; + char *firstDirectory; + char *secondDirectory; + Boolean firstPlaysBlack; + Boolean noChessProgram; + char *firstHost; + char *secondHost; + char *bitmapDirectory; + char *remoteShell; + char *remoteUser; + float timeDelay; + char *timeControl; + Boolean icsActive; + char *icsHost; + char *icsPort; + char *icsCommPort; /* if set, use serial port instead of tcp host/port */ + char *icsLogon; /* Hack to permit variable logon scripts. */ + char *icsHelper; + Boolean icsInputBox; + Boolean useTelnet; + char *telnetProgram; + char *gateway; + char *loadGameFile; + int loadGameIndex; /* game # within file */ + char *saveGameFile; + Boolean autoSaveGames; + char *loadPositionFile; + int loadPositionIndex; /* position # within file */ + char *savePositionFile; + Boolean matchMode; + int matchGames; + Boolean monoMode; + Boolean debugMode; + Boolean clockMode; + /* daniel */ + Boolean userVersion; /* programmer version */ + Boolean icsAnalyze; + Boolean icsEngineKillPV; + Boolean icsEngineWhisper; + Boolean icsEngineKibitz; + Boolean icsEngineTell; + Boolean icsEngineNone; + Boolean icsAnalyzeWindow; + Boolean smartQueue; /* Live broadcast quere */ + Boolean ICC_feature; /* Enable special ICC fetures */ + Boolean windowMove; /* Drop fail high/low moves at icsAnalyzeOutPut */ + int icsAnalyzeOutPut; /* 1=whisper 2=kibitz 3=tell 4=none */ + int icsKillPVs; + char icsTells[MSG_SIZ]; /* handle/channel do we tell somthing */ + Boolean icsWBprotoNorm; + Boolean icsWBprotoAgr; + int icsWBproto; /* dummy */ + int icsSmartQueue; /* 0 = standard game 1 = Blitzgame */ + /* Split smartQueue with int because i want more for the future */ + Boolean icsSmartQueueStd; + Boolean icsSmartQueueBlitz; + Boolean icsShowBook; /* True = show book False = disable */ + Boolean AnalysisWindow; /* Engine Room */ + Boolean engineStart; /* EngineRoom Button */ + Boolean engineTourneyMode; /* EngineRoom checkbox tourneyMode */ + Boolean engineStatLine; /* EngineRoom Statline disable */ + Boolean zippyDraw; /* active zippy draw Handling ? */ + int SendOutPutToICS; /* Analysis window: Send thinking lines to ICS */ + /* 0 none 1 whisper 2 kibitz */ + Boolean ButtonSendOutPutToICS; /* Checkbox analysis window */ + char *boardSize; + Boolean Iconic; + char *searchTime; + int searchDepth; + Boolean showCoords; + char *clockFont; + char *messageFont; /* WinBoard only */ + char *coordFont; + char *font; /* xboard only: all other fonts */ + char *tagsFont; /* WinBoard only */ + char *commentFont; /* WinBoard only */ + char *icsFont; /* WinBoard only */ + Boolean ringBellAfterMoves; + Boolean autoCallFlag; + Boolean flipView; + Boolean autoFlipView; + char *cmailGameName; /* xboard only */ + Boolean alwaysPromoteToQueen; + Boolean oldSaveStyle; + Boolean quietPlay; + Boolean showThinking; + Boolean ponderNextMove; + Boolean periodicUpdates; + Boolean autoObserve; + Boolean autoComment; + Boolean getMoveList; + Boolean testLegality; + int borderXoffset; /* xboard only */ + int borderYoffset; /* xboard only */ + Boolean titleInWindow; /* xboard only */ + Boolean localLineEditing; /* WinBoard only */ + Boolean zippyTalk; + Boolean zippyPlay; + int flashCount; /* Number of times to flash (xboard only) */ + int flashRate; /* Flashes per second (xboard only) */ + char *pixmapDirectory; /* Path to XPM/XIM files to use (xboard only) */ + int msLoginDelay; /* Delay per character (in msec) while sending + ICS logon script (xboard only) */ + Boolean colorize; /* If True, use the following colors to color text */ + /* Strings for colors, as "fg, bg, bold" (strings used in xboard only) */ + char *colorShout; + char *colorSShout; + char *colorChannel1; + char *colorChannel; + char *colorKibitz; + char *colorTell; + char *colorChallenge; + char *colorRequest; + char *colorSeek; + char *colorNormal; + char *soundProgram; /* sound-playing program */ + char *soundShout; + char *soundSShout; + char *soundChannel1; + char *soundChannel; + char *soundKibitz; + char *soundTell; + char *soundChallenge; + char *soundRequest; + char *soundSeek; + char *soundMove; + char *soundIcsWin; + char *soundIcsLoss; + char *soundIcsDraw; + char *soundIcsUnfinished; + char *soundIcsAlarm; + Boolean reuseFirst; + Boolean reuseSecond; + Boolean animateDragging; /* If True, animate mouse dragging of pieces */ + Boolean animate; /* If True, animate non-mouse moves */ + int animSpeed; /* Delay in milliseconds between animation frames */ + Boolean popupMoveErrors; + Boolean popupExitMessage; + int showJail; + Boolean highlightLastMove; + Boolean highlightDragging; + Boolean blindfold; /* if true, no pieces are drawn */ + Boolean premove; /* true if premove feature enabled */ + Boolean premoveWhite; /* true if premoving White first move */ + char *premoveWhiteText; /* text of White premove 1 */ + Boolean premoveBlack; /* true if premoving Black first move */ + char *premoveBlackText; /* text of Black premove 1 */ + Boolean icsAlarm; /* true if sounding alarm at a certain time */ + int icsAlarmTime; /* time to sound alarm, in milliseconds */ + Boolean autoRaiseBoard; + int fontSizeTolerance; /* xboard only */ + char *initialMode; + char *variant; + int firstProtocolVersion; + int secondProtocolVersion; + Boolean showButtonBar; +#if ZIPPY + char *zippyLines; + char *zippyPinhead; + char *zippyPassword; + char *zippyPassword2; + char *zippyPassword3; + char *zippyWrongPassword; + char *zippyAcceptOnly; + int zippyUseI; + int zippyBughouse; + int zippyNoplayCrafty; + char *zippyGameEnd; + char *zippyGameStart; + int zippyAdjourn; + int zippyAbort; + char *zippyVariants; + int zippyMaxGames; + int zippyReplayTimeout; /*seconds*/ +#endif +} AppData, *AppDataPtr; + +extern AppData appData; + +typedef struct { + /* PGN 7-tag info */ + char *event; + char *site; + char *date; + char *round; + char *white; + char *black; + ChessMove result; + /* Additional info */ + char *fen; /* NULL or FEN for starting position; input only */ + char *resultDetails; + char *timeControl; + char *extraTags; /* NULL or "[Tag \"Value\"]\n", etc. */ + int whiteRating; /* -1 if unknown */ + int blackRating; /* -1 if unknown */ + VariantClass variant; +} GameInfo; + + + +#endif diff --git a/winboard-dm-beta4/config.h b/winboard-dm-beta4/config.h new file mode 100755 index 00000000..3f3bf187 --- /dev/null +++ b/winboard-dm-beta4/config.h @@ -0,0 +1,130 @@ +/* config.h.in. Generated automatically from configure.in by autoheader. */ + +/* Define if you have that is POSIX.1 compatible. */ +/*#undef HAVE_SYS_WAIT_H*/ + +/* Define if you need to in order for stat and other things to work. */ +/*#undef _POSIX_SOURCE*/ + +/* Define as the return type of signal handlers (int or void). */ +/*#undef RETSIGTYPE*/ + +/* Define if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Define if you can safely include both and . */ +/*#undef TIME_WITH_SYS_TIME*/ + +/* Define if lex declares yytext as a char * by default, not a char[]. */ +/*#undef YYTEXT_POINTER*/ + +/*#define FIRST_PTY_LETTER 'p'*/ + +#define HAVE_FCNTL_H 1 + +#define HAVE_GETHOSTNAME 0 + +#define HAVE_GETTIMEOFDAY 0 + +#define HAVE_RANDOM 0 + +#define HAVE_SYS_SOCKET_H 0 + +/*#undef IBMRTAIX*/ + +#define LAST_PTY_LETTER 'q' + +#define PATCHLEVEL "6-dm-beta4" + +#define PRODUCT "WinBoard" + +#define PTY_ITERATION + +#define PTY_NAME_SPRINTF + +#define PTY_TTY_NAME_SPRINTF + +#define REMOTE_SHELL "" + +/*#undef RTU*/ + +/*#undef UNIPLUS*/ + +#define USE_PTYS 0 + +#define VERSION "4.2" + +/*#undef X_WCHAR*/ + +#ifndef __BORLANDC__ +#define WIN32 1 +#else +#define WIN32 +#endif + +#define ZIPPY 1 + +/* Define if you have the _getpty function. */ +/*#undef HAVE__GETPTY*/ + +/* Define if you have the ftime function. */ +#define HAVE_FTIME 1 + +/* Define if you have the grantpt function. */ +/*#undef HAVE_GRANTPT*/ + +/* Define if you have the rand48 function. */ +/*#undef HAVE_RAND48*/ + +/* Define if you have the sysinfo function. */ +/*#undef HAVE_SYSINFO*/ + +/* Define if you have the header file. */ +/*#undef HAVE_LAN_SOCKET_H*/ + +/* Define if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define if you have the header file. */ +/*#undef HAVE_STROPTS_H*/ + +/* Define if you have the header file. */ +#define HAVE_SYS_FCNTL_H 0 + +/* Define if you have the header file. */ +/*#undef HAVE_SYS_SYSTEMINFO_H*/ + +/* Define if you have the header file. */ +/*#undef HAVE_SYS_TIME_H*/ + +/* Define if you have the header file. */ +/*#undef HAVE_UNISTD_H*/ + +/* Define if you have the i library (-li). */ +/*#undef HAVE_LIBI*/ + +/* Define if you have the seq library (-lseq). */ +/*#undef HAVE_LIBSEQ*/ + +/* + Options + -DEMULATE_RSH -DREMOTE_SHELL=\"\" is necessary on Windows 95, because it + does not have its own rsh command. It works better this way on NT too, + because the NT rsh does not propagate signals to the remote process. + -DATTENTION is included even though I haven't been able to send signals to + child processes on Windows, because at least I can send them over rsh to + Unix programs. On Windows I send a newline instead, which wakes up the + chess program if it's polling. On my GNU Chess port the newline actually + works even for Move Now. +*/ +#define EMULATE_RSH 1 +#define ATTENTION 1 + +#ifdef __BORLANDC__ +#define _strdup(x) strdup(x) +#define STRICT +#define _winmajor 3 /* windows 95 */ +#define SCF_DEFAULT 0x0000 +#define SCF_ALL 0x0004 +#endif + diff --git a/winboard-dm-beta4/defaults.h b/winboard-dm-beta4/defaults.h new file mode 100755 index 00000000..f5ea885f --- /dev/null +++ b/winboard-dm-beta4/defaults.h @@ -0,0 +1,249 @@ +/* + * defaults.h -- Default settings for Windows NT front end to XBoard + * + * Copyright 1991 by Digital Equipment Corporation, Maynard, Massachusetts. + * Enhancements Copyright 1992-97 Free Software Foundation, Inc. + * + * The following terms apply to Digital Equipment Corporation's copyright + * interest in XBoard: + * ------------------------------------------------------------------------ + * All Rights Reserved + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appear in all copies and that + * both that copyright notice and this permission notice appear in + * supporting documentation, and that the name of Digital not be + * used in advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. + * + * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING + * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL + * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR + * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, + * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + * ------------------------------------------------------------------------ + * + * The following terms apply to the enhanced version of XBoard distributed + * by the Free Software Foundation: + * ------------------------------------------------------------------------ + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * ------------------------------------------------------------------------ + */ + +/* Static */ +#define POSITION_FILT "Position files (*.fen,*.epd,*.pos)\0*.fen;*.epd;*.pos\0All files (*.*)\0*.*\0" +#define GAME_FILT "Game files (*.pgn,*.gam)\0*.pgn;*.gam\0All files (*.*)\0*.*\0" +#define SOUND_FILT "Wave files (*.wav)\0*.wav\0All files (*.*)\0*.*\0" +#define OUTER_MARGIN (tinyLayout ? 0 : 4) +#define INNER_MARGIN (tinyLayout ? 0 : 2) +#define MESSAGE_LINE_LEFTMARGIN 2 +#define MESSAGE_TEXT_MAX 256 +/*#define COLOR_ECHOOFF RGB(192,192,192)*/ +#define COLOR_ECHOOFF consoleBackgroundColor +#define WRAP_INDENT 200 + +/* Settable */ +#define FIRST_CHESS_PROGRAM "" +#define FIRST_DIRECTORY "" +#define SECOND_CHESS_PROGRAM "" +#define SECOND_DIRECTORY "" + +#define CLOCK_FONT_TINY "Arial:9.0 b" +#define CLOCK_FONT_TEENY "Arial:9.0 b" +#define CLOCK_FONT_DINKY "Arial:10.0 b" +#define CLOCK_FONT_PETITE "Arial:10.0 b" +#define CLOCK_FONT_SLIM "Arial:12.0 b" +#define CLOCK_FONT_SMALL "Arial:14.0 b" +#define CLOCK_FONT_MEDIOCRE "Arial:14.0 b" +#define CLOCK_FONT_MIDDLING "Arial:14.0 b" +#define CLOCK_FONT_AVERAGE "Arial:15.0 b" +#define CLOCK_FONT_MODERATE "Arial:16.0 b" +#define CLOCK_FONT_MEDIUM "Arial:16.0 b" +#define CLOCK_FONT_BULKY "Arial:17.0 b" +#define CLOCK_FONT_LARGE "Arial:19.0 b" +#define CLOCK_FONT_BIG "Arial:20.0 b" +#define CLOCK_FONT_HUGE "Arial:21.0 b" +#define CLOCK_FONT_GIANT "Arial:22.0 b" +#define CLOCK_FONT_COLOSSAL "Arial:23.0 b" +#define CLOCK_FONT_TITANIC "Arial:24.0 b" + +#define MESSAGE_FONT_TINY "Small Fonts:6.0" +#define MESSAGE_FONT_TEENY "Small Fonts:6.0" +#define MESSAGE_FONT_DINKY "Small Fonts:7.0" +#define MESSAGE_FONT_PETITE "Small Fonts:7.0" +#define MESSAGE_FONT_SLIM "Arial:8.0 b" +#define MESSAGE_FONT_SMALL "Arial:9.0 b" +#define MESSAGE_FONT_MEDIOCRE "Arial:9.0 b" +#define MESSAGE_FONT_MIDDLING "Arial:9.0 b" +#define MESSAGE_FONT_AVERAGE "Arial:10.0 b" +#define MESSAGE_FONT_MODERATE "Arial:10.0 b" +#define MESSAGE_FONT_MEDIUM "Arial:10.0 b" +#define MESSAGE_FONT_BULKY "Arial:10.0 b" +#define MESSAGE_FONT_LARGE "Arial:10.0 b" +#define MESSAGE_FONT_BIG "Arial:11.0 b" +#define MESSAGE_FONT_HUGE "Arial:11.0 b" +#define MESSAGE_FONT_GIANT "Arial:11.0 b" +#define MESSAGE_FONT_COLOSSAL "Arial:12.0 b" +#define MESSAGE_FONT_TITANIC "Arial:12.0 b" + +#define COORD_FONT_TINY "Small Fonts:4.0" +#define COORD_FONT_TEENY "Small Fonts:4.0" +#define COORD_FONT_DINKY "Small Fonts:5.0" +#define COORD_FONT_PETITE "Small Fonts:5.0" +#define COORD_FONT_SLIM "Small Fonts:6.0" +#define COORD_FONT_SMALL "Small Fonts:7.0" +#define COORD_FONT_MEDIOCRE "Small Fonts:7.0" +#define COORD_FONT_MIDDLING "Small Fonts:7.0" +#define COORD_FONT_AVERAGE "Arial:7.0 b" +#define COORD_FONT_MODERATE "Arial:7.0 b" +#define COORD_FONT_MEDIUM "Arial:7.0 b" +#define COORD_FONT_BULKY "Arial:7.0 b" +#define COORD_FONT_LARGE "Arial:7.0 b" +#define COORD_FONT_BIG "Arial:8.0 b" +#define COORD_FONT_HUGE "Arial:8.0 b" +#define COORD_FONT_GIANT "Arial:8.0 b" +#define COORD_FONT_COLOSSAL "Arial:9.0 b" +#define COORD_FONT_TITANIC "Arial:9.0 b" + +#define CONSOLE_FONT_TINY "Courier New:8.0" +#define CONSOLE_FONT_TEENY "Courier New:8.0" +#define CONSOLE_FONT_DINKY "Courier New:8.0" +#define CONSOLE_FONT_PETITE "Courier New:8.0" +#define CONSOLE_FONT_SLIM "Courier New:8.0" +#define CONSOLE_FONT_SMALL "Courier New:8.0" +#define CONSOLE_FONT_MEDIOCRE "Courier New:8.0" +#define CONSOLE_FONT_MIDDLING "Courier New:8.0" +#define CONSOLE_FONT_AVERAGE "Courier New:8.0" +#define CONSOLE_FONT_MODERATE "Courier New:8.0" +#define CONSOLE_FONT_MEDIUM "Courier New:8.0" +#define CONSOLE_FONT_BULKY "Courier New:8.0" +#define CONSOLE_FONT_LARGE "Courier New:8.0" +#define CONSOLE_FONT_BIG "Courier New:8.0" +#define CONSOLE_FONT_HUGE "Courier New:8.0" +#define CONSOLE_FONT_GIANT "Courier New:8.0" +#define CONSOLE_FONT_COLOSSAL "Courier New:8.0" +#define CONSOLE_FONT_TITANIC "Courier New:8.0" + +#define COMMENT_FONT_TINY "Arial:9.0" +#define COMMENT_FONT_TEENY "Arial:9.0" +#define COMMENT_FONT_DINKY "Arial:9.0" +#define COMMENT_FONT_PETITE "Arial:9.0" +#define COMMENT_FONT_SLIM "Arial:9.0" +#define COMMENT_FONT_SMALL "Arial:9.0" +#define COMMENT_FONT_MEDIOCRE "Arial:9.0" +#define COMMENT_FONT_MIDDLING "Arial:9.0" +#define COMMENT_FONT_AVERAGE "Arial:9.0" +#define COMMENT_FONT_MODERATE "Arial:9.0" +#define COMMENT_FONT_MEDIUM "Arial:9.0" +#define COMMENT_FONT_BULKY "Arial:9.0" +#define COMMENT_FONT_LARGE "Arial:9.0" +#define COMMENT_FONT_BIG "Arial:9.0" +#define COMMENT_FONT_HUGE "Arial:9.0" +#define COMMENT_FONT_GIANT "Arial:9.0" +#define COMMENT_FONT_COLOSSAL "Arial:9.0" +#define COMMENT_FONT_TITANIC "Arial:9.0" + +#define EDITTAGS_FONT_TINY "Courier New:8.0" +#define EDITTAGS_FONT_TEENY "Courier New:8.0" +#define EDITTAGS_FONT_DINKY "Courier New:8.0" +#define EDITTAGS_FONT_PETITE "Courier New:8.0" +#define EDITTAGS_FONT_SLIM "Courier New:8.0" +#define EDITTAGS_FONT_SMALL "Courier New:8.0" +#define EDITTAGS_FONT_MEDIUM "Courier New:8.0" +#define EDITTAGS_FONT_MEDIOCRE "Courier New:8.0" +#define EDITTAGS_FONT_MIDDLING "Courier New:8.0" +#define EDITTAGS_FONT_AVERAGE "Courier New:8.0" +#define EDITTAGS_FONT_MODERATE "Courier New:8.0" +#define EDITTAGS_FONT_BULKY "Courier New:8.0" +#define EDITTAGS_FONT_LARGE "Courier New:8.0" +#define EDITTAGS_FONT_BIG "Courier New:8.0" +#define EDITTAGS_FONT_HUGE "Courier New:8.0" +#define EDITTAGS_FONT_GIANT "Courier New:8.0" +#define EDITTAGS_FONT_COLOSSAL "Courier New:8.0" +#define EDITTAGS_FONT_TITANIC "Courier New:8.0" + +#define COLOR_SHOUT "#209000" +#define COLOR_SSHOUT "b #289808" +#define COLOR_CHANNEL1 "#2020E0" +#define COLOR_CHANNEL "b #4040FF" +#define COLOR_KIBITZ "b #FF00FF" +#define COLOR_TELL "b #FF0000" +#define COLOR_CHALLENGE "bi #FF0000" +#define COLOR_REQUEST "bi #FF0000" +#define COLOR_SEEK "#980808" +#define COLOR_NORMAL "#000000" +#define COLOR_NONE "#000000" +#define COLOR_BKGD "#FFFFFF" + +#define SOUND_BELL "$" + +#define BUILT_IN_SOUND_NAMES {\ + "Beepbeep", "Ching", "Click", "Cymbal", "Ding", "Drip", \ + "Gong", "Laser", "Move", "Penalty", "Phone", "Pop", "Pop2", \ + "Slap", "Squeak", "Swish", "Thud", "Whipcrack", \ + "Alarm", "Challenge", "Channel", "Channel1", "Draw", "Kibitz", \ + "Lose", "Request", "Seek", "Shout", "SShout", "Tell", "Unfinished", \ + "Win", NULL \ +} + +#define SETTINGS_FILE "winboard.ini" + +#define ICS_LOGON "ics.ini" + +#define ICS_NAMES "\ +chessclub.com /icsport=5000 /icshelper=timestamp\n\ +freechess.org /icsport=5000 /icshelper=timeseal\n\ +global.chessparlor.com /icsport=6000 /icshelper=timeseal\n\ +chess.net /icsport=5000\n\ +chess-square.com /icsport=5000\n\ +icchess.net /icsport=5000\n\ +zics.org /icsport=5000\n\ +jogo.cex.org.br /icsport=5000\n\ +ajedrez.cec.uchile.cl /icsport=5000\n\ +fly.cc.fer.hr /icsport=7890\n\ +freechess.nl /icsport=5000 /icshelper=timeseal\n\ +jeu.echecs.com /icsport=5000\n\ +chess.unix-ag.uni-kl.de /icsport=5000 /icshelper=timeseal\n\ +chess.mds.mdh.se /icsport=5000\n\ +" + +#define ICS_TEXT_MENU_DEFAULT "\ +-\n\ +&Who,who,0,1\n\ +Playe&rs,players,0,1\n\ +&Games,games,0,1\n\ +&Sought,sought,0,1\n\ +|&Tell (name),tell,1,0\n\ +M&essage (name),message,1,0\n\ +-\n\ +&Finger (name),finger,1,1\n\ +&Vars (name),vars,1,1\n\ +&Observe (name),observe,1,1\n\ +&Match (name),match,1,1\n\ +Pl&ay (name),play,1,1\n\ +" + +#define FCP_NAMES "\ +GNUChess\n\ +\"GNUChes5 xboard\"\n\ +" + +#define SCP_NAMES "\ +GNUChess\n\ +\"GNUChes5 xboard\"\n\ +" diff --git a/winboard-dm-beta4/frontend.h b/winboard-dm-beta4/frontend.h new file mode 100755 index 00000000..bc55c103 --- /dev/null +++ b/winboard-dm-beta4/frontend.h @@ -0,0 +1,173 @@ +/* + * frontend.h -- Interface exported by all XBoard front ends + * $Id$ + * + * Copyright 1991 by Digital Equipment Corporation, Maynard, Massachusetts. + * Enhancements Copyright 1992-95 Free Software Foundation, Inc. + * + * The following terms apply to Digital Equipment Corporation's copyright + * interest in XBoard: + * ------------------------------------------------------------------------ + * All Rights Reserved + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appear in all copies and that + * both that copyright notice and this permission notice appear in + * supporting documentation, and that the name of Digital not be + * used in advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. + * + * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING + * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL + * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR + * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, + * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + * ------------------------------------------------------------------------ + * + * The following terms apply to the enhanced version of XBoard distributed + * by the Free Software Foundation: + * ------------------------------------------------------------------------ + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * ------------------------------------------------------------------------ + */ + +#ifndef _FRONTEND +#define _FRONTEND + +#include + +typedef VOIDSTAR ProcRef; +#define NoProc ((ProcRef) 0) +typedef VOIDSTAR InputSourceRef; + +void ModeHighlight P((void)); +void SetICSMode P((void)); +void SetGNUMode P((void)); +void SetNCPMode P((void)); +void SetCmailMode P((void)); +void SetTrainingModeOn P((void)); +void SetTrainingModeOff P((void)); +void SetUserThinkingEnables P((void)); +void SetMachineThinkingEnables P((void)); +void DisplayTitle P((String title)); +void DisplayMessage P((String message, String extMessage)); +void DisplayError P((String message, int error)); +void DisplayMoveError P((String message)); + +/* If status == 0, we are exiting with a benign message, not an error */ +void DisplayFatalError P((String message, int error, int status)); + +void DisplayInformation P((String message)); +void AskQuestion P((String title, String question, String replyPrefix, + ProcRef pr)); +void DisplayIcsInteractionTitle P((String title)); +void DrawPosition P((int fullRedraw, Board board)); +void ResetFrontEnd P((void)); +void CommentPopUp P((String title, String comment)); +void CommentPopDown P((void)); +void EditCommentPopUp P((int index, String title, String text)); + +void RingBell P((void)); +void PlayIcsWinSound P((void)); +void PlayIcsLossSound P((void)); +void PlayIcsDrawSound P((void)); +void PlayIcsUnfinishedSound P((void)); +void PlayAlarmSound P((void)); +void EchoOn P((void)); +void EchoOff P((void)); +void Raw P((void)); +void Colorize P((ColorClass cc, int continuation)); + +char *UserName P((void)); +char *HostName P((void)); + +int ClockTimerRunning P((void)); +int StopClockTimer P((void)); +void StartClockTimer P((long millisec)); +void DisplayWhiteClock P((long timeRemaining, int highlight)); +void DisplayBlackClock P((long timeRemaining, int highlight)); + +int LoadGameTimerRunning P((void)); +int StopLoadGameTimer P((void)); +void StartLoadGameTimer P((long millisec)); +void AutoSaveGame P((void)); + +typedef void (*DelayedEventCallback) P((void)); +void ScheduleDelayedEvent P((DelayedEventCallback cb, long millisec)); +DelayedEventCallback GetDelayedEvent P((void)); +void CancelDelayedEvent P((void)); + +int StartChildProcess P((char *cmdLine, char *dir, ProcRef *pr)); +void DestroyChildProcess P((ProcRef pr, int/*boolean*/ signal)); +void InterruptChildProcess P((ProcRef pr)); + +int OpenTelnet P((char *host, char *port, ProcRef *pr)); +int OpenTCP P((char *host, char *port, ProcRef *pr)); +int OpenCommPort P((char *name, ProcRef *pr)); +int OpenLoopback P((ProcRef *pr)); +int OpenRcmd P((char *host, char *user, char *cmd, ProcRef *pr)); + +typedef void (*InputCallback) P((InputSourceRef isr, VOIDSTAR closure, + char *buf, int count, int error)); +/* pr == NoProc means the local keyboard */ +InputSourceRef AddInputSource P((ProcRef pr, int lineByLine, + InputCallback func, VOIDSTAR closure)); +void RemoveInputSource P((InputSourceRef isr)); + +/* pr == NoProc means the local display */ +int OutputToProcess P((ProcRef pr, char *message, int count, int *outError)); +int OutputToProcessDelayed P((ProcRef pr, char *message, int count, + int *outError, long msdelay)); + +void CmailSigHandlerCallBack P((InputSourceRef isr, VOIDSTAR closure, + char *buf, int count, int error)); + +extern ProcRef cmailPR; + +/* these are in wgamelist.c */ +void GameListPopUp P((FILE *fp, char *filename)); +void GameListPopDown P((void)); +void GameListHighlight P((int index)); +void GameListDestroy P((void)); + +/* these are in wedittags.c */ +void EditTagsPopUp P((char *tags)); +void TagsPopUp P((char *tags, char *msg)); +void TagsPopDown P((void)); + +void ICSInitScript P((void)); +void StartAnalysisClock P((void)); +void AnalysisPopUp P((char *pv, char *depth, char *nps, + char *nodes, char *score, char *move_nr, char *time, int state)); +void AnalysisPopDown P((void)); + +void SetHighlights P((int fromX, int fromY, int toX, int toY)); +void ClearHighlights P((void)); +void SetPremoveHighlights P((int fromX, int fromY, int toX, int toY)); +void ClearPremoveHighlights P((void)); + +void ShutDownFrontEnd P((void)); +void BoardToTop P((void)); +void AnimateMove P((Board board, int fromX, int fromY, int toX, int toY)); +void HistorySet P((char movelist[][2*MOVE_LEN], + int first, int last, int current)); +void FreezeUI P((void)); +void ThawUI P((void)); +extern char *programName; + +#endif diff --git a/winboard-dm-beta4/gamelist.c b/winboard-dm-beta4/gamelist.c new file mode 100755 index 00000000..0df36b6b --- /dev/null +++ b/winboard-dm-beta4/gamelist.c @@ -0,0 +1,305 @@ +/* + * gamelist.c -- Functions to manage a gamelist + * XBoard $Id$ + * + * Copyright 1995 Free Software Foundation, Inc. + * + * ------------------------------------------------------------------------ + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA. + * ------------------------------------------------------------------------ + */ + +#include "config.h" + +#include +#include +#if STDC_HEADERS +# include +# include +#else /* not STDC_HEADERS */ +# if HAVE_STRING_H +# include +# else /* not HAVE_STRING_H */ +# include +# endif /* not HAVE_STRING_H */ +#endif /* not STDC_HEADERS */ + +#include "common.h" +#include "frontend.h" +#include "backend.h" +#include "parser.h" + + +/* Variables + */ +List gameList; + + +/* Local function prototypes + */ +static void GameListDeleteGame P((ListGame *)); +static ListGame *GameListCreate P((void)); +static void GameListFree P((List *)); +static int GameListNewGame P((ListGame **)); + +/* Delete a ListGame; implies removint it from a list. + */ +static void GameListDeleteGame(listGame) + ListGame *listGame; +{ + if (listGame) { + if (listGame->gameInfo.event) free(listGame->gameInfo.event); + if (listGame->gameInfo.site) free(listGame->gameInfo.site); + if (listGame->gameInfo.date) free(listGame->gameInfo.date); + if (listGame->gameInfo.round) free(listGame->gameInfo.round); + if (listGame->gameInfo.white) free(listGame->gameInfo.white); + if (listGame->gameInfo.black) free(listGame->gameInfo.black); + if (listGame->gameInfo.fen) free(listGame->gameInfo.fen); + if (listGame->gameInfo.resultDetails) free(listGame->gameInfo.resultDetails); + if (listGame->gameInfo.timeControl) free(listGame->gameInfo.timeControl); + if (listGame->gameInfo.extraTags) free(listGame->gameInfo.extraTags); + ListNodeFree((ListNode *) listGame); + } +} + + +/* Free the previous list of games. + */ +static void GameListFree(gameList) + List *gameList; +{ + while (!ListEmpty(gameList)) + { + GameListDeleteGame((ListGame *) gameList->head); + } +} + + + +/* Initialize a new GameInfo structure. + */ +void GameListInitGameInfo(gameInfo) + GameInfo *gameInfo; +{ + gameInfo->event = NULL; + gameInfo->site = NULL; + gameInfo->date = NULL; + gameInfo->round = NULL; + gameInfo->white = NULL; + gameInfo->black = NULL; + gameInfo->result = GameUnfinished; + gameInfo->fen = NULL; + gameInfo->resultDetails = NULL; + gameInfo->timeControl = NULL; + gameInfo->extraTags = NULL; + gameInfo->whiteRating = -1; /* unknown */ + gameInfo->blackRating = -1; /* unknown */ + gameInfo->variant = VariantNormal; +} + + +/* Create empty ListGame; returns ListGame or NULL, if out of memory. + * + * Note, that the ListGame is *not* added to any list + */ +static ListGame *GameListCreate() + +{ + ListGame *listGame; + + if ((listGame = (ListGame *) ListNodeCreate(sizeof(*listGame)))) { + GameListInitGameInfo(&listGame->gameInfo); + } + return(listGame); +} + + +/* Creates a new game for the gamelist. + */ +static int GameListNewGame(listGamePtr) + ListGame **listGamePtr; +{ + if (!(*listGamePtr = (ListGame *) GameListCreate())) { + GameListFree(&gameList); + return(ENOMEM); + } + ListAddTail(&gameList, (ListNode *) *listGamePtr); + return(0); +} + + +/* Build the list of games in the open file f. + * Returns 0 for success or error number. + */ +int GameListBuild(f) + FILE *f; +{ + ChessMove cm, lastStart; + int gameNumber; + ListGame *currentListGame = NULL; + int error; + int offset; + + GameListFree(&gameList); + yynewfile(f); + gameNumber = 0; + + lastStart = (ChessMove) 0; + yyskipmoves = TRUE; + do { + yyboardindex = 1; + offset = yyoffset(); + cm = (ChessMove) yylex(); + switch (cm) { + case GNUChessGame: + if ((error = GameListNewGame(¤tListGame))) { + rewind(f); + yyskipmoves = FALSE; + return(error); + } + currentListGame->number = ++gameNumber; + currentListGame->offset = offset; + if (currentListGame->gameInfo.event != NULL) { + free(currentListGame->gameInfo.event); + } + currentListGame->gameInfo.event = StrSave(yy_text); + lastStart = cm; + break; + case XBoardGame: + lastStart = cm; + break; + case MoveNumberOne: + switch (lastStart) { + case GNUChessGame: + break; /* ignore */ + case PGNTag: + lastStart = cm; + break; /* Already started */ + case (ChessMove) 0: + case MoveNumberOne: + case XBoardGame: + if ((error = GameListNewGame(¤tListGame))) { + rewind(f); + yyskipmoves = FALSE; + return(error); + } + currentListGame->number = ++gameNumber; + currentListGame->offset = offset; + lastStart = cm; + break; + default: + break; /* impossible */ + } + break; + case PGNTag: + lastStart = cm; + if ((error = GameListNewGame(¤tListGame))) { + rewind(f); + yyskipmoves = FALSE; + return(error); + } + currentListGame->number = ++gameNumber; + currentListGame->offset = offset; + ParsePGNTag(yy_text, ¤tListGame->gameInfo); + do { + yyboardindex = 1; + offset = yyoffset(); + cm = (ChessMove) yylex(); + if (cm == PGNTag) { + ParsePGNTag(yy_text, ¤tListGame->gameInfo); + } + } while (cm == PGNTag || cm == Comment); + break; + default: + break; + } + } + while (cm != (ChessMove) 0); + + + if (appData.debugMode) { + for (currentListGame = (ListGame *) gameList.head; + currentListGame->node.succ; + currentListGame = (ListGame *) currentListGame->node.succ) { + + fprintf(debugFP, "Parsed game number %d, offset %ld:\n", + currentListGame->number, currentListGame->offset); + PrintPGNTags(debugFP, ¤tListGame->gameInfo); + } + } + + rewind(f); + yyskipmoves = FALSE; + return 0; +} + + +/* Clear an existing GameInfo structure. + */ +void ClearGameInfo(gameInfo) + GameInfo *gameInfo; +{ + if (gameInfo->event != NULL) { + free(gameInfo->event); + } + if (gameInfo->site != NULL) { + free(gameInfo->site); + } + if (gameInfo->date != NULL) { + free(gameInfo->date); + } + if (gameInfo->round != NULL) { + free(gameInfo->round); + } + if (gameInfo->white != NULL) { + free(gameInfo->white); + } + if (gameInfo->black != NULL) { + free(gameInfo->black); + } + if (gameInfo->resultDetails != NULL) { + free(gameInfo->resultDetails); + } + if (gameInfo->fen != NULL) { + free(gameInfo->fen); + } + if (gameInfo->timeControl != NULL) { + free(gameInfo->timeControl); + } + if (gameInfo->extraTags != NULL) { + free(gameInfo->extraTags); + } + + GameListInitGameInfo(gameInfo); +} + +char * +GameListLine(number, gameInfo) + int number; + GameInfo *gameInfo; +{ + char *event = (gameInfo->event && strcmp(gameInfo->event, "?") != 0) ? + gameInfo->event : gameInfo->site ? gameInfo->site : "?"; + char *white = gameInfo->white ? gameInfo->white : "?"; + char *black = gameInfo->black ? gameInfo->black : "?"; + char *date = gameInfo->date ? gameInfo->date : "?"; + int len = 10 + strlen(event) + 2 + strlen(white) + 1 + + strlen(black) + 11 + strlen(date) + 1; + char *ret = (char *) malloc(len); + sprintf(ret, "%d. %s, %s-%s, %s, %s", + number, event, white, black, PGNResult(gameInfo->result), date); + return ret; +} + diff --git a/winboard-dm-beta4/lists.c b/winboard-dm-beta4/lists.c new file mode 100755 index 00000000..9f6d4b5e --- /dev/null +++ b/winboard-dm-beta4/lists.c @@ -0,0 +1,149 @@ +/* + * lists.c -- Functions to implement a double linked list + * XBoard $Id$ + * + * Copyright 1995 Free Software Foundation, Inc. + * + * ------------------------------------------------------------------------ + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA. + * ------------------------------------------------------------------------ + * + * This file could well be a part of backend.c, but I prefer it this + * way. + */ + +#include "config.h" + +#include +#if STDC_HEADERS +# include +#endif /* not STDC_HEADERS */ + +#include "common.h" +#include "lists.h" + + + +/* Check, if List l is empty; returns TRUE, if it is, FALSE + * otherwise. + */ +int ListEmpty(l) + List *l; +{ + return(l->head == (ListNode *) &l->tail); +} + + +/* Initialize a list. Must be executed before list is used. + */ +void ListNew(l) + List *l; +{ + l->head = (ListNode *) &l->tail; + l->tail = NULL; + l->tailPred = (ListNode *) l; +} + + +/* Remove node n from the list it is inside. + */ +void ListRemove(n) + ListNode *n; +{ + if (n->succ != NULL) { /* Be safe */ + n->pred->succ = n->succ; + n->succ->pred = n->pred; + n->succ = NULL; /* Mark node as no longer being member */ + n->pred = NULL; /* of a list. */ + } +} + + +/* Delete node n. + */ +void ListNodeFree(n) + ListNode *n; +{ + if (n) { + ListRemove(n); + free(n); + } +} + + +/* Create a list node with size s. Returns NULL, if out of memory. + */ +ListNode *ListNodeCreate(s) + size_t s; +{ + ListNode *n; + + if ((n = (ListNode*) malloc(s))) { + n->succ = NULL; /* Mark node as not being member of a list. */ + n->pred = NULL; + } + return(n); +} + + +/* Insert node n into the list of node m after m. + */ +void ListInsert(m, n) + ListNode *m, *n; +{ + n->succ = m->succ; + n->pred = m; + m->succ = n; + n->succ->pred = n; +} + + +/* Add node n to the head of list l. + */ +void ListAddHead(l, n) + List *l; + ListNode *n; +{ + ListInsert((ListNode *) &l->head, n); +} + + +/* Add node n to the tail of list l. + */ +void ListAddTail(l, n) + List *l; + ListNode *n; +{ + ListInsert((ListNode *) l->tailPred, n); +} + + +/* Return element with number n of list l. (NULL, if n doesn't exist.) + * Counting starts with 0. + */ +ListNode *ListElem(l, n) + List *l; + int n; +{ + ListNode *ln; + + for (ln = l->head; ln->succ; ln = ln->succ) { + if (!n--) { + return (ln); + } + } + + return(NULL); +} diff --git a/winboard-dm-beta4/lists.h b/winboard-dm-beta4/lists.h new file mode 100755 index 00000000..780f6c22 --- /dev/null +++ b/winboard-dm-beta4/lists.h @@ -0,0 +1,66 @@ +/* + * lists.c -- Includefile of lists.c + * XBoard $Id$ + * + * Copyright 1995 Free Software Foundation, Inc. + * + * ------------------------------------------------------------------------ + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA. + * ------------------------------------------------------------------------ + * + * This file could well be a part of backend.c, but I prefer it this + * way. + */ + +#ifndef _LISTS_H +#define _LISTS_H + + +/* Type definition: Node of a double linked list. + */ +typedef struct _ListNode { + struct _ListNode *succ; + struct _ListNode *pred; +} ListNode; + + +/* Type definition: Double linked list. + * + * The list structure consists of two ListNode's: The pred entry of + * the head being the succ entry of the tail. Thus a list is empty + * if and only if it consists of 2 nodes. :-) + */ +typedef struct { + struct _ListNode *head; /* The list structure consists of two */ + struct _ListNode *tail; /* ListNode's: The pred entry of the */ + struct _ListNode *tailPred; /* head being the succ entry of the */ +} List; /* tail. */ + + + +/* Function prototypes + */ +extern int ListEmpty P((List *)); +void ListNew P((List *)); +void ListRemove P((ListNode *)); +void ListNodeFree P((ListNode *)); +ListNode *ListNodeCreate P((size_t)); +void ListInsert P((ListNode *, ListNode *)); +void ListAddHead P((List *, ListNode *)); +void ListAddTail P((List *, ListNode *)); +ListNode *ListElem P((List *, int)); + + +#endif diff --git a/winboard-dm-beta4/moves.c b/winboard-dm-beta4/moves.c new file mode 100755 index 00000000..bed20640 --- /dev/null +++ b/winboard-dm-beta4/moves.c @@ -0,0 +1,978 @@ +/* + * moves.c - Move generation and checking + * $Id$ + * + * Copyright 1991 by Digital Equipment Corporation, Maynard, Massachusetts. + * Enhancements Copyright 1992-95 Free Software Foundation, Inc. + * + * The following terms apply to Digital Equipment Corporation's copyright + * interest in XBoard: + * ------------------------------------------------------------------------ + * All Rights Reserved + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appear in all copies and that + * both that copyright notice and this permission notice appear in + * supporting documentation, and that the name of Digital not be + * used in advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. + * + * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING + * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL + * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR + * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, + * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + * ------------------------------------------------------------------------ + * + * The following terms apply to the enhanced version of XBoard distributed + * by the Free Software Foundation: + * ------------------------------------------------------------------------ + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * ------------------------------------------------------------------------ + */ + +#include "config.h" + +#include +#if HAVE_STRING_H +# include +#else /* not HAVE_STRING_H */ +# include +#endif /* not HAVE_STRING_H */ +#include "common.h" +#include "backend.h" +#include "moves.h" +#include "parser.h" + +int WhitePiece P((ChessSquare)); +int BlackPiece P((ChessSquare)); +int SameColor P((ChessSquare, ChessSquare)); + + +int WhitePiece(piece) + ChessSquare piece; +{ + return (int) piece >= (int) WhitePawn && (int) piece <= (int) WhiteKing; +} + +int BlackPiece(piece) + ChessSquare piece; +{ + return (int) piece >= (int) BlackPawn && (int) piece <= (int) BlackKing; +} + +int SameColor(piece1, piece2) + ChessSquare piece1, piece2; +{ + return ((int) piece1 >= (int) WhitePawn && + (int) piece1 <= (int) WhiteKing && + (int) piece2 >= (int) WhitePawn && + (int) piece2 <= (int) WhiteKing) + || ((int) piece1 >= (int) BlackPawn && + (int) piece1 <= (int) BlackKing && + (int) piece2 >= (int) BlackPawn && + (int) piece2 <= (int) BlackKing); +} + +ChessSquare PromoPiece(moveType) + ChessMove moveType; +{ + switch (moveType) { + default: + return EmptySquare; + case WhitePromotionQueen: + return WhiteQueen; + case BlackPromotionQueen: + return BlackQueen; + case WhitePromotionRook: + return WhiteRook; + case BlackPromotionRook: + return BlackRook; + case WhitePromotionBishop: + return WhiteBishop; + case BlackPromotionBishop: + return BlackBishop; + case WhitePromotionKnight: + return WhiteKnight; + case BlackPromotionKnight: + return BlackKnight; + case WhitePromotionKing: + return WhiteKing; + case BlackPromotionKing: + return BlackKing; + } +} + +ChessMove PromoCharToMoveType(whiteOnMove, promoChar) + int whiteOnMove; + int promoChar; +{ + if (whiteOnMove) { + switch (promoChar) { + case 'n': + case 'N': + return WhitePromotionKnight; + case 'b': + case 'B': + return WhitePromotionBishop; + case 'r': + case 'R': + return WhitePromotionRook; + case 'q': + case 'Q': + return WhitePromotionQueen; + case 'k': + case 'K': + return WhitePromotionKing; + case NULLCHAR: + default: + return NormalMove; + } + } else { + switch (promoChar) { + case 'n': + case 'N': + return BlackPromotionKnight; + case 'b': + case 'B': + return BlackPromotionBishop; + case 'r': + case 'R': + return BlackPromotionRook; + case 'q': + case 'Q': + return BlackPromotionQueen; + case 'k': + case 'K': + return BlackPromotionKing; + case NULLCHAR: + default: + return NormalMove; + } + } +} + +char pieceToChar[] = { + 'P', 'N', 'B', 'R', 'Q', 'K', + 'p', 'n', 'b', 'r', 'q', 'k', 'x' + }; + +char PieceToChar(p) + ChessSquare p; +{ + return pieceToChar[(int) p]; +} + +ChessSquare CharToPiece(c) + int c; +{ + switch (c) { + default: + case 'x': return EmptySquare; + case 'P': return WhitePawn; + case 'R': return WhiteRook; + case 'N': return WhiteKnight; + case 'B': return WhiteBishop; + case 'Q': return WhiteQueen; + case 'K': return WhiteKing; + case 'p': return BlackPawn; + case 'r': return BlackRook; + case 'n': return BlackKnight; + case 'b': return BlackBishop; + case 'q': return BlackQueen; + case 'k': return BlackKing; + } +} + +void CopyBoard(to, from) + Board to, from; +{ + int i, j; + + for (i = 0; i < BOARD_SIZE; i++) + for (j = 0; j < BOARD_SIZE; j++) + to[i][j] = from[i][j]; +} + +int CompareBoards(board1, board2) + Board board1, board2; +{ + int i, j; + + for (i = 0; i < BOARD_SIZE; i++) + for (j = 0; j < BOARD_SIZE; j++) { + if (board1[i][j] != board2[i][j]) + return FALSE; + } + return TRUE; +} + + +/* Call callback once for each pseudo-legal move in the given + position, except castling moves. A move is pseudo-legal if it is + legal, or if it would be legal except that it leaves the king in + check. In the arguments, epfile is EP_NONE if the previous move + was not a double pawn push, or the file 0..7 if it was, or + EP_UNKNOWN if we don't know and want to allow all e.p. captures. + Promotion moves generated are to Queen only. +*/ +void GenPseudoLegal(board, flags, epfile, callback, closure) + Board board; + int flags; + int epfile; + MoveCallback callback; + VOIDSTAR closure; +{ + int rf, ff; + int i, j, d, s, fs, rs, rt, ft; + + for (rf = 0; rf <= 7; rf++) + for (ff = 0; ff <= 7; ff++) { + if (flags & F_WHITE_ON_MOVE) { + if (!WhitePiece(board[rf][ff])) continue; + } else { + if (!BlackPiece(board[rf][ff])) continue; + } + switch (board[rf][ff]) { + case EmptySquare: + default: + /* can't happen */ + break; + + case WhitePawn: + if (rf < 7 && board[rf + 1][ff] == EmptySquare) { + callback(board, flags, + rf == 6 ? WhitePromotionQueen : NormalMove, + rf, ff, rf + 1, ff, closure); + } + if (rf == 1 && board[2][ff] == EmptySquare && + board[3][ff] == EmptySquare) { + callback(board, flags, NormalMove, + rf, ff, 3, ff, closure); + } + for (s = -1; s <= 1; s += 2) { + if (rf < 7 && ff + s >= 0 && ff + s <= 7 && + ((flags & F_KRIEGSPIEL_CAPTURE) || + BlackPiece(board[rf + 1][ff + s]))) { + callback(board, flags, + rf == 6 ? WhitePromotionQueen : NormalMove, + rf, ff, rf + 1, ff + s, closure); + } + if (rf == 4) { + if (ff + s >= 0 && ff + s <= 7 && + (epfile == ff + s || epfile == EP_UNKNOWN) && + board[4][ff + s] == BlackPawn && + board[5][ff + s] == EmptySquare) { + callback(board, flags, WhiteCapturesEnPassant, + rf, ff, 5, ff + s, closure); + } + } + } + break; + + case BlackPawn: + if (rf > 0 && board[rf - 1][ff] == EmptySquare) { + callback(board, flags, + rf == 1 ? BlackPromotionQueen : NormalMove, + rf, ff, rf - 1, ff, closure); + } + if (rf == 6 && board[5][ff] == EmptySquare && + board[4][ff] == EmptySquare) { + callback(board, flags, NormalMove, + rf, ff, 4, ff, closure); + } + for (s = -1; s <= 1; s += 2) { + if (rf > 0 && ff + s >= 0 && ff + s <= 7 && + ((flags & F_KRIEGSPIEL_CAPTURE) || + WhitePiece(board[rf - 1][ff + s]))) { + callback(board, flags, + rf == 1 ? BlackPromotionQueen : NormalMove, + rf, ff, rf - 1, ff + s, closure); + } + if (rf == 3) { + if (ff + s >= 0 && ff + s <= 7 && + (epfile == ff + s || epfile == EP_UNKNOWN) && + board[3][ff + s] == WhitePawn && + board[2][ff + s] == EmptySquare) { + callback(board, flags, BlackCapturesEnPassant, + rf, ff, 2, ff + s, closure); + } + } + } + break; + + case WhiteKnight: + case BlackKnight: + for (i = -1; i <= 1; i += 2) + for (j = -1; j <= 1; j += 2) + for (s = 1; s <= 2; s++) { + rt = rf + i*s; + ft = ff + j*(3-s); + if (rt < 0 || rt > 7 || ft < 0 || ft > 7) continue; + if (SameColor(board[rf][ff], board[rt][ft])) continue; + callback(board, flags, NormalMove, + rf, ff, rt, ft, closure); + } + break; + + case WhiteBishop: + case BlackBishop: + for (rs = -1; rs <= 1; rs += 2) + for (fs = -1; fs <= 1; fs += 2) + for (i = 1;; i++) { + rt = rf + (i * rs); + ft = ff + (i * fs); + if (rt < 0 || rt > 7 || ft < 0 || ft > 7) break; + if (SameColor(board[rf][ff], board[rt][ft])) break; + callback(board, flags, NormalMove, + rf, ff, rt, ft, closure); + if (board[rt][ft] != EmptySquare) break; + } + break; + + case WhiteRook: + case BlackRook: + for (d = 0; d <= 1; d++) + for (s = -1; s <= 1; s += 2) + for (i = 1;; i++) { + rt = rf + (i * s) * d; + ft = ff + (i * s) * (1 - d); + if (rt < 0 || rt > 7 || ft < 0 || ft > 7) break; + if (SameColor(board[rf][ff], board[rt][ft])) break; + callback(board, flags, NormalMove, + rf, ff, rt, ft, closure); + if (board[rt][ft] != EmptySquare) break; + } + break; + + case WhiteQueen: + case BlackQueen: + for (rs = -1; rs <= 1; rs++) + for (fs = -1; fs <= 1; fs++) { + if (rs == 0 && fs == 0) continue; + for (i = 1;; i++) { + rt = rf + (i * rs); + ft = ff + (i * fs); + if (rt < 0 || rt > 7 || ft < 0 || ft > 7) break; + if (SameColor(board[rf][ff], board[rt][ft])) break; + callback(board, flags, NormalMove, + rf, ff, rt, ft, closure); + if (board[rt][ft] != EmptySquare) break; + } + } + break; + + case WhiteKing: + case BlackKing: + for (i = -1; i <= 1; i++) + for (j = -1; j <= 1; j++) { + if (i == 0 && j == 0) continue; + rt = rf + i; + ft = ff + j; + if (rt < 0 || rt > 7 || ft < 0 || ft > 7) continue; + if (SameColor(board[rf][ff], board[rt][ft])) continue; + callback(board, flags, NormalMove, + rf, ff, rt, ft, closure); + } + break; + } + } +} + + +typedef struct { + MoveCallback cb; + VOIDSTAR cl; +} GenLegalClosure; + +extern void GenLegalCallback P((Board board, int flags, ChessMove kind, + int rf, int ff, int rt, int ft, + VOIDSTAR closure)); + +void GenLegalCallback(board, flags, kind, rf, ff, rt, ft, closure) + Board board; + int flags; + ChessMove kind; + int rf, ff, rt, ft; + VOIDSTAR closure; +{ + register GenLegalClosure *cl = (GenLegalClosure *) closure; + + if (!(flags & F_IGNORE_CHECK) && + CheckTest(board, flags, rf, ff, rt, ft, + kind == WhiteCapturesEnPassant || + kind == BlackCapturesEnPassant)) return; + if (flags & F_ATOMIC_CAPTURE) { + if (board[rt][ft] != EmptySquare || + kind == WhiteCapturesEnPassant || kind == BlackCapturesEnPassant) { + int r, f; + ChessSquare king = (flags & F_WHITE_ON_MOVE) ? WhiteKing : BlackKing; + if (board[rf][ff] == king) return; + for (r = rt-1; r <= rt+1; r++) { + for (f = ft-1; f <= ft+1; f++) { + if (r >= 0 && r <= 7 && f >= 0 && f <= 7 && + board[r][f] == king) return; + } + } + } + } + cl->cb(board, flags, kind, rf, ff, rt, ft, cl->cl); +} + + +/* Like GenPseudoLegal, but (1) include castling moves, (2) unless + F_IGNORE_CHECK is set in the flags, omit moves that would leave the + king in check, and (3) if F_ATOMIC_CAPTURE is set in the flags, omit + moves that would destroy your own king. The CASTLE_OK flags are + true if castling is not yet ruled out by a move of the king or + rook. Return TRUE if the player on move is currently in check and + F_IGNORE_CHECK is not set. */ +int GenLegal(board, flags, epfile, callback, closure) + Board board; + int flags; + int epfile; + MoveCallback callback; + VOIDSTAR closure; +{ + GenLegalClosure cl; + int ff; + int ignoreCheck = (flags & F_IGNORE_CHECK) != 0; + + cl.cb = callback; + cl.cl = closure; + GenPseudoLegal(board, flags, epfile, GenLegalCallback, (VOIDSTAR) &cl); + + if (!ignoreCheck && + CheckTest(board, flags, -1, -1, -1, -1, FALSE)) return TRUE; + + /* Generate castling moves */ + for (ff = 4; ff >= 3; ff-- /*ics wild 1*/) { + if ((flags & F_WHITE_ON_MOVE) && + (flags & F_WHITE_KCASTLE_OK) && + board[0][ff] == WhiteKing && + board[0][ff + 1] == EmptySquare && + board[0][ff + 2] == EmptySquare && + board[0][6] == EmptySquare && + board[0][7] == WhiteRook && + (ignoreCheck || + (!CheckTest(board, flags, 0, ff, 0, ff + 1, FALSE) && + !CheckTest(board, flags, 0, ff, 0, ff + 2, FALSE)))) { + + callback(board, flags, + ff==4 ? WhiteKingSideCastle : WhiteKingSideCastleWild, + 0, ff, 0, ff + 2, closure); + } + if ((flags & F_WHITE_ON_MOVE) && + (flags & F_WHITE_QCASTLE_OK) && + board[0][ff] == WhiteKing && + board[0][ff - 1] == EmptySquare && + board[0][ff - 2] == EmptySquare && + board[0][1] == EmptySquare && + board[0][0] == WhiteRook && + (ignoreCheck || + (!CheckTest(board, flags, 0, ff, 0, ff - 1, FALSE) && + !CheckTest(board, flags, 0, ff, 0, ff - 2, FALSE)))) { + + callback(board, flags, + ff==4 ? WhiteQueenSideCastle : WhiteQueenSideCastleWild, + 0, ff, 0, ff - 2, closure); + } + if (!(flags & F_WHITE_ON_MOVE) && + (flags & F_BLACK_KCASTLE_OK) && + board[7][ff] == BlackKing && + board[7][ff + 1] == EmptySquare && + board[7][ff + 2] == EmptySquare && + board[7][6] == EmptySquare && + board[7][7] == BlackRook && + (ignoreCheck || + (!CheckTest(board, flags, 7, ff, 7, ff + 1, FALSE) && + !CheckTest(board, flags, 7, ff, 7, ff + 2, FALSE)))) { + + callback(board, flags, + ff==4 ? BlackKingSideCastle : BlackKingSideCastleWild, + 7, ff, 7, ff + 2, closure); + } + if (!(flags & F_WHITE_ON_MOVE) && + (flags & F_BLACK_QCASTLE_OK) && + board[7][ff] == BlackKing && + board[7][ff - 1] == EmptySquare && + board[7][ff - 2] == EmptySquare && + board[7][1] == EmptySquare && + board[7][0] == BlackRook && + (ignoreCheck || + (!CheckTest(board, flags, 7, ff, 7, ff - 1, FALSE) && + !CheckTest(board, flags, 7, ff, 7, ff - 1, FALSE)))) { + + callback(board, flags, + ff==4 ? BlackQueenSideCastle : BlackQueenSideCastleWild, + 7, ff, 7, ff - 2, closure); + } + } + + return FALSE; +} + + +typedef struct { + int rking, fking; + int check; +} CheckTestClosure; + + +extern void CheckTestCallback P((Board board, int flags, ChessMove kind, + int rf, int ff, int rt, int ft, + VOIDSTAR closure)); + + +void CheckTestCallback(board, flags, kind, rf, ff, rt, ft, closure) + Board board; + int flags; + ChessMove kind; + int rf, ff, rt, ft; + VOIDSTAR closure; +{ + register CheckTestClosure *cl = (CheckTestClosure *) closure; + + if (rt == cl->rking && ft == cl->fking) cl->check++; +} + + +/* If the player on move were to move from (rf, ff) to (rt, ft), would + he leave himself in check? Or if rf == -1, is the player on move + in check now? enPassant must be TRUE if the indicated move is an + e.p. capture. The possibility of castling out of a check along the + back rank is not accounted for (i.e., we still return nonzero), as + this is illegal anyway. Return value is the number of times the + king is in check. */ +int CheckTest(board, flags, rf, ff, rt, ft, enPassant) + Board board; + int flags; + int rf, ff, rt, ft, enPassant; +{ + CheckTestClosure cl; + ChessSquare king = flags & F_WHITE_ON_MOVE ? WhiteKing : BlackKing; + ChessSquare captured = EmptySquare; + /* Suppress warnings on uninitialized variables */ + + if (rf >= 0) { + if (enPassant) { + captured = board[rf][ft]; + board[rf][ft] = EmptySquare; + } else { + captured = board[rt][ft]; + } + board[rt][ft] = board[rf][ff]; + board[rf][ff] = EmptySquare; + } + + /* For compatibility with ICS wild 9, we scan the board in the + order a1, a2, a3, ... b1, b2, ..., h8 to find the first king, + and we test only whether that one is in check. */ + cl.check = 0; + for (cl.fking = 0; cl.fking <= 7; cl.fking++) + for (cl.rking = 0; cl.rking <= 7; cl.rking++) { + if (board[cl.rking][cl.fking] == king) { + GenPseudoLegal(board, flags ^ F_WHITE_ON_MOVE, -1, + CheckTestCallback, (VOIDSTAR) &cl); + goto undo_move; /* 2-level break */ + } + } + + undo_move: + + if (rf >= 0) { + board[rf][ff] = board[rt][ft]; + if (enPassant) { + board[rf][ft] = captured; + board[rt][ft] = EmptySquare; + } else { + board[rt][ft] = captured; + } + } + + return cl.check; +} + + +typedef struct { + int rf, ff, rt, ft; + ChessMove kind; +} LegalityTestClosure; + +extern void LegalityTestCallback P((Board board, int flags, ChessMove kind, + int rf, int ff, int rt, int ft, + VOIDSTAR closure)); + +void LegalityTestCallback(board, flags, kind, rf, ff, rt, ft, closure) + Board board; + int flags; + ChessMove kind; + int rf, ff, rt, ft; + VOIDSTAR closure; +{ + register LegalityTestClosure *cl = (LegalityTestClosure *) closure; + + if (rf == cl->rf && ff == cl->ff && rt == cl->rt && ft == cl->ft) + cl->kind = kind; +} + +ChessMove LegalityTest(board, flags, epfile, rf, ff, rt, ft, promoChar) + Board board; + int flags, epfile; + int rf, ff, rt, ft, promoChar; +{ + LegalityTestClosure cl; + + cl.rf = rf; + cl.ff = ff; + cl.rt = rt; + cl.ft = ft; + cl.kind = IllegalMove; + GenLegal(board, flags, epfile, LegalityTestCallback, (VOIDSTAR) &cl); + if (promoChar != NULLCHAR && promoChar != 'x') { + if (cl.kind == WhitePromotionQueen || cl.kind == BlackPromotionQueen) { + cl.kind = + PromoCharToMoveType((flags & F_WHITE_ON_MOVE) != 0, promoChar); + } else { + cl.kind = IllegalMove; + } + } + return cl.kind; +} + +typedef struct { + int count; +} MateTestClosure; + +extern void MateTestCallback P((Board board, int flags, ChessMove kind, + int rf, int ff, int rt, int ft, + VOIDSTAR closure)); + +void MateTestCallback(board, flags, kind, rf, ff, rt, ft, closure) + Board board; + int flags; + ChessMove kind; + int rf, ff, rt, ft; + VOIDSTAR closure; +{ + register MateTestClosure *cl = (MateTestClosure *) closure; + + cl->count++; +} + +/* Return MT_NONE, MT_CHECK, MT_CHECKMATE, or MT_STALEMATE */ +int MateTest(board, flags, epfile) + Board board; + int flags, epfile; +{ + MateTestClosure cl; + int inCheck; + + cl.count = 0; + inCheck = GenLegal(board, flags, epfile, MateTestCallback, (VOIDSTAR) &cl); + if (cl.count > 0) { + return inCheck ? MT_CHECK : MT_NONE; + } else { + return inCheck ? MT_CHECKMATE : MT_STALEMATE; + } +} + + +extern void DisambiguateCallback P((Board board, int flags, ChessMove kind, + int rf, int ff, int rt, int ft, + VOIDSTAR closure)); + +void DisambiguateCallback(board, flags, kind, rf, ff, rt, ft, closure) + Board board; + int flags; + ChessMove kind; + int rf, ff, rt, ft; + VOIDSTAR closure; +{ + register DisambiguateClosure *cl = (DisambiguateClosure *) closure; + + if ((cl->pieceIn == EmptySquare || cl->pieceIn == board[rf][ff]) && + (cl->rfIn == -1 || cl->rfIn == rf) && + (cl->ffIn == -1 || cl->ffIn == ff) && + (cl->rtIn == -1 || cl->rtIn == rt) && + (cl->ftIn == -1 || cl->ftIn == ft)) { + + cl->count++; + cl->piece = board[rf][ff]; + cl->rf = rf; + cl->ff = ff; + cl->rt = rt; + cl->ft = ft; + cl->kind = kind; + } +} + +void Disambiguate(board, flags, epfile, closure) + Board board; + int flags, epfile; + DisambiguateClosure *closure; +{ + int illegal = 0; + closure->count = 0; + closure->rf = closure->ff = closure->rt = closure->ft = 0; + closure->kind = ImpossibleMove; + GenLegal(board, flags, epfile, DisambiguateCallback, (VOIDSTAR) closure); + if (closure->count == 0) { + /* See if it's an illegal move due to check */ + illegal = 1; + GenLegal(board, flags|F_IGNORE_CHECK, epfile, DisambiguateCallback, + (VOIDSTAR) closure); + if (closure->count == 0) { + /* No, it's not even that */ + return; + } + } + if (closure->promoCharIn != NULLCHAR && closure->promoCharIn != 'x') { + if (closure->kind == WhitePromotionQueen + || closure->kind == BlackPromotionQueen) { + closure->kind = + PromoCharToMoveType((flags & F_WHITE_ON_MOVE) != 0, + closure->promoCharIn); + } else { + closure->kind = IllegalMove; + } + } + closure->promoChar = ToLower(PieceToChar(PromoPiece(closure->kind))); + if (closure->promoChar == 'x') closure->promoChar = NULLCHAR; + if (closure->count > 1) { + closure->kind = AmbiguousMove; + } + if (illegal) { + /* Note: If more than one illegal move matches, but no legal + moves, we return IllegalMove, not AmbiguousMove. Caller + can look at closure->count to detect this. + */ + closure->kind = IllegalMove; + } +} + + +typedef struct { + /* Input */ + ChessSquare piece; + int rf, ff, rt, ft; + /* Output */ + ChessMove kind; + int rank; + int file; + int either; +} CoordsToAlgebraicClosure; + +extern void CoordsToAlgebraicCallback P((Board board, int flags, + ChessMove kind, int rf, int ff, + int rt, int ft, VOIDSTAR closure)); + +void CoordsToAlgebraicCallback(board, flags, kind, rf, ff, rt, ft, closure) + Board board; + int flags; + ChessMove kind; + int rf, ff, rt, ft; + VOIDSTAR closure; +{ + register CoordsToAlgebraicClosure *cl = + (CoordsToAlgebraicClosure *) closure; + + if (rt == cl->rt && ft == cl->ft && + board[rf][ff] == cl->piece) { + if (rf == cl->rf) { + if (ff == cl->ff) { + cl->kind = kind; /* this is the move we want */ + } else { + cl->file++; /* need file to rule out this move */ + } + } else { + if (ff == cl->ff) { + cl->rank++; /* need rank to rule out this move */ + } else { + cl->either++; /* rank or file will rule out this move */ + } + } + } +} + +/* Convert coordinates to normal algebraic notation. + promoChar must be NULLCHAR or 'x' if not a promotion. +*/ +ChessMove CoordsToAlgebraic(board, flags, epfile, + rf, ff, rt, ft, promoChar, out) + Board board; + int flags, epfile; + int rf, ff, rt, ft; + int promoChar; + char out[MOVE_LEN]; +{ + ChessSquare piece; + ChessMove kind; + char *outp = out; + CoordsToAlgebraicClosure cl; + + if (rf == DROP_RANK) { + /* Bughouse piece drop */ + *outp++ = ToUpper(PieceToChar((ChessSquare) ff)); + *outp++ = '@'; + *outp++ = ft + 'a'; + *outp++ = rt + '1'; + *outp = NULLCHAR; + return (flags & F_WHITE_ON_MOVE) ? WhiteDrop : BlackDrop; + } + + if (promoChar == 'x') promoChar = NULLCHAR; + piece = board[rf][ff]; + switch (piece) { + case WhitePawn: + case BlackPawn: + kind = LegalityTest(board, flags, epfile, rf, ff, rt, ft, promoChar); + if (kind == IllegalMove && !(flags&F_IGNORE_CHECK)) { + /* Keep short notation if move is illegal only because it + leaves the player in check, but still return IllegalMove */ + kind = LegalityTest(board, flags|F_IGNORE_CHECK, epfile, + rf, ff, rt, ft, promoChar); + if (kind == IllegalMove) break; + kind = IllegalMove; + } + /* Pawn move */ + *outp++ = ff + 'a'; + if (ff == ft) { + /* Non-capture; use style "e5" */ + *outp++ = rt + '1'; + } else { + /* Capture; use style "exd5" */ + *outp++ = 'x'; + *outp++ = ft + 'a'; + *outp++ = rt + '1'; + } + /* Use promotion suffix style "=Q" */ + if (promoChar != NULLCHAR && promoChar != 'x') { + *outp++ = '='; + *outp++ = ToUpper(promoChar); + } + *outp = NULLCHAR; + return kind; + + + case WhiteKing: + case BlackKing: + /* Test for castling or ICS wild castling */ + /* Use style "O-O" (oh-oh) for PGN compatibility */ + if (rf == rt && + rf == ((piece == WhiteKing) ? 0 : 7) && + ((ff == 4 && (ft == 2 || ft == 6)) || + (ff == 3 && (ft == 1 || ft == 5)))) { + switch (ft) { + case 1: + case 6: + strcpy(out, "O-O"); + break; + case 2: + case 5: + strcpy(out, "O-O-O"); + break; + } + /* This notation is always unambiguous, unless there are + kings on both the d and e files, with "wild castling" + possible for the king on the d file and normal castling + possible for the other. ICS rules for wild 9 + effectively make castling illegal for either king in + this situation. So I am not going to worry about it; + I'll just generate an ambiguous O-O in this case. + */ + return LegalityTest(board, flags, epfile, + rf, ff, rt, ft, promoChar); + } + /* else fall through */ + + default: + /* Piece move */ + cl.rf = rf; + cl.ff = ff; + cl.rt = rt; + cl.ft = ft; + cl.piece = piece; + cl.kind = IllegalMove; + cl.rank = cl.file = cl.either = 0; + GenLegal(board, flags, epfile, + CoordsToAlgebraicCallback, (VOIDSTAR) &cl); + + if (cl.kind == IllegalMove && !(flags&F_IGNORE_CHECK)) { + /* Generate pretty moves for moving into check, but + still return IllegalMove. + */ + GenLegal(board, flags|F_IGNORE_CHECK, epfile, + CoordsToAlgebraicCallback, (VOIDSTAR) &cl); + if (cl.kind == IllegalMove) break; + cl.kind = IllegalMove; + } + + /* Style is "Nf3" or "Nxf7" if this is unambiguous, + else "Ngf3" or "Ngxf7", + else "N1f3" or "N5xf7", + else "Ng1f3" or "Ng5xf7". + */ + *outp++ = ToUpper(PieceToChar(piece)); + + if (cl.file || (cl.either && !cl.rank)) { + *outp++ = ff + 'a'; + } + if (cl.rank) { + *outp++ = rf + '1'; + } + + if(board[rt][ft] != EmptySquare) + *outp++ = 'x'; + + *outp++ = ft + 'a'; + *outp++ = rt + '1'; + *outp = NULLCHAR; + return cl.kind; + + case EmptySquare: + /* Moving a nonexistent piece */ + break; + } + + /* Not a legal move, even ignoring check. + If there was a piece on the from square, + use style "Ng1g3" or "Ng1xe8"; + if there was a pawn or nothing (!), + use style "g1g3" or "g1xe8". Use "x" + if a piece was on the to square, even + a piece of the same color. + */ + outp = out; + if (piece != EmptySquare && piece != WhitePawn && piece != BlackPawn) { + *outp++ = ToUpper(PieceToChar(piece)); + } + *outp++ = ff + 'a'; + *outp++ = rf + '1'; + if (board[rt][ft] != EmptySquare) *outp++ = 'x'; + *outp++ = ft + 'a'; + *outp++ = rt + '1'; + /* Use promotion suffix style "=Q" */ + if (promoChar != NULLCHAR && promoChar != 'x') { + *outp++ = '='; + *outp++ = ToUpper(promoChar); + } + *outp = NULLCHAR; + + return IllegalMove; +} diff --git a/winboard-dm-beta4/parser.c b/winboard-dm-beta4/parser.c new file mode 100755 index 00000000..e9ec033c --- /dev/null +++ b/winboard-dm-beta4/parser.c @@ -0,0 +1,3830 @@ +/* A lexical scanner generated by flex */ + +/* Scanner skeleton version: + * $Header$ + */ + +#define FLEX_SCANNER +#define YY_FLEX_MAJOR_VERSION 2 +#define YY_FLEX_MINOR_VERSION 5 + +#include + + +/* cfront 1.2 defines "c_plusplus" instead of "__cplusplus" */ +#ifdef c_plusplus +#ifndef __cplusplus +#define __cplusplus +#endif +#endif + + +#ifdef __cplusplus + +#include +#include + +/* Use prototypes in function declarations. */ +#define YY_USE_PROTOS + +/* The "const" storage-class-modifier is valid. */ +#define YY_USE_CONST + +#else /* ! __cplusplus */ + +#if __STDC__ + +#define YY_USE_PROTOS +#define YY_USE_CONST + +#endif /* __STDC__ */ +#endif /* ! __cplusplus */ + +#ifdef __TURBOC__ + #pragma warn -rch + #pragma warn -use +#include +#include +#define YY_USE_CONST +#define YY_USE_PROTOS +#endif + +#ifdef YY_USE_CONST +#define yyconst const +#else +#define yyconst +#endif + + +#ifdef YY_USE_PROTOS +#define YY_PROTO(proto) proto +#else +#define YY_PROTO(proto) () +#endif + +/* Returned upon end-of-file. */ +#define YY_NULL 0 + +/* Promotes a possibly negative, possibly signed char to an unsigned + * integer for use as an array index. If the signed char is negative, + * we want to instead treat it as an 8-bit unsigned char, hence the + * double cast. + */ +#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c) + +/* Enter a start condition. This macro really ought to take a parameter, + * but we do it the disgusting crufty way forced on us by the ()-less + * definition of BEGIN. + */ +#define BEGIN yy_start = 1 + 2 * + +/* Translate the current start state into a value that can be later handed + * to BEGIN to return to the state. The YYSTATE alias is for lex + * compatibility. + */ +#define YY_START ((yy_start - 1) / 2) +#define YYSTATE YY_START + +/* Action number for EOF rule of a given start state. */ +#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) + +/* Special action meaning "start processing a new file". */ +#define YY_NEW_FILE yyrestart( yyin ) + +#define YY_END_OF_BUFFER_CHAR 0 + +/* Size of default input buffer. */ +#define YY_BUF_SIZE 16384 + +typedef struct yy_buffer_state *YY_BUFFER_STATE; + +extern int yyleng; +extern FILE *yyin, *yyout; + +#define EOB_ACT_CONTINUE_SCAN 0 +#define EOB_ACT_END_OF_FILE 1 +#define EOB_ACT_LAST_MATCH 2 + +/* The funky do-while in the following #define is used to turn the definition + * int a single C statement (which needs a semi-colon terminator). This + * avoids problems with code like: + * + * if ( condition_holds ) + * yyless( 5 ); + * else + * do_something_else(); + * + * Prior to using the do-while the compiler would get upset at the + * "else" because it interpreted the "if" statement as being all + * done when it reached the ';' after the yyless() call. + */ + +/* Return all but the first 'n' matched characters back to the input stream. */ + +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + *yy_cp = yy_hold_char; \ + YY_RESTORE_YY_MORE_OFFSET \ + yy_c_buf_p = yy_cp = yy_bp + n - YY_MORE_ADJ; \ + YY_DO_BEFORE_ACTION; /* set up yytext again */ \ + } \ + while ( 0 ) + +#define unput(c) yyunput( c, yytext_ptr ) + +/* The following is because we cannot portably get our hands on size_t + * (without autoconf's help, which isn't available because we want + * flex-generated scanners to compile on their own). + */ +typedef unsigned int yy_size_t; + + +struct yy_buffer_state + { + FILE *yy_input_file; + + char *yy_ch_buf; /* input buffer */ + char *yy_buf_pos; /* current position in input buffer */ + + /* Size of input buffer in bytes, not including room for EOB + * characters. + */ + yy_size_t yy_buf_size; + + /* Number of characters read into yy_ch_buf, not including EOB + * characters. + */ + int yy_n_chars; + + /* Whether we "own" the buffer - i.e., we know we created it, + * and can realloc() it to grow it, and should free() it to + * delete it. + */ + int yy_is_our_buffer; + + /* Whether this is an "interactive" input source; if so, and + * if we're using stdio for input, then we want to use getc() + * instead of fread(), to make sure we stop fetching input after + * each newline. + */ + int yy_is_interactive; + + /* Whether we're considered to be at the beginning of a line. + * If so, '^' rules will be active on the next match, otherwise + * not. + */ + int yy_at_bol; + + /* Whether to try to fill the input buffer when we reach the + * end of it. + */ + int yy_fill_buffer; + + int yy_buffer_status; +#define YY_BUFFER_NEW 0 +#define YY_BUFFER_NORMAL 1 + /* When an EOF's been seen but there's still some text to process + * then we mark the buffer as YY_EOF_PENDING, to indicate that we + * shouldn't try reading from the input source any more. We might + * still have a bunch of tokens to match, though, because of + * possible backing-up. + * + * When we actually see the EOF, we change the status to "new" + * (via yyrestart()), so that the user can continue scanning by + * just pointing yyin at a new input file. + */ +#define YY_BUFFER_EOF_PENDING 2 + }; + +static YY_BUFFER_STATE yy_current_buffer = 0; + +/* We provide macros for accessing buffer states in case in the + * future we want to put the buffer states in a more general + * "scanner state". + */ +#define YY_CURRENT_BUFFER yy_current_buffer + + +/* yy_hold_char holds the character lost when yytext is formed. */ +static char yy_hold_char; + +static int yy_n_chars; /* number of characters read into yy_ch_buf */ + + +int yyleng; + +/* Points to current character in buffer. */ +static char *yy_c_buf_p = (char *) 0; +static int yy_init = 1; /* whether we need to initialize */ +static int yy_start = 0; /* start state number */ + +/* Flag which is used to allow yywrap()'s to do buffer switches + * instead of setting up a fresh yyin. A bit of a hack ... + */ +static int yy_did_buffer_switch_on_eof; + +void yyrestart YY_PROTO(( FILE *input_file )); + +void yy_switch_to_buffer YY_PROTO(( YY_BUFFER_STATE new_buffer )); +void yy_load_buffer_state YY_PROTO(( void )); +YY_BUFFER_STATE yy_create_buffer YY_PROTO(( FILE *file, int size )); +void yy_delete_buffer YY_PROTO(( YY_BUFFER_STATE b )); +void yy_init_buffer YY_PROTO(( YY_BUFFER_STATE b, FILE *file )); +void yy_flush_buffer YY_PROTO(( YY_BUFFER_STATE b )); +#define YY_FLUSH_BUFFER yy_flush_buffer( yy_current_buffer ) + +YY_BUFFER_STATE yy_scan_buffer YY_PROTO(( char *base, yy_size_t size )); +YY_BUFFER_STATE yy_scan_string YY_PROTO(( yyconst char *yy_str )); +YY_BUFFER_STATE yy_scan_bytes YY_PROTO(( yyconst char *bytes, int len )); + +static void *yy_flex_alloc YY_PROTO(( yy_size_t )); +static void *yy_flex_realloc YY_PROTO(( void *, yy_size_t )); +static void yy_flex_free YY_PROTO(( void * )); + +#define yy_new_buffer yy_create_buffer + +#define yy_set_interactive(is_interactive) \ + { \ + if ( ! yy_current_buffer ) \ + yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \ + yy_current_buffer->yy_is_interactive = is_interactive; \ + } + +#define yy_set_bol(at_bol) \ + { \ + if ( ! yy_current_buffer ) \ + yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \ + yy_current_buffer->yy_at_bol = at_bol; \ + } + +#define YY_AT_BOL() (yy_current_buffer->yy_at_bol) + + +#define YY_USES_REJECT +typedef unsigned char YY_CHAR; +FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0; +typedef int yy_state_type; +extern char *yytext; +#define yytext_ptr yytext + +static yy_state_type yy_get_previous_state YY_PROTO(( void )); +static yy_state_type yy_try_NUL_trans YY_PROTO(( yy_state_type current_state )); +static int yy_get_next_buffer YY_PROTO(( void )); +static void yy_fatal_error YY_PROTO(( yyconst char msg[] )); + +/* Done after the current pattern has been matched and before the + * corresponding action - sets up yytext. + */ +#define YY_DO_BEFORE_ACTION \ + yytext_ptr = yy_bp; \ + yyleng = (int) (yy_cp - yy_bp); \ + yy_hold_char = *yy_cp; \ + *yy_cp = '\0'; \ + yy_c_buf_p = yy_cp; + +#define YY_NUM_RULES 42 +#define YY_END_OF_BUFFER 43 +static yyconst short int yy_acclist[661] = + { 0, + 43, 41, 42, 41, 42, 41, 42, 40, 41, 42, + 41, 42, 25, 41, 42, 41, 42, 40, 41, 42, + 40, 41, 42,16410, 40, 41, 42,16410, 41, 42, + 40, 41, 42, 40, 41, 42, 40, 41, 42, 40, + 41, 42, 40, 41, 42, 40, 41, 42, 40, 41, + 42, 40, 41, 42, 40, 41, 42, 40, 41, 42, + 40, 41, 42, 40, 41, 42, 40, 41, 42, 41, + 42, 40, 41, 42, 40, 41, 42, 40, 41, 42, + 40, 41, 42, 40, 41, 42, 40, 41, 42, 40, + 41, 42, 40, 41, 42, 40, 41, 42, 41, 42, + + 41, 42, 40, 41, 42, 40, 41, 42, 40, 41, + 42,16410, 40, 41, 42,16410, 41, 42, 40, 41, + 42, 40, 41, 42, 40, 41, 42, 40, 41, 42, + 40, 41, 42, 40, 41, 42, 40, 41, 42, 40, + 41, 42, 40, 41, 42, 40, 41, 42, 40, 41, + 42, 40, 41, 42, 40, 41, 42, 40, 41, 42, + 40, 41, 42, 40, 41, 42, 40, 41, 42, 40, + 41, 42, 40, 41, 42, 40, 41, 42, 40, 41, + 42, 40, 41, 42, 41, 42, 33, 40, 17, 40, + 9, 40, 40, 40,16410, 8218, 40, 35, 40, 40, + + 40, 40, 40, 40, 40, 40, 40, 40, 40, 9, + 40, 40, 40, 40, 40, 40, 36, 40, 3, 40, + 40, 40, 4, 40, 40, 3, 40, 40, 4, 40, + 40, 40, 40, 9, 40, 34, 40, 40, 9, 40, + 40, 40,16410, 8218, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 9, 40, 40, 40, + 40, 40, 40, 40, 3, 40, 40, 40, 4, 40, + 40, 3, 40, 40, 4, 40, 40, 40, 40, 9, + 40, 15, 9, 40, 23, 40, 23, 8, 40, 8218, + 22, 40, 22, 24, 40, 40, 40, 6, 40, 40, + + 40, 40, 40, 40, 40, 9, 40, 40, 40, 40, + 40, 20, 40, 4, 40, 40, 3, 40, 40, 3, + 40, 4, 5, 40, 4, 40, 40, 4, 40, 40, + 40, 3, 40, 4, 4, 40, 5, 6, 40, 4, + 40, 40, 9, 40, 34, 39, 9, 40, 23, 40, + 8, 40, 22, 40, 35, 40, 40, 40, 6, 40, + 40, 40, 40, 40, 40, 40, 9, 40, 40, 40, + 40, 40, 20, 40, 4, 40, 40, 3, 40, 40, + 3, 40, 5, 40, 4, 40, 40, 4, 40, 40, + 40, 3, 40, 4, 40, 5, 6, 40, 4, 40, + + 40, 9, 40, 38, 38, 37, 25, 25, 40, 6, + 40, 7, 40, 6, 10, 40, 40, 40, 40, 19, + 40, 40, 21, 40, 16, 40, 40, 40, 40, 40, + 20, 20, 40, 20, 40, 36, 3, 3, 2, 40, + 5, 4, 5, 40, 40, 4, 4, 40, 2, 7, + 40, 5, 6, 5, 6, 40, 5, 40, 40, 40, + 25, 39, 40, 6, 40, 7, 40, 40, 40, 40, + 40, 19, 40, 40, 21, 40, 16, 40, 40, 40, + 40, 40, 20, 40, 20, 20, 40, 2, 40, 5, + 40, 40, 4, 40, 2, 7, 40, 5, 6, 40, + + 5, 40, 40, 40, 7, 1, 40, 40, 40, 19, + 40, 40, 40, 21, 21, 40, 21, 40, 40, 40, + 40, 30, 36, 2, 2, 40, 5, 4, 5, 5, + 40, 2, 7, 39, 1, 40, 40, 40, 19, 40, + 40, 40, 21, 40, 21, 21, 40, 40, 40, 40, + 20, 39, 2, 40, 5, 40, 27, 38, 23, 23, + 22, 22, 24, 24, 20, 21, 1, 1, 40, 40, + 40, 40, 11, 40, 40, 28, 36, 30, 2, 2, + 5, 27, 34, 39, 39, 1, 40, 40, 40, 40, + 21, 39, 11, 40, 40, 20, 39, 18, 24, 20, + + 21, 1, 1, 19, 40, 40, 40, 11, 40, 40, + 40, 40, 21, 39, 40, 11, 40, 40, 12, 40, + 40, 40, 40, 12, 40, 40, 14, 40, 40, 40, + 14, 40, 40, 40, 39, 40, 40, 40, 40, 39, + 39, 40, 40, 31, 40, 39, 39, 31, 40, 13, + 31, 32, 32, 35, 39, 39, 31, 39, 34, 29 + } ; + +static yyconst short int yy_accept[712] = + { 0, + 1, 1, 1, 2, 4, 6, 8, 11, 13, 16, + 18, 21, 25, 29, 31, 34, 37, 40, 43, 46, + 49, 52, 55, 58, 61, 64, 67, 70, 72, 75, + 78, 81, 84, 87, 90, 93, 96, 99, 101, 103, + 106, 109, 113, 117, 119, 122, 125, 128, 131, 134, + 137, 140, 143, 146, 149, 152, 155, 158, 161, 164, + 167, 170, 173, 176, 179, 182, 185, 187, 187, 188, + 189, 189, 189, 189, 189, 190, 190, 190, 191, 191, + 193, 193, 193, 193, 194, 194, 194, 196, 196, 198, + 198, 199, 199, 200, 200, 201, 201, 201, 202, 203, + + 204, 205, 206, 207, 208, 209, 210, 212, 213, 214, + 215, 216, 217, 217, 217, 217, 217, 218, 219, 221, + 221, 222, 223, 225, 226, 228, 228, 229, 231, 232, + 233, 234, 236, 236, 236, 236, 237, 237, 238, 238, + 239, 241, 241, 242, 244, 244, 246, 246, 247, 248, + 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, + 259, 260, 261, 262, 263, 264, 265, 267, 267, 268, + 269, 271, 272, 274, 274, 275, 277, 278, 279, 280, + 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, + 282, 282, 283, 283, 283, 283, 285, 287, 288, 290, + + 291, 291, 291, 291, 293, 294, 295, 295, 295, 295, + 295, 296, 296, 297, 297, 298, 298, 298, 300, 301, + 302, 303, 304, 305, 306, 308, 309, 310, 311, 312, + 314, 314, 314, 314, 314, 316, 316, 317, 317, 317, + 319, 320, 322, 323, 325, 325, 325, 327, 328, 330, + 331, 331, 332, 334, 335, 337, 340, 342, 343, 345, + 346, 346, 346, 346, 346, 347, 349, 351, 353, 355, + 355, 356, 356, 357, 358, 358, 359, 361, 362, 363, + 364, 365, 366, 367, 369, 370, 371, 372, 373, 375, + 377, 378, 378, 380, 381, 383, 385, 387, 388, 390, + + 391, 391, 392, 394, 396, 399, 401, 402, 404, 404, + 404, 405, 406, 406, 406, 407, 407, 407, 408, 408, + 409, 409, 409, 409, 410, 410, 410, 410, 410, 410, + 410, 410, 410, 410, 410, 410, 412, 412, 412, 414, + 415, 416, 417, 417, 418, 419, 420, 422, 422, 423, + 425, 427, 428, 429, 430, 431, 432, 434, 436, 436, + 436, 436, 436, 437, 438, 438, 439, 441, 442, 443, + 443, 443, 443, 445, 446, 447, 447, 449, 449, 452, + 454, 457, 459, 460, 461, 461, 462, 462, 462, 462, + 462, 463, 463, 464, 464, 464, 466, 468, 469, 469, + + 470, 471, 472, 474, 475, 477, 479, 480, 481, 482, + 483, 485, 486, 488, 490, 492, 493, 495, 498, 501, + 503, 504, 505, 505, 505, 505, 505, 505, 505, 505, + 505, 505, 505, 505, 505, 505, 505, 505, 505, 505, + 506, 508, 509, 510, 510, 512, 512, 513, 514, 515, + 517, 519, 520, 521, 522, 522, 522, 524, 524, 524, + 525, 525, 525, 527, 528, 528, 529, 530, 530, 532, + 532, 534, 534, 534, 534, 534, 534, 534, 535, 535, + 535, 537, 538, 539, 541, 542, 543, 545, 546, 548, + 549, 550, 551, 553, 555, 557, 557, 557, 559, 559, + + 559, 560, 560, 561, 561, 562, 562, 563, 563, 564, + 564, 565, 565, 565, 565, 565, 567, 567, 568, 568, + 568, 570, 571, 571, 571, 571, 571, 571, 572, 573, + 575, 576, 578, 578, 579, 580, 581, 582, 582, 582, + 584, 584, 584, 585, 586, 586, 586, 588, 589, 590, + 591, 593, 595, 596, 598, 598, 599, 599, 599, 599, + 600, 600, 600, 600, 602, 602, 603, 604, 604, 605, + 605, 605, 605, 605, 606, 607, 608, 610, 611, 611, + 611, 611, 611, 611, 612, 613, 615, 616, 618, 619, + 619, 619, 619, 619, 619, 619, 620, 620, 620, 620, + + 620, 621, 622, 622, 622, 622, 622, 623, 624, 624, + 624, 624, 624, 625, 625, 625, 625, 626, 627, 629, + 629, 629, 629, 629, 630, 630, 631, 633, 633, 633, + 633, 633, 634, 635, 635, 635, 635, 635, 636, 637, + 638, 638, 638, 638, 638, 638, 639, 640, 640, 640, + 640, 640, 641, 642, 643, 644, 644, 644, 644, 644, + 644, 646, 646, 646, 646, 646, 647, 648, 650, 650, + 650, 651, 651, 652, 652, 653, 653, 653, 655, 655, + 656, 657, 657, 657, 657, 657, 659, 659, 659, 659, + 659, 659, 659, 659, 659, 659, 659, 659, 659, 659, + + 659, 659, 659, 659, 659, 659, 659, 659, 660, 661, + 661 + } ; + +static yyconst int yy_ec[256] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 4, 1, 5, 6, 7, 8, 1, 9, 10, + 11, 12, 13, 1, 14, 15, 16, 17, 18, 19, + 20, 20, 20, 20, 20, 20, 21, 22, 23, 1, + 24, 1, 1, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 34, 44, 34, 45, 46, 34, 34, + 47, 1, 48, 1, 49, 1, 50, 51, 52, 53, + + 54, 55, 56, 57, 58, 34, 59, 60, 61, 62, + 63, 64, 41, 65, 66, 67, 68, 34, 69, 46, + 70, 34, 71, 1, 72, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1 + } ; + +static yyconst int yy_meta[73] = + { 0, + 1, 2, 3, 2, 1, 1, 1, 1, 4, 5, + 6, 1, 1, 7, 1, 1, 4, 8, 8, 8, + 4, 9, 1, 10, 1, 4, 11, 4, 4, 4, + 4, 4, 4, 4, 11, 4, 4, 11, 12, 12, + 11, 11, 4, 4, 4, 7, 1, 1, 1, 13, + 14, 13, 13, 15, 13, 13, 13, 4, 11, 4, + 4, 11, 12, 12, 11, 4, 4, 4, 4, 4, + 1, 1 + } ; + +static yyconst short int yy_base[787] = + { 0, + 0, 72, 2588, 4394, 119, 129, 0, 141, 2583, 139, + 150, 171, 238, 2583, 257, 2527, 2518, 117, 159, 2518, + 2530, 190, 142, 233, 191, 2512, 239, 317, 376, 420, + 125, 205, 193, 114, 243, 120, 204, 331, 2574, 174, + 353, 476, 258, 260, 543, 244, 282, 346, 311, 334, + 256, 312, 365, 595, 331, 351, 354, 644, 688, 242, + 348, 327, 365, 386, 303, 392, 552, 2521, 432, 0, + 2566, 258, 557, 282, 4394, 2562, 393, 320, 2556, 2554, + 2552, 342, 442, 2551, 457, 364, 605, 2550, 0, 2562, + 4394, 576, 530, 617, 732, 625, 661, 449, 2514, 2509, + + 2512, 2517, 2492, 2493, 2490, 2517, 2515, 463, 572, 2503, + 2494, 2489, 2502, 789, 372, 861, 4394, 669, 924, 705, + 713, 468, 980, 765, 1032, 773, 789, 1076, 481, 637, + 2486, 2485, 390, 2475, 830, 2542, 2541, 383, 2540, 617, + 593, 546, 858, 874, 406, 579, 432, 865, 1120, 1005, + 505, 683, 726, 727, 621, 872, 870, 876, 603, 873, + 905, 665, 891, 884, 882, 973, 1168, 1013, 1049, 936, + 1225, 1057, 1277, 1093, 1101, 1321, 641, 983, 928, 930, + 896, 2478, 538, 543, 612, 2531, 622, 1030, 1221, 2528, + 2466, 4394, 2532, 2531, 2529, 2518, 2527, 2526, 0, 4394, + + 2525, 2524, 2523, 2521, 2520, 443, 2465, 2459, 2471, 2466, + 668, 709, 594, 1218, 732, 753, 756, 1365, 2467, 2466, + 2446, 803, 906, 2460, 2498, 0, 2453, 2449, 2441, 1422, + 689, 1069, 172, 1494, 790, 1251, 1294, 1302, 1415, 2496, + 838, 976, 1288, 1557, 1413, 1449, 678, 629, 910, 1338, + 1346, 992, 1105, 1502, 1057, 1609, 1182, 1100, 2492, 4394, + 1510, 996, 2501, 191, 2501, 1172, 960, 962, 1158, 831, + 2499, 1132, 1237, 889, 1482, 1300, 1653, 1176, 1228, 1010, + 1273, 1315, 1175, 1190, 0, 1204, 1531, 1071, 1710, 1774, + 1550, 1582, 1242, 1443, 1551, 1830, 1272, 1239, 1121, 1493, + + 1590, 1606, 1659, 1141, 1882, 1673, 1721, 1427, 1504, 2447, + 4394, 843, 1025, 2489, 4394, 1727, 2487, 2485, 2423, 2422, + 2475, 2474, 2473, 2473, 1010, 2472, 539, 2471, 1290, 1541, + 610, 2421, 2421, 2414, 2414, 0, 939, 1197, 0, 4394, + 4394, 1699, 1710, 1344, 2420, 2419, 885, 879, 1130, 1939, + 0, 2438, 2420, 2421, 2420, 0, 2011, 2083, 733, 949, + 1131, 1410, 2468, 2461, 1365, 4394, 2146, 1356, 1154, 689, + 1752, 1796, 1157, 715, 2417, 2406, 0, 1386, 0, 1564, + 2202, 1802, 1633, 2406, 1857, 2464, 1571, 1672, 2417, 2403, + 2462, 1187, 1451, 1003, 894, 1295, 1470, 1718, 1855, 1823, + + 1555, 1665, 1782, 1796, 2267, 1574, 1588, 1826, 1647, 1674, + 2339, 2460, 2411, 2475, 1840, 1858, 1608, 0, 2531, 1905, + 1956, 1857, 1728, 2409, 2451, 1639, 2450, 2385, 2445, 2383, + 2443, 2381, 2434, 1281, 2399, 2395, 2395, 2390, 1389, 4394, + 2587, 2443, 1146, 1916, 2442, 1281, 2415, 2390, 0, 2652, + 2724, 2378, 2378, 2428, 1322, 1883, 4394, 2426, 1966, 1457, + 2002, 2076, 2419, 1428, 952, 4394, 2375, 2364, 0, 2410, + 1544, 1774, 2396, 1877, 2392, 2347, 2341, 1521, 1030, 1255, + 2787, 1676, 1881, 1788, 1891, 1861, 2852, 2402, 2924, 1963, + 1841, 1944, 2402, 1691, 1649, 1816, 1235, 4394, 1979, 2393, + + 2392, 2330, 2329, 2389, 2388, 2326, 2325, 2385, 2381, 2319, + 2318, 2366, 2362, 2315, 2323, 1377, 2320, 1778, 2004, 2102, + 2355, 2310, 2348, 2304, 2287, 2326, 2288, 2289, 2264, 1524, + 2279, 4394, 1980, 4394, 2317, 4394, 4394, 2312, 2053, 2319, + 2268, 2261, 2315, 1999, 1555, 548, 1908, 1982, 1951, 1786, + 2301, 2043, 2029, 2297, 2054, 4394, 2243, 2158, 2289, 2284, + 2219, 2205, 2209, 4394, 2198, 2239, 4394, 2235, 2228, 2174, + 2228, 2182, 2157, 2174, 2105, 2086, 0, 2061, 2130, 2120, + 2054, 1040, 358, 2032, 2091, 2073, 2093, 1970, 2136, 2120, + 1988, 2029, 1542, 1985, 1941, 1941, 1923, 884, 1858, 1831, + + 2996, 1815, 1772, 1768, 1617, 651, 3068, 2150, 2149, 1757, + 1745, 1725, 4394, 1623, 1924, 2045, 3140, 2054, 0, 1631, + 1594, 1302, 1202, 3212, 2158, 2066, 2040, 2177, 1577, 1531, + 2110, 1524, 1496, 1455, 1427, 1308, 1895, 2162, 1448, 1422, + 2179, 1319, 1298, 2163, 2154, 1285, 1115, 1083, 1117, 1726, + 1576, 2196, 2198, 1062, 984, 2193, 2056, 930, 2153, 2166, + 0, 902, 804, 803, 1618, 2210, 2238, 0, 2213, 583, + 4394, 497, 2199, 486, 4394, 426, 460, 4394, 2116, 2203, + 2254, 2231, 392, 317, 1804, 2255, 2281, 239, 2027, 829, + 2006, 2117, 2293, 2295, 2298, 2299, 2303, 2317, 2321, 2322, + + 2323, 2365, 2366, 2369, 2370, 2371, 2233, 154, 4394, 4394, + 3281, 3296, 3311, 3326, 3341, 3353, 3368, 3383, 3397, 3412, + 3427, 3442, 3457, 3472, 3487, 3502, 3517, 3532, 3547, 3562, + 3577, 3592, 3607, 3622, 3633, 3648, 3663, 3678, 3693, 3708, + 3723, 3738, 3753, 3768, 3783, 3792, 3807, 3822, 3837, 3852, + 3867, 3882, 3897, 3908, 3923, 3938, 3953, 3968, 3983, 3998, + 4013, 4028, 4043, 4058, 4073, 4088, 4103, 4118, 4133, 4148, + 4163, 4174, 4188, 4203, 4218, 4233, 4244, 4258, 4273, 4288, + 4303, 4318, 4333, 4348, 4363, 4378 + } ; + +static yyconst short int yy_def[787] = + { 0, + 710, 710, 710, 710, 710, 710, 711, 712, 710, 710, + 711, 710, 12, 713, 711, 711, 711, 711, 15, 711, + 711, 15, 711, 711, 15, 711, 711, 714, 711, 15, + 29, 29, 29, 29, 29, 29, 711, 715, 710, 716, + 716, 710, 42, 713, 716, 716, 716, 716, 45, 716, + 716, 45, 716, 716, 45, 716, 716, 716, 45, 58, + 58, 58, 58, 58, 58, 716, 715, 710, 710, 711, + 717, 718, 717, 710, 710, 710, 710, 711, 710, 711, + 710, 719, 719, 711, 719, 710, 12, 710, 711, 713, + 710, 710, 711, 710, 711, 710, 710, 95, 711, 711, + + 711, 711, 711, 711, 711, 711, 711, 711, 95, 711, + 711, 711, 720, 714, 720, 721, 710, 711, 711, 710, + 711, 711, 711, 711, 119, 710, 711, 123, 95, 711, + 711, 711, 715, 722, 715, 710, 723, 716, 710, 716, + 716, 710, 716, 42, 710, 716, 724, 716, 148, 710, + 149, 716, 716, 716, 716, 716, 716, 716, 716, 716, + 716, 149, 716, 716, 716, 148, 148, 710, 148, 716, + 716, 148, 167, 710, 148, 171, 149, 716, 716, 716, + 715, 710, 717, 725, 725, 726, 727, 717, 717, 728, + 729, 710, 710, 710, 710, 711, 711, 710, 711, 710, + + 710, 710, 710, 711, 710, 710, 710, 710, 710, 710, + 711, 710, 95, 710, 711, 710, 710, 711, 711, 711, + 711, 711, 711, 711, 711, 218, 711, 711, 711, 730, + 731, 732, 733, 734, 123, 710, 711, 710, 710, 711, + 711, 711, 735, 711, 710, 710, 711, 711, 123, 711, + 710, 711, 711, 735, 123, 244, 711, 711, 711, 710, + 715, 710, 736, 710, 737, 716, 716, 716, 716, 738, + 736, 739, 716, 149, 710, 716, 149, 716, 716, 716, + 716, 716, 716, 716, 277, 716, 716, 716, 740, 716, + 716, 710, 716, 716, 716, 290, 716, 716, 290, 291, + + 710, 716, 716, 290, 296, 716, 716, 716, 715, 710, + 710, 741, 741, 742, 710, 743, 744, 744, 745, 745, + 710, 710, 710, 711, 710, 710, 710, 710, 710, 710, + 710, 710, 710, 710, 710, 711, 746, 710, 711, 710, + 710, 711, 710, 711, 711, 711, 711, 710, 711, 747, + 711, 711, 711, 711, 711, 748, 749, 749, 750, 750, + 751, 752, 753, 710, 710, 710, 711, 754, 710, 710, + 710, 710, 711, 711, 710, 710, 711, 710, 367, 754, + 367, 711, 711, 711, 715, 710, 710, 710, 710, 710, + 755, 710, 716, 756, 756, 716, 716, 291, 710, 716, + + 716, 716, 716, 716, 757, 716, 716, 716, 716, 716, + 758, 748, 758, 716, 716, 716, 716, 414, 414, 716, + 716, 716, 715, 710, 759, 760, 761, 762, 763, 764, + 765, 766, 710, 710, 710, 710, 710, 710, 710, 710, + 711, 711, 711, 710, 711, 710, 711, 711, 767, 768, + 768, 711, 711, 711, 769, 770, 710, 771, 710, 772, + 710, 710, 711, 710, 710, 710, 710, 710, 711, 710, + 772, 715, 710, 710, 710, 710, 710, 773, 774, 774, + 414, 716, 716, 716, 716, 716, 775, 767, 775, 716, + 716, 716, 776, 716, 716, 715, 710, 710, 760, 761, + + 761, 762, 762, 763, 763, 764, 764, 765, 765, 766, + 766, 710, 710, 710, 710, 710, 710, 777, 710, 710, + 711, 711, 778, 710, 710, 710, 710, 711, 711, 711, + 711, 710, 710, 710, 710, 710, 710, 710, 715, 710, + 710, 710, 773, 773, 774, 774, 716, 716, 716, 716, + 779, 716, 716, 776, 715, 710, 710, 760, 710, 710, + 710, 710, 710, 710, 710, 710, 710, 778, 778, 710, + 710, 710, 710, 711, 711, 711, 711, 711, 715, 710, + 710, 774, 774, 716, 716, 779, 716, 716, 716, 715, + 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, + + 780, 711, 710, 710, 774, 774, 781, 716, 715, 710, + 710, 710, 710, 710, 782, 782, 780, 617, 711, 710, + 710, 774, 774, 781, 782, 624, 716, 715, 710, 710, + 782, 617, 617, 710, 710, 774, 774, 783, 624, 624, + 715, 710, 710, 782, 782, 617, 617, 710, 710, 774, + 774, 783, 783, 624, 624, 715, 710, 710, 782, 782, + 617, 784, 710, 785, 774, 783, 783, 624, 715, 710, + 710, 710, 782, 784, 710, 710, 785, 710, 774, 783, + 783, 715, 710, 710, 774, 783, 715, 710, 774, 715, + 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, + + 786, 786, 786, 786, 786, 786, 786, 710, 710, 0, + 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, + 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, + 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, + 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, + 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, + 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, + 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, + 710, 710, 710, 710, 710, 710 + } ; + +static yyconst short int yy_nxt[4467] = + { 0, + 4, 4, 4, 5, 4, 4, 6, 4, 7, 8, + 4, 9, 10, 7, 4, 4, 11, 12, 13, 13, + 13, 4, 14, 4, 4, 7, 15, 16, 17, 7, + 7, 18, 7, 7, 19, 20, 21, 22, 23, 24, + 22, 25, 26, 7, 27, 7, 28, 4, 4, 29, + 30, 31, 32, 33, 34, 35, 36, 7, 19, 20, + 21, 22, 37, 24, 25, 26, 7, 7, 27, 7, + 38, 4, 4, 4, 4, 5, 4, 39, 6, 39, + 7, 8, 4, 9, 10, 40, 4, 4, 41, 42, + 43, 43, 43, 4, 44, 4, 4, 40, 45, 46, + + 47, 40, 40, 48, 40, 40, 49, 50, 51, 52, + 53, 54, 52, 55, 56, 40, 57, 40, 28, 4, + 4, 58, 59, 60, 61, 62, 63, 64, 65, 40, + 49, 50, 51, 52, 66, 54, 55, 56, 40, 40, + 57, 40, 67, 4, 68, 69, 69, 69, 69, 69, + 72, 75, 76, 77, 102, 106, 709, 73, 73, 73, + 73, 73, 710, 78, 122, 79, 80, 123, 68, 123, + 122, 81, 82, 82, 83, 123, 362, 123, 103, 70, + 107, 130, 70, 710, 84, 85, 86, 87, 87, 87, + 87, 87, 88, 710, 710, 139, 70, 89, 70, 70, + + 70, 70, 70, 70, 70, 89, 70, 70, 89, 89, + 89, 89, 89, 70, 70, 70, 70, 131, 70, 363, + 89, 89, 89, 89, 89, 89, 89, 89, 70, 89, + 70, 70, 89, 89, 89, 89, 70, 70, 70, 70, + 70, 82, 92, 122, 109, 123, 389, 123, 94, 70, + 70, 70, 70, 710, 390, 122, 123, 97, 123, 710, + 92, 82, 91, 147, 70, 139, 132, 186, 187, 101, + 93, 138, 94, 710, 95, 95, 95, 139, 96, 139, + 102, 97, 108, 108, 108, 108, 108, 108, 108, 108, + 70, 190, 662, 122, 171, 111, 112, 123, 178, 123, + + 153, 112, 93, 139, 103, 158, 98, 98, 98, 98, + 98, 98, 98, 98, 710, 710, 99, 113, 114, 114, + 114, 113, 113, 113, 113, 113, 113, 113, 113, 113, + 115, 113, 113, 134, 710, 710, 196, 197, 113, 113, + 113, 113, 70, 82, 82, 82, 154, 135, 135, 135, + 135, 135, 191, 170, 70, 139, 77, 92, 171, 70, + 91, 70, 70, 113, 117, 113, 140, 139, 79, 141, + 138, 138, 139, 70, 142, 139, 688, 170, 159, 171, + 205, 171, 206, 155, 162, 231, 139, 113, 113, 118, + 138, 70, 134, 119, 119, 119, 157, 120, 170, 171, + + 70, 171, 136, 160, 139, 179, 193, 156, 194, 265, + 164, 165, 154, 139, 195, 170, 165, 163, 171, 117, + 171, 121, 205, 155, 606, 122, 123, 122, 122, 122, + 122, 122, 122, 124, 271, 272, 170, 125, 125, 125, + 171, 126, 171, 82, 82, 82, 330, 156, 69, 69, + 69, 69, 69, 556, 180, 201, 331, 202, 82, 82, + 82, 136, 678, 203, 331, 127, 218, 218, 218, 128, + 129, 128, 129, 129, 129, 129, 129, 82, 82, 83, + 226, 226, 226, 684, 70, 244, 244, 244, 675, 143, + 85, 86, 144, 144, 144, 144, 144, 145, 256, 256, + + 256, 138, 146, 138, 138, 138, 138, 138, 138, 138, + 146, 138, 138, 146, 146, 146, 146, 146, 138, 138, + 138, 138, 277, 277, 277, 146, 146, 146, 146, 146, + 146, 146, 146, 138, 146, 138, 138, 146, 146, 146, + 146, 138, 138, 138, 138, 138, 92, 184, 311, 265, + 91, 70, 186, 312, 134, 205, 148, 206, 94, 683, + 149, 149, 149, 198, 150, 181, 184, 97, 135, 135, + 135, 135, 135, 188, 188, 188, 188, 188, 189, 211, + 211, 211, 211, 211, 211, 211, 211, 70, 148, 218, + 218, 218, 151, 151, 151, 151, 151, 151, 151, 151, + + 139, 70, 152, 70, 207, 583, 208, 70, 82, 268, + 94, 70, 209, 433, 139, 710, 139, 210, 70, 97, + 710, 186, 312, 136, 139, 70, 710, 434, 207, 70, + 208, 314, 315, 266, 267, 671, 209, 227, 139, 70, + 210, 284, 139, 376, 161, 161, 161, 161, 161, 161, + 161, 161, 70, 91, 244, 244, 244, 166, 305, 305, + 305, 167, 167, 167, 281, 168, 212, 212, 212, 212, + 212, 212, 212, 212, 216, 216, 216, 216, 216, 216, + 216, 216, 277, 277, 277, 336, 336, 336, 375, 169, + 220, 70, 377, 170, 171, 170, 170, 170, 170, 170, + + 170, 172, 360, 376, 139, 173, 173, 173, 623, 174, + 217, 217, 217, 217, 217, 217, 217, 217, 235, 235, + 235, 235, 235, 235, 235, 235, 337, 337, 337, 468, + 286, 248, 278, 175, 70, 70, 117, 176, 177, 176, + 177, 177, 177, 177, 177, 213, 360, 139, 139, 339, + 339, 339, 466, 214, 243, 243, 243, 243, 243, 243, + 243, 243, 123, 123, 123, 123, 123, 123, 123, 123, + 340, 340, 340, 341, 341, 341, 280, 213, 469, 279, + 117, 215, 215, 215, 215, 215, 215, 215, 215, 113, + 114, 114, 114, 113, 113, 113, 113, 113, 113, 113, + + 113, 113, 113, 113, 113, 678, 348, 70, 70, 70, + 113, 113, 113, 113, 249, 249, 249, 249, 249, 249, + 249, 249, 254, 254, 254, 254, 254, 254, 254, 254, + 349, 691, 134, 271, 272, 113, 117, 113, 255, 255, + 255, 255, 255, 255, 255, 255, 135, 135, 135, 135, + 135, 261, 314, 315, 349, 367, 367, 367, 676, 113, + 113, 113, 232, 232, 232, 233, 70, 113, 113, 113, + 113, 113, 113, 70, 269, 113, 113, 82, 70, 139, + 70, 70, 113, 113, 70, 113, 139, 138, 444, 710, + 70, 139, 70, 139, 139, 139, 91, 139, 134, 70, + + 136, 136, 138, 139, 675, 139, 446, 113, 117, 309, + 139, 268, 139, 70, 273, 273, 273, 273, 273, 273, + 273, 273, 285, 285, 285, 524, 139, 336, 336, 336, + 446, 113, 113, 236, 138, 282, 70, 237, 70, 281, + 287, 288, 283, 289, 70, 238, 445, 239, 524, 139, + 240, 139, 343, 296, 296, 296, 480, 139, 240, 350, + 343, 240, 455, 325, 240, 240, 468, 136, 70, 237, + 70, 350, 350, 241, 242, 241, 241, 241, 241, 241, + 241, 139, 240, 139, 343, 240, 366, 672, 240, 245, + 308, 70, 268, 367, 367, 367, 117, 244, 244, 244, + + 296, 296, 296, 246, 139, 91, 247, 386, 265, 379, + 379, 379, 387, 388, 247, 537, 265, 247, 70, 427, + 247, 247, 290, 290, 290, 290, 290, 290, 290, 290, + 247, 139, 91, 248, 314, 315, 279, 668, 247, 184, + 311, 247, 91, 605, 247, 250, 188, 188, 188, 188, + 188, 189, 479, 251, 216, 216, 216, 216, 216, 216, + 216, 216, 243, 243, 243, 243, 243, 243, 243, 243, + 232, 232, 232, 233, 381, 381, 381, 250, 403, 70, + 428, 252, 253, 252, 252, 252, 252, 252, 252, 213, + 545, 668, 139, 256, 256, 256, 265, 214, 171, 171, + + 171, 171, 171, 171, 171, 171, 299, 299, 299, 299, + 299, 299, 299, 299, 376, 366, 117, 339, 339, 339, + 663, 213, 379, 379, 379, 215, 257, 215, 215, 258, + 215, 215, 215, 274, 91, 362, 662, 410, 396, 396, + 396, 275, 254, 254, 254, 254, 254, 254, 254, 254, + 304, 304, 304, 304, 304, 304, 304, 304, 419, 419, + 419, 329, 447, 377, 375, 274, 70, 467, 661, 276, + 276, 276, 276, 276, 276, 276, 276, 236, 363, 139, + 70, 291, 522, 70, 70, 393, 448, 394, 478, 292, + 478, 239, 375, 139, 293, 395, 139, 139, 70, 339, + + 339, 339, 293, 407, 91, 293, 522, 370, 293, 293, + 374, 139, 70, 291, 440, 440, 440, 294, 295, 294, + 294, 294, 294, 294, 294, 139, 293, 401, 406, 293, + 184, 311, 293, 70, 245, 248, 70, 316, 316, 316, + 316, 316, 296, 296, 296, 70, 139, 70, 246, 139, + 70, 297, 366, 376, 396, 396, 396, 91, 139, 297, + 139, 408, 297, 139, 637, 297, 297, 338, 338, 338, + 338, 338, 338, 338, 338, 297, 348, 364, 298, 402, + 70, 70, 375, 297, 512, 364, 297, 556, 364, 297, + 300, 364, 364, 139, 139, 557, 513, 245, 301, 429, + + 404, 364, 417, 70, 91, 368, 368, 368, 70, 364, + 91, 246, 364, 526, 661, 364, 139, 397, 397, 397, + 546, 139, 300, 70, 404, 298, 302, 303, 302, 302, + 302, 302, 302, 302, 274, 455, 139, 527, 305, 305, + 305, 370, 275, 241, 241, 241, 241, 241, 241, 241, + 241, 365, 365, 365, 365, 365, 365, 365, 365, 636, + 430, 441, 441, 441, 658, 371, 274, 650, 405, 532, + 276, 306, 276, 276, 307, 276, 276, 276, 342, 372, + 405, 405, 460, 460, 460, 657, 343, 252, 252, 252, + 252, 252, 252, 252, 252, 378, 378, 378, 378, 378, + + 378, 378, 378, 471, 471, 471, 518, 518, 518, 465, + 342, 456, 456, 456, 344, 344, 344, 344, 344, 344, + 344, 344, 356, 356, 236, 356, 356, 356, 356, 356, + 563, 356, 356, 356, 356, 70, 356, 356, 467, 369, + 422, 364, 564, 356, 356, 356, 356, 369, 139, 364, + 369, 70, 364, 369, 369, 364, 364, 457, 245, 70, + 414, 414, 414, 369, 139, 364, 461, 268, 356, 356, + 356, 369, 139, 364, 369, 369, 364, 369, 70, 364, + 462, 465, 655, 369, 654, 265, 369, 358, 649, 369, + 369, 139, 356, 356, 113, 232, 232, 232, 233, 369, + + 113, 113, 113, 113, 113, 113, 134, 369, 113, 113, + 369, 245, 134, 369, 648, 113, 113, 423, 113, 380, + 380, 380, 544, 392, 544, 246, 385, 385, 385, 385, + 385, 338, 338, 338, 338, 338, 338, 338, 338, 70, + 113, 117, 302, 302, 302, 302, 302, 302, 302, 302, + 431, 431, 139, 461, 331, 370, 647, 91, 70, 70, + 646, 366, 331, 70, 113, 113, 371, 462, 414, 414, + 414, 139, 139, 371, 77, 136, 139, 576, 91, 665, + 372, 136, 70, 373, 473, 265, 79, 372, 643, 577, + 409, 373, 81, 265, 373, 139, 70, 373, 373, 294, + + 294, 294, 294, 294, 294, 294, 294, 373, 582, 139, + 374, 432, 432, 482, 70, 373, 70, 465, 373, 91, + 91, 373, 342, 418, 418, 418, 268, 139, 642, 139, + 343, 365, 365, 365, 365, 365, 365, 365, 365, 378, + 378, 378, 378, 378, 378, 378, 378, 468, 184, 498, + 441, 441, 441, 499, 342, 70, 635, 70, 344, 382, + 344, 344, 383, 344, 344, 344, 398, 70, 139, 366, + 139, 622, 679, 70, 399, 474, 418, 418, 418, 92, + 139, 70, 70, 375, 70, 475, 139, 86, 634, 630, + 397, 397, 397, 88, 139, 139, 469, 139, 398, 70, + + 491, 536, 400, 400, 400, 400, 400, 400, 400, 400, + 356, 356, 139, 356, 356, 356, 356, 356, 357, 356, + 356, 356, 356, 483, 356, 356, 298, 492, 91, 70, + 134, 412, 356, 356, 356, 376, 184, 311, 397, 397, + 397, 496, 139, 426, 426, 426, 426, 426, 344, 344, + 344, 344, 344, 344, 344, 344, 356, 356, 356, 439, + 439, 439, 439, 439, 439, 439, 439, 400, 400, 400, + 400, 400, 400, 400, 400, 413, 134, 613, 464, 664, + 356, 356, 70, 245, 417, 444, 464, 519, 539, 464, + 70, 444, 464, 464, 70, 139, 70, 246, 629, 136, + + 297, 520, 464, 139, 70, 371, 91, 139, 297, 139, + 464, 297, 467, 464, 297, 297, 464, 139, 134, 441, + 441, 441, 464, 556, 297, 621, 620, 298, 485, 555, + 464, 70, 297, 464, 70, 297, 464, 464, 297, 371, + 481, 481, 481, 484, 139, 540, 464, 139, 70, 70, + 467, 585, 486, 372, 464, 374, 415, 464, 265, 134, + 464, 139, 139, 689, 415, 70, 70, 415, 619, 70, + 415, 415, 468, 472, 472, 472, 472, 472, 139, 139, + 415, 490, 139, 416, 456, 456, 456, 136, 415, 70, + 201, 415, 202, 416, 415, 398, 615, 91, 203, 70, + + 615, 553, 139, 399, 439, 439, 439, 439, 439, 439, + 439, 439, 139, 70, 550, 467, 70, 548, 567, 268, + 549, 495, 481, 481, 481, 523, 139, 398, 136, 139, + 457, 400, 420, 400, 400, 421, 400, 400, 400, 449, + 449, 548, 449, 449, 449, 449, 449, 92, 449, 449, + 449, 449, 70, 449, 449, 631, 651, 524, 416, 70, + 449, 449, 449, 449, 70, 139, 525, 533, 533, 533, + 468, 70, 139, 481, 481, 481, 614, 139, 70, 631, + 524, 533, 533, 533, 139, 449, 449, 449, 184, 311, + 70, 139, 451, 584, 612, 558, 558, 558, 558, 558, + + 544, 392, 544, 139, 451, 451, 613, 596, 693, 449, + 449, 356, 356, 534, 356, 356, 356, 356, 356, 495, + 356, 356, 356, 356, 552, 356, 356, 534, 535, 91, + 566, 158, 356, 356, 356, 356, 535, 70, 566, 535, + 70, 566, 535, 535, 566, 566, 611, 560, 70, 610, + 139, 70, 535, 139, 566, 134, 134, 356, 356, 356, + 535, 139, 566, 535, 139, 566, 535, 590, 566, 579, + 579, 579, 579, 579, 607, 392, 631, 260, 589, 632, + 664, 356, 356, 356, 356, 461, 356, 356, 356, 356, + 356, 639, 356, 356, 356, 356, 587, 356, 356, 70, + + 631, 70, 535, 633, 356, 356, 356, 356, 588, 670, + 535, 519, 139, 535, 139, 640, 535, 535, 91, 693, + 604, 671, 134, 603, 136, 136, 535, 602, 566, 356, + 356, 356, 134, 609, 535, 644, 566, 535, 577, 566, + 535, 631, 566, 566, 70, 588, 579, 579, 579, 579, + 579, 134, 566, 356, 356, 461, 607, 139, 70, 645, + 566, 638, 628, 566, 392, 631, 566, 184, 498, 462, + 601, 139, 463, 685, 558, 558, 558, 558, 558, 134, + 463, 134, 673, 463, 631, 631, 463, 463, 260, 631, + 641, 136, 656, 653, 631, 134, 463, 631, 392, 659, + + 392, 540, 608, 627, 463, 392, 669, 463, 631, 631, + 463, 371, 392, 631, 660, 134, 601, 653, 631, 673, + 136, 631, 600, 666, 599, 372, 682, 653, 373, 653, + 631, 598, 686, 134, 653, 693, 373, 597, 569, 373, + 392, 653, 373, 373, 687, 569, 680, 667, 136, 567, + 136, 653, 373, 653, 631, 374, 392, 392, 653, 596, + 373, 564, 595, 373, 136, 653, 373, 449, 449, 653, + 449, 449, 449, 449, 449, 450, 449, 449, 449, 449, + 594, 449, 449, 134, 136, 653, 653, 593, 488, 449, + 449, 449, 592, 653, 690, 693, 591, 693, 681, 392, + + 693, 693, 136, 392, 708, 693, 694, 686, 695, 653, + 653, 696, 697, 449, 449, 449, 698, 392, 581, 693, + 489, 580, 262, 693, 693, 693, 537, 536, 578, 575, + 699, 574, 489, 489, 700, 701, 702, 449, 449, 356, + 356, 573, 356, 356, 356, 356, 356, 357, 356, 356, + 356, 356, 136, 356, 356, 572, 571, 570, 569, 105, + 412, 356, 356, 356, 260, 567, 260, 693, 693, 260, + 260, 693, 693, 693, 260, 565, 562, 561, 703, 704, + 560, 559, 705, 706, 707, 356, 356, 356, 260, 511, + 511, 509, 260, 260, 260, 509, 507, 507, 505, 505, + + 503, 503, 501, 501, 392, 551, 542, 541, 205, 356, + 356, 356, 356, 198, 356, 356, 356, 356, 356, 357, + 356, 356, 356, 356, 466, 356, 356, 538, 465, 536, + 459, 92, 412, 356, 356, 356, 260, 260, 531, 530, + 260, 260, 260, 529, 528, 444, 92, 517, 516, 515, + 514, 434, 511, 509, 507, 505, 503, 356, 356, 356, + 501, 187, 497, 493, 392, 477, 476, 74, 199, 470, + 370, 366, 459, 454, 453, 452, 199, 443, 442, 438, + 437, 356, 356, 70, 461, 436, 435, 205, 205, 199, + 198, 198, 198, 320, 320, 318, 139, 318, 462, 187, + + 424, 494, 264, 392, 264, 384, 366, 355, 354, 494, + 353, 352, 494, 351, 347, 494, 494, 346, 345, 335, + 334, 333, 332, 329, 329, 494, 328, 327, 326, 325, + 325, 324, 323, 494, 322, 321, 494, 320, 318, 494, + 371, 311, 310, 265, 264, 262, 260, 199, 259, 117, + 230, 229, 228, 199, 372, 225, 224, 415, 223, 222, + 222, 221, 220, 219, 91, 415, 205, 204, 415, 198, + 199, 415, 415, 198, 192, 184, 182, 137, 110, 105, + 104, 415, 101, 100, 416, 91, 74, 710, 710, 415, + 710, 710, 415, 710, 710, 415, 519, 710, 710, 710, + + 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, + 520, 710, 710, 521, 710, 710, 710, 710, 710, 710, + 710, 521, 710, 710, 521, 710, 710, 521, 521, 710, + 710, 710, 710, 710, 710, 710, 710, 521, 710, 710, + 710, 710, 710, 710, 710, 521, 710, 710, 521, 710, + 710, 521, 449, 449, 710, 449, 449, 449, 449, 449, + 710, 449, 449, 449, 449, 710, 449, 449, 710, 710, + 710, 710, 710, 449, 449, 449, 449, 710, 710, 710, + 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, + 710, 710, 710, 710, 710, 710, 710, 710, 449, 449, + + 449, 710, 710, 710, 710, 710, 710, 710, 710, 710, + 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, + 710, 710, 449, 449, 449, 449, 710, 449, 449, 449, + 449, 449, 710, 449, 449, 449, 449, 710, 449, 449, + 710, 710, 710, 710, 710, 449, 449, 449, 449, 710, + 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, + 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, + 449, 449, 449, 710, 710, 710, 710, 451, 710, 710, + 710, 710, 710, 710, 710, 710, 710, 710, 710, 451, + 451, 710, 710, 710, 449, 449, 519, 710, 710, 710, + + 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, + 520, 710, 710, 547, 710, 710, 710, 710, 710, 710, + 710, 547, 710, 710, 547, 710, 710, 547, 547, 710, + 710, 710, 710, 710, 710, 710, 710, 547, 710, 710, + 710, 710, 710, 710, 710, 547, 710, 710, 547, 710, + 710, 547, 449, 449, 710, 449, 449, 449, 449, 449, + 450, 449, 449, 449, 449, 710, 449, 449, 710, 710, + 710, 710, 710, 488, 449, 449, 449, 710, 710, 710, + 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, + 710, 710, 710, 710, 710, 710, 710, 710, 449, 449, + + 449, 710, 710, 710, 710, 710, 710, 710, 710, 710, + 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, + 710, 710, 449, 449, 449, 449, 710, 449, 449, 449, + 449, 449, 450, 449, 449, 449, 449, 710, 449, 449, + 710, 710, 710, 710, 710, 488, 449, 449, 449, 710, + 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, + 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, + 449, 449, 449, 710, 710, 710, 710, 489, 710, 710, + 710, 710, 710, 710, 710, 710, 710, 710, 710, 489, + 489, 710, 710, 710, 449, 449, 616, 616, 710, 616, + + 616, 616, 616, 616, 710, 616, 616, 616, 616, 710, + 616, 616, 710, 710, 710, 710, 710, 616, 616, 616, + 616, 710, 710, 710, 710, 710, 710, 618, 710, 710, + 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, + 710, 710, 616, 616, 616, 710, 710, 710, 710, 710, + 710, 618, 710, 710, 710, 710, 710, 710, 710, 710, + 710, 710, 710, 710, 710, 710, 616, 616, 616, 616, + 710, 616, 616, 616, 616, 616, 617, 616, 616, 616, + 616, 710, 616, 616, 710, 710, 710, 710, 710, 625, + 616, 616, 616, 710, 710, 710, 710, 710, 710, 626, + + 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, + 710, 710, 710, 710, 616, 616, 616, 710, 710, 710, + 710, 710, 710, 626, 710, 710, 710, 710, 710, 710, + 710, 710, 710, 710, 710, 710, 710, 710, 616, 616, + 616, 616, 710, 616, 616, 616, 616, 616, 710, 616, + 616, 616, 616, 710, 616, 616, 710, 710, 710, 710, + 710, 616, 616, 616, 616, 710, 710, 710, 710, 710, + 710, 618, 710, 710, 710, 710, 710, 710, 710, 710, + 710, 710, 710, 710, 710, 710, 616, 616, 616, 710, + 710, 710, 710, 710, 710, 618, 710, 710, 710, 710, + + 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, + 616, 616, 616, 616, 710, 616, 616, 616, 616, 616, + 617, 616, 616, 616, 616, 710, 616, 616, 710, 710, + 710, 710, 710, 625, 616, 616, 616, 710, 710, 710, + 710, 710, 710, 626, 710, 710, 710, 710, 710, 710, + 710, 710, 710, 710, 710, 710, 710, 710, 616, 616, + 616, 710, 710, 710, 710, 710, 710, 626, 710, 710, + 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, + 710, 710, 616, 616, 70, 710, 710, 70, 70, 710, + 710, 70, 70, 70, 70, 70, 71, 71, 71, 71, + + 71, 710, 71, 71, 71, 71, 71, 71, 71, 71, + 71, 90, 90, 90, 90, 90, 90, 90, 90, 90, + 90, 90, 90, 90, 90, 90, 116, 116, 116, 116, + 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, + 116, 133, 133, 133, 133, 133, 133, 133, 133, 133, + 133, 133, 133, 133, 133, 133, 138, 710, 710, 138, + 138, 138, 710, 138, 138, 138, 138, 138, 183, 183, + 183, 183, 183, 710, 183, 183, 183, 183, 183, 183, + 183, 183, 183, 185, 185, 185, 185, 185, 185, 185, + 185, 185, 185, 185, 185, 185, 185, 185, 200, 200, + + 710, 710, 710, 710, 710, 710, 710, 200, 200, 200, + 200, 200, 113, 113, 113, 113, 113, 113, 113, 113, + 113, 113, 113, 113, 113, 113, 113, 234, 234, 234, + 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, + 234, 234, 134, 134, 134, 134, 134, 134, 134, 134, + 134, 134, 134, 134, 134, 134, 134, 263, 263, 263, + 263, 263, 263, 263, 263, 263, 263, 263, 263, 263, + 263, 263, 270, 270, 270, 270, 270, 270, 270, 270, + 270, 270, 270, 270, 270, 270, 270, 185, 185, 185, + 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, + + 185, 185, 186, 186, 186, 186, 186, 186, 186, 186, + 186, 186, 186, 186, 186, 186, 186, 313, 313, 313, + 313, 313, 313, 313, 313, 313, 313, 313, 313, 313, + 313, 313, 317, 317, 710, 317, 317, 317, 317, 317, + 317, 317, 317, 317, 317, 317, 317, 319, 319, 710, + 319, 319, 319, 319, 319, 319, 319, 319, 319, 319, + 319, 319, 357, 357, 710, 357, 357, 357, 357, 357, + 357, 357, 357, 357, 357, 357, 357, 359, 359, 359, + 359, 359, 359, 359, 359, 359, 359, 359, 359, 359, + 359, 359, 113, 113, 113, 113, 113, 113, 113, 113, + + 113, 113, 113, 113, 113, 113, 113, 361, 361, 361, + 361, 361, 361, 361, 361, 361, 361, 361, 361, 361, + 361, 361, 234, 234, 234, 234, 234, 234, 234, 234, + 234, 234, 234, 234, 234, 234, 234, 369, 710, 710, + 369, 710, 369, 369, 710, 710, 369, 369, 263, 263, + 263, 263, 263, 263, 263, 263, 263, 263, 263, 263, + 263, 263, 263, 391, 391, 391, 391, 391, 391, 391, + 391, 391, 391, 391, 391, 391, 391, 391, 270, 270, + 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, + 270, 270, 270, 90, 90, 90, 90, 90, 90, 90, + + 90, 90, 90, 90, 90, 90, 90, 90, 411, 411, + 710, 411, 411, 411, 411, 411, 411, 411, 411, 411, + 411, 411, 411, 313, 313, 313, 313, 313, 313, 313, + 313, 313, 313, 313, 313, 313, 313, 313, 425, 425, + 425, 425, 710, 425, 425, 425, 425, 425, 425, 425, + 425, 425, 425, 183, 183, 183, 183, 183, 183, 183, + 183, 183, 183, 183, 183, 183, 183, 183, 317, 317, + 710, 317, 317, 317, 317, 317, 317, 317, 317, 317, + 317, 317, 317, 319, 319, 710, 319, 319, 319, 319, + 319, 319, 319, 319, 319, 319, 319, 319, 439, 710, + + 439, 710, 710, 710, 439, 439, 439, 450, 450, 710, + 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, + 450, 450, 356, 356, 710, 356, 356, 356, 356, 356, + 356, 356, 356, 356, 356, 356, 356, 357, 357, 710, + 357, 357, 357, 357, 357, 357, 357, 357, 357, 357, + 357, 357, 359, 359, 359, 359, 359, 359, 359, 359, + 359, 359, 359, 359, 359, 359, 359, 361, 361, 361, + 361, 361, 361, 361, 361, 361, 361, 361, 361, 361, + 361, 361, 113, 113, 113, 113, 113, 113, 113, 113, + 113, 113, 113, 113, 113, 113, 113, 458, 458, 458, + + 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, + 458, 458, 464, 710, 710, 710, 710, 464, 464, 710, + 710, 464, 464, 391, 391, 391, 391, 391, 391, 391, + 391, 391, 391, 391, 391, 391, 391, 391, 90, 90, + 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, + 90, 90, 90, 487, 487, 710, 487, 487, 487, 487, + 487, 487, 487, 487, 487, 487, 487, 487, 411, 411, + 710, 411, 411, 411, 411, 411, 411, 411, 411, 411, + 411, 411, 411, 425, 425, 425, 425, 710, 425, 425, + 425, 425, 425, 425, 425, 425, 425, 425, 183, 183, + + 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, + 183, 183, 183, 500, 500, 710, 500, 500, 500, 500, + 500, 500, 500, 500, 500, 500, 500, 500, 502, 502, + 710, 502, 502, 502, 502, 502, 502, 502, 502, 502, + 502, 502, 502, 504, 504, 710, 504, 504, 504, 504, + 504, 504, 504, 504, 504, 504, 504, 504, 506, 506, + 710, 506, 506, 506, 506, 506, 506, 506, 506, 506, + 506, 506, 506, 508, 508, 710, 508, 508, 508, 508, + 508, 508, 508, 508, 508, 508, 508, 508, 510, 510, + 710, 510, 510, 510, 510, 510, 510, 510, 510, 510, + + 510, 510, 510, 449, 449, 710, 449, 449, 449, 449, + 449, 449, 449, 449, 449, 449, 449, 449, 450, 450, + 710, 450, 450, 450, 450, 450, 450, 450, 450, 450, + 450, 450, 450, 359, 359, 359, 359, 359, 359, 359, + 359, 359, 359, 359, 359, 359, 359, 359, 113, 113, + 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, + 113, 113, 113, 458, 458, 458, 458, 458, 458, 458, + 458, 458, 458, 458, 458, 458, 458, 458, 535, 710, + 710, 710, 710, 535, 535, 710, 710, 535, 543, 543, + 543, 543, 543, 543, 543, 543, 543, 543, 543, 543, + + 543, 543, 543, 90, 90, 90, 90, 90, 90, 90, + 90, 90, 90, 90, 90, 90, 90, 90, 487, 487, + 710, 487, 487, 487, 487, 487, 487, 487, 487, 487, + 487, 487, 487, 554, 554, 554, 554, 554, 554, 554, + 554, 554, 554, 554, 554, 554, 554, 554, 566, 710, + 710, 710, 710, 566, 566, 710, 710, 566, 568, 568, + 710, 568, 568, 568, 568, 568, 568, 568, 568, 568, + 568, 568, 568, 586, 586, 586, 586, 586, 586, 586, + 586, 586, 586, 586, 586, 586, 586, 586, 617, 617, + 710, 617, 617, 617, 617, 617, 617, 617, 617, 617, + + 617, 617, 617, 624, 624, 710, 624, 624, 624, 624, + 624, 624, 624, 624, 624, 624, 624, 624, 616, 616, + 710, 616, 616, 616, 616, 616, 616, 616, 616, 616, + 616, 616, 616, 652, 652, 652, 652, 652, 652, 652, + 652, 652, 652, 652, 652, 652, 652, 652, 674, 674, + 674, 674, 674, 674, 674, 674, 674, 674, 674, 674, + 674, 674, 674, 677, 677, 677, 677, 677, 677, 677, + 677, 677, 677, 677, 677, 677, 677, 677, 692, 692, + 692, 692, 692, 692, 692, 692, 692, 692, 692, 692, + 692, 692, 692, 3, 710, 710, 710, 710, 710, 710, + + 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, + 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, + 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, + 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, + 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, + 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, + 710, 710, 710, 710, 710, 710 + } ; + +static yyconst short int yy_chk[4467] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 5, 6, 6, 6, 6, 6, + 8, 10, 10, 11, 18, 23, 708, 8, 8, 8, + 8, 8, 19, 11, 34, 11, 11, 34, 5, 34, + 36, 11, 12, 12, 12, 36, 233, 31, 18, 12, + 23, 31, 40, 19, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 22, 25, 40, 12, 12, 12, 12, + + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 37, 19, 233, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 13, 27, 33, 25, 33, 264, 33, 24, 22, + 25, 13, 46, 13, 264, 32, 32, 24, 32, 13, + 15, 43, 44, 44, 51, 46, 37, 72, 72, 32, + 15, 43, 15, 43, 15, 15, 15, 51, 15, 43, + 35, 15, 24, 24, 24, 24, 24, 24, 24, 24, + 47, 74, 688, 35, 60, 27, 27, 35, 60, 35, + + 46, 27, 15, 47, 35, 51, 15, 15, 15, 15, + 15, 15, 15, 15, 49, 52, 15, 28, 28, 28, + 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, + 28, 28, 28, 38, 55, 49, 78, 78, 28, 28, + 28, 28, 50, 82, 82, 82, 47, 38, 38, 38, + 38, 38, 74, 65, 48, 50, 41, 57, 65, 56, + 583, 41, 57, 28, 28, 28, 41, 48, 41, 41, + 49, 52, 56, 53, 41, 57, 684, 62, 53, 62, + 86, 62, 86, 48, 55, 115, 53, 28, 28, 29, + 55, 138, 133, 29, 29, 29, 50, 29, 61, 61, + + 66, 61, 38, 53, 138, 66, 77, 48, 77, 145, + 57, 57, 61, 66, 77, 63, 57, 56, 63, 115, + 63, 29, 145, 64, 583, 29, 29, 29, 29, 29, + 29, 29, 29, 30, 147, 147, 64, 30, 30, 30, + 64, 30, 64, 83, 83, 83, 206, 64, 69, 69, + 69, 69, 69, 683, 66, 83, 206, 83, 85, 85, + 85, 133, 677, 83, 206, 30, 98, 98, 98, 30, + 30, 30, 30, 30, 30, 30, 30, 42, 42, 42, + 108, 108, 108, 676, 42, 122, 122, 122, 674, 42, + 42, 42, 42, 42, 42, 42, 42, 42, 129, 129, + + 129, 42, 42, 42, 42, 42, 42, 42, 42, 42, + 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, + 42, 42, 151, 151, 151, 42, 42, 42, 42, 42, + 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, + 42, 42, 42, 42, 42, 42, 45, 183, 183, 142, + 546, 45, 184, 184, 67, 327, 45, 327, 45, 672, + 45, 45, 45, 142, 45, 67, 73, 45, 67, 67, + 67, 67, 67, 73, 73, 73, 73, 73, 73, 93, + 93, 93, 93, 93, 93, 93, 93, 146, 45, 109, + 109, 109, 45, 45, 45, 45, 45, 45, 45, 45, + + 146, 141, 45, 54, 92, 546, 92, 213, 87, 141, + 54, 159, 92, 331, 141, 213, 54, 92, 87, 54, + 87, 185, 185, 67, 159, 140, 87, 331, 92, 155, + 92, 187, 187, 140, 140, 670, 92, 109, 140, 213, + 92, 159, 155, 248, 54, 54, 54, 54, 54, 54, + 54, 54, 58, 606, 130, 130, 130, 58, 177, 177, + 177, 58, 58, 58, 155, 58, 94, 94, 94, 94, + 94, 94, 94, 94, 96, 96, 96, 96, 96, 96, + 96, 96, 162, 162, 162, 211, 211, 211, 247, 58, + 130, 152, 248, 58, 58, 58, 58, 58, 58, 58, + + 58, 59, 231, 370, 152, 59, 59, 59, 606, 59, + 97, 97, 97, 97, 97, 97, 97, 97, 118, 118, + 118, 118, 118, 118, 118, 118, 212, 212, 212, 374, + 162, 247, 152, 59, 153, 154, 231, 59, 59, 59, + 59, 59, 59, 59, 59, 95, 359, 153, 154, 215, + 215, 215, 370, 95, 120, 120, 120, 120, 120, 120, + 120, 120, 121, 121, 121, 121, 121, 121, 121, 121, + 216, 216, 216, 217, 217, 217, 154, 95, 374, 153, + 359, 95, 95, 95, 95, 95, 95, 95, 95, 114, + 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, + + 114, 114, 114, 114, 114, 664, 222, 235, 235, 235, + 114, 114, 114, 114, 124, 124, 124, 124, 124, 124, + 124, 124, 126, 126, 126, 126, 126, 126, 126, 126, + 222, 690, 135, 270, 270, 114, 114, 114, 127, 127, + 127, 127, 127, 127, 127, 127, 135, 135, 135, 135, + 135, 135, 312, 312, 222, 241, 241, 241, 663, 114, + 114, 116, 116, 116, 116, 116, 143, 116, 116, 116, + 116, 116, 116, 148, 143, 116, 116, 144, 157, 143, + 156, 160, 116, 116, 158, 116, 148, 144, 347, 144, + 165, 157, 164, 156, 160, 144, 395, 158, 181, 163, + + 690, 135, 274, 165, 662, 164, 348, 116, 116, 181, + 274, 160, 163, 161, 148, 148, 148, 148, 148, 148, + 148, 148, 161, 161, 161, 598, 161, 249, 249, 249, + 348, 116, 116, 119, 274, 157, 179, 119, 180, 156, + 163, 164, 158, 165, 170, 119, 347, 119, 598, 179, + 119, 180, 337, 170, 170, 170, 395, 170, 119, 223, + 337, 119, 360, 267, 119, 119, 465, 181, 267, 119, + 268, 223, 223, 119, 119, 119, 119, 119, 119, 119, + 119, 267, 119, 268, 337, 119, 242, 658, 119, 123, + 179, 178, 180, 242, 242, 242, 360, 123, 123, 123, + + 178, 178, 178, 123, 178, 394, 123, 262, 150, 252, + 252, 252, 262, 262, 123, 465, 168, 123, 280, 325, + 123, 123, 166, 166, 166, 166, 166, 166, 166, 166, + 123, 280, 479, 123, 313, 313, 178, 655, 123, 188, + 188, 123, 582, 582, 123, 125, 188, 188, 188, 188, + 188, 188, 394, 125, 150, 150, 150, 150, 150, 150, + 150, 150, 168, 168, 168, 168, 168, 168, 168, 168, + 232, 232, 232, 232, 255, 255, 255, 125, 280, 288, + 325, 125, 125, 125, 125, 125, 125, 125, 125, 128, + 479, 654, 288, 128, 128, 128, 174, 128, 169, 169, + + 169, 169, 169, 169, 169, 169, 172, 172, 172, 172, + 172, 172, 172, 172, 258, 253, 232, 258, 258, 258, + 649, 128, 253, 253, 253, 128, 128, 128, 128, 128, + 128, 128, 128, 149, 272, 361, 648, 288, 299, 299, + 299, 149, 174, 174, 174, 174, 174, 174, 174, 174, + 175, 175, 175, 175, 175, 175, 175, 175, 304, 304, + 304, 269, 349, 258, 369, 149, 269, 373, 647, 149, + 149, 149, 149, 149, 149, 149, 149, 167, 361, 269, + 266, 167, 443, 283, 278, 266, 349, 272, 392, 167, + 392, 167, 257, 266, 167, 272, 283, 278, 284, 257, + + 257, 257, 167, 284, 623, 167, 443, 369, 167, 167, + 373, 284, 286, 167, 338, 338, 338, 167, 167, 167, + 167, 167, 167, 167, 167, 286, 167, 278, 283, 167, + 189, 189, 167, 171, 171, 257, 279, 189, 189, 189, + 189, 189, 171, 171, 171, 273, 171, 298, 171, 279, + 293, 171, 293, 298, 273, 273, 273, 480, 273, 171, + 298, 286, 171, 293, 623, 171, 171, 214, 214, 214, + 214, 214, 214, 214, 214, 171, 281, 236, 171, 279, + 297, 281, 297, 171, 434, 236, 171, 497, 236, 171, + 173, 236, 236, 297, 281, 497, 434, 243, 173, 329, + + 281, 236, 298, 396, 622, 243, 243, 243, 276, 236, + 636, 243, 236, 446, 646, 236, 396, 276, 276, 276, + 480, 276, 173, 282, 281, 297, 173, 173, 173, 173, + 173, 173, 173, 173, 176, 455, 282, 446, 176, 176, + 176, 243, 176, 237, 237, 237, 237, 237, 237, 237, + 237, 238, 238, 238, 238, 238, 238, 238, 238, 622, + 329, 344, 344, 344, 643, 368, 176, 636, 282, 455, + 176, 176, 176, 176, 176, 176, 176, 176, 218, 368, + 282, 282, 365, 365, 365, 642, 218, 250, 250, 250, + 250, 250, 250, 250, 250, 251, 251, 251, 251, 251, + + 251, 251, 251, 378, 378, 378, 439, 439, 439, 368, + 218, 362, 362, 362, 218, 218, 218, 218, 218, 218, + 218, 218, 230, 230, 239, 230, 230, 230, 230, 230, + 516, 230, 230, 230, 230, 308, 230, 230, 464, 245, + 308, 239, 516, 230, 230, 230, 230, 245, 308, 239, + 245, 294, 239, 245, 245, 239, 239, 362, 246, 393, + 294, 294, 294, 245, 294, 239, 460, 393, 230, 230, + 230, 245, 393, 239, 245, 246, 239, 245, 397, 239, + 460, 464, 640, 246, 639, 275, 246, 230, 635, 246, + 246, 397, 230, 230, 234, 234, 234, 234, 234, 246, + + 234, 234, 234, 234, 234, 234, 309, 246, 234, 234, + 246, 254, 261, 246, 634, 234, 234, 309, 234, 254, + 254, 254, 478, 478, 478, 254, 261, 261, 261, 261, + 261, 275, 275, 275, 275, 275, 275, 275, 275, 287, + 234, 234, 300, 300, 300, 300, 300, 300, 300, 300, + 330, 593, 287, 471, 330, 254, 633, 545, 291, 295, + 632, 295, 330, 401, 234, 234, 244, 471, 295, 295, + 295, 291, 295, 380, 387, 309, 401, 530, 651, 651, + 244, 261, 406, 244, 387, 292, 387, 380, 630, 530, + 287, 244, 387, 301, 244, 406, 407, 244, 244, 291, + + 291, 291, 291, 291, 291, 291, 291, 244, 545, 407, + 244, 330, 593, 401, 302, 244, 417, 380, 244, 605, + 665, 244, 256, 302, 302, 302, 407, 302, 629, 417, + 256, 292, 292, 292, 292, 292, 292, 292, 292, 301, + 301, 301, 301, 301, 301, 301, 301, 383, 426, 426, + 383, 383, 383, 426, 256, 409, 621, 495, 256, 256, + 256, 256, 256, 256, 256, 256, 277, 303, 409, 303, + 495, 605, 665, 402, 277, 388, 303, 303, 303, 482, + 303, 306, 410, 306, 482, 388, 402, 388, 620, 614, + 306, 306, 306, 388, 306, 410, 383, 482, 277, 494, + + 409, 494, 277, 277, 277, 277, 277, 277, 277, 277, + 289, 289, 494, 289, 289, 289, 289, 289, 289, 289, + 289, 289, 289, 402, 289, 289, 306, 410, 650, 307, + 423, 289, 289, 289, 289, 307, 316, 316, 307, 307, + 307, 423, 307, 316, 316, 316, 316, 316, 342, 342, + 342, 342, 342, 342, 342, 342, 289, 289, 289, 343, + 343, 343, 343, 343, 343, 343, 343, 398, 398, 398, + 398, 398, 398, 398, 398, 289, 472, 612, 371, 650, + 289, 289, 290, 290, 307, 403, 371, 518, 472, 371, + 403, 484, 371, 371, 550, 290, 484, 290, 611, 423, + + 290, 518, 371, 403, 404, 372, 685, 550, 290, 484, + 371, 290, 382, 371, 290, 290, 371, 404, 496, 382, + 382, 382, 372, 610, 290, 604, 603, 290, 404, 496, + 372, 400, 290, 372, 408, 290, 372, 372, 290, 296, + 400, 400, 400, 403, 400, 472, 372, 408, 415, 491, + 415, 550, 404, 296, 372, 382, 296, 372, 399, 385, + 372, 415, 491, 685, 296, 422, 416, 296, 602, 486, + 296, 296, 416, 385, 385, 385, 385, 385, 422, 416, + 296, 408, 486, 296, 456, 456, 456, 496, 296, 483, + 474, 296, 474, 415, 296, 305, 600, 637, 474, 485, + + 599, 491, 483, 305, 399, 399, 399, 399, 399, 399, + 399, 399, 485, 420, 486, 420, 547, 483, 547, 422, + 485, 416, 420, 420, 420, 444, 420, 305, 385, 547, + 456, 305, 305, 305, 305, 305, 305, 305, 305, 350, + 350, 483, 350, 350, 350, 350, 350, 492, 350, 350, + 350, 350, 492, 350, 350, 615, 637, 444, 420, 549, + 350, 350, 350, 350, 421, 492, 444, 459, 459, 459, + 421, 490, 549, 421, 421, 421, 597, 421, 588, 615, + 444, 533, 533, 533, 490, 350, 350, 350, 499, 499, + 548, 588, 350, 549, 596, 499, 499, 499, 499, 499, + + 544, 544, 544, 548, 350, 350, 596, 595, 691, 350, + 350, 357, 357, 459, 357, 357, 357, 357, 357, 421, + 357, 357, 357, 357, 490, 357, 357, 533, 461, 689, + 519, 548, 357, 357, 357, 357, 461, 553, 519, 461, + 584, 519, 461, 461, 519, 519, 594, 592, 627, 591, + 553, 552, 461, 584, 519, 539, 555, 357, 357, 357, + 461, 627, 519, 461, 552, 519, 461, 555, 519, 539, + 539, 539, 539, 539, 584, 586, 616, 691, 553, 618, + 689, 357, 357, 358, 358, 462, 358, 358, 358, 358, + 358, 626, 358, 358, 358, 358, 552, 358, 358, 585, + + 616, 587, 462, 618, 358, 358, 358, 358, 552, 657, + 462, 520, 585, 462, 587, 626, 462, 462, 679, 692, + 581, 657, 590, 580, 539, 555, 462, 578, 520, 358, + 358, 358, 579, 590, 462, 631, 520, 462, 576, 520, + 462, 631, 520, 520, 589, 587, 579, 579, 579, 579, + 579, 609, 520, 358, 358, 367, 585, 589, 608, 631, + 520, 625, 609, 520, 638, 631, 520, 558, 558, 367, + 575, 608, 367, 679, 558, 558, 558, 558, 558, 628, + 367, 641, 659, 367, 659, 645, 367, 367, 692, 625, + 628, 590, 641, 638, 644, 656, 367, 660, 652, 644, + + 653, 579, 589, 608, 367, 680, 656, 367, 659, 645, + 367, 381, 666, 625, 645, 669, 574, 638, 644, 660, + 609, 660, 573, 653, 572, 381, 669, 652, 381, 653, + 673, 571, 680, 682, 680, 707, 381, 570, 569, 381, + 667, 666, 381, 381, 682, 568, 666, 653, 628, 566, + 641, 652, 381, 653, 673, 381, 681, 686, 680, 565, + 381, 563, 562, 381, 656, 666, 381, 405, 405, 667, + 405, 405, 405, 405, 405, 405, 405, 405, 405, 405, + 561, 405, 405, 687, 669, 681, 686, 560, 405, 405, + 405, 405, 559, 667, 687, 693, 557, 694, 667, 554, + + 695, 696, 682, 551, 707, 697, 693, 681, 694, 681, + 686, 695, 696, 405, 405, 405, 697, 543, 542, 698, + 405, 541, 540, 699, 700, 701, 538, 535, 531, 529, + 698, 528, 405, 405, 699, 700, 701, 405, 405, 411, + 411, 527, 411, 411, 411, 411, 411, 411, 411, 411, + 411, 411, 687, 411, 411, 526, 525, 524, 523, 522, + 411, 411, 411, 411, 693, 521, 694, 702, 703, 695, + 696, 704, 705, 706, 697, 517, 515, 514, 702, 703, + 513, 512, 704, 705, 706, 411, 411, 411, 698, 511, + 510, 509, 699, 700, 701, 508, 507, 506, 505, 504, + + 503, 502, 501, 500, 493, 488, 477, 476, 475, 411, + 411, 413, 413, 473, 413, 413, 413, 413, 413, 413, + 413, 413, 413, 413, 470, 413, 413, 468, 467, 463, + 458, 454, 413, 413, 413, 413, 702, 703, 453, 452, + 704, 705, 706, 448, 447, 445, 442, 438, 437, 436, + 435, 433, 432, 431, 430, 429, 428, 413, 413, 413, + 427, 425, 424, 412, 391, 390, 389, 386, 384, 376, + 375, 364, 363, 355, 354, 353, 352, 346, 345, 335, + 334, 413, 413, 414, 414, 333, 332, 328, 326, 324, + 323, 322, 321, 320, 319, 318, 414, 317, 414, 314, + + 310, 414, 271, 265, 263, 259, 240, 229, 228, 414, + 227, 225, 414, 224, 221, 414, 414, 220, 219, 210, + 209, 208, 207, 205, 204, 414, 203, 202, 201, 198, + 197, 196, 195, 414, 194, 193, 414, 191, 190, 414, + 419, 186, 182, 139, 137, 136, 134, 132, 131, 113, + 112, 111, 110, 107, 419, 106, 105, 419, 104, 103, + 102, 101, 100, 99, 90, 419, 88, 84, 419, 81, + 80, 419, 419, 79, 76, 71, 68, 39, 26, 21, + 20, 419, 17, 16, 419, 14, 9, 3, 0, 419, + 0, 0, 419, 0, 0, 419, 441, 0, 0, 0, + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 441, 0, 0, 441, 0, 0, 0, 0, 0, 0, + 0, 441, 0, 0, 441, 0, 0, 441, 441, 0, + 0, 0, 0, 0, 0, 0, 0, 441, 0, 0, + 0, 0, 0, 0, 0, 441, 0, 0, 441, 0, + 0, 441, 450, 450, 0, 450, 450, 450, 450, 450, + 0, 450, 450, 450, 450, 0, 450, 450, 0, 0, + 0, 0, 0, 450, 450, 450, 450, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 450, 450, + + 450, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 450, 450, 451, 451, 0, 451, 451, 451, + 451, 451, 0, 451, 451, 451, 451, 0, 451, 451, + 0, 0, 0, 0, 0, 451, 451, 451, 451, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 451, 451, 451, 0, 0, 0, 0, 451, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 451, + 451, 0, 0, 0, 451, 451, 481, 0, 0, 0, + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 481, 0, 0, 481, 0, 0, 0, 0, 0, 0, + 0, 481, 0, 0, 481, 0, 0, 481, 481, 0, + 0, 0, 0, 0, 0, 0, 0, 481, 0, 0, + 0, 0, 0, 0, 0, 481, 0, 0, 481, 0, + 0, 481, 487, 487, 0, 487, 487, 487, 487, 487, + 487, 487, 487, 487, 487, 0, 487, 487, 0, 0, + 0, 0, 0, 487, 487, 487, 487, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 487, 487, + + 487, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 487, 487, 489, 489, 0, 489, 489, 489, + 489, 489, 489, 489, 489, 489, 489, 0, 489, 489, + 0, 0, 0, 0, 0, 489, 489, 489, 489, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 489, 489, 489, 0, 0, 0, 0, 489, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 489, + 489, 0, 0, 0, 489, 489, 601, 601, 0, 601, + + 601, 601, 601, 601, 0, 601, 601, 601, 601, 0, + 601, 601, 0, 0, 0, 0, 0, 601, 601, 601, + 601, 0, 0, 0, 0, 0, 0, 601, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 601, 601, 601, 0, 0, 0, 0, 0, + 0, 601, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 601, 601, 607, 607, + 0, 607, 607, 607, 607, 607, 607, 607, 607, 607, + 607, 0, 607, 607, 0, 0, 0, 0, 0, 607, + 607, 607, 607, 0, 0, 0, 0, 0, 0, 607, + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 607, 607, 607, 0, 0, 0, + 0, 0, 0, 607, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 607, 607, + 617, 617, 0, 617, 617, 617, 617, 617, 0, 617, + 617, 617, 617, 0, 617, 617, 0, 0, 0, 0, + 0, 617, 617, 617, 617, 0, 0, 0, 0, 0, + 0, 617, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 617, 617, 617, 0, + 0, 0, 0, 0, 0, 617, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 617, 617, 624, 624, 0, 624, 624, 624, 624, 624, + 624, 624, 624, 624, 624, 0, 624, 624, 0, 0, + 0, 0, 0, 624, 624, 624, 624, 0, 0, 0, + 0, 0, 0, 624, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 624, 624, + 624, 0, 0, 0, 0, 0, 0, 624, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 624, 624, 711, 0, 0, 711, 711, 0, + 0, 711, 711, 711, 711, 711, 712, 712, 712, 712, + + 712, 0, 712, 712, 712, 712, 712, 712, 712, 712, + 712, 713, 713, 713, 713, 713, 713, 713, 713, 713, + 713, 713, 713, 713, 713, 713, 714, 714, 714, 714, + 714, 714, 714, 714, 714, 714, 714, 714, 714, 714, + 714, 715, 715, 715, 715, 715, 715, 715, 715, 715, + 715, 715, 715, 715, 715, 715, 716, 0, 0, 716, + 716, 716, 0, 716, 716, 716, 716, 716, 717, 717, + 717, 717, 717, 0, 717, 717, 717, 717, 717, 717, + 717, 717, 717, 718, 718, 718, 718, 718, 718, 718, + 718, 718, 718, 718, 718, 718, 718, 718, 719, 719, + + 0, 0, 0, 0, 0, 0, 0, 719, 719, 719, + 719, 719, 720, 720, 720, 720, 720, 720, 720, 720, + 720, 720, 720, 720, 720, 720, 720, 721, 721, 721, + 721, 721, 721, 721, 721, 721, 721, 721, 721, 721, + 721, 721, 722, 722, 722, 722, 722, 722, 722, 722, + 722, 722, 722, 722, 722, 722, 722, 723, 723, 723, + 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, + 723, 723, 724, 724, 724, 724, 724, 724, 724, 724, + 724, 724, 724, 724, 724, 724, 724, 725, 725, 725, + 725, 725, 725, 725, 725, 725, 725, 725, 725, 725, + + 725, 725, 726, 726, 726, 726, 726, 726, 726, 726, + 726, 726, 726, 726, 726, 726, 726, 727, 727, 727, + 727, 727, 727, 727, 727, 727, 727, 727, 727, 727, + 727, 727, 728, 728, 0, 728, 728, 728, 728, 728, + 728, 728, 728, 728, 728, 728, 728, 729, 729, 0, + 729, 729, 729, 729, 729, 729, 729, 729, 729, 729, + 729, 729, 730, 730, 0, 730, 730, 730, 730, 730, + 730, 730, 730, 730, 730, 730, 730, 731, 731, 731, + 731, 731, 731, 731, 731, 731, 731, 731, 731, 731, + 731, 731, 732, 732, 732, 732, 732, 732, 732, 732, + + 732, 732, 732, 732, 732, 732, 732, 733, 733, 733, + 733, 733, 733, 733, 733, 733, 733, 733, 733, 733, + 733, 733, 734, 734, 734, 734, 734, 734, 734, 734, + 734, 734, 734, 734, 734, 734, 734, 735, 0, 0, + 735, 0, 735, 735, 0, 0, 735, 735, 736, 736, + 736, 736, 736, 736, 736, 736, 736, 736, 736, 736, + 736, 736, 736, 737, 737, 737, 737, 737, 737, 737, + 737, 737, 737, 737, 737, 737, 737, 737, 738, 738, + 738, 738, 738, 738, 738, 738, 738, 738, 738, 738, + 738, 738, 738, 739, 739, 739, 739, 739, 739, 739, + + 739, 739, 739, 739, 739, 739, 739, 739, 740, 740, + 0, 740, 740, 740, 740, 740, 740, 740, 740, 740, + 740, 740, 740, 741, 741, 741, 741, 741, 741, 741, + 741, 741, 741, 741, 741, 741, 741, 741, 742, 742, + 742, 742, 0, 742, 742, 742, 742, 742, 742, 742, + 742, 742, 742, 743, 743, 743, 743, 743, 743, 743, + 743, 743, 743, 743, 743, 743, 743, 743, 744, 744, + 0, 744, 744, 744, 744, 744, 744, 744, 744, 744, + 744, 744, 744, 745, 745, 0, 745, 745, 745, 745, + 745, 745, 745, 745, 745, 745, 745, 745, 746, 0, + + 746, 0, 0, 0, 746, 746, 746, 747, 747, 0, + 747, 747, 747, 747, 747, 747, 747, 747, 747, 747, + 747, 747, 748, 748, 0, 748, 748, 748, 748, 748, + 748, 748, 748, 748, 748, 748, 748, 749, 749, 0, + 749, 749, 749, 749, 749, 749, 749, 749, 749, 749, + 749, 749, 750, 750, 750, 750, 750, 750, 750, 750, + 750, 750, 750, 750, 750, 750, 750, 751, 751, 751, + 751, 751, 751, 751, 751, 751, 751, 751, 751, 751, + 751, 751, 752, 752, 752, 752, 752, 752, 752, 752, + 752, 752, 752, 752, 752, 752, 752, 753, 753, 753, + + 753, 753, 753, 753, 753, 753, 753, 753, 753, 753, + 753, 753, 754, 0, 0, 0, 0, 754, 754, 0, + 0, 754, 754, 755, 755, 755, 755, 755, 755, 755, + 755, 755, 755, 755, 755, 755, 755, 755, 756, 756, + 756, 756, 756, 756, 756, 756, 756, 756, 756, 756, + 756, 756, 756, 757, 757, 0, 757, 757, 757, 757, + 757, 757, 757, 757, 757, 757, 757, 757, 758, 758, + 0, 758, 758, 758, 758, 758, 758, 758, 758, 758, + 758, 758, 758, 759, 759, 759, 759, 0, 759, 759, + 759, 759, 759, 759, 759, 759, 759, 759, 760, 760, + + 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, + 760, 760, 760, 761, 761, 0, 761, 761, 761, 761, + 761, 761, 761, 761, 761, 761, 761, 761, 762, 762, + 0, 762, 762, 762, 762, 762, 762, 762, 762, 762, + 762, 762, 762, 763, 763, 0, 763, 763, 763, 763, + 763, 763, 763, 763, 763, 763, 763, 763, 764, 764, + 0, 764, 764, 764, 764, 764, 764, 764, 764, 764, + 764, 764, 764, 765, 765, 0, 765, 765, 765, 765, + 765, 765, 765, 765, 765, 765, 765, 765, 766, 766, + 0, 766, 766, 766, 766, 766, 766, 766, 766, 766, + + 766, 766, 766, 767, 767, 0, 767, 767, 767, 767, + 767, 767, 767, 767, 767, 767, 767, 767, 768, 768, + 0, 768, 768, 768, 768, 768, 768, 768, 768, 768, + 768, 768, 768, 769, 769, 769, 769, 769, 769, 769, + 769, 769, 769, 769, 769, 769, 769, 769, 770, 770, + 770, 770, 770, 770, 770, 770, 770, 770, 770, 770, + 770, 770, 770, 771, 771, 771, 771, 771, 771, 771, + 771, 771, 771, 771, 771, 771, 771, 771, 772, 0, + 0, 0, 0, 772, 772, 0, 0, 772, 773, 773, + 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, + + 773, 773, 773, 774, 774, 774, 774, 774, 774, 774, + 774, 774, 774, 774, 774, 774, 774, 774, 775, 775, + 0, 775, 775, 775, 775, 775, 775, 775, 775, 775, + 775, 775, 775, 776, 776, 776, 776, 776, 776, 776, + 776, 776, 776, 776, 776, 776, 776, 776, 777, 0, + 0, 0, 0, 777, 777, 0, 0, 777, 778, 778, + 0, 778, 778, 778, 778, 778, 778, 778, 778, 778, + 778, 778, 778, 779, 779, 779, 779, 779, 779, 779, + 779, 779, 779, 779, 779, 779, 779, 779, 780, 780, + 0, 780, 780, 780, 780, 780, 780, 780, 780, 780, + + 780, 780, 780, 781, 781, 0, 781, 781, 781, 781, + 781, 781, 781, 781, 781, 781, 781, 781, 782, 782, + 0, 782, 782, 782, 782, 782, 782, 782, 782, 782, + 782, 782, 782, 783, 783, 783, 783, 783, 783, 783, + 783, 783, 783, 783, 783, 783, 783, 783, 784, 784, + 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, + 784, 784, 784, 785, 785, 785, 785, 785, 785, 785, + 785, 785, 785, 785, 785, 785, 785, 785, 786, 786, + 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, + 786, 786, 786, 710, 710, 710, 710, 710, 710, 710, + + 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, + 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, + 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, + 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, + 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, + 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, + 710, 710, 710, 710, 710, 710 + } ; + +static yy_state_type yy_state_buf[YY_BUF_SIZE + 2], *yy_state_ptr; +static char *yy_full_match; +static int yy_lp; +static int yy_looking_for_trail_begin = 0; +static int yy_full_lp; +static int *yy_full_state; +#define YY_TRAILING_MASK 0x2000 +#define YY_TRAILING_HEAD_MASK 0x4000 +#define REJECT \ +{ \ +*yy_cp = yy_hold_char; /* undo effects of setting up yytext */ \ +yy_cp = yy_full_match; /* restore poss. backed-over text */ \ +yy_lp = yy_full_lp; /* restore orig. accepting pos. */ \ +yy_state_ptr = yy_full_state; /* restore orig. state */ \ +yy_current_state = *yy_state_ptr; /* restore curr. state */ \ +++yy_lp; \ +goto find_rule; \ +} +#define yymore() yymore_used_but_not_detected +#define YY_MORE_ADJ 0 +#define YY_RESTORE_YY_MORE_OFFSET +char *yytext; +#define INITIAL 0 +/* + * parser.l -- lex parser of algebraic chess moves for XBoard + * $Id$ + * + * Copyright 1991 by Digital Equipment Corporation, Maynard, Massachusetts. + * Enhancements Copyright 1992-95 Free Software Foundation, Inc. + * + * The following terms apply to Digital Equipment Corporation's copyright + * interest in XBoard: + * ------------------------------------------------------------------------ + * All Rights Reserved + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appear in all copies and that + * both that copyright notice and this permission notice appear in + * supporting documentation, and that the name of Digital not be + * used in advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. + * + * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING + * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL + * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR + * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, + * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + * ------------------------------------------------------------------------ + * + * The following terms apply to the enhanced version of XBoard distributed + * by the Free Software Foundation: + * ------------------------------------------------------------------------ + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * ------------------------------------------------------------------------ + */ + +/* This parser handles all forms of promotion. + * The parser resolves ambiguous moves by searching and check-testing. + * It also parses comments of the form [anything] or (anything). + */ + +#include "config.h" + +#define NO_CONSTRAINT -1 +#undef YYLMAX +#define YYLMAX 4096 +#define UNPUT_BUF_SIZE YYLMAX + +#ifdef FLEX_SCANNER +/* yytext is probably a char*, but could be a char[]. yy_text is set + in YY_DECL below, because if yytext is a char*, its value is not + constant. */ +char *yy_text; +#else /*!FLEX_SCANNER*/ +/* yytext is definitely a char[], so yy_text can be set here, statically. */ +char *yy_text = (char *) yytext; +#endif + +#ifdef FLEX_SCANNER +/* This is flex */ +#undef YY_INPUT +#define YY_INPUT(buf, result, max_size) my_yy_input(buf, &result, max_size) +#undef YY_DECL +#define YY_DECL \ + int _yylex YY_PROTO((void)); \ + int yylex YY_PROTO((void)) \ + { \ + int result = _yylex(); \ + yy_text = (char *) yytext; \ + return(result); \ + } \ + int _yylex YY_PROTO((void)) +#else +/* This is lex */ +#undef input +#undef output +#undef unput +#endif + +/* The includes must be here, below the #undef input */ + +#include + +#if STDC_HEADERS +# include +# include +#else /* not STDC_HEADERS */ +# if HAVE_STRING_H +# include +# else /* not HAVE_STRING_H */ +# include +# endif /* not HAVE_STRING_H */ +#endif /* not STDC_HEADERS */ + +#if HAVE_UNISTD_H +# include +#endif + +#if defined(_amigados) +# include +# if HAVE_FCNTL_H +# include /* isatty() prototype */ +# endif /* HAVE_FCNTL_H */ +#endif /* defined(_amigados) */ + +#include "common.h" +#include "backend.h" +#include "frontend.h" +#include "parser.h" +#include "moves.h" + +extern int PosFlags P((int)); + +extern Board boards[MAX_MOVES]; +int yyboardindex; +int yyskipmoves = FALSE; +char currentMoveString[YYLMAX]; +#ifndef FLEX_SCANNER +char unputBuffer[UNPUT_BUF_SIZE]; +int unputCount = 0; +#endif + +#ifdef FLEX_SCANNER +void my_yy_input P((char *buf, int *result, int max_size)); +#else /*!FLEX_SCANNER*/ +static int input P((void)); +static void output P((int ch)); +static void unput P((int ch)); +int yylook P((void)); +int yyback P((int *, int)); +#endif +#undef yywrap +int yywrap P((void)); +extern void CopyBoard P((Board to, Board from)); + + +/* Macros after this point can all be overridden by user definitions in + * section 1. + */ + +#ifndef YY_SKIP_YYWRAP +#ifdef __cplusplus +extern "C" int yywrap YY_PROTO(( void )); +#else +extern int yywrap YY_PROTO(( void )); +#endif +#endif + +#ifndef YY_NO_UNPUT +static void yyunput YY_PROTO(( int c, char *buf_ptr )); +#endif + +#ifndef yytext_ptr +static void yy_flex_strncpy YY_PROTO(( char *, yyconst char *, int )); +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen YY_PROTO(( yyconst char * )); +#endif + +#ifndef YY_NO_INPUT +#ifdef __cplusplus +static int yyinput YY_PROTO(( void )); +#else +static int input YY_PROTO(( void )); +#endif +#endif + +#if YY_STACK_USED +static int yy_start_stack_ptr = 0; +static int yy_start_stack_depth = 0; +static int *yy_start_stack = 0; +#ifndef YY_NO_PUSH_STATE +static void yy_push_state YY_PROTO(( int new_state )); +#endif +#ifndef YY_NO_POP_STATE +static void yy_pop_state YY_PROTO(( void )); +#endif +#ifndef YY_NO_TOP_STATE +static int yy_top_state YY_PROTO(( void )); +#endif + +#else +#define YY_NO_PUSH_STATE 1 +#define YY_NO_POP_STATE 1 +#define YY_NO_TOP_STATE 1 +#endif + +#ifdef YY_MALLOC_DECL +YY_MALLOC_DECL +#else +#if __STDC__ +#ifndef __cplusplus +#include +#endif +#else +/* Just try to get by without declaring the routines. This will fail + * miserably on non-ANSI systems for which sizeof(size_t) != sizeof(int) + * or sizeof(void*) != sizeof(int). + */ +#endif +#endif + +/* Amount of stuff to slurp up with each read. */ +#ifndef YY_READ_BUF_SIZE +#define YY_READ_BUF_SIZE 8192 +#endif + +/* Copy whatever the last rule matched to the standard output. */ + +#ifndef ECHO +/* This used to be an fputs(), but since the string might contain NUL's, + * we now use fwrite(). + */ +#define ECHO (void) fwrite( yytext, yyleng, 1, yyout ) +#endif + +/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, + * is returned in "result". + */ +#ifndef YY_INPUT +#define YY_INPUT(buf,result,max_size) \ + if ( yy_current_buffer->yy_is_interactive ) \ + { \ + int c = '*', n; \ + for ( n = 0; n < max_size && \ + (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ + buf[n] = (char) c; \ + if ( c == '\n' ) \ + buf[n++] = (char) c; \ + if ( c == EOF && ferror( yyin ) ) \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + result = n; \ + } \ + else if ( ((result = fread( buf, 1, max_size, yyin )) == 0) \ + && ferror( yyin ) ) \ + YY_FATAL_ERROR( "input in flex scanner failed" ); +#endif + +/* No semi-colon after return; correct usage is to write "yyterminate();" - + * we don't want an extra ';' after the "return" because that will cause + * some compilers to complain about unreachable statements. + */ +#ifndef yyterminate +#define yyterminate() return YY_NULL +#endif + +/* Number of entries by which start-condition stack grows. */ +#ifndef YY_START_STACK_INCR +#define YY_START_STACK_INCR 25 +#endif + +/* Report a fatal error. */ +#ifndef YY_FATAL_ERROR +#define YY_FATAL_ERROR(msg) yy_fatal_error( msg ) +#endif + +/* Default declaration of generated scanner - a define so the user can + * easily add parameters. + */ +#ifndef YY_DECL +#define YY_DECL int yylex YY_PROTO(( void )) +#endif + +/* Code executed at the beginning of each rule, after yytext and yyleng + * have been set up. + */ +#ifndef YY_USER_ACTION +#define YY_USER_ACTION +#endif + +/* Code executed at the end of each rule. */ +#ifndef YY_BREAK +#define YY_BREAK break; +#endif + +#define YY_RULE_SETUP \ + if ( yyleng > 0 ) \ + yy_current_buffer->yy_at_bol = \ + (yytext[yyleng - 1] == '\n'); \ + YY_USER_ACTION + +YY_DECL + { + register yy_state_type yy_current_state; + register char *yy_cp, *yy_bp; + register int yy_act; + + + + + if ( yy_init ) + { + yy_init = 0; + +#ifdef YY_USER_INIT + YY_USER_INIT; +#endif + + if ( ! yy_start ) + yy_start = 1; /* first start state */ + + if ( ! yyin ) + yyin = stdin; + + if ( ! yyout ) + yyout = stdout; + + if ( ! yy_current_buffer ) + yy_current_buffer = + yy_create_buffer( yyin, YY_BUF_SIZE ); + + yy_load_buffer_state(); + } + + while ( 1 ) /* loops until end-of-file is reached */ + { + yy_cp = yy_c_buf_p; + + /* Support of yytext. */ + *yy_cp = yy_hold_char; + + /* yy_bp points to the position in yy_ch_buf of the start of + * the current run. + */ + yy_bp = yy_cp; + + yy_current_state = yy_start; + yy_current_state += YY_AT_BOL(); + yy_state_ptr = yy_state_buf; + *yy_state_ptr++ = yy_current_state; +yy_match: + do + { + register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)]; + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 711 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + *yy_state_ptr++ = yy_current_state; + ++yy_cp; + } + while ( yy_base[yy_current_state] != 4394 ); + +yy_find_action: + yy_current_state = *--yy_state_ptr; + yy_lp = yy_accept[yy_current_state]; +find_rule: /* we branch to this label when backing up */ + for ( ; ; ) /* until we find what rule we matched */ + { + if ( yy_lp && yy_lp < yy_accept[yy_current_state + 1] ) + { + yy_act = yy_acclist[yy_lp]; + if ( yy_act & YY_TRAILING_HEAD_MASK || + yy_looking_for_trail_begin ) + { + if ( yy_act == yy_looking_for_trail_begin ) + { + yy_looking_for_trail_begin = 0; + yy_act &= ~YY_TRAILING_HEAD_MASK; + break; + } + } + else if ( yy_act & YY_TRAILING_MASK ) + { + yy_looking_for_trail_begin = yy_act & ~YY_TRAILING_MASK; + yy_looking_for_trail_begin |= YY_TRAILING_HEAD_MASK; + } + else + { + yy_full_match = yy_cp; + yy_full_state = yy_state_ptr; + yy_full_lp = yy_lp; + break; + } + ++yy_lp; + goto find_rule; + } + --yy_cp; + yy_current_state = *--yy_state_ptr; + yy_lp = yy_accept[yy_current_state]; + } + + YY_DO_BEFORE_ACTION; + + +do_action: /* This label is used only to access EOF actions. */ + + + switch ( yy_act ) + { /* beginning of action switch */ +case 1: +YY_RULE_SETUP +{ + /* + * Fully-qualified algebraic move, possibly with promotion + */ + int skip1 = 0, skip2 = 0; + ChessSquare piece; + ChessMove result; + + if (yyskipmoves) return (int) AmbiguousMove; /* not disambiguated */ + + /* remove the / */ + if (yytext[1] == '/') skip1 = 1; + + /* remove the [xX:-] */ + if ((yytext[3+skip1] == 'x') || (yytext[3+skip1] == 'X') || + (yytext[3+skip1] == '-') || (yytext[3+skip1] == ':')) skip2 = 1; + + currentMoveString[0] = yytext[1+skip1]; + currentMoveString[1] = yytext[2+skip1]; + currentMoveString[2] = yytext[3+skip1+skip2]; + currentMoveString[3] = yytext[4+skip1+skip2]; + currentMoveString[4] = NULLCHAR; + + if (yyleng-skip1-skip2 > 5) { + if (yytext[yyleng-1] == ')') { + currentMoveString[4] = ToLower(yytext[yyleng-2]); + } else { + currentMoveString[4] = ToLower(yytext[yyleng-1]); + } + currentMoveString[5] = NULLCHAR; + } + + piece = boards[yyboardindex] + [currentMoveString[1] - '1'][currentMoveString[0] - 'a']; + if (ToLower(yytext[0]) != ToLower(PieceToChar(piece))) + return (int) IllegalMove; + + result = LegalityTest(boards[yyboardindex], + PosFlags(yyboardindex), EP_UNKNOWN, + currentMoveString[1] - '1', + currentMoveString[0] - 'a', + currentMoveString[3] - '1', + currentMoveString[2] - 'a', + currentMoveString[4]); + + if (currentMoveString[4] == NULLCHAR && + (result == WhitePromotionQueen || result == BlackPromotionQueen)) { + currentMoveString[4] = 'q'; + currentMoveString[5] = NULLCHAR; + } + + return (int) result; +} + YY_BREAK +case 2: +YY_RULE_SETUP +{ + /* + * Simple algebraic move, possibly with promotion + */ + int skip = 0; + ChessMove result; + + if (yyskipmoves) return (int) AmbiguousMove; /* not disambiguated */ + + /* remove the [xX:-] */ + if ((yytext[2] == 'x') || (yytext[2] == 'X') || + (yytext[2] == '-') || (yytext[2] == ':')) skip = 1; + + currentMoveString[0] = yytext[0]; + currentMoveString[1] = yytext[1]; + currentMoveString[2] = yytext[2+skip]; + currentMoveString[3] = yytext[3+skip]; + currentMoveString[4] = NULLCHAR; + + if (yyleng-skip > 4) { + if (yytext[yyleng-1] == ')') { + currentMoveString[4] = ToLower(yytext[yyleng-2]); + } else { + currentMoveString[4] = ToLower(yytext[yyleng-1]); + } + currentMoveString[5] = NULLCHAR; + } + + result = LegalityTest(boards[yyboardindex], + PosFlags(yyboardindex), EP_UNKNOWN, + currentMoveString[1] - '1', + currentMoveString[0] - 'a', + currentMoveString[3] - '1', + currentMoveString[2] - 'a', + currentMoveString[4]); + + if (currentMoveString[4] == NULLCHAR && + (result == WhitePromotionQueen || result == BlackPromotionQueen)) { + currentMoveString[4] = 'q'; + currentMoveString[5] = NULLCHAR; + } + + return (int) result; +} + YY_BREAK +case 3: +YY_RULE_SETUP +{ + /* + * Pawn move, possibly with promotion + */ + DisambiguateClosure cl; + int skip = 0; + + if (yyskipmoves) return (int) AmbiguousMove; /* not disambiguated */ + + /* remove the =() */ + if (yytext[2] == '=') skip++; + if (yytext[2+skip] == '(') skip++; + + cl.pieceIn = WhiteOnMove(yyboardindex) ? WhitePawn : BlackPawn; + cl.rfIn = -1; + cl.ffIn = yytext[0] - 'a'; + cl.rtIn = yytext[1] - '1'; + cl.ftIn = yytext[0] - 'a'; + cl.promoCharIn = yytext[2+skip]; + Disambiguate(boards[yyboardindex], + PosFlags(yyboardindex), EP_UNKNOWN, &cl); + + currentMoveString[0] = cl.ff + 'a'; + currentMoveString[1] = cl.rf + '1'; + currentMoveString[2] = cl.ft + 'a'; + currentMoveString[3] = cl.rt + '1'; + currentMoveString[4] = cl.promoChar; + currentMoveString[5] = NULLCHAR; + + return (int) cl.kind; +} + YY_BREAK +case 4: +YY_RULE_SETUP +{ + /* + * Pawn capture, possibly with promotion, possibly ambiguous + */ + DisambiguateClosure cl; + int skip1 = 0, skip2 = 0; + + if (yyskipmoves) return (int) AmbiguousMove; /* not disambiguated */ + + /* remove trailing ep or e.p. (nonstandard PGN) */ + if (yytext[yyleng-1] == 'p') { + yyleng -= 2; + yytext[yyleng] = NULLCHAR; + } else if (yytext[yyleng-1] == '.') { + yyleng -= 4; + yytext[yyleng] = NULLCHAR; + } + + /* remove the [xX:-] and =() */ + if ((yytext[1] == 'x') || (yytext[1] == 'X') + || (yytext[1] == ':') || (yytext[1] == '-')) skip1 = 1; + if (yytext[2+skip1] == '=') skip2++; + if (yytext[2+skip1+skip2] == '(') skip2++; + + cl.pieceIn = WhiteOnMove(yyboardindex) ? WhitePawn : BlackPawn; + cl.rfIn = -1; + cl.ffIn = yytext[0] - 'a'; + cl.rtIn = -1; + cl.ftIn = yytext[1+skip1] - 'a'; + cl.promoCharIn = yytext[2+skip1+skip2]; + Disambiguate(boards[yyboardindex], + PosFlags(yyboardindex), EP_UNKNOWN, &cl); + + currentMoveString[0] = cl.ff + 'a'; + currentMoveString[1] = cl.rf + '1'; + currentMoveString[2] = cl.ft + 'a'; + currentMoveString[3] = cl.rt + '1'; + currentMoveString[4] = cl.promoChar; + currentMoveString[5] = NULLCHAR; + + return (int) cl.kind; +} + YY_BREAK +case 5: +YY_RULE_SETUP +{ + /* + * unambiguously abbreviated Pawn capture, possibly with promotion + */ + int skip = 0; + ChessMove result; + + if (yyskipmoves) return (int) AmbiguousMove; /* not disambiguated */ + + /* remove trailing ep or e.p. (nonstandard PGN) */ + if (yytext[yyleng-1] == 'p') { + yyleng -= 2; + yytext[yyleng] = NULLCHAR; + } else if (yytext[yyleng-1] == '.') { + yyleng -= 4; + yytext[yyleng] = NULLCHAR; + } + + /* remove the [xX:-] */ + if ((yytext[1] == 'x') || (yytext[1] == 'X') + || (yytext[1] == ':') || (yytext[1] == '-')) skip = 1; + + currentMoveString[0] = yytext[0]; + currentMoveString[2] = yytext[1+skip]; + currentMoveString[3] = yytext[2+skip]; + if (WhiteOnMove(yyboardindex)) { + if (yytext[2+skip] == '1') return (int) ImpossibleMove; + currentMoveString[1] = yytext[2+skip] - 1; + } else { + if (yytext[2+skip] == '8') return (int) ImpossibleMove; + currentMoveString[1] = yytext[2+skip] + 1; + } + if (yyleng-skip > 3) { + if (yytext[yyleng-1] == ')') + currentMoveString[4] = ToLower(yytext[yyleng-2]); + else + currentMoveString[4] = ToLower(yytext[yyleng-1]); + currentMoveString[5] = NULLCHAR; + } else { + currentMoveString[4] = NULLCHAR; + } + + result = LegalityTest(boards[yyboardindex], + PosFlags(yyboardindex), EP_UNKNOWN, + currentMoveString[1] - '1', + currentMoveString[0] - 'a', + currentMoveString[3] - '1', + currentMoveString[2] - 'a', + currentMoveString[4]); + + if (currentMoveString[4] == NULLCHAR && + (result == WhitePromotionQueen || result == BlackPromotionQueen)) { + currentMoveString[4] = 'q'; + currentMoveString[5] = NULLCHAR; + } + + if (result != IllegalMove) return (int) result; + + /* Special case: improperly written en passant capture */ + if (WhiteOnMove(yyboardindex)) { + if (currentMoveString[3] == '5') { + currentMoveString[1] = '5'; + currentMoveString[3] = '6'; + } else { + return (int) IllegalMove; + } + } else { + if (currentMoveString[3] == '4') { + currentMoveString[1] = '4'; + currentMoveString[3] = '3'; + } else { + return (int) IllegalMove; + } + } + + result = LegalityTest(boards[yyboardindex], + PosFlags(yyboardindex), EP_UNKNOWN, + currentMoveString[1] - '1', + currentMoveString[0] - 'a', + currentMoveString[3] - '1', + currentMoveString[2] - 'a', + currentMoveString[4]); + + if (result == WhiteCapturesEnPassant || result == BlackCapturesEnPassant) + return (int) result; + else + return (int) IllegalMove; +} + YY_BREAK +case 6: +YY_RULE_SETUP +{ + /* + * piece move, possibly ambiguous + */ + DisambiguateClosure cl; + int skip = 0; + + if (yyskipmoves) return (int) AmbiguousMove; /* not disambiguated */ + + /* remove the [xX:-] */ + if ((yytext[1] == 'x') || (yytext[1] == 'X') + || (yytext[1] == ':') || (yytext[1] == '-')) skip = 1; + + if (WhiteOnMove(yyboardindex)) { + cl.pieceIn = CharToPiece(ToUpper(yytext[0])); + } else { + cl.pieceIn = CharToPiece(ToLower(yytext[0])); + } + cl.rfIn = -1; + cl.ffIn = -1; + cl.rtIn = yytext[2+skip] - '1'; + cl.ftIn = yytext[1+skip] - 'a'; + cl.promoCharIn = NULLCHAR; + Disambiguate(boards[yyboardindex], + PosFlags(yyboardindex), EP_UNKNOWN, &cl); + + currentMoveString[0] = cl.ff + 'a'; + currentMoveString[1] = cl.rf + '1'; + currentMoveString[2] = cl.ft + 'a'; + currentMoveString[3] = cl.rt + '1'; + currentMoveString[4] = cl.promoChar; + currentMoveString[5] = NULLCHAR; + + return (int) cl.kind; +} + YY_BREAK +case 7: +YY_RULE_SETUP +{ + /* + * piece move with rank or file disambiguator + */ + DisambiguateClosure cl; + int skip = 0; + + if (yyskipmoves) return (int) AmbiguousMove; /* not disambiguated */ + + /* remove the [xX:-] */ + if ((yytext[2] == 'x') || (yytext[2] == 'X') + || (yytext[2] == ':') || (yytext[2] == '-')) skip = 1; + + if (WhiteOnMove(yyboardindex)) { + cl.pieceIn = CharToPiece(ToUpper(yytext[0])); + } else { + cl.pieceIn = CharToPiece(ToLower(yytext[0])); + } + if (isalpha(yytext[1])) { + cl.rfIn = -1; + cl.ffIn = yytext[1] - 'a'; + } else { + cl.rfIn = yytext[1] - '1'; + cl.ffIn = -1; + } + cl.rtIn = yytext[3+skip] - '1'; + cl.ftIn = yytext[2+skip] - 'a'; + cl.promoCharIn = NULLCHAR; + Disambiguate(boards[yyboardindex], + PosFlags(yyboardindex), EP_UNKNOWN, &cl); + + currentMoveString[0] = cl.ff + 'a'; + currentMoveString[1] = cl.rf + '1'; + currentMoveString[2] = cl.ft + 'a'; + currentMoveString[3] = cl.rt + '1'; + currentMoveString[4] = cl.promoChar; + currentMoveString[5] = NULLCHAR; + + return (int) cl.kind; +} + YY_BREAK +case 8: +YY_RULE_SETUP +{ + int rf, ff, rt, ft; + + if (yyskipmoves) return (int) AmbiguousMove; /* not disambiguated */ + + if (WhiteOnMove(yyboardindex)) { + if (boards[yyboardindex][0][3] == WhiteKing) { + /* ICS wild castling */ + strcpy(currentMoveString, "d1f1"); + rf = 0; + ff = 3; + rt = 0; + ft = 5; + } else { + strcpy(currentMoveString, "e1c1"); + rf = 0; + ff = 4; + rt = 0; + ft = 2; + } + } else{ + if (boards[yyboardindex][7][3] == BlackKing) { + /* ICS wild castling */ + strcpy(currentMoveString, "d8f8"); + rf = 7; + ff = 3; + rt = 7; + ft = 5; + } else { + strcpy(currentMoveString, "e8c8"); + rf = 7; + ff = 4; + rt = 7; + ft = 2; + } + } + return (int) LegalityTest(boards[yyboardindex], + PosFlags(yyboardindex), EP_UNKNOWN, + rf, ff, rt, ft, NULLCHAR); +} + YY_BREAK +case 9: +YY_RULE_SETUP +{ + int rf, ff, rt, ft; + + if (yyskipmoves) return (int) AmbiguousMove; /* not disambiguated */ + + if (WhiteOnMove(yyboardindex)) { + if (boards[yyboardindex][0][3] == WhiteKing) { + /* ICS wild castling */ + strcpy(currentMoveString, "d1b1"); + rf = 0; + ff = 3; + rt = 0; + ft = 1; + } else { + strcpy(currentMoveString, "e1g1"); + rf = 0; + ff = 4; + rt = 0; + ft = 6; + } + } else { + if (boards[yyboardindex][7][3] == BlackKing) { + /* ICS wild castling */ + strcpy(currentMoveString, "d8b8"); + rf = 7; + ff = 3; + rt = 7; + ft = 1; + } else { + strcpy(currentMoveString, "e8g8"); + rf = 7; + ff = 4; + rt = 7; + ft = 6; + } + } + return (int) LegalityTest(boards[yyboardindex], + PosFlags(yyboardindex), EP_UNKNOWN, + rf, ff, rt, ft, NULLCHAR); +} + YY_BREAK +case 10: +YY_RULE_SETUP +{ + /* Bughouse piece drop. No legality checking for now. */ + currentMoveString[1] = '@'; + currentMoveString[2] = yytext[2]; + currentMoveString[3] = yytext[3]; + currentMoveString[4] = NULLCHAR; + if (WhiteOnMove(yyboardindex)) { + currentMoveString[0] = ToUpper(yytext[0]); + return (int) WhiteDrop; + } else { + currentMoveString[0] = ToLower(yytext[0]); + return (int) BlackDrop; + } +} + YY_BREAK +case 11: +YY_RULE_SETUP +{ + if (WhiteOnMove(yyboardindex)) + return (int) BlackWins; + else + return (int) WhiteWins; +} + YY_BREAK +case 12: +YY_RULE_SETUP +{ + return (int) (ToUpper(yytext[0]) == 'W' ? BlackWins : WhiteWins); +} + YY_BREAK +case 13: +YY_RULE_SETUP +{ + return (int) GameUnfinished; +} + YY_BREAK +case 14: +YY_RULE_SETUP +{ + return (int) GameIsDrawn; +} + YY_BREAK +case 15: +YY_RULE_SETUP +{ + return (int) GameIsDrawn; +} + YY_BREAK +case 16: +YY_RULE_SETUP +{ + if (WhiteOnMove(yyboardindex)) + return (int) BlackWins; + else + return (int) WhiteWins; +} + YY_BREAK +case 17: +YY_RULE_SETUP +{ + if (WhiteOnMove(yyboardindex)) + return (int) BlackWins; + else + return (int) WhiteWins; +} + YY_BREAK +case 18: +YY_RULE_SETUP +{ + return (int) GameIsDrawn; +} + YY_BREAK +case 19: +YY_RULE_SETUP +{ + return (int) GameIsDrawn; +} + YY_BREAK +case 20: +YY_RULE_SETUP +{ + return (int) (ToUpper(yytext[0]) == 'W' ? WhiteWins : BlackWins); +} + YY_BREAK +case 21: +YY_RULE_SETUP +{ + return (int) (ToUpper(yytext[0]) == 'W' ? BlackWins : WhiteWins); +} + YY_BREAK +case 22: +YY_RULE_SETUP +{ + return (int) WhiteWins; +} + YY_BREAK +case 23: +YY_RULE_SETUP +{ + return (int) BlackWins; +} + YY_BREAK +case 24: +YY_RULE_SETUP +{ + return (int) GameIsDrawn; +} + YY_BREAK +case 25: +YY_RULE_SETUP +{ + return (int) GameUnfinished; +} + YY_BREAK +case 26: +YY_RULE_SETUP +{ + /* move numbers */ + if ((yyleng == 1) && (yytext[0] == '1')) + return (int) MoveNumberOne; +} + YY_BREAK +case 27: +YY_RULE_SETUP +{ + /* elapsed time indication, e.g. (0:12) or {10:21.071} */ + return (int) ElapsedTime; +} + YY_BREAK +case 28: +YY_RULE_SETUP +{ + /* position diagram enclosed in [-- --] */ + return (int) PositionDiagram; +} + YY_BREAK +case 29: +*yy_cp = yy_hold_char; /* undo effects of setting up yytext */ +yy_c_buf_p = yy_cp -= 1; +YY_DO_BEFORE_ACTION; /* set up yytext again */ +YY_RULE_SETUP +{ + /* position diagram enclosed in {-- --} */ + return (int) PositionDiagram; +} + YY_BREAK +case 30: +YY_RULE_SETUP +{ + return (int) PGNTag; +} + YY_BREAK +case 31: +YY_RULE_SETUP +{ + return (int) GNUChessGame; +} + YY_BREAK +case 32: +*yy_cp = yy_hold_char; /* undo effects of setting up yytext */ +yy_c_buf_p = yy_cp -= 1; +YY_DO_BEFORE_ACTION; /* set up yytext again */ +YY_RULE_SETUP +{ + return (int) XBoardGame; +} + YY_BREAK +case 33: +YY_RULE_SETUP +{ /* numeric annotation glyph */ + return (int) NAG; +} + YY_BREAK +case 34: +YY_RULE_SETUP +{ /* anything in {} */ + return (int) Comment; +} + YY_BREAK +case 35: +*yy_cp = yy_hold_char; /* undo effects of setting up yytext */ +yy_c_buf_p = yy_cp -= 1; +YY_DO_BEFORE_ACTION; /* set up yytext again */ +YY_RULE_SETUP +{ /* ; to end of line */ + return (int) Comment; +} + YY_BREAK +case 36: +YY_RULE_SETUP +{ /* anything in [] */ + return (int) Comment; +} + YY_BREAK +case 37: +YY_RULE_SETUP +{ /* nested () */ + return (int) Comment; +} + YY_BREAK +case 38: +YY_RULE_SETUP +{ /* >=2 chars in () */ + return (int) Comment; +} + YY_BREAK +case 39: +YY_RULE_SETUP +{ + /* Skip mail headers */ +} + YY_BREAK +case 40: +YY_RULE_SETUP +{ + /* Skip random words */ +} + YY_BREAK +case 41: +YY_RULE_SETUP +{ + /* Skip everything else */ +} + YY_BREAK +case 42: +YY_RULE_SETUP +ECHO; + YY_BREAK + case YY_STATE_EOF(INITIAL): + yyterminate(); + + case YY_END_OF_BUFFER: + { + /* Amount of text matched not including the EOB char. */ + int yy_amount_of_matched_text = (int) (yy_cp - yytext_ptr) - 1; + + /* Undo the effects of YY_DO_BEFORE_ACTION. */ + *yy_cp = yy_hold_char; + YY_RESTORE_YY_MORE_OFFSET + + if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_NEW ) + { + /* We're scanning a new file or input source. It's + * possible that this happened because the user + * just pointed yyin at a new source and called + * yylex(). If so, then we have to assure + * consistency between yy_current_buffer and our + * globals. Here is the right place to do so, because + * this is the first action (other than possibly a + * back-up) that will match for the new input source. + */ + yy_n_chars = yy_current_buffer->yy_n_chars; + yy_current_buffer->yy_input_file = yyin; + yy_current_buffer->yy_buffer_status = YY_BUFFER_NORMAL; + } + + /* Note that here we test for yy_c_buf_p "<=" to the position + * of the first EOB in the buffer, since yy_c_buf_p will + * already have been incremented past the NUL character + * (since all states make transitions on EOB to the + * end-of-buffer state). Contrast this with the test + * in input(). + */ + if ( yy_c_buf_p <= &yy_current_buffer->yy_ch_buf[yy_n_chars] ) + { /* This was really a NUL. */ + yy_state_type yy_next_state; + + yy_c_buf_p = yytext_ptr + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state(); + + /* Okay, we're now positioned to make the NUL + * transition. We couldn't have + * yy_get_previous_state() go ahead and do it + * for us because it doesn't know how to deal + * with the possibility of jamming (and we don't + * want to build jamming into it because then it + * will run more slowly). + */ + + yy_next_state = yy_try_NUL_trans( yy_current_state ); + + yy_bp = yytext_ptr + YY_MORE_ADJ; + + if ( yy_next_state ) + { + /* Consume the NUL. */ + yy_cp = ++yy_c_buf_p; + yy_current_state = yy_next_state; + goto yy_match; + } + + else + { + yy_cp = yy_c_buf_p; + goto yy_find_action; + } + } + + else switch ( yy_get_next_buffer() ) + { + case EOB_ACT_END_OF_FILE: + { + yy_did_buffer_switch_on_eof = 0; + + if ( yywrap() ) + { + /* Note: because we've taken care in + * yy_get_next_buffer() to have set up + * yytext, we can now set up + * yy_c_buf_p so that if some total + * hoser (like flex itself) wants to + * call the scanner after we return the + * YY_NULL, it'll still work - another + * YY_NULL will get returned. + */ + yy_c_buf_p = yytext_ptr + YY_MORE_ADJ; + + yy_act = YY_STATE_EOF(YY_START); + goto do_action; + } + + else + { + if ( ! yy_did_buffer_switch_on_eof ) + YY_NEW_FILE; + } + break; + } + + case EOB_ACT_CONTINUE_SCAN: + yy_c_buf_p = + yytext_ptr + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state(); + + yy_cp = yy_c_buf_p; + yy_bp = yytext_ptr + YY_MORE_ADJ; + goto yy_match; + + case EOB_ACT_LAST_MATCH: + yy_c_buf_p = + &yy_current_buffer->yy_ch_buf[yy_n_chars]; + + yy_current_state = yy_get_previous_state(); + + yy_cp = yy_c_buf_p; + yy_bp = yytext_ptr + YY_MORE_ADJ; + goto yy_find_action; + } + break; + } + + default: + YY_FATAL_ERROR( + "fatal flex scanner internal error--no action found" ); + } /* end of action switch */ + } /* end of scanning one token */ + } /* end of yylex */ + + +/* yy_get_next_buffer - try to read in a new buffer + * + * Returns a code representing an action: + * EOB_ACT_LAST_MATCH - + * EOB_ACT_CONTINUE_SCAN - continue scanning from current position + * EOB_ACT_END_OF_FILE - end of file + */ + +static int yy_get_next_buffer() + { + register char *dest = yy_current_buffer->yy_ch_buf; + register char *source = yytext_ptr; + register int number_to_move, i; + int ret_val; + + if ( yy_c_buf_p > &yy_current_buffer->yy_ch_buf[yy_n_chars + 1] ) + YY_FATAL_ERROR( + "fatal flex scanner internal error--end of buffer missed" ); + + if ( yy_current_buffer->yy_fill_buffer == 0 ) + { /* Don't try to fill the buffer, so this is an EOF. */ + if ( yy_c_buf_p - yytext_ptr - YY_MORE_ADJ == 1 ) + { + /* We matched a single character, the EOB, so + * treat this as a final EOF. + */ + return EOB_ACT_END_OF_FILE; + } + + else + { + /* We matched some text prior to the EOB, first + * process it. + */ + return EOB_ACT_LAST_MATCH; + } + } + + /* Try to read more data. */ + + /* First move last chars to start of buffer. */ + number_to_move = (int) (yy_c_buf_p - yytext_ptr) - 1; + + for ( i = 0; i < number_to_move; ++i ) + *(dest++) = *(source++); + + if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_EOF_PENDING ) + /* don't do the read, it's not guaranteed to return an EOF, + * just force an EOF + */ + yy_current_buffer->yy_n_chars = yy_n_chars = 0; + + else + { + int num_to_read = + yy_current_buffer->yy_buf_size - number_to_move - 1; + + while ( num_to_read <= 0 ) + { /* Not enough room in the buffer - grow it. */ +#ifdef YY_USES_REJECT + YY_FATAL_ERROR( +"input buffer overflow, can't enlarge buffer because scanner uses REJECT" ); +#else + + /* just a shorter name for the current buffer */ + YY_BUFFER_STATE b = yy_current_buffer; + + int yy_c_buf_p_offset = + (int) (yy_c_buf_p - b->yy_ch_buf); + + if ( b->yy_is_our_buffer ) + { + int new_size = b->yy_buf_size * 2; + + if ( new_size <= 0 ) + b->yy_buf_size += b->yy_buf_size / 8; + else + b->yy_buf_size *= 2; + + b->yy_ch_buf = (char *) + /* Include room in for 2 EOB chars. */ + yy_flex_realloc( (void *) b->yy_ch_buf, + b->yy_buf_size + 2 ); + } + else + /* Can't grow it, we don't own it. */ + b->yy_ch_buf = 0; + + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( + "fatal error - scanner input buffer overflow" ); + + yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset]; + + num_to_read = yy_current_buffer->yy_buf_size - + number_to_move - 1; +#endif + } + + if ( num_to_read > YY_READ_BUF_SIZE ) + num_to_read = YY_READ_BUF_SIZE; + + /* Read in more data. */ + YY_INPUT( (&yy_current_buffer->yy_ch_buf[number_to_move]), + yy_n_chars, num_to_read ); + + yy_current_buffer->yy_n_chars = yy_n_chars; + } + + if ( yy_n_chars == 0 ) + { + if ( number_to_move == YY_MORE_ADJ ) + { + ret_val = EOB_ACT_END_OF_FILE; + yyrestart( yyin ); + } + + else + { + ret_val = EOB_ACT_LAST_MATCH; + yy_current_buffer->yy_buffer_status = + YY_BUFFER_EOF_PENDING; + } + } + + else + ret_val = EOB_ACT_CONTINUE_SCAN; + + yy_n_chars += number_to_move; + yy_current_buffer->yy_ch_buf[yy_n_chars] = YY_END_OF_BUFFER_CHAR; + yy_current_buffer->yy_ch_buf[yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR; + + yytext_ptr = &yy_current_buffer->yy_ch_buf[0]; + + return ret_val; + } + + +/* yy_get_previous_state - get the state just before the EOB char was reached */ + +static yy_state_type yy_get_previous_state() + { + register yy_state_type yy_current_state; + register char *yy_cp; + + yy_current_state = yy_start; + yy_current_state += YY_AT_BOL(); + yy_state_ptr = yy_state_buf; + *yy_state_ptr++ = yy_current_state; + + for ( yy_cp = yytext_ptr + YY_MORE_ADJ; yy_cp < yy_c_buf_p; ++yy_cp ) + { + register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 711 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + *yy_state_ptr++ = yy_current_state; + } + + return yy_current_state; + } + + +/* yy_try_NUL_trans - try to make a transition on the NUL character + * + * synopsis + * next_state = yy_try_NUL_trans( current_state ); + */ + +#ifdef YY_USE_PROTOS +static yy_state_type yy_try_NUL_trans( yy_state_type yy_current_state ) +#else +static yy_state_type yy_try_NUL_trans( yy_current_state ) +yy_state_type yy_current_state; +#endif + { + register int yy_is_jam; + + register YY_CHAR yy_c = 1; + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 711 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + yy_is_jam = (yy_current_state == 710); + if ( ! yy_is_jam ) + *yy_state_ptr++ = yy_current_state; + + return yy_is_jam ? 0 : yy_current_state; + } + + +#ifndef YY_NO_UNPUT +#ifdef YY_USE_PROTOS +static void yyunput( int c, register char *yy_bp ) +#else +static void yyunput( c, yy_bp ) +int c; +register char *yy_bp; +#endif + { + register char *yy_cp = yy_c_buf_p; + + /* undo effects of setting up yytext */ + *yy_cp = yy_hold_char; + + if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 ) + { /* need to shift things up to make room */ + /* +2 for EOB chars. */ + register int number_to_move = yy_n_chars + 2; + register char *dest = &yy_current_buffer->yy_ch_buf[ + yy_current_buffer->yy_buf_size + 2]; + register char *source = + &yy_current_buffer->yy_ch_buf[number_to_move]; + + while ( source > yy_current_buffer->yy_ch_buf ) + *--dest = *--source; + + yy_cp += (int) (dest - source); + yy_bp += (int) (dest - source); + yy_current_buffer->yy_n_chars = + yy_n_chars = yy_current_buffer->yy_buf_size; + + if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 ) + YY_FATAL_ERROR( "flex scanner push-back overflow" ); + } + + *--yy_cp = (char) c; + + + yytext_ptr = yy_bp; + yy_hold_char = *yy_cp; + yy_c_buf_p = yy_cp; + } +#endif /* ifndef YY_NO_UNPUT */ + + +#ifdef __cplusplus +static int yyinput() +#else +static int input() +#endif + { + int c; + + *yy_c_buf_p = yy_hold_char; + + if ( *yy_c_buf_p == YY_END_OF_BUFFER_CHAR ) + { + /* yy_c_buf_p now points to the character we want to return. + * If this occurs *before* the EOB characters, then it's a + * valid NUL; if not, then we've hit the end of the buffer. + */ + if ( yy_c_buf_p < &yy_current_buffer->yy_ch_buf[yy_n_chars] ) + /* This was really a NUL. */ + *yy_c_buf_p = '\0'; + + else + { /* need more input */ + int offset = yy_c_buf_p - yytext_ptr; + ++yy_c_buf_p; + + switch ( yy_get_next_buffer() ) + { + case EOB_ACT_LAST_MATCH: + /* This happens because yy_g_n_b() + * sees that we've accumulated a + * token and flags that we need to + * try matching the token before + * proceeding. But for input(), + * there's no matching to consider. + * So convert the EOB_ACT_LAST_MATCH + * to EOB_ACT_END_OF_FILE. + */ + + /* Reset buffer status. */ + yyrestart( yyin ); + + /* fall through */ + + case EOB_ACT_END_OF_FILE: + { + if ( yywrap() ) + return EOF; + + if ( ! yy_did_buffer_switch_on_eof ) + YY_NEW_FILE; +#ifdef __cplusplus + return yyinput(); +#else + return input(); +#endif + } + + case EOB_ACT_CONTINUE_SCAN: + yy_c_buf_p = yytext_ptr + offset; + break; + } + } + } + + c = *(unsigned char *) yy_c_buf_p; /* cast for 8-bit char's */ + *yy_c_buf_p = '\0'; /* preserve yytext */ + yy_hold_char = *++yy_c_buf_p; + + yy_current_buffer->yy_at_bol = (c == '\n'); + + return c; + } + + +#ifdef YY_USE_PROTOS +void yyrestart( FILE *input_file ) +#else +void yyrestart( input_file ) +FILE *input_file; +#endif + { + if ( ! yy_current_buffer ) + yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); + + yy_init_buffer( yy_current_buffer, input_file ); + yy_load_buffer_state(); + } + + +#ifdef YY_USE_PROTOS +void yy_switch_to_buffer( YY_BUFFER_STATE new_buffer ) +#else +void yy_switch_to_buffer( new_buffer ) +YY_BUFFER_STATE new_buffer; +#endif + { + if ( yy_current_buffer == new_buffer ) + return; + + if ( yy_current_buffer ) + { + /* Flush out information for old buffer. */ + *yy_c_buf_p = yy_hold_char; + yy_current_buffer->yy_buf_pos = yy_c_buf_p; + yy_current_buffer->yy_n_chars = yy_n_chars; + } + + yy_current_buffer = new_buffer; + yy_load_buffer_state(); + + /* We don't actually know whether we did this switch during + * EOF (yywrap()) processing, but the only time this flag + * is looked at is after yywrap() is called, so it's safe + * to go ahead and always set it. + */ + yy_did_buffer_switch_on_eof = 1; + } + + +#ifdef YY_USE_PROTOS +void yy_load_buffer_state( void ) +#else +void yy_load_buffer_state() +#endif + { + yy_n_chars = yy_current_buffer->yy_n_chars; + yytext_ptr = yy_c_buf_p = yy_current_buffer->yy_buf_pos; + yyin = yy_current_buffer->yy_input_file; + yy_hold_char = *yy_c_buf_p; + } + + +#ifdef YY_USE_PROTOS +YY_BUFFER_STATE yy_create_buffer( FILE *file, int size ) +#else +YY_BUFFER_STATE yy_create_buffer( file, size ) +FILE *file; +int size; +#endif + { + YY_BUFFER_STATE b; + + b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + + b->yy_buf_size = size; + + /* yy_ch_buf has to be 2 characters longer than the size given because + * we need to put in 2 end-of-buffer characters. + */ + b->yy_ch_buf = (char *) yy_flex_alloc( b->yy_buf_size + 2 ); + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + + b->yy_is_our_buffer = 1; + + yy_init_buffer( b, file ); + + return b; + } + + +#ifdef YY_USE_PROTOS +void yy_delete_buffer( YY_BUFFER_STATE b ) +#else +void yy_delete_buffer( b ) +YY_BUFFER_STATE b; +#endif + { + if ( ! b ) + return; + + if ( b == yy_current_buffer ) + yy_current_buffer = (YY_BUFFER_STATE) 0; + + if ( b->yy_is_our_buffer ) + yy_flex_free( (void *) b->yy_ch_buf ); + + yy_flex_free( (void *) b ); + } + + +#ifndef YY_ALWAYS_INTERACTIVE +#ifndef YY_NEVER_INTERACTIVE +extern int isatty YY_PROTO(( int )); +#endif +#endif + +#ifdef YY_USE_PROTOS +void yy_init_buffer( YY_BUFFER_STATE b, FILE *file ) +#else +void yy_init_buffer( b, file ) +YY_BUFFER_STATE b; +FILE *file; +#endif + + + { + yy_flush_buffer( b ); + + b->yy_input_file = file; + b->yy_fill_buffer = 1; + +#if YY_ALWAYS_INTERACTIVE + b->yy_is_interactive = 1; +#else +#if YY_NEVER_INTERACTIVE + b->yy_is_interactive = 0; +#else + b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0; +#endif +#endif + } + + +#ifdef YY_USE_PROTOS +void yy_flush_buffer( YY_BUFFER_STATE b ) +#else +void yy_flush_buffer( b ) +YY_BUFFER_STATE b; +#endif + + { + if ( ! b ) + return; + + b->yy_n_chars = 0; + + /* We always need two end-of-buffer characters. The first causes + * a transition to the end-of-buffer state. The second causes + * a jam in that state. + */ + b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; + b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; + + b->yy_buf_pos = &b->yy_ch_buf[0]; + + b->yy_at_bol = 1; + b->yy_buffer_status = YY_BUFFER_NEW; + + if ( b == yy_current_buffer ) + yy_load_buffer_state(); + } + + +#ifndef YY_NO_SCAN_BUFFER +#ifdef YY_USE_PROTOS +YY_BUFFER_STATE yy_scan_buffer( char *base, yy_size_t size ) +#else +YY_BUFFER_STATE yy_scan_buffer( base, size ) +char *base; +yy_size_t size; +#endif + { + YY_BUFFER_STATE b; + + if ( size < 2 || + base[size-2] != YY_END_OF_BUFFER_CHAR || + base[size-1] != YY_END_OF_BUFFER_CHAR ) + /* They forgot to leave room for the EOB's. */ + return 0; + + b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" ); + + b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */ + b->yy_buf_pos = b->yy_ch_buf = base; + b->yy_is_our_buffer = 0; + b->yy_input_file = 0; + b->yy_n_chars = b->yy_buf_size; + b->yy_is_interactive = 0; + b->yy_at_bol = 1; + b->yy_fill_buffer = 0; + b->yy_buffer_status = YY_BUFFER_NEW; + + yy_switch_to_buffer( b ); + + return b; + } +#endif + + +#ifndef YY_NO_SCAN_STRING +#ifdef YY_USE_PROTOS +YY_BUFFER_STATE yy_scan_string( yyconst char *yy_str ) +#else +YY_BUFFER_STATE yy_scan_string( yy_str ) +yyconst char *yy_str; +#endif + { + int len; + for ( len = 0; yy_str[len]; ++len ) + ; + + return yy_scan_bytes( yy_str, len ); + } +#endif + + +#ifndef YY_NO_SCAN_BYTES +#ifdef YY_USE_PROTOS +YY_BUFFER_STATE yy_scan_bytes( yyconst char *bytes, int len ) +#else +YY_BUFFER_STATE yy_scan_bytes( bytes, len ) +yyconst char *bytes; +int len; +#endif + { + YY_BUFFER_STATE b; + char *buf; + yy_size_t n; + int i; + + /* Get memory for full buffer, including space for trailing EOB's. */ + n = len + 2; + buf = (char *) yy_flex_alloc( n ); + if ( ! buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" ); + + for ( i = 0; i < len; ++i ) + buf[i] = bytes[i]; + + buf[len] = buf[len+1] = YY_END_OF_BUFFER_CHAR; + + b = yy_scan_buffer( buf, n ); + if ( ! b ) + YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" ); + + /* It's okay to grow etc. this buffer, and we should throw it + * away when we're done. + */ + b->yy_is_our_buffer = 1; + + return b; + } +#endif + + +#ifndef YY_NO_PUSH_STATE +#ifdef YY_USE_PROTOS +static void yy_push_state( int new_state ) +#else +static void yy_push_state( new_state ) +int new_state; +#endif + { + if ( yy_start_stack_ptr >= yy_start_stack_depth ) + { + yy_size_t new_size; + + yy_start_stack_depth += YY_START_STACK_INCR; + new_size = yy_start_stack_depth * sizeof( int ); + + if ( ! yy_start_stack ) + yy_start_stack = (int *) yy_flex_alloc( new_size ); + + else + yy_start_stack = (int *) yy_flex_realloc( + (void *) yy_start_stack, new_size ); + + if ( ! yy_start_stack ) + YY_FATAL_ERROR( + "out of memory expanding start-condition stack" ); + } + + yy_start_stack[yy_start_stack_ptr++] = YY_START; + + BEGIN(new_state); + } +#endif + + +#ifndef YY_NO_POP_STATE +static void yy_pop_state() + { + if ( --yy_start_stack_ptr < 0 ) + YY_FATAL_ERROR( "start-condition stack underflow" ); + + BEGIN(yy_start_stack[yy_start_stack_ptr]); + } +#endif + + +#ifndef YY_NO_TOP_STATE +static int yy_top_state() + { + return yy_start_stack[yy_start_stack_ptr - 1]; + } +#endif + +#ifndef YY_EXIT_FAILURE +#define YY_EXIT_FAILURE 2 +#endif + +#ifdef YY_USE_PROTOS +static void yy_fatal_error( yyconst char msg[] ) +#else +static void yy_fatal_error( msg ) +char msg[]; +#endif + { + (void) fprintf( stderr, "%s\n", msg ); + exit( YY_EXIT_FAILURE ); + } + + + +/* Redefine yyless() so it works in section 3 code. */ + +#undef yyless +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + yytext[yyleng] = yy_hold_char; \ + yy_c_buf_p = yytext + n; \ + yy_hold_char = *yy_c_buf_p; \ + *yy_c_buf_p = '\0'; \ + yyleng = n; \ + } \ + while ( 0 ) + + +/* Internal utility routines. */ + +#ifndef yytext_ptr +#ifdef YY_USE_PROTOS +static void yy_flex_strncpy( char *s1, yyconst char *s2, int n ) +#else +static void yy_flex_strncpy( s1, s2, n ) +char *s1; +yyconst char *s2; +int n; +#endif + { + register int i; + for ( i = 0; i < n; ++i ) + s1[i] = s2[i]; + } +#endif + +#ifdef YY_NEED_STRLEN +#ifdef YY_USE_PROTOS +static int yy_flex_strlen( yyconst char *s ) +#else +static int yy_flex_strlen( s ) +yyconst char *s; +#endif + { + register int n; + for ( n = 0; s[n]; ++n ) + ; + + return n; + } +#endif + + +#ifdef YY_USE_PROTOS +static void *yy_flex_alloc( yy_size_t size ) +#else +static void *yy_flex_alloc( size ) +yy_size_t size; +#endif + { + return (void *) malloc( size ); + } + +#ifdef YY_USE_PROTOS +static void *yy_flex_realloc( void *ptr, yy_size_t size ) +#else +static void *yy_flex_realloc( ptr, size ) +void *ptr; +yy_size_t size; +#endif + { + /* The cast to (char *) in the following accommodates both + * implementations that use char* generic pointers, and those + * that use void* generic pointers. It works with the latter + * because both ANSI C and C++ allow castless assignment from + * any pointer type to void*, and deal with argument conversions + * as though doing an assignment. + */ + return (void *) realloc( (char *) ptr, size ); + } + +#ifdef YY_USE_PROTOS +static void yy_flex_free( void *ptr ) +#else +static void yy_flex_free( ptr ) +void *ptr; +#endif + { + free( ptr ); + } + +#if YY_MAIN +int main() + { + yylex(); + return 0; + } +#endif + + + +static char *StringToLex; + +#ifndef FLEX_SCANNER +static FILE *lexFP; + +static int input() +{ + int ret; + + if (StringToLex != NULL) { + ret = *StringToLex; + if (ret == NULLCHAR) + ret = EOF; + else + StringToLex++; + } else if (unputCount > 0) { + ret = unputBuffer[--unputCount]; + } else { + ret = fgetc(lexFP); + } + + if (ret == EOF) + return 0; + else + return ret; +} + +/* + * Return offset of next pattern within current file + */ +int yyoffset() +{ + int offset = ftell(lexFP) - unputCount; + + if (offset < 0) { + offset = 0; + } + return(offset); +} + +static void output(ch) + int ch; +{ + fprintf(stderr, "PARSER BUG: unmatched character '%c' (0%o)\n", + ch, ch); +} + +static void unput(ch) + int ch; +{ + if (ch == 0) return; + if (StringToLex != NULL) { + StringToLex--; + } else { + if (unputCount >= UNPUT_BUF_SIZE) + fprintf(stderr, "PARSER BUG: unput buffer overflow '%c' (0%o)\n", + ch, ch); + unputBuffer[unputCount++] = ch; + } +} + +/* Get ready to lex from a new file. Kludge below sticks + an artificial newline at the front of the file, which the + above grammar ignores, but which makes ^ at start of pattern + match at the real start of the file. +*/ +void yynewfile(f) + FILE *f; +{ + lexFP = f; + StringToLex = NULL; + unputCount = 0; + unput('\n'); /* kludge */ +} + +/* Get ready to lex from a string. ^ at start of pattern WON'T + match at the start of the string! +*/ +void yynewstr(s) + char *s; +{ + lexFP = NULL; + StringToLex = s; + unputCount = 0; +} +#endif /*!FLEX_SCANNER*/ + +#ifdef FLEX_SCANNER +void my_yy_input(buf, result, max_size) + char *buf; + int *result; + int max_size; +{ + int count; + + if (StringToLex != NULL) { + count = 0; + while (*StringToLex != NULLCHAR) { + *buf++ = *StringToLex++; + count++; + } + *result = count; + return; + } else { + count = fread(buf, 1, max_size, yyin); + if (count == 0) { + *result = YY_NULL; + } else { + *result = count; + } + return; + } +} + +static YY_BUFFER_STATE my_file_buffer = NULL; + +/* + Return offset of next pattern in the current file. +*/ +int yyoffset() +{ + int pos = yy_c_buf_p - yy_current_buffer->yy_ch_buf; + + return(ftell(yy_current_buffer->yy_input_file) - + yy_n_chars + pos); +} + + +void yynewstr(s) + char *s; +{ + if (my_file_buffer != NULL) + yy_delete_buffer(my_file_buffer); + StringToLex = s; + my_file_buffer = yy_create_buffer(stdin, YY_BUF_SIZE); + yy_switch_to_buffer(my_file_buffer); +} + +void yynewfile(f) + FILE *f; +{ + if (my_file_buffer != NULL) + yy_delete_buffer(my_file_buffer); + StringToLex = NULL; + my_file_buffer = yy_create_buffer(f, YY_BUF_SIZE); + yy_switch_to_buffer(my_file_buffer); +} +#endif /*FLEX_SCANNER*/ + +int yywrap() +{ + return TRUE; +} + +/* Parse a move from the given string s */ +/* ^ at start of pattern WON'T work here unless using flex */ +ChessMove yylexstr(boardIndex, s) + int boardIndex; + char *s; +{ + ChessMove ret; + char *oldStringToLex; +#ifdef FLEX_SCANNER + YY_BUFFER_STATE buffer, oldBuffer; +#endif + + yyboardindex = boardIndex; + oldStringToLex = StringToLex; + StringToLex = s; +#ifdef FLEX_SCANNER + buffer = yy_create_buffer(stdin, YY_BUF_SIZE); + oldBuffer = YY_CURRENT_BUFFER; + yy_switch_to_buffer(buffer); +#endif /*FLEX_SCANNER*/ + + ret = (ChessMove) yylex(); + +#ifdef FLEX_SCANNER + if (oldBuffer != NULL) + yy_switch_to_buffer(oldBuffer); + yy_delete_buffer(buffer); +#endif /*FLEX_SCANNER*/ + StringToLex = oldStringToLex; + + return ret; +} diff --git a/winboard-dm-beta4/parser.h b/winboard-dm-beta4/parser.h new file mode 100755 index 00000000..dfc257a4 --- /dev/null +++ b/winboard-dm-beta4/parser.h @@ -0,0 +1,59 @@ +/* + * parser.h -- Interface to XBoard move parser + * $Id$ + * + * Copyright 1991 by Digital Equipment Corporation, Maynard, Massachusetts. + * Enhancements Copyright 1992-95 Free Software Foundation, Inc. + * + * The following terms apply to Digital Equipment Corporation's copyright + * interest in XBoard: + * ------------------------------------------------------------------------ + * All Rights Reserved + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appear in all copies and that + * both that copyright notice and this permission notice appear in + * supporting documentation, and that the name of Digital not be + * used in advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. + * + * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING + * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL + * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR + * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, + * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + * ------------------------------------------------------------------------ + * + * The following terms apply to the enhanced version of XBoard distributed + * by the Free Software Foundation: + * ------------------------------------------------------------------------ + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * ------------------------------------------------------------------------ + */ + +extern void yynewfile P((FILE *f)); +extern void yynewstr P((char *s)); +extern int yylex P((void)); +extern ChessMove yylexstr P((int boardIndex, char *s)); +extern char currentMoveString[]; +extern int yyboardindex; +extern int yyskipmoves; /* If TRUE, all moves are reported as AmbiguousMove + instead of being disambiguated. */ +extern char *yy_text; /* Needed because yytext can be either a char[] + or a (non-constant) char* */ +extern int yyoffset P((void)); diff --git a/winboard-dm-beta4/pgntags.c b/winboard-dm-beta4/pgntags.c new file mode 100755 index 00000000..8a1f6b5d --- /dev/null +++ b/winboard-dm-beta4/pgntags.c @@ -0,0 +1,262 @@ +/* + * pgntags.c -- Functions to manage PGN tags + * XBoard $Id$ + * + * Copyright 1995 Free Software Foundation, Inc. + * + * ------------------------------------------------------------------------ + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA. + * ------------------------------------------------------------------------ + * + * This file could well be a part of backend.c, but I prefer it this + * way. + */ + +#include "config.h" + +#include +#include +#include +#if STDC_HEADERS +# include +# include +#else /* not STDC_HEADERS */ +# if HAVE_STRING_H +# include +# else /* not HAVE_STRING_H */ +# include +# endif /* not HAVE_STRING_H */ +#endif /* not STDC_HEADERS */ + +#include "common.h" +#include "frontend.h" +#include "backend.h" +#include "parser.h" + +static char *PGNTagsStatic P((GameInfo *)); + + + +/* Parse PGN tags; returns 0 for success or error number + */ +int ParsePGNTag(tag, gameInfo) + char *tag; + GameInfo *gameInfo; +{ + char *name, *value, *p, *oldTags; + int len; + int success; + + name = tag; + while (!isalpha(*name) && !isdigit(*name)) { + name++; + } + p = name; + while (*p != ' ' && *p != '\t' && *p != '\n') { + p++; + } + *p = NULLCHAR; + value = strchr(p + 1, '"') + 1; + p = strrchr(value, '"'); + *p = NULLCHAR; + + if (StrCaseCmp(name, "Event") == 0) { + success = StrSavePtr(value, &gameInfo->event) != NULL; + } else if (StrCaseCmp(name, "Site") == 0) { + success = StrSavePtr(value, &gameInfo->site) != NULL; + } else if (StrCaseCmp(name, "Date") == 0) { + success = StrSavePtr(value, &gameInfo->date) != NULL; + } else if (StrCaseCmp(name, "Round") == 0) { + success = StrSavePtr(value, &gameInfo->round) != NULL; + } else if (StrCaseCmp(name, "White") == 0) { + success = StrSavePtr(value, &gameInfo->white) != NULL; + } else if (StrCaseCmp(name, "Black") == 0) { + success = StrSavePtr(value, &gameInfo->black) != NULL; + } + /* Fold together the various ways of denoting White/Black rating */ + else if ((StrCaseCmp(name, "WhiteElo")==0) || + (StrCaseCmp(name, "WhiteUSCF")==0) ) { + success = TRUE; + gameInfo->whiteRating = atoi( value ); + } else if ((StrCaseCmp(name, "BlackElo")==0) || + (StrCaseCmp(name, "BlackUSCF")==0)) { + success = TRUE; + gameInfo->blackRating = atoi( value ); + } + else if (StrCaseCmp(name, "Result") == 0) { + if (strcmp(value, "1-0") == 0) + gameInfo->result = WhiteWins; + else if (strcmp(value, "0-1") == 0) + gameInfo->result = BlackWins; + else if (strcmp(value, "1/2-1/2") == 0) + gameInfo->result = GameIsDrawn; + else + gameInfo->result = GameUnfinished; + success = TRUE; + } else if (StrCaseCmp(name, "FEN") == 0) { + success = StrSavePtr(value, &gameInfo->fen) != NULL; + } else if (StrCaseCmp(name, "SetUp") == 0) { + /* ignore on input; presence of FEN governs */ + success = TRUE; + } else if (StrCaseCmp(name, "Variant") == 0) { + /* xboard-defined extension */ + gameInfo->variant = StringToVariant(value); + success = TRUE; + } else { + if (gameInfo->extraTags == NULL) { + oldTags = ""; + } else { + oldTags = gameInfo->extraTags; + } + /* Buffer size includes 7 bytes of space for [ ""]\n\0 */ + len = strlen(oldTags) + strlen(value) + strlen(name) + 7; + if ((p = (char *) malloc(len)) != NULL) { + sprintf(p, "%s[%s \"%s\"]\n", oldTags, name, value); + if (gameInfo->extraTags != NULL) free(gameInfo->extraTags); + gameInfo->extraTags = p; + success = TRUE; + } else { + success = FALSE; + } + } + return(success ? 0 : ENOMEM); +} + + + +/* Return a static buffer with a game's data. + */ +static char *PGNTagsStatic(gameInfo) + GameInfo *gameInfo; +{ + static char buf[8192]; + char buf1[MSG_SIZ]; + + buf[0] = NULLCHAR; + + sprintf(buf1, "[Event \"%s\"]\n", + gameInfo->event ? gameInfo->event : "?"); + strcat(buf, buf1); + sprintf(buf1, "[Site \"%s\"]\n", + gameInfo->site ? gameInfo->site : "?"); + strcat(buf, buf1); + sprintf(buf1, "[Date \"%s\"]\n", + gameInfo->date ? gameInfo->date : "?"); + strcat(buf, buf1); + sprintf(buf1, "[Round \"%s\"]\n", + gameInfo->round ? gameInfo->round : "-"); + strcat(buf, buf1); + sprintf(buf1, "[White \"%s\"]\n", + gameInfo->white ? gameInfo->white : "?"); + strcat(buf, buf1); + sprintf(buf1, "[Black \"%s\"]\n", + gameInfo->black ? gameInfo->black : "?"); + strcat(buf, buf1); + sprintf(buf1, "[Result \"%s\"]\n", PGNResult(gameInfo->result)); + strcat(buf, buf1); + + if (gameInfo->whiteRating >= 0 ) { + sprintf(buf1, "[WhiteElo \"%d\"]\n", gameInfo->whiteRating ); + strcat(buf, buf1); + } + if ( gameInfo->blackRating >= 0 ) { + sprintf(buf1, "[BlackElo \"%d\"]\n", gameInfo->blackRating ); + strcat(buf, buf1); + } + if (gameInfo->timeControl != NULL) { + sprintf(buf1, "[TimeControl \"%s\"]\n", gameInfo->timeControl); + strcat(buf, buf1); + } + if (gameInfo->variant != VariantNormal) { + sprintf(buf1, "[Variant \"%s\"]\n", VariantName(gameInfo->variant)); + strcat(buf, buf1); + } + if (gameInfo->extraTags != NULL) { + strcat(buf, gameInfo->extraTags); + } + return buf; +} + + + +/* Print game info + */ +void PrintPGNTags(fp, gameInfo) + FILE *fp; + GameInfo *gameInfo; +{ + fprintf(fp, "%s", PGNTagsStatic(gameInfo)); +} + + +/* Return a non-static buffer with a games info. + */ +char *PGNTags(gameInfo) + GameInfo *gameInfo; +{ + return StrSave(PGNTagsStatic(gameInfo)); +} + + +/* Returns pointer to a static string with a result. + */ +char *PGNResult(result) + ChessMove result; +{ + switch (result) { + case GameUnfinished: + default: + return "*"; + case WhiteWins: + return "1-0"; + case BlackWins: + return "0-1"; + case GameIsDrawn: + return "1/2-1/2"; + } +} + +/* Returns 0 for success, nonzero for error */ +int +ReplaceTags(tags, gameInfo) + char *tags; + GameInfo *gameInfo; +{ + ChessMove moveType; + int err; + + ClearGameInfo(gameInfo); + yynewstr(tags); + for (;;) { + yyboardindex = 0; + moveType = (ChessMove) yylex(); + if (moveType == (ChessMove) 0) { + break; + } else if (moveType == PGNTag) { + err = ParsePGNTag(yy_text, gameInfo); + if (err != 0) return err; + } + } + /* just one problem...if there is a result in the new tags, + * DisplayMove() won't ever show it because ClearGameInfo() set + * gameInfo->resultDetails to NULL. So we must plug something in if there + * is a result. + */ + if (gameInfo->result != GameUnfinished) { + if (gameInfo->resultDetails) free(gameInfo->resultDetails); + gameInfo->resultDetails = strdup(""); + } + return 0; +} diff --git a/winboard-dm-beta4/wclipbrd.c b/winboard-dm-beta4/wclipbrd.c new file mode 100755 index 00000000..85e91f9a --- /dev/null +++ b/winboard-dm-beta4/wclipbrd.c @@ -0,0 +1,320 @@ +/* + * wclipbrd.c -- Clipboard routines for WinBoard + * $Id$ + * + * Copyright 2000 Free Software Foundation, Inc. + * + * ------------------------------------------------------------------------ + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * ------------------------------------------------------------------------ + */ + +#include "config.h" + +#include /* required for all Windows applications */ +#include +#include +#include +#include +#include + +#include "common.h" +#include "winboard.h" +#include "frontend.h" +#include "backend.h" +#include "wclipbrd.h" + +/* Imports from winboard.c */ +extern HWND hwndMain; + +/* File globals */ +static char *copyTemp; +static char *pasteTemp; + +VOID +CopyFENToClipboard() +{ + char *fen = NULL; + + fen = PositionToFEN(currentMove); + if (!fen) { + DisplayError("Unable to convert position to FEN.", 0); + return; + } + if (!CopyTextToClipboard(fen)) + DisplayError("Unable to copy FEN to clipboard.", 0); + free(fen); +} + + +VOID +CopyGameToClipboard() +{ + /* A rather cheesy hack here. Write the game to a file, then read from the + * file into the clipboard. + */ + char *buf = NULL; + FILE *f; + unsigned long size; + size_t len; + struct stat st; + + if (!copyTemp) { + copyTemp = tmpnam(NULL); + } + if (!copyTemp) { + DisplayError("Cannot create temporary file name.",0); + return; + } + f = fopen(copyTemp, "w"); + if (!f) { + DisplayError("Cannot open temporary file.", 0); + return; + } + if (!SaveGame(f,0,"")) { /* call into backend */ + DisplayError("Cannot write to temporary file.", 0); + goto copy_game_to_clipboard_cleanup; + } + f = fopen(copyTemp, "rb"); + if (!f) { + DisplayError("Cannot reopen temporary file.", 0); + goto copy_game_to_clipboard_cleanup; + } + if (fstat(fileno(f), &st) < 0) { + DisplayError("Cannot determine size of file.", 0); + goto copy_game_to_clipboard_cleanup; + } + size = st.st_size; + if (size == -1) { + DisplayError("Cannot determine size of file.", 0); + goto copy_game_to_clipboard_cleanup; + } + rewind(f); + buf = (char*)malloc(size+1); + if (!buf) { + DisplayError("Cannot allocate clipboard buffer.", 0); + goto copy_game_to_clipboard_cleanup; + } + len = fread(buf, sizeof(char), size, f); + if (len == -1) { + DisplayError("Cannot read from temporary file.", 0); + goto copy_game_to_clipboard_cleanup; + } + if ((unsigned long)size != (unsigned long)len) { /* sigh */ + DisplayError("Error reading from temporary file.", 0); + goto copy_game_to_clipboard_cleanup; + } + buf[size] = 0; + if (!CopyTextToClipboard(buf)) { + DisplayError("Cannot copy text to clipboard", 0); + } + +copy_game_to_clipboard_cleanup: + if (buf) free(buf); + if (f) fclose(f); +} + + +int +CopyTextToClipboard(char *text) +{ + /* some (most?) of the error checking may be overkill, + * but hey, this is Windows + */ + HGLOBAL hGlobalMem; + LPVOID lpGlobalMem; + BOOL locked; + UINT lockCount; + DWORD err; + + hGlobalMem = GlobalAlloc(GHND, (DWORD)lstrlen(text)+1); + if (hGlobalMem == NULL) { + DisplayError("Unable to allocate memory for clipboard.", 0); + return FALSE; + } + lpGlobalMem = GlobalLock(hGlobalMem); + if (lpGlobalMem == NULL) { + DisplayError("Unable to lock clipboard memory.", 0); + GlobalFree(hGlobalMem); + return FALSE; + } + lstrcpy(lpGlobalMem, text); + if (appData.debugMode) { + lockCount = GlobalFlags(hGlobalMem) & GMEM_LOCKCOUNT; + fprintf(debugFP, "CopyTextToClipboard(): lock count %d\n", lockCount); + } + SetLastError(NO_ERROR); + locked = GlobalUnlock(hGlobalMem); + err = GetLastError(); + if (appData.debugMode) { + lockCount = GlobalFlags(hGlobalMem) & GMEM_LOCKCOUNT; + fprintf(debugFP, "CopyTextToClipboard(): lock count %d\n", lockCount); + } + if (!locked) { + locked = !((err == NO_ERROR) || (err == ERROR_NOT_LOCKED)); + if (appData.debugMode) { + fprintf(debugFP, + "CopyTextToClipboard(): err %d locked %d\n", err, locked); + } + } + if (locked) { + DisplayError("Cannot unlock clipboard memory.", 0); + GlobalFree(hGlobalMem); + return FALSE; + } + if (!OpenClipboard(hwndMain)) { + DisplayError("Cannot open clipboard.", 0); + GlobalFree(hGlobalMem); + return FALSE; + } + if (!EmptyClipboard()) { + DisplayError("Cannot empty clipboard.", 0); + return FALSE; + } + if (hGlobalMem != SetClipboardData(CF_TEXT, hGlobalMem)) { + DisplayError("Cannot copy text to clipboard.", 0); + CloseClipboard(); + GlobalFree(hGlobalMem); + return FALSE; + } + if (!CloseClipboard()) + DisplayError("Cannot close clipboard.", 0); + + return TRUE; +} + + + +VOID +PasteFENFromClipboard() +{ + char *fen = NULL; + if (!PasteTextFromClipboard(&fen)) { + DisplayError("Unable to paste FEN from clipboard.", 0); + return; + } + if (appData.debugMode) { + fprintf(debugFP, "PasteFenFromClipboard(): fen '%s'\n", fen); + } + EditPositionPasteFEN(fen); /* call into backend */ + free(fen); +} + + +VOID +PasteGameFromClipboard() +{ + /* Write the clipboard to a temp file, then let LoadGameFromFile() + * do all the work. */ + char *buf; + FILE *f; + size_t len; + if (!PasteTextFromClipboard(&buf)) { + return; + } + if (!pasteTemp) { + pasteTemp = tmpnam(NULL); + } + f = fopen(pasteTemp, "wb+"); + if (!f) { + DisplayError("Unable to create temporary file.", 0); + return; + } + len = fwrite(buf, sizeof(char), strlen(buf), f); + fclose(f); + if (len != strlen(buf)) { + DisplayError("Error writing to temporary file.", 0); + return; + } + LoadGameFromFile(pasteTemp, 0, "Clipboard", TRUE); +} + + +int +PasteTextFromClipboard(char **text) +{ + /* some (most?) of the error checking may be overkill, + * but hey, this is Windows + */ + HANDLE hClipMem; + LPVOID lpClipMem; + BOOL locked = FALSE; + DWORD err; + UINT lockCount; + + if (!OpenClipboard(hwndMain)) { + DisplayError("Unable to open clipboard.", 0); + return FALSE; + } + hClipMem = GetClipboardData(CF_TEXT); + if (hClipMem == NULL) { + CloseClipboard(); + DisplayError("No text in clipboard.", 0); + return FALSE; + } + lpClipMem = GlobalLock(hClipMem); + if (lpClipMem == NULL) { + CloseClipboard(); + DisplayError("Unable to lock clipboard memory.", 0); + return FALSE; + } + *text = (char *) malloc(GlobalSize(hClipMem)+1); + if (!*text) { + DisplayError("Unable to allocate memory for text string.", 0); + CloseClipboard(); + return FALSE; + } + lstrcpy(*text, lpClipMem); + if (appData.debugMode) { + lockCount = GlobalFlags(hClipMem) & GMEM_LOCKCOUNT; + fprintf(debugFP, "PasteTextFromClipboard(): lock count %d\n", lockCount); + } + SetLastError(NO_ERROR); +#if 1 + /*suggested by Wilkin Ng*/ + lockCount = GlobalFlags(hClipMem) & GMEM_LOCKCOUNT; + if (lockCount) { + locked = GlobalUnlock(hClipMem); + } +#else + locked = GlobalUnlock(hClipMem); +#endif + err = GetLastError(); + if (appData.debugMode) { + lockCount = GlobalFlags(hClipMem) & GMEM_LOCKCOUNT; + fprintf(debugFP, "PasteTextFromClipboard(): lock count %d\n", lockCount); + } + if (!locked) { + locked = !((err == NO_ERROR) || (err == ERROR_NOT_LOCKED)); + if (appData.debugMode) { + fprintf(debugFP, + "PasteTextFromClipboard(): err %d locked %d\n", err, locked); + } + } + if (locked) + DisplayError("Unable to unlock clipboard memory.", 0); + + if (!CloseClipboard()) + DisplayError("Unable to close clipboard.", 0); + + return TRUE; +} + +VOID +DeleteClipboardTempFiles() +{ + if (copyTemp) remove(copyTemp); + if (pasteTemp) remove(pasteTemp); +} diff --git a/winboard-dm-beta4/wclipbrd.h b/winboard-dm-beta4/wclipbrd.h new file mode 100755 index 00000000..010166ea --- /dev/null +++ b/winboard-dm-beta4/wclipbrd.h @@ -0,0 +1,32 @@ +/* + * wclipbrd.c -- Clipboard routines for WinBoard + * $Id$ + * + * Copyright 2000 Free Software Foundation, Inc. + * + * ------------------------------------------------------------------------ + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * ------------------------------------------------------------------------ + */ + +VOID CopyFENToClipboard(); +VOID CopyGameToClipboard(); +int CopyTextToClipboard(char *text); + +VOID PasteFENFromClipboard(); +VOID PasteGameFromClipboard(); +int PasteTextFromClipboard(char **text); + +VOID DeleteClipboardTempFiles(); diff --git a/winboard-dm-beta4/wedittags.c b/winboard-dm-beta4/wedittags.c new file mode 100755 index 00000000..5730f6be --- /dev/null +++ b/winboard-dm-beta4/wedittags.c @@ -0,0 +1,234 @@ +/* + * wedittags.c -- EditTags window for WinBoard + * $Id$ + * + * Copyright 1995 Free Software Foundation, Inc. + * + * ------------------------------------------------------------------------ + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * ------------------------------------------------------------------------ + */ + +#include "config.h" + +#include /* required for all Windows applications */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "common.h" +#include "winboard.h" +#include "frontend.h" +#include "backend.h" + +/* Module globals */ +static char *editTagsText; +HWND editTagsDialog = NULL; +BOOL editTagsUp = FALSE; +BOOL canEditTags = FALSE; +int editTagsX, editTagsY, editTagsW, editTagsH; + +/* Imports from winboard.c */ +extern HINSTANCE hInst; +extern HWND hwndMain; +extern BoardSize boardSize; + +LRESULT CALLBACK +EditTagsDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + static HANDLE hwndText; + static int sizeX, sizeY; + int len, newSizeX, newSizeY, flags; + char *str; + RECT rect; + MINMAXINFO *mmi; + int err; + + switch (message) { + case WM_INITDIALOG: /* message: initialize dialog box */ + /* Initialize the dialog items */ + hwndText = GetDlgItem(hDlg, OPT_TagsText); + SendMessage(hwndText, WM_SETFONT, + (WPARAM)font[boardSize][EDITTAGS_FONT]->hf, MAKELPARAM(FALSE, 0)); + SetDlgItemText(hDlg, OPT_TagsText, editTagsText); + EnableWindow(GetDlgItem(hDlg, OPT_TagsCancel), canEditTags); + EnableWindow(GetDlgItem(hDlg, OPT_EditTags), !canEditTags); + SendMessage(hwndText, EM_SETREADONLY, !canEditTags, 0); + if (canEditTags) { + SetWindowText(hDlg, "Edit Tags"); + SetFocus(hwndText); + } else { + SetWindowText(hDlg, "Tags"); + SetFocus(GetDlgItem(hDlg, IDOK)); + } + if (!editTagsDialog) { + editTagsDialog = hDlg; + flags = SWP_NOZORDER; + GetClientRect(hDlg, &rect); + sizeX = rect.right; + sizeY = rect.bottom; + if (editTagsX != CW_USEDEFAULT && editTagsY != CW_USEDEFAULT && + editTagsW != CW_USEDEFAULT && editTagsH != CW_USEDEFAULT) { + WINDOWPLACEMENT wp; + EnsureOnScreen(&editTagsX, &editTagsY); + wp.length = sizeof(WINDOWPLACEMENT); + wp.flags = 0; + wp.showCmd = SW_SHOW; + wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0; + wp.rcNormalPosition.left = editTagsX; + wp.rcNormalPosition.right = editTagsX + editTagsW; + wp.rcNormalPosition.top = editTagsY; + wp.rcNormalPosition.bottom = editTagsY + editTagsH; + SetWindowPlacement(hDlg, &wp); + + GetClientRect(hDlg, &rect); + newSizeX = rect.right; + newSizeY = rect.bottom; + ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, + newSizeX, newSizeY); + sizeX = newSizeX; + sizeY = newSizeY; + } + } + return FALSE; + + case WM_COMMAND: + switch (LOWORD(wParam)) { + case IDOK: + if (canEditTags) { + char *p, *q; + /* Read changed options from the dialog box */ + len = GetWindowTextLength(hwndText); + str = (char *) malloc(len + 1); + GetWindowText(hwndText, str, len + 1); + p = q = str; + while (*q) { + if (*q == '\r'|| *q == '\n') + q++; + else + *p++ = *q++; + } + *p = NULLCHAR; + err = ReplaceTags(str, &gameInfo); + if (err) DisplayError("Error replacing tags.", err); + + free(str); + } + TagsPopDown(); + return TRUE; + + case IDCANCEL: + case OPT_TagsCancel: + TagsPopDown(); + return TRUE; + + case OPT_EditTags: + EditTagsEvent(); + return TRUE; + + default: + break; + } + break; + + case WM_SIZE: + newSizeX = LOWORD(lParam); + newSizeY = HIWORD(lParam); + ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY); + sizeX = newSizeX; + sizeY = newSizeY; + break; + + case WM_GETMINMAXINFO: + /* Prevent resizing window too small */ + mmi = (MINMAXINFO *) lParam; + mmi->ptMinTrackSize.x = 100; + mmi->ptMinTrackSize.y = 100; + break; + } + return FALSE; +} + +VOID TagsPopDown(void) +{ + if (editTagsDialog) ShowWindow(editTagsDialog, SW_HIDE); + CheckMenuItem(GetMenu(hwndMain), IDM_EditTags, MF_UNCHECKED); + editTagsUp = FALSE; +} + + +VOID EitherTagsPopUp(char *tags, char *msg, BOOLEAN edit) +{ + FARPROC lpProc; + char *p, *q; + + if (msg == NULL) msg = ""; + p = (char *) malloc(2 * (strlen(tags) + strlen(msg)) + 2); + q = p; + while (*tags) { + if (*tags == '\n') *q++ = '\r'; + *q++ = *tags++; + } + if (*msg != NULLCHAR) { + *q++ = '\r'; + *q++ = '\n'; + while (*msg) { + if (*msg == '\n') *q++ = '\r'; + *q++ = *msg++; + } + } + *q = NULLCHAR; + if (editTagsText != NULL) free(editTagsText); + editTagsText = p; + canEditTags = edit; + + CheckMenuItem(GetMenu(hwndMain), IDM_EditTags, MF_CHECKED); + if (editTagsDialog) { + SendMessage(editTagsDialog, WM_INITDIALOG, 0, 0); + ShowWindow(editTagsDialog, SW_SHOW); + } else { + lpProc = MakeProcInstance((FARPROC)EditTagsDialog, hInst); + CreateDialog(hInst, MAKEINTRESOURCE(DLG_EditTags), + hwndMain, (DLGPROC)lpProc); + FreeProcInstance(lpProc); + } + editTagsUp = TRUE; +} + +VOID TagsPopUp(char *tags, char *msg) +{ + HWND hwnd = GetActiveWindow(); + EitherTagsPopUp(tags, msg, FALSE); + SetActiveWindow(hwnd); +} + +VOID EditTagsPopUp(char *tags) +{ + EitherTagsPopUp(tags, "", TRUE); +} + +VOID EditTagsProc() +{ + if (editTagsUp) { + TagsPopDown(); + } else { + EditTagsEvent(); + } +} diff --git a/winboard-dm-beta4/wedittags.h b/winboard-dm-beta4/wedittags.h new file mode 100755 index 00000000..45e3359f --- /dev/null +++ b/winboard-dm-beta4/wedittags.h @@ -0,0 +1,27 @@ +/* + * wedittags.h -- EditTags window for WinBoard + * $Id$ + * + * Copyright 1995 Free Software Foundation, Inc. + * + * ------------------------------------------------------------------------ + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * ------------------------------------------------------------------------ + */ + +VOID EditTagsProc(void); +extern HWND editTagsDialog; +extern int editTagsX, editTagsY, editTagsW, editTagsH; + diff --git a/winboard-dm-beta4/wgamelist.c b/winboard-dm-beta4/wgamelist.c new file mode 100755 index 00000000..4abca99f --- /dev/null +++ b/winboard-dm-beta4/wgamelist.c @@ -0,0 +1,250 @@ +/* + * wgamelist.c -- Game list window for WinBoard + * $Id$ + * + * Copyright 1995 Free Software Foundation, Inc. + * + * ------------------------------------------------------------------------ + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * ------------------------------------------------------------------------ + */ + +#include "config.h" + +#include /* required for all Windows applications */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "common.h" +#include "winboard.h" +#include "frontend.h" +#include "backend.h" + +/* Module globals */ +HWND gameListDialog = NULL; +BOOLEAN gameListUp = FALSE; +FILE* gameFile; +char* gameFileName = NULL; +int gameListX, gameListY, gameListW, gameListH; + +/* Imports from winboard.c */ +extern HINSTANCE hInst; +extern HWND hwndMain; + + +LRESULT CALLBACK +GameListDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + static HANDLE hwndText; + int nItem; + ListGame *lg; + RECT rect; + static int sizeX, sizeY; + int newSizeX, newSizeY, flags; + MINMAXINFO *mmi; + + switch (message) { + case WM_INITDIALOG: + if (gameListDialog) { + SendDlgItemMessage(hDlg, OPT_GameListText, LB_RESETCONTENT, 0, 0); + } + /* Initialize the dialog items */ + hwndText = GetDlgItem(hDlg, OPT_TagsText); + lg = (ListGame *) gameList.head; + for (nItem = 0; nItem < ((ListGame *) gameList.tailPred)->number; nItem++){ + char *st = GameListLine(lg->number, &lg->gameInfo); + SendDlgItemMessage(hDlg, OPT_GameListText, LB_ADDSTRING, 0, (LPARAM) st); + free(st); + lg = (ListGame *) lg->node.succ; + } + SendDlgItemMessage(hDlg, OPT_GameListText, LB_SETCURSEL, 0, 0); + /* Size and position the dialog */ + if (!gameListDialog) { + gameListDialog = hDlg; + flags = SWP_NOZORDER; + GetClientRect(hDlg, &rect); + sizeX = rect.right; + sizeY = rect.bottom; + if (gameListX != CW_USEDEFAULT && gameListY != CW_USEDEFAULT && + gameListW != CW_USEDEFAULT && gameListH != CW_USEDEFAULT) { + WINDOWPLACEMENT wp; + EnsureOnScreen(&gameListX, &gameListY); + wp.length = sizeof(WINDOWPLACEMENT); + wp.flags = 0; + wp.showCmd = SW_SHOW; + wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0; + wp.rcNormalPosition.left = gameListX; + wp.rcNormalPosition.right = gameListX + gameListW; + wp.rcNormalPosition.top = gameListY; + wp.rcNormalPosition.bottom = gameListY + gameListH; + SetWindowPlacement(hDlg, &wp); + + GetClientRect(hDlg, &rect); + newSizeX = rect.right; + newSizeY = rect.bottom; + ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, + newSizeX, newSizeY); + sizeX = newSizeX; + sizeY = newSizeY; + } + } + return FALSE; + + case WM_SIZE: + newSizeX = LOWORD(lParam); + newSizeY = HIWORD(lParam); + ResizeEditPlusButtons(hDlg, GetDlgItem(hDlg, OPT_GameListText), + sizeX, sizeY, newSizeX, newSizeY); + sizeX = newSizeX; + sizeY = newSizeY; + break; + + case WM_GETMINMAXINFO: + /* Prevent resizing window too small */ + mmi = (MINMAXINFO *) lParam; + mmi->ptMinTrackSize.x = 100; + mmi->ptMinTrackSize.y = 100; + break; + + case WM_COMMAND: + switch (LOWORD(wParam)) { + case IDOK: + case OPT_GameListLoad: + nItem = SendDlgItemMessage(hDlg, OPT_GameListText, LB_GETCURSEL, 0, 0); + if (nItem < 0) { + /* is this possible? */ + DisplayError("No game selected", 0); + return TRUE; + } + break; /* load the game*/ + + case OPT_GameListNext: + nItem = SendDlgItemMessage(hDlg, OPT_GameListText, LB_GETCURSEL, 0, 0); + nItem++; + if (nItem >= ((ListGame *) gameList.tailPred)->number) { + DisplayError("Can't go forward any further", 0); + return TRUE; + } + SendDlgItemMessage(hDlg, OPT_GameListText, LB_SETCURSEL, nItem, 0); + break; /* load the game*/ + + case OPT_GameListPrev: + nItem = SendDlgItemMessage(hDlg, OPT_GameListText, LB_GETCURSEL, 0, 0); + nItem--; + if (nItem < 0) { + DisplayError("Can't back up any further", 0); + } + SendDlgItemMessage(hDlg, OPT_GameListText, LB_SETCURSEL, nItem, 0); + break; /* load the game*/ + + case IDCANCEL: + case OPT_GameListClose: + GameListPopDown(); + return TRUE; + + case OPT_GameListText: + switch (HIWORD(wParam)) { + case LBN_DBLCLK: + nItem = SendMessage((HWND) lParam, LB_GETCURSEL, 0, 0); + break; /* load the game*/ + + default: + return FALSE; + } + break; + + default: + return FALSE; + } + /* Load the game */ + if (cmailMsgLoaded) { + CmailLoadGame(gameFile, nItem + 1, gameFileName, TRUE); + } else { + LoadGame(gameFile, nItem + 1, gameFileName, TRUE); + } + return TRUE; + + default: + break; + } + return FALSE; +} + + +VOID GameListPopUp(FILE *fp, char *filename) +{ + FARPROC lpProc; + + gameFile = fp; + if (gameFileName != filename) { + if (gameFileName) free(gameFileName); + gameFileName = StrSave(filename); + } + CheckMenuItem(GetMenu(hwndMain), IDM_ShowGameList, MF_CHECKED); + if (gameListDialog) { + SendMessage(gameListDialog, WM_INITDIALOG, 0, 0); + if (!gameListUp) ShowWindow(gameListDialog, SW_SHOW); + } else { + lpProc = MakeProcInstance((FARPROC)GameListDialog, hInst); + CreateDialog(hInst, MAKEINTRESOURCE(DLG_GameList), + hwndMain, (DLGPROC)lpProc); + FreeProcInstance(lpProc); + } + gameListUp = TRUE; +} + +VOID GameListPopDown(void) +{ + CheckMenuItem(GetMenu(hwndMain), IDM_ShowGameList, MF_UNCHECKED); + if (gameListDialog) ShowWindow(gameListDialog, SW_HIDE); + gameListUp = FALSE; +} + + +VOID GameListHighlight(int index) +{ + if (gameListDialog == NULL) return; + SendDlgItemMessage(gameListDialog, OPT_GameListText, + LB_SETCURSEL, index - 1, 0); +} + + +VOID GameListDestroy() +{ + GameListPopDown(); + if (gameFileName) { + free(gameFileName); + gameFileName = NULL; + } +} + +VOID ShowGameListProc() +{ + if (gameListUp) { + GameListPopDown(); + } else { + if (gameFileName) { + GameListPopUp(gameFile, gameFileName); + } else { + DisplayError("No game list", 0); + } + } +} diff --git a/winboard-dm-beta4/winboard.c b/winboard-dm-beta4/winboard.c new file mode 100755 index 00000000..c0f7a0cb --- /dev/null +++ b/winboard-dm-beta4/winboard.c @@ -0,0 +1,8401 @@ +/* + * WinBoard.c -- Windows NT front end to XBoard + * $Id$ + * + * Copyright 1991 by Digital Equipment Corporation, Maynard, Massachusetts. + * Enhancements Copyright 1992-2001 Free Software Foundation, Inc. + * + * XBoard borrows its colors and the bitmaps.xchess bitmap set from XChess, + * which was written and is copyrighted by Wayne Christopher. + * + * The following terms apply to Digital Equipment Corporation's copyright + * interest in XBoard: + * ------------------------------------------------------------------------ + * All Rights Reserved + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appear in all copies and that + * both that copyright notice and this permission notice appear in + * supporting documentation, and that the name of Digital not be + * used in advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. + * + * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING + * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL + * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR + * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, + * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + * ------------------------------------------------------------------------ + * + * The following terms apply to the enhanced version of XBoard distributed + * by the Free Software Foundation: + * ------------------------------------------------------------------------ + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * ------------------------------------------------------------------------ + */ + +#include "config.h" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Need for Shell */ +#include + +#if __GNUC__ +#include +#include +#endif + +#include "common.h" +#include "winboard.h" +#include "frontend.h" +#include "backend.h" +#include "moves.h" +#include "wclipbrd.h" +#include "wgamelist.h" +#include "wedittags.h" +#include "woptions.h" +#include "wsockerr.h" +#include "defaults.h" + + char *tit; + char *pvs; + char *dep; + char *np; + char *nod; + char *sco; + +typedef struct { + ChessSquare piece; + POINT pos; /* window coordinates of current pos */ + POINT lastpos; /* window coordinates of last pos - used for clipping */ + POINT from; /* board coordinates of the piece's orig pos */ + POINT to; /* board coordinates of the piece's new pos */ +} AnimInfo; + +static AnimInfo animInfo = { EmptySquare, {-1,-1}, {-1,-1}, {-1,-1} }; + +typedef struct { + POINT start; /* window coordinates of start pos */ + POINT pos; /* window coordinates of current pos */ + POINT lastpos; /* window coordinates of last pos - used for clipping */ + POINT from; /* board coordinates of the piece's orig pos */ +} DragInfo; + +static DragInfo dragInfo = { {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1} }; + +typedef struct { + POINT sq[2]; /* board coordinates of from, to squares */ +} HighlightInfo; + +static HighlightInfo highlightInfo = { {{-1, -1}, {-1, -1}} }; +static HighlightInfo premoveHighlightInfo = { {{-1, -1}, {-1, -1}} }; + +/* Window class names */ +char szAppName[] = "WinBoard"; +char szConsoleName[] = "WBConsole"; + +/* Title bar text */ +char szTitle[] = "WinBoard"; +char szConsoleTitle[] = "ICS Interaction"; + +char *programName; +char *settingsFileName; +BOOLEAN saveSettingsOnExit; +char installDir[MSG_SIZ]; + +BoardSize boardSize; +BOOLEAN chessProgram; +static int boardX, boardY, consoleX, consoleY, consoleW, consoleH; +static int squareSize, lineGap; +static int winWidth, winHeight; +static RECT messageRect, whiteRect, blackRect; +static char messageText[MESSAGE_TEXT_MAX]; +static int clockTimerEvent = 0; +static int loadGameTimerEvent = 0; +static DelayedEventCallback delayedTimerCallback; +static int delayedTimerEvent = 0; +static int buttonCount = 2; +char *icsTextMenuString; +char *icsNames; +char *firstChessProgramNames; +char *secondChessProgramNames; + +static int analysisTimerEvent = 0; + +#define ARG_MAX 20000 + +#define PALETTESIZE 256 + +/* GUI -> engine */ +extern void GuiCommand P((int command, int param)); + +HINSTANCE hInst; /* current instance */ +HWND hwndMain = NULL; /* root window*/ +HWND hwndConsole = NULL; + +BOOLEAN alwaysOnTop = FALSE; +RECT boardRect; +COLORREF lightSquareColor, darkSquareColor, whitePieceColor, + blackPieceColor, highlightSquareColor, premoveHighlightColor; +HPALETTE hPal; +ColorClass currentColorClass; + +HWND hCommPort = NULL; /* currently open comm port */ +static HWND hwndPause; /* pause button */ +static HBITMAP pieceBitmap[3][(int) WhiteKing + 1]; +static HBRUSH lightSquareBrush, darkSquareBrush, + whitePieceBrush, blackPieceBrush, iconBkgndBrush, outlineBrush; +static POINT gridEndpoints[(BOARD_SIZE + 1) * 4]; +static DWORD gridVertexCounts[(BOARD_SIZE + 1) * 2]; +static HPEN gridPen = NULL; +static HPEN highlightPen = NULL; +static HPEN premovePen = NULL; +static NPLOGPALETTE pLogPal; +static BOOL paletteChanged = FALSE; +static HICON iconWhite, iconBlack, iconCurrent; +static int doingSizing = FALSE; +static int lastSizing = 0; + +#if __GNUC__ && !defined(_winmajor) +#define oldDialog 0 /* cygwin doesn't define _winmajor; mingw does */ +#else +#define oldDialog (_winmajor < 4) +#endif + +char *defaultTextAttribs[] = +{ + COLOR_SHOUT, COLOR_SSHOUT, COLOR_CHANNEL1, COLOR_CHANNEL, COLOR_KIBITZ, + COLOR_TELL, COLOR_CHALLENGE, COLOR_REQUEST, COLOR_SEEK, COLOR_NORMAL, + COLOR_NONE +}; + +typedef struct { + char *name; + int squareSize; + int lineGap; + int smallLayout; + int tinyLayout; + int cliWidth, cliHeight; +} SizeInfo; + +SizeInfo sizeInfo[] = +{ + { "tiny", 21, 0, 1, 1, 0, 0 }, + { "teeny", 25, 1, 1, 1, 0, 0 }, + { "dinky", 29, 1, 1, 1, 0, 0 }, + { "petite", 33, 1, 1, 1, 0, 0 }, + { "slim", 37, 2, 1, 0, 0, 0 }, + { "small", 40, 2, 1, 0, 0, 0 }, + { "mediocre", 45, 2, 1, 0, 0, 0 }, + { "middling", 49, 2, 0, 0, 0, 0 }, + { "average", 54, 2, 0, 0, 0, 0 }, + { "moderate", 58, 3, 0, 0, 0, 0 }, + { "medium", 64, 3, 0, 0, 0, 0 }, + { "bulky", 72, 3, 0, 0, 0, 0 }, + { "large", 80, 3, 0, 0, 0, 0 }, + { "big", 87, 3, 0, 0, 0, 0 }, + { "huge", 95, 3, 0, 0, 0, 0 }, + { "giant", 108, 3, 0, 0, 0, 0 }, + { "colossal", 116, 4, 0, 0, 0, 0 }, + { "titanic", 129, 4, 0, 0, 0, 0 }, + { NULL, 0, 0, 0, 0, 0, 0 } +}; + +#define MF(x) {x, {0, }, {0, }, 0} +MyFont fontRec[NUM_SIZES][NUM_FONTS] = +{ + { MF(CLOCK_FONT_TINY), MF(MESSAGE_FONT_TINY), + MF(COORD_FONT_TINY), MF(CONSOLE_FONT_TINY), + MF(COMMENT_FONT_TINY), MF(EDITTAGS_FONT_TINY) }, + { MF(CLOCK_FONT_TEENY), MF(MESSAGE_FONT_TEENY), + MF(COORD_FONT_TEENY), MF(CONSOLE_FONT_TEENY), + MF(COMMENT_FONT_TEENY), MF(EDITTAGS_FONT_TEENY) }, + { MF(CLOCK_FONT_DINKY), MF(MESSAGE_FONT_DINKY), + MF(COORD_FONT_DINKY), MF(CONSOLE_FONT_DINKY), + MF(COMMENT_FONT_DINKY), MF(EDITTAGS_FONT_DINKY) }, + { MF(CLOCK_FONT_PETITE), MF(MESSAGE_FONT_PETITE), + MF(COORD_FONT_PETITE), MF(CONSOLE_FONT_PETITE), + MF(COMMENT_FONT_PETITE), MF(EDITTAGS_FONT_PETITE) }, + { MF(CLOCK_FONT_SLIM), MF(MESSAGE_FONT_SLIM), + MF(COORD_FONT_SLIM), MF(CONSOLE_FONT_SLIM), + MF(COMMENT_FONT_SLIM), MF(EDITTAGS_FONT_SLIM) }, + { MF(CLOCK_FONT_SMALL), MF(MESSAGE_FONT_SMALL), + MF(COORD_FONT_SMALL), MF(CONSOLE_FONT_SMALL), + MF(COMMENT_FONT_SMALL), MF(EDITTAGS_FONT_SMALL) }, + { MF(CLOCK_FONT_MEDIOCRE), MF(MESSAGE_FONT_MEDIOCRE), + MF(COORD_FONT_MEDIOCRE), MF(CONSOLE_FONT_MEDIOCRE), + MF(COMMENT_FONT_MEDIOCRE), MF(EDITTAGS_FONT_MEDIOCRE) }, + { MF(CLOCK_FONT_MIDDLING), MF(MESSAGE_FONT_MIDDLING), + MF(COORD_FONT_MIDDLING), MF(CONSOLE_FONT_MIDDLING), + MF(COMMENT_FONT_MIDDLING), MF(EDITTAGS_FONT_MIDDLING) }, + { MF(CLOCK_FONT_AVERAGE), MF(MESSAGE_FONT_AVERAGE), + MF(COORD_FONT_AVERAGE), MF(CONSOLE_FONT_AVERAGE), + MF(COMMENT_FONT_AVERAGE), MF(EDITTAGS_FONT_AVERAGE) }, + { MF(CLOCK_FONT_MODERATE), MF(MESSAGE_FONT_MODERATE), + MF(COORD_FONT_MODERATE), MF(CONSOLE_FONT_MODERATE), + MF(COMMENT_FONT_MODERATE), MF(EDITTAGS_FONT_MODERATE) }, + { MF(CLOCK_FONT_MEDIUM), MF(MESSAGE_FONT_MEDIUM), + MF(COORD_FONT_MEDIUM), MF(CONSOLE_FONT_MEDIUM), + MF(COMMENT_FONT_MEDIUM), MF(EDITTAGS_FONT_MEDIUM) }, + { MF(CLOCK_FONT_BULKY), MF(MESSAGE_FONT_BULKY), + MF(COORD_FONT_BULKY), MF(CONSOLE_FONT_BULKY), + MF(COMMENT_FONT_BULKY), MF(EDITTAGS_FONT_BULKY) }, + { MF(CLOCK_FONT_LARGE), MF(MESSAGE_FONT_LARGE), + MF(COORD_FONT_LARGE), MF(CONSOLE_FONT_LARGE), + MF(COMMENT_FONT_LARGE), MF(EDITTAGS_FONT_LARGE) }, + { MF(CLOCK_FONT_BIG), MF(MESSAGE_FONT_BIG), + MF(COORD_FONT_BIG), MF(CONSOLE_FONT_BIG), + MF(COMMENT_FONT_BIG), MF(EDITTAGS_FONT_BIG) }, + { MF(CLOCK_FONT_HUGE), MF(MESSAGE_FONT_HUGE), + MF(COORD_FONT_HUGE), MF(CONSOLE_FONT_HUGE), + MF(COMMENT_FONT_HUGE), MF(EDITTAGS_FONT_HUGE) }, + { MF(CLOCK_FONT_GIANT), MF(MESSAGE_FONT_GIANT), + MF(COORD_FONT_GIANT), MF(CONSOLE_FONT_GIANT), + MF(COMMENT_FONT_GIANT), MF(EDITTAGS_FONT_GIANT) }, + { MF(CLOCK_FONT_COLOSSAL), MF(MESSAGE_FONT_COLOSSAL), + MF(COORD_FONT_COLOSSAL), MF(CONSOLE_FONT_COLOSSAL), + MF(COMMENT_FONT_COLOSSAL), MF(EDITTAGS_FONT_COLOSSAL) }, + { MF(CLOCK_FONT_TITANIC), MF(MESSAGE_FONT_TITANIC), + MF(COORD_FONT_TITANIC), MF(CONSOLE_FONT_TITANIC), + MF(COMMENT_FONT_TITANIC), MF(EDITTAGS_FONT_TITANIC) }, +}; + +MyFont *font[NUM_SIZES][NUM_FONTS]; + +typedef struct { + char *label; + int id; + HWND hwnd; + WNDPROC wndproc; +} MyButtonDesc; + +#define BUTTON_WIDTH (tinyLayout ? 16 : 32) +#define N_BUTTONS 5 + +MyButtonDesc buttonDesc[N_BUTTONS] = +{ + {"<<", IDM_ToStart, NULL, NULL}, + {"<", IDM_Backward, NULL, NULL}, + {"P", IDM_Pause, NULL, NULL}, + {">", IDM_Forward, NULL, NULL}, + {">>", IDM_ToEnd, NULL, NULL}, +}; + +int tinyLayout = 0, smallLayout = 0; +#define MENU_BAR_ITEMS 6 +char *menuBarText[2][MENU_BAR_ITEMS+1] = { + { "&File", "&Mode", "&Action", "&Step", "&Options", "&Help", NULL }, + { "&F", "&M", "&A", "&S", "&O", "&H", NULL }, +}; + + +MySound sounds[(int)NSoundClasses]; +MyTextAttribs textAttribs[(int)NColorClasses]; + +MyColorizeAttribs colorizeAttribs[] = { + { (COLORREF)0, 0, "Shout Text" }, + { (COLORREF)0, 0, "SShout/CShout" }, + { (COLORREF)0, 0, "Channel 1 Text" }, + { (COLORREF)0, 0, "Channel Text" }, + { (COLORREF)0, 0, "Kibitz Text" }, + { (COLORREF)0, 0, "Tell Text" }, + { (COLORREF)0, 0, "Challenge Text" }, + { (COLORREF)0, 0, "Request Text" }, + { (COLORREF)0, 0, "Seek Text" }, + { (COLORREF)0, 0, "Normal Text" }, + { (COLORREF)0, 0, "None" } +}; + + + +static char *commentTitle; +static char *commentText; +static int commentIndex; +static Boolean editComment = FALSE; +HWND commentDialog = NULL; +BOOLEAN commentDialogUp = FALSE; +static int commentX, commentY, commentH, commentW; + +HWND analysisDialog = NULL; +BOOLEAN analysisDialogUp = FALSE; +static int analysisX, analysisY, analysisH, analysisW; + +char errorMessage[2*MSG_SIZ]; +HWND errorDialog = NULL; +BOOLEAN moveErrorMessageUp = FALSE; +BOOLEAN consoleEcho = TRUE; +CHARFORMAT consoleCF; +COLORREF consoleBackgroundColor; + +char *programVersion; + +#include + +#define CPReal 1 +#define CPComm 2 +#define CPSock 3 +#define CPRcmd 4 +typedef int CPKind; + +typedef struct { + CPKind kind; + HANDLE hProcess; + DWORD pid; + HANDLE hTo; + HANDLE hFrom; + SOCKET sock; + SOCKET sock2; /* stderr socket for OpenRcmd */ +} ChildProc; + +#define INPUT_SOURCE_BUF_SIZE 4096 + +typedef struct _InputSource { + CPKind kind; + HANDLE hFile; + SOCKET sock; + int lineByLine; + HANDLE hThread; + DWORD id; + char buf[INPUT_SOURCE_BUF_SIZE]; + char *next; + DWORD count; + int error; + InputCallback func; + struct _InputSource *second; /* for stderr thread on CPRcmd */ + VOIDSTAR closure; +} InputSource; + +InputSource *consoleInputSource; + +DCB dcb; + +/* forward */ +VOID ConsoleOutput(char* data, int length, int forceVisible); +VOID ConsoleCreate(); +LRESULT CALLBACK + ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam); +LRESULT CALLBACK + AnalysisDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam); +VOID ColorizeTextPopup(HWND hwnd, ColorClass cc); +VOID PrintCommSettings(FILE *f, char *name, DCB *dcb); +VOID ParseCommSettings(char *arg, DCB *dcb); + +LRESULT CALLBACK + StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam); +VOID APIENTRY MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def); +void ParseIcsTextMenu(char *icsTextMenuString); +VOID PopUpMoveDialog(char firstchar); +VOID UpdateSampleText(HWND hDlg, int id, MyColorizeAttribs *mca); + +/* + * Setting "frozen" should disable all user input other than deleting + * the window. We do this while engines are initializing themselves. + */ +static int frozen = 0; +static int oldMenuItemState[MENU_BAR_ITEMS]; +void FreezeUI() +{ + HMENU hmenu; + int i; + + if (frozen) return; + frozen = 1; + hmenu = GetMenu(hwndMain); + for (i=0; i screenWidth - 32) *x = 0; + if (*y > screenHeight - 32) *y = 0; +} + +BOOL +InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine) +{ + HWND hwnd; /* Main window handle. */ + int ibs; + WINDOWPLACEMENT wp; + char *filepart; + + hInst = hInstance; /* Store instance handle in our global variable */ + + if (SearchPath(NULL, "WinBoard.exe", NULL, MSG_SIZ, installDir, &filepart)) { + *filepart = NULLCHAR; + } else { + GetCurrentDirectory(MSG_SIZ, installDir); + } + InitAppData(lpCmdLine); /* Get run-time parameters */ + if (appData.debugMode) { + debugFP = fopen("winboard.debug", "w"); + setbuf(debugFP, NULL); + } + + InitBackEnd1(); + + /* Create a main window for this application instance. */ + hwnd = CreateWindow(szAppName, szTitle, + (WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX), + CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, + NULL, NULL, hInstance, NULL); + hwndMain = hwnd; + + /* If window could not be created, return "failure" */ + if (!hwnd) { + return (FALSE); + } + + iconWhite = LoadIcon(hInstance, "icon_white"); + iconBlack = LoadIcon(hInstance, "icon_black"); + iconCurrent = iconWhite; + InitDrawingColors(); + screenHeight = GetSystemMetrics(SM_CYSCREEN); + screenWidth = GetSystemMetrics(SM_CXSCREEN); + for (ibs = (int) NUM_SIZES - 1; ibs >= 0; ibs--) { + /* Compute window size for each board size, and use the largest + size that fits on this screen as the default. */ + InitDrawingSizes((BoardSize)ibs, 0); + if (boardSize == (BoardSize)-1 && + winHeight <= screenHeight && winWidth <= screenWidth) { + boardSize = (BoardSize)ibs; + } + } + InitDrawingSizes(boardSize, 0); + InitMenuChecks(); + buttonCount = GetSystemMetrics(SM_CMOUSEBUTTONS); + + InitBackEnd2(); + + /* Make the window visible; update its client area; and return "success" */ + EnsureOnScreen(&boardX, &boardY); + wp.length = sizeof(WINDOWPLACEMENT); + wp.flags = 0; + wp.showCmd = nCmdShow; + wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0; + wp.rcNormalPosition.left = boardX; + wp.rcNormalPosition.right = boardX + winWidth; + wp.rcNormalPosition.top = boardY; + wp.rcNormalPosition.bottom = boardY + winHeight; + SetWindowPlacement(hwndMain, &wp); + + SetWindowPos(hwndMain, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST, + 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE); + if (hwndConsole) { +#if AOT_CONSOLE + SetWindowPos(hwndConsole, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST, + 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE); +#endif + ShowWindow(hwndConsole, nCmdShow); + } + UpdateWindow(hwnd); + + return TRUE; + +} + + +typedef enum { + ArgString, ArgInt, ArgFloat, ArgBoolean, ArgTrue, ArgFalse, ArgNone, + ArgColor, ArgAttribs, ArgFilename, ArgBoardSize, ArgFont, ArgCommSettings, + ArgSettingsFilename +} ArgType; + +typedef struct { + char *argName; + ArgType argType; + /*** + union { + String *pString; // ArgString + int *pInt; // ArgInt + float *pFloat; // ArgFloat + Boolean *pBoolean; // ArgBoolean + COLORREF *pColor; // ArgColor + ColorClass cc; // ArgAttribs + String *pFilename; // ArgFilename + BoardSize *pBoardSize; // ArgBoardSize + int whichFont; // ArgFont + DCB *pDCB; // ArgCommSettings + String *pFilename; // ArgSettingsFilename + } argLoc; + ***/ + LPVOID argLoc; + BOOL save; +} ArgDescriptor; + +int junk; +ArgDescriptor argDescriptors[] = { + /* positional arguments */ + { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE }, + { "", ArgNone, NULL }, + /* keyword arguments */ + { "EngineRoom", ArgBoolean, (LPVOID) &appData.AnalysisWindow, TRUE }, + { "eRoom", ArgTrue, (LPVOID) &appData.AnalysisWindow, FALSE }, + { "xeRoom", ArgFalse, (LPVOID) &appData.AnalysisWindow, FALSE }, + { "whitePieceColor", ArgColor, (LPVOID) &whitePieceColor, TRUE }, + { "wpc", ArgColor, (LPVOID) &whitePieceColor, FALSE }, + { "blackPieceColor", ArgColor, (LPVOID) &blackPieceColor, TRUE }, + { "bpc", ArgColor, (LPVOID) &blackPieceColor, FALSE }, + { "lightSquareColor", ArgColor, (LPVOID) &lightSquareColor, TRUE }, + { "lsc", ArgColor, (LPVOID) &lightSquareColor, FALSE }, + { "darkSquareColor", ArgColor, (LPVOID) &darkSquareColor, TRUE }, + { "dsc", ArgColor, (LPVOID) &darkSquareColor, FALSE }, + { "highlightSquareColor", ArgColor, (LPVOID) &highlightSquareColor, TRUE }, + { "hsc", ArgColor, (LPVOID) &highlightSquareColor, FALSE }, + { "premoveHighlightColor", ArgColor, (LPVOID) &premoveHighlightColor, TRUE }, + { "phc", ArgColor, (LPVOID) &premoveHighlightColor, FALSE }, + { "movesPerSession", ArgInt, (LPVOID) &appData.movesPerSession, TRUE }, + { "mps", ArgInt, (LPVOID) &appData.movesPerSession, FALSE }, + { "initString", ArgString, (LPVOID) &appData.initString, FALSE }, + { "firstInitString", ArgString, (LPVOID) &appData.initString, FALSE }, + { "secondInitString", ArgString, (LPVOID) &appData.secondInitString, FALSE }, + { "firstComputerString", ArgString, (LPVOID) &appData.firstComputerString, + FALSE }, + { "secondComputerString", ArgString, (LPVOID) &appData.secondComputerString, + FALSE }, + { "firstChessProgram", ArgFilename, (LPVOID) &appData.firstChessProgram, + FALSE }, + { "fcp", ArgFilename, (LPVOID) &appData.firstChessProgram, FALSE }, + { "secondChessProgram", ArgFilename, (LPVOID) &appData.secondChessProgram, + FALSE }, + { "scp", ArgFilename, (LPVOID) &appData.secondChessProgram, FALSE }, + { "firstPlaysBlack", ArgBoolean, (LPVOID) &appData.firstPlaysBlack, FALSE }, + { "fb", ArgTrue, (LPVOID) &appData.firstPlaysBlack, FALSE }, + { "xfb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE }, + { "-fb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE }, + { "noChessProgram", ArgBoolean, (LPVOID) &appData.noChessProgram, FALSE }, + { "ncp", ArgTrue, (LPVOID) &appData.noChessProgram, FALSE }, + { "xncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE }, + { "-ncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE }, + { "firstHost", ArgString, (LPVOID) &appData.firstHost, FALSE }, + { "fh", ArgString, (LPVOID) &appData.firstHost, FALSE }, + { "secondHost", ArgString, (LPVOID) &appData.secondHost, FALSE }, + { "sh", ArgString, (LPVOID) &appData.secondHost, FALSE }, + { "firstDirectory", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE }, + { "fd", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE }, + { "secondDirectory", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE }, + { "sd", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE }, + /*!!bitmapDirectory?*/ + { "remoteShell", ArgFilename, (LPVOID) &appData.remoteShell, FALSE }, + { "rsh", ArgFilename, (LPVOID) &appData.remoteShell, FALSE }, + { "remoteUser", ArgString, (LPVOID) &appData.remoteUser, FALSE }, + { "ruser", ArgString, (LPVOID) &appData.remoteUser, FALSE }, + { "timeDelay", ArgFloat, (LPVOID) &appData.timeDelay, TRUE }, + { "td", ArgFloat, (LPVOID) &appData.timeDelay, FALSE }, + { "timeControl", ArgString, (LPVOID) &appData.timeControl, TRUE }, + { "tc", ArgString, (LPVOID) &appData.timeControl, FALSE }, + { "timeIncrement", ArgInt, (LPVOID) &appData.timeIncrement, TRUE }, + { "inc", ArgInt, (LPVOID) &appData.timeIncrement, FALSE }, + { "internetChessServerMode", ArgBoolean, (LPVOID) &appData.icsActive, FALSE }, + { "ics", ArgTrue, (LPVOID) &appData.icsActive, FALSE }, + { "xics", ArgFalse, (LPVOID) &appData.icsActive, FALSE }, + { "-ics", ArgFalse, (LPVOID) &appData.icsActive, FALSE }, + { "internetChessServerHost", ArgString, (LPVOID) &appData.icsHost, FALSE }, + { "icshost", ArgString, (LPVOID) &appData.icsHost, FALSE }, + { "internetChessServerPort", ArgString, (LPVOID) &appData.icsPort, FALSE }, + { "icsport", ArgString, (LPVOID) &appData.icsPort, FALSE }, + { "internetChessServerCommPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE }, + { "icscomm", ArgString, (LPVOID) &appData.icsCommPort, FALSE }, + { "internetChessServerComPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE }, + { "icscom", ArgString, (LPVOID) &appData.icsCommPort, FALSE }, + { "internetChessServerLogonScript", ArgFilename, (LPVOID) &appData.icsLogon, FALSE }, + { "icslogon", ArgFilename, (LPVOID) &appData.icsLogon, FALSE }, + { "useTelnet", ArgBoolean, (LPVOID) &appData.useTelnet, FALSE }, + { "telnet", ArgTrue, (LPVOID) &appData.useTelnet, FALSE }, + { "xtelnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE }, + { "-telnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE }, + { "telnetProgram", ArgFilename, (LPVOID) &appData.telnetProgram, FALSE }, + { "icshelper", ArgFilename, (LPVOID) &appData.icsHelper, FALSE }, + { "gateway", ArgString, (LPVOID) &appData.gateway, FALSE }, + { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE }, + { "lgf", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE }, + { "loadGameIndex", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE }, + { "lgi", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE }, + { "saveGameFile", ArgFilename, (LPVOID) &appData.saveGameFile, TRUE }, + { "sgf", ArgFilename, (LPVOID) &appData.saveGameFile, FALSE }, + { "autoSaveGames", ArgBoolean, (LPVOID) &appData.autoSaveGames, TRUE }, + { "autosave", ArgTrue, (LPVOID) &appData.autoSaveGames, FALSE }, + { "xautosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE }, + { "-autosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE }, + { "loadPositionFile", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE }, + { "lpf", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE }, + { "loadPositionIndex", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE }, + { "lpi", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE }, + { "savePositionFile", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE }, + { "spf", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE }, + { "matchMode", ArgBoolean, (LPVOID) &appData.matchMode, FALSE }, + { "mm", ArgTrue, (LPVOID) &appData.matchMode, FALSE }, + { "xmm", ArgFalse, (LPVOID) &appData.matchMode, FALSE }, + { "-mm", ArgFalse, (LPVOID) &appData.matchMode, FALSE }, + { "matchGames", ArgInt, (LPVOID) &appData.matchGames, FALSE }, + { "mg", ArgInt, (LPVOID) &appData.matchGames, FALSE }, + { "monoMode", ArgBoolean, (LPVOID) &appData.monoMode, TRUE }, + { "mono", ArgTrue, (LPVOID) &appData.monoMode, FALSE }, + { "xmono", ArgFalse, (LPVOID) &appData.monoMode, FALSE }, + { "-mono", ArgFalse, (LPVOID) &appData.monoMode, FALSE }, + { "debugMode", ArgBoolean, (LPVOID) &appData.debugMode, FALSE }, + { "debug", ArgTrue, (LPVOID) &appData.debugMode, FALSE }, + { "xdebug", ArgFalse, (LPVOID) &appData.debugMode, FALSE }, + { "-debug", ArgFalse, (LPVOID) &appData.debugMode, FALSE }, + { "clockMode", ArgBoolean, (LPVOID) &appData.clockMode, FALSE }, + { "clock", ArgTrue, (LPVOID) &appData.clockMode, FALSE }, + { "xclock", ArgFalse, (LPVOID) &appData.clockMode, FALSE }, + { "-clock", ArgFalse, (LPVOID) &appData.clockMode, FALSE }, + { "searchTime", ArgString, (LPVOID) &appData.searchTime, FALSE }, + { "st", ArgString, (LPVOID) &appData.searchTime, FALSE }, + { "searchDepth", ArgInt, (LPVOID) &appData.searchDepth, FALSE }, + { "depth", ArgInt, (LPVOID) &appData.searchDepth, FALSE }, + { "showCoords", ArgBoolean, (LPVOID) &appData.showCoords, TRUE }, + { "coords", ArgTrue, (LPVOID) &appData.showCoords, FALSE }, + { "xcoords", ArgFalse, (LPVOID) &appData.showCoords, FALSE }, + { "-coords", ArgFalse, (LPVOID) &appData.showCoords, FALSE }, + { "showThinking", ArgBoolean, (LPVOID) &appData.showThinking, TRUE }, + { "thinking", ArgTrue, (LPVOID) &appData.showThinking, FALSE }, + { "xthinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE }, + { "-thinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE }, + { "icc", ArgTrue, (LPVOID) &appData.ICC_feature, FALSE }, + { "ponderNextMove", ArgBoolean, (LPVOID) &appData.ponderNextMove, TRUE }, + { "ponder", ArgTrue, (LPVOID) &appData.ponderNextMove, FALSE }, + { "xponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE }, + { "-ponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE }, + { "periodicUpdates", ArgBoolean, (LPVOID) &appData.periodicUpdates, TRUE }, + { "periodic", ArgTrue, (LPVOID) &appData.periodicUpdates, FALSE }, + { "xperiodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE }, + { "-periodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE }, + { "popupExitMessage", ArgBoolean, (LPVOID) &appData.popupExitMessage, TRUE }, + { "exit", ArgTrue, (LPVOID) &appData.popupExitMessage, FALSE }, + { "xexit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE }, + { "-exit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE }, + { "popupMoveErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors, TRUE }, + { "popup", ArgTrue, (LPVOID) &appData.popupMoveErrors, FALSE }, + { "xpopup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE }, + { "-popup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE }, + { "popUpErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors, + FALSE }, /* only so that old WinBoard.ini files from betas can be read */ + { "clockFont", ArgFont, (LPVOID) CLOCK_FONT, TRUE }, + { "messageFont", ArgFont, (LPVOID) MESSAGE_FONT, TRUE }, + { "coordFont", ArgFont, (LPVOID) COORD_FONT, TRUE }, + { "tagsFont", ArgFont, (LPVOID) EDITTAGS_FONT, TRUE }, + { "commentFont", ArgFont, (LPVOID) COMMENT_FONT, TRUE }, + { "icsFont", ArgFont, (LPVOID) CONSOLE_FONT, TRUE }, + { "boardSize", ArgBoardSize, (LPVOID) &boardSize, + TRUE }, /* must come after all fonts */ + { "size", ArgBoardSize, (LPVOID) &boardSize, FALSE }, + { "ringBellAfterMoves", ArgBoolean, (LPVOID) &appData.ringBellAfterMoves, + FALSE }, /* historical; kept only so old winboard.ini files will parse */ + { "alwaysOnTop", ArgBoolean, (LPVOID) &alwaysOnTop, TRUE }, + { "top", ArgTrue, (LPVOID) &alwaysOnTop, FALSE }, + { "xtop", ArgFalse, (LPVOID) &alwaysOnTop, FALSE }, + { "-top", ArgFalse, (LPVOID) &alwaysOnTop, FALSE }, + { "autoCallFlag", ArgBoolean, (LPVOID) &appData.autoCallFlag, TRUE }, + { "autoflag", ArgTrue, (LPVOID) &appData.autoCallFlag, FALSE }, + { "xautoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE }, + { "-autoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE }, + { "autoComment", ArgBoolean, (LPVOID) &appData.autoComment, TRUE }, + { "autocomm", ArgTrue, (LPVOID) &appData.autoComment, FALSE }, + { "xautocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE }, + { "-autocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE }, + { "autoObserve", ArgBoolean, (LPVOID) &appData.autoObserve, TRUE }, + { "autobs", ArgTrue, (LPVOID) &appData.autoObserve, FALSE }, + { "xautobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE }, + { "-autobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE }, + { "flipView", ArgBoolean, (LPVOID) &appData.flipView, FALSE }, + { "flip", ArgTrue, (LPVOID) &appData.flipView, FALSE }, + { "xflip", ArgFalse, (LPVOID) &appData.flipView, FALSE }, + { "-flip", ArgFalse, (LPVOID) &appData.flipView, FALSE }, + { "autoFlipView", ArgBoolean, (LPVOID) &appData.autoFlipView, TRUE }, + { "autoflip", ArgTrue, (LPVOID) &appData.autoFlipView, FALSE }, + { "xautoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE }, + { "-autoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE }, + { "autoRaiseBoard", ArgBoolean, (LPVOID) &appData.autoRaiseBoard, TRUE }, + { "autoraise", ArgTrue, (LPVOID) &appData.autoRaiseBoard, FALSE }, + { "xautoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE }, + { "-autoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE }, +#if 0 + { "cmailGameName", ArgString, (LPVOID) &appData.cmailGameName, FALSE }, + { "cmail", ArgString, (LPVOID) &appData.cmailGameName, FALSE }, +#endif + { "alwaysPromoteToQueen", ArgBoolean, (LPVOID) &appData.alwaysPromoteToQueen, TRUE }, + { "queen", ArgTrue, (LPVOID) &appData.alwaysPromoteToQueen, FALSE }, + { "xqueen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE }, + { "-queen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE }, + { "oldSaveStyle", ArgBoolean, (LPVOID) &appData.oldSaveStyle, TRUE }, + { "oldsave", ArgTrue, (LPVOID) &appData.oldSaveStyle, FALSE }, + { "xoldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE }, + { "-oldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE }, + { "quietPlay", ArgBoolean, (LPVOID) &appData.quietPlay, TRUE }, + { "quiet", ArgTrue, (LPVOID) &appData.quietPlay, FALSE }, + { "xquiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE }, + { "-quiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE }, + { "getMoveList", ArgBoolean, (LPVOID) &appData.getMoveList, TRUE }, + { "moves", ArgTrue, (LPVOID) &appData.getMoveList, FALSE }, + { "xmoves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE }, + { "-moves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE }, + { "testLegality", ArgBoolean, (LPVOID) &appData.testLegality, TRUE }, + { "legal", ArgTrue, (LPVOID) &appData.testLegality, FALSE }, + { "xlegal", ArgFalse, (LPVOID) &appData.testLegality, FALSE }, + { "-legal", ArgFalse, (LPVOID) &appData.testLegality, FALSE }, + { "premove", ArgBoolean, (LPVOID) &appData.premove, TRUE }, + { "pre", ArgTrue, (LPVOID) &appData.premove, FALSE }, + { "xpre", ArgFalse, (LPVOID) &appData.premove, FALSE }, + { "-pre", ArgFalse, (LPVOID) &appData.premove, FALSE }, + { "premoveWhite", ArgBoolean, (LPVOID) &appData.premoveWhite, TRUE }, + { "prewhite", ArgTrue, (LPVOID) &appData.premoveWhite, FALSE }, + { "xprewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE }, + { "-prewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE }, + { "premoveWhiteText", ArgString, (LPVOID) &appData.premoveWhiteText, TRUE }, + { "premoveBlack", ArgBoolean, (LPVOID) &appData.premoveBlack, TRUE }, + { "preblack", ArgTrue, (LPVOID) &appData.premoveBlack, FALSE }, + { "xpreblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE }, + { "-preblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE }, + { "premoveBlackText", ArgString, (LPVOID) &appData.premoveBlackText, TRUE }, + { "icsAlarm", ArgBoolean, (LPVOID) &appData.icsAlarm, TRUE}, + { "alarm", ArgTrue, (LPVOID) &appData.icsAlarm, FALSE}, + { "xalarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE}, + { "-alarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE}, + { "icsAlarmTime", ArgInt, (LPVOID) &appData.icsAlarmTime, TRUE}, + { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE}, + { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE}, + { "edit", ArgTrue, (LPVOID) &appData.localLineEditing, FALSE }, + { "xedit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE }, + { "-edit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE }, + { "animateMoving", ArgBoolean, (LPVOID) &appData.animate, TRUE }, + { "animate", ArgTrue, (LPVOID) &appData.animate, FALSE }, + { "xanimate", ArgFalse, (LPVOID) &appData.animate, FALSE }, + { "-animate", ArgFalse, (LPVOID) &appData.animate, FALSE }, + { "animateSpeed", ArgInt, (LPVOID) &appData.animSpeed, TRUE }, + { "animateDragging", ArgBoolean, (LPVOID) &appData.animateDragging, TRUE }, + { "drag", ArgTrue, (LPVOID) &appData.animateDragging, FALSE }, + { "xdrag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE }, + { "-drag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE }, + { "blindfold", ArgBoolean, (LPVOID) &appData.blindfold, TRUE }, + { "blind", ArgTrue, (LPVOID) &appData.blindfold, FALSE }, + { "xblind", ArgFalse, (LPVOID) &appData.blindfold, FALSE }, + { "-blind", ArgFalse, (LPVOID) &appData.blindfold, FALSE }, + { "highlightLastMove", ArgBoolean, + (LPVOID) &appData.highlightLastMove, TRUE }, + { "highlight", ArgTrue, (LPVOID) &appData.highlightLastMove, FALSE }, + { "xhighlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE }, + { "-highlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE }, + { "highlightDragging", ArgBoolean, + (LPVOID) &appData.highlightDragging, TRUE }, + { "highdrag", ArgTrue, (LPVOID) &appData.highlightDragging, FALSE }, + { "xhighdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE }, + { "-highdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE }, + { "colorizeMessages", ArgBoolean, (LPVOID) &appData.colorize, TRUE }, + { "colorize", ArgTrue, (LPVOID) &appData.colorize, FALSE }, + { "xcolorize", ArgFalse, (LPVOID) &appData.colorize, FALSE }, + { "-colorize", ArgFalse, (LPVOID) &appData.colorize, FALSE }, + { "colorShout", ArgAttribs, (LPVOID) ColorShout, TRUE }, + { "colorSShout", ArgAttribs, (LPVOID) ColorSShout, TRUE }, + { "colorChannel1", ArgAttribs, (LPVOID) ColorChannel1, TRUE }, + { "colorChannel", ArgAttribs, (LPVOID) ColorChannel, TRUE }, + { "colorKibitz", ArgAttribs, (LPVOID) ColorKibitz, TRUE }, + { "colorTell", ArgAttribs, (LPVOID) ColorTell, TRUE }, + { "colorChallenge", ArgAttribs, (LPVOID) ColorChallenge, TRUE }, + { "colorRequest", ArgAttribs, (LPVOID) ColorRequest, TRUE }, + { "colorSeek", ArgAttribs, (LPVOID) ColorSeek, TRUE }, + { "colorNormal", ArgAttribs, (LPVOID) ColorNormal, TRUE }, + { "colorBackground", ArgColor, (LPVOID) &consoleBackgroundColor, TRUE }, + { "soundShout", ArgFilename, + (LPVOID) &textAttribs[ColorShout].sound.name, TRUE }, + { "soundSShout", ArgFilename, + (LPVOID) &textAttribs[ColorSShout].sound.name, TRUE }, + { "soundChannel1", ArgFilename, + (LPVOID) &textAttribs[ColorChannel1].sound.name, TRUE }, + { "soundChannel", ArgFilename, + (LPVOID) &textAttribs[ColorChannel].sound.name, TRUE }, + { "soundKibitz", ArgFilename, + (LPVOID) &textAttribs[ColorKibitz].sound.name, TRUE }, + { "soundTell", ArgFilename, + (LPVOID) &textAttribs[ColorTell].sound.name, TRUE }, + { "soundChallenge", ArgFilename, + (LPVOID) &textAttribs[ColorChallenge].sound.name, TRUE }, + { "soundRequest", ArgFilename, + (LPVOID) &textAttribs[ColorRequest].sound.name, TRUE }, + { "soundSeek", ArgFilename, + (LPVOID) &textAttribs[ColorSeek].sound.name, TRUE }, + { "soundMove", ArgFilename, (LPVOID) &sounds[(int)SoundMove].name, TRUE }, + { "soundBell", ArgFilename, (LPVOID) &sounds[(int)SoundBell].name, TRUE }, + { "soundIcsWin", ArgFilename, (LPVOID) &sounds[(int)SoundIcsWin].name,TRUE }, + { "soundIcsLoss", ArgFilename, + (LPVOID) &sounds[(int)SoundIcsLoss].name, TRUE }, + { "soundIcsDraw", ArgFilename, + (LPVOID) &sounds[(int)SoundIcsDraw].name, TRUE }, + { "soundIcsUnfinished", ArgFilename, + (LPVOID) &sounds[(int)SoundIcsUnfinished].name, TRUE}, + { "soundIcsAlarm", ArgFilename, + (LPVOID) &sounds[(int)SoundAlarm].name, TRUE }, + { "reuseFirst", ArgBoolean, (LPVOID) &appData.reuseFirst, FALSE }, + { "reuse", ArgTrue, (LPVOID) &appData.reuseFirst, FALSE }, + { "xreuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE }, + { "-reuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE }, + { "reuseChessPrograms", ArgBoolean, + (LPVOID) &appData.reuseFirst, FALSE }, /* backward compat only */ + { "reuseSecond", ArgBoolean, (LPVOID) &appData.reuseSecond, FALSE }, + { "reuse2", ArgTrue, (LPVOID) &appData.reuseSecond, FALSE }, + { "xreuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE }, + { "-reuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE }, + { "comPortSettings", ArgCommSettings, (LPVOID) &dcb, TRUE }, + { "x", ArgInt, (LPVOID) &boardX, TRUE }, + { "y", ArgInt, (LPVOID) &boardY, TRUE }, + { "icsX", ArgInt, (LPVOID) &consoleX, TRUE }, + { "icsY", ArgInt, (LPVOID) &consoleY, TRUE }, + { "icsW", ArgInt, (LPVOID) &consoleW, TRUE }, + { "icsH", ArgInt, (LPVOID) &consoleH, TRUE }, + { "analysisX", ArgInt, (LPVOID) &analysisX, TRUE }, + { "analysisY", ArgInt, (LPVOID) &analysisY, TRUE }, + { "analysisW", ArgInt, (LPVOID) &analysisW, TRUE }, + { "analysisH", ArgInt, (LPVOID) &analysisH, TRUE }, + { "commentX", ArgInt, (LPVOID) &commentX, TRUE }, + { "commentY", ArgInt, (LPVOID) &commentY, TRUE }, + { "commentW", ArgInt, (LPVOID) &commentW, TRUE }, + { "commentH", ArgInt, (LPVOID) &commentH, TRUE }, + { "tagsX", ArgInt, (LPVOID) &editTagsX, TRUE }, + { "tagsY", ArgInt, (LPVOID) &editTagsY, TRUE }, + { "tagsW", ArgInt, (LPVOID) &editTagsW, TRUE }, + { "tagsH", ArgInt, (LPVOID) &editTagsH, TRUE }, + { "gameListX", ArgInt, (LPVOID) &gameListX, TRUE }, + { "gameListY", ArgInt, (LPVOID) &gameListY, TRUE }, + { "gameListW", ArgInt, (LPVOID) &gameListW, TRUE }, + { "gameListH", ArgInt, (LPVOID) &gameListH, TRUE }, + { "settingsFile", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE }, + { "ini", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE }, + { "saveSettingsOnExit", ArgBoolean, (LPVOID) &saveSettingsOnExit, TRUE }, + { "chessProgram", ArgBoolean, (LPVOID) &chessProgram, FALSE }, + { "cp", ArgTrue, (LPVOID) &chessProgram, FALSE }, + { "xcp", ArgFalse, (LPVOID) &chessProgram, FALSE }, + { "-cp", ArgFalse, (LPVOID) &chessProgram, FALSE }, + { "icsMenu", ArgString, (LPVOID) &icsTextMenuString, TRUE }, + { "icsNames", ArgString, (LPVOID) &icsNames, TRUE }, + { "firstChessProgramNames", ArgString, (LPVOID) &firstChessProgramNames, + TRUE }, + { "secondChessProgramNames", ArgString, (LPVOID) &secondChessProgramNames, + TRUE }, + { "initialMode", ArgString, (LPVOID) &appData.initialMode, FALSE }, + { "mode", ArgString, (LPVOID) &appData.initialMode, FALSE }, + { "variant", ArgString, (LPVOID) &appData.variant, FALSE }, + { "firstProtocolVersion", ArgInt, (LPVOID) &appData.firstProtocolVersion, + FALSE }, + { "secondProtocolVersion", ArgInt, (LPVOID) &appData.secondProtocolVersion, + FALSE }, + { "showButtonBar", ArgBoolean, (LPVOID) &appData.showButtonBar, TRUE }, + { "buttons", ArgTrue, (LPVOID) &appData.showButtonBar, FALSE }, + { "xbuttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE }, + { "-buttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE }, +#ifdef ZIPPY + { "zippyTalk", ArgBoolean, (LPVOID) &appData.zippyTalk, FALSE }, + { "zt", ArgTrue, (LPVOID) &appData.zippyTalk, FALSE }, + { "xzt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE }, + { "-zt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE }, + { "zippyPlay", ArgBoolean, (LPVOID) &appData.zippyPlay, FALSE }, + { "zp", ArgTrue, (LPVOID) &appData.zippyPlay, FALSE }, + { "xzp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE }, + { "-zp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE }, + { "zippyLines", ArgFilename, (LPVOID) &appData.zippyLines, FALSE }, + { "zippyPinhead", ArgString, (LPVOID) &appData.zippyPinhead, FALSE }, + { "zippyPassword", ArgString, (LPVOID) &appData.zippyPassword, FALSE }, + { "zippyPassword2", ArgString, (LPVOID) &appData.zippyPassword2, FALSE }, + { "zippyPassword3", ArgString, (LPVOID) &appData.zippyPassword3, FALSE }, + { "zippyWrongPassword", ArgString, (LPVOID) &appData.zippyWrongPassword, + FALSE }, + { "zippyAcceptOnly", ArgString, (LPVOID) &appData.zippyAcceptOnly, FALSE }, + { "zippyUseI", ArgBoolean, (LPVOID) &appData.zippyUseI, FALSE }, + { "zui", ArgTrue, (LPVOID) &appData.zippyUseI, FALSE }, + { "xzui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE }, + { "-zui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE }, + { "zippyBughouse", ArgInt, (LPVOID) &appData.zippyBughouse, FALSE }, + { "zippyNoplayCrafty", ArgBoolean, (LPVOID) &appData.zippyNoplayCrafty, + FALSE }, + { "znc", ArgTrue, (LPVOID) &appData.zippyNoplayCrafty, FALSE }, + { "xznc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE }, + { "-znc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE }, + { "zippyGameEnd", ArgString, (LPVOID) &appData.zippyGameEnd, FALSE }, + { "zippyGameStart", ArgString, (LPVOID) &appData.zippyGameStart, FALSE }, + { "zippyAdjourn", ArgBoolean, (LPVOID) &appData.zippyAdjourn, FALSE }, + { "zadj", ArgTrue, (LPVOID) &appData.zippyAdjourn, FALSE }, + { "xzadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE }, + { "-zadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE }, + { "zippyAbort", ArgBoolean, (LPVOID) &appData.zippyAbort, FALSE }, + { "zab", ArgTrue, (LPVOID) &appData.zippyAbort, FALSE }, + { "xzab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE }, + { "-zab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE }, + { "zippyVariants", ArgString, (LPVOID) &appData.zippyVariants, FALSE }, + { "zippyMaxGames", ArgInt, (LPVOID)&appData.zippyMaxGames, FALSE }, + { "zippyReplayTimeout", ArgInt, (LPVOID)&appData.zippyReplayTimeout, FALSE }, + /* Kludge to allow winboard.ini files from buggy 4.0.4 to be read: */ + { "zippyReplyTimeout", ArgInt, (LPVOID)&junk, FALSE }, +#endif + { NULL, ArgNone, NULL, FALSE } +}; + + +/* Kludge for indirection files on command line */ +char* lastIndirectionFilename; +ArgDescriptor argDescriptorIndirection = +{ "", ArgSettingsFilename, (LPVOID) NULL, FALSE }; + + +VOID +ExitArgError(char *msg, char *badArg) +{ + char buf[MSG_SIZ]; + + sprintf(buf, "%s %s", msg, badArg); + DisplayFatalError(buf, 0, 2); + exit(2); +} + +/* Command line font name parser. NULL name means do nothing. + Syntax like "Courier New:10.0 bi" or "Arial:10" or "Arial:10b" + For backward compatibility, syntax without the colon is also + accepted, but font names with digits in them won't work in that case. +*/ +VOID +ParseFontName(char *name, MyFontParams *mfp) +{ + char *p, *q; + if (name == NULL) return; + p = name; + q = strchr(p, ':'); + if (q) { + if (q - p >= sizeof(mfp->faceName)) + ExitArgError("Font name too long:", name); + memcpy(mfp->faceName, p, q - p); + mfp->faceName[q - p] = NULLCHAR; + p = q + 1; + } else { + q = mfp->faceName; + while (*p && !isdigit(*p)) { + *q++ = *p++; + if (q - mfp->faceName >= sizeof(mfp->faceName)) + ExitArgError("Font name too long:", name); + } + while (q > mfp->faceName && q[-1] == ' ') q--; + *q = NULLCHAR; + } + if (!*p) ExitArgError("Font point size missing:", name); + mfp->pointSize = (float) atof(p); + mfp->bold = (strchr(p, 'b') != NULL); + mfp->italic = (strchr(p, 'i') != NULL); + mfp->underline = (strchr(p, 'u') != NULL); + mfp->strikeout = (strchr(p, 's') != NULL); +} + +/* Color name parser. + X version accepts X color names, but this one + handles only the #rrggbb form (hex) or rrr,ggg,bbb (decimal) */ +COLORREF +ParseColorName(char *name) +{ + int red, green, blue, count; + char buf[MSG_SIZ]; + + count = sscanf(name, "#%2x%2x%2x", &red, &green, &blue); + if (count != 3) { + count = sscanf(name, "%3d%*[^0-9]%3d%*[^0-9]%3d", + &red, &green, &blue); + } + if (count != 3) { + sprintf(buf, "Can't parse color name %s", name); + DisplayError(buf, 0); + return RGB(0, 0, 0); + } + return PALETTERGB(red, green, blue); +} + + +void ParseAttribs(COLORREF *color, int *effects, char* argValue) +{ + char *e = argValue; + int eff = 0; + + while (*e) { + if (*e == 'b') eff |= CFE_BOLD; + else if (*e == 'i') eff |= CFE_ITALIC; + else if (*e == 'u') eff |= CFE_UNDERLINE; + else if (*e == 's') eff |= CFE_STRIKEOUT; + else if (*e == '#' || isdigit(*e)) break; + e++; + } + *effects = eff; + *color = ParseColorName(e); +} + + +BoardSize +ParseBoardSize(char *name) +{ + BoardSize bs = SizeTiny; + while (sizeInfo[bs].name != NULL) { + if (StrCaseCmp(name, sizeInfo[bs].name) == 0) return bs; + bs++; + } + ExitArgError("Unrecognized board size value", name); + return bs; /* not reached */ +} + + +char +StringGet(void *getClosure) +{ + char **p = (char **) getClosure; + return *((*p)++); +} + +char +FileGet(void *getClosure) +{ + int c; + FILE* f = (FILE*) getClosure; + + c = getc(f); + if (c == EOF) + return NULLCHAR; + else + return (char) c; +} + +/* Parse settings file named "name". If file found, return the + full name in fullname and return TRUE; else return FALSE */ +BOOLEAN +ParseSettingsFile(char *name, char fullname[MSG_SIZ]) +{ + char *dummy; + FILE *f; + + if (SearchPath(installDir, name, NULL, MSG_SIZ, fullname, &dummy)) { + f = fopen(fullname, "r"); + if (f != NULL) { + ParseArgs(FileGet, f); + fclose(f); + return TRUE; + } + } + return FALSE; +} + +VOID +ParseArgs(GetFunc get, void *cl) +{ + char argName[ARG_MAX]; + char argValue[ARG_MAX]; + ArgDescriptor *ad; + char start; + char *q; + int i, octval; + char ch; + int posarg = 0; + + ch = get(cl); + for (;;) { + while (ch == ' ' || ch == '\n' || ch == '\t') ch = get(cl); + if (ch == NULLCHAR) break; + if (ch == ';') { + /* Comment to end of line */ + ch = get(cl); + while (ch != '\n' && ch != NULLCHAR) ch = get(cl); + continue; + } else if (ch == '/' || ch == '-') { + /* Switch */ + q = argName; + while (ch != ' ' && ch != '=' && ch != ':' && ch != NULLCHAR && + ch != '\n' && ch != '\t') { + *q++ = ch; + ch = get(cl); + } + *q = NULLCHAR; + + for (ad = argDescriptors; ad->argName != NULL; ad++) + if (strcmp(ad->argName, argName + 1) == 0) break; + + if (ad->argName == NULL) + ExitArgError("Unrecognized argument", argName); + + } else if (ch == '@') { + /* Indirection file */ + ad = &argDescriptorIndirection; + ch = get(cl); + } else { + /* Positional argument */ + ad = &argDescriptors[posarg++]; + strcpy(argName, ad->argName); + } + + if (ad->argType == ArgTrue) { + *(Boolean *) ad->argLoc = TRUE; + continue; + } + if (ad->argType == ArgFalse) { + *(Boolean *) ad->argLoc = FALSE; + continue; + } + + while (ch == ' ' || ch == '=' || ch == ':' || ch == '\t') ch = get(cl); + if (ch == NULLCHAR || ch == '\n') { + ExitArgError("No value provided for argument", argName); + } + q = argValue; + if (ch == '{') { + // Quoting with { }. No characters have to (or can) be escaped. + // Thus the string cannot contain a '}' character. + start = ch; + ch = get(cl); + while (start) { + switch (ch) { + case NULLCHAR: + start = NULLCHAR; + break; + + case '}': + ch = get(cl); + start = NULLCHAR; + break; + + default: + *q++ = ch; + ch = get(cl); + break; + } + } + } else if (ch == '\'' || ch == '"') { + // Quoting with ' ' or " ", with \ as escape character. + // Inconvenient for long strings that may contain Windows filenames. + start = ch; + ch = get(cl); + while (start) { + switch (ch) { + case NULLCHAR: + start = NULLCHAR; + break; + + default: + not_special: + *q++ = ch; + ch = get(cl); + break; + + case '\'': + case '\"': + if (ch == start) { + ch = get(cl); + start = NULLCHAR; + break; + } else { + goto not_special; + } + + case '\\': + if (ad->argType == ArgFilename + || ad->argType == ArgSettingsFilename) { + goto not_special; + } + ch = get(cl); + switch (ch) { + case NULLCHAR: + ExitArgError("Incomplete \\ escape in value for", argName); + break; + case 'n': + *q++ = '\n'; + ch = get(cl); + break; + case 'r': + *q++ = '\r'; + ch = get(cl); + break; + case 't': + *q++ = '\t'; + ch = get(cl); + break; + case 'b': + *q++ = '\b'; + ch = get(cl); + break; + case 'f': + *q++ = '\f'; + ch = get(cl); + break; + default: + octval = 0; + for (i = 0; i < 3; i++) { + if (ch >= '0' && ch <= '7') { + octval = octval*8 + (ch - '0'); + ch = get(cl); + } else { + break; + } + } + if (i > 0) { + *q++ = (char) octval; + } else { + *q++ = ch; + ch = get(cl); + } + break; + } + break; + } + } + } else { + while (ch != ' ' && ch != NULLCHAR && ch != '\t' && ch != '\n') { + *q++ = ch; + ch = get(cl); + } + } + *q = NULLCHAR; + + switch (ad->argType) { + case ArgInt: + *(int *) ad->argLoc = atoi(argValue); + break; + + case ArgFloat: + *(float *) ad->argLoc = (float) atof(argValue); + break; + + case ArgString: + case ArgFilename: + *(char **) ad->argLoc = strdup(argValue); + break; + + case ArgSettingsFilename: + { + char fullname[MSG_SIZ]; + if (ParseSettingsFile(argValue, fullname)) { + if (ad->argLoc != NULL) { + *(char **) ad->argLoc = strdup(fullname); + } + } else { + if (ad->argLoc != NULL) { + } else { + ExitArgError("Failed to open indirection file", argValue); + } + } + } + break; + + case ArgBoolean: + switch (argValue[0]) { + case 't': + case 'T': + *(Boolean *) ad->argLoc = TRUE; + break; + case 'f': + case 'F': + *(Boolean *) ad->argLoc = FALSE; + break; + default: + ExitArgError("Unrecognized boolean argument value", argValue); + break; + } + break; + + case ArgColor: + *(COLORREF *)ad->argLoc = ParseColorName(argValue); + break; + + case ArgAttribs: { + ColorClass cc = (ColorClass)ad->argLoc; + ParseAttribs(&textAttribs[cc].color, &textAttribs[cc].effects, argValue); + } + break; + + case ArgBoardSize: + *(BoardSize *)ad->argLoc = ParseBoardSize(argValue); + break; + + case ArgFont: + ParseFontName(argValue, &font[boardSize][(int)ad->argLoc]->mfp); + break; + + case ArgCommSettings: + ParseCommSettings(argValue, &dcb); + break; + + case ArgNone: + ExitArgError("Unrecognized argument", argValue); + break; + } + } +} + +VOID +LFfromMFP(LOGFONT* lf, MyFontParams *mfp) +{ + HDC hdc = CreateDC("DISPLAY", NULL, NULL, NULL); + lf->lfHeight = -(int)(mfp->pointSize * GetDeviceCaps(hdc, LOGPIXELSY) / 72.0 + 0.5); + DeleteDC(hdc); + lf->lfWidth = 0; + lf->lfEscapement = 0; + lf->lfOrientation = 0; + lf->lfWeight = mfp->bold ? FW_BOLD : FW_NORMAL; + lf->lfItalic = mfp->italic; + lf->lfUnderline = mfp->underline; + lf->lfStrikeOut = mfp->strikeout; + lf->lfCharSet = DEFAULT_CHARSET; + lf->lfOutPrecision = OUT_DEFAULT_PRECIS; + lf->lfClipPrecision = CLIP_DEFAULT_PRECIS; + lf->lfQuality = DEFAULT_QUALITY; + lf->lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE; + strcpy(lf->lfFaceName, mfp->faceName); +} + +VOID +CreateFontInMF(MyFont *mf) +{ + LFfromMFP(&mf->lf, &mf->mfp); + if (mf->hf) DeleteObject(mf->hf); + mf->hf = CreateFontIndirect(&mf->lf); +} + +VOID +SetDefaultTextAttribs() +{ + ColorClass cc; + for (cc = (ColorClass)0; cc < NColorClasses; cc++) { + ParseAttribs(&textAttribs[cc].color, + &textAttribs[cc].effects, + defaultTextAttribs[cc]); + } +} + +VOID +SetDefaultSounds() +{ + ColorClass cc; + SoundClass sc; + for (cc = (ColorClass)0; cc < NColorClasses; cc++) { + textAttribs[cc].sound.name = strdup(""); + textAttribs[cc].sound.data = NULL; + } + for (sc = (SoundClass)0; sc < NSoundClasses; sc++) { + sounds[sc].name = strdup(""); + sounds[sc].data = NULL; + } + sounds[(int)SoundBell].name = strdup(SOUND_BELL); +} + +VOID +LoadAllSounds() +{ + ColorClass cc; + SoundClass sc; + for (cc = (ColorClass)0; cc < NColorClasses; cc++) { + MyLoadSound(&textAttribs[cc].sound); + } + for (sc = (SoundClass)0; sc < NSoundClasses; sc++) { + MyLoadSound(&sounds[sc]); + } +} + +VOID +InitAppData(LPSTR lpCmdLine) +{ + int i, j; + char buf[ARG_MAX], currDir[MSG_SIZ]; + char *dummy, *p; + + programName = szAppName; + + /* Initialize to defaults */ + lightSquareColor = ParseColorName(LIGHT_SQUARE_COLOR); + darkSquareColor = ParseColorName(DARK_SQUARE_COLOR); + whitePieceColor = ParseColorName(WHITE_PIECE_COLOR); + blackPieceColor = ParseColorName(BLACK_PIECE_COLOR); + highlightSquareColor = ParseColorName(HIGHLIGHT_SQUARE_COLOR); + premoveHighlightColor = ParseColorName(PREMOVE_HIGHLIGHT_COLOR); + consoleBackgroundColor = ParseColorName(COLOR_BKGD); + SetDefaultTextAttribs(); + SetDefaultSounds(); + appData.movesPerSession = MOVES_PER_SESSION; + appData.initString = INIT_STRING; + appData.secondInitString = INIT_STRING; + appData.firstComputerString = COMPUTER_STRING; + appData.secondComputerString = COMPUTER_STRING; + appData.firstChessProgram = FIRST_CHESS_PROGRAM; + appData.secondChessProgram = SECOND_CHESS_PROGRAM; + appData.firstPlaysBlack = FALSE; + appData.noChessProgram = FALSE; + chessProgram = FALSE; + appData.firstHost = FIRST_HOST; + appData.secondHost = SECOND_HOST; + appData.firstDirectory = FIRST_DIRECTORY; + appData.secondDirectory = SECOND_DIRECTORY; + appData.bitmapDirectory = ""; + appData.remoteShell = REMOTE_SHELL; + appData.remoteUser = ""; + appData.timeDelay = TIME_DELAY; + appData.timeControl = TIME_CONTROL; + appData.timeIncrement = TIME_INCREMENT; + appData.icsActive = FALSE; + appData.icsHost = ""; + appData.icsPort = ICS_PORT; + appData.icsCommPort = ICS_COMM_PORT; + appData.icsLogon = ICS_LOGON; + appData.icsHelper = ""; + appData.useTelnet = FALSE; + appData.telnetProgram = TELNET_PROGRAM; + appData.gateway = ""; + appData.loadGameFile = ""; + appData.loadGameIndex = 0; + appData.saveGameFile = ""; + appData.autoSaveGames = FALSE; + appData.loadPositionFile = ""; + appData.loadPositionIndex = 1; + appData.savePositionFile = ""; + appData.matchMode = FALSE; + appData.matchGames = 0; + appData.monoMode = FALSE; + appData.debugMode = FALSE; + appData.clockMode = TRUE; + boardSize = (BoardSize) -1; /* determine by screen size */ + appData.Iconic = FALSE; /*unused*/ + appData.searchTime = ""; + appData.searchDepth = 0; + appData.showCoords = FALSE; + appData.ringBellAfterMoves = TRUE; /*obsolete in WinBoard*/ + appData.autoCallFlag = FALSE; + appData.flipView = FALSE; + appData.autoFlipView = TRUE; + appData.cmailGameName = ""; + appData.alwaysPromoteToQueen = FALSE; + appData.oldSaveStyle = FALSE; + appData.quietPlay = FALSE; + appData.showThinking = FALSE; + appData.ButtonSendOutPutToICS = TRUE; + appData.SendOutPutToICS = 1; /* default whisper */ + appData.icsAnalyze = FALSE; + appData.icsEngineKillPV = FALSE; + appData.smartQueue = TRUE; /* smart queue with IcsAnalyzeOutPut */ + appData.icsEngineWhisper = FALSE; + appData.icsEngineKibitz = FALSE; + appData.icsEngineTell = FALSE; + appData.icsAnalyzeWindow = FALSE; + appData.icsEngineNone = TRUE; /* don't send */ + appData.icsAnalyzeOutPut = 4; /* don't send */ + appData.icsKillPVs = 9; /* a recommend value for most programs */ + appData.windowMove = TRUE; /* Drop display fail low/high moves at ICS */ + appData.icsSmartQueue = 0; /* 0 = standard 1 = blitz */ + appData.icsShowBook = FALSE; /* show engine book */ + appData.userVersion = FALSE; /* programmer version false */ + appData.icsWBprotoAgr = FALSE; + appData.icsWBprotoNorm = TRUE; + appData.icsSmartQueueStd = TRUE; + appData.icsSmartQueueBlitz = FALSE; + appData.engineStatLine = TRUE; /* default send "." with engine room */ + appData.engineTourneyMode = FALSE; /* default no tourney mode */ + appData.zippyDraw = TRUE; + appData.ponderNextMove = TRUE; + appData.periodicUpdates = TRUE; + appData.popupExitMessage = TRUE; + appData.popupMoveErrors = FALSE; + appData.autoObserve = FALSE; + appData.autoComment = FALSE; + appData.animate = TRUE; + appData.animSpeed = 10; + appData.animateDragging = TRUE; + appData.highlightLastMove = TRUE; + appData.getMoveList = TRUE; + appData.testLegality = TRUE; + appData.premove = TRUE; + appData.premoveWhite = FALSE; + appData.premoveWhiteText = ""; + appData.premoveBlack = FALSE; + appData.premoveBlackText = ""; + appData.icsAlarm = TRUE; + appData.icsAlarmTime = 5000; + appData.autoRaiseBoard = TRUE; + appData.localLineEditing = TRUE; + appData.colorize = TRUE; + appData.reuseFirst = TRUE; + appData.reuseSecond = TRUE; + appData.blindfold = FALSE; + dcb.DCBlength = sizeof(DCB); + dcb.BaudRate = 9600; + dcb.fBinary = TRUE; + dcb.fParity = FALSE; + dcb.fOutxCtsFlow = FALSE; + dcb.fOutxDsrFlow = FALSE; + dcb.fDtrControl = DTR_CONTROL_ENABLE; + dcb.fDsrSensitivity = FALSE; + dcb.fTXContinueOnXoff = TRUE; + dcb.fOutX = FALSE; + dcb.fInX = FALSE; + dcb.fNull = FALSE; + dcb.fRtsControl = RTS_CONTROL_ENABLE; + dcb.fAbortOnError = FALSE; + dcb.wReserved = 0; + dcb.ByteSize = 7; + dcb.Parity = SPACEPARITY; + dcb.StopBits = ONESTOPBIT; + settingsFileName = SETTINGS_FILE; + saveSettingsOnExit = TRUE; + boardX = CW_USEDEFAULT; + boardY = CW_USEDEFAULT; + consoleX = CW_USEDEFAULT; + consoleY = CW_USEDEFAULT; + consoleW = CW_USEDEFAULT; + consoleH = CW_USEDEFAULT; + analysisX = CW_USEDEFAULT; + analysisY = CW_USEDEFAULT; + analysisW = 589; + analysisH = 330; + commentX = CW_USEDEFAULT; + commentY = CW_USEDEFAULT; + commentW = CW_USEDEFAULT; + commentH = CW_USEDEFAULT; + editTagsX = CW_USEDEFAULT; + editTagsY = CW_USEDEFAULT; + editTagsW = CW_USEDEFAULT; + editTagsH = CW_USEDEFAULT; + gameListX = CW_USEDEFAULT; + gameListY = CW_USEDEFAULT; + gameListW = CW_USEDEFAULT; + gameListH = CW_USEDEFAULT; + icsTextMenuString = ICS_TEXT_MENU_DEFAULT; + icsNames = ICS_NAMES; + firstChessProgramNames = FCP_NAMES; + secondChessProgramNames = SCP_NAMES; + appData.initialMode = ""; + appData.variant = "normal"; + appData.firstProtocolVersion = PROTOVER; + appData.secondProtocolVersion = PROTOVER; + appData.showButtonBar = TRUE; +#ifdef ZIPPY + appData.zippyTalk = ZIPPY_TALK; + appData.zippyPlay = ZIPPY_PLAY; + appData.zippyLines = ZIPPY_LINES; + appData.zippyPinhead = ZIPPY_PINHEAD; + appData.zippyPassword = ZIPPY_PASSWORD; + appData.zippyPassword2 = ZIPPY_PASSWORD2; + appData.zippyPassword3 = ZIPPY_PASSWORD3; + appData.zippyWrongPassword = ZIPPY_WRONG_PASSWORD; + appData.zippyAcceptOnly = ZIPPY_ACCEPT_ONLY; + appData.zippyUseI = ZIPPY_USE_I; + appData.zippyBughouse = ZIPPY_BUGHOUSE; + appData.zippyNoplayCrafty = ZIPPY_NOPLAY_CRAFTY; + appData.zippyGameEnd = ZIPPY_GAME_END; + appData.zippyGameStart = ZIPPY_GAME_START; + appData.zippyAdjourn = ZIPPY_ADJOURN; + appData.zippyAbort = ZIPPY_ABORT; + appData.zippyVariants = ZIPPY_VARIANTS; + appData.zippyMaxGames = ZIPPY_MAX_GAMES; + appData.zippyReplayTimeout = ZIPPY_REPLAY_TIMEOUT; +#endif + + /* Point font array elements to structures and + parse default font names */ + for (i=0; idef, &font[j][i]->mfp); + } + } + + /* Parse default settings file if any */ + if (ParseSettingsFile(settingsFileName, buf)) { + settingsFileName = strdup(buf); + } + + /* Parse command line */ + ParseArgs(StringGet, &lpCmdLine); + + /* Propagate options that affect others */ + if (appData.matchMode || appData.matchGames) chessProgram = TRUE; + if (appData.icsActive || appData.noChessProgram) { + chessProgram = FALSE; /* not local chess program mode */ + } + + /* Open startup dialog if needed */ + if ((!appData.noChessProgram && !chessProgram && !appData.icsActive) || + (appData.icsActive && *appData.icsHost == NULLCHAR) || + (chessProgram && (*appData.firstChessProgram == NULLCHAR || + *appData.secondChessProgram == NULLCHAR))) { + FARPROC lpProc; + + lpProc = MakeProcInstance((FARPROC)StartupDialog, hInst); + DialogBox(hInst, MAKEINTRESOURCE(DLG_Startup), NULL, (DLGPROC)lpProc); + FreeProcInstance(lpProc); + } + + /* Make sure save files land in the right (?) directory */ + if (GetFullPathName(appData.saveGameFile, MSG_SIZ, buf, &dummy)) { + appData.saveGameFile = strdup(buf); + } + if (GetFullPathName(appData.savePositionFile, MSG_SIZ, buf, &dummy)) { + appData.savePositionFile = strdup(buf); + } + + /* Finish initialization for fonts and sounds */ + for (i=0; iargName != NULL; ad++) { + if (!ad->save) continue; + switch (ad->argType) { + case ArgString: + { + char *p = *(char **)ad->argLoc; + if ((strchr(p, '\\') || strchr(p, '\n')) && !strchr(p, '}')) { + /* Quote multiline values or \-containing values + with { } if possible */ + fprintf(f, "/%s={%s}\n", ad->argName, p); + } else { + /* Else quote with " " */ + fprintf(f, "/%s=\"", ad->argName); + while (*p) { + if (*p == '\n') fprintf(f, "\n"); + else if (*p == '\r') fprintf(f, "\\r"); + else if (*p == '\t') fprintf(f, "\\t"); + else if (*p == '\b') fprintf(f, "\\b"); + else if (*p == '\f') fprintf(f, "\\f"); + else if (*p < ' ') fprintf(f, "\\%03o", *p); + else if (*p == '\"') fprintf(f, "\\\""); + else if (*p == '\\') fprintf(f, "\\\\"); + else putc(*p, f); + p++; + } + fprintf(f, "\"\n"); + } + } + break; + case ArgInt: + fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc); + break; + case ArgFloat: + fprintf(f, "/%s=%g\n", ad->argName, *(float *)ad->argLoc); + break; + case ArgBoolean: + fprintf(f, "/%s=%s\n", ad->argName, + (*(Boolean *)ad->argLoc) ? "true" : "false"); + break; + case ArgTrue: + if (*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName); + break; + case ArgFalse: + if (!*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName); + break; + case ArgColor: + { + COLORREF color = *(COLORREF *)ad->argLoc; + fprintf(f, "/%s=#%02x%02x%02x\n", ad->argName, + color&0xff, (color>>8)&0xff, (color>>16)&0xff); + } + break; + case ArgAttribs: + { + MyTextAttribs* ta = &textAttribs[(ColorClass)ad->argLoc]; + fprintf(f, "/%s=\"%s%s%s%s%s#%02x%02x%02x\"\n", ad->argName, + (ta->effects & CFE_BOLD) ? "b" : "", + (ta->effects & CFE_ITALIC) ? "i" : "", + (ta->effects & CFE_UNDERLINE) ? "u" : "", + (ta->effects & CFE_STRIKEOUT) ? "s" : "", + (ta->effects) ? " " : "", + ta->color&0xff, (ta->color >> 8)&0xff, (ta->color >> 16)&0xff); + } + break; + case ArgFilename: + if (strchr(*(char **)ad->argLoc, '\"')) { + fprintf(f, "/%s='%s'\n", ad->argName, *(char **)ad->argLoc); + } else { + fprintf(f, "/%s=\"%s\"\n", ad->argName, *(char **)ad->argLoc); + } + break; + case ArgBoardSize: + fprintf(f, "/%s=%s\n", ad->argName, + sizeInfo[*(BoardSize *)ad->argLoc].name); + break; + case ArgFont: + { + int bs; + for (bs=0; bsargLoc]->mfp; + fprintf(f, "/size=%s ", sizeInfo[bs].name); + fprintf(f, "/%s=\"%s:%g%s%s%s%s%s\"\n", + ad->argName, mfp->faceName, mfp->pointSize, + mfp->bold || mfp->italic || mfp->underline || mfp->strikeout ? " " : "", + mfp->bold ? "b" : "", + mfp->italic ? "i" : "", + mfp->underline ? "u" : "", + mfp->strikeout ? "s" : ""); + } + } + break; + case ArgCommSettings: + PrintCommSettings(f, ad->argName, (DCB *)ad->argLoc); + } + } + fclose(f); +} + + + +/*---------------------------------------------------------------------------*\ + * + * GDI board drawing routines + * +\*---------------------------------------------------------------------------*/ + +HBITMAP +DoLoadBitmap(HINSTANCE hinst, char *piece, int squareSize, char *suffix) +{ + char name[128]; + + sprintf(name, "%s%d%s", piece, squareSize, suffix); + if (gameInfo.event && + strcmp(gameInfo.event, "Easter Egg Hunt") == 0 && + strcmp(name, "k80s") == 0) { + strcpy(name, "tim"); + } + return LoadBitmap(hinst, name); +} + + +/* Insert a color into the program's logical palette + structure. This code assumes the given color is + the result of the RGB or PALETTERGB macro, and it + knows how those macros work (which is documented). +*/ +VOID +InsertInPalette(COLORREF color) +{ + LPPALETTEENTRY pe = &(pLogPal->palPalEntry[pLogPal->palNumEntries]); + + if (pLogPal->palNumEntries++ >= PALETTESIZE) { + DisplayFatalError("Too many colors", 0, 1); + pLogPal->palNumEntries--; + return; + } + + pe->peFlags = (char) 0; + pe->peRed = (char) (0xFF & color); + pe->peGreen = (char) (0xFF & (color >> 8)); + pe->peBlue = (char) (0xFF & (color >> 16)); + return; +} + + +VOID +InitDrawingColors() +{ + if (pLogPal == NULL) { + /* Allocate enough memory for a logical palette with + * PALETTESIZE entries and set the size and version fields + * of the logical palette structure. + */ + pLogPal = (NPLOGPALETTE) + LocalAlloc(LMEM_FIXED, (sizeof(LOGPALETTE) + + (sizeof(PALETTEENTRY) * (PALETTESIZE)))); + pLogPal->palVersion = 0x300; + } + pLogPal->palNumEntries = 0; + + InsertInPalette(lightSquareColor); + InsertInPalette(darkSquareColor); + InsertInPalette(whitePieceColor); + InsertInPalette(blackPieceColor); + InsertInPalette(highlightSquareColor); + InsertInPalette(premoveHighlightColor); + + /* create a logical color palette according the information + * in the LOGPALETTE structure. + */ + hPal = CreatePalette((LPLOGPALETTE) pLogPal); + + lightSquareBrush = CreateSolidBrush(lightSquareColor); + darkSquareBrush = CreateSolidBrush(darkSquareColor); + whitePieceBrush = CreateSolidBrush(whitePieceColor); + blackPieceBrush = CreateSolidBrush(blackPieceColor); + iconBkgndBrush = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND)); +} + + +int +BoardWidth(int boardSize) +{ + return (BOARD_SIZE + 1) * sizeInfo[boardSize].lineGap + + BOARD_SIZE * sizeInfo[boardSize].squareSize; +} + +/* Respond to board resize by dragging edge */ +VOID +ResizeBoard(int newSizeX, int newSizeY, int flags) +{ + BoardSize newSize = NUM_SIZES - 1; + static int recurse = 0; + if (IsIconic(hwndMain)) return; + if (recurse > 0) return; + recurse++; + while (newSize > 0 && + (newSizeX < sizeInfo[newSize].cliWidth || + newSizeY < sizeInfo[newSize].cliHeight)) { + newSize--; + } + boardSize = newSize; + InitDrawingSizes(boardSize, flags); + recurse--; +} + + + +VOID +InitDrawingSizes(BoardSize boardSize, int flags) +{ + int i, boardWidth; + ChessSquare piece; + static int oldBoardSize = -1, oldTinyLayout = 0; + HDC hdc; + SIZE clockSize, messageSize; + HFONT oldFont; + char buf[MSG_SIZ]; + char *str; + HMENU hmenu = GetMenu(hwndMain); + RECT crect, wrect; + int offby; + LOGBRUSH logbrush; + + tinyLayout = sizeInfo[boardSize].tinyLayout; + smallLayout = sizeInfo[boardSize].smallLayout; + squareSize = sizeInfo[boardSize].squareSize; + lineGap = sizeInfo[boardSize].lineGap; + + if (tinyLayout != oldTinyLayout) { + long style = GetWindowLong(hwndMain, GWL_STYLE); + if (tinyLayout) { + style &= ~WS_SYSMENU; + InsertMenu(hmenu, IDM_Exit, MF_BYCOMMAND, IDM_Minimize, + "&Minimize\tCtrl+F4"); + } else { + style |= WS_SYSMENU; + RemoveMenu(hmenu, IDM_Minimize, MF_BYCOMMAND); + } + SetWindowLong(hwndMain, GWL_STYLE, style); + + for (i=0; menuBarText[tinyLayout][i]; i++) { + ModifyMenu(hmenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP, + (UINT)GetSubMenu(hmenu, i), menuBarText[tinyLayout][i]); + } + DrawMenuBar(hwndMain); + } + + boardWidth = BoardWidth(boardSize); + + /* Get text area sizes */ + hdc = GetDC(hwndMain); + if (appData.clockMode) { + sprintf(buf, "White: %s", TimeString(23*60*60*1000L)); + } else { + sprintf(buf, "White"); + } + oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf); + GetTextExtentPoint(hdc, buf, strlen(buf), &clockSize); + SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf); + str = "We only care about the height here"; + GetTextExtentPoint(hdc, str, strlen(str), &messageSize); + SelectObject(hdc, oldFont); + ReleaseDC(hwndMain, hdc); + + /* Compute where everything goes */ + whiteRect.left = OUTER_MARGIN; + whiteRect.right = whiteRect.left + boardWidth/2 - INNER_MARGIN/2; + whiteRect.top = OUTER_MARGIN; + whiteRect.bottom = whiteRect.top + clockSize.cy; + + blackRect.left = whiteRect.right + INNER_MARGIN; + blackRect.right = blackRect.left + boardWidth/2 - 1; + blackRect.top = whiteRect.top; + blackRect.bottom = whiteRect.bottom; + + messageRect.left = whiteRect.left + MESSAGE_LINE_LEFTMARGIN; + if (appData.showButtonBar) { + messageRect.right = blackRect.right + - N_BUTTONS*BUTTON_WIDTH - MESSAGE_LINE_LEFTMARGIN; + } else { + messageRect.right = blackRect.right; + } + messageRect.top = whiteRect.bottom + INNER_MARGIN; + messageRect.bottom = messageRect.top + messageSize.cy; + + boardRect.left = whiteRect.left; + boardRect.right = boardRect.left + boardWidth; + boardRect.top = messageRect.bottom + INNER_MARGIN; + boardRect.bottom = boardRect.top + boardWidth; + + sizeInfo[boardSize].cliWidth = boardRect.right + OUTER_MARGIN; + sizeInfo[boardSize].cliHeight = boardRect.bottom + OUTER_MARGIN; + winWidth = 2 * GetSystemMetrics(SM_CXFRAME) + boardRect.right + OUTER_MARGIN; + winHeight = 2 * GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYMENU) + + GetSystemMetrics(SM_CYCAPTION) + boardRect.bottom + OUTER_MARGIN; + GetWindowRect(hwndMain, &wrect); + SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight, + SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE); + /* compensate if menu bar wrapped */ + GetClientRect(hwndMain, &crect); + offby = boardRect.bottom + OUTER_MARGIN - crect.bottom; + winHeight += offby; + switch (flags) { + case WMSZ_TOPLEFT: + SetWindowPos(hwndMain, NULL, + wrect.right - winWidth, wrect.bottom - winHeight, + winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER); + break; + + case WMSZ_TOPRIGHT: + case WMSZ_TOP: + SetWindowPos(hwndMain, NULL, + wrect.left, wrect.bottom - winHeight, + winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER); + break; + + case WMSZ_BOTTOMLEFT: + case WMSZ_LEFT: + SetWindowPos(hwndMain, NULL, + wrect.right - winWidth, wrect.top, + winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER); + break; + + case WMSZ_BOTTOMRIGHT: + case WMSZ_BOTTOM: + case WMSZ_RIGHT: + default: + SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight, + SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE); + break; + } + + hwndPause = NULL; + for (i = 0; i < N_BUTTONS; i++) { + if (buttonDesc[i].hwnd != NULL) { + DestroyWindow(buttonDesc[i].hwnd); + buttonDesc[i].hwnd = NULL; + } + if (appData.showButtonBar) { + buttonDesc[i].hwnd = + CreateWindow("BUTTON", buttonDesc[i].label, + WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON , + boardRect.right - BUTTON_WIDTH*(N_BUTTONS-i), + messageRect.top, BUTTON_WIDTH, messageSize.cy, hwndMain, + (HMENU) buttonDesc[i].id, + (HINSTANCE) GetWindowLong(hwndMain, GWL_HINSTANCE), NULL); + if (tinyLayout) { + SendMessage(buttonDesc[i].hwnd, WM_SETFONT, + (WPARAM)font[boardSize][MESSAGE_FONT]->hf, + MAKELPARAM(FALSE, 0)); + } + if (buttonDesc[i].id == IDM_Pause) + hwndPause = buttonDesc[i].hwnd; + buttonDesc[i].wndproc = (WNDPROC) + SetWindowLong(buttonDesc[i].hwnd, GWL_WNDPROC, (LONG) ButtonProc); + } + } + if (gridPen != NULL) DeleteObject(gridPen); + if (highlightPen != NULL) DeleteObject(highlightPen); + if (premovePen != NULL) DeleteObject(premovePen); + if (lineGap != 0) { + logbrush.lbStyle = BS_SOLID; + logbrush.lbColor = RGB(0, 0, 0); /* grid pen color = black */ + gridPen = + ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER, + lineGap, &logbrush, 0, NULL); + logbrush.lbColor = highlightSquareColor; + highlightPen = + ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER, + lineGap, &logbrush, 0, NULL); + + logbrush.lbColor = premoveHighlightColor; + premovePen = + ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER, + lineGap, &logbrush, 0, NULL); + + for (i = 0; i < BOARD_SIZE + 1; i++) { + gridEndpoints[i*2].x = boardRect.left + lineGap / 2; + gridEndpoints[i*2 + BOARD_SIZE*2 + 2].y = boardRect.top + lineGap / 2; + gridEndpoints[i*2].y = gridEndpoints[i*2 + 1].y = + boardRect.top + lineGap / 2 + (i * (squareSize + lineGap)); + gridEndpoints[i*2 + 1].x = boardRect.left + lineGap / 2 + + BOARD_SIZE * (squareSize + lineGap); + gridEndpoints[i*2 + BOARD_SIZE*2 + 2].x = + gridEndpoints[i*2 + 1 + BOARD_SIZE*2 + 2].x = boardRect.left + + lineGap / 2 + (i * (squareSize + lineGap)); + gridEndpoints[i*2 + 1 + BOARD_SIZE*2 + 2].y = + boardRect.top + BOARD_SIZE * (squareSize + lineGap); + gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2; + } + } + + if (boardSize == oldBoardSize) return; + oldBoardSize = boardSize; + oldTinyLayout = tinyLayout; + + /* Load piece bitmaps for this board size */ + for (i=0; i<=2; i++) { + for (piece = WhitePawn; + (int) piece <= (int) WhiteKing; + piece = (ChessSquare) ((int) piece + 1)) { + if (pieceBitmap[i][piece] != NULL) + DeleteObject(pieceBitmap[i][piece]); + } + } + + pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "s"); + pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "s"); + pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "s"); + pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "s"); + pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "s"); + pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "s"); + pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "o"); + pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "o"); + pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "o"); + pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "o"); + pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "o"); + pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "o"); + pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "w"); + pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "w"); + pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "w"); + pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "w"); + pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "w"); + pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "w"); + +} + +HBITMAP +PieceBitmap(ChessSquare p, int kind) +{ + if ((int) p >= (int) BlackPawn) + p = (ChessSquare) ((int) p - (int) BlackPawn + (int) WhitePawn); + + return pieceBitmap[kind][(int) p]; +} + +/***************************************************************/ + +#define MIN(a,b) (((a) < (b)) ? (a) : (b)) +#define MAX(a,b) (((a) > (b)) ? (a) : (b)) +/* +#define MIN3(a,b,c) (((a) < (b) && (a) < (c)) ? (a) : (((b) < (a) && (b) < (c)) ? (b) : (c))) +#define MAX3(a,b,c) (((a) > (b) && (a) > (c)) ? (a) : (((b) > (a) && (b) > (c)) ? (b) : (c))) +*/ + +VOID +SquareToPos(int row, int column, int * x, int * y) +{ + if (flipView) { + *x = boardRect.left + lineGap + ((BOARD_SIZE-1)-column) * (squareSize + lineGap); + *y = boardRect.top + lineGap + row * (squareSize + lineGap); + } else { + *x = boardRect.left + lineGap + column * (squareSize + lineGap); + *y = boardRect.top + lineGap + ((BOARD_SIZE-1)-row) * (squareSize + lineGap); + } +} + +VOID +DrawCoordsOnDC(HDC hdc) +{ + static char files[16] = {'1','2','3','4','5','6','7','8','8','7','6','5','4','3','2','1'}; + static char ranks[16] = {'h','g','f','e','d','c','b','a','a','b','c','d','e','f','g','h'}; + char str[2] = { NULLCHAR, NULLCHAR }; + int oldMode, oldAlign, x, y, start, i; + HFONT oldFont; + HBRUSH oldBrush; + + if (!appData.showCoords) + return; + + start = flipView ? 0 : 8; + + oldBrush = SelectObject(hdc, GetStockObject(BLACK_BRUSH)); + oldMode = SetBkMode(hdc, (appData.monoMode ? OPAQUE : TRANSPARENT)); + oldAlign = GetTextAlign(hdc); + oldFont = SelectObject(hdc, font[boardSize][COORD_FONT]->hf); + + y = boardRect.top + lineGap; + x = boardRect.left + lineGap; + + SetTextAlign(hdc, TA_LEFT|TA_TOP); + for (i = 0; i < 8; i++) { + str[0] = files[start + i]; + ExtTextOut(hdc, x + 2, y + 1, 0, NULL, str, 1, NULL); + y += squareSize + lineGap; + } + + SetTextAlign(hdc, TA_RIGHT|TA_BOTTOM); + for (i = 0; i < 8; i++) { + str[0] = ranks[start + i]; + ExtTextOut(hdc, x + squareSize - 2, y - 1, 0, NULL, str, 1, NULL); + x += squareSize + lineGap; + } + + SelectObject(hdc, oldBrush); + SetBkMode(hdc, oldMode); + SetTextAlign(hdc, oldAlign); + SelectObject(hdc, oldFont); +} + +VOID +DrawGridOnDC(HDC hdc) +{ + HPEN oldPen; + + if (lineGap != 0) { + oldPen = SelectObject(hdc, gridPen); + PolyPolyline(hdc, gridEndpoints, gridVertexCounts, BOARD_SIZE*2 + 2); + SelectObject(hdc, oldPen); + } +} + +#define HIGHLIGHT_PEN 0 +#define PREMOVE_PEN 1 + +VOID +DrawHighlightOnDC(HDC hdc, BOOLEAN on, int x, int y, int pen) +{ + int x1, y1; + HPEN oldPen, hPen; + if (lineGap == 0) return; + if (flipView) { + x1 = boardRect.left + + lineGap/2 + ((BOARD_SIZE-1)-x) * (squareSize + lineGap); + y1 = boardRect.top + + lineGap/2 + y * (squareSize + lineGap); + } else { + x1 = boardRect.left + + lineGap/2 + x * (squareSize + lineGap); + y1 = boardRect.top + + lineGap/2 + ((BOARD_SIZE-1)-y) * (squareSize + lineGap); + } + hPen = pen ? premovePen : highlightPen; + oldPen = SelectObject(hdc, on ? hPen : gridPen); + MoveToEx(hdc, x1, y1, NULL); + LineTo(hdc, x1 + squareSize + lineGap, y1); + LineTo(hdc, x1 + squareSize + lineGap, y1 + squareSize + lineGap); + LineTo(hdc, x1, y1 + squareSize + lineGap); + LineTo(hdc, x1, y1); + SelectObject(hdc, oldPen); +} + +VOID +DrawHighlightsOnDC(HDC hdc) +{ + int i; + for (i=0; i<2; i++) { + if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0) + DrawHighlightOnDC(hdc, TRUE, + highlightInfo.sq[i].x, highlightInfo.sq[i].y, + HIGHLIGHT_PEN); + } + for (i=0; i<2; i++) { + if (premoveHighlightInfo.sq[i].x >= 0 && + premoveHighlightInfo.sq[i].y >= 0) { + DrawHighlightOnDC(hdc, TRUE, + premoveHighlightInfo.sq[i].x, + premoveHighlightInfo.sq[i].y, + PREMOVE_PEN); + } + } +} + +/* Note: sqcolor is used only in monoMode */ +/* Note that this code is largely duplicated in woptions.c, + function DrawSampleSquare, so that needs to be updated too */ +VOID +DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y, HDC tmphdc) +{ + HBITMAP oldBitmap; + HBRUSH oldBrush; + + if (appData.blindfold) return; + + if (appData.monoMode) { + SelectObject(tmphdc, PieceBitmap(piece, + color == sqcolor ? OUTLINE_PIECE : SOLID_PIECE)); + BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0, + sqcolor ? SRCCOPY : NOTSRCCOPY); + } else { + if (color) { + oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE)); + oldBrush = SelectObject(hdc, whitePieceBrush); + BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0, 0x00B8074A); +#if 0 + /* Use black piece color for outline of white pieces */ + /* Not sure this looks really good (though xboard does it). + Maybe better to have another selectable color, default black */ + SelectObject(hdc, blackPieceBrush); /* could have own brush */ + SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE)); + BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0, 0x00B8074A); +#else + /* Use black for outline of white pieces */ + SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE)); + BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0, SRCAND); +#endif + } else { +#if 0 + /* Use white piece color for details of black pieces */ + /* Requires filled-in solid bitmaps (BLACK_PIECE class); the + WHITE_PIECE ones aren't always the right shape. */ + /* Not sure this looks really good (though xboard does it). + Maybe better to have another selectable color, default medium gray? */ + oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, BLACK_PIECE)); + oldBrush = SelectObject(hdc, whitePieceBrush); /* could have own brush */ + BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0, 0x00B8074A); + SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE)); + SelectObject(hdc, blackPieceBrush); + BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0, 0x00B8074A); +#else + /* Use square color for details of black pieces */ + oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE)); + oldBrush = SelectObject(hdc, blackPieceBrush); + BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0, 0x00B8074A); +#endif + } + SelectObject(hdc, oldBrush); + SelectObject(tmphdc, oldBitmap); + } +} + +VOID +DrawBoardOnDC(HDC hdc, Board board, HDC tmphdc) +{ + int row, column, x, y, square_color, piece_color; + ChessSquare piece; + HBRUSH oldBrush; + + for (row = 0; row < BOARD_SIZE; row++) { + for (column = 0; column < BOARD_SIZE; column++) { + + SquareToPos(row, column, &x, &y); + + piece = board[row][column]; + + square_color = ((column + row) % 2) == 1; + piece_color = (int) piece < (int) BlackPawn; + + if (appData.monoMode) { + if (piece == EmptySquare) { + BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0, + square_color ? WHITENESS : BLACKNESS); + } else { + DrawPieceOnDC(hdc, piece, piece_color, square_color, x, y, tmphdc); + } + } else { + oldBrush = SelectObject(hdc, square_color ? + lightSquareBrush : darkSquareBrush); + BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0, PATCOPY); + SelectObject(hdc, oldBrush); + if (piece != EmptySquare) + DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc); + } + } + } +} + +#define MAX_CLIPS 200 /* more than enough */ + +VOID +HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board) +{ + static Board lastReq, lastDrawn; + static HighlightInfo lastDrawnHighlight, lastDrawnPremove; + static int lastDrawnFlipView = 0; + static int lastReqValid = 0, lastDrawnValid = 0; + int releaseDC, x, y, x2, y2, row, column, num_clips = 0, i; + HDC tmphdc; + HDC hdcmem; + HBITMAP bufferBitmap; + HBITMAP oldBitmap; + RECT Rect; + HRGN clips[MAX_CLIPS]; + ChessSquare dragged_piece = EmptySquare; + + /* I'm undecided on this - this function figures out whether a full + * repaint is necessary on its own, so there's no real reason to have the + * caller tell it that. I think this can safely be set to FALSE - but + * if we trust the callers not to request full repaints unnessesarily, then + * we could skip some clipping work. In other words, only request a full + * redraw when the majority of pieces have changed positions (ie. flip, + * gamestart and similar) --Hawk + */ + Boolean fullrepaint = repaint; + + if (board == NULL) { + if (!lastReqValid) { + return; + } + board = lastReq; + } else { + CopyBoard(lastReq, board); + lastReqValid = 1; + } + + if (doingSizing) { + return; + } + + if (IsIconic(hwndMain)) { + return; + } + + if (hdc == NULL) { + hdc = GetDC(hwndMain); + if (!appData.monoMode) { + SelectPalette(hdc, hPal, FALSE); + RealizePalette(hdc); + } + releaseDC = TRUE; + } else { + releaseDC = FALSE; + } + +#if 0 + fprintf(debugFP, "*******************************\n" + "repaint = %s\n" + "dragInfo.from (%d,%d)\n" + "dragInfo.start (%d,%d)\n" + "dragInfo.pos (%d,%d)\n" + "dragInfo.lastpos (%d,%d)\n", + repaint ? "TRUE" : "FALSE", + dragInfo.from.x, dragInfo.from.y, + dragInfo.start.x, dragInfo.start.y, + dragInfo.pos.x, dragInfo.pos.y, + dragInfo.lastpos.x, dragInfo.lastpos.y); + fprintf(debugFP, "prev: "); + for (row = 0; row < 8; row++) { + for (column = 0; column < 8; column++) { + fprintf(debugFP, "%d ", lastDrawn[row][column]); + } + } + fprintf(debugFP, "\n"); + fprintf(debugFP, "board: "); + for (row = 0; row < 8; row++) { + for (column = 0; column < 8; column++) { + fprintf(debugFP, "%d ", board[row][column]); + } + } + fprintf(debugFP, "\n"); + fflush(debugFP); +#endif + + /* Create some work-DCs */ + hdcmem = CreateCompatibleDC(hdc); + tmphdc = CreateCompatibleDC(hdc); + + /* Figure out which squares need updating by comparing the + * newest board with the last drawn board and checking if + * flipping has changed. + */ + if (!fullrepaint && lastDrawnValid && lastDrawnFlipView == flipView) { + for (row = 0; row < 8; row++) { + for (column = 0; column < 8; column++) { + if (lastDrawn[row][column] != board[row][column]) { + SquareToPos(row, column, &x, &y); + clips[num_clips++] = + CreateRectRgn(x, y, x + squareSize, y + squareSize); + } + } + } + for (i=0; i<2; i++) { + if (lastDrawnHighlight.sq[i].x != highlightInfo.sq[i].x || + lastDrawnHighlight.sq[i].y != highlightInfo.sq[i].y) { + if (lastDrawnHighlight.sq[i].x >= 0 && + lastDrawnHighlight.sq[i].y >= 0) { + SquareToPos(lastDrawnHighlight.sq[i].y, + lastDrawnHighlight.sq[i].x, &x, &y); + clips[num_clips++] = + CreateRectRgn(x - lineGap, y - lineGap, + x + squareSize + lineGap, y + squareSize + lineGap); + } + if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0) { + SquareToPos(highlightInfo.sq[i].y, highlightInfo.sq[i].x, &x, &y); + clips[num_clips++] = + CreateRectRgn(x - lineGap, y - lineGap, + x + squareSize + lineGap, y + squareSize + lineGap); + } + } + } + for (i=0; i<2; i++) { + if (lastDrawnPremove.sq[i].x != premoveHighlightInfo.sq[i].x || + lastDrawnPremove.sq[i].y != premoveHighlightInfo.sq[i].y) { + if (lastDrawnPremove.sq[i].x >= 0 && + lastDrawnPremove.sq[i].y >= 0) { + SquareToPos(lastDrawnPremove.sq[i].y, + lastDrawnPremove.sq[i].x, &x, &y); + clips[num_clips++] = + CreateRectRgn(x - lineGap, y - lineGap, + x + squareSize + lineGap, y + squareSize + lineGap); + } + if (premoveHighlightInfo.sq[i].x >= 0 && + premoveHighlightInfo.sq[i].y >= 0) { + SquareToPos(premoveHighlightInfo.sq[i].y, + premoveHighlightInfo.sq[i].x, &x, &y); + clips[num_clips++] = + CreateRectRgn(x - lineGap, y - lineGap, + x + squareSize + lineGap, y + squareSize + lineGap); + } + } + } + } else { + fullrepaint = TRUE; + } + + /* Create a buffer bitmap - this is the actual bitmap + * being written to. When all the work is done, we can + * copy it to the real DC (the screen). This avoids + * the problems with flickering. + */ + GetClientRect(hwndMain, &Rect); + bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1, + Rect.bottom-Rect.top+1); + oldBitmap = SelectObject(hdcmem, bufferBitmap); + if (!appData.monoMode) { + SelectPalette(hdcmem, hPal, FALSE); + } + + /* Create clips for dragging */ + if (!fullrepaint) { + if (dragInfo.from.x >= 0) { + SquareToPos(dragInfo.from.y, dragInfo.from.x, &x, &y); + clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize); + } + if (dragInfo.start.x >= 0) { + SquareToPos(dragInfo.start.y, dragInfo.start.x, &x, &y); + clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize); + } + if (dragInfo.pos.x >= 0) { + x = dragInfo.pos.x - squareSize / 2; + y = dragInfo.pos.y - squareSize / 2; + clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize); + } + if (dragInfo.lastpos.x >= 0) { + x = dragInfo.lastpos.x - squareSize / 2; + y = dragInfo.lastpos.y - squareSize / 2; + clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize); + } + } + + /* If dragging is in progress, we temporarely remove the piece */ + if (dragInfo.from.x >= 0 && dragInfo.pos.x >= 0) { + dragged_piece = board[dragInfo.from.y][dragInfo.from.x]; + board[dragInfo.from.y][dragInfo.from.x] = EmptySquare; + } + + /* Are we animating a move? + * If so, + * - remove the piece from the board (temporarely) + * - calculate the clipping region + */ + if (!fullrepaint) { + if (animInfo.piece != EmptySquare) { + board[animInfo.from.y][animInfo.from.x] = EmptySquare; + x = boardRect.left + animInfo.lastpos.x; + y = boardRect.top + animInfo.lastpos.y; + x2 = boardRect.left + animInfo.pos.x; + y2 = boardRect.top + animInfo.pos.y; + clips[num_clips++] = CreateRectRgn(MIN(x,x2), MIN(y,y2), MAX(x,x2)+squareSize, MAX(y,y2)+squareSize); + /* Slight kludge. The real problem is that after AnimateMove is + done, the position on the screen does not match lastDrawn. + This currently causes trouble only on e.p. captures in + atomic, where the piece moves to an empty square and then + explodes. The old and new positions both had an empty square + at the destination, but animation has drawn a piece there and + we have to remember to erase it. */ + lastDrawn[animInfo.to.y][animInfo.to.x] = animInfo.piece; + } + } + + /* No clips? Make sure we have fullrepaint set to TRUE */ + if (num_clips == 0) + fullrepaint = TRUE; + + /* Set clipping on the memory DC */ + if (!fullrepaint) { + SelectClipRgn(hdcmem, clips[0]); + for (x = 1; x < num_clips; x++) { + if (ExtSelectClipRgn(hdcmem, clips[x], RGN_OR) == ERROR) + abort(); // this should never ever happen! + } + } + + /* Do all the drawing to the memory DC */ + DrawGridOnDC(hdcmem); + DrawHighlightsOnDC(hdcmem); + DrawBoardOnDC(hdcmem, board, tmphdc); + DrawCoordsOnDC(hdcmem); + + /* Put the dragged piece back into place and draw it */ + if (dragged_piece != EmptySquare) { + board[dragInfo.from.y][dragInfo.from.x] = dragged_piece; + x = dragInfo.pos.x - squareSize / 2; + y = dragInfo.pos.y - squareSize / 2; + DrawPieceOnDC(hdcmem, dragged_piece, + ((int) dragged_piece < (int) BlackPawn), + (dragInfo.from.y + dragInfo.from.x) % 2, x, y, tmphdc); + } + + /* Put the animated piece back into place and draw it */ + if (animInfo.piece != EmptySquare) { + board[animInfo.from.y][animInfo.from.x] = animInfo.piece; + x = boardRect.left + animInfo.pos.x; + y = boardRect.top + animInfo.pos.y; + DrawPieceOnDC(hdcmem, animInfo.piece, + ((int) animInfo.piece < (int) BlackPawn), + (animInfo.from.y + animInfo.from.x) % 2, x, y, tmphdc); + } + + /* Release the bufferBitmap by selecting in the old bitmap + * and delete the memory DC + */ + SelectObject(hdcmem, oldBitmap); + DeleteDC(hdcmem); + + /* Set clipping on the target DC */ + if (!fullrepaint) { + SelectClipRgn(hdc, clips[0]); + for (x = 1; x < num_clips; x++) { + if (ExtSelectClipRgn(hdc, clips[x], RGN_OR) == ERROR) + abort(); // this should never ever happen! + } + } + + /* Copy the new bitmap onto the screen in one go. + * This way we avoid any flickering + */ + oldBitmap = SelectObject(tmphdc, bufferBitmap); + BitBlt(hdc, boardRect.left, boardRect.top, + boardRect.right - boardRect.left, + boardRect.bottom - boardRect.top, + tmphdc, boardRect.left, boardRect.top, SRCCOPY); + SelectObject(tmphdc, oldBitmap); + + /* Massive cleanup */ + for (x = 0; x < num_clips; x++) + DeleteObject(clips[x]); + + DeleteDC(tmphdc); + DeleteObject(bufferBitmap); + + if (releaseDC) + ReleaseDC(hwndMain, hdc); + + if (lastDrawnFlipView != flipView) { + if (flipView) + CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_CHECKED); + else + CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_UNCHECKED); + } + + CopyBoard(lastDrawn, board); + lastDrawnHighlight = highlightInfo; + lastDrawnPremove = premoveHighlightInfo; + lastDrawnFlipView = flipView; + lastDrawnValid = 1; +} + + +/*---------------------------------------------------------------------------*\ +| CLIENT PAINT PROCEDURE +| This is the main event-handler for the WM_PAINT message. +| +\*---------------------------------------------------------------------------*/ +VOID +PaintProc(HWND hwnd) +{ + HDC hdc; + PAINTSTRUCT ps; + HFONT oldFont; + + if(hdc = BeginPaint(hwnd, &ps)) { + if (IsIconic(hwnd)) { + DrawIcon(hdc, 2, 2, iconCurrent); + } else { + if (!appData.monoMode) { + SelectPalette(hdc, hPal, FALSE); + RealizePalette(hdc); + } + HDCDrawPosition(hdc, 1, NULL); + oldFont = + SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf); + ExtTextOut(hdc, messageRect.left, messageRect.top, + ETO_CLIPPED|ETO_OPAQUE, + &messageRect, messageText, strlen(messageText), NULL); + SelectObject(hdc, oldFont); + DisplayBothClocks(); + } + EndPaint(hwnd,&ps); + } + + return; +} + + +/* + * If the user selects on a border boundary, return -1; if off the board, + * return -2. Otherwise map the event coordinate to the square. + * The offset boardRect.left or boardRect.top must already have been + * subtracted from x. + */ +int +EventToSquare(int x) +{ + if (x <= 0) + return -2; + if (x < lineGap) + return -1; + x -= lineGap; + if ((x % (squareSize + lineGap)) >= squareSize) + return -1; + x /= (squareSize + lineGap); + if (x >= BOARD_SIZE) + return -2; + return x; +} + +typedef struct { + char piece; + int command; + char* name; +} DropEnable; + +DropEnable dropEnables[] = { + { 'P', DP_Pawn, "Pawn" }, + { 'N', DP_Knight, "Knight" }, + { 'B', DP_Bishop, "Bishop" }, + { 'R', DP_Rook, "Rook" }, + { 'Q', DP_Queen, "Queen" }, +}; + +VOID +SetupDropMenu(HMENU hmenu) +{ + int i, count, enable; + char *p; + extern char white_holding[], black_holding[]; + char item[MSG_SIZ]; + + for (i=0; i 0 || !appData.testLegality + /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse + && !appData.icsActive); + ModifyMenu(hmenu, dropEnables[i].command, + MF_BYCOMMAND | (enable ? MF_ENABLED : MF_GRAYED) | MF_STRING, + dropEnables[i].command, item); + } +} + +static int fromX = -1, fromY = -1, toX, toY; + +/* Event handler for mouse messages */ +VOID +MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + int x, y; + POINT pt; + static int recursive = 0; + HMENU hmenu; + BOOLEAN saveAnimate; + static BOOLEAN sameAgain = FALSE; + + if (recursive) { + if (message == WM_MBUTTONUP) { + /* Hideous kludge to fool TrackPopupMenu into paying attention + to the middle button: we simulate pressing the left button too! + */ + PostMessage(hwnd, WM_LBUTTONDOWN, wParam, lParam); + PostMessage(hwnd, WM_LBUTTONUP, wParam, lParam); + } + return; + } + recursive++; + + pt.x = LOWORD(lParam); + pt.y = HIWORD(lParam); + x = EventToSquare(pt.x - boardRect.left); + y = EventToSquare(pt.y - boardRect.top); + if (!flipView && y >= 0) { + y = BOARD_SIZE - 1 - y; + } + if (flipView && x >= 0) { + x = BOARD_SIZE - 1 - x; + } + + switch (message) { + case WM_LBUTTONDOWN: + ErrorPopDown(); + sameAgain = FALSE; + if (y == -2) { + /* Downclick vertically off board; check if on clock */ + if (PtInRect((LPRECT) &whiteRect, pt)) { + if (gameMode == EditPosition) { + SetWhiteToPlayEvent(); + } else if (gameMode == IcsPlayingBlack || + gameMode == MachinePlaysWhite) { + CallFlagEvent(); + } + } else if (PtInRect((LPRECT) &blackRect, pt)) { + if (gameMode == EditPosition) { + SetBlackToPlayEvent(); + } else if (gameMode == IcsPlayingWhite || + gameMode == MachinePlaysBlack) { + CallFlagEvent(); + } + } + if (!appData.highlightLastMove) { + ClearHighlights(); + DrawPosition(FALSE, NULL); + } + fromX = fromY = -1; + dragInfo.start.x = dragInfo.start.y = -1; + dragInfo.from = dragInfo.start; + break; + } else if (x < 0 || y < 0) { + break; + } else if (fromX == x && fromY == y) { + /* Downclick on same square again */ + ClearHighlights(); + DrawPosition(FALSE, NULL); + sameAgain = TRUE; + } else if (fromX != -1) { + /* Downclick on different square */ + ChessSquare pdown, pup; + pdown = boards[currentMove][fromY][fromX]; + pup = boards[currentMove][y][x]; + if (gameMode == EditPosition || + !((WhitePawn <= pdown && pdown <= WhiteKing && + WhitePawn <= pup && pup <= WhiteKing) || + (BlackPawn <= pdown && pdown <= BlackKing && + BlackPawn <= pup && pup <= BlackKing))) { + /* EditPosition, empty square, or different color piece; + click-click move is possible */ + toX = x; + toY = y; + if (IsPromotion(fromX, fromY, toX, toY)) { + if (appData.alwaysPromoteToQueen) { + UserMoveEvent(fromX, fromY, toX, toY, 'q'); + if (!appData.highlightLastMove) { + ClearHighlights(); + DrawPosition(FALSE, NULL); + } + } else { + SetHighlights(fromX, fromY, toX, toY); + DrawPosition(FALSE, NULL); + PromotionPopup(hwnd); + } + } else { /* not a promotion */ + if (appData.animate || appData.highlightLastMove) { + SetHighlights(fromX, fromY, toX, toY); + } else { + ClearHighlights(); + } + UserMoveEvent(fromX, fromY, toX, toY, NULLCHAR); + if (appData.animate && !appData.highlightLastMove) { + ClearHighlights(); + DrawPosition(FALSE, NULL); + } + } + if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY); + fromX = fromY = -1; + break; + } + ClearHighlights(); + DrawPosition(FALSE, NULL); + } + /* First downclick, or restart on a square with same color piece */ + if (!frozen && OKToStartUserMove(x, y)) { + fromX = x; + fromY = y; + dragInfo.lastpos = pt; + dragInfo.from.x = fromX; + dragInfo.from.y = fromY; + dragInfo.start = dragInfo.from; + SetCapture(hwndMain); + } else { + fromX = fromY = -1; + dragInfo.start.x = dragInfo.start.y = -1; + dragInfo.from = dragInfo.start; + } + break; + + case WM_LBUTTONUP: + ReleaseCapture(); + if (fromX == -1) break; + if (x == fromX && y == fromY) { + dragInfo.from.x = dragInfo.from.y = -1; + /* Upclick on same square */ + if (sameAgain) { + /* Clicked same square twice: abort click-click move */ + fromX = fromY = -1; + gotPremove = 0; + ClearPremoveHighlights(); + } else { + /* First square clicked: start click-click move */ + SetHighlights(fromX, fromY, -1, -1); + } + DrawPosition(FALSE, NULL); + } else if (dragInfo.from.x < 0 || dragInfo.from.y < 0) { + /* Errant click; ignore */ + break; + } else { + /* Finish drag move */ + dragInfo.from.x = dragInfo.from.y = -1; + toX = x; + toY = y; + saveAnimate = appData.animate; /* sorry, Hawk :) */ + appData.animate = appData.animate && !appData.animateDragging; + if (IsPromotion(fromX, fromY, toX, toY)) { + if (appData.alwaysPromoteToQueen) { + UserMoveEvent(fromX, fromY, toX, toY, 'q'); + } else { + DrawPosition(FALSE, NULL); + PromotionPopup(hwnd); + } + } else { + UserMoveEvent(fromX, fromY, toX, toY, NULLCHAR); + } + if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY); + appData.animate = saveAnimate; + fromX = fromY = -1; + if (appData.highlightDragging && !appData.highlightLastMove) { + ClearHighlights(); + } + if (appData.animate || appData.animateDragging || + appData.highlightDragging || gotPremove) { + DrawPosition(FALSE, NULL); + } + } + dragInfo.start.x = dragInfo.start.y = -1; + dragInfo.pos = dragInfo.lastpos = dragInfo.start; + break; + + case WM_MOUSEMOVE: + if ((appData.animateDragging || appData.highlightDragging) + && (wParam & MK_LBUTTON) + && dragInfo.from.x >= 0) { + if (appData.animateDragging) { + dragInfo.pos = pt; + } + if (appData.highlightDragging) { + SetHighlights(fromX, fromY, x, y); + } + DrawPosition(FALSE, NULL); + dragInfo.lastpos = dragInfo.pos; + } + break; + case WM_MOUSEWHEEL: + { + signed short u = HIWORD(wParam); + fprintf(debugFP, "mouse\n"); + + /* Example: if the mouse wheel is brought forward one click, u is 120. Two clicks, its 240. + if the mouse wheel is brought back one click, its -120, two clicks, -240, etc. */ + + if (u && !(u%WHEEL_DELTA)) { + while(u) { + if (u>0) { + u -= WHEEL_DELTA; + ForwardEvent(); + SetFocus(hwndMain); + } else { + u+= WHEEL_DELTA; + BackwardEvent(); + SetFocus(hwndMain); + } + } + } + } + break; + case WM_MBUTTONDOWN: + case WM_RBUTTONDOWN: + ErrorPopDown(); + ReleaseCapture(); + fromX = fromY = -1; + dragInfo.pos.x = dragInfo.pos.y = -1; + dragInfo.start.x = dragInfo.start.y = -1; + dragInfo.from = dragInfo.start; + dragInfo.lastpos = dragInfo.pos; + if (appData.highlightDragging) { + ClearHighlights(); + } + DrawPosition(TRUE, NULL); + + switch (gameMode) { + case EditPosition: + case IcsExamining: + if (x < 0 || y < 0) break; + fromX = x; + fromY = y; + if (message == WM_MBUTTONDOWN) { + buttonCount = 3; /* even if system didn't think so */ + if (wParam & MK_SHIFT) + MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1); + else + MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1); + } else { /* message == WM_RBUTTONDOWN */ +#if 0 + if (buttonCount == 3) { + if (wParam & MK_SHIFT) + MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1); + else + MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1); + } else { + MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1); + } +#else + /* Just have one menu, on the right button. Windows users don't + think to try the middle one, and sometimes other software steals + it, or it doesn't really exist. */ + MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1); +#endif + } + break; + case IcsPlayingWhite: + case IcsPlayingBlack: + case EditGame: + case MachinePlaysWhite: + case MachinePlaysBlack: + if (appData.testLegality && + gameInfo.variant != VariantBughouse && + gameInfo.variant != VariantCrazyhouse) break; + if (x < 0 || y < 0) break; + fromX = x; + fromY = y; + hmenu = LoadMenu(hInst, "DropPieceMenu"); + SetupDropMenu(hmenu); + MenuPopup(hwnd, pt, hmenu, -1); + break; + default: + break; + } + break; + } + + recursive--; +} + +/* Preprocess messages for buttons in main window */ +LRESULT CALLBACK +ButtonProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + int id = GetWindowLong(hwnd, GWL_ID); + int i, dir; + + for (i=0; inumber > 1) { + GameListPopUp(f, fileTitle); + return; + } + GameListDestroy(); + number = 1; + } + LoadGame(f, number, fileTitle, FALSE); + } +} + +VOID +ChangedConsoleFont() +{ + CHARFORMAT cfmt; + CHARRANGE tmpsel, sel; + MyFont *f = font[boardSize][CONSOLE_FONT]; + HWND hText = GetDlgItem(hwndConsole, OPT_ConsoleText); + HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput); + PARAFORMAT paraf; + + cfmt.cbSize = sizeof(CHARFORMAT); + cfmt.dwMask = CFM_FACE|CFM_SIZE|CFM_CHARSET; + strcpy(cfmt.szFaceName, font[boardSize][CONSOLE_FONT]->mfp.faceName); + /* yHeight is expressed in twips. A twip is 1/20 of a font's point + * size. This was undocumented in the version of MSVC++ that I had + * when I wrote the code, but is apparently documented now. + */ + cfmt.yHeight = (int)(f->mfp.pointSize * 20.0 + 0.5); + cfmt.bCharSet = f->lf.lfCharSet; + cfmt.bPitchAndFamily = f->lf.lfPitchAndFamily; + SendMessage(hText, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt); + SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt); + /* Why are the following seemingly needed too? */ + SendMessage(hText, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt); + SendMessage(hInput, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt); + SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&sel); + tmpsel.cpMin = 0; + tmpsel.cpMax = -1; /*999999?*/ + SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&tmpsel); + SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cfmt); + /* Trying putting this here too. It still seems to tickle a RichEdit + * bug: sometimes RichEdit indents the first line of a paragraph too. + */ + paraf.cbSize = sizeof(paraf); + paraf.dwMask = PFM_OFFSET | PFM_STARTINDENT; + paraf.dxStartIndent = 0; + paraf.dxOffset = WRAP_INDENT; + SendMessage(hText, EM_SETPARAFORMAT, 0, (LPARAM) ¶f); + SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel); +} + +/*---------------------------------------------------------------------------*\ + * + * Window Proc for main window + * +\*---------------------------------------------------------------------------*/ + +/* Process messages for main window, etc. */ +LRESULT CALLBACK +WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + FARPROC lpProc; + int wmId, wmEvent; + char *defName; + FILE *f; + UINT number; + char fileTitle[MSG_SIZ]; + + switch (message) { + + case WM_PAINT: /* message: repaint portion of window */ + PaintProc(hwnd); + break; + + case WM_ERASEBKGND: + if (IsIconic(hwnd)) { + /* Cheat; change the message */ + return (DefWindowProc(hwnd, WM_ICONERASEBKGND, wParam, lParam)); + } else { + return (DefWindowProc(hwnd, message, wParam, lParam)); + } + break; + + case WM_LBUTTONDOWN: + case WM_MBUTTONDOWN: + case WM_RBUTTONDOWN: + case WM_LBUTTONUP: + case WM_MBUTTONUP: + case WM_RBUTTONUP: + case WM_MOUSEMOVE: + case WM_MOUSEWHEEL: + MouseEvent(hwnd, message, wParam, lParam); + break; + + case WM_CHAR: + + if (appData.icsActive) { + if (wParam == '\t') { + if (GetKeyState(VK_SHIFT) < 0) { + /* shifted */ + HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput); + if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE); + SetFocus(h); + } else { + /* unshifted */ + HWND h = GetDlgItem(hwndConsole, OPT_ConsoleText); + if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE); + SetFocus(h); + } + } else { + HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput); + if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE); + SetFocus(h); + SendMessage(h, message, wParam, lParam); + } + } else if (isalpha((char)wParam) || isdigit((char)wParam)) { + PopUpMoveDialog((char)wParam); + } + break; + + case WM_PALETTECHANGED: + if (hwnd != (HWND)wParam && !appData.monoMode) { + int nnew; + HDC hdc = GetDC(hwndMain); + SelectPalette(hdc, hPal, TRUE); + nnew = RealizePalette(hdc); + if (nnew > 0) { + paletteChanged = TRUE; +#if 0 + UpdateColors(hdc); +#else + InvalidateRect(hwnd, &boardRect, FALSE);/*faster!*/ +#endif + } + ReleaseDC(hwnd, hdc); + } + break; + + case WM_QUERYNEWPALETTE: + if (!appData.monoMode /*&& paletteChanged*/) { + int nnew; + HDC hdc = GetDC(hwndMain); + paletteChanged = FALSE; + SelectPalette(hdc, hPal, FALSE); + nnew = RealizePalette(hdc); + if (nnew > 0) { + InvalidateRect(hwnd, &boardRect, FALSE); + } + ReleaseDC(hwnd, hdc); + return TRUE; + } + return FALSE; + + case WM_COMMAND: /* message: command from application menu */ + wmId = LOWORD(wParam); + wmEvent = HIWORD(wParam); + + switch (wmId) { + case IDM_NewGame: + ResetGameEvent(); + /* try without */ + /*AnalysisPopDown(); */ + break; + + case IDM_LoadGame: + LoadGameDialog(hwnd, "Load Game from File"); + break; + + case IDM_LoadNextGame: + ReloadGame(1); + break; + + case IDM_LoadPrevGame: + ReloadGame(-1); + break; + + case IDM_ReloadGame: + ReloadGame(0); + break; + + case IDM_LoadPosition: + if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) { + Reset(FALSE, TRUE); + } + number = 1; + f = OpenFileDialog(hwnd, FALSE, "", + appData.oldSaveStyle ? "pos" : "fen", + POSITION_FILT, + "Load Position from File", &number, fileTitle, NULL); + if (f != NULL) { + LoadPosition(f, number, fileTitle); + } + break; + + case IDM_LoadNextPosition: + ReloadPosition(1); + break; + + case IDM_LoadPrevPosition: + ReloadPosition(-1); + break; + + case IDM_ReloadPosition: + ReloadPosition(0); + break; + + case IDM_SaveGame: + defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn"); + f = OpenFileDialog(hwnd, TRUE, defName, + appData.oldSaveStyle ? "gam" : "pgn", + GAME_FILT, + "Save Game to File", NULL, fileTitle, NULL); + if (f != NULL) { + SaveGame(f, 0, ""); + } + break; + + case IDM_SavePosition: + defName = DefaultFileName(appData.oldSaveStyle ? "pos" : "fen"); + f = OpenFileDialog(hwnd, TRUE, defName, + appData.oldSaveStyle ? "pos" : "fen", + POSITION_FILT, + "Save Position to File", NULL, fileTitle, NULL); + if (f != NULL) { + SavePosition(f, 0, ""); + } + break; + + case IDM_CopyGame: + CopyGameToClipboard(); + break; + + case IDM_PasteGame: + PasteGameFromClipboard(); + break; + + case IDM_CopyPosition: + CopyFENToClipboard(); + break; + + case IDM_PastePosition: + PasteFENFromClipboard(); + break; + + case IDM_MailMove: + MailMoveEvent(); + break; + + case IDM_ReloadCMailMsg: + Reset(TRUE, TRUE); + ReloadCmailMsgEvent(FALSE); + break; + + case IDM_Minimize: + ShowWindow(hwnd, SW_MINIMIZE); + break; + + case IDM_focus_EngineRoom: + SetFocus(analysisDialog); + break; + + case IDM_focus_wb: + SetFocus(hwndMain); + break; + + case IDM_Exit: + ExitEvent(0); + break; + + case IDM_MachineWhite: + MachineWhiteEvent(); + /* + * refresh the tags dialog only if it's visible + */ + if (gameMode == MachinePlaysWhite && IsWindowVisible(editTagsDialog)) { + char *tags; + tags = PGNTags(&gameInfo); + TagsPopUp(tags, CmailMsg()); + free(tags); + } + break; + + case IDM_MachineBlack: + MachineBlackEvent(); + /* + * refresh the tags dialog only if it's visible + */ + if (gameMode == MachinePlaysBlack && IsWindowVisible(editTagsDialog)) { + char *tags; + tags = PGNTags(&gameInfo); + TagsPopUp(tags, CmailMsg()); + free(tags); + } + break; + + case IDM_TwoMachines: + TwoMachinesEvent(); + /* + * refresh the tags dialog only if it's visible + */ + if (gameMode == TwoMachinesPlay && IsWindowVisible(editTagsDialog)) { + char *tags; + tags = PGNTags(&gameInfo); + TagsPopUp(tags, CmailMsg()); + free(tags); + } + break; + + case IDM_AnalysisMode: + if (!first.analysisSupport) { + char buf[MSG_SIZ]; + sprintf(buf, "%s does not support analysis", first.tidy); + DisplayError(buf, 0); + } else { + if (!appData.showThinking) ToggleShowThinking(); + AnalyzeModeEvent(); + } + break; + + case IDM_AnalyzeFile: + if (!first.analysisSupport) { + char buf[MSG_SIZ]; + sprintf(buf, "%s does not support analysis", first.tidy); + DisplayError(buf, 0); + } else { + if (!appData.showThinking) ToggleShowThinking(); + AnalyzeFileEvent(); + LoadGameDialog(hwnd, "Analyze Game from File"); + AnalysisPeriodicEvent(1); + } + break; + + case IDM_IcsClient: + IcsClientEvent(); + break; + + case IDM_EditGame: + EditGameEvent(); + break; + + case IDM_EditPosition: + EditPositionEvent(); + break; + + case IDM_Training: + TrainingEvent(); + break; + + case IDM_ShowGameList: + ShowGameListProc(); + break; + + case IDM_EditTags: + EditTagsProc(); + break; + + case IDM_EditComment: + if (commentDialogUp && editComment) { + CommentPopDown(); + } else { + EditCommentEvent(); + } + break; + + case IDM_Pause: + PauseEvent(); + break; + + case IDM_Accept: + AcceptEvent(); + break; + + case IDM_Decline: + DeclineEvent(); + break; + + case IDM_Rematch: + RematchEvent(); + break; + + case IDM_CallFlag: + CallFlagEvent(); + break; + + case IDM_Draw: + DrawEvent(); + break; + + case IDM_Adjourn: + AdjournEvent(); + break; + + case IDM_Abort: + AbortEvent(); + break; + + case IDM_Resign: + ResignEvent(); + break; + + case IDM_StopObserving: + StopObservingEvent(); + break; + + case IDM_StopExamining: + StopExaminingEvent(); + break; + + case IDM_TypeInMove: + PopUpMoveDialog('\000'); + break; + + case IDM_Backward: + BackwardEvent(); + SetFocus(hwndMain); + break; + + case IDM_Forward: + ForwardEvent(); + SetFocus(hwndMain); + break; + + case IDM_ToStart: + ToStartEvent(); + SetFocus(hwndMain); + break; + + case IDM_ToEnd: + ToEndEvent(); + SetFocus(hwndMain); + break; + + case IDM_Revert: + RevertEvent(); + break; + + case IDM_TruncateGame: + TruncateGameEvent(); + break; + + case IDM_MoveNow: + MoveNowEvent(); + break; + + case IDM_RetractMove: + RetractMoveEvent(); + break; + + case IDM_FlipView: + flipView = !flipView; + DrawPosition(FALSE, NULL); + break; + + case IDM_GeneralOptions: + GeneralOptionsPopup(hwnd); + break; + + case IDM_BoardOptions: + BoardOptionsPopup(hwnd); + break; + + case IDM_IcsOptions: + IcsOptionsPopup(hwnd); + break; + + case IDM_ZippyDraw: + icsZippyDrawPopUp(hwnd); + break; + + case IDM_Fonts: + FontsOptionsPopup(hwnd); + break; + + case IDM_Sounds: + SoundOptionsPopup(hwnd); + break; + + case IDM_CommPort: + CommPortOptionsPopup(hwnd); + break; + + case IDM_LoadOptions: + LoadOptionsPopup(hwnd); + break; + + case IDM_SaveOptions: + SaveOptionsPopup(hwnd); + break; + + case IDM_TimeControl: + TimeControlOptionsPopup(hwnd); + break; + + case IDM_SaveSettings: + SaveSettings(settingsFileName); + break; + + case IDM_SaveSettingsOnExit: + saveSettingsOnExit = !saveSettingsOnExit; + (void) CheckMenuItem(GetMenu(hwndMain), IDM_SaveSettingsOnExit, + MF_BYCOMMAND|(saveSettingsOnExit ? + MF_CHECKED : MF_UNCHECKED)); + break; + + case IDM_Hint: + HintEvent(); + break; + + case IDM_Book: + BookEvent(); + break; + + case IDM_AboutGame: + AboutGameEvent(); + break; + + case IDM_Debug: + appData.debugMode = !appData.debugMode; + if (appData.debugMode) { + char dir[MSG_SIZ]; + GetCurrentDirectory(MSG_SIZ, dir); + SetCurrentDirectory(installDir); + debugFP = fopen("WinBoard.debug", "w"); + SetCurrentDirectory(dir); + setbuf(debugFP, NULL); + } else { + fclose(debugFP); + debugFP = NULL; + } + break; + + case IDM_HELPCONTENTS: + if (!WinHelp (hwnd, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) { + MessageBox (GetFocus(), + "Unable to activate help", + szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND); + } + break; + + case IDM_HELPSEARCH: + if (!WinHelp(hwnd, "winboard.hlp", HELP_PARTIALKEY, (DWORD)(LPSTR)"")) { + MessageBox (GetFocus(), + "Unable to activate help", + szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND); + } + break; + + case IDM_HELPHELP: + if(!WinHelp(hwnd, (LPSTR)NULL, HELP_HELPONHELP, 0)) { + MessageBox (GetFocus(), + "Unable to activate help", + szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND); + } + break; + + case IDM_ABOUT: + lpProc = MakeProcInstance((FARPROC)About, hInst); + DialogBox(hInst, + (gameInfo.event && strcmp(gameInfo.event, "Easter Egg Hunt") == 0) ? + "AboutBox2" : "AboutBox", hwnd, (DLGPROC)lpProc); + FreeProcInstance(lpProc); + break; + + case IDM_DirectCommand1: + AskQuestionEvent("Direct Command", + "Send to chess program:", "", "1"); + break; + case IDM_DirectCommand2: + AskQuestionEvent("Direct Command", + "Send to second chess program:", "", "2"); + break; + + case EP_WhitePawn: + EditPositionMenuEvent(WhitePawn, fromX, fromY); + fromX = fromY = -1; + break; + + case EP_WhiteKnight: + EditPositionMenuEvent(WhiteKnight, fromX, fromY); + fromX = fromY = -1; + break; + + case EP_WhiteBishop: + EditPositionMenuEvent(WhiteBishop, fromX, fromY); + fromX = fromY = -1; + break; + + case EP_WhiteRook: + EditPositionMenuEvent(WhiteRook, fromX, fromY); + fromX = fromY = -1; + break; + + case EP_WhiteQueen: + EditPositionMenuEvent(WhiteQueen, fromX, fromY); + fromX = fromY = -1; + break; + + case EP_WhiteKing: + EditPositionMenuEvent(WhiteKing, fromX, fromY); + fromX = fromY = -1; + break; + + case EP_BlackPawn: + EditPositionMenuEvent(BlackPawn, fromX, fromY); + fromX = fromY = -1; + break; + + case EP_BlackKnight: + EditPositionMenuEvent(BlackKnight, fromX, fromY); + fromX = fromY = -1; + break; + + case EP_BlackBishop: + EditPositionMenuEvent(BlackBishop, fromX, fromY); + fromX = fromY = -1; + break; + + case EP_BlackRook: + EditPositionMenuEvent(BlackRook, fromX, fromY); + fromX = fromY = -1; + break; + + case EP_BlackQueen: + EditPositionMenuEvent(BlackQueen, fromX, fromY); + fromX = fromY = -1; + break; + + case EP_BlackKing: + EditPositionMenuEvent(BlackKing, fromX, fromY); + fromX = fromY = -1; + break; + + case EP_EmptySquare: + EditPositionMenuEvent(EmptySquare, fromX, fromY); + fromX = fromY = -1; + break; + + case EP_ClearBoard: + EditPositionMenuEvent(ClearBoard, fromX, fromY); + fromX = fromY = -1; + break; + + case EP_White: + EditPositionMenuEvent(WhitePlay, fromX, fromY); + fromX = fromY = -1; + break; + + case EP_Black: + EditPositionMenuEvent(BlackPlay, fromX, fromY); + fromX = fromY = -1; + break; + + case DP_Pawn: + DropMenuEvent(WhitePawn, fromX, fromY); + fromX = fromY = -1; + break; + + case DP_Knight: + DropMenuEvent(WhiteKnight, fromX, fromY); + fromX = fromY = -1; + break; + + case DP_Bishop: + DropMenuEvent(WhiteBishop, fromX, fromY); + fromX = fromY = -1; + break; + + case DP_Rook: + DropMenuEvent(WhiteRook, fromX, fromY); + fromX = fromY = -1; + break; + + case DP_Queen: + DropMenuEvent(WhiteQueen, fromX, fromY); + fromX = fromY = -1; + break; + + default: + return (DefWindowProc(hwnd, message, wParam, lParam)); + } + break; + + case WM_TIMER: + switch (wParam) { + case CLOCK_TIMER_ID: + KillTimer(hwnd, clockTimerEvent); /* Simulate one-shot timer as in X */ + clockTimerEvent = 0; + DecrementClocks(); /* call into back end */ + break; + case LOAD_GAME_TIMER_ID: + KillTimer(hwnd, loadGameTimerEvent); /* Simulate one-shot timer as in X*/ + loadGameTimerEvent = 0; + AutoPlayGameLoop(); /* call into back end */ + break; + case ANALYSIS_TIMER_ID: + /* dirty hack without stat line and support */ + if ((gameMode == AnalyzeMode || gameMode == AnalyzeFile || + appData.icsAnalyzeWindow || appData.AnalysisWindow) && + appData.periodicUpdates) { + AnalysisPeriodicEvent(0); + } else { + KillTimer(hwnd, analysisTimerEvent); + analysisTimerEvent = 0; + } + break; + case DELAYED_TIMER_ID: + KillTimer(hwnd, delayedTimerEvent); + delayedTimerEvent = 0; + delayedTimerCallback(); + break; + } + break; + + case WM_USER_Input: + InputEvent(hwnd, message, wParam, lParam); + break; + + case WM_ENTERSIZEMOVE: + if (hwnd == hwndMain) { + doingSizing = TRUE; + lastSizing = 0; + } + break; + + case WM_SIZING: + if (hwnd == hwndMain) { + lastSizing = wParam; + } + break; + + case WM_EXITSIZEMOVE: + if (hwnd == hwndMain) { + RECT client; + doingSizing = FALSE; + InvalidateRect(hwnd, &boardRect, FALSE); + GetClientRect(hwnd, &client); + ResizeBoard(client.right, client.bottom, lastSizing); + lastSizing = 0; + } + break; + + case WM_DESTROY: /* message: window being destroyed */ + PostQuitMessage(0); + break; + + case WM_CLOSE: + if (hwnd == hwndMain) { + ExitEvent(0); + } + break; + + default: /* Passes it on if unprocessed */ + return (DefWindowProc(hwnd, message, wParam, lParam)); + } + return 0; +} + +/*---------------------------------------------------------------------------*\ + * + * Misc utility routines + * +\*---------------------------------------------------------------------------*/ + +/* + * returns TRUE if user selects a different color, FALSE otherwise + */ + +BOOL +ChangeColor(HWND hwnd, COLORREF *which) +{ + static BOOL firstTime = TRUE; + static DWORD customColors[16]; + CHOOSECOLOR cc; + COLORREF newcolor; + int i; + ColorClass ccl; + + if (firstTime) { + /* Make initial colors in use available as custom colors */ + /* Should we put the compiled-in defaults here instead? */ + i = 0; + customColors[i++] = lightSquareColor & 0xffffff; + customColors[i++] = darkSquareColor & 0xffffff; + customColors[i++] = whitePieceColor & 0xffffff; + customColors[i++] = blackPieceColor & 0xffffff; + customColors[i++] = highlightSquareColor & 0xffffff; + customColors[i++] = premoveHighlightColor & 0xffffff; + + for (ccl = (ColorClass) 0; ccl < NColorClasses && i < 16; ccl++) { + customColors[i++] = textAttribs[ccl].color; + } + while (i < 16) customColors[i++] = RGB(255, 255, 255); + firstTime = FALSE; + } + + cc.lStructSize = sizeof(cc); + cc.hwndOwner = hwnd; + cc.hInstance = NULL; + cc.rgbResult = (DWORD) (*which & 0xffffff); + cc.lpCustColors = (LPDWORD) customColors; + cc.Flags = CC_RGBINIT|CC_FULLOPEN; + + if (!ChooseColor(&cc)) return FALSE; + + newcolor = (COLORREF) (0x2000000 | cc.rgbResult); + if (newcolor == *which) return FALSE; + *which = newcolor; + return TRUE; + + /* + InitDrawingColors(); + InvalidateRect(hwnd, &boardRect, FALSE); + */ +} + +BOOLEAN +MyLoadSound(MySound *ms) +{ + BOOL ok = FALSE; + struct stat st; + FILE *f; + + if (ms->data) free(ms->data); + ms->data = NULL; + + switch (ms->name[0]) { + case NULLCHAR: + /* Silence */ + ok = TRUE; + break; + case '$': + /* System sound from Control Panel. Don't preload here. */ + ok = TRUE; + break; + case '!': + if (ms->name[1] == NULLCHAR) { + /* "!" alone = silence */ + ok = TRUE; + } else { + /* Builtin wave resource. Error if not found. */ + HANDLE h = FindResource(hInst, ms->name + 1, "WAVE"); + if (h == NULL) break; + ms->data = (void *)LoadResource(hInst, h); + if (h == NULL) break; + ok = TRUE; + } + break; + default: + /* .wav file. Error if not found. */ + f = fopen(ms->name, "rb"); + if (f == NULL) break; + if (fstat(fileno(f), &st) < 0) break; + ms->data = malloc(st.st_size); + if (fread(ms->data, st.st_size, 1, f) < 1) break; + fclose(f); + ok = TRUE; + break; + } + if (!ok) { + char buf[MSG_SIZ]; + sprintf(buf, "Error loading sound %s", ms->name); + DisplayError(buf, GetLastError()); + } + return ok; +} + +BOOLEAN +MyPlaySound(MySound *ms) +{ + BOOLEAN ok = FALSE; + switch (ms->name[0]) { + case NULLCHAR: + /* Silence */ + ok = TRUE; + break; + case '$': + /* System sound from Control Panel (deprecated feature). + "$" alone or an unset sound name gets default beep (still in use). */ + if (ms->name[1]) { + ok = PlaySound(ms->name + 1, NULL, SND_ALIAS|SND_ASYNC); + } + if (!ok) ok = MessageBeep(MB_OK); + break; + case '!': + /* Builtin wave resource, or "!" alone for silence */ + if (ms->name[1]) { + if (ms->data == NULL) return FALSE; + ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC); + } else { + ok = TRUE; + } + break; + default: + /* .wav file. Error if not found. */ + if (ms->data == NULL) return FALSE; + ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC); + break; + } + /* Don't print an error: this can happen innocently if the sound driver + is busy; for instance, if another instance of WinBoard is playing + a sound at about the same time. */ +#if 0 + if (!ok) { + char buf[MSG_SIZ]; + sprintf(buf, "Error playing sound %s", ms->name); + DisplayError(buf, GetLastError()); + } +#endif + return ok; +} + + +LRESULT CALLBACK +OldOpenFileHook(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + BOOL ok; + OPENFILENAME *ofn; + static UINT *number; /* gross that this is static */ + + switch (message) { + case WM_INITDIALOG: /* message: initialize dialog box */ + /* Center the dialog over the application window */ + ofn = (OPENFILENAME *) lParam; + if (ofn->Flags & OFN_ENABLETEMPLATE) { + number = (UINT *) ofn->lCustData; + SendMessage(GetDlgItem(hDlg, edt2), WM_SETTEXT, 0, (LPARAM) ""); + } else { + number = NULL; + } + CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER)); + return FALSE; /* Allow for further processing */ + + case WM_COMMAND: + if ((LOWORD(wParam) == IDOK) && (number != NULL)) { + *number = GetDlgItemInt(hDlg, OPT_IndexNumberOld, &ok, FALSE); + } + return FALSE; /* Allow for further processing */ + } + return FALSE; +} + +UINT APIENTRY +OpenFileHook(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam) +{ + static UINT *number; + OPENFILENAME *ofname; + OFNOTIFY *ofnot; + switch (uiMsg) { + case WM_INITDIALOG: + ofname = (OPENFILENAME *)lParam; + number = (UINT *)(ofname->lCustData); + break; + case WM_NOTIFY: + ofnot = (OFNOTIFY *)lParam; + if (ofnot->hdr.code == CDN_FILEOK) { + *number = GetDlgItemInt(hdlg, OPT_IndexNumber, NULL, FALSE); + } + break; + } + return 0; +} + + +FILE * +OpenFileDialog(HWND hwnd, BOOL write, char *defName, char *defExt, + char *nameFilt, char *dlgTitle, UINT *number, + char fileTitle[MSG_SIZ], char fileName[MSG_SIZ]) +{ + OPENFILENAME openFileName; + char buf1[MSG_SIZ]; + FILE *f; + + if (fileName == NULL) fileName = buf1; + if (defName == NULL) { + strcpy(fileName, "*."); + strcat(fileName, defExt); + } else { + strcpy(fileName, defName); + } + if (fileTitle) strcpy(fileTitle, ""); + if (number) *number = 0; + + openFileName.lStructSize = sizeof(OPENFILENAME); + openFileName.hwndOwner = hwnd; + openFileName.hInstance = (HANDLE) hInst; + openFileName.lpstrFilter = nameFilt; + openFileName.lpstrCustomFilter = (LPSTR) NULL; + openFileName.nMaxCustFilter = 0L; + openFileName.nFilterIndex = 1L; + openFileName.lpstrFile = fileName; + openFileName.nMaxFile = MSG_SIZ; + openFileName.lpstrFileTitle = fileTitle; + openFileName.nMaxFileTitle = fileTitle ? MSG_SIZ : 0; + openFileName.lpstrInitialDir = NULL; + openFileName.lpstrTitle = dlgTitle; + openFileName.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY + | (write ? 0 : OFN_FILEMUSTEXIST) + | (number ? OFN_ENABLETEMPLATE | OFN_ENABLEHOOK: 0) + | (oldDialog ? 0 : OFN_EXPLORER); + openFileName.nFileOffset = 0; + openFileName.nFileExtension = 0; + openFileName.lpstrDefExt = defExt; + openFileName.lCustData = (LONG) number; + openFileName.lpfnHook = oldDialog ? + (LPOFNHOOKPROC) OldOpenFileHook : (LPOFNHOOKPROC) OpenFileHook; + openFileName.lpTemplateName = (LPSTR)(oldDialog ? 1536 : DLG_IndexNumber); + + if (write ? GetSaveFileName(&openFileName) : + GetOpenFileName(&openFileName)) { + /* open the file */ + f = fopen(openFileName.lpstrFile, write ? "a" : "r"); + if (f == NULL) { + MessageBox(hwnd, "File open failed", NULL, + MB_OK|MB_ICONEXCLAMATION); + return NULL; + } + } else { + int err = CommDlgExtendedError(); + if (err != 0) DisplayError("Internal error in file dialog box", err); + return FALSE; + } + return f; +} + + + +VOID APIENTRY +MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def) +{ + HMENU hmenuTrackPopup; /* floating pop-up menu */ + + /* + * Get the first pop-up menu in the menu template. This is the + * menu that TrackPopupMenu displays. + */ + hmenuTrackPopup = GetSubMenu(hmenu, 0); + + SetMenuDefaultItem(hmenuTrackPopup, def, FALSE); + + /* + * TrackPopup uses screen coordinates, so convert the + * coordinates of the mouse click to screen coordinates. + */ + ClientToScreen(hwnd, (LPPOINT) &pt); + + /* Draw and track the floating pop-up menu. */ + TrackPopupMenu(hmenuTrackPopup, TPM_CENTERALIGN | TPM_RIGHTBUTTON, + pt.x, pt.y, 0, hwnd, NULL); + + /* Destroy the menu.*/ + DestroyMenu(hmenu); +} + +typedef struct { + HWND hDlg, hText; + int sizeX, sizeY, newSizeX, newSizeY; + HDWP hdwp; +} ResizeEditPlusButtonsClosure; + +BOOL CALLBACK +ResizeEditPlusButtonsCallback(HWND hChild, LPARAM lparam) +{ + ResizeEditPlusButtonsClosure *cl = (ResizeEditPlusButtonsClosure *)lparam; + RECT rect; + POINT pt; + + if (hChild == cl->hText) return TRUE; + GetWindowRect(hChild, &rect); /* gives screen coords */ + pt.x = rect.left + (cl->newSizeX - cl->sizeX)/2; + pt.y = rect.top + cl->newSizeY - cl->sizeY; + ScreenToClient(cl->hDlg, &pt); + cl->hdwp = DeferWindowPos(cl->hdwp, hChild, NULL, + pt.x, pt.y, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER); + return TRUE; +} + +/* Resize a dialog that has a (rich) edit field filling most of + the top, with a row of buttons below */ +VOID +ResizeEditPlusButtons(HWND hDlg, HWND hText, int sizeX, int sizeY, int newSizeX, int newSizeY) +{ + RECT rectText; + int newTextHeight, newTextWidth; + ResizeEditPlusButtonsClosure cl; + + /*if (IsIconic(hDlg)) return;*/ + if (newSizeX == sizeX && newSizeY == sizeY) return; + + cl.hdwp = BeginDeferWindowPos(8); + + GetWindowRect(hText, &rectText); /* gives screen coords */ + newTextWidth = rectText.right - rectText.left + newSizeX - sizeX; + newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY; + if (newTextHeight < 0) { + newSizeY += -newTextHeight; + newTextHeight = 0; + } + cl.hdwp = DeferWindowPos(cl.hdwp, hText, NULL, 0, 0, + newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE); + + cl.hDlg = hDlg; + cl.hText = hText; + cl.sizeX = sizeX; + cl.sizeY = sizeY; + cl.newSizeX = newSizeX; + cl.newSizeY = newSizeY; + EnumChildWindows(hDlg, ResizeEditPlusButtonsCallback, (LPARAM)&cl); + + EndDeferWindowPos(cl.hdwp); +} + +/* Center one window over another */ +BOOL CenterWindow (HWND hwndChild, HWND hwndParent) +{ + RECT rChild, rParent; + int wChild, hChild, wParent, hParent; + int wScreen, hScreen, xNew, yNew; + HDC hdc; + + /* Get the Height and Width of the child window */ + GetWindowRect (hwndChild, &rChild); + wChild = rChild.right - rChild.left; + hChild = rChild.bottom - rChild.top; + + /* Get the Height and Width of the parent window */ + GetWindowRect (hwndParent, &rParent); + wParent = rParent.right - rParent.left; + hParent = rParent.bottom - rParent.top; + + /* Get the display limits */ + hdc = GetDC (hwndChild); + wScreen = GetDeviceCaps (hdc, HORZRES); + hScreen = GetDeviceCaps (hdc, VERTRES); + ReleaseDC(hwndChild, hdc); + + /* Calculate new X position, then adjust for screen */ + xNew = rParent.left + ((wParent - wChild) /2); + if (xNew < 0) { + xNew = 0; + } else if ((xNew+wChild) > wScreen) { + xNew = wScreen - wChild; + } + + /* Calculate new Y position, then adjust for screen */ + yNew = rParent.top + ((hParent - hChild) /2); + if (yNew < 0) { + yNew = 0; + } else if ((yNew+hChild) > hScreen) { + yNew = hScreen - hChild; + } + + /* Set it, and return */ + return SetWindowPos (hwndChild, NULL, + xNew, yNew, 0, 0, SWP_NOSIZE | SWP_NOZORDER); +} + +/*---------------------------------------------------------------------------*\ + * + * Startup Dialog functions + * +\*---------------------------------------------------------------------------*/ +void +InitComboStrings(HANDLE hwndCombo, char **cd) +{ + SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0); + + while (*cd != NULL) { + SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) *cd); + cd++; + } +} + +void +InitComboStringsFromOption(HANDLE hwndCombo, char *str) +{ + char buf1[ARG_MAX]; + int len; + + if (str[0] == '@') { + FILE* f = fopen(str + 1, "r"); + if (f == NULL) { + DisplayFatalError(str + 1, errno, 2); + return; + } + len = fread(buf1, 1, sizeof(buf1)-1, f); + fclose(f); + buf1[len] = NULLCHAR; + str = buf1; + } + + SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0); + + for (;;) { + char buf[MSG_SIZ]; + char *end = strchr(str, '\n'); + if (end == NULL) return; + memcpy(buf, str, end - str); + buf[end - str] = NULLCHAR; + SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) buf); + str = end + 1; + } +} + +void +SetStartupDialogEnables(HWND hDlg) +{ + EnableWindow(GetDlgItem(hDlg, OPT_ChessEngineName), + IsDlgButtonChecked(hDlg, OPT_ChessEngine) || + appData.zippyPlay && IsDlgButtonChecked(hDlg, OPT_ChessServer)); + EnableWindow(GetDlgItem(hDlg, OPT_SecondChessEngineName), + IsDlgButtonChecked(hDlg, OPT_ChessEngine)); + EnableWindow(GetDlgItem(hDlg, OPT_ChessServerName), + IsDlgButtonChecked(hDlg, OPT_ChessServer)); + EnableWindow(GetDlgItem(hDlg, OPT_AdditionalOptions), + IsDlgButtonChecked(hDlg, OPT_AnyAdditional)); + EnableWindow(GetDlgItem(hDlg, IDOK), + IsDlgButtonChecked(hDlg, OPT_ChessEngine) || + IsDlgButtonChecked(hDlg, OPT_ChessServer) || + IsDlgButtonChecked(hDlg, OPT_View)); +} + +char * +QuoteForFilename(char *filename) +{ + int dquote, space; + dquote = strchr(filename, '"') != NULL; + space = strchr(filename, ' ') != NULL; + if (dquote || space) { + if (dquote) { + return "'"; + } else { + return "\""; + } + } else { + return ""; + } +} + +VOID +InitEngineBox(HWND hDlg, HWND hwndCombo, char* nthcp, char* nthd, char* nthdir, char *nthnames) +{ + char buf[MSG_SIZ]; + char *q; + + InitComboStringsFromOption(hwndCombo, nthnames); + q = QuoteForFilename(nthcp); + sprintf(buf, "%s%s%s", q, nthcp, q); + if (*nthdir != NULLCHAR) { + q = QuoteForFilename(nthdir); + sprintf(buf + strlen(buf), " /%s=%s%s%s", nthd, q, nthdir, q); + } + if (*nthcp == NULLCHAR) { + SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0); + } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) { + SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0); + SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf); + } +} + +LRESULT CALLBACK +StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + char buf[MSG_SIZ]; + HANDLE hwndCombo; + char *p; + + switch (message) { + case WM_INITDIALOG: + /* Center the dialog */ + CenterWindow (hDlg, GetDesktopWindow()); + /* Initialize the dialog items */ + InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_ChessEngineName), + appData.firstChessProgram, "fd", appData.firstDirectory, + firstChessProgramNames); + InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_SecondChessEngineName), + appData.secondChessProgram, "sd", appData.secondDirectory, + secondChessProgramNames); + hwndCombo = GetDlgItem(hDlg, OPT_ChessServerName); + InitComboStringsFromOption(hwndCombo, icsNames); + sprintf(buf, "%s /icsport=%s", appData.icsHost, appData.icsPort); + if (*appData.icsHelper != NULLCHAR) { + char *q = QuoteForFilename(appData.icsHelper); + sprintf(buf + strlen(buf), " /icshelper=%s%s%s", q, appData.icsHelper, q); + } + if (*appData.icsHost == NULLCHAR) { + SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0); + /*SendMessage(hwndCombo, CB_SHOWDROPDOWN, (WPARAM) TRUE, (LPARAM) 0); !!too soon */ + } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) { + SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0); + SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf); + } + if (chessProgram) { + CheckDlgButton(hDlg, OPT_ChessEngine, BST_CHECKED); + } else if (appData.icsActive) { + CheckDlgButton(hDlg, OPT_ChessServer, BST_CHECKED); + } else if (appData.noChessProgram) { + CheckDlgButton(hDlg, OPT_View, BST_CHECKED); + } + SetStartupDialogEnables(hDlg); + return TRUE; + + case WM_COMMAND: + switch (LOWORD(wParam)) { + case IDOK: + if (IsDlgButtonChecked(hDlg, OPT_ChessEngine)) { + strcpy(buf, "/fcp="); + GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf)); + p = buf; + ParseArgs(StringGet, &p); + strcpy(buf, "/scp="); + GetDlgItemText(hDlg, OPT_SecondChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf)); + p = buf; + ParseArgs(StringGet, &p); + appData.noChessProgram = FALSE; + appData.icsActive = FALSE; + } else if (IsDlgButtonChecked(hDlg, OPT_ChessServer)) { + strcpy(buf, "/ics /icshost="); + GetDlgItemText(hDlg, OPT_ChessServerName, buf + strlen(buf), sizeof(buf) - strlen(buf)); + p = buf; + ParseArgs(StringGet, &p); + if (appData.zippyPlay) { + strcpy(buf, "/fcp="); + GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf)); + p = buf; + ParseArgs(StringGet, &p); + } + } else if (IsDlgButtonChecked(hDlg, OPT_View)) { + appData.noChessProgram = TRUE; + appData.icsActive = FALSE; + } else { + MessageBox(hDlg, "Choose an option, or cancel to exit", + "Option Error", MB_OK|MB_ICONEXCLAMATION); + return TRUE; + } + if (IsDlgButtonChecked(hDlg, OPT_AnyAdditional)) { + GetDlgItemText(hDlg, OPT_AdditionalOptions, buf, sizeof(buf)); + p = buf; + ParseArgs(StringGet, &p); + } + EndDialog(hDlg, TRUE); + return TRUE; + + case IDCANCEL: + ExitEvent(0); + return TRUE; + + case IDM_HELPCONTENTS: + if (!WinHelp (hDlg, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) { + MessageBox (GetFocus(), + "Unable to activate help", + szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND); + } + break; + + default: + SetStartupDialogEnables(hDlg); + break; + } + break; + } + return FALSE; +} + +/*---------------------------------------------------------------------------*\ + * + * About box dialog functions + * +\*---------------------------------------------------------------------------*/ + +/* Process messages for "About" dialog box */ +LRESULT CALLBACK +About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + switch (message) { + case WM_INITDIALOG: /* message: initialize dialog box */ + /* Center the dialog over the application window */ + CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER)); + SetDlgItemText(hDlg, ABOUTBOX_Version, programVersion); + return (TRUE); + + case WM_COMMAND: /* message: received a command */ + if (LOWORD(wParam) == IDOK /* "OK" box selected? */ + || LOWORD(wParam) == IDCANCEL) { /* System menu close command? */ + EndDialog(hDlg, TRUE); /* Exit the dialog */ + return (TRUE); + } + break; + } + return (FALSE); +} + +/*---------------------------------------------------------------------------*\ + * + * Comment Dialog functions + * +\*---------------------------------------------------------------------------*/ + +LRESULT CALLBACK +CommentDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + static HANDLE hwndText = NULL; + int len, newSizeX, newSizeY, flags; + static int sizeX, sizeY; + char *str; + RECT rect; + MINMAXINFO *mmi; + + switch (message) { + case WM_INITDIALOG: /* message: initialize dialog box */ + /* Initialize the dialog items */ + hwndText = GetDlgItem(hDlg, OPT_CommentText); + SetDlgItemText(hDlg, OPT_CommentText, commentText); + EnableWindow(GetDlgItem(hDlg, OPT_CancelComment), editComment); + EnableWindow(GetDlgItem(hDlg, OPT_ClearComment), editComment); + EnableWindow(GetDlgItem(hDlg, OPT_EditComment), !editComment); + SendMessage(hwndText, EM_SETREADONLY, !editComment, 0); + SetWindowText(hDlg, commentTitle); + if (editComment) { + SetFocus(hwndText); + } else { + SetFocus(GetDlgItem(hDlg, IDOK)); + } + SendMessage(GetDlgItem(hDlg, OPT_CommentText), + WM_SETFONT, (WPARAM)font[boardSize][COMMENT_FONT]->hf, + MAKELPARAM(FALSE, 0)); + /* Size and position the dialog */ + if (!commentDialog) { + commentDialog = hDlg; + flags = SWP_NOZORDER; + GetClientRect(hDlg, &rect); + sizeX = rect.right; + sizeY = rect.bottom; + if (commentX != CW_USEDEFAULT && commentY != CW_USEDEFAULT && + commentW != CW_USEDEFAULT && commentH != CW_USEDEFAULT) { + WINDOWPLACEMENT wp; + EnsureOnScreen(&commentX, &commentY); + wp.length = sizeof(WINDOWPLACEMENT); + wp.flags = 0; + wp.showCmd = SW_SHOW; + wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0; + wp.rcNormalPosition.left = commentX; + wp.rcNormalPosition.right = commentX + commentW; + wp.rcNormalPosition.top = commentY; + wp.rcNormalPosition.bottom = commentY + commentH; + SetWindowPlacement(hDlg, &wp); + + GetClientRect(hDlg, &rect); + newSizeX = rect.right; + newSizeY = rect.bottom; + ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, + newSizeX, newSizeY); + sizeX = newSizeX; + sizeY = newSizeY; + } + } + return FALSE; + + case WM_COMMAND: /* message: received a command */ + switch (LOWORD(wParam)) { + case IDOK: + if (editComment) { + char *p, *q; + /* Read changed options from the dialog box */ + hwndText = GetDlgItem(hDlg, OPT_CommentText); + len = GetWindowTextLength(hwndText); + str = (char *) malloc(len + 1); + GetWindowText(hwndText, str, len + 1); + p = q = str; + while (*q) { + if (*q == '\r') + q++; + else + *p++ = *q++; + } + *p = NULLCHAR; + ReplaceComment(commentIndex, str); + free(str); + } + CommentPopDown(); + return TRUE; + + case IDCANCEL: + case OPT_CancelComment: + CommentPopDown(); + return TRUE; + + case OPT_ClearComment: + SetDlgItemText(hDlg, OPT_CommentText, ""); + break; + + case OPT_EditComment: + EditCommentEvent(); + return TRUE; + + default: + break; + } + break; + + case WM_SIZE: + newSizeX = LOWORD(lParam); + newSizeY = HIWORD(lParam); + ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY); + sizeX = newSizeX; + sizeY = newSizeY; + break; + + case WM_GETMINMAXINFO: + /* Prevent resizing window too small */ + mmi = (MINMAXINFO *) lParam; + mmi->ptMinTrackSize.x = 100; + mmi->ptMinTrackSize.y = 100; + break; + } + return FALSE; +} + +VOID +EitherCommentPopUp(int index, char *title, char *str, BOOLEAN edit) +{ + FARPROC lpProc; + char *p, *q; + + CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, edit ? MF_CHECKED : MF_UNCHECKED); + + if (str == NULL) str = ""; + p = (char *) malloc(2 * strlen(str) + 2); + q = p; + while (*str) { + if (*str == '\n') *q++ = '\r'; + *q++ = *str++; + } + *q = NULLCHAR; + if (commentText != NULL) free(commentText); + + commentIndex = index; + commentTitle = title; + commentText = p; + editComment = edit; + + if (commentDialog) { + SendMessage(commentDialog, WM_INITDIALOG, 0, 0); + if (!commentDialogUp) ShowWindow(commentDialog, SW_SHOW); + } else { + lpProc = MakeProcInstance((FARPROC)CommentDialog, hInst); + CreateDialog(hInst, MAKEINTRESOURCE(DLG_EditComment), + hwndMain, (DLGPROC)lpProc); + FreeProcInstance(lpProc); + } + commentDialogUp = TRUE; +} + + +/*---------------------------------------------------------------------------*\ + * + * Type-in move dialog functions + * +\*---------------------------------------------------------------------------*/ + +LRESULT CALLBACK +TypeInMoveDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + char move[MSG_SIZ]; + HWND hInput; + ChessMove moveType; + int fromX, fromY, toX, toY; + char promoChar; + + switch (message) { + case WM_INITDIALOG: + move[0] = (char) lParam; + move[1] = NULLCHAR; + CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER)); + hInput = GetDlgItem(hDlg, OPT_Move); + SetWindowText(hInput, move); + SetFocus(hInput); + SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999); + return FALSE; + + case WM_COMMAND: + switch (LOWORD(wParam)) { + case IDOK: + if (gameMode != EditGame && currentMove != forwardMostMove && + gameMode != Training) { + DisplayMoveError("Displayed move is not current"); + } else { + GetDlgItemText(hDlg, OPT_Move, move, sizeof(move)); + if (ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove, + &moveType, &fromX, &fromY, &toX, &toY, &promoChar)) { + if (gameMode != Training) + forwardMostMove = currentMove; + UserMoveEvent(fromX, fromY, toX, toY, promoChar); + } else { + DisplayMoveError("Could not parse move"); + } + } + EndDialog(hDlg, TRUE); + return TRUE; + case IDCANCEL: + EndDialog(hDlg, FALSE); + return TRUE; + default: + break; + } + break; + } + return FALSE; +} + +VOID +PopUpMoveDialog(char firstchar) +{ + FARPROC lpProc; + + if ((gameMode == BeginningOfGame && !appData.icsActive) || + gameMode == MachinePlaysWhite || gameMode == MachinePlaysBlack || + gameMode == AnalyzeMode || gameMode == EditGame || + gameMode == EditPosition || gameMode == IcsExamining || + gameMode == IcsPlayingWhite || gameMode == IcsPlayingBlack || + gameMode == Training) { + lpProc = MakeProcInstance((FARPROC)TypeInMoveDialog, hInst); + DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInMove), + hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar); + FreeProcInstance(lpProc); + } +} + +/*---------------------------------------------------------------------------*\ + * + * Error dialogs + * +\*---------------------------------------------------------------------------*/ + +/* Nonmodal error box */ +VOID +ErrorPopDown() +{ + if (!appData.popupMoveErrors && moveErrorMessageUp) DisplayMessage("", ""); + if (errorDialog == NULL) return; + DestroyWindow(errorDialog); + errorDialog = NULL; +} + +LRESULT CALLBACK +ErrorDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + HANDLE hwndText; + RECT rChild; + + switch (message) { + case WM_INITDIALOG: + GetWindowRect(hDlg, &rChild); + SetWindowPos(hDlg, NULL, rChild.left, + rChild.top + boardRect.top - (rChild.bottom - rChild.top), + 0, 0, SWP_NOZORDER|SWP_NOSIZE); + errorDialog = hDlg; + hwndText = GetDlgItem(hDlg, OPT_ErrorText); + SetDlgItemText(hDlg, OPT_ErrorText, errorMessage); + return FALSE; + + case WM_COMMAND: + switch (LOWORD(wParam)) { + case IDOK: + case IDCANCEL: + if (errorDialog = hDlg) errorDialog = NULL; + DestroyWindow(hDlg); + return TRUE; + + default: + break; + } + break; + } + return FALSE; +} + +/*---------------------------------------------------------------------------*\ + * + * Ics Interaction console functions + * +\*---------------------------------------------------------------------------*/ + +#define HISTORY_SIZE 64 +static char *history[HISTORY_SIZE]; +int histIn = 0, histP = 0; + +VOID +SaveInHistory(char *cmd) +{ + if (history[histIn] != NULL) { + free(history[histIn]); + history[histIn] = NULL; + } + if (*cmd == NULLCHAR) return; + history[histIn] = StrSave(cmd); + histIn = (histIn + 1) % HISTORY_SIZE; + if (history[histIn] != NULL) { + free(history[histIn]); + history[histIn] = NULL; + } + histP = histIn; +} + +char * +PrevInHistory(char *cmd) +{ + int newhp; + if (histP == histIn) { + if (history[histIn] != NULL) free(history[histIn]); + history[histIn] = StrSave(cmd); + } + newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE; + if (newhp == histIn || history[newhp] == NULL) return NULL; + histP = newhp; + return history[histP]; +} + +char * +NextInHistory() +{ + if (histP == histIn) return NULL; + histP = (histP + 1) % HISTORY_SIZE; + return history[histP]; +} + +typedef struct { + char *item; + char *command; + BOOLEAN getname; + BOOLEAN immediate; +} IcsTextMenuEntry; +#define ICS_TEXT_MENU_SIZE (IDM_CommandXLast - IDM_CommandX + 1) +IcsTextMenuEntry icsTextMenuEntry[ICS_TEXT_MENU_SIZE]; + +void +ParseIcsTextMenu(char *icsTextMenuString) +{ + int flags = 0; + IcsTextMenuEntry *e = icsTextMenuEntry; + char *p = icsTextMenuString; + while (e->item != NULL && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) { + free(e->item); + e->item = NULL; + if (e->command != NULL) { + free(e->command); + e->command = NULL; + } + e++; + } + e = icsTextMenuEntry; + while (*p && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) { + if (*p == ';' || *p == '\n') { + e->item = strdup("-"); + e->command = NULL; + p++; + } else if (*p == '-') { + e->item = strdup("-"); + e->command = NULL; + p++; + if (*p) p++; + } else { + char *q, *r, *s, *t; + char c; + q = strchr(p, ','); + if (q == NULL) break; + *q = NULLCHAR; + r = strchr(q + 1, ','); + if (r == NULL) break; + *r = NULLCHAR; + s = strchr(r + 1, ','); + if (s == NULL) break; + *s = NULLCHAR; + c = ';'; + t = strchr(s + 1, c); + if (t == NULL) { + c = '\n'; + t = strchr(s + 1, c); + } + if (t != NULL) *t = NULLCHAR; + e->item = strdup(p); + e->command = strdup(q + 1); + e->getname = *(r + 1) != '0'; + e->immediate = *(s + 1) != '0'; + *q = ','; + *r = ','; + *s = ','; + if (t == NULL) break; + *t = c; + p = t + 1; + } + e++; + } +} + +HMENU +LoadIcsTextMenu(IcsTextMenuEntry *e) +{ + HMENU hmenu, h; + int i = 0; + hmenu = LoadMenu(hInst, "TextMenu"); + h = GetSubMenu(hmenu, 0); + while (e->item) { + if (strcmp(e->item, "-") == 0) { + AppendMenu(h, MF_SEPARATOR, 0, 0); + } else { + if (e->item[0] == '|') { + AppendMenu(h, MF_STRING|MF_MENUBARBREAK, + IDM_CommandX + i, &e->item[1]); + } else { + AppendMenu(h, MF_STRING, IDM_CommandX + i, e->item); + } + } + e++; + i++; + } + return hmenu; +} + +WNDPROC consoleTextWindowProc; +WNDPROC PvWindowProc; +WNDPROC NameWindowProc; + +void +CommandX(HWND hwnd, char *command, BOOLEAN getname, BOOLEAN immediate) +{ + char buf[MSG_SIZ], name[MSG_SIZ]; + HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput); + CHARRANGE sel; + + if (!getname) { + SetWindowText(hInput, command); + if (immediate) { + SendMessage(hInput, WM_CHAR, '\r', 0); + } else { + sel.cpMin = 999999; + sel.cpMax = 999999; + SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel); + SetFocus(hInput); + } + return; + } + SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel); + if (sel.cpMin == sel.cpMax) { + /* Expand to surrounding word */ + TEXTRANGE tr; + do { + tr.chrg.cpMax = sel.cpMin; + tr.chrg.cpMin = --sel.cpMin; + if (sel.cpMin < 0) break; + tr.lpstrText = name; + SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr); + } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-'); + sel.cpMin++; + + do { + tr.chrg.cpMin = sel.cpMax; + tr.chrg.cpMax = ++sel.cpMax; + tr.lpstrText = name; + if (SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr) < 1) break; + } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-'); + sel.cpMax--; + + if (sel.cpMax == sel.cpMin || sel.cpMax - sel.cpMin > MSG_SIZ/2) { + MessageBeep(MB_ICONEXCLAMATION); + return; + } + tr.chrg = sel; + tr.lpstrText = name; + SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr); + } else { + if (sel.cpMax - sel.cpMin > MSG_SIZ/2) { + MessageBeep(MB_ICONEXCLAMATION); + return; + } + SendMessage(hwnd, EM_GETSELTEXT, 0, (LPARAM) name); + } + if (immediate) { + sprintf(buf, "%s %s", command, name); + SetWindowText(hInput, buf); + SendMessage(hInput, WM_CHAR, '\r', 0); + } else { + sprintf(buf, "%s %s ", command, name); /* trailing space */ + SetWindowText(hInput, buf); + sel.cpMin = 999999; + sel.cpMax = 999999; + SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel); + SetFocus(hInput); + } +} + +LRESULT CALLBACK +ConsoleTextSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + HWND hInput; + CHARRANGE sel; + + switch (message) { + case WM_KEYDOWN: + if (!(GetKeyState(VK_CONTROL) & ~1)) break; + switch (wParam) { + case VK_PRIOR: + SendMessage(hwnd, EM_LINESCROLL, 0, -999999); + return 0; + case VK_NEXT: + sel.cpMin = 999999; + sel.cpMax = 999999; + SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel); + SendMessage(hwnd, EM_SCROLLCARET, 0, 0); + return 0; + } + break; + case WM_CHAR: + if (wParam == '\t') { + if (GetKeyState(VK_SHIFT) < 0) { + /* shifted */ + if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE); + if (buttonDesc[0].hwnd) { + SetFocus(buttonDesc[0].hwnd); + } else { + SetFocus(hwndMain); + } + } else { + /* unshifted */ + SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleInput)); + } + } else { + hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput); + SetFocus(hInput); + SendMessage(hInput, message, wParam, lParam); + } + return 0; + case WM_PASTE: + hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput); + SetFocus(hInput); + return SendMessage(hInput, message, wParam, lParam); + case WM_MBUTTONDOWN: + return SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0); + case WM_RBUTTONDOWN: + if (!(GetKeyState(VK_SHIFT) & ~1)) { + /* Move selection here if it was empty */ + POINT pt; + pt.x = LOWORD(lParam); + pt.y = HIWORD(lParam); + SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel); + if (sel.cpMin == sel.cpMax) { + sel.cpMin = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&pt); /*doc is wrong*/ + sel.cpMax = sel.cpMin; + SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel); + } + SendMessage(hwnd, EM_HIDESELECTION, FALSE, FALSE); + } + return 0; + case WM_RBUTTONUP: + if (GetKeyState(VK_SHIFT) & ~1) { + SendDlgItemMessage(hwndConsole, OPT_ConsoleText, + WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0); + } else { + POINT pt; + HMENU hmenu = LoadIcsTextMenu(icsTextMenuEntry); + SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel); + if (!IsClipboardFormatAvailable(CF_TEXT)) { + EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED); + } + pt.x = LOWORD(lParam); + pt.y = HIWORD(lParam); + MenuPopup(hwnd, pt, hmenu, -1); + } + return 0; + case WM_COMMAND: + switch (LOWORD(wParam)) { + case IDM_QuickPaste: + { + SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel); + if (sel.cpMin == sel.cpMax) { + MessageBeep(MB_ICONEXCLAMATION); + return 0; + } + SendMessage(hwnd, WM_COPY, 0, 0); + hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput); + SendMessage(hInput, WM_PASTE, 0, 0); + SetFocus(hInput); + return 0; + } + case IDM_Cut: + SendMessage(hwnd, WM_CUT, 0, 0); + return 0; + case IDM_Paste: + SendMessage(hwnd, WM_PASTE, 0, 0); + return 0; + case IDM_Copy: + SendMessage(hwnd, WM_COPY, 0, 0); + return 0; + default: + { + int i = LOWORD(wParam) - IDM_CommandX; + if (i >= 0 && i < ICS_TEXT_MENU_SIZE && + icsTextMenuEntry[i].command != NULL) { + CommandX(hwnd, icsTextMenuEntry[i].command, + icsTextMenuEntry[i].getname, + icsTextMenuEntry[i].immediate); + return 0; + } + } + break; + } + break; + } + return (*consoleTextWindowProc)(hwnd, message, wParam, lParam); +} + +WNDPROC consoleInputWindowProc; + +LRESULT CALLBACK +ConsoleInputSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + char buf[MSG_SIZ]; + char *p; + static BOOL sendNextChar = FALSE; + static BOOL quoteNextChar = FALSE; + InputSource *is = consoleInputSource; + CHARFORMAT cf; + CHARRANGE sel; + + switch (message) { + case WM_CHAR: + if (!appData.localLineEditing || sendNextChar) { + is->buf[0] = (CHAR) wParam; + is->count = 1; + SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is); + sendNextChar = FALSE; + return 0; + } + if (quoteNextChar) { + buf[0] = (char) wParam; + buf[1] = NULLCHAR; + SendMessage(hwnd, EM_REPLACESEL, TRUE, (LPARAM) buf); + quoteNextChar = FALSE; + return 0; + } + switch (wParam) { + case '\r': /* Enter key */ + is->count = GetWindowText(hwnd, is->buf, INPUT_SOURCE_BUF_SIZE-1); + if (consoleEcho) SaveInHistory(is->buf); + is->buf[is->count++] = '\n'; + is->buf[is->count] = NULLCHAR; + SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is); + if (consoleEcho) { + ConsoleOutput(is->buf, is->count, TRUE); + } else if (appData.localLineEditing) { + ConsoleOutput("\n", 1, TRUE); + } + /* fall thru */ + case '\033': /* Escape key */ + SetWindowText(hwnd, ""); + cf.cbSize = sizeof(CHARFORMAT); + cf.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT; + if (consoleEcho) { + cf.crTextColor = textAttribs[ColorNormal].color; + } else { + cf.crTextColor = COLOR_ECHOOFF; + } + cf.dwEffects = textAttribs[ColorNormal].effects; + SendMessage(hwnd, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf); + return 0; + case '\t': /* Tab key */ + if (GetKeyState(VK_SHIFT) < 0) { + /* shifted */ + SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleText)); + } else { + /* unshifted */ + if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE); + if (buttonDesc[0].hwnd) { + SetFocus(buttonDesc[0].hwnd); + } else { + SetFocus(hwndMain); + } + } + return 0; + case '\023': /* Ctrl+S */ + sendNextChar = TRUE; + return 0; + case '\021': /* Ctrl+Q */ + quoteNextChar = TRUE; + return 0; + default: + break; + } + break; + case WM_KEYDOWN: + switch (wParam) { + case VK_UP: + GetWindowText(hwnd, buf, MSG_SIZ); + p = PrevInHistory(buf); + if (p != NULL) { + SetWindowText(hwnd, p); + sel.cpMin = 999999; + sel.cpMax = 999999; + SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel); + return 0; + } + break; + case VK_DOWN: + p = NextInHistory(); + if (p != NULL) { + SetWindowText(hwnd, p); + sel.cpMin = 999999; + sel.cpMax = 999999; + SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel); + return 0; + } + break; + case VK_HOME: + case VK_END: + if (!(GetKeyState(VK_CONTROL) & ~1)) break; + /* fall thru */ + case VK_PRIOR: + case VK_NEXT: + SendDlgItemMessage(hwndConsole, OPT_ConsoleText, message, wParam, lParam); + return 0; + } + break; + case WM_MBUTTONDOWN: + SendDlgItemMessage(hwndConsole, OPT_ConsoleText, + WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0); + break; + case WM_RBUTTONUP: + if (GetKeyState(VK_SHIFT) & ~1) { + SendDlgItemMessage(hwndConsole, OPT_ConsoleText, + WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0); + } else { + POINT pt; + HMENU hmenu; + hmenu = LoadMenu(hInst, "InputMenu"); + SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel); + if (sel.cpMin == sel.cpMax) { + EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED); + EnableMenuItem(hmenu, IDM_Cut, MF_BYCOMMAND|MF_GRAYED); + } + if (!IsClipboardFormatAvailable(CF_TEXT)) { + EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED); + } + pt.x = LOWORD(lParam); + pt.y = HIWORD(lParam); + MenuPopup(hwnd, pt, hmenu, -1); + } + return 0; + case WM_COMMAND: + switch (LOWORD(wParam)) { + case IDM_Undo: + SendMessage(hwnd, EM_UNDO, 0, 0); + return 0; + case IDM_SelectAll: + sel.cpMin = 0; + sel.cpMax = -1; /*999999?*/ + SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel); + return 0; + case IDM_Cut: + SendMessage(hwnd, WM_CUT, 0, 0); + return 0; + case IDM_Paste: + SendMessage(hwnd, WM_PASTE, 0, 0); + return 0; + case IDM_Copy: + SendMessage(hwnd, WM_COPY, 0, 0); + return 0; + } + break; + } + return (*consoleInputWindowProc)(hwnd, message, wParam, lParam); +} + +#define CO_MAX 100000 +#define CO_TRIM 1000 + +LRESULT CALLBACK +ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + static HWND hText, hInput, hFocus; + InputSource *is = consoleInputSource; + RECT rect; + static int sizeX, sizeY; + int newSizeX, newSizeY; + MINMAXINFO *mmi; + + switch (message) { + case WM_INITDIALOG: /* message: initialize dialog box */ + hwndConsole = hDlg; + hText = GetDlgItem(hDlg, OPT_ConsoleText); + hInput = GetDlgItem(hDlg, OPT_ConsoleInput); + SetFocus(hInput); + consoleTextWindowProc = (WNDPROC) + SetWindowLong(hText, GWL_WNDPROC, (LONG) ConsoleTextSubclass); + SendMessage(hText, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor); + consoleInputWindowProc = (WNDPROC) + SetWindowLong(hInput, GWL_WNDPROC, (LONG) ConsoleInputSubclass); + SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor); + Colorize(ColorNormal, TRUE); + SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &consoleCF); + ChangedConsoleFont(); + GetClientRect(hDlg, &rect); + sizeX = rect.right; + sizeY = rect.bottom; + if (consoleX != CW_USEDEFAULT && consoleY != CW_USEDEFAULT && + consoleW != CW_USEDEFAULT && consoleH != CW_USEDEFAULT) { + WINDOWPLACEMENT wp; + EnsureOnScreen(&consoleX, &consoleY); + wp.length = sizeof(WINDOWPLACEMENT); + wp.flags = 0; + wp.showCmd = SW_SHOW; + wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0; + wp.rcNormalPosition.left = consoleX; + wp.rcNormalPosition.right = consoleX + consoleW; + wp.rcNormalPosition.top = consoleY; + wp.rcNormalPosition.bottom = consoleY + consoleH; + SetWindowPlacement(hDlg, &wp); + } + return FALSE; + + case WM_SETFOCUS: + SetFocus(hInput); + return 0; + + case WM_CLOSE: + ExitEvent(0); + /* not reached */ + break; + + case WM_SIZE: + if (IsIconic(hDlg)) break; + newSizeX = LOWORD(lParam); + newSizeY = HIWORD(lParam); + if (sizeX != newSizeX || sizeY != newSizeY) { + RECT rectText, rectInput; + POINT pt; + int newTextHeight, newTextWidth; + GetWindowRect(hText, &rectText); + newTextWidth = rectText.right - rectText.left + newSizeX - sizeX; + newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY; + if (newTextHeight < 0) { + newSizeY += -newTextHeight; + newTextHeight = 0; + } + SetWindowPos(hText, NULL, 0, 0, + newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE); + GetWindowRect(hInput, &rectInput); /* gives screen coords */ + pt.x = rectInput.left; + pt.y = rectInput.top + newSizeY - sizeY; + ScreenToClient(hDlg, &pt); + SetWindowPos(hInput, NULL, + pt.x, pt.y, /* needs client coords */ + rectInput.right - rectInput.left + newSizeX - sizeX, + rectInput.bottom - rectInput.top, SWP_NOZORDER); + } + sizeX = newSizeX; + sizeY = newSizeY; + break; + + case WM_GETMINMAXINFO: + /* Prevent resizing window too small */ + mmi = (MINMAXINFO *) lParam; + mmi->ptMinTrackSize.x = 100; + mmi->ptMinTrackSize.y = 100; + break; + } + return DefWindowProc(hDlg, message, wParam, lParam); +} + + +VOID +ConsoleCreate() +{ + HWND hCons; + if (hwndConsole) return; + hCons = CreateDialog(hInst, szConsoleName, 0, NULL); + SendMessage(hCons, WM_INITDIALOG, 0, 0); +} + +BOOL httpseglight_continued = FALSE; +char *spitlight(HWND hText, char *p, ColorClass cc, CHARRANGE *sel) { + int effects; + char *urlstart = p; + char backup; + httpseglight_continued = TRUE; + backup = 0; + while (*p) { + switch(*p) { + case '\n': case '\r': case ' ': case '\t': + backup = *p; *p = 0; httpseglight_continued = FALSE; break; + default: p++; + } + } + effects = consoleCF.dwEffects; + consoleCF.crTextColor = textAttribs[ColorKibitz].color; + consoleCF.dwEffects |= CFM_UNDERLINE; + SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)sel); + SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&consoleCF); + SendMessage(hText, EM_REPLACESEL, 0, (LPARAM) urlstart); + sel->cpMax = sel->cpMin += p - urlstart; + consoleCF.crTextColor = textAttribs[currentColorClass].color; + consoleCF.dwEffects = effects; + SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)sel); + SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&consoleCF); + *p = backup; + return p; +} + +char *strnpstr(char *p, char *needle, char *end) { + char *loc; + char *o = needle; + while (p < end) { + if (*p == *o) { + if (o==needle) loc = p; + o++; + } else o = needle; + if (*o == 0) return loc; + p++; + } + return p=NULL; + } +int seglight(HWND hText, char *p, char *end, char *seg, int seglen, ColorClass cc, CHARRANGE *sel) { + char *op, *urlstart; + if (p==NULL || seg == NULL || sel == NULL) return -1; + if (httpseglight_continued) { + p = spitlight(hText, p, cc, sel); + } + while (end-p >= seglen && (urlstart = strnpstr(p, seg, end)) != NULL) { + op = urlstart; + *op = 0; + SendMessage(hText, EM_REPLACESEL, 0, (LPARAM) p); + sel->cpMax = sel->cpMin += op - p; + *op = seg[0]; + p = spitlight(hText, op, cc, sel); + } + if (end-p>0) { + SendMessage(hText, EM_REPLACESEL, 0, (LPARAM) p); + sel->cpMax = sel->cpMin += end-p; + } + return 0; +} + +VOID +ConsoleOutput(char* data, int length, int forceVisible) +{ + HWND hText; + int trim, exlen; + char *p, *q; + char buf[CO_MAX+1]; + POINT pEnd; + RECT rect; + static int delayLF = 0; + CHARRANGE savesel, sel; + + if (hwndConsole == NULL || length > CO_MAX-100 || length == 0) return; + p = data; + q = buf; + if (delayLF) { + *q++ = '\r'; + *q++ = '\n'; + delayLF = 0; + } + while (length--) { + if (*p == '\n') { + if (*++p) { + *q++ = '\r'; + *q++ = '\n'; + } else { + delayLF = 1; + } + } else if (*p == '\007') { + MyPlaySound(&sounds[(int)SoundBell]); + p++; + } else { + *q++ = *p++; + } + } + *q = NULLCHAR; + hText = GetDlgItem(hwndConsole, OPT_ConsoleText); + SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE); + /* Save current selection */ + SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&savesel); + exlen = GetWindowTextLength(hText); + /* Find out whether current end of text is visible */ + SendMessage(hText, EM_GETRECT, 0, (LPARAM) &rect); + SendMessage(hText, EM_POSFROMCHAR, (WPARAM) &pEnd, exlen); + /* Trim existing text if it's too long */ + if (exlen + (q - buf) > CO_MAX) { + trim = (CO_TRIM > (q - buf)) ? CO_TRIM : (q - buf); + sel.cpMin = 0; + sel.cpMax = trim; + SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel); + SendMessage(hText, EM_REPLACESEL, 0, (LPARAM)""); + exlen -= trim; + savesel.cpMin -= trim; + savesel.cpMax -= trim; + if (exlen < 0) exlen = 0; + if (savesel.cpMin < 0) savesel.cpMin = 0; + if (savesel.cpMax < savesel.cpMin) savesel.cpMax = savesel.cpMin; + } + /* Append the new text */ + sel.cpMin = exlen; + sel.cpMax = exlen; + SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel); + SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&consoleCF); + + /* append text while checking for and highlight links */ + seglight(hText, buf, q, "http://", 7, ColorKibitz, &sel); + + if (forceVisible || exlen == 0 || + (rect.left <= pEnd.x && pEnd.x < rect.right && + rect.top <= pEnd.y && pEnd.y < rect.bottom)) { + /* Scroll to make new end of text visible if old end of text + was visible or new text is an echo of user typein */ + sel.cpMin = 9999999; + sel.cpMax = 9999999; + SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel); + SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE); + SendMessage(hText, EM_SCROLLCARET, 0, 0); + SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE); + } + if (savesel.cpMax == exlen || forceVisible) { + /* Move insert point to new end of text if it was at the old + end of text or if the new text is an echo of user typein */ + sel.cpMin = 9999999; + sel.cpMax = 9999999; + SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel); + } else { + /* Restore previous selection */ + SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&savesel); + } + SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE); +} + +/*---------*/ + + +void +DisplayAClock(HDC hdc, int timeRemaining, int highlight, + RECT *rect, char *color) +{ + char buf[100]; + char *str; + COLORREF oldFg, oldBg; + HFONT oldFont; + + if (appData.clockMode) { + if (tinyLayout) + sprintf(buf, "%c %s", color[0], TimeString(timeRemaining)); + else + sprintf(buf, "%s: %s", color, TimeString(timeRemaining)); + str = buf; + } else { + str = color; + } + + if (highlight) { + oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */ + oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */ + } else { + oldFg = SetTextColor(hdc, RGB(0, 0, 0)); /* black */ + oldBg = SetBkColor(hdc, RGB(255, 255, 255)); /* white */ + } + oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf); + + ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN, + rect->top, ETO_CLIPPED|ETO_OPAQUE, + rect, str, strlen(str), NULL); + + (void) SetTextColor(hdc, oldFg); + (void) SetBkColor(hdc, oldBg); + (void) SelectObject(hdc, oldFont); +} + + +int +DoReadFile(HANDLE hFile, char *buf, int count, DWORD *outCount, + OVERLAPPED *ovl) +{ + int ok, err; + + ResetEvent(ovl->hEvent); + ovl->Offset = ovl->OffsetHigh = 0; + ok = ReadFile(hFile, buf, count, outCount, ovl); + if (ok) { + err = NO_ERROR; + } else { + err = GetLastError(); + if (err == ERROR_IO_PENDING) { + ok = GetOverlappedResult(hFile, ovl, outCount, TRUE); + if (ok) + err = NO_ERROR; + else + err = GetLastError(); + } + } + return err; +} + +int +DoWriteFile(HANDLE hFile, char *buf, int count, DWORD *outCount, + OVERLAPPED *ovl) +{ + int ok, err; + + ResetEvent(ovl->hEvent); + ovl->Offset = ovl->OffsetHigh = 0; + ok = WriteFile(hFile, buf, count, outCount, ovl); + if (ok) { + err = NO_ERROR; + } else { + err = GetLastError(); + if (err == ERROR_IO_PENDING) { + ok = GetOverlappedResult(hFile, ovl, outCount, TRUE); + if (ok) + err = NO_ERROR; + else + err = GetLastError(); + } + } + return err; +} + + +DWORD +InputThread(LPVOID arg) +{ + InputSource *is; + OVERLAPPED ovl; + + is = (InputSource *) arg; + ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0; + while (is->hThread != NULL) { + is->error = DoReadFile(is->hFile, is->next, + INPUT_SOURCE_BUF_SIZE - (is->next - is->buf), + &is->count, &ovl); + if (is->error == NO_ERROR) { + is->next += is->count; + } else { + if (is->error == ERROR_BROKEN_PIPE) { + /* Correct for MS brain damage. EOF reading a pipe is not an error. */ + is->count = 0; + } else { + is->count = (DWORD) -1; + } + } + SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is); + if (is->count <= 0) break; /* Quit on EOF or error */ + } + CloseHandle(ovl.hEvent); + CloseHandle(is->hFile); + return 0; +} + + +/* Windows 95 beta 2 won't let you do overlapped i/o on a console or pipe */ +DWORD +NonOvlInputThread(LPVOID arg) +{ + InputSource *is; + char *p, *q; + int i; + char prev; + + is = (InputSource *) arg; + while (is->hThread != NULL) { + is->error = ReadFile(is->hFile, is->next, + INPUT_SOURCE_BUF_SIZE - (is->next - is->buf), + &is->count, NULL) ? NO_ERROR : GetLastError(); + if (is->error == NO_ERROR) { + /* Change CRLF to LF */ + if (is->next > is->buf) { + p = is->next - 1; + i = is->count + 1; + } else { + p = is->next; + i = is->count; + } + q = p; + prev = NULLCHAR; + while (i > 0) { + if (prev == '\r' && *p == '\n') { + *(q-1) = '\n'; + is->count--; + } else { + *q++ = *p; + } + prev = *p++; + i--; + } + *q = NULLCHAR; + is->next = q; + } else { + if (is->error == ERROR_BROKEN_PIPE) { + /* Correct for MS brain damage. EOF reading a pipe is not an error. */ + is->count = 0; + } else { + is->count = (DWORD) -1; + } + } + SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is); + if (is->count < 0) break; /* Quit on error */ + } + CloseHandle(is->hFile); + return 0; +} + +DWORD +SocketInputThread(LPVOID arg) +{ + InputSource *is; + + is = (InputSource *) arg; + while (is->hThread != NULL) { + is->count = recv(is->sock, is->buf, INPUT_SOURCE_BUF_SIZE, 0); + if ((int)is->count == SOCKET_ERROR) { + is->count = (DWORD) -1; + is->error = WSAGetLastError(); + } else { + is->error = NO_ERROR; + is->next += is->count; + if (is->count == 0 && is->second == is) { + /* End of file on stderr; quit with no message */ + break; + } + } + SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is); + if (is->count <= 0) break; /* Quit on EOF or error */ + } + return 0; +} + +VOID +InputEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + InputSource *is; + + is = (InputSource *) lParam; + if (is->lineByLine) { + /* Feed in lines one by one */ + char *p = is->buf; + char *q = p; + while (q < is->next) { + if (*q++ == '\n') { + (is->func)(is, is->closure, p, q - p, NO_ERROR); + p = q; + } + } + /* Move any partial line to the start of the buffer */ + q = is->buf; + while (p < is->next) { + *q++ = *p++; + } + is->next = q; + if (is->error != NO_ERROR || is->count == 0) { + /* Notify backend of the error. Note: If there was a partial + line at the end, it is not flushed through. */ + (is->func)(is, is->closure, is->buf, is->count, is->error); + } + } else { + /* Feed in the whole chunk of input at once */ + (is->func)(is, is->closure, is->buf, is->count, is->error); + is->next = is->buf; + } +} + +/*---------------------------------------------------------------------------*\ + * + * Menu enables. Used when setting various modes. + * +\*---------------------------------------------------------------------------*/ + +typedef struct { + int item; + int flags; +} Enables; + +VOID +SetMenuEnables(HMENU hmenu, Enables *enab) +{ + while (enab->item > 0) { + (void) EnableMenuItem(hmenu, enab->item, enab->flags); + enab++; + } +} + +Enables gnuEnables[] = { + { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED }, + { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED }, + { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED }, + { IDM_Accept, MF_BYCOMMAND|MF_GRAYED }, + { IDM_Decline, MF_BYCOMMAND|MF_GRAYED }, + { IDM_Rematch, MF_BYCOMMAND|MF_GRAYED }, + { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED }, + { IDM_StopExamining, MF_BYCOMMAND|MF_GRAYED }, + { IDM_StopObserving, MF_BYCOMMAND|MF_GRAYED }, + { IDM_Revert, MF_BYCOMMAND|MF_GRAYED }, + { -1, -1 } +}; + +Enables icsEnables[] = { + { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED }, + { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED }, + { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED }, + { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED }, + { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED }, + { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED }, + { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED }, + { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED }, + { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED }, + { IDM_Hint, MF_BYCOMMAND|MF_GRAYED }, + { IDM_Book, MF_BYCOMMAND|MF_GRAYED }, + { IDM_IcsOptions, MF_BYCOMMAND|MF_ENABLED }, + { -1, -1 } +}; + +#ifdef ZIPPY +Enables zippyEnables[] = { + { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED }, + { IDM_Hint, MF_BYCOMMAND|MF_ENABLED }, + { IDM_Book, MF_BYCOMMAND|MF_ENABLED }, + { -1, -1 } +}; +#endif + +Enables ncpEnables[] = { + { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED }, + { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED }, + { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED }, + { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED }, + { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED }, + { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED }, + { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED }, + { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED }, + { ACTION_POS, MF_BYPOSITION|MF_GRAYED }, + { IDM_Revert, MF_BYCOMMAND|MF_GRAYED }, + { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED }, + { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED }, + { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED }, + { IDM_Hint, MF_BYCOMMAND|MF_GRAYED }, + { IDM_Book, MF_BYCOMMAND|MF_GRAYED }, + { -1, -1 } +}; + +Enables trainingOnEnables[] = { + { IDM_EditComment, MF_BYCOMMAND|MF_GRAYED }, + { IDM_Pause, MF_BYCOMMAND|MF_GRAYED }, + { IDM_Forward, MF_BYCOMMAND|MF_GRAYED }, + { IDM_Backward, MF_BYCOMMAND|MF_GRAYED }, + { IDM_ToEnd, MF_BYCOMMAND|MF_GRAYED }, + { IDM_ToStart, MF_BYCOMMAND|MF_GRAYED }, + { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED }, + { IDM_TruncateGame, MF_BYCOMMAND|MF_GRAYED }, + { -1, -1 } +}; + +Enables trainingOffEnables[] = { + { IDM_EditComment, MF_BYCOMMAND|MF_ENABLED }, + { IDM_Pause, MF_BYCOMMAND|MF_ENABLED }, + { IDM_Forward, MF_BYCOMMAND|MF_ENABLED }, + { IDM_Backward, MF_BYCOMMAND|MF_ENABLED }, + { IDM_ToEnd, MF_BYCOMMAND|MF_ENABLED }, + { IDM_ToStart, MF_BYCOMMAND|MF_ENABLED }, + { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED }, + { IDM_TruncateGame, MF_BYCOMMAND|MF_ENABLED }, + { -1, -1 } +}; + +/* These modify either ncpEnables or gnuEnables */ +Enables cmailEnables[] = { + { IDM_MailMove, MF_BYCOMMAND|MF_ENABLED }, + { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_ENABLED }, + { ACTION_POS, MF_BYPOSITION|MF_ENABLED }, + { IDM_CallFlag, MF_BYCOMMAND|MF_GRAYED }, + { IDM_Draw, MF_BYCOMMAND|MF_ENABLED }, + { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED }, + { IDM_Abort, MF_BYCOMMAND|MF_GRAYED }, + { -1, -1 } +}; + +Enables machineThinkingEnables[] = { + { IDM_LoadGame, MF_BYCOMMAND|MF_GRAYED }, + { IDM_LoadNextGame, MF_BYCOMMAND|MF_GRAYED }, + { IDM_LoadPrevGame, MF_BYCOMMAND|MF_GRAYED }, + { IDM_ReloadGame, MF_BYCOMMAND|MF_GRAYED }, + { IDM_PasteGame, MF_BYCOMMAND|MF_GRAYED }, + { IDM_LoadPosition, MF_BYCOMMAND|MF_GRAYED }, + { IDM_LoadNextPosition, MF_BYCOMMAND|MF_GRAYED }, + { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_GRAYED }, + { IDM_ReloadPosition, MF_BYCOMMAND|MF_GRAYED }, + { IDM_PastePosition, MF_BYCOMMAND|MF_GRAYED }, + { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED }, + { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED }, + { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED }, + { IDM_TypeInMove, MF_BYCOMMAND|MF_GRAYED }, + { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED }, + { -1, -1 } +}; + +Enables userThinkingEnables[] = { + { IDM_LoadGame, MF_BYCOMMAND|MF_ENABLED }, + { IDM_LoadNextGame, MF_BYCOMMAND|MF_ENABLED }, + { IDM_LoadPrevGame, MF_BYCOMMAND|MF_ENABLED }, + { IDM_ReloadGame, MF_BYCOMMAND|MF_ENABLED }, + { IDM_PasteGame, MF_BYCOMMAND|MF_ENABLED }, + { IDM_LoadPosition, MF_BYCOMMAND|MF_ENABLED }, + { IDM_LoadNextPosition, MF_BYCOMMAND|MF_ENABLED }, + { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_ENABLED }, + { IDM_ReloadPosition, MF_BYCOMMAND|MF_ENABLED }, + { IDM_PastePosition, MF_BYCOMMAND|MF_ENABLED }, + { IDM_MachineWhite, MF_BYCOMMAND|MF_ENABLED }, + { IDM_MachineBlack, MF_BYCOMMAND|MF_ENABLED }, + { IDM_TwoMachines, MF_BYCOMMAND|MF_ENABLED }, + { IDM_TypeInMove, MF_BYCOMMAND|MF_ENABLED }, + { IDM_RetractMove, MF_BYCOMMAND|MF_ENABLED }, + { -1, -1 } +}; + +/*---------------------------------------------------------------------------*\ + * + * Front-end interface functions exported by XBoard. + * Functions appear in same order as prototypes in frontend.h. + * +\*---------------------------------------------------------------------------*/ +VOID +ModeHighlight() +{ + static UINT prevChecked = 0; + static int prevPausing = 0; + UINT nowChecked; + + if (pausing != prevPausing) { + prevPausing = pausing; + (void) CheckMenuItem(GetMenu(hwndMain), IDM_Pause, + MF_BYCOMMAND|(pausing ? MF_CHECKED : MF_UNCHECKED)); + if (hwndPause) SetWindowText(hwndPause, pausing ? "C" : "P"); + } + + switch (gameMode) { + case BeginningOfGame: + if (appData.icsActive) + nowChecked = IDM_IcsClient; + else if (appData.noChessProgram) + nowChecked = IDM_EditGame; + else + nowChecked = IDM_MachineBlack; + break; + case MachinePlaysBlack: + nowChecked = IDM_MachineBlack; + break; + case MachinePlaysWhite: + nowChecked = IDM_MachineWhite; + break; + case TwoMachinesPlay: + nowChecked = IDM_TwoMachines; + break; + case AnalyzeMode: + nowChecked = IDM_AnalysisMode; + break; + case AnalyzeFile: + nowChecked = IDM_AnalyzeFile; + break; + case EditGame: + nowChecked = IDM_EditGame; + break; + case PlayFromGameFile: + nowChecked = IDM_LoadGame; + break; + case EditPosition: + nowChecked = IDM_EditPosition; + break; + case Training: + nowChecked = IDM_Training; + break; + case IcsPlayingWhite: + case IcsPlayingBlack: + case IcsObserving: + case IcsIdle: + nowChecked = IDM_IcsClient; + break; + default: + case EndOfGame: + nowChecked = 0; + break; + } + if (prevChecked != 0) + (void) CheckMenuItem(GetMenu(hwndMain), + prevChecked, MF_BYCOMMAND|MF_UNCHECKED); + if (nowChecked != 0) + (void) CheckMenuItem(GetMenu(hwndMain), + nowChecked, MF_BYCOMMAND|MF_CHECKED); + + if (nowChecked == IDM_LoadGame || nowChecked == IDM_Training) { + (void) EnableMenuItem(GetMenu(hwndMain), IDM_Training, + MF_BYCOMMAND|MF_ENABLED); + } else { + (void) EnableMenuItem(GetMenu(hwndMain), + IDM_Training, MF_BYCOMMAND|MF_GRAYED); + } + + prevChecked = nowChecked; +} + +VOID +SetICSMode() +{ + HMENU hmenu = GetMenu(hwndMain); + SetMenuEnables(hmenu, icsEnables); + EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), ICS_POS, + MF_BYPOSITION|MF_ENABLED); +#ifdef ZIPPY + if (appData.zippyPlay) { + SetMenuEnables(hmenu, zippyEnables); + } +#endif +} + +VOID +SetGNUMode() +{ + SetMenuEnables(GetMenu(hwndMain), gnuEnables); +} + +VOID +SetNCPMode() +{ + HMENU hmenu = GetMenu(hwndMain); + SetMenuEnables(hmenu, ncpEnables); + EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), SOUNDS_POS, + MF_BYPOSITION|MF_GRAYED); + DrawMenuBar(hwndMain); +} + +VOID +SetCmailMode() +{ + SetMenuEnables(GetMenu(hwndMain), cmailEnables); +} + +VOID +SetTrainingModeOn() +{ + int i; + SetMenuEnables(GetMenu(hwndMain), trainingOnEnables); + for (i = 0; i < N_BUTTONS; i++) { + if (buttonDesc[i].hwnd != NULL) + EnableWindow(buttonDesc[i].hwnd, FALSE); + } + CommentPopDown(); +} + +VOID SetTrainingModeOff() +{ + int i; + SetMenuEnables(GetMenu(hwndMain), trainingOffEnables); + for (i = 0; i < N_BUTTONS; i++) { + if (buttonDesc[i].hwnd != NULL) + EnableWindow(buttonDesc[i].hwnd, TRUE); + } +} + + +VOID +SetUserThinkingEnables() +{ + SetMenuEnables(GetMenu(hwndMain), userThinkingEnables); +} + +VOID +SetMachineThinkingEnables() +{ + HMENU hMenu = GetMenu(hwndMain); + int flags = MF_BYCOMMAND|MF_ENABLED; + + SetMenuEnables(hMenu, machineThinkingEnables); + + if (gameMode == MachinePlaysBlack) { + (void)EnableMenuItem(hMenu, IDM_MachineBlack, flags); + } else if (gameMode == MachinePlaysWhite) { + (void)EnableMenuItem(hMenu, IDM_MachineWhite, flags); + } else if (gameMode == TwoMachinesPlay) { + (void)EnableMenuItem(hMenu, IDM_TwoMachines, flags); + } +} + + +VOID +DisplayTitle(char *str) +{ + char title[MSG_SIZ], *host; + if (str[0] != NULLCHAR) { + strcpy(title, str); + } else if (appData.icsActive) { + if (appData.icsCommPort[0] != NULLCHAR) + host = "ICS"; + else + host = appData.icsHost; + sprintf(title, "%s: %s", szTitle, host); + } else if (appData.noChessProgram) { + strcpy(title, szTitle); + } else { + strcpy(title, szTitle); + strcat(title, ": "); + strcat(title, first.tidy); + } + SetWindowText(hwndMain, title); +} + + +VOID +DisplayMessage(char *str1, char *str2) +{ + HDC hdc; + HFONT oldFont; + int remain = MESSAGE_TEXT_MAX - 1; + int len; + + moveErrorMessageUp = FALSE; /* turned on later by caller if needed */ + messageText[0] = NULLCHAR; + if (*str1) { + len = strlen(str1); + if (len > remain) len = remain; + strncpy(messageText, str1, len); + messageText[len] = NULLCHAR; + remain -= len; + } + if (*str2 && remain >= 2) { + if (*str1) { + strcat(messageText, " "); + remain -= 2; + } + len = strlen(str2); + if (len > remain) len = remain; + strncat(messageText, str2, len); + } + messageText[MESSAGE_TEXT_MAX - 1] = NULLCHAR; + + if (IsIconic(hwndMain)) return; + hdc = GetDC(hwndMain); + oldFont = SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf); + ExtTextOut(hdc, messageRect.left, messageRect.top, ETO_CLIPPED|ETO_OPAQUE, + &messageRect, messageText, strlen(messageText), NULL); + (void) SelectObject(hdc, oldFont); + (void) ReleaseDC(hwndMain, hdc); +} + +VOID +DisplayError(char *str, int error) +{ + FARPROC lpProc; + char buf[MSG_SIZ*2], buf2[MSG_SIZ]; + int len; + char *p, *q; + + if (error == 0) { + strcpy(buf, str); + } else { + len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, + NULL, error, LANG_NEUTRAL, + (LPSTR) buf2, MSG_SIZ, NULL); + if (len > 0) { + sprintf(buf, "%s:\n%s", str, buf2); + } else { + ErrorMap *em = errmap; + while (em->err != 0 && em->err != error) em++; + if (em->err != 0) { + sprintf(buf, "%s:\n%s", str, em->msg); + } else { + sprintf(buf, "%s:\nError code %d", str, error); + } + } + } + p = buf; + q = errorMessage; + while (*p) { + if (*p == '\n') { + if (hwndMain != NULL /*!!?*/) { + *q++ = '\r'; + *q++ = *p++; + } else { + *q++ = ' '; + p++; + } + } else { + *q++ = *p++; + } + } + *q = NULLCHAR; + + if (hwndMain == NULL) { + MessageBox(NULL, errorMessage, "Error", MB_OK|MB_ICONEXCLAMATION); + } else { + lpProc = MakeProcInstance((FARPROC)ErrorDialog, hInst); + CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error), + hwndMain, (DLGPROC)lpProc); + FreeProcInstance(lpProc); + } +} + + +VOID +DisplayMoveError(char *str) +{ + fromX = fromY = -1; + ClearHighlights(); + DrawPosition(FALSE, NULL); + if (appData.popupMoveErrors) { + DisplayError(str, 0); + } else { + DisplayMessage(str, ""); + moveErrorMessageUp = TRUE; + } +} + +VOID +DisplayFatalError(char *str, int error, int exitStatus) +{ + char buf[2*MSG_SIZ], buf2[MSG_SIZ]; + int len; + char *label = exitStatus ? "Fatal Error" : "Exiting"; + + if (error != 0) { + len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, + NULL, error, LANG_NEUTRAL, + (LPSTR) buf2, MSG_SIZ, NULL); + if (len > 0) { + sprintf(buf, "%s:\n%s", str, buf2); + } else { + ErrorMap *em = errmap; + while (em->err != 0 && em->err != error) em++; + if (em->err != 0) { + sprintf(buf, "%s:\n%s", str, em->msg); + } else { + sprintf(buf, "%s:\nError code %d", str, error); + } + } + str = buf; + } + if (appData.debugMode) { + fprintf(debugFP, "%s: %s\n", label, str); + } + if (appData.popupExitMessage) { + (void) MessageBox(hwndMain, str, label, MB_OK| + (exitStatus ? MB_ICONSTOP : MB_ICONINFORMATION)); + } + ExitEvent(exitStatus); +} + + +VOID +DisplayInformation(char *str) +{ + (void) MessageBox(hwndMain, str, "Information", MB_OK|MB_ICONINFORMATION); +} + + +typedef struct { + char *title, *question, *replyPrefix; + ProcRef pr; +} QuestionParams; + +LRESULT CALLBACK +QuestionDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + static QuestionParams *qp; + char reply[MSG_SIZ]; + int len, err; + + switch (message) { + case WM_INITDIALOG: + qp = (QuestionParams *) lParam; + CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER)); + SetWindowText(hDlg, qp->title); + SetDlgItemText(hDlg, OPT_QuestionText, qp->question); + SetFocus(GetDlgItem(hDlg, OPT_QuestionInput)); + return FALSE; + + case WM_COMMAND: + switch (LOWORD(wParam)) { + case IDOK: + strcpy(reply, qp->replyPrefix); + if (*reply) strcat(reply, " "); + len = strlen(reply); + GetDlgItemText(hDlg, OPT_QuestionInput, reply + len, sizeof(reply) - len); + strcat(reply, "\n"); + OutputToProcess(qp->pr, reply, strlen(reply), &err); + EndDialog(hDlg, TRUE); + if (err) DisplayFatalError("Error writing to chess program", err, 1); + return TRUE; + case IDCANCEL: + EndDialog(hDlg, FALSE); + return TRUE; + default: + break; + } + break; + } + return FALSE; +} + +VOID +AskQuestion(char* title, char *question, char *replyPrefix, ProcRef pr) +{ + QuestionParams qp; + FARPROC lpProc; + + qp.title = title; + qp.question = question; + qp.replyPrefix = replyPrefix; + qp.pr = pr; + lpProc = MakeProcInstance((FARPROC)QuestionDialog, hInst); + DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_Question), + hwndMain, (DLGPROC)lpProc, (LPARAM)&qp); + FreeProcInstance(lpProc); +} + + +VOID +DisplayIcsInteractionTitle(char *str) +{ + char consoleTitle[MSG_SIZ]; + + sprintf(consoleTitle, "%s: %s", szConsoleTitle, str); + SetWindowText(hwndConsole, consoleTitle); +} + +void +DrawPosition(int fullRedraw, Board board) +{ + HDCDrawPosition(NULL, (BOOLEAN) fullRedraw, board); +} + + +VOID +ResetFrontEnd() +{ + fromX = fromY = -1; + if (dragInfo.pos.x != -1 || dragInfo.pos.y != -1) { + dragInfo.pos.x = dragInfo.pos.y = -1; + dragInfo.pos.x = dragInfo.pos.y = -1; + dragInfo.lastpos = dragInfo.pos; + dragInfo.start.x = dragInfo.start.y = -1; + dragInfo.from = dragInfo.start; + ReleaseCapture(); + DrawPosition(TRUE, NULL); + } +} + + +VOID +CommentPopUp(char *title, char *str) +{ + HWND hwnd = GetActiveWindow(); + EitherCommentPopUp(0, title, str, FALSE); + SetActiveWindow(hwnd); +} + +VOID +CommentPopDown(void) +{ + CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, MF_UNCHECKED); + if (commentDialog) { + ShowWindow(commentDialog, SW_HIDE); + } + commentDialogUp = FALSE; +} + +VOID +EditCommentPopUp(int index, char *title, char *str) +{ + EitherCommentPopUp(index, title, str, TRUE); +} + + +VOID +RingBell() +{ + MyPlaySound(&sounds[(int)SoundMove]); +} + +VOID PlayIcsWinSound() +{ + MyPlaySound(&sounds[(int)SoundIcsWin]); +} + +VOID PlayIcsLossSound() +{ + MyPlaySound(&sounds[(int)SoundIcsLoss]); +} + +VOID PlayIcsDrawSound() +{ + MyPlaySound(&sounds[(int)SoundIcsDraw]); +} + +VOID PlayIcsUnfinishedSound() +{ + MyPlaySound(&sounds[(int)SoundIcsUnfinished]); +} + +VOID +PlayAlarmSound() +{ + MyPlaySound(&sounds[(int)SoundAlarm]); +} + + +VOID +EchoOn() +{ + HWND hInput; + consoleEcho = TRUE; + hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput); + SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&consoleCF); + SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor); +} + + +VOID +EchoOff() +{ + CHARFORMAT cf; + HWND hInput; + consoleEcho = FALSE; + hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput); + /* This works OK: set text and background both to the same color */ + cf = consoleCF; + cf.crTextColor = COLOR_ECHOOFF; + SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf); + SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, cf.crTextColor); +} + +/* No Raw()...? */ + +void Colorize(ColorClass cc, int continuation) +{ + currentColorClass = cc; + consoleCF.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT; + consoleCF.crTextColor = textAttribs[cc].color; + consoleCF.dwEffects = textAttribs[cc].effects|CFE_LINK; + if (!continuation) MyPlaySound(&textAttribs[cc].sound); +} + +char * +UserName() +{ + static char buf[MSG_SIZ]; + DWORD bufsiz = MSG_SIZ; + + if (!GetUserName(buf, &bufsiz)) { + /*DisplayError("Error getting user name", GetLastError());*/ + strcpy(buf, "User"); + } + return buf; +} + +char * +HostName() +{ + static char buf[MSG_SIZ]; + DWORD bufsiz = MSG_SIZ; + + if (!GetComputerName(buf, &bufsiz)) { + /*DisplayError("Error getting host name", GetLastError());*/ + strcpy(buf, "Unknown"); + } + return buf; +} + + +int +ClockTimerRunning() +{ + return clockTimerEvent != 0; +} + +int +StopClockTimer() +{ + if (clockTimerEvent == 0) return FALSE; + KillTimer(hwndMain, clockTimerEvent); + clockTimerEvent = 0; + return TRUE; +} + +void +StartClockTimer(long millisec) +{ + clockTimerEvent = SetTimer(hwndMain, (UINT) CLOCK_TIMER_ID, + (UINT) millisec, NULL); +} + +void +DisplayWhiteClock(long timeRemaining, int highlight) +{ + HDC hdc; + hdc = GetDC(hwndMain); + if (!IsIconic(hwndMain)) { + DisplayAClock(hdc, timeRemaining, highlight, &whiteRect, "White"); + } + if (highlight && iconCurrent == iconBlack) { + iconCurrent = iconWhite; + PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent); + if (IsIconic(hwndMain)) { + DrawIcon(hdc, 2, 2, iconCurrent); + } + } + (void) ReleaseDC(hwndMain, hdc); + if (hwndConsole) + PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent); +} + +void +DisplayBlackClock(long timeRemaining, int highlight) +{ + HDC hdc; + hdc = GetDC(hwndMain); + if (!IsIconic(hwndMain)) { + DisplayAClock(hdc, timeRemaining, highlight, &blackRect, "Black"); + } + if (highlight && iconCurrent == iconWhite) { + iconCurrent = iconBlack; + PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent); + if (IsIconic(hwndMain)) { + DrawIcon(hdc, 2, 2, iconCurrent); + } + } + (void) ReleaseDC(hwndMain, hdc); + if (hwndConsole) + PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent); +} + + +int +LoadGameTimerRunning() +{ + return loadGameTimerEvent != 0; +} + +int +StopLoadGameTimer() +{ + if (loadGameTimerEvent == 0) return FALSE; + KillTimer(hwndMain, loadGameTimerEvent); + loadGameTimerEvent = 0; + return TRUE; +} + +void +StartLoadGameTimer(long millisec) +{ + loadGameTimerEvent = SetTimer(hwndMain, (UINT) LOAD_GAME_TIMER_ID, + (UINT) millisec, NULL); +} + +void +AutoSaveGame() +{ + char *defName; + FILE *f; + char fileTitle[MSG_SIZ]; + + defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn"); + f = OpenFileDialog(hwndMain, TRUE, defName, + appData.oldSaveStyle ? "gam" : "pgn", + GAME_FILT, + "Save Game to File", NULL, fileTitle, NULL); + if (f != NULL) { + SaveGame(f, 0, ""); + fclose(f); + } +} + + +void +ScheduleDelayedEvent(DelayedEventCallback cb, long millisec) +{ + if (delayedTimerEvent != 0) { + if (appData.debugMode) { + fprintf(debugFP, "ScheduleDelayedEvent: event already scheduled\n"); + } + KillTimer(hwndMain, delayedTimerEvent); + delayedTimerEvent = 0; + delayedTimerCallback(); + } + delayedTimerCallback = cb; + delayedTimerEvent = SetTimer(hwndMain, (UINT) DELAYED_TIMER_ID, + (UINT) millisec, NULL); +} + +DelayedEventCallback +GetDelayedEvent() +{ + if (delayedTimerEvent) { + return delayedTimerCallback; + } else { + return NULL; + } +} + +void +CancelDelayedEvent() +{ + if (delayedTimerEvent) { + KillTimer(hwndMain, delayedTimerEvent); + delayedTimerEvent = 0; + } +} + +/* Start a child process running the given program. + The process's standard output can be read from "from", and its + standard input can be written to "to". + Exit with fatal error if anything goes wrong. + Returns an opaque pointer that can be used to destroy the process + later. +*/ +int +StartChildProcess(char *cmdLine, char *dir, ProcRef *pr) +{ +#define BUFSIZE 4096 + + HANDLE hChildStdinRd, hChildStdinWr, + hChildStdoutRd, hChildStdoutWr; + HANDLE hChildStdinWrDup, hChildStdoutRdDup; + SECURITY_ATTRIBUTES saAttr; + BOOL fSuccess; + PROCESS_INFORMATION piProcInfo; + STARTUPINFO siStartInfo; + ChildProc *cp; + char buf[MSG_SIZ]; + DWORD err; + + if (appData.debugMode) { + fprintf(debugFP, "StartChildProcess (dir=\"%s\") %s\n", dir, cmdLine); + } + + *pr = NoProc; + + /* Set the bInheritHandle flag so pipe handles are inherited. */ + saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); + saAttr.bInheritHandle = TRUE; + saAttr.lpSecurityDescriptor = NULL; + + /* + * The steps for redirecting child's STDOUT: + * 1. Create anonymous pipe to be STDOUT for child. + * 2. Create a noninheritable duplicate of read handle, + * and close the inheritable read handle. + */ + + /* Create a pipe for the child's STDOUT. */ + if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) { + return GetLastError(); + } + + /* Duplicate the read handle to the pipe, so it is not inherited. */ + fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd, + GetCurrentProcess(), &hChildStdoutRdDup, 0, + FALSE, /* not inherited */ + DUPLICATE_SAME_ACCESS); + if (! fSuccess) { + return GetLastError(); + } + CloseHandle(hChildStdoutRd); + + /* + * The steps for redirecting child's STDIN: + * 1. Create anonymous pipe to be STDIN for child. + * 2. Create a noninheritable duplicate of write handle, + * and close the inheritable write handle. + */ + + /* Create a pipe for the child's STDIN. */ + if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) { + return GetLastError(); + } + + /* Duplicate the write handle to the pipe, so it is not inherited. */ + fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr, + GetCurrentProcess(), &hChildStdinWrDup, 0, + FALSE, /* not inherited */ + DUPLICATE_SAME_ACCESS); + if (! fSuccess) { + return GetLastError(); + } + CloseHandle(hChildStdinWr); + + /* Arrange to (1) look in dir for the child .exe file, and + * (2) have dir be the child's working directory. Interpret + * dir relative to the directory WinBoard loaded from. */ + GetCurrentDirectory(MSG_SIZ, buf); + SetCurrentDirectory(installDir); + SetCurrentDirectory(dir); + + /* Now create the child process. */ + + siStartInfo.cb = sizeof(STARTUPINFO); + siStartInfo.lpReserved = NULL; + siStartInfo.lpDesktop = NULL; + siStartInfo.lpTitle = NULL; + siStartInfo.dwFlags = STARTF_USESTDHANDLES; + siStartInfo.cbReserved2 = 0; + siStartInfo.lpReserved2 = NULL; + siStartInfo.hStdInput = hChildStdinRd; + siStartInfo.hStdOutput = hChildStdoutWr; + siStartInfo.hStdError = hChildStdoutWr; + + fSuccess = CreateProcess(NULL, + cmdLine, /* command line */ + NULL, /* process security attributes */ + NULL, /* primary thread security attrs */ + TRUE, /* handles are inherited */ + DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP, + NULL, /* use parent's environment */ + NULL, + &siStartInfo, /* STARTUPINFO pointer */ + &piProcInfo); /* receives PROCESS_INFORMATION */ + + err = GetLastError(); + SetCurrentDirectory(buf); /* return to prev directory */ + if (! fSuccess) { + return err; + } + + /* Close the handles we don't need in the parent */ + CloseHandle(piProcInfo.hThread); + CloseHandle(hChildStdinRd); + CloseHandle(hChildStdoutWr); + + /* Prepare return value */ + cp = (ChildProc *) calloc(1, sizeof(ChildProc)); + cp->kind = CPReal; + cp->hProcess = piProcInfo.hProcess; + cp->pid = piProcInfo.dwProcessId; + cp->hFrom = hChildStdoutRdDup; + cp->hTo = hChildStdinWrDup; + + *pr = (void *) cp; + + /* Klaus Friedel says that this Sleep solves a problem under Windows + 2000 where engines sometimes don't see the initial command(s) + from WinBoard and hang. I don't understand how that can happen, + but the Sleep is harmless, so I've put it in. Others have also + reported what may be the same problem, so hopefully this will fix + it for them too. */ + Sleep(500); + + return NO_ERROR; +} + + +void +DestroyChildProcess(ProcRef pr, int/*boolean*/ signal) +{ + ChildProc *cp; + + cp = (ChildProc *) pr; + if (cp == NULL) return; + + switch (cp->kind) { + case CPReal: + /* TerminateProcess is considered harmful, so... */ + CloseHandle(cp->hTo); /* Closing this will give the child an EOF and hopefully kill it */ + if (cp->hFrom) CloseHandle(cp->hFrom); /* if NULL, InputThread will close it */ + /* The following doesn't work because the chess program + doesn't "have the same console" as WinBoard. Maybe + we could arrange for this even though neither WinBoard + nor the chess program uses a console for stdio? */ + /*!!if (signal) GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, cp->pid);*/ + CloseHandle(cp->hProcess); + break; + + case CPComm: + if (cp->hFrom) CloseHandle(cp->hFrom); + break; + + case CPSock: + closesocket(cp->sock); + WSACleanup(); + break; + + case CPRcmd: + if (signal) send(cp->sock2, "\017", 1, 0); /* 017 = 15 = SIGTERM */ + closesocket(cp->sock); + closesocket(cp->sock2); + WSACleanup(); + break; + } + free(cp); +} + +void +InterruptChildProcess(ProcRef pr) +{ + ChildProc *cp; + + cp = (ChildProc *) pr; + if (cp == NULL) return; + switch (cp->kind) { + case CPReal: + /* The following doesn't work because the chess program + doesn't "have the same console" as WinBoard. Maybe + we could arrange for this even though neither WinBoard + nor the chess program uses a console for stdio */ + /*!!GenerateConsoleCtrlEvent(CTRL_C_EVENT, cp->pid);*/ + break; + + case CPComm: + case CPSock: + /* Can't interrupt */ + break; + + case CPRcmd: + send(cp->sock2, "\002", 1, 0); /* 2 = SIGINT */ + break; + } +} + + +int +OpenTelnet(char *host, char *port, ProcRef *pr) +{ + char cmdLine[MSG_SIZ]; + + if (port[0] == NULLCHAR) { + sprintf(cmdLine, "%s %s", appData.telnetProgram, host); + } else { + sprintf(cmdLine, "%s %s %s", appData.telnetProgram, host, port); + } + return StartChildProcess(cmdLine, "", pr); +} + + +/* Code to open TCP sockets */ + +int +OpenTCP(char *host, char *port, ProcRef *pr) +{ + ChildProc *cp; + int err; + SOCKET s; + struct sockaddr_in sa, mysa; + struct hostent FAR *hp; + unsigned short uport; + WORD wVersionRequested; + WSADATA wsaData; + + /* Initialize socket DLL */ + wVersionRequested = MAKEWORD(1, 1); + err = WSAStartup(wVersionRequested, &wsaData); + if (err != 0) return err; + + /* Make socket */ + if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) { + err = WSAGetLastError(); + WSACleanup(); + return err; + } + + /* Bind local address using (mostly) don't-care values. + */ + memset((char *) &mysa, 0, sizeof(struct sockaddr_in)); + mysa.sin_family = AF_INET; + mysa.sin_addr.s_addr = INADDR_ANY; + uport = (unsigned short) 0; + mysa.sin_port = htons(uport); + if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in)) + == SOCKET_ERROR) { + err = WSAGetLastError(); + WSACleanup(); + return err; + } + + /* Resolve remote host name */ + memset((char *) &sa, 0, sizeof(struct sockaddr_in)); + if (!(hp = gethostbyname(host))) { + unsigned int b0, b1, b2, b3; + + err = WSAGetLastError(); + + if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) { + hp = (struct hostent *) calloc(1, sizeof(struct hostent)); + hp->h_addrtype = AF_INET; + hp->h_length = 4; + hp->h_addr_list = (char **) calloc(2, sizeof(char *)); + hp->h_addr_list[0] = (char *) malloc(4); + hp->h_addr_list[0][0] = (char) b0; + hp->h_addr_list[0][1] = (char) b1; + hp->h_addr_list[0][2] = (char) b2; + hp->h_addr_list[0][3] = (char) b3; + } else { + WSACleanup(); + return err; + } + } + sa.sin_family = hp->h_addrtype; + uport = (unsigned short) atoi(port); + sa.sin_port = htons(uport); + memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length); + + /* Make connection */ + if (connect(s, (struct sockaddr *) &sa, + sizeof(struct sockaddr_in)) == SOCKET_ERROR) { + err = WSAGetLastError(); + WSACleanup(); + return err; + } + + /* Prepare return value */ + cp = (ChildProc *) calloc(1, sizeof(ChildProc)); + cp->kind = CPSock; + cp->sock = s; + *pr = (ProcRef *) cp; + + return NO_ERROR; +} + +int +OpenCommPort(char *name, ProcRef *pr) +{ + HANDLE h; + COMMTIMEOUTS ct; + ChildProc *cp; + char fullname[MSG_SIZ]; + + if (*name != '\\') + sprintf(fullname, "\\\\.\\%s", name); + else + strcpy(fullname, name); + + h = CreateFile(name, GENERIC_READ | GENERIC_WRITE, + 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); + if (h == (HANDLE) -1) { + return GetLastError(); + } + hCommPort = h; + + if (!SetCommState(h, (LPDCB) &dcb)) return GetLastError(); + + /* Accumulate characters until a 100ms pause, then parse */ + ct.ReadIntervalTimeout = 100; + ct.ReadTotalTimeoutMultiplier = 0; + ct.ReadTotalTimeoutConstant = 0; + ct.WriteTotalTimeoutMultiplier = 0; + ct.WriteTotalTimeoutConstant = 0; + if (!SetCommTimeouts(h, (LPCOMMTIMEOUTS) &ct)) return GetLastError(); + + /* Prepare return value */ + cp = (ChildProc *) calloc(1, sizeof(ChildProc)); + cp->kind = CPComm; + cp->hFrom = h; + cp->hTo = h; + *pr = (ProcRef *) cp; + + return NO_ERROR; +} + +int +OpenLoopback(ProcRef *pr) +{ + DisplayFatalError("Not implemented", 0, 1); + return NO_ERROR; +} + + +int +OpenRcmd(char* host, char* user, char* cmd, ProcRef* pr) +{ + ChildProc *cp; + int err; + SOCKET s, s2, s3; + struct sockaddr_in sa, mysa; + struct hostent FAR *hp; + unsigned short uport; + WORD wVersionRequested; + WSADATA wsaData; + int fromPort; + char stderrPortStr[MSG_SIZ]; + + /* Initialize socket DLL */ + wVersionRequested = MAKEWORD(1, 1); + err = WSAStartup(wVersionRequested, &wsaData); + if (err != 0) return err; + + /* Resolve remote host name */ + memset((char *) &sa, 0, sizeof(struct sockaddr_in)); + if (!(hp = gethostbyname(host))) { + unsigned int b0, b1, b2, b3; + + err = WSAGetLastError(); + + if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) { + hp = (struct hostent *) calloc(1, sizeof(struct hostent)); + hp->h_addrtype = AF_INET; + hp->h_length = 4; + hp->h_addr_list = (char **) calloc(2, sizeof(char *)); + hp->h_addr_list[0] = (char *) malloc(4); + hp->h_addr_list[0][0] = (char) b0; + hp->h_addr_list[0][1] = (char) b1; + hp->h_addr_list[0][2] = (char) b2; + hp->h_addr_list[0][3] = (char) b3; + } else { + WSACleanup(); + return err; + } + } + sa.sin_family = hp->h_addrtype; + uport = (unsigned short) 514; + sa.sin_port = htons(uport); + memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length); + + /* Bind local socket to unused "privileged" port address + */ + s = INVALID_SOCKET; + memset((char *) &mysa, 0, sizeof(struct sockaddr_in)); + mysa.sin_family = AF_INET; + mysa.sin_addr.s_addr = INADDR_ANY; + for (fromPort = 1023;; fromPort--) { + if (fromPort < 0) { + WSACleanup(); + return WSAEADDRINUSE; + } + if (s == INVALID_SOCKET) { + if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) { + err = WSAGetLastError(); + WSACleanup(); + return err; + } + } + uport = (unsigned short) fromPort; + mysa.sin_port = htons(uport); + if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in)) + == SOCKET_ERROR) { + err = WSAGetLastError(); + if (err == WSAEADDRINUSE) continue; + WSACleanup(); + return err; + } + if (connect(s, (struct sockaddr *) &sa, + sizeof(struct sockaddr_in)) == SOCKET_ERROR) { + err = WSAGetLastError(); + if (err == WSAEADDRINUSE) { + closesocket(s); + s = -1; + continue; + } + WSACleanup(); + return err; + } + break; + } + + /* Bind stderr local socket to unused "privileged" port address + */ + s2 = INVALID_SOCKET; + memset((char *) &mysa, 0, sizeof(struct sockaddr_in)); + mysa.sin_family = AF_INET; + mysa.sin_addr.s_addr = INADDR_ANY; + for (fromPort = 1023;; fromPort--) { + if (fromPort < 0) { + (void) closesocket(s); + WSACleanup(); + return WSAEADDRINUSE; + } + if (s2 == INVALID_SOCKET) { + if ((s2 = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) { + err = WSAGetLastError(); + closesocket(s); + WSACleanup(); + return err; + } + } + uport = (unsigned short) fromPort; + mysa.sin_port = htons(uport); + if (bind(s2, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in)) + == SOCKET_ERROR) { + err = WSAGetLastError(); + if (err == WSAEADDRINUSE) continue; + (void) closesocket(s); + WSACleanup(); + return err; + } + if (listen(s2, 1) == SOCKET_ERROR) { + err = WSAGetLastError(); + if (err == WSAEADDRINUSE) { + closesocket(s2); + s2 = INVALID_SOCKET; + continue; + } + (void) closesocket(s); + (void) closesocket(s2); + WSACleanup(); + return err; + } + break; + } + sprintf(stderrPortStr, "%d", fromPort); + + if (send(s, stderrPortStr, strlen(stderrPortStr) + 1, 0) == SOCKET_ERROR) { + err = WSAGetLastError(); + (void) closesocket(s); + (void) closesocket(s2); + WSACleanup(); + return err; + } + + if (send(s, UserName(), strlen(UserName()) + 1, 0) == SOCKET_ERROR) { + err = WSAGetLastError(); + (void) closesocket(s); + (void) closesocket(s2); + WSACleanup(); + return err; + } + if (*user == NULLCHAR) user = UserName(); + if (send(s, user, strlen(user) + 1, 0) == SOCKET_ERROR) { + err = WSAGetLastError(); + (void) closesocket(s); + (void) closesocket(s2); + WSACleanup(); + return err; + } + if (send(s, cmd, strlen(cmd) + 1, 0) == SOCKET_ERROR) { + err = WSAGetLastError(); + (void) closesocket(s); + (void) closesocket(s2); + WSACleanup(); + return err; + } + + if ((s3 = accept(s2, NULL, NULL)) == INVALID_SOCKET) { + err = WSAGetLastError(); + (void) closesocket(s); + (void) closesocket(s2); + WSACleanup(); + return err; + } + (void) closesocket(s2); /* Stop listening */ + + /* Prepare return value */ + cp = (ChildProc *) calloc(1, sizeof(ChildProc)); + cp->kind = CPRcmd; + cp->sock = s; + cp->sock2 = s3; + *pr = (ProcRef *) cp; + + return NO_ERROR; +} + + +InputSourceRef +AddInputSource(ProcRef pr, int lineByLine, + InputCallback func, VOIDSTAR closure) +{ + InputSource *is, *is2; + ChildProc *cp = (ChildProc *) pr; + + is = (InputSource *) calloc(1, sizeof(InputSource)); + is->lineByLine = lineByLine; + is->func = func; + is->closure = closure; + is->second = NULL; + is->next = is->buf; + if (pr == NoProc) { + is->kind = CPReal; + consoleInputSource = is; + } else { + is->kind = cp->kind; + switch (cp->kind) { + case CPReal: + is->hFile = cp->hFrom; + cp->hFrom = NULL; /* now owned by InputThread */ + is->hThread = + CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) NonOvlInputThread, + (LPVOID) is, 0, &is->id); + break; + + case CPComm: + is->hFile = cp->hFrom; + cp->hFrom = NULL; /* now owned by InputThread */ + is->hThread = + CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) InputThread, + (LPVOID) is, 0, &is->id); + break; + + case CPSock: + is->sock = cp->sock; + is->hThread = + CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread, + (LPVOID) is, 0, &is->id); + break; + + case CPRcmd: + is2 = (InputSource *) calloc(1, sizeof(InputSource)); + *is2 = *is; + is->sock = cp->sock; + is->second = is2; + is2->sock = cp->sock2; + is2->second = is2; + is->hThread = + CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread, + (LPVOID) is, 0, &is->id); + is2->hThread = + CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread, + (LPVOID) is2, 0, &is2->id); + break; + } + } + return (InputSourceRef) is; +} + +void +RemoveInputSource(InputSourceRef isr) +{ + InputSource *is; + + is = (InputSource *) isr; + is->hThread = NULL; /* tell thread to stop */ + CloseHandle(is->hThread); + if (is->second != NULL) { + is->second->hThread = NULL; + CloseHandle(is->second->hThread); + } +} + + +int +OutputToProcess(ProcRef pr, char *message, int count, int *outError) +{ + DWORD dOutCount; + int outCount = SOCKET_ERROR; + ChildProc *cp = (ChildProc *) pr; + static OVERLAPPED ovl; + + if (pr == NoProc) { + ConsoleOutput(message, count, FALSE); + return count; + } + + if (ovl.hEvent == NULL) { + ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + } + ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0; + + switch (cp->kind) { + case CPSock: + case CPRcmd: + outCount = send(cp->sock, message, count, 0); + if (outCount == SOCKET_ERROR) { + *outError = WSAGetLastError(); + } else { + *outError = NO_ERROR; + } + break; + + case CPReal: + if (WriteFile(((ChildProc *)pr)->hTo, message, count, + &dOutCount, NULL)) { + *outError = NO_ERROR; + outCount = (int) dOutCount; + } else { + *outError = GetLastError(); + } + break; + + case CPComm: + *outError = DoWriteFile(((ChildProc *)pr)->hTo, message, count, + &dOutCount, &ovl); + if (*outError == NO_ERROR) { + outCount = (int) dOutCount; + } + break; + } + return outCount; +} + +int +OutputToProcessDelayed(ProcRef pr, char *message, int count, int *outError, + long msdelay) +{ + /* Ignore delay, not implemented for WinBoard */ + return OutputToProcess(pr, message, count, outError); +} + + +void +CmailSigHandlerCallBack(InputSourceRef isr, VOIDSTAR closure, + char *buf, int count, int error) +{ + DisplayFatalError("Not implemented", 0, 1); +} + +/* see wgamelist.c for Game List functions */ +/* see wedittags.c for Edit Tags functions */ + + +VOID +ICSInitScript() +{ + FILE *f; + char buf[MSG_SIZ]; + char *dummy; + + if (SearchPath(installDir, appData.icsLogon, NULL, MSG_SIZ, buf, &dummy)) { + f = fopen(buf, "r"); + if (f != NULL) { + ProcessICSInitScript(f); + fclose(f); + } + } +} + + +VOID +StartAnalysisClock() +{ + if (analysisTimerEvent) return; + analysisTimerEvent = SetTimer(hwndMain, (UINT) ANALYSIS_TIMER_ID, + (UINT) 1000, NULL); +} + +LRESULT CALLBACK +NameSubClass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) +{ +/* + HWND Name; + CHARRANGE pos; +*/ + switch (message) { + switch (wParam) { + case VK_PRIOR: + return 0; + case VK_NEXT: + return 0; + } + break; + } + return (*NameWindowProc)(hwnd, message, wParam, lParam); +} + + +LRESULT CALLBACK +PvSubClass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + HWND pvDisplay; + int GetSel; + char buf[MSG_SIZ]; + pvDisplay = GetDlgItem(analysisDialog, OPT_AnalysisText); + + switch (message) { + case WM_MBUTTONUP: + case WM_RBUTTONUP: + { + POINT pt; + pt.x = LOWORD(lParam); + pt.y = HIWORD(lParam); + if (appData.icsActive) { + MenuPopup(pvDisplay, pt, LoadMenu(hInst, "ICSENGINEROOM"), -1); + } else { + MenuPopup(pvDisplay, pt, LoadMenu(hInst, "ENGINEROOM"), -1); + } + } + break; + case WM_COMMAND: + switch (LOWORD(wParam)) { + case IDM_SelectAll: + GetSel = SendMessage(hwnd, LB_GETCOUNT, 0, 0); + SendMessage(hwnd, LB_SETSEL, GetSel, -1); + case IDM_Copy: + GetSel = SendMessage(hwnd, LB_GETCOUNT, 0, 0); + SendMessage(hwnd, LB_SETSEL, GetSel, -1); + SendMessage(hwnd, LB_GETTEXT, 0, (LPARAM)&buf); + + + SendMessage(hwnd, WM_COPY, 0, 0); + case IDM_SelPaste: + GetSel = SendMessage(hwnd, LB_GETCOUNT, 0, 0); + SendMessage(hwnd, LB_SETSEL, GetSel, -1); + SendMessage(hwnd, LB_GETTEXT, 0, (LPARAM)&buf); + + /* + SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel); + SendMessage(hwnd, WM_COPY, 0, 0); + */ + return 0; + case IDM_MachineWhite: + SendMessage(hwndMain, WM_COMMAND, IDM_MachineWhite, 0); + break; + case IDM_MachineBlack: + SendMessage(hwndMain, WM_COMMAND, IDM_MachineBlack, 0); + break; + case IDM_AnalysisMode: + SendMessage(hwndMain, WM_COMMAND, IDM_AnalysisMode, 0); + break; + case IDM_MoveNow: + GuiCommand(1,0); + break; + case IDM_EnginesButton: + if (first.analyzing == TRUE || first.maybeThinking == TRUE) { + SetDlgItemText(analysisDialog, OPT_engineStart, "Start Engine"); + } else if (first.analyzing == FALSE || first.maybeThinking == FALSE) { + SetDlgItemText(analysisDialog, OPT_engineStart, "Stop Engine"); + } + GuiCommand(2,0); + break; + case IDM_OperatorTime: + default: + break; + } + } + return (*PvWindowProc)(hwnd, message, wParam, lParam); +} + + +VOID +AnalysisDialogEnable(HWND hDlg) +{ + + #define IS_CHECKED(x) (Boolean)IsDlgButtonChecked(hDlg, (x)) + appData.engineStatLine = IS_CHECKED(OPT_engineStatLine); + if (!appData.engineTourneyMode) { + appData.engineTourneyMode = IS_CHECKED(OPT_engineTourneyMode); + } + #undef IS_CHECKED + + #define ENABLE_DLG_ITEM(x,y) EnableWindow(GetDlgItem(hDlg,(x)), (y)) + if (appData.engineTourneyMode) { + /* Freeze GUI */ + EnableWindow(GetDlgItem(hDlg, OPT_engineStart), FALSE); + EnableWindow(GetDlgItem(hDlg, OPT_engineMove), FALSE); + /* disable myself B-) */ + EnableWindow(GetDlgItem(hDlg, OPT_engineTourneyMode), FALSE); + EnableWindow(GetDlgItem(hDlg, OPT_engineStatLine), FALSE); + EnableWindow(GetDlgItem(hDlg, OPT_SendToICS), FALSE); + return; + } else { + if (appData.icsActive) { + EnableWindow(GetDlgItem(hDlg, OPT_engineTourneyMode), FALSE); + if (gameMode == IcsObserving) { + EnableWindow(GetDlgItem(hDlg, OPT_engineStart), FALSE); + EnableWindow(GetDlgItem(hDlg, OPT_engineMove), FALSE); + EnableWindow(GetDlgItem(hDlg, OPT_engineStatLine), FALSE); + EnableWindow(GetDlgItem(hDlg, OPT_SendToICS), FALSE); + } else { + EnableWindow(GetDlgItem(hDlg, OPT_engineStart), FALSE); + EnableWindow(GetDlgItem(hDlg, OPT_engineMove), FALSE); + EnableWindow(GetDlgItem(hDlg, OPT_engineStatLine), TRUE); + EnableWindow(GetDlgItem(hDlg, OPT_SendToICS), TRUE); + } + /* normal mode */ + } else { + /* mh, all should allow ;-) */ + switch (gameMode) { + case AnalyzeMode: + case AnalyzeFile: + EnableWindow(GetDlgItem(hDlg, OPT_engineTourneyMode), FALSE); + EnableWindow(GetDlgItem(hDlg, OPT_engineStatLine), FALSE); + EnableWindow(GetDlgItem(hDlg, OPT_engineStart), TRUE); + EnableWindow(GetDlgItem(hDlg, OPT_engineMove), FALSE); + break; + case MachinePlaysWhite: + if (WhiteOnMove(currentMove)) EnableWindow(GetDlgItem(hDlg, OPT_engineMove), TRUE); + if (!WhiteOnMove(currentMove)) EnableWindow(GetDlgItem(hDlg, OPT_engineMove), FALSE); + EnableWindow(GetDlgItem(hDlg, OPT_engineStart), TRUE); + EnableWindow(GetDlgItem(hDlg, OPT_engineTourneyMode), TRUE); + EnableWindow(GetDlgItem(hDlg, OPT_engineStatLine), TRUE); + break; + case MachinePlaysBlack: + if (!WhiteOnMove(currentMove)) EnableWindow(GetDlgItem(hDlg, OPT_engineMove), TRUE); + if (WhiteOnMove(currentMove)) EnableWindow(GetDlgItem(hDlg, OPT_engineMove), FALSE); + EnableWindow(GetDlgItem(hDlg, OPT_engineStart), TRUE); + EnableWindow(GetDlgItem(hDlg, OPT_engineTourneyMode), TRUE); + EnableWindow(GetDlgItem(hDlg, OPT_engineStatLine), TRUE); + break; + default: + EnableWindow(GetDlgItem(hDlg, OPT_engineStart), TRUE); + EnableWindow(GetDlgItem(hDlg, OPT_engineMove), FALSE); + EnableWindow(GetDlgItem(hDlg, OPT_engineTourneyMode), TRUE); + EnableWindow(GetDlgItem(hDlg, OPT_engineStatLine), TRUE); + } + /* Send OPT_SendToICS only for ICS */ + EnableWindow(GetDlgItem(hDlg, OPT_SendToICS), FALSE); + appData.ButtonSendOutPutToICS = FALSE; + appData.SendOutPutToICS = 0; + } + } + #undef ENABLE_DLG_ITEM +} + + +LRESULT CALLBACK +AnalysisDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + static HWND pvDisplay; + static HWND Name; + static HANDLE depth; + static HANDLE nps; + static HANDLE nodes; + static HANDLE score; + static HANDLE move_nr; + static HANDLE time; + static HANDLE statistic; + static HANDLE tourney; + static HANDLE OutPutSendToICS; + + RECT rect; + RECT rectPV; + RECT rectStatistic; + RECT rectTourney; + + RECT rc; + LPMEASUREITEMSTRUCT lpmis; + LPARAM lparam; + + static int sizeX, sizeY; + int newSizeX, newSizeY, flags; + static int newTextHeight, newTextWidth; + + MINMAXINFO *mmi; + + COLORREF PvBkColor = RGB(224,218,222); + COLORREF NameColor = RGB(171,216,173); + COLORREF FailLow = RGB(255, 255, 34); + COLORREF FailHigh = RGB(255, 0, 0); + /* + * COLORREF TourneyColor = RGB(235, 80, 71); + */ + switch (message) { + case WM_INITDIALOG: /* message: initialize dialog box */ + /* Initialize the dialog items */ + pvDisplay = GetDlgItem(hDlg, OPT_AnalysisText); + depth = GetDlgItem(hDlg, OPT_engineDepth); + nps = GetDlgItem(hDlg, OPT_engineNPS); + nodes = GetDlgItem(hDlg, OPT_engineNodes); + score = GetDlgItem(hDlg, OPT_engineScore); + Name = GetDlgItem(hDlg, OPT_engineName); + move_nr = GetDlgItem(hDlg, OPT_engineMoveNr); + time = GetDlgItem(hDlg, OPT_engineTime); + statistic = GetDlgItem(hDlg, OPT_engineStatLine); + tourney = GetDlgItem(hDlg, OPT_engineTourneyMode); + OutPutSendToICS = GetDlgItem(hDlg, OPT_SendToICS); + + #define CHECK_BOX(x,y) CheckDlgButton(hDlg, (x), (BOOL)(y)) + #define IS_CHECKED(x) (Boolean)IsDlgButtonChecked(hDlg, (x)) + AnalysisDialogEnable(hDlg); + SetWindowText(hDlg, "Winboard Engine Room"); + NameWindowProc = (WNDPROC) + SetWindowLong(Name, GWL_WNDPROC, (LONG) NameSubClass); + PvWindowProc = (WNDPROC) + SetWindowLong(pvDisplay, GWL_WNDPROC, (LONG) PvSubClass); + + if (!analysisDialog) { + analysisDialog = hDlg; + flags = SWP_NOZORDER; + GetClientRect(hDlg, &rect); + sizeX = rect.right; + sizeY = rect.bottom; + SendMessage(pvDisplay, EM_SETBKGNDCOLOR, FALSE, PvBkColor); + SendMessage(Name, EM_SETBKGNDCOLOR, FALSE, NameColor); + /* gameMode - we do a check */ + AnalysisDialogEnable(hDlg); + if (analysisH < 200 || analysisW < 300) { + /* center - safty position at startup after broken*/ + analysisH = 330; + analysisW = 518; + CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER)); + } + if (analysisW != CW_USEDEFAULT && analysisH != CW_USEDEFAULT) { + WINDOWPLACEMENT wp; + EnsureOnScreen(&analysisX, &analysisY); + wp.length = sizeof(WINDOWPLACEMENT); + wp.flags = WPF_RESTORETOMAXIMIZED; + wp.showCmd = SW_SHOW|SW_RESTORE; + wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0; + wp.rcNormalPosition.left = analysisX; + wp.rcNormalPosition.right = analysisX + analysisW; + wp.rcNormalPosition.top = analysisY; + wp.rcNormalPosition.bottom = analysisY + analysisH; + SetWindowPlacement(hDlg, &wp); + GetClientRect(hDlg, &rect); + GetClientRect(pvDisplay, &rectPV); + GetClientRect(statistic, &rectStatistic); + GetClientRect(tourney, &rectTourney); + newSizeX = rect.right; + newSizeY = rect.bottom; + sizeX = newSizeX; + sizeY = newSizeY; + } + /* set focus to main window on start */ + SetFocus(hwndMain); + /* Check Send engine output to ICS */ + CHECK_BOX(OPT_SendToICS, appData.ButtonSendOutPutToICS); + } + return FALSE; + + case WM_MEASUREITEM: + // lpmis = (LPMEASUREITEMSTRUCT) lparam; + // GetWindowRect(GetDlgItem(pvDisplay, lpmis->CtlID), &rc); + break; + + case WM_DRAWITEM: + break; + + case WM_COMMAND: /* message: received a command */ + CHECK_BOX(OPT_engineStatLine, appData.engineStatLine); + CHECK_BOX(OPT_engineTourneyMode, appData.engineTourneyMode); + + switch (LOWORD(wParam)) { + case OPT_engineMove: + GuiCommand(1, 0); + break; + case OPT_engineStart: + if (first.analyzing == TRUE || first.maybeThinking == TRUE) { + SetDlgItemText(analysisDialog, OPT_engineStart, "Start Engine"); + } else if (first.analyzing == FALSE || first.maybeThinking == FALSE) { + SetDlgItemText(analysisDialog, OPT_engineStart, "Stop Engine"); + } + GuiCommand(2, 0); + break; + case OPT_engineStatLine: + /* over checkbox vars */ + break; + case OPT_SendToICS: + appData.ButtonSendOutPutToICS = IS_CHECKED(OPT_SendToICS); + + if (appData.ButtonSendOutPutToICS) { + appData.SendOutPutToICS = 1; + } else { + appData.SendOutPutToICS = 0; + } + break; + case OPT_engineTourneyMode: + /*appData.engineTourneyMode = TRUE;*/ + MessageBox(hDlg, "Tourney Mode: Disable a lot of WB function.\rYou can leave this mode by closing Engine Room Window !\r\ +This mode is for events suchs as World Champion Chips\rbut not ready at the moment.", + "ICCA/FIDE Tourney Mode", MB_OK); + SetWindowText(analysisDialog, "Winboard Engine Room - Tourney Mode"); + SetWindowText(hwndMain, "Winboard - Tourney Mode"); + break; + case IDCANCEL: + /* TourneyMode off */ + if (appData.engineTourneyMode) { + CheckDlgButton(hDlg, OPT_engineTourneyMode, BST_UNCHECKED); + appData.engineTourneyMode = FALSE; + AnalysisDialogEnable(hDlg); + SetWindowText(analysisDialog, "Winboard Engine Room"); + break; + } + if (gameMode == MachinePlaysWhite || gameMode == MachinePlaysBlack || + gameMode == IcsPlayingWhite || gameMode == IcsPlayingBlack) { + appData.AnalysisWindow = FALSE; + AnalysisPopDown(); + } else if (gameMode == IcsObserving) { + appData.icsAnalyzeWindow = FALSE; + AnalysisPopDown(); + } else { + AnalysisPopDown(); + appData.AnalysisWindow = FALSE; + EditGameEvent(); + } + return TRUE; + + default: + AnalysisDialogEnable(hDlg); + break; + } + break; + + case WM_SIZE: + newSizeX = LOWORD(lParam); + newSizeY = HIWORD(lParam); + if (sizeX != newSizeX || sizeY != newSizeY) { + GetWindowRect(pvDisplay, &rectPV); + newTextWidth = rectPV.right - + rectPV.left + newSizeX - sizeX; + newTextHeight = rectPV.bottom - + rectPV.top + newSizeY - sizeY; + if (newTextHeight < 0) { + newSizeY += -newTextHeight; + newTextHeight = 0; + } + SetWindowPos(pvDisplay, NULL, 0, 0, + newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE); + + } + sizeX = newSizeX; + sizeY = newSizeY; + break; + + case WM_GETMINMAXINFO: + mmi = (MINMAXINFO *) lParam; + mmi->ptMinTrackSize.x = 518; + mmi->ptMinTrackSize.y = 250; + break; + + case WM_QUERYOPEN: + MoveWindow(pvDisplay, sizeX, sizeY, newTextWidth, + newTextHeight, TRUE); + /* engineRoom no longer a parent Window */ + /* possible that hwndMain is hidden */ + /* if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE); */ + break; + + default: + AnalysisDialogEnable(hDlg); + break; + } + return FALSE; +} + +/* Engine Room */ + +/* style from EngineRoom */ +void +SetEngineRoomFonts() +{ + CHARFORMAT2 pvdisplayf; + CHARFORMAT2 enginenamf; + HWND PvDisplay; + HWND Name; + PvDisplay = GetDlgItem(analysisDialog, OPT_AnalysisText); + Name = GetDlgItem(analysisDialog, OPT_engineName); + + /* PV screen */ + pvdisplayf.cbSize = sizeof(CHARFORMAT); + pvdisplayf.bCharSet = DEFAULT_CHARSET; + pvdisplayf.dwMask = CFM_COLOR|CFM_BOLD|CFM_SPACING| + CFM_ITALIC|CFM_CHARSET|CFM_WEIGHT; + pvdisplayf.dwEffects = CFE_ITALIC; + pvdisplayf.wWeight = 2; + pvdisplayf.sSpacing = 10; + pvdisplayf.crTextColor = RGB(0,0,0); + + /* + SendMessage(PvDisplay, EM_SETCHARFORMAT, (WPARAM) SCF_ALL, + (LPARAM) &pvdisplayf); + */ + + /* engine Name */ + enginenamf.cbSize = sizeof(CHARFORMAT); + enginenamf.bCharSet = "Arial Black"; + enginenamf.dwMask = CFM_BOLD; + enginenamf.crTextColor = RGB(0,0,0); + enginenamf.dwEffects = CFE_BOLD; + + SendMessage(Name, EM_SETCHARFORMAT, (WPARAM) SCF_ALL, + (LPARAM) &enginenamf); +} + +/* dirty dirty code: use buffer. I can use EM_*. If i have more time ... + * WriteText is allso better. If War Room comes (2 engine window) i will + * change to good code. At the moment we work with dirty buffers + */ +int i; + +VOID +AnalysisPopUp(pv, depth, nps, nodes, score, move_nr, time, state) +char* pv; +char* depth; +char* nps; +char* nodes; +char* score; +char* move_nr; +char* time; +int state; +{ + FARPROC lpProc; + HWND pvDisplay; + HWND Name; + HWND engineStart; + + COLORREF NamePonder = RGB(255, 132, 132); /* opponent/ponder on move */ + COLORREF NameColor = RGB(171,216,173); /* we are on move */ + COLORREF NameAnalyze = RGB(148, 148, 248); /* Analyze anf FileanalyzeMode */ + COLORREF NameObserve = RGB(241, 248, 116); /* ICS observe */ + + + static char last_pv[MSG_SIZ]; + char pv_output[16384]; + static int last_move; + static int counter, last_line; + pvDisplay = GetDlgItem(analysisDialog, OPT_AnalysisText); + Name = GetDlgItem(analysisDialog, OPT_engineName); + engineStart = GetDlgItem(analysisDialog, OPT_engineStart); + + if (!analysisDialog) { + lpProc = MakeProcInstance((FARPROC)AnalysisDialog, hInst); + CreateDialog(hInst, MAKEINTRESOURCE(DLG_Analysis), + 0, (DLGPROC)lpProc); + FreeProcInstance(lpProc); + SetEngineRoomFonts(); + /* engine button don't support icsMode */ + if (appData.icsActive) { + SetDlgItemText(analysisDialog, OPT_engineStart, "Disable"); + SetDlgItemText(analysisDialog, OPT_engineMove, "Disable"); + } else { + SetDlgItemText(analysisDialog, OPT_engineStart, "Start Engine"); + SetDlgItemText(analysisDialog, OPT_engineMove, "Move!"); + } + /* if state 5 we have a WB bootup init */ + if (state == 5) { + DisplayAnalysis(0,0); + SendDlgItemMessage(analysisDialog, OPT_AnalysisText, + LB_ADDSTRING, (WPARAM) 0, + (LPARAM) "ready for play"); + //SetDlgItemText(analysisDialog, OPT_AnalysisText, "ready for play"); + return; + } + } + + /* check if core part say no support for stat line */ + /* only if new game or so */ + if (appData.engineStatLine == TRUE) { + CheckDlgButton(analysisDialog, OPT_engineStatLine, BST_CHECKED); + SetDlgItemText(analysisDialog, OPT_engineMoveNr, "disable"); + } else if (appData.engineStatLine == FALSE) { + CheckDlgButton(analysisDialog, OPT_engineStatLine, BST_UNCHECKED); + } + + /* new move - begin from 0 */ + if (last_move != currentMove) { + SendDlgItemMessage(analysisDialog, OPT_AnalysisText, LB_RESETCONTENT, 0, 0); + last_move = currentMove; + counter = 0; + } + + /* Set engine button to engine state */ + if (pv[0] != NULLCHAR) { + if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) { + if (first.analyzing == TRUE) { + SetDlgItemText(analysisDialog, OPT_engineStart, "Stop Engine"); + + } + } else if (gameMode == MachinePlaysWhite || gameMode == MachinePlaysBlack) { + if (first.maybeThinking) { + SetDlgItemText(analysisDialog, OPT_engineStart, "Stop Engine"); + } + } + } + /* colorize EngineName - really check every action? */ + /* If we fast yes, think about build a own function + * and set it on GameModeEvent() + */ + switch (state) { + case 0: + SendMessage(Name, EM_SETBKGNDCOLOR, FALSE, NameColor); + break; + case 1: + SendMessage(Name, EM_SETBKGNDCOLOR, FALSE, NamePonder); + break; + case 2: + SendMessage(Name, EM_SETBKGNDCOLOR, FALSE, NameAnalyze); + break; + case 3: + SendMessage(Name, EM_SETBKGNDCOLOR, FALSE, NameObserve); + break; + } + + if (pv[0] != NULLCHAR) { + strcpy(pv_output, time); + strcat(pv_output, pv); + strcpy(engineRoom[counter].mainline, pv_output); + + counter++; + + /* + for (i = 0; i <= counter; i++) { + if (i == 0) { + strcpy(pv_output, engineRoom[i].mainline); + strcat(pv_output, "\r\n"); + } else if (i == counter) { + strcat(pv_output, engineRoom[i].mainline); + } else { + strcat(pv_output, engineRoom[i].mainline); + strcat(pv_output, "\r\n"); + } + } + //SetDlgItemText(analysisDialog, OPT_AnalysisText, pv_output); + */ + + + SendDlgItemMessage(analysisDialog, OPT_AnalysisText, LB_ADDSTRING, (WPARAM) 0, (LPARAM) pv_output); + + /* mark last pv */ + SendDlgItemMessage(analysisDialog, OPT_AnalysisText, LB_SETSEL, 0, -1); + SendDlgItemMessage(analysisDialog, OPT_AnalysisText, LB_SETSEL, counter, counter-1); + + SendMessage(pvDisplay, WM_VSCROLL, SB_BOTTOM, 0); + } + + SetDlgItemText(analysisDialog, OPT_engineDepth, depth); + SetDlgItemText(analysisDialog, OPT_engineNPS, nps); + SetDlgItemText(analysisDialog, OPT_engineNodes, nodes); + SetDlgItemText(analysisDialog, OPT_engineScore, score); + SetDlgItemText(analysisDialog, OPT_engineMoveNr, move_nr); + SetDlgItemText(analysisDialog, OPT_engineTime, time); + SetDlgItemText(analysisDialog, OPT_engineHash, "reserved"); + SetDlgItemText(analysisDialog, OPT_egtb, "reserved"); + if (state == 4) { + SetDlgItemText(analysisDialog, OPT_engineName, "no support"); + if (appData.AnalysisWindow) { + /* We need an other window and a *queue* for each engine to + * read data !! + */ + appData.AnalysisWindow = FALSE; + SetDlgItemText(analysisDialog, OPT_AnalysisText, + "Sorry, no Support. Please wait for a coming Engine War Room !"); + /* take TourneyMode to block user action ;-) */ + if (!appData.engineTourneyMode) appData.engineTourneyMode = TRUE; + } + } else { + /* We don't need this because we have only 1 engine + * and set on start should be enought, but for tests + * it's enable at the moment + */ + SetDlgItemText(analysisDialog, OPT_engineName, first.tidy); + } + + strcpy(last_pv, pv); + if (analysisDialogUp != TRUE) { + analysisDialogUp = TRUE; + ShowWindow(analysisDialog, SW_SHOW); + } +} + +VOID +AnalysisPopDown() +{ + if (analysisDialog) { + ShowWindow(analysisDialog, SW_HIDE); + } + analysisDialogUp = FALSE; +} + + +VOID +SetHighlights(int fromX, int fromY, int toX, int toY) +{ + highlightInfo.sq[0].x = fromX; + highlightInfo.sq[0].y = fromY; + highlightInfo.sq[1].x = toX; + highlightInfo.sq[1].y = toY; +} + +VOID +ClearHighlights() +{ + highlightInfo.sq[0].x = highlightInfo.sq[0].y = + highlightInfo.sq[1].x = highlightInfo.sq[1].y = -1; +} + +VOID +SetPremoveHighlights(int fromX, int fromY, int toX, int toY) +{ + premoveHighlightInfo.sq[0].x = fromX; + premoveHighlightInfo.sq[0].y = fromY; + premoveHighlightInfo.sq[1].x = toX; + premoveHighlightInfo.sq[1].y = toY; +} + +VOID +ClearPremoveHighlights() +{ + premoveHighlightInfo.sq[0].x = premoveHighlightInfo.sq[0].y = + premoveHighlightInfo.sq[1].x = premoveHighlightInfo.sq[1].y = -1; +} + +VOID +ShutDownFrontEnd() +{ + if (saveSettingsOnExit) SaveSettings(settingsFileName); + DeleteClipboardTempFiles(); +} + +void +BoardToTop() +{ + if (IsIconic(hwndMain)) + ShowWindow(hwndMain, SW_RESTORE); + + SetActiveWindow(hwndMain); +} + +/* + * Prototypes for animation support routines + */ +static void ScreenSquare(int column, int row, POINT * pt); +static void Tween( POINT * start, POINT * mid, POINT * finish, int factor, + POINT frames[], int * nFrames); + + +#define kFactor 4 + +void +AnimateMove(board, fromX, fromY, toX, toY) + Board board; + int fromX; + int fromY; + int toX; + int toY; +{ + ChessSquare piece; + POINT start, finish, mid; + POINT frames[kFactor * 2 + 1]; + int nFrames, n; + + if (!appData.animate) return; + if (doingSizing) return; + if (fromY < 0 || fromX < 0) return; + piece = board[fromY][fromX]; + if (piece >= EmptySquare) return; + + ScreenSquare(fromX, fromY, &start); + ScreenSquare(toX, toY, &finish); + + /* All pieces except knights move in straight line */ + if (piece != WhiteKnight && piece != BlackKnight) { + mid.x = start.x + (finish.x - start.x) / 2; + mid.y = start.y + (finish.y - start.y) / 2; + } else { + /* Knight: make diagonal movement then straight */ + if (abs(toY - fromY) < abs(toX - fromX)) { + mid.x = start.x + (finish.x - start.x) / 2; + mid.y = finish.y; + } else { + mid.x = finish.x; + mid.y = start.y + (finish.y - start.y) / 2; + } + } + + /* Don't use as many frames for very short moves */ + if (abs(toY - fromY) + abs(toX - fromX) <= 2) + Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames); + else + Tween(&start, &mid, &finish, kFactor, frames, &nFrames); + + animInfo.from.x = fromX; + animInfo.from.y = fromY; + animInfo.to.x = toX; + animInfo.to.y = toY; + animInfo.lastpos = start; + animInfo.piece = piece; + for (n = 0; n < nFrames; n++) { + animInfo.pos = frames[n]; + DrawPosition(FALSE, NULL); + animInfo.lastpos = animInfo.pos; + Sleep(appData.animSpeed); + } + animInfo.pos = finish; + DrawPosition(FALSE, NULL); + animInfo.piece = EmptySquare; +} + +/* Convert board position to corner of screen rect and color */ + +static void +ScreenSquare(column, row, pt) + int column; int row; POINT * pt; +{ + if (flipView) { + pt->x = lineGap + ((BOARD_SIZE-1)-column) * (squareSize + lineGap); + pt->y = lineGap + row * (squareSize + lineGap); + } else { + pt->x = lineGap + column * (squareSize + lineGap); + pt->y = lineGap + ((BOARD_SIZE-1)-row) * (squareSize + lineGap); + } +} + +/* Generate a series of frame coords from start->mid->finish. + The movement rate doubles until the half way point is + reached, then halves back down to the final destination, + which gives a nice slow in/out effect. The algorithmn + may seem to generate too many intermediates for short + moves, but remember that the purpose is to attract the + viewers attention to the piece about to be moved and + then to where it ends up. Too few frames would be less + noticeable. */ + +static void +Tween(start, mid, finish, factor, frames, nFrames) + POINT * start; POINT * mid; + POINT * finish; int factor; + POINT frames[]; int * nFrames; +{ + int n, fraction = 1, count = 0; + + /* Slow in, stepping 1/16th, then 1/8th, ... */ + for (n = 0; n < factor; n++) + fraction *= 2; + for (n = 0; n < factor; n++) { + frames[count].x = start->x + (mid->x - start->x) / fraction; + frames[count].y = start->y + (mid->y - start->y) / fraction; + count ++; + fraction = fraction / 2; + } + + /* Midpoint */ + frames[count] = *mid; + count ++; + + /* Slow out, stepping 1/2, then 1/4, ... */ + fraction = 2; + for (n = 0; n < factor; n++) { + frames[count].x = finish->x - (finish->x - mid->x) / fraction; + frames[count].y = finish->y - (finish->y - mid->y) / fraction; + count ++; + fraction = fraction * 2; + } + *nFrames = count; +} + +void +HistorySet(char movelist[][2*MOVE_LEN], int first, int last, int current) +{ + /* Currently not implemented in WinBoard */ +} + + diff --git a/winboard-dm-beta4/winboard.dsp b/winboard-dm-beta4/winboard.dsp new file mode 100755 index 00000000..9a25d506 --- /dev/null +++ b/winboard-dm-beta4/winboard.dsp @@ -0,0 +1,1776 @@ +# Microsoft Developer Studio Project File - Name="winboard" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** NICHT BEARBEITEN ** + +# TARGTYPE "Win32 (x86) External Target" 0x0106 + +CFG=winboard - Win32 Release +!MESSAGE Dies ist kein gültiges Makefile. Zum Erstellen dieses Projekts mit NMAKE +!MESSAGE verwenden Sie den Befehl "Makefile exportieren" und führen Sie den Befehl +!MESSAGE +!MESSAGE NMAKE /f "winboard.mak". +!MESSAGE +!MESSAGE Sie können beim Ausführen von NMAKE eine Konfiguration angeben +!MESSAGE durch Definieren des Makros CFG in der Befehlszeile. Zum Beispiel: +!MESSAGE +!MESSAGE NMAKE /f "winboard.mak" CFG="winboard - Win32 Release" +!MESSAGE +!MESSAGE Für die Konfiguration stehen zur Auswahl: +!MESSAGE +!MESSAGE "winboard - Win32 Release" (basierend auf "Win32 (x86) External Target") +!MESSAGE "winboard - Win32 Debug" (basierend auf "Win32 (x86) External Target") +!MESSAGE "winboard - Win32 Opt" (basierend auf "Win32 (x86) External Target") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" + +!IF "$(CFG)" == "winboard - Win32 Release" + +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir ".\Release" +# PROP BASE Intermediate_Dir ".\Release" +# PROP BASE Cmd_Line "NMAKE /f winboard.mak" +# PROP BASE Rebuild_Opt "/a" +# PROP BASE Target_File "winboard.exe" +# PROP BASE Bsc_Name "winboard.bsc" +# PROP BASE Target_Dir "" +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir ".\Release" +# PROP Intermediate_Dir ".\Release" +# PROP Cmd_Line "NMAKE" +# PROP Rebuild_Opt "/a" +# PROP Target_File "winboard.exe" +# PROP Bsc_Name "winboard.bsc" +# PROP Target_Dir "" + +!ELSEIF "$(CFG)" == "winboard - Win32 Debug" + +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir ".\Debug" +# PROP BASE Intermediate_Dir ".\Debug" +# PROP BASE Cmd_Line "NMAKE /f winboard.mak" +# PROP BASE Rebuild_Opt "/a" +# PROP BASE Target_File "winboard.exe" +# PROP BASE Bsc_Name "winboard.bsc" +# PROP BASE Target_Dir "" +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir ".\Debug" +# PROP Intermediate_Dir ".\Debug" +# PROP Cmd_Line "NMAKE" +# PROP Rebuild_Opt "" +# PROP Target_File "winboard.exe" +# PROP Bsc_Name "winboard.bsc" +# PROP Target_Dir "" + +!ELSEIF "$(CFG)" == "winboard - Win32 Opt" + +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "winboard___Win32_Opt" +# PROP BASE Intermediate_Dir "winboard___Win32_Opt" +# PROP BASE Cmd_Line "NMAKE" +# PROP BASE Rebuild_Opt "/a" +# PROP BASE Target_File "winboard.exe" +# PROP BASE Bsc_Name "winboard.bsc" +# PROP BASE Target_Dir "" +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "winboard___Win32_Opt" +# PROP Intermediate_Dir "winboard___Win32_Opt" +# PROP Cmd_Line "NMAKE" +# PROP Rebuild_Opt "/a" +# PROP Target_File "winboard.exe" +# PROP Bsc_Name "winboard.bsc" +# PROP Target_Dir "" + +!ENDIF + +# Begin Target + +# Name "winboard - Win32 Release" +# Name "winboard - Win32 Debug" +# Name "winboard - Win32 Opt" + +!IF "$(CFG)" == "winboard - Win32 Release" + +!ELSEIF "$(CFG)" == "winboard - Win32 Debug" + +!ELSEIF "$(CFG)" == "winboard - Win32 Opt" + +!ENDIF + +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;hpj;bat;for;f90" +# Begin Source File + +SOURCE=.\backend.c +# End Source File +# Begin Source File + +SOURCE=.\gamelist.c +# End Source File +# Begin Source File + +SOURCE=.\lists.c +# End Source File +# Begin Source File + +SOURCE=.\moves.c +# End Source File +# Begin Source File + +SOURCE=.\parser.c +# End Source File +# Begin Source File + +SOURCE=.\parser.l +# End Source File +# Begin Source File + +SOURCE=.\pgntags.c +# End Source File +# Begin Source File + +SOURCE=.\wedittags.c +# End Source File +# Begin Source File + +SOURCE=.\wgamelist.c +# End Source File +# Begin Source File + +SOURCE=.\winboard.c +# End Source File +# Begin Source File + +SOURCE=.\woptions.c +# End Source File +# Begin Source File + +SOURCE=.\wsockerr.c +# End Source File +# Begin Source File + +SOURCE=.\zippy.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl;fi;fd" +# Begin Source File + +SOURCE=.\backend.h +# End Source File +# Begin Source File + +SOURCE=.\backendz.h +# End Source File +# Begin Source File + +SOURCE=.\common.h +# End Source File +# Begin Source File + +SOURCE=.\config.h +# End Source File +# Begin Source File + +SOURCE=.\defaults.h +# End Source File +# Begin Source File + +SOURCE=.\frontend.h +# End Source File +# Begin Source File + +SOURCE=.\lists.h +# End Source File +# Begin Source File + +SOURCE=.\moves.h +# End Source File +# Begin Source File + +SOURCE=.\parser.h +# End Source File +# Begin Source File + +SOURCE=.\resource.h +# End Source File +# Begin Source File + +SOURCE=.\wedittags.h +# End Source File +# Begin Source File + +SOURCE=.\wgamelist.h +# End Source File +# Begin Source File + +SOURCE=.\winboard.h +# End Source File +# Begin Source File + +SOURCE=.\woptions.h +# End Source File +# Begin Source File + +SOURCE=.\wsockerr.h +# End Source File +# Begin Source File + +SOURCE=.\zippy.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe" +# Begin Source File + +SOURCE=.\bitmaps\b108o.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\b108s.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\b108w.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\b116o.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\b116s.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\b116w.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\b129o.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\b129s.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\b129w.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\B21o.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\B21s.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\b21w.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\b25o.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\b25s.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\b25w.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\b29o.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\b29s.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\b29w.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\b33o.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\b33s.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\b33w.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\b37o.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\b37s.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\b37w.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\B40o.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\B40s.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\b40w.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\b45o.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\b45s.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\b45w.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\b49o.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\b49s.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\b49w.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\b54o.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\b54s.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\b54w.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\b58o.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\b58s.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\b58w.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\b64o.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\B64s.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\b64w.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\b72o.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\b72s.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\b72w.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\B80o.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\B80s.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\b80w.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\b87o.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\b87s.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\b87w.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\b95o.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\b95s.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\b95w.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\bepbeep.wav +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\board.ico +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\ching.wav +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\click.wav +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\cymbal.wav +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\Ding1.wav +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\doodloop.wav +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\drip.wav +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\galactic.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\gong.wav +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\honkhonk.wav +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\icon_b.ico +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\icon_ob.ico +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\icon_ow.ico +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\icon_whi.ico +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\k108o.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\k108s.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\k108w.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\k116o.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\k116s.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\k116w.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\k129o.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\k129s.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\k129w.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\K21o.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\K21s.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\k21w.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\k25o.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\k25s.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\k25w.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\k29o.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\k29s.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\k29w.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\k33o.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\k33s.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\k33w.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\k37o.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\k37s.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\k37w.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\k40o.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\k40s.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\k40w.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\k45o.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\k45s.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\k45w.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\k49o.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\k49s.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\k49w.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\k54o.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\k54s.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\k54w.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\k58o.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\k58s.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\k58w.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\k64o.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\k64s.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\k64w.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\k72o.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\k72s.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\k72w.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\k80o.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\k80s.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\k80w.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\k87o.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\k87s.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\k87w.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\k95o.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\k95s.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\k95w.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\laser.wav +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\move.wav +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\n108o.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\n108s.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\n108w.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\n116o.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\n116s.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\n116w.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\n129o.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\n129s.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\n129w.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\N21o.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\N21s.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\n21w.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\n25o.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\n25s.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\n25w.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\n29o.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\n29s.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\n29w.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\n33o.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\n33s.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\n33w.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\n37o.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\n37s.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\n37w.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\n40o.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\n40s.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\n40w.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\n45o.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\n45s.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\n45w.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\n49o.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\n49s.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\n49w.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\n54o.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\n54s.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\n54w.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\n58o.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\n58s.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\n58w.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\n64o.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\n64s.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\n64w.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\n72o.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\n72s.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\n72w.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\n80o.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\n80s.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\n80w.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\n87o.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\n87s.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\n87w.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\n95o.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\n95s.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\n95w.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\p108o.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\p108s.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\p108w.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\p116o.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\p116s.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\p116w.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\p129o.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\p129s.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\p129w.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\P21o.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\P21s.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\p21w.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\p25o.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\p25s.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\p25w.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\p29o.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\p29s.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\p29w.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\p33o.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\p33s.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\p33w.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\p37o.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\p37s.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\p37w.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\p40o.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\p40s.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\p40w.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\p45o.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\p45s.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\p45w.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\p49o.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\p49s.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\p49w.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\p54o.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\p54s.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\p54w.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\p58o.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\p58s.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\p58w.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\p64o.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\p64s.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\p64w.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\p72o.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\p72s.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\p72w.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\p80o.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\p80s.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\p80w.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\p87o.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\p87s.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\p87w.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\p95o.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\p95s.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\p95w.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\penalty.wav +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\phone.wav +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\pop.wav +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\pop2.wav +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\q108o.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\q108s.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\q108w.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\q116o.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\q116s.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\q116w.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\q129o.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\q129s.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\q129w.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\Q21o.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\Q21s.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\q21w.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\q25o.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\q25s.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\q25w.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\q29o.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\q29s.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\q29w.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\q33o.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\q33s.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\q33w.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\q37o.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\q37s.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\q37w.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\q40o.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\q40s.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\q40w.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\q45o.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\q45s.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\q45w.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\q49o.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\q49s.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\q49w.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\q54o.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\q54s.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\q54w.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\q58o.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\q58s.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\q58w.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\q64o.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\q64s.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\q64w.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\q72o.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\q72s.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\q72w.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\q80o.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\q80s.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\q80w.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\q87o.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\q87s.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\q87w.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\q95o.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\q95s.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\q95w.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\r108o.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\r108s.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\r108w.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\r116o.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\r116s.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\r116w.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\r129o.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\r129s.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\r129w.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\R21o.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\R21s.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\r21w.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\r25o.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\r25s.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\r25w.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\r29o.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\r29s.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\r29w.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\r33o.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\r33s.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\r33w.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\r37o.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\r37s.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\r37w.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\r40o.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\r40s.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\r40w.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\r45o.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\r45s.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\r45w.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\r49o.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\r49s.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\r49w.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\r54o.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\r54s.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\r54w.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\r58o.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\r58s.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\r58w.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\r64o.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\r64s.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\r64w.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\r72o.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\r72s.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\r72w.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\R80o.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\R80s.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\r80w.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\r87o.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\r87s.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\r87w.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\r95o.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\r95s.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\r95w.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\slap.wav +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\squeak.wav +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\swish.wav +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\thud.wav +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\tim.bmp +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\whipcrak.wav +# End Source File +# Begin Source File + +SOURCE=.\winboard.rc +# End Source File +# Begin Source File + +SOURCE=.\WINBOARD.rtf +# End Source File +# Begin Source File + +SOURCE=.\bitmaps\zap.wav +# End Source File +# End Group +# Begin Source File + +SOURCE=.\sounds\alarm.wav +# End Source File +# Begin Source File + +SOURCE=.\sounds\challenge.wav +# End Source File +# Begin Source File + +SOURCE=.\sounds\channel.wav +# End Source File +# Begin Source File + +SOURCE=.\sounds\channel1.wav +# End Source File +# Begin Source File + +SOURCE=.\sounds\ching.wav +# End Source File +# Begin Source File + +SOURCE=.\sounds\click.wav +# End Source File +# Begin Source File + +SOURCE=.\sounds\cymbal.wav +# End Source File +# Begin Source File + +SOURCE=.\sounds\ding1.wav +# End Source File +# Begin Source File + +SOURCE=.\sounds\draw.wav +# End Source File +# Begin Source File + +SOURCE=.\sounds\drip.wav +# End Source File +# Begin Source File + +SOURCE=.\sounds\gong.wav +# End Source File +# Begin Source File + +SOURCE=.\sounds\honkhonk.wav +# End Source File +# Begin Source File + +SOURCE=.\sounds\kibitz.wav +# End Source File +# Begin Source File + +SOURCE=.\sounds\laser.wav +# End Source File +# Begin Source File + +SOURCE=.\sounds\lose.wav +# End Source File +# Begin Source File + +SOURCE=.\sounds\move.wav +# End Source File +# Begin Source File + +SOURCE=.\sounds\penalty.wav +# End Source File +# Begin Source File + +SOURCE=.\sounds\phone.wav +# End Source File +# Begin Source File + +SOURCE=.\sounds\pop.wav +# End Source File +# Begin Source File + +SOURCE=.\sounds\pop2.wav +# End Source File +# Begin Source File + +SOURCE=.\sounds\request.wav +# End Source File +# Begin Source File + +SOURCE=.\sounds\seek.wav +# End Source File +# Begin Source File + +SOURCE=.\sounds\shout.wav +# End Source File +# Begin Source File + +SOURCE=.\sounds\slap.wav +# End Source File +# Begin Source File + +SOURCE=.\sounds\squeak.wav +# End Source File +# Begin Source File + +SOURCE=.\sounds\sshout.wav +# End Source File +# Begin Source File + +SOURCE=.\sounds\swish.wav +# End Source File +# Begin Source File + +SOURCE=.\sounds\tell.wav +# End Source File +# Begin Source File + +SOURCE=.\sounds\thud.wav +# End Source File +# Begin Source File + +SOURCE=.\sounds\unfinished.wav +# End Source File +# Begin Source File + +SOURCE=.\sounds\whipcrak.wav +# End Source File +# Begin Source File + +SOURCE=.\sounds\win.wav +# End Source File +# End Target +# End Project diff --git a/winboard-dm-beta4/winboard.dsw b/winboard-dm-beta4/winboard.dsw new file mode 100755 index 00000000..0374221d --- /dev/null +++ b/winboard-dm-beta4/winboard.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNUNG: DIESE ARBEITSBEREICHSDATEI DARF NICHT BEARBEITET ODER GELÖSCHT WERDEN! + +############################################################################### + +Project: "winboard"=.\winboard.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/winboard-dm-beta4/winboard.h b/winboard-dm-beta4/winboard.h new file mode 100755 index 00000000..db7c2bd3 --- /dev/null +++ b/winboard-dm-beta4/winboard.h @@ -0,0 +1,165 @@ +/* + * WinBoard.h -- Definitions for Windows NT front end to XBoard + * + * Copyright 1991 by Digital Equipment Corporation, Maynard, Massachusetts. + * Enhancements Copyright 1992-97 Free Software Foundation, Inc. + * + * The following terms apply to Digital Equipment Corporation's copyright + * interest in XBoard: + * ------------------------------------------------------------------------ + * All Rights Reserved + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appear in all copies and that + * both that copyright notice and this permission notice appear in + * supporting documentation, and that the name of Digital not be + * used in advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. + * + * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING + * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL + * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR + * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, + * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + * ------------------------------------------------------------------------ + * + * The following terms apply to the enhanced version of XBoard distributed + * by the Free Software Foundation: + * ------------------------------------------------------------------------ + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * ------------------------------------------------------------------------ + */ +#include "resource.h" +#include + +/* Types */ +typedef struct { + char faceName[LF_FACESIZE]; + float pointSize; + BYTE bold, italic, underline, strikeout; +} MyFontParams; + +typedef struct { + char *def; + MyFontParams mfp; + LOGFONT lf; + HFONT hf; +} MyFont; + +typedef enum { + SizeTiny, SizeTeeny, SizeDinky, SizePetite, SizeSlim, SizeSmall, + SizeMediocre, SizeMiddling, SizeAverage, SizeModerate, SizeMedium, + SizeBulky, SizeLarge, SizeBig, SizeHuge, SizeGiant, SizeColossal, + SizeTitanic, NUM_SIZES +} BoardSize; + +typedef struct { + COLORREF color; + int effects; + char *name; +} MyColorizeAttribs; + +typedef struct { + char* name; + void* data; +} MySound; + +typedef struct { + COLORREF color; + int effects; + MySound sound; +} MyTextAttribs; + +/* Functions */ + +BOOL InitApplication(HINSTANCE); +BOOL InitInstance(HINSTANCE, int, LPSTR); +LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); +LRESULT CALLBACK About(HWND, UINT, WPARAM, LPARAM); +LRESULT CALLBACK BoardSizeDlg(HWND, UINT, WPARAM, LPARAM); +LRESULT CALLBACK ButtonProc(HWND, UINT, WPARAM, LPARAM); +VOID InitAppData(LPSTR); +VOID InitDrawingColors(VOID); +VOID InitDrawingSizes(BoardSize boardSize, int flags); +VOID InitMenuChecks(VOID); +VOID ICSInitScript(VOID); +BOOL CenterWindow(HWND hwndChild, HWND hwndParent); +VOID ResizeEditPlusButtons(HWND hDlg, HWND hText, int sizeX, int sizeY, int newSizeX, int newSizeY); +VOID PromotionPopup(HWND hwnd); +FILE *OpenFileDialog(HWND hWnd, BOOL write, char *defName, char *defExt, + char *nameFilt, char *dlgTitle, UINT *number, + char fileTitle[MSG_SIZ], char fileName[MSG_SIZ]); +VOID InputEvent(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); +DWORD InputThread(LPVOID arg); +DWORD NonOvlInputThread(LPVOID arg); +DWORD SocketInputThread(LPVOID arg); +BOOL ChangeColor(HWND hwnd, COLORREF *which); +VOID ChangeBoardSize(BoardSize newSize); +BOOL APIENTRY MyCreateFont(HWND hwnd, MyFont *font); +VOID ErrorPopDown(VOID); +VOID EnsureOnScreen(int *x, int *y); +typedef char GetFunc(void *getClosure); +VOID ParseArgs(GetFunc get, void *cl); +HBITMAP +DoLoadBitmap(HINSTANCE hinst, char *piece, int squareSize, char *suffix); +COLORREF ParseColorName(char *name); +void ParseAttribs(COLORREF *color, int *effects, char* argValue); +VOID CreateFontInMF(MyFont *mf); +VOID ChangedConsoleFont(); +VOID ParseFontName(char *name, MyFontParams *mfp); +void InitComboStrings(HANDLE hwndCombo, char **cd); +BOOLEAN MyLoadSound(MySound *ms); +BOOLEAN MyPlaySound(MySound *ms); +VOID ExitArgError(char *msg, char *badArg); + +/* Constants */ +#define CLOCK_FONT 0 +#define MESSAGE_FONT 1 +#define COORD_FONT 2 +#define CONSOLE_FONT 3 +#define COMMENT_FONT 4 +#define EDITTAGS_FONT 5 +#define NUM_FONTS 6 + +/* Positions of some menu items. Origin is zero and separator lines count. */ +/* It's gross that these are needed. */ +#define ACTION_POS 2 /* Posn of "Action" on menu bar */ +#define OPTIONS_POS 4 /* Posn of "Options" on menu bar */ +#define ICS_POS 4 /* Posn of "ICS " on Options menu */ +#define SOUNDS_POS 6 /* Posn of "Sounds" on Options menu */ +/* end grossness */ + +extern MyFont *font[NUM_SIZES][NUM_FONTS]; + +#define WM_USER_Input (WM_USER + 4242) +#define WM_USER_Mouseleave (WM_USER + 4243) +#define WM_USER_GetConsoleBackground (WM_USER + 4244) + +#define CLOCK_TIMER_ID 51 +#define LOAD_GAME_TIMER_ID 52 +#define ANALYSIS_TIMER_ID 53 +#define MOUSE_TIMER_ID 54 +#define DELAYED_TIMER_ID 55 + +#define SOLID_PIECE 0 +#define OUTLINE_PIECE 1 +#define WHITE_PIECE 2 + +#define COPY_TMP "wbcopy.tmp" +#define PASTE_TMP "wbpaste.tmp" + diff --git a/winboard-dm-beta4/winboard.hpj b/winboard-dm-beta4/winboard.hpj new file mode 100755 index 00000000..48e48ff2 --- /dev/null +++ b/winboard-dm-beta4/winboard.hpj @@ -0,0 +1,19 @@ +; This file is maintained by HCW. Do not modify this file directly. + +; This help project requires hc 3.1 +[OPTIONS] +ERRORLOG=winboard.err +LCID=0x409 0x0 0x0 ; English (United States) +REPORT=Yes +TITLE=WinBoard Help +BMROOT=bitmaps +HLP=.\winboard.hlp + +[FILES] +winboard.rtf + +[WINDOWS] +main="WinBoard Help",,60676,,(r12632256),f2 + +[CONFIG] +BrowseButtons() diff --git a/winboard-dm-beta4/winboard.rc b/winboard-dm-beta4/winboard.rc new file mode 100755 index 00000000..0e9dd4b9 --- /dev/null +++ b/winboard-dm-beta4/winboard.rc @@ -0,0 +1,1526 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#define APSTUDIO_HIDDEN_SYMBOLS +#include "windows.h" +#undef APSTUDIO_HIDDEN_SYMBOLS +#include "dlgs.h" + + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// Englisch (USA) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +ABOUTBOX DIALOG DISCARDABLE 22, 17, 228, 73 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "About WinBoard" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,185,52,32,14,WS_GROUP + ICON "icon_white",-1,3,6,21,20 + LTEXT "Chessboard for Windows",400,25,15,121,8 + LTEXT "Copyright 1991-2002 Digital Equipment Corporation",201, + 6,34,149,8 + LTEXT "Enhancements Copyright 1992-2002 Free Software Foundation", + OPT_TCtext1,6,44,121,17 + CONTROL "",OPT_TCTime,"Static",SS_BLACKRECT,4,28,219,1 + LTEXT "WinBoard 0.0.0",ABOUTBOX_Version,25,4,142,8 +END + +DLG_TimeControl DIALOG DISCARDABLE 6, 18, 147, 113 +STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +CAPTION "Time Control" +FONT 8, "MS Sans Serif" +BEGIN + CONTROL "Conventional chess clock",OPT_TCUseMoves,"Button", + BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP,6,6,113,10 + CONTROL "Incremental clock",OPT_TCUseInc,"Button", + BS_AUTORADIOBUTTON | WS_TABSTOP,6,42,107,10 + EDITTEXT OPT_TCMoves,14,20,22,12,ES_AUTOHSCROLL | WS_GROUP + LTEXT "moves in",OPT_TCtext1,40,22,30,8,NOT WS_GROUP + EDITTEXT OPT_TCTime,74,20,32,12,ES_AUTOHSCROLL + LTEXT "minutes",OPT_TCtext2,111,22,26,8,NOT WS_GROUP + EDITTEXT OPT_TCTime2,14,56,32,12,ES_AUTOHSCROLL | WS_GROUP + LTEXT "minutes initially,",405,51,57,73,8,NOT WS_GROUP + LTEXT "plus",406,19,74,15,8,NOT WS_GROUP + EDITTEXT OPT_TCInc,37,72,32,12,ES_AUTOHSCROLL + LTEXT "seconds per move",408,74,74,67,8,NOT WS_GROUP + PUSHBUTTON "OK",IDOK,32,95,40,14,WS_GROUP + PUSHBUTTON "Cancel",IDCANCEL,88,95,40,14 +END + +DLG_LoadOptions DIALOG DISCARDABLE 10, 18, 144, 55 +STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +CAPTION "Load Game Options" +FONT 8, "MS Sans Serif" +BEGIN + CONTROL "Load games with automatic stepping",OPT_Autostep,"Button", + BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP,4,4,136,10 + EDITTEXT OPT_ASTimeDelay,23,18,28,12,ES_AUTOHSCROLL + LTEXT "seconds per move",OPT_AStext1,57,20,60,8,NOT WS_GROUP + PUSHBUTTON "OK",IDOK,24,37,40,14,WS_GROUP + PUSHBUTTON "Cancel",IDCANCEL,80,37,40,14 +END + +DLG_SaveOptions DIALOG DISCARDABLE 6, 17, 133, 119 +STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +CAPTION "Save Game Options" +FONT 8, "MS Sans Serif" +BEGIN + CONTROL "Save games automatically",OPT_Autosave,"Button", + BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP,4,4,97,10 + CONTROL "Prompt for filename",OPT_AVPrompt,"Button", + BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP,18,18,75,10 + CONTROL "To file:",OPT_AVToFile,"Button",BS_AUTORADIOBUTTON,18, + 31,36,10 + EDITTEXT OPT_AVFilename,18,44,97,12,ES_AUTOHSCROLL + GROUPBOX "Save Style",801,4,63,125,28,WS_GROUP + CONTROL "PGN",OPT_PGN,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP, + 18,75,39,10 + CONTROL "Old",OPT_Old,"Button",BS_AUTORADIOBUTTON,73,75,39,10 + PUSHBUTTON "OK",IDOK,18,98,40,14,WS_GROUP + PUSHBUTTON "Cancel",IDCANCEL,74,98,40,14 + PUSHBUTTON "Browse...",OPT_AVBrowse,76,31,39,14 +END + +1536 DIALOG DISCARDABLE 36, 24, 264, 134 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Open" +FONT 8, "Helv" +BEGIN + LTEXT "File &Name:",1090,6,6,76,9 + EDITTEXT 1152,6,16,90,12,ES_AUTOHSCROLL | ES_OEMCONVERT + LISTBOX 1120,6,32,90,68,LBS_SORT | LBS_OWNERDRAWFIXED | + LBS_HASSTRINGS | LBS_DISABLENOSCROLL | WS_VSCROLL | + WS_TABSTOP + LTEXT "&Directories:",-1,110,6,92,9 + LTEXT "",1088,110,18,92,9,SS_NOPREFIX | NOT WS_GROUP + LISTBOX 1121,110,32,92,68,LBS_SORT | LBS_OWNERDRAWFIXED | + LBS_HASSTRINGS | LBS_DISABLENOSCROLL | WS_VSCROLL | + WS_TABSTOP + LTEXT "List Files of &Type:",1089,6,104,90,9 + COMBOBOX 1136,6,114,90,36,CBS_DROPDOWNLIST | CBS_AUTOHSCROLL | + WS_BORDER | WS_VSCROLL | WS_TABSTOP + LTEXT "Dri&ves:",1091,110,104,92,9 + COMBOBOX 1137,110,114,92,68,CBS_DROPDOWNLIST | CBS_OWNERDRAWFIXED | + CBS_AUTOHSCROLL | CBS_SORT | CBS_HASSTRINGS | WS_BORDER | + WS_VSCROLL | WS_TABSTOP + DEFPUSHBUTTON "OK",IDOK,208,6,50,14,WS_GROUP + PUSHBUTTON "Cancel",IDCANCEL,208,24,50,14,WS_GROUP + PUSHBUTTON "&Help",1038,208,46,50,14,NOT WS_VISIBLE | WS_GROUP + LTEXT "&Index number:",-1,208,74,48,8 + EDITTEXT OPT_IndexNumberOld,208,84,50,12,ES_AUTOHSCROLL + PUSHBUTTON "Net&work...",1037,208,113,50,14,WS_GROUP +END + +DLG_CommPort DIALOG DISCARDABLE 25, 30, 159, 98 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Communication Port Settings" +FONT 8, "Helv" +BEGIN + RTEXT "&Port:",-1,4,6,40,10 + COMBOBOX OPT_Port,49,4,55,60,CBS_DROPDOWN | WS_VSCROLL | + WS_TABSTOP + RTEXT "Data &Rate:",-1,4,21,40,10,NOT WS_GROUP + COMBOBOX OPT_DataRate,49,19,55,100,CBS_DROPDOWN | WS_VSCROLL | + WS_TABSTOP + RTEXT "Data &Bits:",-1,4,36,40,10,NOT WS_GROUP + COMBOBOX OPT_Bits,49,34,55,60,CBS_DROPDOWNLIST | CBS_HASSTRINGS | + WS_VSCROLL | WS_TABSTOP + RTEXT "P&arity:",-1,4,51,40,10,NOT WS_GROUP + COMBOBOX OPT_Parity,49,49,55,60,CBS_DROPDOWNLIST | CBS_HASSTRINGS | + WS_VSCROLL | WS_TABSTOP + RTEXT "&Stop Bits:",-1,4,66,40,10,NOT WS_GROUP + COMBOBOX OPT_StopBits,49,64,55,60,CBS_DROPDOWNLIST | + CBS_HASSTRINGS | WS_VSCROLL | WS_TABSTOP + RTEXT "F&low:",-1,4,81,40,10,NOT WS_GROUP + DEFPUSHBUTTON "OK",IDOK,115,4,40,14 + PUSHBUTTON "Cancel",IDCANCEL,115,24,40,14 + COMBOBOX OPT_Flow,49,79,55,60,CBS_DROPDOWNLIST | CBS_HASSTRINGS | + WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "&Help",OPT_SerialHelp,115,80,40,14,NOT WS_VISIBLE +END + +DLG_EditComment DIALOG DISCARDABLE 6, 18, 306, 104 +STYLE WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME +CAPTION "Edit Comment" +FONT 8, "MS Sans Serif" +BEGIN + PUSHBUTTON "OK",IDOK,61,86,40,14 + PUSHBUTTON "Cancel",OPT_CancelComment,109,86,40,14 + PUSHBUTTON "&Clear",OPT_ClearComment,157,86,40,14 + PUSHBUTTON "&Edit",OPT_EditComment,205,86,40,14 + CONTROL "",OPT_CommentText,"RICHEDIT",ES_MULTILINE | + ES_AUTOHSCROLL | ES_WANTRETURN | WS_BORDER | WS_VSCROLL | + WS_HSCROLL | WS_TABSTOP,4,4,298,78 +END + +DLG_PromotionKing DIALOG DISCARDABLE 98, 90, 183, 41 +STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +CAPTION "Promotion" +FONT 8, "MS Sans Serif" +BEGIN + PUSHBUTTON "&Queen",PB_Queen,4,23,40,14,WS_GROUP + PUSHBUTTON "&Rook",PB_Rook,49,23,40,14,NOT WS_TABSTOP + PUSHBUTTON "&Bishop",PB_Bishop,94,23,40,14,NOT WS_TABSTOP + PUSHBUTTON "K&night",PB_Knight,139,23,40,14,NOT WS_TABSTOP + PUSHBUTTON "&King",PB_King,94,4,40,14,NOT WS_TABSTOP + PUSHBUTTON "&Cancel",IDCANCEL,139,4,40,14,WS_GROUP + LTEXT "Promote pawn to:",501,6,8,58,8 +END + +ABOUTBOX2 DIALOG DISCARDABLE 22, 17, 281, 198 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "About WinBoard" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,244,180,32,14,WS_GROUP + RTEXT "Chessboard for Windows",DLG_TimeControl,196,154,80,8 + LTEXT "Copyright 1991 Digital Equipment Corporation",201,4,167, + 151,8 + LTEXT "Enhancements Copyright 1992-2002 Free Software Foundation", + OPT_TCtext1,4,177,126,17 + CONTROL "",OPT_TCTime,"Static",SS_BLACKRECT,4,164,272,1 + LTEXT "WinBoard 0.0.0",ABOUTBOX_Version,4,154,64,8 + CONTROL "galactic",IDC_STATIC,"Static",SS_BITMAP,4,4,15,13 +END + +DLG_GameList DIALOG DISCARDABLE 6, 18, 307, 159 +STYLE WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME +CAPTION "Game List" +FONT 8, "MS Sans Serif" +BEGIN + LISTBOX OPT_GameListText,4,4,299,130,LBS_NOINTEGRALHEIGHT | + WS_VSCROLL | WS_HSCROLL | WS_TABSTOP + PUSHBUTTON "&Load",OPT_GameListLoad,61,138,40,15 + PUSHBUTTON "&Prev",OPT_GameListPrev,109,138,40,15 + PUSHBUTTON "&Next",OPT_GameListNext,157,138,40,15 + PUSHBUTTON "&Close",OPT_GameListClose,205,138,40,15 +END + +DLG_EditTags DIALOG DISCARDABLE 6, 18, 160, 141 +STYLE WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME +CAPTION "Edit Tags" +FONT 8, "MS Sans Serif" +BEGIN + PUSHBUTTON "OK",IDOK,12,123,40,14 + PUSHBUTTON "Cancel",OPT_TagsCancel,60,123,40,14 + PUSHBUTTON "&Edit",OPT_EditTags,108,123,40,14 + CONTROL "",OPT_TagsText,"RICHEDIT",ES_MULTILINE | ES_AUTOVSCROLL | + ES_AUTOHSCROLL | ES_WANTRETURN | WS_BORDER | WS_VSCROLL | + WS_HSCROLL | WS_TABSTOP,4,4,152,115 +END + +WBCONSOLE DIALOG DISCARDABLE 0, 0, 335, 133 +STYLE WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_CAPTION | WS_SYSMENU | + WS_THICKFRAME +CAPTION "ICS Interaction" +CLASS "WBConsole" +FONT 8, "Courier New" +BEGIN + CONTROL "",OPT_ConsoleText,"RICHEDIT",ES_MULTILINE | + ES_AUTOVSCROLL | ES_NOHIDESEL | ES_READONLY | ES_NUMBER | + WS_BORDER | WS_VSCROLL | WS_TABSTOP,0,0,335,119 + CONTROL "",OPT_ConsoleInput,"RICHEDIT",ES_MULTILINE | + ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_NOHIDESEL | + ES_NUMBER | WS_BORDER | WS_TABSTOP,0,120,335,13, + WS_EX_TRANSPARENT +END + +DLG_Analysis DIALOGEX 330, 148, 338, 111 +STYLE DS_3DLOOK | DS_CENTERMOUSE | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | + WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME +FONT 8, "Arial", 0, 0, 0x1 +BEGIN + EDITTEXT OPT_engineDepth,55,32,44,12,ES_CENTER | ES_READONLY | + NOT WS_BORDER,WS_EX_DLGMODALFRAME + EDITTEXT OPT_engineScore,11,32,37,12,ES_CENTER | ES_READONLY | + NOT WS_BORDER,WS_EX_DLGMODALFRAME + EDITTEXT OPT_engineNPS,105,32,43,12,ES_CENTER | ES_READONLY | NOT + WS_BORDER,WS_EX_DLGMODALFRAME + EDITTEXT OPT_engineNodes,155,32,82,12,ES_CENTER | ES_READONLY | + NOT WS_BORDER,WS_EX_DLGMODALFRAME + GROUPBOX "Engine Information",IDC_STATIC,0,4,338,49,BS_LEFT + CONTROL "",OPT_engineName,"RICHEDIT",ES_CENTER | ES_MULTILINE | + ES_READONLY,10,15,104,12,WS_EX_DLGMODALFRAME + EDITTEXT OPT_engineMoveNr,121,15,50,12,ES_CENTER | ES_READONLY | + NOT WS_BORDER,WS_EX_DLGMODALFRAME + EDITTEXT OPT_engineTime,178,15,42,12,ES_CENTER | ES_READONLY | + NOT WS_BORDER,WS_EX_DLGMODALFRAME + DEFPUSHBUTTON "",OPT_engineStart,283,15,46,12,0,WS_EX_STATICEDGE + DEFPUSHBUTTON "",OPT_engineMove,289,32,35,12,NOT WS_TABSTOP, + WS_EX_STATICEDGE + CONTROL "Disable send statistic question",OPT_engineStatLine, + "Button",BS_AUTOCHECKBOX | BS_LEFT | BS_VCENTER | + BS_FLAT,0,55,118,8 + CONTROL "Enable Tourney Mode",OPT_engineTourneyMode,"Button", + BS_AUTOCHECKBOX | BS_LEFT | BS_VCENTER | BS_FLAT,242,55, + 84,8 + EDITTEXT OPT_engineHash,227,15,49,12,ES_CENTER | ES_READONLY | + NOT WS_BORDER,WS_EX_DLGMODALFRAME + EDITTEXT OPT_egtb,244,32,39,12,ES_CENTER | ES_READONLY | NOT + WS_BORDER,WS_EX_DLGMODALFRAME + CONTROL "Send engine output to ICS",OPT_SendToICS,"Button", + BS_AUTOCHECKBOX | BS_LEFT | BS_VCENTER | BS_FLAT,125,55, + 102,8 + LISTBOX OPT_AnalysisText,0,66,337,44,LBS_MULTIPLESEL | + LBS_USETABSTOPS | LBS_NOINTEGRALHEIGHT | + LBS_DISABLENOSCROLL | WS_VSCROLL | WS_HSCROLL | + WS_TABSTOP,WS_EX_TRANSPARENT +END + +DLG_Error DIALOG DISCARDABLE 0, 0, 183, 33 +STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION +CAPTION "Error" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,163,9,16,14 + ICON 32515,IDC_STATIC,4,6,20,20 + LTEXT "Sorry Charlie",OPT_ErrorText,27,4,130,25 +END + +DLG_Colorize DIALOGEX 0, 0, 183, 52 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "ICS Interaction Colors" +FONT 8, "MS Sans Serif", 0, 0, 0x1 +BEGIN + PUSHBUTTON "&Choose Color...",OPT_ChooseColor,15,29,51,14,WS_GROUP + CONTROL "&Bold",OPT_Bold,"Button",BS_AUTOCHECKBOX | WS_GROUP | + WS_TABSTOP,93,4,30,10 + CONTROL "&Italic",OPT_Italic,"Button",BS_AUTOCHECKBOX,93,14,30, + 10 + CONTROL "&Underline",OPT_Underline,"Button",BS_AUTOCHECKBOX,93, + 24,45,10 + CONTROL "&Strikeout",OPT_Strikeout,"Button",BS_AUTOCHECKBOX,93, + 34,42,10 + DEFPUSHBUTTON "OK",IDOK,145,7,31,14,WS_GROUP + PUSHBUTTON "Cancel",IDCANCEL,145,24,31,14 + CONTROL "",OPT_Sample,"RICHEDIT",ES_CENTER | ES_MULTILINE | + ES_READONLY | WS_GROUP,4,9,75,15,WS_EX_CLIENTEDGE +END + +DLG_Question DIALOG DISCARDABLE 0, 0, 187, 60 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Question" +FONT 8, "MS Sans Serif" +BEGIN + EDITTEXT OPT_QuestionInput,4,44,179,12,ES_AUTOHSCROLL + DEFPUSHBUTTON "Enter",IDOK,133,4,50,14,WS_GROUP + PUSHBUTTON "Cancel",IDCANCEL,133,24,50,14 + LTEXT "Enter a chess engine command or just type something stupid that will completely screw things up.", + OPT_QuestionText,27,4,101,33 + ICON 32514,IDC_STATIC,4,13,20,20 +END + +DLG_Startup DIALOG DISCARDABLE 0, 0, 276, 127 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "WinBoard Startup" +FONT 8, "MS Sans Serif" +BEGIN + CONTROL "Play against a chess engine or match two engines", + OPT_ChessEngine,"Button",BS_AUTORADIOBUTTON | WS_GROUP | + WS_TABSTOP,8,17,193,10 + COMBOBOX OPT_ChessEngineName,15,29,194,129,CBS_DROPDOWN | + CBS_AUTOHSCROLL | WS_VSCROLL | WS_TABSTOP + COMBOBOX OPT_SecondChessEngineName,15,45,194,129,CBS_DROPDOWN | + CBS_AUTOHSCROLL | WS_VSCROLL | WS_TABSTOP + CONTROL "Use an Internet Chess Server",OPT_ChessServer,"Button", + BS_AUTORADIOBUTTON | WS_TABSTOP,8,62,195,10 + COMBOBOX OPT_ChessServerName,16,73,194,129,CBS_DROPDOWN | + CBS_AUTOHSCROLL | WS_VSCROLL | WS_TABSTOP + CONTROL "Just view or edit game files",OPT_View,"Button", + BS_AUTORADIOBUTTON | WS_TABSTOP,8,91,193,10 + CONTROL "Additional options",OPT_AnyAdditional,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,8,111,71,10 + EDITTEXT OPT_AdditionalOptions,85,110,187,13,ES_AUTOHSCROLL + DEFPUSHBUTTON "OK",IDOK,222,4,50,14 + PUSHBUTTON "Cancel",IDCANCEL,222,21,50,14 + PUSHBUTTON "Help",IDM_HELPCONTENTS,222,38,50,14 + GROUPBOX "What would you like to do?",IDC_STATIC,4,4,211,101 +END + +DLG_IndexNumber DIALOG DISCARDABLE 0, 0, 236, 18 +STYLE DS_3DLOOK | DS_CONTROL | WS_CHILD | WS_CLIPSIBLINGS +FONT 8, "MS Sans Serif" +BEGIN + LTEXT "Inde&x number:",IDC_STATIC,5,2,46,8 + EDITTEXT OPT_IndexNumber,54,0,155,13,ES_AUTOHSCROLL +END + +DLG_TypeInMove DIALOG DISCARDABLE 0, 0, 186, 46 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Type in a move" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,129,7,50,14 + PUSHBUTTON "Cancel",IDCANCEL,129,24,50,14 + EDITTEXT OPT_Move,7,16,109,13,ES_AUTOHSCROLL +END + +DLG_Sound DIALOG DISCARDABLE 0, 0, 257, 95 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Sounds" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,199,6,47,14 + PUSHBUTTON "Cancel",IDCANCEL,199,23,47,14 + PUSHBUTTON "Defaults",OPT_DefaultSounds,199,40,47,14 + COMBOBOX CBO_Sounds,52,6,128,110,CBS_DROPDOWNLIST | WS_VSCROLL | + WS_TABSTOP + CONTROL "No sound",OPT_NoSound,"Button",BS_AUTORADIOBUTTON | + WS_GROUP | WS_TABSTOP,11,25,47,10 + CONTROL "Default beep",OPT_DefaultBeep,"Button", + BS_AUTORADIOBUTTON | WS_TABSTOP,11,42,57,10 + CONTROL "Built-in sound:",OPT_BuiltInSound,"Button", + BS_AUTORADIOBUTTON | WS_TABSTOP,11,59,60,10 + COMBOBOX OPT_BuiltInSoundName,78,58,103,109,CBS_DROPDOWNLIST | + CBS_SORT | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Play",OPT_PlaySound,200,57,47,14 + CONTROL "WAV file:",OPT_WavFile,"Button",BS_AUTORADIOBUTTON | + WS_TABSTOP,11,76,45,10 + EDITTEXT OPT_WavFileName,78,75,103,12,ES_AUTOHSCROLL + PUSHBUTTON "Browse...",OPT_BrowseSound,200,74,47,14 + LTEXT "Event:",IDC_STATIC,19,9,26,9 +END + +DLG_GeneralOptions DIALOG DISCARDABLE 0, 0, 271, 154 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "General Options" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,207,7,50,14 + PUSHBUTTON "Cancel",IDCANCEL,208,25,50,14 + CONTROL "Always on &Top",OPT_AlwaysOnTop,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,16,6,79,10 + CONTROL "Always &Queen",OPT_AlwaysQueen,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,16,20,79,10 + CONTROL "Animate &Dragging",OPT_AnimateDragging,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,16,34,79,10 + CONTROL "&Animate Moving",OPT_AnimateMoving,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,16,48,79,10 + CONTROL "Auto &Flag",OPT_AutoFlag,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,16,62,79,10 + CONTROL "Auto Flip &View",OPT_AutoFlipView,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,16,76,79,10 + CONTROL "Auto &Raise Board",OPT_AutoRaiseBoard,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,16,90,71,10 + CONTROL "&Blindfold",OPT_Blindfold,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,16,104,79,10 + CONTROL "&Highlight Dragging",OPT_HighlightDragging,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,16,118,79,10 + CONTROL "Highlight Last &Move",OPT_HighlightLastMove,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,109,6,79,10 + CONTROL "Periodic &Updates",OPT_PeriodicUpdates,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,109,20,79,10 + CONTROL "Ponder &Next Move",OPT_PonderNextMove,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,109,34,79,10 + CONTROL "&Popup Exit Message",OPT_PopupExitMessage,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,109,48,79,10 + CONTROL "Popup Move &Errors",OPT_PopupMoveErrors,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,109,62,79,10 + CONTROL "Show Butt&on Bar",OPT_ShowButtonBar,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,109,76,79,10 + CONTROL "Show &Coordinates",OPT_ShowCoordinates,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,109,90,79,10 + CONTROL "&Show Thinking",OPT_ShowThinking,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,109,104,79,10 + CONTROL "Test &Legality",OPT_TestLegality,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,109,118,79,10 + CONTROL "Winboard Engine Room",OPT_AnalysisWindow,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,16,132,91,10 +END + +DLG_IcsOptions DIALOGEX 0, 0, 310, 338 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "ICS Options" +FONT 8, "MS Sans Serif", 0, 0, 0x1 +BEGIN + DEFPUSHBUTTON "OK",IDOK,101,316,48,15 + PUSHBUTTON "Cancel",IDCANCEL,165,316,48,15 + CONTROL "&Auto Comment",OPT_AutoComment,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,18,12,62,12 + CONTROL "Auto &Observe",OPT_AutoObserve,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,18,27,62,12 + CONTROL "&Get Move List",OPT_GetMoveList,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,18,42,62,12 + CONTROL "&Local Line Editing",OPT_LocalLineEditing,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,18,57,72,8 + CONTROL "&Quiet Play",OPT_QuietPlay,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,18,72,62,8 + CONTROL "&Premove",OPT_Premove,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,121,12,44,12 + CONTROL "&White first move",OPT_PremoveWhite,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,121,27,67,12 + EDITTEXT OPT_PremoveWhiteText,196,24,25,12,ES_AUTOHSCROLL + CONTROL "&Black first move",OPT_PremoveBlack,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,121,42,66,12 + EDITTEXT OPT_PremoveBlackText,196,40,25,12,ES_AUTOHSCROLL + CONTROL "&Sound alarm at",OPT_IcsAlarm,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,121,71,63,10 + EDITTEXT OPT_IcsAlarmTime,196,68,17,13 + LTEXT "seconds",IDC_STATIC,219,71,37,8 + PUSHBUTTON "Choose...",OPT_ChooseShoutColor,104,173,40,15 + PUSHBUTTON "Choose...",OPT_ChooseSShoutColor,104,195,40,15 + PUSHBUTTON "Choose...",OPT_ChooseChannel1Color,104,213,40,15 + PUSHBUTTON "Choose...",OPT_ChooseChannelColor,104,235,40,15 + PUSHBUTTON "Choose...",OPT_ChooseKibitzColor,104,253,40,15 + PUSHBUTTON "Choose...",OPT_ChooseTellColor,251,173,40,15 + PUSHBUTTON "Choose...",OPT_ChooseChallengeColor,251,195,40,15 + PUSHBUTTON "Choose...",OPT_ChooseRequestColor,251,213,40,15 + PUSHBUTTON "Choose...",OPT_ChooseSeekColor,251,235,40,15 + PUSHBUTTON "Choose...",OPT_ChooseNormalColor,251,253,40,15 + PUSHBUTTON "&Choose Background Color...",OPT_ChooseBackgroundColor, + 18,276,131,16 + PUSHBUTTON "&Default ICS Colors",OPT_DefaultColors,165,276,131,16 + CONTROL "Do ¬ colorize messages",OPT_DontColorize,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,110,299,97,10 + CONTROL "",OPT_SampleShout,"RICHEDIT",ES_CENTER | ES_MULTILINE | + ES_READONLY | WS_DISABLED | WS_GROUP,18,173,75,15, + WS_EX_CLIENTEDGE + CONTROL "",OPT_SampleSShout,"RICHEDIT",ES_CENTER | ES_MULTILINE | + ES_READONLY | WS_DISABLED | WS_GROUP,18,195,75,15, + WS_EX_CLIENTEDGE + CONTROL "",OPT_SampleChannel1,"RICHEDIT",ES_CENTER | + ES_MULTILINE | ES_READONLY | WS_DISABLED | WS_GROUP,18, + 213,75,15,WS_EX_CLIENTEDGE + CONTROL "",OPT_SampleChannel,"RICHEDIT",ES_CENTER | ES_MULTILINE | + ES_READONLY | WS_DISABLED | WS_GROUP,18,235,75,15, + WS_EX_CLIENTEDGE + CONTROL "",OPT_SampleKibitz,"RICHEDIT",ES_CENTER | ES_MULTILINE | + ES_READONLY | WS_GROUP,18,253,75,15,WS_EX_CLIENTEDGE + CONTROL "",OPT_SampleTell,"RICHEDIT",ES_CENTER | ES_MULTILINE | + ES_READONLY | WS_DISABLED | WS_GROUP,165,173,75,15, + WS_EX_CLIENTEDGE + CONTROL "",OPT_SampleChallenge,"RICHEDIT",ES_CENTER | + ES_MULTILINE | ES_READONLY | WS_DISABLED | WS_GROUP,165, + 195,75,15,WS_EX_CLIENTEDGE + CONTROL "",OPT_SampleRequest,"RICHEDIT",ES_CENTER | ES_MULTILINE | + ES_READONLY | WS_DISABLED | WS_GROUP,165,213,75,15, + WS_EX_CLIENTEDGE + CONTROL "",OPT_SampleSeek,"RICHEDIT",ES_CENTER | ES_MULTILINE | + ES_READONLY | WS_DISABLED | WS_GROUP,165,235,75,15, + WS_EX_CLIENTEDGE + CONTROL "",OPT_SampleNormal,"RICHEDIT",ES_CENTER | ES_MULTILINE | + ES_READONLY | WS_DISABLED | WS_GROUP,165,253,75,15, + WS_EX_CLIENTEDGE + GROUPBOX "Interaction Colors",IDC_STATIC,7,163,296,150 + GROUPBOX "Premove",IDC_STATIC,112,3,191,58 + GROUPBOX "Server",IDC_STATIC,7,3,101,83 + GROUPBOX "Alarm",IDC_STATIC,112,62,191,24 + GROUPBOX "Engine Analyse",IDC_STATIC,7,88,101,69 + CONTROL "Enable Engine",OPT_icsAnalyze,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,18,99,62,10 + CONTROL "Enable Window",OPT_icsAnalyzeWindow,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,18,117,89,10 + CONTROL "kill PV <",OPT_icsKillPV,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,196,140,40,10 + EDITTEXT OPT_icsKillPVs,238,139,13,12 + CONTROL "Whisper",OPT_icsWhisper,"Button",BS_AUTORADIOBUTTON | + WS_GROUP | WS_TABSTOP,121,97,42,10 + CONTROL "Kibitz",OPT_icsKibitz,"Button",BS_AUTORADIOBUTTON,121, + 113,33,10 + CONTROL "Tell",OPT_icsTell,"Button",BS_AUTORADIOBUTTON,121,129, + 27,10 + CONTROL "None",OPT_icsNone,"Button",BS_AUTORADIOBUTTON,121,145, + 33,10 + EDITTEXT OPT_icsTells,151,128,34,13,ES_AUTOHSCROLL + LTEXT "less then",IDC_STATIC,255,141,29,10 + CONTROL "Enable Smart Queue",OPT_smartQueue,"Button", + BS_AUTOCHECKBOX,196,100,81,10 + CONTROL "Skip fail low/high moves",OPT_dropMoves,"Button", + BS_AUTOCHECKBOX | BS_LEFT | BS_VCENTER,196,120,98,10 + GROUPBOX "Engine Analyse Broadcasting",IDC_STATIC,112,88,191,69 + PUSHBUTTON "Advanced / UCI...",OPT_ADV,18,136,70,15 +END + +DLG_BoardOptions DIALOG DISCARDABLE 0, 0, 262, 250 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Board Options" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,205,10,50,14 + PUSHBUTTON "Cancel",IDCANCEL,205,35,50,14 + CONTROL "&Tiny",OPT_SizeTiny,"Button",BS_AUTORADIOBUTTON | + WS_GROUP | WS_TABSTOP,15,15,50,10 + CONTROL "T&eeny",OPT_SizeTeeny,"Button",BS_AUTORADIOBUTTON,15,25, + 50,10 + CONTROL "&Dinky",OPT_SizeDinky,"Button",BS_AUTORADIOBUTTON,15,35, + 50,10 + CONTROL "&Petite",OPT_SizePetite,"Button",BS_AUTORADIOBUTTON,15, + 45,50,10 + CONTROL "Sl&im",OPT_SizeSlim,"Button",BS_AUTORADIOBUTTON,15,55, + 50,10 + CONTROL "&Small",OPT_SizeSmall,"Button",BS_AUTORADIOBUTTON,15,65, + 50,10 + CONTROL "Medi&ocre",OPT_SizeMediocre,"Button",BS_AUTORADIOBUTTON, + 76,15,50,10 + CONTROL "&Middling",OPT_SizeMiddling,"Button",BS_AUTORADIOBUTTON, + 76,25,50,10 + CONTROL "&Average",OPT_SizeAverage,"Button",BS_AUTORADIOBUTTON, + 76,35,50,10 + CONTROL "Mode&rate",OPT_SizeModerate,"Button",BS_AUTORADIOBUTTON, + 76,45,50,10 + CONTROL "Medi&um",OPT_SizeMedium,"Button",BS_AUTORADIOBUTTON,76, + 55,50,10 + CONTROL "Bul&ky",OPT_SizeBulky,"Button",BS_AUTORADIOBUTTON,76,65, + 50,10 + CONTROL "&Large",OPT_SizeLarge,"Button",BS_AUTORADIOBUTTON,140, + 15,50,10 + CONTROL "&Big",OPT_SizeBig,"Button",BS_AUTORADIOBUTTON,140,25,50, + 10 + CONTROL "&Huge",OPT_SizeHuge,"Button",BS_AUTORADIOBUTTON,140,35, + 50,10 + CONTROL "&Giant",OPT_SizeGiant,"Button",BS_AUTORADIOBUTTON,140, + 45,50,10 + CONTROL "&Colossal",OPT_SizeColossal,"Button",BS_AUTORADIOBUTTON, + 140,55,50,10 + CONTROL "Tita&nic",OPT_SizeTitanic,"Button",BS_AUTORADIOBUTTON, + 140,65,50,10 + PUSHBUTTON "Choose...",OPT_ChooseLightSquareColor,144,100,40,15 + PUSHBUTTON "Choose...",OPT_ChooseDarkSquareColor,144,120,40,15 + PUSHBUTTON "Choose...",OPT_ChooseWhitePieceColor,144,140,40,15 + PUSHBUTTON "Choose...",OPT_ChooseBlackPieceColor,144,160,40,15 + PUSHBUTTON "Choose...",OPT_ChooseHighlightSquareColor,144,180,40,15 + PUSHBUTTON "Choose...",OPT_ChoosePremoveHighlightColor,144,200,40, + 15 + PUSHBUTTON "Defaults",OPT_DefaultBoardColors,118,225,65,15 + EDITTEXT OPT_DarkSquareColor,104,120,25,15,ES_READONLY | + WS_DISABLED | NOT WS_BORDER | NOT WS_TABSTOP + EDITTEXT OPT_LightSquareColor,104,100,25,15,ES_READONLY | + WS_DISABLED | NOT WS_BORDER | NOT WS_TABSTOP + EDITTEXT OPT_WhitePieceColor,104,140,25,15,ES_READONLY | + WS_DISABLED | NOT WS_BORDER | NOT WS_TABSTOP + EDITTEXT OPT_BlackPieceColor,104,160,25,15,ES_READONLY | + WS_DISABLED | NOT WS_BORDER | NOT WS_TABSTOP + EDITTEXT OPT_HighlightSquareColor,104,180,25,15,ES_READONLY | + WS_DISABLED | NOT WS_BORDER | NOT WS_TABSTOP + GROUPBOX "Colors",IDC_STATIC,10,90,185,155 + EDITTEXT OPT_PremoveHighlightColor,104,200,25,15,ES_READONLY | + WS_DISABLED | NOT WS_BORDER | NOT WS_TABSTOP + LTEXT "Light Squares",IDC_STATIC,25,105,60,10 + LTEXT "Dark Squares",IDC_STATIC,25,124,60,10 + LTEXT "White Pieces",IDC_STATIC,25,145,60,10 + LTEXT "Black Pieces",IDC_STATIC,25,165,60,10 + LTEXT "Square Highlights",IDC_STATIC,25,185,60,10 + LTEXT "Premove Highlights",IDC_STATIC,25,205,70,10 + GROUPBOX "Size",IDC_STATIC,10,5,185,75 + CONTROL "Monochrome",OPT_Monochrome,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,25,225,75,10 + EDITTEXT OPT_SampleLightSquare,205,110,39,36,ES_READONLY | + WS_DISABLED | NOT WS_BORDER | NOT WS_TABSTOP + EDITTEXT OPT_SampleDarkSquare,205,165,39,36,ES_READONLY | + WS_DISABLED | NOT WS_BORDER | NOT WS_TABSTOP +END + +DLG_Fonts DIALOG DISCARDABLE 0, 0, 280, 231 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Fonts" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,155,210,50,14 + PUSHBUTTON "Cancel",IDCANCEL,215,210,50,14 + PUSHBUTTON "Choose...",OPT_ChooseClockFont,221,17,45,15 + PUSHBUTTON "Choose...",OPT_ChooseMessageFont,221,47,45,15 + PUSHBUTTON "Choose...",OPT_ChooseCoordFont,221,77,45,15 + PUSHBUTTON "Choose...",OPT_ChooseTagFont,221,120,45,15 + PUSHBUTTON "Choose...",OPT_ChooseCommentsFont,221,150,45,15 + PUSHBUTTON "Choose...",OPT_ChooseConsoleFont,221,180,45,15 + PUSHBUTTON "&Revert to Defaults",OPT_DefaultFonts,15,210,80,15 + CONTROL "",OPT_SampleCoordFont,"RICHEDIT",ES_READONLY | + WS_DISABLED | WS_BORDER,70,72,140,20 + CONTROL "",OPT_SampleTagFont,"RICHEDIT",ES_READONLY | + WS_DISABLED | WS_BORDER,70,115,140,20 + CONTROL "",OPT_SampleCommentsFont,"RICHEDIT",ES_READONLY | + WS_DISABLED | WS_BORDER,70,145,140,20 + CONTROL "",OPT_SampleConsoleFont,"RICHEDIT",ES_READONLY | + WS_DISABLED | WS_BORDER,70,175,140,20 + LTEXT "Clocks",OPT_ClockFont,16,17,45,10,NOT WS_GROUP + LTEXT "Messages",OPT_MessageFont,16,47,45,10,NOT WS_GROUP + LTEXT "Coordinates",OPT_CoordFont,16,77,45,10,NOT WS_GROUP + LTEXT "Tags",OPT_EditTagsFont,16,120,45,10,NOT WS_GROUP + LTEXT "Comments",OPT_CommentsFont,16,150,45,10,NOT WS_GROUP + LTEXT "ICS Interaction",OPT_MessageFont5,16,180,50,10,NOT + WS_GROUP + CONTROL "",OPT_SampleClockFont,"RICHEDIT",ES_READONLY | + WS_DISABLED | WS_BORDER,70,12,140,20 + CONTROL "",OPT_SampleMessageFont,"RICHEDIT",ES_READONLY | + WS_DISABLED | WS_BORDER,70,42,140,20 + GROUPBOX "Current Board Size",IDC_STATIC,5,2,270,100 + GROUPBOX "All Board Sizes",IDC_STATIC,5,105,270,100 +END + +DLG_icsAnalyze DIALOG DISCARDABLE 0, 0, 233, 117 +STYLE DS_MODALFRAME | DS_NOIDLEMSG | DS_3DLOOK | DS_NOFAILCREATE | WS_POPUP | + WS_CAPTION +CAPTION "ICS Engine Analysis Options" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,75,99,35,14 + PUSHBUTTON "Cancel",IDCANCEL,115,99,35,14 + GROUPBOX "Options",IDC_STATIC,7,50,103,44 + GROUPBOX "UCI Settings",IDC_STATIC,115,50,111,44 + CONTROL "normal commands",OPT_icsWBprotoNorm,"Button", + BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP,13,16,86,10 + CONTROL "agressive commands",OPT_icsWBprotoAgr,"Button", + BS_AUTORADIOBUTTON | WS_TABSTOP,13,32,86,10 + CONTROL "Write Analysis Logfile",OPT_icsWriteLog,"Button", + BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,13,79,86,10 + CONTROL "Show Book",OPT_icsShowBook,"Button",BS_AUTOCHECKBOX | + WS_DISABLED | WS_TABSTOP,13,62,86,10 + GROUPBOX "Engine Handling",IDC_STATIC,7,3,103,44 + GROUPBOX "Smart Queue",IDC_STATIC,115,3,111,44 + CONTROL "Tuning for Blitz games",OPT_icsSmartQueueBlitz,"Button", + BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP,121,16,99,10 + CONTROL "Tuning for Standard games",OPT_icsSmartQueueStd,"Button", + BS_AUTORADIOBUTTON,121,32,98,10 +END + +DLG_ZippyDraw DIALOG DISCARDABLE 0, 0, 219, 209 +STYLE DS_MODALFRAME | WS_CHILD | WS_CAPTION | WS_SYSMENU +CAPTION "ICS Zippy Draw" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,107,187,48,15 + CONTROL "&Enable Zippy Draw",OPT_EnableZippyDraw,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,15,26,75,12 + LTEXT "(Only avaible if engine don't support WB2 draw feature)", + IDC_STATIC,15,15,175,10 + GROUPBOX "General Options",IDC_STATIC,10,4,202,38 + PUSHBUTTON "Cancel",IDCANCEL,53,187,48,15 + CONTROL "&Offer Draw",OPT_OfferDraw,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,15,58,50,10 + CONTROL "&Accept Draw",OPT_AcceptDraw,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,68,57,57,10 + CONTROL "&Draw Factor add",OPT_DrawFactor,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,20,111,68,12 + CONTROL "Title players bonus",OPT_TitlePlayers,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,20,82,75,12 + GROUPBOX "Settings",IDC_STATIC,10,47,202,136 + GROUPBOX "Refer with",IDC_STATIC,16,71,190,107 + CONTROL "Opponent rating diff less then",OPT_DrawFactor2,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,20,96,109,12 + EDITTEXT OPT_RatingPoints,131,94,25,12,ES_AUTOHSCROLL + EDITTEXT OPT_RatingPoints2,39,124,21,12,ES_AUTOHSCROLL + LTEXT "points to score (1 pawn=100)",IDC_STATIC,65,128,92,8 + LTEXT "ELO",IDC_STATIC,161,98,19,8 + CONTROL "&Dynamic Draw: Take score as draw from ",OPT_smartQueue, + "Button",BS_AUTOCHECKBOX,41,142,143,10 + EDITTEXT OPT_RatingPoints3,53,153,21,12,ES_AUTOHSCROLL + LTEXT "points to",IDC_STATIC,79,156,28,8 + EDITTEXT OPT_RatingPoints4,110,154,21,12,ES_AUTOHSCROLL + LTEXT "points (1 Pawn=100)",IDC_STATIC,136,156,65,8 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO DISCARDABLE +BEGIN + DLG_GeneralOptions, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 264 + TOPMARGIN, 7 + BOTTOMMARGIN, 147 + END + + DLG_IcsOptions, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 303 + TOPMARGIN, 3 + BOTTOMMARGIN, 335 + END + + DLG_BoardOptions, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 255 + TOPMARGIN, 7 + BOTTOMMARGIN, 243 + END + + DLG_Fonts, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 273 + TOPMARGIN, 7 + BOTTOMMARGIN, 224 + END + + DLG_icsAnalyze, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 226 + TOPMARGIN, 3 + BOTTOMMARGIN, 113 + END + + DLG_ZippyDraw, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 212 + TOPMARGIN, 7 + BOTTOMMARGIN, 202 + END +END +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +ICON_BLACK ICON DISCARDABLE "bitmaps\\icon_ob.ico" +ICON_BOARD ICON DISCARDABLE "bitmaps\\board.ico" +ICON_WHITE ICON DISCARDABLE "bitmaps\\icon_whi.ico" + +///////////////////////////////////////////////////////////////////////////// +// +// Menu +// + +WINBOARD MENU DISCARDABLE +BEGIN + POPUP "&File" + BEGIN + MENUITEM "Reset &Game", IDM_NewGame + MENUITEM SEPARATOR + MENUITEM "&Load Game...", IDM_LoadGame + MENUITEM "Load &Next Game\tAlt+PgDn", IDM_LoadNextGame + MENUITEM "Load &Previous Game\tAlt+PgUp", IDM_LoadPrevGame + MENUITEM "&Reload Same Game", IDM_ReloadGame + MENUITEM "&Save Game...", IDM_SaveGame + MENUITEM SEPARATOR + MENUITEM "&Copy Game To Clipboard\tAlt+C", IDM_CopyGame + MENUITEM "Paste Game &From Clipboard\tAlt+V", IDM_PasteGame + MENUITEM SEPARATOR + MENUITEM "L&oad Position...", IDM_LoadPosition + MENUITEM "Load N&ext Position\tAlt+Shift+PgDn", IDM_LoadNextPosition + MENUITEM "Load Pre&vious Position\tAlt+Shift+PgUp", + IDM_LoadPrevPosition + MENUITEM "Reload Sa&me Position", IDM_ReloadPosition + MENUITEM "S&ave Position...", IDM_SavePosition + MENUITEM SEPARATOR + MENUITEM "Cop&y Position To Clipboard\tAlt+Shift+C", + IDM_CopyPosition + MENUITEM "Pas&te Position From Clipboard\tAlt+Shift+V", + IDM_PastePosition + MENUITEM SEPARATOR + MENUITEM "E&xit", IDM_Exit + END + POPUP "&Mode" + BEGIN + MENUITEM "Machine &White", IDM_MachineWhite + MENUITEM "Machine &Black", IDM_MachineBlack + MENUITEM "Two &Machines", IDM_TwoMachines + MENUITEM "&Analysis Mode", IDM_AnalysisMode + MENUITEM "Analyze &File", IDM_AnalyzeFile + MENUITEM "&ICS Client", IDM_IcsClient + MENUITEM "Edit &Game", IDM_EditGame + MENUITEM "&Edit Position", IDM_EditPosition + MENUITEM "Trai&ning", IDM_Training, GRAYED + MENUITEM SEPARATOR + MENUITEM "Show Game &List...", IDM_ShowGameList + MENUITEM "Edit &Tags...", IDM_EditTags + MENUITEM "Edit &Comment...", IDM_EditComment + MENUITEM "&Pause\tPause", IDM_Pause + END + POPUP "&Action" + BEGIN + MENUITEM "&Accept\tF3", IDM_Accept + MENUITEM "D&ecline\tF4", IDM_Decline + MENUITEM "Re&match\tF12", IDM_Rematch + MENUITEM SEPARATOR + MENUITEM "Call &Flag\tF5", IDM_CallFlag + MENUITEM "&Draw\tF6", IDM_Draw + MENUITEM "Ad&journ\tF7", IDM_Adjourn + MENUITEM "A&bort\tF8", IDM_Abort + MENUITEM "&Resign\tF9", IDM_Resign + MENUITEM SEPARATOR + MENUITEM "Stop &Observing\tF10", IDM_StopObserving + MENUITEM "Stop E&xamining\tF11", IDM_StopExamining + END + POPUP "&Step" + BEGIN + MENUITEM "T&ype In Move...", IDM_TypeInMove + MENUITEM SEPARATOR + MENUITEM "&Backward\tAlt+Left", IDM_Backward + MENUITEM "&Forward\tAlt+Right", IDM_Forward + MENUITEM "Back to &Start\tAlt+Up", IDM_ToStart + MENUITEM "Forward to &End\tAlt+Down", IDM_ToEnd + MENUITEM "Re&vert\tAlt+Home", IDM_Revert + MENUITEM "&Truncate Game\tAlt+End", IDM_TruncateGame + MENUITEM SEPARATOR + MENUITEM "&Move Now\tAlt+Ins", IDM_MoveNow + MENUITEM "&Retract Move\tAlt+Del", IDM_RetractMove + END + POPUP "&Options" + BEGIN + MENUITEM "Flip &View\tF2", IDM_FlipView + MENUITEM SEPARATOR + MENUITEM "&General...", IDM_GeneralOptions + MENUITEM "&Board...", IDM_BoardOptions + POPUP "&ICS...", GRAYED + BEGIN + MENUITEM "ICS Options Gerneral", IDM_IcsOptions + MENUITEM "ICS Zippy Draw", IDM_ZippyDraw, GRAYED + END + MENUITEM "&Fonts...", IDM_Fonts + MENUITEM "Soun&ds...", IDM_Sounds + MENUITEM SEPARATOR + MENUITEM "Comm&unications...", IDM_CommPort + MENUITEM "&Load Game...", IDM_LoadOptions + MENUITEM "&Save Game...", IDM_SaveOptions + MENUITEM "&Time Control...", IDM_TimeControl + MENUITEM SEPARATOR + MENUITEM "Save Settings &Now", IDM_SaveSettings + MENUITEM "Save Settings on E&xit", IDM_SaveSettingsOnExit + END + POPUP "&Help" + BEGIN + MENUITEM "Help &Contents\tF1", IDM_HELPCONTENTS + MENUITEM "Help &Index", IDM_HELPSEARCH + MENUITEM "How to &Use Help", IDM_HELPHELP + MENUITEM SEPARATOR + MENUITEM "&Hint...", IDM_Hint + MENUITEM "&Book...", IDM_Book + MENUITEM SEPARATOR + MENUITEM "&About WinBoard", IDM_ABOUT + END +END + +PIECEMENU MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "White", EP_White + MENUITEM SEPARATOR + MENUITEM "Pawn", EP_WhitePawn + MENUITEM "Knight", EP_WhiteKnight + MENUITEM "Bishop", EP_WhiteBishop + MENUITEM "Rook", EP_WhiteRook + MENUITEM "Queen", EP_WhiteQueen + MENUITEM "King", EP_WhiteKing + MENUITEM SEPARATOR + MENUITEM "Empty Square", EP_EmptySquare + MENUITEM "Black", EP_Black, MENUBARBREAK + MENUITEM SEPARATOR + MENUITEM "Pawn", EP_BlackPawn + MENUITEM "Knight", EP_BlackKnight + MENUITEM "Bishop", EP_BlackBishop + MENUITEM "Rook", EP_BlackRook + MENUITEM "Queen", EP_BlackQueen + MENUITEM "King", EP_BlackKing + MENUITEM SEPARATOR + MENUITEM "Clear Board ", EP_ClearBoard + END +END + +WHITEPIECEMENU MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "White", EP_White + MENUITEM SEPARATOR + MENUITEM "Pawn", EP_WhitePawn + MENUITEM "Knight", EP_WhiteKnight + MENUITEM "Bishop", EP_WhiteBishop + MENUITEM "Rook", EP_WhiteRook + MENUITEM "Queen", EP_WhiteQueen + MENUITEM "King", EP_WhiteKing + MENUITEM SEPARATOR + MENUITEM "Empty Square", EP_EmptySquare + MENUITEM "Clear Board", EP_ClearBoard + END +END + +BLACKPIECEMENU MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "Black", EP_Black + MENUITEM SEPARATOR + MENUITEM "Pawn", EP_BlackPawn + MENUITEM "Knight", EP_BlackKnight + MENUITEM "Bishop", EP_BlackBishop + MENUITEM "Rook", EP_BlackRook + MENUITEM "Queen", EP_BlackQueen + MENUITEM "King", EP_BlackKing + MENUITEM SEPARATOR + MENUITEM "Empty Square", EP_EmptySquare + MENUITEM "Clear Board", EP_ClearBoard + END +END + +DROPPIECEMENU MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "Drop", 0, INACTIVE + MENUITEM SEPARATOR + MENUITEM "Pawn", DP_Pawn + MENUITEM "Knight", DP_Knight + MENUITEM "Bishop", DP_Bishop + MENUITEM "Rook", DP_Rook + MENUITEM "Queen", DP_Queen + END +END + +TEXTMENU MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "Cop&y and Paste", IDM_QuickPaste + MENUITEM "&Copy", IDM_Copy + MENUITEM "&Paste", IDM_Paste + END +END + +INPUTMENU MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&Undo", IDM_Undo + MENUITEM SEPARATOR + MENUITEM "Cu&t", IDM_Cut + MENUITEM "&Copy", IDM_Copy + MENUITEM "&Paste", IDM_Paste + MENUITEM SEPARATOR + MENUITEM "Select &All", IDM_SelectAll + END +END + +ENGINEROOM MENU DISCARDABLE +BEGIN + POPUP "Engine Room" + BEGIN + MENUITEM "Select all and ©", IDM_SelPaste + MENUITEM "Select &all", IDM_SelectAll + MENUITEM "&Copy", IDM_Copy + MENUITEM SEPARATOR + MENUITEM "Move!", IDM_MoveNow + MENUITEM "Start/Stop Engine", IDM_EnginesButton + MENUITEM SEPARATOR + MENUITEM "Switch &Analysis Mode", IDM_AnalysisMode + MENUITEM "Switch &Machine White", IDM_MachineWhite + MENUITEM "Switch &Machine Black", IDM_MachineBlack + MENUITEM "Set/Change &Operator Time", IDM_OperatorTime + END +END + +ICSENGINEROOM MENU DISCARDABLE +BEGIN + POPUP "ICS Engine Room" + BEGIN + MENUITEM "Select all and ©", IDM_SelPaste + MENUITEM SEPARATOR + MENUITEM "Select &All", IDM_SelectAll + MENUITEM "&Copy", IDM_Copy + END +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Accelerator +// + +WINBOARD ACCELERATORS MOVEABLE PURE +BEGIN + "1", IDM_DirectCommand1, VIRTKEY, ALT, NOINVERT + "2", IDM_DirectCommand2, VIRTKEY, ALT, NOINVERT + "C", IDM_CopyGame, VIRTKEY, ALT, NOINVERT + "C", IDM_CopyPosition, VIRTKEY, SHIFT, ALT, NOINVERT + "E", IDM_focus_EngineRoom, VIRTKEY, ALT, NOINVERT + "R", IDM_focus_wb, VIRTKEY, ALT, NOINVERT + "V", IDM_PasteGame, VIRTKEY, ALT, NOINVERT + "V", IDM_PastePosition, VIRTKEY, SHIFT, ALT, NOINVERT + VK_DELETE, IDM_RetractMove, VIRTKEY, ALT, NOINVERT + VK_DOWN, IDM_ToEnd, VIRTKEY, ALT, NOINVERT + VK_END, IDM_TruncateGame, VIRTKEY, ALT, NOINVERT + VK_F1, IDM_HELPCONTENTS, VIRTKEY, NOINVERT + VK_F10, IDM_StopObserving, VIRTKEY, NOINVERT + VK_F11, IDM_StopExamining, VIRTKEY, NOINVERT + VK_F12, IDM_Rematch, VIRTKEY, NOINVERT + VK_F12, IDM_Debug, VIRTKEY, CONTROL, ALT, NOINVERT + VK_F2, IDM_FlipView, VIRTKEY, NOINVERT + VK_F3, IDM_Accept, VIRTKEY, NOINVERT + VK_F4, IDM_Decline, VIRTKEY, NOINVERT + VK_F4, IDM_Minimize, VIRTKEY, CONTROL, NOINVERT + VK_F5, IDM_CallFlag, VIRTKEY, NOINVERT + VK_F6, IDM_Draw, VIRTKEY, NOINVERT + VK_F7, IDM_Adjourn, VIRTKEY, NOINVERT + VK_F8, IDM_Abort, VIRTKEY, NOINVERT + VK_F9, IDM_Resign, VIRTKEY, NOINVERT + VK_HOME, IDM_Revert, VIRTKEY, ALT, NOINVERT + VK_INSERT, IDM_MoveNow, VIRTKEY, ALT, NOINVERT + VK_LBUTTON, IDM_focus_EngineRoom, VIRTKEY, CONTROL, NOINVERT + VK_LEFT, IDM_Backward, VIRTKEY, ALT, NOINVERT + VK_NEXT, IDM_LoadNextGame, VIRTKEY, ALT, NOINVERT + VK_NEXT, IDM_LoadNextPosition, VIRTKEY, SHIFT, ALT, NOINVERT + VK_PAUSE, IDM_Pause, VIRTKEY, NOINVERT + VK_PAUSE, IDM_Pause, VIRTKEY, ALT, NOINVERT + VK_PRIOR, IDM_LoadPrevGame, VIRTKEY, ALT, NOINVERT + VK_PRIOR, IDM_LoadPrevPosition, VIRTKEY, SHIFT, ALT, NOINVERT + VK_RIGHT, IDM_Forward, VIRTKEY, ALT, NOINVERT + VK_UP, IDM_ToStart, VIRTKEY, ALT, NOINVERT +END + +NO_ALT ACCELERATORS MOVEABLE PURE +BEGIN + VK_DELETE, IDM_RetractMove, VIRTKEY, NOINVERT + VK_DOWN, IDM_ToEnd, VIRTKEY, NOINVERT + VK_END, IDM_TruncateGame, VIRTKEY, NOINVERT + VK_HOME, IDM_Revert, VIRTKEY, NOINVERT + VK_INSERT, IDM_MoveNow, VIRTKEY, NOINVERT + VK_LEFT, IDM_Backward, VIRTKEY, NOINVERT + VK_NEXT, IDM_LoadNextGame, VIRTKEY, NOINVERT + VK_NEXT, IDM_LoadNextPosition, VIRTKEY, SHIFT, NOINVERT + VK_PRIOR, IDM_LoadPrevGame, VIRTKEY, NOINVERT + VK_PRIOR, IDM_LoadPrevPosition, VIRTKEY, SHIFT, NOINVERT + VK_RIGHT, IDM_Forward, VIRTKEY, NOINVERT + VK_UP, IDM_ToStart, VIRTKEY, NOINVERT +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Bitmap +// + +P21O BITMAP MOVEABLE PURE "bitmaps\\P21o.bmp" +N21O BITMAP MOVEABLE PURE "bitmaps\\N21o.bmp" +B21O BITMAP MOVEABLE PURE "bitmaps\\B21o.bmp" +R21O BITMAP MOVEABLE PURE "bitmaps\\R21o.bmp" +K21O BITMAP MOVEABLE PURE "bitmaps\\K21o.bmp" +Q21O BITMAP MOVEABLE PURE "bitmaps\\Q21o.bmp" +P21S BITMAP MOVEABLE PURE "bitmaps\\P21s.bmp" +N21S BITMAP MOVEABLE PURE "bitmaps\\N21s.bmp" +B21S BITMAP MOVEABLE PURE "bitmaps\\B21s.bmp" +R21S BITMAP MOVEABLE PURE "bitmaps\\R21s.bmp" +Q21S BITMAP MOVEABLE PURE "bitmaps\\Q21s.bmp" +K21S BITMAP MOVEABLE PURE "bitmaps\\K21s.bmp" +P21W BITMAP MOVEABLE PURE "bitmaps\\P21w.bmp" +N21W BITMAP MOVEABLE PURE "bitmaps\\N21w.bmp" +B21W BITMAP MOVEABLE PURE "bitmaps\\B21w.bmp" +R21W BITMAP MOVEABLE PURE "bitmaps\\R21w.bmp" +Q21W BITMAP MOVEABLE PURE "bitmaps\\Q21w.bmp" +K21W BITMAP MOVEABLE PURE "bitmaps\\K21w.bmp" +P25O BITMAP MOVEABLE PURE "bitmaps\\P25o.bmp" +N25O BITMAP MOVEABLE PURE "bitmaps\\N25o.bmp" +B25O BITMAP MOVEABLE PURE "bitmaps\\B25o.bmp" +R25O BITMAP MOVEABLE PURE "bitmaps\\R25o.bmp" +Q25O BITMAP MOVEABLE PURE "bitmaps\\Q25o.bmp" +K25O BITMAP MOVEABLE PURE "bitmaps\\K25o.bmp" +P25S BITMAP MOVEABLE PURE "bitmaps\\P25s.bmp" +N25S BITMAP MOVEABLE PURE "bitmaps\\N25s.bmp" +B25S BITMAP MOVEABLE PURE "bitmaps\\B25s.bmp" +R25S BITMAP MOVEABLE PURE "bitmaps\\R25s.bmp" +Q25S BITMAP MOVEABLE PURE "bitmaps\\Q25s.bmp" +K25S BITMAP MOVEABLE PURE "bitmaps\\K25s.bmp" +P25W BITMAP MOVEABLE PURE "bitmaps\\P25w.bmp" +N25W BITMAP MOVEABLE PURE "bitmaps\\N25w.bmp" +B25W BITMAP MOVEABLE PURE "bitmaps\\B25w.bmp" +R25W BITMAP MOVEABLE PURE "bitmaps\\R25w.bmp" +Q25W BITMAP MOVEABLE PURE "bitmaps\\Q25w.bmp" +K25W BITMAP MOVEABLE PURE "bitmaps\\K25w.bmp" +P29O BITMAP MOVEABLE PURE "bitmaps\\P29o.bmp" +N29O BITMAP MOVEABLE PURE "bitmaps\\N29o.bmp" +B29O BITMAP MOVEABLE PURE "bitmaps\\B29o.bmp" +R29O BITMAP MOVEABLE PURE "bitmaps\\R29o.bmp" +Q29O BITMAP MOVEABLE PURE "bitmaps\\Q29o.bmp" +K29O BITMAP MOVEABLE PURE "bitmaps\\K29o.bmp" +P29S BITMAP MOVEABLE PURE "bitmaps\\P29s.bmp" +N29S BITMAP MOVEABLE PURE "bitmaps\\N29s.bmp" +B29S BITMAP MOVEABLE PURE "bitmaps\\B29s.bmp" +R29S BITMAP MOVEABLE PURE "bitmaps\\R29s.bmp" +Q29S BITMAP MOVEABLE PURE "bitmaps\\Q29s.bmp" +K29S BITMAP MOVEABLE PURE "bitmaps\\K29s.bmp" +P29W BITMAP MOVEABLE PURE "bitmaps\\P29w.bmp" +N29W BITMAP MOVEABLE PURE "bitmaps\\N29w.bmp" +B29W BITMAP MOVEABLE PURE "bitmaps\\B29w.bmp" +R29W BITMAP MOVEABLE PURE "bitmaps\\R29w.bmp" +Q29W BITMAP MOVEABLE PURE "bitmaps\\Q29w.bmp" +K29W BITMAP MOVEABLE PURE "bitmaps\\K29w.bmp" +P33O BITMAP MOVEABLE PURE "bitmaps\\P33o.bmp" +N33O BITMAP MOVEABLE PURE "bitmaps\\N33o.bmp" +B33O BITMAP MOVEABLE PURE "bitmaps\\B33o.bmp" +R33O BITMAP MOVEABLE PURE "bitmaps\\R33o.bmp" +Q33O BITMAP MOVEABLE PURE "bitmaps\\Q33o.bmp" +K33O BITMAP MOVEABLE PURE "bitmaps\\K33o.bmp" +P33S BITMAP MOVEABLE PURE "bitmaps\\P33s.bmp" +N33S BITMAP MOVEABLE PURE "bitmaps\\N33s.bmp" +B33S BITMAP MOVEABLE PURE "bitmaps\\B33s.bmp" +R33S BITMAP MOVEABLE PURE "bitmaps\\R33s.bmp" +Q33S BITMAP MOVEABLE PURE "bitmaps\\Q33s.bmp" +K33S BITMAP MOVEABLE PURE "bitmaps\\K33s.bmp" +P33W BITMAP MOVEABLE PURE "bitmaps\\P33w.bmp" +N33W BITMAP MOVEABLE PURE "bitmaps\\N33w.bmp" +B33W BITMAP MOVEABLE PURE "bitmaps\\B33w.bmp" +R33W BITMAP MOVEABLE PURE "bitmaps\\R33w.bmp" +Q33W BITMAP MOVEABLE PURE "bitmaps\\Q33w.bmp" +K33W BITMAP MOVEABLE PURE "bitmaps\\K33w.bmp" +P37O BITMAP MOVEABLE PURE "bitmaps\\P37o.bmp" +N37O BITMAP MOVEABLE PURE "bitmaps\\N37o.bmp" +B37O BITMAP MOVEABLE PURE "bitmaps\\B37o.bmp" +R37O BITMAP MOVEABLE PURE "bitmaps\\R37o.bmp" +Q37O BITMAP MOVEABLE PURE "bitmaps\\Q37o.bmp" +K37O BITMAP MOVEABLE PURE "bitmaps\\K37o.bmp" +P37S BITMAP MOVEABLE PURE "bitmaps\\P37s.bmp" +N37S BITMAP MOVEABLE PURE "bitmaps\\N37s.bmp" +B37S BITMAP MOVEABLE PURE "bitmaps\\B37s.bmp" +R37S BITMAP MOVEABLE PURE "bitmaps\\R37s.bmp" +Q37S BITMAP MOVEABLE PURE "bitmaps\\Q37s.bmp" +K37S BITMAP MOVEABLE PURE "bitmaps\\K37s.bmp" +P37W BITMAP MOVEABLE PURE "bitmaps\\P37w.bmp" +N37W BITMAP MOVEABLE PURE "bitmaps\\N37w.bmp" +B37W BITMAP MOVEABLE PURE "bitmaps\\B37w.bmp" +R37W BITMAP MOVEABLE PURE "bitmaps\\R37w.bmp" +Q37W BITMAP MOVEABLE PURE "bitmaps\\Q37w.bmp" +K37W BITMAP MOVEABLE PURE "bitmaps\\K37w.bmp" +P40O BITMAP MOVEABLE PURE "bitmaps\\P40o.bmp" +N40O BITMAP MOVEABLE PURE "bitmaps\\N40o.bmp" +B40O BITMAP MOVEABLE PURE "bitmaps\\B40o.bmp" +R40O BITMAP MOVEABLE PURE "bitmaps\\R40o.bmp" +Q40O BITMAP MOVEABLE PURE "bitmaps\\Q40o.bmp" +K40O BITMAP MOVEABLE PURE "bitmaps\\K40o.bmp" +P40S BITMAP MOVEABLE PURE "bitmaps\\P40s.bmp" +N40S BITMAP MOVEABLE PURE "bitmaps\\N40s.bmp" +B40S BITMAP MOVEABLE PURE "bitmaps\\B40s.bmp" +R40S BITMAP MOVEABLE PURE "bitmaps\\R40s.bmp" +Q40S BITMAP MOVEABLE PURE "bitmaps\\Q40s.bmp" +K40S BITMAP MOVEABLE PURE "bitmaps\\K40s.bmp" +P40W BITMAP MOVEABLE PURE "bitmaps\\P40w.bmp" +N40W BITMAP MOVEABLE PURE "bitmaps\\N40w.bmp" +B40W BITMAP MOVEABLE PURE "bitmaps\\B40w.bmp" +R40W BITMAP MOVEABLE PURE "bitmaps\\R40w.bmp" +Q40W BITMAP MOVEABLE PURE "bitmaps\\Q40w.bmp" +K40W BITMAP MOVEABLE PURE "bitmaps\\K40w.bmp" +P45O BITMAP MOVEABLE PURE "bitmaps\\P45o.bmp" +N45O BITMAP MOVEABLE PURE "bitmaps\\N45o.bmp" +B45O BITMAP MOVEABLE PURE "bitmaps\\B45o.bmp" +R45O BITMAP MOVEABLE PURE "bitmaps\\R45o.bmp" +Q45O BITMAP MOVEABLE PURE "bitmaps\\Q45o.bmp" +K45O BITMAP MOVEABLE PURE "bitmaps\\K45o.bmp" +P45S BITMAP MOVEABLE PURE "bitmaps\\P45s.bmp" +N45S BITMAP MOVEABLE PURE "bitmaps\\N45s.bmp" +B45S BITMAP MOVEABLE PURE "bitmaps\\B45s.bmp" +R45S BITMAP MOVEABLE PURE "bitmaps\\R45s.bmp" +Q45S BITMAP MOVEABLE PURE "bitmaps\\Q45s.bmp" +K45S BITMAP MOVEABLE PURE "bitmaps\\K45s.bmp" +P45W BITMAP MOVEABLE PURE "bitmaps\\P45w.bmp" +N45W BITMAP MOVEABLE PURE "bitmaps\\N45w.bmp" +B45W BITMAP MOVEABLE PURE "bitmaps\\B45w.bmp" +R45W BITMAP MOVEABLE PURE "bitmaps\\R45w.bmp" +Q45W BITMAP MOVEABLE PURE "bitmaps\\Q45w.bmp" +K45W BITMAP MOVEABLE PURE "bitmaps\\K45w.bmp" +P49O BITMAP MOVEABLE PURE "bitmaps\\P49o.bmp" +N49O BITMAP MOVEABLE PURE "bitmaps\\N49o.bmp" +B49O BITMAP MOVEABLE PURE "bitmaps\\B49o.bmp" +R49O BITMAP MOVEABLE PURE "bitmaps\\R49o.bmp" +Q49O BITMAP MOVEABLE PURE "bitmaps\\Q49o.bmp" +K49O BITMAP MOVEABLE PURE "bitmaps\\K49o.bmp" +P49S BITMAP MOVEABLE PURE "bitmaps\\P49s.bmp" +N49S BITMAP MOVEABLE PURE "bitmaps\\N49s.bmp" +B49S BITMAP MOVEABLE PURE "bitmaps\\B49s.bmp" +R49S BITMAP MOVEABLE PURE "bitmaps\\R49s.bmp" +Q49S BITMAP MOVEABLE PURE "bitmaps\\Q49s.bmp" +K49S BITMAP MOVEABLE PURE "bitmaps\\K49s.bmp" +P49W BITMAP MOVEABLE PURE "bitmaps\\P49w.bmp" +N49W BITMAP MOVEABLE PURE "bitmaps\\N49w.bmp" +B49W BITMAP MOVEABLE PURE "bitmaps\\B49w.bmp" +R49W BITMAP MOVEABLE PURE "bitmaps\\R49w.bmp" +Q49W BITMAP MOVEABLE PURE "bitmaps\\Q49w.bmp" +K49W BITMAP MOVEABLE PURE "bitmaps\\K49w.bmp" +P54O BITMAP MOVEABLE PURE "bitmaps\\P54o.bmp" +N54O BITMAP MOVEABLE PURE "bitmaps\\N54o.bmp" +B54O BITMAP MOVEABLE PURE "bitmaps\\B54o.bmp" +R54O BITMAP MOVEABLE PURE "bitmaps\\R54o.bmp" +Q54O BITMAP MOVEABLE PURE "bitmaps\\Q54o.bmp" +K54O BITMAP MOVEABLE PURE "bitmaps\\K54o.bmp" +P54S BITMAP MOVEABLE PURE "bitmaps\\P54s.bmp" +N54S BITMAP MOVEABLE PURE "bitmaps\\N54s.bmp" +B54S BITMAP MOVEABLE PURE "bitmaps\\B54s.bmp" +R54S BITMAP MOVEABLE PURE "bitmaps\\R54s.bmp" +Q54S BITMAP MOVEABLE PURE "bitmaps\\Q54s.bmp" +K54S BITMAP MOVEABLE PURE "bitmaps\\K54s.bmp" +P54W BITMAP MOVEABLE PURE "bitmaps\\P54w.bmp" +N54W BITMAP MOVEABLE PURE "bitmaps\\N54w.bmp" +B54W BITMAP MOVEABLE PURE "bitmaps\\B54w.bmp" +R54W BITMAP MOVEABLE PURE "bitmaps\\R54w.bmp" +Q54W BITMAP MOVEABLE PURE "bitmaps\\Q54w.bmp" +K54W BITMAP MOVEABLE PURE "bitmaps\\K54w.bmp" +P58O BITMAP MOVEABLE PURE "bitmaps\\P58o.bmp" +N58O BITMAP MOVEABLE PURE "bitmaps\\N58o.bmp" +B58O BITMAP MOVEABLE PURE "bitmaps\\B58o.bmp" +R58O BITMAP MOVEABLE PURE "bitmaps\\R58o.bmp" +Q58O BITMAP MOVEABLE PURE "bitmaps\\Q58o.bmp" +K58O BITMAP MOVEABLE PURE "bitmaps\\K58o.bmp" +P58S BITMAP MOVEABLE PURE "bitmaps\\P58s.bmp" +N58S BITMAP MOVEABLE PURE "bitmaps\\N58s.bmp" +B58S BITMAP MOVEABLE PURE "bitmaps\\B58s.bmp" +R58S BITMAP MOVEABLE PURE "bitmaps\\R58s.bmp" +Q58S BITMAP MOVEABLE PURE "bitmaps\\Q58s.bmp" +K58S BITMAP MOVEABLE PURE "bitmaps\\K58s.bmp" +P58W BITMAP MOVEABLE PURE "bitmaps\\P58w.bmp" +N58W BITMAP MOVEABLE PURE "bitmaps\\N58w.bmp" +B58W BITMAP MOVEABLE PURE "bitmaps\\B58w.bmp" +R58W BITMAP MOVEABLE PURE "bitmaps\\R58w.bmp" +Q58W BITMAP MOVEABLE PURE "bitmaps\\Q58w.bmp" +K58W BITMAP MOVEABLE PURE "bitmaps\\K58w.bmp" +P64O BITMAP MOVEABLE PURE "bitmaps\\P64o.bmp" +N64O BITMAP MOVEABLE PURE "bitmaps\\N64o.bmp" +B64O BITMAP MOVEABLE PURE "bitmaps\\B64o.bmp" +R64O BITMAP MOVEABLE PURE "bitmaps\\R64o.bmp" +Q64O BITMAP MOVEABLE PURE "bitmaps\\Q64o.bmp" +K64O BITMAP MOVEABLE PURE "bitmaps\\K64o.bmp" +P64S BITMAP MOVEABLE PURE "bitmaps\\P64s.bmp" +N64S BITMAP MOVEABLE PURE "bitmaps\\N64s.bmp" +B64S BITMAP MOVEABLE PURE "bitmaps\\B64s.bmp" +R64S BITMAP MOVEABLE PURE "bitmaps\\R64s.bmp" +Q64S BITMAP MOVEABLE PURE "bitmaps\\Q64s.bmp" +K64S BITMAP MOVEABLE PURE "bitmaps\\K64s.bmp" +P64W BITMAP MOVEABLE PURE "bitmaps\\P64w.bmp" +N64W BITMAP MOVEABLE PURE "bitmaps\\N64w.bmp" +B64W BITMAP MOVEABLE PURE "bitmaps\\B64w.bmp" +R64W BITMAP MOVEABLE PURE "bitmaps\\R64w.bmp" +Q64W BITMAP MOVEABLE PURE "bitmaps\\Q64w.bmp" +K64W BITMAP MOVEABLE PURE "bitmaps\\K64w.bmp" +P72O BITMAP MOVEABLE PURE "bitmaps\\P72o.bmp" +N72O BITMAP MOVEABLE PURE "bitmaps\\N72o.bmp" +B72O BITMAP MOVEABLE PURE "bitmaps\\B72o.bmp" +R72O BITMAP MOVEABLE PURE "bitmaps\\R72o.bmp" +Q72O BITMAP MOVEABLE PURE "bitmaps\\Q72o.bmp" +K72O BITMAP MOVEABLE PURE "bitmaps\\K72o.bmp" +P72S BITMAP MOVEABLE PURE "bitmaps\\P72s.bmp" +N72S BITMAP MOVEABLE PURE "bitmaps\\N72s.bmp" +B72S BITMAP MOVEABLE PURE "bitmaps\\B72s.bmp" +R72S BITMAP MOVEABLE PURE "bitmaps\\R72s.bmp" +Q72S BITMAP MOVEABLE PURE "bitmaps\\Q72s.bmp" +K72S BITMAP MOVEABLE PURE "bitmaps\\K72s.bmp" +P72W BITMAP MOVEABLE PURE "bitmaps\\P72w.bmp" +N72W BITMAP MOVEABLE PURE "bitmaps\\N72w.bmp" +B72W BITMAP MOVEABLE PURE "bitmaps\\B72w.bmp" +R72W BITMAP MOVEABLE PURE "bitmaps\\R72w.bmp" +Q72W BITMAP MOVEABLE PURE "bitmaps\\Q72w.bmp" +K72W BITMAP MOVEABLE PURE "bitmaps\\K72w.bmp" +P80O BITMAP MOVEABLE PURE "bitmaps\\P80o.bmp" +N80O BITMAP MOVEABLE PURE "bitmaps\\N80o.bmp" +B80O BITMAP MOVEABLE PURE "bitmaps\\B80o.bmp" +R80O BITMAP MOVEABLE PURE "bitmaps\\R80o.bmp" +Q80O BITMAP MOVEABLE PURE "bitmaps\\Q80o.bmp" +K80O BITMAP MOVEABLE PURE "bitmaps\\K80o.bmp" +P80S BITMAP MOVEABLE PURE "bitmaps\\P80s.bmp" +N80S BITMAP MOVEABLE PURE "bitmaps\\N80s.bmp" +B80S BITMAP MOVEABLE PURE "bitmaps\\B80s.bmp" +R80S BITMAP MOVEABLE PURE "bitmaps\\R80s.bmp" +Q80S BITMAP MOVEABLE PURE "bitmaps\\Q80s.bmp" +K80S BITMAP MOVEABLE PURE "bitmaps\\K80s.bmp" +P80W BITMAP MOVEABLE PURE "bitmaps\\P80w.bmp" +N80W BITMAP MOVEABLE PURE "bitmaps\\N80w.bmp" +B80W BITMAP MOVEABLE PURE "bitmaps\\B80w.bmp" +R80W BITMAP MOVEABLE PURE "bitmaps\\R80w.bmp" +Q80W BITMAP MOVEABLE PURE "bitmaps\\Q80w.bmp" +K80W BITMAP MOVEABLE PURE "bitmaps\\K80w.bmp" +P87O BITMAP MOVEABLE PURE "bitmaps\\P87o.bmp" +N87O BITMAP MOVEABLE PURE "bitmaps\\N87o.bmp" +B87O BITMAP MOVEABLE PURE "bitmaps\\B87o.bmp" +R87O BITMAP MOVEABLE PURE "bitmaps\\R87o.bmp" +Q87O BITMAP MOVEABLE PURE "bitmaps\\Q87o.bmp" +K87O BITMAP MOVEABLE PURE "bitmaps\\K87o.bmp" +P87S BITMAP MOVEABLE PURE "bitmaps\\P87s.bmp" +N87S BITMAP MOVEABLE PURE "bitmaps\\N87s.bmp" +B87S BITMAP MOVEABLE PURE "bitmaps\\B87s.bmp" +R87S BITMAP MOVEABLE PURE "bitmaps\\R87s.bmp" +Q87S BITMAP MOVEABLE PURE "bitmaps\\Q87s.bmp" +K87S BITMAP MOVEABLE PURE "bitmaps\\K87s.bmp" +P87W BITMAP MOVEABLE PURE "bitmaps\\P87w.bmp" +N87W BITMAP MOVEABLE PURE "bitmaps\\N87w.bmp" +B87W BITMAP MOVEABLE PURE "bitmaps\\B87w.bmp" +R87W BITMAP MOVEABLE PURE "bitmaps\\R87w.bmp" +Q87W BITMAP MOVEABLE PURE "bitmaps\\Q87w.bmp" +K87W BITMAP MOVEABLE PURE "bitmaps\\K87w.bmp" +P95O BITMAP MOVEABLE PURE "bitmaps\\P95o.bmp" +N95O BITMAP MOVEABLE PURE "bitmaps\\N95o.bmp" +B95O BITMAP MOVEABLE PURE "bitmaps\\B95o.bmp" +R95O BITMAP MOVEABLE PURE "bitmaps\\R95o.bmp" +Q95O BITMAP MOVEABLE PURE "bitmaps\\Q95o.bmp" +K95O BITMAP MOVEABLE PURE "bitmaps\\K95o.bmp" +P95S BITMAP MOVEABLE PURE "bitmaps\\P95s.bmp" +N95S BITMAP MOVEABLE PURE "bitmaps\\N95s.bmp" +B95S BITMAP MOVEABLE PURE "bitmaps\\B95s.bmp" +R95S BITMAP MOVEABLE PURE "bitmaps\\R95s.bmp" +Q95S BITMAP MOVEABLE PURE "bitmaps\\Q95s.bmp" +K95S BITMAP MOVEABLE PURE "bitmaps\\K95s.bmp" +P95W BITMAP MOVEABLE PURE "bitmaps\\P95w.bmp" +N95W BITMAP MOVEABLE PURE "bitmaps\\N95w.bmp" +B95W BITMAP MOVEABLE PURE "bitmaps\\B95w.bmp" +R95W BITMAP MOVEABLE PURE "bitmaps\\R95w.bmp" +Q95W BITMAP MOVEABLE PURE "bitmaps\\Q95w.bmp" +K95W BITMAP MOVEABLE PURE "bitmaps\\K95w.bmp" +P108O BITMAP MOVEABLE PURE "bitmaps\\P108o.bmp" +N108O BITMAP MOVEABLE PURE "bitmaps\\N108o.bmp" +B108O BITMAP MOVEABLE PURE "bitmaps\\B108o.bmp" +R108O BITMAP MOVEABLE PURE "bitmaps\\R108o.bmp" +Q108O BITMAP MOVEABLE PURE "bitmaps\\Q108o.bmp" +K108O BITMAP MOVEABLE PURE "bitmaps\\K108o.bmp" +P108S BITMAP MOVEABLE PURE "bitmaps\\P108s.bmp" +N108S BITMAP MOVEABLE PURE "bitmaps\\N108s.bmp" +B108S BITMAP MOVEABLE PURE "bitmaps\\B108s.bmp" +R108S BITMAP MOVEABLE PURE "bitmaps\\R108s.bmp" +Q108S BITMAP MOVEABLE PURE "bitmaps\\Q108s.bmp" +K108S BITMAP MOVEABLE PURE "bitmaps\\K108s.bmp" +P108W BITMAP MOVEABLE PURE "bitmaps\\P108w.bmp" +N108W BITMAP MOVEABLE PURE "bitmaps\\N108w.bmp" +B108W BITMAP MOVEABLE PURE "bitmaps\\B108w.bmp" +R108W BITMAP MOVEABLE PURE "bitmaps\\R108w.bmp" +Q108W BITMAP MOVEABLE PURE "bitmaps\\Q108w.bmp" +K108W BITMAP MOVEABLE PURE "bitmaps\\K108w.bmp" +P116O BITMAP MOVEABLE PURE "bitmaps\\P116o.bmp" +N116O BITMAP MOVEABLE PURE "bitmaps\\N116o.bmp" +B116O BITMAP MOVEABLE PURE "bitmaps\\B116o.bmp" +R116O BITMAP MOVEABLE PURE "bitmaps\\R116o.bmp" +Q116O BITMAP MOVEABLE PURE "bitmaps\\Q116o.bmp" +K116O BITMAP MOVEABLE PURE "bitmaps\\K116o.bmp" +P116S BITMAP MOVEABLE PURE "bitmaps\\P116s.bmp" +N116S BITMAP MOVEABLE PURE "bitmaps\\N116s.bmp" +B116S BITMAP MOVEABLE PURE "bitmaps\\B116s.bmp" +R116S BITMAP MOVEABLE PURE "bitmaps\\R116s.bmp" +Q116S BITMAP MOVEABLE PURE "bitmaps\\Q116s.bmp" +K116S BITMAP MOVEABLE PURE "bitmaps\\K116s.bmp" +P116W BITMAP MOVEABLE PURE "bitmaps\\P116w.bmp" +N116W BITMAP MOVEABLE PURE "bitmaps\\N116w.bmp" +B116W BITMAP MOVEABLE PURE "bitmaps\\B116w.bmp" +R116W BITMAP MOVEABLE PURE "bitmaps\\R116w.bmp" +Q116W BITMAP MOVEABLE PURE "bitmaps\\Q116w.bmp" +K116W BITMAP MOVEABLE PURE "bitmaps\\K116w.bmp" +P129O BITMAP MOVEABLE PURE "bitmaps\\P129o.bmp" +N129O BITMAP MOVEABLE PURE "bitmaps\\N129o.bmp" +B129O BITMAP MOVEABLE PURE "bitmaps\\B129o.bmp" +R129O BITMAP MOVEABLE PURE "bitmaps\\R129o.bmp" +Q129O BITMAP MOVEABLE PURE "bitmaps\\Q129o.bmp" +K129O BITMAP MOVEABLE PURE "bitmaps\\K129o.bmp" +P129S BITMAP MOVEABLE PURE "bitmaps\\P129s.bmp" +N129S BITMAP MOVEABLE PURE "bitmaps\\N129s.bmp" +B129S BITMAP MOVEABLE PURE "bitmaps\\B129s.bmp" +R129S BITMAP MOVEABLE PURE "bitmaps\\R129s.bmp" +Q129S BITMAP MOVEABLE PURE "bitmaps\\Q129s.bmp" +K129S BITMAP MOVEABLE PURE "bitmaps\\K129s.bmp" +P129W BITMAP MOVEABLE PURE "bitmaps\\P129w.bmp" +N129W BITMAP MOVEABLE PURE "bitmaps\\N129w.bmp" +B129W BITMAP MOVEABLE PURE "bitmaps\\B129w.bmp" +R129W BITMAP MOVEABLE PURE "bitmaps\\R129w.bmp" +Q129W BITMAP MOVEABLE PURE "bitmaps\\Q129w.bmp" +K129W BITMAP MOVEABLE PURE "bitmaps\\K129w.bmp" +GALACTIC BITMAP MOVEABLE PURE "bitmaps\\galactic.bmp" +TIM BITMAP MOVEABLE PURE "bitmaps\\tim.bmp" + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "#define APSTUDIO_HIDDEN_SYMBOLS\r\n" + "#include ""windows.h""\r\n" + "#undef APSTUDIO_HIDDEN_SYMBOLS\r\n" + "#include ""dlgs.h""\r\n" + "\r\n" + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// WAVE +// + +DING WAVE DISCARDABLE "sounds\\ding1.wav" +CHING WAVE DISCARDABLE "sounds\\ching.wav" +CLICK WAVE DISCARDABLE "sounds\\click.wav" +CYMBAL WAVE DISCARDABLE "sounds\\cymbal.wav" +DRIP WAVE DISCARDABLE "sounds\\drip.wav" +GONG WAVE DISCARDABLE "sounds\\gong.wav" +BEEPBEEP WAVE DISCARDABLE "sounds\\honkhonk.wav" +LASER WAVE DISCARDABLE "sounds\\laser.wav" +PENALTY WAVE DISCARDABLE "sounds\\penalty.wav" +PHONE WAVE DISCARDABLE "sounds\\phone.wav" +POP WAVE DISCARDABLE "sounds\\pop.wav" +POP2 WAVE DISCARDABLE "sounds\\pop2.wav" +SLAP WAVE DISCARDABLE "sounds\\slap.wav" +SQUEAK WAVE DISCARDABLE "sounds\\squeak.wav" +SWISH WAVE DISCARDABLE "sounds\\swish.wav" +THUD WAVE DISCARDABLE "sounds\\thud.wav" +WHIPCRACK WAVE DISCARDABLE "sounds\\whipcrak.wav" +MOVE WAVE DISCARDABLE "sounds\\move.wav" +ALARM WAVE DISCARDABLE "sounds\\alarm.wav" +CHALLENGE WAVE DISCARDABLE "sounds\\challenge.wav" +CHANNEL WAVE DISCARDABLE "sounds\\channel.wav" +CHANNEL1 WAVE DISCARDABLE "sounds\\channel1.wav" +DRAW WAVE DISCARDABLE "sounds\\draw.wav" +KIBITZ WAVE DISCARDABLE "sounds\\kibitz.wav" +LOSE WAVE DISCARDABLE "sounds\\lose.wav" +REQUEST WAVE DISCARDABLE "sounds\\request.wav" +SEEK WAVE DISCARDABLE "sounds\\seek.wav" +SHOUT WAVE DISCARDABLE "sounds\\shout.wav" +SSHOUT WAVE DISCARDABLE "sounds\\sshout.wav" +TELL WAVE DISCARDABLE "sounds\\tell.wav" +UNFINISHED WAVE DISCARDABLE "sounds\\unfinished.wav" +WIN WAVE DISCARDABLE "sounds\\win.wav" +#endif // Englisch (USA) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/winboard-dm-beta4/winboard.rtf b/winboard-dm-beta4/winboard.rtf new file mode 100755 index 00000000..d584bbc8 --- /dev/null +++ b/winboard-dm-beta4/winboard.rtf @@ -0,0 +1,1880 @@ +{\rtf1\ansi\ansicpg1252\uc1 \deff5\deflang1033\deflangfe1033{\fonttbl{\f0\froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\f1\fswiss\fcharset0\fprq2{\*\panose 020b0604020202020204}Arial;} +{\f2\fmodern\fcharset0\fprq1{\*\panose 02070309020205020404}Courier New;}{\f3\froman\fcharset2\fprq2{\*\panose 05050102010706020507}Symbol;}{\f5\fswiss\fcharset0\fprq2{\*\panose 00000000000000000000}Helvetica{\*\falt Arial};} +{\f6\fmodern\fcharset0\fprq1{\*\panose 00000000000000000000}Courier;}{\f11\fswiss\fcharset0\fprq2{\*\panose 00000000000000000000}MS Sans Serif;}{\f27\fswiss\fcharset0\fprq2{\*\panose 020b0604030504040204}Tahoma;} +{\f226\fswiss\fcharset0\fprq0{\*\panose 00000000000000000000}Univers (WN);}{\f227\froman\fcharset0\fprq0{\*\panose 00000000000000000000}CG Times (WN);}{\f484\froman\fcharset238\fprq2 Times New Roman CE;} +{\f485\froman\fcharset204\fprq2 Times New Roman Cyr;}{\f487\froman\fcharset161\fprq2 Times New Roman Greek;}{\f488\froman\fcharset162\fprq2 Times New Roman Tur;}{\f489\froman\fcharset177\fprq2 Times New Roman (Hebrew);} +{\f490\froman\fcharset178\fprq2 Times New Roman (Arabic);}{\f491\froman\fcharset186\fprq2 Times New Roman Baltic;}{\f492\fswiss\fcharset238\fprq2 Arial CE;}{\f493\fswiss\fcharset204\fprq2 Arial Cyr;}{\f495\fswiss\fcharset161\fprq2 Arial Greek;} +{\f496\fswiss\fcharset162\fprq2 Arial Tur;}{\f497\fswiss\fcharset177\fprq2 Arial (Hebrew);}{\f498\fswiss\fcharset178\fprq2 Arial (Arabic);}{\f499\fswiss\fcharset186\fprq2 Arial Baltic;}{\f500\fmodern\fcharset238\fprq1 Courier New CE;} +{\f501\fmodern\fcharset204\fprq1 Courier New Cyr;}{\f503\fmodern\fcharset161\fprq1 Courier New Greek;}{\f504\fmodern\fcharset162\fprq1 Courier New Tur;}{\f505\fmodern\fcharset177\fprq1 Courier New (Hebrew);} +{\f506\fmodern\fcharset178\fprq1 Courier New (Arabic);}{\f507\fmodern\fcharset186\fprq1 Courier New Baltic;}{\f700\fswiss\fcharset238\fprq2 Tahoma CE;}{\f701\fswiss\fcharset204\fprq2 Tahoma Cyr;}{\f703\fswiss\fcharset161\fprq2 Tahoma Greek;} +{\f704\fswiss\fcharset162\fprq2 Tahoma Tur;}{\f705\fswiss\fcharset177\fprq2 Tahoma (Hebrew);}{\f706\fswiss\fcharset178\fprq2 Tahoma (Arabic);}{\f707\fswiss\fcharset186\fprq2 Tahoma Baltic;}}{\colortbl;\red0\green0\blue0;\red0\green0\blue255; +\red0\green255\blue255;\red0\green255\blue0;\red255\green0\blue255;\red255\green0\blue0;\red255\green255\blue0;\red255\green255\blue255;\red0\green0\blue128;\red0\green128\blue128;\red0\green128\blue0;\red128\green0\blue128;\red128\green0\blue0; +\red128\green128\blue0;\red128\green128\blue128;\red192\green192\blue192;}{\stylesheet{\ql \li120\ri0\sb80\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \snext0 Normal;}{ +\s1\ql \li120\ri0\sb280\sa120\sl-320\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \b\f5\fs24\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \sbasedon0 \snext26 heading 1;}{\s2\ql \li120\ri0\sb120\sa60\sl-240\slmult0 +\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \b\f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \sbasedon0 \snext0 heading 2;}{\s3\ql \li120\ri0\sb120\sa60\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 +\f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \sbasedon0 \snext0 heading 3;}{\s4\ql \fi-245\li360\ri0\sb120\sa60\sl-240\slmult0\nowidctlpar\faauto\outlinelevel1\adjustright\rin0\lin360\itap0 +\f11\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \sbasedon2 \snext4 heading 4;}{\s5\ql \li120\ri0\sb80\sl-240\slmult0\keepn\nowidctlpar\faauto\outlinelevel4\adjustright\rin0\lin120\itap0 +\f5\fs20\ul\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \sbasedon0 \snext0 heading 5;}{\*\cs10 \additive Default Paragraph Font;}{\*\cs15 \additive \f5\fs18\up6\lang1033\langfe0\langnp1033 \sbasedon10 footnote reference;}{ +\s16\ql \li120\ri0\sb80\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \sbasedon0 \snext0 footnote text;}{\s17\ql \li360\ri0\sb80\sl-240\slmult0 +\nowidctlpar\faauto\adjustright\rin0\lin360\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \sbasedon0 \snext0 Normal Indent;}{\s18\ql \fi-240\li600\ri0\sb60\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin600\itap0 +\f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \snext18 Jli;}{\s19\ql \li120\ri0\sb60\sl-240\slmult0\keep\nowidctlpar\tx520\tx920\tx1320\tx1720\tx2120\faauto\adjustright\rin0\lin120\itap0 +\f6\fs16\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \snext19 Ex;}{\s20\ql \li120\ri0\sb160\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \snext29 Sa1;}{ +\s21\ql \fi-240\li360\ri0\sl-240\slmult0\nowidctlpar\tx360\faauto\adjustright\rin0\lin360\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \snext22 Lb1;}{\s22\ql \fi-240\li360\ri0\sb60\sl-240\slmult0\nowidctlpar +\tx360\faauto\adjustright\rin0\lin360\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \snext22 Lb2;}{\s23\ql \li360\ri0\sb60\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin360\itap0 +\f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \snext22 Lp1;}{\s24\ql \fi-1800\li1920\ri0\sb120\sa40\sl-240\slmult0\nowidctlpar\brdrb\brdrs\brdrw15\brsp20 \brdrbtw\brdrs\brdrw15\brsp20 \tx1920\faauto\adjustright\rin0\lin1920\itap0 +\b\f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \snext25 Th;}{\s25\ql \fi-1800\li1920\ri0\sb60\sl-240\slmult0\nowidctlpar\tx1920\faauto\adjustright\rin0\lin1920\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \snext25 Tp;}{ +\s26\ql \li120\ri0\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \snext0 Normal 2;}{\s27\ql \li120\ri0\sb120\sa120\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 +\f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \snext0 bitmap;}{\s28\ql \li120\ri0\sb120\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \snext29 Sa2;}{ +\s29\ql \fi-240\li360\ri0\sb60\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin360\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \snext29 Jl;}{\s30\ql \li120\ri0\sa60\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 +\f226\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \snext30 *body;}{\s31\ql \li120\ri0\sa60\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \b\f226\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \snext31 *heading;}{ +\s32\ql \li120\ri0\sa60\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f226\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \sbasedon30 \snext32 para;}{ +\s33\ql \fi-280\li400\ri0\sa60\nowidctlpar\faauto\adjustright\rin0\lin400\itap0 \f226\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \sbasedon30 \snext33 jump;}{\s34\ql \fi-280\li400\ri0\sa60\nowidctlpar\tx400\faauto\adjustright\rin0\lin400\itap0 +\f226\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \sbasedon30 \snext34 list bullet;}{\s35\ql \fi-280\li600\ri0\sa60\nowidctlpar\faauto\adjustright\rin0\lin600\itap0 \f226\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 +\sbasedon30 \snext35 jump indent;}{\s36\ql \li120\ri0\sa60\sl-40\slmult0\nowidctlpar\brdrb\brdrs\brdrw15\brsp20 \brdrbtw\brdrs\brdrw15\brsp20 \faauto\adjustright\rin0\lin120\itap0 \f226\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 +\sbasedon30 \snext36 table rule;}{\s37\ql \fi-280\li400\ri0\sa60\nowidctlpar\tqr\tx280\tx400\faauto\adjustright\rin0\lin400\itap0 \f226\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \sbasedon30 \snext37 list number;}{ +\s38\ql \li120\ri0\sb100\sa60\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \b\f226\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \sbasedon31 \snext33 see also;}{\s39\ql \li400\ri0\sa60\nowidctlpar\faauto\adjustright\rin0\lin400\itap0 +\f226\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \sbasedon30 \snext39 para indent;}{\s40\ql \fi-1800\li1920\ri0\nowidctlpar\tx1920\faauto\adjustright\rin0\lin1920\itap0 \b\f226\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 +\sbasedon31 \snext36 table head;}{\s41\ql \fi-1800\li1920\ri0\sa60\nowidctlpar\tx1920\faauto\adjustright\rin0\lin1920\itap0 \f226\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \sbasedon30 \snext41 table text;}{ +\s42\ql \li120\ri0\sb120\sa60\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f226\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \sbasedon30 \snext35 see also 2;}{\s43\ql \li120\ri0\sa60\keep\nowidctlpar +\tx520\tx920\tx1320\tx1720\tx2120\faauto\adjustright\rin0\lin120\itap0 \f6\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \sbasedon30 \snext43 code;}{\s44\ql \li0\ri0\sl-120\slmult0\nowidctlpar\faauto\adjustright\rin0\lin0\itap0 +\f227\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \snext32 *spacing;}{\s45\ql \li0\ri0\sl-120\slmult0\nowidctlpar\faauto\adjustright\rin0\lin0\itap0 \f227\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \sbasedon44 \snext45 s6;}{ +\s46\qj \li360\ri0\nowidctlpar\faauto\adjustright\rin0\lin360\itap0 \f5\fs24\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \sbasedon0 \snext46 Help Text;}{\s47\ql \li115\ri0\sb120\sa40\sl-240\slmult0\nowidctlpar\brdrb\brdrs\brdrw15\brsp20 \brdrbtw +\brdrs\brdrw15\brsp20 \faauto\adjustright\rin0\lin115\itap0 \f11\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \sbasedon24 \snext25 Th2;}{\s48\ql \li115\ri0\sb120\sa40\sl-240\slmult0\nowidctlpar\brdrb\brdrs\brdrw15\brsp20 \brdrbtw +\brdrs\brdrw15\brsp20 \faauto\adjustright\rin0\lin115\itap0 \b\f11\fs16\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \sbasedon24 \snext25 Th3;}{\s49\ql \li115\ri0\sb200\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin115\itap0 +\f11\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \sbasedon0 \snext0 Normal 3;}{\s50\ql \fi-1800\li1915\ri0\sb120\sa40\sl-240\slmult0\nowidctlpar\brdrb\brdrs\brdrw15\brsp20 \brdrbtw\brdrs\brdrw15\brsp20 +\tx1915\faauto\adjustright\rin0\lin1915\itap0 \b\f11\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \sbasedon0 \snext51 Thh;}{\s51\ql \fi-1800\li1915\ri0\sb60\sl-240\slmult0\nowidctlpar\tx1915\faauto\adjustright\rin0\lin1915\itap0 +\f11\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \sbasedon0 \snext51 Tph;}{\s52\ql \li288\ri-432\sb80\sl-240\slmult0\nowidctlpar\tx288\tx864\tx1440\faauto\adjustright\rin-432\lin288\itap0 +\f5\fs24\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \sbasedon0 \snext52 unixman1;}{\s53\ql \li1440\ri-432\sb80\sa240\sl-240\slmult0\nowidctlpar\tx288\tx864\tx1440\faauto\adjustright\rin-432\lin1440\itap0 +\f5\fs24\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \sbasedon0 \snext53 unixman2;}{\s54\ql \li115\ri-432\sb80\sl-240\slmult0\nowidctlpar\tx288\tx864\tx1440\faauto\adjustright\rin-432\lin115\itap0 +\f5\fs24\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \sbasedon52 \snext54 unixman0;}{\s55\ql \li288\ri-432\sb80\sa240\sl-240\slmult0\nowidctlpar\tx288\tx864\tx1440\faauto\adjustright\rin-432\lin288\itap0 +\f5\fs24\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \sbasedon52 \snext55 unixman1a;}{\s56\ql \li115\ri0\sa60\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin115\itap0 \b\f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 +\sbasedon2 \snext56 heading 2a;}{\s57\ql \li120\ri0\sb80\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \sbasedon0 \snext57 endnote text;}{\*\cs58 \additive \super \sbasedon10 +endnote reference;}{\*\cs59 \additive \ul\cf2 \sbasedon10 Hyperlink;}{\*\cs60 \additive \ul\cf12 \sbasedon10 FollowedHyperlink;}{\s61\ql \li120\ri0\sb80\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \cbpat9 +\f27\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \sbasedon0 \snext61 Document Map;}{\s62\ql \li480\ri0\sb80\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin480\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 +\sbasedon0 \snext62 Body Text 2;}{\s63\ql \fi-720\li1440\ri0\sb80\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin1440\itap0 \f2\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \sbasedon0 \snext63 Body Text Indent 2;}{ +\s64\ql \li120\ri0\sb80\sl-240\slmult0\nowidctlpar\tqc\tx4320\tqr\tx8640\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \sbasedon0 \snext64 header;}{\s65\ql \li120\ri0\sb80\sl-240\slmult0\nowidctlpar +\tqc\tx4320\tqr\tx8640\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \sbasedon0 \snext65 footer;}}{\*\listtable{\list\listtemplateid67698703\listsimple{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0 +\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'02\'00.;}{\levelnumbers\'01;}\chbrdr\brdrnone\brdrcf1 \chshdng0\chcfpat1\chcbpat1 \fi-360\li360\jclisttab\tx360 }{\listname ;}\listid74976790}{\list\listtemplateid67698703\listsimple +{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'02\'00.;}{\levelnumbers\'01;}\chbrdr\brdrnone\brdrcf1 \chshdng0\chcfpat1\chcbpat1 \fi-360\li360\jclisttab\tx360 }{\listname +;}\listid349260549}{\list\listtemplateid67698689\listsimple{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\chbrdr\brdrnone\brdrcf1 +\chshdng0\chcfpat1\chcbpat1\fbias0 \fi-360\li360\jclisttab\tx360 }{\listname ;}\listid470094698}{\list\listtemplateid67698703\listsimple{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext +\'02\'00.;}{\levelnumbers\'01;}\chbrdr\brdrnone\brdrcf1 \chshdng0\chcfpat1\chcbpat1 \fi-360\li360\jclisttab\tx360 }{\listname ;}\listid640160996}{\list\listtemplateid67698689\listsimple{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0 +\levelstartat1\levelspace0\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\chbrdr\brdrnone\brdrcf1 \chshdng0\chcfpat1\chcbpat1\fbias0 \fi-360\li360\jclisttab\tx360 }{\listname ;}\listid768165129}{\list\listtemplateid67698703\listsimple +{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'02\'00.;}{\levelnumbers\'01;}\chbrdr\brdrnone\brdrcf1 \chshdng0\chcfpat1\chcbpat1 \fi-360\li360\jclisttab\tx360 }{\listname +;}\listid781152802}{\list\listtemplateid67698703\listsimple{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'02\'00.;}{\levelnumbers\'01;}\chbrdr\brdrnone\brdrcf1 +\chshdng0\chcfpat1\chcbpat1 \fi-360\li360\jclisttab\tx360 }{\listname ;}\listid903878531}{\list\listtemplateid67698689\listsimple{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext +\'01\u-3913 ?;}{\levelnumbers;}\f3\chbrdr\brdrnone\brdrcf1 \chshdng0\chcfpat1\chcbpat1\fbias0 \fi-360\li360\jclisttab\tx360 }{\listname ;}\listid1002394966}{\list\listtemplateid67698703\listsimple{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0 +\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'02\'00.;}{\levelnumbers\'01;}\chbrdr\brdrnone\brdrcf1 \chshdng0\chcfpat1\chcbpat1 \fi-360\li360\jclisttab\tx360 }{\listname ;}\listid1021513731}{\list\listtemplateid67698703\listsimple +{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'02\'00.;}{\levelnumbers\'01;}\chbrdr\brdrnone\brdrcf1 \chshdng0\chcfpat1\chcbpat1 \fi-360\li360\jclisttab\tx360 }{\listname +;}\listid1099714113}{\list\listtemplateid67698703\listsimple{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'02\'00.;}{\levelnumbers\'01;}\chbrdr\brdrnone\brdrcf1 +\chshdng0\chcfpat1\chcbpat1 \fi-360\li360\jclisttab\tx360 }{\listname ;}\listid1240552867}{\list\listtemplateid67698703\listsimple{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext +\'02\'00.;}{\levelnumbers\'01;}\chbrdr\brdrnone\brdrcf1 \chshdng0\chcfpat1\chcbpat1 \fi-360\li360\jclisttab\tx360 }{\listname ;}\listid1332292840}{\list\listtemplateid67698703\listsimple{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0 +\levelstartat1\levelspace0\levelindent0{\leveltext\'02\'00.;}{\levelnumbers\'01;}\chbrdr\brdrnone\brdrcf1 \chshdng0\chcfpat1\chcbpat1 \fi-360\li360\jclisttab\tx360 }{\listname ;}\listid1358388700}{\list\listtemplateid67698689\listsimple{\listlevel +\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\chbrdr\brdrnone\brdrcf1 \chshdng0\chcfpat1\chcbpat1\fbias0 \fi-360\li360\jclisttab\tx360 }{\listname +;}\listid1405952460}{\list\listtemplateid67698689\listsimple{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\chbrdr\brdrnone\brdrcf1 +\chshdng0\chcfpat1\chcbpat1\fbias0 \fi-360\li360\jclisttab\tx360 }{\listname ;}\listid2025940873}{\list\listtemplateid67698689\listsimple{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext +\'01\u-3913 ?;}{\levelnumbers;}\f3\chbrdr\brdrnone\brdrcf1 \chshdng0\chcfpat1\chcbpat1\fbias0 \fi-360\li360\jclisttab\tx360 }{\listname ;}\listid2044863907}}{\*\listoverridetable{\listoverride\listid2025940873\listoverridecount0\ls1} +{\listoverride\listid1002394966\listoverridecount0\ls2}{\listoverride\listid470094698\listoverridecount0\ls3}{\listoverride\listid1099714113\listoverridecount0\ls4}{\listoverride\listid1358388700\listoverridecount0\ls5}{\listoverride\listid2044863907 +\listoverridecount0\ls6}{\listoverride\listid640160996\listoverridecount0\ls7}{\listoverride\listid768165129\listoverridecount0\ls8}{\listoverride\listid903878531\listoverridecount0\ls9}{\listoverride\listid781152802\listoverridecount0\ls10} +{\listoverride\listid1240552867\listoverridecount0\ls11}{\listoverride\listid640160996\listoverridecount0\ls12}{\listoverride\listid349260549\listoverridecount0\ls13}{\listoverride\listid1021513731\listoverridecount0\ls14}{\listoverride\listid1405952460 +\listoverridecount0\ls15}{\listoverride\listid1332292840\listoverridecount0\ls16}}{\*\revtbl {Unknown;}{Tim Mann;}}{\info{\title + $ # KWinBoard: Chessboard for Windows}{\author TRIO}{\operator Timothy Mann}{\creatim\yr2001\mo12\dy9\hr12\min56}{\revtim\yr2001\mo12\dy9\hr12\min56} +{\printim\yr1997\mo4\dy22\hr23\min5}{\version2}{\edmins2}{\nofpages60}{\nofwords12847}{\nofchars73230}{\*\company DEC SRC}{\nofcharsws89931}{\vern8269}} +\widowctrl\endnotes\aendnotes\ftnnrlc\aftnnar\noxlattoyen\expshrtn\noultrlspc\dntblnsbdb\nospaceforul\hyphcaps0\horzdoc\dghspace120\dgvspace120\dghorigin1701\dgvorigin1984\dghshow0\dgvshow3\jcompress\viewkind4\viewscale100\nolnhtadjtbl \fet1{\*\aftnsep +\pard\plain \ql \li120\ri0\sb80\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\chftnsep +\par }}\sectd \linex0\sectdefaultcl {\*\pnseclvl1\pnucrm\pnstart1\pnindent720\pnhang{\pntxta .}}{\*\pnseclvl2\pnucltr\pnstart1\pnindent720\pnhang{\pntxta .}}{\*\pnseclvl3\pndec\pnstart1\pnindent720\pnhang{\pntxta .}}{\*\pnseclvl4 +\pnlcltr\pnstart1\pnindent720\pnhang{\pntxta )}}{\*\pnseclvl5\pndec\pnstart1\pnindent720\pnhang{\pntxtb (}{\pntxta )}}{\*\pnseclvl6\pnlcltr\pnstart1\pnindent720\pnhang{\pntxtb (}{\pntxta )}}{\*\pnseclvl7\pnlcrm\pnstart1\pnindent720\pnhang{\pntxtb (} +{\pntxta )}}{\*\pnseclvl8\pnlcltr\pnstart1\pnindent720\pnhang{\pntxtb (}{\pntxta )}}{\*\pnseclvl9\pnlcrm\pnstart1\pnindent720\pnhang{\pntxtb (}{\pntxta )}}\pard\plain \s1\ql \li120\ri0\sb280\sa120\sl-320\slmult0 +\nowidctlpar\faauto\outlinelevel0\adjustright\rin0\lin120\itap0 \b\f5\fs24\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\fs20\super +{\footnote\ftnalt \pard\plain \s57\ql \li120\ri0\sb80\sl-240\slmult0 +\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super +}{\f1 main}}${\footnote\ftnalt \pard\plain \s57\ql \li120\ri0\sb80\sl-240\slmult0 +\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super $}{\f1 Contents}}#{\footnote\ftnalt \pard\plain \s57\ql \li120\ri0\sb80\sl-240\slmult0 +\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super #}{\f1 Contents}}K{\footnote\ftnalt \pard\plain \s57\ql \li120\ri0\sb80\sl-240\slmult0 +\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super K}{\f1 Contents}}}{\i\f1\fs32 WinBoard}{\f1\fs32 : Chessboard for Windows +\par }\pard\plain \s2\ql \li120\ri0\sb120\sa60\sl-240\slmult0\nowidctlpar\faauto\outlinelevel1\adjustright\rin0\lin120\itap0 \b\f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super K{\footnote\ftnalt \pard\plain +\s57\ql \li120\ri0\sb80\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super K}{\f1 Description}}#{\footnote\ftnalt \pard\plain \s57\ql \li120\ri0\sb80\sl-240\slmult0 +\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super #}{\f1 Description}}}{\f1 Description +\par }\pard\plain \s26\ql \li120\ri0\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\i\f1 WinBoard}{\f1 + is a graphical user interface for chess. It displays a chessboard on the screen, accepts moves made with the mouse, and loads and saves game files in standard chess notation. WinBoard serves as a front-end for many different services, including: +\par {\pntext\pard\plain\f3\fs20 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard\plain \ql \fi-360\li480\ri0\sb80\sl-240\slmult0\nowidctlpar\jclisttab\tx480{\*\pn \pnlvlblt\ilvl0\ls3\pnrnot0\pnf3\pnstart1\pnindent360\pnsp120\pnhang{\pntxtb \'b7}} +\faauto\ls3\adjustright\rin0\lin480\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\b\i\f1 Chess engines}{\f1 + that run on your PC. You can play a game against an engine, set up arbitrary positions, force variations, or watch a game between two engines. }{\i\f1 GNU Chess}{\f1 is supplied with WinBoard, and over 10 +0 other free chess engines are available separately. Of these, Crafty is the most popular. See }{\f1\uldb Installing Chess Engines}{\v\f1 InstallingChessEngines}{\f1 for instructions on installing additional chess engines. +\par {\pntext\pard\plain\f3\fs20 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \ql \fi-360\li480\ri0\sb80\sl-240\slmult0\nowidctlpar\jclisttab\tx480{\*\pn \pnlvlblt\ilvl0\ls3\pnrnot0\pnf3\pnstart1\pnindent360\pnsp120\pnhang{\pntxtb \'b7}} +\faauto\ls3\adjustright\rin0\lin480\itap0 {\b\i\f1 Chess servers}{\b\f1 }{\f1 on the Internet. You can play against other + Internet Chess Server (ICS) users, observe games they are playing, review games in the ICS libraries, chat, and more. WinBoard can also be used to run an automated computer player on the ICS, but this feature is for advanced users only and is subject to +some caveats; see the separate file zippy.README for information. +\par {\pntext\pard\plain\f3\fs20 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \ql \fi-360\li480\ri0\sb80\sl-240\slmult0\nowidctlpar\jclisttab\tx480{\*\pn \pnlvlblt\ilvl0\ls3\pnrnot0\pnf3\pnstart1\pnindent360\pnsp120\pnhang{\pntxtb \'b7}} +\faauto\ls3\adjustright\rin0\lin480\itap0 {\b\i\f1 The Web}{\f1 and your own saved games. You can use WinBoard as a helper application to view files in your Web browser or the Explorer. You can use it to keep track of email postal games, browse ga +mes off the net, or review games you have saved. +\par }\pard\plain \s2\ql \li120\ri0\sb120\sa60\sl-240\slmult0\nowidctlpar\faauto\outlinelevel1\adjustright\rin0\lin120\itap0 \b\f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super K{\footnote\ftnalt \pard\plain +\s57\ql \li120\ri0\sb80\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\super K}{ Getting Started}}#{\footnote\ftnalt \pard\plain \s57\ql \li120\ri0\sb80\sl-240\slmult0 +\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\super #}{ GettingStarted}}}{\f1 Getting Started +\par }\pard\plain \s26\ql \li120\ri0\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\f1 +WinBoard starts up in one of three major modes: chess engine mode, ICS client mode, or game viewer mode. You cannot change modes while WinBoard is running, but you can access all the game v +iewer features directly from the other two modes. Also, you can start WinBoard several times to get multiple chessboard windows running in any combination of modes. +\par }\pard\plain \s20\ql \li120\ri0\sb80\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {You will usually run WinBoard by choosing an item from the Windows Start menu that runs it +in the mode you want. If you just double-click on WinBoard.exe, you get a startup dialog asking which mode you want. If you choose chess engine mode, you can then select from the installed engines; if you choose ICS client mode, you can then select from a + list of known chess servers. More advanced users can }{\uldb customize}{\v icsNames}{ these lists or type in WinBoard }{\uldb command line options}{\v Options}{ directly. +\par }\pard\plain \ql \li120\ri0\sb80\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\f1 After starting WinBoard, you can make }{\cs58\f1\super K{\footnote\ftnalt \pard\plain +\s57\ql \li120\ri0\sb80\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super K}{\f1 move}}#{\footnote\ftnalt \pard\plain \s57\ql \li120\ri0\sb80\sl-240\slmult0 +\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super #}{\f1 move}}}{\f1 moves in several different ways. To move by dragging, press the left mouse +button while the cursor is on one of your pieces, move the cursor to another square, and release the button. You can also move by clicking the left mouse button once (press and release) over one of your pieces, moving the cursor to another square, and cli +c +king again. You drop new pieces on the board (when applicable) by selecting from a context menu. Press the right mouse button over a square to bring up the menu; no menu will come up in modes where dropping a new piece is not permitted. You can also make +moves by typing them in standard algebraic chess notation. Either a dialog box will pop up for you to type into, or in ICS mode, your typing will be redirected into the ICS interaction window. +\par When WinBoard}{\i\f1 }{\f1 is iconized, its }{\cs58\f1\super K{\footnote\ftnalt \pard\plain \s57\ql \li120\ri0\sb80\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 { +\cs58\f1\super K}{\f1 icon}}#{\footnote\ftnalt \pard\plain \s57\ql \li120\ri0\sb80\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super #}{\f1 icon}}}{\f1 +icon is a white knight if it is White's turn to move, a black knight if it is Black's turn. +\par }\pard\plain \s2\ql \li120\ri0\sb120\sa60\sl-240\slmult0\nowidctlpar\faauto\outlinelevel1\adjustright\rin0\lin120\itap0 \b\f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\f1 Additional Information +\par }\pard\plain \s29\ql \fi-240\li360\ri0\sb60\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin360\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\f1\uldb Menus}{\v\f1\uldb Menus}{\f1\uldb +\par Shortcut Buttons}{\v\f1\uldb Buttons}{\f1\uldb +\par Command Line Options}{\v\f1 Options}{\f1 +\par }{\f1\uldb Initialization Files}{\v\f1\uldb Files}{\f1\uldb +\par Installing Chess Engines}{\v\f1\uldb InstallingChessEngines}{\f1\uldb +\par Firewalls}{\v\f1 Firewalls}{\f1 +\par }{\f1\uldb Limitations}{\v\f1 Limitations}{\f1\uldb +\par Authors}{\v\f1 Authors}{\f1 +\par }{\f1\uldb Copyright}{\v\f1 Copyright}{\f1 +\par }{\f1\uldb Frequently Asked Questions}{\v\f1 !ExecFile(FAQ.html)}{\f1 +\par }\pard\plain \s1\ql \li120\ri0\sb280\sa120\sl-320\slmult0\nowidctlpar\faauto\outlinelevel0\adjustright\rin0\lin120\itap0 \b\f5\fs24\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\f1\fs20 \page }{\cs58\f1\fs20\super K{\footnote\ftnalt \pard\plain +\s57\ql \li120\ri0\sb80\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super K}{\f1 Menus}}#{\footnote\ftnalt \pard\plain \s57\ql \li120\ri0\sb80\sl-240\slmult0 +\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super #}{\f1 Menus}}${\footnote\ftnalt \pard\plain \s57\ql \li120\ri0\sb80\sl-240\slmult0 +\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super $}{\f1 Menus}}+{\footnote\ftnalt \pard\plain \s57\ql \li120\ri0\sb80\sl-240\slmult0 +\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super +}{\f1 main}}}{\f1\fs20 MENUS +\par }\pard\plain \s29\ql \fi-240\li360\ri0\sb60\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin360\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\f1\uldb File Menu}{\v\f1 FileMenu}{\f1 +\par }{\f1\uldb Mode Menu}{\v\f1 ModeMenu}{\f1 +\par }{\f1\uldb Action Menu}{\v\f1 ActionMenu}{\f1 +\par }{\f1\uldb Step Menu}{\v\f1 StepMenu}{\f1 +\par }{\f1\uldb Options Menu}{\v\f1 OptionsMenu}{\f1 +\par }{\f1\uldb Help Menu}{\v\f1 HelpMenu}{\f1 +\par }{\f1\uldb ICS Interaction Context Menu}{\v\f1 ICSInteractionContextMenu}{\f1 +\par }\pard\plain \s1\ql \li120\ri0\sb280\sa120\sl-320\slmult0\nowidctlpar\faauto\outlinelevel0\adjustright\rin0\lin120\itap0 \b\f5\fs24\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\f1\fs20 \page }{\cs58\f1\fs20\super K{\footnote\ftnalt \pard\plain +\s57\ql \li120\ri0\sb80\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super K}{\f1 File Menu}}#{\footnote\ftnalt \pard\plain \s57\ql \li120\ri0\sb80\sl-240\slmult0 +\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super #}{\f1 FileMenu}}${\footnote\ftnalt \pard\plain \s57\ql \li120\ri0\sb80\sl-240\slmult0 +\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super $}{\f1 File Menu}}+{\footnote\ftnalt \pard\plain \s57\ql \li120\ri0\sb80\sl-240\slmult0 +\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super +}{\f1 main}}}{\f1\fs18\up6 }{\f1\fs20 File Menu +\par }\pard\plain \s2\ql \li120\ri0\sb120\sa60\sl-240\slmult0\nowidctlpar\faauto\outlinelevel1\adjustright\rin0\lin120\itap0 \b\f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super K{\footnote\ftnalt \pard\plain +\s57\ql \li120\ri0\sb80\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super K}{\f1 Reset}}#{\footnote\ftnalt \pard\plain \s57\ql \li120\ri0\sb80\sl-240\slmult0 +\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super #}{\f1 Reset}}}{\f1 Reset +\par }\pard\plain \s26\ql \li120\ri0\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\f1 +Resets WinBoard and the chess engine (if any) to the beginning of a new chess game. In Internet Chess Server mode, clears the current state of WinBoard, then resynchronizes with ICS by sending a }{\b\f1 refresh }{\f1 command. If you + want to stop playing, observing, or examining a game on ICS, use an appropriate command from the }{\f1\uldb Action}{\v\f1 ActionMenu}{\f1 menu, not Reset. +\par }\pard\plain \s2\ql \li120\ri0\sb120\sa60\sl-240\slmult0\nowidctlpar\faauto\outlinelevel1\adjustright\rin0\lin120\itap0 \b\f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super K{\footnote\ftnalt \pard\plain +\s57\ql \li120\ri0\sb80\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super K}{\f1 Load Game}}#{\footnote\ftnalt \pard\plain \s57\ql \li120\ri0\sb80\sl-240\slmult0 +\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super #}{\f1 LoadGame}}}{\f1 Load Game +\par }\pard\plain \s26\ql \li120\ri0\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\f1 +Plays a game from a record file. A popup dialog prompts you for the filename. If the file contains more than on +e game, a second popup dialog displays a list of games (with information drawn from their PGN tags, if any), and you can select the one you want. +\par }\pard\plain \ql \li120\ri0\sb80\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\f1 +The game file parser will accept PGN (portable game notation), or in fact almost any file that contains moves in algebraic notation. Notation of the form }{\i\f1 P@f7}{\f1 + is accepted for piece-drops in bughouse games; this is a nonstandard extension to PGN. If the file includes a PGN position (FEN tag), or a WinBoard position diagram bracketed by "[--" and "--]" before the fi +rst move, the game starts from that position. Text enclosed in parentheses, square brackets, or curly braces is assumed to be commentary and is displayed in a pop-up window. Any other text in the file is ignored. PGN variations (enclosed in parentheses) a +re treated as comments; WinBoard is not able to walk variation trees. The nonstandard PGN tag }{\f2 [Variant "varname"]}{\f1 functions similarly to the }{\f1\uldb variant}{\v\f1 variant }{\f1 +command-line option, allowing games in certain chess variants to be loaded. There is also a heuristic to recognize chess variants from the }{\f2 Event}{\f1 + tag, by looking for the strings that the Internet Chess Servers put there when saving variant ("wild") games. +\par }\pard\plain \s2\ql \li120\ri0\sb120\sa60\sl-240\slmult0\nowidctlpar\faauto\outlinelevel1\adjustright\rin0\lin120\itap0 \b\f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super K{\footnote\ftnalt \pard\plain +\s57\ql \li120\ri0\sb80\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super K}{\f1 Load Next Game}}#{\footnote\ftnalt \pard\plain +\s57\ql \li120\ri0\sb80\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super #}{\f1 LoadNextGame}}}{\f1 Load Next Game +\par }\pard\plain \s26\ql \li120\ri0\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\f1 Loads the next game from the last game record file you loaded. +\par }\pard\plain \s2\ql \li120\ri0\sb120\sa60\sl-240\slmult0\nowidctlpar\faauto\outlinelevel1\adjustright\rin0\lin120\itap0 \b\f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super K{\footnote\ftnalt \pard\plain +\s57\ql \li120\ri0\sb80\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super K}{\f1 Load Previous Game}}#{\footnote\ftnalt \pard\plain +\s57\ql \li120\ri0\sb80\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super #}{\f1 LoadPreviousGame}}}{\f1 Load Previous Game +\par }\pard\plain \s26\ql \li120\ri0\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\f1 +Loads the previous game from the last game record file you loaded. Not available if the last game was loaded from a pipe. +\par }\pard\plain \s2\ql \li120\ri0\sb120\sa60\sl-240\slmult0\nowidctlpar\faauto\outlinelevel1\adjustright\rin0\lin120\itap0 \b\f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super K{\footnote\ftnalt \pard\plain +\s57\ql \li120\ri0\sb80\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super K}{\f1 Reload Same Game}}#{\footnote\ftnalt \pard\plain +\s57\ql \li120\ri0\sb80\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super #}{\f1 ReloadSameGame}}}{\f1 Reload Same Game +\par }\pard\plain \s26\ql \li120\ri0\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\f1 Reloads the last game you loaded. Not available if the last game was loaded from a pipe. +\par }\pard\plain \s2\ql \li120\ri0\sb120\sa60\sl-240\slmult0\nowidctlpar\faauto\outlinelevel1\adjustright\rin0\lin120\itap0 \b\f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super K{\footnote\ftnalt \pard\plain +\s57\ql \li120\ri0\sb80\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super K}{\f1 Save Game}}#{\footnote\ftnalt \pard\plain \s57\ql \li120\ri0\sb80\sl-240\slmult0 +\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super #}{\f1 SaveGame}}}{\f1 Save Game +\par }\pard\plain \s26\ql \li120\ri0\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\f1 Appends a r +ecord of the current game to a file. A popup dialog prompts you for the filename. If the game did not begin with the standard starting position, the game file includes the starting position used. Game files are saved in the PGN (portable game notation) fo +rmat, unless the }{\f1\uldb oldSaveStyle}{\v\f1 oldSaveStyle}{\f1 option is True, in which case they are saved in an older format that is specific to WinBoard}{\i\f1 .}{\f1 + Both formats are human-readable, and both can be read back by the Load Game command. Notation of the form }{\i\f1 P@f7}{\f1 is generated for piece-drops in bughouse games; this is a nonstandard extension to PGN. +\par }\pard\plain \s2\ql \li120\ri0\sb120\sa60\sl-240\slmult0\nowidctlpar\faauto\outlinelevel1\adjustright\rin0\lin120\itap0 \b\f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super K{\footnote\ftnalt \pard\plain +\s57\ql \li120\ri0\sb80\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super K}{\f1 Copy Game To Clipboard}}#{\footnote\ftnalt \pard\plain +\s57\ql \li120\ri0\sb80\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super #}{\f1 CopyGameToClipboard}}}{\f1 Copy Game To Clipboard +\par }\pard\plain \ql \li120\ri0\sb80\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 { +Copies the record of the current game to the Windows clipboard in PGN (portable game notation) format. +\par }\pard\plain \s2\ql \li120\ri0\sb120\sa60\sl-240\slmult0\nowidctlpar\faauto\outlinelevel1\adjustright\rin0\lin120\itap0 \b\f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super K{\footnote\ftnalt \pard\plain +\s57\ql \li120\ri0\sb80\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super K}{\f1 Paste Game From Clipboard}}#{\footnote\ftnalt \pard\plain +\s57\ql \li120\ri0\sb80\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super #}{\f1 PasteGameFromClipboard}}}{\f1 Paste Game From Clipboard +\par }\pard\plain \ql \li120\ri0\sb80\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {Plays a game from the Windows clipboard.}{\f1 See }{\f1\uldb Load Game}{\v\f1 LoadGame}{\f1 + for a discussion of game file format and parser behavior.}{ +\par }\pard\plain \s2\ql \li120\ri0\sb120\sa60\sl-240\slmult0\nowidctlpar\faauto\outlinelevel1\adjustright\rin0\lin120\itap0 \b\f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super K{\footnote\ftnalt \pard\plain +\s57\ql \li120\ri0\sb80\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super K}{\f1 Load Position}}#{\footnote\ftnalt \pard\plain \s57\ql \li120\ri0\sb80\sl-240\slmult0 +\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super #}{\f1 LoadPosition}}}{\f1 Load Position +\par }\pard\plain \s26\ql \li120\ri0\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\f1 +Sets up a position from a position file. A popup dialog prompts you for the filename. Position files must be in FEN (Forsythe-Edwards notation), or in the format that the }{\f1\uldb Save Position}{\f1 command writes when }{\f1\uldb oldSaveStyle}{\v\f1 +oldSaveStyle}{\f1 is turned on. +\par }\pard\plain \s2\ql \li120\ri0\sb120\sa60\sl-240\slmult0\nowidctlpar\faauto\outlinelevel1\adjustright\rin0\lin120\itap0 \b\f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super K{\footnote\ftnalt \pard\plain +\s57\ql \li120\ri0\sb80\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super K}{\f1 Load Next Position}}#{\footnote\ftnalt \pard\plain +\s57\ql \li120\ri0\sb80\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super #}{\f1 LoadNextPosition}}}{\f1 Load Next Position +\par }\pard\plain \s26\ql \li120\ri0\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\f1 Loads the next position from the last position file you loaded. +\par }\pard\plain \s2\ql \li120\ri0\sb120\sa60\sl-240\slmult0\nowidctlpar\faauto\outlinelevel1\adjustright\rin0\lin120\itap0 \b\f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super K{\footnote\ftnalt \pard\plain +\s57\ql \li120\ri0\sb80\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super K}{\f1 Load Previous Position}}#{\footnote\ftnalt \pard\plain +\s57\ql \li120\ri0\sb80\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super #}{\f1 LoadPreviousPosition}}}{\f1 Load Previous Position +\par }\pard\plain \s26\ql \li120\ri0\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\f1 Loads the previous position from the l +ast position file you loaded. Not available if the last position was loaded from a pipe. +\par }\pard\plain \s2\ql \li120\ri0\sb120\sa60\sl-240\slmult0\nowidctlpar\faauto\outlinelevel1\adjustright\rin0\lin120\itap0 \b\f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super K{\footnote\ftnalt \pard\plain +\s57\ql \li120\ri0\sb80\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super K}{\f1 Reload Same Position}}#{\footnote\ftnalt \pard\plain +\s57\ql \li120\ri0\sb80\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super #}{\f1 ReloadSamePosition}}}{\f1 Reload Same Position +\par }\pard\plain \s26\ql \li120\ri0\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\f1 +Reloads the last position you loaded. Not available if the last position was loaded from a pipe. +\par }\pard\plain \s2\ql \li120\ri0\sb120\sa60\sl-240\slmult0\nowidctlpar\faauto\outlinelevel1\adjustright\rin0\lin120\itap0 \b\f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super K{\footnote\ftnalt \pard\plain +\s57\ql \li120\ri0\sb80\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super K}{\f1 Save Position}}#{\footnote\ftnalt \pard\plain \s57\ql \li120\ri0\sb80\sl-240\slmult0 +\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super #}{\f1 SavePosition}}}{\f1 Save Position +\par }\pard\plain \s26\ql \li120\ri0\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\f1 Appends a diagram of the curr +ent position to a file. A popup dialog prompts you for the filename. Positions are saved in FEN (Forsythe-Edwards notation) format, unless the }{\f1\uldb oldSaveStyle}{\v\f1 oldSaveStyle}{\f1 + option is True, in which case they are saved in an older, human-readable format that is specific to WinBoard}{\i\f1 .}{\f1 + Both formats can be read back by the Load Position command; however, currently Load Position can load only the first position in a file. +\par }\pard\plain \s2\ql \li120\ri0\sb120\sa60\sl-240\slmult0\nowidctlpar\faauto\outlinelevel1\adjustright\rin0\lin120\itap0 \b\f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super K{\footnote\ftnalt \pard\plain +\s57\ql \li120\ri0\sb80\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super K}{\f1 Copy Position Clipboard}}#{\footnote\ftnalt \pard\plain +\s57\ql \li120\ri0\sb80\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super #}{\f1 CopyPositionToClipboard}}}{\f1 Copy Position To Clipboard +\par }\pard\plain \ql \li120\ri0\sb80\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\f1 Places a diagram of the current position (in Forsythe-Edwards notat +ion) into the Windows clipboard. +\par }\pard\plain \s2\ql \li120\ri0\sb120\sa60\sl-240\slmult0\nowidctlpar\faauto\outlinelevel1\adjustright\rin0\lin120\itap0 \b\f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super K{\footnote\ftnalt \pard\plain +\s57\ql \li120\ri0\sb80\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super K}{\f1 Paste Position Clipboard}}#{\footnote\ftnalt \pard\plain +\s57\ql \li120\ri0\sb80\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super #}{\f1 PastePositionFromClipboard}}}{\f1 Paste Position From Clipboard +\par }\pard\plain \s26\ql \li120\ri0\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\f1 +Sets up a position from the Windows clipboard. Position must be in FEN (Forsythe-Edwards notation). Puts WinBoard into }{\f1\uldb Edit Game}{\v\f1 EditGame}{\f1 mode if it was not there already. +\par }\pard\plain \s2\ql \li120\ri0\sb120\sa60\sl-240\slmult0\nowidctlpar\faauto\outlinelevel1\adjustright\rin0\lin120\itap0 \b\f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super K{\footnote\ftnalt \pard\plain +\s57\ql \li120\ri0\sb80\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super K}{\f1 Exit}}#{\footnote\ftnalt \pard\plain \s57\ql \li120\ri0\sb80\sl-240\slmult0 +\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super #}{\f1 Exit}}}{\f1 Exit +\par }\pard\plain \s26\ql \li120\ri0\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\f1 Exits from WinBoard. +\par }\pard\plain \s1\ql \li120\ri0\sb280\sa120\sl-320\slmult0\nowidctlpar\faauto\outlinelevel0\adjustright\rin0\lin120\itap0 \b\f5\fs24\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\f1\fs20 \page }{\cs58\f1\fs20\super K{\footnote\ftnalt \pard\plain +\ql \li120\ri0\sb80\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super K}{\f1 Mode Menu}}#{\footnote\ftnalt \pard\plain \s57\ql \li120\ri0\sb80\sl-240\slmult0 +\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super #}{\f1 ModeMenu}}${\footnote\ftnalt \pard\plain \s57\ql \li120\ri0\sb80\sl-240\slmult0 +\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super $}{\f1 Mode Menu}}+{\footnote\ftnalt \pard\plain \s57\ql \li120\ri0\sb80\sl-240\slmult0 +\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super +}{\f1 main}}}{\f1\fs20 Mode Menu +\par }\pard\plain \s2\ql \li120\ri0\sb120\sa60\sl-240\slmult0\nowidctlpar\faauto\outlinelevel1\adjustright\rin0\lin120\itap0 \b\f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super K{\footnote\ftnalt \pard\plain +\s57\ql \li120\ri0\sb80\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super K}{\f1 Machine White}}#{\footnote\ftnalt \pard\plain \s57\ql \li120\ri0\sb80\sl-240\slmult0 +\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super #}{\f1 MachineWhite}}}{\f1 Machine White +\par }\pard\plain \s26\ql \li120\ri0\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\f1 Forces the chess engine to play white. +\par }\pard\plain \s2\ql \li120\ri0\sb120\sa60\sl-240\slmult0\nowidctlpar\faauto\outlinelevel1\adjustright\rin0\lin120\itap0 \b\f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super K{\footnote\ftnalt \pard\plain +\s57\ql \li120\ri0\sb80\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super K}{\f1 Machine Black}}#{\footnote\ftnalt \pard\plain \s57\ql \li120\ri0\sb80\sl-240\slmult0 +\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super #}{\f1 MachineBlack}}}{\f1 Machine Black +\par }\pard\plain \s26\ql \li120\ri0\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\f1 Forces the chess engine to play black. +\par }\pard\plain \s2\ql \li120\ri0\sb120\sa60\sl-240\slmult0\nowidctlpar\faauto\outlinelevel1\adjustright\rin0\lin120\itap0 \b\f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super K{\footnote\ftnalt \pard\plain +\s57\ql \li120\ri0\sb80\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super K}{\f1 Two Machines}}#{\footnote\ftnalt \pard\plain \s57\ql \li120\ri0\sb80\sl-240\slmult0 +\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super #}{\f1 TwoMachines}}}{\f1 Two Machines +\par }\pard\plain \s26\ql \li120\ri0\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\f1 Starts a game between two chess engines. +\par }\pard\plain \s2\ql \li120\ri0\sb120\sa60\sl-240\slmult0\nowidctlpar\faauto\outlinelevel1\adjustright\rin0\lin120\itap0 \b\f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super K{\footnote\ftnalt \pard\plain +\s57\ql \li120\ri0\sb80\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super K}{\f1 Analysis Mode}}#{\footnote\ftnalt \pard\plain \s57\ql \li120\ri0\sb80\sl-240\slmult0 +\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super #}{\f1 AnalysisMode}}}{\f1 Analysis Mode +\par }\pard\plain \s26\ql \li120\ri0\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\f1 In this mode, you can make moves for both si +des on the board. After each move, the chess engine will think about possible replies and display its analysis in a separate window. This feature currently works only if Crafty is the chess engine. +\par }\pard\plain \s2\ql \li120\ri0\sb120\sa60\sl-240\slmult0\nowidctlpar\faauto\outlinelevel1\adjustright\rin0\lin120\itap0 \b\f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super K{\footnote\ftnalt \pard\plain +\s57\ql \li120\ri0\sb80\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super K}{\f1 Analyze File}}#{\footnote\ftnalt \pard\plain \s57\ql \li120\ri0\sb80\sl-240\slmult0 +\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super #}{\f1 AnalyzeFile}}}{\f1 Analyze File +\par }\pard\plain \s26\ql \li120\ri0\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\f1 In this mode, you can load a game from a f +ile, and the chess engine will analyze each move as in Analysis Mode. This feature currently works only if Crafty is the chess engine. +\par }\pard\plain \s2\ql \li120\ri0\sb120\sa60\sl-240\slmult0\nowidctlpar\faauto\outlinelevel1\adjustright\rin0\lin120\itap0 \b\f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super K{\footnote\ftnalt \pard\plain +\s57\ql \li120\ri0\sb80\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super K}{\f1 ICS Client}}#{\footnote\ftnalt \pard\plain \s57\ql \li120\ri0\sb80\sl-240\slmult0 +\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super #}{\f1 ICSClient}}}{\f1 ICS Client +\par }\pard\plain \s26\ql \li120\ri0\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\f1 +This is the normal mode when WinBoard is connected to a chess server. If you have moved into Edit Game or Edit Position mode, you can select this option to get out. +\par }\pard\plain \ql \li120\ri0\sb80\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\f1 +When you run WinBoard in ICS mode, it starts up a console window in which you can type commands and receive text responses from the chess server. You can use the standard Windows editing keys to edi +t your command line before pressing Enter. The console window keeps a history of the last few commands you typed. Press the up-arrow key to go back to a previous command; press the down-arrow key to go forward again to a later command. Press the right mou +se button in the output area for a }{\f1\uldb context menu}{\v\f1 ICSInteractionContextMenu}{\f1 of editing commands and ICS command shortcuts. +\par Some useful ICS commands include }{\b\f1 who}{\f1 to see who is logged on, }{\b\f1 games}{\f1 to see what games are being played, }{\b\f1 match}{\f1 to challenge another player to a game, }{\b\f1 observe}{\f1 to observe an ongoing game, }{\b\f1 +examine}{\f1 or }{\b\f1 smoves}{\f1 to review a recently completed game, and of course }{\b\f1 help}{\f1 . +\par Whenever you ask to observe an ongoing game, review a completed game, or resume an adjourned game, WinBoard retrieves and parses the list of past moves from the ICS, so you can review them with }{\f1\uldb Forward}{\v\f1 Forward}{\f1 and }{\f1\uldb +Backward}{\v\f1 Backward}{\f1 or save them with }{\f1\uldb Save Game}{\v\f1 SaveGame}{\f1 . +\par Some special ICS Client features are activated when you are in }{\b\f1 examine}{\f1 or }{\b\f1 bsetup }{\f1 mode on ICS. See the descriptions of the menu commands }{\f1\uldb Forward}{\v\f1 Forward}{\f1 , }{\f1\uldb Backward}{\v\f1 Backward}{\f1 , }{ +\f1\uldb Pause}{\v\f1 Pause}{\f1 , and }{\f1\uldb Stop Examining}{\v\f1 StopExamining}{\f1 below. You can also issue the ICS position-editing commands with the mouse. Move pieces by dragging with the left mouse button, or by left-clicking once on the sta +rting square and once on the ending square. Press the right mouse button over a square for a context menu that lets you drop a new piece, empty the square, or clear the board. Click on the White or Black clock to set the side to play. You cannot set the s +i +de to play or drag pieces to arbitrary squares while examining on ICC, but you can do so in bsetup mode on FICS. You can also make moves by typing them into the ICS window; you may have to do this occasionally if you are playing a chess variant whose rule +s WinBoard does not understand, such as Fischer Random. +\par If you are playing a bughouse game on the ICS, a list of the offboard pieces that each player holds is shown in the window title bar. To drop an offboard piece, press the right mouse button over an emp +ty square to bring up a context menu. To observe your partner's games, start a second copy of WinBoard, log in as a guest, and use the ICS }{\b\f1 follow}{\f1 or }{\b\f1 pfollow}{\f1 command in the new window. +\par }\pard\plain \s2\ql \li120\ri0\sb120\sa60\sl-240\slmult0\nowidctlpar\faauto\outlinelevel1\adjustright\rin0\lin120\itap0 \b\f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super K{\footnote\ftnalt \pard\plain +\s57\ql \li120\ri0\sb80\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super K}{\f1 Edit Game}}#{\footnote\ftnalt \pard\plain \s57\ql \li120\ri0\sb80\sl-240\slmult0 +\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super #}{\f1 EditGame}}}{\f1 Edit Game +\par }\pard\plain \s26\ql \li120\ri0\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\f1 Allows you to make moves for both Black and White, and to c +hange moves after backing up with the }{\f1\uldb Backward}{\v\f1 Backward}{\f1 command. The clocks do not run. +\par }\pard\plain \ql \li120\ri0\sb80\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\f1 +In chess engine mode, the chess engine continues to check moves for legality but does not participate in the game. You can bring the chess engine back into the game by selecting }{\f1\uldb Machine White}{\v\f1 MachineWhite}{\f1 , }{\f1\uldb Machine Black} +{\v\f1 MachineBlack}{\f1 , or }{\f1\uldb Two Machines}{\v\f1 TwoMachines}{\f1 . +\par In ICS mode, the moves are not sent to the ICS: Edit Game takes WinBoard out of ICS Client mode and lets you edit games locally. If you want to edit a game on ICS in a way that other ICS users can see, use the ICS }{\b\f1 examine}{\f1 + command or start an ICS match against yourself. +\par }\pard\plain \s2\ql \li120\ri0\sb120\sa60\sl-240\slmult0\nowidctlpar\faauto\outlinelevel1\adjustright\rin0\lin120\itap0 \b\f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super K{\footnote\ftnalt \pard\plain +\s57\ql \li120\ri0\sb80\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super K}{\f1 Edit Position}}#{\footnote\ftnalt \pard\plain \s57\ql \li120\ri0\sb80\sl-240\slmult0 +\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super #}{\f1 EditPosition}}}{\f1 Edit Position +\par }\pard\plain \s26\ql \li120\ri0\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\f1 +Lets you set up an arbitrary board position. Use the left mouse button to drag pieces to new squares, or to delete a piece by dragging + it off the board or dragging an empty square on top of it. To drop a new piece on a square, press the right mouse button over the square. This brings up a menu of pieces. Additional menu choices let you empty the square or clear the board. You can set th +e side to play next by clicking on the White or Black indicator at the top of the screen. +\par }\pard\plain \ql \li120\ri0\sb80\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\f1 Selecting Edit Position causes WinBoard}{\i\f1 }{\f1 +to discard all remembered moves in the current game. +\par In ICS mode, change made to the position by Edit Position are not sent to +the ICS: Edit Position takes WinBoard out of ICS Client mode and lets you edit positions locally. If you want to edit positions on ICS in a way that other ICS users can see, use the ICS }{\b\f1 examine}{\f1 + command, or start an ICS match against yourself. (See also }{\f1\uldb ICS Client}{\v\f1 ICSClient}{\f1 above.) +\par }\pard\plain \s2\ql \li120\ri0\sb120\sa60\sl-240\slmult0\nowidctlpar\faauto\outlinelevel1\adjustright\rin0\lin120\itap0 \b\f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super K{\footnote\ftnalt \pard\plain +\s57\ql \li120\ri0\sb80\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super K}{\f1 Training}}#{\footnote\ftnalt \pard\plain \s57\ql \li120\ri0\sb80\sl-240\slmult0 +\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super #}{\f1 Training}}}{\f1 Training +\par }\pard\plain \ql \li120\ri0\sb80\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 { +Training mode lets you interactively guess the moves of a game for one of the players. While in Training mode, the navigation buttons are disabled. You guess the next move of the game by playing the move on the board (or using the }{\uldb Type In Move}{ +\v\uldb TypeInMove}{ command). If the move played matches the next move of the game, the move is accepted and the opponent\rquote s response is autoplayed. If the move played is incorrect, an error message is displayed. +\par }\pard\plain \s2\ql \li120\ri0\sb120\sa60\sl-240\slmult0\nowidctlpar\faauto\outlinelevel1\adjustright\rin0\lin120\itap0 \b\f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super K{\footnote\ftnalt \pard\plain +\s57\ql \li120\ri0\sb80\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super K}{\f1 Show Game List}}#{\footnote\ftnalt \pard\plain +\s57\ql \li120\ri0\sb80\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super #}{\f1 ShowGameList}}}{\f1 Show Game List +\par }\pard\plain \s26\ql \li120\ri0\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\f1 Shows or hides the list of games generated by the last }{\f1\uldb Load Game}{\v\f1 LoadGame}{ +\f1 command. +\par }\pard\plain \s2\ql \li120\ri0\sb120\sa60\sl-240\slmult0\nowidctlpar\faauto\outlinelevel1\adjustright\rin0\lin120\itap0 \b\f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super K{\footnote\ftnalt \pard\plain +\s57\ql \li120\ri0\sb80\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super K}{\f1 Edit Tags}}#{\footnote\ftnalt \pard\plain \s57\ql \li120\ri0\sb80\sl-240\slmult0 +\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super #}{\f1 EditTags}}}{\f1 Edit Tags +\par }\pard\plain \s26\ql \li120\ri0\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\f1 +Lets you edit the PGN (portable game notation) tags for the current game. After editing, the tags must still conform to the PGN tag syntax: +\par }\pard\plain \s43\ql \li520\ri0\sa60\keep\nowidctlpar\tx520\tx920\tx1320\tx1720\tx2120\faauto\adjustright\rin0\lin520\itap0 \f6\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\f2 \line ::= \line + \line ::= [ ]\line ::= \line ::= +\par }\pard\plain \s20\ql \li120\ri0\sb80\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\f1 See the PGN Standard for full details. Here is an example: +\par }\pard\plain \s43\ql \li520\ri0\sa60\keep\nowidctlpar\tx520\tx920\tx1320\tx1720\tx2120\faauto\adjustright\rin0\lin520\itap0 \f6\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\f2 \line [Event "Portoroz Interzonal"]\line [Site "Portoroz, Yugosl +avia"]\line [Date "1958.08.16"]\line [Round "8"]\line [White "Robert J. Fischer"]\line [Black "Bent Larsen"]\line [Result "1-0"] +\par }\pard\plain \ql \li120\ri0\sb80\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\f1 +Any characters that do not match this syntax are silently ignored. Note that the PGN standard requires all games to have at least the seven tags shown above. Any that you omit will be filled in by WinBoard with }{\f2 "?"}{\f1 (unknown value) or }{\f2 "-" +}{\f1 (inapplicable value). +\par }\pard\plain \s2\ql \li120\ri0\sb120\sa60\sl-240\slmult0\nowidctlpar\faauto\outlinelevel1\adjustright\rin0\lin120\itap0 \b\f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super K{\footnote\ftnalt \pard\plain +\s57\ql \li120\ri0\sb80\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super K}{\f1 Edit Comment}}#{\footnote\ftnalt \pard\plain \s57\ql \li120\ri0\sb80\sl-240\slmult0 +\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super #}{\f1 EditComment}}}{\f1 Edit Comment +\par }\pard\plain \s26\ql \li120\ri0\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\f1 Adds or modifies a comment on the current position. Comments are saved by }{\f1\uldb Save Game} +{\v\f1 SaveGame}{\f1 and are displayed by }{\f1\uldb Load Game}{\v\f1 LoadGame}{\f1 , }{\f1\uldb Forward}{\v\f1 Forward}{\f1 , and }{\f1\uldb Backward}{\v\f1 Backward}{\f1 . +\par }\pard\plain \s2\ql \li120\ri0\sb120\sa60\sl-240\slmult0\nowidctlpar\faauto\outlinelevel1\adjustright\rin0\lin120\itap0 \b\f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super K{\footnote\ftnalt \pard\plain +\s57\ql \li120\ri0\sb80\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super K}{\f1 Pause}}#{\footnote\ftnalt \pard\plain \s57\ql \li120\ri0\sb80\sl-240\slmult0 +\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super #}{\f1 Pause}}}{\f1 Pause +\par }\pard\plain \s26\ql \li120\ri0\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\f1 +Pauses updates to the board, and if you are playing against a local chess engine, also pauses your clock. To continue, select Pause again, and the display will automatically update to the latest position. The }{\b\f1 P}{\f1 (or }{\b\f1 C}{\f1 +) button is equivalent to selecting Pause. +\par }\pard\plain \ql \li120\ri0\sb80\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\f1 If you select Pause when you are playing{\*\bkmkstart WHATSelSavT}{\*\bkmkend WHATSelSavT} +{\*\bkmkstart fWHATtopic}against{\*\bkmkend fWHATtopic} a chess engine and it is not your move, the chess engine\rquote s clock will continue to run and it will eventually make a move, at which point both clocks will sto +p. Since board updates are paused, however, you will not see the move until you exit from Pause mode (or select }{\f1\uldb Forward}{\v\f1 Forward}{\f1 ). This behavior is meant to simulate adjournment with a sealed move. +\par If you select Pause while you are in }{\b\f1 examine}{\f1 mode on ICS, yo +u can step backward and forward in the current history of the examined game without affecting the other examiners or observers. Select Pause again to reconnect yourself to the current state of the game on ICS. +\par If you select Pause while you are loading a game, the game stops loading. You can load more moves one at a time by selecting }{\f1\uldb Forward}{\v\f1 Forward}{\f1 , or resume automatic loading by selecting Pause again. +\par }\pard\plain \s1\ql \li120\ri0\sb280\sa120\sl-320\slmult0\nowidctlpar\faauto\outlinelevel0\adjustright\rin0\lin120\itap0 \b\f5\fs24\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\f1\fs20 \page }{\cs58\f1\fs20\super K{\footnote\ftnalt \pard\plain +\s57\ql \li120\ri0\sb80\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super K}{\f1 Action Menu}}#{\footnote\ftnalt \pard\plain \s57\ql \li120\ri0\sb80\sl-240\slmult0 +\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super #}{\f1 ActionMenu}}${\footnote\ftnalt \pard\plain \s57\ql \li120\ri0\sb80\sl-240\slmult0 +\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super $}{\f1 Action Menu}}+{\footnote\ftnalt \pard\plain \s57\ql \li120\ri0\sb80\sl-240\slmult0 +\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super +}{\f1 main}}}{\f1\fs20 Action Menu +\par }\pard\plain \s26\ql \li120\ri0\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\f1 Most of these commands are available in chess server mode only. +\par }\pard\plain \s2\ql \li120\ri0\sb120\sa60\sl-240\slmult0\nowidctlpar\faauto\outlinelevel1\adjustright\rin0\lin120\itap0 \b\f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super K{\footnote\ftnalt \pard\plain +\s57\ql \li120\ri0\sb80\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super K}{\f1 Accept}}#{\footnote\ftnalt \pard\plain \s57\ql \li120\ri0\sb80\sl-240\slmult0 +\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super #}{\f1 Accept}}}{\f1 Accept +\par }\pard\plain \s26\ql \li120\ri0\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\f1 Accepts a pendi +ng match offer. If there is more than one offer pending, you will have to type in a more specific command instead of using this menu choice. +\par }\pard\plain \s2\ql \li120\ri0\sb120\sa60\sl-240\slmult0\nowidctlpar\faauto\outlinelevel1\adjustright\rin0\lin120\itap0 \b\f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super K{\footnote\ftnalt \pard\plain +\s57\ql \li120\ri0\sb80\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super K}{\f1 Decline}}#{\footnote\ftnalt \pard\plain \s57\ql \li120\ri0\sb80\sl-240\slmult0 +\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super #}{\f1 Decline}}}{\f1 Decline +\par }\pard\plain \s26\ql \li120\ri0\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\f1 +Declines a pending offer (match, draw, etc.). If there is more than one offer pending, you will have to type in a more specific command instead of using this menu choice. +\par }\pard\plain \s2\ql \li120\ri0\sb120\sa60\sl-240\slmult0\nowidctlpar\faauto\outlinelevel1\adjustright\rin0\lin120\itap0 \b\f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super K{\footnote\ftnalt \pard\plain +\s57\ql \li120\ri0\sb80\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super K}{\f1 Rematch}}#{\footnote\ftnalt \pard\plain \s57\ql \li120\ri0\sb80\sl-240\slmult0 +\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super #}{\f1 Rematch}}}{\f1 Rematch +\par }\pard\plain \s26\ql \li120\ri0\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\f1 Issues the ICS }{\b\f1 rematch}{\f1 + command, which asks for another game against your last opponent with the same time control and rule set. +\par }\pard\plain \s2\ql \li120\ri0\sb120\sa60\sl-240\slmult0\nowidctlpar\faauto\outlinelevel1\adjustright\rin0\lin120\itap0 \b\f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super K{\footnote\ftnalt \pard\plain +\s57\ql \li120\ri0\sb80\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super K}{\f1 Call Flag}}#{\footnote\ftnalt \pard\plain \s57\ql \li120\ri0\sb80\sl-240\slmult0 +\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super #}{\f1 CallFlag}}}{\f1 Call Flag +\par }\pard\plain \s26\ql \li120\ri0\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\f1 Calls your opponent's flag, claiming +a win on time, or claiming a draw if you are both out of time. You can also call your opponent's flag by clicking on his clock. +\par }\pard\plain \s2\ql \li120\ri0\sb120\sa60\sl-240\slmult0\nowidctlpar\faauto\outlinelevel1\adjustright\rin0\lin120\itap0 \b\f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super K{\footnote\ftnalt \pard\plain +\s57\ql \li120\ri0\sb80\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super K}{\f1 Draw}}#{\footnote\ftnalt \pard\plain \s57\ql \li120\ri0\sb80\sl-240\slmult0 +\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super #}{\f1 Draw}}}{\f1 Draw +\par }\pard\plain \s26\ql \li120\ri0\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\f1 +Offers a draw to your opponent, accepts a pending draw offer from your opponent, or claims a draw by repetition or the 50-move rule, as appropriate. +\par }\pard\plain \s2\ql \li120\ri0\sb120\sa60\sl-240\slmult0\nowidctlpar\faauto\outlinelevel1\adjustright\rin0\lin120\itap0 \b\f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super K{\footnote\ftnalt \pard\plain +\s57\ql \li120\ri0\sb80\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super K}{\f1 Adjourn}}#{\footnote\ftnalt \pard\plain \s57\ql \li120\ri0\sb80\sl-240\slmult0 +\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super #}{\f1 Adjourn}}}{\f1 Adjourn +\par }\pard\plain \s26\ql \li120\ri0\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\f1 +Asks your opponent to agree to adjourning the current game, or agrees to a pending adjournment offer from your opponent. You continue an adjourned ICS game by challenging the same player again with the ICS }{\b\f1 match}{\f1 command. +\par }\pard\plain \s2\ql \li120\ri0\sb120\sa60\sl-240\slmult0\nowidctlpar\faauto\outlinelevel1\adjustright\rin0\lin120\itap0 \b\f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super K{\footnote\ftnalt \pard\plain +\s57\ql \li120\ri0\sb80\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super K}{\f1 Abort}}#{\footnote\ftnalt \pard\plain \s57\ql \li120\ri0\sb80\sl-240\slmult0 +\nowidctlpar\faauto\adjustright\rin0\lin120\itap0 \f5\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\cs58\f1\super #}{\f1 Abort}}}{\f1 Abort +\par }\pard\plain \s26\ql \li120\ri0\sl-240\slmult0\nowidctlpar\faauto\ad