Blender V5.0
string.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2001-2002 NaN Holding BV. All rights reserved.
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include <algorithm>
10#include <cctype>
11#include <cinttypes>
12#include <cmath>
13#include <cstdarg>
14#include <cstdio>
15#include <cstdlib>
16#include <cstring>
17
18#include "MEM_guardedalloc.h"
19
20#include "BLI_string.h"
21
22#include "BLI_utildefines.h"
23
24#include "BLI_strict_flags.h" /* IWYU pragma: keep. Keep last. */
25
26/* -------------------------------------------------------------------- */
29
30char *BLI_strdupn(const char *str, const size_t len)
31{
32 BLI_assert_msg(BLI_strnlen(str, len) == len, "strlen(str) must be greater or equal to 'len'!");
33
34 char *n = MEM_malloc_arrayN<char>(len + 1, "strdup");
35 memcpy(n, str, len);
36 n[len] = '\0';
37
38 return n;
39}
40
41char *BLI_strdup(const char *str)
42{
43 return BLI_strdupn(str, strlen(str));
44}
45
46char *BLI_strdup_null(const char *str)
47{
48 return (str != nullptr) ? BLI_strdupn(str, strlen(str)) : nullptr;
49}
50
51char *BLI_strdupcat(const char *__restrict str1, const char *__restrict str2)
52{
53 /* Include the null terminator of `str2` only. */
54 const size_t str1_len = strlen(str1);
55 const size_t str2_len = strlen(str2) + 1;
56 char *str, *s;
57
58 str = MEM_calloc_arrayN<char>(str1_len + str2_len, "strdupcat");
59 s = str;
60
61 memcpy(s, str1, str1_len); /* NOLINT: bugprone-not-null-terminated-result */
62 s += str1_len;
63 memcpy(s, str2, str2_len);
64
65 return str;
66}
67
68char *BLI_strncpy(char *__restrict dst, const char *__restrict src, const size_t dst_maxncpy)
69{
70 BLI_string_debug_size(dst, dst_maxncpy);
71
72 BLI_assert(dst_maxncpy != 0);
73 size_t srclen = BLI_strnlen(src, dst_maxncpy - 1);
74
75 memcpy(dst, src, srclen);
76 dst[srclen] = '\0';
77 return dst;
78}
79
80char *BLI_strncpy_ensure_pad(char *__restrict dst,
81 const char *__restrict src,
82 const char pad,
83 size_t dst_maxncpy)
84{
85 BLI_string_debug_size(dst, dst_maxncpy);
86 BLI_assert(dst_maxncpy != 0);
87
88 if (src[0] == '\0') {
89 dst[0] = '\0';
90 }
91 else {
92 /* Add heading/trailing wildcards if needed. */
93 size_t idx = 0;
94 size_t srclen;
95
96 if (src[idx] != pad) {
97 dst[idx++] = pad;
98 dst_maxncpy--;
99 }
100 dst_maxncpy--; /* trailing '\0' */
101
102 srclen = BLI_strnlen(src, dst_maxncpy);
103 if ((src[srclen - 1] != pad) && (srclen == dst_maxncpy)) {
104 srclen--;
105 }
106
107 memcpy(&dst[idx], src, srclen);
108 idx += srclen;
109
110 if (dst[idx - 1] != pad) {
111 dst[idx++] = pad;
112 }
113 dst[idx] = '\0';
114 }
115
116 return dst;
117}
118
119size_t BLI_strncpy_rlen(char *__restrict dst, const char *__restrict src, const size_t dst_maxncpy)
120{
121 BLI_string_debug_size(dst, dst_maxncpy);
122
123 size_t srclen = BLI_strnlen(src, dst_maxncpy - 1);
124 BLI_assert(dst_maxncpy != 0);
125
126 memcpy(dst, src, srclen);
127 dst[srclen] = '\0';
128 return srclen;
129}
130
132
133/* -------------------------------------------------------------------- */
136
137char *BLI_strncat(char *__restrict dst, const char *__restrict src, const size_t dst_maxncpy)
138{
139 BLI_string_debug_size(dst, dst_maxncpy);
140
141 size_t len = BLI_strnlen(dst, dst_maxncpy);
142 if (len < dst_maxncpy) {
143 BLI_strncpy(dst + len, src, dst_maxncpy - len);
144 }
145 return dst;
146}
147
149
150/* -------------------------------------------------------------------- */
153
154size_t BLI_vsnprintf(char *__restrict dst,
155 size_t dst_maxncpy,
156 const char *__restrict format,
157 va_list arg)
158{
159 BLI_string_debug_size(dst, dst_maxncpy);
160
161 BLI_assert(dst != nullptr);
162 BLI_assert(dst_maxncpy > 0);
163 BLI_assert(format != nullptr);
164
165 const size_t n = size_t(vsnprintf(dst, dst_maxncpy, format, arg));
166 if (n < dst_maxncpy) {
167 dst[n] = '\0';
168 }
169 else {
170 dst[dst_maxncpy - 1] = '\0';
171 }
172
173 return n;
174}
175
176size_t BLI_vsnprintf_rlen(char *__restrict dst,
177 size_t dst_maxncpy,
178 const char *__restrict format,
179 va_list arg)
180{
181 BLI_string_debug_size(dst, dst_maxncpy);
182
183 BLI_assert(dst != nullptr);
184 BLI_assert(dst_maxncpy > 0);
185 BLI_assert(format != nullptr);
186
187 size_t n = size_t(vsnprintf(dst, dst_maxncpy, format, arg));
188 if (n < dst_maxncpy) {
189 /* pass */
190 }
191 else {
192 n = dst_maxncpy - 1;
193 }
194 dst[n] = '\0';
195
196 return n;
197}
198
199size_t BLI_snprintf(char *__restrict dst, size_t dst_maxncpy, const char *__restrict format, ...)
200{
201 BLI_string_debug_size(dst, dst_maxncpy);
202
203 va_list arg;
204 va_start(arg, format);
205 const size_t n = BLI_vsnprintf(dst, dst_maxncpy, format, arg);
206 va_end(arg);
207
208 return n;
209}
210
211size_t BLI_snprintf_rlen(char *__restrict dst,
212 size_t dst_maxncpy,
213 const char *__restrict format,
214 ...)
215{
216 BLI_string_debug_size(dst, dst_maxncpy);
217
218 va_list arg;
219 va_start(arg, format);
220 const size_t n = BLI_vsnprintf_rlen(dst, dst_maxncpy, format, arg);
221 va_end(arg);
222
223 return n;
224}
225
227 char *fixed_buf, size_t fixed_buf_size, size_t *result_len, const char *__restrict format, ...)
228{
229 va_list args;
230 va_start(args, format);
231 int retval = vsnprintf(fixed_buf, fixed_buf_size, format, args);
232 va_end(args);
233 if (UNLIKELY(retval < 0)) {
234 /* Return an empty string as there was an error there is no valid output. */
235 *result_len = 0;
236 if (UNLIKELY(fixed_buf_size == 0)) {
237 return MEM_calloc_arrayN<char>(1, __func__);
238 }
239 *fixed_buf = '\0';
240 return fixed_buf;
241 }
242 *result_len = size_t(retval);
243 if (size_t(retval) < fixed_buf_size) {
244 return fixed_buf;
245 }
246
247 /* `retval` doesn't include null terminator. */
248 const size_t size = size_t(retval) + 1;
249 char *result = MEM_malloc_arrayN<char>(size, __func__);
250 va_start(args, format);
251 retval = vsnprintf(result, size, format, args);
252 va_end(args);
253 BLI_assert(size_t(retval + 1) == size);
254 UNUSED_VARS_NDEBUG(retval);
255 return result;
256}
257
258char *BLI_vsprintfN_with_buffer(char *fixed_buf,
259 size_t fixed_buf_size,
260 size_t *result_len,
261 const char *__restrict format,
262 va_list args)
263{
264 va_list args_copy;
265 va_copy(args_copy, args);
266 int retval = vsnprintf(fixed_buf, fixed_buf_size, format, args_copy);
267 va_end(args_copy);
268 if (UNLIKELY(retval < 0)) {
269 /* Return an empty string as there was an error there is no valid output. */
270 *result_len = 0;
271 if (UNLIKELY(fixed_buf_size == 0)) {
272 return MEM_calloc_arrayN<char>(1, __func__);
273 }
274 *fixed_buf = '\0';
275 return fixed_buf;
276 }
277 *result_len = size_t(retval);
278 if (size_t(retval) < fixed_buf_size) {
279 return fixed_buf;
280 }
281
282 /* `retval` doesn't include null terminator. */
283 const size_t size = size_t(retval) + 1;
284 char *result = MEM_malloc_arrayN<char>(size, __func__);
285 retval = vsnprintf(result, size, format, args);
286 BLI_assert(size_t(retval + 1) == size);
287 UNUSED_VARS_NDEBUG(retval);
288 return result;
289}
290
291char *BLI_sprintfN(const char *__restrict format, ...)
292{
293 char fixed_buf[256];
294 size_t result_len;
295 va_list args;
296 va_start(args, format);
298 fixed_buf, sizeof(fixed_buf), &result_len, format, args);
299 va_end(args);
300 if (result != fixed_buf) {
301 return result;
302 }
303 size_t size = result_len + 1;
305 memcpy(result, fixed_buf, size);
306 return result;
307}
308
309char *BLI_vsprintfN(const char *__restrict format, va_list args)
310{
311 char fixed_buf[256];
312 size_t result_len;
314 fixed_buf, sizeof(fixed_buf), &result_len, format, args);
315 if (result != fixed_buf) {
316 return result;
317 }
318 size_t size = result_len + 1;
320 memcpy(result, fixed_buf, size);
321 return result;
322}
323
325
326/* -------------------------------------------------------------------- */
329
330size_t BLI_str_escape(char *__restrict dst, const char *__restrict src, const size_t dst_maxncpy)
331{
332 BLI_assert(dst_maxncpy != 0);
333 BLI_string_debug_size(dst, dst_maxncpy);
334
335 size_t len = 0;
336 for (; (len < dst_maxncpy) && (*src != '\0'); dst++, src++, len++) {
337 char c = *src;
338 if (ELEM(c, '\\', '"') || /* Use as-is. */
339 ((c == '\t') && ((void)(c = 't'), true)) || /* Tab. */
340 ((c == '\n') && ((void)(c = 'n'), true)) || /* Newline. */
341 ((c == '\r') && ((void)(c = 'r'), true)) || /* Carriage return. */
342 ((c == '\a') && ((void)(c = 'a'), true)) || /* Bell. */
343 ((c == '\b') && ((void)(c = 'b'), true)) || /* Backspace. */
344 ((c == '\f') && ((void)(c = 'f'), true))) /* Form-feed. */
345 {
346 if (UNLIKELY(len + 1 >= dst_maxncpy)) {
347 /* Not enough space to escape. */
348 break;
349 }
350 *dst++ = '\\';
351 len++;
352 }
353 *dst = c;
354 }
355 *dst = '\0';
356
357 return len;
358}
359
360std::string BLI_str_escape(const char *str)
361{
362 if (!str) {
363 return {};
364 }
365 const size_t max_result_size = strlen(str) * 2 + 1;
366 std::string result;
367 result.resize(max_result_size);
368 const size_t result_size = BLI_str_escape(result.data(), str, max_result_size);
369 result.resize(result_size);
370 return result;
371}
372
373BLI_INLINE bool str_unescape_pair(char c_next, char *r_out)
374{
375#define CASE_PAIR(value_src, value_dst) \
376 case value_src: { \
377 *r_out = value_dst; \
378 return true; \
379 }
380 switch (c_next) {
381 CASE_PAIR('"', '"'); /* Quote. */
382 CASE_PAIR('\\', '\\'); /* Backslash. */
383 CASE_PAIR('t', '\t'); /* Tab. */
384 CASE_PAIR('n', '\n'); /* Newline. */
385 CASE_PAIR('r', '\r'); /* Carriage return. */
386 CASE_PAIR('a', '\a'); /* Bell. */
387 CASE_PAIR('b', '\b'); /* Backspace. */
388 CASE_PAIR('f', '\f'); /* Form-feed. */
389 }
390#undef CASE_PAIR
391 return false;
392}
393
394size_t BLI_str_unescape_ex(char *__restrict dst,
395 const char *__restrict src,
396 const size_t src_maxncpy,
397 /* Additional arguments to #BLI_str_unescape */
398 const size_t dst_maxncpy,
399 bool *r_is_complete)
400{
401 BLI_string_debug_size(dst, dst_maxncpy);
402
403 size_t len = 0;
404 bool is_complete = true;
405 const size_t max_strlen = dst_maxncpy - 1; /* Account for trailing zero byte. */
406 for (const char *src_end = src + src_maxncpy; (src < src_end) && *src; src++) {
407 if (UNLIKELY(len == max_strlen)) {
408 is_complete = false;
409 break;
410 }
411 char c = *src;
412 if (UNLIKELY(c == '\\') && str_unescape_pair(*(src + 1), &c)) {
413 src++;
414 }
415 dst[len++] = c;
416 }
417 dst[len] = 0;
418 *r_is_complete = is_complete;
419 return len;
420}
421
422size_t BLI_str_unescape(char *__restrict dst, const char *__restrict src, const size_t src_maxncpy)
423{
424 BLI_string_debug_size(dst, src_maxncpy); /* `dst` must be at least as big as `src`. */
425
426 size_t len = 0;
427 for (const char *src_end = src + src_maxncpy; (src < src_end) && *src; src++) {
428 char c = *src;
429 if (UNLIKELY(c == '\\') && str_unescape_pair(*(src + 1), &c)) {
430 src++;
431 }
432 dst[len++] = c;
433 }
434 dst[len] = 0;
435 return len;
436}
437
438const char *BLI_str_escape_find_quote(const char *str)
439{
440 bool escape = false;
441 while (*str && (*str != '"' || escape)) {
442 /* A pair of back-slashes represents a single back-slash,
443 * only use a single back-slash for escaping. */
444 escape = (escape == false) && (*str == '\\');
445 str++;
446 }
447 return (*str == '"') ? str : nullptr;
448}
449
451
452/* -------------------------------------------------------------------- */
455
456bool BLI_str_quoted_substr_range(const char *__restrict str,
457 const char *__restrict prefix,
458 int *__restrict r_start,
459 int *__restrict r_end)
460{
461 const char *str_start = strstr(str, prefix);
462 if (str_start == nullptr) {
463 return false;
464 }
465 const size_t prefix_len = strlen(prefix);
466 if (UNLIKELY(prefix_len == 0)) {
468 "Zero length prefix passed in, "
469 "caller must prevent this from happening!");
470 return false;
471 }
472 BLI_assert_msg(prefix[prefix_len - 1] != '"',
473 "Prefix includes trailing quote, "
474 "caller must prevent this from happening!");
475
476 str_start += prefix_len;
477 if (UNLIKELY(*str_start != '\"')) {
478 return false;
479 }
480 str_start += 1;
481 const char *str_end = BLI_str_escape_find_quote(str_start);
482 if (UNLIKELY(str_end == nullptr)) {
483 return false;
484 }
485
486 *r_start = int(str_start - str);
487 *r_end = int(str_end - str);
488 return true;
489}
490
491/* NOTE(@ideasman42): in principal it should be possible to access a quoted string
492 * with an arbitrary size, currently all callers for this functionality
493 * happened to use a fixed size buffer, so only #BLI_str_quoted_substr is needed. */
494#if 0
505char *BLI_str_quoted_substrN(const char *__restrict str, const char *__restrict prefix)
506{
507 int start_match_ofs, end_match_ofs;
508 if (!BLI_str_quoted_substr_range(str, prefix, &start_match_ofs, &end_match_ofs)) {
509 return nullptr;
510 }
511 const size_t escaped_len = size_t(end_match_ofs - start_match_ofs);
512 char *result = MEM_malloc_arrayN<char>(escaped_len + 1, __func__);
513 const size_t unescaped_len = BLI_str_unescape(result, str + start_match_ofs, escaped_len);
514 if (unescaped_len != escaped_len) {
515 result = MEM_reallocN(result, sizeof(char) * (unescaped_len + 1));
516 }
517 return result;
518}
519#endif
520
521bool BLI_str_quoted_substr(const char *__restrict str,
522 const char *__restrict prefix,
523 char *result,
524 size_t result_maxncpy)
525{
526 BLI_string_debug_size(result, result_maxncpy);
527
528 int start_match_ofs, end_match_ofs;
529 if (!BLI_str_quoted_substr_range(str, prefix, &start_match_ofs, &end_match_ofs)) {
530 return false;
531 }
532 const size_t escaped_len = size_t(end_match_ofs - start_match_ofs);
533 bool is_complete;
534 BLI_str_unescape_ex(result, str + start_match_ofs, escaped_len, result_maxncpy, &is_complete);
535 if (is_complete == false) {
536 *result = '\0';
537 }
538 return is_complete;
539}
540
542
543/* -------------------------------------------------------------------- */
546
547int BLI_strcaseeq(const char *a, const char *b)
548{
549 return (BLI_strcasecmp(a, b) == 0);
550}
551
552char *BLI_strcasestr(const char *s, const char *find)
553{
554 char c, sc;
555 size_t len;
556
557 if ((c = *find++) != 0) {
558 c = char(tolower(c));
559 len = strlen(find);
560 do {
561 do {
562 if ((sc = *s++) == 0) {
563 return nullptr;
564 }
565 sc = char(tolower(sc));
566 } while (sc != c);
567 } while (BLI_strncasecmp(s, find, len) != 0);
568 s--;
569 }
570 return ((char *)s);
571}
572
574{
575 return (str_len / 2) + 1;
576}
577
578bool BLI_string_has_word_prefix(const char *haystack, const char *needle, size_t needle_len)
579{
580 const char *match = BLI_strncasestr(haystack, needle, needle_len);
581 if (match) {
582 if ((match == haystack) || (*(match - 1) == ' ') || ispunct(*(match - 1))) {
583 return true;
584 }
585 return BLI_string_has_word_prefix(match + 1, needle, needle_len);
586 }
587 return false;
588}
589
591 const char *str,
592 int (*words)[2],
593 const int words_len)
594{
595 int index;
596 for (index = 0; index < words_len; index++) {
597 if (!BLI_string_has_word_prefix(name, str + words[index][0], size_t(words[index][1]))) {
598 break;
599 }
600 }
601 const bool all_words_matched = (index == words_len);
602
603 return all_words_matched;
604}
605
606char *BLI_strncasestr(const char *s, const char *find, size_t len)
607{
608 char c, sc;
609
610 if ((c = *find++) != 0) {
611 c = char(tolower(c));
612 if (len > 1) {
613 do {
614 do {
615 if ((sc = *s++) == 0) {
616 return nullptr;
617 }
618 sc = char(tolower(sc));
619 } while (sc != c);
620 } while (BLI_strncasecmp(s, find, len - 1) != 0);
621 }
622 else {
623 {
624 do {
625 if ((sc = *s++) == 0) {
626 return nullptr;
627 }
628 sc = char(tolower(sc));
629 } while (sc != c);
630 }
631 }
632 s--;
633 }
634 return ((char *)s);
635}
636
637int BLI_strcasecmp(const char *s1, const char *s2)
638{
639 int i;
640 char c1, c2;
641
642 for (i = 0;; i++) {
643 c1 = char(tolower(s1[i]));
644 c2 = char(tolower(s2[i]));
645
646 if (c1 < c2) {
647 return -1;
648 }
649 if (c1 > c2) {
650 return 1;
651 }
652 if (c1 == 0) {
653 break;
654 }
655 }
656
657 return 0;
658}
659
660int BLI_strncasecmp(const char *s1, const char *s2, size_t len)
661{
662 size_t i;
663 char c1, c2;
664
665 for (i = 0; i < len; i++) {
666 c1 = char(tolower(s1[i]));
667 c2 = char(tolower(s2[i]));
668
669 if (c1 < c2) {
670 return -1;
671 }
672 if (c1 > c2) {
673 return 1;
674 }
675 if (c1 == 0) {
676 break;
677 }
678 }
679
680 return 0;
681}
682
683/* compare number on the left size of the string */
684static int left_number_strcmp(const char *s1, const char *s2, int *tiebreaker)
685{
686 const char *p1 = s1, *p2 = s2;
687 int numdigit, numzero1, numzero2;
688
689 /* count and skip leading zeros */
690 for (numzero1 = 0; *p1 == '0'; numzero1++) {
691 p1++;
692 }
693 for (numzero2 = 0; *p2 == '0'; numzero2++) {
694 p2++;
695 }
696
697 /* find number of consecutive digits */
698 for (numdigit = 0;; numdigit++) {
699 if (isdigit(*(p1 + numdigit)) && isdigit(*(p2 + numdigit))) {
700 continue;
701 }
702 if (isdigit(*(p1 + numdigit))) {
703 return 1; /* s2 is bigger */
704 }
705 if (isdigit(*(p2 + numdigit))) {
706 return -1; /* s1 is bigger */
707 }
708 break;
709 }
710
711 /* same number of digits, compare size of number */
712 if (numdigit > 0) {
713 int compare = strncmp(p1, p2, size_t(numdigit));
714
715 if (compare != 0) {
716 return compare;
717 }
718 }
719
720 /* use number of leading zeros as tie breaker if still equal */
721 if (*tiebreaker == 0) {
722 if (numzero1 > numzero2) {
723 *tiebreaker = 1;
724 }
725 else if (numzero1 < numzero2) {
726 *tiebreaker = -1;
727 }
728 }
729
730 return 0;
731}
732
733int BLI_strcasecmp_natural(const char *s1, const char *s2)
734{
735 int d1 = 0, d2 = 0;
736 char c1, c2;
737 int tiebreaker = 0;
738
739 /* if both chars are numeric, to a left_number_strcmp().
740 * then increase string deltas as long they are
741 * numeric, else do a tolower and char compare */
742
743 while (true) {
744 if (isdigit(s1[d1]) && isdigit(s2[d2])) {
745 int numcompare = left_number_strcmp(s1 + d1, s2 + d2, &tiebreaker);
746
747 if (numcompare != 0) {
748 return numcompare;
749 }
750
751 /* Some wasted work here, left_number_strcmp already consumes at least some digits. */
752 d1++;
753 while (isdigit(s1[d1])) {
754 d1++;
755 }
756 d2++;
757 while (isdigit(s2[d2])) {
758 d2++;
759 }
760 }
761
762 /* Test for end of strings first so that shorter strings are ordered in front. */
763 if (ELEM(0, s1[d1], s2[d2])) {
764 break;
765 }
766
767 c1 = char(tolower(s1[d1]));
768 c2 = char(tolower(s2[d2]));
769
770 if (c1 == c2) {
771 /* Continue iteration */
772 }
773 /* Check for '.' so "foo.bar" comes before "foo 1.bar". */
774 else if (c1 == '.') {
775 return -1;
776 }
777 else if (c2 == '.') {
778 return 1;
779 }
780 else if (c1 < c2) {
781 return -1;
782 }
783 else if (c1 > c2) {
784 return 1;
785 }
786
787 d1++;
788 d2++;
789 }
790
791 if (tiebreaker) {
792 return tiebreaker;
793 }
794
795 /* we might still have a different string because of lower/upper case, in
796 * that case fall back to regular string comparison */
797 return strcmp(s1, s2);
798}
799
800int BLI_strcmp_ignore_pad(const char *str1, const char *str2, const char pad)
801{
802 size_t str1_len, str2_len;
803
804 while (*str1 == pad) {
805 str1++;
806 }
807 while (*str2 == pad) {
808 str2++;
809 }
810
811 str1_len = strlen(str1);
812 str2_len = strlen(str2);
813
814 while (str1_len && (str1[str1_len - 1] == pad)) {
815 str1_len--;
816 }
817 while (str2_len && (str2[str2_len - 1] == pad)) {
818 str2_len--;
819 }
820
821 if (str1_len == str2_len) {
822 return strncmp(str1, str2, str2_len);
823 }
824 if (str1_len > str2_len) {
825 int ret = strncmp(str1, str2, str2_len);
826 if (ret == 0) {
827 ret = 1;
828 }
829 return ret;
830 }
831 {
832 int ret = strncmp(str1, str2, str1_len);
833 if (ret == 0) {
834 ret = -1;
835 }
836 return ret;
837 }
838}
839
841
842/* -------------------------------------------------------------------- */
845
846int BLI_str_index_in_array_n(const char *__restrict str,
847 const char **__restrict str_array,
848 const int str_array_len)
849{
850 int index;
851 const char **str_iter = str_array;
852
853 for (index = 0; index < str_array_len; str_iter++, index++) {
854 if (STREQ(str, *str_iter)) {
855 return index;
856 }
857 }
858 return -1;
859}
860
861int BLI_str_index_in_array(const char *__restrict str, const char **__restrict str_array)
862{
863 int index;
864 const char **str_iter = str_array;
865
866 for (index = 0; *str_iter; str_iter++, index++) {
867 if (STREQ(str, *str_iter)) {
868 return index;
869 }
870 }
871 return -1;
872}
873
874bool BLI_str_startswith(const char *__restrict str, const char *__restrict start)
875{
876 for (; *str && *start; str++, start++) {
877 if (*str != *start) {
878 return false;
879 }
880 }
881
882 return (*start == '\0');
883}
884
885bool BLI_strn_endswith(const char *__restrict str, const char *__restrict end, size_t str_len)
886{
887 size_t end_len = strlen(end);
888
889 if (end_len <= str_len) {
890 const char *iter = &str[str_len - end_len];
891 while (*iter) {
892 if (*iter++ != *end++) {
893 return false;
894 }
895 }
896 return true;
897 }
898 return false;
899}
900
901bool BLI_str_endswith(const char *__restrict str, const char *__restrict end)
902{
903 const size_t str_len = strlen(str);
904 return BLI_strn_endswith(str, end, str_len);
905}
906
908
909/* -------------------------------------------------------------------- */
912
913size_t BLI_strnlen(const char *str, const size_t maxlen)
914{
915 size_t len;
916
917 for (len = 0; len < maxlen; len++, str++) {
918 if (!*str) {
919 break;
920 }
921 }
922 return len;
923}
924
926
927/* -------------------------------------------------------------------- */
930
931const char *BLI_strchr_or_end(const char *str, const char ch)
932{
933 const char *p = str;
934 while (!ELEM(*p, ch, '\0')) {
935 p++;
936 }
937 return p;
938}
939
941
942/* -------------------------------------------------------------------- */
945
946char BLI_tolower_ascii(const char c)
947{
948 return (c >= 'A' && c <= 'Z') ? c + ('a' - 'A') : c;
949}
950
951char BLI_toupper_ascii(const char c)
952{
953 return (c >= 'a' && c <= 'z') ? c - ('a' - 'A') : c;
954}
955
956void BLI_str_tolower_ascii(char *str, const size_t len)
957{
958 size_t i;
959
960 for (i = 0; (i < len) && str[i]; i++) {
962 }
963}
964
965void BLI_str_toupper_ascii(char *str, const size_t len)
966{
967 size_t i;
968
969 for (i = 0; (i < len) && str[i]; i++) {
971 }
972}
973
975
976/* -------------------------------------------------------------------- */
979
981{
982 for (int i = int(strlen(str)) - 1; i >= 0; i--) {
983 if (isspace(str[i])) {
984 str[i] = '\0';
985 }
986 else {
987 break;
988 }
989 }
990}
991
992int BLI_str_rstrip_float_zero(char *str, const char pad)
993{
994 char *p = strchr(str, '.');
995 int totstrip = 0;
996 if (p) {
997 char *end_p;
998 p++; /* position at first decimal place */
999 end_p = p + (strlen(p) - 1); /* position at last character */
1000 if (end_p > p) {
1001 while (end_p != p && *end_p == '0') {
1002 *end_p = pad;
1003 end_p--;
1004 totstrip++;
1005 }
1006 }
1007 }
1008
1009 return totstrip;
1010}
1011
1013{
1014 int totstrip = 0;
1015 int str_len = int(strlen(str));
1016 while (str_len > 0 && isdigit(str[--str_len])) {
1017 str[str_len] = '\0';
1018 totstrip++;
1019 }
1020 return totstrip;
1021}
1022
1024
1025/* -------------------------------------------------------------------- */
1028
1029size_t BLI_str_partition(const char *str, const char delim[], const char **sep, const char **suf)
1030{
1031 return BLI_str_partition_ex(str, nullptr, delim, sep, suf, false);
1032}
1033
1034size_t BLI_str_rpartition(const char *str, const char delim[], const char **sep, const char **suf)
1035{
1036 return BLI_str_partition_ex(str, nullptr, delim, sep, suf, true);
1037}
1038
1039size_t BLI_str_partition_ex(const char *str,
1040 const char *end,
1041 const char delim[],
1042 const char **sep,
1043 const char **suf,
1044 const bool from_right)
1045{
1046 const char *d;
1047
1048 BLI_assert(end == nullptr || end > str);
1049
1050 *sep = *suf = nullptr;
1051
1052 for (d = delim; *d != '\0'; d++) {
1053 const char *tmp;
1054
1055 if (end) {
1056 if (from_right) {
1057 for (tmp = end - 1; (tmp >= str) && (*tmp != *d); tmp--) {
1058 /* pass */
1059 }
1060 if (tmp < str) {
1061 tmp = nullptr;
1062 }
1063 }
1064 else {
1065 tmp = strchr(str, *d);
1066 if (tmp >= end) {
1067 tmp = nullptr;
1068 }
1069 }
1070 }
1071 else {
1072 tmp = (from_right) ? strrchr(str, *d) : strchr(str, *d);
1073 }
1074
1075 if (tmp && (from_right ? (*sep < tmp) : (!*sep || *sep > tmp))) {
1076 *sep = tmp;
1077 }
1078 }
1079
1080 if (*sep) {
1081 *suf = *sep + 1;
1082 return size_t(*sep - str);
1083 }
1084
1085 return end ? size_t(end - str) : strlen(str);
1086}
1087
1089 const char *str, const size_t str_maxlen, const char delim, int r_words[][2], int words_max)
1090{
1091 int n = 0, i;
1092 bool charsearch = true;
1093
1094 /* Skip leading spaces */
1095 for (i = 0; (i < int(str_maxlen)) && (str[i] != '\0'); i++) {
1096 if (str[i] != delim) {
1097 break;
1098 }
1099 }
1100
1101 for (; (i < int(str_maxlen)) && (str[i] != '\0') && (n < words_max); i++) {
1102 if ((str[i] != delim) && (charsearch == true)) {
1103 r_words[n][0] = i;
1104 charsearch = false;
1105 }
1106 else {
1107 if ((str[i] == delim) && (charsearch == false)) {
1108 r_words[n][1] = i - r_words[n][0];
1109 n++;
1110 charsearch = true;
1111 }
1112 }
1113 }
1114
1115 if (charsearch == false) {
1116 r_words[n][1] = i - r_words[n][0];
1117 n++;
1118 }
1119
1120 return n;
1121}
1122
1123bool BLI_string_elem_split_by_delim(const char *haystack, const char delim, const char *needle)
1124{
1125 /* May be zero, returns true when an empty span exists. */
1126 const size_t needle_len = strlen(needle);
1127 const char *p = haystack;
1128 while (true) {
1129 const char *p_next = BLI_strchr_or_end(p, delim);
1130 if ((size_t(p_next - p) == needle_len) && (memcmp(p, needle, needle_len) == 0)) {
1131 return true;
1132 }
1133 if (*p_next == '\0') {
1134 break;
1135 }
1136 p = p_next + 1;
1137 }
1138 return false;
1139}
1140
1142
1143/* -------------------------------------------------------------------- */
1146
1147static size_t BLI_str_format_int_grouped_ex(char *src, char *dst, int num_len)
1148{
1149 char *p_src = src;
1150 char *p_dst = dst;
1151
1152 const char separator = ',';
1153 int commas;
1154
1155 if (*p_src == '-') {
1156 *p_dst++ = *p_src++;
1157 num_len--;
1158 }
1159
1160 for (commas = 2 - num_len % 3; *p_src; commas = (commas + 1) % 3) {
1161 *p_dst++ = *p_src++;
1162 if (commas == 1) {
1163 *p_dst++ = separator;
1164 }
1165 }
1166 *--p_dst = '\0';
1167
1168 return size_t(p_dst - dst);
1169}
1170
1172{
1173 const size_t dst_maxncpy = BLI_STR_FORMAT_INT32_GROUPED_SIZE;
1174 BLI_string_debug_size(dst, dst_maxncpy);
1175 UNUSED_VARS_NDEBUG(dst_maxncpy);
1176
1178 const int num_len = int(SNPRINTF(src, "%d", num));
1179
1180 return BLI_str_format_int_grouped_ex(src, dst, num_len);
1181}
1182
1184{
1185 const size_t dst_maxncpy = BLI_STR_FORMAT_UINT64_GROUPED_SIZE;
1186 BLI_string_debug_size(dst, dst_maxncpy);
1187 UNUSED_VARS_NDEBUG(dst_maxncpy);
1188
1190 const int num_len = int(SNPRINTF(src, "%" PRIu64 "", num));
1191
1192 return BLI_str_format_int_grouped_ex(src, dst, num_len);
1193}
1194
1196{
1197 const size_t dst_maxncpy = BLI_STR_FORMAT_INT64_GROUPED_SIZE;
1198 BLI_string_debug_size(dst, dst_maxncpy);
1199 UNUSED_VARS_NDEBUG(dst_maxncpy);
1200
1202 const int num_len = int(SNPRINTF(src, "%" PRId64 "", num));
1203
1204 return BLI_str_format_int_grouped_ex(src, dst, num_len);
1205}
1206
1208 long long int bytes,
1209 const bool base_10)
1210{
1211 const size_t dst_maxncpy = BLI_STR_FORMAT_INT64_BYTE_UNIT_SIZE;
1212 BLI_string_debug_size(dst, dst_maxncpy);
1213
1214 double bytes_converted = double(bytes);
1215 int order = 0;
1216 int decimals;
1217 const int base = base_10 ? 1000 : 1024;
1218 const char *units_base_10[] = {"B", "KB", "MB", "GB", "TB", "PB"};
1219 const char *units_base_2[] = {"B", "KiB", "MiB", "GiB", "TiB", "PiB"};
1220 const int units_num = int(ARRAY_SIZE(units_base_2));
1221
1222 BLI_STATIC_ASSERT(ARRAY_SIZE(units_base_2) == ARRAY_SIZE(units_base_10), "array size mismatch");
1223
1224 while ((fabs(bytes_converted) >= base) && ((order + 1) < units_num)) {
1225 bytes_converted /= base;
1226 order++;
1227 }
1228 decimals = std::max(order - 1, 0);
1229
1230 /* Format value first, stripping away floating zeroes. */
1231 size_t len = BLI_snprintf_rlen(dst, dst_maxncpy, "%.*f", decimals, bytes_converted);
1232 len -= size_t(BLI_str_rstrip_float_zero(dst, '\0'));
1233 dst[len++] = ' ';
1234 BLI_strncpy(dst + len, base_10 ? units_base_10[order] : units_base_2[order], dst_maxncpy - len);
1235}
1236
1238 long long int bytes,
1239 const bool base_10)
1240{
1241 const size_t dst_maxncpy = BLI_STR_FORMAT_INT64_BYTE_UNIT_COMPACT_SIZE;
1242 BLI_string_debug_size(dst, dst_maxncpy);
1243
1244 float number_to_format_converted = float(bytes);
1245 int order = 0;
1246 const float base = base_10 ? 1000.0f : 1024.0f;
1247 const char *units[] = {"B", "K", "M", "G", "T", "P"};
1248 const int units_num = int(ARRAY_SIZE(units));
1249
1250 while ((fabsf(number_to_format_converted) >= base) && ((order + 1) < units_num)) {
1251 number_to_format_converted /= base;
1252 order++;
1253 }
1254
1255 const bool add_dot = (llabs(bytes) > 99999) && fabsf(number_to_format_converted) > 99;
1256
1257 if (add_dot) {
1258 number_to_format_converted /= 100.0f;
1259 order++;
1260 }
1261
1262 BLI_snprintf(dst,
1263 dst_maxncpy,
1264 "%s%d%s",
1265 add_dot ? "." : "",
1266 int(floorf(fabsf(number_to_format_converted))),
1267 units[order]);
1268}
1269
1271 int number_to_format)
1272{
1274
1275 float number_to_format_converted = float(number_to_format);
1276 int order = 0;
1277 const float base = 1000.0f;
1278 const char *units[] = {"", "K", "M", "B"};
1279 const int units_num = int(ARRAY_SIZE(units));
1280
1281 while ((fabsf(number_to_format_converted) >= base) && ((order + 1) < units_num)) {
1282 number_to_format_converted /= base;
1283 order++;
1284 }
1285
1286 const size_t dst_maxncpy = BLI_STR_FORMAT_INT32_DECIMAL_UNIT_SIZE;
1287 int decimals = 0;
1288 if ((order > 0) && fabsf(number_to_format_converted) < 100.0f) {
1289 decimals = 1;
1290 }
1291 BLI_snprintf(dst, dst_maxncpy, "%.*f%s", decimals, number_to_format_converted, units[order]);
1292}
1293
1295 const int number_to_format)
1296{
1297 const size_t dst_maxncpy = BLI_STR_FORMAT_INT32_INTEGER_UNIT_SIZE;
1298 BLI_string_debug_size(dst, dst_maxncpy);
1299
1300 float number_to_format_converted = float(number_to_format);
1301 int order = 0;
1302 const float base = 1000;
1303 const char *units[] = {"", "K", "M", "B"};
1304 const int units_num = int(ARRAY_SIZE(units));
1305
1306 while ((fabsf(number_to_format_converted) >= base) && ((order + 1) < units_num)) {
1307 number_to_format_converted /= base;
1308 order++;
1309 }
1310
1311 const bool add_dot = (abs(number_to_format) > 99999) && fabsf(number_to_format_converted) > 99;
1312
1313 if (add_dot) {
1314 number_to_format_converted /= 100;
1315 order++;
1316 }
1317
1318 BLI_snprintf(dst,
1319 dst_maxncpy,
1320 "%s%s%d%s",
1321 number_to_format < 0 ? "-" : "",
1322 add_dot ? "." : "",
1323 int(floorf(fabsf(number_to_format_converted))),
1324 units[order]);
1325}
1326
1328
1329/* -------------------------------------------------------------------- */
1332
1333#ifdef WITH_STRSIZE_DEBUG
1334void BLI_string_debug_size_after_nil(char *str, size_t str_maxncpy)
1335{
1336 /* Step over the nil, into the character afterwards. */
1337 size_t str_tail = BLI_strnlen(str, str_maxncpy) + 2;
1338 if (str_tail < str_maxncpy) {
1339 BLI_string_debug_size(str + str_tail, str_maxncpy - str_tail);
1340 }
1341}
1342
1343#endif /* WITH_STRSIZE_DEBUG */
1344
#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
ATTR_WARN_UNUSED_RESULT const size_t num
#define BLI_STR_FORMAT_INT64_GROUPED_SIZE
Definition BLI_string.h:25
#define BLI_STR_FORMAT_INT64_BYTE_UNIT_SIZE
Definition BLI_string.h:31
#define SNPRINTF(dst, format,...)
Definition BLI_string.h:604
#define BLI_STR_FORMAT_INT32_DECIMAL_UNIT_SIZE
Definition BLI_string.h:37
#define BLI_string_debug_size_after_nil(str, str_maxncpy)
Definition BLI_string.h:681
#define BLI_STR_FORMAT_INT32_GROUPED_SIZE
Definition BLI_string.h:28
#define BLI_STR_FORMAT_INT32_INTEGER_UNIT_SIZE
Definition BLI_string.h:40
#define BLI_string_debug_size(str, str_maxncpy)
Definition BLI_string.h:676
#define BLI_STR_FORMAT_UINT64_GROUPED_SIZE
Definition BLI_string.h:22
#define BLI_STR_FORMAT_INT64_BYTE_UNIT_COMPACT_SIZE
Definition BLI_string.h:34
#define ARRAY_SIZE(arr)
#define UNUSED_VARS_NDEBUG(...)
#define UNLIKELY(x)
#define ELEM(...)
#define STREQ(a, b)
Read Guarded memory(de)allocation.
#define MEM_reallocN(vmemh, len)
int pad[32 - sizeof(int)]
long long int int64_t
unsigned long long int uint64_t
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
nullptr float
#define str(s)
#define abs
#define PRIu64
Definition inttypes.h:132
#define PRId64
Definition inttypes.h:78
format
void * MEM_calloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:123
void * MEM_malloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:133
ccl_device_inline float2 fabs(const float2 a)
const char * name
return ret
#define floorf
#define fabsf
int BLI_str_index_in_array(const char *__restrict str, const char **__restrict str_array)
Definition string.cc:861
size_t BLI_str_format_int_grouped(char dst[BLI_STR_FORMAT_INT32_GROUPED_SIZE], int num)
Definition string.cc:1171
#define CASE_PAIR(value_src, value_dst)
char * BLI_strdupn(const char *str, const size_t len)
Definition string.cc:30
static int left_number_strcmp(const char *s1, const char *s2, int *tiebreaker)
Definition string.cc:684
char * BLI_strncasestr(const char *s, const char *find, size_t len)
Definition string.cc:606
int BLI_strcasecmp(const char *s1, const char *s2)
Definition string.cc:637
void BLI_str_format_decimal_unit(char dst[BLI_STR_FORMAT_INT32_DECIMAL_UNIT_SIZE], int number_to_format)
Definition string.cc:1270
size_t BLI_str_partition(const char *str, const char delim[], const char **sep, const char **suf)
Definition string.cc:1029
bool BLI_string_has_word_prefix(const char *haystack, const char *needle, size_t needle_len)
Definition string.cc:578
int BLI_string_max_possible_word_count(const int str_len)
Definition string.cc:573
void BLI_str_format_byte_unit_compact(char dst[BLI_STR_FORMAT_INT64_BYTE_UNIT_COMPACT_SIZE], long long int bytes, const bool base_10)
Definition string.cc:1237
bool BLI_string_all_words_matched(const char *name, const char *str, int(*words)[2], const int words_len)
Definition string.cc:590
void BLI_str_rstrip(char *str)
Definition string.cc:980
void BLI_str_format_byte_unit(char dst[BLI_STR_FORMAT_INT64_BYTE_UNIT_SIZE], long long int bytes, const bool base_10)
Definition string.cc:1207
char * BLI_vsprintfN(const char *__restrict format, va_list args)
Definition string.cc:309
size_t BLI_str_format_int64_grouped(char dst[BLI_STR_FORMAT_INT64_GROUPED_SIZE], int64_t num)
Definition string.cc:1195
int BLI_strcmp_ignore_pad(const char *str1, const char *str2, const char pad)
Definition string.cc:800
int BLI_str_index_in_array_n(const char *__restrict str, const char **__restrict str_array, const int str_array_len)
Definition string.cc:846
char * BLI_strcasestr(const char *s, const char *find)
Definition string.cc:552
int BLI_strcasecmp_natural(const char *s1, const char *s2)
Definition string.cc:733
int BLI_strncasecmp(const char *s1, const char *s2, size_t len)
Definition string.cc:660
size_t BLI_snprintf_rlen(char *__restrict dst, size_t dst_maxncpy, const char *__restrict format,...)
Definition string.cc:211
char BLI_toupper_ascii(const char c)
Definition string.cc:951
size_t BLI_snprintf(char *__restrict dst, size_t dst_maxncpy, const char *__restrict format,...)
Definition string.cc:199
char * BLI_vsprintfN_with_buffer(char *fixed_buf, size_t fixed_buf_size, size_t *result_len, const char *__restrict format, va_list args)
Definition string.cc:258
void BLI_str_format_integer_unit(char dst[BLI_STR_FORMAT_INT32_INTEGER_UNIT_SIZE], const int number_to_format)
Definition string.cc:1294
bool BLI_str_quoted_substr_range(const char *__restrict str, const char *__restrict prefix, int *__restrict r_start, int *__restrict r_end)
Definition string.cc:456
int BLI_string_find_split_words(const char *str, const size_t str_maxlen, const char delim, int r_words[][2], int words_max)
Definition string.cc:1088
char * BLI_strdup_null(const char *str)
Definition string.cc:46
size_t BLI_str_escape(char *__restrict dst, const char *__restrict src, const size_t dst_maxncpy)
Definition string.cc:330
void BLI_str_tolower_ascii(char *str, const size_t len)
Definition string.cc:956
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.cc:1039
size_t BLI_str_rpartition(const char *str, const char delim[], const char **sep, const char **suf)
Definition string.cc:1034
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, const size_t dst_maxncpy)
Definition string.cc:68
size_t BLI_vsnprintf(char *__restrict dst, size_t dst_maxncpy, const char *__restrict format, va_list arg)
Definition string.cc:154
bool BLI_strn_endswith(const char *__restrict str, const char *__restrict end, size_t str_len)
Definition string.cc:885
char * BLI_sprintfN_with_buffer(char *fixed_buf, size_t fixed_buf_size, size_t *result_len, const char *__restrict format,...)
Definition string.cc:226
size_t BLI_strnlen(const char *str, const size_t maxlen)
Definition string.cc:913
size_t BLI_str_unescape(char *__restrict dst, const char *__restrict src, const size_t src_maxncpy)
Definition string.cc:422
char * BLI_strncpy_ensure_pad(char *__restrict dst, const char *__restrict src, const char pad, size_t dst_maxncpy)
Definition string.cc:80
BLI_INLINE bool str_unescape_pair(char c_next, char *r_out)
Definition string.cc:373
size_t BLI_vsnprintf_rlen(char *__restrict dst, size_t dst_maxncpy, const char *__restrict format, va_list arg)
Definition string.cc:176
char * BLI_sprintfN(const char *__restrict format,...)
Definition string.cc:291
size_t BLI_strncpy_rlen(char *__restrict dst, const char *__restrict src, const size_t dst_maxncpy)
Definition string.cc:119
char BLI_tolower_ascii(const char c)
Definition string.cc:946
bool BLI_string_elem_split_by_delim(const char *haystack, const char delim, const char *needle)
Definition string.cc:1123
static size_t BLI_str_format_int_grouped_ex(char *src, char *dst, int num_len)
Definition string.cc:1147
const char * BLI_str_escape_find_quote(const char *str)
Definition string.cc:438
const char * BLI_strchr_or_end(const char *str, const char ch)
Definition string.cc:931
bool BLI_str_quoted_substr(const char *__restrict str, const char *__restrict prefix, char *result, size_t result_maxncpy)
Definition string.cc:521
void BLI_str_toupper_ascii(char *str, const size_t len)
Definition string.cc:965
bool BLI_str_endswith(const char *__restrict str, const char *__restrict end)
Definition string.cc:901
size_t BLI_str_format_uint64_grouped(char dst[BLI_STR_FORMAT_UINT64_GROUPED_SIZE], uint64_t num)
Definition string.cc:1183
char * BLI_strdupcat(const char *__restrict str1, const char *__restrict str2)
Definition string.cc:51
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.cc:394
int BLI_str_rstrip_float_zero(char *str, const char pad)
Definition string.cc:992
char * BLI_strncat(char *__restrict dst, const char *__restrict src, const size_t dst_maxncpy)
Definition string.cc:137
char * BLI_strdup(const char *str)
Definition string.cc:41
bool BLI_str_startswith(const char *__restrict str, const char *__restrict start)
Definition string.cc:874
int BLI_strcaseeq(const char *a, const char *b)
Definition string.cc:547
int BLI_str_rstrip_digits(char *str)
Definition string.cc:1012
i
Definition text_draw.cc:230
uint len