1 /* radare - LGPL - Copyright 2019 - pancake, ret2libc */
2
3 #include "r_util/r_spaces.h"
4
r_spaces_new(const char * name)5 R_API RSpaces *r_spaces_new(const char *name) {
6 RSpaces *sp = R_NEW0 (RSpaces);
7 if (!sp || !r_spaces_init (sp, name)) {
8 free (sp);
9 return NULL;
10 }
11 return sp;
12 }
13
r_spaces_init(RSpaces * sp,const char * name)14 R_API bool r_spaces_init(RSpaces *sp, const char *name) {
15 r_return_val_if_fail (sp && name, false);
16 sp->name = strdup (name);
17 if (!sp->name) {
18 goto fail;
19 }
20
21 sp->spaces = NULL;
22 sp->current = NULL;
23 sp->spacestack = r_list_new ();
24 if (!sp->spacestack) {
25 goto fail;
26 }
27
28 sp->event = r_event_new (sp);
29 if (!sp->event) {
30 goto fail;
31 }
32
33 return true;
34
35 fail:
36 r_spaces_fini (sp);
37 return false;
38 }
39
r_spaces_free(RSpaces * sp)40 R_API void r_spaces_free(RSpaces *sp) {
41 r_spaces_fini (sp);
42 free (sp);
43 }
44
space_free(RSpace * s)45 static inline void space_free(RSpace *s) {
46 if (s) {
47 free (s->name);
48 free (s);
49 }
50 }
51
space_node_free(RBNode * n,void * user)52 static void space_node_free(RBNode *n, void *user) {
53 RSpace *s = container_of (n, RSpace, rb);
54 space_free (s);
55 }
56
r_spaces_fini(RSpaces * sp)57 R_API void r_spaces_fini(RSpaces *sp) {
58 r_list_free (sp->spacestack);
59 sp->spacestack = NULL;
60 r_rbtree_free (sp->spaces, space_node_free, NULL);
61 sp->spaces = NULL;
62 r_event_free (sp->event);
63 sp->event = NULL;
64 sp->current = NULL;
65 R_FREE (sp->name);
66 }
67
r_spaces_purge(RSpaces * sp)68 R_API void r_spaces_purge(RSpaces *sp) {
69 sp->current = NULL;
70 r_list_purge (sp->spacestack);
71 r_rbtree_free (sp->spaces, space_node_free, NULL);
72 sp->spaces = NULL;
73 }
74
name_space_cmp(const void * incoming,const RBNode * rb,void * user)75 static int name_space_cmp(const void *incoming, const RBNode *rb, void *user) {
76 const RSpace *s = container_of (rb, const RSpace, rb);
77 return strcmp (incoming, s->name);
78 }
79
r_spaces_get(RSpaces * sp,const char * name)80 R_API RSpace *r_spaces_get(RSpaces *sp, const char *name) {
81 if (!name) {
82 return NULL;
83 }
84 RBNode *n = r_rbtree_find (sp->spaces, (void *)name, name_space_cmp, NULL);
85 return n? container_of (n, RSpace, rb): NULL;
86 }
87
space_cmp(const void * incoming,const RBNode * rb,void * user)88 static int space_cmp(const void *incoming, const RBNode *rb, void *user) {
89 const RSpace *a = (const RSpace *)incoming;
90 const RSpace *b = container_of (rb, const RSpace, rb);
91 return strcmp (a->name, b->name);
92 }
93
r_spaces_add(RSpaces * sp,const char * name)94 R_API RSpace *r_spaces_add(RSpaces *sp, const char *name) {
95 r_return_val_if_fail (sp, NULL);
96 if (!name || !*name || *name == '*') {
97 return NULL;
98 }
99
100 RSpace *s = r_spaces_get (sp, name);
101 if (s) {
102 return s;
103 }
104
105 s = R_NEW0 (RSpace);
106 if (!s) {
107 return NULL;
108 }
109
110 s->name = strdup (name);
111 if (!s->name) {
112 free (s);
113 return NULL;
114 }
115
116 r_rbtree_insert (&sp->spaces, s, &s->rb, space_cmp, NULL);
117 return s;
118 }
119
r_spaces_set(RSpaces * sp,const char * name)120 R_API RSpace *r_spaces_set(RSpaces *sp, const char *name) {
121 sp->current = r_spaces_add (sp, name);
122 return sp->current;
123 }
124
spaces_unset_single(RSpaces * sp,const char * name)125 static inline bool spaces_unset_single(RSpaces *sp, const char *name) {
126 RSpace *space = r_spaces_get (sp, name);
127 if (!space) {
128 return false;
129 }
130
131 RSpaceEvent ev = { .data.unset.space = space };
132 r_event_send (sp->event, R_SPACE_EVENT_UNSET, &ev);
133 if (sp->current == space) {
134 sp->current = NULL;
135 }
136 return r_rbtree_delete (&sp->spaces, (void *)name, name_space_cmp, NULL, space_node_free, NULL);
137 }
138
r_spaces_unset(RSpaces * sp,const char * name)139 R_API bool r_spaces_unset(RSpaces *sp, const char *name) {
140 if (name) {
141 return spaces_unset_single (sp, name);
142 }
143
144 RList *names = r_list_newf ((RListFree)free);
145 if (!names) {
146 return false;
147 }
148
149 RBIter it;
150 RSpace *s;
151 r_spaces_foreach (sp, it, s) {
152 r_list_append (names, strdup (s->name));
153 }
154
155 RListIter *lit;
156 const char *n;
157 bool res = false;
158 r_list_foreach (names, lit, n) {
159 res |= spaces_unset_single (sp, n);
160 }
161 r_list_free (names);
162 return res;
163 }
164
r_spaces_count(RSpaces * sp,const char * name)165 R_API int r_spaces_count(RSpaces *sp, const char *name) {
166 RSpace *s = r_spaces_get (sp, name);
167 if (!s) {
168 return 0;
169 }
170 RSpaceEvent ev = { .data.count.space = s, .res = 0 };
171 r_event_send (sp->event, R_SPACE_EVENT_COUNT, &ev);
172 return ev.res;
173 }
174
r_spaces_push(RSpaces * sp,const char * name)175 R_API bool r_spaces_push(RSpaces *sp, const char *name) {
176 r_return_val_if_fail (sp, false);
177
178 r_list_push (sp->spacestack, sp->current? sp->current->name: "*");
179 r_spaces_set (sp, name);
180 return true;
181 }
182
r_spaces_pop(RSpaces * sp)183 R_API bool r_spaces_pop(RSpaces *sp) {
184 char *name = r_list_pop (sp->spacestack);
185 if (!name) {
186 return false;
187 }
188
189 RSpace *s = r_spaces_get (sp, name);
190 r_spaces_set (sp, s? s->name: NULL);
191 return true;
192 }
193
r_spaces_rename(RSpaces * sp,const char * oname,const char * nname)194 R_API bool r_spaces_rename(RSpaces *sp, const char *oname, const char *nname) {
195 if (!oname && !sp->current) {
196 return false;
197 }
198
199 RSpace *s;
200 if (oname) {
201 s = r_spaces_get (sp, oname);
202 if (!s) {
203 return false;
204 }
205 } else {
206 s = sp->current;
207 }
208
209 RSpace *sn = r_spaces_get (sp, nname);
210 if (sn) {
211 return false;
212 }
213
214 RSpaceEvent ev = {
215 .data.rename.oldname = s->name,
216 .data.rename.newname = nname,
217 .data.rename.space = s
218 };
219 r_event_send (sp->event, R_SPACE_EVENT_RENAME, &ev);
220
221 r_rbtree_delete (&sp->spaces, (void *)s->name, name_space_cmp, NULL, NULL, NULL);
222 free (s->name);
223 s->name = strdup (nname);
224 r_rbtree_insert (&sp->spaces, s, &s->rb, space_cmp, NULL);
225
226 return true;
227 }
228