mirror of
https://https.git.savannah.gnu.org/git/bash.git
synced 2026-06-26 07:13:10 +02:00
fix for posix semantics for the := word expansion when assigning array elements
This commit is contained in:
@@ -2640,3 +2640,25 @@ variables.c
|
||||
doc/Makefile.in
|
||||
- changes to allow man pages that include others (.so FN) to be built
|
||||
outside the source tree
|
||||
|
||||
12/13
|
||||
-----
|
||||
arrayfunc.c
|
||||
- assign_array_element_internal: take an additional argument: char **NVALP.
|
||||
If non-null, it gets the value eventually assigned to the array
|
||||
element
|
||||
- assign_array_element: take an additional NVALP argument; pass it to
|
||||
assign_array_element_internal
|
||||
|
||||
arrayfunc.h
|
||||
- assign_array_element: new extern function declaration
|
||||
|
||||
{subst,variables}.c,builtins/{common.c,declare.def}
|
||||
- assign_array_element: change callers
|
||||
|
||||
subst.c
|
||||
- parameter_brace_expand_rhs: for the ${param:=value}, use the value
|
||||
returned by assign_array_element in NVALP as the return value, since
|
||||
it's the value ultimately assigned to the variable after possible
|
||||
modification (e.g., arithmetic evaluation). Reported by
|
||||
oguzismailuysal@gmail.com after flawed fix applied 11/16
|
||||
|
||||
@@ -933,6 +933,7 @@ tests/array26.sub f
|
||||
tests/array27.sub f
|
||||
tests/array28.sub f
|
||||
tests/array29.sub f
|
||||
tests/array30.sub f
|
||||
tests/array-at-star f
|
||||
tests/array2.right f
|
||||
tests/assoc.tests f
|
||||
|
||||
@@ -27,8 +27,6 @@
|
||||
|
||||
typedef intmax_t arrayind_t;
|
||||
|
||||
enum atype {array_indexed, array_assoc}; /* not used */
|
||||
|
||||
typedef struct array {
|
||||
arrayind_t max_index;
|
||||
arrayind_t num_elements;
|
||||
|
||||
+14
-4
@@ -53,7 +53,7 @@ int assoc_expand_once = 0;
|
||||
int array_expand_once = 0;
|
||||
|
||||
static SHELL_VAR *bind_array_var_internal PARAMS((SHELL_VAR *, arrayind_t, char *, char *, int));
|
||||
static SHELL_VAR *assign_array_element_internal PARAMS((SHELL_VAR *, char *, char *, char *, int, char *, int));
|
||||
static SHELL_VAR *assign_array_element_internal PARAMS((SHELL_VAR *, char *, char *, char *, int, char *, int, char **));
|
||||
|
||||
static void assign_assoc_from_kvlist PARAMS((SHELL_VAR *, WORD_LIST *, HASH_TABLE *, int));
|
||||
|
||||
@@ -322,9 +322,10 @@ bind_assoc_variable (entry, name, key, value, flags)
|
||||
assign VALUE to that array element by calling bind_array_variable().
|
||||
Flags are ASS_ assignment flags */
|
||||
SHELL_VAR *
|
||||
assign_array_element (name, value, flags)
|
||||
assign_array_element (name, value, flags, nvalp)
|
||||
char *name, *value;
|
||||
int flags;
|
||||
char **nvalp;
|
||||
{
|
||||
char *sub, *vname;
|
||||
int sublen, isassoc;
|
||||
@@ -352,14 +353,14 @@ assign_array_element (name, value, flags)
|
||||
return ((SHELL_VAR *)NULL);
|
||||
}
|
||||
|
||||
entry = assign_array_element_internal (entry, name, vname, sub, sublen, value, flags);
|
||||
entry = assign_array_element_internal (entry, name, vname, sub, sublen, value, flags, nvalp);
|
||||
|
||||
free (vname);
|
||||
return entry;
|
||||
}
|
||||
|
||||
static SHELL_VAR *
|
||||
assign_array_element_internal (entry, name, vname, sub, sublen, value, flags)
|
||||
assign_array_element_internal (entry, name, vname, sub, sublen, value, flags, nvalp)
|
||||
SHELL_VAR *entry;
|
||||
char *name; /* only used for error messages */
|
||||
char *vname;
|
||||
@@ -367,9 +368,11 @@ assign_array_element_internal (entry, name, vname, sub, sublen, value, flags)
|
||||
int sublen;
|
||||
char *value;
|
||||
int flags;
|
||||
char **nvalp;
|
||||
{
|
||||
char *akey;
|
||||
arrayind_t ind;
|
||||
char *newval;
|
||||
|
||||
if (entry && assoc_p (entry))
|
||||
{
|
||||
@@ -386,6 +389,7 @@ assign_array_element_internal (entry, name, vname, sub, sublen, value, flags)
|
||||
return ((SHELL_VAR *)NULL);
|
||||
}
|
||||
entry = bind_assoc_variable (entry, vname, akey, value, flags);
|
||||
newval = entry ? assoc_reference (assoc_cell (entry), akey) : 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -399,8 +403,14 @@ assign_array_element_internal (entry, name, vname, sub, sublen, value, flags)
|
||||
return ((SHELL_VAR *)NULL);
|
||||
}
|
||||
entry = bind_array_variable (vname, ind, value, flags);
|
||||
newval = entry ? array_reference (array_cell (entry), ind) : 0;
|
||||
}
|
||||
|
||||
/* If the caller asks, return the (possibly modified) final value assigned.
|
||||
This saves subseqent lookups. */
|
||||
if (nvalp)
|
||||
*nvalp = newval;
|
||||
|
||||
return (entry);
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -56,7 +56,7 @@ extern char *make_array_variable_value PARAMS((SHELL_VAR *, arrayind_t, char *,
|
||||
|
||||
extern SHELL_VAR *bind_array_variable PARAMS((char *, arrayind_t, char *, int));
|
||||
extern SHELL_VAR *bind_array_element PARAMS((SHELL_VAR *, arrayind_t, char *, int));
|
||||
extern SHELL_VAR *assign_array_element PARAMS((char *, char *, int));
|
||||
extern SHELL_VAR *assign_array_element PARAMS((char *, char *, int, char **));
|
||||
|
||||
extern SHELL_VAR *bind_assoc_variable PARAMS((SHELL_VAR *, char *, char *, char *, int));
|
||||
|
||||
|
||||
+1
-1
@@ -1004,7 +1004,7 @@ builtin_bind_variable (name, value, flags)
|
||||
if (valid_array_reference (name, vflags) == 0)
|
||||
v = bind_variable (name, value, flags);
|
||||
else
|
||||
v = assign_array_element (name, value, bindflags);
|
||||
v = assign_array_element (name, value, bindflags, (char **)0);
|
||||
#else /* !ARRAY_VARS */
|
||||
v = bind_variable (name, value, flags);
|
||||
#endif /* !ARRAY_VARS */
|
||||
|
||||
@@ -949,7 +949,7 @@ restart_new_var_name:
|
||||
local_aflags = aflags&ASS_APPEND;
|
||||
local_aflags |= assoc_noexpand ? ASS_NOEXPAND : 0;
|
||||
local_aflags |= ASS_ALLOWALLSUB; /* allow declare a[@]=at */
|
||||
var = assign_array_element (name, value, local_aflags); /* XXX - not aflags */
|
||||
var = assign_array_element (name, value, local_aflags, (char **)0); /* XXX - not aflags */
|
||||
*subscript_start = '\0';
|
||||
if (var == 0) /* some kind of assignment error */
|
||||
{
|
||||
|
||||
+1
-1
@@ -281,7 +281,7 @@ An \fIinteractive\fP shell is one started without non-option arguments
|
||||
(unless \fB\-s\fP is specified)
|
||||
and without the
|
||||
.B \-c
|
||||
option
|
||||
option,
|
||||
whose standard input and error are
|
||||
both connected to terminals (as determined by
|
||||
.IR isatty (3)),
|
||||
|
||||
+3
-2
@@ -7091,8 +7091,9 @@ the same, but the effective user id is not reset.
|
||||
@subsection What is an Interactive Shell?
|
||||
|
||||
An interactive shell
|
||||
is one started without non-option arguments, unless @option{-s} is
|
||||
specified, without specifying the @option{-c} option, and
|
||||
is one started without non-option arguments
|
||||
(unless @option{-s} is specified)
|
||||
and without specifying the @option{-c} option,
|
||||
whose input and error output are both
|
||||
connected to terminals (as determined by @code{isatty(3)}),
|
||||
or one started with the @option{-i} option.
|
||||
|
||||
@@ -3308,7 +3308,7 @@ do_assignment_internal (word, expand)
|
||||
ASSIGN_RETURN (0);
|
||||
}
|
||||
aflags |= ASS_ALLOWALLSUB; /* allow a[@]=value for existing associative arrays */
|
||||
entry = assign_array_element (name, value, aflags);
|
||||
entry = assign_array_element (name, value, aflags, (char **)0);
|
||||
if (entry == 0)
|
||||
ASSIGN_RETURN (0);
|
||||
}
|
||||
@@ -7227,8 +7227,8 @@ parameter_brace_expand_rhs (name, value, op, quoted, pflags, qdollaratp, hasdoll
|
||||
{
|
||||
WORD_DESC *w;
|
||||
WORD_LIST *l, *tl;
|
||||
char *t, *t1, *temp, *vname;
|
||||
int l_hasdollat, sindex;
|
||||
char *t, *t1, *temp, *vname, *newval;
|
||||
int l_hasdollat, sindex, arrayref;
|
||||
SHELL_VAR *v;
|
||||
|
||||
/*itrace("parameter_brace_expand_rhs: %s:%s pflags = %d", name, value, pflags);*/
|
||||
@@ -7374,9 +7374,13 @@ parameter_brace_expand_rhs (name, value, op, quoted, pflags, qdollaratp, hasdoll
|
||||
}
|
||||
}
|
||||
|
||||
arrayref = 0;
|
||||
#if defined (ARRAY_VARS)
|
||||
if (valid_array_reference (vname, 0))
|
||||
v = assign_array_element (vname, t1, 0);
|
||||
{
|
||||
v = assign_array_element (vname, t1, ASS_ALLOWALLSUB, &newval);
|
||||
arrayref = 1;
|
||||
}
|
||||
else
|
||||
#endif /* ARRAY_VARS */
|
||||
v = bind_variable (vname, t1, 0);
|
||||
@@ -7399,16 +7403,20 @@ parameter_brace_expand_rhs (name, value, op, quoted, pflags, qdollaratp, hasdoll
|
||||
|
||||
stupidly_hack_special_variables (vname);
|
||||
|
||||
if (vname != name)
|
||||
free (vname);
|
||||
|
||||
/* "In all cases, the final value of parameter shall be substituted." */
|
||||
if (shell_compatibility_level > 51)
|
||||
{
|
||||
FREE (t1);
|
||||
#if defined (ARRAY_VARS)
|
||||
t1 = arrayref ? newval : get_variable_value (v);
|
||||
#else
|
||||
t1 = value_cell (v);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (vname != name)
|
||||
free (vname);
|
||||
|
||||
/* From Posix group discussion Feb-March 2010. Issue 7 0000221 */
|
||||
|
||||
/* If we are double-quoted or if we are not going to be performing word
|
||||
|
||||
@@ -773,3 +773,15 @@ declare -A foo=([v]=$'\001\001\001\001' )
|
||||
declare -A foo=([v]=$'\001\001\001\001' )
|
||||
declare -A foo=([$'\001']=$'ab\001c' )
|
||||
declare -A foo=([$'\001']=$'ab\001c' )
|
||||
foo
|
||||
declare -a a=([42]="foo")
|
||||
foo
|
||||
declare -a a=([42]="foo")
|
||||
7
|
||||
declare -ai a=([42]="7")
|
||||
42
|
||||
declare -ai a=([42]="42")
|
||||
FOO
|
||||
declare -Au A=([Darwin]="FOO" )
|
||||
FOO
|
||||
declare -Au A=(["@"]="FOO" )
|
||||
|
||||
@@ -426,3 +426,4 @@ ${THIS_SH} ./array26.sub
|
||||
${THIS_SH} ./array27.sub
|
||||
${THIS_SH} ./array28.sub
|
||||
${THIS_SH} ./array29.sub
|
||||
${THIS_SH} ./array30.sub
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
# 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/>.
|
||||
#
|
||||
declare -a a
|
||||
a=()
|
||||
|
||||
echo ${a[42]=foo}
|
||||
declare -p a
|
||||
|
||||
a=()
|
||||
echo ${a[$(echo 42)]=foo}
|
||||
declare -p a
|
||||
|
||||
unset a
|
||||
|
||||
declare -ai a
|
||||
a=()
|
||||
echo ${a[42]=4+3}
|
||||
declare -p a
|
||||
|
||||
a=()
|
||||
echo ${a[$(echo 42)]=42}
|
||||
declare -p a
|
||||
|
||||
unset a
|
||||
|
||||
declare -A A
|
||||
declare -u A
|
||||
A=()
|
||||
echo ${A[$(echo Darwin)]=foo}
|
||||
|
||||
declare -p A
|
||||
A=()
|
||||
|
||||
echo ${A[@]:=foo}
|
||||
declare -p A
|
||||
@@ -409,3 +409,11 @@ cdefg
|
||||
abcdefg
|
||||
abcde
|
||||
abcdefg
|
||||
foo
|
||||
declare -- a="foo"
|
||||
7
|
||||
declare -i a="7"
|
||||
42
|
||||
declare -- a="42"
|
||||
FOO
|
||||
declare -u A="FOO"
|
||||
|
||||
@@ -423,3 +423,4 @@ ${THIS_SH} ./exp9.sub
|
||||
${THIS_SH} ./exp10.sub
|
||||
${THIS_SH} ./exp11.sub
|
||||
${THIS_SH} ./exp12.sub
|
||||
${THIS_SH} ./exp13.sub
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
# 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/>.
|
||||
#
|
||||
unset a
|
||||
|
||||
echo ${a:=foo}
|
||||
declare -p a
|
||||
|
||||
unset a
|
||||
|
||||
declare -i a
|
||||
echo ${a:=4+3}
|
||||
declare -p a
|
||||
|
||||
unset a
|
||||
echo ${a:=42}
|
||||
declare -p a
|
||||
|
||||
unset a
|
||||
declare -u A
|
||||
A=
|
||||
echo ${A:=foo}
|
||||
|
||||
declare -p A
|
||||
+4
-4
@@ -2495,7 +2495,7 @@ get_variable_value (var)
|
||||
/* Return the string value of a variable. Return NULL if the variable
|
||||
doesn't exist. Don't cons a new string. This is a potential memory
|
||||
leak if the variable is found in the temporary environment, but doesn't
|
||||
leak in practice. Since functions and variables have separate name
|
||||
leak in practice. Since functions and variables have separate name
|
||||
spaces, returns NULL if var_name is a shell function only. */
|
||||
char *
|
||||
get_string_value (var_name)
|
||||
@@ -3111,7 +3111,7 @@ bind_variable_internal (name, value, table, hflags, aflags)
|
||||
assign_array_element will eventually do it itself based on
|
||||
newval and aflags. */
|
||||
|
||||
entry = assign_array_element (newval, value, aflags|ASS_NAMEREF);
|
||||
entry = assign_array_element (newval, value, aflags|ASS_NAMEREF, (char **)0);
|
||||
if (entry == 0)
|
||||
return entry;
|
||||
}
|
||||
@@ -3268,7 +3268,7 @@ bind_variable (name, value, flags)
|
||||
return (bind_variable_internal (nv->name, value, nvc->table, 0, flags));
|
||||
#if defined (ARRAY_VARS)
|
||||
else if (valid_array_reference (nameref_cell (nv), 0))
|
||||
return (assign_array_element (nameref_cell (nv), value, flags));
|
||||
return (assign_array_element (nameref_cell (nv), value, flags, (char **)0));
|
||||
else
|
||||
#endif
|
||||
return (bind_variable_internal (nameref_cell (nv), value, nvc->table, 0, flags));
|
||||
@@ -3433,7 +3433,7 @@ bind_int_variable (lhs, rhs, flags)
|
||||
|
||||
#if defined (ARRAY_VARS)
|
||||
if (isarr)
|
||||
v = assign_array_element (lhs, rhs, flags);
|
||||
v = assign_array_element (lhs, rhs, flags, (char **)0);
|
||||
else if (implicitarray)
|
||||
v = bind_array_variable (lhs, 0, rhs, 0); /* XXX - check on flags */
|
||||
else
|
||||
|
||||
Reference in New Issue
Block a user