]> granicus.if.org Git - apache/commitdiff
* ap_exr: Add replace(string, from, to) function.
authorJan Kaluža <jkaluza@apache.org>
Thu, 27 Nov 2014 13:46:11 +0000 (13:46 +0000)
committerJan Kaluža <jkaluza@apache.org>
Thu, 27 Nov 2014 13:46:11 +0000 (13:46 +0000)
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1642154 13f79535-47bb-0310-9956-ffa450edef68

docs/manual/expr.xml
include/ap_expr.h
server/util_expr_eval.c
server/util_expr_parse.y

index e386ff51acbf731781bb7171e38685cc3c0f3b88..abf6fd917b0b3140eacf82cd4de91a3b10149aae 100644 (file)
@@ -136,7 +136,7 @@ variable    ::= "<strong>%{</strong>" varname "<strong>}</strong>"
 
 rebackref   ::= "<strong>$</strong>" [0-9]
 
-function     ::= funcname "<strong>(</strong>" word "<strong>)</strong>"
+function     ::= funcname "<strong>(</strong>" wordlist "<strong>)</strong>"
 
 listfunction ::= listfuncname "<strong>(</strong>" word "<strong>)</strong>"
 </pre>
@@ -526,6 +526,9 @@ listfunction ::= listfuncname "<strong>(</strong>" word "<strong>)</strong>"
     <tr><td><code>ldap</code></td>
         <td>Escape characters as required by LDAP distinguished name escaping
             (RFC4514) and LDAP filter escaping (RFC4515).</td><td></td></tr>
+    <tr><td><code>replace</code></td>
+        <td>replace(string, "from", "to") replaces all occurences of "from"
+            in the string with "to".</td><td></td></tr>
 
     </table>
 
index 55fff36317bffa81d436112dbba41c96941f1f18..a961193f139be2da9657e3dab8ca2b0192381977 100644 (file)
@@ -232,6 +232,16 @@ typedef const char *(ap_expr_string_func_t)(ap_expr_eval_ctx_t *ctx,
                                             const void *data,
                                             const char *arg);
 
+/** String valued function, takes a list argument and returns a string
+ * @param ctx The evaluation context
+ * @param data An opaque context provided by the lookup hook function
+ * @param args The list of string arguments
+ * @return The functions result string, may be NULL for 'empty string'
+ */
+typedef const char *(ap_expr_string_list_func_t)(ap_expr_eval_ctx_t *ctx,
+                                            const void *data,
+                                            const apr_array_header_t *args);
+
 /** 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
@@ -276,7 +286,9 @@ typedef struct {
     const char **err;
 
     /** arg for pre-parsing (only if a simple string).
-     *  For binary ops, this is the right argument. */
+     *  For binary ops, this is the right argument.
+     *  For functions with more arguments, this is the first string
+     *  argument. */
     const char *arg;
 } ap_expr_lookup_parms;
 
index f7c439c627575b614b7243fcce49d1a44e504119..7e914b720d85ae4d5eb6f8b4614c186ddd17562b 100644 (file)
@@ -24,6 +24,7 @@
 #include "http_protocol.h"
 #include "http_request.h"
 #include "ap_provider.h"
+#include "util_varbuf.h"
 #include "util_expr_private.h"
 #include "util_md5.h"
 
@@ -32,6 +33,8 @@
 #include "apr_base64.h"
 #include "apr_sha1.h"
 #include "apr_version.h"
+#include "apr_strings.h"
+#include "apr_strmatch.h"
 #if APR_VERSION_AT_LEAST(1,5,0)
 #include "apr_escape.h"
 #endif
@@ -183,13 +186,29 @@ static const char *ap_expr_eval_string_func(ap_expr_eval_ctx_t *ctx,
                                             const ap_expr_t *info,
                                             const ap_expr_t *arg)
 {
-    ap_expr_string_func_t *func = (ap_expr_string_func_t *)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(info->node_arg1 != NULL);
     AP_DEBUG_ASSERT(data != NULL);
-    return (*func)(ctx, data, ap_expr_eval_word(ctx, arg));
+    if (arg->node_op == op_ListElement) {
+        /* Evaluate the list elements and store them in apr_array_header. */
+        ap_expr_string_list_func_t *func = (ap_expr_string_list_func_t *)info->node_arg1;
+        apr_array_header_t *args = apr_array_make(ctx->p, 1, sizeof(char *));
+        do {
+            const ap_expr_t *val = arg->node_arg1;
+            const char **new = apr_array_push(args);
+            *new = ap_expr_eval_word(ctx, val);
+
+            arg = arg->node_arg2;
+        } while (arg != NULL);
+
+        return (*func)(ctx, data, args);
+    }
+    else {
+        ap_expr_string_func_t *func = (ap_expr_string_func_t *)info->node_arg1;
+        return (*func)(ctx, data, ap_expr_eval_word(ctx, arg));
+    }
 }
 
 static int intstrcmp(const char *s1, const char *s2)
@@ -443,7 +462,27 @@ static ap_expr_t *ap_expr_info_make(int type, const char *name,
     parms.func  = &info->node_arg1;
     parms.data  = &info->node_arg2;
     parms.err   = &ctx->error2;
-    parms.arg   = (arg && arg->node_op == op_String) ? arg->node_arg1 : NULL;
+    parms.arg   = NULL;
+    if (arg) {
+        switch(arg->node_op) {
+            case op_String:
+                parms.arg = arg->node_arg1;
+                break;
+            case op_ListElement:
+                do {
+                    const ap_expr_t *val = arg->node_arg1;
+                    if (val->node_op == op_String) {
+                        parms.arg = val->node_arg1;
+                    }
+                    arg = arg->node_arg2;
+                } while (arg != NULL);
+                break;
+            default:
+                break;
+        }
+    }
+                        ap_log_error(APLOG_MARK, APLOG_ERR, 0, 0,
+                                    "sss %s", parms.arg);
     if (ctx->lookup_fn(&parms) != OK)
         return NULL;
     return info;
@@ -1071,6 +1110,59 @@ static const char *ldap_func(ap_expr_eval_ctx_t *ctx, const void *data,
 }
 #endif
 
+static int replace_func_parse_arg(ap_expr_lookup_parms *parms)
+{
+    const char *original = parms->arg;
+    const apr_strmatch_pattern *pattern;
+
+    if (!parms->arg) {
+        *parms->err = apr_psprintf(parms->ptemp, "replace() function needs "
+                                   "exactly 3 arguments");
+        return !OK;
+    }
+    pattern = apr_strmatch_precompile(parms->pool, original, 0);
+    *parms->data = pattern;
+    return OK;
+}
+
+static const char *replace_func(ap_expr_eval_ctx_t *ctx, const void *data,
+                               const apr_array_header_t *args)
+{
+    char *buff, *original, *replacement;
+    struct ap_varbuf vb;
+    apr_size_t repl_len;
+    const char *repl;
+    apr_size_t bytes;
+    apr_size_t len;
+    const apr_strmatch_pattern *pattern = data;
+    if (args->nelts != 3) {
+        *ctx->err = apr_psprintf(ctx->p, "replace() function needs "
+                                 "exactly 3 arguments");
+        return "";
+    }
+
+    buff = APR_ARRAY_IDX(args, 2, char *);
+    original = APR_ARRAY_IDX(args, 1, char *);
+    replacement = APR_ARRAY_IDX(args, 0, char *);
+    repl_len = strlen(replacement);
+    bytes = strlen(buff);
+
+    ap_varbuf_init(ctx->p, &vb, 0);
+    vb.strlen = 0;
+    
+    while ((repl = apr_strmatch(pattern, buff, bytes))) {
+        len = (apr_size_t) (repl - buff);
+        ap_varbuf_strmemcat(&vb, buff, len);
+        ap_varbuf_strmemcat(&vb, replacement, repl_len);
+
+        len += repl_len;
+        bytes -= len;
+        buff += len;
+    }
+
+    return ap_varbuf_pdup(ctx->p, &vb, NULL, 0, buff, bytes, &len);
+}
+
 #define MAX_FILE_SIZE 10*1024*1024
 static const char *file_func(ap_expr_eval_ctx_t *ctx, const void *data,
                              char *arg)
@@ -1657,6 +1749,7 @@ static const struct expr_provider_single string_func_providers[] = {
 #if APR_VERSION_AT_LEAST(1,6,0)
     { ldap_func,            "ldap",           NULL, 0 },
 #endif
+    { replace_func,         "replace",        replace_func_parse_arg, 0 },
     { NULL, NULL, NULL}
 };
 
index a389410b7fdaebf819c7b7adfb55b3dfdab3ffab..9e02602139ecbe8af6b9be4e28d62097b0bd62ab 100644 (file)
@@ -205,6 +205,7 @@ lstfunccall : T_ID '(' word ')' { $$ = ap_expr_list_func_make($1, $3, ctx); }
             ;
 
 strfunccall : T_ID '(' word ')' { $$ = ap_expr_str_func_make($1, $3, ctx); }
+            | T_ID '(' words ')' { $$ = ap_expr_str_func_make($1, $3, ctx); }
             ;
 
 %%