summaryrefslogtreecommitdiff
path: root/expr.c
diff options
context:
space:
mode:
authorJari Aalto <jari.aalto@cante.net>2004-07-27 13:29:18 +0000
committerJari Aalto <jari.aalto@cante.net>2009-09-12 16:46:56 +0000
commitb80f6443b6b7b620c7272664c66ecb0b120a0998 (patch)
tree9f71c98d8fe8fa0f41d95e1eb4227f32a09d43ca /expr.c
parent7117c2d221b2aed4ede8600f6a36b7c1454b4f55 (diff)
downloadbash-b80f6443b6b7b620c7272664c66ecb0b120a0998.tar.gz
Imported from ../bash-3.0.tar.gz.
Diffstat (limited to 'expr.c')
-rw-r--r--expr.c132
1 files changed, 93 insertions, 39 deletions
diff --git a/expr.c b/expr.c
index a4a3ae8a..a45e6a7c 100644
--- a/expr.c
+++ b/expr.c
@@ -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;
}