mirror of
git://git.sv.gnu.org/coreutils.git
synced 2026-07-25 10:16:53 +02:00
Include "exitfail.h", "quotearg.h".
(EXPR_INVALID, EXPR_ERROR): New constants. (nomoreargs, null, toarith, nextarg): Return bool, not int. (syntax_error): New function, exiting with status 2. Use it insteading of printing "syntax error" ourselves. (main): Initialize exit_failure to EXPR_ERROR. Exit with EXPR_INVALID on syntax error (too few arguments). (nextarg): Use strcmp, not strcoll; strcoll might return an undesirable 0, or might fail. (docolon, eval4, eval3): Exit with status 3 on invalid argument type or other such error. (eval2): Report an error if strcoll fails in a string comparison.
This commit is contained in:
+72
-27
@@ -37,7 +37,9 @@
|
||||
#include "long-options.h"
|
||||
#include "error.h"
|
||||
#include "closeout.h"
|
||||
#include "exitfail.h"
|
||||
#include "inttostr.h"
|
||||
#include "quotearg.h"
|
||||
|
||||
/* The official name of this program (e.g., no `g' prefix). */
|
||||
#define PROGRAM_NAME "expr"
|
||||
@@ -48,6 +50,18 @@
|
||||
#define NEW(Type) XMALLOC (Type, 1)
|
||||
#define OLD(x) free (x)
|
||||
|
||||
/* Exit statuses. */
|
||||
enum
|
||||
{
|
||||
/* Invalid expression: i.e., its form does not conform to the
|
||||
grammar for expressions. Our grammar is an extension of the
|
||||
POSIX grammar. */
|
||||
EXPR_INVALID = 2,
|
||||
|
||||
/* Some other error occurred. */
|
||||
EXPR_ERROR
|
||||
};
|
||||
|
||||
/* The kinds of value we can have. */
|
||||
enum valtype
|
||||
{
|
||||
@@ -75,8 +89,8 @@ static char **args;
|
||||
char *program_name;
|
||||
|
||||
static VALUE *eval (void);
|
||||
static int nomoreargs (void);
|
||||
static int null (VALUE *v);
|
||||
static bool nomoreargs (void);
|
||||
static bool null (VALUE *v);
|
||||
static void printv (VALUE *v);
|
||||
|
||||
void
|
||||
@@ -151,6 +165,13 @@ Pattern matches return the string matched between \\( and \\) or null; if\n\
|
||||
exit (status);
|
||||
}
|
||||
|
||||
/* Report a syntax error and exit. */
|
||||
static void
|
||||
syntax_error (void)
|
||||
{
|
||||
error (EXPR_INVALID, 0, _("syntax error"));
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
@@ -162,6 +183,9 @@ main (int argc, char **argv)
|
||||
bindtextdomain (PACKAGE, LOCALEDIR);
|
||||
textdomain (PACKAGE);
|
||||
|
||||
/* Change the way library functions fail. */
|
||||
exit_failure = EXPR_ERROR;
|
||||
|
||||
atexit (close_stdout);
|
||||
|
||||
parse_long_options (argc, argv, PROGRAM_NAME, GNU_PACKAGE, VERSION,
|
||||
@@ -177,14 +201,14 @@ main (int argc, char **argv)
|
||||
if (argc <= 1)
|
||||
{
|
||||
error (0, 0, _("too few arguments"));
|
||||
usage (EXIT_FAILURE);
|
||||
usage (EXPR_INVALID);
|
||||
}
|
||||
|
||||
args = argv + 1;
|
||||
|
||||
v = eval ();
|
||||
if (!nomoreargs ())
|
||||
error (2, 0, _("syntax error"));
|
||||
syntax_error ();
|
||||
printv (v);
|
||||
|
||||
exit (null (v));
|
||||
@@ -249,9 +273,9 @@ printv (VALUE *v)
|
||||
puts (p);
|
||||
}
|
||||
|
||||
/* Return nonzero if V is a null-string or zero-number. */
|
||||
/* Return true if V is a null-string or zero-number. */
|
||||
|
||||
static int
|
||||
static bool
|
||||
null (VALUE *v)
|
||||
{
|
||||
switch (v->type)
|
||||
@@ -285,19 +309,19 @@ tostring (VALUE *v)
|
||||
}
|
||||
}
|
||||
|
||||
/* Coerce V to an integer value. Return 1 on success, 0 on failure. */
|
||||
/* Coerce V to an integer value. Return true on success, false on failure. */
|
||||
|
||||
static int
|
||||
static bool
|
||||
toarith (VALUE *v)
|
||||
{
|
||||
intmax_t i;
|
||||
int neg;
|
||||
bool neg;
|
||||
char *cp;
|
||||
|
||||
switch (v->type)
|
||||
{
|
||||
case integer:
|
||||
return 1;
|
||||
return true;
|
||||
case string:
|
||||
i = 0;
|
||||
cp = v->u.s;
|
||||
@@ -310,14 +334,14 @@ toarith (VALUE *v)
|
||||
if (ISDIGIT (*cp))
|
||||
i = i * 10 + *cp - '0';
|
||||
else
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
while (*++cp);
|
||||
|
||||
free (v->u.s);
|
||||
v->u.i = i * (neg ? -1 : 1);
|
||||
v->type = integer;
|
||||
return 1;
|
||||
return true;
|
||||
default:
|
||||
abort ();
|
||||
}
|
||||
@@ -326,22 +350,22 @@ toarith (VALUE *v)
|
||||
/* Return nonzero and advance if the next token matches STR exactly.
|
||||
STR must not be NULL. */
|
||||
|
||||
static int
|
||||
nextarg (char *str)
|
||||
static bool
|
||||
nextarg (char const *str)
|
||||
{
|
||||
if (*args == NULL)
|
||||
return 0;
|
||||
else
|
||||
{
|
||||
int r = strcoll (*args, str) == 0;
|
||||
bool r = strcmp (*args, str) == 0;
|
||||
args += r;
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
/* Return nonzero if there no more tokens. */
|
||||
/* Return true if there no more tokens. */
|
||||
|
||||
static int
|
||||
static bool
|
||||
nomoreargs (void)
|
||||
{
|
||||
return *args == 0;
|
||||
@@ -399,7 +423,7 @@ of the basic regular expression is not portable; it is being ignored"),
|
||||
re_syntax_options = RE_SYNTAX_POSIX_BASIC;
|
||||
errmsg = re_compile_pattern (pv->u.s, len, &re_buffer);
|
||||
if (errmsg)
|
||||
error (2, 0, "%s", errmsg);
|
||||
error (EXPR_ERROR, 0, "%s", errmsg);
|
||||
|
||||
matchlen = re_match (&re_buffer, sv->u.s, strlen (sv->u.s), 0, &re_regs);
|
||||
if (0 <= matchlen)
|
||||
@@ -436,18 +460,18 @@ eval7 (void)
|
||||
trace ("eval7");
|
||||
#endif
|
||||
if (nomoreargs ())
|
||||
error (2, 0, _("syntax error"));
|
||||
syntax_error ();
|
||||
|
||||
if (nextarg ("("))
|
||||
{
|
||||
v = eval ();
|
||||
if (!nextarg (")"))
|
||||
error (2, 0, _("syntax error"));
|
||||
syntax_error ();
|
||||
return v;
|
||||
}
|
||||
|
||||
if (nextarg (")"))
|
||||
error (2, 0, _("syntax error"));
|
||||
syntax_error ();
|
||||
|
||||
return str_value (*args++);
|
||||
}
|
||||
@@ -469,7 +493,7 @@ eval6 (void)
|
||||
if (nextarg ("+"))
|
||||
{
|
||||
if (nomoreargs ())
|
||||
error (2, 0, _("syntax error"));
|
||||
syntax_error ();
|
||||
return str_value (*args++);
|
||||
}
|
||||
else if (nextarg ("length"))
|
||||
@@ -584,13 +608,13 @@ eval4 (void)
|
||||
return l;
|
||||
r = eval5 ();
|
||||
if (!toarith (l) || !toarith (r))
|
||||
error (2, 0, _("non-numeric argument"));
|
||||
error (EXPR_ERROR, 0, _("non-numeric argument"));
|
||||
if (fxn == multiply)
|
||||
val = l->u.i * r->u.i;
|
||||
else
|
||||
{
|
||||
if (r->u.i == 0)
|
||||
error (2, 0, _("division by zero"));
|
||||
error (EXPR_ERROR, 0, _("division by zero"));
|
||||
val = fxn == divide ? l->u.i / r->u.i : l->u.i % r->u.i;
|
||||
}
|
||||
freev (l);
|
||||
@@ -623,7 +647,7 @@ eval3 (void)
|
||||
return l;
|
||||
r = eval4 ();
|
||||
if (!toarith (l) || !toarith (r))
|
||||
error (2, 0, _("non-numeric argument"));
|
||||
error (EXPR_ERROR, 0, _("non-numeric argument"));
|
||||
val = fxn == plus ? l->u.i + r->u.i : l->u.i - r->u.i;
|
||||
freev (l);
|
||||
freev (r);
|
||||
@@ -642,9 +666,11 @@ eval2 (void)
|
||||
{
|
||||
less_than, less_equal, equal, not_equal, greater_equal, greater_than
|
||||
} fxn;
|
||||
int val;
|
||||
bool val;
|
||||
intmax_t lval;
|
||||
intmax_t rval;
|
||||
int collation_errno;
|
||||
char *collation_arg1;
|
||||
|
||||
#ifdef EVAL_TRACE
|
||||
trace ("eval2");
|
||||
@@ -669,13 +695,31 @@ eval2 (void)
|
||||
r = eval3 ();
|
||||
tostring (l);
|
||||
tostring (r);
|
||||
lval = strcoll (l->u.s, r->u.s);
|
||||
|
||||
/* Save the first arg to strcoll, in case we need its value for
|
||||
a diagnostic later. This is needed because 'toarith' might
|
||||
free the first arg. */
|
||||
collation_arg1 = xstrdup (l->u.s);
|
||||
|
||||
errno = 0;
|
||||
lval = strcoll (collation_arg1, r->u.s);
|
||||
collation_errno = errno;
|
||||
rval = 0;
|
||||
if (toarith (l) && toarith (r))
|
||||
{
|
||||
lval = l->u.i;
|
||||
rval = r->u.i;
|
||||
}
|
||||
else if (collation_errno)
|
||||
{
|
||||
error (0, collation_errno, _("string comparison failed"));
|
||||
error (0, 0, _("Set LC_ALL='C' to work around the problem."));
|
||||
error (EXPR_ERROR, 0,
|
||||
_("The strings compared were %s and %s."),
|
||||
quotearg_n_style (0, locale_quoting_style, collation_arg1),
|
||||
quotearg_n_style (1, locale_quoting_style, r->u.s));
|
||||
}
|
||||
|
||||
switch (fxn)
|
||||
{
|
||||
case less_than: val = (lval < rval); break;
|
||||
@@ -688,6 +732,7 @@ eval2 (void)
|
||||
}
|
||||
freev (l);
|
||||
freev (r);
|
||||
free (collation_arg1);
|
||||
l = int_value (val);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user