As I've mentioned in the past, if you see ksh-like behavior in zsh that doesn't quite match ksh, it's often because the ksh behavior was implemented based on reading examples from the ksh manual pages way back when ksh was proprietary software and unavailable for running a comparison.
Other times it's because the ksh behavior or syntax conflicted with something else zsh was already doing.
Expands to name of the subscript unless subscript is *, @. or of the form sub1 .. sub2. When subscript is *, the list of array subscripts for vname is generated. For a variable that is not an array, the value is 0 if the variable is set. Otherwise it is the empty string. When subscript is @, same as above, except that when used in double quotes, each array subscript yields a separate argument. When subscript is of the form sub1 .. sub2 it expands to the list of subscripts between sub1 and sub2 inclusive using the same quoting rules as @.
--- expected
+++ actual
@@ -1,3 +1,3 @@
+characters
.k02.array
-.k02.array
characters
Test K02parameter.ztst failed: output differs from expected as shown above for:
() {
typeset -n .k02.ref=.k02.array
emulate -L ksh
print -l ${!.k02.ref} ${(!).k02.ref} ${.k02.ref}
}
Was testing: namerefs with namespaces
K02parameter.ztst: test failed.
> Below is a patch that changes Zsh's emulation of ksh to map ksh's ! to just (k) instead of (!k). Note that the flag combination (!k) is forbidden, which I think is right.
This doesn't look right to me? The test is prefixed with
.k02.array=(characters in an array)
${!.k02.ref} should not return "characters" ...? That makes '!' just
a no-op for this case.
diff --git a/Src/subst.c b/Src/subst.c
index 1b75c035a..efbd81105 100644
--- a/Src/subst.c
+++ b/Src/subst.c
@@ -2118,7 +2118,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags,
* handle this with the ^, =, ~ stuff, below.
*/
if ((c = *s) == '!' && s[1] != Outbrace && EMULATION(EMULATE_KSH)) {
- hkeys = SCANPM_WANTKEYS|SCANPM_NONAMEREF;
+ hkeys = SCANPM_WANTKEYS;
s++;
/* There's a slew of other special bash meanings of parameter
* references that start with "!":
diff --git a/Test/K01nameref.ztst b/Test/K01nameref.ztst
index 0e1cc9e4e..bfc8ee508 100644
--- a/Test/K01nameref.ztst
+++ b/Test/K01nameref.ztst
@@ -2363,4 +2363,59 @@ F:converting from association/array to string should work here too
typeset -Hn ref_H
0:unsusual but legal option combinations
+ typeset str0=abc
+ typeset -a arr0=(aa bb cc)
+ typeset -A hsh0=([0]=aa [1]=bb [2]=cc)
+ typeset -n str1=str0 arr1=arr0 hsh1=hsh0
+ typeset -n str2=str1 arr2=arr1 hsh2=hsh1
+ emulate ksh -c '
+ echo "${str0} - ${str1} - ${str2}"
+ echo "${str0[1]} - ${str1[1]} - ${str2[1]}"
+ echo "${str0[1,2]} - ${str1[1,2]} - ${str2[1,2]}"
+ echo "${str0[@]} - ${str1[@]} - ${str2[@]}"
+ echo "${arr0} - ${arr1} - ${arr2}"
+ echo "${arr0[1]} - ${arr1[1]} - ${arr2[1]}"
+ echo "${arr0[1,2]} - ${arr1[1,2]} - ${arr2[1,2]}"
+ echo "${arr0[@]} - ${arr1[@]} - ${arr2[@]}"
+ echo "${hsh0} - ${hsh1} - ${hsh2}"
+ echo "${hsh0[1]} - ${hsh1[1]} - ${hsh2[1]}"
+ echo "${hsh0[@]} - ${hsh1[@]} - ${hsh2[@]}"
+ echo
+ echo "${!str0} - ${!str1} - ${!str2}"
+ echo "${!str0[1]} - ${!str1[1]} - ${!str2[1]}"
+ echo "${!str0[1,2]} - ${!str1[1,2]} - ${!str2[1,2]}"
+ echo "${!str0[@]} - ${!str1[@]} - ${!str2[@]}"
+ echo "${!arr0} - ${!arr1} - ${!arr2}"
+ echo "${!arr0[1]} - ${!arr1[1]} - ${!arr2[1]}"
+ echo "$(exec 2>&1; echo ${!arr0[1,2]}) - $(exec 2>&1; echo ${!arr1[1,2]}) - $(exec 2>&1; echo ${!arr2[1,2]})"
+ echo "${!arr0[@]} - ${!arr1[@]} - ${!arr2[@]}"
+ echo "${!hsh0} - ${!hsh1} - ${!hsh2}"
+ echo "${!hsh0[1]} - ${!hsh1[1]} - ${!hsh2[1]}"
+ echo "${!hsh0[@]} - ${!hsh1[@]} - ${!hsh2[@]}"
+ '
+0:emulation of ksh's bang always dereferences the expanded parameter
+>abc - abc - abc
+>b - b - b
+>bc - bc - bc
+>abc - abc - abc
+>aa - aa - aa
+>bb - bb - bb
+>bb cc - bb cc - bb cc
+>aa bb cc - aa bb cc - aa bb cc
+>aa - aa - aa
+>bb - bb - bb
+>aa bb cc - aa bb cc - aa bb cc
+>
+>abc - abc - abc
+>b - b - b
+>bc - bc - bc
+>abc - abc - abc
+>aa - aa - aa
+>1 - 1 - 1
+>(eval):6: invalid subscript - (eval):6: invalid subscript - (eval):6: invalid subscript
+>aa bb cc - aa bb cc - aa bb cc
+>aa - aa - aa
+>1 - 1 - 1
+>0 1 2 - 0 1 2 - 0 1 2
+
%clean
diff --git a/Test/K02parameter.ztst b/Test/K02parameter.ztst
index f9f434b36..2ae711e76 100644
--- a/Test/K02parameter.ztst
+++ b/Test/K02parameter.ztst
@@ -93,12 +93,25 @@ F:Braces are required
() {
typeset -n .k02.ref=.k02.array
emulate -L ksh
- print -l ${!.k02.ref} ${(!).k02.ref} ${.k02.ref}
+ print -l ${!.k02.ref} ${(k).k02.ref} ${(!).k02.ref} ${.k02.ref}
+ print -l ${!.k02.ref[2]} ${(k).k02.ref[2]} ${(!).k02.ref[2]} ${.k02.ref[2]}
}
0:namerefs with namespaces
+F:ksh expands "${!.k02.ref}" to ".k02.ref" but ("${!ref}" when in namespace "k02") to "array"
+F:the former looks bogus; expanding to ".k02.array" looks more logical/consistent
+>characters
+>characters
>.k02.array
->.k02.array
+F:ksh expands "${.k02.ref}" to ".k02.array" but ("${ref}" when in namespace "k02") to "characters"
+F:the former looks bogus; expanding to "characters" looks more logical/consistent
>characters
+F:ksh expands "${!.k02.ref[2]}" and ("${!ref[2]}" when in namespace "k02") to "array[2]"
+>2
+>2
+F:"${(!).k02.ref[2]}" -> "${${:-.k02.array}[2]}" -> "0"
+>0
+F:ksh expands "${.k02.ref[2]}" and ("${ref[2]}" when in namespace "k02") to "an"
+>an
k.=empty
k.2=test
diff --git a/Src/subst.c b/Src/subst.c
index efbd81105..f85eeb778 100644
--- a/Src/subst.c
+++ b/Src/subst.c
@@ -2763,6 +2763,8 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags,
*/
if (!subexp || aspar) {
char *ov = val;
+ char *ie = itype_end(subexp ? ov : s, inbrace ? INAMESPC : IIDENT, 0);
+ int nobracks = *ie != '[' && *ie != Inbrack;
int scanflags = hkeys | hvals;
if (arrasg)
scanflags |= SCANPM_ASSIGNING;
@@ -2859,6 +2861,14 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags,
v = NULL;
isarr = 0;
}
+ if (EMULATION(EMULATE_KSH) && (hkeys & SCANPM_WANTKEYS) && nobracks &&
+ v && v->pm && ((v->pm->node.flags & PM_DECLARED) ||
+ !(v->pm->node.flags & PM_UNSET)) ) {
+ val = dupstring(v->pm->node.nam);
+ vunset = 0;
+ v = NULL;
+ isarr = 0;
+ }
}
/*
* We get in here two ways; either we need to convert v into
diff --git a/Test/K01nameref.ztst b/Test/K01nameref.ztst
index bfc8ee508..6840e6974 100644
--- a/Test/K01nameref.ztst
+++ b/Test/K01nameref.ztst
@@ -2406,15 +2406,15 @@ F:converting from association/array to string should work here too
>bb - bb - bb
>aa bb cc - aa bb cc - aa bb cc
>
->abc - abc - abc
+>str0 - str0 - str0
>b - b - b
>bc - bc - bc
>abc - abc - abc
->aa - aa - aa
+>arr0 - arr0 - arr0
>1 - 1 - 1
>(eval):6: invalid subscript - (eval):6: invalid subscript - (eval):6: invalid subscript
>aa bb cc - aa bb cc - aa bb cc
->aa - aa - aa
+>hsh0 - hsh0 - hsh0
>1 - 1 - 1
>0 1 2 - 0 1 2 - 0 1 2
diff --git a/Test/K02parameter.ztst b/Test/K02parameter.ztst
index 2ae711e76..91ce2520f 100644
--- a/Test/K02parameter.ztst
+++ b/Test/K02parameter.ztst
@@ -99,8 +99,8 @@ F:Braces are required
0:namerefs with namespaces
F:ksh expands "${!.k02.ref}" to ".k02.ref" but ("${!ref}" when in namespace "k02") to "array"
F:the former looks bogus; expanding to ".k02.array" looks more logical/consistent
->characters
->characters
+>.k02.array
+>.k02.array
>.k02.array
F:ksh expands "${.k02.ref}" to ".k02.array" but ("${ref}" when in namespace "k02") to "characters"
F:the former looks bogus; expanding to "characters" looks more logical/consistent