From d2241f59022c38d4b171e56eea42e216ecccfdd9 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sat, 31 Oct 2020 03:34:07 +0100 Subject: shell: better support of [[ ]] bashism Still rather rudimentary for ash function old new delta binop 433 589 +156 check_operator 65 101 +36 done_word 736 769 +33 test_main 405 418 +13 parse_stream 2227 2238 +11 ops_texts 124 133 +9 ops_table 80 86 +6 run_pipe 1557 1562 +5 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 8/0 up/down: 269/0) Total: 269 bytes Signed-off-by: Denys Vlasenko --- shell/hush.c | 57 ++++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 40 insertions(+), 17 deletions(-) (limited to 'shell/hush.c') diff --git a/shell/hush.c b/shell/hush.c index bc6e6014f..7c1e1d748 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -84,13 +84,12 @@ * [[ args ]] are CMD_SINGLEWORD_NOGLOB: * v='a b'; [[ $v = 'a b' ]]; echo 0:$? * [[ /bin/n* ]]; echo 0:$? + * = is glob match operator, not equality operator: STR = GLOB + * (in GLOB, quoting is significant on char-by-char basis: a*cd"*") + * == same as = + * =~ is regex match operator: STR =~ REGEX * TODO: - * &&/|| are AND/OR ops, -a/-o are not * quoting needs to be considered (-f is an operator, "-f" and ""-f are not; etc) - * = is glob match operator, not equality operator: STR = GLOB - * (in GLOB, quoting is significant on char-by-char basis: a*cd"*") - * == same as = - * add =~ regex match operator: STR =~ REGEX */ //config:config HUSH //config: bool "hush (68 kb)" @@ -651,14 +650,16 @@ struct command { smallint cmd_type; /* CMD_xxx */ #define CMD_NORMAL 0 #define CMD_SUBSHELL 1 -#if BASH_TEST2 || ENABLE_HUSH_LOCAL || ENABLE_HUSH_EXPORT || ENABLE_HUSH_READONLY -/* used for "[[ EXPR ]]", and to prevent word splitting and globbing in - * "export v=t*" - */ -# define CMD_SINGLEWORD_NOGLOB 2 +#if BASH_TEST2 +/* used for "[[ EXPR ]]" */ +# define CMD_TEST2_SINGLEWORD_NOGLOB 2 +#endif +#if ENABLE_HUSH_LOCAL || ENABLE_HUSH_EXPORT || ENABLE_HUSH_READONLY +/* used to prevent word splitting and globbing in "export v=t*" */ +# define CMD_SINGLEWORD_NOGLOB 3 #endif #if ENABLE_HUSH_FUNCTIONS -# define CMD_FUNCDEF 3 +# define CMD_FUNCDEF 4 #endif smalluint cmd_exitcode; @@ -4111,6 +4112,14 @@ static int done_word(struct parse_context *ctx) /* ctx->ctx_res_w = RES_MATCH; */ ctx->ctx_dsemicolon = 0; } else +# endif +# if defined(CMD_TEST2_SINGLEWORD_NOGLOB) + if (command->cmd_type == CMD_TEST2_SINGLEWORD_NOGLOB + && strcmp(ctx->word.data, "]]") == 0 + ) { + /* allow "[[ ]] >file" etc */ + command->cmd_type = CMD_SINGLEWORD_NOGLOB; + } else # endif if (!command->argv /* if it's the first word... */ # if ENABLE_HUSH_LOOPS @@ -4146,11 +4155,13 @@ static int done_word(struct parse_context *ctx) (ctx->ctx_res_w == RES_SNTX)); return (ctx->ctx_res_w == RES_SNTX); } +# if defined(CMD_TEST2_SINGLEWORD_NOGLOB) + if (strcmp(ctx->word.data, "[[") == 0) { + command->cmd_type = CMD_TEST2_SINGLEWORD_NOGLOB; + } else +# endif # if defined(CMD_SINGLEWORD_NOGLOB) if (0 -# if BASH_TEST2 - || strcmp(ctx->word.data, "[[") == 0 -# endif /* In bash, local/export/readonly are special, args * are assignments and therefore expansion of them * should be "one-word" expansion: @@ -4172,7 +4183,8 @@ static int done_word(struct parse_context *ctx) ) { command->cmd_type = CMD_SINGLEWORD_NOGLOB; } - /* fall through */ +# else + { /* empty block to pair "if ... else" */ } # endif } #endif /* HAS_KEYWORDS */ @@ -5354,9 +5366,15 @@ static struct pipe *parse_stream(char **pstring, if (ch != '\n') next = i_peek_and_eat_bkslash_nl(input); - is_special = "{}<>;&|()#" /* special outside of "str" */ + is_special = "{}<>&|();#" /* special outside of "str" */ "$\"" IF_HUSH_TICK("`") /* always special */ SPECIAL_VAR_SYMBOL_STR; +#if defined(CMD_TEST2_SINGLEWORD_NOGLOB) + if (ctx.command->cmd_type == CMD_TEST2_SINGLEWORD_NOGLOB) { + /* In [[ ]], {}<>&|() are not special */ + is_special += 8; + } else +#endif /* Are { and } special here? */ if (ctx.command->argv /* word [word]{... - non-special */ || ctx.word.length /* word{... - non-special */ @@ -6953,7 +6971,7 @@ static char **expand_strvec_to_strvec(char **argv) return expand_variables(argv, EXP_FLAG_GLOB | EXP_FLAG_ESC_GLOB_CHARS); } -#if defined(CMD_SINGLEWORD_NOGLOB) +#if defined(CMD_SINGLEWORD_NOGLOB) || defined(CMD_TEST2_SINGLEWORD_NOGLOB) static char **expand_strvec_to_strvec_singleword_noglob(char **argv) { return expand_variables(argv, EXP_FLAG_SINGLEWORD); @@ -9133,6 +9151,11 @@ static NOINLINE int run_pipe(struct pipe *pi) } /* Expand the rest into (possibly) many strings each */ +#if defined(CMD_TEST2_SINGLEWORD_NOGLOB) + if (command->cmd_type == CMD_TEST2_SINGLEWORD_NOGLOB) + argv_expanded = expand_strvec_to_strvec_singleword_noglob(argv + command->assignment_cnt); + else +#endif #if defined(CMD_SINGLEWORD_NOGLOB) if (command->cmd_type == CMD_SINGLEWORD_NOGLOB) argv_expanded = expand_strvec_to_strvec_singleword_noglob(argv + command->assignment_cnt); -- cgit v1.2.3