diff options
Diffstat (limited to 'source/blender/blenlib/intern/string.c')
-rw-r--r-- | source/blender/blenlib/intern/string.c | 234 |
1 files changed, 211 insertions, 23 deletions
diff --git a/source/blender/blenlib/intern/string.c b/source/blender/blenlib/intern/string.c index eeafc1a9e8f..e93d2b7507a 100644 --- a/source/blender/blenlib/intern/string.c +++ b/source/blender/blenlib/intern/string.c @@ -126,6 +126,54 @@ char *BLI_strncpy(char *__restrict dst, const char *__restrict src, const size_t } /** + * Like BLI_strncpy but ensures dst is always padded by given char, on both sides (unless src is empty). + * + * \param dst Destination for copy + * \param src Source string to copy + * \param pad the char to use for padding + * \param maxncpy Maximum number of characters to copy (generally the size of dst) + * \retval Returns dst + */ +char *BLI_strncpy_ensure_pad(char *__restrict dst, const char *__restrict src, const char pad, size_t maxncpy) +{ + BLI_assert(maxncpy != 0); + +#ifdef DEBUG_STRSIZE + memset(dst, 0xff, sizeof(*dst) * maxncpy); +#endif + + if (src[0] == '\0') { + dst[0] = '\0'; + } + else { + /* Add heading/trailing wildcards if needed. */ + size_t idx = 0; + size_t srclen; + + if (src[idx] != pad) { + dst[idx++] = pad; + maxncpy--; + } + maxncpy--; /* trailing '\0' */ + + srclen = BLI_strnlen(src, maxncpy); + if ((src[srclen - 1] != pad) && (srclen == maxncpy)) { + srclen--; + } + + memcpy(&dst[idx], src, srclen); + idx += srclen; + + if (dst[idx - 1] != pad) { + dst[idx++] = pad; + } + dst[idx] = '\0'; + } + + return dst; +} + +/** * Like strncpy but ensures dst is always * '\0' terminated. * @@ -183,6 +231,30 @@ size_t BLI_vsnprintf(char *__restrict buffer, size_t maxncpy, const char *__rest } /** + * A version of #BLI_vsnprintf that returns ``strlen(buffer)`` + */ +size_t BLI_vsnprintf_rlen(char *__restrict buffer, size_t maxncpy, const char *__restrict format, va_list arg) +{ + size_t n; + + BLI_assert(buffer != NULL); + BLI_assert(maxncpy > 0); + BLI_assert(format != NULL); + + n = (size_t)vsnprintf(buffer, maxncpy, format, arg); + + if (n != -1 && n < maxncpy) { + /* pass */ + } + else { + n = maxncpy - 1; + } + buffer[n] = '\0'; + + return n; +} + +/** * Portable replacement for #snprintf */ size_t BLI_snprintf(char *__restrict dst, size_t maxncpy, const char *__restrict format, ...) @@ -202,6 +274,25 @@ size_t BLI_snprintf(char *__restrict dst, size_t maxncpy, const char *__restrict } /** + * A version of #BLI_snprintf that returns ``strlen(dst)`` + */ +size_t BLI_snprintf_rlen(char *__restrict dst, size_t maxncpy, const char *__restrict format, ...) +{ + size_t n; + va_list arg; + +#ifdef DEBUG_STRSIZE + memset(dst, 0xff, sizeof(*dst) * maxncpy); +#endif + + va_start(arg, format); + n = BLI_vsnprintf_rlen(dst, maxncpy, format, arg); + va_end(arg); + + return n; +} + +/** * Print formatted string into a newly #MEM_mallocN'd string * and return it. */ @@ -288,12 +379,13 @@ escape_finish: */ char *BLI_str_quoted_substrN(const char *__restrict str, const char *__restrict prefix) { - size_t prefixLen = strlen(prefix); const char *startMatch, *endMatch; - + /* get the starting point (i.e. where prefix starts, and add prefixLen+1 to it to get be after the first " */ - startMatch = strstr(str, prefix) + prefixLen + 1; + startMatch = strstr(str, prefix); if (startMatch) { + const size_t prefixLen = strlen(prefix); + startMatch += prefixLen + 1; /* get the end point (i.e. where the next occurance of " is after the starting point) */ endMatch = startMatch; @@ -327,7 +419,7 @@ char *BLI_str_quoted_substrN(const char *__restrict str, const char *__restrict * \param substr_new The text in the string to find and replace * \retval Returns the duplicated string */ -char *BLI_replacestrN(const char *__restrict str, const char *__restrict substr_old, const char *__restrict substr_new) +char *BLI_str_replaceN(const char *__restrict str, const char *__restrict substr_old, const char *__restrict substr_new) { DynStr *ds = NULL; size_t len_old = strlen(substr_old); @@ -386,6 +478,23 @@ char *BLI_replacestrN(const char *__restrict str, const char *__restrict substr_ } /** + * In-place replace every \a src to \a dst in \a str. + * + * \param str: The string to operate on. + * \param src: The character to replace. + * \param dst: The character to replace with. + */ +void BLI_str_replace_char(char *str, char src, char dst) +{ + while (*str) { + if (*str == src) { + *str = dst; + } + str++; + } +} + +/** * Compare two strings without regard to case. * * \retval True if the strings are equal, false otherwise. @@ -566,19 +675,47 @@ int BLI_natstrcmp(const char *s1, const char *s2) return strcmp(s1, s2); } -void BLI_timestr(double _time, char *str, size_t maxlen) +/** + * Like strcmp, but will ignore any heading/trailing pad char for comparison. + * So e.g. if pad is '*', '*world' and 'world*' will compare equal. + */ +int BLI_strcmp_ignore_pad(const char *str1, const char *str2, const char pad) { - /* format 00:00:00.00 (hr:min:sec) string has to be 12 long */ - int hr = ( (int) _time) / (60 * 60); - int min = (((int) _time) / 60 ) % 60; - int sec = ( (int) _time) % 60; - int hun = ( (int) (_time * 100.0)) % 100; + size_t str1_len, str2_len; + + while (*str1 == pad) { + str1++; + } + while (*str2 == pad) { + str2++; + } + + str1_len = strlen(str1); + str2_len = strlen(str2); + + while (str1_len && (str1[str1_len - 1] == pad)) { + str1_len--; + } + while (str2_len && (str2[str2_len - 1] == pad)) { + str2_len--; + } - if (hr) { - BLI_snprintf(str, maxlen, "%.2d:%.2d:%.2d.%.2d", hr, min, sec, hun); + if (str1_len == str2_len) { + return strncmp(str1, str2, str2_len); + } + else if (str1_len > str2_len) { + int ret = strncmp(str1, str2, str2_len); + if (ret == 0) { + ret = 1; + } + return ret; } else { - BLI_snprintf(str, maxlen, "%.2d:%.2d.%.2d", min, sec, hun); + int ret = strncmp(str1, str2, str1_len); + if (ret == 0) { + ret = -1; + } + return ret; } } @@ -594,7 +731,7 @@ size_t BLI_strnlen(const char *s, const size_t maxlen) return len; } -void BLI_ascii_strtolower(char *str, const size_t len) +void BLI_str_tolower_ascii(char *str, const size_t len) { size_t i; @@ -603,7 +740,7 @@ void BLI_ascii_strtolower(char *str, const size_t len) str[i] += 'a' - 'A'; } -void BLI_ascii_strtoupper(char *str, const size_t len) +void BLI_str_toupper_ascii(char *str, const size_t len) { size_t i; @@ -619,7 +756,7 @@ void BLI_ascii_strtoupper(char *str, const size_t len) * * \param str * \param pad - * \return The number of zeto's stripped. + * \return The number of zeros stripped. */ int BLI_str_rstrip_float_zero(char *str, const char pad) { @@ -681,6 +818,35 @@ int BLI_str_index_in_array(const char *__restrict str, const char **__restrict s return -1; } +bool BLI_strn_endswith(const char *__restrict str, const char *__restrict end, size_t slength) +{ + size_t elength = strlen(end); + + if (elength < slength) { + const char *iter = &str[slength - elength]; + while (*iter) { + if (*iter++ != *end++) { + return false; + } + } + return true; + } + return false; +} + +/** + * Find if a string ends with another string. + * + * \param str The string to search within. + * \param end The string we look for at the end. + * \return If str ends with end. + */ +bool BLI_str_endswith(const char *__restrict str, const char *end) +{ + const size_t slength = strlen(str); + return BLI_strn_endswith(str, end, slength); +} + /** * Find the first char matching one of the chars in \a delim, from left. * @@ -690,9 +856,9 @@ int BLI_str_index_in_array(const char *__restrict str, const char **__restrict s * \param suf Return value, set to next char after the first delimiter found (or NULL if none found). * \return The length of the prefix (i.e. *sep - str). */ -size_t BLI_str_partition(const char *str, const char delim[], char **sep, char **suf) +size_t BLI_str_partition(const char *str, const char delim[], const char **sep, const char **suf) { - return BLI_str_partition_ex(str, delim, sep, suf, false); + return BLI_str_partition_ex(str, NULL, delim, sep, suf, false); } /** @@ -704,30 +870,52 @@ size_t BLI_str_partition(const char *str, const char delim[], char **sep, char * * \param suf Return value, set to next char after the first delimiter found (or NULL if none found). * \return The length of the prefix (i.e. *sep - str). */ -size_t BLI_str_rpartition(const char *str, const char delim[], char **sep, char **suf) +size_t BLI_str_rpartition(const char *str, const char delim[], const char **sep, const char **suf) { - return BLI_str_partition_ex(str, delim, sep, suf, true); + return BLI_str_partition_ex(str, NULL, delim, sep, suf, true); } /** * Find the first char matching one of the chars in \a delim, either from left or right. * * \param str The string to search within. + * \param end If non-NULL, the right delimiter of the string. * \param delim The set of delimiters to search for, as unicode values. * \param sep Return value, set to the first delimiter found (or NULL if none found). * \param suf Return value, set to next char after the first delimiter found (or NULL if none found). * \param from_right If %true, search from the right of \a str, else, search from its left. * \return The length of the prefix (i.e. *sep - str). */ -size_t BLI_str_partition_ex(const char *str, const char delim[], char **sep, char **suf, const bool from_right) +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) { const char *d; char *(*func)(const char *str, int c) = from_right ? strrchr : strchr; + BLI_assert(end == NULL || end > str); + *sep = *suf = NULL; for (d = delim; *d != '\0'; ++d) { - char *tmp = func(str, *d); + const char *tmp; + + if (end) { + if (from_right) { + for (tmp = end - 1; (tmp >= str) && (*tmp != *d); tmp--); + if (tmp < str) { + tmp = NULL; + } + } + else { + tmp = func(str, *d); + if (tmp >= end) { + tmp = NULL; + } + } + } + else { + tmp = func(str, *d); + } if (tmp && (from_right ? (*sep < tmp) : (!*sep || *sep > tmp))) { *sep = tmp; @@ -739,7 +927,7 @@ size_t BLI_str_partition_ex(const char *str, const char delim[], char **sep, cha return (size_t)(*sep - str); } - return strlen(str); + return end ? (size_t)(end - str) : strlen(str); } /** |