From ed8bc7b5e8ba1f72a0ae083b3005fbe18718544b Mon Sep 17 00:00:00 2001 From: Greg Hudson Date: Fri, 22 Jul 2011 00:26:56 +0000 Subject: [PATCH] Add libedit/readline support to ss 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 | 6 ++++- src/configure.in | 38 +++++++++++++++++++++++++++++ src/util/ss/Makefile.in | 2 +- src/util/ss/listen.c | 54 ++++++++++++++++++++++++++--------------- 4 files changed, 79 insertions(+), 21 deletions(-) diff --git a/src/config/pre.in b/src/config/pre.in index 7b96ebc7d..67117d6b4 100644 --- a/src/config/pre.in +++ b/src/config/pre.in @@ -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@ diff --git a/src/configure.in b/src/configure.in index 4ed9e31e3..b057a3b48 100644 --- a/src/configure.in +++ b/src/configure.in @@ -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(. diff --git a/src/util/ss/Makefile.in b/src/util/ss/Makefile.in index 3f6fd84f9..48f022925 100644 --- a/src/util/ss/Makefile.in +++ b/src/util/ss/Makefile.in @@ -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. diff --git a/src/util/ss/listen.c b/src/util/ss/listen.c index f7be47b13..10e04654a 100644 --- a/src/util/ss/listen.c +++ b/src/util/ss/listen.c @@ -14,20 +14,43 @@ #include #include +#if defined(HAVE_LIBEDIT) +#include +#include +#elif defined(HAVE_READLINE) +#include +#include +#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') -- 2.26.2