From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 17461 invoked from network); 24 Jun 2001 11:34:48 -0000 Received: from sunsite.dk (130.225.51.30) by ns1.primenet.com.au with SMTP; 24 Jun 2001 11:34:48 -0000 Received: (qmail 21558 invoked by alias); 24 Jun 2001 11:34:03 -0000 Mailing-List: contact zsh-workers-help@sunsite.dk; run by ezmlm Precedence: bulk X-No-Archive: yes X-Seq: 15058 Received: (qmail 21527 invoked from network); 24 Jun 2001 11:34:02 -0000 Sender: kiddleo Message-ID: <3B35D04E.F6F4E3A1@u.genie.co.uk> Date: Sun, 24 Jun 2001 12:34:38 +0100 From: Oliver Kiddle X-Mailer: Mozilla 4.77 [en] (X11; U; Linux 2.2.15 i686) X-Accept-Language: en MIME-Version: 1.0 To: zsh-workers@sunsite.dk Subject: named references Content-Type: multipart/mixed; boundary="------------6DDEFA638A32B183DE306073" This is a multi-part message in MIME format. --------------6DDEFA638A32B183DE306073 Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit 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 --------------6DDEFA638A32B183DE306073 Content-Type: text/plain; charset=us-ascii; name="nameref.patch" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="nameref.patch" 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); --------------6DDEFA638A32B183DE306073 Content-Type: text/plain; charset=us-ascii; name="nameref" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="nameref" 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 --------------6DDEFA638A32B183DE306073--