adding gnu-readline support
[xboard.git] / xboard.c
index 3d62a69..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;
@@ -1585,6 +1603,7 @@ void
 PopUpStartupDialog()
 {  // start menu not implemented in XBoard
 }
+
 char *
 ConvertToLine(int argc, char **argv)
 {
@@ -1592,15 +1611,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] != '{' )
-      snprintf(buf, sizeof(buf)/sizeof(buf[0]), "{%s} ", argv[i]);
-    else
-      snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%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;
 }
 
@@ -1770,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);
@@ -2593,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)
@@ -2639,22 +2673,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
@@ -3560,11 +3605,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:
@@ -3682,7 +3727,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) {
@@ -7274,9 +7319,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();
 
@@ -8061,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
+
     }
 }
 
@@ -8126,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);
@@ -8950,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