This diff implements history for bc(1) using editline(3).

History is not persistent, I can add this feature if needed.

el_init with stderr should not be a problem for an interactive program,
let me know otherwise.

This is my first diff, so hints/advices/crucifixion are welcome :)



Index: Makefile
===================================================================
RCS file: /cvs/src/usr.bin/bc/Makefile,v
retrieving revision 1.4
diff -u -r1.4 Makefile
--- Makefile    30 Jun 2006 19:02:28 -0000      1.4
+++ Makefile    13 Aug 2010 11:23:19 -0000
@@ -5,6 +5,8 @@
 CPPFLAGS+=     -I. -I${.CURDIR}
 CFLAGS+=       -Wall -Wno-unused
 YFLAGS+=
+LDADD=         -lcurses -ledit
+DPADD=         ${LIBCURSES} ${LIBEDIT}
 
 beforeinstall:
        install -c -o ${BINOWN} -g ${BINGRP} -m 444 ${.CURDIR}/bc.library \
Index: bc.y
===================================================================
RCS file: /cvs/src/usr.bin/bc/bc.y,v
retrieving revision 1.33
diff -u -r1.33 bc.y
--- bc.y        27 Oct 2009 23:59:36 -0000      1.33
+++ bc.y        13 Aug 2010 11:23:19 -0000
@@ -43,6 +43,7 @@
 #include <stdbool.h>
 #include <string.h>
 #include <unistd.h>
+#include <histedit.h>
 
 #include "extern.h"
 #include "pathnames.h"
@@ -1073,6 +1074,27 @@
        }
 }
 
+static void
+init_editline(void)
+{
+       if (interactive) {
+               /*
+                * Our stdout will be stdin for dc, so we pass stderr as stdout.
+                */
+               if ((el = el_init(__progname, stdin, stderr, stderr)) == NULL)
+                       err(1, "cannot initialise editline");
+               if ((hl = history_init()) == NULL)
+                       err(1, "cannot initialise editline history");
+               history(hl, &hev, H_SETSIZE, 100);
+               el_set(el, EL_HIST, history, hl);
+               el_set(el, EL_PROMPT, prompt);
+               el_set(el, EL_EDITOR, "emacs");
+               el_set(el, EL_TERMINAL, NULL);
+               el_set(el, EL_SIGNAL, 1);
+               el_source(el, NULL);
+       }
+}
+
 int
 main(int argc, char *argv[])
 {
@@ -1129,6 +1151,7 @@
                        dup(p[1]);
                        close(p[0]);
                        close(p[1]);
+                       init_editline();
                } else {
                        close(STDIN_FILENO);
                        dup(p[0]);
Index: extern.h
===================================================================
RCS file: /cvs/src/usr.bin/bc/extern.h,v
retrieving revision 1.6
diff -u -r1.6 extern.h
--- extern.h    18 Mar 2006 20:44:43 -0000      1.6
+++ extern.h    13 Aug 2010 11:23:19 -0000
@@ -23,17 +23,23 @@
        ssize_t store;
 };
 
-int            yylex(void);
-void           yyerror(char *);
-void           fatal(const char *);
-void           abort_line(int);
+int                    yylex(void);
+void                   yyerror(char *);
+void                   fatal(const char *);
+void                   abort_line(int);
 
-extern int     lineno;
-extern char    *yytext;
-extern FILE    *yyin;
-extern int     fileindex;
-extern int     sargc;
-extern char    **sargv;
-extern char    *filename;
-extern char    *cmdexpr;
-bool           interactive;
+extern int             lineno;
+extern char            *yytext;
+extern FILE            *yyin;
+extern int             fileindex;
+extern int             sargc;
+extern char            **sargv;
+extern char            *filename;
+extern char            *cmdexpr;
+extern bool            interactive;
+
+const char             *prompt(EditLine *);
+
+extern History         *hl;
+extern HistEvent       hev;
+extern EditLine                *el;
Index: scan.l
===================================================================
RCS file: /cvs/src/usr.bin/bc/scan.l,v
retrieving revision 1.23
diff -u -r1.23 scan.l
--- scan.l      27 Oct 2009 23:59:36 -0000      1.23
+++ scan.l      13 Aug 2010 11:23:19 -0000
@@ -22,6 +22,7 @@
 #include <stdbool.h>
 #include <string.h>
 #include <unistd.h>
+#include <histedit.h>
 
 #include "extern.h"
 #include "pathnames.h"
@@ -30,6 +31,10 @@
 int            lineno;
 bool           interactive;
 
+History                *hl;
+HistEvent      hev;
+EditLine       *el;
+
 static char    *strbuf = NULL;
 static size_t  strbuf_sz = 1;
 static bool    dot_seen;
@@ -37,6 +42,10 @@
 static void    init_strbuf(void);
 static void    add_str(const char *);
 
+static void    yy_input(char *, int *, const int);
+
+#define YY_INPUT(buf, result, max_size)        (yy_input(buf, &result, 
max_size))
+
 %}
 
 %option always-interactive
@@ -280,3 +289,38 @@
        return (1);
 }
 
+/* ARGSUSED */
+const char *
+prompt(EditLine *el)
+{
+       return "";
+}
+
+static void
+yy_input(char *buf, int *result, const int max_size)
+{
+       if (interactive) {
+               const char *line;
+               int count;
+               if ((line = el_gets(el, &count)) == NULL || count <= 0) {
+                       if (count == 0) {
+                               *result = YY_NULL;
+                               return;
+                       }
+                       err(1, "cannot read input line");
+               }
+               if (strlcpy(buf, line, max_size) >= max_size) {
+                       fprintf(stderr, "Error: input line too long\n");
+                       *result = YY_NULL;
+                       return;
+               }
+               history(hl, &hev, H_ENTER, line);
+               *result = count;
+       } else {
+               if (feof(yyin)) {
+                       *result = YY_NULL;
+                       return;
+               }
+               *result = fread(buf, sizeof(char), max_size, yyin);
+       }
+}

Reply via email to