diff --git a/similar/main/menu.cpp b/similar/main/menu.cpp index c372b32e3..0be35063e 100644 --- a/similar/main/menu.cpp +++ b/similar/main/menu.cpp @@ -2332,21 +2332,32 @@ window_event_result browser::callback_handler(const d_event &event, window_event return get_absolute_path(userdata, ""); else { - const size_t len_newpath = strlen(newpath.data()); - const size_t len_item = strlen(list[citem]); - /* The separator may or may not be included, depending on - * whether one is already present. Regardless of whether a new - * separator is printed by the block, require sufficient space - * for it to fit. This is pessimistic, but should discourage - * gcc's -Wformat-truncation from warning about insufficient - * buffer capacity. In practice, users should never have a - * path that approaches this limit, so the `if` test should - * succeed in all reasonable cases. + const std::size_t len_newpath{strlen(newpath.data())}; + const std::size_t len_item{1 + strlen(list[citem])}; // also copy the trailing null + const std::size_t len_sep{strlen(sep)}; + /* If `newpath` is long enough to contain a separator, test + * whether it ends with a separator. If it is not long enough + * to contain one, or is tested and does not end with one, then + * set `len_copy_sep` to copy from `sep`. Otherwise, set + * `len_copy_sep` to copy nothing. */ - const size_t len_sep = strlen(sep); - if (len_newpath + len_item + len_sep < newpath.size()) + const std::size_t len_copy_sep{ + (len_newpath >= len_sep && !memcmp(&newpath[len_newpath - len_sep], sep, len_sep)) + ? std::size_t{0} + : len_sep + }; + const std::size_t capacity_newpath{newpath.size()}; + /* In practice, users should never have a path that approaches + * this limit, so the `if` test should succeed in all + * reasonable cases. + */ + if (const std::size_t total_used_after_insertion{len_newpath + len_copy_sep + len_item}; total_used_after_insertion < capacity_newpath) { - snprintf(&newpath[len_newpath], newpath.size() - len_newpath, "%s%s", (len_newpath >= len_sep && strncmp(&newpath[len_newpath - len_sep], sep, len_sep)) ? sep : "", list[citem]); + const auto begin_insert_sep{std::next(newpath.begin(), len_newpath)}; + const auto begin_insert_item{std::ranges::copy_n(sep, len_copy_sep, begin_insert_sep).out}; + const auto end_insert_item{std::ranges::copy_n(list[citem], len_item, begin_insert_item).out}; + (void)end_insert_item; + assert(end_insert_item == std::next(newpath.begin(), total_used_after_insertion)); } } if ((citem == 0) || PHYSFS_isDirectory(list[citem]))