diff --git a/common/main/player-callsign.h b/common/main/player-callsign.h index 529f7bc3f..825a954a4 100644 --- a/common/main/player-callsign.h +++ b/common/main/player-callsign.h @@ -8,10 +8,10 @@ #pragma once -#ifdef __cplusplus #include #include #include +#include #include "dxxsconf.h" #include @@ -28,10 +28,18 @@ struct callsign_t { return std::tolower(static_cast(c)); } - void copy(const char *s, std::size_t N) + template + requires(Extent == std::dynamic_extent || Extent <= array_length) + void copy(const std::span s) { + /* Zero the entire array first, so that word-sized moves can be used to + * store the null bytes in bulk. Then copy an appropriate number of + * characters using byte-sized moves, with a limit to prevent + * overwriting the final null byte even if the input string is too + * long. + */ a = {}; - std::copy_n(s, std::min(a.size() - 1, N), begin(a)); + std::copy_n(s.data(), std::min(a.size() - 1, s.size()), begin(a)); } void copy_lower(const char *s, std::size_t N) { @@ -52,8 +60,7 @@ struct callsign_t template void operator=(const char (&s)[N]) { - static_assert(N <= array_length, "string too long"); - copy(s, N); + copy(std::span(s)); } template void copy_lower(const char (&s)[N]) @@ -80,5 +87,3 @@ struct callsign_t } }; static_assert(sizeof(callsign_t) == CALLSIGN_LEN + 1, "callsign_t too big"); - -#endif diff --git a/similar/main/inferno.cpp b/similar/main/inferno.cpp index e08bdc7d1..7fc364935 100644 --- a/similar/main/inferno.cpp +++ b/similar/main/inferno.cpp @@ -726,7 +726,7 @@ static int main(int argc, char *argv[]) } if(PHYSFSX_exists(filename,0)) { - InterfaceUniqueState.PilotName.copy(b, std::distance(b, &filename[j - 4])); + InterfaceUniqueState.PilotName.copy(std::span(b, std::distance(b, &filename[j - 4]))); InterfaceUniqueState.update_window_title(); read_player_file(); WriteConfigFile(); diff --git a/similar/main/net_udp.cpp b/similar/main/net_udp.cpp index 6a3992857..4cdc3cbf6 100644 --- a/similar/main/net_udp.cpp +++ b/similar/main/net_udp.cpp @@ -204,8 +204,20 @@ net_udp_select_teams_menu_items::net_udp_select_teams_menu_items(const unsigned blue_team_color(BM_XRGB(player_rgb[0].r, player_rgb[0].g, player_rgb[0].b)), red_team_color(BM_XRGB(player_rgb[1].r, player_rgb[1].g, player_rgb[1].b)) { - team_names[0].copy(TXT_BLUE, ~0ul); - team_names[1].copy(TXT_RED, ~0ul); + const auto set_team_name = [](callsign_t &team_name, const auto &&s) { + if constexpr (std::is_array::type>::value) + /* When the input is an array (due to + * -D'USE_BUILTIN_ENGLISH_TEXT_STRINGS'), construct a std::span + * implicitly with the correct length. + */ + team_name.copy(s); + else + /* Otherwise, construct one explicitly with the dynamically + * detected length. */ + team_name.copy(std::span(s, strlen(s))); + }; + set_team_name(team_names[0], TXT_BLUE); + set_team_name(team_names[1], TXT_RED); /* Round blue team up. Round red team down. */ const unsigned num_blue_players = (num_players + 1) >> 1; // Put first half of players on team A @@ -3183,7 +3195,7 @@ static void net_udp_process_game_info_heavy(const uint8_t *data, uint_fast32_t, Netgame.InvulAppear = data[len]; len += 1; range_for (auto &i, Netgame.team_name) { - i.copy(reinterpret_cast(&data[len]), (CALLSIGN_LEN+1)); + i.copy(std::span(reinterpret_cast(&data[len]), CALLSIGN_LEN + 1)); len += CALLSIGN_LEN + 1; } range_for (auto &i, Netgame.locations)