diff options
Diffstat (limited to 'shell/hush.c')
-rw-r--r-- | shell/hush.c | 57 |
1 files changed, 40 insertions, 17 deletions
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 @@ | |||
84 | * [[ args ]] are CMD_SINGLEWORD_NOGLOB: | 84 | * [[ args ]] are CMD_SINGLEWORD_NOGLOB: |
85 | * v='a b'; [[ $v = 'a b' ]]; echo 0:$? | 85 | * v='a b'; [[ $v = 'a b' ]]; echo 0:$? |
86 | * [[ /bin/n* ]]; echo 0:$? | 86 | * [[ /bin/n* ]]; echo 0:$? |
87 | * = is glob match operator, not equality operator: STR = GLOB | ||
88 | * (in GLOB, quoting is significant on char-by-char basis: a*cd"*") | ||
89 | * == same as = | ||
90 | * =~ is regex match operator: STR =~ REGEX | ||
87 | * TODO: | 91 | * TODO: |
88 | * &&/|| are AND/OR ops, -a/-o are not | ||
89 | * quoting needs to be considered (-f is an operator, "-f" and ""-f are not; etc) | 92 | * quoting needs to be considered (-f is an operator, "-f" and ""-f are not; etc) |
90 | * = is glob match operator, not equality operator: STR = GLOB | ||
91 | * (in GLOB, quoting is significant on char-by-char basis: a*cd"*") | ||
92 | * == same as = | ||
93 | * add =~ regex match operator: STR =~ REGEX | ||
94 | */ | 93 | */ |
95 | //config:config HUSH | 94 | //config:config HUSH |
96 | //config: bool "hush (68 kb)" | 95 | //config: bool "hush (68 kb)" |
@@ -651,14 +650,16 @@ struct command { | |||
651 | smallint cmd_type; /* CMD_xxx */ | 650 | smallint cmd_type; /* CMD_xxx */ |
652 | #define CMD_NORMAL 0 | 651 | #define CMD_NORMAL 0 |
653 | #define CMD_SUBSHELL 1 | 652 | #define CMD_SUBSHELL 1 |
654 | #if BASH_TEST2 || ENABLE_HUSH_LOCAL || ENABLE_HUSH_EXPORT || ENABLE_HUSH_READONLY | 653 | #if BASH_TEST2 |
655 | /* used for "[[ EXPR ]]", and to prevent word splitting and globbing in | 654 | /* used for "[[ EXPR ]]" */ |
656 | * "export v=t*" | 655 | # define CMD_TEST2_SINGLEWORD_NOGLOB 2 |
657 | */ | 656 | #endif |
658 | # define CMD_SINGLEWORD_NOGLOB 2 | 657 | #if ENABLE_HUSH_LOCAL || ENABLE_HUSH_EXPORT || ENABLE_HUSH_READONLY |
658 | /* used to prevent word splitting and globbing in "export v=t*" */ | ||
659 | # define CMD_SINGLEWORD_NOGLOB 3 | ||
659 | #endif | 660 | #endif |
660 | #if ENABLE_HUSH_FUNCTIONS | 661 | #if ENABLE_HUSH_FUNCTIONS |
661 | # define CMD_FUNCDEF 3 | 662 | # define CMD_FUNCDEF 4 |
662 | #endif | 663 | #endif |
663 | 664 | ||
664 | smalluint cmd_exitcode; | 665 | smalluint cmd_exitcode; |
@@ -4112,6 +4113,14 @@ static int done_word(struct parse_context *ctx) | |||
4112 | ctx->ctx_dsemicolon = 0; | 4113 | ctx->ctx_dsemicolon = 0; |
4113 | } else | 4114 | } else |
4114 | # endif | 4115 | # endif |
4116 | # if defined(CMD_TEST2_SINGLEWORD_NOGLOB) | ||
4117 | if (command->cmd_type == CMD_TEST2_SINGLEWORD_NOGLOB | ||
4118 | && strcmp(ctx->word.data, "]]") == 0 | ||
4119 | ) { | ||
4120 | /* allow "[[ ]] >file" etc */ | ||
4121 | command->cmd_type = CMD_SINGLEWORD_NOGLOB; | ||
4122 | } else | ||
4123 | # endif | ||
4115 | if (!command->argv /* if it's the first word... */ | 4124 | if (!command->argv /* if it's the first word... */ |
4116 | # if ENABLE_HUSH_LOOPS | 4125 | # if ENABLE_HUSH_LOOPS |
4117 | && ctx->ctx_res_w != RES_FOR /* ...not after FOR or IN */ | 4126 | && ctx->ctx_res_w != RES_FOR /* ...not after FOR or IN */ |
@@ -4146,11 +4155,13 @@ static int done_word(struct parse_context *ctx) | |||
4146 | (ctx->ctx_res_w == RES_SNTX)); | 4155 | (ctx->ctx_res_w == RES_SNTX)); |
4147 | return (ctx->ctx_res_w == RES_SNTX); | 4156 | return (ctx->ctx_res_w == RES_SNTX); |
4148 | } | 4157 | } |
4158 | # if defined(CMD_TEST2_SINGLEWORD_NOGLOB) | ||
4159 | if (strcmp(ctx->word.data, "[[") == 0) { | ||
4160 | command->cmd_type = CMD_TEST2_SINGLEWORD_NOGLOB; | ||
4161 | } else | ||
4162 | # endif | ||
4149 | # if defined(CMD_SINGLEWORD_NOGLOB) | 4163 | # if defined(CMD_SINGLEWORD_NOGLOB) |
4150 | if (0 | 4164 | if (0 |
4151 | # if BASH_TEST2 | ||
4152 | || strcmp(ctx->word.data, "[[") == 0 | ||
4153 | # endif | ||
4154 | /* In bash, local/export/readonly are special, args | 4165 | /* In bash, local/export/readonly are special, args |
4155 | * are assignments and therefore expansion of them | 4166 | * are assignments and therefore expansion of them |
4156 | * should be "one-word" expansion: | 4167 | * should be "one-word" expansion: |
@@ -4172,7 +4183,8 @@ static int done_word(struct parse_context *ctx) | |||
4172 | ) { | 4183 | ) { |
4173 | command->cmd_type = CMD_SINGLEWORD_NOGLOB; | 4184 | command->cmd_type = CMD_SINGLEWORD_NOGLOB; |
4174 | } | 4185 | } |
4175 | /* fall through */ | 4186 | # else |
4187 | { /* empty block to pair "if ... else" */ } | ||
4176 | # endif | 4188 | # endif |
4177 | } | 4189 | } |
4178 | #endif /* HAS_KEYWORDS */ | 4190 | #endif /* HAS_KEYWORDS */ |
@@ -5354,9 +5366,15 @@ static struct pipe *parse_stream(char **pstring, | |||
5354 | if (ch != '\n') | 5366 | if (ch != '\n') |
5355 | next = i_peek_and_eat_bkslash_nl(input); | 5367 | next = i_peek_and_eat_bkslash_nl(input); |
5356 | 5368 | ||
5357 | is_special = "{}<>;&|()#" /* special outside of "str" */ | 5369 | is_special = "{}<>&|();#" /* special outside of "str" */ |
5358 | "$\"" IF_HUSH_TICK("`") /* always special */ | 5370 | "$\"" IF_HUSH_TICK("`") /* always special */ |
5359 | SPECIAL_VAR_SYMBOL_STR; | 5371 | SPECIAL_VAR_SYMBOL_STR; |
5372 | #if defined(CMD_TEST2_SINGLEWORD_NOGLOB) | ||
5373 | if (ctx.command->cmd_type == CMD_TEST2_SINGLEWORD_NOGLOB) { | ||
5374 | /* In [[ ]], {}<>&|() are not special */ | ||
5375 | is_special += 8; | ||
5376 | } else | ||
5377 | #endif | ||
5360 | /* Are { and } special here? */ | 5378 | /* Are { and } special here? */ |
5361 | if (ctx.command->argv /* word [word]{... - non-special */ | 5379 | if (ctx.command->argv /* word [word]{... - non-special */ |
5362 | || ctx.word.length /* word{... - non-special */ | 5380 | || ctx.word.length /* word{... - non-special */ |
@@ -6953,7 +6971,7 @@ static char **expand_strvec_to_strvec(char **argv) | |||
6953 | return expand_variables(argv, EXP_FLAG_GLOB | EXP_FLAG_ESC_GLOB_CHARS); | 6971 | return expand_variables(argv, EXP_FLAG_GLOB | EXP_FLAG_ESC_GLOB_CHARS); |
6954 | } | 6972 | } |
6955 | 6973 | ||
6956 | #if defined(CMD_SINGLEWORD_NOGLOB) | 6974 | #if defined(CMD_SINGLEWORD_NOGLOB) || defined(CMD_TEST2_SINGLEWORD_NOGLOB) |
6957 | static char **expand_strvec_to_strvec_singleword_noglob(char **argv) | 6975 | static char **expand_strvec_to_strvec_singleword_noglob(char **argv) |
6958 | { | 6976 | { |
6959 | return expand_variables(argv, EXP_FLAG_SINGLEWORD); | 6977 | return expand_variables(argv, EXP_FLAG_SINGLEWORD); |
@@ -9133,6 +9151,11 @@ static NOINLINE int run_pipe(struct pipe *pi) | |||
9133 | } | 9151 | } |
9134 | 9152 | ||
9135 | /* Expand the rest into (possibly) many strings each */ | 9153 | /* Expand the rest into (possibly) many strings each */ |
9154 | #if defined(CMD_TEST2_SINGLEWORD_NOGLOB) | ||
9155 | if (command->cmd_type == CMD_TEST2_SINGLEWORD_NOGLOB) | ||
9156 | argv_expanded = expand_strvec_to_strvec_singleword_noglob(argv + command->assignment_cnt); | ||
9157 | else | ||
9158 | #endif | ||
9136 | #if defined(CMD_SINGLEWORD_NOGLOB) | 9159 | #if defined(CMD_SINGLEWORD_NOGLOB) |
9137 | if (command->cmd_type == CMD_SINGLEWORD_NOGLOB) | 9160 | if (command->cmd_type == CMD_SINGLEWORD_NOGLOB) |
9138 | argv_expanded = expand_strvec_to_strvec_singleword_noglob(argv + command->assignment_cnt); | 9161 | argv_expanded = expand_strvec_to_strvec_singleword_noglob(argv + command->assignment_cnt); |