[git commit] vi: fix "s /find/repl" with whitespace before /

Denys Vlasenko vda.linux at googlemail.com
Fri Feb 6 21:56:16 UTC 2026


commit: https://git.busybox.net/busybox/commit/?id=3620c4ee677224aed6d6fa02aa8d034b4495370e
branch: https://git.busybox.net/busybox/log/?h=master

function                                             old     new   delta
colon                                               3977    4005     +28

Signed-off-by: Denys Vlasenko <vda.linux at googlemail.com>
---
 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;


More information about the busybox-cvs mailing list