]> git.ipfire.org Git - thirdparty/bash.git/commitdiff
fix expansion of $* and $@ in contexts where word splitting is not performed to be...
authorChet Ramey <chet.ramey@case.edu>
Mon, 24 Nov 2025 14:51:15 +0000 (09:51 -0500)
committerChet Ramey <chet.ramey@case.edu>
Mon, 24 Nov 2025 14:51:15 +0000 (09:51 -0500)
13 files changed:
CWRU/CWRU.chlog
MANIFEST
builtins/help.def
subst.c
tests/RUN-ONE-TEST
tests/RUN-TEST-SCRIPT
tests/builtins.right
tests/builtins10.sub
tests/exp.right
tests/exp.tests
tests/exp14.sub [new file with mode: 0644]
tests/run-all
variables.c

index 6698b8378296acd4777e3752e9d8a69579ccc4e5..8580314bf363276dbc5ad3d4c271450401692c64 100644 (file)
@@ -12253,3 +12253,32 @@ sig.c
 doc/bash.1,doc/bashref.texi
        - fix some options typeset in the wrong font
          Report and patch from Grisha Levit <grishalevit@gmail.com>
+
+subst.c
+       - list_remove_pattern,parameter_list_remove_pattern,array_remove_pattern,
+         parameter_brace_remove_pattern: take an additional PFLAGS argument
+         from the PFLAGS passed to parameter_brace_expand
+       - list_remove_pattern: pass PFLAGS to string_list_pos_params so it can
+         get the right expansion of `@' and `*'
+         Report by Emanuele Torre <torreemanuele6@gmail.com>
+
+                                  11/18
+                                  -----
+variables.c
+       - get_bash_name: only call sh_canonpath on the directory portion of
+         the full pathname to the current executable; it only works on
+         directories. Then glue the return value and the trailing component
+         together to get the full pathname
+         Report from Stan Marsh <gazelle@xmission.com>
+
+                                  11/20
+                                  -----
+subst.c
+       - parameter_list_transform,array_transform,list_transform: add an
+         extra PFLAGS argument, passed down from parameter_brace_transform
+       - list_transform,array_transform: pass PFLAGS to string_list_pos_params
+         so it can get the right expansion of `@' and `*'
+         This makes all the quoted and unquoted expansions of `@' consistent
+         when they are expanded in a context that will not perform word
+         splitting
+         Report by Emanuele Torre <torreemanuele6@gmail.com>
index 7f965be547496b14769404fdfd152407b3a2108f..d1b00de7d74e84f3e3cf493df40630b3b8d18d8d 100644 (file)
--- a/MANIFEST
+++ b/MANIFEST
@@ -1204,6 +1204,7 @@ tests/exp10.sub           f
 tests/exp11.sub                f
 tests/exp12.sub                f
 tests/exp13.sub                f
+tests/exp14.sub                f
 tests/exportfunc.tests f
 tests/exportfunc.right f
 tests/exportfunc1.sub  f
index f6db8a95f8e8426b707a9c4966779ba022af5d1c..f2a975bcb81ebd29dbc956ac636bb68604029675 100644 (file)
@@ -135,7 +135,7 @@ help_builtin (WORD_LIST *list)
 
       globpat = glob_pattern_p (pattern);
       if (globpat)
-       printf (_("Shell commands matching pattern '%s':\n\n"), pattern);
+       printf (_("Shell commands matching pattern '%s':\n"), pattern);
 
       for (pass = 1, this_found = 0; pass < 3; pass++)
        {
@@ -153,6 +153,8 @@ help_builtin (WORD_LIST *list)
 
              if (m)
                {
+                 if (globpat && this_found == 0)
+                   putchar ('\n');
                  this_found = 1;
                  match_found++;
                  if (dflag)
diff --git a/subst.c b/subst.c
index 34754189f71395855485aaf0581c0bdc3ae28856..bdbafac8f5ab06dfb26da98437daa9f1313892ff 100644 (file)
--- a/subst.c
+++ b/subst.c
@@ -299,23 +299,23 @@ static int match_pattern (char *, char *, int, char **, char **);
 static int getpatspec (int, const char *);
 static char *getpattern (char *, int, int);
 static char *variable_remove_pattern (char *, char *, int, int);
-static char *list_remove_pattern (WORD_LIST *, char *, int, int, int);
-static char *parameter_list_remove_pattern (int, char *, int, int);
+static char *list_remove_pattern (WORD_LIST *, char *, int, int, int, int);
+static char *parameter_list_remove_pattern (int, char *, int, int, int);
 #ifdef ARRAY_VARS
-static char *array_remove_pattern (SHELL_VAR *, char *, int, int, int);
+static char *array_remove_pattern (SHELL_VAR *, char *, int, int, int, int);
 #endif
-static char *parameter_brace_remove_pattern (char *, char *, array_eltstate_t *, char *, int, int, int);
+static char *parameter_brace_remove_pattern (char *, char *, array_eltstate_t *, char *, int, int, int, int);
 
 static char *string_var_assignment (SHELL_VAR *, char *);
 #if defined (ARRAY_VARS)
 static char *array_var_assignment (SHELL_VAR *, int, int, int);
 #endif
-static char *pos_params_assignment (WORD_LIST *, int, int);
+static char *pos_params_assignment (WORD_LIST *, int, int, int);
 static char *string_transform (int, SHELL_VAR *, char *);
-static char *list_transform (int, SHELL_VAR *, WORD_LIST *, int, int);
-static char *parameter_list_transform (int, int, int);
+static char *list_transform (int, SHELL_VAR *, WORD_LIST *, int, int, int);
+static char *parameter_list_transform (int, int, int, int);
 #if defined ARRAY_VARS
-static char *array_transform (int, SHELL_VAR *, int, int);
+static char *array_transform (int, SHELL_VAR *, int, int, int);
 #endif
 static char *parameter_brace_transform (char *, char *, array_eltstate_t *, char *, int, int, int, int);
 static int valid_parameter_transform (const char *);
@@ -3045,6 +3045,7 @@ string_list_dollar_at (WORD_LIST *list, int quoted, int flags)
    string_list as appropriate. */
 /* This needs to fully understand the additional contexts where word
    splitting does not occur (W_ASSIGNRHS, etc.) */
+/* XXX - does this need to handle (pflags & PF_NOSPLIT2)? */
 char *
 string_list_pos_params (int pchar, WORD_LIST *list, int quoted, int pflags)
 {
@@ -3086,9 +3087,18 @@ string_list_pos_params (int pchar, WORD_LIST *list, int quoted, int pflags)
   else if (pchar == '@' && quoted == 0 && ifs_is_null) /* XXX */
     ret = string_list_dollar_at (list, quoted, 0);     /* Posix interp 888 */
   else if (pchar == '@' && quoted == 0 && (pflags & PF_ASSIGNRHS))
+    /* XXX - param_expand uses quoted|Q_DOUBLE_QUOTES for this case, but
+       that quotes the escapes. We could use string_list_internal with " "
+       as the second argument. */
     ret = string_list_dollar_at (list, quoted, pflags);        /* Posix interp 888 */
   else if (pchar == '@')
+#if 0
+    /* XXX - param_expand uses string_list_dollar_at() for this case. */
+    /* string_list_dollar_at quotes CTLESC, even if quoted == 0 */
+    ret = string_list_dollar_at (list, quoted, 0);
+#else
     ret = string_list_dollar_star (list, quoted, 0);
+#endif
   else
     ret = string_list ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? quote_list (list) : list);
 
@@ -5777,7 +5787,7 @@ variable_remove_pattern (char *value, char *pattern, int patspec, int quoted)
 #endif
 
 static char *
-list_remove_pattern (WORD_LIST *list, char *pattern, int patspec, int itype, int quoted)
+list_remove_pattern (WORD_LIST *list, char *pattern, int patspec, int itype, int quoted, int pflags)
 {
   WORD_LIST *new, *l;
   WORD_DESC *w;
@@ -5792,14 +5802,14 @@ list_remove_pattern (WORD_LIST *list, char *pattern, int patspec, int itype, int
     }
 
   l = REVERSE_LIST (new, WORD_LIST *);
-  tword = string_list_pos_params (itype, l, quoted, 0);
+  tword = string_list_pos_params (itype, l, quoted, pflags);
   dispose_words (l);
 
   return (tword);
 }
 
 static char *
-parameter_list_remove_pattern (int itype, char *pattern, int patspec, int quoted)
+parameter_list_remove_pattern (int itype, char *pattern, int patspec, int quoted, int pflags)
 {
   char *ret;
   WORD_LIST *list;
@@ -5807,7 +5817,7 @@ parameter_list_remove_pattern (int itype, char *pattern, int patspec, int quoted
   list = list_rest_of_args ();
   if (list == 0)
     return ((char *)NULL);
-  ret = list_remove_pattern (list, pattern, patspec, itype, quoted);
+  ret = list_remove_pattern (list, pattern, patspec, itype, quoted, pflags);
   dispose_words (list);
   return (ret);
 }
@@ -5815,7 +5825,7 @@ parameter_list_remove_pattern (int itype, char *pattern, int patspec, int quoted
 #if defined (ARRAY_VARS)
 /* STARSUB is so we can figure out how it's indexed */
 static char *
-array_remove_pattern (SHELL_VAR *var, char *pattern, int patspec, int starsub, int quoted)
+array_remove_pattern (SHELL_VAR *var, char *pattern, int patspec, int starsub, int quoted, int pflags)
 {
   ARRAY *a;
   HASH_TABLE *h;
@@ -5834,7 +5844,7 @@ array_remove_pattern (SHELL_VAR *var, char *pattern, int patspec, int starsub, i
   list = a ? array_to_word_list (a) : (h ? assoc_to_word_list (h) : 0);
   if (list == 0)
    return ((char *)NULL);
-  ret = list_remove_pattern (list, pattern, patspec, itype, quoted);
+  ret = list_remove_pattern (list, pattern, patspec, itype, quoted, pflags);
   dispose_words (list);
 
   return ret;
@@ -5844,7 +5854,7 @@ array_remove_pattern (SHELL_VAR *var, char *pattern, int patspec, int starsub, i
 static char *
 parameter_brace_remove_pattern (char *varname, char *value,
                                array_eltstate_t *estatep, char *patstr,
-                               int rtype, int quoted, int flags)
+                               int rtype, int quoted, int pflags, int flags)
 {
   int vtype, patspec, starsub;
   char *temp1, *val, *pattern, *oname;
@@ -5894,7 +5904,7 @@ parameter_brace_remove_pattern (char *varname, char *value,
       break;
 #if defined (ARRAY_VARS)
     case VT_ARRAYVAR:
-      temp1 = array_remove_pattern (v, pattern, patspec, starsub, quoted);
+      temp1 = array_remove_pattern (v, pattern, patspec, starsub, quoted, pflags);
       if (temp1 && ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0))
        {
          val = quote_escapes (temp1);
@@ -5904,7 +5914,7 @@ parameter_brace_remove_pattern (char *varname, char *value,
       break;
 #endif
     case VT_POSPARMS:
-      temp1 = parameter_list_remove_pattern (varname[0], pattern, patspec, quoted);
+      temp1 = parameter_list_remove_pattern (varname[0], pattern, patspec, quoted, pflags);
       if (temp1 && quoted == 0 && ifs_is_null)
        {
          /* Posix interp 888 */
@@ -8783,12 +8793,12 @@ array_var_assignment (SHELL_VAR *v, int itype, int quoted, int atype)
 #endif
 
 static char *
-pos_params_assignment (WORD_LIST *list, int itype, int quoted)
+pos_params_assignment (WORD_LIST *list, int itype, int quoted, int pflags)
 {
   char *temp, *ret;
 
   /* first, we transform the list to quote each word. */
-  temp = list_transform ('Q', (SHELL_VAR *)0, list, itype, quoted);
+  temp = list_transform ('Q', (SHELL_VAR *)0, list, itype, quoted, 0);
   ret = (char *)xmalloc (strlen (temp) + 8);
   strcpy (ret, "set -- ");
   strcpy (ret + 7, temp);
@@ -8848,7 +8858,7 @@ string_transform (int xc, SHELL_VAR *v, char *s)
 }
 
 static char *
-list_transform (int xc, SHELL_VAR *v, WORD_LIST *list, int itype, int quoted)
+list_transform (int xc, SHELL_VAR *v, WORD_LIST *list, int itype, int quoted, int pflags)
 {
   WORD_LIST *new, *l;
   WORD_DESC *w;
@@ -8870,14 +8880,14 @@ list_transform (int xc, SHELL_VAR *v, WORD_LIST *list, int itype, int quoted)
   if (itype == '*' && expand_no_split_dollar_star && ifs_is_null)
     qflags |= Q_DOUBLE_QUOTES;         /* Posix interp 888 */
 
-  tword = string_list_pos_params (itype, l, qflags, 0);
+  tword = string_list_pos_params (itype, l, qflags, pflags);
   dispose_words (l);
 
   return (tword);
 }
 
 static char *
-parameter_list_transform (int xc, int itype, int quoted)
+parameter_list_transform (int xc, int itype, int quoted, int pflags)
 {
   char *ret;
   WORD_LIST *list;
@@ -8886,9 +8896,9 @@ parameter_list_transform (int xc, int itype, int quoted)
   if (list == 0)
     return ((char *)NULL);
   if (xc == 'A')
-    ret = pos_params_assignment (list, itype, quoted);
+    ret = pos_params_assignment (list, itype, quoted, pflags);
   else
-    ret = list_transform (xc, (SHELL_VAR *)0, list, itype, quoted);
+    ret = list_transform (xc, (SHELL_VAR *)0, list, itype, quoted, pflags);
   dispose_words (list);
   return (ret);
 }
@@ -8896,7 +8906,7 @@ parameter_list_transform (int xc, int itype, int quoted)
 #if defined (ARRAY_VARS)
 /* STARSUB so we can figure out how it's indexed */
 static char *
-array_transform (int xc, SHELL_VAR *var, int starsub, int quoted)
+array_transform (int xc, SHELL_VAR *var, int starsub, int quoted, int pflags)
 {
   ARRAY *a;
   HASH_TABLE *h;
@@ -8939,7 +8949,7 @@ array_transform (int xc, SHELL_VAR *var, int starsub, int quoted)
       if (itype == '*' && expand_no_split_dollar_star && ifs_is_null)
        qflags |= Q_DOUBLE_QUOTES;              /* Posix interp 888 */
 
-      ret = string_list_pos_params (itype, list, qflags, 0);
+      ret = string_list_pos_params (itype, list, qflags, pflags);
       dispose_words (list);
       return ret;
     }
@@ -8947,7 +8957,7 @@ array_transform (int xc, SHELL_VAR *var, int starsub, int quoted)
   list = a ? array_to_word_list (a) : (h ? assoc_to_word_list (h) : 0);
   if (list == 0)
    return ((char *)NULL);
-  ret = list_transform (xc, v, list, itype, quoted);
+  ret = list_transform (xc, v, list, itype, quoted, pflags);
   dispose_words (list);
 
   return ret;
@@ -9035,7 +9045,7 @@ parameter_brace_transform (char *varname, char *value, array_eltstate_t *estatep
       break;
 #if defined (ARRAY_VARS)
     case VT_ARRAYVAR:
-      temp1 = array_transform (xc, v, starsub, quoted);
+      temp1 = array_transform (xc, v, starsub, quoted, pflags);
       if (temp1 && quoted == 0 && ifs_is_null)
        {
                /* Posix interp 888 */
@@ -9049,7 +9059,7 @@ parameter_brace_transform (char *varname, char *value, array_eltstate_t *estatep
       break;
 #endif
     case VT_POSPARMS:
-      temp1 = parameter_list_transform (xc, varname[0], quoted);
+      temp1 = parameter_list_transform (xc, varname[0], quoted, pflags);
       if (temp1 && quoted == 0 && ifs_is_null)
        {
                /* Posix interp 888 */
@@ -10391,7 +10401,7 @@ bad_substitution:
          FREE (value);
          break;
        }
-      temp1 = parameter_brace_remove_pattern (name, temp, &es, value, c, quoted, (tflag & W_ARRAYIND) ? AV_USEIND : 0);
+      temp1 = parameter_brace_remove_pattern (name, temp, &es, value, c, quoted, pflags, (tflag & W_ARRAYIND) ? AV_USEIND : 0);
       free (temp);
       free (value);
 #if defined (ARRAY_VARS)
index f3a23b8f8e88afd74c77ff33c2bab39be54449c0..74e5889061142b1bb35e7af40365d3a36a81bf9d 100755 (executable)
@@ -12,7 +12,8 @@ rm -f ${BASH_TSTOUT}
 
 if [ -t 1 ]; then
        if type -P tput >/dev/null; then
-               CSTART=$(tput setaf 15 setab 1) CEND=$(tput sgr0)
+#              CSTART=$(tput setaf 15 setab 1) CEND=$(tput sgr0)
+               CSTART=$(tput bold ; tput setab 9 ; tput setaf 7) CEND=$(tput sgr0)
        else
                # can't rely on having $'...' or printf understanding \e
                # bright red background, white foreground text
index fec43b2de9bef774555dcc3a6e6b1c2a7b4f1c8a..814cfbc166894e251219459dcf968a30e3dcfe87 100755 (executable)
@@ -12,7 +12,8 @@ rm -f ${BASH_TSTOUT}
 
 if [ -t 1 ]; then
        if type -P tput >/dev/null; then
-               CSTART=$(tput setaf 15 setab 1) CEND=$(tput sgr0)
+#              CSTART=$(tput setaf 15 setab 1) CEND=$(tput sgr0)
+               CSTART=$(tput bold ; tput setab 9 ; tput setaf 7) CEND=$(tput sgr0)
        else
                # can't rely on having $'...' or printf understanding \e
                # bright red background, white foreground text
index 740dc47f082cbc40eb54b6f921eb463c6b8e7a94..d7fcd38fbf0aff1db63843cb323756a36e0e67c6 100644 (file)
@@ -354,7 +354,7 @@ found
 ./builtins9.sub: line 52: hash: /: Is a directory
 builtin hash -p /nosuchfile cat
        builtins10.sub
-./builtins10.sub: line 17: help: -x: invalid option
+./builtins10.sub: line 19: help: -x: invalid option
 help: usage: help [-dms] [pattern ...]
 These shell commands are defined internally.  Type `help' to see this list.
 Type `help name' to find out more about the function `name'.
@@ -495,7 +495,9 @@ A star (*) next to a name means that the command is disabled.
  getopts optstring name [arg ...]        while COMMANDS; do COMMANDS-2; done
  hash [-lr] [-p pathname] [-dt] [name >  { COMMANDS ; }
  help [-dms] [pattern ...]
-./builtins10.sub: line 39: help: no help topics match 'bash'. Try 'help help', 'man -k bash', or 'info bash'.
+./builtins10.sub: line 41: help: no help topics match 'bash'. Try 'help help', 'man -k bash', or 'info bash'.
+Shell commands matching pattern 'ad*x':
+./builtins10.sub: line 44: help: no help topics match 'ad*x'.
        builtins11.sub
 unlimited
 unlimited
index e8413f819b8f235a664745c74cee616ba922c175..326079652a2b1c096940fa9c5bcda425257af746 100644 (file)
@@ -13,6 +13,8 @@
 #
 # have to run through sed or grep to filter out version information
 
+COLUMNS=80
+
 # let's exercise print-help
 help -x
 
@@ -37,3 +39,6 @@ help -- | sed 1d
 
 # maybe sometime in the future this will do something
 help -- bash
+
+# Tinkering with format for pattern output
+help 'ad*x'
index ac4e014a7f7f704557ca0fabaad669d95472218b..739e68d0f6739a3b0020fd9b5464391a314dc1cb 100644 (file)
@@ -446,3 +446,31 @@ declare -i a="7"
 declare -- a="42"
 FOO
 declare -u A="FOO"
+       exp14.sub
+!Q= <a b c> <a:b:c>
+ Q= <a b c> <a:b:c>
+!Q= <a b c> <a:b:c>
+Q= <a b c> <a:b:c>
+!Q- <a b c> <a:b:c>
+ Q- <a b c> <a:b:c>
+!Q? <a b c> <a:b:c>
+ Q? <a b c> <a:b:c>
+!Q+ <a b c> <a:b:c>
+ Q+ <a b c> <a:b:c>
++Q+ <a b c> <a:b:c>
+!Q: <a b c> <a:b:c>
+Q: <a:b:c> <a:b:c>
+!Q# <a b c> <a:b:c>
+Q# <a:b:c> <a:b:c>
+!Q% <a b c> <a:b:c>
+Q% <a:b:c> <a:b:c>
+!Q/ <x x x> <x:x:x>
+Q/ <x:x:x> <x:x:x>
+!Q^ <A B C> <A:B:C>
+Q^ <A:B:C> <A:B:C>
+!Q, <a b c> <a:b:c>
+Q, <a:b:c> <a:b:c>
+!Q@Q <'a' 'b' 'c'> <'a':'b':'c'>
+Q@Q <'a':'b':'c'> <'a':'b':'c'>
+!Q@A <set -- 'a':'b':'c'> <set -- 'a':'b':'c'>
+Q@A <set -- 'a':'b':'c'> <set -- 'a':'b':'c'>
index ca752fdc867341606636df97050e79ca1608328c..f61b6eb21122f7cd99a466a0a26331601e2291cc 100644 (file)
@@ -430,3 +430,4 @@ test_runsub ./exp10.sub
 test_runsub ./exp11.sub
 test_runsub ./exp12.sub
 test_runsub ./exp13.sub
+test_runsub ./exp14.sub
diff --git a/tests/exp14.sub b/tests/exp14.sub
new file mode 100644 (file)
index 0000000..bfe4b29
--- /dev/null
@@ -0,0 +1,69 @@
+#   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/>.
+#
+#
+# tests for quoted and unquoted expansions of $@/$* in contexts without
+# word splitting
+
+set -- a b c
+OIFS="$IFS"
+
+IFS=:; o=$@ s=$*;               printf '!Q= <%s> <%s>\n' "$o" "$s" ; IFS=$OIFS
+IFS=:; o="$@" s="$*";           printf ' Q= <%s> <%s>\n' "$o" "$s" ; IFS=$OIFS
+IFS=:; o=${@} s=${*};           printf '!Q= <%s> <%s>\n' "$o" "$s" ; IFS=$OIFS
+IFS=:; o="${@}" s="${*}";       printf 'Q= <%s> <%s>\n' "$o" "$s" ; IFS=$OIFS
+IFS=:; o=${@-x} s=${*-x};       printf '!Q- <%s> <%s>\n' "$o" "$s" ; IFS=$OIFS
+IFS=:; o="${@-x}" s="${*-x}";   printf ' Q- <%s> <%s>\n' "$o" "$s" ; IFS=$OIFS
+IFS=:; o=${@?x} s=${*?x};       printf '!Q? <%s> <%s>\n' "$o" "$s" ; IFS=$OIFS
+IFS=:; o="${@?x}" s="${*?x}";   printf ' Q? <%s> <%s>\n' "$o" "$s" ; IFS=$OIFS
+IFS=:; o=${@+$@} s=${*+$*};     printf '!Q+ <%s> <%s>\n' "$o" "$s" ; IFS=$OIFS
+IFS=:; o="${@+$@}" s="${*+$*}"; printf ' Q+ <%s> <%s>\n' "$o" "$s" ; IFS=$OIFS
+IFS=:; o=${@+"$@"} s=${*+"$*"}; printf '+Q+ <%s> <%s>\n' "$o" "$s" ; IFS=$OIFS
+
+# positional parameter substring expansion
+IFS=:; o=${@:1} s=${*:1}; printf '!Q: <%s> <%s>\n' "$o" "$s" ; IFS=$OIFS
+IFS=:; o="${@:1}" s="${*:1}"; printf 'Q: <%s> <%s>\n' "$o" "$s" ; IFS=$OIFS
+
+set -- aa bb cc
+
+# positional parameter pattern removal
+IFS=:; o=${@#?} s=${*#?}; printf '!Q# <%s> <%s>\n' "$o" "$s" ; IFS=$OIFS
+IFS=:; o="${@#?}" s="${*#?}"; printf 'Q# <%s> <%s>\n' "$o" "$s" ; IFS=$OIFS
+
+IFS=:; o=${@%?} s=${*%?}; printf '!Q%% <%s> <%s>\n' "$o" "$s" ; IFS=$OIFS
+IFS=:; o="${@%?}" s="${*%?}"; printf 'Q%% <%s> <%s>\n' "$o" "$s" ; IFS=$OIFS
+
+set -- a b c
+
+# positional parameter pattern substitution
+IFS=:; o=${@/?/x} s=${*/?/x}; printf '!Q/ <%s> <%s>\n' "$o" "$s" ; IFS=$OIFS
+IFS=:; o="${@/?/x}" s="${*/?/x}"; printf 'Q/ <%s> <%s>\n' "$o" "$s" ; IFS=$OIFS
+
+# positional parameter case modification
+IFS=:; o=${@^[abc]} s=${*^[abc]}; printf '!Q^ <%s> <%s>\n' "$o" "$s" ; IFS=$OIFS
+IFS=:; o="${@^[abc]}" s="${*^[abc]}"; printf 'Q^ <%s> <%s>\n' "$o" "$s" ; IFS=$OIFS
+
+set -- A B C
+
+IFS=:; o=${@,[ABC]} s=${*,[ABC]}; printf '!Q, <%s> <%s>\n' "$o" "$s" ; IFS=$OIFS
+IFS=:; o="${@,[ABC]}" s="${*,[ABC]}"; printf 'Q, <%s> <%s>\n' "$o" "$s" ; IFS=$OIFS
+
+set -- a b c
+
+# positional parameter transformation -- quoting
+IFS=:; o=${@@Q} s=${*@Q}; printf '!Q@Q <%s> <%s>\n' "$o" "$s" ; IFS=$OIFS
+IFS=:; o="${@@Q}" s="${*@Q}"; printf 'Q@Q <%s> <%s>\n' "$o" "$s" ; IFS=$OIFS
+
+# positional parameter transformation -- assignment
+IFS=:; o=${@@A} s=${*@A}; printf '!Q@A <%s> <%s>\n' "$o" "$s" ; IFS=$OIFS
+IFS=:; o="${@@A}" s="${*@A}"; printf 'Q@A <%s> <%s>\n' "$o" "$s" ; IFS=$OIFS
index cf795478391298fb52ad42f3bcb15d307e205482..762d662d153b3fc3a65ee19ec469d28fc9e1ec45 100644 (file)
@@ -63,7 +63,8 @@ echo Any output from any test, unless otherwise noted, indicates a possible anom
 # keep track of passed and failed tests and report them
 if [ -t 1 ]; then
        if type -P tput >/dev/null; then
-               CSTART=$(tput setaf 15 setab 1) CEND=$(tput sgr0)
+#              CSTART=$(tput bold ; tput setaf 15 ; tput setab 1) CEND=$(tput sgr0)
+               CSTART=$(tput bold ; tput setab 9 ; tput setaf 7) CEND=$(tput sgr0)
        else
                # can't rely on having $'...' or printf understanding \e
                # bright red background, white foreground text
index 6a03175e0bec83efb84fa73b07d8550234871a0d..00a73da842391c006c728f4887925ac913f2ba90 100644 (file)
@@ -820,11 +820,24 @@ get_bash_name (void)
              tname = make_absolute (shell_name, get_string_value ("PWD"));
              if (*shell_name == '.')
                {
+                 char *x, *fp;
+
+                 x = strrchr (tname, '/');
+                 *x = 0;
                  name = sh_canonpath (tname, PATH_CHECKDOTDOT|PATH_CHECKEXISTS);
+                 *x++ = '/';
                  if (name == 0)
                    name = tname;
                  else
-                   free (tname);
+                   {
+                     fp = sh_makepath (name, x, 0);
+                     free (tname);
+                     if (fp)
+                       {
+                         free (name);
+                         name = fp;
+                       }
+                   }
                }
             else
                name = tname;