diff --git a/src/industry_cmd.cpp b/src/industry_cmd.cpp --- a/src/industry_cmd.cpp +++ b/src/industry_cmd.cpp @@ -2431,11 +2431,9 @@ void Industry::RecomputeProductionMultip void Industry::FillCachedName() const { - char buf[256]; int64 args_array[] = { this->index }; StringParameters tmp_params(args_array); - char *end = GetStringWithArgs(buf, STR_INDUSTRY_NAME, &tmp_params, lastof(buf)); - this->cached_name.assign(buf, end); + this->cached_name = GetStringWithArgs(STR_INDUSTRY_NAME, &tmp_params); } void ClearAllIndustryCachedNames() diff --git a/src/newgrf_townname.cpp b/src/newgrf_townname.cpp --- a/src/newgrf_townname.cpp +++ b/src/newgrf_townname.cpp @@ -16,6 +16,7 @@ #include "newgrf_townname.h" #include "core/alloc_func.hpp" #include "string_func.h" +#include "strings_internal.h" #include "table/strings.h" @@ -46,7 +47,7 @@ void DelGRFTownName(uint32 grfid) _grf_townnames.erase(std::find_if(std::begin(_grf_townnames), std::end(_grf_townnames), [&grfid](const GRFTownName &t){ return t.grfid == grfid; })); } -static char *RandomPart(char *buf, const GRFTownName *t, uint32 seed, byte id, const char *last) +static void RandomPart(StringBuilder &builder, const GRFTownName *t, uint32 seed, byte id) { assert(t != nullptr); for (const auto &partlist : t->partlists[id]) { @@ -57,25 +58,22 @@ static char *RandomPart(char *buf, const maxprob -= GB(part.prob, 0, 7); if (maxprob > r) continue; if (HasBit(part.prob, 7)) { - buf = RandomPart(buf, t, seed, part.id, last); + RandomPart(builder, t, seed, part.id); } else { - buf = strecat(buf, part.text.c_str(), last); + builder += part.text; } break; } } - return buf; } -char *GRFTownNameGenerate(char *buf, uint32 grfid, uint16 gen, uint32 seed, const char *last) +void GRFTownNameGenerate(StringBuilder &builder, uint32 grfid, uint16 gen, uint32 seed) { - strecpy(buf, "", last); const GRFTownName *t = GetGRFTownName(grfid); if (t != nullptr) { assert(gen < t->styles.size()); - buf = RandomPart(buf, t, seed, t->styles[gen].id, last); + RandomPart(builder, t, seed, t->styles[gen].id); } - return buf; } diff --git a/src/newgrf_townname.h b/src/newgrf_townname.h --- a/src/newgrf_townname.h +++ b/src/newgrf_townname.h @@ -47,7 +47,6 @@ GRFTownName *AddGRFTownName(uint32 grfid GRFTownName *GetGRFTownName(uint32 grfid); void DelGRFTownName(uint32 grfid); void CleanUpGRFTownNames(); -char *GRFTownNameGenerate(char *buf, uint32 grfid, uint16 gen, uint32 seed, const char *last); uint32 GetGRFTownNameId(uint16 gen); uint16 GetGRFTownNameType(uint16 gen); StringID GetGRFTownNameName(uint16 gen); diff --git a/src/station_cmd.cpp b/src/station_cmd.cpp --- a/src/station_cmd.cpp +++ b/src/station_cmd.cpp @@ -461,11 +461,9 @@ void UpdateAllStationVirtCoords() void BaseStation::FillCachedName() const { - char buf[MAX_LENGTH_STATION_NAME_CHARS * MAX_CHAR_LENGTH]; int64 args_array[] = { this->index }; StringParameters tmp_params(args_array); - char *end = GetStringWithArgs(buf, Waypoint::IsExpected(this) ? STR_WAYPOINT_NAME : STR_STATION_NAME, &tmp_params, lastof(buf)); - this->cached_name.assign(buf, end); + this->cached_name = GetStringWithArgs(Waypoint::IsExpected(this) ? STR_WAYPOINT_NAME : STR_STATION_NAME, &tmp_params); } void ClearAllStationCachedNames() diff --git a/src/strings.cpp b/src/strings.cpp --- a/src/strings.cpp +++ b/src/strings.cpp @@ -172,8 +172,8 @@ void CopyOutDParam(uint64 *dst, const ch } static void StationGetSpecialString(StringBuilder &builder, int x); -static char *GetSpecialTownNameString(char *buff, int ind, uint32 seed, const char *last); -static char *GetSpecialNameString(char *buff, int ind, StringParameters *args, const char *last); +static void GetSpecialTownNameString(StringBuilder &builder, int ind, uint32 seed); +static void GetSpecialNameString(StringBuilder &builder, int ind, StringParameters *args); static void FormatString(StringBuilder &builder, const char *str, StringParameters *args, uint case_index = 0, bool game_script = false, bool dry_run = false); @@ -216,17 +216,18 @@ const char *GetStringPtr(StringID string /** * Get a parsed string with most special stringcodes replaced by the string parameters. - * @param buffr Pointer to a string buffer where the formatted string should be written to. - * @param string - * @param args Arguments for the string. - * @param last Pointer just past the end of \a buffr. + * @param builder The builder of the string. + * @param string The ID of the string to parse. + * @param args 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. - * @return Pointer to the final zero byte of the formatted string. */ -char *GetStringWithArgs(char *buffr, StringID string, StringParameters *args, const char *last, uint case_index, bool game_script) +void GetStringWithArgs(StringBuilder &builder, StringID string, StringParameters *args, uint case_index, bool game_script) { - if (string == 0) return GetStringWithArgs(buffr, STR_UNDEFINED, args, last); + if (string == 0) { + GetStringWithArgs(builder, STR_UNDEFINED, args); + return; + } uint index = GetStringIndex(string); StringTab tab = GetStringTab(string); @@ -234,13 +235,15 @@ char *GetStringWithArgs(char *buffr, Str switch (tab) { case TEXT_TAB_TOWN: if (index >= 0xC0 && !game_script) { - return GetSpecialTownNameString(buffr, index - 0xC0, args->GetInt32(), last); + GetSpecialTownNameString(builder, index - 0xC0, args->GetInt32()); + return; } break; case TEXT_TAB_SPECIAL: if (index >= 0xE4 && !game_script) { - return GetSpecialNameString(buffr, index - 0xE4, args, last); + GetSpecialNameString(builder, index - 0xE4, args); + return; } break; @@ -252,18 +255,16 @@ char *GetStringWithArgs(char *buffr, Str break; case TEXT_TAB_GAMESCRIPT_START: { - StringBuilder builder(buffr, last); FormatString(builder, GetGameStringPtr(index), args, case_index, true); - return builder.GetEnd(); + return; } case TEXT_TAB_OLD_NEWGRF: NOT_REACHED(); case TEXT_TAB_NEWGRF_START: { - StringBuilder builder(buffr, last); FormatString(builder, GetGRFStringPtr(index), args, case_index); - return builder.GetEnd(); + return; } default: @@ -272,34 +273,21 @@ char *GetStringWithArgs(char *buffr, Str if (index >= _langpack.langtab_num[tab]) { if (game_script) { - return GetStringWithArgs(buffr, STR_UNDEFINED, args, last); + return GetStringWithArgs(builder, STR_UNDEFINED, args); } FatalError("String 0x{:X} is invalid. You are probably using an old version of the .lng file.\n", string); } - StringBuilder builder(buffr, last); FormatString(builder, GetStringPtr(string), args, case_index); - return builder.GetEnd(); } char *GetString(char *buffr, StringID string, const char *last) { _global_string_params.ClearTypeInformation(); _global_string_params.offset = 0; - return GetStringWithArgs(buffr, string, &_global_string_params, last); -} - -/** - * 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 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, StringParameters *args, uint case_index = 0, bool game_script = false) -{ - builder.AddViaStreCallback([&](auto buff, auto last) { return GetStringWithArgs(buff, string, args, last, case_index, game_script); }); + StringBuilder builder(buffr, last); + GetStringWithArgs(builder, string, &_global_string_params); + return builder.GetEnd(); } @@ -317,6 +305,20 @@ std::string GetString(StringID string) } /** + * Get a parsed string with most special stringcodes replaced by the string parameters. + * @param string The ID of the string to parse. + * @param args Arguments for the string. + * @return The parsed string. + */ +std::string GetStringWithArgs(StringID string, StringParameters *args) +{ + char buffer[DRAW_STRING_BUFFER]; + StringBuilder builder(buffer, lastof(buffer)); + GetStringWithArgs(builder, string, args); + return std::string(buffer, builder.GetEnd()); +} + +/** * This function is used to "bind" a C string to a OpenTTD dparam slot. * @param n slot of the string * @param str string to bind @@ -1568,7 +1570,7 @@ static void FormatString(StringBuilder & StringParameters tmp_params(args_array); GetStringWithArgs(builder, STR_JUST_RAW_STRING, &tmp_params); } else { - builder.AddViaStreCallback([&t](auto buff, auto last) { return GetTownName(buff, t, last); }); + GetTownName(builder, t); } break; } @@ -1659,9 +1661,9 @@ static void StationGetSpecialString(Stri if ((x & FACIL_AIRPORT) != 0) builder.Utf8Encode(SCC_PLANE); } -static char *GetSpecialTownNameString(char *buff, int ind, uint32 seed, const char *last) +static void GetSpecialTownNameString(StringBuilder &builder, int ind, uint32 seed) { - return GenerateTownNameString(buff, last, ind, seed); + builder.AddViaStreCallback([&](auto buff, auto last) { return GenerateTownNameString(buff, last, ind, seed); }); } static const char * const _silly_company_names[] = { @@ -1732,7 +1734,7 @@ static const char _initial_name_letters[ 'K', 'L', 'M', 'N', 'P', 'R', 'S', 'T', 'W', }; -static char *GenAndCoName(char *buff, uint32 arg, const char *last) +static void GenAndCoName(StringBuilder &builder, uint32 arg) { const char * const *base; uint num; @@ -1745,13 +1747,11 @@ static char *GenAndCoName(char *buff, ui num = lengthof(_surname_list); } - buff = strecpy(buff, base[num * GB(arg, 16, 8) >> 8], last); - buff = strecpy(buff, " & Co.", last); - - return buff; + builder += base[num * GB(arg, 16, 8) >> 8]; + builder += " & Co."; } -static char *GenPresidentName(char *buff, uint32 x, const char *last) +static void GenPresidentName(StringBuilder &builder, uint32 x) { char initial[] = "?. "; const char * const *base; @@ -1759,12 +1759,12 @@ static char *GenPresidentName(char *buff uint i; initial[0] = _initial_name_letters[sizeof(_initial_name_letters) * GB(x, 0, 8) >> 8]; - buff = strecpy(buff, initial, last); + builder += initial; i = (sizeof(_initial_name_letters) + 35) * GB(x, 8, 8) >> 8; if (i < sizeof(_initial_name_letters)) { initial[0] = _initial_name_letters[i]; - buff = strecpy(buff, initial, last); + builder += initial; } if (_settings_game.game_creation.landscape == LT_TOYLAND) { @@ -1775,28 +1775,30 @@ static char *GenPresidentName(char *buff num = lengthof(_surname_list); } - buff = strecpy(buff, base[num * GB(x, 16, 8) >> 8], last); - - return buff; + builder += base[num * GB(x, 16, 8) >> 8]; } -static char *GetSpecialNameString(char *buff, int ind, StringParameters *args, const char *last) +static void GetSpecialNameString(StringBuilder &builder, int ind, StringParameters *args) { switch (ind) { case 1: // not used - return strecpy(buff, _silly_company_names[std::min(args->GetInt32() & 0xFFFF, lengthof(_silly_company_names) - 1)], last); + builder += _silly_company_names[std::min(args->GetInt32() & 0xFFFF, lengthof(_silly_company_names) - 1)]; + return; case 2: // used for Foobar & Co company names - return GenAndCoName(buff, args->GetInt32(), last); + GenAndCoName(builder, args->GetInt32()); + return; case 3: // President name - return GenPresidentName(buff, args->GetInt32(), last); + GenPresidentName(builder, args->GetInt32()); + return; } /* town name? */ if (IsInsideMM(ind - 6, 0, SPECSTR_TOWNNAME_LAST - SPECSTR_TOWNNAME_START + 1)) { - buff = GetSpecialTownNameString(buff, ind - 6, args->GetInt32(), last); - return strecpy(buff, " Transport", last); + GetSpecialTownNameString(builder, ind - 6, args->GetInt32()); + builder += " Transport"; + return; } NOT_REACHED(); diff --git a/src/strings_func.h b/src/strings_func.h --- a/src/strings_func.h +++ b/src/strings_func.h @@ -172,7 +172,7 @@ extern StringParameters _global_string_p char *GetString(char *buffr, StringID string, const char *last); std::string GetString(StringID string); -char *GetStringWithArgs(char *buffr, StringID string, StringParameters *args, const char *last, uint case_index = 0, bool game_script = false); +std::string GetStringWithArgs(StringID string, StringParameters *args); const char *GetStringPtr(StringID string); uint ConvertKmhishSpeedToDisplaySpeed(uint speed, VehicleType type); diff --git a/src/strings_internal.h b/src/strings_internal.h --- a/src/strings_internal.h +++ b/src/strings_internal.h @@ -10,6 +10,8 @@ #ifndef STRINGS_INTERNAL_H #define STRINGS_INTERNAL_H +#include "strings_func.h" + /** * Equivalent to the std::back_insert_iterator in function, with some * convenience helpers for string concatenation. @@ -130,4 +132,10 @@ public: } }; +void GetStringWithArgs(StringBuilder &builder, StringID string, StringParameters *args, uint case_index = 0, bool game_script = false); + +/* Do not leak the StringBuilder to everywhere. */ +void GetTownName(StringBuilder &builder, const struct Town *t); +void GRFTownNameGenerate(StringBuilder &builder, uint32 grfid, uint16 gen, uint32 seed); + #endif /* STRINGS_INTERNAL_H */ diff --git a/src/townname.cpp b/src/townname.cpp --- a/src/townname.cpp +++ b/src/townname.cpp @@ -15,6 +15,7 @@ #include "core/random_func.hpp" #include "genworld.h" #include "gfx_layout.h" +#include "strings_internal.h" #include "table/townname.h" @@ -39,6 +40,24 @@ TownNameParams::TownNameParams(const Tow /** + * Fills builder with specified town name. + * @param builder The string builder. + * @param par Town name parameters. + * @param townnameparts 'Encoded' town name. + */ +static void GetTownName(StringBuilder &builder, const TownNameParams *par, uint32 townnameparts) +{ + if (par->grfid == 0) { + int64 args_array[1] = { townnameparts }; + StringParameters tmp_params(args_array); + GetStringWithArgs(builder, par->type, &tmp_params); + return; + } + + GRFTownNameGenerate(builder, par->grfid, par->type, townnameparts); +} + +/** * Fills buffer with specified town name * @param buff buffer start * @param par town name parameters @@ -48,15 +67,21 @@ TownNameParams::TownNameParams(const Tow */ char *GetTownName(char *buff, const TownNameParams *par, uint32 townnameparts, const char *last) { - if (par->grfid == 0) { - int64 args_array[1] = { townnameparts }; - StringParameters tmp_params(args_array); - return GetStringWithArgs(buff, par->type, &tmp_params, last); - } - - return GRFTownNameGenerate(buff, par->grfid, par->type, townnameparts, last); + StringBuilder builder(buff, last); + GetTownName(builder, par, townnameparts); + return builder.GetEnd(); } +/** + * Fills builder with town's name. + * @param builder String builder. + * @param t The town to get the name from. + */ +void GetTownName(StringBuilder &builder, const Town *t) +{ + TownNameParams par(t); + GetTownName(builder, &par, t->townnameparts); +} /** * Fills buffer with town's name @@ -67,8 +92,9 @@ char *GetTownName(char *buff, const Town */ char *GetTownName(char *buff, const Town *t, const char *last) { - TownNameParams par(t); - return GetTownName(buff, &par, t->townnameparts, last); + StringBuilder builder(buff, last); + GetTownName(builder, t); + return builder.GetEnd(); }