aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--shell/ash.c79
1 files changed, 28 insertions, 51 deletions
diff --git a/shell/ash.c b/shell/ash.c
index e7e70817f..282f761fc 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -5525,6 +5525,7 @@ ash_arith(const char *s)
#define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
#define RMESCAPE_GROW 0x8 /* Grow 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. */
#define QUOTES_ESC (EXP_FULL | EXP_CASE | EXP_QPAT | EXP_REDIR)
@@ -5594,14 +5595,16 @@ esclen(const char *start, const char *p)
static char *
rmescapes(char *str, int flag)
{
- static const char qchars[] ALIGN1 = { CTLESC, CTLQUOTEMARK, '\0' };
+ static const char qchars[] ALIGN1 = {
+ IF_ASH_BASH_COMPAT('/',) CTLESC, CTLQUOTEMARK, '\0' };
char *p, *q, *r;
unsigned inquotes;
unsigned protect_against_glob;
unsigned globbing;
+ IF_ASH_BASH_COMPAT(unsigned slash = flag & RMESCAPE_SLASH;)
- p = strpbrk(str, qchars);
+ p = strpbrk(str, qchars IF_ASH_BASH_COMPAT(+ !slash));
if (!p)
return str;
@@ -5650,6 +5653,13 @@ rmescapes(char *str, int flag)
protect_against_glob = 0;
goto copy;
}
+#if ENABLE_ASH_BASH_COMPAT
+ else if (*p == '/' && slash) {
+ /* stop handling globbing and mark location of slash */
+ globbing = slash = 0;
+ *p = CTLESC;
+ }
+#endif
protect_against_glob = globbing;
copy:
*q++ = *p++;
@@ -6274,50 +6284,6 @@ varunset(const char *end, const char *var, const char *umsg, int varflags)
ash_msg_and_raise_error("%.*s: %s%s", (int)(end - var - 1), var, msg, tail);
}
-#if ENABLE_ASH_BASH_COMPAT
-static char *
-parse_sub_pattern(char *arg, int quoted)
-{
- char *idx, *repl = NULL;
- unsigned char c;
-
- //char *org_arg = arg;
- //bb_error_msg("arg:'%s' quoted:%x", arg, quoted);
- idx = arg;
- while (1) {
- c = *arg;
- if (!c)
- break;
- if (c == '/') {
- /* Only the first '/' seen is our separator */
- if (!repl) {
- repl = idx + 1;
- c = '\0';
- }
- }
- *idx++ = c;
- arg++;
- /*
- * Example: v='a\bc'; echo ${v/\\b/_\\_\z_}
- * The result is a_\_z_c (not a\_\_z_c)!
- *
- * Enable debug prints in this function and you'll see:
- * ash: arg:'\\b/_\\_z_' varflags:d
- * ash: pattern:'\\b' repl:'_\_z_'
- * That is, \\b is interpreted as \\b, but \\_ as \_!
- * IOW: search pattern and replace string treat backslashes
- * differently! That is the reason why we check repl below:
- */
- if (c == '\\' && *arg == '\\' && repl && !quoted)
- arg++; /* skip both '\', not just first one */
- }
- *idx = c; /* NUL */
- //bb_error_msg("pattern:'%s' repl:'%s'", org_arg, repl);
-
- return repl;
-}
-#endif /* ENABLE_ASH_BASH_COMPAT */
-
static const char *
subevalvar(char *p, char *varname, int strloc, int subtype,
int startloc, int varflags, int flag, struct strlist *var_str_list)
@@ -6328,7 +6294,7 @@ subevalvar(char *p, char *varname, int strloc, int subtype,
char *loc;
char *rmesc, *rmescend;
char *str;
- IF_ASH_BASH_COMPAT(const char *repl = NULL;)
+ IF_ASH_BASH_COMPAT(char *repl = NULL;)
IF_ASH_BASH_COMPAT(int pos, len, orig_len;)
int saveherefd = herefd;
int amount, resetloc;
@@ -6453,7 +6419,17 @@ subevalvar(char *p, char *varname, int strloc, int subtype,
}
rmescend--;
str = (char *)stackblock() + strloc;
- preglob(str, 0);
+ /*
+ * Example: v='a\bc'; echo ${v/\\b/_\\_\z_}
+ * The result is a_\_z_c (not a\_\_z_c)!
+ *
+ * The search pattern and replace string treat backslashes differently!
+ * RMESCAPE_SLASH causes preglob to work differently on the pattern
+ * and string. It's only used on the first call.
+ */
+ preglob(str, IF_ASH_BASH_COMPAT(
+ (subtype == VSREPLACE || subtype == VSREPLACEALL) && !repl ?
+ RMESCAPE_SLASH :) 0);
#if ENABLE_ASH_BASH_COMPAT
workloc = expdest - (char *)stackblock();
@@ -6461,11 +6437,12 @@ subevalvar(char *p, char *varname, int strloc, int subtype,
char *idx, *end;
if (!repl) {
- repl = parse_sub_pattern(str, flag & EXP_QUOTED);
- //bb_error_msg("repl:'%s'", repl);
- if (!repl)
+ if ((repl=strchr(str, CTLESC)))
+ *repl++ = '\0';
+ else
repl = nullstr;
}
+ //bb_error_msg("str:'%s' repl:'%s'", str, repl);
/* If there's no pattern to match, return the expansion unmolested */
if (str[0] == '\0')