Re: [PATCH] Implement references to positional parameters

Philippe Altherr <[email protected]>
Newsgroups gmane.comp.shells.zsh.devel
Message-ID <CAGdYchtKZKitbEyaA+wxS_C2b6y=s5-ZXfjeNDNjSy20gjmEXA@mail.gmail.com>
And one more update.

- Implement references to positional parameters
<https://github.com/paltherr/zsh/compare/paltherr:fix-unset...paltherr:zsh:fix-argn-refs>

Philippe
fix-argn-refs.txt (text/plain, 6.6 KB)
diff --git a/Src/params.c b/Src/params.c
index 81c3da74e..1ab6af595 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;
 
@@ -4898,6 +4905,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' */
 
 /**/
@@ -6290,6 +6340,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 0336a507d..6cfe6d1d0 100644
--- a/Test/K01nameref.ztst
+++ b/Test/K01nameref.ztst
@@ -1419,24 +1419,25 @@ 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 2 02 \! \? \$ - _
  do
-  edgelocal $edge
-  edgeupper $edge
+  edgelocal $edge foo
+  edgeupper $edge foo
  done
  unfunction edgelocal edgeupper
 0q:references to builtin specials
-F:BUG:References to 1, 2, ... are supported but don't work (always expand to "")
 >typeset -n x=argv
->argv
+>argv foo
 >typeset -n x=ARGC
->1
+>2
 >typeset -n x=0
 >edgelocal
->typeset -n x=1
->
->typeset -n x=01
->
+>typeset -n x=00
+>edgelocal
+>typeset -n x=2
+>foo
+>typeset -n x=02
+>foo
 >typeset -n x=!
 >0
 >typeset -un x=!
@@ -1466,8 +1467,78 @@ F:BUG:References to 1, 2, ... are supported but don't work (always expand to "")
 ?edgelocal: invalid variable name: #
 ?edgeupper: invalid variable name: #
 ?edgeupper: invalid variable name: 0
-?edgeupper: invalid variable name: 1
-?edgeupper: invalid variable name: 01
+?edgeupper: invalid variable name: 00
+?edgeupper: invalid variable name: 2
+?edgeupper: invalid variable name: 02
+
+ 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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.