From 3620c4ee677224aed6d6fa02aa8d034b4495370e Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 6 Feb 2026 22:56:16 +0100 Subject: vi: fix "s /find/repl" with whitespace before / function old new delta colon 3977 4005 +28 Signed-off-by: Denys Vlasenko --- editors/vi.c | 23 ++++++++++++----------- include/libbb.h | 2 ++ 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/editors/vi.c b/editors/vi.c index 5bc180b5d..814a63a7b 100644 --- a/editors/vi.c +++ b/editors/vi.c @@ -2850,7 +2850,7 @@ static void colon(char *buf) not_implemented(p); #else char c, *q, *r; - char *fn, cmd[MAX_INPUT_LEN], *cmdend, *args; + char *fn, cmd[MAX_INPUT_LEN], *args; char *exp = NULL; char *useforce; int cmdlen; @@ -2890,15 +2890,14 @@ static void colon(char *buf) goto ret; // get the COMMAND into cmd[] - strcpy(cmd, buf); - cmdend = skip_non_whitespace(cmd); - // get any ARGuments - args = skip_whitespace(cmdend); -//NB: arguments can be accessed in buf[] as well, there is no need to copy them into cmd[]? - *cmdend = '\0'; + args = skip_non_whitespace(buf); + safe_strncpy(cmd, buf, (args - buf) + 1); +//NB: in "s/find/repl" and "!CMD" cases, we copy unnecessary data into buf[] useforce = last_char_is(cmd, '!'); if (useforce && useforce > cmd) *useforce = '\0'; // "CMD!" -> "CMD" (unless single "!") + // find ARGuments + args = skip_whitespace(args); // assume the command will want a range, certain commands // (read, substitute) need to adjust these assumptions @@ -3151,7 +3150,9 @@ static void colon(char *buf) editing = 0; } # if ENABLE_FEATURE_VI_SET - } else if (strncmp(cmd, "set", cmdlen) == 0) { // set or clear features + } else if (strncmp(cmd, "set", cmdlen) == 0 // set or clear features + IF_FEATURE_VI_SEARCH(&& cmdlen > 1) // (do not confuse with "s /find/repl/") + ) { # if ENABLE_FEATURE_VI_SETOPTS char *argp, *argn, oldch; # endif @@ -3210,12 +3211,12 @@ static void colon(char *buf) int undo = 0; # endif # endif - + buf = skip_whitespace(buf + 1); // spaces allowed: "s /find/repl/" // F points to the "find" pattern // R points to the "replace" pattern // replace the cmd line delimiters "/" with NULs - c = buf[1]; // what is the delimiter - F = buf + 2; // start of "find" + c = buf[0]; // what is the delimiter + F = buf + 1; // start of "find" R = strchr_backslash(F, c); // middle delimiter if (!R) goto colon_s_fail; diff --git a/include/libbb.h b/include/libbb.h index 6ce01ea94..baf0f29e5 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -939,6 +939,8 @@ int parse_pasv_epsv(char *buf) FAST_FUNC; /* 0 if argv[0] is NULL: */ unsigned string_array_len(char **argv) FAST_FUNC; void overlapping_strcpy(char *dst, const char *src) FAST_FUNC; +/* Like strncpy but make sure the resulting string is always 0 terminated: */ +/* writes SIZE chars, the [SIZE-1] char is always NUL (unless SIZE==0). */ char *safe_strncpy(char *dst, const char *src, size_t size) FAST_FUNC; char *strncpy_IFNAMSIZ(char *dst, const char *src) FAST_FUNC; unsigned count_strstr(const char *str, const char *sub) FAST_FUNC; -- cgit v1.2.3-55-g6feb