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