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