f686d7
From 6b8f3f9906ee44be46e022480b6e01755feeaa99 Mon Sep 17 00:00:00 2001
f686d7
From: Peter Stephenson <pws@zsh.org>
f686d7
Date: Tue, 6 Jan 2015 17:05:17 +0000
f686d7
Subject: [PATCH 1/9] Fix command substitutions to parse contents as they are
f686d7
 read in.
f686d7
f686d7
Do this by refactoring misnamed lexsave()/lexrestore() to allow
f686d7
continuity of history and input.
f686d7
f686d7
Add test.
f686d7
f686d7
Upstream-commit: c0d01a6fe0c67911650730cf13a2b9a0db16e59b
f686d7
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
f686d7
---
f686d7
 Src/init.c            |   3 +-
f686d7
 Src/input.c           |  13 +-
f686d7
 Src/lex.c             | 498 ++++++++++++++++++++++++++++++++------------------
f686d7
 Src/parse.c           |  29 ++-
f686d7
 Src/zsh.h             |   9 +
f686d7
 Test/D08cmdsubst.ztst |  42 +++++
f686d7
 6 files changed, 401 insertions(+), 193 deletions(-)
f686d7
f686d7
diff --git a/Src/init.c b/Src/init.c
f686d7
index 0742a9f..78f171d 100644
f686d7
--- a/Src/init.c
f686d7
+++ b/Src/init.c
f686d7
@@ -129,7 +129,8 @@ loop(int toplevel, int justonce)
f686d7
 	use_exit_printed = 0;
f686d7
 	intr();			/* interrupts on            */
f686d7
 	lexinit();              /* initialize lexical state */
f686d7
-	if (!(prog = parse_event())) {	/* if we couldn't parse a list */
f686d7
+	if (!(prog = parse_event(ENDINPUT))) {
f686d7
+	    /* if we couldn't parse a list */
f686d7
 	    hend(NULL);
f686d7
 	    if ((tok == ENDINPUT && !errflag) ||
f686d7
 		(tok == LEXERR && (!isset(SHINSTDIN) || !toplevel)) ||
f686d7
diff --git a/Src/input.c b/Src/input.c
f686d7
index 5cff22d..1579762 100644
f686d7
--- a/Src/input.c
f686d7
+++ b/Src/input.c
f686d7
@@ -175,12 +175,12 @@ shingetline(void)
f686d7
 /* Get the next character from the input.
f686d7
  * Will call inputline() to get a new line where necessary.
f686d7
  */
f686d7
-  
f686d7
+
f686d7
 /**/
f686d7
 int
f686d7
 ingetc(void)
f686d7
 {
f686d7
-    int lastc;
f686d7
+    int lastc = ' ';
f686d7
 
f686d7
     if (lexstop)
f686d7
 	return ' ';
f686d7
@@ -192,7 +192,7 @@ ingetc(void)
f686d7
 		continue;
f686d7
 	    if (((inbufflags & INP_LINENO) || !strin) && lastc == '\n')
f686d7
 		lineno++;
f686d7
-	    return lastc;
f686d7
+	    break;
f686d7
 	}
f686d7
 
f686d7
 	/*
f686d7
@@ -204,7 +204,7 @@ ingetc(void)
f686d7
 	 */
f686d7
 	if (!inbufct && (strin || errflag)) {
f686d7
 	    lexstop = 1;
f686d7
-	    return ' ';
f686d7
+	    break;
f686d7
 	}
f686d7
 	/* If the next element down the input stack is a continuation of
f686d7
 	 * this, use it.
f686d7
@@ -215,8 +215,10 @@ ingetc(void)
f686d7
 	}
f686d7
 	/* As a last resort, get some more input */
f686d7
 	if (inputline())
f686d7
-	    return ' ';
f686d7
+	    break;
f686d7
     }
f686d7
+    zshlex_raw_add(lastc);
f686d7
+    return lastc;
f686d7
 }
f686d7
 
f686d7
 /* Read a line from the current command stream and store it as input */
f686d7
@@ -421,6 +423,7 @@ inungetc(int c)
f686d7
 	    inbufleft = 0;
f686d7
 	    inbuf = inbufptr = "";
f686d7
 	}
f686d7
+	zshlex_raw_back();
f686d7
     }
f686d7
 }
f686d7
 
f686d7
diff --git a/Src/lex.c b/Src/lex.c
f686d7
index 82bf848..bcceda6 100644
f686d7
--- a/Src/lex.c
f686d7
+++ b/Src/lex.c
f686d7
@@ -146,6 +146,16 @@ mod_export int parend;
f686d7
 /**/
f686d7
 mod_export int nocomments;
f686d7
 
f686d7
+/* add raw input characters while parsing command substitution */
f686d7
+
f686d7
+/**/
f686d7
+static int lex_add_raw;
f686d7
+
f686d7
+/* variables associated with the above */
f686d7
+
f686d7
+static char *tokstr_raw, *bptr_raw;
f686d7
+static int len_raw, bsiz_raw;
f686d7
+
f686d7
 /* text of punctuation tokens */
f686d7
 
f686d7
 /**/
f686d7
@@ -214,6 +224,11 @@ struct lexstack {
f686d7
     char *bptr;
f686d7
     int bsiz;
f686d7
     int len;
f686d7
+    int lex_add_raw;
f686d7
+    char *tokstr_raw;
f686d7
+    char *bptr_raw;
f686d7
+    int bsiz_raw;
f686d7
+    int len_raw;
f686d7
     short *chwords;
f686d7
     int chwordlen;
f686d7
     int chwordpos;
f686d7
@@ -239,89 +254,121 @@ struct lexstack {
f686d7
 
f686d7
 static struct lexstack *lstack = NULL;
f686d7
 
f686d7
-/* save the lexical state */
f686d7
+/* save the context or parts thereof */
f686d7
 
f686d7
 /* is this a hack or what? */
f686d7
 
f686d7
 /**/
f686d7
 mod_export void
f686d7
-lexsave(void)
f686d7
+lexsave_partial(int parts)
f686d7
 {
f686d7
     struct lexstack *ls;
f686d7
 
f686d7
     ls = (struct lexstack *)malloc(sizeof(struct lexstack));
f686d7
 
f686d7
-    ls->incmdpos = incmdpos;
f686d7
-    ls->incond = incond;
f686d7
-    ls->incasepat = incasepat;
f686d7
-    ls->dbparens = dbparens;
f686d7
-    ls->isfirstln = isfirstln;
f686d7
-    ls->isfirstch = isfirstch;
f686d7
-    ls->histactive = histactive;
f686d7
-    ls->histdone = histdone;
f686d7
-    ls->lexflags = lexflags;
f686d7
-    ls->stophist = stophist;
f686d7
-    stophist = 0;
f686d7
-    if (!lstack) {
f686d7
-	/* top level, make this version visible to ZLE */
f686d7
-	zle_chline = chline;
f686d7
-	/* ensure line stored is NULL-terminated */
f686d7
-	if (hptr)
f686d7
-	    *hptr = '\0';
f686d7
+    if (parts & ZCONTEXT_LEX) {
f686d7
+	ls->incmdpos = incmdpos;
f686d7
+	ls->incond = incond;
f686d7
+	ls->incasepat = incasepat;
f686d7
+	ls->dbparens = dbparens;
f686d7
+	ls->isfirstln = isfirstln;
f686d7
+	ls->isfirstch = isfirstch;
f686d7
+	ls->lexflags = lexflags;
f686d7
+
f686d7
+	ls->tok = tok;
f686d7
+	ls->isnewlin = isnewlin;
f686d7
+	ls->tokstr = tokstr;
f686d7
+	ls->zshlextext = zshlextext;
f686d7
+	ls->bptr = bptr;
f686d7
+	ls->bsiz = bsiz;
f686d7
+	ls->len = len;
f686d7
+	ls->lex_add_raw = lex_add_raw;
f686d7
+	ls->tokstr_raw = tokstr_raw;
f686d7
+	ls->bptr_raw = bptr_raw;
f686d7
+	ls->bsiz_raw = bsiz_raw;
f686d7
+	ls->len_raw = len_raw;
f686d7
+	ls->lexstop = lexstop;
f686d7
+	ls->toklineno = toklineno;
f686d7
+
f686d7
+	tokstr = zshlextext = bptr = NULL;
f686d7
+	bsiz = 256;
f686d7
+	tokstr_raw = bptr_raw = NULL;
f686d7
+	bsiz_raw = len_raw = lex_add_raw = 0;
f686d7
+
f686d7
+	inredir = 0;
f686d7
+    }
f686d7
+    if (parts & ZCONTEXT_HIST) {
f686d7
+	if (!lstack) {
f686d7
+	    /* top level, make this version visible to ZLE */
f686d7
+	    zle_chline = chline;
f686d7
+	    /* ensure line stored is NULL-terminated */
f686d7
+	    if (hptr)
f686d7
+		*hptr = '\0';
f686d7
+	}
f686d7
+	ls->histactive = histactive;
f686d7
+	ls->histdone = histdone;
f686d7
+	ls->stophist = stophist;
f686d7
+	ls->hline = chline;
f686d7
+	ls->hptr = hptr;
f686d7
+	ls->chwords = chwords;
f686d7
+	ls->chwordlen = chwordlen;
f686d7
+	ls->chwordpos = chwordpos;
f686d7
+	ls->hwgetword = hwgetword;
f686d7
+	ls->hgetc = hgetc;
f686d7
+	ls->hungetc = hungetc;
f686d7
+	ls->hwaddc = hwaddc;
f686d7
+	ls->hwbegin = hwbegin;
f686d7
+	ls->hwend = hwend;
f686d7
+	ls->addtoline = addtoline;
f686d7
+	ls->hlinesz = hlinesz;
f686d7
+	/*
f686d7
+	 * We save and restore the command stack with history
f686d7
+	 * as it's visible to the user interactively, so if
f686d7
+	 * we're preserving history state we'll continue to
f686d7
+	 * show the current set of commands from input.
f686d7
+	 */
f686d7
+	ls->cstack = cmdstack;
f686d7
+	ls->csp = cmdsp;
f686d7
+
f686d7
+	stophist = 0;
f686d7
+	chline = NULL;
f686d7
+	hptr = NULL;
f686d7
+	histactive = 0;
f686d7
+	cmdstack = (unsigned char *)zalloc(CMDSTACKSZ);
f686d7
+	cmdsp = 0;
f686d7
+    }
f686d7
+    if (parts & ZCONTEXT_PARSE) {
f686d7
+	ls->hdocs = hdocs;
f686d7
+	ls->eclen = eclen;
f686d7
+	ls->ecused = ecused;
f686d7
+	ls->ecnpats = ecnpats;
f686d7
+	ls->ecbuf = ecbuf;
f686d7
+	ls->ecstrs = ecstrs;
f686d7
+	ls->ecsoffs = ecsoffs;
f686d7
+	ls->ecssub = ecssub;
f686d7
+	ls->ecnfunc = ecnfunc;
f686d7
+	ecbuf = NULL;
f686d7
+	hdocs = NULL;
f686d7
     }
f686d7
-    ls->hline = chline;
f686d7
-    chline = NULL;
f686d7
-    ls->hptr = hptr;
f686d7
-    hptr = NULL;
f686d7
-    ls->hlinesz = hlinesz;
f686d7
-    ls->cstack = cmdstack;
f686d7
-    ls->csp = cmdsp;
f686d7
-    cmdstack = (unsigned char *)zalloc(CMDSTACKSZ);
f686d7
-    ls->tok = tok;
f686d7
-    ls->isnewlin = isnewlin;
f686d7
-    ls->tokstr = tokstr;
f686d7
-    ls->zshlextext = zshlextext;
f686d7
-    ls->bptr = bptr;
f686d7
-    tokstr = zshlextext = bptr = NULL;
f686d7
-    ls->bsiz = bsiz;
f686d7
-    bsiz = 256;
f686d7
-    ls->len = len;
f686d7
-    ls->chwords = chwords;
f686d7
-    ls->chwordlen = chwordlen;
f686d7
-    ls->chwordpos = chwordpos;
f686d7
-    ls->hwgetword = hwgetword;
f686d7
-    ls->lexstop = lexstop;
f686d7
-    ls->hdocs = hdocs;
f686d7
-    ls->hgetc = hgetc;
f686d7
-    ls->hungetc = hungetc;
f686d7
-    ls->hwaddc = hwaddc;
f686d7
-    ls->hwbegin = hwbegin;
f686d7
-    ls->hwend = hwend;
f686d7
-    ls->addtoline = addtoline;
f686d7
-    ls->eclen = eclen;
f686d7
-    ls->ecused = ecused;
f686d7
-    ls->ecnpats = ecnpats;
f686d7
-    ls->ecbuf = ecbuf;
f686d7
-    ls->ecstrs = ecstrs;
f686d7
-    ls->ecsoffs = ecsoffs;
f686d7
-    ls->ecssub = ecssub;
f686d7
-    ls->ecnfunc = ecnfunc;
f686d7
-    ls->toklineno = toklineno;
f686d7
-    cmdsp = 0;
f686d7
-    inredir = 0;
f686d7
-    hdocs = NULL;
f686d7
-    histactive = 0;
f686d7
-    ecbuf = NULL;
f686d7
 
f686d7
     ls->next = lstack;
f686d7
     lstack = ls;
f686d7
 }
f686d7
 
f686d7
-/* restore lexical state */
f686d7
+/* save context in full */
f686d7
 
f686d7
 /**/
f686d7
 mod_export void
f686d7
-lexrestore(void)
f686d7
+lexsave(void)
f686d7
+{
f686d7
+    lexsave_partial(ZCONTEXT_HIST|ZCONTEXT_LEX|ZCONTEXT_PARSE);
f686d7
+}
f686d7
+
f686d7
+/* restore context or part therefore */
f686d7
+
f686d7
+/**/
f686d7
+mod_export void
f686d7
+lexrestore_partial(int parts)
f686d7
 {
f686d7
     struct lexstack *ln = lstack;
f686d7
 
f686d7
@@ -330,65 +377,89 @@ lexrestore(void)
f686d7
     queue_signals();
f686d7
     lstack = lstack->next;
f686d7
 
f686d7
-    if (!lstack) {
f686d7
-	/* Back to top level: don't need special ZLE value */
f686d7
-	DPUTS(ln->hline != zle_chline, "BUG: Ouch, wrong chline for ZLE");
f686d7
-	zle_chline = NULL;
f686d7
+    if (parts & ZCONTEXT_LEX) {
f686d7
+	incmdpos = ln->incmdpos;
f686d7
+	incond = ln->incond;
f686d7
+	incasepat = ln->incasepat;
f686d7
+	dbparens = ln->dbparens;
f686d7
+	isfirstln = ln->isfirstln;
f686d7
+	isfirstch = ln->isfirstch;
f686d7
+	lexflags = ln->lexflags;
f686d7
+	tok = ln->tok;
f686d7
+	isnewlin = ln->isnewlin;
f686d7
+	tokstr = ln->tokstr;
f686d7
+	zshlextext = ln->zshlextext;
f686d7
+	bptr = ln->bptr;
f686d7
+	bsiz = ln->bsiz;
f686d7
+	len = ln->len;
f686d7
+	lex_add_raw = ln->lex_add_raw;
f686d7
+	tokstr_raw = ln->tokstr_raw;
f686d7
+	bptr_raw = ln->bptr_raw;
f686d7
+	bsiz_raw = ln->bsiz_raw;
f686d7
+	len_raw = ln->len_raw;
f686d7
+	lexstop = ln->lexstop;
f686d7
+	toklineno = ln->toklineno;
f686d7
+    }
f686d7
+
f686d7
+    if (parts & ZCONTEXT_HIST) {
f686d7
+	if (!lstack) {
f686d7
+	    /* Back to top level: don't need special ZLE value */
f686d7
+	    DPUTS(ln->hline != zle_chline, "BUG: Ouch, wrong chline for ZLE");
f686d7
+	    zle_chline = NULL;
f686d7
+	}
f686d7
+	histactive = ln->histactive;
f686d7
+	histdone = ln->histdone;
f686d7
+	stophist = ln->stophist;
f686d7
+	chline = ln->hline;
f686d7
+	hptr = ln->hptr;
f686d7
+	chwords = ln->chwords;
f686d7
+	chwordlen = ln->chwordlen;
f686d7
+	chwordpos = ln->chwordpos;
f686d7
+	hwgetword = ln->hwgetword;
f686d7
+	hgetc = ln->hgetc;
f686d7
+	hungetc = ln->hungetc;
f686d7
+	hwaddc = ln->hwaddc;
f686d7
+	hwbegin = ln->hwbegin;
f686d7
+	hwend = ln->hwend;
f686d7
+	addtoline = ln->addtoline;
f686d7
+	hlinesz = ln->hlinesz;
f686d7
+	if (cmdstack)
f686d7
+	    zfree(cmdstack, CMDSTACKSZ);
f686d7
+	cmdstack = ln->cstack;
f686d7
+	cmdsp = ln->csp;
f686d7
+    }
f686d7
+
f686d7
+    if (parts & ZCONTEXT_PARSE) {
f686d7
+	if (ecbuf)
f686d7
+	    zfree(ecbuf, eclen);
f686d7
+
f686d7
+	hdocs = ln->hdocs;
f686d7
+	eclen = ln->eclen;
f686d7
+	ecused = ln->ecused;
f686d7
+	ecnpats = ln->ecnpats;
f686d7
+	ecbuf = ln->ecbuf;
f686d7
+	ecstrs = ln->ecstrs;
f686d7
+	ecsoffs = ln->ecsoffs;
f686d7
+	ecssub = ln->ecssub;
f686d7
+	ecnfunc = ln->ecnfunc;
f686d7
+
f686d7
+	errflag = 0;
f686d7
     }
f686d7
 
f686d7
-    incmdpos = ln->incmdpos;
f686d7
-    incond = ln->incond;
f686d7
-    incasepat = ln->incasepat;
f686d7
-    dbparens = ln->dbparens;
f686d7
-    isfirstln = ln->isfirstln;
f686d7
-    isfirstch = ln->isfirstch;
f686d7
-    histactive = ln->histactive;
f686d7
-    histdone = ln->histdone;
f686d7
-    lexflags = ln->lexflags;
f686d7
-    stophist = ln->stophist;
f686d7
-    chline = ln->hline;
f686d7
-    hptr = ln->hptr;
f686d7
-    if (cmdstack)
f686d7
-	zfree(cmdstack, CMDSTACKSZ);
f686d7
-    cmdstack = ln->cstack;
f686d7
-    cmdsp = ln->csp;
f686d7
-    tok = ln->tok;
f686d7
-    isnewlin = ln->isnewlin;
f686d7
-    tokstr = ln->tokstr;
f686d7
-    zshlextext = ln->zshlextext;
f686d7
-    bptr = ln->bptr;
f686d7
-    bsiz = ln->bsiz;
f686d7
-    len = ln->len;
f686d7
-    chwords = ln->chwords;
f686d7
-    chwordlen = ln->chwordlen;
f686d7
-    chwordpos = ln->chwordpos;
f686d7
-    hwgetword = ln->hwgetword;
f686d7
-    lexstop = ln->lexstop;
f686d7
-    hdocs = ln->hdocs;
f686d7
-    hgetc = ln->hgetc;
f686d7
-    hungetc = ln->hungetc;
f686d7
-    hwaddc = ln->hwaddc;
f686d7
-    hwbegin = ln->hwbegin;
f686d7
-    hwend = ln->hwend;
f686d7
-    addtoline = ln->addtoline;
f686d7
-    if (ecbuf)
f686d7
-	zfree(ecbuf, eclen);
f686d7
-    eclen = ln->eclen;
f686d7
-    ecused = ln->ecused;
f686d7
-    ecnpats = ln->ecnpats;
f686d7
-    ecbuf = ln->ecbuf;
f686d7
-    ecstrs = ln->ecstrs;
f686d7
-    ecsoffs = ln->ecsoffs;
f686d7
-    ecssub = ln->ecssub;
f686d7
-    ecnfunc = ln->ecnfunc;
f686d7
-    hlinesz = ln->hlinesz;
f686d7
-    toklineno = ln->toklineno;
f686d7
-    errflag = 0;
f686d7
     free(ln);
f686d7
 
f686d7
     unqueue_signals();
f686d7
 }
f686d7
 
f686d7
+/* complete restore context */
f686d7
+
f686d7
+/**/
f686d7
+mod_export void
f686d7
+lexrestore(void)
f686d7
+{
f686d7
+    lexrestore_partial(ZCONTEXT_HIST|ZCONTEXT_LEX|ZCONTEXT_PARSE);
f686d7
+}
f686d7
+
f686d7
 /**/
f686d7
 void
f686d7
 zshlex(void)
f686d7
@@ -1889,80 +1960,151 @@ exalias(void)
f686d7
     return 0;
f686d7
 }
f686d7
 
f686d7
-/* skip (...) */
f686d7
+/**/
f686d7
+void
f686d7
+zshlex_raw_add(int c)
f686d7
+{
f686d7
+    if (!lex_add_raw)
f686d7
+	return;
f686d7
+
f686d7
+    *bptr_raw++ = c;
f686d7
+    if (bsiz_raw == ++len_raw) {
f686d7
+	int newbsiz = bsiz_raw * 2;
f686d7
+
f686d7
+	tokstr_raw = (char *)hrealloc(tokstr_raw, bsiz_raw, newbsiz);
f686d7
+	bptr_raw = tokstr_raw + len_raw;
f686d7
+	memset(bptr_raw, 0, newbsiz - bsiz_raw);
f686d7
+	bsiz_raw = newbsiz;
f686d7
+    }
f686d7
+}
f686d7
+
f686d7
+/**/
f686d7
+void
f686d7
+zshlex_raw_back(void)
f686d7
+{
f686d7
+    if (!lex_add_raw)
f686d7
+	return;
f686d7
+    bptr_raw--;
f686d7
+    len_raw--;
f686d7
+}
f686d7
+
f686d7
+/*
f686d7
+ * Skip (...) for command-style substitutions: $(...), <(...), >(...)
f686d7
+ *
f686d7
+ * In order to ensure we don't stop at closing parentheses with
f686d7
+ * some other syntactic significance, we'll parse the input until
f686d7
+ * we find an unmatched closing parenthesis.  However, we'll throw
f686d7
+ * away the result of the parsing and just keep the string we've built
f686d7
+ * up on the way.
f686d7
+ */
f686d7
 
f686d7
 /**/
f686d7
 static int
f686d7
 skipcomm(void)
f686d7
 {
f686d7
-    int pct = 1, c, start = 1;
f686d7
+    char *new_tokstr, *new_bptr = bptr_raw;
f686d7
+    int new_len, new_bsiz, new_lexstop, new_lex_add_raw;
f686d7
 
f686d7
     cmdpush(CS_CMDSUBST);
f686d7
     SETPARBEGIN
f686d7
-    c = Inpar;
f686d7
-    do {
f686d7
-	int iswhite;
f686d7
-	add(c);
f686d7
-	c = hgetc();
f686d7
-	if (itok(c) || lexstop)
f686d7
-	    break;
f686d7
-	iswhite = inblank(c);
f686d7
-	switch (c) {
f686d7
-	case '(':
f686d7
-	    pct++;
f686d7
-	    break;
f686d7
-	case ')':
f686d7
-	    pct--;
f686d7
-	    break;
f686d7
-	case '\\':
f686d7
-	    add(c);
f686d7
-	    c = hgetc();
f686d7
-	    break;
f686d7
-	case '\'': {
f686d7
-	    int strquote = bptr[-1] == '$';
f686d7
-	    add(c);
f686d7
-	    STOPHIST
f686d7
-	    while ((c = hgetc()) != '\'' && !lexstop) {
f686d7
-		if (c == '\\' && strquote) {
f686d7
-		    add(c);
f686d7
-		    c = hgetc();
f686d7
-		}
f686d7
-		add(c);
f686d7
-	    }
f686d7
-	    ALLOWHIST
f686d7
-	    break;
f686d7
-	}
f686d7
-	case '\"':
f686d7
-	    add(c);
f686d7
-	    while ((c = hgetc()) != '\"' && !lexstop)
f686d7
-		if (c == '\\') {
f686d7
-		    add(c);
f686d7
-		    add(hgetc());
f686d7
-		} else
f686d7
-		    add(c);
f686d7
-	    break;
f686d7
-	case '`':
f686d7
-	    add(c);
f686d7
-	    while ((c = hgetc()) != '`' && !lexstop)
f686d7
-		if (c == '\\')
f686d7
-		    add(c), add(hgetc());
f686d7
-		else
f686d7
-		    add(c);
f686d7
-	    break;
f686d7
-	case '#':
f686d7
-	    if (start) {
f686d7
-		add(c);
f686d7
-		while ((c = hgetc()) != '\n' && !lexstop)
f686d7
-		    add(c);
f686d7
-		iswhite = 1;
f686d7
-	    }
f686d7
-	    break;
f686d7
+    add(Inpar);
f686d7
+
f686d7
+    new_lex_add_raw = lex_add_raw + 1;
f686d7
+    if (!lex_add_raw) {
f686d7
+	/*
f686d7
+	 * We'll combine the string so far with the input
f686d7
+	 * read in for the command substitution.  To do this
f686d7
+	 * we'll just propagate the current tokstr etc. as the
f686d7
+	 * variables used for adding raw input, and
f686d7
+	 * ensure we swap those for the real tokstr etc. at the end.
f686d7
+	 *
f686d7
+	 * However, we need to save and restore the rest of the
f686d7
+	 * lexical and parse state as we're effectively parsing
f686d7
+	 * an internal string.  Because we're still parsing it from
f686d7
+	 * the original input source (we have to --- we don't know
f686d7
+	 * when to stop inputting it otherwise and can't rely on
f686d7
+	 * the input being recoverable until we've read it) we need
f686d7
+	 * to keep the same history context.
f686d7
+	 */
f686d7
+	new_tokstr = tokstr;
f686d7
+	new_bptr = bptr;
f686d7
+	new_len = len;
f686d7
+	new_bsiz = bsiz;
f686d7
+
f686d7
+	lexsave_partial(ZCONTEXT_LEX|ZCONTEXT_PARSE);
f686d7
+    } else {
f686d7
+	/*
f686d7
+	 * Set up for nested command subsitution, however
f686d7
+	 * we don't actually need the string until we get
f686d7
+	 * back to the top level and recover the lot.
f686d7
+	 * The $() body just appears empty.
f686d7
+	 *
f686d7
+	 * We do need to propagate the raw variables which would
f686d7
+	 * otherwise by cleared, though.
f686d7
+	 */
f686d7
+	new_tokstr = tokstr_raw;
f686d7
+	new_bptr = bptr_raw;
f686d7
+	new_len = len_raw;
f686d7
+	new_bsiz = bsiz_raw;
f686d7
+
f686d7
+	lexsave_partial(ZCONTEXT_LEX|ZCONTEXT_PARSE);
f686d7
+    }
f686d7
+    tokstr_raw = new_tokstr;
f686d7
+    bsiz_raw = new_bsiz;
f686d7
+    len_raw = new_len;
f686d7
+    bptr_raw = new_bptr;
f686d7
+    lex_add_raw = new_lex_add_raw;
f686d7
+
f686d7
+    if (!parse_event(OUTPAR) || tok != OUTPAR)
f686d7
+	lexstop = 1;
f686d7
+     /* Outpar lexical token gets added in caller if present */
f686d7
+
f686d7
+    /*
f686d7
+     * We're going to keep the full raw input string
f686d7
+     * as the current token string after popping the stack.
f686d7
+     */
f686d7
+    new_tokstr = tokstr_raw;
f686d7
+    new_bptr = bptr_raw;
f686d7
+    new_len = len_raw;
f686d7
+    new_bsiz = bsiz_raw;
f686d7
+    /*
f686d7
+     * We're also going to propagate the lexical state:
f686d7
+     * if we couldn't parse the command substitution we
f686d7
+     * can't continue.
f686d7
+     */
f686d7
+    new_lexstop = lexstop;
f686d7
+
f686d7
+    lexrestore_partial(ZCONTEXT_LEX|ZCONTEXT_PARSE);
f686d7
+
f686d7
+    if (lex_add_raw) {
f686d7
+	/*
f686d7
+	 * Keep going, so retain the raw variables.
f686d7
+	 */
f686d7
+	tokstr_raw = new_tokstr;
f686d7
+	bptr_raw = new_bptr;
f686d7
+	len_raw = new_len;
f686d7
+	bsiz_raw = new_bsiz;
f686d7
+    } else {
f686d7
+	if (!new_lexstop) {
f686d7
+	    /* Ignore the ')' added on input */
f686d7
+	    new_len--;
f686d7
+	    *--new_bptr = '\0';
f686d7
 	}
f686d7
-	start = iswhite;
f686d7
+
f686d7
+	/*
f686d7
+	 * Convince the rest of lex.c we were examining a string
f686d7
+	 * all along.
f686d7
+	 */
f686d7
+	tokstr = new_tokstr;
f686d7
+	bptr = new_bptr;
f686d7
+	len = new_len;
f686d7
+	bsiz = new_bsiz;
f686d7
+	lexstop = new_lexstop;
f686d7
     }
f686d7
-    while (pct);
f686d7
+
f686d7
     if (!lexstop)
f686d7
 	SETPAREND
f686d7
     cmdpop();
f686d7
+
f686d7
     return lexstop;
f686d7
 }
f686d7
diff --git a/Src/parse.c b/Src/parse.c
f686d7
index 753080d..b0a7624 100644
f686d7
--- a/Src/parse.c
f686d7
+++ b/Src/parse.c
f686d7
@@ -360,7 +360,8 @@ ecstrcode(char *s)
f686d7
 
f686d7
 /* Initialise wordcode buffer. */
f686d7
 
f686d7
-static void
f686d7
+/**/
f686d7
+void
f686d7
 init_parse(void)
f686d7
 {
f686d7
     if (ecbuf) zfree(ecbuf, eclen);
f686d7
@@ -439,11 +440,15 @@ clear_hdocs()
f686d7
  * event	: ENDINPUT
f686d7
  *			| SEPER
f686d7
  *			| sublist [ SEPER | AMPER | AMPERBANG ]
f686d7
+ *
f686d7
+ * cmdsubst indicates our event is part of a command-style
f686d7
+ * substitution terminated by the token indicationg, usual closing
f686d7
+ * parenthesis.  In other cases endtok is ENDINPUT.
f686d7
  */
f686d7
 
f686d7
 /**/
f686d7
 Eprog
f686d7
-parse_event(void)
f686d7
+parse_event(int endtok)
f686d7
 {
f686d7
     tok = ENDINPUT;
f686d7
     incmdpos = 1;
f686d7
@@ -451,36 +456,42 @@ parse_event(void)
f686d7
     zshlex();
f686d7
     init_parse();
f686d7
 
f686d7
-    if (!par_event()) {
f686d7
+    if (!par_event(endtok)) {
f686d7
         clear_hdocs();
f686d7
         return NULL;
f686d7
     }
f686d7
+    if (endtok != ENDINPUT) {
f686d7
+	/* don't need to build an eprog for this */
f686d7
+	return &dummy_eprog;
f686d7
+    }
f686d7
     return bld_eprog();
f686d7
 }
f686d7
 
f686d7
 /**/
f686d7
-static int
f686d7
-par_event(void)
f686d7
+int
f686d7
+par_event(int endtok)
f686d7
 {
f686d7
     int r = 0, p, c = 0;
f686d7
 
f686d7
     while (tok == SEPER) {
f686d7
-	if (isnewlin > 0)
f686d7
+	if (isnewlin > 0 && endtok == ENDINPUT)
f686d7
 	    return 0;
f686d7
 	zshlex();
f686d7
     }
f686d7
     if (tok == ENDINPUT)
f686d7
 	return 0;
f686d7
+    if (tok == endtok)
f686d7
+	return 0;
f686d7
 
f686d7
     p = ecadd(0);
f686d7
 
f686d7
     if (par_sublist(&c)) {
f686d7
-	if (tok == ENDINPUT) {
f686d7
+	if (tok == ENDINPUT || tok == endtok) {
f686d7
 	    set_list_code(p, Z_SYNC, c);
f686d7
 	    r = 1;
f686d7
 	} else if (tok == SEPER) {
f686d7
 	    set_list_code(p, Z_SYNC, c);
f686d7
-	    if (isnewlin <= 0)
f686d7
+	    if (isnewlin <= 0 || endtok != ENDINPUT)
f686d7
 		zshlex();
f686d7
 	    r = 1;
f686d7
 	} else if (tok == AMPER) {
f686d7
@@ -509,7 +520,7 @@ par_event(void)
f686d7
     } else {
f686d7
 	int oec = ecused;
f686d7
 
f686d7
-	if (!par_event()) {
f686d7
+	if (!par_event(endtok)) {
f686d7
 	    ecused = oec;
f686d7
 	    ecbuf[p] |= wc_bdata(Z_END);
f686d7
 	}
f686d7
diff --git a/Src/zsh.h b/Src/zsh.h
f686d7
index 207ef18..b3391ed 100644
f686d7
--- a/Src/zsh.h
f686d7
+++ b/Src/zsh.h
f686d7
@@ -395,6 +395,15 @@ enum {
f686d7
 #define META_HEAPDUP	6
f686d7
 #define META_HREALLOC	7
f686d7
 
f686d7
+/* Context to save and restore (bit fields) */
f686d7
+enum {
f686d7
+    /* History mechanism */
f686d7
+    ZCONTEXT_HIST       = (1<<0),
f686d7
+    /* Lexical analyser */
f686d7
+    ZCONTEXT_LEX        = (1<<1),
f686d7
+    /* Parser */
f686d7
+    ZCONTEXT_PARSE      = (1<<2)
f686d7
+};
f686d7
 
f686d7
 /**************************/
f686d7
 /* Abstract types for zsh */
f686d7
diff --git a/Test/D08cmdsubst.ztst b/Test/D08cmdsubst.ztst
f686d7
index 5661b0a..a4c69a0 100644
f686d7
--- a/Test/D08cmdsubst.ztst
f686d7
+++ b/Test/D08cmdsubst.ztst
f686d7
@@ -106,3 +106,45 @@
f686d7
 >34
f686d7
 >"
f686d7
 >" OK
f686d7
+
f686d7
+ echo $(case foo in
f686d7
+ foo)
f686d7
+ echo This test worked.
f686d7
+ ;;
f686d7
+ bar)
f686d7
+ echo This test failed in a rather bizarre way.
f686d7
+ ;;
f686d7
+ *)
f686d7
+ echo This test failed.
f686d7
+ ;;
f686d7
+ esac)
f686d7
+0:Parsing of command substitution with unmatched parentheses: case, basic
f686d7
+>This test worked.
f686d7
+
f686d7
+ echo "$(case bar in
f686d7
+ foo)
f686d7
+ echo This test spoobed.
f686d7
+ ;;
f686d7
+ bar)
f686d7
+ echo This test plurbled.
f686d7
+ ;;
f686d7
+ *)
f686d7
+ echo This test bzonked.
f686d7
+ ;;
f686d7
+ esac)"
f686d7
+0:Parsing of command substitution with unmatched parentheses: case with quotes
f686d7
+>This test plurbled.
f686d7
+
f686d7
+ echo before $(
f686d7
+ echo start; echo unpretentious |
f686d7
+ while read line; do
f686d7
+   case $line in
f686d7
+   u*)
f686d7
+   print Word began with u
f686d7
+   print and ended with a crunch
f686d7
+   ;;
f686d7
+   esac
f686d7
+ done | sed -e 's/Word/Universe/'; echo end
f686d7
+ ) after
f686d7
+0:Parsing of command substitution with ummatched parentheses: with frills
f686d7
+>before start Universe began with u and ended with a crunch end after
f686d7
-- 
f686d7
2.4.3
f686d7
f686d7
f686d7
From 925112048811087520954e0c739b29371eee188a Mon Sep 17 00:00:00 2001
f686d7
From: Kamil Dudka <kdudka@redhat.com>
f686d7
Date: Thu, 8 Jan 2015 21:39:26 +0000
f686d7
Subject: [PATCH 2/9] Resolves: #1338689 - better initialize parser state
f686d7
f686d7
This fix is isolated out from a huge upstream commit that includes major
f686d7
code refactoring changes together with the initialization fix actually
f686d7
needed to resolve #1338689.
f686d7
f686d7
Upstream-commit: cfd91eac0732da8ece012ca4ab051d928a85c9dd
f686d7
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
f686d7
---
f686d7
 Src/hist.c  |  5 +++++
f686d7
 Src/parse.c | 20 ++++++++++++++++++--
f686d7
 2 files changed, 23 insertions(+), 2 deletions(-)
f686d7
f686d7
diff --git a/Src/hist.c b/Src/hist.c
f686d7
index 561e2ac..4ba61b1 100644
f686d7
--- a/Src/hist.c
f686d7
+++ b/Src/hist.c
f686d7
@@ -804,6 +804,11 @@ strinbeg(int dohist)
f686d7
     strin++;
f686d7
     hbegin(dohist);
f686d7
     lexinit();
f686d7
+    /*
f686d7
+     * Also initialise some variables owned by the parser but
f686d7
+     * used for communication between the parser and lexer.
f686d7
+     */
f686d7
+    init_parse_status();
f686d7
 }
f686d7
 
f686d7
 /* done reading a string */
f686d7
diff --git a/Src/parse.c b/Src/parse.c
f686d7
index b0a7624..b3b004b 100644
f686d7
--- a/Src/parse.c
f686d7
+++ b/Src/parse.c
f686d7
@@ -358,6 +358,21 @@ ecstrcode(char *s)
f686d7
     } while (0)
f686d7
 
f686d7
 
f686d7
+/**/
f686d7
+mod_export void
f686d7
+init_parse_status(void)
f686d7
+{
f686d7
+    /*
f686d7
+     * These variables are currently declared by the parser, so we
f686d7
+     * initialise them here.  Possibly they are more naturally declared
f686d7
+     * by the lexical anaylser; however, as they are used for signalling
f686d7
+     * between the two it's a bit ambiguous.  We clear them when
f686d7
+     * using the lexical analyser for strings as well as here.
f686d7
+     */
f686d7
+    incasepat = incond = inredir = infor = 0;
f686d7
+    incmdpos = 1;
f686d7
+}
f686d7
+
f686d7
 /* Initialise wordcode buffer. */
f686d7
 
f686d7
 /**/
f686d7
@@ -372,6 +387,8 @@ init_parse(void)
f686d7
     ecsoffs = ecnpats = 0;
f686d7
     ecssub = 0;
f686d7
     ecnfunc = 0;
f686d7
+
f686d7
+    init_parse_status();
f686d7
 }
f686d7
 
f686d7
 /* Build eprog. */
f686d7
@@ -535,9 +552,8 @@ parse_list(void)
f686d7
     int c = 0;
f686d7
 
f686d7
     tok = ENDINPUT;
f686d7
-    incmdpos = 1;
f686d7
-    zshlex();
f686d7
     init_parse();
f686d7
+    zshlex();
f686d7
     par_list(&c);
f686d7
     if (tok != ENDINPUT) {
f686d7
         clear_hdocs();
f686d7
-- 
f686d7
2.5.5
f686d7
f686d7
f686d7
From 00bc31b497525433dbaeafd3e7b92c7fe364dc8c Mon Sep 17 00:00:00 2001
f686d7
From: Peter Stephenson <pws@zsh.org>
f686d7
Date: Wed, 15 Apr 2015 10:20:06 +0100
f686d7
Subject: [PATCH 3/9] 34892 (slightly tweaked): math evaluation fix
f686d7
f686d7
An empty expression resulting from substitution includes a
f686d7
Nularg, which needs handling the same as an empty string.
f686d7
f686d7
Upstream-commit: 2ef4b38461dfb554ed2226d9de8958703bc00b98
f686d7
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
f686d7
---
f686d7
 Src/math.c         | 15 ++++++++++++++-
f686d7
 Test/C01arith.ztst |  4 ++++
f686d7
 2 files changed, 18 insertions(+), 1 deletion(-)
f686d7
f686d7
diff --git a/Src/math.c b/Src/math.c
f686d7
index e90d6a5..d6db7d3 100644
f686d7
--- a/Src/math.c
f686d7
+++ b/Src/math.c
f686d7
@@ -1330,7 +1330,7 @@ matheval(char *s)
f686d7
     if (!mlevel)
f686d7
 	outputradix = 0;
f686d7
 
f686d7
-    if (!*s) {
f686d7
+    if (!*s || *s == Nularg) {
f686d7
 	x.type = MN_INTEGER;
f686d7
 	x.u.l = 0;
f686d7
 	return x;
f686d7
@@ -1358,6 +1358,19 @@ mathevalarg(char *s, char **ss)
f686d7
     mnumber x;
f686d7
     int xmtok = mtok;
f686d7
 
f686d7
+    /*
f686d7
+     * At this entry point we don't allow an empty expression,
f686d7
+     * whereas we do with matheval().  I'm not sure if this
f686d7
+     * difference is deliberate, but it does mean that e.g.
f686d7
+     * $array[$ind] where ind hasn't been set produces an error,
f686d7
+     * which is probably safe.
f686d7
+     *
f686d7
+     * To avoid a more opaque error further in, bail out here.
f686d7
+     */
f686d7
+    if (!*s || *s == Nularg) {
f686d7
+       zerr("bad math expression: empty string");
f686d7
+       return (zlong)0;
f686d7
+    }
f686d7
     x = mathevall(s, MPREC_ARG, ss);
f686d7
     if (mtok == COMMA)
f686d7
 	(*ss)--;
f686d7
diff --git a/Test/C01arith.ztst b/Test/C01arith.ztst
f686d7
index 02d1519..33b03ef 100644
f686d7
--- a/Test/C01arith.ztst
f686d7
+++ b/Test/C01arith.ztst
f686d7
@@ -243,3 +243,7 @@
f686d7
 >6000000
f686d7
 >5000
f686d7
 >255
f686d7
+
f686d7
+  print $((`:`))
f686d7
+0:Null string in arithmetic evaluation after command substitution
f686d7
+>0
f686d7
-- 
f686d7
2.4.6
f686d7
f686d7
f686d7
From 0c1450a286e578a1cfe266bf743faf2f0719f85b Mon Sep 17 00:00:00 2001
f686d7
From: "Barton E. Schaefer" <schaefer@zsh.org>
f686d7
Date: Wed, 29 Jul 2015 22:36:45 -0700
f686d7
Subject: [PATCH 4/9] 35953: fix handling of command substitution in math
f686d7
 context
f686d7
f686d7
Upstream-commit: c0a80171ee615b52a15a6fc8efe83c2bb53451d2
f686d7
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
f686d7
---
f686d7
 Src/lex.c            | 6 +++++-
f686d7
 Test/A01grammar.ztst | 6 ++++++
f686d7
 2 files changed, 11 insertions(+), 1 deletion(-)
f686d7
f686d7
diff --git a/Src/lex.c b/Src/lex.c
f686d7
index bcceda6..f43b92b 100644
f686d7
--- a/Src/lex.c
f686d7
+++ b/Src/lex.c
f686d7
@@ -1541,7 +1541,7 @@ dquote_parse(char endchar, int sub)
f686d7
 {
f686d7
     int pct = 0, brct = 0, bct = 0, intick = 0, err = 0;
f686d7
     int c;
f686d7
-    int math = endchar == ')' || endchar == ']';
f686d7
+    int math = endchar == ')' || endchar == ']' || infor;
f686d7
     int zlemath = math && zlemetacs > zlemetall + addedx - inbufct;
f686d7
 
f686d7
     while (((c = hgetc()) != endchar || bct ||
f686d7
@@ -2004,7 +2004,9 @@ skipcomm(void)
f686d7
 {
f686d7
     char *new_tokstr, *new_bptr = bptr_raw;
f686d7
     int new_len, new_bsiz, new_lexstop, new_lex_add_raw;
f686d7
+    int save_infor = infor;
f686d7
 
f686d7
+    infor = 0;
f686d7
     cmdpush(CS_CMDSUBST);
f686d7
     SETPARBEGIN
f686d7
     add(Inpar);
f686d7
@@ -2054,6 +2056,7 @@ skipcomm(void)
f686d7
     len_raw = new_len;
f686d7
     bptr_raw = new_bptr;
f686d7
     lex_add_raw = new_lex_add_raw;
f686d7
+    dbparens = 0;	/* restored by zcontext_restore_partial() */
f686d7
 
f686d7
     if (!parse_event(OUTPAR) || tok != OUTPAR)
f686d7
 	lexstop = 1;
f686d7
@@ -2105,6 +2108,7 @@ skipcomm(void)
f686d7
     if (!lexstop)
f686d7
 	SETPAREND
f686d7
     cmdpop();
f686d7
+    infor = save_infor;
f686d7
 
f686d7
     return lexstop;
f686d7
 }
f686d7
diff --git a/Test/A01grammar.ztst b/Test/A01grammar.ztst
f686d7
index f04ddda..584ebd6 100644
f686d7
--- a/Test/A01grammar.ztst
f686d7
+++ b/Test/A01grammar.ztst
f686d7
@@ -169,6 +169,12 @@
f686d7
 >1
f686d7
 >2
f686d7
 
f686d7
+  for (( $(true); ; )); do break; done
f686d7
+  for (( ; $(true); )); do break; done
f686d7
+  for (( ; ; $(true) )); do break; done
f686d7
+  for (( ; $((1)); )); do break; done
f686d7
+0:regression test, nested cmdsubst in arithmetic `for' loop
f686d7
+
f686d7
   for keyvar valvar in key1 val1 key2 val2; do
f686d7
      print key=$keyvar val=$valvar
f686d7
   done
f686d7
-- 
f686d7
2.4.6
f686d7
f686d7
f686d7
From 821815bd9c24a84d8bb5796732ab6144b35e7d27 Mon Sep 17 00:00:00 2001
f686d7
From: Peter Stephenson <p.w.stephenson@ntlworld.com>
f686d7
Date: Sat, 10 Jan 2015 20:28:57 +0000
f686d7
Subject: [PATCH 5/9] 34220: new $(...) handling needs to back up over alias
f686d7
 expansion
f686d7
f686d7
Upstream-commit: 3b32abafdb019cfb8f29908bc3d148e01518981d
f686d7
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
f686d7
---
f686d7
 Src/input.c | 6 ++++++
f686d7
 1 file changed, 6 insertions(+)
f686d7
f686d7
diff --git a/Src/input.c b/Src/input.c
f686d7
index 1579762..5b782dc 100644
f686d7
--- a/Src/input.c
f686d7
+++ b/Src/input.c
f686d7
@@ -532,6 +532,12 @@ inpush(char *str, int flags, Alias inalias)
f686d7
 static void
f686d7
 inpoptop(void)
f686d7
 {
f686d7
+    if (!lexstop) {
f686d7
+	inbufflags &= ~INP_ALCONT;
f686d7
+	while (inbufptr > inbuf)
f686d7
+	    inungetc(inbufptr[-1]);
f686d7
+    }
f686d7
+
f686d7
     if (inbuf && (inbufflags & INP_FREE))
f686d7
 	free(inbuf);
f686d7
 
f686d7
-- 
f686d7
2.4.6
f686d7
f686d7
f686d7
From 1c731b7d1178a2623aa1b986f38a7decebf2c993 Mon Sep 17 00:00:00 2001
f686d7
From: Peter Stephenson <pws@zsh.org>
f686d7
Date: Fri, 16 Jan 2015 13:20:05 +0000
f686d7
Subject: [PATCH 6/9] 34304: improve use of new cmd subst in completion
f686d7
f686d7
Upstream-commit: db05cc51fa2298cf128e480d3ac8e5373029f6b9
f686d7
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
f686d7
---
f686d7
 Src/lex.c | 113 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++------
f686d7
 1 file changed, 103 insertions(+), 10 deletions(-)
f686d7
f686d7
diff --git a/Src/lex.c b/Src/lex.c
f686d7
index f43b92b..45c1117 100644
f686d7
--- a/Src/lex.c
f686d7
+++ b/Src/lex.c
f686d7
@@ -88,6 +88,12 @@ int inalmore;
f686d7
 int nocorrect;
f686d7
 
f686d7
 /*
f686d7
+ * TBD: the following exported variables are part of the non-interface
f686d7
+ * with ZLE for completion.  They are poorly named and the whole
f686d7
+ * scheme is incredibly brittle.  One piece of robustness is applied:
f686d7
+ * the variables are only set if LEXFLAGS_ZLE is set.  Improvements
f686d7
+ * should therefore concentrate on areas with this flag set.
f686d7
+ *
f686d7
  * Cursor position and line length in zle when the line is
f686d7
  * metafied for access from the main shell.
f686d7
  */
f686d7
@@ -111,6 +117,16 @@ mod_export int addedx;
f686d7
 /**/
f686d7
 mod_export int wb, we;
f686d7
 
f686d7
+/**/
f686d7
+mod_export int wordbeg;
f686d7
+
f686d7
+/**/
f686d7
+mod_export int parbegin;
f686d7
+
f686d7
+/**/
f686d7
+mod_export int parend;
f686d7
+
f686d7
+
f686d7
 /* 1 if aliases should not be expanded */
f686d7
 
f686d7
 /**/
f686d7
@@ -132,15 +148,6 @@ mod_export int noaliases;
f686d7
 /**/
f686d7
 mod_export int lexflags;
f686d7
 
f686d7
-/**/
f686d7
-mod_export int wordbeg;
f686d7
-
f686d7
-/**/
f686d7
-mod_export int parbegin;
f686d7
-
f686d7
-/**/
f686d7
-mod_export int parend;
f686d7
-
f686d7
 /* don't recognize comments */
f686d7
 
f686d7
 /**/
f686d7
@@ -791,7 +798,8 @@ gettok(void)
f686d7
     if (lexstop)
f686d7
 	return (errflag) ? LEXERR : ENDINPUT;
f686d7
     isfirstln = 0;
f686d7
-    wordbeg = inbufct - (qbang && c == bangchar);
f686d7
+    if ((lexflags & LEXFLAGS_ZLE))
f686d7
+	wordbeg = inbufct - (qbang && c == bangchar);
f686d7
     hwbegin(-1-(qbang && c == bangchar));
f686d7
     /* word includes the last character read and possibly \ before ! */
f686d7
     if (dbparens) {
f686d7
@@ -2002,6 +2010,78 @@ zshlex_raw_back(void)
f686d7
 static int
f686d7
 skipcomm(void)
f686d7
 {
f686d7
+#ifdef ZSH_OLD_SKIPCOMM
f686d7
+    int pct = 1, c, start = 1;
f686d7
+
f686d7
+    cmdpush(CS_CMDSUBST);
f686d7
+    SETPARBEGIN
f686d7
+    c = Inpar;
f686d7
+    do {
f686d7
+	int iswhite;
f686d7
+	add(c);
f686d7
+	c = hgetc();
f686d7
+	if (itok(c) || lexstop)
f686d7
+	    break;
f686d7
+	iswhite = inblank(c);
f686d7
+	switch (c) {
f686d7
+	case '(':
f686d7
+	    pct++;
f686d7
+	    break;
f686d7
+	case ')':
f686d7
+	    pct--;
f686d7
+	    break;
f686d7
+	case '\\':
f686d7
+	    add(c);
f686d7
+	    c = hgetc();
f686d7
+	    break;
f686d7
+	case '\'': {
f686d7
+	    int strquote = lexbuf.ptr[-1] == '$';
f686d7
+	    add(c);
f686d7
+	    STOPHIST
f686d7
+	    while ((c = hgetc()) != '\'' && !lexstop) {
f686d7
+		if (c == '\\' && strquote) {
f686d7
+		    add(c);
f686d7
+		    c = hgetc();
f686d7
+		}
f686d7
+		add(c);
f686d7
+	    }
f686d7
+	    ALLOWHIST
f686d7
+	    break;
f686d7
+	}
f686d7
+	case '\"':
f686d7
+	    add(c);
f686d7
+	    while ((c = hgetc()) != '\"' && !lexstop)
f686d7
+		if (c == '\\') {
f686d7
+		    add(c);
f686d7
+		    add(hgetc());
f686d7
+		} else
f686d7
+		    add(c);
f686d7
+	    break;
f686d7
+	case '`':
f686d7
+	    add(c);
f686d7
+	    while ((c = hgetc()) != '`' && !lexstop)
f686d7
+		if (c == '\\')
f686d7
+		    add(c), add(hgetc());
f686d7
+		else
f686d7
+		    add(c);
f686d7
+	    break;
f686d7
+	case '#':
f686d7
+	    if (start) {
f686d7
+		add(c);
f686d7
+		while ((c = hgetc()) != '\n' && !lexstop)
f686d7
+		    add(c);
f686d7
+		iswhite = 1;
f686d7
+	    }
f686d7
+	    break;
f686d7
+	}
f686d7
+	start = iswhite;
f686d7
+    }
f686d7
+    while (pct);
f686d7
+    if (!lexstop)
f686d7
+	SETPAREND
f686d7
+    cmdpop();
f686d7
+    return lexstop;
f686d7
+#else
f686d7
     char *new_tokstr, *new_bptr = bptr_raw;
f686d7
     int new_len, new_bsiz, new_lexstop, new_lex_add_raw;
f686d7
     int save_infor = infor;
f686d7
@@ -2057,6 +2137,18 @@ skipcomm(void)
f686d7
     bptr_raw = new_bptr;
f686d7
     lex_add_raw = new_lex_add_raw;
f686d7
     dbparens = 0;	/* restored by zcontext_restore_partial() */
f686d7
+    /*
f686d7
+     * Don't do any ZLE specials down here: they're only needed
f686d7
+     * when we return the string from the recursive parse.
f686d7
+     * (TBD: this probably means we should be initialising lexflags
f686d7
+     * more consistently.)
f686d7
+     *
f686d7
+     * Note that in that case we're still using the ZLE line reading
f686d7
+     * function at the history layer --- this is consistent with the
f686d7
+     * intention of maintaining the history and input layers across
f686d7
+     * the recursive parsing.
f686d7
+     */
f686d7
+    lexflags &= ~LEXFLAGS_ZLE;
f686d7
 
f686d7
     if (!parse_event(OUTPAR) || tok != OUTPAR)
f686d7
 	lexstop = 1;
f686d7
@@ -2111,4 +2203,5 @@ skipcomm(void)
f686d7
     infor = save_infor;
f686d7
 
f686d7
     return lexstop;
f686d7
+#endif
f686d7
 }
f686d7
-- 
f686d7
2.5.5
f686d7
f686d7
f686d7
From ad64470d3ea4190cd854aab2bc0f8d01ec6aef11 Mon Sep 17 00:00:00 2001
f686d7
From: Peter Stephenson <p.w.stephenson@ntlworld.com>
f686d7
Date: Fri, 16 Jan 2015 20:12:40 +0000
f686d7
Subject: [PATCH 7/9] 32413: turn off history word marking in cmd subst
f686d7
f686d7
Upstream-commit: f2a2f28f7bde196cd1fa205ac0c20336046cf2cf
f686d7
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
f686d7
---
f686d7
 Src/hist.c | 22 ++++++++++++++++++++--
f686d7
 Src/lex.c  |  2 ++
f686d7
 2 files changed, 22 insertions(+), 2 deletions(-)
f686d7
f686d7
diff --git a/Src/hist.c b/Src/hist.c
f686d7
index 561e2ac..e29a566 100644
f686d7
--- a/Src/hist.c
f686d7
+++ b/Src/hist.c
f686d7
@@ -131,6 +131,8 @@ mod_export int hist_skip_flags;
f686d7
 /* Bits of histactive variable */
f686d7
 #define HA_ACTIVE	(1<<0)	/* History mechanism is active */
f686d7
 #define HA_NOINC	(1<<1)	/* Don't store, curhist not incremented */
f686d7
+#define HA_INWORD       (1<<2)  /* We're inside a word, don't add
f686d7
+				   start and end markers */
f686d7
 
f686d7
 /* Array of word beginnings and endings in current history line. */
f686d7
 
f686d7
@@ -219,6 +221,22 @@ static int histsave_stack_pos = 0;
f686d7
 
f686d7
 static zlong histfile_linect;
f686d7
 
f686d7
+/*
f686d7
+ * Mark that the current level of history is or is not
f686d7
+ * within a word, whatever turns up.  This is used for nested
f686d7
+ * parsing of substitutions.
f686d7
+ */
f686d7
+
f686d7
+/**/
f686d7
+void
f686d7
+hist_in_word(int yesno)
f686d7
+{
f686d7
+    if (yesno)
f686d7
+	histactive |= HA_INWORD;
f686d7
+    else
f686d7
+	histactive &= ~HA_INWORD;
f686d7
+}
f686d7
+
f686d7
 /* add a character to the current history word */
f686d7
 
f686d7
 static void
f686d7
@@ -1329,7 +1347,7 @@ int hwgetword = -1;
f686d7
 void
f686d7
 ihwbegin(int offset)
f686d7
 {
f686d7
-    if (stophist == 2)
f686d7
+    if (stophist == 2 || (histactive & HA_INWORD))
f686d7
 	return;
f686d7
     if (chwordpos%2)
f686d7
 	chwordpos--;	/* make sure we're on a word start, not end */
f686d7
@@ -1349,7 +1367,7 @@ ihwbegin(int offset)
f686d7
 void
f686d7
 ihwend(void)
f686d7
 {
f686d7
-    if (stophist == 2)
f686d7
+    if (stophist == 2 || (histactive & HA_INWORD))
f686d7
 	return;
f686d7
     if (chwordpos%2 && chline) {
f686d7
 	/* end of word reached and we've already begun a word */
f686d7
diff --git a/Src/lex.c b/Src/lex.c
f686d7
index f43b92b..f1aa85d 100644
f686d7
--- a/Src/lex.c
f686d7
+++ b/Src/lex.c
f686d7
@@ -2114,6 +2114,7 @@ skipcomm(void)
f686d7
 	new_bsiz = bsiz;
f686d7
 
f686d7
 	lexsave_partial(ZCONTEXT_LEX|ZCONTEXT_PARSE);
f686d7
+	hist_in_word(1);
f686d7
     } else {
f686d7
 	/*
f686d7
 	 * Set up for nested command subsitution, however
f686d7
@@ -2195,6 +2196,7 @@ skipcomm(void)
f686d7
 	len = new_len;
f686d7
 	bsiz = new_bsiz;
f686d7
 	lexstop = new_lexstop;
f686d7
+	hist_in_word(0);
f686d7
     }
f686d7
 
f686d7
     if (!lexstop)
f686d7
-- 
f686d7
2.5.5
f686d7
f686d7
f686d7
From 22b063c5f2bb3350c856215e436a62d25440e605 Mon Sep 17 00:00:00 2001
f686d7
From: Peter Stephenson <p.w.stephenson@ntlworld.com>
f686d7
Date: Sun, 18 Jan 2015 16:43:26 +0000
f686d7
Subject: [PATCH 8/9] 34319: fix alias expansion in history for command
f686d7
 substitution
f686d7
f686d7
Upstream-commit: e34ce85151dcd5ac698e116a6742d481ff64ae2c
f686d7
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
f686d7
---
f686d7
 Src/hist.c | 26 ++++++++++++++++++++------
f686d7
 1 file changed, 20 insertions(+), 6 deletions(-)
f686d7
f686d7
diff --git a/Src/hist.c b/Src/hist.c
f686d7
index e29a566..08763fe 100644
f686d7
--- a/Src/hist.c
f686d7
+++ b/Src/hist.c
f686d7
@@ -243,7 +243,16 @@ static void
f686d7
 ihwaddc(int c)
f686d7
 {
f686d7
     /* Only if history line exists and lexing has not finished. */
f686d7
-    if (chline && !(errflag || lexstop)) {
f686d7
+    if (chline && !(errflag || lexstop) &&
f686d7
+	/*
f686d7
+	 * If we're reading inside a word for command substitution
f686d7
+	 * we allow the lexer to expand aliases but don't deal
f686d7
+	 * with them here.  Note matching code in ihungetc().
f686d7
+	 * TBD: it might be neater to deal with all aliases in this
f686d7
+	 * fashion as we never need the expansion in the history
f686d7
+	 * line, only in the lexer and above.
f686d7
+	 */
f686d7
+	!((histactive & HA_INWORD) && (inbufflags & INP_ALIAS))) {
f686d7
 	/* Quote un-expanded bangs in the history line. */
f686d7
 	if (c == bangchar && stophist < 2 && qbang)
f686d7
 	    /* If qbang is not set, we do not escape this bangchar as it's *
f686d7
@@ -798,11 +807,16 @@ ihungetc(int c)
f686d7
 	    zlemetall--;
f686d7
 	    exlast++;
f686d7
 	}
f686d7
-	DPUTS(hptr <= chline, "BUG: hungetc attempted at buffer start");
f686d7
-	hptr--;
f686d7
-	DPUTS(*hptr != (char) c, "BUG: wrong character in hungetc() ");
f686d7
-	qbang = (c == bangchar && stophist < 2 &&
f686d7
-		 hptr > chline && hptr[-1] == '\\');
f686d7
+	if (!(histactive & HA_INWORD) || !(inbufflags & INP_ALIAS)) {
f686d7
+	    DPUTS(hptr <= chline, "BUG: hungetc attempted at buffer start");
f686d7
+	    hptr--;
f686d7
+	    DPUTS(*hptr != (char) c, "BUG: wrong character in hungetc() ");
f686d7
+	    qbang = (c == bangchar && stophist < 2 &&
f686d7
+		     hptr > chline && hptr[-1] == '\\');
f686d7
+	} else {
f686d7
+	    /* No active bangs in aliases */
f686d7
+	    qbang = 0;
f686d7
+	}
f686d7
 	if (doit)
f686d7
 	    inungetc(c);
f686d7
 	if (!qbang)
f686d7
-- 
f686d7
2.5.5
f686d7
f686d7
f686d7
From 155587d13060e4c7c9bbd61b7cc0a6dd17922d56 Mon Sep 17 00:00:00 2001
f686d7
From: Peter Stephenson <p.w.stephenson@ntlworld.com>
f686d7
Date: Sun, 18 Jan 2015 22:38:57 +0000
f686d7
Subject: [PATCH 9/9] 34322: bug with interface to parsestr() etc.
f686d7
f686d7
Was showing up in places like ${(e)...} where command substitution
f686d7
could reallocate the token string, but actually there was never any
f686d7
guarantee that the lexer wouldn't do that, so this was always
f686d7
a bit iffy.
f686d7
f686d7
Upstream-commit: c6c9f5daf2e196e6ab7346dfbf5f5166a1d87f0c
f686d7
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
f686d7
---
f686d7
 Src/Zle/compctl.c      |  4 ++--
f686d7
 Src/Zle/compresult.c   |  3 ++-
f686d7
 Src/exec.c             |  9 +++++----
f686d7
 Src/init.c             | 11 +++++++----
f686d7
 Src/lex.c              | 30 +++++++++++++++++++++---------
f686d7
 Src/params.c           |  3 ++-
f686d7
 Src/prompt.c           |  2 +-
f686d7
 Src/subst.c            |  8 +++++---
f686d7
 Src/utils.c            |  2 +-
f686d7
 Test/D04parameter.ztst |  7 +++++++
f686d7
 10 files changed, 53 insertions(+), 26 deletions(-)
f686d7
f686d7
diff --git a/Src/Zle/compctl.c b/Src/Zle/compctl.c
f686d7
index 0143370..5d67137 100644
f686d7
--- a/Src/Zle/compctl.c
f686d7
+++ b/Src/Zle/compctl.c
f686d7
@@ -3854,7 +3854,7 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd)
f686d7
 	    yaptr = get_user_var(uv);
f686d7
 	if ((tt = cc->explain)) {
f686d7
 	    tt = dupstring(tt);
f686d7
-	    if ((cc->mask & CC_EXPANDEXPL) && !parsestr(tt)) {
f686d7
+	    if ((cc->mask & CC_EXPANDEXPL) && !parsestr(&tt)) {
f686d7
 		singsub(&tt;;
f686d7
 		untokenize(tt);
f686d7
 	    }
f686d7
@@ -3874,7 +3874,7 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd)
f686d7
 	}
f686d7
     } else if ((tt = cc->explain)) {
f686d7
 	tt = dupstring(tt);
f686d7
-	if ((cc->mask & CC_EXPANDEXPL) && !parsestr(tt)) {
f686d7
+	if ((cc->mask & CC_EXPANDEXPL) && !parsestr(&tt)) {
f686d7
 	    singsub(&tt;;
f686d7
 	    untokenize(tt);
f686d7
 	}
f686d7
diff --git a/Src/Zle/compresult.c b/Src/Zle/compresult.c
f686d7
index c0e5ff3..69d066c 100644
f686d7
--- a/Src/Zle/compresult.c
f686d7
+++ b/Src/Zle/compresult.c
f686d7
@@ -1090,7 +1090,8 @@ do_single(Cmatch m)
f686d7
 		    }
f686d7
 		    if (tryit) {
f686d7
 			noerrs = 1;
f686d7
-			parsestr(p);
f686d7
+			p = dupstring(p);
f686d7
+			parsestr(&p);
f686d7
 			singsub(&p);
f686d7
 			errflag = 0;
f686d7
 			noerrs = ne;
f686d7
diff --git a/Src/exec.c b/Src/exec.c
f686d7
index 7817a64..27e235f 100644
f686d7
--- a/Src/exec.c
f686d7
+++ b/Src/exec.c
f686d7
@@ -3631,17 +3631,18 @@ gethere(char **strp, int typ)
f686d7
 	*bptr++ = '\n';
f686d7
     }
f686d7
     *t = '\0';
f686d7
+    s = buf;
f686d7
+    buf = dupstring(buf);
f686d7
+    zfree(s, bsiz);
f686d7
     if (!qt) {
f686d7
 	int ef = errflag;
f686d7
 
f686d7
-	parsestr(buf);
f686d7
+	parsestr(&buf;;
f686d7
 
f686d7
 	if (!errflag)
f686d7
 	    errflag = ef;
f686d7
     }
f686d7
-    s = dupstring(buf);
f686d7
-    zfree(buf, bsiz);
f686d7
-    return s;
f686d7
+    return buf;
f686d7
 }
f686d7
 
f686d7
 /* open here string fd */
f686d7
diff --git a/Src/init.c b/Src/init.c
f686d7
index 78f171d..485fb32 100644
f686d7
--- a/Src/init.c
f686d7
+++ b/Src/init.c
f686d7
@@ -1143,10 +1143,13 @@ run_init_scripts(void)
f686d7
 	    if (islogin)
f686d7
 		sourcehome(".profile");
f686d7
 	    noerrs = 2;
f686d7
-	    if (s && !parsestr(s)) {
f686d7
-		singsub(&s);
f686d7
-		noerrs = 0;
f686d7
-		source(s);
f686d7
+	    if (s) {
f686d7
+		s = dupstring(s);
f686d7
+		if (!parsestr(&s)) {
f686d7
+		    singsub(&s);
f686d7
+		    noerrs = 0;
f686d7
+		    source(s);
f686d7
+		}
f686d7
 	    }
f686d7
 	    noerrs = 0;
f686d7
 	} else
f686d7
diff --git a/Src/lex.c b/Src/lex.c
f686d7
index b8fe332..fa920bd 100644
f686d7
--- a/Src/lex.c
f686d7
+++ b/Src/lex.c
f686d7
@@ -1693,17 +1693,27 @@ dquote_parse(char endchar, int sub)
f686d7
     return err;
f686d7
 }
f686d7
 
f686d7
-/* Tokenize a string given in s. Parsing is done as in double *
f686d7
- * quotes.  This is usually called before singsub().          */
f686d7
+/*
f686d7
+ * Tokenize a string given in s. Parsing is done as in double
f686d7
+ * quotes.  This is usually called before singsub().
f686d7
+ *
f686d7
+ * parsestr() is noisier, reporting an error if the parse failed.
f686d7
+ *
f686d7
+ * On entry, *s must point to a string allocated from the stack of
f686d7
+ * exactly the right length, i.e. strlen(*s) + 1, as the string
f686d7
+ * is used as the lexical token string whose memory management
f686d7
+ * demands this.  Usually the input string will therefore be
f686d7
+ * the result of an immediately preceding dupstring().
f686d7
+ */
f686d7
 
f686d7
 /**/
f686d7
 mod_export int
f686d7
-parsestr(char *s)
f686d7
+parsestr(char **s)
f686d7
 {
f686d7
     int err;
f686d7
 
f686d7
     if ((err = parsestrnoerr(s))) {
f686d7
-	untokenize(s);
f686d7
+	untokenize(*s);
f686d7
 	if (err > 32 && err < 127)
f686d7
 	    zerr("parse error near `%c'", err);
f686d7
 	else
f686d7
@@ -1714,18 +1724,20 @@ parsestr(char *s)
f686d7
 
f686d7
 /**/
f686d7
 mod_export int
f686d7
-parsestrnoerr(char *s)
f686d7
+parsestrnoerr(char **s)
f686d7
 {
f686d7
-    int l = strlen(s), err;
f686d7
+    int l = strlen(*s), err;
f686d7
 
f686d7
     lexsave();
f686d7
-    untokenize(s);
f686d7
-    inpush(dupstring(s), 0, NULL);
f686d7
+    untokenize(*s);
f686d7
+    inpush(dupstring(*s), 0, NULL);
f686d7
     strinbeg(0);
f686d7
     len = 0;
f686d7
-    bptr = tokstr = s;
f686d7
+    bptr = tokstr = *s;
f686d7
     bsiz = l + 1;
f686d7
     err = dquote_parse('\0', 1);
f686d7
+    if (tokstr)
f686d7
+	*s = tokstr;
f686d7
     *bptr = '\0';
f686d7
     strinend();
f686d7
     inpop();
f686d7
diff --git a/Src/params.c b/Src/params.c
f686d7
index babf6f2..f7551b2 100644
f686d7
--- a/Src/params.c
f686d7
+++ b/Src/params.c
f686d7
@@ -1241,7 +1241,8 @@ getarg(char **str, int *inv, Value v, int a2, zlong *w,
f686d7
     if (ishash && (keymatch || !rev))
f686d7
 	remnulargs(s);
f686d7
     if (needtok) {
f686d7
-	if (parsestr(s))
f686d7
+	s = dupstring(s);
f686d7
+	if (parsestr(&s))
f686d7
 	    return 0;
f686d7
 	singsub(&s);
f686d7
     } else if (rev)
f686d7
diff --git a/Src/prompt.c b/Src/prompt.c
f686d7
index e51ce24..290f227 100644
f686d7
--- a/Src/prompt.c
f686d7
+++ b/Src/prompt.c
f686d7
@@ -183,7 +183,7 @@ promptexpand(char *s, int ns, char *rs, char *Rs, unsigned int *txtchangep)
f686d7
 	int oldval = lastval;
f686d7
 
f686d7
 	s = dupstring(s);
f686d7
-	if (!parsestr(s))
f686d7
+	if (!parsestr(&s))
f686d7
 	    singsub(&s);
f686d7
 	/*
f686d7
 	 * We don't need the special Nularg hack here and we're
f686d7
diff --git a/Src/subst.c b/Src/subst.c
f686d7
index a4df256..dcffe2f 100644
f686d7
--- a/Src/subst.c
f686d7
+++ b/Src/subst.c
f686d7
@@ -1306,7 +1306,7 @@ get_intarg(char **s, int *delmatchp)
f686d7
     p = dupstring(*s + arglen);
f686d7
     *s = t + arglen;
f686d7
     *t = sav;
f686d7
-    if (parsestr(p))
f686d7
+    if (parsestr(&p))
f686d7
 	return -1;
f686d7
     singsub(&p);
f686d7
     if (errflag)
f686d7
@@ -1329,7 +1329,8 @@ subst_parse_str(char **sp, int single, int err)
f686d7
 
f686d7
     *sp = s = dupstring(*sp);
f686d7
 
f686d7
-    if (!(err ? parsestr(s) : parsestrnoerr(s))) {
f686d7
+    if (!(err ? parsestr(&s) : parsestrnoerr(&s))) {
f686d7
+	*sp = s;
f686d7
 	if (!single) {
f686d7
             int qt = 0;
f686d7
 
f686d7
@@ -1426,7 +1427,8 @@ check_colon_subscript(char *str, char **endp)
f686d7
     }
f686d7
     sav = **endp;
f686d7
     **endp = '\0';
f686d7
-    if (parsestr(str = dupstring(str)))
f686d7
+    str = dupstring(str);
f686d7
+    if (parsestr(&str))
f686d7
 	return NULL;
f686d7
     singsub(&str);
f686d7
     remnulargs(str);
f686d7
diff --git a/Src/utils.c b/Src/utils.c
f686d7
index 26e2a5c..2c1d034 100644
f686d7
--- a/Src/utils.c
f686d7
+++ b/Src/utils.c
f686d7
@@ -1440,7 +1440,7 @@ checkmailpath(char **s)
f686d7
 		    setunderscore(*s);
f686d7
 
f686d7
 		    u = dupstring(u);
f686d7
-		    if (! parsestr(u)) {
f686d7
+		    if (!parsestr(&u)) {
f686d7
 			singsub(&u);
f686d7
 			zputs(u, shout);
f686d7
 			fputc('\n', shout);
f686d7
diff --git a/Test/D04parameter.ztst b/Test/D04parameter.ztst
f686d7
index bea9459..fa629b2 100644
f686d7
--- a/Test/D04parameter.ztst
f686d7
+++ b/Test/D04parameter.ztst
f686d7
@@ -1551,3 +1551,10 @@
f686d7
 0:Empty parameter shouldn't cause modifiers to crash the shell
f686d7
 >
f686d7
 >
f686d7
+
f686d7
+# The following tests the return behaviour of parsestr/parsestrnoerr
f686d7
+  alias param-test-alias='print $'\''\x45xpanded in substitution'\'
f686d7
+  param='$(param-test-alias)'
f686d7
+  print ${(e)param}
f686d7
+0:Alias expansion in command substitution in parameter evaluation
f686d7
+>Expanded in substitution
f686d7
-- 
f686d7
2.7.4
f686d7