first set of changes to eliminate array subscript double expansion in math contexts

This commit is contained in:
Chet Ramey
2021-05-07 10:56:24 -04:00
parent 59c575fd91
commit 35bc7025c1
22 changed files with 797 additions and 77 deletions
+57
View File
@@ -10151,3 +10151,60 @@ builtins/read.def
builtins/mapfile.def
- mapfile: call zsyncfd before calling the callback. Suggested by
Koichi Murase <myoga.murase@gmail.com>; we'll see how it goes
5/5
---
subst.h
- expand_subscript_string: extern declaration
{arrayfunc,subst}.c
- expand_subscript_string: replace expand_assignment_string_to_string
with calls to this when expanding array subscripts
subst.c
- cond_expand_word: call expand_word_internal with Q_ARITH if `special'
says we should quote for an arithmetic expression context
- expand_word_internal: call expand_array_subscript when we see `[' in
arithmetic or array subscript contexts, make conditional on the
compatibility level later
- expand_word_internal: make sure W_ARRAYREF makes it through this
function and into the returned word
5/6
---
arrayfunc.c
- array_expand_index: call evalexp with a flag of 0 since we call
expand_arith_string with Q_ARITH and we want evalexp to remove
the quotes
execute_cmd.c
- eval_arith_for_expr,execute_arith_command: now that Q_ARITH has an
effect on array subscripts (it quotes the special expansion
characters), call evalexp with 0 as the flags arg so quote removal
is performed on this quoted argument. Make this conditional on the
shell compatibility level later
- execute_cond_command: make sure to expand the argument to -v by
calling cond_expand_node with Q_ARITH, and correspondingly turn off
assoc_expand_once when calling unary_test with that argument, since
we want it to be expanded again to remove the quotes
- execute_cond_command: expand the arguments to the arithmetic operators
with Q_ARITH and pass TEST_ARITHEXP to binary_test to ensure that
it lets evalexp expand the arguments to remove the quoting
test.c
- arithcomp: if TEST_ARITHEXP is in FLAGS, call evalexp with a flag
if 0 to force evalexp to expand the arguments to remove the quoting
subst.c
- param_expand: since we call expand_arith_string with Q_ARITH, we need
to call evalexp with 0 instead of EXP_EXPANDED for $((...)) expansion
- expand_word_internal: if we recursively call expand_word_internal to
expand the contents of a double-quoted string, make sure we pass
through Q_ARITH if it appears in QUOTED
- verify_substring_values: call expand_arith_string with Q_ARITH and
correspondingly call evalexp with 0 instead of EXP_EXPANDED
execute_cmd.c
- execute_cond_node: if -v is the operator, and the operand is a valid
array reference, pass TEST_ARRAYEXP flag to unary_test
+8
View File
@@ -948,6 +948,7 @@ tests/assoc9.sub f
tests/assoc10.sub f
tests/assoc11.sub f
tests/assoc12.sub f
tests/assoc13.sub f
tests/attr.tests f
tests/attr.right f
tests/attr1.sub f
@@ -1307,6 +1308,11 @@ tests/quote1.sub f
tests/quote2.sub f
tests/quote3.sub f
tests/quote4.sub f
tests/quotearray.right f
tests/quotearray.tests f
tests/quotearray1.sub f
tests/quotearray2.sub f
tests/quotearray3.sub f
tests/read.tests f
tests/read.right f
tests/read1.sub f
@@ -1316,6 +1322,7 @@ tests/read4.sub f
tests/read5.sub f
tests/read6.sub f
tests/read7.sub f
tests/read8.sub f
tests/redir.tests f
tests/redir.right f
tests/redir1.sub f
@@ -1408,6 +1415,7 @@ tests/run-precedence f
tests/run-printf f
tests/run-procsub f
tests/run-quote f
tests/run-quotearray f
tests/run-read f
tests/run-redir f
tests/run-rhs-exp f
+17 -12
View File
@@ -374,7 +374,7 @@ assign_array_element_internal (entry, name, vname, sub, sublen, value, flags)
{
sub[sublen-1] = '\0';
if ((flags & ASS_NOEXPAND) == 0)
akey = expand_assignment_string_to_string (sub, 0); /* [ */
akey = expand_subscript_string (sub, 0); /* [ */
else
akey = savestring (sub);
sub[sublen-1] = ']';
@@ -579,7 +579,7 @@ assign_assoc_from_kvlist (var, nlist, h, flags)
if (list->next)
list = list->next;
akey = expand_assignment_string_to_string (k, 0);
akey = expand_subscript_string (k, 0);
if (akey == 0 || *akey == 0)
{
err_badarraysub (k);
@@ -587,7 +587,7 @@ assign_assoc_from_kvlist (var, nlist, h, flags)
continue;
}
aval = expand_assignment_string_to_string (v, 0);
aval = expand_subscript_string (v, 0);
if (aval == 0)
{
aval = (char *)xmalloc (1);
@@ -614,7 +614,7 @@ expand_and_quote_kvpair_word (w)
{
char *t, *r;
t = w ? expand_assignment_string_to_string (w, 0) : 0;
t = w ? expand_subscript_string (w, 0) : 0;
r = sh_single_quote (t ? t : "");
free (t);
return r;
@@ -740,7 +740,7 @@ assign_compound_array_list (var, nlist, flags)
{
/* This is not performed above, see expand_compound_array_assignment */
w[len] = '\0'; /*[*/
akey = expand_assignment_string_to_string (w+1, 0);
akey = expand_subscript_string (w+1, 0);
w[len] = ']';
/* And we need to expand the value also, see below */
if (akey == 0 || *akey == 0)
@@ -776,7 +776,7 @@ assign_compound_array_list (var, nlist, flags)
/* See above; we need to expand the value here */
if (assoc_p (var))
{
val = expand_assignment_string_to_string (val, 0);
val = expand_subscript_string (val, 0);
if (val == 0)
{
val = (char *)xmalloc (1);
@@ -938,7 +938,7 @@ expand_and_quote_assoc_word (w, type)
return (sh_single_quote (w));
w[ind] = '\0';
t = expand_assignment_string_to_string (w+1, 0);
t = expand_subscript_string (w+1, 0);
w[ind] = RBRACK;
key = sh_single_quote (t ? t : "");
free (t);
@@ -954,7 +954,7 @@ expand_and_quote_assoc_word (w, type)
nword[i++] = w[ind++];
nword[i++] = w[ind++];
t = expand_assignment_string_to_string (w+ind, 0);
t = expand_subscript_string (w+ind, 0);
value = sh_single_quote (t ? t : "");
free (t);
nword = xrealloc (nword, wlen + 5 + STRLEN (value));
@@ -1070,7 +1070,7 @@ unbind_array_element (var, sub, flags)
if (assoc_p (var))
{
akey = (flags & VA_NOEXPAND) ? sub : expand_assignment_string_to_string (sub, 0);
akey = (flags & VA_NOEXPAND) ? sub : expand_subscript_string (sub, 0);
if (akey == 0 || *akey == 0)
{
builtin_error ("[%s]: %s", sub, _(bash_badsub_errmsg));
@@ -1218,7 +1218,7 @@ array_expand_index (var, s, len, flags)
int flags;
{
char *exp, *t, *savecmd;
int expok;
int expok, eflag;
arrayind_t val;
exp = (char *)xmalloc (len);
@@ -1234,7 +1234,12 @@ array_expand_index (var, s, len, flags)
#endif
savecmd = this_command_name;
this_command_name = (char *)NULL;
val = evalexp (t, EXP_EXPANDED, &expok); /* XXX - was 0 but we expanded exp already */
#if 0 /* TAG:bash-5.2 */
eflag = (shell_compatibility_level > 51) ? 0 : EXP_EXPANDED;
#else
eflag = 0;
#endif
val = evalexp (t, eflag, &expok); /* XXX - was 0 but we expanded exp already */
this_command_name = savecmd;
if (t != exp)
free (t);
@@ -1435,7 +1440,7 @@ array_value_internal (s, quoted, flags, rtype, indp)
{
t[len - 1] = '\0';
if ((flags & AV_NOEXPAND) == 0)
akey = expand_assignment_string_to_string (t, 0); /* [ */
akey = expand_subscript_string (t, 0); /* [ */
else
akey = savestring (t);
t[len - 1] = ']';
+6 -4
View File
@@ -5,12 +5,12 @@
.\" Case Western Reserve University
.\" chet.ramey@case.edu
.\"
.\" Last Change: Wed Apr 28 14:35:46 EDT 2021
.\" Last Change: Wed May 5 16:28:46 EDT 2021
.\"
.\" bash_builtins, strip all but Built-Ins section
.if \n(zZ=1 .ig zZ
.if \n(zY=1 .ig zY
.TH BASH 1 "2021 April 28" "GNU Bash 5.1"
.TH BASH 1 "2021 May 5" "GNU Bash 5.1"
.\"
.\" There's some problem with having a `@'
.\" in a tagged paragraph with the BSD man macros.
@@ -700,8 +700,10 @@ below under
.SM
.BR "ARITHMETIC EVALUATION" .
If the value of the expression is non-zero, the return status is 0;
otherwise the return status is 1. This is exactly equivalent to
\fBlet "\fIexpression\fP"\fR.
otherwise the return status is 1.
The \fIexpression\fP is expanded as if it were within double quotes,
but double quote characters in \fIexpression\fP are not special and
are removed.
.TP
\fB[[\fP \fIexpression\fP \fB]]\fP
Return a status of 0 or 1 depending on the evaluation of
+5 -6
View File
@@ -1126,13 +1126,12 @@ done
The arithmetic @var{expression} is evaluated according to the rules
described below (@pxref{Shell Arithmetic}).
The @var{expression} is expanded as if it were within double quotes,
but double quote characters in @var{expression} are not special and
are removed.
If the value of the expression is non-zero, the return status is 0;
otherwise the return status is 1. This is exactly equivalent to
@example
let "@var{expression}"
@end example
@noindent
@xref{Bash Builtins}, for a full description of the @code{let} builtin.
otherwise the return status is 1.
@item [[@dots{}]]
@rwindex [[
+3 -3
View File
@@ -2,10 +2,10 @@
Copyright (C) 1988-2021 Free Software Foundation, Inc.
@end ignore
@set LASTCHANGE Wed Mar 31 11:53:05 EDT 2021
@set LASTCHANGE Wed May 5 16:29:06 EDT 2021
@set EDITION 5.1
@set VERSION 5.1
@set UPDATED 31 March 2021
@set UPDATED-MONTH March 2021
@set UPDATED 5 May 2021
@set UPDATED-MONTH May 2021
+54 -17
View File
@@ -3010,7 +3010,7 @@ eval_arith_for_expr (l, okp)
{
WORD_LIST *new;
intmax_t expresult;
int r;
int r, eflag;
char *expr, *temp;
expr = l->next ? string_list (l) : l->word->word;
@@ -3037,9 +3037,15 @@ eval_arith_for_expr (l, okp)
r = run_debug_trap ();
/* In debugging mode, if the DEBUG trap returns a non-zero status, we
skip the command. */
#if 0 /* TAG:bash-5.2 */
eflag = (shell_compatibility_level > 51) ? 0 : EXP_EXPANDED;
#else
eflag = 0;
#endif
#if defined (DEBUGGER)
if (debugging_mode == 0 || r == EXECUTION_SUCCESS)
expresult = evalexp (new->word->word, EXP_EXPANDED, okp);
expresult = evalexp (new->word->word, eflag, okp);
else
{
expresult = 0;
@@ -3047,7 +3053,7 @@ eval_arith_for_expr (l, okp)
*okp = 1;
}
#else
expresult = evalexp (new->word->word, EXP_EXPANDED, okp);
expresult = evalexp (new->word->word, eflag, okp);
#endif
dispose_words (new);
}
@@ -3744,7 +3750,7 @@ static int
execute_arith_command (arith_command)
ARITH_COM *arith_command;
{
int expok, save_line_number, retval;
int expok, save_line_number, retval, eflag;
intmax_t expresult;
WORD_LIST *new;
char *exp, *t;
@@ -3805,7 +3811,12 @@ execute_arith_command (arith_command)
if (exp)
{
expresult = evalexp (exp, EXP_EXPANDED, &expok);
#if 0 /* TAG:bash-5.2 */
eflag = (shell_compatibility_level > 51) ? 0 : EXP_EXPANDED;
#else
eflag = 0;
#endif
expresult = evalexp (exp, eflag, &expok);
line_number = save_line_number;
free (exp);
}
@@ -3831,8 +3842,8 @@ static int
execute_cond_node (cond)
COND_COM *cond;
{
int result, invert, patmatch, rmatch, mflags, ignore;
char *arg1, *arg2;
int result, invert, patmatch, rmatch, arith, mode, mflags, ignore;
char *arg1, *arg2, *op;
#if 0
char *t1, *t2;
#endif
@@ -3863,41 +3874,67 @@ execute_cond_node (cond)
}
else if (cond->type == COND_UNARY)
{
int oa, varop, varflag;
if (ignore)
comsub_ignore_return++;
arg1 = cond_expand_word (cond->left->op, 0);
varop = STREQ (cond->op->word, "-v");
#if defined (ARRAY_VARS)
varflag = (varop && valid_array_reference (cond->left->op->word, VA_NOEXPAND)) ? TEST_ARRAYEXP : 0;
#else
varflag = 0;
#endif
arg1 = cond_expand_word (cond->left->op, varop ? 3 : 0);
if (ignore)
comsub_ignore_return--;
if (arg1 == 0)
arg1 = nullstr;
if (echo_command_at_execute)
xtrace_print_cond_term (cond->type, invert, cond->op, arg1, (char *)NULL);
result = unary_test (cond->op->word, arg1) ? EXECUTION_SUCCESS : EXECUTION_FAILURE;
/* TAG:bash-5.2 fix up later with set_expand_once() */
oa = assoc_expand_once;
#if 0
if (varop && shell_compatibility_level > 51)
#else
if (varop)
#endif
assoc_expand_once = 0;
result = unary_test (cond->op->word, arg1, varflag) ? EXECUTION_SUCCESS : EXECUTION_FAILURE;
assoc_expand_once = oa;
if (arg1 != nullstr)
free (arg1);
}
else if (cond->type == COND_BINARY)
{
rmatch = 0;
patmatch = (((cond->op->word[1] == '=') && (cond->op->word[2] == '\0') &&
(cond->op->word[0] == '!' || cond->op->word[0] == '=')) ||
(cond->op->word[0] == '=' && cond->op->word[1] == '\0'));
op = cond->op->word;
mode = 0;
patmatch = (((op[1] == '=') && (op[2] == '\0') &&
(op[0] == '!' || op[0] == '=')) ||
(op[0] == '=' && op[1] == '\0'));
#if defined (COND_REGEXP)
rmatch = (cond->op->word[0] == '=' && cond->op->word[1] == '~' &&
cond->op->word[2] == '\0');
rmatch = (op[0] == '=' && op[1] == '~' && op[2] == '\0');
#endif
arith = STREQ (op, "-eq") || STREQ (op, "-ne") || STREQ (op, "-lt") ||
STREQ (op, "-le") || STREQ (op, "-gt") || STREQ (op, "-ge");
if (arith)
mode = 3;
else if (rmatch && shell_compatibility_level > 31)
mode = 2;
else if (patmatch)
mode = 1;
if (ignore)
comsub_ignore_return++;
arg1 = cond_expand_word (cond->left->op, 0);
arg1 = cond_expand_word (cond->left->op, arith ? mode : 0);
if (ignore)
comsub_ignore_return--;
if (arg1 == 0)
arg1 = nullstr;
if (ignore)
comsub_ignore_return++;
arg2 = cond_expand_word (cond->right->op,
(rmatch && shell_compatibility_level > 31) ? 2 : (patmatch ? 1 : 0));
arg2 = cond_expand_word (cond->right->op, mode);
if (ignore)
comsub_ignore_return--;
if (arg2 == 0)
+2
View File
@@ -59,6 +59,8 @@ zread (fd, buf, len)
ssize_t r;
check_signals (); /* check for signals before a blocking read */
/* should generalize into a mechanism where different parts of the shell can
`register' timeouts and have them checked here. */
while (((r = read_builtin_timeout (fd)) < 0 || (r = read (fd, buf, len)) < 0) &&
errno == EINTR)
{
+47 -17
View File
@@ -3594,7 +3594,7 @@ expand_arith_string (string, quoted)
if (EXP_CHAR (string[i]))
break;
else if (string[i] == '\'' || string[i] == '\\' || string[i] == '"')
saw_quote = 1;
saw_quote = string[i];
ADVANCE_CHAR (string, slen, i);
}
@@ -3684,7 +3684,8 @@ cond_expand_word (w, special)
expand_no_split_dollar_star = 1;
w->flags |= W_NOSPLIT2;
l = call_expand_word_internal (w, 0, 0, (int *)0, (int *)0);
qflags = (special == 3) ? Q_ARITH : 0;
l = call_expand_word_internal (w, qflags, 0, (int *)0, (int *)0);
expand_no_split_dollar_star = 0;
if (l)
{
@@ -6714,7 +6715,7 @@ array_length_reference (s)
if (assoc_p (var))
{
t[len - 1] = '\0';
akey = expand_assignment_string_to_string (t, 0); /* [ */
akey = expand_subscript_string (t, 0); /* [ */
t[len - 1] = RBRACK;
if (akey == 0 || *akey == 0)
{
@@ -7526,7 +7527,7 @@ verify_substring_values (v, value, substr, vtype, e1p, e2p)
{
char *t, *temp1, *temp2;
arrayind_t len;
int expok;
int expok, eflag;
#if defined (ARRAY_VARS)
ARRAY *a;
HASH_TABLE *h;
@@ -7539,12 +7540,14 @@ verify_substring_values (v, value, substr, vtype, e1p, e2p)
else
t = (char *)0;
temp1 = expand_arith_string (substr, Q_DOUBLE_QUOTES); /* Q_ARITH? */
#if 1 /* TAG: bash-5.2 */
*e1p = evalexp (temp1, EXP_EXPANDED, &expok);
temp1 = expand_arith_string (substr, Q_DOUBLE_QUOTES|Q_ARITH);
#if 0 /* TAG: bash-5.2 */
eflag = (shell_compatibility_level > 51) ? 0 : EXP_EXPANDED;
#else
*e1p = evalexp (temp1, 0, &expok); /* XXX - EXP_EXPANDED? */
eflag = 0;
#endif
*e1p = evalexp (temp1, eflag, &expok);
free (temp1);
if (expok == 0)
return (0);
@@ -7599,14 +7602,10 @@ verify_substring_values (v, value, substr, vtype, e1p, e2p)
{
t++;
temp2 = savestring (t);
temp1 = expand_arith_string (temp2, Q_DOUBLE_QUOTES); /* Q_ARITH? */
temp1 = expand_arith_string (temp2, Q_DOUBLE_QUOTES|Q_ARITH);
free (temp2);
t[-1] = ':';
#if 1 /* TAG: bash-5.2 */
*e2p = evalexp (temp1, EXP_EXPANDED, &expok);
#else
*e2p = evalexp (temp1, 0, &expok); /* XXX - EXP_EXPANDED? */
#endif
*e2p = evalexp (temp1, eflag, &expok);
free (temp1);
if (expok == 0)
return (0);
@@ -9574,7 +9573,7 @@ param_expand (string, sindex, quoted, expanded_something,
int *quoted_dollar_at_p, *had_quoted_null_p, pflags;
{
char *temp, *temp1, uerror[3], *savecmd;
int zindex, t_index, expok;
int zindex, t_index, expok, eflag;
unsigned char c;
intmax_t number;
SHELL_VAR *var;
@@ -9952,7 +9951,12 @@ arithsub:
/* No error messages. */
savecmd = this_command_name;
this_command_name = (char *)NULL;
number = evalexp (temp1, EXP_EXPANDED, &expok);
#if 0 /* TAG: bash-5.2 */
eflag = (shell_compatibility_level > 51) ? 0 : EXP_EXPANDED;
#else
eflag = 0;
#endif
number = evalexp (temp1, eflag, &expok);
this_command_name = savecmd;
free (temp);
free (temp1);
@@ -10435,6 +10439,26 @@ add_string:
}
#endif /* PROCESS_SUBSTITUTION */
#if defined (ARRAY_VARS)
case '[': /*]*/
#if 0 /* TAG:bash-5.2 */
if (((quoted & Q_ARITH) == 0 && (word->flags & W_ARRAYREF) == 0) || (shell_compatibility_level <= 51))
#else
if (((quoted & Q_ARITH) == 0 && (word->flags & W_ARRAYREF) == 0))
#endif
{
if (isexp == 0 && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0 && isifs (c) && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) == 0)
goto add_ifs_character;
else
goto add_character;
}
else
{
temp = expand_array_subscript (string, &sindex, quoted, word->flags);
goto add_string;
}
#endif
case '=':
/* Posix.2 section 3.6.1 says that tildes following `=' in words
which are not assignment statements are not expanded. If the
@@ -10708,6 +10732,7 @@ add_twochars:
break;
case '"':
/* XXX - revisit this */
if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) && ((quoted & Q_ARITH) == 0))
goto add_character;
@@ -10741,7 +10766,8 @@ add_twochars:
temp_has_dollar_at = 0; /* does this quoted (sub)string include $@? */
/* Need to get W_HASQUOTEDNULL flag through this function. */
list = expand_word_internal (tword, Q_DOUBLE_QUOTES, 0, &temp_has_dollar_at, (int *)NULL);
/* XXX - preserve Q_ARITH here? */
list = expand_word_internal (tword, Q_DOUBLE_QUOTES|(quoted&Q_ARITH), 0, &temp_has_dollar_at, (int *)NULL);
has_dollar_at += temp_has_dollar_at;
if (list == &expand_word_error || list == &expand_word_fatal)
@@ -11074,6 +11100,8 @@ finished_with_string:
tword->flags |= W_NOGLOB; /* XXX */
if (word->flags & W_NOBRACE)
tword->flags |= W_NOBRACE; /* XXX */
if (word->flags & W_ARRAYREF)
tword->flags |= W_ARRAYREF;
if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
tword->flags |= W_QUOTED;
list = make_word_list (tword, (WORD_LIST *)NULL);
@@ -11182,6 +11210,8 @@ set_word_flags:
tword->flags |= W_NOGLOB;
if (word->flags & W_NOBRACE)
tword->flags |= W_NOBRACE;
if (word->flags & W_ARRAYREF)
tword->flags |= W_ARRAYREF;
list = make_word_list (tword, (WORD_LIST *)NULL);
}
}
+1
View File
@@ -184,6 +184,7 @@ extern WORD_LIST *expand_string PARAMS((char *, int));
extern char *expand_string_to_string PARAMS((char *, int));
extern char *expand_string_unsplit_to_string PARAMS((char *, int));
extern char *expand_assignment_string_to_string PARAMS((char *, int));
extern char *expand_subscript_string PARAMS((char *, int));
/* Expand an arithmetic expression string */
extern char *expand_arith_string PARAMS((char *, int));
+17 -7
View File
@@ -339,12 +339,19 @@ arithcomp (s, t, op, flags)
intmax_t l, r;
int expok;
if (flags & TEST_ARITHEXP)
if (flags & TEST_ARITHEXP) /* conditional command */
{
l = evalexp (s, EXP_EXPANDED, &expok);
int eflag;
#if 0 /* TAG:bash-5.2 */
eflag = (shell_compatibility_level > 51) ? 0 : EXP_EXPANDED;
#else
eflag = 0;
#endif
l = evalexp (s, eflag, &expok);
if (expok == 0)
return (FALSE); /* should probably longjmp here */
r = evalexp (t, EXP_EXPANDED, &expok);
r = evalexp (t, eflag, &expok);
if (expok == 0)
return (FALSE); /* ditto */
}
@@ -492,13 +499,13 @@ unary_operator ()
if (legal_number (argv[pos], &r))
{
advance (0);
return (unary_test (op, argv[pos - 1]));
return (unary_test (op, argv[pos - 1], 0));
}
else
return (FALSE);
}
else
return (unary_test (op, "1"));
return (unary_test (op, "1", 0));
}
/* All of the unary operators take an argument, so we first call
@@ -506,12 +513,13 @@ unary_operator ()
argument, and then advances pos right past it. This means that
pos - 1 is the location of the argument. */
unary_advance ();
return (unary_test (op, argv[pos - 1]));
return (unary_test (op, argv[pos - 1], 0));
}
int
unary_test (op, arg)
unary_test (op, arg, flags)
char *op, *arg;
int flags;
{
intmax_t r;
struct stat stat_buf;
@@ -630,6 +638,8 @@ unary_test (op, arg)
int rtype, ret, flags;
/* Let's assume that this has already been expanded once. */
/* XXX - TAG:bash-5.2 fix with corresponding fix to execute_cmd.c:
execute_cond_node() that passes TEST_ARRAYEXP in FLAGS */
flags = assoc_expand_once ? AV_NOEXPAND : 0;
t = array_value (arg, 0, flags, &rtype, (arrayind_t *)0);
ret = t ? TRUE : FALSE;
+2 -1
View File
@@ -27,11 +27,12 @@
#define TEST_PATMATCH 0x01
#define TEST_ARITHEXP 0x02
#define TEST_LOCALE 0x04
#define TEST_ARRAYEXP 0x08 /* array subscript expansion */
extern int test_unop PARAMS((char *));
extern int test_binop PARAMS((char *));
extern int unary_test PARAMS((char *, char *));
extern int unary_test PARAMS((char *, char *, int));
extern int binary_test PARAMS((char *, char *, char *, int));
extern int test_command PARAMS((int, char **));
+7 -10
View File
@@ -520,13 +520,11 @@ argv[1] = <y>
<X> <X> <X> <X>
./array23.sub: line 22: $( echo >&2 foo ) : syntax error: operand expected (error token is "$( echo >&2 foo ) ")
./array23.sub: line 23: $( echo >&2 foo ) : syntax error: operand expected (error token is "$( echo >&2 foo ) ")
foo
0
foo
foo
foo
6
./array23.sub: line 34: $( echo >&2 foo ): syntax error: operand expected (error token is "$( echo >&2 foo )")
./array23.sub: line 24: $( echo >&2 foo ) : syntax error: operand expected (error token is "$( echo >&2 foo ) ")
./array23.sub: line 26: $( echo >&2 foo ) : syntax error: operand expected (error token is "$( echo >&2 foo ) ")
./array23.sub: line 30: $( echo >&2 foo ): syntax error: operand expected (error token is "$( echo >&2 foo )")
./array23.sub: line 33: $( echo >&2 foo ): syntax error: operand expected (error token is "$( echo >&2 foo )")
./array23.sub: line 34: $index: syntax error: operand expected (error token is "$index")
./array23.sub: line 35: $( echo >&2 foo ): syntax error: operand expected (error token is "$( echo >&2 foo )")
0
0
@@ -743,10 +741,9 @@ argv[1] = <b>
argv[2] = <a>
argv[1] = <b+a>
7
./array27.sub: line 24: a[]]=7 : syntax error: invalid arithmetic operator (error token is "]=7 ")
7
declare -A A=([$'\t']="2" [" "]="2" )
./array27.sub: line 36: ((: A[]]=2 : syntax error: invalid arithmetic operator (error token is "]=2 ")
declare -A A=([$'\t']="2" ["*"]="2" [" "]="2" ["@"]="2" )
declare -A A=([$'\t']="2" ["*"]="2" [" "]="2" ["]"]="2" ["@"]="2" )
declare -A A=([$'\t']="2" ["*"]="2" [" "]="2" ["]"]="2" ["@"]="2" )
./array27.sub: line 52: A[]]: bad array subscript
declare -A A=([$'\t']="X" ["*"]="X" [" "]="X" ["@"]="X" )
+9
View File
@@ -283,3 +283,12 @@ declare -A v3=(["1 2"]="3 4 5" ["\$xtra"]="xtra" )
declare -A v1=(["20 40 80"]="new xtra" ["1 2"]="3 4 5" )
declare -A v2=(["20 40 80"]="new xtra" ["1 2"]="3 4 5" )
declare -A v3=(["1 2"]="3 4 5" ["\$xtra"]="new xtra" )
declare -A assoc=(["*"]="star" ["!"]="bang" ["@"]="at" )
at
star
declare -A a=(["@"]="at" )
./assoc13.sub: line 22: ia[@]: bad array subscript
declare -a ia
declare -A a=(["@"]="at2" )
declare -A a=(["@"]=" string" )
declare -A a=(["*"]="star2" ["@"]="at" )
+3
View File
@@ -247,3 +247,6 @@ ${THIS_SH} ./assoc11.sub
# more kvpair associative array assignment tests
${THIS_SH} ./assoc12.sub
# assignment to @ and *
${THIS_SH} ./assoc13.sub
+44
View File
@@ -0,0 +1,44 @@
# assignment to @ and *
declare -A assoc
key=@
key2=*
assoc[$key]=at
assoc[$key2]=star
assoc[!]=bang
declare -p assoc
echo ${assoc[$key]}
echo ${assoc[$key2]}
unset assoc
declare -A a
a[@]=at
declare -p a
declare -a ia
ia[@]=garbage
declare -p ia
declare a[@]=at2
declare -p a
unset a ia
declare -A a
printf -v a[@] "%10s" string
declare -p a
unset a
declare -A a
declare a[$key2]=star
declare a[@]=at
declare a[*]=star2
declare -p a
unset a
+85
View File
@@ -0,0 +1,85 @@
declare -A assoc=(["x],b[\$(echo uname >&2)"]="1" )
declare -A assoc=(["\$key"]="1" ["x],b[\$(echo uname >&2)"]="1" )
declare -A assoc=(["\$key"]="1" ["x],b[\$(echo uname >&2)"]="2" )
./quotearray.tests: line 31: ((: 'assoc[x\],b\[\$(echo uname >&2)]++' : syntax error: operand expected (error token is "'assoc[x\],b\[\$(echo uname >&2)]++' ")
declare -A assoc=(["\$key"]="1" ["x],b[\$(echo uname >&2)"]="2" )
./quotearray.tests: line 34: ((: 'assoc[x\],b\[\$(echo uname >&2)]'++ : syntax error: operand expected (error token is "'assoc[x\],b\[\$(echo uname >&2)]'++ ")
declare -A assoc=(["\$key"]="1" ["x],b[\$(echo uname >&2)"]="2" )
declare -A assoc=(["\$key"]="1" ["x],b[\$(echo uname >&2)"]="3" )
4
klmnopqrst
klmnopqrst
klmno
klmnopqrst
declare -A A=(["\$(echo %)"]="5" [%]="10" ["]"]="10" )
declare -A A=(["~"]="42" )
42
declare -A A=(["~"]="43" )
42
declare -A A=(["~"]="43" ["~0"]="43" )
12
declare -a a=([0]="12" [1]="42")
2
2
declare -Ai assoc=(["']"]="2" ["\$var"]="1" )
105
declare -A assoc=(["\` echo >&2 foo\`"]="42" ["\$( echo >&2 bar)"]="63" )
./quotearray.tests: line 139: x],b[$(echo uname >&2): syntax error: invalid arithmetic operator (error token is "],b[$(echo uname >&2)")
./quotearray.tests: line 143: x],b[$(echo uname >&2): syntax error: invalid arithmetic operator (error token is "],b[$(echo uname >&2)")
1
./quotearray.tests: line 146: x],b[$(echo uname >&2): syntax error: invalid arithmetic operator (error token is "],b[$(echo uname >&2)")
1
./quotearray.tests: line 149: x],b[$(echo uname >&2): syntax error: invalid arithmetic operator (error token is "],b[$(echo uname >&2)")
1
./quotearray.tests: line 152: x],b[$(echo uname >&2): syntax error: invalid arithmetic operator (error token is "],b[$(echo uname >&2)")
1
declare -A assoc
0
0
1
0
0
0
declare -A assoc=(["\` echo >&2 foo\`"]="128" [0]="0" ["]"]="12" ["x],b[\$(echo uname >&2)"]="42" ["~"]="42" ["\$( echo 2>& date)"]="foo" )
foo
0
0
./quotearray1.sub: line 67: 0\],b\[1: syntax error: invalid arithmetic operator (error token is "\],b\[1")
declare -a array
0
0
0
0
1
1
declare -A aa=(["\$( echo 2>& date)"]="foo" )
foo
0
1
declare -A a=([1]="1" [0]="0" [" "]="11" )
7
7
declare -A A=([$'\t']="2" [" "]="2" )
declare -A A=([$'\t']="2" ["*"]="2" [" "]="2" ["]"]="2" ["@"]="2" )
./quotearray2.sub: line 54: read: `A[]]': not a valid identifier
declare -A A=([$'\t']="X" ["*"]="X" [" "]="X" ["@"]="X" )
./quotearray2.sub: line 62: printf: `A[]]': not a valid identifier
declare -A A=([$'\t']="X" ["*"]="X" [" "]="X" ["@"]="X" )
./quotearray2.sub: line 70: declare: `A[]]=X': not a valid identifier
declare -A A=(["*"]="X" ["@"]="X" )
./quotearray2.sub: line 78: declare: `A[]]=X': not a valid identifier
declare -A A=(["*"]="X" ["@"]="X" )
./quotearray2.sub: line 89: let: assoc[x],b[$(echo: bad array subscript (error token is "b[$(echo")
declare -A assoc
declare -A assoc=(["\$var"]="value" )
declare -A assoc=(["\$var"]="value" )
declare -A assoc=(["\$var"]="value" )
declare -A assoc=()
declare -A a=()
declare -A a=(["\$(echo foo)"]="1" )
declare -A a=()
declare -A a=(["\$(echo foo)"]="1" )
./quotearray3.sub: line 66: typeset: assoc: not found
1
./quotearray3.sub: line 71: \@: syntax error: operand expected (error token is "\@")
1
+157
View File
@@ -0,0 +1,157 @@
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# a set of tests for associative arrays in arithmetic contexts
declare -A assoc
key='x],b[$(echo uname >&2)'
(( assoc[$key]++ ))
declare -p assoc
(( assoc['$key']++ ))
declare -p assoc
(( assoc["$key"]++ ))
declare -p assoc
declare -A assoc
(( 'assoc[$key]++' ))
declare -p assoc
(( 'assoc[$key]'++ ))
declare -p assoc
(( "assoc[$key]++" ))
declare -p assoc
unset assoc
typeset -A a
b="80's"
((++a[$b]))
((++a["$b"]))
[[ $((++a[$b])) ]]
[[ $((++a["$b"])) ]]
echo ${a[$b]}
unset a
declare -A A
string=abcdefghijklmnopqrstuvwxyz
echo ${string:10:10}
k1='%'
k2='$(echo %)'
A[%]=10
A[']']=10
A[$k2]=5
k3=']'
echo ${string:A[%]:A[$k1]}
echo ${string:A[%]:A[$k2]}
echo ${string:A[%]:A[$k3]}
declare -p A
unset A string key
key='~'
declare -A A
A[$key]=42
declare -p A
echo $(( A[$key]++ ))
declare -p A
key='~0'
A[$key]=42
echo $(( A[$key]++ ))
declare -p A
declare -a a
key='~-2'
a[0]=12
a[$key]=42
echo $(( a[7<(4+2)] ))
declare -p a
unset A a key
declare -A A
declare -a a
sString="devel packager's guide"
i=2
A["$sString"]=$i
a[$i]=$sString
echo "${A[${a[i]}]}"
echo ${A["${a[i]}"]}
unset A a
#LANG=C
unset var assoc
var=\'\]
declare -Ai assoc
assoc[$var]=1
assoc[$var]+=1
((assoc['$var']++))
typeset -p assoc
unset assoc
declare -A assoc
key1='` echo >&2 foo`'
key2='$( echo >&2 bar)'
assoc[$key1]=42
assoc[$key2]=63
echo $(( assoc[$key1] + assoc[$key2] ))
declare -p assoc
unset assoc
declare -a a
key='x],b[$(echo uname >&2)'
a[$key]=42
expr='a[$key]'
(( $expr ))
echo $?
echo $(( $expr ))
echo $?
echo $(( expr ))
echo $?
(( expr ))
echo $?
${THIS_SH} ./quotearray1.sub
${THIS_SH} ./quotearray2.sub
${THIS_SH} ./quotearray3.sub
+105
View File
@@ -0,0 +1,105 @@
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# arithmetic operators for conditional commands and arithmetic commands
declare -A assoc
declare -a index
key='x],b[$(echo uname >&2)'
key1=']'
key2='` echo >&2 foo`'
key3='~'
key4='7<(4+2)'
key5='$( echo 2>& date)'
[[ -n assoc[$key] ]]
declare -p assoc
assoc[$key]=42
assoc[$key1]=12
assoc[$key2]=128
assoc[$key3]=42
assoc[0]=0
[[ assoc[$key] -eq assoc[$key] ]]
echo $?
[[ assoc[$key] -gt assoc[$key1] ]]
echo $?
[[ assoc[$key2] -lt assoc[$key] ]]
echo $?
[[ assoc[$key] -eq assoc[$key3] ]]
echo $?
[[ index[7<(4+2)] -le assoc[0] ]]
echo $?
[[ index[$key4] -le assoc[0] ]]
echo $?
assoc[$key5]=foo
declare -p assoc
echo "${assoc[$key5]}"
[[ -v assoc[$key5] ]]
echo $?
[[ -v assoc[$key] ]]
echo $?
unset assoc
declare -a array
index='0],b[1';
((array[$index]++))
declare -p array
unset array
declare -A assoc
assoc[$key]=42
assoc[$key4]=42
[[ -v assoc[$key] ]]
echo $?
[[ -v assoc["$key"] ]]
echo $?
[[ -v assoc[$key4] ]]
echo $?
[[ -v assoc["$key4"] ]]
echo $?
[[ -v assoc['$key'] ]]
echo $?
[[ -v assoc['$key4'] ]]
echo $?
declare -A aa
aa[$key5]=foo
declare -p aa
echo "${aa[$key5]}"
[[ -v aa[$key5] ]]
echo $?
[[ -v aa[$key] ]]
echo $?
unset aa key
+92
View File
@@ -0,0 +1,92 @@
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# assoc_expand_once for builtins
typeset -A a
a[0]=0 a[1]=1
let "a[\" \"]=11" ; typeset -p a ; a[0]=0
unset a
# tests for `problem' keys when using associative arrays and assoc_expand_once
# deal with problems for now; this is a placeholder for if and when I fix them
typeset -A a
k='['
echo $(( a[$k]=7 ))
k=']'
echo $(( a[$k]=7 ))
unset a
declare -A A
for k in $'\t' ' '; do
(( A[$k]=2 ))
done
declare -p A
for k in ']' '*' '@'; do
(( A[$k]=2 ))
done
declare -p A
unset A
declare -A A
for k in $'\t' ' ' ']' '*' '@'; do
read "A[$k]" <<< X
done
declare -p A
unset A
declare -A A
for k in $'\t' ' ' ']' '*' '@'; do
printf -v "A[$k]" "%s" X
done
declare -p A
unset A
declare -A A
for k in ']' '*' '@'; do
declare A[$k]=X
done
declare -p A
unset A
declare -A A
for k in ']' '*' '@'; do
declare "A[$k]=X"
done
declare -p A
unset A
# this isn't right yet, but changes will show up here
shopt -s assoc_expand_once
declare -A assoc
key='x],b[$(echo uname >&2)'
let assoc[$key]++
declare -p assoc
unset assoc
+74
View File
@@ -0,0 +1,74 @@
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# assoc_expand_once and unset builtin, which is treated specially
declare -A assoc
var=x123
assoc['$var']=value
declare -p assoc
shopt -u assoc_expand_once
unset "assoc[$var]"
declare -p assoc
unset 'assoc[$var]'
declare -p assoc
assoc['$var']=value
shopt -s assoc_expand_once
unset 'assoc[$var]'
declare -p assoc
unset assoc
declare -A a
a['$(echo foo)']=1
unset 'a[$(echo foo)]'
declare -p a
key='$(echo foo)'
a[$key]=1
unset 'a[$key]'
declare -p a
a[$key]=1
unset "a[$key]"
declare -p a
a[$key]=1
unset a[$key]
declare -p a
unset a
typeset -A assoc
key=@
assoc[@]=at
assoc[!]=bang
unset -v assoc[$key]
typeset -p assoc
test -v assoc[$key]
echo $?
[[ -v assoc[$key] ]]
echo $?
unset assoc
+2
View File
@@ -0,0 +1,2 @@
${THIS_SH} ./quotearray.tests >${BASH_TSTOUT} 2>&1
diff ${BASH_TSTOUT} quotearray.right && rm -f ${BASH_TSTOUT}