about summary refs log tree commit diff
diff options
context:
space:
mode:
authorPeter Stephenson <pws@zsh.org>2017-10-13 18:17:09 +0100
committerPeter Stephenson <pws@zsh.org>2017-10-13 18:17:09 +0100
commitb3fa5c528c79b27986a77c92a48b7f70e7f9e7d3 (patch)
treea7aba1e9bf6b5549111a388a9835db091faf9122
parent57cfa8b160d16a37fcd6a5da7c8bcd492c76021e (diff)
downloadzsh-b3fa5c528c79b27986a77c92a48b7f70e7f9e7d3.tar.gz
zsh-b3fa5c528c79b27986a77c92a48b7f70e7f9e7d3.tar.xz
zsh-b3fa5c528c79b27986a77c92a48b7f70e7f9e7d3.zip
41877: Separate out SH_FILE_EXPANSION loop from parameter substitution.
Parameter substitution can add nodes that need to be rescanned by
it, but not by file expansion, so the two don't play well together.
-rw-r--r--ChangeLog8
-rw-r--r--Src/subst.c39
-rw-r--r--Test/E01options.ztst10
3 files changed, 41 insertions, 16 deletions
diff --git a/ChangeLog b/ChangeLog
index 06f3ba89c..d89e92f95 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+2017-10-13  Peter Stephenson  <p.stephenson@samsung.com>
+
+	* 41877: Src/subst·c, Test/E01options.ztst: Separate out
+	SH_FILE_EXPANSION loop from parameter substitution as the latter
+	can add nodes: SH_FILE_EXPANSION should see following nodes
+	only, but on the next loop parameter substitution needs to see
+	added nodes for further expansion.
+
 2017-10-11  Daniel Shahaf  <d.s@xxxxxxxxxxxxxxxxxx>
 
 	* 41825/0002: Completion/Zsh/Command/_stat: Complete -x options
diff --git a/Src/subst.c b/Src/subst.c
index 8c290cccf..d027e3d83 100644
--- a/Src/subst.c
+++ b/Src/subst.c
@@ -108,7 +108,6 @@ prefork(LinkList list, int flags, int *ret_flags)
     queue_signals();
     node = firstnode(list);
     while (node) {
-	LinkNode nextnode = 0;
 	if ((flags & (PREFORK_SINGLE|PREFORK_ASSIGN)) == PREFORK_ASSIGN &&
 	    (insnode = keyvalpairelement(list, node))) {
 	    node = insnode;
@@ -137,23 +136,31 @@ prefork(LinkList list, int flags, int *ret_flags)
 	     * testing if cptr changed...
 	     */
 	    setdata(node, cptr);
-	    /*
-	     * Advance now because we must not expand filenames again
-	     * after string substitution (which may insert new nodes).
-	     */
-	    nextnode = node;
-	    incnode(nextnode);
-	}
-	if (!(node = stringsubst(list, node,
-				 flags & ~(PREFORK_TYPESET|PREFORK_ASSIGN),
-				 ret_flags, asssub))) {
-	    unqueue_signals();
-	    return;
 	}
-	if (isset(SHFILEEXPANSION))
-	    node = nextnode;
 	else
-	    incnode(node);
+	{
+	    if (!(node = stringsubst(list, node,
+				     flags & ~(PREFORK_TYPESET|PREFORK_ASSIGN),
+				     ret_flags, asssub))) {
+		unqueue_signals();
+		return;
+	    }
+	}
+	incnode(node);
+    }
+    if (isset(SHFILEEXPANSION)) {
+	/*
+	 * stringsubst() may insert new nodes, so doesn't work
+	 * well in the same loop as file expansion.
+	 */
+	for (node = firstnode(list); node; incnode(node)) {
+	    if (!(node = stringsubst(list, node,
+				     flags & ~(PREFORK_TYPESET|PREFORK_ASSIGN),
+				     ret_flags, asssub))) {
+		unqueue_signals();
+		return;
+	    }
+	}
     }
     for (node = firstnode(list); node; incnode(node)) {
 	if (node == stop)
diff --git a/Test/E01options.ztst b/Test/E01options.ztst
index 6929f5140..0f6bb3455 100644
--- a/Test/E01options.ztst
+++ b/Test/E01options.ztst
@@ -1038,6 +1038,16 @@ F:Regression test for workers/41811
 >~/one
 >~/two
 
+  (
+    setopt shfileexpansion
+    set -- also appearing
+    print -l $*$*
+  )
+0:SH_FILE_EXPANSION interaction with inserting nodes from parameters
+>also
+>appearingalso
+>appearing
+
   testpat() {
     if [[ $1 = ${~2} ]]; then print $1 $2 yes; else print $1 $2 no; fi
   }