diff options
Diffstat (limited to 'shell')
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 | ||
630 | static const char dolatstr[] ALIGN1 = { | 627 | static 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 | */ |
5687 | static char * | 5671 | static char * |
5688 | preglob(const char *pattern, int quoted, int flag) | 5672 | preglob(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 | */ |
5907 | static void | 5889 | static void |
5908 | expbackq(union node *cmd, int quoted, int quotes) | 5890 | expbackq(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 | */ |
5969 | static void | 5951 | static void |
5970 | expari(int quotes) | 5952 | expari(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 |
6298 | static char * | 6278 | static char * |
6299 | parse_sub_pattern(char *arg, int varflags) | 6279 | parse_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 | ||
6341 | static const char * | 6321 | static const char * |
6342 | subevalvar(char *p, char *varname, int strloc, int subtype, | 6322 | subevalvar(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 | |||
7307 | expandhere(union node *arg, int fd) | 7286 | expandhere(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) | |||
7317 | static int | 7296 | static int |
7318 | patmatch(char *pattern, const char *string) | 7297 | patmatch(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 @@ | |||
1 | a=/b/c/* | ||
2 | b=\\ | ||
3 | echo ${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#[\\]}>" | |||