ash: split bash compatible extensions into separate defines. No code changes

Splitting these options makes it self-documenting about what
bash-compatible features we have.

Signed-off-by: Kang-Che Sung <explorer09@gmail.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
Denys Vlasenko
2017-01-11 14:00:38 +01:00
parent a8a075acfe
commit 7d4aec0c3e

View File

@@ -145,15 +145,10 @@
//kbuild:lib-$(CONFIG_ASH_RANDOM_SUPPORT) += random.o //kbuild:lib-$(CONFIG_ASH_RANDOM_SUPPORT) += random.o
/* /*
* The following should be set to reflect the type of system you have: * DEBUG=1 to compile in debugging ('set -o debug' turns on)
* JOBS -> 1 if you have Berkeley job control, 0 otherwise. * DEBUG=2 to compile in and turn on debugging.
* define SYSV if you are running under System V. * When debugging is on ("set -o debug" was executed, or DEBUG=2),
* define DEBUG=1 to compile in debugging ('set -o debug' to turn on) * debugging info is written to ./trace, quit signal generates core dump.
* define DEBUG=2 to compile in and turn on debugging.
*
* When debugging is on (DEBUG is 1 and "set -o debug" was executed),
* debugging info will be written to ./trace and a quit signal
* will generate a core dump.
*/ */
#define DEBUG 0 #define DEBUG 0
/* Tweak debug output verbosity here */ /* Tweak debug output verbosity here */
@@ -170,9 +165,30 @@
#include <fnmatch.h> #include <fnmatch.h>
#include <sys/times.h> #include <sys/times.h>
#include <sys/utsname.h> /* for setting $HOSTNAME */ #include <sys/utsname.h> /* for setting $HOSTNAME */
#include "busybox.h" /* for applet_names */ #include "busybox.h" /* for applet_names */
/* So far, all bash compat is controlled by one config option */
/* Separate defines document which part of code implements what */
/* function keyword */
#define BASH_FUNCTION ENABLE_ASH_BASH_COMPAT
#define IF_BASH_FUNCTION IF_ASH_BASH_COMPAT
/* &>file */
#define BASH_REDIR_OUTPUT ENABLE_ASH_BASH_COMPAT
#define IF_BASH_REDIR_OUTPUT IF_ASH_BASH_COMPAT
/* $'...' */
#define BASH_DOLLAR_SQUOTE ENABLE_ASH_BASH_COMPAT
#define IF_BASH_DOLLAR_SQUOTE IF_ASH_BASH_COMPAT
#define BASH_PATTERN_SUBST ENABLE_ASH_BASH_COMPAT
#define IF_BASH_PATTERN_SUBST IF_ASH_BASH_COMPAT
#define BASH_SUBSTR ENABLE_ASH_BASH_COMPAT
#define IF_BASH_SUBSTR IF_ASH_BASH_COMPAT
/* [[ EXPR ]] */
#define BASH_TEST2 (ENABLE_ASH_BASH_COMPAT * ENABLE_ASH_TEST)
#define BASH_SOURCE ENABLE_ASH_BASH_COMPAT
#define BASH_PIPEFAIL ENABLE_ASH_BASH_COMPAT
#define BASH_HOSTNAME_VAR ENABLE_ASH_BASH_COMPAT
#define BASH_SHLVL_VAR ENABLE_ASH_BASH_COMPAT
#if defined(__ANDROID_API__) && __ANDROID_API__ <= 24 #if defined(__ANDROID_API__) && __ANDROID_API__ <= 24
/* Bionic at least up to version 24 has no glob() */ /* Bionic at least up to version 24 has no glob() */
# undef ENABLE_ASH_INTERNAL_GLOB # undef ENABLE_ASH_INTERNAL_GLOB
@@ -250,7 +266,7 @@ static const char *const optletters_optnames[] = {
"b" "notify", "b" "notify",
"u" "nounset", "u" "nounset",
"\0" "vi" "\0" "vi"
#if ENABLE_ASH_BASH_COMPAT #if BASH_PIPEFAIL
,"\0" "pipefail" ,"\0" "pipefail"
#endif #endif
#if DEBUG #if DEBUG
@@ -327,14 +343,14 @@ struct globals_misc {
#define bflag optlist[11] #define bflag optlist[11]
#define uflag optlist[12] #define uflag optlist[12]
#define viflag optlist[13] #define viflag optlist[13]
#if ENABLE_ASH_BASH_COMPAT #if BASH_PIPEFAIL
# define pipefail optlist[14] # define pipefail optlist[14]
#else #else
# define pipefail 0 # define pipefail 0
#endif #endif
#if DEBUG #if DEBUG
# define nolog optlist[14 + ENABLE_ASH_BASH_COMPAT] # define nolog optlist[14 + BASH_PIPEFAIL]
# define debug optlist[15 + ENABLE_ASH_BASH_COMPAT] # define debug optlist[15 + BASH_PIPEFAIL]
#endif #endif
/* trap handler commands */ /* trap handler commands */
@@ -655,8 +671,10 @@ out2str(const char *p)
#define VSTRIMLEFT 0x8 /* ${var#pattern} */ #define VSTRIMLEFT 0x8 /* ${var#pattern} */
#define VSTRIMLEFTMAX 0x9 /* ${var##pattern} */ #define VSTRIMLEFTMAX 0x9 /* ${var##pattern} */
#define VSLENGTH 0xa /* ${#var} */ #define VSLENGTH 0xa /* ${#var} */
#if ENABLE_ASH_BASH_COMPAT #if BASH_SUBSTR
#define VSSUBSTR 0xc /* ${var:position:length} */ #define VSSUBSTR 0xc /* ${var:position:length} */
#endif
#if BASH_PATTERN_SUBST
#define VSREPLACE 0xd /* ${var/pattern/replacement} */ #define VSREPLACE 0xd /* ${var/pattern/replacement} */
#define VSREPLACEALL 0xe /* ${var//pattern/replacement} */ #define VSREPLACEALL 0xe /* ${var//pattern/replacement} */
#endif #endif
@@ -683,7 +701,7 @@ static const char dolatstr[] ALIGN1 = {
#define NDEFUN 14 #define NDEFUN 14
#define NARG 15 #define NARG 15
#define NTO 16 #define NTO 16
#if ENABLE_ASH_BASH_COMPAT #if BASH_REDIR_OUTPUT
#define NTO2 17 #define NTO2 17
#endif #endif
#define NCLOBBER 18 #define NCLOBBER 18
@@ -1093,7 +1111,7 @@ shcmd(union node *cmd, FILE *fp)
case NTO: s = ">>"+1; dftfd = 1; break; case NTO: s = ">>"+1; dftfd = 1; break;
case NCLOBBER: s = ">|"; dftfd = 1; break; case NCLOBBER: s = ">|"; dftfd = 1; break;
case NAPPEND: s = ">>"; dftfd = 1; break; case NAPPEND: s = ">>"; dftfd = 1; break;
#if ENABLE_ASH_BASH_COMPAT #if BASH_REDIR_OUTPUT
case NTO2: case NTO2:
#endif #endif
case NTOFD: s = ">&"; dftfd = 1; break; case NTOFD: s = ">&"; dftfd = 1; break;
@@ -4455,7 +4473,8 @@ cmdputs(const char *s)
static const char vstype[VSTYPE + 1][3] = { static const char vstype[VSTYPE + 1][3] = {
"", "}", "-", "+", "?", "=", "", "}", "-", "+", "?", "=",
"%", "%%", "#", "##" "%", "%%", "#", "##"
IF_ASH_BASH_COMPAT(, ":", "/", "//") IF_BASH_SUBSTR(, ":")
IF_BASH_PATTERN_SUBST(, "/", "//")
}; };
const char *p, *str; const char *p, *str;
@@ -4682,7 +4701,7 @@ cmdtxt(union node *n)
case NAPPEND: case NAPPEND:
p = ">>"; p = ">>";
goto redir; goto redir;
#if ENABLE_ASH_BASH_COMPAT #if BASH_REDIR_OUTPUT
case NTO2: case NTO2:
#endif #endif
case NTOFD: case NTOFD:
@@ -5209,7 +5228,7 @@ openredirect(union node *redir)
goto ecreate; goto ecreate;
break; break;
case NTO: case NTO:
#if ENABLE_ASH_BASH_COMPAT #if BASH_REDIR_OUTPUT
case NTO2: case NTO2:
#endif #endif
/* Take care of noclobber mode. */ /* Take care of noclobber mode. */
@@ -5370,7 +5389,7 @@ redirect(union node *redir, int flags)
union node *tmp = redir; union node *tmp = redir;
do { do {
sv_pos++; sv_pos++;
#if ENABLE_ASH_BASH_COMPAT #if BASH_REDIR_OUTPUT
if (tmp->nfile.type == NTO2) if (tmp->nfile.type == NTO2)
sv_pos++; sv_pos++;
#endif #endif
@@ -5412,7 +5431,7 @@ redirect(union node *redir, int flags)
continue; continue;
} }
} }
#if ENABLE_ASH_BASH_COMPAT #if BASH_REDIR_OUTPUT
redirect_more: redirect_more:
#endif #endif
if (need_to_remember(sv, fd)) { if (need_to_remember(sv, fd)) {
@@ -5465,12 +5484,12 @@ redirect(union node *redir, int flags)
} }
} else if (fd != newfd) { /* move newfd to fd */ } else if (fd != newfd) { /* move newfd to fd */
dup2_or_raise(newfd, fd); dup2_or_raise(newfd, fd);
#if ENABLE_ASH_BASH_COMPAT #if BASH_REDIR_OUTPUT
if (!(redir->nfile.type == NTO2 && fd == 2)) if (!(redir->nfile.type == NTO2 && fd == 2))
#endif #endif
close(newfd); close(newfd);
} }
#if ENABLE_ASH_BASH_COMPAT #if BASH_REDIR_OUTPUT
if (redir->nfile.type == NTO2 && fd == 1) { if (redir->nfile.type == NTO2 && fd == 1) {
/* We already redirected it to fd 1, now copy it to 2 */ /* We already redirected it to fd 1, now copy it to 2 */
newfd = 1; newfd = 1;
@@ -5787,15 +5806,15 @@ static char *
rmescapes(char *str, int flag) rmescapes(char *str, int flag)
{ {
static const char qchars[] ALIGN1 = { static const char qchars[] ALIGN1 = {
IF_ASH_BASH_COMPAT('/',) CTLESC, CTLQUOTEMARK, '\0' }; IF_BASH_PATTERN_SUBST('/',) CTLESC, CTLQUOTEMARK, '\0' };
char *p, *q, *r; char *p, *q, *r;
unsigned inquotes; unsigned inquotes;
unsigned protect_against_glob; unsigned protect_against_glob;
unsigned globbing; unsigned globbing;
IF_ASH_BASH_COMPAT(unsigned slash = flag & RMESCAPE_SLASH;) IF_BASH_PATTERN_SUBST(unsigned slash = flag & RMESCAPE_SLASH;)
p = strpbrk(str, qchars IF_ASH_BASH_COMPAT(+ !slash)); p = strpbrk(str, qchars IF_BASH_PATTERN_SUBST(+ !slash));
if (!p) if (!p)
return str; return str;
@@ -5847,7 +5866,7 @@ rmescapes(char *str, int flag)
protect_against_glob = 0; protect_against_glob = 0;
goto copy; goto copy;
} }
#if ENABLE_ASH_BASH_COMPAT #if BASH_PATTERN_SUBST
else if (*p == '/' && slash) { else if (*p == '/' && slash) {
/* stop handling globbing and mark location of slash */ /* stop handling globbing and mark location of slash */
globbing = slash = 0; globbing = slash = 0;
@@ -6494,10 +6513,10 @@ subevalvar(char *p, char *varname, int strloc, int subtype,
char *loc; char *loc;
char *rmesc, *rmescend; char *rmesc, *rmescend;
char *str; char *str;
IF_ASH_BASH_COMPAT(char *repl = NULL;) IF_BASH_SUBSTR(int pos, len, orig_len;)
IF_ASH_BASH_COMPAT(int pos, len, orig_len;)
int amount, resetloc; int amount, resetloc;
IF_ASH_BASH_COMPAT(int workloc;) IF_BASH_PATTERN_SUBST(int workloc;)
IF_BASH_PATTERN_SUBST(char *repl = NULL;)
int zero; int zero;
char *(*scan)(char*, char*, char*, char*, int, int); char *(*scan)(char*, char*, char*, char*, int, int);
@@ -6522,7 +6541,7 @@ subevalvar(char *p, char *varname, int strloc, int subtype,
varunset(p, varname, startp, varflags); varunset(p, varname, startp, varflags);
/* NOTREACHED */ /* NOTREACHED */
#if ENABLE_ASH_BASH_COMPAT #if BASH_SUBSTR
case VSSUBSTR: case VSSUBSTR:
//TODO: support more general format ${v:EXPR:EXPR}, //TODO: support more general format ${v:EXPR:EXPR},
// where EXPR follows $(()) rules // where EXPR follows $(()) rules
@@ -6591,17 +6610,19 @@ subevalvar(char *p, char *varname, int strloc, int subtype,
amount = loc - expdest; amount = loc - expdest;
STADJUST(amount, expdest); STADJUST(amount, expdest);
return loc; return loc;
#endif #endif /* BASH_SUBSTR */
} }
resetloc = expdest - (char *)stackblock(); resetloc = expdest - (char *)stackblock();
#if BASH_PATTERN_SUBST
/* We'll comeback here if we grow the stack while handling /* We'll comeback here if we grow the stack while handling
* a VSREPLACE or VSREPLACEALL, since our pointers into the * a VSREPLACE or VSREPLACEALL, since our pointers into the
* stack will need rebasing, and we'll need to remove our work * stack will need rebasing, and we'll need to remove our work
* areas each time * areas each time
*/ */
IF_ASH_BASH_COMPAT(restart:) restart:
#endif
amount = expdest - ((char *)stackblock() + resetloc); amount = expdest - ((char *)stackblock() + resetloc);
STADJUST(-amount, expdest); STADJUST(-amount, expdest);
@@ -6626,11 +6647,11 @@ subevalvar(char *p, char *varname, int strloc, int subtype,
* RMESCAPE_SLASH causes preglob to work differently on the pattern * RMESCAPE_SLASH causes preglob to work differently on the pattern
* and string. It's only used on the first call. * and string. It's only used on the first call.
*/ */
preglob(str, IF_ASH_BASH_COMPAT( preglob(str, IF_BASH_PATTERN_SUBST(
(subtype == VSREPLACE || subtype == VSREPLACEALL) && !repl ? (subtype == VSREPLACE || subtype == VSREPLACEALL) && !repl ?
RMESCAPE_SLASH :) 0); RMESCAPE_SLASH : ) 0);
#if ENABLE_ASH_BASH_COMPAT #if BASH_PATTERN_SUBST
workloc = expdest - (char *)stackblock(); workloc = expdest - (char *)stackblock();
if (subtype == VSREPLACE || subtype == VSREPLACEALL) { if (subtype == VSREPLACE || subtype == VSREPLACEALL) {
char *idx, *end; char *idx, *end;
@@ -6731,7 +6752,7 @@ subevalvar(char *p, char *varname, int strloc, int subtype,
STADJUST(-amount, expdest); STADJUST(-amount, expdest);
return startp; return startp;
} }
#endif /* ENABLE_ASH_BASH_COMPAT */ #endif /* BASH_PATTERN_SUBST */
subtype -= VSTRIMRIGHT; subtype -= VSTRIMRIGHT;
#if DEBUG #if DEBUG
@@ -6999,8 +7020,10 @@ evalvar(char *p, int flag, struct strlist *var_str_list)
case VSTRIMLEFTMAX: case VSTRIMLEFTMAX:
case VSTRIMRIGHT: case VSTRIMRIGHT:
case VSTRIMRIGHTMAX: case VSTRIMRIGHTMAX:
#if ENABLE_ASH_BASH_COMPAT #if BASH_SUBSTR
case VSSUBSTR: case VSSUBSTR:
#endif
#if BASH_PATTERN_SUBST
case VSREPLACE: case VSREPLACE:
case VSREPLACEALL: case VSREPLACEALL:
#endif #endif
@@ -7924,7 +7947,7 @@ enum {
TESAC, TESAC,
TFI, TFI,
TFOR, TFOR,
#if ENABLE_ASH_BASH_COMPAT #if BASH_FUNCTION
TFUNCTION, TFUNCTION,
#endif #endif
TIF, TIF,
@@ -7962,7 +7985,7 @@ enum {
/* 19 */ | (1u << TESAC) /* 19 */ | (1u << TESAC)
/* 20 */ | (1u << TFI) /* 20 */ | (1u << TFI)
/* 21 */ | (0u << TFOR) /* 21 */ | (0u << TFOR)
#if ENABLE_ASH_BASH_COMPAT #if BASH_FUNCTION
/* 22 */ | (0u << TFUNCTION) /* 22 */ | (0u << TFUNCTION)
#endif #endif
/* 23 */ | (0u << TIF) /* 23 */ | (0u << TIF)
@@ -8000,7 +8023,7 @@ static const char *const tokname_array[] = {
"esac", "esac",
"fi", "fi",
"for", "for",
#if ENABLE_ASH_BASH_COMPAT #if BASH_FUNCTION
"function", "function",
#endif #endif
"if", "if",
@@ -8244,7 +8267,7 @@ static const uint8_t nodesize[N_NUMBER] ALIGN1 = {
[NDEFUN ] = SHELL_ALIGN(sizeof(struct narg)), [NDEFUN ] = SHELL_ALIGN(sizeof(struct narg)),
[NARG ] = SHELL_ALIGN(sizeof(struct narg)), [NARG ] = SHELL_ALIGN(sizeof(struct narg)),
[NTO ] = SHELL_ALIGN(sizeof(struct nfile)), [NTO ] = SHELL_ALIGN(sizeof(struct nfile)),
#if ENABLE_ASH_BASH_COMPAT #if BASH_REDIR_OUTPUT
[NTO2 ] = SHELL_ALIGN(sizeof(struct nfile)), [NTO2 ] = SHELL_ALIGN(sizeof(struct nfile)),
#endif #endif
[NCLOBBER ] = SHELL_ALIGN(sizeof(struct nfile)), [NCLOBBER ] = SHELL_ALIGN(sizeof(struct nfile)),
@@ -8326,7 +8349,7 @@ calcsize(int funcblocksize, union node *n)
funcblocksize = calcsize(funcblocksize, n->narg.next); funcblocksize = calcsize(funcblocksize, n->narg.next);
break; break;
case NTO: case NTO:
#if ENABLE_ASH_BASH_COMPAT #if BASH_REDIR_OUTPUT
case NTO2: case NTO2:
#endif #endif
case NCLOBBER: case NCLOBBER:
@@ -8440,7 +8463,7 @@ copynode(union node *n)
new->narg.next = copynode(n->narg.next); new->narg.next = copynode(n->narg.next);
break; break;
case NTO: case NTO:
#if ENABLE_ASH_BASH_COMPAT #if BASH_REDIR_OUTPUT
case NTO2: case NTO2:
#endif #endif
case NCLOBBER: case NCLOBBER:
@@ -8873,14 +8896,14 @@ expredir(union node *n)
case NFROMTO: case NFROMTO:
case NFROM: case NFROM:
case NTO: case NTO:
#if ENABLE_ASH_BASH_COMPAT #if BASH_REDIR_OUTPUT
case NTO2: case NTO2:
#endif #endif
case NCLOBBER: case NCLOBBER:
case NAPPEND: case NAPPEND:
expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR); expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
TRACE(("expredir expanded to '%s'\n", fn.list->text)); TRACE(("expredir expanded to '%s'\n", fn.list->text));
#if ENABLE_ASH_BASH_COMPAT #if BASH_REDIR_OUTPUT
store_expfname: store_expfname:
#endif #endif
#if 0 #if 0
@@ -8902,7 +8925,7 @@ expredir(union node *n)
expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE); expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
if (fn.list == NULL) if (fn.list == NULL)
ash_msg_and_raise_error("redir error"); ash_msg_and_raise_error("redir error");
#if ENABLE_ASH_BASH_COMPAT #if BASH_REDIR_OUTPUT
//FIXME: we used expandarg with different args! //FIXME: we used expandarg with different args!
if (!isdigit_str9(fn.list->text)) { if (!isdigit_str9(fn.list->text)) {
/* >&file, not >&fd */ /* >&file, not >&fd */
@@ -9298,7 +9321,7 @@ static int FAST_FUNC echocmd(int argc, char **argv) { return echo_main(argc, a
#if ENABLE_ASH_PRINTF #if ENABLE_ASH_PRINTF
static int FAST_FUNC printfcmd(int argc, char **argv) { return printf_main(argc, argv); } static int FAST_FUNC printfcmd(int argc, char **argv) { return printf_main(argc, argv); }
#endif #endif
#if ENABLE_ASH_TEST #if ENABLE_ASH_TEST || BASH_TEST2
static int FAST_FUNC testcmd(int argc, char **argv) { return test_main(argc, argv); } static int FAST_FUNC testcmd(int argc, char **argv) { return test_main(argc, argv); }
#endif #endif
@@ -9308,9 +9331,9 @@ static const struct builtincmd builtintab[] = {
{ BUILTIN_SPEC_REG ":" , truecmd }, { BUILTIN_SPEC_REG ":" , truecmd },
#if ENABLE_ASH_TEST #if ENABLE_ASH_TEST
{ BUILTIN_REGULAR "[" , testcmd }, { BUILTIN_REGULAR "[" , testcmd },
# if ENABLE_ASH_BASH_COMPAT #endif
#if BASH_TEST2
{ BUILTIN_REGULAR "[[" , testcmd }, { BUILTIN_REGULAR "[[" , testcmd },
# endif
#endif #endif
#if ENABLE_ASH_ALIAS #if ENABLE_ASH_ALIAS
{ BUILTIN_REG_ASSG "alias" , aliascmd }, { BUILTIN_REG_ASSG "alias" , aliascmd },
@@ -9363,7 +9386,7 @@ static const struct builtincmd builtintab[] = {
{ BUILTIN_SPEC_REG "return" , returncmd }, { BUILTIN_SPEC_REG "return" , returncmd },
{ BUILTIN_SPEC_REG "set" , setcmd }, { BUILTIN_SPEC_REG "set" , setcmd },
{ BUILTIN_SPEC_REG "shift" , shiftcmd }, { BUILTIN_SPEC_REG "shift" , shiftcmd },
#if ENABLE_ASH_BASH_COMPAT #if BASH_SOURCE
{ BUILTIN_SPEC_REG "source" , dotcmd }, { BUILTIN_SPEC_REG "source" , dotcmd },
#endif #endif
#if ENABLE_ASH_TEST #if ENABLE_ASH_TEST
@@ -9386,7 +9409,7 @@ static const struct builtincmd builtintab[] = {
#define COMMANDCMD (builtintab + \ #define COMMANDCMD (builtintab + \
/* . : */ 2 + \ /* . : */ 2 + \
/* [ */ 1 * ENABLE_ASH_TEST + \ /* [ */ 1 * ENABLE_ASH_TEST + \
/* [[ */ 1 * ENABLE_ASH_TEST * ENABLE_ASH_BASH_COMPAT + \ /* [[ */ 1 * BASH_TEST2 + \
/* alias */ 1 * ENABLE_ASH_ALIAS + \ /* alias */ 1 * ENABLE_ASH_ALIAS + \
/* bg */ 1 * ENABLE_ASH_JOB_CONTROL + \ /* bg */ 1 * ENABLE_ASH_JOB_CONTROL + \
/* break cd cddir */ 3) /* break cd cddir */ 3)
@@ -11008,10 +11031,10 @@ simplecmd(void)
union node *vars, **vpp; union node *vars, **vpp;
union node **rpp, *redir; union node **rpp, *redir;
int savecheckkwd; int savecheckkwd;
#if ENABLE_ASH_BASH_COMPAT #if BASH_TEST2
smallint double_brackets_flag = 0; smallint double_brackets_flag = 0;
smallint function_flag = 0;
#endif #endif
IF_BASH_FUNCTION(smallint function_flag = 0;)
args = NULL; args = NULL;
app = &args; app = &args;
@@ -11026,12 +11049,14 @@ simplecmd(void)
checkkwd = savecheckkwd; checkkwd = savecheckkwd;
t = readtoken(); t = readtoken();
switch (t) { switch (t) {
#if ENABLE_ASH_BASH_COMPAT #if BASH_FUNCTION
case TFUNCTION: case TFUNCTION:
if (peektoken() != TWORD) if (peektoken() != TWORD)
raise_error_unexpected_syntax(TWORD); raise_error_unexpected_syntax(TWORD);
function_flag = 1; function_flag = 1;
break; break;
#endif
#if BASH_TEST2
case TAND: /* "&&" */ case TAND: /* "&&" */
case TOR: /* "||" */ case TOR: /* "||" */
if (!double_brackets_flag) { if (!double_brackets_flag) {
@@ -11045,7 +11070,7 @@ simplecmd(void)
n->type = NARG; n->type = NARG;
/*n->narg.next = NULL; - stzalloc did it */ /*n->narg.next = NULL; - stzalloc did it */
n->narg.text = wordtext; n->narg.text = wordtext;
#if ENABLE_ASH_BASH_COMPAT #if BASH_TEST2
if (strcmp("[[", wordtext) == 0) if (strcmp("[[", wordtext) == 0)
double_brackets_flag = 1; double_brackets_flag = 1;
else if (strcmp("]]", wordtext) == 0) else if (strcmp("]]", wordtext) == 0)
@@ -11060,7 +11085,7 @@ simplecmd(void)
app = &n->narg.next; app = &n->narg.next;
savecheckkwd = 0; savecheckkwd = 0;
} }
#if ENABLE_ASH_BASH_COMPAT #if BASH_FUNCTION
if (function_flag) { if (function_flag) {
checkkwd = CHKNL | CHKKWD; checkkwd = CHKNL | CHKKWD;
switch (peektoken()) { switch (peektoken()) {
@@ -11090,7 +11115,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_BASH_FUNCTION(do_func:)
if (args && app == &args->narg.next if (args && app == &args->narg.next
&& !vars && !redir && !vars && !redir
) { ) {
@@ -11098,7 +11123,7 @@ simplecmd(void)
const char *name; const char *name;
/* We have a function */ /* We have a function */
if (IF_ASH_BASH_COMPAT(!function_flag &&) readtoken() != TRP) if (IF_BASH_FUNCTION(!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)
@@ -11111,7 +11136,7 @@ simplecmd(void)
n->narg.next = parse_command(); n->narg.next = parse_command();
return n; return n;
} }
IF_ASH_BASH_COMPAT(function_flag = 0;) IF_BASH_FUNCTION(function_flag = 0;)
/* fall through */ /* fall through */
default: default:
tokpushback = 1; tokpushback = 1;
@@ -11292,7 +11317,7 @@ parse_command(void)
n1 = list(0); n1 = list(0);
t = TEND; t = TEND;
break; break;
IF_ASH_BASH_COMPAT(case TFUNCTION:) IF_BASH_FUNCTION(case TFUNCTION:)
case TWORD: case TWORD:
case TREDIR: case TREDIR:
tokpushback = 1; tokpushback = 1;
@@ -11325,7 +11350,7 @@ parse_command(void)
return n1; return n1;
} }
#if ENABLE_ASH_BASH_COMPAT #if BASH_DOLLAR_SQUOTE
static int static int
decode_dollar_squote(void) decode_dollar_squote(void)
{ {
@@ -11410,7 +11435,7 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs)
IF_FEATURE_SH_MATH(int parenlevel;) /* levels of parens in arithmetic */ IF_FEATURE_SH_MATH(int parenlevel;) /* levels of parens in arithmetic */
int dqvarnest; /* levels of variables expansion within double quotes */ int dqvarnest; /* levels of variables expansion within double quotes */
IF_ASH_BASH_COMPAT(smallint bash_dollar_squote = 0;) IF_BASH_DOLLAR_SQUOTE(smallint bash_dollar_squote = 0;)
startlinno = g_parsefile->linno; startlinno = g_parsefile->linno;
bqlist = NULL; bqlist = NULL;
@@ -11445,7 +11470,7 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs)
USTPUTC(c, out); USTPUTC(c, out);
break; break;
case CCTL: case CCTL:
#if ENABLE_ASH_BASH_COMPAT #if BASH_DOLLAR_SQUOTE
if (c == '\\' && bash_dollar_squote) { if (c == '\\' && bash_dollar_squote) {
c = decode_dollar_squote(); c = decode_dollar_squote();
if (c == '\0') { if (c == '\0') {
@@ -11506,7 +11531,7 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs)
dblquote = 1; dblquote = 1;
goto quotemark; goto quotemark;
case CENDQUOTE: case CENDQUOTE:
IF_ASH_BASH_COMPAT(bash_dollar_squote = 0;) IF_BASH_DOLLAR_SQUOTE(bash_dollar_squote = 0;)
if (eofmark != NULL && varnest == 0) { if (eofmark != NULL && varnest == 0) {
USTPUTC(c, out); USTPUTC(c, out);
} else { } else {
@@ -11565,7 +11590,7 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs)
break; break;
default: default:
if (varnest == 0) { if (varnest == 0) {
#if ENABLE_ASH_BASH_COMPAT #if BASH_REDIR_OUTPUT
if (c == '&') { if (c == '&') {
//Can't call pgetc_eatbnl() here, this requires three-deep pungetc() //Can't call pgetc_eatbnl() here, this requires three-deep pungetc()
if (pgetc() == '>') if (pgetc() == '>')
@@ -11597,7 +11622,7 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs)
len = out - (char *)stackblock(); len = out - (char *)stackblock();
out = stackblock(); out = stackblock();
if (eofmark == NULL) { if (eofmark == NULL) {
if ((c == '>' || c == '<' IF_ASH_BASH_COMPAT( || c == 0x100 + '>')) if ((c == '>' || c == '<' IF_BASH_REDIR_OUTPUT( || c == 0x100 + '>'))
&& quotef == 0 && quotef == 0
) { ) {
if (isdigit_str9(out)) { if (isdigit_str9(out)) {
@@ -11685,7 +11710,7 @@ parseredir: {
pungetc(); pungetc();
} }
} }
#if ENABLE_ASH_BASH_COMPAT #if BASH_REDIR_OUTPUT
else if (c == 0x100 + '>') { /* this flags &> redirection */ else if (c == 0x100 + '>') { /* this flags &> redirection */
np->nfile.fd = 1; np->nfile.fd = 1;
pgetc(); /* this is '>', no need to check */ pgetc(); /* this is '>', no need to check */
@@ -11751,7 +11776,7 @@ parsesub: {
if (c > 255 /* PEOA or PEOF */ if (c > 255 /* PEOA or PEOF */
|| (c != '(' && c != '{' && !is_name(c) && !is_special(c)) || (c != '(' && c != '{' && !is_name(c) && !is_special(c))
) { ) {
#if ENABLE_ASH_BASH_COMPAT #if BASH_DOLLAR_SQUOTE
if (syntax != DQSYNTAX && c == '\'') if (syntax != DQSYNTAX && c == '\'')
bash_dollar_squote = 1; bash_dollar_squote = 1;
else else
@@ -11827,7 +11852,7 @@ parsesub: {
switch (c) { switch (c) {
case ':': case ':':
c = pgetc_eatbnl(); c = pgetc_eatbnl();
#if ENABLE_ASH_BASH_COMPAT #if BASH_SUBSTR
/* This check is only needed to not misinterpret /* This check is only needed to not misinterpret
* ${VAR:-WORD}, ${VAR:+WORD}, ${VAR:=WORD}, ${VAR:?WORD} * ${VAR:-WORD}, ${VAR:+WORD}, ${VAR:=WORD}, ${VAR:?WORD}
* constructs. * constructs.
@@ -11857,7 +11882,7 @@ parsesub: {
subtype++; subtype++;
break; break;
} }
#if ENABLE_ASH_BASH_COMPAT #if BASH_PATTERN_SUBST
case '/': case '/':
/* ${v/[/]pattern/repl} */ /* ${v/[/]pattern/repl} */
//TODO: encode pattern and repl separately. //TODO: encode pattern and repl separately.
@@ -12112,7 +12137,7 @@ xxreadtoken(void)
p += xxreadtoken_doubles + 1; p += xxreadtoken_doubles + 1;
} else { } else {
pungetc(); pungetc();
#if ENABLE_ASH_BASH_COMPAT #if BASH_REDIR_OUTPUT
if (c == '&' && cc == '>') /* &> */ if (c == '&' && cc == '>') /* &> */
break; /* return readtoken1(...) */ break; /* return readtoken1(...) */
#endif #endif
@@ -13274,9 +13299,11 @@ init(void)
setvareq((char*)defoptindvar, VTEXTFIXED); setvareq((char*)defoptindvar, VTEXTFIXED);
setvar0("PPID", utoa(getppid())); setvar0("PPID", utoa(getppid()));
#if ENABLE_ASH_BASH_COMPAT #if BASH_SHLVL_VAR
p = lookupvar("SHLVL"); p = lookupvar("SHLVL");
setvar("SHLVL", utoa((p ? atoi(p) : 0) + 1), VEXPORT); setvar("SHLVL", utoa((p ? atoi(p) : 0) + 1), VEXPORT);
#endif
#if BASH_HOSTNAME_VAR
if (!lookupvar("HOSTNAME")) { if (!lookupvar("HOSTNAME")) {
struct utsname uts; struct utsname uts;
uname(&uts); uname(&uts);