Skip to content

Commit 04637cb

Browse files
authored
Merge pull request #3901 from ovidiusas/master_regex_match
regex: Enhance pcre_match to optionally return the matched string
2 parents 22b7f9c + 019b0f0 commit 04637cb

2 files changed

Lines changed: 103 additions & 12 deletions

File tree

modules/regex/doc/regex_admin.xml

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -222,13 +222,14 @@ modparam("regex", "pcre_extended", 1)
222222

223223
<section id="func_pcre_match" xreflabel="pcre_match()">
224224
<title>
225-
<function moreinfo="none">pcre_match (string, pcre_regex)</function>
225+
<function moreinfo="none">pcre_match (string, pcre_regex [, match])</function>
226226
</title>
227227

228228
<para>
229229
Matches the given string parameter against the regular expression pcre_regex,
230230
which is compiled into a PCRE object. Returns TRUE if it matches, FALSE
231-
otherwise.
231+
otherwise. When the optional match parameter is provided, it is set to
232+
the matched part of the string, or cleared if there is no match.
232233
</para>
233234

234235
<para>Meaning of the parameters is as follows:</para>
@@ -245,6 +246,12 @@ modparam("regex", "pcre_extended", 1)
245246
in a PCRE object.
246247
</para>
247248
</listitem>
249+
<listitem>
250+
<para>
251+
<emphasis>match</emphasis> (var, optional) - Writable pseudo-variable
252+
where the matched part of the string is stored.
253+
</para>
254+
</listitem>
248255
</itemizedlist>
249256

250257
<para>

modules/regex/regex_mod.c

Lines changed: 94 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,8 @@
7777
#include "../../str.h"
7878
#include "../../locking.h"
7979
#include "../../mod_fix.h"
80+
#include "../../pvar.h"
81+
#include "../../error.h"
8082
#include "../../mi/mi.h"
8183

8284
#define START 0
@@ -128,12 +130,15 @@ static void destroy(void);
128130
*/
129131
static int load_pcres(int);
130132
static void free_shared_memory(void);
133+
static int fixup_check_pv_setf(void **param);
134+
static int set_match_pvar(struct sip_msg *msg, pv_spec_t *match, str *value);
131135

132136

133137
/*
134138
* Script functions
135139
*/
136-
static int w_pcre_match(struct sip_msg* _msg, str* string, str* _regex_s);
140+
static int w_pcre_match(struct sip_msg* _msg, str* string, str* _regex_s,
141+
pv_spec_t *match);
137142
static int w_pcre_match_group(struct sip_msg* _msg, str* string, int* _num_pcre);
138143

139144

@@ -152,7 +157,8 @@ static const cmd_export_t cmds[] =
152157
{
153158
{"pcre_match", (cmd_function)w_pcre_match, {
154159
{CMD_PARAM_STR,0,0},
155-
{CMD_PARAM_STR,0,0}, {0,0,0}},
160+
{CMD_PARAM_STR,0,0},
161+
{CMD_PARAM_VAR|CMD_PARAM_OPT, fixup_check_pv_setf, 0}, {0,0,0}},
156162
REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE|
157163
STARTUP_ROUTE|TIMER_ROUTE|EVENT_ROUTE},
158164
{"pcre_match_group", (cmd_function)w_pcre_match_group, {
@@ -584,8 +590,49 @@ static void free_shared_memory(void)
584590
* Script functions
585591
*/
586592

593+
static int fixup_check_pv_setf(void **param)
594+
{
595+
if (!pv_is_w(((pv_spec_t*)*param))) {
596+
LM_ERR("invalid output parameter: must be writable\n");
597+
return E_SCRIPT;
598+
}
599+
600+
return 0;
601+
}
602+
603+
604+
static int set_match_pvar(struct sip_msg *msg, pv_spec_t *match, str *value)
605+
{
606+
pv_value_t pv_val;
607+
608+
if (!match)
609+
return 0;
610+
611+
if (!value) {
612+
if (pv_set_value(msg, match, 0, NULL) != 0) {
613+
LM_ERR("failed to clear match pvar\n");
614+
return -1;
615+
}
616+
617+
return 0;
618+
}
619+
620+
memset(&pv_val, 0, sizeof(pv_val));
621+
pv_val.flags = PV_VAL_STR;
622+
pv_val.rs = *value;
623+
624+
if (pv_set_value(msg, match, 0, &pv_val) != 0) {
625+
LM_ERR("failed to set match pvar\n");
626+
return -1;
627+
}
628+
629+
return 0;
630+
}
631+
632+
587633
/*! \brief Return true if the argument matches the regular expression parameter */
588-
static int w_pcre_match(struct sip_msg* _msg, str* string, str* _regex_s)
634+
static int w_pcre_match(struct sip_msg* _msg, str* string, str* _regex_s,
635+
pv_spec_t *match)
589636
{
590637
pcre2_code *pcre_re = NULL;
591638
int pcre_rc;
@@ -594,8 +641,12 @@ static int w_pcre_match(struct sip_msg* _msg, str* string, str* _regex_s)
594641
PCRE2_SIZE pcre_erroffset;
595642
#ifdef PCRE2_LIB
596643
pcre2_match_data *match_data;
644+
PCRE2_SIZE *ovector;
645+
#else
646+
int ovector[3];
597647
#endif
598648
str regex;
649+
str match_str;
599650

600651
if (pkg_nt_str_dup(&regex, _regex_s) < 0)
601652
return -1;
@@ -616,10 +667,19 @@ static int w_pcre_match(struct sip_msg* _msg, str* string, str* _regex_s)
616667
string->len, /* the length of the subject */
617668
0, /* start at offset 0 in the subject */
618669
0, /* default options */
619-
NULL, /* output vector for substring information */
620-
0); /* number of elements in the output vector */
670+
match ? ovector : NULL, /* output vector for substring information */
671+
match ? 3 : 0); /* number of elements in the output vector */
621672
#else
622-
match_data = pcre2_match_data_create(0, NULL); // no captures needed
673+
if (match)
674+
match_data = pcre2_match_data_create_from_pattern(pcre_re, NULL);
675+
else
676+
match_data = pcre2_match_data_create(0, NULL);
677+
if (!match_data) {
678+
LM_ERR("failed to allocate match data\n");
679+
pcre2_code_free(pcre_re);
680+
pkg_free(regex.s);
681+
return -1;
682+
}
623683

624684
pcre_rc = pcre2_match(
625685
pcre_re, /* the compiled pattern */
@@ -629,8 +689,6 @@ static int w_pcre_match(struct sip_msg* _msg, str* string, str* _regex_s)
629689
0, /* default options */
630690
match_data, /* match data block */
631691
NULL); /* match context */
632-
633-
pcre2_match_data_free(match_data);
634692
#endif
635693

636694
/* Matching failed: handle error cases */
@@ -643,14 +701,40 @@ static int w_pcre_match(struct sip_msg* _msg, str* string, str* _regex_s)
643701
LM_DBG("matching error '%d'\n", pcre_rc);
644702
break;
645703
}
704+
#ifdef PCRE2_LIB
705+
pcre2_match_data_free(match_data);
706+
#endif
646707
pcre2_code_free(pcre_re);
647708
pkg_free(regex.s);
709+
if (set_match_pvar(_msg, match, NULL) < 0)
710+
return -1;
648711
return -1;
649712
}
650713

714+
LM_DBG("'%s' matches '%s'\n", string->s, regex.s);
715+
716+
if (match) {
717+
#ifdef PCRE2_LIB
718+
ovector = pcre2_get_ovector_pointer(match_data);
719+
#endif
720+
match_str.s = string->s + ovector[0];
721+
match_str.len = (int)(ovector[1] - ovector[0]);
722+
723+
if (set_match_pvar(_msg, match, &match_str) < 0) {
724+
#ifdef PCRE2_LIB
725+
pcre2_match_data_free(match_data);
726+
#endif
727+
pcre2_code_free(pcre_re);
728+
pkg_free(regex.s);
729+
return -1;
730+
}
731+
}
732+
733+
#ifdef PCRE2_LIB
734+
pcre2_match_data_free(match_data);
735+
#endif
651736
pcre2_code_free(pcre_re);
652737
pkg_free(regex.s);
653-
LM_DBG("'%s' matches '%s'\n", string->s, regex.s);
654738
return 1;
655739
}
656740

@@ -769,7 +853,7 @@ mi_response_t *mi_pcres_match(const mi_params_t *params, struct mi_handler *asyn
769853
}
770854

771855
/* handle call back function result */
772-
rc = w_pcre_match(NULL, &string, &pcre_regex);
856+
rc = w_pcre_match(NULL, &string, &pcre_regex, NULL);
773857
LM_DBG("w_pcre_match: string<%s>, pcre_regex=<%s>, result:<%i>\n", string.s, pcre_regex.s, rc);
774858

775859
switch(rc) {

0 commit comments

Comments
 (0)