minor change to here-doc processing in compoind lists; change to completion to avoid quoting word expansion characters like `$'

This commit is contained in:
Chet Ramey
2022-01-04 11:05:30 -05:00
parent 1d17c604fc
commit be7fc0525e
7 changed files with 223 additions and 53 deletions
+39
View File
@@ -2863,3 +2863,42 @@ variables.c
- bind_int_variable: translate the assignment flags (ASS_xxx) to
VA_xxx flags for valid_array_reference calls (ASS_ONEWORD); translate
assignment flags to AV_xxx flags for array_variable_part
12/30
-----
subst.c
- parameter_brace_expand: when expanding an indirect variable, extend
the special case for array[@] and array[*] (set -u/no positional
parameters, obeying the baroque quoting rules) to the value of the
indirection. Report amd fix from konsolebox <konsolebox@gmail.com>
12/31
-----
parse.y
- compound_list: when parsing a compound_list production, collect any
pending here-documents after reading a newline, not after reading
any command terminator. Fixes interactive-only prompting bug
reported back in 8/2021 by Hyunho Cho <mug896@gmail.com>
1/1/2022
--------
bashline.c
- set_filename_quote_chars: break code that modifies
rl_filename_quote_characters based on whether DIRNAME needs to be
expanded from bash_directory_completion_hook into its own function
- bash_check_expchar: break code that checks whether DIRNAME will be
word expanded from bash_directory_completion_hook into its own
function
- bashline_reset,attempt_shell_completion: make sure complete_fullquote
is set to 1 (as it is by default) in case a completion modifies it
- bash_quote_filename: if we are completing (but not expanding --
direxpand is unset) and backslash-quoting a filename with expansion
characters as determined by bash_check_expchar, make sure
filename_bstab is set not to include the expansion char (and any
following char and closer) and set complete_fullquote to 0 so
sh_backslash_quote uses filename_bstab. Fixes the longstanding issue
of quoting a `$', for instance, if the rest of the filename contains
any characters that need quoting in filenames. This assumes that the
filename is unquoted (*QCP == 0) so the word will be expanded and is
not part of the filename (if needed, we can use file_exists to check
whether the expansion characters are actually part of the filename)
+110 -52
View File
@@ -1,6 +1,6 @@
/* bashline.c -- Bash's interface to the readline library. */
/* Copyright (C) 1987-2021 Free Software Foundation, Inc.
/* Copyright (C) 1987-2022 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
@@ -192,6 +192,8 @@ static int return_zero PARAMS((const char *));
static char *bash_dequote_filename PARAMS((char *, int));
static char *quote_word_break_chars PARAMS((char *));
static int bash_check_expchar PARAMS((char *, int, int *, int *));
static void set_filename_quote_chars PARAMS((int, int, int));
static void set_filename_bstab PARAMS((const char *));
static char *bash_quote_filename PARAMS((char *, int, char *));
@@ -674,6 +676,8 @@ bashline_reset ()
rl_attempted_completion_function = attempt_shell_completion;
rl_completion_entry_function = NULL;
rl_ignore_some_completions_function = filename_completion_ignore;
complete_fullquote = 1;
rl_filename_quote_characters = default_filename_quote_characters;
set_filename_bstab (rl_filename_quote_characters);
@@ -1575,6 +1579,7 @@ attempt_shell_completion (text, start, end)
matches = (char **)NULL;
rl_ignore_some_completions_function = filename_completion_ignore;
complete_fullquote = 1; /* full filename quoting by default */
rl_filename_quote_characters = default_filename_quote_characters;
set_filename_bstab (rl_filename_quote_characters);
set_directory_hook ();
@@ -3458,38 +3463,7 @@ bash_directory_completion_hook (dirname)
return_value = should_expand_dirname = nextch = closer = 0;
local_dirname = *dirname;
if (t = mbschr (local_dirname, '$'))
{
should_expand_dirname = '$';
nextch = t[1];
/* Deliberately does not handle the deprecated $[...] arithmetic
expansion syntax */
if (nextch == '(')
closer = ')';
else if (nextch == '{')
closer = '}';
else
nextch = 0;
if (closer)
{
int p;
char delims[2];
delims[0] = closer; delims[1] = 0;
p = skip_to_delim (t, 1, delims, SD_NOJMP|SD_COMPLETE);
if (t[p] != closer)
should_expand_dirname = 0;
}
}
else if (local_dirname[0] == '~')
should_expand_dirname = '~';
else
{
t = mbschr (local_dirname, '`');
if (t && unclosed_pair (local_dirname, strlen (local_dirname), "`") == 0)
should_expand_dirname = '`';
}
should_expand_dirname = bash_check_expchar (local_dirname, 1, &nextch, &closer);
if (should_expand_dirname && directory_exists (local_dirname, 1))
should_expand_dirname = 0;
@@ -3508,24 +3482,8 @@ bash_directory_completion_hook (dirname)
free (new_dirname);
dispose_words (wl);
local_dirname = *dirname;
/* XXX - change rl_filename_quote_characters here based on
should_expand_dirname/nextch/closer. This is the only place
custom_filename_quote_characters is modified. */
if (rl_filename_quote_characters && *rl_filename_quote_characters)
{
int i, j, c;
i = strlen (default_filename_quote_characters);
custom_filename_quote_characters = xrealloc (custom_filename_quote_characters, i+1);
for (i = j = 0; c = default_filename_quote_characters[i]; i++)
{
if (c == should_expand_dirname || c == nextch || c == closer)
continue;
custom_filename_quote_characters[j++] = c;
}
custom_filename_quote_characters[j] = '\0';
rl_filename_quote_characters = custom_filename_quote_characters;
set_filename_bstab (rl_filename_quote_characters);
}
set_filename_quote_chars (should_expand_dirname, nextch, closer);
}
else
{
@@ -4194,6 +4152,95 @@ quote_word_break_chars (text)
return ret;
}
/* Return a character in DIRNAME that will cause shell expansion to be
performed. If NEXTP is non-null, *NEXTP gets the expansion character that
follows RET (e.g., '{' or `(' for `$'). If CLOSERP is non-null, *CLOSERP
gets the character that should close <RET><NEXTP>. If NEED_CLOSER is non-
zero, any expansion pair that isn't closed causes this function to
return 0, which indicates that we didn't find an expansion character. It's
used in case DIRNAME is going to be expanded. If DIRNAME is just going to
be quoted, NEED_CLOSER will be 0. */
static int
bash_check_expchar (dirname, need_closer, nextp, closerp)
char *dirname;
int need_closer;
int *nextp, *closerp;
{
char *t;
int ret, n, c;
ret = n = c = 0;
if (t = mbschr (dirname, '$'))
{
ret = '$';
n = t[1];
/* Deliberately does not handle the deprecated $[...] arithmetic
expansion syntax */
if (n == '(')
c = ')';
else if (n == '{')
c = '}';
else
n = 0;
if (c && need_closer) /* XXX */
{
int p;
char delims[2];
delims[0] = c; delims[1] = 0;
p = skip_to_delim (t, 1, delims, SD_NOJMP|SD_COMPLETE);
if (t[p] != c)
ret = 0;
}
}
else if (dirname[0] == '~')
ret = '~';
else
{
t = mbschr (dirname, '`');
if (t)
{
if (need_closer == 0)
ret = '`';
else if (unclosed_pair (dirname, strlen (dirname), "`") == 0)
ret = '`';
}
}
if (nextp)
*nextp = n;
if (closerp)
*closerp = c;
return ret;
}
/* Make sure EXPCHAR and, if non-zero, NEXTCH and CLOSER are not in the set
of characters to be backslash-escaped. This is the only place
custom_filename_quote_characters is modified. */
static void
set_filename_quote_chars (expchar, nextch, closer)
int expchar, nextch, closer;
{
int i, j, c;
if (rl_filename_quote_characters && *rl_filename_quote_characters)
{
i = strlen (default_filename_quote_characters);
custom_filename_quote_characters = xrealloc (custom_filename_quote_characters, i+1);
for (i = j = 0; c = default_filename_quote_characters[i]; i++)
{
if (c == expchar || c == nextch || c == closer)
continue;
custom_filename_quote_characters[j++] = c;
}
custom_filename_quote_characters[j] = '\0';
rl_filename_quote_characters = custom_filename_quote_characters;
set_filename_bstab (rl_filename_quote_characters);
}
}
/* Use characters in STRING to populate the table of characters that should
be backslash-quoted. The table will be used for sh_backslash_quote from
this file. */
@@ -4222,6 +4269,7 @@ bash_quote_filename (s, rtype, qcp)
{
char *rtext, *mtext, *ret;
int rlen, cs;
int expchar, nextch, closer;
rtext = (char *)NULL;
@@ -4239,7 +4287,17 @@ bash_quote_filename (s, rtype, qcp)
the word being completed contains newlines, since those are not
quoted correctly using backslashes (a backslash-newline pair is
special to the shell parser). */
if (*qcp == '\0' && cs == COMPLETE_BSQUOTE && mbschr (s, '\n'))
expchar = nextch = closer = 0;
if (*qcp == '\0' && cs == COMPLETE_BSQUOTE && dircomplete_expand == 0 &&
(expchar = bash_check_expchar (s, 0, &nextch, &closer)))
{
/* Usually this will have been set by bash_directory_completion_hook, but
there are rare cases where it will not be. */
if (rl_filename_quote_characters != custom_filename_quote_characters)
set_filename_quote_chars (expchar, nextch, closer);
complete_fullquote = 0;
}
else if (*qcp == '\0' && cs == COMPLETE_BSQUOTE && mbschr (s, '\n'))
cs = COMPLETE_SQUOTE;
else if (*qcp == '"')
cs = COMPLETE_DQUOTE;
+1 -1
View File
@@ -1119,7 +1119,7 @@ pattern: WORD
compound_list: newline_list list0
{
$$ = $2;
if (need_here_doc)
if (need_here_doc && last_read_token == '\n')
gather_here_documents ();
}
| newline_list list1
+5
View File
@@ -9352,6 +9352,11 @@ parameter_brace_expand (string, indexp, quoted, pflags, quoted_dollar_atp, conta
to return the index we're supposed to be using. */
if (tdesc && tdesc->flags)
tdesc->flags &= ~W_ARRAYIND;
/* If the indir expansion contains $@/$*, extend the special treatment
of the case of no positional parameters and `set -u' to it. */
if (contains_dollar_at && *contains_dollar_at)
all_element_arrayref = 1;
}
else
{
+5
View File
@@ -393,3 +393,8 @@ declare -A A=(["]"]="rbracket" ["["]="lbracket" )
declare -A A=()
declare -A A=(["]"]="rbracket" ["["]="lbracket" )
declare -A A=()
declare -A A=(["]"]="rbracket" ["["]="lbracket" )
declare -A A=()
declare -A A=(["]"]="rbracket" ["["]="lbracket" )
declare -A A=()
5: ok 1
+4
View File
@@ -262,3 +262,7 @@ ${THIS_SH} ./assoc16.sub
# tests with `[' and `]' subscripts and `unset'
${THIS_SH} ./assoc17.sub
# tests with `[' and `]' subscripts and printf/read/wait builtins
${THIS_SH} ./assoc18.sub
+59
View File
@@ -0,0 +1,59 @@
# 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/>.
#
# test behavior of builtins that can take array subscript arguments, make
# sure they work in the presence of associative arrays and `problematic' keys
# if assoc_expand_once is set
#
# affected builtins: printf, read, wait
declare -A A
rkey=']'
lkey='['
shopt -s assoc_expand_once
printf -v A[$rkey] rbracket
printf -v A[$lkey] lbracket
declare -p A
unset A[$rkey]
unset A[$lkey]
declare -p A
unset A
declare -A A
read A[$rkey] <<<rbracket
read A[$lkey] <<<lbracket
declare -p A
unset A[$rkey]
unset A[$lkey]
declare -p A
unset A
declare -A A
{ sleep 1 ; exit 4; } &
{ sleep 2 ; exit 5; } & bgpid1=$!
{ sleep 4 ; exit 6; } &
wait -p A[$rkey] -n %2 %3
case "${A[$rkey]}" in
$bgpid1) echo $?: ok 1;;
*) echo bad 1;;
esac
exit 0