On Fri, Aug 13, 2010 at 01:26:37PM +0200, Gabriel Linder wrote:
> 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 :)
Take a look at freebsd. They have added editline support to bc. If
(big if) we're going to add command line editing and history, I'd
rather take that.
-Otto
>
>
>
> 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);
> + }
> +}