about summary refs log tree commit diff
path: root/Src
diff options
context:
space:
mode:
authorPaul Ackersviller <packersv@users.sourceforge.net>2007-11-11 21:51:20 +0000
committerPaul Ackersviller <packersv@users.sourceforge.net>2007-11-11 21:51:20 +0000
commit66ae2822dd269332a06641d8fc0da0c0e60734eb (patch)
treedb8451cd0044899ae62b5cc63e44503e744cb66a /Src
parent469921ba16eae89eb7ecfb1ea8fcdd34c1b0a642 (diff)
downloadzsh-66ae2822dd269332a06641d8fc0da0c0e60734eb.tar.gz
zsh-66ae2822dd269332a06641d8fc0da0c0e60734eb.tar.xz
zsh-66ae2822dd269332a06641d8fc0da0c0e60734eb.zip
Merge of 23115: add ";|" at end of case statement to cause testing of later patterns.
Diffstat (limited to 'Src')
-rw-r--r--Src/lex.c4
-rw-r--r--Src/loop.c245
-rw-r--r--Src/parse.c12
-rw-r--r--Src/text.c28
-rw-r--r--Src/zsh.h33
5 files changed, 228 insertions, 94 deletions
diff --git a/Src/lex.c b/Src/lex.c
index 5b001c4eb..e91cecfbc 100644
--- a/Src/lex.c
+++ b/Src/lex.c
@@ -158,6 +158,7 @@ mod_export char *tokstrings[WHILE + 1] = {
     "))",	/* DOUTPAR	     */
     "&|",	/* AMPERBANG	  30 */
     ";&",	/* SEMIAMP	     */
+    ";|",	/* SEMIBAR	     */
 };
 
 /* lexical state */
@@ -384,6 +385,7 @@ ctxtlex(void)
     case SEMI:
     case DSEMI:
     case SEMIAMP:
+    case SEMIBAR:
     case AMPER:
     case AMPERBANG:
     case INPAR:
@@ -716,6 +718,8 @@ gettok(void)
 	    return DSEMI;
 	else if(d == '&')
 	    return SEMIAMP;
+	else if (d == '|')
+	    return SEMIBAR;
 	hungetc(d);
 	lexstop = 0;
 	return SEMI;
diff --git a/Src/loop.c b/Src/loop.c
index 668f47b97..8acd51a54 100644
--- a/Src/loop.c
+++ b/Src/loop.c
@@ -38,7 +38,7 @@ int loops;
 /* # of continue levels */
  
 /**/
-int contflag;
+mod_export int contflag;
  
 /* # of break levels */
  
@@ -52,15 +52,15 @@ execfor(Estate state, int do_exec)
     Wordcode end, loop;
     wordcode code = state->pc[-1];
     int iscond = (WC_FOR_TYPE(code) == WC_FOR_COND), ctok = 0, atok = 0;
+    int last = 0;
     char *name, *str, *cond = NULL, *advance = NULL;
     zlong val = 0;
-    LinkList args = NULL;
+    LinkList vars = NULL, args = NULL;
 
-    name = ecgetstr(state, EC_NODUP, NULL);
     end = state->pc + WC_FOR_SKIP(code);
 
     if (iscond) {
-	str = dupstring(name);
+	str = dupstring(ecgetstr(state, EC_NODUP, NULL));
 	singsub(&str);
 	if (isset(XTRACE)) {
 	    char *str2 = dupstring(str);
@@ -77,28 +77,32 @@ execfor(Estate state, int do_exec)
 	}
 	cond = ecgetstr(state, EC_NODUP, &ctok);
 	advance = ecgetstr(state, EC_NODUP, &atok);
-    } else if (WC_FOR_TYPE(code) == WC_FOR_LIST) {
-	int htok = 0;
-
-	if (!(args = ecgetlist(state, *state->pc++, EC_DUPTOK, &htok))) {
-	    state->pc = end;
-	    return 0;
-	}
-	if (htok)
-	    execsubst(args);
     } else {
-	char **x;
+	vars = ecgetlist(state, *state->pc++, EC_NODUP, NULL);
 
-	args = newlinklist();
-	for (x = pparams; *x; x++)
-	    addlinknode(args, dupstring(*x));
+	if (WC_FOR_TYPE(code) == WC_FOR_LIST) {
+	    int htok = 0;
+
+	    if (!(args = ecgetlist(state, *state->pc++, EC_DUPTOK, &htok))) {
+		state->pc = end;
+		return 0;
+	    }
+	    if (htok)
+		execsubst(args);
+	} else {
+	    char **x;
+
+	    args = newlinklist();
+	    for (x = pparams; *x; x++)
+		addlinknode(args, dupstring(*x));
+	}
     }
     lastval = 0;
     loops++;
     pushheap();
     cmdpush(CS_FOR);
     loop = state->pc;
-    for (;;) {
+    while (!last) {
 	if (iscond) {
 	    if (ctok) {
 		str = dupstring(cond);
@@ -127,14 +131,29 @@ execfor(Estate state, int do_exec)
 	    if (!val)
 		break;
 	} else {
-	    if (!args || !(str = (char *) ugetnode(args)))
-		break;
-	    if (isset(XTRACE)) {
-		printprompt4();
-		fprintf(xtrerr, "%s=%s\n", name, str);
-		fflush(xtrerr);
+	    LinkNode node;
+	    int count = 0;
+	    for (node = firstnode(vars); node; incnode(node))
+	    {
+		name = (char *)getdata(node);
+		if (!args || !(str = (char *) ugetnode(args)))
+		{
+		    if (count) { 
+			str = "";
+			last = 1;
+		    } else
+			break;
+		}
+		if (isset(XTRACE)) {
+		    printprompt4();
+		    fprintf(xtrerr, "%s=%s\n", name, str);
+		    fflush(xtrerr);
+		}
+		setsparam(name, ztrdup(str));
+		count++;
 	    }
-	    setsparam(name, ztrdup(str));
+	    if (!count)
+		break;
 	}
 	state->pc = loop;
 	execlist(state, 1, do_exec && args && empty(args));
@@ -177,7 +196,7 @@ execfor(Estate state, int do_exec)
 
 /**/
 int
-execselect(Estate state, int do_exec)
+execselect(Estate state, UNUSED(int do_exec))
 {
     Wordcode end, loop;
     wordcode code = state->pc[-1];
@@ -226,7 +245,7 @@ execselect(Estate state, int do_exec)
 		    int oef = errflag;
 
 		    isfirstln = 1;
-		    str = (char *)zleread(prompt3, NULL, 0);
+		    str = (char *)zleread(&prompt3, NULL, 0, ZLCON_SELECT);
 		    if (errflag)
 			str = NULL;
 		    errflag = oef;
@@ -319,7 +338,8 @@ selectlist(LinkList l, size_t start)
     for (t1 = start; t1 != colsz && t1 - start < lines - 2; t1++) {
 	ap = arr + t1;
 	do {
-	    int t2 = strlen(*ap) + 2, t3;
+	    size_t t2 = strlen(*ap) + 2;
+	    int t3;
 
 	    fprintf(stderr, "%d) %s", t3 = ap - arr + 1, *ap);
 	    while (t3)
@@ -348,7 +368,7 @@ selectlist(LinkList l, size_t start)
 
 /**/
 int
-execwhile(Estate state, int do_exec)
+execwhile(Estate state, UNUSED(int do_exec))
 {
     Wordcode end, loop;
     wordcode code = state->pc[-1];
@@ -361,37 +381,53 @@ execwhile(Estate state, int do_exec)
     cmdpush(isuntil ? CS_UNTIL : CS_WHILE);
     loops++;
     loop = state->pc;
-    for (;;) {
-	state->pc = loop;
-	noerrexit = 1;
-	execlist(state, 1, 0);
-	noerrexit = olderrexit;
-	if (!((lastval == 0) ^ isuntil)) {
-	    if (breaks)
-		breaks--;
-	    lastval = oldval;
-	    break;
-	}
-	if (retflag) {
-	    lastval = oldval;
-	    break;
-	}
-	execlist(state, 1, 0);
-	if (breaks) {
-	    breaks--;
-	    if (breaks || !contflag)
-		break;
-	    contflag = 0;
-	}
-	if (errflag) {
-	    lastval = 1;
-	    break;
-	}
-	if (retflag)
-	    break;
-	freeheap();
-	oldval = lastval;
-    }
+
+    if (loop[0] == WC_END && loop[1] == WC_END) {
+
+        /* This is an empty loop.  Make sure the signal handler sets the
+        * flags and then just wait for someone hitting ^C. */
+
+        int old_simple_pline = simple_pline;
+
+        simple_pline = 1;
+
+        while (!breaks)
+            ;
+        breaks--;
+
+        simple_pline = old_simple_pline;
+    } else
+        for (;;) {
+            state->pc = loop;
+            noerrexit = 1;
+            execlist(state, 1, 0);
+            noerrexit = olderrexit;
+            if (!((lastval == 0) ^ isuntil)) {
+                if (breaks)
+                    breaks--;
+                lastval = oldval;
+                break;
+            }
+            if (retflag) {
+                lastval = oldval;
+                break;
+            }
+            execlist(state, 1, 0);
+            if (breaks) {
+                breaks--;
+                if (breaks || !contflag)
+                    break;
+                contflag = 0;
+            }
+            if (errflag) {
+                lastval = 1;
+                break;
+            }
+            if (retflag)
+                break;
+            freeheap();
+            oldval = lastval;
+        }
     cmdpop();
     popheap();
     loops--;
@@ -401,7 +437,7 @@ execwhile(Estate state, int do_exec)
 
 /**/
 int
-execrepeat(Estate state, int do_exec)
+execrepeat(Estate state, UNUSED(int do_exec))
 {
     Wordcode end, loop;
     wordcode code = state->pc[-1];
@@ -524,9 +560,9 @@ execcase(Estate state, int do_exec)
 	if (isset(XTRACE)) {
 	    char *pat2, *opat;
 
-	    opat = pat = ecgetstr(state, EC_DUP, NULL);
+	    pat = dupstring(opat = ecrawstr(state->prog, state->pc, NULL));
 	    singsub(&pat);
-	    save = (state->prog->alloc != EA_HEAP &&
+	    save = (!(state->prog->flags & EF_HEAP) &&
 		    !strcmp(pat, opat) && *spprog != dummy_patprog2);
 
 	    pat2 = dupstring(pat);
@@ -534,9 +570,8 @@ execcase(Estate state, int do_exec)
 	    printprompt4();
 	    fprintf(xtrerr, "case %s (%s)\n", word, pat2);
 	    fflush(xtrerr);
-	    state->pc++;
-	} else
-	    state->pc += 2;
+	}
+	state->pc += 2;
 
 	if (*spprog != dummy_patprog1 && *spprog != dummy_patprog2)
 	    pprog = *spprog;
@@ -546,11 +581,11 @@ execcase(Estate state, int do_exec)
 		char *opat;
 		int htok = 0;
 
-		opat = pat = dupstring(ecrawstr(state->prog,
+		pat = dupstring(opat = ecrawstr(state->prog,
 						state->pc - 2, &htok));
 		if (htok)
 		    singsub(&pat);
-		save = (state->prog->alloc != EA_HEAP &&
+		save = (!(state->prog->flags & EF_HEAP) &&
 			!strcmp(pat, opat) && *spprog != dummy_patprog2);
 	    }
 	    if (!(pprog = patcompile(pat, (save ? PAT_ZDUP : PAT_STATIC),
@@ -567,13 +602,14 @@ execcase(Estate state, int do_exec)
 		state->pc = next;
 		code = *state->pc;
 		state->pc += 3;
-		next = state->pc + WC_CASE_SKIP(code) - 1;
+		next = state->pc + WC_CASE_SKIP(code) - 2;
 		execlist(state, 1, ((WC_CASE_TYPE(code) == WC_CASE_OR) &&
 				    do_exec));
 	    }
-	    break;
-	} else
-	    state->pc = next;
+	    if (WC_CASE_TYPE(code) != WC_CASE_TESTAND)
+		break;
+	}
+	state->pc = next;
     }
     cmdpop();
 
@@ -581,3 +617,68 @@ execcase(Estate state, int do_exec)
 
     return lastval;
 }
+
+/*
+ * Errflag from `try' block, may be reset in `always' block.
+ * Accessible from an integer parameter, so needs to be a zlong.
+ */
+
+/**/
+zlong
+try_errflag = -1;
+
+/**/
+int
+exectry(Estate state, int do_exec)
+{
+    Wordcode end, always;
+    int endval;
+    int save_retflag, save_breaks, save_loops, save_contflag;
+    zlong save_try_errflag;
+
+    end = state->pc + WC_TRY_SKIP(state->pc[-1]);
+    always = state->pc + 1 + WC_TRY_SKIP(*state->pc);
+    state->pc++;
+    pushheap();
+    cmdpush(CS_CURSH);
+
+    /* The :try clause */
+    execlist(state, 1, do_exec);
+
+    /* Don't record errflag here, may be reset. */
+    endval = lastval;
+
+    freeheap();
+
+    cmdpop();
+    cmdpush(CS_ALWAYS);
+
+    /* The always clause. */
+    save_try_errflag = try_errflag;
+    try_errflag = (zlong)errflag;
+    errflag = 0;
+    save_retflag = retflag;
+    retflag = 0;
+    save_breaks = breaks;
+    breaks = 0;
+    save_loops = loops;
+    loops = 0;
+    save_contflag = contflag;
+    contflag = 0;
+
+    state->pc = always;
+    execlist(state, 1, do_exec);
+
+    errflag = try_errflag ? 1 : 0;
+    try_errflag = save_try_errflag;
+    retflag = save_retflag;
+    breaks = save_breaks;
+    loops = save_loops;
+    contflag = save_contflag;
+
+    cmdpop();
+    popheap();
+    state->pc = end;
+
+    return endval;
+}
diff --git a/Src/parse.c b/Src/parse.c
index edcca82da..f53c216d8 100644
--- a/Src/parse.c
+++ b/Src/parse.c
@@ -167,9 +167,9 @@ struct heredocs *hdocs;
  *
  *   WC_CASE
  *     - first CASE is always of type HEAD, data contains offset to esac
- *     - after that CASEs of type OR (;;) and AND (;&), data is offset to
- *       next case
- *     - each OR/AND case is followed by pattern, pattern-number, list
+ *     - after that CASEs of type OR (;;), AND (;&) and TESTAND (;|),
+ *       data is offset to next case
+ *     - each OR/AND/TESTAND case is followed by pattern, pattern-number, list
  *
  *   WC_IF
  *     - first IF is of type HEAD, data contains offset to fi
@@ -1012,7 +1012,7 @@ par_for(int *complex)
 /*
  * case	: CASE STRING { SEPER } ( "in" | INBRACE )
 				{ { SEPER } STRING { BAR STRING } OUTPAR
-					list [ DSEMI | SEMIAMP ] }
+					list [ DSEMI | SEMIAMP | SEMIBAR ] }
 				{ SEPER } ( "esac" | OUTBRACE )
  */
 
@@ -1139,10 +1139,12 @@ par_case(int *complex)
 	n++;
 	if (tok == SEMIAMP)
 	    type = WC_CASE_AND;
+	else if (tok == SEMIBAR)
+	    type = WC_CASE_TESTAND;
 	ecbuf[pp] = WCB_CASE(type, ecused - 1 - pp);
 	if ((tok == ESAC && !brflag) || (tok == OUTBRACE && brflag))
 	    break;
-	if (tok != DSEMI && tok != SEMIAMP)
+	if (tok != DSEMI && tok != SEMIAMP && tok != SEMIBAR)
 	    YYERRORV(oecused);
 	incasepat = 1;
 	incmdpos = 0;
diff --git a/Src/text.c b/Src/text.c
index 0aca8371a..55e03c579 100644
--- a/Src/text.c
+++ b/Src/text.c
@@ -537,7 +537,19 @@ gettext2(Estate state)
 		}
 	    } else if (state->pc < s->u._case.end) {
 		tindent--;
-		taddstr(WC_CASE_TYPE(code) == WC_CASE_OR ? " ;;" : ";&");
+		switch (WC_CASE_TYPE(code)) {
+		case WC_CASE_OR:
+		    taddstr(" ;;");
+		    break;
+
+		case WC_CASE_AND:
+		    taddstr(";&");
+		    break;
+
+		default:
+		    taddstr(";|");
+		    break;
+		}
 		if (tnewlins)
 		    taddnl();
 		else
@@ -553,7 +565,19 @@ gettext2(Estate state)
 			  s->u._case.end);
 	    } else {
 		tindent--;
-		taddstr(WC_CASE_TYPE(code) == WC_CASE_OR ? " ;;" : ";&");
+		switch (WC_CASE_TYPE(code)) {
+		case WC_CASE_OR:
+		    taddstr(" ;;");
+		    break;
+
+		case WC_CASE_AND:
+		    taddstr(";&");
+		    break;
+
+		default:
+		    taddstr(";|");
+		    break;
+		}
 		tindent--;
 		if (tnewlins)
 		    taddnl();
diff --git a/Src/zsh.h b/Src/zsh.h
index f4646fb93..9a45fee38 100644
--- a/Src/zsh.h
+++ b/Src/zsh.h
@@ -217,37 +217,38 @@ enum {
     DOUTPAR,
     AMPERBANG,		/* 30 */
     SEMIAMP,
+    SEMIBAR,
     DOUTBRACK,
     STRING,
-    ENVSTRING,
-    ENVARRAY,		/* 35 */
+    ENVSTRING,		/* 35 */
+    ENVARRAY,
     ENDINPUT,
     LEXERR,
 
     /* Tokens for reserved words */
     BANG,	/* !         */
-    DINBRACK,	/* [[        */
-    INBRACE,    /* {         */	/* 40 */
+    DINBRACK,	/* [[        */	/* 40 */
+    INBRACE,    /* {         */
     OUTBRACE,   /* }         */
     CASE,	/* case      */
     COPROC,	/* coproc    */
-    DOLOOP,	/* do        */
-    DONE,	/* done      */ /* 45 */
+    DOLOOP,	/* do        */ /* 45 */
+    DONE,	/* done      */
     ELIF,	/* elif      */
     ELSE,	/* else      */
     ZEND,	/* end       */
-    ESAC,	/* esac      */
-    FI,		/* fi        */ /* 50 */
+    ESAC,	/* esac      */ /* 50 */
+    FI,		/* fi        */
     FOR,	/* for       */
     FOREACH,	/* foreach   */
     FUNC,	/* function  */
-    IF,		/* if        */
-    NOCORRECT,	/* nocorrect */ /* 55 */
+    IF,		/* if        */ /* 55 */
+    NOCORRECT,	/* nocorrect */
     REPEAT,	/* repeat    */
     SELECT,	/* select    */
     THEN,	/* then      */
-    TIME,	/* time      */
-    UNTIL,	/* until     */ /* 60 */
+    TIME,	/* time      */ /* 60 */
+    UNTIL,	/* until     */
     WHILE	/* while     */
 };
 
@@ -712,12 +713,14 @@ struct eccstr {
 #define WC_TRY_SKIP(C)	    wc_data(C)
 #define WCB_TRY(O)	    wc_bld(WC_TRY, (O))
 
-#define WC_CASE_TYPE(C)     (wc_data(C) & 3)
+#define WC_CASE_TYPE(C)     (wc_data(C) & 7)
 #define WC_CASE_HEAD        0
 #define WC_CASE_OR          1
 #define WC_CASE_AND         2
-#define WC_CASE_SKIP(C)     (wc_data(C) >> 2)
-#define WCB_CASE(T,O)       wc_bld(WC_CASE, ((T) | ((O) << 2)))
+#define WC_CASE_TESTAND     3
+#define WC_CASE_FREE	    (3) /* Next bit available in integer */
+#define WC_CASE_SKIP(C)     (wc_data(C) >> WC_CASE_FREE)
+#define WCB_CASE(T,O)       wc_bld(WC_CASE, ((T) | ((O) << WC_CASE_FREE)))
 
 #define WC_IF_TYPE(C)       (wc_data(C) & 3)
 #define WC_IF_HEAD          0