aboutsummaryrefslogtreecommitdiff
path: root/shell
diff options
context:
space:
mode:
Diffstat (limited to 'shell')
-rw-r--r--shell/ash.c164
-rw-r--r--shell/ash_test/ash-vars/var-do-not-quote-backslashes-in-parameter-expansions-outside-quotes.right1
-rwxr-xr-xshell/ash_test/ash-vars/var-do-not-quote-backslashes-in-parameter-expansions-outside-quotes.tests3
-rw-r--r--shell/ash_test/ash-vars/var-runtime-quote-detection.right1
-rwxr-xr-xshell/ash_test/ash-vars/var-runtime-quote-detection.tests1
5 files changed, 72 insertions, 98 deletions
diff --git a/shell/ash.c b/shell/ash.c
index 33a477d80..e7e70817f 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -598,8 +598,6 @@ out2str(const char *p)
598#define CTLVAR ((unsigned char)'\202') /* variable defn */ 598#define CTLVAR ((unsigned char)'\202') /* variable defn */
599#define CTLENDVAR ((unsigned char)'\203') 599#define CTLENDVAR ((unsigned char)'\203')
600#define CTLBACKQ ((unsigned char)'\204') 600#define CTLBACKQ ((unsigned char)'\204')
601#define CTLQUOTE 01 /* ored with CTLBACKQ code if in quotes */
602/* CTLBACKQ | CTLQUOTE == '\205' */
603#define CTLARI ((unsigned char)'\206') /* arithmetic expression */ 601#define CTLARI ((unsigned char)'\206') /* arithmetic expression */
604#define CTLENDARI ((unsigned char)'\207') 602#define CTLENDARI ((unsigned char)'\207')
605#define CTLQUOTEMARK ((unsigned char)'\210') 603#define CTLQUOTEMARK ((unsigned char)'\210')
@@ -608,7 +606,6 @@ out2str(const char *p)
608/* variable substitution byte (follows CTLVAR) */ 606/* variable substitution byte (follows CTLVAR) */
609#define VSTYPE 0x0f /* type of variable substitution */ 607#define VSTYPE 0x0f /* type of variable substitution */
610#define VSNUL 0x10 /* colon--treat the empty string as unset */ 608#define VSNUL 0x10 /* colon--treat the empty string as unset */
611#define VSQUOTE 0x80 /* inside double quotes--suppress splitting */
612 609
613/* values of VSTYPE field */ 610/* values of VSTYPE field */
614#define VSNORMAL 0x1 /* normal variable: $var or ${var} */ 611#define VSNORMAL 0x1 /* normal variable: $var or ${var} */
@@ -628,8 +625,9 @@ out2str(const char *p)
628#endif 625#endif
629 626
630static const char dolatstr[] ALIGN1 = { 627static const char dolatstr[] ALIGN1 = {
631 CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0' 628 CTLQUOTEMARK, CTLVAR, VSNORMAL, '@', '=', CTLQUOTEMARK, '\0'
632}; 629};
630#define DOLATSTRLEN 6
633 631
634#define NCMD 0 632#define NCMD 0
635#define NPIPE 1 633#define NPIPE 1
@@ -865,9 +863,7 @@ trace_puts_quoted(char *s)
865 case '\\': c = '\\'; goto backslash; 863 case '\\': c = '\\'; goto backslash;
866 case CTLESC: c = 'e'; goto backslash; 864 case CTLESC: c = 'e'; goto backslash;
867 case CTLVAR: c = 'v'; goto backslash; 865 case CTLVAR: c = 'v'; goto backslash;
868 case CTLVAR+CTLQUOTE: c = 'V'; goto backslash;
869 case CTLBACKQ: c = 'q'; goto backslash; 866 case CTLBACKQ: c = 'q'; goto backslash;
870 case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash;
871 backslash: 867 backslash:
872 putc('\\', tracefile); 868 putc('\\', tracefile);
873 putc(c, tracefile); 869 putc(c, tracefile);
@@ -1030,7 +1026,6 @@ sharg(union node *arg, FILE *fp)
1030 putc('}', fp); 1026 putc('}', fp);
1031 break; 1027 break;
1032 case CTLBACKQ: 1028 case CTLBACKQ:
1033 case CTLBACKQ|CTLQUOTE:
1034 putc('$', fp); 1029 putc('$', fp);
1035 putc('(', fp); 1030 putc('(', fp);
1036 shtree(bqlist->n, -1, NULL, fp); 1031 shtree(bqlist->n, -1, NULL, fp);
@@ -4413,11 +4408,7 @@ cmdputs(const char *s)
4413 str = "${#"; 4408 str = "${#";
4414 else 4409 else
4415 str = "${"; 4410 str = "${";
4416 if (!(subtype & VSQUOTE) == !(quoted & 1)) 4411 goto dostr;
4417 goto dostr;
4418 quoted ^= 1;
4419 c = '"';
4420 break;
4421 case CTLENDVAR: 4412 case CTLENDVAR:
4422 str = "\"}" + !(quoted & 1); 4413 str = "\"}" + !(quoted & 1);
4423 quoted >>= 1; 4414 quoted >>= 1;
@@ -4426,9 +4417,6 @@ cmdputs(const char *s)
4426 case CTLBACKQ: 4417 case CTLBACKQ:
4427 str = "$(...)"; 4418 str = "$(...)";
4428 goto dostr; 4419 goto dostr;
4429 case CTLBACKQ+CTLQUOTE:
4430 str = "\"$(...)\"";
4431 goto dostr;
4432#if ENABLE_SH_MATH_SUPPORT 4420#if ENABLE_SH_MATH_SUPPORT
4433 case CTLARI: 4421 case CTLARI:
4434 str = "$(("; 4422 str = "$((";
@@ -5526,7 +5514,7 @@ ash_arith(const char *s)
5526#define EXP_VARTILDE 0x4 /* expand tildes in an assignment */ 5514#define EXP_VARTILDE 0x4 /* expand tildes in an assignment */
5527#define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */ 5515#define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */
5528#define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */ 5516#define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
5529#define EXP_RECORD 0x20 /* need to record arguments for ifs breakup */ 5517#define EXP_QPAT 0x20 /* pattern in quoted parameter expansion */
5530#define EXP_VARTILDE2 0x40 /* expand tildes after colons only */ 5518#define EXP_VARTILDE2 0x40 /* expand tildes after colons only */
5531#define EXP_WORD 0x80 /* expand word in parameter expansion */ 5519#define EXP_WORD 0x80 /* expand word in parameter expansion */
5532#define EXP_QUOTED 0x100 /* expand word in double quotes */ 5520#define EXP_QUOTED 0x100 /* expand word in double quotes */
@@ -5535,12 +5523,11 @@ ash_arith(const char *s)
5535 */ 5523 */
5536#define RMESCAPE_ALLOC 0x1 /* Allocate a new string */ 5524#define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
5537#define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */ 5525#define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
5538#define RMESCAPE_QUOTED 0x4 /* Remove CTLESC unless in quotes */
5539#define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */ 5526#define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */
5540#define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */ 5527#define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */
5541 5528
5542/* Add CTLESC when necessary. */ 5529/* Add CTLESC when necessary. */
5543#define QUOTES_ESC (EXP_FULL | EXP_CASE | EXP_REDIR) 5530#define QUOTES_ESC (EXP_FULL | EXP_CASE | EXP_QPAT | EXP_REDIR)
5544/* Do not skip NUL characters. */ 5531/* Do not skip NUL characters. */
5545#define QUOTES_KEEPNUL EXP_TILDE 5532#define QUOTES_KEEPNUL EXP_TILDE
5546 5533
@@ -5641,13 +5628,11 @@ rmescapes(char *str, int flag)
5641 } 5628 }
5642 } 5629 }
5643 5630
5644 inquotes = (flag & RMESCAPE_QUOTED) ^ RMESCAPE_QUOTED; 5631 inquotes = 0;
5645 globbing = flag & RMESCAPE_GLOB; 5632 globbing = flag & RMESCAPE_GLOB;
5646 protect_against_glob = globbing; 5633 protect_against_glob = globbing;
5647 while (*p) { 5634 while (*p) {
5648 if ((unsigned char)*p == CTLQUOTEMARK) { 5635 if ((unsigned char)*p == CTLQUOTEMARK) {
5649// TODO: if no RMESCAPE_QUOTED in flags, inquotes never becomes 0
5650// (alternates between RMESCAPE_QUOTED and ~RMESCAPE_QUOTED). Is it ok?
5651// Note: both inquotes and protect_against_glob only affect whether 5636// Note: both inquotes and protect_against_glob only affect whether
5652// CTLESC,<ch> gets converted to <ch> or to \<ch> 5637// CTLESC,<ch> gets converted to <ch> or to \<ch>
5653 inquotes = ~inquotes; 5638 inquotes = ~inquotes;
@@ -5655,16 +5640,15 @@ rmescapes(char *str, int flag)
5655 protect_against_glob = globbing; 5640 protect_against_glob = globbing;
5656 continue; 5641 continue;
5657 } 5642 }
5658 if (*p == '\\') {
5659 /* naked back slash */
5660 protect_against_glob = 0;
5661 goto copy;
5662 }
5663 if ((unsigned char)*p == CTLESC) { 5643 if ((unsigned char)*p == CTLESC) {
5664 p++; 5644 p++;
5665 if (protect_against_glob && inquotes && *p != '/') { 5645 if (protect_against_glob) {
5666 *q++ = '\\'; 5646 *q++ = '\\';
5667 } 5647 }
5648 } else if (*p == '\\' && !inquotes) {
5649 /* naked back slash */
5650 protect_against_glob = 0;
5651 goto copy;
5668 } 5652 }
5669 protect_against_glob = globbing; 5653 protect_against_glob = globbing;
5670 copy: 5654 copy:
@@ -5685,13 +5669,9 @@ rmescapes(char *str, int flag)
5685 * Returns an stalloced string. 5669 * Returns an stalloced string.
5686 */ 5670 */
5687static char * 5671static char *
5688preglob(const char *pattern, int quoted, int flag) 5672preglob(const char *pattern, int flag)
5689{ 5673{
5690 flag |= RMESCAPE_GLOB; 5674 return rmescapes((char *)pattern, flag | RMESCAPE_GLOB);
5691 if (quoted) {
5692 flag |= RMESCAPE_QUOTED;
5693 }
5694 return rmescapes((char *)pattern, flag);
5695} 5675}
5696 5676
5697/* 5677/*
@@ -5712,7 +5692,9 @@ memtodest(const char *p, size_t len, int syntax, int quotes)
5712 if (c) { 5692 if (c) {
5713 int n = SIT(c, syntax); 5693 int n = SIT(c, syntax);
5714 if ((quotes & QUOTES_ESC) && 5694 if ((quotes & QUOTES_ESC) &&
5715 (n == CCTL || n == CBACK)) 5695 ((n == CCTL) ||
5696 (((quotes & EXP_FULL) || syntax != BASESYNTAX) &&
5697 n == CBACK)))
5716 USTPUTC(CTLESC, q); 5698 USTPUTC(CTLESC, q);
5717 } else if (!(quotes & QUOTES_KEEPNUL)) 5699 } else if (!(quotes & QUOTES_KEEPNUL))
5718 continue; 5700 continue;
@@ -5905,7 +5887,7 @@ evalbackcmd(union node *n, struct backcmd *result)
5905 * Expand stuff in backwards quotes. 5887 * Expand stuff in backwards quotes.
5906 */ 5888 */
5907static void 5889static void
5908expbackq(union node *cmd, int quoted, int quotes) 5890expbackq(union node *cmd, int flag)
5909{ 5891{
5910 struct backcmd in; 5892 struct backcmd in;
5911 int i; 5893 int i;
@@ -5913,7 +5895,7 @@ expbackq(union node *cmd, int quoted, int quotes)
5913 char *p; 5895 char *p;
5914 char *dest; 5896 char *dest;
5915 int startloc; 5897 int startloc;
5916 int syntax = quoted ? DQSYNTAX : BASESYNTAX; 5898 int syntax = flag & EXP_QUOTED ? DQSYNTAX : BASESYNTAX;
5917 struct stackmark smark; 5899 struct stackmark smark;
5918 5900
5919 INT_OFF; 5901 INT_OFF;
@@ -5929,7 +5911,7 @@ expbackq(union node *cmd, int quoted, int quotes)
5929 if (i == 0) 5911 if (i == 0)
5930 goto read; 5912 goto read;
5931 for (;;) { 5913 for (;;) {
5932 memtodest(p, i, syntax, quotes); 5914 memtodest(p, i, syntax, flag & QUOTES_ESC);
5933 read: 5915 read:
5934 if (in.fd < 0) 5916 if (in.fd < 0)
5935 break; 5917 break;
@@ -5953,7 +5935,7 @@ expbackq(union node *cmd, int quoted, int quotes)
5953 STUNPUTC(dest); 5935 STUNPUTC(dest);
5954 expdest = dest; 5936 expdest = dest;
5955 5937
5956 if (quoted == 0) 5938 if (!(flag & EXP_QUOTED))
5957 recordregion(startloc, dest - (char *)stackblock(), 0); 5939 recordregion(startloc, dest - (char *)stackblock(), 0);
5958 TRACE(("evalbackq: size:%d:'%.*s'\n", 5940 TRACE(("evalbackq: size:%d:'%.*s'\n",
5959 (int)((dest - (char *)stackblock()) - startloc), 5941 (int)((dest - (char *)stackblock()) - startloc),
@@ -5967,11 +5949,10 @@ expbackq(union node *cmd, int quoted, int quotes)
5967 * evaluate, place result in (backed up) result, adjust string position. 5949 * evaluate, place result in (backed up) result, adjust string position.
5968 */ 5950 */
5969static void 5951static void
5970expari(int quotes) 5952expari(int flag)
5971{ 5953{
5972 char *p, *start; 5954 char *p, *start;
5973 int begoff; 5955 int begoff;
5974 int flag;
5975 int len; 5956 int len;
5976 5957
5977 /* ifsfree(); */ 5958 /* ifsfree(); */
@@ -6009,16 +5990,14 @@ expari(int quotes)
6009 5990
6010 removerecordregions(begoff); 5991 removerecordregions(begoff);
6011 5992
6012 flag = p[1];
6013
6014 expdest = p; 5993 expdest = p;
6015 5994
6016 if (quotes) 5995 if (flag & QUOTES_ESC)
6017 rmescapes(p + 2, 0); 5996 rmescapes(p + 1, 0);
6018 5997
6019 len = cvtnum(ash_arith(p + 2)); 5998 len = cvtnum(ash_arith(p + 1));
6020 5999
6021 if (flag != '"') 6000 if (!(flag & EXP_QUOTED))
6022 recordregion(begoff, begoff + len, 0); 6001 recordregion(begoff, begoff + len, 0);
6023} 6002}
6024#endif 6003#endif
@@ -6046,14 +6025,12 @@ argstr(char *p, int flags, struct strlist *var_str_list)
6046 CTLESC, 6025 CTLESC,
6047 CTLVAR, 6026 CTLVAR,
6048 CTLBACKQ, 6027 CTLBACKQ,
6049 CTLBACKQ | CTLQUOTE,
6050#if ENABLE_SH_MATH_SUPPORT 6028#if ENABLE_SH_MATH_SUPPORT
6051 CTLENDARI, 6029 CTLENDARI,
6052#endif 6030#endif
6053 '\0' 6031 '\0'
6054 }; 6032 };
6055 const char *reject = spclchars; 6033 const char *reject = spclchars;
6056 int quotes = flags & QUOTES_ESC;
6057 int breakall = (flags & (EXP_WORD | EXP_QUOTED)) == EXP_WORD; 6034 int breakall = (flags & (EXP_WORD | EXP_QUOTED)) == EXP_WORD;
6058 int inquotes; 6035 int inquotes;
6059 size_t length; 6036 size_t length;
@@ -6128,19 +6105,14 @@ argstr(char *p, int flags, struct strlist *var_str_list)
6128 case CTLENDVAR: /* ??? */ 6105 case CTLENDVAR: /* ??? */
6129 goto breakloop; 6106 goto breakloop;
6130 case CTLQUOTEMARK: 6107 case CTLQUOTEMARK:
6108 inquotes ^= EXP_QUOTED;
6131 /* "$@" syntax adherence hack */ 6109 /* "$@" syntax adherence hack */
6132 if (!inquotes 6110 if (inquotes && !memcmp(p, dolatstr + 1, DOLATSTRLEN - 1)) {
6133 && memcmp(p, dolatstr, 4) == 0 6111 p = evalvar(p + 1, flags | inquotes, /* var_str_list: */ NULL) + 1;
6134 && ( p[4] == (char)CTLQUOTEMARK
6135 || (p[4] == (char)CTLENDVAR && p[5] == (char)CTLQUOTEMARK)
6136 )
6137 ) {
6138 p = evalvar(p + 1, flags, /* var_str_list: */ NULL) + 1;
6139 goto start; 6112 goto start;
6140 } 6113 }
6141 inquotes = !inquotes;
6142 addquote: 6114 addquote:
6143 if (quotes) { 6115 if (flags & QUOTES_ESC) {
6144 p--; 6116 p--;
6145 length++; 6117 length++;
6146 startloc++; 6118 startloc++;
@@ -6149,22 +6121,30 @@ argstr(char *p, int flags, struct strlist *var_str_list)
6149 case CTLESC: 6121 case CTLESC:
6150 startloc++; 6122 startloc++;
6151 length++; 6123 length++;
6124
6125 /*
6126 * Quoted parameter expansion pattern: remove quote
6127 * unless inside inner quotes or we have a literal
6128 * backslash.
6129 */
6130 if (((flags | inquotes) & (EXP_QPAT | EXP_QUOTED)) ==
6131 EXP_QPAT && *p != '\\')
6132 break;
6133
6152 goto addquote; 6134 goto addquote;
6153 case CTLVAR: 6135 case CTLVAR:
6154 TRACE(("argstr: evalvar('%s')\n", p)); 6136 TRACE(("argstr: evalvar('%s')\n", p));
6155 p = evalvar(p, flags, var_str_list); 6137 p = evalvar(p, flags | inquotes, var_str_list);
6156 TRACE(("argstr: evalvar:'%s'\n", (char *)stackblock())); 6138 TRACE(("argstr: evalvar:'%s'\n", (char *)stackblock()));
6157 goto start; 6139 goto start;
6158 case CTLBACKQ: 6140 case CTLBACKQ:
6159 c = '\0'; 6141 expbackq(argbackq->n, flags | inquotes);
6160 case CTLBACKQ|CTLQUOTE:
6161 expbackq(argbackq->n, c, quotes);
6162 argbackq = argbackq->next; 6142 argbackq = argbackq->next;
6163 goto start; 6143 goto start;
6164#if ENABLE_SH_MATH_SUPPORT 6144#if ENABLE_SH_MATH_SUPPORT
6165 case CTLENDARI: 6145 case CTLENDARI:
6166 p--; 6146 p--;
6167 expari(quotes); 6147 expari(flags | inquotes);
6168 goto start; 6148 goto start;
6169#endif 6149#endif
6170 } 6150 }
@@ -6296,13 +6276,13 @@ varunset(const char *end, const char *var, const char *umsg, int varflags)
6296 6276
6297#if ENABLE_ASH_BASH_COMPAT 6277#if ENABLE_ASH_BASH_COMPAT
6298static char * 6278static char *
6299parse_sub_pattern(char *arg, int varflags) 6279parse_sub_pattern(char *arg, int quoted)
6300{ 6280{
6301 char *idx, *repl = NULL; 6281 char *idx, *repl = NULL;
6302 unsigned char c; 6282 unsigned char c;
6303 6283
6304 //char *org_arg = arg; 6284 //char *org_arg = arg;
6305 //bb_error_msg("arg:'%s' varflags:%x", arg, varflags); 6285 //bb_error_msg("arg:'%s' quoted:%x", arg, quoted);
6306 idx = arg; 6286 idx = arg;
6307 while (1) { 6287 while (1) {
6308 c = *arg; 6288 c = *arg;
@@ -6318,7 +6298,7 @@ parse_sub_pattern(char *arg, int varflags)
6318 *idx++ = c; 6298 *idx++ = c;
6319 arg++; 6299 arg++;
6320 /* 6300 /*
6321 * Example: v='ab\c'; echo ${v/\\b/_\\_\z_} 6301 * Example: v='a\bc'; echo ${v/\\b/_\\_\z_}
6322 * The result is a_\_z_c (not a\_\_z_c)! 6302 * The result is a_\_z_c (not a\_\_z_c)!
6323 * 6303 *
6324 * Enable debug prints in this function and you'll see: 6304 * Enable debug prints in this function and you'll see:
@@ -6328,7 +6308,7 @@ parse_sub_pattern(char *arg, int varflags)
6328 * IOW: search pattern and replace string treat backslashes 6308 * IOW: search pattern and replace string treat backslashes
6329 * differently! That is the reason why we check repl below: 6309 * differently! That is the reason why we check repl below:
6330 */ 6310 */
6331 if (c == '\\' && *arg == '\\' && repl && !(varflags & VSQUOTE)) 6311 if (c == '\\' && *arg == '\\' && repl && !quoted)
6332 arg++; /* skip both '\', not just first one */ 6312 arg++; /* skip both '\', not just first one */
6333 } 6313 }
6334 *idx = c; /* NUL */ 6314 *idx = c; /* NUL */
@@ -6340,9 +6320,10 @@ parse_sub_pattern(char *arg, int varflags)
6340 6320
6341static const char * 6321static const char *
6342subevalvar(char *p, char *varname, int strloc, int subtype, 6322subevalvar(char *p, char *varname, int strloc, int subtype,
6343 int startloc, int varflags, int quotes, struct strlist *var_str_list) 6323 int startloc, int varflags, int flag, struct strlist *var_str_list)
6344{ 6324{
6345 struct nodelist *saveargbackq = argbackq; 6325 struct nodelist *saveargbackq = argbackq;
6326 int quotes = flag & QUOTES_ESC;
6346 char *startp; 6327 char *startp;
6347 char *loc; 6328 char *loc;
6348 char *rmesc, *rmescend; 6329 char *rmesc, *rmescend;
@@ -6360,7 +6341,8 @@ subevalvar(char *p, char *varname, int strloc, int subtype,
6360 6341
6361 herefd = -1; 6342 herefd = -1;
6362 argstr(p, EXP_TILDE | (subtype != VSASSIGN && subtype != VSQUESTION ? 6343 argstr(p, EXP_TILDE | (subtype != VSASSIGN && subtype != VSQUESTION ?
6363 EXP_CASE : 0), var_str_list); 6344 (flag & (EXP_QUOTED | EXP_QPAT) ? EXP_QPAT : EXP_CASE) : 0),
6345 var_str_list);
6364 STPUTC('\0', expdest); 6346 STPUTC('\0', expdest);
6365 herefd = saveherefd; 6347 herefd = saveherefd;
6366 argbackq = saveargbackq; 6348 argbackq = saveargbackq;
@@ -6471,7 +6453,7 @@ subevalvar(char *p, char *varname, int strloc, int subtype,
6471 } 6453 }
6472 rmescend--; 6454 rmescend--;
6473 str = (char *)stackblock() + strloc; 6455 str = (char *)stackblock() + strloc;
6474 preglob(str, varflags & VSQUOTE, 0); 6456 preglob(str, 0);
6475 6457
6476#if ENABLE_ASH_BASH_COMPAT 6458#if ENABLE_ASH_BASH_COMPAT
6477 workloc = expdest - (char *)stackblock(); 6459 workloc = expdest - (char *)stackblock();
@@ -6479,7 +6461,7 @@ subevalvar(char *p, char *varname, int strloc, int subtype,
6479 char *idx, *end; 6461 char *idx, *end;
6480 6462
6481 if (!repl) { 6463 if (!repl) {
6482 repl = parse_sub_pattern(str, varflags); 6464 repl = parse_sub_pattern(str, flag & EXP_QUOTED);
6483 //bb_error_msg("repl:'%s'", repl); 6465 //bb_error_msg("repl:'%s'", repl);
6484 if (!repl) 6466 if (!repl)
6485 repl = nullstr; 6467 repl = nullstr;
@@ -6618,7 +6600,7 @@ varvalue(char *name, int varflags, int flags, struct strlist *var_str_list)
6618 int i; 6600 int i;
6619 ssize_t len = 0; 6601 ssize_t len = 0;
6620 int sep; 6602 int sep;
6621 int quoted = varflags & VSQUOTE; 6603 int quoted = flags & EXP_QUOTED;
6622 int subtype = varflags & VSTYPE; 6604 int subtype = varflags & VSTYPE;
6623 int discard = subtype == VSPLUS || subtype == VSLENGTH; 6605 int discard = subtype == VSPLUS || subtype == VSLENGTH;
6624 int quotes = (discard ? 0 : (flags & QUOTES_ESC)) | QUOTES_KEEPNUL; 6606 int quotes = (discard ? 0 : (flags & QUOTES_ESC)) | QUOTES_KEEPNUL;
@@ -6758,7 +6740,7 @@ evalvar(char *p, int flags, struct strlist *var_str_list)
6758{ 6740{
6759 char varflags; 6741 char varflags;
6760 char subtype; 6742 char subtype;
6761 char quoted; 6743 int quoted;
6762 char easy; 6744 char easy;
6763 char *var; 6745 char *var;
6764 int patloc; 6746 int patloc;
@@ -6767,7 +6749,7 @@ evalvar(char *p, int flags, struct strlist *var_str_list)
6767 6749
6768 varflags = (unsigned char) *p++; 6750 varflags = (unsigned char) *p++;
6769 subtype = varflags & VSTYPE; 6751 subtype = varflags & VSTYPE;
6770 quoted = varflags & VSQUOTE; 6752 quoted = flags & EXP_QUOTED;
6771 var = p; 6753 var = p;
6772 easy = (!quoted || (*var == '@' && shellparam.nparam)); 6754 easy = (!quoted || (*var == '@' && shellparam.nparam));
6773 startloc = expdest - (char *)stackblock(); 6755 startloc = expdest - (char *)stackblock();
@@ -6788,7 +6770,7 @@ evalvar(char *p, int flags, struct strlist *var_str_list)
6788 if (varlen < 0) { 6770 if (varlen < 0) {
6789 argstr( 6771 argstr(
6790 p, 6772 p,
6791 flags | EXP_TILDE | EXP_WORD | (quoted ? EXP_QUOTED : 0), 6773 flags | EXP_TILDE | EXP_WORD,
6792 var_str_list 6774 var_str_list
6793 ); 6775 );
6794 goto end; 6776 goto end;
@@ -6802,7 +6784,7 @@ evalvar(char *p, int flags, struct strlist *var_str_list)
6802 if (varlen < 0) { 6784 if (varlen < 0) {
6803 if (subevalvar(p, var, /* strloc: */ 0, 6785 if (subevalvar(p, var, /* strloc: */ 0,
6804 subtype, startloc, varflags, 6786 subtype, startloc, varflags,
6805 /* quotes: */ 0, 6787 /* quotes: */ flags & ~QUOTES_ESC,
6806 var_str_list) 6788 var_str_list)
6807 ) { 6789 ) {
6808 varflags &= ~VSNUL; 6790 varflags &= ~VSNUL;
@@ -6859,10 +6841,7 @@ evalvar(char *p, int flags, struct strlist *var_str_list)
6859 STPUTC('\0', expdest); 6841 STPUTC('\0', expdest);
6860 patloc = expdest - (char *)stackblock(); 6842 patloc = expdest - (char *)stackblock();
6861 if (NULL == subevalvar(p, /* varname: */ NULL, patloc, subtype, 6843 if (NULL == subevalvar(p, /* varname: */ NULL, patloc, subtype,
6862 startloc, varflags, 6844 startloc, varflags, flags, var_str_list)) {
6863 /* quotes: */ flags & QUOTES_ESC,
6864 var_str_list)
6865 ) {
6866 int amount = expdest - ( 6845 int amount = expdest - (
6867 (char *)stackblock() + patloc - 1 6846 (char *)stackblock() + patloc - 1
6868 ); 6847 );
@@ -6881,7 +6860,7 @@ evalvar(char *p, int flags, struct strlist *var_str_list)
6881 unsigned char c = *p++; 6860 unsigned char c = *p++;
6882 if (c == CTLESC) 6861 if (c == CTLESC)
6883 p++; 6862 p++;
6884 else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) { 6863 else if (c == CTLBACKQ) {
6885 if (varlen >= 0) 6864 if (varlen >= 0)
6886 argbackq = argbackq->next; 6865 argbackq = argbackq->next;
6887 } else if (c == CTLVAR) { 6866 } else if (c == CTLVAR) {
@@ -7217,7 +7196,7 @@ expandmeta(struct strlist *str /*, int flag*/)
7217 savelastp = exparg.lastp; 7196 savelastp = exparg.lastp;
7218 7197
7219 INT_OFF; 7198 INT_OFF;
7220 p = preglob(str->text, 0, RMESCAPE_ALLOC | RMESCAPE_HEAP); 7199 p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP);
7221 { 7200 {
7222 int i = strlen(str->text); 7201 int i = strlen(str->text);
7223 expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */ 7202 expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
@@ -7307,7 +7286,7 @@ static void
7307expandhere(union node *arg, int fd) 7286expandhere(union node *arg, int fd)
7308{ 7287{
7309 herefd = fd; 7288 herefd = fd;
7310 expandarg(arg, (struct arglist *)NULL, 0); 7289 expandarg(arg, (struct arglist *)NULL, EXP_QUOTED);
7311 full_write(fd, stackblock(), expdest - (char *)stackblock()); 7290 full_write(fd, stackblock(), expdest - (char *)stackblock());
7312} 7291}
7313 7292
@@ -7317,7 +7296,7 @@ expandhere(union node *arg, int fd)
7317static int 7296static int
7318patmatch(char *pattern, const char *string) 7297patmatch(char *pattern, const char *string)
7319{ 7298{
7320 return pmatch(preglob(pattern, 0, 0), string); 7299 return pmatch(preglob(pattern, 0), string);
7321} 7300}
7322 7301
7323/* 7302/*
@@ -8570,7 +8549,7 @@ evalfor(union node *n, int flags)
8570 arglist.list = NULL; 8549 arglist.list = NULL;
8571 arglist.lastp = &arglist.list; 8550 arglist.lastp = &arglist.list;
8572 for (argp = n->nfor.args; argp; argp = argp->narg.next) { 8551 for (argp = n->nfor.args; argp; argp = argp->narg.next) {
8573 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD); 8552 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
8574 /* XXX */ 8553 /* XXX */
8575 if (evalskip) 8554 if (evalskip)
8576 goto out; 8555 goto out;
@@ -11260,11 +11239,9 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs)
11260 && c != '$' 11239 && c != '$'
11261 && (c != '"' || eofmark != NULL) 11240 && (c != '"' || eofmark != NULL)
11262 ) { 11241 ) {
11263 USTPUTC(CTLESC, out);
11264 USTPUTC('\\', out); 11242 USTPUTC('\\', out);
11265 } 11243 }
11266 if (SIT(c, SQSYNTAX) == CCTL) 11244 USTPUTC(CTLESC, out);
11267 USTPUTC(CTLESC, out);
11268 USTPUTC(c, out); 11245 USTPUTC(c, out);
11269 quotef = 1; 11246 quotef = 1;
11270 } 11247 }
@@ -11637,8 +11614,6 @@ parsesub: {
11637 do_pungetc: 11614 do_pungetc:
11638 pungetc(); 11615 pungetc();
11639 } 11616 }
11640 if (dblquote || arinest)
11641 flags |= VSQUOTE;
11642 ((unsigned char *)stackblock())[typeloc] = subtype | flags; 11617 ((unsigned char *)stackblock())[typeloc] = subtype | flags;
11643 if (subtype != VSNORMAL) { 11618 if (subtype != VSNORMAL) {
11644 varnest++; 11619 varnest++;
@@ -11792,10 +11767,7 @@ parsebackq: {
11792 } 11767 }
11793 parsebackquote = savepbq; 11768 parsebackquote = savepbq;
11794 exception_handler = savehandler; 11769 exception_handler = savehandler;
11795 if (arinest || dblquote) 11770 USTPUTC(CTLBACKQ, out);
11796 USTPUTC(CTLBACKQ | CTLQUOTE, out);
11797 else
11798 USTPUTC(CTLBACKQ, out);
11799 if (oldstyle) 11771 if (oldstyle)
11800 goto parsebackq_oldreturn; 11772 goto parsebackq_oldreturn;
11801 goto parsebackq_newreturn; 11773 goto parsebackq_newreturn;
@@ -11811,10 +11783,6 @@ parsearith: {
11811 syntax = ARISYNTAX; 11783 syntax = ARISYNTAX;
11812 } 11784 }
11813 USTPUTC(CTLARI, out); 11785 USTPUTC(CTLARI, out);
11814 if (dblquote)
11815 USTPUTC('"', out);
11816 else
11817 USTPUTC(' ', out);
11818 goto parsearith_return; 11786 goto parsearith_return;
11819} 11787}
11820#endif 11788#endif
@@ -12129,7 +12097,7 @@ expandstr(const char *ps)
12129 n.narg.text = wordtext; 12097 n.narg.text = wordtext;
12130 n.narg.backquote = backquotelist; 12098 n.narg.backquote = backquotelist;
12131 12099
12132 expandarg(&n, NULL, 0); 12100 expandarg(&n, NULL, EXP_QUOTED);
12133 return stackblock(); 12101 return stackblock();
12134} 12102}
12135#endif 12103#endif
diff --git a/shell/ash_test/ash-vars/var-do-not-quote-backslashes-in-parameter-expansions-outside-quotes.right b/shell/ash_test/ash-vars/var-do-not-quote-backslashes-in-parameter-expansions-outside-quotes.right
new file mode 100644
index 000000000..030ebdeb6
--- /dev/null
+++ b/shell/ash_test/ash-vars/var-do-not-quote-backslashes-in-parameter-expansions-outside-quotes.right
@@ -0,0 +1 @@
/b/c/
diff --git a/shell/ash_test/ash-vars/var-do-not-quote-backslashes-in-parameter-expansions-outside-quotes.tests b/shell/ash_test/ash-vars/var-do-not-quote-backslashes-in-parameter-expansions-outside-quotes.tests
new file mode 100755
index 000000000..fb9371467
--- /dev/null
+++ b/shell/ash_test/ash-vars/var-do-not-quote-backslashes-in-parameter-expansions-outside-quotes.tests
@@ -0,0 +1,3 @@
1a=/b/c/*
2b=\\
3echo ${a%$b*}
diff --git a/shell/ash_test/ash-vars/var-runtime-quote-detection.right b/shell/ash_test/ash-vars/var-runtime-quote-detection.right
new file mode 100644
index 000000000..b554d9e46
--- /dev/null
+++ b/shell/ash_test/ash-vars/var-runtime-quote-detection.right
@@ -0,0 +1 @@
<>
diff --git a/shell/ash_test/ash-vars/var-runtime-quote-detection.tests b/shell/ash_test/ash-vars/var-runtime-quote-detection.tests
new file mode 100755
index 000000000..e570631fd
--- /dev/null
+++ b/shell/ash_test/ash-vars/var-runtime-quote-detection.tests
@@ -0,0 +1 @@
foo=\\ echo "<${foo#[\\]}>"