diff options
Diffstat (limited to 'expr.c')
| -rw-r--r-- | expr.c | 106 |
1 files changed, 84 insertions, 22 deletions
@@ -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 |
