diff options
Diffstat (limited to 'shell')
-rw-r--r-- | shell/ash.c | 79 |
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) | |||
5594 | static char * | 5595 | static char * |
5595 | rmescapes(char *str, int flag) | 5596 | rmescapes(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 | ||
6278 | static char * | ||
6279 | parse_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 | |||
6321 | static const char * | 6287 | static const char * |
6322 | subevalvar(char *p, char *varname, int strloc, int subtype, | 6288 | subevalvar(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') |