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>
This commit is contained in:
parent
bc9bee01f3
commit
95ebcf79ff
101
shell/ash.c
101
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;
|
||||
|
12
shell/ash_test/ash-misc/func_bash1.right
Normal file
12
shell/ash_test/ash-misc/func_bash1.right
Normal file
@ -0,0 +1,12 @@
|
||||
1
|
||||
2
|
||||
3
|
||||
1
|
||||
2
|
||||
3
|
||||
1
|
||||
2
|
||||
3
|
||||
1
|
||||
2
|
||||
3
|
28
shell/ash_test/ash-misc/func_bash1.tests
Executable file
28
shell/ash_test/ash-misc/func_bash1.tests
Executable file
@ -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
|
Loading…
Reference in New Issue
Block a user