Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

named references



I've had a bit of a look at the possibility of implementing ksh93 style
named references. The purpose of this e-mail is as a feeler to sound out
your opinions.

For the benefit of anyone who is not familiar with them, it involves a
new -n option to typeset so typeset -n ref=val creates a parameter --
ref -- which is then effectively a synonym for the val parameter. unset
also gains a -n option to unset the reference as opposed to what it
refers to. This is handy in the sort of situations where eval or
${(P)var} might currently be used but has certain advantages (in my
opinion) such as cleaner syntax.and the ability to remember the local
level of the variable referenced.

I've attached the text file where I've been jotting down any issues I've
thought of. There are a number of unusual issues (like the one with for
loops) so it is quite possible I've missed something.

I've also attached a patch of what I've done so far in case you are
interested but be aware that it has a number of problems and
limitations. At the moment I'm not interested in minor bug reports
(unless obscure) but am interested if you have more fundamental
suggestions. I'm going to be away until Wednesday but I should have
more time after then to devote to it.

At the moment, the basics work. I have not implemented ksh93's ${!ref}
which expands to whatever ref is a reference to. This syntax is a csh
style history reference in zsh, so I feared that any attempt by me to
implement it would break something else. It might be better to do this
with a parameter expansion flag (possibly two to allow a single
dereference in addition to ksh's full dereference?)? At the moment,
I've crudely implemented this with d as the expansion flag.

Oliver
Index: Src/builtin.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/builtin.c,v
retrieving revision 1.47
diff -u -r1.47 builtin.c
--- Src/builtin.c	2001/06/14 09:49:02	1.47
+++ Src/builtin.c	2001/06/24 11:32:04
@@ -111,12 +111,12 @@
     BUILTIN("trap", BINF_PSPECIAL, bin_trap, 0, -1, 0, NULL, NULL),
     BUILTIN("true", 0, bin_true, 0, -1, 0, NULL, NULL),
     BUILTIN("type", 0, bin_whence, 0, -1, 0, "ampfsw", "v"),
-    BUILTIN("typeset", BINF_TYPEOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, 0, "AEFHLRTUZafghilrtuxm", NULL),
+    BUILTIN("typeset", BINF_TYPEOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, 0, "AEFHLRTUZafghilnrtuxm", NULL),
     BUILTIN("umask", 0, bin_umask, 0, 1, 0, "S", NULL),
     BUILTIN("unalias", 0, bin_unhash, 1, -1, 0, "m", "a"),
     BUILTIN("unfunction", 0, bin_unhash, 1, -1, 0, "m", "f"),
     BUILTIN("unhash", 0, bin_unhash, 1, -1, 0, "adfm", NULL),
-    BUILTIN("unset", BINF_PSPECIAL, bin_unset, 1, -1, 0, "fm", NULL),
+    BUILTIN("unset", BINF_PSPECIAL, bin_unset, 1, -1, 0, "fmn", NULL),
     BUILTIN("unsetopt", 0, bin_setopt, 0, -1, BIN_UNSETOPT, NULL, NULL),
     BUILTIN("wait", 0, bin_fg, 0, -1, BIN_WAIT, NULL, NULL),
     BUILTIN("whence", 0, bin_whence, 0, -1, 0, "acmpvfsw", NULL),
@@ -1623,7 +1623,7 @@
     if (usepm || newspecial) {
 	int chflags = ((off & pm->flags) | (on & ~pm->flags)) &
 	     (PM_INTEGER|PM_EFLOAT|PM_FFLOAT|PM_HASHED|
-	      PM_ARRAY|PM_TIED|PM_AUTOLOAD);
+	      PM_NAMEREF|PM_ARRAY|PM_TIED|PM_AUTOLOAD);
 	/* keep the parameter if just switching between floating types */
 	if ((tc = chflags && chflags != (PM_EFLOAT|PM_FFLOAT)))
 	    usepm = 0;
@@ -1689,7 +1689,10 @@
 		   PM_EFLOAT | PM_FFLOAT)) &&
 	    auxlen)
 	    pm->ct = auxlen;
-	if (!(pm->flags & (PM_ARRAY|PM_HASHED))) {
+	if (pm->flags & PM_NAMEREF) {
+	    if (value && !(pm = setrparam(pname, ztrdup(value))))
+		return NULL;
+	} else if (!(pm->flags & (PM_ARRAY|PM_HASHED))) {
 	    if (pm->flags & PM_EXPORTED) {
 		if (!(pm->flags & PM_UNSET) && !pm->env && !value)
 		    pm->env = addenv(pname, getsparam(pname), pm->flags);
@@ -1794,6 +1797,10 @@
 	    zerrnam(cname,
 		    "%s: can't create readonly array elements", pname, 0);
 	    return NULL;
+	} else if (PM_TYPE(on) == PM_NAMEREF) {
+	    zerrnam(cname,
+		    "%s: array elements cannot be a reference", pname, 0);
+	    return NULL;
 	} else if (PM_TYPE(on) == PM_SCALAR) {
 	    /*
 	     * This will either complain about bad identifiers, or will set
@@ -1808,8 +1815,22 @@
 	    zerrnam(cname,
 		    "%s: array elements must be scalar", pname, 0);
 	    return NULL;
+	}
+    } else if (!isident(pname)) {
+	zerr("not an identifier: %s", pname, 0);
+	return NULL;
+    } else if (PM_TYPE(on) == PM_NAMEREF) {
+	if (!value) {
+    	    zerrnam(cname, "%s: must have value for nameref", pname, 0);
+	    return NULL;
 	}
-    } else if (isident(pname)) {
+
+	/* let setrparam call createparam for namerefs because we are  *
+	 * relying on error checking there and don't want to leave the *
+	 * parameter record in an inconsistent state                   */
+	if (!(pm = setrparam(pname, ztrdup(value))))
+	    return NULL;
+    } else {
 	/*
 	 * Create a new node for a parameter with the flags in `on' minus the
 	 * readonly flag
@@ -1817,9 +1838,6 @@
 	pm = createparam(pname, on & ~PM_READONLY);
 	DPUTS(!pm, "BUG: parameter not created");
 	pm->ct = auxlen;
-    } else {
-	zerr("not an identifier: %s", pname, 0);
-	return NULL;
     }
 
     if (altpm && PM_TYPE(pm->flags) == PM_SCALAR) {
@@ -1837,7 +1855,7 @@
 	pm->level = keeplocal;
     else if (on & PM_LOCAL)
 	pm->level = locallevel;
-    if (value && !(pm->flags & (PM_ARRAY|PM_HASHED))) {
+    if (value && !(pm->flags & (PM_ARRAY|PM_HASHED|PM_NAMEREF))) {
 	Param ipm = pm;
 	if (!(pm = setsparam(pname, ztrdup(value))))
 	    return NULL;
@@ -1877,7 +1895,6 @@
 	unsetparam_pm(pm, 0, 1);
 	return NULL;
     }
-
     return pm;
 }
 
@@ -1912,16 +1929,16 @@
     /* Sanity checks on the options.  Remove conficting options. */
     if (on & PM_FFLOAT) {
 	off |= PM_RIGHT_B | PM_LEFT | PM_RIGHT_Z | PM_UPPER | PM_ARRAY |
-	    PM_HASHED | PM_INTEGER | PM_EFLOAT;
+	    PM_HASHED | PM_NAMEREF | PM_INTEGER | PM_EFLOAT;
 	/* Allow `float -F' to work even though float sets -E by default */
 	on &= ~PM_EFLOAT;
     }
     if (on & PM_EFLOAT)
 	off |= PM_RIGHT_B | PM_LEFT | PM_RIGHT_Z | PM_UPPER | PM_ARRAY |
-	    PM_HASHED | PM_INTEGER | PM_FFLOAT;
+	    PM_HASHED | PM_NAMEREF | PM_INTEGER | PM_FFLOAT;
     if (on & PM_INTEGER)
 	off |= PM_RIGHT_B | PM_LEFT | PM_RIGHT_Z | PM_UPPER | PM_ARRAY |
-	    PM_HASHED | PM_EFLOAT | PM_FFLOAT;
+	    PM_HASHED | PM_NAMEREF | PM_EFLOAT | PM_FFLOAT;
     if (on & PM_LEFT)
 	off |= PM_RIGHT_B | PM_INTEGER | PM_EFLOAT | PM_FFLOAT;
     if (on & PM_RIGHT_B)
@@ -1933,9 +1950,12 @@
     if (on & PM_LOWER)
 	off |= PM_UPPER;
     if (on & PM_HASHED)
+	off |= PM_ARRAY | PM_NAMEREF;
+    if (on & PM_NAMEREF)
 	off |= PM_ARRAY;
     if (on & PM_TIED)
-	off |= PM_INTEGER | PM_EFLOAT | PM_FFLOAT | PM_ARRAY | PM_HASHED;
+	off |= PM_INTEGER | PM_EFLOAT | PM_FFLOAT | PM_ARRAY | PM_HASHED |
+	    PM_NAMEREF;
 
     on &= ~off;
 
@@ -2303,6 +2323,8 @@
     char *s;
     int match = 0, returnval = 0;
     int i;
+    int deref=(!ops['n']);
+    int level;
 
     /* unset -f is the same as unfunction */
     if (ops['f'])
@@ -2320,12 +2342,21 @@
 		    for (pm = (Param) paramtab->nodes[i]; pm; pm = next) {
 			/* record pointer to next, since we may free this one */
 			next = (Param) pm->next;
-			if ((!(pm->flags & PM_RESTRICTED) ||
-			    unset(RESTRICTED)) &&
-			    pattry(pprog, pm->nam)) {
-			    unsetparam_pm(pm, 0, 1);
-			    match++;
+
+			while (deref && pm && (pm->flags & PM_NAMEREF)) {
+			    level = pm->ct;
+    			    pm = (Param) paramtab->getnode(paramtab,
+			    	pm->gets.cfn(pm));
+	    	    	    while (pm && (pm->level > level)) pm = pm->old;
 			}
+
+			if (pm)
+			    if ((!(pm->flags & PM_RESTRICTED) ||
+				unset(RESTRICTED)) &&
+				pattry(pprog, pm->nam)) {
+				unsetparam_pm(pm, 0, 1);
+				match++;
+			    }
 		    }
 		}
 		unqueue_signals();
@@ -2346,6 +2377,7 @@
     while ((s = *argv++)) {
 	char *ss = strchr(s, '[');
 	char *sse = ss;
+	int level;
 	if (ss) {
 	    if (skipparens('[', ']', &sse) || *sse) {
 		zerrnam(name, "%s: invalid parameter name", s, 0);
@@ -2357,6 +2389,13 @@
 	pm = (Param) (paramtab == realparamtab ?
 		      gethashnode2(paramtab, s) :
 		      paramtab->getnode(paramtab, s));
+
+	while (deref && pm && (pm->flags & PM_NAMEREF)) {
+	    level = pm->ct;
+	    pm = (Param) paramtab->getnode(paramtab, pm->gets.cfn(pm));
+	    while (pm && (pm->level > level)) pm = pm->old;
+	}
+
 	if (!pm)
 	    returnval = 1;
 	else if ((pm->flags & PM_RESTRICTED) && isset(RESTRICTED)) {
Index: Src/params.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/params.c,v
retrieving revision 1.50
diff -u -r1.50 params.c
--- Src/params.c	2001/06/15 13:07:50	1.50
+++ Src/params.c	2001/06/24 11:32:04
@@ -456,7 +456,7 @@
 }
 
 /*
- * Split environment string into (name, vlaue) pair.
+ * Split environment string into (name, value) pair.
  * this is used to avoid in-place editing of environment table
  * that results in core dump on some systems
  */
@@ -644,6 +644,10 @@
 	pm->sets.hfn = hashsetfn;
 	pm->gets.hfn = hashgetfn;
 	break;
+    case PM_NAMEREF:
+    	pm->sets.cfn = refsetfn;
+	pm->gets.cfn = refgetfn;
+	break;
     default:
 	DPUTS(1, "BUG: tried to create param node without valid flag");
 	break;
@@ -674,7 +678,7 @@
 			 paramtab->getnode(paramtab, name));
 
 	DPUTS(oldpm && oldpm->level > locallevel,
-	      "BUG:  old local parameter not deleteed");
+	      "BUG:  old local parameter not deleted");
 	if (oldpm && (oldpm->level == locallevel || !(flags & PM_LOCAL))) {
 	    if (!(oldpm->flags & PM_UNSET) || (oldpm->flags & PM_SPECIAL)) {
 		oldpm->flags &= ~PM_UNSET;
@@ -756,6 +760,9 @@
     case PM_HASHED:
 	tpm->u.hash = copyparamtable(pm->gets.hfn(pm), pm->nam);
 	break;
+    default:
+	DPUTS(1, "BUG: tried to copy param node without valid flag");
+	break;
     }
     /*
      * If called from inside an associative array, that array is later going
@@ -782,7 +789,7 @@
 	return 0;
 
     if (idigit(*s)) {
-	/* If the first character is `s' is a digit, then all must be */
+	/* If the first character in `s' is a digit, then all must be */
 	for (ss = ++s; *ss; ss++)
 	    if (!idigit(*ss))
 		break;
@@ -1288,17 +1295,38 @@
     return 0;
 }
 
+/* dereferences a value, returning also the name of the referenced parameter *
+ * for cases where that parameter might be unset so the name is needed       */
+
+/**/
+Value
+derefvalue(Value v, char **name, int flags)
+{
+    /* will probably merge this into fetchvalue, adding another param to
+       fetchvalue */
+    char *s = *name;
+
+    if (!v) return NULL;
+    
+    v = fetchvalue(v, &s, 1, flags, 0);
+    while (v && (v->pm->flags & PM_NAMEREF)) {
+        *name = s = v->pm->gets.cfn(v->pm);
+        v = fetchvalue(v, &s, 1, flags, 0);
+    }
+    
+    return v;
+}
 
 /**/
 mod_export Value
 getvalue(Value v, char **pptr, int bracks)
 {
-  return fetchvalue(v, pptr, bracks, 0);
+  return fetchvalue(v, pptr, bracks, 0, 1);
 }
 
 /**/
 mod_export Value
-fetchvalue(Value v, char **pptr, int bracks, int flags)
+fetchvalue(Value v, char **pptr, int bracks, int flags, int deref)
 {
     char *s, *t;
     char sav, c;
@@ -1347,12 +1375,21 @@
     } else {
 	Param pm;
 	int isvarat;
+	int level;
 
         isvarat = (t[0] == '@' && !t[1]);
 	pm = (Param) paramtab->getnode(paramtab, *t == '0' ? "0" : t);
 	if (sav)
 	    *s = sav;
 	*pptr = s;
+
+	/* dereference namerefs */
+    	while (deref && pm && (pm->flags & PM_NAMEREF)) {
+	    level = pm->ct;
+	    pm = (Param) paramtab->getnode(paramtab, pm->gets.cfn(pm));
+	    while (pm && (pm->level > level)) pm = pm->old;
+	}
+	
 	if (!pm || (pm->flags & PM_UNSET))
 	    return NULL;
 	if (v)
@@ -1886,12 +1923,12 @@
     queue_signals();
     if ((ss = strchr(s, '['))) {
 	*ss = '\0';
-	if (!(v = getvalue(&vbuf, &s, 1)))
+	if (!(v = derefvalue(&vbuf, &t, 0)))
 	    createparam(t, PM_ARRAY);
 	*ss = '[';
 	v = NULL;
     } else {
-	if (!(v = getvalue(&vbuf, &s, 1)))
+	if (!(v = derefvalue(&vbuf, &t, 0)))
 	    createparam(t, PM_SCALAR);
 	else if ((PM_TYPE(v->pm->flags) & (PM_ARRAY|PM_HASHED)) &&
 		 !(v->pm->flags & (PM_SPECIAL|PM_TIED)) && unset(KSHARRAYS)) {
@@ -1928,7 +1965,7 @@
     queue_signals();
     if ((ss = strchr(s, '['))) {
 	*ss = '\0';
-	if (!(v = getvalue(&vbuf, &s, 1)))
+	if (!(v = derefvalue(&vbuf, &t, 0)))
 	    createparam(t, PM_ARRAY);
 	*ss = '[';
 	if (v && PM_TYPE(v->pm->flags) == PM_HASHED) {
@@ -1941,7 +1978,7 @@
 	}
 	v = NULL;
     } else {
-	if (!(v = fetchvalue(&vbuf, &s, 1, SCANPM_ASSIGNING)))
+	if (!(v = derefvalue(&vbuf, &t, SCANPM_ASSIGNING)))
 	    createparam(t, PM_ARRAY);
 	else if (!(PM_TYPE(v->pm->flags) & (PM_ARRAY|PM_HASHED)) &&
 		 !(v->pm->flags & (PM_SPECIAL|PM_TIED))) {
@@ -1952,7 +1989,7 @@
 	}
     }
     if (!v)
-	if (!(v = fetchvalue(&vbuf, &t, 1, SCANPM_ASSIGNING))) {
+	if (!(v = derefvalue(&vbuf, &t, SCANPM_ASSIGNING))) {
 	    unqueue_signals();
 	    return NULL;
 	}
@@ -1982,7 +2019,7 @@
 	return NULL;
     }
     queue_signals();
-    if (!(v = fetchvalue(&vbuf, &s, 1, SCANPM_ASSIGNING)))
+    if (!(v = derefvalue(&vbuf, &t, SCANPM_ASSIGNING)))
 	createparam(t, PM_HASHED);
     else if (!(PM_TYPE(v->pm->flags) & PM_HASHED) &&
 	     !(v->pm->flags & PM_SPECIAL)) {
@@ -1991,7 +2028,7 @@
 	v = NULL;
     }
     if (!v)
-	if (!(v = fetchvalue(&vbuf, &t, 1, SCANPM_ASSIGNING))) {
+	if (!(v = derefvalue(&vbuf, &t, SCANPM_ASSIGNING))) {
 	    unqueue_signals();
 	    return NULL;
 	}
@@ -2006,7 +2043,7 @@
 {
     struct value vbuf;
     Value v;
-    char *t = s, *ss;
+    char *ss;
     Param pm;
     mnumber mnval;
 
@@ -2016,18 +2053,18 @@
 	return NULL;
     }
     queue_signals();
-    if (!(v = getvalue(&vbuf, &s, 1))) {
+    if (!(v = derefvalue(&vbuf, &s, 0))) {
 	if ((ss = strchr(s, '[')))
 	    *ss = '\0';
-	if (!(pm = createparam(t, ss ? PM_ARRAY : PM_INTEGER)))
-	    pm = (Param) paramtab->getnode(paramtab, t);
+	if (!(pm = createparam(s, ss ? PM_ARRAY : PM_INTEGER)))
+	    pm = (Param) paramtab->getnode(paramtab, s);
 	DPUTS(!pm, "BUG: parameter not created");
 	if (ss) {
 	    *ss = '[';
 	} else {
 	    pm->ct = outputradix;
 	}
-	v = getvalue(&vbuf, &t, 1);
+	v = derefvalue(&vbuf, &s, 0);
 	DPUTS(!v, "BUG: value not found for new parameter");
     }
     mnval.type = MN_INTEGER;
@@ -2048,7 +2085,7 @@
 {
     struct value vbuf;
     Value v;
-    char *t = s, *ss = NULL;
+    char *ss;
     Param pm;
 
     if (!isident(s)) {
@@ -2057,20 +2094,20 @@
 	return NULL;
     }
     queue_signals();
-    if (!(v = getvalue(&vbuf, &s, 1))) {
+    if (!(v = derefvalue(&vbuf, &s, 0))) {
 	if ((ss = strchr(s, '[')))
 	    *ss = '\0';
-	pm = createparam(t, ss ? PM_ARRAY :
+	pm = createparam(s, ss ? PM_ARRAY :
 			 (val.type & MN_INTEGER) ? PM_INTEGER : PM_FFLOAT);
 	if (!pm)
-	    pm = (Param) paramtab->getnode(paramtab, t);
+	    pm = (Param) paramtab->getnode(paramtab, s);
 	DPUTS(!pm, "BUG: parameter not created");
 	if (ss) {
 	    *ss = '[';
 	} else if (val.type & MN_INTEGER) {
 	    pm->ct = outputradix;
 	}
-	v = getvalue(&vbuf, &t, 1);
+	v = derefvalue(&vbuf, &s, 0);
 	DPUTS(!v, "BUG: value not found for new parameter");
     }
     setnumvalue(v, val);
@@ -2078,6 +2115,61 @@
     return v->pm;
 }
 
+/* function for setting a reference to the name of a parameter */
+
+/**/
+Param
+setrparam(char *s, char *val)
+{
+    struct value vbuf;
+    Value v;
+    Param vpm;
+    char *t = s;
+    char *w = val;
+    char *ss;
+
+    if (!isident(s) || idigit(*s) || strchr(s, '[')) {
+	zerr("not an identifier: %s", s, 0);
+	zsfree(val);
+	errflag = 1;
+	return NULL;
+    }
+    if (!isident(val) || idigit(*val) || strchr(val, '[')) {
+    	zerr("invalid variable name: %s", val, 0);
+	zsfree(val);
+	errflag = 1;
+	return NULL;
+    }
+
+    vpm = (Param) paramtab->getnode(paramtab, val);
+    if (!strcmp(s, val) && ((!vpm) || (vpm->level >= locallevel))) {
+    	zerr("invalid self reference: %s", s, 0);
+	zsfree(val);
+	errflag = 1;
+	return NULL;
+    }
+    v = derefvalue(&vbuf, &w, 0);
+    if (!strcmp(s, w)) {
+    	zerr("invalid self reference: %s", s, 0);
+	zsfree(val);
+	errflag = 1;
+	return NULL;
+    }
+	
+    queue_signals();
+    if (!(v = fetchvalue(&vbuf, &s, 1, 0, 0)))
+	createparam(t, PM_NAMEREF);
+    if (!v && !(v = fetchvalue(&vbuf, &t, 1, 0, 0))) {
+	unqueue_signals();
+	zsfree(val);
+	return NULL;
+    }
+    v->pm->sets.cfn(v->pm, val);
+    v->pm->ct = (vpm ? vpm->level : 0);
+    unqueue_signals();
+    return v->pm;
+}
+
 /* Unset a parameter */
 
 /**/
@@ -2323,6 +2415,26 @@
     free(val);		/* not freearray() */
 }
 
+
+/* Function to get value of a nameref parameter */
+
+/**/
+char *
+refgetfn(Param pm)
+{
+    return pm->u.str;
+}
+
+/* Function to set value of a nameref parameter */
+
+/**/
+static void
+refsetfn(Param pm, char *x)
+{
+    zsfree(pm->u.str);
+    pm->u.str = x;
+}
+
 /*
  * These functions are used as the set function for special parameters that
  * cannot be set by the user.  The set is incomplete as the only such
@@ -3347,6 +3459,8 @@
 	    printf("array ");
 	else if (p->flags & PM_HASHED)
 	    printf("association ");
+	else if (p->flags & PM_NAMEREF)
+	    printf("nameref ");
 	if (p->level)
 	    printf("local ");
 	if (p->flags & PM_LEFT)
@@ -3389,6 +3503,7 @@
      * on the type of the parameter       */
     switch (PM_TYPE(p->flags)) {
     case PM_SCALAR:
+    case PM_NAMEREF:
 	/* string: simple output */
 	if (p->gets.cfn && (t = p->gets.cfn(p)))
 	    quotedzputs(t, stdout);
Index: Src/subst.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/subst.c,v
retrieving revision 1.20
diff -u -r1.20 subst.c
--- Src/subst.c	2001/06/12 10:34:57	1.20
+++ Src/subst.c	2001/06/24 11:32:04
@@ -778,6 +778,7 @@
     zlong prenum = 0, postnum = 0;
     int copied = 0;
     int arrasg = 0;
+    int deref = 0;
     int eval = 0;
     int aspar = 0;
     int presc = 0;
@@ -889,6 +890,9 @@
 		    quoteerr = 1;
 		    break;
 
+    	    	case 'd':
+		    deref = 1;
+		    break;
 		case 'e':
 		    eval = 1;
 		    break;
@@ -1079,7 +1083,7 @@
 	    s++;
 	v = (Value) NULL;
     } else if (aspar) {
-	if ((v = fetchvalue(&vbuf, &s, 1, (qt ? SCANPM_DQUOTED : 0)))) {
+	if ((v = fetchvalue(&vbuf, &s, 1, (qt ? SCANPM_DQUOTED : 0), 1))) {
 	    val = idbeg = getstrvalue(v);
 	    subexp = 1;
 	} else
@@ -1088,14 +1092,28 @@
     if (!subexp || aspar) {
 	char *ov = val;
 
+	if (deref) {
+            /* this doesn't work */
+    	    val = s;
+	    v = derefvalue(&vbuf, &val, 0);
+	    val = dupstring(val);
+	    isarr = 0;
+	}
+	
 	if (!(v = fetchvalue(&vbuf, (subexp ? &ov : &s),
 			     (wantt ? -1 :
 			      ((unset(KSHARRAYS) || inbrace) ? 1 : -1)),
 			     hkeys|hvals|
 			     (arrasg ? SCANPM_ASSIGNING : 0)|
-			     (qt ? SCANPM_DQUOTED : 0))) ||
+			     (qt ? SCANPM_DQUOTED : 0), 1)) ||
 	    (v->pm && (v->pm->flags & PM_UNSET)))
 	    vunset = 1;
+	
+	if (deref) {
+	  /* need the updated s from above */
+	  vunset = 0;
+	  v = NULL;
+	}
 
 	if (wantt) {
 	    if (v && v->pm && !(v->pm->flags & PM_UNSET)) {
Index: Src/zsh.h
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/zsh.h,v
retrieving revision 1.31
diff -u -r1.31 zsh.h
--- Src/zsh.h	2001/06/12 10:34:57	1.31
+++ Src/zsh.h	2001/06/24 11:32:04
@@ -1096,46 +1096,47 @@
 #define PM_EFLOAT	(1<<2)	/* double with %e output		    */
 #define PM_FFLOAT	(1<<3)	/* double with %f output		    */
 #define PM_HASHED	(1<<4)	/* association                              */
+#define PM_NAMEREF	(1<<5)  /* named reference                          */
 
 #define PM_TYPE(X) \
-  (X & (PM_SCALAR|PM_INTEGER|PM_EFLOAT|PM_FFLOAT|PM_ARRAY|PM_HASHED))
+  (X & (PM_SCALAR|PM_INTEGER|PM_EFLOAT|PM_FFLOAT|PM_ARRAY|PM_HASHED|PM_NAMEREF))
 
-#define PM_LEFT		(1<<5)	/* left justify, remove leading blanks      */
-#define PM_RIGHT_B	(1<<6)	/* right justify, fill with leading blanks  */
-#define PM_RIGHT_Z	(1<<7)	/* right justify, fill with leading zeros   */
-#define PM_LOWER	(1<<8)	/* all lower case                           */
+#define PM_LEFT		(1<<6)	/* left justify, remove leading blanks      */
+#define PM_RIGHT_B	(1<<7)	/* right justify, fill with leading blanks  */
+#define PM_RIGHT_Z	(1<<8)	/* right justify, fill with leading zeros   */
+#define PM_LOWER	(1<<9)	/* all lower case                           */
 
 /* The following are the same since they *
  * both represent -u option to typeset   */
-#define PM_UPPER	(1<<9)	/* all upper case                           */
-#define PM_UNDEFINED	(1<<9)	/* undefined (autoloaded) shell function    */
+#define PM_UPPER	(1<<10)	/* all upper case                           */
+#define PM_UNDEFINED	(1<<10)	/* undefined (autoloaded) shell function    */
 
-#define PM_READONLY	(1<<10)	/* readonly                                 */
-#define PM_TAGGED	(1<<11)	/* tagged                                   */
-#define PM_EXPORTED	(1<<12)	/* exported                                 */
+#define PM_READONLY	(1<<11)	/* readonly                                 */
+#define PM_TAGGED	(1<<12)	/* tagged                                   */
+#define PM_EXPORTED	(1<<13)	/* exported                                 */
 
 /* The following are the same since they *
  * both represent -U option to typeset   */
-#define PM_UNIQUE	(1<<13)	/* remove duplicates                        */
-#define PM_UNALIASED	(1<<13)	/* do not expand aliases when autoloading   */
+#define PM_UNIQUE	(1<<14)	/* remove duplicates                        */
+#define PM_UNALIASED	(1<<14)	/* do not expand aliases when autoloading   */
 
-#define PM_HIDE		(1<<14)	/* Special behaviour hidden by local        */
-#define PM_HIDEVAL	(1<<15)	/* Value not shown in `typeset' commands    */
-#define PM_TIED 	(1<<16)	/* array tied to colon-path or v.v.         */
+#define PM_HIDE		(1<<15)	/* Special behaviour hidden by local        */
+#define PM_HIDEVAL	(1<<16)	/* Value not shown in `typeset' commands    */
+#define PM_TIED 	(1<<17)	/* array tied to colon-path or v.v.         */
 
 /* Remaining flags do not correspond directly to command line arguments */
-#define PM_LOCAL	(1<<17) /* this parameter will be made local        */
-#define PM_SPECIAL	(1<<18) /* special builtin parameter                */
-#define PM_DONTIMPORT	(1<<19)	/* do not import this variable              */
-#define PM_RESTRICTED	(1<<20) /* cannot be changed in restricted mode     */
-#define PM_UNSET	(1<<21)	/* has null value                           */
-#define PM_REMOVABLE	(1<<22)	/* special can be removed from paramtab     */
-#define PM_AUTOLOAD	(1<<23) /* autoloaded from module                   */
-#define PM_NORESTORE	(1<<24)	/* do not restore value of local special    */
-#define PM_HASHELEM     (1<<25) /* is a hash-element */
+#define PM_LOCAL	(1<<18) /* this parameter will be made local        */
+#define PM_SPECIAL	(1<<19) /* special builtin parameter                */
+#define PM_DONTIMPORT	(1<<20)	/* do not import this variable              */
+#define PM_RESTRICTED	(1<<21) /* cannot be changed in restricted mode     */
+#define PM_UNSET	(1<<22)	/* has null value                           */
+#define PM_REMOVABLE	(1<<23)	/* special can be removed from paramtab     */
+#define PM_AUTOLOAD	(1<<24) /* autoloaded from module                   */
+#define PM_NORESTORE	(1<<25)	/* do not restore value of local special    */
+#define PM_HASHELEM     (1<<26) /* is a hash-element */
 
 /* The option string corresponds to the first of the variables above */
-#define TYPESET_OPTSTR "aiEFALRZlurtxUhHT"
+#define TYPESET_OPTSTR "aiEFAnLRZlurtxUhHT"
 
 /* These typeset options take an optional numeric argument */
 #define TYPESET_OPTNUM "LRZiEF"
Index: Src/Zle/compcore.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/Zle/compcore.c,v
retrieving revision 1.45
diff -u -r1.45 compcore.c
--- Src/Zle/compcore.c	2001/02/28 09:12:57	1.45
+++ Src/Zle/compcore.c	2001/06/24 11:32:05
@@ -1549,7 +1549,7 @@
     queue_signals();
     if (!(v = fetchvalue(&vbuf, &name, 1,
 			 (keys ? SCANPM_WANTKEYS : SCANPM_WANTVALS) |
-			 SCANPM_MATCHMANY)))
+			 SCANPM_MATCHMANY, 1)))
 	ret = NULL;
     else
 	ret = getarrvalue(v);
Index: Src/Zle/zle_main.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/Zle/zle_main.c,v
retrieving revision 1.18
diff -u -r1.18 zle_main.c
--- Src/Zle/zle_main.c	2001/05/17 15:56:13	1.18
+++ Src/Zle/zle_main.c	2001/06/24 11:32:05
@@ -839,7 +839,7 @@
     s = args[0];
     queue_signals();
     v = fetchvalue(&vbuf, &s, (!create || type == PM_SCALAR),
-		   SCANPM_WANTKEYS|SCANPM_WANTVALS|SCANPM_MATCHMANY);
+		   SCANPM_WANTKEYS|SCANPM_WANTVALS|SCANPM_MATCHMANY, 1);
     if (!v && !create) {
 	unqueue_signals();
 	zwarnnam(name, "no such variable: %s", args[0], 0);
ksh93 style named references - semantics

references to references allowed, so:
  $ val=fred
  $ typeset -n ref=val
  $ typeset -n word=ref
  $ echo $word
  fred

can point to an unset variable:
  $ unset val
  $ typeset -n ref=val
  $ echo $ref

  $ echo $val

can point to array, assoc etc and will be treated as such:
  $ arr=(one two three)
  $ typeset -n val=arr
  $ echo ${val[1]}
  two

but cannot point to an array element:
  $ typeset -n val=arr[1]
  ksh: typeset: arr[1]: is not an identifier

also, the element of an array, assoc can not be a reference, just as it can't
be a float etc:
  $ typeset -n ref[1]=val
  ksh: typeset: ref: reference variable cannot be an array

but can't point to an invalid variable name:
  $ typeset -n ref=1val
  ksh: typeset: 1val: invalid variable name

or to nothing:
  $ typeset -n ref
  ksh: typeset: ref: no reference name
  $ typeset -n r=''
  ksh: typeset: : is not an identifier

or to a positional parameter

cycles and self-references blocked
  $ typeset -n ref=val
  $ typeset -n val=ref
  ksh: typeset: val: invalid self reference

references can't be exported
local applies to the reference not the variable

attributes apply to the value not the reference:
  $ typeset -n val=one
  $ typeset -n ref=val
  $ typeset -u ref
  $ echo $ref
  ONE
  $ echo $val
  ONE
this includes readonly

in ksh though:
  $ typeset -n -r ref=val
  ksh: typeset: ref: is read only
might be good if this would define ref as a readonly reference
  
dereference with ${!...}
  $ typeset -n ref=val
  $ echo ${!ref}
  val

dereference goes all the way so
  $ typeset -n ref=val
  $ typeset -n ref2=ref
  $ echo ${!ref2}
  val

ksh has compiled in alias - nameref='typeset -n'

typeset +n lists names of reference variables

typeset -n lists reference variables with values

only with -n will typeset act on the reference not the value

unset applies to the referenced variable

unset has a -n option which will unset the actual reference

typeset +n ref converts ref to a scalar

in ksh, references to positional variables are not allowed:
  $ typeset -n val=3
  ksh: typeset: 3: invalid variable name

if ksh is given an nameref as the index to a for loop it assigns the values as
for the reference, not the value. It could be very useful but isn't what what
you'd first expect. Is there a good alternative to avoid this:
  $ typeset -n ref=dummy
  $ for ref in var1 var2 ...

in ksh, typeset -n ref[one]=val is allowed with [one] ignored

reference records the local level so:
  $ function f {
  $   typeset -n ref=val
  $   typeset val=two
  $   echo $ref
  $ }
  $ val=one
  $ f val
would echo `one'

because of the above, it needs to handle the situation where
unset ref is done in the function above and also where ref is
then also reassigned a value.

ksh is not clever enough to allow typeset -n ref=ref in a function though

Extra issues in zsh:

local should be implied for typeset -n without +l.

what should ${(t)ref} return - the same as what it refers to with -nameref-
inserted?

should we use namerefs for prompt, rprompt, PROMPT-PROMPT4?

how messy will references to specials be?
might we need special references - I hope not.

any uses in completion functions? _call_function for starters.

test vared, read, case etc


Messages sorted by: Reverse Date, Date, Thread, Author