X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=coreutils%2Fexpr.c;h=b23de8e9f8b5061125f5aa7cbe14f6e774ce75f2;hb=45d545890faa025491716035426ceb2af9c1906f;hp=9e3c04a11e7c02900b35b089a0c58b93498743a0;hpb=1b355ebba68bdd567dd3961a18291dfd9532c2e8;p=oweals%2Fbusybox.git diff --git a/coreutils/expr.c b/coreutils/expr.c index 9e3c04a11..b23de8e9f 100644 --- a/coreutils/expr.c +++ b/coreutils/expr.c @@ -5,27 +5,30 @@ * based on GNU expr Mike Parker. * Copyright (C) 86, 1991-1997, 1999 Free Software Foundation, Inc. * - * Busybox modifications + * Busybox modifications * Copyright (c) 2000 Edward Betts . + * Copyright (C) 2003-2005 Vladimir Oleynik + * - reduced 464 bytes. + * - 64 math support * - * this program is free software; you can redistribute it and/or modify - * it under the terms of the gnu general public license as published by - * the free software foundation; either version 2 of the license, or + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * - * this program is distributed in the hope that it will be useful, - * but without any warranty; without even the implied warranty of - * merchantability or fitness for a particular purpose. see the gnu - * general public license for more details. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. * - * you should have received a copy of the gnu general public license - * along with this program; if not, write to the free software - * foundation, inc., 59 temple place, suite 330, boston, ma 02111-1307 usa + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /* This program evaluates expressions. Each token (operator, operand, - * parenthesis) of the expression must be a seperate argument. The + * parenthesis) of the expression must be a separate argument. The * parser used is a reasonably general one, though any incarnation of * it is language-specific. It is especially nice for expressions. * @@ -33,11 +36,16 @@ * One function can handle multiple operators all of equal precedence, * provided they all associate ((x op x) op x). */ -#include "internal.h" +/* no getopt needed */ + #include +#include +#include +#include #include +#include +#include "busybox.h" -#include /* The kinds of value we can have. */ enum valtype { @@ -46,11 +54,23 @@ enum valtype { }; typedef enum valtype TYPE; +#if ENABLE_EXPR_MATH_SUPPORT_64 +typedef int64_t arith_t; +#define PF_REZ "ll" +#define PF_REZ_TYPE (long long) +#define STRTOL(s, e, b) strtoll(s, e, b) +#else +typedef long arith_t; +#define PF_REZ "l" +#define PF_REZ_TYPE (long) +#define STRTOL(s, e, b) strtol(s, e, b) +#endif + /* A value is.... */ struct valinfo { - TYPE type; /* Which kind. */ - union { /* The value itself. */ - int i; + TYPE type; /* Which kind. */ + union { /* The value itself. */ + arith_t i; char *s; } u; }; @@ -61,7 +81,7 @@ static char **args; static VALUE *docolon (VALUE *sv, VALUE *pv); static VALUE *eval (void); -static VALUE *int_value (int i); +static VALUE *int_value (arith_t i); static VALUE *str_value (char *s); static int nextarg (char *str); static int null (VALUE *v); @@ -74,26 +94,26 @@ int expr_main (int argc, char **argv) VALUE *v; if (argc == 1) { - fatalError("too few arguments\n"); + bb_error_msg_and_die("too few arguments"); } args = argv + 1; v = eval (); if (*args) - fatalError ("syntax error\n"); + bb_error_msg_and_die ("syntax error"); if (v->type == integer) - printf ("%d\n", v->u.i); - else - printf ("%s\n", v->u.s); + printf ("%" PF_REZ "d\n", PF_REZ_TYPE v->u.i); + else + puts (v->u.s); exit (null (v)); } /* Return a VALUE for I. */ -static VALUE *int_value (int i) +static VALUE *int_value (arith_t i) { VALUE *v; @@ -111,7 +131,7 @@ static VALUE *str_value (char *s) v = xmalloc (sizeof(VALUE)); v->type = string; - v->u.s = strdup (s); + v->u.s = bb_xstrdup (s); return v; } @@ -131,10 +151,8 @@ static int null (VALUE *v) switch (v->type) { case integer: return v->u.i == 0; - case string: + default: /* string: */ return v->u.s[0] == '\0' || strcmp (v->u.s, "0") == 0; - default: - abort (); } } @@ -142,12 +160,8 @@ static int null (VALUE *v) static void tostring (VALUE *v) { - char *temp; - if (v->type == integer) { - temp = xmalloc (4 * (sizeof (int) / sizeof (char))); - sprintf (temp, "%d", v->u.i); - v->u.s = temp; + v->u.s = bb_xasprintf ("%" PF_REZ "d", PF_REZ_TYPE v->u.i); v->type = string; } } @@ -156,24 +170,20 @@ static void tostring (VALUE *v) static int toarith (VALUE *v) { - int i; - - switch (v->type) { - case integer: - return 1; - case string: - i = 0; - /* Don't interpret the empty string as an integer. */ - if (v->u.s == 0) - return 0; - i = atoi(v->u.s); - free (v->u.s); - v->u.i = i; - v->type = integer; - return 1; - default: - abort (); + if(v->type == string) { + arith_t i; + char *e; + + /* Don't interpret the empty string as an integer. */ + /* Currently does not worry about overflow or int/long differences. */ + i = STRTOL(v->u.s, &e, 10); + if ((v->u.s == e) || *e) + return 0; + free (v->u.s); + v->u.i = i; + v->type = integer; } + return 1; } /* Return nonzero if the next token matches STR exactly. @@ -189,56 +199,59 @@ nextarg (char *str) /* The comparison operator handling functions. */ -#define cmpf(name, rel) \ -static int name (l, r) VALUE *l; VALUE *r; \ -{ \ - if (l->type == string || r->type == string) { \ - tostring (l); \ - tostring (r); \ - return strcmp (l->u.s, r->u.s) rel 0; \ - } \ - else \ - return l->u.i rel r->u.i; \ -} - cmpf (less_than, <) - cmpf (less_equal, <=) - cmpf (equal, ==) - cmpf (not_equal, !=) - cmpf (greater_equal, >=) - cmpf (greater_than, >) +static int cmp_common (VALUE *l, VALUE *r, int op) +{ + int cmpval; -#undef cmpf + if (l->type == string || r->type == string) { + tostring (l); + tostring (r); + cmpval = strcmp (l->u.s, r->u.s); + } + else + cmpval = l->u.i - r->u.i; + switch(op) { + case '<': + return cmpval < 0; + case ('L'+'E'): + return cmpval <= 0; + case '=': + return cmpval == 0; + case '!': + return cmpval != 0; + case '>': + return cmpval > 0; + default: /* >= */ + return cmpval >= 0; + } +} /* The arithmetic operator handling functions. */ -#define arithf(name, op) \ -static \ -int name (l, r) VALUE *l; VALUE *r; \ -{ \ - if (!toarith (l) || !toarith (r)) \ - fatalError ("non-numeric argument\n"); \ - return l->u.i op r->u.i; \ -} - -#define arithdivf(name, op) \ -int name (l, r) VALUE *l; VALUE *r; \ -{ \ - if (!toarith (l) || !toarith (r)) \ - fatalError ( "non-numeric argument\n"); \ - if (r->u.i == 0) \ - fatalError ( "division by zero\n"); \ - return l->u.i op r->u.i; \ +static arith_t arithmetic_common (VALUE *l, VALUE *r, int op) +{ + arith_t li, ri; + + if (!toarith (l) || !toarith (r)) + bb_error_msg_and_die ("non-numeric argument"); + li = l->u.i; + ri = r->u.i; + if((op == '/' || op == '%') && ri == 0) + bb_error_msg_and_die ( "division by zero"); + switch(op) { + case '+': + return li + ri; + case '-': + return li - ri; + case '*': + return li * ri; + case '/': + return li / ri; + default: + return li % ri; + } } - arithf (plus, +) - arithf (minus, -) - arithf (multiply, *) - arithdivf (divide, /) - arithdivf (mod, %) - -#undef arithf -#undef arithdivf - /* Do the : operator. SV is the VALUE for the lhs (the string), PV is the VALUE for the rhs (the pattern). */ @@ -246,10 +259,9 @@ int name (l, r) VALUE *l; VALUE *r; \ static VALUE *docolon (VALUE *sv, VALUE *pv) { VALUE *v; - const char *errmsg; - struct re_pattern_buffer re_buffer; - struct re_registers re_regs; - int len; + regex_t re_buffer; + const int NMATCH = 2; + regmatch_t re_regs[NMATCH]; tostring (sv); tostring (pv); @@ -261,27 +273,22 @@ of a basic regular expression is not portable; it is being ignored", pv->u.s); } - len = strlen (pv->u.s); memset (&re_buffer, 0, sizeof (re_buffer)); - memset (&re_regs, 0, sizeof (re_regs)); - re_buffer.allocated = 2 * len; - re_buffer.buffer = (unsigned char *) xmalloc (re_buffer.allocated); - re_buffer.translate = 0; - re_syntax_options = RE_SYNTAX_POSIX_BASIC; - errmsg = re_compile_pattern (pv->u.s, len, &re_buffer); - if (errmsg) { - fatalError("%s\n", errmsg); - } - - len = re_match (&re_buffer, sv->u.s, strlen (sv->u.s), 0, &re_regs); - if (len >= 0) { + memset (re_regs, 0, sizeof (*re_regs)); + if( regcomp (&re_buffer, pv->u.s, 0) != 0 ) + bb_error_msg_and_die("Invalid regular expression"); + + /* expr uses an anchored pattern match, so check that there was a + * match and that the match starts at offset 0. */ + if (regexec (&re_buffer, sv->u.s, NMATCH, re_regs, 0) != REG_NOMATCH && + re_regs[0].rm_so == 0) { /* Were \(...\) used? */ - if (re_buffer.re_nsub > 0) { /* was (re_regs.start[1] >= 0) */ - sv->u.s[re_regs.end[1]] = '\0'; - v = str_value (sv->u.s + re_regs.start[1]); + if (re_buffer.re_nsub > 0) { + sv->u.s[re_regs[1].rm_eo] = '\0'; + v = str_value (sv->u.s + re_regs[1].rm_so); } else - v = int_value (len); + v = int_value (re_regs[0].rm_eo); } else { /* Match failed -- return the right kind of null. */ @@ -290,7 +297,6 @@ of a basic regular expression is not portable; it is being ignored", else v = int_value (0); } - free (re_buffer.buffer); return v; } @@ -301,19 +307,19 @@ static VALUE *eval7 (void) VALUE *v; if (!*args) - fatalError ( "syntax error\n"); + bb_error_msg_and_die ( "syntax error"); if (nextarg ("(")) { args++; v = eval (); if (!nextarg (")")) - fatalError ( "syntax error\n"); + bb_error_msg_and_die ( "syntax error"); args++; return v; } if (nextarg (")")) - fatalError ( "syntax error\n"); + bb_error_msg_and_die ( "syntax error"); return str_value (*args++); } @@ -327,7 +333,7 @@ static VALUE *eval6 (void) if (nextarg ("quote")) { args++; if (!*args) - fatalError ( "syntax error\n"); + bb_error_msg_and_die ( "syntax error"); return str_value (*args++); } else if (nextarg ("length")) { @@ -354,7 +360,7 @@ static VALUE *eval6 (void) tostring (l); tostring (r); v = int_value (strcspn (l->u.s, r->u.s) + 1); - if (v->u.i == (int) strlen (l->u.s) + 1) + if (v->u.i == (arith_t) strlen (l->u.s) + 1) v->u.i = 0; freev (l); freev (r); @@ -367,15 +373,13 @@ static VALUE *eval6 (void) i2 = eval6 (); tostring (l); if (!toarith (i1) || !toarith (i2) - || i1->u.i > (int) strlen (l->u.s) + || i1->u.i > (arith_t) strlen (l->u.s) || i1->u.i <= 0 || i2->u.i <= 0) v = str_value (""); else { v = xmalloc (sizeof(VALUE)); v->type = string; - v->u.s = strncpy ((char *) xmalloc (i2->u.i + 1), - l->u.s + i1->u.i - 1, i2->u.i); - v->u.s[i2->u.i] = 0; + v->u.s = bb_xstrndup(l->u.s + i1->u.i - 1, i2->u.i); } freev (l); freev (i1); @@ -410,21 +414,22 @@ static VALUE *eval5 (void) static VALUE *eval4 (void) { VALUE *l, *r; - int (*fxn) (), val; + int op; + arith_t val; l = eval5 (); while (1) { if (nextarg ("*")) - fxn = multiply; + op = '*'; else if (nextarg ("/")) - fxn = divide; + op = '/'; else if (nextarg ("%")) - fxn = mod; + op = '%'; else return l; args++; r = eval5 (); - val = (*fxn) (l, r); + val = arithmetic_common (l, r, op); freev (l); freev (r); l = int_value (val); @@ -436,19 +441,20 @@ static VALUE *eval4 (void) static VALUE *eval3 (void) { VALUE *l, *r; - int (*fxn) (), val; + int op; + arith_t val; l = eval4 (); while (1) { if (nextarg ("+")) - fxn = plus; + op = '+'; else if (nextarg ("-")) - fxn = minus; + op = '-'; else return l; args++; r = eval4 (); - val = (*fxn) (l, r); + val = arithmetic_common (l, r, op); freev (l); freev (r); l = int_value (val); @@ -460,29 +466,30 @@ static VALUE *eval3 (void) static VALUE *eval2 (void) { VALUE *l, *r; - int (*fxn) (), val; + int op; + arith_t val; l = eval3 (); while (1) { if (nextarg ("<")) - fxn = less_than; + op = '<'; else if (nextarg ("<=")) - fxn = less_equal; + op = 'L'+'E'; else if (nextarg ("=") || nextarg ("==")) - fxn = equal; + op = '='; else if (nextarg ("!=")) - fxn = not_equal; + op = '!'; else if (nextarg (">=")) - fxn = greater_equal; + op = 'G'+'E'; else if (nextarg (">")) - fxn = greater_than; + op = '>'; else return l; args++; r = eval3 (); toarith (l); toarith (r); - val = (*fxn) (l, r); + val = cmp_common (l, r, op); freev (l); freev (r); l = int_value (val);