Busybox 1.20.0 squashed commit for ICS
diff --git a/editors/vi.c b/editors/vi.c
index 96a0c8d..b4ad12e 100644
--- a/editors/vi.c
+++ b/editors/vi.c
@@ -278,7 +278,6 @@
 	smallint cmd_mode;       // 0=command  1=insert 2=replace
 	int file_modified;       // buffer contents changed (counter, not flag!)
 	int last_file_modified;  // = -1;
-	int fn_start;            // index of first cmd line file name
 	int save_argc;           // how many file names on cmd line
 	int cmdcnt;              // repetition count
 	unsigned rows, columns;	 // the terminal screen is this size
@@ -363,7 +362,6 @@
 #define cmd_mode                (G.cmd_mode           )
 #define file_modified           (G.file_modified      )
 #define last_file_modified      (G.last_file_modified )
-#define fn_start                (G.fn_start           )
 #define save_argc               (G.save_argc          )
 #define cmdcnt                  (G.cmdcnt             )
 #define rows                    (G.rows               )
@@ -599,9 +597,10 @@
 	}
 
 	// The argv array can be used by the ":next"  and ":rewind" commands
-	// save optind.
-	fn_start = optind;	// remember first file name for :next and :rew
+	argv += optind;
+	argc -= optind;
 	save_argc = argc;
+	optind = 0;
 
 	//----- This is the main file handling loop --------------
 	while (1) {
@@ -1021,7 +1020,7 @@
 	} else if (strncmp(cmd, "edit", i) == 0) {	// Edit a file
 		// don't edit, if the current file has been modified
 		if (file_modified && !useforce) {
-			status_line_bold("No write since last change (:edit! overrides)");
+			status_line_bold("No write since last change (:%s! overrides)", cmd);
 			goto ret;
 		}
 		if (args[0]) {
@@ -1040,13 +1039,13 @@
 			goto ret;
 
 #if ENABLE_FEATURE_VI_YANKMARK
-		if (Ureg >= 0 && Ureg < 28 && reg[Ureg] != 0) {
+		if (Ureg >= 0 && Ureg < 28) {
 			free(reg[Ureg]);	//   free orig line reg- for 'U'
-			reg[Ureg]= 0;
+			reg[Ureg] = NULL;
 		}
-		if (YDreg >= 0 && YDreg < 28 && reg[YDreg] != 0) {
+		if (YDreg >= 0 && YDreg < 28) {
 			free(reg[YDreg]);	//   free default yank/delete register
-			reg[YDreg]= 0;
+			reg[YDreg] = NULL;
 		}
 #endif
 		// how many lines in text[]?
@@ -1111,11 +1110,12 @@
 		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) {
-			// force end of argv list
 			if (*cmd == 'q') {
+				// force end of argv list
 				optind = save_argc;
 			}
 			editing = 0;
@@ -1123,8 +1123,7 @@
 		}
 		// don't exit if the file been modified
 		if (file_modified) {
-			status_line_bold("No write since last change (:%s! overrides)",
-				 (*cmd == 'q' ? "quit" : "next"));
+			status_line_bold("No write since last change (:%s! overrides)", cmd);
 			goto ret;
 		}
 		// are there other file to edit
@@ -1137,6 +1136,14 @@
 			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[]
 		fn = args;
@@ -1172,10 +1179,10 @@
 		}
 	} else if (strncmp(cmd, "rewind", i) == 0) {	// rewind cmd line args
 		if (file_modified && !useforce) {
-			status_line_bold("No write since last change (:rewind! overrides)");
+			status_line_bold("No write since last change (:%s! overrides)", cmd);
 		} else {
 			// reset the filenames to edit
-			optind = fn_start - 1;
+			optind = -1; /* start from 0th file */
 			editing = 0;
 		}
 #if ENABLE_FEATURE_VI_SET
@@ -1225,51 +1232,53 @@
 #endif /* FEATURE_VI_SET */
 #if ENABLE_FEATURE_VI_SEARCH
 	} else if (cmd[0] == 's') {	// substitute a pattern with a replacement pattern
-		char *ls, *F, *R;
-		int gflag;
+		char *F, *R, *flags;
+		size_t len_F, len_R;
+		int gflag;		// global replace flag
 
 		// F points to the "find" pattern
 		// R points to the "replace" pattern
-		// replace the cmd line delimiters "/" with NULLs
-		gflag = 0;		// global replace flag
+		// 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"
-		buf1 = strchr(R, c);
-		if (!buf1)
+		flags = strchr(R, c);
+		if (!flags)
 			goto colon_s_fail;
-		*buf1++ = '\0';	// terminate "replace"
-		if (*buf1 == 'g') {	// :s/foo/bar/g
-			buf1++;
-			gflag++;	// turn on gflag
-		}
+		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
+			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
-			ls = q;		// orig line start
+			char *ls = q;		// orig line start
+			char *found;
  vc4:
-			buf1 = char_search(q, F, FORWARD, LIMITED);	// search cur line only for "find"
-			if (buf1) {
+			found = char_search(q, F, FORWARD, LIMITED);	// search cur line only for "find"
+			if (found) {
 				uintptr_t bias;
 				// we found the "find" pattern - delete it
-				text_hole_delete(buf1, buf1 + strlen(F) - 1);
+				text_hole_delete(found, found + len_F - 1);
 				// inset the "replace" patern
-				bias = string_insert(buf1, R);	// insert the string
-				buf1 += bias;
+				bias = string_insert(found, R);	// insert the string
+				found += bias;
 				ls += bias;
 				/*q += bias; - recalculated anyway */
 				// check for "global"  :s/foo/bar/g
-				if (gflag == 1) {
-					if ((buf1 + strlen(R)) < end_line(ls)) {
-						q = buf1 + strlen(R);
+				if (gflag == 'g') {
+					if ((found + len_R) < end_line(ls)) {
+						q = found + len_R;
 						goto vc4;	// don't let q move past cur line
 					}
 				}
@@ -2073,6 +2082,14 @@
 		dot         += bias;
 		end         += bias;
 		p           += bias;
+#if ENABLE_FEATURE_VI_YANKMARK
+		{
+			int i;
+			for (i = 0; i < ARRAY_SIZE(mark); i++)
+				if (mark[i])
+					mark[i] += bias;
+		}
+#endif
 		text = new_text;
 	}
 	memmove(p + size, p, end - size - p);
@@ -2304,7 +2321,7 @@
 {
 	tcgetattr(0, &term_orig);
 	term_vi = term_orig;
-	term_vi.c_lflag &= (~ICANON & ~ECHO);	// leave ISIG ON- allow intr's
+	term_vi.c_lflag &= (~ICANON & ~ECHO);	// leave ISIG on - allow intr's
 	term_vi.c_iflag &= (~IXON & ~ICRNL);
 	term_vi.c_oflag &= (~ONLCR);
 	term_vi.c_cc[VMIN] = 1;
@@ -3063,7 +3080,6 @@
 //----- Execute a Vi Command -----------------------------------
 static void do_cmd(int c)
 {
-	const char *msg = msg; // for compiler
 	char *p, *q, *save_dot;
 	char buf[12];
 	int dir;
@@ -3072,8 +3088,8 @@
 
 //	c1 = c; // quiet the compiler
 //	cnt = yf = 0; // quiet the compiler
-//	msg = p = q = save_dot = buf; // quiet the compiler
-	memset(buf, '\0', 12);
+//	p = q = save_dot = buf; // quiet the compiler
+	memset(buf, '\0', sizeof(buf));
 
 	show_status_line();
 
@@ -3189,19 +3205,18 @@
 	case KEYCODE_LEFT:	// cursor key Left
 	case 8:		// ctrl-H- move left    (This may be ERASE char)
 	case 0x7f:	// DEL- move left   (This may be ERASE char)
-		if (--cmdcnt > 0) {
-			do_cmd(c);
-		}
-		dot_left();
+		do {
+			dot_left();
+		} while (--cmdcnt > 0);
 		break;
 	case 10:			// Newline ^J
 	case 'j':			// j- goto next line, same col
 	case KEYCODE_DOWN:	// cursor key Down
-		if (--cmdcnt > 0) {
-			do_cmd(c);
-		}
-		dot_next();		// go to next B-o-l
-		dot = move_to_col(dot, ccol + offset);	// try stay in same col
+		do {
+			dot_next();		// go to next B-o-l
+			// try stay in same col
+			dot = move_to_col(dot, ccol + offset);
+		} while (--cmdcnt > 0);
 		break;
 	case 12:			// ctrl-L  force redraw whole screen
 	case 18:			// ctrl-R  force redraw
@@ -3214,11 +3229,10 @@
 		break;
 	case 13:			// Carriage Return ^M
 	case '+':			// +- goto next line
-		if (--cmdcnt > 0) {
-			do_cmd(c);
-		}
-		dot_next();
-		dot_skip_over_ws();
+		do {
+			dot_next();
+			dot_skip_over_ws();
+		} while (--cmdcnt > 0);
 		break;
 	case 21:			// ctrl-U  scroll up   half screen
 		dot_scroll((rows - 2) / 2, -1);
@@ -3236,10 +3250,9 @@
 	case ' ':			// move right
 	case 'l':			// move right
 	case KEYCODE_RIGHT:	// Cursor Key Right
-		if (--cmdcnt > 0) {
-			do_cmd(c);
-		}
-		dot_right();
+		do {
+			dot_right();
+		} while (--cmdcnt > 0);
 		break;
 #if ENABLE_FEATURE_VI_YANKMARK
 	case '"':			// "- name a register to use for Delete/Yank
@@ -3309,7 +3322,7 @@
 		end_cmd_q();	// stop adding to q
 		break;
 	case 'U':			// U- Undo; replace current line with original version
-		if (reg[Ureg] != 0) {
+		if (reg[Ureg] != NULL) {
 			p = begin_line(dot);
 			q = end_line(dot);
 			p = text_hole_delete(p, q);	// delete cur line
@@ -3321,11 +3334,12 @@
 #endif /* FEATURE_VI_YANKMARK */
 	case '$':			// $- goto end of line
 	case KEYCODE_END:		// Cursor Key End
-		if (--cmdcnt > 0) {
+		for (;;) {
+			dot = end_line(dot);
+			if (--cmdcnt <= 0)
+				break;
 			dot_next();
-			do_cmd(c);
 		}
-		dot = end_line(dot);
 		break;
 	case '%':			// %- find matching char of pair () [] {}
 		for (q = dot; q < end && *q != '\n'; q++) {
@@ -3350,38 +3364,35 @@
 		//
 		//**** fall through to ... ';'
 	case ';':			// ;- look at rest of line for last forward char
-		if (--cmdcnt > 0) {
-			do_cmd(';');
-		}
-		if (last_forward_char == 0)
-			break;
-		q = dot + 1;
-		while (q < end - 1 && *q != '\n' && *q != last_forward_char) {
-			q++;
-		}
-		if (*q == last_forward_char)
-			dot = q;
+		do {
+			if (last_forward_char == 0)
+				break;
+			q = dot + 1;
+			while (q < end - 1 && *q != '\n' && *q != last_forward_char) {
+				q++;
+			}
+			if (*q == last_forward_char)
+				dot = q;
+		} while (--cmdcnt > 0);
 		break;
 	case ',':           // repeat latest 'f' in opposite direction
-		if (--cmdcnt > 0) {
-			do_cmd(',');
-		}
 		if (last_forward_char == 0)
 			break;
-		q = dot - 1;
-		while (q >= text && *q != '\n' && *q != last_forward_char) {
-			q--;
-		}
-		if (q >= text && *q == last_forward_char)
-			dot = q;
+		do {
+			q = dot - 1;
+			while (q >= text && *q != '\n' && *q != last_forward_char) {
+				q--;
+			}
+			if (q >= text && *q == last_forward_char)
+				dot = q;
+		} while (--cmdcnt > 0);
 		break;
 
 	case '-':			// -- goto prev line
-		if (--cmdcnt > 0) {
-			do_cmd(c);
-		}
-		dot_prev();
-		dot_skip_over_ws();
+		do {
+			dot_prev();
+			dot_skip_over_ws();
+		} while (--cmdcnt > 0);
 		break;
 #if ENABLE_FEATURE_VI_DOT_CMD
 	case '.':			// .- repeat the last modifying command
@@ -3413,9 +3424,6 @@
 		// user changed mind and erased the "/"-  do nothing
 		break;
 	case 'N':			// N- backward search for last pattern
-		if (--cmdcnt > 0) {
-			do_cmd(c);
-		}
 		dir = BACK;		// assume BACKWARD search
 		p = dot - 1;
 		if (last_search_pattern[0] == '?') {
@@ -3427,41 +3435,41 @@
 	case 'n':			// n- repeat search for last pattern
 		// search rest of text[] starting at next char
 		// if search fails return orignal "p" not the "p+1" address
-		if (--cmdcnt > 0) {
-			do_cmd(c);
-		}
+		do {
+			const char *msg;
  dc3:
-		dir = FORWARD;	// assume FORWARD search
-		p = dot + 1;
-		if (last_search_pattern[0] == '?') {
-			dir = BACK;
-			p = dot - 1;
-		}
- dc4:
-		q = char_search(p, last_search_pattern + 1, dir, FULL);
-		if (q != NULL) {
-			dot = q;	// good search, update "dot"
-			msg = "";
-			goto dc2;
-		}
-		// no pattern found between "dot" and "end"- continue at top
-		p = text;
-		if (dir == BACK) {
-			p = end - 1;
-		}
-		q = char_search(p, last_search_pattern + 1, dir, FULL);
-		if (q != NULL) {	// found something
-			dot = q;	// found new pattern- goto it
-			msg = "search hit BOTTOM, continuing at TOP";
-			if (dir == BACK) {
-				msg = "search hit TOP, continuing at BOTTOM";
+			dir = FORWARD;	// assume FORWARD search
+			p = dot + 1;
+			if (last_search_pattern[0] == '?') {
+				dir = BACK;
+				p = dot - 1;
 			}
-		} else {
-			msg = "Pattern not found";
-		}
+ dc4:
+			q = char_search(p, last_search_pattern + 1, dir, FULL);
+			if (q != NULL) {
+				dot = q;	// good search, update "dot"
+				msg = NULL;
+				goto dc2;
+			}
+			// no pattern found between "dot" and "end"- continue at top
+			p = text;
+			if (dir == BACK) {
+				p = end - 1;
+			}
+			q = char_search(p, last_search_pattern + 1, dir, FULL);
+			if (q != NULL) {	// found something
+				dot = q;	// found new pattern- goto it
+				msg = "search hit BOTTOM, continuing at TOP";
+				if (dir == BACK) {
+					msg = "search hit TOP, continuing at BOTTOM";
+				}
+			} else {
+				msg = "Pattern not found";
+			}
  dc2:
-		if (*msg)
-			status_line_bold("%s", msg);
+			if (msg)
+				status_line_bold("%s", msg);
+		} while (--cmdcnt > 0);
 		break;
 	case '{':			// {- move backward paragraph
 		q = char_search(dot, "\n\n", BACK, FULL);
@@ -3506,7 +3514,7 @@
 		 || strncmp(p, "q!", cnt) == 0   // delete lines
 		) {
 			if (file_modified && p[1] != '!') {
-				status_line_bold("No write since last change (:quit! overrides)");
+				status_line_bold("No write since last change (:%s! overrides)", p);
 			} else {
 				editing = 0;
 			}
@@ -3580,18 +3588,17 @@
 	case 'B':			// B- back a blank-delimited Word
 	case 'E':			// E- end of a blank-delimited word
 	case 'W':			// W- forward a blank-delimited word
-		if (--cmdcnt > 0) {
-			do_cmd(c);
-		}
 		dir = FORWARD;
 		if (c == 'B')
 			dir = BACK;
-		if (c == 'W' || isspace(dot[dir])) {
-			dot = skip_thing(dot, 1, dir, S_TO_WS);
-			dot = skip_thing(dot, 2, dir, S_OVER_WS);
-		}
-		if (c != 'W')
-			dot = skip_thing(dot, 1, dir, S_BEFORE_WS);
+		do {
+			if (c == 'W' || isspace(dot[dir])) {
+				dot = skip_thing(dot, 1, dir, S_TO_WS);
+				dot = skip_thing(dot, 2, dir, S_OVER_WS);
+			}
+			if (c != 'W')
+				dot = skip_thing(dot, 1, dir, S_BEFORE_WS);
+		} while (--cmdcnt > 0);
 		break;
 	case 'C':			// C- Change to e-o-l
 	case 'D':			// D- delete to e-o-l
@@ -3642,20 +3649,19 @@
 	case 'i':			// i- insert before current char
 	case KEYCODE_INSERT:	// Cursor Key Insert
  dc_i:
-		cmd_mode = 1;	// start insrting
+		cmd_mode = 1;	// start inserting
 		break;
 	case 'J':			// J- join current and next lines together
-		if (--cmdcnt > 1) {
-			do_cmd(c);
-		}
-		dot_end();		// move to NL
-		if (dot < end - 1) {	// make sure not last char in text[]
-			*dot++ = ' ';	// replace NL with space
-			file_modified++;
-			while (isblank(*dot)) {	// delete leading WS
-				dot_delete();
+		do {
+			dot_end();		// move to NL
+			if (dot < end - 1) {	// make sure not last char in text[]
+				*dot++ = ' ';	// replace NL with space
+				file_modified++;
+				while (isblank(*dot)) {	// delete leading WS
+					dot_delete();
+				}
 			}
-		}
+		} while (--cmdcnt > 0);
 		end_cmd_q();	// stop adding to q
 		break;
 	case 'L':			// L- goto bottom line on screen
@@ -3699,20 +3705,19 @@
 	case 'X':			// X- delete char before dot
 	case 'x':			// x- delete the current char
 	case 's':			// s- substitute the current char
-		if (--cmdcnt > 0) {
-			do_cmd(c);
-		}
 		dir = 0;
 		if (c == 'X')
 			dir = -1;
-		if (dot[dir] != '\n') {
-			if (c == 'X')
-				dot--;	// delete prev char
-			dot = yank_delete(dot, dot, 0, YANKDEL);	// delete char
-		}
-		if (c == 's')
-			goto dc_i;	// start insrting
+		do {
+			if (dot[dir] != '\n') {
+				if (c == 'X')
+					dot--;	// delete prev char
+				dot = yank_delete(dot, dot, 0, YANKDEL);	// delete char
+			}
+		} while (--cmdcnt > 0);
 		end_cmd_q();	// stop adding to q
+		if (c == 's')
+			goto dc_i;	// start inserting
 		break;
 	case 'Z':			// Z- if modified, {write}; exit
 		// ZZ means to save file (if necessary), then exit
@@ -3743,23 +3748,22 @@
 		break;
 	case 'b':			// b- back a word
 	case 'e':			// e- end of word
-		if (--cmdcnt > 0) {
-			do_cmd(c);
-		}
 		dir = FORWARD;
 		if (c == 'b')
 			dir = BACK;
-		if ((dot + dir) < text || (dot + dir) > end - 1)
-			break;
-		dot += dir;
-		if (isspace(*dot)) {
-			dot = skip_thing(dot, (c == 'e') ? 2 : 1, dir, S_OVER_WS);
-		}
-		if (isalnum(*dot) || *dot == '_') {
-			dot = skip_thing(dot, 1, dir, S_END_ALNUM);
-		} else if (ispunct(*dot)) {
-			dot = skip_thing(dot, 1, dir, S_END_PUNCT);
-		}
+		do {
+			if ((dot + dir) < text || (dot + dir) > end - 1)
+				break;
+			dot += dir;
+			if (isspace(*dot)) {
+				dot = skip_thing(dot, (c == 'e') ? 2 : 1, dir, S_OVER_WS);
+			}
+			if (isalnum(*dot) || *dot == '_') {
+				dot = skip_thing(dot, 1, dir, S_END_ALNUM);
+			} else if (ispunct(*dot)) {
+				dot = skip_thing(dot, 1, dir, S_END_PUNCT);
+			}
+		} while (--cmdcnt > 0);
 		break;
 	case 'c':			// c- change something
 	case 'd':			// d- delete something
@@ -3844,11 +3848,10 @@
 	}
 	case 'k':			// k- goto prev line, same col
 	case KEYCODE_UP:		// cursor key Up
-		if (--cmdcnt > 0) {
-			do_cmd(c);
-		}
-		dot_prev();
-		dot = move_to_col(dot, ccol + offset);	// try stay in same col
+		do {
+			dot_prev();
+			dot = move_to_col(dot, ccol + offset);	// try stay in same col
+		} while (--cmdcnt > 0);
 		break;
 	case 'r':			// r- replace the current char with user input
 		c1 = get_one_char();	// get the replacement char
@@ -3866,19 +3869,18 @@
 		last_forward_char = 0;
 		break;
 	case 'w':			// w- forward a word
-		if (--cmdcnt > 0) {
-			do_cmd(c);
-		}
-		if (isalnum(*dot) || *dot == '_') {	// we are on ALNUM
-			dot = skip_thing(dot, 1, FORWARD, S_END_ALNUM);
-		} else if (ispunct(*dot)) {	// we are on PUNCT
-			dot = skip_thing(dot, 1, FORWARD, S_END_PUNCT);
-		}
-		if (dot < end - 1)
-			dot++;		// move over word
-		if (isspace(*dot)) {
-			dot = skip_thing(dot, 2, FORWARD, S_OVER_WS);
-		}
+		do {
+			if (isalnum(*dot) || *dot == '_') {	// we are on ALNUM
+				dot = skip_thing(dot, 1, FORWARD, S_END_ALNUM);
+			} else if (ispunct(*dot)) {	// we are on PUNCT
+				dot = skip_thing(dot, 1, FORWARD, S_END_PUNCT);
+			}
+			if (dot < end - 1)
+				dot++;		// move over word
+			if (isspace(*dot)) {
+				dot = skip_thing(dot, 2, FORWARD, S_OVER_WS);
+			}
+		} while (--cmdcnt > 0);
 		break;
 	case 'z':			// z-
 		c1 = get_one_char();	// get the replacement char
@@ -3894,17 +3896,16 @@
 		dot = move_to_col(dot, cmdcnt - 1);	// try to move to column
 		break;
 	case '~':			// ~- flip the case of letters   a-z -> A-Z
-		if (--cmdcnt > 0) {
-			do_cmd(c);
-		}
-		if (islower(*dot)) {
-			*dot = toupper(*dot);
-			file_modified++;
-		} else if (isupper(*dot)) {
-			*dot = tolower(*dot);
-			file_modified++;
-		}
-		dot_right();
+		do {
+			if (islower(*dot)) {
+				*dot = toupper(*dot);
+				file_modified++;
+			} else if (isupper(*dot)) {
+				*dot = tolower(*dot);
+				file_modified++;
+			}
+			dot_right();
+		} while (--cmdcnt > 0);
 		end_cmd_q();	// stop adding to q
 		break;
 		//----- The Cursor and Function Keys -----------------------------