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