1993-06-12 14:58:17 +00:00
|
|
|
%{
|
2005-01-10 08:39:26 +00:00
|
|
|
/*-
|
2011-07-09 12:20:15 +00:00
|
|
|
* Written by Pace Willisson (pace@blitz.com)
|
1993-08-17 16:06:00 +00:00
|
|
|
* and placed in the public domain.
|
1993-06-12 14:58:17 +00:00
|
|
|
*
|
1993-08-17 16:06:00 +00:00
|
|
|
* Largely rewritten by J.T. Conklin (jtc@wimsey.com)
|
|
|
|
*
|
1999-08-27 23:15:48 +00:00
|
|
|
* $FreeBSD$
|
1993-06-12 14:58:17 +00:00
|
|
|
*/
|
1993-09-14 22:49:52 +00:00
|
|
|
|
2000-07-10 21:30:55 +00:00
|
|
|
#include <sys/types.h>
|
2002-03-22 20:18:26 +00:00
|
|
|
|
1993-06-12 14:58:17 +00:00
|
|
|
#include <ctype.h>
|
1993-08-17 16:06:00 +00:00
|
|
|
#include <err.h>
|
2000-07-22 10:59:36 +00:00
|
|
|
#include <errno.h>
|
2002-03-22 20:18:26 +00:00
|
|
|
#include <inttypes.h>
|
2000-07-22 10:59:36 +00:00
|
|
|
#include <limits.h>
|
2002-03-22 20:18:26 +00:00
|
|
|
#include <locale.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <regex.h>
|
|
|
|
#include <unistd.h>
|
2011-07-09 12:20:15 +00:00
|
|
|
|
2002-03-22 20:18:26 +00:00
|
|
|
/*
|
|
|
|
* POSIX specifies a specific error code for syntax errors. We exit
|
|
|
|
* with this code for all errors.
|
|
|
|
*/
|
|
|
|
#define ERR_EXIT 2
|
|
|
|
|
1993-06-12 14:58:17 +00:00
|
|
|
enum valtype {
|
1995-11-18 18:05:03 +00:00
|
|
|
integer, numeric_string, string
|
1993-06-12 14:58:17 +00:00
|
|
|
} ;
|
1993-06-19 01:55:46 +00:00
|
|
|
|
1993-06-12 14:58:17 +00:00
|
|
|
struct val {
|
|
|
|
enum valtype type;
|
|
|
|
union {
|
|
|
|
char *s;
|
2002-03-22 20:18:26 +00:00
|
|
|
intmax_t i;
|
1993-06-12 14:58:17 +00:00
|
|
|
} u;
|
1993-06-19 01:55:46 +00:00
|
|
|
} ;
|
1993-06-12 14:58:17 +00:00
|
|
|
|
2011-07-09 12:14:57 +00:00
|
|
|
char **av;
|
|
|
|
int nonposix;
|
2011-07-09 12:20:15 +00:00
|
|
|
struct val *result;
|
2001-05-26 20:45:25 +00:00
|
|
|
|
Make /bin/expr support 64bit numeric range and range checks by default,
again. This brings back the behaviour of expr in FreeBSD-4, which had been
reverted due to an assumed incompatbility with POSIX.1 for FreeBSD-5.
This issue has been discussed in the freebsd-standards list, and the
consensus was, that POSIX.1 is in fact not violated by this extension,
since it affects only cases of POSIX undefined behaviour (overflow of
signed long).
Other operating systems did upgrade their versions of expr to support
64bit range, after it had been initially brought to FreeBSD. They have
used it for a decade without problems, meanwhile.
The -e option is retained, but it will only select less strict checking
of numeric parameters (leading white-space, leading "+" are allowed and
skipped, an empty string is considered to represent 0 in numeric context.)
The call of check_utility_compat() as a means of establishing backwards
compatibility with FreeBSD-4 is considered obsolete, but preserved in
this commit. It is expected to be removed in a later revision of this
file.
Reviewed by: bde, das, jilles
MFC after: 2 month (those parts that do not violate POLA)
2011-07-09 12:05:53 +00:00
|
|
|
void assert_to_integer(struct val *);
|
2011-07-09 12:14:57 +00:00
|
|
|
void assert_div(intmax_t, intmax_t);
|
|
|
|
void assert_minus(intmax_t, intmax_t, intmax_t);
|
|
|
|
void assert_plus(intmax_t, intmax_t, intmax_t);
|
|
|
|
void assert_times(intmax_t, intmax_t, intmax_t);
|
|
|
|
int compare_vals(struct val *, struct val *);
|
2002-02-02 06:36:49 +00:00
|
|
|
void free_value(struct val *);
|
Make /bin/expr support 64bit numeric range and range checks by default,
again. This brings back the behaviour of expr in FreeBSD-4, which had been
reverted due to an assumed incompatbility with POSIX.1 for FreeBSD-5.
This issue has been discussed in the freebsd-standards list, and the
consensus was, that POSIX.1 is in fact not violated by this extension,
since it affects only cases of POSIX undefined behaviour (overflow of
signed long).
Other operating systems did upgrade their versions of expr to support
64bit range, after it had been initially brought to FreeBSD. They have
used it for a decade without problems, meanwhile.
The -e option is retained, but it will only select less strict checking
of numeric parameters (leading white-space, leading "+" are allowed and
skipped, an empty string is considered to represent 0 in numeric context.)
The call of check_utility_compat() as a means of establishing backwards
compatibility with FreeBSD-4 is considered obsolete, but preserved in
this commit. It is expected to be removed in a later revision of this
file.
Reviewed by: bde, das, jilles
MFC after: 2 month (those parts that do not violate POLA)
2011-07-09 12:05:53 +00:00
|
|
|
int is_integer(const char *);
|
2011-07-09 12:20:15 +00:00
|
|
|
int is_string(struct val *);
|
Make /bin/expr support 64bit numeric range and range checks by default,
again. This brings back the behaviour of expr in FreeBSD-4, which had been
reverted due to an assumed incompatbility with POSIX.1 for FreeBSD-5.
This issue has been discussed in the freebsd-standards list, and the
consensus was, that POSIX.1 is in fact not violated by this extension,
since it affects only cases of POSIX undefined behaviour (overflow of
signed long).
Other operating systems did upgrade their versions of expr to support
64bit range, after it had been initially brought to FreeBSD. They have
used it for a decade without problems, meanwhile.
The -e option is retained, but it will only select less strict checking
of numeric parameters (leading white-space, leading "+" are allowed and
skipped, an empty string is considered to represent 0 in numeric context.)
The call of check_utility_compat() as a means of establishing backwards
compatibility with FreeBSD-4 is considered obsolete, but preserved in
this commit. It is expected to be removed in a later revision of this
file.
Reviewed by: bde, das, jilles
MFC after: 2 month (those parts that do not violate POLA)
2011-07-09 12:05:53 +00:00
|
|
|
int is_zero_or_null(struct val *);
|
2002-03-22 20:18:26 +00:00
|
|
|
struct val *make_integer(intmax_t);
|
2002-02-02 06:36:49 +00:00
|
|
|
struct val *make_str(const char *);
|
|
|
|
struct val *op_and(struct val *, struct val *);
|
|
|
|
struct val *op_colon(struct val *, struct val *);
|
|
|
|
struct val *op_div(struct val *, struct val *);
|
|
|
|
struct val *op_eq(struct val *, struct val *);
|
|
|
|
struct val *op_ge(struct val *, struct val *);
|
|
|
|
struct val *op_gt(struct val *, struct val *);
|
|
|
|
struct val *op_le(struct val *, struct val *);
|
|
|
|
struct val *op_lt(struct val *, struct val *);
|
|
|
|
struct val *op_minus(struct val *, struct val *);
|
|
|
|
struct val *op_ne(struct val *, struct val *);
|
|
|
|
struct val *op_or(struct val *, struct val *);
|
|
|
|
struct val *op_plus(struct val *, struct val *);
|
|
|
|
struct val *op_rem(struct val *, struct val *);
|
|
|
|
struct val *op_times(struct val *, struct val *);
|
Make /bin/expr support 64bit numeric range and range checks by default,
again. This brings back the behaviour of expr in FreeBSD-4, which had been
reverted due to an assumed incompatbility with POSIX.1 for FreeBSD-5.
This issue has been discussed in the freebsd-standards list, and the
consensus was, that POSIX.1 is in fact not violated by this extension,
since it affects only cases of POSIX undefined behaviour (overflow of
signed long).
Other operating systems did upgrade their versions of expr to support
64bit range, after it had been initially brought to FreeBSD. They have
used it for a decade without problems, meanwhile.
The -e option is retained, but it will only select less strict checking
of numeric parameters (leading white-space, leading "+" are allowed and
skipped, an empty string is considered to represent 0 in numeric context.)
The call of check_utility_compat() as a means of establishing backwards
compatibility with FreeBSD-4 is considered obsolete, but preserved in
this commit. It is expected to be removed in a later revision of this
file.
Reviewed by: bde, das, jilles
MFC after: 2 month (those parts that do not violate POLA)
2011-07-09 12:05:53 +00:00
|
|
|
int to_integer(struct val *);
|
2002-02-02 06:36:49 +00:00
|
|
|
void to_string(struct val *);
|
|
|
|
int yyerror(const char *);
|
|
|
|
int yylex(void);
|
1993-06-12 14:58:17 +00:00
|
|
|
|
|
|
|
%}
|
|
|
|
|
|
|
|
%union
|
|
|
|
{
|
|
|
|
struct val *val;
|
|
|
|
}
|
|
|
|
|
|
|
|
%left <val> '|'
|
|
|
|
%left <val> '&'
|
|
|
|
%left <val> '=' '>' '<' GE LE NE
|
|
|
|
%left <val> '+' '-'
|
|
|
|
%left <val> '*' '/' '%'
|
|
|
|
%left <val> ':'
|
|
|
|
|
|
|
|
%token <val> TOKEN
|
|
|
|
%type <val> start expr
|
|
|
|
|
|
|
|
%%
|
|
|
|
|
|
|
|
start: expr { result = $$; }
|
|
|
|
|
|
|
|
expr: TOKEN
|
|
|
|
| '(' expr ')' { $$ = $2; }
|
2011-07-09 12:20:15 +00:00
|
|
|
| expr '|' expr { $$ = op_or($1, $3); }
|
|
|
|
| expr '&' expr { $$ = op_and($1, $3); }
|
|
|
|
| expr '=' expr { $$ = op_eq($1, $3); }
|
|
|
|
| expr '>' expr { $$ = op_gt($1, $3); }
|
|
|
|
| expr '<' expr { $$ = op_lt($1, $3); }
|
|
|
|
| expr GE expr { $$ = op_ge($1, $3); }
|
|
|
|
| expr LE expr { $$ = op_le($1, $3); }
|
|
|
|
| expr NE expr { $$ = op_ne($1, $3); }
|
|
|
|
| expr '+' expr { $$ = op_plus($1, $3); }
|
|
|
|
| expr '-' expr { $$ = op_minus($1, $3); }
|
|
|
|
| expr '*' expr { $$ = op_times($1, $3); }
|
|
|
|
| expr '/' expr { $$ = op_div($1, $3); }
|
|
|
|
| expr '%' expr { $$ = op_rem($1, $3); }
|
|
|
|
| expr ':' expr { $$ = op_colon($1, $3); }
|
1993-06-12 14:58:17 +00:00
|
|
|
;
|
|
|
|
|
|
|
|
%%
|
|
|
|
|
|
|
|
struct val *
|
2002-03-22 20:18:26 +00:00
|
|
|
make_integer(intmax_t i)
|
1993-06-12 14:58:17 +00:00
|
|
|
{
|
|
|
|
struct val *vp;
|
|
|
|
|
2011-07-09 12:20:15 +00:00
|
|
|
vp = (struct val *)malloc(sizeof(*vp));
|
|
|
|
if (vp == NULL)
|
2002-03-22 20:18:26 +00:00
|
|
|
errx(ERR_EXIT, "malloc() failed");
|
1993-06-12 14:58:17 +00:00
|
|
|
|
|
|
|
vp->type = integer;
|
|
|
|
vp->u.i = i;
|
2011-07-09 12:20:15 +00:00
|
|
|
return (vp);
|
1993-06-12 14:58:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
struct val *
|
2002-02-02 06:36:49 +00:00
|
|
|
make_str(const char *s)
|
1993-06-12 14:58:17 +00:00
|
|
|
{
|
|
|
|
struct val *vp;
|
|
|
|
|
2011-07-09 12:20:15 +00:00
|
|
|
vp = (struct val *)malloc(sizeof(*vp));
|
|
|
|
if (vp == NULL || ((vp->u.s = strdup(s)) == NULL))
|
2002-03-22 20:18:26 +00:00
|
|
|
errx(ERR_EXIT, "malloc() failed");
|
1993-06-12 14:58:17 +00:00
|
|
|
|
Make /bin/expr support 64bit numeric range and range checks by default,
again. This brings back the behaviour of expr in FreeBSD-4, which had been
reverted due to an assumed incompatbility with POSIX.1 for FreeBSD-5.
This issue has been discussed in the freebsd-standards list, and the
consensus was, that POSIX.1 is in fact not violated by this extension,
since it affects only cases of POSIX undefined behaviour (overflow of
signed long).
Other operating systems did upgrade their versions of expr to support
64bit range, after it had been initially brought to FreeBSD. They have
used it for a decade without problems, meanwhile.
The -e option is retained, but it will only select less strict checking
of numeric parameters (leading white-space, leading "+" are allowed and
skipped, an empty string is considered to represent 0 in numeric context.)
The call of check_utility_compat() as a means of establishing backwards
compatibility with FreeBSD-4 is considered obsolete, but preserved in
this commit. It is expected to be removed in a later revision of this
file.
Reviewed by: bde, das, jilles
MFC after: 2 month (those parts that do not violate POLA)
2011-07-09 12:05:53 +00:00
|
|
|
if (is_integer(s))
|
|
|
|
vp->type = numeric_string;
|
2002-05-10 22:59:29 +00:00
|
|
|
else
|
1995-11-18 18:05:03 +00:00
|
|
|
vp->type = string;
|
1995-08-04 17:08:07 +00:00
|
|
|
|
2011-07-09 12:20:15 +00:00
|
|
|
return (vp);
|
1993-06-12 14:58:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2002-02-02 06:36:49 +00:00
|
|
|
free_value(struct val *vp)
|
1993-06-12 14:58:17 +00:00
|
|
|
{
|
1995-11-18 18:05:03 +00:00
|
|
|
if (vp->type == string || vp->type == numeric_string)
|
2011-07-09 12:20:15 +00:00
|
|
|
free(vp->u.s);
|
1993-06-12 14:58:17 +00:00
|
|
|
}
|
|
|
|
|
Make /bin/expr support 64bit numeric range and range checks by default,
again. This brings back the behaviour of expr in FreeBSD-4, which had been
reverted due to an assumed incompatbility with POSIX.1 for FreeBSD-5.
This issue has been discussed in the freebsd-standards list, and the
consensus was, that POSIX.1 is in fact not violated by this extension,
since it affects only cases of POSIX undefined behaviour (overflow of
signed long).
Other operating systems did upgrade their versions of expr to support
64bit range, after it had been initially brought to FreeBSD. They have
used it for a decade without problems, meanwhile.
The -e option is retained, but it will only select less strict checking
of numeric parameters (leading white-space, leading "+" are allowed and
skipped, an empty string is considered to represent 0 in numeric context.)
The call of check_utility_compat() as a means of establishing backwards
compatibility with FreeBSD-4 is considered obsolete, but preserved in
this commit. It is expected to be removed in a later revision of this
file.
Reviewed by: bde, das, jilles
MFC after: 2 month (those parts that do not violate POLA)
2011-07-09 12:05:53 +00:00
|
|
|
int
|
2002-02-02 06:36:49 +00:00
|
|
|
to_integer(struct val *vp)
|
1993-06-12 14:58:17 +00:00
|
|
|
{
|
2002-03-22 20:18:26 +00:00
|
|
|
intmax_t i;
|
1993-06-12 14:58:17 +00:00
|
|
|
|
Make /bin/expr support 64bit numeric range and range checks by default,
again. This brings back the behaviour of expr in FreeBSD-4, which had been
reverted due to an assumed incompatbility with POSIX.1 for FreeBSD-5.
This issue has been discussed in the freebsd-standards list, and the
consensus was, that POSIX.1 is in fact not violated by this extension,
since it affects only cases of POSIX undefined behaviour (overflow of
signed long).
Other operating systems did upgrade their versions of expr to support
64bit range, after it had been initially brought to FreeBSD. They have
used it for a decade without problems, meanwhile.
The -e option is retained, but it will only select less strict checking
of numeric parameters (leading white-space, leading "+" are allowed and
skipped, an empty string is considered to represent 0 in numeric context.)
The call of check_utility_compat() as a means of establishing backwards
compatibility with FreeBSD-4 is considered obsolete, but preserved in
this commit. It is expected to be removed in a later revision of this
file.
Reviewed by: bde, das, jilles
MFC after: 2 month (those parts that do not violate POLA)
2011-07-09 12:05:53 +00:00
|
|
|
/* we can only convert numeric_string to integer, here */
|
|
|
|
if (vp->type == numeric_string) {
|
|
|
|
errno = 0;
|
2002-05-10 22:59:29 +00:00
|
|
|
i = strtoimax(vp->u.s, (char **)NULL, 10);
|
Make /bin/expr support 64bit numeric range and range checks by default,
again. This brings back the behaviour of expr in FreeBSD-4, which had been
reverted due to an assumed incompatbility with POSIX.1 for FreeBSD-5.
This issue has been discussed in the freebsd-standards list, and the
consensus was, that POSIX.1 is in fact not violated by this extension,
since it affects only cases of POSIX undefined behaviour (overflow of
signed long).
Other operating systems did upgrade their versions of expr to support
64bit range, after it had been initially brought to FreeBSD. They have
used it for a decade without problems, meanwhile.
The -e option is retained, but it will only select less strict checking
of numeric parameters (leading white-space, leading "+" are allowed and
skipped, an empty string is considered to represent 0 in numeric context.)
The call of check_utility_compat() as a means of establishing backwards
compatibility with FreeBSD-4 is considered obsolete, but preserved in
this commit. It is expected to be removed in a later revision of this
file.
Reviewed by: bde, das, jilles
MFC after: 2 month (those parts that do not violate POLA)
2011-07-09 12:05:53 +00:00
|
|
|
/* just keep as numeric_string, if the conversion fails */
|
|
|
|
if (errno != ERANGE) {
|
2011-07-09 12:20:15 +00:00
|
|
|
free(vp->u.s);
|
Make /bin/expr support 64bit numeric range and range checks by default,
again. This brings back the behaviour of expr in FreeBSD-4, which had been
reverted due to an assumed incompatbility with POSIX.1 for FreeBSD-5.
This issue has been discussed in the freebsd-standards list, and the
consensus was, that POSIX.1 is in fact not violated by this extension,
since it affects only cases of POSIX undefined behaviour (overflow of
signed long).
Other operating systems did upgrade their versions of expr to support
64bit range, after it had been initially brought to FreeBSD. They have
used it for a decade without problems, meanwhile.
The -e option is retained, but it will only select less strict checking
of numeric parameters (leading white-space, leading "+" are allowed and
skipped, an empty string is considered to represent 0 in numeric context.)
The call of check_utility_compat() as a means of establishing backwards
compatibility with FreeBSD-4 is considered obsolete, but preserved in
this commit. It is expected to be removed in a later revision of this
file.
Reviewed by: bde, das, jilles
MFC after: 2 month (those parts that do not violate POLA)
2011-07-09 12:05:53 +00:00
|
|
|
vp->u.i = i;
|
|
|
|
vp->type = integer;
|
|
|
|
}
|
2002-05-10 22:59:29 +00:00
|
|
|
}
|
Make /bin/expr support 64bit numeric range and range checks by default,
again. This brings back the behaviour of expr in FreeBSD-4, which had been
reverted due to an assumed incompatbility with POSIX.1 for FreeBSD-5.
This issue has been discussed in the freebsd-standards list, and the
consensus was, that POSIX.1 is in fact not violated by this extension,
since it affects only cases of POSIX undefined behaviour (overflow of
signed long).
Other operating systems did upgrade their versions of expr to support
64bit range, after it had been initially brought to FreeBSD. They have
used it for a decade without problems, meanwhile.
The -e option is retained, but it will only select less strict checking
of numeric parameters (leading white-space, leading "+" are allowed and
skipped, an empty string is considered to represent 0 in numeric context.)
The call of check_utility_compat() as a means of establishing backwards
compatibility with FreeBSD-4 is considered obsolete, but preserved in
this commit. It is expected to be removed in a later revision of this
file.
Reviewed by: bde, das, jilles
MFC after: 2 month (those parts that do not violate POLA)
2011-07-09 12:05:53 +00:00
|
|
|
return (vp->type == integer);
|
|
|
|
}
|
2002-03-22 20:18:26 +00:00
|
|
|
|
Make /bin/expr support 64bit numeric range and range checks by default,
again. This brings back the behaviour of expr in FreeBSD-4, which had been
reverted due to an assumed incompatbility with POSIX.1 for FreeBSD-5.
This issue has been discussed in the freebsd-standards list, and the
consensus was, that POSIX.1 is in fact not violated by this extension,
since it affects only cases of POSIX undefined behaviour (overflow of
signed long).
Other operating systems did upgrade their versions of expr to support
64bit range, after it had been initially brought to FreeBSD. They have
used it for a decade without problems, meanwhile.
The -e option is retained, but it will only select less strict checking
of numeric parameters (leading white-space, leading "+" are allowed and
skipped, an empty string is considered to represent 0 in numeric context.)
The call of check_utility_compat() as a means of establishing backwards
compatibility with FreeBSD-4 is considered obsolete, but preserved in
this commit. It is expected to be removed in a later revision of this
file.
Reviewed by: bde, das, jilles
MFC after: 2 month (those parts that do not violate POLA)
2011-07-09 12:05:53 +00:00
|
|
|
void
|
|
|
|
assert_to_integer(struct val *vp)
|
|
|
|
{
|
|
|
|
if (vp->type == string)
|
|
|
|
errx(ERR_EXIT, "not a decimal number: '%s'", vp->u.s);
|
|
|
|
if (!to_integer(vp))
|
|
|
|
errx(ERR_EXIT, "operand too large: '%s'", vp->u.s);
|
1993-06-12 14:58:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2002-02-02 06:36:49 +00:00
|
|
|
to_string(struct val *vp)
|
1993-06-12 14:58:17 +00:00
|
|
|
{
|
|
|
|
char *tmp;
|
|
|
|
|
1995-11-18 18:05:03 +00:00
|
|
|
if (vp->type == string || vp->type == numeric_string)
|
1993-06-12 14:58:17 +00:00
|
|
|
return;
|
|
|
|
|
2002-03-22 20:18:26 +00:00
|
|
|
/*
|
|
|
|
* log_10(x) ~= 0.3 * log_2(x). Rounding up gives the number
|
|
|
|
* of digits; add one each for the sign and terminating null
|
|
|
|
* character, respectively.
|
|
|
|
*/
|
|
|
|
#define NDIGITS(x) (3 * (sizeof(x) * CHAR_BIT) / 10 + 1 + 1 + 1)
|
|
|
|
tmp = malloc(NDIGITS(vp->u.i));
|
|
|
|
if (tmp == NULL)
|
|
|
|
errx(ERR_EXIT, "malloc() failed");
|
|
|
|
|
|
|
|
sprintf(tmp, "%jd", vp->u.i);
|
1993-06-12 14:58:17 +00:00
|
|
|
vp->type = string;
|
|
|
|
vp->u.s = tmp;
|
|
|
|
}
|
|
|
|
|
Make /bin/expr support 64bit numeric range and range checks by default,
again. This brings back the behaviour of expr in FreeBSD-4, which had been
reverted due to an assumed incompatbility with POSIX.1 for FreeBSD-5.
This issue has been discussed in the freebsd-standards list, and the
consensus was, that POSIX.1 is in fact not violated by this extension,
since it affects only cases of POSIX undefined behaviour (overflow of
signed long).
Other operating systems did upgrade their versions of expr to support
64bit range, after it had been initially brought to FreeBSD. They have
used it for a decade without problems, meanwhile.
The -e option is retained, but it will only select less strict checking
of numeric parameters (leading white-space, leading "+" are allowed and
skipped, an empty string is considered to represent 0 in numeric context.)
The call of check_utility_compat() as a means of establishing backwards
compatibility with FreeBSD-4 is considered obsolete, but preserved in
this commit. It is expected to be removed in a later revision of this
file.
Reviewed by: bde, das, jilles
MFC after: 2 month (those parts that do not violate POLA)
2011-07-09 12:05:53 +00:00
|
|
|
int
|
|
|
|
is_integer(const char *s)
|
|
|
|
{
|
|
|
|
if (nonposix) {
|
|
|
|
if (*s == '\0')
|
|
|
|
return (1);
|
|
|
|
while (isspace((unsigned char)*s))
|
|
|
|
s++;
|
|
|
|
}
|
|
|
|
if (*s == '-' || (nonposix && *s == '+'))
|
|
|
|
s++;
|
|
|
|
if (*s == '\0')
|
|
|
|
return (0);
|
|
|
|
while (isdigit((unsigned char)*s))
|
|
|
|
s++;
|
|
|
|
return (*s == '\0');
|
|
|
|
}
|
|
|
|
|
1993-06-12 14:58:17 +00:00
|
|
|
int
|
2011-07-09 12:20:15 +00:00
|
|
|
is_string(struct val *vp)
|
1993-06-12 14:58:17 +00:00
|
|
|
{
|
1995-11-18 18:05:03 +00:00
|
|
|
/* only TRUE if this string is not a valid integer */
|
1993-06-12 14:58:17 +00:00
|
|
|
return (vp->type == string);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2002-02-02 06:36:49 +00:00
|
|
|
yylex(void)
|
1993-06-12 14:58:17 +00:00
|
|
|
{
|
|
|
|
char *p;
|
|
|
|
|
|
|
|
if (*av == NULL)
|
|
|
|
return (0);
|
|
|
|
|
|
|
|
p = *av++;
|
|
|
|
|
2011-07-09 12:20:15 +00:00
|
|
|
if (strlen(p) == 1) {
|
|
|
|
if (strchr("|&=<>+-*/%:()", *p))
|
1993-06-12 14:58:17 +00:00
|
|
|
return (*p);
|
2011-07-09 12:20:15 +00:00
|
|
|
} else if (strlen(p) == 2 && p[1] == '=') {
|
1993-06-12 14:58:17 +00:00
|
|
|
switch (*p) {
|
|
|
|
case '>': return (GE);
|
|
|
|
case '<': return (LE);
|
|
|
|
case '!': return (NE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-07-09 12:20:15 +00:00
|
|
|
yylval.val = make_str(p);
|
1993-06-12 14:58:17 +00:00
|
|
|
return (TOKEN);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2002-02-02 06:36:49 +00:00
|
|
|
is_zero_or_null(struct val *vp)
|
1993-06-12 14:58:17 +00:00
|
|
|
{
|
2011-07-09 12:20:15 +00:00
|
|
|
if (vp->type == integer)
|
1993-06-12 14:58:17 +00:00
|
|
|
return (vp->u.i == 0);
|
2011-07-09 12:20:15 +00:00
|
|
|
|
|
|
|
return (*vp->u.s == 0 || (to_integer(vp) && vp->u.i == 0));
|
1993-06-12 14:58:17 +00:00
|
|
|
}
|
|
|
|
|
1995-11-18 18:05:03 +00:00
|
|
|
int
|
2002-03-22 20:18:26 +00:00
|
|
|
main(int argc, char *argv[])
|
1993-06-12 14:58:17 +00:00
|
|
|
{
|
2002-03-22 20:18:26 +00:00
|
|
|
int c;
|
|
|
|
|
2011-07-09 12:20:15 +00:00
|
|
|
setlocale(LC_ALL, "");
|
2002-10-28 00:15:43 +00:00
|
|
|
if (getenv("EXPR_COMPAT") != NULL
|
|
|
|
|| check_utility_compat("expr")) {
|
2002-04-22 21:23:09 +00:00
|
|
|
av = argv + 1;
|
Make /bin/expr support 64bit numeric range and range checks by default,
again. This brings back the behaviour of expr in FreeBSD-4, which had been
reverted due to an assumed incompatbility with POSIX.1 for FreeBSD-5.
This issue has been discussed in the freebsd-standards list, and the
consensus was, that POSIX.1 is in fact not violated by this extension,
since it affects only cases of POSIX undefined behaviour (overflow of
signed long).
Other operating systems did upgrade their versions of expr to support
64bit range, after it had been initially brought to FreeBSD. They have
used it for a decade without problems, meanwhile.
The -e option is retained, but it will only select less strict checking
of numeric parameters (leading white-space, leading "+" are allowed and
skipped, an empty string is considered to represent 0 in numeric context.)
The call of check_utility_compat() as a means of establishing backwards
compatibility with FreeBSD-4 is considered obsolete, but preserved in
this commit. It is expected to be removed in a later revision of this
file.
Reviewed by: bde, das, jilles
MFC after: 2 month (those parts that do not violate POLA)
2011-07-09 12:05:53 +00:00
|
|
|
nonposix = 1;
|
2002-04-22 21:23:09 +00:00
|
|
|
} else {
|
2011-07-09 12:20:15 +00:00
|
|
|
while ((c = getopt(argc, argv, "e")) != -1) {
|
2002-04-22 21:23:09 +00:00
|
|
|
switch (c) {
|
2002-05-10 22:59:29 +00:00
|
|
|
case 'e':
|
Make /bin/expr support 64bit numeric range and range checks by default,
again. This brings back the behaviour of expr in FreeBSD-4, which had been
reverted due to an assumed incompatbility with POSIX.1 for FreeBSD-5.
This issue has been discussed in the freebsd-standards list, and the
consensus was, that POSIX.1 is in fact not violated by this extension,
since it affects only cases of POSIX undefined behaviour (overflow of
signed long).
Other operating systems did upgrade their versions of expr to support
64bit range, after it had been initially brought to FreeBSD. They have
used it for a decade without problems, meanwhile.
The -e option is retained, but it will only select less strict checking
of numeric parameters (leading white-space, leading "+" are allowed and
skipped, an empty string is considered to represent 0 in numeric context.)
The call of check_utility_compat() as a means of establishing backwards
compatibility with FreeBSD-4 is considered obsolete, but preserved in
this commit. It is expected to be removed in a later revision of this
file.
Reviewed by: bde, das, jilles
MFC after: 2 month (those parts that do not violate POLA)
2011-07-09 12:05:53 +00:00
|
|
|
nonposix = 1;
|
2002-05-10 22:59:29 +00:00
|
|
|
break;
|
2002-04-22 21:23:09 +00:00
|
|
|
default:
|
2011-07-09 12:20:15 +00:00
|
|
|
errx(ERR_EXIT,
|
2002-05-10 22:59:29 +00:00
|
|
|
"usage: expr [-e] expression\n");
|
2002-04-22 21:23:09 +00:00
|
|
|
}
|
2011-07-09 12:20:15 +00:00
|
|
|
}
|
2002-04-22 21:23:09 +00:00
|
|
|
av = argv + optind;
|
|
|
|
}
|
1993-06-12 14:58:17 +00:00
|
|
|
|
2002-03-22 20:18:26 +00:00
|
|
|
yyparse();
|
1993-06-12 14:58:17 +00:00
|
|
|
|
|
|
|
if (result->type == integer)
|
2002-03-22 20:18:26 +00:00
|
|
|
printf("%jd\n", result->u.i);
|
1993-06-12 14:58:17 +00:00
|
|
|
else
|
2002-03-22 20:18:26 +00:00
|
|
|
printf("%s\n", result->u.s);
|
1993-06-12 14:58:17 +00:00
|
|
|
|
2002-03-22 20:18:26 +00:00
|
|
|
return (is_zero_or_null(result));
|
1993-06-12 14:58:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2002-02-02 06:36:49 +00:00
|
|
|
yyerror(const char *s __unused)
|
1993-06-12 14:58:17 +00:00
|
|
|
{
|
2002-03-22 20:18:26 +00:00
|
|
|
errx(ERR_EXIT, "syntax error");
|
1993-06-12 14:58:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
struct val *
|
2002-02-02 06:36:49 +00:00
|
|
|
op_or(struct val *a, struct val *b)
|
1993-06-12 14:58:17 +00:00
|
|
|
{
|
Make /bin/expr support 64bit numeric range and range checks by default,
again. This brings back the behaviour of expr in FreeBSD-4, which had been
reverted due to an assumed incompatbility with POSIX.1 for FreeBSD-5.
This issue has been discussed in the freebsd-standards list, and the
consensus was, that POSIX.1 is in fact not violated by this extension,
since it affects only cases of POSIX undefined behaviour (overflow of
signed long).
Other operating systems did upgrade their versions of expr to support
64bit range, after it had been initially brought to FreeBSD. They have
used it for a decade without problems, meanwhile.
The -e option is retained, but it will only select less strict checking
of numeric parameters (leading white-space, leading "+" are allowed and
skipped, an empty string is considered to represent 0 in numeric context.)
The call of check_utility_compat() as a means of establishing backwards
compatibility with FreeBSD-4 is considered obsolete, but preserved in
this commit. It is expected to be removed in a later revision of this
file.
Reviewed by: bde, das, jilles
MFC after: 2 month (those parts that do not violate POLA)
2011-07-09 12:05:53 +00:00
|
|
|
if (!is_zero_or_null(a)) {
|
|
|
|
free_value(b);
|
1993-06-12 14:58:17 +00:00
|
|
|
return (a);
|
|
|
|
}
|
Make /bin/expr support 64bit numeric range and range checks by default,
again. This brings back the behaviour of expr in FreeBSD-4, which had been
reverted due to an assumed incompatbility with POSIX.1 for FreeBSD-5.
This issue has been discussed in the freebsd-standards list, and the
consensus was, that POSIX.1 is in fact not violated by this extension,
since it affects only cases of POSIX undefined behaviour (overflow of
signed long).
Other operating systems did upgrade their versions of expr to support
64bit range, after it had been initially brought to FreeBSD. They have
used it for a decade without problems, meanwhile.
The -e option is retained, but it will only select less strict checking
of numeric parameters (leading white-space, leading "+" are allowed and
skipped, an empty string is considered to represent 0 in numeric context.)
The call of check_utility_compat() as a means of establishing backwards
compatibility with FreeBSD-4 is considered obsolete, but preserved in
this commit. It is expected to be removed in a later revision of this
file.
Reviewed by: bde, das, jilles
MFC after: 2 month (those parts that do not violate POLA)
2011-07-09 12:05:53 +00:00
|
|
|
free_value(a);
|
|
|
|
if (!is_zero_or_null(b))
|
|
|
|
return (b);
|
|
|
|
free_value(b);
|
|
|
|
return (make_integer((intmax_t)0));
|
1993-06-12 14:58:17 +00:00
|
|
|
}
|
Make /bin/expr support 64bit numeric range and range checks by default,
again. This brings back the behaviour of expr in FreeBSD-4, which had been
reverted due to an assumed incompatbility with POSIX.1 for FreeBSD-5.
This issue has been discussed in the freebsd-standards list, and the
consensus was, that POSIX.1 is in fact not violated by this extension,
since it affects only cases of POSIX undefined behaviour (overflow of
signed long).
Other operating systems did upgrade their versions of expr to support
64bit range, after it had been initially brought to FreeBSD. They have
used it for a decade without problems, meanwhile.
The -e option is retained, but it will only select less strict checking
of numeric parameters (leading white-space, leading "+" are allowed and
skipped, an empty string is considered to represent 0 in numeric context.)
The call of check_utility_compat() as a means of establishing backwards
compatibility with FreeBSD-4 is considered obsolete, but preserved in
this commit. It is expected to be removed in a later revision of this
file.
Reviewed by: bde, das, jilles
MFC after: 2 month (those parts that do not violate POLA)
2011-07-09 12:05:53 +00:00
|
|
|
|
1993-06-12 14:58:17 +00:00
|
|
|
struct val *
|
2002-02-02 06:36:49 +00:00
|
|
|
op_and(struct val *a, struct val *b)
|
1993-06-12 14:58:17 +00:00
|
|
|
{
|
2011-07-09 12:20:15 +00:00
|
|
|
if (is_zero_or_null(a) || is_zero_or_null(b)) {
|
|
|
|
free_value(a);
|
|
|
|
free_value(b);
|
|
|
|
return (make_integer((intmax_t)0));
|
1993-06-12 14:58:17 +00:00
|
|
|
} else {
|
2011-07-09 12:20:15 +00:00
|
|
|
free_value(b);
|
1993-06-12 14:58:17 +00:00
|
|
|
return (a);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-07-09 12:14:57 +00:00
|
|
|
int
|
|
|
|
compare_vals(struct val *a, struct val *b)
|
1993-06-12 14:58:17 +00:00
|
|
|
{
|
2011-07-09 12:14:57 +00:00
|
|
|
int r;
|
1993-06-12 14:58:17 +00:00
|
|
|
|
2011-07-09 12:20:15 +00:00
|
|
|
if (is_string(a) || is_string(b)) {
|
2011-07-09 12:14:57 +00:00
|
|
|
to_string(a);
|
|
|
|
to_string(b);
|
|
|
|
r = strcoll(a->u.s, b->u.s);
|
1993-06-12 14:58:17 +00:00
|
|
|
} else {
|
Make /bin/expr support 64bit numeric range and range checks by default,
again. This brings back the behaviour of expr in FreeBSD-4, which had been
reverted due to an assumed incompatbility with POSIX.1 for FreeBSD-5.
This issue has been discussed in the freebsd-standards list, and the
consensus was, that POSIX.1 is in fact not violated by this extension,
since it affects only cases of POSIX undefined behaviour (overflow of
signed long).
Other operating systems did upgrade their versions of expr to support
64bit range, after it had been initially brought to FreeBSD. They have
used it for a decade without problems, meanwhile.
The -e option is retained, but it will only select less strict checking
of numeric parameters (leading white-space, leading "+" are allowed and
skipped, an empty string is considered to represent 0 in numeric context.)
The call of check_utility_compat() as a means of establishing backwards
compatibility with FreeBSD-4 is considered obsolete, but preserved in
this commit. It is expected to be removed in a later revision of this
file.
Reviewed by: bde, das, jilles
MFC after: 2 month (those parts that do not violate POLA)
2011-07-09 12:05:53 +00:00
|
|
|
assert_to_integer(a);
|
|
|
|
assert_to_integer(b);
|
2011-07-09 12:14:57 +00:00
|
|
|
if (a->u.i > b->u.i)
|
|
|
|
r = 1;
|
|
|
|
else if (a->u.i < b->u.i)
|
|
|
|
r = -1;
|
|
|
|
else
|
|
|
|
r = 0;
|
1993-06-12 14:58:17 +00:00
|
|
|
}
|
|
|
|
|
2011-07-09 12:14:57 +00:00
|
|
|
free_value(a);
|
|
|
|
free_value(b);
|
|
|
|
return (r);
|
1993-06-12 14:58:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
struct val *
|
2011-07-09 12:14:57 +00:00
|
|
|
op_eq(struct val *a, struct val *b)
|
1993-06-12 14:58:17 +00:00
|
|
|
{
|
2011-07-09 12:14:57 +00:00
|
|
|
return (make_integer((intmax_t)(compare_vals(a, b) == 0)));
|
|
|
|
}
|
1993-06-12 14:58:17 +00:00
|
|
|
|
2011-07-09 12:14:57 +00:00
|
|
|
struct val *
|
|
|
|
op_gt(struct val *a, struct val *b)
|
|
|
|
{
|
|
|
|
return (make_integer((intmax_t)(compare_vals(a, b) > 0)));
|
1993-06-12 14:58:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
struct val *
|
2002-02-02 06:36:49 +00:00
|
|
|
op_lt(struct val *a, struct val *b)
|
1993-06-12 14:58:17 +00:00
|
|
|
{
|
2011-07-09 12:14:57 +00:00
|
|
|
return (make_integer((intmax_t)(compare_vals(a, b) < 0)));
|
1993-06-12 14:58:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
struct val *
|
2002-02-02 06:36:49 +00:00
|
|
|
op_ge(struct val *a, struct val *b)
|
1993-06-12 14:58:17 +00:00
|
|
|
{
|
2011-07-09 12:14:57 +00:00
|
|
|
return (make_integer((intmax_t)(compare_vals(a, b) >= 0)));
|
1993-06-12 14:58:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
struct val *
|
2002-02-02 06:36:49 +00:00
|
|
|
op_le(struct val *a, struct val *b)
|
1993-06-12 14:58:17 +00:00
|
|
|
{
|
2011-07-09 12:14:57 +00:00
|
|
|
return (make_integer((intmax_t)(compare_vals(a, b) <= 0)));
|
1993-06-12 14:58:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
struct val *
|
2002-02-02 06:36:49 +00:00
|
|
|
op_ne(struct val *a, struct val *b)
|
1993-06-12 14:58:17 +00:00
|
|
|
{
|
2011-07-09 12:14:57 +00:00
|
|
|
return (make_integer((intmax_t)(compare_vals(a, b) != 0)));
|
1993-06-12 14:58:17 +00:00
|
|
|
}
|
|
|
|
|
2011-07-09 12:14:57 +00:00
|
|
|
void
|
|
|
|
assert_plus(intmax_t a, intmax_t b, intmax_t r)
|
2000-07-22 10:59:36 +00:00
|
|
|
{
|
2011-07-09 12:14:57 +00:00
|
|
|
/*
|
|
|
|
* sum of two positive numbers must be positive,
|
|
|
|
* sum of two negative numbers must be negative
|
|
|
|
*/
|
|
|
|
if ((a > 0 && b > 0 && r <= 0) ||
|
|
|
|
(a < 0 && b < 0 && r >= 0))
|
|
|
|
errx(ERR_EXIT, "overflow");
|
2000-07-22 10:59:36 +00:00
|
|
|
}
|
|
|
|
|
1993-06-12 14:58:17 +00:00
|
|
|
struct val *
|
2002-02-02 06:36:49 +00:00
|
|
|
op_plus(struct val *a, struct val *b)
|
1993-06-12 14:58:17 +00:00
|
|
|
{
|
|
|
|
struct val *r;
|
|
|
|
|
Make /bin/expr support 64bit numeric range and range checks by default,
again. This brings back the behaviour of expr in FreeBSD-4, which had been
reverted due to an assumed incompatbility with POSIX.1 for FreeBSD-5.
This issue has been discussed in the freebsd-standards list, and the
consensus was, that POSIX.1 is in fact not violated by this extension,
since it affects only cases of POSIX undefined behaviour (overflow of
signed long).
Other operating systems did upgrade their versions of expr to support
64bit range, after it had been initially brought to FreeBSD. They have
used it for a decade without problems, meanwhile.
The -e option is retained, but it will only select less strict checking
of numeric parameters (leading white-space, leading "+" are allowed and
skipped, an empty string is considered to represent 0 in numeric context.)
The call of check_utility_compat() as a means of establishing backwards
compatibility with FreeBSD-4 is considered obsolete, but preserved in
this commit. It is expected to be removed in a later revision of this
file.
Reviewed by: bde, das, jilles
MFC after: 2 month (those parts that do not violate POLA)
2011-07-09 12:05:53 +00:00
|
|
|
assert_to_integer(a);
|
|
|
|
assert_to_integer(b);
|
|
|
|
r = make_integer(a->u.i + b->u.i);
|
2011-07-09 12:14:57 +00:00
|
|
|
assert_plus(a->u.i, b->u.i, r->u.i);
|
2002-05-10 22:59:29 +00:00
|
|
|
|
2011-07-09 12:20:15 +00:00
|
|
|
free_value(a);
|
|
|
|
free_value(b);
|
|
|
|
return (r);
|
1993-06-12 14:58:17 +00:00
|
|
|
}
|
2000-07-22 10:59:36 +00:00
|
|
|
|
2011-07-09 12:14:57 +00:00
|
|
|
void
|
|
|
|
assert_minus(intmax_t a, intmax_t b, intmax_t r)
|
2000-07-22 10:59:36 +00:00
|
|
|
{
|
2018-04-14 04:35:10 +00:00
|
|
|
if ((a >= 0 && b < 0 && r <= 0) ||
|
|
|
|
(a < 0 && b > 0 && r >= 0))
|
2011-07-09 12:14:57 +00:00
|
|
|
errx(ERR_EXIT, "overflow");
|
2000-07-22 10:59:36 +00:00
|
|
|
}
|
|
|
|
|
1993-06-12 14:58:17 +00:00
|
|
|
struct val *
|
2002-02-02 06:36:49 +00:00
|
|
|
op_minus(struct val *a, struct val *b)
|
1993-06-12 14:58:17 +00:00
|
|
|
{
|
|
|
|
struct val *r;
|
|
|
|
|
Make /bin/expr support 64bit numeric range and range checks by default,
again. This brings back the behaviour of expr in FreeBSD-4, which had been
reverted due to an assumed incompatbility with POSIX.1 for FreeBSD-5.
This issue has been discussed in the freebsd-standards list, and the
consensus was, that POSIX.1 is in fact not violated by this extension,
since it affects only cases of POSIX undefined behaviour (overflow of
signed long).
Other operating systems did upgrade their versions of expr to support
64bit range, after it had been initially brought to FreeBSD. They have
used it for a decade without problems, meanwhile.
The -e option is retained, but it will only select less strict checking
of numeric parameters (leading white-space, leading "+" are allowed and
skipped, an empty string is considered to represent 0 in numeric context.)
The call of check_utility_compat() as a means of establishing backwards
compatibility with FreeBSD-4 is considered obsolete, but preserved in
this commit. It is expected to be removed in a later revision of this
file.
Reviewed by: bde, das, jilles
MFC after: 2 month (those parts that do not violate POLA)
2011-07-09 12:05:53 +00:00
|
|
|
assert_to_integer(a);
|
|
|
|
assert_to_integer(b);
|
|
|
|
r = make_integer(a->u.i - b->u.i);
|
2011-07-09 12:14:57 +00:00
|
|
|
assert_minus(a->u.i, b->u.i, r->u.i);
|
2002-05-10 22:59:29 +00:00
|
|
|
|
2011-07-09 12:20:15 +00:00
|
|
|
free_value(a);
|
|
|
|
free_value(b);
|
|
|
|
return (r);
|
1993-06-12 14:58:17 +00:00
|
|
|
}
|
2000-07-22 10:59:36 +00:00
|
|
|
|
2015-01-27 18:04:41 +00:00
|
|
|
/*
|
|
|
|
* We depend on undefined behaviour giving a result (in r).
|
|
|
|
* To test this result, pass it as volatile. This prevents
|
|
|
|
* optimizing away of the test based on the undefined behaviour.
|
|
|
|
*/
|
2011-07-09 12:14:57 +00:00
|
|
|
void
|
2015-01-27 18:04:41 +00:00
|
|
|
assert_times(intmax_t a, intmax_t b, volatile intmax_t r)
|
2000-07-22 10:59:36 +00:00
|
|
|
{
|
2011-07-09 12:14:57 +00:00
|
|
|
/*
|
2015-01-27 18:04:41 +00:00
|
|
|
* If the first operand is 0, no overflow is possible,
|
|
|
|
* else the result of the division test must match the
|
|
|
|
* second operand.
|
|
|
|
*
|
|
|
|
* Be careful to avoid overflow in the overflow test, as
|
|
|
|
* in assert_div(). Overflow in division would kill us
|
|
|
|
* with a SIGFPE before getting the test wrong. In old
|
|
|
|
* buggy versions, optimization used to give a null test
|
|
|
|
* instead of a SIGFPE.
|
2011-07-09 12:14:57 +00:00
|
|
|
*/
|
2015-01-27 18:04:41 +00:00
|
|
|
if ((a == -1 && b == INTMAX_MIN) || (a != 0 && r / a != b))
|
2011-07-09 12:14:57 +00:00
|
|
|
errx(ERR_EXIT, "overflow");
|
2000-07-22 10:59:36 +00:00
|
|
|
}
|
|
|
|
|
1993-06-12 14:58:17 +00:00
|
|
|
struct val *
|
2002-02-02 06:36:49 +00:00
|
|
|
op_times(struct val *a, struct val *b)
|
1993-06-12 14:58:17 +00:00
|
|
|
{
|
|
|
|
struct val *r;
|
|
|
|
|
Make /bin/expr support 64bit numeric range and range checks by default,
again. This brings back the behaviour of expr in FreeBSD-4, which had been
reverted due to an assumed incompatbility with POSIX.1 for FreeBSD-5.
This issue has been discussed in the freebsd-standards list, and the
consensus was, that POSIX.1 is in fact not violated by this extension,
since it affects only cases of POSIX undefined behaviour (overflow of
signed long).
Other operating systems did upgrade their versions of expr to support
64bit range, after it had been initially brought to FreeBSD. They have
used it for a decade without problems, meanwhile.
The -e option is retained, but it will only select less strict checking
of numeric parameters (leading white-space, leading "+" are allowed and
skipped, an empty string is considered to represent 0 in numeric context.)
The call of check_utility_compat() as a means of establishing backwards
compatibility with FreeBSD-4 is considered obsolete, but preserved in
this commit. It is expected to be removed in a later revision of this
file.
Reviewed by: bde, das, jilles
MFC after: 2 month (those parts that do not violate POLA)
2011-07-09 12:05:53 +00:00
|
|
|
assert_to_integer(a);
|
|
|
|
assert_to_integer(b);
|
|
|
|
r = make_integer(a->u.i * b->u.i);
|
2011-07-09 12:14:57 +00:00
|
|
|
assert_times(a->u.i, b->u.i, r->u.i);
|
2002-05-10 22:59:29 +00:00
|
|
|
|
2011-07-09 12:20:15 +00:00
|
|
|
free_value(a);
|
|
|
|
free_value(b);
|
1993-06-12 14:58:17 +00:00
|
|
|
return (r);
|
|
|
|
}
|
2000-07-22 10:59:36 +00:00
|
|
|
|
2011-07-09 12:14:57 +00:00
|
|
|
void
|
|
|
|
assert_div(intmax_t a, intmax_t b)
|
2000-07-22 10:59:36 +00:00
|
|
|
{
|
2011-07-09 12:14:57 +00:00
|
|
|
if (b == 0)
|
|
|
|
errx(ERR_EXIT, "division by zero");
|
2002-03-22 20:18:26 +00:00
|
|
|
/* only INTMAX_MIN / -1 causes overflow */
|
|
|
|
if (a == INTMAX_MIN && b == -1)
|
2011-07-09 12:14:57 +00:00
|
|
|
errx(ERR_EXIT, "overflow");
|
2000-07-22 10:59:36 +00:00
|
|
|
}
|
|
|
|
|
1993-06-12 14:58:17 +00:00
|
|
|
struct val *
|
2002-02-02 06:36:49 +00:00
|
|
|
op_div(struct val *a, struct val *b)
|
1993-06-12 14:58:17 +00:00
|
|
|
{
|
|
|
|
struct val *r;
|
|
|
|
|
Make /bin/expr support 64bit numeric range and range checks by default,
again. This brings back the behaviour of expr in FreeBSD-4, which had been
reverted due to an assumed incompatbility with POSIX.1 for FreeBSD-5.
This issue has been discussed in the freebsd-standards list, and the
consensus was, that POSIX.1 is in fact not violated by this extension,
since it affects only cases of POSIX undefined behaviour (overflow of
signed long).
Other operating systems did upgrade their versions of expr to support
64bit range, after it had been initially brought to FreeBSD. They have
used it for a decade without problems, meanwhile.
The -e option is retained, but it will only select less strict checking
of numeric parameters (leading white-space, leading "+" are allowed and
skipped, an empty string is considered to represent 0 in numeric context.)
The call of check_utility_compat() as a means of establishing backwards
compatibility with FreeBSD-4 is considered obsolete, but preserved in
this commit. It is expected to be removed in a later revision of this
file.
Reviewed by: bde, das, jilles
MFC after: 2 month (those parts that do not violate POLA)
2011-07-09 12:05:53 +00:00
|
|
|
assert_to_integer(a);
|
|
|
|
assert_to_integer(b);
|
2011-07-09 12:14:57 +00:00
|
|
|
/* assert based on operands only, not on result */
|
|
|
|
assert_div(a->u.i, b->u.i);
|
Make /bin/expr support 64bit numeric range and range checks by default,
again. This brings back the behaviour of expr in FreeBSD-4, which had been
reverted due to an assumed incompatbility with POSIX.1 for FreeBSD-5.
This issue has been discussed in the freebsd-standards list, and the
consensus was, that POSIX.1 is in fact not violated by this extension,
since it affects only cases of POSIX undefined behaviour (overflow of
signed long).
Other operating systems did upgrade their versions of expr to support
64bit range, after it had been initially brought to FreeBSD. They have
used it for a decade without problems, meanwhile.
The -e option is retained, but it will only select less strict checking
of numeric parameters (leading white-space, leading "+" are allowed and
skipped, an empty string is considered to represent 0 in numeric context.)
The call of check_utility_compat() as a means of establishing backwards
compatibility with FreeBSD-4 is considered obsolete, but preserved in
this commit. It is expected to be removed in a later revision of this
file.
Reviewed by: bde, das, jilles
MFC after: 2 month (those parts that do not violate POLA)
2011-07-09 12:05:53 +00:00
|
|
|
r = make_integer(a->u.i / b->u.i);
|
2002-05-10 22:59:29 +00:00
|
|
|
|
2011-07-09 12:20:15 +00:00
|
|
|
free_value(a);
|
|
|
|
free_value(b);
|
|
|
|
return (r);
|
1993-06-12 14:58:17 +00:00
|
|
|
}
|
2011-07-09 12:20:15 +00:00
|
|
|
|
1993-06-12 14:58:17 +00:00
|
|
|
struct val *
|
2002-02-02 06:36:49 +00:00
|
|
|
op_rem(struct val *a, struct val *b)
|
1993-06-12 14:58:17 +00:00
|
|
|
{
|
|
|
|
struct val *r;
|
|
|
|
|
Make /bin/expr support 64bit numeric range and range checks by default,
again. This brings back the behaviour of expr in FreeBSD-4, which had been
reverted due to an assumed incompatbility with POSIX.1 for FreeBSD-5.
This issue has been discussed in the freebsd-standards list, and the
consensus was, that POSIX.1 is in fact not violated by this extension,
since it affects only cases of POSIX undefined behaviour (overflow of
signed long).
Other operating systems did upgrade their versions of expr to support
64bit range, after it had been initially brought to FreeBSD. They have
used it for a decade without problems, meanwhile.
The -e option is retained, but it will only select less strict checking
of numeric parameters (leading white-space, leading "+" are allowed and
skipped, an empty string is considered to represent 0 in numeric context.)
The call of check_utility_compat() as a means of establishing backwards
compatibility with FreeBSD-4 is considered obsolete, but preserved in
this commit. It is expected to be removed in a later revision of this
file.
Reviewed by: bde, das, jilles
MFC after: 2 month (those parts that do not violate POLA)
2011-07-09 12:05:53 +00:00
|
|
|
assert_to_integer(a);
|
|
|
|
assert_to_integer(b);
|
2011-07-09 12:14:57 +00:00
|
|
|
/* pass a=1 to only check for div by zero */
|
|
|
|
assert_div(1, b->u.i);
|
Make /bin/expr support 64bit numeric range and range checks by default,
again. This brings back the behaviour of expr in FreeBSD-4, which had been
reverted due to an assumed incompatbility with POSIX.1 for FreeBSD-5.
This issue has been discussed in the freebsd-standards list, and the
consensus was, that POSIX.1 is in fact not violated by this extension,
since it affects only cases of POSIX undefined behaviour (overflow of
signed long).
Other operating systems did upgrade their versions of expr to support
64bit range, after it had been initially brought to FreeBSD. They have
used it for a decade without problems, meanwhile.
The -e option is retained, but it will only select less strict checking
of numeric parameters (leading white-space, leading "+" are allowed and
skipped, an empty string is considered to represent 0 in numeric context.)
The call of check_utility_compat() as a means of establishing backwards
compatibility with FreeBSD-4 is considered obsolete, but preserved in
this commit. It is expected to be removed in a later revision of this
file.
Reviewed by: bde, das, jilles
MFC after: 2 month (those parts that do not violate POLA)
2011-07-09 12:05:53 +00:00
|
|
|
r = make_integer(a->u.i % b->u.i);
|
2002-05-10 22:59:29 +00:00
|
|
|
|
2011-07-09 12:20:15 +00:00
|
|
|
free_value(a);
|
|
|
|
free_value(b);
|
|
|
|
return (r);
|
1993-06-12 14:58:17 +00:00
|
|
|
}
|
2011-07-09 12:20:15 +00:00
|
|
|
|
1993-06-12 14:58:17 +00:00
|
|
|
struct val *
|
2002-02-02 06:36:49 +00:00
|
|
|
op_colon(struct val *a, struct val *b)
|
1993-06-12 14:58:17 +00:00
|
|
|
{
|
1993-06-19 01:55:46 +00:00
|
|
|
regex_t rp;
|
1993-09-14 22:49:52 +00:00
|
|
|
regmatch_t rm[2];
|
1993-06-19 01:55:46 +00:00
|
|
|
char errbuf[256];
|
|
|
|
int eval;
|
|
|
|
struct val *v;
|
1993-07-21 22:56:14 +00:00
|
|
|
|
2007-02-18 19:48:59 +00:00
|
|
|
/* coerce both arguments to strings */
|
1993-07-21 22:56:14 +00:00
|
|
|
to_string(a);
|
|
|
|
to_string(b);
|
1993-06-19 01:55:46 +00:00
|
|
|
|
|
|
|
/* compile regular expression */
|
2011-07-09 12:20:15 +00:00
|
|
|
if ((eval = regcomp(&rp, b->u.s, 0)) != 0) {
|
|
|
|
regerror(eval, &rp, errbuf, sizeof(errbuf));
|
2002-03-22 20:18:26 +00:00
|
|
|
errx(ERR_EXIT, "%s", errbuf);
|
1993-06-12 14:58:17 +00:00
|
|
|
}
|
1993-06-19 01:55:46 +00:00
|
|
|
|
|
|
|
/* compare string against pattern */
|
1993-10-04 21:58:53 +00:00
|
|
|
/* remember that patterns are anchored to the beginning of the line */
|
2011-07-09 12:20:15 +00:00
|
|
|
if (regexec(&rp, a->u.s, (size_t)2, rm, 0) == 0 && rm[0].rm_so == 0)
|
1993-06-19 01:55:46 +00:00
|
|
|
if (rm[1].rm_so >= 0) {
|
1993-08-17 16:06:00 +00:00
|
|
|
*(a->u.s + rm[1].rm_eo) = '\0';
|
2011-07-09 12:20:15 +00:00
|
|
|
v = make_str(a->u.s + rm[1].rm_so);
|
1993-06-19 01:55:46 +00:00
|
|
|
|
2011-07-09 12:20:15 +00:00
|
|
|
} else
|
2012-03-19 00:45:01 +00:00
|
|
|
v = make_integer((intmax_t)(rm[0].rm_eo));
|
2011-07-09 12:20:15 +00:00
|
|
|
else
|
|
|
|
if (rp.re_nsub == 0)
|
|
|
|
v = make_integer((intmax_t)0);
|
|
|
|
else
|
|
|
|
v = make_str("");
|
1993-06-12 14:58:17 +00:00
|
|
|
|
1993-06-19 01:55:46 +00:00
|
|
|
/* free arguments and pattern buffer */
|
2011-07-09 12:20:15 +00:00
|
|
|
free_value(a);
|
|
|
|
free_value(b);
|
|
|
|
regfree(&rp);
|
1993-06-19 01:55:46 +00:00
|
|
|
|
2011-07-09 12:20:15 +00:00
|
|
|
return (v);
|
1993-06-12 14:58:17 +00:00
|
|
|
}
|