ash: fix var_bash5.tests - ${VAR/pattern/repl} construct
function old new delta subevalvar 1198 1279 +81 rmescapes 308 330 +22 preglob 8 10 +2 parsefname 152 154 +2 expandarg 973 975 +2 argstr 1144 1146 +2 mklocal 290 288 -2 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 6/1 up/down: 111/-2) Total: 109 bytes Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
parent
4261341281
commit
740058b42b
1 changed files with 72 additions and 25 deletions
97
shell/ash.c
97
shell/ash.c
|
@ -5811,7 +5811,6 @@ ash_arith(const char *s)
|
||||||
#define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
|
#define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
|
||||||
#define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */
|
#define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */
|
||||||
#define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */
|
#define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */
|
||||||
#define RMESCAPE_SLASH 0x20 /* Stop globbing after slash */
|
|
||||||
|
|
||||||
/* Add CTLESC when necessary. */
|
/* Add CTLESC when necessary. */
|
||||||
#define QUOTES_ESC (EXP_FULL | EXP_CASE | EXP_QPAT)
|
#define QUOTES_ESC (EXP_FULL | EXP_CASE | EXP_QPAT)
|
||||||
|
@ -5992,8 +5991,12 @@ esclen(const char *start, const char *p)
|
||||||
/*
|
/*
|
||||||
* Remove any CTLESC characters from a string.
|
* Remove any CTLESC characters from a string.
|
||||||
*/
|
*/
|
||||||
|
#if !BASH_PATTERN_SUBST
|
||||||
|
#define rmescapes(str, flag, slash_position) \
|
||||||
|
rmescapes(str, flag)
|
||||||
|
#endif
|
||||||
static char *
|
static char *
|
||||||
rmescapes(char *str, int flag)
|
rmescapes(char *str, int flag, int *slash_position)
|
||||||
{
|
{
|
||||||
static const char qchars[] ALIGN1 = {
|
static const char qchars[] ALIGN1 = {
|
||||||
IF_BASH_PATTERN_SUBST('/',) CTLESC, CTLQUOTEMARK, '\0' };
|
IF_BASH_PATTERN_SUBST('/',) CTLESC, CTLQUOTEMARK, '\0' };
|
||||||
|
@ -6002,9 +6005,8 @@ rmescapes(char *str, int flag)
|
||||||
unsigned inquotes;
|
unsigned inquotes;
|
||||||
unsigned protect_against_glob;
|
unsigned protect_against_glob;
|
||||||
unsigned globbing;
|
unsigned globbing;
|
||||||
IF_BASH_PATTERN_SUBST(unsigned slash = flag & RMESCAPE_SLASH;)
|
|
||||||
|
|
||||||
p = strpbrk(str, qchars IF_BASH_PATTERN_SUBST(+ !slash));
|
p = strpbrk(str, qchars IF_BASH_PATTERN_SUBST(+ !slash_position));
|
||||||
if (!p)
|
if (!p)
|
||||||
return str;
|
return str;
|
||||||
|
|
||||||
|
@ -6084,10 +6086,11 @@ rmescapes(char *str, int flag)
|
||||||
goto copy;
|
goto copy;
|
||||||
}
|
}
|
||||||
#if BASH_PATTERN_SUBST
|
#if BASH_PATTERN_SUBST
|
||||||
else if (*p == '/' && slash) {
|
else if (slash_position && p == str + *slash_position) {
|
||||||
/* stop handling globbing and mark location of slash */
|
/* stop handling globbing */
|
||||||
globbing = slash = 0;
|
globbing = 0;
|
||||||
*p = CTLESC;
|
*slash_position = q - r;
|
||||||
|
slash_position = NULL;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
protect_against_glob = globbing;
|
protect_against_glob = globbing;
|
||||||
|
@ -6111,7 +6114,7 @@ rmescapes(char *str, int flag)
|
||||||
static char *
|
static char *
|
||||||
preglob(const char *pattern, int flag)
|
preglob(const char *pattern, int flag)
|
||||||
{
|
{
|
||||||
return rmescapes((char *)pattern, flag | RMESCAPE_GLOB);
|
return rmescapes((char *)pattern, flag | RMESCAPE_GLOB, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -6454,7 +6457,7 @@ expari(int flag)
|
||||||
expdest = p;
|
expdest = p;
|
||||||
|
|
||||||
if (flag & QUOTES_ESC)
|
if (flag & QUOTES_ESC)
|
||||||
rmescapes(p + 1, 0);
|
rmescapes(p + 1, 0, NULL);
|
||||||
|
|
||||||
len = cvtnum(ash_arith(p + 1));
|
len = cvtnum(ash_arith(p + 1));
|
||||||
|
|
||||||
|
@ -6742,20 +6745,57 @@ subevalvar(char *p, char *varname, int strloc, int subtype,
|
||||||
char *rmesc, *rmescend;
|
char *rmesc, *rmescend;
|
||||||
char *str;
|
char *str;
|
||||||
int amount, resetloc;
|
int amount, resetloc;
|
||||||
|
int argstr_flags;
|
||||||
IF_BASH_PATTERN_SUBST(int workloc;)
|
IF_BASH_PATTERN_SUBST(int workloc;)
|
||||||
IF_BASH_PATTERN_SUBST(char *repl = NULL;)
|
IF_BASH_PATTERN_SUBST(int slash_pos;)
|
||||||
|
IF_BASH_PATTERN_SUBST(char *repl;)
|
||||||
int zero;
|
int zero;
|
||||||
char *(*scan)(char*, char*, char*, char*, int, int);
|
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)",
|
//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);
|
// p, varname, strloc, subtype, startloc, varflags, quotes);
|
||||||
|
|
||||||
argstr(p, EXP_TILDE | (subtype != VSASSIGN && subtype != VSQUESTION ?
|
#if BASH_PATTERN_SUBST
|
||||||
(flag & (EXP_QUOTED | EXP_QPAT) ? EXP_QPAT : EXP_CASE) : 0)
|
repl = NULL;
|
||||||
);
|
if (subtype == VSREPLACE || subtype == VSREPLACEALL) {
|
||||||
|
/* Find '/' and replace with NUL */
|
||||||
|
repl = p;
|
||||||
|
for (;;) {
|
||||||
|
/* Handle escaped slashes, e.g. "${v/\//_}" (they are CTLESC'ed by this point) */
|
||||||
|
if (*repl == '\0') {
|
||||||
|
repl = NULL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (*repl == '/') {
|
||||||
|
*repl = '\0';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if ((unsigned char)*repl == CTLESC
|
||||||
|
&& repl[1]
|
||||||
|
) {
|
||||||
|
repl++;
|
||||||
|
}
|
||||||
|
repl++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
argstr_flags = EXP_TILDE;
|
||||||
|
if (subtype != VSASSIGN && subtype != VSQUESTION)
|
||||||
|
argstr_flags |= (flag & (EXP_QUOTED | EXP_QPAT) ? EXP_QPAT : EXP_CASE);
|
||||||
|
argstr(p, argstr_flags);
|
||||||
|
#if BASH_PATTERN_SUBST
|
||||||
|
slash_pos = -1;
|
||||||
|
if (repl) {
|
||||||
|
slash_pos = expdest - ((char *)stackblock() + strloc);
|
||||||
|
STPUTC('/', expdest);
|
||||||
|
argstr(repl + 1, argstr_flags);
|
||||||
|
*repl = '/';
|
||||||
|
}
|
||||||
|
#endif
|
||||||
STPUTC('\0', expdest);
|
STPUTC('\0', expdest);
|
||||||
argbackq = saveargbackq;
|
argbackq = saveargbackq;
|
||||||
startp = (char *)stackblock() + startloc;
|
startp = (char *)stackblock() + startloc;
|
||||||
|
//bb_error_msg("str1:'%s'", (char *)stackblock() + strloc);
|
||||||
|
|
||||||
switch (subtype) {
|
switch (subtype) {
|
||||||
case VSASSIGN:
|
case VSASSIGN:
|
||||||
|
@ -6853,6 +6893,8 @@ subevalvar(char *p, char *varname, int strloc, int subtype,
|
||||||
resetloc = expdest - (char *)stackblock();
|
resetloc = expdest - (char *)stackblock();
|
||||||
|
|
||||||
#if BASH_PATTERN_SUBST
|
#if BASH_PATTERN_SUBST
|
||||||
|
repl = NULL;
|
||||||
|
|
||||||
/* We'll comeback here if we grow the stack while handling
|
/* We'll comeback here if we grow the stack while handling
|
||||||
* a VSREPLACE or VSREPLACEALL, since our pointers into the
|
* a VSREPLACE or VSREPLACEALL, since our pointers into the
|
||||||
* stack will need rebasing, and we'll need to remove our work
|
* stack will need rebasing, and we'll need to remove our work
|
||||||
|
@ -6867,8 +6909,10 @@ subevalvar(char *p, char *varname, int strloc, int subtype,
|
||||||
|
|
||||||
rmesc = startp;
|
rmesc = startp;
|
||||||
rmescend = (char *)stackblock() + strloc;
|
rmescend = (char *)stackblock() + strloc;
|
||||||
|
//bb_error_msg("str7:'%s'", rmescend);
|
||||||
if (quotes) {
|
if (quotes) {
|
||||||
rmesc = rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW);
|
//TODO: how to handle slash_pos here if string changes (shortens?)
|
||||||
|
rmesc = rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW, NULL);
|
||||||
if (rmesc != startp) {
|
if (rmesc != startp) {
|
||||||
rmescend = expdest;
|
rmescend = expdest;
|
||||||
startp = (char *)stackblock() + startloc;
|
startp = (char *)stackblock() + startloc;
|
||||||
|
@ -6881,12 +6925,13 @@ subevalvar(char *p, char *varname, int strloc, int subtype,
|
||||||
* The result is a_\_z_c (not a\_\_z_c)!
|
* The result is a_\_z_c (not a\_\_z_c)!
|
||||||
*
|
*
|
||||||
* The search pattern and replace string treat backslashes differently!
|
* The search pattern and replace string treat backslashes differently!
|
||||||
* RMESCAPE_SLASH causes preglob to work differently on the pattern
|
* "&slash_pos" causes rmescapes() to work differently on the pattern
|
||||||
* and string. It's only used on the first call.
|
* and string. It's only used on the first call.
|
||||||
*/
|
*/
|
||||||
preglob(str, IF_BASH_PATTERN_SUBST(
|
//bb_error_msg("str8:'%s' slash_pos:%d", str, slash_pos);
|
||||||
(subtype == VSREPLACE || subtype == VSREPLACEALL) && !repl ?
|
rmescapes(str, RMESCAPE_GLOB,
|
||||||
RMESCAPE_SLASH : ) 0);
|
repl ? NULL : (slash_pos < 0 ? NULL : &slash_pos)
|
||||||
|
);
|
||||||
|
|
||||||
#if BASH_PATTERN_SUBST
|
#if BASH_PATTERN_SUBST
|
||||||
workloc = expdest - (char *)stackblock();
|
workloc = expdest - (char *)stackblock();
|
||||||
|
@ -6895,11 +6940,13 @@ subevalvar(char *p, char *varname, int strloc, int subtype,
|
||||||
char *idx, *end;
|
char *idx, *end;
|
||||||
|
|
||||||
if (!repl) {
|
if (!repl) {
|
||||||
repl = strchr(str, CTLESC);
|
//bb_error_msg("str9:'%s' slash_pos:%d", str, slash_pos);
|
||||||
if (repl)
|
if (slash_pos >= 0) {
|
||||||
|
repl = str + slash_pos;
|
||||||
*repl++ = '\0';
|
*repl++ = '\0';
|
||||||
else
|
} else {
|
||||||
repl = nullstr;
|
repl = nullstr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
//bb_error_msg("str:'%s' repl:'%s'", str, repl);
|
//bb_error_msg("str:'%s' repl:'%s'", str, repl);
|
||||||
|
|
||||||
|
@ -7419,7 +7466,7 @@ expandmeta(struct strlist *str /*, int flag*/)
|
||||||
INT_ON;
|
INT_ON;
|
||||||
nometa:
|
nometa:
|
||||||
*exparg.lastp = str;
|
*exparg.lastp = str;
|
||||||
rmescapes(str->text, 0);
|
rmescapes(str->text, 0, NULL);
|
||||||
exparg.lastp = &str->next;
|
exparg.lastp = &str->next;
|
||||||
break;
|
break;
|
||||||
default: /* GLOB_NOSPACE */
|
default: /* GLOB_NOSPACE */
|
||||||
|
@ -7648,7 +7695,7 @@ expandmeta(struct strlist *str /*, int flag*/)
|
||||||
*/
|
*/
|
||||||
nometa:
|
nometa:
|
||||||
*exparg.lastp = str;
|
*exparg.lastp = str;
|
||||||
rmescapes(str->text, 0);
|
rmescapes(str->text, 0, NULL);
|
||||||
exparg.lastp = &str->next;
|
exparg.lastp = &str->next;
|
||||||
} else {
|
} else {
|
||||||
*exparg.lastp = NULL;
|
*exparg.lastp = NULL;
|
||||||
|
@ -11328,7 +11375,7 @@ parsefname(void)
|
||||||
if (quoteflag == 0)
|
if (quoteflag == 0)
|
||||||
n->type = NXHERE;
|
n->type = NXHERE;
|
||||||
TRACE(("Here document %d\n", n->type));
|
TRACE(("Here document %d\n", n->type));
|
||||||
rmescapes(wordtext, 0);
|
rmescapes(wordtext, 0, NULL);
|
||||||
here->eofmark = wordtext;
|
here->eofmark = wordtext;
|
||||||
here->next = NULL;
|
here->next = NULL;
|
||||||
if (heredoclist == NULL)
|
if (heredoclist == NULL)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue