diff options
| author | Denis Vlasenko <vda.linux@googlemail.com> | 2009-04-10 19:05:43 +0000 |
|---|---|---|
| committer | Denis Vlasenko <vda.linux@googlemail.com> | 2009-04-10 19:05:43 +0000 |
| commit | b7d8c0dbbd250649d647142edd33226822f3c879 (patch) | |
| tree | a315a2c6a2fa6b062fe66aacf0eea66587737a54 /shell | |
| parent | 835fcfd33d574d471d9b67a69116281d9ff42040 (diff) | |
| download | busybox-w32-b7d8c0dbbd250649d647142edd33226822f3c879.tar.gz busybox-w32-b7d8c0dbbd250649d647142edd33226822f3c879.tar.bz2 busybox-w32-b7d8c0dbbd250649d647142edd33226822f3c879.zip | |
hush: first stab at function support. argv passing is not coded yet.
Only very rudimentary testing was done.
With function support off, code growth is zero, with it on:
function old new delta
run_list 2158 2339 +181
parse_stream 1929 2044 +115
find_builtin 24 67 +43
find_function - 36 +36
file_get 244 264 +20
pseudo_exec_argv 145 160 +15
free_strings - 7 +7
free_pipe 183 181 -2
done_word 735 728 -7
expand_variables 2227 2204 -23
------------------------------------------------------------------------------
(add/remove: 2/0 grow/shrink: 5/3 up/down: 417/-32) Total: 385 bytes
Diffstat (limited to 'shell')
| -rw-r--r-- | shell/hush.c | 233 |
1 files changed, 169 insertions, 64 deletions
diff --git a/shell/hush.c b/shell/hush.c index 9adf0e127..3728583fc 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
| @@ -86,7 +86,7 @@ | |||
| 86 | */ | 86 | */ |
| 87 | #define HUSH_DEBUG 1 | 87 | #define HUSH_DEBUG 1 |
| 88 | /* In progress... */ | 88 | /* In progress... */ |
| 89 | #define ENABLE_HUSH_FUNCTIONS 0 | 89 | #define ENABLE_HUSH_FUNCTIONS 1 |
| 90 | 90 | ||
| 91 | 91 | ||
| 92 | #if BUILD_AS_NOMMU | 92 | #if BUILD_AS_NOMMU |
| @@ -374,12 +374,12 @@ struct command { | |||
| 374 | #define GRP_NORMAL 0 | 374 | #define GRP_NORMAL 0 |
| 375 | #define GRP_SUBSHELL 1 | 375 | #define GRP_SUBSHELL 1 |
| 376 | #if ENABLE_HUSH_FUNCTIONS | 376 | #if ENABLE_HUSH_FUNCTIONS |
| 377 | #define GRP_FUNCTION 2 | 377 | # define GRP_FUNCTION 2 |
| 378 | #endif | 378 | #endif |
| 379 | 379 | ||
| 380 | struct pipe { | 380 | struct pipe { |
| 381 | struct pipe *next; | 381 | struct pipe *next; |
| 382 | int num_cmds; /* total number of commands in job */ | 382 | int num_cmds; /* total number of commands in pipe */ |
| 383 | int alive_cmds; /* number of commands running (not exited) */ | 383 | int alive_cmds; /* number of commands running (not exited) */ |
| 384 | int stopped_cmds; /* number of commands alive, but stopped */ | 384 | int stopped_cmds; /* number of commands alive, but stopped */ |
| 385 | #if ENABLE_HUSH_JOB | 385 | #if ENABLE_HUSH_JOB |
| @@ -452,6 +452,12 @@ enum { | |||
| 452 | BC_CONTINUE = 2, | 452 | BC_CONTINUE = 2, |
| 453 | }; | 453 | }; |
| 454 | 454 | ||
| 455 | struct function { | ||
| 456 | struct function *next; | ||
| 457 | char *name; | ||
| 458 | struct pipe *body; | ||
| 459 | }; | ||
| 460 | |||
| 455 | 461 | ||
| 456 | /* "Globals" within this file */ | 462 | /* "Globals" within this file */ |
| 457 | /* Sorted roughly by size (smaller offsets == smaller code) */ | 463 | /* Sorted roughly by size (smaller offsets == smaller code) */ |
| @@ -504,6 +510,7 @@ struct globals { | |||
| 504 | const char *cwd; | 510 | const char *cwd; |
| 505 | struct variable *top_var; /* = &G.shell_ver (set in main()) */ | 511 | struct variable *top_var; /* = &G.shell_ver (set in main()) */ |
| 506 | struct variable shell_ver; | 512 | struct variable shell_ver; |
| 513 | struct function *top_func; | ||
| 507 | /* Signal and trap handling */ | 514 | /* Signal and trap handling */ |
| 508 | // unsigned count_SIGCHLD; | 515 | // unsigned count_SIGCHLD; |
| 509 | // unsigned handled_SIGCHLD; | 516 | // unsigned handled_SIGCHLD; |
| @@ -2585,6 +2592,35 @@ static void free_pipe_list(struct pipe *head, int indent) | |||
| 2585 | } | 2592 | } |
| 2586 | 2593 | ||
| 2587 | 2594 | ||
| 2595 | static const struct built_in_command* find_builtin(const char *name) | ||
| 2596 | { | ||
| 2597 | const struct built_in_command *x; | ||
| 2598 | for (x = bltins; x != &bltins[ARRAY_SIZE(bltins)]; x++) { | ||
| 2599 | if (strcmp(name, x->cmd) != 0) | ||
| 2600 | continue; | ||
| 2601 | debug_printf_exec("found builtin '%s'\n", name); | ||
| 2602 | return x; | ||
| 2603 | } | ||
| 2604 | return NULL; | ||
| 2605 | } | ||
| 2606 | |||
| 2607 | # if ENABLE_HUSH_FUNCTIONS | ||
| 2608 | static const struct function *find_function(const char *name) | ||
| 2609 | { | ||
| 2610 | const struct function *funcp = G.top_func; | ||
| 2611 | while (funcp) { | ||
| 2612 | if (strcmp(name, funcp->name) != 0) | ||
| 2613 | continue; | ||
| 2614 | return funcp; | ||
| 2615 | debug_printf_exec("found function '%s'\n", name); | ||
| 2616 | } | ||
| 2617 | return NULL; | ||
| 2618 | } | ||
| 2619 | #endif | ||
| 2620 | |||
| 2621 | |||
| 2622 | static int run_list(struct pipe *pi); | ||
| 2623 | |||
| 2588 | #if BB_MMU | 2624 | #if BB_MMU |
| 2589 | #define pseudo_exec_argv(nommu_save, argv, assignment_cnt, argv_expanded) \ | 2625 | #define pseudo_exec_argv(nommu_save, argv, assignment_cnt, argv_expanded) \ |
| 2590 | pseudo_exec_argv(argv, assignment_cnt, argv_expanded) | 2626 | pseudo_exec_argv(argv, assignment_cnt, argv_expanded) |
| @@ -2627,6 +2663,11 @@ static void pseudo_exec_argv(nommu_save_t *nommu_save, | |||
| 2627 | #endif | 2663 | #endif |
| 2628 | } | 2664 | } |
| 2629 | 2665 | ||
| 2666 | #if ENABLE_FEATURE_SH_STANDALONE || BB_MMU | ||
| 2667 | if (strchr(argv[0], '/') != NULL) | ||
| 2668 | goto skip; | ||
| 2669 | #endif | ||
| 2670 | |||
| 2630 | /* On NOMMU, we must never block! | 2671 | /* On NOMMU, we must never block! |
| 2631 | * Example: { sleep 99999 | read line } & echo Ok | 2672 | * Example: { sleep 99999 | read line } & echo Ok |
| 2632 | * read builtin will block on read syscall, leaving parent blocked | 2673 | * read builtin will block on read syscall, leaving parent blocked |
| @@ -2640,30 +2681,38 @@ static void pseudo_exec_argv(nommu_save_t *nommu_save, | |||
| 2640 | */ | 2681 | */ |
| 2641 | { | 2682 | { |
| 2642 | int rcode; | 2683 | int rcode; |
| 2643 | const struct built_in_command *x; | 2684 | const struct built_in_command *x = find_builtin(argv[0]); |
| 2644 | for (x = bltins; x != &bltins[ARRAY_SIZE(bltins)]; x++) { | 2685 | if (x) { |
| 2645 | if (strcmp(argv[0], x->cmd) == 0) { | 2686 | rcode = x->function(argv); |
| 2646 | debug_printf_exec("running builtin '%s'\n", | 2687 | fflush(NULL); |
| 2647 | argv[0]); | 2688 | _exit(rcode); |
| 2648 | rcode = x->function(argv); | ||
| 2649 | fflush(NULL); | ||
| 2650 | _exit(rcode); | ||
| 2651 | } | ||
| 2652 | } | 2689 | } |
| 2653 | } | 2690 | } |
| 2691 | # if ENABLE_HUSH_FUNCTIONS | ||
| 2692 | /* Check if the command matches any functions */ | ||
| 2693 | { | ||
| 2694 | int rcode; | ||
| 2695 | const struct function *funcp = find_function(argv[0]); | ||
| 2696 | if (funcp) { | ||
| 2697 | rcode = run_list(funcp->body); | ||
| 2698 | fflush(NULL); | ||
| 2699 | _exit(rcode); | ||
| 2700 | } | ||
| 2701 | } | ||
| 2702 | # endif | ||
| 2654 | #endif | 2703 | #endif |
| 2655 | 2704 | ||
| 2656 | #if ENABLE_FEATURE_SH_STANDALONE | 2705 | #if ENABLE_FEATURE_SH_STANDALONE |
| 2657 | /* Check if the command matches any busybox applets */ | 2706 | /* Check if the command matches any busybox applets */ |
| 2658 | if (strchr(argv[0], '/') == NULL) { | 2707 | { |
| 2659 | int a = find_applet_by_name(argv[0]); | 2708 | int a = find_applet_by_name(argv[0]); |
| 2660 | if (a >= 0) { | 2709 | if (a >= 0) { |
| 2661 | #if BB_MMU /* see above why on NOMMU it is not allowed */ | 2710 | # if BB_MMU /* see above why on NOMMU it is not allowed */ |
| 2662 | if (APPLET_IS_NOEXEC(a)) { | 2711 | if (APPLET_IS_NOEXEC(a)) { |
| 2663 | debug_printf_exec("running applet '%s'\n", argv[0]); | 2712 | debug_printf_exec("running applet '%s'\n", argv[0]); |
| 2664 | run_applet_no_and_exit(a, argv); | 2713 | run_applet_no_and_exit(a, argv); |
| 2665 | } | 2714 | } |
| 2666 | #endif | 2715 | # endif |
| 2667 | /* Re-exec ourselves */ | 2716 | /* Re-exec ourselves */ |
| 2668 | debug_printf_exec("re-execing applet '%s'\n", argv[0]); | 2717 | debug_printf_exec("re-execing applet '%s'\n", argv[0]); |
| 2669 | sigprocmask(SIG_SETMASK, &G.inherited_set, NULL); | 2718 | sigprocmask(SIG_SETMASK, &G.inherited_set, NULL); |
| @@ -2674,6 +2723,7 @@ static void pseudo_exec_argv(nommu_save_t *nommu_save, | |||
| 2674 | } | 2723 | } |
| 2675 | #endif | 2724 | #endif |
| 2676 | 2725 | ||
| 2726 | skip: | ||
| 2677 | debug_printf_exec("execing '%s'\n", argv[0]); | 2727 | debug_printf_exec("execing '%s'\n", argv[0]); |
| 2678 | sigprocmask(SIG_SETMASK, &G.inherited_set, NULL); | 2728 | sigprocmask(SIG_SETMASK, &G.inherited_set, NULL); |
| 2679 | execvp(argv[0], argv); | 2729 | execvp(argv[0], argv); |
| @@ -2681,8 +2731,6 @@ static void pseudo_exec_argv(nommu_save_t *nommu_save, | |||
| 2681 | _exit(EXIT_FAILURE); | 2731 | _exit(EXIT_FAILURE); |
| 2682 | } | 2732 | } |
| 2683 | 2733 | ||
| 2684 | static int run_list(struct pipe *pi); | ||
| 2685 | |||
| 2686 | /* Called after [v]fork() in run_pipe | 2734 | /* Called after [v]fork() in run_pipe |
| 2687 | */ | 2735 | */ |
| 2688 | static void pseudo_exec(nommu_save_t *nommu_save, | 2736 | static void pseudo_exec(nommu_save_t *nommu_save, |
| @@ -3031,8 +3079,35 @@ static int run_pipe(struct pipe *pi) | |||
| 3031 | if (command->group) { | 3079 | if (command->group) { |
| 3032 | #if ENABLE_HUSH_FUNCTIONS | 3080 | #if ENABLE_HUSH_FUNCTIONS |
| 3033 | if (command->grp_type == GRP_FUNCTION) { | 3081 | if (command->grp_type == GRP_FUNCTION) { |
| 3034 | /* func () { list } */ | 3082 | /* "executing" func () { list } */ |
| 3035 | bb_error_msg("here we ought to remember function definition, and go on"); | 3083 | struct function *funcp; |
| 3084 | struct function **funcpp = &G.top_func; | ||
| 3085 | |||
| 3086 | while ((funcp = *funcpp) != NULL) { | ||
| 3087 | if (strcmp(funcp->name, command->argv[0]) == 0) { | ||
| 3088 | debug_printf_exec("replacing function '%s'", funcp->name); | ||
| 3089 | free(funcp->name); | ||
| 3090 | free_pipe_list(funcp->body, /* indent: */ 0); | ||
| 3091 | goto skip; | ||
| 3092 | } | ||
| 3093 | funcpp = &funcp->next; | ||
| 3094 | } | ||
| 3095 | debug_printf_exec("remembering new function '%s'", funcp->name); | ||
| 3096 | funcp = *funcpp = xzalloc(sizeof(*funcp)); | ||
| 3097 | /*funcp->next = NULL;*/ | ||
| 3098 | skip: | ||
| 3099 | funcp->name = command->argv[0]; | ||
| 3100 | funcp->body = command->group; | ||
| 3101 | command->group = NULL; | ||
| 3102 | command->argv[0] = NULL; | ||
| 3103 | free_strings(command->argv); | ||
| 3104 | command->argv = NULL; | ||
| 3105 | /* note: if we are in a loop, future "executions" | ||
| 3106 | * of func def will see it as null command since | ||
| 3107 | * command->group == NULL and command->argv == NULL */ | ||
| 3108 | //this isn't exactly right: while...do f1() {a;}; f1; f1 {b;}; done | ||
| 3109 | //second loop will execute b! | ||
| 3110 | |||
| 3036 | return EXIT_SUCCESS; | 3111 | return EXIT_SUCCESS; |
| 3037 | } | 3112 | } |
| 3038 | #endif | 3113 | #endif |
| @@ -3052,6 +3127,11 @@ static int run_pipe(struct pipe *pi) | |||
| 3052 | argv = command->argv ? command->argv : (char **) &null_ptr; | 3127 | argv = command->argv ? command->argv : (char **) &null_ptr; |
| 3053 | { | 3128 | { |
| 3054 | const struct built_in_command *x; | 3129 | const struct built_in_command *x; |
| 3130 | #if ENABLE_HUSH_FUNCTIONS | ||
| 3131 | const struct function *funcp; | ||
| 3132 | #else | ||
| 3133 | enum { funcp = 0 }; | ||
| 3134 | #endif | ||
| 3055 | char **new_env = NULL; | 3135 | char **new_env = NULL; |
| 3056 | char **old_env = NULL; | 3136 | char **old_env = NULL; |
| 3057 | 3137 | ||
| @@ -3078,13 +3158,18 @@ static int run_pipe(struct pipe *pi) | |||
| 3078 | /* Expand the rest into (possibly) many strings each */ | 3158 | /* Expand the rest into (possibly) many strings each */ |
| 3079 | argv_expanded = expand_strvec_to_strvec(argv + command->assignment_cnt); | 3159 | argv_expanded = expand_strvec_to_strvec(argv + command->assignment_cnt); |
| 3080 | 3160 | ||
| 3081 | for (x = bltins; x != &bltins[ARRAY_SIZE(bltins)]; x++) { | 3161 | x = find_builtin(argv_expanded[0]); |
| 3082 | if (strcmp(argv_expanded[0], x->cmd) != 0) | 3162 | #if ENABLE_HUSH_FUNCTIONS |
| 3083 | continue; | 3163 | if (!x) |
| 3084 | if (x->function == builtin_exec && argv_expanded[1] == NULL) { | 3164 | funcp = find_function(argv_expanded[0]); |
| 3085 | debug_printf("exec with redirects only\n"); | 3165 | #endif |
| 3086 | rcode = setup_redirects(command, NULL); | 3166 | if (x || funcp) { |
| 3087 | goto clean_up_and_ret1; | 3167 | if (!funcp) { |
| 3168 | if (x->function == builtin_exec && argv_expanded[1] == NULL) { | ||
| 3169 | debug_printf("exec with redirects only\n"); | ||
| 3170 | rcode = setup_redirects(command, NULL); | ||
| 3171 | goto clean_up_and_ret1; | ||
| 3172 | } | ||
| 3088 | } | 3173 | } |
| 3089 | debug_printf("builtin inline %s\n", argv_expanded[0]); | 3174 | debug_printf("builtin inline %s\n", argv_expanded[0]); |
| 3090 | /* XXX setup_redirects acts on file descriptors, not FILEs. | 3175 | /* XXX setup_redirects acts on file descriptors, not FILEs. |
| @@ -3095,9 +3180,18 @@ static int run_pipe(struct pipe *pi) | |||
| 3095 | if (rcode == 0) { | 3180 | if (rcode == 0) { |
| 3096 | new_env = expand_assignments(argv, command->assignment_cnt); | 3181 | new_env = expand_assignments(argv, command->assignment_cnt); |
| 3097 | old_env = putenv_all_and_save_old(new_env); | 3182 | old_env = putenv_all_and_save_old(new_env); |
| 3098 | debug_printf_exec(": builtin '%s' '%s'...\n", | 3183 | if (!funcp) { |
| 3184 | debug_printf_exec(": builtin '%s' '%s'...\n", | ||
| 3099 | x->cmd, argv_expanded[1]); | 3185 | x->cmd, argv_expanded[1]); |
| 3100 | rcode = x->function(argv_expanded) & 0xff; | 3186 | rcode = x->function(argv_expanded) & 0xff; |
| 3187 | } | ||
| 3188 | #if ENABLE_HUSH_FUNCTIONS | ||
| 3189 | else { | ||
| 3190 | debug_printf_exec(": function '%s' '%s'...\n", | ||
| 3191 | funcp->name, argv_expanded[1]); | ||
| 3192 | rcode = run_list(funcp->body) & 0xff; | ||
| 3193 | } | ||
| 3194 | #endif | ||
| 3101 | } | 3195 | } |
| 3102 | #if ENABLE_FEATURE_SH_STANDALONE | 3196 | #if ENABLE_FEATURE_SH_STANDALONE |
| 3103 | clean_up_and_ret: | 3197 | clean_up_and_ret: |
| @@ -3114,6 +3208,7 @@ static int run_pipe(struct pipe *pi) | |||
| 3114 | debug_printf_exec("run_pipe return %d\n", rcode); | 3208 | debug_printf_exec("run_pipe return %d\n", rcode); |
| 3115 | return rcode; | 3209 | return rcode; |
| 3116 | } | 3210 | } |
| 3211 | |||
| 3117 | #if ENABLE_FEATURE_SH_STANDALONE | 3212 | #if ENABLE_FEATURE_SH_STANDALONE |
| 3118 | i = find_applet_by_name(argv_expanded[0]); | 3213 | i = find_applet_by_name(argv_expanded[0]); |
| 3119 | if (i >= 0 && APPLET_IS_NOFORK(i)) { | 3214 | if (i >= 0 && APPLET_IS_NOFORK(i)) { |
| @@ -4081,6 +4176,10 @@ static int done_word(o_string *word, struct parse_context *ctx) | |||
| 4081 | } | 4176 | } |
| 4082 | } | 4177 | } |
| 4083 | command->argv = add_string_to_strings(command->argv, xstrdup(word->data)); | 4178 | command->argv = add_string_to_strings(command->argv, xstrdup(word->data)); |
| 4179 | //SEGV, but good idea. | ||
| 4180 | // command->argv = add_string_to_strings(command->argv, word->data); | ||
| 4181 | // word->data = NULL; | ||
| 4182 | // word->length = 0; | ||
| 4084 | debug_print_strings("word appended to argv", command->argv); | 4183 | debug_print_strings("word appended to argv", command->argv); |
| 4085 | } | 4184 | } |
| 4086 | 4185 | ||
| @@ -4089,7 +4188,7 @@ static int done_word(o_string *word, struct parse_context *ctx) | |||
| 4089 | if (word->o_quoted | 4188 | if (word->o_quoted |
| 4090 | || !is_well_formed_var_name(command->argv[0], '\0') | 4189 | || !is_well_formed_var_name(command->argv[0], '\0') |
| 4091 | ) { | 4190 | ) { |
| 4092 | /* bash says "not a valid identifier" */ | 4191 | /* bash says just "not a valid identifier" */ |
| 4093 | syntax_error("not a valid identifier in for"); | 4192 | syntax_error("not a valid identifier in for"); |
| 4094 | return 1; | 4193 | return 1; |
| 4095 | } | 4194 | } |
| @@ -4462,27 +4561,55 @@ static int parse_group(o_string *dest, struct parse_context *ctx, | |||
| 4462 | 4561 | ||
| 4463 | debug_printf_parse("parse_group entered\n"); | 4562 | debug_printf_parse("parse_group entered\n"); |
| 4464 | #if ENABLE_HUSH_FUNCTIONS | 4563 | #if ENABLE_HUSH_FUNCTIONS |
| 4465 | if (ch == 'F') { /* function definition? */ | 4564 | if (ch == '(') { |
| 4466 | bb_error_msg("aha '%s' is a function, parsing it...", dest->data); | 4565 | if (!dest->o_quoted) { |
| 4467 | //command->fname = dest->data; | 4566 | if (dest->length) |
| 4468 | command->grp_type = GRP_FUNCTION; | 4567 | done_word(dest, ctx); |
| 4469 | memset(dest, 0, sizeof(*dest)); | 4568 | if (!command->argv) |
| 4569 | goto skip; /* (... */ | ||
| 4570 | if (command->argv[1]) { /* word word ... (... */ | ||
| 4571 | syntax_error("unexpected character ("); | ||
| 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 | } | ||
| 4470 | } | 4592 | } |
| 4471 | #endif | 4593 | #endif |
| 4472 | if (command->argv /* word [word](... */ | 4594 | if (command->argv /* word [word]{... */ |
| 4473 | || dest->length /* word(... */ | 4595 | || dest->length /* word{... */ |
| 4474 | || dest->o_quoted /* ""(... */ | 4596 | || dest->o_quoted /* ""{... */ |
| 4475 | ) { | 4597 | ) { |
| 4476 | syntax_error(NULL); | 4598 | syntax_error(NULL); |
| 4477 | debug_printf_parse("parse_group return 1: " | 4599 | debug_printf_parse("parse_group return 1: " |
| 4478 | "syntax error, groups and arglists don't mix\n"); | 4600 | "syntax error, groups and arglists don't mix\n"); |
| 4479 | return 1; | 4601 | return 1; |
| 4480 | } | 4602 | } |
| 4603 | |||
| 4604 | #if ENABLE_HUSH_FUNCTIONS | ||
| 4605 | skip: | ||
| 4606 | #endif | ||
| 4481 | endch = '}'; | 4607 | endch = '}'; |
| 4482 | if (ch == '(') { | 4608 | if (ch == '(') { |
| 4483 | endch = ')'; | 4609 | endch = ')'; |
| 4484 | command->grp_type = GRP_SUBSHELL; | 4610 | command->grp_type = GRP_SUBSHELL; |
| 4485 | } | 4611 | } |
| 4612 | |||
| 4486 | { | 4613 | { |
| 4487 | #if !BB_MMU | 4614 | #if !BB_MMU |
| 4488 | char *as_string = NULL; | 4615 | char *as_string = NULL; |
| @@ -5311,28 +5438,6 @@ static struct pipe *parse_stream(char **pstring, | |||
| 5311 | continue; | 5438 | continue; |
| 5312 | } | 5439 | } |
| 5313 | #endif | 5440 | #endif |
| 5314 | #if ENABLE_HUSH_FUNCTIONS | ||
| 5315 | if (dest.length != 0 /* not just () but word() */ | ||
| 5316 | && dest.o_quoted == 0 /* not a"b"c() */ | ||
| 5317 | && ctx.command->argv == NULL /* it's the first word */ | ||
| 5318 | //TODO: "func ( ) {...}" - note spaces - is valid format too in bash | ||
| 5319 | && i_peek(input) == ')' | ||
| 5320 | && !match_reserved_word(&dest) | ||
| 5321 | ) { | ||
| 5322 | bb_error_msg("seems like a function definition"); | ||
| 5323 | i_getch(input); | ||
| 5324 | //if !BB_MMU o_addchr(&ctx.as_string... | ||
| 5325 | do { | ||
| 5326 | //TODO: do it properly. | ||
| 5327 | ch = i_getch(input); | ||
| 5328 | } while (ch == ' ' || ch == '\n'); | ||
| 5329 | if (ch != '{') { | ||
| 5330 | syntax_error("was expecting {"); | ||
| 5331 | goto parse_error; | ||
| 5332 | } | ||
| 5333 | ch = 'F'; /* magic value */ | ||
| 5334 | } | ||
| 5335 | #endif | ||
| 5336 | case '{': | 5441 | case '{': |
| 5337 | if (parse_group(&dest, &ctx, input, ch) != 0) { | 5442 | if (parse_group(&dest, &ctx, input, ch) != 0) { |
| 5338 | goto parse_error; | 5443 | goto parse_error; |
| @@ -6427,11 +6532,11 @@ static int builtin_unset(char **argv) | |||
| 6427 | ret = EXIT_FAILURE; | 6532 | ret = EXIT_FAILURE; |
| 6428 | } | 6533 | } |
| 6429 | } | 6534 | } |
| 6430 | #if ENABLE_HUSH_FUNCTIONS | 6535 | //#if ENABLE_HUSH_FUNCTIONS |
| 6431 | else { | 6536 | // else { |
| 6432 | unset_local_func(*argv); | 6537 | // unset_local_func(*argv); |
| 6433 | } | 6538 | // } |
| 6434 | #endif | 6539 | //#endif |
| 6435 | argv++; | 6540 | argv++; |
| 6436 | } | 6541 | } |
| 6437 | return ret; | 6542 | return ret; |
