2 * Copyright 2005 Timo Hirvonen
13 #include "ui_curses.h"
18 struct window
*filters_win
;
19 struct searchable
*filters_searchable
;
20 LIST_HEAD(filters_head
);
22 static const char *recursive_filter
;
24 static inline void filter_entry_to_iter(struct filter_entry
*e
, struct iter
*iter
)
26 iter
->data0
= &filters_head
;
31 static GENERIC_ITER_PREV(filters_get_prev
, struct filter_entry
, node
)
32 static GENERIC_ITER_NEXT(filters_get_next
, struct filter_entry
, node
)
34 static int filters_search_get_current(void *data
, struct iter
*iter
)
36 return window_get_sel(filters_win
, iter
);
39 static int filters_search_matches(void *data
, struct iter
*iter
, const char *text
)
41 char **words
= get_words(text
);
44 if (words
[0] != NULL
) {
45 struct filter_entry
*e
;
48 e
= iter_to_filter_entry(iter
);
50 if (words
[i
] == NULL
) {
51 window_set_sel(filters_win
, iter
);
55 if (u_strcasestr(e
->name
, words
[i
]) == NULL
)
59 free_str_array(words
);
63 static const struct searchable_ops filters_search_ops
= {
64 .get_prev
= filters_get_prev
,
65 .get_next
= filters_get_next
,
66 .get_current
= filters_search_get_current
,
67 .matches
= filters_search_matches
70 static void free_filter(struct filter_entry
*e
)
77 static struct filter_entry
*find_filter(const char *name
)
79 struct filter_entry
*e
;
81 list_for_each_entry(e
, &filters_head
, node
) {
82 if (strcmp(e
->name
, name
) == 0)
88 static const char *get_filter(const char *name
)
90 struct filter_entry
*e
= find_filter(name
);
94 recursive_filter
= e
->name
;
103 void filters_activate(void)
105 struct filter_entry
*f
;
106 struct expr
*e
, *expr
= NULL
;
108 /* mark visited and AND together all selected filters
109 * mark any other filters unvisited */
110 list_for_each_entry(f
, &filters_head
, node
) {
112 if (f
->sel_stat
== FS_IGNORE
)
116 e
= expr_parse(f
->filter
);
118 error_msg("error parsing filter %s: %s", f
->name
, expr_error());
124 if (f
->sel_stat
== FS_NO
) {
126 struct expr
*not = xnew(struct expr
, 1);
128 not->type
= EXPR_NOT
;
137 struct expr
*and = xnew(struct expr
, 1);
139 and->type
= EXPR_AND
;
149 recursive_filter
= NULL
;
150 if (expr
&& expr_check_leaves(&expr
, get_filter
)) {
151 if (recursive_filter
) {
152 error_msg("recursion detected in filter %s", recursive_filter
);
154 error_msg("error parsing filter: %s", expr_error());
160 /* update active flag */
161 list_for_each_entry(f
, &filters_head
, node
) {
162 f
->act_stat
= f
->sel_stat
;
164 lib_set_filter(expr
);
165 filters_win
->changed
= 1;
168 static int for_each_name(const char *str
, int (*cb
)(const char *name
, int sel_stat
))
175 int sel_stat
= FS_YES
;
178 while (str
[s
] == ' ')
185 while (str
[e
] && str
[e
] != ' ')
191 if (len
>= sizeof(buf
)) {
192 error_msg("filter name too long");
196 memcpy(buf
, str
+ s
, len
);
199 if (cb(buf
, sel_stat
))
204 static int ensure_filter_name(const char *name
, int sel_stat
)
206 if (find_filter(name
) == NULL
) {
207 error_msg("no such filter %s", name
);
213 static int select_filter(const char *name
, int sel_stat
)
215 struct filter_entry
*e
= find_filter(name
);
217 e
->sel_stat
= sel_stat
;
221 void filters_activate_names(const char *str
)
223 struct filter_entry
*f
;
225 /* first validate all filter names */
226 if (str
&& for_each_name(str
, ensure_filter_name
))
229 /* mark all filters unselected */
230 list_for_each_entry(f
, &filters_head
, node
)
231 f
->sel_stat
= FS_IGNORE
;
233 /* select the filters */
235 for_each_name(str
, select_filter
);
237 /* activate selected */
241 void filters_toggle_filter(void)
245 if (window_get_sel(filters_win
, &iter
)) {
246 struct filter_entry
*e
;
248 e
= iter_to_filter_entry(&iter
);
249 e
->sel_stat
= (e
->sel_stat
+ 1) % 3;
250 filters_win
->changed
= 1;
254 void filters_delete_filter(void)
258 if (window_get_sel(filters_win
, &iter
)) {
259 struct filter_entry
*e
;
261 e
= iter_to_filter_entry(&iter
);
262 if (yes_no_query("Delete filter '%s'? [y/N]", e
->name
)) {
263 window_row_vanishes(filters_win
, &iter
);
270 static int validate_filter_name(const char *name
)
274 for (i
= 0; name
[i
]; i
++) {
275 if (isalnum(name
[i
]))
277 if (name
[i
] == '_' || name
[i
] == '-')
284 static void do_filters_set_filter(const char *keyval
)
286 const char *eq
= strchr(keyval
, '=');
289 struct filter_entry
*new;
290 struct list_head
*item
;
294 error_msg("invalid argument ('key=value' expected)");
297 key
= xstrndup(keyval
, eq
- keyval
);
298 val
= xstrdup(eq
+ 1);
299 if (!validate_filter_name(key
)) {
301 error_msg("invalid filter name (can only contain 'a-zA-Z0-9_-' characters)");
306 expr
= expr_parse(val
);
309 error_msg("error parsing filter %s: %s", val
, expr_error());
316 new = xnew(struct filter_entry
, 1);
319 new->act_stat
= FS_IGNORE
;
320 new->sel_stat
= FS_IGNORE
;
322 /* add or replace filter */
323 list_for_each(item
, &filters_head
) {
324 struct filter_entry
*e
= container_of(item
, struct filter_entry
, node
);
325 int res
= strcmp(key
, e
->name
);
333 if (ui_initialized
) {
334 filter_entry_to_iter(e
, &iter
);
335 window_row_vanishes(filters_win
, &iter
);
343 /* add before item */
344 list_add_tail(&new->node
, item
);
346 window_changed(filters_win
);
349 void filters_init(void)
353 filters_win
= window_new(filters_get_prev
, filters_get_next
);
354 window_set_contents(filters_win
, &filters_head
);
355 window_changed(filters_win
);
357 iter
.data0
= &filters_head
;
360 filters_searchable
= searchable_new(NULL
, &iter
, &filters_search_ops
);
363 void filters_exit(void)
365 searchable_free(filters_searchable
);
366 window_free(filters_win
);
369 void filters_set_filter(const char *keyval
)
371 do_filters_set_filter(keyval
);
374 struct expr
*parse_filter(const char *val
)
376 struct expr
*e
= NULL
;
377 struct filter_entry
*f
;
382 error_msg("error parsing filter %s: %s", val
, expr_error());
387 /* mark all unvisited so that we can check recursion */
388 list_for_each_entry(f
, &filters_head
, node
)
391 recursive_filter
= NULL
;
392 if (e
&& expr_check_leaves(&e
, get_filter
)) {
393 if (recursive_filter
) {
394 error_msg("recursion detected in filter %s", recursive_filter
);
396 error_msg("error parsing filter: %s", expr_error());
404 void filters_set_anonymous(const char *val
)
406 struct filter_entry
*f
;
407 struct expr
*e
= NULL
;
410 e
= parse_filter(val
);
415 /* deactive all filters */
416 list_for_each_entry(f
, &filters_head
, node
)
417 f
->act_stat
= FS_IGNORE
;
421 filters_win
->changed
= 1;