]> git.ipfire.org Git - thirdparty/bash.git/blobdiff - expr.c
Imported from ../bash-3.1.tar.gz.
[thirdparty/bash.git] / expr.c
diff --git a/expr.c b/expr.c
index a4a3ae8ad5aba2d86595be2794ef8c016aecf821..7f9a2f185ec30d3041949c942fca6e5403aa8c68 100644 (file)
--- 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 ();
+      val2 = exppower ();      /* exponentiation is right-associative */
       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 */
@@ -1081,7 +1135,7 @@ evalerror (msg)
    Base may be >=2 and <=64.  If base is <= 36, the numbers are drawn
    from [0-9][a-zA-Z], and lowercase and uppercase letters may be used
    interchangably.  If base is > 36 and <= 64, the numbers are drawn
-   from [0-9][a-z][A-Z]_@ (a = 10, z = 35, A = 36, Z = 61, _ = 62, @ = 63 --
+   from [0-9][a-z][A-Z]_@ (a = 10, z = 35, A = 36, Z = 61, @ = 62, _ = 63 --
    you get the picture). */
 
 static intmax_t
@@ -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,13 +1199,14 @@ strlong (num)
            c = 63;
 
          if (c >= base)
-           evalerror ("value too great for base");
+           evalerror (_("value too great for base"));
 
          val = (val * base) + c;
        }
       else
        break;
     }
+
   return (val);
 }