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

Reply via email to