summaryrefslogtreecommitdiff
path: root/Src/params.c
diff options
context:
space:
mode:
authorBart Schaefer <schaefer@zsh.org>2024-03-04 21:07:01 -0800
committerBart Schaefer <schaefer@zsh.org>2024-03-04 21:07:01 -0800
commit610b18875ad9f4498a57e9af6903bcac3b14ff46 (patch)
tree44123f9fbd7650323f320cb81b4ed05448dd36d1 /Src/params.c
parent05c7b21e2b30873d002b50b37e2fbd3803d4b608 (diff)
downloadzsh-610b18875ad9f4498a57e9af6903bcac3b14ff46.tar.gz
zsh-610b18875ad9f4498a57e9af6903bcac3b14ff46.zip
52650 plus minor fixes: add -u for named references pointing to "upper" scope
Diffstat (limited to 'Src/params.c')
-rw-r--r--Src/params.c32
1 files changed, 20 insertions, 12 deletions
diff --git a/Src/params.c b/Src/params.c
index e83e4aa5e..263cd0c52 100644
--- a/Src/params.c
+++ b/Src/params.c
@@ -1060,8 +1060,7 @@ createparam(char *name, int flags)
"BUG: local parameter is not unset");
oldpm = lastpm;
}
- } else
- flags |= PM_NAMEREF;
+ }
}
DPUTS(oldpm && oldpm->level > locallevel,
@@ -6267,10 +6266,12 @@ resolve_nameref(Param pm, const Asgment stop)
}
} else if ((hn = gethashnode2(realparamtab, seek))) {
if (pm) {
- if (!(stop && (stop->flags & (PM_LOCAL))))
- hn = (HashNode)upscope((Param)hn,
- ((pm->node.flags & PM_NAMEREF) ?
- pm->base : ((Param)hn)->level));
+ if (!(stop && (stop->flags & (PM_LOCAL)))) {
+ int scope = ((pm->node.flags & PM_NAMEREF) ?
+ ((pm->node.flags & PM_UPPER) ? -1 :
+ pm->base) : ((Param)hn)->level);
+ hn = (HashNode)upscope((Param)hn, scope);
+ }
/* user can't tag a nameref, safe for loop detection */
pm->node.flags |= PM_TAGGED;
}
@@ -6316,11 +6317,13 @@ setloopvar(char *name, char *value)
static void
setscope(Param pm)
{
- if (pm->node.flags & PM_NAMEREF) {
+ queue_signals();
+ if (pm->node.flags & PM_NAMEREF) do {
Param basepm;
struct asgment stop;
char *refname = GETREFNAME(pm);
char *t = refname ? itype_end(refname, INAMESPC, 0) : NULL;
+ int q = queue_signal_level();
/* Temporarily change nameref to array parameter itself */
if (t && *t == '[')
@@ -6330,9 +6333,11 @@ setscope(Param pm)
stop.name = "";
stop.value.scalar = NULL;
stop.flags = PM_NAMEREF;
- if (locallevel)
+ if (locallevel && !(pm->node.flags & PM_UPPER))
stop.flags |= PM_LOCAL;
+ dont_queue_signals(); /* Prevent unkillable loops */
basepm = (Param)resolve_nameref(pm, &stop);
+ restore_queue_signals(q);
if (t) {
pm->width = t - refname;
*t = '[';
@@ -6345,7 +6350,7 @@ setscope(Param pm)
if (upscope(pm, pm->base) == pm) {
zerr("%s: invalid self reference", refname);
unsetparam_pm(pm, 0, 1);
- return;
+ break;
}
pm->node.flags &= ~PM_SELFREF;
} else if (pm->base == pm->level) {
@@ -6353,7 +6358,7 @@ setscope(Param pm)
strcmp(pm->node.nam, refname) == 0) {
zerr("%s: invalid self reference", refname);
unsetparam_pm(pm, 0, 1);
- return;
+ break;
}
}
} else if ((t = GETREFNAME(basepm))) {
@@ -6361,7 +6366,7 @@ setscope(Param pm)
strcmp(pm->node.nam, t) == 0) {
zerr("%s: invalid self reference", refname);
unsetparam_pm(pm, 0, 1);
- return;
+ break;
}
}
} else
@@ -6381,7 +6386,8 @@ setscope(Param pm)
zerr("%s: invalid self reference", refname);
unsetparam_pm(pm, 0, 1);
}
- }
+ } while (0);
+ unqueue_signals();
}
/**/
@@ -6393,6 +6399,8 @@ upscope(Param pm, int reflevel)
pm = up;
up = up->old;
}
+ if (reflevel < 0 && locallevel > 0)
+ return pm->level == locallevel ? up : pm;
return pm;
}