hush: support "f() (cmd)" functions
Many other shells support this construct
function old new delta
parse_stream 2950 3018 +68
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
diff --git a/shell/ash_test/ash-misc/func5.right b/shell/ash_test/ash-misc/func5.right
index 2c9d316..01e79c3 100644
--- a/shell/ash_test/ash-misc/func5.right
+++ b/shell/ash_test/ash-misc/func5.right
@@ -1,6 +1,3 @@
1
2
3
-1
-2
-3
diff --git a/shell/ash_test/ash-misc/func5.tests b/shell/ash_test/ash-misc/func5.tests
index e967208..5c33560 100755
--- a/shell/ash_test/ash-misc/func5.tests
+++ b/shell/ash_test/ash-misc/func5.tests
@@ -6,8 +6,3 @@
f() ( echo $1 )
f 3
-
-f() for i in 1 2 3; do
- echo $i
-done
-f
diff --git a/shell/ash_test/ash-misc/func_compound1.right b/shell/ash_test/ash-misc/func_compound1.right
new file mode 100644
index 0000000..01e79c3
--- /dev/null
+++ b/shell/ash_test/ash-misc/func_compound1.right
@@ -0,0 +1,3 @@
+1
+2
+3
diff --git a/shell/ash_test/ash-misc/func_compound1.tests b/shell/ash_test/ash-misc/func_compound1.tests
new file mode 100755
index 0000000..20c8bf1
--- /dev/null
+++ b/shell/ash_test/ash-misc/func_compound1.tests
@@ -0,0 +1,4 @@
+f() for i in 1 2 3; do
+ echo $i
+done
+f
diff --git a/shell/hush.c b/shell/hush.c
index 94e429c..3351072 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -4297,6 +4297,11 @@
/* dest contains characters seen prior to ( or {.
* Typically it's empty, but for function defs,
* it contains function name (without '()'). */
+#if BB_MMU
+# define as_string NULL
+#else
+ char *as_string = NULL;
+#endif
struct pipe *pipe_list;
int endch;
struct command *command = ctx->command;
@@ -4325,7 +4330,7 @@
do
ch = i_getch(input);
while (ch == ' ' || ch == '\t' || ch == '\n');
- if (ch != '{') {
+ if (ch != '{' && ch != '(') {
syntax_error_unexpected_ch(ch);
return 1;
}
@@ -4347,13 +4352,13 @@
}
#endif
-#if ENABLE_HUSH_FUNCTIONS
- skip:
-#endif
+ IF_HUSH_FUNCTIONS(skip:)
+
endch = '}';
if (ch == '(') {
endch = ')';
- command->cmd_type = CMD_SUBSHELL;
+ IF_HUSH_FUNCTIONS(if (command->cmd_type != CMD_FUNCDEF))
+ command->cmd_type = CMD_SUBSHELL;
} else {
/* bash does not allow "{echo...", requires whitespace */
ch = i_peek(input);
@@ -4369,38 +4374,54 @@
}
}
- {
-#if BB_MMU
-# define as_string NULL
-#else
- char *as_string = NULL;
-#endif
- pipe_list = parse_stream(&as_string, input, endch);
+ pipe_list = parse_stream(&as_string, input, endch);
#if !BB_MMU
- if (as_string)
- o_addstr(&ctx->as_string, as_string);
+ if (as_string)
+ o_addstr(&ctx->as_string, as_string);
#endif
- /* empty ()/{} or parse error? */
- if (!pipe_list || pipe_list == ERR_PTR) {
- /* parse_stream already emitted error msg */
- if (!BB_MMU)
- free(as_string);
- debug_printf_parse("parse_group return 1: "
- "parse_stream returned %p\n", pipe_list);
- return 1;
- }
- command->group = pipe_list;
-#if !BB_MMU
- as_string[strlen(as_string) - 1] = '\0'; /* plink ')' or '}' */
- command->group_as_string = as_string;
- debug_printf_parse("end of group, remembering as:'%s'\n",
- command->group_as_string);
-#endif
-#undef as_string
+
+ /* empty ()/{} or parse error? */
+ if (!pipe_list || pipe_list == ERR_PTR) {
+ /* parse_stream already emitted error msg */
+ if (!BB_MMU)
+ free(as_string);
+ debug_printf_parse("parse_group return 1: "
+ "parse_stream returned %p\n", pipe_list);
+ return 1;
}
+#if !BB_MMU
+ as_string[strlen(as_string) - 1] = '\0'; /* plink ')' or '}' */
+ command->group_as_string = as_string;
+ debug_printf_parse("end of group, remembering as:'%s'\n",
+ command->group_as_string);
+#endif
+
+#if ENABLE_HUSH_FUNCTIONS
+ /* Convert "f() (cmds)" to "f() {(cmds)}" */
+ if (command->cmd_type == CMD_FUNCDEF && endch == ')') {
+ struct command *cmd2;
+
+ cmd2 = xzalloc(sizeof(*cmd2));
+ cmd2->cmd_type = CMD_SUBSHELL;
+ cmd2->group = pipe_list;
+# if !BB_MMU
+//UNTESTED!
+ cmd2->group_as_string = command->group_as_string;
+ command->group_as_string = xasprintf("(%s)", command->group_as_string);
+# endif
+
+ pipe_list = new_pipe();
+ pipe_list->cmds = cmd2;
+ pipe_list->num_cmds = 1;
+ }
+#endif
+
+ command->group = pipe_list;
+
debug_printf_parse("parse_group return 0\n");
return 0;
/* command remains "open", available for possible redirects */
+#undef as_string
}
#if ENABLE_HUSH_TICK || ENABLE_FEATURE_SH_MATH || ENABLE_HUSH_DOLLAR_OPS
diff --git a/shell/hush_test/hush-misc/func5.tests b/shell/hush_test/hush-misc/func5.tests
index 9c5f9fa..5c33560 100755
--- a/shell/hush_test/hush-misc/func5.tests
+++ b/shell/hush_test/hush-misc/func5.tests
@@ -1,9 +1,8 @@
f() { echo $1; }
f 1
-# hush fails on this syntax, but i've never seen anyone use it ...
-#f() ( echo $1; )
+f() ( echo $1; )
f 2
-#f() ( echo $1 )
+f() ( echo $1 )
f 3