[git commit] vi: rearrange functions, no logic changes

Denys Vlasenko vda.linux at googlemail.com
Mon Apr 1 12:16:53 UTC 2019


commit: https://git.busybox.net/busybox/commit/?id=de69775838eed0acd02f40de5e988d80611557ab
branch: https://git.busybox.net/busybox/commit/?id=refs/heads/master

Signed-off-by: Denys Vlasenko <vda.linux at googlemail.com>
---
 editors/vi.c | 1574 +++++++++++++++++++++++++++++-----------------------------
 1 file changed, 787 insertions(+), 787 deletions(-)

diff --git a/editors/vi.c b/editors/vi.c
index e960afc37..9db763ccd 100644
--- a/editors/vi.c
+++ b/editors/vi.c
@@ -693,424 +693,700 @@ static ALWAYS_INLINE int query_screen_dimensions(void)
 }
 #endif
 
-//----- The Colon commands -------------------------------------
-#if ENABLE_FEATURE_VI_COLON
-static char *get_one_address(char *p, int *addr)	// get colon addr, if present
+// sleep for 'h' 1/100 seconds, return 1/0 if stdin is (ready for read)/(not ready)
+static int mysleep(int hund)
 {
-	int st;
-	char *q;
-	IF_FEATURE_VI_YANKMARK(char c;)
-	IF_FEATURE_VI_SEARCH(char *pat;)
+	struct pollfd pfd[1];
 
-	*addr = -1;			// assume no addr
-	if (*p == '.') {	// the current line
-		p++;
-		q = begin_line(dot);
-		*addr = count_lines(text, q);
-	}
-#if ENABLE_FEATURE_VI_YANKMARK
-	else if (*p == '\'') {	// is this a mark addr
-		p++;
-		c = tolower(*p);
-		p++;
-		if (c >= 'a' && c <= 'z') {
-			// we have a mark
-			c = c - 'a';
-			q = mark[(unsigned char) c];
-			if (q != NULL) {	// is mark valid
-				*addr = count_lines(text, q);
-			}
-		}
-	}
-#endif
-#if ENABLE_FEATURE_VI_SEARCH
-	else if (*p == '/') {	// a search pattern
-		q = strchrnul(++p, '/');
-		pat = xstrndup(p, q - p); // save copy of pattern
-		p = q;
-		if (*p == '/')
-			p++;
-		q = char_search(dot, pat, (FORWARD << 1) | FULL);
-		if (q != NULL) {
-			*addr = count_lines(text, q);
-		}
-		free(pat);
-	}
-#endif
-	else if (*p == '$') {	// the last line in file
-		p++;
-		q = begin_line(end - 1);
-		*addr = count_lines(text, q);
-	} else if (isdigit(*p)) {	// specific line number
-		sscanf(p, "%d%n", addr, &st);
-		p += st;
-	} else {
-		// unrecognized address - assume -1
-		*addr = -1;
+	if (hund != 0)
+		fflush_all();
+
+	pfd[0].fd = STDIN_FILENO;
+	pfd[0].events = POLLIN;
+	return safe_poll(pfd, 1, hund*10) > 0;
+}
+
+//----- Set terminal attributes --------------------------------
+static void rawmode(void)
+{
+	// no TERMIOS_CLEAR_ISIG: leave ISIG on - allow signals
+	set_termios_to_raw(STDIN_FILENO, &term_orig, TERMIOS_RAW_CRNL);
+	erase_char = term_orig.c_cc[VERASE];
+}
+
+static void cookmode(void)
+{
+	fflush_all();
+	tcsetattr_stdin_TCSANOW(&term_orig);
+}
+
+//----- Terminal Drawing ---------------------------------------
+// The terminal is made up of 'rows' line of 'columns' columns.
+// classically this would be 24 x 80.
+//  screen coordinates
+//  0,0     ...     0,79
+//  1,0     ...     1,79
+//  .       ...     .
+//  .       ...     .
+//  22,0    ...     22,79
+//  23,0    ...     23,79   <- status line
+
+//----- Move the cursor to row x col (count from 0, not 1) -------
+static void place_cursor(int row, int col)
+{
+	char cm1[sizeof(ESC_SET_CURSOR_POS) + sizeof(int)*3 * 2];
+
+	if (row < 0) row = 0;
+	if (row >= rows) row = rows - 1;
+	if (col < 0) col = 0;
+	if (col >= columns) col = columns - 1;
+
+	sprintf(cm1, ESC_SET_CURSOR_POS, row + 1, col + 1);
+	write1(cm1);
+}
+
+//----- Erase from cursor to end of line -----------------------
+static void clear_to_eol(void)
+{
+	write1(ESC_CLEAR2EOL);
+}
+
+static void go_bottom_and_clear_to_eol(void)
+{
+	place_cursor(rows - 1, 0);
+	clear_to_eol();
+}
+
+//----- Start standout mode ------------------------------------
+static void standout_start(void)
+{
+	write1(ESC_BOLD_TEXT);
+}
+
+//----- End standout mode --------------------------------------
+static void standout_end(void)
+{
+	write1(ESC_NORM_TEXT);
+}
+
+//----- Text Movement Routines ---------------------------------
+static char *begin_line(char *p) // return pointer to first char cur line
+{
+	if (p > text) {
+		p = memrchr(text, '\n', p - text);
+		if (!p)
+			return text;
+		return p + 1;
 	}
 	return p;
 }
 
-static char *get_address(char *p, int *b, int *e)	// get two colon addrs, if present
+static char *end_line(char *p) // return pointer to NL of cur line
 {
-	//----- get the address' i.e., 1,3   'a,'b  -----
-	// get FIRST addr, if present
-	while (isblank(*p))
-		p++;				// skip over leading spaces
-	if (*p == '%') {			// alias for 1,$
-		p++;
-		*b = 1;
-		*e = count_lines(text, end-1);
-		goto ga0;
-	}
-	p = get_one_address(p, b);
-	while (isblank(*p))
-		p++;
-	if (*p == ',') {			// is there a address separator
-		p++;
-		while (isblank(*p))
-			p++;
-		// get SECOND addr, if present
-		p = get_one_address(p, e);
+	if (p < end - 1) {
+		p = memchr(p, '\n', end - p - 1);
+		if (!p)
+			return end - 1;
 	}
- ga0:
-	while (isblank(*p))
-		p++;				// skip over trailing spaces
 	return p;
 }
 
-#if ENABLE_FEATURE_VI_SET && ENABLE_FEATURE_VI_SETOPTS
-static void setops(const char *args, const char *opname, int flg_no,
-			const char *short_opname, int opt)
+static char *dollar_line(char *p) // return pointer to just before NL line
 {
-	const char *a = args + flg_no;
-	int l = strlen(opname) - 1; // opname have + ' '
+	p = end_line(p);
+	// Try to stay off of the Newline
+	if (*p == '\n' && (p - begin_line(p)) > 0)
+		p--;
+	return p;
+}
 
-	// maybe strncmp? we had tons of erroneous strncasecmp's...
-	if (strncasecmp(a, opname, l) == 0
-	 || strncasecmp(a, short_opname, 2) == 0
-	) {
-		if (flg_no)
-			vi_setops &= ~opt;
-		else
-			vi_setops |= opt;
-	}
+static char *prev_line(char *p) // return pointer first char prev line
+{
+	p = begin_line(p);	// goto beginning of cur line
+	if (p > text && p[-1] == '\n')
+		p--;			// step to prev line
+	p = begin_line(p);	// goto beginning of prev line
+	return p;
 }
-#endif
 
-#endif /* FEATURE_VI_COLON */
+static char *next_line(char *p) // return pointer first char next line
+{
+	p = end_line(p);
+	if (p < end - 1 && *p == '\n')
+		p++;			// step to next line
+	return p;
+}
 
-// buf must be no longer than MAX_INPUT_LEN!
-static void colon(char *buf)
+//----- Text Information Routines ------------------------------
+static char *end_screen(void)
 {
-#if !ENABLE_FEATURE_VI_COLON
-	// Simple ":cmd" handler with minimal set of commands
-	char *p = buf;
+	char *q;
 	int cnt;
 
-	if (*p == ':')
-		p++;
-	cnt = strlen(p);
-	if (cnt == 0)
-		return;
-	if (strncmp(p, "quit", cnt) == 0
-	 || strncmp(p, "q!", cnt) == 0
-	) {
-		if (modified_count && p[1] != '!') {
-			status_line_bold("No write since last change (:%s! overrides)", p);
-		} else {
-			editing = 0;
-		}
-		return;
+	// find new bottom line
+	q = screenbegin;
+	for (cnt = 0; cnt < rows - 2; cnt++)
+		q = next_line(q);
+	q = end_line(q);
+	return q;
+}
+
+// count line from start to stop
+static int count_lines(char *start, char *stop)
+{
+	char *q;
+	int cnt;
+
+	if (stop < start) { // start and stop are backwards- reverse them
+		q = start;
+		start = stop;
+		stop = q;
 	}
-	if (strncmp(p, "write", cnt) == 0
-	 || strncmp(p, "wq", cnt) == 0
-	 || strncmp(p, "wn", cnt) == 0
-	 || (p[0] == 'x' && !p[1])
-	) {
-		if (modified_count != 0 || p[0] != 'x') {
-			cnt = file_write(current_filename, text, end - 1);
-		}
-		if (cnt < 0) {
-			if (cnt == -1)
-				status_line_bold("Write error: "STRERROR_FMT STRERROR_ERRNO);
-		} else {
-			modified_count = 0;
-			last_modified_count = -1;
-			status_line("'%s' %dL, %dC",
-				current_filename,
-				count_lines(text, end - 1), cnt
-			);
-			if (p[0] == 'x'
-			 || p[1] == 'q' || p[1] == 'n'
-			 || p[1] == 'Q' || p[1] == 'N'
-			) {
-				editing = 0;
-			}
-		}
-		return;
-	}
-	if (strncmp(p, "file", cnt) == 0) {
-		last_status_cksum = 0;	// force status update
-		return;
-	}
-	if (sscanf(p, "%d", &cnt) > 0) {
-		dot = find_line(cnt);
-		dot_skip_over_ws();
-		return;
+	cnt = 0;
+	stop = end_line(stop);
+	while (start <= stop && start <= end - 1) {
+		start = end_line(start);
+		if (*start == '\n')
+			cnt++;
+		start++;
 	}
-	not_implemented(p);
-#else
+	return cnt;
+}
 
-	char c, *buf1, *q, *r;
-	char *fn, cmd[MAX_INPUT_LEN], args[MAX_INPUT_LEN];
-	int i, l, li, b, e;
-	int useforce;
-# if ENABLE_FEATURE_VI_SEARCH || ENABLE_FEATURE_ALLOW_EXEC
-	char *orig_buf;
-# endif
+static char *find_line(int li)	// find beginning of line #li
+{
+	char *q;
 
-	// :3154	// if (-e line 3154) goto it  else stay put
-	// :4,33w! foo	// write a portion of buffer to file "foo"
-	// :w		// write all of buffer to current file
-	// :q		// quit
-	// :q!		// quit- dont care about modified file
-	// :'a,'z!sort -u   // filter block through sort
-	// :'f		// goto mark "f"
-	// :'fl		// list literal the mark "f" line
-	// :.r bar	// read file "bar" into buffer before dot
-	// :/123/,/abc/d    // delete lines from "123" line to "abc" line
-	// :/xyz/	// goto the "xyz" line
-	// :s/find/replace/ // substitute pattern "find" with "replace"
-	// :!<cmd>	// run <cmd> then return
-	//
+	for (q = text; li > 1; li--) {
+		q = next_line(q);
+	}
+	return q;
+}
 
-	if (!buf[0])
-		goto ret;
-	if (*buf == ':')
-		buf++;			// move past the ':'
+static int next_tabstop(int col)
+{
+	return col + ((tabstop - 1) - (col % tabstop));
+}
 
-	li = i = 0;
-	b = e = -1;
-	q = text;			// assume 1,$ for the range
-	r = end - 1;
-	li = count_lines(text, end - 1);
-	fn = current_filename;
+//----- Erase the Screen[] memory ------------------------------
+static void screen_erase(void)
+{
+	memset(screen, ' ', screensize);	// clear new screen
+}
 
-	// look for optional address(es)  :.  :1  :1,9   :'q,'a   :%
-	buf = get_address(buf, &b, &e);
+//----- Synchronize the cursor to Dot --------------------------
+static NOINLINE void sync_cursor(char *d, int *row, int *col)
+{
+	char *beg_cur;	// begin and end of "d" line
+	char *tp;
+	int cnt, ro, co;
 
-# if ENABLE_FEATURE_VI_SEARCH || ENABLE_FEATURE_ALLOW_EXEC
-	// remember orig command line
-	orig_buf = buf;
-# endif
+	beg_cur = begin_line(d);	// first char of cur line
 
-	// get the COMMAND into cmd[]
-	buf1 = cmd;
-	while (*buf != '\0') {
-		if (isspace(*buf))
-			break;
-		*buf1++ = *buf++;
+	if (beg_cur < screenbegin) {
+		// "d" is before top line on screen
+		// how many lines do we have to move
+		cnt = count_lines(beg_cur, screenbegin);
+ sc1:
+		screenbegin = beg_cur;
+		if (cnt > (rows - 1) / 2) {
+			// we moved too many lines. put "dot" in middle of screen
+			for (cnt = 0; cnt < (rows - 1) / 2; cnt++) {
+				screenbegin = prev_line(screenbegin);
+			}
+		}
+	} else {
+		char *end_scr;	// begin and end of screen
+		end_scr = end_screen();	// last char of screen
+		if (beg_cur > end_scr) {
+			// "d" is after bottom line on screen
+			// how many lines do we have to move
+			cnt = count_lines(end_scr, beg_cur);
+			if (cnt > (rows - 1) / 2)
+				goto sc1;	// too many lines
+			for (ro = 0; ro < cnt - 1; ro++) {
+				// move screen begin the same amount
+				screenbegin = next_line(screenbegin);
+				// now, move the end of screen
+				end_scr = next_line(end_scr);
+				end_scr = end_line(end_scr);
+			}
+		}
 	}
-	*buf1 = '\0';
-	// get any ARGuments
-	while (isblank(*buf))
-		buf++;
-	strcpy(args, buf);
-	useforce = FALSE;
-	buf1 = last_char_is(cmd, '!');
-	if (buf1) {
-		useforce = TRUE;
-		*buf1 = '\0';   // get rid of !
+	// "d" is on screen- find out which row
+	tp = screenbegin;
+	for (ro = 0; ro < rows - 1; ro++) {	// drive "ro" to correct row
+		if (tp == beg_cur)
+			break;
+		tp = next_line(tp);
 	}
-	if (b >= 0) {
-		// if there is only one addr, then the addr
-		// is the line number of the single line the
-		// user wants. So, reset the end
-		// pointer to point at end of the "b" line
-		q = find_line(b);	// what line is #b
-		r = end_line(q);
-		li = 1;
+
+	// find out what col "d" is on
+	co = 0;
+	while (tp < d) { // drive "co" to correct column
+		if (*tp == '\n') //vda || *tp == '\0')
+			break;
+		if (*tp == '\t') {
+			// handle tabs like real vi
+			if (d == tp && cmd_mode) {
+				break;
+			}
+			co = next_tabstop(co);
+		} else if ((unsigned char)*tp < ' ' || *tp == 0x7f) {
+			co++; // display as ^X, use 2 columns
+		}
+		co++;
+		tp++;
 	}
-	if (e >= 0) {
-		// we were given two addrs.  change the
-		// end pointer to the addr given by user.
-		r = find_line(e);	// what line is #e
-		r = end_line(r);
-		li = e - b + 1;
+
+	// "co" is the column where "dot" is.
+	// The screen has "columns" columns.
+	// The currently displayed columns are  0+offset -- columns+ofset
+	// |-------------------------------------------------------------|
+	//               ^ ^                                ^
+	//        offset | |------- columns ----------------|
+	//
+	// If "co" is already in this range then we do not have to adjust offset
+	//      but, we do have to subtract the "offset" bias from "co".
+	// If "co" is outside this range then we have to change "offset".
+	// If the first char of a line is a tab the cursor will try to stay
+	//  in column 7, but we have to set offset to 0.
+
+	if (co < 0 + offset) {
+		offset = co;
 	}
-	// ------------ now look for the command ------------
-	i = strlen(cmd);
-	if (i == 0) {		// :123CR goto line #123
-		if (b >= 0) {
-			dot = find_line(b);	// what line is #b
-			dot_skip_over_ws();
-		}
+	if (co >= columns + offset) {
+		offset = co - columns + 1;
 	}
-# if ENABLE_FEATURE_ALLOW_EXEC
-	else if (cmd[0] == '!') {	// run a cmd
-		int retcode;
-		// :!ls   run the <cmd>
-		go_bottom_and_clear_to_eol();
-		cookmode();
-		retcode = system(orig_buf + 1);	// run the cmd
-		if (retcode)
-			printf("\nshell returned %i\n\n", retcode);
-		rawmode();
-		Hit_Return();			// let user see results
+	// if the first char of the line is a tab, and "dot" is sitting on it
+	//  force offset to 0.
+	if (d == beg_cur && *d == '\t') {
+		offset = 0;
 	}
-# endif
-	else if (cmd[0] == '=' && !cmd[1]) {	// where is the address
-		if (b < 0) {	// no addr given- use defaults
-			b = e = count_lines(text, dot);
-		}
-		status_line("%d", b);
-	} else if (strncmp(cmd, "delete", i) == 0) {	// delete lines
-		if (b < 0) {	// no addr given- use defaults
-			q = begin_line(dot);	// assume .,. for the range
-			r = end_line(dot);
-		}
-		dot = yank_delete(q, r, 1, YANKDEL, ALLOW_UNDO);	// save, then delete lines
-		dot_skip_over_ws();
-	} else if (strncmp(cmd, "edit", i) == 0) {	// Edit a file
-		int size;
+	co -= offset;
 
-		// don't edit, if the current file has been modified
-		if (modified_count && !useforce) {
-			status_line_bold("No write since last change (:%s! overrides)", cmd);
-			goto ret;
-		}
-		if (args[0]) {
-			// the user supplied a file name
-			fn = args;
-		} else if (current_filename && current_filename[0]) {
-			// no user supplied name- use the current filename
-			// fn = current_filename;  was set by default
-		} else {
-			// no user file name, no current name- punt
-			status_line_bold("No current filename");
-			goto ret;
-		}
+	*row = ro;
+	*col = co;
+}
 
-		size = init_text_buffer(fn);
+//----- The Colon commands -------------------------------------
+#if ENABLE_FEATURE_VI_COLON
+static char *get_one_address(char *p, int *addr)	// get colon addr, if present
+{
+	int st;
+	char *q;
+	IF_FEATURE_VI_YANKMARK(char c;)
+	IF_FEATURE_VI_SEARCH(char *pat;)
 
-# if ENABLE_FEATURE_VI_YANKMARK
-		if (Ureg >= 0 && Ureg < 28) {
-			free(reg[Ureg]);	//   free orig line reg- for 'U'
-			reg[Ureg] = NULL;
-		}
-		if (YDreg >= 0 && YDreg < 28) {
-			free(reg[YDreg]);	//   free default yank/delete register
-			reg[YDreg] = NULL;
-		}
-# endif
-		// how many lines in text[]?
-		li = count_lines(text, end - 1);
-		status_line("'%s'%s"
-			IF_FEATURE_VI_READONLY("%s")
-			" %dL, %dC",
-			current_filename,
-			(size < 0 ? " [New file]" : ""),
-			IF_FEATURE_VI_READONLY(
-				((readonly_mode) ? " [Readonly]" : ""),
-			)
-			li, (int)(end - text)
-		);
-	} else if (strncmp(cmd, "file", i) == 0) {	// what File is this
-		if (b != -1 || e != -1) {
-			status_line_bold("No address allowed on this command");
-			goto ret;
-		}
-		if (args[0]) {
-			// user wants a new filename
-			free(current_filename);
-			current_filename = xstrdup(args);
-		} else {
-			// user wants file status info
-			last_status_cksum = 0;	// force status update
+	*addr = -1;			// assume no addr
+	if (*p == '.') {	// the current line
+		p++;
+		q = begin_line(dot);
+		*addr = count_lines(text, q);
+	}
+#if ENABLE_FEATURE_VI_YANKMARK
+	else if (*p == '\'') {	// is this a mark addr
+		p++;
+		c = tolower(*p);
+		p++;
+		if (c >= 'a' && c <= 'z') {
+			// we have a mark
+			c = c - 'a';
+			q = mark[(unsigned char) c];
+			if (q != NULL) {	// is mark valid
+				*addr = count_lines(text, q);
+			}
 		}
-	} else if (strncmp(cmd, "features", i) == 0) {	// what features are available
-		// print out values of all features
-		go_bottom_and_clear_to_eol();
-		cookmode();
-		show_help();
-		rawmode();
-		Hit_Return();
-	} else if (strncmp(cmd, "list", i) == 0) {	// literal print line
-		if (b < 0) {	// no addr given- use defaults
-			q = begin_line(dot);	// assume .,. for the range
-			r = end_line(dot);
+	}
+#endif
+#if ENABLE_FEATURE_VI_SEARCH
+	else if (*p == '/') {	// a search pattern
+		q = strchrnul(++p, '/');
+		pat = xstrndup(p, q - p); // save copy of pattern
+		p = q;
+		if (*p == '/')
+			p++;
+		q = char_search(dot, pat, (FORWARD << 1) | FULL);
+		if (q != NULL) {
+			*addr = count_lines(text, q);
 		}
-		go_bottom_and_clear_to_eol();
-		puts("\r");
-		for (; q <= r; q++) {
-			int c_is_no_print;
+		free(pat);
+	}
+#endif
+	else if (*p == '$') {	// the last line in file
+		p++;
+		q = begin_line(end - 1);
+		*addr = count_lines(text, q);
+	} else if (isdigit(*p)) {	// specific line number
+		sscanf(p, "%d%n", addr, &st);
+		p += st;
+	} else {
+		// unrecognized address - assume -1
+		*addr = -1;
+	}
+	return p;
+}
 
-			c = *q;
-			c_is_no_print = (c & 0x80) && !Isprint(c);
-			if (c_is_no_print) {
-				c = '.';
-				standout_start();
-			}
-			if (c == '\n') {
-				write1("$\r");
-			} else if (c < ' ' || c == 127) {
-				bb_putchar('^');
-				if (c == 127)
-					c = '?';
-				else
-					c += '@';
-			}
-			bb_putchar(c);
-			if (c_is_no_print)
-				standout_end();
-		}
-		Hit_Return();
-	} else if (strncmp(cmd, "quit", i) == 0 // quit
-	        || strncmp(cmd, "next", i) == 0 // edit next file
-	        || strncmp(cmd, "prev", i) == 0 // edit previous file
+static char *get_address(char *p, int *b, int *e)	// get two colon addrs, if present
+{
+	//----- get the address' i.e., 1,3   'a,'b  -----
+	// get FIRST addr, if present
+	while (isblank(*p))
+		p++;				// skip over leading spaces
+	if (*p == '%') {			// alias for 1,$
+		p++;
+		*b = 1;
+		*e = count_lines(text, end-1);
+		goto ga0;
+	}
+	p = get_one_address(p, b);
+	while (isblank(*p))
+		p++;
+	if (*p == ',') {			// is there a address separator
+		p++;
+		while (isblank(*p))
+			p++;
+		// get SECOND addr, if present
+		p = get_one_address(p, e);
+	}
+ ga0:
+	while (isblank(*p))
+		p++;				// skip over trailing spaces
+	return p;
+}
+
+#if ENABLE_FEATURE_VI_SET && ENABLE_FEATURE_VI_SETOPTS
+static void setops(const char *args, const char *opname, int flg_no,
+			const char *short_opname, int opt)
+{
+	const char *a = args + flg_no;
+	int l = strlen(opname) - 1; // opname have + ' '
+
+	// maybe strncmp? we had tons of erroneous strncasecmp's...
+	if (strncasecmp(a, opname, l) == 0
+	 || strncasecmp(a, short_opname, 2) == 0
 	) {
-		int n;
-		if (useforce) {
-			if (*cmd == 'q') {
-				// force end of argv list
-				optind = save_argc;
-			}
+		if (flg_no)
+			vi_setops &= ~opt;
+		else
+			vi_setops |= opt;
+	}
+}
+#endif
+
+#endif /* FEATURE_VI_COLON */
+
+// buf must be no longer than MAX_INPUT_LEN!
+static void colon(char *buf)
+{
+#if !ENABLE_FEATURE_VI_COLON
+	// Simple ":cmd" handler with minimal set of commands
+	char *p = buf;
+	int cnt;
+
+	if (*p == ':')
+		p++;
+	cnt = strlen(p);
+	if (cnt == 0)
+		return;
+	if (strncmp(p, "quit", cnt) == 0
+	 || strncmp(p, "q!", cnt) == 0
+	) {
+		if (modified_count && p[1] != '!') {
+			status_line_bold("No write since last change (:%s! overrides)", p);
+		} else {
 			editing = 0;
-			goto ret;
-		}
-		// don't exit if the file been modified
-		if (modified_count) {
-			status_line_bold("No write since last change (:%s! overrides)", cmd);
-			goto ret;
-		}
-		// are there other file to edit
-		n = save_argc - optind - 1;
-		if (*cmd == 'q' && n > 0) {
-			status_line_bold("%d more file(s) to edit", n);
-			goto ret;
 		}
-		if (*cmd == 'n' && n <= 0) {
-			status_line_bold("No more files to edit");
-			goto ret;
+		return;
+	}
+	if (strncmp(p, "write", cnt) == 0
+	 || strncmp(p, "wq", cnt) == 0
+	 || strncmp(p, "wn", cnt) == 0
+	 || (p[0] == 'x' && !p[1])
+	) {
+		if (modified_count != 0 || p[0] != 'x') {
+			cnt = file_write(current_filename, text, end - 1);
 		}
-		if (*cmd == 'p') {
-			// are there previous files to edit
-			if (optind < 1) {
-				status_line_bold("No previous files to edit");
-				goto ret;
+		if (cnt < 0) {
+			if (cnt == -1)
+				status_line_bold("Write error: "STRERROR_FMT STRERROR_ERRNO);
+		} else {
+			modified_count = 0;
+			last_modified_count = -1;
+			status_line("'%s' %dL, %dC",
+				current_filename,
+				count_lines(text, end - 1), cnt
+			);
+			if (p[0] == 'x'
+			 || p[1] == 'q' || p[1] == 'n'
+			 || p[1] == 'Q' || p[1] == 'N'
+			) {
+				editing = 0;
 			}
-			optind -= 2;
 		}
-		editing = 0;
-	} else if (strncmp(cmd, "read", i) == 0) {	// read file into text[]
-		int size;
+		return;
+	}
+	if (strncmp(p, "file", cnt) == 0) {
+		last_status_cksum = 0;	// force status update
+		return;
+	}
+	if (sscanf(p, "%d", &cnt) > 0) {
+		dot = find_line(cnt);
+		dot_skip_over_ws();
+		return;
+	}
+	not_implemented(p);
+#else
 
-		fn = args;
-		if (!fn[0]) {
-			status_line_bold("No filename given");
-			goto ret;
-		}
+	char c, *buf1, *q, *r;
+	char *fn, cmd[MAX_INPUT_LEN], args[MAX_INPUT_LEN];
+	int i, l, li, b, e;
+	int useforce;
+# if ENABLE_FEATURE_VI_SEARCH || ENABLE_FEATURE_ALLOW_EXEC
+	char *orig_buf;
+# endif
+
+	// :3154	// if (-e line 3154) goto it  else stay put
+	// :4,33w! foo	// write a portion of buffer to file "foo"
+	// :w		// write all of buffer to current file
+	// :q		// quit
+	// :q!		// quit- dont care about modified file
+	// :'a,'z!sort -u   // filter block through sort
+	// :'f		// goto mark "f"
+	// :'fl		// list literal the mark "f" line
+	// :.r bar	// read file "bar" into buffer before dot
+	// :/123/,/abc/d    // delete lines from "123" line to "abc" line
+	// :/xyz/	// goto the "xyz" line
+	// :s/find/replace/ // substitute pattern "find" with "replace"
+	// :!<cmd>	// run <cmd> then return
+	//
+
+	if (!buf[0])
+		goto ret;
+	if (*buf == ':')
+		buf++;			// move past the ':'
+
+	li = i = 0;
+	b = e = -1;
+	q = text;			// assume 1,$ for the range
+	r = end - 1;
+	li = count_lines(text, end - 1);
+	fn = current_filename;
+
+	// look for optional address(es)  :.  :1  :1,9   :'q,'a   :%
+	buf = get_address(buf, &b, &e);
+
+# if ENABLE_FEATURE_VI_SEARCH || ENABLE_FEATURE_ALLOW_EXEC
+	// remember orig command line
+	orig_buf = buf;
+# endif
+
+	// get the COMMAND into cmd[]
+	buf1 = cmd;
+	while (*buf != '\0') {
+		if (isspace(*buf))
+			break;
+		*buf1++ = *buf++;
+	}
+	*buf1 = '\0';
+	// get any ARGuments
+	while (isblank(*buf))
+		buf++;
+	strcpy(args, buf);
+	useforce = FALSE;
+	buf1 = last_char_is(cmd, '!');
+	if (buf1) {
+		useforce = TRUE;
+		*buf1 = '\0';   // get rid of !
+	}
+	if (b >= 0) {
+		// if there is only one addr, then the addr
+		// is the line number of the single line the
+		// user wants. So, reset the end
+		// pointer to point at end of the "b" line
+		q = find_line(b);	// what line is #b
+		r = end_line(q);
+		li = 1;
+	}
+	if (e >= 0) {
+		// we were given two addrs.  change the
+		// end pointer to the addr given by user.
+		r = find_line(e);	// what line is #e
+		r = end_line(r);
+		li = e - b + 1;
+	}
+	// ------------ now look for the command ------------
+	i = strlen(cmd);
+	if (i == 0) {		// :123CR goto line #123
+		if (b >= 0) {
+			dot = find_line(b);	// what line is #b
+			dot_skip_over_ws();
+		}
+	}
+# if ENABLE_FEATURE_ALLOW_EXEC
+	else if (cmd[0] == '!') {	// run a cmd
+		int retcode;
+		// :!ls   run the <cmd>
+		go_bottom_and_clear_to_eol();
+		cookmode();
+		retcode = system(orig_buf + 1);	// run the cmd
+		if (retcode)
+			printf("\nshell returned %i\n\n", retcode);
+		rawmode();
+		Hit_Return();			// let user see results
+	}
+# endif
+	else if (cmd[0] == '=' && !cmd[1]) {	// where is the address
+		if (b < 0) {	// no addr given- use defaults
+			b = e = count_lines(text, dot);
+		}
+		status_line("%d", b);
+	} else if (strncmp(cmd, "delete", i) == 0) {	// delete lines
+		if (b < 0) {	// no addr given- use defaults
+			q = begin_line(dot);	// assume .,. for the range
+			r = end_line(dot);
+		}
+		dot = yank_delete(q, r, 1, YANKDEL, ALLOW_UNDO);	// save, then delete lines
+		dot_skip_over_ws();
+	} else if (strncmp(cmd, "edit", i) == 0) {	// Edit a file
+		int size;
+
+		// don't edit, if the current file has been modified
+		if (modified_count && !useforce) {
+			status_line_bold("No write since last change (:%s! overrides)", cmd);
+			goto ret;
+		}
+		if (args[0]) {
+			// the user supplied a file name
+			fn = args;
+		} else if (current_filename && current_filename[0]) {
+			// no user supplied name- use the current filename
+			// fn = current_filename;  was set by default
+		} else {
+			// no user file name, no current name- punt
+			status_line_bold("No current filename");
+			goto ret;
+		}
+
+		size = init_text_buffer(fn);
+
+# if ENABLE_FEATURE_VI_YANKMARK
+		if (Ureg >= 0 && Ureg < 28) {
+			free(reg[Ureg]);	//   free orig line reg- for 'U'
+			reg[Ureg] = NULL;
+		}
+		if (YDreg >= 0 && YDreg < 28) {
+			free(reg[YDreg]);	//   free default yank/delete register
+			reg[YDreg] = NULL;
+		}
+# endif
+		// how many lines in text[]?
+		li = count_lines(text, end - 1);
+		status_line("'%s'%s"
+			IF_FEATURE_VI_READONLY("%s")
+			" %dL, %dC",
+			current_filename,
+			(size < 0 ? " [New file]" : ""),
+			IF_FEATURE_VI_READONLY(
+				((readonly_mode) ? " [Readonly]" : ""),
+			)
+			li, (int)(end - text)
+		);
+	} else if (strncmp(cmd, "file", i) == 0) {	// what File is this
+		if (b != -1 || e != -1) {
+			status_line_bold("No address allowed on this command");
+			goto ret;
+		}
+		if (args[0]) {
+			// user wants a new filename
+			free(current_filename);
+			current_filename = xstrdup(args);
+		} else {
+			// user wants file status info
+			last_status_cksum = 0;	// force status update
+		}
+	} else if (strncmp(cmd, "features", i) == 0) {	// what features are available
+		// print out values of all features
+		go_bottom_and_clear_to_eol();
+		cookmode();
+		show_help();
+		rawmode();
+		Hit_Return();
+	} else if (strncmp(cmd, "list", i) == 0) {	// literal print line
+		if (b < 0) {	// no addr given- use defaults
+			q = begin_line(dot);	// assume .,. for the range
+			r = end_line(dot);
+		}
+		go_bottom_and_clear_to_eol();
+		puts("\r");
+		for (; q <= r; q++) {
+			int c_is_no_print;
+
+			c = *q;
+			c_is_no_print = (c & 0x80) && !Isprint(c);
+			if (c_is_no_print) {
+				c = '.';
+				standout_start();
+			}
+			if (c == '\n') {
+				write1("$\r");
+			} else if (c < ' ' || c == 127) {
+				bb_putchar('^');
+				if (c == 127)
+					c = '?';
+				else
+					c += '@';
+			}
+			bb_putchar(c);
+			if (c_is_no_print)
+				standout_end();
+		}
+		Hit_Return();
+	} else if (strncmp(cmd, "quit", i) == 0 // quit
+	        || strncmp(cmd, "next", i) == 0 // edit next file
+	        || strncmp(cmd, "prev", i) == 0 // edit previous file
+	) {
+		int n;
+		if (useforce) {
+			if (*cmd == 'q') {
+				// force end of argv list
+				optind = save_argc;
+			}
+			editing = 0;
+			goto ret;
+		}
+		// don't exit if the file been modified
+		if (modified_count) {
+			status_line_bold("No write since last change (:%s! overrides)", cmd);
+			goto ret;
+		}
+		// are there other file to edit
+		n = save_argc - optind - 1;
+		if (*cmd == 'q' && n > 0) {
+			status_line_bold("%d more file(s) to edit", n);
+			goto ret;
+		}
+		if (*cmd == 'n' && n <= 0) {
+			status_line_bold("No more files to edit");
+			goto ret;
+		}
+		if (*cmd == 'p') {
+			// are there previous files to edit
+			if (optind < 1) {
+				status_line_bold("No previous files to edit");
+				goto ret;
+			}
+			optind -= 2;
+		}
+		editing = 0;
+	} else if (strncmp(cmd, "read", i) == 0) {	// read file into text[]
+		int size;
+
+		fn = args;
+		if (!fn[0]) {
+			status_line_bold("No filename given");
+			goto ret;
+		}
 		if (b < 0) {	// no addr given- use defaults
 			q = begin_line(dot);	// assume "dot"
 		}
@@ -1205,348 +1481,154 @@ static void colon(char *buf)
 		int dont_chain_first_item = ALLOW_UNDO;
 #  endif
 
-		// F points to the "find" pattern
-		// R points to the "replace" pattern
-		// replace the cmd line delimiters "/" with NULs
-		c = orig_buf[1];	// what is the delimiter
-		F = orig_buf + 2;	// start of "find"
-		R = strchr(F, c);	// middle delimiter
-		if (!R)
-			goto colon_s_fail;
-		len_F = R - F;
-		*R++ = '\0';	// terminate "find"
-		flags = strchr(R, c);
-		if (!flags)
-			goto colon_s_fail;
-		len_R = flags - R;
-		*flags++ = '\0';	// terminate "replace"
-		gflag = *flags;
-
-		q = begin_line(q);
-		if (b < 0) {	// maybe :s/foo/bar/
-			q = begin_line(dot);      // start with cur line
-			b = count_lines(text, q); // cur line number
-		}
-		if (e < 0)
-			e = b;		// maybe :.s/foo/bar/
-
-		for (i = b; i <= e; i++) {	// so, :20,23 s \0 find \0 replace \0
-			char *ls = q;		// orig line start
-			char *found;
- vc4:
-			found = char_search(q, F, (FORWARD << 1) | LIMITED);	// search cur line only for "find"
-			if (found) {
-				uintptr_t bias;
-				// we found the "find" pattern - delete it
-				// For undo support, the first item should not be chained
-				text_hole_delete(found, found + len_F - 1, dont_chain_first_item);
-#  if ENABLE_FEATURE_VI_UNDO
-				dont_chain_first_item = ALLOW_UNDO_CHAIN;
-#  endif
-				// insert the "replace" patern
-				bias = string_insert(found, R, ALLOW_UNDO_CHAIN);
-				found += bias;
-				ls += bias;
-				/*q += bias; - recalculated anyway */
-				// check for "global"  :s/foo/bar/g
-				if (gflag == 'g') {
-					if ((found + len_R) < end_line(ls)) {
-						q = found + len_R;
-						goto vc4;	// don't let q move past cur line
-					}
-				}
-			}
-			q = next_line(ls);
-		}
-# endif /* FEATURE_VI_SEARCH */
-	} else if (strncmp(cmd, "version", i) == 0) {  // show software version
-		status_line(BB_VER);
-	} else if (strncmp(cmd, "write", i) == 0  // write text to file
-	        || strncmp(cmd, "wq", i) == 0
-	        || strncmp(cmd, "wn", i) == 0
-	        || (cmd[0] == 'x' && !cmd[1])
-	) {
-		int size;
-		//int forced = FALSE;
-
-		// is there a file name to write to?
-		if (args[0]) {
-			fn = args;
-		}
-# if ENABLE_FEATURE_VI_READONLY
-		if (readonly_mode && !useforce) {
-			status_line_bold("'%s' is read only", fn);
-			goto ret;
-		}
-# endif
-		//if (useforce) {
-			// if "fn" is not write-able, chmod u+w
-			// sprintf(syscmd, "chmod u+w %s", fn);
-			// system(syscmd);
-			// forced = TRUE;
-		//}
-		if (modified_count != 0 || cmd[0] != 'x') {
-			size = r - q + 1;
-			l = file_write(fn, q, r);
-		} else {
-			size = 0;
-			l = 0;
-		}
-		//if (useforce && forced) {
-			// chmod u-w
-			// sprintf(syscmd, "chmod u-w %s", fn);
-			// system(syscmd);
-			// forced = FALSE;
-		//}
-		if (l < 0) {
-			if (l == -1)
-				status_line_bold_errno(fn);
-		} else {
-			// how many lines written
-			li = count_lines(q, q + l - 1);
-			status_line("'%s' %dL, %dC", fn, li, l);
-			if (l == size) {
-				if (q == text && q + l == end) {
-					modified_count = 0;
-					last_modified_count = -1;
-				}
-				if (cmd[0] == 'x'
-				 || cmd[1] == 'q' || cmd[1] == 'n'
-				 || cmd[1] == 'Q' || cmd[1] == 'N'
-				) {
-					editing = 0;
-				}
-			}
-		}
-# if ENABLE_FEATURE_VI_YANKMARK
-	} else if (strncmp(cmd, "yank", i) == 0) {	// yank lines
-		if (b < 0) {	// no addr given- use defaults
-			q = begin_line(dot);	// assume .,. for the range
-			r = end_line(dot);
-		}
-		text_yank(q, r, YDreg);
-		li = count_lines(q, r);
-		status_line("Yank %d lines (%d chars) into [%c]",
-				li, strlen(reg[YDreg]), what_reg());
-# endif
-	} else {
-		// cmd unknown
-		not_implemented(cmd);
-	}
- ret:
-	dot = bound_dot(dot);	// make sure "dot" is valid
-	return;
-# if ENABLE_FEATURE_VI_SEARCH
- colon_s_fail:
-	status_line(":s expression missing delimiters");
-# endif
-#endif /* FEATURE_VI_COLON */
-}
-
-static void Hit_Return(void)
-{
-	int c;
-
-	standout_start();
-	write1("[Hit return to continue]");
-	standout_end();
-	while ((c = get_one_char()) != '\n' && c != '\r')
-		continue;
-	redraw(TRUE);		// force redraw all
-}
-
-static int next_tabstop(int col)
-{
-	return col + ((tabstop - 1) - (col % tabstop));
-}
-
-//----- Synchronize the cursor to Dot --------------------------
-static NOINLINE void sync_cursor(char *d, int *row, int *col)
-{
-	char *beg_cur;	// begin and end of "d" line
-	char *tp;
-	int cnt, ro, co;
-
-	beg_cur = begin_line(d);	// first char of cur line
-
-	if (beg_cur < screenbegin) {
-		// "d" is before top line on screen
-		// how many lines do we have to move
-		cnt = count_lines(beg_cur, screenbegin);
- sc1:
-		screenbegin = beg_cur;
-		if (cnt > (rows - 1) / 2) {
-			// we moved too many lines. put "dot" in middle of screen
-			for (cnt = 0; cnt < (rows - 1) / 2; cnt++) {
-				screenbegin = prev_line(screenbegin);
-			}
-		}
-	} else {
-		char *end_scr;	// begin and end of screen
-		end_scr = end_screen();	// last char of screen
-		if (beg_cur > end_scr) {
-			// "d" is after bottom line on screen
-			// how many lines do we have to move
-			cnt = count_lines(end_scr, beg_cur);
-			if (cnt > (rows - 1) / 2)
-				goto sc1;	// too many lines
-			for (ro = 0; ro < cnt - 1; ro++) {
-				// move screen begin the same amount
-				screenbegin = next_line(screenbegin);
-				// now, move the end of screen
-				end_scr = next_line(end_scr);
-				end_scr = end_line(end_scr);
-			}
-		}
-	}
-	// "d" is on screen- find out which row
-	tp = screenbegin;
-	for (ro = 0; ro < rows - 1; ro++) {	// drive "ro" to correct row
-		if (tp == beg_cur)
-			break;
-		tp = next_line(tp);
-	}
-
-	// find out what col "d" is on
-	co = 0;
-	while (tp < d) { // drive "co" to correct column
-		if (*tp == '\n') //vda || *tp == '\0')
-			break;
-		if (*tp == '\t') {
-			// handle tabs like real vi
-			if (d == tp && cmd_mode) {
-				break;
-			}
-			co = next_tabstop(co);
-		} else if ((unsigned char)*tp < ' ' || *tp == 0x7f) {
-			co++; // display as ^X, use 2 columns
-		}
-		co++;
-		tp++;
-	}
-
-	// "co" is the column where "dot" is.
-	// The screen has "columns" columns.
-	// The currently displayed columns are  0+offset -- columns+ofset
-	// |-------------------------------------------------------------|
-	//               ^ ^                                ^
-	//        offset | |------- columns ----------------|
-	//
-	// If "co" is already in this range then we do not have to adjust offset
-	//      but, we do have to subtract the "offset" bias from "co".
-	// If "co" is outside this range then we have to change "offset".
-	// If the first char of a line is a tab the cursor will try to stay
-	//  in column 7, but we have to set offset to 0.
-
-	if (co < 0 + offset) {
-		offset = co;
-	}
-	if (co >= columns + offset) {
-		offset = co - columns + 1;
-	}
-	// if the first char of the line is a tab, and "dot" is sitting on it
-	//  force offset to 0.
-	if (d == beg_cur && *d == '\t') {
-		offset = 0;
-	}
-	co -= offset;
-
-	*row = ro;
-	*col = co;
-}
-
-//----- Text Movement Routines ---------------------------------
-static char *begin_line(char *p) // return pointer to first char cur line
-{
-	if (p > text) {
-		p = memrchr(text, '\n', p - text);
-		if (!p)
-			return text;
-		return p + 1;
-	}
-	return p;
-}
-
-static char *end_line(char *p) // return pointer to NL of cur line
-{
-	if (p < end - 1) {
-		p = memchr(p, '\n', end - p - 1);
-		if (!p)
-			return end - 1;
-	}
-	return p;
-}
-
-static char *dollar_line(char *p) // return pointer to just before NL line
-{
-	p = end_line(p);
-	// Try to stay off of the Newline
-	if (*p == '\n' && (p - begin_line(p)) > 0)
-		p--;
-	return p;
-}
-
-static char *prev_line(char *p) // return pointer first char prev line
-{
-	p = begin_line(p);	// goto beginning of cur line
-	if (p > text && p[-1] == '\n')
-		p--;			// step to prev line
-	p = begin_line(p);	// goto beginning of prev line
-	return p;
-}
-
-static char *next_line(char *p) // return pointer first char next line
-{
-	p = end_line(p);
-	if (p < end - 1 && *p == '\n')
-		p++;			// step to next line
-	return p;
-}
-
-//----- Text Information Routines ------------------------------
-static char *end_screen(void)
-{
-	char *q;
-	int cnt;
+		// F points to the "find" pattern
+		// R points to the "replace" pattern
+		// replace the cmd line delimiters "/" with NULs
+		c = orig_buf[1];	// what is the delimiter
+		F = orig_buf + 2;	// start of "find"
+		R = strchr(F, c);	// middle delimiter
+		if (!R)
+			goto colon_s_fail;
+		len_F = R - F;
+		*R++ = '\0';	// terminate "find"
+		flags = strchr(R, c);
+		if (!flags)
+			goto colon_s_fail;
+		len_R = flags - R;
+		*flags++ = '\0';	// terminate "replace"
+		gflag = *flags;
 
-	// find new bottom line
-	q = screenbegin;
-	for (cnt = 0; cnt < rows - 2; cnt++)
-		q = next_line(q);
-	q = end_line(q);
-	return q;
-}
+		q = begin_line(q);
+		if (b < 0) {	// maybe :s/foo/bar/
+			q = begin_line(dot);      // start with cur line
+			b = count_lines(text, q); // cur line number
+		}
+		if (e < 0)
+			e = b;		// maybe :.s/foo/bar/
 
-// count line from start to stop
-static int count_lines(char *start, char *stop)
-{
-	char *q;
-	int cnt;
+		for (i = b; i <= e; i++) {	// so, :20,23 s \0 find \0 replace \0
+			char *ls = q;		// orig line start
+			char *found;
+ vc4:
+			found = char_search(q, F, (FORWARD << 1) | LIMITED);	// search cur line only for "find"
+			if (found) {
+				uintptr_t bias;
+				// we found the "find" pattern - delete it
+				// For undo support, the first item should not be chained
+				text_hole_delete(found, found + len_F - 1, dont_chain_first_item);
+#  if ENABLE_FEATURE_VI_UNDO
+				dont_chain_first_item = ALLOW_UNDO_CHAIN;
+#  endif
+				// insert the "replace" patern
+				bias = string_insert(found, R, ALLOW_UNDO_CHAIN);
+				found += bias;
+				ls += bias;
+				/*q += bias; - recalculated anyway */
+				// check for "global"  :s/foo/bar/g
+				if (gflag == 'g') {
+					if ((found + len_R) < end_line(ls)) {
+						q = found + len_R;
+						goto vc4;	// don't let q move past cur line
+					}
+				}
+			}
+			q = next_line(ls);
+		}
+# endif /* FEATURE_VI_SEARCH */
+	} else if (strncmp(cmd, "version", i) == 0) {  // show software version
+		status_line(BB_VER);
+	} else if (strncmp(cmd, "write", i) == 0  // write text to file
+	        || strncmp(cmd, "wq", i) == 0
+	        || strncmp(cmd, "wn", i) == 0
+	        || (cmd[0] == 'x' && !cmd[1])
+	) {
+		int size;
+		//int forced = FALSE;
 
-	if (stop < start) { // start and stop are backwards- reverse them
-		q = start;
-		start = stop;
-		stop = q;
-	}
-	cnt = 0;
-	stop = end_line(stop);
-	while (start <= stop && start <= end - 1) {
-		start = end_line(start);
-		if (*start == '\n')
-			cnt++;
-		start++;
+		// is there a file name to write to?
+		if (args[0]) {
+			fn = args;
+		}
+# if ENABLE_FEATURE_VI_READONLY
+		if (readonly_mode && !useforce) {
+			status_line_bold("'%s' is read only", fn);
+			goto ret;
+		}
+# endif
+		//if (useforce) {
+			// if "fn" is not write-able, chmod u+w
+			// sprintf(syscmd, "chmod u+w %s", fn);
+			// system(syscmd);
+			// forced = TRUE;
+		//}
+		if (modified_count != 0 || cmd[0] != 'x') {
+			size = r - q + 1;
+			l = file_write(fn, q, r);
+		} else {
+			size = 0;
+			l = 0;
+		}
+		//if (useforce && forced) {
+			// chmod u-w
+			// sprintf(syscmd, "chmod u-w %s", fn);
+			// system(syscmd);
+			// forced = FALSE;
+		//}
+		if (l < 0) {
+			if (l == -1)
+				status_line_bold_errno(fn);
+		} else {
+			// how many lines written
+			li = count_lines(q, q + l - 1);
+			status_line("'%s' %dL, %dC", fn, li, l);
+			if (l == size) {
+				if (q == text && q + l == end) {
+					modified_count = 0;
+					last_modified_count = -1;
+				}
+				if (cmd[0] == 'x'
+				 || cmd[1] == 'q' || cmd[1] == 'n'
+				 || cmd[1] == 'Q' || cmd[1] == 'N'
+				) {
+					editing = 0;
+				}
+			}
+		}
+# if ENABLE_FEATURE_VI_YANKMARK
+	} else if (strncmp(cmd, "yank", i) == 0) {	// yank lines
+		if (b < 0) {	// no addr given- use defaults
+			q = begin_line(dot);	// assume .,. for the range
+			r = end_line(dot);
+		}
+		text_yank(q, r, YDreg);
+		li = count_lines(q, r);
+		status_line("Yank %d lines (%d chars) into [%c]",
+				li, strlen(reg[YDreg]), what_reg());
+# endif
+	} else {
+		// cmd unknown
+		not_implemented(cmd);
 	}
-	return cnt;
+ ret:
+	dot = bound_dot(dot);	// make sure "dot" is valid
+	return;
+# if ENABLE_FEATURE_VI_SEARCH
+ colon_s_fail:
+	status_line(":s expression missing delimiters");
+# endif
+#endif /* FEATURE_VI_COLON */
 }
 
-static char *find_line(int li)	// find beginning of line #li
+static void Hit_Return(void)
 {
-	char *q;
+	int c;
 
-	for (q = text; li > 1; li--) {
-		q = next_line(q);
-	}
-	return q;
+	standout_start();
+	write1("[Hit return to continue]");
+	standout_end();
+	while ((c = get_one_char()) != '\n' && c != '\r')
+		continue;
+	redraw(TRUE);		// force redraw all
 }
 
 //----- Dot Movement Routines ----------------------------------
@@ -2430,32 +2512,6 @@ static char *swap_context(char *p) // goto new context for '' command make this
 }
 #endif /* FEATURE_VI_YANKMARK */
 
-//----- Set terminal attributes --------------------------------
-static void rawmode(void)
-{
-	// no TERMIOS_CLEAR_ISIG: leave ISIG on - allow signals
-	set_termios_to_raw(STDIN_FILENO, &term_orig, TERMIOS_RAW_CRNL);
-	erase_char = term_orig.c_cc[VERASE];
-}
-
-static void cookmode(void)
-{
-	fflush_all();
-	tcsetattr_stdin_TCSANOW(&term_orig);
-}
-
-static int mysleep(int hund)	// sleep for 'hund' 1/100 seconds or stdin ready
-{
-	struct pollfd pfd[1];
-
-	if (hund != 0)
-		fflush_all();
-
-	pfd[0].fd = STDIN_FILENO;
-	pfd[0].events = POLLIN;
-	return safe_poll(pfd, 1, hund*10) > 0;
-}
-
 //----- IO Routines --------------------------------------------
 static int readit(void) // read (maybe cursor) key from stdin
 {
@@ -2637,55 +2693,6 @@ static int file_write(char *fn, char *first, char *last)
 	return charcnt;
 }
 
-//----- Terminal Drawing ---------------------------------------
-// The terminal is made up of 'rows' line of 'columns' columns.
-// classically this would be 24 x 80.
-//  screen coordinates
-//  0,0     ...     0,79
-//  1,0     ...     1,79
-//  .       ...     .
-//  .       ...     .
-//  22,0    ...     22,79
-//  23,0    ...     23,79   <- status line
-
-//----- Move the cursor to row x col (count from 0, not 1) -------
-static void place_cursor(int row, int col)
-{
-	char cm1[sizeof(ESC_SET_CURSOR_POS) + sizeof(int)*3 * 2];
-
-	if (row < 0) row = 0;
-	if (row >= rows) row = rows - 1;
-	if (col < 0) col = 0;
-	if (col >= columns) col = columns - 1;
-
-	sprintf(cm1, ESC_SET_CURSOR_POS, row + 1, col + 1);
-	write1(cm1);
-}
-
-//----- Erase from cursor to end of line -----------------------
-static void clear_to_eol(void)
-{
-	write1(ESC_CLEAR2EOL);
-}
-
-static void go_bottom_and_clear_to_eol(void)
-{
-	place_cursor(rows - 1, 0);
-	clear_to_eol();
-}
-
-//----- Start standout mode ------------------------------------
-static void standout_start(void)
-{
-	write1(ESC_BOLD_TEXT);
-}
-
-//----- End standout mode --------------------------------------
-static void standout_end(void)
-{
-	write1(ESC_NORM_TEXT);
-}
-
 //----- Flash the screen  --------------------------------------
 static void flash(int h)
 {
@@ -2709,13 +2716,6 @@ static void indicate_error(void)
 	}
 }
 
-//----- Screen[] Routines --------------------------------------
-//----- Erase the Screen[] memory ------------------------------
-static void screen_erase(void)
-{
-	memset(screen, ' ', screensize);	// clear new screen
-}
-
 static int bufsum(char *buf, int count)
 {
 	int sum = 0;


More information about the busybox-cvs mailing list