diff --git a/src/industry_cmd.cpp b/src/industry_cmd.cpp index 2df20b0a81..909e3ba5d8 100644 --- a/src/industry_cmd.cpp +++ b/src/industry_cmd.cpp @@ -25,7 +25,7 @@ #include "newgrf_industrytiles.h" #include "autoslope.h" #include "water.h" -#include "strings_internal.h" +#include "strings_func.h" #include "window_func.h" #include "vehicle_func.h" #include "sound_func.h" diff --git a/src/station_cmd.cpp b/src/station_cmd.cpp index 6a1c4c1c19..487cd119a5 100644 --- a/src/station_cmd.cpp +++ b/src/station_cmd.cpp @@ -28,7 +28,7 @@ #include "road_internal.h" /* For drawing catenary/checking road removal */ #include "autoslope.h" #include "water.h" -#include "strings_internal.h" +#include "strings_func.h" #include "clear_func.h" #include "timer/timer_game_calendar.h" #include "vehicle_func.h" diff --git a/src/strings.cpp b/src/strings.cpp index 83d6a923f4..18785e1596 100644 --- a/src/strings.cpp +++ b/src/strings.cpp @@ -194,6 +194,22 @@ static bool GetSpecialNameString(StringBuilder &builder, StringID string, String static void FormatString(StringBuilder &builder, const char *str, StringParameters &args, uint case_index = 0, bool game_script = false, bool dry_run = false); +/** + * Parse most format codes within a string and write the result to a buffer. + * This is a wrapper for a span of StringParameter which creates the StringParameters state and forwards to the regular call. + * @param builder The string builder to write the final string to. + * @param str Pointer to string to format. + * @param params The span of parameters to pass. + * @param case_index The current case index. + * @param game_script True when doing GameScript text processing. + * @param dry_run True when the args' type data is not yet initialized. + */ +static void FormatString(StringBuilder &builder, const char *str, std::span params, uint case_index = 0, bool game_script = false, bool dry_run = false) +{ + StringParameters tmp_params{params}; + FormatString(builder, str, tmp_params, case_index, game_script, dry_run); +} + struct LanguagePack : public LanguagePackHeader { char data[]; // list of strings }; @@ -322,6 +338,19 @@ void GetStringWithArgs(StringBuilder &builder, StringID string, StringParameters FormatString(builder, GetStringPtr(string), args, case_index); } +/** + * Get a parsed string with most special stringcodes replaced by the string parameters. + * @param builder The builder of the string. + * @param string The ID of the string to parse. + * @param args Span of arguments for the string. + * @param case_index The "case index". This will only be set when FormatString wants to print the string in a different case. + * @param game_script The string is coming directly from a game script. + */ +void GetStringWithArgs(StringBuilder &builder, StringID string, std::span params, uint case_index, bool game_script) +{ + StringParameters tmp_params{params}; + GetStringWithArgs(builder, string, tmp_params, case_index, game_script); +} /** * Resolve the given StringID into a std::string with all the associated @@ -362,6 +391,14 @@ std::string GetStringWithArgs(StringID string, StringParameters &args) return result; } +std::string GetStringWithArgs(StringID string, std::span args) +{ + std::string result; + StringBuilder builder(result); + GetStringWithArgs(builder, string, args); + return result; +} + /** * This function is used to "bind" a C string to a OpenTTD dparam slot. * @param n slot of the string @@ -563,8 +600,7 @@ static void FormatGenericCurrency(StringBuilder &builder, const CurrencySpec *sp if (StrEmpty(separator)) separator = _langpack.langpack->digit_group_separator_currency; FormatNumber(builder, number, separator); if (number_str != STR_NULL) { - auto tmp_params = ArrayStringParameters<0>(); - FormatString(builder, GetStringPtr(number_str), tmp_params); + FormatString(builder, GetStringPtr(number_str), {}); } /* Add suffix part, following symbol_pos specification. @@ -1559,8 +1595,7 @@ static void FormatString(StringBuilder &builder, const char *str_arg, StringPara } } - auto tmp_params = ArrayStringParameters<0>(); - GetStringWithArgs(builder, e->info.string_id, tmp_params); + GetStringWithArgs(builder, e->info.string_id, {}); break; } @@ -1586,8 +1621,7 @@ static void FormatString(StringBuilder &builder, const char *str_arg, StringPara if (_scan_for_gender_data) { /* Gender is defined by the industry type. * STR_FORMAT_INDUSTRY_NAME may have the town first, so it would result in the gender of the town name */ - auto tmp_params = ArrayStringParameters<0>(); - FormatString(builder, GetStringPtr(GetIndustrySpec(i->type)->name), tmp_params, next_substr_case_index); + FormatString(builder, GetStringPtr(GetIndustrySpec(i->type)->name), {}, next_substr_case_index); } else if (use_cache) { // Use cached version if first call AutoRestoreBackup cache_backup(use_cache, false); builder += i->GetCachedName(); @@ -1622,8 +1656,7 @@ static void FormatString(StringBuilder &builder, const char *str_arg, StringPara /* The station doesn't exist anymore. The only place where we might * be "drawing" an invalid station is in the case of cargo that is * in transit. */ - auto tmp_params = ArrayStringParameters<0>(); - GetStringWithArgs(builder, STR_UNKNOWN_STATION, tmp_params); + GetStringWithArgs(builder, STR_UNKNOWN_STATION, {}); break; } @@ -1723,8 +1756,7 @@ static void FormatString(StringBuilder &builder, const char *str_arg, StringPara auto tmp_params = MakeParameters(si->name); GetStringWithArgs(builder, STR_JUST_RAW_STRING, tmp_params); } else { - auto tmp_params = ArrayStringParameters<0>(); - GetStringWithArgs(builder, STR_DEFAULT_SIGN_NAME, tmp_params); + GetStringWithArgs(builder, STR_DEFAULT_SIGN_NAME, {}); } break; } diff --git a/src/strings_func.h b/src/strings_func.h index 23a5eb3ce8..ed4aaef2fb 100644 --- a/src/strings_func.h +++ b/src/strings_func.h @@ -59,6 +59,7 @@ inline StringID MakeStringID(StringTab tab, StringIndexInTab index) return (tab << TAB_SIZE_BITS) + index.base(); } +std::string GetStringWithArgs(StringID string, std::span args); std::string GetString(StringID string); const char *GetStringPtr(StringID string); void AppendStringInPlace(std::string &result, StringID string); @@ -109,6 +110,18 @@ void InitializeLanguagePacks(); const char *GetCurrentLanguageIsoCode(); std::string_view GetListSeparator(); +/** + * Helper to create the StringParameters with its own buffer with the given + * parameter values. + * @param args The parameters to set for the to be created StringParameters. + * @return The constructed StringParameters. + */ +template +auto MakeParameters(Args &&... args) +{ + return std::array({std::forward(args)...}); +} + /** * A searcher for missing glyphs. */ diff --git a/src/strings_internal.h b/src/strings_internal.h index 9462a1c984..a5a0609663 100644 --- a/src/strings_internal.h +++ b/src/strings_internal.h @@ -13,12 +13,6 @@ #include "strings_func.h" #include "string_func.h" -/** The data required to format and validate a single parameter of a string. */ -struct StringParameter { - StringParameterData data; ///< The data of the parameter. - char32_t type; ///< The #StringControlCode to interpret this data with when it's the first parameter, otherwise '\0'. -}; - class StringParameters { protected: StringParameters *parent = nullptr; ///< If not nullptr, this instance references data from this parent instance. @@ -27,10 +21,6 @@ protected: size_t offset = 0; ///< Current offset in the parameters span. char32_t next_type = 0; ///< The type of the next data that is retrieved. - StringParameters(std::span parameters = {}) : - parameters(parameters) - {} - const StringParameter &GetNextParameterReference(); public: @@ -43,6 +33,8 @@ public: parameters(parent.parameters.subspan(parent.offset, size)) {} + StringParameters(std::span parameters = {}) : parameters(parameters) {} + void PrepareForNextRun(); void SetTypeOfNextParameter(char32_t type) { this->next_type = type; } @@ -225,21 +217,6 @@ public: ArrayStringParameters& operator=(const ArrayStringParameters &other) = delete; }; -/** - * Helper to create the StringParameters with its own buffer with the given - * parameter values. - * @param args The parameters to set for the to be created StringParameters. - * @return The constructed StringParameters. - */ -template -static auto MakeParameters(const Args&... args) -{ - ArrayStringParameters parameters; - size_t index = 0; - (parameters.SetParam(index++, std::forward(args)), ...); - return parameters; -} - /** * Equivalent to the std::back_insert_iterator in function, with some * convenience helpers for string concatenation. @@ -339,6 +316,7 @@ public: }; void GetStringWithArgs(StringBuilder &builder, StringID string, StringParameters &args, uint case_index = 0, bool game_script = false); +void GetStringWithArgs(StringBuilder &builder, StringID string, std::span params, uint case_index = 0, bool game_script = false); std::string GetStringWithArgs(StringID string, StringParameters &args); /* Do not leak the StringBuilder to everywhere. */ diff --git a/src/strings_type.h b/src/strings_type.h index 534eeacb48..6446e4d653 100644 --- a/src/strings_type.h +++ b/src/strings_type.h @@ -10,6 +10,7 @@ #ifndef STRINGS_TYPE_H #define STRINGS_TYPE_H +#include "core/convertible_through_base.hpp" #include "core/strong_typedef_type.hpp" /** @@ -73,4 +74,21 @@ static constexpr StringID SPECSTR_PRESIDENT_NAME = 0x70E7; ///< Special string f using StringParameterData = std::variant; +/** The data required to format and validate a single parameter of a string. */ +struct StringParameter { + StringParameterData data; ///< The data of the parameter. + char32_t type; ///< The #StringControlCode to interpret this data with when it's the first parameter, otherwise '\0'. + + StringParameter() = default; + inline StringParameter(StringParameterData &&data) : data(std::move(data)), type(0) {} + + inline StringParameter(uint64_t data) : data(data), type(0) {} + + inline StringParameter(const char *data) : data(std::string{data}), type(0) {} + inline StringParameter(std::string &&data) : data(std::move(data)), type(0) {} + inline StringParameter(const std::string &data) : data(data), type(0) {} + + inline StringParameter(const ConvertibleThroughBase auto &data) : data(static_cast(data.base())), type(0) {} +}; + #endif /* STRINGS_TYPE_H */