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

PATCH: incorrect tied param splitting/joining when imeta(separator) is true



Since no one seemed to be interested in the NUL-separator bugs I've taken
a look at the code myself and I've managed to locate the bugs. 

The function tiedarrsetfn() does not convert characters for which imeta()
is true into separator strings properly. This means that the bug is not
limited to NUL-characters but affects all characters for which imeta() is
true (e.g. 0x83). 

There are also 2 bugs in zjoin():
1. zjoin() doesn't put the NUL-terminator in the right place when delim is
a meta-character.

2. zjoin() refuses to add 0-delimiters (although it does count them when
computing the length). This behaviour does not seem to be used anywhere in
zsh code AFAICS and even if it were, that would be a bug in the respective
call.


The attached patch fixes both problems and adds 2 regression tests to
B02typeset.ztst (both tests are necessary, since 0 and 0x83 are treated
differently in some places, so that one case could regress independent of
the other).

MSB
diff -r --unified=23 zsh-4.2.1/Src/params.c zsh-4.2.1-split-join-with-meta-sep-fix/Src/params.c
--- zsh-4.2.1/Src/params.c	Fri Aug 13 12:22:45 2004
+++ zsh-4.2.1-split-join-with-meta-sep-fix/Src/params.c	Thu Sep 16 19:34:59 2004
@@ -2623,47 +2623,47 @@
 }
 
 /**/
 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[1] = dptr->joinchar ^ 32;
 	    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, UNUSED(int exp))
 {
     /*
      * Special unset function because we allocated a struct tieddata
diff -r --unified=23 zsh-4.2.1/Src/utils.c zsh-4.2.1-split-join-with-meta-sep-fix/Src/utils.c
--- zsh-4.2.1/Src/utils.c	Fri Aug 13 12:22:46 2004
+++ zsh-4.2.1-split-join-with-meta-sep-fix/Src/utils.c	Thu Sep 16 21:25:56 2004
@@ -1853,56 +1853,54 @@
 	} else {
 	    if (ztrftimebuf(&bufsize, 1))
 		return 0;
 	    *buf++ = *fmt++;
 	}
     *buf = '\0';
     return buf - origbuf;
 }
 
 /**/
 mod_export char *
 zjoin(char **arr, int delim, int heap)
 {
     int len = 0;
     char **s, *ret, *ptr;
 
     for (s = arr; *s; s++)
 	len += strlen(*s) + 1 + (imeta(delim) ? 1 : 0);
     if (!len)
 	return heap? "" : ztrdup("");
     ptr = ret = (heap ? (char *) hcalloc(len) : (char *) zshcalloc(len));
     for (s = arr; *s; s++) {
 	strucpy(&ptr, *s);
-	if (delim) {
 	    if (imeta(delim)) {
 		*ptr++ = Meta;
 		*ptr++ = delim ^ 32;
 	    }
 	    else
 		*ptr++ = delim;
-	}
     }
-    ptr[-1] = '\0';
+    ptr[-1 - (imeta(delim) ? 1 : 0)] = '\0';
     return ret;
 }
 
 /* Split a string containing a colon separated list *
  * of items into an array of strings.               */
 
 /**/
 char **
 colonsplit(char *s, int uniq)
 {
     int ct;
     char *t, **ret, **ptr, **p;
 
     for (t = s, ct = 0; *t; t++) /* count number of colons */
 	if (*t == ':')
 	    ct++;
     ptr = ret = (char **) zalloc(sizeof(char **) * (ct + 2));
 
     t = s;
     do {
 	s = t;
         /* move t to point at next colon */
 	for (; *t && *t != ':'; t++);
diff -r --unified=23 zsh-4.2.1/Test/B02typeset.ztst zsh-4.2.1-split-join-with-meta-sep-fix/Test/B02typeset.ztst
--- zsh-4.2.1/Test/B02typeset.ztst	Fri Aug 13 12:22:54 2004
+++ zsh-4.2.1-split-join-with-meta-sep-fix/Test/B02typeset.ztst	Thu Sep 16 21:58:41 2004
@@ -163,46 +163,61 @@
 ?(eval):3: read-only variable: r
 
  typeset r=success
  readonly r
  print $r
  r=failure
 1:Convert to readonly
 >success
 ?(eval):4: read-only variable: r
 
  typeset -gU array
  print $array
 0:Uniquified arrays and non-local scope
 >a r y
 
  typeset -T SCALAR=l:o:c:a:l array
  print $array
  typeset -U SCALAR
  print $SCALAR $array
 0:Tied parameters and uniquified colon-arrays
 >l o c a l
 >l:o:c:a l o c a
 
+ typeset -T SCALAR=$'l\x83o\x83c\x83a\x83l' array $'\x83'
+ print $array
+ typeset -U SCALAR
+ print $SCALAR $array
+0:Tied parameters and uniquified arrays with meta-character as separator
+>l o c a l
+>l?o?c?a l o c a
+
+ typeset -T SCALAR=$'l\000o\000c\000a\000l' array $'\000'
+ typeset -U SCALAR
+ print $array
+ [[ $SCALAR == $'l\000o\000c\000a' ]]
+0:Tied parameters and uniquified arrays with NUL-character as separator
+>l o c a
+
  typeset -T SCALAR array
  typeset +T SCALAR
 1:Untying is prohibited
 ?(eval):typeset:2: use unset to remove tied variables
 
  OUTER=outer
  scope13
  print $OUTER
 0:Export of tied parameters
 >i:n:n:e:r
 >outer
 
  typeset -TU MORESTUFF=here-we-go-go-again morestuff '-'
  print -l $morestuff
 0:Tied arrays with separator specified
 >here
 >we
 >go
 >again
 
  typeset -T THIS will not work
 1:Tied array syntax
 ?(eval):typeset:1: -T requires names of scalar and array


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