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