Add number and memory size formatting throughout the UI
[blender.git] / source / blender / blenlib / intern / string.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
19  * All rights reserved.
20  *
21  * The Original Code is: all of this file.
22  *
23  * Contributor(s): none yet.
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  * 
27  */
28
29 /** \file blender/blenlib/intern/string.c
30  *  \ingroup bli
31  */
32
33
34 #include <string.h>
35 #include <stdlib.h>
36 #include <stdarg.h>
37 #include <ctype.h>
38
39 #include "MEM_guardedalloc.h"
40
41 #include "BLI_dynstr.h"
42 #include "BLI_string.h"
43
44 #include "BLI_utildefines.h"
45
46 #ifdef __GNUC__
47 #  pragma GCC diagnostic error "-Wsign-conversion"
48 #endif
49
50 // #define DEBUG_STRSIZE
51
52 /**
53  * Duplicates the first \a len bytes of cstring \a str
54  * into a newly mallocN'd string and returns it. \a str
55  * is assumed to be at least len bytes long.
56  *
57  * \param str The string to be duplicated
58  * \param len The number of bytes to duplicate
59  * \retval Returns the duplicated string
60  */
61 char *BLI_strdupn(const char *str, const size_t len)
62 {
63         char *n = MEM_mallocN(len + 1, "strdup");
64         memcpy(n, str, len);
65         n[len] = '\0';
66         
67         return n;
68 }
69
70 /**
71  * Duplicates the cstring \a str into a newly mallocN'd
72  * string and returns it.
73  *
74  * \param str The string to be duplicated
75  * \retval Returns the duplicated string
76  */
77 char *BLI_strdup(const char *str)
78 {
79         return BLI_strdupn(str, strlen(str));
80 }
81
82 /**
83  * Appends the two strings, and returns new mallocN'ed string
84  * \param str1 first string for copy
85  * \param str2 second string for append
86  * \retval Returns dst
87  */
88 char *BLI_strdupcat(const char *__restrict str1, const char *__restrict str2)
89 {
90         /* include the NULL terminator of str2 only */
91         const size_t str1_len = strlen(str1);
92         const size_t str2_len = strlen(str2) + 1;
93         char *str, *s;
94         
95         str = MEM_mallocN(str1_len + str2_len, "strdupcat");
96         s = str;
97
98         memcpy(s, str1, str1_len); s += str1_len;
99         memcpy(s, str2, str2_len);
100
101         return str;
102 }
103
104 /**
105  * Like strncpy but ensures dst is always
106  * '\0' terminated.
107  *
108  * \param dst Destination for copy
109  * \param src Source string to copy
110  * \param maxncpy Maximum number of characters to copy (generally
111  * the size of dst)
112  * \retval Returns dst
113  */
114 char *BLI_strncpy(char *__restrict dst, const char *__restrict src, const size_t maxncpy)
115 {
116         size_t srclen = BLI_strnlen(src, maxncpy - 1);
117         BLI_assert(maxncpy != 0);
118
119 #ifdef DEBUG_STRSIZE
120         memset(dst, 0xff, sizeof(*dst) * maxncpy);
121 #endif
122
123         memcpy(dst, src, srclen);
124         dst[srclen] = '\0';
125         return dst;
126 }
127
128 /**
129  * Like BLI_strncpy but ensures dst is always padded by given char, on both sides (unless src is empty).
130  *
131  * \param dst Destination for copy
132  * \param src Source string to copy
133  * \param pad the char to use for padding
134  * \param maxncpy Maximum number of characters to copy (generally the size of dst)
135  * \retval Returns dst
136  */
137 char *BLI_strncpy_ensure_pad(char *__restrict dst, const char *__restrict src, const char pad, size_t maxncpy)
138 {
139         BLI_assert(maxncpy != 0);
140
141 #ifdef DEBUG_STRSIZE
142         memset(dst, 0xff, sizeof(*dst) * maxncpy);
143 #endif
144
145         if (src[0] == '\0') {
146                 dst[0] = '\0';
147         }
148         else {
149                 /* Add heading/trailing wildcards if needed. */
150                 size_t idx = 0;
151                 size_t srclen;
152
153                 if (src[idx] != pad) {
154                         dst[idx++] = pad;
155                         maxncpy--;
156                 }
157                 maxncpy--;  /* trailing '\0' */
158
159                 srclen = BLI_strnlen(src, maxncpy);
160                 if ((src[srclen - 1] != pad) && (srclen == maxncpy)) {
161                         srclen--;
162                 }
163
164                 memcpy(&dst[idx], src, srclen);
165                 idx += srclen;
166
167                 if (dst[idx - 1] != pad) {
168                         dst[idx++] = pad;
169                 }
170                 dst[idx] = '\0';
171         }
172
173         return dst;
174 }
175
176 /**
177  * Like strncpy but ensures dst is always
178  * '\0' terminated.
179  *
180  * \note This is a duplicate of #BLI_strncpy that returns bytes copied.
181  * And is a drop in replacement for 'snprintf(str, sizeof(str), "%s", arg);'
182  *
183  * \param dst Destination for copy
184  * \param src Source string to copy
185  * \param maxncpy Maximum number of characters to copy (generally
186  * the size of dst)
187  * \retval The number of bytes copied (The only difference from BLI_strncpy).
188  */
189 size_t BLI_strncpy_rlen(char *__restrict dst, const char *__restrict src, const size_t maxncpy)
190 {
191         size_t srclen = BLI_strnlen(src, maxncpy - 1);
192         BLI_assert(maxncpy != 0);
193
194 #ifdef DEBUG_STRSIZE
195         memset(dst, 0xff, sizeof(*dst) * maxncpy);
196 #endif
197
198         memcpy(dst, src, srclen);
199         dst[srclen] = '\0';
200         return srclen;
201 }
202
203 size_t BLI_strcpy_rlen(char *__restrict dst, const char *__restrict src)
204 {
205         size_t srclen = strlen(src);
206         memcpy(dst, src, srclen + 1);
207         return srclen;
208 }
209
210 /**
211  * Portable replacement for `vsnprintf`.
212  */
213 size_t BLI_vsnprintf(char *__restrict buffer, size_t maxncpy, const char *__restrict format, va_list arg)
214 {
215         size_t n;
216
217         BLI_assert(buffer != NULL);
218         BLI_assert(maxncpy > 0);
219         BLI_assert(format != NULL);
220
221         n = (size_t)vsnprintf(buffer, maxncpy, format, arg);
222
223         if (n != -1 && n < maxncpy) {
224                 buffer[n] = '\0';
225         }
226         else {
227                 buffer[maxncpy - 1] = '\0';
228         }
229
230         return n;
231 }
232
233 /**
234  * A version of #BLI_vsnprintf that returns ``strlen(buffer)``
235  */
236 size_t BLI_vsnprintf_rlen(char *__restrict buffer, size_t maxncpy, const char *__restrict format, va_list arg)
237 {
238         size_t n;
239
240         BLI_assert(buffer != NULL);
241         BLI_assert(maxncpy > 0);
242         BLI_assert(format != NULL);
243
244         n = (size_t)vsnprintf(buffer, maxncpy, format, arg);
245
246         if (n != -1 && n < maxncpy) {
247                 /* pass */
248         }
249         else {
250                 n = maxncpy - 1;
251         }
252         buffer[n] = '\0';
253
254         return n;
255 }
256
257 /**
258  * Portable replacement for #snprintf
259  */
260 size_t BLI_snprintf(char *__restrict dst, size_t maxncpy, const char *__restrict format, ...)
261 {
262         size_t n;
263         va_list arg;
264
265 #ifdef DEBUG_STRSIZE
266         memset(dst, 0xff, sizeof(*dst) * maxncpy);
267 #endif
268
269         va_start(arg, format);
270         n = BLI_vsnprintf(dst, maxncpy, format, arg);
271         va_end(arg);
272
273         return n;
274 }
275
276 /**
277  * A version of #BLI_snprintf that returns ``strlen(dst)``
278  */
279 size_t BLI_snprintf_rlen(char *__restrict dst, size_t maxncpy, const char *__restrict format, ...)
280 {
281         size_t n;
282         va_list arg;
283
284 #ifdef DEBUG_STRSIZE
285         memset(dst, 0xff, sizeof(*dst) * maxncpy);
286 #endif
287
288         va_start(arg, format);
289         n = BLI_vsnprintf_rlen(dst, maxncpy, format, arg);
290         va_end(arg);
291
292         return n;
293 }
294
295 /**
296  * Print formatted string into a newly #MEM_mallocN'd string
297  * and return it.
298  */
299 char *BLI_sprintfN(const char *__restrict format, ...)
300 {
301         DynStr *ds;
302         va_list arg;
303         char *n;
304
305         va_start(arg, format);
306
307         ds = BLI_dynstr_new();
308         BLI_dynstr_vappendf(ds, format, arg);
309         n = BLI_dynstr_get_cstring(ds);
310         BLI_dynstr_free(ds);
311
312         va_end(arg);
313
314         return n;
315 }
316
317
318 /* match pythons string escaping, assume double quotes - (")
319  * TODO: should be used to create RNA animation paths.
320  * TODO: support more fancy string escaping. current code is primitive
321  *    this basically is an ascii version of PyUnicode_EncodeUnicodeEscape()
322  *    which is a useful reference. */
323 size_t BLI_strescape(char *__restrict dst, const char *__restrict src, const size_t maxncpy)
324 {
325         size_t len = 0;
326
327         BLI_assert(maxncpy != 0);
328
329         while (len < maxncpy) {
330                 switch (*src) {
331                         case '\0':
332                                 goto escape_finish;
333                         case '\\':
334                         case '"':
335                                 ATTR_FALLTHROUGH;
336
337                         /* less common but should also be support */
338                         case '\t':
339                         case '\n':
340                         case '\r':
341                                 if (len + 1 < maxncpy) {
342                                         *dst++ = '\\';
343                                         len++;
344                                 }
345                                 else {
346                                         /* not enough space to escape */
347                                         break;
348                                 }
349                                 ATTR_FALLTHROUGH;
350                         default:
351                                 *dst = *src;
352                                 break;
353                 }
354                 dst++;
355                 src++;
356                 len++;
357         }
358
359 escape_finish:
360
361         *dst = '\0';
362
363         return len;
364 }
365
366 /**
367  * Makes a copy of the text within the "" that appear after some text 'blahblah'
368  * i.e. for string 'pose["apples"]' with prefix 'pose[', it should grab "apples"
369  *
370  * - str: is the entire string to chop
371  * - prefix: is the part of the string to leave out
372  *
373  * Assume that the strings returned must be freed afterwards, and that the inputs will contain
374  * data we want...
375  *
376  * \return the offset and a length so as to avoid doing an allocation.
377  */
378 char *BLI_str_quoted_substrN(const char *__restrict str, const char *__restrict prefix)
379 {
380         const char *startMatch, *endMatch;
381
382         /* get the starting point (i.e. where prefix starts, and add prefixLen+1 to it to get be after the first " */
383         startMatch = strstr(str, prefix);
384         if (startMatch) {
385                 const size_t prefixLen = strlen(prefix);
386                 startMatch += prefixLen + 1;
387                 /* get the end point (i.e. where the next occurance of " is after the starting point) */
388
389                 endMatch = startMatch;
390                 while ((endMatch = strchr(endMatch, '"'))) {
391                         if (LIKELY(*(endMatch - 1) != '\\')) {
392                                 break;
393                         }
394                         else {
395                                 endMatch++;
396                         }
397                 }
398
399                 if (endMatch) {
400                         /* return the slice indicated */
401                         return BLI_strdupn(startMatch, (size_t)(endMatch - startMatch));
402                 }
403         }
404         return BLI_strdupn("", 0);
405 }
406
407 /**
408  * string with all instances of substr_old replaced with substr_new,
409  * Returns a copy of the cstring \a str into a newly mallocN'd
410  * and returns it.
411  *
412  * \note A rather wasteful string-replacement utility, though this shall do for now...
413  * Feel free to replace this with an even safe + nicer alternative
414  *
415  * \param str The string to replace occurrences of substr_old in
416  * \param substr_old The text in the string to find and replace
417  * \param substr_new The text in the string to find and replace
418  * \retval Returns the duplicated string
419  */
420 char *BLI_str_replaceN(const char *__restrict str, const char *__restrict substr_old, const char *__restrict substr_new)
421 {
422         DynStr *ds = NULL;
423         size_t len_old = strlen(substr_old);
424         const char *match;
425
426         BLI_assert(substr_old[0] != '\0');
427
428         /* while we can still find a match for the old substring that we're searching for, 
429          * keep dicing and replacing
430          */
431         while ((match = strstr(str, substr_old))) {
432                 /* the assembly buffer only gets created when we actually need to rebuild the string */
433                 if (ds == NULL)
434                         ds = BLI_dynstr_new();
435                         
436                 /* if the match position does not match the current position in the string, 
437                  * copy the text up to this position and advance the current position in the string
438                  */
439                 if (str != match) {
440                         /* add the segment of the string from str to match to the buffer, then restore the value at match
441                          */
442                         BLI_dynstr_nappend(ds, str, (match - str));
443                         
444                         /* now our current position should be set on the start of the match */
445                         str = match;
446                 }
447                 
448                 /* add the replacement text to the accumulation buffer */
449                 BLI_dynstr_append(ds, substr_new);
450                 
451                 /* advance the current position of the string up to the end of the replaced segment */
452                 str += len_old;
453         }
454         
455         /* finish off and return a new string that has had all occurrences of */
456         if (ds) {
457                 char *str_new;
458                 
459                 /* add what's left of the string to the assembly buffer 
460                  * - we've been adjusting str to point at the end of the replaced segments
461                  */
462                 BLI_dynstr_append(ds, str);
463                 
464                 /* convert to new c-string (MEM_malloc'd), and free the buffer */
465                 str_new = BLI_dynstr_get_cstring(ds);
466                 BLI_dynstr_free(ds);
467                 
468                 return str_new;
469         }
470         else {
471                 /* just create a new copy of the entire string - we avoid going through the assembly buffer 
472                  * for what should be a bit more efficiency...
473                  */
474                 return BLI_strdup(str);
475         }
476
477
478 /**
479  * In-place replace every \a src to \a dst in \a str.
480  *
481  * \param str: The string to operate on.
482  * \param src: The character to replace.
483  * \param dst: The character to replace with.
484  */
485 void BLI_str_replace_char(char *str, char src, char dst)
486 {
487         while (*str) {
488                 if (*str == src) {
489                         *str = dst;
490                 }
491                 str++;
492         }
493 }
494
495 /**
496  * Compare two strings without regard to case.
497  *
498  * \retval True if the strings are equal, false otherwise.
499  */
500 int BLI_strcaseeq(const char *a, const char *b) 
501 {
502         return (BLI_strcasecmp(a, b) == 0);
503 }
504
505 /**
506  * Portable replacement for `strcasestr` (not available in MSVC)
507  */
508 char *BLI_strcasestr(const char *s, const char *find)
509 {
510         register char c, sc;
511         register size_t len;
512         
513         if ((c = *find++) != 0) {
514                 c = tolower(c);
515                 len = strlen(find);
516                 do {
517                         do {
518                                 if ((sc = *s++) == 0)
519                                         return (NULL);
520                                 sc = tolower(sc);
521                         } while (sc != c);
522                 } while (BLI_strncasecmp(s, find, len) != 0);
523                 s--;
524         }
525         return ((char *) s);
526 }
527
528 /**
529  * Variation of #BLI_strcasestr with string length limited to \a len
530  */
531 char *BLI_strncasestr(const char *s, const char *find, size_t len)
532 {
533         register char c, sc;
534
535         if ((c = *find++) != 0) {
536                 c = tolower(c);
537                 if (len > 1) {
538                         do {
539                                 do {
540                                         if ((sc = *s++) == 0)
541                                                 return NULL;
542                                         sc = tolower(sc);
543                                 } while (sc != c);
544                         } while (BLI_strncasecmp(s, find, len - 1) != 0);
545                 }
546                 else {
547                         {
548                                 do {
549                                         if ((sc = *s++) == 0)
550                                                 return NULL;
551                                         sc = tolower(sc);
552                                 } while (sc != c);
553                         }
554                 }
555                 s--;
556         }
557         return ((char *)s);
558 }
559
560 int BLI_strcasecmp(const char *s1, const char *s2)
561 {
562         register int i;
563         register char c1, c2;
564
565         for (i = 0;; i++) {
566                 c1 = tolower(s1[i]);
567                 c2 = tolower(s2[i]);
568
569                 if (c1 < c2) {
570                         return -1;
571                 }
572                 else if (c1 > c2) {
573                         return 1;
574                 }
575                 else if (c1 == 0) {
576                         break;
577                 }
578         }
579
580         return 0;
581 }
582
583 int BLI_strncasecmp(const char *s1, const char *s2, size_t len)
584 {
585         register size_t i;
586         register char c1, c2;
587
588         for (i = 0; i < len; i++) {
589                 c1 = tolower(s1[i]);
590                 c2 = tolower(s2[i]);
591
592                 if (c1 < c2) {
593                         return -1;
594                 }
595                 else if (c1 > c2) {
596                         return 1;
597                 }
598                 else if (c1 == 0) {
599                         break;
600                 }
601         }
602
603         return 0;
604 }
605
606 /* compare number on the left size of the string */
607 static int left_number_strcmp(const char *s1, const char *s2, int *tiebreaker)
608 {
609         const char *p1 = s1, *p2 = s2;
610         int numdigit, numzero1, numzero2;
611
612         /* count and skip leading zeros */
613         for (numzero1 = 0; *p1 && (*p1 == '0'); numzero1++)
614                 p1++;
615         for (numzero2 = 0; *p2 && (*p2 == '0'); numzero2++)
616                 p2++;
617
618         /* find number of consecutive digits */
619         for (numdigit = 0; ; numdigit++) {
620                 if (isdigit(*(p1 + numdigit)) && isdigit(*(p2 + numdigit)))
621                         continue;
622                 else if (isdigit(*(p1 + numdigit)))
623                         return 1; /* s2 is bigger */
624                 else if (isdigit(*(p2 + numdigit)))
625                         return -1; /* s1 is bigger */
626                 else
627                         break;
628         }
629
630         /* same number of digits, compare size of number */
631         if (numdigit > 0) {
632                 int compare = (int)strncmp(p1, p2, (size_t)numdigit);
633
634                 if (compare != 0)
635                         return compare;
636         }
637
638         /* use number of leading zeros as tie breaker if still equal */
639         if (*tiebreaker == 0) {
640                 if (numzero1 > numzero2)
641                         *tiebreaker = 1;
642                 else if (numzero1 < numzero2)
643                         *tiebreaker = -1;
644         }
645
646         return 0;
647 }
648
649 /* natural string compare, keeping numbers in order */
650 int BLI_natstrcmp(const char *s1, const char *s2)
651 {
652         register int d1 = 0, d2 = 0;
653         register char c1, c2;
654         int tiebreaker = 0;
655
656         /* if both chars are numeric, to a left_number_strcmp().
657          * then increase string deltas as long they are 
658          * numeric, else do a tolower and char compare */
659
660         while (1) {
661                 c1 = tolower(s1[d1]);
662                 c2 = tolower(s2[d2]);
663                 
664                 if (isdigit(c1) && isdigit(c2)) {
665                         int numcompare = left_number_strcmp(s1 + d1, s2 + d2, &tiebreaker);
666                         
667                         if (numcompare != 0)
668                                 return numcompare;
669
670                         d1++;
671                         while (isdigit(s1[d1]))
672                                 d1++;
673                         d2++;
674                         while (isdigit(s2[d2]))
675                                 d2++;
676                         
677                         c1 = tolower(s1[d1]);
678                         c2 = tolower(s2[d2]);
679                 }
680         
681                 /* first check for '.' so "foo.bar" comes before "foo 1.bar" */
682                 if (c1 == '.' && c2 != '.')
683                         return -1;
684                 if (c1 != '.' && c2 == '.')
685                         return 1;
686                 else if (c1 < c2) {
687                         return -1;
688                 }
689                 else if (c1 > c2) {
690                         return 1;
691                 }
692                 else if (c1 == 0) {
693                         break;
694                 }
695                 d1++;
696                 d2++;
697         }
698
699         if (tiebreaker)
700                 return tiebreaker;
701         
702         /* we might still have a different string because of lower/upper case, in
703          * that case fall back to regular string comparison */
704         return strcmp(s1, s2);
705 }
706
707 /**
708  * Like strcmp, but will ignore any heading/trailing pad char for comparison.
709  * So e.g. if pad is '*', '*world' and 'world*' will compare equal.
710  */
711 int BLI_strcmp_ignore_pad(const char *str1, const char *str2, const char pad)
712 {
713         size_t str1_len, str2_len;
714
715         while (*str1 == pad) {
716                 str1++;
717         }
718         while (*str2 == pad) {
719                 str2++;
720         }
721
722         str1_len = strlen(str1);
723         str2_len = strlen(str2);
724
725         while (str1_len && (str1[str1_len - 1] == pad)) {
726                 str1_len--;
727         }
728         while (str2_len && (str2[str2_len - 1] == pad)) {
729                 str2_len--;
730         }
731
732         if (str1_len == str2_len) {
733                 return strncmp(str1, str2, str2_len);
734         }
735         else if (str1_len > str2_len) {
736                 int ret = strncmp(str1, str2, str2_len);
737                 if (ret == 0) {
738                         ret = 1;
739                 }
740                 return ret;
741         }
742         else {
743                 int ret = strncmp(str1, str2, str1_len);
744                 if (ret == 0) {
745                         ret = -1;
746                 }
747                 return ret;
748         }
749 }
750
751 /* determine the length of a fixed-size string */
752 size_t BLI_strnlen(const char *s, const size_t maxlen)
753 {
754         size_t len;
755
756         for (len = 0; len < maxlen; len++, s++) {
757                 if (!*s)
758                         break;
759         }
760         return len;
761 }
762
763 void BLI_str_tolower_ascii(char *str, const size_t len)
764 {
765         size_t i;
766
767         for (i = 0; (i < len) && str[i]; i++)
768                 if (str[i] >= 'A' && str[i] <= 'Z')
769                         str[i] += 'a' - 'A';
770 }
771
772 void BLI_str_toupper_ascii(char *str, const size_t len)
773 {
774         size_t i;
775
776         for (i = 0; (i < len) && str[i]; i++)
777                 if (str[i] >= 'a' && str[i] <= 'z')
778                         str[i] -= 'a' - 'A';
779 }
780
781 /**
782  * Strip trailing zeros from a float, eg:
783  *   0.0000 -> 0.0
784  *   2.0010 -> 2.001
785  *
786  * \param str
787  * \param pad
788  * \return The number of zeros stripped.
789  */
790 int BLI_str_rstrip_float_zero(char *str, const char pad)
791 {
792         char *p = strchr(str, '.');
793         int totstrip = 0;
794         if (p) {
795                 char *end_p;
796                 p++;  /* position at first decimal place */
797                 end_p = p + (strlen(p) - 1);  /* position at last character */
798                 if (end_p > p) {
799                         while (end_p != p && *end_p == '0') {
800                                 *end_p = pad;
801                                 end_p--;
802                         }
803                 }
804         }
805
806         return totstrip;
807 }
808
809 /**
810  * Return index of a string in a string array.
811  *
812  * \param str The string to find.
813  * \param str_array Array of strings.
814  * \param str_array_len The length of the array, or -1 for a NULL-terminated array.
815  * \return The index of str in str_array or -1.
816  */
817 int BLI_str_index_in_array_n(const char *__restrict str, const char **__restrict str_array, const int str_array_len)
818 {
819         int index;
820         const char **str_iter = str_array;
821
822         for (index = 0; index < str_array_len; str_iter++, index++) {
823                 if (STREQ(str, *str_iter)) {
824                         return index;
825                 }
826         }
827         return -1;
828 }
829
830 /**
831  * Return index of a string in a string array.
832  *
833  * \param str The string to find.
834  * \param str_array Array of strings, (must be NULL-terminated).
835  * \return The index of str in str_array or -1.
836  */
837 int BLI_str_index_in_array(const char *__restrict str, const char **__restrict str_array)
838 {
839         int index;
840         const char **str_iter = str_array;
841
842         for (index = 0; *str_iter; str_iter++, index++) {
843                 if (STREQ(str, *str_iter)) {
844                         return index;
845                 }
846         }
847         return -1;
848 }
849
850 bool BLI_strn_endswith(const char *__restrict str, const char *__restrict end, size_t slength)
851 {
852         size_t elength = strlen(end);
853         
854         if (elength < slength) {
855                 const char *iter = &str[slength - elength];
856                 while (*iter) {
857                         if (*iter++ != *end++) {
858                                 return false;
859                         }
860                 }
861                 return true;
862         }
863         return false;
864 }
865
866 /**
867  * Find if a string ends with another string.
868  *
869  * \param str The string to search within.
870  * \param end The string we look for at the end.
871  * \return If str ends with end.
872  */
873 bool BLI_str_endswith(const char *__restrict str, const char * __restrict end)
874 {
875         const size_t slength = strlen(str);
876         return BLI_strn_endswith(str, end, slength);
877 }
878
879 /**
880  * Find the first char matching one of the chars in \a delim, from left.
881  *
882  * \param str The string to search within.
883  * \param delim The set of delimiters to search for, as unicode values.
884  * \param sep Return value, set to the first delimiter found (or NULL if none found).
885  * \param suf Return value, set to next char after the first delimiter found (or NULL if none found).
886  * \return The length of the prefix (i.e. *sep - str).
887  */
888 size_t BLI_str_partition(const char *str, const char delim[], const char **sep, const char **suf)
889 {
890         return BLI_str_partition_ex(str, NULL, delim, sep, suf, false);
891 }
892
893 /**
894  * Find the first char matching one of the chars in \a delim, from right.
895  *
896  * \param str The string to search within.
897  * \param delim The set of delimiters to search for, as unicode values.
898  * \param sep Return value, set to the first delimiter found (or NULL if none found).
899  * \param suf Return value, set to next char after the first delimiter found (or NULL if none found).
900  * \return The length of the prefix (i.e. *sep - str).
901  */
902 size_t BLI_str_rpartition(const char *str, const char delim[], const char **sep, const char **suf)
903 {
904         return BLI_str_partition_ex(str, NULL, delim, sep, suf, true);
905 }
906
907 /**
908  * Find the first char matching one of the chars in \a delim, either from left or right.
909  *
910  * \param str The string to search within.
911  * \param end If non-NULL, the right delimiter of the string.
912  * \param delim The set of delimiters to search for, as unicode values.
913  * \param sep Return value, set to the first delimiter found (or NULL if none found).
914  * \param suf Return value, set to next char after the first delimiter found (or NULL if none found).
915  * \param from_right If %true, search from the right of \a str, else, search from its left.
916  * \return The length of the prefix (i.e. *sep - str).
917  */
918 size_t BLI_str_partition_ex(
919         const char *str, const char *end, const char delim[], const char **sep, const char **suf, const bool from_right)
920 {
921         const char *d;
922         char *(*func)(const char *str, int c) = from_right ? strrchr : strchr;
923
924         BLI_assert(end == NULL || end > str);
925
926         *sep = *suf = NULL;
927
928         for (d = delim; *d != '\0'; ++d) {
929                 const char *tmp;
930
931                 if (end) {
932                         if (from_right) {
933                                 for (tmp = end - 1; (tmp >= str) && (*tmp != *d); tmp--);
934                                 if (tmp < str) {
935                                         tmp = NULL;
936                                 }
937                         }
938                         else {
939                                 tmp = func(str, *d);
940                                 if (tmp >= end) {
941                                         tmp = NULL;
942                                 }
943                         }
944                 }
945                 else {
946                         tmp = func(str, *d);
947                 }
948
949                 if (tmp && (from_right ? (*sep < tmp) : (!*sep || *sep > tmp))) {
950                         *sep = tmp;
951                 }
952         }
953
954         if (*sep) {
955                 *suf = *sep + 1;
956                 return (size_t)(*sep - str);
957         }
958
959         return end ? (size_t)(end - str) : strlen(str);
960 }
961
962 /**
963  * Format ints with decimal grouping.
964  * 1000 -> 1,000
965  *
966  * \param dst  The resulting string
967  * \param num  Number to format
968  * \return The length of \a dst
969  */
970 size_t BLI_str_format_int_grouped(char dst[16], int num)
971 {
972         char src[16];
973         char *p_src = src;
974         char *p_dst = dst;
975
976         const char separator = ',';
977         int num_len, commas;
978
979         num_len = sprintf(src, "%d", num);
980
981         if (*p_src == '-') {
982                 *p_dst++ = *p_src++;
983                 num_len--;
984         }
985
986         for (commas = 2 - num_len % 3; *p_src; commas = (commas + 1) % 3) {
987                 *p_dst++ = *p_src++;
988                 if (commas == 1) {
989                         *p_dst++ = separator;
990                 }
991         }
992         *--p_dst = '\0';
993
994         return (size_t)(p_dst - dst);
995 }
996
997 /**
998  * Format a size in bytes using binary units.
999  * 1000 -> 1 KB
1000  * Number of decimal places grows with the used unit (e.g. 1.5 MB, 1.55 GB, 1.545 TB).
1001  *
1002  * \param dst The resulting string. Dimension of 14 to support largest possible value for \a bytes (LLONG_MAX).
1003  * \param bytes Number to format
1004  * \param base_10 Calculate using base 10 (GB, MB, ...) or 2 (GiB, MiB, ...)
1005  */
1006 void BLI_str_format_byte_unit(char dst[15], long long int bytes, const bool base_10)
1007 {
1008         double bytes_converted = bytes;
1009         int order = 0;
1010         int decimals;
1011         const int base = base_10 ? 1000 : 1024;
1012         const char *units_base_10[] = {"B", "KB", "MB", "GB", "TB", "PB"};
1013         const char *units_base_2[] = {"B", "KiB", "MiB", "GiB", "TiB", "PiB"};
1014         const int tot_units = ARRAY_SIZE(units_base_2);
1015
1016         BLI_STATIC_ASSERT(ARRAY_SIZE(units_base_2) == ARRAY_SIZE(units_base_10), "array size mismatch");
1017
1018         while ((ABS(bytes_converted) >= base) && ((order + 1) < tot_units)) {
1019                 bytes_converted /= base;
1020                 order++;
1021         }
1022         decimals = MAX2(order - 1, 0);
1023
1024         /* Format value first, stripping away floating zeroes. */
1025         sprintf(dst, "%.*f", decimals, bytes_converted);
1026         BLI_str_rstrip_float_zero(dst, '\0');
1027         /* Append unit. */
1028         sprintf(dst, "%s %s", dst, base_10 ? units_base_10[order] : units_base_2[order]);
1029 }
1030
1031
1032 /**
1033  * Find the ranges needed to split \a str into its individual words.
1034  *
1035  * \param str: The string to search for words.
1036  * \param len: Size of the string to search.
1037  * \param delim: Character to use as a delimiter.
1038  * \param r_words: Info about the words found. Set to [index, len] pairs.
1039  * \param words_max: Max number of words to find
1040  * \return The number of words found in \a str
1041  */
1042 int BLI_string_find_split_words(
1043         const char *str, const size_t len,
1044         const char delim, int r_words[][2], int words_max)
1045 {
1046         int n = 0, i;
1047         bool charsearch = true;
1048
1049         /* Skip leading spaces */
1050         for (i = 0; (i < len) && (str[i] != '\0'); i++) {
1051                 if (str[i] != delim) {
1052                         break;
1053                 }
1054         }
1055
1056         for (; (i < len) && (str[i] != '\0') && (n < words_max); i++) {
1057                 if ((str[i] != delim) && (charsearch == true)) {
1058                         r_words[n][0] = i;
1059                         charsearch = false;
1060                 }
1061                 else {
1062                         if ((str[i] == delim) && (charsearch == false)) {
1063                                 r_words[n][1] = i - r_words[n][0];
1064                                 n++;
1065                                 charsearch = true;
1066                         }
1067                 }
1068         }
1069
1070         if (charsearch == false) {
1071                 r_words[n][1] = i - r_words[n][0];
1072                 n++;
1073         }
1074
1075         return n;
1076 }