On Fri, 13 Aug 2010 15:09:20 +0200 Gabriel Linder <[email protected]> wrote:
> On Fri, 13 Aug 2010 14:30:50 +0200 > Otto Moerbeek <[email protected]> wrote: > > > 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. > > I will take a look at their implementation then, thank you. > Here is a new diff with evolutions from FreeBSD added. I did keep a single fread for real files, though. Bonus : fixed a bug in their version when el_push'ing lines. ? test 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 17 Aug 2010 16:00:05 -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 17 Aug 2010 16:00:05 -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,34 @@ } } +/* ARGSUSED */ +static const char * +prompt(EditLine *el) +{ + return ""; +} + +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 +1158,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 17 Aug 2010 16:00:05 -0000 @@ -23,17 +23,19 @@ 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 *); -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; +extern EditLine *el; +extern History *hl; +extern HistEvent hev; 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 17 Aug 2010 16:00:05 -0000 @@ -18,10 +18,10 @@ */ #include <err.h> -#include <signal.h> #include <stdbool.h> #include <string.h> #include <unistd.h> +#include <histedit.h> #include "extern.h" #include "pathnames.h" @@ -29,6 +29,9 @@ int lineno; bool interactive; +EditLine *el; +History *hl; +HistEvent hev; static char *strbuf = NULL; static size_t strbuf_sz = 1; @@ -36,6 +39,10 @@ static void init_strbuf(void); static void add_str(const char *); +static int bc_yyinput(char *, const int); + +#define YY_INPUT(buf, result, max_size) \ + (result = bc_yyinput(buf, max_size)) %} @@ -221,19 +228,6 @@ strlcat(strbuf, str, strbuf_sz); } -/* ARGSUSED */ -void -abort_line(int sig) -{ - static const char str[] = "[\n]P\n"; - int save_errno; - - save_errno = errno; - YY_FLUSH_BUFFER; /* XXX signal race? */ - write(STDOUT_FILENO, str, sizeof(str) - 1); - errno = save_errno; -} - int yywrap(void) { @@ -271,8 +265,6 @@ } else if (fileindex == sargc) { fileindex++; yyin = stdin; - if (interactive) - signal(SIGINT, abort_line); lineno = 1; filename = "stdin"; return (0); @@ -280,3 +272,45 @@ return (1); } +static int +bc_yyinput(char *buf, const int max_size) +{ + /* + * This function is used to read both math library and user input, + * so we have to check for stdin before using editline even in + * interactive mode. + */ + if (interactive && yyin == stdin) { + /* + * el_push'ed lines do not need to be added to history. + */ + static bool was_pushed = false; + const char *line; + int count; + if ((line = el_gets(el, &count)) == NULL || count <= 0) { + if (count == 0) { + return YY_NULL; + } + err(1, "cannot read input line"); + } + if (!was_pushed) + history(hl, &hev, H_ENTER, line); + else + was_pushed = false; + if (count > max_size) { + el_push(el, (char *)((uintptr_t)line + max_size)); + count = max_size; + was_pushed = true; + } + memcpy(buf, line, count); + return count; + } else { + if (feof(yyin)) { + if (ferror(yyin)) { + YY_FATAL_ERROR("input in flex scanner failed"); + } + return YY_NULL; + } + return fread(buf, sizeof(char), max_size, yyin); + } +}
