diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2009-04-17 23:44:18 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2009-04-17 23:44:18 +0000 |
commit | 3d40d8e65534a7805393c3c9dfadba097f8d07f3 (patch) | |
tree | 53e4e3a0a7eb0c2ed614411f2746f8c2950f50bd /shell | |
parent | 3be2308676607bdb0e901d439e288081c39011a4 (diff) | |
download | busybox-w32-3d40d8e65534a7805393c3c9dfadba097f8d07f3.tar.gz busybox-w32-3d40d8e65534a7805393c3c9dfadba097f8d07f3.tar.bz2 busybox-w32-3d40d8e65534a7805393c3c9dfadba097f8d07f3.zip |
hush: return builtin by Bayram Kurumahmut (kbayram AT ubicom.com)
~+200 bytes
Diffstat (limited to 'shell')
-rw-r--r-- | shell/hush.c | 93 | ||||
-rw-r--r-- | shell/hush_test/hush-misc/func3.right | 4 | ||||
-rwxr-xr-x | shell/hush_test/hush-misc/func3.tests | 8 |
3 files changed, 91 insertions, 14 deletions
diff --git a/shell/hush.c b/shell/hush.c index 84364e0e7..82634ff83 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
@@ -444,6 +444,13 @@ struct globals { | |||
444 | #if ENABLE_HUSH_LOOPS | 444 | #if ENABLE_HUSH_LOOPS |
445 | smallint flag_break_continue; | 445 | smallint flag_break_continue; |
446 | #endif | 446 | #endif |
447 | #if ENABLE_HUSH_FUNCTIONS | ||
448 | /* 0: outside of a function (or sourced file) | ||
449 | * -1: inside of a function, ok to use return builtin | ||
450 | * 1: return is invoked, skip all till end of func. | ||
451 | */ | ||
452 | smallint flag_return_in_progress; | ||
453 | #endif | ||
447 | smallint fake_mode; | 454 | smallint fake_mode; |
448 | smallint exiting; /* used to prevent EXIT trap recursion */ | 455 | smallint exiting; /* used to prevent EXIT trap recursion */ |
449 | /* These four support $?, $#, and $1 */ | 456 | /* These four support $?, $#, and $1 */ |
@@ -522,6 +529,9 @@ static int builtin_wait(char **argv); | |||
522 | static int builtin_break(char **argv); | 529 | static int builtin_break(char **argv); |
523 | static int builtin_continue(char **argv); | 530 | static int builtin_continue(char **argv); |
524 | #endif | 531 | #endif |
532 | #if ENABLE_HUSH_FUNCTIONS | ||
533 | static int builtin_return(char **argv); | ||
534 | #endif | ||
525 | 535 | ||
526 | /* Table of built-in functions. They can be forked or not, depending on | 536 | /* Table of built-in functions. They can be forked or not, depending on |
527 | * context: within pipes, they fork. As simple commands, they do not. | 537 | * context: within pipes, they fork. As simple commands, they do not. |
@@ -575,7 +585,9 @@ static const struct built_in_command bltins[] = { | |||
575 | #endif | 585 | #endif |
576 | BLTIN("pwd" , builtin_pwd , "Print current directory"), | 586 | BLTIN("pwd" , builtin_pwd , "Print current directory"), |
577 | BLTIN("read" , builtin_read , "Input environment variable"), | 587 | BLTIN("read" , builtin_read , "Input environment variable"), |
578 | // BLTIN("return" , builtin_return , "Return from a function"), | 588 | #if ENABLE_HUSH_FUNCTIONS |
589 | BLTIN("return" , builtin_return , "Return from a function"), | ||
590 | #endif | ||
579 | BLTIN("set" , builtin_set , "Set/unset shell local variables"), | 591 | BLTIN("set" , builtin_set , "Set/unset shell local variables"), |
580 | BLTIN("shift" , builtin_shift , "Shift positional parameters"), | 592 | BLTIN("shift" , builtin_shift , "Shift positional parameters"), |
581 | BLTIN("test" , builtin_test , "Test condition"), | 593 | BLTIN("test" , builtin_test , "Test condition"), |
@@ -2849,9 +2861,14 @@ static void exec_function(nommu_save_t *nommu_save, | |||
2849 | static int run_function(const struct function *funcp, char **argv) | 2861 | static int run_function(const struct function *funcp, char **argv) |
2850 | { | 2862 | { |
2851 | int rc; | 2863 | int rc; |
2864 | smallint sv_flg; | ||
2852 | save_arg_t sv; | 2865 | save_arg_t sv; |
2853 | 2866 | ||
2854 | save_and_replace_G_args(&sv, argv); | 2867 | save_and_replace_G_args(&sv, argv); |
2868 | /* "we are in function, ok to use return" */ | ||
2869 | sv_flg = G.flag_return_in_progress; | ||
2870 | G.flag_return_in_progress = -1; | ||
2871 | |||
2855 | /* On MMU, funcp->body is always non-NULL */ | 2872 | /* On MMU, funcp->body is always non-NULL */ |
2856 | #if !BB_MMU | 2873 | #if !BB_MMU |
2857 | if (!funcp->body) { | 2874 | if (!funcp->body) { |
@@ -2863,6 +2880,8 @@ static int run_function(const struct function *funcp, char **argv) | |||
2863 | { | 2880 | { |
2864 | rc = run_list(funcp->body); | 2881 | rc = run_list(funcp->body); |
2865 | } | 2882 | } |
2883 | |||
2884 | G.flag_return_in_progress = sv_flg; | ||
2866 | restore_G_args(&sv, argv); | 2885 | restore_G_args(&sv, argv); |
2867 | 2886 | ||
2868 | return rc; | 2887 | return rc; |
@@ -3886,7 +3905,8 @@ static int run_list(struct pipe *pi) | |||
3886 | #endif | 3905 | #endif |
3887 | rcode = r = run_pipe(pi); /* NB: rcode is a smallint */ | 3906 | rcode = r = run_pipe(pi); /* NB: rcode is a smallint */ |
3888 | if (r != -1) { | 3907 | if (r != -1) { |
3889 | /* We only ran a builtin: rcode is already known | 3908 | /* We ran a builtin, function, or group. |
3909 | * rcode is already known | ||
3890 | * and we don't need to wait for anything. */ | 3910 | * and we don't need to wait for anything. */ |
3891 | G.last_exitcode = rcode; | 3911 | G.last_exitcode = rcode; |
3892 | debug_printf_exec(": builtin/func exitcode %d\n", rcode); | 3912 | debug_printf_exec(": builtin/func exitcode %d\n", rcode); |
@@ -3910,6 +3930,10 @@ static int run_list(struct pipe *pi) | |||
3910 | continue; | 3930 | continue; |
3911 | } | 3931 | } |
3912 | #endif | 3932 | #endif |
3933 | #if ENABLE_HUSH_FUNCTIONS | ||
3934 | if (G.flag_return_in_progress == 1) | ||
3935 | goto check_jobs_and_break; | ||
3936 | #endif | ||
3913 | } else if (pi->followup == PIPE_BG) { | 3937 | } else if (pi->followup == PIPE_BG) { |
3914 | /* What does bash do with attempts to background builtins? */ | 3938 | /* What does bash do with attempts to background builtins? */ |
3915 | /* even bash 3.2 doesn't do that well with nested bg: | 3939 | /* even bash 3.2 doesn't do that well with nested bg: |
@@ -6675,6 +6699,7 @@ static int builtin_shift(char **argv) | |||
6675 | static int builtin_source(char **argv) | 6699 | static int builtin_source(char **argv) |
6676 | { | 6700 | { |
6677 | FILE *input; | 6701 | FILE *input; |
6702 | smallint sv_flg; | ||
6678 | save_arg_t sv; | 6703 | save_arg_t sv; |
6679 | 6704 | ||
6680 | if (*++argv == NULL) | 6705 | if (*++argv == NULL) |
@@ -6688,12 +6713,17 @@ static int builtin_source(char **argv) | |||
6688 | } | 6713 | } |
6689 | close_on_exec_on(fileno(input)); | 6714 | close_on_exec_on(fileno(input)); |
6690 | 6715 | ||
6691 | /* Now run the file */ | 6716 | sv_flg = G.flag_return_in_progress; |
6717 | /* "we are inside sourced file, ok to use return" */ | ||
6718 | G.flag_return_in_progress = -1; | ||
6692 | save_and_replace_G_args(&sv, argv); | 6719 | save_and_replace_G_args(&sv, argv); |
6720 | |||
6693 | parse_and_run_file(input); | 6721 | parse_and_run_file(input); |
6694 | restore_G_args(&sv, argv); | ||
6695 | fclose(input); | 6722 | fclose(input); |
6696 | 6723 | ||
6724 | restore_G_args(&sv, argv); | ||
6725 | G.flag_return_in_progress = sv_flg; | ||
6726 | |||
6697 | return G.last_exitcode; | 6727 | return G.last_exitcode; |
6698 | } | 6728 | } |
6699 | 6729 | ||
@@ -6833,25 +6863,36 @@ static int builtin_wait(char **argv) | |||
6833 | return ret; | 6863 | return ret; |
6834 | } | 6864 | } |
6835 | 6865 | ||
6866 | #if ENABLE_HUSH_LOOPS || ENABLE_HUSH_FUNCTIONS | ||
6867 | static unsigned parse_numeric_argv1(char **argv, unsigned def, unsigned def_min) | ||
6868 | { | ||
6869 | if (argv[1]) { | ||
6870 | def = bb_strtou(argv[1], NULL, 10); | ||
6871 | if (errno || def < def_min || argv[2]) { | ||
6872 | bb_error_msg("%s: bad arguments", argv[0]); | ||
6873 | def = UINT_MAX; | ||
6874 | } | ||
6875 | } | ||
6876 | return def; | ||
6877 | } | ||
6878 | #endif | ||
6879 | |||
6836 | #if ENABLE_HUSH_LOOPS | 6880 | #if ENABLE_HUSH_LOOPS |
6837 | static int builtin_break(char **argv) | 6881 | static int builtin_break(char **argv) |
6838 | { | 6882 | { |
6883 | unsigned depth; | ||
6839 | if (G.depth_of_loop == 0) { | 6884 | if (G.depth_of_loop == 0) { |
6840 | bb_error_msg("%s: only meaningful in a loop", argv[0]); | 6885 | bb_error_msg("%s: only meaningful in a loop", argv[0]); |
6841 | return EXIT_SUCCESS; /* bash compat */ | 6886 | return EXIT_SUCCESS; /* bash compat */ |
6842 | } | 6887 | } |
6843 | G.flag_break_continue++; /* BC_BREAK = 1 */ | 6888 | G.flag_break_continue++; /* BC_BREAK = 1 */ |
6844 | G.depth_break_continue = 1; | 6889 | |
6845 | if (argv[1]) { | 6890 | G.depth_break_continue = depth = parse_numeric_argv1(argv, 1, 1); |
6846 | G.depth_break_continue = bb_strtou(argv[1], NULL, 10); | 6891 | if (depth == UINT_MAX) |
6847 | if (errno || !G.depth_break_continue || argv[2]) { | 6892 | G.flag_break_continue = BC_BREAK; |
6848 | bb_error_msg("%s: bad arguments", argv[0]); | 6893 | if (G.depth_of_loop < depth) |
6849 | G.flag_break_continue = BC_BREAK; | ||
6850 | G.depth_break_continue = UINT_MAX; | ||
6851 | } | ||
6852 | } | ||
6853 | if (G.depth_of_loop < G.depth_break_continue) | ||
6854 | G.depth_break_continue = G.depth_of_loop; | 6894 | G.depth_break_continue = G.depth_of_loop; |
6895 | |||
6855 | return EXIT_SUCCESS; | 6896 | return EXIT_SUCCESS; |
6856 | } | 6897 | } |
6857 | 6898 | ||
@@ -6861,3 +6902,27 @@ static int builtin_continue(char **argv) | |||
6861 | return builtin_break(argv); | 6902 | return builtin_break(argv); |
6862 | } | 6903 | } |
6863 | #endif | 6904 | #endif |
6905 | |||
6906 | #if ENABLE_HUSH_FUNCTIONS | ||
6907 | static int builtin_return(char **argv UNUSED_PARAM) | ||
6908 | { | ||
6909 | int rc; | ||
6910 | |||
6911 | if (G.flag_return_in_progress != -1) { | ||
6912 | bb_error_msg("%s: not in a function or sourced script", argv[0]); | ||
6913 | return EXIT_FAILURE; /* bash compat */ | ||
6914 | } | ||
6915 | |||
6916 | G.flag_return_in_progress = 1; | ||
6917 | |||
6918 | /* bash: | ||
6919 | * out of range: wraps around at 256, does not error out | ||
6920 | * non-numeric param: | ||
6921 | * f() { false; return qwe; }; f; echo $? | ||
6922 | * bash: return: qwe: numeric argument required <== we do this | ||
6923 | * 255 <== we also do this | ||
6924 | */ | ||
6925 | rc = parse_numeric_argv1(argv, G.last_exitcode, 0); | ||
6926 | return rc; | ||
6927 | } | ||
6928 | #endif | ||
diff --git a/shell/hush_test/hush-misc/func3.right b/shell/hush_test/hush-misc/func3.right new file mode 100644 index 000000000..b6d73459a --- /dev/null +++ b/shell/hush_test/hush-misc/func3.right | |||
@@ -0,0 +1,4 @@ | |||
1 | One:1 | ||
2 | Zero:0 | ||
3 | One:1 | ||
4 | Five:5 | ||
diff --git a/shell/hush_test/hush-misc/func3.tests b/shell/hush_test/hush-misc/func3.tests new file mode 100755 index 000000000..fa6f26a23 --- /dev/null +++ b/shell/hush_test/hush-misc/func3.tests | |||
@@ -0,0 +1,8 @@ | |||
1 | f() { false; return; echo BAD; }; | ||
2 | { f; echo One:$?; }; echo Zero:$? | ||
3 | |||
4 | f() { false; return; }; | ||
5 | f; echo One:$? | ||
6 | |||
7 | f() { return 5; }; | ||
8 | f; echo Five:$? | ||