diff options
author | Nguyễn Thái Ngọc Duy <pclouds@gmail.com> | 2010-09-14 13:36:48 +1000 |
---|---|---|
committer | Nguyễn Thái Ngọc Duy <pclouds@gmail.com> | 2010-09-14 13:36:48 +1000 |
commit | 6e55663080e33d1856d949d60e45b135f2613087 (patch) | |
tree | 7318387028176038ca96344831febb30a582d661 /shell | |
parent | c6933c626b97c3f6bc446586ee2e6c7d9930c938 (diff) | |
parent | dcaed97e0f44d0cd285fb590ec6ec80d0d73e738 (diff) | |
download | busybox-w32-6e55663080e33d1856d949d60e45b135f2613087.tar.gz busybox-w32-6e55663080e33d1856d949d60e45b135f2613087.tar.bz2 busybox-w32-6e55663080e33d1856d949d60e45b135f2613087.zip |
Merge branch 'origin/master' (early part)
Diffstat (limited to 'shell')
-rw-r--r-- | shell/ash.c | 108 | ||||
-rw-r--r-- | shell/ash_test/ash-vars/var_bash4.right | 25 | ||||
-rwxr-xr-x | shell/ash_test/ash-vars/var_bash4.tests | 51 | ||||
-rw-r--r-- | shell/hush.c | 2 |
4 files changed, 109 insertions, 77 deletions
diff --git a/shell/ash.c b/shell/ash.c index 308cc0273..f7fad88cd 100644 --- a/shell/ash.c +++ b/shell/ash.c | |||
@@ -5977,7 +5977,7 @@ removerecordregions(int endoff) | |||
5977 | return; | 5977 | return; |
5978 | 5978 | ||
5979 | if (ifsfirst.endoff > endoff) { | 5979 | if (ifsfirst.endoff > endoff) { |
5980 | while (ifsfirst.next != NULL) { | 5980 | while (ifsfirst.next) { |
5981 | struct ifsregion *ifsp; | 5981 | struct ifsregion *ifsp; |
5982 | INT_OFF; | 5982 | INT_OFF; |
5983 | ifsp = ifsfirst.next->next; | 5983 | ifsp = ifsfirst.next->next; |
@@ -5985,9 +5985,9 @@ removerecordregions(int endoff) | |||
5985 | ifsfirst.next = ifsp; | 5985 | ifsfirst.next = ifsp; |
5986 | INT_ON; | 5986 | INT_ON; |
5987 | } | 5987 | } |
5988 | if (ifsfirst.begoff > endoff) | 5988 | if (ifsfirst.begoff > endoff) { |
5989 | ifslastp = NULL; | 5989 | ifslastp = NULL; |
5990 | else { | 5990 | } else { |
5991 | ifslastp = &ifsfirst; | 5991 | ifslastp = &ifsfirst; |
5992 | ifsfirst.endoff = endoff; | 5992 | ifsfirst.endoff = endoff; |
5993 | } | 5993 | } |
@@ -5996,8 +5996,8 @@ removerecordregions(int endoff) | |||
5996 | 5996 | ||
5997 | ifslastp = &ifsfirst; | 5997 | ifslastp = &ifsfirst; |
5998 | while (ifslastp->next && ifslastp->next->begoff < endoff) | 5998 | while (ifslastp->next && ifslastp->next->begoff < endoff) |
5999 | ifslastp=ifslastp->next; | 5999 | ifslastp = ifslastp->next; |
6000 | while (ifslastp->next != NULL) { | 6000 | while (ifslastp->next) { |
6001 | struct ifsregion *ifsp; | 6001 | struct ifsregion *ifsp; |
6002 | INT_OFF; | 6002 | INT_OFF; |
6003 | ifsp = ifslastp->next->next; | 6003 | ifsp = ifslastp->next->next; |
@@ -6205,9 +6205,9 @@ expbackq(union node *cmd, int quoted, int quotes) | |||
6205 | 6205 | ||
6206 | if (quoted == 0) | 6206 | if (quoted == 0) |
6207 | recordregion(startloc, dest - (char *)stackblock(), 0); | 6207 | recordregion(startloc, dest - (char *)stackblock(), 0); |
6208 | TRACE(("evalbackq: size=%d: \"%.*s\"\n", | 6208 | TRACE(("evalbackq: size:%d:'%.*s'\n", |
6209 | (dest - (char *)stackblock()) - startloc, | 6209 | (int)((dest - (char *)stackblock()) - startloc), |
6210 | (dest - (char *)stackblock()) - startloc, | 6210 | (int)((dest - (char *)stackblock()) - startloc), |
6211 | stackblock() + startloc)); | 6211 | stackblock() + startloc)); |
6212 | } | 6212 | } |
6213 | 6213 | ||
@@ -6426,42 +6426,16 @@ argstr(char *p, int flags, struct strlist *var_str_list) | |||
6426 | } | 6426 | } |
6427 | 6427 | ||
6428 | static char * | 6428 | static char * |
6429 | scanleft(char *startp, char *rmesc, char *rmescend UNUSED_PARAM, char *str, int quotes, | 6429 | scanleft(char *startp, char *rmesc, char *rmescend UNUSED_PARAM, |
6430 | int zero) | 6430 | char *pattern, int quotes, int zero) |
6431 | { | 6431 | { |
6432 | // This commented out code was added by James Simmons <jsimmons@infradead.org> | 6432 | char *loc, *loc2; |
6433 | // as part of a larger change when he added support for ${var/a/b}. | ||
6434 | // However, it broke # and % operators: | ||
6435 | // | ||
6436 | //var=ababcdcd | ||
6437 | // ok bad | ||
6438 | //echo ${var#ab} abcdcd abcdcd | ||
6439 | //echo ${var##ab} abcdcd abcdcd | ||
6440 | //echo ${var#a*b} abcdcd ababcdcd (!) | ||
6441 | //echo ${var##a*b} cdcd cdcd | ||
6442 | //echo ${var#?} babcdcd ababcdcd (!) | ||
6443 | //echo ${var##?} babcdcd babcdcd | ||
6444 | //echo ${var#*} ababcdcd babcdcd (!) | ||
6445 | //echo ${var##*} | ||
6446 | //echo ${var%cd} ababcd ababcd | ||
6447 | //echo ${var%%cd} ababcd abab (!) | ||
6448 | //echo ${var%c*d} ababcd ababcd | ||
6449 | //echo ${var%%c*d} abab ababcdcd (!) | ||
6450 | //echo ${var%?} ababcdc ababcdc | ||
6451 | //echo ${var%%?} ababcdc ababcdcd (!) | ||
6452 | //echo ${var%*} ababcdcd ababcdcd | ||
6453 | //echo ${var%%*} | ||
6454 | // | ||
6455 | // Commenting it back out helped. Remove it completely if it really | ||
6456 | // is not needed. | ||
6457 | |||
6458 | char *loc, *loc2; //, *full; | ||
6459 | char c; | 6433 | char c; |
6460 | 6434 | ||
6461 | loc = startp; | 6435 | loc = startp; |
6462 | loc2 = rmesc; | 6436 | loc2 = rmesc; |
6463 | do { | 6437 | do { |
6464 | int match; // = strlen(str); | 6438 | int match; |
6465 | const char *s = loc2; | 6439 | const char *s = loc2; |
6466 | 6440 | ||
6467 | c = *loc2; | 6441 | c = *loc2; |
@@ -6469,35 +6443,22 @@ scanleft(char *startp, char *rmesc, char *rmescend UNUSED_PARAM, char *str, int | |||
6469 | *loc2 = '\0'; | 6443 | *loc2 = '\0'; |
6470 | s = rmesc; | 6444 | s = rmesc; |
6471 | } | 6445 | } |
6472 | match = pmatch(str, s); // this line was deleted | 6446 | match = pmatch(pattern, s); |
6473 | 6447 | ||
6474 | // // chop off end if its '*' | ||
6475 | // full = strrchr(str, '*'); | ||
6476 | // if (full && full != str) | ||
6477 | // match--; | ||
6478 | // | ||
6479 | // // If str starts with '*' replace with s. | ||
6480 | // if ((*str == '*') && strlen(s) >= match) { | ||
6481 | // full = xstrdup(s); | ||
6482 | // strncpy(full+strlen(s)-match+1, str+1, match-1); | ||
6483 | // } else | ||
6484 | // full = xstrndup(str, match); | ||
6485 | // match = strncmp(s, full, strlen(full)); | ||
6486 | // free(full); | ||
6487 | // | ||
6488 | *loc2 = c; | 6448 | *loc2 = c; |
6489 | if (match) // if (!match) | 6449 | if (match) |
6490 | return loc; | 6450 | return loc; |
6491 | if (quotes && (unsigned char)*loc == CTLESC) | 6451 | if (quotes && (unsigned char)*loc == CTLESC) |
6492 | loc++; | 6452 | loc++; |
6493 | loc++; | 6453 | loc++; |
6494 | loc2++; | 6454 | loc2++; |
6495 | } while (c); | 6455 | } while (c); |
6496 | return 0; | 6456 | return NULL; |
6497 | } | 6457 | } |
6498 | 6458 | ||
6499 | static char * | 6459 | static char * |
6500 | scanright(char *startp, char *rmesc, char *rmescend, char *pattern, int quotes, int match_at_start) | 6460 | scanright(char *startp, char *rmesc, char *rmescend, |
6461 | char *pattern, int quotes, int match_at_start) | ||
6501 | { | 6462 | { |
6502 | #if !ENABLE_ASH_OPTIMIZE_FOR_SIZE | 6463 | #if !ENABLE_ASH_OPTIMIZE_FOR_SIZE |
6503 | int try2optimize = match_at_start; | 6464 | int try2optimize = match_at_start; |
@@ -6563,7 +6524,7 @@ scanright(char *startp, char *rmesc, char *rmescend, char *pattern, int quotes, | |||
6563 | } | 6524 | } |
6564 | } | 6525 | } |
6565 | } | 6526 | } |
6566 | return 0; | 6527 | return NULL; |
6567 | } | 6528 | } |
6568 | 6529 | ||
6569 | static void varunset(const char *, const char *, const char *, int) NORETURN; | 6530 | static void varunset(const char *, const char *, const char *, int) NORETURN; |
@@ -6583,16 +6544,18 @@ varunset(const char *end, const char *var, const char *umsg, int varflags) | |||
6583 | msg = umsg; | 6544 | msg = umsg; |
6584 | } | 6545 | } |
6585 | } | 6546 | } |
6586 | ash_msg_and_raise_error("%.*s: %s%s", end - var - 1, var, msg, tail); | 6547 | ash_msg_and_raise_error("%.*s: %s%s", (int)(end - var - 1), var, msg, tail); |
6587 | } | 6548 | } |
6588 | 6549 | ||
6589 | #if ENABLE_ASH_BASH_COMPAT | 6550 | #if ENABLE_ASH_BASH_COMPAT |
6590 | static char * | 6551 | static char * |
6591 | parse_sub_pattern(char *arg, int inquotes) | 6552 | parse_sub_pattern(char *arg, int varflags) |
6592 | { | 6553 | { |
6593 | char *idx, *repl = NULL; | 6554 | char *idx, *repl = NULL; |
6594 | unsigned char c; | 6555 | unsigned char c; |
6595 | 6556 | ||
6557 | //char *org_arg = arg; | ||
6558 | //bb_error_msg("arg:'%s' varflags:%x", arg, varflags); | ||
6596 | idx = arg; | 6559 | idx = arg; |
6597 | while (1) { | 6560 | while (1) { |
6598 | c = *arg; | 6561 | c = *arg; |
@@ -6606,11 +6569,23 @@ parse_sub_pattern(char *arg, int inquotes) | |||
6606 | } | 6569 | } |
6607 | } | 6570 | } |
6608 | *idx++ = c; | 6571 | *idx++ = c; |
6609 | if (!inquotes && c == '\\' && arg[1] == '\\') | ||
6610 | arg++; /* skip both \\, not just first one */ | ||
6611 | arg++; | 6572 | arg++; |
6573 | /* | ||
6574 | * Example: v='ab\c'; echo ${v/\\b/_\\_\z_} | ||
6575 | * The result is a_\_z_c (not a\_\_z_c)! | ||
6576 | * | ||
6577 | * Enable debug prints in this function and you'll see: | ||
6578 | * ash: arg:'\\b/_\\_z_' varflags:d | ||
6579 | * ash: pattern:'\\b' repl:'_\_z_' | ||
6580 | * That is, \\b is interpreted as \\b, but \\_ as \_! | ||
6581 | * IOW: search pattern and replace string treat backslashes | ||
6582 | * differently! That is the reason why we check repl below: | ||
6583 | */ | ||
6584 | if (c == '\\' && *arg == '\\' && repl && !(varflags & VSQUOTE)) | ||
6585 | arg++; /* skip both '\', not just first one */ | ||
6612 | } | 6586 | } |
6613 | *idx = c; /* NUL */ | 6587 | *idx = c; /* NUL */ |
6588 | //bb_error_msg("pattern:'%s' repl:'%s'", org_arg, repl); | ||
6614 | 6589 | ||
6615 | return repl; | 6590 | return repl; |
6616 | } | 6591 | } |
@@ -6748,7 +6723,7 @@ subevalvar(char *p, char *varname, int strloc, int subtype, | |||
6748 | char *idx, *end; | 6723 | char *idx, *end; |
6749 | 6724 | ||
6750 | if (!repl) { | 6725 | if (!repl) { |
6751 | repl = parse_sub_pattern(str, varflags & VSQUOTE); | 6726 | repl = parse_sub_pattern(str, varflags); |
6752 | //bb_error_msg("repl:'%s'", repl); | 6727 | //bb_error_msg("repl:'%s'", repl); |
6753 | if (!repl) | 6728 | if (!repl) |
6754 | repl = nullstr; | 6729 | repl = nullstr; |
@@ -6817,12 +6792,9 @@ subevalvar(char *p, char *varname, int strloc, int subtype, | |||
6817 | } | 6792 | } |
6818 | 6793 | ||
6819 | if (subtype == VSREPLACE) { | 6794 | if (subtype == VSREPLACE) { |
6795 | //bb_error_msg("tail:'%s', quotes:%x", idx, quotes); | ||
6820 | while (*idx) { | 6796 | while (*idx) { |
6821 | char *restart_detect = stackblock(); | 6797 | char *restart_detect = stackblock(); |
6822 | if (quotes && *idx == '\\') { | ||
6823 | STPUTC(CTLESC, expdest); | ||
6824 | len++; | ||
6825 | } | ||
6826 | STPUTC(*idx, expdest); | 6798 | STPUTC(*idx, expdest); |
6827 | if (stackblock() != restart_detect) | 6799 | if (stackblock() != restart_detect) |
6828 | goto restart; | 6800 | goto restart; |
diff --git a/shell/ash_test/ash-vars/var_bash4.right b/shell/ash_test/ash-vars/var_bash4.right index fc3a9e41c..600e8532f 100644 --- a/shell/ash_test/ash-vars/var_bash4.right +++ b/shell/ash_test/ash-vars/var_bash4.right | |||
@@ -1,4 +1,23 @@ | |||
1 | In assignment: a*b-backslashstar- | 1 | Source: a*b\*c |
2 | Unquoted: a*b-backslashstar- | 2 | Replace str: _\\_\z_ |
3 | Quoted: a*b-backslashstar- | 3 | Pattern: single backslash and star: "replace literal star" |
4 | In assignment: a_\_z_b\*c | ||
5 | Unquoted: a_\_z_b\*c | ||
6 | Quoted: a_\_\z_b\*c | ||
7 | Pattern: double backslash and star: "replace backslash and everything after it" | ||
8 | In assignment: a*b_\_z_ | ||
9 | Unquoted: a*b_\_z_ | ||
10 | Quoted: a*b_\_\z_ | ||
11 | |||
12 | Source: a\bc | ||
13 | Replace str: _\\_\z_ | ||
14 | Pattern: single backslash and b: "replace b" | ||
15 | In assignment: a\_\_z_c | ||
16 | Unquoted: a\_\_z_c | ||
17 | Quoted: a\_\_\z_c | ||
18 | Pattern: double backslash and b: "replace backslash and b" | ||
19 | In assignment: a_\_z_c | ||
20 | Unquoted: a_\_z_c | ||
21 | Quoted: a_\_\z_c | ||
22 | |||
4 | Done: 0 | 23 | Done: 0 |
diff --git a/shell/ash_test/ash-vars/var_bash4.tests b/shell/ash_test/ash-vars/var_bash4.tests index 3b323c576..d5470614b 100755 --- a/shell/ash_test/ash-vars/var_bash4.tests +++ b/shell/ash_test/ash-vars/var_bash4.tests | |||
@@ -1,6 +1,47 @@ | |||
1 | FOO='a*b\*c' | 1 | # This testcase demonstrates that backslashes are treated differently |
2 | BAR=${FOO//\\*/-backslashstar-} | 2 | # in 1st and 2nd parts of ${var/search/repl}: |
3 | echo In assignment: "$BAR" | 3 | # if quoted ("${var/search/repl}"), and repl contains \a (a non-special char), |
4 | echo Unquoted: ${FOO//\\*/-backslashstar-} | 4 | # the backslash in repl stays; if unquoted, backslash is removed. |
5 | echo Quoted: "${FOO//\\*/-backslashstar-}" | 5 | # But search part does not act like that: \a is always converted to just a, |
6 | # even in quotes. | ||
7 | # | ||
8 | # bash4 (and probably bash3 too): "Quoted:" results are different from | ||
9 | # unquoted and assignment expansions - they have a backslash before z. | ||
10 | |||
11 | v='a*b\*c' | ||
12 | echo 'Source: ' "$v" | ||
13 | echo 'Replace str: ' '_\\_\z_' | ||
14 | |||
15 | echo 'Pattern: ' 'single backslash and star: "replace literal star"' | ||
16 | r=${v/\*/_\\_\z_} | ||
17 | echo 'In assignment:' "$r" | ||
18 | echo 'Unquoted: ' ${v/\*/_\\_\z_} | ||
19 | echo 'Quoted: ' "${v/\*/_\\_\z_}" | ||
20 | |||
21 | echo 'Pattern: ' 'double backslash and star: "replace backslash and everything after it"' | ||
22 | r=${v/\\*/_\\_\z_} | ||
23 | echo 'In assignment:' "$r" | ||
24 | echo 'Unquoted: ' ${v/\\*/_\\_\z_} | ||
25 | echo 'Quoted: ' "${v/\\*/_\\_\z_}" | ||
26 | |||
27 | echo | ||
28 | |||
29 | v='a\bc' | ||
30 | echo 'Source: ' "$v" | ||
31 | echo 'Replace str: ' '_\\_\z_' | ||
32 | |||
33 | echo 'Pattern: ' 'single backslash and b: "replace b"' | ||
34 | r=${v/\b/_\\_\z_} | ||
35 | echo 'In assignment:' "$r" | ||
36 | echo 'Unquoted: ' ${v/\b/_\\_\z_} | ||
37 | echo 'Quoted: ' "${v/\b/_\\_\z_}" | ||
38 | |||
39 | echo 'Pattern: ' 'double backslash and b: "replace backslash and b"' | ||
40 | r=${v/\\b/_\\_\z_} | ||
41 | echo 'In assignment:' "$r" | ||
42 | echo 'Unquoted: ' ${v/\\b/_\\_\z_} | ||
43 | echo 'Quoted: ' "${v/\\b/_\\_\z_}" | ||
44 | |||
45 | echo | ||
46 | |||
6 | echo Done: $? | 47 | echo Done: $? |
diff --git a/shell/hush.c b/shell/hush.c index 0a420f685..df4058998 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
@@ -2788,7 +2788,7 @@ static NOINLINE int expand_vars_to_list(o_string *output, int n, char *arg, char | |||
2788 | /* lookup the variable in question */ | 2788 | /* lookup the variable in question */ |
2789 | if (isdigit(var[0])) { | 2789 | if (isdigit(var[0])) { |
2790 | /* parse_dollar() should have vetted var for us */ | 2790 | /* parse_dollar() should have vetted var for us */ |
2791 | i = xatoi_u(var); | 2791 | i = xatoi_positive(var); |
2792 | if (i < G.global_argc) | 2792 | if (i < G.global_argc) |
2793 | val = G.global_argv[i]; | 2793 | val = G.global_argv[i]; |
2794 | /* else val remains NULL: $N with too big N */ | 2794 | /* else val remains NULL: $N with too big N */ |