Browse code

split up regex_list. begin testing for regex_suffix

git-svn: trunk@3985

Török Edvin authored on 2008/07/25 03:48:31
Showing 13 changed files
... ...
@@ -169,6 +169,8 @@ libclamav_la_SOURCES = \
169 169
 	iana_tld.h \
170 170
 	regex_list.c \
171 171
 	regex_list.h \
172
+	regex_suffix.c \
173
+	regex_suffix.h \
172 174
 	mspack.c \
173 175
 	mspack.h \
174 176
 	cab.c \
... ...
@@ -88,8 +88,9 @@ am_libclamav_la_OBJECTS = matcher-ac.lo matcher-bm.lo matcher.lo \
88 88
 	regerror.lo regexec.lo regfree.lo unarj.lo bzlib.lo nulsft.lo \
89 89
 	infblock.lo pdf.lo spin.lo yc.lo elf.lo sis.lo uuencode.lo \
90 90
 	phishcheck.lo phish_domaincheck_db.lo phish_whitelist.lo \
91
-	regex_list.lo mspack.lo cab.lo entconv.lo hashtab.lo dconf.lo \
92
-	lzma_iface.lo explode.lo textnorm.lo dlp.lo js-norm.lo
91
+	regex_list.lo regex_suffix.lo mspack.lo cab.lo entconv.lo \
92
+	hashtab.lo dconf.lo lzma_iface.lo explode.lo textnorm.lo \
93
+	dlp.lo js-norm.lo
93 94
 libclamav_la_OBJECTS = $(am_libclamav_la_OBJECTS)
94 95
 libclamav_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
95 96
 	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
... ...
@@ -410,6 +411,8 @@ libclamav_la_SOURCES = \
410 410
 	iana_tld.h \
411 411
 	regex_list.c \
412 412
 	regex_list.h \
413
+	regex_suffix.c \
414
+	regex_suffix.h \
413 415
 	mspack.c \
414 416
 	mspack.h \
415 417
 	cab.c \
... ...
@@ -582,6 +585,7 @@ distclean-compile:
582 582
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/regcomp.Plo@am__quote@
583 583
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/regerror.Plo@am__quote@
584 584
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/regex_list.Plo@am__quote@
585
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/regex_suffix.Plo@am__quote@
585 586
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/regexec.Plo@am__quote@
586 587
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/regfree.Plo@am__quote@
587 588
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rtf.Plo@am__quote@
... ...
@@ -83,6 +83,7 @@ CLAMAV_PRIVATE {
83 83
     cli_unescape;
84 84
     cli_textbuffer_append_normalize;
85 85
     cli_dconf_init;
86
+    cli_regex2suffix;
86 87
     html_normalise_mem;
87 88
   local:
88 89
     *;
... ...
@@ -56,380 +56,14 @@
56 56
 #include "str.h"
57 57
 #include "readdb.h"
58 58
 #include "jsparse/textbuf.h"
59
-
60
-/* ------- parse a regular expression, and extract a static suffix ------*/
61
-enum node_type {
62
-	root=0,
63
-	concat,
64
-	alternate, /* | */
65
-	optional,/* ?, * */
66
-	leaf, /* a character */
67
-	leaf_class /* character class */
68
-	/* (x)+ is transformed into (x)*(x) */
69
-};
70
-
71
-struct node {
72
-	enum node_type type;
73
-	struct node *parent;
74
-	union {
75
-		struct {
76
-			struct node* left;
77
-			struct node* right;
78
-		} children;
79
-		uint8_t*    leaf_class_bitmap;
80
-		uint8_t     leaf_char;
81
-	} u;
82
-};
83
-
59
+#include "regex_suffix.h"
84 60
 /* Prototypes */
85 61
 static size_t reverse_string(char *pattern);
86 62
 static int add_pattern(struct regex_matcher *matcher, char *pattern);
87
-static int add_pattern_suffix(struct regex_matcher *matcher, char *suffix, size_t suffix_len, struct regex_list *regex);
63
+static int add_pattern_suffix(void *cbdata, const char *suffix, size_t suffix_len, struct regex_list *regex);
88 64
 static int add_static_pattern(struct regex_matcher *matcher, char* pattern);
89
-static int build_suffixtree_descend(struct regex_matcher *matcher, struct regex_list *regex, struct node *n, struct text_buffer *buf);
90 65
 /* ---------- */
91 66
 
92
-static uint8_t dot_bitmap[32];
93
-
94
-static struct node* make_node(enum node_type type, struct node *left, struct node *right)
95
-{
96
-	struct node *n;
97
-	if(type == concat) {
98
-		if(left == NULL)
99
-			return right;
100
-		if(right == NULL)
101
-			return left;
102
-	}
103
-	n = cli_malloc(sizeof(*n));
104
-	if(!n)
105
-		return NULL;
106
-	n->type = type;
107
-	n->parent = NULL;
108
-	n->u.children.left = left;
109
-	n->u.children.right = right;
110
-	if(left)
111
-		left->parent = n;
112
-	if(right)
113
-		right->parent = n;
114
-	return n;
115
-}
116
-
117
-static struct node *dup_node(struct node *p)
118
-{
119
-	struct node *node_left, *node_right;
120
-	struct node *d;
121
-
122
-	if(!p)
123
-		return NULL;
124
-	d = cli_malloc(sizeof(*d));
125
-	if(!d)
126
-		return NULL;
127
-	d->type = p->type;
128
-	d->parent = NULL;
129
-	switch(p->type) {
130
-		case leaf:
131
-			d->u.leaf_char = p->u.leaf_char;
132
-			break;
133
-		case leaf_class:
134
-			d->u.leaf_class_bitmap = cli_malloc(32);
135
-			if(!d->u.leaf_class_bitmap)
136
-				return NULL;
137
-			memcpy(d->u.leaf_class_bitmap, p->u.leaf_class_bitmap, 32);
138
-			break;
139
-		default:
140
-			node_left = dup_node(p->u.children.left);
141
-			node_right = dup_node(p->u.children.right);
142
-			d->u.children.left = node_left;
143
-			d->u.children.right = node_right;
144
-			if(node_left)
145
-				node_left->parent = d;
146
-			if(node_right)
147
-				node_right->parent = d;
148
-			break;
149
-	}
150
-	return d;
151
-}
152
-
153
-static struct node *make_charclass(uint8_t *bitmap)
154
-{
155
-	struct node *v = cli_malloc(sizeof(*v));
156
-	if(!v)
157
-		return NULL;
158
-	v->type = leaf_class;
159
-	v->parent = NULL;
160
-	v->u.leaf_class_bitmap = bitmap;
161
-	return v;
162
-}
163
-
164
-static struct node *make_leaf(char c)
165
-{
166
-	struct node *v = cli_malloc(sizeof(*v));
167
-	if(!v)
168
-		return NULL;
169
-	v->type = leaf;
170
-	v->parent = NULL;
171
-	v->u.leaf_char = c;
172
-	return v;
173
-}
174
-
175
-static void destroy_tree(struct node *n)
176
-{
177
-	if(!n)
178
-		return;
179
-	switch(n->type) {
180
-		case concat:
181
-		case alternate:
182
-		case optional:
183
-			destroy_tree(n->u.children.left);
184
-			destroy_tree(n->u.children.right);
185
-			break;
186
-		case leaf_class:
187
-			if(n->u.leaf_class_bitmap != dot_bitmap)
188
-			  free(n->u.leaf_class_bitmap);
189
-			break;
190
-		case root:
191
-		case leaf:
192
-			break;
193
-	}
194
-	free(n);
195
-}
196
-
197
-static uint8_t* parse_char_class(const char *pat, size_t *pos)
198
-{
199
-	unsigned char range_start=0;
200
-	int hasprev = 0;
201
-	uint8_t* bitmap = cli_malloc(32);
202
-	if(!bitmap)
203
-		return NULL;
204
-	if (pat[*pos]=='^') {
205
-		memset(bitmap,0xFF,32);/*match chars not in brackets*/
206
-		++*pos;
207
-	}
208
-	else
209
-		memset(bitmap,0x00,32);
210
-	do {
211
-		/* literal ] can be first character, so test for it at the end of the loop, for example: []] */
212
-		if (pat[*pos]=='-' && hasprev) {
213
-			/* it is a range*/
214
-			unsigned char range_end;
215
-			unsigned int c;
216
-			assert(range_start);
217
-			++*pos;
218
-			if (pat[*pos]=='[')
219
-				if (pat[*pos+1]=='.') {
220
-					/* collating sequence not handled */
221
-					free(bitmap);
222
-					/* we are parsing the regex for a
223
-					 * filter, be conservative and
224
-					 * tell the filter that anything could
225
-					 * match here */
226
-					while(pat[*pos] != ']') ++*pos;
227
-					++*pos;
228
-					while(pat[*pos] != ']') ++*pos;
229
-					return dot_bitmap;
230
-				}
231
-				else
232
-					range_end = pat[*pos];
233
-			else
234
-				range_end = pat[*pos];
235
-			for(c=range_start+1;c<=range_end;c++)
236
-				bitmap[c>>3] ^= 1<<(c&0x7);
237
-			hasprev = 0;
238
-		}
239
-		else if (pat[*pos]=='[' && pat[*pos]==':') {
240
-			/* char class */
241
-			free(bitmap);
242
-			while(pat[*pos] != ']') ++*pos;
243
-			++*pos;
244
-			while(pat[*pos] != ']') ++*pos;
245
-			return dot_bitmap;
246
-		} else {
247
-			bitmap[pat[*pos]>>3] ^= 1<<(pat[*pos]&0x7);
248
-			++*pos;
249
-			range_start = pat[*pos];
250
-			hasprev = 1;
251
-		}
252
-	} while(pat[*pos]!=']');
253
-	return bitmap;
254
-}
255
-
256
-static struct node* parse_regex(const char *p, size_t *last)
257
-{
258
-	struct node *v = NULL;
259
-	struct node *right;
260
-	struct node *tmp;
261
-
262
-	while(p[*last] != '$' && p[*last] != '\0') {
263
-		switch(p[*last]) {
264
-			case '|':
265
-				++*last;
266
-				right = parse_regex(p, last);
267
-				v = make_node(alternate, v, right);
268
-				if(!v)
269
-					return NULL;
270
-				break;
271
-			case '*':
272
-			case '?':
273
-				v = make_node(optional, v, NULL);
274
-				if(!v)
275
-					return NULL;
276
-				++*last;
277
-				break;
278
-			case '+':
279
-				/* (x)* */
280
-				tmp = make_node(optional, v, NULL);
281
-				if(!tmp)
282
-					return NULL;
283
-				/* (x) */
284
-				right = dup_node(v);
285
-				if(!right)
286
-					return NULL;
287
-				/* (x)*(x) => (x)+ */
288
-				v = make_node(concat, tmp, right);
289
-				if(!v)
290
-					return NULL;
291
-				++*last;
292
-				break;
293
-			case '(':
294
-				++*last;
295
-				right = parse_regex(p, last);
296
-				if(!right)
297
-					return NULL;
298
-				++*last;
299
-				v = make_node(concat, v, right);
300
-				break;
301
-			case ')':
302
-				return v;
303
-			case '.':
304
-				right = make_charclass(dot_bitmap);
305
-				if(!right)
306
-					return NULL;
307
-				v = make_node(concat, v, right);
308
-				if(!v)
309
-					return NULL;
310
-				++*last;
311
-				break;
312
-			case '[':
313
-				right = make_charclass( parse_char_class(p, last) );
314
-				if(!right)
315
-					return NULL;
316
-				v = make_node(concat, v, right);
317
-				if(!v)
318
-					return NULL;
319
-			case '\\':
320
-				/* next char is escaped, advance pointer
321
-				 * and let fall-through handle it */
322
-				++*last;
323
-			default:
324
-				right = make_leaf(p[*last]);
325
-				v = make_node(concat, v, right);
326
-				if(!v)
327
-					return NULL;
328
-				++*last;
329
-				break;
330
-		}
331
-	}
332
-	return v;
333
-}
334
-
335
-#define BITMAP_HASSET(b, i) (b[i>>3] & (1<<(i&7)))
336
-
337
-static int build_suffixtree_ascend(struct regex_matcher *matcher, struct regex_list *regex, struct node *n, struct text_buffer *buf, struct node *prev)
338
-{
339
-	size_t i;
340
-	while(n) {
341
-		struct node *q = n;
342
-		switch(n->type) {
343
-			case root:
344
-				textbuffer_putc(buf, '\0');
345
-				if(add_pattern_suffix(matcher, buf->data, buf->pos, regex) < 0)
346
-					return CL_EMEM;
347
-				return 0;
348
-			case leaf:
349
-				textbuffer_putc(buf, n->u.leaf_char);
350
-				n = n->parent;
351
-				break;
352
-			case leaf_class:
353
-				if(memcmp(n->u.leaf_class_bitmap, dot_bitmap, sizeof(dot_bitmap)) == 0) {
354
-					textbuffer_putc(buf, '\0');
355
-					if(add_pattern_suffix(matcher, buf->data, buf->pos, regex) < 0)
356
-						return CL_EMEM;
357
-					return 0;
358
-				}
359
-				for(i=0;i<255;i++) {
360
-					if(BITMAP_HASSET(n->u.leaf_class_bitmap, i)) {
361
-						size_t pos;
362
-						pos = buf->pos;
363
-						textbuffer_putc(buf, i);
364
-						if(build_suffixtree_ascend(matcher, regex, n->parent, buf, n) < 0)
365
-							return CL_EMEM;
366
-						buf->pos = pos;
367
-					}
368
-				}
369
-				return 0;
370
-			case concat:
371
-				if(prev != n->u.children.left) {
372
-					if(build_suffixtree_descend(matcher, regex, n->u.children.left, buf) < 0)
373
-						return CL_EMEM;
374
-					/* we're done here, descend will call
375
-					 * ascend if needed */
376
-					return 0;
377
-				} else {
378
-					n = n->parent;
379
-				}
380
-				break;
381
-			case alternate:
382
-				n = n->parent;
383
-				break;
384
-			case optional:
385
-				textbuffer_putc(buf, '\0');
386
-				if(add_pattern_suffix(matcher, buf->data, buf->pos, regex) < 0)
387
-					return CL_EMEM;
388
-				return 0;
389
-		}
390
-		prev = q;
391
-	}
392
-	return 0;
393
-}
394
-
395
-static int build_suffixtree_descend(struct regex_matcher *matcher, struct regex_list *regex, struct node *n, struct text_buffer *buf)
396
-{
397
-	size_t pos;
398
-	while(n && n->type == concat) {
399
-		n = n->u.children.right;
400
-	}
401
-	if(!n)
402
-		return 0;
403
-	/* find out end of the regular expression,
404
-	 * if it ends with a static pattern */
405
-	switch(n->type) {
406
-		case alternate:
407
-			/* save pos as restart point */
408
-			pos = buf->pos;
409
-			if(build_suffixtree_descend(matcher, regex, n->u.children.left, buf) < 0)
410
-				return CL_EMEM;
411
-			buf->pos = pos;
412
-			if(build_suffixtree_descend(matcher, regex, n->u.children.right, buf) < 0)
413
-				return CL_EMEM;
414
-			buf->pos = pos;
415
-			break;
416
-		case optional:
417
-			textbuffer_putc(buf, '\0');
418
-			if(add_pattern_suffix(matcher, buf->data, buf->pos, regex) < 0)
419
-				return CL_EMEM;
420
-			return 0;
421
-		case leaf:
422
-		case leaf_class:
423
-			if(build_suffixtree_ascend(matcher, regex, n, buf, NULL) < 0)
424
-			        return CL_EMEM;
425
-			return 0;
426
-		default:
427
-			break;
428
-	}
429
-	return 0;
430
-}
431
-
432
-
433 67
 /* ----- shift-or filtering -------------- */
434 68
 
435 69
 #define BITMAP_CONTAINS(bmap, val) ((bmap)[(val) >> 5] & (1 << ((val) & 0x1f)))
... ...
@@ -557,7 +191,6 @@ static inline size_t get_char_at_pos_with_skip(const struct pre_fixup_info* info
557 557
 static int validate_subdomain(const struct regex_list *regex, const struct pre_fixup_info *pre_fixup, const char *buffer, size_t buffer_len, char *real_url, size_t real_len, char *orig_real_url)
558 558
 {
559 559
 	char c;
560
-	const char *matched;
561 560
 	size_t match_len;
562 561
 
563 562
 	if(!regex || !regex->pattern)
... ...
@@ -626,7 +259,6 @@ int regex_list_match(struct regex_matcher* matcher,char* real_url,const char* di
626 626
 		size_t buffer_len  = (hostOnly && !is_whitelist) ? real_len + 1 : real_len + display_len + 1 + 1;
627 627
 		char *buffer = cli_malloc(buffer_len+1);
628 628
 		char *bufrev;
629
-		size_t i;
630 629
 		int rc = 0;
631 630
 		struct cli_ac_data mdata;
632 631
 
... ...
@@ -662,7 +294,7 @@ int regex_list_match(struct regex_matcher* matcher,char* real_url,const char* di
662 662
 
663 663
 		if(rc) {
664 664
 			/* TODO loop over multiple virusnames here */
665
-			regex = (struct regex_list*)vinfo;
665
+			regex = (const struct regex_list*)vinfo;
666 666
 			do {
667 667
 				/* loop over multiple regexes corresponding to
668 668
 				 * this suffix */
... ...
@@ -903,7 +535,7 @@ int is_regex_ok(struct regex_matcher* matcher)
903 903
 	return (!matcher->list_inited || matcher->list_inited!=-1);/* either we don't have a regexlist, or we initialized it successfully */
904 904
 }
905 905
 
906
-static int add_newsuffix(struct regex_matcher *matcher, struct regex_list *info, char *suffix, size_t len)
906
+static int add_newsuffix(struct regex_matcher *matcher, struct regex_list *info, const char *suffix, size_t len)
907 907
 {
908 908
 	struct cli_matcher *root = &matcher->suffixes;
909 909
 	struct cli_ac_patt *new = cli_calloc(1,sizeof(*new));
... ...
@@ -951,8 +583,9 @@ static int add_newsuffix(struct regex_matcher *matcher, struct regex_list *info,
951 951
 /* ------ load a regex, determine suffix, determine suffix2regexlist map ---- */
952 952
 
953 953
 /* returns 0 on success, clamav error code otherwise */
954
-static int add_pattern_suffix(struct regex_matcher *matcher, char *suffix, size_t suffix_len, struct regex_list *regex)
954
+static int add_pattern_suffix(void *cbdata, const char *suffix, size_t suffix_len, struct regex_list *regex)
955 955
 {
956
+	struct regex_matcher *matcher = cbdata;
956 957
 	const struct element *el;
957 958
 
958 959
 	assert(matcher);
... ...
@@ -1006,12 +639,8 @@ static int add_static_pattern(struct regex_matcher *matcher, char* pattern)
1006 1006
 
1007 1007
 static int add_pattern(struct regex_matcher *matcher, char *pattern)
1008 1008
 {
1009
-	struct text_buffer buf;
1010
-	struct node *n;
1011
-	size_t last=0;
1012 1009
 	int rc;
1013 1010
 	struct regex_list *regex = cli_malloc(sizeof(*regex));
1014
-	struct node root_node;
1015 1011
 	size_t len;
1016 1012
 	/* we only match the host, so remove useless stuff */
1017 1013
 	const char remove_end[] = "([/?].*)?/";
... ...
@@ -1032,32 +661,11 @@ static int add_pattern(struct regex_matcher *matcher, char *pattern)
1032 1032
 	}
1033 1033
 	pattern[len] = '\0';
1034 1034
 
1035
-
1036
-	rc = cli_regcomp(&regex->preg, pattern, REG_EXTENDED);
1035
+	rc = cli_regex2suffix(pattern, regex, add_pattern_suffix, matcher);
1037 1036
 	if(rc) {
1038
-		size_t buflen = cli_regerror(rc, &regex->preg, NULL, 0);
1039
-		char *errbuf = cli_malloc(buflen);
1040
-		if(errbuf) {
1041
-			cli_regerror(rc, &regex->preg, errbuf, buflen);
1042
-			cli_errmsg(MODULE "Error compiling regular expression %s: %s\n", pattern, errbuf);
1043
-			free(errbuf);
1044
-		} else {
1045
-			cli_errmsg(MODULE "Error compiling regular expression: %s\n", pattern);
1046
-		}
1047
-		return rc;
1048 1037
 		cli_regfree(&regex->preg);
1049 1038
 		free(regex);
1050
-		return CL_EMALFDB;
1051 1039
 	}
1052
-	regex->pattern = cli_strdup(pattern);
1053
-	regex->nxt = NULL;
1054
-
1055
-	n = parse_regex(pattern, &last);
1056
-	memset(&buf, 0, sizeof(buf));
1057
-	memset(&root_node, 0, sizeof(buf));
1058
-	n->parent = &root_node;
1059 1040
 
1060
-	rc = build_suffixtree_descend(matcher, regex, n, &buf);
1061
-	destroy_tree(n);
1062 1041
 	return rc;
1063 1042
 }
... ...
@@ -29,12 +29,6 @@
29 29
 #include "matcher.h"
30 30
 #include <zlib.h> /* for gzFile */
31 31
 
32
-struct regex_list {
33
-	const char *pattern;
34
-	regex_t preg;
35
-	struct regex_list *nxt;
36
-};
37
-
38 32
 struct filter {
39 33
 	uint32_t B[65536];
40 34
 	uint32_t end_fast[256];
41 35
new file mode 100644
... ...
@@ -0,0 +1,448 @@
0
+/*
1
+ *  Parse a regular expression, and extract a static suffix.
2
+ *
3
+ *  Copyright (C) 2007-2008 Sourcefire, Inc.
4
+ *
5
+ *  Authors: Török Edvin
6
+ *
7
+ *  This program is free software; you can redistribute it and/or modify
8
+ *  it under the terms of the GNU General Public License version 2 as
9
+ *  published by the Free Software Foundation.
10
+ *
11
+ *  This program is distributed in the hope that it will be useful,
12
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
+ *  GNU General Public License for more details.
15
+ *
16
+ *  You should have received a copy of the GNU General Public License
17
+ *  along with this program; if not, write to the Free Software
18
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19
+ *  MA 02110-1301, USA.
20
+ */
21
+#if HAVE_CONFIG_H
22
+#include "clamav-config.h"
23
+#endif
24
+
25
+#ifndef CL_DEBUG
26
+#define NDEBUG
27
+#endif
28
+
29
+#include <stdio.h>
30
+#include <stdlib.h>
31
+#include <string.h>
32
+#include <assert.h>
33
+
34
+#include "others.h"
35
+#include "jsparse/textbuf.h"
36
+#include "regex_suffix.h"
37
+#define MODULE "regex_suffix: "
38
+
39
+
40
+enum node_type {
41
+	root=0,
42
+	concat,
43
+	alternate, /* | */
44
+	optional,/* ?, * */
45
+	leaf, /* a character */
46
+	leaf_class /* character class */
47
+	/* (x)+ is transformed into (x)*(x) */
48
+};
49
+
50
+struct node {
51
+	enum node_type type;
52
+	struct node *parent;
53
+	union {
54
+		struct {
55
+			struct node* left;
56
+			struct node* right;
57
+		} children;
58
+		uint8_t*    leaf_class_bitmap;
59
+		uint8_t     leaf_char;
60
+	} u;
61
+};
62
+
63
+/* --- Prototypes --*/
64
+static int build_suffixtree_descend(struct node *n, struct text_buffer *buf, suffix_callback cb, void *cbdata, struct regex_list *regex);
65
+/* -----------------*/
66
+
67
+static uint8_t dot_bitmap[32];
68
+
69
+static struct node* make_node(enum node_type type, struct node *left, struct node *right)
70
+{
71
+	struct node *n;
72
+	if(type == concat) {
73
+		if(left == NULL)
74
+			return right;
75
+		if(right == NULL)
76
+			return left;
77
+	}
78
+	n = cli_malloc(sizeof(*n));
79
+	if(!n)
80
+		return NULL;
81
+	n->type = type;
82
+	n->parent = NULL;
83
+	n->u.children.left = left;
84
+	n->u.children.right = right;
85
+	if(left)
86
+		left->parent = n;
87
+	if(right)
88
+		right->parent = n;
89
+	return n;
90
+}
91
+
92
+static struct node *dup_node(struct node *p)
93
+{
94
+	struct node *node_left, *node_right;
95
+	struct node *d;
96
+
97
+	if(!p)
98
+		return NULL;
99
+	d = cli_malloc(sizeof(*d));
100
+	if(!d)
101
+		return NULL;
102
+	d->type = p->type;
103
+	d->parent = NULL;
104
+	switch(p->type) {
105
+		case leaf:
106
+			d->u.leaf_char = p->u.leaf_char;
107
+			break;
108
+		case leaf_class:
109
+			d->u.leaf_class_bitmap = cli_malloc(32);
110
+			if(!d->u.leaf_class_bitmap)
111
+				return NULL;
112
+			memcpy(d->u.leaf_class_bitmap, p->u.leaf_class_bitmap, 32);
113
+			break;
114
+		default:
115
+			node_left = dup_node(p->u.children.left);
116
+			node_right = dup_node(p->u.children.right);
117
+			d->u.children.left = node_left;
118
+			d->u.children.right = node_right;
119
+			if(node_left)
120
+				node_left->parent = d;
121
+			if(node_right)
122
+				node_right->parent = d;
123
+			break;
124
+	}
125
+	return d;
126
+}
127
+
128
+static struct node *make_charclass(uint8_t *bitmap)
129
+{
130
+	struct node *v = cli_malloc(sizeof(*v));
131
+	if(!v)
132
+		return NULL;
133
+	v->type = leaf_class;
134
+	v->parent = NULL;
135
+	v->u.leaf_class_bitmap = bitmap;
136
+	return v;
137
+}
138
+
139
+static struct node *make_leaf(char c)
140
+{
141
+	struct node *v = cli_malloc(sizeof(*v));
142
+	if(!v)
143
+		return NULL;
144
+	v->type = leaf;
145
+	v->parent = NULL;
146
+	v->u.leaf_char = c;
147
+	return v;
148
+}
149
+
150
+static void destroy_tree(struct node *n)
151
+{
152
+	if(!n)
153
+		return;
154
+	switch(n->type) {
155
+		case concat:
156
+		case alternate:
157
+		case optional:
158
+			destroy_tree(n->u.children.left);
159
+			destroy_tree(n->u.children.right);
160
+			break;
161
+		case leaf_class:
162
+			if(n->u.leaf_class_bitmap != dot_bitmap)
163
+			  free(n->u.leaf_class_bitmap);
164
+			break;
165
+		case root:
166
+		case leaf:
167
+			break;
168
+	}
169
+	free(n);
170
+}
171
+
172
+static uint8_t* parse_char_class(const char *pat, size_t *pos)
173
+{
174
+	unsigned char range_start=0;
175
+	int hasprev = 0;
176
+	uint8_t* bitmap = cli_malloc(32);
177
+	if(!bitmap)
178
+		return NULL;
179
+	if (pat[*pos]=='^') {
180
+		memset(bitmap,0xFF,32);/*match chars not in brackets*/
181
+		++*pos;
182
+	}
183
+	else
184
+		memset(bitmap,0x00,32);
185
+	do {
186
+		/* literal ] can be first character, so test for it at the end of the loop, for example: []] */
187
+		if (pat[*pos]=='-' && hasprev) {
188
+			/* it is a range*/
189
+			unsigned char range_end;
190
+			unsigned int c;
191
+			assert(range_start);
192
+			++*pos;
193
+			if (pat[*pos]=='[')
194
+				if (pat[*pos+1]=='.') {
195
+					/* collating sequence not handled */
196
+					free(bitmap);
197
+					/* we are parsing the regex for a
198
+					 * filter, be conservative and
199
+					 * tell the filter that anything could
200
+					 * match here */
201
+					while(pat[*pos] != ']') ++*pos;
202
+					++*pos;
203
+					while(pat[*pos] != ']') ++*pos;
204
+					return dot_bitmap;
205
+				}
206
+				else
207
+					range_end = pat[*pos];
208
+			else
209
+				range_end = pat[*pos];
210
+			for(c=range_start+1;c<=range_end;c++)
211
+				bitmap[c>>3] ^= 1<<(c&0x7);
212
+			hasprev = 0;
213
+		}
214
+		else if (pat[*pos]=='[' && pat[*pos]==':') {
215
+			/* char class */
216
+			free(bitmap);
217
+			while(pat[*pos] != ']') ++*pos;
218
+			++*pos;
219
+			while(pat[*pos] != ']') ++*pos;
220
+			return dot_bitmap;
221
+		} else {
222
+			bitmap[pat[*pos]>>3] ^= 1<<(pat[*pos]&0x7);
223
+			++*pos;
224
+			range_start = pat[*pos];
225
+			hasprev = 1;
226
+		}
227
+	} while(pat[*pos]!=']');
228
+	return bitmap;
229
+}
230
+
231
+static struct node* parse_regex(const char *p, size_t *last)
232
+{
233
+	struct node *v = NULL;
234
+	struct node *right;
235
+	struct node *tmp;
236
+
237
+	while(p[*last] != '$' && p[*last] != '\0') {
238
+		switch(p[*last]) {
239
+			case '|':
240
+				++*last;
241
+				right = parse_regex(p, last);
242
+				v = make_node(alternate, v, right);
243
+				if(!v)
244
+					return NULL;
245
+				break;
246
+			case '*':
247
+			case '?':
248
+				v = make_node(optional, v, NULL);
249
+				if(!v)
250
+					return NULL;
251
+				++*last;
252
+				break;
253
+			case '+':
254
+				/* (x)* */
255
+				tmp = make_node(optional, v, NULL);
256
+				if(!tmp)
257
+					return NULL;
258
+				/* (x) */
259
+				right = dup_node(v);
260
+				if(!right)
261
+					return NULL;
262
+				/* (x)*(x) => (x)+ */
263
+				v = make_node(concat, tmp, right);
264
+				if(!v)
265
+					return NULL;
266
+				++*last;
267
+				break;
268
+			case '(':
269
+				++*last;
270
+				right = parse_regex(p, last);
271
+				if(!right)
272
+					return NULL;
273
+				++*last;
274
+				v = make_node(concat, v, right);
275
+				break;
276
+			case ')':
277
+				return v;
278
+			case '.':
279
+				right = make_charclass(dot_bitmap);
280
+				if(!right)
281
+					return NULL;
282
+				v = make_node(concat, v, right);
283
+				if(!v)
284
+					return NULL;
285
+				++*last;
286
+				break;
287
+			case '[':
288
+				right = make_charclass( parse_char_class(p, last) );
289
+				if(!right)
290
+					return NULL;
291
+				v = make_node(concat, v, right);
292
+				if(!v)
293
+					return NULL;
294
+			case '\\':
295
+				/* next char is escaped, advance pointer
296
+				 * and let fall-through handle it */
297
+				++*last;
298
+			default:
299
+				right = make_leaf(p[*last]);
300
+				v = make_node(concat, v, right);
301
+				if(!v)
302
+					return NULL;
303
+				++*last;
304
+				break;
305
+		}
306
+	}
307
+	return v;
308
+}
309
+
310
+#define BITMAP_HASSET(b, i) (b[i>>3] & (1<<(i&7)))
311
+
312
+static int build_suffixtree_ascend(struct node *n, struct text_buffer *buf, struct node *prev, suffix_callback cb, void *cbdata, struct regex_list *regex)
313
+{
314
+	size_t i;
315
+	while(n) {
316
+		struct node *q = n;
317
+		switch(n->type) {
318
+			case root:
319
+				textbuffer_putc(buf, '\0');
320
+				if(cb(cbdata, buf->data, buf->pos-1, regex) < 0)
321
+					return CL_EMEM;
322
+				return 0;
323
+			case leaf:
324
+				textbuffer_putc(buf, n->u.leaf_char);
325
+				n = n->parent;
326
+				break;
327
+			case leaf_class:
328
+				if(memcmp(n->u.leaf_class_bitmap, dot_bitmap, sizeof(dot_bitmap)) == 0) {
329
+					textbuffer_putc(buf, '\0');
330
+					if(cb(cbdata, buf->data, buf->pos-1, regex) < 0)
331
+						return CL_EMEM;
332
+					return 0;
333
+				}
334
+				for(i=0;i<255;i++) {
335
+					if(BITMAP_HASSET(n->u.leaf_class_bitmap, i)) {
336
+						size_t pos;
337
+						pos = buf->pos;
338
+						textbuffer_putc(buf, i);
339
+						if(build_suffixtree_ascend(n->parent, buf, n, cb, cbdata, regex) < 0)
340
+							return CL_EMEM;
341
+						buf->pos = pos;
342
+					}
343
+				}
344
+				return 0;
345
+			case concat:
346
+				if(prev != n->u.children.left) {
347
+					if(build_suffixtree_descend(n->u.children.left, buf, cb, cbdata, regex) < 0)
348
+						return CL_EMEM;
349
+					/* we're done here, descend will call
350
+					 * ascend if needed */
351
+					return 0;
352
+				} else {
353
+					n = n->parent;
354
+				}
355
+				break;
356
+			case alternate:
357
+				n = n->parent;
358
+				break;
359
+			case optional:
360
+				textbuffer_putc(buf, '\0');
361
+				if(cb(cbdata, buf->data, buf->pos-1, regex) < 0)
362
+					return CL_EMEM;
363
+				return 0;
364
+		}
365
+		prev = q;
366
+	}
367
+	return 0;
368
+}
369
+
370
+static int build_suffixtree_descend(struct node *n, struct text_buffer *buf, suffix_callback cb, void *cbdata, struct regex_list *regex)
371
+{
372
+	size_t pos;
373
+	while(n && n->type == concat) {
374
+		n = n->u.children.right;
375
+	}
376
+	if(!n)
377
+		return 0;
378
+	/* find out end of the regular expression,
379
+	 * if it ends with a static pattern */
380
+	switch(n->type) {
381
+		case alternate:
382
+			/* save pos as restart point */
383
+			pos = buf->pos;
384
+			if(build_suffixtree_descend(n->u.children.left, buf, cb, cbdata, regex) < 0)
385
+				return CL_EMEM;
386
+			buf->pos = pos;
387
+			if(build_suffixtree_descend(n->u.children.right, buf, cb, cbdata, regex) < 0)
388
+				return CL_EMEM;
389
+			buf->pos = pos;
390
+			break;
391
+		case optional:
392
+			textbuffer_putc(buf, '\0');
393
+			if(cb(cbdata, buf->data, buf->pos-1, regex) < 0)
394
+				return CL_EMEM;
395
+			return 0;
396
+		case leaf:
397
+		case leaf_class:
398
+			if(build_suffixtree_ascend(n, buf, NULL, cb, cbdata, regex) < 0)
399
+			        return CL_EMEM;
400
+			return 0;
401
+		default:
402
+			break;
403
+	}
404
+	return 0;
405
+}
406
+
407
+int cli_regex2suffix(const char *pattern, struct regex_list *regex, suffix_callback cb, void *cbdata)
408
+{
409
+	struct text_buffer buf;
410
+	struct node root_node;
411
+	struct node *n;
412
+	size_t last = 0;
413
+	int rc;
414
+
415
+	assert(regex && pattern);
416
+
417
+	rc = cli_regcomp(&regex->preg, pattern, REG_EXTENDED);
418
+	if(rc) {
419
+		size_t buflen = cli_regerror(rc, &regex->preg, NULL, 0);
420
+		char *errbuf = cli_malloc(buflen);
421
+		if(errbuf) {
422
+			cli_regerror(rc, &regex->preg, errbuf, buflen);
423
+			cli_errmsg(MODULE "Error compiling regular expression %s: %s\n", pattern, errbuf);
424
+			free(errbuf);
425
+		} else {
426
+			cli_errmsg(MODULE "Error compiling regular expression: %s\n", pattern);
427
+		}
428
+		return rc;
429
+	}
430
+#ifdef CL_DEBUG
431
+	regex->pattern = cli_strdup(pattern);
432
+#endif
433
+	regex->nxt = NULL;
434
+
435
+	n = parse_regex(pattern, &last);
436
+	if(!n)
437
+		return REG_ESPACE;
438
+	memset(&buf, 0, sizeof(buf));
439
+	memset(&root_node, 0, sizeof(buf));
440
+	n->parent = &root_node;
441
+
442
+	rc = build_suffixtree_descend(n, &buf, cb, cbdata, regex);
443
+	destroy_tree(n);
444
+	return rc;
445
+}
446
+
447
+
0 448
new file mode 100644
... ...
@@ -0,0 +1,35 @@
0
+/*
1
+ *  Parse a regular expression, and extract a static suffix.
2
+ *
3
+ *  Copyright (C) 2007-2008 Sourcefire, Inc.
4
+ *
5
+ *  Authors: Török Edvin
6
+ *
7
+ *  This program is free software; you can redistribute it and/or modify
8
+ *  it under the terms of the GNU General Public License version 2 as
9
+ *  published by the Free Software Foundation.
10
+ *
11
+ *  This program is distributed in the hope that it will be useful,
12
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
+ *  GNU General Public License for more details.
15
+ *
16
+ *  You should have received a copy of the GNU General Public License
17
+ *  along with this program; if not, write to the Free Software
18
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19
+ *  MA 02110-1301, USA.
20
+ */
21
+#ifndef REGEX_SUFFIX_H
22
+#define REGEX_SUFFIX_H
23
+#include "regex/regex.h"
24
+
25
+struct regex_list {
26
+#ifdef CL_DEBUG
27
+	const char *pattern;
28
+#endif
29
+	regex_t preg;
30
+	struct regex_list *nxt;
31
+};
32
+typedef int (*suffix_callback)(void *cbdata, const char *suffix, size_t len, struct regex_list *regex);
33
+int cli_regex2suffix(const char *pattern, struct regex_list *regex, suffix_callback cb, void *cbdata);
34
+#endif
... ...
@@ -9,7 +9,7 @@ else
9 9
 check_PROGRAMS = $(programs)
10 10
 check_SCRIPTS = $(scripts)
11 11
 endif
12
-check_clamav_SOURCES = check_clamav.c check_jsnorm.c check_str.c checks.h $(top_builddir)/libclamav/clamav.h
12
+check_clamav_SOURCES = check_clamav.c check_jsnorm.c check_str.c check_regex.c checks.h $(top_builddir)/libclamav/clamav.h
13 13
 check_clamav_CFLAGS = @CHECK_CFLAGS@
14 14
 check_clamav_LDADD = $(top_builddir)/libclamav/libclamav.la @THREAD_LIBS@ @CHECK_LIBS@
15 15
 
... ...
@@ -55,7 +55,8 @@ binPROGRAMS_INSTALL = $(INSTALL_PROGRAM)
55 55
 PROGRAMS = $(bin_PROGRAMS)
56 56
 am_check_clamav_OBJECTS = check_clamav-check_clamav.$(OBJEXT) \
57 57
 	check_clamav-check_jsnorm.$(OBJEXT) \
58
-	check_clamav-check_str.$(OBJEXT)
58
+	check_clamav-check_str.$(OBJEXT) \
59
+	check_clamav-check_regex.$(OBJEXT)
59 60
 check_clamav_OBJECTS = $(am_check_clamav_OBJECTS)
60 61
 check_clamav_DEPENDENCIES = $(top_builddir)/libclamav/libclamav.la
61 62
 check_clamav_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
... ...
@@ -219,7 +220,7 @@ programs = check_clamav
219 219
 scripts = check_clamd.sh check_freshclam.sh check_sigtool.sh check_clamscan.sh
220 220
 @ENABLE_UT_INSTALL_TRUE@dist_bin_SCRIPTS = $(scripts)
221 221
 @ENABLE_UT_INSTALL_FALSE@check_SCRIPTS = $(scripts)
222
-check_clamav_SOURCES = check_clamav.c check_jsnorm.c check_str.c checks.h $(top_builddir)/libclamav/clamav.h
222
+check_clamav_SOURCES = check_clamav.c check_jsnorm.c check_str.c check_regex.c checks.h $(top_builddir)/libclamav/clamav.h
223 223
 check_clamav_CFLAGS = @CHECK_CFLAGS@
224 224
 check_clamav_LDADD = $(top_builddir)/libclamav/libclamav.la @THREAD_LIBS@ @CHECK_LIBS@
225 225
 EXTRA_DIST = test-clamd.conf test-freshclam.conf
... ...
@@ -329,6 +330,7 @@ distclean-compile:
329 329
 
330 330
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/check_clamav-check_clamav.Po@am__quote@
331 331
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/check_clamav-check_jsnorm.Po@am__quote@
332
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/check_clamav-check_regex.Po@am__quote@
332 333
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/check_clamav-check_str.Po@am__quote@
333 334
 
334 335
 .c.o:
... ...
@@ -394,6 +396,20 @@ check_clamav-check_str.obj: check_str.c
394 394
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
395 395
 @am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(check_clamav_CFLAGS) $(CFLAGS) -c -o check_clamav-check_str.obj `if test -f 'check_str.c'; then $(CYGPATH_W) 'check_str.c'; else $(CYGPATH_W) '$(srcdir)/check_str.c'; fi`
396 396
 
397
+check_clamav-check_regex.o: check_regex.c
398
+@am__fastdepCC_TRUE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(check_clamav_CFLAGS) $(CFLAGS) -MT check_clamav-check_regex.o -MD -MP -MF $(DEPDIR)/check_clamav-check_regex.Tpo -c -o check_clamav-check_regex.o `test -f 'check_regex.c' || echo '$(srcdir)/'`check_regex.c
399
+@am__fastdepCC_TRUE@	mv -f $(DEPDIR)/check_clamav-check_regex.Tpo $(DEPDIR)/check_clamav-check_regex.Po
400
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='check_regex.c' object='check_clamav-check_regex.o' libtool=no @AMDEPBACKSLASH@
401
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
402
+@am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(check_clamav_CFLAGS) $(CFLAGS) -c -o check_clamav-check_regex.o `test -f 'check_regex.c' || echo '$(srcdir)/'`check_regex.c
403
+
404
+check_clamav-check_regex.obj: check_regex.c
405
+@am__fastdepCC_TRUE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(check_clamav_CFLAGS) $(CFLAGS) -MT check_clamav-check_regex.obj -MD -MP -MF $(DEPDIR)/check_clamav-check_regex.Tpo -c -o check_clamav-check_regex.obj `if test -f 'check_regex.c'; then $(CYGPATH_W) 'check_regex.c'; else $(CYGPATH_W) '$(srcdir)/check_regex.c'; fi`
406
+@am__fastdepCC_TRUE@	mv -f $(DEPDIR)/check_clamav-check_regex.Tpo $(DEPDIR)/check_clamav-check_regex.Po
407
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='check_regex.c' object='check_clamav-check_regex.obj' libtool=no @AMDEPBACKSLASH@
408
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
409
+@am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(check_clamav_CFLAGS) $(CFLAGS) -c -o check_clamav-check_regex.obj `if test -f 'check_regex.c'; then $(CYGPATH_W) 'check_regex.c'; else $(CYGPATH_W) '$(srcdir)/check_regex.c'; fi`
410
+
397 411
 mostlyclean-libtool:
398 412
 	-rm -f *.lo
399 413
 
... ...
@@ -298,6 +298,11 @@ static Suite *test_cli_suite(void)
298 298
     return s;
299 299
 }
300 300
 
301
+void errmsg_expected(void)
302
+{
303
+	fputs("cli_errmsg() expected here\n", stderr);
304
+}
305
+
301 306
 int main(int argc, char **argv)
302 307
 {
303 308
     int nf;
... ...
@@ -306,8 +311,11 @@ int main(int argc, char **argv)
306 306
     srunner_add_suite(sr, test_cli_suite());
307 307
     srunner_add_suite(sr, test_jsnorm_suite());
308 308
     srunner_add_suite(sr, test_str_suite());
309
+    srunner_add_suite(sr, test_regex_suite());
309 310
 
310 311
     srunner_set_log(sr, "test.log");
312
+    freopen("test-stderr.log","w+",stderr);
313
+
311 314
     srunner_run_all(sr, CK_NORMAL);
312 315
     nf = srunner_ntests_failed(sr);
313 316
     srunner_free(sr);
... ...
@@ -1,3 +1,24 @@
1
+/*
2
+ *  Unit tests for JS normalizer.
3
+ *
4
+ *  Copyright (C) 2008 Sourcefire, Inc.
5
+ *
6
+ *  Authors: Török Edvin
7
+ *
8
+ *  This program is free software; you can redistribute it and/or modify
9
+ *  it under the terms of the GNU General Public License version 2 as
10
+ *  published by the Free Software Foundation.
11
+ *
12
+ *  This program is distributed in the hope that it will be useful,
13
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
+ *  GNU General Public License for more details.
16
+ *
17
+ *  You should have received a copy of the GNU General Public License
18
+ *  along with this program; if not, write to the Free Software
19
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
20
+ *  MA 02110-1301, USA.
21
+ */
1 22
 #if HAVE_CONFIG_H
2 23
 #include "clamav-config.h"
3 24
 #endif
... ...
@@ -1,3 +1,24 @@
1
+/*
2
+ *  Unit tests for string functions. 
3
+ *
4
+ *  Copyright (C) 2008 Sourcefire, Inc.
5
+ *
6
+ *  Authors: Török Edvin
7
+ *
8
+ *  This program is free software; you can redistribute it and/or modify
9
+ *  it under the terms of the GNU General Public License version 2 as
10
+ *  published by the Free Software Foundation.
11
+ *
12
+ *  This program is distributed in the hope that it will be useful,
13
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
+ *  GNU General Public License for more details.
16
+ *
17
+ *  You should have received a copy of the GNU General Public License
18
+ *  along with this program; if not, write to the Free Software
19
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
20
+ *  MA 02110-1301, USA.
21
+ */
1 22
 #if HAVE_CONFIG_H
2 23
 #include "clamav-config.h"
3 24
 #endif
... ...
@@ -2,4 +2,6 @@
2 2
 #define CHECKS_H
3 3
 Suite *test_jsnorm_suite(void);
4 4
 Suite *test_str_suite(void);
5
+Suite *test_regex_suite(void);
6
+void errmsg_expected(void);
5 7
 #endif