mirror of
git://git.code.sf.net/p/zsh/code
synced 2025-06-12 07:28:04 +02:00
51509 (+ fix typo): Add ${(!)name} for the referred-to name of a named reference
Extend ${!name} in ksh emulation for same
This commit is contained in:
parent
ac1bf482ba
commit
0562be0af8
4 changed files with 41 additions and 9 deletions
|
@ -1,5 +1,9 @@
|
||||||
2023-03-06 Bart Schaefer <schaefer@zsh.org>
|
2023-03-06 Bart Schaefer <schaefer@zsh.org>
|
||||||
|
|
||||||
|
* 51509 (+ fix typo): Src/params.c, Src/subst.c, Src/zsh.h: Add
|
||||||
|
${(!)name} for the referred-to parameter of a named reference,
|
||||||
|
and extend ${!name} in ksh emulation for same
|
||||||
|
|
||||||
* 51524: Src/Modules/ksh93.mdd: dependency on zsh/zle for linkage
|
* 51524: Src/Modules/ksh93.mdd: dependency on zsh/zle for linkage
|
||||||
|
|
||||||
2023-03-05 Bart Schaefer <schaefer@zsh.org>
|
2023-03-05 Bart Schaefer <schaefer@zsh.org>
|
||||||
|
|
|
@ -2144,7 +2144,10 @@ fetchvalue(Value v, char **pptr, int bracks, int flags)
|
||||||
int isvarat;
|
int isvarat;
|
||||||
|
|
||||||
isvarat = (t[0] == '@' && !t[1]);
|
isvarat = (t[0] == '@' && !t[1]);
|
||||||
pm = (Param) paramtab->getnode(paramtab, *t == '0' ? "0" : t);
|
if (flags & SCANPM_NONAMEREF)
|
||||||
|
pm = (Param) paramtab->getnode2(paramtab, *t == '0' ? "0" : t);
|
||||||
|
else
|
||||||
|
pm = (Param) paramtab->getnode(paramtab, *t == '0' ? "0" : t);
|
||||||
if (sav)
|
if (sav)
|
||||||
*s = sav;
|
*s = sav;
|
||||||
*pptr = s;
|
*pptr = s;
|
||||||
|
@ -2155,7 +2158,7 @@ fetchvalue(Value v, char **pptr, int bracks, int flags)
|
||||||
memset(v, 0, sizeof(*v));
|
memset(v, 0, sizeof(*v));
|
||||||
else
|
else
|
||||||
v = (Value) hcalloc(sizeof *v);
|
v = (Value) hcalloc(sizeof *v);
|
||||||
if (pm->node.flags & PM_NAMEREF) {
|
if ((pm->node.flags & PM_NAMEREF) && !(flags & SCANPM_NONAMEREF)) {
|
||||||
char *refname = GETREFNAME(pm);
|
char *refname = GETREFNAME(pm);
|
||||||
if (refname && *refname) {
|
if (refname && *refname) {
|
||||||
/* only happens for namerefs pointing to array elements */
|
/* only happens for namerefs pointing to array elements */
|
||||||
|
|
38
Src/subst.c
38
Src/subst.c
|
@ -1818,14 +1818,14 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags,
|
||||||
* Use for the (k) flag. Goes down into the parameter code,
|
* Use for the (k) flag. Goes down into the parameter code,
|
||||||
* sometimes.
|
* sometimes.
|
||||||
*/
|
*/
|
||||||
char hkeys = 0;
|
int hkeys = 0;
|
||||||
/*
|
/*
|
||||||
* Used for the (v) flag, ditto. Not quite sure why they're
|
* Used for the (v) flag, ditto. Not quite sure why they're
|
||||||
* separate, but the tradition seems to be that things only
|
* separate, but the tradition seems to be that things only
|
||||||
* get combined when that makes the result more obscure rather
|
* get combined when that makes the result more obscure rather
|
||||||
* than less.
|
* than less.
|
||||||
*/
|
*/
|
||||||
char hvals = 0;
|
int hvals = 0;
|
||||||
/*
|
/*
|
||||||
* Whether we had to evaluate a subexpression, i.e. an
|
* Whether we had to evaluate a subexpression, i.e. an
|
||||||
* internal ${...} or $(...) or plain $pm. We almost don't
|
* internal ${...} or $(...) or plain $pm. We almost don't
|
||||||
|
@ -1870,8 +1870,8 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags,
|
||||||
* these later on, too.
|
* these later on, too.
|
||||||
*/
|
*/
|
||||||
c = *s;
|
c = *s;
|
||||||
if (itype_end(s, INAMESPC, 1) == s && *s != '#' && c != Pound &&
|
if (itype_end(s, (c == Inbrace ? INAMESPC : IIDENT), 1) == s &&
|
||||||
!IS_DASH(c) &&
|
*s != '#' && c != Pound && !IS_DASH(c) &&
|
||||||
c != '!' && c != '$' && c != String && c != Qstring &&
|
c != '!' && c != '$' && c != String && c != Qstring &&
|
||||||
c != '?' && c != Quest &&
|
c != '?' && c != Quest &&
|
||||||
c != '*' && c != Star && c != '@' && c != '{' &&
|
c != '*' && c != Star && c != '@' && c != '{' &&
|
||||||
|
@ -1891,15 +1891,30 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags,
|
||||||
s++;
|
s++;
|
||||||
/*
|
/*
|
||||||
* In ksh emulation a leading `!' is a special flag working
|
* In ksh emulation a leading `!' is a special flag working
|
||||||
* sort of like our (k).
|
* sort of like our (k). This is true only for arrays or
|
||||||
|
* associative arrays and only with subscripts [*] or [@],
|
||||||
|
* so zsh's implementation is approximate. For namerefs
|
||||||
|
* in ksh, ${!ref} substitues the parameter name at the
|
||||||
|
* end of any chain of references, rather than the value.
|
||||||
|
*
|
||||||
* TODO: this is one of very few cases tied directly to
|
* TODO: this is one of very few cases tied directly to
|
||||||
* the emulation mode rather than an option. Since ksh
|
* the emulation mode rather than an option. Since ksh
|
||||||
* doesn't have parameter flags it might be neater to
|
* doesn't have parameter flags it might be neater to
|
||||||
* handle this with the ^, =, ~ stuff, below.
|
* handle this with the ^, =, ~ stuff, below.
|
||||||
*/
|
*/
|
||||||
if ((c = *s) == '!' && s[1] != Outbrace && EMULATION(EMULATE_KSH)) {
|
if ((c = *s) == '!' && s[1] != Outbrace && EMULATION(EMULATE_KSH)) {
|
||||||
hkeys = SCANPM_WANTKEYS;
|
hkeys = SCANPM_WANTKEYS|SCANPM_NONAMEREF;
|
||||||
s++;
|
s++;
|
||||||
|
/* There's a slew of other special bash meanings of parameter
|
||||||
|
* references that start with "!":
|
||||||
|
* ${!name} == ${(P)name} (when name is not a nameref)
|
||||||
|
* ${!name*} == ${(k)parameters[(I)name*]}
|
||||||
|
* ${!name@} == ${(@k)parameters[(I)name*]}
|
||||||
|
* ${!name[*]} == ${(k)name} (but indexes of ordinary arrays, too)
|
||||||
|
* ${!name[@]} == ${(@k)name} (ditto, as noted above for ksh)
|
||||||
|
*
|
||||||
|
* See also workers/34390, workers/34397, workers/34408.
|
||||||
|
*/
|
||||||
} else if (c == '(' || c == Inpar) {
|
} else if (c == '(' || c == Inpar) {
|
||||||
char *t, sav;
|
char *t, sav;
|
||||||
int tt = 0;
|
int tt = 0;
|
||||||
|
@ -2154,10 +2169,19 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags,
|
||||||
escapes = 1;
|
escapes = 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case '!':
|
||||||
|
if ((hkeys|hvals) & ~SCANPM_NONAMEREF)
|
||||||
|
goto flagerr;
|
||||||
|
hkeys = SCANPM_NONAMEREF;
|
||||||
|
break;
|
||||||
case 'k':
|
case 'k':
|
||||||
|
if (hkeys & ~SCANPM_WANTKEYS)
|
||||||
|
goto flagerr;
|
||||||
hkeys = SCANPM_WANTKEYS;
|
hkeys = SCANPM_WANTKEYS;
|
||||||
break;
|
break;
|
||||||
case 'v':
|
case 'v':
|
||||||
|
if (hvals & ~SCANPM_WANTVALS)
|
||||||
|
goto flagerr;
|
||||||
hvals = SCANPM_WANTVALS;
|
hvals = SCANPM_WANTVALS;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -2308,7 +2332,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags,
|
||||||
/*
|
/*
|
||||||
* Look for special unparenthesised flags.
|
* Look for special unparenthesised flags.
|
||||||
* TODO: could make these able to appear inside parentheses, too,
|
* TODO: could make these able to appear inside parentheses, too,
|
||||||
* i.e. ${(^)...} etc.
|
* i.e. ${(^)...} etc., but ${(~)...} already has another meaning.
|
||||||
*/
|
*/
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if ((c = *s) == '^' || c == Hat) {
|
if ((c = *s) == '^' || c == Hat) {
|
||||||
|
|
|
@ -1964,6 +1964,7 @@ struct tieddata {
|
||||||
#define SCANPM_CHECKING (1<<10) /* Check if set, no need to create */
|
#define SCANPM_CHECKING (1<<10) /* Check if set, no need to create */
|
||||||
#define SCANPM_NOEXEC (1<<11) /* No command substitutions, etc. */
|
#define SCANPM_NOEXEC (1<<11) /* No command substitutions, etc. */
|
||||||
#define SCANPM_NONAMESPC (1<<12) /* namespace syntax not allowed */
|
#define SCANPM_NONAMESPC (1<<12) /* namespace syntax not allowed */
|
||||||
|
#define SCANPM_NONAMEREF (1<<13) /* named references are not followed */
|
||||||
|
|
||||||
/* "$foo[@]"-style substitution
|
/* "$foo[@]"-style substitution
|
||||||
* Only sign bit is significant
|
* Only sign bit is significant
|
||||||
|
|
Loading…
Reference in a new issue