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-95ebcf79ff6f8ad21ceacb7bac665fb86c078d84.tar.gz
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)
clearcmdentry(firstchange);
builtinloc = idx_bltin;
}
-
-#define TEOF 0
-#define TNL 1
-#define TREDIR 2
-#define TWORD 3
-#define TSEMI 4
-#define TBACKGND 5
-#define TAND 6
-#define TOR 7
-#define TPIPE 8
-#define TLP 9
-#define TRP 10
-#define TENDCASE 11
-#define TENDBQUOTE 12
-#define TNOT 13
-#define TCASE 14
-#define TDO 15
-#define TDONE 16
-#define TELIF 17
-#define TELSE 18
-#define TESAC 19
-#define TFI 20
-#define TFOR 21
-#define TIF 22
-#define TIN 23
-#define TTHEN 24
-#define TUNTIL 25
-#define TWHILE 26
-#define TBEGIN 27
-#define TEND 28
+enum {
+ TEOF,
+ TNL,
+ TREDIR,
+ TWORD,
+ TSEMI,
+ TBACKGND,
+ TAND,
+ TOR,
+ TPIPE,
+ TLP,
+ TRP,
+ TENDCASE,
+ TENDBQUOTE,
+ TNOT,
+ TCASE,
+ TDO,
+ TDONE,
+ TELIF,
+ TELSE,
+ TESAC,
+ TFI,
+ TFOR,
+#if ENABLE_ASH_BASH_COMPAT
+ TFUNCTION,
+#endif
+ TIF,
+ TIN,
+ TTHEN,
+ TUNTIL,
+ TWHILE,
+ TBEGIN,
+ TEND
+};
typedef smallint token_id_t;
/* first char is indicating which tokens mark the end of a list */
@@ -7784,6 +7788,9 @@ static const char *const tokname_array[] = {
"\1esac",
"\1fi",
"\0for",
+#if ENABLE_ASH_BASH_COMPAT
+ "\0function",
+#endif
"\0if",
"\0in",
"\1then",
@@ -10762,6 +10769,7 @@ simplecmd(void)
int savecheckkwd;
#if ENABLE_ASH_BASH_COMPAT
smallint double_brackets_flag = 0;
+ smallint function_flag = 0;
#endif
args = NULL;
@@ -10778,6 +10786,11 @@ simplecmd(void)
t = readtoken();
switch (t) {
#if ENABLE_ASH_BASH_COMPAT
+ case TFUNCTION:
+ if (peektoken() != TWORD)
+ raise_error_unexpected_syntax(TWORD);
+ function_flag = 1;
+ break;
case TAND: /* "&&" */
case TOR: /* "||" */
if (!double_brackets_flag) {
@@ -10806,6 +10819,29 @@ simplecmd(void)
app = &n->narg.next;
savecheckkwd = 0;
}
+#if ENABLE_ASH_BASH_COMPAT
+ if (function_flag) {
+ checkkwd = CHKNL | CHKKWD;
+ switch (peektoken()) {
+ case TBEGIN:
+ case TIF:
+ case TCASE:
+ case TUNTIL:
+ case TWHILE:
+ case TFOR:
+ goto do_func;
+ case TLP:
+ function_flag = 0;
+ break;
+ case TWORD:
+ if (strcmp("[[", wordtext) == 0)
+ goto do_func;
+ /* fall through */
+ default:
+ raise_error_unexpected_syntax(-1);
+ }
+ }
+#endif
break;
case TREDIR:
*rpp = n = redirnode;
@@ -10813,6 +10849,7 @@ simplecmd(void)
parsefname(); /* read name of redirection file */
break;
case TLP:
+ IF_ASH_BASH_COMPAT(do_func:)
if (args && app == &args->narg.next
&& !vars && !redir
) {
@@ -10820,7 +10857,7 @@ simplecmd(void)
const char *name;
/* We have a function */
- if (readtoken() != TRP)
+ if (IF_ASH_BASH_COMPAT(!function_flag &&) readtoken() != TRP)
raise_error_unexpected_syntax(TRP);
name = n->narg.text;
if (!goodname(name)
@@ -10833,6 +10870,7 @@ simplecmd(void)
n->narg.next = parse_command();
return n;
}
+ IF_ASH_BASH_COMPAT(function_flag = 0;)
/* fall through */
default:
tokpushback = 1;
@@ -11013,6 +11051,7 @@ parse_command(void)
n1 = list(0);
t = TEND;
break;
+ IF_ASH_BASH_COMPAT(case TFUNCTION:)
case TWORD:
case TREDIR:
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
+2
+3
+1
+2
+3
+1
+2
+3
+1
+2
+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 @@
+function f() { echo $1; }
+f 1
+
+function f() ( echo $1; )
+f 2
+
+function f() ( echo $1 )
+f 3
+
+function f() for i in 1 2 3; do
+ echo $i
+done
+f
+
+function f { echo $1; }
+f 1
+
+# the next two don't work
+#function f ( echo $1; )
+f 2
+
+#function f ( echo $1 )
+f 3
+
+function f for i in 1 2 3; do
+ echo $i
+done
+f