mirror of
https://github.com/sheumann/hush.git
synced 2024-12-22 14:30:31 +00:00
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:
parent
342a63d659
commit
e9bda90e54
35
shell/hush.c
35
shell/hush.c
@ -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;
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
0
|
0
|
||||||
unset: invalid option -- 'm'
|
unset: invalid option -- m
|
||||||
1
|
1
|
||||||
0
|
0
|
||||||
___
|
___
|
||||||
|
Loading…
Reference in New Issue
Block a user