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

PATCH: zsh-3.1.5-pws-5 + recent: typeset -T MYPATH mypath (finally!)



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 <pws@xxxxxxxxxxxxxxxxx>       Tel: +39 050 844536
WWW:  http://www.ifh.de/~pws/
Dipartimento di Fisica, Via Buonarroti 2, 56127 Pisa, Italy



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