[PATCH] N-ary event operators

Casey Dahlin cdahlin at redhat.com
Tue Aug 11 22:33:23 BST 2009


This makes EventOperators N-ary rather than binary trees. It 
auto-optimizes them with a new event_operator_add_child helper that 
simply gifts all of the new child's children to the new parent rather 
than attaching it when the new parent and child are of the same type.

This makes it a bit easier to make qualitative statements about trees, 
particularly "this tree only contains OR operators," which should become 
useful as AND operators become deprecated in future state models.


=== modified file 'ChangeLog'
--- ChangeLog	2009-08-04 08:51:25 +0000
+++ ChangeLog	2009-08-11 05:51:31 +0000
@@ -1,3 +1,60 @@
+2009-08-11  Casey Dahlin  <cdahlin at redhat.com>
+
+	* init/event_operator.h (EventOperatorType): Change types from AND/OR to
+	ANY/ALL
+
+	(EventOperator): Get rid of node entry and add children list.
+
+	* init/event_operator.c (event_operator_subtree_environment): New
+	version of event_operator_environment that assumes we are not at the
+	root of the tree.
+
+	(event_operator_new): Initialize new children member instead of tree
+	node.
+
+	(event_operator_copy): Use recursive call to correctly copy N-ary tree
+
+	(event_operator_reset): Use recursive call to correctly reset N-ary tree
+
+	(event_operator_events): Use recursive call to correctly get events from
+	N-ary tree.
+
+	(event_operator_handle): Use recursive call to correctly handle N-ary
+	tree.
+
+	(event_operator_update): Update based on all N children
+
+	(event_operator_match): Don't assert based on now-defunct node
+
+	(event_operator_add_child): New helper to add a child to a tree,
+	automatically collapsing it into its new parent if it is the same type.
+
+	(event_operator_destroy): Destroy children list head correctly.
+
+	(event_operator_environment): Use new event_operator_subtree_environment
+	to recursively collect environment variables.
+
+	* init/parse_job.c (parse_on_operator): Change AND/OR to ANY/ALL. Change
+	tree adds to event_operator_add_child calls.
+
+	(parse_on_collect): Change tree adds to event_operator_add_child calls
+
+	* init/tests/test_event.c (test_pending_handle_jobs): Fix structural
+	assumptions about EventOperator.
+
+	(test_finish): Change AND/OR to ANY/ALL
+
+	* init/tests/test_event_operator.c (everywhere): Fix structural
+	assumptions about EventOperator.
+
+	(test_operator_add_child): New test for this new helper.
+
+	* init/tests/test_job_process.c (everywhere): Fix structural assumptions
+	about EventOperator
+
+	* init/tests/test_parse_job.c (everywhere): Fix structural assumptions
+	about EventOperator
+
  2009-08-04  Johan Kiviniemi  <johan at kiviniemi.name>

  	* conf/rc-sysinit.conf: Don't replace DEFAULT_RUNLEVEL with an

=== modified file 'init/event_operator.c'
--- init/event_operator.c	2009-06-23 09:29:35 +0000
+++ init/event_operator.c	2009-08-11 05:12:01 +0000
@@ -43,6 +43,9 @@
  #include "blocked.h"
  #include "errors.h"

+static char** event_operator_subtree_environment
+		(EventOperator *oper, char ***env, const void *parent,
+		 size_t *len, const char *key, char **evlist);

  /**
   * event_operator_new:
@@ -85,7 +88,8 @@
  	if (! oper)
  		return NULL;

-	nih_tree_init (&oper->node);
+	nih_list_init (&oper->entry);
+	nih_list_init (&oper->children);

  	oper->type = type;
  	oper->value = FALSE;
@@ -163,33 +167,51 @@
  		event_block (oper->event);
  	}

-	if (old_oper->node.left) {
-		child = event_operator_copy (
-			oper, (EventOperator *)old_oper->node.left);
-		if (! child) {
-			nih_free (oper);
-			return NULL;
-		}
-
-		nih_tree_add (&oper->node, &child->node, NIH_TREE_LEFT);
-	}
-
-
-	if (old_oper->node.right) {
-		child = event_operator_copy (
-			oper, (EventOperator *)old_oper->node.right);
-		if (! child) {
-			nih_free (oper);
-			return NULL;
-		}
-
-		nih_tree_add (&oper->node, &child->node, NIH_TREE_RIGHT);
+	NIH_LIST_FOREACH (&old_oper->children, iter) {
+		EventOperator *child = event_operator_copy (
+				       oper, (EventOperator *)iter);
+		if (! child) {
+			nih_free (oper);
+			return NULL;
+		}
+
+		event_operator_add_child (oper, child);
  	}

  	return oper;
  }

  /**
+ * event_operator_add_child:
+ * @oper: oper to add child to,
+ * @child: child to add.
+ *
+ * Makes @child a child of @oper. If @child and @oper are the same 
type, then
+ * @oper simply steals all of @child's children.
+ **/
+void
+event_operator_add_child (EventOperator *oper, EventOperator *child)
+{
+	nih_assert (oper != NULL);
+	nih_assert (child != NULL);
+	nih_assert (oper->type != EVENT_MATCH);
+
+	if (child->type != oper->type) {
+		nih_ref (child, oper);
+		nih_list_add (&oper->children, &child->entry);
+		return;
+	}
+
+	NIH_LIST_FOREACH_SAFE (&child->children, iter) {
+		EventOperator *grandchild = (EventOperator *)iter;
+
+		nih_ref (grandchild, oper);
+		nih_unref (grandchild, child);
+		nih_list_add (&oper->children, &grandchild->entry);
+	}
+}
+
+/**
   * event_operator_destroy:
   * @oper: operator to be destroyed.
   *
@@ -209,7 +231,7 @@
  	if (oper->event)
  		event_unblock (oper->event);

-	nih_tree_destroy (&oper->node);
+	nih_list_destroy (&oper->entry);

  	return 0;
  }
@@ -227,24 +249,17 @@
  void
  event_operator_update (EventOperator *oper)
  {
-	EventOperator *left, *right;
-
  	nih_assert (oper != NULL);
-	nih_assert (oper->node.left != NULL);
-	nih_assert (oper->node.right != NULL);
-
-	left = (EventOperator *)oper->node.left;
-	right = (EventOperator *)oper->node.right;
-
-	switch (oper->type) {
-	case EVENT_OR:
-		oper->value = (left->value || right->value);
-		break;
-	case EVENT_AND:
-		oper->value = (left->value && right->value);
-		break;
-	default:
-		nih_assert_not_reached ();
+	nih_assert (oper->type != EVENT_MATCH);
+
+	oper->value = (oper->type == EVENT_ALL) ? TRUE : FALSE;
+
+	NIH_LIST_FOREACH (&oper->children, iter) {
+		EventOperator *child = (EventOperator *)iter;
+		if (child->value != oper->value) {
+			oper->value = child->value;
+			return;
+		}
  	}
  }

@@ -280,8 +295,6 @@

  	nih_assert (oper != NULL);
  	nih_assert (oper->type == EVENT_MATCH);
-	nih_assert (oper->node.left == NULL);
-	nih_assert (oper->node.right == NULL);
  	nih_assert (event != NULL);

  	/* Names must match */
@@ -391,29 +404,30 @@
  	 * before we update the node itself.  Simply iterate the tree and
  	 * update the nodes.
  	 */
-	NIH_TREE_FOREACH_POST (&root->node, iter) {
+	NIH_LIST_FOREACH (&root->children, iter) {
  		EventOperator *oper = (EventOperator *)iter;

-		switch (oper->type) {
-		case EVENT_OR:
-		case EVENT_AND:
-			event_operator_update (oper);
-			break;
-		case EVENT_MATCH:
-			if ((! oper->value)
-			    && event_operator_match (oper, event, env)) {
-				oper->value = TRUE;
-
-				oper->event = event;
-				event_block (oper->event);
-
-				ret = TRUE;
-			}
-			break;
-		default:
-			nih_assert_not_reached ();
+		ret = ret || event_operator_handle (oper, event, env);
+	}
+
+	switch (root->type) {
+	case EVENT_ANY:
+	case EVENT_ALL:
+		event_operator_update (root);
+		break;
+	case EVENT_MATCH:
+		if ((! root->value)
+		    && event_operator_match (root, event, env)) {
+			root->value = TRUE;
+
+			root->event = event;
+			event_block (root->event);
+
+			ret = TRUE;
  		}
-
+		break;
+	default:
+		nih_assert_not_reached ();
  	}

  	return ret;
@@ -501,38 +515,9 @@
  			return NULL;
  	}

-	/* Iterate the operator tree, filtering out nodes with a non-TRUE
-	 * value and their children.  The rationale for this is that this
-	 * then matches only the events that had an active role in starting
-	 * the job, not the ones that were also blocked, but the other half
-	 * of their logic wasn't present.
-	 */
-	NIH_TREE_FOREACH_FULL (&root->node, iter,
-			       (NihTreeFilter)event_operator_filter, NULL) {
-		EventOperator *oper = (EventOperator *)iter;
-
-		if (oper->type != EVENT_MATCH)
-			continue;
-
-		nih_assert (oper->event != NULL);
-
-		/* Add environment from the event */
-		if (! environ_append (env, parent, len, TRUE, oper->event->env))
-			return NULL;
-
-		/* Append the name of the event to the string we're building */
-		if (evlist) {
-			if (evlist[strlen (evlist) - 1] != '=') {
-				if (! nih_strcat_sprintf (&evlist, NULL, " %s",
-							  oper->event->name))
-					return NULL;
-			} else {
-				if (! nih_strcat (&evlist, NULL,
-						  oper->event->name))
-					return NULL;
-			}
-		}
-	}
+	if (! event_operator_subtree_environment (root, env, parent,
+					          len, key, &evlist))
+		return NULL;

  	/* Append the event list to the environment */
  	if (evlist)
@@ -543,6 +528,68 @@
  }

  /**
+ * event_operator_subtree_environment:
+ * @root: operator tree to collect from,
+ * @env: NULL-terminated array of environment variables to add to,
+ * @parent: parent object for new array,
+ * @len: length of @env,
+ * @key: key of variable to contain event names,
+ * @evlist: string in which to accumulate the event list.
+ *
+ * Does the work of event_operator_environment for one subtree.
+ **/
+
+static char**
+event_operator_subtree_environment (EventOperator   *oper,
+				    char          ***env,
+				    const void      *parent,
+				    size_t          *len,
+				    const char      *key,
+				    char           **evlist)
+{
+	/* Filtering out nodes with a non-TRUE value and their children. The
+	 * rationale for this is that this then matches only the events that had
+	 * an active role in starting the job, not the ones that were also
+	 * blocked, but the other half of their logic wasn't present.
+	 */
+	if (! oper->value)
+		return *env;
+
+	if (oper->type != EVENT_MATCH) {
+		NIH_LIST_FOREACH(&oper->children, iter) {
+			EventOperator *child = (EventOperator *)iter;
+			if (! event_operator_subtree_environment (child, env, parent,
+							          len, key, evlist))
+				return NULL;
+		}
+
+		return *env;
+	}
+
+	nih_assert (oper->event != NULL);
+
+	/* Add environment from the event */
+	if (! environ_append (env, parent, len, TRUE, oper->event->env))
+		return NULL;
+
+	/* Append the name of the event to the string we're building */
+	if (*evlist) {
+		if ((*evlist)[strlen (*evlist) - 1] != '=') {
+			if (! nih_strcat_sprintf (evlist, NULL, " %s",
+						  oper->event->name))
+				return NULL;
+		} else {
+			if (! nih_strcat (evlist, NULL,
+					  oper->event->name)) {
+				return NULL;
+			}
+		}
+	}
+
+	return *env;
+}
+
+/**
   * event_operator_events:
   * @root: operator tree to collect from,
   * @parent: parent object for blocked structures,
@@ -564,31 +611,31 @@
  		       const void    *parent,
  		       NihList       *list)
  {
+	Blocked       *blocked;
+
  	nih_assert (root != NULL);
  	nih_assert (list != NULL);

-	/* Iterate the operator tree, filtering out nodes with a non-TRUE
-	 * value and their children.  The rationale for this is that this
-	 * then matches only the events that had an active role in starting
-	 * the job, not the ones that were also blocked, but the other half
-	 * of their logic wasn't present.
-	 */
-	NIH_TREE_FOREACH_FULL (&root->node, iter,
-			       (NihTreeFilter)event_operator_filter, NULL) {
+	if (! root->value)
+		return;
+
+	NIH_LIST_FOREACH (&root->children, iter) {
  		EventOperator *oper = (EventOperator *)iter;
-		Blocked       *blocked;
-
-		if (oper->type != EVENT_MATCH)
-			continue;
-
-		nih_assert (oper->event != NULL);
-
-		blocked = NIH_MUST (blocked_new (parent, BLOCKED_EVENT,
-						 oper->event));
-		nih_list_add (list, &blocked->entry);
-
-		event_block (blocked->event);
+
+		event_operator_events (oper, parent, list);
  	}
+
+
+	if (root->type != EVENT_MATCH)
+		return;
+
+	nih_assert (root->event != NULL);
+
+	blocked = NIH_MUST (blocked_new (parent, BLOCKED_EVENT,
+					 root->event));
+	nih_list_add (list, &blocked->entry);
+
+	event_block (blocked->event);
  }


@@ -606,24 +653,26 @@
  	nih_assert (root != NULL);

  	/* A post-order iteration means we visit children first, perfect! */
-	NIH_TREE_FOREACH_POST (&root->node, iter) {
+	NIH_LIST_FOREACH (&root->children, iter) {
  		EventOperator *oper = (EventOperator *)iter;

-		switch (oper->type) {
-		case EVENT_OR:
-		case EVENT_AND:
-			event_operator_update (oper);
-			break;
-		case EVENT_MATCH:
-			oper->value = FALSE;
-
-			if (oper->event) {
-				event_unblock (oper->event);
-				oper->event = NULL;
-			}
-			break;
-		default:
-			nih_assert_not_reached ();
+		event_operator_reset (oper);
+	}
+
+	switch (root->type) {
+	case EVENT_ANY:
+	case EVENT_ALL:
+		event_operator_update (root);
+		break;
+	case EVENT_MATCH:
+		root->value = FALSE;
+
+		if (root->event) {
+			event_unblock (root->event);
+			root->event = NULL;
  		}
+		break;
+	default:
+		nih_assert_not_reached ();
  	}
  }

=== modified file 'init/event_operator.h'
--- init/event_operator.h	2009-06-23 09:29:35 +0000
+++ init/event_operator.h	2009-08-11 05:12:01 +0000
@@ -33,14 +33,15 @@
   * the EventOperator structure.
   **/
  typedef enum event_operator_type {
-	EVENT_OR,
-	EVENT_AND,
+	EVENT_ANY,
+	EVENT_ALL,
  	EVENT_MATCH
  } EventOperatorType;

  /**
   * EventOperator:
- * @node: tree node,
+ * @entry: sibling list entry,
+ * @children: list of children,
   * @type: operator type,
   * @value: operator value,
   * @name: name of event to match (EVENT_MATCH only),
@@ -49,19 +50,20 @@
   *
   * This structure is used to build up an event expression tree; the leaf
   * nodes are all of EVENT_MATCH type which match a specific event, the 
other
- * nodes are built up of EVENT_OR and EVENT_AND operators that combine the
- * EventOperators to their left and right in interesting ways.
+ * nodes are built up of EVENT_ANY and EVENT_ALL operators that combine the
+ * EventOperators which are their children in interesting ways.
   *
   * @value indicates whether this operator is currently TRUE or FALSE.
   * For EVENT_MATCH operators, a TRUE @value means that @event is set to
- * the matched event; for EVENT_OR and EVENT_AND operators, @value is set
- * depending on the value of both immediate children.
+ * the matched event; for EVENT_ANY and EVENT_ALL operators, @value is set
+ * depending on the value of the immediate children.
   *
   * Once an event has been matched, the @event member is set and a 
reference
   * held until the structure is cleared.
   **/
  typedef struct event_operator {
-	NihTree             node;
+	NihList             entry;
+	NihList             children;
  	EventOperatorType   type;

  	int                 value;
@@ -84,6 +86,8 @@
  	__attribute__ ((warn_unused_result, malloc));

  int            event_operator_destroy     (EventOperator *oper);
+void           event_operator_add_child   (EventOperator *oper,
+		                           EventOperator *child);

  void           event_operator_update      (EventOperator *oper);
  int            event_operator_match       (EventOperator *oper, Event 
*event,

=== modified file 'init/parse_job.c'
--- init/parse_job.c	2009-07-09 11:01:53 +0000
+++ init/parse_job.c	2009-08-11 05:12:01 +0000
@@ -644,9 +644,9 @@
  	 * back to the starting position and deal with it as an operand.
  	 */
  	if (! strcmp (arg, "and")) {
-		type = EVENT_AND;
+		type = EVENT_ALL;
  	} else if (! strcmp (arg, "or")) {
-		type = EVENT_OR;
+		type = EVENT_ANY;
  	} else {
  		return parse_on_operand (class, stanza, file, len, pos, lineno,
  					 stack, root);
@@ -665,10 +665,8 @@
  	if (! oper)
  		nih_return_system_error (-1);

-	nih_ref (*root, oper);
+	event_operator_add_child (oper, *root);
  	nih_unref (*root, class);
-
-	nih_tree_add (&oper->node, &(*root)->node, NIH_TREE_LEFT);
  	*root = NULL;

  	/* Push the new operator onto the stack */
@@ -938,11 +936,8 @@
  		 * event matches.
  		 */
  		if ((oper->type != EVENT_MATCH) && (*root)) {
-			nih_ref (*root, oper);
+			event_operator_add_child (oper, *root);
  			nih_unref (*root, class);
-
-			nih_tree_add (&oper->node, &(*root)->node,
-				      NIH_TREE_RIGHT);
  		} else if (oper->type != EVENT_MATCH) {
  			nih_return_error (-1, PARSE_EXPECTED_EVENT,
  					  _(PARSE_EXPECTED_EVENT_STR));

=== modified file 'init/tests/test_event.c'
--- init/tests/test_event.c	2009-08-04 00:19:41 +0000
+++ init/tests/test_event.c	2009-08-11 05:51:31 +0000
@@ -275,6 +275,7 @@
  	EventOperator  *oper;
  	Blocked        *blocked = NULL, *blocked1 = NULL, *blocked2 = NULL;
  	char          **env1 = NULL, **env2 = NULL;
+	int             any_true = FALSE, all_true = TRUE;

  	TEST_FUNCTION ("event_pending_handle_jobs");
  	program_name = "test";
@@ -331,17 +332,15 @@
  			class->task = TRUE;

  			class->start_on = event_operator_new (
-				class, EVENT_AND, NULL, NULL);
+				class, EVENT_ALL, NULL, NULL);

  			oper = event_operator_new (
  				class->start_on, EVENT_MATCH, "wibble", NULL);
-			nih_tree_add (&class->start_on->node, &oper->node,
-				      NIH_TREE_LEFT);
+			event_operator_add_child (class->start_on, oper);

  			oper = event_operator_new (
  				class->start_on, EVENT_MATCH, "wobble", NULL);
-			nih_tree_add (&class->start_on->node, &oper->node,
-				      NIH_TREE_RIGHT);
+			event_operator_add_child (class->start_on, oper);

  			nih_hash_add (job_classes, &class->entry);
  		}
@@ -358,13 +357,18 @@
  		TEST_EQ (oper->value, FALSE);
  		TEST_EQ_P (oper->event, NULL);

-		oper = (EventOperator *)class->start_on->node.left;
-		TEST_EQ (oper->value, TRUE);
-		TEST_EQ_P (oper->event, event1);
-
-		oper = (EventOperator *)class->start_on->node.right;
-		TEST_EQ (oper->value, FALSE);
-		TEST_EQ_P (oper->event, NULL);
+		NIH_LIST_FOREACH (&oper->children, iter) {
+			EventOperator *child = (EventOperator *)iter;
+
+			any_true = any_true || child->value;
+			all_true = all_true && child->value;
+		}
+
+		TEST_EQ (any_true, TRUE);
+		TEST_EQ (all_true, FALSE);
+		
+		any_true = FALSE;
+		all_true = TRUE;

  		nih_free (class);
  		nih_free (event1);
@@ -395,17 +399,15 @@
  						   NULL, "BAR=BAZ"));

  			class->start_on = event_operator_new (
-				class, EVENT_AND, NULL, NULL);
+				class, EVENT_ALL, NULL, NULL);

  			oper = event_operator_new (
  				class->start_on, EVENT_MATCH, "wibble", NULL);
-			nih_tree_add (&class->start_on->node, &oper->node,
-				      NIH_TREE_LEFT);
+			event_operator_add_child (class->start_on, oper);

  			oper = event_operator_new (
  				class->start_on, EVENT_MATCH, "wobble", NULL);
-			nih_tree_add (&class->start_on->node, &oper->node,
-				      NIH_TREE_RIGHT);
+			event_operator_add_child (class->start_on, oper);

  			nih_hash_add (job_classes, &class->entry);
  		}
@@ -447,14 +449,18 @@
  		TEST_EQ (oper->value, FALSE);
  		TEST_EQ_P (oper->event, NULL);

-		oper = (EventOperator *)class->start_on->node.left;
-		TEST_EQ (oper->value, FALSE);
-		TEST_EQ_P (oper->event, NULL);
-
-		oper = (EventOperator *)class->start_on->node.right;
-		TEST_EQ (oper->value, FALSE);
-		TEST_EQ_P (oper->event, NULL);
-
+		NIH_LIST_FOREACH (&oper->children, iter) {
+			EventOperator *child = (EventOperator *)iter;
+
+			any_true = any_true || child->value;
+			all_true = all_true && child->value;
+		}
+
+		TEST_EQ (any_true, FALSE);
+		TEST_EQ (all_true, FALSE);
+		
+		any_true = FALSE;
+		all_true = TRUE;

  		TEST_LIST_NOT_EMPTY (&job->blocking);

@@ -511,17 +517,15 @@
  						   NULL, "BAR=BAZ"));

  			class->start_on = event_operator_new (
-				class, EVENT_AND, NULL, NULL);
+				class, EVENT_ALL, NULL, NULL);

  			oper = event_operator_new (
  				class->start_on, EVENT_MATCH, "wibble", NULL);
-			nih_tree_add (&class->start_on->node, &oper->node,
-				      NIH_TREE_LEFT);
+			event_operator_add_child (class->start_on, oper);

  			oper = event_operator_new (
  				class->start_on, EVENT_MATCH, "wobble", NULL);
-			nih_tree_add (&class->start_on->node, &oper->node,
-				      NIH_TREE_RIGHT);
+			event_operator_add_child (class->start_on, oper);

  			nih_hash_add (job_classes, &class->entry);
  		}
@@ -572,13 +576,18 @@
  		oper = class->start_on;
  		TEST_EQ (oper->value, FALSE);

-		oper = (EventOperator *)class->start_on->node.left;
-		TEST_EQ (oper->value, FALSE);
-		TEST_EQ_P (oper->event, NULL);
-
-		oper = (EventOperator *)class->start_on->node.right;
-		TEST_EQ (oper->value, FALSE);
-		TEST_EQ_P (oper->event, NULL);
+		NIH_LIST_FOREACH (&oper->children, iter) {
+			EventOperator *child = (EventOperator *)iter;
+
+			any_true = any_true || child->value;
+			all_true = all_true && child->value;
+		}
+
+		TEST_EQ (any_true, FALSE);
+		TEST_EQ (all_true, FALSE);
+		
+		any_true = FALSE;
+		all_true = TRUE;


  		TEST_LIST_NOT_EMPTY (&job->blocking);
@@ -637,17 +646,15 @@
  						   NULL, "BAR=BAZ"));

  			class->start_on = event_operator_new (
-				class, EVENT_AND, NULL, NULL);
+				class, EVENT_ALL, NULL, NULL);

  			oper = event_operator_new (
  				class->start_on, EVENT_MATCH, "wibble", NULL);
-			nih_tree_add (&class->start_on->node, &oper->node,
-				      NIH_TREE_LEFT);
+			event_operator_add_child (class->start_on, oper);

  			oper = event_operator_new (
  				class->start_on, EVENT_MATCH, "wobble", NULL);
-			nih_tree_add (&class->start_on->node, &oper->node,
-				      NIH_TREE_RIGHT);
+			event_operator_add_child (class->start_on, oper);

  			nih_hash_add (job_classes, &class->entry);

@@ -736,13 +743,18 @@
  		oper = class->start_on;
  		TEST_EQ (oper->value, FALSE);

-		oper = (EventOperator *)class->start_on->node.left;
-		TEST_EQ (oper->value, FALSE);
-		TEST_EQ_P (oper->event, NULL);
-
-		oper = (EventOperator *)class->start_on->node.right;
-		TEST_EQ (oper->value, FALSE);
-		TEST_EQ_P (oper->event, NULL);
+		NIH_LIST_FOREACH (&oper->children, iter) {
+			EventOperator *child = (EventOperator *)iter;
+
+			any_true = any_true || child->value;
+			all_true = all_true && child->value;
+		}
+
+		TEST_EQ (any_true, FALSE);
+		TEST_EQ (all_true, FALSE);
+		
+		any_true = FALSE;
+		all_true = TRUE;

  		TEST_FREE (blocked1);
  		TEST_FREE (blocked2);
@@ -805,17 +817,15 @@
  						   NULL, "BAR=BAZ"));

  			class->start_on = event_operator_new (
-				class, EVENT_AND, NULL, NULL);
+				class, EVENT_ALL, NULL, NULL);

  			oper = event_operator_new (
  				class->start_on, EVENT_MATCH, "wibble", NULL);
-			nih_tree_add (&class->start_on->node, &oper->node,
-				      NIH_TREE_LEFT);
+			event_operator_add_child (class->start_on, oper);

  			oper = event_operator_new (
  				class->start_on, EVENT_MATCH, "wobble", NULL);
-			nih_tree_add (&class->start_on->node, &oper->node,
-				      NIH_TREE_RIGHT);
+			event_operator_add_child (class->start_on, oper);

  			nih_hash_add (job_classes, &class->entry);

@@ -886,13 +896,18 @@
  		oper = class->start_on;
  		TEST_EQ (oper->value, FALSE);

-		oper = (EventOperator *)class->start_on->node.left;
-		TEST_EQ (oper->value, FALSE);
-		TEST_EQ_P (oper->event, NULL);
-
-		oper = (EventOperator *)class->start_on->node.right;
-		TEST_EQ (oper->value, FALSE);
-		TEST_EQ_P (oper->event, NULL);
+		NIH_LIST_FOREACH (&oper->children, iter) {
+			EventOperator *child = (EventOperator *)iter;
+
+			any_true = any_true || child->value;
+			all_true = all_true && child->value;
+		}
+
+		TEST_EQ (any_true, FALSE);
+		TEST_EQ (all_true, FALSE);
+		
+		any_true = FALSE;
+		all_true = TRUE;

  		TEST_LIST_NOT_EMPTY (&job->blocking);
  		TEST_NOT_FREE (blocked1);
@@ -1704,17 +1719,15 @@
  			class->process[PROCESS_MAIN]->command = "echo";

  			class->start_on = event_operator_new (
-				class, EVENT_OR, NULL, NULL);
+				class, EVENT_ANY, NULL, NULL);

  			oper = event_operator_new (class, EVENT_MATCH,
  						   "test/failed", NULL);
-			nih_tree_add (&class->start_on->node, &oper->node,
-				      NIH_TREE_LEFT);
+			event_operator_add_child (class->start_on, oper);

  			oper = event_operator_new (class, EVENT_MATCH,
  						   "test/failed/failed", NULL);
-			nih_tree_add (&class->start_on->node, &oper->node,
-				      NIH_TREE_RIGHT);
+			event_operator_add_child (class->start_on, oper);

  			nih_hash_add (job_classes, &class->entry);
  		}

=== modified file 'init/tests/test_event_operator.c'
--- init/tests/test_event_operator.c	2009-08-04 00:20:04 +0000
+++ init/tests/test_event_operator.c	2009-08-11 05:51:31 +0000
@@ -53,9 +53,7 @@
  		}

  		TEST_ALLOC_SIZE (oper, sizeof (EventOperator));
-		TEST_EQ_P (oper->node.parent, NULL);
-		TEST_EQ_P (oper->node.left, NULL);
-		TEST_EQ_P (oper->node.right, NULL);
+		TEST_LIST_EMPTY (&oper->children);
  		TEST_EQ (oper->value, FALSE);
  		TEST_EQ_STR (oper->name, "test");
  		TEST_ALLOC_PARENT (oper->name, oper);
@@ -92,9 +90,7 @@
  		nih_discard (env);

  		TEST_ALLOC_SIZE (oper, sizeof (EventOperator));
-		TEST_EQ_P (oper->node.parent, NULL);
-		TEST_EQ_P (oper->node.left, NULL);
-		TEST_EQ_P (oper->node.right, NULL);
+		TEST_LIST_EMPTY (&oper->children);
  		TEST_EQ (oper->value, FALSE);
  		TEST_EQ_STR (oper->name, "test");
  		TEST_ALLOC_PARENT (oper->name, oper);
@@ -109,9 +105,9 @@


  	/* Check that an ordinary operator needs no name attached. */
-	TEST_FEATURE ("with EVENT_OR");
+	TEST_FEATURE ("with EVENT_ANY");
  	TEST_ALLOC_FAIL {
-		oper = event_operator_new (NULL, EVENT_OR, NULL, NULL);
+		oper = event_operator_new (NULL, EVENT_ANY, NULL, NULL);

  		if (test_alloc_failed) {
  			TEST_EQ_P (oper, NULL);
@@ -119,9 +115,7 @@
  		}

  		TEST_ALLOC_SIZE (oper, sizeof (EventOperator));
-		TEST_EQ_P (oper->node.parent, NULL);
-		TEST_EQ_P (oper->node.left, NULL);
-		TEST_EQ_P (oper->node.right, NULL);
+		TEST_LIST_EMPTY (&oper->children);
  		TEST_EQ (oper->value, FALSE);
  		TEST_EQ_P (oper->name, NULL);
  		TEST_EQ_P (oper->env, NULL);
@@ -143,10 +137,10 @@
  	/* Check that we can copy a plain event operator, the value should
  	 * be copied as well, and the other fields left as NULL.
  	 */
-	TEST_FEATURE ("with EVENT_OR");
+	TEST_FEATURE ("with EVENT_ANY");
  	TEST_ALLOC_FAIL {
  		TEST_ALLOC_SAFE {
-			oper = event_operator_new (NULL, EVENT_OR, NULL, NULL);
+			oper = event_operator_new (NULL, EVENT_ANY, NULL, NULL);
  			oper->value = TRUE;
  		}

@@ -159,10 +153,8 @@
  		}

  		TEST_ALLOC_SIZE (copy, sizeof (EventOperator));
-		TEST_EQ_P (copy->node.parent, NULL);
-		TEST_EQ_P (copy->node.left, NULL);
-		TEST_EQ_P (copy->node.right, NULL);
-		TEST_EQ (copy->type, EVENT_OR);
+		TEST_LIST_EMPTY (&copy->children);
+		TEST_EQ (copy->type, EVENT_ANY);
  		TEST_EQ (copy->value, TRUE);
  		TEST_EQ_P (copy->name, NULL);
  		TEST_EQ_P (copy->env, NULL);
@@ -193,9 +185,7 @@
  		}

  		TEST_ALLOC_SIZE (copy, sizeof (EventOperator));
-		TEST_EQ_P (copy->node.parent, NULL);
-		TEST_EQ_P (copy->node.left, NULL);
-		TEST_EQ_P (copy->node.right, NULL);
+		TEST_LIST_EMPTY (&copy->children);
  		TEST_EQ (copy->type, EVENT_MATCH);
  		TEST_EQ (copy->value, TRUE);
  		TEST_EQ_STR (copy->name, "test");
@@ -233,9 +223,7 @@
  		}

  		TEST_ALLOC_SIZE (copy, sizeof (EventOperator));
-		TEST_EQ_P (copy->node.parent, NULL);
-		TEST_EQ_P (copy->node.left, NULL);
-		TEST_EQ_P (copy->node.right, NULL);
+		TEST_LIST_EMPTY (&copy->children);
  		TEST_EQ (copy->type, EVENT_MATCH);
  		TEST_EQ (copy->value, TRUE);
  		TEST_EQ_STR (copy->name, "test");
@@ -279,9 +267,7 @@
  		}

  		TEST_ALLOC_SIZE (copy, sizeof (EventOperator));
-		TEST_EQ_P (copy->node.parent, NULL);
-		TEST_EQ_P (copy->node.left, NULL);
-		TEST_EQ_P (copy->node.right, NULL);
+		TEST_LIST_EMPTY (&copy->children);
  		TEST_EQ (copy->type, EVENT_MATCH);
  		TEST_EQ (copy->value, TRUE);
  		TEST_EQ_STR (copy->name, "test");
@@ -302,7 +288,7 @@
  	TEST_FEATURE ("with children");
  	TEST_ALLOC_FAIL {
  		TEST_ALLOC_SAFE {
-			oper = event_operator_new (NULL, EVENT_OR, NULL, NULL);
+			oper = event_operator_new (NULL, EVENT_ANY, NULL, NULL);
  			oper->value = TRUE;

  			oper1 = event_operator_new (NULL, EVENT_MATCH,
@@ -310,45 +296,37 @@
  			oper1->value = TRUE;
  			oper1->event = event_new (oper1, "foo", NULL);
  			event_block (oper1->event);
-			nih_tree_add (&oper->node, &oper1->node,
-				      NIH_TREE_LEFT);
+			event_operator_add_child (oper, oper1);

  			oper2 = event_operator_new (NULL, EVENT_MATCH,
  						    "bar", NULL);
  			oper2->value = TRUE;
  			oper2->event = event_new (oper2, "foo", NULL);
  			event_block (oper2->event);
-			nih_tree_add (&oper->node, &oper2->node,
-				      NIH_TREE_RIGHT);
+			event_operator_add_child (oper, oper2);
  		}

  		copy = event_operator_copy (NULL, oper);

  		if (test_alloc_failed) {
  			TEST_EQ_P (copy, NULL);
-			nih_free (oper);
  			TEST_EQ (oper1->event->blockers, 1);
-			nih_free (oper1);
  			TEST_EQ (oper2->event->blockers, 1);
-			nih_free (oper2);
+			nih_free (oper);
  			continue;
  		}

  		TEST_ALLOC_SIZE (copy, sizeof (EventOperator));
-		TEST_EQ_P (copy->node.parent, NULL);
-		TEST_NE_P (copy->node.left, NULL);
-		TEST_NE_P (copy->node.right, NULL);
-		TEST_EQ (copy->type, EVENT_OR);
+		TEST_LIST_NOT_EMPTY (&copy->children);
+		TEST_EQ (copy->type, EVENT_ANY);
  		TEST_EQ (copy->value, TRUE);
  		TEST_EQ_P (copy->name, NULL);
  		TEST_EQ_P (copy->env, NULL);

-		copy1 = (EventOperator *)copy->node.left;
+		copy1 = (EventOperator *)copy->children.next;
  		TEST_ALLOC_SIZE (copy1, sizeof (EventOperator));
  		TEST_ALLOC_PARENT (copy1, copy);
-		TEST_EQ_P (copy1->node.parent, &copy->node);
-		TEST_EQ_P (copy1->node.left, NULL);
-		TEST_EQ_P (copy1->node.right, NULL);
+		TEST_LIST_EMPTY (&copy1->children);
  		TEST_EQ (copy1->type, EVENT_MATCH);
  		TEST_EQ (copy1->value, TRUE);
  		TEST_EQ_STR (copy1->name, "foo");
@@ -360,12 +338,10 @@

  		nih_free (copy1);

-		copy2 = (EventOperator *)copy->node.right;
+		copy2 = (EventOperator *)copy1->entry.next;
  		TEST_ALLOC_SIZE (copy2, sizeof (EventOperator));
  		TEST_ALLOC_PARENT (copy2, copy);
-		TEST_EQ_P (copy2->node.parent, &copy->node);
-		TEST_EQ_P (copy2->node.left, NULL);
-		TEST_EQ_P (copy2->node.right, NULL);
+		TEST_LIST_EMPTY (&copy1->children);
  		TEST_EQ (copy2->type, EVENT_MATCH);
  		TEST_EQ (copy2->value, TRUE);
  		TEST_EQ_STR (copy2->name, "bar");
@@ -430,16 +406,16 @@
  	EventOperator *oper1, *oper2, *oper3;

  	TEST_FUNCTION ("event_operator_update");
-	oper1 = event_operator_new (NULL, EVENT_OR, NULL, NULL);
+	oper1 = event_operator_new (NULL, EVENT_ANY, NULL, NULL);
  	oper2 = event_operator_new (NULL, EVENT_MATCH, "foo", NULL);
  	oper3 = event_operator_new (NULL, EVENT_MATCH, "bar", NULL);

-	nih_tree_add (&oper1->node, &oper2->node, NIH_TREE_LEFT);
-	nih_tree_add (&oper1->node, &oper3->node, NIH_TREE_RIGHT);
-
-
-	/* Check that EVENT_OR is FALSE if both children are FALSE. */
-	TEST_FEATURE ("with EVENT_OR and both children FALSE");
+	event_operator_add_child (oper1, oper2);
+	event_operator_add_child (oper1, oper3);
+
+
+	/* Check that EVENT_ANY is FALSE if both children are FALSE. */
+	TEST_FEATURE ("with EVENT_ANY and both children FALSE");
  	oper1->value = oper2->value = oper3->value = FALSE;

  	event_operator_update (oper1);
@@ -447,8 +423,8 @@
  	TEST_EQ (oper1->value, FALSE);


-	/* Check that EVENT_OR is TRUE if only the left child is TRUE. */
-	TEST_FEATURE ("with EVENT_OR and only left child TRUE");
+	/* Check that EVENT_ANY is TRUE if only the left child is TRUE. */
+	TEST_FEATURE ("with EVENT_ANY and only left child TRUE");
  	oper1->value = oper3->value = FALSE;
  	oper2->value = TRUE;

@@ -457,8 +433,8 @@
  	TEST_EQ (oper1->value, TRUE);


-	/* Check that EVENT_OR is TRUE if only the right child is TRUE. */
-	TEST_FEATURE ("with EVENT_OR and only right child TRUE");
+	/* Check that EVENT_ANY is TRUE if only the right child is TRUE. */
+	TEST_FEATURE ("with EVENT_ANY and only right child TRUE");
  	oper1->value = oper2->value = FALSE;
  	oper3->value = TRUE;

@@ -467,8 +443,8 @@
  	TEST_EQ (oper1->value, TRUE);


-	/* Check that EVENT_OR is TRUE if both children are TRUE. */
-	TEST_FEATURE ("with EVENT_OR and both children TRUE");
+	/* Check that EVENT_ANY is TRUE if both children are TRUE. */
+	TEST_FEATURE ("with EVENT_ANY and both children TRUE");
  	oper1->value = FALSE;
  	oper2->value = oper3->value = TRUE;

@@ -477,9 +453,9 @@
  	TEST_EQ (oper1->value, TRUE);


-	/* Check that EVENT_AND is FALSE if both children are FALSE. */
-	TEST_FEATURE ("with EVENT_AND and both children FALSE");
-	oper1->type = EVENT_AND;
+	/* Check that EVENT_ALL is FALSE if both children are FALSE. */
+	TEST_FEATURE ("with EVENT_ALL and both children FALSE");
+	oper1->type = EVENT_ALL;
  	oper1->value = oper2->value = oper3->value = FALSE;

  	event_operator_update (oper1);
@@ -487,8 +463,8 @@
  	TEST_EQ (oper1->value, FALSE);


-	/* Check that EVENT_AND is FALSE if only the left child is TRUE. */
-	TEST_FEATURE ("with EVENT_AND and only left child TRUE");
+	/* Check that EVENT_ALL is FALSE if only the left child is TRUE. */
+	TEST_FEATURE ("with EVENT_ALL and only left child TRUE");
  	oper1->value = oper3->value = FALSE;
  	oper2->value = TRUE;

@@ -497,8 +473,8 @@
  	TEST_EQ (oper1->value, FALSE);


-	/* Check that EVENT_AND is FALSE if only the right child is TRUE. */
-	TEST_FEATURE ("with EVENT_AND and only right child TRUE");
+	/* Check that EVENT_ALL is FALSE if only the right child is TRUE. */
+	TEST_FEATURE ("with EVENT_ALL and only right child TRUE");
  	oper1->value = oper2->value = FALSE;
  	oper3->value = TRUE;

@@ -507,8 +483,8 @@
  	TEST_EQ (oper1->value, FALSE);


-	/* Check that EVENT_AND is TRUE if both children are TRUE. */
-	TEST_FEATURE ("with EVENT_AND and both children TRUE");
+	/* Check that EVENT_ALL is TRUE if both children are TRUE. */
+	TEST_FEATURE ("with EVENT_ALL and both children TRUE");
  	oper1->value = FALSE;
  	oper2->value = oper3->value = TRUE;

@@ -518,8 +494,6 @@


  	nih_free (oper1);
-	nih_free (oper2);
-	nih_free (oper3);
  }

  void
@@ -804,8 +778,8 @@
  	int            ret;

  	TEST_FUNCTION ("event_operator_handle");
-	oper1 = event_operator_new (NULL, EVENT_OR, NULL, NULL);
-	oper2 = event_operator_new (NULL, EVENT_AND, NULL, NULL);
+	oper1 = event_operator_new (NULL, EVENT_ANY, NULL, NULL);
+	oper2 = event_operator_new (NULL, EVENT_ALL, NULL, NULL);
  	oper3 = event_operator_new (NULL, EVENT_MATCH, "foo", NULL);
  	oper4 = event_operator_new (NULL, EVENT_MATCH, "bar", NULL);
  	oper5 = event_operator_new (NULL, EVENT_MATCH, "baz", NULL);
@@ -813,10 +787,10 @@
  	oper5->env[0] = "BAR=$WIBBLE";
  	oper5->env[1] = NULL;

-	nih_tree_add (&oper1->node, &oper2->node, NIH_TREE_LEFT);
-	nih_tree_add (&oper2->node, &oper3->node, NIH_TREE_LEFT);
-	nih_tree_add (&oper2->node, &oper4->node, NIH_TREE_RIGHT);
-	nih_tree_add (&oper1->node, &oper5->node, NIH_TREE_RIGHT);
+	event_operator_add_child (oper1, oper2);
+	event_operator_add_child (oper2, oper3);
+	event_operator_add_child (oper2, oper4);
+	event_operator_add_child (oper1, oper5);


  	/* Check that a non-matching event doesn't touch the tree. */
@@ -938,10 +912,6 @@
  	event_operator_reset (oper1);

  	nih_free (oper1);
-	nih_free (oper2);
-	nih_free (oper3);
-	nih_free (oper4);
-	nih_free (oper5);

  	event_poll ();
  }
@@ -956,20 +926,20 @@
  	size_t          len;

  	TEST_FUNCTION ("event_operator_environment");
-	root = event_operator_new (NULL, EVENT_OR, NULL, NULL);
-	oper1 = event_operator_new (root, EVENT_AND, NULL, NULL);
-	oper2 = event_operator_new (root, EVENT_AND, NULL, NULL);
+	root = event_operator_new (NULL, EVENT_ANY, NULL, NULL);
+	oper1 = event_operator_new (root, EVENT_ALL, NULL, NULL);
+	oper2 = event_operator_new (root, EVENT_ALL, NULL, NULL);
  	oper3 = event_operator_new (root, EVENT_MATCH, "foo", NULL);
  	oper4 = event_operator_new (root, EVENT_MATCH, "bar", NULL);
  	oper5 = event_operator_new (root, EVENT_MATCH, "frodo", NULL);
  	oper6 = event_operator_new (root, EVENT_MATCH, "bilbo", NULL);

-	nih_tree_add (&root->node, &oper1->node, NIH_TREE_LEFT);
-	nih_tree_add (&root->node, &oper2->node, NIH_TREE_RIGHT);
-	nih_tree_add (&oper1->node, &oper3->node, NIH_TREE_LEFT);
-	nih_tree_add (&oper1->node, &oper4->node, NIH_TREE_RIGHT);
-	nih_tree_add (&oper2->node, &oper5->node, NIH_TREE_LEFT);
-	nih_tree_add (&oper2->node, &oper6->node, NIH_TREE_RIGHT);
+	event_operator_add_child (root, oper1);
+	event_operator_add_child (root, oper2);
+	event_operator_add_child (oper1, oper3);
+	event_operator_add_child (oper1, oper4);
+	event_operator_add_child (oper2, oper5);
+	event_operator_add_child (oper2, oper6);

  	root->value = TRUE;

@@ -1124,20 +1094,20 @@
  	Blocked        *blocked;

  	TEST_FUNCTION ("event_operator_events");
-	root = event_operator_new (NULL, EVENT_OR, NULL, NULL);
-	oper1 = event_operator_new (root, EVENT_AND, NULL, NULL);
-	oper2 = event_operator_new (root, EVENT_AND, NULL, NULL);
+	root = event_operator_new (NULL, EVENT_ANY, NULL, NULL);
+	oper1 = event_operator_new (root, EVENT_ALL, NULL, NULL);
+	oper2 = event_operator_new (root, EVENT_ALL, NULL, NULL);
  	oper3 = event_operator_new (root, EVENT_MATCH, "foo", NULL);
  	oper4 = event_operator_new (root, EVENT_MATCH, "bar", NULL);
  	oper5 = event_operator_new (root, EVENT_MATCH, "frodo", NULL);
  	oper6 = event_operator_new (root, EVENT_MATCH, "bilbo", NULL);

-	nih_tree_add (&root->node, &oper1->node, NIH_TREE_LEFT);
-	nih_tree_add (&root->node, &oper2->node, NIH_TREE_RIGHT);
-	nih_tree_add (&oper1->node, &oper3->node, NIH_TREE_LEFT);
-	nih_tree_add (&oper1->node, &oper4->node, NIH_TREE_RIGHT);
-	nih_tree_add (&oper2->node, &oper5->node, NIH_TREE_LEFT);
-	nih_tree_add (&oper2->node, &oper6->node, NIH_TREE_RIGHT);
+	event_operator_add_child (root, oper1);
+	event_operator_add_child (root, oper2);
+	event_operator_add_child (oper1, oper3);
+	event_operator_add_child (oper1, oper4);
+	event_operator_add_child (oper2, oper5);
+	event_operator_add_child (oper2, oper6);

  	root->value = TRUE;

@@ -1232,16 +1202,16 @@
  	 * all the values back to FALSE.
  	 */
  	TEST_FUNCTION ("event_operator_reset");
-	oper1 = event_operator_new (NULL, EVENT_OR, NULL, NULL);
-	oper2 = event_operator_new (NULL, EVENT_AND, NULL, NULL);
+	oper1 = event_operator_new (NULL, EVENT_ANY, NULL, NULL);
+	oper2 = event_operator_new (NULL, EVENT_ALL, NULL, NULL);
  	oper3 = event_operator_new (NULL, EVENT_MATCH, "foo", NULL);
  	oper4 = event_operator_new (NULL, EVENT_MATCH, "bar", NULL);
  	oper5 = event_operator_new (NULL, EVENT_MATCH, "baz", NULL);

-	nih_tree_add (&oper1->node, &oper2->node, NIH_TREE_LEFT);
-	nih_tree_add (&oper2->node, &oper3->node, NIH_TREE_LEFT);
-	nih_tree_add (&oper2->node, &oper4->node, NIH_TREE_RIGHT);
-	nih_tree_add (&oper1->node, &oper5->node, NIH_TREE_RIGHT);
+	event_operator_add_child (oper1, oper2);
+	event_operator_add_child (oper2, oper3);
+	event_operator_add_child (oper2, oper4);
+	event_operator_add_child (oper1, oper5);

  	event1 = event_new (NULL, "foo", NULL);
  	event2 = event_new (NULL, "bar", NULL);
@@ -1274,15 +1244,73 @@
  	TEST_EQ (event2->blockers, 0);

  	nih_free (oper1);
-	nih_free (oper2);
-	nih_free (oper3);
-	nih_free (oper4);
-	nih_free (oper5);

  	event_poll ();
  }


+void
+test_operator_add_child (void)
+{
+	EventOperator *oper1, *oper2, *oper3, *oper4, *oper5, *oper6, *oper7;
+	int found_foo = 0;
+	int found_bar = 0;
+	int found_baz = 0;
+	int found_bam = 0;
+	int found_all = 0;
+
+	TEST_FUNCTION ("event_operator_add_child");
+	oper1 = event_operator_new (NULL, EVENT_ANY, NULL, NULL);
+	oper2 = event_operator_new (NULL, EVENT_ALL, NULL, NULL);
+	oper3 = event_operator_new (NULL, EVENT_MATCH, "foo", NULL);
+	oper4 = event_operator_new (NULL, EVENT_MATCH, "bar", NULL);
+	oper5 = event_operator_new (NULL, EVENT_MATCH, "baz", NULL);
+	oper6 = event_operator_new (NULL, EVENT_MATCH, "bam", NULL);
+	oper7 = event_operator_new (NULL, EVENT_ANY, NULL, NULL);
+
+	event_operator_add_child (oper2, oper3);
+	event_operator_add_child (oper2, oper4);
+	event_operator_add_child (oper7, oper5);
+	event_operator_add_child (oper7, oper6);
+	event_operator_add_child (oper1, oper2);
+	event_operator_add_child (oper1, oper7);
+
+	TEST_EQ (oper1->type, EVENT_ANY);
+
+	NIH_LIST_FOREACH (&oper1->children, iter) {
+		EventOperator *child = (EventOperator *)iter;
+
+		if (child->type == EVENT_ALL) {
+			found_all++;
+			continue;
+		}
+
+		TEST_EQ (child->type, EVENT_MATCH);
+
+		if (! strncmp (child->name, "foo", 4))
+			found_foo++;
+
+		if (! strncmp (child->name, "bar", 4))
+			found_bar++;
+
+		if (! strncmp (child->name, "baz", 4))
+			found_baz++;
+
+		if (! strncmp (child->name, "bam", 4))
+			found_bam++;
+	}
+
+	// Not a truth test. 2 is also a failure.
+	TEST_EQ (found_all, 1);
+	TEST_EQ (found_foo, 0);
+	TEST_EQ (found_bar, 0);
+	TEST_EQ (found_baz, 1);
+	TEST_EQ (found_bam, 1);
+
+	nih_free (oper1);
+}
+
+
  int
  main (int   argc,
        char *argv[])
@@ -1296,6 +1324,7 @@
  	test_operator_environment ();
  	test_operator_events ();
  	test_operator_reset ();
+	test_operator_add_child ();

  	return 0;
  }

=== modified file 'init/tests/test_parse_job.c'
--- init/tests/test_parse_job.c	2009-07-09 11:01:53 +0000
+++ init/tests/test_parse_job.c	2009-08-11 05:12:01 +0000
@@ -1714,11 +1714,12 @@
  void
  test_stanza_start (void)
  {
-	JobClass     *job;
+	JobClass      *job;
  	EventOperator *oper;
  	NihError      *err;
  	size_t         pos, lineno;
  	char           buf[1024];
+	int            got_wibble, got_wobble, got_wiggle;

  	TEST_FUNCTION ("stanza_start");

@@ -1757,9 +1758,7 @@
  		TEST_EQ_STR (oper->name, "wibble");
  		TEST_EQ_P (oper->env, NULL);

-		TEST_EQ_P (oper->node.parent, NULL);
-		TEST_EQ_P (oper->node.left, NULL);
-		TEST_EQ_P (oper->node.right, NULL);
+		TEST_LIST_EMPTY (&oper->children);

  		nih_free (job);
  	}
@@ -1807,9 +1806,7 @@
  		TEST_EQ_STR (oper->env[2], "b?z*");
  		TEST_EQ_P (oper->env[3], NULL);

-		TEST_EQ_P (oper->node.parent, NULL);
-		TEST_EQ_P (oper->node.left, NULL);
-		TEST_EQ_P (oper->node.right, NULL);
+		TEST_LIST_EMPTY (&oper->children);

  		nih_free (job);
  	}
@@ -1861,9 +1858,7 @@
  		TEST_EQ_STR (oper->env[4], "BILBO=foo bar");
  		TEST_EQ_P (oper->env[5], NULL);

-		TEST_EQ_P (oper->node.parent, NULL);
-		TEST_EQ_P (oper->node.left, NULL);
-		TEST_EQ_P (oper->node.right, NULL);
+		TEST_LIST_EMPTY (&oper->children);

  		nih_free (job);
  	}
@@ -1901,31 +1896,26 @@
  		TEST_ALLOC_PARENT (job->start_on, job);

  		oper = job->start_on;
-		TEST_EQ (oper->type, EVENT_OR);
-
-		TEST_EQ_P (oper->node.parent, NULL);
-		TEST_ALLOC_SIZE (oper->node.left, sizeof (EventOperator));
-		TEST_ALLOC_PARENT (oper->node.left, oper);
-		TEST_ALLOC_SIZE (oper->node.right, sizeof (EventOperator));
-		TEST_ALLOC_PARENT (oper->node.right, oper);
-
-		oper = (EventOperator *)job->start_on->node.left;
-		TEST_EQ (oper->type, EVENT_MATCH);
-		TEST_EQ_STR (oper->name, "wibble");
-		TEST_EQ_P (oper->env, NULL);
-
-		TEST_EQ_P (oper->node.parent, &job->start_on->node);
-		TEST_EQ_P (oper->node.left, NULL);
-		TEST_EQ_P (oper->node.right, NULL);
-
-		oper = (EventOperator *)job->start_on->node.right;
-		TEST_EQ (oper->type, EVENT_MATCH);
-		TEST_EQ_STR (oper->name, "wobble");
-		TEST_EQ_P (oper->env, NULL);
-
-		TEST_EQ_P (oper->node.parent, &job->start_on->node);
-		TEST_EQ_P (oper->node.left, NULL);
-		TEST_EQ_P (oper->node.right, NULL);
+		TEST_EQ (oper->type, EVENT_ANY);
+
+		got_wibble = FALSE;
+		got_wobble = FALSE;
+		EventOperator *parent = oper;
+		NIH_LIST_FOREACH (&oper->children, iter) {
+			EventOperator *child = (EventOperator *)iter;
+
+			TEST_ALLOC_SIZE (child, sizeof (EventOperator));
+
+			TEST_LIST_EMPTY (&child->children);
+			TEST_EQ_P (child->env, NULL);
+			TEST_EQ (child->type, EVENT_MATCH);
+			if (!strncmp ("wibble", child->name, 7) && ! got_wibble)
+				got_wibble = TRUE;
+			else if (!strncmp ("wobble", child->name, 7) && ! got_wobble)
+				got_wobble = TRUE;
+			else
+				TEST_FAILED ("Unexpected child");
+		}

  		nih_free (job);
  	}
@@ -1964,39 +1954,32 @@
  		TEST_ALLOC_PARENT (job->start_on, job);

  		oper = job->start_on;
-		TEST_EQ (oper->type, EVENT_AND);
-
-		TEST_EQ_P (oper->node.parent, NULL);
-		TEST_ALLOC_SIZE (oper->node.left, sizeof (EventOperator));
-		TEST_ALLOC_PARENT (oper->node.left, oper);
-		TEST_ALLOC_SIZE (oper->node.right, sizeof (EventOperator));
-		TEST_ALLOC_PARENT (oper->node.right, oper);
-
-		oper = (EventOperator *)job->start_on->node.left;
-		TEST_EQ (oper->type, EVENT_MATCH);
-		TEST_EQ_STR (oper->name, "wibble");
-
-		TEST_ALLOC_SIZE (oper->env, sizeof (char *) * 3);
-		TEST_EQ_STR (oper->env[0], "foo");
-		TEST_EQ_STR (oper->env[1], "bar");
-		TEST_EQ_P (oper->env[2], NULL);
-
-		TEST_EQ_P (oper->node.parent, &job->start_on->node);
-		TEST_EQ_P (oper->node.left, NULL);
-		TEST_EQ_P (oper->node.right, NULL);
-
-		oper = (EventOperator *)job->start_on->node.right;
-		TEST_EQ (oper->type, EVENT_MATCH);
-		TEST_EQ_STR (oper->name, "wobble");
-
-		TEST_ALLOC_SIZE (oper->env, sizeof (char *) * 3);
-		TEST_EQ_STR (oper->env[0], "frodo");
-		TEST_EQ_STR (oper->env[1], "bilbo");
-		TEST_EQ_P (oper->env[2], NULL);
-
-		TEST_EQ_P (oper->node.parent, &job->start_on->node);
-		TEST_EQ_P (oper->node.left, NULL);
-		TEST_EQ_P (oper->node.right, NULL);
+		TEST_EQ (oper->type, EVENT_ALL);
+
+		got_wibble = FALSE;
+		got_wobble = FALSE;
+		NIH_LIST_FOREACH (&oper->children, iter) {
+			EventOperator *child = (EventOperator *)iter;
+
+			TEST_ALLOC_SIZE (child, sizeof (EventOperator));
+
+			TEST_LIST_EMPTY (&child->children);
+			TEST_EQ (child->type, EVENT_MATCH);
+			TEST_ALLOC_SIZE (child->env, sizeof (char *) * 3);
+			if (!strncmp ("wibble", child->name, 7) && ! got_wibble) {
+				got_wibble = TRUE;
+				TEST_EQ_STR (child->env[0], "foo");
+				TEST_EQ_STR (child->env[1], "bar");
+				TEST_EQ_P (child->env[2], NULL);
+			} else if (!strncmp ("wobble", child->name, 7) && ! got_wobble) {
+				got_wobble = TRUE;
+				TEST_EQ_STR (child->env[0], "frodo");
+				TEST_EQ_STR (child->env[1], "bilbo");
+				TEST_EQ_P (child->env[2], NULL);
+			} else {
+				TEST_FAILED ("Unexpected child");
+			}
+		}

  		nih_free (job);
  	}
@@ -2034,48 +2017,29 @@
  		TEST_ALLOC_PARENT (job->start_on, job);

  		oper = job->start_on;
-		TEST_EQ (oper->type, EVENT_OR);
-
-		TEST_EQ_P (oper->node.parent, NULL);
-		TEST_ALLOC_SIZE (oper->node.left, sizeof (EventOperator));
-		TEST_ALLOC_PARENT (oper->node.left, oper);
-		TEST_ALLOC_SIZE (oper->node.right, sizeof (EventOperator));
-		TEST_ALLOC_PARENT (oper->node.right, oper);
-
-		oper = (EventOperator *)job->start_on->node.left;
-		TEST_EQ (oper->type, EVENT_OR);
-		TEST_EQ_P (oper->node.parent, &job->start_on->node);
-		TEST_ALLOC_SIZE (oper->node.left, sizeof (EventOperator));
-		TEST_ALLOC_PARENT (oper->node.left, oper);
-		TEST_ALLOC_SIZE (oper->node.right, sizeof (EventOperator));
-		TEST_ALLOC_PARENT (oper->node.right, oper);
-
-		oper = (EventOperator *)job->start_on->node.left->left;
-		TEST_EQ (oper->type, EVENT_MATCH);
-		TEST_EQ_STR (oper->name, "wibble");
-		TEST_EQ_P (oper->env, NULL);
-
-		TEST_EQ_P (oper->node.parent, job->start_on->node.left);
-		TEST_EQ_P (oper->node.left, NULL);
-		TEST_EQ_P (oper->node.right, NULL);
-
-		oper = (EventOperator *)job->start_on->node.left->right;
-		TEST_EQ (oper->type, EVENT_MATCH);
-		TEST_EQ_STR (oper->name, "wobble");
-		TEST_EQ_P (oper->env, NULL);
-
-		TEST_EQ_P (oper->node.parent, job->start_on->node.left);
-		TEST_EQ_P (oper->node.left, NULL);
-		TEST_EQ_P (oper->node.right, NULL);
-
-		oper = (EventOperator *)job->start_on->node.right;
-		TEST_EQ (oper->type, EVENT_MATCH);
-		TEST_EQ_STR (oper->name, "wiggle");
-		TEST_EQ_P (oper->env, NULL);
-
-		TEST_EQ_P (oper->node.parent, &job->start_on->node);
-		TEST_EQ_P (oper->node.left, NULL);
-		TEST_EQ_P (oper->node.right, NULL);
+		TEST_EQ (oper->type, EVENT_ANY);
+
+		got_wibble = FALSE;
+		got_wobble = FALSE;
+		got_wiggle = FALSE;
+		NIH_LIST_FOREACH (&oper->children, iter) {
+			EventOperator *child = (EventOperator *)iter;
+
+			TEST_ALLOC_SIZE (child, sizeof (EventOperator));
+
+			TEST_LIST_EMPTY (&child->children);
+			TEST_EQ (child->type, EVENT_MATCH);
+			TEST_EQ_P (child->env, NULL);
+			if (!strncmp ("wibble", child->name, 7) && ! got_wibble) {
+				got_wibble = TRUE;
+			} else if (!strncmp ("wobble", child->name, 7) && ! got_wobble) {
+				got_wobble = TRUE;
+			} else if (!strncmp ("wiggle", child->name, 7) && ! got_wiggle) {
+				got_wiggle = TRUE;
+			} else {
+				TEST_FAILED ("Unexpected child");
+			}
+		}

  		nih_free (job);
  	}
@@ -2112,49 +2076,29 @@
  		TEST_ALLOC_PARENT (job->start_on, job);

  		oper = job->start_on;
-		TEST_EQ (oper->type, EVENT_OR);
-
-		TEST_EQ_P (oper->node.parent, NULL);
-		TEST_ALLOC_SIZE (oper->node.left, sizeof (EventOperator));
-		TEST_ALLOC_PARENT (oper->node.left, oper);
-		TEST_ALLOC_SIZE (oper->node.right, sizeof (EventOperator));
-		TEST_ALLOC_PARENT (oper->node.right, oper);
-
-		oper = (EventOperator *)job->start_on->node.left;
-		TEST_EQ (oper->type, EVENT_MATCH);
-		TEST_EQ_STR (oper->name, "wibble");
-		TEST_EQ_P (oper->env, NULL);
-
-		TEST_EQ_P (oper->node.parent, &job->start_on->node);
-		TEST_EQ_P (oper->node.left, NULL);
-		TEST_EQ_P (oper->node.right, NULL);
-
-		oper = (EventOperator *)job->start_on->node.right;
-		TEST_EQ (oper->type, EVENT_OR);
-
-		TEST_EQ_P (oper->node.parent, &job->start_on->node);
-		TEST_ALLOC_SIZE (oper->node.left, sizeof (EventOperator));
-		TEST_ALLOC_PARENT (oper->node.left, oper);
-		TEST_ALLOC_SIZE (oper->node.right, sizeof (EventOperator));
-		TEST_ALLOC_PARENT (oper->node.right, oper);
-
-		oper = (EventOperator *)job->start_on->node.right->left;
-		TEST_EQ (oper->type, EVENT_MATCH);
-		TEST_EQ_STR (oper->name, "wobble");
-		TEST_EQ_P (oper->env, NULL);
-
-		TEST_EQ_P (oper->node.parent, job->start_on->node.right);
-		TEST_EQ_P (oper->node.left, NULL);
-		TEST_EQ_P (oper->node.right, NULL);
-
-		oper = (EventOperator *)job->start_on->node.right->right;
-		TEST_EQ (oper->type, EVENT_MATCH);
-		TEST_EQ_STR (oper->name, "wiggle");
-		TEST_EQ_P (oper->env, NULL);
-
-		TEST_EQ_P (oper->node.parent, job->start_on->node.right);
-		TEST_EQ_P (oper->node.left, NULL);
-		TEST_EQ_P (oper->node.right, NULL);
+		TEST_EQ (oper->type, EVENT_ANY);
+
+		got_wibble = FALSE;
+		got_wobble = FALSE;
+		got_wiggle = FALSE;
+		NIH_LIST_FOREACH (&oper->children, iter) {
+			EventOperator *child = (EventOperator *)iter;
+
+			TEST_ALLOC_SIZE (child, sizeof (EventOperator));
+
+			TEST_LIST_EMPTY (&child->children);
+			TEST_EQ (child->type, EVENT_MATCH);
+			TEST_EQ_P (child->env, NULL);
+			if (!strncmp ("wibble", child->name, 7) && ! got_wibble) {
+				got_wibble = TRUE;
+			} else if (!strncmp ("wobble", child->name, 7) && ! got_wobble) {
+				got_wobble = TRUE;
+			} else if (!strncmp ("wiggle", child->name, 7) && ! got_wiggle) {
+				got_wiggle = TRUE;
+			} else {
+				TEST_FAILED ("Unexpected child");
+			}
+		}

  		nih_free (job);
  	}
@@ -2192,49 +2136,29 @@
  		TEST_ALLOC_PARENT (job->start_on, job);

  		oper = job->start_on;
-		TEST_EQ (oper->type, EVENT_OR);
-
-		TEST_EQ_P (oper->node.parent, NULL);
-		TEST_ALLOC_SIZE (oper->node.left, sizeof (EventOperator));
-		TEST_ALLOC_PARENT (oper->node.left, oper);
-		TEST_ALLOC_SIZE (oper->node.right, sizeof (EventOperator));
-		TEST_ALLOC_PARENT (oper->node.right, oper);
-
-		oper = (EventOperator *)job->start_on->node.left;
-		TEST_EQ (oper->type, EVENT_MATCH);
-		TEST_EQ_STR (oper->name, "wibble");
-		TEST_EQ_P (oper->env, NULL);
-
-		TEST_EQ_P (oper->node.parent, &job->start_on->node);
-		TEST_EQ_P (oper->node.left, NULL);
-		TEST_EQ_P (oper->node.right, NULL);
-
-		oper = (EventOperator *)job->start_on->node.right;
-		TEST_EQ (oper->type, EVENT_OR);
-
-		TEST_EQ_P (oper->node.parent, &job->start_on->node);
-		TEST_ALLOC_SIZE (oper->node.left, sizeof (EventOperator));
-		TEST_ALLOC_PARENT (oper->node.left, oper);
-		TEST_ALLOC_SIZE (oper->node.right, sizeof (EventOperator));
-		TEST_ALLOC_PARENT (oper->node.right, oper);
-
-		oper = (EventOperator *)job->start_on->node.right->left;
-		TEST_EQ (oper->type, EVENT_MATCH);
-		TEST_EQ_STR (oper->name, "wobble");
-		TEST_EQ_P (oper->env, NULL);
-
-		TEST_EQ_P (oper->node.parent, job->start_on->node.right);
-		TEST_EQ_P (oper->node.left, NULL);
-		TEST_EQ_P (oper->node.right, NULL);
-
-		oper = (EventOperator *)job->start_on->node.right->right;
-		TEST_EQ (oper->type, EVENT_MATCH);
-		TEST_EQ_STR (oper->name, "wiggle");
-		TEST_EQ_P (oper->env, NULL);
-
-		TEST_EQ_P (oper->node.parent, job->start_on->node.right);
-		TEST_EQ_P (oper->node.left, NULL);
-		TEST_EQ_P (oper->node.right, NULL);
+		TEST_EQ (oper->type, EVENT_ANY);
+
+		got_wibble = FALSE;
+		got_wobble = FALSE;
+		got_wiggle = FALSE;
+		NIH_LIST_FOREACH (&oper->children, iter) {
+			EventOperator *child = (EventOperator *)iter;
+
+			TEST_ALLOC_SIZE (child, sizeof (EventOperator));
+
+			TEST_LIST_EMPTY (&child->children);
+			TEST_EQ (child->type, EVENT_MATCH);
+			TEST_EQ_P (child->env, NULL);
+			if (!strncmp ("wibble", child->name, 7) && ! got_wibble) {
+				got_wibble = TRUE;
+			} else if (!strncmp ("wobble", child->name, 7) && ! got_wobble) {
+				got_wobble = TRUE;
+			} else if (!strncmp ("wiggle", child->name, 7) && ! got_wiggle) {
+				got_wiggle = TRUE;
+			} else {
+				TEST_FAILED ("Unexpected child");
+			}
+		}

  		nih_free (job);
  	}
@@ -2275,9 +2199,7 @@
  		TEST_EQ_STR (oper->name, "waggle");
  		TEST_EQ_P (oper->env, NULL);

-		TEST_EQ_P (oper->node.parent, NULL);
-		TEST_EQ_P (oper->node.left, NULL);
-		TEST_EQ_P (oper->node.right, NULL);
+		TEST_LIST_EMPTY (&oper->children);

  		nih_free (job);
  	}
@@ -2536,6 +2458,7 @@
  	NihError      *err;
  	size_t         pos, lineno;
  	char           buf[1024];
+	int            got_wibble, got_wobble, got_wiggle;

  	TEST_FUNCTION ("stanza_stop");

@@ -2574,9 +2497,7 @@
  		TEST_EQ_STR (oper->name, "wibble");
  		TEST_EQ_P (oper->env, NULL);

-		TEST_EQ_P (oper->node.parent, NULL);
-		TEST_EQ_P (oper->node.left, NULL);
-		TEST_EQ_P (oper->node.right, NULL);
+		TEST_LIST_EMPTY (&oper->children);

  		nih_free (job);
  	}
@@ -2624,9 +2545,7 @@
  		TEST_EQ_STR (oper->env[2], "b?z*");
  		TEST_EQ_P (oper->env[3], NULL);

-		TEST_EQ_P (oper->node.parent, NULL);
-		TEST_EQ_P (oper->node.left, NULL);
-		TEST_EQ_P (oper->node.right, NULL);
+		TEST_LIST_EMPTY (&oper->children);

  		nih_free (job);
  	}
@@ -2678,9 +2597,7 @@
  		TEST_EQ_STR (oper->env[4], "BILBO=foo bar");
  		TEST_EQ_P (oper->env[5], NULL);

-		TEST_EQ_P (oper->node.parent, NULL);
-		TEST_EQ_P (oper->node.left, NULL);
-		TEST_EQ_P (oper->node.right, NULL);
+		TEST_LIST_EMPTY (&oper->children);

  		nih_free (job);
  	}
@@ -2718,31 +2635,26 @@
  		TEST_ALLOC_PARENT (job->stop_on, job);

  		oper = job->stop_on;
-		TEST_EQ (oper->type, EVENT_OR);
-
-		TEST_EQ_P (oper->node.parent, NULL);
-		TEST_ALLOC_SIZE (oper->node.left, sizeof (EventOperator));
-		TEST_ALLOC_PARENT (oper->node.left, oper);
-		TEST_ALLOC_SIZE (oper->node.right, sizeof (EventOperator));
-		TEST_ALLOC_PARENT (oper->node.right, oper);
-
-		oper = (EventOperator *)job->stop_on->node.left;
-		TEST_EQ (oper->type, EVENT_MATCH);
-		TEST_EQ_STR (oper->name, "wibble");
-		TEST_EQ_P (oper->env, NULL);
-
-		TEST_EQ_P (oper->node.parent, &job->stop_on->node);
-		TEST_EQ_P (oper->node.left, NULL);
-		TEST_EQ_P (oper->node.right, NULL);
-
-		oper = (EventOperator *)job->stop_on->node.right;
-		TEST_EQ (oper->type, EVENT_MATCH);
-		TEST_EQ_STR (oper->name, "wobble");
-		TEST_EQ_P (oper->env, NULL);
-
-		TEST_EQ_P (oper->node.parent, &job->stop_on->node);
-		TEST_EQ_P (oper->node.left, NULL);
-		TEST_EQ_P (oper->node.right, NULL);
+		TEST_EQ (oper->type, EVENT_ANY);
+
+		got_wibble = FALSE;
+		got_wobble = FALSE;
+		NIH_LIST_FOREACH (&oper->children, iter) {
+			EventOperator *child = (EventOperator *)iter;
+
+			TEST_ALLOC_SIZE (child, sizeof (EventOperator));
+
+			TEST_LIST_EMPTY (&child->children);
+			TEST_EQ (child->type, EVENT_MATCH);
+			TEST_EQ_P (child->env, NULL);
+			if (!strncmp ("wibble", child->name, 7) && ! got_wibble) {
+				got_wibble = TRUE;
+			} else if (!strncmp ("wobble", child->name, 7) && ! got_wobble) {
+				got_wobble = TRUE;
+			} else {
+				TEST_FAILED ("Unexpected child");
+			}
+		}

  		nih_free (job);
  	}
@@ -2781,39 +2693,32 @@
  		TEST_ALLOC_PARENT (job->stop_on, job);

  		oper = job->stop_on;
-		TEST_EQ (oper->type, EVENT_AND);
-
-		TEST_EQ_P (oper->node.parent, NULL);
-		TEST_ALLOC_SIZE (oper->node.left, sizeof (EventOperator));
-		TEST_ALLOC_PARENT (oper->node.left, oper);
-		TEST_ALLOC_SIZE (oper->node.right, sizeof (EventOperator));
-		TEST_ALLOC_PARENT (oper->node.right, oper);
-
-		oper = (EventOperator *)job->stop_on->node.left;
-		TEST_EQ (oper->type, EVENT_MATCH);
-		TEST_EQ_STR (oper->name, "wibble");
-
-		TEST_ALLOC_SIZE (oper->env, sizeof (char *) * 3);
-		TEST_EQ_STR (oper->env[0], "foo");
-		TEST_EQ_STR (oper->env[1], "bar");
-		TEST_EQ_P (oper->env[2], NULL);
-
-		TEST_EQ_P (oper->node.parent, &job->stop_on->node);
-		TEST_EQ_P (oper->node.left, NULL);
-		TEST_EQ_P (oper->node.right, NULL);
-
-		oper = (EventOperator *)job->stop_on->node.right;
-		TEST_EQ (oper->type, EVENT_MATCH);
-		TEST_EQ_STR (oper->name, "wobble");
-
-		TEST_ALLOC_SIZE (oper->env, sizeof (char *) * 3);
-		TEST_EQ_STR (oper->env[0], "frodo");
-		TEST_EQ_STR (oper->env[1], "bilbo");
-		TEST_EQ_P (oper->env[2], NULL);
-
-		TEST_EQ_P (oper->node.parent, &job->stop_on->node);
-		TEST_EQ_P (oper->node.left, NULL);
-		TEST_EQ_P (oper->node.right, NULL);
+		TEST_EQ (oper->type, EVENT_ALL);
+
+		got_wibble = FALSE;
+		got_wobble = FALSE;
+		NIH_LIST_FOREACH (&oper->children, iter) {
+			EventOperator *child = (EventOperator *)iter;
+
+			TEST_ALLOC_SIZE (child, sizeof (EventOperator));
+
+			TEST_LIST_EMPTY (&child->children);
+			TEST_EQ (child->type, EVENT_MATCH);
+			TEST_ALLOC_SIZE (child->env, sizeof (char *) * 3);
+			if (!strncmp ("wibble", child->name, 7) && ! got_wibble) {
+				got_wibble = TRUE;
+				TEST_EQ_STR (child->env[0], "foo");
+				TEST_EQ_STR (child->env[1], "bar");
+				TEST_EQ_P (child->env[2], NULL);
+			} else if (!strncmp ("wobble", child->name, 7) && ! got_wobble) {
+				got_wobble = TRUE;
+				TEST_EQ_STR (child->env[0], "frodo");
+				TEST_EQ_STR (child->env[1], "bilbo");
+				TEST_EQ_P (child->env[2], NULL);
+			} else {
+				TEST_FAILED ("Unexpected child");
+			}
+		}

  		nih_free (job);
  	}
@@ -2851,48 +2756,29 @@
  		TEST_ALLOC_PARENT (job->stop_on, job);

  		oper = job->stop_on;
-		TEST_EQ (oper->type, EVENT_OR);
-
-		TEST_EQ_P (oper->node.parent, NULL);
-		TEST_ALLOC_SIZE (oper->node.left, sizeof (EventOperator));
-		TEST_ALLOC_PARENT (oper->node.left, oper);
-		TEST_ALLOC_SIZE (oper->node.right, sizeof (EventOperator));
-		TEST_ALLOC_PARENT (oper->node.right, oper);
-
-		oper = (EventOperator *)job->stop_on->node.left;
-		TEST_EQ (oper->type, EVENT_OR);
-		TEST_EQ_P (oper->node.parent, &job->stop_on->node);
-		TEST_ALLOC_SIZE (oper->node.left, sizeof (EventOperator));
-		TEST_ALLOC_PARENT (oper->node.left, oper);
-		TEST_ALLOC_SIZE (oper->node.right, sizeof (EventOperator));
-		TEST_ALLOC_PARENT (oper->node.right, oper);
-
-		oper = (EventOperator *)job->stop_on->node.left->left;
-		TEST_EQ (oper->type, EVENT_MATCH);
-		TEST_EQ_STR (oper->name, "wibble");
-		TEST_EQ_P (oper->env, NULL);
-
-		TEST_EQ_P (oper->node.parent, job->stop_on->node.left);
-		TEST_EQ_P (oper->node.left, NULL);
-		TEST_EQ_P (oper->node.right, NULL);
-
-		oper = (EventOperator *)job->stop_on->node.left->right;
-		TEST_EQ (oper->type, EVENT_MATCH);
-		TEST_EQ_STR (oper->name, "wobble");
-		TEST_EQ_P (oper->env, NULL);
-
-		TEST_EQ_P (oper->node.parent, job->stop_on->node.left);
-		TEST_EQ_P (oper->node.left, NULL);
-		TEST_EQ_P (oper->node.right, NULL);
-
-		oper = (EventOperator *)job->stop_on->node.right;
-		TEST_EQ (oper->type, EVENT_MATCH);
-		TEST_EQ_STR (oper->name, "wiggle");
-		TEST_EQ_P (oper->env, NULL);
-
-		TEST_EQ_P (oper->node.parent, &job->stop_on->node);
-		TEST_EQ_P (oper->node.left, NULL);
-		TEST_EQ_P (oper->node.right, NULL);
+		TEST_EQ (oper->type, EVENT_ANY);
+
+		got_wibble = FALSE;
+		got_wobble = FALSE;
+		got_wiggle = FALSE;
+		NIH_LIST_FOREACH (&oper->children, iter) {
+			EventOperator *child = (EventOperator *)iter;
+
+			TEST_ALLOC_SIZE (child, sizeof (EventOperator));
+
+			TEST_LIST_EMPTY (&child->children);
+			TEST_EQ (child->type, EVENT_MATCH);
+			TEST_EQ_P (child->env, NULL);
+			if (!strncmp ("wibble", child->name, 7) && ! got_wibble) {
+				got_wibble = TRUE;
+			} else if (!strncmp ("wobble", child->name, 7) && ! got_wobble) {
+				got_wobble = TRUE;
+			} else if (!strncmp ("wiggle", child->name, 7) && ! got_wiggle) {
+				got_wiggle = TRUE;
+			} else {
+				TEST_FAILED ("Unexpected child");
+			}
+		}

  		nih_free (job);
  	}
@@ -2929,49 +2815,29 @@
  		TEST_ALLOC_PARENT (job->stop_on, job);

  		oper = job->stop_on;
-		TEST_EQ (oper->type, EVENT_OR);
-
-		TEST_EQ_P (oper->node.parent, NULL);
-		TEST_ALLOC_SIZE (oper->node.left, sizeof (EventOperator));
-		TEST_ALLOC_PARENT (oper->node.left, oper);
-		TEST_ALLOC_SIZE (oper->node.right, sizeof (EventOperator));
-		TEST_ALLOC_PARENT (oper->node.right, oper);
-
-		oper = (EventOperator *)job->stop_on->node.left;
-		TEST_EQ (oper->type, EVENT_MATCH);
-		TEST_EQ_STR (oper->name, "wibble");
-		TEST_EQ_P (oper->env, NULL);
-
-		TEST_EQ_P (oper->node.parent, &job->stop_on->node);
-		TEST_EQ_P (oper->node.left, NULL);
-		TEST_EQ_P (oper->node.right, NULL);
-
-		oper = (EventOperator *)job->stop_on->node.right;
-		TEST_EQ (oper->type, EVENT_OR);
-
-		TEST_EQ_P (oper->node.parent, &job->stop_on->node);
-		TEST_ALLOC_SIZE (oper->node.left, sizeof (EventOperator));
-		TEST_ALLOC_PARENT (oper->node.left, oper);
-		TEST_ALLOC_SIZE (oper->node.right, sizeof (EventOperator));
-		TEST_ALLOC_PARENT (oper->node.right, oper);
-
-		oper = (EventOperator *)job->stop_on->node.right->left;
-		TEST_EQ (oper->type, EVENT_MATCH);
-		TEST_EQ_STR (oper->name, "wobble");
-		TEST_EQ_P (oper->env, NULL);
-
-		TEST_EQ_P (oper->node.parent, job->stop_on->node.right);
-		TEST_EQ_P (oper->node.left, NULL);
-		TEST_EQ_P (oper->node.right, NULL);
-
-		oper = (EventOperator *)job->stop_on->node.right->right;
-		TEST_EQ (oper->type, EVENT_MATCH);
-		TEST_EQ_STR (oper->name, "wiggle");
-		TEST_EQ_P (oper->env, NULL);
-
-		TEST_EQ_P (oper->node.parent, job->stop_on->node.right);
-		TEST_EQ_P (oper->node.left, NULL);
-		TEST_EQ_P (oper->node.right, NULL);
+		TEST_EQ (oper->type, EVENT_ANY);
+
+		got_wibble = FALSE;
+		got_wobble = FALSE;
+		got_wiggle = FALSE;
+		NIH_LIST_FOREACH (&oper->children, iter) {
+			EventOperator *child = (EventOperator *)iter;
+
+			TEST_ALLOC_SIZE (child, sizeof (EventOperator));
+
+			TEST_LIST_EMPTY (&child->children);
+			TEST_EQ (child->type, EVENT_MATCH);
+			TEST_EQ_P (child->env, NULL);
+			if (!strncmp ("wibble", child->name, 7) && ! got_wibble) {
+				got_wibble = TRUE;
+			} else if (!strncmp ("wobble", child->name, 7) && ! got_wobble) {
+				got_wobble = TRUE;
+			} else if (!strncmp ("wiggle", child->name, 7) && ! got_wiggle) {
+				got_wiggle = TRUE;
+			} else {
+				TEST_FAILED ("Unexpected child");
+			}
+		}

  		nih_free (job);
  	}
@@ -3009,49 +2875,29 @@
  		TEST_ALLOC_PARENT (job->stop_on, job);

  		oper = job->stop_on;
-		TEST_EQ (oper->type, EVENT_OR);
-
-		TEST_EQ_P (oper->node.parent, NULL);
-		TEST_ALLOC_SIZE (oper->node.left, sizeof (EventOperator));
-		TEST_ALLOC_PARENT (oper->node.left, oper);
-		TEST_ALLOC_SIZE (oper->node.right, sizeof (EventOperator));
-		TEST_ALLOC_PARENT (oper->node.right, oper);
-
-		oper = (EventOperator *)job->stop_on->node.left;
-		TEST_EQ (oper->type, EVENT_MATCH);
-		TEST_EQ_STR (oper->name, "wibble");
-		TEST_EQ_P (oper->env, NULL);
-
-		TEST_EQ_P (oper->node.parent, &job->stop_on->node);
-		TEST_EQ_P (oper->node.left, NULL);
-		TEST_EQ_P (oper->node.right, NULL);
-
-		oper = (EventOperator *)job->stop_on->node.right;
-		TEST_EQ (oper->type, EVENT_OR);
-
-		TEST_EQ_P (oper->node.parent, &job->stop_on->node);
-		TEST_ALLOC_SIZE (oper->node.left, sizeof (EventOperator));
-		TEST_ALLOC_PARENT (oper->node.left, oper);
-		TEST_ALLOC_SIZE (oper->node.right, sizeof (EventOperator));
-		TEST_ALLOC_PARENT (oper->node.right, oper);
-
-		oper = (EventOperator *)job->stop_on->node.right->left;
-		TEST_EQ (oper->type, EVENT_MATCH);
-		TEST_EQ_STR (oper->name, "wobble");
-		TEST_EQ_P (oper->env, NULL);
-
-		TEST_EQ_P (oper->node.parent, job->stop_on->node.right);
-		TEST_EQ_P (oper->node.left, NULL);
-		TEST_EQ_P (oper->node.right, NULL);
-
-		oper = (EventOperator *)job->stop_on->node.right->right;
-		TEST_EQ (oper->type, EVENT_MATCH);
-		TEST_EQ_STR (oper->name, "wiggle");
-		TEST_EQ_P (oper->env, NULL);
-
-		TEST_EQ_P (oper->node.parent, job->stop_on->node.right);
-		TEST_EQ_P (oper->node.left, NULL);
-		TEST_EQ_P (oper->node.right, NULL);
+		TEST_EQ (oper->type, EVENT_ANY);
+
+		got_wibble = FALSE;
+		got_wobble = FALSE;
+		got_wiggle = FALSE;
+		NIH_LIST_FOREACH (&oper->children, iter) {
+			EventOperator *child = (EventOperator *)iter;
+
+			TEST_ALLOC_SIZE (child, sizeof (EventOperator));
+
+			TEST_LIST_EMPTY (&child->children);
+			TEST_EQ (child->type, EVENT_MATCH);
+			TEST_EQ_P (child->env, NULL);
+			if (!strncmp ("wibble", child->name, 7) && ! got_wibble) {
+				got_wibble = TRUE;
+			} else if (!strncmp ("wobble", child->name, 7) && ! got_wobble) {
+				got_wobble = TRUE;
+			} else if (!strncmp ("wiggle", child->name, 7) && ! got_wiggle) {
+				got_wiggle = TRUE;
+			} else {
+				TEST_FAILED ("Unexpected child");
+			}
+		}

  		nih_free (job);
  	}
@@ -3092,9 +2938,7 @@
  		TEST_EQ_STR (oper->name, "waggle");
  		TEST_EQ_P (oper->env, NULL);

-		TEST_EQ_P (oper->node.parent, NULL);
-		TEST_EQ_P (oper->node.left, NULL);
-		TEST_EQ_P (oper->node.right, NULL);
+		TEST_LIST_EMPTY (&oper->children);

  		nih_free (job);
  	}




More information about the upstart-devel mailing list