1 /* radare - LGPL - Copyright 2013-2020 - pancake */
2
3 #include "r_types.h"
4 #include "r_util.h"
5 #include <stdio.h>
6
r_strbuf_new(const char * str)7 R_API RStrBuf *r_strbuf_new(const char *str) {
8 RStrBuf *s = R_NEW0 (RStrBuf);
9 if (str) {
10 r_strbuf_set (s, str);
11 }
12 return s;
13 }
14
r_strbuf_equals(RStrBuf * sa,RStrBuf * sb)15 R_API bool r_strbuf_equals(RStrBuf *sa, RStrBuf *sb) {
16 r_return_val_if_fail (sa && sb, false);
17 if (sa->len != sb->len) {
18 return false;
19 }
20 return strcmp (r_strbuf_get (sa), r_strbuf_get (sb)) == 0;
21 }
22
r_strbuf_is_empty(RStrBuf * sb)23 R_API bool r_strbuf_is_empty(RStrBuf *sb) {
24 return sb->len == 0;
25 }
26
r_strbuf_length(RStrBuf * sb)27 R_API int r_strbuf_length(RStrBuf *sb) {
28 r_return_val_if_fail (sb, 0);
29 return sb->len;
30 }
31
r_strbuf_init(RStrBuf * sb)32 R_API void r_strbuf_init(RStrBuf *sb) {
33 r_return_if_fail (sb);
34 memset (sb, 0, sizeof (RStrBuf));
35 }
36
r_strbuf_initf(RStrBuf * sb,const char * fmt,...)37 R_API const char *r_strbuf_initf(RStrBuf *sb, const char *fmt, ...) {
38 r_return_val_if_fail (sb && fmt, NULL);
39 r_strbuf_init (sb);
40 va_list ap;
41 va_start (ap, fmt);
42 const char *r = r_strbuf_vsetf (sb, fmt, ap);
43 va_end (ap);
44 return r;
45 }
46
r_strbuf_copy(RStrBuf * dst,RStrBuf * src)47 R_API bool r_strbuf_copy(RStrBuf *dst, RStrBuf *src) {
48 r_return_val_if_fail (dst && src, false);
49 if (src->ptr) {
50 char *p = malloc (src->ptrlen);
51 if (!p) {
52 return false;
53 }
54 memcpy (p, src->ptr, src->ptrlen);
55 free (dst->ptr);
56 dst->ptr = p;
57 dst->ptrlen = src->ptrlen;
58 } else {
59 R_FREE (dst->ptr);
60 memcpy (dst->buf, src->buf, sizeof (dst->buf));
61 }
62 dst->len = src->len;
63 return true;
64 }
65
r_strbuf_reserve(RStrBuf * sb,size_t len)66 R_API bool r_strbuf_reserve(RStrBuf *sb, size_t len) {
67 r_return_val_if_fail (sb, false);
68
69 if ((sb->ptr && len < sb->ptrlen) || (!sb->ptr && len < sizeof (sb->buf))) {
70 return true;
71 }
72 char *newptr = realloc (sb->ptr, len + 1);
73 if (!newptr) {
74 return false;
75 }
76 if (!sb->ptr) {
77 memcpy (newptr, sb->buf, sizeof (sb->buf));
78 }
79 sb->ptr = newptr;
80 sb->ptrlen = len + 1;
81 return true;
82 }
83
r_strbuf_setbin(RStrBuf * sb,const ut8 * s,size_t l)84 R_API bool r_strbuf_setbin(RStrBuf *sb, const ut8 *s, size_t l) {
85 r_return_val_if_fail (sb && s, false);
86 if (l >= sizeof (sb->buf)) {
87 char *ptr = sb->ptr;
88 if (!ptr || l + 1 > sb->ptrlen) {
89 ptr = malloc (l + 1);
90 if (!ptr) {
91 return false;
92 }
93 R_FREE (sb->ptr);
94 sb->ptrlen = l + 1;
95 sb->ptr = ptr;
96 }
97 memcpy (ptr, s, l);
98 ptr[l] = 0;
99 } else {
100 R_FREE (sb->ptr);
101 memcpy (sb->buf, s, l);
102 sb->buf[l] = 0;
103 }
104 sb->len = l;
105 sb->weakref = false;
106 return true;
107 }
108
109 // TODO: there's room for optimizations here
r_strbuf_slice(RStrBuf * sb,int from,int len)110 R_API bool r_strbuf_slice(RStrBuf *sb, int from, int len) {
111 r_return_val_if_fail (sb && from >= 0 && len >= 0, false);
112 if (from < 1 && len >= sb->len) {
113 return false;
114 }
115 const char *s = r_strbuf_get (sb);
116 const char *fr = r_str_ansi_chrn (s, from + 1);
117 const char *to = r_str_ansi_chrn (s, from + len + 1);
118 char *r = r_str_newlen (fr, to - fr);
119 r_strbuf_fini (sb);
120 r_strbuf_init (sb);
121 if (from >= len) {
122 r_strbuf_set (sb, "");
123 free (r);
124 return false;
125 }
126 r_strbuf_set (sb, r);
127 free (r);
128 return true;
129 }
130
r_strbuf_setptr(RStrBuf * sb,char * s,int len)131 R_API bool r_strbuf_setptr(RStrBuf *sb, char *s, int len) {
132 r_return_val_if_fail (sb, false);
133 if (len < 0) {
134 sb->len = strlen (s);
135 sb->ptrlen = sb->len + 1;
136 } else {
137 sb->ptrlen = len;
138 sb->len = len;
139 }
140 sb->ptr = s;
141 sb->weakref = true;
142 return true;
143 }
144
r_strbuf_set(RStrBuf * sb,const char * s)145 R_API const char *r_strbuf_set(RStrBuf *sb, const char *s) {
146 r_return_val_if_fail (sb, NULL);
147 if (!s) {
148 r_strbuf_init (sb);
149 return r_strbuf_get (sb);
150 }
151 size_t len = strlen (s);
152 if (!r_strbuf_setbin (sb, (const ut8*)s, len)) {
153 return NULL;
154 }
155 sb->len = len;
156 return r_strbuf_get (sb);
157 }
158
r_strbuf_setf(RStrBuf * sb,const char * fmt,...)159 R_API const char *r_strbuf_setf(RStrBuf *sb, const char *fmt, ...) {
160 r_return_val_if_fail (sb && fmt, false);
161
162 va_list ap;
163 va_start (ap, fmt);
164 const char *ret = r_strbuf_vsetf (sb, fmt, ap);
165 va_end (ap);
166 return ret;
167 }
168
r_strbuf_vsetf(RStrBuf * sb,const char * fmt,va_list ap)169 R_API const char *r_strbuf_vsetf(RStrBuf *sb, const char *fmt, va_list ap) {
170 r_return_val_if_fail (sb && fmt, false);
171
172 const char *ret = NULL;
173 va_list ap2;
174 va_copy (ap2, ap);
175 char string[1024];
176 int rc = vsnprintf (string, sizeof (string), fmt, ap);
177 if (rc >= sizeof (string)) {
178 char *p = malloc (rc + 1);
179 if (!p) {
180 goto done;
181 }
182 vsnprintf (p, rc + 1, fmt, ap2);
183 ret = r_strbuf_set (sb, p);
184 free (p);
185 } else if (rc >= 0) {
186 ret = r_strbuf_set (sb, string);
187 }
188 done:
189 va_end (ap2);
190 return ret;
191 }
192
r_strbuf_prepend(RStrBuf * sb,const char * s)193 R_API bool r_strbuf_prepend(RStrBuf *sb, const char *s) {
194 r_return_val_if_fail (sb && s, false);
195 int l = strlen (s);
196 // fast path if no chars to append
197 if (l == 0) {
198 return true;
199 }
200 int newlen = l + sb->len;
201 char *ns = malloc (newlen + 1);
202 bool ret = false;
203 if (ns) {
204 memcpy (ns, s, l);
205 char *s = sb->ptr ? sb->ptr: sb->buf;
206 memcpy (ns + l, s, sb->len);
207 ns[newlen] = 0;
208 ret = r_strbuf_set (sb, ns);
209 free (ns);
210 }
211 return ret;
212 }
213
r_strbuf_append(RStrBuf * sb,const char * s)214 R_API bool r_strbuf_append(RStrBuf *sb, const char *s) {
215 r_return_val_if_fail (sb && s, false);
216
217 int l = strlen (s);
218 return r_strbuf_append_n (sb, s, l);
219 }
220
r_strbuf_append_n(RStrBuf * sb,const char * s,size_t l)221 R_API bool r_strbuf_append_n(RStrBuf *sb, const char *s, size_t l) {
222 r_return_val_if_fail (sb && s, false);
223
224 if (sb->weakref) {
225 return false;
226 }
227
228 // fast path if no chars to append
229 if (l == 0) {
230 return true;
231 }
232
233 if ((sb->len + l + 1) <= sizeof (sb->buf)) {
234 memcpy (sb->buf + sb->len, s, l);
235 sb->buf[sb->len + l] = 0;
236 R_FREE (sb->ptr);
237 } else {
238 int newlen = sb->len + l + 128;
239 char *p = sb->ptr;
240 bool allocated = true;
241 if (!sb->ptr) {
242 p = malloc (newlen);
243 if (p && sb->len > 0) {
244 memcpy (p, sb->buf, sb->len);
245 }
246 } else if (sb->len + l + 1 > sb->ptrlen) {
247 p = realloc (sb->ptr, newlen);
248 } else {
249 allocated = false;
250 }
251 if (allocated) {
252 if (!p) {
253 return false;
254 }
255 sb->ptr = p;
256 sb->ptrlen = newlen;
257 }
258 if (p) {
259 memcpy (p + sb->len, s, l);
260 *(p + sb->len + l) = 0;
261 }
262 }
263 sb->len += l;
264 return true;
265 }
266
r_strbuf_appendf(RStrBuf * sb,const char * fmt,...)267 R_API bool r_strbuf_appendf(RStrBuf *sb, const char *fmt, ...) {
268 va_list ap;
269
270 r_return_val_if_fail (sb && fmt, -1);
271
272 va_start (ap, fmt);
273 bool ret = r_strbuf_vappendf (sb, fmt, ap);
274 va_end (ap);
275 return ret;
276 }
277
r_strbuf_vappendf(RStrBuf * sb,const char * fmt,va_list ap)278 R_API bool r_strbuf_vappendf(RStrBuf *sb, const char *fmt, va_list ap) {
279 int ret;
280 va_list ap2;
281 char string[1024];
282
283 r_return_val_if_fail (sb && fmt, -1);
284
285 if (sb->weakref) {
286 return false;
287 }
288 va_copy (ap2, ap);
289 ret = vsnprintf (string, sizeof (string), fmt, ap);
290 if (ret >= sizeof (string)) {
291 char *p = malloc (ret + 1);
292 if (!p) {
293 va_end (ap2);
294 return false;
295 }
296 *p = 0;
297 vsnprintf (p, ret + 1, fmt, ap2);
298 ret = r_strbuf_append (sb, p);
299 free (p);
300 } else if (ret >= 0) {
301 ret = r_strbuf_append (sb, string);
302 } else {
303 ret = false;
304 }
305 va_end (ap2);
306 return ret;
307 }
308
r_strbuf_get(RStrBuf * sb)309 R_API char *r_strbuf_get(RStrBuf *sb) {
310 r_return_val_if_fail (sb, NULL);
311 return sb->ptr ? sb->ptr : sb->buf;
312 }
313
r_strbuf_getbin(RStrBuf * sb,int * len)314 R_API ut8 *r_strbuf_getbin(RStrBuf *sb, int *len) {
315 r_return_val_if_fail (sb, NULL);
316 if (len) {
317 *len = sb->len;
318 }
319 return (ut8 *)(sb->ptr ? sb->ptr : sb->buf);
320 }
321
drain(RStrBuf * sb)322 static inline char *drain(RStrBuf *sb) {
323 return sb->ptr
324 ? sb->weakref
325 ? r_mem_dup (sb->ptr, sb->ptrlen)
326 : sb->ptr
327 : strdup (sb->buf);
328 }
329
r_strbuf_drain(RStrBuf * sb)330 R_API char *r_strbuf_drain(RStrBuf *sb) {
331 r_return_val_if_fail (sb, NULL);
332 char *ret = drain (sb);
333 free (sb);
334 return ret;
335 }
336
r_strbuf_drain_nofree(RStrBuf * sb)337 R_API char *r_strbuf_drain_nofree(RStrBuf *sb) {
338 r_return_val_if_fail (sb, NULL);
339 char *ret = drain (sb);
340 sb->ptr = NULL;
341 sb->len = 0;
342 sb->buf[0] = '\0';
343 return ret;
344 }
345
r_strbuf_free(RStrBuf * sb)346 R_API void r_strbuf_free(RStrBuf *sb) {
347 if (sb) {
348 r_strbuf_fini (sb);
349 free (sb);
350 }
351 }
352
r_strbuf_fini(RStrBuf * sb)353 R_API void r_strbuf_fini(RStrBuf *sb) {
354 if (sb && !sb->weakref) {
355 R_FREE (sb->ptr);
356 sb->len = 0;
357 sb->buf[0] = '\0';
358 }
359 }
360