summaryrefslogtreecommitdiffstats
path: root/usr.bin/bc
diff options
context:
space:
mode:
authordelphij <delphij@FreeBSD.org>2014-05-07 08:06:54 +0000
committerdelphij <delphij@FreeBSD.org>2014-05-07 08:06:54 +0000
commitebef83dbd2b82b4ddf471e1d2b423eef86ccf414 (patch)
tree10b2f68e28cd9e992a4ec257c552c27e4588d64c /usr.bin/bc
parentd6c003e92088f30bee1dd2cb9013d5686ad0de3d (diff)
downloadFreeBSD-src-ebef83dbd2b82b4ddf471e1d2b423eef86ccf414.zip
FreeBSD-src-ebef83dbd2b82b4ddf471e1d2b423eef86ccf414.tar.gz
MFC r264573+264608+264609:
Sync with OpenBSD.
Diffstat (limited to 'usr.bin/bc')
-rw-r--r--usr.bin/bc/Makefile12
-rw-r--r--usr.bin/bc/bc.131
-rw-r--r--usr.bin/bc/bc.library6
-rw-r--r--usr.bin/bc/bc.y48
-rw-r--r--usr.bin/bc/extern.h29
-rw-r--r--usr.bin/bc/scan.l216
-rw-r--r--usr.bin/bc/tty.c65
7 files changed, 278 insertions, 129 deletions
diff --git a/usr.bin/bc/Makefile b/usr.bin/bc/Makefile
index 39d54e0..5fd918d 100644
--- a/usr.bin/bc/Makefile
+++ b/usr.bin/bc/Makefile
@@ -1,12 +1,12 @@
# $FreeBSD$
-# $OpenBSD: Makefile,v 1.4 2006/06/30 19:02:28 otto Exp $
+# $OpenBSD: Makefile,v 1.7 2013/09/19 16:12:00 otto Exp $
-PROG= bc
-SRCS= bc.y scan.l
-CFLAGS+= -I. -I${.CURDIR}
+PROG= bc
+SRCS= bc.y scan.l tty.c
+CFLAGS+= -I. -I${.CURDIR}
-DPADD= ${LIBEDIT} ${LIBTERMCAP}
-LDADD= -ledit -ltermcap
+LDADD+= -ledit -lcurses
+DPADD+= ${LIBEDIT} ${LIBCURSES}
NO_WMISSING_VARIABLE_DECLARATIONS=
diff --git a/usr.bin/bc/bc.1 b/usr.bin/bc/bc.1
index 0592acd..2d539ee 100644
--- a/usr.bin/bc/bc.1
+++ b/usr.bin/bc/bc.1
@@ -1,5 +1,5 @@
.\" $FreeBSD$
-.\" $OpenBSD: bc.1,v 1.25 2010/01/02 19:48:56 schwarze Exp $
+.\" $OpenBSD: bc.1,v 1.30 2014/01/14 07:42:42 jmc Exp $
.\"
.\" Copyright (C) Caldera International Inc. 2001-2002.
.\" All rights reserved.
@@ -35,7 +35,7 @@
.\"
.\" @(#)bc.1 6.8 (Berkeley) 8/8/91
.\"
-.Dd December 6, 2013
+.Dd April 16, 2014
.Dt BC 1
.Os
.Sh NAME
@@ -140,8 +140,7 @@ The following arithmetic and logical operators can be used.
The semantics of the operators is the same as in the C language.
They are listed in order of decreasing precedence.
Operators in the same group have the same precedence.
-.Bl -column -offset indent "= += \-= *= /= %= ^=" "Associativity" \
-"multiply, divide, modulus"
+.Bl -column "= += \-= *= /= %= ^=" "Associativity" "multiply, divide, modulus" -offset indent
.It Sy "Operator" Ta Sy "Associativity" Ta Sy "Description"
.It "++ \-\-" Ta "none" Ta "increment, decrement"
.It "\-" Ta "none" Ta "unary minus"
@@ -160,7 +159,7 @@ Note the following:
.It
The relational operators may appear in any expression.
The
-.St -p1003.2
+.St -p1003.1-2008
standard only allows them in the conditional expression of an
.Sq if ,
.Sq while
@@ -342,6 +341,22 @@ $ bc -l -e 'scale = 500; 2 * a(2^10000)' -e quit
.Ed
.Pp
prints an approximation of pi.
+.Sh COMMAND LINE EDITING
+.Nm
+supports interactive command line editing, via the
+.Xr editline 3
+library.
+It is enabled by default if input is from a tty.
+Previous lines can be recalled and edited with the arrow keys,
+and other GNU Emacs-style editing keys may be used as well.
+.Pp
+The
+.Xr editline 3
+library is configured with a
+.Pa .editrc
+file \- refer to
+.Xr editrc 5
+for more information.
.Sh FILES
.Bl -tag -width /usr/share/misc/bc.library -compact
.It Pa /usr/share/misc/bc.library
@@ -359,9 +374,6 @@ options are no-ops for compatibility with some other implementations of
and their use is discouraged.
.Sh SEE ALSO
.Xr dc 1
-.Pp
-"BC \- An Arbitrary Precision Desk-Calculator Language",
-.Pa /usr/share/doc/usd/06.bc/ .
.Sh STANDARDS
The
.Nm
@@ -370,7 +382,8 @@ utility is compliant with the
specification.
.Pp
The flags
-.Op Fl ce
+.Op Fl ce ,
+as well as the parts noted above,
are extensions to that specification.
.Sh HISTORY
The
diff --git a/usr.bin/bc/bc.library b/usr.bin/bc/bc.library
index 7f4a93e..8b92d25 100644
--- a/usr.bin/bc/bc.library
+++ b/usr.bin/bc/bc.library
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
-/* $OpenBSD: bc.library,v 1.3 2007/02/03 21:15:06 otto Exp $ */
+/* $OpenBSD: bc.library,v 1.4 2012/03/14 07:35:53 otto Exp $ */
/*
* Copyright (C) Caldera International Inc. 2001-2002.
@@ -100,13 +100,13 @@ define l(x) {
if (x < 1) {
s = scale(x)
} else {
- s = length(x) - scale(x)
+ s = length(x)-scale(x)
}
scale = 0
a = (2.31*s)/1 /* estimated integer part of the answer */
s = t + length(a) + 2 /* estimated length of the answer */
while (x > 2) {
- scale=0
+ scale = 0
scale = (length(x) + scale(x))/2 + 1
if (scale < s) scale = s
x = sqrt(x)
diff --git a/usr.bin/bc/bc.y b/usr.bin/bc/bc.y
index a819e3f..8e7e00c 100644
--- a/usr.bin/bc/bc.y
+++ b/usr.bin/bc/bc.y
@@ -1,5 +1,5 @@
%{
-/* $OpenBSD: bc.y,v 1.33 2009/10/27 23:59:36 deraadt Exp $ */
+/* $OpenBSD: bc.y,v 1.44 2013/11/20 21:33:54 deraadt Exp $ */
/*
* Copyright (c) 2003, Otto Moerbeek <otto@drijf.net>
@@ -45,7 +45,6 @@ __FBSDID("$FreeBSD$");
#include <search.h>
#include <signal.h>
#include <stdarg.h>
-#include <stdbool.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
@@ -53,7 +52,7 @@ __FBSDID("$FreeBSD$");
#include "extern.h"
#include "pathnames.h"
-#define BC_VER "1.0-FreeBSD"
+#define BC_VER "1.1-FreeBSD"
#define END_NODE ((ssize_t) -1)
#define CONST_STRING ((ssize_t) -2)
#define ALLOC_STRING ((ssize_t) -3)
@@ -971,7 +970,12 @@ yyerror(const char *s)
if (yyin != NULL && feof(yyin))
n = asprintf(&str, "%s: %s:%d: %s: unexpected EOF",
__progname, filename, lineno, s);
- else if (isspace(yytext[0]) || !isprint(yytext[0]))
+ else if (yytext[0] == '\n')
+ n = asprintf(&str,
+ "%s: %s:%d: %s: newline unexpected",
+ __progname, filename, lineno, s);
+ else if (isspace((unsigned char)yytext[0]) ||
+ !isprint((unsigned char)yytext[0]))
n = asprintf(&str,
"%s: %s:%d: %s: ascii char 0x%02x unexpected",
__progname, filename, lineno, s, yytext[0]);
@@ -1085,26 +1089,25 @@ escape(const char *str)
/* ARGSUSED */
static void
-sigchld(int signo)
+sigchld(int signo __unused)
{
pid_t pid;
- int status;
-
- switch (signo) {
- default:
- for (;;) {
- pid = waitpid(dc, &status, WUNTRACED);
- if (pid == -1) {
- if (errno == EINTR)
- continue;
- _exit(0);
- }
- if (WIFEXITED(status) || WIFSIGNALED(status))
- _exit(0);
- else
- break;
- }
+ int status, save_errno = errno;
+
+ for (;;) {
+ pid = waitpid(dc, &status, WCONTINUED | WNOHANG);
+ if (pid == -1) {
+ if (errno == EINTR)
+ continue;
+ _exit(0);
+ } else if (pid == 0)
+ break;
+ if (WIFEXITED(status) || WIFSIGNALED(status))
+ _exit(0);
+ else
+ break;
}
+ errno = save_errno;
}
static const char *
@@ -1191,6 +1194,7 @@ main(int argc, char *argv[])
}
}
if (interactive) {
+ gettty(&ttysaved);
el = el_init("bc", stdin, stderr, stderr);
hist = history_init();
history(hist, &he, H_SETSIZE, 100);
@@ -1198,6 +1202,8 @@ main(int argc, char *argv[])
el_set(el, EL_EDITOR, "emacs");
el_set(el, EL_SIGNAL, 1);
el_set(el, EL_PROMPT, dummy_prompt);
+ el_set(el, EL_ADDFN, "bc_eof", "", bc_eof);
+ el_set(el, EL_BIND, "^D", "bc_eof", NULL);
el_source(el, NULL);
}
yywrap();
diff --git a/usr.bin/bc/extern.h b/usr.bin/bc/extern.h
index d1e9fe8..685942a 100644
--- a/usr.bin/bc/extern.h
+++ b/usr.bin/bc/extern.h
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
-/* $OpenBSD: extern.h,v 1.6 2006/03/18 20:44:43 otto Exp $ */
+/* $OpenBSD: extern.h,v 1.10 2013/09/19 16:12:01 otto Exp $ */
/*
* Copyright (c) 2003, Otto Moerbeek <otto@drijf.net>
@@ -17,26 +17,31 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#include <stdbool.h>
#include <stdio.h>
struct lvalue {
- ssize_t load;
- ssize_t store;
+ ssize_t load;
+ ssize_t store;
};
-int yylex(void);
-void yyerror(const char *);
-void fatal(const char *);
-void abort_line(int);
+int yylex(void);
+void yyerror(const char *);
+void fatal(const char *);
+void abort_line(int);
+struct termios;
+int gettty(struct termios *);
+void tstpcont(int);
+unsigned char bc_eof(EditLine *, int);
-extern int lineno;
-extern int fileindex;
-extern int sargc;
+extern int lineno;
+extern int fileindex;
+extern int sargc;
extern const char **sargv;
extern const char *filename;
-extern char *cmdexpr;
extern bool interactive;
extern EditLine *el;
extern History *hist;
extern HistEvent he;
-
+extern char *cmdexpr;
+extern struct termios ttysaved;
diff --git a/usr.bin/bc/scan.l b/usr.bin/bc/scan.l
index 71cb295..cb1977a 100644
--- a/usr.bin/bc/scan.l
+++ b/usr.bin/bc/scan.l
@@ -1,5 +1,5 @@
%{
-/* $OpenBSD: scan.l,v 1.23 2009/10/27 23:59:36 deraadt Exp $ */
+/* $OpenBSD: scan.l,v 1.28 2013/09/19 16:12:01 otto Exp $ */
/*
* Copyright (c) 2003, Otto Moerbeek <otto@drijf.net>
@@ -24,6 +24,7 @@ __FBSDID("$FreeBSD$");
#include <errno.h>
#include <histedit.h>
#include <stdbool.h>
+#include <signal.h>
#include <string.h>
#include <unistd.h>
@@ -31,19 +32,22 @@ __FBSDID("$FreeBSD$");
#include "bc.h"
#include "pathnames.h"
-int lineno;
+int lineno;
+bool interactive;
-bool interactive;
HistEvent he;
EditLine *el;
History *hist;
static char *strbuf = NULL;
-static size_t strbuf_sz = 1;
-static bool dot_seen;
+static size_t strbuf_sz = 1;
+static bool dot_seen;
+static int use_el;
+static volatile sig_atomic_t skipchars;
+
+static void init_strbuf(void);
+static void add_str(const char *);
-static void init_strbuf(void);
-static void add_str(const char *);
static int bc_yyinput(char *, int);
#define YY_DECL int yylex(void)
@@ -51,6 +55,7 @@ static int bc_yyinput(char *, int);
#undef YY_INPUT
#define YY_INPUT(buf,retval,max) \
(retval = bc_yyinput(buf, max))
+
%}
%option always-interactive
@@ -102,7 +107,7 @@ ALPHANUM [a-z_0-9]
BEGIN(INITIAL);
yylval.str = strbuf;
unput('.');
- return (NUMBER);
+ return NUMBER;
} else {
dot_seen = true;
add_str(".");
@@ -113,73 +118,73 @@ ALPHANUM [a-z_0-9]
BEGIN(INITIAL);
unput(yytext[0]);
if (strcmp(strbuf, ".") == 0)
- return (DOT);
+ return DOT;
else {
yylval.str = strbuf;
- return (NUMBER);
+ return NUMBER;
}
}
}
-"auto" return (AUTO);
-"break" return (BREAK);
-"continue" return (CONTINUE);
-"define" return (DEFINE);
-"else" return (ELSE);
-"ibase" return (IBASE);
-"if" return (IF);
-"last" return (DOT);
-"for" return (FOR);
-"length" return (LENGTH);
-"obase" return (OBASE);
-"print" return (PRINT);
-"quit" return (QUIT);
-"return" return (RETURN);
-"scale" return (SCALE);
-"sqrt" return (SQRT);
-"while" return (WHILE);
-
-"^" return (EXPONENT);
-"*" return (MULTIPLY);
-"/" return (DIVIDE);
-"%" return (REMAINDER);
-
-"!" return (BOOL_NOT);
-"&&" return (BOOL_AND);
-"||" return (BOOL_OR);
-
-"+" return (PLUS);
-"-" return (MINUS);
-
-"++" return (INCR);
-"--" return (DECR);
-
-"=" yylval.str = ""; return (ASSIGN_OP);
-"+=" yylval.str = "+"; return (ASSIGN_OP);
-"-=" yylval.str = "-"; return (ASSIGN_OP);
-"*=" yylval.str = "*"; return (ASSIGN_OP);
-"/=" yylval.str = "/"; return (ASSIGN_OP);
-"%=" yylval.str = "%"; return (ASSIGN_OP);
-"^=" yylval.str = "^"; return (ASSIGN_OP);
-
-"==" return (EQUALS);
-"<=" return (LESS_EQ);
-">=" return (GREATER_EQ);
-"!=" return (UNEQUALS);
-"<" return (LESS);
-">" return (GREATER);
-
-"," return (COMMA);
-";" return (SEMICOLON);
-
-"(" return (LPAR);
-")" return (RPAR);
-
-"[" return (LBRACKET);
-"]" return (RBRACKET);
-
-"{" return (LBRACE);
-"}" return (RBRACE);
+"auto" return AUTO;
+"break" return BREAK;
+"continue" return CONTINUE;
+"define" return DEFINE;
+"else" return ELSE;
+"ibase" return IBASE;
+"if" return IF;
+"last" return DOT;
+"for" return FOR;
+"length" return LENGTH;
+"obase" return OBASE;
+"print" return PRINT;
+"quit" return QUIT;
+"return" return RETURN;
+"scale" return SCALE;
+"sqrt" return SQRT;
+"while" return WHILE;
+
+"^" return EXPONENT;
+"*" return MULTIPLY;
+"/" return DIVIDE;
+"%" return REMAINDER;
+
+"!" return BOOL_NOT;
+"&&" return BOOL_AND;
+"||" return BOOL_OR;
+
+"+" return PLUS;
+"-" return MINUS;
+
+"++" return INCR;
+"--" return DECR;
+
+"=" yylval.str = ""; return ASSIGN_OP;
+"+=" yylval.str = "+"; return ASSIGN_OP;
+"-=" yylval.str = "-"; return ASSIGN_OP;
+"*=" yylval.str = "*"; return ASSIGN_OP;
+"/=" yylval.str = "/"; return ASSIGN_OP;
+"%=" yylval.str = "%"; return ASSIGN_OP;
+"^=" yylval.str = "^"; return ASSIGN_OP;
+
+"==" return EQUALS;
+"<=" return LESS_EQ;
+">=" return GREATER_EQ;
+"!=" return UNEQUALS;
+"<" return LESS;
+">" return GREATER;
+
+"," return COMMA;
+";" return SEMICOLON;
+
+"(" return LPAR;
+")" return RPAR;
+
+"[" return LBRACKET;
+"]" return RBRACKET;
+
+"{" return LBRACE;
+"}" return RBRACE;
{ALPHA}{ALPHANUM}* {
/* alloc an extra byte for the type marker */
@@ -188,15 +193,15 @@ ALPHANUM [a-z_0-9]
err(1, NULL);
strlcpy(p, yytext, yyleng + 1);
yylval.astr = p;
- return (LETTER);
+ return LETTER;
}
\\\n lineno++;
-\n lineno++; return (NEWLINE);
+\n lineno++; return NEWLINE;
#[^\n]* ;
[ \t] ;
-<<EOF>> return (QUIT);
+<<EOF>> return QUIT;
. yyerror("illegal character");
%%
@@ -204,7 +209,6 @@ ALPHANUM [a-z_0-9]
static void
init_strbuf(void)
{
-
if (strbuf == NULL) {
strbuf = malloc(strbuf_sz);
if (strbuf == NULL)
@@ -221,8 +225,8 @@ add_str(const char *str)
arglen = strlen(str);
if (strlen(strbuf) + arglen + 1 > strbuf_sz) {
- size_t newsize;
- char *p;
+ size_t newsize;
+ char *p;
newsize = strbuf_sz + arglen + 1;
p = realloc(strbuf, newsize);
@@ -236,11 +240,47 @@ add_str(const char *str)
strlcat(strbuf, str, strbuf_sz);
}
+/* ARGSUSED */
+void
+abort_line(int sig __unused)
+{
+ static const char str1[] = "[\n]P\n";
+ static const char str2[] = "[^C\n]P\n";
+ int save_errno;
+ const LineInfo *info;
+
+ save_errno = errno;
+ if (use_el) {
+ write(STDOUT_FILENO, str2, sizeof(str2) - 1);
+ info = el_line(el);
+ skipchars = info->lastchar - info->buffer;
+ } else
+ write(STDOUT_FILENO, str1, sizeof(str1) - 1);
+ errno = save_errno;
+}
+
+/*
+ * Avoid the echo of ^D by the default code of editline and take
+ * into account skipchars to make ^D work when the cursor is at start of
+ * line after a ^C.
+ */
+unsigned char
+bc_eof(EditLine *e, int ch __unused)
+{
+ const struct lineinfo *info = el_line(e);
+
+ if (info->buffer + skipchars == info->cursor &&
+ info->cursor == info->lastchar)
+ return (CC_EOF);
+ else
+ return (CC_ERROR);
+}
+
int
yywrap(void)
{
- static YY_BUFFER_STATE buf;
static int state;
+ static YY_BUFFER_STATE buf;
if (fileindex == 0 && sargc > 0 && strcmp(sargv[0], _PATH_LIBB) == 0) {
filename = sargv[fileindex++];
@@ -273,6 +313,10 @@ yywrap(void)
} else if (fileindex == sargc) {
fileindex++;
yyin = stdin;
+ if (interactive) {
+ signal(SIGINT, abort_line);
+ signal(SIGTSTP, tstpcont);
+ }
lineno = 1;
filename = "stdin";
return (0);
@@ -284,17 +328,32 @@ static int
bc_yyinput(char *buf, int maxlen)
{
int num;
- if (yyin == stdin && interactive) {
+
+ if (el != NULL)
+ el_get(el, EL_EDITMODE, &use_el);
+
+ if (yyin == stdin && interactive && use_el) {
const char *bp;
+ sigset_t oset, nset;
if ((bp = el_gets(el, &num)) == NULL || num == 0)
return (0);
+ sigemptyset(&nset);
+ sigaddset(&nset, SIGINT);
+ sigprocmask(SIG_BLOCK, &nset, &oset);
+ if (skipchars < num) {
+ bp += skipchars;
+ num -= skipchars;
+ }
+ skipchars = 0;
+ sigprocmask(SIG_SETMASK, &oset, NULL);
if (num > maxlen) {
- el_push(el, (char *)(uintptr_t)(bp) + maxlen);
+ el_push(el, bp + maxlen);
num = maxlen;
}
memcpy(buf, bp, num);
history(hist, &he, H_ENTER, bp);
+ el_get(el, EL_EDITMODE, &use_el);
} else {
int c = '*';
for (num = 0; num < maxlen &&
@@ -308,3 +367,4 @@ bc_yyinput(char *buf, int maxlen)
return (num);
}
+
diff --git a/usr.bin/bc/tty.c b/usr.bin/bc/tty.c
new file mode 100644
index 0000000..05f9d14
--- /dev/null
+++ b/usr.bin/bc/tty.c
@@ -0,0 +1,65 @@
+/* $FreeBSD$ */
+/* $OpenBSD: tty.c,v 1.2 2013/11/12 13:54:51 deraadt Exp $ */
+
+/*
+ * Copyright (c) 2013, Otto Moerbeek <otto@drijf.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <errno.h>
+#include <signal.h>
+#include <histedit.h>
+#include <termios.h>
+#include "extern.h"
+
+struct termios ttysaved, ttyedit;
+
+static int
+settty(struct termios *t)
+{
+ int ret;
+
+ while ((ret = tcsetattr(0, TCSADRAIN, t) == -1) && errno == EINTR)
+ continue;
+ return ret;
+}
+
+int
+gettty(struct termios *t)
+{
+ int ret;
+
+ while ((ret = tcgetattr(0, t) == -1) && errno == EINTR)
+ continue;
+ return ret;
+}
+
+/* ARGSUSED */
+void
+tstpcont(int sig)
+{
+ int save_errno = errno;
+
+ if (sig == SIGTSTP) {
+ signal(SIGCONT, tstpcont);
+ gettty(&ttyedit);
+ settty(&ttysaved);
+ } else {
+ signal(SIGTSTP, tstpcont);
+ settty(&ttyedit);
+ }
+ signal(sig, SIG_DFL);
+ kill(0, sig);
+ errno = save_errno;
+}
OpenPOWER on IntegriCloud