diff options
author | Jari Aalto <jari.aalto@cante.net> | 2004-07-27 13:29:18 +0000 |
---|---|---|
committer | Jari Aalto <jari.aalto@cante.net> | 2009-09-12 16:46:56 +0000 |
commit | b80f6443b6b7b620c7272664c66ecb0b120a0998 (patch) | |
tree | 9f71c98d8fe8fa0f41d95e1eb4227f32a09d43ca /expr.c | |
parent | 7117c2d221b2aed4ede8600f6a36b7c1454b4f55 (diff) | |
download | bash-b80f6443b6b7b620c7272664c66ecb0b120a0998.tar.gz |
Imported from ../bash-3.0.tar.gz.
Diffstat (limited to 'expr.c')
-rw-r--r-- | expr.c | 132 |
1 files changed, 93 insertions, 39 deletions
@@ -1,6 +1,6 @@ /* expr.c -- arithmetic expression evaluation. */ -/* Copyright (C) 1990-2002 Free Software Foundation, Inc. +/* Copyright (C) 1990-2004 Free Software Foundation, Inc. This file is part of GNU Bash, the Bourne Again SHell. @@ -42,6 +42,7 @@ "||" "expr ? expr : expr" "=", "*=", "/=", "%=", "+=", "-=", "<<=", ">>=", "&=", "^=", "|=" + , [comma] (Note that most of these operators have special meaning to bash, and an entire expression should be quoted, e.g. "a=$a+1" or "a=a+1" to ensure @@ -78,6 +79,7 @@ #endif #include "chartypes.h" +#include "bashintl.h" #include "shell.h" @@ -155,6 +157,7 @@ static void evalerror __P((char *)); static void pushexp __P((void)); static void popexp __P((void)); static void expr_unwind __P((void)); +static void expr_bind_variable __P((char *, char *)); static intmax_t subexpr __P((char *)); @@ -200,6 +203,10 @@ static int expr_stack_size; /* Number of slots already allocated. */ extern char *this_command_name; extern int unbound_vars_is_error; +#if defined (ARRAY_VARS) +extern char *bash_badsub_errmsg; +#endif + #define SAVETOK(X) \ do { \ (X)->curtok = curtok; \ @@ -230,7 +237,7 @@ pushexp () EXPR_CONTEXT *context; if (expr_depth >= MAX_EXPR_RECURSION_LEVEL) - evalerror ("expression recursion level exceeded"); + evalerror (_("expression recursion level exceeded")); if (expr_depth >= expr_stack_size) { @@ -254,7 +261,7 @@ popexp () EXPR_CONTEXT *context; if (expr_depth == 0) - evalerror ("recursion stack underflow"); + evalerror (_("recursion stack underflow")); context = expr_stack[--expr_depth]; @@ -280,6 +287,14 @@ expr_unwind () free (expr_stack[expr_depth]); /* free the allocated EXPR_CONTEXT */ } +static void +expr_bind_variable (lhs, rhs) + char *lhs, *rhs; +{ + (void)bind_int_variable (lhs, rhs); + stupidly_hack_special_variables (lhs); +} + /* Evaluate EXPR, and return the arithmetic result. If VALIDP is non-null, a zero is stored into the location to which it points if the expression is invalid, non-zero otherwise. If a non-zero @@ -299,10 +314,16 @@ evalexp (expr, validp) int *validp; { intmax_t val; + int c; + procenv_t oevalbuf; val = 0; - if (setjmp (evalbuf)) + FASTCOPY (evalbuf, oevalbuf, sizeof (evalbuf)); + + c = setjmp (evalbuf); + + if (c) { FREE (tokstr); FREE (expression); @@ -320,6 +341,8 @@ evalexp (expr, validp) if (validp) *validp = 1; + FASTCOPY (oevalbuf, evalbuf, sizeof (evalbuf)); + return (val); } @@ -349,7 +372,7 @@ subexpr (expr) val = EXP_HIGHEST (); if (curtok != 0) - evalerror ("syntax error in expression"); + evalerror (_("syntax error in expression")); FREE (tokstr); FREE (expression); @@ -389,7 +412,7 @@ expassign () special = curtok == OP_ASSIGN; if (lasttok != STR) - evalerror ("attempted assignment to non-variable"); + evalerror (_("attempted assignment to non-variable")); if (special) { @@ -410,12 +433,12 @@ expassign () break; case DIV: if (value == 0) - evalerror ("division by 0"); + evalerror (_("division by 0")); lvalue /= value; break; case MOD: if (value == 0) - evalerror ("division by 0"); + evalerror (_("division by 0")); lvalue %= value; break; case PLUS: @@ -441,7 +464,7 @@ expassign () break; default: free (lhs); - evalerror ("bug: bad expassign token"); + evalerror (_("bug: bad expassign token")); break; } value = lvalue; @@ -449,7 +472,7 @@ expassign () rhs = itos (value); if (noeval == 0) - (void)bind_int_variable (lhs, rhs); + expr_bind_variable (lhs, rhs); free (rhs); free (lhs); FREE (tokstr); @@ -471,7 +494,7 @@ expcond () { readtok (); if (curtok == 0 || curtok == COL) - evalerror ("expression expected"); + evalerror (_("expression expected")); if (cval == 0) { set_noeval = 1; @@ -483,10 +506,10 @@ expcond () if (set_noeval) noeval--; if (curtok != COL) - evalerror ("`:' expected for conditional expression"); + evalerror (_("`:' expected for conditional expression")); readtok (); if (curtok == 0) - evalerror ("expression expected"); + evalerror (_("expression expected")); set_noeval = 0; if (cval) { @@ -725,7 +748,7 @@ exp2 () val2 = exppower (); if (((op == DIV) || (op == MOD)) && (val2 == 0)) - evalerror ("division by 0"); + evalerror (_("division by 0")); if (op == MUL) val1 *= val2; @@ -743,14 +766,14 @@ exppower () register intmax_t val1, val2, c; val1 = exp1 (); - if (curtok == POWER) + while (curtok == POWER) { readtok (); val2 = exp1 (); if (val2 == 0) return (1); if (val2 < 0) - evalerror ("exponent less than 0"); + evalerror (_("exponent less than 0")); for (c = 1; val2--; c *= val1) ; val1 = c; @@ -785,6 +808,7 @@ exp0 () register intmax_t val = 0, v2; char *vincdec; int stok; + EXPR_CONTEXT ec; /* XXX - might need additional logic here to decide whether or not pre-increment or pre-decrement is legal at this point. */ @@ -794,12 +818,12 @@ exp0 () readtok (); if (curtok != STR) /* readtok() catches this */ - evalerror ("identifier expected after pre-increment or pre-decrement"); + evalerror (_("identifier expected after pre-increment or pre-decrement")); v2 = tokval + ((stok == PREINC) ? 1 : -1); vincdec = itos (v2); if (noeval == 0) - (void)bind_int_variable (tokstr, vincdec); + expr_bind_variable (tokstr, vincdec); free (vincdec); val = v2; @@ -821,8 +845,8 @@ exp0 () readtok (); val = EXP_HIGHEST (); - if (curtok != RPAR) - evalerror ("missing `)'"); + if (curtok != RPAR) /* ( */ + evalerror (_("missing `)'")); /* Skip over closing paren. */ readtok (); @@ -830,23 +854,42 @@ exp0 () else if ((curtok == NUM) || (curtok == STR)) { val = tokval; - if (curtok == STR && (*tp == '+' || *tp == '-') && tp[1] == *tp && - (tp[2] == '\0' || (ISALNUM ((unsigned char)tp[2]) == 0))) + if (curtok == STR) { + SAVETOK (&ec); + tokstr = (char *)NULL; /* keep it from being freed */ + noeval = 1; + readtok (); + stok = curtok; + /* post-increment or post-decrement */ - v2 = val + ((*tp == '+') ? 1 : -1); - vincdec = itos (v2); - if (noeval == 0) - (void)bind_int_variable (tokstr, vincdec); - free (vincdec); - tp += 2; - curtok = NUM; /* make sure x++=7 is flagged as an error */ + if (stok == POSTINC || stok == POSTDEC) + { + /* restore certain portions of EC */ + tokstr = ec.tokstr; + noeval = ec.noeval; + lasttok = STR; /* ec.curtok */ + + v2 = val + ((stok == POSTINC) ? 1 : -1); + vincdec = itos (v2); + if (noeval == 0) + expr_bind_variable (tokstr, vincdec); + free (vincdec); + curtok = NUM; /* make sure x++=7 is flagged as an error */ + } + else + { + if (stok == STR) /* free new tokstr before old one is restored */ + FREE (tokstr); + RESTORETOK (&ec); + } + } readtok (); } else - evalerror ("syntax error: operand expected"); + evalerror (_("syntax error: operand expected")); return (val); } @@ -913,7 +956,7 @@ expr_streval (tok, e) static void readtok () { - register char *cp; + register char *cp, *xp; register unsigned char c, c1; register int e; @@ -959,7 +1002,7 @@ readtok () e = ']'; } else - evalerror ("bad array subscript"); + evalerror (bash_badsub_errmsg); } #endif /* ARRAY_VARS */ @@ -972,6 +1015,7 @@ readtok () tokstr = (char *)NULL; /* keep it from being freed */ tp = savecp = cp; noeval = 1; + curtok = STR; readtok (); peektok = curtok; if (peektok == STR) /* free new tokstr before old one is restored */ @@ -1041,10 +1085,20 @@ readtok () c = LOR; else if ((c == '*') && (c1 == '*')) c = POWER; - else if ((c == '-') && (c1 == '-') && legal_variable_starter ((unsigned char)*cp)) - c = PREDEC; - else if ((c == '+') && (c1 == '+') && legal_variable_starter ((unsigned char)*cp)) - c = PREINC; + else if ((c == '-' || c == '+') && c1 == c && curtok == STR) + c = (c == '-') ? POSTDEC : POSTINC; + else if ((c == '-' || c == '+') && c1 == c) + { + /* Quickly scan forward to see if this is followed by optional + whitespace and an identifier. */ + xp = cp; + while (xp && *xp && cr_whitespace (*xp)) + xp++; + if (legal_variable_starter ((unsigned char)*xp)) + c = (c == '-') ? PREDEC : PREINC; + else + cp--; /* not preinc or predec, so unget the character */ + } else if (c1 == EQ && member (c, "*/%+-&^|")) { assigntok = c; /* a OP= b */ @@ -1121,11 +1175,11 @@ strlong (num) if (c == '#') { if (foundbase) - evalerror ("bad number"); + evalerror (_("invalid number")); /* Illegal base specifications raise an evaluation error. */ if (val < 2 || val > 64) - evalerror ("illegal arithmetic base"); + evalerror (_("invalid arithmetic base")); base = val; val = 0; @@ -1145,7 +1199,7 @@ strlong (num) c = 63; if (c >= base) - evalerror ("value too great for base"); + evalerror (_("value too great for base")); val = (val * base) + c; } |