hush: fix problems with case in subshells and with "case esac"

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
Denys Vlasenko 2009-05-23 16:50:07 +02:00
parent 342a63d659
commit e9bda90e54
4 changed files with 42 additions and 18 deletions

View File

@ -192,9 +192,10 @@ typedef enum reserved_style {
#endif #endif
#if ENABLE_HUSH_CASE #if ENABLE_HUSH_CASE
RES_CASE , RES_CASE ,
/* two pseudo-keywords support contrived "case" syntax: */ /* three pseudo-keywords support contrived "case" syntax: */
RES_MATCH , /* "word)" */ RES_CASE_IN, /* "case ... IN", turns into RES_MATCH when IN is observed */
RES_CASEI , /* "this command is inside CASE" */ RES_MATCH , /* "word)" */
RES_CASE_BODY, /* "this command is inside CASE" */
RES_ESAC , RES_ESAC ,
#endif #endif
RES_XXXX , RES_XXXX ,
@ -3766,8 +3767,9 @@ static void debug_print_tree(struct pipe *pi, int lvl)
#endif #endif
#if ENABLE_HUSH_CASE #if ENABLE_HUSH_CASE
[RES_CASE ] = "CASE" , [RES_CASE ] = "CASE" ,
[RES_CASE_IN ] = "CASE_IN" ,
[RES_MATCH] = "MATCH", [RES_MATCH] = "MATCH",
[RES_CASEI] = "CASEI", [RES_CASE_BODY] = "CASE_BODY",
[RES_ESAC ] = "ESAC" , [RES_ESAC ] = "ESAC" ,
#endif #endif
[RES_XXXX ] = "XXXX" , [RES_XXXX ] = "XXXX" ,
@ -4011,7 +4013,7 @@ static int run_list(struct pipe *pi)
} }
continue; continue;
} }
if (rword == RES_CASEI) { /* inside of a case branch */ if (rword == RES_CASE_BODY) { /* inside of a case branch */
if (cond_code != 0) if (cond_code != 0)
continue; /* not matched yet, skip this pipe */ continue; /* not matched yet, skip this pipe */
} }
@ -4252,7 +4254,9 @@ static void done_pipe(struct parse_context *ctx, pipe_style type)
#endif #endif
#if ENABLE_HUSH_CASE #if ENABLE_HUSH_CASE
if (ctx->ctx_res_w == RES_MATCH) if (ctx->ctx_res_w == RES_MATCH)
ctx->ctx_res_w = RES_CASEI; ctx->ctx_res_w = RES_CASE_BODY;
if (ctx->ctx_res_w == RES_CASE)
ctx->ctx_res_w = RES_CASE_IN;
#endif #endif
ctx->command = NULL; /* trick done_command below */ ctx->command = NULL; /* trick done_command below */
/* Create the memory for command, roughly: /* Create the memory for command, roughly:
@ -4366,10 +4370,10 @@ static int reserved_word(o_string *word, struct parse_context *ctx)
debug_printf("found reserved word %s, res %d\n", r->literal, r->res); debug_printf("found reserved word %s, res %d\n", r->literal, r->res);
#if ENABLE_HUSH_CASE #if ENABLE_HUSH_CASE
if (r->res == RES_IN && ctx->ctx_res_w == RES_CASE) if (r->res == RES_IN && ctx->ctx_res_w == RES_CASE_IN) {
/* "case word IN ..." - IN part starts first match part */ /* "case word IN ..." - IN part starts first MATCH part */
r = &reserved_match; r = &reserved_match;
else } else
#endif #endif
if (r->flag == 0) { /* '!' */ if (r->flag == 0) { /* '!' */
if (ctx->ctx_inverted) { /* bash doesn't accept '! ! true' */ if (ctx->ctx_inverted) { /* bash doesn't accept '! ! true' */
@ -4494,6 +4498,9 @@ static int done_word(o_string *word, struct parse_context *ctx)
# if ENABLE_HUSH_LOOPS # if ENABLE_HUSH_LOOPS
&& ctx->ctx_res_w != RES_FOR /* ...not after FOR or IN */ && ctx->ctx_res_w != RES_FOR /* ...not after FOR or IN */
&& ctx->ctx_res_w != RES_IN && ctx->ctx_res_w != RES_IN
# endif
# if ENABLE_HUSH_CASE
&& ctx->ctx_res_w != RES_CASE
# endif # endif
) { ) {
debug_printf_parse("checking '%s' for reserved-ness\n", word->data); debug_printf_parse("checking '%s' for reserved-ness\n", word->data);
@ -5578,7 +5585,13 @@ static struct pipe *parse_stream(char **pstring,
} }
if (end_trigger && end_trigger == ch if (end_trigger && end_trigger == ch
&& (heredoc_cnt == 0 || end_trigger != ';') && (ch != ';' || heredoc_cnt == 0)
#if ENABLE_HUSH_CASE
&& (ch != ')'
|| ctx.ctx_res_w != RES_MATCH
|| (!dest.o_quoted && strcmp(dest.data, "esac") == 0)
)
#endif
) { ) {
if (heredoc_cnt) { if (heredoc_cnt) {
/* This is technically valid: /* This is technically valid:
@ -5784,7 +5797,7 @@ static struct pipe *parse_stream(char **pstring,
break; break;
ch = i_getch(input); ch = i_getch(input);
nommu_addchr(&ctx.as_string, ch); nommu_addchr(&ctx.as_string, ch);
if (ctx.ctx_res_w == RES_CASEI) { if (ctx.ctx_res_w == RES_CASE_BODY) {
ctx.ctx_dsemicolon = 1; ctx.ctx_dsemicolon = 1;
ctx.ctx_res_w = RES_MATCH; ctx.ctx_res_w = RES_MATCH;
break; break;

View File

@ -12,3 +12,11 @@ OK_44
OK_51 OK_51
OK_52 OK_52
OK_53 OK_53
OK_sub1
OK_sub2
OK_sub3
OK_sub4
OK_sub5
OK_sub6
OK_esac1
Done

View File

@ -25,13 +25,16 @@ case w in `echo w`) echo OK_51;; `echo WRONG >&2`w) echo WRONG;; esac;
case w in `echo OK_52 >&2`) echo SKIP;; `echo`w) echo OK_53;; esac; case w in `echo OK_52 >&2`) echo SKIP;; `echo`w) echo OK_53;; esac;
# parsing cases in subshells can easily get messy # parsing cases in subshells can easily get messy
case m in m) echo ok-sub1;; esac case m in m) echo OK_sub1;; esac
case m in (m) echo ok-sub2;; esac case m in (m) echo OK_sub2;; esac
(case m in m) echo ok-sub3;; esac) (case m in m) echo OK_sub3;; esac)
(case m in (m) echo ok-sub4;; esac) (case m in (m) echo OK_sub4;; esac)
( (
case m in m) echo ok-sub5;; esac case m in m) echo OK_sub5;; esac
) )
( (
case m in (m) echo ok-sub6;; esac case m in (m) echo OK_sub6;; esac
) )
(case esac in "esac") echo OK_esac1;; esac)
echo Done

View File

@ -1,5 +1,5 @@
0 0
unset: invalid option -- 'm' unset: invalid option -- m
1 1
0 0
___ ___