From cf787cf3a54f21e643d760dc3f893233ecce4ad5 Mon Sep 17 00:00:00 2001
From: Denis Vlasenko <vda.linux@googlemail.com>
Date: Sun, 4 Feb 2007 17:11:25 +0000
Subject: find: support for !

---
 findutils/Config.in | 18 ++++++++++++++++++
 findutils/find.c    | 45 +++++++++++++++++++++++++++++++++++++--------
 shell/msh.c         |  2 +-
 3 files changed, 56 insertions(+), 9 deletions(-)

diff --git a/findutils/Config.in b/findutils/Config.in
index 73ce36f51..e5f82986d 100644
--- a/findutils/Config.in
+++ b/findutils/Config.in
@@ -90,6 +90,24 @@ config FEATURE_FIND_USER
 	help
 	  Support the 'find -user' option for searching by username or uid.
 
+config FEATURE_FIND_NOT
+	bool "Enable the 'not' (!) operator"
+	default y
+	depends on FIND
+	help
+	  Support the '!' operator to invert the test results. If 'Enable
+	  full-blown desktop' is enabled, then will also the non-POSIX 
+	  '-not' be supported.
+
+config FEATURE_FIND_NOT
+	bool "Enable the 'not' (!) operator"
+	default y
+	depends on FIND
+	help
+	  Support the '!' operator to invert the test results. If 'Enable
+	  full-blown desktop' is enabled, then will also the non-POSIX 
+	  '-not' be supported.
+
 config GREP
 	bool "grep"
 	default n
diff --git a/findutils/find.c b/findutils/find.c
index bfdd84497..5645b5a4d 100644
--- a/findutils/find.c
+++ b/findutils/find.c
@@ -55,6 +55,9 @@ typedef int (*action_fp)(const char *fileName, struct stat *statbuf, void *);
 
 typedef struct {
 	action_fp f;
+#if ENABLE_FEATURE_FIND_NOT
+	smallint invert;
+#endif
 } action;
 #define ACTS(name, arg...) typedef struct { action a; arg; } action_##name;
 #define ACTF(name)         static int func_##name(const char *fileName, struct stat *statbuf, action_##name* ap)
@@ -118,12 +121,20 @@ static int exec_actions(action ***appp, const char *fileName, struct stat *statb
 	cur_group = -1;
 	while ((app = appp[++cur_group])) {
 		cur_action = -1;
-		do {
+		while (1) {
 			ap = app[++cur_action];
-		} while (ap && (rc = ap->f(fileName, statbuf, ap)));
-		if (!ap) {
-			/* all actions in group were successful */
-			break;
+			if (!ap) {
+				/* all actions in group were successful */
+				return rc;
+			}
+			rc = ap->f(fileName, statbuf, ap);
+#if ENABLE_FEATURE_FIND_NOT
+			if (ap->invert) rc = !rc;
+#endif
+			if (!rc) {
+				/* current group failed, try next */
+				break;
+			}
 		}
 	}
 	return rc;
@@ -331,6 +342,7 @@ static action*** parse_params(char **argv)
 	action*** appp;
 	unsigned cur_group = 0;
 	unsigned cur_action = 0;
+	USE_FEATURE_FIND_NOT( smallint invert_flag = 0; )
 
 	action* alloc_action(int sizeof_struct, action_fp f)
 	{
@@ -339,11 +351,12 @@ static action*** parse_params(char **argv)
 		appp[cur_group][cur_action++] = ap = xmalloc(sizeof_struct);
 		appp[cur_group][cur_action] = NULL;
 		ap->f = f;
+		USE_FEATURE_FIND_NOT( ap->invert = invert_flag; )
 		return ap;
 	}
 #define ALLOC_ACTION(name) (action_##name*)alloc_action(sizeof(action_##name), (action_fp) func_##name)
 
-	appp = xzalloc(2 * sizeof(*appp)); /* appp[0],[1] == NULL */
+	appp = xzalloc(2 * sizeof(appp[0])); /* appp[0],[1] == NULL */
 
 // Actions have side effects and return a true or false value
 // We implement: -print, -print0, -exec
@@ -367,27 +380,39 @@ static action*** parse_params(char **argv)
 		if (strcmp(arg, "-a") == 0
 		    USE_DESKTOP(|| strcmp(arg, "-and") == 0)
 		) {
-			/* no special handling required */
+			USE_FEATURE_FIND_NOT( invert_flag = 0; )
+			/* no further special handling required */
 		}
 		else if (strcmp(arg, "-o") == 0
 		         USE_DESKTOP(|| strcmp(arg, "-or") == 0)
 		) {
 			/* start new OR group */
+			USE_FEATURE_FIND_NOT( invert_flag = 0; )
 			cur_group++;
 			appp = xrealloc(appp, (cur_group+2) * sizeof(*appp));
-			appp[cur_group] = NULL;
+			/*appp[cur_group] = NULL; - already NULL */
 			appp[cur_group+1] = NULL;
 			cur_action = 0;
 		}
+#if ENABLE_FEATURE_FIND_NOT
+		else if (LONE_CHAR(arg, '!')
+		         USE_DESKTOP(|| strcmp(arg, "-not") == 0)
+		) {
+			invert_flag = 1;
+		}
+#endif
 
 	/* --- Tests and actions --- */
 		else if (strcmp(arg, "-print") == 0) {
 			need_print = 0;
+			/* GNU find ignores '!' here: "find ! -print" */
+			USE_FEATURE_FIND_NOT( invert_flag = 0; )
 			(void) ALLOC_ACTION(print);
 		}
 #if ENABLE_FEATURE_FIND_PRINT0
 		else if (strcmp(arg, "-print0") == 0) {
 			need_print = 0;
+			USE_FEATURE_FIND_NOT( invert_flag = 0; )
 			(void) ALLOC_ACTION(print0);
 		}
 #endif
@@ -471,6 +496,7 @@ static action*** parse_params(char **argv)
 			int i;
 			action_exec *ap;
 			need_print = 0;
+			USE_FEATURE_FIND_NOT( invert_flag = 0; )
 			ap = ALLOC_ACTION(exec);
 			ap->exec_argv = ++argv; /* first arg after -exec */
 			ap->exec_argc = 0;
@@ -524,6 +550,7 @@ static action*** parse_params(char **argv)
 			argv = endarg;
 		}
 		else if (strcmp(arg, "-prune") == 0) {
+			USE_FEATURE_FIND_NOT( invert_flag = 0; )
 			(void) ALLOC_ACTION(prune);
 		}
 		else if (strcmp(arg, "-size") == 0) {
@@ -555,6 +582,8 @@ int find_main(int argc, char **argv)
 	for (firstopt = 1; firstopt < argc; firstopt++) {
 		if (argv[firstopt][0] == '-')
 			break;
+		if (ENABLE_FEATURE_FIND_NOT && LONE_CHAR(argv[firstopt], '!'))
+			break;
 #if ENABLE_DESKTOP
 		if (LONE_CHAR(argv[firstopt], '('))
 			break;
diff --git a/shell/msh.c b/shell/msh.c
index 817b84093..a2da540b3 100644
--- a/shell/msh.c
+++ b/shell/msh.c
@@ -1278,7 +1278,7 @@ struct op *scantree(struct op *head)
 
 	DBGPRINTF5(("SCANTREE: checking node %p\n", head));
 
-	if ((head->type != TDOT) && (strcmp(".", head->words[0]) == 0)) {
+	if ((head->type != TDOT) && LONE_CHAR(head->words[0], '.')) {
 		DBGPRINTF5(("SCANTREE: dot found in node %p\n", head));
 		return head;
 	}
-- 
cgit v1.2.3-55-g6feb