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

Re: brace expansion inconsistency



On Jan 2,  4:08pm, Oliver Kiddle wrote:
}
} Matt Armstrong wrote:
} > Is there a simple way to turn an array (a b c) into (a "" b "" c "")?
} 
} I would have thought that _p4_cmds=( {$a,} ) would do the job but
} it doesn't. On closer inspection, it seems that {,$a} does expand
} in the way I would expect with alternate array elements and empty
} strings.

With RC_EXPAND_PARAM set, of course.  Otherwise you get {,a b c} (three
words) and the braces don't do anything.

} In bash {x,} expands to just 'x'. ksh 93 expands it to two
} words - 'x' and an empty word. zsh is different for
} {x,} and {,x}. I'd argue that ksh93 is right.

Interesting (zsh's behavior, I mean): {x,}y produces xy and y, but {x,}''
produces just x.  The problem appears to be in prefork():

    for (node = firstnode(list); node; incnode(node)) {
	if (*(char *)getdata(node)) {
	    remnulargs(getdata(node));
	    if (unset(IGNOREBRACES) && !(flags & PF_SINGLE))
		while (hasbraces(getdata(node)))
		    xpandbraces(list, &node);

For {,x}, we enter this block with getdata(node) == "{,x}" and expand
the braces, which replaces node with the first word of the expanded
list, which is the empty string; the loop incnode(node) then moves to
the next node of the expansion, which is "x", leaving the empty element
in place.

For {x,} the expansion happens the same way, except now incnode(node)
takes us to the empty string node and we go through this branch instead:

	} else if (!(flags & PF_SINGLE))
	    uremnode(list, node);

Thus, empty nodes after the first are lost whenever there is a brace
expansion, unless something non-empty precedes or follows the braces:

    zsh% print -l {x,,y}
    x
    y

} Any thoughts?

This is clearly a bug, because xpandbraces() inserts the empty nodes as
it should, and prefork() is inconsistent about stripping them out again.
The following patch fixes it; there may be a simpler way.

Index: Src/subst.c
===================================================================
--- Src/subst.c	2001/10/17 14:38:29	1.8
+++ Src/subst.c	2002/01/06 00:14:33
@@ -49,8 +49,8 @@
 mod_export void
 prefork(LinkList list, int flags)
 {
-    LinkNode node;
-    int asssub = (flags & PF_TYPESET) && isset(KSHTYPESET);
+    LinkNode node, stop = 0;
+    int keep = 0, asssub = (flags & PF_TYPESET) && isset(KSHTYPESET);
 
     queue_signals();
     for (node = firstnode(list); node; incnode(node)) {
@@ -78,15 +78,21 @@
 	}
     }
     for (node = firstnode(list); node; incnode(node)) {
+	if (node == stop)
+	    keep = 0;
 	if (*(char *)getdata(node)) {
 	    remnulargs(getdata(node));
-	    if (unset(IGNOREBRACES) && !(flags & PF_SINGLE))
-		while (hasbraces(getdata(node)))
+	    if (unset(IGNOREBRACES) && !(flags & PF_SINGLE)) {
+		stop = nextnode(node);
+		while (hasbraces(getdata(node))) {
+		    keep = 1;
 		    xpandbraces(list, &node);
+		}
+	    }
 	    if (unset(SHFILEEXPANSION))
 		filesub((char **)getaddrdata(node),
 			flags & (PF_TYPESET|PF_ASSIGN));
-	} else if (!(flags & PF_SINGLE))
+	} else if (!(flags & PF_SINGLE) && !keep)
 	    uremnode(list, node);
 	if (errflag) {
 	    unqueue_signals();

-- 
Bart Schaefer                                 Brass Lantern Enterprises
http://www.well.com/user/barts              http://www.brasslantern.com

Zsh: http://www.zsh.org | PHPerl Project: http://phperl.sourceforge.net   



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