hush: fix "$v" expansion in case patterns when v='[a]'

function                                             old     new   delta
run_list                                            1053    1063     +10
setup_redirects                                      311     320      +9
encode_then_expand_string                            135     142      +7
run_pipe                                            1784    1789      +5
expand_assignments                                    81      86      +5
expand_string_to_string                              124     125      +1
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 6/0 up/down: 37/0)               Total: 37 bytes

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
Denys Vlasenko 2018-04-11 13:47:59 +02:00
parent 680c3016a2
commit 34179956f9
5 changed files with 52 additions and 16 deletions

View File

@ -0,0 +1 @@
s

View File

@ -0,0 +1,8 @@
g='[3](a)(b)(c)'
s='[3](a)(b)(c)'
case $g in
"$s") echo s
;;
*) echo "*"
;;
esac

View File

@ -5610,11 +5610,10 @@ static struct pipe *parse_stream(char **pstring,
/* Expansion can recurse, need forward decls: */ /* Expansion can recurse, need forward decls: */
#if !BASH_PATTERN_SUBST && !ENABLE_HUSH_CASE #if !BASH_PATTERN_SUBST && !ENABLE_HUSH_CASE
/* only ${var/pattern/repl} (its pattern part) needs additional mode */ #define expand_string_to_string(str, EXP_flags, do_unbackslash) \
#define expand_string_to_string(str, do_unbackslash) \
expand_string_to_string(str) expand_string_to_string(str)
#endif #endif
static char *expand_string_to_string(const char *str, int do_unbackslash); static char *expand_string_to_string(const char *str, int EXP_flags, int do_unbackslash);
#if ENABLE_HUSH_TICK #if ENABLE_HUSH_TICK
static int process_command_subs(o_string *dest, const char *s); static int process_command_subs(o_string *dest, const char *s);
#endif #endif
@ -5760,7 +5759,10 @@ static char *encode_then_expand_string(const char *str, int process_bkslash, int
encode_string(NULL, &dest, &input, EOF, process_bkslash); encode_string(NULL, &dest, &input, EOF, process_bkslash);
//TODO: error check (encode_string returns 0 on error)? //TODO: error check (encode_string returns 0 on error)?
//bb_error_msg("'%s' -> '%s'", str, dest.data); //bb_error_msg("'%s' -> '%s'", str, dest.data);
exp_str = expand_string_to_string(dest.data, /*unbackslash:*/ do_unbackslash); exp_str = expand_string_to_string(dest.data,
do_unbackslash ? EXP_FLAG_ESC_GLOB_CHARS : 0,
do_unbackslash
);
//bb_error_msg("'%s' -> '%s'", dest.data, exp_str); //bb_error_msg("'%s' -> '%s'", dest.data, exp_str);
o_free_unsafe(&dest); o_free_unsafe(&dest);
return exp_str; return exp_str;
@ -6393,10 +6395,11 @@ static char **expand_strvec_to_strvec_singleword_noglob(char **argv)
* NB: should NOT do globbing! * NB: should NOT do globbing!
* "export v=/bin/c*; env | grep ^v=" outputs "v=/bin/c*" * "export v=/bin/c*; env | grep ^v=" outputs "v=/bin/c*"
*/ */
static char *expand_string_to_string(const char *str, int do_unbackslash) static char *expand_string_to_string(const char *str, int EXP_flags, int do_unbackslash)
{ {
#if !BASH_PATTERN_SUBST && !ENABLE_HUSH_CASE #if !BASH_PATTERN_SUBST && !ENABLE_HUSH_CASE
const int do_unbackslash = 1; const int do_unbackslash = 1;
const int EXP_flags = EXP_FLAG_ESC_GLOB_CHARS;
#endif #endif
char *argv[2], **list; char *argv[2], **list;
@ -6413,10 +6416,7 @@ static char *expand_string_to_string(const char *str, int do_unbackslash)
argv[0] = (char*)str; argv[0] = (char*)str;
argv[1] = NULL; argv[1] = NULL;
list = expand_variables(argv, do_unbackslash list = expand_variables(argv, EXP_flags | EXP_FLAG_SINGLEWORD);
? EXP_FLAG_ESC_GLOB_CHARS | EXP_FLAG_SINGLEWORD
: EXP_FLAG_SINGLEWORD
);
if (HUSH_DEBUG) if (HUSH_DEBUG)
if (!list[0] || list[1]) if (!list[0] || list[1])
bb_error_msg_and_die("BUG in varexp2"); bb_error_msg_and_die("BUG in varexp2");
@ -6460,7 +6460,13 @@ static char **expand_assignments(char **argv, int count)
G.expanded_assignments = p = NULL; G.expanded_assignments = p = NULL;
/* Expand assignments into one string each */ /* Expand assignments into one string each */
for (i = 0; i < count; i++) { for (i = 0; i < count; i++) {
G.expanded_assignments = p = add_string_to_strings(p, expand_string_to_string(argv[i], /*unbackslash:*/ 1)); p = add_string_to_strings(p,
expand_string_to_string(argv[i],
EXP_FLAG_ESC_GLOB_CHARS,
/*unbackslash:*/ 1
)
);
G.expanded_assignments = p;
} }
G.expanded_assignments = NULL; G.expanded_assignments = NULL;
return p; return p;
@ -7172,7 +7178,8 @@ static int setup_redirects(struct command *prog, struct squirrel **sqp)
continue; continue;
} }
mode = redir_table[redir->rd_type].mode; mode = redir_table[redir->rd_type].mode;
p = expand_string_to_string(redir->rd_filename, /*unbackslash:*/ 1); p = expand_string_to_string(redir->rd_filename,
EXP_FLAG_ESC_GLOB_CHARS, /*unbackslash:*/ 1);
newfd = open_or_warn(p, mode); newfd = open_or_warn(p, mode);
free(p); free(p);
if (newfd < 0) { if (newfd < 0) {
@ -8370,7 +8377,10 @@ static NOINLINE int run_pipe(struct pipe *pi)
bb_putchar_stderr('+'); bb_putchar_stderr('+');
i = 0; i = 0;
while (i < command->assignment_cnt) { while (i < command->assignment_cnt) {
char *p = expand_string_to_string(argv[i], /*unbackslash:*/ 1); char *p = expand_string_to_string(argv[i],
EXP_FLAG_ESC_GLOB_CHARS,
/*unbackslash:*/ 1
);
if (G_x_mode) if (G_x_mode)
fprintf(stderr, " %s", p); fprintf(stderr, " %s", p);
debug_printf_env("set shell var:'%s'->'%s'\n", *argv, p); debug_printf_env("set shell var:'%s'->'%s'\n", *argv, p);
@ -8865,7 +8875,8 @@ static int run_list(struct pipe *pi)
#if ENABLE_HUSH_CASE #if ENABLE_HUSH_CASE
if (rword == RES_CASE) { if (rword == RES_CASE) {
debug_printf_exec("CASE cond_code:%d\n", cond_code); debug_printf_exec("CASE cond_code:%d\n", cond_code);
case_word = expand_string_to_string(pi->cmds->argv[0], 1); case_word = expand_string_to_string(pi->cmds->argv[0],
EXP_FLAG_ESC_GLOB_CHARS, /*unbackslash:*/ 1);
debug_printf_exec("CASE word1:'%s'\n", case_word); debug_printf_exec("CASE word1:'%s'\n", case_word);
//unbackslash(case_word); //unbackslash(case_word);
//debug_printf_exec("CASE word2:'%s'\n", case_word); //debug_printf_exec("CASE word2:'%s'\n", case_word);
@ -8880,12 +8891,19 @@ static int run_list(struct pipe *pi)
/* all prev words didn't match, does this one match? */ /* all prev words didn't match, does this one match? */
argv = pi->cmds->argv; argv = pi->cmds->argv;
while (*argv) { while (*argv) {
char *pattern = expand_string_to_string(*argv, /*unbackslash:*/ 0); char *pattern;
debug_printf_exec("expand_string_to_string('%s')\n", *argv);
pattern = expand_string_to_string(*argv,
EXP_FLAG_ESC_GLOB_CHARS,
/*unbackslash:*/ 0
);
/* TODO: which FNM_xxx flags to use? */ /* TODO: which FNM_xxx flags to use? */
cond_code = (fnmatch(pattern, case_word, /*flags:*/ 0) != 0); cond_code = (fnmatch(pattern, case_word, /*flags:*/ 0) != 0);
debug_printf_exec("fnmatch(pattern:'%s',str:'%s'):%d\n", pattern, case_word, cond_code); debug_printf_exec("fnmatch(pattern:'%s',str:'%s'):%d\n",
pattern, case_word, cond_code);
free(pattern); free(pattern);
if (cond_code == 0) { /* match! we will execute this branch */ if (cond_code == 0) {
/* match! we will execute this branch */
free(case_word); free(case_word);
case_word = NULL; /* make future "word)" stop */ case_word = NULL; /* make future "word)" stop */
break; break;

View File

@ -0,0 +1 @@
s

View File

@ -0,0 +1,8 @@
g='[3](a)(b)(c)'
s='[3](a)(b)(c)'
case $g in
"$s") echo s
;;
*) echo "*"
;;
esac