ash: optional support for $'...\t...\n...' bashism

function                                             old     new   delta
readtoken1                                          2824    3172    +348
static.C_escapes                                       -      18     +18
parse_command                                       1504    1500      -4
SIT                                                   89      83      -6
------------------------------------------------------------------------------
(add/remove: 1/0 grow/shrink: 1/2 up/down: 366/-10)           Total: 356 bytes
This commit is contained in:
Denis Vlasenko 2008-06-23 01:52:30 +00:00
parent a80d0e4bf7
commit ef527f50e6
3 changed files with 104 additions and 29 deletions

View File

@ -1460,19 +1460,19 @@ _STPUTC(int c, char *p)
if (l > m) \ if (l > m) \
(p) = makestrspace(l, q); \ (p) = makestrspace(l, q); \
} while (0) } while (0)
#define USTPUTC(c, p) (*p++ = (c)) #define USTPUTC(c, p) (*(p)++ = (c))
#define STACKSTRNUL(p) \ #define STACKSTRNUL(p) \
do { \ do { \
if ((p) == sstrend) \ if ((p) == sstrend) \
p = growstackstr(); \ (p) = growstackstr(); \
*p = '\0'; \ *(p) = '\0'; \
} while (0) } while (0)
#define STUNPUTC(p) (--p) #define STUNPUTC(p) (--(p))
#define STTOPC(p) (p[-1]) #define STTOPC(p) ((p)[-1])
#define STADJUST(amount, p) (p += (amount)) #define STADJUST(amount, p) ((p) += (amount))
#define grabstackstr(p) stalloc((char *)(p) - (char *)stackblock()) #define grabstackstr(p) stalloc((char *)(p) - (char *)stackblock())
#define ungrabstackstr(s, p) stunalloc((s)) #define ungrabstackstr(s, p) stunalloc(s)
#define stackstrend() ((void *)sstrend) #define stackstrend() ((void *)sstrend)
@ -2687,10 +2687,10 @@ SIT(int c, int syntax)
) { ) {
return CCTL; return CCTL;
} else { } else {
s = strchr(spec_symbls, c); s = strchrnul(spec_symbls, c);
if (s == NULL || *s == '\0') if (*s == '\0')
return CWORD; return CWORD;
indx = syntax_index_table[(s - spec_symbls)]; indx = syntax_index_table[s - spec_symbls];
} }
return S_I_T[indx][syntax]; return S_I_T[indx][syntax];
} }
@ -4201,7 +4201,7 @@ cmdputs(const char *s)
nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc); nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
p = s; p = s;
while ((c = *p++) != 0) { while ((c = *p++) != 0) {
str = 0; str = NULL;
switch (c) { switch (c) {
case CTLESC: case CTLESC:
c = *p++; c = *p++;
@ -10345,6 +10345,52 @@ parse_command(void)
return n1; return n1;
} }
#if ENABLE_ASH_BASH_COMPAT
static int decode_dollar_squote(void)
{
static const char C_escapes[] ALIGN1 = "nrbtfav""x\\01234567";
int c, cnt;
char *p;
char buf[4];
c = pgetc();
p = strchr(C_escapes, c);
if (p) {
buf[0] = c;
p = buf;
cnt = 3;
if ((unsigned char)(c - '0') <= 7) { /* \ooo */
do {
c = pgetc();
*++p = c;
} while ((unsigned char)(c - '0') <= 7 && --cnt);
pungetc();
} else if (c == 'x') { /* \xHH */
do {
c = pgetc();
*++p = c;
} while (isxdigit(c) && --cnt);
pungetc();
if (cnt == 3) { /* \x but next char is "bad" */
c = 'x';
goto unrecognized;
}
} else { /* simple seq like \\ or \t */
p++;
}
*p = '\0';
p = buf;
c = bb_process_escape_sequence((void*)&p);
} else { /* unrecognized "\z": print both chars unless ' or " */
if (c != '\'' && c != '"') {
unrecognized:
c |= 0x100; /* "please encode \, then me" */
}
}
return c;
}
#endif
/* /*
* If eofmark is NULL, read a word or a redirection symbol. If eofmark * If eofmark is NULL, read a word or a redirection symbol. If eofmark
* is not NULL, read a here document. In the latter case, eofmark is the * is not NULL, read a here document. In the latter case, eofmark is the
@ -10356,14 +10402,12 @@ parse_command(void)
* using goto's to implement the subroutine linkage. The following macros * using goto's to implement the subroutine linkage. The following macros
* will run code that appears at the end of readtoken1. * will run code that appears at the end of readtoken1.
*/ */
#define CHECKEND() {goto checkend; checkend_return:;} #define CHECKEND() {goto checkend; checkend_return:;}
#define PARSEREDIR() {goto parseredir; parseredir_return:;} #define PARSEREDIR() {goto parseredir; parseredir_return:;}
#define PARSESUB() {goto parsesub; parsesub_return:;} #define PARSESUB() {goto parsesub; parsesub_return:;}
#define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;} #define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;} #define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
#define PARSEARITH() {goto parsearith; parsearith_return:;} #define PARSEARITH() {goto parsearith; parsearith_return:;}
static int static int
readtoken1(int firstc, int syntax, char *eofmark, int striptabs) readtoken1(int firstc, int syntax, char *eofmark, int striptabs)
{ {
@ -10385,6 +10429,8 @@ readtoken1(int firstc, int syntax, char *eofmark, int striptabs)
int parenlevel; /* levels of parens in arithmetic */ 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 */
USE_ASH_BASH_COMPAT(smallint bash_dollar_squote = 0;)
#if __GNUC__ #if __GNUC__
/* Avoid longjmp clobbering */ /* Avoid longjmp clobbering */
(void) &out; (void) &out;
@ -10435,6 +10481,15 @@ readtoken1(int firstc, int syntax, char *eofmark, int striptabs)
case CCTL: case CCTL:
if (eofmark == NULL || dblquote) if (eofmark == NULL || dblquote)
USTPUTC(CTLESC, out); USTPUTC(CTLESC, out);
#if ENABLE_ASH_BASH_COMPAT
if (c == '\\' && bash_dollar_squote) {
c = decode_dollar_squote();
if (c & 0x100) {
USTPUTC('\\', out);
c = (unsigned char)c;
}
}
#endif
USTPUTC(c, out); USTPUTC(c, out);
break; break;
case CBACK: /* backslash */ case CBACK: /* backslash */
@ -10453,11 +10508,9 @@ readtoken1(int firstc, int syntax, char *eofmark, int striptabs)
USTPUTC('\\', out); USTPUTC('\\', out);
} }
#endif #endif
if (dblquote && if (dblquote && c != '\\'
c != '\\' && c != '`' && && c != '`' && c != '$'
c != '$' && ( && (c != '"' || eofmark != NULL)
c != '"' ||
eofmark != NULL)
) { ) {
USTPUTC(CTLESC, out); USTPUTC(CTLESC, out);
USTPUTC('\\', out); USTPUTC('\\', out);
@ -10480,6 +10533,7 @@ readtoken1(int firstc, int syntax, char *eofmark, int striptabs)
dblquote = 1; dblquote = 1;
goto quotemark; goto quotemark;
case CENDQUOTE: case CENDQUOTE:
USE_ASH_BASH_COMPAT(bash_dollar_squote = 0;)
if (eofmark != NULL && arinest == 0 if (eofmark != NULL && arinest == 0
&& varnest == 0 && varnest == 0
) { ) {
@ -10552,7 +10606,7 @@ readtoken1(int firstc, int syntax, char *eofmark, int striptabs)
} }
c = pgetc_macro(); c = pgetc_macro();
} } /* for(;;) */
} }
endword: endword:
#if ENABLE_ASH_MATH_SUPPORT #if ENABLE_ASH_MATH_SUPPORT
@ -10573,12 +10627,13 @@ readtoken1(int firstc, int syntax, char *eofmark, int striptabs)
if ((c == '>' || c == '<') if ((c == '>' || c == '<')
&& quotef == 0 && quotef == 0
&& len <= 2 && len <= 2
&& (*out == '\0' || isdigit(*out))) { && (*out == '\0' || isdigit(*out))
) {
PARSEREDIR(); PARSEREDIR();
return lasttoken = TREDIR; lasttoken = TREDIR;
} else { return lasttoken;
pungetc();
} }
pungetc();
} }
quoteflag = quotef; quoteflag = quotef;
backquotelist = bqlist; backquotelist = bqlist;
@ -10697,8 +10752,8 @@ parseredir: {
/* is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise /* is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise
* (assuming ascii char codes, as the original implementation did) */ * (assuming ascii char codes, as the original implementation did) */
#define is_special(c) \ #define is_special(c) \
((((unsigned int)c) - 33 < 32) \ (((unsigned)(c) - 33 < 32) \
&& ((0xc1ff920dUL >> (((unsigned int)c) - 33)) & 1)) && ((0xc1ff920dU >> ((unsigned)(c) - 33)) & 1))
parsesub: { parsesub: {
int subtype; int subtype;
int typeloc; int typeloc;
@ -10707,10 +10762,14 @@ parsesub: {
static const char types[] ALIGN1 = "}-+?="; static const char types[] ALIGN1 = "}-+?=";
c = pgetc(); c = pgetc();
if ( if (c <= PEOA_OR_PEOF
c <= 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 (c == '\'')
bash_dollar_squote = 1;
else
#endif
USTPUTC('$', out); USTPUTC('$', out);
pungetc(); pungetc();
} else if (c == '(') { /* $(command) or $((arith)) */ } else if (c == '(') { /* $(command) or $((arith)) */

View File

@ -0,0 +1,9 @@
a b
a
b c
def
a'b c"d e\f
a3b c3b e33f
a\80b c08b
a3b c30b
x y

View File

@ -0,0 +1,7 @@
echo $'a\tb'
echo $'a\nb' $'c\nd''ef'
echo $'a\'b' $'c\"d' $'e\\f'
echo $'a\63b' $'c\063b' $'e\0633f'
echo $'a\80b' $'c\608b'
echo $'a\x33b' $'c\x330b'
echo $'x\x9y'