1
0
Fork 0
mirror of git://git.code.sf.net/p/zsh/code synced 2025-09-26 05:51:08 +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>
* unposted: Doc/Zsh/calsys.yo: typo with parentheses.

View file

@ -199,14 +199,23 @@ var(list) is then executed var(n) times.
findex(case)
cindex(case selection)
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)
that matches var(word), if any. The form of the patterns
is the same as that used for filename generation. See
noderef(Filename Generation).
If the var(list) that is executed is terminated with tt(;&) rather than
tt(;;), the following list is also executed. This continues until either
a list is terminated with tt(;;) or the tt(esac) is reached.
tt(;;), the following list is also executed. The rule for
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)
cindex(user selection)
@ -390,7 +399,7 @@ var(list) mentioned above.
item(tt(repeat) var(word) var(sublist))(
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).
)
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 */
"&|", /* AMPERBANG 30 */
";&", /* SEMIAMP */
";|", /* SEMIBAR */
};
/* lexical state */
@ -381,6 +382,7 @@ ctxtlex(void)
case SEMI:
case DSEMI:
case SEMIAMP:
case SEMIBAR:
case AMPER:
case AMPERBANG:
case INPAR:
@ -713,6 +715,8 @@ gettok(void)
return DSEMI;
else if(d == '&')
return SEMIAMP;
else if (d == '|')
return SEMIBAR;
hungetc(d);
lexstop = 0;
return SEMI;

View file

@ -606,9 +606,10 @@ execcase(Estate state, int do_exec)
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();

View file

@ -169,9 +169,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
@ -1014,7 +1014,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 )
*/
@ -1141,10 +1141,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;

View file

@ -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();

View file

@ -246,37 +246,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 */
};
@ -783,12 +784,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

View file

@ -413,6 +413,29 @@
0:`case' with braces
>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
name=0
# The number 4375 here is chosen to produce more than 16384 bytes of output