1 /* radare2 - MIT - Copyright 2018 - pancake */
2 
3 #include <r_util.h>
4 #include <r_vector.h>
5 
6 typedef struct r_event_callback_hook_t {
7 	REventCallback cb;
8 	void *user;
9 	int handle;
10 } REventCallbackHook;
11 
ht_callback_free(HtUPKv * kv)12 static void ht_callback_free(HtUPKv *kv) {
13 	r_vector_free ((RVector *)kv->value);
14 }
15 
r_event_new(void * user)16 R_API REvent *r_event_new(void *user) {
17 	REvent *ev = R_NEW0 (REvent);
18 	if (!ev) {
19 		return NULL;
20 	}
21 
22 	ev->user = user;
23 	ev->next_handle = 0;
24 	ev->callbacks = ht_up_new (NULL, ht_callback_free, NULL);
25 	if (!ev->callbacks) {
26 		goto err;
27 	}
28 	r_vector_init (&ev->all_callbacks, sizeof (REventCallbackHook), NULL, NULL);
29 	return ev;
30 err:
31 	r_event_free (ev);
32 	return NULL;
33 }
34 
r_event_free(REvent * ev)35 R_API void r_event_free(REvent *ev) {
36 	if (!ev) {
37 		return;
38 	}
39 	ht_up_free (ev->callbacks);
40 	r_vector_clear (&ev->all_callbacks);
41 	free (ev);
42 }
43 
get_cbs(REvent * ev,int type)44 static RVector *get_cbs(REvent *ev, int type) {
45 	RVector *cbs = ht_up_find (ev->callbacks, (ut64)type, NULL);
46 	if (!cbs) {
47 		cbs = r_vector_new (sizeof (REventCallbackHook), NULL, NULL);
48 		if (cbs) {
49 			ht_up_insert (ev->callbacks, (ut64)type, cbs);
50 		}
51 	}
52 	return cbs;
53 }
54 
r_event_hook(REvent * ev,int type,REventCallback cb,void * user)55 R_API REventCallbackHandle r_event_hook(REvent *ev, int type, REventCallback cb, void *user) {
56 	REventCallbackHandle handle = { 0 };
57 	REventCallbackHook hook;
58 
59 	r_return_val_if_fail (ev, handle);
60 	hook.cb = cb;
61 	hook.user = user;
62 	hook.handle = ev->next_handle++;
63 	if (type == R_EVENT_ALL) {
64 		r_vector_push (&ev->all_callbacks, &hook);
65 	} else {
66 		RVector *cbs = get_cbs (ev, type);
67 		if (!cbs) {
68 			return handle;
69 		}
70 		r_vector_push (cbs, &hook);
71 	}
72 	handle.handle = hook.handle;
73 	handle.type = type;
74 	return handle;
75 }
76 
del_hook(void * user,const ut64 k,const void * v)77 static bool del_hook(void *user, const ut64 k, const void *v) {
78 	int handle = *(int *)user;
79 	RVector *cbs = (RVector *)v;
80 	REventCallbackHook *hook;
81 	size_t i;
82 	r_return_val_if_fail (cbs, false);
83 	r_vector_enumerate (cbs, hook, i) {
84 		if (hook->handle == handle) {
85 			r_vector_remove_at (cbs, i, NULL);
86 			break;
87 		}
88 	}
89 	return true;
90 }
91 
r_event_unhook(REvent * ev,REventCallbackHandle handle)92 R_API void r_event_unhook(REvent *ev, REventCallbackHandle handle) {
93 	r_return_if_fail (ev);
94 	if (handle.type == R_EVENT_ALL) {
95 		// try to delete it both from each list of callbacks and from
96 		// the "all_callbacks" vector
97 		ht_up_foreach (ev->callbacks, del_hook, &handle.handle);
98 		del_hook (&handle.handle, 0, &ev->all_callbacks);
99 	} else {
100 		RVector *cbs = ht_up_find (ev->callbacks, (ut64)handle.type, NULL);
101 		r_return_if_fail (cbs);
102 		del_hook (&handle.handle, 0, cbs);
103 	}
104 }
105 
r_event_send(REvent * ev,int type,void * data)106 R_API void r_event_send(REvent *ev, int type, void *data) {
107 	REventCallbackHook *hook;
108 	r_return_if_fail (ev && !ev->incall);
109 
110 	// send to both the per-type callbacks and to the all_callbacks
111 	ev->incall = true;
112 	r_vector_foreach (&ev->all_callbacks, hook) {
113 		hook->cb (ev, type, hook->user, data);
114 	}
115 	ev->incall = false;
116 
117 	RVector *cbs = ht_up_find (ev->callbacks, (ut64)type, NULL);
118 	if (!cbs) {
119 		return;
120 	}
121 	ev->incall = true;
122 	r_vector_foreach (cbs, hook) {
123 		hook->cb (ev, type, hook->user, data);
124 	}
125 	ev->incall = false;
126 }
127