From fbf44854a3b7a32a0a0ff1a03f4163d25f2d62af Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 3 Apr 2018 14:56:52 +0200 Subject: [PATCH] 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 --- shell/ash_test/ash-misc/func5.right | 3 - shell/ash_test/ash-misc/func5.tests | 5 -- shell/ash_test/ash-misc/func_compound1.right | 3 + shell/ash_test/ash-misc/func_compound1.tests | 4 + shell/hush.c | 79 +++++++++++++------- shell/hush_test/hush-misc/func5.tests | 5 +- 6 files changed, 59 insertions(+), 40 deletions(-) create mode 100644 shell/ash_test/ash-misc/func_compound1.right create mode 100755 shell/ash_test/ash-misc/func_compound1.tests diff --git a/shell/ash_test/ash-misc/func5.right b/shell/ash_test/ash-misc/func5.right index 2c9d316b3..01e79c32a 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 e967208cc..5c33560bc 100755 --- a/shell/ash_test/ash-misc/func5.tests +++ b/shell/ash_test/ash-misc/func5.tests @@ -6,8 +6,3 @@ f 2 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 000000000..01e79c32a --- /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 000000000..20c8bf18b --- /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 94e429c0d..335107283 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -4297,6 +4297,11 @@ static int parse_group(o_string *dest, struct parse_context *ctx, /* 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 @@ static int parse_group(o_string *dest, struct parse_context *ctx, 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 @@ static int parse_group(o_string *dest, struct parse_context *ctx, } #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 @@ static int parse_group(o_string *dest, struct parse_context *ctx, } } - { -#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; + + /* 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); + 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 + +#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 9c5f9fa48..5c33560bc 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 -- 2.25.1