diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2009-04-10 21:22:02 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2009-04-10 21:22:02 +0000 |
commit | c0ea329297862003a32570a7a38fa2bcb20e57f1 (patch) | |
tree | 7c48bd11a6710c9e2a948bab2faf845bd44b32f0 | |
parent | b7d8c0dbbd250649d647142edd33226822f3c879 (diff) | |
download | busybox-w32-c0ea329297862003a32570a7a38fa2bcb20e57f1.tar.gz busybox-w32-c0ea329297862003a32570a7a38fa2bcb20e57f1.tar.bz2 busybox-w32-c0ea329297862003a32570a7a38fa2bcb20e57f1.zip |
hush: fix a few thinkos in function support; make it work on NOMMU;
functions in child shells now even have $n passed to them! :)
(in main shell it still doesn't work)
-rw-r--r-- | shell/hush.c | 189 |
1 files changed, 120 insertions, 69 deletions
diff --git a/shell/hush.c b/shell/hush.c index 3728583fc..dd5031951 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
@@ -452,11 +452,16 @@ enum { | |||
452 | BC_CONTINUE = 2, | 452 | BC_CONTINUE = 2, |
453 | }; | 453 | }; |
454 | 454 | ||
455 | #if ENABLE_HUSH_FUNCTIONS | ||
455 | struct function { | 456 | struct function { |
456 | struct function *next; | 457 | struct function *next; |
457 | char *name; | 458 | char *name; |
458 | struct pipe *body; | 459 | struct pipe *body; |
460 | #if !BB_MMU | ||
461 | char *body_as_string; | ||
462 | #endif | ||
459 | }; | 463 | }; |
464 | #endif | ||
460 | 465 | ||
461 | 466 | ||
462 | /* "Globals" within this file */ | 467 | /* "Globals" within this file */ |
@@ -510,7 +515,9 @@ struct globals { | |||
510 | const char *cwd; | 515 | const char *cwd; |
511 | struct variable *top_var; /* = &G.shell_ver (set in main()) */ | 516 | struct variable *top_var; /* = &G.shell_ver (set in main()) */ |
512 | struct variable shell_ver; | 517 | struct variable shell_ver; |
518 | #if ENABLE_HUSH_FUNCTIONS | ||
513 | struct function *top_func; | 519 | struct function *top_func; |
520 | #endif | ||
514 | /* Signal and trap handling */ | 521 | /* Signal and trap handling */ |
515 | // unsigned count_SIGCHLD; | 522 | // unsigned count_SIGCHLD; |
516 | // unsigned handled_SIGCHLD; | 523 | // unsigned handled_SIGCHLD; |
@@ -675,11 +682,12 @@ static void xxfree(void *ptr) | |||
675 | * HUSH_DEBUG >= 2 prints line number in this file where it was detected. | 682 | * HUSH_DEBUG >= 2 prints line number in this file where it was detected. |
676 | */ | 683 | */ |
677 | #if HUSH_DEBUG < 2 | 684 | #if HUSH_DEBUG < 2 |
678 | # define die_if_script(lineno, fmt...) die_if_script(fmt) | 685 | # define die_if_script(lineno, fmt...) die_if_script(fmt) |
679 | # define syntax_error(lineno, msg) syntax_error(msg) | 686 | # define syntax_error(lineno, msg) syntax_error(msg) |
680 | # define syntax_error_at(lineno, msg) syntax_error_at(msg) | 687 | # define syntax_error_at(lineno, msg) syntax_error_at(msg) |
681 | # define syntax_error_unterm_ch(lineno, ch) syntax_error_unterm_ch(ch) | 688 | # define syntax_error_unterm_ch(lineno, ch) syntax_error_unterm_ch(ch) |
682 | # define syntax_error_unterm_str(lineno, s) syntax_error_unterm_str(s) | 689 | # define syntax_error_unterm_str(lineno, s) syntax_error_unterm_str(s) |
690 | # define syntax_error_unexpected_ch(lineno, ch) syntax_error_unexpected_ch(ch) | ||
683 | #endif | 691 | #endif |
684 | 692 | ||
685 | static void die_if_script(unsigned lineno, const char *fmt, ...) | 693 | static void die_if_script(unsigned lineno, const char *fmt, ...) |
@@ -729,18 +737,29 @@ static void syntax_error_unterm_str(unsigned lineno, const char *s) | |||
729 | die_if_script(lineno, "syntax error: unterminated %s", s); | 737 | die_if_script(lineno, "syntax error: unterminated %s", s); |
730 | } | 738 | } |
731 | 739 | ||
740 | static void syntax_error_unexpected_ch(unsigned lineno, char ch) | ||
741 | { | ||
742 | char msg[2]; | ||
743 | msg[0] = ch; | ||
744 | msg[1] = '\0'; | ||
745 | die_if_script(lineno, "syntax error: unexpected %s", msg); | ||
746 | xfunc_die(); | ||
747 | } | ||
748 | |||
732 | #if HUSH_DEBUG < 2 | 749 | #if HUSH_DEBUG < 2 |
733 | # undef die_if_script | 750 | # undef die_if_script |
734 | # undef syntax_error | 751 | # undef syntax_error |
735 | # undef syntax_error_at | 752 | # undef syntax_error_at |
736 | # undef syntax_error_unterm_ch | 753 | # undef syntax_error_unterm_ch |
737 | # undef syntax_error_unterm_str | 754 | # undef syntax_error_unterm_str |
755 | # undef syntax_error_unexpected_ch | ||
738 | #else | 756 | #else |
739 | # define die_if_script(fmt...) die_if_script(__LINE__, fmt) | 757 | # define die_if_script(fmt...) die_if_script(__LINE__, fmt) |
740 | # define syntax_error(msg) syntax_error(__LINE__, msg) | 758 | # define syntax_error(msg) syntax_error(__LINE__, msg) |
741 | # define syntax_error_at(msg) syntax_error_at(__LINE__, msg) | 759 | # define syntax_error_at(msg) syntax_error_at(__LINE__, msg) |
742 | # define syntax_error_unterm_ch(ch) syntax_error_unterm_ch(__LINE__, ch) | 760 | # define syntax_error_unterm_ch(ch) syntax_error_unterm_ch(__LINE__, ch) |
743 | # define syntax_error_unterm_str(s) syntax_error_unterm_str(__LINE__, s) | 761 | # define syntax_error_unterm_str(s) syntax_error_unterm_str(__LINE__, s) |
762 | # define syntax_error_unexpected_ch(ch) syntax_error_unexpected_ch(__LINE__, ch) | ||
744 | #endif | 763 | #endif |
745 | 764 | ||
746 | 765 | ||
@@ -2234,8 +2253,11 @@ static char **expand_assignments(char **argv, int count) | |||
2234 | 2253 | ||
2235 | 2254 | ||
2236 | #if BB_MMU | 2255 | #if BB_MMU |
2237 | void re_execute_shell(const char *s, int is_heredoc); /* never called */ | 2256 | /* never called */ |
2257 | void re_execute_shell(const char *s, char *argv0, char **argv); | ||
2258 | |||
2238 | #define clean_up_after_re_execute() ((void)0) | 2259 | #define clean_up_after_re_execute() ((void)0) |
2260 | |||
2239 | static void reset_traps_to_defaults(void) | 2261 | static void reset_traps_to_defaults(void) |
2240 | { | 2262 | { |
2241 | unsigned sig; | 2263 | unsigned sig; |
@@ -2266,16 +2288,16 @@ static void reset_traps_to_defaults(void) | |||
2266 | 2288 | ||
2267 | #else /* !BB_MMU */ | 2289 | #else /* !BB_MMU */ |
2268 | 2290 | ||
2269 | static void re_execute_shell(const char *s, int is_heredoc) NORETURN; | 2291 | static void re_execute_shell(const char *s, char *g_argv0, char **g_argv) NORETURN; |
2270 | static void re_execute_shell(const char *s, int is_heredoc) | 2292 | static void re_execute_shell(const char *s, char *g_argv0, char **g_argv) |
2271 | { | 2293 | { |
2272 | char param_buf[sizeof("-$%x:%x:%x:%x") + sizeof(unsigned) * 4]; | 2294 | char param_buf[sizeof("-$%x:%x:%x:%x") + sizeof(unsigned) * 4]; |
2273 | char *heredoc_argv[4]; | 2295 | char *heredoc_argv[4]; |
2274 | struct variable *cur; | 2296 | struct variable *cur; |
2275 | char **argv, **pp, **pp2; | 2297 | char **argv, **pp; |
2276 | unsigned cnt; | 2298 | unsigned cnt; |
2277 | 2299 | ||
2278 | if (is_heredoc) { | 2300 | if (!g_argv0) { /* heredoc */ |
2279 | argv = heredoc_argv; | 2301 | argv = heredoc_argv; |
2280 | argv[0] = (char *) G.argv0_for_re_execing; | 2302 | argv[0] = (char *) G.argv0_for_re_execing; |
2281 | argv[1] = (char *) "-<"; | 2303 | argv[1] = (char *) "-<"; |
@@ -2292,13 +2314,16 @@ static void re_execute_shell(const char *s, int is_heredoc) | |||
2292 | USE_HUSH_LOOPS(, G.depth_of_loop) | 2314 | USE_HUSH_LOOPS(, G.depth_of_loop) |
2293 | ); | 2315 | ); |
2294 | /* 1:hush 2:-$<pid>:<pid>:<exitcode>:<depth> <vars...> | 2316 | /* 1:hush 2:-$<pid>:<pid>:<exitcode>:<depth> <vars...> |
2295 | * 3:-c 4:<cmd> <argN...> 5:NULL | 2317 | * 3:-c 4:<cmd> 5:<arg0> <argN...> 6:NULL |
2296 | */ | 2318 | */ |
2297 | cnt = 5 + G.global_argc; | 2319 | cnt = 6; |
2298 | for (cur = G.top_var; cur; cur = cur->next) { | 2320 | for (cur = G.top_var; cur; cur = cur->next) { |
2299 | if (!cur->flg_export || cur->flg_read_only) | 2321 | if (!cur->flg_export || cur->flg_read_only) |
2300 | cnt += 2; | 2322 | cnt += 2; |
2301 | } | 2323 | } |
2324 | pp = g_argv; | ||
2325 | while (*pp++) | ||
2326 | cnt++; | ||
2302 | G.argv_from_re_execing = argv = pp = xzalloc(sizeof(argv[0]) * cnt); | 2327 | G.argv_from_re_execing = argv = pp = xzalloc(sizeof(argv[0]) * cnt); |
2303 | *pp++ = (char *) G.argv0_for_re_execing; | 2328 | *pp++ = (char *) G.argv0_for_re_execing; |
2304 | *pp++ = param_buf; | 2329 | *pp++ = param_buf; |
@@ -2335,9 +2360,9 @@ static void re_execute_shell(const char *s, int is_heredoc) | |||
2335 | */ | 2360 | */ |
2336 | *pp++ = (char *) "-c"; | 2361 | *pp++ = (char *) "-c"; |
2337 | *pp++ = (char *) s; | 2362 | *pp++ = (char *) s; |
2338 | pp2 = G.global_argv; | 2363 | *pp++ = g_argv0; |
2339 | while (*pp2) | 2364 | while (*g_argv) |
2340 | *pp++ = *pp2++; | 2365 | *pp++ = *g_argv++; |
2341 | /* *pp = NULL; - is already there */ | 2366 | /* *pp = NULL; - is already there */ |
2342 | pp = environ; | 2367 | pp = environ; |
2343 | 2368 | ||
@@ -2426,7 +2451,7 @@ static void setup_heredoc(struct redir_struct *redir) | |||
2426 | /* Delegate blocking writes to another process */ | 2451 | /* Delegate blocking writes to another process */ |
2427 | disable_restore_tty_pgrp_on_exit(); | 2452 | disable_restore_tty_pgrp_on_exit(); |
2428 | xmove_fd(pair.wr, STDOUT_FILENO); | 2453 | xmove_fd(pair.wr, STDOUT_FILENO); |
2429 | re_execute_shell(heredoc, 1); | 2454 | re_execute_shell(heredoc, NULL, NULL); |
2430 | #endif | 2455 | #endif |
2431 | } | 2456 | } |
2432 | /* parent */ | 2457 | /* parent */ |
@@ -2592,6 +2617,8 @@ static void free_pipe_list(struct pipe *head, int indent) | |||
2592 | } | 2617 | } |
2593 | 2618 | ||
2594 | 2619 | ||
2620 | static int run_list(struct pipe *pi); | ||
2621 | |||
2595 | static const struct built_in_command* find_builtin(const char *name) | 2622 | static const struct built_in_command* find_builtin(const char *name) |
2596 | { | 2623 | { |
2597 | const struct built_in_command *x; | 2624 | const struct built_in_command *x; |
@@ -2604,22 +2631,39 @@ static const struct built_in_command* find_builtin(const char *name) | |||
2604 | return NULL; | 2631 | return NULL; |
2605 | } | 2632 | } |
2606 | 2633 | ||
2607 | # if ENABLE_HUSH_FUNCTIONS | 2634 | #if ENABLE_HUSH_FUNCTIONS |
2608 | static const struct function *find_function(const char *name) | 2635 | static const struct function *find_function(const char *name) |
2609 | { | 2636 | { |
2610 | const struct function *funcp = G.top_func; | 2637 | const struct function *funcp = G.top_func; |
2611 | while (funcp) { | 2638 | while (funcp) { |
2612 | if (strcmp(name, funcp->name) != 0) | 2639 | if (strcmp(name, funcp->name) == 0) { |
2613 | continue; | 2640 | break; |
2614 | return funcp; | 2641 | } |
2615 | debug_printf_exec("found function '%s'\n", name); | 2642 | funcp = funcp->next; |
2616 | } | 2643 | } |
2617 | return NULL; | 2644 | debug_printf_exec("found function '%s'\n", name); |
2645 | return funcp; | ||
2618 | } | 2646 | } |
2619 | #endif | 2647 | static void exec_function(const struct function *funcp, char **argv) NORETURN; |
2648 | static void exec_function(const struct function *funcp, char **argv) | ||
2649 | { | ||
2650 | # if BB_MMU | ||
2651 | int n = 1; | ||
2620 | 2652 | ||
2653 | argv[0] = G.global_argv[0]; | ||
2654 | G.global_argv = argv; | ||
2655 | while (*++argv) | ||
2656 | n++; | ||
2657 | G.global_argc = n; | ||
2658 | n = run_list(funcp->body); | ||
2659 | fflush(NULL); | ||
2660 | _exit(n); | ||
2661 | # else | ||
2662 | re_execute_shell(funcp->body_as_string, G.global_argv[0], argv + 1); | ||
2663 | #endif | ||
2664 | } | ||
2665 | #endif | ||
2621 | 2666 | ||
2622 | static int run_list(struct pipe *pi); | ||
2623 | 2667 | ||
2624 | #if BB_MMU | 2668 | #if BB_MMU |
2625 | #define pseudo_exec_argv(nommu_save, argv, assignment_cnt, argv_expanded) \ | 2669 | #define pseudo_exec_argv(nommu_save, argv, assignment_cnt, argv_expanded) \ |
@@ -2688,18 +2732,15 @@ static void pseudo_exec_argv(nommu_save_t *nommu_save, | |||
2688 | _exit(rcode); | 2732 | _exit(rcode); |
2689 | } | 2733 | } |
2690 | } | 2734 | } |
2691 | # if ENABLE_HUSH_FUNCTIONS | 2735 | #endif |
2736 | #if ENABLE_HUSH_FUNCTIONS | ||
2692 | /* Check if the command matches any functions */ | 2737 | /* Check if the command matches any functions */ |
2693 | { | 2738 | { |
2694 | int rcode; | ||
2695 | const struct function *funcp = find_function(argv[0]); | 2739 | const struct function *funcp = find_function(argv[0]); |
2696 | if (funcp) { | 2740 | if (funcp) { |
2697 | rcode = run_list(funcp->body); | 2741 | exec_function(funcp, argv); |
2698 | fflush(NULL); | ||
2699 | _exit(rcode); | ||
2700 | } | 2742 | } |
2701 | } | 2743 | } |
2702 | # endif | ||
2703 | #endif | 2744 | #endif |
2704 | 2745 | ||
2705 | #if ENABLE_FEATURE_SH_STANDALONE | 2746 | #if ENABLE_FEATURE_SH_STANDALONE |
@@ -2723,7 +2764,9 @@ static void pseudo_exec_argv(nommu_save_t *nommu_save, | |||
2723 | } | 2764 | } |
2724 | #endif | 2765 | #endif |
2725 | 2766 | ||
2767 | #if ENABLE_FEATURE_SH_STANDALONE || BB_MMU | ||
2726 | skip: | 2768 | skip: |
2769 | #endif | ||
2727 | debug_printf_exec("execing '%s'\n", argv[0]); | 2770 | debug_printf_exec("execing '%s'\n", argv[0]); |
2728 | sigprocmask(SIG_SETMASK, &G.inherited_set, NULL); | 2771 | sigprocmask(SIG_SETMASK, &G.inherited_set, NULL); |
2729 | execvp(argv[0], argv); | 2772 | execvp(argv[0], argv); |
@@ -2761,7 +2804,9 @@ static void pseudo_exec(nommu_save_t *nommu_save, | |||
2761 | * since this process is about to exit */ | 2804 | * since this process is about to exit */ |
2762 | _exit(rcode); | 2805 | _exit(rcode); |
2763 | #else | 2806 | #else |
2764 | re_execute_shell(command->group_as_string, 0); | 2807 | re_execute_shell(command->group_as_string, |
2808 | G.global_argv[0], | ||
2809 | G.global_argv + 1); | ||
2765 | #endif | 2810 | #endif |
2766 | } | 2811 | } |
2767 | 2812 | ||
@@ -3085,19 +3130,23 @@ static int run_pipe(struct pipe *pi) | |||
3085 | 3130 | ||
3086 | while ((funcp = *funcpp) != NULL) { | 3131 | while ((funcp = *funcpp) != NULL) { |
3087 | if (strcmp(funcp->name, command->argv[0]) == 0) { | 3132 | if (strcmp(funcp->name, command->argv[0]) == 0) { |
3088 | debug_printf_exec("replacing function '%s'", funcp->name); | 3133 | debug_printf_exec("replacing function '%s'\n", funcp->name); |
3089 | free(funcp->name); | 3134 | free(funcp->name); |
3090 | free_pipe_list(funcp->body, /* indent: */ 0); | 3135 | free_pipe_list(funcp->body, /* indent: */ 0); |
3091 | goto skip; | 3136 | goto skip; |
3092 | } | 3137 | } |
3093 | funcpp = &funcp->next; | 3138 | funcpp = &funcp->next; |
3094 | } | 3139 | } |
3095 | debug_printf_exec("remembering new function '%s'", funcp->name); | 3140 | debug_printf_exec("remembering new function '%s'\n", command->argv[0]); |
3096 | funcp = *funcpp = xzalloc(sizeof(*funcp)); | 3141 | funcp = *funcpp = xzalloc(sizeof(*funcp)); |
3097 | /*funcp->next = NULL;*/ | 3142 | /*funcp->next = NULL;*/ |
3098 | skip: | 3143 | skip: |
3099 | funcp->name = command->argv[0]; | 3144 | funcp->name = command->argv[0]; |
3100 | funcp->body = command->group; | 3145 | funcp->body = command->group; |
3146 | #if !BB_MMU | ||
3147 | funcp->body_as_string = command->group_as_string; | ||
3148 | command->group_as_string = NULL; | ||
3149 | #endif | ||
3101 | command->group = NULL; | 3150 | command->group = NULL; |
3102 | command->argv[0] = NULL; | 3151 | command->argv[0] = NULL; |
3103 | free_strings(command->argv); | 3152 | free_strings(command->argv); |
@@ -3160,6 +3209,7 @@ static int run_pipe(struct pipe *pi) | |||
3160 | 3209 | ||
3161 | x = find_builtin(argv_expanded[0]); | 3210 | x = find_builtin(argv_expanded[0]); |
3162 | #if ENABLE_HUSH_FUNCTIONS | 3211 | #if ENABLE_HUSH_FUNCTIONS |
3212 | funcp = NULL; | ||
3163 | if (!x) | 3213 | if (!x) |
3164 | funcp = find_function(argv_expanded[0]); | 3214 | funcp = find_function(argv_expanded[0]); |
3165 | #endif | 3215 | #endif |
@@ -3171,7 +3221,6 @@ static int run_pipe(struct pipe *pi) | |||
3171 | goto clean_up_and_ret1; | 3221 | goto clean_up_and_ret1; |
3172 | } | 3222 | } |
3173 | } | 3223 | } |
3174 | debug_printf("builtin inline %s\n", argv_expanded[0]); | ||
3175 | /* XXX setup_redirects acts on file descriptors, not FILEs. | 3224 | /* XXX setup_redirects acts on file descriptors, not FILEs. |
3176 | * This is perfect for work that comes after exec(). | 3225 | * This is perfect for work that comes after exec(). |
3177 | * Is it really safe for inline use? Experimentally, | 3226 | * Is it really safe for inline use? Experimentally, |
@@ -3681,7 +3730,7 @@ static int run_list(struct pipe *pi) | |||
3681 | /* We only ran a builtin: rcode is already known | 3730 | /* We only ran a builtin: rcode is already known |
3682 | * and we don't need to wait for anything. */ | 3731 | * and we don't need to wait for anything. */ |
3683 | G.last_exitcode = rcode; | 3732 | G.last_exitcode = rcode; |
3684 | debug_printf_exec(": builtin exitcode %d\n", rcode); | 3733 | debug_printf_exec(": builtin/func exitcode %d\n", rcode); |
3685 | check_and_run_traps(0); | 3734 | check_and_run_traps(0); |
3686 | #if ENABLE_HUSH_LOOPS | 3735 | #if ENABLE_HUSH_LOOPS |
3687 | /* Was it "break" or "continue"? */ | 3736 | /* Was it "break" or "continue"? */ |
@@ -4497,7 +4546,9 @@ static FILE *generate_stream_from_string(const char *s) | |||
4497 | * huge=`cat BIG` # was blocking here forever | 4546 | * huge=`cat BIG` # was blocking here forever |
4498 | * echo OK | 4547 | * echo OK |
4499 | */ | 4548 | */ |
4500 | re_execute_shell(s, 0); | 4549 | re_execute_shell(s, |
4550 | G.global_argv[0], | ||
4551 | G.global_argv + 1); | ||
4501 | #endif | 4552 | #endif |
4502 | } | 4553 | } |
4503 | 4554 | ||
@@ -4561,34 +4612,34 @@ static int parse_group(o_string *dest, struct parse_context *ctx, | |||
4561 | 4612 | ||
4562 | debug_printf_parse("parse_group entered\n"); | 4613 | debug_printf_parse("parse_group entered\n"); |
4563 | #if ENABLE_HUSH_FUNCTIONS | 4614 | #if ENABLE_HUSH_FUNCTIONS |
4564 | if (ch == '(') { | 4615 | if (ch == '(' && !dest->o_quoted) { |
4565 | if (!dest->o_quoted) { | 4616 | if (dest->length) |
4566 | if (dest->length) | 4617 | done_word(dest, ctx); |
4567 | done_word(dest, ctx); | 4618 | if (!command->argv) |
4568 | if (!command->argv) | 4619 | goto skip; /* (... */ |
4569 | goto skip; /* (... */ | 4620 | if (command->argv[1]) { /* word word ... (... */ |
4570 | if (command->argv[1]) { /* word word ... (... */ | 4621 | syntax_error_unexpected_ch('('); |
4571 | syntax_error("unexpected character ("); | 4622 | return 1; |
4572 | return 1; | ||
4573 | } | ||
4574 | /* it is "word(..." or "word (..." */ | ||
4575 | do | ||
4576 | ch = i_getch(input); | ||
4577 | while (ch == ' ' || ch == '\t'); | ||
4578 | if (ch != ')') { | ||
4579 | syntax_error("unexpected character X"); | ||
4580 | return 1; | ||
4581 | } | ||
4582 | do | ||
4583 | ch = i_getch(input); | ||
4584 | while (ch == ' ' || ch == '\t' || ch == '\n'); | ||
4585 | if (ch != '{') { | ||
4586 | syntax_error("unexpected character X"); | ||
4587 | return 1; | ||
4588 | } | ||
4589 | command->grp_type = GRP_FUNCTION; | ||
4590 | goto skip; | ||
4591 | } | 4623 | } |
4624 | /* it is "word(..." or "word (..." */ | ||
4625 | do | ||
4626 | ch = i_getch(input); | ||
4627 | while (ch == ' ' || ch == '\t'); | ||
4628 | if (ch != ')') { | ||
4629 | syntax_error_unexpected_ch(ch); | ||
4630 | return 1; | ||
4631 | } | ||
4632 | nommu_addchr(&ctx->as_string, ch); | ||
4633 | do | ||
4634 | ch = i_getch(input); | ||
4635 | while (ch == ' ' || ch == '\t' || ch == '\n'); | ||
4636 | if (ch != '{') { | ||
4637 | syntax_error_unexpected_ch(ch); | ||
4638 | return 1; | ||
4639 | } | ||
4640 | nommu_addchr(&ctx->as_string, ch); | ||
4641 | command->grp_type = GRP_FUNCTION; | ||
4642 | goto skip; | ||
4592 | } | 4643 | } |
4593 | #endif | 4644 | #endif |
4594 | if (command->argv /* word [word]{... */ | 4645 | if (command->argv /* word [word]{... */ |
@@ -5452,7 +5503,7 @@ static struct pipe *parse_stream(char **pstring, | |||
5452 | /* proper use of this character is caught by end_trigger: | 5503 | /* proper use of this character is caught by end_trigger: |
5453 | * if we see {, we call parse_group(..., end_trigger='}') | 5504 | * if we see {, we call parse_group(..., end_trigger='}') |
5454 | * and it will match } earlier (not here). */ | 5505 | * and it will match } earlier (not here). */ |
5455 | syntax_error("unexpected } or )"); | 5506 | syntax_error_unexpected_ch(ch); |
5456 | goto parse_error; | 5507 | goto parse_error; |
5457 | default: | 5508 | default: |
5458 | if (HUSH_DEBUG) | 5509 | if (HUSH_DEBUG) |