Fixed joiner detection, allowing it to work with timeseal
[xboard.git] / backend.c
old mode 100644 (file)
new mode 100755 (executable)
index 1d03351..0bbe876
--- a/backend.c
+++ b/backend.c
@@ -77,6 +77,7 @@
 #if STDC_HEADERS
 # include <stdlib.h>
 # include <string.h>
+# include <stdarg.h>
 #else /* not STDC_HEADERS */
 # if HAVE_STRING_H
 #  include <string.h>
@@ -183,7 +184,6 @@ void FeedMovesToProgram P((ChessProgramState *cps, int upto));
 void ResurrectChessProgram P((void));
 void DisplayComment P((int moveNumber, char *text));
 void DisplayMove P((int moveNumber));
-void DisplayAnalysis P((void));
 
 void ParseGameHistory P((char *game));
 void ParseBoard12 P((char *string));
@@ -1423,12 +1423,14 @@ KeepAlive()
 /* added routine for printf style output to ics */
 void ics_printf(char *format, ...)
 {
-       char buffer[MSG_SIZ], *args;
-       
-       args = (char *)&format + sizeof(format);
-       vsnprintf(buffer, sizeof(buffer), format, args);
-       buffer[sizeof(buffer)-1] = '\0';
-       SendToICS(buffer);
+    char buffer[MSG_SIZ];
+    va_list args;
+
+    va_start(args, format);
+    vsnprintf(buffer, sizeof(buffer), format, args);
+    buffer[sizeof(buffer)-1] = '\0';
+    SendToICS(buffer);
+    va_end(args);
 }
 
 void
@@ -1549,6 +1551,10 @@ StringToVariant(e)
         while( *e++ != '_');
     }
 
+    if(StrCaseStr(e, "misc/")) { // [HGM] on FICS, misc/shogi is not shogi
+       v = VariantNormal;
+       found = TRUE;
+    } else
     for (i=0; i<sizeof(variantNames)/sizeof(char*); i++) {
       if (StrCaseStr(e, variantNames[i])) {
        v = (VariantClass) i;
@@ -1933,8 +1939,6 @@ void
 VariantSwitch(Board board, VariantClass newVariant)
 {
    int newHoldingsWidth, newWidth = 8, newHeight = 8, i, j;
-   int oldCurrentMove = currentMove, oldForwardMostMove = forwardMostMove, oldBackwardMostMove = backwardMostMove;
-//   Board tempBoard; int saveCastling[BOARD_SIZE], saveEP;
 
    startedFromPositionFile = FALSE;
    if(gameInfo.variant == newVariant) return;
@@ -1951,59 +1955,65 @@ VariantSwitch(Board board, VariantClass newVariant)
     * case we want to add those holdings to the already received position.
     */
 
-
-  if (appData.debugMode) {
-    fprintf(debugFP, "Switch board from %s to %s\n",
-               VariantName(gameInfo.variant), VariantName(newVariant));
-    setbuf(debugFP, NULL);
-  }
-    shuffleOpenings = 0;       /* [HGM] shuffle */
-    gameInfo.holdingsSize = 5; /* [HGM] prepare holdings */
-    switch(newVariant) {
-            case VariantShogi:
-              newWidth = 9;  newHeight = 9;
-              gameInfo.holdingsSize = 7;
-            case VariantBughouse:
-            case VariantCrazyhouse:
-              newHoldingsWidth = 2; break;
-            default:
-              newHoldingsWidth = gameInfo.holdingsSize = 0;
-    }
-
-    if(newWidth  != gameInfo.boardWidth  ||
-       newHeight != gameInfo.boardHeight ||
-       newHoldingsWidth != gameInfo.holdingsWidth ) {
-
-        /* shift position to new playing area, if needed */
-        if(newHoldingsWidth > gameInfo.holdingsWidth) {
-           for(i=0; i<BOARD_HEIGHT; i++) 
-               for(j=BOARD_RGHT-1; j>=BOARD_LEFT; j--)
-                   board[i][j+newHoldingsWidth-gameInfo.holdingsWidth] =
-                                                     board[i][j];
-           for(i=0; i<newHeight; i++) {
-               board[i][0] = board[i][newWidth+2*newHoldingsWidth-1] = EmptySquare;
-               board[i][1] = board[i][newWidth+2*newHoldingsWidth-2] = (ChessSquare) 0;
-           }
-        } else if(newHoldingsWidth < gameInfo.holdingsWidth) {
-           for(i=0; i<BOARD_HEIGHT; i++)
-               for(j=BOARD_LEFT; j<BOARD_RGHT; j++)
-                   board[i][j+newHoldingsWidth-gameInfo.holdingsWidth] =
-                                                 board[i][j];
-        }
-
-        gameInfo.boardWidth  = newWidth;
-        gameInfo.boardHeight = newHeight;
-        gameInfo.holdingsWidth = newHoldingsWidth;
-        gameInfo.variant = newVariant;
-        InitDrawingSizes(-2, 0);
-
-        /* [HGM] The following should definitely be solved in a better way */
-        InitPosition(FALSE);          /* this sets up board[0], but also other stuff        */
-    } else { gameInfo.variant = newVariant; InitPosition(FALSE); }
-
-    forwardMostMove = oldForwardMostMove;
-    backwardMostMove = oldBackwardMostMove;
-    currentMove = oldCurrentMove; /* InitPos reset these, but we need still to redraw the position */
+   
+   if (appData.debugMode) {
+     fprintf(debugFP, "Switch board from %s to %s\n",
+            VariantName(gameInfo.variant), VariantName(newVariant));
+     setbuf(debugFP, NULL);
+   }
+   shuffleOpenings = 0;       /* [HGM] shuffle */
+   gameInfo.holdingsSize = 5; /* [HGM] prepare holdings */
+   switch(newVariant) 
+     {
+     case VariantShogi:
+       newWidth = 9;  newHeight = 9;
+       gameInfo.holdingsSize = 7;
+     case VariantBughouse:
+     case VariantCrazyhouse:
+       newHoldingsWidth = 2; break;
+     case VariantGreat:
+       newWidth = 10;
+     case VariantSuper:
+       newHoldingsWidth = 2;
+       gameInfo.holdingsSize = 8;
+       return;
+     case VariantGothic:
+     case VariantCapablanca:
+     case VariantCapaRandom:
+       newWidth = 10;
+     default:
+       newHoldingsWidth = gameInfo.holdingsSize = 0;
+     };
+   
+   if(newWidth  != gameInfo.boardWidth  ||
+      newHeight != gameInfo.boardHeight ||
+      newHoldingsWidth != gameInfo.holdingsWidth ) {
+     
+     /* shift position to new playing area, if needed */
+     if(newHoldingsWidth > gameInfo.holdingsWidth) {
+       for(i=0; i<BOARD_HEIGHT; i++) 
+        for(j=BOARD_RGHT-1; j>=BOARD_LEFT; j--)
+          board[i][j+newHoldingsWidth-gameInfo.holdingsWidth] =
+            board[i][j];
+       for(i=0; i<newHeight; i++) {
+        board[i][0] = board[i][newWidth+2*newHoldingsWidth-1] = EmptySquare;
+        board[i][1] = board[i][newWidth+2*newHoldingsWidth-2] = (ChessSquare) 0;
+       }
+     } else if(newHoldingsWidth < gameInfo.holdingsWidth) {
+       for(i=0; i<BOARD_HEIGHT; i++)
+        for(j=BOARD_LEFT; j<BOARD_RGHT; j++)
+          board[i][j+newHoldingsWidth-gameInfo.holdingsWidth] =
+            board[i][j];
+     }
+     gameInfo.boardWidth  = newWidth;
+     gameInfo.boardHeight = newHeight;
+     gameInfo.holdingsWidth = newHoldingsWidth;
+     gameInfo.variant = newVariant;
+     InitDrawingSizes(-2, 0);
+     InitPosition(FALSE);          /* this sets up board[0], but also other stuff        */
+   } else { gameInfo.variant = newVariant; InitPosition(FALSE); }
+   
+   DrawPosition(TRUE, boards[currentMove]);
 }
 
 static int loggedOn = FALSE;
@@ -2012,7 +2022,8 @@ static int loggedOn = FALSE;
 int gs_gamenum;
 char gs_kind[MSG_SIZ];
 static char player1Name[128] = "";
-static char player2Name[128] = "";
+static char player2Name[128] = "";\r
+static char cont_seq[] = "\n\\   ";
 static int player1Rating = -1;
 static int player2Rating = -1;
 /*----------------------------*/
@@ -2044,7 +2055,9 @@ read_from_ics(isr, closure, data, count, error)
     static char buf[BUF_SIZE + 1];
     static int firstTime = TRUE, intfSet = FALSE;
     static ColorClass prevColor = ColorNormal;
-    static int savingComment = FALSE;
+    static int savingComment = FALSE;\r
+       static int cmatch = 0; // continuation sequence match\r
+       char *bp;
     char str[500];
     int i, oldi;
     int buf_len;
@@ -2075,19 +2088,53 @@ read_from_ics(isr, closure, data, count, error)
              buf[i] = buf[leftover_start + i];
        }
 
-       /* Copy in new characters, removing nulls and \r's */
-       buf_len = leftover_len;
-       for (i = 0; i < count; i++) {
-           if (data[i] != NULLCHAR && data[i] != '\r')
-             buf[buf_len++] = data[i];
-           if(!appData.noJoin && buf_len >= 5 && buf[buf_len-5]=='\n' && buf[buf_len-4]=='\\' && 
-                               buf[buf_len-3]==' '  && buf[buf_len-2]==' '  && buf[buf_len-1]==' ') {
-               buf_len -= 5; // [HGM] ICS: join continuation line of Lasker 2.2.3 server with previous
-               if(buf_len == 0 || buf[buf_len-1] != ' ')
-                  buf[buf_len++] = ' '; // add space (assumes ICS does not break lines within word)
-           }
-       }
-
+    /* copy new characters into the buffer */\r
+    bp = buf + leftover_len;\r
+    buf_len=leftover_len;\r
+    for (i=0; i<count; i++)\r
+    {\r
+        // ignore these\r
+        if (data[i] == '\r')\r
+            continue;\r
+\r
+        // join lines split by ICS?\r
+        if (!appData.noJoin)\r
+        {\r
+            /*\r
+                Joining just consists of finding matches against the\r
+                continuation sequence, and discarding that sequence\r
+                if found instead of copying it.  So, until a match\r
+                fails, there's nothing to do since it might be the\r
+                complete sequence, and thus, something we don't want\r
+                copied.\r
+            */\r
+            if (data[i] == cont_seq[cmatch])\r
+            {\r
+                cmatch++;\r
+                if (cmatch == strlen(cont_seq))\r
+                    cmatch = 0; // complete match.  just reset the counter\r
+                continue;\r
+            }\r
+            else if (cmatch)\r
+            {\r
+                /*\r
+                    match failed, so we have to copy what matched before\r
+                    falling through and copying this character.  In reality,\r
+                    this will only ever be just the newline character, but\r
+                    it doesn't hurt to be precise.\r
+                */\r
+                strncpy(bp, cont_seq, cmatch);\r
+                bp += cmatch;\r
+                buf_len += cmatch;\r
+                cmatch = 0;\r
+            }\r
+        }\r
+\r
+        // copy this char\r
+        *bp++ = data[i];\r
+        buf_len++;\r
+    }\r
+\r
        buf[buf_len] = NULLCHAR;
        next_out = leftover_len;
        leftover_start = 0;
@@ -2214,8 +2261,6 @@ read_from_ics(isr, closure, data, count, error)
                  sprintf(str,
                          "/set-quietly interface %s\n/set-quietly style 12\n",
                          programVersion);
-                 strcat(str, "/set-quietly wrap 0\n");
-
                } else if (ics_type == ICS_CHESSNET) {
                  sprintf(str, "/style 12\n");
                } else {
@@ -2225,7 +2270,6 @@ read_from_ics(isr, closure, data, count, error)
 #ifdef WIN32
                  strcat(str, "$iset nohighlight 1\n");
 #endif
-                 strcat(str, "$iset nowrap 1\n");
                  strcat(str, "$iset lock 1\n$style 12\n");
                }
                SendToICS(str);
@@ -6680,7 +6724,6 @@ if(appData.debugMode) fprintf(debugFP, "nodes = %d, %lld\n", (int) programStats.
                 if (currentMove == forwardMostMove || gameMode == AnalyzeMode
                         || gameMode == AnalyzeFile || appData.icsEngineAnalyze) {
                    DisplayMove(currentMove - 1);
-                   DisplayAnalysis();
                }
                return;
 
@@ -6708,7 +6751,6 @@ if(appData.debugMode) fprintf(debugFP, "nodes = %d, %lld\n", (int) programStats.
                if (currentMove == forwardMostMove || gameMode==AnalyzeMode || 
                            gameMode == AnalyzeFile || appData.icsEngineAnalyze) {
                    DisplayMove(currentMove - 1);
-                   DisplayAnalysis();
                }
                return;
            } else if (sscanf(message,"stat01: %d " u64Display " %d %d %d %s",
@@ -6733,7 +6775,6 @@ if(appData.debugMode) fprintf(debugFP, "nodes = %d, %lld\n", (int) programStats.
 
                 SendProgramStatsToFrontend( cps, &programStats );
 
-               DisplayAnalysis();
                return;
 
            } else if (strncmp(message,"++",2) == 0) {
@@ -6769,7 +6810,6 @@ if(appData.debugMode) fprintf(debugFP, "nodes = %d, %lld\n", (int) programStats.
                if (currentMove == forwardMostMove || gameMode==AnalyzeMode ||
                            gameMode == AnalyzeFile || appData.icsEngineAnalyze) {
                    DisplayMove(currentMove - 1);
-                   DisplayAnalysis();
                }
                return;
            }
@@ -9591,7 +9631,7 @@ SaveGamePGN(f)
            fprintf(f, " ");
            linelen++;
        }
-       fprintf(f, numtext);
+       fprintf(f, "%s", numtext);
        linelen += numlen;
 
        /* Get move */
@@ -9609,7 +9649,7 @@ SaveGamePGN(f)
            fprintf(f, " ");
            linelen++;
        }
-       fprintf(f, move_buffer);
+       fprintf(f, "%s", move_buffer);
        linelen += movelen;
 
         /* [AS] Add PV info if present */
@@ -9653,7 +9693,7 @@ SaveGamePGN(f)
                fprintf(f, " ");
                linelen++;
            }
-           fprintf(f, move_buffer);
+           fprintf(f, "%s", move_buffer);
            linelen += movelen;
         }
 
@@ -10316,8 +10356,7 @@ AnalyzeModeEvent()
        first.analyzing = TRUE;
        /*first.maybeThinking = TRUE;*/
        first.maybeThinking = FALSE; /* avoid killing GNU Chess */
-       AnalysisPopUp(_("Analysis"),
-                     _("Starting analysis mode...\nIf this message stays up, your chess program does not support analysis."));
+       EngineOutputPopUp();
     }
     if (!appData.icsEngineAnalyze) gameMode = AnalyzeMode;
     pausing = FALSE;
@@ -10343,8 +10382,7 @@ AnalyzeFileEvent()
        first.analyzing = TRUE;
        /*first.maybeThinking = TRUE;*/
        first.maybeThinking = FALSE; /* avoid killing GNU Chess */
-       AnalysisPopUp(_("Analysis"),
-                     _("Starting analysis mode...\nIf this message stays up, your chess program does not support analysis."));
+       EngineOutputPopUp();
     }
     gameMode = AnalyzeFile;
     pausing = FALSE;
@@ -10842,7 +10880,6 @@ ExitAnalyzeMode()
       SendToProgram("exit\n", &first);
       first.analyzing = FALSE;
     }
-    AnalysisPopDown();
     thinkOutput[0] = NULLCHAR;
 }
 
@@ -12543,7 +12580,7 @@ PeriodicUpdatesEvent(newState)
     appData.periodicUpdates=newState;
 
     /* Display type changes, so update it now */
-    DisplayAnalysis();
+//    DisplayAnalysis();
 
     /* Get the ball rolling again... */
     if (newState) {
@@ -12683,92 +12720,6 @@ DisplayMove(moveNumber)
 }
 
 void
-DisplayAnalysisText(text)
-     char *text;
-{
-    char buf[MSG_SIZ];
-
-    if (gameMode == AnalyzeMode || gameMode == AnalyzeFile 
-               || appData.icsEngineAnalyze) {
-       sprintf(buf, "Analysis (%s)", first.tidy);
-       AnalysisPopUp(buf, text);
-    }
-}
-
-static int
-only_one_move(str)
-     char *str;
-{
-    while (*str && isspace(*str)) ++str;
-    while (*str && !isspace(*str)) ++str;
-    if (!*str) return 1;
-    while (*str && isspace(*str)) ++str;
-    if (!*str) return 1;
-    return 0;
-}
-
-void
-DisplayAnalysis()
-{
-    char buf[MSG_SIZ];
-    char lst[MSG_SIZ / 2];
-    double nps;
-    static char *xtra[] = { "", " (--)", " (++)" };
-    int h, m, s, cs;
-  
-    if (programStats.time == 0) {
-       programStats.time = 1;
-    }
-  
-    if (programStats.got_only_move) {
-       safeStrCpy(buf, programStats.movelist, sizeof(buf));
-    } else {
-        safeStrCpy( lst, programStats.movelist, sizeof(lst));
-
-        nps = (u64ToDouble(programStats.nodes) /
-             ((double)programStats.time /100.0));
-
-       cs = programStats.time % 100;
-       s = programStats.time / 100;
-       h = (s / (60*60));
-       s = s - h*60*60;
-       m = (s/60);
-       s = s - m*60;
-
-       if (programStats.moves_left > 0 && appData.periodicUpdates) {
-         if (programStats.move_name[0] != NULLCHAR) {
-           sprintf(buf, "depth=%d %d/%d(%s) %+.2f %s%s\nNodes: " u64Display " NPS: %d\nTime: %02d:%02d:%02d.%02d",
-                   programStats.depth,
-                   programStats.nr_moves-programStats.moves_left,
-                   programStats.nr_moves, programStats.move_name,
-                   ((float)programStats.score)/100.0, lst,
-                   only_one_move(lst)?
-                   xtra[programStats.got_fail] : "",
-                   (u64)programStats.nodes, (int)nps, h, m, s, cs);
-         } else {
-           sprintf(buf, "depth=%d %d/%d %+.2f %s%s\nNodes: " u64Display " NPS: %d\nTime: %02d:%02d:%02d.%02d",
-                   programStats.depth,
-                   programStats.nr_moves-programStats.moves_left,
-                   programStats.nr_moves, ((float)programStats.score)/100.0,
-                   lst,
-                   only_one_move(lst)?
-                   xtra[programStats.got_fail] : "",
-                   (u64)programStats.nodes, (int)nps, h, m, s, cs);
-         }
-       } else {
-           sprintf(buf, "depth=%d %+.2f %s%s\nNodes: " u64Display " NPS: %d\nTime: %02d:%02d:%02d.%02d",
-                   programStats.depth,
-                   ((float)programStats.score)/100.0,
-                   lst,
-                   only_one_move(lst)?
-                   xtra[programStats.got_fail] : "",
-                   (u64)programStats.nodes, (int)nps, h, m, s, cs);
-       }
-    }
-    DisplayAnalysisText(buf);
-}
-
-void
 DisplayComment(moveNumber, text)
      int moveNumber;
      char *text;
@@ -13494,6 +13445,14 @@ PositionToFEN(move, overrideCastling)
        } else {
            *p++ = '-';
        }
+    } else if(move == backwardMostMove) {
+       // [HGM] perhaps we should always do it like this, and forget the above?
+       if(epStatus[move] >= 0) {
+           *p++ = epStatus[move] + AAA;
+           *p++ = whiteToPlay ? '6'+BOARD_HEIGHT-8 : '3';
+       } else {
+           *p++ = '-';
+       }
     } else {
        *p++ = '-';
     }