FreeSWITCH API Documentation  1.7.0
switch_regex.c
Go to the documentation of this file.
1 /*
2  * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
3  * Copyright (C) 2005-2014, Anthony Minessale II <anthm@freeswitch.org>
4  *
5  * Version: MPL 1.1
6  *
7  * The contents of this file are subject to the Mozilla Public License Version
8  * 1.1 (the "License"); you may not use this file except in compliance with
9  * the License. You may obtain a copy of the License at
10  * http://www.mozilla.org/MPL/
11  *
12  * Software distributed under the License is distributed on an "AS IS" basis,
13  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14  * for the specific language governing rights and limitations under the
15  * License.
16  *
17  * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
18  *
19  * The Initial Developer of the Original Code is
20  * Michael Jerris <mike@jerris.com>
21  * Portions created by the Initial Developer are Copyright (C)
22  * the Initial Developer. All Rights Reserved.
23  *
24  * Contributor(s):
25  *
26  * Michael Jerris <mike@jerris.com>
27  *
28  *
29  * switch_regex.c -- PCRE wrapper
30  *
31  */
32 
33 #include <switch.h>
34 #include <pcre.h>
35 
37  int options, const char **errorptr, int *erroroffset, const unsigned char *tables)
38 {
39 
40  return pcre_compile(pattern, options, errorptr, erroroffset, tables);
41 
42 }
43 
44 SWITCH_DECLARE(int) switch_regex_copy_substring(const char *subject, int *ovector, int stringcount, int stringnumber, char *buffer, int size)
45 {
46  return pcre_copy_substring(subject, ovector, stringcount, stringnumber, buffer, size);
47 }
48 
50 {
51  pcre_free(data);
52 
53 }
54 
55 SWITCH_DECLARE(int) switch_regex_perform(const char *field, const char *expression, switch_regex_t **new_re, int *ovector, uint32_t olen)
56 {
57  const char *error = NULL;
58  int erroffset = 0;
59  pcre *re = NULL;
60  int match_count = 0;
61  char *tmp = NULL;
62  uint32_t flags = 0;
63  char abuf[256] = "";
64 
65  if (!(field && expression)) {
66  return 0;
67  }
68 
69  if (*expression == '_') {
70  if (switch_ast2regex(expression + 1, abuf, sizeof(abuf))) {
71  expression = abuf;
72  }
73  }
74 
75  if (*expression == '/') {
76  char *opts = NULL;
77  tmp = strdup(expression + 1);
78  assert(tmp);
79  if ((opts = strrchr(tmp, '/'))) {
80  *opts++ = '\0';
81  } else {
82  /* Note our error */
84  "Regular Expression Error expression[%s] missing ending '/' delimeter\n", expression);
85  goto end;
86  }
87  expression = tmp;
88  if (opts) {
89  if (strchr(opts, 'i')) {
90  flags |= PCRE_CASELESS;
91  }
92  if (strchr(opts, 's')) {
93  flags |= PCRE_DOTALL;
94  }
95  }
96  }
97 
98  re = pcre_compile(expression, /* the pattern */
99  flags, /* default options */
100  &error, /* for error message */
101  &erroffset, /* for error offset */
102  NULL); /* use default character tables */
103  if (error) {
104  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "COMPILE ERROR: %d [%s][%s]\n", erroffset, error, expression);
106  goto end;
107  }
108 
109  match_count = pcre_exec(re, /* result of pcre_compile() */
110  NULL, /* we didn't study the pattern */
111  field, /* the subject string */
112  (int) strlen(field), /* the length of the subject string */
113  0, /* start at offset 0 in the subject */
114  0, /* default options */
115  ovector, /* vector of integers for substring information */
116  olen); /* number of elements (NOT size in bytes) */
117 
118 
119  if (match_count <= 0) {
121  match_count = 0;
122  }
123 
124  *new_re = (switch_regex_t *) re;
125 
126  end:
127  switch_safe_free(tmp);
128  return match_count;
129 }
130 
131 SWITCH_DECLARE(void) switch_perform_substitution(switch_regex_t *re, int match_count, const char *data, const char *field_data,
132  char *substituted, switch_size_t len, int *ovector)
133 {
134  char index[10] = "";
135  const char *replace = NULL;
136  switch_size_t x, y = 0, z = 0;
137  int num = 0;
138  int brace;
139 
140  for (x = 0; y < (len - 1) && x < strlen(data);) {
141  if (data[x] == '$') {
142  x++;
143 
144  brace = data[x] == '{';
145  if (brace) {
146  x++;
147  }
148 
149  if (!(data[x] > 47 && data[x] < 58)) {
150  x -= brace;
151  substituted[y++] = data[x - 1];
152  continue;
153  }
154 
155  while (data[x] > 47 && data[x] < 58 && z < sizeof(index) - 1) {
156  index[z++] = data[x];
157  x++;
158  }
159  if (brace) {
160  if (data[x] != '}') {
161  x -= z - 1;
162  substituted[y++] = data[x - 1];
163  continue;
164  }
165  else {
166  x++;
167  }
168  }
169  index[z++] = '\0';
170  z = 0;
171  num = atoi(index);
172 
173  if (num < 0 || num > 256) {
174  num = -1;
175  }
176 
177  if (pcre_get_substring(field_data, ovector, match_count, num, &replace) > 0) {
178  switch_size_t r;
179  for (r = 0; r < strlen(replace) && y < (len - 1); r++) {
180  substituted[y++] = replace[r];
181  }
182  pcre_free_substring(replace);
183  }
184  } else {
185  substituted[y++] = data[x];
186  x++;
187  }
188  }
189  substituted[y++] = '\0';
190 }
191 
192 
193 SWITCH_DECLARE(void) switch_capture_regex(switch_regex_t *re, int match_count, const char *field_data,
194  int *ovector, const char *var, switch_cap_callback_t callback, void *user_data)
195 
196 {
197 
198 
199  const char *replace;
200  int i;
201 
202  for (i = 0; i < match_count; i++) {
203  if (pcre_get_substring(field_data, ovector, match_count, i, &replace) > 0) {
204  callback(var, replace, user_data);
205  pcre_free_substring(replace);
206  }
207  }
208 }
209 
210 SWITCH_DECLARE(switch_status_t) switch_regex_match_partial(const char *target, const char *expression, int *partial)
211 {
212  const char *error = NULL; /* Used to hold any errors */
213  int error_offset = 0; /* Holds the offset of an error */
214  pcre *pcre_prepared = NULL; /* Holds the compiled regex */
215  int match_count = 0; /* Number of times the regex was matched */
216  int offset_vectors[255]; /* not used, but has to exist or pcre won't even try to find a match */
217  int pcre_flags = 0;
218  uint32_t flags = 0;
219  char *tmp = NULL;
221 
222  if (*expression == '/') {
223  char *opts = NULL;
224  tmp = strdup(expression + 1);
225  assert(tmp);
226  if ((opts = strrchr(tmp, '/'))) {
227  *opts++ = '\0';
228  } else {
229  /* Note our error */
231  "Regular Expression Error expression[%s] missing ending '/' delimeter\n", expression);
232  goto end;
233  }
234  expression = tmp;
235  if (opts) {
236  if (strchr(opts, 'i')) {
237  flags |= PCRE_CASELESS;
238  }
239  if (strchr(opts, 's')) {
240  flags |= PCRE_DOTALL;
241  }
242  }
243  }
244 
245  /* Compile the expression */
246  pcre_prepared = pcre_compile(expression, flags, &error, &error_offset, NULL);
247 
248  /* See if there was an error in the expression */
249  if (error != NULL) {
250  /* Clean up after ourselves */
251  if (pcre_prepared) {
252  pcre_free(pcre_prepared);
253  pcre_prepared = NULL;
254  }
255  /* Note our error */
257  "Regular Expression Error expression[%s] error[%s] location[%d]\n", expression, error, error_offset);
258 
259  /* We definitely didn't match anything */
260  goto end;
261  }
262 
263  if (*partial) {
264  pcre_flags = PCRE_PARTIAL;
265  }
266 
267  /* So far so good, run the regex */
268  match_count =
269  pcre_exec(pcre_prepared, NULL, target, (int) strlen(target), 0, pcre_flags, offset_vectors, sizeof(offset_vectors) / sizeof(offset_vectors[0]));
270 
271  /* Clean up */
272  if (pcre_prepared) {
273  pcre_free(pcre_prepared);
274  pcre_prepared = NULL;
275  }
276 
277  /* switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "number of matches: %d\n", match_count); */
278 
279  /* Was it a match made in heaven? */
280  if (match_count > 0) {
281  *partial = 0;
283  } else if (match_count == PCRE_ERROR_PARTIAL || match_count == PCRE_ERROR_BADPARTIAL) {
284  /* yes it is already set, but the code is clearer this way */
285  *partial = 1;
287  } else {
288  goto end;
289  }
290  end:
291  switch_safe_free(tmp);
292  return status;
293 }
294 
295 SWITCH_DECLARE(switch_status_t) switch_regex_match(const char *target, const char *expression)
296 {
297  int partial = 0;
298  return switch_regex_match_partial(target, expression, &partial);
299 }
300 
301 SWITCH_DECLARE_NONSTD(void) switch_regex_set_var_callback(const char *var, const char *val, void *user_data)
302 {
303  switch_core_session_t *session = (switch_core_session_t *) user_data;
306 }
307 
308 SWITCH_DECLARE_NONSTD(void) switch_regex_set_event_header_callback(const char *var, const char *val, void *user_data)
309 {
310 
311  switch_event_t *event = (switch_event_t *) user_data;
313 }
314 
315 
316 
317 /* For Emacs:
318  * Local Variables:
319  * mode:c
320  * indent-tabs-mode:t
321  * tab-width:4
322  * c-basic-offset:4
323  * End:
324  * For VIM:
325  * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
326  */
#define switch_regex_safe_free(re)
Definition: switch_regex.h:79
int switch_regex_copy_substring(const char *subject, int *ovector, int stringcount, int stringnumber, char *buffer, int size)
Definition: switch_regex.c:44
#define SWITCH_CHANNEL_LOG
void switch_perform_substitution(switch_regex_t *re, int match_count, const char *data, const char *field_data, char *substituted, switch_size_t len, int *ovector)
Definition: switch_regex.c:131
Representation of an event.
Definition: switch_event.h:80
struct real_pcre switch_regex_t
Definition: switch_regex.h:43
switch_status_t switch_regex_match_partial(const char *target, const char *expression, int *partial)
Function to evaluate an expression against a string.
Definition: switch_regex.c:210
_Ret_ switch_channel_t * switch_core_session_get_channel(_In_ switch_core_session_t *session)
Retrieve a pointer to the channel object associated with a given session.
switch_status_t switch_channel_add_variable_var_check(switch_channel_t *channel, const char *varname, const char *value, switch_bool_t var_check, switch_stack_t stack)
switch_status_t switch_event_add_header_string(switch_event_t *event, switch_stack_t stack, const char *header_name, const char *data)
Add a string header to an event.
#define switch_safe_free(it)
Free a pointer and set it to NULL unless it already is NULL.
Definition: switch_utils.h:789
uintptr_t switch_size_t
int switch_regex_perform(const char *field, const char *expression, switch_regex_t **new_re, int *ovector, uint32_t olen)
Definition: switch_regex.c:55
#define SWITCH_DECLARE_NONSTD(type)
void switch_capture_regex(switch_regex_t *re, int match_count, const char *field_data, int *ovector, const char *var, switch_cap_callback_t callback, void *user_data)
Definition: switch_regex.c:193
switch_status_t
Common return values.
void switch_regex_set_var_callback(const char *var, const char *val, void *user_data)
Definition: switch_regex.c:301
#define switch_goto_status(_status, _label)
Definition: switch_utils.h:256
Main Library Header.
#define SWITCH_DECLARE(type)
switch_regex_t * switch_regex_compile(const char *pattern, int options, const char **errorptr, int *erroroffset, const unsigned char *tables)
Definition: switch_regex.c:36
void switch_log_printf(_In_ switch_text_channel_t channel, _In_z_ const char *file, _In_z_ const char *func, _In_ int line, _In_opt_z_ const char *userdata, _In_ switch_log_level_t level, _In_z_ _Printf_format_string_ const char *fmt,...) PRINTF_FUNCTION(7
Write log data to the logging engine.
void(* switch_cap_callback_t)(const char *var, const char *val, void *user_data)
switch_bool_t switch_ast2regex(const char *pat, char *rbuf, size_t len)
void switch_regex_set_event_header_callback(const char *var, const char *val, void *user_data)
Definition: switch_regex.c:308
switch_status_t switch_regex_match(const char *target, const char *expression)
Function to evaluate an expression against a string.
Definition: switch_regex.c:295
void switch_regex_free(void *data)
Definition: switch_regex.c:49