From 4b49422a08b89bd01023e7b4fa73ab058ee66932 Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Sun, 28 Apr 2019 09:09:33 +0100 Subject: vi: fix changes to word at end of line. Closes 11796 As reported in bug 11796 BusyBox vi incorrectly handles changes to a word at the end of a line. If the following line starts with whitespace changing or deleting the last word of a line with the 'cw' or 'dw' commands causes the lines to be joined. This happens because the range for the change returned by find_range() covers all whitespace after the word, including newlines. The problem can be fixed by setting 'ml' to zero to indicate to yank_delete() that processing should stop at the end of the current line. However, this results in a new problem. 'dw' correctly deletes all whitespace following the word but so does 'cw', which should preserve the trailing whitespace. To fix this the code to omit whitespace from the change is modified to include all whitespace not just blanks. function old new delta do_cmd 5034 5069 +35 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 1/0 up/down: 35/0) Total: 35 bytes Reported-by: David Kelly Signed-off-by: Ron Yorston Signed-off-by: Denys Vlasenko --- editors/vi.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'editors/vi.c') diff --git a/editors/vi.c b/editors/vi.c index c4360f8d3..dfef42019 100644 --- a/editors/vi.c +++ b/editors/vi.c @@ -3770,11 +3770,10 @@ static void do_cmd(int c) if (c1 == 27) { // ESC- user changed mind and wants out c = c1 = 27; // Escape- do nothing } else if (strchr("wW", c1)) { + ml = 0; // multi-line ranges aren't allowed for words if (c == 'c') { // don't include trailing WS as part of word - while (isblank(*q)) { - if (q <= text || q[-1] == '\n') - break; + while (isspace(*q) && q > p) { q--; } } -- cgit v1.2.3-55-g6feb From 7b93e317c13053e40e76cc5c36404f92d05dd41c Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Sun, 28 Apr 2019 09:10:16 +0100 Subject: vi: enable 'dG' command. Closes 11801 The 'G' command was omitted from the list of commands that change or delete whole lines. Add it in the appropriate places so the 'dG', 'cG' and 'yG' commands work, including in cases where an explicit line number has been supplied. function old new delta find_range 534 596 +62 .rodata 175166 175167 +1 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 2/0 up/down: 63/0) Total: 63 bytes Reported-by: David Kelly Signed-off-by: Ron Yorston Signed-off-by: Denys Vlasenko --- editors/vi.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'editors/vi.c') diff --git a/editors/vi.c b/editors/vi.c index dfef42019..8af1ef76b 100644 --- a/editors/vi.c +++ b/editors/vi.c @@ -3001,11 +3001,14 @@ static void do_cmd(int c); static int find_range(char **start, char **stop, char c) { char *save_dot, *p, *q, *t; - int cnt, multiline = 0; + int cnt, multiline = 0, forward; save_dot = dot; p = q = dot; + // will a 'G' command move forwards or backwards? + forward = cmdcnt == 0 || cmdcnt > count_lines(text, dot); + if (strchr("cdy><", c)) { // these cmds operate on whole lines p = q = begin_line(p); @@ -3029,13 +3032,13 @@ static int find_range(char **start, char **stop, char c) if (dot > text && *dot == '\n') dot--; // stay off NL q = dot; - } else if (strchr("H-k{", c)) { + } else if (strchr("H-k{", c) || (c == 'G' && !forward)) { // these operate on multi-lines backwards q = end_line(dot); // find NL do_cmd(c); // execute movement cmd dot_begin(); p = dot; - } else if (strchr("L+j}\r\n", c)) { + } else if (strchr("L+j}\r\n", c) || (c == 'G' && forward)) { // these operate on multi-lines forwards p = begin_line(dot); do_cmd(c); // execute movement cmd @@ -3781,7 +3784,7 @@ static void do_cmd(int c) } else if (strchr("^0bBeEft%$ lh\b\177", c1)) { // partial line copy text into a register and delete dot = yank_delete(p, q, ml, yf, ALLOW_UNDO); // delete word - } else if (strchr("cdykjHL+-{}\r\n", c1)) { + } else if (strchr("cdykjGHL+-{}\r\n", c1)) { // whole line copy text into a register and delete dot = yank_delete(p, q, ml, yf, ALLOW_UNDO); // delete lines whole = 1; -- cgit v1.2.3-55-g6feb