RTS API Documentation  1.10.11
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 (switch_regex_t *)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  switch_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  if (replace) {
179  switch_size_t r;
180 
181  for (r = 0; r < strlen(replace) && y < (len - 1); r++) {
182  substituted[y++] = replace[r];
183  }
184  pcre_free_substring(replace);
185  }
186  }
187  } else {
188  substituted[y++] = data[x];
189  x++;
190  }
191  }
192  substituted[y++] = '\0';
193 }
194 
195 
196 SWITCH_DECLARE(void) switch_capture_regex(switch_regex_t *re, int match_count, const char *field_data,
197  int *ovector, const char *var, switch_cap_callback_t callback, void *user_data)
198 
199 {
200 
201 
202  const char *replace;
203  int i;
204 
205  for (i = 0; i < match_count; i++) {
206  if (pcre_get_substring(field_data, ovector, match_count, i, &replace) >= 0) {
207  if (replace) {
208  callback(var, replace, user_data);
209  pcre_free_substring(replace);
210  }
211  }
212  }
213 }
214 
215 SWITCH_DECLARE(switch_status_t) switch_regex_match_partial(const char *target, const char *expression, int *partial)
216 {
217  const char *error = NULL; /* Used to hold any errors */
218  int error_offset = 0; /* Holds the offset of an error */
219  pcre *pcre_prepared = NULL; /* Holds the compiled regex */
220  int match_count = 0; /* Number of times the regex was matched */
221  int offset_vectors[255]; /* not used, but has to exist or pcre won't even try to find a match */
222  int pcre_flags = 0;
223  uint32_t flags = 0;
224  char *tmp = NULL;
226 
227  if (*expression == '/') {
228  char *opts = NULL;
229  tmp = strdup(expression + 1);
230  switch_assert(tmp);
231  if ((opts = strrchr(tmp, '/'))) {
232  *opts++ = '\0';
233  } else {
234  /* Note our error */
236  "Regular Expression Error expression[%s] missing ending '/' delimeter\n", expression);
237  goto end;
238  }
239  expression = tmp;
240  if (*opts) {
241  if (strchr(opts, 'i')) {
242  flags |= PCRE_CASELESS;
243  }
244  if (strchr(opts, 's')) {
245  flags |= PCRE_DOTALL;
246  }
247  }
248  }
249 
250  /* Compile the expression */
251  pcre_prepared = pcre_compile(expression, flags, &error, &error_offset, NULL);
252 
253  /* See if there was an error in the expression */
254  if (error != NULL) {
255  /* Clean up after ourselves */
256  if (pcre_prepared) {
257  pcre_free(pcre_prepared);
258  pcre_prepared = NULL;
259  }
260  /* Note our error */
262  "Regular Expression Error expression[%s] error[%s] location[%d]\n", expression, error, error_offset);
263 
264  /* We definitely didn't match anything */
265  goto end;
266  }
267 
268  if (*partial) {
269  pcre_flags = PCRE_PARTIAL;
270  }
271 
272  /* So far so good, run the regex */
273  match_count =
274  pcre_exec(pcre_prepared, NULL, target, (int) strlen(target), 0, pcre_flags, offset_vectors, sizeof(offset_vectors) / sizeof(offset_vectors[0]));
275 
276  /* Clean up */
277  if (pcre_prepared) {
278  pcre_free(pcre_prepared);
279  pcre_prepared = NULL;
280  }
281 
282  /* switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "number of matches: %d\n", match_count); */
283 
284  /* Was it a match made in heaven? */
285  if (match_count > 0) {
286  *partial = 0;
288  } else if (match_count == PCRE_ERROR_PARTIAL || match_count == PCRE_ERROR_BADPARTIAL) {
289  /* yes it is already set, but the code is clearer this way */
290  *partial = 1;
292  } else {
293  goto end;
294  }
295  end:
296  switch_safe_free(tmp);
297  return status;
298 }
299 
300 SWITCH_DECLARE(switch_status_t) switch_regex_match(const char *target, const char *expression)
301 {
302  int partial = 0;
303  return switch_regex_match_partial(target, expression, &partial);
304 }
305 
306 SWITCH_DECLARE_NONSTD(void) switch_regex_set_var_callback(const char *var, const char *val, void *user_data)
307 {
308  switch_core_session_t *session = (switch_core_session_t *) user_data;
311 }
312 
313 SWITCH_DECLARE_NONSTD(void) switch_regex_set_event_header_callback(const char *var, const char *val, void *user_data)
314 {
315 
316  switch_event_t *event = (switch_event_t *) user_data;
318 }
319 
320 
321 
322 /* For Emacs:
323  * Local Variables:
324  * mode:c
325  * indent-tabs-mode:t
326  * tab-width:4
327  * c-basic-offset:4
328  * End:
329  * For VIM:
330  * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
331  */
#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:215
_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.
Definition: cJSON.c:68
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)
int index
Definition: switch_cJSON.h:160
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:885
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:196
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:306
#define switch_goto_status(_status, _label)
Definition: switch_utils.h:287
const cJSON *const target
Main Library Header.
void(* switch_cap_callback_t)(const char *var, const char *val, void *user_data)
#define SWITCH_DECLARE(type)
char * buffer
Definition: switch_cJSON.h:153
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.
#define switch_assert(expr)
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:313
switch_status_t switch_regex_match(const char *target, const char *expression)
Function to evaluate an expression against a string.
Definition: switch_regex.c:300
void switch_regex_free(void *data)
Definition: switch_regex.c:49