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>
This commit is contained in:
parent
e74d79866c
commit
b0fbe4b540
83
shell/ash.c
83
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)
|
||||
|
0
shell/ash_test/ash-redir/redir9.tests
Normal file → Executable file
0
shell/ash_test/ash-redir/redir9.tests
Normal file → Executable file
@ -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
|
||||
|
@ -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}"
|
||||
|
2
shell/ash_test/ash-vars/var_bash4.right
Normal file
2
shell/ash_test/ash-vars/var_bash4.right
Normal file
@ -0,0 +1,2 @@
|
||||
a*b-backslashstar-
|
||||
Done: 0
|
3
shell/ash_test/ash-vars/var_bash4.tests
Executable file
3
shell/ash_test/ash-vars/var_bash4.tests
Executable file
@ -0,0 +1,3 @@
|
||||
FOO='a*b\*c'
|
||||
echo "${FOO//\\*/-backslashstar-}"
|
||||
echo Done: $?
|
Loading…
Reference in New Issue
Block a user