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:
parent
a5729be835
commit
de272e0309
8 changed files with 101 additions and 29 deletions
|
@ -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.
|
||||||
|
|
|
@ -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))(
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
|
|
12
Src/parse.c
12
Src/parse.c
|
@ -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;
|
||||||
|
|
28
Src/text.c
28
Src/text.c
|
@ -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();
|
||||||
|
|
33
Src/zsh.h
33
Src/zsh.h
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue