aboutsummaryrefslogtreecommitdiff
path: root/shell/ash.c
diff options
context:
space:
mode:
Diffstat (limited to 'shell/ash.c')
-rw-r--r--shell/ash.c18
1 files changed, 12 insertions, 6 deletions
diff --git a/shell/ash.c b/shell/ash.c
index e8ec0b1a6..199975191 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -7251,7 +7251,7 @@ subevalvar(char *start, char *str, int strloc,
7251#if BASH_PATTERN_SUBST 7251#if BASH_PATTERN_SUBST
7252 workloc = expdest - (char *)stackblock(); 7252 workloc = expdest - (char *)stackblock();
7253 if (subtype == VSREPLACE || subtype == VSREPLACEALL) { 7253 if (subtype == VSREPLACE || subtype == VSREPLACEALL) {
7254 size_t no_meta_len; 7254 size_t no_meta_len, first_escaped;
7255 int len; 7255 int len;
7256 char *idx, *end; 7256 char *idx, *end;
7257 7257
@@ -7269,28 +7269,34 @@ subevalvar(char *start, char *str, int strloc,
7269 if (str[0] == '\0') 7269 if (str[0] == '\0')
7270 goto out1; 7270 goto out1;
7271 7271
7272 no_meta_len = (ENABLE_ASH_OPTIMIZE_FOR_SIZE || strpbrk(str, "*?[\\")) ? 0 : strlen(str); 7272 first_escaped = (str[0] == '\\' && str[1]);
7273 /* "first_escaped" trick allows to treat e.g. "\*no_glob_chars"
7274 * as literal too (as it is semi-common, and easy to accomodate
7275 * by just using str + 1).
7276 */
7277 no_meta_len = strpbrk(str + first_escaped * 2, "*?[\\") ? 0 : strlen(str);
7273 len = 0; 7278 len = 0;
7274 idx = startp; 7279 idx = startp;
7275 end = str - 1; 7280 end = str - 1;
7276 while (idx <= end) { 7281 while (idx <= end) {
7277 try_to_match: 7282 try_to_match:
7278 if (no_meta_len == 0) { 7283 if (no_meta_len == 0) {
7279 /* pattern has meta chars, have to glob; or ENABLE_ASH_OPTIMIZE_FOR_SIZE */ 7284 /* pattern has meta chars, have to glob */
7280 loc = scanright(idx, rmesc, rmescend, str, quotes, /*match_at_start:*/ 1); 7285 loc = scanright(idx, rmesc, rmescend, str, quotes, /*match_at_start:*/ 1);
7281 } else { 7286 } else {
7282 /* Testcase for very slow replace (performs about 22k replaces): 7287 /* Testcase for very slow replace (performs about 22k replaces):
7283 * x=:::::::::::::::::::::: 7288 * x=::::::::::::::::::::::
7284 * x=$x$x;x=$x$x;x=$x$x;x=$x$x;x=$x$x;x=$x$x;x=$x$x;x=$x$x;x=$x$x;x=$x$x;echo ${#x} 7289 * x=$x$x;x=$x$x;x=$x$x;x=$x$x;x=$x$x;x=$x$x;x=$x$x;x=$x$x;x=$x$x;x=$x$x;echo ${#x}
7285 * echo "${x//:/|}" 7290 * echo "${x//:/|}"
7291 * To test "first_escaped" logic, replace : with *.
7286 */ 7292 */
7287 if (strncmp(rmesc, str, no_meta_len) != 0) 7293 if (strncmp(rmesc, str + first_escaped, no_meta_len - first_escaped) != 0)
7288 goto no_match; 7294 goto no_match;
7289 loc = idx; 7295 loc = idx;
7290 if (!quotes) { 7296 if (!quotes) {
7291 loc += no_meta_len; 7297 loc += no_meta_len - first_escaped;
7292 } else { 7298 } else {
7293 size_t n = no_meta_len; 7299 size_t n = no_meta_len - first_escaped;
7294 do { 7300 do {
7295 if ((unsigned char)*loc == CTLESC) 7301 if ((unsigned char)*loc == CTLESC)
7296 loc++; 7302 loc++;