rizin/librz/util/event.c
pelijah b8ebd5ac42
Add missing vector foreach macros to clang-format cfg (#4456)
* Add rz_vector_foreach to clang-format cfg
* Add other vector foreach macros
2024-04-22 07:16:46 +08:00

136 lines
3.4 KiB
C

// SPDX-FileCopyrightText: 2018 pancake
// SPDX-License-Identifier: MIT
#include <rz_util.h>
#include <rz_vector.h>
typedef struct rz_event_callback_hook_t {
RzEventCallback cb;
void *user;
int handle;
} RzEventCallbackHook;
RZ_API RzEvent *rz_event_new(void *user) {
RzEvent *ev = RZ_NEW0(RzEvent);
if (!ev) {
return NULL;
}
ev->user = user;
ev->next_handle = 0;
ev->callbacks = ht_up_new(NULL, (HtUPFreeValue)rz_vector_free);
if (!ev->callbacks) {
goto err;
}
rz_vector_init(&ev->all_callbacks, sizeof(RzEventCallbackHook), NULL, NULL);
rz_vector_init(&ev->pending_unhook, sizeof(RzEventCallbackHandle), NULL, NULL);
return ev;
err:
rz_event_free(ev);
return NULL;
}
RZ_API void rz_event_free(RzEvent *ev) {
if (!ev) {
return;
}
rz_vector_fini(&ev->pending_unhook);
ht_up_free(ev->callbacks);
rz_vector_fini(&ev->all_callbacks);
free(ev);
}
static RzVector /*<RzEventCallbackHook>*/ *get_cbs(RzEvent *ev, int type) {
RzVector *cbs = ht_up_find(ev->callbacks, (ut64)type, NULL);
if (!cbs) {
cbs = rz_vector_new(sizeof(RzEventCallbackHook), NULL, NULL);
if (cbs) {
ht_up_insert(ev->callbacks, (ut64)type, cbs);
}
}
return cbs;
}
RZ_API RzEventCallbackHandle rz_event_hook(RzEvent *ev, int type, RzEventCallback cb, void *user) {
RzEventCallbackHandle handle = { 0 };
RzEventCallbackHook hook;
rz_return_val_if_fail(ev, handle);
hook.cb = cb;
hook.user = user;
hook.handle = ev->next_handle++;
if (type == RZ_EVENT_ALL) {
rz_vector_push(&ev->all_callbacks, &hook);
} else {
RzVector *cbs = get_cbs(ev, type);
if (!cbs) {
return handle;
}
rz_vector_push(cbs, &hook);
}
handle.handle = hook.handle;
handle.type = type;
return handle;
}
static bool del_hook(void *user, const ut64 k, const void *v) {
int handle = *(int *)user;
RzVector *cbs = (RzVector *)v;
RzEventCallbackHook *hook;
size_t i;
rz_return_val_if_fail(cbs, false);
rz_vector_enumerate (cbs, hook, i) {
if (hook->handle == handle) {
rz_vector_remove_at(cbs, i, NULL);
break;
}
}
return true;
}
RZ_API void rz_event_unhook(RzEvent *ev, RzEventCallbackHandle handle) {
rz_return_if_fail(ev);
if (ev->incall) {
// when inside a call (meaning rz_event_send currently iterates over the callback vectors),
// defer the unhook to after the rz_event_send is done.
rz_vector_push(&ev->pending_unhook, &handle);
return;
}
if (handle.type == RZ_EVENT_ALL) {
// try to delete it both from each list of callbacks and from
// the "all_callbacks" vector
ht_up_foreach(ev->callbacks, del_hook, &handle.handle);
del_hook(&handle.handle, 0, &ev->all_callbacks);
} else {
RzVector *cbs = ht_up_find(ev->callbacks, (ut64)handle.type, NULL);
rz_return_if_fail(cbs);
del_hook(&handle.handle, 0, cbs);
}
}
RZ_API void rz_event_send(RzEvent *ev, int type, void *data) {
RzEventCallbackHook *hook;
rz_return_if_fail(ev && !ev->incall);
// send to both the per-type callbacks and to the all_callbacks
ev->incall = true;
rz_vector_foreach (&ev->all_callbacks, hook) {
hook->cb(ev, type, hook->user, data);
}
ev->incall = false;
RzVector *cbs = ht_up_find(ev->callbacks, (ut64)type, NULL);
if (cbs) {
ev->incall = true;
rz_vector_foreach (cbs, hook) {
hook->cb(ev, type, hook->user, data);
}
ev->incall = false;
}
RzEventCallbackHandle *unhook_handle;
rz_vector_foreach (&ev->pending_unhook, unhook_handle) {
rz_event_unhook(ev, *unhook_handle);
}
rz_vector_clear(&ev->pending_unhook);
}