#include "lib.h"
#include "var-expand-private.h"
#include "expansion.h"
+#include "dregex.h"
#include "wildcard-match.h"
-#include <regex.h>
-
enum var_expand_if_op {
OP_UNKNOWN,
OP_NUM_EQ,
enum var_expand_if_op op, const struct var_expand_parameter *p_rhs,
bool *result_r, const char **error_r)
{
- bool neg = FALSE;
if (op < OP_STR_EQ) {
intmax_t a;
intmax_t b;
return -1;
}
+ bool neg ATTR_UNUSED = FALSE;
+
switch (op) {
case OP_STR_EQ:
*result_r = strcmp(lhs,rhs) == 0;
case OP_STR_REGEXP: {
int ec;
bool res;
- regex_t reg;
- if ((ec = regcomp(®, rhs, REG_EXTENDED)) != 0) {
- size_t size;
- char *errbuf;
- size = regerror(ec, ®, NULL, 0);
- errbuf = t_malloc_no0(size);
- (void)regerror(ec, ®, errbuf, size);
- *error_r = t_strdup_printf("regexp() failed: %s",
- errbuf);
+
+ ec = dregex_match(rhs, lhs, 0, error_r);
+
+ if (ec < 0)
return -1;
- }
- if ((ec = regexec(®, lhs, 0, 0, 0)) != 0) {
- i_assert(ec == REG_NOMATCH);
- res = FALSE;
- } else {
- res = TRUE;
- }
- regfree(®);
- /* this should be same as neg.
- if NOT_REGEXP, neg == TRUE and res should be FALSE
- if REGEXP, ned == FALSE, and res should be TRUE
- */
+
+ res = ec == 1;
*result_r = res != neg;
+
return 0;
}
default:
#include "str.h"
#include "strescape.h"
#include "str-sanitize.h"
+#include "dregex.h"
#include "var-expand-private.h"
#include "expansion.h"
#include <ctype.h>
-#include <regex.h>
ARRAY_DEFINE_TYPE(var_expand_filter, struct var_expand_filter);
static ARRAY_TYPE(var_expand_filter) dyn_filters = ARRAY_INIT;
ERROR_IF_NO_TRANSFER_TO("regexp");
- int ret;
- regex_t reg;
- regmatch_t matches[10];
- const char *input = str_c(state->transfer);
- i_zero(®);
- i_zero(&matches);
- if ((ret = regcomp(®, pat, REG_EXTENDED)) != 0) {
- char errbuf[1024] = {0};
- (void)regerror(ret, ®, errbuf, sizeof(errbuf));
- regfree(®);
- *error_r = t_strdup(errbuf);
- return -1;
- }
-
- ret = regexec(®, input, N_ELEMENTS(matches), matches, 0);
- if (ret == REG_NOMATCH) {
- /* no match, do not modify */
- regfree(®);
- return 0;
- }
-
- /* perform replacement */
+ const char *input ATTR_UNUSED = str_c(state->transfer);
string_t *dest = t_str_new(strlen(rep));
- const char *p0 = rep;
- const char *p1;
- ret = 0;
-
- /* Supports up to 9 capture groups,
- * if we need more, then this code should
- * be refactored to see how many we really need
- * and create a proper template from this. */
- while ((p1 = strchr(p0, '\\')) != NULL) {
- if (i_isdigit(p1[1])) {
- /* looks like a placeholder */
- str_append_data(dest, p0, p1 - p0);
- unsigned int g = p1[1] - '0';
- if (g >= N_ELEMENTS(matches) ||
- matches[g].rm_so == -1) {
- *error_r = "Invalid capture group";
- ret = -1;
- break;
- }
- i_assert(matches[g].rm_eo >= matches[g].rm_so);
- str_append_data(dest, input + matches[g].rm_so,
- matches[g].rm_eo - matches[g].rm_so);
- p0 = p1 + 2;
- } else {
- str_append_c(dest, *p1);
- p1++;
- }
- }
- regfree(®);
+ int ret = dregex_replace(pat, input, rep, dest, 0, error_r);
- if (ret == 0) {
- str_append(dest, p0);
+ if (ret > 0)
var_expand_state_set_transfer_data(state, dest->data, dest->used);
- }
- return ret == 0 ? 0 : -1;
+ return ret < 0 ? -1 : 0;
}
static int fn_number(const struct var_expand_statement *stmt, bool be,
{ .in = "%{truncate(3)}", .out = "truncate: No value to truncate", .ret = -1 },
/* ldap dn */
{ .in = "cn=%{first},ou=%{domain | ldap_dn}", .out = "cn=hello,ou=test,dc=dovecot,dc=org", .ret = 0 },
+#ifdef HAVE_LIBPCRE
/* regexp */
- { .in = "%{literal('hello world') | regexp('(.*) (.*)', '\\\\2 \\\\1')}", .out = "world hello" },
+ { .in = "%{literal('hello world') | regexp('(.*) (.*)', '$2 $1')}", .out = "world hello" },
+#endif
/* index */
{ .in = "%{user | index('@',0)}", .out = "user", .ret = 0 },
{ .in = "%{user | username}", .out = "user", .ret = 0 },
{ .in = "%{literal('a') | if('!*', '*a*', 'yes', 'no')}", .out = "no", .ret = 0 },
{ .in = "%{literal('a') | if('!*', '*b*', 'yes', 'no')}", .out = "yes", .ret = 0 },
{ .in = "%{literal('a') | if('!*', '*', 'yes', 'no')}", .out = "no", .ret = 0 },
+#ifdef HAVE_LIBPCRE
{ .in = "%{literal('a') | if('~', 'a', 'yes', 'no')}", .out = "yes", .ret = 0 },
{ .in = "%{literal('a') | if('~', 'b', 'yes', 'no')}", .out = "no", .ret = 0 },
{ .in = "%{literal('a') | if('~', '.*a.*', 'yes', 'no')}", .out = "yes", .ret = 0 },
{ .in = "%{literal('a') | if('!~', '.*', 'yes', 'no')}", .out = "no", .ret = 0 },
{ .in = "%{literal('this is test') | if('~', '^test', 'yes', 'no')}", .out = "no", .ret = 0 },
{ .in = "%{literal('this is test') | if('~', '.*test', 'yes', 'no')}", .out = "yes", .ret = 0 },
+#endif
/* variable expansion */
{ .in = "%{alpha | if('eq', alpha, 'yes', 'no')}", .out = "yes", .ret = 0 },
{ .in = "%{alpha | if('eq', beta, 'yes', 'no')}", .out = "no", .ret = 0 },