Blender  V3.3
string.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2001-2002 NaN Holding BV. All rights reserved. */
3 
8 #include <ctype.h>
9 #include <inttypes.h>
10 #include <math.h>
11 #include <stdarg.h>
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 
16 #include "MEM_guardedalloc.h"
17 
18 #include "BLI_dynstr.h"
19 #include "BLI_string.h"
20 
21 #include "BLI_utildefines.h"
22 
23 #ifdef __GNUC__
24 # pragma GCC diagnostic error "-Wsign-conversion"
25 #endif
26 
27 // #define DEBUG_STRSIZE
28 
29 /* -------------------------------------------------------------------- */
33 char *BLI_strdupn(const char *str, const size_t len)
34 {
35  char *n = MEM_mallocN(len + 1, "strdup");
36  memcpy(n, str, len);
37  n[len] = '\0';
38 
39  return n;
40 }
41 
42 char *BLI_strdup(const char *str)
43 {
44  return BLI_strdupn(str, strlen(str));
45 }
46 
47 char *BLI_strdupcat(const char *__restrict str1, const char *__restrict str2)
48 {
49  /* include the NULL terminator of str2 only */
50  const size_t str1_len = strlen(str1);
51  const size_t str2_len = strlen(str2) + 1;
52  char *str, *s;
53 
54  str = MEM_mallocN(str1_len + str2_len, "strdupcat");
55  s = str;
56 
57  memcpy(s, str1, str1_len); /* NOLINT: bugprone-not-null-terminated-result */
58  s += str1_len;
59  memcpy(s, str2, str2_len);
60 
61  return str;
62 }
63 
64 char *BLI_strncpy(char *__restrict dst, const char *__restrict src, const size_t maxncpy)
65 {
66  size_t srclen = BLI_strnlen(src, maxncpy - 1);
67  BLI_assert(maxncpy != 0);
68 
69 #ifdef DEBUG_STRSIZE
70  memset(dst, 0xff, sizeof(*dst) * maxncpy);
71 #endif
72 
73  memcpy(dst, src, srclen);
74  dst[srclen] = '\0';
75  return dst;
76 }
77 
78 char *BLI_strncpy_ensure_pad(char *__restrict dst,
79  const char *__restrict src,
80  const char pad,
81  size_t maxncpy)
82 {
83  BLI_assert(maxncpy != 0);
84 
85 #ifdef DEBUG_STRSIZE
86  memset(dst, 0xff, sizeof(*dst) * maxncpy);
87 #endif
88 
89  if (src[0] == '\0') {
90  dst[0] = '\0';
91  }
92  else {
93  /* Add heading/trailing wildcards if needed. */
94  size_t idx = 0;
95  size_t srclen;
96 
97  if (src[idx] != pad) {
98  dst[idx++] = pad;
99  maxncpy--;
100  }
101  maxncpy--; /* trailing '\0' */
102 
103  srclen = BLI_strnlen(src, maxncpy);
104  if ((src[srclen - 1] != pad) && (srclen == maxncpy)) {
105  srclen--;
106  }
107 
108  memcpy(&dst[idx], src, srclen);
109  idx += srclen;
110 
111  if (dst[idx - 1] != pad) {
112  dst[idx++] = pad;
113  }
114  dst[idx] = '\0';
115  }
116 
117  return dst;
118 }
119 
120 size_t BLI_strncpy_rlen(char *__restrict dst, const char *__restrict src, const size_t maxncpy)
121 {
122  size_t srclen = BLI_strnlen(src, maxncpy - 1);
123  BLI_assert(maxncpy != 0);
124 
125 #ifdef DEBUG_STRSIZE
126  memset(dst, 0xff, sizeof(*dst) * maxncpy);
127 #endif
128 
129  memcpy(dst, src, srclen);
130  dst[srclen] = '\0';
131  return srclen;
132 }
133 
134 size_t BLI_strcpy_rlen(char *__restrict dst, const char *__restrict src)
135 {
136  size_t srclen = strlen(src);
137  memcpy(dst, src, srclen + 1);
138  return srclen;
139 }
140 
143 /* -------------------------------------------------------------------- */
147 size_t BLI_vsnprintf(char *__restrict buffer,
148  size_t maxncpy,
149  const char *__restrict format,
150  va_list arg)
151 {
152  size_t n;
153 
154  BLI_assert(buffer != NULL);
155  BLI_assert(maxncpy > 0);
156  BLI_assert(format != NULL);
157 
158  n = (size_t)vsnprintf(buffer, maxncpy, format, arg);
159 
160  if (n != -1 && n < maxncpy) {
161  buffer[n] = '\0';
162  }
163  else {
164  buffer[maxncpy - 1] = '\0';
165  }
166 
167  return n;
168 }
169 
170 size_t BLI_vsnprintf_rlen(char *__restrict buffer,
171  size_t maxncpy,
172  const char *__restrict format,
173  va_list arg)
174 {
175  size_t n;
176 
177  BLI_assert(buffer != NULL);
178  BLI_assert(maxncpy > 0);
179  BLI_assert(format != NULL);
180 
181  n = (size_t)vsnprintf(buffer, maxncpy, format, arg);
182 
183  if (n != -1 && n < maxncpy) {
184  /* pass */
185  }
186  else {
187  n = maxncpy - 1;
188  }
189  buffer[n] = '\0';
190 
191  return n;
192 }
193 
194 size_t BLI_snprintf(char *__restrict dst, size_t maxncpy, const char *__restrict format, ...)
195 {
196  size_t n;
197  va_list arg;
198 
199 #ifdef DEBUG_STRSIZE
200  memset(dst, 0xff, sizeof(*dst) * maxncpy);
201 #endif
202 
203  va_start(arg, format);
204  n = BLI_vsnprintf(dst, maxncpy, format, arg);
205  va_end(arg);
206 
207  return n;
208 }
209 
210 size_t BLI_snprintf_rlen(char *__restrict dst, size_t maxncpy, const char *__restrict format, ...)
211 {
212  size_t n;
213  va_list arg;
214 
215 #ifdef DEBUG_STRSIZE
216  memset(dst, 0xff, sizeof(*dst) * maxncpy);
217 #endif
218 
219  va_start(arg, format);
220  n = BLI_vsnprintf_rlen(dst, maxncpy, format, arg);
221  va_end(arg);
222 
223  return n;
224 }
225 
226 char *BLI_sprintfN(const char *__restrict format, ...)
227 {
228  DynStr *ds;
229  va_list arg;
230  char *n;
231 
232  va_start(arg, format);
233 
234  ds = BLI_dynstr_new();
235  BLI_dynstr_vappendf(ds, format, arg);
236  n = BLI_dynstr_get_cstring(ds);
237  BLI_dynstr_free(ds);
238 
239  va_end(arg);
240 
241  return n;
242 }
243 
246 /* -------------------------------------------------------------------- */
250 size_t BLI_str_escape(char *__restrict dst, const char *__restrict src, const size_t dst_maxncpy)
251 {
252 
253  BLI_assert(dst_maxncpy != 0);
254 
255  size_t len = 0;
256  for (; (len < dst_maxncpy) && (*src != '\0'); dst++, src++, len++) {
257  char c = *src;
258  if (ELEM(c, '\\', '"') || /* Use as-is. */
259  ((c == '\t') && ((void)(c = 't'), true)) || /* Tab. */
260  ((c == '\n') && ((void)(c = 'n'), true)) || /* Newline. */
261  ((c == '\r') && ((void)(c = 'r'), true)) || /* Carriage return. */
262  ((c == '\a') && ((void)(c = 'a'), true)) || /* Bell. */
263  ((c == '\b') && ((void)(c = 'b'), true)) || /* Backspace. */
264  ((c == '\f') && ((void)(c = 'f'), true))) /* Form-feed. */
265  {
266  if (UNLIKELY(len + 1 >= dst_maxncpy)) {
267  /* Not enough space to escape. */
268  break;
269  }
270  *dst++ = '\\';
271  len++;
272  }
273  *dst = c;
274  }
275  *dst = '\0';
276 
277  return len;
278 }
279 
280 BLI_INLINE bool str_unescape_pair(char c_next, char *r_out)
281 {
282 #define CASE_PAIR(value_src, value_dst) \
283  case value_src: { \
284  *r_out = value_dst; \
285  return true; \
286  }
287  switch (c_next) {
288  CASE_PAIR('"', '"'); /* Quote. */
289  CASE_PAIR('\\', '\\'); /* Backslash. */
290  CASE_PAIR('t', '\t'); /* Tab. */
291  CASE_PAIR('n', '\n'); /* Newline. */
292  CASE_PAIR('r', '\r'); /* Carriage return. */
293  CASE_PAIR('a', '\a'); /* Bell. */
294  CASE_PAIR('b', '\b'); /* Backspace. */
295  CASE_PAIR('f', '\f'); /* Form-feed. */
296  }
297 #undef CASE_PAIR
298  return false;
299 }
300 
301 size_t BLI_str_unescape_ex(char *__restrict dst,
302  const char *__restrict src,
303  const size_t src_maxncpy,
304  /* Additional arguments to #BLI_str_unescape */
305  const size_t dst_maxncpy,
306  bool *r_is_complete)
307 {
308  size_t len = 0;
309  bool is_complete = true;
310  const size_t max_strlen = dst_maxncpy - 1; /* Account for trailing zero byte. */
311  for (const char *src_end = src + src_maxncpy; (src < src_end) && *src; src++) {
312  if (UNLIKELY(len == max_strlen)) {
313  is_complete = false;
314  break;
315  }
316  char c = *src;
317  if (UNLIKELY(c == '\\') && (str_unescape_pair(*(src + 1), &c))) {
318  src++;
319  }
320  dst[len++] = c;
321  }
322  dst[len] = 0;
323  *r_is_complete = is_complete;
324  return len;
325 }
326 
327 size_t BLI_str_unescape(char *__restrict dst, const char *__restrict src, const size_t src_maxncpy)
328 {
329  size_t len = 0;
330  for (const char *src_end = src + src_maxncpy; (src < src_end) && *src; src++) {
331  char c = *src;
332  if (UNLIKELY(c == '\\') && (str_unescape_pair(*(src + 1), &c))) {
333  src++;
334  }
335  dst[len++] = c;
336  }
337  dst[len] = 0;
338  return len;
339 }
340 
341 const char *BLI_str_escape_find_quote(const char *str)
342 {
343  bool escape = false;
344  while (*str && (*str != '"' || escape)) {
345  /* A pair of back-slashes represents a single back-slash,
346  * only use a single back-slash for escaping. */
347  escape = (escape == false) && (*str == '\\');
348  str++;
349  }
350  return (*str == '"') ? str : NULL;
351 }
352 
355 /* -------------------------------------------------------------------- */
359 bool BLI_str_quoted_substr_range(const char *__restrict str,
360  const char *__restrict prefix,
361  int *__restrict r_start,
362  int *__restrict r_end)
363 {
364  const char *str_start = strstr(str, prefix);
365  if (str_start == NULL) {
366  return false;
367  }
368  const size_t prefix_len = strlen(prefix);
369  if (UNLIKELY(prefix_len == 0)) {
370  BLI_assert_msg(0,
371  "Zero length prefix passed in, "
372  "caller must prevent this from happening!");
373  return false;
374  }
375  BLI_assert_msg(prefix[prefix_len - 1] != '"',
376  "Prefix includes trailing quote, "
377  "caller must prevent this from happening!");
378 
379  str_start += prefix_len;
380  if (UNLIKELY(*str_start != '\"')) {
381  return false;
382  }
383  str_start += 1;
384  const char *str_end = BLI_str_escape_find_quote(str_start);
385  if (UNLIKELY(str_end == NULL)) {
386  return false;
387  }
388 
389  *r_start = (int)(str_start - str);
390  *r_end = (int)(str_end - str);
391  return true;
392 }
393 
394 /* NOTE(@campbellbarton): in principal it should be possible to access a quoted string
395  * with an arbitrary size, currently all callers for this functionality
396  * happened to use a fixed size buffer, so only #BLI_str_quoted_substr is needed. */
397 #if 0
408 char *BLI_str_quoted_substrN(const char *__restrict str, const char *__restrict prefix)
409 {
410  int start_match_ofs, end_match_ofs;
411  if (!BLI_str_quoted_substr_range(str, prefix, &start_match_ofs, &end_match_ofs)) {
412  return NULL;
413  }
414  const size_t escaped_len = (size_t)(end_match_ofs - start_match_ofs);
415  char *result = MEM_mallocN(sizeof(char) * (escaped_len + 1), __func__);
416  const size_t unescaped_len = BLI_str_unescape(result, str + start_match_ofs, escaped_len);
417  if (unescaped_len != escaped_len) {
418  result = MEM_reallocN(result, sizeof(char) * (unescaped_len + 1));
419  }
420  return result;
421 }
422 #endif
423 
424 bool BLI_str_quoted_substr(const char *__restrict str,
425  const char *__restrict prefix,
426  char *result,
427  size_t result_maxlen)
428 {
429  int start_match_ofs, end_match_ofs;
430  if (!BLI_str_quoted_substr_range(str, prefix, &start_match_ofs, &end_match_ofs)) {
431  return false;
432  }
433  const size_t escaped_len = (size_t)(end_match_ofs - start_match_ofs);
434  bool is_complete;
435  BLI_str_unescape_ex(result, str + start_match_ofs, escaped_len, result_maxlen, &is_complete);
436  if (is_complete == false) {
437  *result = '\0';
438  }
439  return is_complete;
440 }
441 
444 /* -------------------------------------------------------------------- */
448 char *BLI_str_replaceN(const char *__restrict str,
449  const char *__restrict substr_old,
450  const char *__restrict substr_new)
451 {
452  DynStr *ds = NULL;
453  size_t len_old = strlen(substr_old);
454  const char *match;
455 
456  BLI_assert(substr_old[0] != '\0');
457 
458  /* While we can still find a match for the old sub-string that we're searching for,
459  * keep dicing and replacing. */
460  while ((match = strstr(str, substr_old))) {
461  /* the assembly buffer only gets created when we actually need to rebuild the string */
462  if (ds == NULL) {
463  ds = BLI_dynstr_new();
464  }
465 
466  /* If the match position does not match the current position in the string,
467  * copy the text up to this position and advance the current position in the string. */
468  if (str != match) {
469  /* Add the segment of the string from `str` to match to the buffer,
470  * then restore the value at match. */
471  BLI_dynstr_nappend(ds, str, (match - str));
472 
473  /* now our current position should be set on the start of the match */
474  str = match;
475  }
476 
477  /* Add the replacement text to the accumulation buffer. */
478  BLI_dynstr_append(ds, substr_new);
479 
480  /* Advance the current position of the string up to the end of the replaced segment. */
481  str += len_old;
482  }
483 
484  /* Finish off and return a new string that has had all occurrences of. */
485  if (ds) {
486  char *str_new;
487 
488  /* Add what's left of the string to the assembly buffer
489  * - we've been adjusting `str` to point at the end of the replaced segments. */
490  BLI_dynstr_append(ds, str);
491 
492  /* Convert to new c-string (MEM_malloc'd), and free the buffer. */
493  str_new = BLI_dynstr_get_cstring(ds);
494  BLI_dynstr_free(ds);
495 
496  return str_new;
497  }
498  /* Just create a new copy of the entire string - we avoid going through the assembly buffer
499  * for what should be a bit more efficiency. */
500  return BLI_strdup(str);
501 }
502 
503 void BLI_str_replace_char(char *str, char src, char dst)
504 {
505  while (*str) {
506  if (*str == src) {
507  *str = dst;
508  }
509  str++;
510  }
511 }
512 
513 bool BLI_str_replace_table_exact(char *string,
514  const size_t string_len,
515  const char *replace_table[][2],
516  int replace_table_len)
517 {
518  for (int i = 0; i < replace_table_len; i++) {
519  if (STREQ(string, replace_table[i][0])) {
520  BLI_strncpy(string, replace_table[i][1], string_len);
521  return true;
522  }
523  }
524  return false;
525 }
526 
529 /* -------------------------------------------------------------------- */
533 int BLI_strcaseeq(const char *a, const char *b)
534 {
535  return (BLI_strcasecmp(a, b) == 0);
536 }
537 
538 char *BLI_strcasestr(const char *s, const char *find)
539 {
540  char c, sc;
541  size_t len;
542 
543  if ((c = *find++) != 0) {
544  c = tolower(c);
545  len = strlen(find);
546  do {
547  do {
548  if ((sc = *s++) == 0) {
549  return NULL;
550  }
551  sc = tolower(sc);
552  } while (sc != c);
553  } while (BLI_strncasecmp(s, find, len) != 0);
554  s--;
555  }
556  return ((char *)s);
557 }
558 
560 {
561  return (str_len / 2) + 1;
562 }
563 
564 bool BLI_string_has_word_prefix(const char *haystack, const char *needle, size_t needle_len)
565 {
566  const char *match = BLI_strncasestr(haystack, needle, needle_len);
567  if (match) {
568  if ((match == haystack) || (*(match - 1) == ' ') || ispunct(*(match - 1))) {
569  return true;
570  }
571  return BLI_string_has_word_prefix(match + 1, needle, needle_len);
572  }
573  return false;
574 }
575 
576 bool BLI_string_all_words_matched(const char *name,
577  const char *str,
578  int (*words)[2],
579  const int words_len)
580 {
581  int index;
582  for (index = 0; index < words_len; index++) {
583  if (!BLI_string_has_word_prefix(name, str + words[index][0], (size_t)words[index][1])) {
584  break;
585  }
586  }
587  const bool all_words_matched = (index == words_len);
588 
589  return all_words_matched;
590 }
591 
592 char *BLI_strncasestr(const char *s, const char *find, size_t len)
593 {
594  char c, sc;
595 
596  if ((c = *find++) != 0) {
597  c = tolower(c);
598  if (len > 1) {
599  do {
600  do {
601  if ((sc = *s++) == 0) {
602  return NULL;
603  }
604  sc = tolower(sc);
605  } while (sc != c);
606  } while (BLI_strncasecmp(s, find, len - 1) != 0);
607  }
608  else {
609  {
610  do {
611  if ((sc = *s++) == 0) {
612  return NULL;
613  }
614  sc = tolower(sc);
615  } while (sc != c);
616  }
617  }
618  s--;
619  }
620  return ((char *)s);
621 }
622 
623 int BLI_strcasecmp(const char *s1, const char *s2)
624 {
625  int i;
626  char c1, c2;
627 
628  for (i = 0;; i++) {
629  c1 = tolower(s1[i]);
630  c2 = tolower(s2[i]);
631 
632  if (c1 < c2) {
633  return -1;
634  }
635  if (c1 > c2) {
636  return 1;
637  }
638  if (c1 == 0) {
639  break;
640  }
641  }
642 
643  return 0;
644 }
645 
646 int BLI_strncasecmp(const char *s1, const char *s2, size_t len)
647 {
648  size_t i;
649  char c1, c2;
650 
651  for (i = 0; i < len; i++) {
652  c1 = tolower(s1[i]);
653  c2 = tolower(s2[i]);
654 
655  if (c1 < c2) {
656  return -1;
657  }
658  if (c1 > c2) {
659  return 1;
660  }
661  if (c1 == 0) {
662  break;
663  }
664  }
665 
666  return 0;
667 }
668 
669 /* compare number on the left size of the string */
670 static int left_number_strcmp(const char *s1, const char *s2, int *tiebreaker)
671 {
672  const char *p1 = s1, *p2 = s2;
673  int numdigit, numzero1, numzero2;
674 
675  /* count and skip leading zeros */
676  for (numzero1 = 0; *p1 == '0'; numzero1++) {
677  p1++;
678  }
679  for (numzero2 = 0; *p2 == '0'; numzero2++) {
680  p2++;
681  }
682 
683  /* find number of consecutive digits */
684  for (numdigit = 0;; numdigit++) {
685  if (isdigit(*(p1 + numdigit)) && isdigit(*(p2 + numdigit))) {
686  continue;
687  }
688  if (isdigit(*(p1 + numdigit))) {
689  return 1; /* s2 is bigger */
690  }
691  if (isdigit(*(p2 + numdigit))) {
692  return -1; /* s1 is bigger */
693  }
694  break;
695  }
696 
697  /* same number of digits, compare size of number */
698  if (numdigit > 0) {
699  int compare = (int)strncmp(p1, p2, (size_t)numdigit);
700 
701  if (compare != 0) {
702  return compare;
703  }
704  }
705 
706  /* use number of leading zeros as tie breaker if still equal */
707  if (*tiebreaker == 0) {
708  if (numzero1 > numzero2) {
709  *tiebreaker = 1;
710  }
711  else if (numzero1 < numzero2) {
712  *tiebreaker = -1;
713  }
714  }
715 
716  return 0;
717 }
718 
719 int BLI_strcasecmp_natural(const char *s1, const char *s2)
720 {
721  int d1 = 0, d2 = 0;
722  char c1, c2;
723  int tiebreaker = 0;
724 
725  /* if both chars are numeric, to a left_number_strcmp().
726  * then increase string deltas as long they are
727  * numeric, else do a tolower and char compare */
728 
729  while (1) {
730  if (isdigit(s1[d1]) && isdigit(s2[d2])) {
731  int numcompare = left_number_strcmp(s1 + d1, s2 + d2, &tiebreaker);
732 
733  if (numcompare != 0) {
734  return numcompare;
735  }
736 
737  /* Some wasted work here, left_number_strcmp already consumes at least some digits. */
738  d1++;
739  while (isdigit(s1[d1])) {
740  d1++;
741  }
742  d2++;
743  while (isdigit(s2[d2])) {
744  d2++;
745  }
746  }
747 
748  /* Test for end of strings first so that shorter strings are ordered in front. */
749  if (ELEM(0, s1[d1], s2[d2])) {
750  break;
751  }
752 
753  c1 = tolower(s1[d1]);
754  c2 = tolower(s2[d2]);
755 
756  if (c1 == c2) {
757  /* Continue iteration */
758  }
759  /* Check for '.' so "foo.bar" comes before "foo 1.bar". */
760  else if (c1 == '.') {
761  return -1;
762  }
763  else if (c2 == '.') {
764  return 1;
765  }
766  else if (c1 < c2) {
767  return -1;
768  }
769  else if (c1 > c2) {
770  return 1;
771  }
772 
773  d1++;
774  d2++;
775  }
776 
777  if (tiebreaker) {
778  return tiebreaker;
779  }
780 
781  /* we might still have a different string because of lower/upper case, in
782  * that case fall back to regular string comparison */
783  return strcmp(s1, s2);
784 }
785 
786 int BLI_strcmp_ignore_pad(const char *str1, const char *str2, const char pad)
787 {
788  size_t str1_len, str2_len;
789 
790  while (*str1 == pad) {
791  str1++;
792  }
793  while (*str2 == pad) {
794  str2++;
795  }
796 
797  str1_len = strlen(str1);
798  str2_len = strlen(str2);
799 
800  while (str1_len && (str1[str1_len - 1] == pad)) {
801  str1_len--;
802  }
803  while (str2_len && (str2[str2_len - 1] == pad)) {
804  str2_len--;
805  }
806 
807  if (str1_len == str2_len) {
808  return strncmp(str1, str2, str2_len);
809  }
810  if (str1_len > str2_len) {
811  int ret = strncmp(str1, str2, str2_len);
812  if (ret == 0) {
813  ret = 1;
814  }
815  return ret;
816  }
817  {
818  int ret = strncmp(str1, str2, str1_len);
819  if (ret == 0) {
820  ret = -1;
821  }
822  return ret;
823  }
824 }
825 
828 /* -------------------------------------------------------------------- */
832 int BLI_str_index_in_array_n(const char *__restrict str,
833  const char **__restrict str_array,
834  const int str_array_len)
835 {
836  int index;
837  const char **str_iter = str_array;
838 
839  for (index = 0; index < str_array_len; str_iter++, index++) {
840  if (STREQ(str, *str_iter)) {
841  return index;
842  }
843  }
844  return -1;
845 }
846 
847 int BLI_str_index_in_array(const char *__restrict str, const char **__restrict str_array)
848 {
849  int index;
850  const char **str_iter = str_array;
851 
852  for (index = 0; *str_iter; str_iter++, index++) {
853  if (STREQ(str, *str_iter)) {
854  return index;
855  }
856  }
857  return -1;
858 }
859 
860 bool BLI_str_startswith(const char *__restrict str, const char *__restrict start)
861 {
862  for (; *str && *start; str++, start++) {
863  if (*str != *start) {
864  return false;
865  }
866  }
867 
868  return (*start == '\0');
869 }
870 
871 bool BLI_strn_endswith(const char *__restrict str, const char *__restrict end, size_t slength)
872 {
873  size_t elength = strlen(end);
874 
875  if (elength < slength) {
876  const char *iter = &str[slength - elength];
877  while (*iter) {
878  if (*iter++ != *end++) {
879  return false;
880  }
881  }
882  return true;
883  }
884  return false;
885 }
886 
887 bool BLI_str_endswith(const char *__restrict str, const char *__restrict end)
888 {
889  const size_t slength = strlen(str);
890  return BLI_strn_endswith(str, end, slength);
891 }
892 
895 /* -------------------------------------------------------------------- */
899 size_t BLI_strnlen(const char *s, const size_t maxlen)
900 {
901  size_t len;
902 
903  for (len = 0; len < maxlen; len++, s++) {
904  if (!*s) {
905  break;
906  }
907  }
908  return len;
909 }
910 
913 /* -------------------------------------------------------------------- */
917 char BLI_tolower_ascii(const char c)
918 {
919  return (c >= 'A' && c <= 'Z') ? c + ('a' - 'A') : c;
920 }
921 
922 char BLI_toupper_ascii(const char c)
923 {
924  return (c >= 'a' && c <= 'z') ? c - ('a' - 'A') : c;
925 }
926 
927 void BLI_str_tolower_ascii(char *str, const size_t len)
928 {
929  size_t i;
930 
931  for (i = 0; (i < len) && str[i]; i++) {
932  str[i] = BLI_tolower_ascii(str[i]);
933  }
934 }
935 
936 void BLI_str_toupper_ascii(char *str, const size_t len)
937 {
938  size_t i;
939 
940  for (i = 0; (i < len) && str[i]; i++) {
941  str[i] = BLI_toupper_ascii(str[i]);
942  }
943 }
944 
947 /* -------------------------------------------------------------------- */
951 void BLI_str_rstrip(char *str)
952 {
953  for (int i = (int)strlen(str) - 1; i >= 0; i--) {
954  if (isspace(str[i])) {
955  str[i] = '\0';
956  }
957  else {
958  break;
959  }
960  }
961 }
962 
963 int BLI_str_rstrip_float_zero(char *str, const char pad)
964 {
965  char *p = strchr(str, '.');
966  int totstrip = 0;
967  if (p) {
968  char *end_p;
969  p++; /* position at first decimal place */
970  end_p = p + (strlen(p) - 1); /* position at last character */
971  if (end_p > p) {
972  while (end_p != p && *end_p == '0') {
973  *end_p = pad;
974  end_p--;
975  totstrip++;
976  }
977  }
978  }
979 
980  return totstrip;
981 }
982 
985 /* -------------------------------------------------------------------- */
989 size_t BLI_str_partition(const char *str, const char delim[], const char **sep, const char **suf)
990 {
991  return BLI_str_partition_ex(str, NULL, delim, sep, suf, false);
992 }
993 
994 size_t BLI_str_rpartition(const char *str, const char delim[], const char **sep, const char **suf)
995 {
996  return BLI_str_partition_ex(str, NULL, delim, sep, suf, true);
997 }
998 
999 size_t BLI_str_partition_ex(const char *str,
1000  const char *end,
1001  const char delim[],
1002  const char **sep,
1003  const char **suf,
1004  const bool from_right)
1005 {
1006  const char *d;
1007  char *(*func)(const char *str, int c) = from_right ? strrchr : strchr;
1008 
1009  BLI_assert(end == NULL || end > str);
1010 
1011  *sep = *suf = NULL;
1012 
1013  for (d = delim; *d != '\0'; d++) {
1014  const char *tmp;
1015 
1016  if (end) {
1017  if (from_right) {
1018  for (tmp = end - 1; (tmp >= str) && (*tmp != *d); tmp--) {
1019  /* pass */
1020  }
1021  if (tmp < str) {
1022  tmp = NULL;
1023  }
1024  }
1025  else {
1026  tmp = func(str, *d);
1027  if (tmp >= end) {
1028  tmp = NULL;
1029  }
1030  }
1031  }
1032  else {
1033  tmp = func(str, *d);
1034  }
1035 
1036  if (tmp && (from_right ? (*sep < tmp) : (!*sep || *sep > tmp))) {
1037  *sep = tmp;
1038  }
1039  }
1040 
1041  if (*sep) {
1042  *suf = *sep + 1;
1043  return (size_t)(*sep - str);
1044  }
1045 
1046  return end ? (size_t)(end - str) : strlen(str);
1047 }
1048 
1050  const char *str, const size_t len, const char delim, int r_words[][2], int words_max)
1051 {
1052  int n = 0, i;
1053  bool charsearch = true;
1054 
1055  /* Skip leading spaces */
1056  for (i = 0; (i < len) && (str[i] != '\0'); i++) {
1057  if (str[i] != delim) {
1058  break;
1059  }
1060  }
1061 
1062  for (; (i < len) && (str[i] != '\0') && (n < words_max); i++) {
1063  if ((str[i] != delim) && (charsearch == true)) {
1064  r_words[n][0] = i;
1065  charsearch = false;
1066  }
1067  else {
1068  if ((str[i] == delim) && (charsearch == false)) {
1069  r_words[n][1] = i - r_words[n][0];
1070  n++;
1071  charsearch = true;
1072  }
1073  }
1074  }
1075 
1076  if (charsearch == false) {
1077  r_words[n][1] = i - r_words[n][0];
1078  n++;
1079  }
1080 
1081  return n;
1082 }
1083 
1086 /* -------------------------------------------------------------------- */
1090 static size_t BLI_str_format_int_grouped_ex(char src[16], char dst[16], int num_len)
1091 {
1092  char *p_src = src;
1093  char *p_dst = dst;
1094 
1095  const char separator = ',';
1096  int commas;
1097 
1098  if (*p_src == '-') {
1099  *p_dst++ = *p_src++;
1100  num_len--;
1101  }
1102 
1103  for (commas = 2 - num_len % 3; *p_src; commas = (commas + 1) % 3) {
1104  *p_dst++ = *p_src++;
1105  if (commas == 1) {
1106  *p_dst++ = separator;
1107  }
1108  }
1109  *--p_dst = '\0';
1110 
1111  return (size_t)(p_dst - dst);
1112 }
1113 
1114 size_t BLI_str_format_int_grouped(char dst[16], int num)
1115 {
1116  char src[16];
1117  int num_len = sprintf(src, "%d", num);
1118 
1119  return BLI_str_format_int_grouped_ex(src, dst, num_len);
1120 }
1121 
1122 size_t BLI_str_format_uint64_grouped(char dst[16], uint64_t num)
1123 {
1124  /* NOTE: Buffer to hold maximum unsigned int64, which is 1.8e+19. but
1125  * we also need space for commas and null-terminator. */
1126  char src[27];
1127  int num_len = sprintf(src, "%" PRIu64 "", num);
1128 
1129  return BLI_str_format_int_grouped_ex(src, dst, num_len);
1130 }
1131 
1132 void BLI_str_format_byte_unit(char dst[15], long long int bytes, const bool base_10)
1133 {
1134  double bytes_converted = bytes;
1135  int order = 0;
1136  int decimals;
1137  const int base = base_10 ? 1000 : 1024;
1138  const char *units_base_10[] = {"B", "KB", "MB", "GB", "TB", "PB"};
1139  const char *units_base_2[] = {"B", "KiB", "MiB", "GiB", "TiB", "PiB"};
1140  const int units_num = ARRAY_SIZE(units_base_2);
1141 
1142  BLI_STATIC_ASSERT(ARRAY_SIZE(units_base_2) == ARRAY_SIZE(units_base_10), "array size mismatch");
1143 
1144  while ((fabs(bytes_converted) >= base) && ((order + 1) < units_num)) {
1145  bytes_converted /= base;
1146  order++;
1147  }
1148  decimals = MAX2(order - 1, 0);
1149 
1150  /* Format value first, stripping away floating zeroes. */
1151  const size_t dst_len = 15;
1152  size_t len = BLI_snprintf_rlen(dst, dst_len, "%.*f", decimals, bytes_converted);
1153  len -= (size_t)BLI_str_rstrip_float_zero(dst, '\0');
1154  dst[len++] = ' ';
1155  BLI_strncpy(dst + len, base_10 ? units_base_10[order] : units_base_2[order], dst_len - len);
1156 }
1157 
1158 void BLI_str_format_decimal_unit(char dst[7], int number_to_format)
1159 {
1160  float number_to_format_converted = number_to_format;
1161  int order = 0;
1162  const float base = 1000;
1163  const char *units[] = {"", "K", "M", "B"};
1164  const int units_num = ARRAY_SIZE(units);
1165 
1166  while ((fabsf(number_to_format_converted) >= base) && ((order + 1) < units_num)) {
1167  number_to_format_converted /= base;
1168  order++;
1169  }
1170 
1171  const size_t dst_len = 7;
1172  int decimals = 0;
1173  if ((order > 0) && fabsf(number_to_format_converted) < 100.0f) {
1174  decimals = 1;
1175  }
1176  BLI_snprintf(dst, dst_len, "%.*f%s", decimals, number_to_format_converted, units[order]);
1177 }
1178 
#define BLI_STATIC_ASSERT(a, msg)
Definition: BLI_assert.h:83
#define BLI_assert(a)
Definition: BLI_assert.h:46
#define BLI_assert_msg(a, msg)
Definition: BLI_assert.h:53
#define BLI_INLINE
A dynamically sized string ADT.
DynStr * BLI_dynstr_new(void) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
Definition: BLI_dynstr.c:50
void BLI_dynstr_nappend(DynStr *__restrict ds, const char *cstr, int len) ATTR_NONNULL()
Definition: BLI_dynstr.c:94
char * BLI_dynstr_get_cstring(const DynStr *ds) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: BLI_dynstr.c:256
void BLI_dynstr_vappendf(DynStr *__restrict ds, const char *__restrict format, va_list args) ATTR_PRINTF_FORMAT(2
void BLI_dynstr_free(DynStr *ds) ATTR_NONNULL()
Definition: BLI_dynstr.c:281
void BLI_dynstr_append(DynStr *__restrict ds, const char *cstr) ATTR_NONNULL()
Definition: BLI_dynstr.c:75
#define ARRAY_SIZE(arr)
#define MAX2(a, b)
#define UNLIKELY(x)
#define ELEM(...)
#define STREQ(a, b)
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint order
Read Guarded memory(de)allocation.
#define MEM_reallocN(vmemh, len)
int pad[32 - sizeof(int)]
SyclQueue void void * src
SyclQueue void void size_t num_bytes void
int len
Definition: draw_manager.c:108
#define str(s)
#define PRIu64
Definition: inttypes.h:132
ccl_global float * buffer
format
Definition: logImageCore.h:38
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:33
ccl_device_inline float2 fabs(const float2 &a)
Definition: math_float2.h:222
#define fabsf(x)
Definition: metal/compat.h:219
static unsigned c
Definition: RandGen.cpp:83
static unsigned a[3]
Definition: RandGen.cpp:78
static const pxr::TfToken b("b", pxr::TfToken::Immortal)
return ret
unsigned __int64 uint64_t
Definition: stdint.h:90
bool BLI_str_quoted_substr(const char *__restrict str, const char *__restrict prefix, char *result, size_t result_maxlen)
Definition: string.c:424
int BLI_str_index_in_array(const char *__restrict str, const char **__restrict str_array)
Definition: string.c:847
void BLI_str_replace_char(char *str, char src, char dst)
Definition: string.c:503
#define CASE_PAIR(value_src, value_dst)
size_t BLI_snprintf_rlen(char *__restrict dst, size_t maxncpy, const char *__restrict format,...)
Definition: string.c:210
size_t BLI_strnlen(const char *s, const size_t maxlen)
Definition: string.c:899
void BLI_str_format_decimal_unit(char dst[7], int number_to_format)
Definition: string.c:1158
bool BLI_str_replace_table_exact(char *string, const size_t string_len, const char *replace_table[][2], int replace_table_len)
Definition: string.c:513
size_t BLI_snprintf(char *__restrict dst, size_t maxncpy, const char *__restrict format,...)
Definition: string.c:194
static int left_number_strcmp(const char *s1, const char *s2, int *tiebreaker)
Definition: string.c:670
int BLI_strcasecmp(const char *s1, const char *s2)
Definition: string.c:623
size_t BLI_str_partition(const char *str, const char delim[], const char **sep, const char **suf)
Definition: string.c:989
bool BLI_string_has_word_prefix(const char *haystack, const char *needle, size_t needle_len)
Definition: string.c:564
int BLI_string_max_possible_word_count(const int str_len)
Definition: string.c:559
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, const size_t maxncpy)
Definition: string.c:64
bool BLI_string_all_words_matched(const char *name, const char *str, int(*words)[2], const int words_len)
Definition: string.c:576
char * BLI_strncpy_ensure_pad(char *__restrict dst, const char *__restrict src, const char pad, size_t maxncpy)
Definition: string.c:78
void BLI_str_rstrip(char *str)
Definition: string.c:951
size_t BLI_vsnprintf_rlen(char *__restrict buffer, size_t maxncpy, const char *__restrict format, va_list arg)
Definition: string.c:170
size_t BLI_strncpy_rlen(char *__restrict dst, const char *__restrict src, const size_t maxncpy)
Definition: string.c:120
int BLI_string_find_split_words(const char *str, const size_t len, const char delim, int r_words[][2], int words_max)
Definition: string.c:1049
size_t BLI_str_format_int_grouped(char dst[16], int num)
Definition: string.c:1114
char * BLI_strdup(const char *str)
Definition: string.c:42
size_t BLI_strcpy_rlen(char *__restrict dst, const char *__restrict src)
Definition: string.c:134
int BLI_strcmp_ignore_pad(const char *str1, const char *str2, const char pad)
Definition: string.c:786
int BLI_str_index_in_array_n(const char *__restrict str, const char **__restrict str_array, const int str_array_len)
Definition: string.c:832
char * BLI_strdupcat(const char *__restrict str1, const char *__restrict str2)
Definition: string.c:47
int BLI_strcasecmp_natural(const char *s1, const char *s2)
Definition: string.c:719
int BLI_strncasecmp(const char *s1, const char *s2, size_t len)
Definition: string.c:646
char BLI_toupper_ascii(const char c)
Definition: string.c:922
char * BLI_strncasestr(const char *s, const char *find, size_t len)
Definition: string.c:592
char * BLI_strdupn(const char *str, const size_t len)
Definition: string.c:33
bool BLI_str_quoted_substr_range(const char *__restrict str, const char *__restrict prefix, int *__restrict r_start, int *__restrict r_end)
Definition: string.c:359
const char * BLI_str_escape_find_quote(const char *str)
Definition: string.c:341
size_t BLI_str_escape(char *__restrict dst, const char *__restrict src, const size_t dst_maxncpy)
Definition: string.c:250
void BLI_str_tolower_ascii(char *str, const size_t len)
Definition: string.c:927
size_t BLI_str_partition_ex(const char *str, const char *end, const char delim[], const char **sep, const char **suf, const bool from_right)
Definition: string.c:999
size_t BLI_str_rpartition(const char *str, const char delim[], const char **sep, const char **suf)
Definition: string.c:994
size_t BLI_vsnprintf(char *__restrict buffer, size_t maxncpy, const char *__restrict format, va_list arg)
Definition: string.c:147
bool BLI_strn_endswith(const char *__restrict str, const char *__restrict end, size_t slength)
Definition: string.c:871
void BLI_str_format_byte_unit(char dst[15], long long int bytes, const bool base_10)
Definition: string.c:1132
size_t BLI_str_unescape(char *__restrict dst, const char *__restrict src, const size_t src_maxncpy)
Definition: string.c:327
BLI_INLINE bool str_unescape_pair(char c_next, char *r_out)
Definition: string.c:280
char BLI_tolower_ascii(const char c)
Definition: string.c:917
size_t BLI_str_format_uint64_grouped(char dst[16], uint64_t num)
Definition: string.c:1122
char * BLI_str_replaceN(const char *__restrict str, const char *__restrict substr_old, const char *__restrict substr_new)
Definition: string.c:448
void BLI_str_toupper_ascii(char *str, const size_t len)
Definition: string.c:936
bool BLI_str_endswith(const char *__restrict str, const char *__restrict end)
Definition: string.c:887
char * BLI_strcasestr(const char *s, const char *find)
Definition: string.c:538
size_t BLI_str_unescape_ex(char *__restrict dst, const char *__restrict src, const size_t src_maxncpy, const size_t dst_maxncpy, bool *r_is_complete)
Definition: string.c:301
int BLI_str_rstrip_float_zero(char *str, const char pad)
Definition: string.c:963
char * BLI_sprintfN(const char *__restrict format,...)
Definition: string.c:226
bool BLI_str_startswith(const char *__restrict str, const char *__restrict start)
Definition: string.c:860
static size_t BLI_str_format_int_grouped_ex(char src[16], char dst[16], int num_len)
Definition: string.c:1090
int BLI_strcaseeq(const char *a, const char *b)
Definition: string.c:533