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:
Denys Vlasenko 2018-01-09 17:01:00 +01:00
parent 4261341281
commit 740058b42b

View file

@ -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)