ash: support &> redirection (bashism). ~90 bytes of code
diff --git a/shell/ash.c b/shell/ash.c
index 962d5be..70b7ae3 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -2572,34 +2572,36 @@
/* ============ ... */
+
#define IBUFSIZ COMMON_BUFSIZE
-#define basebuf bb_common_bufsiz1 /* buffer for top level input file */
+/* buffer for top level input file */
+#define basebuf bb_common_bufsiz1
/* Syntax classes */
-#define CWORD 0 /* character is nothing special */
-#define CNL 1 /* newline character */
-#define CBACK 2 /* a backslash character */
-#define CSQUOTE 3 /* single quote */
-#define CDQUOTE 4 /* double quote */
+#define CWORD 0 /* character is nothing special */
+#define CNL 1 /* newline character */
+#define CBACK 2 /* a backslash character */
+#define CSQUOTE 3 /* single quote */
+#define CDQUOTE 4 /* double quote */
#define CENDQUOTE 5 /* a terminating quote */
-#define CBQUOTE 6 /* backwards single quote */
-#define CVAR 7 /* a dollar sign */
-#define CENDVAR 8 /* a '}' character */
-#define CLP 9 /* a left paren in arithmetic */
-#define CRP 10 /* a right paren in arithmetic */
+#define CBQUOTE 6 /* backwards single quote */
+#define CVAR 7 /* a dollar sign */
+#define CENDVAR 8 /* a '}' character */
+#define CLP 9 /* a left paren in arithmetic */
+#define CRP 10 /* a right paren in arithmetic */
#define CENDFILE 11 /* end of file */
-#define CCTL 12 /* like CWORD, except it must be escaped */
-#define CSPCL 13 /* these terminate a word */
-#define CIGN 14 /* character should be ignored */
+#define CCTL 12 /* like CWORD, except it must be escaped */
+#define CSPCL 13 /* these terminate a word */
+#define CIGN 14 /* character should be ignored */
#if ENABLE_ASH_ALIAS
-#define SYNBASE 130
-#define PEOF -130
-#define PEOA -129
+#define SYNBASE 130
+#define PEOF -130
+#define PEOA -129
#define PEOA_OR_PEOF PEOA
#else
-#define SYNBASE 129
-#define PEOF -129
+#define SYNBASE 129
+#define PEOF -129
#define PEOA_OR_PEOF PEOF
#endif
@@ -9269,7 +9271,7 @@
return signed_char2int(*parsenextc++);
}
-#define pgetc_as_macro() (--parsenleft >= 0? signed_char2int(*parsenextc++) : preadbuffer())
+#define pgetc_as_macro() (--parsenleft >= 0 ? signed_char2int(*parsenextc++) : preadbuffer())
static int
pgetc(void)
{
@@ -9277,9 +9279,9 @@
}
#if ENABLE_ASH_OPTIMIZE_FOR_SIZE
-#define pgetc_macro() pgetc()
+#define pgetc_fast() pgetc()
#else
-#define pgetc_macro() pgetc_as_macro()
+#define pgetc_fast() pgetc_as_macro()
#endif
/*
@@ -9290,18 +9292,13 @@
pgetc2(void)
{
int c;
-
do {
- c = pgetc_macro();
+ c = pgetc_fast();
} while (c == PEOA);
return c;
}
#else
-static int
-pgetc2(void)
-{
- return pgetc_macro();
-}
+#define pgetc2() pgetc()
#endif
/*
@@ -9355,7 +9352,6 @@
len = strlen(s);
INT_OFF;
-/*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
if (g_parsefile->strpush) {
sp = ckzalloc(sizeof(struct strpush));
sp->prev = g_parsefile->strpush;
@@ -10800,15 +10796,23 @@
case CIGN:
break;
default:
- if (varnest == 0)
+ if (varnest == 0) {
+#if ENABLE_ASH_BASH_COMPAT
+ if (c == '&') {
+ if (pgetc() == '>')
+ c = 0x100 + '>'; /* flag &> */
+ pungetc();
+ }
+#endif
goto endword; /* exit outer loop */
+ }
#if ENABLE_ASH_ALIAS
if (c != PEOA)
#endif
USTPUTC(c, out);
}
- c = pgetc_macro();
+ c = pgetc_fast();
} /* for (;;) */
}
endword:
@@ -10827,7 +10831,9 @@
len = out - (char *)stackblock();
out = stackblock();
if (eofmark == NULL) {
- if ((c == '>' || c == '<') && quotef == 0) {
+ if ((c == '>' || c == '<' USE_ASH_BASH_COMPAT( || c == 0x100 + '>'))
+ && quotef == 0
+ ) {
if (isdigit_str9(out)) {
PARSEREDIR(); /* passed as params: out, c */
lasttoken = TREDIR;
@@ -10908,7 +10914,15 @@
np->type = NTO;
pungetc();
}
- } else { /* c == '<' */
+ }
+#if ENABLE_ASH_BASH_COMPAT
+ else if (c == 0x100 + '>') { /* this flags &> redirection */
+ np->nfile.fd = 1;
+ pgetc(); /* this is '>', no need to check */
+ np->type = NTO2;
+ }
+#endif
+ else { /* c == '<' */
/*np->nfile.fd = 0; - stzalloc did it */
c = pgetc();
switch (c) {
@@ -11281,9 +11295,14 @@
#ifdef NEW_xxreadtoken
/* singles must be first! */
static const char xxreadtoken_chars[7] ALIGN1 = {
- '\n', '(', ')', '&', '|', ';', 0
+ '\n', '(', ')', /* singles */
+ '&', '|', ';', /* doubles */
+ 0
};
+#define xxreadtoken_singles 3
+#define xxreadtoken_doubles 3
+
static const char xxreadtoken_tokens[] ALIGN1 = {
TNL, TLP, TRP, /* only single occurrence allowed */
TBACKGND, TPIPE, TSEMI, /* if single occurrence */
@@ -11291,11 +11310,6 @@
TAND, TOR, TENDCASE /* if double occurrence */
};
-#define xxreadtoken_doubles \
- (sizeof(xxreadtoken_tokens) - sizeof(xxreadtoken_chars))
-#define xxreadtoken_singles \
- (sizeof(xxreadtoken_chars) - xxreadtoken_doubles - 1)
-
static int
xxreadtoken(void)
{
@@ -11310,7 +11324,7 @@
}
startlinno = plinno;
for (;;) { /* until token or start of word found */
- c = pgetc_macro();
+ c = pgetc_fast();
if (c == ' ' || c == '\t' USE_ASH_ALIAS( || c == PEOA))
continue;
@@ -11321,7 +11335,7 @@
} else if (c == '\\') {
if (pgetc() != '\n') {
pungetc();
- goto READTOKEN1;
+ break; /* return readtoken1(...) */
}
startlinno = ++plinno;
if (doprompt)
@@ -11337,16 +11351,19 @@
}
p = strchr(xxreadtoken_chars, c);
- if (p == NULL) {
- READTOKEN1:
- return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
- }
+ if (p == NULL)
+ break; /* return readtoken1(...) */
- if ((size_t)(p - xxreadtoken_chars) >= xxreadtoken_singles) {
- if (pgetc() == *p) { /* double occurrence? */
+ if ((int)(p - xxreadtoken_chars) >= xxreadtoken_singles) {
+ int cc = pgetc();
+ if (cc == c) { /* double occurrence? */
p += xxreadtoken_doubles + 1;
} else {
pungetc();
+#if ENABLE_ASH_BASH_COMPAT
+ if (c == '&' && cc == '>') /* &> */
+ break; /* return readtoken1(...) */
+#endif
}
}
}
@@ -11354,6 +11371,8 @@
return lasttoken;
}
} /* for (;;) */
+
+ return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
}
#else /* old xxreadtoken */
#define RETURN(token) return lasttoken = token
@@ -11371,7 +11390,7 @@
}
startlinno = plinno;
for (;;) { /* until token or start of word found */
- c = pgetc_macro();
+ c = pgetc_fast();
switch (c) {
case ' ': case '\t':
#if ENABLE_ASH_ALIAS