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
+
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);
{
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;
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);
}
}
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;
}
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);
/* 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 */
/* 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.
#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 */
#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 */
.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]
.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]
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
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
"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]. */
_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);
}
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
{
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);
}
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;
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);
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;
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;
{
/* 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;
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 $@ */
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;
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
temp = bash_tilde_find_word (string + sindex, tflag, &t_index);
- word->flags &= ~W_ITILDE;
+ internal_tilde = 0;
if (temp && *temp && t_index > 0)
{
#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 */
-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
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]="")
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
declare "A[$k]=X"
done
declare -p A
-
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>
chaff[hello world]=flip
declare -p chaff
-# TEST - errors
+# TEST - no longer errors
waste[stuff]=other
unset waste
chaff[*]=12
./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" )
f() { declare -p ${!var*}; }
+# this is no longer an error
var[0]=X var[@]=Y
f