1 /* radare - LGPL - Copyright 2007-2020 - pancake */
2 
3 #include "r_types.h"
4 #include "r_util.h"
5 #include "r_cons.h"
6 #include "r_bin.h"
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <ctype.h>
11 #include <stdarg.h>
12 #include <r_util/r_base64.h>
13 
14 /* stable code */
15 static const char *nullstr = "";
16 static const char *nullstr_c = "(null)";
17 static const char *rwxstr[] = {
18 	[0] = "---",
19 	[1] = "--x",
20 	[2] = "-w-",
21 	[3] = "-wx",
22 	[4] = "r--",
23 	[5] = "r-x",
24 	[6] = "rw-",
25 	[7] = "rwx",
26 
27 	[8] = "---",
28 	[9] = "--x",
29 	[10] = "-w-",
30 	[11] = "-wx",
31 	[12] = "r--",
32 	[13] = "r-x",
33 	[14] = "rw-",
34 	[15] = "rwx",
35 };
36 
37 
r_str_casecmp(const char * s1,const char * s2)38 R_API int r_str_casecmp(const char *s1, const char *s2) {
39 #ifdef _MSC_VER
40 	return stricmp (s1, s2);
41 #else
42 	return strcasecmp (s1, s2);
43 #endif
44 }
45 
r_str_ncasecmp(const char * s1,const char * s2,size_t n)46 R_API int r_str_ncasecmp(const char *s1, const char *s2, size_t n) {
47 #ifdef _MSC_VER
48 	return _strnicmp (s1, s2, n);
49 #else
50 	return strncasecmp (s1, s2, n);
51 #endif
52 }
53 
54 // GOOD
55 // In-place replace the first instance of the character a, with the character b.
r_str_replace_ch(char * s,char a,char b,bool global)56 R_API int r_str_replace_ch(char *s, char a, char b, bool global) {
57 	int ret = 0;
58 	char *o = s;
59 	if (!s || a == b) {
60 		return 0;
61 	}
62 	for (; *o; s++, o++) {
63 		if (*o == a) {
64 			ret++;
65 			if (b) {
66 				*s = b;
67 			} else {
68 				/* remove char */
69 				s--;
70 			}
71 			if (!global) {
72 				return 1;
73 			}
74 		} else {
75 			*s = *o;
76 		}
77 	}
78 	*s = 0;
79 	return ret;
80 }
81 
r_str_replace_char_once(char * s,int a,int b)82 R_API int r_str_replace_char_once(char *s, int a, int b) {
83 	return r_str_replace_ch (s, a, b, false);
84 }
85 
r_str_replace_char(char * s,int a,int b)86 R_API int r_str_replace_char(char *s, int a, int b) {
87 	return r_str_replace_ch (s, a, b, true);
88 }
89 
r_str_remove_char(char * str,char c)90 R_API void r_str_remove_char(char *str, char c) {
91 	while (*str) {
92 		if (*str == c) {
93 			memmove (str, str + 1, strlen (str + 1) + 1);
94 			continue;
95 		}
96 		str++;
97 	}
98 }
99 
r_str_reverse(char * str)100 R_API void r_str_reverse(char *str) {
101 	int i, len = strlen (str);
102 	int half = len / 2;
103 	for (i = 0; i < half; i++) {
104 		char ch = str[i];
105 		str[i] = str[len - i - 1];
106 		str[len - i - 1] = ch;
107 	}
108 }
109 
110 // TODO: do not use toupper.. must support modes to also append lowercase chars like in r1
111 // TODO: this functions needs some stabilization
r_str_bits(char * strout,const ut8 * buf,int len,const char * bitz)112 R_API int r_str_bits(char *strout, const ut8 *buf, int len, const char *bitz) {
113 	int i, j, idx;
114 	if (bitz) {
115 		for (i = j = 0; i<len && (!bitz||bitz[i]); i++) {
116 			if (i > 0 && (i % 8) == 0) {
117 				buf++;
118 			}
119 			if (*buf & (1 << (i % 8))) {
120 				strout[j++] = toupper ((const ut8)bitz[i]);
121 			}
122 		}
123 	} else {
124 		for (i = j = 0; i < len; i++) {
125 			idx = (i / 8);
126 			int bit = 7 - (i % 8);
127 			strout[j++] = (buf[idx] & (1 << bit))? '1' : '0';
128 		}
129 	}
130 	strout[j] = 0;
131 	return j;
132 }
133 
r_str_sysbits(const int v)134 R_API const char *r_str_sysbits(const int v) {
135 	switch (v) {
136 	case R_SYS_BITS_8: return "8";
137 	case R_SYS_BITS_16: return "16";
138 	case R_SYS_BITS_32: return "32";
139 	case R_SYS_BITS_64: return "64";
140 	case R_SYS_BITS_16 | R_SYS_BITS_32: return "16,32";
141 	case R_SYS_BITS_16 | R_SYS_BITS_32 | R_SYS_BITS_64: return "16,32,64";
142 	case R_SYS_BITS_32 | R_SYS_BITS_64: return "32,64";
143 	}
144 	return "?";
145 }
146 
147 // In-place trims a bitstring to groups of 8 bits.
148 // For example, the bitstring 1000000000000000 will not be modified, but the
149 // bitstring 0000000001000000 will be changed to 01000000.
trimbits(char * b)150 static void trimbits(char *b) {
151 	const int len = strlen (b);
152 	char *one = strchr (b, '1');
153 	int pos = one ? (int)(size_t)(one - b) : len - 1;
154 	pos = (pos / 8) * 8;
155 	memmove (b, b + pos, len - pos + 1);
156 }
157 
158 // Set 'strout' to the binary representation of the input value.
159 // strout must be a char array of 65 or greater.
160 // The string is then trimmed using the "trimbits" function above.
r_str_bits64(char * strout,ut64 in)161 R_API int r_str_bits64(char* strout, ut64 in) {
162 	int i, bit, count = 0;
163 	count = 0;
164 	for (i = (sizeof (in) * 8) - 1; i >= 0; i--) {
165 		bit = in >> i;
166 		if (bit & 1) {
167 			strout[count] = '1';
168 		} else {
169 			strout[count] = '0';
170 		}
171 		count++;
172 	}
173 	strout[count] = '\0';
174 	/* trim by 8 bits */
175 	trimbits (strout);
176 	return count;
177 }
178 
179 /**
180  * function: r_str_bits_from_num
181  *
182  */
r_str_bits_from_string(const char * buf,const char * bitz)183 R_API ut64 r_str_bits_from_string(const char *buf, const char *bitz) {
184 	ut64 out = 0LL;
185 	/* return the numeric value associated to a string (rflags) */
186 	for (; *buf; buf++) {
187 		char *ch = strchr (bitz, toupper ((const unsigned char)*buf));
188 		if (!ch) {
189 			ch = strchr (bitz, tolower ((const unsigned char)*buf));
190 		}
191 		if (ch) {
192 			int bit = (int)(size_t)(ch - bitz);
193 			out |= (ut64)(1LL << bit);
194 		} else {
195 			return UT64_MAX;
196 		}
197 	}
198 	return out;
199 }
200 
r_str_binstr2bin(const char * str,ut8 * out,int outlen)201 R_API int r_str_binstr2bin(const char *str, ut8 *out, int outlen) {
202 	int n, i, j, k, ret, len;
203 	len = strlen (str);
204 	for (n = i = 0; i < len; i += 8) {
205 		ret = 0;
206 		while (str[i]==' ') {
207 			str++;
208 		}
209 		if (i + 7 < len) {
210 			for (k = 0, j = i + 7; j >= i; j--, k++) {
211 				// INVERSE for (k=0,j=i; j<i+8; j++,k++) {
212 				if (str[j] == ' ') {
213 					//k--;
214 					continue;
215 				}
216 				//		printf ("---> j=%d (%c) (%02x)\n", j, str[j], str[j]);
217 				if (str[j] == '1') {
218 					ret|=1 << k;
219 				} else if (str[j] != '0') {
220 					return n;
221 				}
222 			}
223 		}
224 	//	printf ("-======> %02x\n", ret);
225 		out[n++] = ret;
226 		if (n == outlen) {
227 			return n;
228 		}
229 	}
230 	return n;
231 }
232 
233 // Returns the permissions as in integer given an input in the form of rwx, rx,
234 // etc.
r_str_rwx(const char * str)235 R_API int r_str_rwx(const char *str) {
236 	int ret = atoi (str);
237 	if (!ret) {
238 		ret |= strchr (str, 'm') ? 16 : 0;
239 		ret |= strchr (str, 'r') ? 4 : 0;
240 		ret |= strchr (str, 'w') ? 2 : 0;
241 		ret |= strchr (str, 'x') ? 1 : 0;
242 	} else if (ret < 0 || ret >= R_ARRAY_SIZE (rwxstr)) {
243 		ret = 0;
244 	}
245 	return ret;
246 }
247 
248 // Returns the string representation of the permission of the inputted integer.
r_str_rwx_i(int rwx)249 R_API const char *r_str_rwx_i(int rwx) {
250 	if (rwx < 0 || rwx >= R_ARRAY_SIZE (rwxstr)) {
251 		rwx = 0;
252 	}
253 	return rwxstr[rwx % 24]; // 15 for srwx
254 }
255 
256 // If up is true, upcase all characters in the string, otherwise downcase all
257 // characters in the string.
r_str_case(char * str,bool up)258 R_API void r_str_case(char *str, bool up) {
259 	if (up) {
260 		char oc = 0;
261 		for (; *str; oc = *str++) {
262 			*str = (*str=='x' && oc=='0') ? 'x': toupper ((int)(ut8)*str);
263 		}
264 	} else {
265 		for (; *str; str++) {
266 			*str = tolower ((int)(ut8)*str);
267 		}
268 	}
269 }
270 
r_str_home(const char * str)271 R_API char *r_str_home(const char *str) {
272 	char *dst, *home = r_sys_getenv (R_SYS_HOME);
273 	size_t length;
274 	if (!home) {
275 		home = r_file_tmpdir ();
276 		if (!home) {
277 			return NULL;
278 		}
279 	}
280 	length = strlen (home) + 1;
281 	if (str) {
282 		length += strlen (R_SYS_DIR) + strlen (str);
283 	}
284 	dst = (char *)malloc (length);
285 	if (!dst) {
286 		goto fail;
287 	}
288 	int home_len = strlen (home);
289 	memcpy (dst, home, home_len + 1);
290 	if (str) {
291 		dst[home_len] = R_SYS_DIR[0];
292 		strcpy (dst + home_len + 1, str);
293 	}
294 fail:
295 	free (home);
296 	return dst;
297 }
298 
r_str_r2_prefix(const char * str)299 R_API char *r_str_r2_prefix(const char *str) {
300 	return r_str_newf ("%s%s%s", r_sys_prefix (NULL), R_SYS_DIR, str);
301 }
302 
303 // Compute a 64 bit DJB hash of a string.
r_str_hash64(const char * s)304 R_API ut64 r_str_hash64(const char *s) {
305 	ut64 len, h = 5381;
306 	if (!s) {
307 		return 0;
308 	}
309 	for (len = strlen (s); len > 0; len--) {
310 		h = (h ^ (h << 5)) ^ *s++;
311 	}
312 	return h;
313 }
314 
315 // Compute a 32bit DJB hash of a string.
r_str_hash(const char * s)316 R_API ut32 r_str_hash(const char *s) {
317 	return (ut32) r_str_hash64 (s);
318 }
319 
r_str_delta(char * p,char a,char b)320 R_API int r_str_delta(char *p, char a, char b) {
321 	char *_a = strchr (p, a);
322 	char *_b = strchr (p, b);
323 	return (!_a || !_b)? 0 : (_a - _b);
324 }
325 
326 // In-place split string using ch as a delimiter. Replaces all instances of ch
327 // with a null byte. Returns the number of split strings. For example
328 // r_str_split("hello world", ' ') will replace the space with '\0' and
329 // return 2.
r_str_split(char * str,char ch)330 R_API int r_str_split(char *str, char ch) {
331 	int i;
332 	char *p;
333 	if (!str || !*str) {
334 		return 0;
335 	}
336 	/* TODO: sync with r1 code */
337 	for (i = 1, p = str; *p; p++) {
338 		if (*p == ch) {
339 			i++;
340 			*p = '\0';
341 		} // s/ /\0/g
342 	}
343 	return i;
344 }
345 
346 // Convert a string into an array of string separated by \0
347 // And the last by \0\0
348 // Separates by words and skip spaces.
349 // Returns the number of tokens that the string is tokenized into.
r_str_word_set0(char * str)350 R_API int r_str_word_set0(char *str) {
351 	int i, quote = 0;
352 	char *p;
353 	if (!str || !*str) {
354 		return 0;
355 	}
356 	for (i = 0; str[i] && str[i + 1]; i++) {
357 		if (i > 0 && str[i-1] == ' ' && str[i] == ' ') {
358 			int len = strlen (str + i);
359 			memmove (str + i, str + i + 1, len);
360 			i--;
361 		}
362 	}
363 	if (str[i] == ' ') {
364 		str[i] = 0;
365 	}
366 	for (i = 1, p = str; *p; p++) {
367 		if (*p == '\"') {
368 			if (quote) {
369 				quote = 0;
370 				*p = '\0';
371 				// FIX: i++;
372 				continue;
373 			} else {
374 				quote = 1;
375 				memmove (p, p + 1, strlen (p + 1) + 1);
376 			}
377 		}
378 		if (quote) {
379 			continue;
380 		}
381 		if (*p == ' ') {
382 			char *q = p - 1;
383 			if (p > str && (*q == '\\' || !*q)) {
384 				memmove (p, p + 1, strlen (p + 1) + 1);
385 				if (*q == '\\') {
386 					*q = ' ';
387 					continue;
388 				}
389 				p--;
390 			}
391 			i++;
392 			*p = '\0';
393 		} // s/ /\0/g
394 	}
395 	return i;
396 }
397 
r_str_word_set0_stack(char * str)398 R_API int r_str_word_set0_stack(char *str) {
399 	int i;
400 	char *p, *q;
401 	RStack *s;
402 	void *pop;
403 	if (!str || !*str) {
404 		return 0;
405 	}
406 	for (i = 0; str[i] && str[i+1]; i++) {
407 		if (i > 0 && str[i - 1] == ' ' && str[i] == ' ') {
408 			memmove (str + i, str + i + 1, strlen (str + i));
409 			i--;
410 		}
411 		if (i == 0 && str[i] == ' ') {
412 			memmove (str + i, str + i + 1, strlen (str + i));
413 		}
414 	}
415 	if (str[i] == ' ') {
416 		str[i] = 0;
417 	}
418 	s = r_stack_new (5); //Some random number
419 	for (i = 1, p = str; *p; p++) {
420 		q = p - 1;
421 		if (p > str && (*q == '\\')) {
422 			memmove (q, p, strlen (p) + 1);
423 			p--;
424 			continue;
425 		}
426 		switch (*p) {
427 		case '(':
428 		case '{':
429 		case '[':
430 			r_stack_push (s, (void *)p);
431 			continue;
432 		case '\'':
433 		case '"':
434 			pop = r_stack_pop (s);
435 			if (pop && *(char *)pop != *p) {
436 				r_stack_push (s, pop);
437 				r_stack_push (s, (void *)p);
438 			} else if (!pop) {
439 				r_stack_push (s, (void *)p);
440 			}
441 			continue;
442 		case ')':
443 		case '}':
444 		case ']':
445 			pop = r_stack_pop (s);
446 			if (pop) {
447 				if ((*(char *)pop == '(' && *p == ')') ||
448 					(*(char *)pop == '{' && *p == '}') ||
449 					(*(char *)pop == '[' && *p == ']')) {
450 					continue;
451 				}
452 			}
453 			break;
454 		case ' ':
455 			if (p > str && !*q) {
456 				memmove (p, p+1, strlen (p + 1) + 1);
457 				if (*q == '\\') {
458 					*q = ' ';
459 					continue;
460 				}
461 				p--;
462 			}
463 			if (r_stack_is_empty (s)) {
464 				i++;
465 				*p = '\0';
466 			}
467 		default:
468 			break;
469 		}
470 	}
471 	r_stack_free (s);
472 	return i;
473 }
474 
r_str_word_get0set(char * stra,int stralen,int idx,const char * newstr,int * newlen)475 R_API char *r_str_word_get0set(char *stra, int stralen, int idx, const char *newstr, int *newlen) {
476 	char *p = NULL;
477 	char *out;
478 	int alen, blen, nlen;
479 	if (!stra && !newstr) {
480 		return NULL;
481 	}
482 	if (stra) {
483 		p = (char *)r_str_word_get0 (stra, idx);
484 	}
485 	if (!p) {
486 		int nslen = strlen (newstr);
487 		out = malloc (nslen + 1);
488 		if (!out) {
489 			return NULL;
490 		}
491 		strcpy (out, newstr);
492 		out[nslen] = 0;
493 		if (newlen) {
494 			*newlen = nslen;
495 		}
496 		return out;
497 	}
498 	alen = (size_t)(p - stra);
499 	blen = stralen - ((alen + strlen (p)) + 1);
500 	if (blen < 0) {
501 		blen = 0;
502 	}
503 	nlen = alen + blen + strlen (newstr);
504 	out = malloc (nlen + 2);
505 	if (!out) {
506 		return NULL;
507 	}
508 	if (alen > 0) {
509 		memcpy (out, stra, alen);
510 	}
511 	memcpy (out + alen, newstr, strlen (newstr) + 1);
512 	if (blen > 0) {
513 		memcpy (out + alen + strlen (newstr) + 1, p + strlen (p) + 1, blen + 1);
514 	}
515 	out[nlen + 1] = 0;
516 	if (newlen) {
517 		*newlen = nlen + ((blen == 0)? 1 : 0);
518 	}
519 	return out;
520 }
521 
522 // Get the idx'th entry of a tokenized string.
523 // XXX: Warning! this function is UNSAFE, check that the string has, at least,
524 // idx+1 tokens.
r_str_word_get0(const char * str,int idx)525 R_API const char *r_str_word_get0(const char *str, int idx) {
526 	int i;
527 	const char *ptr = str;
528 	if (!ptr || idx < 0 /* prevent crashes with negative index */) {
529 		return (char *)nullstr;
530 	}
531 	for (i = 0; i != idx; i++) {
532 		ptr += strlen (ptr) + 1;
533 	}
534 	return ptr;
535 }
536 
537 // Return the number of times that the character ch appears in the string.
r_str_char_count(const char * string,char ch)538 R_API int r_str_char_count(const char *string, char ch) {
539 	int i, count = 0;
540 	for (i = 0; string[i]; i++) {
541 		if (string[i] == ch) {
542 			count++;
543 		}
544 	}
545 	return count;
546 }
547 
548 // Counts the number of words (separated by separator characters: newlines, tabs,
549 // return, space). See r_util.h for more details of the IS_SEPARATOR macro.
r_str_word_count(const char * string)550 R_API int r_str_word_count(const char *string) {
551 	const char *text, *tmp;
552 	int word;
553 
554 	for (text = tmp = string; *text && IS_SEPARATOR (*text); text++) {
555 		;
556 	}
557 	for (word = 0; *text; word++) {
558 		for (; *text && !IS_SEPARATOR (*text); text++) {
559 			;
560 		}
561 		for (tmp = text; *text && IS_SEPARATOR (*text); text++) {
562 			;
563 		}
564 	}
565 	return word;
566 }
567 
568 // Returns a pointer to the first instance of a character that isn't chr in a
569 // string.
570 // TODO: make this const-correct.
571 // XXX if the string is only made up of chr, then the pointer will just point to
572 // a null byte!
r_str_ichr(char * str,char chr)573 R_API char *r_str_ichr(char *str, char chr) {
574 	while (*str == chr) {
575 		str++;
576 	}
577 	return str;
578 }
579 
580 // Returns a pointer to the last instance of the character chr in the input
581 // string.
r_str_lchr(const char * str,char chr)582 R_API const char *r_str_lchr(const char *str, char chr) {
583 	if (str) {
584 		int len = strlen (str);
585 		for (; len >= 0; len--) {
586 			if (str[len] == chr) {
587 				return str + len;
588 			}
589 		}
590 	}
591 	return NULL;
592 }
593 
594 /* find the last char chr in the substring str[start:end] with end not included */
r_sub_str_lchr(const char * str,int start,int end,char chr)595 R_API const char *r_sub_str_lchr(const char *str, int start, int end, char chr) {
596 	do {
597 		end--;
598 	} while (str[end] != chr && end >= start);
599 	return str[end] == chr ? &str[end] : NULL;
600 }
601 
602 /* find the first char chr in the substring str[start:end] with end not included */
r_sub_str_rchr(const char * str,int start,int end,char chr)603 R_API const char *r_sub_str_rchr(const char *str, int start, int end, char chr) {
604 	while (str[start] != chr && start < end) {
605 		start++;
606 	}
607 	return str[start] == chr ? str + start : NULL;
608 }
609 
r_str_sep(const char * base,const char * sep)610 R_API const char *r_str_sep(const char *base, const char *sep) {
611 	int i;
612 	while (*base) {
613 		for (i = 0; sep[i]; i++) {
614 			if (*base == sep[i]) {
615 				return base;
616 			}
617 		}
618 		base++;
619 	}
620 	return NULL;
621 }
622 
r_str_rsep(const char * base,const char * p,const char * sep)623 R_API const char *r_str_rsep(const char *base, const char *p, const char *sep) {
624 	int i;
625 	while (p >= base) {
626 		for (i = 0; sep[i]; i++) {
627 			if (*p == sep[i]) {
628 				return p;
629 			}
630 		}
631 		p--;
632 	}
633 	return NULL;
634 }
635 
r_str_rstr(const char * base,const char * p)636 R_API const char *r_str_rstr(const char *base, const char *p) {
637 	char *s = strdup (base);
638 	char *k = strdup (p);
639 	r_str_reverse (s);
640 	r_str_reverse (k);
641 	char *q = strstr (s, k);
642 	const char *r = NULL;
643 	if (q) {
644 		r = base + strlen (base) - (q - s) - strlen (p);
645 	}
646 	free (s);
647 	free (k);
648 	return r;
649 }
650 
r_str_rchr(const char * base,const char * p,int ch)651 R_API const char *r_str_rchr(const char *base, const char *p, int ch) {
652 	r_return_val_if_fail (base, NULL);
653 	if (!p) {
654 		return strrchr (base, ch);
655 	}
656 	for (; p >= base; p--) {
657 		if (ch == *p) {
658 			break;
659 		}
660 	}
661 	return (p >= base) ? p: NULL;
662 }
663 
r_str_nstr(const char * s,const char * find,int slen)664 R_API const char *r_str_nstr(const char *s, const char *find, int slen) {
665 	char c, sc;
666 	size_t len;
667 
668 	if ((c = *find++) != '\0') {
669 		len = strlen (find);
670 		do {
671 			do {
672 				if (slen-- < 1 || !(sc = *s++)) {
673 					return NULL;
674 				}
675 			} while (sc != c);
676 			if (len > slen) {
677 				return NULL;
678 			}
679 		} while (strncmp (s, find, len) != 0);
680 		s--;
681 	}
682 	return (char *)s;
683 }
684 
685 // Returns a new heap-allocated copy of str.
686 // XXX what's the diff with r_str_dup ?
r_str_new(const char * str)687 R_API char *r_str_new(const char *str) {
688 	return str? strdup (str): NULL;
689 }
690 
691 // Returns a new heap-allocated copy of str, sets str[len] to '\0'.
692 // If the input str is longer than len, it will be truncated.
r_str_newlen(const char * str,int len)693 R_API char *r_str_newlen(const char *str, int len) {
694 	if (len < 1) {
695 		return NULL;
696 	}
697 	char *buf = malloc (len + 1);
698 	if (buf) {
699 		memcpy (buf, str, len);
700 		buf[len] = 0;
701 	}
702 	return buf;
703 }
704 
r_str_trunc_ellipsis(const char * str,int len)705 R_API char *r_str_trunc_ellipsis(const char *str, int len) {
706 	if (!str) {
707 		return NULL;
708 	}
709 	if (strlen (str) < len) {
710 		return strdup (str);
711 	}
712 	char *buf = r_str_newlen (str, len);
713 	if (buf && len > 4) {
714 		strcpy (buf + len - 4, "...");
715 	}
716 	return buf;
717 }
718 
r_str_newf(const char * fmt,...)719 R_API char *r_str_newf(const char *fmt, ...) {
720 	va_list ap, ap2;
721 
722 	va_start (ap, fmt);
723 	if (!strchr (fmt, '%')) {
724 		va_end (ap);
725 		return strdup (fmt);
726 	}
727 	va_copy (ap2, ap);
728 	int ret = vsnprintf (NULL, 0, fmt, ap2);
729 	ret++;
730 	char *p = calloc (1, ret);
731 	if (p) {
732 		(void)vsnprintf (p, ret, fmt, ap);
733 	}
734 	va_end (ap2);
735 	va_end (ap);
736 	return p;
737 }
738 
739 // Secure string copy with null terminator (like strlcpy or strscpy but ours
r_str_ncpy(char * dst,const char * src,size_t n)740 R_API size_t r_str_ncpy(char *dst, const char *src, size_t n) {
741 	size_t i;
742 
743 	// do not do anything if n is 0
744 	if (n == 0) {
745 		return 0;
746 	}
747 
748 	n--;
749 	for (i = 0; src[i] && n > 0; i++, n--) {
750 		dst[i] = src[i];
751 	}
752 	dst[i] = 0;
753 	return i;
754 }
755 
756 /* memccmp("foo.bar", "foo.cow, '.') == 0 */
757 // Returns 1 if src and dst are equal up until the first instance of ch in src.
r_str_ccmp(const char * dst,const char * src,int ch)758 R_API bool r_str_ccmp(const char *dst, const char *src, int ch) {
759 	int i;
760 	for (i = 0; src[i] && src[i] != ch; i++) {
761 		if (dst[i] != src[i]) {
762 			return true;
763 		}
764 	}
765 	return false;
766 }
767 
768 // Returns true if item is in sep-separated list
r_str_cmp_list(const char * list,const char * item,char sep)769 R_API bool r_str_cmp_list(const char *list, const char *item, char sep) {
770 	if (!list || !item) {
771 		return false;
772 	}
773 	int i = 0, j = 0;
774 	for (; list[i] && list[i] != sep; i++, j++) {
775 		if (item[j] != list[i]) {
776 			while (list[i] && list[i] != sep) {
777 				i++;
778 			}
779 			if (!list[i]) {
780 				return false;
781 			}
782 			j = -1;
783 			continue;
784 		}
785 	}
786 	return true;
787 }
788 
789 // like strncmp, but checking for null pointers
r_str_cmp(const char * a,const char * b,int len)790 R_API int r_str_cmp(const char *a, const char *b, int len) {
791 	if ((a == b) || (!a && !b)) {
792 		return 0;
793 	}
794 	if (!a && b) {
795 		return -1;
796 	}
797 	if (a && !b) {
798 		return 1;
799 	}
800 	if (len < 0) {
801 		return strcmp (a, b);
802 	}
803 	return strncmp (a, b, len);
804 }
805 
806 // Copies all characters from src to dst up until the character 'ch'.
r_str_ccpy(char * dst,char * src,int ch)807 R_API int r_str_ccpy(char *dst, char *src, int ch) {
808 	int i;
809 	for (i = 0; src[i] && src[i] != ch; i++) {
810 		dst[i] = src[i];
811 	}
812 	dst[i] = '\0';
813 	return i;
814 }
815 
r_str_word_get_first(const char * text)816 R_API char *r_str_word_get_first(const char *text) {
817 	for (; *text && IS_SEPARATOR (*text); text++) {
818 		;
819 	}
820 	return strdup (text);
821 }
822 
r_str_get(const char * str)823 R_API const char *r_str_get(const char *str) {
824 	return str? str: nullstr;
825 }
826 
r_str_get_fail(const char * str,const char * failstr)827 R_API const char *r_str_get_fail(const char *str, const char *failstr) {
828 	return str? str: failstr;
829 }
830 
r_str_getf(const char * str)831 R_API const char *r_str_getf(const char *str) {
832 	return str? str: nullstr_c;
833 }
834 
r_str_ndup(const char * ptr,int len)835 R_API char *r_str_ndup(const char *ptr, int len) {
836 	if (len < 0) {
837 		return NULL;
838 	}
839 	char *out = malloc (len + 1);
840 	if (!out) {
841 		return NULL;
842 	}
843 	strncpy (out, ptr, len);
844 	out[len] = 0;
845 	return out;
846 }
847 
848 // TODO: deprecate?
r_str_dup(char * ptr,const char * string)849 R_API char *r_str_dup(char *ptr, const char *string) {
850 	char *str = r_str_new (string);
851 	free (ptr); // in case ptr == string
852 	return str;
853 }
854 
r_str_prepend(char * ptr,const char * string)855 R_API char *r_str_prepend(char *ptr, const char *string) {
856 	int slen, plen;
857 	if (!ptr) {
858 		return strdup (string);
859 	}
860 	plen = strlen (ptr);
861 	slen = strlen (string);
862 	ptr = realloc (ptr, slen + plen + 1);
863 	if (!ptr) {
864 		return NULL;
865 	}
866 	memmove (ptr + slen, ptr, plen + 1);
867 	memmove (ptr, string, slen);
868 	return ptr;
869 }
870 
r_str_appendlen(char * ptr,const char * string,int slen)871 R_API char *r_str_appendlen(char *ptr, const char *string, int slen) {
872 	char *msg = r_str_newlen (string, slen);
873 	char *ret = r_str_append (ptr, msg);
874 	free (msg);
875 	return ret;
876 }
877 
r_str_append_owned(char * ptr,char * string)878 R_API char *r_str_append_owned(char *ptr, char *string) {
879 	if (!ptr) {
880 		return string;
881 	}
882 	char *r = r_str_append(ptr, string);
883 	free (string);
884 	return r;
885 }
886 /*
887  * first argument must be allocated
888  * return: the pointer ptr resized to string size.
889  */
r_str_append(char * ptr,const char * string)890 R_API char *r_str_append(char *ptr, const char *string) {
891 	if (string && !ptr) {
892 		return strdup (string);
893 	}
894 	if (R_STR_ISEMPTY (string)) {
895 		return ptr;
896 	}
897 	int plen = strlen (ptr);
898 	int slen = strlen (string);
899 	char *newptr = realloc (ptr, slen + plen + 1);
900 	if (!newptr) {
901 		free (ptr);
902 		return NULL;
903 	}
904 	ptr = newptr;
905 	memcpy (ptr + plen, string, slen + 1);
906 	return ptr;
907 }
908 
r_str_appendf(char * ptr,const char * fmt,...)909 R_API char *r_str_appendf(char *ptr, const char *fmt, ...) {
910 	va_list ap, ap2;
911 
912 	va_start (ap, fmt);
913 	if (!strchr (fmt, '%')) {
914 		va_end (ap);
915 		return r_str_append (ptr, fmt);
916 	}
917 	va_copy (ap2, ap);
918 	int ret = vsnprintf (NULL, 0, fmt, ap2);
919 	ret++;
920 	char *p = calloc (1, ret);
921 	if (p) {
922 		(void)vsnprintf (p, ret, fmt, ap);
923 		ptr = r_str_append (ptr, p);
924 		free (p);
925 	}
926 	va_end (ap2);
927 	va_end (ap);
928 	return ptr;
929 }
930 
r_str_appendch(char * x,char y)931 R_API char *r_str_appendch(char *x, char y) {
932 	char b[2] = { y, 0 };
933 	return r_str_append (x, b);
934 }
935 
r_str_replace(char * str,const char * key,const char * val,int g)936 R_API char* r_str_replace(char *str, const char *key, const char *val, int g) {
937 	if (g == 'i') {
938 		return r_str_replace_icase (str, key, val, g, true);
939 	}
940 	r_return_val_if_fail (str && key && val, NULL);
941 
942 	int off, i, slen;
943 	char *newstr, *p = str;
944 	int klen = strlen (key);
945 	int vlen = strlen (val);
946 	if (klen == 1 && vlen < 2) {
947 		r_str_replace_char (str, *key, *val);
948 		return str;
949 	}
950 	if (klen == vlen && !strcmp (key, val)) {
951 		return str;
952 	}
953 	slen = strlen (str);
954 	char *q = str;
955 	for (;;) {
956 		p = strstr (q, key);
957 		if (!p) {
958 			break;
959 		}
960 		off = (int)(size_t)(p - str);
961 		if (vlen != klen) {
962 			int tlen = slen - (off + klen);
963 			slen += vlen - klen;
964 			if (vlen > klen) {
965 				newstr = realloc (str, slen + 1);
966 				if (!newstr) {
967 					eprintf ("realloc fail\n");
968 					R_FREE (str);
969 					break;
970 				}
971 				str = newstr;
972 			}
973 			p = str + off;
974 			memmove (p + vlen, p + klen, tlen + 1);
975 		}
976 		memcpy (p, val, vlen);
977 		i = off + vlen;
978 		q = str + i;
979 		if (!g) {
980 			break;
981 		}
982 	}
983 	return str;
984 }
985 
r_str_replace_icase(char * str,const char * key,const char * val,int g,int keep_case)986 R_API char *r_str_replace_icase(char *str, const char *key, const char *val, int g, int keep_case) {
987 	r_return_val_if_fail (str && key && val, NULL);
988 
989 	int off, i, klen, vlen, slen;
990 	char *newstr, *p = str;
991 	klen = strlen (key);
992 	vlen = strlen (val);
993 
994 	slen = strlen (str);
995 	for (i = 0; i < slen;) {
996 		p = (char *)r_str_casestr (str + i, key);
997 		if (!p) {
998 			break;
999 		}
1000 		off = (int)(size_t) (p - str);
1001 		if (vlen != klen) {
1002 			int tlen = slen - (off + klen);
1003 			slen += vlen - klen;
1004 			if (vlen > klen) {
1005 				newstr = realloc (str, slen + 1);
1006 				if (!newstr) {
1007 					goto alloc_fail;
1008 				}
1009 				str = newstr;
1010 			}
1011 			p = str + off;
1012 			memmove (p + vlen, p + klen, tlen + 1);
1013 		}
1014 
1015 		if (keep_case) {
1016 			char *tmp_val = strdup (val);
1017 			char *str_case = r_str_ndup (p, klen);
1018 			if (!tmp_val || !str_case) {
1019 				free (tmp_val);
1020 				free (str_case);
1021 				goto alloc_fail;
1022 			}
1023 			tmp_val = r_str_replace_icase (tmp_val, key, str_case, 0, 0);
1024 			free (str_case);
1025 			if (!tmp_val) {
1026 				goto alloc_fail;
1027 			}
1028 			memcpy (p, tmp_val, vlen);
1029 			free (tmp_val);
1030 		} else {
1031 			memcpy (p, val, vlen);
1032 		}
1033 
1034 		i = off + vlen;
1035 		if (!g) {
1036 			break;
1037 		}
1038 	}
1039 	return str;
1040 
1041 alloc_fail:
1042 	eprintf ("alloc fail\n");
1043 	free (str);
1044 	return NULL;
1045 }
1046 
1047 /* replace the key in str with val.
1048  *
1049  * str - input string
1050  * clean - input string cleaned of ANSI chars
1051  * thunk - array of integers that map each char of the clean string into the
1052  *         position in the str string
1053  * clen  - number of elements in thunk
1054  * key   - string to find in the clean string
1055  * val   - string that replaces key in the str string
1056  * g     - if true, replace all occurrences of key
1057  *
1058  * It returns a pointer to the modified string */
r_str_replace_thunked(char * str,char * clean,int * thunk,int clen,const char * key,const char * val,int g)1059 R_API char* r_str_replace_thunked(char *str, char *clean, int *thunk, int clen,
1060 				  const char *key, const char *val, int g) {
1061 	int i, klen, vlen, slen, delta = 0, bias;
1062 	char *newstr, *scnd, *p = clean, *str_p;
1063 
1064 	if (!str || !key || !val || !clean || !thunk) {
1065 		return NULL;
1066 	}
1067 	klen = strlen (key);
1068 	vlen = strlen (val);
1069 	if (klen == vlen && !strcmp (key, val)) {
1070 		return str;
1071 	}
1072 	slen = strlen (str) + 1;
1073 
1074 	for (i = 0; i < clen; ) {
1075 		p = (char *)r_mem_mem (
1076 			(const ut8*)clean + i, clen - i,
1077 			(const ut8*)key, klen);
1078 		if (!p) {
1079 			break;
1080 		}
1081 		i = (int)(size_t)(p - clean);
1082 		/* as the original string changes size during replacement
1083 		 * we need delta to keep track of it*/
1084 		str_p = str + thunk[i] + delta;
1085 
1086 		int newo = thunk[i + klen] - thunk[i];
1087 		r_str_ansi_filter (str_p, NULL, NULL, newo);
1088 		scnd = strdup (str_p + newo);
1089 		bias = vlen - newo;
1090 
1091 		slen += bias;
1092 		// HACK: this 32 avoids overwrites wtf
1093 		newstr = realloc (str, slen + klen);
1094 		if (!newstr) {
1095 			eprintf ("realloc fail\n");
1096 			R_FREE (str);
1097 			free (scnd);
1098 			break;
1099 		}
1100 		str = newstr;
1101 		str_p = str + thunk[i] + delta;
1102 		memcpy (str_p, val, vlen);
1103 		memcpy (str_p + vlen, scnd, strlen (scnd) + 1);
1104 		i += klen;
1105 		delta += bias;
1106 		free (scnd);
1107 		if (!g) {
1108 			break;
1109 		}
1110 	}
1111 	return str;
1112 }
1113 
r_str_replace_in(char * str,ut32 sz,const char * key,const char * val,int g)1114 R_API char *r_str_replace_in(char *str, ut32 sz, const char *key, const char *val, int g) {
1115 	if (!str || !key || !val) {
1116 		return NULL;
1117 	}
1118 	char *heaped = r_str_replace (strdup (str), key, val, g);
1119 	if (heaped) {
1120 		strncpy (str, heaped, sz);
1121 		free (heaped);
1122 	}
1123 	return str;
1124 }
1125 
r_str_unescape(char * buf)1126 R_API int r_str_unescape(char *buf) {
1127 	unsigned char ch = 0, ch2 = 0;
1128 	int err = 0;
1129 	int i;
1130 
1131 	for (i = 0; buf[i]; i++) {
1132 		if (buf[i] != '\\') {
1133 			continue;
1134 		}
1135 		int esc_seq_len = 2;
1136 		switch (buf[i + 1]) {
1137 		case 'e':
1138 			buf[i] = 0x1b;
1139 			break;
1140 		case '\\':
1141 			buf[i] = '\\';
1142 			break;
1143 		case 'r':
1144 			buf[i] = 0x0d;
1145 			break;
1146 		case 'n':
1147 			buf[i] = 0x0a;
1148 			break;
1149 		case 'a':
1150 			buf[i] = 0x07;
1151 			break;
1152 		case 'b':
1153 			buf[i] = 0x08;
1154 			break;
1155 		case 't':
1156 			buf[i] = 0x09;
1157 			break;
1158 		case 'v':
1159 			buf[i] = 0x0b;
1160 			break;
1161 		case 'f':
1162 			buf[i] = 0x0c;
1163 			break;
1164 		case 'x':
1165 			err = ch2 = ch = 0;
1166 			if (!buf[i + 2] || !buf[i + 3]) {
1167 				eprintf ("Unexpected end of string.\n");
1168 				return 0;
1169 			}
1170 			err |= r_hex_to_byte (&ch,  buf[i + 2]);
1171 			err |= r_hex_to_byte (&ch2, buf[i + 3]);
1172 			if (err) {
1173 				eprintf ("Error: Non-hexadecimal chars in input.\n");
1174 				return 0; // -1?
1175 			}
1176 			buf[i] = (ch << 4) + ch2;
1177 			esc_seq_len = 4;
1178 			break;
1179 		case '$':
1180 			buf[i] = '$';
1181 			break;
1182 		default:
1183 			if (IS_OCTAL (buf[i + 1])) {
1184 				int num_digits = 1;
1185 				buf[i] = buf[i + 1] - '0';
1186 				if (IS_OCTAL (buf[i + 2])) {
1187 					num_digits++;
1188 					buf[i] = (ut8)buf[i] * 8 + (buf[i + 2] - '0');
1189 					if (IS_OCTAL (buf[i + 3])) {
1190 						num_digits++;
1191 						buf[i] = (ut8)buf[i] * 8 + (buf[i + 3] - '0');
1192 					}
1193 				}
1194 				esc_seq_len = 1 + num_digits;
1195 			} else {
1196 				eprintf ("Error: Unknown escape sequence.\n");
1197 				return 0; // -1?
1198 			}
1199 		}
1200 		memmove (buf + i + 1, buf + i + esc_seq_len, strlen (buf + i + esc_seq_len) + 1);
1201 	}
1202 	return i;
1203 }
1204 
r_str_sanitize(char * c)1205 R_API void r_str_sanitize(char *c) {
1206 	char *d = c;
1207 	if (d)  {
1208 		for (; *d; c++, d++) {
1209 			switch (*d) {
1210 			case '`':
1211 			case '$':
1212 			case '{':
1213 			case '}':
1214 			case '~':
1215 			case '|':
1216 			case ';':
1217 			case '#':
1218 			case '@':
1219 			case '&':
1220 			case '<':
1221 			case '>':
1222 				*c = '_';
1223 				continue;
1224 			}
1225 		}
1226 	}
1227 }
1228 
r_str_sanitize_sdb_key(const char * s)1229 R_API char *r_str_sanitize_sdb_key(const char *s) {
1230 	if (!s || !*s) {
1231 		return NULL;
1232 	}
1233 	size_t len = strlen (s);
1234 	char *ret = malloc (len + 1);
1235 	if (!ret) {
1236 		return NULL;
1237 	}
1238 	char *cur = ret;
1239 	while (len > 0) {
1240 		char c = *s;
1241 		if (!(c >= 'a' && c <= 'z') && !(c >= 'A' && c <= 'Z') && !(c >= '0' && c <= '9')
1242 			&& c != '_' && c != ':') {
1243 			c = '_';
1244 		}
1245 		*cur = c;
1246 		s++;
1247 		cur++;
1248 		len--;
1249 	}
1250 	*cur = '\0';
1251 	return ret;
1252 }
1253 
r_str_byte_escape(const char * p,char ** dst,int dot_nl,bool default_dot,bool esc_bslash)1254 R_API void r_str_byte_escape(const char *p, char **dst, int dot_nl, bool default_dot, bool esc_bslash) {
1255 	char *q = *dst;
1256 	switch (*p) {
1257 	case '\n':
1258 		*q++ = '\\';
1259 		*q++ = dot_nl ? 'l' : 'n';
1260 		break;
1261 	case '\r':
1262 		*q++ = '\\';
1263 		*q++ = 'r';
1264 		break;
1265 	case '\\':
1266 		*q++ = '\\';
1267 		if (esc_bslash) {
1268 			*q++ = '\\';
1269 		}
1270 		break;
1271 	case '\t':
1272 		*q++ = '\\';
1273 		*q++ = 't';
1274 		break;
1275 	case '"' :
1276 		*q++ = '\\';
1277 		*q++ = '"';
1278 		break;
1279 	case '\f':
1280 		*q++ = '\\';
1281 		*q++ = 'f';
1282 		break;
1283 	case '\b':
1284 		*q++ = '\\';
1285 		*q++ = 'b';
1286 		break;
1287 	case '\v':
1288 		*q++ = '\\';
1289 		*q++ = 'v';
1290 		break;
1291 	case '\a':
1292 		*q++ = '\\';
1293 		*q++ = 'a';
1294 		break;
1295 	default:
1296 		/* Outside the ASCII printable range */
1297 		if (!IS_PRINTABLE (*p)) {
1298 			if (default_dot) {
1299 				*q++ = '.';
1300 			} else {
1301 				*q++ = '\\';
1302 				*q++ = 'x';
1303 				*q++ = "0123456789abcdef"[*p >> 4 & 0xf];
1304 				*q++ = "0123456789abcdef"[*p & 0xf];
1305 			}
1306 		} else {
1307 			*q++ = *p;
1308 		}
1309 	}
1310 	*dst = q;
1311 }
1312 
1313 /* Internal function. dot_nl specifies whether to convert \n into the
1314  * graphiz-compatible newline \l */
r_str_escape_(const char * buf,int dot_nl,bool parse_esc_seq,bool ign_esc_seq,bool show_asciidot,bool esc_bslash)1315 static char *r_str_escape_(const char *buf, int dot_nl, bool parse_esc_seq, bool ign_esc_seq, bool show_asciidot, bool esc_bslash) {
1316 	r_return_val_if_fail (buf, NULL);
1317 
1318 	/* Worst case scenario, we convert every byte to a single-char escape
1319 	 * (e.g. \n) if show_asciidot, or \xhh if !show_asciidot */
1320 	char *new_buf = malloc (1 + strlen (buf) * (show_asciidot ? 2 : 4));
1321 	if (!new_buf) {
1322 		return NULL;
1323 	}
1324 	const char *p = buf;
1325 	char *q = new_buf;
1326 	while (*p) {
1327 		switch (*p) {
1328 		case 0x1b: // ESC
1329 			if (parse_esc_seq) {
1330 				const char *start_seq = p;
1331 				p++;
1332 				/* Parse the ANSI code (only the graphic mode
1333 				 * set ones are supported) */
1334 				if (*p == '\0') {
1335 					goto out;
1336 				}
1337 				if (*p == '[') {
1338 					for (p++; *p != 'm'; p++) {
1339 						if (*p == '\0') {
1340 							goto out;
1341 						}
1342 					}
1343 					if (!ign_esc_seq) {
1344 						memcpy (q, start_seq, p - start_seq + 1);
1345 						q += (p - start_seq + 1);
1346 					}
1347 				}
1348 				break;
1349 			}
1350 			/* fallthrough */
1351 		default:
1352 			r_str_byte_escape (p, &q, dot_nl, show_asciidot, esc_bslash);
1353 		}
1354 		p++;
1355 	}
1356 out:
1357 	*q = '\0';
1358 	return new_buf;
1359 }
1360 
r_str_escape(const char * buf)1361 R_API char *r_str_escape(const char *buf) {
1362 	return r_str_escape_ (buf, false, true, true, false, true);
1363 }
1364 
r_str_sanitize_r2(const char * buf)1365 R_API char *r_str_sanitize_r2(const char *buf) {
1366 	r_return_val_if_fail (buf, NULL);
1367 	char *new_buf = malloc (1 + strlen (buf) * 2);
1368 	if (!new_buf) {
1369 		return NULL;
1370 	}
1371 	const char *p = buf;
1372 	char *q = new_buf;
1373 	while (*p) {
1374 		switch (*p) {
1375 		case ';':
1376 		case '$':
1377 		case '`':
1378 		case '\\':
1379 		case '"':
1380 			*q++ = ' ';
1381 			p++;
1382 			break;
1383 		default:
1384 			*q++ = *p++;
1385 			break;
1386 		}
1387 	}
1388 	*q = '\0';
1389 	return new_buf;
1390 }
1391 
r_str_escape_sql(const char * buf)1392 R_API char *r_str_escape_sql(const char *buf) {
1393 	r_return_val_if_fail (buf, NULL);
1394 	char *res = r_str_replace (strdup (buf), "'", "\\'", true);
1395 	return res;
1396 }
1397 
1398 // Return MUST BE surrounded by double-quotes
r_str_escape_sh(const char * buf)1399 R_API char *r_str_escape_sh(const char *buf) {
1400 	r_return_val_if_fail (buf, NULL);
1401 	char *new_buf = malloc (1 + strlen (buf) * 2);
1402 	if (!new_buf) {
1403 		return NULL;
1404 	}
1405 	const char *p = buf;
1406 	char *q = new_buf;
1407 	while (*p) {
1408 		switch (*p) {
1409 #if __UNIX__
1410 		case '$':
1411 		case '`':
1412 #endif
1413 		case '\\':
1414 		case '"':
1415 			*q++ = '\\';
1416 			/* FALLTHRU */
1417 		default:
1418 			*q++ = *p++;
1419 			break;
1420 		}
1421 	}
1422 	*q = '\0';
1423 	return new_buf;
1424 }
1425 
r_str_escape_dot(const char * buf)1426 R_API char *r_str_escape_dot(const char *buf) {
1427 	return r_str_escape_ (buf, true, true, true, false, true);
1428 }
1429 
r_str_escape_latin1(const char * buf,bool show_asciidot,bool esc_bslash,bool colors)1430 R_API char *r_str_escape_latin1(const char *buf, bool show_asciidot, bool esc_bslash, bool colors) {
1431 	return r_str_escape_ (buf, false, colors, !colors, show_asciidot, esc_bslash);
1432 }
1433 
r_str_escape_utf(const char * buf,int buf_size,RStrEnc enc,bool show_asciidot,bool esc_bslash,bool keep_printable)1434 static char *r_str_escape_utf(const char *buf, int buf_size, RStrEnc enc, bool show_asciidot, bool esc_bslash, bool keep_printable) {
1435 	char *new_buf, *q;
1436 	const char *p, *end;
1437 	RRune ch;
1438 	int i, len, ch_bytes;
1439 
1440 	if (!buf) {
1441 		return NULL;
1442 	}
1443 	switch (enc) {
1444 	case R_STRING_ENC_UTF16LE:
1445 	case R_STRING_ENC_UTF16BE:
1446 	case R_STRING_ENC_UTF32LE:
1447 	case R_STRING_ENC_UTF32BE:
1448 		if (buf_size < 0) {
1449 			return NULL;
1450 		}
1451 		if (enc == R_STRING_ENC_UTF16LE || enc == R_STRING_ENC_UTF16BE) {
1452 			end = (char *)r_mem_mem_aligned ((ut8 *)buf, buf_size, (ut8 *)"\0\0", 2, 2);
1453 		} else {
1454 			end = (char *)r_mem_mem_aligned ((ut8 *)buf, buf_size, (ut8 *)"\0\0\0\0", 4, 4);
1455 		}
1456 		if (!end) {
1457 			end = buf + buf_size - 1; /* TODO: handle overlong strings properly */
1458 		}
1459 		len = end - buf;
1460 		break;
1461 	default:
1462 		len = strlen (buf);
1463 		end = buf + len;
1464 	}
1465 	/* Worst case scenario, we convert every byte to \xhh */
1466 	new_buf = malloc (1 + (len * 4));
1467 	if (!new_buf) {
1468 		return NULL;
1469 	}
1470 	p = buf;
1471 	q = new_buf;
1472 	while (p < end) {
1473 		switch (enc) {
1474 		case R_STRING_ENC_UTF16LE:
1475 		case R_STRING_ENC_UTF16BE:
1476 		case R_STRING_ENC_UTF32LE:
1477 		case R_STRING_ENC_UTF32BE:
1478 			if (enc == R_STRING_ENC_UTF16LE || enc == R_STRING_ENC_UTF16BE) {
1479 				ch_bytes = r_utf16_decode ((ut8 *)p, end - p, &ch, enc == R_STRING_ENC_UTF16BE);
1480 			} else {
1481 				ch_bytes = r_utf32_decode ((ut8 *)p, end - p, &ch, enc == R_STRING_ENC_UTF32BE);
1482 			}
1483 			if (ch_bytes == 0) {
1484 				p++;
1485 				continue;
1486 			}
1487 			break;
1488 		default:
1489 			ch_bytes = r_utf8_decode ((ut8 *)p, end - p, &ch);
1490 			if (ch_bytes == 0) {
1491 				ch_bytes = 1;
1492 			}
1493 		}
1494 		if (show_asciidot && !IS_PRINTABLE(ch)) {
1495 			*q++ = '.';
1496 		} else if (ch_bytes > 1) {
1497 			if (keep_printable) {
1498 				q += r_utf8_encode ((ut8 *)q, ch);
1499 			} else {
1500 				*q++ = '\\';
1501 				*q++ = ch_bytes == 4 ? 'U' : 'u';
1502 				for (i = ch_bytes == 4 ? 6 : 2; i >= 0; i -= 2) {
1503 					*q++ = "0123456789abcdef"[ch >> 4 * (i + 1) & 0xf];
1504 					*q++ = "0123456789abcdef"[ch >> 4 * i & 0xf];
1505 				}
1506 			}
1507 		} else {
1508 			int offset = enc == R_STRING_ENC_UTF16BE ? 1 : enc == R_STRING_ENC_UTF32BE ? 3 : 0;
1509 			r_str_byte_escape (p + offset, &q, false, false, esc_bslash);
1510 		}
1511 		switch (enc) {
1512 		case R_STRING_ENC_UTF16LE:
1513 		case R_STRING_ENC_UTF16BE:
1514 			p += ch_bytes < 2 ? 2 : ch_bytes;
1515 			break;
1516 		case R_STRING_ENC_UTF32LE:
1517 		case R_STRING_ENC_UTF32BE:
1518 			p += 4;
1519 			break;
1520 		default:
1521 			p += ch_bytes;
1522 		}
1523 	}
1524 	*q = '\0';
1525 	return new_buf;
1526 }
1527 
r_str_escape_utf8(const char * buf,bool show_asciidot,bool esc_bslash)1528 R_API char *r_str_escape_utf8(const char *buf, bool show_asciidot, bool esc_bslash) {
1529 	return r_str_escape_utf (buf, -1, R_STRING_ENC_UTF8, show_asciidot, esc_bslash, false);
1530 }
1531 
r_str_escape_utf8_keep_printable(const char * buf,bool show_asciidot,bool esc_bslash)1532 R_API char *r_str_escape_utf8_keep_printable(const char *buf, bool show_asciidot, bool esc_bslash) {
1533 	return r_str_escape_utf (buf, -1, R_STRING_ENC_UTF8, show_asciidot, esc_bslash, true);
1534 }
1535 
r_str_escape_utf16le(const char * buf,int buf_size,bool show_asciidot,bool esc_bslash)1536 R_API char *r_str_escape_utf16le(const char *buf, int buf_size, bool show_asciidot, bool esc_bslash) {
1537 	return r_str_escape_utf (buf, buf_size, R_STRING_ENC_UTF16LE, show_asciidot, esc_bslash, false);
1538 }
1539 
r_str_escape_utf32le(const char * buf,int buf_size,bool show_asciidot,bool esc_bslash)1540 R_API char *r_str_escape_utf32le(const char *buf, int buf_size, bool show_asciidot, bool esc_bslash) {
1541 	return r_str_escape_utf (buf, buf_size, R_STRING_ENC_UTF32LE, show_asciidot, esc_bslash, false);
1542 }
1543 
r_str_escape_utf16be(const char * buf,int buf_size,bool show_asciidot,bool esc_bslash)1544 R_API char *r_str_escape_utf16be(const char *buf, int buf_size, bool show_asciidot, bool esc_bslash) {
1545 	return r_str_escape_utf (buf, buf_size, R_STRING_ENC_UTF16BE, show_asciidot, esc_bslash, false);
1546 }
1547 
r_str_escape_utf32be(const char * buf,int buf_size,bool show_asciidot,bool esc_bslash)1548 R_API char *r_str_escape_utf32be(const char *buf, int buf_size, bool show_asciidot, bool esc_bslash) {
1549 	return r_str_escape_utf (buf, buf_size, R_STRING_ENC_UTF32BE, show_asciidot, esc_bslash, false);
1550 }
1551 
r_str_encoded_json(const char * buf,int buf_size,int encoding)1552 R_API char *r_str_encoded_json(const char *buf, int buf_size, int encoding) {
1553 	r_return_val_if_fail (buf, NULL);
1554 	size_t buf_sz = buf_size < 0 ? strlen (buf) : buf_size;
1555 	char *encoded_str;
1556 
1557 	if (encoding == PJ_ENCODING_STR_BASE64) {
1558 		encoded_str = r_base64_encode_dyn (buf, buf_sz);
1559 	} else if (encoding == PJ_ENCODING_STR_HEX || encoding == PJ_ENCODING_STR_ARRAY) {
1560 		size_t loop = 0;
1561 		size_t i = 0;
1562 		size_t increment = encoding == PJ_ENCODING_STR_ARRAY ? 4 : 2;
1563 
1564 		if (!SZT_MUL_OVFCHK (((buf_sz * increment) + 1), SZT_MAX)) {
1565 			return NULL;
1566 		}
1567 		size_t new_sz = (buf_sz * increment) + 1;
1568 
1569 		encoded_str = malloc (new_sz);
1570 		if (!encoded_str) {
1571 			return NULL;
1572 		}
1573 
1574 		const char *format = encoding == PJ_ENCODING_STR_ARRAY ? "%03u," : "%02X";
1575 		while (buf[loop] != '\0' && i < (new_sz - 1)) {
1576 			snprintf (encoded_str + i, new_sz - i, format, (ut8) buf[loop]);
1577 			loop++;
1578 			i += increment;
1579 		}
1580 		if (encoding == PJ_ENCODING_STR_ARRAY && i) {
1581 			// get rid of the trailing comma
1582 			encoded_str[i - 1] = '\0';
1583 		} else {
1584 			encoded_str[i] = '\0';
1585 		}
1586 	} else if (encoding == PJ_ENCODING_STR_STRIP) {
1587 		encoded_str = r_str_escape_utf8_for_json_strip (buf, buf_sz);
1588 	} else {
1589 		encoded_str = r_str_escape_utf8_for_json (buf, buf_sz);
1590 	}
1591 	return encoded_str;
1592 }
1593 
r_str_escape_utf8_for_json_strip(const char * buf,int buf_size)1594 R_API char *r_str_escape_utf8_for_json_strip(const char *buf, int buf_size) {
1595 	char *new_buf, *q;
1596 	const char *p, *end;
1597 	RRune ch;
1598 	int i, len, ch_bytes;
1599 
1600 	if (!buf) {
1601 		return NULL;
1602 	}
1603 	len = buf_size < 0 ? strlen (buf) : buf_size;
1604 	end = buf + len;
1605 	/* Worst case scenario, we convert every byte to \u00hh */
1606 	new_buf = malloc (1 + (len * 6));
1607 	if (!new_buf) {
1608 		return NULL;
1609 	}
1610 	p = buf;
1611 	q = new_buf;
1612 	while (p < end) {
1613 		ch_bytes = r_utf8_decode ((ut8 *)p, end - p, &ch);
1614 		if (ch_bytes == 1) {
1615 			switch (*p) {
1616 			case '\n':
1617 				*q++ = '\\';
1618 				*q++ = 'n';
1619 				break;
1620 			case '\r':
1621 				*q++ = '\\';
1622 				*q++ = 'r';
1623 				break;
1624 			case '\\':
1625 				*q++ = '\\';
1626 				*q++ = '\\';
1627 				break;
1628 			case '\t':
1629 				*q++ = '\\';
1630 				*q++ = 't';
1631 				break;
1632 			case '"' :
1633 				*q++ = '\\';
1634 				*q++ = '"';
1635 				break;
1636 			case '\f':
1637 				*q++ = '\\';
1638 				*q++ = 'f';
1639 				break;
1640 			case '\b':
1641 				*q++ = '\\';
1642 				*q++ = 'b';
1643 				break;
1644 			default:
1645 				if (IS_PRINTABLE (*p)) {
1646 					*q++ = *p;
1647 				}
1648 			}
1649 		} else if (ch_bytes == 4) {
1650 			if (r_isprint (ch)) {
1651 				// Assumes buf is UTF8-encoded
1652 				for (i = 0; i < ch_bytes; i++) {
1653 					*q++ = *(p + i);
1654 				}
1655 			} else {
1656 				RRune high, low;
1657 				ch -= 0x10000;
1658 				high = 0xd800 + (ch >> 10 & 0x3ff);
1659 				low = 0xdc00 + (ch & 0x3ff);
1660 				*q++ = '\\';
1661 				*q++ = 'u';
1662 				for (i = 2; i >= 0; i -= 2) {
1663 					*q++ = "0123456789abcdef"[high >> 4 * (i + 1) & 0xf];
1664 					*q++ = "0123456789abcdef"[high >> 4 * i & 0xf];
1665 				}
1666 				*q++ = '\\';
1667 				*q++ = 'u';
1668 				for (i = 2; i >= 0; i -= 2) {
1669 					*q++ = "0123456789abcdef"[low >> 4 * (i + 1) & 0xf];
1670 					*q++ = "0123456789abcdef"[low >> 4 * i & 0xf];
1671 				}
1672 			}
1673 		} else if (ch_bytes > 1) {
1674 			if (r_isprint (ch)) {
1675 				// Assumes buf is UTF8-encoded
1676 				for (i = 0; i < ch_bytes; i++) {
1677 					*q++ = *(p + i);
1678 				}
1679 			} else {
1680 				*q++ = '\\';
1681 				*q++ = 'u';
1682 				for (i = 2; i >= 0; i -= 2) {
1683 					*q++ = "0123456789abcdef"[ch >> 4 * (i + 1) & 0xf];
1684 					*q++ = "0123456789abcdef"[ch >> 4 * i & 0xf];
1685 				}
1686 			}
1687 		} else {
1688 			ch_bytes = 1;
1689 		}
1690 		p += ch_bytes;
1691 	}
1692 	*q = '\0';
1693 	return new_buf;
1694 }
1695 
1696 
r_str_escape_utf8_for_json(const char * buf,int buf_size)1697 R_API char *r_str_escape_utf8_for_json(const char *buf, int buf_size) {
1698 	char *new_buf, *q;
1699 	const char *p, *end;
1700 	RRune ch;
1701 	int i, len, ch_bytes;
1702 
1703 	if (!buf) {
1704 		return NULL;
1705 	}
1706 	len = buf_size < 0 ? strlen (buf) : buf_size;
1707 	end = buf + len;
1708 	/* Worst case scenario, we convert every byte to \u00hh */
1709 	new_buf = malloc (1 + (len * 6));
1710 	if (!new_buf) {
1711 		return NULL;
1712 	}
1713 	p = buf;
1714 	q = new_buf;
1715 	while (p < end) {
1716 		ch_bytes = r_utf8_decode ((ut8 *)p, end - p, &ch);
1717 		if (ch_bytes == 1) {
1718 			switch (*p) {
1719 			case '\n':
1720 				*q++ = '\\';
1721 				*q++ = 'n';
1722 				break;
1723 			case '\r':
1724 				*q++ = '\\';
1725 				*q++ = 'r';
1726 				break;
1727 			case '\\':
1728 				*q++ = '\\';
1729 				*q++ = '\\';
1730 				break;
1731 			case '\t':
1732 				*q++ = '\\';
1733 				*q++ = 't';
1734 				break;
1735 			case '"' :
1736 				*q++ = '\\';
1737 				*q++ = '"';
1738 				break;
1739 			case '\f':
1740 				*q++ = '\\';
1741 				*q++ = 'f';
1742 				break;
1743 			case '\b':
1744 				*q++ = '\\';
1745 				*q++ = 'b';
1746 				break;
1747 			default:
1748 				if (!IS_PRINTABLE (*p)) {
1749 					*q++ = '\\';
1750 					*q++ = 'u';
1751 					*q++ = '0';
1752 					*q++ = '0';
1753 					*q++ = "0123456789abcdef"[*p >> 4 & 0xf];
1754 					*q++ = "0123456789abcdef"[*p & 0xf];
1755 				} else {
1756 					*q++ = *p;
1757 				}
1758 			}
1759 		} else if (ch_bytes == 4) {
1760 			if (r_isprint (ch)) {
1761 				// Assumes buf is UTF8-encoded
1762 				for (i = 0; i < ch_bytes; i++) {
1763 					*q++ = *(p + i);
1764 				}
1765 			} else {
1766 				RRune high, low;
1767 				ch -= 0x10000;
1768 				high = 0xd800 + (ch >> 10 & 0x3ff);
1769 				low = 0xdc00 + (ch & 0x3ff);
1770 				*q++ = '\\';
1771 				*q++ = 'u';
1772 				for (i = 2; i >= 0; i -= 2) {
1773 					*q++ = "0123456789abcdef"[high >> 4 * (i + 1) & 0xf];
1774 					*q++ = "0123456789abcdef"[high >> 4 * i & 0xf];
1775 				}
1776 				*q++ = '\\';
1777 				*q++ = 'u';
1778 				for (i = 2; i >= 0; i -= 2) {
1779 					*q++ = "0123456789abcdef"[low >> 4 * (i + 1) & 0xf];
1780 					*q++ = "0123456789abcdef"[low >> 4 * i & 0xf];
1781 				}
1782 			}
1783 		} else if (ch_bytes > 1) {
1784 			if (r_isprint (ch)) {
1785 				// Assumes buf is UTF8-encoded
1786 				for (i = 0; i < ch_bytes; i++) {
1787 					*q++ = *(p + i);
1788 				}
1789 			} else {
1790 				*q++ = '\\';
1791 				*q++ = 'u';
1792 				for (i = 2; i >= 0; i -= 2) {
1793 					*q++ = "0123456789abcdef"[ch >> 4 * (i + 1) & 0xf];
1794 					*q++ = "0123456789abcdef"[ch >> 4 * i & 0xf];
1795 				}
1796 			}
1797 		} else { // ch_bytes == 0
1798 			// Outside JSON spec, but apparently no better
1799 			// alternative if need to reconstruct the original string
1800 			*q++ = '\\';
1801 			*q++ = 'x';
1802 			*q++ = "0123456789abcdef"[*p >> 4 & 0xf];
1803 			*q++ = "0123456789abcdef"[*p & 0xf];
1804 			ch_bytes = 1;
1805 		}
1806 		p += ch_bytes;
1807 	}
1808 	*q = '\0';
1809 	return new_buf;
1810 }
1811 
1812 // http://daviddeley.com/autohotkey/parameters/parameters.htm#WINCRULES
1813 // https://docs.microsoft.com/en-us/cpp/cpp/main-function-command-line-args?redirectedfrom=MSDN&view=vs-2019#parsing-c-command-line-arguments
r_str_format_msvc_argv(size_t argc,const char ** argv)1814 R_API char *r_str_format_msvc_argv(size_t argc, const char **argv) {
1815 	RStrBuf sb;
1816 	r_strbuf_init (&sb);
1817 
1818 	size_t i;
1819 	for (i = 0; i < argc; i++) {
1820 		if (i > 0) {
1821 			r_strbuf_append (&sb, " ");
1822 		}
1823 		const char *arg = argv[i];
1824 		bool must_escape = strchr (arg, '\"') != NULL;
1825 		bool must_quote = strpbrk (arg, " \t") != NULL || !*arg;
1826 		if (!must_escape && must_quote && *arg && arg[strlen (arg) - 1] == '\\') {
1827 			// if the last char is a bs and we would quote it, we must also escape
1828 			must_escape = true;
1829 		}
1830 		if (must_quote) {
1831 			r_strbuf_append (&sb, "\"");
1832 		}
1833 		if (must_escape) {
1834 			size_t bs_count = 0; // bullshit counter
1835 			for (; *arg; arg++) {
1836 				switch (*arg) {
1837 				case '\"':
1838 					for (; bs_count; bs_count--) {
1839 						// backslashes must be escaped iff they precede a "
1840 						// so just duplicate the number of backslashes already printed
1841 						r_strbuf_append (&sb, "\\");
1842 					}
1843 					r_strbuf_append (&sb, "\\\"");
1844 					break;
1845 				case '\\':
1846 					bs_count++;
1847 					r_strbuf_append (&sb, "\\");
1848 					break;
1849 				default:
1850 					bs_count = 0;
1851 					r_strbuf_append_n (&sb, arg, 1);
1852 					break;
1853 				}
1854 			}
1855 			if (must_quote) {
1856 				// there will be a quote after this so we have to escape bs here as well
1857 				for (; bs_count; bs_count--) {
1858 					r_strbuf_append (&sb, "\\");
1859 				}
1860 			}
1861 		} else {
1862 			r_strbuf_append (&sb, arg);
1863 		}
1864 		if (must_quote) {
1865 			r_strbuf_append (&sb, "\"");
1866 		}
1867 	}
1868 
1869 	return r_strbuf_drain_nofree (&sb);
1870 }
1871 
__str_ansi_length(char const * str)1872 static size_t __str_ansi_length(char const *str) {
1873 	size_t i = 1;
1874 	if (str[0] == 0x1b) {
1875 		if (str[1] == '[') {
1876 			i++;
1877 			while (str[i] && str[i] != 'J' && str[i] != 'm' && str[i] != 'H' && str[i] != 'K') {
1878 				i++;
1879 			}
1880 		} else if (str[1] == '#') {
1881 			while (str[i] && str[i] != 'q') {
1882 				i++;
1883 			}
1884 		}
1885 		if (str[i]) {
1886 			i++;
1887 		}
1888 	}
1889 	return i;
1890 }
1891 
1892 /* ansi helpers */
r_str_ansi_nlen(const char * str,size_t slen)1893 R_API size_t r_str_ansi_nlen(const char *str, size_t slen) {
1894 	size_t i = 0, len = 0;
1895 	if (slen > 0) {
1896 		while (str[i] && i < slen) {
1897 			size_t chlen = __str_ansi_length (str + i);
1898 			if (chlen == 1) {
1899 				len ++;
1900 			}
1901 			i += chlen;
1902 		}
1903 		return len > 0 ? len: 1;
1904 	}
1905 	while (str[i]) {
1906 		size_t chlen = __str_ansi_length (str + i);
1907 		if (chlen == 1) {
1908 			len ++;
1909 		}
1910 		i += chlen;
1911 	}
1912 	return len > 0 ? len: 1;
1913 }
1914 
r_str_ansi_len(const char * str)1915 R_API size_t r_str_ansi_len(const char *str) {
1916 	return r_str_ansi_nlen (str, 0);
1917 }
1918 
r_str_nlen(const char * str,int n)1919 R_API size_t r_str_nlen(const char *str, int n) {
1920 	size_t len = 0;
1921 	if (str) {
1922 		while (*str && n > 0) {
1923 			len++;
1924 			str++;
1925 			n--;
1926 		}
1927 	}
1928 	return len;
1929 }
1930 
1931 //to handle wide string as well
1932 //XXX can be error prone
r_str_nlen_w(const char * str,int n)1933 R_API size_t r_str_nlen_w(const char *str, int n) {
1934 	size_t len = 0;
1935 	if (str) {
1936 		while (*str && n > 0) {
1937 			len++;
1938 			str++;
1939 			if (!*str) {
1940 				//handle wide strings
1941 			 	//xx00yy00bb00
1942 				if (n - 2 > 0) {
1943 					if (str[2]) {
1944 						break;
1945 					}
1946 				}
1947 				str++;
1948 			}
1949 			n--;
1950 		}
1951 	}
1952 	return len;
1953 }
1954 
r_str_is_ascii(const char * str)1955 R_API bool r_str_is_ascii(const char *str) {
1956 	const ut8 *ptr;
1957 	for (ptr = (const ut8 *)str; *ptr; ptr++) {
1958 		if (*ptr > 0x7f) {
1959 			return false;
1960 		}
1961 	}
1962 	return true;
1963 }
1964 
r_str_is_printable(const char * str)1965 R_API bool r_str_is_printable(const char *str) {
1966 	while (*str) {
1967 		int ulen = r_utf8_decode ((const ut8*)str, strlen (str), NULL);
1968 		if (ulen > 1) {
1969 			str += ulen;
1970 			continue;
1971 		}
1972 		if (!IS_PRINTABLE (*str)) {
1973 			return false;
1974 		}
1975 		str++;
1976 	}
1977 	return true;
1978 }
1979 
r_str_is_printable_limited(const char * str,int size)1980 R_API bool r_str_is_printable_limited(const char *str, int size) {
1981 	while (size > 0 && *str) {
1982 		int ulen = r_utf8_decode ((const ut8*)str, strlen (str), NULL);
1983 		if (ulen > 1) {
1984 			str += ulen;
1985 			continue;
1986 		}
1987 		if (!IS_PRINTABLE (*str)) {
1988 			return false;
1989 		}
1990 		str++;
1991 		size--;
1992 	}
1993 	return true;
1994 }
1995 
r_str_is_printable_incl_newlines(const char * str)1996 R_API bool r_str_is_printable_incl_newlines(const char *str) {
1997 	while (*str) {
1998 		int ulen = r_utf8_decode ((const ut8*)str, strlen (str), NULL);
1999 		if (ulen > 1) {
2000 			str += ulen;
2001 			continue;
2002 		}
2003 		if (!IS_PRINTABLE (*str)) {
2004 			if (*str != '\r' && *str != '\n' && *str != '\t') {
2005 				return false;
2006 			}
2007 		}
2008 		str++;
2009 	}
2010 	return true;
2011 }
2012 
2013 // Length in chars of a wide string (find better name?)
r_wstr_clen(const char * s)2014 R_API size_t r_wstr_clen(const char *s) {
2015 	size_t len = 0;
2016 	if (!*s++) {
2017 		return 0;
2018 	}
2019 	while (*s++ || *s++) {
2020 		len++;
2021 	}
2022 	return len + 1;
2023 }
2024 
r_str_ansi_chrn(const char * str,size_t n)2025 R_API const char *r_str_ansi_chrn(const char *str, size_t n) {
2026 	int len, i, li;
2027 	for (li = i = len = 0; str[i] && (n != len); i++) {
2028 		size_t chlen = __str_ansi_length (str + i);
2029 		if (chlen > 1) {
2030 			i += chlen - 1;
2031 		} else {
2032 			if ((str[i] & 0xc0) != 0x80) {
2033 				len++;
2034 			}
2035 			li = i;
2036 		}
2037 	}
2038 	return str + li;
2039 }
2040 
2041 /*
2042  * filter out ansi CSI shit in-place!.
2043  * str - input string,
2044  * out - if not NULL write a pointer to the original string there,
2045  * cposs - if not NULL write a pointer to thunk array there
2046  * (*cposs)[i] is the offset of the out[i] in str
2047  * len - length of str
2048  *
2049  * it returns the number of normal characters found in str
2050  */
r_str_ansi_filter(char * str,char ** out,int ** cposs,int len)2051 R_API int r_str_ansi_filter(char *str, char **out, int **cposs, int len) {
2052 	int i, j, *cps;
2053 
2054 	if (len == 0) {
2055 		return 0;
2056 	}
2057 	if (len < 0) {
2058 		len = strlen (str);
2059 	}
2060 	char *tmp = malloc (len + 1);
2061 	if (!tmp) {
2062 		return -1;
2063 	}
2064 	memcpy (tmp, str, len + 1);
2065 	cps = calloc (len + 1, sizeof (int));
2066 	if (!cps) {
2067 		free (tmp);
2068 		return -1;
2069 	}
2070 
2071 	for (i = j = 0; i < len; i++) {
2072 		if (tmp[i] == 0x1b) {
2073 			size_t chlen = __str_ansi_length (str + i);
2074 			if (chlen > 1) {
2075 				i += chlen;
2076 				i--;
2077 			}
2078 		} else {
2079 			str[j] = tmp[i];
2080 			cps[j] = i;
2081 			j++;
2082 		}
2083 	}
2084 	str[j] = tmp[i];
2085 
2086 	if (out) {
2087 		*out = tmp;
2088 	} else {
2089 		free (tmp);
2090 	}
2091 
2092 	if (cposs) {
2093 		*cposs = cps;
2094 	} else {
2095 		free (cps);
2096 	}
2097 
2098 	return j;
2099 }
2100 
r_str_ansi_crop(const char * str,ut32 x,ut32 y,ut32 x2,ut32 y2)2101 R_API char *r_str_ansi_crop(const char *str, ut32 x, ut32 y, ut32 x2, ut32 y2) {
2102 	char *r, *r_end, *ret;
2103 	const char *s, *s_start;
2104 	size_t r_len, str_len = 0, nr_of_lines = 0;
2105 	ut32 ch = 0, cw = 0;
2106 	if (x2 <= x || y2 <= y || !str) {
2107 		return strdup ("");
2108 	}
2109 	s = s_start = str;
2110 	while (*s) {
2111 		str_len++;
2112 		if (*s == '\n') {
2113 			nr_of_lines++;
2114 		}
2115 		s++;
2116 	}
2117 	r_len = str_len + nr_of_lines * strlen (Color_RESET) + 1;
2118 	r = ret = malloc (r_len);
2119 	if (!r) {
2120 		return NULL;
2121 	}
2122 	r_end = r + r_len;
2123 	while (*str) {
2124 		/* crop height */
2125 		if (ch >= y2) {
2126 			r--;
2127 			break;
2128 		}
2129 		if (*str == '\n') {
2130 			if (ch >= y && ch < y2) {
2131 				const char *reset = Color_RESET "\n";
2132 				if (strlen (reset) < (r_end - r)) {
2133 					const int reset_length = strlen (reset);
2134 					memcpy (r, reset, reset_length + 1);
2135 					r += reset_length;
2136 				}
2137 			}
2138 			str++;
2139 			ch++;
2140 			cw = 0;
2141 		} else {
2142 			if (ch >= y && ch < y2) {
2143 				if ((*str & 0xc0) == 0x80) {
2144 					if (cw > x) {
2145 						*r++ = *str++;
2146 					} else {
2147 						str++;
2148 					}
2149 					continue;
2150 				}
2151 				if (r_str_char_fullwidth (str, str_len - (str - s_start))) {
2152 					cw++;
2153 					if (cw == x) {
2154 						*r++ = ' ';
2155 						str++;
2156 						continue;
2157 					}
2158 				}
2159 				if (*str == 0x1b && *(str + 1) == '[') {
2160 					const char *ptr = str;
2161 					if ((r_end - r) > 2) {
2162 						/* copy 0x1b and [ */
2163 						*r++ = *str++;
2164 						*r++ = *str++;
2165 						for (ptr = str; *ptr && *ptr != 'J' && *ptr != 'm' && *ptr != 'H'; ptr++) {
2166 							*r++ = *ptr;
2167 						}
2168 						*r++ = *ptr++;
2169 					}
2170 					str = ptr;
2171 					continue;
2172 				} else if (cw >= x && cw < x2) {
2173 					*r++ = *str;
2174 				}
2175 			}
2176 			/* skip until newline */
2177 			if (cw >= x2) {
2178 				while (*str && *str != '\n') {
2179 					str++;
2180 				}
2181 			} else {
2182 				str++;
2183 			}
2184 			cw++;
2185 		}
2186 	}
2187 	*r = 0;
2188 	return ret;
2189 }
2190 
r_str_utf8_codepoint(const char * s,size_t left)2191 R_API size_t r_str_utf8_codepoint(const char* s, size_t left) {
2192 	if ((*s & 0x80) != 0x80) {
2193 		return 0;
2194 	} else if ((*s & 0xe0) == 0xc0 && left >= 1) {
2195 		return ((*s & 0x1f) << 6) + (*(s + 1) & 0x3f);
2196 	} else if ((*s & 0xf0) == 0xe0 && left >= 2) {
2197 		return ((*s & 0xf) << 12) + ((*(s + 1) & 0x3f) << 6) + (*(s + 2) & 0x3f);
2198 	} else if ((*s & 0xf8) == 0xf0 && left >= 3) {
2199 		return ((*s & 0x7) << 18) + ((*(s + 1) & 0x3f) << 12) + ((*(s + 2) & 0x3f) << 6) + (*(s + 3) & 0x3f);
2200 	}
2201 	return 0;
2202 }
2203 
r_str_char_fullwidth(const char * s,size_t left)2204 R_API bool r_str_char_fullwidth (const char* s, size_t left) {
2205 	size_t codepoint = r_str_utf8_codepoint (s, left);
2206 	return (codepoint >= 0x1100 &&
2207 		 (codepoint <= 0x115f ||                  /* Hangul Jamo init. consonants */
2208 			  codepoint == 0x2329 || codepoint == 0x232a ||
2209 		 (R_BETWEEN (0x2e80, codepoint, 0xa4cf)
2210 			&& codepoint != 0x303f) ||        /* CJK ... Yi */
2211 		 R_BETWEEN (0xac00, codepoint, 0xd7a3) || /* Hangul Syllables */
2212 		 R_BETWEEN (0xf900, codepoint, 0xfaff) || /* CJK Compatibility Ideographs */
2213 		 R_BETWEEN (0xfe10, codepoint, 0xfe19) || /* Vertical forms */
2214 		 R_BETWEEN (0xfe30, codepoint, 0xfe6f) || /* CJK Compatibility Forms */
2215 		 R_BETWEEN (0xff00, codepoint, 0xff60) || /* Fullwidth Forms */
2216 		 R_BETWEEN (0xffe0, codepoint, 0xffe6) ||
2217 		 R_BETWEEN (0x20000, codepoint, 0x2fffd) ||
2218 		 R_BETWEEN (0x30000, codepoint, 0x3fffd)));
2219 
2220 }
2221 
2222 /**
2223  * Returns size in bytes of the utf8 char
2224  * Returns 1 in case of ASCII
2225  * str - Pointer to buffer
2226  */
r_str_utf8_charsize(const char * str)2227 R_API size_t r_str_utf8_charsize(const char *str) {
2228 	r_return_val_if_fail (str, 0);
2229 	size_t size = 0;
2230 	size_t length = strlen (str);
2231 	while (size < length && size < 5) {
2232 		size++;
2233 		if ((str[size] & 0xc0) != 0x80) {
2234 			break;
2235 		}
2236 	}
2237 	return size < 5 ? size : 0;
2238 }
2239 
2240 /**
2241  * Returns size in bytes of the utf8 char previous to str
2242  * Returns 1 in case of ASCII
2243  * str - Pointer to leading utf8 char
2244  * prev_len - Length in bytes of the buffer until str
2245  */
r_str_utf8_charsize_prev(const char * str,int prev_len)2246 R_API size_t r_str_utf8_charsize_prev(const char *str, int prev_len) {
2247 	r_return_val_if_fail (str, 0);
2248 	int pos = 0;
2249 	size_t size = 0, minsize = R_MIN (5, prev_len);
2250 	while (size < minsize) {
2251 		size++;
2252 		if ((str[--pos] & 0xc0) != 0x80) {
2253 			break;
2254 		}
2255 	}
2256 	return size < 5 ? size : 0;
2257 }
2258 
2259 /**
2260  * Returns size in bytes of the last utf8 char of the string
2261  * Returns 1 in case of ASCII
2262  * str - Pointer to buffer
2263  */
r_str_utf8_charsize_last(const char * str)2264 R_API size_t r_str_utf8_charsize_last(const char *str) {
2265 	r_return_val_if_fail (str, 0);
2266 	size_t len = strlen (str);
2267 	return r_str_utf8_charsize_prev (str + len, len);
2268 }
2269 
r_str_filter_zeroline(char * str,int len)2270 R_API void r_str_filter_zeroline(char *str, int len) {
2271 	int i;
2272 	for (i = 0; i < len && str[i]; i++) {
2273 		if (str[i] == '\n' || str[i] == '\r') {
2274 			break;
2275 		}
2276 		if (!IS_PRINTABLE (str[i])) {
2277 			break;
2278 		}
2279 	}
2280 	str[i] = 0;
2281 }
2282 
r_str_filter(char * str,int len)2283 R_API void r_str_filter(char *str, int len) {
2284 	size_t i;
2285 	if (len < 1) {
2286 		len = strlen (str);
2287 	}
2288 	for (i = 0; i < len; i++) {
2289 		if (!IS_PRINTABLE (str[i])) {
2290 			str[i] = '.';
2291 		}
2292 	}
2293 }
2294 
r_str_glob(const char * str,const char * glob)2295 R_API bool r_str_glob(const char* str, const char *glob) {
2296         const char* cp = NULL, *mp = NULL;
2297         if (!glob || !strcmp (glob, "*")) {
2298                 return true;
2299         }
2300         if (!strchr (glob, '*')) {
2301                 if (*glob == '^') {
2302                         glob++;
2303                         while (*str) {
2304                                 if (*glob != *str) {
2305                                         return false;
2306                                 }
2307                                 if (!*++glob) {
2308                                         return true;
2309                                 }
2310                                 str++;
2311                         }
2312                 } else {
2313                         return strstr (str, glob) != NULL;
2314                 }
2315         }
2316         if (*glob == '^') {
2317                 glob++;
2318         }
2319         while (*str && (*glob != '*')) {
2320                 if (*glob != *str) {
2321                         return false;
2322                 }
2323                 glob++;
2324                 str++;
2325         }
2326         while (*str) {
2327                 if (*glob == '*') {
2328                         if (!*++glob) {
2329                                 return true;
2330                         }
2331                         mp = glob;
2332                         cp = str + 1;
2333                 } else if (*glob == *str) {
2334                         glob++;
2335                         str++;
2336                 } else {
2337                         glob = mp;
2338                         str = cp++;
2339                 }
2340         }
2341         while (*glob == '*') {
2342                 ++glob;
2343         }
2344         return (*glob == '\x00');
2345 }
2346 
2347 // Escape the string arg so that it is parsed as a single argument by r_str_argv
r_str_arg_escape(const char * arg)2348 R_API char *r_str_arg_escape(const char *arg) {
2349 	char *str;
2350 	int dest_i = 0, src_i = 0;
2351 	if (!arg) {
2352 		return NULL;
2353 	}
2354 	str = malloc ((2 * strlen (arg) + 1) * sizeof (char)); // Worse case when every character need to be escaped
2355 	if (!str) {
2356 		return NULL;
2357 	}
2358 	for (src_i = 0; arg[src_i] != '\0'; src_i++) {
2359 		char c = arg[src_i];
2360 		switch (c) {
2361 		case '\'':
2362 		case '"':
2363 		case '\\':
2364 		case ' ':
2365 			str[dest_i++] = '\\';
2366 			str[dest_i++] = c;
2367 			break;
2368 		default:
2369 			str[dest_i++] = c;
2370 			break;
2371 		}
2372 	}
2373 	str[dest_i] = '\0';
2374 	return realloc (str, (strlen(str)+1) * sizeof (char));
2375 }
2376 
2377 // Unescape the string arg to its original format
r_str_arg_unescape(char * arg)2378 R_API int r_str_arg_unescape(char *arg) {
2379 	int dest_i = 0, src_i = 0;
2380 	if (!arg) {
2381 		return 0;
2382 	}
2383 	for (src_i = 0; arg[src_i] != '\0'; src_i++) {
2384 		char c = arg[src_i];
2385 		if (c == '\\') {
2386 			if (arg[++src_i] == '\0') {
2387 				break;
2388 			}
2389 			arg[dest_i++] = arg[src_i];
2390 		} else {
2391 			arg[dest_i++] = c;
2392 		}
2393 	}
2394 	arg[dest_i] = '\0';
2395 	return dest_i;
2396 }
2397 
r_str_path_escape(const char * path)2398 R_API char *r_str_path_escape(const char *path) {
2399 	char *str;
2400 	int dest_i = 0, src_i = 0;
2401 
2402 	if (!path) {
2403 		return NULL;
2404 	}
2405 	// Worst case when every character need to be escaped
2406 	str = malloc ((2 * strlen (path) + 1) * sizeof (char));
2407 	if (!str) {
2408 		return NULL;
2409 	}
2410 
2411 	for (src_i = 0; path[src_i] != '\0'; src_i++) {
2412 		char c = path[src_i];
2413 		switch (c) {
2414 		case ' ':
2415 			str[dest_i++] = '\\';
2416 			str[dest_i++] = c;
2417 			break;
2418 		default:
2419 			str[dest_i++] = c;
2420 			break;
2421 		}
2422 	}
2423 
2424 	str[dest_i] = '\0';
2425 	return realloc (str, (strlen (str) + 1) * sizeof (char));
2426 }
2427 
r_str_path_unescape(char * path)2428 R_API int r_str_path_unescape(char *path) {
2429 	int i;
2430 
2431 	for (i = 0; path[i]; i++) {
2432 		if (path[i] != '\\') {
2433 			continue;
2434 		}
2435 		if (path[i + 1] == ' ') {
2436 			path[i] = ' ';
2437 			memmove (path + i + 1, path + i + 2, strlen (path + i + 2) + 1);
2438 		}
2439 	}
2440 
2441 	return i;
2442 }
2443 
r_str_argv(const char * cmdline,int * _argc)2444 R_API char **r_str_argv(const char *cmdline, int *_argc) {
2445 	int argc = 0;
2446 	int argv_len = 128; // Begin with that, argv will reallocated if necessary
2447 	char *args; // Working buffer for writing unescaped args
2448 	int cmdline_current = 0; // Current character index in _cmdline
2449 	int args_current = 0; // Current character index in  args
2450 	int arg_begin = 0; // Index of the first character of the current argument in args
2451 
2452 	if (!cmdline) {
2453 		return NULL;
2454 	}
2455 
2456 	char **argv = malloc (argv_len * sizeof (char *));
2457 	if (!argv) {
2458 		return NULL;
2459 	}
2460 	args = malloc (128 + strlen (cmdline) * sizeof (char)); // Unescaped args will be shorter, so strlen (cmdline) will be enough
2461 	if (!args) {
2462 		free (argv);
2463 		return NULL;
2464 	}
2465 	do {
2466 		// States for parsing args
2467 		int escaped = 0;
2468 		int singlequoted = 0;
2469 		int doublequoted = 0;
2470 
2471 		// Seek the beginning of next argument (skip whitespaces)
2472 		while (cmdline[cmdline_current] != '\0' && IS_WHITECHAR (cmdline[cmdline_current])) {
2473 			cmdline_current++;
2474 		}
2475 
2476 		if (cmdline[cmdline_current] == '\0') {
2477 			break; // No more arguments
2478 		}
2479 		// Read the argument
2480 		while (1) {
2481 			char c = cmdline[cmdline_current];
2482 			int end_of_current_arg = 0;
2483 			if (escaped) {
2484 				switch (c) {
2485 				case '\'':
2486 				case '"':
2487 				case ' ':
2488 				case '\\':
2489 					args[args_current++] = '\\';
2490 					args[args_current++] = c;
2491 					break;
2492 				case '\0':
2493 					args[args_current++] = '\\';
2494 					end_of_current_arg = 1;
2495 					break;
2496 				default:
2497 					args[args_current++] = '\\';
2498 					args[args_current++] = c;
2499 				}
2500 				escaped = 0;
2501 			} else {
2502 				switch (c) {
2503 				case '\'':
2504 					if (doublequoted) {
2505 						args[args_current++] = c;
2506 					} else {
2507 						singlequoted = !singlequoted;
2508 					}
2509 					break;
2510 				case '"':
2511 					if (singlequoted) {
2512 						args[args_current++] = c;
2513 					} else {
2514 						doublequoted = !doublequoted;
2515 					}
2516 					break;
2517 				case '\\':
2518 					escaped = 1;
2519 					break;
2520 				case ' ':
2521 					if (singlequoted || doublequoted) {
2522 						args[args_current++] = c;
2523 					} else {
2524 						end_of_current_arg = 1;
2525 					}
2526 					break;
2527 				case '\0':
2528 					end_of_current_arg = 1;
2529 					break;
2530 				default:
2531 					args[args_current++] = c;
2532 				}
2533 			}
2534 			if (end_of_current_arg) {
2535 				break;
2536 			}
2537 			cmdline_current++;
2538 		}
2539 		args[args_current++] = '\0';
2540 		argv[argc++] = strdup (&args[arg_begin]);
2541 		if (argc >= argv_len) {
2542 			argv_len *= 2;
2543 			char **tmp = realloc (argv, argv_len * sizeof (char *));
2544 			if (!tmp) {
2545 				free (args);
2546 				free (argv);
2547 				return NULL;
2548 			}
2549 			argv = tmp;
2550 		}
2551 		arg_begin = args_current;
2552 	} while (cmdline[cmdline_current++] != '\0');
2553 	argv[argc] = NULL;
2554 	char **tmp = realloc (argv, (argc + 1) * sizeof (char *));
2555 	if (tmp) {
2556 		argv = tmp;
2557 	} else {
2558 		free (argv);
2559 		argv = NULL;
2560 	}
2561 	if (_argc) {
2562 		*_argc = argc;
2563 	}
2564 	free (args);
2565 	return argv;
2566 }
2567 
r_str_argv_free(char ** argv)2568 R_API void r_str_argv_free(char **argv) {
2569 	int argc = 0;
2570 	if (!argv) {
2571 		return;
2572 	}
2573 	while (argv[argc]) {
2574 		free (argv[argc++]);
2575 	}
2576 	free (argv);
2577 }
2578 
r_str_firstbut(const char * s,char ch,const char * but)2579 R_API const char *r_str_firstbut(const char *s, char ch, const char *but) {
2580 	int idx, _b = 0;
2581 	ut8 *b = (ut8*)&_b;
2582 	const char *isbut, *p;
2583 	const int bsz = sizeof (_b) * 8;
2584 	if (!but) {
2585 		return strchr (s, ch);
2586 	}
2587 	if (strlen (but) >= bsz) {
2588 		eprintf ("r_str_firstbut: but string too long\n");
2589 		return NULL;
2590 	}
2591 	for (p = s; *p; p++) {
2592 		isbut = strchr (but, *p);
2593 		if (isbut) {
2594 			idx = (int)(size_t)(isbut - but);
2595 			_b = R_BIT_TOGGLE (b, idx);
2596 			continue;
2597 		}
2598 		if (*p == ch && !_b) {
2599 			return p;
2600 		}
2601 	}
2602 	return NULL;
2603 }
2604 
r_str_lastbut(const char * s,char ch,const char * but)2605 R_API const char *r_str_lastbut(const char *s, char ch, const char *but) {
2606 	int idx, _b = 0;
2607 	ut8 *b = (ut8*)&_b;
2608 	const char *isbut, *p, *lp = NULL;
2609 	const int bsz = sizeof (_b) * 8;
2610 	if (!but) {
2611 		return r_str_lchr (s, ch);
2612 	}
2613 	if (strlen (but) >= bsz) {
2614 		eprintf ("r_str_lastbut: but string too long\n");
2615 		return NULL;
2616 	}
2617 	for (p = s; *p; p++) {
2618 		isbut = strchr (but, *p);
2619 		if (isbut) {
2620 			idx = (int)(size_t)(isbut - but);
2621 			_b = R_BIT_TOGGLE (b, idx);
2622 			continue;
2623 		}
2624 		if (*p == ch && !_b) {
2625 			lp = p;
2626 		}
2627 	}
2628 	return lp;
2629 }
2630 
2631 // Must be merged inside strlen
r_str_len_utf8char(const char * s,int left)2632 R_API size_t r_str_len_utf8char(const char *s, int left) {
2633 	size_t i = 1;
2634 	while (s[i] && (!left || i<left)) {
2635 		if ((s[i] & 0xc0) != 0x80) {
2636 			i++;
2637 		} else {
2638 			break;
2639 		}
2640 	}
2641 	return i;
2642 }
2643 
r_str_len_utf8(const char * s)2644 R_API size_t r_str_len_utf8(const char *s) {
2645 	size_t i = 0, j = 0, fullwidths = 0;
2646 	while (s[i]) {
2647 		if ((s[i] & 0xc0) != 0x80) {
2648 			j++;
2649 			if (r_str_char_fullwidth (s + i, 4)) {
2650 				fullwidths++;
2651 			}
2652 		}
2653 		i++;
2654 	}
2655 	return j + fullwidths;
2656 }
2657 
r_str_len_utf8_ansi(const char * str)2658 R_API size_t r_str_len_utf8_ansi(const char *str) {
2659 	int i = 0, len = 0, fullwidths = 0;
2660 	while (str[i]) {
2661 		char ch = str[i];
2662 		size_t chlen = __str_ansi_length (str + i);
2663 		if (chlen > 1) {
2664 			i += chlen - 1;
2665 		} else if ((ch & 0xc0) != 0x80) { // utf8
2666 			len++;
2667 			if (r_str_char_fullwidth (str + i, 4)) {
2668 				fullwidths++;
2669 			}
2670 		}
2671 		i++;
2672 	}
2673 	return len + fullwidths;
2674 }
2675 
2676 // XXX must find across the ansi tags, as well as support utf8
r_strstr_ansi(const char * a,const char * b)2677 R_API const char *r_strstr_ansi(const char *a, const char *b) {
2678 	const char *ch, *p = a;
2679 	do {
2680 		ch = strchr (p, '\x1b');
2681 		if (ch) {
2682 			const char *v = r_str_nstr (p, b, ch - p);
2683 			if (v) {
2684 				return v;
2685 			}
2686 			p = ch + __str_ansi_length (ch);
2687 		}
2688 	} while (ch);
2689 	return strstr (p, b);
2690 }
2691 
r_str_casestr(const char * a,const char * b)2692 R_API const char *r_str_casestr(const char *a, const char *b) {
2693 	// That's a GNUism that works in many places.. but we don't want it
2694 	// return strcasestr (a, b);
2695 	size_t hay_len = strlen (a);
2696 	size_t needle_len = strlen (b);
2697 	if (!hay_len || !needle_len) {
2698 		return NULL;
2699 	}
2700 	while (hay_len >= needle_len) {
2701 		if (!r_str_ncasecmp (a, b, needle_len)) {
2702 			return (const char *) a;
2703 		}
2704 		a++;
2705 		hay_len--;
2706 	}
2707 	return NULL;
2708 }
2709 
r_str_write(int fd,const char * b)2710 R_API int r_str_write(int fd, const char *b) {
2711 	return write (fd, b, strlen (b));
2712 }
2713 
r_str_range_foreach(const char * r,RStrRangeCallback cb,void * u)2714 R_API void r_str_range_foreach(const char *r, RStrRangeCallback cb, void *u) {
2715 	const char *p = r;
2716 	for (; *r; r++) {
2717 		if (*r == ',') {
2718 			cb (u, atoi (p));
2719 			p = r + 1;
2720 		}
2721 		if (*r == '-') {
2722 			if (p != r) {
2723 				int from = atoi (p);
2724 				int to = atoi (r + 1);
2725 				for (; from <= to; from++) {
2726 					cb (u, from);
2727 				}
2728 			} else {
2729 				fprintf (stderr, "Invalid range\n");
2730 			}
2731 			for (r++; *r && *r != ',' && *r != '-'; r++) {
2732 				;
2733 			}
2734 			p = r;
2735 		}
2736 	}
2737 	if (*p) {
2738 		cb (u, atoi (p));
2739 	}
2740 }
2741 
r_str_range_in(const char * r,ut64 addr)2742 R_API bool r_str_range_in(const char *r, ut64 addr) {
2743 	const char *p = r;
2744 	ut64 min = UT64_MAX;
2745 	ut64 max = 0;
2746 	if (!r) {
2747 		return false;
2748 	}
2749 	for (; *r; r++) {
2750 		if (*r == ',') {
2751 			if (max == 0) {
2752 				if (addr == r_num_get (NULL, p)) {
2753 					return true;
2754 				}
2755 			} else {
2756 				if (addr >= min && addr <= r_num_get (NULL, p)) {
2757 					return true;
2758 				}
2759 			}
2760 			p = r + 1;
2761 		}
2762 		if (*r == '-') {
2763 			if (p != r) {
2764 				ut64 from = r_num_get (NULL, p);
2765 				ut64 to = r_num_get (NULL, r + 1);
2766 				if (addr >= from && addr <= to) {
2767 					return true;
2768 				}
2769 			} else {
2770 				fprintf (stderr, "Invalid range\n");
2771 			}
2772 			for (r++; *r && *r != ',' && *r != '-'; r++) {
2773 				;
2774 			}
2775 			p = r;
2776 		}
2777 	}
2778 	if (*p) {
2779 		if (addr == r_num_get (NULL, p)) {
2780 			return true;
2781 		}
2782 	}
2783 	return false;
2784 }
2785 
2786 // convert from html escaped sequence "foo%20bar" to "foo bar"
2787 // TODO: find better name.. unencode? decode
r_str_uri_decode(char * s)2788 R_API void r_str_uri_decode(char *s) {
2789 	int n;
2790 	char *d;
2791 	for (d = s; *s; s++, d++) {
2792 		if (*s == '%') {
2793 			sscanf (s + 1, "%02x", &n);
2794 			*d = n;
2795 			s += 2;
2796 		} else {
2797 			*d = *s;
2798 		}
2799 	}
2800 	*d = 0;
2801 }
2802 
r_str_uri_encode(const char * s)2803 R_API char *r_str_uri_encode(const char *s) {
2804 	char ch[4], *d, *od;
2805 	if (!s) {
2806 		return NULL;
2807 	}
2808 	od = d = malloc (1 + (strlen (s) * 4));
2809 	if (!d) {
2810 		return NULL;
2811 	}
2812 	for (; *s; s++) {
2813 		if((*s>='0' && *s<='9')
2814 		|| (*s>='a' && *s<='z')
2815 		|| (*s>='A' && *s<='Z')) {
2816 			*d++ = *s;
2817 		} else {
2818 			*d++ = '%';
2819 			snprintf (ch, sizeof (ch), "%02x", 0xff & ((ut8)*s));
2820 			*d++ = ch[0];
2821 			*d++ = ch[1];
2822 		}
2823 	}
2824 	*d = 0;
2825 	char *trimDown = realloc (od, strlen (od) + 1); // FIT
2826 	return trimDown? trimDown: od;
2827 }
2828 
r_str_utf16_to_utf8(ut8 * dst,int len_dst,const ut8 * src,int len_src,int little_endian)2829 R_API int r_str_utf16_to_utf8(ut8 *dst, int len_dst, const ut8 *src, int len_src, int little_endian) {
2830 	ut8 *outstart = dst;
2831 	ut8 *outend = dst + len_dst;
2832 	ut16 *in = (ut16*)src;
2833 	ut16 *inend;
2834 	ut32 c, d, inlen;
2835 	ut8 *tmp;
2836 	int bits;
2837 
2838 	if ((len_src % 2) == 1) {
2839 		len_src--;
2840 	}
2841 	inlen = len_src / 2;
2842 	inend = in + inlen;
2843 	while ((in < inend) && (dst - outstart + 5 < len_dst)) {
2844 		if (little_endian) {
2845 			c = *in++;
2846 		} else {
2847 			tmp = (ut8*) in;
2848 			c = *tmp++;
2849 			if (!c && !*tmp) {
2850 				break;
2851 			}
2852 			c = c | (((ut32)*tmp) << 8);
2853 			in++;
2854 		}
2855 		if ((c & 0xFC00) == 0xD800) {    /* surrogates */
2856 			if (in >= inend) {           /* (in > inend) shouldn't happens */
2857 				break;
2858 			}
2859 			if (little_endian) {
2860 				d = *in++;
2861 			} else {
2862 				tmp = (ut8*) in;
2863 				d = *tmp++;
2864 				d = d | (((ut32)*tmp) << 8);
2865 				in++;
2866 			}
2867 			if ((d & 0xFC00) == 0xDC00) {
2868 				c &= 0x03FF;
2869 				c <<= 10;
2870 				c |= d & 0x03FF;
2871 				c += 0x10000;
2872 			} else {
2873 				return -2;
2874 			}
2875 		}
2876 
2877 		/* assertion: c is a single UTF-4 value */
2878 		if (dst >= outend) {
2879 			break;
2880 		}
2881 		if (c < 0x80) {
2882 			*dst++ =  c; bits= -6;
2883 		} else if (c < 0x800) {
2884 			*dst++ = ((c >> 6) & 0x1F) | 0xC0;
2885 			bits =  0;
2886 		} else if (c < 0x10000) {
2887 			*dst++ = ((c >> 12) & 0x0F) | 0xE0;
2888 			bits =  6;
2889 		} else {
2890 			*dst++ = ((c >> 18) & 0x07) | 0xF0;
2891 			bits = 12;
2892 		}
2893 
2894 		for (; bits >= 0; bits -= 6) {
2895 			if (dst >= outend) {
2896 				break;
2897 			}
2898 			*dst++ = ((c >> bits) & 0x3F) | 0x80;
2899 		}
2900 	}
2901 	len_dst = dst - outstart;
2902 	return len_dst;
2903 }
2904 
r_str_utf16_decode(const ut8 * s,int len)2905 R_API char *r_str_utf16_decode(const ut8 *s, int len) {
2906 	int i = 0;
2907 	int j = 0;
2908 	char *result = NULL;
2909 	int count_unicode = 0;
2910 	int count_ascii = 0;
2911 	int lenresult = 0;
2912 	if (!s) {
2913 		return NULL;
2914 	}
2915 	for (i = 0; i < len && (s[i] || s[i+1]); i += 2) {
2916 		if (!s[i+1] && 0x20 <= s[i] && s[i] <= 0x7E) {
2917 			++count_ascii;
2918 		} else {
2919 			++count_unicode;
2920 		}
2921 	}
2922 	lenresult = 1 + count_ascii + count_unicode * 6; // len("\\uXXXX") = 6
2923 	if (!(result = calloc (1 + count_ascii + count_unicode * 6, 1))) {
2924 		return NULL;
2925 	}
2926 	for (i = 0; i < len && j < lenresult && (s[i] || s[i+1]); i += 2) {
2927 		if (!s[i+1] && IS_PRINTABLE(s[i])) {
2928 			result[j++] = s[i];
2929 		} else {
2930 			j += snprintf (&result[j], lenresult - j, "\\u%.2"HHXFMT"%.2"HHXFMT"", s[i], s[i+1]);
2931 		}
2932 	}
2933 	return result;
2934 }
2935 
2936 // TODO: kill this completely, it makes no sense:
r_str_utf16_encode(const char * s,int len)2937 R_API char *r_str_utf16_encode(const char *s, int len) {
2938 	int i;
2939 	char ch[4], *d, *od, *tmp;
2940 	if (!s) {
2941 		return NULL;
2942 	}
2943 	if (len < 0) {
2944 		len = strlen (s);
2945 	}
2946 	if ((len * 7) + 1 < len) {
2947 		return NULL;
2948 	}
2949 	od = d = malloc (1 + (len * 7));
2950 	if (!d) {
2951 		return NULL;
2952 	}
2953 	for (i = 0; i < len; s++, i++) {
2954 		if (*s == '\\') {
2955 			*d++ = '\\';
2956 			*d++ = '\\';
2957 		} else if (*s == '"') {
2958 			*d++ = '\\';
2959 			*d++ = '"';
2960 		} else if ((*s >= 0x20) && (*s <= 126)) {
2961 			*d++ = *s;
2962 		} else {
2963 			*d++ = '\\';
2964 			//	*d++ = '\\';
2965 			*d++ = 'u';
2966 			*d++ = '0';
2967 			*d++ = '0';
2968 			snprintf (ch, sizeof (ch), "%02x", 0xff & ((ut8)*s));
2969 			*d++ = ch[0];
2970 			*d++ = ch[1];
2971 		}
2972 	}
2973 	*d = 0;
2974 	tmp = realloc (od, strlen (od) + 1); // FIT
2975 	if (!tmp) {
2976 		free (od);
2977 		return NULL;
2978 	}
2979 	return tmp;
2980 }
2981 
r_str_prefix_all(const char * s,const char * pfx)2982 R_API char *r_str_prefix_all(const char *s, const char *pfx) {
2983 	const char *os = s;
2984 	char *p;
2985 	int newlines = 1;
2986 	int len = 0;
2987 	int pfx_len = 0;
2988 
2989 	if (!s) {
2990 		return strdup (pfx);
2991 	}
2992 	if (!pfx) {
2993 		return strdup (s);
2994 	}
2995 	len = strlen (s);
2996 	pfx_len = strlen (pfx);
2997 	for (os = s; *os; os++)  {
2998 		if (*os == '\n') {
2999 			newlines++;
3000 		}
3001 	}
3002 	char *o = malloc (len + (pfx_len * newlines) + 1);
3003 	if (!o) {
3004 		return NULL;
3005 	}
3006 	memcpy (o, pfx, pfx_len);
3007 	for (p = o + pfx_len; *s; s++) {
3008 		*p++ = *s;
3009 		if (*s == '\n' && s[1]) {
3010 			memcpy (p, pfx, pfx_len);
3011 			p += pfx_len;
3012 		}
3013 	}
3014 	*p = 0;
3015 	return o;
3016 }
3017 
3018 #define HASCH(x) strchr (input_value,x)
3019 #define CAST (void*)(size_t)
r_str_contains_macro(const char * input_value)3020 R_API ut8 r_str_contains_macro(const char *input_value) {
3021 	char *has_tilde = input_value ? HASCH('~') : NULL,
3022 		 *has_bang = input_value ? HASCH('!') : NULL,
3023 		 *has_brace = input_value ? CAST(HASCH('[') || HASCH(']')) : NULL,
3024 		 *has_paren = input_value ? CAST(HASCH('(') || HASCH(')')) : NULL,
3025 		 *has_cbrace = input_value ? CAST(HASCH('{') || HASCH('}')) : NULL,
3026 		 *has_qmark = input_value ? HASCH('?') : NULL,
3027 		 *has_colon = input_value ? HASCH(':') : NULL,
3028 		 *has_at = input_value ? strchr (input_value, '@') : NULL;
3029 
3030 	return has_tilde || has_bang || has_brace || has_cbrace || has_qmark \
3031 		|| has_paren || has_colon || has_at;
3032 }
3033 
r_str_truncate_cmd(char * string)3034 R_API void r_str_truncate_cmd(char *string) {
3035 	ut32 pos = 0;
3036 	if (string && *string) {
3037 		ut32 sz = strlen (string);
3038 		for (pos = 0; pos < sz; pos++) {
3039 			switch (string[pos]) {
3040 			case '!':
3041 			case ':':
3042 			case ';':
3043 			case '@':
3044 			case '~':
3045 			case '(':
3046 			case '[':
3047 			case '{':
3048 			case '?':
3049 				string[pos] = '\0';
3050 				return;
3051 			}
3052 		}
3053 	}
3054 }
3055 
r_str_closer_chr(const char * b,const char * s)3056 R_API const char *r_str_closer_chr(const char *b, const char *s) {
3057 	const char *a;
3058 	while (*b) {
3059 		for (a = s; *a; a++) {
3060 			if (*b == *a) {
3061 				return b;
3062 			}
3063 		}
3064 		b++;
3065 	}
3066 	return NULL;
3067 }
3068 
r_str_bounds(const char * _str,int * h)3069 R_API int r_str_bounds(const char *_str, int *h) {
3070 	const char *str, *ptr;
3071 	int W = 0, H = 0;
3072 	int cw = 0;
3073 
3074 	if (_str) {
3075 		ptr = str = _str;
3076 		while (*str) {
3077 			if (*str == '\n') {
3078 				H++;
3079 				cw = r_str_ansi_nlen (ptr, (size_t)(str - ptr));
3080 				if (cw > W) {
3081 					W = cw;
3082 				}
3083 				cw = 0;
3084 				ptr = str + 1;
3085 			}
3086 			str++;
3087 			cw++;
3088 		}
3089 		if (*str == '\n') {// skip last newline
3090 			H--;
3091 		}
3092 		if (h) {
3093 			*h = H;
3094 		}
3095 	}
3096 	return W;
3097 }
3098 
3099 /* crop a string like it is in a rectangle with the upper-left corner at (x, y)
3100  * coordinates and the bottom-right corner at (x2, y2) coordinates. The result
3101  * is a newly allocated string, that should be deallocated by the user */
r_str_crop(const char * str,unsigned int x,unsigned int y,unsigned int x2,unsigned int y2)3102 R_API char *r_str_crop(const char *str, unsigned int x, unsigned int y,
3103 		unsigned int x2, unsigned int y2) {
3104 	char *r, *ret;
3105 	unsigned int ch = 0, cw = 0;
3106 	if (x2 < 1 || y2 < 1 || !str) {
3107 		return strdup ("");
3108 	}
3109 	r = ret = strdup (str);
3110 	while (*str) {
3111 		/* crop height */
3112 		if (ch >= y2) {
3113 			r--;
3114 			break;
3115 		}
3116 
3117 		if (*str == '\n') {
3118 			if (ch >= y && ch < y2) {
3119 				*r++ = *str;
3120 			}
3121 			str++;
3122 			ch++;
3123 			cw = 0;
3124 		} else {
3125 			if (ch >= y && ch < y2 && cw >= x && cw < x2) {
3126 				*r++ = *str;
3127 			}
3128 			/* crop width */
3129 			/* skip until newline */
3130 			if (cw >= x2) {
3131 				while (*str && *str != '\n') {
3132 					str++;
3133 				}
3134 			} else {
3135 				str++;
3136 			}
3137 			cw++;
3138 		}
3139 	}
3140 	*r = 0;
3141 	return ret;
3142 }
3143 
3144 // TODO: improve loop to wrap by words
r_str_wrap(const char * str,int w)3145 R_API char *r_str_wrap(const char *str, int w) {
3146 	char *r, *ret;
3147 	if (w < 1 || !str) {
3148 		return strdup ("");
3149 	}
3150 	size_t r_size = 8 * strlen (str);
3151 	r = ret = malloc (r_size);
3152 	char *end = r + r_size;
3153 	int cw = 0;
3154 	while (*str && r + 1 < end) {
3155 		if (*str == '\t') {
3156 			// skip
3157 		} else if (*str == '\r') {
3158 			// skip
3159 		} else if (*str == '\n') {
3160 			*r++ = *str++;
3161 			cw = 0;
3162 		} else {
3163 			if (cw > w) {
3164 				*r++ = '\n';
3165 				*r++ = *str++;
3166 				cw = 1;
3167 			} else {
3168 				*r++ = *str++;
3169 				cw++;
3170 			}
3171 		}
3172 	}
3173 	*r = 0;
3174 	return ret;
3175 }
3176 
r_str_tok(const char * str1,const char b,size_t len)3177 R_API const char * r_str_tok(const char *str1, const char b, size_t len) {
3178 	const char *p = str1;
3179 	size_t i = 0;
3180 	if (!p || !*p) {
3181 		return p;
3182 	}
3183 	if (len == -1) {
3184 		len = strlen (str1);
3185 	}
3186 	for ( ; i < len; i++,p++) {
3187 		if (*p == b) {
3188 			break;
3189 		}
3190 	}
3191 	if (i == len) {
3192 		p = NULL;
3193 	}
3194 	return p;
3195 }
3196 
r_str_do_until_token(str_operation op,char * str,const char tok)3197 R_API int r_str_do_until_token(str_operation op, char *str, const char tok) {
3198 	int ret;
3199 	if (!str) {
3200 		return -1;
3201 	}
3202 	if (!op) {
3203 		for (ret = 0; (str[ret] != tok) && str[ret]; ret++) {
3204 			//empty body
3205 		}
3206 	} else {
3207 		for (ret = 0; (str[ret] != tok) && str[ret]; ret++) {
3208 			op (str + ret);
3209 		}
3210 	}
3211 	return ret;
3212 }
3213 
r_str_pad(const char ch,int sz)3214 R_API const char *r_str_pad(const char ch, int sz) {
3215 	static char pad[1024];
3216 	if (sz < 0) {
3217 		sz = 0;
3218 	}
3219 	memset (pad, ch, R_MIN (sz, sizeof (pad)));
3220 	if (sz < sizeof (pad)) {
3221 		pad[sz] = 0;
3222 	}
3223 	pad[sizeof(pad) - 1] = 0;
3224 	return pad;
3225 }
3226 
r_str_repeat(const char * ch,int sz)3227 R_API char *r_str_repeat(const char *ch, int sz) {
3228 	int i;
3229 	if (sz < 0) {
3230 		sz = 0;
3231 	}
3232 	if (sz == 0) {
3233 		return strdup ("");
3234 	}
3235 	RStrBuf *buf = r_strbuf_new (ch);
3236 	for (i = 1; i < sz; i++) {
3237 		r_strbuf_append (buf, ch);
3238 	}
3239 	return r_strbuf_drain (buf);
3240 }
3241 
r_str_between(const char * cmt,const char * prefix,const char * suffix)3242 R_API char *r_str_between(const char *cmt, const char *prefix, const char *suffix) {
3243 	char *c0, *c1;
3244 	if (!cmt || !prefix || !suffix || !*cmt) {
3245 		return NULL;
3246 	}
3247 	c0 = strstr (cmt, prefix);
3248 	if (c0) {
3249 		c1 = strstr (c0 + strlen (prefix), suffix);
3250 		if (c1) {
3251 			return r_str_ndup (c0 + strlen (prefix), (c1 - c0 - strlen (prefix)));
3252 		}
3253 	}
3254 	return NULL;
3255 }
3256 
r_str_startswith(const char * str,const char * needle)3257 R_API bool r_str_startswith(const char *str, const char *needle) {
3258 	r_return_val_if_fail (str && needle, false);
3259 	if (str == needle) {
3260 		return true;
3261 	}
3262 	return !strncmp (str, needle, strlen (needle));
3263 }
3264 
r_str_endswith(const char * str,const char * needle)3265 R_API bool r_str_endswith(const char *str, const char *needle) {
3266 	r_return_val_if_fail (str && needle, false);
3267 	if (!*needle) {
3268 		return true;
3269 	}
3270 	int slen = strlen (str);
3271 	int nlen = strlen (needle);
3272 	if (!slen || !nlen || slen < nlen) {
3273 		return false;
3274 	}
3275 	return !strcmp (str + (slen - nlen), needle);
3276 }
3277 
3278 // Splits the string <str> by string <c> and returns the result in a list.
r_str_split_list(char * str,const char * c,int n)3279 R_API RList *r_str_split_list(char *str, const char *c, int n)  {
3280 	r_return_val_if_fail (str && c, NULL);
3281 	RList *lst = r_list_newf (NULL);
3282 	char *aux = str;
3283 	int i = 0;
3284 	char  *e = aux;
3285 	for (;e;) {
3286 		e = strstr (aux, c);
3287 		if (n > 0) {
3288 			if (++i > n) {
3289 				r_list_append (lst, aux);
3290 				break;
3291 			}
3292 		}
3293 		if (e) {
3294 			*e++ =  0;
3295 		}
3296 		r_str_trim (aux);
3297 		r_list_append (lst, aux);
3298 		aux = e;
3299 	}
3300 	return lst;
3301 }
3302 
r_str_split_duplist(const char * _str,const char * c,bool trim)3303 R_API RList *r_str_split_duplist(const char *_str, const char *c, bool trim) {
3304 	r_return_val_if_fail (_str && c, NULL);
3305 	RList *lst = r_list_newf (free);
3306 	char *str = strdup (_str);
3307 	char *aux = str;
3308 	size_t clen = strlen (c);
3309 	while (aux) {
3310 		char *next = strstr (aux, c);
3311 		if (next) {
3312 			*next = '\0';
3313 			next += clen;
3314 		}
3315 		if (trim) {
3316 			r_str_trim (aux);
3317 		}
3318 		r_list_append (lst, strdup (aux));
3319 		aux = next;
3320 	}
3321 	free (str);
3322 	return lst;
3323 }
3324 
r_str_split_lines(char * str,size_t * count)3325 R_API size_t *r_str_split_lines(char *str, size_t *count) {
3326 	int i;
3327 	size_t lines = 0;
3328 	if (!str) {
3329 		return NULL;
3330 	}
3331 	size_t *indexes = NULL;
3332 	// count lines
3333 	for (i = 0; str[i]; i++) {
3334 		if (str[i] == '\n') {
3335 			lines++;
3336 		}
3337 	}
3338 	// allocate and set indexes
3339 	indexes = calloc (sizeof (count[0]), lines + 1);
3340 	if (!indexes) {
3341 		return NULL;
3342 	}
3343 	size_t line = 0;
3344 	indexes[line++] = 0;
3345 	for (i = 0; str[i]; i++) {
3346 		if (str[i] == '\n') {
3347 			str[i] = 0;
3348 			indexes[line++] = i + 1;
3349 		}
3350 	}
3351 	if (count) {
3352 		*count = line;
3353 	}
3354 	return indexes;
3355 }
3356 
r_str_isnumber(const char * str)3357 R_API bool r_str_isnumber(const char *str) {
3358 	if (!str || (!IS_DIGIT (*str) && *str != '-')) {
3359 		return false;
3360 	}
3361 
3362 	while (*++str) {
3363 		if (!IS_DIGIT (*str)) {
3364 			return false;
3365 		}
3366 	}
3367 
3368 	return true;
3369 }
3370 
3371 /* TODO: optimize to start searching by the end of the string */
r_str_last(const char * str,const char * ch)3372 R_API const char *r_str_last(const char *str, const char *ch) {
3373 	char *ptr, *end = NULL;
3374 	if (!str || !ch) {
3375 		return NULL;
3376 	}
3377 	do {
3378 		ptr = strstr (str, ch);
3379 		if (!ptr) {
3380 			break;
3381 		}
3382 		end = ptr;
3383 		str = ptr + 1;
3384 	} while (true);
3385 	return end;
3386 }
3387 
3388 // copies the WHOLE string but check n against non color code chars only.
strncpy_with_color_codes(char * s1,char * s2,int n)3389 static int strncpy_with_color_codes(char *s1, char *s2, int n) {
3390 	int i = 0, j = 0;
3391 	int count = 0;
3392 	while (s2[j] && count < n) {
3393 		// detect (consecutive) color codes
3394 		while (s2[j] == 0x1b) {
3395 			// copy till 'm'
3396 			while (s2[j] && s2[j] != 'm') {
3397 				s1[i++] = s2[j++];
3398 			}
3399 			// copy 'm'
3400 			if (s2[j]) {
3401 				s1[i++] = s2[j++];
3402 			}
3403 		}
3404 		if (s2[j]) {
3405 			s1[i++] = s2[j++];
3406 			count++;
3407 		}
3408 	}
3409 	return i;
3410 }
3411 
strncmp_skip_color_codes(const char * s1,const char * s2,int n)3412 static int strncmp_skip_color_codes(const char *s1, const char *s2, int n) {
3413 	int i = 0, j = 0;
3414 	int count = 0;
3415 	for (i = 0, j = 0; s1[i]  && s2[j] && count < n; i++, j++, count++) {
3416 		while (s1[i] == 0x1b) {
3417 			while (s1[i] && s1[i] != 'm') {
3418 				i++;
3419 			}
3420 			if (s1[i]) {
3421 				i++;
3422 			}
3423 		}
3424 		while (s2[j] == 0x1b) {
3425 			while (s2[j] && s2[j] != 'm') {
3426 				j++;
3427 			}
3428 			if (s2[j]) {
3429 				j++;
3430 			}
3431 		}
3432 		if (s1[i] != s2[j]) {
3433 			return -1;
3434 		}
3435 	}
3436 
3437 	if (count < n && s1[i] != s2[j]) {
3438 		return -1;
3439 	}
3440 
3441 	return 0;
3442 }
3443 
strchr_skip_color_codes(const char * s,int c)3444 static char *strchr_skip_color_codes(const char *s, int c) {
3445 	int i = 0;
3446 	for (i = 0; s[i]; i++) {
3447 		while (s[i] && s[i] == 0x1b) {
3448 			while (s[i] && s[i] != 'm') {
3449 				i++;
3450 			}
3451 			if (s[i]) {
3452 				i++;
3453 			}
3454 		}
3455 		if (!s[i] || s[i] == (char)c) {
3456 			return (char*)s + i;
3457 		}
3458 	}
3459 	return NULL;
3460 }
3461 
3462 // Global buffer to speed up colorizing performance
3463 
r_str_highlight(char * str,const char * word,const char * color,const char * color_reset)3464 R_API char* r_str_highlight(char *str, const char *word, const char *color, const char *color_reset) {
3465 	if (!str || !*str) {
3466 		return NULL;
3467 	}
3468 	ut32 i = 0, j = 0, to_copy;
3469 	char *start = str;
3470 	ut32 l_str = strlen (str);
3471 	ut32 l_reset = strlen (color_reset);
3472 	ut32 l_color = color? strlen (color): 0;
3473 	if (!color) {
3474 		return strdup (str);
3475 	}
3476 	if (!word || !*word) {
3477 		return r_str_newf ("%s%s%s", color, str, color_reset);
3478 	}
3479 	ut32 l_word = strlen (word);
3480 	// XXX don't use static buffers
3481 	char o[1024] = {0};
3482 	while (start && (start < str + l_str)) {
3483 		int copied = 0;
3484 		// find first letter
3485 		start = strchr_skip_color_codes (str + i, *word);
3486 		if (start) {
3487 			to_copy = start - (str + i);
3488 			if (to_copy + j + 1 > sizeof (o)) {
3489 				// XXX. no limits
3490 				break;
3491 			}
3492 			strncpy (o + j, str + i, to_copy);
3493 			i += to_copy;
3494 			j += to_copy;
3495 			if (!strncmp_skip_color_codes (start, word, l_word)) {
3496 				if (j + strlen (color) >= sizeof (o)) {
3497 					// XXX. no limits
3498 					break;
3499 				}
3500 				strcpy (o + j, color);
3501 				j += l_color;
3502 				if (j + l_word >= sizeof (o)) {
3503 					// XXX. no limits
3504 					break;
3505 				}
3506 				copied = strncpy_with_color_codes (o + j, str + i, l_word);
3507 				i += copied;
3508 				j += copied;
3509 				if (j + strlen (color_reset) >= sizeof (o)) {
3510 					// XXX. no limits
3511 					break;
3512 				}
3513 				strcpy (o + j, color_reset);
3514 				j += l_reset;
3515 			} else {
3516 				o[j++] = str[i++];
3517 			}
3518 		} else {
3519 			if (j + strlen (str + i) >= sizeof (o)) {
3520 				break;
3521 			}
3522 			strcpy (o + j, str + i);
3523 			break;
3524 		}
3525 	}
3526 	return strdup (o);
3527 }
3528 
r_str_mb_to_wc_l(const char * buf,int len)3529 R_API wchar_t* r_str_mb_to_wc_l(const char *buf, int len) {
3530 	wchar_t *res_buf = NULL;
3531 	size_t sz;
3532 	bool fail = true;
3533 
3534 	if (!buf || len <= 0) {
3535 		return NULL;
3536 	}
3537 	sz = mbstowcs (NULL, buf, len);
3538 	if (sz == (size_t)-1) {
3539 		goto err_r_str_mb_to_wc;
3540 	}
3541 	res_buf = (wchar_t *)calloc (1, (sz + 1) * sizeof (wchar_t));
3542 	if (!res_buf) {
3543 		goto err_r_str_mb_to_wc;
3544 	}
3545 	sz = mbstowcs (res_buf, buf, sz + 1);
3546 	if (sz == (size_t)-1) {
3547 		goto err_r_str_mb_to_wc;
3548 	}
3549 	fail = false;
3550 err_r_str_mb_to_wc:
3551 	if (fail) {
3552 		R_FREE (res_buf);
3553 	}
3554 	return res_buf;
3555 }
3556 
r_str_wc_to_mb_l(const wchar_t * buf,int len)3557 R_API char* r_str_wc_to_mb_l(const wchar_t *buf, int len) {
3558 	char *res_buf = NULL;
3559 	bool fail = true;
3560 	size_t sz;
3561 
3562 	if (!buf || len <= 0) {
3563 		return NULL;
3564 	}
3565 	sz = wcstombs (NULL, buf, len);
3566 	if (sz == (size_t)-1) {
3567 		goto err_r_str_wc_to_mb;
3568 	}
3569 	res_buf = (char *)calloc (1, (sz + 1) * sizeof (char));
3570 	if (!res_buf) {
3571 		goto err_r_str_wc_to_mb;
3572 	}
3573 	sz = wcstombs (res_buf, buf, sz + 1);
3574 	if (sz == (size_t)-1) {
3575 		goto err_r_str_wc_to_mb;
3576 	}
3577 	fail = false;
3578 err_r_str_wc_to_mb:
3579 	if (fail) {
3580 		R_FREE (res_buf);
3581 	}
3582 	return res_buf;
3583 }
3584 
r_str_wc_to_mb(const wchar_t * buf)3585 R_API char* r_str_wc_to_mb(const wchar_t *buf) {
3586 	if (!buf) {
3587 		return NULL;
3588 	}
3589 	return r_str_wc_to_mb_l (buf, wcslen (buf));
3590 }
3591 
r_str_mb_to_wc(const char * buf)3592 R_API wchar_t* r_str_mb_to_wc(const char *buf) {
3593 	if (!buf) {
3594 		return NULL;
3595 	}
3596 	return r_str_mb_to_wc_l (buf, strlen (buf));
3597 }
3598 
r_str_from_ut64(ut64 val)3599 R_API char *r_str_from_ut64(ut64 val) {
3600 	int i = 0;
3601 	char *v = (char *)&val;
3602 	char *str = (char *)calloc(1, 9);
3603 	if (!str) {
3604 		return NULL;
3605 	}
3606 	while (i < 8 && *v) {
3607 		str[i++] = *v++;
3608 	}
3609 	return str;
3610 }
3611 
r_snprintf(char * string,int len,const char * fmt,...)3612 R_API int r_snprintf(char *string, int len, const char *fmt, ...) {
3613 	va_list ap;
3614 	va_start (ap, fmt);
3615 	int ret = vsnprintf (string, len, fmt, ap);
3616 	string[len - 1] = 0;
3617 	va_end (ap);
3618 	return ret;
3619 }
3620 
3621 // Strips all the lines in str that contain key
r_str_stripLine(char * str,const char * key)3622 R_API void r_str_stripLine(char *str, const char *key) {
3623 	size_t i, j, klen, slen, off;
3624 	const char *ptr;
3625 
3626 	if (!str || !key) {
3627 		return;
3628 	}
3629 	klen = strlen (key);
3630 	slen = strlen (str);
3631 
3632 	for (i = 0; i < slen; ) {
3633 		ptr = (char*) r_mem_mem ((ut8*) str + i, slen - i, (ut8*) "\n", 1);
3634 		if (!ptr) {
3635 			ptr = (char*) r_mem_mem ((ut8*) str + i, slen - i, (ut8*) key, klen);
3636 			if (ptr) {
3637 				str[i] = '\0';
3638 				break;
3639 			}
3640 			break;
3641 		}
3642 
3643 		off = (size_t) (ptr - (str + i)) + 1;
3644 
3645 		ptr = (char*) r_mem_mem ((ut8*) str + i, off, (ut8*) key, klen);
3646 		if (ptr) {
3647 			for (j = i; j < slen - off + 1; j++) {
3648 				str[j] = str[j + off];
3649 			}
3650 			slen -= off;
3651 		} else {
3652 			i += off;
3653 		}
3654 	}
3655 }
3656 
r_str_list_join(RList * str,const char * sep)3657 R_API char *r_str_list_join(RList *str, const char *sep) {
3658 	RStrBuf *sb = r_strbuf_new ("");
3659 	const char *p;
3660 	while ((p = r_list_pop_head (str))) {
3661 		if (r_strbuf_length (sb) != 0) {
3662 			r_strbuf_append (sb, sep);
3663 		}
3664 		r_strbuf_append (sb, p);
3665 	}
3666 	return r_strbuf_drain (sb);
3667 }
3668 
r_str_array_join(const char ** a,size_t n,const char * sep)3669 R_API char *r_str_array_join(const char **a, size_t n, const char *sep) {
3670 	RStrBuf *sb = r_strbuf_new ("");
3671 	size_t i;
3672 
3673 	if (n > 0) {
3674 		r_strbuf_append (sb, a[0]);
3675 	}
3676 
3677 	for (i = 1; i < n; i++) {
3678 		r_strbuf_append (sb, sep);
3679 		r_strbuf_append (sb, a[i]);
3680 	}
3681 	return r_strbuf_drain (sb);
3682 }
3683 
3684 /* return the number of arguments expected as extra arguments */
r_str_fmtargs(const char * fmt)3685 R_API int r_str_fmtargs(const char *fmt) {
3686 	int n = 0;
3687 	while (*fmt) {
3688 		if (*fmt == '%') {
3689 			if (fmt[1] == '*') {
3690 				n++;
3691 			}
3692 			n++;
3693 		}
3694 		fmt++;
3695 	}
3696 	return n;
3697 }
3698 
3699 // str-bool
3700 
3701 // Returns "true" or "false" as a string given an input integer. The returned
3702 // value is consistent with C's definition of 0 is false, and all other values
3703 // are true.
r_str_bool(int b)3704 R_API const char *r_str_bool(int b) {
3705 	return b? "true": "false";
3706 }
3707 
r_str_is_true(const char * s)3708 R_API bool r_str_is_true(const char *s) {
3709 	return !r_str_casecmp ("yes", s)
3710 		|| !r_str_casecmp ("on", s)
3711 		|| !r_str_casecmp ("true", s)
3712 		|| !r_str_casecmp ("1", s);
3713 }
3714 
r_str_is_false(const char * s)3715 R_API bool r_str_is_false(const char *s) {
3716 	return !r_str_casecmp ("no", s)
3717 		|| !r_str_casecmp ("off", s)
3718 		|| !r_str_casecmp ("false", s)
3719 		|| !r_str_casecmp ("0", s)
3720 		|| !*s;
3721 }
3722 
r_str_is_bool(const char * val)3723 R_API bool r_str_is_bool(const char *val) {
3724 	return r_str_is_true (val) || r_str_is_false (val);
3725 }
3726 
r_str_nextword(char * s,char ch)3727 R_API char *r_str_nextword(char *s, char ch) {
3728 	char *p = strchr (s, ch);
3729 	if (!p) {
3730 		return NULL;
3731 	}
3732 	*p++ = 0;
3733 	return p;
3734 }
3735 
r_str_scale(const char * s,int w,int h)3736 R_API char *r_str_scale(const char *s, int w, int h) {
3737 	// count lines and rows in (s) string
3738 	// compute how many lines we should remove or combine
3739 	// return a string containing
3740 	// for now this function is ascii only (no utf8 or ansi escapes)
3741 	RListIter *iter;
3742 	char *line;
3743 	char *str = strdup (s);
3744 	RList *lines = r_str_split_list (str, "\n", 0);
3745 	int i, j;
3746 	int rows = 0;
3747 	int maxcol = 0;
3748 
3749 	rows = r_list_length (lines);
3750 	r_list_foreach (lines, iter, line) {
3751 		maxcol = R_MAX (strlen (line), maxcol);
3752 	}
3753 
3754 	RList *out = r_list_newf (free);
3755 
3756 	int curline = -1;
3757 	char *linetext = (char*)r_str_pad (' ', w);
3758 	for (i = 0; i < h; i++) {
3759 		int zoomedline = i * ((float)rows / h);
3760 		const char *srcline = r_list_get_n (lines, zoomedline);
3761 		int cols = strlen (srcline);
3762 		for (j = 0; j < w; j++) {
3763 			int zoomedcol = j * ( (float)cols / w);
3764 			linetext[j] = srcline[zoomedcol];
3765 		}
3766 		if (curline != zoomedline) {
3767 			r_list_append (out, strdup (linetext));
3768 			curline = zoomedline;
3769 		}
3770 		memset (linetext, ' ', w);
3771 	}
3772 	free (str);
3773 	return r_str_list_join (out, "\n");
3774 }
3775 
r_str_str_xy(const char * s,const char * word,const char * prev,int * x,int * y)3776 R_API const char *r_str_str_xy(const char *s, const char *word, const char *prev, int *x, int *y) {
3777 	r_return_val_if_fail (s && word && x && y, NULL);
3778 	r_return_val_if_fail (word[0] != '\0' && word[0] != '\n', NULL);
3779 	const char *src = prev ? prev + 1 : s;
3780 	const char *d = strstr (src, word);
3781 	if (!d) {
3782 		return NULL;
3783 	}
3784 	const char *q;
3785 	for (q = prev ? prev : s; q < d; q++) {
3786 		if (*q == '\n') {
3787 			(*y)++;
3788 			*x = 0;
3789 
3790 		} else {
3791 			(*x)++;
3792 		}
3793 	}
3794 	return d;
3795 }
3796 
3797 
3798 // version.c
3799 #include <r_userconf.h>
3800 #include <r_util.h>
3801 
3802 #ifndef R2_GITTAP
3803 #define R2_GITTAP ""
3804 #endif
3805 
3806 #ifndef R2_GITTIP
3807 #define R2_GITTIP ""
3808 #endif
3809 
3810 #ifndef R2_BIRTH
3811 #define R2_BIRTH "unknown"
3812 #endif
3813 
r_str_version(const char * program)3814 R_API char *r_str_version(const char *program) {
3815 	char *s = r_str_newf ("%s "R2_VERSION" %d @ "
3816 			R_SYS_OS"-"
3817 			R_SYS_ARCH"-%d git.%s\n",
3818 			program, R2_VERSION_COMMIT,
3819 			(R_SYS_BITS & 8)? 64: 32,
3820 			*R2_GITTAP ? R2_GITTAP: "");
3821 	if (*R2_GITTIP) {
3822 		s = r_str_appendf (s, "commit: "R2_GITTIP" build: "R2_BIRTH);
3823 	}
3824 	return s;
3825 }
3826