📄 event.c
字号:
/* Event handling functions *//* $Id: event.c,v 1.22.6.1 2005/04/05 21:08:43 jonas Exp $ */#ifdef HAVE_CONFIG_H#include "config.h"#endif#include "elinks.h"#include "sched/event.h"#include "util/error.h"#include "util/hash.h"#include "util/memory.h"#include "util/snprintf.h"#include "util/string.h"/* First, we should set some terminology: * * o event -> Message being [triggerred] by some ELinks part and [catched] * by various random other ones. * * o event hook -> Device being deployed by various ELinks parts, * associated with certain [event It [catches] that event by having a * handler executed when the [event] is triggerred. * * o event chain -> Line of [event hook]s associated with a given [event * The [hook]s are ordered by [priority Each hook returns whenever should * the chain continue or that no other events in the chain should be * triggered (TODO). */struct event_handler { /* The function to be called with the event data. */ event_hook callback; /* The @priority of this handler. */ int priority; /* Handler specific data. */ void *data;};struct event { /* The event name has to be unique. */ unsigned char *name; /* There are @count event @handlers all ordered by priority. */ struct event_handler *handlers; unsigned int count; /* The unique event id and position in events. */ int id;};static struct event *events = NULL;static unsigned int eventssize = 0;static struct hash *event_hash = NULL;/* TODO: This should be tuned to the number of events. When we will have a lot * of them, this should be some big enough number to reduce unnecessary * slavery of CPU on the startup. Then after all main modules will be * initialized and their events will be registered, we could call something * like adjust_events_list() which will tune it to the exactly needed number. * This should be also called after each new plugin loaded. */#define EVENT_GRANULARITY 0x07#define realloc_events(ptr, size) \ mem_align_alloc(ptr, (size), (size) + 1, struct event, EVENT_GRANULARITY)static inline intinvalid_event_id(register int id){ return (id < 0 || id >= eventssize || id == EVENT_NONE);}intregister_event(unsigned char *name){ int id = get_event_id(name); struct event *event; int namelen; if (id != EVENT_NONE) return id; event = events; if (!realloc_events(&events, eventssize)) return EVENT_NONE; /* If @events got relocated update the hash. */ if (event != events) { for (id = 0; id < eventssize; id++) { struct hash_item *item; int len = strlen(events[id].name); item = get_hash_item(event_hash, events[id].name, len); if (item) item->value = &events[id]; } } event = &events[eventssize]; namelen = strlen(name); event->name = memacpy(name, namelen); if (!event->name) return EVENT_NONE; if (!add_hash_item(event_hash, event->name, namelen, event)) { mem_free(event->name); event->name = NULL; return EVENT_NONE; } event->handlers = NULL; event->count = 0; event->id = eventssize++; return event->id;}intget_event_id(unsigned char *name){ struct hash_item *item; int namelen; assertm(name && name[0], "Empty or missing event name"); if_assert_failed return EVENT_NONE; if (!event_hash) return EVENT_NONE; namelen = strlen(name); item = get_hash_item(event_hash, name, namelen); if (item) { struct event *event = item->value; assertm(event, "Hash item with no value"); if_assert_failed return EVENT_NONE; return event->id; } return EVENT_NONE;}unsigned char *get_event_name(int id){ if (invalid_event_id(id)) return NULL; return events[id].name;}static inline voidtrigger_event_va(int id, va_list ap_init){ int i; struct event_handler *ev_handler; if (invalid_event_id(id)) return; ev_handler = events[id].handlers; for (i = 0; i < events[id].count; i++, ev_handler++) { enum evhook_status ret; va_list ap; VA_COPY(ap, ap_init); ret = ev_handler->callback(ap, ev_handler->data); va_end(ap); if (ret == EVENT_HOOK_STATUS_LAST) return; }}voidtrigger_event(int id, ...){ va_list ap; va_start(ap, id); trigger_event_va(id, ap);}voidtrigger_event_name(unsigned char *name, ...){ va_list ap; int id = get_event_id(name); va_start(ap, name); trigger_event_va(id, ap);}static inline voidmove_event_handler(struct event *event, int to, int from){ int d = int_max(to, from); memmove(&event->handlers[to], &event->handlers[from], (event->count - d) * sizeof(*event->handlers));}intregister_event_hook(int id, event_hook callback, int priority, void *data){ struct event *event; int i; assert(callback); if_assert_failed return EVENT_NONE; if (invalid_event_id(id)) return EVENT_NONE; event = &events[id]; for (i = 0; i < event->count; i++) if (event->handlers[i].callback == callback) break; if (i == event->count) { struct event_handler *eh; eh = mem_realloc(event->handlers, (event->count + 1) * sizeof(*event->handlers)); if (!eh) return EVENT_NONE; event->handlers = eh; event->count++; } else { move_event_handler(event, i, i + 1); } for (i = 0; i < event->count - 1; i++) if (event->handlers[i].priority < priority) break; move_event_handler(event, i + 1, i); event->handlers[i].callback = callback; event->handlers[i].priority = priority; event->handlers[i].data = data; return id;}voidunregister_event_hook(int id, event_hook callback){ struct event *event; assert(callback); if_assert_failed return; if (invalid_event_id(id)) return; event = &events[id]; if (event->handlers) { int i; for (i = 0; i < event->count; i++) { if (event->handlers[i].callback != callback) continue; move_event_handler(event, i, i + 1); event->count--; if (!event->count) { mem_free(event->handlers); event->handlers = NULL; } else { struct event_handler *eh; eh = mem_realloc(event->handlers, event->count * sizeof(*event->handlers)); if (eh) event->handlers = eh; } break; } }}voidregister_event_hooks(struct event_hook_info *hooks){ int i; for (i = 0; hooks[i].name; i++) { int id = register_event(hooks[i].name); if (id == EVENT_NONE) continue; register_event_hook(id, hooks[i].callback, 0, hooks[i].data); }}voidunregister_event_hooks(struct event_hook_info *hooks){ int i; for (i = 0; hooks[i].name; i++) { int id = get_event_id(hooks[i].name); if (id == EVENT_NONE) continue; unregister_event_hook(id, hooks[i].callback); }}voidinit_event(void){ event_hash = init_hash(8, strhash);}voiddone_event(void){ int i; if (event_hash) free_hash(event_hash); for (i = 0; i < eventssize; i++) { mem_free_if(events[i].handlers); mem_free(events[i].name); } mem_free_set(&events, NULL); eventssize = 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -