1
0
Fork 0
mirror of git://git.code.sf.net/p/zsh/code synced 2025-09-30 07:10:58 +02:00

23115: ";|" at end of case clause causes later patterns to be tested

This commit is contained in:
Peter Stephenson 2007-01-19 21:36:00 +00:00
parent a5729be835
commit de272e0309
8 changed files with 101 additions and 29 deletions

View file

@ -1,3 +1,9 @@
2007-01-19 Peter Stephenson <p.w.stephenson@ntlworld.com>
* 23115: Doc/Zsh/grammar.yo, Src/lex.c, Src/loop.c, Src/parse.c,
Src/text.c, Src/zsh.h, Test/A01grammar.ztst: add ";|"
at end of case statement to cause testing of later patterns.
2007-01-18 Peter Stephenson <pws@csr.com> 2007-01-18 Peter Stephenson <pws@csr.com>
* unposted: Doc/Zsh/calsys.yo: typo with parentheses. * unposted: Doc/Zsh/calsys.yo: typo with parentheses.

View file

@ -199,14 +199,23 @@ var(list) is then executed var(n) times.
findex(case) findex(case)
cindex(case selection) cindex(case selection)
cindex(selection, case) cindex(selection, case)
item(tt(case) var(word) tt(in) [ [tt(LPAR())] var(pattern) [ tt(|) var(pattern) ] ... tt(RPAR()) var(list) (tt(;;)|tt(;&)) ] ... tt(esac))( item(tt(case) var(word) tt(in) [ [tt(LPAR())] var(pattern) [ tt(|) var(pattern) ] ... tt(RPAR()) var(list) (tt(;;)|tt(;&)|tt(;|)) ] ... tt(esac))(
Execute the var(list) associated with the first var(pattern) Execute the var(list) associated with the first var(pattern)
that matches var(word), if any. The form of the patterns that matches var(word), if any. The form of the patterns
is the same as that used for filename generation. See is the same as that used for filename generation. See
noderef(Filename Generation). noderef(Filename Generation).
If the var(list) that is executed is terminated with tt(;&) rather than If the var(list) that is executed is terminated with tt(;&) rather than
tt(;;), the following list is also executed. This continues until either tt(;;), the following list is also executed. The rule for
a list is terminated with tt(;;) or the tt(esac) is reached. the terminator of the following list tt(;;), tt(;&) or tt(;|) is
applied unless the tt(esac) is reached.
If the var(list) that is executed is terminated with tt(;|) the
shell continues to scan the var(pattern)s looking for the next match,
executing the corresponding var(list), and applying the rule for
the corresponding terminator tt(;;), tt(;&) or tt(;|).
Note that var(word) is not re-expanded; all applicable var(pattern)s
are tested with the same var(word).
) )
findex(select) findex(select)
cindex(user selection) cindex(user selection)
@ -390,7 +399,7 @@ var(list) mentioned above.
item(tt(repeat) var(word) var(sublist))( item(tt(repeat) var(word) var(sublist))(
This is a short form of tt(repeat). This is a short form of tt(repeat).
) )
item(tt(case) var(word) tt({) [ [tt(LPAR())] var(pattern) [ tt(|) var(pattern) ] ... tt(RPAR()) var(list) (tt(;;)|tt(;&)) ] ... tt(}))( item(tt(case) var(word) tt({) [ [tt(LPAR())] var(pattern) [ tt(|) var(pattern) ] ... tt(RPAR()) var(list) (tt(;;)|tt(;&)|tt(;|)) ] ... tt(}))(
An alternative form of tt(case). An alternative form of tt(case).
) )
item(tt(select) var(name) [ tt(in) var(word) var(term) ] var(sublist))( item(tt(select) var(name) [ tt(in) var(word) var(term) ] var(sublist))(

View file

@ -155,6 +155,7 @@ mod_export char *tokstrings[WHILE + 1] = {
"))", /* DOUTPAR */ "))", /* DOUTPAR */
"&|", /* AMPERBANG 30 */ "&|", /* AMPERBANG 30 */
";&", /* SEMIAMP */ ";&", /* SEMIAMP */
";|", /* SEMIBAR */
}; };
/* lexical state */ /* lexical state */
@ -381,6 +382,7 @@ ctxtlex(void)
case SEMI: case SEMI:
case DSEMI: case DSEMI:
case SEMIAMP: case SEMIAMP:
case SEMIBAR:
case AMPER: case AMPER:
case AMPERBANG: case AMPERBANG:
case INPAR: case INPAR:
@ -713,6 +715,8 @@ gettok(void)
return DSEMI; return DSEMI;
else if(d == '&') else if(d == '&')
return SEMIAMP; return SEMIAMP;
else if (d == '|')
return SEMIBAR;
hungetc(d); hungetc(d);
lexstop = 0; lexstop = 0;
return SEMI; return SEMI;

View file

@ -606,9 +606,10 @@ execcase(Estate state, int do_exec)
execlist(state, 1, ((WC_CASE_TYPE(code) == WC_CASE_OR) && execlist(state, 1, ((WC_CASE_TYPE(code) == WC_CASE_OR) &&
do_exec)); do_exec));
} }
break; if (WC_CASE_TYPE(code) != WC_CASE_TESTAND)
} else break;
state->pc = next; }
state->pc = next;
} }
cmdpop(); cmdpop();

View file

@ -169,9 +169,9 @@ struct heredocs *hdocs;
* *
* WC_CASE * WC_CASE
* - first CASE is always of type HEAD, data contains offset to esac * - first CASE is always of type HEAD, data contains offset to esac
* - after that CASEs of type OR (;;) and AND (;&), data is offset to * - after that CASEs of type OR (;;), AND (;&) and TESTAND (;|),
* next case * data is offset to next case
* - each OR/AND case is followed by pattern, pattern-number, list * - each OR/AND/TESTAND case is followed by pattern, pattern-number, list
* *
* WC_IF * WC_IF
* - first IF is of type HEAD, data contains offset to fi * - first IF is of type HEAD, data contains offset to fi
@ -1014,7 +1014,7 @@ par_for(int *complex)
/* /*
* case : CASE STRING { SEPER } ( "in" | INBRACE ) * case : CASE STRING { SEPER } ( "in" | INBRACE )
{ { SEPER } STRING { BAR STRING } OUTPAR { { SEPER } STRING { BAR STRING } OUTPAR
list [ DSEMI | SEMIAMP ] } list [ DSEMI | SEMIAMP | SEMIBAR ] }
{ SEPER } ( "esac" | OUTBRACE ) { SEPER } ( "esac" | OUTBRACE )
*/ */
@ -1141,10 +1141,12 @@ par_case(int *complex)
n++; n++;
if (tok == SEMIAMP) if (tok == SEMIAMP)
type = WC_CASE_AND; type = WC_CASE_AND;
else if (tok == SEMIBAR)
type = WC_CASE_TESTAND;
ecbuf[pp] = WCB_CASE(type, ecused - 1 - pp); ecbuf[pp] = WCB_CASE(type, ecused - 1 - pp);
if ((tok == ESAC && !brflag) || (tok == OUTBRACE && brflag)) if ((tok == ESAC && !brflag) || (tok == OUTBRACE && brflag))
break; break;
if (tok != DSEMI && tok != SEMIAMP) if (tok != DSEMI && tok != SEMIAMP && tok != SEMIBAR)
YYERRORV(oecused); YYERRORV(oecused);
incasepat = 1; incasepat = 1;
incmdpos = 0; incmdpos = 0;

View file

@ -537,7 +537,19 @@ gettext2(Estate state)
} }
} else if (state->pc < s->u._case.end) { } else if (state->pc < s->u._case.end) {
tindent--; 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) if (tnewlins)
taddnl(); taddnl();
else else
@ -553,7 +565,19 @@ gettext2(Estate state)
s->u._case.end); s->u._case.end);
} else { } else {
tindent--; 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--; tindent--;
if (tnewlins) if (tnewlins)
taddnl(); taddnl();

View file

@ -246,37 +246,38 @@ enum {
DOUTPAR, DOUTPAR,
AMPERBANG, /* 30 */ AMPERBANG, /* 30 */
SEMIAMP, SEMIAMP,
SEMIBAR,
DOUTBRACK, DOUTBRACK,
STRING, STRING,
ENVSTRING, ENVSTRING, /* 35 */
ENVARRAY, /* 35 */ ENVARRAY,
ENDINPUT, ENDINPUT,
LEXERR, LEXERR,
/* Tokens for reserved words */ /* Tokens for reserved words */
BANG, /* ! */ BANG, /* ! */
DINBRACK, /* [[ */ DINBRACK, /* [[ */ /* 40 */
INBRACE, /* { */ /* 40 */ INBRACE, /* { */
OUTBRACE, /* } */ OUTBRACE, /* } */
CASE, /* case */ CASE, /* case */
COPROC, /* coproc */ COPROC, /* coproc */
DOLOOP, /* do */ DOLOOP, /* do */ /* 45 */
DONE, /* done */ /* 45 */ DONE, /* done */
ELIF, /* elif */ ELIF, /* elif */
ELSE, /* else */ ELSE, /* else */
ZEND, /* end */ ZEND, /* end */
ESAC, /* esac */ ESAC, /* esac */ /* 50 */
FI, /* fi */ /* 50 */ FI, /* fi */
FOR, /* for */ FOR, /* for */
FOREACH, /* foreach */ FOREACH, /* foreach */
FUNC, /* function */ FUNC, /* function */
IF, /* if */ IF, /* if */ /* 55 */
NOCORRECT, /* nocorrect */ /* 55 */ NOCORRECT, /* nocorrect */
REPEAT, /* repeat */ REPEAT, /* repeat */
SELECT, /* select */ SELECT, /* select */
THEN, /* then */ THEN, /* then */
TIME, /* time */ TIME, /* time */ /* 60 */
UNTIL, /* until */ /* 60 */ UNTIL, /* until */
WHILE /* while */ WHILE /* while */
}; };
@ -783,12 +784,14 @@ struct eccstr {
#define WC_TRY_SKIP(C) wc_data(C) #define WC_TRY_SKIP(C) wc_data(C)
#define WCB_TRY(O) wc_bld(WC_TRY, (O)) #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_HEAD 0
#define WC_CASE_OR 1 #define WC_CASE_OR 1
#define WC_CASE_AND 2 #define WC_CASE_AND 2
#define WC_CASE_SKIP(C) (wc_data(C) >> 2) #define WC_CASE_TESTAND 3
#define WCB_CASE(T,O) wc_bld(WC_CASE, ((T) | ((O) << 2))) #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_TYPE(C) (wc_data(C) & 3)
#define WC_IF_HEAD 0 #define WC_IF_HEAD 0

View file

@ -413,6 +413,29 @@
0:`case' with braces 0:`case' with braces
>schmavo >schmavo
for word in artichoke bladderwort chrysanthemum Zanzibar
case $word in
(*der*) print $word contains the forbidden incantation der
;;
(a*) print $word begins with a
;&
([[:upper:]]*) print $word either begins with a or an upper case letter
;|
([[:lower:]]*) print $word begins with a lower case letter
;|
(*e*) print $word contains an e
;;
esac
0:`case' with mixed ;& and ;|
>artichoke begins with a
>artichoke either begins with a or an upper case letter
>artichoke begins with a lower case letter
>artichoke contains an e
>bladderwort contains the forbidden incantation der
>chrysanthemum begins with a lower case letter
>chrysanthemum contains an e
>Zanzibar either begins with a or an upper case letter
print 'This test hangs the shell when it fails...' >&8 print 'This test hangs the shell when it fails...' >&8
name=0 name=0
# The number 4375 here is chosen to produce more than 16384 bytes of output # The number 4375 here is chosen to produce more than 16384 bytes of output