aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRon Yorston <rmy@pobox.com>2015-11-03 09:42:23 +0000
committerDenys Vlasenko <vda.linux@googlemail.com>2015-11-04 19:30:24 +0100
commit95ebcf79ff6f8ad21ceacb7bac665fb86c078d84 (patch)
tree0097c5c035161420a962dc70d8b1240092063355
parentbc9bee01f35d6c716c087e82dae5f439de90914b (diff)
downloadbusybox-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.c101
-rw-r--r--shell/ash_test/ash-misc/func_bash1.right12
-rwxr-xr-xshell/ash_test/ash-misc/func_bash1.tests28
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 7729enum {
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};
7759typedef smallint token_id_t; 7763typedef 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 @@
11
22
33
41
52
63
71
82
93
101
112
123
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 @@
1function f() { echo $1; }
2f 1
3
4function f() ( echo $1; )
5f 2
6
7function f() ( echo $1 )
8f 3
9
10function f() for i in 1 2 3; do
11 echo $i
12done
13f
14
15function f { echo $1; }
16f 1
17
18# the next two don't work
19#function f ( echo $1; )
20f 2
21
22#function f ( echo $1 )
23f 3
24
25function f for i in 1 2 3; do
26 echo $i
27done
28f