diff options
author | Jim Meyering <jim@meyering.net> | 2003-07-18 07:22:38 +0000 |
---|---|---|
committer | Jim Meyering <jim@meyering.net> | 2003-07-18 07:22:38 +0000 |
commit | 1eaf0e9870d0fa7e0891d5a9557fe3e6973e4b2a (patch) | |
tree | 2f40dc39e691bda4c439d9686eeea552ba9fa9de /src/expr.c | |
parent | e992d666e1c0d9911f279350270f9fae76bc7814 (diff) | |
download | coreutils-1eaf0e9870d0fa7e0891d5a9557fe3e6973e4b2a.tar.xz |
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.
Diffstat (limited to 'src/expr.c')
-rw-r--r-- | src/expr.c | 99 |
1 files changed, 72 insertions, 27 deletions
diff --git a/src/expr.c b/src/expr.c index bfc8dc545..c7f81db3f 100644 --- a/src/expr.c +++ b/src/expr.c @@ -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); } } |