allow assignment to array keys @ and *; minor completion fix

This commit is contained in:
Chet Ramey
2021-04-26 16:31:46 -04:00
parent d128c3ddc1
commit 3fd77612fc
20 changed files with 142 additions and 69 deletions
+53
View File
@@ -10021,3 +10021,56 @@ builtins/bind.def
lib/readline/doc/rltech.texi
- RL_PROMPT_{START,END}_IGNORE: document current values of \001 and
\002. Report from Mingye Wang <arthur200126@gmail.com>
4/19
----
arrayfunc.c
- assign_assoc_from_kvlist: fix memory leak reported by konsolebox
<konsolebox@gmail.com>
4/20
----
command.h,subst.c
- W_ITILDE: remove, replace with a variable since it's only used inside
a single call to expand_word_internal
4/21
----
{subst.c,make_cmd.c,parse.y}
- W_DQUOTE: no longer used, use W_NOPROCSUB and W_NOTILDE directly
(for arithmetic commands and words in arithmetic for commands)
4/24
----
bashline.c
- executable_completion: since this function gets an unquoted filename
from rl_filename_completion_function, we need to quote special
characters before passing it to bash_directory_completion_hook.
Report from Alex fxmbsw7 Ratchev <fxmbsw7@gmail.com>
4/26
----
lib/readline/search.c
- _rl_nsearch_abort: move function calls around so _rl_restore_prompt
happens before rl_clear_message, like when aborting an incremental
search. Suggested by sparrowhawk996@gmail.com
subst.h
- ASS_ALLOWALLSUB: new assignment flag value, means to allow @ and * as
array subscripts when assigning to existing associative arrays
arrayfunc.c
- assign_array_element: allow assignment of key `@' to an existing
associative array if the caller passes ASS_ALLOWALLSUB
- assign_compound_array_list: allow ( [@]=value ) to an existing
associative array
builtins/declare.def
- declare_internal: allow assignment of key `@' to an existing
associative array by passing ASS_ALLOWALLSUB to assign_array_element
as part of local_aflags
subst.c
- do_assignment_internal: allow a[@]=value to an existing associative
array by passing ASS_ALLOWALLSUB to assign_array_element
+12 -14
View File
@@ -338,7 +338,13 @@ assign_array_element (name, value, flags)
entry = find_variable (vname);
isassoc = entry && assoc_p (entry);
if (((isassoc == 0 || (flags & ASS_NOEXPAND) == 0) && (ALL_ELEMENT_SUB (sub[0]) && sub[1] == ']')) || (sublen <= 1))
/* We don't allow assignment to `*' or `@' associative array keys if the
caller hasn't told us the subscript has already been expanded
(ASS_NOEXPAND). If the caller has explicitly told us it's ok
(ASS_ALLOWALLSUB) we allow it. */
if (((isassoc == 0 || (flags & (ASS_NOEXPAND|ASS_ALLOWALLSUB)) == 0) &&
(ALL_ELEMENT_SUB (sub[0]) && sub[1] == ']')) ||
(sublen <= 1))
{
free (vname);
err_badarraysub (name);
@@ -564,12 +570,9 @@ assign_assoc_from_kvlist (var, nlist, h, flags)
{
WORD_LIST *list;
char *akey, *aval, *k, *v;
int free_aval;
for (list = nlist; list; list = list->next)
{
free_aval = 0;
k = list->word->word;
v = list->next ? list->next->word->word : 0;
@@ -577,24 +580,22 @@ assign_assoc_from_kvlist (var, nlist, h, flags)
list = list->next;
akey = expand_assignment_string_to_string (k, 0);
aval = expand_assignment_string_to_string (v, 0);
if (akey == 0 || *akey == 0)
{
err_badarraysub (k);
FREE (akey);
continue;
}
aval = expand_assignment_string_to_string (v, 0);
if (aval == 0)
{
aval = (char *)xmalloc (1);
aval[0] = '\0'; /* like do_assignment_internal */
free_aval = 1;
}
bind_assoc_var_internal (var, h, akey, aval, flags);
if (free_aval)
free (aval);
free (aval);
}
}
@@ -714,13 +715,10 @@ assign_compound_array_list (var, nlist, flags)
continue;
}
if (ALL_ELEMENT_SUB (w[1]) && len == 2)
if (ALL_ELEMENT_SUB (w[1]) && len == 2 && array_p (var))
{
set_exit_status (EXECUTION_FAILURE);
if (assoc_p (var))
report_error (_("%s: invalid associative array key"), w);
else
report_error (_("%s: cannot assign to non-numeric index"), w);
report_error (_("%s: cannot assign to non-numeric index"), w);
continue;
}
+8 -1
View File
@@ -1930,10 +1930,17 @@ executable_completion (filename, searching_path)
const char *filename;
int searching_path;
{
char *f;
char *f, c;
int r;
/* This gets an unquoted filename, so we need to quote special characters
in the filename before the completion hook gets it. */
#if 0
f = savestring (filename);
#else
c = 0;
f = bash_quote_filename (filename, SINGLE_MATCH, &c);
#endif
bash_directory_completion_hook (&f);
r = searching_path ? executable_file (f) : executable_or_directory (f);
+1
View File
@@ -942,6 +942,7 @@ restart_new_var_name:
/* XXX - problem here with appending */
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 */
*subscript_start = '\0';
if (var == 0) /* some kind of assignment error */
+7 -7
View File
@@ -1,7 +1,7 @@
/* command.h -- The structures used internally to represent commands, and
the extern declarations of the functions used to create them. */
/* Copyright (C) 1993-2020 Free Software Foundation, Inc.
/* Copyright (C) 1993-2021 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
@@ -81,18 +81,18 @@ enum command_type { cm_for, cm_case, cm_while, cm_if, cm_simple, cm_select,
#define W_NOGLOB (1 << 5) /* Do not perform globbing on this word. */
#define W_NOSPLIT2 (1 << 6) /* Don't split word except for $@ expansion (using spaces) because context does not allow it. */
#define W_TILDEEXP (1 << 7) /* Tilde expand this assignment word */
#define W_DOLLARAT (1 << 8) /* $@ and its special handling -- UNUSED */
#define W_DOLLARSTAR (1 << 9) /* $* and its special handling -- UNUSED */
#define W_DOLLARAT (1 << 8) /* UNUSED - $@ and its special handling */
#define W_DOLLARSTAR (1 << 9) /* UNUSED - $* and its special handling */
#define W_NOCOMSUB (1 << 10) /* Don't perform command substitution on this word */
#define W_ASSIGNRHS (1 << 11) /* Word is rhs of an assignment statement */
#define W_NOTILDE (1 << 12) /* Don't perform tilde expansion on this word */
#define W_ITILDE (1 << 13) /* Internal flag for word expansion */
#define W_NOASSNTILDE (1 << 13) /* don't do tilde expansion like an assignment statement */
#define W_EXPANDRHS (1 << 14) /* Expanding word in ${paramOPword} */
#define W_COMPASSIGN (1 << 15) /* Compound assignment */
#define W_ASSNBLTIN (1 << 16) /* word is a builtin command that takes assignments */
#define W_ASSIGNARG (1 << 17) /* word is assignment argument to command */
#define W_HASQUOTEDNULL (1 << 18) /* word contains a quoted null character */
#define W_DQUOTE (1 << 19) /* word should be treated as if double-quoted */
#define W_DQUOTE (1 << 19) /* UNUSED - word should be treated as if double-quoted */
#define W_NOPROCSUB (1 << 20) /* don't perform process substitution */
#define W_SAWQUOTEDNULL (1 << 21) /* word contained a quoted null that was removed */
#define W_ASSIGNASSOC (1 << 22) /* word looks like associative array assignment */
@@ -102,8 +102,8 @@ enum command_type { cm_for, cm_case, cm_while, cm_if, cm_simple, cm_select,
#define W_NOBRACE (1 << 26) /* Don't perform brace expansion */
#define W_COMPLETE (1 << 27) /* word is being expanded for completion */
#define W_CHKLOCAL (1 << 28) /* check for local vars on assignment */
#define W_NOASSNTILDE (1 << 29) /* don't do tilde expansion like an assignment statement */
#define W_FORCELOCAL (1 << 30) /* force assignments to be to local variables, non-fatal on assignment errors */
#define W_FORCELOCAL (1 << 29) /* force assignments to be to local variables, non-fatal on assignment errors */
/* UNUSED (1 << 30) */
/* Flags for the `pflags' argument to param_expand() and various
parameter_brace_expand_xxx functions; also used for string_list_dollar_at */
+7 -4
View File
@@ -9160,9 +9160,11 @@ is empty, or a non-existent directory stack entry is specified.
.PP
If the
.B popd
command is successful, a
command is successful,
bash runs
.B dirs
is performed as well, and the return status is 0.
to show the final contents of the directory stack,
and the return status is 0.
.RE
.TP
\fBprintf\fP [\fB\-v\fP \fIvar\fP] \fIformat\fP [\fIarguments\fP]
@@ -9271,9 +9273,10 @@ a non-existent directory stack element is specified.
.PP
If the
.B pushd
command is successful, a
command is successful,
bash runs
.B dirs
is performed as well.
to show the final contents of the directory stack.
.RE
.TP
\fBpwd\fP [\fB\-LP\fP]
+5 -3
View File
@@ -7720,8 +7720,9 @@ Otherwise, @code{popd} returns an unsuccessful status if
an invalid option is encountered, the directory stack
is empty, or a non-existent directory stack entry is specified.
If the @code{popd} command is successful, a @code{dirs}
is performed as well, and the return status is 0.
If the @code{popd} command is successful,
Bash runs @code{dirs} to show the final contents of the directory stack,
and the return status is 0.
@btindex pushd
@item pushd
@@ -7764,7 +7765,8 @@ When rotating the directory stack, @code{pushd} returns 0 unless
the directory stack is empty or a non-existent directory stack element
is specified.
If the @code{pushd} command is successful, a @code{dirs} is performed as well.
If the @code{pushd} command is successful,
Bash runs @code{dirs} to show the final contents of the directory stack.
@end table
+6
View File
@@ -1154,6 +1154,12 @@ const char * const _rl_possible_meta_prefixes[] = {
"Meta", "M-", (const char *)NULL
};
/* Forward declarations */
static int parser_if (char *);
static int parser_else (char *);
static int parser_endif (char *);
static int parser_include (char *);
/* Conditionals. */
/* Calling programs set this to have their argv[0]. */
+2 -2
View File
@@ -259,11 +259,11 @@ static void
_rl_nsearch_abort (_rl_search_cxt *cxt)
{
rl_maybe_unsave_line ();
rl_clear_message ();
rl_point = cxt->save_point;
rl_mark = cxt->save_mark;
_rl_fix_point (1);
rl_restore_prompt ();
rl_clear_message ();
_rl_fix_point (1);
RL_UNSETSTATE (RL_STATE_NSEARCH);
}
+1 -1
View File
@@ -251,7 +251,7 @@ make_arith_for_expr (s)
if (s == 0 || *s == '\0')
return ((WORD_LIST *)NULL);
wd = make_word (s);
wd->flags |= W_NOGLOB|W_NOSPLIT|W_QUOTED|W_DQUOTE; /* no word splitting or globbing */
wd->flags |= W_NOGLOB|W_NOSPLIT|W_QUOTED|W_NOTILDE; /* no word splitting or globbing */
#if defined (PROCESS_SUBSTITUTION)
wd->flags |= W_NOPROCSUB; /* no process substitution */
#endif
+1 -1
View File
@@ -4717,7 +4717,7 @@ parse_dparen (c)
{
wd = alloc_word_desc ();
wd->word = wval;
wd->flags = W_QUOTED|W_NOSPLIT|W_NOGLOB|W_DQUOTE;
wd->flags = W_QUOTED|W_NOSPLIT|W_NOGLOB|W_NOTILDE|W_NOPROCSUB;
yylval.word_list = make_word_list (wd, (WORD_LIST *)NULL);
return (ARITH_CMD);
}
+10 -12
View File
@@ -438,11 +438,6 @@ dump_word_flags (flags)
f &= ~W_EXPANDRHS;
fprintf (stderr, "W_EXPANDRHS%s", f ? "|" : "");
}
if (f & W_ITILDE)
{
f &= ~W_ITILDE;
fprintf (stderr, "W_ITILDE%s", f ? "|" : "");
}
if (f & W_NOTILDE)
{
f &= ~W_NOTILDE;
@@ -3283,6 +3278,7 @@ do_assignment_internal (word, expand)
report_error (_("%s: cannot assign list to array member"), name);
ASSIGN_RETURN (0);
}
aflags |= ASS_ALLOWALLSUB;
entry = assign_array_element (name, value, aflags);
if (entry == 0)
ASSIGN_RETURN (0);
@@ -10197,6 +10193,7 @@ expand_word_internal (word, quoted, isexp, contains_dollar_at, expanded_somethin
int had_quoted_null;
int has_quoted_ifs; /* did we add a quoted $IFS character here? */
int has_dollar_at, temp_has_dollar_at;
int internal_tilde;
int split_on_spaces;
int local_expanded;
int tflag;
@@ -10234,6 +10231,7 @@ expand_word_internal (word, quoted, isexp, contains_dollar_at, expanded_somethin
quoted_dollar_at = had_quoted_null = has_dollar_at = 0;
has_quoted_ifs = 0;
split_on_spaces = 0;
internal_tilde = 0; /* expanding =~ or :~ */
quoted_state = UNQUOTED;
string = word->word;
@@ -10298,7 +10296,7 @@ add_string:
{
/* XXX - technically this should only be expanded at the start
of a word */
if (string[++sindex] != LPAREN || (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || (word->flags & (W_DQUOTE|W_NOPROCSUB)))
if (string[++sindex] != LPAREN || (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || (word->flags & W_NOPROCSUB))
{
sindex--; /* add_character: label increments sindex */
goto add_character;
@@ -10349,7 +10347,7 @@ add_string:
assignoff == -1 && sindex > 0)
assignoff = sindex;
if (sindex == assignoff && string[sindex+1] == '~') /* XXX */
word->flags |= W_ITILDE;
internal_tilde = 1;
if (word->flags & W_ASSIGNARG)
word->flags |= W_ASSIGNRHS; /* affects $@ */
@@ -10374,7 +10372,7 @@ add_string:
if ((word->flags & (W_ASSIGNMENT|W_ASSIGNRHS)) &&
(posixly_correct == 0 || (word->flags & W_TILDEEXP)) &&
string[sindex+1] == '~')
word->flags |= W_ITILDE;
internal_tilde = 1;
if (isexp == 0 && (word->flags & (W_NOSPLIT|W_NOSPLIT2)) == 0 && isifs (c))
goto add_ifs_character;
@@ -10387,11 +10385,11 @@ add_string:
assignment statement, we don't do tilde expansion. We don't
do tilde expansion if quoted or in an arithmetic context. */
if ((word->flags & (W_NOTILDE|W_DQUOTE)) ||
(sindex > 0 && ((word->flags & W_ITILDE) == 0)) ||
if ((word->flags & W_NOTILDE) ||
(sindex > 0 && (internal_tilde == 0)) ||
(quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
{
word->flags &= ~W_ITILDE;
internal_tilde = 0;
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
@@ -10407,7 +10405,7 @@ add_string:
temp = bash_tilde_find_word (string + sindex, tflag, &t_index);
word->flags &= ~W_ITILDE;
internal_tilde = 0;
if (temp && *temp && t_index > 0)
{
+1
View File
@@ -55,6 +55,7 @@
#define ASS_NOEVAL 0x0100 /* don't evaluate value as expression */
#define ASS_NOLONGJMP 0x0200 /* don't longjmp on fatal assignment error */
#define ASS_NOINVIS 0x0400 /* don't resolve local invisible variables */
#define ASS_ALLOWALLSUB 0x0800 /* allow * and @ as associative array keys */
/* Flags for the string extraction functions. */
#define SX_NOALLOC 0x0001 /* just skip; don't return substring */
+1 -1
View File
@@ -1,4 +1,4 @@
BUILD_DIR=/usr/local/build/chet/bash/bash-current
BUILD_DIR=/usr/local/build/bash/bash-current
THIS_SH=$BUILD_DIR/bash
PATH=$PATH:$BUILD_DIR
+6 -7
View File
@@ -747,16 +747,15 @@ argv[1] = <b+a>
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" )
./array27.sub: line 45: A[]]: bad array subscript
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" )
./array27.sub: line 53: A[]]: bad array subscript
./array27.sub: line 60: A[]]: bad array subscript
declare -A A=([$'\t']="X" ["*"]="X" [" "]="X" ["@"]="X" )
./array27.sub: line 61: declare: `A[]]=X': not a valid identifier
./array27.sub: line 68: declare: `A[]]=X': not a valid identifier
declare -A A=(["*"]="X" ["@"]="X" )
./array27.sub: line 76: declare: `A[]]=X': not a valid identifier
declare -A A=(["*"]="X" ["@"]="X" )
./array27.sub: line 69: declare: `A[]]=X': not a valid identifier
./array27.sub: line 69: A[*]: bad array subscript
./array27.sub: line 69: A[@]: bad array subscript
declare -A A
declare -a bug4=([0]="" [1]="5" [2]="" [3]="1" [4]="")
declare -a bug=([0]="" [1]="5" [2]="" [3]="1" [4]="")
declare -a bug2=([0]="")
+7 -1
View File
@@ -38,6 +38,13 @@ done
declare -p A
unset A
declare -A A
for k in ']' '*' '@' $'\t' ' '; do
A[$k]=2
done
declare -p A
unset A
declare -A A
@@ -69,4 +76,3 @@ for k in ']' '*' '@'; do
declare "A[$k]=X"
done
declare -p A
+10 -11
View File
@@ -16,25 +16,24 @@ declare -A wheat=([two]="b" [three]="c" [one]="a" [zero]="0" )
declare -A chaff=(["hello world"]="flip" [one]="10" [zero]="5" )
./assoc.tests: line 51: waste: readonly variable
./assoc.tests: line 52: unset: waste: cannot unset: readonly variable
./assoc.tests: line 53: chaff[*]: bad array subscript
./assoc.tests: line 54: [*]=12: invalid associative array key
declare -A chaff=(["hello world"]="flip" [one]="a" )
declare -A chaff=(["*"]="12" ["hello world"]="flip" [one]="a" )
flip
argv[1] = <multiple>
argv[2] = <words>
argv[3] = <12>
argv[4] = <flip>
argv[5] = <a>
argv[1] = <multiple words>
argv[2] = <12>
argv[3] = <flip>
argv[4] = <a>
argv[1] = <multiple words>
argv[2] = <flip>
argv[3] = <a>
argv[1] = <multiple>
argv[2] = <words>
argv[3] = <flip>
argv[4] = <a>
argv[1] = <multiple words flip a>
argv[3] = <12>
argv[4] = <flip>
argv[5] = <a>
argv[1] = <multiple words 12 flip a>
./assoc.tests: line 71: declare: chaff: cannot destroy array variables in this way
./assoc.tests: line 73: chaff[*]: bad array subscript
./assoc.tests: line 74: [*]=12: invalid associative array key
declare -A wheat=([six]="6" ["foo bar"]="qux qix" )
argv[1] = <qux>
argv[2] = <qix>
+1 -1
View File
@@ -47,7 +47,7 @@ declare +i chaff
chaff[hello world]=flip
declare -p chaff
# TEST - errors
# TEST - no longer errors
waste[stuff]=other
unset waste
chaff[*]=12
+2 -3
View File
@@ -168,10 +168,9 @@ after bar: var=global
./varenv13.sub: line 16: `var[0]': not a valid identifier
./varenv13.sub: line 16: `var[@]': not a valid identifier
./varenv13.sub: line 14: declare: var: not found
./varenv13.sub: line 25: var[@]: bad array subscript
declare -A var=([0]="X" )
declare -A var=([0]="X" ["@"]="Y" )
help
./varenv13.sub: line 34: `var[0]': not a valid identifier
./varenv13.sub: line 35: `var[0]': not a valid identifier
1
declare -A var=([0]="X" )
declare -A var=([Y]="Y" )
+1
View File
@@ -22,6 +22,7 @@ typeset -A var
f() { declare -p ${!var*}; }
# this is no longer an error
var[0]=X var[@]=Y
f