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:
parent
a80d0e4bf7
commit
ef527f50e6
117
shell/ash.c
117
shell/ash.c
@ -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,11 +10762,15 @@ 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))
|
|
||||||
) {
|
) {
|
||||||
USTPUTC('$', out);
|
#if ENABLE_ASH_BASH_COMPAT
|
||||||
|
if (c == '\'')
|
||||||
|
bash_dollar_squote = 1;
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
USTPUTC('$', out);
|
||||||
pungetc();
|
pungetc();
|
||||||
} else if (c == '(') { /* $(command) or $((arith)) */
|
} else if (c == '(') { /* $(command) or $((arith)) */
|
||||||
if (pgetc() == '(') {
|
if (pgetc() == '(') {
|
||||||
|
9
shell/ash_test/ash-quoting/dollar_squote_bash1.right
Normal file
9
shell/ash_test/ash-quoting/dollar_squote_bash1.right
Normal 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
|
7
shell/ash_test/ash-quoting/dollar_squote_bash1.tests
Executable file
7
shell/ash_test/ash-quoting/dollar_squote_bash1.tests
Executable 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'
|
Loading…
Reference in New Issue
Block a user