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