Add WB new popup prototypes
[xboard.git] / backend.c
index f2c0c98..9204e1b 100644 (file)
--- a/backend.c
+++ b/backend.c
@@ -249,6 +249,7 @@ char *SendMoveToBookUser P((int nr, ChessProgramState *cps, int initial)); // [H
 void ics_update_width P((int new_width));
 extern char installDir[MSG_SIZ];
 VariantClass startVariant; /* [HGM] nicks: initial variant */
+Boolean abortMatch;
 
 extern int tinyLayout, smallLayout;
 ChessProgramStats programStats;
@@ -506,6 +507,8 @@ ChessMove savedResult[MAX_VARIATIONS];
 
 void PushTail P((int firstMove, int lastMove));
 Boolean PopTail P((Boolean annotate));
+void PushInner P((int firstMove, int lastMove));
+void PopInner P((Boolean annotate));
 void CleanupTail P((void));
 
 ChessSquare  FIDEArray[2][BOARD_FILES] = {
@@ -858,12 +861,13 @@ ReplaceEngine(ChessProgramState *cps, int n)
     LoadEngine();
 }
 
-extern char *engineName, *engineDir, *engineChoice, *engineLine, *nickName;
+extern char *engineName, *engineDir, *engineChoice, *engineLine, *nickName, *params;
 extern Boolean isUCI, hasBook, storeVariant, v1, addToList;
 
-void Load(ChessProgramState *cps, int i)
+void
+Load(ChessProgramState *cps, int i)
 {
-    char *p, *q, buf[MSG_SIZ];
+    char *p, *q, buf[MSG_SIZ], command[MSG_SIZ];
     if(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*
@@ -875,15 +879,19 @@ void Load(ChessProgramState *cps, int i)
     }
     p = engineName;
     while(q = strchr(p, SLASH)) p = q+1;
-    if(*p== NULLCHAR) return;
-    appData.chessProgram[i] = strdup(p);
+    if(*p== NULLCHAR) { DisplayError(_("You did not specify the engine executable"), 0); return; }
     if(engineDir[0] != NULLCHAR)
        appData.directory[i] = engineDir;
     else if(p != engineName) { // derive directory from engine path, when not given
        p[-1] = 0;
        appData.directory[i] = strdup(engineName);
-       p[-1] = '/';
+       p[-1] = SLASH;
     } else appData.directory[i] = ".";
+    if(params[0]) {
+       snprintf(command, MSG_SIZ, "%s %s", p, params);
+       p = command;
+    }
+    appData.chessProgram[i] = strdup(p);
     appData.isUCI[i] = isUCI;
     appData.protocolVersion[i] = v1 ? 1 : PROTOVER;
     appData.hasOwnBookUCI[i] = hasBook;
@@ -897,7 +905,6 @@ void Load(ChessProgramState *cps, int i)
                        isUCI ? " -fUCI" : "",
                        storeVariant ? " -variant " : "",
                        storeVariant ? VariantName(gameInfo.variant) : "");
-fprintf(debugFP, "new line: %s", buf);
        firstChessProgramNames = malloc(len = strlen(q) + strlen(buf) + 1);
        snprintf(firstChessProgramNames, len, "%s%s", q, buf);
        if(q)   free(q);
@@ -1365,6 +1372,18 @@ void
 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
+           abortMatch = TRUE;
+           appData.matchGames = appData.tourneyFile[0] ? nextGame: matchGame; // kludge to let match terminate after next game.
+           ModeHighlight(); // kludgey way to remove checkmark...
+           return;
+       }
+//     if(gameMode != BeginningOfGame) {
+//         DisplayError(_("You can only start a match from the initial position."), 0);
+//         return;
+//     }
+       abortMatch = FALSE;
+       appData.matchGames = appData.defaultMatchGames;
        /* Set up machine vs. machine match */
        nextGame = 0;
        NextTourneyGame(0, &dummy); // sets appData.matchGames if this is tourney, to make sure ReserveGame knows it
@@ -5207,6 +5226,7 @@ ParseOneMove(move, moveNum, moveType, fromX, fromY, toX, toY, promoChar)
     }
 }
 
+Boolean pushed = FALSE;
 
 void
 ParsePV(char *pv, Boolean storeComments)
@@ -5216,6 +5236,10 @@ ParsePV(char *pv, Boolean storeComments)
   Boolean valid;
   int nr = 0;
 
+  if (gameMode == AnalyzeMode && currentMove < forwardMostMove) {
+    PushInner(currentMove, forwardMostMove); // [HGM] engine might not be thinking on forwardMost position!
+    pushed = TRUE;
+  }
   endPV = forwardMostMove;
   do {
     while(*pv == ' ' || *pv == '\n' || *pv == '\t') pv++; // must still read away whitespace
@@ -5312,6 +5336,7 @@ UnLoadPV()
   if(endPV < 0) return;
   endPV = -1;
   currentMove = forwardMostMove;
+  if(pushed) { PopInner(0); pushed = FALSE; } // restore shelved game contnuation
   ClearPremoveHighlights();
   DrawPosition(TRUE, boards[currentMove]);
 }
@@ -7060,7 +7085,7 @@ TourneyStandings(int display)
          case '-': bScore = 2; break;
          case '=': wScore = bScore = 1; break;
          case ' ':
-         case '*': return NULL; // tourney not finished
+         case '*': return strdup("busy"); // tourney not finished
        }
        score[w] += wScore;
        score[b] += bScore;
@@ -10004,12 +10029,12 @@ 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.tourneyFile[0] && !abortMatch){ // [HGM] we are in a tourney; update tourney file with game result
            ReserveGame(nextGame, resChar); // sets nextGame
            if(nextGame > appData.matchGames) appData.tourneyFile[0] = 0, ranking = TourneyStandings(3); // tourney is done
        } else roundNr = nextGame = matchGame + 1; // normal match, just increment; round equals matchGame
 
-       if (nextGame <= appData.matchGames) {
+       if (nextGame <= appData.matchGames && !abortMatch) {
            gameMode = nextGameMode;
            matchGame = nextGame; // this will be overruled in tourney mode!
            GetTimeMark(&pauseStart); // [HGM] matchpause: stipulate a pause
@@ -10039,9 +10064,16 @@ GameEnds(result, resultDetails, whosays)
     ModeHighlight();
     endingGame = 0;  /* [HGM] crash */
     if(popupRequested) { // [HGM] crash: this calls GameEnds recursively through ExitEvent! Make it a harmless tail recursion.
-      if(matchMode == TRUE) DisplayFatalError(ranking ? ranking : buf, 0, 0); else {
-       matchMode = FALSE; appData.matchGames = matchGame = roundNr = 0;
-       DisplayNote(ranking ? ranking : buf);
+       if(matchMode == TRUE) { // match through command line: exit with or without popup
+           if(ranking) {
+               if(strcmp(ranking, "busy")) DisplayFatalError(ranking, 0, 0);
+               else ExitEvent(0);
+           } else DisplayFatalError(buf, 0, 0);
+       } else { // match through menu; just stop, with or without popup
+           matchMode = FALSE; appData.matchGames = matchGame = roundNr = 0;
+           if(ranking){
+               if(strcmp(ranking, "busy")) DisplayNote(ranking);
+           } else DisplayNote(buf);
       }
       if(ranking) free(ranking);
     }
@@ -16045,16 +16077,10 @@ int wrap(char *dest, char *src, int count, int width, int *lp)
 // [HGM] vari: routines for shelving variations
 
 void
-PushTail(int firstMove, int lastMove)
+PushInner(int firstMove, int lastMove)
 {
        int i, j, nrMoves = lastMove - firstMove;
 
-       if(appData.icsActive) { // only in local mode
-               forwardMostMove = currentMove; // mimic old ICS behavior
-               return;
-       }
-       if(storedGames >= MAX_VARIATIONS-1) return;
-
        // push current tail of game on stack
        savedResult[storedGames] = gameInfo.result;
        savedDetails[storedGames] = gameInfo.resultDetails;
@@ -16079,19 +16105,27 @@ PushTail(int firstMove, int lastMove)
 
        storedGames++;
        forwardMostMove = firstMove; // truncate game so we can start variation
+}
+
+void
+PushTail(int firstMove, int lastMove)
+{
+       if(appData.icsActive) { // only in local mode
+               forwardMostMove = currentMove; // mimic old ICS behavior
+               return;
+       }
+       if(storedGames >= MAX_VARIATIONS-2) return; // leave one for PV-walk
+
+       PushInner(firstMove, lastMove);
        if(storedGames == 1) GreyRevert(FALSE);
 }
 
-Boolean
-PopTail(Boolean annotate)
+void
+PopInner(Boolean annotate)
 {
        int i, j, nrMoves;
        char buf[8000], moveBuf[20];
 
-       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
-
        storedGames--;
        ToNrEvent(savedFirst[storedGames]); // sets currentMove
        nrMoves = savedLast[storedGames] - currentMove;
@@ -16131,6 +16165,17 @@ PopTail(Boolean annotate)
       }
        gameInfo.resultDetails = savedDetails[storedGames];
        forwardMostMove = currentMove + nrMoves;
+}
+
+Boolean
+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(storedGames == 0) GreyRevert(TRUE);
        return TRUE;
 }