summaryrefslogtreecommitdiff
path: root/shell
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2009-04-17 23:44:18 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2009-04-17 23:44:18 +0000
commit3d40d8e65534a7805393c3c9dfadba097f8d07f3 (patch)
tree53e4e3a0a7eb0c2ed614411f2746f8c2950f50bd /shell
parent3be2308676607bdb0e901d439e288081c39011a4 (diff)
downloadbusybox-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.c93
-rw-r--r--shell/hush_test/hush-misc/func3.right4
-rwxr-xr-xshell/hush_test/hush-misc/func3.tests8
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);
522static int builtin_break(char **argv); 529static int builtin_break(char **argv);
523static int builtin_continue(char **argv); 530static int builtin_continue(char **argv);
524#endif 531#endif
532#if ENABLE_HUSH_FUNCTIONS
533static 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,
2849static int run_function(const struct function *funcp, char **argv) 2861static 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)
6675static int builtin_source(char **argv) 6699static 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
6867static 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
6837static int builtin_break(char **argv) 6881static 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
6907static 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 @@
1One:1
2Zero:0
3One:1
4Five: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 @@
1f() { false; return; echo BAD; };
2{ f; echo One:$?; }; echo Zero:$?
3
4f() { false; return; };
5f; echo One:$?
6
7f() { return 5; };
8f; echo Five:$?