diff options
author | Ron Yorston <rmy@pobox.com> | 2015-11-03 09:42:23 +0000 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2015-11-04 19:30:24 +0100 |
commit | 95ebcf79ff6f8ad21ceacb7bac665fb86c078d84 (patch) | |
tree | 0097c5c035161420a962dc70d8b1240092063355 | |
parent | bc9bee01f35d6c716c087e82dae5f439de90914b (diff) | |
download | busybox-w32-95ebcf79ff6f8ad21ceacb7bac665fb86c078d84.tar.gz busybox-w32-95ebcf79ff6f8ad21ceacb7bac665fb86c078d84.tar.bz2 busybox-w32-95ebcf79ff6f8ad21ceacb7bac665fb86c078d84.zip |
ash: add support for bash 'function' keyword
Where the POSIX shell allows functions to be defined as:
name () compound-command [ redirections ]
bash adds the alternative syntax:
function name [()] compound-command [ redirections ]
Implement this in ash's bash compatibility mode. Most compound
commands work (for/while/until/if/case/[[]]/{}); one exception is:
function f (echo "no way!")
The other two variants work:
f() (echo "ok")
function f() (echo "also ok")
function old new delta
parse_command 1555 1744 +189
tokname_array 232 240 +8
.rodata 155612 155566 -46
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 2/1 up/down: 197/-46) Total: 151 bytes
Signed-off-by: Ron Yorston <rmy@pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r-- | shell/ash.c | 101 | ||||
-rw-r--r-- | shell/ash_test/ash-misc/func_bash1.right | 12 | ||||
-rwxr-xr-x | shell/ash_test/ash-misc/func_bash1.tests | 28 |
3 files changed, 110 insertions, 31 deletions
diff --git a/shell/ash.c b/shell/ash.c index 84502636a..e7a867f52 100644 --- a/shell/ash.c +++ b/shell/ash.c | |||
@@ -7726,36 +7726,40 @@ changepath(const char *new) | |||
7726 | clearcmdentry(firstchange); | 7726 | clearcmdentry(firstchange); |
7727 | builtinloc = idx_bltin; | 7727 | builtinloc = idx_bltin; |
7728 | } | 7728 | } |
7729 | 7729 | enum { | |
7730 | #define TEOF 0 | 7730 | TEOF, |
7731 | #define TNL 1 | 7731 | TNL, |
7732 | #define TREDIR 2 | 7732 | TREDIR, |
7733 | #define TWORD 3 | 7733 | TWORD, |
7734 | #define TSEMI 4 | 7734 | TSEMI, |
7735 | #define TBACKGND 5 | 7735 | TBACKGND, |
7736 | #define TAND 6 | 7736 | TAND, |
7737 | #define TOR 7 | 7737 | TOR, |
7738 | #define TPIPE 8 | 7738 | TPIPE, |
7739 | #define TLP 9 | 7739 | TLP, |
7740 | #define TRP 10 | 7740 | TRP, |
7741 | #define TENDCASE 11 | 7741 | TENDCASE, |
7742 | #define TENDBQUOTE 12 | 7742 | TENDBQUOTE, |
7743 | #define TNOT 13 | 7743 | TNOT, |
7744 | #define TCASE 14 | 7744 | TCASE, |
7745 | #define TDO 15 | 7745 | TDO, |
7746 | #define TDONE 16 | 7746 | TDONE, |
7747 | #define TELIF 17 | 7747 | TELIF, |
7748 | #define TELSE 18 | 7748 | TELSE, |
7749 | #define TESAC 19 | 7749 | TESAC, |
7750 | #define TFI 20 | 7750 | TFI, |
7751 | #define TFOR 21 | 7751 | TFOR, |
7752 | #define TIF 22 | 7752 | #if ENABLE_ASH_BASH_COMPAT |
7753 | #define TIN 23 | 7753 | TFUNCTION, |
7754 | #define TTHEN 24 | 7754 | #endif |
7755 | #define TUNTIL 25 | 7755 | TIF, |
7756 | #define TWHILE 26 | 7756 | TIN, |
7757 | #define TBEGIN 27 | 7757 | TTHEN, |
7758 | #define TEND 28 | 7758 | TUNTIL, |
7759 | TWHILE, | ||
7760 | TBEGIN, | ||
7761 | TEND | ||
7762 | }; | ||
7759 | typedef smallint token_id_t; | 7763 | typedef smallint token_id_t; |
7760 | 7764 | ||
7761 | /* first char is indicating which tokens mark the end of a list */ | 7765 | /* first char is indicating which tokens mark the end of a list */ |
@@ -7784,6 +7788,9 @@ static const char *const tokname_array[] = { | |||
7784 | "\1esac", | 7788 | "\1esac", |
7785 | "\1fi", | 7789 | "\1fi", |
7786 | "\0for", | 7790 | "\0for", |
7791 | #if ENABLE_ASH_BASH_COMPAT | ||
7792 | "\0function", | ||
7793 | #endif | ||
7787 | "\0if", | 7794 | "\0if", |
7788 | "\0in", | 7795 | "\0in", |
7789 | "\1then", | 7796 | "\1then", |
@@ -10762,6 +10769,7 @@ simplecmd(void) | |||
10762 | int savecheckkwd; | 10769 | int savecheckkwd; |
10763 | #if ENABLE_ASH_BASH_COMPAT | 10770 | #if ENABLE_ASH_BASH_COMPAT |
10764 | smallint double_brackets_flag = 0; | 10771 | smallint double_brackets_flag = 0; |
10772 | smallint function_flag = 0; | ||
10765 | #endif | 10773 | #endif |
10766 | 10774 | ||
10767 | args = NULL; | 10775 | args = NULL; |
@@ -10778,6 +10786,11 @@ simplecmd(void) | |||
10778 | t = readtoken(); | 10786 | t = readtoken(); |
10779 | switch (t) { | 10787 | switch (t) { |
10780 | #if ENABLE_ASH_BASH_COMPAT | 10788 | #if ENABLE_ASH_BASH_COMPAT |
10789 | case TFUNCTION: | ||
10790 | if (peektoken() != TWORD) | ||
10791 | raise_error_unexpected_syntax(TWORD); | ||
10792 | function_flag = 1; | ||
10793 | break; | ||
10781 | case TAND: /* "&&" */ | 10794 | case TAND: /* "&&" */ |
10782 | case TOR: /* "||" */ | 10795 | case TOR: /* "||" */ |
10783 | if (!double_brackets_flag) { | 10796 | if (!double_brackets_flag) { |
@@ -10806,6 +10819,29 @@ simplecmd(void) | |||
10806 | app = &n->narg.next; | 10819 | app = &n->narg.next; |
10807 | savecheckkwd = 0; | 10820 | savecheckkwd = 0; |
10808 | } | 10821 | } |
10822 | #if ENABLE_ASH_BASH_COMPAT | ||
10823 | if (function_flag) { | ||
10824 | checkkwd = CHKNL | CHKKWD; | ||
10825 | switch (peektoken()) { | ||
10826 | case TBEGIN: | ||
10827 | case TIF: | ||
10828 | case TCASE: | ||
10829 | case TUNTIL: | ||
10830 | case TWHILE: | ||
10831 | case TFOR: | ||
10832 | goto do_func; | ||
10833 | case TLP: | ||
10834 | function_flag = 0; | ||
10835 | break; | ||
10836 | case TWORD: | ||
10837 | if (strcmp("[[", wordtext) == 0) | ||
10838 | goto do_func; | ||
10839 | /* fall through */ | ||
10840 | default: | ||
10841 | raise_error_unexpected_syntax(-1); | ||
10842 | } | ||
10843 | } | ||
10844 | #endif | ||
10809 | break; | 10845 | break; |
10810 | case TREDIR: | 10846 | case TREDIR: |
10811 | *rpp = n = redirnode; | 10847 | *rpp = n = redirnode; |
@@ -10813,6 +10849,7 @@ simplecmd(void) | |||
10813 | parsefname(); /* read name of redirection file */ | 10849 | parsefname(); /* read name of redirection file */ |
10814 | break; | 10850 | break; |
10815 | case TLP: | 10851 | case TLP: |
10852 | IF_ASH_BASH_COMPAT(do_func:) | ||
10816 | if (args && app == &args->narg.next | 10853 | if (args && app == &args->narg.next |
10817 | && !vars && !redir | 10854 | && !vars && !redir |
10818 | ) { | 10855 | ) { |
@@ -10820,7 +10857,7 @@ simplecmd(void) | |||
10820 | const char *name; | 10857 | const char *name; |
10821 | 10858 | ||
10822 | /* We have a function */ | 10859 | /* We have a function */ |
10823 | if (readtoken() != TRP) | 10860 | if (IF_ASH_BASH_COMPAT(!function_flag &&) readtoken() != TRP) |
10824 | raise_error_unexpected_syntax(TRP); | 10861 | raise_error_unexpected_syntax(TRP); |
10825 | name = n->narg.text; | 10862 | name = n->narg.text; |
10826 | if (!goodname(name) | 10863 | if (!goodname(name) |
@@ -10833,6 +10870,7 @@ simplecmd(void) | |||
10833 | n->narg.next = parse_command(); | 10870 | n->narg.next = parse_command(); |
10834 | return n; | 10871 | return n; |
10835 | } | 10872 | } |
10873 | IF_ASH_BASH_COMPAT(function_flag = 0;) | ||
10836 | /* fall through */ | 10874 | /* fall through */ |
10837 | default: | 10875 | default: |
10838 | tokpushback = 1; | 10876 | tokpushback = 1; |
@@ -11013,6 +11051,7 @@ parse_command(void) | |||
11013 | n1 = list(0); | 11051 | n1 = list(0); |
11014 | t = TEND; | 11052 | t = TEND; |
11015 | break; | 11053 | break; |
11054 | IF_ASH_BASH_COMPAT(case TFUNCTION:) | ||
11016 | case TWORD: | 11055 | case TWORD: |
11017 | case TREDIR: | 11056 | case TREDIR: |
11018 | tokpushback = 1; | 11057 | tokpushback = 1; |
diff --git a/shell/ash_test/ash-misc/func_bash1.right b/shell/ash_test/ash-misc/func_bash1.right new file mode 100644 index 000000000..41bf8828c --- /dev/null +++ b/shell/ash_test/ash-misc/func_bash1.right | |||
@@ -0,0 +1,12 @@ | |||
1 | 1 | ||
2 | 2 | ||
3 | 3 | ||
4 | 1 | ||
5 | 2 | ||
6 | 3 | ||
7 | 1 | ||
8 | 2 | ||
9 | 3 | ||
10 | 1 | ||
11 | 2 | ||
12 | 3 | ||
diff --git a/shell/ash_test/ash-misc/func_bash1.tests b/shell/ash_test/ash-misc/func_bash1.tests new file mode 100755 index 000000000..2cc0970e8 --- /dev/null +++ b/shell/ash_test/ash-misc/func_bash1.tests | |||
@@ -0,0 +1,28 @@ | |||
1 | function f() { echo $1; } | ||
2 | f 1 | ||
3 | |||
4 | function f() ( echo $1; ) | ||
5 | f 2 | ||
6 | |||
7 | function f() ( echo $1 ) | ||
8 | f 3 | ||
9 | |||
10 | function f() for i in 1 2 3; do | ||
11 | echo $i | ||
12 | done | ||
13 | f | ||
14 | |||
15 | function f { echo $1; } | ||
16 | f 1 | ||
17 | |||
18 | # the next two don't work | ||
19 | #function f ( echo $1; ) | ||
20 | f 2 | ||
21 | |||
22 | #function f ( echo $1 ) | ||
23 | f 3 | ||
24 | |||
25 | function f for i in 1 2 3; do | ||
26 | echo $i | ||
27 | done | ||
28 | f | ||