diff options
author | Ron Yorston <rmy@pobox.com> | 2021-07-10 11:00:04 +0100 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2021-07-13 14:42:20 +0200 |
commit | 2759201401cf87a9a8621edd9e5f44dfe838407c (patch) | |
tree | ca9db39df419b242c5ca1981c200dfcee6ec4e35 | |
parent | 95ac4a48f17c2fdd2a10524c0b399e3be72d8f42 (diff) | |
download | busybox-w32-2759201401cf87a9a8621edd9e5f44dfe838407c.tar.gz busybox-w32-2759201401cf87a9a8621edd9e5f44dfe838407c.tar.bz2 busybox-w32-2759201401cf87a9a8621edd9e5f44dfe838407c.zip |
vi: allow delimiter in ':s' to be escaped
When regular expressions are allowed in search commands it becomes
possible to escape the delimiter in search/replace commands. For
example, this command will replace '/abc' with '/abc/':
:s/\/abc/\/abc\//g
The code to split the command into 'find' and 'replace' strings
should allow for this possibility.
VI_REGEX_SEARCH isn't enabled by default. When it is:
function old new delta
strchr_backslash - 38 +38
colon 4378 4373 -5
------------------------------------------------------------------------------
(add/remove: 1/0 grow/shrink: 0/1 up/down: 38/-5) Total: 33 bytes
Signed-off-by: Ron Yorston <rmy@pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r-- | editors/vi.c | 19 |
1 files changed, 17 insertions, 2 deletions
diff --git a/editors/vi.c b/editors/vi.c index 070e0f55a..c6bb74cfb 100644 --- a/editors/vi.c +++ b/editors/vi.c | |||
@@ -2680,6 +2680,19 @@ static char *expand_args(char *args) | |||
2680 | #if ENABLE_FEATURE_VI_REGEX_SEARCH | 2680 | #if ENABLE_FEATURE_VI_REGEX_SEARCH |
2681 | # define MAX_SUBPATTERN 10 // subpatterns \0 .. \9 | 2681 | # define MAX_SUBPATTERN 10 // subpatterns \0 .. \9 |
2682 | 2682 | ||
2683 | // Like strchr() but skipping backslash-escaped characters | ||
2684 | static char *strchr_backslash(const char *s, int c) | ||
2685 | { | ||
2686 | for (; *s; ++s) { | ||
2687 | if (*s == c) { | ||
2688 | return (char *)s; | ||
2689 | } else if (*s == '\\' && *++s == '\0') { | ||
2690 | break; | ||
2691 | } | ||
2692 | } | ||
2693 | return NULL; | ||
2694 | } | ||
2695 | |||
2683 | // If the return value is not NULL the caller should free R | 2696 | // If the return value is not NULL the caller should free R |
2684 | static char *regex_search(char *q, regex_t *preg, const char *Rorig, | 2697 | static char *regex_search(char *q, regex_t *preg, const char *Rorig, |
2685 | size_t *len_F, size_t *len_R, char **R) | 2698 | size_t *len_F, size_t *len_R, char **R) |
@@ -2728,6 +2741,8 @@ static char *regex_search(char *q, regex_t *preg, const char *Rorig, | |||
2728 | 2741 | ||
2729 | return found; | 2742 | return found; |
2730 | } | 2743 | } |
2744 | #else /* !ENABLE_FEATURE_VI_REGEX_SEARCH */ | ||
2745 | # define strchr_backslash(s, c) strchr(s, c) | ||
2731 | #endif /* ENABLE_FEATURE_VI_REGEX_SEARCH */ | 2746 | #endif /* ENABLE_FEATURE_VI_REGEX_SEARCH */ |
2732 | 2747 | ||
2733 | // buf must be no longer than MAX_INPUT_LEN! | 2748 | // buf must be no longer than MAX_INPUT_LEN! |
@@ -3151,12 +3166,12 @@ static void colon(char *buf) | |||
3151 | // replace the cmd line delimiters "/" with NULs | 3166 | // replace the cmd line delimiters "/" with NULs |
3152 | c = buf[1]; // what is the delimiter | 3167 | c = buf[1]; // what is the delimiter |
3153 | F = buf + 2; // start of "find" | 3168 | F = buf + 2; // start of "find" |
3154 | R = strchr(F, c); // middle delimiter | 3169 | R = strchr_backslash(F, c); // middle delimiter |
3155 | if (!R) | 3170 | if (!R) |
3156 | goto colon_s_fail; | 3171 | goto colon_s_fail; |
3157 | len_F = R - F; | 3172 | len_F = R - F; |
3158 | *R++ = '\0'; // terminate "find" | 3173 | *R++ = '\0'; // terminate "find" |
3159 | flags = strchr(R, c); | 3174 | flags = strchr_backslash(R, c); |
3160 | if (flags) { | 3175 | if (flags) { |
3161 | *flags++ = '\0'; // terminate "replace" | 3176 | *flags++ = '\0'; // terminate "replace" |
3162 | gflag = *flags; | 3177 | gflag = *flags; |