Bugfix for safeStrCpy patch for XBoard
[xboard.git] / xboard.c
index 849ab40..d1d00a3 100644 (file)
--- a/xboard.c
+++ b/xboard.c
@@ -141,6 +141,12 @@ extern char *getenv();
 # endif
 #endif
 
+
+# if HAVE_LIBREADLINE /* add gnu-readline support */
+#include <readline/readline.h>
+#include <readline/history.h>
+# endif
+
 #include <X11/Intrinsic.h>
 #include <X11/StringDefs.h>
 #include <X11/Shell.h>
@@ -191,6 +197,7 @@ extern char *getenv();
 
 #include "frontend.h"
 #include "backend.h"
+#include "backendz.h"
 #include "moves.h"
 #include "xboard.h"
 #include "childio.h"
@@ -241,6 +248,7 @@ RETSIGTYPE TermSizeSigHandler P((int sig));
 void CreateGCs P((void));
 void CreateXIMPieces P((void));
 void CreateXPMPieces P((void));
+void CreateXPMBoard P((char *s, int n));
 void CreatePieces P((void));
 void CreatePieceMenus P((void));
 Widget CreateMenuBar P((Menu *mb));
@@ -467,6 +475,11 @@ void SettingsPopDown P(());
 void update_ics_width P(());
 int get_term_width P(());
 int CopyMemoProc P(());
+
+# if HAVE_LIBREADLINE /* add gnu-readline support */
+static void ReadlineCompleteHandler P((char *)); 
+# endif
+
 /*
 * XBoard depends on Xt R4 or higher
 */
@@ -502,6 +515,13 @@ FileProc fileProc;
 char *fileOpenMode;
 char installDir[] = "."; // [HGM] UCI: needed for UCI; probably needs run-time initializtion
 
+# if HAVE_LIBREADLINE /* gnu readline support */
+static char* readline_buffer;
+static int readline_complete=0;
+extern int sending_ICS_login;
+extern int sending_ICS_password;
+#endif
+
 Position commentX = -1, commentY = -1;
 Dimension commentW, commentH;
 typedef unsigned int BoardSize;
@@ -543,7 +563,8 @@ Pixmap pieceBitmap2[2][(int)BlackPawn+4];       /* [HGM] pieces */
 Pixmap xpmPieceBitmap[4][(int)BlackPawn];      /* LL, LD, DL, DD actually used*/
 Pixmap xpmPieceBitmap2[4][(int)BlackPawn+4];   /* LL, LD, DL, DD set to select from */
 Pixmap xpmLightSquare, xpmDarkSquare, xpmJailSquare;
-int useImages, useImageSqs;
+Pixmap xpmBoardBitmap[2];
+int useImages, useImageSqs, useTexture, textureW[2], textureH[2];
 XImage *ximPieceBitmap[4][(int)BlackPawn+4];   /* LL, LD, DL, DD */
 Pixmap ximMaskPm[(int)BlackPawn];               /* clipmasks, used for XIM pieces */
 Pixmap ximMaskPm2[(int)BlackPawn+4];            /* clipmasks, used for XIM pieces */
@@ -1060,8 +1081,9 @@ char globalTranslations[] =
                                 \"Send to second chess program:\",,2) \n";
 
 char boardTranslations[] =
-   "<Btn1Down>: HandleUserMove() \n \
-   <Btn1Up>: HandleUserMove() \n \
+   "<Btn1Down>: HandleUserMove(0) \n \
+   Shift<Btn1Up>: HandleUserMove(1) \n \
+   <Btn1Up>: HandleUserMove(0) \n \
    <Btn1Motion>: AnimateUserMove() \n \
    <Btn3Motion>: HandlePV() \n \
    <Btn3Up>: PieceMenuPopup(menuB) \n \
@@ -1450,7 +1472,7 @@ SetCommPortDefaults()
 void
 SaveFontArg(FILE *f, ArgDescriptor *ad)
 {
-  char *name, buf[MSG_SIZ];
+  char *name;
   int i, n = (int)ad->argLoc;
   switch(n) {
     case 0: // CLOCK_FONT
@@ -1584,6 +1606,7 @@ void
 PopUpStartupDialog()
 {  // start menu not implemented in XBoard
 }
+
 char *
 ConvertToLine(int argc, char **argv)
 {
@@ -1591,14 +1614,17 @@ ConvertToLine(int argc, char **argv)
   int i;
 
   line[0] = NULLCHAR;
-  for(i=1; i<argc; i++) {
-    if( (strchr(argv[i], ' ') || strchr(argv[i], '\n') ||strchr(argv[i], '\t') )
-       && argv[i][0] != '{' )
-         sprintf(buf, "{%s} ", argv[i]);
-    else sprintf(buf, "%s ", argv[i]);
-    strcat(line, buf);
-  }
-    line[strlen(line)-1] = NULLCHAR;
+  for(i=1; i<argc; i++)
+    {
+      if( (strchr(argv[i], ' ') || strchr(argv[i], '\n') ||strchr(argv[i], '\t') )
+         && argv[i][0] != '{' )
+       snprintf(buf, sizeof(buf)/sizeof(buf[0]), "{%s} ", argv[i]);
+      else
+       snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%s ", argv[i]);
+      strncat(line, buf, 128*1024 - strlen(line) - 1 );
+    }
+
+  line[strlen(line)-1] = NULLCHAR;
   return line;
 }
 
@@ -1768,6 +1794,12 @@ main(argc, argv)
     setbuf(stdout, NULL);
     setbuf(stderr, NULL);
     debugFP = stderr;
+    
+# if HAVE_LIBREADLINE
+    /* install gnu-readline handler */
+    rl_callback_handler_install("> ", ReadlineCompleteHandler);
+    rl_readline_name="XBoard";
+# endif
 
     if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) {
        printf("%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION);
@@ -1937,6 +1969,7 @@ XBoard square size (hint): %d\n\
            fprintf(stderr, _("Closest %s size: %d\n"), IMAGE_EXT, squareSize);
        }
     }
+    if(appData.overrideLineGap >= 0) lineGap = appData.overrideLineGap;
 
     /* [HR] height treated separately (hacked) */
     boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
@@ -2513,6 +2546,8 @@ XBoard square size (hint): %d\n\
       CreatePieces();
     } else {
       CreateXPMPieces();
+      CreateXPMBoard(appData.liteBackTextureFile, 1);
+      CreateXPMBoard(appData.darkBackTextureFile, 0);
     }
 #else
     CreateXIMPieces();
@@ -2591,6 +2626,13 @@ ShutDownFrontEnd()
     if (saveSettingsOnExit) SaveSettings(settingsFileName);
     unlink(gameCopyFilename);
     unlink(gamePasteFilename);
+
+# if HAVE_LIBREADLINE
+    /* remove gnu-readline handler.  */
+    rl_callback_handler_remove();
+#endif
+
+    return;
 }
 
 RETSIGTYPE TermSizeSigHandler(int sig)
@@ -2637,22 +2679,33 @@ CmailSigHandlerCallBack(isr, closure, message, count, error)
 void
 ICSInitScript()
 {
-    FILE *f;
-    char buf[MSG_SIZ];
-    char *p;
+  /* try to open the icsLogon script, either in the location given
+   * or in the users HOME directory
+   */
+
+  FILE *f;
+  char buf[MSG_SIZ];
+  char *homedir;
 
-    f = fopen(appData.icsLogon, "r");
-    if (f == NULL) {
-       p = getenv("HOME");
-       if (p != NULL) {
-         safeStrCpy(buf, p, sizeof(buf)/sizeof(buf[0]) );
-         strcat(buf, "/");
-         strcat(buf, appData.icsLogon);
+  f = fopen(appData.icsLogon, "r");
+  if (f == NULL)
+    {
+      homedir = getenv("HOME");
+      if (homedir != NULL)
+       {
+         safeStrCpy(buf, homedir, sizeof(buf)/sizeof(buf[0]) );
+         strncat(buf, "/", MSG_SIZ - strlen(buf) - 1);
+         strncat(buf, appData.icsLogon,  MSG_SIZ - strlen(buf) - 1);
          f = fopen(buf, "r");
        }
     }
-    if (f != NULL)
-      ProcessICSInitScript(f);
+
+  if (f != NULL)
+    ProcessICSInitScript(f);
+  else
+    printf("Warning: Couldn't open icsLogon file (checked %s and %s).\n", appData.icsLogon, buf);
+
+  return;
 }
 
 void
@@ -3002,7 +3055,7 @@ FindFont(pattern, targetPxlSize)
     XFontStruct **fnt_list;
 
     base_fnt_lst = calloc(1, strlen(pattern) + 3);
-    sprintf(strInt, "%d", targetPxlSize);
+    snprintf(strInt, sizeof(strInt)/sizeof(strInt[0]), "%d", targetPxlSize);
     p = strstr(pattern, "--");
     strncpy(base_fnt_lst, pattern, p - pattern + 2);
     strcat(base_fnt_lst, strInt);
@@ -3352,6 +3405,16 @@ void CreateXIMPieces()
 }
 
 #if HAVE_LIBXPM
+void CreateXPMBoard(char *s, int kind)
+{
+    XpmAttributes attr;
+    attr.valuemask = 0;
+    if(s == NULL || *s == 0 || *s == '*') return;
+    if (XpmReadFileToPixmap(xDisplay, xBoardWindow, s, &(xpmBoardBitmap[kind]), NULL, &attr) == 0) {
+       useTexture |= kind + 1; textureW[kind] = attr.width; textureH[kind] = attr.height;
+    }
+}
+
 void CreateXPMPieces()
 {
     int piece, kind, r;
@@ -3502,12 +3565,12 @@ void CreatePieces()
 
     for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
        for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
-           sprintf(buf, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
-                   pieceBitmapNames[piece],
-                   ss, kind == SOLID ? 's' : 'o');
-           ReadBitmap(&pieceBitmap2[kind][piece], buf, NULL, ss, ss);
-           if(piece <= (int)WhiteKing)
-               pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
+         snprintf(buf, MSG_SIZ, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
+                  pieceBitmapNames[piece],
+                  ss, kind == SOLID ? 's' : 'o');
+         ReadBitmap(&pieceBitmap2[kind][piece], buf, NULL, ss, ss);
+         if(piece <= (int)WhiteKing)
+           pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
        }
     }
 
@@ -3530,13 +3593,13 @@ void CreatePieces()
 
     for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
        for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
-           sprintf(buf, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
-                   pieceBitmapNames[piece],
-                   ss, kind == SOLID ? 's' : 'o');
-           ReadBitmap(&pieceBitmap2[kind][piece], buf,
-                      bib->bits[kind][piece], ss, ss);
-           if(piece <= (int)WhiteKing)
-               pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
+         snprintf(buf, MSG_SIZ, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
+                  pieceBitmapNames[piece],
+                  ss, kind == SOLID ? 's' : 'o');
+         ReadBitmap(&pieceBitmap2[kind][piece], buf,
+                    bib->bits[kind][piece], ss, ss);
+         if(piece <= (int)WhiteKing)
+           pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
        }
     }
 
@@ -3558,11 +3621,11 @@ void ReadBitmap(pm, name, bits, wreq, hreq)
 
     if (*appData.bitmapDirectory != NULLCHAR) {
       safeStrCpy(fullname, appData.bitmapDirectory, sizeof(fullname)/sizeof(fullname[0]) );
-       strcat(fullname, "/");
-       strcat(fullname, name);
-       errcode = XReadBitmapFile(xDisplay, xBoardWindow, fullname,
-                                 &w, &h, pm, &x_hot, &y_hot);
-    fprintf(stderr, "load %s\n", name);
+      strncat(fullname, "/", MSG_SIZ - strlen(fullname) - 1);
+      strncat(fullname, name, MSG_SIZ - strlen(fullname) - 1);
+      errcode = XReadBitmapFile(xDisplay, xBoardWindow, fullname,
+                               &w, &h, pm, &x_hot, &y_hot);
+      fprintf(stderr, "load %s\n", name);
        if (errcode != BitmapSuccess) {
            switch (errcode) {
              case BitmapOpenFailed:
@@ -3680,7 +3743,7 @@ Widget CreateMenuBar(mb)
 
     while (mb->name != NULL) {
         safeStrCpy(menuName, "menu", sizeof(menuName)/sizeof(menuName[0]) );
-       strcat(menuName, mb->name);
+       strncat(menuName, mb->name, MSG_SIZ - strlen(menuName) - 1);
        j = 0;
        XtSetArg(args[j], XtNmenuName, XtNewString(menuName));  j++;
        if (tinyLayout) {
@@ -4018,11 +4081,34 @@ ClearPremoveHighlights()
   SetPremoveHighlights(-1, -1, -1, -1);
 }
 
-static void BlankSquare(x, y, color, piece, dest)
-     int x, y, color;
+static int CutOutSquare(x, y, x0, y0, kind)
+     int x, y, *x0, *y0, kind;
+{
+    int W = BOARD_WIDTH, H = BOARD_HEIGHT;
+    int nx = x/(squareSize + lineGap), ny = y/(squareSize + lineGap);
+    *x0 = 0; *y0 = 0;
+    if(textureW[kind] < squareSize || textureH[kind] < squareSize) return 0;
+    if(textureW[kind] < W*squareSize)
+       *x0 = (textureW[kind] - squareSize) * nx/(W-1);
+    else
+       *x0 = textureW[kind]*nx / W + (textureW[kind] - W*squareSize) / (2*W);
+    if(textureH[kind] < H*squareSize)
+       *y0 = (textureH[kind] - squareSize) * ny/(H-1);
+    else
+       *y0 = textureH[kind]*ny / H + (textureH[kind] - H*squareSize) / (2*H);
+    return 1;
+}
+
+static void BlankSquare(x, y, color, piece, dest, fac)
+     int x, y, color, fac;
      ChessSquare piece;
      Drawable dest;
-{
+{   // [HGM] extra param 'fac' for forcing destination to (0,0) for copying to animation buffer
+    int x0, y0;
+    if (useImages && color != 2 && (useTexture & color+1) && CutOutSquare(x, y, &x0, &y0, color)) {
+       XCopyArea(xDisplay, xpmBoardBitmap[color], dest, wlPieceGC, x0, y0,
+                 squareSize, squareSize, x*fac, y*fac);
+    } else
     if (useImages && useImageSqs) {
        Pixmap pm;
        switch (color) {
@@ -4038,7 +4124,7 @@ static void BlankSquare(x, y, color, piece, dest)
            break;
        }
        XCopyArea(xDisplay, pm, dest, wlPieceGC, 0, 0,
-                 squareSize, squareSize, x, y);
+                 squareSize, squareSize, x*fac, y*fac);
     } else {
        GC gc;
        switch (color) {
@@ -4053,7 +4139,7 @@ static void BlankSquare(x, y, color, piece, dest)
            gc = jailSquareGC;
            break;
        }
-       XFillRectangle(xDisplay, dest, gc, x, y, squareSize, squareSize);
+       XFillRectangle(xDisplay, dest, gc, x*fac, y*fac, squareSize, squareSize);
     }
 }
 
@@ -4146,7 +4232,7 @@ static void colorDrawPieceImage(piece, square_color, x, y, dest)
      int square_color, x, y;
      Drawable dest;
 {
-    int kind;
+    int kind, p = piece;
 
     switch (square_color) {
       case 1: /* light */
@@ -4168,6 +4254,15 @@ static void colorDrawPieceImage(piece, square_color, x, y, dest)
        }
        break;
     }
+    if(appData.upsideDown && flipView) kind ^= 2; // swap white and black pieces
+    if(useTexture & square_color+1) {
+        BlankSquare(x, y, square_color, piece, dest, 1); // erase previous contents with background
+       XSetClipMask(xDisplay, wlPieceGC, xpmMask[p]);
+       XSetClipOrigin(xDisplay, wlPieceGC, x, y);
+       XCopyArea(xDisplay, xpmPieceBitmap[kind][piece], dest, wlPieceGC, 0, 0, squareSize, squareSize, x, y);
+       XSetClipMask(xDisplay, wlPieceGC, None);
+       XSetClipOrigin(xDisplay, wlPieceGC, 0, 0);
+    } else
     XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
              dest, wlPieceGC, 0, 0,
              squareSize, squareSize, x, y);
@@ -4249,7 +4344,7 @@ void DrawSquare(row, column, piece, do_flash)
                  column == BOARD_LEFT-1 ||  column == BOARD_RGHT
               || (column == BOARD_LEFT-2 && row < BOARD_HEIGHT-gameInfo.holdingsSize)
                  || (column == BOARD_RGHT+1 && row >= gameInfo.holdingsSize) ) {
-                       BlankSquare(x, y, 2, EmptySquare, xBoardWindow);
+                       BlankSquare(x, y, 2, EmptySquare, xBoardWindow, 1);
 
                        // [HGM] print piece counts next to holdings
                        string[1] = NULLCHAR;
@@ -4281,7 +4376,7 @@ void DrawSquare(row, column, piece, do_flash)
                        }
     } else {
            if (piece == EmptySquare || appData.blindfold) {
-                       BlankSquare(x, y, square_color, piece, xBoardWindow);
+                       BlankSquare(x, y, square_color, piece, xBoardWindow, 1);
            } else {
                        drawfunc = ChooseDrawFunc();
                        if (do_flash && appData.flashCount > 0) {
@@ -4291,7 +4386,7 @@ void DrawSquare(row, column, piece, do_flash)
                                        XSync(xDisplay, False);
                                        do_flash_delay(flash_delay);
 
-                                       BlankSquare(x, y, square_color, piece, xBoardWindow);
+                                       BlankSquare(x, y, square_color, piece, xBoardWindow, 1);
                                        XSync(xDisplay, False);
                                        do_flash_delay(flash_delay);
                            }
@@ -4487,7 +4582,7 @@ void XDrawPosition(w, repaint, board)
     if(DrawSeekGraph()) return; // [HGM] seekgraph: suppress any drawing if seek graph up
 
     if (board == NULL) {
-       if (!lastBoardValid) return;
+       if (!lastBoardValid[nr]) return;
        board = lastBoard[nr];
     }
     if (!lastBoardValid[nr] || (nr == 0 && lastFlipView != flipView)) {
@@ -4603,6 +4698,7 @@ void HandleUserMove(w, event, prms, nprms)
      Cardinal *nprms;
 {
     if (w != boardWidget || errorExitStatus != -1) return;
+    if(nprms) shiftKey = !strcmp(prms[0], "1");
 
     if (promotionUp) {
        if (event->type == ButtonPress) {
@@ -5135,13 +5231,6 @@ void FileNamePopUp(label, def, proc, openMode)
      FileProc proc;
      char *openMode;
 {
-    Arg args[16];
-    Widget popup, layout, dialog, edit;
-    Window root, child;
-    int x, y, i;
-    int win_x, win_y;
-    unsigned int mask;
-
     fileProc = proc;           /* I can't see a way not */
     fileOpenMode = openMode;   /*   to use globals here */
     {   // [HGM] use file-selector dialog stolen from Ghostview
@@ -5149,8 +5238,8 @@ void FileNamePopUp(label, def, proc, openMode)
        int index; // this is not supported yet
        FILE *f;
        if(f = XsraSelFile(shellWidget, label, NULL, NULL, "could not open: ",
-           def, openMode, NULL, &name))
-               (void) (*fileProc)(f, index=0, name);
+                          def, openMode, NULL, &name))
+         (void) (*fileProc)(f, index=0, name);
     }
 }
 
@@ -5726,7 +5815,7 @@ SendPositionSelection(Widget w, Atom *selection, Atom *target,
      * automatically call XtFree on the value returned.  So have to
      * make a copy of it allocated with XtMalloc */
     selection_tmp= XtMalloc(strlen(selected_fen_position)+16);
-    safeStrCpy(selection_tmp, selected_fen_position, sizeof(selection_tmp)/sizeof(selection_tmp[0]) );
+    safeStrCpy(selection_tmp, selected_fen_position, strlen(selected_fen_position)+16 );
 
     *value_return=selection_tmp;
     *length_return=strlen(selection_tmp);
@@ -5991,7 +6080,7 @@ void AnalyzeModeProc(w, event, prms, nprms)
     /* [DM] icsEngineAnalyze [HGM] This is horrible code; reverse the gameMode and isEngineAnalyze tests! */
     if (appData.icsActive) {
         if (gameMode != IcsObserving) {
-            sprintf(buf,_("You are not observing a game"));
+         snprintf(buf, MSG_SIZ, _("You are not observing a game"));
             DisplayError(buf, 0);
             /* secure check */
             if (appData.icsEngineAnalyze) {
@@ -7279,9 +7368,9 @@ void AskQuestionReplyAction(w, event, prms, nprms)
 
     reply = XawDialogGetValueString(w = XtParent(w));
     safeStrCpy(buf, pendingReplyPrefix, sizeof(buf)/sizeof(buf[0]) );
-    if (*buf) strcat(buf, " ");
-    strcat(buf, reply);
-    strcat(buf, "\n");
+    if (*buf) strncat(buf, " ", MSG_SIZ - strlen(buf) - 1);
+    strncat(buf, reply, MSG_SIZ - strlen(buf) - 1);
+    strncat(buf, "\n",  MSG_SIZ - strlen(buf) - 1);
     OutputToProcess(pendingReplyPR, buf, strlen(buf), &err);
     AskQuestionPopDown();
 
@@ -7433,18 +7522,18 @@ Colorize(cc, continuation)
 
     if (textColors[(int)cc].bg > 0) {
        if (textColors[(int)cc].fg > 0) {
-           sprintf(buf, "\033[0;%d;%d;%dm", textColors[(int)cc].attr,
-                   textColors[(int)cc].fg, textColors[(int)cc].bg);
+         snprintf(buf, MSG_SIZ, "\033[0;%d;%d;%dm", textColors[(int)cc].attr,
+                  textColors[(int)cc].fg, textColors[(int)cc].bg);
        } else {
-           sprintf(buf, "\033[0;%d;%dm", textColors[(int)cc].attr,
-                   textColors[(int)cc].bg);
+         snprintf(buf, MSG_SIZ, "\033[0;%d;%dm", textColors[(int)cc].attr,
+                  textColors[(int)cc].bg);
        }
     } else {
        if (textColors[(int)cc].fg > 0) {
-           sprintf(buf, "\033[0;%d;%dm", textColors[(int)cc].attr,
+         snprintf(buf, MSG_SIZ, "\033[0;%d;%dm", textColors[(int)cc].attr,
                    textColors[(int)cc].fg);
        } else {
-           sprintf(buf, "\033[0;%dm", textColors[(int)cc].attr);
+         snprintf(buf, MSG_SIZ, "\033[0;%dm", textColors[(int)cc].attr);
        }
     }
     count = strlen(buf);
@@ -7713,11 +7802,11 @@ DisplayTimerLabel(w, color, timer, highlight)
       foregroundOrWarningColor = lowTimeWarningColor;
 
     if (appData.clockMode) {
-       sprintf(buf, "%s: %s", color, TimeString(timer));
-       XtSetArg(args[0], XtNlabel, buf);
+      snprintf(buf, MSG_SIZ, "%s: %s", color, TimeString(timer));
+      XtSetArg(args[0], XtNlabel, buf);
     } else {
-       sprintf(buf, "%s  ", color);
-       XtSetArg(args[0], XtNlabel, buf);
+      snprintf(buf, MSG_SIZ, "%s  ", color);
+      XtSetArg(args[0], XtNlabel, buf);
     }
 
     if (highlight) {
@@ -8066,16 +8155,98 @@ DoInputCallback(closure, source, xid)
        }
        q = is->buf;
        while (p < is->unused) {
-           *q++ = *p++;
+         *q++ = *p++;
        }
        is->unused = q;
     } else {
-       count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
-       if (count == -1)
-         error = errno;
-       else
-         error = 0;
-       (is->func)(is, is->closure, is->buf, count, error);
+# if HAVE_LIBREADLINE
+      /* check if input is from stdin, if yes, use gnu-readline */
+      if( is->fd==fileno(stdin) )
+       {
+         /* to clear the line */
+         printf("\r                                                 \r");
+         
+         /* read from stdin */
+         rl_callback_read_char(); 
+
+         /* redisplay the current line, check special case for login and password */
+         if(sending_ICS_password)
+           {
+             int i; char buf[MSG_SIZ];
+
+             bzero(buf,MSG_SIZ);
+
+             /* blank the password */
+             count = strlen(rl_line_buffer);
+             if(count>MSG_SIZ-1)
+               {
+                 printf("PROBLEM with readline\n");
+                 count=MSG_SIZ;
+               }
+             for(i=0;i<count;i++)
+               buf[i]='*';
+             i++;
+             buf[i]='\0';
+             printf("\rpassword: %s",buf);
+           }
+         else if (sending_ICS_login)
+           {
+             /* show login prompt */
+             count = strlen(rl_line_buffer);
+             printf("\rlogin: %s",rl_line_buffer);
+           }
+         else
+           rl_reset_line_state();
+         
+         if(readline_complete)
+           {
+             /* copy into XBoards buffer */
+             count = strlen(readline_buffer);
+             if (count>INPUT_SOURCE_BUF_SIZE-1)
+               {
+                 printf("PROBLEM with readline\n");
+                 count = INPUT_SOURCE_BUF_SIZE;
+               };
+             strncpy(is->buf,readline_buffer,count);
+             is->buf[count]='\n';count++; 
+
+             /* reset gnu-readline state */
+             free(readline_buffer);
+             readline_buffer=NULL;
+             readline_complete=0;
+
+             if (count == -1)
+               error = errno;
+             else
+               error = 0;
+             (is->func)(is, is->closure, is->buf, count, error);
+
+             /* are we done with the password? */
+             if(sending_ICS_password)
+               sending_ICS_password=0;
+             if(sending_ICS_login)
+               sending_ICS_login=0;
+           }
+       }
+      else
+       {
+         /* input not from stdin, use default method */
+         count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
+         if (count == -1)
+           error = errno;
+         else
+           error = 0;
+         (is->func)(is, is->closure, is->buf, count, error);
+       };
+#else /* no readline support */
+      count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
+      if (count == -1)
+       error = errno;
+      else
+       error = 0;
+      (is->func)(is, is->closure, is->buf, count, error);
+#endif
+
     }
 }
 
@@ -8131,28 +8302,36 @@ int OutputToProcess(pr, message, count, outError)
     ChildProc *cp = (ChildProc *) pr;
     int outCount;
 
+
     if (pr == NoProc)
     {
-        if (appData.noJoin || !appData.useInternalWrap)
-            outCount = fwrite(message, 1, count, stdout);
-        else
+      if (appData.noJoin || !appData.useInternalWrap)
+       outCount = fwrite(message, 1, count, stdout);
+      else
         {
-            int width = get_term_width();
-            int len = wrap(NULL, message, count, width, &line);
-            char *msg = malloc(len);
-            int dbgchk;
-
-            if (!msg)
-                outCount = fwrite(message, 1, count, stdout);
-            else
+         int width = get_term_width();
+         int len = wrap(NULL, message, count, width, &line);
+         char *msg = malloc(len);
+         int dbgchk;
+         
+         if (!msg)
+           outCount = fwrite(message, 1, count, stdout);
+         else
             {
-                dbgchk = wrap(msg, message, count, width, &line);
-                if (dbgchk != len && appData.debugMode)
-                    fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);
-                outCount = fwrite(msg, 1, dbgchk, stdout);
-                free(msg);
+             dbgchk = wrap(msg, message, count, width, &line);
+             if (dbgchk != len && appData.debugMode)
+               fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);
+             outCount = fwrite(msg, 1, dbgchk, stdout);
+             free(msg);
             }
         }
+      
+# if HAVE_LIBREADLINE
+      /* readline support */
+      if(strlen(rl_line_buffer))
+        printf("\n>  %s",rl_line_buffer);
+#endif
+
     }
     else
       outCount = write(cp->fdTo, message, count);
@@ -8612,6 +8791,7 @@ OverlayPiece(piece, clip, outline,  dest)
       kind = 0;
     else
       kind = 2;
+    if(appData.upsideDown && flipView) kind ^= 2;
     XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
              dest, clip,
              0, 0, squareSize, squareSize,
@@ -8631,7 +8811,7 @@ BeginAnimation(anim, piece, startColor, start)
   Pixmap mask;
 
   /* The old buffer is initialised with the start square (empty) */
-  BlankSquare(0, 0, startColor, EmptySquare, anim->saveBuf);
+  BlankSquare(start->x, start->y, startColor, EmptySquare, anim->saveBuf, 0);
   anim->prevFrame = *start;
 
   /* The piece will be drawn using its own bitmap as a matte   */
@@ -8736,6 +8916,29 @@ FrameSequence(anim, piece, startColor, start, finish, frames, nFrames)
   EndAnimation(anim, finish);
 }
 
+void
+AnimateAtomicCapture(Board board, int fromX, int fromY, int toX, int toY)
+{
+    int i, x, y;
+    ChessSquare piece = board[fromY][toY];
+    board[fromY][toY] = EmptySquare;
+    DrawPosition(FALSE, board);
+    if (flipView) {
+       x = lineGap + ((BOARD_WIDTH-1)-toX) * (squareSize + lineGap);
+       y = lineGap + toY * (squareSize + lineGap);
+    } else {
+       x = lineGap + toX * (squareSize + lineGap);
+       y = lineGap + ((BOARD_HEIGHT-1)-toY) * (squareSize + lineGap);
+    }
+    for(i=1; i<4*kFactor; i++) {
+       int r = squareSize * 9 * i/(20*kFactor - 5);
+       XFillArc(xDisplay, xBoardWindow, highlineGC,
+               x + squareSize/2 - r, y+squareSize/2 - r, 2*r, 2*r, 0, 64*360);
+       FrameDelay(appData.animSpeed);
+    }
+    board[fromY][toY] = piece;
+}
+
 /* Main control logic for deciding what to animate and how */
 
 void
@@ -8767,7 +8970,7 @@ AnimateMove(board, fromX, fromY, toX, toY)
 #if DONT_HOP
   hop = FALSE;
 #else
-  hop = (piece == WhiteKnight || piece == BlackKnight);
+  hop = abs(fromX-toX) == 1 && abs(fromY-toY) == 2 || abs(fromX-toX) == 2 && abs(fromY-toY) == 1;
 #endif
 
   if (appData.debugMode) {
@@ -8779,12 +8982,12 @@ AnimateMove(board, fromX, fromY, toX, toY)
   ScreenSquare(toX, toY, &finish, &endColor);
 
   if (hop) {
-    /* Knight: make diagonal movement then straight */
+    /* Knight: make straight movement then diagonal */
     if (abs(toY - fromY) < abs(toX - fromX)) {
        mid.x = start.x + (finish.x - start.x) / 2;
-       mid.y = finish.y;
+       mid.y = start.y;
      } else {
-       mid.x = finish.x;
+       mid.x = start.x;
        mid.y = start.y + (finish.y - start.y) / 2;
      }
   } else {
@@ -8798,6 +9001,11 @@ AnimateMove(board, fromX, fromY, toX, toY)
   else
     Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
   FrameSequence(&game, piece, startColor, &start, &finish, frames, nFrames);
+  if(Explode(board, fromX, fromY, toX, toY)) { // mark as damaged
+    int i,j;
+    for(i=0; i<BOARD_WIDTH; i++) for(j=0; j<BOARD_HEIGHT; j++)
+      if((i-toX)*(i-toX) + (j-toY)*(j-toY) < 6) damage[0][j][i] = True;
+  }
 
   /* Be sure end square is redrawn */
   damage[0][toY][toX] = True;
@@ -8915,7 +9123,7 @@ DrawDragPiece ()
      it's being dragged around the board. So we erase the square
      that the piece is on and draw it at the last known drag point. */
   BlankSquare(player.startSquare.x, player.startSquare.y,
-               player.startColor, EmptySquare, xBoardWindow);
+               player.startColor, EmptySquare, xBoardWindow, 1);
   AnimationFrame(&player, &player.prevFrame, player.dragPiece);
   damage[0][player.startBoardY][player.startBoardX] = TRUE;
 }
@@ -8940,17 +9148,33 @@ int get_term_width()
     return default_width;
 }
 
-void update_ics_width()
+void
+update_ics_width()
 {
-    static int old_width = 0;
-    int new_width = get_term_width();
+  static int old_width = 0;
+  int new_width = get_term_width();
 
-    if (old_width != new_width)
-       ics_printf("set width %d\n", new_width);
-    old_width = new_width;
+  if (old_width != new_width)
+    ics_printf("set width %d\n", new_width);
+  old_width = new_width;
 }
 
 void NotifyFrontendLogin()
 {
     update_ics_width();
 }
+
+# if HAVE_LIBREADLINE
+static void 
+ReadlineCompleteHandler(char* ptr)
+{
+  /* make gnu-readline keep the history */
+  readline_buffer = ptr;
+  readline_complete = 1;
+  
+  if (ptr && *ptr && !sending_ICS_password && !sending_ICS_login)
+    add_history(ptr);
+
+  return;
+}
+#endif