source: filter.c @ 8fa9562

barnowl_perlaimdebianrelease-1.4release-1.5release-1.6release-1.7release-1.8release-1.9
Last change on this file since 8fa9562 was 8fa9562, checked in by Alejandro R. Sedeño <asedeno@mit.edu>, 14 years ago
Added background color support to owl. If we run out of color pairs during a painting of the screen, further background colors will be silently dropped. I'm hoping this doesn't happen often. The used pair list is reset with each draw, so only what's actually on screen matters.
  • Property mode set to 100644
File size: 8.2 KB
Line 
1#include <string.h>
2#include "owl.h"
3
4static const char fileIdent[] = "$Id$";
5
6#define OWL_FILTER_MAXRECURSE 20
7
8int owl_filter_init_fromstring(owl_filter *f, char *name, char *string)
9{
10  char **argv;
11  int argc, out;
12
13  argv=owl_parseline(string, &argc);
14  out=owl_filter_init(f, name, argc, argv);
15  /* owl_parsefree(argv, argc); */
16  return(out);
17}
18
19int owl_filter_init(owl_filter *f, char *name, int argc, char **argv)
20{
21  f->name=owl_strdup(name);
22  f->polarity=0;
23  f->fgcolor=OWL_COLOR_DEFAULT;
24  f->bgcolor=OWL_COLOR_DEFAULT;
25  f->cachedmsgid=-1;
26
27  /* first take arguments that have to come first */
28  /* set the color */
29  while ( argc>=2 && ( !strcmp(argv[0], "-c") ||
30                       !strcmp(argv[0], "-b") ) ) {
31    if (owl_util_string_to_color(argv[1])==-1) {
32      owl_function_error("The color '%s' is not available, using default.", argv[1]);
33    } else {
34      switch (argv[0][1]) {
35      case 'c':
36        f->fgcolor=owl_util_string_to_color(argv[1]);
37        break;
38      case 'b':
39        f->bgcolor=owl_util_string_to_color(argv[1]);
40        break;
41      }
42    }
43    argc-=2;
44    argv+=2;
45  }
46
47  if(!(f->root = owl_filter_parse_expression(argc, argv, NULL)))
48    return(-1);
49
50  /* Now check for recursion. */
51  if (owl_filter_is_toodeep(f)) {
52    owl_function_error("Filter loop or exceeds recursion depth");
53    owl_filter_free(f);
54    return(-1);
55  }
56
57  return(0);
58}
59
60
61/* A primitive expression is one without any toplevel ``and'' or ``or''s*/
62
63static owl_filterelement * owl_filter_parse_primitive_expression(int argc, char **argv, int *next)
64{
65  if(!argc) return NULL;
66
67  owl_filterelement * fe = owl_malloc(sizeof(owl_filterelement));
68  owl_filterelement *op;
69
70  owl_filterelement_create(fe);
71  int i = 0, skip;
72
73  if(!strcasecmp(argv[i], "(")) {
74    i++;
75    op = owl_filter_parse_expression(argc-i, argv+i, &skip);
76    if(!op) goto err;
77    i += skip;
78    if(strcasecmp(argv[i++], ")")) goto err;
79    owl_filterelement_create_group(fe, op);
80  } else if(!strcasecmp(argv[i], "not")) {
81    i++;
82    op = owl_filter_parse_primitive_expression(argc-i, argv+i, &skip);
83    if(!op) goto err;
84    i += skip;
85    owl_filterelement_create_not(fe, op);
86  } else if(!strcasecmp(argv[i], "true")) {
87    i++;
88    owl_filterelement_create_true(fe);
89  } else if(!strcasecmp(argv[i], "false")) {
90    i++;
91    owl_filterelement_create_false(fe);
92  } else {
93    if(argc == 1) goto err;
94    if(!strcasecmp(*argv, "filter")) {
95      owl_filterelement_create_filter(fe, *(argv+1));
96    } else if(!strcasecmp(*argv, "perl")) {
97      owl_filterelement_create_perl(fe, *(argv+1));
98    } else {
99      owl_filterelement_create_re(fe, *argv, *(argv+1));
100    }
101    i += 2;
102  }
103
104  if(next) {
105    *next = i;
106  } else if(i != argc) {
107    goto err;
108  }
109  return fe;
110err:
111  owl_filterelement_free(fe);
112  owl_free(fe);
113  return NULL;
114}
115
116owl_filterelement * owl_filter_parse_expression(int argc, char **argv, int *next)
117{
118  int i = 0, skip;
119  owl_filterelement * op1 = NULL, * op2 = NULL;
120
121  op1 = owl_filter_parse_primitive_expression(argc-i, argv+i, &skip);
122  i += skip;
123  if(!op1) goto err;
124
125  while(i < argc) {
126    if(strcasecmp(argv[i], "and") &&
127       strcasecmp(argv[i], "or")) break;
128    op2 = owl_filter_parse_primitive_expression(argc-i-1, argv+i+1, &skip);
129    if(!op2) goto err;
130    owl_filterelement * tmp = owl_malloc(sizeof(owl_filterelement));
131    if(!strcasecmp(argv[i], "and")) {
132      owl_filterelement_create_and(tmp, op1, op2);
133    } else {
134      owl_filterelement_create_or(tmp, op1, op2);
135    }
136    op1 = tmp;
137    op2 = NULL;
138    i += skip+1;
139  }
140
141  if(next) {
142    *next = i;
143  } else if(i != argc) {
144    goto err;
145  }
146  return op1;
147err:
148  if(op1) {
149    owl_filterelement_free(op1);
150    owl_free(op1);
151  }
152  return NULL;
153}
154
155char *owl_filter_get_name(owl_filter *f)
156{
157  return(f->name);
158}
159
160void owl_filter_set_polarity_match(owl_filter *f)
161{
162  f->polarity=0;
163}
164
165void owl_filter_set_polarity_unmatch(owl_filter *f)
166{
167  f->polarity=1;
168}
169
170void owl_filter_set_fgcolor(owl_filter *f, int color)
171{
172  f->fgcolor=color;
173}
174
175int owl_filter_get_fgcolor(owl_filter *f)
176{
177  return(f->fgcolor);
178}
179
180void owl_filter_set_bgcolor(owl_filter *f, int color)
181{
182  f->bgcolor=color;
183}
184
185int owl_filter_get_bgcolor(owl_filter *f)
186{
187  return(f->bgcolor);
188}
189
190void owl_filter_set_cachedmsgid(owl_filter *f, int cachedmsgid)
191{
192  f->cachedmsgid=cachedmsgid;
193}
194
195int owl_filter_get_cachedmsgid(owl_filter *f)
196{
197  return(f->cachedmsgid);
198}
199
200/* return 1 if the message matches the given filter, otherwise
201 * return 0.
202 */
203int owl_filter_message_match(owl_filter *f, owl_message *m)
204{
205  if(!f->root) return 0;
206  int ret = owl_filterelement_match(f->root, m);
207  if(f->polarity) ret = !ret;
208  return ret;
209}
210
211
212void owl_filter_print(owl_filter *f, char *out)
213{
214  strcpy(out, owl_filter_get_name(f));
215  strcat(out, ": ");
216
217  if (f->fgcolor!=OWL_COLOR_DEFAULT) {
218    strcat(out, "-c ");
219    strcat(out, owl_util_color_to_string(f->fgcolor));
220    strcat(out, " ");
221  }
222  if (f->bgcolor!=OWL_COLOR_DEFAULT) {
223    strcat(out, "-b ");
224    strcat(out, owl_util_color_to_string(f->bgcolor));
225    strcat(out, " ");
226  }
227  if(!f->root) return;
228  owl_filterelement_print(f->root, out);
229  strcat(out, "\n");
230}
231
232/* Return 1 if the filters 'a' and 'b' are equivalent, 0 otherwise */
233int owl_filter_equiv(owl_filter *a, owl_filter *b)
234{
235  char buff[LINE], buff2[LINE];
236
237  owl_filter_print(a, buff);
238  owl_filter_print(b, buff2);
239
240  if (!strcmp(buff, buff2)) return(1);
241  return(0);
242}
243
244
245int owl_filter_is_toodeep(owl_filter *f)
246{
247  return owl_filterelement_is_toodeep(f, f->root);
248}
249
250void owl_filter_free(owl_filter *f)
251{
252  if(f->root) {
253    owl_filterelement_free(f->root);
254    owl_free(f->root);
255  }
256  if (f->name) owl_free(f->name);
257}
258
259/**************************************************************************/
260/************************* REGRESSION TESTS *******************************/
261/**************************************************************************/
262
263#ifdef OWL_INCLUDE_REG_TESTS
264
265int owl_filter_test_string(char * filt, owl_message *m, int shouldmatch) /* noproto */ {
266  owl_filter f;
267  int ok;
268  int failed = 0;
269  if(owl_filter_init_fromstring(&f, "test-filter", filt)) {
270    printf("\tFAIL: parse %s\n", filt);
271    failed = 1;
272    goto out;
273  }
274  ok = owl_filter_message_match(&f, m);
275  if((shouldmatch && !ok) || (!shouldmatch && ok)) {
276    printf("\tFAIL: match %s (got %d, expected %d)\n", filt, ok, shouldmatch);
277    failed = 1;
278  }
279 out:
280  owl_filter_free(&f);
281  if(!failed) {
282    printf("\tok  : %s %s\n", shouldmatch ? "matches" : "doesn't match", filt);
283  }
284  return failed;
285}
286
287
288#include "test.h"
289
290
291int owl_filter_regtest(void) {
292  owl_list_create(&(g.filterlist));
293  int numfailed=0;
294  owl_message m;
295  owl_message_init(&m);
296  owl_message_set_type_zephyr(&m);
297  owl_message_set_direction_in(&m);
298  owl_message_set_class(&m, "owl");
299  owl_message_set_instance(&m, "tester");
300  owl_message_set_sender(&m, "owl-user");
301  owl_message_set_recipient(&m, "joe");
302  owl_message_set_attribute(&m, "foo", "bar");
303
304#define TEST_FILTER(f, e) numfailed += owl_filter_test_string(f, &m, e)
305
306
307  TEST_FILTER("true", 1);
308  TEST_FILTER("false", 0);
309  TEST_FILTER("( true )", 1);
310  TEST_FILTER("not false", 1);
311  TEST_FILTER("( true ) or ( false )", 1);
312  TEST_FILTER("true and false", 0);
313  TEST_FILTER("( true or true ) or ( ( false ) )", 1);
314
315  TEST_FILTER("class owl", 1);
316  TEST_FILTER("class ^owl$", 1);
317  TEST_FILTER("instance test", 1);
318  TEST_FILTER("instance ^test$", 0);
319  TEST_FILTER("instance ^tester$", 1);
320
321  TEST_FILTER("foo bar", 1);
322  TEST_FILTER("class owl and instance tester", 1);
323  TEST_FILTER("type ^zephyr$ and direction ^in$ and ( class ^owl$ or instance ^owl$ )", 1);
324
325  // Order of operations and precedence
326  TEST_FILTER("not true or false", 0);
327  TEST_FILTER("true or true and false", 0);
328  TEST_FILTER("true and true and false or true", 1);
329  TEST_FILTER("false and false or true", 1);
330  TEST_FILTER("true and false or false", 0);
331
332  owl_filter f1, f2, f3, f4;
333
334  owl_filter_init_fromstring(&f1, "f1", "class owl");
335  owl_global_add_filter(&g, &f1);
336  TEST_FILTER("filter f1", 1);
337
338  // Test recursion prevention
339  FAIL_UNLESS("self reference", owl_filter_init_fromstring(&f2, "test", "filter test"));
340
341  // mutual recursion
342  owl_filter_init_fromstring(&f3, "f3", "filter f4");
343  owl_global_add_filter(&g, &f3);
344  FAIL_UNLESS("mutual recursion",   owl_filter_init_fromstring(&f4, "f4", "filter f3"));
345
346  return 0;
347}
348
349
350#endif /* OWL_INCLUDE_REG_TESTS */
Note: See TracBrowser for help on using the repository browser.