aboutsummaryrefslogtreecommitdiff
path: root/shell
diff options
context:
space:
mode:
authorNguyễn Thái Ngọc Duy <pclouds@gmail.com>2010-09-14 13:36:48 +1000
committerNguyễn Thái Ngọc Duy <pclouds@gmail.com>2010-09-14 13:36:48 +1000
commit6e55663080e33d1856d949d60e45b135f2613087 (patch)
tree7318387028176038ca96344831febb30a582d661 /shell
parentc6933c626b97c3f6bc446586ee2e6c7d9930c938 (diff)
parentdcaed97e0f44d0cd285fb590ec6ec80d0d73e738 (diff)
downloadbusybox-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.c108
-rw-r--r--shell/ash_test/ash-vars/var_bash4.right25
-rwxr-xr-xshell/ash_test/ash-vars/var_bash4.tests51
-rw-r--r--shell/hush.c2
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
6428static char * 6428static char *
6429scanleft(char *startp, char *rmesc, char *rmescend UNUSED_PARAM, char *str, int quotes, 6429scanleft(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
6499static char * 6459static char *
6500scanright(char *startp, char *rmesc, char *rmescend, char *pattern, int quotes, int match_at_start) 6460scanright(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
6569static void varunset(const char *, const char *, const char *, int) NORETURN; 6530static 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
6590static char * 6551static char *
6591parse_sub_pattern(char *arg, int inquotes) 6552parse_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 @@
1In assignment: a*b-backslashstar- 1Source: a*b\*c
2Unquoted: a*b-backslashstar- 2Replace str: _\\_\z_
3Quoted: a*b-backslashstar- 3Pattern: single backslash and star: "replace literal star"
4In assignment: a_\_z_b\*c
5Unquoted: a_\_z_b\*c
6Quoted: a_\_\z_b\*c
7Pattern: double backslash and star: "replace backslash and everything after it"
8In assignment: a*b_\_z_
9Unquoted: a*b_\_z_
10Quoted: a*b_\_\z_
11
12Source: a\bc
13Replace str: _\\_\z_
14Pattern: single backslash and b: "replace b"
15In assignment: a\_\_z_c
16Unquoted: a\_\_z_c
17Quoted: a\_\_\z_c
18Pattern: double backslash and b: "replace backslash and b"
19In assignment: a_\_z_c
20Unquoted: a_\_z_c
21Quoted: a_\_\z_c
22
4Done: 0 23Done: 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 @@
1FOO='a*b\*c' 1# This testcase demonstrates that backslashes are treated differently
2BAR=${FOO//\\*/-backslashstar-} 2# in 1st and 2nd parts of ${var/search/repl}:
3echo In assignment: "$BAR" 3# if quoted ("${var/search/repl}"), and repl contains \a (a non-special char),
4echo Unquoted: ${FOO//\\*/-backslashstar-} 4# the backslash in repl stays; if unquoted, backslash is removed.
5echo 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
11v='a*b\*c'
12echo 'Source: ' "$v"
13echo 'Replace str: ' '_\\_\z_'
14
15echo 'Pattern: ' 'single backslash and star: "replace literal star"'
16r=${v/\*/_\\_\z_}
17echo 'In assignment:' "$r"
18echo 'Unquoted: ' ${v/\*/_\\_\z_}
19echo 'Quoted: ' "${v/\*/_\\_\z_}"
20
21echo 'Pattern: ' 'double backslash and star: "replace backslash and everything after it"'
22r=${v/\\*/_\\_\z_}
23echo 'In assignment:' "$r"
24echo 'Unquoted: ' ${v/\\*/_\\_\z_}
25echo 'Quoted: ' "${v/\\*/_\\_\z_}"
26
27echo
28
29v='a\bc'
30echo 'Source: ' "$v"
31echo 'Replace str: ' '_\\_\z_'
32
33echo 'Pattern: ' 'single backslash and b: "replace b"'
34r=${v/\b/_\\_\z_}
35echo 'In assignment:' "$r"
36echo 'Unquoted: ' ${v/\b/_\\_\z_}
37echo 'Quoted: ' "${v/\b/_\\_\z_}"
38
39echo 'Pattern: ' 'double backslash and b: "replace backslash and b"'
40r=${v/\\b/_\\_\z_}
41echo 'In assignment:' "$r"
42echo 'Unquoted: ' ${v/\\b/_\\_\z_}
43echo 'Quoted: ' "${v/\\b/_\\_\z_}"
44
45echo
46
6echo Done: $? 47echo 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 */