From mboxrd@z Thu Jan 1 00:00:00 1970 Mailing-List: contact zsh-workers-help@sunsite.auc.dk; run by ezmlm Precedence: bulk X-No-Archive: yes Message-Id: <9901281725.AA31711@ibmth.df.unipi.it> To: zsh-workers@sunsite.auc.dk (Zsh hackers list) Subject: PATCH: zsh-3.1.5-pws-5 + recent: typeset -T MYPATH mypath (finally!) Date: Thu, 28 Jan 1999 18:25:39 +0100 From: Peter Stephenson X-Mailing-List: 5094 Now I've tidied up bin_typeset() a bit, it's finally possible to make user-tiable path-like variables without the onset of suicidal feelings. This has been requested for several years. Maybe there's not even anyone left who wants it --- word splitting and joining has improved quite a lot since then. The syntax is typeset -T TEXINPUTS texinputs where the scalar has to come first, but there is no restriction on the names. As usual, the pair will be local to any function in which you use typeset. You can avoid this by using export directly: export -T TEXINPUTS=... texinputs is the canonical way to set something like this the first time, since there's not a lot of point of having the colon array unless you export it. `typeset -T' on its own works as expected, but I haven't made any special arrangement for ${(t)...}, which would have to cover $PATH etc. too. Also, typeset +T doesn't work. There are all sorts of potential problems with null arrays and memory leaks etc., but I haven't run across any yet. I fixed a couple of documentation bugs for typeset and a minor (recent) bracketing problem at the top of getarg() (that will be rejected if you're not patched up to date). The problem I was trying to tackle with the new `keeplocal' variable in typeset_single() may or may not be real, but it makes me feel happier. Also, `export -i foo; typeset +i foo' used to forget $foo was exported, now it remembers, likewise `export FOO; typeset -T FOO foo', which is how I discovered it. Feel free to destruction test this. --- Doc/Zsh/builtins.yo.tied Thu Jan 14 16:19:39 1999 +++ Doc/Zsh/builtins.yo Thu Jan 28 18:04:21 1999 @@ -878,7 +878,10 @@ findex(typeset) cindex(parameters, setting) cindex(parameters, declaring) -item(tt(typeset) [ {tt(PLUS())|tt(-)}tt(ALRUZafilrtuxm) [var(n)]] [ var(name)[tt(=)var(value)] ... ])( +xitem(tt(typeset) [ {tt(PLUS())|tt(-)}tt(ALRUZafilrtuxm) [var(n)]] [ \ +var(name)[tt(=)var(value)] ... ]) +item(tt(typeset) -T [ {tt(PLUS()|tt(-))}tt(LRUZrux) ] \ + var(SCALAR)[tt(=)var(value)] var(array))( Set or display attributes and values for shell parameters. A parameter is created for each var(name) that does not already refer @@ -891,13 +894,23 @@ which case the parameter is exported em(only) when var(name) does not already appear in the environment. -For each nofill(var(name)tt(=)var(value)) assignment, the parameter +For each var(name)tt(=)var(value) assignment, the parameter var(name) set to var(value). Note that arrays currently cannot be assigned in tt(typeset) expressions; scalars and integers only. For each remaining var(name) that refers to a parameter that is set, the name and value of the parameter are printed in the form of an assignment. Nothing is printed for newly-created parameters. + +If the tt(-T) option is given, exactly two (or zero) var(name) +arguments must be present. They represent a scalar and an array (in +that order) that will be tied together in the manner of tt($PATH) and +tt($path). In other words, an array present in the latter variable +appears as a scalar with the elements of the array joined by colons in +the former. Only the scalar may have an initial value. Both the +scalar and the array may otherwise be manipulated as normal. If one +is unset, the other will automatically be unset too. There is no way +of untying the variables without unsetting them; tt(+T) does not work. If no var(name) is present, the names and values of all parameters are printed. In this case the attribute flags restrict the the display to --- Src/builtin.c.tied Fri Jan 22 13:28:35 1999 +++ Src/builtin.c Thu Jan 28 18:04:06 1999 @@ -50,7 +50,7 @@ BUILTIN("cd", 0, bin_cd, 0, 2, BIN_CD, NULL, NULL), BUILTIN("chdir", 0, bin_cd, 0, 2, BIN_CD, NULL, NULL), BUILTIN("continue", BINF_PSPECIAL, bin_break, 0, 1, BIN_CONTINUE, NULL, NULL), - BUILTIN("declare", BINF_TYPEOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, 0, "ALRUZafilrtux", NULL), + BUILTIN("declare", BINF_TYPEOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, 0, "ALRTUZafilrtux", NULL), BUILTIN("dirs", 0, bin_dirs, 0, -1, 0, "v", NULL), BUILTIN("disable", 0, bin_enable, 0, -1, BIN_DISABLE, "afmr", NULL), BUILTIN("disown", 0, bin_fg, 0, -1, BIN_DISOWN, NULL, NULL), @@ -60,7 +60,7 @@ BUILTIN("enable", 0, bin_enable, 0, -1, BIN_ENABLE, "afmr", NULL), BUILTIN("eval", BINF_PSPECIAL, bin_eval, 0, -1, BIN_EVAL, NULL, NULL), BUILTIN("exit", BINF_PSPECIAL, bin_break, 0, 1, BIN_EXIT, NULL, NULL), - BUILTIN("export", BINF_TYPEOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, BIN_EXPORT, "LRUZafilrtu", "x"), + BUILTIN("export", BINF_TYPEOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, BIN_EXPORT, "LRTUZafilrtu", "x"), BUILTIN("false", 0, bin_false, 0, -1, 0, NULL, NULL), BUILTIN("fc", BINF_FCOPTS, bin_fc, 0, -1, BIN_FC, "nlreIRWAdDfEim", NULL), BUILTIN("fg", 0, bin_fg, 0, -1, BIN_FG, NULL, NULL), @@ -78,7 +78,7 @@ BUILTIN("jobs", 0, bin_fg, 0, -1, BIN_JOBS, "dlpZrs", NULL), BUILTIN("kill", 0, bin_kill, 0, -1, 0, NULL, NULL), BUILTIN("let", 0, bin_let, 1, -1, 0, NULL, NULL), - BUILTIN("local", BINF_TYPEOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, 0, "ALRUZailrtu", NULL), + BUILTIN("local", BINF_TYPEOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, 0, "ALRTUZailrtu", NULL), BUILTIN("log", 0, bin_log, 0, 0, 0, NULL, NULL), BUILTIN("logout", 0, bin_break, 0, 1, BIN_LOGOUT, NULL, NULL), @@ -93,7 +93,7 @@ BUILTIN("pwd", 0, bin_pwd, 0, 0, 0, "rLP", NULL), BUILTIN("r", BINF_R, bin_fc, 0, -1, BIN_FC, "nrl", NULL), BUILTIN("read", 0, bin_read, 0, -1, 0, "rzu0123456789pkqecnAlE", NULL), - BUILTIN("readonly", BINF_TYPEOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, 0, "ALRUZafiltux", "r"), + BUILTIN("readonly", BINF_TYPEOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, 0, "ALRTUZafiltux", "r"), BUILTIN("rehash", 0, bin_hash, 0, 0, 0, "dfv", "r"), BUILTIN("return", BINF_PSPECIAL, bin_break, 0, 1, BIN_RETURN, NULL, NULL), BUILTIN("set", BINF_PSPECIAL, bin_set, 0, -1, 0, NULL, NULL), @@ -107,7 +107,7 @@ 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, "ALRUZafilrtuxm", NULL), + BUILTIN("typeset", BINF_TYPEOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, 0, "ALRTUZafilrtuxm", 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"), @@ -1468,11 +1468,11 @@ /* function to set a single parameter */ /**/ -int +Param typeset_single(char *cname, char *pname, Param pm, int func, - int on, int off, int roff, char *value) + int on, int off, int roff, char *value, Param altpm) { - int usepm, tc; + int usepm, tc, keeplocal = 0; /* use the existing pm? */ usepm = pm && !(pm->flags & PM_UNSET); @@ -1490,24 +1490,24 @@ locallevel != pm->level && func != BIN_EXPORT) usepm = 0; - /* attempting a type conversion? */ + /* attempting a type conversion, or making a tied colonarray? */ if ((tc = usepm && (((off & pm->flags) | (on & ~pm->flags)) & - (PM_INTEGER|PM_HASHED|PM_ARRAY)))) + (PM_INTEGER|PM_HASHED|PM_ARRAY|PM_TIED)))) usepm = 0; if (tc && (pm->flags & PM_SPECIAL)) { zerrnam(cname, "%s: can't change type of a special parameter", pname, 0); - return 1; + return NULL; } if (usepm) { if (!on && !roff && !value) { paramtab->printnode((HashNode)pm, 0); - return 0; + return pm; } if ((pm->flags & PM_RESTRICTED && isset(RESTRICTED))) { zerrnam(cname, "%s: restricted", pname, 0); - return 1; + return pm; } if (PM_TYPE(pm->flags) == PM_ARRAY && (on & PM_UNIQUE) && !(pm->flags & PM_READONLY & ~off)) @@ -1530,9 +1530,9 @@ setsparam(pname, ztrdup(value)); } else if (value) { zwarnnam(cname, "can't assign new value for array %s", pname, 0); - return 1; + return NULL; } - return 0; + return pm; } /* @@ -1542,10 +1542,15 @@ * last case only, we need to delete the old parameter. */ if (tc) { - if (pm->flags & PM_READONLY) { - on |= ~off & PM_READONLY; - pm->flags &= ~PM_READONLY; - } + /* Maintain existing readonly/exported status... */ + on |= ~off & (PM_READONLY|PM_EXPORTED) & pm->flags; + /* ...but turn off existing readonly so we can delete it */ + pm->flags &= ~PM_READONLY; + /* + * If we're just changing the type, we should keep the + * variable at the current level of localness. + */ + keeplocal = pm->level; /* * Try to carry over a value, but not when changing from, * to, or between non-scalar types. @@ -1563,17 +1568,33 @@ pm = createparam(pname, on & ~PM_READONLY); DPUTS(!pm, "BUG: parameter not created"); pm->ct = auxlen; - if (func != BIN_EXPORT) + + if (altpm && PM_TYPE(pm->flags) == PM_SCALAR) { + /* + * It seems safer to set this here than in createparam(), + * to make sure we only ever use the colonarr functions + * when u.data is correctly set. + */ + pm->sets.cfn = colonarrsetfn; + pm->gets.cfn = colonarrgetfn; + pm->u.data = &altpm->u.arr; + } + + if (keeplocal) + pm->level = keeplocal; + else if (func != BIN_EXPORT) pm->level = locallevel; if (value && !(pm->flags & (PM_ARRAY|PM_HASHED))) setsparam(pname, ztrdup(value)); pm->flags |= (on & PM_READONLY); if (value && (pm->flags & (PM_ARRAY|PM_HASHED))) { zerrnam(cname, "%s: can't assign initial value for array", pname, 0); - return 1; + /* the only safe thing to do here seems to be unset the param */ + unsetparam_pm(pm, 0, 1); + return NULL; } - return 0; + return pm; } /* declare, export, integer, local, readonly, typeset */ @@ -1585,7 +1606,7 @@ Param pm; Asgment asg; Comp com; - char *optstr = "aiALRZlurtxU"; + char *optstr = "aiALRZlurtxUT"; int on = 0, off = 0, roff, bit = PM_ARRAY; int i; int returnval = 0, printflags = 0; @@ -1619,6 +1640,9 @@ off |= PM_UPPER; if (on & PM_HASHED) off |= PM_ARRAY; + if (on & PM_TIED) + off |= PM_INTEGER | PM_ARRAY | PM_HASHED; + on &= ~off; /* Given no arguments, list whatever the options specify. */ @@ -1631,6 +1655,58 @@ return 0; } + if (on & PM_TIED) { + Param apm; + char *name1; + + if (ops['m']) { + zwarnnam(name, "incompatible options for -T", NULL, 0); + return 1; + } + on &= ~off; + if (!argv[1] || argv[2]) { + zwarnnam(name, "-T requires names of scalar and array", NULL, 0); + return 1; + } + + /* + * Create the tied array; this is normal except that + * it has the PM_TIED flag set. Do it first because + * we need the address. + */ + if (!(asg = getasg(argv[1]))) + return 1; + name1 = ztrdup(asg->name); + if (!(apm=typeset_single(name, asg->name, + (Param)paramtab->getnode(paramtab, + asg->name), + func, on | PM_ARRAY, off, roff, + asg->value, NULL))) + return 1; + + /* + * Create the tied colonarray. We make it as a normal scalar + * and fix up the oddities later. + */ + if (!(asg = getasg(argv[0])) || + !(pm=typeset_single(name, asg->name, + (Param)paramtab->getnode(paramtab, + asg->name), + func, on, off, roff, asg->value, apm))) { + unsetparam_pm(apm, 1, 1); + return 1; + } + + pm->ename = name1; + apm->ename = ztrdup(asg->name); + + return 0; + } + if (off & PM_TIED) { + zerrnam(name, "use unset to remove tied variables", NULL, 0); + return 1; + } + /* With the -m option, treat arguments as glob patterns */ if (ops['m']) { MUSTUSEHEAP("typeset -m"); @@ -1664,8 +1740,8 @@ } for (pmnode = firstnode(pmlist); pmnode; incnode(pmnode)) { pm = (Param) getdata(pmnode); - if (typeset_single(name, pm->nam, pm, func, on, off, roff, - asg->value)) + if (!typeset_single(name, pm->nam, pm, func, on, off, roff, + asg->value, NULL)) returnval = 1; } } @@ -1680,9 +1756,9 @@ returnval = 1; continue; } - if (typeset_single(name, asg->name, - (Param)paramtab->getnode(paramtab, asg->name), - func, on, off, roff, asg->value)) + if (!typeset_single(name, asg->name, + (Param)paramtab->getnode(paramtab, asg->name), + func, on, off, roff, asg->value, NULL)) returnval = 1; } return returnval; --- Src/params.c.tied Mon Jan 25 13:28:56 1999 +++ Src/params.c Thu Jan 28 18:21:13 1999 @@ -679,7 +679,7 @@ Comp c; /* first parse any subscription flags */ - if (v->pm && *s == '(' || *s == Inpar) { + if (v->pm && (*s == '(' || *s == Inpar)) { int escapes = 0; int waste; for (s++; *s != ')' && *s != Outpar && s != *str; s++) { @@ -1759,6 +1759,9 @@ if (pm->flags & PM_UNIQUE) uniqarray(x); pm->u.arr = x; + /* Arrays tied to colon-arrays may need to fix the environment */ + if (pm->ename && x) + arrfixenv(pm->ename, x); } /* Function to get value of an association parameter */ @@ -1950,7 +1953,8 @@ char * colonarrgetfn(Param pm) { - return zjoin(*(char ***)pm->u.data, ':'); + char ***dptr = (char ***)pm->u.data; + return *dptr ? zjoin(*dptr, ':') : ""; } /**/ @@ -1959,8 +1963,15 @@ { char ***dptr = (char ***)pm->u.data; - freearray(*dptr); - *dptr = x ? colonsplit(x, pm->flags & PM_UNIQUE) : mkarray(NULL); + /* + * If this is tied to a parameter (rather than internal) array, + * the array itself may be NULL. Otherwise, we have to make + * sure it doesn't ever get null. + */ + if (*dptr) + freearray(*dptr); + *dptr = x ? colonsplit(x, pm->flags & PM_UNIQUE) : + (pm->flags & PM_TIED) ? NULL : mkarray(NULL); if (pm->ename) arrfixenv(pm->nam, *dptr); zsfree(x); @@ -2399,7 +2410,7 @@ MUSTUSEHEAP("arrfixenv"); if (t == path) cmdnamtab->emptytable(cmdnamtab); - u = zjoin(t, ':'); + u = t ? zjoin(t, ':') : ""; len_s = strlen(s); pm = (Param) paramtab->getnode(paramtab, s); for (ep = environ; *ep; ep++) @@ -2602,6 +2613,9 @@ if (delunset) pm->unsetfn(pm, 1); zsfree(pm->nam); + /* If this variable was tied by the user, ename was ztrdup'd */ + if (pm->flags & PM_TIED) + zsfree(pm->ename); zfree(pm, sizeof(struct param)); } --- Src/zsh.h.tied Thu Jan 28 14:59:50 1999 +++ Src/zsh.h Thu Jan 28 17:58:23 1999 @@ -916,10 +917,11 @@ #define PM_TAGGED (1<<9) /* tagged */ #define PM_EXPORTED (1<<10) /* exported */ #define PM_UNIQUE (1<<11) /* remove duplicates */ -#define PM_SPECIAL (1<<12) /* special builtin parameter */ -#define PM_DONTIMPORT (1<<13) /* do not import this variable */ -#define PM_RESTRICTED (1<<14) /* cannot be changed in restricted mode */ -#define PM_UNSET (1<<15) /* has null value */ +#define PM_TIED (1<<12) /* array tied to colon-path or v.v. */ +#define PM_SPECIAL (1<<13) /* special builtin parameter */ +#define PM_DONTIMPORT (1<<14) /* do not import this variable */ +#define PM_RESTRICTED (1<<15) /* cannot be changed in restricted mode */ +#define PM_UNSET (1<<16) /* has null value */ /* Flags for extracting elements of arrays and associative arrays */ #define SCANPM_WANTVALS (1<<0) -- Peter Stephenson Tel: +39 050 844536 WWW: http://www.ifh.de/~pws/ Dipartimento di Fisica, Via Buonarroti 2, 56127 Pisa, Italy