summaryrefslogtreecommitdiff
path: root/expr.c
diff options
context:
space:
mode:
Diffstat (limited to 'expr.c')
-rw-r--r--expr.c106
1 files changed, 84 insertions, 22 deletions
diff --git a/expr.c b/expr.c
index 172964a2..c51240f4 100644
--- a/expr.c
+++ b/expr.c
@@ -82,6 +82,10 @@
#include "bashintl.h"
#include "shell.h"
+#include "arrayfunc.h"
+#include "execute_cmd.h"
+#include "flags.h"
+#include "subst.h"
#include "typemax.h" /* INTMAX_MAX, INTMAX_MIN */
/* Because of the $((...)) construct, expressions may include newlines.
@@ -171,6 +175,9 @@ static intmax_t tokval; /* current token value */
static int noeval; /* set to 1 if no assignment to be done */
static procenv_t evalbuf;
+/* set to 1 if the expression has already been run through word expansion */
+static int already_expanded;
+
static struct lvalue curlval = {0, 0, 0, -1};
static struct lvalue lastlval = {0, 0, 0, -1};
@@ -217,9 +224,6 @@ static EXPR_CONTEXT **expr_stack;
static int expr_depth; /* Location in the stack. */
static int expr_stack_size; /* Number of slots already allocated. */
-extern char *this_command_name;
-extern int unbound_vars_is_error, last_command_exit_value;
-
#if defined (ARRAY_VARS)
extern const char * const bash_badsub_errmsg;
#endif
@@ -279,8 +283,13 @@ popexp ()
{
EXPR_CONTEXT *context;
- if (expr_depth == 0)
- evalerror (_("recursion stack underflow"));
+ if (expr_depth <= 0)
+ {
+ /* See the comment at the top of evalexp() for an explanation of why
+ this is done. */
+ expression = lasttp = 0;
+ evalerror (_("recursion stack underflow"));
+ }
context = expr_stack[--expr_depth];
@@ -303,7 +312,8 @@ expr_unwind ()
free (expr_stack[expr_depth]);
}
- free (expr_stack[expr_depth]); /* free the allocated EXPR_CONTEXT */
+ if (expr_depth == 0)
+ free (expr_stack[expr_depth]); /* free the allocated EXPR_CONTEXT */
noeval = 0; /* XXX */
}
@@ -313,8 +323,14 @@ expr_bind_variable (lhs, rhs)
char *lhs, *rhs;
{
SHELL_VAR *v;
+ int aflags;
- v = bind_int_variable (lhs, rhs);
+#if defined (ARRAY_VARS)
+ aflags = (assoc_expand_once && already_expanded) ? ASS_NOEXPAND : 0;
+#else
+ aflags = 0;
+#endif
+ v = bind_int_variable (lhs, rhs, aflags);
if (v && (readonly_p (v) || noassign_p (v)))
sh_longjmp (evalbuf, 1); /* variable assignment error */
stupidly_hack_special_variables (lhs);
@@ -334,7 +350,7 @@ expr_bind_array_element (tok, ind, rhs)
char ibuf[INT_STRLEN_BOUND (arrayind_t) + 1], *istr;
istr = fmtumax (ind, 10, ibuf, sizeof (ibuf), 0);
- vname = array_variable_name (tok, (char **)NULL, (int *)NULL);
+ vname = array_variable_name (tok, 0, (char **)NULL, (int *)NULL);
llen = strlen (vname) + sizeof (ibuf) + 3;
lhs = xmalloc (llen);
@@ -362,8 +378,9 @@ expr_bind_array_element (tok, ind, rhs)
safe to let the loop terminate when expr_depth == 0, without freeing up
any of the expr_depth[0] stuff. */
intmax_t
-evalexp (expr, validp)
+evalexp (expr, flags, validp)
char *expr;
+ int flags;
int *validp;
{
intmax_t val;
@@ -372,6 +389,7 @@ evalexp (expr, validp)
val = 0;
noeval = 0;
+ already_expanded = (flags&EXP_EXPANDED);
FASTCOPY (evalbuf, oevalbuf, sizeof (evalbuf));
@@ -384,6 +402,10 @@ evalexp (expr, validp)
tokstr = expression = (char *)NULL;
expr_unwind ();
+ expr_depth = 0; /* XXX - make sure */
+
+ /* We copy in case we've called evalexp recursively */
+ FASTCOPY (oevalbuf, evalbuf, sizeof (evalbuf));
if (validp)
*validp = 0;
@@ -480,6 +502,9 @@ expassign ()
lvalue = value;
}
+ if (tokstr == 0)
+ evalerror (_("syntax error in variable assignment"));
+
/* XXX - watch out for pointer aliasing issues here */
lhs = savestring (tokstr);
/* save ind in case rhs is string var and evaluation overwrites it */
@@ -1093,19 +1118,28 @@ expr_streval (tok, e, lvalue)
SHELL_VAR *v;
char *value;
intmax_t tval;
+ int initial_depth;
#if defined (ARRAY_VARS)
arrayind_t ind;
+ int tflag, aflag;
#endif
-/*itrace("expr_streval: %s: noeval = %d", tok, noeval);*/
+/*itrace("expr_streval: %s: noeval = %d expanded=%d", tok, noeval, already_expanded);*/
/* If we are suppressing evaluation, just short-circuit here instead of
going through the rest of the evaluator. */
if (noeval)
return (0);
+ initial_depth = expr_depth;
+
+#if defined (ARRAY_VARS)
+ tflag = assoc_expand_once && already_expanded; /* for a start */
+#endif
+
/* [[[[[ */
#if defined (ARRAY_VARS)
- v = (e == ']') ? array_variable_part (tok, (char **)0, (int *)0) : find_variable (tok);
+ aflag = (tflag) ? AV_NOEXPAND : 0;
+ v = (e == ']') ? array_variable_part (tok, tflag, (char **)0, (int *)0) : find_variable (tok);
#else
v = find_variable (tok);
#endif
@@ -1113,7 +1147,7 @@ expr_streval (tok, e, lvalue)
if ((v == 0 || invisible_p (v)) && unbound_vars_is_error)
{
#if defined (ARRAY_VARS)
- value = (e == ']') ? array_variable_name (tok, (char **)0, (int *)0) : tok;
+ value = (e == ']') ? array_variable_name (tok, tflag, (char **)0, (int *)0) : tok;
#else
value = tok;
#endif
@@ -1141,15 +1175,23 @@ expr_streval (tok, e, lvalue)
#if defined (ARRAY_VARS)
ind = -1;
- /* Second argument of 0 to get_array_value means that we don't allow
- references like array[@]. In this case, get_array_value is just
- like get_variable_value in that it does not return newly-allocated
- memory or quote the results. */
- value = (e == ']') ? get_array_value (tok, 0, (int *)NULL, &ind) : get_variable_value (v);
+ /* If the second argument to get_array_value doesn't include AV_ALLOWALL,
+ we don't allow references like array[@]. In this case, get_array_value
+ is just like get_variable_value in that it does not return newly-allocated
+ memory or quote the results. AFLAG is set above and is either AV_NOEXPAND
+ or 0. */
+ value = (e == ']') ? get_array_value (tok, aflag, (int *)NULL, &ind) : get_variable_value (v);
#else
value = get_variable_value (v);
#endif
+ if (expr_depth < initial_depth)
+ {
+ if (no_longjmp_on_fatal_error && interactive_shell)
+ sh_longjmp (evalbuf, 1);
+ return (0);
+ }
+
tval = (value && *value) ? subexpr (value) : 0;
if (lvalue)
@@ -1270,7 +1312,7 @@ readtok ()
#if defined (ARRAY_VARS)
if (c == '[')
{
- e = skipsubscript (cp, 0, 0);
+ e = skipsubscript (cp, 0, 1); /* XXX - arg 3 was 0 */
if (cp[e] == ']')
{
cp += e + 1;
@@ -1371,6 +1413,14 @@ readtok ()
c = POWER;
else if ((c == '-' || c == '+') && c1 == c && curtok == STR)
c = (c == '-') ? POSTDEC : POSTINC;
+ else if ((c == '-' || c == '+') && c1 == c && curtok == NUM && (lasttok == PREINC || lasttok == PREDEC))
+ {
+ /* This catches something like --FOO++ */
+ if (c == '-')
+ evalerror ("--: assignment requires lvalue");
+ else
+ evalerror ("++: assignment requires lvalue");
+ }
else if ((c == '-' || c == '+') && c1 == c)
{
/* Quickly scan forward to see if this is followed by optional
@@ -1381,7 +1431,19 @@ readtok ()
if (legal_variable_starter ((unsigned char)*xp))
c = (c == '-') ? PREDEC : PREINC;
else
+ /* Could force parsing as preinc or predec and throw an error */
+#if 0
+ {
+ /* bash-5.0 */
+ /* This catches something like --4++ */
+ if (c == '-')
+ evalerror ("--: assignment requires lvalue");
+ else
+ evalerror ("++: assignment requires lvalue");
+ }
+#else
cp--; /* not preinc or predec, so unget the character */
+#endif
}
else if (c1 == EQ && member (c, "*/%+-&^|"))
{
@@ -1417,11 +1479,11 @@ evalerror (msg)
char *name, *t;
name = this_command_name;
- for (t = expression; whitespace (*t); t++)
+ for (t = expression; t && whitespace (*t); t++)
;
internal_error (_("%s%s%s: %s (error token is \"%s\")"),
- name ? name : "", name ? ": " : "", t,
- msg, (lasttp && *lasttp) ? lasttp : "");
+ name ? name : "", name ? ": " : "",
+ t ? t : "", msg, (lasttp && *lasttp) ? lasttp : "");
sh_longjmp (evalbuf, 1);
}
@@ -1544,7 +1606,7 @@ main (argc, argv)
for (i = 1; i < argc; i++)
{
- v = evalexp (argv[i], &expok);
+ v = evalexp (argv[i], 0, &expok);
if (expok == 0)
fprintf (stderr, _("%s: expression error\n"), argv[i]);
else