X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=coreutils%2Fexpr.c;h=51e553dc6baaab5a21e30b9df937815f6d5085d7;hb=e31f721e140a7bb2377f1c1b09715f1bcbf9ec7a;hp=e5816371ad4d174ff8d1c6511a41726d586a5ba1;hpb=c7bda1ce659294d6e22c06e087f6f265983c7578;p=oweals%2Fbusybox.git diff --git a/coreutils/expr.c b/coreutils/expr.c index e5816371a..51e553dc6 100644 --- a/coreutils/expr.c +++ b/coreutils/expr.c @@ -7,26 +7,15 @@ * * Busybox modifications * Copyright (c) 2000 Edward Betts . - * Aug 2003 Vladimir Oleynik - reduced 464 bytes. - * - * 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. - * - * 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 + * Copyright (C) 2003-2005 Vladimir Oleynik + * - reduced 464 bytes. + * - 64 math support * + * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. */ /* 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. * @@ -36,14 +25,8 @@ /* no getopt needed */ -#include -#include -#include -#include -#include -#include #include "busybox.h" - +#include "xregex.h" /* The kinds of value we can have. */ enum valtype { @@ -52,11 +35,27 @@ 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 + +/* TODO: use bb_strtol[l]? It's easier to check for errors... */ + /* A value is.... */ struct valinfo { TYPE type; /* Which kind. */ union { /* The value itself. */ - int i; + arith_t i; char *s; } u; }; @@ -65,17 +64,17 @@ typedef struct valinfo VALUE; /* The arguments given to the program, minus the program name. */ static char **args; -static VALUE *docolon (VALUE *sv, VALUE *pv); -static VALUE *eval (void); -static VALUE *int_value (int i); -static VALUE *str_value (char *s); -static int nextarg (char *str); -static int null (VALUE *v); -static int toarith (VALUE *v); -static void freev (VALUE *v); -static void tostring (VALUE *v); - -int expr_main (int argc, char **argv) +static VALUE *docolon(VALUE * sv, VALUE * pv); +static VALUE *eval(void); +static VALUE *int_value(arith_t i); +static VALUE *str_value(char *s); +static int nextarg(char *str); +static int null(VALUE * v); +static int toarith(VALUE * v); +static void freev(VALUE * v); +static void tostring(VALUE * v); + +int expr_main(int argc, char **argv) { VALUE *v; @@ -85,25 +84,25 @@ int expr_main (int argc, char **argv) args = argv + 1; - v = eval (); + v = eval(); if (*args) - bb_error_msg_and_die ("syntax error"); + bb_error_msg_and_die("syntax error"); if (v->type == integer) - printf ("%d\n", v->u.i); + printf("%" PF_REZ "d\n", PF_REZ_TYPE v->u.i); else - puts (v->u.s); + puts(v->u.s); - exit (null (v)); + fflush_stdout_and_exit(null(v)); } /* Return a VALUE for I. */ -static VALUE *int_value (int i) +static VALUE *int_value(arith_t i) { VALUE *v; - v = xmalloc (sizeof(VALUE)); + v = xmalloc(sizeof(VALUE)); v->type = integer; v->u.i = i; return v; @@ -111,61 +110,59 @@ static VALUE *int_value (int i) /* Return a VALUE for S. */ -static VALUE *str_value (char *s) +static VALUE *str_value(char *s) { VALUE *v; - v = xmalloc (sizeof(VALUE)); + v = xmalloc(sizeof(VALUE)); v->type = string; - v->u.s = bb_xstrdup (s); + v->u.s = xstrdup(s); return v; } /* Free VALUE V, including structure components. */ -static void freev (VALUE *v) +static void freev(VALUE * v) { if (v->type == string) - free (v->u.s); - free (v); + free(v->u.s); + free(v); } /* Return nonzero if V is a null-string or zero-number. */ -static int null (VALUE *v) +static int null(VALUE * v) { - switch (v->type) { - case integer: - return v->u.i == 0; - default: /* string: */ - return v->u.s[0] == '\0' || strcmp (v->u.s, "0") == 0; - } + if (v->type == integer) + return v->u.i == 0; + else /* string: */ + return v->u.s[0] == '\0' || LONE_CHAR(v->u.s, '0'); } /* Coerce V to a string value (can't fail). */ -static void tostring (VALUE *v) +static void tostring(VALUE * v) { if (v->type == integer) { - bb_xasprintf (&(v->u.s), "%d", v->u.i); + v->u.s = xasprintf("%" PF_REZ "d", PF_REZ_TYPE v->u.i); v->type = string; } } /* Coerce V to an integer value. Return 1 on success, 0 on failure. */ -static int toarith (VALUE *v) +static int toarith(VALUE * v) { - if(v->type == string) { - int i; + 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 = (int) strtol(v->u.s, &e, 10); + i = STRTOL(v->u.s, &e, 10); if ((v->u.s == e) || *e) return 0; - free (v->u.s); + free(v->u.s); v->u.i = i; v->type = integer; } @@ -175,228 +172,207 @@ static int toarith (VALUE *v) /* Return nonzero if the next token matches STR exactly. STR must not be NULL. */ -static int -nextarg (char *str) +static int nextarg(char *str) { if (*args == NULL) return 0; - return strcmp (*args, str) == 0; + return strcmp(*args, str) == 0; } /* The comparison operator handling functions. */ -static int cmp_common (VALUE *l, VALUE *r, int op) +static int cmp_common(VALUE * l, VALUE * r, int op) { int cmpval; if (l->type == string || r->type == string) { - tostring (l); - tostring (r); - cmpval = strcmp (l->u.s, r->u.s); - } - else + 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; - } + if (op == '<') + return cmpval < 0; + else if (op == ('L' + 'E')) + return cmpval <= 0; + else if (op == '=') + return cmpval == 0; + else if (op == '!') + return cmpval != 0; + else if (op == '>') + return cmpval > 0; + else /* >= */ + return cmpval >= 0; } /* The arithmetic operator handling functions. */ -static int arithmetic_common (VALUE *l, VALUE *r, int op) +static arith_t arithmetic_common(VALUE * l, VALUE * r, int op) { - int 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 '+': + 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"); + if (op == '+') return li + ri; - case '-': + else if (op == '-') return li - ri; - case '*': + else if (op == '*') return li * ri; - case '/': + else if (op == '/') return li / ri; - default: + else return li % ri; - } } /* Do the : operator. SV is the VALUE for the lhs (the string), PV is the VALUE for the rhs (the pattern). */ -static VALUE *docolon (VALUE *sv, VALUE *pv) +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); + tostring(sv); + tostring(pv); if (pv->u.s[0] == '^') { - fprintf (stderr, "\ + fprintf(stderr, "\ warning: unportable BRE: `%s': using `^' as the first character\n\ -of a basic regular expression is not portable; it is being ignored", - pv->u.s); +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) { - bb_error_msg_and_die("%s", errmsg); - } + memset(&re_buffer, 0, sizeof(re_buffer)); + memset(re_regs, 0, sizeof(*re_regs)); + if (regcomp(&re_buffer, pv->u.s, 0) != 0) + bb_error_msg_and_die("invalid regular expression"); - len = re_match (&re_buffer, sv->u.s, strlen (sv->u.s), 0, &re_regs); - if (len >= 0) { + /* 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]); - } - else - v = int_value (len); - } - else { + 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(re_regs[0].rm_eo); + } else { /* Match failed -- return the right kind of null. */ if (re_buffer.re_nsub > 0) - v = str_value (""); + v = str_value(""); else - v = int_value (0); + v = int_value(0); } - free (re_buffer.buffer); return v; } /* Handle bare operands and ( expr ) syntax. */ -static VALUE *eval7 (void) +static VALUE *eval7(void) { VALUE *v; if (!*args) - bb_error_msg_and_die ( "syntax error"); + bb_error_msg_and_die("syntax error"); - if (nextarg ("(")) { + if (nextarg("(")) { args++; - v = eval (); - if (!nextarg (")")) - bb_error_msg_and_die ( "syntax error"); - args++; - return v; - } + v = eval(); + if (!nextarg(")")) + bb_error_msg_and_die("syntax error"); + args++; + return v; + } - if (nextarg (")")) - bb_error_msg_and_die ( "syntax error"); + if (nextarg(")")) + bb_error_msg_and_die("syntax error"); - return str_value (*args++); + return str_value(*args++); } /* Handle match, substr, index, length, and quote keywords. */ -static VALUE *eval6 (void) +static VALUE *eval6(void) { VALUE *l, *r, *v, *i1, *i2; - if (nextarg ("quote")) { + if (nextarg("quote")) { args++; if (!*args) - bb_error_msg_and_die ( "syntax error"); - return str_value (*args++); - } - else if (nextarg ("length")) { + bb_error_msg_and_die("syntax error"); + return str_value(*args++); + } else if (nextarg("length")) { args++; - r = eval6 (); - tostring (r); - v = int_value (strlen (r->u.s)); - freev (r); + r = eval6(); + tostring(r); + v = int_value(strlen(r->u.s)); + freev(r); return v; - } - else if (nextarg ("match")) { + } else if (nextarg("match")) { args++; - l = eval6 (); - r = eval6 (); - v = docolon (l, r); - freev (l); - freev (r); + l = eval6(); + r = eval6(); + v = docolon(l, r); + freev(l); + freev(r); return v; - } - else if (nextarg ("index")) { + } else if (nextarg("index")) { args++; - l = eval6 (); - r = eval6 (); - 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) + l = eval6(); + r = eval6(); + tostring(l); + tostring(r); + v = int_value(strcspn(l->u.s, r->u.s) + 1); + if (v->u.i == (arith_t) strlen(l->u.s) + 1) v->u.i = 0; - freev (l); - freev (r); + freev(l); + freev(r); return v; - } - else if (nextarg ("substr")) { + } else if (nextarg("substr")) { args++; - l = eval6 (); - i1 = eval6 (); - i2 = eval6 (); - tostring (l); - if (!toarith (i1) || !toarith (i2) - || i1->u.i > (int) strlen (l->u.s) + l = eval6(); + i1 = eval6(); + i2 = eval6(); + tostring(l); + if (!toarith(i1) || !toarith(i2) + || i1->u.i > (arith_t) strlen(l->u.s) || i1->u.i <= 0 || i2->u.i <= 0) - v = str_value (""); + v = str_value(""); else { - v = xmalloc (sizeof(VALUE)); + v = xmalloc(sizeof(VALUE)); v->type = string; - v->u.s = bb_xstrndup(l->u.s + i1->u.i - 1, i2->u.i); + v->u.s = xstrndup(l->u.s + i1->u.i - 1, i2->u.i); } - freev (l); - freev (i1); - freev (i2); + freev(l); + freev(i1); + freev(i2); return v; - } - else - return eval7 (); + } else + return eval7(); } /* Handle : operator (pattern matching). Calls docolon to do the real work. */ -static VALUE *eval5 (void) +static VALUE *eval5(void) { VALUE *l, *r, *v; - l = eval6 (); - while (nextarg (":")) { + l = eval6(); + while (nextarg(":")) { args++; - r = eval6 (); - v = docolon (l, r); - freev (l); - freev (r); + r = eval6(); + v = docolon(l, r); + freev(l); + freev(r); l = v; } return l; @@ -404,125 +380,126 @@ static VALUE *eval5 (void) /* Handle *, /, % operators. */ -static VALUE *eval4 (void) +static VALUE *eval4(void) { VALUE *l, *r; - int op, val; + int op; + arith_t val; - l = eval5 (); + l = eval5(); while (1) { - if (nextarg ("*")) + if (nextarg("*")) op = '*'; - else if (nextarg ("/")) + else if (nextarg("/")) op = '/'; - else if (nextarg ("%")) + else if (nextarg("%")) op = '%'; else return l; args++; - r = eval5 (); - val = arithmetic_common (l, r, op); - freev (l); - freev (r); - l = int_value (val); + r = eval5(); + val = arithmetic_common(l, r, op); + freev(l); + freev(r); + l = int_value(val); } } /* Handle +, - operators. */ -static VALUE *eval3 (void) +static VALUE *eval3(void) { VALUE *l, *r; - int op, val; + int op; + arith_t val; - l = eval4 (); + l = eval4(); while (1) { - if (nextarg ("+")) + if (nextarg("+")) op = '+'; - else if (nextarg ("-")) + else if (nextarg("-")) op = '-'; else return l; args++; - r = eval4 (); - val = arithmetic_common (l, r, op); - freev (l); - freev (r); - l = int_value (val); + r = eval4(); + val = arithmetic_common(l, r, op); + freev(l); + freev(r); + l = int_value(val); } } /* Handle comparisons. */ -static VALUE *eval2 (void) +static VALUE *eval2(void) { VALUE *l, *r; - int op, val; + int op; + arith_t val; - l = eval3 (); + l = eval3(); while (1) { - if (nextarg ("<")) + if (nextarg("<")) op = '<'; - else if (nextarg ("<=")) - op = 'L'+'E'; - else if (nextarg ("=") || nextarg ("==")) + else if (nextarg("<=")) + op = 'L' + 'E'; + else if (nextarg("=") || nextarg("==")) op = '='; - else if (nextarg ("!=")) + else if (nextarg("!=")) op = '!'; - else if (nextarg (">=")) - op = 'G'+'E'; - else if (nextarg (">")) + else if (nextarg(">=")) + op = 'G' + 'E'; + else if (nextarg(">")) op = '>'; else return l; args++; - r = eval3 (); - toarith (l); - toarith (r); - val = cmp_common (l, r, op); - freev (l); - freev (r); - l = int_value (val); + r = eval3(); + toarith(l); + toarith(r); + val = cmp_common(l, r, op); + freev(l); + freev(r); + l = int_value(val); } } /* Handle &. */ -static VALUE *eval1 (void) +static VALUE *eval1(void) { VALUE *l, *r; - l = eval2 (); - while (nextarg ("&")) { + l = eval2(); + while (nextarg("&")) { args++; - r = eval2 (); - if (null (l) || null (r)) { - freev (l); - freev (r); - l = int_value (0); - } - else - freev (r); + r = eval2(); + if (null(l) || null(r)) { + freev(l); + freev(r); + l = int_value(0); + } else + freev(r); } return l; } /* Handle |. */ -static VALUE *eval (void) +static VALUE *eval(void) { VALUE *l, *r; - l = eval1 (); - while (nextarg ("|")) { + l = eval1(); + while (nextarg("|")) { args++; - r = eval1 (); - if (null (l)) { - freev (l); + r = eval1(); + if (null(l)) { + freev(l); l = r; - } - else - freev (r); + } else + freev(r); } return l; }