#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
#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 "\\/%#:-=+?"
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
#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
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
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);
(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;
}
{
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);
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)) */
/* 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 */
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]}
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} */
}
#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
#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) \
int dquote_end,
int process_bkslash)
{
-#if !ENABLE_HUSH_BASH_COMPAT
+#if !BASH_PATTERN_SUBST
const int process_bkslash = 1;
#endif
int ch;
/*** 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)
* 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)
}
#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)
{
debug_printf_varexp("result:'%s'\n", result);
return result;
}
-#endif
+#endif /* BASH_PATTERN_SUBST */
/* Helper:
* Handles <SPECIAL_VAR_SYMBOL>varname...<SPECIAL_VAR_SYMBOL> construct.
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 */
}
}
}
-#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:
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:N<SPECIAL_VAR_SYMBOL>M<SPECIAL_VAR_SYMBOL>
}
debug_printf_varexp("val:'%s'\n", val);
} else
-#endif
+#endif /* HUSH_SUBSTR_EXPANSION && FEATURE_SH_MATH */
{
die_if_script("malformed ${%s:...}", var);
val = NULL;
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);
*/
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;
}
/* 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
/* 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;
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);