about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog4
-rw-r--r--Doc/Zsh/builtins.yo34
-rw-r--r--Src/builtin.c41
-rw-r--r--Src/params.c79
-rw-r--r--Src/utils.c22
-rw-r--r--Src/zsh.h26
6 files changed, 160 insertions, 46 deletions
diff --git a/ChangeLog b/ChangeLog
index 25c4157b6..e24c905b9 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,9 @@
 2003-09-24  Peter Stephenson  <pws@csr.com>
 
+	* 19129: Doc/Zsh/builtins.yo, Src/builtin.c, Src/params.c,
+	Src/utils.c, Src/zsh.h: extra tie arguemnt in
+	"typeset -T PAGER pager ' '" used for joining and splitting.
+
 	* unposted: Completion/Unix/Command/_perforce: improve handling
 	of label completion: now faster and uses filename to narrow
 	range if after `@'.
diff --git a/Doc/Zsh/builtins.yo b/Doc/Zsh/builtins.yo
index b5217abaf..3f6f3c450 100644
--- a/Doc/Zsh/builtins.yo
+++ b/Doc/Zsh/builtins.yo
@@ -1160,7 +1160,7 @@ cindex(parameters, declaring)
 xitem(tt(typeset) [ {tt(PLUS())|tt(-)}tt(AEFHLRUZafghilprtuxm) [var(n)]] [ \
 var(name)[tt(=)var(value)] ... ])
 item(tt(typeset) -T [ {tt(PLUS()|tt(-))}tt(LRUZrux) ] \
-  var(SCALAR)[tt(=)var(value)] var(array))(
+  var(SCALAR)[tt(=)var(value)] var(array) tt([) var(sep) tt(]))(
 Set or display attributes and values for shell parameters.
 
 A parameter is created for each var(name) that does not already refer
@@ -1189,20 +1189,24 @@ separately for arrays and associative arrays), regardless of other flags
 and options.  Note that the tt(-h) flag on parameters is respected; no
 value will be shown for these 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, or converting the
-type of one of them with another tt(typeset) command; tt(+T) does not
-work, assigning an array to var(SCALAR) is an error, and assigning a
-scalar to var(array) sets it to be a single-element array.  Note that
-both `tt(typeset -xT ...)' and `tt(export -T ...)' work, but only the
-scalar will be marked for export.
+If the tt(-T) option is given, two or three arguments must be present (an
+exception is that zero arguments are allowed to show the list of parameters
+created in this fashion).  The first two are the name of a scalar and an
+array parameter (in that order) that will be tied together in the manner of
+tt($PATH) and tt($path).  The optional third argument is a single-character
+separator which will be used to join the elements of the array to form the
+scalar; if absent, a colon is used, as with tt($PATH).  Only the first
+character of the separator is significant; any remaining characters are
+ignored.  Only the scalar parameter may be assigned 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, or converting the type of one
+of them with another tt(typeset) command; tt(+T) does not work, assigning
+an array to var(SCALAR) is an error, and assigning a scalar to var(array)
+sets it to be a single-element array.  Note that both `tt(typeset -xT ...)'
+and `tt(export -T ...)' work, but only the scalar will be marked for
+export.  Setting the value using the scalar version causes a split on all
+separators (which cannot be quoted).
 
 The tt(-g) (global) flag is treated specially: it means that any
 resulting parameter will not be restricted to local scope.  Note that this
diff --git a/Src/builtin.c b/Src/builtin.c
index 62426facb..988a342fd 100644
--- a/Src/builtin.c
+++ b/Src/builtin.c
@@ -1677,7 +1677,7 @@ enum {
 static Param
 typeset_single(char *cname, char *pname, Param pm, int func,
 	       int on, int off, int roff, char *value, Param altpm,
-	       Options ops, int auxlen)
+	       Options ops, int auxlen, int joinchar)
 {
     int usepm, tc, keeplocal = 0, newspecial = NS_NONE, readonly;
     char *subscript;
@@ -1997,9 +1997,17 @@ typeset_single(char *cname, char *pname, Param pm, int func,
 	 * 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;
+	struct tieddata *tdp = (struct tieddata *)
+	    zalloc(sizeof(struct tieddata));
+	if (!tdp)
+	    return NULL;
+	tdp->joinchar = joinchar;
+	tdp->arrptr = &altpm->u.arr;
+
+	pm->sets.cfn = tiedarrsetfn;
+	pm->gets.cfn = tiedarrgetfn;
+	pm->unsetfn = tiedarrunsetfn;
+	pm->u.data = tdp;
     }
 
     if (keeplocal)
@@ -2155,6 +2163,7 @@ bin_typeset(char *name, char **argv, Options ops, int func)
 	Param apm;
 	struct asgment asg0;
 	char *oldval = NULL;
+	int joinchar;
 
 	if (OPT_ISSET(ops,'m')) {
 	    zwarnnam(name, "incompatible options for -T", NULL, 0);
@@ -2162,12 +2171,25 @@ bin_typeset(char *name, char **argv, Options ops, int func)
 	    return 1;
 	}
 	on &= ~off;
-	if (!argv[1] || argv[2]) {
+	if (!argv[1] || argv[3]) {
 	    zwarnnam(name, "-T requires names of scalar and array", NULL, 0);
 	    unqueue_signals();
 	    return 1;
 	}
 
+	/*
+	 * Third argument, if given, is character used to join
+	 * the elements of the array in the scalar.
+	 */
+	if (!argv[2])
+	    joinchar = ':';
+	else if (!*argv[2])
+	    joinchar = 0;
+	else if (*argv[2] == Meta)
+	    joinchar = argv[2][1] ^ 32;
+	else
+	    joinchar = *argv[2];
+
 	if (!(asg = getasg(argv[0]))) {
 	    unqueue_signals();
 	    return 1;
@@ -2212,7 +2234,8 @@ bin_typeset(char *name, char **argv, Options ops, int func)
 				 (Param)paramtab->getnode(paramtab,
 							  asg->name),
 				 func, (on | PM_ARRAY) & ~PM_EXPORTED,
-				 off, roff, asg->value, NULL, ops, auxlen))) {
+				 off, roff, asg->value, NULL, ops, auxlen,
+				 0))) {
 	    unqueue_signals();
 	    return 1;
 	}
@@ -2224,7 +2247,7 @@ bin_typeset(char *name, char **argv, Options ops, int func)
 				(Param)paramtab->getnode(paramtab,
 							 asg0.name),
 				func, on, off, roff, asg0.value, apm,
-				ops, auxlen))) {
+				ops, auxlen, joinchar))) {
 	    if (oldval)
 		zsfree(oldval);
 	    unsetparam_pm(apm, 1, 1);
@@ -2291,7 +2314,7 @@ bin_typeset(char *name, char **argv, Options ops, int func)
 	    for (pmnode = firstnode(pmlist); pmnode; incnode(pmnode)) {
 		pm = (Param) getdata(pmnode);
 		if (!typeset_single(name, pm->nam, pm, func, on, off, roff,
-				    asg->value, NULL, ops, auxlen))
+				    asg->value, NULL, ops, auxlen, 0))
 		    returnval = 1;
 	    }
 	}
@@ -2306,7 +2329,7 @@ bin_typeset(char *name, char **argv, Options ops, int func)
 				     gethashnode2(paramtab, asg->name) :
 				     paramtab->getnode(paramtab, asg->name)),
 			    func, on, off, roff, asg->value, NULL,
-			    ops, auxlen))
+			    ops, auxlen, 0))
 	    returnval = 1;
     }
     unqueue_signals();
diff --git a/Src/params.c b/Src/params.c
index a4890bcb0..079378180 100644
--- a/Src/params.c
+++ b/Src/params.c
@@ -2595,22 +2595,77 @@ void
 colonarrsetfn(Param pm, char *x)
 {
     char ***dptr = (char ***)pm->u.data;
-
     /*
-     * 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.
+     * We have to make sure this is never NULL, since that
+     * can cause problems.
      */
     if (*dptr)
 	freearray(*dptr);
-    *dptr = x ? colonsplit(x, pm->flags & PM_UNIQUE) :
-	(pm->flags & PM_TIED) ? NULL : mkarray(NULL);
+    if (x)
+	*dptr = colonsplit(x, pm->flags & PM_UNIQUE);
+    else
+	*dptr = mkarray(NULL);
     if (pm->ename)
 	arrfixenv(pm->nam, *dptr);
     zsfree(x);
 }
 
 /**/
+char *
+tiedarrgetfn(Param pm)
+{
+    struct tieddata *dptr = (struct tieddata *)pm->u.data;
+    return *dptr->arrptr ? zjoin(*dptr->arrptr, dptr->joinchar, 1) : "";
+}
+
+/**/
+void
+tiedarrsetfn(Param pm, char *x)
+{
+    struct tieddata *dptr = (struct tieddata *)pm->u.data;
+
+    if (*dptr->arrptr)
+	freearray(*dptr->arrptr);
+    if (x) {
+	char sepbuf[3];
+	if (imeta(dptr->joinchar))
+	{
+	    sepbuf[0] = Meta;
+	    sepbuf[1] = dptr->joinchar;
+	    sepbuf[2] = '\0';
+	}
+	else
+	{
+	    sepbuf[0] = dptr->joinchar;
+	    sepbuf[1] = '\0';
+	}
+	*dptr->arrptr = sepsplit(x, sepbuf, 0, 0);
+	if (pm->flags & PM_UNIQUE)
+	    uniqarray(*dptr->arrptr);
+    } else
+	*dptr->arrptr = NULL;
+    if (pm->ename)
+	arrfixenv(pm->nam, *dptr->arrptr);
+    zsfree(x);
+}
+
+/**/
+void
+tiedarrunsetfn(Param pm, int exp)
+{
+    /*
+     * Special unset function because we allocated a struct tieddata
+     * in typeset_single to hold the special data which we now
+     * need to delete.
+     */
+    pm->sets.cfn(pm, NULL);
+    zfree(pm->u.data, sizeof(struct tieddata));
+    /* paranoia -- shouldn't need these, but in case we reuse the struct... */
+    pm->u.data = NULL;
+    pm->flags &= ~PM_TIED;
+}
+
+/**/
 void
 uniqarray(char **x)
 {
@@ -3187,6 +3242,7 @@ void
 arrfixenv(char *s, char **t)
 {
     Param pm;
+    int joinchar;
 
     if (t == path)
 	cmdnamtab->emptytable(cmdnamtab);
@@ -3208,8 +3264,15 @@ arrfixenv(char *s, char **t)
      * Do not "fix" parameters that were not exported
      */
 
-    if (pm->flags & PM_EXPORTED)
-	pm->env = addenv(s, t ? zjoin(t, ':', 1) : "", pm->flags);
+    if (!(pm->flags & PM_EXPORTED))
+	return;
+
+    if (pm->flags & PM_TIED)
+	joinchar = ((struct tieddata *)pm->u.data)->joinchar;
+    else
+	joinchar = ':';
+
+    pm->env = addenv(s, t ? zjoin(t, joinchar, 1) : "", pm->flags);
 }
 
 
diff --git a/Src/utils.c b/Src/utils.c
index 0d9f9f9c3..56230fddb 100644
--- a/Src/utils.c
+++ b/Src/utils.c
@@ -1793,14 +1793,20 @@ zjoin(char **arr, int delim, int heap)
     char **s, *ret, *ptr;
 
     for (s = arr; *s; s++)
-	len += strlen(*s) + 1;
+	len += strlen(*s) + 1 + (imeta(delim) ? 1 : 0);
     if (!len)
 	return heap? "" : ztrdup("");
     ptr = ret = (heap ? (char *) hcalloc(len) : (char *) zcalloc(len));
     for (s = arr; *s; s++) {
 	strucpy(&ptr, *s);
-	if (delim)
-	    *ptr++ = delim;
+	if (delim) {
+	    if (imeta(delim)) {
+		*ptr++ = Meta;
+		*ptr++ = delim ^ 32;
+	    }
+	    else
+		*ptr++ = delim;
+	}
     }
     ptr[-1] = '\0';
     return ret;
@@ -1856,7 +1862,15 @@ skipwsep(char **s)
     return i;
 }
 
-/* see findsep() below for handling of `quote' argument */
+/*
+ * haven't worked out what allownull does; it's passed down from
+ *   sepsplit but all the cases it's used are either 0 or 1 without
+ *   a comment.  it seems to be something to do with the `nulstring'
+ *   which i think is some kind of a metafication thing, so probably
+ *   allownull's value is associated with whether we are using
+ *   metafied strings.
+ * see findsep() below for handling of `quote' argument
+ */
 
 /**/
 mod_export char **
diff --git a/Src/zsh.h b/Src/zsh.h
index 2dca01722..158717dea 100644
--- a/Src/zsh.h
+++ b/Src/zsh.h
@@ -1156,6 +1156,12 @@ struct param {
     int level;			/* if (old != NULL), level of localness  */
 };
 
+/* structure stored in struct param's u.data by tied arrays */
+struct tieddata {
+    char ***arrptr;		/* pointer to corresponding array */
+    int joinchar;		/* character used to join arrays */
+};
+
 /* flags for parameters */
 
 /* parameter types */
@@ -1193,16 +1199,16 @@ struct param {
 #define PM_TIED 	(1<<16)	/* 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_NAMEDDIR     (1<<26) /* has a corresponding nameddirtab entry    */
+#define PM_LOCAL	(1<<21) /* this parameter will be made local        */
+#define PM_SPECIAL	(1<<22) /* special builtin parameter                */
+#define PM_DONTIMPORT	(1<<23)	/* do not import this variable              */
+#define PM_RESTRICTED	(1<<24) /* cannot be changed in restricted mode     */
+#define PM_UNSET	(1<<25)	/* has null value                           */
+#define PM_REMOVABLE	(1<<26)	/* special can be removed from paramtab     */
+#define PM_AUTOLOAD	(1<<27) /* autoloaded from module                   */
+#define PM_NORESTORE	(1<<28)	/* do not restore value of local special    */
+#define PM_HASHELEM     (1<<29) /* is a hash-element */
+#define PM_NAMEDDIR     (1<<30) /* has a corresponding nameddirtab entry    */
 
 /* The option string corresponds to the first of the variables above */
 #define TYPESET_OPTSTR "aiEFALRZlurtxUhHT"