summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2010-08-05 15:19:27 (GMT)
committer Denys Vlasenko <vda.linux@googlemail.com>2010-08-05 15:19:27 (GMT)
commitb0fbe4b5409b136e0c80788cf183ec24237e9c97 (patch)
treed5ef2215b48c894721801f0fe7184a347f91d669
parente74d79866c6d125527e3ba69245a087a28fd19ce (diff)
downloadbusybox-b0fbe4b5409b136e0c80788cf183ec24237e9c97.tar.gz
busybox-b0fbe4b5409b136e0c80788cf183ec24237e9c97.tar.bz2
ash: add a testcase for bug 2281 (currently fails). Small code cleanups.
function old new delta changepath 195 192 -3 subevalvar 1204 1200 -4 readtoken1 3247 3240 -7 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 0/3 up/down: 0/-14) Total: -14 bytes Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r--shell/ash.c83
-rwxr-xr-x[-rw-r--r--]shell/ash_test/ash-redir/redir9.tests0
-rw-r--r--shell/ash_test/ash-vars/var_bash3.right40
-rwxr-xr-xshell/ash_test/ash-vars/var_bash3.tests47
-rw-r--r--shell/ash_test/ash-vars/var_bash4.right2
-rwxr-xr-xshell/ash_test/ash-vars/var_bash4.tests3
6 files changed, 104 insertions, 71 deletions
diff --git a/shell/ash.c b/shell/ash.c
index d8becc3..16783f2 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -6296,13 +6296,14 @@ parse_sub_pattern(char *arg, int inquotes)
#endif /* ENABLE_ASH_BASH_COMPAT */
static const char *
-subevalvar(char *p, char *str, int strloc, int subtype,
+subevalvar(char *p, char *varname, int strloc, int subtype,
int startloc, int varflags, int quotes, struct strlist *var_str_list)
{
struct nodelist *saveargbackq = argbackq;
char *startp;
char *loc;
char *rmesc, *rmescend;
+ char *str;
IF_ASH_BASH_COMPAT(const char *repl = NULL;)
IF_ASH_BASH_COMPAT(int pos, len, orig_len;)
int saveherefd = herefd;
@@ -6310,6 +6311,9 @@ subevalvar(char *p, char *str, int strloc, int subtype,
int zero;
char *(*scan)(char*, char*, char*, char*, int, int);
+ //bb_error_msg("subevalvar(p:'%s',varname:'%s',strloc:%d,subtype:%d,startloc:%d,varflags:%x,quotes:%d",
+ // p, varname, strloc, subtype, startloc, varflags, quotes);
+
herefd = -1;
argstr(p, (subtype != VSASSIGN && subtype != VSQUESTION) ? EXP_CASE : 0,
var_str_list);
@@ -6320,11 +6324,15 @@ subevalvar(char *p, char *str, int strloc, int subtype,
switch (subtype) {
case VSASSIGN:
- setvar(str, startp, 0);
+ setvar(varname, startp, 0);
amount = startp - expdest;
STADJUST(amount, expdest);
return startp;
+ case VSQUESTION:
+ varunset(p, varname, startp, varflags);
+ /* NOTREACHED */
+
#if ENABLE_ASH_BASH_COMPAT
case VSSUBSTR:
loc = str = stackblock() + strloc;
@@ -6385,11 +6393,8 @@ subevalvar(char *p, char *str, int strloc, int subtype,
STADJUST(amount, expdest);
return loc;
#endif
-
- case VSQUESTION:
- varunset(p, str, startp, varflags);
- /* NOTREACHED */
}
+
resetloc = expdest - (char *)stackblock();
/* We'll comeback here if we grow the stack while handling
@@ -6423,13 +6428,14 @@ subevalvar(char *p, char *str, int strloc, int subtype,
if (!repl) {
repl = parse_sub_pattern(str, varflags & VSQUOTE);
+ //bb_error_msg("repl:'%s'", repl);
if (!repl)
repl = nullstr;
}
/* If there's no pattern to match, return the expansion unmolested */
if (str[0] == '\0')
- return 0;
+ return NULL;
len = 0;
idx = startp;
@@ -6437,6 +6443,7 @@ subevalvar(char *p, char *str, int strloc, int subtype,
while (idx < end) {
try_to_match:
loc = scanright(idx, rmesc, rmescend, str, quotes, 1);
+ //bb_error_msg("scanright('%s'):'%s'", str, loc);
if (!loc) {
/* No match, advance */
char *restart_detect = stackblock();
@@ -6475,6 +6482,7 @@ subevalvar(char *p, char *str, int strloc, int subtype,
idx = loc;
}
+ //bb_error_msg("repl:'%s'", repl);
for (loc = (char*)repl; *loc; loc++) {
char *restart_detect = stackblock();
if (quotes && *loc == '\\') {
@@ -6510,6 +6518,7 @@ subevalvar(char *p, char *str, int strloc, int subtype,
STPUTC('\0', expdest);
startp = (char *)stackblock() + startloc;
memmove(startp, (char *)stackblock() + workloc, len + 1);
+ //bb_error_msg("startp:'%s'", startp);
amount = expdest - (startp + len);
STADJUST(-amount, expdest);
return startp;
@@ -6810,7 +6819,7 @@ evalvar(char *p, int flags, struct strlist *var_str_list)
*/
STPUTC('\0', expdest);
patloc = expdest - (char *)stackblock();
- if (NULL == subevalvar(p, /* str: */ NULL, patloc, subtype,
+ if (NULL == subevalvar(p, /* varname: */ NULL, patloc, subtype,
startloc, varflags,
//TODO: | EXP_REDIR too? All other such places do it too
/* quotes: */ flags & (EXP_FULL | EXP_CASE),
@@ -11114,8 +11123,11 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs)
USTPUTC('\\', out);
}
#endif
- if (dblquote && c != '\\'
- && c != '`' && c != '$'
+ /* Backslash is retained if we are in "str" and next char isn't special */
+ if (dblquote
+ && c != '\\'
+ && c != '`'
+ && c != '$'
&& (c != '"' || eofmark != NULL)
) {
USTPUTC(CTLESC, out);
@@ -11187,7 +11199,7 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs)
} else {
/*
* unbalanced parens
- * (don't 2nd guess - no error)
+ * (don't 2nd guess - no error)
*/
pungetc();
USTPUTC(')', out);
@@ -11380,8 +11392,6 @@ parsesub: {
unsigned char subtype;
int typeloc;
int flags;
- char *p;
- static const char types[] ALIGN1 = "}-+?=";
c = pgetc();
if (c > 255 /* PEOA or PEOF */
@@ -11394,7 +11404,8 @@ parsesub: {
#endif
USTPUTC('$', out);
pungetc();
- } else if (c == '(') { /* $(command) or $((arith)) */
+ } else if (c == '(') {
+ /* $(command) or $((arith)) */
if (pgetc() == '(') {
#if ENABLE_SH_MATH_SUPPORT
PARSEARITH();
@@ -11406,6 +11417,7 @@ parsesub: {
PARSEBACKQNEW();
}
} else {
+ /* $VAR, $<specialchar>, ${...}, or PEOA/PEOF */
USTPUTC(CTLVAR, out);
typeloc = out - (char *)stackblock();
USTPUTC(VSNORMAL, out);
@@ -11415,76 +11427,85 @@ parsesub: {
if (c == '#') {
c = pgetc();
if (c == '}')
- c = '#';
+ c = '#'; /* ${#} - same as $# */
else
- subtype = VSLENGTH;
- } else
+ subtype = VSLENGTH; /* ${#VAR} */
+ } else {
subtype = 0;
+ }
}
if (c <= 255 /* not PEOA or PEOF */ && is_name(c)) {
+ /* $[{[#]]NAME[}] */
do {
STPUTC(c, out);
c = pgetc();
} while (c <= 255 /* not PEOA or PEOF */ && is_in_name(c));
} else if (isdigit(c)) {
+ /* $[{[#]]NUM[}] */
do {
STPUTC(c, out);
c = pgetc();
} while (isdigit(c));
} else if (is_special(c)) {
+ /* $[{[#]]<specialchar>[}] */
USTPUTC(c, out);
c = pgetc();
} else {
badsub:
raise_error_syntax("bad substitution");
}
- if (c != '}' && subtype == VSLENGTH)
+ if (c != '}' && subtype == VSLENGTH) {
+ /* ${#VAR didn't end with } */
goto badsub;
+ }
STPUTC('=', out);
flags = 0;
if (subtype == 0) {
+ /* ${VAR...} but not $VAR or ${#VAR} */
+ /* c == first char after VAR */
switch (c) {
case ':':
c = pgetc();
#if ENABLE_ASH_BASH_COMPAT
if (c == ':' || c == '$' || isdigit(c)) {
- pungetc();
subtype = VSSUBSTR;
- break;
+ pungetc();
+ break; /* "goto do_pungetc" is bigger (!) */
}
#endif
flags = VSNUL;
/*FALLTHROUGH*/
- default:
- p = strchr(types, c);
+ default: {
+ static const char types[] ALIGN1 = "}-+?=";
+ const char *p = strchr(types, c);
if (p == NULL)
goto badsub;
subtype = p - types + VSNORMAL;
break;
+ }
case '%':
case '#': {
int cc = c;
- subtype = c == '#' ? VSTRIMLEFT : VSTRIMRIGHT;
+ subtype = (c == '#' ? VSTRIMLEFT : VSTRIMRIGHT);
c = pgetc();
- if (c == cc)
- subtype++;
- else
- pungetc();
+ if (c != cc)
+ goto do_pungetc;
+ subtype++;
break;
}
#if ENABLE_ASH_BASH_COMPAT
case '/':
subtype = VSREPLACE;
c = pgetc();
- if (c == '/')
- subtype++; /* VSREPLACEALL */
- else
- pungetc();
+ if (c != '/')
+ goto do_pungetc;
+ subtype++; /* VSREPLACEALL */
break;
#endif
}
} else {
+ do_pungetc:
pungetc();
}
if (dblquote || arinest)
diff --git a/shell/ash_test/ash-redir/redir9.tests b/shell/ash_test/ash-redir/redir9.tests
index 8befa61..8befa61 100644..100755
--- a/shell/ash_test/ash-redir/redir9.tests
+++ b/shell/ash_test/ash-redir/redir9.tests
diff --git a/shell/ash_test/ash-vars/var_bash3.right b/shell/ash_test/ash-vars/var_bash3.right
index f7f1479..a97c850 100644
--- a/shell/ash_test/ash-vars/var_bash3.right
+++ b/shell/ash_test/ash-vars/var_bash3.right
@@ -1,20 +1,20 @@
-a041#c
-a041#c
-a\041#c
-a\041#c
-a\041#c
-a\041#c
-a\041#c
-a\041#c
-a\041#c
-a\c
-a\c
-a\c
-a\\c
-a\\c
-a\\c
-a\tc
-a\tc
-a\tc
-atc
-a\tc
+1 a041#c
+2 a041#c
+3 a\041#c
+4 a\041#c
+5 a\041#c
+6 a\041#c
+7 a\041#c
+8 a\041#c
+9 a\041#c
+10 a\c
+11 a\c
+12 a\c
+13 a\\c
+14 a\\c
+15 a\\c
+16 a\tc
+17 a\tc
+18 a\tc
+19 atc
+20 a\tc
diff --git a/shell/ash_test/ash-vars/var_bash3.tests b/shell/ash_test/ash-vars/var_bash3.tests
index b905027..eca3318 100755
--- a/shell/ash_test/ash-vars/var_bash3.tests
+++ b/shell/ash_test/ash-vars/var_bash3.tests
@@ -1,41 +1,48 @@
a='abc'
r=${a//b/\041#}
-echo $r
-echo ${a//b/\041#}
-echo "${a//b/\041#}"
+echo 1 $r
+echo 2 ${a//b/\041#}
+echo 3 "${a//b/\041#}"
+# --- var_bash3.xx
+# +++ var_bash3.right
+# -1 a\041#c
+# +1 a041#c
+# 2 a041#c
+# -3 a041#c
+# +3 a\041#c
a='abc'
r=${a//b/\\041#}
-echo $r
-echo ${a//b/\\041#}
-echo "${a//b/\\041#}"
+echo 4 $r
+echo 5 ${a//b/\\041#}
+echo 6 "${a//b/\\041#}"
a='abc'
b='\041#'
r=${a//b/$b}
-echo $r
-echo ${a//b/$b}
-echo "${a//b/$b}"
+echo 7 $r
+echo 8 ${a//b/$b}
+echo 9 "${a//b/$b}"
a='abc'
b='\'
r="${a//b/$b}"
-echo $r
-echo ${a//b/$b}
-echo "${a//b/$b}"
+echo 10 $r
+echo 11 ${a//b/$b}
+echo 12 "${a//b/$b}"
a='abc'
b='\\'
r="${a//b/$b}"
-echo $r
-echo ${a//b/$b}
-echo "${a//b/$b}"
+echo 13 $r
+echo 14 ${a//b/$b}
+echo 15 "${a//b/$b}"
a='abc'
b='\t'
r="${a//b/$b}"
-echo $r
-echo ${a//b/$b}
-echo "${a//b/$b}"
-echo ${a//b/\t}
-echo "${a//b/\t}"
+echo 16 $r
+echo 17 ${a//b/$b}
+echo 18 "${a//b/$b}"
+echo 19 ${a//b/\t}
+echo 20 "${a//b/\t}"
diff --git a/shell/ash_test/ash-vars/var_bash4.right b/shell/ash_test/ash-vars/var_bash4.right
new file mode 100644
index 0000000..33a5112
--- /dev/null
+++ b/shell/ash_test/ash-vars/var_bash4.right
@@ -0,0 +1,2 @@
+a*b-backslashstar-
+Done: 0
diff --git a/shell/ash_test/ash-vars/var_bash4.tests b/shell/ash_test/ash-vars/var_bash4.tests
new file mode 100755
index 0000000..304b3d9
--- /dev/null
+++ b/shell/ash_test/ash-vars/var_bash4.tests
@@ -0,0 +1,3 @@
+FOO='a*b\*c'
+echo "${FOO//\\*/-backslashstar-}"
+echo Done: $?