OSEC

Neohapsis is currently accepting applications for employment. For more information, please visit our website www.neohapsis.com or email hr@neohapsis.com
History for bc(1)

From: Gabriel Linder (linderjeuxvideo.com)
Date: Fri Aug 13 2010 - 06:26:37 CDT


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