1 /* $OSSEC, os_regex.c, v0.3, 2005/04/05, Daniel B. Cid$ */
3 /* Copyright (C) 2009 Trend Micro Inc.
6 * This program is a free software; you can redistribute it
7 * and/or modify it under the terms of the GNU General Public
8 * License (version 3) as published by the FSF - Free Software
18 #include "os_regex_internal.h"
21 /** Internal prototypes **/
22 char *_OS_Regex(char *pattern, char *str, char **prts_closure,
23 char **prts_str, int flags);
27 /** char *OSRegex_Execute(char *str, OSRegex *reg) v0.1
28 * Compare an already compiled regular expression with
30 * Returns the end of the string on success or NULL on error.
31 * The error code is set on reg->error.
33 char *OSRegex_Execute(char *str, OSRegex *reg)
38 /* The string can't be NULL */
41 reg->error = OS_REGEX_STR_NULL;
46 /* If we need the sub strings */
49 int j = 0, k = 0, str_char = 0;
51 /* Looping on all sub patterns */
52 while(reg->patterns[i])
54 /* Cleaning the prts_str */
55 while(reg->prts_closure[i][j])
57 reg->prts_str[i][j] = NULL;
61 if((ret = _OS_Regex(reg->patterns[i], str, reg->prts_closure[i],
62 reg->prts_str[i], reg->flags[i])))
66 /* We must always have the open and the close */
67 while(reg->prts_str[i][j] && reg->prts_str[i][j+1])
69 str_char = reg->prts_str[i][j+1][0];
71 reg->prts_str[i][j+1][0] = '\0';
73 reg->sub_strings[k] = strdup(reg->prts_str[i][j]);
74 if(!reg->sub_strings[k])
76 OSRegex_FreeSubStrings(reg);
80 /* Set the next one to null */
81 reg->prts_str[i][j+1][0] = str_char;
83 reg->sub_strings[k] = NULL;
98 /* If we don't need the sub strings */
100 /* Looping on all sub patterns */
101 while(reg->patterns[i])
103 if((ret = _OS_Regex(reg->patterns[i], str, NULL, NULL, reg->flags[i])))
113 #define PRTS(x) ((prts(*x) && x++) || 1)
114 #define ENDOFFILE(x) ( PRTS(x) && (*x == '\0'))
116 /** int _OS_Regex(char *pattern, char *str, char **prts_closure,
117 char **prts_str, int flags) v0.1
118 * Perform the pattern matching on the pattern/string provided.
119 * Returns 1 on success and 0 on failure.
120 * If prts_closure is set, the parenthesis locations will be
121 * written on prts_str (which must not be NULL)
123 char *_OS_Regex(char *pattern, char *str, char **prts_closure,
124 char **prts_str, int flags)
129 int _regex_matched = 0;
134 char *st_error = NULL;
139 char *pt_error[4] = {NULL, NULL, NULL, NULL};
140 char *pt_error_str[4];
143 /* Will loop the whole string, trying to find a match */
149 if(!(flags & END_SET) || (flags & END_SET && (*st == '\0')))
153 /* If it is a parenthesis do not match against the character */
155 /* Find the closure for the parenthesis */
159 while(prts_closure[prts_int])
161 if(prts_closure[prts_int] == pt)
163 prts_str[prts_int] = st;
173 if(!(flags & END_SET) || (flags & END_SET && (*st == '\0')))
179 /* If it starts on Backslash (future regex) */
182 if(Regex((uchar)*(pt+1), (uchar)*st))
186 /* If we don't have a '+' or '*', we should skip
187 * searching using this pattern.
189 if(!isPlus(*next_pt))
194 /* If st_error is not set, we need to set it here.
195 * In case of error in the matching later, we need
196 * to continue from here (it will be incremented in
205 /* If it is a '*', we need to set the _regex_matched
206 * for the first pattern even.
214 /* If our regex matches and we have a "+" set, we will
215 * try the next one to see if it matches. If yes, we
216 * can jump to it, but saving our currently location
218 * _regex_matched will set set to true after the first
226 /* If it is a parenthesis, jump to the next and write
227 * the location down if 'ok_here >= 0'
238 else if(*next_pt == BACKSLASH)
240 if(Regex((uchar)*(next_pt+1), (uchar)*st))
242 /* If the next one does not have
243 * a '+' or '*', we can set it as
244 * being read and continue.
246 if(!isPlus(*(next_pt+2)))
256 else if(*next_pt == charmap[(uchar)*st])
262 /* If the next character matches in here */
265 if(prts_closure && prts(*(next_pt - 1)))
268 while(prts_closure[prts_int])
270 if(prts_closure[prts_int] == (next_pt -1))
273 prts_str[prts_int] = st+1;
275 prts_str[prts_int] = st;
283 /* If next_pt == \0, return the r_code */
290 /* Each "if" will increment the amount
291 * necessary for the next pattern in ok_here
300 pt_error_str[0] = st;
302 else if(!pt_error[1])
305 pt_error_str[1] = st;
307 else if(!pt_error[2])
310 pt_error_str[2] = st;
313 else if(!pt_error[3])
316 pt_error_str[3] = st;
326 /* If it is a parenthesis, mark the location */
327 if(prts_closure && prts(*next_pt))
330 while(prts_closure[prts_int])
332 if(prts_closure[prts_int] == next_pt)
335 prts_str[prts_int] = st +1;
337 prts_str[prts_int] = st;
352 else if((*(pt+3) == '\0') && (_regex_matched == 1)&&(r_code))
355 if(!(flags & END_SET) || (flags & END_SET && (*st == '\0')))
359 /* If we didn't match regex, but _regex_matched == 1, jump
360 * to the next available pattern
362 else if((*(pt+2) == '+') && (_regex_matched == 1))
369 /* We may not match with '*' */
370 else if(*(pt+2) == '*')
381 else if(*pt == charmap[(uchar)*st])
386 /* If st_error is not set, we need to set it here.
387 * In case of error in the matching later, we need
388 * to continue from here (it will be incremented in
401 st = pt_error_str[3];
408 st = pt_error_str[2];
415 st = pt_error_str[1];
422 st = pt_error_str[0];
426 else if(flags & BEGIN_SET)
428 /* If we get an error and the "^" option is
429 * set, we can return "not matched" in here.
441 }while(*(++st) != '\0');
444 /* Matching for a possible last parenthesis */
447 while(!prts(*pt) && *pt != '\0')
449 if(*pt == BACKSLASH && *(pt+2) == '*')
458 while(prts_closure[prts_int])
460 if(prts_closure[prts_int] == pt)
462 prts_str[prts_int] = st;
478 ((*pt == BACKSLASH) &&
482 (ENDOFFILE(pt)) ))) ||