From c193a920d04521f945a906e3a6db11d3dc025c68 Mon Sep 17 00:00:00 2001 From: Goober5000 Date: Fri, 24 Oct 2025 00:49:27 -0400 Subject: [PATCH] several utility enhancements These were coded for the `split_str` refactor, but are generally useful elsewhere as well. 1. Use SCP_string in some utility functions where appropriate 2. Avoid copying C-strings in some utility functions where it isn't necessary 3. Add concat functions to `SCP_vector` 4. Change return type `int` to `bool` on some common parselo functions 5. Add `find_white_space` and `find_gray_space` parselo functions --- code/globalincs/vmallocator.h | 10 +++++ code/hud/hud.cpp | 14 +++---- code/hud/hudmessage.cpp | 70 ++++++++++++++++++----------------- code/hud/hudmessage.h | 4 +- code/parse/parselo.cpp | 26 +++++++++++-- code/parse/parselo.h | 8 ++-- code/weapon/emp.cpp | 18 +++++---- 7 files changed, 91 insertions(+), 59 deletions(-) diff --git a/code/globalincs/vmallocator.h b/code/globalincs/vmallocator.h index 131fddbdf09..d190e57a4f3 100644 --- a/code/globalincs/vmallocator.h +++ b/code/globalincs/vmallocator.h @@ -32,6 +32,16 @@ class SCP_vector : public std::vector> return std::find(this->begin(), this->end(), item) != this->end(); } + void concat(SCP_vector&& other) + { + insert(this->end(), std::make_move_iterator(other.begin()), std::make_move_iterator(other.end())); + } + + void concat(const SCP_vector& other) + { + insert(this->end(), other.begin(), other.end()); + } + bool in_bounds(int idx) const { return (idx >= 0) && (static_cast(idx) < this->size()); diff --git a/code/hud/hud.cpp b/code/hud/hud.cpp index a3b1ec613a6..ba5b8de7668 100644 --- a/code/hud/hud.cpp +++ b/code/hud/hud.cpp @@ -987,30 +987,28 @@ void HudGauge::renderStringAlignCenter(int x, int y, int area_width, const char void HudGauge::renderPrintf(int x, int y, float scale, bool config, const char* format, ...) { - char tmp[256] = ""; + SCP_string tmp; va_list args; // format the text va_start(args, format); - vsnprintf(tmp, sizeof(tmp), format, args); + vsprintf(tmp, format, args); va_end(args); - tmp[sizeof(tmp)-1] = '\0'; - renderString(x, y, tmp, scale, config); + renderString(x, y, tmp.c_str(), scale, config); } void HudGauge::renderPrintfWithGauge(int x, int y, int gauge_id, float scale, bool config, const char* format, ...) { - char tmp[256] = ""; + SCP_string tmp; va_list args; // format the text va_start(args, format); - vsnprintf(tmp, sizeof(tmp), format, args); + vsprintf(tmp, format, args); va_end(args); - tmp[sizeof(tmp)-1] = '\0'; - renderString(x, y, gauge_id, tmp, scale, config); + renderString(x, y, gauge_id, tmp.c_str(), scale, config); } void HudGauge::renderBitmapColor(int frame, int x, int y, float scale, bool config) const diff --git a/code/hud/hudmessage.cpp b/code/hud/hudmessage.cpp index 9a04589a90f..348b0a207d3 100644 --- a/code/hud/hudmessage.cpp +++ b/code/hud/hudmessage.cpp @@ -140,7 +140,7 @@ static SCP_vector Msg_scrollback_lines; typedef struct HUD_ft { int end_time; // Timestamp at which this message will go away. - char text[MAX_HUD_LINE_LEN]; // Text to display. + char text[MAX_HUD_LINE_BUF]; // Text to display. int color; // 0rgb color, 8 bit fields. } HUD_ft; @@ -487,8 +487,6 @@ void HudGaugeMessages::render(float /*frametime*/, bool config) void HUD_fixed_printf(float duration, color col, const char *format, ...) { va_list args; - char tmp[HUD_MSG_LENGTH_MAX]; - size_t msg_length; // make sure we only print these messages if we're in the correct state if((Game_mode & GM_MULTIPLAYER) && (Netgame.game_state != NETGAME_STATE_IN_MISSION)){ @@ -497,22 +495,9 @@ void HUD_fixed_printf(float duration, color col, const char *format, ...) } va_start(args, format); - vsnprintf(tmp, sizeof(tmp), format, args); + vsnprintf(HUD_fixed_text[0].text, MAX_HUD_LINE_BUF, format, args); va_end(args); - tmp[sizeof(tmp)-1] = '\0'; - - msg_length = strlen(tmp); - - if ( !msg_length ) { - nprintf(("Warning", "HUD_fixed_printf ==> attempt to print a 0 length string in msg window\n")); - return; - - } else if (msg_length > MAX_HUD_LINE_LEN - 1){ - nprintf(("Warning", "HUD_fixed_printf ==> Following string truncated to %d chars: %s\n", MAX_HUD_LINE_LEN - 1, tmp)); - tmp[MAX_HUD_LINE_LEN-1] = '\0'; - } - - strcpy_s(HUD_fixed_text[0].text, tmp); + HUD_fixed_text[0].text[MAX_HUD_LINE_BUF-1] = '\0'; if (duration == 0.0f){ HUD_fixed_text[0].end_time = timestamp(-1); @@ -544,7 +529,7 @@ int HUD_source_get_team(int source) void HUD_printf(const char *format, ...) { va_list args; - char tmp[HUD_MSG_LENGTH_MAX]; + SCP_string tmp; // make sure we only print these messages if we're in the correct state if((Game_mode & GM_MULTIPLAYER) && (Net_player->state != NETPLAYER_STATE_IN_MISSION)){ @@ -553,9 +538,8 @@ void HUD_printf(const char *format, ...) } va_start(args, format); - vsnprintf(tmp, sizeof(tmp), format, args); + vsprintf(tmp, format, args); va_end(args); - tmp[sizeof(tmp)-1] = '\0'; hud_sourced_print(HUD_SOURCE_COMPUTER, tmp); } @@ -570,7 +554,7 @@ void HUD_printf(const char *format, ...) void HUD_sourced_printf(int source, const char *format, ...) { va_list args; - char tmp[HUD_MSG_LENGTH_MAX]; + SCP_string tmp; // make sure we only print these messages if we're in the correct state if((Game_mode & GM_MULTIPLAYER) && (Net_player->state != NETPLAYER_STATE_IN_MISSION)){ @@ -579,16 +563,40 @@ void HUD_sourced_printf(int source, const char *format, ...) } va_start(args, format); - vsnprintf(tmp, sizeof(tmp), format, args); + vsprintf(tmp, format, args); va_end(args); - tmp[sizeof(tmp)-1] = '\0'; hud_sourced_print(source, tmp); } +void hud_sourced_print(int source, const SCP_string &msg) +{ + if ( msg.empty() ) { + nprintf(("Warning", "HUD ==> attempt to print a 0 length string in msg window\n")); + return; + } + + // add message to the scrollback log first + hud_add_msg_to_scrollback(msg.c_str(), source, Missiontime); + + HUD_message_data new_msg; + + new_msg.text = msg; + new_msg.source = source; + new_msg.x = 0; + + HUD_msg_buffer.push_back(new_msg); + + // Invoke the scripting hook + if (OnHudMessageReceivedHook->isActive()) { + OnHudMessageReceivedHook->run(scripting::hook_param_list(scripting::hook_param("Text", 's', msg.c_str()), + scripting::hook_param("SourceType", 'i', source))); + } +} + void hud_sourced_print(int source, const char *msg) { - if ( !strlen(msg) ) { + if ( !*msg ) { nprintf(("Warning", "HUD ==> attempt to print a 0 length string in msg window\n")); return; } @@ -643,21 +651,15 @@ void HUD_add_to_scrollback(const char *text, int source) void hud_add_msg_to_scrollback(const char *text, int source, int t) { - size_t msg_len = strlen(text); - if (msg_len == 0) + if (!*text) return; - - Assert(msg_len < HUD_MSG_LENGTH_MAX); - - char buf[HUD_MSG_LENGTH_MAX], *ptr; - strcpy_s(buf, text); - ptr = strstr(buf, NOX(": ")); int w = 0; // determine the length of the sender's name for underlining + auto ptr = strstr(text, NOX(": ")); if (ptr) { - gr_get_string_size(&w, nullptr, buf, 1.0f, (ptr - buf)); + gr_get_string_size(&w, nullptr, text, 1.0f, (ptr - text)); } // create the new node for the vector diff --git a/code/hud/hudmessage.h b/code/hud/hudmessage.h index 4599cf3a045..ebfbef29d46 100644 --- a/code/hud/hudmessage.h +++ b/code/hud/hudmessage.h @@ -16,7 +16,7 @@ #include "graphics/generic.h" #include "hud/hud.h" -#define MAX_HUD_LINE_LEN 256 // maximum number of characters for a HUD message +#define MAX_HUD_LINE_BUF 256 // maximum size for a HUD message // If these are changed, the lua 'addMessageToScrollback' method in mission.cpp should be updated. #define HUD_SOURCE_COMPUTER 0 @@ -67,12 +67,12 @@ int HUD_team_get_source(int team); int HUD_source_get_team(int team); void HUD_printf(SCP_FORMAT_STRING const char *format, ...) SCP_FORMAT_STRING_ARGS(1, 2); void hud_sourced_print(int source, const char *msg); +void hud_sourced_print(int source, const SCP_string &msg); void HUD_sourced_printf(int source, SCP_FORMAT_STRING const char *format, ...) SCP_FORMAT_STRING_ARGS(2, 3); // send hud message from specified source void HUD_fixed_printf(float duration, color col, SCP_FORMAT_STRING const char *format, ...) SCP_FORMAT_STRING_ARGS(3, 4); // Display a single message for duration seconds. void HUD_init_fixed_text(); // Clear all pending fixed text. void HUD_add_to_scrollback(const char *text, int source); -void hud_add_line_to_scrollback(const char *text, int source, int t, int x, int y, int w); void hud_add_msg_to_scrollback(const char *text, int source, int t); class HudGaugeMessages: public HudGauge // HUD_MESSAGE_LINES diff --git a/code/parse/parselo.cpp b/code/parse/parselo.cpp index 729838a305c..609a5ae2708 100644 --- a/code/parse/parselo.cpp +++ b/code/parse/parselo.cpp @@ -68,25 +68,43 @@ static const SCP_unordered_map retail_hashes = { // Return true if this character is white space, else false. -int is_white_space(char ch) +bool is_white_space(char ch) { return ((ch == ' ') || (ch == '\t') || (ch == EOLN) || (ch == CARRIAGE_RETURN)); } -int is_white_space(unicode::codepoint_t cp) + +// Return true if this character is white space, else false. +bool is_white_space(unicode::codepoint_t cp) { return ((cp == UNICODE_CHAR(' ')) || (cp == UNICODE_CHAR('\t')) || (cp == (unicode::codepoint_t)EOLN) || (cp == (unicode::codepoint_t)CARRIAGE_RETURN)); } +// Returns the length of the string up to but excluding any white space. This could be the entire string if the string contains no white space. +// Equivalently, returns the position of the first white space character, or the string length if no white space is found. +size_t find_white_space(const char *str) +{ + return strcspn(str, " \t\n\r"); +} + // Returns true if this character is gray space, else false (gray space is white space except for EOLN). -int is_gray_space(char ch) +bool is_gray_space(char ch) { return ((ch == ' ') || (ch == '\t')); } -bool is_gray_space(unicode::codepoint_t cp) { +// Returns true if this character is gray space, else false (gray space is white space except for EOLN). +bool is_gray_space(unicode::codepoint_t cp) +{ return cp == UNICODE_CHAR(' ') || cp == UNICODE_CHAR('\t'); } +// Returns the length of the string up to but excluding any white space. This could be the entire string if the string contains no white space. +// Equivalently, returns the position of the first white space character, or the string length if no white space is found. +size_t find_gray_space(const char *str) +{ + return strcspn(str, " \t"); +} + bool is_parenthesis(char ch) { return ((ch == '(') || (ch == ')')); diff --git a/code/parse/parselo.h b/code/parse/parselo.h index f446e690645..50493800a0b 100644 --- a/code/parse/parselo.h +++ b/code/parse/parselo.h @@ -89,8 +89,9 @@ extern void consolidate_double_characters(char *str, char ch); char *three_dot_truncate(char *buffer, const char *source, size_t buffer_size); // white space -extern int is_white_space(char ch); -extern int is_white_space(unicode::codepoint_t cp); +extern bool is_white_space(char ch); +extern bool is_white_space(unicode::codepoint_t cp); +extern size_t find_white_space(const char *str); extern void ignore_white_space(const char **pp = nullptr); extern void drop_trailing_white_space(char *str); extern void drop_leading_white_space(char *str); @@ -102,8 +103,9 @@ extern void drop_leading_white_space(SCP_string &str); extern void drop_white_space(SCP_string &str); // gray space -extern int is_gray_space(char ch); +extern bool is_gray_space(char ch); extern bool is_gray_space(unicode::codepoint_t cp); +extern size_t find_gray_space(const char *str); extern void ignore_gray_space(const char **pp = nullptr); // other diff --git a/code/weapon/emp.cpp b/code/weapon/emp.cpp index 4c72b35b3ee..32fbf1fb887 100644 --- a/code/weapon/emp.cpp +++ b/code/weapon/emp.cpp @@ -489,25 +489,27 @@ int emp_should_blit_gauge() // emp hud string void emp_hud_string(int x, int y, int gauge_id, const char *str, int resize_mode, float scale) { - char tmp[256] = ""; - // maybe bail if (!*str) return; - // copy the string - strcpy_s(tmp, str); - // if the emp effect is not active, don't even bother messing with the text if(emp_active_local()){ + // use a copied string rather than the original + char tmp[256] = ""; + strcpy_s(tmp, str); + emp_maybe_reformat_text(tmp, 256, gauge_id); // jitter the coords emp_hud_jitter(&x, &y); - } - // print the string out - gr_string(x, y, tmp, resize_mode, scale); + // print the string out + gr_string(x, y, tmp, resize_mode, scale); + } else { + // print the original string out + gr_string(x, y, str, resize_mode, scale); + } } // maybe reformat a string