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 2) 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 */
56 while(reg->prts_closure[i][j])
58 reg->prts_str[i][j] = NULL;
62 if((ret = _OS_Regex(reg->patterns[i], str, reg->prts_closure[i],
63 reg->prts_str[i], reg->flags[i])))
67 /* We must always have the open and the close */
68 while(reg->prts_str[i][j] && reg->prts_str[i][j+1])
70 str_char = reg->prts_str[i][j+1][0];
72 reg->prts_str[i][j+1][0] = '\0';
74 reg->sub_strings[k] = strdup(reg->prts_str[i][j]);
75 if(!reg->sub_strings[k])
77 OSRegex_FreeSubStrings(reg);
81 /* Set the next one to null */
82 reg->prts_str[i][j+1][0] = str_char;
84 reg->sub_strings[k] = NULL;
99 /* If we don't need the sub strings */
101 /* Looping on all sub patterns */
102 while(reg->patterns[i])
104 if((ret = _OS_Regex(reg->patterns[i], str, NULL, NULL, reg->flags[i])))
114 #define PRTS(x) ((prts(*x) && x++) || 1)
115 #define ENDOFFILE(x) ( PRTS(x) && (*x == '\0'))
117 /** int _OS_Regex(char *pattern, char *str, char **prts_closure,
118 char **prts_str, int flags) v0.1
119 * Perform the pattern matching on the pattern/string provided.
120 * Returns 1 on success and 0 on failure.
121 * If prts_closure is set, the parenthesis locations will be
122 * written on prts_str (which must not be NULL)
124 char *_OS_Regex(char *pattern, char *str, char **prts_closure,
125 char **prts_str, int flags)
130 int _regex_matched = 0;
135 char *st_error = NULL;
140 char *pt_error[4] = {NULL, NULL, NULL, NULL};
141 char *pt_error_str[4];
144 /* Will loop the whole string, trying to find a match */
150 if(!(flags & END_SET) || (flags & END_SET && (*st == '\0')))
154 /* If it is a parenthesis do not match against the character */
156 /* Find the closure for the parenthesis */
160 while(prts_closure[prts_int])
162 if(prts_closure[prts_int] == pt)
164 prts_str[prts_int] = st;
174 if(!(flags & END_SET) || (flags & END_SET && (*st == '\0')))
180 /* If it starts on Backslash (future regex) */
183 if(Regex((uchar)*(pt+1), (uchar)*st))
187 /* If we don't have a '+' or '*', we should skip
188 * searching using this pattern.
190 if(!isPlus(*next_pt))
195 /* If st_error is not set, we need to set it here.
196 * In case of error in the matching later, we need
197 * to continue from here (it will be incremented in
206 /* If it is a '*', we need to set the _regex_matched
207 * for the first pattern even.
215 /* If our regex matches and we have a "+" set, we will
216 * try the next one to see if it matches. If yes, we
217 * can jump to it, but saving our currently location
219 * _regex_matched will set set to true after the first
227 /* If it is a parenthesis, jump to the next and write
228 * the location down if 'ok_here >= 0'
239 else if(*next_pt == BACKSLASH)
241 if(Regex((uchar)*(next_pt+1), (uchar)*st))
243 /* If the next one does not have
244 * a '+' or '*', we can set it as
245 * being read and continue.
247 if(!isPlus(*(next_pt+2)))
257 else if(*next_pt == charmap[(uchar)*st])
263 /* If the next character matches in here */
266 if(prts_closure && prts(*(next_pt - 1)))
269 while(prts_closure[prts_int])
271 if(prts_closure[prts_int] == (next_pt -1))
274 prts_str[prts_int] = st+1;
276 prts_str[prts_int] = st;
284 /* If next_pt == \0, return the r_code */
291 /* Each "if" will increment the amount
292 * necessary for the next pattern in ok_here
301 pt_error_str[0] = st;
303 else if(!pt_error[1])
306 pt_error_str[1] = st;
308 else if(!pt_error[2])
311 pt_error_str[2] = st;
314 else if(!pt_error[3])
317 pt_error_str[3] = st;
327 /* If it is a parenthesis, mark the location */
328 if(prts_closure && prts(*next_pt))
331 while(prts_closure[prts_int])
333 if(prts_closure[prts_int] == next_pt)
336 prts_str[prts_int] = st +1;
338 prts_str[prts_int] = st;
353 else if((*(pt+3) == '\0') && (_regex_matched == 1)&&(r_code))
356 if(!(flags & END_SET) || (flags & END_SET && (*st == '\0')))
360 /* If we didn't match regex, but _regex_matched == 1, jump
361 * to the next available pattern
363 else if((*(pt+2) == '+') && (_regex_matched == 1))
370 /* We may not match with '*' */
371 else if(*(pt+2) == '*')
382 else if(*pt == charmap[(uchar)*st])
387 /* If st_error is not set, we need to set it here.
388 * In case of error in the matching later, we need
389 * to continue from here (it will be incremented in
402 st = pt_error_str[3];
409 st = pt_error_str[2];
416 st = pt_error_str[1];
423 st = pt_error_str[0];
427 else if(flags & BEGIN_SET)
429 /* If we get an error and the "^" option is
430 * set, we can return "not matched" in here.
442 }while(*(++st) != '\0');
445 /* Matching for a possible last parenthesis */
448 while(!prts(*pt) && *pt != '\0')
450 if(*pt == BACKSLASH && *(pt+2) == '*')
459 while(prts_closure[prts_int])
461 if(prts_closure[prts_int] == pt)
463 prts_str[prts_int] = st;
479 ((*pt == BACKSLASH) &&
483 (ENDOFFILE(pt)) ))) ||