Busybox 1.21.0 squashed commit for jellybean

Change-Id: I423c7fc1254050c6495126b1b18dd33af07fed6b
Signed-off-by: Tanguy Pruvot <tanguy.pruvot@gmail.com>
diff --git a/findutils/grep.c b/findutils/grep.c
index 78be704..a64a735 100644
--- a/findutils/grep.c
+++ b/findutils/grep.c
@@ -344,10 +344,34 @@
 		while (pattern_ptr) {
 			gl = (grep_list_data_t *)pattern_ptr->data;
 			if (FGREP_FLAG) {
-				found |= (((option_mask32 & OPT_i)
-					? strcasestr(line, gl->pattern)
-					: strstr(line, gl->pattern)
-					) != NULL);
+				char *match;
+				char *str = line;
+ opt_f_again:
+				match = ((option_mask32 & OPT_i)
+					? strcasestr(str, gl->pattern)
+					: strstr(str, gl->pattern)
+					);
+				if (match) {
+					if (option_mask32 & OPT_x) {
+						if (match != str)
+							goto opt_f_not_found;
+						if (str[strlen(gl->pattern)] != '\0')
+							goto opt_f_not_found;
+					} else
+					if (option_mask32 & OPT_w) {
+						char c = (match != str) ? match[-1] : ' ';
+						if (!isalnum(c) && c != '_') {
+							c = match[strlen(gl->pattern)];
+							if (!c || (!isalnum(c) && c != '_'))
+								goto opt_f_found;
+						}
+						str = match + 1;
+						goto opt_f_again;
+					}
+ opt_f_found:
+					found = 1;
+ opt_f_not_found: ;
+				}
 			} else {
 				if (!(gl->flg_mem_alocated_compiled & COMPILED)) {
 					gl->flg_mem_alocated_compiled |= COMPILED;
@@ -376,7 +400,8 @@
 					if (option_mask32 & OPT_x) {
 						found = (gl->matched_range.rm_so == 0
 						         && line[gl->matched_range.rm_eo] == '\0');
-					} else if (!(option_mask32 & OPT_w)) {
+					} else
+					if (!(option_mask32 & OPT_w)) {
 						found = 1;
 					} else {
 						char c = ' ';
@@ -387,6 +412,8 @@
 							if (!c || (!isalnum(c) && c != '_'))
 								found = 1;
 						}
+//BUG: "echo foop foo | grep -w foo" should match, but doesn't:
+//we bail out on first "mismatch" because it's not a word.
 					}
 				}
 			}
@@ -638,7 +665,7 @@
 
 	if (opts & OPT_C) {
 		/* -C unsets prev -A and -B, but following -A or -B
-		   may override it */
+		 * may override it */
 		if (!(opts & OPT_A)) /* not overridden */
 			lines_after = Copt;
 		if (!(opts & OPT_B)) /* not overridden */