aboutsummaryrefslogtreecommitdiff
path: root/shell
diff options
context:
space:
mode:
Diffstat (limited to 'shell')
-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)
5525#define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */ 5525#define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
5526#define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */ 5526#define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */
5527#define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */ 5527#define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */
5528#define RMESCAPE_SLASH 0x20 /* Stop globbing after slash */
5528 5529
5529/* Add CTLESC when necessary. */ 5530/* Add CTLESC when necessary. */
5530#define QUOTES_ESC (EXP_FULL | EXP_CASE | EXP_QPAT | EXP_REDIR) 5531#define QUOTES_ESC (EXP_FULL | EXP_CASE | EXP_QPAT | EXP_REDIR)
@@ -5594,14 +5595,16 @@ esclen(const char *start, const char *p)
5594static char * 5595static char *
5595rmescapes(char *str, int flag) 5596rmescapes(char *str, int flag)
5596{ 5597{
5597 static const char qchars[] ALIGN1 = { CTLESC, CTLQUOTEMARK, '\0' }; 5598 static const char qchars[] ALIGN1 = {
5599 IF_ASH_BASH_COMPAT('/',) CTLESC, CTLQUOTEMARK, '\0' };
5598 5600
5599 char *p, *q, *r; 5601 char *p, *q, *r;
5600 unsigned inquotes; 5602 unsigned inquotes;
5601 unsigned protect_against_glob; 5603 unsigned protect_against_glob;
5602 unsigned globbing; 5604 unsigned globbing;
5605 IF_ASH_BASH_COMPAT(unsigned slash = flag & RMESCAPE_SLASH;)
5603 5606
5604 p = strpbrk(str, qchars); 5607 p = strpbrk(str, qchars IF_ASH_BASH_COMPAT(+ !slash));
5605 if (!p) 5608 if (!p)
5606 return str; 5609 return str;
5607 5610
@@ -5650,6 +5653,13 @@ rmescapes(char *str, int flag)
5650 protect_against_glob = 0; 5653 protect_against_glob = 0;
5651 goto copy; 5654 goto copy;
5652 } 5655 }
5656#if ENABLE_ASH_BASH_COMPAT
5657 else if (*p == '/' && slash) {
5658 /* stop handling globbing and mark location of slash */
5659 globbing = slash = 0;
5660 *p = CTLESC;
5661 }
5662#endif
5653 protect_against_glob = globbing; 5663 protect_against_glob = globbing;
5654 copy: 5664 copy:
5655 *q++ = *p++; 5665 *q++ = *p++;
@@ -6274,50 +6284,6 @@ varunset(const char *end, const char *var, const char *umsg, int varflags)
6274 ash_msg_and_raise_error("%.*s: %s%s", (int)(end - var - 1), var, msg, tail); 6284 ash_msg_and_raise_error("%.*s: %s%s", (int)(end - var - 1), var, msg, tail);
6275} 6285}
6276 6286
6277#if ENABLE_ASH_BASH_COMPAT
6278static char *
6279parse_sub_pattern(char *arg, int quoted)
6280{
6281 char *idx, *repl = NULL;
6282 unsigned char c;
6283
6284 //char *org_arg = arg;
6285 //bb_error_msg("arg:'%s' quoted:%x", arg, quoted);
6286 idx = arg;
6287 while (1) {
6288 c = *arg;
6289 if (!c)
6290 break;
6291 if (c == '/') {
6292 /* Only the first '/' seen is our separator */
6293 if (!repl) {
6294 repl = idx + 1;
6295 c = '\0';
6296 }
6297 }
6298 *idx++ = c;
6299 arg++;
6300 /*
6301 * Example: v='a\bc'; echo ${v/\\b/_\\_\z_}
6302 * The result is a_\_z_c (not a\_\_z_c)!
6303 *
6304 * Enable debug prints in this function and you'll see:
6305 * ash: arg:'\\b/_\\_z_' varflags:d
6306 * ash: pattern:'\\b' repl:'_\_z_'
6307 * That is, \\b is interpreted as \\b, but \\_ as \_!
6308 * IOW: search pattern and replace string treat backslashes
6309 * differently! That is the reason why we check repl below:
6310 */
6311 if (c == '\\' && *arg == '\\' && repl && !quoted)
6312 arg++; /* skip both '\', not just first one */
6313 }
6314 *idx = c; /* NUL */
6315 //bb_error_msg("pattern:'%s' repl:'%s'", org_arg, repl);
6316
6317 return repl;
6318}
6319#endif /* ENABLE_ASH_BASH_COMPAT */
6320
6321static const char * 6287static const char *
6322subevalvar(char *p, char *varname, int strloc, int subtype, 6288subevalvar(char *p, char *varname, int strloc, int subtype,
6323 int startloc, int varflags, int flag, struct strlist *var_str_list) 6289 int startloc, int varflags, int flag, struct strlist *var_str_list)
@@ -6328,7 +6294,7 @@ subevalvar(char *p, char *varname, int strloc, int subtype,
6328 char *loc; 6294 char *loc;
6329 char *rmesc, *rmescend; 6295 char *rmesc, *rmescend;
6330 char *str; 6296 char *str;
6331 IF_ASH_BASH_COMPAT(const char *repl = NULL;) 6297 IF_ASH_BASH_COMPAT(char *repl = NULL;)
6332 IF_ASH_BASH_COMPAT(int pos, len, orig_len;) 6298 IF_ASH_BASH_COMPAT(int pos, len, orig_len;)
6333 int saveherefd = herefd; 6299 int saveherefd = herefd;
6334 int amount, resetloc; 6300 int amount, resetloc;
@@ -6453,7 +6419,17 @@ subevalvar(char *p, char *varname, int strloc, int subtype,
6453 } 6419 }
6454 rmescend--; 6420 rmescend--;
6455 str = (char *)stackblock() + strloc; 6421 str = (char *)stackblock() + strloc;
6456 preglob(str, 0); 6422 /*
6423 * Example: v='a\bc'; echo ${v/\\b/_\\_\z_}
6424 * The result is a_\_z_c (not a\_\_z_c)!
6425 *
6426 * The search pattern and replace string treat backslashes differently!
6427 * RMESCAPE_SLASH causes preglob to work differently on the pattern
6428 * and string. It's only used on the first call.
6429 */
6430 preglob(str, IF_ASH_BASH_COMPAT(
6431 (subtype == VSREPLACE || subtype == VSREPLACEALL) && !repl ?
6432 RMESCAPE_SLASH :) 0);
6457 6433
6458#if ENABLE_ASH_BASH_COMPAT 6434#if ENABLE_ASH_BASH_COMPAT
6459 workloc = expdest - (char *)stackblock(); 6435 workloc = expdest - (char *)stackblock();
@@ -6461,11 +6437,12 @@ subevalvar(char *p, char *varname, int strloc, int subtype,
6461 char *idx, *end; 6437 char *idx, *end;
6462 6438
6463 if (!repl) { 6439 if (!repl) {
6464 repl = parse_sub_pattern(str, flag & EXP_QUOTED); 6440 if ((repl=strchr(str, CTLESC)))
6465 //bb_error_msg("repl:'%s'", repl); 6441 *repl++ = '\0';
6466 if (!repl) 6442 else
6467 repl = nullstr; 6443 repl = nullstr;
6468 } 6444 }
6445 //bb_error_msg("str:'%s' repl:'%s'", str, repl);
6469 6446
6470 /* If there's no pattern to match, return the expansion unmolested */ 6447 /* If there's no pattern to match, return the expansion unmolested */
6471 if (str[0] == '\0') 6448 if (str[0] == '\0')