Add support for GNU readline
authorHugo Villeneuve <hugo@hugovil.com>
Sat, 8 Feb 2014 07:40:54 +0000 (02:40 -0500)
committerHugo Villeneuve <hugo@hugovil.com>
Thu, 13 Feb 2014 05:25:18 +0000 (00:25 -0500)
readline input is fed into Lex.

This adds commands history.

There is also a configure option to disable readline support.

configure.ac
src/cli/Makefile.am
src/cli/main.c
src/cli/menu.c
src/cli/menu.h
src/cli/parser.y
src/cli/scanner.l

index 1314fca..b4e5f0d 100644 (file)
@@ -17,6 +17,23 @@ dnl Testing for libtool support.
 AC_PROG_RANLIB
 AM_PROG_AR
 
+AC_ARG_WITH([readline],
+            [AS_HELP_STRING([--without-readline], [disable support for readline])],
+            [],
+            [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])
+              ],
+              [AC_MSG_FAILURE(
+                  [readline test failed (--without-readline to disable)])],
+              []
+)])
+
 dnl Testing for Lex/Yacc
 AC_PROG_LEX
 AC_PROG_YACC
index ac87424..d78b89e 100644 (file)
@@ -5,10 +5,14 @@ AM_CPPFLAGS = \
     -I@top_srcdir@ \
     -I@top_srcdir@/src/common
 
+# Option -d: produce header file scanner.h
+AM_LFLAGS = --header-file=scanner.h
+
 # Option -d: produce header file parser.h
 AM_YFLAGS = -d
 
 LDADD = \
+    $(LIBREADLINE) \
     $(top_builddir)/src/common/libemu8051.a
 
 bin_PROGRAMS = emu8051-cli
index bf71cf9..1a3db81 100644 (file)
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
  */
 
+#include "config.h"
+
 #include <stdbool.h>
 #include <stdio.h>
 
-#include "config.h"
 #include "common.h"
 #include "cpu8051.h"
 #include "options.h"
@@ -55,7 +56,6 @@ main(int argc, char **argv)
        } else {
                menu_display_usage();
                console_show_registers();
-               menu_prompt();
                yyparse();
        }
 
index d57cbb1..f4a12d6 100644 (file)
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
  */
 
+#include "config.h"
+
 #include <stdbool.h>
 #include <stdio.h>
 #include <string.h>
 #include <ctype.h>
+#ifdef HAVE_LIBREADLINE
+#include <readline/readline.h>
+#include <readline/history.h>
+#endif /* HAVE_LIBREADLINE */
 
 #include "common.h"
 #include "cpu8051.h"
 #include "options.h"
 #include "hexfile.h"
 #include "keyboard.h"
+#include "scanner.h"
 #include "menu.h"
 
 extern struct options_t options;
 
-void
-menu_prompt(void)
+#define YY_NULL 0
+
+#define MENU_PROMPT "-> "
+
+int
+menu_get_input(char *buf, ssize_t size)
 {
-       printf("-> ");
+        char *line;
+       int max_len;
+
+       max_len = size - 2;
+
+        if (feof(yyin))
+                return YY_NULL;
+
+#ifdef HAVE_LIBREADLINE
+       /* Get the input line, and if non-empty, place it in the history. */
+       line = readline(MENU_PROMPT);
+        if (!line)
+                return YY_NULL;
+
+       if (line && *line)
+               add_history(line);
+
+        if ((int) strlen(line) > max_len) {
+                printf("input line too long");
+                return YY_NULL;
+        }
+
+        strcpy(buf, line);
+
+       /* Readline never gives you the last '\n', so add it back for Lex. */
+        strcat(buf, "\n");
+
+        free(line);
+#else
+       /* It's okay to print a prompt if we are redirecting stdout,
+        * as long as stdin is still a tty.  Otherwise, don't print
+        * a prompt at all if stdin is redirected.
+        */
+       (void) fputs(MENU_PROMPT, stdout);
+       (void) fflush(stdout);  /* for svr4 */
+       line = fgets(buf, max_len, stdin);
+       if (!line)
+               return YY_NULL;
+#endif
+
+        return strlen(buf);
 }
 
 void
index 9dd2919..eba287a 100644 (file)
@@ -25,8 +25,8 @@
 int
 yyparse(void);
 
-void
-menu_prompt(void);
+int
+menu_get_input(char *buf, ssize_t size);
 
 void
 menu_display_usage(void);
index 1cb282c..7d22681 100644 (file)
@@ -45,13 +45,12 @@ int yyerror(const char *str)
 
 %%
 
-start  :  start command { menu_prompt(); }
+start  :  start command
    |  error TOK_ENTER {
          /* In case of error, discard entire line */
          yyerrok;
-         menu_prompt();
       }
-   | start TOK_ENTER { menu_prompt(); }
+   | start TOK_ENTER
    |
    ;
 
index 6abaa30..4cdf42f 100644 (file)
@@ -2,8 +2,13 @@
 %option noinput
 %option nounput
 %{
+  #include "menu.h"
   #include "parser.h"
   #include "hexfile.h"
+
+#undef YY_INPUT
+#define YY_INPUT(buf,result,max_size) result = menu_get_input(buf, max_size);
+
 %}
 
 digit          [0-9]