From: Aki Tuomi Date: Fri, 1 Aug 2025 09:17:49 +0000 (+0300) Subject: lib-var-expand: Use lib-regex instead of libc regex X-Git-Tag: 2.4.2~464 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=c38041bc74c1c430ed6c6bd91f9ea3c85386f315;p=thirdparty%2Fdovecot%2Fcore.git lib-var-expand: Use lib-regex instead of libc regex --- diff --git a/src/lib-var-expand/expansion-filter-if.c b/src/lib-var-expand/expansion-filter-if.c index cb708402e9..5866efe805 100644 --- a/src/lib-var-expand/expansion-filter-if.c +++ b/src/lib-var-expand/expansion-filter-if.c @@ -3,10 +3,9 @@ #include "lib.h" #include "var-expand-private.h" #include "expansion.h" +#include "dregex.h" #include "wildcard-match.h" -#include - enum var_expand_if_op { OP_UNKNOWN, OP_NUM_EQ, @@ -65,7 +64,6 @@ fn_if_cmp(struct var_expand_state *state, const struct var_expand_parameter *p_l 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; @@ -109,6 +107,8 @@ fn_if_cmp(struct var_expand_state *state, const struct var_expand_parameter *p_l return -1; } + bool neg ATTR_UNUSED = FALSE; + switch (op) { case OP_STR_EQ: *result_r = strcmp(lhs,rhs) == 0; @@ -140,29 +140,15 @@ fn_if_cmp(struct var_expand_state *state, const struct var_expand_parameter *p_l 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: diff --git a/src/lib-var-expand/expansion-filter.c b/src/lib-var-expand/expansion-filter.c index 790005786d..4bff618d97 100644 --- a/src/lib-var-expand/expansion-filter.c +++ b/src/lib-var-expand/expansion-filter.c @@ -8,11 +8,11 @@ #include "str.h" #include "strescape.h" #include "str-sanitize.h" +#include "dregex.h" #include "var-expand-private.h" #include "expansion.h" #include -#include ARRAY_DEFINE_TYPE(var_expand_filter, struct var_expand_filter); static ARRAY_TYPE(var_expand_filter) dyn_filters = ARRAY_INIT; @@ -795,66 +795,15 @@ static int fn_regexp(const struct var_expand_statement *stmt, 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, diff --git a/src/lib-var-expand/test-var-expand.c b/src/lib-var-expand/test-var-expand.c index 3f3327f1b3..6ee360c637 100644 --- a/src/lib-var-expand/test-var-expand.c +++ b/src/lib-var-expand/test-var-expand.c @@ -196,8 +196,10 @@ static void test_var_expand_builtin_filters(void) { { .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 }, @@ -342,6 +344,7 @@ static void test_var_expand_if(void) { .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 }, @@ -354,6 +357,7 @@ static void test_var_expand_if(void) { .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 },