]> granicus.if.org Git - apache/commitdiff
Replace ap_expr with a parser derived from mod_ssl's parser. Make mod_ssl use
authorStefan Fritsch <sf@apache.org>
Sat, 6 Nov 2010 14:31:16 +0000 (14:31 +0000)
committerStefan Fritsch <sf@apache.org>
Sat, 6 Nov 2010 14:31:16 +0000 (14:31 +0000)
the new parser. Rework ap_expr's public interface and provide hooks for modules
to add variables and functions.

The Netware and Windows build files still need to be adjusted

git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1032073 13f79535-47bb-0310-9956-ffa450edef68

32 files changed:
CHANGES
buildconf
include/ap_expr.h
include/ap_mmn.h
include/http_core.h
modules/aaa/mod_authz_core.c
modules/filters/mod_filter.c
modules/metadata/mod_headers.c
modules/ssl/Makefile.in
modules/ssl/config.m4
modules/ssl/mod_ssl.c
modules/ssl/ssl_engine_config.c
modules/ssl/ssl_engine_kernel.c
modules/ssl/ssl_engine_vars.c
modules/ssl/ssl_expr.c [deleted file]
modules/ssl/ssl_expr.h [deleted file]
modules/ssl/ssl_expr_eval.c [deleted file]
modules/ssl/ssl_expr_parse.y [deleted file]
modules/ssl/ssl_expr_scan.l [deleted file]
modules/ssl/ssl_private.h
server/Makefile.in
server/core.c
server/main.c
server/request.c
server/util_expr.c [deleted file]
server/util_expr_eval.c [new file with mode: 0644]
server/util_expr_parse.c [moved from modules/ssl/ssl_expr_parse.c with 71% similarity]
server/util_expr_parse.h [moved from modules/ssl/ssl_expr_parse.h with 73% similarity]
server/util_expr_parse.y [new file with mode: 0644]
server/util_expr_private.h [new file with mode: 0644]
server/util_expr_scan.c [moved from modules/ssl/ssl_expr_scan.c with 65% similarity]
server/util_expr_scan.l [new file with mode: 0644]

diff --git a/CHANGES b/CHANGES
index 737a1474c7ed68f9a760f5a3cc5f095631c828f4..4272cd0d4302c6860b46f46fe6ac07fb7dd62ddd 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -6,6 +6,12 @@ Changes with Apache 2.3.9
      Fix a denial of service attack against mod_reqtimeout.
      [Stefan Fritsch]
 
+  *) core, mod_include, mod_ssl: Move the expression parser derived from
+     mod_include back into mod_include. Replace ap_expr with a parser
+     derived from mod_ssl's parser. Make mod_ssl use the new parser. Rework
+     ap_expr's public interface and provide hooks for modules to add variables
+     and functions. [Stefan Fritsch]
+
   *) core: Do the hook sorting earlier so that the hooks are properly sorted
      for the pre_config hook and during parsing the config. [Stefan Fritsch] 
 
index 772610343a12899c863e46f74d37653fa93d94a1..afa3f3896b2acd1d1506b46cfc0c1a21b04e41af 100755 (executable)
--- a/buildconf
+++ b/buildconf
@@ -226,15 +226,15 @@ if [ -f `which cut` ]; then
     > httpd.spec )
 fi
 
-# ensure that the mod_ssl expression parser sources are never regenerated
+# ensure that the ap_expr expression parser sources are never regenerated
 # when running make
-echo fixing timestamps for mod_ssl sources
-cd modules/ssl
-touch ssl_expr_parse.y
+echo fixing timestamps for ap_expr sources
+cd server
+touch util_expr_parse.y
 sleep 1
-touch ssl_expr_parse.c ssl_expr_parse.h ssl_expr_scan.l
+touch util_expr_parse.c util_expr_parse.h util_expr_scan.l
 sleep 1
-touch ssl_expr_scan.c
-cd ../..
+touch util_expr_scan.c
+cd ..
 
 exit 0
index 99f2d1d883530b0ae6e377a1f79fde95d12bc276..b71c40aee2e5246f105ea4dc74be2146bf6a200f 100644 (file)
 #define AP_EXPR_H
 
 #include "httpd.h"
+#include "http_config.h"
 #include "ap_regex.h"
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
-/* conditional expression parser stuff */
-typedef enum {
-    TOKEN_STRING,
-    TOKEN_RE,
-    TOKEN_AND,
-    TOKEN_OR,
-    TOKEN_NOT,
-    TOKEN_EQ,
-    TOKEN_NE,
-    TOKEN_RBRACE,
-    TOKEN_LBRACE,
-    TOKEN_GROUP,
-    TOKEN_GE,
-    TOKEN_LE,
-    TOKEN_GT,
-    TOKEN_LT,
-    TOKEN_ACCESS,
-    TOKEN_IN
-} token_type_t;
+/** A node in the expression parse tree */
+typedef struct ap_expr_node ap_expr;
 
+/** Struct describing a parsed expression */
 typedef struct {
-    token_type_t  type;
-    const char   *value;
-#ifdef DEBUG_INCLUDE
-    const char   *s;
-#endif
-} token_t;
-
-typedef struct parse_node {
-    struct parse_node *parent;
-    struct parse_node *left;
-    struct parse_node *right;
-    token_t token;
-    int value;
-    int done;
-#ifdef DEBUG_INCLUDE
-    int dump_done;
-#endif
-} ap_parse_node_t;
+    /** The root of the actual expression parse tree */
+    ap_expr *root_node;
+    /** The filename where the expression has been defined (for logging).
+     *  May be NULL
+     */
+    const char *filename;
+    /** The line number where the expression has been defined (for logging). */
+    unsigned int line_number;
+#define AP_EXPR_FLAGS_SSL_EXPR_COMPAT       1
+    /** Flags relevant for the expression */
+    unsigned int flags;
+    /** The module that is used for loglevel configuration (XXX put into eval_ctx?) */
+    int module_index;
+} ap_expr_info_t;
 
-typedef struct {
-    const char *source;
-    const char *rexp;
-    apr_size_t  nsub;
-    ap_regmatch_t match[AP_MAX_REG_MATCH];
-    int have_match;
-} backref_t;
 
-typedef const char *(*string_func_t)(request_rec*, const char*);
-typedef int (*opt_func_t)(request_rec*, ap_parse_node_t*, string_func_t);
-
-/**
- * Parse an expression into a parse tree
- * @param pool Pool
- * @param expr The expression to parse
- * @param was_error On return, set to zero if parse successful, nonzero on error
- * @return The parse tree
- */
-AP_DECLARE(ap_parse_node_t*) ap_expr_parse(apr_pool_t *pool, const char *expr,
-                                           int *was_error);
 /**
  * Evaluate a parse tree
  * @param r The current request
- * @param root The root node of the parse tree
- * @param was_error On return, set to zero if parse successful, nonzero on error
- * @param reptr Regular expression memory for backreferencing if a regexp was parsed
- * @param string_func String parser function - perform variable substitutions
- *                    Use ap_expr_string where applicable
- * @param eval_func Option evaluation function (e.g. -A filename)
- * @return the value the expression parsed to
+ * @param expr The expression to be evaluated
+ * @param err A more detailed error string
+ * @return > 0 if expression evaluates to true, == 0 if false, < 0 on error
  */
-AP_DECLARE(int) ap_expr_eval(request_rec *r, const ap_parse_node_t *root,
-                             int *was_error, backref_t **reptr,
-                             string_func_t string_func, opt_func_t eval_func);
+AP_DECLARE(int) ap_expr_exec(request_rec *r, const ap_expr_info_t *expr,
+                             const char **err);
+
+/** Context used during evaluation of a parse tree, created by ap_expr_exec */
+typedef struct {
+    /** the current request */
+    request_rec *r;
+    /** the current connection */
+    conn_rec *c;
+    /** the current connection */
+    server_rec *s;
+    /** the pool to use */
+    apr_pool_t *p;
+    /** where to store the error string */
+    const char **err;
+    /** ap_expr_info_t for the expression */
+    const ap_expr_info_t *info;
+} ap_expr_eval_ctx;
+
+
 /**
- * Evaluate an expression.  This is functionally equivalent to
- * ap_expr_parse followed by ap_expr_eval, but faster and more efficient
- * when an expression only needs to be parsed once and discarded.
- * @param r The current request
- * @param expr The expression to parse
- * @param was_error On return, set to zero if parse successful, nonzero on error
- * @param reptr Regular expression memory for backreferencing if a regexp was parsed
- * @param string_func String parser function - perform variable substitutions
- *                    Use ap_expr_string where applicable
- * @param eval_func Option evaluation function (e.g. -A filename)
- * @return the value the expression parsed to
+ * The parse can be extended with variable lookup, functions, and
+ * and operators.
+ *
+ * During parsing, the parser calls the lookup function to resolve a
+ * name into a function pointer and an opaque context for the function.
+ *
+ * The default lookup function is the hook 'ap_run_expr_lookup'.
+ * Modules can use it to make functions and variables generally available.
+ *
+ * An ap_expr consumer can also provide its own custom lookup function to
+ * modify the set of variables and functions that are available. The custom
+ * lookup function can in turn call 'ap_run_expr_lookup'.
+ */
+
+/** Unary operator, takes one string argument and returns a bool value.
+ * The name must have the form '-z' (one letter only).
+ * @param ctx The evaluation context
+ * @param data An opaque context provided by the lookup hook function
+ * @param arg The (right) operand
+ * @return 0 or 1
+ */
+typedef int ap_expr_op_unary_t(ap_expr_eval_ctx *ctx, const void *data,
+                               const char *arg);
+
+/** Binary operator, takes two string arguments and returns a bool value.
+ * The name must have the form '-cmp' (at least two letters).
+ * @param ctx The evaluation context
+ * @param data An opaque context provided by the lookup hook function
+ * @param arg1 The left operand
+ * @param arg2 The right operand
+ * @return 0 or 1
+ */
+typedef int ap_expr_op_binary_t(ap_expr_eval_ctx *ctx, const void *data,
+                                const char *arg1, const char *arg2);
+
+/** String valued function, takes a string argument and returns a string
+ * @param ctx The evaluation context
+ * @param data An opaque context provided by the lookup hook function
+ * @param arg The argument
+ * @return The functions result string, may be NULL for 'empty string'
+ */
+typedef const char *(ap_expr_string_func_t)(ap_expr_eval_ctx *ctx, const void *data,
+                                            const char *arg);
+
+/** List valued function, takes a string argument and returns a list of strings
+ * Can currently only be called following the builtin '-in' operator.
+ * @param ctx The evaluation context
+ * @param data An opaque context provided by the lookup hook function
+ * @param arg The argument
+ * @return The functions result list of strings, may be NULL for 'empty array'
  */
-AP_DECLARE(int) ap_expr_evalstring(request_rec *r, const char *expr,
-                                   int *was_error, backref_t **reptr,
-                                   string_func_t string_func,
-                                   opt_func_t eval_func);
+typedef apr_array_header_t *(ap_expr_list_func_t)(ap_expr_eval_ctx *ctx, const void *data,
+                                                  const char *arg);
+
+/** Variable lookup function, takes no argument and returns a string
+ * @param ctx The evaluation context
+ * @param data An opaque context provided by the lookup hook function
+ * @return The expanded variable
+ */
+typedef const char *(ap_expr_var_func_t)(ap_expr_eval_ctx *ctx, const void *data);
+
+/** parameter struct passed to the lookup hook functions */
+typedef struct {
+    /** type of the looked up object */
+    int type;
+#define AP_EXPR_FUNC_VAR        0
+#define AP_EXPR_FUNC_STRING     1
+#define AP_EXPR_FUNC_LIST       2
+#define AP_EXPR_FUNC_OP_UNARY   3
+#define AP_EXPR_FUNC_OP_BINARY  4
+    /** name of the looked up object */
+    const char *name;
+
+    int flags;
+
+    apr_pool_t *pool;
+    apr_pool_t *ptemp;
+
+    /** where to store the function pointer */
+    const void **func;
+    /** where to store the function's context */
+    const void **data;
+    /** Where to store the error message (if any) */
+    const char **err;
+} ap_expr_lookup_parms;
+
+/** Function for looking up the provider function for a variable, operator
+ *  or function in an expression.
+ *  @param parms The parameter struct, also determins where the result is
+ *               stored.
+ *  @return OK on success,
+ *          !OK on failure,
+ *          DECLINED if the requested name is not handled by this function
+ */
+typedef int (ap_expr_lookup_fn)(ap_expr_lookup_parms *parms);
+
+AP_DECLARE_HOOK(int, expr_lookup, (ap_expr_lookup_parms *parms))
 
 /**
- * Internal initialisation of ap_expr (for httpd)
+ * Parse an expression into a parse tree
  * @param pool Pool
- * @return APR_SUCCESS or error
+ * @param ptemp temp pool
+ * @param info The ap_expr_info_t struct (with values filled in)
+ * @param expr The expression string to parse
+ * @param lookup_fn The lookup function to use, NULL for default
+ * @return NULL on success, error message on error.
+ *         A pointer to the resulting parse tree will be stored in
+ *         info->root_node.
  */
-AP_DECLARE(apr_status_t) ap_expr_init(apr_pool_t *pool);
+AP_DECLARE(const char *) ap_expr_parse(apr_pool_t *pool, apr_pool_t *ptemp,
+                                       ap_expr_info_t *info, const char *expr,
+                                       ap_expr_lookup_fn *lookup_fn);
 
 /**
- * Default string evaluation function for passing to ap_expr_eval and
- * ap_expr_evalstring.  Use this (and update as necessary) to offer
- * a consistent expression syntax across different modules.
- * Supports the following:
- *     $req{foo}     - request header "foo"
- *     $resp{foo}    - response header "foo"
- *     $env{foo}     - environment variable "foo"
- *     $handler      - r->handler
- *     $content-type - r->content_type
- * Other strings are returned unmodified.
- * @param r The current request
- * @param str The string to evaluate
- * @return The evaluated string
+ * High level interface to ap_expr_parse that also creates ap_expr_info_t and
+ * uses info from cmd_parms to fill in most of it.
+ * @param cmd The cmd_parms struct
+ * @param expr The expression string to parse
+ * @param err Set to NULL on success, error message on error
+ * @return The parsed expression
  */
-AP_DECLARE_NONSTD(const char*) ap_expr_string(request_rec *r, 
-                                              const char *str);
+AP_DECLARE(ap_expr_info_t *) ap_expr_parse_cmd(const cmd_parms *cmd,
+                                               const char *expr,
+                                               const char **err,
+                                               ap_expr_lookup_fn *lookup_fn);
+
+
+ /**
+  * Internal initialisation of ap_expr (for httpd internal use)
+  */
+void ap_expr_init(apr_pool_t *pool);
 
 #ifdef __cplusplus
 }
index 2eec68b3e703af98f324d08482221157f3425b08..f5de1ccc638c32c453ae829bc4710cf0ad41d6a2 100644 (file)
  * 20101016.0 (2.3.9-dev)  Remove ap_cache_check_allowed().
  * 20101017.0 (2.3.9-dev)  Make ap_cache_control() public, add cache_control_t
  *                         to mod_disk_cache format.
+ * 20101106.0 (2.3.9-dev)  Replace the ap_expr parser derived from
+ *                         mod_include's parser with one derived from
+ *                         mod_ssl's parser. Clean up ap_expr's public
+ *                         interface.
  */
 
 #define MODULE_MAGIC_COOKIE 0x41503234UL /* "AP24" */
 
 #ifndef MODULE_MAGIC_NUMBER_MAJOR
-#define MODULE_MAGIC_NUMBER_MAJOR 20101017
+#define MODULE_MAGIC_NUMBER_MAJOR 20101106
 #endif
 #define MODULE_MAGIC_NUMBER_MINOR 0                     /* 0...n */
 
index 858d8b57413f13b1a54ee8a5f53e40b86cd362ca..f3b7f5b9100d0bc9b6637c08c613ce470eb8f093 100644 (file)
@@ -534,7 +534,7 @@ typedef struct {
 #define USE_CANONICAL_PHYS_PORT_UNSET (2)
     unsigned use_canonical_phys_port : 2;
 
-    ap_parse_node_t *condition;   /* Conditionally merge <If> sections */
+    ap_expr_info_t *condition;   /* Conditionally merge <If> sections */
 
     /** per-dir log config */
     struct ap_logconf *log;
index 7ca38e7a298b2f1b5875e7f7e4887327304a0898..73b13ab5308deebd66fcaeace060bf8ddd22f6ca 100644 (file)
@@ -988,20 +988,22 @@ static authz_status expr_check_authorization(request_rec *r,
                                              const char *require_line,
                                              const void *parsed_require_line)
 {
-    int err = 0;
-    const ap_parse_node_t *expr = parsed_require_line;
+    const char *err = NULL;
+    const ap_expr_info_t *expr = parsed_require_line;
+    int rc = ap_expr_exec(r, expr, &err);
 
-    if (ap_expr_eval(r, expr, &err, NULL, ap_expr_string, NULL))
-        return AUTHZ_GRANTED;
-    else
+    if (err || !rc)
+           /* XXX: real error handling? */
         return AUTHZ_DENIED;
+    else
+        return AUTHZ_GRANTED;
 }
 
 static const char *expr_parse_config(cmd_parms *cmd, const char *require_line,
                                      const void **parsed_require_line)
 {
-    int expr_err = 0;
-    ap_parse_node_t *expr = ap_expr_parse(cmd->pool, require_line, &expr_err);
+    const char *expr_err = NULL;
+    ap_expr_info_t *expr = ap_expr_parse_cmd(cmd, require_line, &expr_err, NULL);
 
     if (expr_err)
         return "Cannot parse expression in require line";
index 3970c836e74b98bb0e4f80b64cac202a319b5a44..250c02d147287bf7f2a04827d442028dab20dfbe 100644 (file)
@@ -36,7 +36,7 @@ module AP_MODULE_DECLARE_DATA filter_module;
  * (2.0-compatible) ap_filter_rec_t* frec.
  */
 struct ap_filter_provider_t {
-    ap_parse_node_t *expr;
+    ap_expr_info_t *expr;
 
     /** The filter that implements this provider */
     ap_filter_rec_t *frec;
@@ -134,7 +134,7 @@ static int filter_lookup(ap_filter_t *f, ap_filter_rec_t *filter)
 {
     ap_filter_provider_t *provider;
     int match;
-    int err = 0;
+    const char *err = NULL;
     unsigned int proto_flags;
     request_rec *r = f->r;
     harness_ctx *ctx = f->ctx;
@@ -146,11 +146,12 @@ static int filter_lookup(ap_filter_t *f, ap_filter_rec_t *filter)
 
     /* Check registered providers in order */
     for (provider = filter->providers; provider; provider = provider->next) {
-        match = ap_expr_eval(r, provider->expr, &err, NULL, ap_expr_string, NULL);
+        match = ap_expr_exec(r, provider->expr, &err);
         if (err) {
             /* log error but accept match value ? */
             ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
-                          "Error evaluating filter dispatch condition");
+                          "Error evaluating filter dispatch condition: %s",
+                          err);
         }
 
         if (match) {
@@ -402,8 +403,8 @@ static const char *filter_provider(cmd_parms *cmd, void *CFG,
     const char *c;
     ap_filter_rec_t* frec;
     ap_filter_rec_t* provider_frec;
-    ap_parse_node_t *node;
-    int err = 0;
+    ap_expr_info_t *node;
+    const char *err = NULL;
 
     /* fname has been declared with DeclareFilter, so we can look it up */
     frec = apr_hash_get(cfg->live_filters, fname, APR_HASH_KEY_STRING);
@@ -426,9 +427,11 @@ static const char *filter_provider(cmd_parms *cmd, void *CFG,
     if (!provider_frec) {
         return apr_psprintf(cmd->pool, "Unknown filter provider %s", pname);
     }
-    node = ap_expr_parse(cmd->pool, expr, &err);
+    node = ap_expr_parse_cmd(cmd, expr, &err, NULL);
     if (err) {
-        return "Error parsing FilterProvider expression.";
+        return apr_pstrcat(cmd->pool,
+                           "Error parsing FilterProvider expression:", err,
+                           NULL);
     }
 
     provider = apr_palloc(cmd->pool, sizeof(ap_filter_provider_t));
@@ -545,7 +548,7 @@ static const char *filter_bytype1(cmd_parms *cmd, void *CFG,
         *p++ = *type++;
     } while (*type);
     *p = 0;
-    expr = apr_psprintf(cmd->temp_pool, "$content-type = /^%s/", etype);
+    expr = apr_psprintf(cmd->temp_pool, "%%{CONTENT_TYPE} =~ m!^%s!", etype);
 
     rv = filter_provider(cmd, CFG, fname, pname, expr);
 
index b02ed715af03f1914b60e6dcd17dd9ce89974833..505cb06eaeaad53f7bf203494468d8e236850fbb 100644 (file)
@@ -130,7 +130,7 @@ typedef struct {
     ap_regex_t *regex;
     const char *condition_var;
     const char *subs;
-    ap_parse_node_t *expr;
+    ap_expr_info_t *expr;
 } header_entry;
 
 /* echo_do is used for Header echo to iterate through the request headers*/
@@ -398,7 +398,7 @@ static APR_INLINE const char *header_inout_cmd(cmd_parms *cmd,
     const char *condition_var = NULL;
     const char *colon;
     header_entry *new;
-    ap_parse_node_t *expr = NULL;
+    ap_expr_info_t *expr = NULL;
 
     apr_array_header_t *fixup = (cmd->info == &hdr_in)
         ? dirconf->fixup_in   : (cmd->info == &hdr_out_always)
@@ -491,10 +491,12 @@ static APR_INLINE const char *header_inout_cmd(cmd_parms *cmd,
             condition_var = envclause + 4;
         }
         else {
-            int err = 0;
-            expr = ap_expr_parse(cmd->pool, envclause, &err);
+            const char *err = NULL;
+            expr = ap_expr_parse_cmd(cmd, envclause, &err, NULL);
             if (err) {
-                return "Can't parse envclause/expression";
+                return apr_pstrcat(cmd->pool,
+                                   "Can't parse envclause/expression: ", err,
+                                   NULL);
             }
         }
     }
@@ -645,12 +647,12 @@ static void do_headers_fixup(request_rec *r, apr_table_t *headers,
         }
         /* Do we have an expression to evaluate? */
         else if (hdr->expr != NULL) {
-            int err = 0;
-            int eval = ap_expr_eval(r, hdr->expr, &err, NULL,
-                                    ap_expr_string, NULL);
+            const char *err = NULL;
+            int eval = ap_expr_exec(r, hdr->expr, &err);
             if (err) {
                 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
-                              "Failed to evaluate expression - ignoring");
+                              "Failed to evaluate expression (%s) - ignoring",
+                              err);
             }
             else if (!eval) {
                 continue;
index e8a88876d0ada0f81ac076776510e041dd6b1db0..4395bc3ac765b000d238b9e92c9b8eb104b5ee65 100644 (file)
 #
 
 include $(top_srcdir)/build/special.mk
-
-#
-#   developer stuff
-#   (we really don't expect end users to use these targets!)
-#
-
-ssl_expr_scan.c: $(top_srcdir)/modules/ssl/ssl_expr_scan.l ssl_expr_parse.h
-       flex -Pssl_expr_yy -o ssl_expr_scan.c $(top_srcdir)/ssl_expr_scan.l
-       mv ssl_expr_scan.c ssl_expr_scan.c.tmp
-       sed -e "s|\"`pwd`/|\"|g" <ssl_expr_scan.c.tmp >ssl_expr_scan.c
-       rm -f ssl_expr_scan.c.tmp
-
-ssl_expr_parse.c ssl_expr_parse.h: $(top_srcdir)/modules/ssl/ssl_expr_parse.y
-       bison -pssl_expr_yy --defines=ssl_expr_parse.h -o ssl_expr_parse.c $(top_srcdir)/modules/ssl/ssl_expr_parse.y
-       mv ssl_expr_parse.c ssl_expr_parse.c.tmp
-       sed -e "s|\"`pwd`/|\"|g" < ssl_expr_parse.c.tmp > ssl_expr_parse.c
-       rm -f ssl_expr_parse.c.tmp
index 2ef06cdcfb7f72cddceee4c5d2cac564ac27aaf7..b020acafcb049b722522a49aadfd4e623c88fc44 100644 (file)
@@ -35,10 +35,6 @@ ssl_engine_mutex.lo dnl
 ssl_engine_pphrase.lo dnl
 ssl_engine_rand.lo dnl
 ssl_engine_vars.lo dnl
-ssl_expr.lo dnl
-ssl_expr_eval.lo dnl
-ssl_expr_parse.lo dnl
-ssl_expr_scan.lo dnl
 ssl_scache.lo dnl
 ssl_util_stapling.lo dnl
 ssl_util.lo dnl
index aa2dec8401520b8398a0392bd079870c2934d858..3d090cb15b10f58b6559486f9fce92025546397b 100644 (file)
@@ -565,11 +565,6 @@ static void ssl_register_hooks(apr_pool_t *p)
                               &ssl_authz_provider_verify_client,
                               AP_AUTH_INTERNAL_PER_CONF);
 
-    ap_register_auth_provider(p, AUTHZ_PROVIDER_GROUP, "ssl-require",
-                              AUTHZ_PROVIDER_VERSION,
-                              &ssl_authz_provider_sslrequire,
-                              AP_AUTH_INTERNAL_PER_CONF);
-
 }
 
 module AP_MODULE_DECLARE_DATA ssl_module = {
index b3dbfef63e982a7a6de42be57491285e45f9f2ed..0ed504422ef3a19c57b7dc6f95c0f96ae8cf79e0 100644 (file)
@@ -1147,17 +1147,21 @@ const char *ssl_cmd_SSLRequire(cmd_parms *cmd,
                                const char *arg)
 {
     SSLDirConfigRec *dc = (SSLDirConfigRec *)dcfg;
-    ssl_expr *expr;
+    ap_expr_info_t *info = apr_pcalloc(cmd->pool, sizeof(ap_expr_info_t));
     ssl_require_t *require;
     const char *errstring;
 
-    if (!(expr = ssl_expr_comp(cmd->pool, arg, &errstring))) {
+    info->flags = AP_EXPR_FLAGS_SSL_EXPR_COMPAT;
+    info->filename = cmd->directive->filename;
+    info->line_number = cmd->directive->line_num;
+    errstring = ap_expr_parse(cmd->pool, cmd->temp_pool, info, arg, NULL);
+    if (errstring) {
         return apr_pstrcat(cmd->pool, "SSLRequire: ", errstring, NULL);
     }
 
     require = apr_array_push(dc->aRequirement);
     require->cpExpr = apr_pstrdup(cmd->pool, arg);
-    require->mpExpr = expr;
+    require->mpExpr = info;
 
     return NULL;
 }
index c374ce0fae661490f633d1857e96184ff270c9c2..2f736c26d864a3147a38ad9578f75341d49b0d3f 100644 (file)
@@ -302,7 +302,6 @@ int ssl_hook_Access(request_rec *r)
     SSL_CTX *ctx = NULL;
     apr_array_header_t *requires;
     ssl_require_t *ssl_requires;
-    char *cp;
     int ok, i;
     BOOL renegotiate = FALSE, renegotiate_quick = FALSE;
     X509 *cert;
@@ -900,17 +899,13 @@ int ssl_hook_Access(request_rec *r)
     for (i = 0; i < requires->nelts; i++) {
         ssl_require_t *req = &ssl_requires[i];
         const char *errstring;
-        ok = ssl_expr_exec(r, req->mpExpr, &errstring);
+        ok = ap_expr_exec(r, req->mpExpr, &errstring);
 
         if (ok < 0) {
-            cp = apr_psprintf(r->pool,
-                              "Failed to execute "
-                              "SSL requirement expression: %s",
-                              errstring);
-
             ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
-                          "access to %s failed, reason: %s",
-                          r->filename, cp);
+                          "access to %s failed, reason: Failed to execute "
+                          "SSL requirement expression: %s",
+                          r->filename, errstring);
 
             /* remember forbidden access for strict require option */
             apr_table_setn(r->notes, "ssl-access-forbidden", "1");
@@ -1282,54 +1277,6 @@ const authz_provider ssl_authz_provider_verify_client =
 };
 
 
-static authz_status ssl_authz_sslrequire_check(request_rec *r,
-                                               const char *require_line,
-                                               const void *parsed)
-{
-    const ssl_expr *expr = parsed;
-    const char *errstring;
-    int ok = ssl_expr_exec(r, expr, &errstring);
-
-    if (ok < 0) {
-        ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
-                      "Failed to execute SSL requirement expression in "
-                      "'Require ssl-require': %s",
-                      errstring);
-        return AUTHZ_DENIED;
-    }
-
-    if (ok != 1) {
-        ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r,
-                      "SSL requirement expression in 'Require ssl-require' "
-                      "not fulfilled");
-        return AUTHZ_DENIED;
-    }
-
-    return AUTHZ_GRANTED;
-}
-
-static const char *ssl_authz_sslrequire_parse(cmd_parms *cmd,
-                                              const char *require_line,
-                                              const void **parsed)
-{
-    const char *errstring;
-    ssl_expr *expr = ssl_expr_comp(cmd->pool, require_line, &errstring);
-
-    if (!expr)
-        return apr_psprintf(cmd->pool, "Error in 'Require require-ssl': %s",
-                            errstring);
-
-    *parsed = expr;
-
-    return NULL;
-}
-
-const authz_provider ssl_authz_provider_sslrequire =
-{
-    &ssl_authz_sslrequire_check,
-    &ssl_authz_sslrequire_parse,
-};
-
 
 /*  _________________________________________________________________
 **
index 62127fff2d1ffdde5733378769b3949ad9ef5deb..f88eebfd4d84d7aaf035206e11a9cf12431c6ec7 100644 (file)
@@ -29,6 +29,7 @@
                                                   -- Unknown       */
 #include "ssl_private.h"
 #include "mod_ssl.h"
+#include "ap_expr.h"
 
 #include "apr_time.h"
 
@@ -62,6 +63,45 @@ static const char var_interface[] = "mod_ssl/" MOD_SSL_VERSION;
 static char var_library_interface[] = SSL_LIBRARY_TEXT;
 static char *var_library = NULL;
 
+static apr_array_header_t *expr_peer_ext_list_fn(ap_expr_eval_ctx *ctx,
+                                                 const void *dummy,
+                                                 const char *arg)
+{
+    return ssl_ext_list(ctx->p, ctx->c, 1, arg);
+}
+
+static const char *expr_var_fn(ap_expr_eval_ctx *ctx, const void *data)
+{
+    char *var = (char *)data;
+    return ssl_var_lookup_ssl(ctx->p, ctx->c, var);
+}
+
+static int ssl_expr_lookup(ap_expr_lookup_parms *parms)
+{
+    switch (parms->type) {
+    case AP_EXPR_FUNC_VAR:
+        /* for now, we just handle everything that starts with SSL_, but
+         * register our hook as APR_HOOK_LAST
+         * XXX: This can be optimized
+         */
+        if (strcEQn(parms->name, "SSL_", 4)) {
+            *parms->func = expr_var_fn;
+            *parms->data = parms->name + 4;
+            return OK;
+        }
+        break;
+    case AP_EXPR_FUNC_LIST:
+        if (strcEQ(parms->name, "PeerExtList")) {
+            *parms->func = expr_peer_ext_list_fn;
+            *parms->data = "PeerExtList";
+            return OK;
+        }
+       break;
+    }
+    return DECLINED;
+}
+
+
 void ssl_var_register(apr_pool_t *p)
 {
     char *cp, *cp2;
@@ -84,6 +124,8 @@ void ssl_var_register(apr_pool_t *p)
         if ((cp2 = strchr(cp, ' ')) != NULL)
             *cp2 = NUL;
     }
+
+    ap_hook_expr_lookup(ssl_expr_lookup, NULL, NULL, APR_HOOK_MIDDLE);
 }
 
 /* This function must remain safe to use for a non-SSL connection. */
@@ -984,3 +1026,4 @@ static const char *ssl_var_log_handler_x(request_rec *r, char *a)
     return result;
 }
 
+
diff --git a/modules/ssl/ssl_expr.c b/modules/ssl/ssl_expr.c
deleted file mode 100644 (file)
index 04262af..0000000
+++ /dev/null
@@ -1,85 +0,0 @@
-/* Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*                      _             _
- *  _ __ ___   ___   __| |    ___ ___| |  mod_ssl
- * | '_ ` _ \ / _ \ / _` |   / __/ __| |  Apache Interface to OpenSSL
- * | | | | | | (_) | (_| |   \__ \__ \ |
- * |_| |_| |_|\___/ \__,_|___|___/___/_|
- *                      |_____|
- *  ssl_expr.c
- *  Expression Handling
- */
-                             /* ``It is hard to fly with
-                                  the eagles when you work
-                                  with the turkeys.''
-                                          -- Unknown  */
-#include "ssl_private.h"
-
-/*  _________________________________________________________________
-**
-**  Expression Handling
-**  _________________________________________________________________
-*/
-
-
-ssl_expr *ssl_expr_comp(apr_pool_t *p, const char *expr, const char **err)
-{
-    ssl_expr_info_type context;
-    int rc;
-
-    context.pool     = p;
-    context.inputbuf = expr;
-    context.inputlen = strlen(expr);
-    context.inputptr = context.inputbuf;
-    context.expr     = FALSE;
-    context.error    = NULL;
-
-    ssl_expr_yylex_init(&context.scanner);
-    ssl_expr_yyset_extra(&context, context.scanner);
-    rc = ssl_expr_yyparse(&context);
-    ssl_expr_yylex_destroy(context.scanner);
-    *err = context.error;
-
-    if (rc)
-        return NULL;
-
-    return context.expr;
-}
-
-ssl_expr *ssl_expr_make(ssl_expr_node_op op, void *a1, void *a2,
-                        ssl_expr_info_type *context)
-{
-    ssl_expr *node;
-
-    node = (ssl_expr *)apr_palloc(context->pool, sizeof(ssl_expr));
-    node->node_op   = op;
-    node->node_arg1 = (char *)a1;
-    node->node_arg2 = (char *)a2;
-    return node;
-}
-
-int ssl_expr_exec(request_rec *r, const ssl_expr *expr, const char **err)
-{
-    BOOL rc;
-
-    *err = NULL;
-    rc = ssl_expr_eval(r, expr, err);
-    if (*err != NULL)
-        return (-1);
-    else
-        return (rc ? 1 : 0);
-}
diff --git a/modules/ssl/ssl_expr.h b/modules/ssl/ssl_expr.h
deleted file mode 100644 (file)
index a8be52c..0000000
+++ /dev/null
@@ -1,109 +0,0 @@
-/* Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/**
- * @verbatim
-                        _             _
-    _ __ ___   ___   __| |    ___ ___| |  mod_ssl
-   | '_ ` _ \ / _ \ / _` |   / __/ __| |  Apache Interface to OpenSSL
-   | | | | | | (_) | (_| |   \__ \__ \ |
-   |_| |_| |_|\___/ \__,_|___|___/___/_|
-                        |_____|
- @endverbatim
- *  @file  ssl_expr.h
- *  @brief Expression Handling (Header).
- *         ``May all your PUSHes be POPed.'' 
- * 
- * @defgroup MOD_SSL_EXPR Expression Handling
- * @ingroup MOD_SSL
- * @{
- */
-
-#ifndef __SSL_EXPR_H__
-#define __SSL_EXPR_H__
-
-#ifndef FALSE
-#define FALSE 0
-#endif
-
-#ifndef TRUE
-#define TRUE !FALSE
-#endif
-
-#ifndef YY_NULL
-#define YY_NULL 0
-#endif
-
-#ifndef MIN
-#define MIN(a,b) (((a)<(b))?(a):(b))
-#endif
-
-#ifndef BOOL
-#define BOOL unsigned int
-#endif
-
-#ifndef NULL
-#define NULL (void *)0
-#endif
-
-#ifndef NUL
-#define NUL '\0'
-#endif
-
-#ifndef YYDEBUG
-#define YYDEBUG 0
-#endif
-
-typedef enum {
-    op_NOP, op_ListElement, op_PeerExtElement,
-    op_True, op_False, op_Not, op_Or, op_And, op_Comp,
-    op_EQ, op_NE, op_LT, op_LE, op_GT, op_GE, op_IN, op_REG, op_NRE,
-    op_Digit, op_String, op_Regex, op_Var, op_Func
-} ssl_expr_node_op;
-
-typedef struct {
-    ssl_expr_node_op node_op;
-    void *node_arg1;
-    void *node_arg2;
-} ssl_expr_node;
-
-typedef ssl_expr_node ssl_expr;
-
-typedef struct {
-    apr_pool_t *pool;
-    const char *inputbuf;
-    int         inputlen;
-    const char *inputptr;
-    ssl_expr   *expr;
-    void       *scanner;
-    char       *error;
-} ssl_expr_info_type;
-
-int  ssl_expr_yyparse(ssl_expr_info_type *context);
-int  ssl_expr_yyerror(ssl_expr_info_type *context, char *errstring);
-int  ssl_expr_yylex_init(void **scanner);
-int  ssl_expr_yylex_destroy(void *scanner);
-void ssl_expr_yyset_extra(ssl_expr_info_type *context, void *scanner);
-
-ssl_expr *ssl_expr_comp(apr_pool_t *p, const char *exprstr, const char **err);
-int       ssl_expr_exec(request_rec *r, const ssl_expr *expr, const char **err);
-ssl_expr *ssl_expr_make(ssl_expr_node_op op, void *arg1, void *arg2,
-                        ssl_expr_info_type *context);
-BOOL      ssl_expr_eval(request_rec *r, const ssl_expr *expr, const char **err);
-
-#endif /* __SSL_EXPR_H__ */
-/** @} */
-
diff --git a/modules/ssl/ssl_expr_eval.c b/modules/ssl/ssl_expr_eval.c
deleted file mode 100644 (file)
index 9480048..0000000
+++ /dev/null
@@ -1,290 +0,0 @@
-/* Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*                      _             _
- *  _ __ ___   ___   __| |    ___ ___| |  mod_ssl
- * | '_ ` _ \ / _ \ / _` |   / __/ __| |  Apache Interface to OpenSSL
- * | | | | | | (_) | (_| |   \__ \__ \ |
- * |_| |_| |_|\___/ \__,_|___|___/___/_|
- *                      |_____|
- *  ssl_expr_eval.c
- *  Expression Evaluation
- */
-                             /* ``Make love,
-                                  not software!''
-                                        -- Unknown */
-#include "ssl_private.h"
-
-/*  _________________________________________________________________
-**
-**  Expression Evaluation
-**  _________________________________________________________________
-*/
-
-static BOOL  ssl_expr_eval_comp(request_rec *, ssl_expr *, const char **err);
-static char *ssl_expr_eval_word(request_rec *, ssl_expr *, const char **err);
-static BOOL  ssl_expr_eval_oid(request_rec *r, const char *word,
-                               const char *oidstr, const char **err);
-static char *ssl_expr_eval_func_file(request_rec *, char *, const char **err);
-static int   ssl_expr_eval_strcmplex(char *, char *, const char **err);
-
-BOOL ssl_expr_eval(request_rec *r, const ssl_expr *node, const char **err)
-{
-    switch (node->node_op) {
-        case op_True: {
-            return TRUE;
-        }
-        case op_False: {
-            return FALSE;
-        }
-        case op_Not: {
-            ssl_expr *e = (ssl_expr *)node->node_arg1;
-            return (!ssl_expr_eval(r, e, err));
-        }
-        case op_Or: {
-            ssl_expr *e1 = (ssl_expr *)node->node_arg1;
-            ssl_expr *e2 = (ssl_expr *)node->node_arg2;
-            return (ssl_expr_eval(r, e1, err) || ssl_expr_eval(r, e2, err));
-        }
-        case op_And: {
-            ssl_expr *e1 = (ssl_expr *)node->node_arg1;
-            ssl_expr *e2 = (ssl_expr *)node->node_arg2;
-            return (ssl_expr_eval(r, e1, err) && ssl_expr_eval(r, e2, err));
-        }
-        case op_Comp: {
-            ssl_expr *e = (ssl_expr *)node->node_arg1;
-            return ssl_expr_eval_comp(r, e, err);
-        }
-        default: {
-            *err = "Internal evaluation error: Unknown expression node";
-            return FALSE;
-        }
-    }
-}
-
-static BOOL ssl_expr_eval_comp(request_rec *r, ssl_expr *node, const char **err)
-{
-    switch (node->node_op) {
-        case op_EQ: {
-            ssl_expr *e1 = (ssl_expr *)node->node_arg1;
-            ssl_expr *e2 = (ssl_expr *)node->node_arg2;
-            return (strcmp(ssl_expr_eval_word(r, e1, err), ssl_expr_eval_word(r, e2, err)) == 0);
-        }
-        case op_NE: {
-            ssl_expr *e1 = (ssl_expr *)node->node_arg1;
-            ssl_expr *e2 = (ssl_expr *)node->node_arg2;
-            return (strcmp(ssl_expr_eval_word(r, e1, err), ssl_expr_eval_word(r, e2, err)) != 0);
-        }
-        case op_LT: {
-            ssl_expr *e1 = (ssl_expr *)node->node_arg1;
-            ssl_expr *e2 = (ssl_expr *)node->node_arg2;
-            return (ssl_expr_eval_strcmplex(ssl_expr_eval_word(r, e1, err), ssl_expr_eval_word(r, e2, err), err) <  0);
-        }
-        case op_LE: {
-            ssl_expr *e1 = (ssl_expr *)node->node_arg1;
-            ssl_expr *e2 = (ssl_expr *)node->node_arg2;
-            return (ssl_expr_eval_strcmplex(ssl_expr_eval_word(r, e1, err), ssl_expr_eval_word(r, e2, err), err) <= 0);
-        }
-        case op_GT: {
-            ssl_expr *e1 = (ssl_expr *)node->node_arg1;
-            ssl_expr *e2 = (ssl_expr *)node->node_arg2;
-            return (ssl_expr_eval_strcmplex(ssl_expr_eval_word(r, e1, err), ssl_expr_eval_word(r, e2, err), err) >  0);
-        }
-        case op_GE: {
-            ssl_expr *e1 = (ssl_expr *)node->node_arg1;
-            ssl_expr *e2 = (ssl_expr *)node->node_arg2;
-            return (ssl_expr_eval_strcmplex(ssl_expr_eval_word(r, e1, err), ssl_expr_eval_word(r, e2, err), err) >= 0);
-        }
-        case op_IN: {
-            ssl_expr *e1 = (ssl_expr *)node->node_arg1;
-            ssl_expr *e2 = (ssl_expr *)node->node_arg2;
-            ssl_expr *e3;
-            char *w1 = ssl_expr_eval_word(r, e1, err);
-            BOOL found = FALSE;
-            do {
-                ssl_expr_node_op op = e2->node_op;
-                e3 = (ssl_expr *)e2->node_arg1;
-                e2 = (ssl_expr *)e2->node_arg2;
-
-                if (op == op_PeerExtElement) {
-                    char *w3 = ssl_expr_eval_word(r, e3, err);
-
-                    found = ssl_expr_eval_oid(r, w1, w3, err);
-
-                    /* There will be no more nodes on the list, so the result is authoritative */
-                    break;
-                }
-
-                if (strcmp(w1, ssl_expr_eval_word(r, e3, err)) == 0) {
-                    found = TRUE;
-                    break;
-                }
-            } while (e2 != NULL);
-            return found;
-        }
-        case op_REG: {
-            ssl_expr *e1;
-            ssl_expr *e2;
-            char *word;
-            ap_regex_t *regex;
-
-            e1 = (ssl_expr *)node->node_arg1;
-            e2 = (ssl_expr *)node->node_arg2;
-            word = ssl_expr_eval_word(r, e1, err);
-            regex = (ap_regex_t *)(e2->node_arg1);
-            return (ap_regexec(regex, word, 0, NULL, 0) == 0);
-        }
-        case op_NRE: {
-            ssl_expr *e1;
-            ssl_expr *e2;
-            char *word;
-            ap_regex_t *regex;
-
-            e1 = (ssl_expr *)node->node_arg1;
-            e2 = (ssl_expr *)node->node_arg2;
-            word = ssl_expr_eval_word(r, e1, err);
-            regex = (ap_regex_t *)(e2->node_arg1);
-            return !(ap_regexec(regex, word, 0, NULL, 0) == 0);
-        }
-        default: {
-            *err = "Internal evaluation error: Unknown expression node";
-            return FALSE;
-        }
-    }
-}
-
-static char *ssl_expr_eval_word(request_rec *r, ssl_expr *node, const char **err)
-{
-    switch (node->node_op) {
-        case op_Digit: {
-            char *string = (char *)node->node_arg1;
-            return string;
-        }
-        case op_String: {
-            char *string = (char *)node->node_arg1;
-            return string;
-        }
-        case op_Var: {
-            char *var = (char *)node->node_arg1;
-            char *val = ssl_var_lookup(r->pool, r->server, r->connection, r, var);
-            return (val == NULL ? "" : val);
-        }
-        case op_Func: {
-            char *name = (char *)node->node_arg1;
-            ssl_expr *args = (ssl_expr *)node->node_arg2;
-            if (strEQ(name, "file"))
-                return ssl_expr_eval_func_file(r, (char *)(args->node_arg1), err);
-            else {
-                *err = "Internal evaluation error: Unknown function name";
-                return "";
-            }
-        }
-        default: {
-            *err = "Internal evaluation error: Unknown expression node";
-            return FALSE;
-        }
-    }
-}
-
-static BOOL ssl_expr_eval_oid(request_rec *r, const char *word,
-                              const char *oidstr, const char **err)
-{
-    int j;
-    BOOL result = FALSE;
-    apr_array_header_t *oid_array;
-    char **oid_value;
-
-    if (NULL == (oid_array = ssl_ext_list(r->pool, r->connection, 1, oidstr))) {
-        return FALSE;
-    }
-
-    oid_value = (char **) oid_array->elts;
-    for (j = 0; j < oid_array->nelts; j++) {
-        if (strcmp(word, oid_value[j]) == 0) {
-            result = TRUE;
-            break;
-        }
-    }
-    return result;
-}
-
-
-static char *ssl_expr_eval_func_file(request_rec *r, char *filename, const char **err)
-{
-    apr_file_t *fp;
-    char *buf;
-    apr_off_t offset;
-    apr_size_t len;
-    apr_finfo_t finfo;
-
-    if (apr_file_open(&fp, filename, APR_READ|APR_BUFFERED,
-                      APR_OS_DEFAULT, r->pool) != APR_SUCCESS) {
-        *err = "Cannot open file";
-        return "";
-    }
-    apr_file_info_get(&finfo, APR_FINFO_SIZE, fp);
-    if ((finfo.size + 1) != ((apr_size_t)finfo.size + 1)) {
-        *err = "Huge file cannot be read";
-        apr_file_close(fp);
-        return "";
-    }
-    len = (apr_size_t)finfo.size;
-    if (len == 0) {
-        buf = (char *)apr_palloc(r->pool, sizeof(char) * 1);
-        *buf = NUL;
-    }
-    else {
-        if ((buf = (char *)apr_palloc(r->pool, sizeof(char)*(len+1))) == NULL) {
-            *err = "Cannot allocate memory";
-            apr_file_close(fp);
-            return "";
-        }
-        offset = 0;
-        apr_file_seek(fp, APR_SET, &offset);
-        if (apr_file_read(fp, buf, &len) != APR_SUCCESS) {
-            *err = "Cannot read from file";
-            apr_file_close(fp);
-            return "";
-        }
-        buf[len] = NUL;
-    }
-    apr_file_close(fp);
-    return buf;
-}
-
-/* a variant of strcmp(3) which works correctly also for number strings */
-static int ssl_expr_eval_strcmplex(char *cpNum1, char *cpNum2, const char **err)
-{
-    int i, n1, n2;
-
-    if (cpNum1 == NULL)
-        return -1;
-    if (cpNum2 == NULL)
-        return +1;
-    n1 = strlen(cpNum1);
-    n2 = strlen(cpNum2);
-    if (n1 > n2)
-        return 1;
-    if (n1 < n2)
-        return -1;
-    for (i = 0; i < n1; i++) {
-        if (cpNum1[i] > cpNum2[i])
-            return 1;
-        if (cpNum1[i] < cpNum2[i])
-            return -1;
-    }
-    return 0;
-}
diff --git a/modules/ssl/ssl_expr_parse.y b/modules/ssl/ssl_expr_parse.y
deleted file mode 100644 (file)
index ce270b6..0000000
+++ /dev/null
@@ -1,169 +0,0 @@
-/* Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*                      _             _ 
- *  _ __ ___   ___   __| |    ___ ___| |  
- * | '_ ` _ \ / _ \ / _` |   / __/ __| |  
- * | | | | | | (_) | (_| |   \__ \__ \ | mod_ssl - Apache Interface to OpenSSL
- * |_| |_| |_|\___/ \__,_|___|___/___/_| http://www.modssl.org/
- *                      |_____|         
- *  ssl_expr_parse.y
- *  Expression LR(1) Parser
- */
-                             /* ``What you see is all you get.''
-                                                                     -- Brian Kernighan      */
-
-/*  _________________________________________________________________
-**
-**  Expression Parser
-**  _________________________________________________________________
-*/
-
-%pure-parser
-%defines
-%error-verbose
-%lex-param   { void *yyscanner }
-%parse-param { ssl_expr_info_type *context }
-
-%{
-#include "ssl_private.h"
-%}
-
-%union {
-    char     *cpVal;
-    ssl_expr *exVal;
-}
-
-%token  T_TRUE
-%token  T_FALSE
-
-%token  <cpVal> T_DIGIT
-%token  <cpVal> T_ID
-%token  <cpVal> T_STRING
-%token  <cpVal> T_REGEX
-%token  <cpVal> T_REGEX_I
-
-%token  T_FUNC_FILE
-
-%token  T_OP_EQ
-%token  T_OP_NE
-%token  T_OP_LT
-%token  T_OP_LE
-%token  T_OP_GT
-%token  T_OP_GE
-%token  T_OP_REG
-%token  T_OP_NRE
-%token  T_OP_IN
-%token  T_OP_PEEREXTLIST
-
-%token  T_OP_OR
-%token  T_OP_AND
-%token  T_OP_NOT
-
-%left   T_OP_OR
-%left   T_OP_AND
-%left   T_OP_NOT
-
-%type   <exVal>   expr
-%type   <exVal>   comparison
-%type   <exVal>   funccall
-%type   <exVal>   regex
-%type   <exVal>   words
-%type   <exVal>   wordlist
-%type   <exVal>   word
-
-%{
-#include "ssl_expr.h"
-#define yyscanner context->scanner
-
-int ssl_expr_yyerror(ssl_expr_info_type *context, char *err);
-int ssl_expr_yylex(YYSTYPE *lvalp, void *scanner);
-%}
-
-
-%%
-
-root      : expr                         { context->expr = $1; }
-          ;
-
-expr      : T_TRUE                       { $$ = ssl_expr_make(op_True,  NULL, NULL, context); }
-          | T_FALSE                      { $$ = ssl_expr_make(op_False, NULL, NULL, context); }
-          | T_OP_NOT expr                { $$ = ssl_expr_make(op_Not,   $2,   NULL, context); }
-          | expr T_OP_OR expr            { $$ = ssl_expr_make(op_Or,    $1,   $3,   context); }
-          | expr T_OP_AND expr           { $$ = ssl_expr_make(op_And,   $1,   $3,   context); }
-          | comparison                   { $$ = ssl_expr_make(op_Comp,  $1,   NULL, context); }
-          | '(' expr ')'                 { $$ = $2; }
-          ;
-
-comparison: word T_OP_EQ word            { $$ = ssl_expr_make(op_EQ,  $1, $3, context); }
-          | word T_OP_NE word            { $$ = ssl_expr_make(op_NE,  $1, $3, context); }
-          | word T_OP_LT word            { $$ = ssl_expr_make(op_LT,  $1, $3, context); }
-          | word T_OP_LE word            { $$ = ssl_expr_make(op_LE,  $1, $3, context); }
-          | word T_OP_GT word            { $$ = ssl_expr_make(op_GT,  $1, $3, context); }
-          | word T_OP_GE word            { $$ = ssl_expr_make(op_GE,  $1, $3, context); }
-          | word T_OP_IN wordlist        { $$ = ssl_expr_make(op_IN,  $1, $3, context); }
-          | word T_OP_REG regex          { $$ = ssl_expr_make(op_REG, $1, $3, context); }
-          | word T_OP_NRE regex          { $$ = ssl_expr_make(op_NRE, $1, $3, context); }
-          ;
-
-wordlist  : T_OP_PEEREXTLIST '(' word ')' { $$ = ssl_expr_make(op_PeerExtElement, $3, NULL, context); }
-          | '{' words '}'                { $$ = $2 ; }
-         ;
-
-words     : word                         { $$ = ssl_expr_make(op_ListElement, $1, NULL, context); }
-          | words ',' word               { $$ = ssl_expr_make(op_ListElement, $3, $1, context);   }
-          ;
-
-word      : T_DIGIT                      { $$ = ssl_expr_make(op_Digit,  $1, NULL, context); }
-          | T_STRING                     { $$ = ssl_expr_make(op_String, $1, NULL, context); }
-          | '%' '{' T_ID '}'             { $$ = ssl_expr_make(op_Var,    $3, NULL, context); }
-          | funccall                     { $$ = $1; }
-          ;
-
-regex     : T_REGEX { 
-                ap_regex_t *regex;
-                if ((regex = ap_pregcomp(context->pool, $1, 
-                                         AP_REG_EXTENDED|AP_REG_NOSUB)) == NULL) {
-                    context->error = "Failed to compile regular expression";
-                    YYERROR;
-                }
-                $$ = ssl_expr_make(op_Regex, regex, NULL, context);
-            }
-          | T_REGEX_I {
-                ap_regex_t *regex;
-                if ((regex = ap_pregcomp(context->pool, $1, 
-                                         AP_REG_EXTENDED|AP_REG_NOSUB|AP_REG_ICASE)) == NULL) {
-                    context->error = "Failed to compile regular expression";
-                    YYERROR;
-                }
-                $$ = ssl_expr_make(op_Regex, regex, NULL, context);
-            }
-          ;
-
-funccall  : T_FUNC_FILE '(' T_STRING ')' { 
-               ssl_expr *args = ssl_expr_make(op_ListElement, $3, NULL, context);
-               $$ = ssl_expr_make(op_Func, "file", args, context);
-            }
-          ;
-
-%%
-
-int yyerror(ssl_expr_info_type *context, char *s)
-{
-    context->error = s;
-    return 2;
-}
-
diff --git a/modules/ssl/ssl_expr_scan.l b/modules/ssl/ssl_expr_scan.l
deleted file mode 100644 (file)
index be57934..0000000
+++ /dev/null
@@ -1,230 +0,0 @@
-/* Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*                      _             _ 
- *  _ __ ___   ___   __| |    ___ ___| |  
- * | '_ ` _ \ / _ \ / _` |   / __/ __| |  
- * | | | | | | (_) | (_| |   \__ \__ \ | mod_ssl - Apache Interface to OpenSSL
- * |_| |_| |_|\___/ \__,_|___|___/___/_| http://www.modssl.org/
- *                      |_____|         
- *  ssl_expr_scan.l
- *  Expression Scanner
- */
-                             /* ``Killing for peace is 
-                                  like fucking for virginity.''
-                                             -- Unknown  */
-
-/*  _________________________________________________________________
-**
-**  Expression Scanner
-**  _________________________________________________________________
-*/
-
-%pointer
-%option batch
-%option never-interactive
-%option nodefault
-%option noyywrap
-%option reentrant
-%option bison-bridge
-%option warn
-%option noinput nounput
-%x str
-%x regex regex_flags
-
-%{
-#include "ssl_private.h"
-
-#include "ssl_expr_parse.h"
-#include "ssl_expr.h"
-
-#undef  YY_INPUT
-#define YY_INPUT(buf,result,max_size)                       \
-{                                                           \
-    if ((result = MIN(max_size, yyextra->inputbuf           \
-                              + yyextra->inputlen           \
-                              - yyextra->inputptr)) <= 0)   \
-    {                                                       \
-        result = YY_NULL;                                   \
-    }                                                       \
-    else {                                                  \
-        memcpy(buf, yyextra->inputptr, result);             \
-        yyextra->inputptr += result;                        \
-    }                                                       \
-}
-
-#define MAX_STR_LEN 2048
-#define YY_EXTRA_TYPE ssl_expr_info_type*
-%}
-
-
-%%
-  
-  char  caStr[MAX_STR_LEN];
-  char *cpStr = NULL;
-  char  caRegex[MAX_STR_LEN];
-  char *cpRegex = NULL;
-  char  cRegexDel = NUL;
-
- /*
-  * Whitespaces
-  */
-[ \t\n]+ { 
-    /* NOP */
-}
-
- /*
-  * C-style strings ("...")
-  */
-\" {
-    cpStr = caStr;
-    BEGIN(str);
-}
-<str>\" {
-    BEGIN(INITIAL);
-    *cpStr = NUL;
-    yylval->cpVal = apr_pstrdup(yyextra->pool, caStr);
-    return T_STRING;
-}
-<str>\n {
-    ssl_expr_yyerror(yyextra, "Unterminated string");
-}
-<str>\\[0-7]{1,3} {
-    int result;
-
-    (void)sscanf(yytext+1, "%o", &result);
-    if (result > 0xff)
-        ssl_expr_yyerror(yyextra, "Escape sequence out of bound");
-    else
-        *cpStr++ = result;
-}
-<str>\\[0-9]+ {
-    ssl_expr_yyerror(yyextra, "Bad escape sequence");
-}
-<str>\\n { *cpStr++ = '\n'; }
-<str>\\r { *cpStr++ = '\r'; }
-<str>\\t { *cpStr++ = '\t'; }
-<str>\\b { *cpStr++ = '\b'; }
-<str>\\f { *cpStr++ = '\f'; }
-<str>\\(.|\n) {
-    *cpStr++ = yytext[1];
-}
-<str>[^\\\n\"]+ {
-    char *cp = yytext;
-    while (*cp != NUL)
-        *cpStr++ = *cp++;
-}
-<str>. {
-    *cpStr++ = yytext[1];
-}
-
- /*
-  * Regular Expression
-  */
-"m". {
-    cRegexDel = yytext[1];
-    cpRegex = caRegex;
-    BEGIN(regex);
-}
-<regex>.|\n {
-    if (yytext[0] == cRegexDel) {
-        *cpRegex = NUL;
-        BEGIN(regex_flags);
-    }
-    else {
-        *cpRegex++ = yytext[0];
-    }
-}
-<regex_flags>i {
-    yylval->cpVal = apr_pstrdup(yyextra->pool, caRegex);
-    BEGIN(INITIAL);
-    return T_REGEX_I;
-}
-<regex_flags>.|\n {
-    yylval->cpVal = apr_pstrdup(yyextra->pool, caRegex);
-    yyless(0);
-    BEGIN(INITIAL);
-    return T_REGEX;
-}
-<regex_flags><<EOF>> {
-    yylval->cpVal = apr_pstrdup(yyextra->pool, caRegex);
-    BEGIN(INITIAL);
-    return T_REGEX;
-}
-
- /*
-  * Operators
-  */
-"eq"  { return T_OP_EQ; }
-"=="  { return T_OP_EQ; }
-"ne"  { return T_OP_NE; }
-"!="  { return T_OP_NE; }
-"lt"  { return T_OP_LT; }
-"<"   { return T_OP_LT; }
-"le"  { return T_OP_LE; }
-"<="  { return T_OP_LE; }
-"gt"  { return T_OP_GT; }
-">"   { return T_OP_GT; }
-"ge"  { return T_OP_GE; }
-">="  { return T_OP_GE; }
-"=~"  { return T_OP_REG; }
-"!~"  { return T_OP_NRE; }
-"and" { return T_OP_AND; }
-"&&"  { return T_OP_AND; }
-"or"  { return T_OP_OR; }
-"||"  { return T_OP_OR; }
-"not" { return T_OP_NOT; }
-"!"   { return T_OP_NOT; }
-"in"  { return T_OP_IN; }
-[Pp][Ee][Ee][Rr][Ee][Xx][Tt][Ll][Ii][Ss][Tt] { return T_OP_PEEREXTLIST; }
-
- /*
-  * Functions
-  */
-"file" { return T_FUNC_FILE; }
-
- /*
-  * Specials
-  */
-"true"  { return T_TRUE; }
-"false" { return T_FALSE; }
-
- /*
-  * Digits
-  */
-[0-9]+ {
-    yylval->cpVal = apr_pstrdup(yyextra->pool, yytext);
-    return T_DIGIT;
-}
-
- /*
-  * Identifiers
-  */
-[a-zA-Z][a-zA-Z0-9_:-]* {
-    yylval->cpVal = apr_pstrdup(yyextra->pool, yytext);
-    return T_ID;
-}
-
- /*
-  * Anything else is returned as is...
-  */
-.|\n { 
-    return yytext[0];
-}
-
-%%
-
-
index 4e8714c732f53c15c10ba4e50d41db3e35aae67d..ae344a141d150c0522aa0f13bb07959fb948cad2 100644 (file)
 
 #define MOD_SSL_VERSION AP_SERVER_BASEREVISION
 
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#ifndef TRUE
+#define TRUE !FALSE
+#endif
+
+#ifndef YY_NULL
+#define YY_NULL 0
+#endif
+
+#ifndef MIN
+#define MIN(a,b) (((a)<(b))?(a):(b))
+#endif
+
+#ifndef BOOL
+#define BOOL unsigned int
+#endif
+
+#ifndef NULL
+#define NULL (void *)0
+#endif
+
+#ifndef NUL
+#define NUL '\0'
+#endif
+
+
 /* mod_ssl headers */
 #include "ssl_toolkit_compat.h"
-#include "ssl_expr.h"
+#include "ap_expr.h"
 #include "ssl_util_ssl.h"
 
 /* The #ifdef macros are only defined AFTER including the above
@@ -272,8 +301,8 @@ typedef enum {
  * Define the SSL requirement structure
  */
 typedef struct {
-    char     *cpExpr;
-    ssl_expr *mpExpr;
+    char           *cpExpr;
+    ap_expr_info_t *mpExpr;
 } ssl_require_t;
 
 /**
@@ -617,7 +646,6 @@ void         ssl_hook_ConfigTest(apr_pool_t *pconf, server_rec *s);
 /** Apache authz provisders */
 extern const authz_provider ssl_authz_provider_require_ssl;
 extern const authz_provider ssl_authz_provider_verify_client;
-extern const authz_provider ssl_authz_provider_sslrequire;
 
 /**  OpenSSL callbacks */
 RSA         *ssl_callback_TmpRSA(SSL *, int, int);
index 10b41446a533d833cfb56bedf5e0fde2bba98006..98d8ee9be3e77f3969111d011088abe4b719671a 100644 (file)
@@ -12,9 +12,10 @@ LTLIBRARY_SOURCES = \
        util_script.c util_md5.c util_cfgtree.c util_ebcdic.c util_time.c \
        connection.c listen.c util_mutex.c mpm_common.c mpm_unix.c \
        util_charset.c util_cookies.c util_debug.c util_xml.c \
-       util_expr.c util_filter.c util_pcre.c util_regex.c exports.c \
+       util_filter.c util_pcre.c util_regex.c exports.c \
        scoreboard.c error_bucket.c protocol.c core.c request.c provider.c \
-       eoc_bucket.c eor_bucket.c core_filters.c
+       eoc_bucket.c eor_bucket.c core_filters.c \
+       util_expr_parse.c util_expr_scan.c util_expr_eval.c
 
 TARGETS = delete-exports $(LTLIBRARY_NAME) $(CORE_IMPLIB_FILE) export_vars.h httpd.exp
 
@@ -83,3 +84,19 @@ httpd.exp: exports.c export_vars.h
        @echo "* Please do not edit by hand." >> $@
        $(CPP) $(ALL_CPPFLAGS) $(ALL_INCLUDES) exports.c | grep "ap_hack_" | grep -v apr_ | sed -e 's/^.*[)]\(.*\);$$/\1/' >> $@
        $(CPP) $(ALL_CPPFLAGS) $(ALL_INCLUDES) export_vars.h | grep -v apr_ | sed -e 's/^\#[^!]*//' | sed -e '/^$$/d' >> $@
+
+
+#   developer stuff
+#   (we really don't expect end users to use these targets!)
+#
+util_expr_scan.c util_expr_parse.c util_expr_parse.h: util_expr_scan.l util_expr_parse.y
+       bison -pap_expr_yy --defines=$(builddir)/util_expr_parse.h \
+           -o $(builddir)/util_expr_parse.c $(srcdir)/util_expr_parse.y
+       flex -Pap_expr_yy -o $(builddir)/util_expr_scan.c $(srcdir)/util_expr_scan.l
+       set -e ; \
+       for f in util_expr_scan.c util_expr_parse.c util_expr_parse.h ; do \
+               sed -e "s|\"$(builddir)/|\"|g" < $(builddir)/$$f > \
+                       $(builddir)/$$f.$$$$ && \
+               mv $(builddir)/$$f.$$$$ $(builddir)/$$f ; \
+       done
+
index e01b4b40ecc11058dc27580cf07dcaf19eb74691..d41ff648f5b71bc91d832c6aac1609c6e93b28f0 100644 (file)
@@ -1986,7 +1986,7 @@ static const char *ifsection(cmd_parms *cmd, void *mconfig, const char *arg)
     const char *err = ap_check_cmd_context(cmd,
                                            NOT_IN_LOCATION | NOT_IN_LIMIT);
     const char *condition;
-    int expr_err = 0;
+    const char *expr_err;
 
     if (err != NULL) {
         return err;
@@ -2012,9 +2012,9 @@ static const char *ifsection(cmd_parms *cmd, void *mconfig, const char *arg)
     conf = ap_set_config_vectors(cmd->server, new_file_conf, cmd->path,
                                  &core_module, cmd->pool);
 
-    conf->condition = ap_expr_parse(cmd->pool, condition, &expr_err);
+    conf->condition = ap_expr_parse_cmd(cmd, condition, &expr_err, NULL);
     if (expr_err) {
-        return "Cannot parse condition clause";
+        return apr_psprintf(cmd->pool, "Cannot parse condition clause: %s", expr_err);
     }
 
     errmsg = ap_walk_config(cmd->directive->first_child, cmd, new_file_conf);
@@ -4133,6 +4133,7 @@ static void register_hooks(apr_pool_t *p)
 {
     errorlog_hash = apr_hash_make(p);
     ap_register_log_hooks(p);
+    ap_expr_init(p);
 
     /* create_connection and pre_connection should always be hooked
      * APR_HOOK_REALLY_LAST by core to give other modules the opportunity
index 19433716935795553d85c8581216e3f854c338c1..3ea53d4bb428343f2d236b3de1b509ffd0d828dc 100644 (file)
@@ -39,7 +39,6 @@
 #include "apr_uri.h"
 #include "util_ebcdic.h"
 #include "ap_mpm.h"
-#include "ap_expr.h"
 
 #if APR_HAVE_UNISTD_H
 #include <unistd.h>
@@ -472,9 +471,6 @@ int main(int argc, const char * const argv[])
         destroy_and_exit_process(process, 1);
     }
 #endif
-    if (ap_expr_init(ap_pglobal) != APR_SUCCESS) {
-        destroy_and_exit_process(process, 1);
-    }
 
     apr_pool_create(&pcommands, ap_pglobal);
     apr_pool_tag(pcommands, "pcommands");
index 2779c8de4711b6138ce57590be379fb3bb2801ab..f516617b8a9dce3dda73be24eb4913ce74977fbb 100644 (file)
@@ -1529,13 +1529,13 @@ AP_DECLARE(int) ap_file_walk(request_rec *r)
          * really try them with the most general first.
          */
         for (sec_idx = 0; sec_idx < num_sec; ++sec_idx) {
-            int err = 0;
+            const char *err = NULL;
             core_dir_config *entry_core;
             entry_core = ap_get_module_config(sec_ent[sec_idx], &core_module);
 
             if (entry_core->condition) {
-                if (!ap_expr_eval(r, entry_core->condition, &err, NULL,
-                                  ap_expr_string, NULL)) {
+                /* XXX: error handling */
+                if (!ap_expr_exec(r, entry_core->condition, &err)) {
                     continue;
                 }
             }
diff --git a/server/util_expr.c b/server/util_expr.c
deleted file mode 100644 (file)
index d6f8194..0000000
+++ /dev/null
@@ -1,1282 +0,0 @@
-/* Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "apr.h"
-#include "apr_strings.h"
-#include "apr_lib.h"
-
-#define APR_WANT_STRFUNC
-#define APR_WANT_MEMFUNC
-#include "apr_want.h"
-
-#include "httpd.h"
-#include "http_log.h"
-#include "http_core.h"
-
-#include "ap_expr.h"
-
-APLOG_USE_MODULE(core);
-
-#if 1
-/*
- * +-------------------------------------------------------+
- * |                                                       |
- * |                  Debugging Utilities
- * |                                                       |
- * +-------------------------------------------------------+
- */
-
-#ifdef DEBUG_INCLUDE
-
-#define TYPE_TOKEN(token, ttype) do { \
-    (token)->type = ttype;            \
-    (token)->s = #ttype;              \
-} while(0)
-
-#define CREATE_NODE(pool,name) do {                          \
-    (name) = apr_pcalloc(pool, sizeof(*(name)));             \
-} while(0)
-
-static void debug_printf(request_rec *r, const char *fmt, ...)
-{
-    va_list ap;
-    char *debug__str;
-
-    va_start(ap, fmt);
-    debug__str = apr_pvsprintf(r->pool, fmt, ap);
-    va_end(ap);
-/*
-    APR_BRIGADE_INSERT_TAIL(ctx->intern->debug.bb, apr_bucket_pool_create(
-                            debug__str, strlen(debug__str), ctx->pool,
-                            ctx->intern->debug.f->c->bucket_alloc));
-                            */
-}
-
-#define DUMP__CHILD(ctx, is, node, child) if (1) {                           \
-    ap_parse_node_t *d__c = node->child;                                     \
-    if (d__c) {                                                              \
-        if (!d__c->dump_done) {                                              \
-            if (d__c->parent != node) {                                      \
-                debug_printf(ctx, "!!! Parse tree is not consistent !!!\n"); \
-                if (!d__c->parent) {                                         \
-                    debug_printf(ctx, "Parent of " #child " child node is "  \
-                                 "NULL.\n");                                 \
-                }                                                            \
-                else {                                                       \
-                    debug_printf(ctx, "Parent of " #child " child node "     \
-                                 "points to another node (of type %s)!\n",   \
-                                 d__c->parent->token.s);                     \
-                }                                                            \
-                return;                                                      \
-            }                                                                \
-            node = d__c;                                                     \
-            continue;                                                        \
-        }                                                                    \
-    }                                                                        \
-    else {                                                                   \
-        debug_printf(ctx, "%s(missing)\n", is);                              \
-    }                                                                        \
-}
-
-static void debug_dump_tree(include_ctx_t *ctx, ap_parse_node_t *root)
-{
-    ap_parse_node_t *current;
-    char *is;
-
-    if (!root) {
-        debug_printf(ctx, "     -- Parse Tree empty --\n\n");
-        return;
-    }
-
-    debug_printf(ctx, "     ----- Parse Tree -----\n");
-    current = root;
-    is = "     ";
-
-    while (current) {
-        switch (current->token.type) {
-        case TOKEN_STRING:
-        case TOKEN_RE:
-            debug_printf(ctx, "%s%s (%s)\n", is, current->token.s,
-                         current->token.value);
-            current->dump_done = 1;
-            current = current->parent;
-            continue;
-
-        case TOKEN_NOT:
-        case TOKEN_GROUP:
-        case TOKEN_RBRACE:
-        case TOKEN_LBRACE:
-            if (!current->dump_done) {
-                debug_printf(ctx, "%s%s\n", is, current->token.s);
-                is = apr_pstrcat(ctx->dpool, is, "    ", NULL);
-                current->dump_done = 1;
-            }
-
-            DUMP__CHILD(ctx, is, current, right)
-
-            if (!current->right || current->right->dump_done) {
-                is = apr_pstrmemdup(ctx->dpool, is, strlen(is) - 4);
-                if (current->right) current->right->dump_done = 0;
-                current = current->parent;
-            }
-            continue;
-
-        default:
-            if (!current->dump_done) {
-                debug_printf(ctx, "%s%s\n", is, current->token.s);
-                is = apr_pstrcat(ctx->dpool, is, "    ", NULL);
-                current->dump_done = 1;
-            }
-
-            DUMP__CHILD(ctx, is, current, left)
-            DUMP__CHILD(ctx, is, current, right)
-
-            if ((!current->left || current->left->dump_done) &&
-                (!current->right || current->right->dump_done)) {
-
-                is = apr_pstrmemdup(ctx->dpool, is, strlen(is) - 4);
-                if (current->left) current->left->dump_done = 0;
-                if (current->right) current->right->dump_done = 0;
-                current = current->parent;
-            }
-            continue;
-        }
-    }
-
-    /* it is possible to call this function within the parser loop, to see
-     * how the tree is built. That way, we must cleanup after us to dump
-     * always the whole tree
-     */
-    root->dump_done = 0;
-    if (root->left) root->left->dump_done = 0;
-    if (root->right) root->right->dump_done = 0;
-
-    debug_printf(ctx, "     --- End Parse Tree ---\n\n");
-
-    return;
-}
-
-#define DEBUG_INIT(ctx, filter, brigade) do { \
-    (ctx)->intern->debug.f = filter;          \
-    (ctx)->intern->debug.bb = brigade;        \
-} while(0)
-
-#define DEBUG_PRINTF(arg) debug_printf arg
-
-#define DEBUG_DUMP_TOKEN(ctx, token) do {                                     \
-    token_t *d__t = (token);                                                  \
-                                                                              \
-    if (d__t->type == TOKEN_STRING || d__t->type == TOKEN_RE) {               \
-        DEBUG_PRINTF(((ctx), "     Found: %s (%s)\n", d__t->s, d__t->value)); \
-    }                                                                         \
-    else {                                                                    \
-        DEBUG_PRINTF((ctx, "     Found: %s\n", d__t->s));                     \
-    }                                                                         \
-} while(0)
-
-#define DEBUG_DUMP_EVAL(r, node) do {                                       \
-    char c = '"';                                                             \
-    switch ((node)->token.type) {                                             \
-    case TOKEN_STRING:                                                        \
-        debug_printf((r), "     Evaluate: %s (%s) -> %c\n", (node)->token.s,\
-                     (node)->token.value, ((node)->value) ? '1':'0');         \
-        break;                                                                \
-    case TOKEN_AND:                                                           \
-    case TOKEN_OR:                                                            \
-        debug_printf((r), "     Evaluate: %s (Left: %s; Right: %s) -> %c\n",\
-                     (node)->token.s,                                         \
-                     (((node)->left->done) ? ((node)->left->value ?"1":"0")   \
-                                          : "short circuited"),               \
-                     (((node)->right->done) ? ((node)->right->value?"1":"0")  \
-                                          : "short circuited"),               \
-                     (node)->value ? '1' : '0');                              \
-        break;                                                                \
-    case TOKEN_EQ:                                                            \
-    case TOKEN_NE:                                                            \
-    case TOKEN_GT:                                                            \
-    case TOKEN_GE:                                                            \
-    case TOKEN_LT:                                                            \
-    case TOKEN_LE:                                                            \
-        if ((node)->right->token.type == TOKEN_RE) c = '/';                   \
-        debug_printf((r), "     Compare:  %s (\"%s\" with %c%s%c) -> %c\n", \
-                     (node)->token.s,                                         \
-                     (node)->left->token.value,                               \
-                     c, (node)->right->token.value, c,                        \
-                     (node)->value ? '1' : '0');                              \
-        break;                                                                \
-    default:                                                                  \
-        debug_printf((r), "     Evaluate: %s -> %c\n", (node)->token.s,     \
-                     (node)->value ? '1' : '0');                              \
-        break;                                                                \
-    }                                                                         \
-} while(0)
-
-#define DEBUG_DUMP_UNMATCHED(r, unmatched) do {                        \
-    if (unmatched) {                                                     \
-        DEBUG_PRINTF(((r), "     Unmatched %c\n", (char)(unmatched))); \
-    }                                                                    \
-} while(0)
-
-#define DEBUG_DUMP_COND(ctx, text)                                 \
-    DEBUG_PRINTF(((ctx), "**** %s cond status=\"%c\"\n", (text),   \
-                  ((ctx)->flags & SSI_FLAG_COND_TRUE) ? '1' : '0'))
-
-#define DEBUG_DUMP_TREE(ctx, root) debug_dump_tree(ctx, root)
-
-#else /* DEBUG_INCLUDE */
-
-#define TYPE_TOKEN(token, ttype) (token)->type = ttype
-
-#define CREATE_NODE(pool,name) do {               \
-    (name) = apr_pcalloc(pool, sizeof(*(name)));  \
-} while(0)
-
-#define DEBUG_INIT(ctx, f, bb)
-#define DEBUG_PRINTF(arg)
-#define DEBUG_DUMP_TOKEN(ctx, token)
-#define DEBUG_DUMP_EVAL(ctx, node)
-#define DEBUG_DUMP_UNMATCHED(ctx, unmatched)
-#define DEBUG_DUMP_COND(ctx, text)
-#define DEBUG_DUMP_TREE(ctx, root)
-
-#endif /* !DEBUG_INCLUDE */
-
-#endif /* 0 */
-
-
-/*
- * +-------------------------------------------------------+
- * |                                                       |
- * |              Conditional Expression Parser
- * |                                                       |
- * +-------------------------------------------------------+
- */
-static APR_INLINE int re_check(request_rec *r, const char *string,
-                               const char *rexp, backref_t **reptr)
-{
-    ap_regex_t *compiled;
-    backref_t *re = reptr ? *reptr : NULL;
-
-    compiled = ap_pregcomp(r->pool, rexp, AP_REG_EXTENDED);
-    if (!compiled) {
-        ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "unable to "
-                      "compile pattern \"%s\"", rexp);
-        return -1;
-    }
-
-    if (!re) {
-        re = apr_palloc(r->pool, sizeof(*re));
-        if (reptr) {
-            *reptr = re;
-        }
-    }
-
-    re->source = apr_pstrdup(r->pool, string);
-    re->rexp = apr_pstrdup(r->pool, rexp);
-    re->nsub = compiled->re_nsub;
-    re->have_match = !ap_regexec(compiled, string, AP_MAX_REG_MATCH,
-                                 re->match, 0);
-
-    ap_pregfree(r->pool, compiled);
-    return re->have_match;
-}
-
-static int get_ptoken(apr_pool_t *pool, const char **parse, token_t *token,
-                      token_t *previous)
-{
-    const char *p;
-    apr_size_t shift;
-    int unmatched;
-
-    token->value = NULL;
-
-    if (!*parse) {
-        return 0;
-    }
-
-    /* Skip leading white space */
-    while (apr_isspace(**parse)) {
-        ++*parse;
-    }
-
-    if (!**parse) {
-        *parse = NULL;
-        return 0;
-    }
-
-    TYPE_TOKEN(token, TOKEN_STRING); /* the default type */
-    p = *parse;
-    unmatched = 0;
-
-    switch (*(*parse)++) {
-    case '(':
-        TYPE_TOKEN(token, TOKEN_LBRACE);
-        return 0;
-    case ')':
-        TYPE_TOKEN(token, TOKEN_RBRACE);
-        return 0;
-    case '=':
-        if (**parse == '=') ++*parse;
-        TYPE_TOKEN(token, TOKEN_EQ);
-        return 0;
-    case '!':
-        if (**parse == '=') {
-            TYPE_TOKEN(token, TOKEN_NE);
-            ++*parse;
-            return 0;
-        }
-        TYPE_TOKEN(token, TOKEN_NOT);
-        return 0;
-    case '\'':
-        unmatched = '\'';
-        break;
-    case '/':
-        /* if last token was ACCESS, this token is STRING */
-        if (previous != NULL && TOKEN_ACCESS == previous->type) {
-            break;
-        }
-        TYPE_TOKEN(token, TOKEN_RE);
-        unmatched = '/';
-        break;
-    case '|':
-        if (**parse == '|') {
-            TYPE_TOKEN(token, TOKEN_OR);
-            ++*parse;
-            return 0;
-        }
-        break;
-    case '&':
-        if (**parse == '&') {
-            TYPE_TOKEN(token, TOKEN_AND);
-            ++*parse;
-            return 0;
-        }
-        break;
-    case '>':
-        if (**parse == '=') {
-            TYPE_TOKEN(token, TOKEN_GE);
-            ++*parse;
-            return 0;
-        }
-        TYPE_TOKEN(token, TOKEN_GT);
-        return 0;
-    case '<':
-        if (**parse == '=') {
-            TYPE_TOKEN(token, TOKEN_LE);
-            ++*parse;
-            return 0;
-        }
-        TYPE_TOKEN(token, TOKEN_LT);
-        return 0;
-    case '-':
-        if (apr_isalnum(**parse) && apr_isspace((*parse)[1])) {
-            TYPE_TOKEN(token, TOKEN_ACCESS);
-            token->value = *parse;
-            ++*parse;
-            return 0;
-        }
-        break;
-    case 'I':
-        if (**parse == 'N') {
-            TYPE_TOKEN(token, TOKEN_IN);
-            ++*parse;
-            return 0;
-        }
-        break;
-    }
-
-    /* It's a string or regex token
-     * Now search for the next token, which finishes this string
-     */
-    shift = 0;
-    p = *parse = token->value = unmatched ? *parse : p;
-
-    for (; **parse; p = ++*parse) {
-        if (**parse == '\\') {
-            if (!*(++*parse)) {
-                p = *parse;
-                break;
-            }
-
-            ++shift;
-        }
-        else {
-            if (unmatched) {
-                if (**parse == unmatched) {
-                    unmatched = 0;
-                    ++*parse;
-                    break;
-                }
-            }
-            else if (apr_isspace(**parse)) {
-                break;
-            }
-            else {
-                int found = 0;
-
-                switch (**parse) {
-                case '(':
-                case ')':
-                case '=':
-                case '!':
-                case '<':
-                case '>':
-                    ++found;
-                    break;
-
-                case '|':
-                case '&':
-                    if ((*parse)[1] == **parse) {
-                        ++found;
-                    }
-                    break;
-                }
-
-                if (found) {
-                    break;
-                }
-            }
-        }
-    }
-
-    if (unmatched) {
-        token->value = apr_pstrdup(pool, "");
-    }
-    else {
-        apr_size_t len = p - token->value - shift;
-        char *c = apr_palloc(pool, len + 1);
-
-        p = token->value;
-        token->value = c;
-
-        while (shift--) {
-            const char *e = ap_strchr_c(p, '\\');
-
-            memcpy(c, p, e-p);
-            c   += e-p;
-            *c++ = *++e;
-            len -= e-p;
-            p    = e+1;
-        }
-
-        if (len) {
-            memcpy(c, p, len);
-        }
-        c[len] = '\0';
-    }
-
-    return unmatched;
-}
-
-/* This is what we export.  We can split it in two. */
-AP_DECLARE(ap_parse_node_t*) ap_expr_parse(apr_pool_t* pool, const char *expr,
-                                           int *was_error)
-{
-    ap_parse_node_t *new, *root = NULL, *current = NULL;
-    const char *error = "Invalid expression \"%s\" in file %s";
-    const char *parse = expr;
-    int was_unmatched = 0;
-    unsigned regex = 0;
-
-    *was_error = 0;
-
-    if (!parse) {
-        return 0;
-    }
-
-    /* Create Parse Tree */
-    while (1) {
-        /* uncomment this to see how the tree a built:
-         *
-         * DEBUG_DUMP_TREE(ctx, root);
-         */
-        CREATE_NODE(pool, new);
-
-        was_unmatched = get_ptoken(pool, &parse, &new->token,
-                     (current != NULL ? &current->token : NULL));
-        if (!parse) {
-            break;
-        }
-
-        DEBUG_DUMP_UNMATCHED(ctx, was_unmatched);
-        DEBUG_DUMP_TOKEN(ctx, &new->token);
-
-        if (!current) {
-            switch (new->token.type) {
-            case TOKEN_STRING:
-            case TOKEN_NOT:
-            case TOKEN_ACCESS:
-            case TOKEN_LBRACE:
-                root = current = new;
-                continue;
-
-            default:
-                *was_error = 1;
-                return 0;
-            }
-        }
-
-        switch (new->token.type) {
-        case TOKEN_STRING:
-            switch (current->token.type) {
-            case TOKEN_STRING:
-                current->token.value =
-                    apr_pstrcat(pool, current->token.value,
-                                *current->token.value ? " " : "",
-                                new->token.value, NULL);
-                continue;
-
-            case TOKEN_RE:
-            case TOKEN_RBRACE:
-            case TOKEN_GROUP:
-                break;
-
-            default:
-                new->parent = current;
-                current = current->right = new;
-                continue;
-            }
-            break;
-
-        case TOKEN_RE:
-            switch (current->token.type) {
-            case TOKEN_EQ:
-            case TOKEN_NE:
-                new->parent = current;
-                current = current->right = new;
-                ++regex;
-                continue;
-
-            default:
-                break;
-            }
-            break;
-
-        case TOKEN_AND:
-        case TOKEN_OR:
-            switch (current->token.type) {
-            case TOKEN_STRING:
-            case TOKEN_RE:
-            case TOKEN_GROUP:
-                current = current->parent;
-
-                while (current) {
-                    switch (current->token.type) {
-                    case TOKEN_AND:
-                    case TOKEN_OR:
-                    case TOKEN_LBRACE:
-                        break;
-
-                    default:
-                        current = current->parent;
-                        continue;
-                    }
-                    break;
-                }
-
-                if (!current) {
-                    new->left = root;
-                    root->parent = new;
-                    current = root = new;
-                    continue;
-                }
-
-                new->left = current->right;
-                new->left->parent = new;
-                new->parent = current;
-                current = current->right = new;
-                continue;
-
-            default:
-                break;
-            }
-            break;
-
-        case TOKEN_EQ:
-        case TOKEN_NE:
-        case TOKEN_GE:
-        case TOKEN_GT:
-        case TOKEN_LE:
-        case TOKEN_LT:
-        case TOKEN_IN:
-            if (current->token.type == TOKEN_STRING) {
-                current = current->parent;
-
-                if (!current) {
-                    new->left = root;
-                    root->parent = new;
-                    current = root = new;
-                    continue;
-                }
-
-                switch (current->token.type) {
-                case TOKEN_LBRACE:
-                case TOKEN_AND:
-                case TOKEN_OR:
-                    new->left = current->right;
-                    new->left->parent = new;
-                    new->parent = current;
-                    current = current->right = new;
-                    continue;
-
-                default:
-                    break;
-                }
-            }
-            break;
-
-        case TOKEN_RBRACE:
-            while (current && current->token.type != TOKEN_LBRACE) {
-                current = current->parent;
-            }
-
-            if (current) {
-                TYPE_TOKEN(&current->token, TOKEN_GROUP);
-                continue;
-            }
-
-            error = "Unmatched ')' in \"%s\" in file %s";
-            break;
-
-        case TOKEN_NOT:
-        case TOKEN_ACCESS:
-        case TOKEN_LBRACE:
-            switch (current->token.type) {
-            case TOKEN_STRING:
-            case TOKEN_RE:
-            case TOKEN_RBRACE:
-            case TOKEN_GROUP:
-                break;
-
-            default:
-                current->right = new;
-                new->parent = current;
-                current = new;
-                continue;
-            }
-            break;
-
-        default:
-            break;
-        }
-
-        *was_error = 1;
-        return 0;
-    }
-
-    DEBUG_DUMP_TREE(ctx, root);
-    return root;
-}
-
-static ap_parse_node_t *ap_expr_clone_tree(apr_pool_t *pool,
-                                           const ap_parse_node_t *pnode,
-                                           ap_parse_node_t *parent)
-{
-    ap_parse_node_t *ret;
-    ret = apr_pmemdup(pool, pnode, sizeof(ap_parse_node_t));
-    if (pnode->left) {
-        ret->left = ap_expr_clone_tree(pool, pnode->left, ret);
-    }
-    if (pnode->right) {
-        ret->right = ap_expr_clone_tree(pool, pnode->right, ret);
-    }
-    ret->parent = parent;
-    return ret;
-}
-
-#define PARSE_STRING(r,s) (string_func ? string_func((r),(s)) : (s))
-static int expr_eval(request_rec *r, ap_parse_node_t *root,
-                     int *was_error, backref_t **reptr,
-                     string_func_t string_func, opt_func_t eval_func)
-{
-    ap_parse_node_t *current = root;
-    const char *error = NULL;
-    unsigned int regex = 0;
-    const char *val;
-    const char *lval;
-    const char *rval;
-
-    /* Evaluate Parse Tree */
-    while (current) {
-        switch (current->token.type) {
-        case TOKEN_STRING:
-            val = PARSE_STRING(r, current->token.value);
-            current->value = !!*val;
-            break;
-
-        case TOKEN_AND:
-        case TOKEN_OR:
-            if (!current->left || !current->right) {
-                ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
-                              "Invalid expression in file %s", r->filename);
-                *was_error = 1;
-                return 0;
-            }
-
-            if (!current->left->done) {
-                switch (current->left->token.type) {
-                case TOKEN_STRING:
-                    lval = PARSE_STRING(r, current->left->token.value);
-                    current->left->value = !!*lval;
-                    DEBUG_DUMP_EVAL(ctx, current->left);
-                    current->left->done = 1;
-                    break;
-
-                default:
-                    current = current->left;
-                    continue;
-                }
-            }
-
-            /* short circuit evaluation */
-            if (!current->right->done && !regex &&
-                ((current->token.type == TOKEN_AND && !current->left->value) ||
-                (current->token.type == TOKEN_OR && current->left->value))) {
-                current->value = current->left->value;
-            }
-            else {
-                if (!current->right->done) {
-                    switch (current->right->token.type) {
-                    case TOKEN_STRING:
-                        rval = PARSE_STRING(r,current->right->token.value);
-                        current->right->value = !!*rval;
-                        DEBUG_DUMP_EVAL(r, current->right);
-                        current->right->done = 1;
-                        break;
-
-                    default:
-                        current = current->right;
-                        continue;
-                    }
-                }
-
-                if (current->token.type == TOKEN_AND) {
-                    current->value = current->left->value &&
-                                     current->right->value;
-                }
-                else {
-                    current->value = current->left->value ||
-                                     current->right->value;
-                }
-            }
-            break;
-
-        case TOKEN_EQ:
-        case TOKEN_NE:
-            if (!current->left || !current->right ||
-                current->left->token.type != TOKEN_STRING ||
-                (current->right->token.type != TOKEN_STRING &&
-                 current->right->token.type != TOKEN_RE)) {
-                ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
-                            "Invalid expression in file %s", r->filename);
-                *was_error = 1;
-                return 0;
-            }
-            lval = PARSE_STRING(r, current->left->token.value);
-            rval = PARSE_STRING(r, current->right->token.value);
-
-            if (current->right->token.type == TOKEN_RE) {
-                current->value = re_check(r, lval, rval, reptr);
-                --regex;
-            }
-            else {
-                current->value = !strcmp(lval, rval);
-            }
-
-            if (current->token.type == TOKEN_NE) {
-                current->value = !current->value;
-            }
-            break;
-
-        case TOKEN_GE:
-        case TOKEN_GT:
-        case TOKEN_LE:
-        case TOKEN_LT:
-            if (!current->left || !current->right ||
-                current->left->token.type != TOKEN_STRING ||
-                current->right->token.type != TOKEN_STRING) {
-                ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
-                              "Invalid expression in file %s", r->filename);
-                *was_error = 1;
-                return 0;
-            }
-
-            lval = PARSE_STRING(r, current->left->token.value);
-            rval = PARSE_STRING(r, current->right->token.value);
-
-            current->value = strcmp(lval, rval);
-
-            switch (current->token.type) {
-            case TOKEN_GE: current->value = current->value >= 0; break;
-            case TOKEN_GT: current->value = current->value >  0; break;
-            case TOKEN_LE: current->value = current->value <= 0; break;
-            case TOKEN_LT: current->value = current->value <  0; break;
-            default: current->value = 0; break; /* should not happen */
-            }
-            break;
-        case TOKEN_IN:
-            if (!current->left || !current->right ||
-                current->left->token.type != TOKEN_STRING ||
-                current->right->token.type != TOKEN_STRING) {
-                ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
-                              "Invalid expression in file %s", r->filename);
-                *was_error = 1;
-                return 0;
-            }
-
-            lval = PARSE_STRING(r, current->left->token.value);
-            rval = PARSE_STRING(r, current->right->token.value);
-            val = ap_strstr_c(rval, lval);
-            /* should be included as a complete word, not a subword
-             * as in regexp /\bLVAL\b/
-             */
-            current->value = (val != NULL
-                              && (val == rval || !isalnum(val[-1]))
-                              && !isalnum(val[strlen(val)]))
-                ? 1 : 0;
-            break;
-
-        case TOKEN_NOT:
-        case TOKEN_GROUP:
-            if (current->right) {
-                if (!current->right->done) {
-                    current = current->right;
-                    continue;
-                }
-                current->value = current->right->value;
-            }
-            else {
-                current->value = 1;
-            }
-
-            if (current->token.type == TOKEN_NOT) {
-                current->value = !current->value;
-            }
-            break;
-        case TOKEN_ACCESS:
-            if (eval_func) {
-                *was_error = eval_func(r, current, string_func);
-                if (*was_error) {
-                    return 0;
-                }
-            }
-            break;
-
-        case TOKEN_RE:
-            if (!error) {
-                error = "No operator before regex in file %s";
-            }
-        case TOKEN_LBRACE:
-            if (!error) {
-                error = "Unmatched '(' in file %s";
-            }
-        default:
-            if (!error) {
-                error = "internal parser error in file %s";
-            }
-
-            ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, error, r->filename);
-            *was_error = 1;
-            return 0;
-        }
-
-        DEBUG_DUMP_EVAL(r, current);
-        current->done = 1;
-        current = current->parent;
-    }
-
-    return (root ? root->value : 0);
-}
-AP_DECLARE(int) ap_expr_eval(request_rec *r, const ap_parse_node_t *root,
-                             int *was_error, backref_t **reptr,
-                             string_func_t string_func, opt_func_t eval_func)
-{
-    ap_parse_node_t *clone;
-    if (root == NULL) {  /* no condition == unconditional */
-        return 1;
-    }
-    clone = ap_expr_clone_tree(r->pool, root, NULL);
-    return expr_eval(r, clone, was_error, reptr, string_func, eval_func);
-}
-AP_DECLARE(int) ap_expr_evalstring(request_rec *r, const char *expr,
-                                   int *was_error, backref_t **reptr,
-                                   string_func_t string_func,
-                                   opt_func_t eval_func)
-{
-    ap_parse_node_t *root = ap_expr_parse(r->pool, expr, was_error);
-    if (*was_error || !root) {
-        ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
-                      "Error parsing expression in %s", r->filename);   
-        return 0;
-    }
-    return expr_eval(r, root, was_error, reptr, string_func, eval_func);
-}
-
-
-static ap_regex_t *isvar = NULL;
-AP_DECLARE_NONSTD(const char*) ap_expr_string(request_rec *r, 
-                                              const char *str)
-{
-    /* a default string evaluator: support headers and env */
-    const char *ret = str;
-    ap_regmatch_t match[3];
-    const char *p;
-
-    ap_assert(isvar != NULL);
-    if (ap_regexec(isvar, str, 3, match, 0) == 0) {
-        apr_table_t *table = NULL;
-        int len = match[1].rm_eo-match[1].rm_so;
-        const char *name = str+match[1].rm_so;
-        if (!strncasecmp("req", name, len)) {
-            table = r->headers_in;
-        }
-        else if (!strncasecmp("resp", name, len)) {
-            table = r->headers_out;
-        }
-        else if (!strncasecmp("env", name, len)) {
-            table = r->subprocess_env;
-        }
-        if (table != NULL) {
-            char *key = apr_pstrndup(r->pool, str+match[2].rm_so,
-                                     match[2].rm_eo-match[2].rm_so);
-            ret = apr_table_get(table, key);
-        }
-    }
-    else if (str[0] == '$') {
-        if (!strcasecmp(str, "$handler")) {
-            ret = r->handler;
-        }
-        else if (!strcasecmp(str, "$content-type")) {
-            ret = r->content_type;
-        }
-    }
-
-    /* copy wholesale from mod_rewrite to support its %{varname} vars */
-    else if ((str[0] == '%') && (str[1] == '{')
-             && (p = ap_strchr_c(str, '}'), p != NULL)) {
-        char *ch, *var;
-        apr_time_exp_t tm;
-
-        var = apr_pstrndup(r->pool, str+2, p-str-2);
-        for (ch = var; *ch; ++ch) {
-            *ch = apr_toupper(*ch);
-        }
-
-        switch (strlen(var)) {
-        case  4:
-            if (!strcmp(var, "TIME")) {
-                apr_time_exp_lt(&tm, apr_time_now());
-                ret = apr_psprintf(r->pool, "%04d%02d%02d%02d%02d%02d",
-                                      tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday,
-                                      tm.tm_hour, tm.tm_min, tm.tm_sec);
-                return (char *)ret;
-            }
-            else if (!strcmp(var, "IPV6")) {
-                int flag = FALSE;
-#if APR_HAVE_IPV6
-                apr_sockaddr_t *addr = r->connection->remote_addr;
-                flag = (addr->family == AF_INET6 &&
-                        !IN6_IS_ADDR_V4MAPPED((struct in6_addr *)addr->ipaddr_ptr));
-#endif
-                ret = (flag ? "on" : "off");
-            }
-            break;
-
-#if FIXME
-        case  5:
-            if (!strcmp(var, "HTTPS")) {
-                int flag = rewrite_is_https && rewrite_is_https(r->connection);
-                return apr_pstrdup(r->pool, flag ? "on" : "off");
-            }
-            break;
-#endif
-        case  8:
-            switch (var[6]) {
-            case 'A':
-                if (!strcmp(var, "TIME_DAY")) {
-                    apr_time_exp_lt(&tm, apr_time_now());
-                    return apr_psprintf(r->pool, "%02d", tm.tm_mday);
-                }
-                break;
-
-            case 'E':
-                if (!strcmp(var, "TIME_SEC")) {
-                    apr_time_exp_lt(&tm, apr_time_now());
-                    return apr_psprintf(r->pool, "%02d", tm.tm_sec);
-                }
-                break;
-
-            case 'I':
-                if (!strcmp(var, "TIME_MIN")) {
-                    apr_time_exp_lt(&tm, apr_time_now());
-                    return apr_psprintf(r->pool, "%02d", tm.tm_min);
-                }
-                break;
-
-            case 'O':
-                if (!strcmp(var, "TIME_MON")) {
-                    apr_time_exp_lt(&tm, apr_time_now());
-                    return apr_psprintf(r->pool, "%02d", tm.tm_mon+1);
-                }
-                break;
-            }
-            break;
-
-        case  9:
-            switch (var[7]) {
-            case 'A':
-                if (var[8] == 'Y' && !strcmp(var, "TIME_WDAY")) {
-                    apr_time_exp_lt(&tm, apr_time_now());
-                    return apr_psprintf(r->pool, "%d", tm.tm_wday);
-                }
-                else if (!strcmp(var, "TIME_YEAR")) {
-                    apr_time_exp_lt(&tm, apr_time_now());
-                    return apr_psprintf(r->pool, "%04d", tm.tm_year+1900);
-                }
-                break;
-
-            case 'E':
-                if (!strcmp(var, "IS_SUBREQ")) {
-                    ret = (r->main ? "true" : "false");
-                }
-                break;
-
-            case 'F':
-                if (!strcmp(var, "PATH_INFO")) {
-                    ret = r->path_info;
-                }
-                break;
-
-            case 'P':
-                if (!strcmp(var, "AUTH_TYPE")) {
-                    ret = r->ap_auth_type;
-                }
-                break;
-
-            case 'S':
-                if (!strcmp(var, "HTTP_HOST")) {
-                    ret = apr_table_get(r->headers_in, "Host");
-                }
-                break;
-
-            case 'U':
-                if (!strcmp(var, "TIME_HOUR")) {
-                    apr_time_exp_lt(&tm, apr_time_now());
-                    return apr_psprintf(r->pool, "%02d", tm.tm_hour);
-                }
-                break;
-            }
-            break;
-
-        case 11:
-            switch (var[8]) {
-            case 'A':
-                if (!strcmp(var, "SERVER_NAME")) {
-                    ret = ap_get_server_name(r);
-                }
-                break;
-
-            case 'D':
-                if (*var == 'R' && !strcmp(var, "REMOTE_ADDR")) {
-                    ret = r->connection->remote_ip;
-                }
-                else if (!strcmp(var, "SERVER_ADDR")) {
-                    ret = r->connection->local_ip;
-                }
-                break;
-
-            case 'E':
-                if (*var == 'H' && !strcmp(var, "HTTP_ACCEPT")) {
-                    ret = apr_table_get(r->headers_in, "Accept");
-                }
-                else if (!strcmp(var, "THE_REQUEST")) {
-                    ret = r->the_request;
-                }
-                break;
-
-            case 'I':
-                if (!strcmp(var, "API_VERSION")) {
-                    return apr_psprintf(r->pool, "%d:%d",
-                                        MODULE_MAGIC_NUMBER_MAJOR,
-                                        MODULE_MAGIC_NUMBER_MINOR);
-                }
-                break;
-
-            case 'K':
-                if (!strcmp(var, "HTTP_COOKIE")) {
-                    ret = apr_table_get(r->headers_in, "Cookie");
-                }
-                break;
-
-            case 'O':
-                if (*var == 'S' && !strcmp(var, "SERVER_PORT")) {
-                    return apr_psprintf(r->pool, "%u", ap_get_server_port(r));
-                }
-                else if (var[7] == 'H' && !strcmp(var, "REMOTE_HOST")) {
-                    ret = ap_get_remote_host(r->connection,r->per_dir_config,
-                                                REMOTE_NAME, NULL);
-                }
-                else if (!strcmp(var, "REMOTE_PORT")) {
-                    return apr_itoa(r->pool, r->connection->remote_addr->port);
-                }
-                break;
-
-            case 'S':
-                if (*var == 'R' && !strcmp(var, "REMOTE_USER")) {
-                    ret = r->user;
-                }
-                else if (!strcmp(var, "SCRIPT_USER")) {
-                    ret = "<unknown>";
-                    if (r->finfo.valid & APR_FINFO_USER) {
-                        apr_uid_name_get((char **)&ret, r->finfo.user,
-                                         r->pool);
-                    }
-                }
-                break;
-
-            case 'U':
-                if (!strcmp(var, "REQUEST_URI")) {
-                    ret = r->uri;
-                }
-                break;
-            }
-            break;
-
-        case 12:
-            switch (var[3]) {
-            case 'I':
-                if (!strcmp(var, "SCRIPT_GROUP")) {
-                    ret = "<unknown>";
-                    if (r->finfo.valid & APR_FINFO_GROUP) {
-                        apr_gid_name_get((char **)&ret, r->finfo.group,
-                                         r->pool);
-                    }
-                }
-                break;
-
-            case 'O':
-                if (!strcmp(var, "REMOTE_IDENT")) {
-                    ret = ap_get_remote_logname(r);
-                }
-                break;
-
-            case 'P':
-                if (!strcmp(var, "HTTP_REFERER")) {
-                    ret = apr_table_get(r->headers_in, "Referer");
-                }
-                break;
-
-            case 'R':
-                if (!strcmp(var, "QUERY_STRING")) {
-                    ret = r->args;
-                }
-                break;
-
-            case 'V':
-                if (!strcmp(var, "SERVER_ADMIN")) {
-                    ret = r->server->server_admin;
-                }
-                break;
-            }
-            break;
-
-        case 13:
-            if (!strcmp(var, "DOCUMENT_ROOT")) {
-                ret = ap_document_root(r);
-            }
-            break;
-
-        case 14:
-            if (*var == 'H' && !strcmp(var, "HTTP_FORWARDED")) {
-                ret = apr_table_get(r->headers_in, "Forwarded");
-            }
-            else if (!strcmp(var, "REQUEST_METHOD")) {
-                ret = r->method;
-            }
-            break;
-
-        case 15:
-            switch (var[7]) {
-            case 'E':
-                if (!strcmp(var, "HTTP_USER_AGENT")) {
-                    ret = apr_table_get(r->headers_in, "User-Agent");
-                }
-                break;
-
-            case 'F':
-                if (!strcmp(var, "SCRIPT_FILENAME")) {
-                    ret = r->filename; /* same as request_filename (16) */
-                }
-                break;
-
-            case 'P':
-                if (!strcmp(var, "SERVER_PROTOCOL")) {
-                    ret = r->protocol;
-                }
-                break;
-
-            case 'S':
-                if (!strcmp(var, "SERVER_SOFTWARE")) {
-                    ret = ap_get_server_banner();
-                }
-                break;
-            }
-            break;
-
-        case 16:
-            if (!strcmp(var, "REQUEST_FILENAME")) {
-                ret = r->filename; /* same as script_filename (15) */
-            }
-            break;
-
-        case 21:
-            if (!strcmp(var, "HTTP_PROXY_CONNECTION")) {
-                ret = apr_table_get(r->headers_in, "Proxy-Connection");
-            }
-            break;
-        }
-    }
-
-    /* TODO: provide a hook so modules can interpret other patterns */
-    /* OhBugger, where's the regexp for backreferences ? */
-    if (!ret) {
-        ret = "";
-    }
-    return ret;  /* default - literal string as-is */
-}
-static apr_status_t ap_expr_term(void *expr)
-{
-    if (isvar) {
-        ap_regfree(isvar);
-        isvar = NULL;
-    }
-    return APR_SUCCESS;
-}
-AP_DECLARE(apr_status_t) ap_expr_init(apr_pool_t *pool)
-{
-    static ap_regex_t var;
-    if (!isvar) {
-        isvar = &var;
-        if (ap_regcomp(isvar, "\\$([A-Za-z0-9]+)\\{([^\\}]+)\\}", 0)) {
-            isvar = NULL;
-        }
-        else {
-            apr_pool_cleanup_register(pool, isvar, ap_expr_term,
-                                      apr_pool_cleanup_null);
-        }
-    }
-    return isvar ? APR_SUCCESS : APR_EGENERAL;
-}
diff --git a/server/util_expr_eval.c b/server/util_expr_eval.c
new file mode 100644 (file)
index 0000000..8a74621
--- /dev/null
@@ -0,0 +1,1024 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*                      _             _
+ *  ap_expr_eval.c, based on ssl_expr_eval.c from mod_ssl
+ */
+
+#include "httpd.h"
+#include "http_log.h"
+#include "http_core.h"
+#include "http_protocol.h"
+#include "ap_provider.h"
+#include "util_expr_private.h"
+
+#include "apr_lib.h"
+
+APLOG_USE_MODULE(core);
+
+APR_HOOK_STRUCT(
+    APR_HOOK_LINK(expr_lookup)
+)
+
+AP_IMPLEMENT_HOOK_RUN_FIRST(int, expr_lookup, (ap_expr_lookup_parms *parms),
+                            (parms), DECLINED)
+
+static const char *ap_expr_eval_string_func(ap_expr_eval_ctx *ctx, const ap_expr *info,
+                                            const ap_expr *args);
+static const char *ap_expr_eval_var(ap_expr_eval_ctx *ctx,
+                                    const ap_expr_var_func_t *func,
+                                    const void *data);
+static void expr_dump_tree(const ap_expr *e, const server_rec *s, int loglevel, int indent);
+
+static const char *ap_expr_eval_word(ap_expr_eval_ctx *ctx, const ap_expr *node)
+{
+    const char *result = "";
+    switch (node->node_op) {
+        case op_Digit:
+            result = node->node_arg1;
+            break;
+        case op_String:
+            result = node->node_arg1;
+            break;
+        case op_Var:
+            result = ap_expr_eval_var(ctx, node->node_arg1, node->node_arg2);
+            break;
+        case op_StringFuncCall: {
+            const ap_expr *info = node->node_arg1;
+            const ap_expr *args = node->node_arg2;
+            result = ap_expr_eval_string_func(ctx, info, args);
+            break;
+        }
+        default:
+            *ctx->err = "Internal evaluation error: Unknown expression node";
+            break;
+    }
+    if (!result)
+        result = "";
+    return result;
+}
+
+static const char *ap_expr_eval_var(ap_expr_eval_ctx *ctx, 
+                                    const ap_expr_var_func_t *func,
+                                    const void *data)
+{
+    AP_DEBUG_ASSERT(func != NULL);
+    AP_DEBUG_ASSERT(data != NULL);
+    return (*func)(ctx, data);
+}
+
+static const char *ap_expr_eval_string_func(ap_expr_eval_ctx *ctx, const ap_expr *info,
+                                            const ap_expr *arg)
+{
+    ap_expr_string_func_t *func = info->node_arg1;
+    const void *data = info->node_arg2;
+
+    AP_DEBUG_ASSERT(info->node_op == op_StringFuncInfo);
+    AP_DEBUG_ASSERT(func != NULL);
+    AP_DEBUG_ASSERT(data != NULL);
+    return (*func)(ctx, data, ap_expr_eval_word(ctx, arg));
+}
+
+static int intstrcmp(const char *s1, const char *s2)
+{
+    apr_int64_t i1 = apr_atoi64(s1);
+    apr_int64_t i2 = apr_atoi64(s2);
+
+    if (i1 < i2)
+        return -1;
+    else if (i1 == i2)
+        return 0;
+    else
+        return 1;
+}
+
+static int ap_expr_eval_comp(ap_expr_eval_ctx *ctx, const ap_expr *node)
+{
+    switch (node->node_op) {
+        case op_EQ: {
+            const ap_expr *e1 = node->node_arg1;
+            const ap_expr *e2 = node->node_arg2;
+            return (intstrcmp(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) == 0);
+        }
+        case op_NE: {
+            const ap_expr *e1 = node->node_arg1;
+            const ap_expr *e2 = node->node_arg2;
+            return (intstrcmp(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) != 0);
+        }
+        case op_LT: {
+            const ap_expr *e1 = node->node_arg1;
+            const ap_expr *e2 = node->node_arg2;
+            return (intstrcmp(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) <  0);
+        }
+        case op_LE: {
+            const ap_expr *e1 = node->node_arg1;
+            const ap_expr *e2 = node->node_arg2;
+            return (intstrcmp(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) <= 0);
+        }
+        case op_GT: {
+            const ap_expr *e1 = node->node_arg1;
+            const ap_expr *e2 = node->node_arg2;
+            return (intstrcmp(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) >  0);
+        }
+        case op_GE: {
+            const ap_expr *e1 = node->node_arg1;
+            const ap_expr *e2 = node->node_arg2;
+            return (intstrcmp(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) >= 0);
+        }
+        case op_STR_EQ: {
+            const ap_expr *e1 = node->node_arg1;
+            const ap_expr *e2 = node->node_arg2;
+            return (strcmp(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) == 0);
+        }
+        case op_STR_NE: {
+            const ap_expr *e1 = node->node_arg1;
+            const ap_expr *e2 = node->node_arg2;
+            return (strcmp(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) != 0);
+        }
+        case op_STR_LT: {
+            const ap_expr *e1 = node->node_arg1;
+            const ap_expr *e2 = node->node_arg2;
+            return (strcmp(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) <  0);
+        }
+        case op_STR_LE: {
+            const ap_expr *e1 = node->node_arg1;
+            const ap_expr *e2 = node->node_arg2;
+            return (strcmp(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) <= 0);
+        }
+        case op_STR_GT: {
+            const ap_expr *e1 = node->node_arg1;
+            const ap_expr *e2 = node->node_arg2;
+            return (strcmp(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) >  0);
+        }
+        case op_STR_GE: {
+            const ap_expr *e1 = node->node_arg1;
+            const ap_expr *e2 = node->node_arg2;
+            return (strcmp(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) >= 0);
+        }
+        case op_IN: {
+            const ap_expr *e1 = node->node_arg1;
+            const ap_expr *e2 = node->node_arg2;
+            const char *needle = ap_expr_eval_word(ctx, e1);
+            if (e2->node_op == op_ListElement) {
+                do {
+                    const ap_expr *val = e2->node_arg1;
+                    AP_DEBUG_ASSERT(e2->node_op == op_ListElement);
+                    if (strcmp(needle, ap_expr_eval_word(ctx, val)) == 0) {
+                        return 1;
+                        break;
+                    }
+                    e2 = e2->node_arg2;
+                } while (e2 != NULL);
+            }
+            else if (e2->node_op == op_ListFuncCall) {
+                const ap_expr *info = e2->node_arg1;
+                const ap_expr *arg = e2->node_arg2;
+                ap_expr_list_func_t *func = info->node_arg1;
+                apr_array_header_t *haystack;
+                int i = 0;
+                AP_DEBUG_ASSERT(func != NULL);
+                AP_DEBUG_ASSERT(info->node_op == op_ListFuncInfo);
+                haystack = (*func)(ctx, info->node_arg2, ap_expr_eval_word(ctx, arg));
+                if (haystack == NULL)
+                    return 0;
+                for (; i < haystack->nelts; i++) {
+                    if (strcmp(needle, APR_ARRAY_IDX(haystack,i,char *)) == 0)
+                        return 1;
+                }
+            }
+            return 0;
+        }
+        case op_REG: {
+            const ap_expr *e1;
+            const ap_expr *e2;
+            const char *word;
+            const ap_regex_t *regex;
+
+            e1 = node->node_arg1;
+            e2 = node->node_arg2;
+            word = ap_expr_eval_word(ctx, e1);
+            regex = e2->node_arg1;
+            return (ap_regexec(regex, word, 0, NULL, 0) == 0);
+        }
+        case op_NRE: {
+            const ap_expr *e1;
+            const ap_expr *e2;
+            const char *word;
+            const ap_regex_t *regex;
+
+            e1 = node->node_arg1;
+            e2 = node->node_arg2;
+            word = ap_expr_eval_word(ctx, e1);
+            regex = e2->node_arg1;
+            return !(ap_regexec(regex, word, 0, NULL, 0) == 0);
+        }
+        default: {
+            *ctx->err = "Internal evaluation error: Unknown expression node";
+            return -1;
+        }
+    }
+}
+
+/* combined string/int comparison for compatibility with ssl_expr */
+static int strcmplex(const char *str1, const char *str2)
+{
+    int i, n1, n2;
+
+    if (str1 == NULL)
+        return -1;
+    if (str2 == NULL)
+        return +1;
+    n1 = strlen(str1);
+    n2 = strlen(str2);
+    if (n1 > n2)
+        return 1;
+    if (n1 < n2)
+        return -1;
+    for (i = 0; i < n1; i++) {
+        if (str1[i] > str2[i])
+            return 1;
+        if (str1[i] < str2[i])
+            return -1;
+    }
+    return 0;
+}
+
+static int ssl_expr_eval_comp(ap_expr_eval_ctx *ctx, const ap_expr *node)
+{
+    const ap_expr *e1 = node->node_arg1;
+    const ap_expr *e2 = node->node_arg2;
+    switch (node->node_op) {
+    case op_EQ:
+    case op_STR_EQ:
+        return (strcmplex(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) == 0);
+    case op_NE:
+    case op_STR_NE:
+        return (strcmplex(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) != 0);
+    case op_LT:
+    case op_STR_LT:
+        return (strcmplex(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) <  0);
+    case op_LE:
+    case op_STR_LE:
+        return (strcmplex(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) <= 0);
+    case op_GT:
+    case op_STR_GT:
+        return (strcmplex(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) >  0);
+    case op_GE:
+    case op_STR_GE:
+        return (strcmplex(ap_expr_eval_word(ctx, e1), ap_expr_eval_word(ctx, e2)) >= 0);
+    default:
+        return ap_expr_eval_comp(ctx, node);
+    }
+}
+
+
+AP_DECLARE(const char *) ap_expr_parse(apr_pool_t *pool, apr_pool_t *ptemp,
+                                       ap_expr_info_t *info, const char *expr,
+                                       ap_expr_lookup_fn *lookup_fn)
+{
+    ap_expr_parse_ctx ctx;
+    int rc;
+
+    ctx.pool     = pool;
+    ctx.ptemp    = ptemp;
+    ctx.inputbuf = expr;
+    ctx.inputlen = strlen(expr);
+    ctx.inputptr = ctx.inputbuf;
+    ctx.expr     = NULL;
+    ctx.error    = NULL;        /* generic bison error message (usually not very useful) */
+    ctx.error2   = NULL;        /* additional error message */
+    ctx.flags    = info->flags;
+    ctx.scan_del    = '\0';
+    ctx.scan_buf[0] = '\0';
+    ctx.scan_ptr    = ctx.scan_buf;
+    ctx.lookup_fn   = lookup_fn ? lookup_fn : ap_run_expr_lookup;
+
+    ap_expr_yylex_init(&ctx.scanner);
+    ap_expr_yyset_extra(&ctx, ctx.scanner);
+    rc = ap_expr_yyparse(&ctx);
+    ap_expr_yylex_destroy(ctx.scanner);
+    if (ctx.error) {
+        if (ctx.error2)
+            return apr_psprintf(pool, "%s: %s", ctx.error, ctx.error2);
+        else
+            return ctx.error;
+    }
+    else if (ctx.error2) {
+        return ctx.error2;
+    }
+
+    if (rc) /* XXX can this happen? */
+        return "syntax error";
+
+    /* XXX Make this properly depend on the loglevel, which requires
+     * XXX having a server_rec
+     */
+    /*
+    if (ctx.expr)
+        expr_dump_tree(ctx.expr, NULL, APLOG_NOTICE, 2);
+    */
+
+    info->root_node = ctx.expr;
+
+    return NULL;
+}
+
+AP_DECLARE(ap_expr_info_t*) ap_expr_parse_cmd(const cmd_parms *cmd,
+                                              const char *expr,
+                                              const char **err,
+                                              ap_expr_lookup_fn *lookup_fn)
+{
+    ap_expr_info_t *info = apr_pcalloc(cmd->pool, sizeof(ap_expr_info_t));
+    info->filename = cmd->directive->filename;
+    info->line_number = cmd->directive->line_num;
+    *err = ap_expr_parse(cmd->pool, cmd->temp_pool, info, expr, lookup_fn);
+
+    if (*err)
+        return NULL;
+
+    return info;
+}
+
+ap_expr *ap_expr_make(ap_expr_node_op op, const void *a1, const void *a2,
+                      ap_expr_parse_ctx *ctx)
+{
+    ap_expr *node = apr_palloc(ctx->pool, sizeof(ap_expr));
+    node->node_op   = op;
+    node->node_arg1 = a1;
+    node->node_arg2 = a2;
+    return node;
+}
+
+
+static ap_expr *ap_expr_info_make(int type, const char *name, ap_expr_parse_ctx *ctx)
+{
+    ap_expr *info = apr_palloc(ctx->pool, sizeof(ap_expr));
+    ap_expr_lookup_parms parms;
+    parms.type  = type;
+    parms.flags = 0;
+    parms.pool  = ctx->pool;
+    parms.ptemp = ctx->ptemp;
+    parms.name  = name;
+    parms.func  = &info->node_arg1;
+    parms.data  = &info->node_arg2;
+    parms.err   = &ctx->error2;
+    if (ctx->lookup_fn(&parms) != OK)
+        return NULL;
+    return info;
+}
+
+ap_expr *ap_expr_str_func_make(const char *name, const ap_expr *arg,
+                               ap_expr_parse_ctx *ctx)
+{
+    ap_expr *info = ap_expr_info_make(AP_EXPR_FUNC_STRING, name, ctx);
+    if (!info)
+        return NULL;
+
+    info->node_op = op_StringFuncInfo;
+    return ap_expr_make(op_StringFuncCall, info, arg, ctx);
+}
+
+ap_expr *ap_expr_list_func_make(const char *name, const ap_expr *arg,
+                                ap_expr_parse_ctx *ctx)
+{
+    ap_expr *info = ap_expr_info_make(AP_EXPR_FUNC_LIST, name, ctx);
+    if (!info)
+        return NULL;
+
+    info->node_op = op_ListFuncInfo;
+    return ap_expr_make(op_ListFuncCall, info, arg, ctx);
+}
+
+ap_expr *ap_expr_unary_op_make(const char *name, const ap_expr *arg,
+                               ap_expr_parse_ctx *ctx)
+{
+    ap_expr *info = ap_expr_info_make(AP_EXPR_FUNC_OP_UNARY, name, ctx);
+    if (!info)
+        return NULL;
+
+    info->node_op = op_UnaryOpInfo;
+    return ap_expr_make(op_UnaryOpCall, info, arg, ctx);
+}
+
+ap_expr *ap_expr_binary_op_make(const char *name, const ap_expr *arg1,
+                                const ap_expr *arg2, ap_expr_parse_ctx *ctx)
+{
+    ap_expr *args;
+    ap_expr *info = ap_expr_info_make(AP_EXPR_FUNC_OP_UNARY, name, ctx);
+    if (!info)
+        return NULL;
+
+    info->node_op = op_BinaryOpInfo;
+    args = ap_expr_make(op_BinaryOpArgs, arg1, arg2, ctx);
+    return ap_expr_make(op_BinaryOpCall, info, args, ctx);
+}
+
+
+ap_expr *ap_expr_var_make(const char *name, ap_expr_parse_ctx *ctx)
+{
+    ap_expr *node = ap_expr_info_make(AP_EXPR_FUNC_VAR, name, ctx);
+    if (!node)
+        return NULL;
+
+    node->node_op = op_Var;
+    return node;
+}
+
+
+#define MARK                        APLOG_MARK,loglevel,0,s
+#define DUMP_E_E(op, e1, e2)                                                \
+    do { ap_log_error(MARK,"%*s%s: %pp %pp", indent, " ", op, e1, e2);      \
+         if (e1) expr_dump_tree(e1, s, loglevel, indent + 2);               \
+         if (e2) expr_dump_tree(e2, s, loglevel, indent + 2);               \
+    } while (0)
+#define DUMP_S_E(op, s1, e1)                                                    \
+    do { ap_log_error(MARK,"%*s%s: '%s' %pp", indent, " ", op, (char *)s1, e1); \
+         if (e1) expr_dump_tree(e1, s, loglevel, indent + 2);                   \
+    } while (0)
+#define DUMP_S_P(op, s1, p1)                                                \
+    ap_log_error(MARK,"%*s%s: '%s' %pp", indent, " ", op, (char *)s1, p1);
+#define DUMP_P_P(op, p1, p2)                                                \
+    ap_log_error(MARK,"%*s%s: %pp %pp", indent, " ", op, p1, p2);
+#define DUMP_S_S(op, s1, s2)                                                       \
+    ap_log_error(MARK,"%*s%s: '%s' '%s'", indent, " ", op, (char *)s1, (char *)s2)
+#define DUMP_P(op, p1)                                                      \
+    ap_log_error(MARK,"%*s%s: %pp", indent, " ", op, p1);
+#define DUMP_S(op, s1)                                                      \
+    ap_log_error(MARK,"%*s%s: '%s'", indent, " ", op, (char *)s1)
+
+#define CASE_OP(op)                  case op: name = #op ; break;
+
+static void expr_dump_tree(const ap_expr *e, const server_rec *s, int loglevel, int indent)
+{
+    switch (e->node_op) {
+    /* no arg */
+    case op_NOP:
+    case op_True:
+    case op_False:
+        {
+            char *name;
+            switch (e->node_op) {
+            CASE_OP(op_NOP);
+            CASE_OP(op_True);
+            CASE_OP(op_False);
+            default:
+                ap_assert(0);
+            }
+            ap_log_error(MARK, "%*s%s", indent, " ", name);
+        }
+        break;
+
+    /* arg1: string, arg2: expr */
+    case op_UnaryOpCall:
+    case op_BinaryOpCall:
+    case op_BinaryOpArgs:
+        {
+            char *name;
+            switch (e->node_op) {
+            CASE_OP(op_BinaryOpCall);
+            CASE_OP(op_UnaryOpCall);
+            CASE_OP(op_BinaryOpArgs);
+            default:
+                ap_assert(0);
+            }
+            DUMP_S_E(name, e->node_arg1, e->node_arg2);
+        }
+        break;
+
+    /* arg1: expr, arg2: expr */
+    case op_Comp:
+    case op_Not:
+    case op_Or:
+    case op_And:
+    case op_EQ:
+    case op_NE:
+    case op_LT:
+    case op_LE:
+    case op_GT:
+    case op_GE:
+    case op_STR_EQ:
+    case op_STR_NE:
+    case op_STR_LT:
+    case op_STR_LE:
+    case op_STR_GT:
+    case op_STR_GE:
+    case op_IN:
+    case op_REG:
+    case op_NRE:
+    case op_Concat:
+    case op_StringFuncCall:
+    case op_ListFuncCall:
+    case op_ListElement:
+        {
+            char *name;
+            switch (e->node_op) {
+            CASE_OP(op_Comp);
+            CASE_OP(op_Not);
+            CASE_OP(op_Or);
+            CASE_OP(op_And);
+            CASE_OP(op_EQ);
+            CASE_OP(op_NE);
+            CASE_OP(op_LT);
+            CASE_OP(op_LE);
+            CASE_OP(op_GT);
+            CASE_OP(op_GE);
+            CASE_OP(op_STR_EQ);
+            CASE_OP(op_STR_NE);
+            CASE_OP(op_STR_LT);
+            CASE_OP(op_STR_LE);
+            CASE_OP(op_STR_GT);
+            CASE_OP(op_STR_GE);
+            CASE_OP(op_IN);
+            CASE_OP(op_REG);
+            CASE_OP(op_NRE);
+            CASE_OP(op_Concat);
+            CASE_OP(op_StringFuncCall);
+            CASE_OP(op_ListFuncCall);
+            CASE_OP(op_ListElement);
+            default:
+                ap_assert(0);
+            }
+            DUMP_E_E(name, e->node_arg1, e->node_arg2);
+        }
+        break;
+    /* arg1: string */
+    case op_Digit:
+    case op_String:
+        {
+            char *name;
+            switch (e->node_op) {
+            CASE_OP(op_Digit);
+            CASE_OP(op_String);
+            default:
+                ap_assert(0);
+            }
+            DUMP_S(name, e->node_arg1);
+        }
+        break;
+    /* arg1: pointer, arg2: pointer */
+    case op_Var:
+    case op_StringFuncInfo:
+    case op_UnaryOpInfo:
+    case op_BinaryOpInfo:
+    case op_ListFuncInfo:
+        {
+            char *name;
+            switch (e->node_op) {
+            CASE_OP(op_Var);
+            CASE_OP(op_StringFuncInfo);
+            CASE_OP(op_UnaryOpInfo);
+            CASE_OP(op_BinaryOpInfo);
+            CASE_OP(op_ListFuncInfo);
+            default:
+                ap_assert(0);
+            }
+            DUMP_P_P(name, e->node_arg1, e->node_arg2);
+        }
+        break;
+    /* arg1: pointer */
+    case op_Regex:
+        DUMP_P("op_Regex", e->node_arg1);
+        break;
+    default:
+        ap_log_error(MARK, "%*sERROR: INVALID OP %d", indent, " ", e->node_op);
+        break;
+    }
+}
+static int ap_expr_eval_unary_op(ap_expr_eval_ctx *ctx, const ap_expr *info,
+                                 const ap_expr *arg)
+{
+    const ap_expr_op_unary_t *op_func = info->node_arg1;
+    const void *data = info->node_arg2;
+
+    AP_DEBUG_ASSERT(info->node_op == op_UnaryOpInfo);
+    AP_DEBUG_ASSERT(op_func != NULL);
+    AP_DEBUG_ASSERT(data != NULL);
+    return (*op_func)(ctx, data, ap_expr_eval_word(ctx, arg));
+}
+
+static int ap_expr_eval_binary_op(ap_expr_eval_ctx *ctx, const ap_expr *info,
+                                  const ap_expr *args)
+{
+    const ap_expr_op_binary_t *op_func = info->node_arg1;
+    const void *data = info->node_arg2;
+    const ap_expr *a1 = args->node_arg1;
+    const ap_expr *a2 = args->node_arg2;
+
+    AP_DEBUG_ASSERT(info->node_op == op_BinaryOpInfo);
+    AP_DEBUG_ASSERT(args->node_op == op_BinaryOpArgs);
+    AP_DEBUG_ASSERT(op_func != NULL);
+    AP_DEBUG_ASSERT(data != NULL);
+    return (*op_func)(ctx, data, ap_expr_eval_word(ctx, a1),
+                      ap_expr_eval_word(ctx, a2));
+}
+
+
+static int ap_expr_eval(ap_expr_eval_ctx *ctx, const ap_expr *node)
+{
+    switch (node->node_op) {
+        case op_True: {
+            return 1;
+        }
+        case op_False: {
+            return 0;
+        }
+        case op_Not: {
+            const ap_expr *e = node->node_arg1;
+            return (!ap_expr_eval(ctx, e));
+        }
+        case op_Or: {
+            const ap_expr *e1 = node->node_arg1;
+            const ap_expr *e2 = node->node_arg2;
+            return (ap_expr_eval(ctx, e1) || ap_expr_eval(ctx, e2));
+        }
+        case op_And: {
+            const ap_expr *e1 = node->node_arg1;
+            const ap_expr *e2 = node->node_arg2;
+            return (ap_expr_eval(ctx, e1) && ap_expr_eval(ctx, e2));
+        }
+        case op_UnaryOpCall: {
+            const ap_expr *info = node->node_arg1;
+            const ap_expr *args = node->node_arg2;
+            return ap_expr_eval_unary_op(ctx, info, args);
+        }
+        case op_BinaryOpCall: {
+            const ap_expr *info = node->node_arg1;
+            const ap_expr *args = node->node_arg2;
+            return ap_expr_eval_binary_op(ctx, info, args);
+        }
+        case op_Comp: {
+            const ap_expr *e = node->node_arg1;
+            if (ctx->info->flags & AP_EXPR_FLAGS_SSL_EXPR_COMPAT)
+                return ssl_expr_eval_comp(ctx, e);
+            else
+                return ap_expr_eval_comp(ctx, e);
+        }
+        default: {
+            *ctx->err = "Internal evaluation error: Unknown expression node";
+            return FALSE;
+        }
+    }
+}
+
+
+AP_DECLARE(int) ap_expr_exec(request_rec *r, const ap_expr_info_t *info, const char **err)
+{
+    ap_expr_eval_ctx ctx;
+    int rc;
+    ctx.r = r;
+    ctx.c = r->connection;
+    ctx.s = r->server;
+    ctx.p = r->pool;
+    ctx.err  = err;
+    ctx.info = info;
+
+    *err = NULL;
+    rc = ap_expr_eval(&ctx, info->root_node);
+    if (*err != NULL)
+        return (-1);
+    else
+        return (rc ? 1 : 0);
+}
+
+static const char *req_func(ap_expr_eval_ctx *ctx, const char *name,
+                            const char *arg)
+{
+    if (ctx->r)
+        return apr_table_get(ctx->r->headers_in, arg);
+    else
+        return "";
+}
+
+static const char *resp_func(ap_expr_eval_ctx *ctx, const char *name,
+                             const char *arg)
+{
+    if (ctx->r)
+        return apr_table_get(ctx->r->headers_out, arg);
+    else
+        return "";
+}
+
+static const char *env_func(ap_expr_eval_ctx *ctx, const char *name,
+                            const char *arg)
+{
+    if (ctx->r)
+        return apr_table_get(ctx->r->subprocess_env, arg);
+    else
+        return "";
+}
+
+static const char *osenv_func(ap_expr_eval_ctx *ctx, const char *name, const char *arg)
+{
+    return getenv(arg);
+}
+
+static const char *tolower_func(ap_expr_eval_ctx *ctx, const char *name, const char *arg)
+{
+    char *result = apr_pstrdup(ctx->p, arg);
+    ap_str_tolower(result);
+    return result;
+}
+
+static const char *toupper_func(ap_expr_eval_ctx *ctx, const char *name, const char *arg)
+{
+    char *p;
+    char *result = apr_pstrdup(ctx->p, arg);
+
+    for (p = result; *p; ++p) {
+         *p = apr_toupper(*p);
+    }
+
+    return result;
+}
+
+static const char *escape_func(ap_expr_eval_ctx *ctx, const char *name, const char *arg)
+{
+    return ap_escape_uri(ctx->p, arg);
+}
+
+static const char *unescape_func(ap_expr_eval_ctx *ctx, const char *name, const char *arg)
+{
+    char *result = apr_pstrdup(ctx->p, arg);
+    if (ap_unescape_url(result))
+        return "";
+    else
+        return result;
+
+}
+
+static const char *request_var_names[] = {
+    "REQUEST_METHOD",           /*  0 */
+    "REQUEST_SCHEME",           /*  1 */
+    "REQUEST_URI",              /*  2 */
+    "REQUEST_FILENAME",         /*  3 */
+    "REMOTE_HOST",              /*  4 */
+    "REMOTE_IDENT",             /*  5 */
+    "REMOTE_USER",              /*  6 */
+    "SERVER_ADMIN",             /*  7 */
+    "SERVER_NAME",              /*  8 */
+    "SERVER_PORT",              /*  9 */
+    "SERVER_PROTOCOL",          /* 10 */
+    "SCRIPT_FILENAME",          /* 11 */
+    "PATH_INFO",                /* 12 */
+    "QUERY_STRING",             /* 13 */
+    "IS_SUBREQ",                /* 14 */
+    "DOCUMENT_ROOT",            /* 15 */
+    "AUTH_TYPE",                /* 16 */
+    "THE_REQUEST",              /* 17 */
+    "REMOTE_ADDR",              /* 18 */
+    "CONTENT_TYPE",             /* 19 */
+    NULL
+};
+
+static const char *request_var_fn(ap_expr_eval_ctx *ctx, const void *data)
+{
+    int index = ((const char **)data - request_var_names);
+    request_rec *r = ctx->r;
+    if (!r)
+        return "";
+
+    switch (index) {
+    case 0:
+        return r->method;
+    case 1:
+        return ap_http_scheme(r);
+    case 2:
+        return r->uri;
+    case 3:
+        return r->filename;
+    case 4:
+        return ap_get_remote_host(r->connection, r->per_dir_config,
+                                  REMOTE_NAME, NULL);
+    case 5:
+        return ap_get_remote_logname(r);
+    case 6:
+        return r->user;
+    case 7:
+        return r->server->server_admin;
+    case 8:
+        return ap_get_server_name(r);
+    case 9:
+        return apr_psprintf(ctx->p, "%u", ap_get_server_port(r));
+    case 10:
+        return r->protocol;
+    case 11:
+        return r->filename;
+    case 12:
+        return r->path_info;
+    case 13:
+        return r->args;
+    case 14:
+        return (r->main != NULL ? "true" : "false");
+    case 15:
+        return ap_document_root(r);
+    case 16:
+        return r->ap_auth_type;
+    case 17:
+        return r->the_request;
+    case 18:
+        return ctx->c->remote_ip;
+    case 19:
+        return r->content_type;
+    default:
+        ap_assert(0);
+        return NULL;
+    }
+}
+
+static const char *req_header_var_names[] = {
+    "HTTP_USER_AGENT",          /* 0 */
+    "HTTP_PROXY_CONNECTION",    /* 1 */
+    "HTTP_REFERER",
+    "HTTP_COOKIE",
+    "HTTP_FORWARDED",
+    "HTTP_HOST",
+    "HTTP_ACCEPT",
+    NULL
+};
+
+static const char *req_header_var_fn(ap_expr_eval_ctx *ctx, const void *data)
+{
+    const char **name = (const char **)data;
+    int index = (name - req_header_var_names);
+    if (!ctx->r)
+        return "";
+
+    switch (index) {
+    case 0:
+        return apr_table_get(ctx->r->headers_in, "User-Agent");
+    case 1:
+        return apr_table_get(ctx->r->headers_in, "Proxy-Connection");
+    default:
+        /* apr_table_get is case insensitive, just skip leading "HTTP_" */
+        return apr_table_get(ctx->r->headers_in, *name + 5);
+    }
+}
+
+static const char *misc_var_names[] = {
+    "TIME_YEAR",        /* 0 */
+    "TIME_MON",         /* 1 */
+    "TIME_DAY",         /* 2 */
+    "TIME_HOUR",        /* 3 */
+    "TIME_MIN",         /* 4 */
+    "TIME_SEC",         /* 5 */
+    "TIME_WDAY",        /* 6 */
+    "TIME",             /* 7 */
+    "SERVER_SOFTWARE",  /* 8 */
+    "API_VERSION",      /* 9 */
+    NULL
+};
+
+static const char *misc_var_fn(ap_expr_eval_ctx *ctx, const void *data)
+{
+    apr_time_exp_t tm;
+    apr_time_exp_lt(&tm, apr_time_now());
+    int index = ((const char **)data - misc_var_names);
+
+    switch (index) {
+    case 0:
+        return apr_psprintf(ctx->p, "%02d%02d", (tm.tm_year / 100) + 19,
+                            tm.tm_year % 100);
+    case 1:
+        return apr_psprintf(ctx->p, "%02d", tm.tm_mon+1);
+    case 2:
+        return apr_psprintf(ctx->p, "%02d", tm.tm_mday);
+    case 3:
+        return apr_psprintf(ctx->p, "%02d", tm.tm_hour);
+    case 4:
+        return apr_psprintf(ctx->p, "%02d", tm.tm_min);
+    case 5:
+        return apr_psprintf(ctx->p, "%02d", tm.tm_sec);
+    case 6:
+        return apr_psprintf(ctx->p, "%d", tm.tm_wday);
+    case 7:
+        return apr_psprintf(ctx->p, "%02d%02d%02d%02d%02d%02d%02d",
+                            (tm.tm_year / 100) + 19, (tm.tm_year % 100),
+                            tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min,
+                            tm.tm_sec);
+    case 8:
+        return ap_get_server_banner();
+    case 9:
+        return apr_itoa(ctx->p, MODULE_MAGIC_NUMBER);
+    default:
+        ap_assert(0);
+    }
+
+    return NULL;
+}
+
+struct expr_provider_single {
+    const void *func;
+    const char *name;
+};
+struct expr_provider_multi {
+    const void *func;
+    const char **names;
+};
+
+static const struct expr_provider_multi var_providers[] = {
+    { misc_var_fn, misc_var_names },
+    { req_header_var_fn, req_header_var_names },
+    { request_var_fn, request_var_names },
+    { NULL, NULL }
+};
+
+static const struct expr_provider_single string_func_providers[] = {
+    { osenv_func, "osenv" },
+    { env_func, "env" },
+    { resp_func, "resp" },
+    { req_func, "req" },
+    /* 'http' as alias for 'req' for compatibility with ssl_expr */
+    { req_func, "http" },
+    { tolower_func, "tolower" },
+    { toupper_func, "toupper" },
+    { escape_func, "escape" },
+    { unescape_func, "unescape" },
+    { NULL, NULL}
+};
+/* XXX: base64 encode/decode ? */
+
+static int core_expr_lookup(ap_expr_lookup_parms *parms)
+{
+    switch (parms->type) {
+    case AP_EXPR_FUNC_VAR: {
+        const struct expr_provider_multi *prov = var_providers;
+        while (prov->func) {
+            const char **name = prov->names;
+            while (*name) {
+                if (strcasecmp(*name, parms->name) == 0) {
+                    *parms->func = prov->func;
+                    *parms->data = name;
+                    return OK;
+                }
+               name++;
+            }
+            prov++;
+        }
+        break;
+    }
+    case AP_EXPR_FUNC_STRING: {
+        const struct expr_provider_single *prov = string_func_providers;
+        while (prov->func) {
+            if (strcasecmp(prov->name, parms->name) == 0) {
+                *parms->func = prov->func;
+                *parms->data = prov->name;
+                return OK;
+            }
+            prov++;
+        }
+        break;
+    }
+    default:
+        break;
+    }
+    return DECLINED;
+}
+
+static int expr_lookup_not_found(ap_expr_lookup_parms *parms)
+{
+    const char *type;
+
+    switch (parms->type) {
+    case AP_EXPR_FUNC_VAR:
+        type = "Variable";
+        break;
+    case AP_EXPR_FUNC_STRING:
+        type = "Function";
+        break;
+    case AP_EXPR_FUNC_LIST:
+        type = "List-returning function";
+        break;
+    case AP_EXPR_FUNC_OP_UNARY:
+        type = "Unary operator";
+        break;
+    case AP_EXPR_FUNC_OP_BINARY:
+        type = "Binary operator";
+        break;
+    default:
+        *parms->err = "Inavalid expression type in expr_lookup";
+        return !OK;
+    }
+    *parms->err = apr_psprintf(parms->ptemp, "%s '%s' does not exist", type,
+                               parms->name);
+    return !OK;
+}
+
+void ap_expr_init(apr_pool_t *p)
+{
+    ap_hook_expr_lookup(core_expr_lookup, NULL, NULL, APR_HOOK_MIDDLE);
+    ap_hook_expr_lookup(expr_lookup_not_found, NULL, NULL, APR_HOOK_REALLY_LAST);
+}
+
similarity index 71%
rename from modules/ssl/ssl_expr_parse.c
rename to server/util_expr_parse.c
index c05caba20fefe932547ef92feac8f184a31058e2..5562e9e8f96588c627d2b0d525bc537a301ccefd 100644 (file)
 #define YYLSP_NEEDED 0
 
 /* Substitute the variable and function names.  */
-#define yyparse         ssl_expr_yyparse
-#define yylex           ssl_expr_yylex
-#define yyerror         ssl_expr_yyerror
-#define yylval          ssl_expr_yylval
-#define yychar          ssl_expr_yychar
-#define yydebug         ssl_expr_yydebug
-#define yynerrs         ssl_expr_yynerrs
+#define yyparse         ap_expr_yyparse
+#define yylex           ap_expr_yylex
+#define yyerror         ap_expr_yyerror
+#define yylval          ap_expr_yylval
+#define yychar          ap_expr_yychar
+#define yydebug         ap_expr_yydebug
+#define yynerrs         ap_expr_yynerrs
 
 
 /* Copy the first part of user declarations.  */
 
 /* Line 189 of yacc.c  */
-#line 41 "ssl_expr_parse.y"
+#line 31 "util_expr_parse.y"
 
-#include "ssl_private.h"
+#include "util_expr_private.h"
 
 
 /* Line 189 of yacc.c  */
-#line 86 "ssl_expr_parse.c"
+#line 86 "util_expr_parse.c"
 
 /* Enabling traces.  */
 #ifndef YYDEBUG
    enum yytokentype {
      T_TRUE = 258,
      T_FALSE = 259,
-     T_DIGIT = 260,
-     T_ID = 261,
-     T_STRING = 262,
-     T_REGEX = 263,
-     T_REGEX_I = 264,
-     T_FUNC_FILE = 265,
-     T_OP_EQ = 266,
-     T_OP_NE = 267,
-     T_OP_LT = 268,
-     T_OP_LE = 269,
-     T_OP_GT = 270,
-     T_OP_GE = 271,
-     T_OP_REG = 272,
-     T_OP_NRE = 273,
-     T_OP_IN = 274,
-     T_OP_PEEREXTLIST = 275,
-     T_OP_OR = 276,
-     T_OP_AND = 277,
-     T_OP_NOT = 278
+     ERROR = 260,
+     T_DIGIT = 261,
+     T_ID = 262,
+     T_STRING = 263,
+     T_REGEX = 264,
+     T_REGEX_I = 265,
+     T_OP_UNARY = 266,
+     T_OP_BINARY = 267,
+     T_STR_BEGIN = 268,
+     T_STR_END = 269,
+     T_VAR_BEGIN = 270,
+     T_VAR_END = 271,
+     T_OP_EQ = 272,
+     T_OP_NE = 273,
+     T_OP_LT = 274,
+     T_OP_LE = 275,
+     T_OP_GT = 276,
+     T_OP_GE = 277,
+     T_OP_REG = 278,
+     T_OP_NRE = 279,
+     T_OP_IN = 280,
+     T_OP_STR_EQ = 281,
+     T_OP_STR_NE = 282,
+     T_OP_STR_LT = 283,
+     T_OP_STR_LE = 284,
+     T_OP_STR_GT = 285,
+     T_OP_STR_GE = 286,
+     T_OP_CONCAT = 287,
+     T_OP_OR = 288,
+     T_OP_AND = 289,
+     T_OP_NOT = 290
    };
 #endif
 
@@ -140,15 +152,15 @@ typedef union YYSTYPE
 {
 
 /* Line 214 of yacc.c  */
-#line 45 "ssl_expr_parse.y"
+#line 35 "util_expr_parse.y"
 
-    char     *cpVal;
-    ssl_expr *exVal;
+    char    *cpVal;
+    ap_expr *exVal;
 
 
 
 /* Line 214 of yacc.c  */
-#line 152 "ssl_expr_parse.c"
+#line 164 "util_expr_parse.c"
 } YYSTYPE;
 # define YYSTYPE_IS_TRIVIAL 1
 # define yystype YYSTYPE /* obsolescent; will be withdrawn */
@@ -159,17 +171,16 @@ typedef union YYSTYPE
 /* Copy the second part of user declarations.  */
 
 /* Line 264 of yacc.c  */
-#line 88 "ssl_expr_parse.y"
+#line 96 "util_expr_parse.y"
 
-#include "ssl_expr.h"
-#define yyscanner context->scanner
+#include "util_expr_private.h"
+#define yyscanner ctx->scanner
 
-int ssl_expr_yyerror(ssl_expr_info_type *context, char *err);
-int ssl_expr_yylex(YYSTYPE *lvalp, void *scanner);
+int ap_expr_yylex(YYSTYPE *lvalp, void *scanner);
 
 
 /* Line 264 of yacc.c  */
-#line 173 "ssl_expr_parse.c"
+#line 184 "util_expr_parse.c"
 
 #ifdef short
 # undef short
@@ -382,22 +393,22 @@ union yyalloc
 #endif
 
 /* YYFINAL -- State number of the termination state.  */
-#define YYFINAL  18
+#define YYFINAL  27
 /* YYLAST -- Last index in YYTABLE.  */
-#define YYLAST   56
+#define YYLAST   117
 
 /* YYNTOKENS -- Number of terminals.  */
-#define YYNTOKENS  30
+#define YYNTOKENS  42
 /* YYNNTS -- Number of nonterminals.  */
-#define YYNNTS  9
+#define YYNNTS  13
 /* YYNRULES -- Number of rules.  */
-#define YYNRULES  29
+#define YYNRULES  47
 /* YYNRULES -- Number of states.  */
-#define YYNSTATES  58
+#define YYNSTATES  88
 
 /* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX.  */
 #define YYUNDEFTOK  2
-#define YYMAXUTOK   278
+#define YYMAXUTOK   290
 
 #define YYTRANSLATE(YYX)                                               \
   ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
@@ -408,16 +419,16 @@ static const yytype_uint8 yytranslate[] =
        0,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,    29,     2,     2,
-      24,    25,     2,     2,    28,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+      36,    37,     2,     2,    40,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,    41,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,    26,     2,    27,     2,     2,     2,     2,
+       2,     2,     2,    38,     2,    39,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
@@ -432,7 +443,9 @@ static const yytype_uint8 yytranslate[] =
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     1,     2,     3,     4,
        5,     6,     7,     8,     9,    10,    11,    12,    13,    14,
-      15,    16,    17,    18,    19,    20,    21,    22,    23
+      15,    16,    17,    18,    19,    20,    21,    22,    23,    24,
+      25,    26,    27,    28,    29,    30,    31,    32,    33,    34,
+      35
 };
 
 #if YYDEBUG
@@ -440,32 +453,42 @@ static const yytype_uint8 yytranslate[] =
    YYRHS.  */
 static const yytype_uint8 yyprhs[] =
 {
-       0,     0,     3,     5,     7,     9,    12,    16,    20,    22,
-      26,    30,    34,    38,    42,    46,    50,    54,    58,    62,
-      67,    71,    73,    77,    79,    81,    86,    88,    90,    92
+       0,     0,     3,     5,     7,     9,    11,    14,    18,    22,
+      24,    27,    31,    35,    39,    43,    47,    51,    55,    59,
+      63,    67,    71,    75,    79,    83,    87,    91,    95,    97,
+     101,   103,   107,   110,   112,   114,   116,   120,   126,   128,
+     132,   134,   136,   140,   143,   145,   147,   152
 };
 
 /* YYRHS -- A `-1'-separated list of the rules' RHS.  */
 static const yytype_int8 yyrhs[] =
 {
-      31,     0,    -1,    32,    -1,     3,    -1,     4,    -1,    23,
-      32,    -1,    32,    21,    32,    -1,    32,    22,    32,    -1,
-      33,    -1,    24,    32,    25,    -1,    36,    11,    36,    -1,
-      36,    12,    36,    -1,    36,    13,    36,    -1,    36,    14,
-      36,    -1,    36,    15,    36,    -1,    36,    16,    36,    -1,
-      36,    19,    34,    -1,    36,    17,    37,    -1,    36,    18,
-      37,    -1,    20,    24,    36,    25,    -1,    26,    35,    27,
-      -1,    36,    -1,    35,    28,    36,    -1,     5,    -1,     7,
-      -1,    29,    26,     6,    27,    -1,    38,    -1,     8,    -1,
-       9,    -1,    10,    24,     7,    25,    -1
+      43,     0,    -1,    44,    -1,     5,    -1,     3,    -1,     4,
+      -1,    35,    44,    -1,    44,    33,    44,    -1,    44,    34,
+      44,    -1,    45,    -1,    11,    51,    -1,    36,    44,    37,
+      -1,    51,    17,    51,    -1,    51,    18,    51,    -1,    51,
+      19,    51,    -1,    51,    20,    51,    -1,    51,    21,    51,
+      -1,    51,    22,    51,    -1,    51,    26,    51,    -1,    51,
+      27,    51,    -1,    51,    28,    51,    -1,    51,    29,    51,
+      -1,    51,    30,    51,    -1,    51,    31,    51,    -1,    51,
+      25,    46,    -1,    51,    23,    52,    -1,    51,    24,    52,
+      -1,    51,    12,    51,    -1,    53,    -1,    38,    47,    39,
+      -1,    51,    -1,    47,    40,    51,    -1,    48,    49,    -1,
+      49,    -1,     8,    -1,    50,    -1,    15,     7,    16,    -1,
+      15,     7,    41,    48,    16,    -1,     6,    -1,    51,    32,
+      51,    -1,    50,    -1,    54,    -1,    13,    48,    14,    -1,
+      13,    14,    -1,     9,    -1,    10,    -1,     7,    36,    51,
+      37,    -1,     7,    36,    51,    37,    -1
 };
 
 /* YYRLINE[YYN] -- source line where rule number YYN was defined.  */
 static const yytype_uint8 yyrline[] =
 {
-       0,    99,    99,   102,   103,   104,   105,   106,   107,   108,
-     111,   112,   113,   114,   115,   116,   117,   118,   119,   122,
-     123,   126,   127,   130,   131,   132,   133,   136,   145,   156
+       0,   106,   106,   107,   110,   111,   112,   113,   114,   115,
+     116,   117,   120,   121,   122,   123,   124,   125,   126,   127,
+     128,   129,   130,   131,   132,   133,   134,   135,   138,   139,
+     142,   143,   146,   147,   151,   152,   155,   156,   159,   160,
+     161,   162,   163,   164,   167,   176,   187,   190
 };
 #endif
 
@@ -474,12 +497,15 @@ static const yytype_uint8 yyrline[] =
    First, the terminals, then, starting at YYNTOKENS, nonterminals.  */
 static const char *const yytname[] =
 {
-  "$end", "error", "$undefined", "T_TRUE", "T_FALSE", "T_DIGIT", "T_ID",
-  "T_STRING", "T_REGEX", "T_REGEX_I", "T_FUNC_FILE", "T_OP_EQ", "T_OP_NE",
-  "T_OP_LT", "T_OP_LE", "T_OP_GT", "T_OP_GE", "T_OP_REG", "T_OP_NRE",
-  "T_OP_IN", "T_OP_PEEREXTLIST", "T_OP_OR", "T_OP_AND", "T_OP_NOT", "'('",
-  "')'", "'{'", "'}'", "','", "'%'", "$accept", "root", "expr",
-  "comparison", "wordlist", "words", "word", "regex", "funccall", 0
+  "$end", "error", "$undefined", "T_TRUE", "T_FALSE", "ERROR", "T_DIGIT",
+  "T_ID", "T_STRING", "T_REGEX", "T_REGEX_I", "T_OP_UNARY", "T_OP_BINARY",
+  "T_STR_BEGIN", "T_STR_END", "T_VAR_BEGIN", "T_VAR_END", "T_OP_EQ",
+  "T_OP_NE", "T_OP_LT", "T_OP_LE", "T_OP_GT", "T_OP_GE", "T_OP_REG",
+  "T_OP_NRE", "T_OP_IN", "T_OP_STR_EQ", "T_OP_STR_NE", "T_OP_STR_LT",
+  "T_OP_STR_LE", "T_OP_STR_GT", "T_OP_STR_GE", "T_OP_CONCAT", "T_OP_OR",
+  "T_OP_AND", "T_OP_NOT", "'('", "')'", "'{'", "'}'", "','", "':'",
+  "$accept", "root", "expr", "comparison", "wordlist", "words", "string",
+  "strpart", "var", "word", "regex", "lstfunccall", "strfunccall", 0
 };
 #endif
 
@@ -490,24 +516,30 @@ static const yytype_uint16 yytoknum[] =
 {
        0,   256,   257,   258,   259,   260,   261,   262,   263,   264,
      265,   266,   267,   268,   269,   270,   271,   272,   273,   274,
-     275,   276,   277,   278,    40,    41,   123,   125,    44,    37
+     275,   276,   277,   278,   279,   280,   281,   282,   283,   284,
+     285,   286,   287,   288,   289,   290,    40,    41,   123,   125,
+      44,    58
 };
 # endif
 
 /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives.  */
 static const yytype_uint8 yyr1[] =
 {
-       0,    30,    31,    32,    32,    32,    32,    32,    32,    32,
-      33,    33,    33,    33,    33,    33,    33,    33,    33,    34,
-      34,    35,    35,    36,    36,    36,    36,    37,    37,    38
+       0,    42,    43,    43,    44,    44,    44,    44,    44,    44,
+      44,    44,    45,    45,    45,    45,    45,    45,    45,    45,
+      45,    45,    45,    45,    45,    45,    45,    45,    46,    46,
+      47,    47,    48,    48,    49,    49,    50,    50,    51,    51,
+      51,    51,    51,    51,    52,    52,    53,    54
 };
 
 /* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN.  */
 static const yytype_uint8 yyr2[] =
 {
-       0,     2,     1,     1,     1,     2,     3,     3,     1,     3,
-       3,     3,     3,     3,     3,     3,     3,     3,     3,     4,
-       3,     1,     3,     1,     1,     4,     1,     1,     1,     4
+       0,     2,     1,     1,     1,     1,     2,     3,     3,     1,
+       2,     3,     3,     3,     3,     3,     3,     3,     3,     3,
+       3,     3,     3,     3,     3,     3,     3,     3,     1,     3,
+       1,     3,     2,     1,     1,     1,     3,     5,     1,     3,
+       1,     1,     3,     2,     1,     1,     4,     4
 };
 
 /* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
@@ -515,37 +547,45 @@ static const yytype_uint8 yyr2[] =
    means the default is an error.  */
 static const yytype_uint8 yydefact[] =
 {
-       0,     3,     4,    23,    24,     0,     0,     0,     0,     0,
-       2,     8,     0,    26,     0,     5,     0,     0,     1,     0,
+       0,     4,     5,     3,    38,     0,     0,     0,     0,     0,
+       0,     0,     2,     9,    40,     0,    41,     0,    10,    34,
+      43,     0,    33,    35,     0,     6,     0,     1,     0,     0,
        0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-       0,     9,     0,     6,     7,    10,    11,    12,    13,    14,
-      15,    27,    28,    17,    18,     0,     0,    16,    29,    25,
-       0,     0,    21,     0,    20,     0,    19,    22
+       0,     0,     0,     0,     0,     0,     0,     0,    42,    32,
+      36,     0,    11,     7,     8,    27,    12,    13,    14,    15,
+      16,    17,    44,    45,    25,    26,     0,     0,    24,    28,
+      18,    19,    20,    21,    22,    23,    39,    47,     0,     0,
+       0,    30,    37,     0,    29,     0,    46,    31
 };
 
 /* YYDEFGOTO[NTERM-NUM].  */
 static const yytype_int8 yydefgoto[] =
 {
-      -1,     9,    10,    11,    47,    51,    12,    43,    13
+      -1,    11,    12,    13,    68,    80,    21,    22,    14,    15,
+      64,    69,    16
 };
 
 /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
    STATE-NUM.  */
-#define YYPACT_NINF -22
+#define YYPACT_NINF -29
 static const yytype_int8 yypact[] =
 {
-       3,   -22,   -22,   -22,   -22,   -12,     3,     3,   -10,    22,
-      23,   -22,    24,   -22,    17,   -22,    -2,    44,   -22,     3,
-       3,     4,     4,     4,     4,     4,     4,    38,    38,    -5,
-      26,   -22,     1,    30,   -22,   -22,   -22,   -22,   -22,   -22,
-     -22,   -22,   -22,   -22,   -22,    29,     4,   -22,   -22,   -22,
-       4,    21,   -22,    31,   -22,     4,   -22,   -22
+      49,   -29,   -29,   -29,   -29,    12,     1,    35,    25,    65,
+      65,    57,   -15,   -29,   -29,    85,   -29,     1,    31,   -29,
+     -29,    51,   -29,   -29,   -10,   -29,    53,   -29,    65,    65,
+       1,     1,     1,     1,     1,     1,     1,    11,    11,    -5,
+       1,     1,     1,     1,     1,     1,     1,   -28,   -29,   -29,
+     -29,    36,   -29,    33,   -29,    31,    31,    31,    31,    31,
+      31,    31,   -29,   -29,   -29,   -29,    34,     1,   -29,   -29,
+      31,    31,    31,    31,    31,    31,   -29,   -29,    -3,     1,
+       6,    31,   -29,   -22,   -29,     1,   -29,    31
 };
 
 /* YYPGOTO[NTERM-NUM].  */
 static const yytype_int8 yypgoto[] =
 {
-     -22,   -22,    11,   -22,   -22,   -22,   -21,    27,   -22
+     -29,   -29,    13,   -29,   -29,   -29,    24,   -20,    -4,    -6,
+      39,   -29,   -29
 };
 
 /* YYTABLE[YYPACT[STATE-NUM]].  What to do in state STATE-NUM.  If
@@ -555,34 +595,49 @@ static const yytype_int8 yypgoto[] =
 #define YYTABLE_NINF -1
 static const yytype_uint8 yytable[] =
 {
-      35,    36,    37,    38,    39,    40,     1,     2,     3,     3,
-       4,     4,    14,     5,     5,    45,    17,    15,    16,    19,
-      20,    46,    18,    31,    30,    52,     6,     7,    49,    53,
-      33,    34,     8,     8,    57,    21,    22,    23,    24,    25,
-      26,    27,    28,    29,    19,    20,    41,    42,    54,    55,
-      32,    48,    20,    50,     0,    44,    56
+      18,    49,    66,    23,    46,    19,    50,     4,     5,    77,
+      46,    47,     8,    82,     7,    86,     8,    23,    28,    29,
+      62,    63,    25,    26,    55,    56,    57,    58,    59,    60,
+      61,    51,    24,    67,    70,    71,    72,    73,    74,    75,
+      76,    53,    54,    19,    19,    84,    85,    23,    17,    20,
+       8,     8,     1,     2,     3,     4,     5,    27,    49,    19,
+       6,    81,     7,    46,     8,    48,     8,    29,     1,     2,
+      79,     4,     5,    83,    23,    78,     6,    65,     7,    87,
+       8,     0,     0,     0,     9,    10,    28,    29,     0,     0,
+      52,     0,     0,     0,     0,     0,     0,    30,     0,     0,
+       9,    10,    31,    32,    33,    34,    35,    36,    37,    38,
+      39,    40,    41,    42,    43,    44,    45,    46
 };
 
 static const yytype_int8 yycheck[] =
 {
-      21,    22,    23,    24,    25,    26,     3,     4,     5,     5,
-       7,     7,    24,    10,    10,    20,    26,     6,     7,    21,
-      22,    26,     0,    25,     7,    46,    23,    24,    27,    50,
-      19,    20,    29,    29,    55,    11,    12,    13,    14,    15,
-      16,    17,    18,    19,    21,    22,     8,     9,    27,    28,
-       6,    25,    22,    24,    -1,    28,    25
+       6,    21,     7,     7,    32,     8,    16,     6,     7,    37,
+      32,    17,    15,    16,    13,    37,    15,    21,    33,    34,
+       9,    10,     9,    10,    30,    31,    32,    33,    34,    35,
+      36,    41,     7,    38,    40,    41,    42,    43,    44,    45,
+      46,    28,    29,     8,     8,    39,    40,    51,    36,    14,
+      15,    15,     3,     4,     5,     6,     7,     0,    78,     8,
+      11,    67,    13,    32,    15,    14,    15,    34,     3,     4,
+      36,     6,     7,    79,    78,    51,    11,    38,    13,    85,
+      15,    -1,    -1,    -1,    35,    36,    33,    34,    -1,    -1,
+      37,    -1,    -1,    -1,    -1,    -1,    -1,    12,    -1,    -1,
+      35,    36,    17,    18,    19,    20,    21,    22,    23,    24,
+      25,    26,    27,    28,    29,    30,    31,    32
 };
 
 /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
    symbol of state STATE-NUM.  */
 static const yytype_uint8 yystos[] =
 {
-       0,     3,     4,     5,     7,    10,    23,    24,    29,    31,
-      32,    33,    36,    38,    24,    32,    32,    26,     0,    21,
-      22,    11,    12,    13,    14,    15,    16,    17,    18,    19,
-       7,    25,     6,    32,    32,    36,    36,    36,    36,    36,
-      36,     8,     9,    37,    37,    20,    26,    34,    25,    27,
-      24,    35,    36,    36,    27,    28,    25,    36
+       0,     3,     4,     5,     6,     7,    11,    13,    15,    35,
+      36,    43,    44,    45,    50,    51,    54,    36,    51,     8,
+      14,    48,    49,    50,     7,    44,    44,     0,    33,    34,
+      12,    17,    18,    19,    20,    21,    22,    23,    24,    25,
+      26,    27,    28,    29,    30,    31,    32,    51,    14,    49,
+      16,    41,    37,    44,    44,    51,    51,    51,    51,    51,
+      51,    51,     9,    10,    52,    52,     7,    38,    46,    53,
+      51,    51,    51,    51,    51,    51,    51,    37,    48,    36,
+      47,    51,    16,    51,    39,    40,    37,    51
 };
 
 #define yyerrok                (yyerrstatus = 0)
@@ -615,7 +670,7 @@ do                                                          \
     }                                                          \
   else                                                         \
     {                                                          \
-      yyerror (context, YY_("syntax error: cannot back up")); \
+      yyerror (ctx, YY_("syntax error: cannot back up")); \
       YYERROR;                                                 \
     }                                                          \
 while (YYID (0))
@@ -695,7 +750,7 @@ do {                                                                          \
     {                                                                    \
       YYFPRINTF (stderr, "%s ", Title);                                          \
       yy_symbol_print (stderr,                                           \
-                 Type, Value, context); \
+                 Type, Value, ctx); \
       YYFPRINTF (stderr, "\n");                                                  \
     }                                                                    \
 } while (YYID (0))
@@ -709,19 +764,19 @@ do {                                                                        \
 #if (defined __STDC__ || defined __C99__FUNC__ \
      || defined __cplusplus || defined _MSC_VER)
 static void
-yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, ssl_expr_info_type *context)
+yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, ap_expr_parse_ctx *ctx)
 #else
 static void
-yy_symbol_value_print (yyoutput, yytype, yyvaluep, context)
+yy_symbol_value_print (yyoutput, yytype, yyvaluep, ctx)
     FILE *yyoutput;
     int yytype;
     YYSTYPE const * const yyvaluep;
-    ssl_expr_info_type *context;
+    ap_expr_parse_ctx *ctx;
 #endif
 {
   if (!yyvaluep)
     return;
-  YYUSE (context);
+  YYUSE (ctx);
 # ifdef YYPRINT
   if (yytype < YYNTOKENS)
     YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
@@ -743,14 +798,14 @@ yy_symbol_value_print (yyoutput, yytype, yyvaluep, context)
 #if (defined __STDC__ || defined __C99__FUNC__ \
      || defined __cplusplus || defined _MSC_VER)
 static void
-yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, ssl_expr_info_type *context)
+yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, ap_expr_parse_ctx *ctx)
 #else
 static void
-yy_symbol_print (yyoutput, yytype, yyvaluep, context)
+yy_symbol_print (yyoutput, yytype, yyvaluep, ctx)
     FILE *yyoutput;
     int yytype;
     YYSTYPE const * const yyvaluep;
-    ssl_expr_info_type *context;
+    ap_expr_parse_ctx *ctx;
 #endif
 {
   if (yytype < YYNTOKENS)
@@ -758,7 +813,7 @@ yy_symbol_print (yyoutput, yytype, yyvaluep, context)
   else
     YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
 
-  yy_symbol_value_print (yyoutput, yytype, yyvaluep, context);
+  yy_symbol_value_print (yyoutput, yytype, yyvaluep, ctx);
   YYFPRINTF (yyoutput, ")");
 }
 
@@ -801,13 +856,13 @@ do {                                                              \
 #if (defined __STDC__ || defined __C99__FUNC__ \
      || defined __cplusplus || defined _MSC_VER)
 static void
-yy_reduce_print (YYSTYPE *yyvsp, int yyrule, ssl_expr_info_type *context)
+yy_reduce_print (YYSTYPE *yyvsp, int yyrule, ap_expr_parse_ctx *ctx)
 #else
 static void
-yy_reduce_print (yyvsp, yyrule, context)
+yy_reduce_print (yyvsp, yyrule, ctx)
     YYSTYPE *yyvsp;
     int yyrule;
-    ssl_expr_info_type *context;
+    ap_expr_parse_ctx *ctx;
 #endif
 {
   int yynrhs = yyr2[yyrule];
@@ -821,7 +876,7 @@ yy_reduce_print (yyvsp, yyrule, context)
       YYFPRINTF (stderr, "   $%d = ", yyi + 1);
       yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi],
                       &(yyvsp[(yyi + 1) - (yynrhs)])
-                                      , context);
+                                      , ctx);
       YYFPRINTF (stderr, "\n");
     }
 }
@@ -829,7 +884,7 @@ yy_reduce_print (yyvsp, yyrule, context)
 # define YY_REDUCE_PRINT(Rule)         \
 do {                                   \
   if (yydebug)                         \
-    yy_reduce_print (yyvsp, Rule, context); \
+    yy_reduce_print (yyvsp, Rule, ctx); \
 } while (YYID (0))
 
 /* Nonzero means print parse trace.  It is left uninitialized so that
@@ -1080,18 +1135,18 @@ yysyntax_error (char *yyresult, int yystate, int yychar)
 #if (defined __STDC__ || defined __C99__FUNC__ \
      || defined __cplusplus || defined _MSC_VER)
 static void
-yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep, ssl_expr_info_type *context)
+yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep, ap_expr_parse_ctx *ctx)
 #else
 static void
-yydestruct (yymsg, yytype, yyvaluep, context)
+yydestruct (yymsg, yytype, yyvaluep, ctx)
     const char *yymsg;
     int yytype;
     YYSTYPE *yyvaluep;
-    ssl_expr_info_type *context;
+    ap_expr_parse_ctx *ctx;
 #endif
 {
   YYUSE (yyvaluep);
-  YYUSE (context);
+  YYUSE (ctx);
 
   if (!yymsg)
     yymsg = "Deleting";
@@ -1114,7 +1169,7 @@ int yyparse ();
 #endif
 #else /* ! YYPARSE_PARAM */
 #if defined __STDC__ || defined __cplusplus
-int yyparse (ssl_expr_info_type *context);
+int yyparse (ap_expr_parse_ctx *ctx);
 #else
 int yyparse ();
 #endif
@@ -1142,11 +1197,11 @@ yyparse (YYPARSE_PARAM)
 #if (defined __STDC__ || defined __C99__FUNC__ \
      || defined __cplusplus || defined _MSC_VER)
 int
-yyparse (ssl_expr_info_type *context)
+yyparse (ap_expr_parse_ctx *ctx)
 #else
 int
-yyparse (context)
-    ssl_expr_info_type *context;
+yyparse (ctx)
+    ap_expr_parse_ctx *ctx;
 #endif
 #endif
 {
@@ -1401,222 +1456,345 @@ yyreduce:
         case 2:
 
 /* Line 1455 of yacc.c  */
-#line 99 "ssl_expr_parse.y"
-    { context->expr = (yyvsp[(1) - (1)].exVal); ;}
+#line 106 "util_expr_parse.y"
+    { ctx->expr = (yyvsp[(1) - (1)].exVal); ;}
     break;
 
   case 3:
 
 /* Line 1455 of yacc.c  */
-#line 102 "ssl_expr_parse.y"
-    { (yyval.exVal) = ssl_expr_make(op_True,  NULL, NULL, context); ;}
+#line 107 "util_expr_parse.y"
+    { YYABORT; ;}
     break;
 
   case 4:
 
 /* Line 1455 of yacc.c  */
-#line 103 "ssl_expr_parse.y"
-    { (yyval.exVal) = ssl_expr_make(op_False, NULL, NULL, context); ;}
+#line 110 "util_expr_parse.y"
+    { (yyval.exVal) = ap_expr_make(op_True,        NULL, NULL, ctx); ;}
     break;
 
   case 5:
 
 /* Line 1455 of yacc.c  */
-#line 104 "ssl_expr_parse.y"
-    { (yyval.exVal) = ssl_expr_make(op_Not,   (yyvsp[(2) - (2)].exVal),   NULL, context); ;}
+#line 111 "util_expr_parse.y"
+    { (yyval.exVal) = ap_expr_make(op_False,       NULL, NULL, ctx); ;}
     break;
 
   case 6:
 
 /* Line 1455 of yacc.c  */
-#line 105 "ssl_expr_parse.y"
-    { (yyval.exVal) = ssl_expr_make(op_Or,    (yyvsp[(1) - (3)].exVal),   (yyvsp[(3) - (3)].exVal),   context); ;}
+#line 112 "util_expr_parse.y"
+    { (yyval.exVal) = ap_expr_make(op_Not,         (yyvsp[(2) - (2)].exVal),   NULL, ctx); ;}
     break;
 
   case 7:
 
 /* Line 1455 of yacc.c  */
-#line 106 "ssl_expr_parse.y"
-    { (yyval.exVal) = ssl_expr_make(op_And,   (yyvsp[(1) - (3)].exVal),   (yyvsp[(3) - (3)].exVal),   context); ;}
+#line 113 "util_expr_parse.y"
+    { (yyval.exVal) = ap_expr_make(op_Or,          (yyvsp[(1) - (3)].exVal),   (yyvsp[(3) - (3)].exVal),   ctx); ;}
     break;
 
   case 8:
 
 /* Line 1455 of yacc.c  */
-#line 107 "ssl_expr_parse.y"
-    { (yyval.exVal) = ssl_expr_make(op_Comp,  (yyvsp[(1) - (1)].exVal),   NULL, context); ;}
+#line 114 "util_expr_parse.y"
+    { (yyval.exVal) = ap_expr_make(op_And,         (yyvsp[(1) - (3)].exVal),   (yyvsp[(3) - (3)].exVal),   ctx); ;}
     break;
 
   case 9:
 
 /* Line 1455 of yacc.c  */
-#line 108 "ssl_expr_parse.y"
-    { (yyval.exVal) = (yyvsp[(2) - (3)].exVal); ;}
+#line 115 "util_expr_parse.y"
+    { (yyval.exVal) = ap_expr_make(op_Comp,        (yyvsp[(1) - (1)].exVal),   NULL, ctx); ;}
     break;
 
   case 10:
 
 /* Line 1455 of yacc.c  */
-#line 111 "ssl_expr_parse.y"
-    { (yyval.exVal) = ssl_expr_make(op_EQ,  (yyvsp[(1) - (3)].exVal), (yyvsp[(3) - (3)].exVal), context); ;}
+#line 116 "util_expr_parse.y"
+    { (yyval.exVal) = ap_expr_unary_op_make(       (yyvsp[(1) - (2)].cpVal),   (yyvsp[(2) - (2)].exVal),   ctx); ;}
     break;
 
   case 11:
 
 /* Line 1455 of yacc.c  */
-#line 112 "ssl_expr_parse.y"
-    { (yyval.exVal) = ssl_expr_make(op_NE,  (yyvsp[(1) - (3)].exVal), (yyvsp[(3) - (3)].exVal), context); ;}
+#line 117 "util_expr_parse.y"
+    { (yyval.exVal) = (yyvsp[(2) - (3)].exVal); ;}
     break;
 
   case 12:
 
 /* Line 1455 of yacc.c  */
-#line 113 "ssl_expr_parse.y"
-    { (yyval.exVal) = ssl_expr_make(op_LT,  (yyvsp[(1) - (3)].exVal), (yyvsp[(3) - (3)].exVal), context); ;}
+#line 120 "util_expr_parse.y"
+    { (yyval.exVal) = ap_expr_make(op_EQ,      (yyvsp[(1) - (3)].exVal), (yyvsp[(3) - (3)].exVal), ctx); ;}
     break;
 
   case 13:
 
 /* Line 1455 of yacc.c  */
-#line 114 "ssl_expr_parse.y"
-    { (yyval.exVal) = ssl_expr_make(op_LE,  (yyvsp[(1) - (3)].exVal), (yyvsp[(3) - (3)].exVal), context); ;}
+#line 121 "util_expr_parse.y"
+    { (yyval.exVal) = ap_expr_make(op_NE,      (yyvsp[(1) - (3)].exVal), (yyvsp[(3) - (3)].exVal), ctx); ;}
     break;
 
   case 14:
 
 /* Line 1455 of yacc.c  */
-#line 115 "ssl_expr_parse.y"
-    { (yyval.exVal) = ssl_expr_make(op_GT,  (yyvsp[(1) - (3)].exVal), (yyvsp[(3) - (3)].exVal), context); ;}
+#line 122 "util_expr_parse.y"
+    { (yyval.exVal) = ap_expr_make(op_LT,      (yyvsp[(1) - (3)].exVal), (yyvsp[(3) - (3)].exVal), ctx); ;}
     break;
 
   case 15:
 
 /* Line 1455 of yacc.c  */
-#line 116 "ssl_expr_parse.y"
-    { (yyval.exVal) = ssl_expr_make(op_GE,  (yyvsp[(1) - (3)].exVal), (yyvsp[(3) - (3)].exVal), context); ;}
+#line 123 "util_expr_parse.y"
+    { (yyval.exVal) = ap_expr_make(op_LE,      (yyvsp[(1) - (3)].exVal), (yyvsp[(3) - (3)].exVal), ctx); ;}
     break;
 
   case 16:
 
 /* Line 1455 of yacc.c  */
-#line 117 "ssl_expr_parse.y"
-    { (yyval.exVal) = ssl_expr_make(op_IN,  (yyvsp[(1) - (3)].exVal), (yyvsp[(3) - (3)].exVal), context); ;}
+#line 124 "util_expr_parse.y"
+    { (yyval.exVal) = ap_expr_make(op_GT,      (yyvsp[(1) - (3)].exVal), (yyvsp[(3) - (3)].exVal), ctx); ;}
     break;
 
   case 17:
 
 /* Line 1455 of yacc.c  */
-#line 118 "ssl_expr_parse.y"
-    { (yyval.exVal) = ssl_expr_make(op_REG, (yyvsp[(1) - (3)].exVal), (yyvsp[(3) - (3)].exVal), context); ;}
+#line 125 "util_expr_parse.y"
+    { (yyval.exVal) = ap_expr_make(op_GE,      (yyvsp[(1) - (3)].exVal), (yyvsp[(3) - (3)].exVal), ctx); ;}
     break;
 
   case 18:
 
 /* Line 1455 of yacc.c  */
-#line 119 "ssl_expr_parse.y"
-    { (yyval.exVal) = ssl_expr_make(op_NRE, (yyvsp[(1) - (3)].exVal), (yyvsp[(3) - (3)].exVal), context); ;}
+#line 126 "util_expr_parse.y"
+    { (yyval.exVal) = ap_expr_make(op_STR_EQ,  (yyvsp[(1) - (3)].exVal), (yyvsp[(3) - (3)].exVal), ctx); ;}
     break;
 
   case 19:
 
 /* Line 1455 of yacc.c  */
-#line 122 "ssl_expr_parse.y"
-    { (yyval.exVal) = ssl_expr_make(op_PeerExtElement, (yyvsp[(3) - (4)].exVal), NULL, context); ;}
+#line 127 "util_expr_parse.y"
+    { (yyval.exVal) = ap_expr_make(op_STR_NE,  (yyvsp[(1) - (3)].exVal), (yyvsp[(3) - (3)].exVal), ctx); ;}
     break;
 
   case 20:
 
 /* Line 1455 of yacc.c  */
-#line 123 "ssl_expr_parse.y"
-    { (yyval.exVal) = (yyvsp[(2) - (3)].exVal) ; ;}
+#line 128 "util_expr_parse.y"
+    { (yyval.exVal) = ap_expr_make(op_STR_LT,  (yyvsp[(1) - (3)].exVal), (yyvsp[(3) - (3)].exVal), ctx); ;}
     break;
 
   case 21:
 
 /* Line 1455 of yacc.c  */
-#line 126 "ssl_expr_parse.y"
-    { (yyval.exVal) = ssl_expr_make(op_ListElement, (yyvsp[(1) - (1)].exVal), NULL, context); ;}
+#line 129 "util_expr_parse.y"
+    { (yyval.exVal) = ap_expr_make(op_STR_LE,  (yyvsp[(1) - (3)].exVal), (yyvsp[(3) - (3)].exVal), ctx); ;}
     break;
 
   case 22:
 
 /* Line 1455 of yacc.c  */
-#line 127 "ssl_expr_parse.y"
-    { (yyval.exVal) = ssl_expr_make(op_ListElement, (yyvsp[(3) - (3)].exVal), (yyvsp[(1) - (3)].exVal), context);   ;}
+#line 130 "util_expr_parse.y"
+    { (yyval.exVal) = ap_expr_make(op_STR_GT,  (yyvsp[(1) - (3)].exVal), (yyvsp[(3) - (3)].exVal), ctx); ;}
     break;
 
   case 23:
 
 /* Line 1455 of yacc.c  */
-#line 130 "ssl_expr_parse.y"
-    { (yyval.exVal) = ssl_expr_make(op_Digit,  (yyvsp[(1) - (1)].cpVal), NULL, context); ;}
+#line 131 "util_expr_parse.y"
+    { (yyval.exVal) = ap_expr_make(op_STR_GE,  (yyvsp[(1) - (3)].exVal), (yyvsp[(3) - (3)].exVal), ctx); ;}
     break;
 
   case 24:
 
 /* Line 1455 of yacc.c  */
-#line 131 "ssl_expr_parse.y"
-    { (yyval.exVal) = ssl_expr_make(op_String, (yyvsp[(1) - (1)].cpVal), NULL, context); ;}
+#line 132 "util_expr_parse.y"
+    { (yyval.exVal) = ap_expr_make(op_IN,      (yyvsp[(1) - (3)].exVal), (yyvsp[(3) - (3)].exVal), ctx); ;}
     break;
 
   case 25:
 
 /* Line 1455 of yacc.c  */
-#line 132 "ssl_expr_parse.y"
-    { (yyval.exVal) = ssl_expr_make(op_Var,    (yyvsp[(3) - (4)].cpVal), NULL, context); ;}
+#line 133 "util_expr_parse.y"
+    { (yyval.exVal) = ap_expr_make(op_REG,     (yyvsp[(1) - (3)].exVal), (yyvsp[(3) - (3)].exVal), ctx); ;}
     break;
 
   case 26:
 
 /* Line 1455 of yacc.c  */
-#line 133 "ssl_expr_parse.y"
-    { (yyval.exVal) = (yyvsp[(1) - (1)].exVal); ;}
+#line 134 "util_expr_parse.y"
+    { (yyval.exVal) = ap_expr_make(op_NRE,     (yyvsp[(1) - (3)].exVal), (yyvsp[(3) - (3)].exVal), ctx); ;}
     break;
 
   case 27:
 
 /* Line 1455 of yacc.c  */
-#line 136 "ssl_expr_parse.y"
-    { 
+#line 135 "util_expr_parse.y"
+    { (yyval.exVal) = ap_expr_binary_op_make((yyvsp[(2) - (3)].cpVal), (yyvsp[(1) - (3)].exVal), (yyvsp[(3) - (3)].exVal), ctx); ;}
+    break;
+
+  case 28:
+
+/* Line 1455 of yacc.c  */
+#line 138 "util_expr_parse.y"
+    { (yyval.exVal) = (yyvsp[(1) - (1)].exVal); ;}
+    break;
+
+  case 29:
+
+/* Line 1455 of yacc.c  */
+#line 139 "util_expr_parse.y"
+    { (yyval.exVal) = (yyvsp[(2) - (3)].exVal); ;}
+    break;
+
+  case 30:
+
+/* Line 1455 of yacc.c  */
+#line 142 "util_expr_parse.y"
+    { (yyval.exVal) = ap_expr_make(op_ListElement, (yyvsp[(1) - (1)].exVal), NULL, ctx); ;}
+    break;
+
+  case 31:
+
+/* Line 1455 of yacc.c  */
+#line 143 "util_expr_parse.y"
+    { (yyval.exVal) = ap_expr_make(op_ListElement, (yyvsp[(3) - (3)].exVal), (yyvsp[(1) - (3)].exVal),   ctx); ;}
+    break;
+
+  case 32:
+
+/* Line 1455 of yacc.c  */
+#line 146 "util_expr_parse.y"
+    { (yyval.exVal) = ap_expr_make(op_Concat, (yyvsp[(1) - (2)].exVal), (yyvsp[(2) - (2)].exVal), ctx); ;}
+    break;
+
+  case 33:
+
+/* Line 1455 of yacc.c  */
+#line 147 "util_expr_parse.y"
+    { (yyval.exVal) = (yyvsp[(1) - (1)].exVal); ;}
+    break;
+
+  case 34:
+
+/* Line 1455 of yacc.c  */
+#line 151 "util_expr_parse.y"
+    { (yyval.exVal) = ap_expr_make(op_String, (yyvsp[(1) - (1)].cpVal), NULL, ctx); ;}
+    break;
+
+  case 35:
+
+/* Line 1455 of yacc.c  */
+#line 152 "util_expr_parse.y"
+    { (yyval.exVal) = (yyvsp[(1) - (1)].exVal); ;}
+    break;
+
+  case 36:
+
+/* Line 1455 of yacc.c  */
+#line 155 "util_expr_parse.y"
+    { (yyval.exVal) = ap_expr_var_make((yyvsp[(2) - (3)].cpVal), ctx); ;}
+    break;
+
+  case 37:
+
+/* Line 1455 of yacc.c  */
+#line 156 "util_expr_parse.y"
+    { (yyval.exVal) = ap_expr_str_func_make((yyvsp[(2) - (5)].cpVal), (yyvsp[(4) - (5)].exVal), ctx); ;}
+    break;
+
+  case 38:
+
+/* Line 1455 of yacc.c  */
+#line 159 "util_expr_parse.y"
+    { (yyval.exVal) = ap_expr_make(op_Digit,  (yyvsp[(1) - (1)].cpVal), NULL, ctx); ;}
+    break;
+
+  case 39:
+
+/* Line 1455 of yacc.c  */
+#line 160 "util_expr_parse.y"
+    { (yyval.exVal) = ap_expr_make(op_Concat, (yyvsp[(1) - (3)].exVal), (yyvsp[(3) - (3)].exVal),   ctx); ;}
+    break;
+
+  case 40:
+
+/* Line 1455 of yacc.c  */
+#line 161 "util_expr_parse.y"
+    { (yyval.exVal) = (yyvsp[(1) - (1)].exVal); ;}
+    break;
+
+  case 41:
+
+/* Line 1455 of yacc.c  */
+#line 162 "util_expr_parse.y"
+    { (yyval.exVal) = (yyvsp[(1) - (1)].exVal); ;}
+    break;
+
+  case 42:
+
+/* Line 1455 of yacc.c  */
+#line 163 "util_expr_parse.y"
+    { (yyval.exVal) = (yyvsp[(2) - (3)].exVal); ;}
+    break;
+
+  case 43:
+
+/* Line 1455 of yacc.c  */
+#line 164 "util_expr_parse.y"
+    { (yyval.exVal) = ap_expr_make(op_String, "", NULL, ctx); ;}
+    break;
+
+  case 44:
+
+/* Line 1455 of yacc.c  */
+#line 167 "util_expr_parse.y"
+    {
                 ap_regex_t *regex;
-                if ((regex = ap_pregcomp(context->pool, (yyvsp[(1) - (1)].cpVal), 
+                if ((regex = ap_pregcomp(ctx->pool, (yyvsp[(1) - (1)].cpVal),
                                          AP_REG_EXTENDED|AP_REG_NOSUB)) == NULL) {
-                    context->error = "Failed to compile regular expression";
+                    ctx->error = "Failed to compile regular expression";
                     YYERROR;
                 }
-                (yyval.exVal) = ssl_expr_make(op_Regex, regex, NULL, context);
+                (yyval.exVal) = ap_expr_make(op_Regex, regex, NULL, ctx);
             ;}
     break;
 
-  case 28:
+  case 45:
 
 /* Line 1455 of yacc.c  */
-#line 145 "ssl_expr_parse.y"
+#line 176 "util_expr_parse.y"
     {
                 ap_regex_t *regex;
-                if ((regex = ap_pregcomp(context->pool, (yyvsp[(1) - (1)].cpVal), 
+                if ((regex = ap_pregcomp(ctx->pool, (yyvsp[(1) - (1)].cpVal),
                                          AP_REG_EXTENDED|AP_REG_NOSUB|AP_REG_ICASE)) == NULL) {
-                    context->error = "Failed to compile regular expression";
+                    ctx->error = "Failed to compile regular expression";
                     YYERROR;
                 }
-                (yyval.exVal) = ssl_expr_make(op_Regex, regex, NULL, context);
+                (yyval.exVal) = ap_expr_make(op_Regex, regex, NULL, ctx);
             ;}
     break;
 
-  case 29:
+  case 46:
 
 /* Line 1455 of yacc.c  */
-#line 156 "ssl_expr_parse.y"
-    { 
-               ssl_expr *args = ssl_expr_make(op_ListElement, (yyvsp[(3) - (4)].cpVal), NULL, context);
-               (yyval.exVal) = ssl_expr_make(op_Func, "file", args, context);
-            ;}
+#line 187 "util_expr_parse.y"
+    { (yyval.exVal) = ap_expr_list_func_make((yyvsp[(1) - (4)].cpVal), (yyvsp[(3) - (4)].exVal), ctx); ;}
+    break;
+
+  case 47:
+
+/* Line 1455 of yacc.c  */
+#line 190 "util_expr_parse.y"
+    { (yyval.exVal) = ap_expr_str_func_make((yyvsp[(1) - (4)].cpVal), (yyvsp[(3) - (4)].exVal), ctx); ;}
     break;
 
 
 
 /* Line 1455 of yacc.c  */
-#line 1620 "ssl_expr_parse.c"
+#line 1798 "util_expr_parse.c"
       default: break;
     }
   YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
@@ -1651,7 +1829,7 @@ yyerrlab:
     {
       ++yynerrs;
 #if ! YYERROR_VERBOSE
-      yyerror (context, YY_("syntax error"));
+      yyerror (ctx, YY_("syntax error"));
 #else
       {
        YYSIZE_T yysize = yysyntax_error (0, yystate, yychar);
@@ -1675,11 +1853,11 @@ yyerrlab:
        if (0 < yysize && yysize <= yymsg_alloc)
          {
            (void) yysyntax_error (yymsg, yystate, yychar);
-           yyerror (context, yymsg);
+           yyerror (ctx, yymsg);
          }
        else
          {
-           yyerror (context, YY_("syntax error"));
+           yyerror (ctx, YY_("syntax error"));
            if (yysize != 0)
              goto yyexhaustedlab;
          }
@@ -1703,7 +1881,7 @@ yyerrlab:
       else
        {
          yydestruct ("Error: discarding",
-                     yytoken, &yylval, context);
+                     yytoken, &yylval, ctx);
          yychar = YYEMPTY;
        }
     }
@@ -1759,7 +1937,7 @@ yyerrlab1:
 
 
       yydestruct ("Error: popping",
-                 yystos[yystate], yyvsp, context);
+                 yystos[yystate], yyvsp, ctx);
       YYPOPSTACK (1);
       yystate = *yyssp;
       YY_STACK_PRINT (yyss, yyssp);
@@ -1794,7 +1972,7 @@ yyabortlab:
 | yyexhaustedlab -- memory exhaustion comes here.  |
 `-------------------------------------------------*/
 yyexhaustedlab:
-  yyerror (context, YY_("memory exhausted"));
+  yyerror (ctx, YY_("memory exhausted"));
   yyresult = 2;
   /* Fall through.  */
 #endif
@@ -1802,7 +1980,7 @@ yyexhaustedlab:
 yyreturn:
   if (yychar != YYEMPTY)
      yydestruct ("Cleanup: discarding lookahead",
-                yytoken, &yylval, context);
+                yytoken, &yylval, ctx);
   /* Do not reclaim the symbols of the rule which action triggered
      this YYABORT or YYACCEPT.  */
   YYPOPSTACK (yylen);
@@ -1810,7 +1988,7 @@ yyreturn:
   while (yyssp != yyss)
     {
       yydestruct ("Cleanup: popping",
-                 yystos[*yyssp], yyvsp, context);
+                 yystos[*yyssp], yyvsp, ctx);
       YYPOPSTACK (1);
     }
 #ifndef yyoverflow
@@ -1828,13 +2006,12 @@ yyreturn:
 
 
 /* Line 1675 of yacc.c  */
-#line 162 "ssl_expr_parse.y"
+#line 193 "util_expr_parse.y"
 
 
-int yyerror(ssl_expr_info_type *context, char *s)
+void yyerror(ap_expr_parse_ctx *ctx, char *s)
 {
-    context->error = s;
-    return 2;
+    ctx->error = s;
 }
 
 
similarity index 73%
rename from modules/ssl/ssl_expr_parse.h
rename to server/util_expr_parse.h
index e847372ee751eb7d4a72d28d0474c1530f03f09d..f806e0121f1a47cab9ecb4026463b029ba217e11 100644 (file)
    enum yytokentype {
      T_TRUE = 258,
      T_FALSE = 259,
-     T_DIGIT = 260,
-     T_ID = 261,
-     T_STRING = 262,
-     T_REGEX = 263,
-     T_REGEX_I = 264,
-     T_FUNC_FILE = 265,
-     T_OP_EQ = 266,
-     T_OP_NE = 267,
-     T_OP_LT = 268,
-     T_OP_LE = 269,
-     T_OP_GT = 270,
-     T_OP_GE = 271,
-     T_OP_REG = 272,
-     T_OP_NRE = 273,
-     T_OP_IN = 274,
-     T_OP_PEEREXTLIST = 275,
-     T_OP_OR = 276,
-     T_OP_AND = 277,
-     T_OP_NOT = 278
+     ERROR = 260,
+     T_DIGIT = 261,
+     T_ID = 262,
+     T_STRING = 263,
+     T_REGEX = 264,
+     T_REGEX_I = 265,
+     T_OP_UNARY = 266,
+     T_OP_BINARY = 267,
+     T_STR_BEGIN = 268,
+     T_STR_END = 269,
+     T_VAR_BEGIN = 270,
+     T_VAR_END = 271,
+     T_OP_EQ = 272,
+     T_OP_NE = 273,
+     T_OP_LT = 274,
+     T_OP_LE = 275,
+     T_OP_GT = 276,
+     T_OP_GE = 277,
+     T_OP_REG = 278,
+     T_OP_NRE = 279,
+     T_OP_IN = 280,
+     T_OP_STR_EQ = 281,
+     T_OP_STR_NE = 282,
+     T_OP_STR_LT = 283,
+     T_OP_STR_LE = 284,
+     T_OP_STR_GT = 285,
+     T_OP_STR_GE = 286,
+     T_OP_CONCAT = 287,
+     T_OP_OR = 288,
+     T_OP_AND = 289,
+     T_OP_NOT = 290
    };
 #endif
 
@@ -70,15 +82,15 @@ typedef union YYSTYPE
 {
 
 /* Line 1676 of yacc.c  */
-#line 45 "ssl_expr_parse.y"
+#line 35 "util_expr_parse.y"
 
-    char     *cpVal;
-    ssl_expr *exVal;
+    char    *cpVal;
+    ap_expr *exVal;
 
 
 
 /* Line 1676 of yacc.c  */
-#line 82 "ssl_expr_parse.h"
+#line 94 "util_expr_parse.h"
 } YYSTYPE;
 # define YYSTYPE_IS_TRIVIAL 1
 # define yystype YYSTYPE /* obsolescent; will be withdrawn */
diff --git a/server/util_expr_parse.y b/server/util_expr_parse.y
new file mode 100644 (file)
index 0000000..c79eee5
--- /dev/null
@@ -0,0 +1,199 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* based on ap_expr_parse.y from mod_ssl */
+
+/*  _________________________________________________________________
+**
+**  Expression Parser
+**  _________________________________________________________________
+*/
+
+%pure-parser
+%error-verbose
+%defines
+%lex-param   { void *yyscanner }
+%parse-param { ap_expr_parse_ctx *ctx }
+
+%{
+#include "util_expr_private.h"
+%}
+
+%union {
+    char    *cpVal;
+    ap_expr *exVal;
+}
+
+%token  T_TRUE
+%token  T_FALSE
+
+%token  <cpVal> ERROR
+
+%token  <cpVal> T_DIGIT
+%token  <cpVal> T_ID
+%token  <cpVal> T_STRING
+%token  <cpVal> T_REGEX
+%token  <cpVal> T_REGEX_I
+%token  <cpVal> T_OP_UNARY
+%token  <cpVal> T_OP_BINARY
+
+%token  T_STR_BEGIN
+%token  T_STR_END
+%token  T_VAR_BEGIN
+%token  T_VAR_END
+
+%token  T_OP_EQ
+%token  T_OP_NE
+%token  T_OP_LT
+%token  T_OP_LE
+%token  T_OP_GT
+%token  T_OP_GE
+%token  T_OP_REG
+%token  T_OP_NRE
+%token  T_OP_IN
+%token  T_OP_STR_EQ
+%token  T_OP_STR_NE
+%token  T_OP_STR_LT
+%token  T_OP_STR_LE
+%token  T_OP_STR_GT
+%token  T_OP_STR_GE
+%token  T_OP_CONCAT
+
+%token  T_OP_OR
+%token  T_OP_AND
+%token  T_OP_NOT
+
+%left   T_OP_OR
+%left   T_OP_AND
+%left   T_OP_NOT
+%left   T_OP_CONCAT
+
+%type   <exVal>   expr
+%type   <exVal>   comparison
+%type   <exVal>   strfunccall
+%type   <exVal>   lstfunccall
+%type   <exVal>   regex
+%type   <exVal>   words
+%type   <exVal>   wordlist
+%type   <exVal>   word
+%type   <exVal>   string
+%type   <exVal>   strpart
+%type   <exVal>   var
+
+%{
+#include "util_expr_private.h"
+#define yyscanner ctx->scanner
+
+int ap_expr_yylex(YYSTYPE *lvalp, void *scanner);
+%}
+
+
+%%
+
+root      : expr                         { ctx->expr = $1; }
+          | ERROR                        { YYABORT; }
+          ;
+
+expr      : T_TRUE                       { $$ = ap_expr_make(op_True,        NULL, NULL, ctx); }
+          | T_FALSE                      { $$ = ap_expr_make(op_False,       NULL, NULL, ctx); }
+          | T_OP_NOT expr                { $$ = ap_expr_make(op_Not,         $2,   NULL, ctx); }
+          | expr T_OP_OR expr            { $$ = ap_expr_make(op_Or,          $1,   $3,   ctx); }
+          | expr T_OP_AND expr           { $$ = ap_expr_make(op_And,         $1,   $3,   ctx); }
+          | comparison                   { $$ = ap_expr_make(op_Comp,        $1,   NULL, ctx); }
+          | T_OP_UNARY word              { $$ = ap_expr_unary_op_make(       $1,   $2,   ctx); }
+          | '(' expr ')'                 { $$ = $2; }
+          ;
+
+comparison: word T_OP_EQ word            { $$ = ap_expr_make(op_EQ,      $1, $3, ctx); }
+          | word T_OP_NE word            { $$ = ap_expr_make(op_NE,      $1, $3, ctx); }
+          | word T_OP_LT word            { $$ = ap_expr_make(op_LT,      $1, $3, ctx); }
+          | word T_OP_LE word            { $$ = ap_expr_make(op_LE,      $1, $3, ctx); }
+          | word T_OP_GT word            { $$ = ap_expr_make(op_GT,      $1, $3, ctx); }
+          | word T_OP_GE word            { $$ = ap_expr_make(op_GE,      $1, $3, ctx); }
+          | word T_OP_STR_EQ word        { $$ = ap_expr_make(op_STR_EQ,  $1, $3, ctx); }
+          | word T_OP_STR_NE word        { $$ = ap_expr_make(op_STR_NE,  $1, $3, ctx); }
+          | word T_OP_STR_LT word        { $$ = ap_expr_make(op_STR_LT,  $1, $3, ctx); }
+          | word T_OP_STR_LE word        { $$ = ap_expr_make(op_STR_LE,  $1, $3, ctx); }
+          | word T_OP_STR_GT word        { $$ = ap_expr_make(op_STR_GT,  $1, $3, ctx); }
+          | word T_OP_STR_GE word        { $$ = ap_expr_make(op_STR_GE,  $1, $3, ctx); }
+          | word T_OP_IN wordlist        { $$ = ap_expr_make(op_IN,      $1, $3, ctx); }
+          | word T_OP_REG regex          { $$ = ap_expr_make(op_REG,     $1, $3, ctx); }
+          | word T_OP_NRE regex          { $$ = ap_expr_make(op_NRE,     $1, $3, ctx); }
+          | word T_OP_BINARY word        { $$ = ap_expr_binary_op_make($2, $1, $3, ctx); }
+          ;
+
+wordlist  : lstfunccall                  { $$ = $1; }
+          | '{' words '}'                { $$ = $2; }
+          ;
+
+words     : word                         { $$ = ap_expr_make(op_ListElement, $1, NULL, ctx); }
+          | words ',' word               { $$ = ap_expr_make(op_ListElement, $3, $1,   ctx); }
+          ;
+
+string    : string strpart               { $$ = ap_expr_make(op_Concat, $1, $2, ctx); }
+          | strpart                      { $$ = $1; }
+          ;
+
+
+strpart   : T_STRING                     { $$ = ap_expr_make(op_String, $1, NULL, ctx); }
+          | var                          { $$ = $1; }
+          ;
+
+var       : T_VAR_BEGIN T_ID T_VAR_END            { $$ = ap_expr_var_make($2, ctx); }
+          | T_VAR_BEGIN T_ID ':' string T_VAR_END { $$ = ap_expr_str_func_make($2, $4, ctx); }
+          ;
+
+word      : T_DIGIT                      { $$ = ap_expr_make(op_Digit,  $1, NULL, ctx); }
+          | word T_OP_CONCAT word        { $$ = ap_expr_make(op_Concat, $1, $3,   ctx); }
+          | var                          { $$ = $1; }
+          | strfunccall                  { $$ = $1; }
+          | T_STR_BEGIN string T_STR_END { $$ = $2; }
+          | T_STR_BEGIN T_STR_END        { $$ = ap_expr_make(op_String, "", NULL, ctx); }
+          ;
+
+regex     : T_REGEX {
+                ap_regex_t *regex;
+                if ((regex = ap_pregcomp(ctx->pool, $1,
+                                         AP_REG_EXTENDED|AP_REG_NOSUB)) == NULL) {
+                    ctx->error = "Failed to compile regular expression";
+                    YYERROR;
+                }
+                $$ = ap_expr_make(op_Regex, regex, NULL, ctx);
+            }
+          | T_REGEX_I {
+                ap_regex_t *regex;
+                if ((regex = ap_pregcomp(ctx->pool, $1,
+                                         AP_REG_EXTENDED|AP_REG_NOSUB|AP_REG_ICASE)) == NULL) {
+                    ctx->error = "Failed to compile regular expression";
+                    YYERROR;
+                }
+                $$ = ap_expr_make(op_Regex, regex, NULL, ctx);
+            }
+          ;
+
+lstfunccall : T_ID '(' word ')' { $$ = ap_expr_list_func_make($1, $3, ctx); }
+            ;
+
+strfunccall : T_ID '(' word ')' { $$ = ap_expr_str_func_make($1, $3, ctx); }
+            ;
+
+%%
+
+void yyerror(ap_expr_parse_ctx *ctx, char *s)
+{
+    ctx->error = s;
+}
+
diff --git a/server/util_expr_private.h b/server/util_expr_private.h
new file mode 100644 (file)
index 0000000..48d1199
--- /dev/null
@@ -0,0 +1,129 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __AP_EXPR_PRIVATE_H__
+#define __AP_EXPR_PRIVATE_H__
+
+#include "httpd.h"
+#include "apr_strings.h"
+#include "apr_tables.h"
+#include "ap_expr.h"
+
+#ifndef YY_NULL
+#define YY_NULL 0
+#endif
+
+#ifndef MIN
+#define MIN(a,b) (((a)<(b))?(a):(b))
+#endif
+
+#ifndef YYDEBUG
+#define YYDEBUG 0
+#endif
+
+/** The operations in a parse tree node */
+typedef enum {
+    op_NOP,
+    op_True, op_False,
+    op_Not, op_Or, op_And,
+    op_Comp,
+    op_EQ, op_NE, op_LT, op_LE, op_GT, op_GE, op_IN,
+    op_REG, op_NRE,
+    op_STR_EQ, op_STR_NE, op_STR_LT, op_STR_LE, op_STR_GT, op_STR_GE,
+    op_Concat,
+    op_Digit, op_String, op_Regex,
+    op_Var,
+    op_ListElement,
+    /*
+     * call external functions/operators.
+     * The info node contains the function pointer and some function specific
+     * info.
+     * For Binary operators, the Call node links to the Info node and the
+     * Args node, which in turn links to the left and right operand.
+     * For all other variants, the Call node links to the Info node and the
+     * argument.
+     */
+    op_UnaryOpCall, op_UnaryOpInfo,
+    op_BinaryOpCall, op_BinaryOpInfo, op_BinaryOpArgs,
+    op_StringFuncCall, op_StringFuncInfo,
+    op_ListFuncCall, op_ListFuncInfo
+} ap_expr_node_op;
+
+/** The basic parse tree node */
+struct ap_expr_node {
+    ap_expr_node_op node_op;
+    const void *node_arg1;
+    const void *node_arg2;
+};
+
+/** The context used by scanner and parser */
+typedef struct {
+    /* internal state of the scanner */
+    const char        *inputbuf;
+    int                inputlen;
+    const char        *inputptr;
+    void              *scanner;
+    char              *scan_ptr;
+    char               scan_buf[MAX_STRING_LEN];
+    char               scan_del;
+
+    /* pools for result and temporary usage */
+    apr_pool_t        *pool;
+    apr_pool_t        *ptemp;
+
+    /* The created parse tree */
+    ap_expr           *expr;
+
+    const char        *error;
+    const char        *error2;
+    unsigned           flags;
+
+    /*
+     * The function to use to lookup provider functions for variables
+     * and funtctions
+     */
+    ap_expr_lookup_fn   *lookup_fn;
+} ap_expr_parse_ctx;
+
+/* flex/bison functions */
+int  ap_expr_yyparse(ap_expr_parse_ctx *context);
+void ap_expr_yyerror(ap_expr_parse_ctx *context, char *err);
+int  ap_expr_yylex_init(void **scanner);
+int  ap_expr_yylex_destroy(void *scanner);
+void ap_expr_yyset_extra(ap_expr_parse_ctx *context, void *scanner);
+
+/* create a parse tree node */
+ap_expr *ap_expr_make(ap_expr_node_op op, const void *arg1, const void *arg2,
+                        ap_expr_parse_ctx *ctx);
+/* create parse tree node for the string-returning function 'name' */
+ap_expr *ap_expr_str_func_make(const char *name, const ap_expr *arg,
+                               ap_expr_parse_ctx *ctx);
+/* create parse tree node for the list-returning function 'name' */
+ap_expr *ap_expr_list_func_make(const char *name, const ap_expr *arg,
+                                ap_expr_parse_ctx *ctx);
+/* create parse tree node for the variable 'name' */
+ap_expr *ap_expr_var_make(const char *name, ap_expr_parse_ctx *ctx);
+/* create parse tree node for the unary operator 'name' */
+ap_expr *ap_expr_unary_op_make(const char *name, const ap_expr *arg,
+                               ap_expr_parse_ctx *ctx);
+/* create parse tree node for the binary operator 'name' */
+ap_expr *ap_expr_binary_op_make(const char *name, const ap_expr *arg1,
+                                const ap_expr *arg2, ap_expr_parse_ctx *ctx);
+
+
+#endif /* __AP_EXPR_PRIVATE_H__ */
+/** @} */
+
similarity index 65%
rename from modules/ssl/ssl_expr_scan.c
rename to server/util_expr_scan.c
index 1151692ea6cdc15972bdb0e7da986718127e48ad..86e7a39eee03798f65552b7323bccc8088c49087 100644 (file)
@@ -1,6 +1,6 @@
-#line 2 "ssl_expr_scan.c"
+#line 2 "util_expr_scan.c"
 
-#line 4 "ssl_expr_scan.c"
+#line 4 "util_expr_scan.c"
 
 #define  YY_INT_ALIGNED short int
 
@@ -153,7 +153,7 @@ typedef void* yyscan_t;
 #define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
 
 /* Special action meaning "start processing a new file". */
-#define YY_NEW_FILE ssl_expr_yyrestart(yyin ,yyscanner )
+#define YY_NEW_FILE ap_expr_yyrestart(yyin ,yyscanner )
 
 #define YY_END_OF_BUFFER_CHAR 0
 
@@ -263,7 +263,7 @@ struct yy_buffer_state
         * possible backing-up.
         *
         * When we actually see the EOF, we change the status to "new"
-        * (via ssl_expr_yyrestart()), so that the user can continue scanning by
+        * (via ap_expr_yyrestart()), so that the user can continue scanning by
         * just pointing yyin at a new input file.
         */
 #define YY_BUFFER_EOF_PENDING 2
@@ -286,36 +286,36 @@ struct yy_buffer_state
  */
 #define YY_CURRENT_BUFFER_LVALUE yyg->yy_buffer_stack[yyg->yy_buffer_stack_top]
 
-void ssl_expr_yyrestart (FILE *input_file ,yyscan_t yyscanner );
-void ssl_expr_yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner );
-YY_BUFFER_STATE ssl_expr_yy_create_buffer (FILE *file,int size ,yyscan_t yyscanner );
-void ssl_expr_yy_delete_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner );
-void ssl_expr_yy_flush_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner );
-void ssl_expr_yypush_buffer_state (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner );
-void ssl_expr_yypop_buffer_state (yyscan_t yyscanner );
+void ap_expr_yyrestart (FILE *input_file ,yyscan_t yyscanner );
+void ap_expr_yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner );
+YY_BUFFER_STATE ap_expr_yy_create_buffer (FILE *file,int size ,yyscan_t yyscanner );
+void ap_expr_yy_delete_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner );
+void ap_expr_yy_flush_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner );
+void ap_expr_yypush_buffer_state (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner );
+void ap_expr_yypop_buffer_state (yyscan_t yyscanner );
 
-static void ssl_expr_yyensure_buffer_stack (yyscan_t yyscanner );
-static void ssl_expr_yy_load_buffer_state (yyscan_t yyscanner );
-static void ssl_expr_yy_init_buffer (YY_BUFFER_STATE b,FILE *file ,yyscan_t yyscanner );
+static void ap_expr_yyensure_buffer_stack (yyscan_t yyscanner );
+static void ap_expr_yy_load_buffer_state (yyscan_t yyscanner );
+static void ap_expr_yy_init_buffer (YY_BUFFER_STATE b,FILE *file ,yyscan_t yyscanner );
 
-#define YY_FLUSH_BUFFER ssl_expr_yy_flush_buffer(YY_CURRENT_BUFFER ,yyscanner)
+#define YY_FLUSH_BUFFER ap_expr_yy_flush_buffer(YY_CURRENT_BUFFER ,yyscanner)
 
-YY_BUFFER_STATE ssl_expr_yy_scan_buffer (char *base,yy_size_t size ,yyscan_t yyscanner );
-YY_BUFFER_STATE ssl_expr_yy_scan_string (yyconst char *yy_str ,yyscan_t yyscanner );
-YY_BUFFER_STATE ssl_expr_yy_scan_bytes (yyconst char *bytes,int len ,yyscan_t yyscanner );
+YY_BUFFER_STATE ap_expr_yy_scan_buffer (char *base,yy_size_t size ,yyscan_t yyscanner );
+YY_BUFFER_STATE ap_expr_yy_scan_string (yyconst char *yy_str ,yyscan_t yyscanner );
+YY_BUFFER_STATE ap_expr_yy_scan_bytes (yyconst char *bytes,int len ,yyscan_t yyscanner );
 
-void *ssl_expr_yyalloc (yy_size_t ,yyscan_t yyscanner );
-void *ssl_expr_yyrealloc (void *,yy_size_t ,yyscan_t yyscanner );
-void ssl_expr_yyfree (void * ,yyscan_t yyscanner );
+void *ap_expr_yyalloc (yy_size_t ,yyscan_t yyscanner );
+void *ap_expr_yyrealloc (void *,yy_size_t ,yyscan_t yyscanner );
+void ap_expr_yyfree (void * ,yyscan_t yyscanner );
 
-#define yy_new_buffer ssl_expr_yy_create_buffer
+#define yy_new_buffer ap_expr_yy_create_buffer
 
 #define yy_set_interactive(is_interactive) \
        { \
        if ( ! YY_CURRENT_BUFFER ){ \
-        ssl_expr_yyensure_buffer_stack (yyscanner); \
+        ap_expr_yyensure_buffer_stack (yyscanner); \
                YY_CURRENT_BUFFER_LVALUE =    \
-            ssl_expr_yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); \
+            ap_expr_yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); \
        } \
        YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \
        }
@@ -323,9 +323,9 @@ void ssl_expr_yyfree (void * ,yyscan_t yyscanner );
 #define yy_set_bol(at_bol) \
        { \
        if ( ! YY_CURRENT_BUFFER ){\
-        ssl_expr_yyensure_buffer_stack (yyscanner); \
+        ap_expr_yyensure_buffer_stack (yyscanner); \
                YY_CURRENT_BUFFER_LVALUE =    \
-            ssl_expr_yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); \
+            ap_expr_yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); \
        } \
        YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \
        }
@@ -334,7 +334,7 @@ void ssl_expr_yyfree (void * ,yyscan_t yyscanner );
 
 /* Begin user sect3 */
 
-#define ssl_expr_yywrap(n) 1
+#define ap_expr_yywrap(n) 1
 #define YY_SKIP_YYWRAP
 
 typedef unsigned char YY_CHAR;
@@ -358,8 +358,8 @@ static void yy_fatal_error (yyconst char msg[] ,yyscan_t yyscanner );
        *yy_cp = '\0'; \
        yyg->yy_c_buf_p = yy_cp;
 
-#define YY_NUM_RULES 47
-#define YY_END_OF_BUFFER 48
+#define YY_NUM_RULES 65
+#define YY_END_OF_BUFFER 66
 /* This struct is not used in this scanner,
    but its presence is necessary. */
 struct yy_trans_info
@@ -367,19 +367,21 @@ struct yy_trans_info
        flex_int32_t yy_verify;
        flex_int32_t yy_nxt;
        };
-static yyconst flex_int16_t yy_accept[97] =
+static yyconst flex_int16_t yy_accept[119] =
     {   0,
-        0,    0,    0,    0,    0,    0,    0,    0,   48,   46,
-        1,   38,    2,   46,   44,   24,   46,   28,   45,   45,
-       45,   45,   45,   45,   45,   45,   45,   45,   45,   45,
-       46,   13,    4,    3,   14,   16,   18,   17,    1,   22,
-       32,   34,   44,   26,   20,   31,   30,   45,   45,   45,
-       19,   45,   45,   29,   27,   39,   25,   23,   15,   15,
-       21,   45,   35,   45,   36,   13,   12,    5,    6,   10,
-       11,    7,    8,    9,   45,   33,   45,   45,   37,   45,
-        5,    6,   45,   45,   41,   42,    5,   45,   43,   45,
-       45,   45,   45,   45,   40,    0
-
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+        0,    0,   66,   64,    1,   41,    2,   64,   64,   63,
+       64,   42,   24,   61,   30,   28,   32,   62,   62,   62,
+       62,   62,   62,   62,   62,   62,   62,   62,   64,   13,
+        4,    3,   16,   65,   16,   21,    4,   20,   18,   19,
+       65,   15,   22,   25,   27,   26,    1,   29,   35,   17,
+       37,   61,   57,   57,   57,   57,   57,   57,   31,   28,
+       34,   33,   62,   62,   55,   62,   53,   52,   56,   51,
+       50,   23,   23,   54,   62,   38,   62,   39,   13,   14,
+       12,    5,    6,   10,   11,    7,    8,    9,   18,   58,
+
+       44,   46,   48,   43,   47,   49,   45,   36,   62,   40,
+       62,    5,    6,   62,   59,    5,   60,    0
     } ;
 
 static yyconst flex_int32_t yy_ec[256] =
@@ -387,17 +389,17 @@ static yyconst flex_int32_t yy_ec[256] =
         1,    1,    1,    1,    1,    1,    1,    1,    2,    3,
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    2,    4,    5,    1,    1,    1,    6,    1,    1,
-        1,    1,    1,    1,    7,    1,    1,    8,    8,    8,
-        8,    8,    8,    8,    8,    9,    9,    7,    1,   10,
-       11,   12,    1,    1,   13,   13,   13,   13,   14,   13,
-       13,   13,   15,   13,   13,   16,   13,   13,   13,   17,
-       13,   18,   19,   20,   13,   13,   13,   21,   13,   13,
-        1,   22,    1,    1,    7,    1,   23,   24,   13,   25,
-
-       26,   27,   28,   13,   29,   13,   13,   30,   31,   32,
-       33,   17,   34,   35,   36,   37,   38,   13,   13,   21,
-       13,   13,    1,   39,    1,   40,    1,    1,    1,    1,
+        1,    2,    4,    5,    6,    6,    7,    8,    5,    9,
+        9,    1,    1,   10,   11,   12,   13,   14,   14,   14,
+       14,   14,   14,   14,   14,   15,   15,   16,    6,   17,
+       18,   19,    6,    1,   20,   20,   20,   20,   20,   20,
+       20,   20,   20,   20,   20,   20,   20,   20,   20,   20,
+       20,   20,   20,   20,   20,   20,   20,   20,   20,   20,
+        1,   21,    1,    6,   22,    1,   23,   24,   20,   25,
+
+       26,   27,   28,   20,   29,   20,   20,   30,   31,   32,
+       33,   20,   34,   35,   36,   37,   38,   20,   20,   20,
+       20,   20,   39,   40,   41,   42,    1,    1,    1,    1,
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
@@ -414,100 +416,125 @@ static yyconst flex_int32_t yy_ec[256] =
         1,    1,    1,    1,    1
     } ;
 
-static yyconst flex_int32_t yy_meta[41] =
+static yyconst flex_int32_t yy_meta[43] =
     {   0,
-        1,    1,    2,    1,    3,    1,    4,    4,    4,    1,
-        1,    1,    4,    4,    4,    4,    4,    4,    4,    4,
-        4,    3,    4,    4,    4,    4,    4,    4,    4,    4,
-        4,    4,    4,    4,    4,    4,    4,    4,    1,    1
+        1,    1,    2,    1,    2,    1,    2,    1,    1,    1,
+        1,    1,    1,    3,    3,    1,    1,    1,    1,    3,
+        2,    3,    3,    3,    3,    3,    3,    3,    3,    3,
+        3,    3,    3,    3,    3,    3,    3,    3,    1,    1,
+        2,    1
     } ;
 
-static yyconst flex_int16_t yy_base[104] =
+static yyconst flex_int16_t yy_base[128] =
     {   0,
-        0,    0,   38,   39,    0,    0,  101,  100,  128,  174,
-       43,   36,  174,  121,   40,  115,   39,  114,    0,   37,
-       92,   89,   29,   27,   90,   28,   79,   29,   82,   81,
-       76,    0,  174,  174,  112,  174,  174,  174,   54,  174,
-      174,  174,   58,  174,  174,  174,  174,    0,   45,   87,
-        0,   81,   80,    0,    0,    0,    0,    0,  174,    0,
-        0,   71,    0,   69,  174,    0,  174,   60,   64,  174,
-      174,  174,  174,  174,   52,    0,   70,   79,    0,   78,
-       66,   69,   68,   74,    0,    0,   84,   78,    0,   66,
-       72,   80,   77,   77,    0,  174,  149,  153,  157,   94,
-
-      161,  165,  169
+        0,    0,   40,   41,   82,    0,  122,  123,    0,    0,
+      138,  133,  161,  260,   47,   33,  260,  121,  151,  260,
+      151,  260,  260,   38,  140,   36,  139,    0,  124,  121,
+      131,   29,  121,   30,  180,   31,  117,  116,  110,    0,
+      260,  260,  110,  207,  260,  260,  260,  260,    0,  260,
+      260,  260,  260,  260,  260,  260,   56,  260,  260,  260,
+      260,   54,    0,  114,   34,  115,   37,  120,  260,  260,
+      260,  260,    0,  120,    0,  112,    0,    0,    0,    0,
+        0,  260,    0,    0,  104,    0,  102,  260,    0,  260,
+      260,   58,   62,  260,  260,  260,  260,  260,    0,  260,
+
+      260,  260,  260,  260,  260,  260,  260,    0,  103,    0,
+      112,   65,  117,  111,    0,  119,    0,  260,  244,  247,
+      250,  133,  132,  253,  256,   67,   62
     } ;
 
-static yyconst flex_int16_t yy_def[104] =
+static yyconst flex_int16_t yy_def[128] =
     {   0,
-       96,    1,   97,   97,   98,   98,   99,   99,   96,   96,
-       96,   96,   96,   96,   96,   96,   96,   96,  100,  100,
-      100,  100,  100,  100,  100,  100,  101,  100,  100,  100,
-       96,  102,   96,   96,  103,   96,   96,   96,   96,   96,
-       96,   96,   96,   96,   96,   96,   96,  100,  100,  100,
-      100,  100,  100,  100,  100,  100,  100,  100,   96,  100,
-      100,  100,  100,  100,   96,  102,   96,   96,   96,   96,
-       96,   96,   96,   96,  100,  100,  100,  100,  100,  100,
-       96,   96,  100,  100,  100,  100,   96,  100,  100,  100,
-      100,  100,  100,  100,  100,    0,   96,   96,   96,   96,
-
-       96,   96,   96
+      118,    1,  119,  119,  118,    5,  119,  119,  120,  120,
+      121,  121,  118,  118,  118,  118,  118,  118,  118,  118,
+      122,  118,  118,  118,  118,  118,  118,  123,  123,  123,
+      123,  123,  123,  123,  123,  123,  123,  123,  118,  124,
+      118,  118,  118,  125,  118,  118,  118,  118,  126,  118,
+      118,  118,  118,  118,  118,  118,  118,  118,  118,  118,
+      118,  118,  127,  127,  127,  127,  127,  127,  118,  118,
+      118,  118,  123,  123,  123,  123,  123,  123,  123,  123,
+      123,  118,  123,  123,  123,  123,  123,  118,  124,  118,
+      118,  118,  118,  118,  118,  118,  118,  118,  126,  118,
+
+      118,  118,  118,  118,  118,  118,  118,  123,  123,  123,
+      123,  118,  118,  123,  123,  118,  123,    0,  118,  118,
+      118,  118,  118,  118,  118,  118,  118
     } ;
 
-static yyconst flex_int16_t yy_nxt[215] =
+static yyconst flex_int16_t yy_nxt[303] =
     {   0,
-       10,   11,   11,   12,   13,   14,   10,   15,   15,   16,
-       17,   18,   19,   19,   19,   19,   20,   19,   19,   19,
-       19,   10,   21,   19,   19,   22,   23,   24,   25,   26,
-       27,   28,   29,   19,   19,   19,   30,   19,   31,   10,
-       33,   33,   34,   34,   39,   39,   40,   43,   43,   45,
-       49,   52,   54,   57,   61,   39,   39,   53,   75,   35,
-       35,   62,   49,   55,   58,   43,   43,   81,   82,   83,
-       75,   82,   82,   87,   82,   41,   82,   82,   46,   59,
-       59,   88,   59,   59,   59,   91,   83,   92,   59,   59,
-       59,   82,   82,   88,   93,   94,   95,   48,   90,   89,
-
-       59,   92,   91,   86,   85,   84,   80,   79,   93,   78,
-       77,   76,   94,   95,   65,   64,   63,   59,   59,   68,
-       69,   56,   51,   50,   47,   44,   42,   96,   38,   38,
-       96,   96,   96,   96,   96,   70,   96,   96,   71,   96,
-       96,   96,   96,   72,   96,   96,   73,   96,   74,   32,
-       32,   32,   32,   36,   36,   36,   36,   37,   37,   37,
-       37,   60,   96,   60,   60,   66,   96,   96,   66,   67,
-       67,   67,   67,    9,   96,   96,   96,   96,   96,   96,
-       96,   96,   96,   96,   96,   96,   96,   96,   96,   96,
-       96,   96,   96,   96,   96,   96,   96,   96,   96,   96,
-
-       96,   96,   96,   96,   96,   96,   96,   96,   96,   96,
-       96,   96,   96,   96
+       14,   15,   15,   16,   17,   14,   18,   19,   20,   20,
+       21,   22,   23,   24,   24,   20,   25,   26,   27,   28,
+       14,   14,   29,   28,   28,   30,   31,   32,   33,   34,
+       35,   36,   37,   28,   28,   28,   38,   28,   20,   39,
+       20,   14,   41,   41,   42,   42,   43,   43,   57,   57,
+       58,   62,   62,   70,   77,   80,   84,   57,   57,  102,
+       44,   44,  105,   85,  100,   78,   81,   62,   62,   99,
+      103,  112,  113,  106,   59,  113,  113,   71,  116,  113,
+       45,   45,   46,   46,   47,   46,   46,   46,   46,   46,
+       46,   46,   46,   46,   46,   46,   46,   48,   46,   46,
+
+       46,   49,   46,   46,   49,   49,   49,   49,   49,   49,
+       49,   49,   49,   49,   49,   49,   49,   49,   49,   49,
+       46,   46,   50,   46,   41,   41,   51,   51,   52,   52,
+      113,  113,  113,  113,   73,   63,  117,  115,  114,  111,
+      110,  109,   44,   44,  108,  107,  104,  101,   90,   88,
+       87,   86,   79,   76,   75,   74,   72,   69,   61,   60,
+      118,   56,   53,   53,   62,   62,   56,  118,  118,  118,
+      118,  118,  118,  118,  118,  118,   64,  118,   65,   66,
+       67,  118,   68,   82,   82,   82,   82,  118,  118,   82,
+       82,   82,   82,  118,  118,   82,  118,  118,  118,  118,
+
+      118,   83,  118,  118,  118,  118,  118,  118,  118,  118,
+      118,  118,  118,  118,  118,  118,  118,  118,  118,   82,
+       92,   93,  118,  118,  118,  118,  118,  118,  118,  118,
+       94,  118,  118,   95,  118,  118,  118,  118,   96,  118,
+      118,   97,  118,   98,   40,   40,   40,   54,   54,   54,
+       55,   55,   55,   89,  118,   89,   91,   91,   91,   13,
+      118,  118,  118,  118,  118,  118,  118,  118,  118,  118,
+      118,  118,  118,  118,  118,  118,  118,  118,  118,  118,
+      118,  118,  118,  118,  118,  118,  118,  118,  118,  118,
+      118,  118,  118,  118,  118,  118,  118,  118,  118,  118,
+
+      118,  118
     } ;
 
-static yyconst flex_int16_t yy_chk[215] =
+static yyconst flex_int16_t yy_chk[303] =
     {   0,
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        3,    4,    3,    4,   11,   11,   12,   15,   15,   17,
-       20,   23,   24,   26,   28,   39,   39,   23,   49,    3,
-        4,   28,   20,   24,   26,   43,   43,   68,   68,   75,
-       49,   69,   69,   81,   81,   12,   82,   82,   17,   27,
-       27,   83,   27,   27,   27,   90,   75,   91,   27,   27,
-       27,   87,   87,   83,   92,   93,   94,  100,   88,   84,
-
-       27,   91,   90,   80,   78,   77,   64,   62,   92,   53,
-       52,   50,   93,   94,   31,   30,   29,   27,   27,   35,
-       35,   25,   22,   21,   18,   16,   14,    9,    8,    7,
-        0,    0,    0,    0,    0,   35,    0,    0,   35,    0,
-        0,    0,    0,   35,    0,    0,   35,    0,   35,   97,
-       97,   97,   97,   98,   98,   98,   98,   99,   99,   99,
-       99,  101,    0,  101,  101,  102,    0,    0,  102,  103,
-      103,  103,  103,   96,   96,   96,   96,   96,   96,   96,
-       96,   96,   96,   96,   96,   96,   96,   96,   96,   96,
-       96,   96,   96,   96,   96,   96,   96,   96,   96,   96,
-
-       96,   96,   96,   96,   96,   96,   96,   96,   96,   96,
-       96,   96,   96,   96
+        1,    1,    3,    4,    3,    4,    3,    4,   15,   15,
+       16,   24,   24,   26,   32,   34,   36,   57,   57,   65,
+        3,    4,   67,   36,  127,   32,   34,   62,   62,  126,
+       65,   92,   92,   67,   16,   93,   93,   26,  112,  112,
+        3,    4,    5,    5,    5,    5,    5,    5,    5,    5,
+        5,    5,    5,    5,    5,    5,    5,    5,    5,    5,
+
+        5,    5,    5,    5,    5,    5,    5,    5,    5,    5,
+        5,    5,    5,    5,    5,    5,    5,    5,    5,    5,
+        5,    5,    5,    5,    7,    8,    7,    8,    7,    8,
+      113,  113,  116,  116,  123,  122,  114,  111,  109,   87,
+       85,   76,    7,    8,   74,   68,   66,   64,   43,   39,
+       38,   37,   33,   31,   30,   29,   27,   25,   19,   18,
+       13,   12,    7,    8,   21,   21,   11,    0,    0,    0,
+        0,    0,    0,    0,    0,    0,   21,    0,   21,   21,
+       21,    0,   21,   35,   35,   35,   35,    0,    0,   35,
+       35,   35,   35,    0,    0,   35,    0,    0,    0,    0,
+
+        0,   35,    0,    0,    0,    0,    0,    0,    0,    0,
+        0,    0,    0,    0,    0,    0,    0,    0,    0,   35,
+       44,   44,    0,    0,    0,    0,    0,    0,    0,    0,
+       44,    0,    0,   44,    0,    0,    0,    0,   44,    0,
+        0,   44,    0,   44,  119,  119,  119,  120,  120,  120,
+      121,  121,  121,  124,    0,  124,  125,  125,  125,  118,
+      118,  118,  118,  118,  118,  118,  118,  118,  118,  118,
+      118,  118,  118,  118,  118,  118,  118,  118,  118,  118,
+      118,  118,  118,  118,  118,  118,  118,  118,  118,  118,
+      118,  118,  118,  118,  118,  118,  118,  118,  118,  118,
+
+      118,  118
     } ;
 
 /* The intent behind this definition is that it'll catch
@@ -517,7 +544,7 @@ static yyconst flex_int16_t yy_chk[215] =
 #define yymore() yymore_used_but_not_detected
 #define YY_MORE_ADJ 0
 #define YY_RESTORE_YY_MORE_OFFSET
-#line 1 "ssl_expr_scan.l"
+#line 1 "util_expr_scan.l"
 /* Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
  * this work for additional information regarding copyright ownership.
@@ -533,18 +560,9 @@ static yyconst flex_int16_t yy_chk[215] =
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-/*                      _             _ 
- *  _ __ ___   ___   __| |    ___ ___| |  
- * | '_ ` _ \ / _ \ / _` |   / __/ __| |  
- * | | | | | | (_) | (_| |   \__ \__ \ | mod_ssl - Apache Interface to OpenSSL
- * |_| |_| |_|\___/ \__,_|___|___/___/_| http://www.modssl.org/
- *                      |_____|         
- *  ssl_expr_scan.l
- *  Expression Scanner
+/*
+ *  ap_expr_scan.l, based on ssl_expr_scan.l from mod_ssl
  */
-/* ``Killing for peace is 
-like fucking for virginity.''
--- Unknown  */
 /*  _________________________________________________________________
 **
 **  Expression Scanner
@@ -553,11 +571,11 @@ like fucking for virginity.''
 #define YY_NO_INPUT 1
 
 
-#line 49 "ssl_expr_scan.l"
-#include "ssl_private.h"
 
-#include "ssl_expr_parse.h"
-#include "ssl_expr.h"
+
+#line 43 "util_expr_scan.l"
+#include "util_expr_private.h"
+#include "util_expr_parse.h"
 
 #undef  YY_INPUT
 #define YY_INPUT(buf,result,max_size)                       \
@@ -574,14 +592,22 @@ like fucking for virginity.''
     }                                                       \
 }
 
-#define MAX_STR_LEN 2048
-#define YY_EXTRA_TYPE ssl_expr_info_type*
-#line 580 "ssl_expr_scan.c"
+#define YY_EXTRA_TYPE ap_expr_parse_ctx*
+
+#define PERROR(msg) yyextra->error2 = msg ; return ERROR;
+
+#define str_ptr     (yyextra->scan_ptr)
+#define str_buf     (yyextra->scan_buf)
+#define str_del     (yyextra->scan_del)
+
+#line 604 "util_expr_scan.c"
 
 #define INITIAL 0
 #define str 1
-#define regex 2
-#define regex_flags 3
+#define var 2
+#define vararg 3
+#define regex 4
+#define regex_flags 5
 
 #ifndef YY_NO_UNISTD_H
 /* Special case for "unistd.h", since it is non-ANSI. We include it way
@@ -637,42 +663,42 @@ static int yy_init_globals (yyscan_t yyscanner );
      * from bison output in section 1.*/
     #    define yylval yyg->yylval_r
     
-int ssl_expr_yylex_init (yyscan_t* scanner);
+int ap_expr_yylex_init (yyscan_t* scanner);
 
-int ssl_expr_yylex_init_extra (YY_EXTRA_TYPE user_defined,yyscan_t* scanner);
+int ap_expr_yylex_init_extra (YY_EXTRA_TYPE user_defined,yyscan_t* scanner);
 
 /* Accessor methods to globals.
    These are made visible to non-reentrant scanners for convenience. */
 
-int ssl_expr_yylex_destroy (yyscan_t yyscanner );
+int ap_expr_yylex_destroy (yyscan_t yyscanner );
 
-int ssl_expr_yyget_debug (yyscan_t yyscanner );
+int ap_expr_yyget_debug (yyscan_t yyscanner );
 
-void ssl_expr_yyset_debug (int debug_flag ,yyscan_t yyscanner );
+void ap_expr_yyset_debug (int debug_flag ,yyscan_t yyscanner );
 
-YY_EXTRA_TYPE ssl_expr_yyget_extra (yyscan_t yyscanner );
+YY_EXTRA_TYPE ap_expr_yyget_extra (yyscan_t yyscanner );
 
-void ssl_expr_yyset_extra (YY_EXTRA_TYPE user_defined ,yyscan_t yyscanner );
+void ap_expr_yyset_extra (YY_EXTRA_TYPE user_defined ,yyscan_t yyscanner );
 
-FILE *ssl_expr_yyget_in (yyscan_t yyscanner );
+FILE *ap_expr_yyget_in (yyscan_t yyscanner );
 
-void ssl_expr_yyset_in  (FILE * in_str ,yyscan_t yyscanner );
+void ap_expr_yyset_in  (FILE * in_str ,yyscan_t yyscanner );
 
-FILE *ssl_expr_yyget_out (yyscan_t yyscanner );
+FILE *ap_expr_yyget_out (yyscan_t yyscanner );
 
-void ssl_expr_yyset_out  (FILE * out_str ,yyscan_t yyscanner );
+void ap_expr_yyset_out  (FILE * out_str ,yyscan_t yyscanner );
 
-int ssl_expr_yyget_leng (yyscan_t yyscanner );
+int ap_expr_yyget_leng (yyscan_t yyscanner );
 
-char *ssl_expr_yyget_text (yyscan_t yyscanner );
+char *ap_expr_yyget_text (yyscan_t yyscanner );
 
-int ssl_expr_yyget_lineno (yyscan_t yyscanner );
+int ap_expr_yyget_lineno (yyscan_t yyscanner );
 
-void ssl_expr_yyset_lineno (int line_number ,yyscan_t yyscanner );
+void ap_expr_yyset_lineno (int line_number ,yyscan_t yyscanner );
 
-YYSTYPE * ssl_expr_yyget_lval (yyscan_t yyscanner );
+YYSTYPE * ap_expr_yyget_lval (yyscan_t yyscanner );
 
-void ssl_expr_yyset_lval (YYSTYPE * yylval_param ,yyscan_t yyscanner );
+void ap_expr_yyset_lval (YYSTYPE * yylval_param ,yyscan_t yyscanner );
 
 /* Macros after this point can all be overridden by user definitions in
  * section 1.
@@ -680,9 +706,9 @@ void ssl_expr_yyset_lval (YYSTYPE * yylval_param ,yyscan_t yyscanner );
 
 #ifndef YY_SKIP_YYWRAP
 #ifdef __cplusplus
-extern "C" int ssl_expr_yywrap (yyscan_t yyscanner );
+extern "C" int ap_expr_yywrap (yyscan_t yyscanner );
 #else
-extern int ssl_expr_yywrap (yyscan_t yyscanner );
+extern int ap_expr_yywrap (yyscan_t yyscanner );
 #endif
 #endif
 
@@ -704,6 +730,12 @@ static int input (yyscan_t yyscanner );
 
 #endif
 
+    static void yy_push_state (int new_state ,yyscan_t yyscanner);
+    
+    static void yy_pop_state (yyscan_t yyscanner );
+    
+    static int yy_top_state (yyscan_t yyscanner );
+    
 /* Amount of stuff to slurp up with each read. */
 #ifndef YY_READ_BUF_SIZE
 #ifdef __ia64__
@@ -784,10 +816,10 @@ static int input (yyscan_t yyscanner );
 #ifndef YY_DECL
 #define YY_DECL_IS_OURS 1
 
-extern int ssl_expr_yylex \
+extern int ap_expr_yylex \
                (YYSTYPE * yylval_param ,yyscan_t yyscanner);
 
-#define YY_DECL int ssl_expr_yylex \
+#define YY_DECL int ap_expr_yylex \
                (YYSTYPE * yylval_param , yyscan_t yyscanner)
 #endif /* !YY_DECL */
 
@@ -815,19 +847,17 @@ YY_DECL
        register int yy_act;
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
 
-#line 74 "ssl_expr_scan.l"
+#line 72 "util_expr_scan.l"
 
-  
-  char  caStr[MAX_STR_LEN];
-  char *cpStr = NULL;
-  char  caRegex[MAX_STR_LEN];
-  char *cpRegex = NULL;
-  char  cRegexDel = NUL;
+
+  char  regex_buf[MAX_STRING_LEN];
+  char *regex_ptr = NULL;
+  char  regex_del = '\0';
 
  /*
   * Whitespaces
   */
-#line 831 "ssl_expr_scan.c"
+#line 861 "util_expr_scan.c"
 
     yylval = yylval_param;
 
@@ -849,12 +879,12 @@ YY_DECL
                        yyout = stdout;
 
                if ( ! YY_CURRENT_BUFFER ) {
-                       ssl_expr_yyensure_buffer_stack (yyscanner);
+                       ap_expr_yyensure_buffer_stack (yyscanner);
                        YY_CURRENT_BUFFER_LVALUE =
-                               ssl_expr_yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner);
+                               ap_expr_yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner);
                }
 
-               ssl_expr_yy_load_buffer_state(yyscanner );
+               ap_expr_yy_load_buffer_state(yyscanner );
                }
 
        while ( 1 )             /* loops until end-of-file is reached */
@@ -882,13 +912,13 @@ yy_match:
                        while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
                                {
                                yy_current_state = (int) yy_def[yy_current_state];
-                               if ( yy_current_state >= 97 )
+                               if ( yy_current_state >= 119 )
                                        yy_c = yy_meta[(unsigned int) yy_c];
                                }
                        yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
                        ++yy_cp;
                        }
-               while ( yy_current_state != 96 );
+               while ( yy_current_state != 118 );
                yy_cp = yyg->yy_last_accepting_cpos;
                yy_current_state = yyg->yy_last_accepting_state;
 
@@ -911,303 +941,474 @@ do_action:      /* This label is used only to access EOF actions. */
 case 1:
 /* rule 1 can match eol */
 YY_RULE_SETUP
-#line 85 "ssl_expr_scan.l"
+#line 81 "util_expr_scan.l"
 { 
     /* NOP */
 }
        YY_BREAK
 /*
-  * C-style strings ("...")
+  * strings ("..." and '...')
   */
 case 2:
 YY_RULE_SETUP
-#line 92 "ssl_expr_scan.l"
+#line 88 "util_expr_scan.l"
 {
-    cpStr = caStr;
+    str_ptr = str_buf;
+    str_del = yytext[0];
     BEGIN(str);
+    return T_STR_BEGIN;
 }
        YY_BREAK
 case 3:
 YY_RULE_SETUP
-#line 96 "ssl_expr_scan.l"
+#line 94 "util_expr_scan.l"
 {
-    BEGIN(INITIAL);
-    *cpStr = NUL;
-    yylval->cpVal = apr_pstrdup(yyextra->pool, caStr);
-    return T_STRING;
+    if (yytext[0] == str_del) {
+        if (YY_START == var) {
+            PERROR("Unterminated variable in string");
+        }
+        else if (str_ptr == str_buf) {
+            BEGIN(INITIAL);
+            return T_STR_END;
+        }
+        else {
+            /* return what we have so far and scan delimiter again */
+            *str_ptr = '\0';
+            yylval->cpVal = apr_pstrdup(yyextra->pool, str_buf);
+            yyless(0);
+            str_ptr = str_buf;
+            return T_STRING;
+        }
+    }
+    else {
+        *str_ptr++ = yytext[0];
+    }
 }
        YY_BREAK
 case 4:
 /* rule 4 can match eol */
 YY_RULE_SETUP
-#line 102 "ssl_expr_scan.l"
+#line 116 "util_expr_scan.l"
 {
-    ssl_expr_yyerror(yyextra, "Unterminated string");
+    PERROR("Unterminated string or variable");
+}
+       YY_BREAK
+case YY_STATE_EOF(str):
+case YY_STATE_EOF(var):
+case YY_STATE_EOF(vararg):
+#line 119 "util_expr_scan.l"
+{
+    PERROR("Unterminated string or variable");
 }
        YY_BREAK
 case 5:
 YY_RULE_SETUP
-#line 105 "ssl_expr_scan.l"
+#line 122 "util_expr_scan.l"
 {
     int result;
 
     (void)sscanf(yytext+1, "%o", &result);
-    if (result > 0xff)
-        ssl_expr_yyerror(yyextra, "Escape sequence out of bound");
-    else
-        *cpStr++ = result;
+    if (result > 0xff) {
+        PERROR("Escape sequence out of bound");
+    }
+    else {
+        *str_ptr++ = result;
+    }
 }
        YY_BREAK
 case 6:
 YY_RULE_SETUP
-#line 114 "ssl_expr_scan.l"
+#line 133 "util_expr_scan.l"
 {
-    ssl_expr_yyerror(yyextra, "Bad escape sequence");
+    PERROR("Bad escape sequence");
 }
        YY_BREAK
 case 7:
 YY_RULE_SETUP
-#line 117 "ssl_expr_scan.l"
-{ *cpStr++ = '\n'; }
+#line 136 "util_expr_scan.l"
+{ *str_ptr++ = '\n'; }
        YY_BREAK
 case 8:
 YY_RULE_SETUP
-#line 118 "ssl_expr_scan.l"
-{ *cpStr++ = '\r'; }
+#line 137 "util_expr_scan.l"
+{ *str_ptr++ = '\r'; }
        YY_BREAK
 case 9:
 YY_RULE_SETUP
-#line 119 "ssl_expr_scan.l"
-{ *cpStr++ = '\t'; }
+#line 138 "util_expr_scan.l"
+{ *str_ptr++ = '\t'; }
        YY_BREAK
 case 10:
 YY_RULE_SETUP
-#line 120 "ssl_expr_scan.l"
-{ *cpStr++ = '\b'; }
+#line 139 "util_expr_scan.l"
+{ *str_ptr++ = '\b'; }
        YY_BREAK
 case 11:
 YY_RULE_SETUP
-#line 121 "ssl_expr_scan.l"
-{ *cpStr++ = '\f'; }
+#line 140 "util_expr_scan.l"
+{ *str_ptr++ = '\f'; }
        YY_BREAK
 case 12:
 /* rule 12 can match eol */
 YY_RULE_SETUP
-#line 122 "ssl_expr_scan.l"
+#line 141 "util_expr_scan.l"
 {
-    *cpStr++ = yytext[1];
+    *str_ptr++ = yytext[1];
 }
        YY_BREAK
 case 13:
 YY_RULE_SETUP
-#line 125 "ssl_expr_scan.l"
+#line 145 "util_expr_scan.l"
 {
     char *cp = yytext;
-    while (*cp != NUL)
-        *cpStr++ = *cp++;
+    while (*cp != '\0')
+        *str_ptr++ = *cp++;
 }
        YY_BREAK
+/* variable inside string */
 case 14:
 YY_RULE_SETUP
-#line 130 "ssl_expr_scan.l"
+#line 152 "util_expr_scan.l"
 {
-    *cpStr++ = yytext[1];
+    if (str_ptr != str_buf) {
+        /* return what we have so far and scan '%{' again */
+        *str_ptr = '\0';
+        yylval->cpVal = apr_pstrdup(yyextra->pool, str_buf);
+        yyless(0);
+        str_ptr = str_buf;
+        return T_STRING;
+    }
+    else {
+        yy_push_state(var, yyscanner);
+        return T_VAR_BEGIN;
+    }
 }
        YY_BREAK
-/*
-  * Regular Expression
-  */
 case 15:
 YY_RULE_SETUP
-#line 137 "ssl_expr_scan.l"
+#line 167 "util_expr_scan.l"
 {
-    cRegexDel = yytext[1];
-    cpRegex = caRegex;
-    BEGIN(regex);
+     *str_ptr++ = yytext[0];
 }
        YY_BREAK
 case 16:
-/* rule 16 can match eol */
 YY_RULE_SETUP
-#line 142 "ssl_expr_scan.l"
+#line 171 "util_expr_scan.l"
 {
-    if (yytext[0] == cRegexDel) {
-        *cpRegex = NUL;
-        BEGIN(regex_flags);
-    }
-    else {
-        *cpRegex++ = yytext[0];
-    }
+     *str_ptr++ = yytext[0];
 }
        YY_BREAK
 case 17:
 YY_RULE_SETUP
-#line 151 "ssl_expr_scan.l"
+#line 175 "util_expr_scan.l"
 {
-    yylval->cpVal = apr_pstrdup(yyextra->pool, caRegex);
-    BEGIN(INITIAL);
-    return T_REGEX_I;
+    yy_push_state(var, yyscanner);
+    return T_VAR_BEGIN;
 }
        YY_BREAK
+/*
+  * fixed name variable expansion %{XXX} and function call in %{func:arg} syntax
+  */
 case 18:
-/* rule 18 can match eol */
 YY_RULE_SETUP
-#line 156 "ssl_expr_scan.l"
-{
-    yylval->cpVal = apr_pstrdup(yyextra->pool, caRegex);
-    yyless(0);
-    BEGIN(INITIAL);
-    return T_REGEX;
-}
-       YY_BREAK
-case YY_STATE_EOF(regex_flags):
-#line 162 "ssl_expr_scan.l"
+#line 183 "util_expr_scan.l"
 {
-    yylval->cpVal = apr_pstrdup(yyextra->pool, caRegex);
-    BEGIN(INITIAL);
-    return T_REGEX;
+    yylval->cpVal = apr_pstrdup(yyextra->pool, yytext);
+    return T_ID;
 }
        YY_BREAK
-/*
-  * Operators
-  */
 case 19:
 YY_RULE_SETUP
-#line 171 "ssl_expr_scan.l"
-{ return T_OP_EQ; }
+#line 188 "util_expr_scan.l"
+{
+    yy_pop_state(yyscanner);
+    return T_VAR_END;
+}
        YY_BREAK
 case 20:
 YY_RULE_SETUP
-#line 172 "ssl_expr_scan.l"
-{ return T_OP_EQ; }
+#line 193 "util_expr_scan.l"
+{
+    BEGIN(vararg);
+    return yytext[0];
+}
        YY_BREAK
 case 21:
+/* rule 21 can match eol */
 YY_RULE_SETUP
-#line 173 "ssl_expr_scan.l"
-{ return T_OP_NE; }
+#line 198 "util_expr_scan.l"
+{
+    char c[2] = { yytext[0], '\0' };
+    char *msg = apr_psprintf(yyextra->pool,
+                             "Invalid character in variable name '%s'", c);
+    PERROR(msg);
+}
        YY_BREAK
 case 22:
 YY_RULE_SETUP
-#line 174 "ssl_expr_scan.l"
-{ return T_OP_NE; }
+#line 205 "util_expr_scan.l"
+{
+    if (str_ptr != str_buf) {
+        /* return what we have so far and scan '}' again */
+        *str_ptr = '\0';
+        yylval->cpVal = apr_pstrdup(yyextra->pool, str_buf);
+        str_ptr = str_buf;
+        yyless(0);
+        return T_STRING;
+    }
+    else {
+        yy_pop_state(yyscanner);
+        return T_VAR_END;
+    }
+}
        YY_BREAK
+/*
+  * Regular Expression
+  */
 case 23:
 YY_RULE_SETUP
-#line 175 "ssl_expr_scan.l"
-{ return T_OP_LT; }
+#line 223 "util_expr_scan.l"
+{
+    regex_del = yytext[1];
+    regex_ptr = regex_buf;
+    BEGIN(regex);
+}
        YY_BREAK
 case 24:
 YY_RULE_SETUP
-#line 176 "ssl_expr_scan.l"
-{ return T_OP_LT; }
+#line 228 "util_expr_scan.l"
+{
+    regex_del = yytext[0];
+    regex_ptr = regex_buf;
+    BEGIN(regex);
+}
        YY_BREAK
 case 25:
+/* rule 25 can match eol */
 YY_RULE_SETUP
-#line 177 "ssl_expr_scan.l"
-{ return T_OP_LE; }
+#line 233 "util_expr_scan.l"
+{
+    if (yytext[0] == regex_del) {
+        *regex_ptr = '\0';
+        BEGIN(regex_flags);
+    }
+    else {
+        *regex_ptr++ = yytext[0];
+    }
+}
        YY_BREAK
 case 26:
 YY_RULE_SETUP
-#line 178 "ssl_expr_scan.l"
-{ return T_OP_LE; }
+#line 242 "util_expr_scan.l"
+{
+    yylval->cpVal = apr_pstrdup(yyextra->pool, regex_buf);
+    BEGIN(INITIAL);
+    return T_REGEX_I;
+}
        YY_BREAK
 case 27:
+/* rule 27 can match eol */
 YY_RULE_SETUP
-#line 179 "ssl_expr_scan.l"
-{ return T_OP_GT; }
+#line 247 "util_expr_scan.l"
+{
+    yylval->cpVal = apr_pstrdup(yyextra->pool, regex_buf);
+    yyless(0);
+    BEGIN(INITIAL);
+    return T_REGEX;
+}
        YY_BREAK
+case YY_STATE_EOF(regex_flags):
+#line 253 "util_expr_scan.l"
+{
+    yylval->cpVal = apr_pstrdup(yyextra->pool, regex_buf);
+    BEGIN(INITIAL);
+    return T_REGEX;
+}
+       YY_BREAK
+/*
+  * Operators
+  */
 case 28:
 YY_RULE_SETUP
-#line 180 "ssl_expr_scan.l"
-{ return T_OP_GT; }
+#line 262 "util_expr_scan.l"
+{ return T_OP_STR_EQ; }
        YY_BREAK
 case 29:
 YY_RULE_SETUP
-#line 181 "ssl_expr_scan.l"
-{ return T_OP_GE; }
+#line 263 "util_expr_scan.l"
+{ return T_OP_STR_NE; }
        YY_BREAK
 case 30:
 YY_RULE_SETUP
-#line 182 "ssl_expr_scan.l"
-{ return T_OP_GE; }
+#line 264 "util_expr_scan.l"
+{ return T_OP_STR_LT; }
        YY_BREAK
 case 31:
 YY_RULE_SETUP
-#line 183 "ssl_expr_scan.l"
-{ return T_OP_REG; }
+#line 265 "util_expr_scan.l"
+{ return T_OP_STR_LE; }
        YY_BREAK
 case 32:
 YY_RULE_SETUP
-#line 184 "ssl_expr_scan.l"
-{ return T_OP_NRE; }
+#line 266 "util_expr_scan.l"
+{ return T_OP_STR_GT; }
        YY_BREAK
 case 33:
 YY_RULE_SETUP
-#line 185 "ssl_expr_scan.l"
-{ return T_OP_AND; }
+#line 267 "util_expr_scan.l"
+{ return T_OP_STR_GE; }
        YY_BREAK
 case 34:
 YY_RULE_SETUP
-#line 186 "ssl_expr_scan.l"
-{ return T_OP_AND; }
+#line 268 "util_expr_scan.l"
+{ return T_OP_REG; }
        YY_BREAK
 case 35:
 YY_RULE_SETUP
-#line 187 "ssl_expr_scan.l"
-{ return T_OP_OR; }
+#line 269 "util_expr_scan.l"
+{ return T_OP_NRE; }
        YY_BREAK
 case 36:
 YY_RULE_SETUP
-#line 188 "ssl_expr_scan.l"
-{ return T_OP_OR; }
+#line 270 "util_expr_scan.l"
+{ return T_OP_AND; }
        YY_BREAK
 case 37:
 YY_RULE_SETUP
-#line 189 "ssl_expr_scan.l"
-{ return T_OP_NOT; }
+#line 271 "util_expr_scan.l"
+{ return T_OP_AND; }
        YY_BREAK
 case 38:
 YY_RULE_SETUP
-#line 190 "ssl_expr_scan.l"
-{ return T_OP_NOT; }
+#line 272 "util_expr_scan.l"
+{ return T_OP_OR; }
        YY_BREAK
 case 39:
 YY_RULE_SETUP
-#line 191 "ssl_expr_scan.l"
-{ return T_OP_IN; }
+#line 273 "util_expr_scan.l"
+{ return T_OP_OR; }
        YY_BREAK
 case 40:
 YY_RULE_SETUP
-#line 192 "ssl_expr_scan.l"
-{ return T_OP_PEEREXTLIST; }
+#line 274 "util_expr_scan.l"
+{ return T_OP_NOT; }
        YY_BREAK
-/*
-  * Functions
-  */
 case 41:
 YY_RULE_SETUP
-#line 197 "ssl_expr_scan.l"
-{ return T_FUNC_FILE; }
+#line 275 "util_expr_scan.l"
+{ return T_OP_NOT; }
+       YY_BREAK
+case 42:
+YY_RULE_SETUP
+#line 276 "util_expr_scan.l"
+{ return T_OP_CONCAT; }
+       YY_BREAK
+case 43:
+YY_RULE_SETUP
+#line 277 "util_expr_scan.l"
+{ return T_OP_IN; }
+       YY_BREAK
+case 44:
+YY_RULE_SETUP
+#line 278 "util_expr_scan.l"
+{ return T_OP_EQ; }
+       YY_BREAK
+case 45:
+YY_RULE_SETUP
+#line 279 "util_expr_scan.l"
+{ return T_OP_NE; }
+       YY_BREAK
+case 46:
+YY_RULE_SETUP
+#line 280 "util_expr_scan.l"
+{ return T_OP_GE; }
+       YY_BREAK
+case 47:
+YY_RULE_SETUP
+#line 281 "util_expr_scan.l"
+{ return T_OP_LE; }
+       YY_BREAK
+case 48:
+YY_RULE_SETUP
+#line 282 "util_expr_scan.l"
+{ return T_OP_GT; }
+       YY_BREAK
+case 49:
+YY_RULE_SETUP
+#line 283 "util_expr_scan.l"
+{ return T_OP_LT; }
+       YY_BREAK
+/* for compatibility with ssl_expr */
+case 50:
+YY_RULE_SETUP
+#line 286 "util_expr_scan.l"
+{ return T_OP_LT; }
+       YY_BREAK
+case 51:
+YY_RULE_SETUP
+#line 287 "util_expr_scan.l"
+{ return T_OP_LE; }
+       YY_BREAK
+case 52:
+YY_RULE_SETUP
+#line 288 "util_expr_scan.l"
+{ return T_OP_GT; }
+       YY_BREAK
+case 53:
+YY_RULE_SETUP
+#line 289 "util_expr_scan.l"
+{ return T_OP_GE; }
+       YY_BREAK
+case 54:
+YY_RULE_SETUP
+#line 290 "util_expr_scan.l"
+{ return T_OP_NE; }
+       YY_BREAK
+case 55:
+YY_RULE_SETUP
+#line 291 "util_expr_scan.l"
+{ return T_OP_EQ; }
+       YY_BREAK
+case 56:
+YY_RULE_SETUP
+#line 292 "util_expr_scan.l"
+{ return T_OP_IN; }
+       YY_BREAK
+case 57:
+YY_RULE_SETUP
+#line 294 "util_expr_scan.l"
+{
+    yylval->cpVal = apr_pstrdup(yyextra->pool, yytext + 1);
+    return T_OP_UNARY;
+}
+       YY_BREAK
+case 58:
+YY_RULE_SETUP
+#line 299 "util_expr_scan.l"
+{
+    yylval->cpVal = apr_pstrdup(yyextra->pool, yytext + 1);
+    return T_OP_BINARY;
+}
        YY_BREAK
 /*
   * Specials
   */
-case 42:
+case 59:
 YY_RULE_SETUP
-#line 202 "ssl_expr_scan.l"
+#line 307 "util_expr_scan.l"
 { return T_TRUE; }
        YY_BREAK
-case 43:
+case 60:
 YY_RULE_SETUP
-#line 203 "ssl_expr_scan.l"
+#line 308 "util_expr_scan.l"
 { return T_FALSE; }
        YY_BREAK
 /*
   * Digits
   */
-case 44:
+case 61:
 YY_RULE_SETUP
-#line 208 "ssl_expr_scan.l"
+#line 313 "util_expr_scan.l"
 {
     yylval->cpVal = apr_pstrdup(yyextra->pool, yytext);
     return T_DIGIT;
@@ -1216,33 +1417,44 @@ YY_RULE_SETUP
 /*
   * Identifiers
   */
-case 45:
+case 62:
 YY_RULE_SETUP
-#line 216 "ssl_expr_scan.l"
+#line 321 "util_expr_scan.l"
 {
     yylval->cpVal = apr_pstrdup(yyextra->pool, yytext);
     return T_ID;
 }
        YY_BREAK
 /*
-  * Anything else is returned as is...
+  * These are parts of the grammar and are returned as is
   */
-case 46:
-/* rule 46 can match eol */
+case 63:
 YY_RULE_SETUP
-#line 224 "ssl_expr_scan.l"
-{ 
+#line 329 "util_expr_scan.l"
+{
     return yytext[0];
 }
        YY_BREAK
-case 47:
+/*
+  * Anything else is an error
+  */
+case 64:
+/* rule 64 can match eol */
 YY_RULE_SETUP
-#line 228 "ssl_expr_scan.l"
+#line 336 "util_expr_scan.l"
+{
+    char c[2] = { yytext[0], '\0' };
+    char *msg = apr_psprintf(yyextra->pool, "Parse error near '%s'", c);
+    PERROR(msg);
+}
+       YY_BREAK
+case 65:
+YY_RULE_SETUP
+#line 342 "util_expr_scan.l"
 YY_FATAL_ERROR( "flex scanner jammed" );
        YY_BREAK
-#line 1244 "ssl_expr_scan.c"
+#line 1457 "util_expr_scan.c"
 case YY_STATE_EOF(INITIAL):
-case YY_STATE_EOF(str):
 case YY_STATE_EOF(regex):
        yyterminate();
 
@@ -1260,7 +1472,7 @@ case YY_STATE_EOF(regex):
                        /* We're scanning a new file or input source.  It's
                         * possible that this happened because the user
                         * just pointed yyin at a new source and called
-                        * ssl_expr_yylex().  If so, then we have to assure
+                        * ap_expr_yylex().  If so, then we have to assure
                         * consistency between YY_CURRENT_BUFFER and our
                         * globals.  Here is the right place to do so, because
                         * this is the first action (other than possibly a
@@ -1321,7 +1533,7 @@ case YY_STATE_EOF(regex):
                                {
                                yyg->yy_did_buffer_switch_on_eof = 0;
 
-                               if ( ssl_expr_yywrap(yyscanner ) )
+                               if ( ap_expr_yywrap(yyscanner ) )
                                        {
                                        /* Note: because we've taken care in
                                         * yy_get_next_buffer() to have set up
@@ -1374,7 +1586,7 @@ case YY_STATE_EOF(regex):
                        "fatal flex scanner internal error--no action found" );
        } /* end of action switch */
                } /* end of scanning one token */
-} /* end of ssl_expr_yylex */
+} /* end of ap_expr_yylex */
 
 /* yy_get_next_buffer - try to read in a new buffer
  *
@@ -1453,7 +1665,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
 
                                b->yy_ch_buf = (char *)
                                        /* Include room in for 2 EOB chars. */
-                                       ssl_expr_yyrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2 ,yyscanner );
+                                       ap_expr_yyrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2 ,yyscanner );
                                }
                        else
                                /* Can't grow it, we don't own it. */
@@ -1485,7 +1697,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
                if ( number_to_move == YY_MORE_ADJ )
                        {
                        ret_val = EOB_ACT_END_OF_FILE;
-                       ssl_expr_yyrestart(yyin  ,yyscanner);
+                       ap_expr_yyrestart(yyin  ,yyscanner);
                        }
 
                else
@@ -1502,7 +1714,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
        if ((yy_size_t) (yyg->yy_n_chars + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) {
                /* Extend the array by 50%, plus the number we really need. */
                yy_size_t new_size = yyg->yy_n_chars + number_to_move + (yyg->yy_n_chars >> 1);
-               YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) ssl_expr_yyrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size ,yyscanner );
+               YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) ap_expr_yyrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size ,yyscanner );
                if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
                        YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" );
        }
@@ -1537,7 +1749,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
                while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
                        {
                        yy_current_state = (int) yy_def[yy_current_state];
-                       if ( yy_current_state >= 97 )
+                       if ( yy_current_state >= 119 )
                                yy_c = yy_meta[(unsigned int) yy_c];
                        }
                yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
@@ -1566,11 +1778,11 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
        while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
                {
                yy_current_state = (int) yy_def[yy_current_state];
-               if ( yy_current_state >= 97 )
+               if ( yy_current_state >= 119 )
                        yy_c = yy_meta[(unsigned int) yy_c];
                }
        yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
-       yy_is_jam = (yy_current_state == 96);
+       yy_is_jam = (yy_current_state == 118);
 
        return yy_is_jam ? 0 : yy_current_state;
 }
@@ -1617,13 +1829,13 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
                                         */
 
                                        /* Reset buffer status. */
-                                       ssl_expr_yyrestart(yyin ,yyscanner);
+                                       ap_expr_yyrestart(yyin ,yyscanner);
 
                                        /*FALLTHROUGH*/
 
                                case EOB_ACT_END_OF_FILE:
                                        {
-                                       if ( ssl_expr_yywrap(yyscanner ) )
+                                       if ( ap_expr_yywrap(yyscanner ) )
                                                return EOF;
 
                                        if ( ! yyg->yy_did_buffer_switch_on_eof )
@@ -1655,34 +1867,34 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
  * @param yyscanner The scanner object.
  * @note This function does not reset the start condition to @c INITIAL .
  */
-    void ssl_expr_yyrestart  (FILE * input_file , yyscan_t yyscanner)
+    void ap_expr_yyrestart  (FILE * input_file , yyscan_t yyscanner)
 {
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
 
        if ( ! YY_CURRENT_BUFFER ){
-        ssl_expr_yyensure_buffer_stack (yyscanner);
+        ap_expr_yyensure_buffer_stack (yyscanner);
                YY_CURRENT_BUFFER_LVALUE =
-            ssl_expr_yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner);
+            ap_expr_yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner);
        }
 
-       ssl_expr_yy_init_buffer(YY_CURRENT_BUFFER,input_file ,yyscanner);
-       ssl_expr_yy_load_buffer_state(yyscanner );
+       ap_expr_yy_init_buffer(YY_CURRENT_BUFFER,input_file ,yyscanner);
+       ap_expr_yy_load_buffer_state(yyscanner );
 }
 
 /** Switch to a different input buffer.
  * @param new_buffer The new input buffer.
  * @param yyscanner The scanner object.
  */
-    void ssl_expr_yy_switch_to_buffer  (YY_BUFFER_STATE  new_buffer , yyscan_t yyscanner)
+    void ap_expr_yy_switch_to_buffer  (YY_BUFFER_STATE  new_buffer , yyscan_t yyscanner)
 {
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
 
        /* TODO. We should be able to replace this entire function body
         * with
-        *              ssl_expr_yypop_buffer_state();
-        *              ssl_expr_yypush_buffer_state(new_buffer);
+        *              ap_expr_yypop_buffer_state();
+        *              ap_expr_yypush_buffer_state(new_buffer);
      */
-       ssl_expr_yyensure_buffer_stack (yyscanner);
+       ap_expr_yyensure_buffer_stack (yyscanner);
        if ( YY_CURRENT_BUFFER == new_buffer )
                return;
 
@@ -1695,17 +1907,17 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
                }
 
        YY_CURRENT_BUFFER_LVALUE = new_buffer;
-       ssl_expr_yy_load_buffer_state(yyscanner );
+       ap_expr_yy_load_buffer_state(yyscanner );
 
        /* We don't actually know whether we did this switch during
-        * EOF (ssl_expr_yywrap()) processing, but the only time this flag
-        * is looked at is after ssl_expr_yywrap() is called, so it's safe
+        * EOF (ap_expr_yywrap()) processing, but the only time this flag
+        * is looked at is after ap_expr_yywrap() is called, so it's safe
         * to go ahead and always set it.
         */
        yyg->yy_did_buffer_switch_on_eof = 1;
 }
 
-static void ssl_expr_yy_load_buffer_state  (yyscan_t yyscanner)
+static void ap_expr_yy_load_buffer_state  (yyscan_t yyscanner)
 {
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
        yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
@@ -1720,35 +1932,35 @@ static void ssl_expr_yy_load_buffer_state  (yyscan_t yyscanner)
  * @param yyscanner The scanner object.
  * @return the allocated buffer state.
  */
-    YY_BUFFER_STATE ssl_expr_yy_create_buffer  (FILE * file, int  size , yyscan_t yyscanner)
+    YY_BUFFER_STATE ap_expr_yy_create_buffer  (FILE * file, int  size , yyscan_t yyscanner)
 {
        YY_BUFFER_STATE b;
     
-       b = (YY_BUFFER_STATE) ssl_expr_yyalloc(sizeof( struct yy_buffer_state ) ,yyscanner );
+       b = (YY_BUFFER_STATE) ap_expr_yyalloc(sizeof( struct yy_buffer_state ) ,yyscanner );
        if ( ! b )
-               YY_FATAL_ERROR( "out of dynamic memory in ssl_expr_yy_create_buffer()" );
+               YY_FATAL_ERROR( "out of dynamic memory in ap_expr_yy_create_buffer()" );
 
        b->yy_buf_size = size;
 
        /* yy_ch_buf has to be 2 characters longer than the size given because
         * we need to put in 2 end-of-buffer characters.
         */
-       b->yy_ch_buf = (char *) ssl_expr_yyalloc(b->yy_buf_size + 2 ,yyscanner );
+       b->yy_ch_buf = (char *) ap_expr_yyalloc(b->yy_buf_size + 2 ,yyscanner );
        if ( ! b->yy_ch_buf )
-               YY_FATAL_ERROR( "out of dynamic memory in ssl_expr_yy_create_buffer()" );
+               YY_FATAL_ERROR( "out of dynamic memory in ap_expr_yy_create_buffer()" );
 
        b->yy_is_our_buffer = 1;
 
-       ssl_expr_yy_init_buffer(b,file ,yyscanner);
+       ap_expr_yy_init_buffer(b,file ,yyscanner);
 
        return b;
 }
 
 /** Destroy the buffer.
- * @param b a buffer created with ssl_expr_yy_create_buffer()
+ * @param b a buffer created with ap_expr_yy_create_buffer()
  * @param yyscanner The scanner object.
  */
-    void ssl_expr_yy_delete_buffer (YY_BUFFER_STATE  b , yyscan_t yyscanner)
+    void ap_expr_yy_delete_buffer (YY_BUFFER_STATE  b , yyscan_t yyscanner)
 {
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
 
@@ -1759,28 +1971,28 @@ static void ssl_expr_yy_load_buffer_state  (yyscan_t yyscanner)
                YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0;
 
        if ( b->yy_is_our_buffer )
-               ssl_expr_yyfree((void *) b->yy_ch_buf ,yyscanner );
+               ap_expr_yyfree((void *) b->yy_ch_buf ,yyscanner );
 
-       ssl_expr_yyfree((void *) b ,yyscanner );
+       ap_expr_yyfree((void *) b ,yyscanner );
 }
 
 /* Initializes or reinitializes a buffer.
  * This function is sometimes called more than once on the same buffer,
- * such as during a ssl_expr_yyrestart() or at EOF.
+ * such as during a ap_expr_yyrestart() or at EOF.
  */
-    static void ssl_expr_yy_init_buffer  (YY_BUFFER_STATE  b, FILE * file , yyscan_t yyscanner)
+    static void ap_expr_yy_init_buffer  (YY_BUFFER_STATE  b, FILE * file , yyscan_t yyscanner)
 
 {
        int oerrno = errno;
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
 
-       ssl_expr_yy_flush_buffer(b ,yyscanner);
+       ap_expr_yy_flush_buffer(b ,yyscanner);
 
        b->yy_input_file = file;
        b->yy_fill_buffer = 1;
 
-    /* If b is the current buffer, then ssl_expr_yy_init_buffer was _probably_
-     * called from ssl_expr_yyrestart() or through yy_get_next_buffer.
+    /* If b is the current buffer, then ap_expr_yy_init_buffer was _probably_
+     * called from ap_expr_yyrestart() or through yy_get_next_buffer.
      * In that case, we don't want to reset the lineno or column.
      */
     if (b != YY_CURRENT_BUFFER){
@@ -1797,7 +2009,7 @@ static void ssl_expr_yy_load_buffer_state  (yyscan_t yyscanner)
  * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER.
  * @param yyscanner The scanner object.
  */
-    void ssl_expr_yy_flush_buffer (YY_BUFFER_STATE  b , yyscan_t yyscanner)
+    void ap_expr_yy_flush_buffer (YY_BUFFER_STATE  b , yyscan_t yyscanner)
 {
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
        if ( ! b )
@@ -1818,7 +2030,7 @@ static void ssl_expr_yy_load_buffer_state  (yyscan_t yyscanner)
        b->yy_buffer_status = YY_BUFFER_NEW;
 
        if ( b == YY_CURRENT_BUFFER )
-               ssl_expr_yy_load_buffer_state(yyscanner );
+               ap_expr_yy_load_buffer_state(yyscanner );
 }
 
 /** Pushes the new state onto the stack. The new state becomes
@@ -1827,15 +2039,15 @@ static void ssl_expr_yy_load_buffer_state  (yyscan_t yyscanner)
  *  @param new_buffer The new state.
  *  @param yyscanner The scanner object.
  */
-void ssl_expr_yypush_buffer_state (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner)
+void ap_expr_yypush_buffer_state (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner)
 {
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
        if (new_buffer == NULL)
                return;
 
-       ssl_expr_yyensure_buffer_stack(yyscanner);
+       ap_expr_yyensure_buffer_stack(yyscanner);
 
-       /* This block is copied from ssl_expr_yy_switch_to_buffer. */
+       /* This block is copied from ap_expr_yy_switch_to_buffer. */
        if ( YY_CURRENT_BUFFER )
                {
                /* Flush out information for old buffer. */
@@ -1849,8 +2061,8 @@ void ssl_expr_yypush_buffer_state (YY_BUFFER_STATE new_buffer , yyscan_t yyscann
                yyg->yy_buffer_stack_top++;
        YY_CURRENT_BUFFER_LVALUE = new_buffer;
 
-       /* copied from ssl_expr_yy_switch_to_buffer. */
-       ssl_expr_yy_load_buffer_state(yyscanner );
+       /* copied from ap_expr_yy_switch_to_buffer. */
+       ap_expr_yy_load_buffer_state(yyscanner );
        yyg->yy_did_buffer_switch_on_eof = 1;
 }
 
@@ -1858,19 +2070,19 @@ void ssl_expr_yypush_buffer_state (YY_BUFFER_STATE new_buffer , yyscan_t yyscann
  *  The next element becomes the new top.
  *  @param yyscanner The scanner object.
  */
-void ssl_expr_yypop_buffer_state (yyscan_t yyscanner)
+void ap_expr_yypop_buffer_state (yyscan_t yyscanner)
 {
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
        if (!YY_CURRENT_BUFFER)
                return;
 
-       ssl_expr_yy_delete_buffer(YY_CURRENT_BUFFER ,yyscanner);
+       ap_expr_yy_delete_buffer(YY_CURRENT_BUFFER ,yyscanner);
        YY_CURRENT_BUFFER_LVALUE = NULL;
        if (yyg->yy_buffer_stack_top > 0)
                --yyg->yy_buffer_stack_top;
 
        if (YY_CURRENT_BUFFER) {
-               ssl_expr_yy_load_buffer_state(yyscanner );
+               ap_expr_yy_load_buffer_state(yyscanner );
                yyg->yy_did_buffer_switch_on_eof = 1;
        }
 }
@@ -1878,7 +2090,7 @@ void ssl_expr_yypop_buffer_state (yyscan_t yyscanner)
 /* Allocates the stack if it does not exist.
  *  Guarantees space for at least one push.
  */
-static void ssl_expr_yyensure_buffer_stack (yyscan_t yyscanner)
+static void ap_expr_yyensure_buffer_stack (yyscan_t yyscanner)
 {
        int num_to_alloc;
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
@@ -1890,11 +2102,11 @@ static void ssl_expr_yyensure_buffer_stack (yyscan_t yyscanner)
                 * immediate realloc on the next call.
          */
                num_to_alloc = 1;
-               yyg->yy_buffer_stack = (struct yy_buffer_state**)ssl_expr_yyalloc
+               yyg->yy_buffer_stack = (struct yy_buffer_state**)ap_expr_yyalloc
                                                                (num_to_alloc * sizeof(struct yy_buffer_state*)
                                                                , yyscanner);
                if ( ! yyg->yy_buffer_stack )
-                       YY_FATAL_ERROR( "out of dynamic memory in ssl_expr_yyensure_buffer_stack()" );
+                       YY_FATAL_ERROR( "out of dynamic memory in ap_expr_yyensure_buffer_stack()" );
                                                                  
                memset(yyg->yy_buffer_stack, 0, num_to_alloc * sizeof(struct yy_buffer_state*));
                                
@@ -1909,12 +2121,12 @@ static void ssl_expr_yyensure_buffer_stack (yyscan_t yyscanner)
                int grow_size = 8 /* arbitrary grow size */;
 
                num_to_alloc = yyg->yy_buffer_stack_max + grow_size;
-               yyg->yy_buffer_stack = (struct yy_buffer_state**)ssl_expr_yyrealloc
+               yyg->yy_buffer_stack = (struct yy_buffer_state**)ap_expr_yyrealloc
                                                                (yyg->yy_buffer_stack,
                                                                num_to_alloc * sizeof(struct yy_buffer_state*)
                                                                , yyscanner);
                if ( ! yyg->yy_buffer_stack )
-                       YY_FATAL_ERROR( "out of dynamic memory in ssl_expr_yyensure_buffer_stack()" );
+                       YY_FATAL_ERROR( "out of dynamic memory in ap_expr_yyensure_buffer_stack()" );
 
                /* zero only the new slots.*/
                memset(yyg->yy_buffer_stack + yyg->yy_buffer_stack_max, 0, grow_size * sizeof(struct yy_buffer_state*));
@@ -1928,7 +2140,7 @@ static void ssl_expr_yyensure_buffer_stack (yyscan_t yyscanner)
  * @param yyscanner The scanner object.
  * @return the newly allocated buffer state object. 
  */
-YY_BUFFER_STATE ssl_expr_yy_scan_buffer  (char * base, yy_size_t  size , yyscan_t yyscanner)
+YY_BUFFER_STATE ap_expr_yy_scan_buffer  (char * base, yy_size_t  size , yyscan_t yyscanner)
 {
        YY_BUFFER_STATE b;
     
@@ -1938,9 +2150,9 @@ YY_BUFFER_STATE ssl_expr_yy_scan_buffer  (char * base, yy_size_t  size , yyscan_
                /* They forgot to leave room for the EOB's. */
                return 0;
 
-       b = (YY_BUFFER_STATE) ssl_expr_yyalloc(sizeof( struct yy_buffer_state ) ,yyscanner );
+       b = (YY_BUFFER_STATE) ap_expr_yyalloc(sizeof( struct yy_buffer_state ) ,yyscanner );
        if ( ! b )
-               YY_FATAL_ERROR( "out of dynamic memory in ssl_expr_yy_scan_buffer()" );
+               YY_FATAL_ERROR( "out of dynamic memory in ap_expr_yy_scan_buffer()" );
 
        b->yy_buf_size = size - 2;      /* "- 2" to take care of EOB's */
        b->yy_buf_pos = b->yy_ch_buf = base;
@@ -1952,33 +2164,33 @@ YY_BUFFER_STATE ssl_expr_yy_scan_buffer  (char * base, yy_size_t  size , yyscan_
        b->yy_fill_buffer = 0;
        b->yy_buffer_status = YY_BUFFER_NEW;
 
-       ssl_expr_yy_switch_to_buffer(b ,yyscanner );
+       ap_expr_yy_switch_to_buffer(b ,yyscanner );
 
        return b;
 }
 
-/** Setup the input buffer state to scan a string. The next call to ssl_expr_yylex() will
+/** Setup the input buffer state to scan a string. The next call to ap_expr_yylex() will
  * scan from a @e copy of @a str.
  * @param yystr a NUL-terminated string to scan
  * @param yyscanner The scanner object.
  * @return the newly allocated buffer state object.
  * @note If you want to scan bytes that may contain NUL values, then use
- *       ssl_expr_yy_scan_bytes() instead.
+ *       ap_expr_yy_scan_bytes() instead.
  */
-YY_BUFFER_STATE ssl_expr_yy_scan_string (yyconst char * yystr , yyscan_t yyscanner)
+YY_BUFFER_STATE ap_expr_yy_scan_string (yyconst char * yystr , yyscan_t yyscanner)
 {
     
-       return ssl_expr_yy_scan_bytes(yystr,strlen(yystr) ,yyscanner);
+       return ap_expr_yy_scan_bytes(yystr,strlen(yystr) ,yyscanner);
 }
 
-/** Setup the input buffer state to scan the given bytes. The next call to ssl_expr_yylex() will
+/** Setup the input buffer state to scan the given bytes. The next call to ap_expr_yylex() will
  * scan from a @e copy of @a bytes.
  * @param yybytes the byte buffer to scan
  * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes.
  * @param yyscanner The scanner object.
  * @return the newly allocated buffer state object.
  */
-YY_BUFFER_STATE ssl_expr_yy_scan_bytes  (yyconst char * yybytes, int  _yybytes_len , yyscan_t yyscanner)
+YY_BUFFER_STATE ap_expr_yy_scan_bytes  (yyconst char * yybytes, int  _yybytes_len , yyscan_t yyscanner)
 {
        YY_BUFFER_STATE b;
        char *buf;
@@ -1987,18 +2199,18 @@ YY_BUFFER_STATE ssl_expr_yy_scan_bytes  (yyconst char * yybytes, int  _yybytes_l
     
        /* Get memory for full buffer, including space for trailing EOB's. */
        n = _yybytes_len + 2;
-       buf = (char *) ssl_expr_yyalloc(n ,yyscanner );
+       buf = (char *) ap_expr_yyalloc(n ,yyscanner );
        if ( ! buf )
-               YY_FATAL_ERROR( "out of dynamic memory in ssl_expr_yy_scan_bytes()" );
+               YY_FATAL_ERROR( "out of dynamic memory in ap_expr_yy_scan_bytes()" );
 
        for ( i = 0; i < _yybytes_len; ++i )
                buf[i] = yybytes[i];
 
        buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR;
 
-       b = ssl_expr_yy_scan_buffer(buf,n ,yyscanner);
+       b = ap_expr_yy_scan_buffer(buf,n ,yyscanner);
        if ( ! b )
-               YY_FATAL_ERROR( "bad buffer in ssl_expr_yy_scan_bytes()" );
+               YY_FATAL_ERROR( "bad buffer in ap_expr_yy_scan_bytes()" );
 
        /* It's okay to grow etc. this buffer, and we should throw it
         * away when we're done.
@@ -2008,6 +2220,46 @@ YY_BUFFER_STATE ssl_expr_yy_scan_bytes  (yyconst char * yybytes, int  _yybytes_l
        return b;
 }
 
+    static void yy_push_state (int  new_state , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+       if ( yyg->yy_start_stack_ptr >= yyg->yy_start_stack_depth )
+               {
+               yy_size_t new_size;
+
+               yyg->yy_start_stack_depth += YY_START_STACK_INCR;
+               new_size = yyg->yy_start_stack_depth * sizeof( int );
+
+               if ( ! yyg->yy_start_stack )
+                       yyg->yy_start_stack = (int *) ap_expr_yyalloc(new_size ,yyscanner );
+
+               else
+                       yyg->yy_start_stack = (int *) ap_expr_yyrealloc((void *) yyg->yy_start_stack,new_size ,yyscanner );
+
+               if ( ! yyg->yy_start_stack )
+                       YY_FATAL_ERROR( "out of memory expanding start-condition stack" );
+               }
+
+       yyg->yy_start_stack[yyg->yy_start_stack_ptr++] = YY_START;
+
+       BEGIN(new_state);
+}
+
+    static void yy_pop_state  (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+       if ( --yyg->yy_start_stack_ptr < 0 )
+               YY_FATAL_ERROR( "start-condition stack underflow" );
+
+       BEGIN(yyg->yy_start_stack[yyg->yy_start_stack_ptr]);
+}
+
+    static int yy_top_state  (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+       return yyg->yy_start_stack[yyg->yy_start_stack_ptr - 1];
+}
+
 #ifndef YY_EXIT_FAILURE
 #define YY_EXIT_FAILURE 2
 #endif
@@ -2040,7 +2292,7 @@ static void yy_fatal_error (yyconst char* msg , yyscan_t yyscanner)
 /** Get the user-defined data for this scanner.
  * @param yyscanner The scanner object.
  */
-YY_EXTRA_TYPE ssl_expr_yyget_extra  (yyscan_t yyscanner)
+YY_EXTRA_TYPE ap_expr_yyget_extra  (yyscan_t yyscanner)
 {
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
     return yyextra;
@@ -2049,7 +2301,7 @@ YY_EXTRA_TYPE ssl_expr_yyget_extra  (yyscan_t yyscanner)
 /** Get the current line number.
  * @param yyscanner The scanner object.
  */
-int ssl_expr_yyget_lineno  (yyscan_t yyscanner)
+int ap_expr_yyget_lineno  (yyscan_t yyscanner)
 {
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
     
@@ -2062,7 +2314,7 @@ int ssl_expr_yyget_lineno  (yyscan_t yyscanner)
 /** Get the current column number.
  * @param yyscanner The scanner object.
  */
-int ssl_expr_yyget_column  (yyscan_t yyscanner)
+int ap_expr_yyget_column  (yyscan_t yyscanner)
 {
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
     
@@ -2075,7 +2327,7 @@ int ssl_expr_yyget_column  (yyscan_t yyscanner)
 /** Get the input stream.
  * @param yyscanner The scanner object.
  */
-FILE *ssl_expr_yyget_in  (yyscan_t yyscanner)
+FILE *ap_expr_yyget_in  (yyscan_t yyscanner)
 {
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
     return yyin;
@@ -2084,7 +2336,7 @@ FILE *ssl_expr_yyget_in  (yyscan_t yyscanner)
 /** Get the output stream.
  * @param yyscanner The scanner object.
  */
-FILE *ssl_expr_yyget_out  (yyscan_t yyscanner)
+FILE *ap_expr_yyget_out  (yyscan_t yyscanner)
 {
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
     return yyout;
@@ -2093,7 +2345,7 @@ FILE *ssl_expr_yyget_out  (yyscan_t yyscanner)
 /** Get the length of the current token.
  * @param yyscanner The scanner object.
  */
-int ssl_expr_yyget_leng  (yyscan_t yyscanner)
+int ap_expr_yyget_leng  (yyscan_t yyscanner)
 {
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
     return yyleng;
@@ -2103,7 +2355,7 @@ int ssl_expr_yyget_leng  (yyscan_t yyscanner)
  * @param yyscanner The scanner object.
  */
 
-char *ssl_expr_yyget_text  (yyscan_t yyscanner)
+char *ap_expr_yyget_text  (yyscan_t yyscanner)
 {
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
     return yytext;
@@ -2113,7 +2365,7 @@ char *ssl_expr_yyget_text  (yyscan_t yyscanner)
  * @param user_defined The data to be associated with this scanner.
  * @param yyscanner The scanner object.
  */
-void ssl_expr_yyset_extra (YY_EXTRA_TYPE  user_defined , yyscan_t yyscanner)
+void ap_expr_yyset_extra (YY_EXTRA_TYPE  user_defined , yyscan_t yyscanner)
 {
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
     yyextra = user_defined ;
@@ -2123,13 +2375,13 @@ void ssl_expr_yyset_extra (YY_EXTRA_TYPE  user_defined , yyscan_t yyscanner)
  * @param line_number
  * @param yyscanner The scanner object.
  */
-void ssl_expr_yyset_lineno (int  line_number , yyscan_t yyscanner)
+void ap_expr_yyset_lineno (int  line_number , yyscan_t yyscanner)
 {
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
 
         /* lineno is only valid if an input buffer exists. */
         if (! YY_CURRENT_BUFFER )
-           yy_fatal_error( "ssl_expr_yyset_lineno called with no buffer" , yyscanner); 
+           yy_fatal_error( "ap_expr_yyset_lineno called with no buffer" , yyscanner); 
     
     yylineno = line_number;
 }
@@ -2138,13 +2390,13 @@ void ssl_expr_yyset_lineno (int  line_number , yyscan_t yyscanner)
  * @param line_number
  * @param yyscanner The scanner object.
  */
-void ssl_expr_yyset_column (int  column_no , yyscan_t yyscanner)
+void ap_expr_yyset_column (int  column_no , yyscan_t yyscanner)
 {
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
 
         /* column is only valid if an input buffer exists. */
         if (! YY_CURRENT_BUFFER )
-           yy_fatal_error( "ssl_expr_yyset_column called with no buffer" , yyscanner); 
+           yy_fatal_error( "ap_expr_yyset_column called with no buffer" , yyscanner); 
     
     yycolumn = column_no;
 }
@@ -2153,27 +2405,27 @@ void ssl_expr_yyset_column (int  column_no , yyscan_t yyscanner)
  * input buffer.
  * @param in_str A readable stream.
  * @param yyscanner The scanner object.
- * @see ssl_expr_yy_switch_to_buffer
+ * @see ap_expr_yy_switch_to_buffer
  */
-void ssl_expr_yyset_in (FILE *  in_str , yyscan_t yyscanner)
+void ap_expr_yyset_in (FILE *  in_str , yyscan_t yyscanner)
 {
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
     yyin = in_str ;
 }
 
-void ssl_expr_yyset_out (FILE *  out_str , yyscan_t yyscanner)
+void ap_expr_yyset_out (FILE *  out_str , yyscan_t yyscanner)
 {
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
     yyout = out_str ;
 }
 
-int ssl_expr_yyget_debug  (yyscan_t yyscanner)
+int ap_expr_yyget_debug  (yyscan_t yyscanner)
 {
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
     return yy_flex_debug;
 }
 
-void ssl_expr_yyset_debug (int  bdebug , yyscan_t yyscanner)
+void ap_expr_yyset_debug (int  bdebug , yyscan_t yyscanner)
 {
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
     yy_flex_debug = bdebug ;
@@ -2181,13 +2433,13 @@ void ssl_expr_yyset_debug (int  bdebug , yyscan_t yyscanner)
 
 /* Accessor methods for yylval and yylloc */
 
-YYSTYPE * ssl_expr_yyget_lval  (yyscan_t yyscanner)
+YYSTYPE * ap_expr_yyget_lval  (yyscan_t yyscanner)
 {
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
     return yylval;
 }
 
-void ssl_expr_yyset_lval (YYSTYPE *  yylval_param , yyscan_t yyscanner)
+void ap_expr_yyset_lval (YYSTYPE *  yylval_param , yyscan_t yyscanner)
 {
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
     yylval = yylval_param;
@@ -2195,12 +2447,12 @@ void ssl_expr_yyset_lval (YYSTYPE *  yylval_param , yyscan_t yyscanner)
 
 /* User-visible API */
 
-/* ssl_expr_yylex_init is special because it creates the scanner itself, so it is
+/* ap_expr_yylex_init is special because it creates the scanner itself, so it is
  * the ONLY reentrant function that doesn't take the scanner as the last argument.
  * That's why we explicitly handle the declaration, instead of using our macros.
  */
 
-int ssl_expr_yylex_init(yyscan_t* ptr_yy_globals)
+int ap_expr_yylex_init(yyscan_t* ptr_yy_globals)
 
 {
     if (ptr_yy_globals == NULL){
@@ -2208,7 +2460,7 @@ int ssl_expr_yylex_init(yyscan_t* ptr_yy_globals)
         return 1;
     }
 
-    *ptr_yy_globals = (yyscan_t) ssl_expr_yyalloc ( sizeof( struct yyguts_t ), NULL );
+    *ptr_yy_globals = (yyscan_t) ap_expr_yyalloc ( sizeof( struct yyguts_t ), NULL );
 
     if (*ptr_yy_globals == NULL){
         errno = ENOMEM;
@@ -2221,27 +2473,27 @@ int ssl_expr_yylex_init(yyscan_t* ptr_yy_globals)
     return yy_init_globals ( *ptr_yy_globals );
 }
 
-/* ssl_expr_yylex_init_extra has the same functionality as ssl_expr_yylex_init, but follows the
+/* ap_expr_yylex_init_extra has the same functionality as ap_expr_yylex_init, but follows the
  * convention of taking the scanner as the last argument. Note however, that
  * this is a *pointer* to a scanner, as it will be allocated by this call (and
  * is the reason, too, why this function also must handle its own declaration).
- * The user defined value in the first argument will be available to ssl_expr_yyalloc in
+ * The user defined value in the first argument will be available to ap_expr_yyalloc in
  * the yyextra field.
  */
 
-int ssl_expr_yylex_init_extra(YY_EXTRA_TYPE yy_user_defined,yyscan_t* ptr_yy_globals )
+int ap_expr_yylex_init_extra(YY_EXTRA_TYPE yy_user_defined,yyscan_t* ptr_yy_globals )
 
 {
     struct yyguts_t dummy_yyguts;
 
-    ssl_expr_yyset_extra (yy_user_defined, &dummy_yyguts);
+    ap_expr_yyset_extra (yy_user_defined, &dummy_yyguts);
 
     if (ptr_yy_globals == NULL){
         errno = EINVAL;
         return 1;
     }
        
-    *ptr_yy_globals = (yyscan_t) ssl_expr_yyalloc ( sizeof( struct yyguts_t ), &dummy_yyguts );
+    *ptr_yy_globals = (yyscan_t) ap_expr_yyalloc ( sizeof( struct yyguts_t ), &dummy_yyguts );
        
     if (*ptr_yy_globals == NULL){
         errno = ENOMEM;
@@ -2252,7 +2504,7 @@ int ssl_expr_yylex_init_extra(YY_EXTRA_TYPE yy_user_defined,yyscan_t* ptr_yy_glo
     yy_init_globals. Leave at 0x00 for releases. */
     memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t));
     
-    ssl_expr_yyset_extra (yy_user_defined, *ptr_yy_globals);
+    ap_expr_yyset_extra (yy_user_defined, *ptr_yy_globals);
     
     return yy_init_globals ( *ptr_yy_globals );
 }
@@ -2261,7 +2513,7 @@ static int yy_init_globals (yyscan_t yyscanner)
 {
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
     /* Initialization is the same as for the non-reentrant scanner.
-     * This function is called from ssl_expr_yylex_destroy(), so don't allocate here.
+     * This function is called from ap_expr_yylex_destroy(), so don't allocate here.
      */
 
     yyg->yy_buffer_stack = 0;
@@ -2285,37 +2537,37 @@ static int yy_init_globals (yyscan_t yyscanner)
 #endif
 
     /* For future reference: Set errno on error, since we are called by
-     * ssl_expr_yylex_init()
+     * ap_expr_yylex_init()
      */
     return 0;
 }
 
-/* ssl_expr_yylex_destroy is for both reentrant and non-reentrant scanners. */
-int ssl_expr_yylex_destroy  (yyscan_t yyscanner)
+/* ap_expr_yylex_destroy is for both reentrant and non-reentrant scanners. */
+int ap_expr_yylex_destroy  (yyscan_t yyscanner)
 {
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
 
     /* Pop the buffer stack, destroying each element. */
        while(YY_CURRENT_BUFFER){
-               ssl_expr_yy_delete_buffer(YY_CURRENT_BUFFER ,yyscanner );
+               ap_expr_yy_delete_buffer(YY_CURRENT_BUFFER ,yyscanner );
                YY_CURRENT_BUFFER_LVALUE = NULL;
-               ssl_expr_yypop_buffer_state(yyscanner);
+               ap_expr_yypop_buffer_state(yyscanner);
        }
 
        /* Destroy the stack itself. */
-       ssl_expr_yyfree(yyg->yy_buffer_stack ,yyscanner);
+       ap_expr_yyfree(yyg->yy_buffer_stack ,yyscanner);
        yyg->yy_buffer_stack = NULL;
 
     /* Destroy the start condition stack. */
-        ssl_expr_yyfree(yyg->yy_start_stack ,yyscanner );
+        ap_expr_yyfree(yyg->yy_start_stack ,yyscanner );
         yyg->yy_start_stack = NULL;
 
     /* Reset the globals. This is important in a non-reentrant scanner so the next time
-     * ssl_expr_yylex() is called, initialization will occur. */
+     * ap_expr_yylex() is called, initialization will occur. */
     yy_init_globals( yyscanner);
 
     /* Destroy the main struct (reentrant only). */
-    ssl_expr_yyfree ( yyscanner , yyscanner );
+    ap_expr_yyfree ( yyscanner , yyscanner );
     yyscanner = NULL;
     return 0;
 }
@@ -2344,12 +2596,12 @@ static int yy_flex_strlen (yyconst char * s , yyscan_t yyscanner)
 }
 #endif
 
-void *ssl_expr_yyalloc (yy_size_t  size , yyscan_t yyscanner)
+void *ap_expr_yyalloc (yy_size_t  size , yyscan_t yyscanner)
 {
        return (void *) malloc( size );
 }
 
-void *ssl_expr_yyrealloc  (void * ptr, yy_size_t  size , yyscan_t yyscanner)
+void *ap_expr_yyrealloc  (void * ptr, yy_size_t  size , yyscan_t yyscanner)
 {
        /* The cast to (char *) in the following accommodates both
         * implementations that use char* generic pointers, and those
@@ -2361,14 +2613,14 @@ void *ssl_expr_yyrealloc  (void * ptr, yy_size_t  size , yyscan_t yyscanner)
        return (void *) realloc( (char *) ptr, size );
 }
 
-void ssl_expr_yyfree (void * ptr , yyscan_t yyscanner)
+void ap_expr_yyfree (void * ptr , yyscan_t yyscanner)
 {
-       free( (char *) ptr );   /* see ssl_expr_yyrealloc() for (char *) cast */
+       free( (char *) ptr );   /* see ap_expr_yyrealloc() for (char *) cast */
 }
 
 #define YYTABLES_NAME "yytables"
 
-#line 228 "ssl_expr_scan.l"
+#line 342 "util_expr_scan.l"
 
 
 
diff --git a/server/util_expr_scan.l b/server/util_expr_scan.l
new file mode 100644 (file)
index 0000000..d2840a0
--- /dev/null
@@ -0,0 +1,344 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ *  ap_expr_scan.l, based on ssl_expr_scan.l from mod_ssl
+ */
+
+/*  _________________________________________________________________
+**
+**  Expression Scanner
+**  _________________________________________________________________
+*/
+
+%pointer
+%option batch
+%option never-interactive
+%option nodefault
+%option noyywrap
+%option reentrant
+%option bison-bridge
+%option warn
+%option noinput nounput
+%option stack
+%x str
+%x var
+%x vararg
+%x regex regex_flags
+
+%{
+#include "util_expr_private.h"
+#include "util_expr_parse.h"
+
+#undef  YY_INPUT
+#define YY_INPUT(buf,result,max_size)                       \
+{                                                           \
+    if ((result = MIN(max_size, yyextra->inputbuf           \
+                              + yyextra->inputlen           \
+                              - yyextra->inputptr)) <= 0)   \
+    {                                                       \
+        result = YY_NULL;                                   \
+    }                                                       \
+    else {                                                  \
+        memcpy(buf, yyextra->inputptr, result);             \
+        yyextra->inputptr += result;                        \
+    }                                                       \
+}
+
+#define YY_EXTRA_TYPE ap_expr_parse_ctx*
+
+#define PERROR(msg) yyextra->error2 = msg ; return ERROR;
+
+#define str_ptr     (yyextra->scan_ptr)
+#define str_buf     (yyextra->scan_buf)
+#define str_del     (yyextra->scan_del)
+
+%}
+
+
+%%
+
+  char  regex_buf[MAX_STRING_LEN];
+  char *regex_ptr = NULL;
+  char  regex_del = '\0';
+
+ /*
+  * Whitespaces
+  */
+[ \t\n]+ { 
+    /* NOP */
+}
+
+ /*
+  * strings ("..." and '...')
+  */
+["'] {
+    str_ptr = str_buf;
+    str_del = yytext[0];
+    BEGIN(str);
+    return T_STR_BEGIN;
+}
+<str>["'] {
+    if (yytext[0] == str_del) {
+        if (YY_START == var) {
+            PERROR("Unterminated variable in string");
+        }
+        else if (str_ptr == str_buf) {
+            BEGIN(INITIAL);
+            return T_STR_END;
+        }
+        else {
+            /* return what we have so far and scan delimiter again */
+            *str_ptr = '\0';
+            yylval->cpVal = apr_pstrdup(yyextra->pool, str_buf);
+            yyless(0);
+            str_ptr = str_buf;
+            return T_STRING;
+        }
+    }
+    else {
+        *str_ptr++ = yytext[0];
+    }
+}
+<str,var,vararg>\n {
+    PERROR("Unterminated string or variable");
+}
+<str,var,vararg><<EOF>> {
+    PERROR("Unterminated string or variable");
+}
+<str,vararg>\\[0-7]{1,3} {
+    int result;
+
+    (void)sscanf(yytext+1, "%o", &result);
+    if (result > 0xff) {
+        PERROR("Escape sequence out of bound");
+    }
+    else {
+        *str_ptr++ = result;
+    }
+}
+<str,vararg>\\[0-9]+ {
+    PERROR("Bad escape sequence");
+}
+<str,vararg>\\n { *str_ptr++ = '\n'; }
+<str,vararg>\\r { *str_ptr++ = '\r'; }
+<str,vararg>\\t { *str_ptr++ = '\t'; }
+<str,vararg>\\b { *str_ptr++ = '\b'; }
+<str,vararg>\\f { *str_ptr++ = '\f'; }
+<str,vararg>\\(.|\n) {
+    *str_ptr++ = yytext[1];
+}
+
+<str,vararg>[^\\\n"'%}]+ {
+    char *cp = yytext;
+    while (*cp != '\0')
+        *str_ptr++ = *cp++;
+}
+
+ /* variable inside string */
+<str>%\{ {
+    if (str_ptr != str_buf) {
+        /* return what we have so far and scan '%{' again */
+        *str_ptr = '\0';
+        yylval->cpVal = apr_pstrdup(yyextra->pool, str_buf);
+        yyless(0);
+        str_ptr = str_buf;
+        return T_STRING;
+    }
+    else {
+        yy_push_state(var, yyscanner);
+        return T_VAR_BEGIN;
+    }
+}
+
+<vararg>% {
+     *str_ptr++ = yytext[0];
+}
+
+<str>[%}] {
+     *str_ptr++ = yytext[0];
+}
+
+%\{ {
+    yy_push_state(var, yyscanner);
+    return T_VAR_BEGIN;
+}
+
+ /*
+  * fixed name variable expansion %{XXX} and function call in %{func:arg} syntax
+  */
+<var>[a-zA-Z][a-zA-Z0-9_]* {
+    yylval->cpVal = apr_pstrdup(yyextra->pool, yytext);
+    return T_ID;
+}
+
+<var>\} {
+    yy_pop_state(yyscanner);
+    return T_VAR_END;
+}
+
+<var>: {
+    BEGIN(vararg);
+    return yytext[0];
+}
+
+<var>.|\n {
+    char c[2] = { yytext[0], '\0' };
+    char *msg = apr_psprintf(yyextra->pool,
+                             "Invalid character in variable name '%s'", c);
+    PERROR(msg);
+}
+
+<vararg>\} {
+    if (str_ptr != str_buf) {
+        /* return what we have so far and scan '}' again */
+        *str_ptr = '\0';
+        yylval->cpVal = apr_pstrdup(yyextra->pool, str_buf);
+        str_ptr = str_buf;
+        yyless(0);
+        return T_STRING;
+    }
+    else {
+        yy_pop_state(yyscanner);
+        return T_VAR_END;
+    }
+}
+
+ /*
+  * Regular Expression
+  */
+"m"[/#$%^,;:_\?\|\^\-\!\.\'\"] {
+    regex_del = yytext[1];
+    regex_ptr = regex_buf;
+    BEGIN(regex);
+}
+"/" {
+    regex_del = yytext[0];
+    regex_ptr = regex_buf;
+    BEGIN(regex);
+}
+<regex>.|\n {
+    if (yytext[0] == regex_del) {
+        *regex_ptr = '\0';
+        BEGIN(regex_flags);
+    }
+    else {
+        *regex_ptr++ = yytext[0];
+    }
+}
+<regex_flags>i {
+    yylval->cpVal = apr_pstrdup(yyextra->pool, regex_buf);
+    BEGIN(INITIAL);
+    return T_REGEX_I;
+}
+<regex_flags>.|\n {
+    yylval->cpVal = apr_pstrdup(yyextra->pool, regex_buf);
+    yyless(0);
+    BEGIN(INITIAL);
+    return T_REGEX;
+}
+<regex_flags><<EOF>> {
+    yylval->cpVal = apr_pstrdup(yyextra->pool, regex_buf);
+    BEGIN(INITIAL);
+    return T_REGEX;
+}
+
+ /*
+  * Operators
+  */
+==?   { return T_OP_STR_EQ; }
+"!="  { return T_OP_STR_NE; }
+"<"   { return T_OP_STR_LT; }
+"<="  { return T_OP_STR_LE; }
+">"   { return T_OP_STR_GT; }
+">="  { return T_OP_STR_GE; }
+"=~"  { return T_OP_REG; }
+"!~"  { return T_OP_NRE; }
+"and" { return T_OP_AND; }
+"&&"  { return T_OP_AND; }
+"or"  { return T_OP_OR; }
+"||"  { return T_OP_OR; }
+"not" { return T_OP_NOT; }
+"!"   { return T_OP_NOT; }
+"."   { return T_OP_CONCAT; }
+"-in"  { return T_OP_IN; }
+"-eq"  { return T_OP_EQ; }
+"-ne"  { return T_OP_NE; }
+"-ge"  { return T_OP_GE; }
+"-le"  { return T_OP_LE; }
+"-gt"  { return T_OP_GT; }
+"-lt"  { return T_OP_LT; }
+
+ /* for compatibility with ssl_expr */
+"lt"  { return T_OP_LT; }
+"le"  { return T_OP_LE; }
+"gt"  { return T_OP_GT; }
+"ge"  { return T_OP_GE; }
+"ne"  { return T_OP_NE; }
+"eq"  { return T_OP_EQ; }
+"in"  { return T_OP_IN; }
+
+"-"[a-zA-Z_] {
+    yylval->cpVal = apr_pstrdup(yyextra->pool, yytext + 1);
+    return T_OP_UNARY;
+}
+
+"-"[a-zA-Z_][a-zA-Z_0-9] {
+    yylval->cpVal = apr_pstrdup(yyextra->pool, yytext + 1);
+    return T_OP_BINARY;
+}
+
+ /*
+  * Specials
+  */
+"true"  { return T_TRUE; }
+"false" { return T_FALSE; }
+
+ /*
+  * Digits
+  */
+-?[0-9]+ {
+    yylval->cpVal = apr_pstrdup(yyextra->pool, yytext);
+    return T_DIGIT;
+}
+
+ /*
+  * Identifiers
+  */
+[a-zA-Z][a-zA-Z0-9_]* {
+    yylval->cpVal = apr_pstrdup(yyextra->pool, yytext);
+    return T_ID;
+}
+
+ /*
+  * These are parts of the grammar and are returned as is
+  */
+[(){},:] {
+    return yytext[0];
+}
+
+ /*
+  * Anything else is an error
+  */
+.|\n {
+    char c[2] = { yytext[0], '\0' };
+    char *msg = apr_psprintf(yyextra->pool, "Parse error near '%s'", c);
+    PERROR(msg);
+}
+
+%%
+
+