diff --git a/shell/hush.c b/shell/hush.c index ecef099ac..fb0321a2c 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -326,6 +326,15 @@ #endif +/* So far, all bash compat is controlled by one config option */ +/* Separate defines document which part of code implements what */ +#define BASH_PATTERN_SUBST ENABLE_HUSH_BASH_COMPAT +#define BASH_SUBSTR ENABLE_HUSH_BASH_COMPAT +#define BASH_TEST2 ENABLE_HUSH_BASH_COMPAT +#define BASH_SOURCE ENABLE_HUSH_BASH_COMPAT +#define BASH_HOSTNAME_VAR ENABLE_HUSH_BASH_COMPAT + + /* Build knobs */ #define LEAK_HUNTING 0 #define BUILD_AS_NOMMU 0 @@ -411,7 +420,7 @@ #define _SPECIAL_VARS_STR "_*@$!?#" #define SPECIAL_VARS_STR ("_*@$!?#" + 1) #define NUMERIC_SPECVARS_STR ("_*@$!?#" + 3) -#if ENABLE_HUSH_BASH_COMPAT +#if BASH_PATTERN_SUBST /* Support / and // replace ops */ /* Note that // is stored as \ in "encoded" string representation */ # define VAR_ENCODED_SUBST_OPS "\\/%#:-=+?" @@ -572,7 +581,7 @@ struct command { smallint cmd_type; /* CMD_xxx */ #define CMD_NORMAL 0 #define CMD_SUBSHELL 1 -#if ENABLE_HUSH_BASH_COMPAT +#if BASH_TEST2 /* used for "[[ EXPR ]]" */ # define CMD_SINGLEWORD_NOGLOB 2 #endif @@ -947,7 +956,7 @@ static int builtin_set(char **argv) FAST_FUNC; #endif static int builtin_shift(char **argv) FAST_FUNC; static int builtin_source(char **argv) FAST_FUNC; -#if ENABLE_HUSH_TEST +#if ENABLE_HUSH_TEST || BASH_TEST2 static int builtin_test(char **argv) FAST_FUNC; #endif #if ENABLE_HUSH_TRAP @@ -1044,7 +1053,7 @@ static const struct built_in_command bltins1[] = { BLTIN("set" , builtin_set , "Set positional parameters"), #endif BLTIN("shift" , builtin_shift , "Shift positional parameters"), -#if ENABLE_HUSH_BASH_COMPAT +#if BASH_SOURCE BLTIN("source" , builtin_source , NULL), #endif #if ENABLE_HUSH_TRAP @@ -2174,7 +2183,7 @@ static void unset_vars(char **strings) free(strings); } -#if ENABLE_FEATURE_SH_MATH || ENABLE_HUSH_BASH_COMPAT || ENABLE_HUSH_READ +#if BASH_HOSTNAME_VAR || ENABLE_FEATURE_SH_MATH || ENABLE_HUSH_READ static void FAST_FUNC set_local_var_from_halves(const char *name, const char *val) { char *var = xasprintf("%s=%s", name, val); @@ -3633,7 +3642,7 @@ static int done_word(o_string *word, struct parse_context *ctx) (ctx->ctx_res_w == RES_SNTX)); return (ctx->ctx_res_w == RES_SNTX); } -# if ENABLE_HUSH_BASH_COMPAT +# if BASH_TEST2 if (strcmp(word->data, "[[") == 0) { command->cmd_type = CMD_SINGLEWORD_NOGLOB; } @@ -4231,7 +4240,7 @@ static int add_till_closing_bracket(o_string *dest, struct in_str *input, unsign { int ch; char dbl = end_ch & DOUBLE_CLOSE_CHAR_FLAG; -# if ENABLE_HUSH_BASH_COMPAT +# if BASH_SUBSTR || BASH_PATTERN_SUBST char end_char2 = end_ch >> 8; # endif end_ch &= (DOUBLE_CLOSE_CHAR_FLAG - 1); @@ -4242,7 +4251,11 @@ static int add_till_closing_bracket(o_string *dest, struct in_str *input, unsign syntax_error_unterm_ch(end_ch); return 0; } - if (ch == end_ch IF_HUSH_BASH_COMPAT( || ch == end_char2)) { + if (ch == end_ch +# if BASH_SUBSTR || BASH_PATTERN_SUBST + || ch == end_char2 +# endif + ) { if (!dbl) break; /* we look for closing )) of $((EXPR)) */ @@ -4395,14 +4408,14 @@ static int parse_dollar(o_string *as_string, /* Eat everything until closing '}' (or ':') */ end_ch = '}'; - if (ENABLE_HUSH_BASH_COMPAT + if (BASH_SUBSTR && ch == ':' && !strchr(MINUS_PLUS_EQUAL_QUESTION, i_peek(input)) ) { /* It's ${var:N[:M]} thing */ end_ch = '}' * 0x100 + ':'; } - if (ENABLE_HUSH_BASH_COMPAT + if (BASH_PATTERN_SUBST && ch == '/' ) { /* It's ${var/[/]pattern[/repl]} thing */ @@ -4429,7 +4442,9 @@ static int parse_dollar(o_string *as_string, o_addchr(as_string, last_ch); } - if (ENABLE_HUSH_BASH_COMPAT && (end_ch & 0xff00)) { + if ((BASH_SUBSTR || BASH_PATTERN_SUBST) + && (end_ch & 0xff00) + ) { /* close the first block: */ o_addchr(dest, SPECIAL_VAR_SYMBOL); /* while parsing N from ${var:N[:M]} @@ -4440,7 +4455,7 @@ static int parse_dollar(o_string *as_string, goto again; } /* got '}' */ - if (end_ch == '}' * 0x100 + ':') { + if (BASH_SUBSTR && end_ch == '}' * 0x100 + ':') { /* it's ${var:N} - emulate :999999999 */ o_addstr(dest, "999999999"); } /* else: it's ${var/[/]pattern} */ @@ -4515,7 +4530,7 @@ static int parse_dollar(o_string *as_string, } #if BB_MMU -# if ENABLE_HUSH_BASH_COMPAT +# if BASH_PATTERN_SUBST #define encode_string(as_string, dest, input, dquote_end, process_bkslash) \ encode_string(dest, input, dquote_end, process_bkslash) # else @@ -4527,7 +4542,7 @@ static int parse_dollar(o_string *as_string, #else /* !MMU */ -# if ENABLE_HUSH_BASH_COMPAT +# if BASH_PATTERN_SUBST /* all parameters are needed, no macro tricks */ # else #define encode_string(as_string, dest, input, dquote_end, process_bkslash) \ @@ -4540,7 +4555,7 @@ static int encode_string(o_string *as_string, int dquote_end, int process_bkslash) { -#if !ENABLE_HUSH_BASH_COMPAT +#if !BASH_PATTERN_SUBST const int process_bkslash = 1; #endif int ch; @@ -5183,7 +5198,7 @@ static struct pipe *parse_stream(char **pstring, /*** Execution routines ***/ /* Expansion can recurse, need forward decls: */ -#if !ENABLE_HUSH_BASH_COMPAT +#if !BASH_PATTERN_SUBST /* only ${var/pattern/repl} (its pattern part) needs additional mode */ #define expand_string_to_string(str, do_unbackslash) \ expand_string_to_string(str) @@ -5304,7 +5319,7 @@ static int expand_on_ifs(int *ended_with_ifs, o_string *output, int n, const cha * Returns malloced string. * As an optimization, we return NULL if expansion is not needed. */ -#if !ENABLE_HUSH_BASH_COMPAT +#if !BASH_PATTERN_SUBST /* only ${var/pattern/repl} (its pattern part) needs additional mode */ #define encode_then_expand_string(str, process_bkslash, do_unbackslash) \ encode_then_expand_string(str) @@ -5358,7 +5373,7 @@ static arith_t expand_and_evaluate_arith(const char *arg, const char **errmsg_p) } #endif -#if ENABLE_HUSH_BASH_COMPAT +#if BASH_PATTERN_SUBST /* ${var/[/]pattern[/repl]} helpers */ static char *strstr_pattern(char *val, const char *pattern, int *size) { @@ -5410,7 +5425,7 @@ static char *replace_pattern(char *val, const char *pattern, const char *repl, c debug_printf_varexp("result:'%s'\n", result); return result; } -#endif +#endif /* BASH_PATTERN_SUBST */ /* Helper: * Handles varname... construct. @@ -5458,7 +5473,7 @@ static NOINLINE const char *expand_one_var(char **to_be_freed_pp, char *arg, cha if (exp_op == ':') { exp_op = *exp_word++; //TODO: try ${var:} and ${var:bogus} in non-bash config - if (ENABLE_HUSH_BASH_COMPAT + if (BASH_SUBSTR && (!exp_op || !strchr(MINUS_PLUS_EQUAL_QUESTION, exp_op)) ) { /* oops... it's ${var:N[:M]}, not ${var:?xxx} or some such */ @@ -5540,7 +5555,7 @@ static NOINLINE const char *expand_one_var(char **to_be_freed_pp, char *arg, cha } } } -#if ENABLE_HUSH_BASH_COMPAT +#if BASH_PATTERN_SUBST else if (exp_op == '/' || exp_op == '\\') { /* It's ${var/[/]pattern[/repl]} thing. * Note that in encoded form it has TWO parts: @@ -5587,9 +5602,9 @@ static NOINLINE const char *expand_one_var(char **to_be_freed_pp, char *arg, cha free(repl); } } -#endif +#endif /* BASH_PATTERN_SUBST */ else if (exp_op == ':') { -#if ENABLE_HUSH_BASH_COMPAT && ENABLE_FEATURE_SH_MATH +#if BASH_SUBSTR && ENABLE_FEATURE_SH_MATH /* It's ${var:N[:M]} bashism. * Note that in encoded form it has TWO parts: * var:NM @@ -5625,7 +5640,7 @@ static NOINLINE const char *expand_one_var(char **to_be_freed_pp, char *arg, cha } debug_printf_varexp("val:'%s'\n", val); } else -#endif +#endif /* HUSH_SUBSTR_EXPANSION && FEATURE_SH_MATH */ { die_if_script("malformed ${%s:...}", var); val = NULL; @@ -5915,7 +5930,7 @@ static char **expand_strvec_to_strvec(char **argv) return expand_variables(argv, EXP_FLAG_GLOB | EXP_FLAG_ESC_GLOB_CHARS); } -#if ENABLE_HUSH_BASH_COMPAT +#if BASH_TEST2 static char **expand_strvec_to_strvec_singleword_noglob(char **argv) { return expand_variables(argv, EXP_FLAG_SINGLEWORD); @@ -5930,7 +5945,7 @@ static char **expand_strvec_to_strvec_singleword_noglob(char **argv) */ static char *expand_string_to_string(const char *str, int do_unbackslash) { -#if !ENABLE_HUSH_BASH_COMPAT +#if !BASH_PATTERN_SUBST const int do_unbackslash = 1; #endif char *argv[2], **list; @@ -7652,7 +7667,7 @@ static NOINLINE int run_pipe(struct pipe *pi) } /* Expand the rest into (possibly) many strings each */ -#if ENABLE_HUSH_BASH_COMPAT +#if BASH_TEST2 if (command->cmd_type == CMD_SINGLEWORD_NOGLOB) { argv_expanded = expand_strvec_to_strvec_singleword_noglob(argv + command->assignment_cnt); } else @@ -8408,7 +8423,7 @@ int hush_main(int argc, char **argv) /* Export PWD */ set_pwd_var(/*exp:*/ 1); -#if ENABLE_HUSH_BASH_COMPAT +#if BASH_HOSTNAME_VAR /* Set (but not export) HOSTNAME unless already set */ if (!get_local_var_value("HOSTNAME")) { struct utsname uts; @@ -8816,7 +8831,7 @@ static int run_applet_main(char **argv, int (*applet_main_func)(int argc, char * return applet_main_func(argc, argv - argc); } #endif -#if ENABLE_HUSH_TEST +#if ENABLE_HUSH_TEST || BASH_TEST2 static int FAST_FUNC builtin_test(char **argv) { return run_applet_main(argv, test_main);