summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog3
-rw-r--r--Doc/Zsh/builtins.yo2
-rw-r--r--Src/params.c108
3 files changed, 69 insertions, 44 deletions
diff --git a/ChangeLog b/ChangeLog
index 38a0395d6..30e9850e5 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,8 @@
2023-03-05 Bart Schaefer <schaefer@zsh.org>
+ * 51484: Src/builtins.yo Src/params.c: Extend named reference
+ handling for special parameters, improve doc.
+
* 51483: Src/Zle/compcore.c, Src/Zle/zle_tricky.c, Src/lex.c,
Src/params.c, Src/subst.c, Src/utils.c, Src/zsh.h, Src/ztype.h:
Enable assignment and expansion of parameters with ksh-like
diff --git a/Doc/Zsh/builtins.yo b/Doc/Zsh/builtins.yo
index 92917c06c..5393cb149 100644
--- a/Doc/Zsh/builtins.yo
+++ b/Doc/Zsh/builtins.yo
@@ -1924,6 +1924,8 @@ redef(SPACES)(0)(tt(ifztexi(NOTRANS(@ @ @ @ @ @ @ @ ))ifnztexi( )))
xitem(tt(typeset )[ {tt(PLUS())|tt(-)}tt(AHUaghlmrtux) ] \
[ {tt(PLUS())|tt(-)}tt(EFLRZip) [ var(n) ] ])
xitem(SPACES()[ tt(+) ] [ var(name)[tt(=)var(value)] ... ])
+xitem(tt(typeset )[ {tt(PLUS())|tt(-)}tt(n) ] \
+[ tt(-gr) ] [ var(name)[tt(=)var(value)] ... ])
xitem(tt(typeset )tt(-T) [ {tt(PLUS())|tt(-)}tt(Uglrux) ] [ {tt(PLUS())|tt(-)}tt(LRZp) [ var(n) ] ])
xitem(SPACES()[ tt(+) | var(SCALAR)[tt(=)var(value)] var(array)[tt(=LPAR())var(value) ...tt(RPAR())] [ var(sep) ] ])
item(tt(typeset) tt(-f) [ {tt(PLUS())|tt(-)}tt(TUkmtuz) ] [ tt(+) ] [ var(name) ... ])(
diff --git a/Src/params.c b/Src/params.c
index d3b6a7d43..c9f4b3017 100644
--- a/Src/params.c
+++ b/Src/params.c
@@ -475,6 +475,15 @@ static initparam argvparam_pm = IPDEF9("", &pparams, NULL, \
((V) && (!(V)->pm || ((V)->pm->node.flags & PM_UNSET) || \
!(V)->pm->node.nam || !*(V)->pm->node.nam))
+/*
+ * For named references. Simple named references are just like scalars
+ * for efficiency, but special named references need get/set functions.
+ */
+#define GETREFNAME(PM) (((PM)->node.flags & PM_SPECIAL) ? \
+ (PM)->gsu.s->getfn(PM) : (PM)->u.str)
+#define SETREFNAME(PM,S) (((PM)->node.flags & PM_SPECIAL) ? \
+ (PM)->gsu.s->setfn(PM,(S)) : ((PM)->u.str = (S)))
+
static Param argvparam;
/* "parameter table" - hash table containing the parameters
@@ -520,7 +529,7 @@ getparamnode(HashTable ht, const char *nam)
HashNode hn = gethashnode2(ht, nam);
Param pm = (Param) hn;
- if (pm && pm->u.str && (pm->node.flags & PM_AUTOLOAD)) {
+ if (pm && (pm->node.flags & PM_AUTOLOAD) && pm->u.str) {
char *mn = dupstring(pm->u.str);
(void)ensurefeature(mn, "p:", (pm->node.flags & PM_AUTOALL) ? NULL :
@@ -1002,12 +1011,13 @@ createparam(char *name, int flags)
struct asgment stop;
stop.flags = PM_NAMEREF | (flags & PM_LOCAL);
stop.name = oldpm->node.nam;
- stop.value.scalar = oldpm->u.str;
+ stop.value.scalar = GETREFNAME(oldpm);
lastpm = (Param)resolve_nameref(oldpm, &stop);
if (lastpm) {
if (lastpm->node.flags & PM_NAMEREF) {
- if (lastpm->u.str && *(lastpm->u.str)) {
- name = lastpm->u.str;
+ char *refname = GETREFNAME(lastpm);
+ if (refname && *refname) {
+ name = refname;
oldpm = NULL;
} else {
if (!(lastpm->node.flags & PM_READONLY))
@@ -2145,25 +2155,28 @@ fetchvalue(Value v, char **pptr, int bracks, int flags)
memset(v, 0, sizeof(*v));
else
v = (Value) hcalloc(sizeof *v);
- if ((pm->node.flags & PM_NAMEREF) && pm->u.str && *(pm->u.str)) {
- /* only happens for namerefs pointing to array elements */
- char *ref = dupstring(pm->u.str);
- char *ss = pm->width ? ref + pm->width : NULL;
- if (ss) {
- sav = *ss;
- *ss = 0;
+ if (pm->node.flags & PM_NAMEREF) {
+ char *refname = GETREFNAME(pm);
+ if (refname && *refname) {
+ /* only happens for namerefs pointing to array elements */
+ char *ref = dupstring(refname);
+ char *ss = pm->width ? ref + pm->width : NULL;
+ if (ss) {
+ sav = *ss;
+ *ss = 0;
+ }
+ Param p1 = (Param)gethashnode2(paramtab, ref);
+ if (!(p1 && (pm = upscope(p1, pm->base))) ||
+ ((pm->node.flags & PM_UNSET) &&
+ !(pm->node.flags & PM_DECLARED)))
+ return NULL;
+ if (ss) {
+ flags |= SCANPM_NOEXEC;
+ *ss = sav;
+ s = dyncat(ss,*pptr);
+ } else
+ s = *pptr;
}
- Param p1 = (Param)gethashnode2(paramtab, ref);
- if (!(p1 && (pm = upscope(p1, pm->base))) ||
- ((pm->node.flags & PM_UNSET) &&
- !(pm->node.flags & PM_DECLARED)))
- return NULL;
- if (ss) {
- flags |= SCANPM_NOEXEC;
- *ss = sav;
- s = dyncat(ss,*pptr);
- } else
- s = *pptr;
}
if (PM_TYPE(pm->node.flags) & (PM_ARRAY|PM_HASHED)) {
/* Overload v->isarr as the flag bits for hashed arrays. */
@@ -3648,7 +3661,7 @@ mod_export Param
setiparam_no_convert(char *s, zlong val)
{
/*
- * If the target is already an integer, thisgets converted
+ * If the target is already an integer, this gets converted
* back. Low technology rules.
*/
char buf[BDIGBUFSIZE];
@@ -6115,22 +6128,23 @@ resolve_nameref(Param pm, const Asgment stop)
const char *seek = stop ? stop->value.scalar : NULL;
if (pm && (pm->node.flags & PM_NAMEREF)) {
- if (pm && (pm->node.flags & (PM_UNSET|PM_TAGGED))) {
+ char *refname = GETREFNAME(pm);
+ if (pm->node.flags & (PM_UNSET|PM_TAGGED)) {
/* Semaphore with createparam() */
pm->node.flags &= ~PM_UNSET;
if (pm->node.flags & PM_NEWREF) /* See setloopvar() */
return NULL;
- if (pm->u.str && *(pm->u.str) && (pm->node.flags & PM_TAGGED))
+ if (refname && *refname && (pm->node.flags & PM_TAGGED))
pm->node.flags |= PM_SELFREF; /* See setscope() */
return (HashNode) pm;
- } else if (pm->u.str) {
+ } else if (refname) {
if ((pm->node.flags & PM_TAGGED) ||
- (stop && strcmp(pm->u.str, stop->name) == 0)) {
- /* zwarnnam(pm->u.str, "invalid self reference"); */
+ (stop && strcmp(refname, stop->name) == 0)) {
+ /* zwarnnam(refname, "invalid self reference"); */
return stop ? (HashNode)pm : NULL;
}
- if (*(pm->u.str))
- seek = pm->u.str;
+ if (*refname)
+ seek = refname;
}
}
else if (pm && !(stop && (stop->flags & PM_NAMEREF)))
@@ -6180,8 +6194,13 @@ setloopvar(char *name, char *value)
Param pm = (Param) gethashnode2(realparamtab, name);
if (pm && (pm->node.flags & PM_NAMEREF)) {
+ if (pm->node.flags & PM_READONLY) {
+ /* Bash error is: "%s: readonly variable" */
+ zerr("read-only reference: %s", pm->node.nam);
+ return;
+ }
pm->base = pm->width = 0;
- pm->u.str = ztrdup(value);
+ SETREFNAME(pm, ztrdup(value));
pm->node.flags &= ~PM_UNSET;
pm->node.flags |= PM_NEWREF;
setscope(pm);
@@ -6197,7 +6216,8 @@ setscope(Param pm)
if (pm->node.flags & PM_NAMEREF) {
Param basepm;
struct asgment stop;
- char *t = pm->u.str ? itype_end(pm->u.str, INAMESPC, 0) : NULL;
+ char *refname = GETREFNAME(pm);
+ char *t = refname ? itype_end(refname, INAMESPC, 0) : NULL;
/* Temporarily change nameref to array parameter itself */
if (t && *t == '[')
@@ -6211,7 +6231,7 @@ setscope(Param pm)
stop.flags |= PM_LOCAL;
basepm = (Param)resolve_nameref(pm, &stop);
if (t) {
- pm->width = t - pm->u.str;
+ pm->width = t - refname;
*t = '[';
}
if (basepm) {
@@ -6220,23 +6240,23 @@ setscope(Param pm)
if (pm->node.flags & PM_SELFREF) {
/* Loop signalled by resolve_nameref() */
if (upscope(pm, pm->base) == pm) {
- zerr("%s: invalid self reference", pm->u.str);
+ zerr("%s: invalid self reference", refname);
unsetparam_pm(pm, 0, 1);
return;
}
pm->node.flags &= ~PM_SELFREF;
} else if (pm->base == pm->level) {
- if (pm->u.str && *(pm->u.str) &&
- strcmp(pm->node.nam, pm->u.str) == 0) {
- zerr("%s: invalid self reference", pm->u.str);
+ if (refname && *refname &&
+ strcmp(pm->node.nam, refname) == 0) {
+ zerr("%s: invalid self reference", refname);
unsetparam_pm(pm, 0, 1);
return;
}
}
- } else if (basepm->u.str) {
+ } else if ((t = GETREFNAME(basepm))) {
if (basepm->base <= basepm->level &&
- strcmp(pm->node.nam, basepm->u.str) == 0) {
- zerr("%s: invalid self reference", pm->u.str);
+ strcmp(pm->node.nam, t) == 0) {
+ zerr("%s: invalid self reference", refname);
unsetparam_pm(pm, 0, 1);
return;
}
@@ -6251,11 +6271,11 @@ setscope(Param pm)
unsetparam_pm(pm, 0, 1);
} else if (isset(WARNNESTEDVAR))
zwarn("reference %s in enclosing scope set to local variable %s",
- pm->node.nam, pm->u.str);
+ pm->node.nam, refname);
}
- if (pm->u.str && upscope(pm, pm->base) == pm &&
- strcmp(pm->node.nam, pm->u.str) == 0) {
- zerr("%s: invalid self reference", pm->u.str);
+ if (refname && upscope(pm, pm->base) == pm &&
+ strcmp(pm->node.nam, refname) == 0) {
+ zerr("%s: invalid self reference", refname);
unsetparam_pm(pm, 0, 1);
}
}