summaryrefslogtreecommitdiffstats
path: root/bin/expr
diff options
context:
space:
mode:
authorwollman <wollman@FreeBSD.org>2002-05-10 22:59:29 +0000
committerwollman <wollman@FreeBSD.org>2002-05-10 22:59:29 +0000
commite11cb46ee8e7eea44531903aaac525bbd80f14c0 (patch)
treeeb552a2a3e43e767f64fbdca6a0411905d9c9852 /bin/expr
parent6cd7fcea88d41d92ee11ffbf6d144c3ea9696084 (diff)
downloadFreeBSD-src-e11cb46ee8e7eea44531903aaac525bbd80f14c0.zip
FreeBSD-src-e11cb46ee8e7eea44531903aaac525bbd80f14c0.tar.gz
The response to my POSIX interpretation request says that `expr'
is required to be oblivious to overflow and to use the data type `long'. (Division by zero is undefined in ISO C so it's still OK to check for it here.) Add a new `-e' flag to get the old, more useful behavior.
Diffstat (limited to 'bin/expr')
-rw-r--r--bin/expr/expr.139
-rw-r--r--bin/expr/expr.y95
2 files changed, 88 insertions, 46 deletions
diff --git a/bin/expr/expr.1 b/bin/expr/expr.1
index 4669000..1425e00 100644
--- a/bin/expr/expr.1
+++ b/bin/expr/expr.1
@@ -30,7 +30,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd March 22, 2002
+.Dd May 10, 2002
.Dt EXPR 1
.Os
.Sh NAME
@@ -38,7 +38,7 @@
.Nd evaluate expression
.Sh SYNOPSIS
.Nm
-.Op Fl \&-
+.Op Fl e
.Ar expression
.Sh DESCRIPTION
The
@@ -50,15 +50,25 @@ and writes the result on standard output.
All operators and operands must be passed as separate arguments.
Several of the operators have special meaning to command interpreters
and must therefore be quoted appropriately.
+All integer operands are interpreted in base 10.
.Pp
-Arithmetic operations are performed using signed integer math,
-in the largest integral type available in the C language. The
+Arithmetic operations are performed using signed integer math.
+If the
+.Fl e
+flag is specified, arithmetic uses the C
+.Ql intmax_t
+data type (the largest integral type available), and
.Nm
-utility will detect arithmetic overflow and division by zero, and
-returns with an exit status of 2 in those cases. If a numeric operand
-is specified which is so large as to overflow conversion to an integer,
-it is parsed as a string instead. All numeric operands are interpreted
-in base 10.
+will detect arithmetic overflow and return an error indication.
+If a numeric operand is specified which is so large as to overflow
+conversion to an integer, it is parsed as a string instead.
+If
+.Fl e
+is not specified, arithmetic operations and parsing of integer
+arguments will overflow silently according to the rules of the C
+standard, and integer computations will be performed using the
+.Ql long
+data type.
.Pp
Operators are listed below in order of increasing precedence; all
are left-associative.
@@ -174,7 +184,7 @@ command, one might rearrange the expression:
More generally, parenthesize possibly-negative values:
.Dl a=$(expr \e( $a \e) + 1)
.It
-The following example prints the filename portion of a pathname stored
+This example prints the filename portion of a pathname stored
in variable
.Va a .
Since
@@ -231,9 +241,6 @@ utility conforms to
provided that the
.Ev EXPR_COMPAT
environment variable is not defined.
-.Tn POSIX
-does not specify whether arithmetic overflow is detected, nor does it specify
-the possible range of integer arguments to
-.Nm ,
-so a portable application must assume that the range is small and that
-overflow may not be detected.
+The
+.Fl e
+flag is an extension.
diff --git a/bin/expr/expr.y b/bin/expr/expr.y
index 3026f52..92c0e5f 100644
--- a/bin/expr/expr.y
+++ b/bin/expr/expr.y
@@ -70,6 +70,7 @@ int yyerror(const char *);
int yylex(void);
int yyparse(void);
+static int eflag;
char **av;
%}
@@ -154,7 +155,10 @@ make_str(const char *s)
* non-digits MUST NOT be considered integers. strtoimax() will
* figure this out for us.
*/
- (void)strtoimax(s, &ep, 10);
+ if (eflag)
+ (void)strtoimax(s, &ep, 10);
+ else
+ (void)strtol(s, &ep, 10);
if (*ep != '\0')
vp->type = string;
@@ -186,9 +190,13 @@ to_integer(struct val *vp)
/* vp->type == numeric_string, make it numeric */
errno = 0;
- i = strtoimax(vp->u.s, (char **)NULL, 10);
- if (errno == ERANGE)
- err(ERR_EXIT, NULL);
+ if (eflag) {
+ i = strtoimax(vp->u.s, (char **)NULL, 10);
+ if (errno == ERANGE)
+ err(ERR_EXIT, NULL);
+ } else {
+ i = strtol(vp->u.s, (char **)NULL, 10);
+ }
free (vp->u.s);
vp->u.i = i;
@@ -273,10 +281,15 @@ main(int argc, char *argv[])
if (getenv("EXPR_COMPAT") != NULL) {
av = argv + 1;
} else {
- while ((c = getopt(argc, argv, "")) != -1)
+ while ((c = getopt(argc, argv, "e")) != -1)
switch (c) {
+ case 'e':
+ eflag = 1;
+ break;
+
default:
- fprintf(stderr,"usage: expr [--] expression\n");
+ fprintf(stderr,
+ "usage: expr [-e] expression\n");
exit(ERR_EXIT);
}
av = argv + optind;
@@ -327,7 +340,7 @@ op_and(struct val *a, struct val *b)
struct val *
op_eq(struct val *a, struct val *b)
{
- struct val *r;
+ struct val *r;
if (isstring (a) || isstring (b)) {
to_string (a);
@@ -447,6 +460,7 @@ op_ne(struct val *a, struct val *b)
int
chk_plus(intmax_t a, intmax_t b, intmax_t r)
{
+
/* sum of two positive numbers must be positive */
if (a > 0 && b > 0 && r <= 0)
return 1;
@@ -462,14 +476,18 @@ op_plus(struct val *a, struct val *b)
{
struct val *r;
- if (!to_integer (a) || !to_integer (b)) {
+ if (!to_integer(a) || !to_integer(b)) {
errx(ERR_EXIT, "non-numeric argument");
}
- r = make_integer (/*(intmax_t)*/(a->u.i + b->u.i));
- if (chk_plus (a->u.i, b->u.i, r->u.i)) {
- errx(ERR_EXIT, "overflow");
- }
+ if (eflag) {
+ r = make_integer(a->u.i + b->u.i);
+ if (chk_plus(a->u.i, b->u.i, r->u.i)) {
+ errx(ERR_EXIT, "overflow");
+ }
+ } else
+ r = make_integer((long)a->u.i + (long)b->u.i);
+
free_value (a);
free_value (b);
return r;
@@ -478,6 +496,7 @@ op_plus(struct val *a, struct val *b)
int
chk_minus(intmax_t a, intmax_t b, intmax_t r)
{
+
/* special case subtraction of INTMAX_MIN */
if (b == INTMAX_MIN) {
if (a >= 0)
@@ -494,14 +513,18 @@ op_minus(struct val *a, struct val *b)
{
struct val *r;
- if (!to_integer (a) || !to_integer (b)) {
+ if (!to_integer(a) || !to_integer(b)) {
errx(ERR_EXIT, "non-numeric argument");
}
- r = make_integer (/*(intmax_t)*/(a->u.i - b->u.i));
- if (chk_minus (a->u.i, b->u.i, r->u.i)) {
- errx(ERR_EXIT, "overflow");
- }
+ if (eflag) {
+ r = make_integer(a->u.i - b->u.i);
+ if (chk_minus(a->u.i, b->u.i, r->u.i)) {
+ errx(ERR_EXIT, "overflow");
+ }
+ } else
+ r = make_integer((long)a->u.i - (long)b->u.i);
+
free_value (a);
free_value (b);
return r;
@@ -524,14 +547,18 @@ op_times(struct val *a, struct val *b)
{
struct val *r;
- if (!to_integer (a) || !to_integer (b)) {
+ if (!to_integer(a) || !to_integer(b)) {
errx(ERR_EXIT, "non-numeric argument");
}
- r = make_integer (/*(intmax_t)*/(a->u.i * b->u.i));
- if (chk_times (a->u.i, b->u.i, r->u.i)) {
- errx(ERR_EXIT, "overflow");
- }
+ if (eflag) {
+ r = make_integer(a->u.i * b->u.i);
+ if (chk_times(a->u.i, b->u.i, r->u.i)) {
+ errx(ERR_EXIT, "overflow");
+ }
+ } else
+ r = make_integer((long)a->u.i * (long)b->u.i);
+
free_value (a);
free_value (b);
return (r);
@@ -553,7 +580,7 @@ op_div(struct val *a, struct val *b)
{
struct val *r;
- if (!to_integer (a) || !to_integer (b)) {
+ if (!to_integer(a) || !to_integer(b)) {
errx(ERR_EXIT, "non-numeric argument");
}
@@ -561,10 +588,14 @@ op_div(struct val *a, struct val *b)
errx(ERR_EXIT, "division by zero");
}
- r = make_integer (/*(intmax_t)*/(a->u.i / b->u.i));
- if (chk_div (a->u.i, b->u.i)) {
- errx(ERR_EXIT, "overflow");
- }
+ if (eflag) {
+ r = make_integer(a->u.i / b->u.i);
+ if (chk_div(a->u.i, b->u.i)) {
+ errx(ERR_EXIT, "overflow");
+ }
+ } else
+ r = make_integer((long)a->u.i / (long)b->u.i);
+
free_value (a);
free_value (b);
return r;
@@ -575,7 +606,7 @@ op_rem(struct val *a, struct val *b)
{
struct val *r;
- if (!to_integer (a) || !to_integer (b)) {
+ if (!to_integer(a) || !to_integer(b)) {
errx(ERR_EXIT, "non-numeric argument");
}
@@ -583,8 +614,12 @@ op_rem(struct val *a, struct val *b)
errx(ERR_EXIT, "division by zero");
}
- r = make_integer (/*(intmax_t)*/(a->u.i % b->u.i));
- /* chk_rem necessary ??? */
+ if (eflag)
+ r = make_integer(a->u.i % b->u.i);
+ /* chk_rem necessary ??? */
+ else
+ r = make_integer((long)a->u.i % (long)b->u.i);
+
free_value (a);
free_value (b);
return r;
OpenPOWER on IntegriCloud