diff options
-rw-r--r-- | filter/ChangeLog | 4 | ||||
-rw-r--r-- | filter/Makefile | 21 | ||||
-rw-r--r-- | filter/filter-arg-types.c | 289 | ||||
-rw-r--r-- | filter/filter-arg-types.h | 32 | ||||
-rw-r--r-- | filter/filter-arg.c | 9 | ||||
-rw-r--r-- | filter/filter-arg.h | 2 | ||||
-rw-r--r-- | filter/filter-driver.c | 386 | ||||
-rw-r--r-- | filter/filter-format.c | 235 | ||||
-rw-r--r-- | filter/filter-format.h | 10 | ||||
-rw-r--r-- | filter/filter-sexp.c | 25 | ||||
-rw-r--r-- | filter/filter-xml.c | 261 | ||||
-rw-r--r-- | filter/filter-xml.h | 11 |
12 files changed, 955 insertions, 330 deletions
diff --git a/filter/ChangeLog b/filter/ChangeLog index aa6d977034..a87ffb2a4f 100644 --- a/filter/ChangeLog +++ b/filter/ChangeLog @@ -1,3 +1,7 @@ +2000-02-18 NotZed <NotZed@HelixCode.com> + + * Uh, more changes, lots, its still work in progress. + 2000-02-14 NotZed <notzed@helixcode.com> * Initial import. diff --git a/filter/Makefile b/filter/Makefile index 2527224874..745574c108 100644 --- a/filter/Makefile +++ b/filter/Makefile @@ -1,11 +1,22 @@ -OBJS = filter-arg-types.o filter-arg.o filter-xml.o filter-sexp.o filter-driver.o -SRCS = filter-arg-types.c filter-arg.c filter-xml.c filter-sexp.c filter-driver.c +OBJS = filter-arg-types.lo filter-arg.lo filter-xml.lo filter-driver.lo filter-format.lo +SRCS = filter-arg-types.c filter-arg.c filter-xml.c filter-driver.c filter-format.c + +LIBFILTEROBJS = filter-sexp.lo +LIBFILTERSRCS = filter-sexp.c + +LIBTOOL=sh ../libtool CFLAGS = `gnome-config --cflags xml gnome gtk gtkhtml gnomeui` -g -I../camel -I .. -I../libibex -LDFLAGS = `gnome-config --libs xml gnome gtk gtkhtml gnomeui` -L ../camel/.libs -lcamel +LDFLAGS = `gnome-config --libs xml gnome gtk gtkhtml gnomeui` ../camel/libcamel.la -lpthread + +all: libfilter.la filter-driver -all: filter-driver +filter-driver: $(OBJS) libfilter.la + $(LIBTOOL) --mode link $(CC) $^ -o $@ $(LDFLAGS) -filter-driver: $(OBJS) +libfilter.la: $(LIBFILTEROBJS) + $(LIBTOOL) --mode link $(CC) -static $^ -o $@ +%.lo: %.c + $(LIBTOOL) --mode compile $(CC) $(CFLAGS) -c -o $@ $< diff --git a/filter/filter-arg-types.c b/filter/filter-arg-types.c index 5b046d9ea6..ce6eac7003 100644 --- a/filter/filter-arg-types.c +++ b/filter/filter-arg-types.c @@ -20,8 +20,188 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include <gnome.h> + #include "filter-arg-types.h" + +/* ********************************************************************** */ +/* String */ +/* ********************************************************************** */ + +/* Use for a superclass of any items which are simple strings */ + +static void filter_arg_string_class_init (FilterArgStringClass *class); +static void filter_arg_string_init (FilterArgString *gspaper); + +static FilterArg *string_parent_class; + +guint +filter_arg_string_get_type (void) +{ + static guint type = 0; + + if (!type) { + GtkTypeInfo type_info = { + "FilterArgString", + sizeof (FilterArgString), + sizeof (FilterArgStringClass), + (GtkClassInitFunc) filter_arg_string_class_init, + (GtkObjectInitFunc) filter_arg_string_init, + (GtkArgSetFunc) NULL, + (GtkArgGetFunc) NULL + }; + + type = gtk_type_unique (filter_arg_get_type (), &type_info); + } + + return type; +} + +static void +arg_string_write_html(FilterArg *argin, GtkHTML *html, GtkHTMLStreamHandle *stream) +{ + FilterArgString *arg = (FilterArgString *)argin; + /* empty */ +} + +static void +arg_string_write_text(FilterArg *argin, GString *string) +{ + FilterArgString *arg = (FilterArgString *)argin; + GList *l; + char *a; + + l = argin->values; + if (l == NULL) { + g_string_append(string, "folder"); + } + while (l) { + a = l->data; + g_string_append(string, a); + if (l->next) { + g_string_append(string, ", "); + } + l = g_list_next(l); + } +} + +static void +arg_string_edit_values(FilterArg *arg) +{ + printf("edit string value!\n"); +} + +static xmlNodePtr +arg_string_values_get_xml(FilterArg *argin) +{ + xmlNodePtr value; + FilterArgString *arg = (FilterArgString *)argin; + GList *l; + char *a; + + value = xmlNewNode(NULL, "optionvalue"); + xmlSetProp(value, "name", argin->name); + + l = argin->values; + while (l) { + xmlNodePtr cur; + + a = l->data; + + cur = xmlNewChild(value, NULL, "folder", NULL); + if (a) + xmlSetProp(cur, "folder", a); + l = g_list_next(l); + } + + return value; +} + +static void +arg_string_values_add_xml(FilterArg *arg, xmlNodePtr node) +{ + xmlNodePtr n; + + n = node->childs; + while (n) { + if (!strcmp(n->name, "folder")) { + filter_arg_string_add(arg, xmlGetProp(n, "folder")); + } else { + g_warning("Loading folders from xml, wrong node encountered: %s\n", n->name); + } + n = n->next; + } +} + +static char * +arg_string_get_value_as_string(FilterArg *argin, void *data) +{ + FilterArgString *arg = (FilterArgString *)argin; + char *a = (char *)data; + + return a; +} + +static void +arg_string_free_value(FilterArg *arg, void *a) +{ + g_free(a); +} + +static void +filter_arg_string_class_init (FilterArgStringClass *class) +{ + GtkObjectClass *object_class; + + object_class = (GtkObjectClass *) class; + if (string_parent_class == NULL) + string_parent_class = gtk_type_class (gtk_object_get_type ()); + + class->parent_class.write_html = arg_string_write_html; + class->parent_class.write_text = arg_string_write_text; + class->parent_class.edit_values = arg_string_edit_values; + class->parent_class.free_value = arg_string_free_value; + + class->parent_class.values_get_xml = arg_string_values_get_xml; + class->parent_class.values_add_xml = arg_string_values_add_xml; +} + +static void +filter_arg_string_init (FilterArgString *arg) +{ + arg->arg.values = NULL; +} + +/** + * filter_arg_string_new: + * + * Create a new FilterArgString widget. + * + * Return value: A new FilterArgString widget. + **/ +FilterArg * +filter_arg_string_new (char *name) +{ + FilterArg *a = FILTER_ARG ( gtk_type_new (filter_arg_string_get_type ())); + a->name = g_strdup(name); + return a; +} + + +void +filter_arg_string_add(FilterArg *arg, char *name) +{ + filter_arg_add(arg, g_strdup(name)); +} + +void +filter_arg_string_remove(FilterArg *arg, char *name) +{ + /* do it */ +} + + /* ********************************************************************** */ /* Address */ /* ********************************************************************** */ @@ -180,7 +360,6 @@ filter_arg_address_class_init (FilterArgAddressClass *class) static void filter_arg_address_init (FilterArgAddress *arg) { - arg->arg.values = NULL; } /** @@ -225,7 +404,7 @@ filter_arg_address_remove(FilterArg *arg, char *name, char *email) static void filter_arg_folder_class_init (FilterArgFolderClass *class); static void filter_arg_folder_init (FilterArgFolder *gspaper); -static FilterArg *parent_class; +static FilterArg *folder_parent_class; guint filter_arg_folder_get_type (void) @@ -243,7 +422,7 @@ filter_arg_folder_get_type (void) (GtkArgGetFunc) NULL }; - type = gtk_type_unique (filter_arg_get_type (), &type_info); + type = gtk_type_unique (filter_arg_string_get_type (), &type_info); } return type; @@ -278,9 +457,79 @@ arg_folder_write_text(FilterArg *argin, GString *string) } static void -arg_folder_edit_values(FilterArg *arg) +arg_folder_edit_values(FilterArg *argin) { - printf("edit it!\n"); + FilterArgFolder *arg = (FilterArgFolder *)argin; + GList *l; + char *a, *start, *ptr, *ptrend, *ptrgap; + char outbuf[128], *outptr; /* FIXME: dont use a bounded buffer! */ + GString *string = g_string_new(""); + GtkWidget *dialogue; + GtkWidget *text; + + dialogue = gnome_dialog_new("Edit addresses", + "Ok", "Cancel", NULL); + text = gtk_text_new(NULL, NULL); + gtk_object_ref(text); + + l = argin->values; + while (l) { + a = l->data; + gtk_text_insert(text, NULL, NULL, NULL, a, strlen(a)); + gtk_text_insert(text, NULL, NULL, NULL, "\n", 1); + l = g_list_next(l); + } + + gtk_box_pack_start(GNOME_DIALOG(dialogue)->vbox, text, TRUE, TRUE, 2); + gtk_widget_show(text); + gtk_text_set_editable(text, 1); + + gnome_dialog_run_and_close(dialogue); + + /* FIXME: free current values */ + argin->values = NULL; + ptr = GTK_TEXT(text)->text.ch; + ptrend = ptr+GTK_TEXT(text)->text_end; + ptrgap = ptr+GTK_TEXT(text)->gap_position; + + start = ptr; + outptr = outbuf; + while (ptr<ptrend) { + printf("%c", *ptr); + if (*ptr == '\n') { + int len = outptr-outbuf; + char *new; + + printf("(len = %d)", len); + + if (len>0) { + new = g_malloc(len+1); + new[len]=0; + memcpy(new, outbuf, len); + printf("(appending '%s')", new); + argin->values = g_list_append(argin->values, new); + } + outptr = outbuf; + } else { + *outptr++ = *ptr; + } + ptr++; + if (ptr==ptrgap) { + ptr += GTK_TEXT(text)->gap_size; + } + } + if (outptr>outbuf) { + int len = outptr-outbuf; + char *new; + + printf("(lastlen = %d)", len); + + new = g_malloc(len+1); + new[len]=0; + memcpy(new, start, len); + argin->values = g_list_append(argin->values, new); + } + printf("\n"); } static xmlNodePtr @@ -314,10 +563,12 @@ arg_folder_values_add_xml(FilterArg *arg, xmlNodePtr node) { xmlNodePtr n; + printf("adding folder values ...\n"); + n = node->childs; while (n) { if (!strcmp(n->name, "folder")) { - filter_arg_folder_add(arg, xmlGetProp(n, "folder")); + filter_arg_folder_add(arg, xmlGetProp(n, "name")); } else { g_warning("Loading folders from xml, wrong node encountered: %s\n", n->name); } @@ -344,24 +595,26 @@ static void filter_arg_folder_class_init (FilterArgFolderClass *class) { GtkObjectClass *object_class; - - object_class = (GtkObjectClass *) class; - if (parent_class == NULL) - parent_class = gtk_type_class (gtk_object_get_type ()); - - class->parent_class.write_html = arg_folder_write_html; - class->parent_class.write_text = arg_folder_write_text; - class->parent_class.edit_values = arg_folder_edit_values; - class->parent_class.free_value = arg_folder_free_value; + FilterArgClass *filter_class; - class->parent_class.values_get_xml = arg_folder_values_get_xml; - class->parent_class.values_add_xml = arg_folder_values_add_xml; + object_class = (GtkObjectClass *) class; + filter_class = (FilterArgClass *) class; + if (folder_parent_class == NULL) + folder_parent_class = gtk_type_class (filter_arg_string_get_type ()); + + /* FIXME: only need to over-ride the edit values right? */ + filter_class->write_html = arg_folder_write_html; + filter_class->write_text = arg_folder_write_text; + filter_class->edit_values = arg_folder_edit_values; + filter_class->free_value = arg_folder_free_value; + + filter_class->values_get_xml = arg_folder_values_get_xml; + filter_class->values_add_xml = arg_folder_values_add_xml; } static void filter_arg_folder_init (FilterArgFolder *arg) { - arg->arg.values = NULL; } /** diff --git a/filter/filter-arg-types.h b/filter/filter-arg-types.h index 26ee280a55..6a1d80bfae 100644 --- a/filter/filter-arg-types.h +++ b/filter/filter-arg-types.h @@ -51,7 +51,32 @@ FilterArg *filter_arg_address_new (char *name); void filter_arg_address_add(FilterArg *, char *name, char *email); void filter_arg_address_remove(FilterArg *, char *name, char *email); -/* A Folder */ +/* A simple String */ +#define FILTER_ARG_STRING(obj) GTK_CHECK_CAST (obj, filter_arg_string_get_type (), FilterArgString) +#define FILTER_ARG_STRING_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, filter_arg_string_get_type (), FilterArgStringClass) +#define IS_FILTER_ARG_STRING(obj) GTK_CHECK_TYPE (obj, filter_arg_string_get_type ()) + +typedef struct _FilterArgString FilterArgString; +typedef struct _FilterArgStringClass FilterArgStringClass; + +struct _FilterArgString { + FilterArg arg; + + /* Name/property to save/load to xml */ + /* char *xmlname; */ + /* char *xmlprop; */ +}; + +struct _FilterArgStringClass { + FilterArgClass parent_class; +}; + +guint filter_arg_string_get_type (void); +FilterArg *filter_arg_string_new (char *name); +void filter_arg_string_add(FilterArg *, char *name); +void filter_arg_string_remove(FilterArg *, char *name); + +/* A Folder, subclass of a string */ #define FILTER_ARG_FOLDER(obj) GTK_CHECK_CAST (obj, filter_arg_folder_get_type (), FilterArgFolder) #define FILTER_ARG_FOLDER_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, filter_arg_folder_get_type (), FilterArgFolderClass) #define IS_FILTER_ARG_FOLDER(obj) GTK_CHECK_TYPE (obj, filter_arg_folder_get_type ()) @@ -60,11 +85,11 @@ typedef struct _FilterArgFolder FilterArgFolder; typedef struct _FilterArgFolderClass FilterArgFolderClass; struct _FilterArgFolder { - FilterArg arg; + FilterArgString arg; }; struct _FilterArgFolderClass { - FilterArgClass parent_class; + FilterArgStringClass parent_class; }; guint filter_arg_folder_get_type (void); @@ -73,3 +98,4 @@ void filter_arg_folder_add(FilterArg *, char *name); void filter_arg_folder_remove(FilterArg *, char *name); #endif /* ! _FILTER_ARG_TYPES_H */ + diff --git a/filter/filter-arg.c b/filter/filter-arg.c index 44dc90471e..55bc09c6a0 100644 --- a/filter/filter-arg.c +++ b/filter/filter-arg.c @@ -135,6 +135,8 @@ filter_arg_new (char *name) void filter_arg_add(FilterArg *arg, void *v) { + g_return_if_fail(v != NULL); + arg->values = g_list_append(arg->values, v); gtk_signal_emit(GTK_OBJECT(arg), signals[CHANGED]); } @@ -160,7 +162,12 @@ filter_arg_write_text(FilterArg *arg, GString *string) void filter_arg_edit_values(FilterArg *arg) { - ((FilterArgClass *)(arg->object.klass))->edit_values(arg); + g_return_if_fail(arg != NULL); + + if (((FilterArgClass *)(arg->object.klass))->edit_values) + ((FilterArgClass *)(arg->object.klass))->edit_values(arg); + else + g_warning("No implementation of virtual method edit_values"); } xmlNodePtr diff --git a/filter/filter-arg.h b/filter/filter-arg.h index ecdba3436d..95e7d1caea 100644 --- a/filter/filter-arg.h +++ b/filter/filter-arg.h @@ -63,6 +63,8 @@ guint filter_arg_get_type (void); FilterArg *filter_arg_new (char *name); void filter_arg_value_add(FilterArg *a, void *v); +void filter_arg_edit_values(FilterArg *arg); + xmlNodePtr filter_arg_values_get_xml(FilterArg *arg); void filter_arg_values_add_xml(FilterArg *arg, xmlNodePtr node); int filter_arg_get_count(FilterArg *arg); diff --git a/filter/filter-driver.c b/filter/filter-driver.c index 6df07e76b8..b51e3f0705 100644 --- a/filter/filter-driver.c +++ b/filter/filter-driver.c @@ -10,19 +10,23 @@ #include "filter-arg-types.h" #include "filter-xml.h" #include "filter-sexp.h" +#include "filter-format.h" extern int filter_find_arg(FilterArg *a, char *name); +#include "check.xpm" +#include "blank.xpm" + /* splices ${cc} lines into a single string */ int -expand_variables(GString *out, char *source, GList *args, int index) +expand_variables(GString *out, char *source, GList *args, GHashTable *globals) { GList *argl; FilterArg *arg; char *name= alloca(32); - char *start, *end, *newstart, *tmp; + char *start, *end, *newstart, *tmp, *val; int namelen=32; int len=0; int ok = 0; @@ -37,13 +41,31 @@ expand_variables(GString *out, char *source, GList *args, int index) } memcpy(name, newstart+2, len); name[len] = 0; - argl = g_list_find_custom(args, name, filter_find_arg); + argl = g_list_find_custom(args, name, (GCompareFunc) filter_find_arg); if (argl) { + int i, count; + + tmp = g_strdup_printf("%.*s", newstart-start, start); + printf("appending: %s\n", tmp); + g_string_append(out, tmp); + g_free(tmp); + arg = argl->data; - tmp = g_strdup_printf("%.*s%s", newstart-start, start, filter_arg_get_value_as_string(arg, index)); + count = filter_arg_get_count(arg); + for (i=0;i<count;i++) { + printf("appending '%s'\n", filter_arg_get_value_as_string(arg, i)); + g_string_append(out, " \""); + g_string_append(out, filter_arg_get_value_as_string(arg, i)); + g_string_append(out, "\""); + } + } else if ( (val = g_hash_table_lookup(globals, name)) ) { + tmp = g_strdup_printf("%.*s", newstart-start, start); printf("appending: %s\n", tmp); g_string_append(out, tmp); g_free(tmp); + g_string_append(out, " \""); + g_string_append(out, val); + g_string_append(out, "\""); } else { ok = 1; tmp = g_strdup_printf("%.*s", end-start+1, start); @@ -66,54 +88,23 @@ expand_filter_option(GString *s, struct filter_option *op) { GList *optionl; FilterArg *arg; + GHashTable *globals; + + globals = g_hash_table_new(g_str_hash, g_str_equal); + + g_hash_table_insert(globals, "self-email", "mzucchi@dehaa.sa.gov.au"); g_string_append(s, "(and "); optionl = op->options; while (optionl) { struct filter_optionrule *or = optionl->data; - if (or->rule->type == FILTER_XML_MATCH) { - GList *argl; - int max=1, count; - int i; - - /* find out how many values we have in each arg (rule - is repeated that many times for each arg) */ - argl = or->args; - while (argl) { - arg = argl->data; - count = filter_arg_get_count(arg); - if (count>=max && max>1) { - g_warning("Rule '%s' has too many multi-valued values, ignored", or->rule->name); - goto next_rule; - } - if (count>max) { - max = count; - } - argl = g_list_next(argl); - } - g_string_append(s, "(or "); - for (i=0;i<max;i++) { - expand_variables(s, or->rule->code, or->args, i); - } - g_string_append(s, ") "); - } - next_rule: - optionl = g_list_next(optionl); - } -#if 0 - optionl = op->options; - while (optionl) { - struct filter_optionrule *or = optionl->data; - if (or->rule->type == FILTER_XML_EXCEPT) { - g_string_append(s, " (except \""); - g_string_append(s, or->rule->name); - g_string_append(s, "\" "); - g_string_append(s, or->rule->code); - g_string_append(s, " ) "); + if (or->rule->type == FILTER_XML_MATCH + || or->rule->type == FILTER_XML_EXCEPT) { + expand_variables(s, or->rule->code, or->args, globals); } optionl = g_list_next(optionl); } -#endif + g_string_append(s, ")"); #if 0 optionl = op->options; @@ -130,21 +121,320 @@ expand_filter_option(GString *s, struct filter_option *op) printf("combined rule '%s'\n", s->str); } +struct filter_optionrule * +find_optionrule(struct filter_option *option, char *name) +{ + GList *optionrulel; + struct filter_optionrule *or; + + optionrulel = option->options; + while (optionrulel) { + or = optionrulel->data; + if (!strcmp(or->rule->name, name)) { + return or; + } + optionrulel = g_list_next(optionrulel); + } + return NULL; +} + +void +html_write_options(GtkHTML *html, struct filter_option *option) +{ + GtkHTMLStreamHandle *stream; + GList *optionrulel; + + stream = gtk_html_begin(html, ""); + gtk_html_write(html, stream, "<body bgcolor=white alink=blue>", strlen("<body bgcolor=white alink=blue>")); + optionrulel = option->options; + while (optionrulel) { + struct filter_optionrule *or = optionrulel->data; + + filter_description_html_write(or->rule->description, or->args, html, stream); + gtk_html_write(html, stream, "<br>", strlen("<br>")); + optionrulel = g_list_next(optionrulel); + } + gtk_html_end(html, stream, GTK_HTML_STREAM_OK); +} + +void +fill_rules(GtkWidget *list, GList *rules, struct filter_option *option, int type) +{ + GList *optionl, *rulel; + GtkWidget *listitem, *hbox, *checkbox, *label; + GList *items = NULL; + + rulel = rules; + while (rulel) { + struct filter_rule *fr = rulel->data; + char *labeltext; + + if (fr->type == type) { + int state; + + state = find_optionrule(option, fr->name) != NULL; + + labeltext = filter_description_text(fr->description, NULL); + + hbox = gtk_hbox_new(FALSE, 3); + checkbox = gnome_pixmap_new_from_xpm_d(state?check_xpm:blank_xpm); + gtk_box_pack_start(GTK_BOX(hbox), checkbox, FALSE, FALSE, 0); + label = gtk_label_new(labeltext); + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, TRUE, 0); + listitem = gtk_list_item_new(); + gtk_container_add(GTK_CONTAINER(listitem), hbox); + gtk_widget_show_all(listitem); + + gtk_object_set_data(GTK_OBJECT(listitem), "checkbox", checkbox); + gtk_object_set_data(GTK_OBJECT(listitem), "checkstate", (void *)state); + gtk_object_set_data(GTK_OBJECT(listitem), "rule", fr); + + items = g_list_append(items, listitem); + } + rulel = g_list_next(rulel); + } + gtk_list_append_items(GTK_LIST(list), items); +} + +void +fill_options(GtkWidget *list, GList *options) +{ + GList *optionl, *rulel, *optionrulel; + GtkWidget *listitem, *hbox, *checkbox, *label; + GList *items = NULL; + + optionl = options; + while (optionl) { + struct filter_option *op = optionl->data; + char *labeltext; + + labeltext = filter_description_text(op->description, NULL); + listitem = gtk_list_item_new_with_label(labeltext); + g_free(labeltext); + gtk_widget_show_all(listitem); + + gtk_object_set_data(GTK_OBJECT(listitem), "option", op); + + items = g_list_append(items, listitem); + optionl = g_list_next(optionl); + } + gtk_list_append_items(GTK_LIST(list), items); +} + +GtkWidget *list_global, *html_global; +struct filter_option *option_current; + +static void +select_rule_child(GtkList *list, GtkWidget *child, void *data) +{ + GtkWidget *w; + struct filter_rule *fr = gtk_object_get_data(GTK_OBJECT(child), "rule"); + int state; + struct filter_optionrule *rule; + + w = gtk_object_get_data(GTK_OBJECT(child), "checkbox"); + state = !(int) gtk_object_get_data(GTK_OBJECT(child), "checkstate"); + + gnome_pixmap_load_xpm_d(GNOME_PIXMAP(w), state?check_xpm:blank_xpm); + gtk_object_set_data(GTK_OBJECT(child), "checkstate", (void *)state); + + if (state) { + printf("adding rule %p\n", fr); + rule = g_malloc0(sizeof(*rule)); + rule->rule = fr; + option_current->options = g_list_prepend(option_current->options, rule); + } else { + /* FIXME: free optionrule */ + rule = find_optionrule(option_current, fr->name); + if (rule) + option_current->options = g_list_remove(option_current->options, rule); + } + + { + GString *s = g_string_new(""); + expand_filter_option(s, option_current); + printf("Rules: %s\n", s->str); + g_string_free(s, TRUE); + } + + html_write_options(html_global, option_current); +} + +static void +select_option_child(GtkList *list, GtkWidget *child, void *data) +{ + struct filter_option *op = gtk_object_get_data(GTK_OBJECT(child), "option"); + struct filter_option *new; + GList *optionsl; + + if (option_current) { + /* free option_current copy */ + optionsl = option_current->options; + while (optionsl) { + GList *op = optionsl; + optionsl = g_list_next(optionsl); + g_free(op->data); + } + g_list_free(option_current->options); + g_free(option_current); + option_current = NULL; + } + + /* clone the option */ + new = g_malloc(sizeof(*new)); + new->type = op->type; + new->description = op->description; + new->options = NULL; + optionsl = op->options; + while (optionsl) { + struct filter_optionrule *ornew = g_malloc(sizeof(*ornew)), + *or = optionsl->data; + ornew->rule = or->rule; + /* FIXME: must copy args too *sigh* */ + ornew->args = or->args; + new->options = g_list_append(new->options, ornew); + optionsl = g_list_next(optionsl); + } + option_current = new; + + html_write_options(GTK_HTML(html_global), option_current); +} + +static void +arg_link_clicked(GtkHTML *html, const char *url, void *data) +{ + printf("url clicked: %s\n", url); + if (!strncmp(url, "arg:", 4)) { + FilterArg *arg; + void *dummy; + + if (sscanf(url+4, "%p %p", &dummy, &arg)==2 + && arg) { + printf("arg = %p\n", arg); + filter_arg_edit_values(arg); + /* should have a changed signal which propagates the rewrite */ + html_write_options(GTK_HTML(html_global), option_current); + } + } +} + +static void +dialogue_clicked(GtkWidget *w, int button, void *data) +{ + GString *s = g_string_new(""); + + printf("button %d clicked ...\n"); + + if (option_current) + expand_filter_option(s, option_current); + + g_string_free(s, TRUE); +} + +void create_dialogue(void) +{ + GtkWidget *dialogue, + *scrolled_window, + *list, + *html, + *frame; + + dialogue = gnome_dialog_new("Filter Rules", + GNOME_STOCK_BUTTON_PREV , GNOME_STOCK_BUTTON_NEXT, + "Finish", GNOME_STOCK_BUTTON_CANCEL, 0); + + list = gtk_list_new(); + frame = gtk_frame_new("Filter Type"); + scrolled_window = gtk_scrolled_window_new(NULL, NULL); + + gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrolled_window), list); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window), + GTK_POLICY_AUTOMATIC, + GTK_POLICY_AUTOMATIC); + gtk_container_set_focus_vadjustment + (GTK_CONTAINER (list), + gtk_scrolled_window_get_vadjustment + (GTK_SCROLLED_WINDOW (scrolled_window))); + gtk_container_add(GTK_CONTAINER(frame), scrolled_window); + gtk_box_pack_start(GTK_BOX(GNOME_DIALOG(dialogue)->vbox), frame, TRUE, TRUE, GNOME_PAD); + +#if 0 + gtk_signal_connect(GTK_OBJECT(list), "select_child", select_rule_child, NULL); + gtk_signal_connect(GTK_OBJECT(list), "unselect_child", select_rule_child, NULL); +#else + gtk_signal_connect(GTK_OBJECT(list), "select_child", select_option_child, NULL); + gtk_signal_connect(GTK_OBJECT(list), "unselect_child", select_option_child, NULL); +#endif + + frame = gtk_frame_new("Filter Description"); + html = gtk_html_new(); + scrolled_window = gtk_scrolled_window_new (NULL, NULL); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window), + GTK_POLICY_AUTOMATIC, + GTK_POLICY_AUTOMATIC); + gtk_container_add(GTK_CONTAINER(scrolled_window), html); + gtk_container_add(GTK_CONTAINER(frame), scrolled_window); + gtk_box_pack_start(GTK_BOX(GNOME_DIALOG(dialogue)->vbox), frame, TRUE, TRUE, GNOME_PAD); + + gtk_signal_connect(GTK_OBJECT(html), "link_clicked", arg_link_clicked, NULL); + gtk_signal_connect(GTK_OBJECT(dialogue), "clicked", dialogue_clicked, NULL); + + list_global = list; + html_global = html; + + gtk_widget_show_all(dialogue); +} + int main(int argc, char **argv) { FilterSEXP *f; FilterSEXPResult *r; - GList *rules, *options; + GList *rules, *options, *options2; xmlDocPtr doc, out, optionset, filteroptions; GString *s; gnome_init("Test", "0.0", argc, argv); + gdk_rgb_init (); + gtk_widget_set_default_colormap (gdk_rgb_get_cmap ()); + gtk_widget_set_default_visual (gdk_rgb_get_visual ()); + + create_dialogue(); doc = xmlParseFile("filterdescription.xml"); - rules = load_ruleset(doc); - options = load_optionset(doc, rules); + rules = filter_load_ruleset(doc); + options = filter_load_optionset(doc, rules); + options2 = options; out = xmlParseFile("saveoptions.xml"); - options = load_optionset(out, rules); + options = filter_load_optionset(out, rules); + +#if 0 + option_current = options->data; + fill_rules(list_global, rules, options->data, FILTER_XML_MATCH); +#else + option_current = NULL; + fill_options(list_global, options2); +#endif + gtk_main(); + + while (options) { + struct filter_option *fo = options->data; + GList *optionrulel; + + optionrulel = fo->options; + while (optionrulel) { + struct filter_optionrule *or = optionrulel->data; + + printf("formatting rule: %s\n", or->rule->name); + + /*filter_description_text(or->rule->description, or->args);*/ + filter_description_html_write(or->rule->description, or->args, NULL, NULL); + + optionrulel = g_list_next(optionrulel); + } + options = g_list_next(options); + } + + return 0; s = g_string_new(""); expand_filter_option(s, options->data); diff --git a/filter/filter-format.c b/filter/filter-format.c new file mode 100644 index 0000000000..00dcba00d3 --- /dev/null +++ b/filter/filter-format.c @@ -0,0 +1,235 @@ +/* -*- Mode: C; c-file-style: "linux"; indent-tabs-mode: t; c-basic-offset: 8; -*- */ + +#include <glib.h> +#include <gtk/gtk.h> +#include <gnome.h> +#include <gtkhtml/gtkhtml.h> + +#include <gnome-xml/tree.h> +#include <gnome-xml/parser.h> + +#include "filter-arg-types.h" +#include "filter-xml.h" + +/* FIXME: remove static, this is defined in filter-xml */ +static int +filter_find_rule(struct filter_rule *a, char *name) +{ + printf("finding, is %s = %s?\n", a->name, name); + return strcmp(a->name, name); +} + +static int +filter_find_arg(FilterArg *a, char *name) +{ + printf("finding, is %s = %s?\n", a->name, name); + return strcmp(a->name, name); +} + +static int display_order[] = { FILTER_XML_MATCH, FILTER_XML_ACTION, FILTER_XML_EXCEPT }; + +static struct filter_option * +option_clone(struct filter_option *source) +{ + struct filter_option *dest = g_malloc0(sizeof(*dest)); + GList *loptions; + struct filter_optionrule *old, *new; + + dest->type = source->type; + dest->description = source->description; + loptions = dest->options; + while (loptions) { + old = loptions->data; + new = g_malloc0(sizeof(*new)); + new->rule = old->rule; + /* FIXME: need to copy any args as well!!! */ + dest->options = g_list_append(dest->options, new); + loptions = g_list_next(loptions); + } + return dest; +} + + + +struct description_decode_lambda { + GString *str; + GList *args; + GtkHTML *html; + GtkHTMLStreamHandle *stream; +}; + +static char * +arg_text(FilterArg *arg) +{ + char *out = NULL; + GList *value, *next; + GString *str; + + value = arg->values; + + printf("getting text from arg %s\n", arg->name); + + if (value == NULL) + return NULL; + + str = g_string_new(""); + filter_arg_write_text(arg, str); + out = str->str; + g_string_free(str, FALSE); + return out; +} + +static void +description_decode_text(struct filter_desc *d, struct description_decode_lambda *l) +{ + GList *list; + char *txt; + + switch (d->type) { + case FILTER_XML_TEXT: + case FILTER_XML_DESC: + dotext: + printf("appending '%s'\n", d->data); + /* printf("vartype = %s\n", detokenise(d->vartype)); */ + printf("varname = %s\n", d->varname); + if (d->vartype !=-1 && d->varname + && (list = g_list_find_custom(l->args, d->varname, (GCompareFunc) filter_find_arg)) + && (txt = arg_text(list->data))) { + } else { + txt = d->data; + } + g_string_append(l->str, txt); + break; + default: + printf("WARN: unknown desc text type '%d' = %s\n", d->type, d->data); + goto dotext; + } +} + +char * +filter_description_text(GList *description, GList *args) +{ + char *txt; + struct description_decode_lambda l; + + printf("\ndecoding ...\n"); + + l.str = g_string_new(""); + l.args = args; + g_list_foreach(description, (GFunc) description_decode_text, &l); + + printf("string is '%s'\n", l.str->str); + + txt = l.str->str; + g_string_free(l.str, FALSE); + + return txt; +} + +static void +html_write(GtkHTML *html, GtkHTMLStreamHandle *stream, char *s) +{ + printf("appending html '%s'\n", s); + gtk_html_write(html, stream, s, strlen(s)); +} + + +static void +description_decode_html(struct filter_desc *d, struct description_decode_lambda *l) +{ + GList *list; + char *txt, *end; + int free; + + switch (d->type) { + case FILTER_XML_TEXT: + case FILTER_XML_DESC: + dotext: + printf("appending '%s'\n", d->data); + /*printf("vartype = %s\n", detokenise(d->vartype));*/ + printf("varname = %s\n", d->varname); + free = FALSE; + if (d->vartype !=-1 && d->varname) { + char *link; + list = g_list_find_custom(l->args, d->varname, (GCompareFunc) filter_find_arg); + end = "</a>"; + if (list) { + txt = arg_text(list->data); + if (txt == NULL) + txt = d->data; + else + free = TRUE; + link = g_strdup_printf("<a href=\"arg:%p %p\">", d, list->data); + } else { + printf("cannot find arg '%s'\n", d->varname); + link = g_strdup_printf("<a href=\"arg:%p %p\">", d, NULL); + txt = d->data; + } + html_write(l->html, l->stream, link); + g_free(link); + } else { + txt = d->data; + end = NULL; + } + html_write(l->html, l->stream, txt); + if (end) { + html_write(l->html, l->stream, end); + } + if (free) + g_free(txt); + break; + default: + /*printf("WARN: unknown desc text type '%s' = %s\n", detokenise(d->type), d->data);*/ + goto dotext; + } +} + +void +filter_description_html_write(GList *description, GList *args, GtkHTML *html, GtkHTMLStreamHandle *stream) +{ + char *txt; + struct description_decode_lambda l; + + printf("\ndecoding ...\n"); + + l.str = NULL; + l.args = args; + l.html = html; + l.stream = stream; + g_list_foreach(description, (GFunc) description_decode_html, &l); +} + +#ifdef TESTER +int main(int argc, char **argv) +{ + GList *rules, *options; + xmlDocPtr doc, out, optionset, filteroptions; + + gnome_init("Test", "0.0", argc, argv); + + doc = xmlParseFile("filterdescription.xml"); + + rules = load_ruleset(doc); + options = load_optionset(doc, rules); + + out = xmlParseFile("saveoptions.xml"); + options = load_optionset(doc, rules); + + while (options) { + printf("applying a rule ...\n"); + filterme(options->data); + options = g_list_next(options); + } + +#if 0 + out = xmlNewDoc("1.0"); + optionset = save_optionset(out, options); + filteroptions = xmlNewDocNode(out, NULL, "filteroptions", NULL); + xmlAddChild(filteroptions, optionset); + xmlDocSetRootElement(out, filteroptions); + xmlSaveFile("saveoptions.xml", out); +#endif + return 0; +} +#endif + diff --git a/filter/filter-format.h b/filter/filter-format.h new file mode 100644 index 0000000000..12a4040a46 --- /dev/null +++ b/filter/filter-format.h @@ -0,0 +1,10 @@ + +#ifndef _FILTER_FORMAT_H +#define _FILTER_FORMAT_H + +#include <glib.h> + +char *filter_description_text(GList *description, GList *args); +void description_html_write(GList *description, GList *args, GtkHTML *html, GtkHTMLStreamHandle *stream); + +#endif /* _FILTER_FORMAT_H */ diff --git a/filter/filter-sexp.c b/filter/filter-sexp.c index 738ffa3380..04f8a82e6c 100644 --- a/filter/filter-sexp.c +++ b/filter/filter-sexp.c @@ -206,10 +206,10 @@ term_eval_and(struct _FilterSEXP *f, int argc, struct _FilterSEXPTerm **argv, vo a1 = (char **)r1->value.ptrarray->pdata; l1 = r1->value.ptrarray->len; - for (j=0;i<l1;j++) { + for (j=0;j<l1;j++) { int n; - n = (int)g_hash_table_lookup(ht, a1[i]); - g_hash_table_insert(ht, a1[i], (void *)n+1); + n = (int)g_hash_table_lookup(ht, a1[j]); + g_hash_table_insert(ht, a1[j], (void *)n+1); } } else if ( r1->type == FSEXP_RES_BOOL ) { bool &= r1->value.bool; @@ -259,7 +259,7 @@ term_eval_or(struct _FilterSEXP *f, int argc, struct _FilterSEXPTerm **argv, voi a1 = (char **)r1->value.ptrarray->pdata; l1 = r1->value.ptrarray->len; - for (j=0;i<l1;j++) { + for (j=0;j<l1;j++) { g_hash_table_insert(ht, a1[j], (void *)1); } } else if (r1->type == FSEXP_RES_BOOL) { @@ -283,6 +283,22 @@ term_eval_or(struct _FilterSEXP *f, int argc, struct _FilterSEXPTerm **argv, voi return r; } +static FilterSEXPResult * +term_eval_not(struct _FilterSEXP *f, int argc, struct _FilterSEXPResult **argv, void *data) +{ + int res = TRUE; + FilterSEXPResult *r; + + if (argc>0) { + if (argv[0]->type == FSEXP_RES_BOOL + && argv[0]->value.bool) + res = FALSE; + } + r = filter_sexp_result_new(FSEXP_RES_BOOL); + r->value.bool = res; + return r; +} + /* this should support all arguments ...? */ static FilterSEXPResult * term_eval_lt(struct _FilterSEXP *f, int argc, struct _FilterSEXPTerm **argv, void *data) @@ -873,6 +889,7 @@ static struct { } symbols[] = { { "and", (FilterSEXPFunc *)term_eval_and, 1 }, { "or", (FilterSEXPFunc *)term_eval_or, 1 }, + { "not", (FilterSEXPFunc *)term_eval_not, 0 }, { "<", (FilterSEXPFunc *)term_eval_lt, 1 }, { ">", (FilterSEXPFunc *)term_eval_gt, 1 }, { "=", (FilterSEXPFunc *)term_eval_eq, 1 }, diff --git a/filter/filter-xml.c b/filter/filter-xml.c index de86749db9..144bd88f0d 100644 --- a/filter/filter-xml.c +++ b/filter/filter-xml.c @@ -1,5 +1,7 @@ /* -*- Mode: C; c-file-style: "linux"; indent-tabs-mode: t; c-basic-offset: 8; -*- */ +/* Load save filter descriptions/options from an xml file */ + #include <glib.h> #include <gtk/gtk.h> #include <gnome.h> @@ -69,7 +71,8 @@ detokenise(int token) } -xmlNodePtr find_node(xmlNodePtr start, char *name) +static xmlNodePtr +find_node(xmlNodePtr start, char *name) { printf("trying to find node '%s'\n", name); while (start && strcmp(start->name, name)) @@ -78,7 +81,8 @@ xmlNodePtr find_node(xmlNodePtr start, char *name) return start; } -xmlNodePtr find_node_attr(xmlNodePtr start, char *name, char *attrname, char *attrvalue) +static xmlNodePtr +find_node_attr(xmlNodePtr start, char *name, char *attrname, char *attrvalue) { xmlNodePtr node; char *s; @@ -95,192 +99,6 @@ xmlNodePtr find_node_attr(xmlNodePtr start, char *name, char *attrname, char *at return start; } -static int -find_arg(FilterArg *a, char *name) -{ - printf("finding, is %s = %s?\n", a->name, name); - return strcmp(a->name, name); -} - -static int -find_rule(struct filter_rule *a, char *name) -{ - printf("finding, is %s = %s?\n", a->name, name); - return strcmp(a->name, name); -} - -static int display_order[] = { FILTER_XML_MATCH, FILTER_XML_ACTION, FILTER_XML_EXCEPT }; - -static struct filter_option * -option_clone(struct filter_option *source) -{ - struct filter_option *dest = g_malloc0(sizeof(*dest)); - GList *loptions; - struct filter_optionrule *old, *new; - - dest->type = source->type; - dest->description = source->description; - loptions = dest->options; - while (loptions) { - old = loptions->data; - new = g_malloc0(sizeof(*new)); - new->rule = old->rule; - /* FIXME: need to copy any args as well!!! */ - dest->options = g_list_append(dest->options, new); - loptions = g_list_next(loptions); - } - return dest; -} - - - -struct description_decode_lambda { - GString *str; - GList *args; - GtkHTML *html; - GtkHTMLStreamHandle *stream; -}; - -static char * -arg_text(FilterArg *arg) -{ - char *out = NULL; - GList *value, *next; - GString *str; - - value = arg->values; - - if (value == NULL) - return NULL; - - str = g_string_new(""); - filter_arg_write_text(arg, str); - out = str->str; - g_string_free(str, FALSE); - return out; -} - -static void -description_decode_text(struct filter_desc *d, struct description_decode_lambda *l) -{ - GList *list; - char *txt; - - switch (d->type) { - case FILTER_XML_TEXT: - case FILTER_XML_DESC: - dotext: - printf("appending '%s'\n", d->data); - printf("vartype = %s\n", detokenise(d->vartype)); - printf("varname = %s\n", d->varname); - if (d->vartype !=-1 && d->varname - && (list = g_list_find_custom(l->args, d->varname, (GCompareFunc) find_arg)) - && (txt = arg_text(list->data))) { - } else { - txt = d->data; - } - g_string_append(l->str, txt); - break; - default: - printf("WARN: unknown desc text type '%s' = %s\n", detokenise(d->type), d->data); - goto dotext; - } -} - -static char * -description_text(GList *description, GList *args) -{ - char *txt; - struct description_decode_lambda l; - - printf("\ndecoding ...\n"); - - l.str = g_string_new(""); - l.args = args; - g_list_foreach(description, (GFunc) description_decode_text, &l); - - printf("string is '%s'\n", l.str->str); - - txt = l.str->str; - g_string_free(l.str, FALSE); - - return txt; -} - -static void -html_write(GtkHTML *html, GtkHTMLStreamHandle *stream, char *s) -{ - printf("appending html '%s'\n", s); - gtk_html_write(html, stream, s, strlen(s)); -} - - -static void -description_decode_html(struct filter_desc *d, struct description_decode_lambda *l) -{ - GList *list; - char *txt, *end; - int free; - - switch (d->type) { - case FILTER_XML_TEXT: - case FILTER_XML_DESC: - dotext: - printf("appending '%s'\n", d->data); - printf("vartype = %s\n", detokenise(d->vartype)); - printf("varname = %s\n", d->varname); - free = FALSE; - if (d->vartype !=-1 && d->varname) { - char *link; - list = g_list_find_custom(l->args, d->varname, (GCompareFunc) find_arg); - end = "</a>"; - if (list) { - txt = arg_text(list->data); - if (txt == NULL) - txt = d->data; - else - free = TRUE; - link = g_strdup_printf("<a href=\"arg:%p %p\">", d, list->data); - } else { - printf("cannot find arg '%s'\n", d->varname); - link = g_strdup_printf("<a href=\"arg:%p %p\">", d, NULL); - txt = d->data; - } - html_write(l->html, l->stream, link); - g_free(link); - } else { - txt = d->data; - end = NULL; - } - html_write(l->html, l->stream, txt); - if (end) { - html_write(l->html, l->stream, end); - } - if (free) - g_free(txt); - break; - default: - printf("WARN: unknown desc text type '%s' = %s\n", detokenise(d->type), d->data); - goto dotext; - } -} - -static void -description_html_write(GList *description, GList *args, GtkHTML *html, GtkHTMLStreamHandle *stream) -{ - char *txt; - struct description_decode_lambda l; - - printf("\ndecoding ...\n"); - - l.str = NULL; - l.args = args; - l.html = html; - l.stream = stream; - g_list_foreach(description, (GFunc) description_decode_html, &l); -} - - static GList * load_desc(xmlNodePtr node, int type, int vartype, char *varname) { @@ -321,7 +139,7 @@ load_desc(xmlNodePtr node, int type, int vartype, char *varname) } GList * -load_ruleset(xmlDocPtr doc) +filter_load_ruleset(xmlDocPtr doc) { xmlNodePtr ruleset, rule, n; struct filter_rule *r; @@ -366,8 +184,6 @@ load_ruleset(xmlDocPtr doc) printf(" ** loading description\n"); r->description = load_desc(n->childs, type, -1, NULL); printf(" ** done loading description\n"); - description_text(r->description, 0); - printf(" ** done dumping description\n"); break; default: printf("warning, unknown token encountered\n"); @@ -456,7 +272,7 @@ optionrule_new(struct filter_rule *rule) } GList * -load_optionset(xmlDocPtr doc, GList *rules) +filter_load_optionset(xmlDocPtr doc, GList *rules) { xmlNodePtr optionset, option, o, or; struct filter_option *op; @@ -525,8 +341,8 @@ load_optionset(xmlDocPtr doc, GList *rules) return l; } -static xmlNodePtr -save_optionset(xmlDocPtr doc, GList *optionl) +xmlNodePtr +filter_write_optionset(xmlDocPtr doc, GList *optionl) { xmlNodePtr root, cur, option, optionrule, optionvalue; GList *optionrulel, *argl; @@ -572,56 +388,6 @@ save_optionset(xmlDocPtr doc, GList *optionl) return root; } - - -/* - build an expression for the filter -*/ -static void -filterme(struct filter_option *op) -{ - GList *optionl; - GString *s; - - s = g_string_new("(if (and "); - optionl = op->options; - while (optionl) { - struct filter_optionrule *or = optionl->data; - if (or->rule->type == FILTER_XML_MATCH) { - g_string_append(s, "(match \""); - g_string_append(s, or->rule->name); - g_string_append(s, "\" "); - g_string_append(s, or->rule->code); - g_string_append(s, ") "); - } - optionl = g_list_next(optionl); - } - optionl = op->options; - while (optionl) { - struct filter_optionrule *or = optionl->data; - if (or->rule->type == FILTER_XML_EXCEPT) { - g_string_append(s, " (except \""); - g_string_append(s, or->rule->name); - g_string_append(s, "\" "); - g_string_append(s, or->rule->code); - g_string_append(s, " ) "); - } - optionl = g_list_next(optionl); - } - g_string_append(s, ") (begin "); - optionl = op->options; - while (optionl) { - struct filter_optionrule *or = optionl->data; - if (or->rule->type == FILTER_XML_ACTION) { - g_string_append(s, or->rule->code); - g_string_append(s, " "); - } - optionl = g_list_next(optionl); - } - g_string_append(s, "))"); - printf("combined rule '%s'\n", s->str); -} - #ifdef TESTER int main(int argc, char **argv) { @@ -637,13 +403,6 @@ int main(int argc, char **argv) out = xmlParseFile("saveoptions.xml"); options = load_optionset(doc, rules); - - while (options) { - printf("applying a rule ...\n"); - filterme(options->data); - options = g_list_next(options); - } - #if 0 out = xmlNewDoc("1.0"); optionset = save_optionset(out, options); diff --git a/filter/filter-xml.h b/filter/filter-xml.h index a56b4baa2e..1ff353bd20 100644 --- a/filter/filter-xml.h +++ b/filter/filter-xml.h @@ -2,6 +2,9 @@ #ifndef _FILTER_XML_H #define _FILTER_XML_H +#include <glib.h> +#include <gnome-xml/tree.h> + enum filter_xml_token { FILTER_XML_TEXT=0, FILTER_XML_RULE, @@ -48,4 +51,12 @@ struct filter_option { GList *options; /* option_rule */ }; +GList *filter_load_ruleset(xmlDocPtr doc); +GList *filter_load_optionset(xmlDocPtr doc, GList *rules); +xmlNodePtr filter_write_optionset(xmlDocPtr doc, GList *optionl); + +/* callbacks for searching GLists of various types */ +int filter_find_rule(struct filter_rule *a, char *name); +int filter_find_arg(FilterArg *a, char *name); + #endif /* ! _FILTER_XML_H */ |