Add libedit/readline support to ss
authorGreg Hudson <ghudson@mit.edu>
Fri, 22 Jul 2011 00:26:56 +0000 (00:26 +0000)
committerGreg Hudson <ghudson@mit.edu>
Fri, 22 Jul 2011 00:26:56 +0000 (00:26 +0000)
By default, look for libedit (using pkg-config) and use it in libss.
Alternatively, the builder can explicitly ask for GNU Readline, but
using it will break the dejagnu test suite and will also add a GPL
dependency to libss and the programs using it.

ticket: 6931

git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@25035 dc483132-0cff-0310-8789-dd5450dbe970

src/config/pre.in
src/configure.in
src/util/ss/Makefile.in
src/util/ss/listen.c

index 7b96ebc7d7aae624763aade5b4fbc33707c7eb55..67117d6b486dd1f9d44bd7615694f8485b6179d8 100644 (file)
@@ -369,9 +369,13 @@ SS_DEPS-k5 = $(BUILDTOP)/include/ss/ss.h $(BUILDTOP)/include/ss/ss_err.h
 # GEN_LIB is -lgen if needed for regexp
 GEN_LIB                = @GEN_LIB@
 
+# Editline or readline flags and libraries.
+RL_CFLAGS      = @RL_CFLAGS@
+RL_LIBS                = @RL_LIBS@
+
 SS_LIB         = $(SS_LIB-@SS_VERSION@)
 SS_LIB-sys     = @SS_LIB@
-SS_LIB-k5      = $(TOPLIBD)/libss.a
+SS_LIB-k5      = $(TOPLIBD)/libss.a $(RL_LIBS)
 KDB5_LIB       = -lkdb5 $(KDB5_PLUGIN_LIBS)
 
 DL_LIB         = @DL_LIB@
index 4ed9e31e376ac8c8ebb43dac9805c611ef69264b..b057a3b483dc132dd2a9fbe34d39bd7586ca29a5 100644 (file)
@@ -1100,6 +1100,44 @@ if test "$ac_cv_lib_socket" = "yes" -a "$ac_cv_lib_nsl" = "yes"; then
        AC_DEFINE(BROKEN_STREAMS_SOCKETS,1,[Define if socket can't be bound to 0.0.0.0])
 fi
 
+# Compile with libedit support in ss by default if available.  Compile
+# with readline only if asked, to avoid a default GPL dependency.
+# Building with readline also breaks the dejagnu test suite.
+AC_ARG_WITH([libedit],
+           AC_HELP_STRING([--without-libedit], [do not compile with libedit]),
+           [], [with_libedit=default])
+AC_ARG_WITH([readline],
+           AC_HELP_STRING([--with-readline], [compile with GNU Readline]),
+           [], [with_readline=no])
+AC_MSG_CHECKING([for readline support])
+if test "x$with_readline" = xyes; then
+  with_libedit=no
+fi
+RL_CFLAGS=
+RL_LIBS=
+if test "x$with_libedit" != xno; then
+  if RL_CFLAGS=`pkg-config --cflags libedit 2>&1`; then
+    RL_LIBS=`pkg-config --libs libedit`
+    AC_DEFINE([HAVE_LIBEDIT], 1, [Define if building with libedit.])
+    AC_MSG_RESULT([using libedit])
+  elif test "x$with_libedit" = yes; then
+    # We were explicitly asked for libedit and couldn't find it.
+    AC_MSG_ERROR([Could not detect libedit with pkg-config.])
+  else
+    AC_MSG_RESULT([not using any])
+  fi
+elif test "x$with_readline" = xyes; then
+  AC_MSG_RESULT([using GNU Readline])
+  AC_CHECK_LIB([readline], [main], :,
+              AC_MSG_FAILURE([Cannot find readline library.]), [-lncurses])
+  AC_DEFINE([HAVE_READLINE], 1, [Define if building with GNU Readline.])
+  RL_LIBS='-lreadline -lhistory -lncurses'
+else
+  AC_MSG_RESULT([not using any])
+fi
+AC_SUBST([RL_CFLAGS])
+AC_SUBST([RL_LIBS])
+
 AC_CONFIG_FILES(krb5-config, [chmod +x krb5-config])
 V5_AC_OUTPUT_MAKEFILE(.
 
index 3f6fd84f9d198a03a9ea9362a59a4c53f1c93a63..48f022925e5a51fe8f09f8ed7a5f349a156c75e2 100644 (file)
@@ -26,7 +26,7 @@ install-unix:: install-libs
 # hard coded ../et is so com_err.h works
 # CFLAGS= -g
 # CPPFLAGS= -I${INCDIR} -I. -I.. -I../et
-LOCALINCLUDES= -I. -I$(srcdir)/
+LOCALINCLUDES= -I. -I$(srcdir)/ $(RL_CFLAGS)
 
 # with ss_err.o first, ss_err.h should get rebuilt first too.  should not
 # be relying on this, though.
index f7be47b13b55b80f911a423dbc2f2832494264af..10e04654a45da849f99985aca708673ebb777a30 100644 (file)
 #include <termios.h>
 #include <sys/param.h>
 
+#if defined(HAVE_LIBEDIT)
+#include <editline/readline.h>
+#include <editline/history.h>
+#elif defined(HAVE_READLINE)
+#include <readline/readline.h>
+#include <readline/history.h>
+#else
+#define NO_READLINE
+#endif
+
 static ss_data *current_info;
 static jmp_buf listen_jmpb;
 
-static RETSIGTYPE print_prompt()
+#ifdef NO_READLINE
+/* Dumb replacement for readline when we don't have support for a real one. */
+static char *readline(const char *prompt)
 {
     struct termios termbuf;
+    char input[BUFSIZ];
 
     if (tcgetattr(STDIN_FILENO, &termbuf) == 0) {
         termbuf.c_lflag |= ICANON|ISIG|ECHO;
         tcsetattr(STDIN_FILENO, TCSANOW, &termbuf);
     }
-    (void) fputs(current_info->prompt, stdout);
-    (void) fflush(stdout);
+    printf("%s", prompt);
+    fflush(stdout);
+    if (fgets(input, BUFSIZ, stdin) == NULL)
+        return NULL;
+    input[strcspn(input, "\r\n")] = '\0';
+    return strdup(input);
+}
+
+/* No-op replacement for add_history() when we have no readline support. */
+static void add_history(const char *line)
+{
 }
+#endif
 
 static RETSIGTYPE listen_int_handler(signo)
     int signo;
@@ -41,9 +64,7 @@ int ss_listen (sci_idx)
 {
     register char *cp;
     register ss_data *info;
-    char input[BUFSIZ];
-    char buffer[BUFSIZ];
-    char *volatile end = buffer;
+    char *input;
     int code;
     jmp_buf old_jmpb;
     ss_data *old_info = current_info;
@@ -88,8 +109,6 @@ int ss_listen (sci_idx)
     (void) sigsetmask(mask);
 #endif
     while(!info->abort) {
-        print_prompt();
-        *end = '\0';
 #ifdef POSIX_SIGNALS
         nsig.sa_handler = listen_int_handler;   /* fgets is not signal-safe */
         osig = csig;
@@ -98,29 +117,26 @@ int ss_listen (sci_idx)
             csig = osig;
 #else
         old_sig_cont = sig_cont;
-        sig_cont = signal(SIGCONT, print_prompt);
-        if (sig_cont == print_prompt)
+        sig_cont = signal(SIGCONT, listen_int_handler);
+        if (sig_cont == listen_int_handler)
             sig_cont = old_sig_cont;
 #endif
-        if (fgets(input, BUFSIZ, stdin) != input) {
+
+        input = readline(current_info->prompt);
+        if (input == NULL) {
             code = SS_ET_EOF;
             goto egress;
         }
-        cp = strchr(input, '\n');
-        if (cp) {
-            *cp = '\0';
-            if (cp == input)
-                continue;
-        }
+        add_history(input);
+
 #ifdef POSIX_SIGNALS
         sigaction(SIGCONT, &csig, (struct sigaction *)0);
 #else
         (void) signal(SIGCONT, sig_cont);
 #endif
-        for (end = input; *end; end++)
-            ;
 
         code = ss_execute_line (sci_idx, input);
+        free(input);
         if (code == SS_ET_COMMAND_NOT_FOUND) {
             register char *c = input;
             while (*c == ' ' || *c == '\t')