about summary refs log tree commit diff
path: root/Src/parse.c
diff options
context:
space:
mode:
authorPeter Stephenson <pws@zsh.org>2015-05-18 09:56:00 +0100
committerPeter Stephenson <pws@zsh.org>2015-05-18 09:56:00 +0100
commit52aeb9aaeb4799b760138a7c34b18ede4b47242a (patch)
tree0da193cbc61ac0000ae0bad210619276f63dccd5 /Src/parse.c
parent34a1489f436d95bc2404f8e371130a469cbccebe (diff)
downloadzsh-52aeb9aaeb4799b760138a7c34b18ede4b47242a.tar.gz
zsh-52aeb9aaeb4799b760138a7c34b18ede4b47242a.tar.xz
zsh-52aeb9aaeb4799b760138a7c34b18ede4b47242a.zip
35168: Improve parsing of case patterns.
"|" is now found properly by looking for words that come
from the lexical analyser, rather than hacking a pattern
returned in one dollop.

Update some completion functions that need extra quoting
as a result.

Add test for new parsing.

Update version number to 5.0.8-dev-3 because of wordcode
incompatibility.
Diffstat (limited to 'Src/parse.c')
-rw-r--r--Src/parse.c89
1 files changed, 23 insertions, 66 deletions
diff --git a/Src/parse.c b/Src/parse.c
index 985eb8e71..c938d2dce 100644
--- a/Src/parse.c
+++ b/Src/parse.c
@@ -349,9 +349,8 @@ ecadd(wordcode c)
 	eclen += a;
     }
     ecbuf[ecused] = c;
-    ecused++;
 
-    return ecused - 1;
+    return ecused++;
 }
 
 /* Delete a wordcode. */
@@ -1128,7 +1127,7 @@ par_for(int *cmplx)
 static void
 par_case(int *cmplx)
 {
-    int oecused = ecused, brflag, p, pp, n = 1, type;
+    int oecused = ecused, brflag, p, pp, palts, type, nalts;
     int ona, onc;
 
     p = ecadd(0);
@@ -1153,7 +1152,7 @@ par_case(int *cmplx)
 	YYERRORV(oecused);
     }
     brflag = (tok == INBRACE);
-    incasepat = 1;
+    incasepat = 2;
     incmdpos = 0;
     noaliases = ona;
     nocorrect = onc;
@@ -1166,8 +1165,10 @@ par_case(int *cmplx)
 	    zshlex();
 	if (tok == OUTBRACE)
 	    break;
-	if (tok == INPAR)
+	if (tok == INPAR) {
+	    incasepat = 1;
 	    zshlex();
+	}
 	if (tok != STRING)
 	    YYERRORV(oecused);
 	if (!strcmp(tokstr, "esac"))
@@ -1176,89 +1177,45 @@ par_case(int *cmplx)
 	incasepat = 0;
 	incmdpos = 1;
 	type = WC_CASE_OR;
+	pp = ecadd(0);
+	palts = ecadd(0);
+	nalts = 0;
 	for (;;) {
+	    ecstr(str);
+	    ecadd(ecnpats++);
+	    nalts++;
+
 	    zshlex();
 	    if (tok == OUTPAR) {
 		incasepat = 0;
 		incmdpos = 1;
 		zshlex();
 		break;
-	    } else if (tok == BAR) {
-		char *str2;
-		int sl = strlen(str);
-
-		incasepat = 1;
-		incmdpos = 0;
-		str2 = hcalloc(sl + 2);
-		strcpy(str2, str);
-		str2[sl] = Bar;
-		str2[sl+1] = '\0';
-		str = str2;
-	    } else {
-		int sl = strlen(str);
-
-		if (!sl || str[sl - 1] != Bar) {
-		    /* POSIX allows (foo*) patterns */
-		    int pct;
-		    char *s;
-
-		    for (s = str, pct = 0; *s; s++) {
-			if (*s == Inpar)
-			    pct++;
-			if (!pct)
-			    break;
-			if (pct == 1) {
-			    if (*s == Bar || *s == Inpar)
-				while (iblank(s[1]))
-				    chuck(s+1);
-			    if (*s == Bar || *s == Outpar)
-				while (iblank(s[-1]) &&
-				       (s < str + 1 || s[-2] != Meta))
-				    chuck(--s);
-			}
-			if (*s == Outpar)
-			    pct--;
-		    }
-		    if (*s || pct || s == str)
-			YYERRORV(oecused);
-		    /* Simplify pattern by removing surrounding (...) */
-		    sl = strlen(str);
-		    DPUTS(*str != Inpar || str[sl - 1] != Outpar,
-			  "BUG: strange case pattern");
-		    str[sl - 1] = '\0';
-		    chuck(str);
-		    break;
-		} else {
-		    char *str2;
-
-		    if (tok != STRING)
-			YYERRORV(oecused);
-		    str2 = hcalloc(sl + strlen(tokstr) + 1);
-		    strcpy(str2, str);
-		    strcpy(str2 + sl, tokstr);
-		    str = str2;
-		}
-	    }
+	    } else if (tok != BAR)
+		YYERRORV(oecused);
+
+	    zshlex();
+	    if (tok != STRING)
+		YYERRORV(oecused);
+	    str = dupstring(tokstr);
 	}
-	pp = ecadd(0);
-	ecstr(str);
-	ecadd(ecnpats++);
 	par_save_list(cmplx);
-	n++;
 	if (tok == SEMIAMP)
 	    type = WC_CASE_AND;
 	else if (tok == SEMIBAR)
 	    type = WC_CASE_TESTAND;
 	ecbuf[pp] = WCB_CASE(type, ecused - 1 - pp);
+	ecbuf[palts] = nalts;
 	if ((tok == ESAC && !brflag) || (tok == OUTBRACE && brflag))
 	    break;
 	if (tok != DSEMI && tok != SEMIAMP && tok != SEMIBAR)
 	    YYERRORV(oecused);
-	incasepat = 1;
+	incasepat = 2;
 	incmdpos = 0;
 	zshlex();
     }
     incmdpos = 1;
+    incasepat = 0;
     zshlex();
 
     ecbuf[p] = WCB_CASE(WC_CASE_HEAD, ecused - 1 - p);