commit bash-20200427 snapshot

This commit is contained in:
Chet Ramey
2020-04-30 11:59:39 -04:00
parent 69333f10bb
commit c6c7ae81bb
13 changed files with 551 additions and 171 deletions
+43
View File
@@ -8211,3 +8211,46 @@ subst.c
or at least -- (if we are inheriting), because we don't want the
declare to get skipped before we perform the word assignment. Fixes
bug reported by Ross Goldberg <ross.goldberg@gmail.com>
4/28
----
subst.c
- expand_declaration_argument: new function, broke code that handles
compound assignments that are arguments to declaration commands out
of shell_expand_word_list into this function. No functional change
yet
4/29
----
subst.c
- expand_compound_assignment_word: helper function for
expand_declaration_argument: takes NAME[+]=( VALUE ), converts VALUE
to a list of words, then single-quotes each word and reconstructs
the original word. This assumes the result will go to
do_word_assignment, which will remove the single quotes
- expand_oneword: helper function for expand_compound_assignment_word,
takes VALUE and performs the splitting into words, and then the
expansion and single-quoting of each individual word. Indexed and
associative arrays take different code paths, because they undergo
different expansions and associative arrays need special handling to
avoid having to scan for the end of the subscript multiple times
- expand_declaration_argument: call expand_compound_assignment_word to
get the expansion-before-calling-builtins word expansion sequence
correct. Better fix for for bug report from Kevin Locke
<kevin@kevinlocke.name>,
https://savannah.gnu.org/support/index.php?109669
arrayfunc.c
- quote_array_compound_word: take [IND]=VALUE and convert it to
['IND']='VALUE'. Called by quote_compound_array_list for each word
in the list
- expand_and_quote_assoc_qword: take [KEY]=VALUE and convert it to
['expanded-key']='expanded-value' (or VALUE to 'expanded-value').
Called by subst.c:expand_oneword() for each word in the list
- quote_compound_array_list: take a list of words and convert each
[IND]=VALUE to ['IND']='VALUE' (or just 'VALUE' if there is no
[IND]=). Used for indexed arrays
arrayfunc.h
- expand_and_quote_assoc_word,quote_compound_array_list: new extern
declarations
+1
View File
@@ -1447,6 +1447,7 @@ tests/varenv15.in f
tests/varenv16.sub f
tests/varenv17.sub f
tests/varenv18.sub f
tests/varenv19.sub f
tests/version f
tests/version.mini f
tests/vredir.tests f
+124 -4
View File
@@ -40,6 +40,11 @@
#include "builtins/common.h"
#ifndef LBRACK
# define LBRACK '['
# define RBRACK ']'
#endif
/* This variable means to not expand associative array subscripts more than
once, when performing variable expansion. */
int assoc_expand_once = 0;
@@ -54,6 +59,7 @@ static void assign_assoc_from_kvlist PARAMS((SHELL_VAR *, WORD_LIST *, HASH_TABL
static char *quote_assign PARAMS((const char *));
static void quote_array_assignment_chars PARAMS((WORD_LIST *));
static char *quote_compound_array_word PARAMS((char *, int));
static char *array_value_internal PARAMS((const char *, int, int, int *, arrayind_t *));
/* Standard error message to use when encountering an invalid array subscript */
@@ -594,9 +600,11 @@ assign_assoc_from_kvlist (var, nlist, h, flags)
#endif
/* Callers ensure that VAR is not NULL. Associative array assignments have not
been expanded when this is called, so we don't have to scan through the
expanded subscript to find the ending bracket; indexed array assignments
have been expanded.
been expanded when this is called, or have been expanded once and single-
quoted, so we don't have to scan through an unquoted expanded subscript to
find the ending bracket; indexed array assignments have been expanded and
possibly single-quoted to prevent further expansion.
If this is an associative array, we perform the assignments into NHASH and
set NHASH to be the value of VAR after processing the assignments in NLIST */
void
@@ -632,7 +640,7 @@ assign_compound_array_list (var, nlist, flags)
last_ind = (a && (flags & ASS_APPEND)) ? array_max_index (a) + 1 : 0;
#if ASSOC_KVPAIR_ASSIGNMENT
if (assoc_p (var) && nlist && (nlist->word->flags & W_ASSIGNMENT) == 0 && nlist->word->word[0] != '[') /*]*/
if (assoc_p (var) && nlist && (nlist->word->flags & W_ASSIGNMENT) == 0 && nlist->word->word[0] != '[') /*]*/
{
iflags = flags & ~ASS_APPEND;
assign_assoc_from_kvlist (var, nlist, nhash, iflags);
@@ -851,6 +859,118 @@ quote_assign (string)
return temp;
}
/* Take a word W of the form [IND]=VALUE and transform it to ['IND]='VALUE'
to prevent further expansion. This is called for compound assignments to
indexed arrays. W has already undergone word expansions. If W has no [IND]=,
just single-quote and return it. */
static char *
quote_compound_array_word (w, type)
char *w;
int type;
{
char *nword, *sub, *value, *t;
int ind, wlen, i;
if (w[0] != LBRACK)
return (sh_single_quote (w));
ind = skipsubscript (w, 0, 0);
if (w[ind] != RBRACK)
return (sh_single_quote (w));
wlen = strlen (w);
w[ind] = '\0';
sub = sh_single_quote (w+1);
w[ind] = RBRACK;
nword = xmalloc (wlen * 4 + 5); /* wlen*4 is max single quoted length */
nword[0] = LBRACK;
i = STRLEN (sub);
memcpy (nword+1, sub, i);
i++; /* accommodate the opening LBRACK */
nword[i++] = w[ind++]; /* RBRACK */
if (w[ind] == '+')
nword[i++] = w[ind++];
nword[i++] = w[ind++];
value = sh_single_quote (w + ind);
strcpy (nword + i, value);
return nword;
}
/* Expand the key and value in W, which is of the form [KEY]=VALUE, and
reconstruct W with the expanded and single-quoted version:
['expanded-key']='expanded-value'. If there is no [KEY]=, single-quote the
word and return it. Very similar to previous function, but does not assume
W has already been expanded, and expands the KEY and VALUE separately.
Used for compound assignments to associative arrays that are arguments to
declaration builtins (declare -A a=( list )). */
char *
expand_and_quote_assoc_word (w, type)
char *w;
int type;
{
char *nword, *key, *value, *t;
int ind, wlen, i;
if (w[0] != LBRACK)
return (sh_single_quote (w));
ind = skipsubscript (w, 0, 0);
if (w[ind] != RBRACK)
return (sh_single_quote (w));
w[ind] = '\0';
t = expand_assignment_string_to_string (w+1, 0);
w[ind] = RBRACK;
key = sh_single_quote (t ? t : "");
free (t);
wlen = STRLEN (key);
nword = xmalloc (wlen + 5);
nword[0] = LBRACK;
memcpy (nword+1, key, wlen);
i = wlen + 1; /* accommodate the opening LBRACK */
nword[i++] = w[ind++]; /* RBRACK */
if (w[ind] == '+')
nword[i++] = w[ind++];
nword[i++] = w[ind++];
t = expand_assignment_string_to_string (w+ind, 0);
value = sh_single_quote (t ? t : "");
free (t);
nword = xrealloc (nword, wlen + 5 + STRLEN (value));
strcpy (nword + i, value);
free (key);
free (value);
return nword;
}
/* For each word in a compound array assignment, if the word looks like
[ind]=value, single-quote ind and value, but leave the brackets and
the = sign (and any `+') alone. This is used for indexed arrays. */
void
quote_compound_array_list (list, type)
WORD_LIST *list;
int type;
{
char *t;
WORD_LIST *l;
for (l = list; l; l = l->next)
{
if (l->word == 0 || l->word->word == 0 || l->word->word[0] == '\0')
continue; /* should not happen, but just in case... */
if ((l->word->flags & W_ASSIGNMENT) == 0)
t = sh_single_quote (l->word->word);
else
t = quote_compound_array_word (l->word->word, type);
free (l->word->word);
l->word->word = t;
}
}
/* For each word in a compound array assignment, if the word looks like
[ind]=value, quote globbing chars and characters in $IFS before the `='. */
static void
+28 -25
View File
@@ -1,6 +1,6 @@
/* arrayfunc.h -- declarations for miscellaneous array functions in arrayfunc.c */
/* Copyright (C) 2001-2010 Free Software Foundation, Inc.
/* Copyright (C) 2001-2020 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
@@ -44,41 +44,44 @@ extern int array_expand_once;
#define VA_NOEXPAND 0x001
#define VA_ONEWORD 0x002
extern SHELL_VAR *convert_var_to_array __P((SHELL_VAR *));
extern SHELL_VAR *convert_var_to_assoc __P((SHELL_VAR *));
extern SHELL_VAR *convert_var_to_array PARAMS((SHELL_VAR *));
extern SHELL_VAR *convert_var_to_assoc PARAMS((SHELL_VAR *));
extern char *make_array_variable_value __P((SHELL_VAR *, arrayind_t, char *, char *, int));
extern char *make_array_variable_value PARAMS((SHELL_VAR *, arrayind_t, char *, char *, int));
extern SHELL_VAR *bind_array_variable __P((char *, arrayind_t, char *, int));
extern SHELL_VAR *bind_array_element __P((SHELL_VAR *, arrayind_t, char *, int));
extern SHELL_VAR *assign_array_element __P((char *, char *, int));
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 *bind_assoc_variable __P((SHELL_VAR *, char *, char *, char *, int));
extern SHELL_VAR *bind_assoc_variable PARAMS((SHELL_VAR *, char *, char *, char *, int));
extern SHELL_VAR *find_or_make_array_variable __P((char *, int));
extern SHELL_VAR *find_or_make_array_variable PARAMS((char *, int));
extern SHELL_VAR *assign_array_from_string __P((char *, char *, int));
extern SHELL_VAR *assign_array_var_from_word_list __P((SHELL_VAR *, WORD_LIST *, int));
extern SHELL_VAR *assign_array_from_string PARAMS((char *, char *, int));
extern SHELL_VAR *assign_array_var_from_word_list PARAMS((SHELL_VAR *, WORD_LIST *, int));
extern WORD_LIST *expand_compound_array_assignment __P((SHELL_VAR *, char *, int));
extern void assign_compound_array_list __P((SHELL_VAR *, WORD_LIST *, int));
extern SHELL_VAR *assign_array_var_from_string __P((SHELL_VAR *, char *, int));
extern WORD_LIST *expand_compound_array_assignment PARAMS((SHELL_VAR *, char *, int));
extern void assign_compound_array_list PARAMS((SHELL_VAR *, WORD_LIST *, int));
extern SHELL_VAR *assign_array_var_from_string PARAMS((SHELL_VAR *, char *, int));
extern int unbind_array_element __P((SHELL_VAR *, char *, int));
extern int skipsubscript __P((const char *, int, int));
extern char *expand_and_quote_assoc_word PARAMS((char *, int));
extern void quote_compound_array_list PARAMS((WORD_LIST *, int));
extern void print_array_assignment __P((SHELL_VAR *, int));
extern void print_assoc_assignment __P((SHELL_VAR *, int));
extern int unbind_array_element PARAMS((SHELL_VAR *, char *, int));
extern int skipsubscript PARAMS((const char *, int, int));
extern arrayind_t array_expand_index __P((SHELL_VAR *, char *, int, int));
extern int valid_array_reference __P((const char *, int));
extern char *array_value __P((const char *, int, int, int *, arrayind_t *));
extern char *get_array_value __P((const char *, int, int *, arrayind_t *));
extern void print_array_assignment PARAMS((SHELL_VAR *, int));
extern void print_assoc_assignment PARAMS((SHELL_VAR *, int));
extern char *array_keys __P((char *, int, int));
extern arrayind_t array_expand_index PARAMS((SHELL_VAR *, char *, int, int));
extern int valid_array_reference PARAMS((const char *, int));
extern char *array_value PARAMS((const char *, int, int, int *, arrayind_t *));
extern char *get_array_value PARAMS((const char *, int, int *, arrayind_t *));
extern char *array_variable_name __P((const char *, int, char **, int *));
extern SHELL_VAR *array_variable_part __P((const char *, int, char **, int *));
extern char *array_keys PARAMS((char *, int, int));
extern char *array_variable_name PARAMS((const char *, int, char **, int *));
extern SHELL_VAR *array_variable_part PARAMS((const char *, int, char **, int *));
#else
+1 -1
View File
@@ -25,6 +25,6 @@
regexp `^#define[ ]*PATCHLEVEL', since that's what support/mkversion.sh
looks for to find the patch level (for the sccs version string). */
#define PATCHLEVEL 16
#define PATCHLEVEL 17
#endif /* _PATCHLEVEL_H_ */
+261 -136
View File
@@ -354,6 +354,8 @@ static WORD_LIST *brace_expand_word_list PARAMS((WORD_LIST *, int));
#endif
#if defined (ARRAY_VARS)
static int make_internal_declare PARAMS((char *, char *, char *));
static void expand_compound_assignment_word PARAMS((WORD_LIST *, int));
static WORD_LIST *expand_declaration_argument PARAMS((WORD_LIST *, WORD_LIST *));
#endif
static WORD_LIST *shell_expand_word_list PARAMS((WORD_LIST *, int));
static WORD_LIST *expand_word_list_internal PARAMS((WORD_LIST *, int));
@@ -11504,7 +11506,260 @@ make_internal_declare (word, option, cmd)
dispose_words (wl);
return r;
}
#endif
/* Expand VALUE in NAME[+]=( VALUE ) to a list of words. FLAGS is 1 if NAME
is an associative array.
If we are processing an indexed array, expand_compound_array_assignment
will expand all the individual words and quote_compound_array_list will
single-quote them. If we are processing an associative array, we use
parse_string_to_word_list to split VALUE into a list of words instead of
faking up a shell variable and calling expand_compound_array_assignment.
expand_and_quote_assoc_word expands and single-quotes each word in VALUE
together so we don't have problems finding the end of the subscript when
quoting it.
Words in VALUE can be individual words, which are expanded and single-quoted,
or words of the form [IND]=VALUE, which end up as explained below, as
['expanded-ind']='expanded-value'. */
static WORD_LIST *
expand_oneword (value, flags)
char *value;
int flags;
{
WORD_LIST *l, *nl;
char *t;
if (flags == 0)
{
/* Indexed array */
l = expand_compound_array_assignment ((SHELL_VAR *)NULL, value, flags);
/* Now we quote the results of the expansion above to prevent double
expansion. */
quote_compound_array_list (l, flags);
return l;
}
else
{
/* Associative array */
l = parse_string_to_word_list (value, 1, "array assign");
/* For associative arrays, with their arbitrary subscripts, we have to
expand and quote in one step so we don't have to search for the
closing right bracket more than once. */
for (nl = l; nl; nl = nl->next)
{
if ((nl->word->flags & W_ASSIGNMENT) == 0)
t = sh_single_quote (nl->word->word ? nl->word->word : "");
else
t = expand_and_quote_assoc_word (nl->word->word, flags);
free (nl->word->word);
nl->word->word = t;
}
return l;
}
}
/* Expand a single compound assignment argument to a declaration builtin.
This word takes the form NAME[+]=( VALUE ). The NAME[+]= is passed through
unchanged. The VALUE is expanded and each word in the result is single-
quoted. Words of the form [key]=value end up as
['expanded-key']='expanded-value'. Associative arrays have special
handling, see expand_oneword() above. The return value is
NAME[+]=( expanded-and-quoted-VALUE ). */
static void
expand_compound_assignment_word (tlist, flags)
WORD_LIST *tlist;
int flags;
{
WORD_LIST *l;
int wlen, oind, t;
char *value, *temp;
/*itrace("expand_compound_assignment_word: original word = -%s-", tlist->word->word);*/
wlen = strlen (tlist->word->word);
t = assignment (tlist->word->word, 0);
/* value doesn't have the open and close parens */
oind = 1;
value = extract_array_assignment_list (tlist->word->word + t + 1, &oind);
/* This performs one round of expansion on the index/key and value and
single-quotes each word in the result. */
l = expand_oneword (value, flags);
free (value);
value = string_list (l);
wlen = STRLEN (value);
/* Now, let's rebuild the string */
temp = xmalloc (t + 3 + wlen + 1); /* name[+]=(value) */
memcpy (temp, tlist->word->word, ++t);
temp[t++] = '(';
if (value)
memcpy (temp + t, value, wlen);
t += wlen;
temp[t++] = ')';
temp[t] = '\0';
/*itrace("expand_compound_assignment_word: reconstructed word = -%s-", temp);*/
free (tlist->word->word);
tlist->word->word = temp;
free (value);
}
/* Expand and process an argument to a declaration command. We have already
set flags in TLIST->word->flags depending on the declaration command
(declare, local, etc.) and the options supplied to it (-a, -A, etc.).
TLIST->word->word is of the form NAME[+]=( VALUE ).
This does several things, all using pieces of other functions to get the
evaluation sequence right. It's called for compound array assignments with
the W_ASSIGNMENT flag set (basically, valid identifier names on the lhs).
It parses out which flags need to be set for declare to create the variable
correctly, then calls declare internally (make_internal_declare) to make
sure the variable exists with the correct attributes. Before the variable
is created, it calls expand_compound_assignment_word to expand VALUE to a
list of words, appropriately quoted for further evaluation. This preserves
the semantics of word-expansion-before-calling-builtins. Finally, it calls
do_word_assignment to perform the expansion and assignment with the same
expansion semantics as a standalone assignment statement (no word splitting,
etc.) even though the word is single-quoted so all that needs to happen is
quote removal. */
static WORD_LIST *
expand_declaration_argument (tlist, wcmd)
WORD_LIST *tlist, *wcmd;
{
char opts[16], omap[128];
int t, opti, oind, skip, inheriting;
WORD_LIST *l;
inheriting = localvar_inherit;
opti = 0;
if (tlist->word->flags & (W_ASSIGNASSOC|W_ASSNGLOBAL|W_CHKLOCAL|W_ASSIGNARRAY))
opts[opti++] = '-';
if ((tlist->word->flags & (W_ASSIGNASSOC|W_ASSNGLOBAL)) == (W_ASSIGNASSOC|W_ASSNGLOBAL))
{
opts[opti++] = 'g';
opts[opti++] = 'A';
}
else if (tlist->word->flags & W_ASSIGNASSOC)
{
opts[opti++] = 'A';
}
else if ((tlist->word->flags & (W_ASSIGNARRAY|W_ASSNGLOBAL)) == (W_ASSIGNARRAY|W_ASSNGLOBAL))
{
opts[opti++] = 'g';
opts[opti++] = 'a';
}
else if (tlist->word->flags & W_ASSIGNARRAY)
{
opts[opti++] = 'a';
}
else if (tlist->word->flags & W_ASSNGLOBAL)
opts[opti++] = 'g';
if (tlist->word->flags & W_CHKLOCAL)
opts[opti++] = 'G';
/* If we have special handling note the integer attribute and others
that transform the value upon assignment. What we do is take all
of the option arguments and scan through them looking for options
that cause such transformations, and add them to the `opts' array. */
memset (omap, '\0', sizeof (omap));
for (l = wcmd->next; l != tlist; l = l->next)
{
if (l->word->word[0] != '-')
break; /* non-option argument */
if (l->word->word[0] == '-' && l->word->word[1] == '-' && l->word->word[2] == 0)
break; /* -- signals end of options */
for (oind = 1; l->word->word[oind]; oind++)
switch (l->word->word[oind])
{
case 'I':
inheriting = 1;
case 'i':
case 'l':
case 'u':
case 'c':
omap[l->word->word[oind]] = 1;
if (opti == 0)
opts[opti++] = '-';
break;
default:
break;
}
}
for (oind = 0; oind < sizeof (omap); oind++)
if (omap[oind])
opts[opti++] = oind;
/* If there are no -a/-A options, but we have a compound assignment,
we have a choice: we can set opts[0]='-', opts[1]='a', since the
default is to create an indexed array, and call
make_internal_declare with that, or we can just skip the -a and let
declare_builtin deal with it. Once we're here, we're better set
up for the latter, since we don't want to deal with looking up
any existing variable here -- better to let declare_builtin do it.
We need the variable created, though, especially if it's local, so
we get the scoping right before we call do_word_assignment.
To ensure that make_local_declare gets called, we add `--' if there
aren't any options. */
if ((tlist->word->flags & (W_ASSIGNASSOC|W_ASSIGNARRAY)) == 0)
{
if (opti == 0)
{
opts[opti++] = '-';
opts[opti++] = '-';
}
}
opts[opti] = '\0';
/* This isn't perfect, but it's a start. Improvements later. We expand
tlist->word->word and single-quote the results to avoid multiple
expansions by, say, do_assignment_internal(). We have to weigh the
cost of reconstructing the compound assignment string with its single
quoting and letting the declare builtin handle it. The single quotes
will prevent any unwanted additional expansion or word splitting. */
expand_compound_assignment_word (tlist, (tlist->word->flags & W_ASSIGNASSOC) ? 1 : 0);
skip = 0;
if (opti > 0)
{
t = make_internal_declare (tlist->word->word, opts, wcmd ? wcmd->word->word : (char *)0);
if (t != EXECUTION_SUCCESS)
{
last_command_exit_value = t;
if (tlist->word->flags & W_FORCELOCAL) /* non-fatal error */
skip = 1;
else
exp_jump_to_top_level (DISCARD);
}
}
if (skip == 0)
{
t = do_word_assignment (tlist->word, 0);
if (t == 0)
{
last_command_exit_value = EXECUTION_FAILURE;
exp_jump_to_top_level (DISCARD);
}
}
/* Now transform the word as ksh93 appears to do and go on */
t = assignment (tlist->word->word, 0);
tlist->word->word[t] = '\0';
if (tlist->word->word[t - 1] == '+')
tlist->word->word[t - 1] = '\0'; /* cut off append op */
tlist->word->flags &= ~(W_ASSIGNMENT|W_NOSPLIT|W_COMPASSIGN|W_ASSIGNARG|W_ASSIGNASSOC|W_ASSIGNARRAY);
return (tlist);
}
#endif /* ARRAY_VARS */
static WORD_LIST *
shell_expand_word_list (tlist, eflags)
@@ -11515,13 +11770,13 @@ shell_expand_word_list (tlist, eflags)
int expanded_something, has_dollar_at;
/* We do tilde expansion all the time. This is what 1003.2 says. */
new_list = (WORD_LIST *)NULL;
for (wcmd = tlist; wcmd; wcmd = wcmd->next)
if (wcmd->word->flags & W_ASSNBLTIN)
break;
wcmd = new_list = (WORD_LIST *)NULL;
for (orig_list = tlist; tlist; tlist = next)
{
if (wcmd == 0 && (tlist->word->flags & W_ASSNBLTIN))
wcmd = tlist;
next = tlist->next;
#if defined (ARRAY_VARS)
@@ -11532,137 +11787,7 @@ shell_expand_word_list (tlist, eflags)
because `declare' does some evaluation of compound assignments on
its own. */
if ((tlist->word->flags & (W_COMPASSIGN|W_ASSIGNARG)) == (W_COMPASSIGN|W_ASSIGNARG))
{
int t;
char opts[16];
int opti, skip, inheriting, array;
inheriting = localvar_inherit;
opti = 0;
if (tlist->word->flags & (W_ASSIGNASSOC|W_ASSNGLOBAL|W_CHKLOCAL|W_ASSIGNARRAY))
opts[opti++] = '-';
if ((tlist->word->flags & (W_ASSIGNASSOC|W_ASSNGLOBAL)) == (W_ASSIGNASSOC|W_ASSNGLOBAL))
{
opts[opti++] = 'g';
opts[opti++] = 'A';
}
else if (tlist->word->flags & W_ASSIGNASSOC)
{
opts[opti++] = 'A';
/* This doesn't work right if a variable with the same name but
a different type exists at a previous scope; it generates
errors that a user would find confusing. */
/* opts[opti++] = 'I'; */
}
else if ((tlist->word->flags & (W_ASSIGNARRAY|W_ASSNGLOBAL)) == (W_ASSIGNARRAY|W_ASSNGLOBAL))
{
opts[opti++] = 'g';
opts[opti++] = 'a';
}
else if (tlist->word->flags & W_ASSIGNARRAY)
{
opts[opti++] = 'a';
/* opts[opti++] = 'I'; */
}
else if (tlist->word->flags & W_ASSNGLOBAL)
opts[opti++] = 'g';
if (tlist->word->flags & W_CHKLOCAL)
opts[opti++] = 'G';
/* If we have special handling note the integer attribute and others
that transform the value upon assignment. What we do is take all
of the option arguments and scan through them looking for options
that cause such transformations, and add them to the `opts' array. */
/* if (opti > 0) */
{
char omap[128];
int oind;
WORD_LIST *l;
memset (omap, '\0', sizeof (omap));
for (l = orig_list->next; l != tlist; l = l->next)
{
if (l->word->word[0] != '-')
break; /* non-option argument */
if (l->word->word[0] == '-' && l->word->word[1] == '-' && l->word->word[2] == 0)
break; /* -- signals end of options */
for (oind = 1; l->word->word[oind]; oind++)
switch (l->word->word[oind])
{
case 'I':
inheriting = 1;
case 'i':
case 'l':
case 'u':
case 'c':
omap[l->word->word[oind]] = 1;
if (opti == 0)
opts[opti++] = '-';
break;
default:
break;
}
}
for (oind = 0; oind < sizeof (omap); oind++)
if (omap[oind])
opts[opti++] = oind;
}
/* If there are no -a/-A options, but we have a compound assignment,
we have a choice: we can set opts[0]='-', opt[1]='a', since the
default is to create an indexed array, and call
make_internal_declare, or we can just skip it and let
declare_builtin deal with it. Once we're here, we're better set
up for the former. We don't do this if we're inheriting local
variables' attributes and values here, since that makes `-a' no
longer the default; we pass `--' instead if we don't have any
options at all, and just leave off the -a if we have some. */
if ((tlist->word->flags & (W_ASSIGNASSOC|W_ASSIGNARRAY)) == 0)
{
if (opti == 0)
{
opts[opti++] = '-';
opts[opti++] = inheriting ? '-' : 'a';
}
else if (inheriting == 0)
opts[opti++] = 'a';
}
opts[opti] = '\0';
skip = 0;
if (opti > 0)
{
t = make_internal_declare (tlist->word->word, opts, wcmd ? wcmd->word->word : (char *)0);
if (t != EXECUTION_SUCCESS)
{
last_command_exit_value = t;
if (tlist->word->flags & W_FORCELOCAL) /* non-fatal error */
skip = 1;
else
exp_jump_to_top_level (DISCARD);
}
}
if (skip == 0)
{
t = do_word_assignment (tlist->word, 0);
if (t == 0)
{
last_command_exit_value = EXECUTION_FAILURE;
exp_jump_to_top_level (DISCARD);
}
}
/* Now transform the word as ksh93 appears to do and go on */
t = assignment (tlist->word->word, 0);
tlist->word->word[t] = '\0';
if (tlist->word->word[t - 1] == '+')
tlist->word->word[t - 1] = '\0'; /* cut off append op */
tlist->word->flags &= ~(W_ASSIGNMENT|W_NOSPLIT|W_COMPASSIGN|W_ASSIGNARG|W_ASSIGNASSOC|W_ASSIGNARRAY);
}
expand_declaration_argument (tlist, wcmd);
#endif
expanded_something = 0;
+8
View File
@@ -249,3 +249,11 @@ declare -A dict=(["?"]="quest" ["*"]="star" ["'"]="squote" ["\$"]="dol" ["\""]="
dict=( "?" "quest" "*" "star" "'" "squote" "\$" "dol" "\"" "dquote" "\\" "bslash" "@" "at" "}" "rbrace" "{" "lbrace" "\`" "bquote" )
declare -A foo=([two]="" [one]="1" )
foo=( two "" one "1" )
rparen dquote rbrace bs
declare -A a=([")"]="rparen" ["\""]="dquote" ["]"]="rbrace" ["\\"]="bs" )
")" "rparen" "\"" "dquote" "]" "rbrace" "\\" "bs"
declare -A a=([")"]="rparen" ["\""]="dquote" ["]"]="rbrace" ["\\"]="bs" )
declare -A a=([")"]="rparen" ["\""]="dquote" ["]"]="rbrace" ["\\"]="bs" )
declare -A a=([")"]="rparen" ["\""]="dquote" ["]"]="rbrace" ["\\"]="bs" )
declare -Arx foo=([two]="2" [three]="3" [one]="1" )
./assoc11.sub: line 90: foo: readonly variable
+20
View File
@@ -68,3 +68,23 @@ loaddict
foo=(one 1 two)
declare -p foo
echo foo=\( ${foo[@]@K} \)
typeset -A a=( [\\]=bs [\"]=dquote [\)]=rparen [\]]=rbrace )
echo ${a[@]}
declare -p a
echo ${a[@]@K}
echo ${a[@]@A}
eval "${a[@]@A}"
declare -p a
eval "a=( ${a[@]@K} )"
declare -p a
unset a foo
readonly -A foo=( one 1 two 2 three 3 )
export foo
declare -p foo
declare foo+=( seven 7 eight 8 )
+2
View File
@@ -1,2 +1,4 @@
echo "warning: some of these tests will fail if arrays have not" >&2
echo "warning: been compiled into the shell" >&2
${THIS_SH} ./varenv.tests 2>&1 | grep -v '^expect' > ${BASH_TSTOUT}
diff ${BASH_TSTOUT} varenv.right && rm -f ${BASH_TSTOUT}
+9 -2
View File
@@ -246,9 +246,16 @@ declare -- var
declare -- var="local"
declare -- var="f1"
declare -- var="local"
declare -a arr=()
declare -a arr=([0]="zero" [1]="one" [2]="two" [3]="three" [4]="four" [5]="five")
declare -a arr=([0]="zero" [1]="one" [2]="two")
declare -a arr=([0]="three" [1]="four" [2]="five")
./varenv18.sub: line 39: !name: unbound variable
declare -a arr=([0]="zero" [1]="one" [2]="two")
ddd 0
aaa 1 2 3
bbb 4 5 6
ccc 7 8 9
declare -a x=([0]="one" [1]="two" [2]="three")
./varenv19.sub: line 51: declare: x: not found
a=z
a=b
a=z
+1
View File
@@ -256,6 +256,7 @@ ${THIS_SH} ./varenv15.sub
${THIS_SH} ./varenv16.sub
${THIS_SH} ./varenv17.sub
${THIS_SH} ./varenv18.sub
${THIS_SH} ./varenv19.sub
# make sure variable scoping is done right
tt() { typeset a=b;echo a=$a; };a=z;echo a=$a;tt;echo a=$a
+2 -3
View File
@@ -12,18 +12,17 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# THIS DOESN'T WORK RIGHT YET
arr=(zero one two)
four=four
f()
{
local -a arr=( "${arr[@]}" )
arr+=(three four five)
declare -p arr
}
f
declare -p arr
f1()
{
+51
View File
@@ -0,0 +1,51 @@
# 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/>.
#
# variable attribute inheritance problems without specifying -a or -A
function aaa() {
local x='1 2 3'
echo "aaa ${x}"
}
function bbb {
local x
x=(4 5 6)
echo "bbb ${x[*]}"
}
ccc()
{
local x=(7 8 9)
echo "ccc ${x[*]}"
}
function ddd
{
local -r x='0'
echo "ddd ${x}"
aaa
bbb
ccc
}
ddd
f()
{
local x=(one two three)
declare -p x
}
f
declare -p x