[PATCH 06/11] vi: allow the '.' command to have a repetition count

Ron Yorston rmy at pobox.com
Tue Apr 6 12:42:40 UTC 2021


The '.' command repeats the last text change.  When it has a
repetition count replay the change the number of times requested.
Update the stored count if it changes.  For example,

   3dw     deletes 3 words
   .       deletes another 3 words
   2.      deletes 2 words and changes the stored count
   .       deletes 2 words

function                                             old     new   delta
get_one_char                                         115     142     +27
do_cmd                                              4767    4786     +19
edit_file                                            887     836     -51
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 2/1 up/down: 46/-51)             Total: -5 bytes

Signed-off-by: Ron Yorston <rmy at pobox.com>
---
 editors/vi.c | 22 +++++++++++++++-------
 1 file changed, 15 insertions(+), 7 deletions(-)

diff --git a/editors/vi.c b/editors/vi.c
index 270a35840..e63b7ca7f 100644
--- a/editors/vi.c
+++ b/editors/vi.c
@@ -330,6 +330,8 @@ struct globals {
 #if ENABLE_FEATURE_VI_DOT_CMD
 	smallint adding2q;	 // are we currently adding user input to q
 	int lmc_len;             // length of last_modifying_cmd
+	int dotcnt;              // number of times to repeat '.' command
+	int ioqcnt;              // working copy of repeat count
 	char *ioq, *ioq_start;   // pointer to string for get_one_char to "read"
 #endif
 #if ENABLE_FEATURE_VI_SEARCH
@@ -451,6 +453,8 @@ struct globals {
 #endif
 #define adding2q                (G.adding2q           )
 #define lmc_len                 (G.lmc_len            )
+#define dotcnt                  (G.dotcnt             )
+#define ioqcnt                  (G.ioqcnt             )
 #define ioq                     (G.ioq                )
 #define ioq_start               (G.ioq_start          )
 #define last_search_pattern     (G.last_search_pattern)
@@ -1075,10 +1079,15 @@ static int get_one_char(void)
 		if (ioq_start != NULL) {
 			// there is a queue to get chars from.
 			// careful with correct sign expansion!
+ redot:
 			c = (unsigned char)*ioq++;
 			if (c != '\0')
 				return c;
 			// the end of the q
+			if (--ioqcnt > 0) {
+				ioq = ioq_start;
+				goto redot;
+			}
 			free(ioq_start);
 			ioq_start = NULL;
 			// read from STDIN:
@@ -1856,13 +1865,9 @@ static char *bound_dot(char *p) // make sure  text[0] <= P < "end"
 static void start_new_cmd_q(char c)
 {
 	// get buffer for new cmd
-	// if there is a current cmd count put it in the buffer first
-	if (cmdcnt > 0) {
-		lmc_len = sprintf(last_modifying_cmd, "%u%c", cmdcnt, c);
-	} else { // just save char c onto queue
-		last_modifying_cmd[0] = c;
-		lmc_len = 1;
-	}
+	dotcnt = cmdcnt;
+	last_modifying_cmd[0] = c;
+	lmc_len = 1;
 	adding2q = 1;
 }
 static void end_cmd_q(void)
@@ -3492,6 +3497,9 @@ static void do_cmd(int c)
 		// Stuff the last_modifying_cmd back into stdin
 		// and let it be re-executed.
 		if (lmc_len != 0) {
+			if (cmdcnt)	// update saved count if current count is non-zero
+				dotcnt = cmdcnt;
+			ioqcnt = dotcnt;
 			ioq = ioq_start = xstrndup(last_modifying_cmd, lmc_len);
 		}
 		break;
-- 
2.30.2



More information about the busybox mailing list