diff --git a/src/misc.c b/src/misc.c index 2dc2136..41867f3 100644 --- a/src/misc.c +++ b/src/misc.c @@ -34,6 +34,7 @@ #include #include #include +#include "misc.h" #define RING_SIZE 512 @@ -164,3 +165,104 @@ next: ent->len -= len; } } + +struct hook_entry { + struct hook_entry *next; + kmscon_hook_cb cb; + void *data; +}; + +struct kmscon_hook { + struct hook_entry *entries; + struct hook_entry *cur_entry; +}; + +int kmscon_hook_new(struct kmscon_hook **out) +{ + struct kmscon_hook *hook; + + if (!out) + return -EINVAL; + + hook = malloc(sizeof(*hook)); + if (!hook) + return -ENOMEM; + memset(hook, 0, sizeof(*hook)); + + *out = hook; + return 0; +} + +void kmscon_hook_free(struct kmscon_hook *hook) +{ + struct hook_entry *entry; + + if (!hook) + return; + + while ((entry = hook->entries)) { + hook->entries = entry->next; + free(entry); + } + + free(hook); +} + +int kmscon_hook_add(struct kmscon_hook *hook, kmscon_hook_cb cb, void *data) +{ + struct hook_entry *entry; + + if (!hook || !cb) + return -EINVAL; + + entry = malloc(sizeof(*entry)); + if (!entry) + return -ENOMEM; + memset(entry, 0, sizeof(*entry)); + entry->cb = cb; + entry->data = data; + + entry->next = hook->entries; + hook->entries = entry; + return 0; +} + +void kmscon_hook_rm(struct kmscon_hook *hook, kmscon_hook_cb cb) +{ + struct hook_entry *entry, *tmp; + + if (!hook || !cb || !hook->entries) + return; + + tmp = NULL; + if (hook->entries->cb == cb) { + tmp = hook->entries; + hook->entries = tmp->next; + } else for (entry = hook->entries; entry->next; entry = entry->next) { + if (entry->next->cb == cb) { + tmp = entry->next; + entry->next = tmp->next; + break; + } + } + + if (tmp) { + /* if *_call() is currently running we must not disturb it */ + if (hook->cur_entry == tmp) + hook->cur_entry = tmp->next; + free(tmp); + } +} + +void kmscon_hook_call(struct kmscon_hook *hook, void *parent, void *arg) +{ + if (!hook) + return; + + hook->cur_entry = hook->entries; + while (hook->cur_entry) { + hook->cur_entry->cb(parent, arg, hook->cur_entry->data); + if (hook->cur_entry) + hook->cur_entry = hook->cur_entry->next; + } +} diff --git a/src/misc.h b/src/misc.h index ee53f27..9c088ce 100644 --- a/src/misc.h +++ b/src/misc.h @@ -45,4 +45,17 @@ int kmscon_ring_write(struct kmscon_ring *ring, const char *val, size_t len); const char *kmscon_ring_peek(struct kmscon_ring *ring, size_t *len); void kmscon_ring_drop(struct kmscon_ring *ring, size_t len); +struct kmscon_hook; +typedef void (*kmscon_hook_cb) (void *parent, void *arg, void *data); + +int kmscon_hook_new(struct kmscon_hook **out); +void kmscon_hook_free(struct kmscon_hook *hook); +int kmscon_hook_add(struct kmscon_hook *hook, kmscon_hook_cb cb, void *data); +void kmscon_hook_rm(struct kmscon_hook *hook, kmscon_hook_cb cb); +void kmscon_hook_call(struct kmscon_hook *hook, void *parent, void *arg); +#define kmscon_hook_add_cast(hook, cb, data) \ + kmscon_hook_add((hook), (kmscon_hook_cb)(cb), (data)) +#define kmscon_hook_rm_cast(hook, cb) \ + kmscon_hook_rm((hook), (kmscon_hook_cb)(cb)) + #endif /* KMSCON_MISC_H */