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