source: filter.c @ 478dc8e

release-1.10
Last change on this file since 478dc8e was c068c03, checked in by Jason Gross <jgross@mit.edu>, 11 years ago
Fix some undefined behavior in filter.c, caught by clang scan-build
  • Property mode set to 100644
File size: 5.8 KB
Line 
1#include "owl.h"
2
3owl_filter *owl_filter_new_fromstring(const char *name, const char *string)
4{
5  owl_filter *f;
6  char **argv;
7  int argc;
8
9  argv = owl_parseline(string, &argc);
10  f = owl_filter_new(name, argc, strs(argv));
11  g_strfreev(argv);
12
13  return f;
14}
15
16owl_filter *owl_filter_new(const char *name, int argc, const char *const *argv)
17{
18  owl_filter *f;
19
20  f = g_new(owl_filter, 1);
21
22  f->name=g_strdup(name);
23  f->fgcolor=OWL_COLOR_DEFAULT;
24  f->bgcolor=OWL_COLOR_DEFAULT;
25
26  /* first take arguments that have to come first */
27  /* set the color */
28  while ( argc>=2 && ( !strcmp(argv[0], "-c") ||
29                       !strcmp(argv[0], "-b") ) ) {
30    if (owl_util_string_to_color(argv[1])==OWL_COLOR_INVALID) {
31      owl_function_error("The color '%s' is not available, using default.", argv[1]);
32    } else {
33      switch (argv[0][1]) {
34      case 'c':
35        f->fgcolor=owl_util_string_to_color(argv[1]);
36        break;
37      case 'b':
38        f->bgcolor=owl_util_string_to_color(argv[1]);
39        break;
40      }
41    }
42    argc-=2;
43    argv+=2;
44  }
45
46  if (!(f->root = owl_filter_parse_expression(argc, argv, NULL))) {
47    owl_filter_delete(f);
48    return NULL;
49  }
50
51  /* Now check for recursion. */
52  if (owl_filter_is_toodeep(f)) {
53    owl_function_error("Filter loop!");
54    owl_filter_delete(f);
55    return NULL;
56  }
57
58  return f;
59}
60
61
62/* A primitive expression is one without any toplevel ``and'' or ``or''s*/
63
64static owl_filterelement * owl_filter_parse_primitive_expression(int argc, const char *const *argv, int *next)
65{
66  owl_filterelement *fe, *op;
67  int i = 0, skip;
68
69  if(!argc) return NULL;
70
71  fe = g_new(owl_filterelement, 1);
72  owl_filterelement_create(fe);
73
74  if(!strcasecmp(argv[i], "(")) {
75    i++;
76    op = owl_filter_parse_expression(argc-i, argv+i, &skip);
77    if(!op) goto err;
78    i += skip;
79    if(i >= argc) goto err;
80    if(strcasecmp(argv[i++], ")")) goto err;
81    owl_filterelement_create_group(fe, op);
82  } else if(!strcasecmp(argv[i], "not")) {
83    i++;
84    op = owl_filter_parse_primitive_expression(argc-i, argv+i, &skip);
85    if(!op) goto err;
86    i += skip;
87    owl_filterelement_create_not(fe, op);
88  } else if(!strcasecmp(argv[i], "true")) {
89    i++;
90    owl_filterelement_create_true(fe);
91  } else if(!strcasecmp(argv[i], "false")) {
92    i++;
93    owl_filterelement_create_false(fe);
94  } else {
95    if(argc == 1) goto err;
96    if(!strcasecmp(*argv, "filter")) {
97      owl_filterelement_create_filter(fe, *(argv+1));
98    } else if(!strcasecmp(*argv, "perl")) {
99      owl_filterelement_create_perl(fe, *(argv+1));
100    } else {
101      if(owl_filterelement_create_re(fe, *argv, *(argv+1))) {
102        goto err;
103      }
104    }
105    i += 2;
106  }
107
108  if(next) {
109    *next = i;
110  } else if(i != argc) {
111    goto err;
112  }
113  return fe;
114err:
115  owl_filterelement_cleanup(fe);
116  g_free(fe);
117  return NULL;
118}
119
120owl_filterelement * owl_filter_parse_expression(int argc, const char *const *argv, int *next)
121{
122  int i = 0, skip;
123  owl_filterelement * op1 = NULL, * op2 = NULL, *tmp;
124
125  op1 = owl_filter_parse_primitive_expression(argc-i, argv+i, &skip);
126  if(!op1) goto err;
127  i += skip;
128
129  while(i < argc) {
130    if(strcasecmp(argv[i], "and") &&
131       strcasecmp(argv[i], "or")) break;
132    op2 = owl_filter_parse_primitive_expression(argc-i-1, argv+i+1, &skip);
133    if(!op2) goto err;
134    tmp = g_new(owl_filterelement, 1);
135    if(!strcasecmp(argv[i], "and")) {
136      owl_filterelement_create_and(tmp, op1, op2);
137    } else {
138      owl_filterelement_create_or(tmp, op1, op2);
139    }
140    op1 = tmp;
141    op2 = NULL;
142    i += skip+1;
143  }
144
145  if(next) {
146    *next = i;
147  } else if(i != argc) {
148    goto err;
149  }
150  return op1;
151err:
152  if(op1) {
153    owl_filterelement_cleanup(op1);
154    g_free(op1);
155  }
156  return NULL;
157}
158
159const char *owl_filter_get_name(const owl_filter *f)
160{
161  return(f->name);
162}
163
164SV *owl_filter_to_sv(const owl_filter *f)
165{
166  return owl_new_sv(owl_filter_get_name(f));
167}
168
169void owl_filter_set_fgcolor(owl_filter *f, int color)
170{
171  f->fgcolor=color;
172}
173
174int owl_filter_get_fgcolor(const owl_filter *f)
175{
176  return(f->fgcolor);
177}
178
179void owl_filter_set_bgcolor(owl_filter *f, int color)
180{
181  f->bgcolor=color;
182}
183
184int owl_filter_get_bgcolor(const owl_filter *f)
185{
186  return(f->bgcolor);
187}
188
189/* return 1 if the message matches the given filter, otherwise
190 * return 0.
191 */
192int owl_filter_message_match(const owl_filter *f, const owl_message *m)
193{
194  int ret;
195  if(!f->root) return 0;
196  ret = owl_filterelement_match(f->root, m);
197  return ret;
198}
199
200
201CALLER_OWN char *owl_filter_print(const owl_filter *f)
202{
203  GString *out = g_string_new("");
204
205  if (f->fgcolor!=OWL_COLOR_DEFAULT) {
206    g_string_append(out, "-c ");
207    if (f->fgcolor < 8) {
208      g_string_append(out, owl_util_color_to_string(f->fgcolor));
209    }
210    else {
211      g_string_append_printf(out, "%i",f->fgcolor);
212    }
213    g_string_append(out, " ");
214  }
215  if (f->bgcolor!=OWL_COLOR_DEFAULT) {
216    g_string_append(out, "-b ");
217    if (f->bgcolor < 8) {
218      g_string_append(out, owl_util_color_to_string(f->bgcolor));
219    }
220    else {
221      g_string_append_printf(out, "%i",f->bgcolor);
222    }
223    g_string_append(out, " ");
224  }
225  if(f->root) {
226    owl_filterelement_print(f->root, out);
227    g_string_append(out, "\n");
228  }
229
230  return g_string_free(out, 0);
231}
232
233/* Return 1 if the filters 'a' and 'b' are equivalent, 0 otherwise */
234int owl_filter_equiv(const owl_filter *a, const owl_filter *b)
235{
236  char *buffa, *buffb;
237  int ret;
238
239  buffa = owl_filter_print(a);
240  buffb = owl_filter_print(b);
241
242  ret = !strcmp(buffa, buffb);
243  ret = ret && !strcmp(owl_filter_get_name(a),
244                       owl_filter_get_name(b));
245
246  g_free(buffa);
247  g_free(buffb);
248
249  return ret;
250}
251
252
253int owl_filter_is_toodeep(const owl_filter *f)
254{
255  return owl_filterelement_is_toodeep(f, f->root);
256}
257
258void owl_filter_delete(owl_filter *f)
259{
260  if (f == NULL)
261    return;
262  if (f->root) {
263    owl_filterelement_cleanup(f->root);
264    g_free(f->root);
265  }
266  if (f->name)
267    g_free(f->name);
268  g_free(f);
269}
Note: See TracBrowser for help on using the repository browser.