By default, continue to use libreadline, but if `--with-cli=linenoise`
is passed to configure, build the linenoise implementation instead.

Signed-off-by: Jeremy Sowden <jer...@azazel.net>
---
 configure.ac             | 17 ++++++++---
 include/cli.h            |  2 +-
 src/cli.c                | 64 ++++++++++++++++++++++++++++++++++------
 tests/build/run-tests.sh |  4 +--
 4 files changed, 71 insertions(+), 16 deletions(-)

diff --git a/configure.ac b/configure.ac
index 68f97f090535..73654b005cd2 100644
--- a/configure.ac
+++ b/configure.ac
@@ -68,12 +68,21 @@ AC_CHECK_LIB([gmp],[__gmpz_init], , AC_MSG_ERROR([No 
suitable version of libgmp
 AM_CONDITIONAL([BUILD_MINIGMP], [test "x$with_mini_gmp" = xyes])
 
 AC_ARG_WITH([cli], [AS_HELP_STRING([--without-cli],
-            [disable interactive CLI (libreadline support)])],
-            [], [with_cli=yes])
-AS_IF([test "x$with_cli" != xno], [
+            [disable interactive CLI (libreadline or linenoise support)])],
+            [], [with_cli=readline])
+
+AS_IF([test "x$with_cli" = xreadline], [
 AC_CHECK_LIB([readline], [readline], ,
-            AC_MSG_ERROR([No suitable version of libreadline found]))
+        AC_MSG_ERROR([No suitable version of libreadline found]))
 AC_DEFINE([HAVE_LIBREADLINE], [1], [])
+],
+      [test "x$with_cli" = xlinenoise], [
+AC_CHECK_LIB([linenoise], [linenoise], ,
+        AC_MSG_ERROR([No suitable version of linenoise found]))
+AC_DEFINE([HAVE_LIBLINENOISE], [1], [])
+],
+      [test "x$with_cli" != xno], [
+AC_MSG_ERROR([unexpected CLI value: $with_cli])
 ])
 AM_CONDITIONAL([BUILD_CLI], [test "x$with_cli" != xno])
 
diff --git a/include/cli.h b/include/cli.h
index 023f004b8dab..d82517750abc 100644
--- a/include/cli.h
+++ b/include/cli.h
@@ -4,7 +4,7 @@
 #include <nftables/libnftables.h>
 #include <config.h>
 
-#ifdef HAVE_LIBREADLINE
+#if defined(HAVE_LIBREADLINE) || defined(HAVE_LIBLINENOISE)
 extern int cli_init(struct nft_ctx *nft);
 #else
 static inline int cli_init(struct nft_ctx *nft)
diff --git a/src/cli.c b/src/cli.c
index f1e89926f2bc..4c0c3e9d67c6 100644
--- a/src/cli.c
+++ b/src/cli.c
@@ -21,16 +21,36 @@
 #include <string.h>
 #include <ctype.h>
 #include <limits.h>
+#ifdef HAVE_LIBREADLINE
 #include <readline/readline.h>
 #include <readline/history.h>
+#else
+#include <linenoise.h>
+#endif
 
 #include <cli.h>
 #include <list.h>
 
 #define CMDLINE_HISTFILE       ".nft.history"
+#define CMDLINE_PROMPT         "nft> "
+#define CMDLINE_QUIT           "quit"
 
-static struct nft_ctx *cli_nft;
 static char histfile[PATH_MAX];
+
+static void
+init_histfile(void)
+{
+       const char *home;
+
+       home = getenv("HOME");
+       if (home == NULL)
+               home = "";
+       snprintf(histfile, sizeof(histfile), "%s/%s", home, CMDLINE_HISTFILE);
+}
+
+#ifdef HAVE_LIBREADLINE
+
+static struct nft_ctx *cli_nft;
 static char *multiline;
 
 static char *cli_append_multiline(char *line)
@@ -100,7 +120,7 @@ static void cli_complete(char *line)
        if (*c == '\0')
                return;
 
-       if (!strcmp(line, "quit")) {
+       if (!strcmp(line, CMDLINE_QUIT)) {
                cli_exit();
                exit(0);
        }
@@ -121,20 +141,15 @@ static char **cli_completion(const char *text, int start, 
int end)
 
 int cli_init(struct nft_ctx *nft)
 {
-       const char *home;
-
        cli_nft = nft;
        rl_readline_name = "nft";
        rl_instream  = stdin;
        rl_outstream = stdout;
 
-       rl_callback_handler_install("nft> ", cli_complete);
+       rl_callback_handler_install(CMDLINE_PROMPT, cli_complete);
        rl_attempted_completion_function = cli_completion;
 
-       home = getenv("HOME");
-       if (home == NULL)
-               home = "";
-       snprintf(histfile, sizeof(histfile), "%s/%s", home, CMDLINE_HISTFILE);
+       init_histfile();
 
        read_history(histfile);
        history_set_pos(history_length);
@@ -150,3 +165,34 @@ void cli_exit(void)
        rl_deprep_terminal();
        write_history(histfile);
 }
+
+#else /* !HAVE_LIBREADLINE */
+
+int cli_init(struct nft_ctx *nft)
+{
+       int quit = 0;
+       char *line;
+
+       init_histfile();
+       linenoiseHistoryLoad(histfile);
+       linenoiseSetMultiLine(1);
+
+       while (!quit && (line = linenoise(CMDLINE_PROMPT)) != NULL) {
+               if (strcmp(line, CMDLINE_QUIT) == 0) {
+                       quit = 1;
+               } else if (line[0] != '\0') {
+                       linenoiseHistoryAdd(line);
+                       nft_run_cmd_from_buffer(nft, line);
+               }
+               linenoiseFree(line);
+       }
+       cli_exit();
+       exit(0);
+}
+
+void cli_exit(void)
+{
+       linenoiseHistorySave(histfile);
+}
+
+#endif /* HAVE_LIBREADLINE */
diff --git a/tests/build/run-tests.sh b/tests/build/run-tests.sh
index b0560da61398..ccb62af3d8dd 100755
--- a/tests/build/run-tests.sh
+++ b/tests/build/run-tests.sh
@@ -2,8 +2,8 @@
 
 log_file="`pwd`/tests.log"
 dir=../..
-argument=( --without-cli --enable-debug --with-mini-gmp --enable-man-doc
-           --with-xtables --with-json)
+argument=( --without-cli --with-cli=linenoise --enable-debug --with-mini-gmp
+          --enable-man-doc --with-xtables --with-json)
 ok=0
 failed=0
 
-- 
2.23.0

Reply via email to