]> git.ipfire.org Git - thirdparty/bash.git/commitdiff
minor change to here-doc processing in compoind lists; change to completion to avoid...
authorChet Ramey <chet.ramey@case.edu>
Tue, 4 Jan 2022 16:05:30 +0000 (11:05 -0500)
committerChet Ramey <chet.ramey@case.edu>
Tue, 4 Jan 2022 16:05:30 +0000 (11:05 -0500)
CWRU/CWRU.chlog
bashline.c
parse.y
subst.c
tests/assoc.right
tests/assoc.tests
tests/assoc18.sub [new file with mode: 0644]

index 81d96ae718fd925fd0b273c5de48fcf5c9bf531d..204e6671213b99d80563bafd86e02e964bc5ced7 100644 (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)
index 63891d6a63f5126bd54213a0043e71e9c658511d..1edff1e1fc8c0a5d0f25948c1c956b0545dacd41 100644 (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;
diff --git a/parse.y b/parse.y
index e3b6e6d86fdefbb09529149080a9e69d6bb230af..94195875faec8b8eae22920cb175d329499d9953 100644 (file)
--- a/parse.y
+++ b/parse.y
@@ -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
diff --git a/subst.c b/subst.c
index 72c61dc2b296085c8498f3028057521879575423..a9cb4e2149acd2925377e3d7466387c25e91399d 100644 (file)
--- a/subst.c
+++ b/subst.c
@@ -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
     {
index 3516a6e55aa6a7b41c890da729cf81f5363c85de..9a1662c453376e8ff7e3b05e1c74cab1fdd608c0 100644 (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
index 5fc2b2cff8012e946eff3d9b8787ec81774cc880..c656536b5fadc5c8dba59a877dc62605455500f7 100644 (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
+
diff --git a/tests/assoc18.sub b/tests/assoc18.sub
new file mode 100644 (file)
index 0000000..0597609
--- /dev/null
@@ -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