--- /dev/null
+#include "squid.h"
+#include "acl/BoolOps.h"
+#include "acl/Checklist.h"
+#include "Debug.h"
+#include "wordlist.h"
+
+
+/* Acl::NotNode */
+
+Acl::NotNode::NotNode(ACL *acl)
+{
+ assert(acl);
+ name[0] = '!';
+ strncat(&name[1], acl->name, sizeof(name)-1-1);
+ add(acl);
+}
+
+void
+Acl::NotNode::parse()
+{
+ // Not implemented: by the time an upper level parser discovers
+ // an '!' operator, there is nothing left for us to parse.
+ assert(false);
+}
+
+int
+Acl::NotNode::doMatch(ACLChecklist *checklist, Nodes::const_iterator start) const
+{
+ assert(start == nodes.begin()); // we only have one node
+
+ if (checklist->matchChild(this, start, *start))
+ return 0; // converting match into mismatch
+
+ if (!checklist->keepMatching())
+ return -1; // suspend on async calls and stop on failures
+
+ return 1; // converting mismatch into match
+}
+
+char const *
+Acl::NotNode::typeString() const
+{
+ return "!";
+}
+
+ACL *
+Acl::NotNode::clone() const
+{
+ // Not implemented: we are not a named ACL type in squid.conf so nobody
+ // should try to create a NotNode instance by ACL type name (which is
+ // what clone() API is for -- it does not really clone anything).
+ assert(false);
+ return NULL;
+}
+
+wordlist*
+Acl::NotNode::dump() const
+{
+ wordlist *text = NULL;
+ wordlistAdd(&text, name);
+ return text;
+}
+
+
+/* Acl::AndNode */
+
+char const *
+Acl::AndNode::typeString() const
+{
+ return "and";
+}
+
+ACL *
+Acl::AndNode::clone() const
+{
+ return new AndNode;
+}
+
+int
+Acl::AndNode::doMatch(ACLChecklist *checklist, Nodes::const_iterator start) const
+{
+ // find the first node that does not match
+ for (Nodes::const_iterator i = start; i != nodes.end(); ++i) {
+ if (!checklist->matchChild(this, i, *i))
+ return checklist->keepMatching() ? 0 : -1;
+ }
+
+ // one and not zero on empty because in math empty product equals identity
+ return 1; // no mismatches found (i.e., all kids matched)
+}
+
+void
+Acl::AndNode::parse()
+{
+ // Not implemented: AndNode cannot be configured directly. See Acl::AllOf.
+ assert(false);
+}
+
+
+/* Acl::OrNode */
+
+char const *
+Acl::OrNode::typeString() const
+{
+ return "any-of";
+}
+
+ACL *
+Acl::OrNode::clone() const
+{
+ return new OrNode;
+}
+
+int
+Acl::OrNode::doMatch(ACLChecklist *checklist, Nodes::const_iterator start) const
+{
+ lastMatch_ = nodes.end();
+
+ // find the first node that matches, but stop if things go wrong
+ for (Nodes::const_iterator i = start; i != nodes.end(); ++i) {
+ if (checklist->matchChild(this, i, *i)) {
+ lastMatch_ = i;
+ return 1;
+ }
+
+ if (!checklist->keepMatching())
+ return -1; // suspend on async calls and stop on failures
+ }
+
+ // zero and not one on empty because in math empty sum equals zero
+ return 0; // all nodes mismatched
+}
+
+void
+Acl::OrNode::parse()
+{
+ // Not implemented: OrNode cannot be configured directly. See Acl::AnyOf.
+ assert(false);
+}
--- /dev/null
+#ifndef SQUID_ACL_LOGIC_H
+#define SQUID_ACL_LOGIC_H
+
+#include "acl/InnerNode.h"
+
+/* ACLs defined here are used internally to construct an ACL expression tree.
+ * They cannot be specified directly in squid.conf because squid.conf ACLs are
+ * more complex than (and are implemented using) these operator-like classes.*/
+
+namespace Acl {
+
+/// Implements the "not" or "!" operator.
+class NotNode: public InnerNode
+{
+public:
+ MEMPROXY_CLASS(NotNode);
+
+ explicit NotNode(ACL *acl);
+
+private:
+ /* ACL API */
+ virtual char const *typeString() const;
+ virtual ACL *clone() const;
+ virtual void parse();
+ virtual wordlist *dump() const;
+
+ /* Acl::InnerNode API */
+ virtual int doMatch(ACLChecklist *checklist, Nodes::const_iterator start) const;
+};
+MEMPROXY_CLASS_INLINE(Acl::NotNode);
+
+
+/// An inner ACL expression tree node representing a boolean conjuction (AND)
+/// operator applied to a list of child tree nodes.
+/// For example, conditions expressed on a single http_access line are ORed.
+class AndNode: public InnerNode
+{
+public:
+ MEMPROXY_CLASS(AndNode);
+
+ /* ACL API */
+ virtual char const *typeString() const;
+ virtual ACL *clone() const;
+ virtual void parse();
+
+private:
+ virtual int doMatch(ACLChecklist *checklist, Nodes::const_iterator start) const;
+};
+MEMPROXY_CLASS_INLINE(Acl::AndNode);
+
+/// An inner ACL expression tree node representing a boolean disjuction (OR)
+/// operator applied to a list of child tree nodes.
+/// For example, conditions expressed by multiple http_access lines are ORed.
+class OrNode: public InnerNode
+{
+public:
+ MEMPROXY_CLASS(OrNode);
+
+ /* ACL API */
+ virtual char const *typeString() const;
+ virtual ACL *clone() const;
+ virtual void parse();
+
+protected:
+ mutable Nodes::const_iterator lastMatch_;
+
+private:
+ virtual int doMatch(ACLChecklist *checklist, Nodes::const_iterator start) const;
+};
+MEMPROXY_CLASS_INLINE(Acl::OrNode);
+
+
+} // namespace Acl
+
+#endif /* SQUID_ACL_LOGIC_H */