/* IRCfs - IRC FileServ for *nix. * Copyright (C) 2002 Nick 'Zaf' Clifford * For licensing details, refer to the LICENSE file in the source * code directory. */ #include "runtime.h" #include "event.h" #include "list.h" #include "pool.h" struct eventnode { unsigned int code; event_callback_t func; void *filter; void *appdata; }; struct eventobj { POOL pool; struct list *listeners; void *appdata; event_filter_func_t filter_func; }; static int event_compare(struct eventnode *what, struct eventnode *node); int event_add_listener(struct eventobj *what, unsigned int code, void *filter, event_callback_t func, void *appdata) { struct eventnode *en; ASSERT(what); ASSERT(func); en = XMALLOC(what->pool,struct eventnode); en->func = func; en->filter = filter; en->code = code; en->appdata = appdata; list_add_front(what->listeners,en); return 0; } /* Remove any matching code. * If NULL is passed for func or appdata, it is assumed to mean match any. */ int event_del_listener_by_data(struct eventobj *obj, unsigned int code, void *filterdata, event_callback_t func, void *appdata) { static struct eventnode match,*en; int found; match.code = code; match.func = func; match.filter = filterdata; match.appdata = appdata; while(1) { en = list_find(obj->listeners, &match, (list_compare_t)event_compare); if (en == NULL) break; list_del_current(obj->listeners); found++; } return found ? found : -1; } int event_del_listener(struct eventobj *what, unsigned int code, void *filter, event_callback_t func) { static struct eventnode match,*en; int found; match.code = code; match.func = func; match.filter = filter; match.appdata = NULL; while(1) { en = list_find(what->listeners, &match, (list_compare_t)event_compare); if (en == NULL) break; list_del_current(what->listeners); found++; } return found ? found : -1; } int event_compare(struct eventnode *what,struct eventnode *node) { if (what->code != event_code_any && what->code != node->code) return -1; if (what->func != NULL && what->func != node->func) return -1; if (what->filter != NULL && what->filter != node->filter) return -1; if (what->appdata != NULL && what->appdata != node->appdata) return -1; return 0; } int event_callback(struct list *l, struct eventnode *node, struct eventmsg *event) { if (node->code == event_code_any || node->code == event->code) { event->appdata = node->appdata; if (event->obj->filter_func && node->filter) { if (event->obj->filter_func(event,node->filter) == -1) return 0; } node->func(event); event->count++; } return 0; } int event_set_filter_func(struct eventobj *obj, event_filter_func_t func) { obj->filter_func = func; return 0; } struct eventobj *event_create_obj(POOL parent, void *appdata) { POOL p; struct eventobj *obj; p = pool_new(parent); obj = XMALLOC(p,struct eventobj); obj->pool = p; obj->listeners = list_create(p); obj->appdata = appdata; return obj; } void event_destroy_obj(struct eventobj *obj) { POOL p; ASSERT(obj); p = obj->pool; ASSERT(p != NULL); obj->pool = NULL; pool_destroy(p); } /* event_raise(obj, code, msgdata) * Raises an event within the specified object with the specified code. * Event listeners (registered with event_add_listener) that * match the specified code, and pass the optional filter (registered * with event_set_filter_func) are called with the msgdata as a parameter * (see event_add_listener). * * Returns -1 on error or the number of listeners that were called (0 * if there were no matches). */ int event_raise(struct eventobj *obj, unsigned int code, void *msgdata) { struct eventmsg *msg; int r; msg = (struct eventmsg *) malloc(sizeof(struct eventmsg)); msg->obj = obj; msg->msg = msgdata; msg->code = code; msg->count = 0; r = list_foreach(obj->listeners, (list_callback_t)event_callback, msg); if (r != -1) r = msg->count; free(msg); return r; }