diff options
Diffstat (limited to 'shell')
-rw-r--r-- | shell/ash.c | 117 | ||||
-rw-r--r-- | shell/ash_test/ash-quoting/dollar_squote_bash1.right | 9 | ||||
-rwxr-xr-x | shell/ash_test/ash-quoting/dollar_squote_bash1.tests | 7 |
3 files changed, 104 insertions, 29 deletions
diff --git a/shell/ash.c b/shell/ash.c index 7924c4dd9..8a731fd68 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -1460,19 +1460,19 @@ _STPUTC(int c, char *p) if (l > m) \ (p) = makestrspace(l, q); \ } while (0) -#define USTPUTC(c, p) (*p++ = (c)) +#define USTPUTC(c, p) (*(p)++ = (c)) #define STACKSTRNUL(p) \ do { \ if ((p) == sstrend) \ - p = growstackstr(); \ - *p = '\0'; \ + (p) = growstackstr(); \ + *(p) = '\0'; \ } while (0) -#define STUNPUTC(p) (--p) -#define STTOPC(p) (p[-1]) -#define STADJUST(amount, p) (p += (amount)) +#define STUNPUTC(p) (--(p)) +#define STTOPC(p) ((p)[-1]) +#define STADJUST(amount, p) ((p) += (amount)) #define grabstackstr(p) stalloc((char *)(p) - (char *)stackblock()) -#define ungrabstackstr(s, p) stunalloc((s)) +#define ungrabstackstr(s, p) stunalloc(s) #define stackstrend() ((void *)sstrend) @@ -2687,10 +2687,10 @@ SIT(int c, int syntax) ) { return CCTL; } else { - s = strchr(spec_symbls, c); - if (s == NULL || *s == '\0') + s = strchrnul(spec_symbls, c); + if (*s == '\0') return CWORD; - indx = syntax_index_table[(s - spec_symbls)]; + indx = syntax_index_table[s - spec_symbls]; } return S_I_T[indx][syntax]; } @@ -4201,7 +4201,7 @@ cmdputs(const char *s) nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc); p = s; while ((c = *p++) != 0) { - str = 0; + str = NULL; switch (c) { case CTLESC: c = *p++; @@ -10345,6 +10345,52 @@ parse_command(void) 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 * 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 * will run code that appears at the end of readtoken1. */ - #define CHECKEND() {goto checkend; checkend_return:;} #define PARSEREDIR() {goto parseredir; parseredir_return:;} #define PARSESUB() {goto parsesub; parsesub_return:;} #define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;} #define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;} #define PARSEARITH() {goto parsearith; parsearith_return:;} - static int 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 dqvarnest; /* levels of variables expansion within double quotes */ + USE_ASH_BASH_COMPAT(smallint bash_dollar_squote = 0;) + #if __GNUC__ /* Avoid longjmp clobbering */ (void) &out; @@ -10435,6 +10481,15 @@ readtoken1(int firstc, int syntax, char *eofmark, int striptabs) case CCTL: if (eofmark == NULL || dblquote) 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); break; case CBACK: /* backslash */ @@ -10453,11 +10508,9 @@ readtoken1(int firstc, int syntax, char *eofmark, int striptabs) USTPUTC('\\', out); } #endif - if (dblquote && - c != '\\' && c != '`' && - c != '$' && ( - c != '"' || - eofmark != NULL) + if (dblquote && c != '\\' + && c != '`' && c != '$' + && (c != '"' || eofmark != NULL) ) { USTPUTC(CTLESC, out); USTPUTC('\\', out); @@ -10480,6 +10533,7 @@ readtoken1(int firstc, int syntax, char *eofmark, int striptabs) dblquote = 1; goto quotemark; case CENDQUOTE: + USE_ASH_BASH_COMPAT(bash_dollar_squote = 0;) if (eofmark != NULL && arinest == 0 && varnest == 0 ) { @@ -10552,7 +10606,7 @@ readtoken1(int firstc, int syntax, char *eofmark, int striptabs) } c = pgetc_macro(); - } + } /* for(;;) */ } endword: #if ENABLE_ASH_MATH_SUPPORT @@ -10573,12 +10627,13 @@ readtoken1(int firstc, int syntax, char *eofmark, int striptabs) if ((c == '>' || c == '<') && quotef == 0 && len <= 2 - && (*out == '\0' || isdigit(*out))) { + && (*out == '\0' || isdigit(*out)) + ) { PARSEREDIR(); - return lasttoken = TREDIR; - } else { - pungetc(); + lasttoken = TREDIR; + return lasttoken; } + pungetc(); } quoteflag = quotef; backquotelist = bqlist; @@ -10697,8 +10752,8 @@ parseredir: { /* is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise * (assuming ascii char codes, as the original implementation did) */ #define is_special(c) \ - ((((unsigned int)c) - 33 < 32) \ - && ((0xc1ff920dUL >> (((unsigned int)c) - 33)) & 1)) + (((unsigned)(c) - 33 < 32) \ + && ((0xc1ff920dU >> ((unsigned)(c) - 33)) & 1)) parsesub: { int subtype; int typeloc; @@ -10707,11 +10762,15 @@ parsesub: { static const char types[] ALIGN1 = "}-+?="; c = pgetc(); - if ( - c <= PEOA_OR_PEOF || - (c != '(' && c != '{' && !is_name(c) && !is_special(c)) + if (c <= PEOA_OR_PEOF + || (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(); } else if (c == '(') { /* $(command) or $((arith)) */ if (pgetc() == '(') { diff --git a/shell/ash_test/ash-quoting/dollar_squote_bash1.right b/shell/ash_test/ash-quoting/dollar_squote_bash1.right new file mode 100644 index 000000000..57536b1d9 --- /dev/null +++ b/shell/ash_test/ash-quoting/dollar_squote_bash1.right @@ -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 diff --git a/shell/ash_test/ash-quoting/dollar_squote_bash1.tests b/shell/ash_test/ash-quoting/dollar_squote_bash1.tests new file mode 100755 index 000000000..93a56cac3 --- /dev/null +++ b/shell/ash_test/ash-quoting/dollar_squote_bash1.tests @@ -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' |