Increase max nr of engines to 2000
[xboard.git] / backend.c
index afb379b..e6f48a4 100644 (file)
--- a/backend.c
+++ b/backend.c
@@ -5,7 +5,7 @@
  * Massachusetts.
  *
  * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006,
- * 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
+ * 2007, 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
  *
  * Enhancements Copyright 2005 Alessandro Scotti
  *
@@ -55,8 +55,6 @@
 #ifdef WIN32
 #include <windows.h>
 
-#define DoSleep( n ) if( (n) != 0 ) Sleep( (n) );
-
 int flock(int f, int code);
 #define LOCK_EX 2
 #define SLASH '\\'
@@ -64,7 +62,6 @@ int flock(int f, int code);
 #else
 
 #include <sys/file.h>
-#define DoSleep( n ) if( (n) >= 0) sleep(n)
 #define SLASH '/'
 
 #endif
@@ -150,12 +147,6 @@ extern int gettimeofday(struct timeval *, struct timezone *);
 #endif
 
 
-/* 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));
@@ -171,8 +162,6 @@ 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));
 int FinishMove P((ChessMove moveType, int fromX, int fromY, int toX, int toY,
@@ -207,7 +196,6 @@ 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));
@@ -216,8 +204,6 @@ void CopyPlayerNameIntoFileName P((char **, char *));
 char *SavePart P((char *));
 int SaveGameOldStyle P((FILE *));
 int SaveGamePGN P((FILE *));
-void GetTimeMark P((TimeMark *));
-long SubtractTimeMarks P((TimeMark *, TimeMark *));
 int CheckFlags P((void));
 long NextTickLength P((long));
 void CheckTimeControl P((void));
@@ -234,7 +220,7 @@ void InitDrawingSizes(int x, int y);
 void NextMatchGame P((void));
 int NextTourneyGame P((int nr, int *swap));
 int Pairing P((int nr, int nPlayers, int *w, int *b, int *sync));
-FILE *WriteTourneyFile P((char *results));
+FILE *WriteTourneyFile P((char *results, FILE *f));
 void DisplayTwoMachinesTitle P(());
 
 #ifdef WIN32
@@ -326,7 +312,7 @@ int promoDefaultAltered;
 #define TN_PORT 23
 
 char*
-safeStrCpy( char *dst, const char *src, size_t count )
+safeStrCpy (char *dst, const char *src, size_t count)
 { // [HGM] made safe
   int i;
   assert( dst != NULL );
@@ -354,7 +340,7 @@ safeStrCpy( char *dst, const char *src, size_t count )
  * We used this for all compiler
  */
 double
-u64ToDouble(u64 value)
+u64ToDouble (u64 value)
 {
   double r;
   u64 tmp = value & u64Const(0x7fffffffffffffff);
@@ -372,7 +358,7 @@ u64ToDouble(u64 value)
    by this function.
  */
 int
-PosFlags(index)
+PosFlags (index)
 {
   int flags = F_ALL_CASTLE_OK;
   if ((index % 2) == 0) flags |= F_WHITE_ON_MOVE;
@@ -468,6 +454,7 @@ int have_sent_ICS_logon = 0;
 int movesPerSession;
 int suddenDeath, whiteStartMove, blackStartMove; /* [HGM] for implementation of 'any per time' sessions, as in first part of byoyomi TC */
 long whiteTimeRemaining, blackTimeRemaining, timeControl, timeIncrement, lastWhite, lastBlack;
+Boolean adjustedClock;
 long timeControl_2; /* [AS] Allow separate time controls */
 char *fullTimeControlString = NULL, *nextSession, *whiteTC, *blackTC; /* [HGM] secondary TC: merge of MPS, TC and inc */
 long timeRemaining[2][MAX_MOVES];
@@ -621,10 +608,10 @@ ChessSquare GothicArray[2][BOARD_FILES] = {
 
 #ifdef FALCON
 ChessSquare FalconArray[2][BOARD_FILES] = {
-    { WhiteRook, WhiteKnight, WhiteBishop, WhiteLance, WhiteQueen,
-        WhiteKing, WhiteLance, WhiteBishop, WhiteKnight, WhiteRook },
-    { BlackRook, BlackKnight, BlackBishop, BlackLance, BlackQueen,
-        BlackKing, BlackLance, BlackBishop, BlackKnight, BlackRook }
+    { WhiteRook, WhiteKnight, WhiteBishop, WhiteFalcon, WhiteQueen,
+        WhiteKing, WhiteFalcon, WhiteBishop, WhiteKnight, WhiteRook },
+    { BlackRook, BlackKnight, BlackBishop, BlackFalcon, BlackQueen,
+        BlackKing, BlackFalcon, BlackBishop, BlackKnight, BlackRook }
 };
 #else // !FALCON
 #define FalconArray CapablancaArray
@@ -656,8 +643,7 @@ Board initialPosition;
 
    "++++", etc. Also strips ()'s */
 int
-string_to_rating(str)
-  char *str;
+string_to_rating (char *str)
 {
   while(*str && !isdigit(*str)) ++str;
   if (!*str)
@@ -667,7 +653,7 @@ string_to_rating(str)
 }
 
 void
-ClearProgramStats()
+ClearProgramStats ()
 {
     /* Init programStats */
     programStats.movelist[0] = 0;
@@ -683,7 +669,7 @@ ClearProgramStats()
 }
 
 void
-CommonEngineInit()
+CommonEngineInit ()
 {   // [HGM] moved some code here from InitBackend1 that has to be done after both engines have contributed their settings
     if (appData.firstPlaysBlack) {
        first.twoMachinesColor = "black\n";
@@ -717,7 +703,7 @@ CommonEngineInit()
 }
 
 void
-UnloadEngine(ChessProgramState *cps)
+UnloadEngine (ChessProgramState *cps)
 {
        /* Kill off first chess program */
        if (cps->isr != NULL)
@@ -736,7 +722,7 @@ UnloadEngine(ChessProgramState *cps)
 }
 
 void
-ClearOptions(ChessProgramState *cps)
+ClearOptions (ChessProgramState *cps)
 {
     int i;
     cps->nrOptions = cps->comboCnt = 0;
@@ -752,7 +738,7 @@ char *engineNames[] = {
 };
 
 void
-InitEngine(ChessProgramState *cps, int n)
+InitEngine (ChessProgramState *cps, int n)
 {   // [HGM] all engine initialiation put in a function that does one engine
 
     ClearOptions(cps);
@@ -828,7 +814,7 @@ InitEngine(ChessProgramState *cps, int n)
 
        len = snprintf(buf, MSG_SIZ, _("protocol version %d not supported"),
                       appData.protocolVersion[n]);
-       if( (len > MSG_SIZ) && appData.debugMode )
+       if( (len >= MSG_SIZ) && appData.debugMode )
          fprintf(debugFP, "InitBackEnd1: buffer truncated.\n");
 
        DisplayFatalError(buf, 0, 2);
@@ -839,12 +825,13 @@ InitEngine(ChessProgramState *cps, int n)
       }
 
     InitEngineUCI( installDir, cps );  // [HGM] moved here from winboard.c, to make available in xboard
+    ParseFeatures(appData.featureDefaults, cps);
 }
 
 ChessProgramState *savCps;
 
 void
-LoadEngine()
+LoadEngine ()
 {
     int i;
     if(WaitForEngine(savCps, LoadEngine)) return;
@@ -864,7 +851,7 @@ LoadEngine()
 }
 
 void
-ReplaceEngine(ChessProgramState *cps, int n)
+ReplaceEngine (ChessProgramState *cps, int n)
 {
     EditGameEvent();
     UnloadEngine(cps);
@@ -882,16 +869,18 @@ extern Boolean isUCI, hasBook, storeVariant, v1, addToList, useNick;
 
 static char resetOptions[] = 
        "-reuse -firstIsUCI false -firstHasOwnBookUCI true -firstTimeOdds 1 "
+       "-firstInitString \"" INIT_STRING "\" -firstComputerString \"" COMPUTER_STRING "\" "
        "-firstOptions \"\" -firstNPS -1 -fn \"\"";
 
 void
-Load(ChessProgramState *cps, int i)
+Load (ChessProgramState *cps, int i)
 {
     char *p, *q, buf[MSG_SIZ], command[MSG_SIZ], buf2[MSG_SIZ];
-    if(engineLine[0]) { // an engine was selected from the combo box
+    if(engineLine && engineLine[0]) { // an engine was selected from the combo box
        snprintf(buf, MSG_SIZ, "-fcp %s", engineLine);
        SwapEngines(i); // kludge to parse -f* / -first* like it is -s* / -second*
-       ParseArgsFromString(resetOptions); appData.fenOverride[0] = NULL;
+       ParseArgsFromString(resetOptions); appData.fenOverride[0] = NULL; appData.pvSAN[0] = FALSE;
+       appData.firstProtocolVersion = PROTOVER;
        ParseArgsFromString(buf);
        SwapEngines(i);
        ReplaceEngine(cps, i);
@@ -907,8 +896,8 @@ Load(ChessProgramState *cps, int i)
        appData.directory[i] = strdup(engineName);
        p[-1] = SLASH;
     } else appData.directory[i] = ".";
-    if(strchr(p, ' ') && !strchr(p, '"')) snprintf(buf2, MSG_SIZ, "\"%s\"", p), p = buf2; // quote if it contains spaces
     if(params[0]) {
+       if(strchr(p, ' ') && !strchr(p, '"')) snprintf(buf2, MSG_SIZ, "\"%s\"", p), p = buf2; // quote if it contains spaces
        snprintf(command, MSG_SIZ, "%s %s", p, params);
        p = command;
     }
@@ -942,7 +931,7 @@ Load(ChessProgramState *cps, int i)
 }
 
 void
-InitTimeControls()
+InitTimeControls ()
 {
     int matched, min, sec;
     /*
@@ -973,7 +962,7 @@ InitTimeControls()
 }
 
 void
-InitBackEnd1()
+InitBackEnd1 ()
 {
 
     ShowThinkingEvent(); // [HGM] thinking: make sure post/nopost state is set according to options
@@ -981,6 +970,7 @@ InitBackEnd1()
 
     GetTimeMark(&programStartTime);
     srandom((programStartTime.ms + 1000*programStartTime.sec)*0x1001001); // [HGM] book: makes sure random is unpredictabe to msec level
+    appData.seedBase = random() + (random()<<15);
     pauseStart = programStartTime; pauseStart.sec -= 100; // [HGM] matchpause: fake a pause that has long since ended
 
     ClearProgramStats();
@@ -1072,7 +1062,7 @@ InitBackEnd1()
       case VariantKriegspiel:   /* need to hide pieces and move details */
        /* case VariantFischeRandom: (Fabien: moved below) */
        len = snprintf(buf,MSG_SIZ, _("Variant %s supported only in ICS mode"), appData.variant);
-       if( (len > MSG_SIZ) && appData.debugMode )
+       if( (len >= MSG_SIZ) && appData.debugMode )
          fprintf(debugFP, "InitBackEnd1: buffer truncated.\n");
 
        DisplayFatalError(buf, 0, 2);
@@ -1090,7 +1080,7 @@ InitBackEnd1()
       case Variant36:
       default:
        len = snprintf(buf, MSG_SIZ, _("Unknown variant name %s"), appData.variant);
-       if( (len > MSG_SIZ) && appData.debugMode )
+       if( (len >= MSG_SIZ) && appData.debugMode )
          fprintf(debugFP, "InitBackEnd1: buffer truncated.\n");
 
        DisplayFatalError(buf, 0, 2);
@@ -1136,7 +1126,8 @@ InitBackEnd1()
 
 }
 
-int NextIntegerFromString( char ** str, long * value )
+int
+NextIntegerFromString (char ** str, long * value)
 {
     int result = -1;
     char * s = *str;
@@ -1161,7 +1152,8 @@ int NextIntegerFromString( char ** str, long * value )
     return result;
 }
 
-int NextTimeControlFromString( char ** str, long * value )
+int
+NextTimeControlFromString (char ** str, long * value)
 {
     long temp;
     int result = NextIntegerFromString( str, &temp );
@@ -1178,7 +1170,8 @@ int NextTimeControlFromString( char ** str, long * value )
     return result;
 }
 
-int NextSessionFromString( char ** str, int *moves, long * tc, long *inc, int *incType)
+int
+NextSessionFromString (char ** str, int *moves, long * tc, long *inc, int *incType)
 {   /* [HGM] routine added to read '+moves/time' for secondary time control. */
     int result = -1, type = 0; long temp, temp2;
 
@@ -1219,7 +1212,8 @@ int NextSessionFromString( char ** str, int *moves, long * tc, long *inc, int *i
     return result;
 }
 
-int GetTimeQuota(int movenr, int lastUsed, char *tcString)
+int
+GetTimeQuota (int movenr, int lastUsed, char *tcString)
 {   /* [HGM] get time to add from the multi-session time-control string */
     int incType, moves=1; /* kludge to force reading of first session */
     long time, increment;
@@ -1242,10 +1236,7 @@ int GetTimeQuota(int movenr, int lastUsed, char *tcString)
 }
 
 int
-ParseTimeControl(tc, ti, mps)
-     char *tc;
-     float ti;
-     int mps;
+ParseTimeControl (char *tc, float ti, int mps)
 {
   long tc1;
   long tc2;
@@ -1308,7 +1299,7 @@ ParseTimeControl(tc, ti, mps)
 }
 
 void
-InitBackEnd2()
+InitBackEnd2 ()
 {
     if (appData.debugMode) {
        fprintf(debugFP, "%s\n", programVersion);
@@ -1338,7 +1329,7 @@ InitBackEnd2()
 }
 
 int
-CalculateIndex(int index, int gameNr)
+CalculateIndex (int index, int gameNr)
 {   // [HGM] autoinc: absolute way to determine load index from game number (taking auto-inc and rewind into account)
     int res;
     if(index > 0) return index; // fixed nmber
@@ -1349,7 +1340,7 @@ CalculateIndex(int index, int gameNr)
 }
 
 int
-LoadGameOrPosition(int gameNr)
+LoadGameOrPosition (int gameNr)
 {   // [HGM] taken out of MatchEvent and NextMatchGame (to combine it)
     if (*appData.loadGameFile != NULLCHAR) {
        if (!LoadGameFromFile(appData.loadGameFile,
@@ -1370,7 +1361,7 @@ LoadGameOrPosition(int gameNr)
 }
 
 void
-ReserveGame(int gameNr, char resChar)
+ReserveGame (int gameNr, char resChar)
 {
     FILE *tf = fopen(appData.tourneyFile, "r+");
     char *p, *q, c, buf[MSG_SIZ];
@@ -1406,13 +1397,17 @@ ReserveGame(int gameNr, char resChar)
     free(p); appData.results = q;
     if(nextGame <= appData.matchGames && resChar != ' ' && !abortMatch &&
        (gameNr < 0 || nextGame / appData.defaultMatchGames != gameNr / appData.defaultMatchGames)) {
+      int round = appData.defaultMatchGames * appData.tourneyType;
+      if(gameNr < 0 || appData.tourneyType < 1 ||  // gauntlet engine can always stay loaded as first engine
+        appData.tourneyType > 1 && nextGame/round != gameNr/round) // in multi-gauntlet change only after round
        UnloadEngine(&first);  // next game belongs to other pairing;
        UnloadEngine(&second); // already unload the engines, so TwoMachinesEvent will load new ones.
     }
+    if(appData.debugMode) fprintf(debugFP, "Reserved, next=%d, nr=%d, procs=(%x,%x)\n", nextGame, gameNr, first.pr, second.pr);
 }
 
 void
-MatchEvent(int mode)
+MatchEvent (int mode)
 {      // [HGM] moved out of InitBackend3, to make it callable when match starts through menu
        int dummy;
        if(matchMode) { // already in match mode: switch it off
@@ -1436,7 +1431,7 @@ MatchEvent(int mode)
                if(strchr(appData.results, '*') == NULL) {
                    FILE *f;
                    appData.tourneyCycles++;
-                   if(f = WriteTourneyFile(appData.results)) { // make a tourney file with increased number of cycles
+                   if(f = WriteTourneyFile(appData.results, NULL)) { // make a tourney file with increased number of cycles
                        fclose(f);
                        NextTourneyGame(-1, &dummy);
                        ReserveGame(-1, 0);
@@ -1495,7 +1490,7 @@ InitBackEnd3 P((void))
              len = snprintf(buf, MSG_SIZ, _("Could not connect to host %s, port %s"),
                        appData.icsHost, appData.icsPort);
 
-           if( (len > MSG_SIZ) && appData.debugMode )
+           if( (len >= MSG_SIZ) && appData.debugMode )
              fprintf(debugFP, "InitBackEnd3: buffer truncated.\n");
 
            DisplayFatalError(buf, err, 1);
@@ -1549,7 +1544,7 @@ InitBackEnd3 P((void))
       initialMode = Training;
     } else {
       len = snprintf(buf, MSG_SIZ, _("Unknown initialMode %s"), appData.initialMode);
-      if( (len > MSG_SIZ) && appData.debugMode )
+      if( (len >= MSG_SIZ) && appData.debugMode )
        fprintf(debugFP, "InitBackEnd3: buffer truncated.\n");
 
       DisplayFatalError(buf, 0, 2);
@@ -1664,6 +1659,18 @@ InitBackEnd3 P((void))
     }
 }
 
+void
+HistorySet (char movelist[][2*MOVE_LEN], int first, int last, int current)
+{
+    DisplayBook(current+1);
+
+    MoveHistorySet( movelist, first, last, current, pvInfoList );
+
+    EvalGraphSet( first, last, current, pvInfoList );
+
+    MakeEngineOutputTitle();
+}
+
 /*
  * Establish will establish a contact to a remote host.port.
  * Sets icsPR to a ProcRef for a process (or pseudo-process)
@@ -1671,7 +1678,7 @@ InitBackEnd3 P((void))
  * Returns 0 if okay, error code if not.
  */
 int
-establish()
+establish ()
 {
     char buf[MSG_SIZ];
 
@@ -1712,7 +1719,8 @@ establish()
     }
 }
 
-void EscapeExpand(char *p, char *q)
+void
+EscapeExpand (char *p, char *q)
 {      // [HGM] initstring: routine to shape up string arguments
        while(*p++ = *q++) if(p[-1] == '\\')
            switch(*q++) {
@@ -1726,10 +1734,7 @@ void EscapeExpand(char *p, char *q)
 }
 
 void
-show_bytes(fp, buf, count)
-     FILE *fp;
-     char *buf;
-     int count;
+show_bytes (FILE *fp, char *buf, int count)
 {
     while (count--) {
        if (*buf < 040 || *(unsigned char *) buf > 0177) {
@@ -1744,11 +1749,7 @@ show_bytes(fp, buf, count)
 
 /* Returns an errno value */
 int
-OutputMaybeTelnet(pr, message, count, outError)
-     ProcRef pr;
-     char *message;
-     int count;
-     int *outError;
+OutputMaybeTelnet (ProcRef pr, char *message, int count, int *outError)
 {
     char buf[8192], *p, *q, *buflim;
     int left, newcount, outcount;
@@ -1802,12 +1803,7 @@ OutputMaybeTelnet(pr, message, count, outError)
 }
 
 void
-read_from_player(isr, closure, message, count, error)
-     InputSourceRef isr;
-     VOIDSTAR closure;
-     char *message;
-     int count;
-     int error;
+read_from_player (InputSourceRef isr, VOIDSTAR closure, char *message, int count, int error)
 {
     int outError, outCount;
     static int gotEof = 0;
@@ -1829,7 +1825,7 @@ read_from_player(isr, closure, message, count, error)
 }
 
 void
-KeepAlive()
+KeepAlive ()
 {   // [HGM] alive: periodically send dummy (date) command to ICS to prevent time-out
     if(!connectionAlive) DisplayFatalError("No response from ICS", 0, 1);
     connectionAlive = FALSE; // only sticks if no response to 'date' command.
@@ -1838,7 +1834,8 @@ KeepAlive()
 }
 
 /* added routine for printf style output to ics */
-void ics_printf(char *format, ...)
+void
+ics_printf (char *format, ...)
 {
     char buffer[MSG_SIZ];
     va_list args;
@@ -1851,12 +1848,11 @@ void ics_printf(char *format, ...)
 }
 
 void
-SendToICS(s)
-     char *s;
+SendToICS (char *s)
 {
     int count, outCount, outError;
 
-    if (icsPR == NULL) return;
+    if (icsPR == NoProc) return;
 
     count = strlen(s);
     outCount = OutputMaybeTelnet(icsPR, s, count, &outError);
@@ -1869,13 +1865,11 @@ SendToICS(s)
    without a delay causes problems when using timestamp on ICC
    (at least on my machine). */
 void
-SendToICSDelayed(s,msdelay)
-     char *s;
-     long msdelay;
+SendToICSDelayed (char *s, long msdelay)
 {
     int count, outCount, outError;
 
-    if (icsPR == NULL) return;
+    if (icsPR == NoProc) return;
 
     count = strlen(s);
     if (appData.debugMode) {
@@ -1895,8 +1889,7 @@ SendToICSDelayed(s,msdelay)
    Also deletes any suffix starting with '('
    */
 char *
-StripHighlightAndTitle(s)
-     char *s;
+StripHighlightAndTitle (char *s)
 {
     static char retbuf[MSG_SIZ];
     char *p = retbuf;
@@ -1920,8 +1913,7 @@ StripHighlightAndTitle(s)
 
 /* Remove all highlighting escape sequences in s */
 char *
-StripHighlight(s)
-     char *s;
+StripHighlight (char *s)
 {
     static char retbuf[MSG_SIZ];
     char *p = retbuf;
@@ -1941,8 +1933,7 @@ StripHighlight(s)
 
 char *variantNames[] = VARIANT_NAMES;
 char *
-VariantName(v)
-     VariantClass v;
+VariantName (VariantClass v)
 {
     return variantNames[v];
 }
@@ -1951,8 +1942,7 @@ VariantName(v)
 /* Identify a variant from the strings the chess servers use or the
    PGN Variant tag names we use. */
 VariantClass
-StringToVariant(e)
-     char *e;
+StringToVariant (char *e)
 {
     char *p;
     int wnum = -1;
@@ -2136,7 +2126,7 @@ StringToVariant(e)
          break;
        default:
          len = snprintf(buf, MSG_SIZ, _("Unknown wild type %d"), wnum);
-         if( (len > MSG_SIZ) && appData.debugMode )
+         if( (len >= MSG_SIZ) && appData.debugMode )
            fprintf(debugFP, "StringToVariant: buffer truncated.\n");
 
          DisplayError(buf, 0);
@@ -2163,10 +2153,7 @@ char star_match[STAR_MATCH_N][MSG_SIZ];
    copied into star_match.
    */
 int
-looking_at(buf, index, pattern)
-     char *buf;
-     int *index;
-     char *pattern;
+looking_at ( char *buf, int *index, char *pattern)
 {
     char *bufp = &buf[*index], *patternp = pattern;
     int star_count = 0;
@@ -2204,9 +2191,7 @@ looking_at(buf, index, pattern)
 }
 
 void
-SendToPlayer(data, length)
-     char *data;
-     int length;
+SendToPlayer (char *data, int length)
 {
     int error, outCount;
     outCount = OutputToProcess(NoProc, data, length, &error);
@@ -2216,9 +2201,7 @@ SendToPlayer(data, length)
 }
 
 void
-PackHolding(packed, holding)
-     char packed[];
-     char *holding;
+PackHolding (char packed[], char *holding)
 {
     char *p = holding;
     char *q = packed;
@@ -2253,8 +2236,7 @@ PackHolding(packed, holding)
 
 /* Telnet protocol requests from the front end */
 void
-TelnetRequest(ddww, option)
-     unsigned char ddww, option;
+TelnetRequest (unsigned char ddww, unsigned char option)
 {
     unsigned char msg[3];
     int outCount, outError;
@@ -2302,21 +2284,21 @@ TelnetRequest(ddww, option)
 }
 
 void
-DoEcho()
+DoEcho ()
 {
     if (!appData.icsActive) return;
     TelnetRequest(TN_DO, TN_ECHO);
 }
 
 void
-DontEcho()
+DontEcho ()
 {
     if (!appData.icsActive) return;
     TelnetRequest(TN_DONT, TN_ECHO);
 }
 
 void
-CopyHoldings(Board board, char *holdings, ChessSquare lowestPiece)
+CopyHoldings (Board board, char *holdings, ChessSquare lowestPiece)
 {
     /* put the holdings sent to us by the server on the board holdings area */
     int i, j, holdingsColumn, holdingsStartRow, direction, countsColumn;
@@ -2358,7 +2340,7 @@ CopyHoldings(Board board, char *holdings, ChessSquare lowestPiece)
 
 
 void
-VariantSwitch(Board board, VariantClass newVariant)
+VariantSwitch (Board board, VariantClass newVariant)
 {
    int newHoldingsWidth, newWidth = 8, newHeight = 8, i, j;
    static Board oldBoard;
@@ -2469,7 +2451,7 @@ int hMargin = 10, vMargin = 20, h, w;
 extern int squareSize, lineGap;
 
 void
-PlotSeekAd(int i)
+PlotSeekAd (int i)
 {
        int x, y, color = 0, r = ratingList[i]; float tc = tcList[i];
        xList[i] = yList[i] = -100; // outside graph, so cannot be clicked
@@ -2491,7 +2473,7 @@ PlotSeekAd(int i)
 }
 
 void
-AddAd(char *handle, char *rating, int base, int inc,  char rated, char *type, int nr, Boolean plot)
+AddAd (char *handle, char *rating, int base, int inc,  char rated, char *type, int nr, Boolean plot)
 {
        char buf[MSG_SIZ], *ext = "";
        VariantClass v = StringToVariant(type);
@@ -2515,7 +2497,7 @@ AddAd(char *handle, char *rating, int base, int inc,  char rated, char *type, in
 }
 
 void
-EraseSeekDot(int i)
+EraseSeekDot (int i)
 {
     int x = xList[i], y = yList[i], d=squareSize/4, k;
     DrawSeekBackground(x-squareSize/8, y-squareSize/8, x+squareSize/8+1, y+squareSize/8+1);
@@ -2529,7 +2511,7 @@ EraseSeekDot(int i)
 }
 
 void
-RemoveSeekAd(int nr)
+RemoveSeekAd (int nr)
 {
        int i;
        for(i=0; i<nrOfSeekAds; i++) if(seekNrList[i] == nr) {
@@ -2549,7 +2531,7 @@ RemoveSeekAd(int nr)
 }
 
 Boolean
-MatchSoughtLine(char *line)
+MatchSoughtLine (char *line)
 {
     char handle[MSG_SIZ], rating[MSG_SIZ], type[MSG_SIZ];
     int nr, base, inc, u=0; char dummy;
@@ -2567,7 +2549,7 @@ MatchSoughtLine(char *line)
 }
 
 int
-DrawSeekGraph()
+DrawSeekGraph ()
 {
     int i;
     if(!seekGraphUp) return FALSE;
@@ -2601,9 +2583,11 @@ DrawSeekGraph()
     return TRUE;
 }
 
-int SeekGraphClick(ClickType click, int x, int y, int moving)
+int
+SeekGraphClick (ClickType click, int x, int y, int moving)
 {
     static int lastDown = 0, displayed = 0, lastSecond;
+    if(y < 0) return FALSE;
     if(!seekGraphUp) { // initiate cration of seek graph by requesting seek-ad list
        if(click == Release || moving) return FALSE;
        nrOfSeekAds = 0;
@@ -2653,12 +2637,7 @@ int SeekGraphClick(ClickType click, int x, int y, int moving)
 }
 
 void
-read_from_ics(isr, closure, data, count, error)
-     InputSourceRef isr;
-     VOIDSTAR closure;
-     char *data;
-     int count;
-     int error;
+read_from_ics (InputSourceRef isr, VOIDSTAR closure, char *data, int count, int error)
 {
 #define BUF_SIZE (16*1024) /* overflowed at 8K with "inchannel 1" on FICS? */
 #define STARTED_NONE 0
@@ -2956,6 +2935,9 @@ read_from_ics(isr, closure, data, count, error)
                            OutputKibitz(suppressKibitz, parse);
                        } else {
                            char tmp[MSG_SIZ];
+                           if(gameMode == IcsObserving) // restore original ICS messages
+                             snprintf(tmp, MSG_SIZ, "%s kibitzes: %s", star_match[0], parse);
+                           else
                            snprintf(tmp, MSG_SIZ, _("your opponent kibitzes: %s"), parse);
                            SendToPlayer(tmp, strlen(tmp));
                        }
@@ -3089,7 +3071,8 @@ read_from_ics(isr, closure, data, count, error)
            if (appData.autoKibitz && started == STARTED_NONE &&
                 !appData.icsEngineAnalyze &&                     // [HGM] [DM] ICS analyze
                (gameMode == IcsPlayingWhite || gameMode == IcsPlayingBlack || gameMode == IcsObserving)) {
-               if((looking_at(buf, &i, "* kibitzes: ") || looking_at(buf, &i, "* whispers: ")) &&
+               if((looking_at(buf, &i, "\n* kibitzes: ") || looking_at(buf, &i, "\n* whispers: ") ||
+                   looking_at(buf, &i, "* kibitzes: ") || looking_at(buf, &i, "* whispers: ")) &&
                   (StrStr(star_match[0], gameInfo.white) == star_match[0] ||
                    StrStr(star_match[0], gameInfo.black) == star_match[0]   )) { // kibitz of self or opponent
                        suppressKibitz = TRUE;
@@ -3124,6 +3107,8 @@ read_from_ics(isr, closure, data, count, error)
                }
            } // [HGM] kibitz: end of patch
 
+           if(looking_at(buf, &i, "* rating adjustment: * --> *\n")) continue;
+
            // [HGM] chat: intercept tells by users for which we have an open chat window
            channel = -1;
            if(started == STARTED_NONE && (looking_at(buf, &i, "* tells you:") || looking_at(buf, &i, "* says:") ||
@@ -3549,7 +3534,7 @@ read_from_ics(isr, closure, data, count, error)
            if (looking_at(buf, &i, "% ") ||
                ((started == STARTED_MOVES || started == STARTED_MOVES_NOHIDE)
                 && looking_at(buf, &i, "}*"))) { char *bookHit = NULL; // [HGM] book
-               if(ics_type == ICS_ICC && soughtPending) { // [HGM] seekgraph: on ICC sought-list has no termination line
+               if(soughtPending) { // [HGM] seekgraph: on ICC sought-list has no termination line
                    soughtPending = FALSE;
                    seekGraphUp = TRUE;
                    DrawSeekGraph();
@@ -3626,8 +3611,8 @@ read_from_ics(isr, closure, data, count, error)
                        flipView = appData.flipView;
                        DrawPosition(TRUE, boards[currentMove]);
                        DisplayBothClocks();
-                       snprintf(str, MSG_SIZ, "%s vs. %s",
-                               gameInfo.white, gameInfo.black);
+                       snprintf(str, MSG_SIZ, "%s %s %s",
+                               gameInfo.white, _("vs."),  gameInfo.black);
                        DisplayTitle(str);
                        gameMode = IcsIdle;
                    } else {
@@ -3853,6 +3838,7 @@ read_from_ics(isr, closure, data, count, error)
                    strncmp(why, "Continuing ", 11) == 0) {
                    gs_gamenum = gamenum;
                    safeStrCpy(gs_kind, strchr(why, ' ') + 1,sizeof(gs_kind)/sizeof(gs_kind[0]));
+                   if(ics_gamenum == -1) // [HGM] only if we are not already involved in a game (because gin=1 sends us such messages)
                    VariantSwitch(boards[currentMove], StringToVariant(gs_kind)); // [HGM] variantswitch: even before we get first board
 #if ZIPPY
                    if (appData.zippyPlay) {
@@ -3888,7 +3874,7 @@ read_from_ics(isr, closure, data, count, error)
 #if ZIPPY
                if (appData.zippyPlay && first.initDone) {
                    ZippyGameEnd(endtype, why);
-                   if (first.pr == NULL) {
+                   if (first.pr == NoProc) {
                      /* Start the next process early so that we'll
                         be ready for the next challenge */
                      StartChessProgram(&first);
@@ -4040,11 +4026,11 @@ read_from_ics(isr, closure, data, count, error)
                            char wh[16], bh[16];
                            PackHolding(wh, white_holding);
                            PackHolding(bh, black_holding);
-                           snprintf(str, MSG_SIZ,"[%s-%s] %s-%s", wh, bh,
+                           snprintf(str, MSG_SIZ, "[%s-%s] %s-%s", wh, bh,
                                    gameInfo.white, gameInfo.black);
                        } else {
-                         snprintf(str, MSG_SIZ, "%s [%s] vs. %s [%s]",
-                                   gameInfo.white, white_holding,
+                         snprintf(str, MSG_SIZ, "%s [%s] %s %s [%s]",
+                                   gameInfo.white, white_holding, _("vs."),
                                    gameInfo.black, black_holding);
                        }
                        if(!partnerUp) // [HGM] bughouse: when peeking at partner game we already know what he captured...
@@ -4120,8 +4106,7 @@ read_from_ics(isr, closure, data, count, error)
 #define RELATION_STARTING_POSITION  -4   /* FICS only */
 
 void
-ParseBoard12(string)
-     char *string;
+ParseBoard12 (char *string)
 {
     GameMode newGameMode;
     int gamenum, newGame, newMove, relation, basetime, increment, ics_flip = 0, i;
@@ -4428,6 +4413,13 @@ ParseBoard12(string)
            board[k][1] = board[k][BOARD_WIDTH-2] = (ChessSquare) 0;;
       }
     }
+    if(moveNum==0 && gameInfo.variant == VariantSChess) {
+      board[5][BOARD_RGHT+1] = WhiteAngel;
+      board[6][BOARD_RGHT+1] = WhiteMarshall;
+      board[1][0] = BlackMarshall;
+      board[2][0] = BlackAngel;
+      board[1][1] = board[2][1] = board[5][BOARD_RGHT] = board[6][BOARD_RGHT] = 1;
+    }
     CopyBoard(boards[moveNum], board);
     boards[moveNum][HOLDINGS_SET] = 0; // [HGM] indicate holdings not set
     if (moveNum == 0) {
@@ -4463,6 +4455,7 @@ ParseBoard12(string)
             if(board[BOARD_HEIGHT-1][i] == BlackRook) j = i;
         initialRights[4] = boards[moveNum][CASTLING][4] = (castle_bl == 0 && gameInfo.variant != VariantFischeRandom ? NoRights : j);
 
+       boards[moveNum][CASTLING][2] = boards[moveNum][CASTLING][5] = NoRights;
        if(gameInfo.variant == VariantKnightmate) { wKing = WhiteUnicorn; bKing = BlackUnicorn; }
         for(k=BOARD_LEFT; k<BOARD_RGHT; k++)
             if(board[0][k] == wKing) initialRights[2] = boards[moveNum][CASTLING][2] = k;
@@ -4652,7 +4645,7 @@ ParseBoard12(string)
            strcat(moveList[moveNum - 1], "\n");
 
             if(gameInfo.holdingsWidth && !appData.disguise && gameInfo.variant != VariantSuper && gameInfo.variant != VariantGreat
-                                 && gameInfo.variant != VariantGrand) // inherit info that ICS does not give from previous board
+               && gameInfo.variant != VariantGrand&& gameInfo.variant != VariantSChess) // inherit info that ICS does not give from previous board
               for(k=0; k<ranks; k++) for(j=BOARD_LEFT; j<BOARD_RGHT; j++) {
                 ChessSquare old, new = boards[moveNum][k][j];
                   if(fromY == DROP_RANK && k==toY && j==toX) continue; // dropped pieces always stand for themselves
@@ -4767,12 +4760,12 @@ ParseBoard12(string)
                    basetime, increment, (int) gameInfo.variant);
        } else {
            if(gameInfo.variant == VariantNormal)
-             snprintf(str, MSG_SIZ, "%s (%d) vs. %s (%d) {%d %d}",
-                   gameInfo.white, white_stren, gameInfo.black, black_stren,
+             snprintf(str, MSG_SIZ, "%s (%d) %s %s (%d) {%d %d}",
+                   gameInfo.white, white_stren, _("vs."), gameInfo.black, black_stren,
                    basetime, increment);
            else
-             snprintf(str, MSG_SIZ, "%s (%d) vs. %s (%d) {%d %d %s}",
-                   gameInfo.white, white_stren, gameInfo.black, black_stren,
+             snprintf(str, MSG_SIZ, "%s (%d) %s %s (%d) {%d %d %s}",
+                   gameInfo.white, white_stren, _("vs."), gameInfo.black, black_stren,
                    basetime, increment, VariantName(gameInfo.variant));
        }
        DisplayTitle(str);
@@ -4820,7 +4813,7 @@ ParseBoard12(string)
 }
 
 void
-GetMoveListEvent()
+GetMoveListEvent ()
 {
     char buf[MSG_SIZ];
     if (appData.icsActive && gameMode != IcsIdle && ics_gamenum > 0) {
@@ -4831,8 +4824,7 @@ GetMoveListEvent()
 }
 
 void
-AnalysisPeriodicEvent(force)
-     int force;
+AnalysisPeriodicEvent (int force)
 {
     if (((programStats.ok_to_send == 0 || programStats.line_is_book)
         && !force) || !appData.periodicUpdates)
@@ -4848,16 +4840,14 @@ AnalysisPeriodicEvent(force)
     programStats.ok_to_send = 0;
 }
 
-void ics_update_width(new_width)
-       int new_width;
+void
+ics_update_width (int new_width)
 {
        ics_printf("set width %d\n", new_width);
 }
 
 void
-SendMoveToProgram(moveNum, cps)
-     int moveNum;
-     ChessProgramState *cps;
+SendMoveToProgram (int moveNum, ChessProgramState *cps)
 {
     char buf[MSG_SIZ];
 
@@ -4935,12 +4925,15 @@ SendMoveToProgram(moveNum, cps)
 }
 
 void
-SendMoveToICS(moveType, fromX, fromY, toX, toY, promoChar)
-     ChessMove moveType;
-     int fromX, fromY, toX, toY;
-     char promoChar;
+SendMoveToICS (ChessMove moveType, int fromX, int fromY, int toX, int toY, char promoChar)
 {
     char user_move[MSG_SIZ];
+    char suffix[4];
+
+    if(gameInfo.variant == VariantSChess && promoChar) {
+       snprintf(suffix, 4, "=%c", toX == BOARD_WIDTH<<1 ? ToUpper(promoChar) : ToLower(promoChar));
+       if(moveType == NormalMove) moveType = WhitePromotion; // kludge to do gating
+    } else suffix[0] = NULLCHAR;
 
     switch (moveType) {
       default:
@@ -4956,7 +4949,7 @@ SendMoveToICS(moveType, fromX, fromY, toX, toY, promoChar)
       case WhiteHSideCastleFR:
       case BlackHSideCastleFR:
       /* POP Fabien */
-       snprintf(user_move, MSG_SIZ, "o-o\n");
+       snprintf(user_move, MSG_SIZ, "o-o%s\n", suffix);
        break;
       case WhiteQueenSideCastle:
       case BlackQueenSideCastle:
@@ -4966,7 +4959,7 @@ SendMoveToICS(moveType, fromX, fromY, toX, toY, promoChar)
       case WhiteASideCastleFR:
       case BlackASideCastleFR:
       /* POP Fabien */
-       snprintf(user_move, MSG_SIZ, "o-o-o\n");
+       snprintf(user_move, MSG_SIZ, "o-o-o%s\n",suffix);
        break;
       case WhiteNonPromotion:
       case BlackNonPromotion:
@@ -5009,13 +5002,13 @@ SendMoveToICS(moveType, fromX, fromY, toX, toY, promoChar)
 }
 
 void
-UploadGameEvent()
+UploadGameEvent ()
 {   // [HGM] upload: send entire stored game to ICS as long-algebraic moves.
     int i, last = forwardMostMove; // make sure ICS reply cannot pre-empt us by clearing fmm
     static char *castlingStrings[4] = { "none", "kside", "qside", "both" };
     if(gameMode == IcsObserving || gameMode == IcsPlayingBlack || gameMode == IcsPlayingWhite) {
-       DisplayError("You cannot do this while you are playing or observing", 0);
-       return;
+      DisplayError(_("You cannot do this while you are playing or observing"), 0);
+      return;
     }
     if(gameMode != IcsExamining) { // is this ever not the case?
        char buf[MSG_SIZ], *p, *fen, command[MSG_SIZ], bsetup = 0;
@@ -5076,10 +5069,7 @@ UploadGameEvent()
 }
 
 void
-CoordsToComputerAlgebraic(rf, ff, rt, ft, promoChar, move)
-     int rf, ff, rt, ft;
-     char promoChar;
-     char move[7];
+CoordsToComputerAlgebraic (int rf, int ff, int rt, int ft, char promoChar, char move[7])
 {
     if (rf == DROP_RANK) {
       if(ff == EmptySquare) sprintf(move, "@@@@\n"); else // [HGM] pass
@@ -5097,8 +5087,7 @@ CoordsToComputerAlgebraic(rf, ff, rt, ft, promoChar, move)
 }
 
 void
-ProcessICSInitScript(f)
-     FILE *f;
+ProcessICSInitScript (FILE *f)
 {
     char buf[MSG_SIZ];
 
@@ -5113,7 +5102,7 @@ ProcessICSInitScript(f)
 static int lastX, lastY, selectFlag, dragging;
 
 void
-Sweep(int step)
+Sweep (int step)
 {
     ChessSquare king = WhiteKing, pawn = WhitePawn, last = promoSweep;
     if(gameInfo.variant == VariantKnightmate) king = WhiteUnicorn;
@@ -5127,19 +5116,20 @@ Sweep(int step)
        else if((int)promoSweep == -1) promoSweep = WhiteKing;
        else if(promoSweep == BlackPawn && step < 0) promoSweep = WhitePawn;
        else if(promoSweep == WhiteKing && step > 0) promoSweep = BlackKing;
-       if(!step) step = 1;
+       if(!step) step = -1;
     } while(PieceToChar(promoSweep) == '.' || PieceToChar(promoSweep) == '~' || promoSweep == pawn ||
            appData.testLegality && (promoSweep == king ||
            gameInfo.variant == VariantShogi && promoSweep != PROMOTED last && last != PROMOTED promoSweep && last != promoSweep));
     ChangeDragPiece(promoSweep);
 }
 
-int PromoScroll(int x, int y)
+int
+PromoScroll (int x, int y)
 {
   int step = 0;
 
   if(promoSweep == EmptySquare || !appData.sweepSelect) return FALSE;
-  if(abs(x - lastX) < 15 && abs(y - lastY) < 15) return FALSE;
+  if(abs(x - lastX) < 25 && abs(y - lastY) < 25) return FALSE;
   if( y > lastY + 2 ) step = -1; else if(y < lastY - 2) step = 1;
   if(!step) return FALSE;
   lastX = x; lastY = y;
@@ -5150,7 +5140,7 @@ int PromoScroll(int x, int y)
 }
 
 void
-NextPiece(int step)
+NextPiece (int step)
 {
     ChessSquare piece = boards[currentMove][toY][toX];
     do {
@@ -5165,7 +5155,7 @@ NextPiece(int step)
 }
 /* [HGM] Shogi move preprocessor: swap digits for letters, vice versa */
 void
-AlphaRank(char *move, int n)
+AlphaRank (char *move, int n)
 {
 //    char *p = move, c; int x, y;
 
@@ -5217,12 +5207,7 @@ char yy_textstr[8000];
 
 /* 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;
+ParseOneMove (char *move, int moveNum, ChessMove *moveType, int *fromX, int *fromY, int *toX, int *toY, char *promoChar)
 {
     *moveType = yylexstr(moveNum, move, yy_textstr, sizeof yy_textstr);
 
@@ -5305,7 +5290,7 @@ Boolean pushed = FALSE;
 char *lastParseAttempt;
 
 void
-ParsePV(char *pv, Boolean storeComments, Boolean atEnd)
+ParsePV (char *pv, Boolean storeComments, Boolean atEnd)
 { // Parse a string of PV moves, and append to current game, behind forwardMostMove
   int fromX, fromY, toX, toY; char promoChar;
   ChessMove moveType;
@@ -5371,7 +5356,7 @@ fprintf(debugFP,"parsePV: %d %c%c%c%c yy='%s'\nPV = '%s'\n", valid, fromX+AAA, f
 }
 
 int
-MultiPV(ChessProgramState *cps)
+MultiPV (ChessProgramState *cps)
 {      // check if engine supports MultiPV, and if so, return the number of the option that sets it
        int i;
        for(i=0; i<cps->nrOptions; i++)
@@ -5381,7 +5366,7 @@ MultiPV(ChessProgramState *cps)
 }
 
 Boolean
-LoadMultiPV(int x, int y, char *buf, int index, int *start, int *end)
+LoadMultiPV (int x, int y, char *buf, int index, int *start, int *end)
 {
        int startPV, multi, lineStart, origIndex = index;
        char *p, buf2[MSG_SIZ];
@@ -5411,10 +5396,10 @@ LoadMultiPV(int x, int y, char *buf, int index, int *start, int *end)
 }
 
 char *
-PvToSAN(char *pv)
+PvToSAN (char *pv)
 {
        static char buf[10*MSG_SIZ];
-       int i, k=0, savedEnd=endPV;
+       int i, k=0, savedEnd=endPV, saveFMM = forwardMostMove;
        *buf = NULLCHAR;
        if(forwardMostMove < endPV) PushInner(forwardMostMove, endPV);
        ParsePV(pv, FALSE, 2); // this appends PV to game, suppressing any display of it
@@ -5424,13 +5409,13 @@ PvToSAN(char *pv)
            k += strlen(buf+k);
        }
        snprintf(buf+k, 10*MSG_SIZ-k, "%s", lastParseAttempt); // if we ran into stuff that could not be parsed, print it verbatim
-       if(forwardMostMove < savedEnd) PopInner(0);
+       if(forwardMostMove < savedEnd) { PopInner(0); forwardMostMove = saveFMM; } // PopInner would set fmm to endPV!
        endPV = savedEnd;
        return buf;
 }
 
 Boolean
-LoadPV(int x, int y)
+LoadPV (int x, int y)
 { // called on right mouse click to load PV
   int which = gameMode == TwoMachinesPlay && (WhiteOnMove(forwardMostMove) == (second.twoMachinesColor[0] == 'w'));
   lastX = x; lastY = y;
@@ -5439,7 +5424,7 @@ LoadPV(int x, int y)
 }
 
 void
-UnLoadPV()
+UnLoadPV ()
 {
   int oldFMM = forwardMostMove; // N.B.: this was currentMove before PV was loaded!
   if(endPV < 0) return;
@@ -5465,13 +5450,13 @@ UnLoadPV()
 }
 
 void
-MovePV(int x, int y, int h)
+MovePV (int x, int y, int h)
 { // step through PV based on mouse coordinates (called on mouse move)
-  int margin = h>>3, step = 0;
+  int margin = h>>3, step = 0, threshold = (pieceSweep == EmptySquare ? 10 : 15);
 
   // we must somehow check if right button is still down (might be released off board!)
   if(endPV < 0 && pieceSweep == EmptySquare) return; // needed in XBoard because lastX/Y is shared :-(
-  if(abs(x - lastX) < 7 && abs(y - lastY) < 7) return;
+  if(abs(x - lastX) < threshold && abs(y - lastY) < threshold) return;
   if( y > lastY + 2 ) step = -1; else if(y < lastY - 2) step = 1;
   if(!step) return;
   lastX = x; lastY = y;
@@ -5500,7 +5485,8 @@ int squaresLeft[4];
 int piecesLeft[(int)BlackPawn];
 int seed, nrOfShuffles;
 
-void GetPositionNumber()
+void
+GetPositionNumber ()
 {      // sets global variable seed
        int i;
 
@@ -5512,7 +5498,8 @@ void GetPositionNumber()
        }
 }
 
-int put(Board board, int pieceType, int rank, int n, int shade)
+int
+put (Board board, int pieceType, int rank, int n, int shade)
 // put the piece on the (n-1)-th empty squares of the given shade
 {
        int i;
@@ -5530,7 +5517,8 @@ int put(Board board, int pieceType, int rank, int n, int shade)
 }
 
 
-void AddOnePiece(Board board, int pieceType, int rank, int shade)
+void
+AddOnePiece (Board board, int pieceType, int rank, int shade)
 // calculate where the next piece goes, (any empty square), and put it there
 {
        int i;
@@ -5541,7 +5529,8 @@ void AddOnePiece(Board board, int pieceType, int rank, int shade)
         put(board, pieceType, rank, i, shade);
 }
 
-void AddTwoPieces(Board board, int pieceType, int rank)
+void
+AddTwoPieces (Board board, int pieceType, int rank)
 // calculate where the next 2 identical pieces go, (any empty square), and put it there
 {
        int i, n=squaresLeft[ANY], j=n-1, k;
@@ -5556,7 +5545,8 @@ void AddTwoPieces(Board board, int pieceType, int rank)
         put(board, pieceType, rank, i, ANY);
 }
 
-void SetUpShuffle(Board board, int number)
+void
+SetUpShuffle (Board board, int number)
 {
        int i, p, first=1;
 
@@ -5644,7 +5634,8 @@ void SetUpShuffle(Board board, int number)
        if(number >= 0) appData.defaultFrcPosition %= nrOfShuffles; // normalize
 }
 
-int SetCharTable( char *table, const char * map )
+int
+SetCharTable (char *table, const char * map)
 /* [HGM] moved here from winboard.c because of its general usefulness */
 /*       Basically a safe strcpy that uses the last character as King */
 {
@@ -5668,7 +5659,8 @@ int SetCharTable( char *table, const char * map )
     return result;
 }
 
-void Prelude(Board board)
+void
+Prelude (Board board)
 {      // [HGM] superchess: random selection of exo-pieces
        int i, j, k; ChessSquare p;
        static ChessSquare exoPieces[4] = { WhiteAngel, WhiteMarshall, WhiteSilver, WhiteLance };
@@ -5705,8 +5697,7 @@ void Prelude(Board board)
 }
 
 void
-InitPosition(redraw)
-     int redraw;
+InitPosition (int redraw)
 {
     ChessSquare (* pieces)[BOARD_FILES];
     int i, j, pawnRow, overrule,
@@ -6000,9 +5991,7 @@ InitPosition(redraw)
 }
 
 void
-SendBoard(cps, moveNum)
-     ChessProgramState *cps;
-     int moveNum;
+SendBoard (ChessProgramState *cps, int moveNum)
 {
     char message[MSG_SIZ];
 
@@ -6014,21 +6003,25 @@ SendBoard(cps, moveNum)
 
     } else {
       ChessSquare *bp;
-      int i, j;
+      int i, j, left=0, right=BOARD_WIDTH;
       /* Kludge to set black to move, avoiding the troublesome and now
        * deprecated "black" command.
        */
       if (!WhiteOnMove(moveNum)) // [HGM] but better a deprecated command than an illegal move...
         SendToProgram(boards[0][1][BOARD_LEFT] == WhitePawn ? "a2a3\n" : "black\n", cps);
 
+      if(!cps->extendedEdit) left = BOARD_LEFT, right = BOARD_RGHT; // only board proper
+
       SendToProgram("edit\n", cps);
       SendToProgram("#\n", cps);
       for (i = BOARD_HEIGHT - 1; i >= 0; i--) {
-       bp = &boards[moveNum][i][BOARD_LEFT];
-        for (j = BOARD_LEFT; j < BOARD_RGHT; j++, bp++) {
+       bp = &boards[moveNum][i][left];
+        for (j = left; j < right; j++, bp++) {
+         if(j == BOARD_LEFT-1 || j == BOARD_RGHT) continue;
          if ((int) *bp < (int) BlackPawn) {
-           snprintf(message, MSG_SIZ, "%c%c%c\n", PieceToChar(*bp),
-                    AAA + j, ONE + i);
+           if(j == BOARD_RGHT+1)
+                snprintf(message, MSG_SIZ, "%c@%d\n", PieceToChar(*bp), bp[-1]);
+           else snprintf(message, MSG_SIZ, "%c%c%c\n", PieceToChar(*bp), AAA + j, ONE + i);
             if(message[0] == '+' || message[0] == '~') {
              snprintf(message, MSG_SIZ,"%c%c%c+\n",
                         PieceToChar((ChessSquare)(DEMOTED *bp)),
@@ -6045,11 +6038,14 @@ SendBoard(cps, moveNum)
 
       SendToProgram("c\n", cps);
       for (i = BOARD_HEIGHT - 1; i >= 0; i--) {
-       bp = &boards[moveNum][i][BOARD_LEFT];
-        for (j = BOARD_LEFT; j < BOARD_RGHT; j++, bp++) {
+       bp = &boards[moveNum][i][left];
+        for (j = left; j < right; j++, bp++) {
+         if(j == BOARD_LEFT-1 || j == BOARD_RGHT) continue;
          if (((int) *bp != (int) EmptySquare)
              && ((int) *bp >= (int) BlackPawn)) {
-           snprintf(message,MSG_SIZ, "%c%c%c\n", ToUpper(PieceToChar(*bp)),
+           if(j == BOARD_LEFT-2)
+                snprintf(message, MSG_SIZ, "%c@%d\n", ToUpper(PieceToChar(*bp)), bp[1]);
+           else snprintf(message,MSG_SIZ, "%c%c%c\n", ToUpper(PieceToChar(*bp)),
                     AAA + j, ONE + i);
             if(message[0] == '+' || message[0] == '~') {
              snprintf(message, MSG_SIZ,"%c%c%c+\n",
@@ -6071,7 +6067,7 @@ SendBoard(cps, moveNum)
 }
 
 ChessSquare
-DefaultPromoChoice(int white)
+DefaultPromoChoice (int white)
 {
     ChessSquare result;
     if(gameInfo.variant == VariantShatranj || gameInfo.variant == VariantCourier || gameInfo.variant == VariantMakruk)
@@ -6088,7 +6084,7 @@ DefaultPromoChoice(int white)
 static int autoQueen; // [HGM] oneclick
 
 int
-HasPromotionChoice(int fromX, int fromY, int toX, int toY, char *promoChoice, int sweepSelect)
+HasPromotionChoice (int fromX, int fromY, int toX, int toY, char *promoChoice, int sweepSelect)
 {
     /* [HGM] rewritten IsPromotion to only flag promotions that offer a choice */
     /* [HGM] add Shogi promotions */
@@ -6190,8 +6186,7 @@ HasPromotionChoice(int fromX, int fromY, int toX, int toY, char *promoChoice, in
 }
 
 int
-InPalace(row, column)
-     int row, column;
+InPalace (int row, int column)
 {   /* [HGM] for Xiangqi */
     if( (row < 3 || row > BOARD_HEIGHT-4) &&
          column < (BOARD_WIDTH + 4)/2 &&
@@ -6200,9 +6195,7 @@ InPalace(row, column)
 }
 
 int
-PieceForSquare (x, y)
-     int x;
-     int y;
+PieceForSquare (int x, int y)
 {
   if (x < 0 || x >= BOARD_WIDTH || y < 0 || y >= BOARD_HEIGHT)
      return -1;
@@ -6211,8 +6204,7 @@ PieceForSquare (x, y)
 }
 
 int
-OKToStartUserMove(x, y)
-     int x, y;
+OKToStartUserMove (int x, int y)
 {
     ChessSquare from_piece;
     int white_piece;
@@ -6231,7 +6223,6 @@ OKToStartUserMove(x, y)
       (int)from_piece < (int)BlackPawn; /* [HGM] can be > King! */
 
     switch (gameMode) {
-      case PlayFromGameFile:
       case AnalyzeFile:
       case TwoMachinesPlay:
       case EndOfGame:
@@ -6259,6 +6250,8 @@ OKToStartUserMove(x, y)
        }
        break;
 
+      case PlayFromGameFile:
+           if(!shiftKey || !appData.variations) return FALSE; // [HGM] allow starting variation in this mode
       case EditGame:
        if (!white_piece && WhiteOnMove(currentMove)) {
            DisplayMoveError(_("It is White's turn"));
@@ -6302,6 +6295,7 @@ OKToStartUserMove(x, y)
     }
     if (currentMove != forwardMostMove && gameMode != AnalyzeMode
        && gameMode != EditGame // [HGM] vari: treat as AnalyzeMode
+       && gameMode != PlayFromGameFile // [HGM] as EditGame, with protected main line
        && gameMode != AnalyzeFile && gameMode != Training) {
        DisplayMoveError(_("Displayed position is not current"));
        return FALSE;
@@ -6310,7 +6304,8 @@ OKToStartUserMove(x, y)
 }
 
 Boolean
-OnlyMove(int *x, int *y, Boolean captures) {
+OnlyMove (int *x, int *y, Boolean captures) 
+{
     DisambiguateClosure cl;
     if (appData.zippyPlay || !appData.testLegality) return FALSE;
     switch(gameMode) {
@@ -6374,9 +6369,7 @@ char lastLoadGameTitle[MSG_SIZ], lastLoadPositionTitle[MSG_SIZ];
 ChessMove lastLoadGameStart = EndOfFile;
 
 void
-UserMoveEvent(fromX, fromY, toX, toY, promoChar)
-     int fromX, fromY, toX, toY;
-     int promoChar;
+UserMoveEvent(int fromX, int fromY, int toX, int toY, int promoChar)
 {
     ChessMove moveType;
     ChessSquare pdown, pup;
@@ -6393,7 +6386,6 @@ UserMoveEvent(fromX, fromY, toX, toY, promoChar)
        */
 
     switch (gameMode) {
-      case PlayFromGameFile:
       case AnalyzeFile:
       case TwoMachinesPlay:
       case EndOfGame:
@@ -6419,6 +6411,8 @@ UserMoveEvent(fromX, fromY, toX, toY, promoChar)
        }
        break;
 
+      case PlayFromGameFile:
+           if(!shiftKey ||!appData.variations) return; // [HGM] only variations
       case EditGame:
       case IcsExamining:
       case BeginningOfGame:
@@ -6550,10 +6544,7 @@ UserMoveEvent(fromX, fromY, toX, toY, promoChar)
 
 /* Common tail of UserMoveEvent and DropMenuEvent */
 int
-FinishMove(moveType, fromX, fromY, toX, toY, promoChar)
-     ChessMove moveType;
-     int fromX, fromY, toX, toY;
-     /*char*/int promoChar;
+FinishMove (ChessMove moveType, int fromX, int fromY, int toX, int toY, int promoChar)
 {
     char *bookHit = 0;
 
@@ -6613,7 +6604,7 @@ FinishMove(moveType, fromX, fromY, toX, toY, promoChar)
 
   /* Ok, now we know that the move is good, so we can kill
      the previous line in Analysis Mode */
-  if ((gameMode == AnalyzeMode || gameMode == EditGame)
+  if ((gameMode == AnalyzeMode || gameMode == EditGame || gameMode == PlayFromGameFile && appData.variations && shiftKey)
                                && currentMove < forwardMostMove) {
     if(appData.variations && shiftKey) PushTail(currentMove, forwardMostMove); // [HGM] vari: save tail of game
     else forwardMostMove = currentMove;
@@ -6644,7 +6635,7 @@ FinishMove(moveType, fromX, fromY, toX, toY, promoChar)
       gameMode = MachinePlaysBlack;
       StartClocks();
       SetGameInfo();
-      snprintf(buf, MSG_SIZ, "%s vs. %s", gameInfo.white, gameInfo.black);
+      snprintf(buf, MSG_SIZ, "%s %s %s", gameInfo.white, _("vs."), gameInfo.black);
       DisplayTitle(buf);
       if (first.sendName) {
        snprintf(buf, MSG_SIZ,"name %s\n", gameInfo.white);
@@ -6738,12 +6729,7 @@ FinishMove(moveType, fromX, fromY, toX, toY, promoChar)
 }
 
 void
-Mark(board, flags, kind, rf, ff, rt, ft, closure)
-     Board board;
-     int flags;
-     ChessMove kind;
-     int rf, ff, rt, ft;
-     VOIDSTAR closure;
+Mark (Board board, int flags, ChessMove kind, int rf, int ff, int rt, int ft, VOIDSTAR closure)
 {
     typedef char Markers[BOARD_RANKS][BOARD_FILES];
     Markers *m = (Markers *) closure;
@@ -6755,7 +6741,7 @@ Mark(board, flags, kind, rf, ff, rt, ft, closure)
 }
 
 void
-MarkTargetSquares(int clear)
+MarkTargetSquares (int clear)
 {
   int x, y;
   if(!appData.markers || !appData.highlightDragging || appData.icsActive && gameInfo.variant < VariantShogi ||
@@ -6775,7 +6761,7 @@ MarkTargetSquares(int clear)
 }
 
 int
-Explode(Board board, int fromX, int fromY, int toX, int toY)
+Explode (Board board, int fromX, int fromY, int toX, int toY)
 {
     if(gameInfo.variant == VariantAtomic &&
        (board[toY][toX] != EmptySquare ||                     // capture?
@@ -6790,7 +6776,8 @@ Explode(Board board, int fromX, int fromY, int toX, int toY)
 
 ChessSquare gatingPiece = EmptySquare; // exported to front-end, for dragging
 
-int CanPromote(ChessSquare piece, int y)
+int
+CanPromote (ChessSquare piece, int y)
 {
        if(gameMode == EditPosition) return FALSE; // no promotions when editing position
        // some variants have fixed promotion piece, no promotion at all, or another selection mechanism
@@ -6804,7 +6791,8 @@ int CanPromote(ChessSquare piece, int y)
                piece == WhiteLance && y == BOARD_HEIGHT-2 );
 }
 
-void LeftClick(ClickType clickType, int xPix, int yPix)
+void
+LeftClick (ClickType clickType, int xPix, int yPix)
 {
     int x, y;
     Boolean saveAnimate;
@@ -7102,7 +7090,8 @@ void LeftClick(ClickType clickType, int xPix, int yPix)
     }
 }
 
-int RightClick(ClickType action, int x, int y, int *fromX, int *fromY)
+int
+RightClick (ClickType action, int x, int y, int *fromX, int *fromY)
 {   // front-end-free part taken out of PieceMenuPopup
     int whichMenu; int xSqr, ySqr;
 
@@ -7192,7 +7181,8 @@ int RightClick(ClickType action, int x, int y, int *fromX, int *fromY)
     return whichMenu;
 }
 
-void SendProgramStatsToFrontend( ChessProgramState * cps, ChessProgramStats * cpstats )
+void
+SendProgramStatsToFrontend (ChessProgramState * cps, ChessProgramStats * cpstats)
 {
 //    char * hint = lastHint;
     FrontEndProgramStats stats;
@@ -7219,7 +7209,7 @@ void SendProgramStatsToFrontend( ChessProgramState * cps, ChessProgramStats * cp
 }
 
 void
-ClearEngineOutputPane(int which)
+ClearEngineOutputPane (int which)
 {
     static FrontEndProgramStats dummyStats;
     dummyStats.which = which;
@@ -7230,7 +7220,7 @@ ClearEngineOutputPane(int which)
 #define MAXPLAYERS 500
 
 char *
-TourneyStandings(int display)
+TourneyStandings (int display)
 {
     int i, w, b, color, wScore, bScore, dummy, nr=0, nPlayers=0;
     int score[MAXPLAYERS], ranking[MAXPLAYERS], points[MAXPLAYERS], games[MAXPLAYERS];
@@ -7274,7 +7264,7 @@ TourneyStandings(int display)
 }
 
 void
-Count(Board board, int pCnt[], int *nW, int *nB, int *wStale, int *bStale, int *bishopColor)
+Count (Board board, int pCnt[], int *nW, int *nB, int *wStale, int *bStale, int *bishopColor)
 {      // count all piece types
        int p, f, r;
        *nB = *nW = *wStale = *bStale = *bishopColor = 0;
@@ -7292,7 +7282,7 @@ Count(Board board, int pCnt[], int *nW, int *nB, int *wStale, int *bStale, int *
 }
 
 int
-SufficientDefence(int pCnt[], int side, int nMine, int nHis)
+SufficientDefence (int pCnt[], int side, int nMine, int nHis)
 {
        int myPawns = pCnt[WhitePawn+side]; // my total Pawn count;
        int majorDefense = pCnt[BlackRook-side] + pCnt[BlackCannon-side] + pCnt[BlackKnight-side];
@@ -7321,7 +7311,7 @@ SufficientDefence(int pCnt[], int side, int nMine, int nHis)
 }
 
 int
-MatingPotential(int pCnt[], int side, int nMine, int nHis, int stale, int bisColor)
+MatingPotential (int pCnt[], int side, int nMine, int nHis, int stale, int bisColor)
 {
        VariantClass v = gameInfo.variant;
 
@@ -7371,7 +7361,29 @@ MatingPotential(int pCnt[], int side, int nMine, int nHis, int stale, int bisCol
 }
 
 int
-Adjudicate(ChessProgramState *cps)
+CompareWithRights (Board b1, Board b2)
+{
+    int rights = 0;
+    if(!CompareBoards(b1, b2)) return FALSE;
+    if(b1[EP_STATUS] != b2[EP_STATUS]) return FALSE;
+    /* compare castling rights */
+    if( b1[CASTLING][2] != b2[CASTLING][2] && (b2[CASTLING][0] != NoRights || b2[CASTLING][1] != NoRights) )
+           rights++; /* King lost rights, while rook still had them */
+    if( b1[CASTLING][2] != NoRights ) { /* king has rights */
+        if( b1[CASTLING][0] != b2[CASTLING][0] || b1[CASTLING][1] != b2[CASTLING][1] )
+           rights++; /* but at least one rook lost them */
+    }
+    if( b1[CASTLING][5] != b1[CASTLING][5] && (b2[CASTLING][3] != NoRights || b2[CASTLING][4] != NoRights) )
+           rights++;
+    if( b1[CASTLING][5] != NoRights ) {
+        if( b1[CASTLING][3] != b2[CASTLING][3] || b1[CASTLING][4] != b2[CASTLING][4] )
+           rights++;
+    }
+    return rights == 0;
+}
+
+int
+Adjudicate (ChessProgramState *cps)
 {      // [HGM] some adjudications useful with buggy engines
        // [HGM] adjudicate: made into separate routine, which now can be called after every move
        //       In any case it determnes if the game is a claimable draw (filling in EP_STATUS).
@@ -7592,8 +7604,10 @@ Adjudicate(ChessProgramState *cps)
                                    hisPerpetual = PerpetualChase(k, forwardMostMove);
                                    ourPerpetual = PerpetualChase(k+1, forwardMostMove);
                                    if(ourPerpetual && !hisPerpetual) { // we are actively chasing him: forfeit
+                                       static char resdet[MSG_SIZ];
                                        result = WhiteOnMove(forwardMostMove) ? WhiteWins : BlackWins;
-                                       details = "Xboard adjudication: perpetual chasing";
+                                       details = resdet;
+                                       snprintf(resdet, MSG_SIZ, "Xboard adjudication: perpetual chasing of %c%c", ourPerpetual>>8, ourPerpetual&255);
                                    } else
                                    if(hisPerpetual && !ourPerpetual)   // he is chasing us, but did not repeat yet
                                        break; // Abort repetition-checking loop.
@@ -7678,7 +7692,8 @@ Adjudicate(ChessProgramState *cps)
        return 0;
 }
 
-char *SendMoveToBookUser(int moveNr, ChessProgramState *cps, int initial)
+char *
+SendMoveToBookUser (int moveNr, ChessProgramState *cps, int initial)
 {   // [HGM] book: this routine intercepts moves to simulate book replies
     char *bookHit = NULL;
 
@@ -7728,7 +7743,8 @@ char *SendMoveToBookUser(int moveNr, ChessProgramState *cps, int initial)
 
 char *savedMessage;
 ChessProgramState *savedState;
-void DeferredBookMove(void)
+void
+DeferredBookMove (void)
 {
        if(savedState->lastPing != savedState->lastPong)
                    ScheduleDelayedEvent(DeferredBookMove, 10);
@@ -7739,9 +7755,7 @@ void DeferredBookMove(void)
 static int savedWhitePlayer, savedBlackPlayer, pairingReceived;
 
 void
-HandleMachineMove(message, cps)
-     char *message;
-     ChessProgramState *cps;
+HandleMachineMove (char *message, ChessProgramState *cps)
 {
     char machineMove[MSG_SIZ], buf1[MSG_SIZ*10], buf2[MSG_SIZ];
     char realname[MSG_SIZ];
@@ -8082,10 +8096,12 @@ if(appData.debugMode) fprintf(debugFP, "nodes = %d, %lld\n", (int) programStats.
       return; // [HGM] This return was missing, causing option features to be recognized as non-compliant commands!
     }
 
-    if (!appData.testLegality && !strncmp(message, "setup ", 6)) { // [HGM] allow first engine to define opening position
+    if ((!appData.testLegality || gameInfo.variant == VariantFairy) && 
+                                       !strncmp(message, "setup ", 6)) { // [HGM] allow first engine to define opening position
       int dummy, s=6; char buf[MSG_SIZ];
-      if(appData.icsActive || forwardMostMove != 0 || cps != &first || startedFromSetupPosition) return;
+      if(appData.icsActive || forwardMostMove != 0 || cps != &first) return;
       if(sscanf(message, "setup (%s", buf) == 1) s = 8 + strlen(buf), buf[s-9] = NULLCHAR, SetCharTable(pieceToChar, buf);
+      if(startedFromSetupPosition) return;
       ParseFEN(boards[0], &dummy, message+s);
       DrawPosition(TRUE, boards[0]);
       startedFromSetupPosition = TRUE;
@@ -8242,7 +8258,8 @@ if(appData.debugMode) fprintf(debugFP, "nodes = %d, %lld\n", (int) programStats.
        if (StrStr(message, "analyze")) {
            cps->analysisSupport = FALSE;
            cps->analyzing = FALSE;
-           Reset(FALSE, TRUE);
+//         Reset(FALSE, TRUE); // [HGM] this caused discrepancy between display and internal state!
+           EditGameEvent(); // [HGM] try to preserve loaded game
            snprintf(buf2,MSG_SIZ, _("%s does not support analysis"), cps->tidy);
            DisplayError(buf2, 0);
            return;
@@ -8313,6 +8330,8 @@ if(appData.debugMode) fprintf(debugFP, "nodes = %d, %lld\n", (int) programStats.
                parseList[currentMove], _(cps->which));
        DisplayMoveError(buf1);
        DrawPosition(FALSE, boards[currentMove]);
+
+       SetUserThinkingEnables();
        return;
     }
     if (strncmp(message, "time", 4) == 0 && StrStr(message, "Illegal")) {
@@ -8607,6 +8626,19 @@ if(appData.debugMode) fprintf(debugFP, "nodes = %d, %lld\n", (int) programStats.
 
                if(appData.pvSAN[cps==&second]) pv = PvToSAN(buf1);
 
+               if(serverMoves && (time > 100 || time == 0 && plylev > 7)) {
+                       char buf[MSG_SIZ];
+                       FILE *f;
+                       snprintf(buf, MSG_SIZ, "%s", appData.serverMovesName);
+                       buf[strlen(buf)-1] = gameMode == MachinePlaysWhite ? 'w' :
+                                            gameMode == MachinePlaysBlack ? 'b' : cps->twoMachinesColor[0];
+                       if(appData.debugMode) fprintf(debugFP, "write PV on file '%s'\n", buf);
+                       if(f = fopen(buf, "w")) { // export PV to applicable PV file
+                               fprintf(f, "%5.2f/%-2d %s", curscore/100., plylev, pv);
+                               fclose(f);
+                       } else DisplayError(_("failed writing PV"), 0);
+               }
+
                tempStats.depth = plylev;
                tempStats.nodes = nodes;
                tempStats.time = time;
@@ -8821,8 +8853,7 @@ if(appData.debugMode) fprintf(debugFP, "nodes = %d, %lld\n", (int) programStats.
    The display is not updated in any way.
    */
 void
-ParseGameHistory(game)
-     char *game;
+ParseGameHistory (char *game)
 {
     ChessMove moveType;
     int fromX, fromY, toX, toY, boardIndex;
@@ -8892,6 +8923,7 @@ ParseGameHistory(game)
            break;
          case WhiteDrop:
          case BlackDrop:
+           if(currentMoveString[0] == '@') continue; // no null moves in ICS mode!
            fromX = moveType == WhiteDrop ?
              (int) CharToPiece(ToUpper(currentMoveString[0])) :
            (int) CharToPiece(ToLower(currentMoveString[0]));
@@ -9004,10 +9036,7 @@ ParseGameHistory(game)
 
 /* Apply a move to the given board  */
 void
-ApplyMove(fromX, fromY, toX, toY, promoChar, board)
-     int fromX, fromY, toX, toY;
-     int promoChar;
-     Board board;
+ApplyMove (int fromX, int fromY, int toX, int toY, int promoChar, Board board)
 {
   ChessSquare captured = board[toY][toX], piece, king; int p, oldEP = EP_NONE, berolina = 0;
   int promoRank = gameInfo.variant == VariantMakruk || gameInfo.variant == VariantGrand ? 3 : 1;
@@ -9310,12 +9339,15 @@ ApplyMove(fromX, fromY, toX, toY, promoChar, board)
 
 /* Updates forwardMostMove */
 void
-MakeMove(fromX, fromY, toX, toY, promoChar)
-     int fromX, fromY, toX, toY;
-     int promoChar;
+MakeMove (int fromX, int fromY, int toX, int toY, int promoChar)
 {
 //    forwardMostMove++; // [HGM] bare: moved downstream
 
+    (void) CoordsToAlgebraic(boards[forwardMostMove],
+                            PosFlags(forwardMostMove),
+                            fromY, fromX, toY, toX, promoChar,
+                            parseList[forwardMostMove]);
+
     if(serverMoves != NULL) { /* [HGM] write moves on file for broadcasting (should be separate routine, really) */
         int timeLeft; static int lastLoadFlag=0; int king, piece;
         piece = boards[forwardMostMove][fromY][fromX];
@@ -9323,10 +9355,14 @@ MakeMove(fromX, fromY, toX, toY, promoChar)
         if(gameInfo.variant == VariantKnightmate)
             king += (int) WhiteUnicorn - (int) WhiteKing;
         if(forwardMostMove == 0) {
-            if(blackPlaysFirst)
+            if(gameMode == MachinePlaysBlack || gameMode == BeginningOfGame)
+                fprintf(serverMoves, "%s;", UserName());
+            else if(gameMode == TwoMachinesPlay && first.twoMachinesColor[0] == 'b')
                 fprintf(serverMoves, "%s;", second.tidy);
             fprintf(serverMoves, "%s;", first.tidy);
-            if(!blackPlaysFirst)
+            if(gameMode == MachinePlaysWhite)
+                fprintf(serverMoves, "%s;", UserName());
+            else if(gameMode == TwoMachinesPlay && first.twoMachinesColor[0] == 'w')
                 fprintf(serverMoves, "%s;", second.tidy);
         } else fprintf(serverMoves, loadFlag|lastLoadFlag ? ":" : ";");
         lastLoadFlag = loadFlag;
@@ -9347,20 +9383,24 @@ MakeMove(fromX, fromY, toX, toY, promoChar)
                 fprintf(serverMoves, ":%c%c:%c%c", AAA+fromX, ONE+fromY, AAA+toX, ONE+fromY);
         // promotion suffix
         if(promoChar != NULLCHAR)
-                fprintf(serverMoves, ":%c:%c%c", promoChar, AAA+toX, ONE+toY);
+                fprintf(serverMoves, ":%c:%c%c", ToLower(promoChar), AAA+toX, ONE+toY);
         if(!loadFlag) {
+               char buf[MOVE_LEN*2], *p; int len;
             fprintf(serverMoves, "/%d/%d",
                pvInfoList[forwardMostMove].depth, pvInfoList[forwardMostMove].score);
             if(forwardMostMove+1 & 1) timeLeft = whiteTimeRemaining/1000;
             else                      timeLeft = blackTimeRemaining/1000;
             fprintf(serverMoves, "/%d", timeLeft);
+               strncpy(buf, parseList[forwardMostMove], MOVE_LEN*2);
+               if(p = strchr(buf, '=')) *p = NULLCHAR;
+               len = strlen(buf); if(len > 1 && buf[len-2] != '-') buf[len-2] = NULLCHAR; // strip to-square
+            fprintf(serverMoves, "/%s", buf);
         }
         fflush(serverMoves);
     }
 
-    if (forwardMostMove+1 > framePtr) { // [HGM] vari: do not run into saved variations
-      DisplayFatalError(_("Game too long; increase MAX_MOVES and recompile"),
-                       0, 1);
+    if (forwardMostMove+1 > framePtr) { // [HGM] vari: do not run into saved variations..
+       GameEnds(GameUnfinished, _("Game too long; increase MAX_MOVES and recompile"), GE_XBOARD);
       return;
     }
     UnLoadPV(); // [HGM] pv: if we are looking at a PV, abort this
@@ -9374,6 +9414,7 @@ MakeMove(fromX, fromY, toX, toY, promoChar)
     SwitchClocks(forwardMostMove+1); // [HGM] race: incrementing move nr inside
     timeRemaining[0][forwardMostMove] = whiteTimeRemaining;
     timeRemaining[1][forwardMostMove] = blackTimeRemaining;
+    adjustedClock = FALSE;
     gameInfo.result = GameUnfinished;
     if (gameInfo.resultDetails != NULL) {
        free(gameInfo.resultDetails);
@@ -9381,10 +9422,6 @@ MakeMove(fromX, fromY, toX, toY, promoChar)
     }
     CoordsToComputerAlgebraic(fromY, fromX, toY, toX, promoChar,
                              moveList[forwardMostMove - 1]);
-    (void) CoordsToAlgebraic(boards[forwardMostMove - 1],
-                            PosFlags(forwardMostMove - 1),
-                            fromY, fromX, toY, toX, promoChar,
-                            parseList[forwardMostMove - 1]);
     switch (MateTest(boards[forwardMostMove], PosFlags(forwardMostMove)) ) {
       case MT_NONE:
       case MT_STALEMATE:
@@ -9407,7 +9444,7 @@ MakeMove(fromX, fromY, toX, toY, promoChar)
 
 /* Updates currentMove if not pausing */
 void
-ShowMove(fromX, fromY, toX, toY)
+ShowMove (int fromX, int fromY, int toX, int toY)
 {
     int instant = (gameMode == PlayFromGameFile) ?
        (matchMode || (appData.timeDelay == 0 && !pausing)) : pausing;
@@ -9431,10 +9468,10 @@ ShowMove(fromX, fromY, toX, toY)
     DrawPosition(FALSE, boards[currentMove]);
     DisplayBothClocks();
     HistorySet(parseList,backwardMostMove,forwardMostMove,currentMove-1);
-    DisplayBook(currentMove);
 }
 
-void SendEgtPath(ChessProgramState *cps)
+void
+SendEgtPath (ChessProgramState *cps)
 {       /* [HGM] EGT: match formats given in feature with those given by user, and send info for each match */
        char buf[MSG_SIZ], name[MSG_SIZ], *p;
 
@@ -9468,15 +9505,15 @@ void SendEgtPath(ChessProgramState *cps)
 }
 
 void
-InitChessProgram(cps, setup)
-     ChessProgramState *cps;
-     int setup; /* [HGM] needed to setup FRC opening position */
+InitChessProgram (ChessProgramState *cps, int setup)
+/* setup needed to setup FRC opening position */
 {
     char buf[MSG_SIZ], b[MSG_SIZ]; int overruled;
     if (appData.noChessProgram) return;
     hintRequested = FALSE;
     bookRequested = FALSE;
 
+    ParseFeatures(appData.features[cps == &second], cps); // [HGM] allow user to overrule features
     /* [HGM] some new WB protocol commands to configure engine are sent now, if engine supports them */
     /*       moved to before sending initstring in 4.3.15, so Polyglot can delay UCI 'isready' to recepton of 'new' */
     if(cps->memSize) { /* [HGM] memory */
@@ -9590,8 +9627,7 @@ InitChessProgram(cps, setup)
 
 
 void
-StartChessProgram(cps)
-     ChessProgramState *cps;
+StartChessProgram (ChessProgramState *cps)
 {
     char buf[MSG_SIZ];
     int err;
@@ -9658,7 +9694,7 @@ TwoMachinesEventIfReady P((void))
 }
 
 char *
-MakeName(char *template)
+MakeName (char *template)
 {
     time_t clock;
     struct tm *tm;
@@ -9687,7 +9723,7 @@ MakeName(char *template)
 }
 
 int
-CountPlayers(char *p)
+CountPlayers (char *p)
 {
     int n = 0;
     while(p = strchr(p, '\n')) p++, n++; // count participants
@@ -9695,12 +9731,13 @@ CountPlayers(char *p)
 }
 
 FILE *
-WriteTourneyFile(char *results)
+WriteTourneyFile (char *results, FILE *f)
 {   // write tournament parameters on tourneyFile; on success return the stream pointer for closing
-    FILE *f = fopen(appData.tourneyFile, "w");
+    if(f == NULL) f = fopen(appData.tourneyFile, "w");
     if(f == NULL) DisplayError(_("Could not write on tourney file"), 0); else {
        // create a file with tournament description
        fprintf(f, "-participants {%s}\n", appData.participants);
+       fprintf(f, "-seedBase %d\n", appData.seedBase);
        fprintf(f, "-tourneyType %d\n", appData.tourneyType);
        fprintf(f, "-tourneyCycles %d\n", appData.tourneyCycles);
        fprintf(f, "-defaultMatchGames %d\n", appData.defaultMatchGames);
@@ -9712,6 +9749,7 @@ WriteTourneyFile(char *results)
        fprintf(f, "-loadPositionFile \"%s\"\n", appData.loadPositionFile);
        fprintf(f, "-loadPositionIndex %d\n", appData.loadPositionIndex);
        fprintf(f, "-rewindIndex %d\n", appData.rewindIndex);
+       fprintf(f, "-discourageOwnBooks %s\n", appData.defNoBook ? "true" : "false");
        if(searchTime > 0)
                fprintf(f, "-searchTime \"%d:%02d\"\n", searchTime/60, searchTime%60);
        else {
@@ -9724,10 +9762,73 @@ WriteTourneyFile(char *results)
     return f;
 }
 
+char *command[MAXENGINES], *mnemonic[MAXENGINES];
+
+void
+Substitute (char *participants, int expunge)
+{
+    int i, changed, changes=0, nPlayers=0;
+    char *p, *q, *r, buf[MSG_SIZ];
+    if(participants == NULL) return;
+    if(appData.tourneyFile[0] == NULLCHAR) { free(participants); return; }
+    r = p = participants; q = appData.participants;
+    while(*p && *p == *q) {
+       if(*p == '\n') r = p+1, nPlayers++;
+       p++; q++;
+    }
+    if(*p) { // difference
+       while(*p && *p++ != '\n');
+       while(*q && *q++ != '\n');
+      changed = nPlayers;
+       changes = 1 + (strcmp(p, q) != 0);
+    }
+    if(changes == 1) { // a single engine mnemonic was changed
+       q = r; while(*q) nPlayers += (*q++ == '\n');
+       p = buf; while(*r && (*p = *r++) != '\n') p++;
+       *p = NULLCHAR;
+       NamesToList(firstChessProgramNames, command, mnemonic);
+       for(i=1; mnemonic[i]; i++) if(!strcmp(buf, mnemonic[i])) break;
+       if(mnemonic[i]) { // The substitute is valid
+           FILE *f;
+           if(appData.tourneyFile[0] && (f = fopen(appData.tourneyFile, "r+")) ) {
+               flock(fileno(f), LOCK_EX);
+               ParseArgsFromFile(f);
+               fseek(f, 0, SEEK_SET);
+               FREE(appData.participants); appData.participants = participants;
+               if(expunge) { // erase results of replaced engine
+                   int len = strlen(appData.results), w, b, dummy;
+                   for(i=0; i<len; i++) {
+                       Pairing(i, nPlayers, &w, &b, &dummy);
+                       if((w == changed || b == changed) && appData.results[i] == '*') {
+                           DisplayError(_("You cannot replace an engine while it is engaged!\nTerminate its game first."), 0);
+                           fclose(f);
+                           return;
+                       }
+                   }
+                   for(i=0; i<len; i++) {
+                       Pairing(i, nPlayers, &w, &b, &dummy);
+                       if(w == changed || b == changed) appData.results[i] = ' '; // mark as not played
+                   }
+               }
+               WriteTourneyFile(appData.results, f);
+               fclose(f); // release lock
+               return;
+           }
+       } else DisplayError(_("No engine with the name you gave is installed"), 0);
+    }
+    if(changes == 0) DisplayError(_("First change an engine by editing the participants list\nof the Tournament Options dialog"), 0);
+    if(changes > 1)  DisplayError(_("You can only change one engine at the time"), 0);
+    free(participants);
+    return;
+}
+
 int
-CreateTourney(char *name)
+CreateTourney (char *name)
 {
        FILE *f;
+       if(matchMode && strcmp(name, appData.tourneyFile)) {
+            ASSIGN(name, appData.tourneyFile); //do not allow change of tourneyfile while playing
+       }
        if(name[0] == NULLCHAR) {
            if(appData.participants[0])
                DisplayError(_("You must supply a tournament file,\nfor storing the tourney progress"), 0);
@@ -9745,7 +9846,7 @@ CreateTourney(char *name)
            }
            ASSIGN(appData.tourneyFile, name);
            if(appData.tourneyType < 0) appData.defaultMatchGames = 1; // Swiss forces games/pairing = 1
-           if((f = WriteTourneyFile("")) == NULL) return 0;
+           if((f = WriteTourneyFile("", NULL)) == NULL) return 0;
        }
        fclose(f);
        appData.noChessProgram = FALSE;
@@ -9754,10 +9855,8 @@ CreateTourney(char *name)
        return 1;
 }
 
-#define MAXENGINES 1000
-char *command[MAXENGINES], *mnemonic[MAXENGINES];
-
-void NamesToList(char *names, char **engineList, char **engineMnemonic)
+void
+NamesToList (char *names, char **engineList, char **engineMnemonic)
 {
     char buf[MSG_SIZ], *p, *q;
     int i=1;
@@ -9779,13 +9878,14 @@ void NamesToList(char *names, char **engineList, char **engineMnemonic)
        names = p; i++;
       if(i > MAXENGINES - 2) break;
     }
-    engineList[i] = NULL;
+    engineList[i] = engineMnemonic[i] = NULL;
 }
 
 // following implemented as macro to avoid type limitations
 #define SWAP(item, temp) temp = appData.item[0]; appData.item[0] = appData.item[n]; appData.item[n] = temp;
 
-void SwapEngines(int n)
+void
+SwapEngines (int n)
 {   // swap settings for first engine and other engine (so far only some selected options)
     int h;
     char *p;
@@ -9801,10 +9901,11 @@ void SwapEngines(int n)
     SWAP(logo, p)
     SWAP(pgnName, p)
     SWAP(pvSAN, h)
+    SWAP(engOptions, p)
 }
 
 void
-SetPlayer(int player)
+SetPlayer (int player)
 {   // [HGM] find the engine line of the partcipant given by number, and parse its options.
     int i;
     char buf[MSG_SIZ], *engineName, *p = appData.participants;
@@ -9813,14 +9914,15 @@ SetPlayer(int player)
     for(i=1; command[i]; i++) if(!strcmp(mnemonic[i], engineName)) break;
     if(mnemonic[i]) {
        snprintf(buf, MSG_SIZ, "-fcp %s", command[i]);
-       ParseArgsFromString(resetOptions); appData.fenOverride[0] = NULL;
+       ParseArgsFromString(resetOptions); appData.fenOverride[0] = NULL; appData.pvSAN[0] = FALSE;
+       appData.firstHasOwnBookUCI = !appData.defNoBook; appData.protocolVersion[0] = PROTOVER;
        ParseArgsFromString(buf);
     }
     free(engineName);
 }
 
 int
-Pairing(int nr, int nPlayers, int *whitePlayer, int *blackPlayer, int *syncInterval)
+Pairing (int nr, int nPlayers, int *whitePlayer, int *blackPlayer, int *syncInterval)
 {   // determine players from game number
     int curCycle, curRound, curPairing, gamesPerCycle, gamesPerRound, roundsPerCycle=1, pairingsPerRound=1;
 
@@ -9855,6 +9957,9 @@ Pairing(int nr, int nPlayers, int *whitePlayer, int *blackPlayer, int *syncInter
            *blackPlayer = curRound + (nPlayers-1)/2 - curPairing;
            if(*blackPlayer >= nPlayers-1+(nPlayers&1)) *blackPlayer -= nPlayers-1+(nPlayers&1);
        }
+    } else if(appData.tourneyType > 1) {
+       *blackPlayer = curPairing; // in multi-gauntlet, assign gauntlet engines to second, so first an be kept loaded during round
+       *whitePlayer = curRound + appData.tourneyType;
     } else if(appData.tourneyType > 0) {
        *whitePlayer = curPairing;
        *blackPlayer = curRound + appData.tourneyType;
@@ -9866,7 +9971,7 @@ Pairing(int nr, int nPlayers, int *whitePlayer, int *blackPlayer, int *syncInter
 }
 
 int
-NextTourneyGame(int nr, int *swapColors)
+NextTourneyGame (int nr, int *swapColors)
 {   // !!!major kludge!!! fiddle appData settings to get everything in order for next tourney game
     char *p, *q;
     int whitePlayer, blackPlayer, firstBusy=1000000000, syncInterval = 0, nPlayers;
@@ -9916,38 +10021,45 @@ NextTourneyGame(int nr, int *swapColors)
        matchGame = 1; roundNr = nr / syncInterval + 1;
     }
 
-    if(first.pr != NoProc) return 1; // engines already loaded
+    if(first.pr != NoProc && second.pr != NoProc) return 1; // engines already loaded
 
     // redefine engines, engine dir, etc.
     NamesToList(firstChessProgramNames, command, mnemonic); // get mnemonics of installed engines
-    SetPlayer(whitePlayer); // find white player amongst it, and parse its engine line
-    SwapEngines(1);
-    SetPlayer(blackPlayer); // find black player amongst it, and parse its engine line
-    SwapEngines(1);         // and make that valid for second engine by swapping
-    InitEngine(&first, 0);  // initialize ChessProgramStates based on new settings.
-    InitEngine(&second, 1);
+    if(first.pr == NoProc || nr < 0) {
+      SetPlayer(whitePlayer); // find white player amongst it, and parse its engine line
+      InitEngine(&first, 0);  // initialize ChessProgramStates based on new settings.
+    }
+    if(second.pr == NoProc) {
+      SwapEngines(1);
+      SetPlayer(blackPlayer); // find black player amongst it, and parse its engine line
+      SwapEngines(1);         // and make that valid for second engine by swapping
+      InitEngine(&second, 1);
+    }
     CommonEngineInit();     // after this TwoMachinesEvent will create correct engine processes
     UpdateLogos(FALSE);     // leave display to ModeHiglight()
     return 1;
 }
 
 void
-NextMatchGame()
+NextMatchGame ()
 {   // performs game initialization that does not invoke engines, and then tries to start the game
-    int firstWhite, swapColors = 0;
+    int res, firstWhite, swapColors = 0;
     if(!NextTourneyGame(nextGame, &swapColors)) return; // this sets matchGame, -fcp / -scp and other options for next game, if needed
     firstWhite = appData.firstPlaysBlack ^ (matchGame & 1 | appData.sameColorGames > 1); // non-incremental default
     firstWhite ^= swapColors; // reverses if NextTourneyGame says we are in an odd round
     first.twoMachinesColor =  firstWhite ? "white\n" : "black\n";   // perform actual color assignement
     second.twoMachinesColor = firstWhite ? "black\n" : "white\n";
     appData.noChessProgram = (first.pr == NoProc); // kludge to prevent Reset from starting up chess program
+    if(appData.loadGameIndex == -2) srandom(appData.seedBase + 68163*(nextGame & ~1)); // deterministic seed to force same opening
     Reset(FALSE, first.pr != NoProc);
-    appData.noChessProgram = FALSE;
-    if(!LoadGameOrPosition(matchGame)) return; // setup game; abort when bad game/pos file
+    res = LoadGameOrPosition(matchGame); // setup game
+    appData.noChessProgram = FALSE; // LoadGameOrPosition might call Reset too!
+    if(!res) return; // abort when bad game/pos file
     TwoMachinesEvent();
 }
 
-void UserAdjudicationEvent( int result )
+void
+UserAdjudicationEvent (int result)
 {
     ChessMove gameResult = GameIsDrawn;
 
@@ -9965,7 +10077,8 @@ void UserAdjudicationEvent( int result )
 
 
 // [HGM] save: calculate checksum of game to make games easily identifiable
-int StringCheckSum(char *s)
+int
+StringCheckSum (char *s)
 {
        int i = 0;
        if(s==NULL) return 0;
@@ -9973,7 +10086,8 @@ int StringCheckSum(char *s)
        return i;
 }
 
-int GameCheckSum()
+int
+GameCheckSum ()
 {
        int i, sum=0;
        for(i=backwardMostMove; i<forwardMostMove; i++) {
@@ -9987,10 +10101,7 @@ int GameCheckSum()
 } // end of save patch
 
 void
-GameEnds(result, resultDetails, whosays)
-     ChessMove result;
-     char *resultDetails;
-     int whosays;
+GameEnds (ChessMove result, char *resultDetails, int whosays)
 {
     GameMode nextGameMode;
     int isIcsGame;
@@ -10130,7 +10241,7 @@ GameEnds(result, resultDetails, whosays)
             if(result==WhiteWins) c = '+';
             if(result==BlackWins) c = '-';
             if(resultDetails != NULL)
-                fprintf(serverMoves, ";%c;%s\n", c, resultDetails);
+                fprintf(serverMoves, ";%c;%s\n", c, resultDetails), fflush(serverMoves);
         }
        if (resultDetails != NULL) {
            gameInfo.result = result;
@@ -10324,6 +10435,7 @@ GameEnds(result, resultDetails, whosays)
 
        if(waitingForGame) resChar = ' '; // quit while waiting for round sync: unreserve already reserved game
        if(appData.tourneyFile[0]){ // [HGM] we are in a tourney; update tourney file with game result
+           if(appData.afterGame && appData.afterGame[0]) RunCommand(appData.afterGame);
            ReserveGame(nextGame, resChar); // sets nextGame
            if(nextGame > appData.matchGames) appData.tourneyFile[0] = 0, ranking = TourneyStandings(3); // tourney is done
            else ranking = strdup("busy"); //suppress popup when aborted but not finished
@@ -10343,6 +10455,7 @@ GameEnds(result, resultDetails, whosays)
                     first.matchWins, second.matchWins,
                     appData.matchGames - (first.matchWins + second.matchWins));
            if(!appData.tourneyFile[0]) matchGame++, DisplayTwoMachinesTitle(); // [HGM] update result in window title
+           if(ranking && strcmp(ranking, "busy") && appData.afterTourney && appData.afterTourney[0]) RunCommand(appData.afterTourney);
            popupRequested++; // [HGM] crash: postpone to after resetting endingGame
            if (appData.firstPlaysBlack) { // [HGM] match: back to original for next match
                first.twoMachinesColor = "black\n";
@@ -10380,9 +10493,7 @@ GameEnds(result, resultDetails, whosays)
 /* Assumes program was just initialized (initString sent).
    Leaves program in force mode. */
 void
-FeedMovesToProgram(cps, upto)
-     ChessProgramState *cps;
-     int upto;
+FeedMovesToProgram (ChessProgramState *cps, int upto)
 {
     int i;
 
@@ -10413,7 +10524,7 @@ FeedMovesToProgram(cps, upto)
 
 
 int
-ResurrectChessProgram()
+ResurrectChessProgram ()
 {
      /* The chess program may have exited.
        If so, restart it and feed it all the moves made so far. */
@@ -10452,8 +10563,7 @@ ResurrectChessProgram()
  * Button procedures
  */
 void
-Reset(redraw, init)
-     int redraw, init;
+Reset (int redraw, int init)
 {
     int i;
 
@@ -10510,6 +10620,7 @@ Reset(redraw, init)
     ModeHighlight();
     if(appData.icsActive) gameInfo.variant = VariantNormal;
     currentMove = forwardMostMove = backwardMostMove = 0;
+    MarkTargetSquares(1);
     InitPosition(redraw);
     for (i = 0; i < MAX_MOVES; i++) {
        if (commentList[i] != NULL) {
@@ -10521,7 +10632,7 @@ Reset(redraw, init)
     timeRemaining[0][0] = whiteTimeRemaining;
     timeRemaining[1][0] = blackTimeRemaining;
 
-    if (first.pr == NULL) {
+    if (first.pr == NoProc) {
        StartChessProgram(&first);
     }
     if (init) {
@@ -10534,7 +10645,7 @@ Reset(redraw, init)
 }
 
 void
-AutoPlayGameLoop()
+AutoPlayGameLoop ()
 {
     for (;;) {
        if (!AutoPlayOneMove())
@@ -10550,7 +10661,7 @@ AutoPlayGameLoop()
 
 
 int
-AutoPlayOneMove()
+AutoPlayOneMove ()
 {
     int fromX, fromY, toX, toY;
 
@@ -10570,8 +10681,8 @@ AutoPlayOneMove()
 
     if (currentMove >= forwardMostMove) {
       if(gameMode == AnalyzeFile) { ExitAnalyzeMode(); SendToProgram("force\n", &first); }
-      gameMode = EditGame;
-      ModeHighlight();
+//      gameMode = EndOfGame;
+//      ModeHighlight();
 
       /* [AS] Clear current move marker at the end of a game */
       /* HistorySet(parseList, backwardMostMove, forwardMostMove, -1); */
@@ -10609,8 +10720,7 @@ AutoPlayOneMove()
 
 
 int
-LoadGameOneMove(readAhead)
-     ChessMove readAhead;
+LoadGameOneMove (ChessMove readAhead)
 {
     int fromX = 0, fromY = 0, toX = 0, toY = 0, done;
     char promoChar = NULLCHAR;
@@ -10845,11 +10955,7 @@ LoadGameOneMove(readAhead)
 
 /* Load the nth game from the given file */
 int
-LoadGameFromFile(filename, n, title, useList)
-     char *filename;
-     int n;
-     char *title;
-     /*Boolean*/ int useList;
+LoadGameFromFile (char *filename, int n, char *title, int useList)
 {
     FILE *f;
     char buf[MSG_SIZ];
@@ -10887,7 +10993,7 @@ LoadGameFromFile(filename, n, title, useList)
 
 
 void
-MakeRegisteredMove()
+MakeRegisteredMove ()
 {
     int fromX, fromY, toX, toY;
     char promoChar;
@@ -10952,11 +11058,7 @@ MakeRegisteredMove()
 
 /* 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;
+CmailLoadGame (FILE *f, int gameNumber, char *title, int useList)
 {
     int retVal;
 
@@ -10997,8 +11099,7 @@ CmailLoadGame(f, gameNumber, title, useList)
 
 /* Support for LoadNextGame, LoadPreviousGame, ReloadSameGame */
 int
-ReloadGame(offset)
-     int offset;
+ReloadGame (int offset)
 {
     int gameNumber = lastLoadGameNumber + offset;
     if (lastLoadGameFP == NULL) {
@@ -11018,22 +11119,379 @@ ReloadGame(offset)
     }
 }
 
+int keys[EmptySquare+1];
 
+int
+PositionMatches (Board b1, Board b2)
+{
+    int r, f, sum=0;
+    switch(appData.searchMode) {
+       case 1: return CompareWithRights(b1, b2);
+       case 2:
+           for(r=0; r<BOARD_HEIGHT; r++) for(f=BOARD_LEFT; f<BOARD_RGHT; f++) {
+               if(b2[r][f] != EmptySquare && b1[r][f] != b2[r][f]) return FALSE;
+           }
+           return TRUE;
+       case 3:
+           for(r=0; r<BOARD_HEIGHT; r++) for(f=BOARD_LEFT; f<BOARD_RGHT; f++) {
+             if((b2[r][f] == WhitePawn || b2[r][f] == BlackPawn) && b1[r][f] != b2[r][f]) return FALSE;
+               sum += keys[b1[r][f]] - keys[b2[r][f]];
+           }
+           return sum==0;
+       case 4:
+           for(r=0; r<BOARD_HEIGHT; r++) for(f=BOARD_LEFT; f<BOARD_RGHT; f++) {
+               sum += keys[b1[r][f]] - keys[b2[r][f]];
+           }
+           return sum==0;
+    }
+    return TRUE;
+}
+
+#define Q_PROMO  4
+#define Q_EP     3
+#define Q_BCASTL 2
+#define Q_WCASTL 1
+
+int pieceList[256], quickBoard[256];
+ChessSquare pieceType[256] = { EmptySquare };
+Board soughtBoard, reverseBoard, flipBoard, rotateBoard;
+int counts[EmptySquare], minSought[EmptySquare], minReverse[EmptySquare], maxSought[EmptySquare], maxReverse[EmptySquare];
+int soughtTotal, turn;
+Boolean epOK, flipSearch;
+
+typedef struct {
+    unsigned char piece, to;
+} Move;
+
+#define DSIZE (250000)
+
+Move initialSpace[DSIZE+1000]; // gamble on that game will not be more than 500 moves
+Move *moveDatabase = initialSpace;
+unsigned int movePtr, dataSize = DSIZE;
+
+int
+MakePieceList (Board board, int *counts)
+{
+    int r, f, n=Q_PROMO, total=0;
+    for(r=0;r<EmptySquare;r++) counts[r] = 0; // piece-type counts
+    for(r=0; r<BOARD_HEIGHT; r++) for(f=BOARD_LEFT; f<BOARD_RGHT; f++) {
+       int sq = f + (r<<4);
+        if(board[r][f] == EmptySquare) quickBoard[sq] = 0; else {
+           quickBoard[sq] = ++n;
+           pieceList[n] = sq;
+           pieceType[n] = board[r][f];
+           counts[board[r][f]]++;
+           if(board[r][f] == WhiteKing) pieceList[1] = n; else
+           if(board[r][f] == BlackKing) pieceList[2] = n; // remember which are Kings, for castling
+           total++;
+       }
+    }
+    epOK = gameInfo.variant != VariantXiangqi && gameInfo.variant != VariantBerolina;
+    return total;
+}
+
+void
+PackMove (int fromX, int fromY, int toX, int toY, ChessSquare promoPiece)
+{
+    int sq = fromX + (fromY<<4);
+    int piece = quickBoard[sq];
+    quickBoard[sq] = 0;
+    moveDatabase[movePtr].to = pieceList[piece] = sq = toX + (toY<<4);
+    if(piece == pieceList[1] && fromY == toY && (toX > fromX+1 || toX < fromX-1) && fromX != BOARD_LEFT && fromX != BOARD_RGHT-1) {
+       int from = toX>fromX ? BOARD_RGHT-1 : BOARD_LEFT;
+       moveDatabase[movePtr++].piece = Q_WCASTL;
+       quickBoard[sq] = piece;
+       piece = quickBoard[from]; quickBoard[from] = 0;
+       moveDatabase[movePtr].to = pieceList[piece] = sq = toX>fromX ? sq-1 : sq+1;
+    } else
+    if(piece == pieceList[2] && fromY == toY && (toX > fromX+1 || toX < fromX-1) && fromX != BOARD_LEFT && fromX != BOARD_RGHT-1) {
+       int from = (toX>fromX ? BOARD_RGHT-1 : BOARD_LEFT) + (BOARD_HEIGHT-1 <<4);
+       moveDatabase[movePtr++].piece = Q_BCASTL;
+       quickBoard[sq] = piece;
+       piece = quickBoard[from]; quickBoard[from] = 0;
+       moveDatabase[movePtr].to = pieceList[piece] = sq = toX>fromX ? sq-1 : sq+1;
+    } else
+    if(epOK && (pieceType[piece] == WhitePawn || pieceType[piece] == BlackPawn) && fromX != toX && quickBoard[sq] == 0) {
+       quickBoard[(fromY<<4)+toX] = 0;
+       moveDatabase[movePtr].piece = Q_EP;
+       moveDatabase[movePtr++].to = (fromY<<4)+toX;
+       moveDatabase[movePtr].to = sq;
+    } else
+    if(promoPiece != pieceType[piece]) {
+       moveDatabase[movePtr++].piece = Q_PROMO;
+       moveDatabase[movePtr].to = pieceType[piece] = (int) promoPiece;
+    }
+    moveDatabase[movePtr].piece = piece;
+    quickBoard[sq] = piece;
+    movePtr++;
+}
+
+int
+PackGame (Board board)
+{
+    Move *newSpace = NULL;
+    moveDatabase[movePtr].piece = 0; // terminate previous game
+    if(movePtr > dataSize) {
+       if(appData.debugMode) fprintf(debugFP, "move-cache overflow, enlarge to %d MB\n", dataSize/128);
+       dataSize *= 8; // increase size by factor 8 (512KB -> 4MB -> 32MB -> 256MB -> 2GB)
+       if(dataSize) newSpace = (Move*) calloc(dataSize + 1000, sizeof(Move));
+       if(newSpace) {
+           int i;
+           Move *p = moveDatabase, *q = newSpace;
+           for(i=0; i<movePtr; i++) *q++ = *p++;    // copy to newly allocated space
+           if(dataSize > 8*DSIZE) free(moveDatabase); // and free old space (if it was allocated)
+           moveDatabase = newSpace;
+       } else { // calloc failed, we must be out of memory. Too bad...
+           dataSize = 0; // prevent calloc events for all subsequent games
+           return 0;     // and signal this one isn't cached
+       }
+    }
+    movePtr++;
+    MakePieceList(board, counts);
+    return movePtr;
+}
+
+int
+QuickCompare (Board board, int *minCounts, int *maxCounts)
+{   // compare according to search mode
+    int r, f;
+    switch(appData.searchMode)
+    {
+      case 1: // exact position match
+       if(!(turn & board[EP_STATUS-1])) return FALSE; // wrong side to move
+       for(r=0; r<BOARD_HEIGHT; r++) for(f=BOARD_LEFT; f<BOARD_RGHT; f++) {
+           if(board[r][f] != pieceType[quickBoard[(r<<4)+f]]) return FALSE;
+       }
+       break;
+      case 2: // can have extra material on empty squares
+       for(r=0; r<BOARD_HEIGHT; r++) for(f=BOARD_LEFT; f<BOARD_RGHT; f++) {
+           if(board[r][f] == EmptySquare) continue;
+           if(board[r][f] != pieceType[quickBoard[(r<<4)+f]]) return FALSE;
+       }
+       break;
+      case 3: // material with exact Pawn structure
+       for(r=0; r<BOARD_HEIGHT; r++) for(f=BOARD_LEFT; f<BOARD_RGHT; f++) {
+           if(board[r][f] != WhitePawn && board[r][f] != BlackPawn) continue;
+           if(board[r][f] != pieceType[quickBoard[(r<<4)+f]]) return FALSE;
+       } // fall through to material comparison
+      case 4: // exact material
+       for(r=0; r<EmptySquare; r++) if(counts[r] != maxCounts[r]) return FALSE;
+       break;
+      case 6: // material range with given imbalance
+       for(r=0; r<BlackPawn; r++) if(counts[r] - minCounts[r] != counts[r+BlackPawn] - minCounts[r+BlackPawn]) return FALSE;
+       // fall through to range comparison
+      case 5: // material range
+       for(r=0; r<EmptySquare; r++) if(counts[r] < minCounts[r] || counts[r] > maxCounts[r]) return FALSE;
+    }
+    return TRUE;
+}
+
+int
+QuickScan (Board board, Move *move)
+{   // reconstruct game,and compare all positions in it
+    int cnt=0, stretch=0, total = MakePieceList(board, counts);
+    do {
+       int piece = move->piece;
+       int to = move->to, from = pieceList[piece];
+       if(piece <= Q_PROMO) { // special moves encoded by otherwise invalid piece numbers 1-4
+         if(!piece) return -1;
+         if(piece == Q_PROMO) { // promotion, encoded as (Q_PROMO, to) + (piece, promoType)
+           piece = (++move)->piece;
+           from = pieceList[piece];
+           counts[pieceType[piece]]--;
+           pieceType[piece] = (ChessSquare) move->to;
+           counts[move->to]++;
+         } else if(piece == Q_EP) { // e.p. capture, encoded as (Q_EP, ep-sqr) + (piece, to)
+           counts[pieceType[quickBoard[to]]]--;
+           quickBoard[to] = 0; total--;
+           move++;
+           continue;
+         } else if(piece <= Q_BCASTL) { // castling, encoded as (Q_XCASTL, king-to) + (rook, rook-to)
+           piece = pieceList[piece]; // first two elements of pieceList contain King numbers
+           from  = pieceList[piece]; // so this must be King
+           quickBoard[from] = 0;
+           quickBoard[to] = piece;
+           pieceList[piece] = to;
+           move++;
+           continue;
+         }
+       }
+       if(appData.searchMode > 2) counts[pieceType[quickBoard[to]]]--; // account capture
+       if((total -= (quickBoard[to] != 0)) < soughtTotal) return -1; // piece count dropped below what we search for
+       quickBoard[from] = 0;
+       quickBoard[to] = piece;
+       pieceList[piece] = to;
+       cnt++; turn ^= 3;
+       if(QuickCompare(soughtBoard, minSought, maxSought) ||
+          appData.ignoreColors && QuickCompare(reverseBoard, minReverse, maxReverse) ||
+          flipSearch && (QuickCompare(flipBoard, minSought, maxSought) ||
+                               appData.ignoreColors && QuickCompare(rotateBoard, minReverse, maxReverse))
+         ) {
+           static int lastCounts[EmptySquare+1];
+           int i;
+           if(stretch) for(i=0; i<EmptySquare; i++) if(lastCounts[i] != counts[i]) { stretch = 0; break; } // reset if material changes
+           if(stretch++ == 0) for(i=0; i<EmptySquare; i++) lastCounts[i] = counts[i]; // remember actual material
+       } else stretch = 0;
+       if(stretch && (appData.searchMode == 1 || stretch >= appData.stretch)) return cnt + 1 - stretch;
+       move++;
+    } while(1);
+}
+
+void
+InitSearch ()
+{
+    int r, f;
+    flipSearch = FALSE;
+    CopyBoard(soughtBoard, boards[currentMove]);
+    soughtTotal = MakePieceList(soughtBoard, maxSought);
+    soughtBoard[EP_STATUS-1] = (currentMove & 1) + 1;
+    if(currentMove == 0 && gameMode == EditPosition) soughtBoard[EP_STATUS-1] = blackPlaysFirst + 1; // (!)
+    CopyBoard(reverseBoard, boards[currentMove]);
+    for(r=0; r<BOARD_HEIGHT; r++) for(f=BOARD_LEFT; f<BOARD_RGHT; f++) {
+       int piece = boards[currentMove][BOARD_HEIGHT-1-r][f];
+       if(piece < BlackPawn) piece += BlackPawn; else if(piece < EmptySquare) piece -= BlackPawn; // color-flip
+       reverseBoard[r][f] = piece;
+    }
+    reverseBoard[EP_STATUS-1] = soughtBoard[EP_STATUS-1] ^ 3; 
+    for(r=0; r<6; r++) reverseBoard[CASTLING][r] = boards[currentMove][CASTLING][(r+3)%6];
+    if(appData.findMirror && appData.searchMode <= 3 && (!nrCastlingRights
+                || (boards[currentMove][CASTLING][2] == NoRights || 
+                    boards[currentMove][CASTLING][0] == NoRights && boards[currentMove][CASTLING][1] == NoRights )
+                && (boards[currentMove][CASTLING][5] == NoRights || 
+                    boards[currentMove][CASTLING][3] == NoRights && boards[currentMove][CASTLING][4] == NoRights ) )
+      ) {
+       flipSearch = TRUE;
+       CopyBoard(flipBoard, soughtBoard);
+       CopyBoard(rotateBoard, reverseBoard);
+       for(r=0; r<BOARD_HEIGHT; r++) for(f=BOARD_LEFT; f<BOARD_RGHT; f++) {
+           flipBoard[r][f]    = soughtBoard[r][BOARD_WIDTH-1-f];
+           rotateBoard[r][f] = reverseBoard[r][BOARD_WIDTH-1-f];
+       }
+    }
+    for(r=0; r<BlackPawn; r++) maxReverse[r] = maxSought[r+BlackPawn], maxReverse[r+BlackPawn] = maxSought[r];
+    if(appData.searchMode >= 5) {
+       for(r=BOARD_HEIGHT/2; r<BOARD_HEIGHT; r++) for(f=BOARD_LEFT; f<BOARD_RGHT; f++) soughtBoard[r][f] = EmptySquare;
+       MakePieceList(soughtBoard, minSought);
+       for(r=0; r<BlackPawn; r++) minReverse[r] = minSought[r+BlackPawn], minReverse[r+BlackPawn] = minSought[r];
+    }
+    if(gameInfo.variant == VariantCrazyhouse || gameInfo.variant == VariantShogi || gameInfo.variant == VariantBughouse)
+       soughtTotal = 0; // in drop games nr of pieces does not fall monotonously
+}
+
+GameInfo dummyInfo;
+
+int
+GameContainsPosition (FILE *f, ListGame *lg)
+{
+    int next, btm=0, plyNr=0, scratch=forwardMostMove+2&~1;
+    int fromX, fromY, toX, toY;
+    char promoChar;
+    static int initDone=FALSE;
+
+    // weed out games based on numerical tag comparison
+    if(lg->gameInfo.variant != gameInfo.variant) return -1; // wrong variant
+    if(appData.eloThreshold1 && (lg->gameInfo.whiteRating < appData.eloThreshold1 && lg->gameInfo.blackRating < appData.eloThreshold1)) return -1;
+    if(appData.eloThreshold2 && (lg->gameInfo.whiteRating < appData.eloThreshold2 || lg->gameInfo.blackRating < appData.eloThreshold2)) return -1;
+    if(appData.dateThreshold && (!lg->gameInfo.date || atoi(lg->gameInfo.date) < appData.dateThreshold)) return -1;
+    if(!initDone) {
+       for(next = WhitePawn; next<EmptySquare; next++) keys[next] = random()>>8 ^ random()<<6 ^random()<<20;
+       initDone = TRUE;
+    }
+    if(lg->gameInfo.fen) ParseFEN(boards[scratch], &btm, lg->gameInfo.fen);
+    else CopyBoard(boards[scratch], initialPosition); // default start position
+    if(lg->moves) {
+       turn = btm + 1;
+       if((next = QuickScan( boards[scratch], &moveDatabase[lg->moves] )) < 0) return -1; // quick scan rules out it is there
+       if(appData.searchMode >= 4) return next; // for material searches, trust QuickScan.
+    }
+    if(btm) plyNr++;
+    if(PositionMatches(boards[scratch], boards[currentMove])) return plyNr;
+    fseek(f, lg->offset, 0);
+    yynewfile(f);
+    while(1) {
+       yyboardindex = scratch;
+       quickFlag = plyNr+1;
+       next = Myylex();
+       quickFlag = 0;
+       switch(next) {
+           case PGNTag:
+               if(plyNr) return -1; // after we have seen moves, any tags will be start of next game
+           default:
+               continue;
+
+           case XBoardGame:
+           case GNUChessGame:
+               if(plyNr) return -1; // after we have seen moves, this is for new game
+             continue;
+
+           case AmbiguousMove: // we cannot reconstruct the game beyond these two
+           case ImpossibleMove:
+           case WhiteWins: // game ends here with these four
+           case BlackWins:
+           case GameIsDrawn:
+           case GameUnfinished:
+               return -1;
+
+           case IllegalMove:
+               if(appData.testLegality) return -1;
+           case WhiteCapturesEnPassant:
+           case BlackCapturesEnPassant:
+           case WhitePromotion:
+           case BlackPromotion:
+           case WhiteNonPromotion:
+           case BlackNonPromotion:
+           case NormalMove:
+           case WhiteKingSideCastle:
+           case WhiteQueenSideCastle:
+           case BlackKingSideCastle:
+           case BlackQueenSideCastle:
+           case WhiteKingSideCastleWild:
+           case WhiteQueenSideCastleWild:
+           case BlackKingSideCastleWild:
+           case BlackQueenSideCastleWild:
+           case WhiteHSideCastleFR:
+           case WhiteASideCastleFR:
+           case BlackHSideCastleFR:
+           case BlackASideCastleFR:
+               fromX = currentMoveString[0] - AAA;
+               fromY = currentMoveString[1] - ONE;
+               toX = currentMoveString[2] - AAA;
+               toY = currentMoveString[3] - ONE;
+               promoChar = currentMoveString[4];
+               break;
+           case WhiteDrop:
+           case BlackDrop:
+               fromX = next == WhiteDrop ?
+                 (int) CharToPiece(ToUpper(currentMoveString[0])) :
+                 (int) CharToPiece(ToLower(currentMoveString[0]));
+               fromY = DROP_RANK;
+               toX = currentMoveString[2] - AAA;
+               toY = currentMoveString[3] - ONE;
+               promoChar = 0;
+               break;
+       }
+       // Move encountered; peform it. We need to shuttle between two boards, as even/odd index determines side to move
+       plyNr++;
+       ApplyMove(fromX, fromY, toX, toY, promoChar, boards[scratch]);
+       if(PositionMatches(boards[scratch], boards[currentMove])) return plyNr;
+       if(appData.ignoreColors && PositionMatches(boards[scratch], reverseBoard)) return plyNr;
+       if(appData.findMirror) {
+           if(PositionMatches(boards[scratch], flipBoard)) return plyNr;
+           if(appData.ignoreColors && PositionMatches(boards[scratch], rotateBoard)) return plyNr;
+       }
+    }
+}
 
 /* Load the nth game from open file f */
 int
-LoadGame(f, gameNumber, title, useList)
-     FILE *f;
-     int gameNumber;
-     char *title;
-     int useList;
+LoadGame (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;
+    int err, pos = -1;
     GameMode oldGameMode;
     VariantClass oldVariant = gameInfo.variant; /* [HGM] PGNvariant */
 
@@ -11059,6 +11517,7 @@ LoadGame(f, gameNumber, title, useList)
        if (lg) {
            fseek(f, lg->offset, 0);
            GameListHighlight(gameNumber);
+           pos = lg->position;
            gn = 1;
        }
        else {
@@ -11086,7 +11545,7 @@ LoadGame(f, gameNumber, title, useList)
     yynewfile(f);
 
     if (lg && lg->gameInfo.white && lg->gameInfo.black) {
-      snprintf(buf, sizeof(buf), "%s vs. %s", lg->gameInfo.white,
+      snprintf(buf, sizeof(buf), "%s %s %s", lg->gameInfo.white, _("vs."),
                lg->gameInfo.black);
            DisplayTitle(buf);
     } else if (*title != NULLCHAR) {
@@ -11458,10 +11917,11 @@ LoadGame(f, gameNumber, title, useList)
       AnalyzeFileEvent();
     }
 
+    if (!matchMode && pos >= 0) {
+       ToNrEvent(pos); // [HGM] no autoplay if selected on position
+    } else
     if (matchMode || appData.timeDelay == 0) {
       ToEndEvent();
-      gameMode = EditGame;
-      ModeHighlight();
     } else if (appData.timeDelay > 0) {
       AutoPlayGameLoop();
     }
@@ -11475,8 +11935,7 @@ LoadGame(f, gameNumber, title, useList)
 
 /* Support for LoadNextPosition, LoadPreviousPosition, ReloadSamePosition */
 int
-ReloadPosition(offset)
-     int offset;
+ReloadPosition (int offset)
 {
     int positionNumber = lastLoadPositionNumber + offset;
     if (lastLoadPositionFP == NULL) {
@@ -11493,10 +11952,7 @@ ReloadPosition(offset)
 
 /* Load the nth position from the given file */
 int
-LoadPositionFromFile(filename, n, title)
-     char *filename;
-     int n;
-     char *title;
+LoadPositionFromFile (char *filename, int n, char *title)
 {
     FILE *f;
     char buf[MSG_SIZ];
@@ -11517,10 +11973,7 @@ LoadPositionFromFile(filename, 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;
+LoadPosition (FILE *f, int positionNumber, char *title)
 {
     char *p, line[MSG_SIZ];
     Board initial_position;
@@ -11539,7 +11992,7 @@ LoadPosition(f, positionNumber, title)
     lastLoadPositionFP = f;
     lastLoadPositionNumber = positionNumber;
     safeStrCpy(lastLoadPositionTitle, title, sizeof(lastLoadPositionTitle)/sizeof(lastLoadPositionTitle[0]));
-    if (first.pr == NoProc) {
+    if (first.pr == NoProc && !appData.noChessProgram) {
       StartChessProgram(&first);
       InitChessProgram(&first, FALSE);
     }
@@ -11611,7 +12064,6 @@ LoadPosition(f, positionNumber, title)
     }
     startedFromSetupPosition = TRUE;
 
-    SendToProgram("force\n", &first);
     CopyBoard(boards[0], initial_position);
     if (blackPlaysFirst) {
        currentMove = forwardMostMove = backwardMostMove = 1;
@@ -11624,7 +12076,10 @@ LoadPosition(f, positionNumber, title)
        DisplayMessage("", _("White to play"));
     }
     initialRulePlies = FENrulePlies; /* [HGM] copy FEN attributes as well */
-    SendBoard(&first, forwardMostMove);
+    if(first.pr != NoProc) { // [HGM] in tourney-mode a position can be loaded before the chess engine is installed
+       SendToProgram("force\n", &first);
+       SendBoard(&first, forwardMostMove);
+    }
     if (appData.debugMode) {
 int i, j;
   for(i=0;i<2;i++){for(j=0;j<6;j++)fprintf(debugFP, " %d", boards[i][CASTLING][j]);fprintf(debugFP,"\n");}
@@ -11650,8 +12105,7 @@ int i, j;
 
 
 void
-CopyPlayerNameIntoFileName(dest, src)
-     char **dest, *src;
+CopyPlayerNameIntoFileName (char **dest, char *src)
 {
     while (*src != NULLCHAR && *src != ',') {
        if (*src == ' ') {
@@ -11663,8 +12117,8 @@ CopyPlayerNameIntoFileName(dest, src)
     }
 }
 
-char *DefaultFileName(ext)
-     char *ext;
+char *
+DefaultFileName (char *ext)
 {
     static char def[MSG_SIZ];
     char *p;
@@ -11684,18 +12138,22 @@ char *DefaultFileName(ext)
 
 /* Save the current game to the given file */
 int
-SaveGameToFile(filename, append)
-     char *filename;
-     int append;
+SaveGameToFile (char *filename, int append)
 {
     FILE *f;
     char buf[MSG_SIZ];
-    int result;
+    int result, i, t,tot=0;
 
     if (strcmp(filename, "-") == 0) {
        return SaveGame(stdout, 0, NULL);
     } else {
-       f = fopen(filename, append ? "a" : "w");
+       for(i=0; i<10; i++) { // upto 10 tries
+            f = fopen(filename, append ? "a" : "w");
+            if(f && i) fprintf(f, "[Delay \"%d retries, %d msec\"]\n",i,tot);
+            if(f || errno != 13) break;
+            DoSleep(t = 5 + random()%11); // wait 5-15 msec
+            tot += t;
+       }
        if (f == NULL) {
            snprintf(buf, sizeof(buf), _("Can't open \"%s\""), filename);
            DisplayError(buf, errno);
@@ -11705,7 +12163,7 @@ SaveGameToFile(filename, append)
            DisplayMessage(_("Waiting for access to save file"), "");
            flock(fileno(f), LOCK_EX); // [HGM] lock: lock file while we are writing
            DisplayMessage(_("Saving game"), "");
-           if(lseek(fileno(f), 0, SEEK_END) == -1) DisplayError("Bad Seek", errno);     // better safe than sorry...
+           if(lseek(fileno(f), 0, SEEK_END) == -1) DisplayError(_("Bad Seek"), errno);     // better safe than sorry...
            result = SaveGame(f, 0, NULL);
            DisplayMessage(buf, "");
            return result;
@@ -11714,8 +12172,7 @@ SaveGameToFile(filename, append)
 }
 
 char *
-SavePart(str)
-     char *str;
+SavePart (char *str)
 {
     static char buf[MSG_SIZ];
     char *p;
@@ -11732,8 +12189,8 @@ SavePart(str)
 #define PGN_SIDE_WHITE  0
 #define PGN_SIDE_BLACK  1
 
-/* [AS] */
-static int FindFirstMoveOutOfBook( int side )
+static int
+FindFirstMoveOutOfBook (int side)
 {
     int result = -1;
 
@@ -11776,8 +12233,8 @@ static int FindFirstMoveOutOfBook( int side )
     return result;
 }
 
-/* [AS] */
-void GetOutOfBookInfo( char * buf )
+void
+GetOutOfBookInfo (char * buf)
 {
     int oob[2];
     int i;
@@ -11808,8 +12265,7 @@ void GetOutOfBookInfo( char * buf )
 
 /* Save game in PGN style and close the file */
 int
-SaveGamePGN(f)
-     FILE *f;
+SaveGamePGN (FILE *f)
 {
     int i, offset, linelen, newblock;
     time_t tm;
@@ -11975,8 +12431,7 @@ SaveGamePGN(f)
 
 /* Save game in old style and close the file */
 int
-SaveGameOldStyle(f)
-     FILE *f;
+SaveGameOldStyle (FILE *f)
 {
     int i, offset;
     time_t tm;
@@ -12040,10 +12495,7 @@ SaveGameOldStyle(f)
 
 /* Save the current game to open file f and close the file */
 int
-SaveGame(f, dummy, dummy2)
-     FILE *f;
-     int dummy;
-     char *dummy2;
+SaveGame (FILE *f, int dummy, char *dummy2)
 {
     if (gameMode == EditPosition) EditPositionDone(TRUE);
     lastSavedGame = GameCheckSum(); // [HGM] save: remember ID of last saved game to prevent double saving
@@ -12055,8 +12507,7 @@ SaveGame(f, dummy, dummy2)
 
 /* Save the current position to the given file */
 int
-SavePositionToFile(filename)
-     char *filename;
+SavePositionToFile (char *filename)
 {
     FILE *f;
     char buf[MSG_SIZ];
@@ -12084,10 +12535,7 @@ SavePositionToFile(filename)
 
 /* Save the current position to the given open file and close the file */
 int
-SavePosition(f, dummy, dummy2)
-     FILE *f;
-     int dummy;
-     char *dummy2;
+SavePosition (FILE *f, int dummy, char *dummy2)
 {
     time_t tm;
     char *fen;
@@ -12111,8 +12559,7 @@ SavePosition(f, dummy, dummy2)
 }
 
 void
-ReloadCmailMsgEvent(unregister)
-     int unregister;
+ReloadCmailMsgEvent (int unregister)
 {
 #if !WIN32
     static char *inFilename = NULL;
@@ -12178,7 +12625,7 @@ ReloadCmailMsgEvent(unregister)
 }
 
 int
-RegisterMove()
+RegisterMove ()
 {
     FILE *f;
     char string[MSG_SIZ];
@@ -12268,7 +12715,7 @@ RegisterMove()
 }
 
 void
-MailMoveEvent()
+MailMoveEvent ()
 {
 #if !WIN32
     static char *partCommandString = "cmail -xv%s -remail -game %s 2>&1";
@@ -12356,7 +12803,7 @@ MailMoveEvent()
 }
 
 char *
-CmailMsg()
+CmailMsg ()
 {
 #if WIN32
     return NULL;
@@ -12429,7 +12876,7 @@ CmailMsg()
 }
 
 void
-ResetGameEvent()
+ResetGameEvent ()
 {
     if (gameMode == Training)
       SetTrainingModeOff();
@@ -12443,8 +12890,7 @@ ResetGameEvent()
 }
 
 void
-ExitEvent(status)
-     int status;
+ExitEvent (int status)
 {
     exiting++;
     if (exiting > 2) {
@@ -12506,7 +12952,7 @@ ExitEvent(status)
 }
 
 void
-PauseEvent()
+PauseEvent ()
 {
     if (appData.debugMode)
        fprintf(debugFP, "PauseEvent(): pausing %d\n", pausing);
@@ -12571,7 +13017,7 @@ PauseEvent()
 }
 
 void
-EditCommentEvent()
+EditCommentEvent ()
 {
     char title[MSG_SIZ];
 
@@ -12588,7 +13034,7 @@ EditCommentEvent()
 
 
 void
-EditTagsEvent()
+EditTagsEvent ()
 {
     char *tags = PGNTags(&gameInfo);
     bookUp = FALSE;
@@ -12597,7 +13043,7 @@ EditTagsEvent()
 }
 
 void
-AnalyzeModeEvent()
+AnalyzeModeEvent ()
 {
     if (appData.noChessProgram || gameMode == AnalyzeMode)
       return;
@@ -12625,7 +13071,7 @@ AnalyzeModeEvent()
 }
 
 void
-AnalyzeFileEvent()
+AnalyzeFileEvent ()
 {
     if (appData.noChessProgram || gameMode == AnalyzeFile)
       return;
@@ -12648,10 +13094,11 @@ AnalyzeFileEvent()
     StartAnalysisClock();
     GetTimeMark(&lastNodeCountTime);
     lastNodeCount = 0;
+    if(appData.timeDelay > 0) StartLoadGameTimer((long)(1000.0 * appData.timeDelay));
 }
 
 void
-MachineWhiteEvent()
+MachineWhiteEvent ()
 {
     char buf[MSG_SIZ];
     char *bookHit = NULL;
@@ -12691,7 +13138,7 @@ MachineWhiteEvent()
     pausing = FALSE;
     ModeHighlight();
     SetGameInfo();
-    snprintf(buf, MSG_SIZ, "%s vs. %s", gameInfo.white, gameInfo.black);
+    snprintf(buf, MSG_SIZ, "%s %s %s", gameInfo.white, _("vs."), gameInfo.black);
     DisplayTitle(buf);
     if (first.sendName) {
       snprintf(buf, MSG_SIZ, "name %s\n", gameInfo.black);
@@ -12732,7 +13179,7 @@ MachineWhiteEvent()
 }
 
 void
-MachineBlackEvent()
+MachineBlackEvent ()
 {
   char buf[MSG_SIZ];
   char *bookHit = NULL;
@@ -12768,7 +13215,7 @@ MachineBlackEvent()
     pausing = FALSE;
     ModeHighlight();
     SetGameInfo();
-    snprintf(buf, MSG_SIZ, "%s vs. %s", gameInfo.white, gameInfo.black);
+    snprintf(buf, MSG_SIZ, "%s %s %s", gameInfo.white, _("vs."), gameInfo.black);
     DisplayTitle(buf);
     if (first.sendName) {
       snprintf(buf, MSG_SIZ, "name %s\n", gameInfo.white);
@@ -12808,35 +13255,35 @@ MachineBlackEvent()
 
 
 void
-DisplayTwoMachinesTitle()
+DisplayTwoMachinesTitle ()
 {
     char buf[MSG_SIZ];
     if (appData.matchGames > 0) {
         if(appData.tourneyFile[0]) {
-         snprintf(buf, MSG_SIZ, "%s vs. %s (%d/%d%s)",
-                  gameInfo.white, gameInfo.black,
+         snprintf(buf, MSG_SIZ, "%s %s %s (%d/%d%s)",
+                  gameInfo.white, _("vs."), gameInfo.black,
                   nextGame+1, appData.matchGames+1,
                   appData.tourneyType>0 ? "gt" : appData.tourneyType<0 ? "sw" : "rr");
         } else 
         if (first.twoMachinesColor[0] == 'w') {
-         snprintf(buf, MSG_SIZ, "%s vs. %s (%d-%d-%d)",
-                  gameInfo.white, gameInfo.black,
+         snprintf(buf, MSG_SIZ, "%s %s %s (%d-%d-%d)",
+                  gameInfo.white, _("vs."),  gameInfo.black,
                   first.matchWins, second.matchWins,
                   matchGame - 1 - (first.matchWins + second.matchWins));
        } else {
-         snprintf(buf, MSG_SIZ, "%s vs. %s (%d-%d-%d)",
-                  gameInfo.white, gameInfo.black,
+         snprintf(buf, MSG_SIZ, "%s %s %s (%d-%d-%d)",
+                  gameInfo.white, _("vs."), gameInfo.black,
                   second.matchWins, first.matchWins,
                   matchGame - 1 - (first.matchWins + second.matchWins));
        }
     } else {
-      snprintf(buf, MSG_SIZ, "%s vs. %s", gameInfo.white, gameInfo.black);
+      snprintf(buf, MSG_SIZ, "%s %s %s", gameInfo.white, _("vs."), gameInfo.black);
     }
     DisplayTitle(buf);
 }
 
 void
-SettingsMenuIfReady()
+SettingsMenuIfReady ()
 {
   if (second.lastPing != second.lastPong) {
     DisplayMessage("", _("Waiting for second chess program"));
@@ -12849,10 +13296,10 @@ SettingsMenuIfReady()
 }
 
 int
-WaitForEngine(ChessProgramState *cps, DelayedEventCallback retry)
+WaitForEngine (ChessProgramState *cps, DelayedEventCallback retry)
 {
     char buf[MSG_SIZ];
-    if (cps->pr == NULL) {
+    if (cps->pr == NoProc) {
        StartChessProgram(cps);
        if (cps->protocolVersion == 1) {
          retry();
@@ -13006,7 +13453,7 @@ TwoMachinesEvent P((void))
 }
 
 void
-TrainingEvent()
+TrainingEvent ()
 {
     if (gameMode == Training) {
       SetTrainingModeOff();
@@ -13029,7 +13476,7 @@ TrainingEvent()
 }
 
 void
-IcsClientEvent()
+IcsClientEvent ()
 {
     if (!appData.icsActive) return;
     switch (gameMode) {
@@ -13063,9 +13510,8 @@ IcsClientEvent()
     return;
 }
 
-
 void
-EditGameEvent()
+EditGameEvent ()
 {
     int i;
 
@@ -13137,9 +13583,11 @@ EditGameEvent()
            SendToProgram("undo\n", &first);
            i--;
        }
+       if(!adjustedClock) {
        whiteTimeRemaining = timeRemaining[0][currentMove];
        blackTimeRemaining = timeRemaining[1][currentMove];
        DisplayBothClocks();
+       }
        if (whiteFlag || blackFlag) {
            whiteFlag = blackFlag = 0;
        }
@@ -13153,7 +13601,7 @@ EditGameEvent()
 
 
 void
-EditPositionEvent()
+EditPositionEvent ()
 {
     if (gameMode == EditPosition) {
        EditGameEvent();
@@ -13177,7 +13625,7 @@ EditPositionEvent()
 }
 
 void
-ExitAnalyzeMode()
+ExitAnalyzeMode ()
 {
     /* [DM] icsEngineAnalyze - possible call from other functions */
     if (appData.icsEngineAnalyze) {
@@ -13193,7 +13641,7 @@ ExitAnalyzeMode()
 }
 
 void
-EditPositionDone(Boolean fakeRights)
+EditPositionDone (Boolean fakeRights)
 {
     int king = gameInfo.variant == VariantKnightmate ? WhiteUnicorn : WhiteKing;
 
@@ -13236,8 +13684,7 @@ EditPositionDone(Boolean fakeRights)
 /* Pause for `ms' milliseconds */
 /* !! Ugh, this is a kludge. Fix it sometime. --tpm */
 void
-TimeDelay(ms)
-     long ms;
+TimeDelay (long ms)
 {
     TimeMark m1, m2;
 
@@ -13249,8 +13696,7 @@ TimeDelay(ms)
 
 /* !! Ugh, this is a kludge. Fix it sometime. --tpm */
 void
-SendMultiLineToICS(buf)
-     char *buf;
+SendMultiLineToICS (char *buf)
 {
     char temp[MSG_SIZ+1], *p;
     int len;
@@ -13275,7 +13721,7 @@ SendMultiLineToICS(buf)
 }
 
 void
-SetWhiteToPlayEvent()
+SetWhiteToPlayEvent ()
 {
     if (gameMode == EditPosition) {
        blackPlaysFirst = FALSE;
@@ -13287,7 +13733,7 @@ SetWhiteToPlayEvent()
 }
 
 void
-SetBlackToPlayEvent()
+SetBlackToPlayEvent ()
 {
     if (gameMode == EditPosition) {
        blackPlaysFirst = TRUE;
@@ -13301,9 +13747,7 @@ SetBlackToPlayEvent()
 }
 
 void
-EditPositionMenuEvent(selection, x, y)
-     ChessSquare selection;
-     int x, y;
+EditPositionMenuEvent (ChessSquare selection, int x, int y)
 {
     char buf[MSG_SIZ];
     ChessSquare piece = boards[0][y][x];
@@ -13431,9 +13875,7 @@ EditPositionMenuEvent(selection, x, y)
 
 
 void
-DropMenuEvent(selection, x, y)
-     ChessSquare selection;
-     int x, y;
+DropMenuEvent (ChessSquare selection, int x, int y)
 {
     ChessMove moveType;
 
@@ -13474,7 +13916,7 @@ DropMenuEvent(selection, x, y)
 }
 
 void
-AcceptEvent()
+AcceptEvent ()
 {
     /* Accept a pending offer of any kind from opponent */
 
@@ -13499,7 +13941,7 @@ AcceptEvent()
 }
 
 void
-DeclineEvent()
+DeclineEvent ()
 {
     /* Decline a pending offer of any kind from opponent */
 
@@ -13524,7 +13966,7 @@ DeclineEvent()
 }
 
 void
-RematchEvent()
+RematchEvent ()
 {
     /* Issue ICS rematch command */
     if (appData.icsActive) {
@@ -13534,7 +13976,7 @@ RematchEvent()
 }
 
 void
-CallFlagEvent()
+CallFlagEvent ()
 {
     /* Call your opponent's flag (claim a win on time) */
     if (appData.icsActive) {
@@ -13571,7 +14013,7 @@ CallFlagEvent()
 }
 
 void
-ClockClick(int which)
+ClockClick (int which)
 {      // [HGM] code moved to back-end from winboard.c
        if(which) { // black clock
          if (gameMode == EditPosition || gameMode == IcsExamining) {
@@ -13601,7 +14043,7 @@ ClockClick(int which)
 }
 
 void
-DrawEvent()
+DrawEvent ()
 {
     /* Offer draw or accept pending draw offer from opponent */
 
@@ -13643,7 +14085,7 @@ DrawEvent()
 }
 
 void
-AdjournEvent()
+AdjournEvent ()
 {
     /* Offer Adjourn or accept pending Adjourn offer from opponent */
 
@@ -13657,7 +14099,7 @@ AdjournEvent()
 
 
 void
-AbortEvent()
+AbortEvent ()
 {
     /* Offer Abort or accept pending Abort offer from opponent */
 
@@ -13670,7 +14112,7 @@ AbortEvent()
 }
 
 void
-ResignEvent()
+ResignEvent ()
 {
     /* Resign.  You can do this even if it's not your turn. */
 
@@ -13704,7 +14146,7 @@ ResignEvent()
 
 
 void
-StopObservingEvent()
+StopObservingEvent ()
 {
     /* Stop observing current games */
     SendToICS(ics_prefix);
@@ -13712,7 +14154,7 @@ StopObservingEvent()
 }
 
 void
-StopExaminingEvent()
+StopExaminingEvent ()
 {
     /* Stop observing current game */
     SendToICS(ics_prefix);
@@ -13720,8 +14162,7 @@ StopExaminingEvent()
 }
 
 void
-ForwardInner(target)
-     int target;
+ForwardInner (int target)
 {
     int limit;
 
@@ -13732,6 +14173,9 @@ ForwardInner(target)
     if (gameMode == EditPosition)
       return;
 
+    seekGraphUp = FALSE;
+    MarkTargetSquares(1);
+
     if (gameMode == PlayFromGameFile && !pausing)
       PauseEvent();
 
@@ -13782,12 +14226,11 @@ ForwardInner(target)
     if ( !matchMode && gameMode != Training) { // [HGM] PV info: routine tests if empty
        DisplayComment(currentMove - 1, commentList[currentMove]);
     }
-    DisplayBook(currentMove);
 }
 
 
 void
-ForwardEvent()
+ForwardEvent ()
 {
     if (gameMode == IcsExamining && !pausing) {
         SendToICS(ics_prefix);
@@ -13798,7 +14241,7 @@ ForwardEvent()
 }
 
 void
-ToEndEvent()
+ToEndEvent ()
 {
     if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
        /* to optimze, we temporarily turn off analysis mode while we feed
@@ -13828,8 +14271,7 @@ ToEndEvent()
 }
 
 void
-BackwardInner(target)
-     int target;
+BackwardInner (int target)
 {
     int full_redraw = TRUE; /* [AS] Was FALSE, had to change it! */
 
@@ -13838,6 +14280,8 @@ BackwardInner(target)
                target, currentMove, forwardMostMove);
 
     if (gameMode == EditPosition) return;
+    seekGraphUp = FALSE;
+    MarkTargetSquares(1);
     if (currentMove <= backwardMostMove) {
        ClearHighlights();
        DrawPosition(full_redraw, boards[currentMove]);
@@ -13895,11 +14339,10 @@ BackwardInner(target)
     HistorySet(parseList,backwardMostMove,forwardMostMove,currentMove-1);
     // [HGM] PV info: routine tests if comment empty
     DisplayComment(currentMove - 1, commentList[currentMove]);
-    DisplayBook(currentMove);
 }
 
 void
-BackwardEvent()
+BackwardEvent ()
 {
     if (gameMode == IcsExamining && !pausing) {
         SendToICS(ics_prefix);
@@ -13910,7 +14353,7 @@ BackwardEvent()
 }
 
 void
-ToStartEvent()
+ToStartEvent ()
 {
     if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
        /* to optimize, we temporarily turn off analysis mode while we undo
@@ -13939,7 +14382,7 @@ ToStartEvent()
 }
 
 void
-ToNrEvent(int to)
+ToNrEvent (int to)
 {
   if (gameMode == PlayFromGameFile && !pausing) PauseEvent();
   if (to >= forwardMostMove) to = forwardMostMove;
@@ -13952,7 +14395,7 @@ ToNrEvent(int to)
 }
 
 void
-RevertEvent(Boolean annotate)
+RevertEvent (Boolean annotate)
 {
     if(PopTail(annotate)) { // [HGM] vari: restore old game tail
        return;
@@ -13970,7 +14413,7 @@ RevertEvent(Boolean annotate)
 }
 
 void
-RetractMoveEvent()
+RetractMoveEvent ()
 {
     switch (gameMode) {
       case MachinePlaysWhite:
@@ -14009,7 +14452,7 @@ RetractMoveEvent()
 }
 
 void
-MoveNowEvent()
+MoveNowEvent ()
 {
     ChessProgramState *cps;
 
@@ -14044,7 +14487,7 @@ MoveNowEvent()
 }
 
 void
-TruncateGameEvent()
+TruncateGameEvent ()
 {
     EditGameEvent();
     if (gameMode != EditGame) return;
@@ -14052,7 +14495,7 @@ TruncateGameEvent()
 }
 
 void
-TruncateGame()
+TruncateGame ()
 {
     CleanupTail(); // [HGM] vari: only keep current variation if we explicitly truncate
     if (forwardMostMove > currentMove) {
@@ -14068,7 +14511,7 @@ TruncateGame()
 }
 
 void
-HintEvent()
+HintEvent ()
 {
     if (appData.noChessProgram) return;
     switch (gameMode) {
@@ -14094,7 +14537,7 @@ HintEvent()
 }
 
 void
-BookEvent()
+BookEvent ()
 {
     if (appData.noChessProgram) return;
     switch (gameMode) {
@@ -14125,7 +14568,7 @@ BookEvent()
 }
 
 void
-AboutGameEvent()
+AboutGameEvent ()
 {
     char *tags = PGNTags(&gameInfo);
     TagsPopUp(tags, CmailMsg());
@@ -14135,9 +14578,7 @@ AboutGameEvent()
 /* end button procedures */
 
 void
-PrintPosition(fp, move)
-     FILE *fp;
-     int move;
+PrintPosition (FILE *fp, int move)
 {
     int i, j;
 
@@ -14155,8 +14596,7 @@ PrintPosition(fp, move)
 }
 
 void
-PrintOpponents(fp)
-     FILE *fp;
+PrintOpponents (FILE *fp)
 {
     if (gameInfo.white != NULL) {
        fprintf(fp, "\t%s vs. %s\n", gameInfo.white, gameInfo.black);
@@ -14167,8 +14607,7 @@ PrintOpponents(fp)
 
 /* Find last component of program's own name, using some heuristics */
 void
-TidyProgramName(prog, host, buf)
-     char *prog, *host, buf[MSG_SIZ];
+TidyProgramName (char *prog, char *host, char buf[MSG_SIZ])
 {
     char *p, *q;
     int local = (strcmp(host, "localhost") == 0);
@@ -14197,7 +14636,7 @@ TidyProgramName(prog, host, buf)
 }
 
 char *
-TimeControlTagValue()
+TimeControlTagValue ()
 {
     char buf[MSG_SIZ];
     if (!appData.clockMode) {
@@ -14213,7 +14652,7 @@ TimeControlTagValue()
 }
 
 void
-SetGameInfo()
+SetGameInfo ()
 {
     /* This routine is used only for certain modes */
     VariantClass v = gameInfo.variant;
@@ -14311,9 +14750,7 @@ SetGameInfo()
 }
 
 void
-ReplaceComment(index, text)
-     int index;
-     char *text;
+ReplaceComment (int index, char *text)
 {
     int len;
     char *p;
@@ -14354,8 +14791,7 @@ ReplaceComment(index, text)
 }
 
 void
-CrushCRs(text)
-     char *text;
+CrushCRs (char *text)
 {
   char *p = text;
   char *q = text;
@@ -14369,10 +14805,8 @@ CrushCRs(text)
 }
 
 void
-AppendComment(index, text, addBraces)
-     int index;
-     char *text;
-     Boolean addBraces; // [HGM] braces: tells if we should add {}
+AppendComment (int index, char *text, Boolean addBraces)
+/* addBraces  tells if we should add {} */
 {
     int oldlen, len;
     char *old;
@@ -14384,10 +14818,12 @@ if(appData.debugMode) fprintf(debugFP, "Append: in='%s' %d\n", text, addBraces);
     while (*text == '\n') text++;
     len = strlen(text);
     while (len > 0 && text[len - 1] == '\n') len--;
+    text[len] = NULLCHAR;
 
     if (len == 0) return;
 
     if (commentList[index] != NULL) {
+      Boolean addClosingBrace = addBraces;
        old = commentList[index];
        oldlen = strlen(old);
        while(commentList[index][oldlen-1] ==  '\n')
@@ -14404,7 +14840,7 @@ if(appData.debugMode) fprintf(debugFP, "Append: in='%s' %d\n", text, addBraces);
        if(addBraces) strcat(commentList[index], addBraces == 2 ? "\n(" : "\n{\n");
        else          strcat(commentList[index], "\n");
        strcat(commentList[index], text);
-       if(addBraces) strcat(commentList[index], addBraces == 2 ? ")\n" : "\n}\n");
+       if(addClosingBrace) strcat(commentList[index], addClosingBrace == 2 ? ")\n" : "\n}\n");
        else          strcat(commentList[index], "\n");
     } else {
        commentList[index] = (char *) malloc(len + 6); // perhaps wastes 4...
@@ -14417,7 +14853,8 @@ if(appData.debugMode) fprintf(debugFP, "Append: in='%s' %d\n", text, addBraces);
     }
 }
 
-static char * FindStr( char * text, char * sub_text )
+static char *
+FindStr (char * text, char * sub_text)
 {
     char * result = strstr( text, sub_text );
 
@@ -14430,7 +14867,8 @@ static char * FindStr( char * text, char * sub_text )
 
 /* [AS] Try to extract PV info from PGN comment */
 /* [HGM] PV time: and then remove it, to prevent it appearing twice */
-char *GetInfoFromComment( int index, char * text )
+char *
+GetInfoFromComment (int index, char * text)
 {
     char * sep = text, *p;
 
@@ -14504,7 +14942,7 @@ char *GetInfoFromComment( int index, char * text )
             while( *++sep >= '0' && *sep <= '9'); // strip seconds
             if(deci >= 0)
             while( *++sep >= '0' && *sep <= '9'); // strip fractional seconds
-            while(*sep == ' ') sep++;
+            while(*sep == ' ' || *sep == '\n' || *sep == '\r') sep++;
         }
 
         if( depth <= 0 ) {
@@ -14525,14 +14963,12 @@ char *GetInfoFromComment( int index, char * text )
 }
 
 void
-SendToProgram(message, cps)
-     char *message;
-     ChessProgramState *cps;
+SendToProgram (char *message, ChessProgramState *cps)
 {
     int count, outCount, error;
     char buf[MSG_SIZ];
 
-    if (cps->pr == NULL) return;
+    if (cps->pr == NoProc) return;
     Attention(cps);
 
     if (appData.debugMode) {
@@ -14567,12 +15003,7 @@ SendToProgram(message, cps)
 }
 
 void
-ReceiveFromProgram(isr, closure, message, count, error)
-     InputSourceRef isr;
-     VOIDSTAR closure;
-     char *message;
-     int count;
-     int error;
+ReceiveFromProgram (InputSourceRef isr, VOIDSTAR closure, char *message, int count, int error)
 {
     char *end_str;
     char buf[MSG_SIZ];
@@ -14662,10 +15093,7 @@ ReceiveFromProgram(isr, closure, message, count, error)
 
 
 void
-SendTimeControl(cps, mps, tc, inc, sd, st)
-     ChessProgramState *cps;
-     int mps, inc, sd, st;
-     long tc;
+SendTimeControl (ChessProgramState *cps, int mps, long tc, int inc, int sd, int st)
 {
     char buf[MSG_SIZ];
     int seconds;
@@ -14729,7 +15157,8 @@ SendTimeControl(cps, mps, tc, inc, sd, st)
     }
 }
 
-ChessProgramState *WhitePlayer()
+ChessProgramState *
+WhitePlayer ()
 /* [HGM] return pointer to 'first' or 'second', depending on who plays white */
 {
     if(gameMode == TwoMachinesPlay && first.twoMachinesColor[0] == 'b' ||
@@ -14739,9 +15168,7 @@ ChessProgramState *WhitePlayer()
 }
 
 void
-SendTimeRemaining(cps, machineWhite)
-     ChessProgramState *cps;
-     int /*boolean*/ machineWhite;
+SendTimeRemaining (ChessProgramState *cps, int machineWhite)
 {
     char message[MSG_SIZ];
     long time, otime;
@@ -14774,11 +15201,7 @@ SendTimeRemaining(cps, machineWhite)
 }
 
 int
-BoolFeature(p, name, loc, cps)
-     char **p;
-     char *name;
-     int *loc;
-     ChessProgramState *cps;
+BoolFeature (char **p, char *name, int *loc, ChessProgramState *cps)
 {
   char buf[MSG_SIZ];
   int len = strlen(name);
@@ -14798,11 +15221,7 @@ BoolFeature(p, name, loc, cps)
 }
 
 int
-IntFeature(p, name, loc, cps)
-     char **p;
-     char *name;
-     int *loc;
-     ChessProgramState *cps;
+IntFeature (char **p, char *name, int *loc, ChessProgramState *cps)
 {
   char buf[MSG_SIZ];
   int len = strlen(name);
@@ -14818,11 +15237,7 @@ IntFeature(p, name, loc, cps)
 }
 
 int
-StringFeature(p, name, loc, cps)
-     char **p;
-     char *name;
-     char loc[];
-     ChessProgramState *cps;
+StringFeature (char **p, char *name, char loc[], ChessProgramState *cps)
 {
   char buf[MSG_SIZ];
   int len = strlen(name);
@@ -14840,7 +15255,7 @@ StringFeature(p, name, loc, cps)
 }
 
 int
-ParseOption(Option *opt, ChessProgramState *cps)
+ParseOption (Option *opt, ChessProgramState *cps)
 // [HGM] options: process the string that defines an engine option, and determine
 // name, type, default value, and allowed value range
 {
@@ -14931,9 +15346,7 @@ ParseOption(Option *opt, ChessProgramState *cps)
 }
 
 void
-FeatureDone(cps, val)
-     ChessProgramState* cps;
-     int val;
+FeatureDone (ChessProgramState *cps, int val)
 {
   DelayedEventCallback cb = GetDelayedEvent();
   if ((cb == InitBackEnd3 && cps == &first) ||
@@ -14948,9 +15361,7 @@ FeatureDone(cps, val)
 
 /* Parse feature command from engine */
 void
-ParseFeatures(args, cps)
-     char* args;
-     ChessProgramState *cps;
+ParseFeatures (char *args, ChessProgramState *cps)
 {
   char *p = args;
   char *q;
@@ -14962,6 +15373,7 @@ ParseFeatures(args, cps)
     if (*p == NULLCHAR) return;
 
     if (BoolFeature(&p, "setboard", &cps->useSetboard, cps)) continue;
+    if (BoolFeature(&p, "xedit", &cps->extendedEdit, 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;
@@ -14972,7 +15384,7 @@ ParseFeatures(args, cps)
       continue;
     }
     if (BoolFeature(&p, "analyze", &cps->analysisSupport, cps)) continue;
-    if (StringFeature(&p, "myname", &cps->tidy, cps)) {
+    if (StringFeature(&p, "myname", cps->tidy, cps)) {
       if (gameMode == TwoMachinesPlay) {
        DisplayTwoMachinesTitle();
       } else {
@@ -14980,7 +15392,7 @@ ParseFeatures(args, cps)
       }
       continue;
     }
-    if (StringFeature(&p, "variants", &cps->variants, cps)) 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;
@@ -15004,8 +15416,8 @@ ParseFeatures(args, cps)
     if (IntFeature(&p, "level", &cps->maxNrOfSessions, cps)) continue;
     if (BoolFeature(&p, "memory", &cps->memSize, cps)) continue;
     if (BoolFeature(&p, "smp", &cps->maxCores, cps)) continue;
-    if (StringFeature(&p, "egt", &cps->egtFormats, cps)) continue;
-    if (StringFeature(&p, "option", &(cps->option[cps->nrOptions].name), cps)) {
+    if (StringFeature(&p, "egt", cps->egtFormats, cps)) continue;
+    if (StringFeature(&p, "option", cps->option[cps->nrOptions].name, cps)) {
        if(!ParseOption(&(cps->option[cps->nrOptions++]), cps)) { // [HGM] options: add option feature
          snprintf(buf, MSG_SIZ, "rejected option %s\n", cps->option[--cps->nrOptions].name);
            SendToProgram(buf, cps);
@@ -15041,8 +15453,7 @@ ParseFeatures(args, cps)
 }
 
 void
-PeriodicUpdatesEvent(newState)
-     int newState;
+PeriodicUpdatesEvent (int newState)
 {
     if (newState == appData.periodicUpdates)
       return;
@@ -15060,8 +15471,7 @@ PeriodicUpdatesEvent(newState)
 }
 
 void
-PonderNextMoveEvent(newState)
-     int newState;
+PonderNextMoveEvent (int newState)
 {
     if (newState == appData.ponderNextMove) return;
     if (gameMode == EditPosition) EditPositionDone(TRUE);
@@ -15081,9 +15491,7 @@ PonderNextMoveEvent(newState)
 }
 
 void
-NewSettingEvent(option, feature, command, value)
-     char *command;
-     int option, value, *feature;
+NewSettingEvent (int option, int *feature, char *command, int value)
 {
     char buf[MSG_SIZ];
 
@@ -15096,7 +15504,7 @@ NewSettingEvent(option, feature, command, value)
 }
 
 void
-ShowThinkingEvent()
+ShowThinkingEvent ()
 // [HGM] thinking: this routine is now also called from "Options -> Engine..." popup
 {
     static int oldState = 2; // kludge alert! Neither true nor fals, so first time oldState is always updated
@@ -15123,8 +15531,7 @@ ShowThinkingEvent()
 }
 
 void
-AskQuestionEvent(title, question, replyPrefix, which)
-     char *title; char *question; char *replyPrefix; char *which;
+AskQuestionEvent (char *title, char *question, char *replyPrefix, char *which)
 {
   ProcRef pr = (which[0] == '1') ? first.pr : second.pr;
   if (pr == NoProc) return;
@@ -15132,7 +15539,7 @@ AskQuestionEvent(title, question, replyPrefix, which)
 }
 
 void
-TypeInEvent(char firstChar)
+TypeInEvent (char firstChar)
 {
     if ((gameMode == BeginningOfGame && !appData.icsActive) || 
         gameMode == MachinePlaysWhite || gameMode == MachinePlaysBlack ||
@@ -15146,7 +15553,7 @@ TypeInEvent(char firstChar)
 }
 
 void
-TypeInDoneEvent(char *move)
+TypeInDoneEvent (char *move)
 {
        Board board;
        int n, fromX, fromY, toX, toY;
@@ -15181,8 +15588,7 @@ TypeInDoneEvent(char *move)
 }
 
 void
-DisplayMove(moveNumber)
-     int moveNumber;
+DisplayMove (int moveNumber)
 {
     char message[MSG_SIZ];
     char res[MSG_SIZ];
@@ -15239,9 +15645,7 @@ DisplayMove(moveNumber)
 }
 
 void
-DisplayComment(moveNumber, text)
-     int moveNumber;
-     char *text;
+DisplayComment (int moveNumber, char *text)
 {
     char title[MSG_SIZ];
 
@@ -15263,8 +15667,7 @@ DisplayComment(moveNumber, text)
  * ioctl, which does not work properly on some flavors of Unix.
  */
 void
-Attention(cps)
-     ChessProgramState *cps;
+Attention (ChessProgramState *cps)
 {
 #if ATTENTION
     if (!cps->useSigint) return;
@@ -15291,7 +15694,7 @@ Attention(cps)
 }
 
 int
-CheckFlags()
+CheckFlags ()
 {
     if (whiteTimeRemaining <= 0) {
        if (!whiteFlag) {
@@ -15341,7 +15744,7 @@ CheckFlags()
 }
 
 void
-CheckTimeControl()
+CheckTimeControl ()
 {
     if (!appData.clockMode || appData.icsActive || searchTime || // [HGM] st: no inc in st mode
        gameMode == PlayFromGameFile || forwardMostMove == 0) return;
@@ -15366,7 +15769,7 @@ CheckTimeControl()
 }
 
 void
-DisplayBothClocks()
+DisplayBothClocks ()
 {
     int wom = gameMode == EditPosition ?
       !blackPlaysFirst : WhiteOnMove(currentMove);
@@ -15388,8 +15791,7 @@ DisplayBothClocks()
 
 /* Get the current time as a TimeMark */
 void
-GetTimeMark(tm)
-     TimeMark *tm;
+GetTimeMark (TimeMark *tm)
 {
 #if HAVE_GETTIMEOFDAY
 
@@ -15421,8 +15823,7 @@ GetTimeMark(tm)
    time marks.  We assume the difference will fit in a long!
 */
 long
-SubtractTimeMarks(tm2, tm1)
-     TimeMark *tm2, *tm1;
+SubtractTimeMarks (TimeMark *tm2, TimeMark *tm1)
 {
     return 1000L*(tm2->sec - tm1->sec) +
            (long) (tm2->ms - tm1->ms);
@@ -15443,8 +15844,7 @@ static TimeMark tickStartTM;
 static long intendedTickLength;
 
 long
-NextTickLength(timeRemaining)
-     long timeRemaining;
+NextTickLength (long timeRemaining)
 {
     long nominalTickLength, nextTickLength;
 
@@ -15460,16 +15860,18 @@ NextTickLength(timeRemaining)
 
 /* Adjust clock one minute up or down */
 void
-AdjustClock(Boolean which, int dir)
+AdjustClock (Boolean which, int dir)
 {
+    if(appData.autoCallFlag) { DisplayError(_("Clock adjustment not allowed in auto-flag mode"), 0); return; }
     if(which) blackTimeRemaining += 60000*dir;
     else      whiteTimeRemaining += 60000*dir;
     DisplayBothClocks();
+    adjustedClock = TRUE;
 }
 
 /* Stop clocks and reset to a fresh time control */
 void
-ResetClocks()
+ResetClocks ()
 {
     (void) StopClockTimer();
     if (appData.icsActive) {
@@ -15488,13 +15890,14 @@ ResetClocks()
     }
     lastWhite = lastBlack = whiteStartMove = blackStartMove = 0;
     DisplayBothClocks();
+    adjustedClock = FALSE;
 }
 
 #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()
+DecrementClocks ()
 {
     long timeRemaining;
     long lastTickLength, fudge;
@@ -15574,7 +15977,7 @@ DecrementClocks()
    from the color that is *not* on move now.
 */
 void
-SwitchClocks(int newMoveNr)
+SwitchClocks (int newMoveNr)
 {
     long lastTickLength;
     TimeMark now;
@@ -15637,7 +16040,7 @@ SwitchClocks(int newMoveNr)
 
 /* Stop both clocks */
 void
-StopClocks()
+StopClocks ()
 {
     long lastTickLength;
     TimeMark now;
@@ -15663,7 +16066,7 @@ StopClocks()
 /* Start clock of player on move.  Time may have been reset, so
    if clock is already running, stop and restart it. */
 void
-StartClocks()
+StartClocks ()
 {
     (void) StopClockTimer(); /* in case it was running already */
     DisplayBothClocks();
@@ -15694,8 +16097,7 @@ StartClocks()
 }
 
 char *
-TimeString(ms)
-     long ms;
+TimeString (long ms)
 {
     long second, minute, hour, day;
     char *sign = "";
@@ -15742,8 +16144,7 @@ TimeString(ms)
  * This is necessary because some C libraries aren't ANSI C compliant yet.
  */
 char *
-StrStr(string, match)
-     char *string, *match;
+StrStr (char *string, char *match)
 {
     int i, length;
 
@@ -15757,8 +16158,7 @@ StrStr(string, match)
 }
 
 char *
-StrCaseStr(string, match)
-     char *string, *match;
+StrCaseStr (char *string, char *match)
 {
     int i, j, length;
 
@@ -15777,8 +16177,7 @@ StrCaseStr(string, match)
 
 #ifndef _amigados
 int
-StrCaseCmp(s1, s2)
-     char *s1, *s2;
+StrCaseCmp (char *s1, char *s2)
 {
     char c1, c2;
 
@@ -15793,24 +16192,21 @@ StrCaseCmp(s1, s2)
 
 
 int
-ToLower(c)
-     int c;
+ToLower (int c)
 {
     return isupper(c) ? tolower(c) : c;
 }
 
 
 int
-ToUpper(c)
-     int c;
+ToUpper (int c)
 {
     return islower(c) ? toupper(c) : c;
 }
 #endif /* !_amigados   */
 
 char *
-StrSave(s)
-     char *s;
+StrSave (char *s)
 {
   char *ret;
 
@@ -15822,8 +16218,7 @@ StrSave(s)
 }
 
 char *
-StrSavePtr(s, savePtr)
-     char *s, **savePtr;
+StrSavePtr (char *s, char **savePtr)
 {
     if (*savePtr) {
        free(*savePtr);
@@ -15835,7 +16230,7 @@ StrSavePtr(s, savePtr)
 }
 
 char *
-PGNDate()
+PGNDate ()
 {
     time_t clock;
     struct tm *tm;
@@ -15850,9 +16245,7 @@ PGNDate()
 
 
 char *
-PositionToFEN(move, overrideCastling)
-     int move;
-     char *overrideCastling;
+PositionToFEN (int move, char *overrideCastling)
 {
     int i, j, fromX, fromY, toX, toY;
     int whiteToPlay;
@@ -16020,10 +16413,7 @@ PositionToFEN(move, overrideCastling)
 }
 
 Boolean
-ParseFEN(board, blackPlaysFirst, fen)
-    Board board;
-     int *blackPlaysFirst;
-     char *fen;
+ParseFEN (Board board, int *blackPlaysFirst, char *fen)
 {
     int i, j;
     char *p, c;
@@ -16263,7 +16653,7 @@ ParseFEN(board, blackPlaysFirst, fen)
 }
 
 void
-EditPositionPasteFEN(char *fen)
+EditPositionPasteFEN (char *fen)
 {
   if (fen != NULL) {
     Board initial_position;
@@ -16286,7 +16676,8 @@ EditPositionPasteFEN(char *fen)
 
 static char cseq[12] = "\\   ";
 
-Boolean set_cont_sequence(char *new_seq)
+Boolean
+set_cont_sequence (char *new_seq)
 {
     int len;
     Boolean ret;
@@ -16311,7 +16702,8 @@ Boolean set_cont_sequence(char *new_seq)
     for the dest buffer.  lp argument indicats line position upon entry, and it's
     passed back upon exit.
 */
-int wrap(char *dest, char *src, int count, int width, int *lp)
+int
+wrap (char *dest, char *src, int count, int width, int *lp)
 {
     int len, i, ansi, cseq_len, line, old_line, old_i, old_len, clen;
 
@@ -16392,9 +16784,10 @@ int wrap(char *dest, char *src, int count, int width, int *lp)
 }
 
 // [HGM] vari: routines for shelving variations
+Boolean modeRestore = FALSE;
 
 void
-PushInner(int firstMove, int lastMove)
+PushInner (int firstMove, int lastMove)
 {
        int i, j, nrMoves = lastMove - firstMove;
 
@@ -16425,7 +16818,7 @@ PushInner(int firstMove, int lastMove)
 }
 
 void
-PushTail(int firstMove, int lastMove)
+PushTail (int firstMove, int lastMove)
 {
        if(appData.icsActive) { // only in local mode
                forwardMostMove = currentMove; // mimic old ICS behavior
@@ -16435,16 +16828,17 @@ PushTail(int firstMove, int lastMove)
 
        PushInner(firstMove, lastMove);
        if(storedGames == 1) GreyRevert(FALSE);
+       if(gameMode == PlayFromGameFile) gameMode = EditGame, modeRestore = TRUE;
 }
 
 void
-PopInner(Boolean annotate)
+PopInner (Boolean annotate)
 {
        int i, j, nrMoves;
        char buf[8000], moveBuf[20];
 
-       storedGames--;
-       ToNrEvent(savedFirst[storedGames]); // sets currentMove
+       ToNrEvent(savedFirst[storedGames-1]); // sets currentMove
+       storedGames--; // do this after ToNrEvent, to make sure HistorySet will refresh entire game after PopInner returns
        nrMoves = savedLast[storedGames] - currentMove;
        if(annotate) {
                int cnt = 10;
@@ -16485,20 +16879,22 @@ PopInner(Boolean annotate)
 }
 
 Boolean
-PopTail(Boolean annotate)
+PopTail (Boolean annotate)
 {
        if(appData.icsActive) return FALSE; // only in local mode
        if(!storedGames) return FALSE; // sanity
        CommentPopDown(); // make sure no stale variation comments to the destroyed line can remain open
 
        PopInner(annotate);
+       if(currentMove < forwardMostMove) ForwardEvent(); else
+       HistorySet(parseList, backwardMostMove, forwardMostMove, currentMove-1);
 
-       if(storedGames == 0) GreyRevert(TRUE);
+       if(storedGames == 0) { GreyRevert(TRUE); if(modeRestore) modeRestore = FALSE, gameMode = PlayFromGameFile; }
        return TRUE;
 }
 
 void
-CleanupTail()
+CleanupTail ()
 {      // remove all shelved variations
        int i;
        for(i=0; i<storedGames; i++) {
@@ -16515,12 +16911,12 @@ CleanupTail()
 }
 
 void
-LoadVariation(int index, char *text)
+LoadVariation (int index, char *text)
 {       // [HGM] vari: shelve previous line and load new variation, parsed from text around text[index]
        char *p = text, *start = NULL, *end = NULL, wait = NULLCHAR;
        int level = 0, move;
 
-       if(gameMode != EditGame && gameMode != AnalyzeMode) return;
+       if(gameMode != EditGame && gameMode != AnalyzeMode && gameMode != PlayFromGameFile) return;
        // first find outermost bracketing variation
        while(*p) { // hope I got this right... Non-nesting {} and [] can screen each other and nesting ()
            if(!wait) { // while inside [] pr {}, ignore everyting except matching closing ]}