diff options
author | Ron Yorston <rmy@pobox.com> | 2015-05-18 09:36:27 +0100 |
---|---|---|
committer | Ron Yorston <rmy@pobox.com> | 2015-05-18 09:36:27 +0100 |
commit | 60063627a6d540871061854a362047e6517f821c (patch) | |
tree | 0de228630450c64e085f2e3f5141b5ba17eccab3 /shell | |
parent | ec39cb770ddd5c0e085d5c4ee10be65bab5e7a44 (diff) | |
parent | 9a595bb36ded308e6d4336aef2c1cd3ac738a398 (diff) | |
download | busybox-w32-60063627a6d540871061854a362047e6517f821c.tar.gz busybox-w32-60063627a6d540871061854a362047e6517f821c.tar.bz2 busybox-w32-60063627a6d540871061854a362047e6517f821c.zip |
Merge branch 'busybox' into mergeFRP
Diffstat (limited to 'shell')
44 files changed, 241 insertions, 222 deletions
diff --git a/shell/ash.c b/shell/ash.c index 8cc3f0872..578904478 100644 --- a/shell/ash.c +++ b/shell/ash.c | |||
@@ -666,8 +666,6 @@ out2str(const char *p) | |||
666 | #define CTLVAR ((unsigned char)'\202') /* variable defn */ | 666 | #define CTLVAR ((unsigned char)'\202') /* variable defn */ |
667 | #define CTLENDVAR ((unsigned char)'\203') | 667 | #define CTLENDVAR ((unsigned char)'\203') |
668 | #define CTLBACKQ ((unsigned char)'\204') | 668 | #define CTLBACKQ ((unsigned char)'\204') |
669 | #define CTLQUOTE 01 /* ored with CTLBACKQ code if in quotes */ | ||
670 | /* CTLBACKQ | CTLQUOTE == '\205' */ | ||
671 | #define CTLARI ((unsigned char)'\206') /* arithmetic expression */ | 669 | #define CTLARI ((unsigned char)'\206') /* arithmetic expression */ |
672 | #define CTLENDARI ((unsigned char)'\207') | 670 | #define CTLENDARI ((unsigned char)'\207') |
673 | #define CTLQUOTEMARK ((unsigned char)'\210') | 671 | #define CTLQUOTEMARK ((unsigned char)'\210') |
@@ -676,7 +674,6 @@ out2str(const char *p) | |||
676 | /* variable substitution byte (follows CTLVAR) */ | 674 | /* variable substitution byte (follows CTLVAR) */ |
677 | #define VSTYPE 0x0f /* type of variable substitution */ | 675 | #define VSTYPE 0x0f /* type of variable substitution */ |
678 | #define VSNUL 0x10 /* colon--treat the empty string as unset */ | 676 | #define VSNUL 0x10 /* colon--treat the empty string as unset */ |
679 | #define VSQUOTE 0x80 /* inside double quotes--suppress splitting */ | ||
680 | 677 | ||
681 | /* values of VSTYPE field */ | 678 | /* values of VSTYPE field */ |
682 | #define VSNORMAL 0x1 /* normal variable: $var or ${var} */ | 679 | #define VSNORMAL 0x1 /* normal variable: $var or ${var} */ |
@@ -696,8 +693,9 @@ out2str(const char *p) | |||
696 | #endif | 693 | #endif |
697 | 694 | ||
698 | static const char dolatstr[] ALIGN1 = { | 695 | static const char dolatstr[] ALIGN1 = { |
699 | CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0' | 696 | CTLQUOTEMARK, CTLVAR, VSNORMAL, '@', '=', CTLQUOTEMARK, '\0' |
700 | }; | 697 | }; |
698 | #define DOLATSTRLEN 6 | ||
701 | 699 | ||
702 | #define NCMD 0 | 700 | #define NCMD 0 |
703 | #define NPIPE 1 | 701 | #define NPIPE 1 |
@@ -933,9 +931,7 @@ trace_puts_quoted(char *s) | |||
933 | case '\\': c = '\\'; goto backslash; | 931 | case '\\': c = '\\'; goto backslash; |
934 | case CTLESC: c = 'e'; goto backslash; | 932 | case CTLESC: c = 'e'; goto backslash; |
935 | case CTLVAR: c = 'v'; goto backslash; | 933 | case CTLVAR: c = 'v'; goto backslash; |
936 | case CTLVAR+CTLQUOTE: c = 'V'; goto backslash; | ||
937 | case CTLBACKQ: c = 'q'; goto backslash; | 934 | case CTLBACKQ: c = 'q'; goto backslash; |
938 | case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash; | ||
939 | backslash: | 935 | backslash: |
940 | putc('\\', tracefile); | 936 | putc('\\', tracefile); |
941 | putc(c, tracefile); | 937 | putc(c, tracefile); |
@@ -1098,7 +1094,6 @@ sharg(union node *arg, FILE *fp) | |||
1098 | putc('}', fp); | 1094 | putc('}', fp); |
1099 | break; | 1095 | break; |
1100 | case CTLBACKQ: | 1096 | case CTLBACKQ: |
1101 | case CTLBACKQ|CTLQUOTE: | ||
1102 | putc('$', fp); | 1097 | putc('$', fp); |
1103 | putc('(', fp); | 1098 | putc('(', fp); |
1104 | shtree(bqlist->n, -1, NULL, fp); | 1099 | shtree(bqlist->n, -1, NULL, fp); |
@@ -2098,7 +2093,7 @@ varcmp(const char *p, const char *q) | |||
2098 | int c, d; | 2093 | int c, d; |
2099 | 2094 | ||
2100 | while ((c = *p) == (d = *q)) { | 2095 | while ((c = *p) == (d = *q)) { |
2101 | if (!c || c == '=') | 2096 | if (c == '\0' || c == '=') |
2102 | goto out; | 2097 | goto out; |
2103 | p++; | 2098 | p++; |
2104 | q++; | 2099 | q++; |
@@ -2315,7 +2310,7 @@ setvar(const char *name, const char *val, int flags) | |||
2315 | } | 2310 | } |
2316 | 2311 | ||
2317 | static void FAST_FUNC | 2312 | static void FAST_FUNC |
2318 | setvar2(const char *name, const char *val) | 2313 | setvar0(const char *name, const char *val) |
2319 | { | 2314 | { |
2320 | setvar(name, val, 0); | 2315 | setvar(name, val, 0); |
2321 | } | 2316 | } |
@@ -2378,7 +2373,7 @@ unsetvar(const char *s) | |||
2378 | free(vp); | 2373 | free(vp); |
2379 | INT_ON; | 2374 | INT_ON; |
2380 | } else { | 2375 | } else { |
2381 | setvar2(s, 0); | 2376 | setvar0(s, NULL); |
2382 | vp->flags &= ~VEXPORT; | 2377 | vp->flags &= ~VEXPORT; |
2383 | } | 2378 | } |
2384 | ok: | 2379 | ok: |
@@ -4689,11 +4684,7 @@ cmdputs(const char *s) | |||
4689 | str = "${#"; | 4684 | str = "${#"; |
4690 | else | 4685 | else |
4691 | str = "${"; | 4686 | str = "${"; |
4692 | if (!(subtype & VSQUOTE) == !(quoted & 1)) | 4687 | goto dostr; |
4693 | goto dostr; | ||
4694 | quoted ^= 1; | ||
4695 | c = '"'; | ||
4696 | break; | ||
4697 | case CTLENDVAR: | 4688 | case CTLENDVAR: |
4698 | str = "\"}" + !(quoted & 1); | 4689 | str = "\"}" + !(quoted & 1); |
4699 | quoted >>= 1; | 4690 | quoted >>= 1; |
@@ -4702,9 +4693,6 @@ cmdputs(const char *s) | |||
4702 | case CTLBACKQ: | 4693 | case CTLBACKQ: |
4703 | str = "$(...)"; | 4694 | str = "$(...)"; |
4704 | goto dostr; | 4695 | goto dostr; |
4705 | case CTLBACKQ+CTLQUOTE: | ||
4706 | str = "\"$(...)\""; | ||
4707 | goto dostr; | ||
4708 | #if ENABLE_SH_MATH_SUPPORT | 4696 | #if ENABLE_SH_MATH_SUPPORT |
4709 | case CTLARI: | 4697 | case CTLARI: |
4710 | str = "$(("; | 4698 | str = "$(("; |
@@ -5822,7 +5810,7 @@ ash_arith(const char *s) | |||
5822 | arith_t result; | 5810 | arith_t result; |
5823 | 5811 | ||
5824 | math_state.lookupvar = lookupvar; | 5812 | math_state.lookupvar = lookupvar; |
5825 | math_state.setvar = setvar2; | 5813 | math_state.setvar = setvar0; |
5826 | //math_state.endofname = endofname; | 5814 | //math_state.endofname = endofname; |
5827 | 5815 | ||
5828 | INT_OFF; | 5816 | INT_OFF; |
@@ -5843,18 +5831,23 @@ ash_arith(const char *s) | |||
5843 | #define EXP_VARTILDE 0x4 /* expand tildes in an assignment */ | 5831 | #define EXP_VARTILDE 0x4 /* expand tildes in an assignment */ |
5844 | #define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */ | 5832 | #define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */ |
5845 | #define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */ | 5833 | #define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */ |
5846 | #define EXP_RECORD 0x20 /* need to record arguments for ifs breakup */ | 5834 | #define EXP_QPAT 0x20 /* pattern in quoted parameter expansion */ |
5847 | #define EXP_VARTILDE2 0x40 /* expand tildes after colons only */ | 5835 | #define EXP_VARTILDE2 0x40 /* expand tildes after colons only */ |
5848 | #define EXP_WORD 0x80 /* expand word in parameter expansion */ | 5836 | #define EXP_WORD 0x80 /* expand word in parameter expansion */ |
5849 | #define EXP_QWORD 0x100 /* expand word in quoted parameter expansion */ | 5837 | #define EXP_QUOTED 0x100 /* expand word in double quotes */ |
5850 | /* | 5838 | /* |
5851 | * rmescape() flags | 5839 | * rmescape() flags |
5852 | */ | 5840 | */ |
5853 | #define RMESCAPE_ALLOC 0x1 /* Allocate a new string */ | 5841 | #define RMESCAPE_ALLOC 0x1 /* Allocate a new string */ |
5854 | #define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */ | 5842 | #define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */ |
5855 | #define RMESCAPE_QUOTED 0x4 /* Remove CTLESC unless in quotes */ | ||
5856 | #define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */ | 5843 | #define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */ |
5857 | #define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */ | 5844 | #define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */ |
5845 | #define RMESCAPE_SLASH 0x20 /* Stop globbing after slash */ | ||
5846 | |||
5847 | /* Add CTLESC when necessary. */ | ||
5848 | #define QUOTES_ESC (EXP_FULL | EXP_CASE | EXP_QPAT | EXP_REDIR) | ||
5849 | /* Do not skip NUL characters. */ | ||
5850 | #define QUOTES_KEEPNUL EXP_TILDE | ||
5858 | 5851 | ||
5859 | /* | 5852 | /* |
5860 | * Structure specifying which parts of the string should be searched | 5853 | * Structure specifying which parts of the string should be searched |
@@ -5919,14 +5912,16 @@ esclen(const char *start, const char *p) | |||
5919 | static char * | 5912 | static char * |
5920 | rmescapes(char *str, int flag) | 5913 | rmescapes(char *str, int flag) |
5921 | { | 5914 | { |
5922 | static const char qchars[] ALIGN1 = { CTLESC, CTLQUOTEMARK, '\0' }; | 5915 | static const char qchars[] ALIGN1 = { |
5916 | IF_ASH_BASH_COMPAT('/',) CTLESC, CTLQUOTEMARK, '\0' }; | ||
5923 | 5917 | ||
5924 | char *p, *q, *r; | 5918 | char *p, *q, *r; |
5925 | unsigned inquotes; | 5919 | unsigned inquotes; |
5926 | unsigned protect_against_glob; | 5920 | unsigned protect_against_glob; |
5927 | unsigned globbing; | 5921 | unsigned globbing; |
5922 | IF_ASH_BASH_COMPAT(unsigned slash = flag & RMESCAPE_SLASH;) | ||
5928 | 5923 | ||
5929 | p = strpbrk(str, qchars); | 5924 | p = strpbrk(str, qchars IF_ASH_BASH_COMPAT(+ !slash)); |
5930 | if (!p) | 5925 | if (!p) |
5931 | return str; | 5926 | return str; |
5932 | 5927 | ||
@@ -5953,13 +5948,11 @@ rmescapes(char *str, int flag) | |||
5953 | } | 5948 | } |
5954 | } | 5949 | } |
5955 | 5950 | ||
5956 | inquotes = (flag & RMESCAPE_QUOTED) ^ RMESCAPE_QUOTED; | 5951 | inquotes = 0; |
5957 | globbing = flag & RMESCAPE_GLOB; | 5952 | globbing = flag & RMESCAPE_GLOB; |
5958 | protect_against_glob = globbing; | 5953 | protect_against_glob = globbing; |
5959 | while (*p) { | 5954 | while (*p) { |
5960 | if ((unsigned char)*p == CTLQUOTEMARK) { | 5955 | if ((unsigned char)*p == CTLQUOTEMARK) { |
5961 | // TODO: if no RMESCAPE_QUOTED in flags, inquotes never becomes 0 | ||
5962 | // (alternates between RMESCAPE_QUOTED and ~RMESCAPE_QUOTED). Is it ok? | ||
5963 | // Note: both inquotes and protect_against_glob only affect whether | 5956 | // Note: both inquotes and protect_against_glob only affect whether |
5964 | // CTLESC,<ch> gets converted to <ch> or to \<ch> | 5957 | // CTLESC,<ch> gets converted to <ch> or to \<ch> |
5965 | inquotes = ~inquotes; | 5958 | inquotes = ~inquotes; |
@@ -5967,17 +5960,23 @@ rmescapes(char *str, int flag) | |||
5967 | protect_against_glob = globbing; | 5960 | protect_against_glob = globbing; |
5968 | continue; | 5961 | continue; |
5969 | } | 5962 | } |
5970 | if (*p == '\\') { | ||
5971 | /* naked back slash */ | ||
5972 | protect_against_glob = 0; | ||
5973 | goto copy; | ||
5974 | } | ||
5975 | if ((unsigned char)*p == CTLESC) { | 5963 | if ((unsigned char)*p == CTLESC) { |
5976 | p++; | 5964 | p++; |
5977 | if (protect_against_glob && inquotes && *p != '/') { | 5965 | if (protect_against_glob) { |
5978 | *q++ = '\\'; | 5966 | *q++ = '\\'; |
5979 | } | 5967 | } |
5968 | } else if (*p == '\\' && !inquotes) { | ||
5969 | /* naked back slash */ | ||
5970 | protect_against_glob = 0; | ||
5971 | goto copy; | ||
5972 | } | ||
5973 | #if ENABLE_ASH_BASH_COMPAT | ||
5974 | else if (*p == '/' && slash) { | ||
5975 | /* stop handling globbing and mark location of slash */ | ||
5976 | globbing = slash = 0; | ||
5977 | *p = CTLESC; | ||
5980 | } | 5978 | } |
5979 | #endif | ||
5981 | protect_against_glob = globbing; | 5980 | protect_against_glob = globbing; |
5982 | copy: | 5981 | copy: |
5983 | *q++ = *p++; | 5982 | *q++ = *p++; |
@@ -5997,13 +5996,9 @@ rmescapes(char *str, int flag) | |||
5997 | * Returns an stalloced string. | 5996 | * Returns an stalloced string. |
5998 | */ | 5997 | */ |
5999 | static char * | 5998 | static char * |
6000 | preglob(const char *pattern, int quoted, int flag) | 5999 | preglob(const char *pattern, int flag) |
6001 | { | 6000 | { |
6002 | flag |= RMESCAPE_GLOB; | 6001 | return rmescapes((char *)pattern, flag | RMESCAPE_GLOB); |
6003 | if (quoted) { | ||
6004 | flag |= RMESCAPE_QUOTED; | ||
6005 | } | ||
6006 | return rmescapes((char *)pattern, flag); | ||
6007 | } | 6002 | } |
6008 | 6003 | ||
6009 | /* | 6004 | /* |
@@ -6012,29 +6007,36 @@ preglob(const char *pattern, int quoted, int flag) | |||
6012 | static void | 6007 | static void |
6013 | memtodest(const char *p, size_t len, int syntax, int quotes) | 6008 | memtodest(const char *p, size_t len, int syntax, int quotes) |
6014 | { | 6009 | { |
6015 | char *q = expdest; | 6010 | char *q; |
6011 | |||
6012 | if (!len) | ||
6013 | return; | ||
6016 | 6014 | ||
6017 | q = makestrspace(quotes ? len * 2 : len, q); | 6015 | q = makestrspace((quotes & QUOTES_ESC) ? len * 2 : len, expdest); |
6018 | 6016 | ||
6019 | while (len--) { | 6017 | do { |
6020 | unsigned char c = *p++; | 6018 | unsigned char c = *p++; |
6021 | if (c == '\0') | 6019 | if (c) { |
6022 | continue; | ||
6023 | if (quotes) { | ||
6024 | int n = SIT(c, syntax); | 6020 | int n = SIT(c, syntax); |
6025 | if (n == CCTL || n == CBACK) | 6021 | if ((quotes & QUOTES_ESC) && |
6022 | ((n == CCTL) || | ||
6023 | (((quotes & EXP_FULL) || syntax != BASESYNTAX) && | ||
6024 | n == CBACK))) | ||
6026 | USTPUTC(CTLESC, q); | 6025 | USTPUTC(CTLESC, q); |
6027 | } | 6026 | } else if (!(quotes & QUOTES_KEEPNUL)) |
6027 | continue; | ||
6028 | USTPUTC(c, q); | 6028 | USTPUTC(c, q); |
6029 | } | 6029 | } while (--len); |
6030 | 6030 | ||
6031 | expdest = q; | 6031 | expdest = q; |
6032 | } | 6032 | } |
6033 | 6033 | ||
6034 | static void | 6034 | static size_t |
6035 | strtodest(const char *p, int syntax, int quotes) | 6035 | strtodest(const char *p, int syntax, int quotes) |
6036 | { | 6036 | { |
6037 | memtodest(p, strlen(p), syntax, quotes); | 6037 | size_t len = strlen(p); |
6038 | memtodest(p, len, syntax, quotes); | ||
6039 | return len; | ||
6038 | } | 6040 | } |
6039 | 6041 | ||
6040 | /* | 6042 | /* |
@@ -6107,7 +6109,7 @@ exptilde(char *startp, char *p, int flags) | |||
6107 | char *name; | 6109 | char *name; |
6108 | struct passwd *pw; | 6110 | struct passwd *pw; |
6109 | const char *home; | 6111 | const char *home; |
6110 | int quotes = flags & (EXP_FULL | EXP_CASE | EXP_REDIR); | 6112 | int quotes = flags & QUOTES_ESC; |
6111 | 6113 | ||
6112 | name = p + 1; | 6114 | name = p + 1; |
6113 | 6115 | ||
@@ -6223,7 +6225,7 @@ evalbackcmd(union node *n, struct backcmd *result) | |||
6223 | * Expand stuff in backwards quotes. | 6225 | * Expand stuff in backwards quotes. |
6224 | */ | 6226 | */ |
6225 | static void | 6227 | static void |
6226 | expbackq(union node *cmd, int quoted, int quotes) | 6228 | expbackq(union node *cmd, int flag) |
6227 | { | 6229 | { |
6228 | struct backcmd in; | 6230 | struct backcmd in; |
6229 | int i; | 6231 | int i; |
@@ -6231,7 +6233,7 @@ expbackq(union node *cmd, int quoted, int quotes) | |||
6231 | char *p; | 6233 | char *p; |
6232 | char *dest; | 6234 | char *dest; |
6233 | int startloc; | 6235 | int startloc; |
6234 | int syntax = quoted ? DQSYNTAX : BASESYNTAX; | 6236 | int syntax = flag & EXP_QUOTED ? DQSYNTAX : BASESYNTAX; |
6235 | struct stackmark smark; | 6237 | struct stackmark smark; |
6236 | 6238 | ||
6237 | INT_OFF; | 6239 | INT_OFF; |
@@ -6247,11 +6249,11 @@ expbackq(union node *cmd, int quoted, int quotes) | |||
6247 | if (i == 0) | 6249 | if (i == 0) |
6248 | goto read; | 6250 | goto read; |
6249 | for (;;) { | 6251 | for (;;) { |
6250 | memtodest(p, i, syntax, quotes); | 6252 | memtodest(p, i, syntax, flag & QUOTES_ESC); |
6251 | read: | 6253 | read: |
6252 | if (in.fd < 0) | 6254 | if (in.fd < 0) |
6253 | break; | 6255 | break; |
6254 | i = nonblock_immune_read(in.fd, buf, sizeof(buf), /*loop_on_EINTR:*/ 1); | 6256 | i = nonblock_immune_read(in.fd, buf, sizeof(buf)); |
6255 | TRACE(("expbackq: read returns %d\n", i)); | 6257 | TRACE(("expbackq: read returns %d\n", i)); |
6256 | if (i <= 0) | 6258 | if (i <= 0) |
6257 | break; | 6259 | break; |
@@ -6272,7 +6274,7 @@ expbackq(union node *cmd, int quoted, int quotes) | |||
6272 | STUNPUTC(dest); | 6274 | STUNPUTC(dest); |
6273 | expdest = dest; | 6275 | expdest = dest; |
6274 | 6276 | ||
6275 | if (quoted == 0) | 6277 | if (!(flag & EXP_QUOTED)) |
6276 | recordregion(startloc, dest - (char *)stackblock(), 0); | 6278 | recordregion(startloc, dest - (char *)stackblock(), 0); |
6277 | TRACE(("evalbackq: size:%d:'%.*s'\n", | 6279 | TRACE(("evalbackq: size:%d:'%.*s'\n", |
6278 | (int)((dest - (char *)stackblock()) - startloc), | 6280 | (int)((dest - (char *)stackblock()) - startloc), |
@@ -6286,11 +6288,10 @@ expbackq(union node *cmd, int quoted, int quotes) | |||
6286 | * evaluate, place result in (backed up) result, adjust string position. | 6288 | * evaluate, place result in (backed up) result, adjust string position. |
6287 | */ | 6289 | */ |
6288 | static void | 6290 | static void |
6289 | expari(int quotes) | 6291 | expari(int flag) |
6290 | { | 6292 | { |
6291 | char *p, *start; | 6293 | char *p, *start; |
6292 | int begoff; | 6294 | int begoff; |
6293 | int flag; | ||
6294 | int len; | 6295 | int len; |
6295 | 6296 | ||
6296 | /* ifsfree(); */ | 6297 | /* ifsfree(); */ |
@@ -6328,16 +6329,14 @@ expari(int quotes) | |||
6328 | 6329 | ||
6329 | removerecordregions(begoff); | 6330 | removerecordregions(begoff); |
6330 | 6331 | ||
6331 | flag = p[1]; | ||
6332 | |||
6333 | expdest = p; | 6332 | expdest = p; |
6334 | 6333 | ||
6335 | if (quotes) | 6334 | if (flag & QUOTES_ESC) |
6336 | rmescapes(p + 2, 0); | 6335 | rmescapes(p + 1, 0); |
6337 | 6336 | ||
6338 | len = cvtnum(ash_arith(p + 2)); | 6337 | len = cvtnum(ash_arith(p + 1)); |
6339 | 6338 | ||
6340 | if (flag != '"') | 6339 | if (!(flag & EXP_QUOTED)) |
6341 | recordregion(begoff, begoff + len, 0); | 6340 | recordregion(begoff, begoff + len, 0); |
6342 | } | 6341 | } |
6343 | #endif | 6342 | #endif |
@@ -6365,15 +6364,13 @@ argstr(char *p, int flags, struct strlist *var_str_list) | |||
6365 | CTLESC, | 6364 | CTLESC, |
6366 | CTLVAR, | 6365 | CTLVAR, |
6367 | CTLBACKQ, | 6366 | CTLBACKQ, |
6368 | CTLBACKQ | CTLQUOTE, | ||
6369 | #if ENABLE_SH_MATH_SUPPORT | 6367 | #if ENABLE_SH_MATH_SUPPORT |
6370 | CTLENDARI, | 6368 | CTLENDARI, |
6371 | #endif | 6369 | #endif |
6372 | '\0' | 6370 | '\0' |
6373 | }; | 6371 | }; |
6374 | const char *reject = spclchars; | 6372 | const char *reject = spclchars; |
6375 | int quotes = flags & (EXP_FULL | EXP_CASE | EXP_REDIR); /* do CTLESC */ | 6373 | int breakall = (flags & (EXP_WORD | EXP_QUOTED)) == EXP_WORD; |
6376 | int breakall = flags & EXP_WORD; | ||
6377 | int inquotes; | 6374 | int inquotes; |
6378 | size_t length; | 6375 | size_t length; |
6379 | int startloc; | 6376 | int startloc; |
@@ -6391,8 +6388,6 @@ argstr(char *p, int flags, struct strlist *var_str_list) | |||
6391 | flags &= ~EXP_TILDE; | 6388 | flags &= ~EXP_TILDE; |
6392 | tilde: | 6389 | tilde: |
6393 | q = p; | 6390 | q = p; |
6394 | if ((unsigned char)*q == CTLESC && (flags & EXP_QWORD)) | ||
6395 | q++; | ||
6396 | if (*q == '~') | 6391 | if (*q == '~') |
6397 | p = exptilde(p, q, flags); | 6392 | p = exptilde(p, q, flags); |
6398 | } | 6393 | } |
@@ -6449,19 +6444,14 @@ argstr(char *p, int flags, struct strlist *var_str_list) | |||
6449 | case CTLENDVAR: /* ??? */ | 6444 | case CTLENDVAR: /* ??? */ |
6450 | goto breakloop; | 6445 | goto breakloop; |
6451 | case CTLQUOTEMARK: | 6446 | case CTLQUOTEMARK: |
6447 | inquotes ^= EXP_QUOTED; | ||
6452 | /* "$@" syntax adherence hack */ | 6448 | /* "$@" syntax adherence hack */ |
6453 | if (!inquotes | 6449 | if (inquotes && !memcmp(p, dolatstr + 1, DOLATSTRLEN - 1)) { |
6454 | && memcmp(p, dolatstr, 4) == 0 | 6450 | p = evalvar(p + 1, flags | inquotes, /* var_str_list: */ NULL) + 1; |
6455 | && ( p[4] == (char)CTLQUOTEMARK | ||
6456 | || (p[4] == (char)CTLENDVAR && p[5] == (char)CTLQUOTEMARK) | ||
6457 | ) | ||
6458 | ) { | ||
6459 | p = evalvar(p + 1, flags, /* var_str_list: */ NULL) + 1; | ||
6460 | goto start; | 6451 | goto start; |
6461 | } | 6452 | } |
6462 | inquotes = !inquotes; | ||
6463 | addquote: | 6453 | addquote: |
6464 | if (quotes) { | 6454 | if (flags & QUOTES_ESC) { |
6465 | p--; | 6455 | p--; |
6466 | length++; | 6456 | length++; |
6467 | startloc++; | 6457 | startloc++; |
@@ -6470,22 +6460,30 @@ argstr(char *p, int flags, struct strlist *var_str_list) | |||
6470 | case CTLESC: | 6460 | case CTLESC: |
6471 | startloc++; | 6461 | startloc++; |
6472 | length++; | 6462 | length++; |
6463 | |||
6464 | /* | ||
6465 | * Quoted parameter expansion pattern: remove quote | ||
6466 | * unless inside inner quotes or we have a literal | ||
6467 | * backslash. | ||
6468 | */ | ||
6469 | if (((flags | inquotes) & (EXP_QPAT | EXP_QUOTED)) == | ||
6470 | EXP_QPAT && *p != '\\') | ||
6471 | break; | ||
6472 | |||
6473 | goto addquote; | 6473 | goto addquote; |
6474 | case CTLVAR: | 6474 | case CTLVAR: |
6475 | TRACE(("argstr: evalvar('%s')\n", p)); | 6475 | TRACE(("argstr: evalvar('%s')\n", p)); |
6476 | p = evalvar(p, flags, var_str_list); | 6476 | p = evalvar(p, flags | inquotes, var_str_list); |
6477 | TRACE(("argstr: evalvar:'%s'\n", (char *)stackblock())); | 6477 | TRACE(("argstr: evalvar:'%s'\n", (char *)stackblock())); |
6478 | goto start; | 6478 | goto start; |
6479 | case CTLBACKQ: | 6479 | case CTLBACKQ: |
6480 | c = '\0'; | 6480 | expbackq(argbackq->n, flags | inquotes); |
6481 | case CTLBACKQ|CTLQUOTE: | ||
6482 | expbackq(argbackq->n, c, quotes); | ||
6483 | argbackq = argbackq->next; | 6481 | argbackq = argbackq->next; |
6484 | goto start; | 6482 | goto start; |
6485 | #if ENABLE_SH_MATH_SUPPORT | 6483 | #if ENABLE_SH_MATH_SUPPORT |
6486 | case CTLENDARI: | 6484 | case CTLENDARI: |
6487 | p--; | 6485 | p--; |
6488 | expari(quotes); | 6486 | expari(flags | inquotes); |
6489 | goto start; | 6487 | goto start; |
6490 | #endif | 6488 | #endif |
6491 | } | 6489 | } |
@@ -6615,60 +6613,17 @@ varunset(const char *end, const char *var, const char *umsg, int varflags) | |||
6615 | ash_msg_and_raise_error("%.*s: %s%s", (int)(end - var - 1), var, msg, tail); | 6613 | ash_msg_and_raise_error("%.*s: %s%s", (int)(end - var - 1), var, msg, tail); |
6616 | } | 6614 | } |
6617 | 6615 | ||
6618 | #if ENABLE_ASH_BASH_COMPAT | ||
6619 | static char * | ||
6620 | parse_sub_pattern(char *arg, int varflags) | ||
6621 | { | ||
6622 | char *idx, *repl = NULL; | ||
6623 | unsigned char c; | ||
6624 | |||
6625 | //char *org_arg = arg; | ||
6626 | //bb_error_msg("arg:'%s' varflags:%x", arg, varflags); | ||
6627 | idx = arg; | ||
6628 | while (1) { | ||
6629 | c = *arg; | ||
6630 | if (!c) | ||
6631 | break; | ||
6632 | if (c == '/') { | ||
6633 | /* Only the first '/' seen is our separator */ | ||
6634 | if (!repl) { | ||
6635 | repl = idx + 1; | ||
6636 | c = '\0'; | ||
6637 | } | ||
6638 | } | ||
6639 | *idx++ = c; | ||
6640 | arg++; | ||
6641 | /* | ||
6642 | * Example: v='ab\c'; echo ${v/\\b/_\\_\z_} | ||
6643 | * The result is a_\_z_c (not a\_\_z_c)! | ||
6644 | * | ||
6645 | * Enable debug prints in this function and you'll see: | ||
6646 | * ash: arg:'\\b/_\\_z_' varflags:d | ||
6647 | * ash: pattern:'\\b' repl:'_\_z_' | ||
6648 | * That is, \\b is interpreted as \\b, but \\_ as \_! | ||
6649 | * IOW: search pattern and replace string treat backslashes | ||
6650 | * differently! That is the reason why we check repl below: | ||
6651 | */ | ||
6652 | if (c == '\\' && *arg == '\\' && repl && !(varflags & VSQUOTE)) | ||
6653 | arg++; /* skip both '\', not just first one */ | ||
6654 | } | ||
6655 | *idx = c; /* NUL */ | ||
6656 | //bb_error_msg("pattern:'%s' repl:'%s'", org_arg, repl); | ||
6657 | |||
6658 | return repl; | ||
6659 | } | ||
6660 | #endif /* ENABLE_ASH_BASH_COMPAT */ | ||
6661 | |||
6662 | static const char * | 6616 | static const char * |
6663 | subevalvar(char *p, char *varname, int strloc, int subtype, | 6617 | subevalvar(char *p, char *varname, int strloc, int subtype, |
6664 | int startloc, int varflags, int quotes, struct strlist *var_str_list) | 6618 | int startloc, int varflags, int flag, struct strlist *var_str_list) |
6665 | { | 6619 | { |
6666 | struct nodelist *saveargbackq = argbackq; | 6620 | struct nodelist *saveargbackq = argbackq; |
6621 | int quotes = flag & QUOTES_ESC; | ||
6667 | char *startp; | 6622 | char *startp; |
6668 | char *loc; | 6623 | char *loc; |
6669 | char *rmesc, *rmescend; | 6624 | char *rmesc, *rmescend; |
6670 | char *str; | 6625 | char *str; |
6671 | IF_ASH_BASH_COMPAT(const char *repl = NULL;) | 6626 | IF_ASH_BASH_COMPAT(char *repl = NULL;) |
6672 | IF_ASH_BASH_COMPAT(int pos, len, orig_len;) | 6627 | IF_ASH_BASH_COMPAT(int pos, len, orig_len;) |
6673 | int saveherefd = herefd; | 6628 | int saveherefd = herefd; |
6674 | int amount, resetloc; | 6629 | int amount, resetloc; |
@@ -6680,7 +6635,8 @@ subevalvar(char *p, char *varname, int strloc, int subtype, | |||
6680 | // p, varname, strloc, subtype, startloc, varflags, quotes); | 6635 | // p, varname, strloc, subtype, startloc, varflags, quotes); |
6681 | 6636 | ||
6682 | herefd = -1; | 6637 | herefd = -1; |
6683 | argstr(p, (subtype != VSASSIGN && subtype != VSQUESTION) ? EXP_CASE : 0, | 6638 | argstr(p, EXP_TILDE | (subtype != VSASSIGN && subtype != VSQUESTION ? |
6639 | (flag & (EXP_QUOTED | EXP_QPAT) ? EXP_QPAT : EXP_CASE) : 0), | ||
6684 | var_str_list); | 6640 | var_str_list); |
6685 | STPUTC('\0', expdest); | 6641 | STPUTC('\0', expdest); |
6686 | herefd = saveherefd; | 6642 | herefd = saveherefd; |
@@ -6689,7 +6645,7 @@ subevalvar(char *p, char *varname, int strloc, int subtype, | |||
6689 | 6645 | ||
6690 | switch (subtype) { | 6646 | switch (subtype) { |
6691 | case VSASSIGN: | 6647 | case VSASSIGN: |
6692 | setvar2(varname, startp); | 6648 | setvar0(varname, startp); |
6693 | amount = startp - expdest; | 6649 | amount = startp - expdest; |
6694 | STADJUST(amount, expdest); | 6650 | STADJUST(amount, expdest); |
6695 | return startp; | 6651 | return startp; |
@@ -6792,7 +6748,17 @@ subevalvar(char *p, char *varname, int strloc, int subtype, | |||
6792 | } | 6748 | } |
6793 | rmescend--; | 6749 | rmescend--; |
6794 | str = (char *)stackblock() + strloc; | 6750 | str = (char *)stackblock() + strloc; |
6795 | preglob(str, varflags & VSQUOTE, 0); | 6751 | /* |
6752 | * Example: v='a\bc'; echo ${v/\\b/_\\_\z_} | ||
6753 | * The result is a_\_z_c (not a\_\_z_c)! | ||
6754 | * | ||
6755 | * The search pattern and replace string treat backslashes differently! | ||
6756 | * RMESCAPE_SLASH causes preglob to work differently on the pattern | ||
6757 | * and string. It's only used on the first call. | ||
6758 | */ | ||
6759 | preglob(str, IF_ASH_BASH_COMPAT( | ||
6760 | (subtype == VSREPLACE || subtype == VSREPLACEALL) && !repl ? | ||
6761 | RMESCAPE_SLASH :) 0); | ||
6796 | 6762 | ||
6797 | #if ENABLE_ASH_BASH_COMPAT | 6763 | #if ENABLE_ASH_BASH_COMPAT |
6798 | workloc = expdest - (char *)stackblock(); | 6764 | workloc = expdest - (char *)stackblock(); |
@@ -6800,11 +6766,12 @@ subevalvar(char *p, char *varname, int strloc, int subtype, | |||
6800 | char *idx, *end; | 6766 | char *idx, *end; |
6801 | 6767 | ||
6802 | if (!repl) { | 6768 | if (!repl) { |
6803 | repl = parse_sub_pattern(str, varflags); | 6769 | if ((repl=strchr(str, CTLESC))) |
6804 | //bb_error_msg("repl:'%s'", repl); | 6770 | *repl++ = '\0'; |
6805 | if (!repl) | 6771 | else |
6806 | repl = nullstr; | 6772 | repl = nullstr; |
6807 | } | 6773 | } |
6774 | //bb_error_msg("str:'%s' repl:'%s'", str, repl); | ||
6808 | 6775 | ||
6809 | /* If there's no pattern to match, return the expansion unmolested */ | 6776 | /* If there's no pattern to match, return the expansion unmolested */ |
6810 | if (str[0] == '\0') | 6777 | if (str[0] == '\0') |
@@ -6937,13 +6904,16 @@ varvalue(char *name, int varflags, int flags, struct strlist *var_str_list) | |||
6937 | const char *p; | 6904 | const char *p; |
6938 | int num; | 6905 | int num; |
6939 | int i; | 6906 | int i; |
6940 | int sepq = 0; | ||
6941 | ssize_t len = 0; | 6907 | ssize_t len = 0; |
6908 | int sep; | ||
6909 | int quoted = flags & EXP_QUOTED; | ||
6942 | int subtype = varflags & VSTYPE; | 6910 | int subtype = varflags & VSTYPE; |
6943 | int quotes = flags & (EXP_FULL | EXP_CASE | EXP_REDIR); | 6911 | int discard = subtype == VSPLUS || subtype == VSLENGTH; |
6944 | int quoted = varflags & VSQUOTE; | 6912 | int quotes = (discard ? 0 : (flags & QUOTES_ESC)) | QUOTES_KEEPNUL; |
6945 | int syntax = quoted ? DQSYNTAX : BASESYNTAX; | 6913 | int syntax = quoted ? DQSYNTAX : BASESYNTAX; |
6946 | 6914 | ||
6915 | sep = quoted ? ((flags & EXP_FULL) << CHAR_BIT) : 0; | ||
6916 | |||
6947 | switch (*name) { | 6917 | switch (*name) { |
6948 | case '$': | 6918 | case '$': |
6949 | num = rootpid; | 6919 | num = rootpid; |
@@ -6978,7 +6948,7 @@ varvalue(char *name, int varflags, int flags, struct strlist *var_str_list) | |||
6978 | break; | 6948 | break; |
6979 | case '@': { | 6949 | case '@': { |
6980 | char **ap; | 6950 | char **ap; |
6981 | int sep; | 6951 | char sepc; |
6982 | 6952 | ||
6983 | if (quoted && (flags & EXP_FULL)) { | 6953 | if (quoted && (flags & EXP_FULL)) { |
6984 | /* note: this is not meant as PEOF value */ | 6954 | /* note: this is not meant as PEOF value */ |
@@ -6988,39 +6958,20 @@ varvalue(char *name, int varflags, int flags, struct strlist *var_str_list) | |||
6988 | /* fall through */ | 6958 | /* fall through */ |
6989 | case '*': | 6959 | case '*': |
6990 | sep = ifsset() ? (unsigned char)(ifsval()[0]) : ' '; | 6960 | sep = ifsset() ? (unsigned char)(ifsval()[0]) : ' '; |
6991 | i = SIT(sep, syntax); | ||
6992 | if (quotes && (i == CCTL || i == CBACK)) | ||
6993 | sepq = 1; | ||
6994 | param: | 6961 | param: |
6995 | ap = shellparam.p; | 6962 | ap = shellparam.p; |
6963 | sepc = sep; | ||
6996 | if (!ap) | 6964 | if (!ap) |
6997 | return -1; | 6965 | return -1; |
6998 | while ((p = *ap++) != NULL) { | 6966 | while ((p = *ap++) != NULL) { |
6999 | size_t partlen; | 6967 | len += strtodest(p, syntax, quotes); |
7000 | |||
7001 | partlen = strlen(p); | ||
7002 | len += partlen; | ||
7003 | |||
7004 | if (!(subtype == VSPLUS || subtype == VSLENGTH)) | ||
7005 | memtodest(p, partlen, syntax, quotes); | ||
7006 | 6968 | ||
7007 | if (*ap && sep) { | 6969 | if (*ap && sep) { |
7008 | char *q; | ||
7009 | |||
7010 | len++; | 6970 | len++; |
7011 | if (subtype == VSPLUS || subtype == VSLENGTH) { | 6971 | memtodest(&sepc, 1, syntax, quotes); |
7012 | continue; | ||
7013 | } | ||
7014 | q = expdest; | ||
7015 | if (sepq) | ||
7016 | STPUTC(CTLESC, q); | ||
7017 | /* note: may put NUL despite sep != 0 | ||
7018 | * (see sep = 1 << CHAR_BIT above) */ | ||
7019 | STPUTC(sep, q); | ||
7020 | expdest = q; | ||
7021 | } | 6972 | } |
7022 | } | 6973 | } |
7023 | return len; | 6974 | break; |
7024 | } /* case '@' and '*' */ | 6975 | } /* case '@' and '*' */ |
7025 | case '0': | 6976 | case '0': |
7026 | case '1': | 6977 | case '1': |
@@ -7069,9 +7020,7 @@ varvalue(char *name, int varflags, int flags, struct strlist *var_str_list) | |||
7069 | if (!p) | 7020 | if (!p) |
7070 | return -1; | 7021 | return -1; |
7071 | 7022 | ||
7072 | len = strlen(p); | 7023 | len = strtodest(p, syntax, quotes); |
7073 | if (!(subtype == VSPLUS || subtype == VSLENGTH)) | ||
7074 | memtodest(p, len, syntax, quotes); | ||
7075 | #if ENABLE_UNICODE_SUPPORT | 7024 | #if ENABLE_UNICODE_SUPPORT |
7076 | if (subtype == VSLENGTH && len > 0) { | 7025 | if (subtype == VSLENGTH && len > 0) { |
7077 | reinit_unicode_for_ash(); | 7026 | reinit_unicode_for_ash(); |
@@ -7080,10 +7029,10 @@ varvalue(char *name, int varflags, int flags, struct strlist *var_str_list) | |||
7080 | } | 7029 | } |
7081 | } | 7030 | } |
7082 | #endif | 7031 | #endif |
7083 | return len; | 7032 | break; |
7084 | } | 7033 | } |
7085 | 7034 | ||
7086 | if (subtype == VSPLUS || subtype == VSLENGTH) | 7035 | if (discard) |
7087 | STADJUST(-len, expdest); | 7036 | STADJUST(-len, expdest); |
7088 | return len; | 7037 | return len; |
7089 | } | 7038 | } |
@@ -7097,7 +7046,7 @@ evalvar(char *p, int flags, struct strlist *var_str_list) | |||
7097 | { | 7046 | { |
7098 | char varflags; | 7047 | char varflags; |
7099 | char subtype; | 7048 | char subtype; |
7100 | char quoted; | 7049 | int quoted; |
7101 | char easy; | 7050 | char easy; |
7102 | char *var; | 7051 | char *var; |
7103 | int patloc; | 7052 | int patloc; |
@@ -7106,7 +7055,7 @@ evalvar(char *p, int flags, struct strlist *var_str_list) | |||
7106 | 7055 | ||
7107 | varflags = (unsigned char) *p++; | 7056 | varflags = (unsigned char) *p++; |
7108 | subtype = varflags & VSTYPE; | 7057 | subtype = varflags & VSTYPE; |
7109 | quoted = varflags & VSQUOTE; | 7058 | quoted = flags & EXP_QUOTED; |
7110 | var = p; | 7059 | var = p; |
7111 | easy = (!quoted || (*var == '@' && shellparam.nparam)); | 7060 | easy = (!quoted || (*var == '@' && shellparam.nparam)); |
7112 | startloc = expdest - (char *)stackblock(); | 7061 | startloc = expdest - (char *)stackblock(); |
@@ -7127,7 +7076,7 @@ evalvar(char *p, int flags, struct strlist *var_str_list) | |||
7127 | if (varlen < 0) { | 7076 | if (varlen < 0) { |
7128 | argstr( | 7077 | argstr( |
7129 | p, | 7078 | p, |
7130 | flags | (quoted ? EXP_TILDE|EXP_QWORD : EXP_TILDE|EXP_WORD), | 7079 | flags | EXP_TILDE | EXP_WORD, |
7131 | var_str_list | 7080 | var_str_list |
7132 | ); | 7081 | ); |
7133 | goto end; | 7082 | goto end; |
@@ -7141,7 +7090,7 @@ evalvar(char *p, int flags, struct strlist *var_str_list) | |||
7141 | if (varlen < 0) { | 7090 | if (varlen < 0) { |
7142 | if (subevalvar(p, var, /* strloc: */ 0, | 7091 | if (subevalvar(p, var, /* strloc: */ 0, |
7143 | subtype, startloc, varflags, | 7092 | subtype, startloc, varflags, |
7144 | /* quotes: */ 0, | 7093 | /* quotes: */ flags & ~QUOTES_ESC, |
7145 | var_str_list) | 7094 | var_str_list) |
7146 | ) { | 7095 | ) { |
7147 | varflags &= ~VSNUL; | 7096 | varflags &= ~VSNUL; |
@@ -7198,10 +7147,7 @@ evalvar(char *p, int flags, struct strlist *var_str_list) | |||
7198 | STPUTC('\0', expdest); | 7147 | STPUTC('\0', expdest); |
7199 | patloc = expdest - (char *)stackblock(); | 7148 | patloc = expdest - (char *)stackblock(); |
7200 | if (NULL == subevalvar(p, /* varname: */ NULL, patloc, subtype, | 7149 | if (NULL == subevalvar(p, /* varname: */ NULL, patloc, subtype, |
7201 | startloc, varflags, | 7150 | startloc, varflags, flags, var_str_list)) { |
7202 | /* quotes: */ flags & (EXP_FULL | EXP_CASE | EXP_REDIR), | ||
7203 | var_str_list) | ||
7204 | ) { | ||
7205 | int amount = expdest - ( | 7151 | int amount = expdest - ( |
7206 | (char *)stackblock() + patloc - 1 | 7152 | (char *)stackblock() + patloc - 1 |
7207 | ); | 7153 | ); |
@@ -7220,7 +7166,7 @@ evalvar(char *p, int flags, struct strlist *var_str_list) | |||
7220 | unsigned char c = *p++; | 7166 | unsigned char c = *p++; |
7221 | if (c == CTLESC) | 7167 | if (c == CTLESC) |
7222 | p++; | 7168 | p++; |
7223 | else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) { | 7169 | else if (c == CTLBACKQ) { |
7224 | if (varlen >= 0) | 7170 | if (varlen >= 0) |
7225 | argbackq = argbackq->next; | 7171 | argbackq = argbackq->next; |
7226 | } else if (c == CTLVAR) { | 7172 | } else if (c == CTLVAR) { |
@@ -7556,7 +7502,7 @@ expandmeta(struct strlist *str /*, int flag*/) | |||
7556 | savelastp = exparg.lastp; | 7502 | savelastp = exparg.lastp; |
7557 | 7503 | ||
7558 | INT_OFF; | 7504 | INT_OFF; |
7559 | p = preglob(str->text, 0, RMESCAPE_ALLOC | RMESCAPE_HEAP); | 7505 | p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP); |
7560 | { | 7506 | { |
7561 | int i = strlen(str->text); | 7507 | int i = strlen(str->text); |
7562 | expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */ | 7508 | expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */ |
@@ -7646,7 +7592,7 @@ static void | |||
7646 | expandhere(union node *arg, int fd) | 7592 | expandhere(union node *arg, int fd) |
7647 | { | 7593 | { |
7648 | herefd = fd; | 7594 | herefd = fd; |
7649 | expandarg(arg, (struct arglist *)NULL, 0); | 7595 | expandarg(arg, (struct arglist *)NULL, EXP_QUOTED); |
7650 | full_write(fd, stackblock(), expdest - (char *)stackblock()); | 7596 | full_write(fd, stackblock(), expdest - (char *)stackblock()); |
7651 | } | 7597 | } |
7652 | 7598 | ||
@@ -7656,7 +7602,7 @@ expandhere(union node *arg, int fd) | |||
7656 | static int | 7602 | static int |
7657 | patmatch(char *pattern, const char *string) | 7603 | patmatch(char *pattern, const char *string) |
7658 | { | 7604 | { |
7659 | return pmatch(preglob(pattern, 0, 0), string); | 7605 | return pmatch(preglob(pattern, 0), string); |
7660 | } | 7606 | } |
7661 | 7607 | ||
7662 | /* | 7608 | /* |
@@ -8956,7 +8902,7 @@ evalfor(union node *n, int flags) | |||
8956 | arglist.list = NULL; | 8902 | arglist.list = NULL; |
8957 | arglist.lastp = &arglist.list; | 8903 | arglist.lastp = &arglist.list; |
8958 | for (argp = n->nfor.args; argp; argp = argp->narg.next) { | 8904 | for (argp = n->nfor.args; argp; argp = argp->narg.next) { |
8959 | expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD); | 8905 | expandarg(argp, &arglist, EXP_FULL | EXP_TILDE); |
8960 | /* XXX */ | 8906 | /* XXX */ |
8961 | if (evalskip) | 8907 | if (evalskip) |
8962 | goto out; | 8908 | goto out; |
@@ -8967,7 +8913,7 @@ evalfor(union node *n, int flags) | |||
8967 | loopnest++; | 8913 | loopnest++; |
8968 | flags &= EV_TESTED; | 8914 | flags &= EV_TESTED; |
8969 | for (sp = arglist.list; sp; sp = sp->next) { | 8915 | for (sp = arglist.list; sp; sp = sp->next) { |
8970 | setvar2(n->nfor.var, sp->text); | 8916 | setvar0(n->nfor.var, sp->text); |
8971 | evaltree(n->nfor.body, flags); | 8917 | evaltree(n->nfor.body, flags); |
8972 | if (evalskip) { | 8918 | if (evalskip) { |
8973 | if (evalskip == SKIPCONT && --skipcount <= 0) { | 8919 | if (evalskip == SKIPCONT && --skipcount <= 0) { |
@@ -9362,7 +9308,8 @@ parse_command_args(char **argv, const char **path) | |||
9362 | * Make a variable a local variable. When a variable is made local, it's | 9308 | * Make a variable a local variable. When a variable is made local, it's |
9363 | * value and flags are saved in a localvar structure. The saved values | 9309 | * value and flags are saved in a localvar structure. The saved values |
9364 | * will be restored when the shell function returns. We handle the name | 9310 | * will be restored when the shell function returns. We handle the name |
9365 | * "-" as a special case. | 9311 | * "-" as a special case: it makes changes to "set +-options" local |
9312 | * (options will be restored on return from the function). | ||
9366 | */ | 9313 | */ |
9367 | static void | 9314 | static void |
9368 | mklocal(char *name) | 9315 | mklocal(char *name) |
@@ -9370,21 +9317,37 @@ mklocal(char *name) | |||
9370 | struct localvar *lvp; | 9317 | struct localvar *lvp; |
9371 | struct var **vpp; | 9318 | struct var **vpp; |
9372 | struct var *vp; | 9319 | struct var *vp; |
9320 | char *eq = strchr(name, '='); | ||
9373 | 9321 | ||
9374 | INT_OFF; | 9322 | INT_OFF; |
9375 | lvp = ckzalloc(sizeof(struct localvar)); | 9323 | /* Cater for duplicate "local". Examples: |
9324 | * x=0; f() { local x=1; echo $x; local x; echo $x; }; f; echo $x | ||
9325 | * x=0; f() { local x=1; echo $x; local x=2; echo $x; }; f; echo $x | ||
9326 | */ | ||
9327 | lvp = localvars; | ||
9328 | while (lvp) { | ||
9329 | if (lvp->vp && varcmp(lvp->vp->var_text, name) == 0) { | ||
9330 | if (eq) | ||
9331 | setvareq(name, 0); | ||
9332 | /* else: | ||
9333 | * it's a duplicate "local VAR" declaration, do nothing | ||
9334 | */ | ||
9335 | return; | ||
9336 | } | ||
9337 | lvp = lvp->next; | ||
9338 | } | ||
9339 | |||
9340 | lvp = ckzalloc(sizeof(*lvp)); | ||
9376 | if (LONE_DASH(name)) { | 9341 | if (LONE_DASH(name)) { |
9377 | char *p; | 9342 | char *p; |
9378 | p = ckmalloc(sizeof(optlist)); | 9343 | p = ckmalloc(sizeof(optlist)); |
9379 | lvp->text = memcpy(p, optlist, sizeof(optlist)); | 9344 | lvp->text = memcpy(p, optlist, sizeof(optlist)); |
9380 | vp = NULL; | 9345 | vp = NULL; |
9381 | } else { | 9346 | } else { |
9382 | char *eq; | ||
9383 | |||
9384 | vpp = hashvar(name); | 9347 | vpp = hashvar(name); |
9385 | vp = *findvar(vpp, name); | 9348 | vp = *findvar(vpp, name); |
9386 | eq = strchr(name, '='); | ||
9387 | if (vp == NULL) { | 9349 | if (vp == NULL) { |
9350 | /* variable did not exist yet */ | ||
9388 | if (eq) | 9351 | if (eq) |
9389 | setvareq(name, VSTRFIXED); | 9352 | setvareq(name, VSTRFIXED); |
9390 | else | 9353 | else |
@@ -9394,12 +9357,15 @@ mklocal(char *name) | |||
9394 | } else { | 9357 | } else { |
9395 | lvp->text = vp->var_text; | 9358 | lvp->text = vp->var_text; |
9396 | lvp->flags = vp->flags; | 9359 | lvp->flags = vp->flags; |
9360 | /* make sure neither "struct var" nor string gets freed | ||
9361 | * during (un)setting: | ||
9362 | */ | ||
9397 | vp->flags |= VSTRFIXED|VTEXTFIXED; | 9363 | vp->flags |= VSTRFIXED|VTEXTFIXED; |
9398 | if (eq) | 9364 | if (eq) |
9399 | setvareq(name, 0); | 9365 | setvareq(name, 0); |
9400 | else | 9366 | else |
9401 | /* "local VAR" unsets VAR: */ | 9367 | /* "local VAR" unsets VAR: */ |
9402 | setvar(name, NULL, 0); | 9368 | setvar0(name, NULL); |
9403 | } | 9369 | } |
9404 | } | 9370 | } |
9405 | lvp->vp = vp; | 9371 | lvp->vp = vp; |
@@ -9914,7 +9880,7 @@ evalcommand(union node *cmd, int flags) | |||
9914 | * '_' in 'vi' command mode during line editing... | 9880 | * '_' in 'vi' command mode during line editing... |
9915 | * However I implemented that within libedit itself. | 9881 | * However I implemented that within libedit itself. |
9916 | */ | 9882 | */ |
9917 | setvar2("_", lastarg); | 9883 | setvar0("_", lastarg); |
9918 | } | 9884 | } |
9919 | popstackmark(&smark); | 9885 | popstackmark(&smark); |
9920 | } | 9886 | } |
@@ -10100,7 +10066,7 @@ preadfd(void) | |||
10100 | #if ENABLE_FEATURE_EDITING | 10066 | #if ENABLE_FEATURE_EDITING |
10101 | retry: | 10067 | retry: |
10102 | if (!iflag || g_parsefile->pf_fd != STDIN_FILENO) | 10068 | if (!iflag || g_parsefile->pf_fd != STDIN_FILENO) |
10103 | nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1, /*loop_on_EINTR:*/ 1); | 10069 | nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1); |
10104 | else { | 10070 | else { |
10105 | int timeout = -1; | 10071 | int timeout = -1; |
10106 | # if ENABLE_ASH_IDLE_TIMEOUT | 10072 | # if ENABLE_ASH_IDLE_TIMEOUT |
@@ -10142,7 +10108,7 @@ preadfd(void) | |||
10142 | } | 10108 | } |
10143 | } | 10109 | } |
10144 | #else | 10110 | #else |
10145 | nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1, /*loop_on_EINTR:*/ 1); | 10111 | nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1); |
10146 | #endif | 10112 | #endif |
10147 | 10113 | ||
10148 | #if 0 /* disabled: nonblock_immune_read() handles this problem */ | 10114 | #if 0 /* disabled: nonblock_immune_read() handles this problem */ |
@@ -11675,11 +11641,9 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs) | |||
11675 | && c != '$' | 11641 | && c != '$' |
11676 | && (c != '"' || eofmark != NULL) | 11642 | && (c != '"' || eofmark != NULL) |
11677 | ) { | 11643 | ) { |
11678 | USTPUTC(CTLESC, out); | ||
11679 | USTPUTC('\\', out); | 11644 | USTPUTC('\\', out); |
11680 | } | 11645 | } |
11681 | if (SIT(c, SQSYNTAX) == CCTL) | 11646 | USTPUTC(CTLESC, out); |
11682 | USTPUTC(CTLESC, out); | ||
11683 | USTPUTC(c, out); | 11647 | USTPUTC(c, out); |
11684 | quotef = 1; | 11648 | quotef = 1; |
11685 | } | 11649 | } |
@@ -11697,9 +11661,7 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs) | |||
11697 | goto quotemark; | 11661 | goto quotemark; |
11698 | case CENDQUOTE: | 11662 | case CENDQUOTE: |
11699 | IF_ASH_BASH_COMPAT(bash_dollar_squote = 0;) | 11663 | IF_ASH_BASH_COMPAT(bash_dollar_squote = 0;) |
11700 | if (eofmark != NULL && arinest == 0 | 11664 | if (eofmark != NULL && varnest == 0) { |
11701 | && varnest == 0 | ||
11702 | ) { | ||
11703 | USTPUTC(c, out); | 11665 | USTPUTC(c, out); |
11704 | } else { | 11666 | } else { |
11705 | if (dqvarnest == 0) { | 11667 | if (dqvarnest == 0) { |
@@ -11733,10 +11695,9 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs) | |||
11733 | parenlevel--; | 11695 | parenlevel--; |
11734 | } else { | 11696 | } else { |
11735 | if (pgetc() == ')') { | 11697 | if (pgetc() == ')') { |
11698 | c = CTLENDARI; | ||
11736 | if (--arinest == 0) { | 11699 | if (--arinest == 0) { |
11737 | syntax = prevsyntax; | 11700 | syntax = prevsyntax; |
11738 | dblquote = (syntax == DQSYNTAX); | ||
11739 | c = CTLENDARI; | ||
11740 | } | 11701 | } |
11741 | } else { | 11702 | } else { |
11742 | /* | 11703 | /* |
@@ -12055,12 +12016,10 @@ parsesub: { | |||
12055 | do_pungetc: | 12016 | do_pungetc: |
12056 | pungetc(); | 12017 | pungetc(); |
12057 | } | 12018 | } |
12058 | if (dblquote || arinest) | ||
12059 | flags |= VSQUOTE; | ||
12060 | ((unsigned char *)stackblock())[typeloc] = subtype | flags; | 12019 | ((unsigned char *)stackblock())[typeloc] = subtype | flags; |
12061 | if (subtype != VSNORMAL) { | 12020 | if (subtype != VSNORMAL) { |
12062 | varnest++; | 12021 | varnest++; |
12063 | if (dblquote || arinest) { | 12022 | if (dblquote) { |
12064 | dqvarnest++; | 12023 | dqvarnest++; |
12065 | } | 12024 | } |
12066 | } | 12025 | } |
@@ -12210,10 +12169,7 @@ parsebackq: { | |||
12210 | } | 12169 | } |
12211 | parsebackquote = savepbq; | 12170 | parsebackquote = savepbq; |
12212 | exception_handler = savehandler; | 12171 | exception_handler = savehandler; |
12213 | if (arinest || dblquote) | 12172 | USTPUTC(CTLBACKQ, out); |
12214 | USTPUTC(CTLBACKQ | CTLQUOTE, out); | ||
12215 | else | ||
12216 | USTPUTC(CTLBACKQ, out); | ||
12217 | if (oldstyle) | 12173 | if (oldstyle) |
12218 | goto parsebackq_oldreturn; | 12174 | goto parsebackq_oldreturn; |
12219 | goto parsebackq_newreturn; | 12175 | goto parsebackq_newreturn; |
@@ -12227,18 +12183,8 @@ parsearith: { | |||
12227 | if (++arinest == 1) { | 12183 | if (++arinest == 1) { |
12228 | prevsyntax = syntax; | 12184 | prevsyntax = syntax; |
12229 | syntax = ARISYNTAX; | 12185 | syntax = ARISYNTAX; |
12230 | USTPUTC(CTLARI, out); | ||
12231 | if (dblquote) | ||
12232 | USTPUTC('"', out); | ||
12233 | else | ||
12234 | USTPUTC(' ', out); | ||
12235 | } else { | ||
12236 | /* | ||
12237 | * we collapse embedded arithmetic expansion to | ||
12238 | * parenthesis, which should be equivalent | ||
12239 | */ | ||
12240 | USTPUTC('(', out); | ||
12241 | } | 12186 | } |
12187 | USTPUTC(CTLARI, out); | ||
12242 | goto parsearith_return; | 12188 | goto parsearith_return; |
12243 | } | 12189 | } |
12244 | #endif | 12190 | #endif |
@@ -12553,7 +12499,7 @@ expandstr(const char *ps) | |||
12553 | n.narg.text = wordtext; | 12499 | n.narg.text = wordtext; |
12554 | n.narg.backquote = backquotelist; | 12500 | n.narg.backquote = backquotelist; |
12555 | 12501 | ||
12556 | expandarg(&n, NULL, 0); | 12502 | expandarg(&n, NULL, EXP_QUOTED); |
12557 | return stackblock(); | 12503 | return stackblock(); |
12558 | } | 12504 | } |
12559 | #endif | 12505 | #endif |
@@ -13348,7 +13294,7 @@ readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
13348 | * to jump out of it. | 13294 | * to jump out of it. |
13349 | */ | 13295 | */ |
13350 | INT_OFF; | 13296 | INT_OFF; |
13351 | r = shell_builtin_read(setvar2, | 13297 | r = shell_builtin_read(setvar0, |
13352 | argptr, | 13298 | argptr, |
13353 | bltinlookup("IFS"), /* can be NULL */ | 13299 | bltinlookup("IFS"), /* can be NULL */ |
13354 | read_flags, | 13300 | read_flags, |
@@ -13560,14 +13506,14 @@ init(void) | |||
13560 | } | 13506 | } |
13561 | } | 13507 | } |
13562 | 13508 | ||
13563 | setvar2("PPID", utoa(getppid())); | 13509 | setvar0("PPID", utoa(getppid())); |
13564 | #if ENABLE_ASH_BASH_COMPAT | 13510 | #if ENABLE_ASH_BASH_COMPAT |
13565 | p = lookupvar("SHLVL"); | 13511 | p = lookupvar("SHLVL"); |
13566 | setvar("SHLVL", utoa((p ? atoi(p) : 0) + 1), VEXPORT); | 13512 | setvar("SHLVL", utoa((p ? atoi(p) : 0) + 1), VEXPORT); |
13567 | if (!lookupvar("HOSTNAME")) { | 13513 | if (!lookupvar("HOSTNAME")) { |
13568 | struct utsname uts; | 13514 | struct utsname uts; |
13569 | uname(&uts); | 13515 | uname(&uts); |
13570 | setvar2("HOSTNAME", uts.nodename); | 13516 | setvar0("HOSTNAME", uts.nodename); |
13571 | } | 13517 | } |
13572 | #endif | 13518 | #endif |
13573 | p = lookupvar("PWD"); | 13519 | p = lookupvar("PWD"); |
@@ -13848,7 +13794,7 @@ int ash_main(int argc UNUSED_PARAM, char **argv) | |||
13848 | hp = lookupvar("HOME"); | 13794 | hp = lookupvar("HOME"); |
13849 | if (hp) { | 13795 | if (hp) { |
13850 | hp = concat_path_file(hp, ".ash_history"); | 13796 | hp = concat_path_file(hp, ".ash_history"); |
13851 | setvar2("HISTFILE", hp); | 13797 | setvar0("HISTFILE", hp); |
13852 | free((char*)hp); | 13798 | free((char*)hp); |
13853 | hp = lookupvar("HISTFILE"); | 13799 | hp = lookupvar("HISTFILE"); |
13854 | } | 13800 | } |
diff --git a/shell/ash_test/ash-heredoc/heredoc1.right b/shell/ash_test/ash-heredoc/heredoc1.right index 895f5ee80..40aa5a5fe 100644 --- a/shell/ash_test/ash-heredoc/heredoc1.right +++ b/shell/ash_test/ash-heredoc/heredoc1.right | |||
@@ -1 +1 @@ | |||
heredoc1.tests: line 3: syntax error: unexpected "then" | ./heredoc1.tests: line 3: syntax error: unexpected "then" | ||
diff --git a/shell/ash_test/ash-vars/var-do-not-collapse-arithmetic-expansion-at-parse-time.right b/shell/ash_test/ash-vars/var-do-not-collapse-arithmetic-expansion-at-parse-time.right new file mode 100644 index 000000000..81a15855c --- /dev/null +++ b/shell/ash_test/ash-vars/var-do-not-collapse-arithmetic-expansion-at-parse-time.right | |||
@@ -0,0 +1,2 @@ | |||
1 | 12 | ||
2 | 9 | ||
diff --git a/shell/ash_test/ash-vars/var-do-not-collapse-arithmetic-expansion-at-parse-time.tests b/shell/ash_test/ash-vars/var-do-not-collapse-arithmetic-expansion-at-parse-time.tests new file mode 100755 index 000000000..e97a08a57 --- /dev/null +++ b/shell/ash_test/ash-vars/var-do-not-collapse-arithmetic-expansion-at-parse-time.tests | |||
@@ -0,0 +1,3 @@ | |||
1 | unset a | ||
2 | echo $((3 + ${a:=$((4 + 5))})) | ||
3 | echo $a | ||
diff --git a/shell/ash_test/ash-vars/var-do-not-expand-tilde-in-parameter-expansion-in-quotes.right b/shell/ash_test/ash-vars/var-do-not-expand-tilde-in-parameter-expansion-in-quotes.right new file mode 100644 index 000000000..4b9b4f038 --- /dev/null +++ b/shell/ash_test/ash-vars/var-do-not-expand-tilde-in-parameter-expansion-in-quotes.right | |||
@@ -0,0 +1 @@ | |||
~root | |||
diff --git a/shell/ash_test/ash-vars/var-do-not-expand-tilde-in-parameter-expansion-in-quotes.tests b/shell/ash_test/ash-vars/var-do-not-expand-tilde-in-parameter-expansion-in-quotes.tests new file mode 100755 index 000000000..d8eb8fc1b --- /dev/null +++ b/shell/ash_test/ash-vars/var-do-not-expand-tilde-in-parameter-expansion-in-quotes.tests | |||
@@ -0,0 +1,2 @@ | |||
1 | unset a | ||
2 | echo "${a:-~root}" | ||
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-expand-tilde-in-parameter-expansion.right b/shell/ash_test/ash-vars/var-expand-tilde-in-parameter-expansion.right new file mode 100644 index 000000000..2357750c5 --- /dev/null +++ b/shell/ash_test/ash-vars/var-expand-tilde-in-parameter-expansion.right | |||
@@ -0,0 +1 @@ | |||
:/root | |||
diff --git a/shell/ash_test/ash-vars/var-expand-tilde-in-parameter-expansion.tests b/shell/ash_test/ash-vars/var-expand-tilde-in-parameter-expansion.tests new file mode 100755 index 000000000..6605315d0 --- /dev/null +++ b/shell/ash_test/ash-vars/var-expand-tilde-in-parameter-expansion.tests | |||
@@ -0,0 +1,2 @@ | |||
1 | a=~root:~root | ||
2 | echo ${a#~root} | ||
diff --git a/shell/ash_test/ash-vars/var-pattern-replacement-in-parameter-expansion-1.right b/shell/ash_test/ash-vars/var-pattern-replacement-in-parameter-expansion-1.right new file mode 100644 index 000000000..2da327222 --- /dev/null +++ b/shell/ash_test/ash-vars/var-pattern-replacement-in-parameter-expansion-1.right | |||
@@ -0,0 +1 @@ | |||
a_\_z_c | |||
diff --git a/shell/ash_test/ash-vars/var-pattern-replacement-in-parameter-expansion-1.tests b/shell/ash_test/ash-vars/var-pattern-replacement-in-parameter-expansion-1.tests new file mode 100755 index 000000000..e4529c631 --- /dev/null +++ b/shell/ash_test/ash-vars/var-pattern-replacement-in-parameter-expansion-1.tests | |||
@@ -0,0 +1,2 @@ | |||
1 | v="a\bc" | ||
2 | echo ${v/\\b/_\\_\z_} | ||
diff --git a/shell/ash_test/ash-vars/var-pattern-replacement-in-parameter-expansion-2.right b/shell/ash_test/ash-vars/var-pattern-replacement-in-parameter-expansion-2.right new file mode 100644 index 000000000..7447c0a04 --- /dev/null +++ b/shell/ash_test/ash-vars/var-pattern-replacement-in-parameter-expansion-2.right | |||
@@ -0,0 +1 @@ | |||
ax/yc | |||
diff --git a/shell/ash_test/ash-vars/var-pattern-replacement-in-parameter-expansion-2.tests b/shell/ash_test/ash-vars/var-pattern-replacement-in-parameter-expansion-2.tests new file mode 100755 index 000000000..2db1db897 --- /dev/null +++ b/shell/ash_test/ash-vars/var-pattern-replacement-in-parameter-expansion-2.tests | |||
@@ -0,0 +1,2 @@ | |||
1 | v="abc" | ||
2 | echo ${v/b/x/y} | ||
diff --git a/shell/ash_test/ash-vars/var-pattern-replacement-in-parameter-expansion-3.right b/shell/ash_test/ash-vars/var-pattern-replacement-in-parameter-expansion-3.right new file mode 100644 index 000000000..5ea5ff892 --- /dev/null +++ b/shell/ash_test/ash-vars/var-pattern-replacement-in-parameter-expansion-3.right | |||
@@ -0,0 +1 @@ | |||
axcabc | |||
diff --git a/shell/ash_test/ash-vars/var-pattern-replacement-in-parameter-expansion-3.tests b/shell/ash_test/ash-vars/var-pattern-replacement-in-parameter-expansion-3.tests new file mode 100755 index 000000000..0935e4509 --- /dev/null +++ b/shell/ash_test/ash-vars/var-pattern-replacement-in-parameter-expansion-3.tests | |||
@@ -0,0 +1,2 @@ | |||
1 | v="abcabc" | ||
2 | echo ${v/b/x} | ||
diff --git a/shell/ash_test/ash-vars/var-pattern-replacement-in-parameter-expansion-4.right b/shell/ash_test/ash-vars/var-pattern-replacement-in-parameter-expansion-4.right new file mode 100644 index 000000000..46dd750c1 --- /dev/null +++ b/shell/ash_test/ash-vars/var-pattern-replacement-in-parameter-expansion-4.right | |||
@@ -0,0 +1 @@ | |||
axcaxc | |||
diff --git a/shell/ash_test/ash-vars/var-pattern-replacement-in-parameter-expansion-4.tests b/shell/ash_test/ash-vars/var-pattern-replacement-in-parameter-expansion-4.tests new file mode 100755 index 000000000..d8de84347 --- /dev/null +++ b/shell/ash_test/ash-vars/var-pattern-replacement-in-parameter-expansion-4.tests | |||
@@ -0,0 +1,2 @@ | |||
1 | v="abcabc" | ||
2 | echo ${v//b/x} | ||
diff --git a/shell/ash_test/ash-vars/var-pattern-replacement-in-parameter-expansion-5.right b/shell/ash_test/ash-vars/var-pattern-replacement-in-parameter-expansion-5.right new file mode 100644 index 000000000..699b27b0c --- /dev/null +++ b/shell/ash_test/ash-vars/var-pattern-replacement-in-parameter-expansion-5.right | |||
@@ -0,0 +1 @@ | |||
axc | |||
diff --git a/shell/ash_test/ash-vars/var-pattern-replacement-in-parameter-expansion-5.tests b/shell/ash_test/ash-vars/var-pattern-replacement-in-parameter-expansion-5.tests new file mode 100755 index 000000000..552388877 --- /dev/null +++ b/shell/ash_test/ash-vars/var-pattern-replacement-in-parameter-expansion-5.tests | |||
@@ -0,0 +1,2 @@ | |||
1 | v="ab/c" | ||
2 | echo ${v/b\//x} | ||
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#[\\]}>" | |||
diff --git a/shell/ash_test/ash-vars/var3.right b/shell/ash_test/ash-vars/var3.right new file mode 100644 index 000000000..8eb0e3337 --- /dev/null +++ b/shell/ash_test/ash-vars/var3.right | |||
@@ -0,0 +1,5 @@ | |||
1 | 1 | ||
2 | 1 | ||
3 | |||
4 | |||
5 | 0 | ||
diff --git a/shell/ash_test/ash-vars/var3.tests b/shell/ash_test/ash-vars/var3.tests new file mode 100755 index 000000000..97b102cbe --- /dev/null +++ b/shell/ash_test/ash-vars/var3.tests | |||
@@ -0,0 +1 @@ | |||
x=0; f() { local x=1; echo $x; local x; echo $x; unset x; echo $x; local x; echo $x; }; f; echo $x | |||
diff --git a/shell/hush_test/hush-bugs/var3.right b/shell/hush_test/hush-bugs/var3.right new file mode 100644 index 000000000..8eb0e3337 --- /dev/null +++ b/shell/hush_test/hush-bugs/var3.right | |||
@@ -0,0 +1,5 @@ | |||
1 | 1 | ||
2 | 1 | ||
3 | |||
4 | |||
5 | 0 | ||
diff --git a/shell/hush_test/hush-bugs/var3.tests b/shell/hush_test/hush-bugs/var3.tests new file mode 100755 index 000000000..97b102cbe --- /dev/null +++ b/shell/hush_test/hush-bugs/var3.tests | |||
@@ -0,0 +1 @@ | |||
x=0; f() { local x=1; echo $x; local x; echo $x; unset x; echo $x; local x; echo $x; }; f; echo $x | |||
diff --git a/shell/hush_test/hush-vars/var-do-not-collapse-arithmetic-expansion-at-parse-time.right b/shell/hush_test/hush-vars/var-do-not-collapse-arithmetic-expansion-at-parse-time.right new file mode 100644 index 000000000..81a15855c --- /dev/null +++ b/shell/hush_test/hush-vars/var-do-not-collapse-arithmetic-expansion-at-parse-time.right | |||
@@ -0,0 +1,2 @@ | |||
1 | 12 | ||
2 | 9 | ||
diff --git a/shell/hush_test/hush-vars/var-do-not-collapse-arithmetic-expansion-at-parse-time.tests b/shell/hush_test/hush-vars/var-do-not-collapse-arithmetic-expansion-at-parse-time.tests new file mode 100755 index 000000000..e97a08a57 --- /dev/null +++ b/shell/hush_test/hush-vars/var-do-not-collapse-arithmetic-expansion-at-parse-time.tests | |||
@@ -0,0 +1,3 @@ | |||
1 | unset a | ||
2 | echo $((3 + ${a:=$((4 + 5))})) | ||
3 | echo $a | ||
diff --git a/shell/hush_test/hush-vars/var-do-not-expand-tilde-in-parameter-expansion-in-quotes.right b/shell/hush_test/hush-vars/var-do-not-expand-tilde-in-parameter-expansion-in-quotes.right new file mode 100644 index 000000000..4b9b4f038 --- /dev/null +++ b/shell/hush_test/hush-vars/var-do-not-expand-tilde-in-parameter-expansion-in-quotes.right | |||
@@ -0,0 +1 @@ | |||
~root | |||
diff --git a/shell/hush_test/hush-vars/var-do-not-expand-tilde-in-parameter-expansion-in-quotes.tests b/shell/hush_test/hush-vars/var-do-not-expand-tilde-in-parameter-expansion-in-quotes.tests new file mode 100755 index 000000000..d8eb8fc1b --- /dev/null +++ b/shell/hush_test/hush-vars/var-do-not-expand-tilde-in-parameter-expansion-in-quotes.tests | |||
@@ -0,0 +1,2 @@ | |||
1 | unset a | ||
2 | echo "${a:-~root}" | ||
diff --git a/shell/hush_test/hush-vars/var-do-not-quote-backslashes-in-parameter-expansions-outside-quotes.right b/shell/hush_test/hush-vars/var-do-not-quote-backslashes-in-parameter-expansions-outside-quotes.right new file mode 100644 index 000000000..030ebdeb6 --- /dev/null +++ b/shell/hush_test/hush-vars/var-do-not-quote-backslashes-in-parameter-expansions-outside-quotes.right | |||
@@ -0,0 +1 @@ | |||
/b/c/ | |||
diff --git a/shell/hush_test/hush-vars/var-do-not-quote-backslashes-in-parameter-expansions-outside-quotes.tests b/shell/hush_test/hush-vars/var-do-not-quote-backslashes-in-parameter-expansions-outside-quotes.tests new file mode 100755 index 000000000..fb9371467 --- /dev/null +++ b/shell/hush_test/hush-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/hush_test/hush-vars/var-pattern-replacement-in-parameter-expansion-1.right b/shell/hush_test/hush-vars/var-pattern-replacement-in-parameter-expansion-1.right new file mode 100644 index 000000000..2da327222 --- /dev/null +++ b/shell/hush_test/hush-vars/var-pattern-replacement-in-parameter-expansion-1.right | |||
@@ -0,0 +1 @@ | |||
a_\_z_c | |||
diff --git a/shell/hush_test/hush-vars/var-pattern-replacement-in-parameter-expansion-1.tests b/shell/hush_test/hush-vars/var-pattern-replacement-in-parameter-expansion-1.tests new file mode 100755 index 000000000..e4529c631 --- /dev/null +++ b/shell/hush_test/hush-vars/var-pattern-replacement-in-parameter-expansion-1.tests | |||
@@ -0,0 +1,2 @@ | |||
1 | v="a\bc" | ||
2 | echo ${v/\\b/_\\_\z_} | ||
diff --git a/shell/hush_test/hush-vars/var-pattern-replacement-in-parameter-expansion-2.right b/shell/hush_test/hush-vars/var-pattern-replacement-in-parameter-expansion-2.right new file mode 100644 index 000000000..7447c0a04 --- /dev/null +++ b/shell/hush_test/hush-vars/var-pattern-replacement-in-parameter-expansion-2.right | |||
@@ -0,0 +1 @@ | |||
ax/yc | |||
diff --git a/shell/hush_test/hush-vars/var-pattern-replacement-in-parameter-expansion-2.tests b/shell/hush_test/hush-vars/var-pattern-replacement-in-parameter-expansion-2.tests new file mode 100755 index 000000000..2db1db897 --- /dev/null +++ b/shell/hush_test/hush-vars/var-pattern-replacement-in-parameter-expansion-2.tests | |||
@@ -0,0 +1,2 @@ | |||
1 | v="abc" | ||
2 | echo ${v/b/x/y} | ||
diff --git a/shell/hush_test/hush-vars/var-pattern-replacement-in-parameter-expansion-3.right b/shell/hush_test/hush-vars/var-pattern-replacement-in-parameter-expansion-3.right new file mode 100644 index 000000000..5ea5ff892 --- /dev/null +++ b/shell/hush_test/hush-vars/var-pattern-replacement-in-parameter-expansion-3.right | |||
@@ -0,0 +1 @@ | |||
axcabc | |||
diff --git a/shell/hush_test/hush-vars/var-pattern-replacement-in-parameter-expansion-3.tests b/shell/hush_test/hush-vars/var-pattern-replacement-in-parameter-expansion-3.tests new file mode 100755 index 000000000..0935e4509 --- /dev/null +++ b/shell/hush_test/hush-vars/var-pattern-replacement-in-parameter-expansion-3.tests | |||
@@ -0,0 +1,2 @@ | |||
1 | v="abcabc" | ||
2 | echo ${v/b/x} | ||
diff --git a/shell/hush_test/hush-vars/var-pattern-replacement-in-parameter-expansion-4.right b/shell/hush_test/hush-vars/var-pattern-replacement-in-parameter-expansion-4.right new file mode 100644 index 000000000..46dd750c1 --- /dev/null +++ b/shell/hush_test/hush-vars/var-pattern-replacement-in-parameter-expansion-4.right | |||
@@ -0,0 +1 @@ | |||
axcaxc | |||
diff --git a/shell/hush_test/hush-vars/var-pattern-replacement-in-parameter-expansion-4.tests b/shell/hush_test/hush-vars/var-pattern-replacement-in-parameter-expansion-4.tests new file mode 100755 index 000000000..d8de84347 --- /dev/null +++ b/shell/hush_test/hush-vars/var-pattern-replacement-in-parameter-expansion-4.tests | |||
@@ -0,0 +1,2 @@ | |||
1 | v="abcabc" | ||
2 | echo ${v//b/x} | ||
diff --git a/shell/hush_test/hush-vars/var-pattern-replacement-in-parameter-expansion-5.right b/shell/hush_test/hush-vars/var-pattern-replacement-in-parameter-expansion-5.right new file mode 100644 index 000000000..699b27b0c --- /dev/null +++ b/shell/hush_test/hush-vars/var-pattern-replacement-in-parameter-expansion-5.right | |||
@@ -0,0 +1 @@ | |||
axc | |||
diff --git a/shell/hush_test/hush-vars/var-pattern-replacement-in-parameter-expansion-5.tests b/shell/hush_test/hush-vars/var-pattern-replacement-in-parameter-expansion-5.tests new file mode 100755 index 000000000..552388877 --- /dev/null +++ b/shell/hush_test/hush-vars/var-pattern-replacement-in-parameter-expansion-5.tests | |||
@@ -0,0 +1,2 @@ | |||
1 | v="ab/c" | ||
2 | echo ${v/b\//x} | ||
diff --git a/shell/hush_test/hush-vars/var-runtime-quote-detection.right b/shell/hush_test/hush-vars/var-runtime-quote-detection.right new file mode 100644 index 000000000..b554d9e46 --- /dev/null +++ b/shell/hush_test/hush-vars/var-runtime-quote-detection.right | |||
@@ -0,0 +1 @@ | |||
<> | |||
diff --git a/shell/hush_test/hush-vars/var-runtime-quote-detection.tests b/shell/hush_test/hush-vars/var-runtime-quote-detection.tests new file mode 100755 index 000000000..e570631fd --- /dev/null +++ b/shell/hush_test/hush-vars/var-runtime-quote-detection.tests | |||
@@ -0,0 +1 @@ | |||
foo=\\ echo "<${foo#[\\]}>" | |||