Zsh Mailing List Archive
Messages sorted by:
Reverse Date,
Date,
Thread,
Author
Re: [PATCH] Implement references to positional parameters
- X-seq: zsh-workers 54726
- From: Philippe Altherr <philippe.altherr@xxxxxxxxx>
- To: Bart Schaefer <schaefer@xxxxxxxxxxxxxxxx>
- Cc: Zsh hackers list <zsh-workers@xxxxxxx>
- Subject: Re: [PATCH] Implement references to positional parameters
- Date: Tue, 9 Jun 2026 03:29:48 +0200
- Arc-authentication-results: i=1; mx.google.com; arc=none
- Arc-message-signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20240605; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:dkim-signature; bh=JVd/w8KvPOmcuAmOl/8rATtuO/WyEscSczNeFN9B2d0=; fh=vuDAGjptCPc/P1/HEZ3j98yPJEW1XjuEoEAmmwDS/+U=; b=hIpA3P+CJNspskdKN941h8/+GIJ041ZENV5FwHcl7H2O5yxdBzEb3l/Z25M/vFvJyW 6yDidnbaIKtf+JSIJYN7W9fd4u1+BIzROANZRqSCTNZn3gHuSRO7qs/0omN/nVgLDpve LSGs/ARNFeM1+L25rOYn23I+BL0qSlNHjnjEQTpbXnswOZSO3VzNs71DsgkCMjYlNihf mFXrx/+XRpjJVrH3xt5hSClq4b7/LjECsKtoYlrpDt5t84bkr7UkkRewyh2IZngnpG42 1zWOTcCBf+VlhAc1ynmXsYP8kuDEEHP+JGpkM7cHg45N9F8topsySGUvTOb97yGe7Tsx t1gQ==; darn=zsh.org
- Arc-seal: i=1; a=rsa-sha256; t=1780968600; cv=none; d=google.com; s=arc-20240605; b=hiuDVuHckyRpu8sllJ9APo2pJxfW+05CeWfrtqV0tJlU0achQvLkNofL74RrcEwsR2 PdBrl+FddjHaoyDkmfPfHOfLMJzl34l6t4pVVFSRUxbtlFuYc23a7MqnNQsMLdYmtOx3 5vi3d10iO7kavapfxAd+FDtqtQiHCUGGfuJ6/ZFXqtGwnfmI4/5uJJnpNjBz5Jbw2ZsI wR62rLQmvcjioO6PD/VhfHTGuEFaA3a1OE5b3zAB92UboErw1NJ/6HToQvKSm/wKuUMc Azhmz+AOOIxDGJtyoIkzXsCiJO62NcUSwF+zKnAMp+nNrONUqp4uZuoMVGr3zQFtbEJD x3pA==
- Archived-at: <https://zsh.org/workers/54726>
- In-reply-to: <CAH+w=7Z7X_v0FRkAGMMqGHi2JJiwBM=JONPxP=BTWW9FabuFgQ@mail.gmail.com>
- List-id: <zsh-workers.zsh.org>
- References: <CAGdYcht3HsZKEkzj7_czPdoXUAnWA0cv7iht3nPFzh3qNiBCXQ@mail.gmail.com> <CAGdYcht-SKfD0_TLMw3GX0gBiorGdeAMRmR=ANMjcAZs5qEwHA@mail.gmail.com> <CAH+w=7Z7X_v0FRkAGMMqGHi2JJiwBM=JONPxP=BTWW9FabuFgQ@mail.gmail.com>
diff --git a/Src/params.c b/Src/params.c
index b95efe9a8..be1bf48fa 100644
--- a/Src/params.c
+++ b/Src/params.c
@@ -224,6 +224,8 @@ static const struct gsu_integer ttyidle_gsu =
static const struct gsu_scalar argzero_gsu =
{ argzerogetfn, argzerosetfn, nullunsetfn };
+static const struct gsu_scalar argn_gsu =
+{ argngetfn, argnsetfn, argnunsetfn };
static const struct gsu_scalar username_gsu =
{ usernamegetfn, usernamesetfn, stdunsetfn };
static const struct gsu_scalar dash_gsu =
@@ -484,6 +486,8 @@ static initparam argvparam_pm = IPDEF9("", &pparams, NULL, \
(zsfree((PM)->u.str), (PM)->u.str = (S)))
static Param argvparam;
+static Param *argnparams;
+static size_t argnparams_size;
/*
* Lists of references to nested variables ("Param" instances) indexed
@@ -856,6 +860,9 @@ createparamtable(void)
}
argvparam = (Param) &argvparam_pm;
+ argnparams = zshcalloc(8 * sizeof(Param));
+ argnparams_size = 8;
+ argnparams[0] = (Param) paramtab->getnode(paramtab, "0");
noerrs = 2;
@@ -4972,6 +4979,49 @@ argzerogetfn(UNUSED(Param pm))
return argzero;
}
+/* Function to get value for positional parameters */
+
+/**/
+static char *
+argngetfn(Param pm)
+{
+ return arrlen_gt(pparams, pm->u.val - 1) ?
+ pparams[pm->u.val - 1] : (char *) hcalloc(1);
+}
+
+/* Function to set value for positional parameters */
+
+/**/
+static void
+argnsetfn(Param pm, char *x)
+{
+ int len = arrlen(pparams);
+ int ppar = pm->u.val;
+ if (ppar <= len)
+ zsfree(pparams[ppar - 1]);
+ else if (x) {
+ int i;
+ pparams = (char **) zrealloc(pparams, sizeof(char *) * ppar + 1);
+ for (i = len; i < ppar - 1; i++)
+ pparams[i] = ztrdup("");
+ pparams[ppar] = 0;
+ }
+ if (x) {
+ pparams[ppar - 1] = ztrdup(x);
+ zsfree(x);
+ } else if (ppar <= len)
+ memmove(pparams + ppar - 1, pparams + ppar, (len - ppar + 1) * sizeof(char *));
+}
+
+/* Function to unset positional parameters */
+
+/**/
+static void
+argnunsetfn(Param pm, UNUSED(int exp))
+{
+ argnsetfn(pm, NULL);
+}
+
/* Function to get value for special parameter `HISTSIZE' */
/**/
@@ -6366,6 +6416,23 @@ resolve_nameref_rec(Param pm, const Param stop, int keep_lastref)
if ((pm = loadparamnode(paramtab, upscope(pm, ref), refname)) &&
pm != stop && !(pm->node.flags & PM_UNSET))
pm = resolve_nameref_rec(pm, stop, keep_lastref);
+ } else if (idigit(*refname)) {
+ int ppar = zstrtol(refname, NULL, 10);
+ if (ppar >= argnparams_size) {
+ size_t old_size = argnparams_size;
+ size_t new_size = argnparams_size = MAX(2 * old_size, ppar);
+ argnparams = zrealloc(argnparams, new_size * sizeof(Param));
+ memset(argnparams + old_size, 0,
+ (new_size - old_size) * sizeof(Param));
+ }
+ if (!(pm = argnparams[ppar])) {
+ pm = argnparams[ppar] = zshcalloc(sizeof(*pm));
+ pm->node.nam = zalloc(snprintf(NULL, 0, "%d", ppar) + 1);
+ sprintf(pm->node.nam, "%d", ppar);
+ pm->node.flags = PM_SCALAR | PM_SPECIAL;
+ pm->u.val = ppar;
+ pm->gsu.s = &argn_gsu;
+ }
} else if (keep_lastref)
pm = ref;
unqueue_signals();
diff --git a/Test/K01nameref.ztst b/Test/K01nameref.ztst
index 68b36f415..86c854ba2 100644
--- a/Test/K01nameref.ztst
+++ b/Test/K01nameref.ztst
@@ -1352,14 +1352,14 @@ F:previously this could create an infinite recursion and crash
edgelocal() ( local -n x=$1; typeset -p x; print -r $x )
edgeupper() ( local -nu x=$1; typeset -p x; print -r $x )
- for edge in argv ARGC \@ \* \# 0 1 01 \! \? - _
+ for edge in argv ARGC \@ \* \# 0 00 1 01 \! \? - _
do
edgelocal $edge
edgelocal "$edge""[1]"
edgeupper $edge
done
0:references to builtin specials
-F:Subscripting on 1 01 ! ? - should print first character but do not
+F:Subscripting on 00 1 01 ! ? - should print first character but do not
>typeset -n x=argv
>argv
>typeset -n x='argv[1]'
@@ -1372,12 +1372,16 @@ F:Subscripting on 1 01 ! ? - should print first character but do not
>edgelocal
>typeset -n x='0[1]'
>e
->typeset -n x=1
+>typeset -n x=00
+>edgelocal
+>typeset -n x='00[1]'
>
+>typeset -n x=1
+>1
>typeset -n x='1[1]'
>
>typeset -n x=01
->
+>01
>typeset -n x='01[1]'
>
>typeset -n x=!
@@ -1416,6 +1420,7 @@ F:Subscripting on 1 01 ! ? - should print first character but do not
?edgelocal: invalid variable name: #[1]
?edgeupper: invalid variable name: #
?edgeupper: invalid variable name: 0
+?edgeupper: invalid variable name: 00
?edgeupper: invalid variable name: 1
?edgeupper: invalid variable name: 01
@@ -1431,6 +1436,75 @@ F:$$[1] reference should print the first digit of $$ but prints nothing
>$$[1]
>$$
+ tst() {
+ typeset -n ref0=0 2>&1
+ typeset -n ref00=00 2>&1
+ typeset -n ref2=2 2>&1
+ typeset -n ref02=02 2>&1
+ echo ${(q)0} ${(q)*} - $ref0 - $ref00 - $ref2 - $ref02
+ ref0=TST
+ ref2=BBB
+ echo ${(q)0} ${(q)*} - $ref0 - $ref00 - $ref2 - $ref02
+ ref00=Tst
+ ref02=Bbb
+ echo ${(q)0} ${(q)*} - $ref0 - $ref00 - $ref2 - $ref02; typeset -p -- 0 00 2 02 2>&1
+ unset ref0
+ unset ref2
+ echo ${(q)0} ${(q)*} - $ref0 - $ref00 - $ref2 - $ref02; typeset -p -- 0 00 2 02 2>&1
+ ref0=tst
+ ref2=bbb
+ echo ${(q)0} ${(q)*} - $ref0 - $ref00 - $ref2 - $ref02; typeset -p -- 0 00 2 02 2>&1
+ { ref0=(TST TST) 2>&1 } always { TRY_BLOCK_ERROR=0 }
+ { ref2=(BBB BBB) 2>&1 } always { TRY_BLOCK_ERROR=0 }
+ echo ${(q)0} ${(q)*} - $ref0 - $ref00 - $ref2 - $ref02; typeset -p -- 0 00 2 02 2>&1
+ typeset -n ref5=5 2>&1
+ ref5=zzz
+ echo ${(q)0} ${(q)*}
+ unset ref2
+ echo ${(q)0} ${(q)*}
+ unset ref2
+ echo ${(q)0} ${(q)*}
+ unset ref2
+ echo ${(q)0} ${(q)*}
+ unset ref2
+ echo ${(q)0} ${(q)*}
+ unset ref2
+ echo ${(q)0} ${(q)*}
+ }
+ tst aaa bbb ccc
+ unfunction tst
+0:references to positional parameters
+>tst aaa bbb ccc - tst - tst - bbb - bbb
+>TST aaa BBB ccc - TST - TST - BBB - BBB
+>Tst aaa Bbb ccc - Tst - Tst - Bbb - Bbb
+>tst:typeset:11: no such variable: 00
+>tst:typeset:11: no such variable: 2
+>tst:typeset:11: no such variable: 02
+>typeset -g 0=Tst
+>Tst aaa ccc - Tst - Tst - ccc - ccc
+>tst:typeset:14: no such variable: 00
+>tst:typeset:14: no such variable: 2
+>tst:typeset:14: no such variable: 02
+>typeset -g 0=Tst
+>tst aaa bbb - tst - tst - bbb - bbb
+>tst:typeset:17: no such variable: 00
+>tst:typeset:17: no such variable: 2
+>tst:typeset:17: no such variable: 02
+>typeset -g 0=tst
+>tst:18: 0: attempt to assign array value to non-array
+>tst:19: 2: attempt to assign array value to non-array
+>tst aaa bbb - tst - tst - bbb - bbb
+>tst:typeset:20: no such variable: 00
+>tst:typeset:20: no such variable: 2
+>tst:typeset:20: no such variable: 02
+>typeset -g 0=tst
+>tst aaa bbb '' '' zzz
+>tst aaa '' '' zzz
+>tst aaa '' zzz
+>tst aaa zzz
+>tst aaa
+>tst aaa
+
#
# The following tests are run in interactive mode, using PS1 as an
# assignable special with side-effects. This crashed at one time.
Messages sorted by:
Reverse Date,
Date,
Thread,
Author