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);
+ }
+}