From 9753e70e3721e60d50eedc050993d837ebb56c9a Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 4 Jul 2023 12:02:25 +1000 Subject: [PATCH] Cleanup: move BLI_str_replace into BLI_string_utils.h String search & replace is a higher level function (unlike BLI_string.h) which handlers lower level replacements for printing and string copying. Also use BLI_string_* prefix (matching other utilities). This makes it possible to use BLI_string in Blender's internal utilities without depending on DynStr, MemArena... etc. --- .../blenkernel/intern/gpencil_geom_legacy.cc | 3 +- source/blender/blenkernel/intern/image.cc | 5 +- source/blender/blenkernel/intern/layer.cc | 4 +- .../blenkernel/intern/simulation_state.cc | 3 +- source/blender/blenkernel/intern/workspace.cc | 2 +- source/blender/blenlib/BLI_string.h | 47 ------ source/blender/blenlib/BLI_string_utils.h | 60 ++++++++ source/blender/blenlib/intern/path_util.c | 23 +-- source/blender/blenlib/intern/string.c | 137 ----------------- source/blender/blenlib/intern/string_utils.c | 138 ++++++++++++++++++ .../blender/blenlib/tests/BLI_memiter_test.cc | 3 +- .../blenlib/tests/BLI_path_util_test.cc | 27 ++-- .../blender/blenlib/tests/BLI_string_test.cc | 2 +- .../blenloader/intern/versioning_270.cc | 4 +- .../blenloader/intern/versioning_300.cc | 2 +- .../blenloader/intern/versioning_userdef.c | 5 +- .../blender/editors/armature/armature_add.c | 2 +- .../editors/object/object_bake_simulation.cc | 3 +- .../blender/editors/render/render_shading.cc | 3 +- source/blender/gpu/intern/gpu_platform.cc | 9 +- source/blender/imbuf/intern/thumbs.cc | 2 +- .../io/usd/intern/usd_writer_material.cc | 5 +- .../function/nodes/node_fn_replace_string.cc | 3 +- 23 files changed, 259 insertions(+), 233 deletions(-) diff --git a/source/blender/blenkernel/intern/gpencil_geom_legacy.cc b/source/blender/blenkernel/intern/gpencil_geom_legacy.cc index 5ee2a236bd3..6083ede2a71 100644 --- a/source/blender/blenkernel/intern/gpencil_geom_legacy.cc +++ b/source/blender/blenkernel/intern/gpencil_geom_legacy.cc @@ -25,6 +25,7 @@ #include "BLI_math_vector_types.hh" #include "BLI_polyfill_2d.h" #include "BLI_span.hh" +#include "BLI_string_utils.h" #include "DNA_gpencil_legacy_types.h" #include "DNA_gpencil_modifier_types.h" @@ -2686,7 +2687,7 @@ static void make_element_name(const char *obname, const char *name, const int ma SNPRINTF(str, "%s_%s", obname, name); /* Replace any point by underscore. */ - BLI_str_replace_char(str, '.', '_'); + BLI_string_replace_char(str, '.', '_'); BLI_strncpy_utf8(r_name, str, maxlen); } diff --git a/source/blender/blenkernel/intern/image.cc b/source/blender/blenkernel/intern/image.cc index 7a3287fba13..21cd3cb27e0 100644 --- a/source/blender/blenkernel/intern/image.cc +++ b/source/blender/blenkernel/intern/image.cc @@ -22,6 +22,7 @@ #include #include "BLI_array.hh" +#include "BLI_string_utils.h" #include "CLG_log.h" @@ -3586,11 +3587,11 @@ char *BKE_image_get_tile_strformat(const char *filepath, eUDIM_TILE_FORMAT *r_ti if (strstr(filepath, "") != nullptr) { *r_tile_format = UDIM_TILE_FORMAT_UDIM; - return BLI_str_replaceN(filepath, "", "%d"); + return BLI_string_replaceN(filepath, "", "%d"); } if (strstr(filepath, "") != nullptr) { *r_tile_format = UDIM_TILE_FORMAT_UVTILE; - return BLI_str_replaceN(filepath, "", "u%d_v%d"); + return BLI_string_replaceN(filepath, "", "u%d_v%d"); } *r_tile_format = UDIM_TILE_FORMAT_NONE; diff --git a/source/blender/blenkernel/intern/layer.cc b/source/blender/blenkernel/intern/layer.cc index 5a1d246651b..63894db46a5 100644 --- a/source/blender/blenkernel/intern/layer.cc +++ b/source/blender/blenkernel/intern/layer.cc @@ -2503,7 +2503,7 @@ static void viewlayer_aov_make_name_unique(ViewLayer *view_layer) /* Don't allow dots, it's incompatible with OpenEXR convention to store channels * as "layer.pass.channel". */ - BLI_str_replace_char(aov->name, '.', '_'); + BLI_string_replace_char(aov->name, '.', '_'); BLI_uniquename( &view_layer->aovs, aov, DATA_("AOV"), '_', offsetof(ViewLayerAOV, name), sizeof(aov->name)); } @@ -2620,7 +2620,7 @@ static void viewlayer_lightgroup_make_name_unique(ViewLayer *view_layer, { /* Don't allow dots, it's incompatible with OpenEXR convention to store channels * as "layer.pass.channel". */ - BLI_str_replace_char(lightgroup->name, '.', '_'); + BLI_string_replace_char(lightgroup->name, '.', '_'); BLI_uniquename(&view_layer->lightgroups, lightgroup, DATA_("Lightgroup"), diff --git a/source/blender/blenkernel/intern/simulation_state.cc b/source/blender/blenkernel/intern/simulation_state.cc index 5a9e466b6c9..0b687976815 100644 --- a/source/blender/blenkernel/intern/simulation_state.cc +++ b/source/blender/blenkernel/intern/simulation_state.cc @@ -15,6 +15,7 @@ #include "BLI_fileops.hh" #include "BLI_hash_md5.h" #include "BLI_path_util.h" +#include "BLI_string_utils.h" namespace blender::bke::sim { @@ -78,7 +79,7 @@ void ModifierSimulationCache::try_discover_bake(const StringRefNull absolute_bak } char modified_file_name[FILE_MAX]; STRNCPY(modified_file_name, dir_entry.relname); - BLI_str_replace_char(modified_file_name, '_', '.'); + BLI_string_replace_char(modified_file_name, '_', '.'); const SubFrame frame = std::stof(modified_file_name); diff --git a/source/blender/blenkernel/intern/workspace.cc b/source/blender/blenkernel/intern/workspace.cc index dbee4bb902a..84ba8390fbd 100644 --- a/source/blender/blenkernel/intern/workspace.cc +++ b/source/blender/blenkernel/intern/workspace.cc @@ -541,7 +541,7 @@ void BKE_workspace_tool_id_replace_table(WorkSpace *workspace, } idname_suffix += idname_prefix_len; } - BLI_str_replace_table_exact( + BLI_string_replace_table_exact( idname_suffix, idname_suffix_len, replace_table, replace_table_num); } } diff --git a/source/blender/blenlib/BLI_string.h b/source/blender/blenlib/BLI_string.h index ea73b7077f6..0380bfb3454 100644 --- a/source/blender/blenlib/BLI_string.h +++ b/source/blender/blenlib/BLI_string.h @@ -160,53 +160,6 @@ bool BLI_str_quoted_substr(const char *__restrict str, const char *__restrict prefix, char *result, size_t result_maxncpy); -/** - * string with all instances of substr_old replaced with substr_new, - * Returns a copy of the c-string \a str into a newly #MEM_mallocN'd - * and returns it. - * - * \note A rather wasteful string-replacement utility, though this shall do for now. - * Feel free to replace this with an even safe + nicer alternative - * - * \param str: The string to replace occurrences of substr_old in - * \param substr_old: The text in the string to find and replace - * \param substr_new: The text in the string to find and replace - * \retval Returns the duplicated string - */ -char *BLI_str_replaceN(const char *__restrict str, - const char *__restrict substr_old, - const char *__restrict substr_new) ATTR_WARN_UNUSED_RESULT - ATTR_NONNULL(1, 2, 3) ATTR_MALLOC; - -/** - * 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) ATTR_NONNULL(1); - -/** - * Simple exact-match string replacement. - * - * \param replace_table: Array of source, destination pairs. - * - * \note Larger tables should use a hash table. - */ -bool BLI_str_replace_table_exact(char *string, - size_t string_len, - const char *replace_table[][2], - int replace_table_len); - -/** - * Write `dst` into the range between `src_beg` & `src_end`, - * resize within `string_maxncpy` limits, ensure null terminated. - * - * \return the length of `string`. - */ -size_t BLI_str_replace_range( - char *string, size_t string_maxncpy, int src_beg, int src_end, const char *dst); /** * Portable replacement for #snprintf diff --git a/source/blender/blenlib/BLI_string_utils.h b/source/blender/blenlib/BLI_string_utils.h index 686338941b9..7d592f4db0c 100644 --- a/source/blender/blenlib/BLI_string_utils.h +++ b/source/blender/blenlib/BLI_string_utils.h @@ -21,6 +21,64 @@ struct ListBase; typedef bool (*UniquenameCheckCallback)(void *arg, const char *name); +/* ------------------------------------------------------------------------- */ +/** \name String Replace + * \{ */ + +/** + * string with all instances of substr_old replaced with substr_new, + * Returns a copy of the c-string \a str into a newly #MEM_mallocN'd + * and returns it. + * + * \note A rather wasteful string-replacement utility, though this shall do for now. + * Feel free to replace this with an even safe + nicer alternative + * + * \param str: The string to replace occurrences of substr_old in + * \param substr_old: The text in the string to find and replace + * \param substr_new: The text in the string to find and replace + * \retval Returns the duplicated string + */ +char *BLI_string_replaceN(const char *__restrict str, + const char *__restrict substr_old, + const char *__restrict substr_new) ATTR_WARN_UNUSED_RESULT + ATTR_NONNULL(1, 2, 3) ATTR_MALLOC; + +/** + * 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_string_replace_char(char *str, char src, char dst) ATTR_NONNULL(1); + +/** + * Simple exact-match string replacement. + * + * \param replace_table: Array of source, destination pairs. + * + * \note Larger tables should use a hash table. + */ +bool BLI_string_replace_table_exact(char *string, + size_t string_len, + const char *replace_table[][2], + int replace_table_len); + +/** + * Write `dst` into the range between `src_beg` & `src_end`, + * resize within `string_maxncpy` limits, ensure null terminated. + * + * \return the length of `string`. + */ +size_t BLI_string_replace_range( + char *string, size_t string_maxncpy, int src_beg, int src_end, const char *dst); + +/** \} */ + +/* ------------------------------------------------------------------------- */ +/** \name String Split + * \{ */ + /** * Looks for a numeric suffix preceded by `delim` character on the end of * name, puts preceding part into *left and value of suffix into *nr. @@ -51,6 +109,8 @@ void BLI_string_split_suffix(const char *string, size_t string_maxlen, char *r_b void BLI_string_split_prefix(const char *string, size_t string_maxlen, char *r_pre, char *r_body) ATTR_NONNULL(1, 3, 4); +/** \} */ + /** * A version of #BLI_string_join_array_by_sep_charN that takes a table array. * The new location of each string is written into this array. diff --git a/source/blender/blenlib/intern/path_util.c b/source/blender/blenlib/intern/path_util.c index fa61657f974..c3096cb7468 100644 --- a/source/blender/blenlib/intern/path_util.c +++ b/source/blender/blenlib/intern/path_util.c @@ -18,6 +18,7 @@ #include "BLI_path_util.h" #include "BLI_string.h" #include "BLI_string_utf8.h" +#include "BLI_string_utils.h" #include "BLI_utildefines.h" #ifdef WIN32 @@ -723,8 +724,8 @@ void BLI_path_rel(char path[FILE_MAX], const char *basepath) STRNCPY(temp, basepath); #endif - BLI_str_replace_char(temp + BLI_path_unc_prefix_len(temp), '\\', '/'); - BLI_str_replace_char(path + BLI_path_unc_prefix_len(path), '\\', '/'); + BLI_string_replace_char(temp + BLI_path_unc_prefix_len(temp), '\\', '/'); + BLI_string_replace_char(path + BLI_path_unc_prefix_len(path), '\\', '/'); /* Remove `/./` which confuse the following slash counting. */ BLI_path_normalize(path); @@ -790,7 +791,7 @@ void BLI_path_rel(char path[FILE_MAX], const char *basepath) r += BLI_strncpy_rlen(r, q + 1, sizeof(res) - (r - res)); #ifdef WIN32 - BLI_str_replace_char(res + 2, '/', '\\'); + BLI_string_replace_char(res + 2, '/', '\\'); #endif BLI_strncpy(path, res, FILE_MAX); } @@ -964,7 +965,7 @@ bool BLI_path_frame(char *path, size_t path_maxncpy, int frame, int digits) char frame_str[FILENAME_FRAME_CHARS_MAX + 1]; /* One for null. */ const int ch_span = MIN2(ch_end - ch_sta, FILENAME_FRAME_CHARS_MAX); SNPRINTF(frame_str, "%.*d", ch_span, frame); - BLI_str_replace_range(path, path_maxncpy, ch_sta, ch_end, frame_str); + BLI_string_replace_range(path, path_maxncpy, ch_sta, ch_end, frame_str); return true; } return false; @@ -984,7 +985,7 @@ bool BLI_path_frame_range(char *path, size_t path_maxncpy, int sta, int end, int char frame_str[(FILENAME_FRAME_CHARS_MAX * 2) + 1 + 1]; /* One for null, one for the '-' */ const int ch_span = MIN2(ch_end - ch_sta, FILENAME_FRAME_CHARS_MAX); SNPRINTF(frame_str, "%.*d-%.*d", ch_span, sta, ch_span, end); - BLI_str_replace_range(path, path_maxncpy, ch_sta, ch_end, frame_str); + BLI_string_replace_range(path, path_maxncpy, ch_sta, ch_end, frame_str); return true; } return false; @@ -1066,7 +1067,7 @@ void BLI_path_to_display_name(char *display_name, int display_name_maxncpy, cons BLI_strncpy(display_name, name + strip_offset, display_name_maxncpy); /* Replace underscores with spaces. */ - BLI_str_replace_char(display_name, '_', ' '); + BLI_string_replace_char(display_name, '_', ' '); BLI_path_extension_strip(display_name); @@ -1150,7 +1151,7 @@ bool BLI_path_abs(char path[FILE_MAX], const char *basepath) * NOTE(@elubie): For UNC paths the first characters containing the UNC prefix * shouldn't be switched as we need to distinguish them from * paths relative to the `.blend` file. */ - BLI_str_replace_char(tmp + BLI_path_unc_prefix_len(tmp), '\\', '/'); + BLI_string_replace_char(tmp + BLI_path_unc_prefix_len(tmp), '\\', '/'); /* Paths starting with `//` will get the blend file as their base, * this isn't standard in any OS but is used in blender all over the place. */ @@ -1161,7 +1162,7 @@ bool BLI_path_abs(char path[FILE_MAX], const char *basepath) /* File component is ignored, so don't bother with the trailing slash. */ BLI_path_normalize(base); lslash = BLI_path_slash_rfind(base); - BLI_str_replace_char(base + BLI_path_unc_prefix_len(base), '\\', '/'); + BLI_string_replace_char(base + BLI_path_unc_prefix_len(base), '\\', '/'); if (lslash) { /* Length up to and including last `/`. */ @@ -1187,7 +1188,7 @@ bool BLI_path_abs(char path[FILE_MAX], const char *basepath) /* NOTE(@jesterking): Skip first two chars, which in case of absolute path will * be `drive:/blabla` and in case of `relpath` `//blabla/`. * So `relpath` `//` will be retained, rest will be nice and shiny WIN32 backward slashes. */ - BLI_str_replace_char(path + 2, '/', '\\'); + BLI_string_replace_char(path + 2, '/', '\\'); #endif /* Ensure this is after correcting for path switch. */ @@ -1968,10 +1969,10 @@ void BLI_path_slash_native(char *path) { #ifdef WIN32 if (path && BLI_strnlen(path, 3) > 2) { - BLI_str_replace_char(path + 2, ALTSEP, SEP); + BLI_string_replace_char(path + 2, ALTSEP, SEP); } #else - BLI_str_replace_char(path + BLI_path_unc_prefix_len(path), ALTSEP, SEP); + BLI_string_replace_char(path + BLI_path_unc_prefix_len(path), ALTSEP, SEP); #endif } diff --git a/source/blender/blenlib/intern/string.c b/source/blender/blenlib/intern/string.c index 156d49ad32a..7cc8d5600ad 100644 --- a/source/blender/blenlib/intern/string.c +++ b/source/blender/blenlib/intern/string.c @@ -16,7 +16,6 @@ #include "MEM_guardedalloc.h" -#include "BLI_dynstr.h" #include "BLI_string.h" #include "BLI_utildefines.h" @@ -528,142 +527,6 @@ bool BLI_str_quoted_substr(const char *__restrict str, /** \} */ -/* -------------------------------------------------------------------- */ -/** \name String Replace - * \{ */ - -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); - const char *match; - - BLI_assert(substr_old[0] != '\0'); - - /* While we can still find a match for the old sub-string that we're searching for, - * keep dicing and replacing. */ - while ((match = strstr(str, substr_old))) { - /* the assembly buffer only gets created when we actually need to rebuild the string */ - if (ds == NULL) { - ds = BLI_dynstr_new(); - } - - /* If the match position does not match the current position in the string, - * copy the text up to this position and advance the current position in the string. */ - if (str != match) { - /* Add the segment of the string from `str` to match to the buffer, - * then restore the value at match. */ - BLI_dynstr_nappend(ds, str, (match - str)); - - /* now our current position should be set on the start of the match */ - str = match; - } - - /* Add the replacement text to the accumulation buffer. */ - BLI_dynstr_append(ds, substr_new); - - /* Advance the current position of the string up to the end of the replaced segment. */ - str += len_old; - } - - /* Finish off and return a new string that has had all occurrences of. */ - if (ds) { - char *str_new; - - /* Add what's left of the string to the assembly buffer - * - we've been adjusting `str` to point at the end of the replaced segments. */ - BLI_dynstr_append(ds, str); - - /* Convert to new c-string (MEM_malloc'd), and free the buffer. */ - str_new = BLI_dynstr_get_cstring(ds); - BLI_dynstr_free(ds); - - return str_new; - } - /* Just create a new copy of the entire string - we avoid going through the assembly buffer - * for what should be a bit more efficiency. */ - return BLI_strdup(str); -} - -void BLI_str_replace_char(char *str, char src, char dst) -{ - while (*str) { - if (*str == src) { - *str = dst; - } - str++; - } -} - -bool BLI_str_replace_table_exact(char *string, - const size_t string_maxncpy, - const char *replace_table[][2], - int replace_table_len) -{ - BLI_string_debug_size_after_nil(string, string_maxncpy); - - for (int i = 0; i < replace_table_len; i++) { - if (STREQ(string, replace_table[i][0])) { - BLI_strncpy(string, replace_table[i][1], string_maxncpy); - return true; - } - } - return false; -} - -size_t BLI_str_replace_range( - char *string, size_t string_maxncpy, int src_beg, int src_end, const char *dst) -{ - int string_len = strlen(string); - BLI_assert(src_beg <= src_end); - BLI_assert(src_end <= string_len); - const int src_len = src_end - src_beg; - int dst_len = strlen(dst); - - if (src_len < dst_len) { - /* Grow, first handle special cases. */ - - /* Special case, the src_end is entirely clipped. */ - if (UNLIKELY(string_maxncpy <= src_beg + dst_len)) { - /* There is only room for the destination. */ - dst_len = ((int)string_maxncpy - src_beg) - 1; - string_len = src_end; - string[string_len] = '\0'; - } - - const int ofs = dst_len - src_len; - /* Clip the string when inserting the destination string exceeds `string_maxncpy`. */ - if (string_len + ofs >= string_maxncpy) { - string_len = ((int)string_maxncpy - ofs) - 1; - string[string_len] = '\0'; - BLI_assert(src_end <= string_len); - } - - /* Grow. */ - memmove(string + (src_end + ofs), string + src_end, (size_t)(string_len - src_end) + 1); - string_len += ofs; - } - else if (src_len > dst_len) { - /* Shrink. */ - const int ofs = src_len - dst_len; - memmove(string + (src_end - ofs), string + src_end, (size_t)(string_len - src_end) + 1); - string_len -= ofs; - } - else { /* Simple case, no resizing. */ - BLI_assert(src_len == dst_len); - } - - if (dst_len > 0) { - memcpy(string + src_beg, dst, (size_t)dst_len); - } - BLI_assert(string[string_len] == '\0'); - return (size_t)string_len; -} - -/** \} */ - /* -------------------------------------------------------------------- */ /** \name String Comparison/Matching * \{ */ diff --git a/source/blender/blenlib/intern/string_utils.c b/source/blender/blenlib/intern/string_utils.c index 4c5ae431aee..60142945d6a 100644 --- a/source/blender/blenlib/intern/string_utils.c +++ b/source/blender/blenlib/intern/string_utils.c @@ -17,12 +17,150 @@ #include "BLI_string_utils.h" #include "BLI_utildefines.h" +#include "BLI_dynstr.h" + #include "DNA_listBase.h" #ifdef __GNUC__ # pragma GCC diagnostic error "-Wsign-conversion" #endif +/* -------------------------------------------------------------------- */ +/** \name String Replace + * \{ */ + +char *BLI_string_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); + const char *match; + + BLI_assert(substr_old[0] != '\0'); + + /* While we can still find a match for the old sub-string that we're searching for, + * keep dicing and replacing. */ + while ((match = strstr(str, substr_old))) { + /* the assembly buffer only gets created when we actually need to rebuild the string */ + if (ds == NULL) { + ds = BLI_dynstr_new(); + } + + /* If the match position does not match the current position in the string, + * copy the text up to this position and advance the current position in the string. */ + if (str != match) { + /* Add the segment of the string from `str` to match to the buffer, + * then restore the value at match. */ + BLI_dynstr_nappend(ds, str, (match - str)); + + /* now our current position should be set on the start of the match */ + str = match; + } + + /* Add the replacement text to the accumulation buffer. */ + BLI_dynstr_append(ds, substr_new); + + /* Advance the current position of the string up to the end of the replaced segment. */ + str += len_old; + } + + /* Finish off and return a new string that has had all occurrences of. */ + if (ds) { + char *str_new; + + /* Add what's left of the string to the assembly buffer + * - we've been adjusting `str` to point at the end of the replaced segments. */ + BLI_dynstr_append(ds, str); + + /* Convert to new c-string (MEM_malloc'd), and free the buffer. */ + str_new = BLI_dynstr_get_cstring(ds); + BLI_dynstr_free(ds); + + return str_new; + } + /* Just create a new copy of the entire string - we avoid going through the assembly buffer + * for what should be a bit more efficiency. */ + return BLI_strdup(str); +} + +void BLI_string_replace_char(char *str, char src, char dst) +{ + while (*str) { + if (*str == src) { + *str = dst; + } + str++; + } +} + +bool BLI_string_replace_table_exact(char *string, + const size_t string_maxncpy, + const char *replace_table[][2], + int replace_table_len) +{ + BLI_string_debug_size_after_nil(string, string_maxncpy); + + for (int i = 0; i < replace_table_len; i++) { + if (STREQ(string, replace_table[i][0])) { + BLI_strncpy(string, replace_table[i][1], string_maxncpy); + return true; + } + } + return false; +} + +size_t BLI_string_replace_range( + char *string, size_t string_maxncpy, int src_beg, int src_end, const char *dst) +{ + int string_len = strlen(string); + BLI_assert(src_beg <= src_end); + BLI_assert(src_end <= string_len); + const int src_len = src_end - src_beg; + int dst_len = strlen(dst); + + if (src_len < dst_len) { + /* Grow, first handle special cases. */ + + /* Special case, the src_end is entirely clipped. */ + if (UNLIKELY(string_maxncpy <= src_beg + dst_len)) { + /* There is only room for the destination. */ + dst_len = ((int)string_maxncpy - src_beg) - 1; + string_len = src_end; + string[string_len] = '\0'; + } + + const int ofs = dst_len - src_len; + /* Clip the string when inserting the destination string exceeds `string_maxncpy`. */ + if (string_len + ofs >= string_maxncpy) { + string_len = ((int)string_maxncpy - ofs) - 1; + string[string_len] = '\0'; + BLI_assert(src_end <= string_len); + } + + /* Grow. */ + memmove(string + (src_end + ofs), string + src_end, (size_t)(string_len - src_end) + 1); + string_len += ofs; + } + else if (src_len > dst_len) { + /* Shrink. */ + const int ofs = src_len - dst_len; + memmove(string + (src_end - ofs), string + src_end, (size_t)(string_len - src_end) + 1); + string_len -= ofs; + } + else { /* Simple case, no resizing. */ + BLI_assert(src_len == dst_len); + } + + if (dst_len > 0) { + memcpy(string + src_beg, dst, (size_t)dst_len); + } + BLI_assert(string[string_len] == '\0'); + return (size_t)string_len; +} + +/** \} */ + size_t BLI_string_split_name_number(const char *name, const char delim, char *r_name_left, diff --git a/source/blender/blenlib/tests/BLI_memiter_test.cc b/source/blender/blenlib/tests/BLI_memiter_test.cc index 88127ef1137..5ce992789df 100644 --- a/source/blender/blenlib/tests/BLI_memiter_test.cc +++ b/source/blender/blenlib/tests/BLI_memiter_test.cc @@ -8,6 +8,7 @@ #include "BLI_array_utils.h" #include "BLI_memiter.h" +#include "BLI_string_utils.h" #include "BLI_ressource_strings.h" #include "BLI_string.h" @@ -100,7 +101,7 @@ static void memiter_words10k_test(const char split_char, const int chunk_size) { const int words_len = sizeof(words10k) - 1; char *words = BLI_strdupn(words10k, words_len); - BLI_str_replace_char(words, split_char, '\0'); + BLI_string_replace_char(words, split_char, '\0'); BLI_memiter *mi = BLI_memiter_create(chunk_size); diff --git a/source/blender/blenlib/tests/BLI_path_util_test.cc b/source/blender/blenlib/tests/BLI_path_util_test.cc index 52db8c49503..f918f5d1472 100644 --- a/source/blender/blenlib/tests/BLI_path_util_test.cc +++ b/source/blender/blenlib/tests/BLI_path_util_test.cc @@ -9,6 +9,7 @@ #include "BLI_fileops.h" #include "BLI_path_util.h" #include "BLI_string.h" +#include "BLI_string_utils.h" /* -------------------------------------------------------------------- */ /** \name Local Utilities @@ -25,7 +26,7 @@ static void str_replace_char_with_relative_exception(char *str, char src, char d } } } - BLI_str_replace_char(str, src, dst); + BLI_string_replace_char(str, src, dst); } static char *str_replace_char_strdup(const char *str, char src, char dst) @@ -34,7 +35,7 @@ static char *str_replace_char_strdup(const char *str, char src, char dst) return nullptr; } char *str_dupe = strdup(str); - BLI_str_replace_char(str_dupe, src, dst); + BLI_string_replace_char(str_dupe, src, dst); return str_dupe; } @@ -52,7 +53,7 @@ static char *str_replace_char_strdup(const char *str, char src, char dst) } \ const int path_len_test = BLI_path_normalize(path); \ if (SEP == '\\') { \ - BLI_str_replace_char(path, '\\', '/'); \ + BLI_string_replace_char(path, '\\', '/'); \ } \ EXPECT_STREQ(path, output_expect); \ EXPECT_EQ(path_len_test, strlen(path)); \ @@ -190,11 +191,11 @@ TEST(path_util, CompareNormalized) { \ char path[FILE_MAX] = input; \ if (SEP == '\\') { \ - BLI_str_replace_char(path, '/', '\\'); \ + BLI_string_replace_char(path, '/', '\\'); \ } \ BLI_path_parent_dir(path); \ if (SEP == '\\') { \ - BLI_str_replace_char(path, '\\', '/'); \ + BLI_string_replace_char(path, '\\', '/'); \ } \ EXPECT_STREQ(path, output_expect); \ } \ @@ -251,7 +252,7 @@ TEST(path_util, ParentDir_Complex) char path[] = str_input; \ /* Test input assumes forward slash, support back-slash on WIN32. */ \ if (SEP == '\\') { \ - BLI_str_replace_char(path, '/', '\\'); \ + BLI_string_replace_char(path, '/', '\\'); \ } \ const char *expect = str_expect; \ int index_output, len_output; \ @@ -469,7 +470,7 @@ TEST(path_util, NameAtIndex_NoneComplexNeg) char *input_back_slash[ARRAY_SIZE(input_forward_slash)] = {nullptr}; \ for (int i = 0; i < ARRAY_SIZE(input_forward_slash); i++) { \ input_back_slash[i] = strdup(input_forward_slash[i]); \ - BLI_str_replace_char(input_back_slash[i], '/', '\\'); \ + BLI_string_replace_char(input_back_slash[i], '/', '\\'); \ } \ /* Check we don't write past the last byte. */ \ result[out_size] = '\0'; \ @@ -477,7 +478,7 @@ TEST(path_util, NameAtIndex_NoneComplexNeg) out_size, \ const_cast(input_back_slash), \ ARRAY_SIZE(input_back_slash)); \ - BLI_str_replace_char(result, '\\', '/'); \ + BLI_string_replace_char(result, '\\', '/'); \ EXPECT_STREQ(result, expect); \ EXPECT_EQ(result[out_size], '\0'); \ for (int i = 0; i < ARRAY_SIZE(input_forward_slash); i++) { \ @@ -599,12 +600,12 @@ TEST(path_util, JoinRelativePrefix) char filename_native[] = filename; \ /* Check we don't write past the last byte. */ \ if (SEP == '\\') { \ - BLI_str_replace_char(filename_native, '/', '\\'); \ - BLI_str_replace_char(result, '/', '\\'); \ + BLI_string_replace_char(filename_native, '/', '\\'); \ + BLI_string_replace_char(result, '/', '\\'); \ } \ BLI_path_append(result, size, filename_native); \ if (SEP == '\\') { \ - BLI_str_replace_char(result, '\\', '/'); \ + BLI_string_replace_char(result, '\\', '/'); \ } \ EXPECT_STREQ(result, expect); \ } \ @@ -1215,12 +1216,12 @@ TEST(path_util, Suffix) const char *ref_path_test = ref_path; \ STRNCPY(path, abs_path); \ if (SEP == '\\') { \ - BLI_str_replace_char(path, '/', '\\'); \ + BLI_string_replace_char(path, '/', '\\'); \ ref_path_test = str_replace_char_strdup(ref_path_test, '/', '\\'); \ } \ BLI_path_rel(path, ref_path_test); \ if (SEP == '\\') { \ - BLI_str_replace_char(path, '\\', '/'); \ + BLI_string_replace_char(path, '\\', '/'); \ free((void *)ref_path_test); \ } \ EXPECT_STREQ(path, rel_path_expect); \ diff --git a/source/blender/blenlib/tests/BLI_string_test.cc b/source/blender/blenlib/tests/BLI_string_test.cc index e4188a1a801..6de71b134cc 100644 --- a/source/blender/blenlib/tests/BLI_string_test.cc +++ b/source/blender/blenlib/tests/BLI_string_test.cc @@ -162,7 +162,7 @@ TEST(string, StrReplaceRange) #define STR_REPLACE_RANGE(src, size, beg, end, dst, result_expect) \ { \ char string[size] = src; \ - BLI_str_replace_range(string, sizeof(string), beg, end, dst); \ + BLI_string_replace_range(string, sizeof(string), beg, end, dst); \ EXPECT_STREQ(string, result_expect); \ } diff --git a/source/blender/blenloader/intern/versioning_270.cc b/source/blender/blenloader/intern/versioning_270.cc index 5e8c8f1fe96..97358ada35f 100644 --- a/source/blender/blenloader/intern/versioning_270.cc +++ b/source/blender/blenloader/intern/versioning_270.cc @@ -364,10 +364,10 @@ static char *replace_bbone_easing_rnapath(char *old_path) * which happen be named after the bbone property id's */ if (strstr(old_path, "bbone_in")) { - new_path = BLI_str_replaceN(old_path, "bbone_in", "bbone_easein"); + new_path = BLI_string_replaceN(old_path, "bbone_in", "bbone_easein"); } else if (strstr(old_path, "bbone_out")) { - new_path = BLI_str_replaceN(old_path, "bbone_out", "bbone_easeout"); + new_path = BLI_string_replaceN(old_path, "bbone_out", "bbone_easeout"); } if (new_path) { diff --git a/source/blender/blenloader/intern/versioning_300.cc b/source/blender/blenloader/intern/versioning_300.cc index af51a0e5c00..8688cc6a36c 100644 --- a/source/blender/blenloader/intern/versioning_300.cc +++ b/source/blender/blenloader/intern/versioning_300.cc @@ -462,7 +462,7 @@ static void do_versions_sequencer_speed_effect_recursive(Scene *scene, const Lis } } if (substr) { - char *new_path = BLI_str_replaceN(fcu->rna_path, "speed_factor", substr); + char *new_path = BLI_string_replaceN(fcu->rna_path, "speed_factor", substr); MEM_freeN(fcu->rna_path); fcu->rna_path = new_path; } diff --git a/source/blender/blenloader/intern/versioning_userdef.c b/source/blender/blenloader/intern/versioning_userdef.c index c68aefa2a13..e759eb1b926 100644 --- a/source/blender/blenloader/intern/versioning_userdef.c +++ b/source/blender/blenloader/intern/versioning_userdef.c @@ -14,6 +14,7 @@ #include "BLI_math.h" #include "BLI_string.h" #include "BLI_string_utf8.h" +#include "BLI_string_utils.h" #include "BLI_utildefines.h" #include "DNA_anim_types.h" @@ -708,10 +709,10 @@ void blo_do_versions_userdef(UserDef *userdef) }; const int replace_table_len = ARRAY_SIZE(replace_table); - BLI_str_replace_table_exact( + BLI_string_replace_table_exact( userdef->keyconfigstr, sizeof(userdef->keyconfigstr), replace_table, replace_table_len); LISTBASE_FOREACH (wmKeyConfigPref *, kpt, &userdef->user_keyconfig_prefs) { - BLI_str_replace_table_exact( + BLI_string_replace_table_exact( kpt->idname, sizeof(kpt->idname), replace_table, replace_table_len); } } diff --git a/source/blender/editors/armature/armature_add.c b/source/blender/editors/armature/armature_add.c index fc5d99ed085..6f8a3d8fca9 100644 --- a/source/blender/editors/armature/armature_add.c +++ b/source/blender/editors/armature/armature_add.c @@ -504,7 +504,7 @@ static void updateDuplicateActionConstraintSettings( char *old_path = new_curve->rna_path; - new_curve->rna_path = BLI_str_replaceN(old_path, orig_bone->name, dup_bone->name); + new_curve->rna_path = BLI_string_replaceN(old_path, orig_bone->name, dup_bone->name); MEM_freeN(old_path); /* Flip the animation */ diff --git a/source/blender/editors/object/object_bake_simulation.cc b/source/blender/editors/object/object_bake_simulation.cc index 5ff75ee08f3..9a25c0bbe86 100644 --- a/source/blender/editors/object/object_bake_simulation.cc +++ b/source/blender/editors/object/object_bake_simulation.cc @@ -11,6 +11,7 @@ #include "BLI_fileops.hh" #include "BLI_path_util.h" #include "BLI_serialize.hh" +#include "BLI_string_utils.h" #include "BLI_vector.hh" #include "PIL_time.h" @@ -286,7 +287,7 @@ static void bake_simulation_job_startjob(void *customdata, char frame_file_c_str[64]; SNPRINTF(frame_file_c_str, "%011.5f", double(frame)); - BLI_str_replace_char(frame_file_c_str, '.', '_'); + BLI_string_replace_char(frame_file_c_str, '.', '_'); const StringRefNull frame_file_str = frame_file_c_str; BKE_scene_graph_update_for_newframe(job.depsgraph); diff --git a/source/blender/editors/render/render_shading.cc b/source/blender/editors/render/render_shading.cc index 2a3d7c7a6d5..3f6b4d387aa 100644 --- a/source/blender/editors/render/render_shading.cc +++ b/source/blender/editors/render/render_shading.cc @@ -26,6 +26,7 @@ #include "BLI_listbase.h" #include "BLI_math_vector.h" #include "BLI_path_util.h" +#include "BLI_string_utils.h" #include "BLI_utildefines.h" #include "BLT_translation.h" @@ -1144,7 +1145,7 @@ static int view_layer_add_lightgroup_exec(bContext *C, wmOperator *op) if (RNA_struct_property_is_set(op->ptr, "name")) { RNA_string_get(op->ptr, "name", name); /* Ensure that there are no dots in the name. */ - BLI_str_replace_char(name, '.', '_'); + BLI_string_replace_char(name, '.', '_'); LISTBASE_FOREACH (ViewLayerLightgroup *, lightgroup, &view_layer->lightgroups) { if (STREQ(lightgroup->name, name)) { return OPERATOR_CANCELLED; diff --git a/source/blender/gpu/intern/gpu_platform.cc b/source/blender/gpu/intern/gpu_platform.cc index 59beac3638b..a176f161296 100644 --- a/source/blender/gpu/intern/gpu_platform.cc +++ b/source/blender/gpu/intern/gpu_platform.cc @@ -13,6 +13,7 @@ #include "BLI_dynstr.h" #include "BLI_string.h" +#include "BLI_string_utils.h" #include "GPU_platform.h" @@ -45,8 +46,8 @@ static char *create_key(eGPUSupportLevel support_level, char *support_key = BLI_dynstr_get_cstring(ds); BLI_dynstr_free(ds); - BLI_str_replace_char(support_key, '\n', ' '); - BLI_str_replace_char(support_key, '\r', ' '); + BLI_string_replace_char(support_key, '\n', ' '); + BLI_string_replace_char(support_key, '\r', ' '); return support_key; } @@ -57,8 +58,8 @@ static char *create_gpu_name(const char *vendor, const char *renderer, const cha char *gpu_name = BLI_dynstr_get_cstring(ds); BLI_dynstr_free(ds); - BLI_str_replace_char(gpu_name, '\n', ' '); - BLI_str_replace_char(gpu_name, '\r', ' '); + BLI_string_replace_char(gpu_name, '\n', ' '); + BLI_string_replace_char(gpu_name, '\r', ' '); return gpu_name; } diff --git a/source/blender/imbuf/intern/thumbs.cc b/source/blender/imbuf/intern/thumbs.cc index e01cf8e9e22..5086b22ad11 100644 --- a/source/blender/imbuf/intern/thumbs.cc +++ b/source/blender/imbuf/intern/thumbs.cc @@ -241,7 +241,7 @@ static bool uri_from_filename(const char *path, char *uri) /* Not a correct absolute path with a drive letter or UNC prefix. */ return false; } - BLI_str_replace_char(orig_uri, '\\', '/'); + BLI_string_replace_char(orig_uri, '\\', '/'); #else SNPRINTF(orig_uri, "file://%s", path); #endif diff --git a/source/blender/io/usd/intern/usd_writer_material.cc b/source/blender/io/usd/intern/usd_writer_material.cc index 4dfb1c8e094..bc4469e5bcd 100644 --- a/source/blender/io/usd/intern/usd_writer_material.cc +++ b/source/blender/io/usd/intern/usd_writer_material.cc @@ -22,6 +22,7 @@ #include "BLI_memory_utils.hh" #include "BLI_path_util.h" #include "BLI_string.h" +#include "BLI_string_utils.h" #include "DNA_material_types.h" @@ -659,7 +660,7 @@ static std::string get_tex_image_asset_filepath(bNode *node, BLI_path_split_dir_part(stage_path.c_str(), dir_path, FILE_MAX); BLI_path_join(exp_path, FILE_MAX, dir_path, "textures", file_path); } - BLI_str_replace_char(exp_path, '\\', '/'); + BLI_string_replace_char(exp_path, '\\', '/'); return exp_path; } @@ -678,7 +679,7 @@ static std::string get_tex_image_asset_filepath(bNode *node, if (!BLI_path_is_rel(rel_path)) { return path; } - BLI_str_replace_char(rel_path, '\\', '/'); + BLI_string_replace_char(rel_path, '\\', '/'); return rel_path + 2; } diff --git a/source/blender/nodes/function/nodes/node_fn_replace_string.cc b/source/blender/nodes/function/nodes/node_fn_replace_string.cc index 0dce7b42826..55e9d8cd8d0 100644 --- a/source/blender/nodes/function/nodes/node_fn_replace_string.cc +++ b/source/blender/nodes/function/nodes/node_fn_replace_string.cc @@ -3,6 +3,7 @@ * SPDX-License-Identifier: GPL-2.0-or-later */ #include "BLI_string_utf8.h" +#include "BLI_string_utils.h" #include "node_function_util.hh" @@ -23,7 +24,7 @@ static std::string replace_all(const StringRefNull str, if (from.is_empty()) { return str; } - char *new_str_ptr = BLI_str_replaceN(str.c_str(), from.c_str(), to.c_str()); + char *new_str_ptr = BLI_string_replaceN(str.c_str(), from.c_str(), to.c_str()); std::string new_str{new_str_ptr}; MEM_freeN(new_str_ptr); return new_str;