Imported from ../bash-2.01.tar.gz.
[platform/upstream/bash.git] / expr.c
diff --git a/expr.c b/expr.c
index eb08054..0930789 100644 (file)
--- a/expr.c
+++ b/expr.c
@@ -130,7 +130,7 @@ static int  noeval;         /* set to 1 if no assignment to be done */
 static procenv_t evalbuf;
 
 static void    readtok ();     /* lexical analyzer */
-static long    expassign (), exp0 (), exp1 (), exp2 (), exp3 (),
+static long    subexpr (), expassign (), exp0 (), exp1 (), exp2 (), exp3 (),
                exp4 (), exp5 (), expshift (), expland (), explor (),
                expband (), expbor (), expbxor (), expcond ();
 static long    strlong ();
@@ -158,8 +158,6 @@ pushexp ()
 {
   EXPR_CONTEXT *context;
 
-  context = (EXPR_CONTEXT *)xmalloc (sizeof (EXPR_CONTEXT));
-
   if (expr_depth >= MAX_EXPR_RECURSION_LEVEL)
     evalerror ("expression recursion level exceeded");
 
@@ -170,6 +168,8 @@ pushexp ()
                  * sizeof (EXPR_CONTEXT *));
     }
 
+  context = (EXPR_CONTEXT *)xmalloc (sizeof (EXPR_CONTEXT));
+
   context->curtok = curtok;
   context->lasttok = lasttok;
   context->expression = expression;
@@ -199,7 +199,11 @@ popexp ()
   free (context);
 }
 
-/* Evaluate EXPR, and return the arithmetic result.
+/* 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
+   value is returned in *VALIDP, the return value of evalexp() may
+   be used.
 
    The `while' loop after the longjmp is caught relies on the above
    implementation of pushexp and popexp leaving in expr_stack[0] the
@@ -209,49 +213,80 @@ popexp ()
    safe to let the loop terminate when expr_depth == 0, without freeing up
    any of the expr_depth[0] stuff. */
 long
-evalexp (expr)
+evalexp (expr, validp)
      char *expr;
+     int *validp;
 {
-  long val = 0L;
+  long val;
+#if 0
   procenv_t old_evalbuf;
-  char *p;
-
-  for (p = expr; p && *p && cr_whitespace (*p); p++)
-    ;
+#endif
 
-  if (p == NULL || *p == '\0')
-    return (0);
+  val = 0L;
 
+#if 0
   /* Save the value of evalbuf to protect it around possible recursive
      calls to evalexp (). */
   COPY_PROCENV (evalbuf, old_evalbuf);
+#endif
 
   if (setjmp (evalbuf))
     {
-      if (tokstr)              /* Clean up local allocation. */
-       free (tokstr);
-
-      if (expression)
-       free (expression);
+      FREE (tokstr);
+      FREE (expression);
+      tokstr = expression = (char *)NULL;
 
-      while (--expr_depth)
+      while (--expr_depth > 0)
        {
          if (expr_stack[expr_depth]->tokstr)
            free (expr_stack[expr_depth]->tokstr);
 
          if (expr_stack[expr_depth]->expression)
            free (expr_stack[expr_depth]->expression);
+
+         free (expr_stack[expr_depth]);
        }
-      jump_to_top_level (DISCARD);
+      free (expr_stack[expr_depth]);   /* free the allocated EXPR_CONTEXT */
+
+      if (validp)
+       *validp = 0;
+      return (0L);
     }
 
+  val = subexpr (expr);
+
+#if 0
+  /* Restore the value of evalbuf so that any subsequent longjmp calls
+     will have a valid location to jump to. */
+  COPY_PROCENV (old_evalbuf, evalbuf);
+#endif
+
+  if (validp)
+    *validp = 1;
+
+  return (val);
+}
+
+static long
+subexpr (expr)
+     char *expr;
+{
+  long val;
+  char *p;
+
+  for (p = expr; p && *p && cr_whitespace (*p); p++)
+    ;
+
+  if (p == NULL || *p == '\0')
+    return (0L);
+
   pushexp ();
   curtok = lasttok = 0;
   expression = savestring (expr);
   tp = expression;
 
   tokstr = (char *)NULL;
-  tokval = 0l;
+  tokval = 0L;
 
   readtok ();
 
@@ -260,18 +295,12 @@ evalexp (expr)
   if (curtok != 0)
     evalerror ("syntax error in expression");
 
-  if (tokstr)
-    free (tokstr);
-  if (expression)
-    free (expression);
+  FREE (tokstr);
+  FREE (expression);
 
   popexp ();
 
-  /* Restore the value of evalbuf so that any subsequent longjmp calls
-     will have a valid location to jump to. */
-  COPY_PROCENV (old_evalbuf, evalbuf);
-
-  return (val);
+  return val;
 }
 
 /* Bind/create a shell variable with the name LHS to the RHS.
@@ -362,6 +391,7 @@ expassign ()
              lvalue |= value;
              break;
            default:
+             free (lhs);
              evalerror ("bug: bad expassign token");
              break;
            }
@@ -373,7 +403,7 @@ expassign ()
        bind_int_variable (lhs, rhs);
       free (rhs);
       free (lhs);
-      free (tokstr);
+      FREE (tokstr);
       tokstr = (char *)NULL;           /* For freeing on errors. */
     }
   return (value);
@@ -384,6 +414,9 @@ static long
 expcond ()
 {
   long cval, val1, val2, rval;
+  int set_noeval;
+
+  set_noeval = 0;
   rval = cval = explor ();
   if (curtok == QUES)          /* found conditional expr */
     {
@@ -391,23 +424,30 @@ expcond ()
       if (curtok == 0 || curtok == COL)
        evalerror ("expression expected");
       if (cval == 0)
-       noeval++;
+       {
+         set_noeval = 1;
+         noeval++;
+       }
 #if 0
       val1 = explor ();
 #else
       val1 = expassign ();
 #endif
-      if (cval == 0)
+      if (set_noeval)
         noeval--;
       if (curtok != COL)
         evalerror ("`:' expected for conditional expression");
       readtok ();
       if (curtok == 0)
        evalerror ("expression expected");
+      set_noeval = 0;
       if (cval)
-        noeval++;
+       {
+         set_noeval = 1;
+         noeval++;
+       }
       val2 = explor ();
-      if (cval)
+      if (set_noeval)
         noeval--;
       rval = cval ? val1 : val2;
       lasttok = COND;
@@ -420,18 +460,24 @@ static long
 explor ()
 {
   register long val1, val2;
+  int set_noeval;
 
   val1 = expland ();
 
   while (curtok == LOR)
     {
-      readtok ();
+      set_noeval = 0;
       if (val1 != 0)
-       noeval++;
+       {
+         noeval++;
+         set_noeval = 1;
+       }
+      readtok ();
       val2 = expland ();
-      if (val1 != 0)
+      if (set_noeval)
        noeval--;
       val1 = val1 || val2;
+      lasttok = LOR;
     }
 
   return (val1);
@@ -442,18 +488,24 @@ static long
 expland ()
 {
   register long val1, val2;
+  int set_noeval;
 
   val1 = expbor ();
 
   while (curtok == LAND)
     {
-      readtok ();
+      set_noeval = 0;
       if (val1 == 0)
-       noeval++;
+       {
+         set_noeval = 1;
+         noeval++;
+       }
+      readtok ();
       val2 = expbor ();
-      if (val1 == 0)
+      if (set_noeval)
        noeval--;
       val1 = val1 && val2;
+      lasttok = LAND;
     }
 
   return (val1);
@@ -556,7 +608,7 @@ exp4 ()
        val1 = val1 >= val2;
       else if (op == LT)
        val1 = val1 < val2;
-      else if (op == GT)
+      else                     /* (op == GT) */
        val1 = val1 > val2;
     }
   return (val1);
@@ -762,7 +814,12 @@ readtok ()
       value = get_string_value (tokstr);
 #endif
 
-      tokval = (value && *value) ? evalexp (value) : 0;
+      tokval = (value && *value) ? subexpr (value) : 0;
+
+#if defined (ARRAY_VARS)
+      if (e == ']')
+       FREE (value);   /* get_array_value returns newly-allocated memory */
+#endif
 
       *cp = c;
       lasttok = curtok;
@@ -960,14 +1017,18 @@ main (argc, argv)
 {
   register int i;
   long v;
+  int expok;
 
   if (setjmp (top_level))
     exit (0);
 
   for (i = 1; i < argc; i++)
     {
-      v = evalexp (argv[i]);
-      printf ("'%s' -> %ld\n", argv[i], v);
+      v = evalexp (argv[i], &expok);
+      if (expok == 0)
+        fprintf (stderr, "%s: expression error\n", argv[i]);
+      else
+        printf ("'%s' -> %ld\n", argv[i], v);
     }
   exit (0);
 }