summaryrefslogtreecommitdiff
path: root/shell/ash.c
diff options
context:
space:
mode:
authorDenys Vlasenko2021-10-09 03:32:20 +0200
committerDenys Vlasenko2021-10-09 03:33:22 +0200
commit5aaeb550b76f063ffddef8587d9d91f7fddc4406 (patch)
treec643b6ceba297c4951c582bc30e7e5aa5aecbf4c /shell/ash.c
parent21e8dbfd9d11a461ed7f91b495fa39d8a9131b28 (diff)
downloadbusybox-5aaeb550b76f063ffddef8587d9d91f7fddc4406.zip
busybox-5aaeb550b76f063ffddef8587d9d91f7fddc4406.tar.gz
ash: speed up ${x//\*/|} too, make it independent of ASH_OPTIMIZE_FOR_SIZE
function old new delta subevalvar 1503 1545 +42 Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
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 e8ec0b1..1999751 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -7251,7 +7251,7 @@ subevalvar(char *start, char *str, int strloc,
#if BASH_PATTERN_SUBST
workloc = expdest - (char *)stackblock();
if (subtype == VSREPLACE || subtype == VSREPLACEALL) {
- size_t no_meta_len;
+ size_t no_meta_len, first_escaped;
int len;
char *idx, *end;
@@ -7269,28 +7269,34 @@ subevalvar(char *start, char *str, int strloc,
if (str[0] == '\0')
goto out1;
- no_meta_len = (ENABLE_ASH_OPTIMIZE_FOR_SIZE || strpbrk(str, "*?[\\")) ? 0 : strlen(str);
+ first_escaped = (str[0] == '\\' && str[1]);
+ /* "first_escaped" trick allows to treat e.g. "\*no_glob_chars"
+ * as literal too (as it is semi-common, and easy to accomodate
+ * by just using str + 1).
+ */
+ no_meta_len = strpbrk(str + first_escaped * 2, "*?[\\") ? 0 : strlen(str);
len = 0;
idx = startp;
end = str - 1;
while (idx <= end) {
try_to_match:
if (no_meta_len == 0) {
- /* pattern has meta chars, have to glob; or ENABLE_ASH_OPTIMIZE_FOR_SIZE */
+ /* pattern has meta chars, have to glob */
loc = scanright(idx, rmesc, rmescend, str, quotes, /*match_at_start:*/ 1);
} else {
/* Testcase for very slow replace (performs about 22k replaces):
* 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$x;echo ${#x}
* echo "${x//:/|}"
+ * To test "first_escaped" logic, replace : with *.
*/
- if (strncmp(rmesc, str, no_meta_len) != 0)
+ if (strncmp(rmesc, str + first_escaped, no_meta_len - first_escaped) != 0)
goto no_match;
loc = idx;
if (!quotes) {
- loc += no_meta_len;
+ loc += no_meta_len - first_escaped;
} else {
- size_t n = no_meta_len;
+ size_t n = no_meta_len - first_escaped;
do {
if ((unsigned char)*loc == CTLESC)
loc++;