adding gnu-readline support
authorArun Persaud <arun@nubati.net>
Wed, 31 Mar 2010 03:24:49 +0000 (20:24 -0700)
committerArun Persaud <arun@nubati.net>
Fri, 8 Oct 2010 01:51:10 +0000 (18:51 -0700)
should make the user interface for xboard a bit nicer. In the end we want to have a separate input window, but this probably will have to wait until the GTK version.

Makefile.am
backend.c
configure.ac
xboard.c

index fba80a8..a669994 100644 (file)
@@ -30,7 +30,7 @@ xboard_SOURCES = backend.c backend.h backendz.h \
                 filebrowser/draw.c filebrowser/path.c \
                 filebrowser/dir.c filebrowser/xstat.h \
                 $(ZPY)
-xboard_LDADD = -lm @XAW_LIBS@ @X_LIBS@ 
+xboard_LDADD = -lm @XAW_LIBS@ @X_LIBS@ @LIBREADLINE@
 
 EXTRA_DIST = pixmaps bitmaps winboard sounds filebrowser/README \
        xboard.texi gpl.texinfo texi2man texinfo.tex xboard.man \
index f936459..eed8bff 100644 (file)
--- a/backend.c
+++ b/backend.c
@@ -449,7 +449,11 @@ int adjudicateLossPlies = 6;
 char white_holding[64], black_holding[64];
 TimeMark lastNodeCountTime;
 long lastNodeCount=0;
+
 int have_sent_ICS_logon = 0;
+int sending_ICS_login    = 0;
+int sending_ICS_password = 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;
@@ -3108,10 +3112,17 @@ read_from_ics(isr, closure, data, count, error)
            if (!have_sent_ICS_logon && looking_at(buf, &i, "login:")) {
                ICSInitScript();
                have_sent_ICS_logon = 1;
+               sending_ICS_password = 0; // in case we come back to login
+               sending_ICS_login = 1; 
                continue;
            }
-
-           if (ics_getting_history != H_GETTING_MOVES /*smpos kludge*/ &&
+           /* need to shadow the password */
+           if (!sending_ICS_password && looking_at(buf, &i, "password:")) {
+             sending_ICS_password = 1;
+             continue;
+           }
+             
+           if (ics_getting_history != H_GETTING_MOVES /*smpos kludge*/ && 
                (looking_at(buf, &i, "\n<12> ") ||
                 looking_at(buf, &i, "<12> "))) {
                loggedOn = TRUE;
index 712c250..64844e1 100644 (file)
@@ -61,7 +61,6 @@ AH_TEMPLATE([USE_XAW3D],[template])
 AH_TEMPLATE([X_LOCALE],[template])
 
 
-
 if test -z "$CFLAGS" ; then
 dnl| Prevent the next macro from setting CFLAGS to -g
   CFLAGS=" "
@@ -164,6 +163,28 @@ if test "$xaw_headers" = "no" ; then
 fi
 
 
+dnl | test for readline
+AC_ARG_WITH([readline],
+           [AS_HELP_STRING([--with-readline],
+                           [support fancy command line editing @<:@default=yes@:>@])
+           ],
+            [],
+           [with_readline=yes])
+          
+LIBREADLINE=
+AS_IF([test "x$with_readline" != xno],
+      [AC_CHECK_LIB([readline], [main],
+                    [AC_SUBST([LIBREADLINE], ["-lreadline "])
+                     AC_DEFINE([HAVE_LIBREADLINE], [1],
+                               [Define if you have libreadline])
+                    ],
+                    [if test "x$with_readline" != xyes; then
+                     AC_MSG_FAILURE(
+                     [--with-readline was given, but test for readline failed])
+                            fi
+                   ], "")])
+
+
 AC_CANONICAL_HOST
 
 dnl| The following info is mostly gathered from GNU Emacs 19.24.  Basically,
@@ -441,6 +462,7 @@ echo "        infodir:         $infodir   (info files will go here)"
 echo "        sysconfdir:      $sysconfdir   (xboard.conf will go here)"
 echo ""
 echo "        Xaw3d:           $with_xaw3d"
+echo "        readline:        $with_readline"
 echo ""
 echo "        xpm:             $enable_xpm"
 echo "        ptys:            $enable_ptys"
index 9a073d0..0f12af6 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>
@@ -468,6 +474,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
 */
@@ -503,6 +514,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;
@@ -1773,6 +1791,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);
@@ -2596,6 +2620,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)
@@ -8075,16 +8106,97 @@ 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 */
+         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
+
     }
 }
 
@@ -8140,28 +8252,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);
@@ -8964,3 +9084,18 @@ 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