+ }
+
+ /* --- Done --- */
+
+ return (l);
+ }
+
+ /* --- Unfriendly nodes --- *
+ *
+ * Create a binop node and return that. If @l@ is a binop node, and @r@
+ * isn't, and the operation isn't set difference (i.e., it's commutative)
+ * then swap the two over to lessen the depth of recursion later.
+ */
+
+ else {
+ class_node *c = xmalloc(sizeof(*c));
+
+ c->type = type | op;
+ c->ref = 1;
+ if (lnode >= clNode_binop && rnode < clNode_binop && op != clNode_diff) {
+ c->v.c.l = r;
+ c->v.c.r = l;
+ } else {
+ c->v.c.l = l;
+ c->v.c.r = r;
+ }
+ return (c);
+ }
+}
+
+/* --- @class_union@ --- *
+ *
+ * Arguments: @class_node *l@ = left argument
+ * @class_node *r@ = right argument
+ *
+ * Returns: A class node representing the union of the two classes.
+ *
+ * Use: Performs the union operation on classes. If the types don't
+ * match, then a null pointer is returned. Both @l@ and @r@
+ * may be modified, and will be decremented before they get
+ * returned to you. If you don't want that to happen, ensure
+ * that you've claimed a reference to the original versions.
+ */
+
+class_node *class_union(class_node *l, class_node *r)
+{
+ /* --- Check for the really simple cases --- */
+
+ if (l == class_all || r == class_all) {
+ class_dec(l);
+ class_dec(r);
+ return (class_all);
+ }
+
+ if (l == class_none)
+ return (r);
+ if (r == class_none)
+ return (l);
+
+ /* --- Do the job --- */
+
+ return (class__binop(l, r, clNode_union));
+}
+
+/* --- @class_diff@ --- *
+ *
+ * Arguments: @class_node *l@ = left argument
+ * @class_node *r@ = right argument
+ *
+ * Returns: A class node representing the difference of the two classes.
+ *
+ * Use: Performs the set difference operation on classes. If the
+ * types don't match, then a null pointer is returned. Both
+ * @l@ and @r@ may be modified, and will be decremented before
+ * they get returned to you. If you don't want that to happen,
+ * ensure that you've claimed a reference to the original
+ * versions.
+ */
+
+class_node *class_diff(class_node *l, class_node *r)
+{
+ /* --- Check for the really simple cases --- */
+
+ if (l == class_none || r == class_all) {
+ class_dec(l);
+ class_dec(r);
+ return (class_none);
+ }
+
+ if (r == class_none)
+ return (l);
+
+ /* --- Do the job --- */
+
+ return (class__binop(l, r, clNode_diff));
+}
+
+/* --- @class_isect@ --- *
+ *
+ * Arguments: @class_node *l@ = left argument
+ * @class_node *r@ = right argument
+ *
+ * Returns: A class node representing the intersection of the two
+ * classes.
+ *
+ * Use: Performs the intersecion operation on classes. If the types
+ * don't match, then a null pointer is returned. Both @l@ and
+ * @r@ may be modified, and will be decremented before they get
+ * returned to you. If you don't want that to happen, ensure
+ * that you've claimed a reference to the original versions.
+ */
+
+class_node *class_isect(class_node *l, class_node *r)
+{
+ /* --- Check for the really simple cases --- */
+
+ if (l == class_none || r == class_none) {
+ class_dec(l);
+ class_dec(r);
+ return (class_none);
+ }
+
+ if (l == class_all)
+ return (r);
+ if (r == class_all)
+ return (l);
+
+ /* --- Do the job --- */
+
+ return (class__binop(l, r, clNode_isect));
+}
+
+/*----- Building the predefined classes -----------------------------------*/
+
+/* --- @class_addUser@ --- *
+ *
+ * Arguments: @class_node *c@ = pointer to a class node (may be null)
+ * @uid_t u@ = user id number
+ *
+ * Returns: Pointer to the combined node.
+ *
+ * Use: Adds a user to a node, maybe hashifying it.
+ */
+
+class_node *class_addUser(class_node *c, uid_t u)
+{
+ if (!c)
+ return (class_fromUser(clType_user, u));
+ if ((c->type & clNode_mask) == clNode_immed)
+ c = class__hashify(c);
+ sym_find(&c->v.t, (char *)&u, sizeof(u), sizeof(sym_base), 0);
+ return (c);
+}
+
+/* --- @class_addString@ --- *
+ *
+ * Arguments: @class_node *c@ = pointer to a class node (may be null)
+ * @const char *s@ = pointer to a string
+ *
+ * Returns: Pointer to the combined node.
+ *
+ * Use: Adds a user to a node, maybe hashifying it.
+ */
+
+class_node *class_addString(class_node *c, const char *s)
+{
+ class_node *n = class_fromString(clType_host, s); /* hack */
+ if (c)
+ return (class_union(c, n));
+ else
+ return (n);
+}
+
+/*----- Matching functions ------------------------------------------------*/