Rizin
unix-like reverse engineering framework and cli tools
str.c
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: 2007-2020 pancake <pancake@nopcode.org>
2 // SPDX-License-Identifier: LGPL-3.0-only
3 
4 #include <rz_regex.h>
5 #include "rz_list.h"
6 #include "rz_types.h"
7 #include "rz_util.h"
8 #include "rz_cons.h"
9 #include "rz_bin.h"
10 #include "rz_util/rz_assert.h"
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <ctype.h>
15 #include <wchar.h>
16 #include <stdarg.h>
17 #include <rz_util/rz_base64.h>
18 #include <rz_util/rz_utf8.h>
19 #include <rz_util/rz_utf16.h>
20 #include <rz_util/rz_utf32.h>
21 #include <rz_util/rz_ebcdic.h>
22 
23 /* stable code */
24 static const char *rwxstr[] = {
25  [0] = "---",
26  [1] = "--x",
27  [2] = "-w-",
28  [3] = "-wx",
29  [4] = "r--",
30  [5] = "r-x",
31  [6] = "rw-",
32  [7] = "rwx",
33 
34  [8] = "---",
35  [9] = "--x",
36  [10] = "-w-",
37  [11] = "-wx",
38  [12] = "r--",
39  [13] = "r-x",
40  [14] = "rw-",
41  [15] = "rwx",
42 };
43 
45  switch (enc) {
46  case RZ_STRING_ENC_8BIT:
47  return "ascii";
48  case RZ_STRING_ENC_UTF8:
49  return "utf8";
51  return "mutf8";
53  return "utf16le";
55  return "utf32le";
57  return "utf16be";
59  return "utf32be";
61  return "base64";
63  return "ibm037";
65  return "ibm290";
67  return "ebcdices";
69  return "ebcdicuk";
71  return "ebcdicus";
73  return "guessed";
74  default:
76  return "unknown";
77  }
78 }
79 
87  if (!encoding || !strncmp(encoding, "guess", 5)) {
88  return RZ_STRING_ENC_GUESS;
89  } else if (!strcmp(encoding, "ascii") || !strcmp(encoding, "8bit")) {
90  return RZ_STRING_ENC_8BIT;
91  } else if (!strcmp(encoding, "mutf8")) {
92  return RZ_STRING_ENC_MUTF8;
93  } else if (!strcmp(encoding, "utf8")) {
94  return RZ_STRING_ENC_UTF8;
95  } else if (!strcmp(encoding, "utf16le")) {
96  return RZ_STRING_ENC_UTF16LE;
97  } else if (!strcmp(encoding, "utf32le")) {
98  return RZ_STRING_ENC_UTF32LE;
99  } else if (!strcmp(encoding, "utf16be")) {
100  return RZ_STRING_ENC_UTF16BE;
101  } else if (!strcmp(encoding, "utf32be")) {
102  return RZ_STRING_ENC_UTF32BE;
103  } else if (!strcmp(encoding, "ibm037")) {
104  return RZ_STRING_ENC_IBM037;
105  } else if (!strcmp(encoding, "ibm290")) {
106  return RZ_STRING_ENC_IBM290;
107  } else if (!strcmp(encoding, "ebcdices")) {
109  } else if (!strcmp(encoding, "ebcdicuk")) {
111  } else if (!strcmp(encoding, "ebcdicus")) {
113  } else if (!strcmp(encoding, "base64")) {
114  return RZ_STRING_ENC_BASE64;
115  }
116 
117  RZ_LOG_ERROR("rz_str: encoding %s not supported\n", encoding);
118  return RZ_STRING_ENC_GUESS;
119 }
120 
121 RZ_API int rz_str_casecmp(const char *s1, const char *s2) {
122 #ifdef _MSC_VER
123  return stricmp(s1, s2);
124 #else
125  return strcasecmp(s1, s2);
126 #endif
127 }
128 
129 RZ_API int rz_str_ncasecmp(const char *s1, const char *s2, size_t n) {
130 #ifdef _MSC_VER
131  return _strnicmp(s1, s2, n);
132 #else
133  return strncasecmp(s1, s2, n);
134 #endif
135 }
136 
137 // GOOD
138 // In-place replace the first instance of the character a, with the character b.
139 RZ_API int rz_str_replace_ch(char *s, char a, char b, bool global) {
140  int ret = 0;
141  char *o = s;
142  if (!s || a == b) {
143  return 0;
144  }
145  for (; *o; s++, o++) {
146  if (*o == a) {
147  ret++;
148  if (b) {
149  *s = b;
150  } else {
151  /* remove char */
152  s--;
153  }
154  if (!global) {
155  return 1;
156  }
157  } else {
158  *s = *o;
159  }
160  }
161  *s = 0;
162  return ret;
163 }
164 
165 RZ_API int rz_str_replace_char_once(char *s, int a, int b) {
166  return rz_str_replace_ch(s, a, b, false);
167 }
168 
169 RZ_API int rz_str_replace_char(char *s, int a, int b) {
170  return rz_str_replace_ch(s, a, b, true);
171 }
172 
173 RZ_API void rz_str_remove_char(char *str, char c) {
174  while (*str) {
175  if (*str == c) {
176  memmove(str, str + 1, strlen(str + 1) + 1);
177  continue;
178  }
179  str++;
180  }
181 }
182 
183 RZ_API void rz_str_reverse(char *str) {
184  int i, len = strlen(str);
185  int half = len / 2;
186  for (i = 0; i < half; i++) {
187  char ch = str[i];
188  str[i] = str[len - i - 1];
189  str[len - i - 1] = ch;
190  }
191 }
192 
193 // TODO: do not use toupper.. must support modes to also append lowercase chars like in r1
194 // TODO: this functions needs some stabilization
195 RZ_API int rz_str_bits(char *strout, const ut8 *buf, int len, const char *bitz) {
196  int i, j, idx;
197  if (bitz) {
198  for (i = j = 0; i < len && (!bitz || bitz[i]); i++) {
199  if (i > 0 && (i % 8) == 0) {
200  buf++;
201  }
202  if (*buf & (1 << (i % 8))) {
203  strout[j++] = toupper((const ut8)bitz[i]);
204  }
205  }
206  } else {
207  for (i = j = 0; i < len; i++) {
208  idx = (i / 8);
209  int bit = 7 - (i % 8);
210  strout[j++] = (buf[idx] & (1 << bit)) ? '1' : '0';
211  }
212  }
213  strout[j] = 0;
214  return j;
215 }
216 
217 RZ_API const char *rz_str_sysbits(const int v) {
218  switch (v) {
219  case RZ_SYS_BITS_8: return "8";
220  case RZ_SYS_BITS_16: return "16";
221  case RZ_SYS_BITS_32: return "32";
222  case RZ_SYS_BITS_64: return "64";
223  case RZ_SYS_BITS_16 | RZ_SYS_BITS_32: return "16,32";
224  case RZ_SYS_BITS_16 | RZ_SYS_BITS_32 | RZ_SYS_BITS_64: return "16,32,64";
225  case RZ_SYS_BITS_32 | RZ_SYS_BITS_64: return "32,64";
226  }
227  return "?";
228 }
229 
230 // In-place trims a bitstring to groups of 8 bits.
231 // For example, the bitstring 1000000000000000 will not be modified, but the
232 // bitstring 0000000001000000 will be changed to 01000000.
233 static void trimbits(char *b) {
234  const int len = strlen(b);
235  char *one = strchr(b, '1');
236  int pos = one ? (int)(size_t)(one - b) : len - 1;
237  pos = (pos / 8) * 8;
238  memmove(b, b + pos, len - pos + 1);
239 }
240 
241 // Set 'strout' to the binary representation of the input value.
242 // strout must be a char array of 65 or greater.
243 // The string is then trimmed using the "trimbits" function above.
244 RZ_API int rz_str_bits64(char *strout, ut64 in) {
245  int i, bit, count = 0;
246  count = 0;
247  for (i = (sizeof(in) * 8) - 1; i >= 0; i--) {
248  bit = in >> i;
249  if (bit & 1) {
250  strout[count] = '1';
251  } else {
252  strout[count] = '0';
253  }
254  count++;
255  }
256  strout[count] = '\0';
257  /* trim by 8 bits */
258  trimbits(strout);
259  return count;
260 }
261 
266 RZ_API ut64 rz_str_bits_from_string(const char *buf, const char *bitz) {
267  ut64 out = 0LL;
268  /* return the numeric value associated to a string (rflags) */
269  for (; *buf; buf++) {
270  char *ch = strchr(bitz, toupper((const unsigned char)*buf));
271  if (!ch) {
272  ch = strchr(bitz, tolower((const unsigned char)*buf));
273  }
274  if (ch) {
275  int bit = (int)(size_t)(ch - bitz);
276  out |= (ut64)(1LL << bit);
277  } else {
278  return UT64_MAX;
279  }
280  }
281  return out;
282 }
283 
284 RZ_API int rz_str_binstr2bin(const char *str, ut8 *out, int outlen) {
285  int n, i, j, k, ret, len;
286  len = strlen(str);
287  for (n = i = 0; i < len; i += 8) {
288  ret = 0;
289  while (str[i] == ' ') {
290  str++;
291  }
292  if (i + 7 < len) {
293  for (k = 0, j = i + 7; j >= i; j--, k++) {
294  // INVERSE for (k=0,j=i; j<i+8; j++,k++) {
295  if (str[j] == ' ') {
296  // k--;
297  continue;
298  }
299  // printf ("---> j=%d (%c) (%02x)\n", j, str[j], str[j]);
300  if (str[j] == '1') {
301  ret |= 1 << k;
302  } else if (str[j] != '0') {
303  return n;
304  }
305  }
306  }
307  // printf ("-======> %02x\n", ret);
308  out[n++] = ret;
309  if (n == outlen) {
310  return n;
311  }
312  }
313  return n;
314 }
315 
316 // Returns the permissions as in integer given an input in the form of rwx, rx,
317 // etc.
318 RZ_API int rz_str_rwx(const char *str) {
319  int ret = atoi(str);
320  if (!ret) {
321  ret |= strchr(str, 'm') ? 16 : 0;
322  ret |= strchr(str, 'r') ? 4 : 0;
323  ret |= strchr(str, 'w') ? 2 : 0;
324  ret |= strchr(str, 'x') ? 1 : 0;
325  } else if (ret < 0 || ret >= RZ_ARRAY_SIZE(rwxstr)) {
326  ret = 0;
327  }
328  return ret;
329 }
330 
331 // Returns the string representation of the permission of the inputted integer.
332 RZ_API const char *rz_str_rwx_i(int rwx) {
333  if (rwx < 0 || rwx >= RZ_ARRAY_SIZE(rwxstr)) {
334  rwx = 0;
335  }
336  return rwxstr[rwx % 24]; // 15 for srwx
337 }
338 
339 // If up is true, upcase all characters in the string, otherwise downcase all
340 // characters in the string.
341 RZ_API void rz_str_case(char *str, bool up) {
342  if (up) {
343  char oc = 0;
344  for (; *str; oc = *str++) {
345  *str = (*str == 'x' && oc == '0') ? 'x' : toupper((int)(ut8)*str);
346  }
347  } else {
348  for (; *str; str++) {
349  *str = tolower((int)(ut8)*str);
350  }
351  }
352 }
353 
354 RZ_API char *rz_str_home(const char *str) {
355  char *dst, *home = rz_sys_getenv(RZ_SYS_HOME);
356  size_t length;
357  if (!home) {
358  home = rz_file_tmpdir();
359  if (!home) {
360  return NULL;
361  }
362  }
363  length = strlen(home) + 1;
364  if (str) {
365  length += strlen(RZ_SYS_DIR) + strlen(str);
366  }
367  dst = (char *)malloc(length);
368  if (!dst) {
369  goto fail;
370  }
371  int home_len = strlen(home);
372  memcpy(dst, home, home_len + 1);
373  if (str) {
374  dst[home_len] = RZ_SYS_DIR[0];
375  strcpy(dst + home_len + 1, str);
376  }
377 fail:
378  free(home);
379  return dst;
380 }
381 
382 // Compute a 64 bit DJB hash of a string.
384  ut64 len, h = 5381;
385  if (!s) {
386  return 0;
387  }
388  for (len = strlen(s); len > 0; len--) {
389  h = (h ^ (h << 5)) ^ *s++;
390  }
391  return h;
392 }
393 
394 RZ_API int rz_str_delta(char *p, char a, char b) {
395  char *_a = strchr(p, a);
396  char *_b = strchr(p, b);
397  return (!_a || !_b) ? 0 : (_a - _b);
398 }
399 
406 RZ_API size_t rz_str_split(char *str, char ch) {
408  size_t i;
409  char *p;
410  for (i = 1, p = str; *p; p++) {
411  if (*p == ch) {
412  i++;
413  *p = '\0';
414  }
415  }
416  return i;
417 }
418 
419 // Convert a string into an array of string separated by \0
420 // And the last by \0\0
421 // Separates by words and skip spaces.
422 // Returns the number of tokens that the string is tokenized into.
424  int i, quote = 0;
425  char *p;
426  if (!str || !*str) {
427  return 0;
428  }
429  for (i = 0; str[i] && str[i + 1]; i++) {
430  if (i > 0 && str[i - 1] == ' ' && str[i] == ' ') {
431  int len = strlen(str + i);
432  memmove(str + i, str + i + 1, len);
433  i--;
434  }
435  }
436  if (str[i] == ' ') {
437  str[i] = 0;
438  }
439  for (i = 1, p = str; *p; p++) {
440  if (*p == '\"') {
441  if (quote) {
442  quote = 0;
443  *p = '\0';
444  // FIX: i++;
445  continue;
446  } else {
447  quote = 1;
448  memmove(p, p + 1, strlen(p + 1) + 1);
449  }
450  }
451  if (quote) {
452  continue;
453  }
454  if (*p == ' ') {
455  char *q = p - 1;
456  if (p > str && (*q == '\\' || !*q)) {
457  memmove(p, p + 1, strlen(p + 1) + 1);
458  if (*q == '\\') {
459  *q = ' ';
460  continue;
461  }
462  p--;
463  }
464  i++;
465  *p = '\0';
466  } // s/ /\0/g
467  }
468  return i;
469 }
470 
472  int i;
473  char *p, *q;
474  RzStack *s;
475  void *pop;
476  if (!str || !*str) {
477  return 0;
478  }
479  for (i = 0; str[i] && str[i + 1]; i++) {
480  if (i > 0 && str[i - 1] == ' ' && str[i] == ' ') {
481  memmove(str + i, str + i + 1, strlen(str + i));
482  i--;
483  }
484  if (i == 0 && str[i] == ' ') {
485  memmove(str + i, str + i + 1, strlen(str + i));
486  }
487  }
488  if (str[i] == ' ') {
489  str[i] = 0;
490  }
491  s = rz_stack_new(5); // Some random number
492  for (i = 1, p = str; *p; p++) {
493  q = p - 1;
494  if (p > str && (*q == '\\')) {
495  memmove(q, p, strlen(p) + 1);
496  p--;
497  continue;
498  }
499  switch (*p) {
500  case '(':
501  case '{':
502  case '[':
503  rz_stack_push(s, (void *)p);
504  continue;
505  case '\'':
506  case '"':
507  pop = rz_stack_pop(s);
508  if (pop && *(char *)pop != *p) {
509  rz_stack_push(s, pop);
510  rz_stack_push(s, (void *)p);
511  } else if (!pop) {
512  rz_stack_push(s, (void *)p);
513  }
514  continue;
515  case ')':
516  case '}':
517  case ']':
518  pop = rz_stack_pop(s);
519  if (pop) {
520  if ((*(char *)pop == '(' && *p == ')') ||
521  (*(char *)pop == '{' && *p == '}') ||
522  (*(char *)pop == '[' && *p == ']')) {
523  continue;
524  }
525  }
526  break;
527  case ' ':
528  if (p > str && !*q) {
529  memmove(p, p + 1, strlen(p + 1) + 1);
530  if (*q == '\\') {
531  *q = ' ';
532  continue;
533  }
534  p--;
535  }
536  if (rz_stack_is_empty(s)) {
537  i++;
538  *p = '\0';
539  }
540  default:
541  break;
542  }
543  }
544  rz_stack_free(s);
545  return i;
546 }
547 
548 RZ_API char *rz_str_word_get0set(char *stra, int stralen, int idx, const char *newstr, int *newlen) {
549  char *p = NULL;
550  char *out;
551  int alen, blen, nlen;
552  if (!stra && !newstr) {
553  return NULL;
554  }
555  if (stra) {
556  p = (char *)rz_str_word_get0(stra, idx);
557  }
558  if (!p) {
559  int nslen = strlen(newstr);
560  out = malloc(nslen + 1);
561  if (!out) {
562  return NULL;
563  }
564  strcpy(out, newstr);
565  out[nslen] = 0;
566  if (newlen) {
567  *newlen = nslen;
568  }
569  return out;
570  }
571  alen = (size_t)(p - stra);
572  blen = stralen - ((alen + strlen(p)) + 1);
573  if (blen < 0) {
574  blen = 0;
575  }
576  nlen = alen + blen + strlen(newstr);
577  out = malloc(nlen + 2);
578  if (!out) {
579  return NULL;
580  }
581  if (alen > 0) {
582  memcpy(out, stra, alen);
583  }
584  memcpy(out + alen, newstr, strlen(newstr) + 1);
585  if (blen > 0) {
586  memcpy(out + alen + strlen(newstr) + 1, p + strlen(p) + 1, blen + 1);
587  }
588  out[nlen + 1] = 0;
589  if (newlen) {
590  *newlen = nlen + ((blen == 0) ? 1 : 0);
591  }
592  return out;
593 }
594 
595 // Get the idx'th entry of a tokenized string.
596 // XXX: Warning! this function is UNSAFE, check that the string has, at least,
597 // idx+1 tokens.
598 RZ_API const char *rz_str_word_get0(const char *str, int idx) {
599  int i;
600  const char *ptr = str;
601  if (!ptr || idx < 0 /* prevent crashes with negative index */) {
602  return "";
603  }
604  for (i = 0; i != idx; i++) {
605  ptr = rz_str_word_get_next0(ptr);
606  }
607  return ptr;
608 }
609 
610 // Return the number of times that the character ch appears in the string.
611 RZ_API int rz_str_char_count(const char *string, char ch) {
612  int i, count = 0;
613  for (i = 0; string[i]; i++) {
614  if (string[i] == ch) {
615  count++;
616  }
617  }
618  return count;
619 }
620 
621 static const char *separator_get_first(const char *text) {
622  for (; *text && !IS_SEPARATOR(*text); text++)
623  ;
624  ;
625 
626  return text;
627 }
628 
629 static const char *word_get_first(const char *text) {
630  for (; *text && IS_SEPARATOR(*text); text++)
631  ;
632  ;
633 
634  return text;
635 }
636 
637 RZ_API char *rz_str_word_get_first(const char *text) {
638  return strdup(word_get_first(text));
639 }
640 
641 // Counts the number of words (separated by separator characters: newlines, tabs,
642 // return, space). See rz_util.h for more details of the IS_SEPARATOR macro.
643 RZ_API int rz_str_word_count(const char *string) {
644  int word;
645  const char *text = word_get_first(string);
646 
647  for (word = 0; *text; word++) {
650  }
651 
652  return word;
653 }
654 
655 // Returns a pointer to the first instance of a character that isn't chr in a
656 // string.
657 // TODO: make this const-correct.
658 // XXX if the string is only made up of chr, then the pointer will just point to
659 // a null byte!
660 RZ_API char *rz_str_ichr(char *str, char chr) {
661  while (*str == chr) {
662  str++;
663  }
664  return str;
665 }
666 
667 // Returns a pointer to the last instance of the character chr in the input
668 // string.
669 RZ_API const char *rz_str_lchr(const char *str, char chr) {
670  if (str) {
671  int len = strlen(str);
672  for (; len >= 0; len--) {
673  if (str[len] == chr) {
674  return str + len;
675  }
676  }
677  }
678  return NULL;
679 }
680 
681 /* find the last char chr in the substring str[start:end] with end not included */
682 RZ_API const char *rz_sub_str_lchr(const char *str, int start, int end, char chr) {
683  do {
684  end--;
685  } while (str[end] != chr && end >= start);
686  return str[end] == chr ? &str[end] : NULL;
687 }
688 
689 /* find the first char chr in the substring str[start:end] with end not included */
690 RZ_API const char *rz_sub_str_rchr(const char *str, int start, int end, char chr) {
691  while (str[start] && str[start] != chr && start < end) {
692  start++;
693  }
694  return str[start] == chr ? str + start : NULL;
695 }
696 
703 RZ_API bool rz_str_is2utf8(RZ_NONNULL const char *c) {
704  rz_return_val_if_fail(c, false);
705  if (!c[0] || !c[1]) {
706  return false;
707  }
708  return ((c[0] & 0xe0) == 0xc0) && ((c[1] & 0xc0) == 0x80);
709 }
710 
717 RZ_API bool rz_str_is3utf8(RZ_NONNULL const char *c) {
718  rz_return_val_if_fail(c, false);
719  if (!c[0] || !c[1] || !c[2]) {
720  return false;
721  }
722  return ((c[0] & 0xf0) == 0xe0) && ((c[1] & 0xc0) == 0x80) && ((c[2] & 0xc0) == 0x80);
723 }
724 
731 RZ_API bool rz_str_is4utf8(RZ_NONNULL const char *c) {
732  rz_return_val_if_fail(c, false);
733  if (!c[0] || !c[1] || !c[2] || !c[3]) {
734  return false;
735  }
736  return ((c[0] & 0xf8) == 0xf0) && ((c[1] & 0xc0) == 0x80) && ((c[2] & 0xc0) == 0x80) && ((c[3] & 0xc0) == 0x80);
737 }
738 
745 RZ_API bool rz_str_isXutf8(RZ_NONNULL const char *c, ut8 x) {
746  rz_return_val_if_fail(c, false);
747  switch (x) {
748  default:
749  return false;
750  case 1:
751  return isascii(c[0]);
752  case 2:
753  return rz_str_is2utf8(c);
754  case 3:
755  return rz_str_is3utf8(c);
756  case 4:
757  return rz_str_is4utf8(c);
758  }
759 }
760 
768 RZ_API const char *rz_str_strchr(RZ_NONNULL const char *str, RZ_NONNULL const char *c) {
770  ut32 i = 0;
771  ut64 str_len = strlen(str);
772  ut8 c_len = isascii(*c) ? 1 : (rz_str_is2utf8(c) ? 2 : (rz_str_is3utf8(c) ? 3 : (rz_str_is4utf8(c) ? 4 : 1)));
773  while (i <= str_len && i + c_len <= str_len) {
774  if (c_len == 1) {
775  if (str[i] == c[0]) {
776  return str + i;
777  }
778  } else {
779  if (rz_mem_eq((ut8 *)str + i, (ut8 *)c, c_len)) {
780  return str + i;
781  }
782  }
783  ++i;
784  }
785  return NULL;
786 }
787 
788 RZ_API const char *rz_str_sep(const char *base, const char *sep) {
789  int i;
790  while (*base) {
791  for (i = 0; sep[i]; i++) {
792  if (*base == sep[i]) {
793  return base;
794  }
795  }
796  base++;
797  }
798  return NULL;
799 }
800 
801 RZ_API const char *rz_str_rsep(const char *base, const char *p, const char *sep) {
802  int i;
803  while (p >= base) {
804  for (i = 0; sep[i]; i++) {
805  if (*p == sep[i]) {
806  return p;
807  }
808  }
809  p--;
810  }
811  return NULL;
812 }
813 
814 RZ_API const char *rz_str_rstr(const char *base, const char *p) {
815  char *s = strdup(base);
816  char *k = strdup(p);
817  rz_str_reverse(s);
818  rz_str_reverse(k);
819  char *q = strstr(s, k);
820  const char *r = NULL;
821  if (q) {
822  r = base + strlen(base) - (q - s) - strlen(p);
823  }
824  free(s);
825  free(k);
826  return r;
827 }
828 
829 RZ_API const char *rz_str_rchr(const char *base, const char *p, int ch) {
831  if (!p) {
832  return strrchr(base, ch);
833  }
834  for (; p >= base; p--) {
835  if (ch == *p) {
836  break;
837  }
838  }
839  return (p >= base) ? p : NULL;
840 }
841 
842 RZ_API const char *rz_str_nstr(const char *s, const char *find, int slen) {
843  char c, sc;
844  size_t len;
845 
846  if ((c = *find++) != '\0') {
847  len = strlen(find);
848  do {
849  do {
850  if (slen-- < 1 || !(sc = *s++)) {
851  return NULL;
852  }
853  } while (sc != c);
854  if (len > slen) {
855  return NULL;
856  }
857  } while (strncmp(s, find, len) != 0);
858  s--;
859  }
860  return (char *)s;
861 }
862 
863 // Returns a new heap-allocated copy of str.
864 // XXX what's the diff with rz_str_dup ?
865 RZ_API char *rz_str_new(const char *str) {
866  return str ? strdup(str) : NULL;
867 }
868 
869 // Returns a new heap-allocated copy of str, sets str[len] to '\0'.
870 // If the input str is longer than len, it will be truncated.
871 RZ_API char *rz_str_newlen(const char *str, int len) {
872  if (len < 0) {
873  return NULL;
874  }
875  char *buf = malloc(len + 1);
876  if (buf) {
877  memcpy(buf, str, len);
878  buf[len] = 0;
879  }
880  return buf;
881 }
882 
883 RZ_API char *rz_str_trunc_ellipsis(const char *str, int len) {
884  if (!str) {
885  return NULL;
886  }
887  if (strlen(str) < len) {
888  return strdup(str);
889  }
890  char *buf = rz_str_newlen(str, len);
891  if (buf && len > 4) {
892  strcpy(buf + len - 4, "...");
893  }
894  return buf;
895 }
896 
897 RZ_API char *rz_str_newf(const char *fmt, ...) {
899  va_list ap, ap2;
900 
901  va_start(ap, fmt);
902  if (!strchr(fmt, '%')) {
903  va_end(ap);
904  return strdup(fmt);
905  }
906  va_copy(ap2, ap);
907  int ret = vsnprintf(NULL, 0, fmt, ap2);
908  ret++;
909  char *p = calloc(1, ret);
910  if (p) {
911  (void)vsnprintf(p, ret, fmt, ap);
912  }
913  va_end(ap2);
914  va_end(ap);
915  return p;
916 }
917 
923 RZ_API size_t rz_str_ncpy(char *dst, const char *src, size_t dst_size) {
925 
926  // do not do anything if dst_size is 0
927  if (dst_size == 0) {
928  return 0;
929  }
930 #if HAVE_STRLCPY
931  return strlcpy(dst, src, dst_size);
932 #else
933  strncpy(dst, src, dst_size - 1);
934  dst[dst_size - 1] = '\0';
935  return strlen(src);
936 #endif
937 }
938 
939 /* memccmp("foo.bar", "foo.cow, '.') == 0 */
940 // Returns 1 if src and dst are equal up until the first instance of ch in src.
941 RZ_API bool rz_str_ccmp(const char *dst, const char *src, int ch) {
942  rz_return_val_if_fail(dst && src, false);
943  int i;
944  for (i = 0; src[i] && src[i] != ch; i++) {
945  if (dst[i] != src[i]) {
946  return true;
947  }
948  }
949  return false;
950 }
951 
952 // Returns true if item is in sep-separated list
953 RZ_API bool rz_str_cmp_list(const char *list, const char *item, char sep) {
954  if (!list || !item) {
955  return false;
956  }
957  int i = 0, j = 0;
958  for (; list[i] && list[i] != sep; i++, j++) {
959  if (item[j] != list[i]) {
960  while (list[i] && list[i] != sep) {
961  i++;
962  }
963  if (!list[i]) {
964  return false;
965  }
966  j = -1;
967  continue;
968  }
969  }
970  return true;
971 }
972 
973 // like strncmp, but checking for null pointers
974 RZ_API int rz_str_cmp(const char *a, const char *b, int len) {
975  if ((a == b) || (!a && !b)) {
976  return 0;
977  }
978  if (!a && b) {
979  return -1;
980  }
981  if (a && !b) {
982  return 1;
983  }
984  if (len < 0) {
985  return strcmp(a, b);
986  }
987  return strncmp(a, b, len);
988 }
989 
990 // Copies all characters from src to dst up until the character 'ch'.
991 RZ_API int rz_str_ccpy(char *dst, char *src, int ch) {
992  int i;
993  for (i = 0; src[i] && src[i] != ch; i++) {
994  dst[i] = src[i];
995  }
996  dst[i] = '\0';
997  return i;
998 }
999 
1006 RZ_API char *rz_str_ndup(RZ_NULLABLE const char *ptr, int len) {
1007  if (!ptr || len < 0) {
1008  return NULL;
1009  }
1010  const size_t str_len = rz_str_nlen(ptr, len);
1011  char *out = malloc(str_len + 1);
1012  if (!out) {
1013  return NULL;
1014  }
1015  memcpy(out, ptr, str_len);
1016  out[str_len] = 0;
1017  return out;
1018 }
1019 
1020 // TODO: deprecate?
1021 RZ_API char *rz_str_dup(char *ptr, const char *string) {
1022  char *str = rz_str_new(string);
1023  free(ptr); // in case ptr == string
1024  return str;
1025 }
1026 
1027 RZ_API char *rz_str_prepend(char *ptr, const char *string) {
1028  int slen, plen;
1029  if (!ptr) {
1030  return strdup(string);
1031  }
1032  plen = strlen(ptr);
1033  slen = strlen(string);
1034  ptr = realloc(ptr, slen + plen + 1);
1035  if (!ptr) {
1036  return NULL;
1037  }
1038  memmove(ptr + slen, ptr, plen + 1);
1039  memmove(ptr, string, slen);
1040  return ptr;
1041 }
1042 
1043 RZ_API char *rz_str_appendlen(char *ptr, const char *string, int slen) {
1044  char *msg = rz_str_newlen(string, slen);
1045  char *ret = rz_str_append(ptr, msg);
1046  free(msg);
1047  return ret;
1048 }
1049 
1050 RZ_API char *rz_str_append_owned(char *ptr, char *string) {
1051  if (!ptr) {
1052  return string;
1053  }
1054  char *r = rz_str_append(ptr, string);
1055  free(string);
1056  return r;
1057 }
1058 
1059 /*
1060  * first argument must be allocated
1061  * return: the pointer ptr resized to string size.
1062  */
1063 RZ_API char *rz_str_append(char *ptr, const char *string) {
1064  if (string && !ptr) {
1065  return strdup(string);
1066  }
1067  if (RZ_STR_ISEMPTY(string)) {
1068  return ptr;
1069  }
1070  int plen = strlen(ptr);
1071  int slen = strlen(string);
1072  char *newptr = realloc(ptr, slen + plen + 1);
1073  if (!newptr) {
1074  free(ptr);
1075  return NULL;
1076  }
1077  ptr = newptr;
1078  memcpy(ptr + plen, string, slen + 1);
1079  return ptr;
1080 }
1081 
1082 RZ_API char *rz_str_appendf(char *ptr, const char *fmt, ...) {
1084  va_list ap, ap2;
1085 
1086  va_start(ap, fmt);
1087  if (!strchr(fmt, '%')) {
1088  va_end(ap);
1089  return rz_str_append(ptr, fmt);
1090  }
1091  va_copy(ap2, ap);
1092  int ret = vsnprintf(NULL, 0, fmt, ap2);
1093  ret++;
1094  char *p = calloc(1, ret);
1095  if (p) {
1096  (void)vsnprintf(p, ret, fmt, ap);
1097  ptr = rz_str_append(ptr, p);
1098  free(p);
1099  }
1100  va_end(ap2);
1101  va_end(ap);
1102  return ptr;
1103 }
1104 
1105 RZ_API char *rz_str_appendch(char *x, char y) {
1106  char b[2] = { y, 0 };
1107  return rz_str_append(x, b);
1108 }
1109 
1110 RZ_API char *rz_str_replace(char *str, const char *key, const char *val, int g) {
1111  if (g == 'i') {
1112  return rz_str_replace_icase(str, key, val, g, true);
1113  }
1115 
1116  int off, i, slen;
1117  char *newstr, *p = str;
1118  int klen = strlen(key);
1119  int vlen = strlen(val);
1120  if (klen == 1 && vlen < 2) {
1122  return str;
1123  }
1124  if (klen == vlen && !strcmp(key, val)) {
1125  return str;
1126  }
1127  slen = strlen(str);
1128  char *q = str;
1129  for (;;) {
1130  p = strstr(q, key);
1131  if (!p) {
1132  break;
1133  }
1134  off = (int)(size_t)(p - str);
1135  if (vlen != klen) {
1136  int tlen = slen - (off + klen);
1137  slen += vlen - klen;
1138  if (vlen > klen) {
1139  newstr = realloc(str, slen + 1);
1140  if (!newstr) {
1141  eprintf("realloc fail\n");
1142  RZ_FREE(str);
1143  break;
1144  }
1145  str = newstr;
1146  }
1147  p = str + off;
1148  memmove(p + vlen, p + klen, tlen + 1);
1149  }
1150  memcpy(p, val, vlen);
1151  i = off + vlen;
1152  q = str + i;
1153  if (!g) {
1154  break;
1155  }
1156  }
1157  return str;
1158 }
1159 
1160 RZ_API char *rz_str_replace_icase(char *str, const char *key, const char *val, int g, int keep_case) {
1162 
1163  int off, i, klen, vlen, slen;
1164  char *newstr, *p = str;
1165  klen = strlen(key);
1166  vlen = strlen(val);
1167 
1168  slen = strlen(str);
1169  for (i = 0; i < slen;) {
1170  p = (char *)rz_str_casestr(str + i, key);
1171  if (!p) {
1172  break;
1173  }
1174  off = (int)(size_t)(p - str);
1175  if (vlen != klen) {
1176  int tlen = slen - (off + klen);
1177  slen += vlen - klen;
1178  if (vlen > klen) {
1179  newstr = realloc(str, slen + 1);
1180  if (!newstr) {
1181  goto alloc_fail;
1182  }
1183  str = newstr;
1184  }
1185  p = str + off;
1186  memmove(p + vlen, p + klen, tlen + 1);
1187  }
1188 
1189  if (keep_case) {
1190  char *tmp_val = strdup(val);
1191  char *str_case = rz_str_ndup(p, klen);
1192  if (!tmp_val || !str_case) {
1193  free(tmp_val);
1194  free(str_case);
1195  goto alloc_fail;
1196  }
1197  tmp_val = rz_str_replace_icase(tmp_val, key, str_case, 0, 0);
1198  free(str_case);
1199  if (!tmp_val) {
1200  goto alloc_fail;
1201  }
1202  memcpy(p, tmp_val, vlen);
1203  free(tmp_val);
1204  } else {
1205  memcpy(p, val, vlen);
1206  }
1207 
1208  i = off + vlen;
1209  if (!g) {
1210  break;
1211  }
1212  }
1213  return str;
1214 
1215 alloc_fail:
1216  eprintf("alloc fail\n");
1217  free(str);
1218  return NULL;
1219 }
1220 
1221 /* replace the key in str with val.
1222  *
1223  * str - input string
1224  * clean - input string cleaned of ANSI chars
1225  * thunk - array of integers that map each char of the clean string into the
1226  * position in the str string
1227  * clen - number of elements in thunk
1228  * key - string to find in the clean string
1229  * val - string that replaces key in the str string
1230  * g - if true, replace all occurrences of key
1231  *
1232  * It returns a pointer to the modified string */
1233 RZ_API char *rz_str_replace_thunked(char *str, char *clean, int *thunk, int clen,
1234  const char *key, const char *val, int g) {
1235  int i, klen, vlen, slen, delta = 0, bias;
1236  char *newstr, *scnd, *p = clean, *str_p;
1237 
1238  if (!str || !key || !val || !clean || !thunk) {
1239  return NULL;
1240  }
1241  klen = strlen(key);
1242  vlen = strlen(val);
1243  if (klen == vlen && !strcmp(key, val)) {
1244  return str;
1245  }
1246  slen = strlen(str) + 1;
1247 
1248  for (i = 0; i < clen;) {
1249  p = (char *)rz_mem_mem(
1250  (const ut8 *)clean + i, clen - i,
1251  (const ut8 *)key, klen);
1252  if (!p) {
1253  break;
1254  }
1255  i = (int)(size_t)(p - clean);
1256  /* as the original string changes size during replacement
1257  * we need delta to keep track of it*/
1258  str_p = str + thunk[i] + delta;
1259 
1260  int newo = thunk[i + klen] - thunk[i];
1261  rz_str_ansi_filter(str_p, NULL, NULL, newo);
1262  scnd = strdup(str_p + newo);
1263  bias = vlen - newo;
1264 
1265  slen += bias;
1266  // HACK: this 32 avoids overwrites
1267  newstr = realloc(str, slen + klen);
1268  if (!newstr) {
1269  eprintf("realloc fail\n");
1270  RZ_FREE(str);
1271  free(scnd);
1272  break;
1273  }
1274  str = newstr;
1275  str_p = str + thunk[i] + delta;
1276  memcpy(str_p, val, vlen);
1277  memcpy(str_p + vlen, scnd, strlen(scnd) + 1);
1278  i += klen;
1279  delta += bias;
1280  free(scnd);
1281  if (!g) {
1282  break;
1283  }
1284  }
1285  return str;
1286 }
1287 
1288 RZ_API char *rz_str_replace_in(char *str, ut32 sz, const char *key, const char *val, int g) {
1289  if (!str || !key || !val) {
1290  return NULL;
1291  }
1292  char *heaped = rz_str_replace(strdup(str), key, val, g);
1293  if (heaped) {
1294  strncpy(str, heaped, sz);
1295  free(heaped);
1296  }
1297  return str;
1298 }
1299 
1301  unsigned char ch = 0, ch2 = 0;
1302  int err = 0;
1303  int i;
1304 
1305  for (i = 0; buf[i]; i++) {
1306  if (buf[i] != '\\') {
1307  continue;
1308  }
1309  int esc_seq_len = 2;
1310  switch (buf[i + 1]) {
1311  case '\\':
1312  case '?':
1313  case '$':
1314  buf[i] = buf[i + 1];
1315  break;
1316  case 'e':
1317  buf[i] = 0x1b;
1318  break;
1319  case 'r':
1320  buf[i] = 0x0d;
1321  break;
1322  case 'n':
1323  buf[i] = 0x0a;
1324  break;
1325  case 'a':
1326  buf[i] = 0x07;
1327  break;
1328  case 'b':
1329  buf[i] = 0x08;
1330  break;
1331  case 't':
1332  buf[i] = 0x09;
1333  break;
1334  case 'v':
1335  buf[i] = 0x0b;
1336  break;
1337  case 'f':
1338  buf[i] = 0x0c;
1339  break;
1340  case 'x':
1341  err = ch2 = ch = 0;
1342  if (!buf[i + 2] || !buf[i + 3]) {
1343  eprintf("Unexpected end of string.\n");
1344  return 0;
1345  }
1346  err |= rz_hex_to_byte(&ch, buf[i + 2]);
1347  err |= rz_hex_to_byte(&ch2, buf[i + 3]);
1348  if (err) {
1349  eprintf("Error: Non-hexadecimal chars in input.\n");
1350  return 0; // -1?
1351  }
1352  buf[i] = (ch << 4) + ch2;
1353  esc_seq_len = 4;
1354  break;
1355  case '\0':
1356  buf[i] = '\0';
1357  return i;
1358  default:
1359  if (IS_OCTAL(buf[i + 1])) {
1360  int num_digits = 1;
1361  buf[i] = buf[i + 1] - '0';
1362  if (IS_OCTAL(buf[i + 2])) {
1363  num_digits++;
1364  buf[i] = (ut8)buf[i] * 8 + (buf[i + 2] - '0');
1365  if (IS_OCTAL(buf[i + 3])) {
1366  num_digits++;
1367  buf[i] = (ut8)buf[i] * 8 + (buf[i + 3] - '0');
1368  }
1369  }
1370  esc_seq_len = 1 + num_digits;
1371  } else {
1372  buf[i] = buf[i + 1];
1373  }
1374  break;
1375  }
1376  memmove(buf + i + 1, buf + i + esc_seq_len, strlen(buf + i + esc_seq_len) + 1);
1377  }
1378  return i;
1379 }
1380 
1381 RZ_API void rz_str_sanitize(char *c) {
1382  char *d = c;
1383  if (d) {
1384  for (; *d; c++, d++) {
1385  switch (*d) {
1386  case '`':
1387  case '$':
1388  case '{':
1389  case '}':
1390  case '~':
1391  case '|':
1392  case ';':
1393  case '#':
1394  case '@':
1395  case '&':
1396  case '<':
1397  case '>':
1398  *c = '_';
1399  continue;
1400  }
1401  }
1402  }
1403 }
1404 
1405 RZ_API char *rz_str_sanitize_sdb_key(const char *s) {
1406  if (!s || !*s) {
1407  return NULL;
1408  }
1409  size_t len = strlen(s);
1410  char *ret = malloc(len + 1);
1411  if (!ret) {
1412  return NULL;
1413  }
1414  char *cur = ret;
1415  while (len > 0) {
1416  char c = *s;
1417  if (!(c >= 'a' && c <= 'z') && !(c >= 'A' && c <= 'Z') && !(c >= '0' && c <= '9') && c != '_' && c != ':') {
1418  c = '_';
1419  }
1420  *cur = c;
1421  s++;
1422  cur++;
1423  len--;
1424  }
1425  *cur = '\0';
1426  return ret;
1427 }
1428 
1436 RZ_API void rz_str_byte_escape(const char *p, char **dst, RzStrEscOptions *opt) {
1437  char *q = *dst;
1438  switch (*p) {
1439  case '\n':
1440  *q++ = '\\';
1441  *q++ = opt->dot_nl ? 'l' : 'n';
1442  break;
1443  case '\r':
1444  *q++ = '\\';
1445  *q++ = 'r';
1446  break;
1447  case '\\':
1448  if (opt->esc_bslash) {
1449  *q++ = '\\';
1450  }
1451  *q++ = '\\';
1452  break;
1453  case '\t':
1454  *q++ = '\\';
1455  *q++ = 't';
1456  break;
1457  case '"':
1458  if (opt->esc_double_quotes) {
1459  *q++ = '\\';
1460  }
1461  *q++ = '"';
1462  break;
1463  case '\f':
1464  *q++ = '\\';
1465  *q++ = 'f';
1466  break;
1467  case '\b':
1468  *q++ = '\\';
1469  *q++ = 'b';
1470  break;
1471  case '\v':
1472  *q++ = '\\';
1473  *q++ = 'v';
1474  break;
1475  case '\a':
1476  *q++ = '\\';
1477  *q++ = 'a';
1478  break;
1479  case '\x1b':
1480  *q++ = '\\';
1481  *q++ = 'e';
1482  break;
1483  default:
1484  /* Outside the ASCII printable range */
1485  if (!IS_PRINTABLE(*p)) {
1486  if (opt->show_asciidot) {
1487  *q++ = '.';
1488  } else {
1489  *q++ = '\\';
1490  *q++ = 'x';
1491  *q++ = "0123456789abcdef"[*p >> 4 & 0xf];
1492  *q++ = "0123456789abcdef"[*p & 0xf];
1493  }
1494  } else {
1495  *q++ = *p;
1496  }
1497  }
1498  *dst = q;
1499 }
1500 
1501 /* Internal function. dot_nl specifies whether to convert \n into the
1502  * graphiz-compatible newline \l */
1503 static RZ_OWN char *rz_str_escape_(const char *buf, bool parse_esc_seq, bool ign_esc_seq, RzStrEscOptions *opt) {
1505 
1506  /* Worst case scenario, we convert every byte to a single-char escape
1507  * (e.g. \n) if show_asciidot, or \xhh if !show_asciidot */
1508  char *new_buf = malloc(1 + strlen(buf) * (opt->show_asciidot ? 2 : 4));
1509  if (!new_buf) {
1510  return NULL;
1511  }
1512  const char *p = buf;
1513  char *q = new_buf;
1514  while (*p) {
1515  switch (*p) {
1516  case 0x1b: // ESC
1517  if (parse_esc_seq) {
1518  const char *start_seq = p;
1519  p++;
1520  /* Parse the ANSI code (only the graphic mode
1521  * set ones are supported) */
1522  if (*p == '\0') {
1523  goto out;
1524  }
1525  if (*p == '[') {
1526  for (p++; *p != 'm'; p++) {
1527  if (*p == '\0') {
1528  goto out;
1529  }
1530  }
1531  if (!ign_esc_seq) {
1532  memcpy(q, start_seq, p - start_seq + 1);
1533  q += (p - start_seq + 1);
1534  }
1535  }
1536  break;
1537  }
1538  /* fallthrough */
1539  default:
1540  rz_str_byte_escape(p, &q, opt);
1541  break;
1542  }
1543  p++;
1544  }
1545 out:
1546  *q = '\0';
1547  return new_buf;
1548 }
1549 
1552  RzStrEscOptions opt = { 0 };
1553  opt.dot_nl = false;
1554  opt.show_asciidot = false;
1555  opt.esc_bslash = true;
1556  return rz_str_escape_(buf, true, true, &opt);
1557 }
1558 
1559 // Return MUST BE surrounded by double-quotes
1560 RZ_API char *rz_str_escape_sh(const char *buf) {
1562  char *new_buf = malloc(1 + strlen(buf) * 2);
1563  if (!new_buf) {
1564  return NULL;
1565  }
1566  const char *p = buf;
1567  char *q = new_buf;
1568  while (*p) {
1569  switch (*p) {
1570 #if __UNIX__
1571  case '$':
1572  case '`':
1573 #endif
1574  case '\\':
1575  case '"':
1576  *q++ = '\\';
1577  /* FALLTHRU */
1578  default:
1579  *q++ = *p++;
1580  break;
1581  }
1582  }
1583  *q = '\0';
1584  return new_buf;
1585 }
1586 
1587 RZ_API char *rz_str_escape_dot(const char *buf) {
1588  RzStrEscOptions opt = { 0 };
1589  opt.dot_nl = true;
1590  opt.show_asciidot = false;
1591  opt.esc_bslash = true;
1592  return rz_str_escape_(buf, true, true, &opt);
1593 }
1594 
1595 RZ_API char *rz_str_escape_8bit(const char *buf, bool colors, RzStrEscOptions *opt) {
1596  return rz_str_escape_(buf, colors, !colors, opt);
1597 }
1598 
1599 static char *rz_str_escape_utf(const char *buf, int buf_size, RzStrEnc enc, bool show_asciidot, bool esc_bslash, bool esc_double_quotes, bool keep_printable) {
1600  char *new_buf, *q;
1601  const char *p, *end;
1602  RzRune ch;
1603  int i, len, ch_bytes;
1604 
1605  if (!buf) {
1606  return NULL;
1607  }
1608  switch (enc) {
1609  case RZ_STRING_ENC_UTF16LE:
1610  case RZ_STRING_ENC_UTF16BE:
1611  case RZ_STRING_ENC_UTF32LE:
1612  case RZ_STRING_ENC_UTF32BE:
1613  if (buf_size < 0) {
1614  return NULL;
1615  }
1616  if (enc == RZ_STRING_ENC_UTF16LE || enc == RZ_STRING_ENC_UTF16BE) {
1617  end = (char *)rz_mem_mem_aligned((ut8 *)buf, buf_size, (ut8 *)"\0\0", 2, 2);
1618  } else {
1619  end = (char *)rz_mem_mem_aligned((ut8 *)buf, buf_size, (ut8 *)"\0\0\0\0", 4, 4);
1620  }
1621  if (!end) {
1622  end = buf + buf_size - 1; /* TODO: handle overlong strings properly */
1623  }
1624  len = end - buf;
1625  break;
1626  default:
1627  len = strlen(buf);
1628  end = buf + len;
1629  }
1630  /* Worst case scenario, we convert every byte to \xhh */
1631  new_buf = malloc(1 + (len * 4));
1632  if (!new_buf) {
1633  return NULL;
1634  }
1635  p = buf;
1636  q = new_buf;
1637  while (p < end) {
1638  switch (enc) {
1639  case RZ_STRING_ENC_UTF16LE:
1640  case RZ_STRING_ENC_UTF16BE:
1641  case RZ_STRING_ENC_UTF32LE:
1642  case RZ_STRING_ENC_UTF32BE:
1643  if (enc == RZ_STRING_ENC_UTF16LE || enc == RZ_STRING_ENC_UTF16BE) {
1644  ch_bytes = rz_utf16_decode((ut8 *)p, end - p, &ch, enc == RZ_STRING_ENC_UTF16BE);
1645  } else {
1646  ch_bytes = rz_utf32_decode((ut8 *)p, end - p, &ch, enc == RZ_STRING_ENC_UTF32BE);
1647  }
1648  if (ch_bytes == 0) {
1649  p++;
1650  continue;
1651  }
1652  break;
1653  default:
1654  ch_bytes = rz_utf8_decode((ut8 *)p, end - p, &ch);
1655  if (ch_bytes == 0) {
1656  ch_bytes = 1;
1657  }
1658  }
1659  if (show_asciidot && !IS_PRINTABLE(ch)) {
1660  *q++ = '.';
1661  } else if (ch_bytes > 1) {
1662  if (keep_printable) {
1663  q += rz_utf8_encode((ut8 *)q, ch);
1664  } else {
1665  *q++ = '\\';
1666  *q++ = ch_bytes == 4 ? 'U' : 'u';
1667  for (i = ch_bytes == 4 ? 6 : 2; i >= 0; i -= 2) {
1668  *q++ = "0123456789abcdef"[ch >> 4 * (i + 1) & 0xf];
1669  *q++ = "0123456789abcdef"[ch >> 4 * i & 0xf];
1670  }
1671  }
1672  } else {
1673  int offset = enc == RZ_STRING_ENC_UTF16BE ? 1 : enc == RZ_STRING_ENC_UTF32BE ? 3
1674  : 0;
1675  RzStrEscOptions opt = { 0 };
1676  opt.dot_nl = false;
1677  opt.show_asciidot = false;
1678  opt.esc_bslash = esc_bslash;
1679  opt.esc_double_quotes = esc_double_quotes;
1680  rz_str_byte_escape(p + offset, &q, &opt);
1681  }
1682  switch (enc) {
1683  case RZ_STRING_ENC_UTF16LE:
1684  case RZ_STRING_ENC_UTF16BE:
1685  p += ch_bytes < 2 ? 2 : ch_bytes;
1686  break;
1687  case RZ_STRING_ENC_UTF32LE:
1688  case RZ_STRING_ENC_UTF32BE:
1689  p += 4;
1690  break;
1691  default:
1692  p += ch_bytes;
1693  }
1694  }
1695  *q = '\0';
1696  return new_buf;
1697 }
1698 
1699 RZ_API char *rz_str_escape_utf8(const char *buf, RzStrEscOptions *opt) {
1700  return rz_str_escape_utf(buf, -1, RZ_STRING_ENC_UTF8, opt->show_asciidot, opt->esc_bslash, opt->esc_double_quotes, false);
1701 }
1702 
1705 }
1706 
1709 }
1710 
1713 }
1714 
1717 }
1718 
1721 }
1722 
1723 static char *escape_utf8_for_json(const char *buf, int buf_size, bool mutf8) {
1724  char *new_buf, *q;
1725  const ut8 *p, *end;
1726  RzRune ch;
1727  int i, len, ch_bytes;
1728 
1729  if (!buf) {
1730  return NULL;
1731  }
1732  len = buf_size < 0 ? strlen(buf) : buf_size;
1733  end = (const ut8 *)buf + len;
1734  /* Worst case scenario, we convert every byte to \u00hh */
1735  new_buf = malloc(1 + (len * 6));
1736  if (!new_buf) {
1737  return NULL;
1738  }
1739  p = (const ut8 *)buf;
1740  q = new_buf;
1741  while (p < end) {
1742  ptrdiff_t bytes_left = end - p;
1743  ch_bytes = mutf8 ? rz_mutf8_decode(p, bytes_left, &ch) : rz_utf8_decode(p, bytes_left, &ch);
1744  if (ch_bytes == 1) {
1745  switch (*p) {
1746  case '\n':
1747  *q++ = '\\';
1748  *q++ = 'n';
1749  break;
1750  case '\r':
1751  *q++ = '\\';
1752  *q++ = 'r';
1753  break;
1754  case '\\':
1755  *q++ = '\\';
1756  *q++ = '\\';
1757  break;
1758  case '\t':
1759  *q++ = '\\';
1760  *q++ = 't';
1761  break;
1762  case '"':
1763  *q++ = '\\';
1764  *q++ = '"';
1765  break;
1766  case '\f':
1767  *q++ = '\\';
1768  *q++ = 'f';
1769  break;
1770  case '\b':
1771  *q++ = '\\';
1772  *q++ = 'b';
1773  break;
1774  default:
1775  if (!IS_PRINTABLE(*p)) {
1776  *q++ = '\\';
1777  *q++ = 'u';
1778  *q++ = '0';
1779  *q++ = '0';
1780  *q++ = "0123456789abcdef"[*p >> 4 & 0xf];
1781  *q++ = "0123456789abcdef"[*p & 0xf];
1782  } else {
1783  *q++ = *p;
1784  }
1785  }
1786  } else if (ch_bytes == 4) {
1787  if (rz_rune_is_printable(ch)) {
1788  // Assumes buf is UTF8-encoded
1789  for (i = 0; i < ch_bytes; i++) {
1790  *q++ = *(p + i);
1791  }
1792  } else {
1793  RzRune high, low;
1794  ch -= 0x10000;
1795  high = 0xd800 + (ch >> 10 & 0x3ff);
1796  low = 0xdc00 + (ch & 0x3ff);
1797  *q++ = '\\';
1798  *q++ = 'u';
1799  for (i = 2; i >= 0; i -= 2) {
1800  *q++ = "0123456789abcdef"[high >> 4 * (i + 1) & 0xf];
1801  *q++ = "0123456789abcdef"[high >> 4 * i & 0xf];
1802  }
1803  *q++ = '\\';
1804  *q++ = 'u';
1805  for (i = 2; i >= 0; i -= 2) {
1806  *q++ = "0123456789abcdef"[low >> 4 * (i + 1) & 0xf];
1807  *q++ = "0123456789abcdef"[low >> 4 * i & 0xf];
1808  }
1809  }
1810  } else if (ch_bytes > 1) {
1811  if (rz_rune_is_printable(ch)) {
1812  // Assumes buf is UTF8-encoded
1813  for (i = 0; i < ch_bytes; i++) {
1814  *q++ = *(p + i);
1815  }
1816  } else {
1817  *q++ = '\\';
1818  *q++ = 'u';
1819  for (i = 2; i >= 0; i -= 2) {
1820  *q++ = "0123456789abcdef"[ch >> 4 * (i + 1) & 0xf];
1821  *q++ = "0123456789abcdef"[ch >> 4 * i & 0xf];
1822  }
1823  }
1824  } else { // ch_bytes == 0
1825  // invalid utf-8
1826  ch_bytes = 1;
1827  }
1828  p += ch_bytes;
1829  }
1830  *q = '\0';
1831  return new_buf;
1832 }
1833 
1835  return escape_utf8_for_json(buf, buf_size, false);
1836 }
1837 
1839  return escape_utf8_for_json(buf, buf_size, true);
1840 }
1841 
1842 // http://daviddeley.com/autohotkey/parameters/parameters.htm#WINCRULES
1843 // https://docs.microsoft.com/en-us/cpp/cpp/main-function-command-line-args?redirectedfrom=MSDN&view=vs-2019#parsing-c-command-line-arguments
1844 RZ_API char *rz_str_format_msvc_argv(size_t argc, const char **argv) {
1845  RzStrBuf sb;
1846  rz_strbuf_init(&sb);
1847 
1848  size_t i;
1849  for (i = 0; i < argc; i++) {
1850  if (i > 0) {
1851  rz_strbuf_append(&sb, " ");
1852  }
1853  const char *arg = argv[i];
1854  bool must_escape = strchr(arg, '\"') != NULL;
1855  bool must_quote = strpbrk(arg, " \t") != NULL || !*arg;
1856  if (!must_escape && must_quote && *arg && arg[strlen(arg) - 1] == '\\') {
1857  // if the last char is a bs and we would quote it, we must also escape
1858  must_escape = true;
1859  }
1860  if (must_quote) {
1861  rz_strbuf_append(&sb, "\"");
1862  }
1863  if (must_escape) {
1864  size_t bs_count = 0; // backslash counter
1865  for (; *arg; arg++) {
1866  switch (*arg) {
1867  case '\"':
1868  for (; bs_count; bs_count--) {
1869  // backslashes must be escaped iff they precede a "
1870  // so just duplicate the number of backslashes already printed
1871  rz_strbuf_append(&sb, "\\");
1872  }
1873  rz_strbuf_append(&sb, "\\\"");
1874  break;
1875  case '\\':
1876  bs_count++;
1877  rz_strbuf_append(&sb, "\\");
1878  break;
1879  default:
1880  bs_count = 0;
1881  rz_strbuf_append_n(&sb, arg, 1);
1882  break;
1883  }
1884  }
1885  if (must_quote) {
1886  // there will be a quote after this so we have to escape bs here as well
1887  for (; bs_count; bs_count--) {
1888  rz_strbuf_append(&sb, "\\");
1889  }
1890  }
1891  } else {
1892  rz_strbuf_append(&sb, arg);
1893  }
1894  if (must_quote) {
1895  rz_strbuf_append(&sb, "\"");
1896  }
1897  }
1898 
1899  return rz_strbuf_drain_nofree(&sb);
1900 }
1901 
1902 static size_t __str_ansi_length(char const *str) {
1903  size_t i = 1;
1904  if (str[0] == 0x1b) {
1905  if (str[1] == '[') {
1906  i++;
1907  while (str[i] && str[i] != 'J' && str[i] != 'm' && str[i] != 'H' && str[i] != 'K') {
1908  i++;
1909  }
1910  } else if (str[1] == '#') {
1911  while (str[i] && str[i] != 'q') {
1912  i++;
1913  }
1914  }
1915  if (str[i]) {
1916  i++;
1917  }
1918  }
1919  return i;
1920 }
1921 
1922 /* ansi helpers */
1923 RZ_API size_t rz_str_ansi_nlen(const char *str, size_t slen) {
1924  size_t i = 0, len = 0;
1925  if (slen > 0) {
1926  while (str[i] && i < slen) {
1927  size_t chlen = __str_ansi_length(str + i);
1928  if (chlen == 1) {
1929  len++;
1930  }
1931  i += chlen;
1932  }
1933  return len > 0 ? len : 1;
1934  }
1935  while (str[i]) {
1936  size_t chlen = __str_ansi_length(str + i);
1937  if (chlen == 1) {
1938  len++;
1939  }
1940  i += chlen;
1941  }
1942  return len > 0 ? len : 1;
1943 }
1944 
1945 RZ_API size_t rz_str_ansi_len(const char *str) {
1946  return rz_str_ansi_nlen(str, 0);
1947 }
1948 
1949 RZ_API size_t rz_str_nlen(const char *str, size_t n) {
1951 #if HAVE_STRNLEN
1952  return strnlen(str, n);
1953 #else
1954  size_t len = 0;
1955  while (*str && n) {
1956  len++;
1957  str++;
1958  n--;
1959  }
1960  return len;
1961 #endif
1962 }
1963 
1964 // to handle wide string as well
1965 // XXX can be error prone
1966 RZ_API size_t rz_str_nlen_w(const char *str, int n) {
1967  size_t len = 0;
1968  if (str) {
1969  while (*str && n > 0) {
1970  len++;
1971  str++;
1972  if (!*str) {
1973  // handle wide strings
1974  // xx00yy00bb00
1975  if (n - 2 > 0) {
1976  if (str[2]) {
1977  break;
1978  }
1979  }
1980  str++;
1981  }
1982  n--;
1983  }
1984  }
1985  return len;
1986 }
1987 
1988 RZ_API bool rz_str_is_ascii(const char *str) {
1989  const ut8 *ptr;
1990  for (ptr = (const ut8 *)str; *ptr; ptr++) {
1991  if (*ptr > 0x7f) {
1992  return false;
1993  }
1994  }
1995  return true;
1996 }
1997 
2005  rz_return_val_if_fail(str, false);
2006  for (const char *ptr = str; *ptr != '\0'; ptr++) {
2007  if (!isspace(*ptr)) {
2008  return false;
2009  }
2010  }
2011  return true;
2012 }
2013 
2024  rz_return_val_if_fail(str, false);
2025  const ut8 *ptr = (const ut8 *)str;
2026  size_t len = strlen(str);
2027  while (len) {
2028  int bytes = rz_utf8_decode(ptr, len, NULL);
2029  if (!bytes) {
2030  return false;
2031  }
2032  len -= bytes;
2033  ptr += bytes;
2034  }
2035  return true;
2036 }
2037 
2038 RZ_API bool rz_str_is_printable(const char *str) {
2039  while (*str) {
2040  int ulen = rz_utf8_decode((const ut8 *)str, strlen(str), NULL);
2041  if (ulen > 1) {
2042  str += ulen;
2043  continue;
2044  }
2045  if (!IS_PRINTABLE(*str)) {
2046  return false;
2047  }
2048  str++;
2049  }
2050  return true;
2051 }
2052 
2053 RZ_API bool rz_str_is_printable_limited(const char *str, int size) {
2054  while (size > 0 && *str) {
2055  int ulen = rz_utf8_decode((const ut8 *)str, strlen(str), NULL);
2056  if (ulen > 1) {
2057  str += ulen;
2058  continue;
2059  }
2060  if (!IS_PRINTABLE(*str)) {
2061  return false;
2062  }
2063  str++;
2064  size--;
2065  }
2066  return true;
2067 }
2068 
2070  while (*str) {
2071  int ulen = rz_utf8_decode((const ut8 *)str, strlen(str), NULL);
2072  if (ulen > 1) {
2073  str += ulen;
2074  continue;
2075  }
2076  if (!IS_PRINTABLE(*str)) {
2077  if (*str != '\r' && *str != '\n' && *str != '\t') {
2078  return false;
2079  }
2080  }
2081  str++;
2082  }
2083  return true;
2084 }
2085 
2086 // Length in chars of a wide string (find better name?)
2087 RZ_API size_t rz_wstr_clen(const char *s) {
2088  size_t len = 0;
2089  if (!*s++) {
2090  return 0;
2091  }
2092  while (*s++ || *s++) {
2093  len++;
2094  }
2095  return len + 1;
2096 }
2097 
2098 RZ_API const char *rz_str_ansi_chrn(const char *str, size_t n) {
2099  int len, i, li;
2100  for (li = i = len = 0; str[i] && (n != len); i++) {
2101  size_t chlen = __str_ansi_length(str + i);
2102  if (chlen > 1) {
2103  i += chlen - 1;
2104  } else {
2105  if ((str[i] & 0xc0) != 0x80) {
2106  len++;
2107  }
2108  li = i;
2109  }
2110  }
2111  return str + li;
2112 }
2113 
2114 /*
2115  * filter out ansi CSI.
2116  * str - input string,
2117  * out - if not NULL write a pointer to the original string there,
2118  * cposs - if not NULL write a pointer to thunk array there
2119  * (*cposs)[i] is the offset of the out[i] in str
2120  * len - length of str
2121  *
2122  * it returns the number of normal characters found in str
2123  */
2124 RZ_API int rz_str_ansi_filter(char *str, char **out, int **cposs, int len) {
2125  int i, j, *cps;
2126 
2127  if (len == 0) {
2128  return 0;
2129  }
2130  if (len < 0) {
2131  len = strlen(str);
2132  }
2133  char *tmp = malloc(len + 1);
2134  if (!tmp) {
2135  return -1;
2136  }
2137  memcpy(tmp, str, len + 1);
2138  cps = calloc(len + 1, sizeof(int));
2139  if (!cps) {
2140  free(tmp);
2141  return -1;
2142  }
2143 
2144  for (i = j = 0; i < len; i++) {
2145  if (tmp[i] == 0x1b) {
2146  size_t chlen = __str_ansi_length(str + i);
2147  if (chlen > 1) {
2148  i += chlen;
2149  i--;
2150  }
2151  } else {
2152  str[j] = tmp[i];
2153  cps[j] = i;
2154  j++;
2155  }
2156  }
2157  str[j] = tmp[i];
2158 
2159  if (out) {
2160  *out = tmp;
2161  } else {
2162  free(tmp);
2163  }
2164 
2165  if (cposs) {
2166  *cposs = cps;
2167  } else {
2168  free(cps);
2169  }
2170 
2171  return j;
2172 }
2173 
2174 RZ_API char *rz_str_ansi_crop(const char *str, ut32 x, ut32 y, ut32 x2, ut32 y2) {
2175  char *r, *rz_end, *ret;
2176  const char *s, *s_start;
2177  size_t rz_len, str_len = 0, nr_of_lines = 0;
2178  ut32 ch = 0, cw = 0;
2179  if (x2 <= x || y2 <= y || !str) {
2180  return strdup("");
2181  }
2182  s = s_start = str;
2183  while (*s) {
2184  str_len++;
2185  if (*s == '\n') {
2186  nr_of_lines++;
2187  }
2188  s++;
2189  }
2190  rz_len = str_len + nr_of_lines * strlen(Color_RESET) + 1;
2191  r = ret = malloc(rz_len);
2192  if (!r) {
2193  return NULL;
2194  }
2195  rz_end = r + rz_len;
2196  while (*str) {
2197  /* crop height */
2198  if (ch >= y2) {
2199  r--;
2200  break;
2201  }
2202  if (*str == '\n') {
2203  if (ch >= y && ch < y2) {
2204  const char *reset = Color_RESET "\n";
2205  if (strlen(reset) < (rz_end - r)) {
2206  const int reset_length = strlen(reset);
2207  memcpy(r, reset, reset_length + 1);
2208  r += reset_length;
2209  }
2210  }
2211  str++;
2212  ch++;
2213  cw = 0;
2214  } else {
2215  if (ch >= y && ch < y2) {
2216  if ((*str & 0xc0) == 0x80) {
2217  if (cw > x) {
2218  *r++ = *str++;
2219  } else {
2220  str++;
2221  }
2222  continue;
2223  }
2224  if (rz_str_char_fullwidth(str, str_len - (str - s_start))) {
2225  cw++;
2226  if (cw == x) {
2227  *r++ = ' ';
2228  str++;
2229  continue;
2230  }
2231  }
2232  if (*str == 0x1b && *(str + 1) == '[') {
2233  const char *ptr = str;
2234  if ((rz_end - r) > 2) {
2235  /* copy 0x1b and [ */
2236  *r++ = *str++;
2237  *r++ = *str++;
2238  for (ptr = str; *ptr && *ptr != 'J' && *ptr != 'm' && *ptr != 'H'; ptr++) {
2239  *r++ = *ptr;
2240  }
2241  *r++ = *ptr++;
2242  }
2243  str = ptr;
2244  continue;
2245  } else if (cw >= x && cw < x2) {
2246  *r++ = *str;
2247  }
2248  }
2249  /* skip until newline */
2250  if (cw >= x2) {
2251  while (*str && *str != '\n') {
2252  str++;
2253  }
2254  } else {
2255  str++;
2256  }
2257  cw++;
2258  }
2259  }
2260  *r = 0;
2261  return ret;
2262 }
2263 
2264 RZ_API size_t rz_str_utf8_codepoint(const char *s, size_t left) {
2265  if ((*s & 0x80) != 0x80) {
2266  return 0;
2267  } else if ((*s & 0xe0) == 0xc0 && left >= 1) {
2268  return ((*s & 0x1f) << 6) + (*(s + 1) & 0x3f);
2269  } else if ((*s & 0xf0) == 0xe0 && left >= 2) {
2270  return ((*s & 0xf) << 12) + ((*(s + 1) & 0x3f) << 6) + (*(s + 2) & 0x3f);
2271  } else if ((*s & 0xf8) == 0xf0 && left >= 3) {
2272  return ((*s & 0x7) << 18) + ((*(s + 1) & 0x3f) << 12) + ((*(s + 2) & 0x3f) << 6) + (*(s + 3) & 0x3f);
2273  }
2274  return 0;
2275 }
2276 
2277 RZ_API bool rz_str_char_fullwidth(const char *s, size_t left) {
2278  size_t codepoint = rz_str_utf8_codepoint(s, left);
2279  return (codepoint >= 0x1100 &&
2280  (codepoint <= 0x115f || /* Hangul Jamo init. consonants */
2281  codepoint == 0x2329 || codepoint == 0x232a ||
2282  (RZ_BETWEEN(0x2e80, codepoint, 0xa4cf) && codepoint != 0x303f) || /* CJK ... Yi */
2283  RZ_BETWEEN(0xac00, codepoint, 0xd7a3) || /* Hangul Syllables */
2284  RZ_BETWEEN(0xf900, codepoint, 0xfaff) || /* CJK Compatibility Ideographs */
2285  RZ_BETWEEN(0xfe10, codepoint, 0xfe19) || /* Vertical forms */
2286  RZ_BETWEEN(0xfe30, codepoint, 0xfe6f) || /* CJK Compatibility Forms */
2287  RZ_BETWEEN(0xff00, codepoint, 0xff60) || /* Fullwidth Forms */
2288  RZ_BETWEEN(0xffe0, codepoint, 0xffe6) ||
2289  RZ_BETWEEN(0x20000, codepoint, 0x2fffd) ||
2290  RZ_BETWEEN(0x30000, codepoint, 0x3fffd)));
2291 }
2292 
2298 RZ_API size_t rz_str_utf8_charsize(const char *str) {
2300  size_t size = 0;
2301  size_t length = strlen(str);
2302  while (size < length && size < 5) {
2303  size++;
2304  if ((str[size] & 0xc0) != 0x80) {
2305  break;
2306  }
2307  }
2308  return size < 5 ? size : 0;
2309 }
2310 
2317 RZ_API size_t rz_str_utf8_charsize_prev(const char *str, int prev_len) {
2319  int pos = 0;
2320  size_t size = 0, minsize = RZ_MIN(5, prev_len);
2321  while (size < minsize) {
2322  size++;
2323  if ((str[--pos] & 0xc0) != 0x80) {
2324  break;
2325  }
2326  }
2327  return size < 5 ? size : 0;
2328 }
2329 
2335 RZ_API size_t rz_str_utf8_charsize_last(const char *str) {
2337  size_t len = strlen(str);
2338  return rz_str_utf8_charsize_prev(str + len, len);
2339 }
2340 
2342  int i;
2343  for (i = 0; i < len && str[i]; i++) {
2344  if (str[i] == '\n' || str[i] == '\r') {
2345  break;
2346  }
2347  if (!IS_PRINTABLE(str[i])) {
2348  break;
2349  }
2350  }
2351  str[i] = 0;
2352 }
2353 
2359 RZ_API void rz_str_filter(char *str) {
2360  size_t i;
2361  for (i = 0; str[i]; i++) {
2362  if (!IS_PRINTABLE(str[i])) {
2363  str[i] = '.';
2364  }
2365  }
2366 }
2367 
2368 RZ_API bool rz_str_glob(const char *str, const char *glob) {
2369  if (!glob) {
2370  return true;
2371  }
2372  char *begin = strchr(glob, '^');
2373  if (begin) {
2374  glob = ++begin;
2375  }
2376  while (*str) {
2377  if (!*glob) {
2378  return true;
2379  }
2380  switch (*glob) {
2381  case '*':
2382  if (!*++glob) {
2383  return true;
2384  }
2385  while (*str) {
2386  if (*glob == *str) {
2387  break;
2388  }
2389  str++;
2390  }
2391  break;
2392  case '$':
2393  return (*++glob == '\x00');
2394  case '?':
2395  str++;
2396  glob++;
2397  break;
2398  default:
2399  if (*glob != *str) {
2400  return false;
2401  }
2402  str++;
2403  glob++;
2404  }
2405  }
2406  while (*glob == '*') {
2407  ++glob;
2408  }
2409  return ((*glob == '$' && !*glob++) || !*glob);
2410 }
2411 
2412 // Escape the string arg so that it is parsed as a single argument by rz_str_argv
2413 RZ_API char *rz_str_arg_escape(const char *arg) {
2414  char *str;
2415  int dest_i = 0, src_i = 0;
2416  if (!arg) {
2417  return NULL;
2418  }
2419  str = malloc((2 * strlen(arg) + 1) * sizeof(char)); // Worse case when every character need to be escaped
2420  if (!str) {
2421  return NULL;
2422  }
2423  for (src_i = 0; arg[src_i] != '\0'; src_i++) {
2424  char c = arg[src_i];
2425  switch (c) {
2426  case '\'':
2427  case '"':
2428  case '\\':
2429  case ' ':
2430  str[dest_i++] = '\\';
2431  str[dest_i++] = c;
2432  break;
2433  default:
2434  str[dest_i++] = c;
2435  break;
2436  }
2437  }
2438  str[dest_i] = '\0';
2439  return realloc(str, (strlen(str) + 1) * sizeof(char));
2440 }
2441 
2442 // Unescape the string arg to its original format
2444  int dest_i = 0, src_i = 0;
2445  if (!arg) {
2446  return 0;
2447  }
2448  for (src_i = 0; arg[src_i] != '\0'; src_i++) {
2449  char c = arg[src_i];
2450  if (c == '\\') {
2451  if (arg[++src_i] == '\0') {
2452  break;
2453  }
2454  arg[dest_i++] = arg[src_i];
2455  } else {
2456  arg[dest_i++] = c;
2457  }
2458  }
2459  arg[dest_i] = '\0';
2460  return dest_i;
2461 }
2462 
2463 RZ_API char *rz_str_path_escape(const char *path) {
2464  char *str;
2465  int dest_i = 0, src_i = 0;
2466 
2467  if (!path) {
2468  return NULL;
2469  }
2470  // Worst case when every character need to be escaped
2471  str = malloc((2 * strlen(path) + 1) * sizeof(char));
2472  if (!str) {
2473  return NULL;
2474  }
2475 
2476  for (src_i = 0; path[src_i] != '\0'; src_i++) {
2477  char c = path[src_i];
2478  switch (c) {
2479  case ' ':
2480  str[dest_i++] = '\\';
2481  str[dest_i++] = c;
2482  break;
2483  default:
2484  str[dest_i++] = c;
2485  break;
2486  }
2487  }
2488 
2489  str[dest_i] = '\0';
2490  return realloc(str, (strlen(str) + 1) * sizeof(char));
2491 }
2492 
2494  int i;
2495 
2496  for (i = 0; path[i]; i++) {
2497  if (path[i] != '\\') {
2498  continue;
2499  }
2500  if (path[i + 1] == ' ') {
2501  path[i] = ' ';
2502  memmove(path + i + 1, path + i + 2, strlen(path + i + 2) + 1);
2503  }
2504  }
2505 
2506  return i;
2507 }
2508 
2509 RZ_API char **rz_str_argv(const char *cmdline, int *_argc) {
2510  int argc = 0;
2511  int argv_len = 128; // Begin with that, argv will reallocated if necessary
2512  char *args; // Working buffer for writing unescaped args
2513  int cmdline_current = 0; // Current character index in _cmdline
2514  int args_current = 0; // Current character index in args
2515  int arg_begin = 0; // Index of the first character of the current argument in args
2516 
2517  if (!cmdline) {
2518  return NULL;
2519  }
2520 
2521  char **argv = malloc(argv_len * sizeof(char *));
2522  if (!argv) {
2523  return NULL;
2524  }
2525  args = malloc(128 + strlen(cmdline) * sizeof(char)); // Unescaped args will be shorter, so strlen (cmdline) will be enough
2526  if (!args) {
2527  free(argv);
2528  return NULL;
2529  }
2530  do {
2531  // States for parsing args
2532  int escaped = 0;
2533  int singlequoted = 0;
2534  int doublequoted = 0;
2535 
2536  // Seek the beginning of next argument (skip whitespaces)
2537  while (cmdline[cmdline_current] != '\0' && IS_WHITECHAR(cmdline[cmdline_current])) {
2538  cmdline_current++;
2539  }
2540 
2541  if (cmdline[cmdline_current] == '\0') {
2542  break; // No more arguments
2543  }
2544  // Read the argument
2545  while (1) {
2546  char c = cmdline[cmdline_current];
2547  int end_of_current_arg = 0;
2548  if (escaped) {
2549  switch (c) {
2550  case '\'':
2551  case '"':
2552  case ' ':
2553  case '\\':
2554  args[args_current++] = '\\';
2555  args[args_current++] = c;
2556  break;
2557  case '\0':
2558  args[args_current++] = '\\';
2559  end_of_current_arg = 1;
2560  break;
2561  default:
2562  args[args_current++] = '\\';
2563  args[args_current++] = c;
2564  }
2565  escaped = 0;
2566  } else {
2567  switch (c) {
2568  case '\'':
2569  if (doublequoted) {
2570  args[args_current++] = c;
2571  } else {
2572  singlequoted = !singlequoted;
2573  }
2574  break;
2575  case '"':
2576  if (singlequoted) {
2577  args[args_current++] = c;
2578  } else {
2579  doublequoted = !doublequoted;
2580  }
2581  break;
2582  case '\\':
2583  escaped = 1;
2584  break;
2585  case ' ':
2586  if (singlequoted || doublequoted) {
2587  args[args_current++] = c;
2588  } else {
2589  end_of_current_arg = 1;
2590  }
2591  break;
2592  case '\0':
2593  end_of_current_arg = 1;
2594  break;
2595  default:
2596  args[args_current++] = c;
2597  }
2598  }
2599  if (end_of_current_arg) {
2600  break;
2601  }
2602  cmdline_current++;
2603  }
2604  args[args_current++] = '\0';
2605  argv[argc++] = strdup(&args[arg_begin]);
2606  if (argc >= argv_len) {
2607  argv_len *= 2;
2608  char **tmp = realloc(argv, argv_len * sizeof(char *));
2609  if (!tmp) {
2610  free(args);
2611  free(argv);
2612  return NULL;
2613  }
2614  argv = tmp;
2615  }
2616  arg_begin = args_current;
2617  } while (cmdline[cmdline_current++] != '\0');
2618  argv[argc] = NULL;
2619  char **tmp = realloc(argv, (argc + 1) * sizeof(char *));
2620  if (tmp) {
2621  argv = tmp;
2622  } else {
2623  free(argv);
2624  argv = NULL;
2625  }
2626  if (_argc) {
2627  *_argc = argc;
2628  }
2629  free(args);
2630  return argv;
2631 }
2632 
2634  int argc = 0;
2635  if (!argv) {
2636  return;
2637  }
2638  while (argv[argc]) {
2639  free(argv[argc++]);
2640  }
2641  free(argv);
2642 }
2643 
2644 RZ_API const char *rz_str_firstbut(const char *s, char ch, const char *but) {
2645  int idx, _b = 0;
2646  ut8 *b = (ut8 *)&_b;
2647  const char *isbut, *p;
2648  const int bsz = sizeof(_b) * 8;
2649  if (!but) {
2650  return strchr(s, ch);
2651  }
2652  if (strlen(but) >= bsz) {
2653  eprintf("rz_str_firstbut: but string too long\n");
2654  return NULL;
2655  }
2656  for (p = s; *p; p++) {
2657  isbut = strchr(but, *p);
2658  if (isbut) {
2659  idx = (int)(size_t)(isbut - but);
2660  _b = RZ_BIT_TOGGLE(b, idx);
2661  continue;
2662  }
2663  if (*p == ch && !_b) {
2664  return p;
2665  }
2666  }
2667  return NULL;
2668 }
2669 
2670 RZ_API const char *rz_str_lastbut(const char *s, char ch, const char *but) {
2671  int idx, _b = 0;
2672  ut8 *b = (ut8 *)&_b;
2673  const char *isbut, *p, *lp = NULL;
2674  const int bsz = sizeof(_b) * 8;
2675  if (!but) {
2676  return rz_str_lchr(s, ch);
2677  }
2678  if (strlen(but) >= bsz) {
2679  eprintf("rz_str_lastbut: but string too long\n");
2680  return NULL;
2681  }
2682  for (p = s; *p; p++) {
2683  isbut = strchr(but, *p);
2684  if (isbut) {
2685  idx = (int)(size_t)(isbut - but);
2686  _b = RZ_BIT_TOGGLE(b, idx);
2687  continue;
2688  }
2689  if (*p == ch && !_b) {
2690  lp = p;
2691  }
2692  }
2693  return lp;
2694 }
2695 
2696 // Must be merged inside strlen
2697 RZ_API size_t rz_str_len_utf8char(const char *s, int left) {
2698  size_t i = 1;
2699  while (s[i] && (!left || i < left)) {
2700  if ((s[i] & 0xc0) != 0x80) {
2701  i++;
2702  } else {
2703  break;
2704  }
2705  }
2706  return i;
2707 }
2708 
2709 RZ_API size_t rz_str_len_utf8(const char *s) {
2710  size_t i = 0, j = 0, fullwidths = 0;
2711  while (s[i]) {
2712  if ((s[i] & 0xc0) != 0x80) {
2713  j++;
2714  if (rz_str_char_fullwidth(s + i, 4)) {
2715  fullwidths++;
2716  }
2717  }
2718  i++;
2719  }
2720  return j + fullwidths;
2721 }
2722 
2723 RZ_API size_t rz_str_len_utf8_ansi(const char *str) {
2724  int i = 0, len = 0, fullwidths = 0;
2725  while (str[i]) {
2726  char ch = str[i];
2727  size_t chlen = __str_ansi_length(str + i);
2728  if (chlen > 1) {
2729  i += chlen - 1;
2730  } else if ((ch & 0xc0) != 0x80) { // utf8
2731  len++;
2732  if (rz_str_char_fullwidth(str + i, chlen)) {
2733  fullwidths++;
2734  }
2735  }
2736  i++;
2737  }
2738  return len + fullwidths;
2739 }
2740 
2741 // XXX must find across the ansi tags, as well as support utf8
2742 RZ_API const char *rz_strstr_ansi(const char *a, const char *b) {
2743  const char *ch, *p = a;
2744  do {
2745  ch = strchr(p, '\x1b');
2746  if (ch) {
2747  const char *v = rz_str_nstr(p, b, ch - p);
2748  if (v) {
2749  return v;
2750  }
2751  p = ch + __str_ansi_length(ch);
2752  }
2753  } while (ch);
2754  return strstr(p, b);
2755 }
2756 
2757 RZ_API const char *rz_str_casestr(const char *a, const char *b) {
2758  // That's a GNUism that works in many places.. but we don't want it
2759  // return strcasestr (a, b);
2760  size_t hay_len = strlen(a);
2761  size_t needle_len = strlen(b);
2762  if (!hay_len || !needle_len) {
2763  return NULL;
2764  }
2765  while (hay_len >= needle_len) {
2766  if (!rz_str_ncasecmp(a, b, needle_len)) {
2767  return (const char *)a;
2768  }
2769  a++;
2770  hay_len--;
2771  }
2772  return NULL;
2773 }
2774 
2775 RZ_API int rz_str_write(int fd, const char *b) {
2776  return write(fd, b, strlen(b));
2777 }
2778 
2779 RZ_API void rz_str_range_foreach(const char *r, RzStrRangeCallback cb, void *u) {
2780  const char *p = r;
2781  for (; *r; r++) {
2782  if (*r == ',') {
2783  cb(u, atoi(p));
2784  p = r + 1;
2785  }
2786  if (*r == '-') {
2787  if (p != r) {
2788  int from = atoi(p);
2789  int to = atoi(r + 1);
2790  for (; from <= to; from++) {
2791  cb(u, from);
2792  }
2793  } else {
2794  fprintf(stderr, "Invalid range\n");
2795  }
2796  for (r++; *r && *r != ',' && *r != '-'; r++) {
2797  ;
2798  }
2799  p = r;
2800  }
2801  }
2802  if (*p) {
2803  cb(u, atoi(p));
2804  }
2805 }
2806 
2807 RZ_API bool rz_str_range_in(const char *r, ut64 addr) {
2808  const char *p = r;
2809  if (!r) {
2810  return false;
2811  }
2812  for (; *r; r++) {
2813  if (*r == ',') {
2814  if (addr == rz_num_get(NULL, p)) {
2815  return true;
2816  }
2817  p = r + 1;
2818  }
2819  if (*r == '-') {
2820  if (p != r) {
2821  ut64 from = rz_num_get(NULL, p);
2822  ut64 to = rz_num_get(NULL, r + 1);
2823  if (addr >= from && addr <= to) {
2824  return true;
2825  }
2826  } else {
2827  fprintf(stderr, "Invalid range\n");
2828  }
2829  for (r++; *r && *r != ',' && *r != '-'; r++) {
2830  ;
2831  }
2832  p = r;
2833  }
2834  }
2835  if (*p) {
2836  if (addr == rz_num_get(NULL, p)) {
2837  return true;
2838  }
2839  }
2840  return false;
2841 }
2842 
2843 // convert from html escaped sequence "foo%20bar" to "foo bar"
2844 // TODO: find better name.. unencode? decode
2846  int n;
2847  char *d;
2848  for (d = s; *s; s++, d++) {
2849  if (*s == '%') {
2850  sscanf(s + 1, "%02x", &n);
2851  *d = n;
2852  s += 2;
2853  } else {
2854  *d = *s;
2855  }
2856  }
2857  *d = 0;
2858 }
2859 
2860 RZ_API char *rz_str_uri_encode(const char *s) {
2861  char ch[4], *d, *od;
2862  if (!s) {
2863  return NULL;
2864  }
2865  od = d = malloc(1 + (strlen(s) * 4));
2866  if (!d) {
2867  return NULL;
2868  }
2869  for (; *s; s++) {
2870  if ((*s >= '0' && *s <= '9') || (*s >= 'a' && *s <= 'z') || (*s >= 'A' && *s <= 'Z')) {
2871  *d++ = *s;
2872  } else {
2873  *d++ = '%';
2874  snprintf(ch, sizeof(ch), "%02x", 0xff & ((ut8)*s));
2875  *d++ = ch[0];
2876  *d++ = ch[1];
2877  }
2878  }
2879  *d = 0;
2880  char *trimDown = realloc(od, strlen(od) + 1); // FIT
2881  return trimDown ? trimDown : od;
2882 }
2883 
2884 RZ_API int rz_str_utf16_to_utf8(ut8 *dst, int len_dst, const ut8 *src, int len_src, bool little_endian) {
2885  ut8 *outstart = dst;
2886  ut8 *outend = dst + len_dst;
2887  ut16 *in = (ut16 *)src;
2888  ut16 *inend;
2889  ut32 c, d, inlen;
2890  ut8 *tmp;
2891  int bits;
2892 
2893  if ((len_src % 2) == 1) {
2894  len_src--;
2895  }
2896  inlen = len_src / 2;
2897  inend = in + inlen;
2898  while ((in < inend) && (dst - outstart + 5 < len_dst)) {
2899  if (little_endian) {
2900  c = *in++;
2901  } else {
2902  tmp = (ut8 *)in;
2903  c = *tmp++;
2904  if (!c && !*tmp) {
2905  break;
2906  }
2907  c = c | (((ut32)*tmp) << 8);
2908  in++;
2909  }
2910  if ((c & 0xFC00) == 0xD800) { /* surrogates */
2911  if (in >= inend) { /* (in > inend) shouldn't happens */
2912  break;
2913  }
2914  if (little_endian) {
2915  d = *in++;
2916  } else {
2917  tmp = (ut8 *)in;
2918  d = *tmp++;
2919  d = d | (((ut32)*tmp) << 8);
2920  in++;
2921  }
2922  if ((d & 0xFC00) == 0xDC00) {
2923  c &= 0x03FF;
2924  c <<= 10;
2925  c |= d & 0x03FF;
2926  c += 0x10000;
2927  } else {
2928  return -2;
2929  }
2930  }
2931 
2932  /* assertion: c is a single UTF-4 value */
2933  if (dst >= outend) {
2934  break;
2935  }
2936  if (c < 0x80) {
2937  *dst++ = c;
2938  bits = -6;
2939  } else if (c < 0x800) {
2940  *dst++ = ((c >> 6) & 0x1F) | 0xC0;
2941  bits = 0;
2942  } else if (c < 0x10000) {
2943  *dst++ = ((c >> 12) & 0x0F) | 0xE0;
2944  bits = 6;
2945  } else {
2946  *dst++ = ((c >> 18) & 0x07) | 0xF0;
2947  bits = 12;
2948  }
2949 
2950  for (; bits >= 0; bits -= 6) {
2951  if (dst >= outend) {
2952  break;
2953  }
2954  *dst++ = ((c >> bits) & 0x3F) | 0x80;
2955  }
2956  }
2957  len_dst = dst - outstart;
2958  return len_dst;
2959 }
2960 
2961 RZ_API char *rz_str_utf16_decode(const ut8 *s, int len) {
2962  int i = 0;
2963  int j = 0;
2964  char *result = NULL;
2965  int count_unicode = 0;
2966  int count_ascii = 0;
2967  int lenresult = 0;
2968  if (!s) {
2969  return NULL;
2970  }
2971  for (i = 0; i < len && (s[i] || s[i + 1]); i += 2) {
2972  if (!s[i + 1] && 0x20 <= s[i] && s[i] <= 0x7E) {
2973  ++count_ascii;
2974  } else {
2975  ++count_unicode;
2976  }
2977  }
2978  lenresult = 1 + count_ascii + count_unicode * 6; // len("\\uXXXX") = 6
2979  if (!(result = calloc(1 + count_ascii + count_unicode * 6, 1))) {
2980  return NULL;
2981  }
2982  for (i = 0; i < len && j < lenresult && (s[i] || s[i + 1]); i += 2) {
2983  if (!s[i + 1] && IS_PRINTABLE(s[i])) {
2984  result[j++] = s[i];
2985  } else {
2986  j += snprintf(&result[j], lenresult - j, "\\u%.2" HHXFMT "%.2" HHXFMT "", s[i], s[i + 1]);
2987  }
2988  }
2989  return result;
2990 }
2991 
2992 // TODO: kill this completely, it makes no sense:
2993 RZ_API char *rz_str_utf16_encode(const char *s, int len) {
2994  int i;
2995  char ch[4], *d, *od, *tmp;
2996  if (!s) {
2997  return NULL;
2998  }
2999  if (len < 0) {
3000  len = strlen(s);
3001  }
3002  if ((len * 7) + 1 < len) {
3003  return NULL;
3004  }
3005  od = d = malloc(1 + (len * 7));
3006  if (!d) {
3007  return NULL;
3008  }
3009  for (i = 0; i < len; s++, i++) {
3010  if (*s == '\\') {
3011  *d++ = '\\';
3012  *d++ = '\\';
3013  } else if (*s == '"') {
3014  *d++ = '\\';
3015  *d++ = '"';
3016  } else if ((*s >= 0x20) && (*s <= 126)) {
3017  *d++ = *s;
3018  } else {
3019  *d++ = '\\';
3020  // *d++ = '\\';
3021  *d++ = 'u';
3022  *d++ = '0';
3023  *d++ = '0';
3024  snprintf(ch, sizeof(ch), "%02x", 0xff & ((ut8)*s));
3025  *d++ = ch[0];
3026  *d++ = ch[1];
3027  }
3028  }
3029  *d = 0;
3030  tmp = realloc(od, strlen(od) + 1); // FIT
3031  if (!tmp) {
3032  free(od);
3033  return NULL;
3034  }
3035  return tmp;
3036 }
3037 
3038 RZ_API char *rz_str_prefix_all(const char *s, const char *pfx) {
3039  const char *os = s;
3040  char *p;
3041  int newlines = 1;
3042  int len = 0;
3043  int pfx_len = 0;
3044 
3045  if (!s) {
3046  return strdup(pfx);
3047  }
3048  if (!pfx) {
3049  return strdup(s);
3050  }
3051  len = strlen(s);
3052  pfx_len = strlen(pfx);
3053  for (os = s; *os; os++) {
3054  if (*os == '\n') {
3055  newlines++;
3056  }
3057  }
3058  char *o = malloc(len + (pfx_len * newlines) + 1);
3059  if (!o) {
3060  return NULL;
3061  }
3062  memcpy(o, pfx, pfx_len);
3063  for (p = o + pfx_len; *s; s++) {
3064  *p++ = *s;
3065  if (*s == '\n' && s[1]) {
3066  memcpy(p, pfx, pfx_len);
3067  p += pfx_len;
3068  }
3069  }
3070  *p = 0;
3071  return o;
3072 }
3073 
3074 #define HASCH(x) strchr(input_value, x)
3075 #define CAST (void *)(size_t)
3076 RZ_API ut8 rz_str_contains_macro(const char *input_value) {
3077  char *has_tilde = input_value ? HASCH('~') : NULL,
3078  *has_bang = input_value ? HASCH('!') : NULL,
3079  *has_brace = input_value ? CAST(HASCH('[') || HASCH(']')) : NULL,
3080  *has_paren = input_value ? CAST(HASCH('(') || HASCH(')')) : NULL,
3081  *has_cbrace = input_value ? CAST(HASCH('{') || HASCH('}')) : NULL,
3082  *has_qmark = input_value ? HASCH('?') : NULL,
3083  *has_colon = input_value ? HASCH(':') : NULL,
3084  *has_at = input_value ? strchr(input_value, '@') : NULL;
3085 
3086  return has_tilde || has_bang || has_brace || has_cbrace || has_qmark || has_paren || has_colon || has_at;
3087 }
3088 
3089 RZ_API void rz_str_truncate_cmd(char *string) {
3090  ut32 pos = 0;
3091  if (string && *string) {
3092  ut32 sz = strlen(string);
3093  for (pos = 0; pos < sz; pos++) {
3094  switch (string[pos]) {
3095  case '!':
3096  case ':':
3097  case ';':
3098  case '@':
3099  case '~':
3100  case '(':
3101  case '[':
3102  case '{':
3103  case '?':
3104  string[pos] = '\0';
3105  return;
3106  }
3107  }
3108  }
3109 }
3110 
3111 RZ_API const char *rz_str_closer_chr(const char *b, const char *s) {
3112  const char *a;
3113  while (*b) {
3114  for (a = s; *a; a++) {
3115  if (*b == *a) {
3116  return b;
3117  }
3118  }
3119  b++;
3120  }
3121  return NULL;
3122 }
3123 
3124 RZ_API int rz_str_bounds(const char *_str, int *h) {
3125  const char *str, *ptr;
3126  int W = 0, H = 0;
3127  int cw = 0;
3128 
3129  if (_str) {
3130  ptr = str = _str;
3131  while (*str) {
3132  if (*str == '\n') {
3133  H++;
3134  cw = rz_str_ansi_nlen(ptr, (size_t)(str - ptr));
3135  if (cw > W) {
3136  W = cw;
3137  }
3138  cw = 0;
3139  ptr = str + 1;
3140  }
3141  str++;
3142  cw++;
3143  }
3144  if (*str == '\n') { // skip last newline
3145  H--;
3146  }
3147  if (h) {
3148  *h = H;
3149  }
3150  }
3151  return W;
3152 }
3153 
3154 /* crop a string like it is in a rectangle with the upper-left corner at (x, y)
3155  * coordinates and the bottom-right corner at (x2, y2) coordinates. The result
3156  * is a newly allocated string, that should be deallocated by the user */
3157 RZ_API char *rz_str_crop(const char *str, unsigned int x, unsigned int y,
3158  unsigned int x2, unsigned int y2) {
3159  char *r, *ret;
3160  unsigned int ch = 0, cw = 0;
3161  if (x2 < 1 || y2 < 1 || !str) {
3162  return strdup("");
3163  }
3164  r = ret = strdup(str);
3165  while (*str) {
3166  /* crop height */
3167  if (ch >= y2) {
3168  r--;
3169  break;
3170  }
3171 
3172  if (*str == '\n') {
3173  if (ch >= y && ch < y2) {
3174  *r++ = *str;
3175  }
3176  str++;
3177  ch++;
3178  cw = 0;
3179  } else {
3180  if (ch >= y && ch < y2 && cw >= x && cw < x2) {
3181  *r++ = *str;
3182  }
3183  /* crop width */
3184  /* skip until newline */
3185  if (cw >= x2) {
3186  while (*str && *str != '\n') {
3187  str++;
3188  }
3189  } else {
3190  str++;
3191  }
3192  cw++;
3193  }
3194  }
3195  *r = 0;
3196  return ret;
3197 }
3198 
3199 RZ_API const char *rz_str_tok(const char *str1, const char b, size_t len) {
3200  const char *p = str1;
3201  size_t i = 0;
3202  if (!p || !*p) {
3203  return p;
3204  }
3205  if (len == -1) {
3206  len = strlen(str1);
3207  }
3208  for (; i < len; i++, p++) {
3209  if (*p == b) {
3210  break;
3211  }
3212  }
3213  if (i == len) {
3214  p = NULL;
3215  }
3216  return p;
3217 }
3218 
3219 RZ_API int rz_str_do_until_token(str_operation op, char *str, const char tok) {
3220  int ret;
3221  if (!str) {
3222  return -1;
3223  }
3224  if (!op) {
3225  for (ret = 0; (str[ret] != tok) && str[ret]; ret++) {
3226  // empty body
3227  }
3228  } else {
3229  for (ret = 0; (str[ret] != tok) && str[ret]; ret++) {
3230  op(str + ret);
3231  }
3232  }
3233  return ret;
3234 }
3235 
3236 RZ_API const char *rz_str_pad(const char ch, int sz) {
3237  static char pad[1024];
3238  if (sz < 0) {
3239  sz = 0;
3240  }
3241  memset(pad, ch, RZ_MIN(sz, sizeof(pad)));
3242  if (sz < sizeof(pad)) {
3243  pad[sz] = 0;
3244  }
3245  pad[sizeof(pad) - 1] = 0;
3246  return pad;
3247 }
3248 
3249 RZ_API char *rz_str_repeat(const char *ch, int sz) {
3250  int i;
3251  if (sz < 0) {
3252  sz = 0;
3253  }
3254  if (sz == 0) {
3255  return strdup("");
3256  }
3257  RzStrBuf *buf = rz_strbuf_new(ch);
3258  for (i = 1; i < sz; i++) {
3259  rz_strbuf_append(buf, ch);
3260  }
3261  return rz_strbuf_drain(buf);
3262 }
3263 
3264 RZ_API char *rz_str_between(const char *cmt, const char *prefix, const char *suffix) {
3265  char *c0, *c1;
3266  if (!cmt || !prefix || !suffix || !*cmt) {
3267  return NULL;
3268  }
3269  c0 = strstr(cmt, prefix);
3270  if (c0) {
3271  c1 = strstr(c0 + strlen(prefix), suffix);
3272  if (c1) {
3273  return rz_str_ndup(c0 + strlen(prefix), (c1 - c0 - strlen(prefix)));
3274  }
3275  }
3276  return NULL;
3277 }
3278 
3286 RZ_API bool rz_str_startswith(RZ_NONNULL const char *str, RZ_NONNULL const char *needle) {
3287  rz_return_val_if_fail(str && needle, false);
3288  if (str == needle) {
3289  return true;
3290  }
3291  return !strncmp(str, needle, strlen(needle));
3292 }
3293 
3301 RZ_API bool rz_str_startswith_icase(RZ_NONNULL const char *str, RZ_NONNULL const char *needle) {
3302  rz_return_val_if_fail(str && needle, false);
3303  if (str == needle) {
3304  return true;
3305  }
3306  return !rz_str_ncasecmp(str, needle, strlen(needle));
3307 }
3308 
3309 static bool str_endswith(RZ_NONNULL const char *str, RZ_NONNULL const char *needle, bool case_sensitive) {
3310  rz_return_val_if_fail(str && needle, false);
3311  if (!*needle) {
3312  return true;
3313  }
3314  int slen = strlen(str);
3315  int nlen = strlen(needle);
3316  if (!slen || !nlen || slen < nlen) {
3317  return false;
3318  }
3319  return case_sensitive ? !strcmp(str + (slen - nlen), needle) : !rz_str_ncasecmp(str + (slen - nlen), needle, nlen);
3320 }
3321 
3329 RZ_API bool rz_str_endswith(RZ_NONNULL const char *str, RZ_NONNULL const char *needle) {
3330  return str_endswith(str, needle, true);
3331 }
3332 
3340 RZ_API bool rz_str_endswith_icase(RZ_NONNULL const char *str, RZ_NONNULL const char *needle) {
3341  return str_endswith(str, needle, false);
3342 }
3343 
3344 static RzList *str_split_list_common(char *str, const char *c, int n, bool trim, bool dup) {
3346  RzList *lst = rz_list_newf(dup ? free : NULL);
3347  char *aux = str;
3348  int i = 0;
3349  char *e = aux;
3350  size_t clen = strlen(c);
3351  for (; e;) {
3352  e = strstr(aux, c);
3353  if (n > 0 && ++i > n) {
3354  rz_list_append(lst, dup ? strdup(aux) : aux);
3355  break;
3356  }
3357  if (e) {
3358  *e = 0;
3359  e += clen;
3360  }
3361  if (trim) {
3362  rz_str_trim(aux);
3363  }
3364  rz_list_append(lst, dup ? strdup(aux) : aux);
3365  aux = e;
3366  }
3367  return lst;
3368 }
3369 
3372  RzList *lst = rz_list_newf(dup ? free : NULL);
3373  RzRegexMatch m[1];
3374  char *aux;
3375  int i = 0;
3376  int s = 0, e = 0;
3377  int j = 0;
3378  while (rz_regex_exec(r, str + j, 1, m, 0) == 0) {
3379  if (n == i && n > 0) {
3380  break;
3381  }
3382  s = m[0].rm_so; // Match start (inclusive) in string str + j
3383  e = m[0].rm_eo; // Match end (exclusive) in string str + j
3384  if (dup) {
3385  aux = rz_str_ndup(str + j, s);
3386  } else {
3387  // Overwrite split chararcters.
3388  memset(str + j + s, 0, e - s);
3389  aux = str + j;
3390  }
3391  if (trim) {
3392  rz_str_trim(aux);
3393  }
3394  rz_list_append(lst, aux);
3395  j += e;
3396  ++i;
3397  }
3398  if (*(str + j) == 0 || (n == i && n > 0) || rz_list_length(lst) == 0) {
3399  // No token left.
3400  return lst;
3401  }
3402 
3403  if (dup) {
3404  aux = rz_str_ndup(str + j, strlen(str + j));
3405  } else {
3406  // Overwrite split chararcters.
3407  memset(str + j + s, 0, e - s);
3408  aux = str + j;
3409  }
3410  if (trim) {
3411  rz_str_trim(aux);
3412  }
3413  rz_list_append(lst, aux);
3414 
3415  return lst;
3416 }
3417 
3429 RZ_API RzList *rz_str_split_list(char *str, const char *c, int n) {
3431  return str_split_list_common(str, c, n, true, false);
3432 }
3433 
3447  RzRegex *regex = rz_regex_new(r, "e");
3448  RzList *res = str_split_list_common_regex(str, regex, n, false, false);
3449  rz_regex_free(regex);
3450  return res;
3451 }
3452 
3464 RZ_API RzList *rz_str_split_duplist(const char *_str, const char *c, bool trim) {
3465  rz_return_val_if_fail(_str && c, NULL);
3466  char *str = strdup(_str);
3467  RzList *res = str_split_list_common(str, c, 0, trim, true);
3468  free(str);
3469  return res;
3470 }
3471 
3485 RZ_API RzList *rz_str_split_duplist_n(const char *_str, const char *c, int n, bool trim) {
3486  rz_return_val_if_fail(_str && c, NULL);
3487  char *str = strdup(_str);
3488  RzList *res = str_split_list_common(str, c, n, trim, true);
3489  free(str);
3490  return res;
3491 }
3492 
3506 RZ_API RZ_OWN RzList *rz_str_split_duplist_n_regex(RZ_NONNULL const char *_str, RZ_NONNULL const char *r, int n, bool trim) {
3507  rz_return_val_if_fail(_str && r, NULL);
3508  char *str = strdup(_str);
3509  RzRegex *regex = rz_regex_new(r, "e");
3510  RzList *res = str_split_list_common_regex(str, regex, n, trim, true);
3511  free(str);
3512  rz_regex_free(regex);
3513  return res;
3514 }
3515 
3526 RZ_API size_t *rz_str_split_lines(char *str, size_t *count) {
3528  RzList *l = str_split_list_common(str, "\n", 0, false, false);
3529  if (!l) {
3530  return NULL;
3531  }
3532  size_t cnt = rz_list_length(l);
3533  size_t *res = RZ_NEWS(size_t, cnt);
3534  if (!res) {
3535  return NULL;
3536  }
3537  RzListIter *it;
3538  char *s;
3539  size_t i = 0;
3540  rz_list_foreach (l, it, s) {
3541  res[i++] = s - str;
3542  }
3543  if (count) {
3544  *count = cnt;
3545  }
3546  rz_list_free(l);
3547  return res;
3548 }
3549 
3550 RZ_API bool rz_str_isnumber(const char *str) {
3551  if (!str || (!IS_DIGIT(*str) && *str != '-')) {
3552  return false;
3553  }
3554 
3555  while (*++str) {
3556  if (!IS_DIGIT(*str)) {
3557  return false;
3558  }
3559  }
3560 
3561  return true;
3562 }
3563 
3564 /* TODO: optimize to start searching by the end of the string */
3565 RZ_API const char *rz_str_last(const char *str, const char *ch) {
3566  char *ptr, *end = NULL;
3567  if (!str || !ch) {
3568  return NULL;
3569  }
3570  do {
3571  ptr = strstr(str, ch);
3572  if (!ptr) {
3573  break;
3574  }
3575  end = ptr;
3576  str = ptr + 1;
3577  } while (true);
3578  return end;
3579 }
3580 
3581 // copies the WHOLE string but check n against non color code chars only.
3582 static int strncpy_with_color_codes(char *s1, char *s2, int n) {
3583  int i = 0, j = 0;
3584  int count = 0;
3585  while (s2[j] && count < n) {
3586  // detect (consecutive) color codes
3587  while (s2[j] == 0x1b) {
3588  // copy till 'm'
3589  while (s2[j] && s2[j] != 'm') {
3590  s1[i++] = s2[j++];
3591  }
3592  // copy 'm'
3593  if (s2[j]) {
3594  s1[i++] = s2[j++];
3595  }
3596  }
3597  if (s2[j]) {
3598  s1[i++] = s2[j++];
3599  count++;
3600  }
3601  }
3602  return i;
3603 }
3604 
3605 static int strncmp_skip_color_codes(const char *s1, const char *s2, int n) {
3606  int i = 0, j = 0;
3607  int count = 0;
3608  for (i = 0, j = 0; s1[i] && s2[j] && count < n; i++, j++, count++) {
3609  while (s1[i] == 0x1b) {
3610  while (s1[i] && s1[i] != 'm') {
3611  i++;
3612  }
3613  if (s1[i]) {
3614  i++;
3615  }
3616  }
3617  while (s2[j] == 0x1b) {
3618  while (s2[j] && s2[j] != 'm') {
3619  j++;
3620  }
3621  if (s2[j]) {
3622  j++;
3623  }
3624  }
3625  if (s1[i] != s2[j]) {
3626  return -1;
3627  }
3628  }
3629 
3630  if (count < n && s1[i] != s2[j]) {
3631  return -1;
3632  }
3633 
3634  return 0;
3635 }
3636 
3637 static char *strchr_skip_color_codes(const char *s, int c) {
3638  int i = 0;
3639  for (i = 0; s[i]; i++) {
3640  while (s[i] && s[i] == 0x1b) {
3641  while (s[i] && s[i] != 'm') {
3642  i++;
3643  }
3644  if (s[i]) {
3645  i++;
3646  }
3647  }
3648  if (!s[i] || s[i] == (char)c) {
3649  return (char *)s + i;
3650  }
3651  }
3652  return NULL;
3653 }
3654 
3655 // Global buffer to speed up colorizing performance
3656 
3657 RZ_API char *rz_str_highlight(char *str, const char *word, const char *color, const char *color_reset) {
3658  if (!str || !*str) {
3659  return NULL;
3660  }
3661  ut32 i = 0, j = 0, to_copy;
3662  char *start = str;
3663  ut32 l_str = strlen(str);
3664  ut32 l_reset = strlen(color_reset);
3665  ut32 l_color = color ? strlen(color) : 0;
3666  if (!color) {
3667  return strdup(str);
3668  }
3669  if (!word || !*word) {
3670  return rz_str_newf("%s%s%s", color, str, color_reset);
3671  }
3672  ut32 l_word = strlen(word);
3673  // XXX don't use static buffers
3674  char o[1024] = { 0 };
3675  while (start && (start < str + l_str)) {
3676  int copied = 0;
3677  // find first letter
3678  start = strchr_skip_color_codes(str + i, *word);
3679  if (start) {
3680  to_copy = start - (str + i);
3681  if (to_copy + j + 1 > sizeof(o)) {
3682  // XXX. no limits
3683  break;
3684  }
3685  strncpy(o + j, str + i, to_copy);
3686  i += to_copy;
3687  j += to_copy;
3688  if (!strncmp_skip_color_codes(start, word, l_word)) {
3689  if (j + strlen(color) >= sizeof(o)) {
3690  // XXX. no limits
3691  break;
3692  }
3693  strcpy(o + j, color);
3694  j += l_color;
3695  if (j + l_word >= sizeof(o)) {
3696  // XXX. no limits
3697  break;
3698  }
3699  copied = strncpy_with_color_codes(o + j, str + i, l_word);
3700  i += copied;
3701  j += copied;
3702  if (j + strlen(color_reset) >= sizeof(o)) {
3703  // XXX. no limits
3704  break;
3705  }
3706  strcpy(o + j, color_reset);
3707  j += l_reset;
3708  } else {
3709  o[j++] = str[i++];
3710  }
3711  } else {
3712  if (j + strlen(str + i) >= sizeof(o)) {
3713  break;
3714  }
3715  strcpy(o + j, str + i);
3716  break;
3717  }
3718  }
3719  return strdup(o);
3720 }
3721 
3722 RZ_API wchar_t *rz_str_mb_to_wc_l(const char *buf, int len) {
3723  wchar_t *res_buf = NULL;
3724  size_t sz;
3725  bool fail = true;
3726 
3727  if (!buf || len <= 0) {
3728  return NULL;
3729  }
3730  sz = mbstowcs(NULL, buf, len);
3731  if (sz == (size_t)-1) {
3732  goto err_r_str_mb_to_wc;
3733  }
3734  res_buf = (wchar_t *)calloc(1, (sz + 1) * sizeof(wchar_t));
3735  if (!res_buf) {
3736  goto err_r_str_mb_to_wc;
3737  }
3738  sz = mbstowcs(res_buf, buf, sz + 1);
3739  if (sz == (size_t)-1) {
3740  goto err_r_str_mb_to_wc;
3741  }
3742  fail = false;
3743 err_r_str_mb_to_wc:
3744  if (fail) {
3745  RZ_FREE(res_buf);
3746  }
3747  return res_buf;
3748 }
3749 
3750 RZ_API char *rz_str_wc_to_mb_l(const wchar_t *buf, int len) {
3751  char *res_buf = NULL;
3752  mbstate_t mbstate = { 0 };
3753  size_t sz;
3754 
3755  if (!buf || len <= 0) {
3756  return NULL;
3757  }
3758  sz = wcsrtombs(NULL, &buf, 0, &mbstate);
3759  if (sz == (size_t)-1) {
3760  goto err_r_str_wc_to_mb;
3761  }
3762  res_buf = RZ_NEWS0(char, sz + 1);
3763  if (!res_buf) {
3764  goto err_r_str_wc_to_mb;
3765  }
3766  sz = wcsrtombs(res_buf, &buf, sz + 1, &mbstate);
3767  if (sz == (size_t)-1) {
3768  goto err_r_str_wc_to_mb;
3769  }
3770  return res_buf;
3771 
3772 err_r_str_wc_to_mb:
3773  free(res_buf);
3774  return NULL;
3775 }
3776 
3777 RZ_API char *rz_str_wc_to_mb(const wchar_t *buf) {
3778  if (!buf) {
3779  return NULL;
3780  }
3781  return rz_str_wc_to_mb_l(buf, wcslen(buf));
3782 }
3783 
3784 RZ_API wchar_t *rz_str_mb_to_wc(const char *buf) {
3785  if (!buf) {
3786  return NULL;
3787  }
3788  return rz_str_mb_to_wc_l(buf, strlen(buf));
3789 }
3790 
3792  int i = 0;
3793  char *v = (char *)&val;
3794  char *str = (char *)calloc(1, 9);
3795  if (!str) {
3796  return NULL;
3797  }
3798  while (i < 8 && *v) {
3799  str[i++] = *v++;
3800  }
3801  return str;
3802 }
3803 
3804 RZ_API int rz_snprintf(char *string, int len, const char *fmt, ...) {
3805  va_list ap;
3806  va_start(ap, fmt);
3807  int ret = vsnprintf(string, len, fmt, ap);
3808  string[len - 1] = 0;
3809  va_end(ap);
3810  return ret;
3811 }
3812 
3813 // Strips all the lines in str that contain key
3814 RZ_API void rz_str_stripLine(char *str, const char *key) {
3815  size_t i, j, klen, slen, off;
3816  const char *ptr;
3817 
3818  if (!str || !key) {
3819  return;
3820  }
3821  klen = strlen(key);
3822  slen = strlen(str);
3823 
3824  for (i = 0; i < slen;) {
3825  ptr = (char *)rz_mem_mem((ut8 *)str + i, slen - i, (ut8 *)"\n", 1);
3826  if (!ptr) {
3827  ptr = (char *)rz_mem_mem((ut8 *)str + i, slen - i, (ut8 *)key, klen);
3828  if (ptr) {
3829  str[i] = '\0';
3830  break;
3831  }
3832  break;
3833  }
3834 
3835  off = (size_t)(ptr - (str + i)) + 1;
3836 
3837  ptr = (char *)rz_mem_mem((ut8 *)str + i, off, (ut8 *)key, klen);
3838  if (ptr) {
3839  for (j = i; j < slen - off + 1; j++) {
3840  str[j] = str[j + off];
3841  }
3842  slen -= off;
3843  } else {
3844  i += off;
3845  }
3846  }
3847 }
3848 
3849 RZ_API char *rz_str_list_join(RzList *str, const char *sep) {
3850  RzStrBuf *sb = rz_strbuf_new("");
3851  const char *p;
3852  while ((p = rz_list_pop_head(str))) {
3853  if (rz_strbuf_length(sb) != 0) {
3854  rz_strbuf_append(sb, sep);
3855  }
3856  rz_strbuf_append(sb, p);
3857  }
3858  return rz_strbuf_drain(sb);
3859 }
3860 
3861 RZ_API char *rz_str_array_join(const char **a, size_t n, const char *sep) {
3862  RzStrBuf *sb = rz_strbuf_new("");
3863  size_t i;
3864 
3865  if (n > 0) {
3866  rz_strbuf_append(sb, a[0]);
3867  }
3868 
3869  for (i = 1; i < n; i++) {
3870  rz_strbuf_append(sb, sep);
3871  rz_strbuf_append(sb, a[i]);
3872  }
3873  return rz_strbuf_drain(sb);
3874 }
3875 
3876 /* return the number of arguments expected as extra arguments */
3877 RZ_API int rz_str_fmtargs(const char *fmt) {
3878  int n = 0;
3879  while (*fmt) {
3880  if (*fmt == '%') {
3881  if (fmt[1] == '*') {
3882  n++;
3883  }
3884  n++;
3885  }
3886  fmt++;
3887  }
3888  return n;
3889 }
3890 
3891 // str-bool
3892 
3893 // Returns "true" or "false" as a string given an input integer. The returned
3894 // value is consistent with C's definition of 0 is false, and all other values
3895 // are true.
3896 RZ_API const char *rz_str_bool(int b) {
3897  return b ? "true" : "false";
3898 }
3899 
3900 RZ_API bool rz_str_is_true(const char *s) {
3901  return !rz_str_casecmp("yes", s) || !rz_str_casecmp("on", s) || !rz_str_casecmp("true", s) || !rz_str_casecmp("1", s);
3902 }
3903 
3904 RZ_API bool rz_str_is_false(const char *s) {
3905  return !rz_str_casecmp("no", s) || !rz_str_casecmp("off", s) || !rz_str_casecmp("false", s) || !rz_str_casecmp("0", s) || !*s;
3906 }
3907 
3908 RZ_API bool rz_str_is_bool(const char *val) {
3909  return rz_str_is_true(val) || rz_str_is_false(val);
3910 }
3911 
3912 RZ_API char *rz_str_nextword(char *s, char ch) {
3913  char *p = strchr(s, ch);
3914  if (!p) {
3915  return NULL;
3916  }
3917  *p++ = 0;
3918  return p;
3919 }
3920 
3921 RZ_API char *rz_str_scale(const char *s, int w, int h) {
3922  // count lines and rows in (s) string
3923  // compute how many lines we should remove or combine
3924  // return a string containing
3925  // for now this function is ascii only (no utf8 or ansi escapes)
3926  RzListIter *iter;
3927  char *line;
3928  char *str = strdup(s);
3929  RzList *lines = rz_str_split_list(str, "\n", 0);
3930  int i, j;
3931  int rows = 0;
3932  int maxcol = 0;
3933 
3934  rows = rz_list_length(lines);
3935  rz_list_foreach (lines, iter, line) {
3936  maxcol = RZ_MAX(strlen(line), maxcol);
3937  }
3938 
3940 
3941  int curline = -1;
3942  char *linetext = (char *)rz_str_pad(' ', w);
3943  for (i = 0; i < h; i++) {
3944  int zoomedline = i * (int)((float)rows / h);
3945  const char *srcline = rz_list_get_n(lines, zoomedline);
3946  int cols = strlen(srcline);
3947  for (j = 0; j < w; j++) {
3948  int zoomedcol = j * ((float)cols / w);
3949  linetext[j] = srcline[zoomedcol];
3950  }
3951  if (curline != zoomedline) {
3952  rz_list_append(out, strdup(linetext));
3953  curline = zoomedline;
3954  }
3955  memset(linetext, ' ', w);
3956  }
3957  free(str);
3958 
3959  char *join = rz_str_list_join(out, "\n");
3960  rz_list_free(out);
3961  return join;
3962 }
3963 
3964 RZ_API const char *rz_str_str_xy(const char *s, const char *word, const char *prev, int *x, int *y) {
3965  rz_return_val_if_fail(s && word && x && y, NULL);
3966  rz_return_val_if_fail(word[0] != '\0' && word[0] != '\n', NULL);
3967  const char *src = prev ? prev + 1 : s;
3968  const char *d = strstr(src, word);
3969  if (!d) {
3970  return NULL;
3971  }
3972  const char *q;
3973  for (q = prev ? prev : s; q < d; q++) {
3974  if (*q == '\n') {
3975  (*y)++;
3976  *x = 0;
3977 
3978  } else {
3979  (*x)++;
3980  }
3981  }
3982  return d;
3983 }
3984 
3996 RZ_API RzList *rz_str_wrap(char *str, size_t width) {
3998 
3999  RzList *res = rz_list_new();
4000  if (!res) {
4001  return NULL;
4002  }
4003  char *p, *start_line = str;
4004  char *first_space = NULL, *last_space = NULL;
4005 
4006  p = (char *)rz_str_trim_head_ro(str);
4007  if (!*p) {
4008  return res;
4009  }
4010 
4011  do {
4012  p++;
4013  if (!*p || isspace((int)*p)) {
4014  if (!last_space || p != last_space + 1) {
4015  if (p - start_line > width && first_space) {
4016  rz_list_append(res, start_line);
4017  *first_space = '\0';
4018  start_line = last_space + 1;
4019  }
4020  first_space = p;
4021  }
4022  last_space = p;
4023  }
4024  } while (*p);
4025  p--;
4026  while (p >= str && isspace((int)*p)) {
4027  *p = '\0';
4028  p--;
4029  }
4030  if (p > start_line) {
4031  rz_list_append(res, start_line);
4032  }
4033 
4034  return res;
4035 }
4036 
4037 // version.c
4038 #include <rz_userconf.h>
4039 #include <rz_util.h>
4040 
4041 #ifdef RZ_PACKAGER_VERSION
4042 #ifdef RZ_PACKAGER
4043 #define RZ_STR_PKG_VERSION_STRING ", package: " RZ_PACKAGER_VERSION " (" RZ_PACKAGER ")"
4044 #else
4045 #define RZ_STR_PKG_VERSION_STRING ", package: " RZ_PACKAGER_VERSION
4046 #endif
4047 #else
4048 #define RZ_STR_PKG_VERSION_STRING ""
4049 #endif
4050 
4051 RZ_API char *rz_str_version(const char *program) {
4053  if (program) {
4054  rz_strbuf_appendf(sb, "%s ", program);
4055  }
4057  (RZ_SYS_BITS & 8) ? 64 : 32);
4060  }
4061  char *gittip_pathname = rz_str_newf("%s" RZ_SYS_DIR "gittip", rz_path_bindir());
4062  char *gittip = NULL;
4063  if (!gittip_pathname) {
4064  goto done;
4065  }
4066  gittip = rz_file_slurp(gittip_pathname, NULL);
4067  if (!gittip || !*rz_str_trim_head_ro(gittip)) {
4068  goto done;
4069  }
4070  rz_str_trim(gittip);
4071  rz_strbuf_append(sb, "\n");
4072  rz_strbuf_appendf(sb, "commit: %s", gittip);
4073 done:
4074  free(gittip_pathname);
4075  free(gittip);
4076  return rz_strbuf_drain(sb);
4077 }
4078 
4079 #undef RZ_STR_PKG_VERSION_STRING
4080 
4092  if (enc != RZ_STRING_ENC_GUESS) {
4093  return enc;
4094  }
4095  for (ut32 i = 0, utf32le = 0, utf32be = 0, utf16le = 0, utf16be = 0, ascii = 0; i < length; ++i) {
4096  ut32 leftovers = length - i;
4097  if (leftovers > 4 && IS_PRINTABLE(buffer[i]) && buffer[i + 1] == 0 && buffer[i + 2] == 0 && buffer[i + 3] == 0) {
4098  utf32le++;
4099  if (utf32le > 2) {
4100  enc = RZ_STRING_ENC_UTF32LE;
4101  break;
4102  }
4103  } else if (leftovers > 4 && buffer[i] == 0 && buffer[i + 1] == 0 && buffer[i + 2] == 0 && IS_PRINTABLE(buffer[i + 3])) {
4104  utf32be++;
4105  if (utf32be > 2) {
4106  enc = RZ_STRING_ENC_UTF32BE;
4107  break;
4108  }
4109  }
4110  if (leftovers > 2 && IS_PRINTABLE(buffer[i]) && buffer[i + 1] == 0) {
4111  utf16le++;
4112  if (utf16le > 2) {
4113  enc = RZ_STRING_ENC_UTF16LE;
4114  break;
4115  }
4116  } else if (leftovers > 2 && buffer[i] == 0 && IS_PRINTABLE(buffer[i + 1])) {
4117  utf16be++;
4118  if (utf16be > 2) {
4119  enc = RZ_STRING_ENC_UTF16BE;
4120  break;
4121  }
4122  }
4123  if (IS_PRINTABLE(buffer[i]) || buffer[i] == ' ') {
4124  ascii++;
4125  if (ascii > length - 1) {
4126  enc = RZ_STRING_ENC_8BIT;
4127  break;
4128  }
4129  }
4130  }
4131  return enc == RZ_STRING_ENC_GUESS ? RZ_STRING_ENC_UTF8 : enc;
4132 }
4133 
4142  rz_return_val_if_fail(option && option->buffer && option->encoding != RZ_STRING_ENC_GUESS, NULL);
4143  if (option->length < 1) {
4144  return NULL;
4145  }
4146 
4147  RzStrBuf sb;
4148  const ut8 *buf = option->buffer;
4149  ut32 buflen = option->length;
4150  RzStrEnc enc = option->encoding;
4151  ut32 wrap_at = option->wrap_at;
4152  RzRune rune;
4153  ut32 n_runes = 0;
4154  int rsize = 1; // rune size
4155 
4156  rz_strbuf_init(&sb);
4157  for (ut32 i = 0, line_runes = 0; i < buflen; i += rsize) {
4158  if (enc == RZ_STRING_ENC_UTF32LE) {
4159  rsize = rz_utf32le_decode(&buf[i], buflen - i, &rune);
4160  if (rsize) {
4161  rsize = 4;
4162  }
4163  } else if (enc == RZ_STRING_ENC_UTF16LE) {
4164  rsize = rz_utf16le_decode(&buf[i], buflen - i, &rune);
4165  if (rsize == 1) {
4166  rsize = 2;
4167  }
4168  } else if (enc == RZ_STRING_ENC_UTF32BE) {
4169  rsize = rz_utf32be_decode(&buf[i], buflen - i, &rune);
4170  if (rsize) {
4171  rsize = 4;
4172  }
4173  } else if (enc == RZ_STRING_ENC_UTF16BE) {
4174  rsize = rz_utf16be_decode(&buf[i], buflen - i, &rune);
4175  if (rsize == 1) {
4176  rsize = 2;
4177  }
4178  } else if (enc == RZ_STRING_ENC_IBM037) {
4179  rsize = rz_str_ibm037_to_unicode(buf[i], &rune);
4180  } else if (enc == RZ_STRING_ENC_IBM290) {
4181  rsize = rz_str_ibm290_to_unicode(buf[i], &rune);
4182  } else if (enc == RZ_STRING_ENC_EBCDIC_ES) {
4183  rsize = rz_str_ebcdic_es_to_unicode(buf[i], &rune);
4184  } else if (enc == RZ_STRING_ENC_EBCDIC_UK) {
4185  rsize = rz_str_ebcdic_uk_to_unicode(buf[i], &rune);
4186  } else if (enc == RZ_STRING_ENC_EBCDIC_US) {
4187  rsize = rz_str_ebcdic_us_to_unicode(buf[i], &rune);
4188  } else if (enc == RZ_STRING_ENC_8BIT) {
4189  rune = buf[i];
4190  rsize = rune < 0x7F ? 1 : 0;
4191  } else {
4192  rsize = rz_utf8_decode(&buf[i], buflen - i, &rune);
4193  }
4194 
4195  if (rsize == 0) {
4196  switch (enc) {
4197  case RZ_STRING_ENC_UTF32LE:
4198  rsize = RZ_MIN(4, buflen - i);
4199  break;
4200  case RZ_STRING_ENC_UTF16LE:
4201  rsize = RZ_MIN(2, buflen - i);
4202  break;
4203  case RZ_STRING_ENC_UTF32BE:
4204  rsize = RZ_MIN(4, buflen - i);
4205  break;
4206  case RZ_STRING_ENC_UTF16BE:
4207  rsize = RZ_MIN(2, buflen - i);
4208  break;
4209  default:
4210  rsize = 1;
4211  break;
4212  }
4213  for (int j = 0; j < rsize; ++j) {
4214  rune = buf[i + j];
4215  n_runes++;
4216  if (option->urlencode) {
4217  rz_strbuf_appendf(&sb, "%%%02x", rune);
4218  } else if (option->json) {
4219  rz_strbuf_appendf(&sb, "\\u%04x", rune);
4220  } else {
4221  rz_strbuf_appendf(&sb, "\\x%02x", rune);
4222  }
4223  }
4224  if (wrap_at && line_runes + 1 >= wrap_at) {
4225  rz_strbuf_appendf(&sb, "\n");
4226  line_runes = 0;
4227  }
4228  continue;
4229  } else if (rune == '\0' && option->stop_at_nil) {
4230  break;
4231  } else if (rune == '\n') {
4232  line_runes = 0;
4233  }
4234  line_runes++;
4235  n_runes++;
4236  if (option->urlencode) {
4237  if (IS_DIGIT(rune) || IS_UPPER(rune) || IS_LOWER(rune) || rune == '-' || rune == '_' || rune == '.' || rune == '~') {
4238  // RFC 3986 section 2.3 Unreserved Characters
4239  // A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
4240  // a b c d e f g h i j k l m n o p q r s t u v w x y z
4241  // 0 1 2 3 4 5 6 7 8 9 - _ . ~
4242  char ch = rune;
4243  rz_strbuf_appendf(&sb, "%c", ch);
4244  } else {
4245  ut8 tmp[4];
4246  int n_enc = rz_utf8_encode((ut8 *)tmp, rune);
4247  for (int j = 0; j < n_enc; ++j) {
4248  rz_strbuf_appendf(&sb, "%%%02x", tmp[j]);
4249  }
4250  }
4251  } else if (option->json) {
4252  if (IS_PRINTABLE(rune) && rune != '\"' && rune != '\\') {
4253  char ch = rune;
4254  rz_strbuf_appendf(&sb, "%c", ch);
4255  } else if (rune == '\n') {
4256  rz_strbuf_append(&sb, "\\n");
4257  } else if (rune == '\r') {
4258  rz_strbuf_append(&sb, "\\r");
4259  } else if (rune == '\\') {
4260  rz_strbuf_append(&sb, "\\\\");
4261  } else if (rune == '\t') {
4262  rz_strbuf_append(&sb, "\\t");
4263  } else if (rune == '\f') {
4264  rz_strbuf_append(&sb, "\\f");
4265  } else if (rune == '\b') {
4266  rz_strbuf_append(&sb, "\\b");
4267  } else if (rune == '"') {
4268  rz_strbuf_append(&sb, "\\\"");
4269  } else {
4270  for (int j = 0; j < rsize; ++j) {
4271  rune = buf[i + j];
4272  rz_strbuf_appendf(&sb, "\\u%04x", rune);
4273  }
4274  n_runes += rsize - 1;
4275  }
4276  } else {
4277  if (rune == '\\') {
4278  rz_strbuf_appendf(&sb, "\\\\");
4279  } else if ((rune == '\n' && !option->escape_nl) || (rz_rune_is_printable(rune) && rune >= ' ')) {
4280  char tmp[5] = { 0 };
4281  rz_utf8_encode((ut8 *)tmp, rune);
4282  rz_strbuf_appendf(&sb, "%s", tmp);
4283  } else {
4284  ut8 tmp[4];
4285  int n_enc = rz_utf8_encode((ut8 *)tmp, rune);
4286  for (int j = 0; j < n_enc; ++j) {
4287  rz_strbuf_appendf(&sb, "\\x%02x", tmp[j]);
4288  }
4289  }
4290  }
4291  if (wrap_at && line_runes + 1 >= wrap_at) {
4292  rz_strbuf_appendf(&sb, "\n");
4293  line_runes = 0;
4294  }
4295  }
4296  if (!option->json) {
4297  rz_strbuf_appendf(&sb, "\n");
4298  }
4299  if (length) {
4300  *length = n_runes;
4301  }
4302  return rz_strbuf_drain_nofree(&sb);
4303 }
size_t len
Definition: 6502dis.c:15
ut8 op
Definition: 6502dis.c:13
#define e(frag)
lzma_index ** i
Definition: index.h:629
lzma_index * src
Definition: index.h:567
static const char * arg(RzAnalysis *a, csh *handle, cs_insn *insn, char *buf, int n)
Definition: arm_esil32.c:136
ut16 val
Definition: armass64_const.h:6
static bool err
Definition: armass.c:435
static ut8 bytes[32]
Definition: asm_arc.c:23
static RASN1String * newstr(const char *string)
Definition: astr.c:23
lsl lsr asr ror lsl lsr asr ror lsl lsl lsr asr ror lsl lsr asr ror lsl lsr asr ror lsl lsr asr ror lsl lsr asr ror lsl lsr asr ror lsl lsr asr ror lsl lsr asr ror lsl lsr asr ror lsl lsr asr ror c1
lsl lsr asr ror lsl lsr asr ror lsl lsl lsr asr ror lsl lsr asr ror lsl lsr asr ror lsl lsr asr ror lsl lsr asr ror lsl lsr asr ror lsl lsr asr ror lsl lsr asr ror lsl lsr asr ror lsl lsr asr ror c0
#define W(x, y, z)
#define H(x)
static SblHeader sb
Definition: bin_mbn.c:26
static RzBinSourceLineInfo * lines(RzBinFile *bf)
Definition: bin_symbols.c:427
int bits(struct state *s, int need)
Definition: blast.c:72
const lzma_allocator const uint8_t * in
Definition: block.h:527
const lzma_allocator const uint8_t size_t uint8_t * out
Definition: block.h:528
#define RZ_API
#define NULL
Definition: cris-opc.c:27
RzCryptoSelector bit
Definition: crypto.c:16
#define r
Definition: crypto_rc6.c:12
#define w
Definition: crypto_rc6.c:13
static static fork const void static count static fd const char const char static newpath const char static path const char path
Definition: sflib.h:35
static static fork write
Definition: sflib.h:33
static static sync static getppid static getegid const char static filename char static len const char char static bufsiz static mask static vfork const void static prot static getpgrp const char static swapflags static arg static fd static protocol static who struct sockaddr static addrlen static backlog struct timeval struct timezone static tz const struct iovec static count static mode const void const struct sockaddr static tolen const char static pathname void count
Definition: sflib.h:98
static static sync static getppid static getegid const char static filename char static len const char char static bufsiz static mask static vfork const void static prot static getpgrp const char static swapflags static arg static fd static protocol static who struct sockaddr static addrlen static backlog struct timeval struct timezone static tz const struct iovec static count static mode const void const struct sockaddr static tolen const char static pathname void static offset struct stat static buf void long static basep static whence static length const void static len static semflg const void static shmflg const struct timespec struct timespec static rem const char static group const void start
Definition: sflib.h:133
static static sync static getppid static getegid const char static filename char static len const char char static bufsiz static mask static vfork const void static prot static getpgrp const char static swapflags static arg static fd static protocol static who struct sockaddr static addrlen static backlog struct timeval struct timezone static tz const struct iovec static count static mode const void const struct sockaddr static tolen const char static pathname void static offset struct stat static buf void long static basep static whence static length const void static len key
Definition: sflib.h:118
static static sync static getppid static getegid const char static filename char static len const char char static bufsiz static mask static vfork const void static prot static getpgrp const char static swapflags static arg static fd static protocol static who struct sockaddr static addrlen static backlog struct timeval struct timezone static tz const struct iovec static count static mode const void const struct sockaddr static tolen const char static pathname void static offset struct stat static buf void long static basep static whence static length const void static len static semflg const void static shmflg const struct timespec struct timespec static rem const char static group const void length
Definition: sflib.h:133
#define ut8
Definition: dcpu16.h:8
static int buf_size
Definition: debug_qnx.c:35
uint16_t ut16
uint32_t ut32
const char * k
Definition: dsignal.c:11
const char * v
Definition: dsignal.c:12
static char sc[]
Definition: egg_cb.c:6
struct @667 g
struct tab * done
Definition: enough.c:233
void trim(string &s, string characters)
Definition: gen_manual.cpp:43
unsigned char suffix[65536]
Definition: gun.c:164
unsigned short prefix[65536]
Definition: gun.c:163
RZ_API void Ht_() free(HtName_(Ht) *ht)
Definition: ht_inc.c:130
RZ_API VALUE_TYPE Ht_() find(HtName_(Ht) *ht, const KEY_TYPE key, bool *found)
Definition: ht_inc.c:330
voidpf void uLong size
Definition: ioapi.h:138
voidpf uLong offset
Definition: ioapi.h:144
voidpf void * buf
Definition: ioapi.h:138
snprintf
Definition: kernel.h:364
vsnprintf
Definition: kernel.h:366
uint8_t ut8
Definition: lh5801.h:11
return memset(p, 0, total)
void * p
Definition: libc.cpp:67
memcpy(mem, inblock.get(), min(CONTAINING_RECORD(inblock.get(), MEMBLOCK, data) ->size, size))
static void list(RzEgg *egg)
Definition: rz-gg.c:52
RZ_API RZ_OWN RzList * rz_list_newf(RzListFree f)
Returns a new initialized RzList pointer and sets the free method.
Definition: list.c:248
RZ_API RZ_OWN RzList * rz_list_new(void)
Returns a new initialized RzList pointer (free method is not initialized)
Definition: list.c:235
RZ_API RZ_BORROW void * rz_list_get_n(RZ_NONNULL const RzList *list, ut32 n)
Returns the N-th element of the list.
Definition: list.c:574
RZ_API ut32 rz_list_length(RZ_NONNULL const RzList *list)
Returns the length of the list.
Definition: list.c:109
RZ_API RZ_OWN void * rz_list_pop_head(RZ_NONNULL RzList *list)
Removes and returns the first element of the list.
Definition: list.c:401
RZ_API RZ_BORROW RzListIter * rz_list_append(RZ_NONNULL RzList *list, void *data)
Appends at the end of the list a new element.
Definition: list.c:288
RZ_API void rz_list_free(RZ_NONNULL RzList *list)
Empties the list and frees the list pointer.
Definition: list.c:137
void * realloc(void *ptr, size_t size)
Definition: malloc.c:144
void * malloc(size_t size)
Definition: malloc.c:123
void * calloc(size_t number, size_t size)
Definition: malloc.c:102
static static fork const void static count static fd const char const char static newpath char char char static envp time_t static t const char static mode static whence const char static dir time_t static t unsigned static seconds const char struct utimbuf static buf static inc static sig const char static mode dup
Definition: sflib.h:68
static static fork const void static count static fd const char const char static newpath char char argv
Definition: sflib.h:40
return strdup("=SP r13\n" "=LR r14\n" "=PC r15\n" "=A0 r0\n" "=A1 r1\n" "=A2 r2\n" "=A3 r3\n" "=ZF zf\n" "=SF nf\n" "=OF vf\n" "=CF cf\n" "=SN or0\n" "gpr lr .32 56 0\n" "gpr pc .32 60 0\n" "gpr cpsr .32 64 0 ____tfiae_________________qvczn\n" "gpr or0 .32 68 0\n" "gpr tf .1 64.5 0 thumb\n" "gpr ef .1 64.9 0 endian\n" "gpr jf .1 64.24 0 java\n" "gpr qf .1 64.27 0 sticky_overflow\n" "gpr vf .1 64.28 0 overflow\n" "gpr cf .1 64.29 0 carry\n" "gpr zf .1 64.30 0 zero\n" "gpr nf .1 64.31 0 negative\n" "gpr itc .4 64.10 0 if_then_count\n" "gpr gef .4 64.16 0 great_or_equal\n" "gpr r0 .32 0 0\n" "gpr r1 .32 4 0\n" "gpr r2 .32 8 0\n" "gpr r3 .32 12 0\n" "gpr r4 .32 16 0\n" "gpr r5 .32 20 0\n" "gpr r6 .32 24 0\n" "gpr r7 .32 28 0\n" "gpr r8 .32 32 0\n" "gpr r9 .32 36 0\n" "gpr r10 .32 40 0\n" "gpr r11 .32 44 0\n" "gpr r12 .32 48 0\n" "gpr r13 .32 52 0\n" "gpr r14 .32 56 0\n" "gpr r15 .32 60 0\n" "gpr r16 .32 64 0\n" "gpr r17 .32 68 0\n")
char * dst
Definition: lz4.h:724
int args
Definition: mipsasm.c:18
int x
Definition: mipsasm.c:20
int n
Definition: mipsasm.c:19
line
Definition: setup.py:34
int idx
Definition: setup.py:197
size_t strnlen(const char *str, size_t maxlen)
int off
Definition: pal.c:13
struct @219 colors[]
static void pad(RzStrBuf *sb, ut32 count)
Definition: protobuf.c:36
#define eprintf(x, y...)
Definition: rlcc.c:7
static RzSocket * s
Definition: rtr.c:28
#define rz_warn_if_reached()
Definition: rz_assert.h:29
#define rz_return_val_if_fail(expr, val)
Definition: rz_assert.h:108
#define Color_RESET
Definition: rz_cons.h:617
RZ_API int rz_str_ibm037_to_unicode(const ut8 src, RZ_NONNULL RZ_OUT RzRune *dst)
Convert an ibm037 char into an unicode RzRune.
Definition: ebcdic.c:457
RZ_API int rz_str_ibm290_to_unicode(const ut8 src, RZ_NONNULL RZ_OUT RzRune *dst)
Convert an ibm290 char into an unicode RzRune.
Definition: ebcdic.c:516
RZ_API int rz_str_ebcdic_es_to_unicode(const ut8 src, RZ_NONNULL RZ_OUT RzRune *dst)
Convert an ebcdic_es char into an unicode RzRune.
Definition: ebcdic.c:650
RZ_API int rz_str_ebcdic_us_to_unicode(const ut8 src, RZ_NONNULL RZ_OUT RzRune *dst)
Convert an ebcdic_us char into an unicode RzRune.
Definition: ebcdic.c:607
RZ_API int rz_str_ebcdic_uk_to_unicode(const ut8 src, RZ_NONNULL RZ_OUT RzRune *dst)
Convert an ebcdic_uk char into an unicode RzRune.
Definition: ebcdic.c:563
RZ_API char * rz_file_tmpdir(void)
Definition: file.c:1132
RZ_API RZ_OWN char * rz_file_slurp(const char *str, RZ_NULLABLE size_t *usz)
Definition: file.c:454
RZ_API bool rz_hex_to_byte(ut8 *val, ut8 c)
Definition: hex.c:10
#define RZ_LOG_ERROR(fmtstr,...)
Definition: rz_log.h:58
RZ_API int rz_mem_eq(const ut8 *a, const ut8 *b, int len)
Compares memory a with b over len bytes.
Definition: mem.c:31
RZ_API const ut8 * rz_mem_mem_aligned(const ut8 *haystack, int hlen, const ut8 *needle, int nlen, int align)
Definition: mem.c:260
RZ_API const ut8 * rz_mem_mem(const ut8 *haystack, int hlen, const ut8 *needle, int nlen)
Definition: mem.c:246
RZ_API ut64 rz_num_get(RzNum *num, const char *str)
Definition: unum.c:172
RZ_API RZ_OWN char * rz_path_bindir(void)
Return the directory where the Rizin binaries are placed.
Definition: path.c:148
RZ_API RzRegex * rz_regex_new(const char *pattern, const char *cflags)
Definition: regcomp.c:183
RZ_API int rz_regex_exec(const RzRegex *preg, const char *string, size_t nmatch, RzRegexMatch __pmatch[], int eflags)
Definition: regexec.c:149
RZ_API void rz_regex_free(RzRegex *)
Definition: regcomp.c:249
RZ_API bool rz_stack_is_empty(RzStack *s)
Definition: stack.c:68
RZ_API void * rz_stack_pop(RzStack *s)
Definition: stack.c:59
RZ_API bool rz_stack_push(RzStack *s, void *el)
Definition: stack.c:42
RZ_API RzStack * rz_stack_new(ut32 n)
Definition: stack.c:6
RZ_API void rz_stack_free(RzStack *s)
Definition: stack.c:29
#define RZ_STR_ISNOTEMPTY(x)
Definition: rz_str.h:68
RzStrEnc
Definition: rz_str.h:19
@ RZ_STRING_ENC_UTF32LE
Definition: rz_str.h:24
@ RZ_STRING_ENC_8BIT
Definition: rz_str.h:20
@ RZ_STRING_ENC_BASE64
Definition: rz_str.h:27
@ RZ_STRING_ENC_EBCDIC_US
Definition: rz_str.h:31
@ RZ_STRING_ENC_MUTF8
Definition: rz_str.h:22
@ RZ_STRING_ENC_UTF32BE
Definition: rz_str.h:26
@ RZ_STRING_ENC_UTF8
Definition: rz_str.h:21
@ RZ_STRING_ENC_GUESS
Definition: rz_str.h:33
@ RZ_STRING_ENC_UTF16LE
Definition: rz_str.h:23
@ RZ_STRING_ENC_UTF16BE
Definition: rz_str.h:25
@ RZ_STRING_ENC_EBCDIC_UK
Definition: rz_str.h:30
@ RZ_STRING_ENC_IBM037
Definition: rz_str.h:28
@ RZ_STRING_ENC_IBM290
Definition: rz_str.h:29
@ RZ_STRING_ENC_EBCDIC_ES
Definition: rz_str.h:32
#define RZ_STR_ISEMPTY(x)
Definition: rz_str.h:67
RZ_API const char * rz_str_trim_head_ro(const char *str)
Definition: str_trim.c:86
int(* RzStrRangeCallback)(void *, int)
Definition: rz_str.h:65
RZ_API void rz_str_trim(RZ_NONNULL RZ_INOUT char *str)
Removes whitespace characters (space, tab, newline etc.) from the beginning and end of a string.
Definition: str_trim.c:190
void(* str_operation)(char *c)
Definition: rz_str.h:204
static const char * rz_str_word_get_next0(const char *str)
Definition: rz_str.h:154
#define IS_UPPER(c)
Definition: rz_str_util.h:14
#define IS_LOWER(c)
Definition: rz_str_util.h:15
#define IS_SEPARATOR(x)
Definition: rz_str_util.h:6
#define IS_DIGIT(x)
Definition: rz_str_util.h:11
#define IS_OCTAL(x)
Definition: rz_str_util.h:12
#define IS_PRINTABLE(x)
Definition: rz_str_util.h:10
#define IS_WHITECHAR(x)
Definition: rz_str_util.h:5
RZ_API RZ_OWN char * rz_strbuf_drain(RzStrBuf *sb)
Definition: strbuf.c:342
RZ_API RZ_OWN char * rz_strbuf_drain_nofree(RzStrBuf *sb)
Definition: strbuf.c:349
RZ_API bool rz_strbuf_append(RzStrBuf *sb, const char *s)
Definition: strbuf.c:222
RZ_API RzStrBuf * rz_strbuf_new(const char *s)
Definition: strbuf.c:8
RZ_API bool rz_strbuf_appendf(RzStrBuf *sb, const char *fmt,...) RZ_PRINTF_CHECK(2
RZ_API void rz_strbuf_init(RzStrBuf *sb)
Definition: strbuf.c:33
RZ_API int rz_strbuf_length(RzStrBuf *sb)
Definition: strbuf.c:28
RZ_API bool rz_strbuf_append_n(RzStrBuf *sb, const char *s, size_t l)
Definition: strbuf.c:229
RZ_API char * rz_sys_getenv(const char *key)
Get the value of an environment variable named key or NULL if none exists.
Definition: sys.c:483
@ RZ_SYS_BITS_32
Definition: rz_sys.h:20
@ RZ_SYS_BITS_64
Definition: rz_sys.h:21
@ RZ_SYS_BITS_16
Definition: rz_sys.h:19
@ RZ_SYS_BITS_8
Definition: rz_sys.h:18
#define RZ_NEWS(x, y)
Definition: rz_types.h:283
#define RZ_SYS_DIR
Definition: rz_types.h:218
#define RZ_NULLABLE
Definition: rz_types.h:65
#define RZ_OWN
Definition: rz_types.h:62
#define RZ_OUT
Definition: rz_types.h:51
#define RZ_SYS_BITS
Definition: rz_types.h:520
#define HHXFMT
Definition: rz_types.h:402
#define RZ_NONNULL
Definition: rz_types.h:64
#define RZ_SYS_HOME
Definition: rz_types.h:220
#define RZ_SYS_ARCH
Definition: rz_types.h:519
#define RZ_SYS_OS
Definition: rz_types.h:587
#define RZ_NEWS0(x, y)
Definition: rz_types.h:282
#define RZ_BIT_TOGGLE(x, y)
Definition: rz_types.h:313
#define RZ_ARRAY_SIZE(x)
Definition: rz_types.h:300
#define RZ_FREE(x)
Definition: rz_types.h:369
#define RZ_BORROW
Definition: rz_types.h:63
#define RZ_MIN(x, y)
#define RZ_MAX(x, y)
#define UT64_MAX
Definition: rz_types_base.h:86
#define RZ_BETWEEN(x, y, z)
RZ_API int rz_utf16_decode(const ut8 *ptr, int ptrlen, RzRune *ch, bool bigendian)
Definition: utf16.c:8
RZ_API int rz_utf16le_decode(const ut8 *ptr, int ptrlen, RzRune *ch)
Definition: utf16.c:36
RZ_API int rz_utf16be_decode(const ut8 *ptr, int ptrlen, RzRune *ch)
Definition: utf16.c:41
RZ_API int rz_utf32le_decode(const ut8 *ptr, int ptrlen, RzRune *ch)
Definition: utf32.c:39
RZ_API int rz_utf32_decode(const ut8 *ptr, int ptrlen, RzRune *ch, bool bigendian)
Definition: utf32.c:8
RZ_API int rz_utf32be_decode(const ut8 *ptr, int ptrlen, RzRune *ch)
Definition: utf32.c:44
RZ_API RzStrEnc rz_utf_bom_encoding(const ut8 *ptr, int ptrlen)
Definition: utf8.c:809
RZ_API int rz_utf8_decode(const ut8 *ptr, int ptrlen, RzRune *ch)
Definition: utf8.c:492
RZ_API bool rz_rune_is_printable(const RzRune c)
Returns true when the RzRune is a printable symbol.
Definition: utf8.c:606
RZ_API int rz_mutf8_decode(const ut8 *ptr, int ptrlen, RzRune *ch)
Definition: utf8.c:524
ut32 RzRune
Definition: rz_utf8.h:13
RZ_API int rz_utf8_encode(ut8 *ptr, const RzRune ch)
Definition: utf8.c:535
#define RZ_VERSION
Definition: rz_version.h:8
#define isspace(c)
Definition: safe-ctype.h:141
#define tolower(c)
Definition: safe-ctype.h:149
#define toupper(c)
Definition: safe-ctype.h:147
static struct sockaddr static addrlen static backlog const void static flags void struct sockaddr from
Definition: sfsocketcall.h:123
static struct sockaddr static addrlen static backlog const void static flags void struct sockaddr socklen_t static fromlen const void const struct sockaddr to
Definition: sfsocketcall.h:125
static int
Definition: sfsocketcall.h:114
static struct sockaddr static addrlen static backlog const void msg
Definition: sfsocketcall.h:119
int size_t
Definition: sftypes.h:40
int ptrdiff_t
Definition: sftypes.h:68
#define d(i)
Definition: sha256.c:44
#define b(i)
Definition: sha256.c:42
#define c(i)
Definition: sha256.c:43
#define a(i)
Definition: sha256.c:41
#define s1(x)
Definition: sha256.c:60
#define h(i)
Definition: sha256.c:48
RZ_API int rz_str_utf16_to_utf8(ut8 *dst, int len_dst, const ut8 *src, int len_src, bool little_endian)
Definition: str.c:2884
RZ_API RzList * rz_str_split_duplist_n(const char *_str, const char *c, int n, bool trim)
Split the string str according to the substring c and returns a RzList with the result.
Definition: str.c:3485
RZ_API void rz_str_byte_escape(const char *p, char **dst, RzStrEscOptions *opt)
Converts unprintable characters to C-like backslash representation.
Definition: str.c:1436
static bool str_endswith(RZ_NONNULL const char *str, RZ_NONNULL const char *needle, bool case_sensitive)
Definition: str.c:3309
RZ_API void rz_str_truncate_cmd(char *string)
Definition: str.c:3089
RZ_API int rz_str_char_count(const char *string, char ch)
Definition: str.c:611
RZ_API size_t rz_str_ansi_nlen(const char *str, size_t slen)
Definition: str.c:1923
RZ_API char * rz_str_append_owned(char *ptr, char *string)
Definition: str.c:1050
RZ_API char * rz_str_appendf(char *ptr, const char *fmt,...)
Definition: str.c:1082
RZ_API char * rz_str_escape_dot(const char *buf)
Definition: str.c:1587
RZ_API bool rz_str_is_false(const char *s)
Definition: str.c:3904
RZ_API const char * rz_str_lchr(const char *str, char chr)
Definition: str.c:669
RZ_API ut8 rz_str_contains_macro(const char *input_value)
Definition: str.c:3076
static const char * separator_get_first(const char *text)
Definition: str.c:621
RZ_API bool rz_str_char_fullwidth(const char *s, size_t left)
Definition: str.c:2277
RZ_API const char * rz_str_pad(const char ch, int sz)
Definition: str.c:3236
RZ_API char * rz_str_crop(const char *str, unsigned int x, unsigned int y, unsigned int x2, unsigned int y2)
Definition: str.c:3157
RZ_API const char * rz_str_rwx_i(int rwx)
Definition: str.c:332
RZ_API bool rz_str_range_in(const char *r, ut64 addr)
Definition: str.c:2807
RZ_API const char * rz_str_str_xy(const char *s, const char *word, const char *prev, int *x, int *y)
Definition: str.c:3964
RZ_API size_t rz_str_utf8_charsize_prev(const char *str, int prev_len)
Definition: str.c:2317
RZ_API RZ_OWN RzList * rz_str_split_duplist_n_regex(RZ_NONNULL const char *_str, RZ_NONNULL const char *r, int n, bool trim)
Split the string str according to the regex r and returns a RzList with the result.
Definition: str.c:3506
RZ_API ut64 rz_str_bits_from_string(const char *buf, const char *bitz)
Definition: str.c:266
RZ_API const char * rz_str_last(const char *str, const char *ch)
Definition: str.c:3565
RZ_API char * rz_str_replace_icase(char *str, const char *key, const char *val, int g, int keep_case)
Definition: str.c:1160
RZ_API bool rz_str_cmp_list(const char *list, const char *item, char sep)
Definition: str.c:953
RZ_API char * rz_str_repeat(const char *ch, int sz)
Definition: str.c:3249
static const char * rwxstr[]
Definition: str.c:24
static size_t __str_ansi_length(char const *str)
Definition: str.c:1902
RZ_API int rz_str_replace_ch(char *s, char a, char b, bool global)
Definition: str.c:139
RZ_API bool rz_str_is4utf8(RZ_NONNULL const char *c)
Checks if the given character string is a four byte UTF-8 character.
Definition: str.c:731
RZ_API size_t rz_str_utf8_charsize_last(const char *str)
Definition: str.c:2335
RZ_API const char * rz_str_sep(const char *base, const char *sep)
Definition: str.c:788
RZ_API char * rz_str_append(char *ptr, const char *string)
Definition: str.c:1063
RZ_API char * rz_str_ndup(RZ_NULLABLE const char *ptr, int len)
Create new copy of string ptr limited to size len.
Definition: str.c:1006
RZ_API char * rz_str_escape_utf16be(const char *buf, int buf_size, RzStrEscOptions *opt)
Definition: str.c:1715
RZ_API bool rz_str_is_true(const char *s)
Definition: str.c:3900
RZ_API char * rz_str_between(const char *cmt, const char *prefix, const char *suffix)
Definition: str.c:3264
RZ_API RZ_OWN char * rz_str_escape(RZ_NONNULL const char *buf)
Definition: str.c:1550
RZ_API int rz_str_word_set0_stack(char *str)
Definition: str.c:471
RZ_API char * rz_str_newf(const char *fmt,...)
Definition: str.c:897
RZ_API int rz_str_ncasecmp(const char *s1, const char *s2, size_t n)
Definition: str.c:129
RZ_API char * rz_str_sanitize_sdb_key(const char *s)
Definition: str.c:1405
RZ_API char * rz_str_new(const char *str)
Definition: str.c:865
RZ_API int rz_str_rwx(const char *str)
Definition: str.c:318
RZ_API ut64 rz_str_djb2_hash(const char *s)
Definition: str.c:383
RZ_API char * rz_str_replace_in(char *str, ut32 sz, const char *key, const char *val, int g)
Definition: str.c:1288
RZ_API size_t rz_str_ansi_len(const char *str)
Definition: str.c:1945
RZ_API char * rz_str_escape_utf8_keep_printable(const char *buf, RzStrEscOptions *opt)
Definition: str.c:1703
#define RZ_STR_PKG_VERSION_STRING
Definition: str.c:4048
RZ_API int rz_str_arg_unescape(char *arg)
Definition: str.c:2443
RZ_API RzStrEnc rz_str_enc_string_as_type(RZ_NULLABLE const char *encoding)
converts an encoding name to RzStrEnc
Definition: str.c:86
RZ_API char * rz_str_wc_to_mb_l(const wchar_t *buf, int len)
Definition: str.c:3750
RZ_API char ** rz_str_argv(const char *cmdline, int *_argc)
Definition: str.c:2509
RZ_API void rz_str_stripLine(char *str, const char *key)
Definition: str.c:3814
RZ_API const char * rz_str_rchr(const char *base, const char *p, int ch)
Definition: str.c:829
static RzList * str_split_list_common_regex(RZ_BORROW char *str, RZ_BORROW RzRegex *r, int n, bool trim, bool dup)
Definition: str.c:3370
RZ_API int rz_str_path_unescape(char *path)
Definition: str.c:2493
RZ_API int rz_str_fmtargs(const char *fmt)
Definition: str.c:3877
static int strncpy_with_color_codes(char *s1, char *s2, int n)
Definition: str.c:3582
RZ_API const char * rz_str_bool(int b)
Definition: str.c:3896
RZ_API char * rz_str_appendlen(char *ptr, const char *string, int slen)
Definition: str.c:1043
RZ_API char * rz_str_ichr(char *str, char chr)
Definition: str.c:660
RZ_API int rz_str_word_count(const char *string)
Definition: str.c:643
RZ_API char * rz_str_appendch(char *x, char y)
Definition: str.c:1105
RZ_API void rz_str_uri_decode(char *s)
Definition: str.c:2845
RZ_API int rz_str_ccpy(char *dst, char *src, int ch)
Definition: str.c:991
RZ_API int rz_str_ansi_filter(char *str, char **out, int **cposs, int len)
Definition: str.c:2124
RZ_API char * rz_str_dup(char *ptr, const char *string)
Definition: str.c:1021
RZ_API char * rz_str_format_msvc_argv(size_t argc, const char **argv)
Definition: str.c:1844
RZ_API bool rz_str_is_utf8(RZ_NONNULL const char *str)
Returns true if the input string is correctly UTF-8-encoded.
Definition: str.c:2023
RZ_API void rz_str_case(char *str, bool up)
Definition: str.c:341
RZ_API const char * rz_str_enc_as_string(RzStrEnc enc)
Definition: str.c:44
RZ_API RZ_OWN RzList * rz_str_split_list_regex(RZ_NONNULL char *str, RZ_NONNULL const char *r, int n)
Split the string str according to the regex r and returns a RzList with the result.
Definition: str.c:3445
RZ_API const char * rz_str_ansi_chrn(const char *str, size_t n)
Definition: str.c:2098
RZ_API char * rz_str_escape_mutf8_for_json(const char *buf, int buf_size)
Definition: str.c:1838
static void trimbits(char *b)
Definition: str.c:233
RZ_API char * rz_str_word_get_first(const char *text)
Definition: str.c:637
RZ_API int rz_str_binstr2bin(const char *str, ut8 *out, int outlen)
Definition: str.c:284
RZ_API char * rz_str_wc_to_mb(const wchar_t *buf)
Definition: str.c:3777
static char * rz_str_escape_utf(const char *buf, int buf_size, RzStrEnc enc, bool show_asciidot, bool esc_bslash, bool esc_double_quotes, bool keep_printable)
Definition: str.c:1599
RZ_API bool rz_str_startswith_icase(RZ_NONNULL const char *str, RZ_NONNULL const char *needle)
Checks if a string starts with a specifc sequence of characters (case insensitive)
Definition: str.c:3301
RZ_API size_t rz_str_utf8_codepoint(const char *s, size_t left)
Definition: str.c:2264
RZ_API char * rz_str_array_join(const char **a, size_t n, const char *sep)
Definition: str.c:3861
RZ_API int rz_str_do_until_token(str_operation op, char *str, const char tok)
Definition: str.c:3219
RZ_API int rz_str_bounds(const char *_str, int *h)
Definition: str.c:3124
RZ_API char * rz_str_home(const char *str)
Definition: str.c:354
RZ_API const char * rz_str_rstr(const char *base, const char *p)
Definition: str.c:814
RZ_API int rz_str_replace_char_once(char *s, int a, int b)
Definition: str.c:165
RZ_API size_t rz_str_nlen_w(const char *str, int n)
Definition: str.c:1966
RZ_API char * rz_str_uri_encode(const char *s)
Definition: str.c:2860
RZ_API char * rz_str_utf16_encode(const char *s, int len)
Definition: str.c:2993
RZ_API int rz_str_bits64(char *strout, ut64 in)
Definition: str.c:244
RZ_API char * rz_str_escape_utf32le(const char *buf, int buf_size, RzStrEscOptions *opt)
Definition: str.c:1711
RZ_API RzList * rz_str_split_duplist(const char *_str, const char *c, bool trim)
Split the string str according to the substring c and returns a RzList with the result.
Definition: str.c:3464
RZ_API bool rz_str_is_printable_limited(const char *str, int size)
Definition: str.c:2053
RZ_API bool rz_str_glob(const char *str, const char *glob)
Definition: str.c:2368
RZ_API int rz_str_cmp(const char *a, const char *b, int len)
Definition: str.c:974
RZ_API int rz_str_delta(char *p, char a, char b)
Definition: str.c:394
#define CAST
Definition: str.c:3075
RZ_API void rz_str_range_foreach(const char *r, RzStrRangeCallback cb, void *u)
Definition: str.c:2779
RZ_API void rz_str_filter(char *str)
Convert all non-printable characters in str with '.'.
Definition: str.c:2359
RZ_API size_t rz_str_nlen(const char *str, size_t n)
Definition: str.c:1949
RZ_API char * rz_str_prepend(char *ptr, const char *string)
Definition: str.c:1027
RZ_API RzList * rz_str_wrap(char *str, size_t width)
Definition: str.c:3996
RZ_API char * rz_str_escape_8bit(const char *buf, bool colors, RzStrEscOptions *opt)
Definition: str.c:1595
RZ_API char * rz_str_escape_utf8(const char *buf, RzStrEscOptions *opt)
Definition: str.c:1699
RZ_API bool rz_str_isnumber(const char *str)
Definition: str.c:3550
static RzList * str_split_list_common(char *str, const char *c, int n, bool trim, bool dup)
Definition: str.c:3344
RZ_API char * rz_str_newlen(const char *str, int len)
Definition: str.c:871
RZ_API size_t rz_str_len_utf8(const char *s)
Definition: str.c:2709
RZ_API const char * rz_str_tok(const char *str1, const char b, size_t len)
Definition: str.c:3199
RZ_API int rz_str_bits(char *strout, const ut8 *buf, int len, const char *bitz)
Definition: str.c:195
RZ_API char * rz_str_prefix_all(const char *s, const char *pfx)
Definition: str.c:3038
RZ_API bool rz_str_is2utf8(RZ_NONNULL const char *c)
Checks if the given character string is a two byte UTF-8 character.
Definition: str.c:703
RZ_API char * rz_str_utf16_decode(const ut8 *s, int len)
Definition: str.c:2961
RZ_API const char * rz_str_rsep(const char *base, const char *p, const char *sep)
Definition: str.c:801
RZ_API char * rz_str_replace_thunked(char *str, char *clean, int *thunk, int clen, const char *key, const char *val, int g)
Definition: str.c:1233
RZ_API size_t rz_wstr_clen(const char *s)
Definition: str.c:2087
#define HASCH(x)
Definition: str.c:3074
RZ_API char * rz_str_replace(char *str, const char *key, const char *val, int g)
Definition: str.c:1110
RZ_API size_t rz_str_ncpy(char *dst, const char *src, size_t dst_size)
Secure string copy with null terminator.
Definition: str.c:923
RZ_API int rz_str_casecmp(const char *s1, const char *s2)
Definition: str.c:121
RZ_API bool rz_str_is_whitespace(RZ_NONNULL const char *str)
Checks if the whole string is composed of whitespace.
Definition: str.c:2004
RZ_API const char * rz_sub_str_rchr(const char *str, int start, int end, char chr)
Definition: str.c:690
static int strncmp_skip_color_codes(const char *s1, const char *s2, int n)
Definition: str.c:3605
RZ_API bool rz_str_is_printable_incl_newlines(const char *str)
Definition: str.c:2069
RZ_API bool rz_str_is3utf8(RZ_NONNULL const char *c)
Checks if the given character string is a three byte UTF-8 character.
Definition: str.c:717
RZ_API const char * rz_str_firstbut(const char *s, char ch, const char *but)
Definition: str.c:2644
RZ_API char * rz_str_escape_utf32be(const char *buf, int buf_size, RzStrEscOptions *opt)
Definition: str.c:1719
RZ_API const char * rz_str_strchr(RZ_NONNULL const char *str, RZ_NONNULL const char *c)
Returns a pointer to the first occurrence of UTF-8 character c in the string s.
Definition: str.c:768
RZ_API char * rz_str_ansi_crop(const char *str, ut32 x, ut32 y, ut32 x2, ut32 y2)
Definition: str.c:2174
RZ_API bool rz_str_is_printable(const char *str)
Definition: str.c:2038
RZ_API char * rz_str_trunc_ellipsis(const char *str, int len)
Definition: str.c:883
RZ_API int rz_str_word_set0(char *str)
Definition: str.c:423
RZ_API char * rz_str_path_escape(const char *path)
Definition: str.c:2463
RZ_API bool rz_str_is_bool(const char *val)
Definition: str.c:3908
RZ_API bool rz_str_startswith(RZ_NONNULL const char *str, RZ_NONNULL const char *needle)
Checks if a string starts with a specifc sequence of characters (case sensitive)
Definition: str.c:3286
RZ_API char * rz_str_highlight(char *str, const char *word, const char *color, const char *color_reset)
Definition: str.c:3657
static char * escape_utf8_for_json(const char *buf, int buf_size, bool mutf8)
Definition: str.c:1723
RZ_API bool rz_str_isXutf8(RZ_NONNULL const char *c, ut8 x)
Checks if the byte string matches the criteria of a UTF-8 character of length x.
Definition: str.c:745
RZ_API wchar_t * rz_str_mb_to_wc(const char *buf)
Definition: str.c:3784
RZ_API const char * rz_strstr_ansi(const char *a, const char *b)
Definition: str.c:2742
RZ_API char * rz_str_escape_utf16le(const char *buf, int buf_size, RzStrEscOptions *opt)
Definition: str.c:1707
RZ_API char * rz_str_scale(const char *s, int w, int h)
Definition: str.c:3921
RZ_API size_t rz_str_len_utf8char(const char *s, int left)
Definition: str.c:2697
RZ_API int rz_str_replace_char(char *s, int a, int b)
Definition: str.c:169
RZ_API const char * rz_str_casestr(const char *a, const char *b)
Definition: str.c:2757
RZ_API bool rz_str_ccmp(const char *dst, const char *src, int ch)
Definition: str.c:941
RZ_API const char * rz_sub_str_lchr(const char *str, int start, int end, char chr)
Definition: str.c:682
RZ_API size_t rz_str_utf8_charsize(const char *str)
Definition: str.c:2298
RZ_API size_t rz_str_len_utf8_ansi(const char *str)
Definition: str.c:2723
static char * strchr_skip_color_codes(const char *s, int c)
Definition: str.c:3637
RZ_API size_t * rz_str_split_lines(char *str, size_t *count)
Split the string str in lines and returns the result in an array.
Definition: str.c:3526
RZ_API char * rz_str_escape_utf8_for_json(const char *buf, int buf_size)
Definition: str.c:1834
RZ_API char * rz_str_version(const char *program)
Definition: str.c:4051
RZ_API char * rz_str_word_get0set(char *stra, int stralen, int idx, const char *newstr, int *newlen)
Definition: str.c:548
RZ_API RzStrEnc rz_str_guess_encoding_from_buffer(RZ_NONNULL const ut8 *buffer, ut32 length)
Tries to guess the string encoding method from the buffer.
Definition: str.c:4089
RZ_API RzList * rz_str_split_list(char *str, const char *c, int n)
Split the string str according to the substring c and returns a RzList with the result.
Definition: str.c:3429
RZ_API int rz_str_unescape(char *buf)
Definition: str.c:1300
RZ_API void rz_str_filter_zeroline(char *str, int len)
Definition: str.c:2341
RZ_API int rz_snprintf(char *string, int len, const char *fmt,...)
Definition: str.c:3804
RZ_API const char * rz_str_word_get0(const char *str, int idx)
Definition: str.c:598
RZ_API bool rz_str_is_ascii(const char *str)
Definition: str.c:1988
RZ_API void rz_str_remove_char(char *str, char c)
Definition: str.c:173
RZ_API const char * rz_str_lastbut(const char *s, char ch, const char *but)
Definition: str.c:2670
static RZ_OWN char * rz_str_escape_(const char *buf, bool parse_esc_seq, bool ign_esc_seq, RzStrEscOptions *opt)
Definition: str.c:1503
RZ_API bool rz_str_endswith_icase(RZ_NONNULL const char *str, RZ_NONNULL const char *needle)
Checks if a string ends with a specifc sequence of characters (case insensitive)
Definition: str.c:3340
RZ_API bool rz_str_endswith(RZ_NONNULL const char *str, RZ_NONNULL const char *needle)
Checks if a string ends with a specifc sequence of characters (case sensitive)
Definition: str.c:3329
RZ_API wchar_t * rz_str_mb_to_wc_l(const char *buf, int len)
Definition: str.c:3722
static const char * word_get_first(const char *text)
Definition: str.c:629
RZ_API void rz_str_argv_free(char **argv)
Definition: str.c:2633
RZ_API char * rz_str_list_join(RzList *str, const char *sep)
Definition: str.c:3849
RZ_API void rz_str_reverse(char *str)
Definition: str.c:183
RZ_API void rz_str_sanitize(char *c)
Definition: str.c:1381
RZ_API char * rz_str_nextword(char *s, char ch)
Definition: str.c:3912
RZ_API const char * rz_str_sysbits(const int v)
Definition: str.c:217
RZ_API char * rz_str_from_ut64(ut64 val)
Definition: str.c:3791
RZ_API const char * rz_str_closer_chr(const char *b, const char *s)
Definition: str.c:3111
RZ_API RZ_OWN char * rz_str_stringify_raw_buffer(RzStrStringifyOpt *option, RZ_NULLABLE RZ_OUT ut32 *length)
Converts a raw buffer to a printable string based on the selected options.
Definition: str.c:4141
RZ_API const char * rz_str_nstr(const char *s, const char *find, int slen)
Definition: str.c:842
RZ_API size_t rz_str_split(char *str, char ch)
Split string str in place by using ch as a delimiter.
Definition: str.c:406
RZ_API int rz_str_write(int fd, const char *b)
Definition: str.c:2775
RZ_API char * rz_str_arg_escape(const char *arg)
Definition: str.c:2413
RZ_API char * rz_str_escape_sh(const char *buf)
Definition: str.c:1560
Group together some common options used by string escaping functions.
Definition: rz_str.h:39
bool esc_bslash
When true, backslashes \ are quoted with \\
Definition: rz_str.h:41
bool show_asciidot
When true, dots . are placed instead of unprintable characters.
Definition: rz_str.h:40
bool esc_double_quotes
When true, double quotes "</tt> are quoted with <tt>\\"
Definition: rz_str.h:42
bool dot_nl
When true, is converted into the graphiz-compatible newline \l.
Definition: rz_str.h:43
Definition: buffer.h:15
Definition: getopt.h:84
int pos
Definition: main.c:11
int width
Definition: main.c:10
ut64 buflen
Definition: core.c:76
#define fail(test)
Definition: tests.h:29
Definition: dis.c:32
static int color
Definition: visual.c:20
static st64 delta
Definition: vmenus.c:2425
ut64(WINAPI *w32_GetEnabledXStateFeatures)()
static const z80_opcode fd[]
Definition: z80_tab.h:997
static const char * cb[]
Definition: z80_tab.h:176
static int addr
Definition: z80asm.c:58