Add -afterTourney option
[xboard.git] / backend.c
index 2f71b5e..5e346e5 100644 (file)
--- a/backend.c
+++ b/backend.c
@@ -147,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));
@@ -210,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));
@@ -823,7 +815,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);
@@ -834,6 +826,7 @@ 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;
@@ -1069,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);
@@ -1087,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);
@@ -1492,7 +1485,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);
@@ -1546,7 +1539,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);
@@ -2145,7 +2138,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);
@@ -3635,7 +3628,7 @@ read_from_ics(isr, closure, data, count, error)
                        flipView = appData.flipView;
                        DrawPosition(TRUE, boards[currentMove]);
                        DisplayBothClocks();
-                       snprintf(str, MSG_SIZ, "%s vs. %s",
+                       snprintf(str, MSG_SIZ, _("%s vs. %s"),
                                gameInfo.white, gameInfo.black);
                        DisplayTitle(str);
                        gameMode = IcsIdle;
@@ -3862,6 +3855,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) {
@@ -4049,10 +4043,10 @@ 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]",
+                         snprintf(str, MSG_SIZ, _("%s [%s] vs. %s [%s]"),
                                    gameInfo.white, white_holding,
                                    gameInfo.black, black_holding);
                        }
@@ -4776,11 +4770,11 @@ ParseBoard12(string)
                    basetime, increment, (int) gameInfo.variant);
        } else {
            if(gameInfo.variant == VariantNormal)
-             snprintf(str, MSG_SIZ, "%s (%d) vs. %s (%d) {%d %d}",
+             snprintf(str, MSG_SIZ, _("%s (%d) vs. %s (%d) {%d %d}"),
                    gameInfo.white, white_stren, gameInfo.black, black_stren,
                    basetime, increment);
            else
-             snprintf(str, MSG_SIZ, "%s (%d) vs. %s (%d) {%d %d %s}",
+             snprintf(str, MSG_SIZ, _("%s (%d) vs. %s (%d) {%d %d %s}"),
                    gameInfo.white, white_stren, gameInfo.black, black_stren,
                    basetime, increment, VariantName(gameInfo.variant));
        }
@@ -4950,6 +4944,12 @@ SendMoveToICS(moveType, fromX, fromY, toX, toY, promoChar)
      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(toX == BOARD_WIDTH>>1) moveType = WhitePromotion; // kludge to do gating at Rook
+    } else suffix[0] = NULLCHAR;
 
     switch (moveType) {
       default:
@@ -4965,7 +4965,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:
@@ -4975,7 +4975,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:
@@ -5023,8 +5023,8 @@ UploadGameEvent()
     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;
@@ -6656,7 +6656,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 vs. %s"), gameInfo.white, gameInfo.black);
       DisplayTitle(buf);
       if (first.sendName) {
        snprintf(buf, MSG_SIZ,"name %s\n", gameInfo.white);
@@ -8118,10 +8118,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;
@@ -8654,7 +8656,7 @@ if(appData.debugMode) fprintf(debugFP, "nodes = %d, %lld\n", (int) programStats.
                        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);
+                       } else DisplayError(_("failed writing PV"), 0);
                }
 
                tempStats.depth = plylev;
@@ -9537,6 +9539,7 @@ InitChessProgram(cps, setup)
     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 */
@@ -9923,6 +9926,7 @@ void SwapEngines(int n)
     SWAP(logo, p)
     SWAP(pgnName, p)
     SWAP(pvSAN, h)
+    SWAP(engOptions, p)
 }
 
 void
@@ -10469,6 +10473,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(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";
@@ -11567,7 +11572,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 vs. %s"), lg->gameInfo.white,
                lg->gameInfo.black);
            DisplayTitle(buf);
     } else if (*title != NULLCHAR) {
@@ -12195,7 +12200,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;
@@ -13182,7 +13187,7 @@ MachineWhiteEvent()
     pausing = FALSE;
     ModeHighlight();
     SetGameInfo();
-    snprintf(buf, MSG_SIZ, "%s vs. %s", gameInfo.white, gameInfo.black);
+    snprintf(buf, MSG_SIZ, _("%s vs. %s"), gameInfo.white, gameInfo.black);
     DisplayTitle(buf);
     if (first.sendName) {
       snprintf(buf, MSG_SIZ, "name %s\n", gameInfo.black);
@@ -13259,7 +13264,7 @@ MachineBlackEvent()
     pausing = FALSE;
     ModeHighlight();
     SetGameInfo();
-    snprintf(buf, MSG_SIZ, "%s vs. %s", gameInfo.white, gameInfo.black);
+    snprintf(buf, MSG_SIZ, _("%s vs. %s"), gameInfo.white, gameInfo.black);
     DisplayTitle(buf);
     if (first.sendName) {
       snprintf(buf, MSG_SIZ, "name %s\n", gameInfo.white);
@@ -13304,24 +13309,24 @@ DisplayTwoMachinesTitle()
     char buf[MSG_SIZ];
     if (appData.matchGames > 0) {
         if(appData.tourneyFile[0]) {
-         snprintf(buf, MSG_SIZ, "%s vs. %s (%d/%d%s)",
+         snprintf(buf, MSG_SIZ, _("%s vs. %s (%d/%d%s)"),
                   gameInfo.white, 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)",
+         snprintf(buf, MSG_SIZ, _("%s vs. %s (%d-%d-%d)"),
                   gameInfo.white, gameInfo.black,
                   first.matchWins, second.matchWins,
                   matchGame - 1 - (first.matchWins + second.matchWins));
        } else {
-         snprintf(buf, MSG_SIZ, "%s vs. %s (%d-%d-%d)",
+         snprintf(buf, MSG_SIZ, _("%s vs. %s (%d-%d-%d)"),
                   gameInfo.white, 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 vs. %s"), gameInfo.white, gameInfo.black);
     }
     DisplayTitle(buf);
 }