Use StringBuilder for GetString/GetStringWithArgs, as per upstream

Update dependent code as required
pull/621/head
Jonathan G Rennison 4 months ago
parent 1b7a5372ec
commit f034714559

@ -73,28 +73,31 @@ inline void IterateCargoPacketDeferredPayments(CargoPacketID index, bool erase_r
}
}
void DumpCargoPacketDeferredPaymentStats(char *buffer, const char *last)
std::string DumpCargoPacketDeferredPaymentStats()
{
Money payments[256][4] = {};
for (auto &it : _cargo_packet_deferred_payments) {
payments[GB(it.first, 24, 8)][GB(it.first, 22, 2)] += it.second;
}
std::string buffer;
for (uint i = 0; i < 256; i++) {
for (uint j = 0; j < 4; j++) {
if (payments[i][j] != 0) {
SetDParam(0, i);
buffer = GetString(buffer, STR_COMPANY_NAME, last);
buffer += seprintf(buffer, last, " (");
buffer = GetString(buffer, STR_REPLACE_VEHICLE_TRAIN + j, last);
buffer += seprintf(buffer, last, "): ");
GetString(StringBuilder(buffer), STR_COMPANY_NAME);
buffer += " (";
GetString(StringBuilder(buffer), STR_REPLACE_VEHICLE_TRAIN + j);
buffer += "): ";
SetDParam(0, payments[i][j]);
buffer = GetString(buffer, STR_JUST_CURRENCY_LONG, last);
buffer += seprintf(buffer, last, "\n");
GetString(StringBuilder(buffer), STR_JUST_CURRENCY_LONG);
buffer += '\n';
}
}
}
buffer += seprintf(buffer, last, "Deferred payment count: %u\n", (uint) _cargo_packet_deferred_payments.size());
buffer += seprintf(buffer, last, "Total cargo packets: %u\n", (uint)CargoPacket::GetNumItems());
buffer += stdstr_fmt("Deferred payment count: %u\n", (uint) _cargo_packet_deferred_payments.size());
buffer += stdstr_fmt("Total cargo packets: %u\n", (uint)CargoPacket::GetNumItems());
return buffer;
}
/**

@ -1353,34 +1353,26 @@ void CommandCost::UseTextRefStack(const GRFFile *grffile, uint num_registers)
}
std::string CommandCost::SummaryMessage(StringID cmd_msg) const
{
char buf[DRAW_STRING_BUFFER];
this->WriteSummaryMessage(buf, lastof(buf), cmd_msg);
return buf;
}
int CommandCost::WriteSummaryMessage(char *buf, char *last, StringID cmd_msg) const
{
if (this->Succeeded()) {
return seprintf(buf, last, "Success: cost: " OTTD_PRINTF64, (int64) this->GetCost());
return stdstr_fmt("Success: cost: " OTTD_PRINTF64, (int64) this->GetCost());
} else {
const uint textref_stack_size = this->GetTextRefStackSize();
if (textref_stack_size > 0) StartTextRefStackUsage(this->GetTextRefStackGRF(), textref_stack_size, this->GetTextRefStack());
char *b = buf;
b += seprintf(b, last, "Failed: cost: " OTTD_PRINTF64, (int64) this->GetCost());
std::string buf = stdstr_fmt("Failed: cost: " OTTD_PRINTF64, (int64) this->GetCost());
if (cmd_msg != 0) {
b += seprintf(b, last, " ");
b = GetString(b, cmd_msg, last);
buf += ' ';
GetString(StringBuilder(buf), cmd_msg);
}
if (this->message != INVALID_STRING_ID) {
b += seprintf(b, last, " ");
b = GetString(b, this->message, last);
buf += ' ';
GetString(StringBuilder(buf), this->message);
}
if (textref_stack_size > 0) StopTextRefStackUsage();
return b - buf;
return buf;
}
}

@ -222,15 +222,6 @@ public:
*/
std::string SummaryMessage(StringID cmd_msg = 0) const;
/**
* Write a string summarising the command result
* @param buf buffer to write to
* @param last last byte in buffer
* @param cmd_msg optional failure string as passed to DoCommand
* @return the number of bytes written
*/
int WriteSummaryMessage(char *buf, char *last, StringID cmd_msg = 0) const;
bool IsSuccessWithMessage() const
{
return this->Succeeded() && this->message != INVALID_STRING_ID;

@ -380,10 +380,6 @@ CommandCost CheckTileOwnership(TileIndex tile)
*/
static void GenerateCompanyName(Company *c)
{
/* Reserve space for extra unicode character. We need to do this to be able
* to detect too long company name. */
char buffer[(MAX_LENGTH_COMPANY_NAME_CHARS + 1) * MAX_CHAR_LENGTH];
if (c->name_1 != STR_SV_UNNAMED) return;
if (c->last_build_coordinate == 0) return;
@ -391,6 +387,7 @@ static void GenerateCompanyName(Company *c)
StringID str;
uint32 strp;
std::string buffer;
if (t->name.empty() && IsInsideMM(t->townnametype, SPECSTR_TOWNNAME_START, SPECSTR_TOWNNAME_LAST + 1)) {
str = t->townnametype - SPECSTR_TOWNNAME_START + SPECSTR_COMPANY_NAME_START;
strp = t->townnameparts;
@ -402,7 +399,7 @@ verify_name:;
}
SetDParam(0, strp);
GetString(buffer, str, lastof(buffer));
buffer = GetString(str);
if (Utf8StringLength(buffer) >= MAX_LENGTH_COMPANY_NAME_CHARS) goto bad_town_name;
set_name:;
@ -524,18 +521,15 @@ restart:;
/* Reserve space for extra unicode character. We need to do this to be able
* to detect too long president name. */
char buffer[(MAX_LENGTH_PRESIDENT_NAME_CHARS + 1) * MAX_CHAR_LENGTH];
SetDParam(0, c->index);
GetString(buffer, STR_PRESIDENT_NAME, lastof(buffer));
if (Utf8StringLength(buffer) >= MAX_LENGTH_PRESIDENT_NAME_CHARS) continue;
std::string name = GetString(STR_PRESIDENT_NAME);
if (Utf8StringLength(name) >= MAX_LENGTH_PRESIDENT_NAME_CHARS) continue;
for (const Company *cc : Company::Iterate()) {
if (c != cc) {
/* Reserve extra space so even overlength president names can be compared. */
char buffer2[(MAX_LENGTH_PRESIDENT_NAME_CHARS + 1) * MAX_CHAR_LENGTH];
SetDParam(0, cc->index);
GetString(buffer2, STR_PRESIDENT_NAME, lastof(buffer2));
if (strcmp(buffer2, buffer) == 0) goto restart;
std::string other_name = GetString(STR_PRESIDENT_NAME);
if (name == other_name) goto restart;
}
}
return;

@ -1895,9 +1895,8 @@ DEF_CONSOLE_CMD(ConCompanies)
for (const Company *c : Company::Iterate()) {
/* Grab the company name */
char company_name[512];
SetDParam(0, c->index);
GetString(company_name, STR_COMPANY_NAME, lastof(company_name));
std::string company_name = GetString(STR_COMPANY_NAME);
const char *password_state = "";
if (c->is_ai) {
@ -1906,10 +1905,8 @@ DEF_CONSOLE_CMD(ConCompanies)
password_state = _network_company_states[c->index].password.empty() ? "unprotected" : "protected";
}
char colour[512];
GetString(colour, STR_COLOUR_DARK_BLUE + _company_colours[c->index], lastof(colour));
IConsolePrintF(CC_INFO, "#:%d(%s) Company Name: '%s' Year Founded: %d Money: " OTTD_PRINTF64 " Loan: " OTTD_PRINTF64 " Value: " OTTD_PRINTF64 " (T:%d, R:%d, P:%d, S:%d) %s",
c->index + 1, colour, company_name,
c->index + 1, GetStringPtr(STR_COLOUR_DARK_BLUE + _company_colours[c->index]), company_name.c_str(),
c->inaugurated_year, (int64)c->money, (int64)c->current_loan, (int64)CalculateCompanyValue(c),
c->group_all[VEH_TRAIN].num_vehicle,
c->group_all[VEH_ROAD].num_vehicle,
@ -2076,14 +2073,11 @@ DEF_CONSOLE_CMD(ConCompanyPasswordHashes)
for (const Company *c : Company::Iterate()) {
/* Grab the company name */
char company_name[512];
SetDParam(0, c->index);
GetString(company_name, STR_COMPANY_NAME, lastof(company_name));
std::string company_name = GetString(STR_COMPANY_NAME);
char colour[512];
GetString(colour, STR_COLOUR_DARK_BLUE + _company_colours[c->index], lastof(colour));
IConsolePrintF(CC_INFO, "#:%d(%s) Company Name: '%s' Hash: '%s'",
c->index + 1, colour, company_name, _network_company_states[c->index].password.c_str());
c->index + 1, GetStringPtr(STR_COLOUR_DARK_BLUE + _company_colours[c->index]), company_name.c_str(), _network_company_states[c->index].password.c_str());
}
return true;
@ -2472,10 +2466,8 @@ DEF_CONSOLE_CMD(ConResetBlockedHeliports)
if (!occupied) {
st->airport.flags = 0;
count++;
char buffer[256];
SetDParam(0, st->index);
GetString(buffer, STR_STATION_NAME, lastof(buffer));
IConsolePrintF(CC_DEFAULT, "Unblocked: %s", buffer);
IConsolePrintF(CC_DEFAULT, "Unblocked: %s", GetString(STR_STATION_NAME).c_str());
}
}
@ -2635,10 +2627,8 @@ DEF_CONSOLE_CMD(ConDumpCpdpStats)
return true;
}
extern void DumpCargoPacketDeferredPaymentStats(char *buffer, const char *last);
char buffer[32768];
DumpCargoPacketDeferredPaymentStats(buffer, lastof(buffer));
PrintLineByLine(buffer);
extern std::string DumpCargoPacketDeferredPaymentStats();
PrintLineByLine(DumpCargoPacketDeferredPaymentStats());
return true;
}

@ -901,7 +901,7 @@ void CrashLog::CloseCrashLogFile()
if (_screen.width < 1 || _screen.height < 1 || _screen.dst_ptr == nullptr) return false;
bool res = MakeScreenshot(SC_CRASHLOG, name);
if (res) strecpy(filename, _full_screenshot_name, filename_last);
if (res) strecpy(filename, _full_screenshot_path.c_str(), filename_last);
return res;
}

@ -875,20 +875,16 @@ void DeparturesWindow<Twaypoint>::DrawDeparturesListItems(const Rect &r) const
}
}
char buf[256] = "";
auto tmp_params = MakeParameters(Waypoint::IsValidID(id) ? STR_WAYPOINT_NAME : STR_STATION_NAME, id, icon_via);
char *end = GetStringWithArgs(buf, STR_DEPARTURES_VIA_DESCRIPTOR, tmp_params, lastof(buf));
_temp_special_strings[temp_str].assign(buf, end);
_temp_special_strings[temp_str] = GetStringWithArgs(STR_DEPARTURES_VIA_DESCRIPTOR, tmp_params);
};
get_single_via_string(0, via);
if (via2 != INVALID_STATION) {
get_single_via_string(1, via2);
char buf[512] = "";
auto tmp_params = MakeParameters(SPECSTR_TEMP_START, SPECSTR_TEMP_START + 1);
char *end = GetStringWithArgs(buf, STR_DEPARTURES_VIA_AND, tmp_params, lastof(buf));
_temp_special_strings[0].assign(buf, end);
_temp_special_strings[0] = GetStringWithArgs(STR_DEPARTURES_VIA_AND, tmp_params);
}
SetDParam(offset, SPECSTR_TEMP_START);
@ -987,11 +983,11 @@ void DeparturesWindow<Twaypoint>::DrawDeparturesListItems(const Rect &r) const
/* RTL languages can be handled in the language file, e.g. by having the following: */
/* STR_DEPARTURES_CALLING_AT_STATION :{STATION}, {RAW_STRING} */
/* STR_DEPARTURES_CALLING_AT_LAST_STATION :{STATION} & {RAW_STRING}*/
char buffer[512], scratch[512];
std::string buffer;
if (d->calling_at.size() != 0) {
SetDParam(0, (d->calling_at[0]).station);
GetString(scratch, STR_DEPARTURES_CALLING_AT_FIRST_STATION, lastof(scratch));
std::string calling_at_buffer = GetString(STR_DEPARTURES_CALLING_AT_FIRST_STATION);
StationID continues_to = INVALID_STATION;
@ -1008,29 +1004,25 @@ void DeparturesWindow<Twaypoint>::DrawDeparturesListItems(const Rect &r) const
continues_to = d->calling_at[d->calling_at.size() - 1].station;
break;
}
SetDParamStr(0, scratch);
SetDParamStr(0, std::move(calling_at_buffer));
SetDParam(1, s);
GetString(buffer, STR_DEPARTURES_CALLING_AT_STATION, lastof(buffer));
strncpy(scratch, buffer, sizeof(scratch));
calling_at_buffer = GetString(STR_DEPARTURES_CALLING_AT_STATION);
}
/* Finally, finish off with " and <station>". */
SetDParamStr(0, scratch);
SetDParamStr(0, std::move(calling_at_buffer));
SetDParam(1, d->calling_at[i].station);
GetString(buffer, STR_DEPARTURES_CALLING_AT_LAST_STATION, lastof(buffer));
strncpy(scratch, buffer, sizeof(scratch));
calling_at_buffer = GetString(STR_DEPARTURES_CALLING_AT_LAST_STATION);
}
SetDParamStr(1, scratch);
SetDParamStr(1, std::move(calling_at_buffer));
if (continues_to == INVALID_STATION) {
SetDParam(0, STR_DEPARTURES_CALLING_AT_LIST);
} else {
SetDParam(0, STR_DEPARTURES_CALLING_AT_LIST_SMART_TERMINUS);
SetDParam(2, continues_to);
}
GetString(buffer, size_prefix, lastof(buffer));
} else {
buffer[0] = 0;
buffer = GetString(size_prefix);
}
int list_width = (GetStringBoundingBox(buffer, _settings_client.gui.departure_larger_font ? FS_NORMAL : FS_SMALL)).width;

@ -169,29 +169,27 @@ uint GetTotalCapacityOfArticulatedParts(EngineID engine)
static StringID GetEngineInfoCapacityString(EngineID engine)
{
char buffer[1024];
CargoArray cap = GetCapacityOfArticulatedParts(engine);
if (cap.GetSum<uint>() == 0) {
/* no cargo at all */
auto tmp_params = MakeParameters(CT_INVALID, 0);
GetStringWithArgs(buffer, STR_JUST_CARGO, tmp_params, lastof(buffer));
_temp_special_strings[1] = GetStringWithArgs(STR_JUST_CARGO, tmp_params);
} else {
char *b = buffer;
std::string buffer;
for (uint i = 0; i < NUM_CARGO; i++) {
if (cap[i] == 0) continue;
if (b != buffer) {
if (!buffer.empty()) {
auto tmp_params = MakeParameters();
b = GetStringWithArgs(b, STR_COMMA_SEPARATOR, tmp_params, lastof(buffer));
GetStringWithArgs(StringBuilder(buffer), STR_COMMA_SEPARATOR, tmp_params);
}
auto tmp_params = MakeParameters(i, cap[i]);
b = GetStringWithArgs(b, STR_JUST_CARGO, tmp_params, lastof(buffer));
GetStringWithArgs(StringBuilder(buffer), STR_JUST_CARGO, tmp_params);
}
_temp_special_strings[1] = std::move(buffer);
}
_temp_special_strings[1].assign(buffer);
return SPECSTR_TEMP_START + 1;
}

@ -376,25 +376,24 @@ void ShowErrorMessage(StringID summary_msg, StringID detailed_msg, WarningLevel
if (wl != WL_INFO) {
/* Print message to console */
char buf[DRAW_STRING_BUFFER];
if (textref_stack_size > 0) StartTextRefStackUsage(textref_stack_grffile, textref_stack_size, textref_stack);
char *b = GetString(buf, summary_msg, lastof(buf));
std::string message = GetString(summary_msg);
if (detailed_msg != INVALID_STRING_ID) {
b += seprintf(b, lastof(buf), " ");
GetString(b, detailed_msg, lastof(buf));
message += ' ';
message += GetString(detailed_msg);
}
if (extra_msg != INVALID_STRING_ID) {
b += seprintf(b, lastof(buf), " ");
GetString(b, extra_msg, lastof(buf));
message += ' ';
message += GetString(extra_msg);
}
if (textref_stack_size > 0) StopTextRefStackUsage();
switch (wl) {
case WL_WARNING: IConsolePrint(CC_WARNING, buf); break;
default: IConsoleError(buf); break;
case WL_WARNING: IConsolePrint(CC_WARNING, message.c_str()); break;
default: IConsoleError(message.c_str()); break;
}
}

@ -1112,17 +1112,17 @@ void DeterminePaths(const char *exe, bool only_local_path)
/**
* Sanitizes a filename, i.e. removes all illegal characters from it.
* @param filename the "\0" terminated filename
* @param filename the filename
*/
void SanitizeFilename(char *filename)
void SanitizeFilename(std::string &filename)
{
for (; *filename != '\0'; filename++) {
switch (*filename) {
for (auto &c : filename) {
switch (c) {
/* The following characters are not allowed in filenames
* on at least one of the supported operating systems: */
case ':': case '\\': case '*': case '?': case '/':
case '<': case '>': case '|': case '"':
*filename = '_';
c = '_';
break;
}
}

@ -26,7 +26,7 @@ void FioRenameFile(const std::string &oldname, const std::string &newname);
const char *FiosGetScreenshotDir();
void SanitizeFilename(char *filename);
void SanitizeFilename(std::string &filename);
void AppendPathSeparator(std::string &buf);
void DeterminePaths(const char *exe, bool only_local_path);
std::unique_ptr<char[]> ReadFileToMem(const std::string &filename, size_t &lenp, size_t maxsize);

@ -308,8 +308,7 @@ public:
/** Generate a default save filename. */
void GenerateFileName()
{
GenerateDefaultSaveName(this->filename_editbox.text.buf, &this->filename_editbox.text.buf[this->filename_editbox.text.max_bytes - 1]);
this->filename_editbox.text.UpdateSize();
this->filename_editbox.text.Assign(GenerateDefaultSaveName());
}
SaveLoadWindow(WindowDesc *desc, AbstractFileType abstract_filetype, SaveLoadOperation fop)

@ -712,9 +712,7 @@ int DrawString(int left, int right, int top, std::string_view str, TextColour co
*/
int DrawString(int left, int right, int top, StringID str, TextColour colour, StringAlignment align, bool underline, FontSize fontsize)
{
char buffer[DRAW_STRING_BUFFER];
GetString(buffer, str, lastof(buffer));
return DrawString(left, right, top, buffer, colour, align, underline, fontsize);
return DrawString(left, right, top, GetString(str), colour, align, underline, fontsize);
}
/**
@ -738,9 +736,7 @@ int GetStringHeight(std::string_view str, int maxw, FontSize fontsize)
*/
int GetStringHeight(StringID str, int maxw)
{
char buffer[DRAW_STRING_BUFFER];
GetString(buffer, str, lastof(buffer));
return GetStringHeight(buffer, maxw);
return GetStringHeight(GetString(str), maxw);
}
/**
@ -751,10 +747,7 @@ int GetStringHeight(StringID str, int maxw)
*/
int GetStringLineCount(StringID str, int maxw)
{
char buffer[DRAW_STRING_BUFFER];
GetString(buffer, str, lastof(buffer));
Layouter layout(buffer, maxw);
Layouter layout(GetString(str), maxw);
return (uint)layout.size();
}
@ -862,9 +855,7 @@ int DrawStringMultiLine(int left, int right, int top, int bottom, std::string_vi
*/
int DrawStringMultiLine(int left, int right, int top, int bottom, StringID str, TextColour colour, StringAlignment align, bool underline, FontSize fontsize)
{
char buffer[DRAW_STRING_BUFFER];
GetString(buffer, str, lastof(buffer));
return DrawStringMultiLine(left, right, top, bottom, buffer, colour, align, underline, fontsize);
return DrawStringMultiLine(left, right, top, bottom, GetString(str), colour, align, underline, fontsize);
}
/**
@ -891,10 +882,7 @@ Dimension GetStringBoundingBox(std::string_view str, FontSize start_fontsize)
*/
Dimension GetStringBoundingBox(StringID strid, FontSize start_fontsize)
{
char buffer[DRAW_STRING_BUFFER];
GetString(buffer, strid, lastof(buffer));
return GetStringBoundingBox(buffer, start_fontsize);
return GetStringBoundingBox(GetString(strid), start_fontsize);
}
/**

@ -97,9 +97,6 @@ enum AdjustGUIZoomMode {
};
bool AdjustGUIZoom(AdjustGUIZoomMode mode);
/** Size of the buffer used for drawing strings. */
static const int DRAW_STRING_BUFFER = 2048;
void RedrawScreenRect(int left, int top, int right, int bottom);
Dimension GetSpriteSize(SpriteID sprid, Point *offset = nullptr, ZoomLevel zoom = ZOOM_LVL_GUI);

@ -787,20 +787,20 @@ std::string GenerateAutoNameForVehicleGroup(const Vehicle *v)
CargoTypes cargoes = GetVehicleCargoList(v);
char group_name[512];
StringID str;
if (town_from == town_to || town_to == nullptr) {
SetDParam(0, town_from->index);
SetDParam(1, (cargoes != 0) ? STR_VEHICLE_AUTO_GROUP_CARGO_LIST : STR_EMPTY);
SetDParam(2, cargoes);
GetString(group_name, STR_VEHICLE_AUTO_GROUP_LOCAL_ROUTE, lastof(group_name));
str = STR_VEHICLE_AUTO_GROUP_LOCAL_ROUTE;
} else {
SetDParam(0, town_from->index);
SetDParam(1, town_to->index);
SetDParam(2, (cargoes != 0) ? STR_VEHICLE_AUTO_GROUP_CARGO_LIST : STR_EMPTY);
SetDParam(3, cargoes);
GetString(group_name, STR_VEHICLE_AUTO_GROUP_ROUTE, lastof(group_name));
str = STR_VEHICLE_AUTO_GROUP_ROUTE;
}
return std::string(group_name);
return GetString(str);
}
/**

@ -2596,10 +2596,8 @@ void Industry::RecomputeProductionMultipliers()
void Industry::FillCachedName() const
{
char buf[256];
auto tmp_params = MakeParameters(this->index);
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()

@ -91,7 +91,7 @@ enum CargoSuffixDisplay {
/** Transfer storage of cargo suffix information. */
struct CargoSuffix {
CargoSuffixDisplay display; ///< How to display the cargo and text.
char text[512]; ///< Cargo suffix text.
std::string text; ///< Cargo suffix text.
};
extern void GenerateIndustries();
@ -108,19 +108,19 @@ static void ShowIndustryCargoesWindow(IndustryType id);
*/
static void GetCargoSuffix(uint cargo, CargoSuffixType cst, const Industry *ind, IndustryType ind_type, const IndustrySpec *indspec, CargoSuffix &suffix)
{
suffix.text[0] = '\0';
suffix.text.clear();
suffix.display = CSD_CARGO_AMOUNT;
if (HasBit(indspec->callback_mask, CBM_IND_CARGO_SUFFIX)) {
TileIndex t = (cst != CST_FUND) ? ind->location.tile : INVALID_TILE;
uint16 callback = GetIndustryCallback(CBID_INDUSTRY_CARGO_SUFFIX, 0, (cst << 8) | cargo, const_cast<Industry *>(ind), ind_type, t);
uint16_t callback = GetIndustryCallback(CBID_INDUSTRY_CARGO_SUFFIX, 0, (cst << 8) | cargo, const_cast<Industry *>(ind), ind_type, t);
if (callback == CALLBACK_FAILED) return;
if (indspec->grf_prop.grffile->grf_version < 8) {
if (GB(callback, 0, 8) == 0xFF) return;
if (callback < 0x400) {
StartTextRefStackUsage(indspec->grf_prop.grffile, 6);
GetString(suffix.text, GetGRFStringID(indspec->grf_prop.grffile->grfid, 0xD000 + callback), lastof(suffix.text));
suffix.text = GetString(GetGRFStringID(indspec->grf_prop.grffile->grfid, 0xD000 + callback));
StopTextRefStackUsage();
suffix.display = CSD_CARGO_AMOUNT_TEXT;
return;
@ -136,14 +136,14 @@ static void GetCargoSuffix(uint cargo, CargoSuffixType cst, const Industry *ind,
}
if (callback < 0x400) {
StartTextRefStackUsage(indspec->grf_prop.grffile, 6);
GetString(suffix.text, GetGRFStringID(indspec->grf_prop.grffile->grfid, 0xD000 + callback), lastof(suffix.text));
suffix.text = GetString(GetGRFStringID(indspec->grf_prop.grffile->grfid, 0xD000 + callback));
StopTextRefStackUsage();
suffix.display = CSD_CARGO_AMOUNT_TEXT;
return;
}
if (callback >= 0x800 && callback < 0xC00) {
StartTextRefStackUsage(indspec->grf_prop.grffile, 6);
GetString(suffix.text, GetGRFStringID(indspec->grf_prop.grffile->grfid, 0xD000 - 0x800 + callback), lastof(suffix.text));
suffix.text = GetString(GetGRFStringID(indspec->grf_prop.grffile->grfid, 0xD000 - 0x800 + callback));
StopTextRefStackUsage();
suffix.display = CSD_CARGO_TEXT;
return;
@ -210,35 +210,26 @@ static inline void GetAllCargoSuffixes(CargoSuffixInOut use_input, CargoSuffixTy
std::array<IndustryType, NUM_INDUSTRYTYPES> _sorted_industry_types; ///< Industry types sorted by name.
/** Sort industry types by their name. */
static bool IndustryTypeNameSorter(const IndustryType &a, const IndustryType &b)
{
static char industry_name[2][64];
const IndustrySpec *indsp1 = GetIndustrySpec(a);
GetString(industry_name[0], indsp1->name, lastof(industry_name[0]));
const IndustrySpec *indsp2 = GetIndustrySpec(b);
GetString(industry_name[1], indsp2->name, lastof(industry_name[1]));
int r = StrNaturalCompare(industry_name[0], industry_name[1]); // Sort by name (natural sorting).
/* If the names are equal, sort by industry type. */
return (r != 0) ? r < 0 : (a < b);
}
/**
* Initialize the list of sorted industry types.
*/
void SortIndustryTypes()
{
std::string industry_spec_names[NUM_INDUSTRYTYPES]{};
/* Add each industry type to the list. */
for (IndustryType i = 0; i < NUM_INDUSTRYTYPES; i++) {
_sorted_industry_types[i] = i;
industry_spec_names[i] = GetString(GetIndustrySpec(i)->name);
}
/* Sort industry types by name. */
std::sort(_sorted_industry_types.begin(), _sorted_industry_types.end(), IndustryTypeNameSorter);
std::sort(_sorted_industry_types.begin(), _sorted_industry_types.end(), [&](const IndustryType &a, const IndustryType &b) {
int r = StrNaturalCompare(industry_spec_names[a], industry_spec_names[b]); // Sort by name (natural sorting).
/* If the names are equal, sort by industry type. */
return (r != 0) ? r < 0 : (a < b);
});
}
/**
@ -371,33 +362,33 @@ class BuildIndustryWindow : public Window {
std::string MakeCargoListString(const CargoID *cargolist, const CargoSuffix *cargo_suffix, size_t cargolistlen, StringID prefixstr) const
{
std::string cargostring;
char buf[1024];
int numcargo = 0;
int firstcargo = -1;
size_t firstcargo = cargolistlen;
for (size_t j = 0; j < cargolistlen; j++) {
size_t j = 0;
for (; j < cargolistlen; j++) {
if (cargolist[j] == CT_INVALID) continue;
numcargo++;
if (firstcargo < 0) {
firstcargo = (int)j;
continue;
if (firstcargo == cargolistlen) {
firstcargo = j;
j++;
break;
}
SetDParam(0, CargoSpec::Get(cargolist[j])->name);
SetDParamStr(1, cargo_suffix[j].text);
GetString(buf, STR_INDUSTRY_VIEW_CARGO_LIST_EXTENSION, lastof(buf));
cargostring += buf;
}
if (numcargo > 0) {
if (firstcargo < cargolistlen) {
SetDParam(0, CargoSpec::Get(cargolist[firstcargo])->name);
SetDParamStr(1, cargo_suffix[firstcargo].text);
GetString(buf, prefixstr, lastof(buf));
cargostring = std::string(buf) + cargostring;
GetString(StringBuilder(cargostring), prefixstr);
} else {
SetDParam(0, STR_JUST_NOTHING);
SetDParamStr(1, "");
GetString(buf, prefixstr, lastof(buf));
cargostring = std::string(buf);
GetString(StringBuilder(cargostring), prefixstr);
}
for (; j < cargolistlen; j++) {
if (cargolist[j] == CT_INVALID) continue;
SetDParam(0, CargoSpec::Get(cargolist[j])->name);
SetDParamStr(1, cargo_suffix[j].text);
GetString(StringBuilder(cargostring), STR_INDUSTRY_VIEW_CARGO_LIST_EXTENSION);
}
return cargostring;
@ -1563,7 +1554,7 @@ protected:
for (byte j = 0; j < lengthof(i->produced_cargo); j++) {
if (i->produced_cargo[j] == CT_INVALID) continue;
cargos.push_back({ i->produced_cargo[j], i->last_month_production[j], cargo_suffix[j].text, ToPercent8(i->last_month_pct_transported[j]) });
cargos.push_back({ i->produced_cargo[j], i->last_month_production[j], cargo_suffix[j].text.c_str(), ToPercent8(i->last_month_pct_transported[j]) });
}
switch (static_cast<IndustryDirectoryWindow::SorterType>(this->industries.SortType())) {

@ -518,8 +518,8 @@ bool LinkGraphOverlay::ShowTooltip(Point pt, TooltipCloseCondition close_cond)
pt.y - 2 <= std::max(pta.y, ptb.y) &&
check_distance()) {
char buf[2048];
char *buf_end = buf;
std::string buf;
StringBuilder builder(buf);
buf[0] = 0;
auto add_travel_time = [&](uint32 time) {
@ -527,10 +527,10 @@ bool LinkGraphOverlay::ShowTooltip(Point pt, TooltipCloseCondition close_cond)
if (_settings_time.time_in_minutes) {
SetDParam(0, STR_TIMETABLE_MINUTES);
SetDParam(1, time / _settings_time.ticks_per_minute);
buf_end = GetString(buf_end, STR_LINKGRAPH_STATS_TOOLTIP_TIME_EXTENSION_GENERAL, lastof(buf));
GetString(builder, STR_LINKGRAPH_STATS_TOOLTIP_TIME_EXTENSION_GENERAL);
} else {
SetDParam(0, time / (DAY_TICKS * _settings_game.economy.day_length_factor));
buf_end = GetString(buf_end, STR_LINKGRAPH_STATS_TOOLTIP_TIME_EXTENSION, lastof(buf));
GetString(builder, STR_LINKGRAPH_STATS_TOOLTIP_TIME_EXTENSION);
}
}
};
@ -539,15 +539,15 @@ bool LinkGraphOverlay::ShowTooltip(Point pt, TooltipCloseCondition close_cond)
if (info_link.usage < info_link.planned) {
SetDParam(0, info_link.cargo);
SetDParam(1, info_link.usage);
buf_end = GetString(buf_end, STR_LINKGRAPH_STATS_TOOLTIP_USAGE, lastof(buf));
GetString(builder, STR_LINKGRAPH_STATS_TOOLTIP_USAGE);
} else if (info_link.planned < info_link.usage) {
SetDParam(0, info_link.cargo);
SetDParam(1, info_link.planned);
buf_end = GetString(buf_end, STR_LINKGRAPH_STATS_TOOLTIP_PLANNED, lastof(buf));
GetString(builder, STR_LINKGRAPH_STATS_TOOLTIP_PLANNED);
}
SetDParam(0, info_link.cargo);
SetDParam(1, info_link.capacity);
buf_end = GetString(buf_end, STR_LINKGRAPH_STATS_TOOLTIP_CAPACITY, lastof(buf));
GetString(builder, STR_LINKGRAPH_STATS_TOOLTIP_CAPACITY);
add_travel_time(info_link.time);
};
@ -561,11 +561,11 @@ bool LinkGraphOverlay::ShowTooltip(Point pt, TooltipCloseCondition close_cond)
if (j->from_id == i->to_id && j->to_id == i->from_id) {
back_time = j->prop.time;
if (j->prop.Usage() > 0 || (_ctrl_pressed && j->prop.capacity > 0)) {
if (_ctrl_pressed) buf_end = strecat(buf_end, "\n", lastof(buf));
if (_ctrl_pressed) builder += '\n';
SetDParam(0, j->prop.cargo);
SetDParam(1, j->prop.Usage());
SetDParam(2, j->prop.Usage() * 100 / (j->prop.capacity + 1));
buf_end = GetString(buf_end, STR_LINKGRAPH_STATS_TOOLTIP_RETURN_EXTENSION, lastof(buf));
GetString(builder, STR_LINKGRAPH_STATS_TOOLTIP_RETURN_EXTENSION);
if (_ctrl_pressed) {
add_extra_info(j->prop);
}
@ -580,14 +580,14 @@ bool LinkGraphOverlay::ShowTooltip(Point pt, TooltipCloseCondition close_cond)
if (_ctrl_pressed) {
/* Add distance information */
buf_end = strecat(buf_end, "\n\n", lastof(buf));
builder += "\n\n";
TileIndex t0 = Station::Get(i->from_id)->xy;
TileIndex t1 = Station::Get(i->to_id)->xy;
uint dx = Delta(TileX(t0), TileX(t1));
uint dy = Delta(TileY(t0), TileY(t1));
SetDParam(0, DistanceManhattan(t0, t1));
SetDParam(1, IntSqrt64(((uint64)dx * (uint64)dx) + ((uint64)dy * (uint64)dy))); // Avoid overflow in DistanceSquare
buf_end = GetString(buf_end, STR_LINKGRAPH_STATS_TOOLTIP_DISTANCE, lastof(buf));
GetString(builder, STR_LINKGRAPH_STATS_TOOLTIP_DISTANCE);
}
SetDParam(0, link.cargo);
@ -595,7 +595,7 @@ bool LinkGraphOverlay::ShowTooltip(Point pt, TooltipCloseCondition close_cond)
SetDParam(2, i->from_id);
SetDParam(3, i->to_id);
SetDParam(4, link.Usage() * 100 / (link.capacity + 1));
SetDParamStr(5, buf);
SetDParamStr(5, std::move(buf));
GuiShowTooltips(this->window, STR_LINKGRAPH_STATS_TOOLTIP, close_cond);
return true;
}

@ -53,9 +53,8 @@ void CcGiveMoney(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2
if (result.Failed() || !_settings_game.economy.give_money || !_networking) return;
/* Inform the company of the action of one of its clients (controllers). */
char msg[64];
SetDParam(0, p1);
GetString(msg, STR_COMPANY_NAME, lastof(msg));
std::string msg = GetString(STR_COMPANY_NAME);
/*
* bits 31-16: source company

@ -709,7 +709,7 @@ struct TooltipsWindow : public Window
StringID string_id; ///< String to display as tooltip.
std::vector<StringParameterBackup> params; ///< The string parameters.
TooltipCloseCondition close_cond; ///< Condition for closing the window.
char buffer[DRAW_STRING_BUFFER]; ///< Text to draw
std::string buffer; ///< Text to draw
int viewport_virtual_left; ///< Owner viewport state: left
int viewport_virtual_top; ///< Owner viewport state: top
bool delete_next_mouse_loop; ///< Delete window on the next mouse loop
@ -721,7 +721,7 @@ struct TooltipsWindow : public Window
CopyOutDParam(this->params, paramcount);
this->close_cond = close_tooltip;
this->delete_next_mouse_loop = false;
if (this->params.size() == 0) GetString(this->buffer, str, lastof(this->buffer)); // Get the text while params are available
if (this->params.size() == 0) this->buffer = GetString(str); // Get the text while params are available
if (close_tooltip == TCC_HOVER_VIEWPORT) {
this->viewport_virtual_left = parent->viewport->virtual_left;
this->viewport_virtual_top = parent->viewport->virtual_top;
@ -1025,19 +1025,7 @@ struct QueryStringWindow : public Window
QueryStringWindow(StringID str, StringID caption, uint max_bytes, uint max_chars, WindowDesc *desc, Window *parent, CharSetFilter afilter, QueryStringFlags flags) :
Window(desc), editbox(max_bytes, max_chars)
{
assert(parent != nullptr);
char *last_of = &this->editbox.text.buf[this->editbox.text.max_bytes - 1];
GetString(this->editbox.text.buf, str, last_of);
StrMakeValidInPlace(this->editbox.text.buf, last_of, SVS_NONE);
/* Make sure the name isn't too long for the text buffer in the number of
* characters (not bytes). max_chars also counts the '\0' characters. */
while (Utf8StringLength(this->editbox.text.buf) + 1 > this->editbox.text.max_chars) {
*Utf8PrevChar(this->editbox.text.buf + strlen(this->editbox.text.buf)) = '\0';
}
this->editbox.text.UpdateSize();
this->editbox.text.Assign(str);
if ((flags & QSF_ACCEPT_UNCHANGED) == 0) this->editbox.orig = this->editbox.text.buf;

@ -265,7 +265,6 @@ void NetworkTextMessage(NetworkAction action, TextColour colour, bool self_send,
{
SetDParamStr(0, name);
char message_src[256];
StringID strid;
switch (action) {
case NETWORK_ACTION_SERVER_MESSAGE:
@ -294,8 +293,7 @@ void NetworkTextMessage(NetworkAction action, TextColour colour, bool self_send,
case NETWORK_ACTION_GIVE_MONEY: {
SetDParam(1, data.auxdata >> 16);
GetString(message_src, STR_NETWORK_MESSAGE_MONEY_GIVE_SRC_DESCRIPTION, lastof(message_src));
SetDParamStr(0, message_src);
SetDParamStr(0, GetString(STR_NETWORK_MESSAGE_MONEY_GIVE_SRC_DESCRIPTION));
extern byte GetCurrentGrfLangID();
byte lang_id = GetCurrentGrfLangID();
@ -317,7 +315,8 @@ void NetworkTextMessage(NetworkAction action, TextColour colour, bool self_send,
default: strid = STR_NETWORK_CHAT_ALL; break;
}
char message[1024];
std::string message;
StringBuilder builder(message);
SetDParamStr(1, str);
SetDParam(2, data.data);
SetDParamStr(3, data_str);
@ -326,12 +325,12 @@ void NetworkTextMessage(NetworkAction action, TextColour colour, bool self_send,
* right-to-left characters depending on the context. As the next text might be an user's name, the
* user name's characters will influence the direction of the "***" instead of the language setting
* of the game. Manually set the direction of the "***" by inserting a text-direction marker. */
char *msg_ptr = message + Utf8Encode(message, _current_text_dir == TD_LTR ? CHAR_TD_LRM : CHAR_TD_RLM);
GetString(msg_ptr, strid, lastof(message));
builder.Utf8Encode(_current_text_dir == TD_LTR ? CHAR_TD_LRM : CHAR_TD_RLM);
GetString(builder, strid);
DEBUG(desync, 1, "msg: %s; %s", debug_date_dumper().HexDate(), message);
IConsolePrintF(colour, "%s", message);
NetworkAddChatMessage(colour, _settings_client.gui.network_chat_timeout, message);
DEBUG(desync, 1, "msg: %s; %s", debug_date_dumper().HexDate(), message.c_str());
IConsolePrintF(colour, "%s", message.c_str());
NetworkAddChatMessage(colour, _settings_client.gui.network_chat_timeout, message.c_str());
}
/* Calculate the frame-lag of a client */

@ -33,10 +33,6 @@
#include "../safeguards.h"
/** The draw buffer must be able to contain the chat message, client name and the "[All]" message,
* some spaces and possible translations of [All] to other languages. */
static_assert((int)DRAW_STRING_BUFFER >= (int)NETWORK_CHAT_LENGTH + NETWORK_NAME_LENGTH + 40);
/** Spacing between chat lines. */
static const uint NETWORK_CHAT_LINE_SPACING = 3;

@ -745,8 +745,7 @@ public:
if (!this->selected->dependencies.empty()) {
/* List dependencies */
char buf[DRAW_STRING_BUFFER] = "";
char *p = buf;
std::string buf;
for (auto &cid : this->selected->dependencies) {
/* Try to find the dependency */
ConstContentIterator iter = _network_content_client.Begin();
@ -754,22 +753,23 @@ public:
const ContentInfo *ci = *iter;
if (ci->id != cid) continue;
p += seprintf(p, lastof(buf), p == buf ? "%s" : ", %s", (*iter)->name.c_str());
if (!buf.empty()) buf += ", ";
buf += (*iter)->name;
break;
}
}
SetDParamStr(0, buf);
SetDParamStr(0, std::move(buf));
tr.top = DrawStringMultiLine(tr, STR_CONTENT_DETAIL_DEPENDENCIES);
}
if (!this->selected->tags.empty()) {
/* List all tags */
char buf[DRAW_STRING_BUFFER] = "";
char *p = buf;
std::string buf;
for (auto &tag : this->selected->tags) {
p += seprintf(p, lastof(buf), p == buf ? "%s" : ", %s", tag.c_str());
if (!buf.empty()) buf += ", ";
buf += tag;
}
SetDParamStr(0, buf);
SetDParamStr(0, std::move(buf));
tr.top = DrawStringMultiLine(tr, STR_CONTENT_DETAIL_TAGS);
}
@ -778,15 +778,15 @@ public:
ConstContentVector tree;
_network_content_client.ReverseLookupTreeDependency(tree, this->selected);
char buf[DRAW_STRING_BUFFER] = "";
char *p = buf;
std::string buf;
for (const ContentInfo *ci : tree) {
if (ci == this->selected || ci->state != ContentInfo::SELECTED) continue;
p += seprintf(p, lastof(buf), buf == p ? "%s" : ", %s", ci->name.c_str());
if (!buf.empty()) buf += ", ";
buf += ci->name;
}
if (p != buf) {
SetDParamStr(0, buf);
if (!buf.empty()) {
SetDParamStr(0, std::move(buf));
tr.top = DrawStringMultiLine(tr, STR_CONTENT_DETAIL_SELECTED_BECAUSE_OF);
}
}

@ -522,17 +522,14 @@ void ErrorUnknownCallbackResult(uint32 grfid, uint16 cbid, uint16 cb_res)
ShowErrorMessage(STR_NEWGRF_BUGGY, STR_NEWGRF_BUGGY_UNKNOWN_CALLBACK_RESULT, WL_CRITICAL);
}
/* debug output */
char buffer[512];
SetDParamStr(0, grfconfig->GetName());
GetString(buffer, STR_NEWGRF_BUGGY, lastof(buffer));
DEBUG(grf, 0, "%s", buffer + 3);
std::string buffer = GetString(STR_NEWGRF_BUGGY);
DEBUG(grf, 0, "%s", strip_leading_colours(buffer));
SetDParam(1, cbid);
SetDParam(2, cb_res);
GetString(buffer, STR_NEWGRF_BUGGY_UNKNOWN_CALLBACK_RESULT, lastof(buffer));
DEBUG(grf, 0, "%s", buffer + 3);
buffer = GetString(STR_NEWGRF_BUGGY_UNKNOWN_CALLBACK_RESULT);
DEBUG(grf, 0, "%s", strip_leading_colours(buffer));
}
/**

@ -542,9 +542,8 @@ struct NewGRFInspectWindow : Window {
if (this->log_console) {
GetFeatureHelper(this->window_number)->SetStringParameters(this->GetFeatureIndex());
char buf[1024];
GetString(buf, STR_NEWGRF_INSPECT_CAPTION, lastof(buf));
DEBUG(misc, 0, "*** %s ***", buf + Utf8EncodedCharLen(buf[0]));
std::string buf = GetString(STR_NEWGRF_INSPECT_CAPTION);
if (!buf.empty()) DEBUG(misc, 0, "*** %s ***", strip_leading_colours(buf));
}
uint index = this->GetFeatureIndex();
@ -807,9 +806,7 @@ struct NewGRFInspectWindow : Window {
NOT_REACHED();
}
char buffer[64];
GetString(buffer, string, lastof(buffer));
this->DrawString(r, i++, " %02x: %s (%s)", nip->prop, buffer, nip->name);
this->DrawString(r, i++, " %02x: %s (%s)", nip->prop, GetString(string).c_str(), nip->name);
}
}

@ -896,13 +896,13 @@ void StopTextRefStackUsage()
/**
* FormatString for NewGRF specific "magic" string control codes
* @param scc the string control code that has been read
* @param buff the buffer we're writing to
* @param buffer the buffer we're writing to
* @param str the string that we need to write
* @param parameters the OpenTTD string formatting parameters
* @param modify_parameters When true, modify the OpenTTD string formatting parameters.
* @return the string control code to "execute" now
*/
uint RemapNewGRFStringControlCode(uint scc, char *buf_start, char **buff, const char **str, StringParameters &parameters, bool modify_parameters)
uint RemapNewGRFStringControlCode(uint scc, std::string *buffer, const char **str, StringParameters &parameters, bool modify_parameters)
{
auto too_many_newgrf_params = [&]() {
const char *buffer = *str;
@ -1011,7 +1011,7 @@ uint RemapNewGRFStringControlCode(uint scc, char *buf_start, char **buff, const
case SCC_NEWGRF_ROTATE_TOP_4_WORDS: _newgrf_textrefstack.RotateTop4Words(); break;
case SCC_NEWGRF_PUSH_WORD: _newgrf_textrefstack.PushWord(Utf8Consume(str)); break;
case SCC_NEWGRF_UNPRINT: *buff = std::max(*buff - Utf8Consume(str), buf_start); break;
case SCC_NEWGRF_UNPRINT: if (buffer != nullptr) buffer->resize(buffer->size() - std::min<size_t>(buffer->size(), Utf8Consume(str))); break;
case SCC_NEWGRF_PRINT_WORD_CARGO_LONG:
case SCC_NEWGRF_PRINT_WORD_CARGO_SHORT:

@ -54,7 +54,7 @@ struct TextRefStack *CreateTextRefStackBackup();
void RestoreTextRefStackBackup(struct TextRefStack *backup);
class StringParameters;
uint RemapNewGRFStringControlCode(uint scc, char *buf_start, char **buff, const char **str, StringParameters &parameters, bool modify_parameters);
uint RemapNewGRFStringControlCode(uint scc, std::string *buffer, const char **str, StringParameters &parameters, bool modify_parameters);
/** Mapping of language data between a NewGRF and OpenTTD. */
struct LanguageMap {

@ -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"
@ -24,14 +25,14 @@
static std::vector<GRFTownName> _grf_townnames;
static std::vector<StringID> _grf_townname_names;
GRFTownName *GetGRFTownName(uint32 grfid)
GRFTownName *GetGRFTownName(uint32_t grfid)
{
auto found = std::find_if(std::begin(_grf_townnames), std::end(_grf_townnames), [&grfid](const GRFTownName &t){ return t.grfid == grfid; });
if (found != std::end(_grf_townnames)) return &*found;
return nullptr;
}
GRFTownName *AddGRFTownName(uint32 grfid)
GRFTownName *AddGRFTownName(uint32_t grfid)
{
GRFTownName *t = GetGRFTownName(grfid);
if (t == nullptr) {
@ -41,41 +42,38 @@ GRFTownName *AddGRFTownName(uint32 grfid)
return t;
}
void DelGRFTownName(uint32 grfid)
void DelGRFTownName(uint32_t 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_t seed, byte id)
{
assert(t != nullptr);
for (const auto &partlist : t->partlists[id]) {
byte count = partlist.bitcount;
uint16 maxprob = partlist.maxprob;
uint32 r = (GB(seed, partlist.bitstart, count) * maxprob) >> count;
uint16_t maxprob = partlist.maxprob;
uint32_t r = (GB(seed, partlist.bitstart, count) * maxprob) >> count;
for (const auto &part : partlist.parts) {
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_t grfid, uint16_t gen, uint32_t 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;
}
@ -95,7 +93,7 @@ const std::vector<StringID> &GetGRFTownNameList()
return _grf_townname_names;
}
StringID GetGRFTownNameName(uint16 gen)
StringID GetGRFTownNameName(uint16_t gen)
{
return gen < _grf_townname_names.size() ? _grf_townname_names[gen] : STR_UNDEFINED;
}
@ -105,21 +103,21 @@ void CleanUpGRFTownNames()
_grf_townnames.clear();
}
uint32 GetGRFTownNameId(uint16 gen)
uint32_t GetGRFTownNameId(uint16_t gen)
{
for (const auto &t : _grf_townnames) {
if (gen < t.styles.size()) return t.grfid;
gen -= static_cast<uint16>(t.styles.size());
gen -= static_cast<uint16_t>(t.styles.size());
}
/* Fallback to no NewGRF */
return 0;
}
uint16 GetGRFTownNameType(uint16 gen)
uint16_t GetGRFTownNameType(uint16_t gen)
{
for (const auto &t : _grf_townnames) {
if (gen < t.styles.size()) return gen;
gen -= static_cast<uint16>(t.styles.size());
gen -= static_cast<uint16_t>(t.styles.size());
}
/* Fallback to english original */
return SPECSTR_TOWNNAME_ENGLISH;

@ -25,7 +25,7 @@ struct NamePart {
struct NamePartList {
byte bitstart; ///< Start of random seed bits to use.
byte bitcount; ///< Number of bits of random seed to use.
uint16 maxprob; ///< Total probability of all parts.
uint16_t maxprob; ///< Total probability of all parts.
std::vector<NamePart> parts; ///< List of parts to choose from.
};
@ -39,19 +39,18 @@ struct TownNameStyle {
struct GRFTownName {
static const uint MAX_LISTS = 128; ///< Maximum number of town name lists that can be defined per GRF.
uint32 grfid; ///< GRF ID of NewGRF.
uint32_t grfid; ///< GRF ID of NewGRF.
std::vector<TownNameStyle> styles; ///< Style names defined by the Town Name NewGRF.
std::vector<NamePartList> partlists[MAX_LISTS]; ///< Lists of town name parts.
};
GRFTownName *AddGRFTownName(uint32 grfid);
GRFTownName *GetGRFTownName(uint32 grfid);
void DelGRFTownName(uint32 grfid);
GRFTownName *AddGRFTownName(uint32_t grfid);
GRFTownName *GetGRFTownName(uint32_t grfid);
void DelGRFTownName(uint32_t 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);
uint32_t GetGRFTownNameId(uint16_t gen);
uint16_t GetGRFTownNameType(uint16_t gen);
StringID GetGRFTownNameName(uint16_t gen);
const std::vector<StringID> &GetGRFTownNameList();

@ -870,10 +870,11 @@ int openttd_main(int argc, char *argv[])
fprintf(stderr, "Failed to open savegame\n");
if (_load_check_data.HasErrors()) {
InitializeLanguagePacks(); // A language pack is needed for GetString()
char buf[256];
std::string buf;
SetDParamStr(0, _load_check_data.error_msg);
GetString(buf, _load_check_data.error, lastof(buf));
fprintf(stderr, "%s\n", buf);
GetString(StringBuilder(buf), _load_check_data.error);
buf += '\n';
fputs(buf.c_str(), stderr);
}
return ret;
}
@ -1508,7 +1509,7 @@ void WriteVehicleInfo(char *&p, const char *last, const Vehicle *u, const Vehicl
p += seprintf(p, last, ": type %i, vehicle %i (%i), company %i, unit number %i, wagon %i, engine: ",
(int)u->type, u->index, v->index, (int)u->owner, v->unitnumber, length);
SetDParam(0, u->engine_type);
p = GetString(p, STR_ENGINE_NAME, last);
p = strecpy(p, GetString(STR_ENGINE_NAME).c_str(), last, true);
uint32 grfid = u->GetGRFID();
if (grfid) {
p += seprintf(p, last, ", GRF: %08X", BSWAP32(grfid));

@ -1063,7 +1063,6 @@ void DrawOrderString(const Vehicle *v, const Order *order, int order_index, int
SetDParam(3, STR_ORDER_CONDITIONAL_COMPARATOR_EQUALS + order->GetConditionComparator());
SetDParam(4, order->GetXData());
} else if (ocv == OCV_CARGO_WAITING_AMOUNT) {
char buf[512] = "";
ArrayStringParameters<10> tmp_params;
StringID substr;
@ -1089,8 +1088,7 @@ void DrawOrderString(const Vehicle *v, const Order *order, int order_index, int
tmp_params.SetParam(7, order->GetConditionValue());
tmp_params.SetParam(8, GB(order->GetXData(), 0, 16));
}
char *end = GetStringWithArgs(buf, substr, tmp_params, lastof(buf));
_temp_special_strings[0].assign(buf, end);
_temp_special_strings[0] = GetStringWithArgs(substr, tmp_params);
SetDParam(0, SPECSTR_TEMP_START);
} else if (ocv == OCV_COUNTER_VALUE) {
if (TraceRestrictCounter::IsValidID(GB(order->GetXData(), 16, 16))) {
@ -1117,10 +1115,8 @@ void DrawOrderString(const Vehicle *v, const Order *order, int order_index, int
if (GB(order->GetXData(), 0, 16) != UINT16_MAX) {
const DispatchSchedule &ds = v->orders->GetDispatchScheduleByIndex(GB(order->GetXData(), 0, 16));
if (ds.ScheduleName().empty()) {
char buf[256];
auto tmp_params = MakeParameters(GB(order->GetXData(), 0, 16) + 1);
char *end = GetStringWithArgs(buf, STR_TIMETABLE_ASSIGN_SCHEDULE_ID, tmp_params, lastof(buf));
_temp_special_strings[0].assign(buf, end);
_temp_special_strings[0] = GetStringWithArgs(STR_TIMETABLE_ASSIGN_SCHEDULE_ID, tmp_params);
} else {
_temp_special_strings[0] = ds.ScheduleName();
}

@ -140,7 +140,7 @@ static const StringID _program_sigstate[] = {
};
/** Get the string for a condition */
static char *GetConditionString(SignalCondition *cond, char *buf, char *buflast)
static std::string GetConditionString(SignalCondition *cond)
{
StringID string = INVALID_STRING_ID;
if (cond->ConditionCode() == PSC_SLOT_OCC || cond->ConditionCode() == PSC_SLOT_OCC_REM) {
@ -184,7 +184,7 @@ static char *GetConditionString(SignalCondition *cond, char *buf, char *buflast)
}
}
}
return GetString(buf, string, buflast);
return GetString(string);
}
/**
@ -200,8 +200,6 @@ static void DrawInstructionString(SignalInstruction *instruction, int y, bool se
{
StringID instruction_string = INVALID_STRING_ID;
char condstr[512];
switch (instruction->Opcode()) {
case PSO_FIRST:
instruction_string = STR_PROGSIG_FIRST;
@ -213,8 +211,7 @@ static void DrawInstructionString(SignalInstruction *instruction, int y, bool se
case PSO_IF: {
SignalIf *if_ins = static_cast<SignalIf*>(instruction);
GetConditionString(if_ins->condition, condstr, lastof(condstr));
SetDParamStr(0, condstr);
SetDParamStr(0, GetConditionString(if_ins->condition));
instruction_string = STR_PROGSIG_IF;
break;
}

@ -50,7 +50,7 @@ const char *scope_dumper::CompanyInfo(int company_id)
const char *last = lastof(this->buffer);
b += seprintf(b, last, "%d (", company_id);
SetDParam(0, company_id);
b = GetString(b, STR_COMPANY_NAME, last);
b = strecpy(b, GetString(STR_COMPANY_NAME).c_str(), last);
b += seprintf(b, last, ")");
return buffer;
}
@ -79,7 +79,7 @@ const char *scope_dumper::VehicleInfo(const Vehicle *v)
default:
SetDParam(0, v->index);
b = GetString(b, STR_VEHICLE_NAME, last);
b = strecpy(b, GetString(STR_VEHICLE_NAME).c_str(), last);
break;
}
if (v->type < VEH_COMPANY_END) {
@ -95,7 +95,7 @@ const char *scope_dumper::VehicleInfo(const Vehicle *v)
return this->buffer;
}
SetDParam(0, v->First()->index);
b = GetString(b, STR_VEHICLE_NAME, last);
b = strecpy(b, GetString(STR_VEHICLE_NAME).c_str(), last);
b += seprintf(b, last, ", ");
dump_flags(v->First());
b += seprintf(b, last, ")");
@ -116,7 +116,7 @@ const char *scope_dumper::StationInfo(const BaseStation *st)
const bool waypoint = Waypoint::IsExpected(st);
b += seprintf(b, last, "%s: %u: (", waypoint ? "waypoint" : "station", st->index);
SetDParam(0, st->index);
b = GetString(b, waypoint ? STR_WAYPOINT_NAME : STR_STATION_NAME, last);
b = strecpy(b, GetString(waypoint ? STR_WAYPOINT_NAME : STR_STATION_NAME).c_str(), last);
b += seprintf(b, last, ", c:%d, facil: ", (int) st->owner);
auto dump_facil = [&](char c, StationFacility flag) {
if (st->facilities & flag) b += seprintf(b, last, "%c", c);

@ -43,8 +43,8 @@ static const char * const HEIGHTMAP_NAME = "heightmap"; ///< Default filename
std::string _screenshot_format_name; ///< Extension of the current screenshot format (corresponds with #_cur_screenshot_format).
uint _num_screenshot_formats; ///< Number of available screenshot formats.
uint _cur_screenshot_format; ///< Index of the currently selected screenshot format in #_screenshot_formats.
static char _screenshot_name[128]; ///< Filename of the screenshot file.
char _full_screenshot_name[MAX_PATH]; ///< Pathname of the screenshot file.
static std::string _screenshot_name; ///< Filename of the screenshot file.
std::string _full_screenshot_path; ///< Pathname of the screenshot file.
uint _heightmap_highest_peak; ///< When saving a heightmap, this contains the highest peak on the map.
static const char *_screenshot_aux_text_key = nullptr;
@ -700,47 +700,47 @@ static void LargeWorldCallback(void *userdata, void *buf, uint y, uint pitch, ui
*/
static const char *MakeScreenshotName(const char *default_fn, const char *ext, bool crashlog = false)
{
bool generate = StrEmpty(_screenshot_name);
bool generate = _screenshot_name.empty();
if (generate) {
if (_game_mode == GM_EDITOR || _game_mode == GM_MENU || _local_company == COMPANY_SPECTATOR) {
strecpy(_screenshot_name, default_fn, lastof(_screenshot_name));
_screenshot_name = default_fn;
} else {
GenerateDefaultSaveName(_screenshot_name, lastof(_screenshot_name));
_screenshot_name = GenerateDefaultSaveName();
}
}
size_t len = strlen(_screenshot_name);
size_t len = _screenshot_name.size();
/* Handle user-specified filenames ending in %d or # with automatic numbering */
if (len >= 2 && _screenshot_name[len - 2] == '%' && _screenshot_name[len - 1] == 'd') {
generate = true;
len -= 2;
_screenshot_name[len] = '\0';
_screenshot_name.resize(len - 2);
} else if (len >= 1 && _screenshot_name[len - 1] == '#') {
generate = true;
len -= 1;
_screenshot_name[len] = '\0';
_screenshot_name.resize(len - 1);
}
len = _screenshot_name.size();
/* Add extension to screenshot file */
seprintf(&_screenshot_name[len], lastof(_screenshot_name), ".%s", ext);
_screenshot_name += '.';
_screenshot_name += ext;
const char *screenshot_dir = crashlog ? _personal_dir.c_str() : FiosGetScreenshotDir();
for (uint serial = 1;; serial++) {
if (seprintf(_full_screenshot_name, lastof(_full_screenshot_name), "%s%s", screenshot_dir, _screenshot_name) >= (int)lengthof(_full_screenshot_name)) {
/* We need more characters than MAX_PATH -> end with error */
_full_screenshot_name[0] = '\0';
break;
}
_full_screenshot_path = screenshot_dir;
_full_screenshot_path += _screenshot_name;
if (!generate) break; // allow overwriting of non-automatic filenames
if (!FileExists(_full_screenshot_name)) break;
if (!FileExists(_full_screenshot_path)) break;
/* If file exists try another one with same name, but just with a higher index */
seprintf(&_screenshot_name[len], lastof(_screenshot_name) - len, "#%u.%s", serial, ext);
_screenshot_name.erase(len);
_screenshot_name += stdstr_fmt("#%u.%s", serial, ext);
}
return _full_screenshot_name;
return _full_screenshot_path.c_str();
}
/** Make a screenshot of the current screen. */
@ -983,8 +983,7 @@ static bool RealMakeScreenshot(ScreenshotType t, std::string name, uint32 width,
SetScreenshotWindowHidden(false);
}
_screenshot_name[0] = '\0';
if (!name.empty()) strecpy(_screenshot_name, name.c_str(), lastof(_screenshot_name));
_screenshot_name = name;
bool ret;
switch (t) {
@ -1332,8 +1331,8 @@ static void IndustryScreenCallback(void *userdata, void *buf, uint y, uint pitch
*/
bool MakeMinimapWorldScreenshot(const char *name)
{
_screenshot_name[0] = '\0';
if (name != nullptr) strecpy(_screenshot_name, name, lastof(_screenshot_name));
_screenshot_name.clear();
if (name != nullptr) _screenshot_name.assign(name);
const ScreenshotFormat *sf = _screenshot_formats + _cur_screenshot_format;
return sf->proc(MakeScreenshotName(SCREENSHOT_NAME, sf->extension), MinimapScreenCallback, nullptr, MapSizeX(), MapSizeY(), 32, _cur_palette.palette);
@ -1344,8 +1343,8 @@ bool MakeMinimapWorldScreenshot(const char *name)
*/
bool MakeTopographyScreenshot(const char *name)
{
_screenshot_name[0] = '\0';
if (name != nullptr) strecpy(_screenshot_name, name, lastof(_screenshot_name));
_screenshot_name.clear();
if (name != nullptr) _screenshot_name.assign(name);
const ScreenshotFormat *sf = _screenshot_formats + _cur_screenshot_format;
return sf->proc(MakeScreenshotName(SCREENSHOT_NAME, sf->extension), TopographyScreenCallback, nullptr, MapSizeX(), MapSizeY(), 32, _cur_palette.palette);
@ -1356,8 +1355,8 @@ bool MakeTopographyScreenshot(const char *name)
*/
bool MakeIndustryScreenshot(const char *name)
{
_screenshot_name[0] = '\0';
if (name != nullptr) strecpy(_screenshot_name, name, lastof(_screenshot_name));
_screenshot_name.clear();
if (name != nullptr) _screenshot_name.assign(name);
const ScreenshotFormat *sf = _screenshot_formats + _cur_screenshot_format;
return sf->proc(MakeScreenshotName(SCREENSHOT_NAME, sf->extension), IndustryScreenCallback, nullptr, MapSizeX(), MapSizeY(), 32, _cur_palette.palette);

@ -45,6 +45,6 @@ inline void ClearScreenshotAuxiliaryText() { SetScreenshotAuxiliaryText(nullptr,
extern std::string _screenshot_format_name;
extern uint _num_screenshot_formats;
extern uint _cur_screenshot_format;
extern char _full_screenshot_name[MAX_PATH];
extern std::string _full_screenshot_path;
#endif /* SCREENSHOT_H */

@ -136,7 +136,7 @@ SQInteger ScriptText::AddParam(HSQUIRRELVM vm)
SQInteger ScriptText::_set(HSQUIRRELVM vm)
{
int32 k;
int32_t k;
if (sq_gettype(vm, 2) == OT_STRING) {
const SQChar *key_string;
@ -149,7 +149,7 @@ SQInteger ScriptText::_set(HSQUIRRELVM vm)
} else if (sq_gettype(vm, 2) == OT_INTEGER) {
SQInteger key;
sq_getinteger(vm, 2, &key);
k = (int32)key;
k = (int32_t)key;
} else {
return SQ_ERROR;
}
@ -161,15 +161,16 @@ SQInteger ScriptText::_set(HSQUIRRELVM vm)
return this->_SetParam(k, vm);
}
const std::string ScriptText::GetEncodedText()
std::string ScriptText::GetEncodedText()
{
static char buf[1024];
static StringIDList seen_ids;
int param_count = 0;
seen_ids.clear();
this->_GetEncodedText(buf, lastof(buf), param_count, seen_ids);
std::string result;
auto output = std::back_inserter(result);
this->_GetEncodedText(output, param_count, seen_ids);
if (param_count > SCRIPT_TEXT_MAX_PARAMETERS) throw Script_FatalError(fmt::format("{}: Too many parameters", GetGameStringName(this->string)));
return buf;
return result;
}
void ScriptText::_TextParamError(std::string msg)
@ -181,28 +182,28 @@ void ScriptText::_TextParamError(std::string msg)
}
}
char *ScriptText::_GetEncodedText(char *p, char *lastofp, int &param_count, StringIDList &seen_ids)
void ScriptText::_GetEncodedText(std::back_insert_iterator<std::string> &output, int &param_count, StringIDList &seen_ids)
{
const std::string &name = GetGameStringName(this->string);
if (std::find(seen_ids.begin(), seen_ids.end(), this->string) != seen_ids.end()) throw Script_FatalError(fmt::format("{}: Circular reference detected", name));
seen_ids.push_back(this->string);
p += Utf8Encode(p, SCC_ENCODED);
p += seprintf(p, lastofp, "%X", this->string);
Utf8Encode(output, SCC_ENCODED);
fmt::format_to(output, "{:X}", this->string);
auto write_param_fallback = [&](int idx) {
if (std::holds_alternative<ScriptTextRef>(this->param[idx])) {
int count = 1; // 1 because the string id is included in consumed parameters
p += seprintf(p, lastofp, ":");
p = std::get<ScriptTextRef>(this->param[idx])->_GetEncodedText(p, lastofp, count, seen_ids);
fmt::format_to(output, ":");
std::get<ScriptTextRef>(this->param[idx])->_GetEncodedText(output, count, seen_ids);
param_count += count;
} else if (std::holds_alternative<SQInteger>(this->param[idx])) {
p += seprintf(p, lastofp, ":" OTTD_PRINTFHEX64, std::get<SQInteger>(this->param[idx]));
fmt::format_to(output, ":{:X}", std::get<SQInteger>(this->param[idx]));
param_count++;
} else {
/* Fallback value */
p += seprintf(p, lastofp, ":0");
fmt::format_to(output, ":0");
param_count++;
}
};
@ -227,7 +228,7 @@ char *ScriptText::_GetEncodedText(char *p, char *lastofp, int &param_count, Stri
write_param_fallback(cur_idx++);
break;
}
p += seprintf(p, lastofp, ":\"%s\"", std::get<std::string>(this->param[cur_idx++]).c_str());
fmt::format_to(output, ":\"{}\"", std::get<std::string>(this->param[cur_idx++]));
param_count++;
break;
@ -238,8 +239,8 @@ char *ScriptText::_GetEncodedText(char *p, char *lastofp, int &param_count, Stri
break;
}
int count = 1; // 1 because the string id is included in consumed parameters
p += seprintf(p, lastofp, ":");
p = std::get<ScriptTextRef>(this->param[cur_idx++])->_GetEncodedText(p, lastofp, count, seen_ids);
fmt::format_to(output, ":");
std::get<ScriptTextRef>(this->param[cur_idx++])->_GetEncodedText(output, count, seen_ids);
if (count != cur_param.consumes) {
this->_TextParamError(fmt::format("{}: Parameter {} substring consumes {}, but expected {} to be consumed", name, cur_idx, count - 1, cur_param.consumes - 1));
}
@ -257,7 +258,7 @@ char *ScriptText::_GetEncodedText(char *p, char *lastofp, int &param_count, Stri
write_param_fallback(cur_idx++);
continue;
}
p += seprintf(p, lastofp, ":" OTTD_PRINTFHEX64, std::get<SQInteger>(this->param[cur_idx++]));
fmt::format_to(output, ":{:X}", std::get<SQInteger>(this->param[cur_idx++]));
param_count++;
}
break;
@ -267,12 +268,12 @@ char *ScriptText::_GetEncodedText(char *p, char *lastofp, int &param_count, Stri
/* The previous substring added more parameters than expected, means we will consume them but can't properly validate them. */
for (int i = 0; i < cur_param.consumes; i++) {
if (prev_idx < prev_count) {
ScriptLog::Warning(fmt::format("{}: Parameter {} uses parameter {} from substring {} and cannot be validated", name, param_count + i, prev_idx++, prev_string).c_str());
ScriptLog::Warning(fmt::format("{}: Parameter {} uses parameter {} from substring {} and cannot be validated", name, param_count + i, prev_idx++, prev_string));
} else {
/* No more extra parameters, assume SQInteger are expected. */
if (cur_idx >= this->paramc) throw Script_FatalError(fmt::format("{}: Not enough parameters", name));
if (!std::holds_alternative<SQInteger>(this->param[cur_idx])) throw Script_FatalError(fmt::format("{}: Parameter {} expects an integer", name, param_count + i));
p += seprintf(p, lastofp, ":" OTTD_PRINTFHEX64, std::get<SQInteger>(this->param[cur_idx++]));
fmt::format_to(output, ":{:X}", std::get<SQInteger>(this->param[cur_idx++]));
}
}
if (prev_idx == prev_count) {
@ -283,18 +284,18 @@ char *ScriptText::_GetEncodedText(char *p, char *lastofp, int &param_count, Stri
switch (cur_param.type) {
case StringParam::RAW_STRING:
if (!std::holds_alternative<std::string>(this->param[cur_idx])) throw Script_FatalError(fmt::format("{}: Parameter {} expects a raw string", name, param_count));
p += seprintf(p, lastofp, ":\"%s\"", std::get<std::string>(this->param[cur_idx++]).c_str());
fmt::format_to(output, ":\"{}\"", std::get<std::string>(this->param[cur_idx++]));
break;
case StringParam::STRING: {
if (!std::holds_alternative<ScriptTextRef>(this->param[cur_idx])) throw Script_FatalError(fmt::format("{}: Parameter {} expects a substring", name, param_count));
int count = 0;
p += seprintf(p, lastofp, ":");
p = std::get<ScriptTextRef>(this->param[cur_idx++])->_GetEncodedText(p, lastofp, count, seen_ids);
fmt::format_to(output, ":");
std::get<ScriptTextRef>(this->param[cur_idx++])->_GetEncodedText(output, count, seen_ids);
if (++count != cur_param.consumes) {
ScriptLog::Error(fmt::format("{}: Parameter {} substring consumes {}, but expected {} to be consumed", name, param_count, count - 1, cur_param.consumes - 1).c_str());
ScriptLog::Error(fmt::format("{}: Parameter {} substring consumes {}, but expected {} to be consumed", name, param_count, count - 1, cur_param.consumes - 1));
/* Fill missing params if needed. */
for (int i = count; i < cur_param.consumes; i++) p += seprintf(p, lastofp, ":0");
for (int i = count; i < cur_param.consumes; i++) fmt::format_to(output, ":0");
/* Disable validation for the extra params if any. */
if (count > cur_param.consumes) {
prev_string = param_count;
@ -309,7 +310,7 @@ char *ScriptText::_GetEncodedText(char *p, char *lastofp, int &param_count, Stri
if (cur_idx + cur_param.consumes > this->paramc) throw Script_FatalError(fmt::format("{}: Not enough parameters", name));
for (int i = 0; i < cur_param.consumes; i++) {
if (!std::holds_alternative<SQInteger>(this->param[cur_idx])) throw Script_FatalError(fmt::format("{}: Parameter {} expects an integer", name, param_count + i));
p += seprintf(p, lastofp, ":" OTTD_PRINTFHEX64, std::get<SQInteger>(this->param[cur_idx++]));
fmt::format_to(output, ":{:X}", std::get<SQInteger>(this->param[cur_idx++]));
}
}
}
@ -323,14 +324,10 @@ char *ScriptText::_GetEncodedText(char *p, char *lastofp, int &param_count, Stri
}
seen_ids.pop_back();
return p;
}
const std::string Text::GetDecodedText()
{
static char buf[1024];
::SetDParamStr(0, this->GetEncodedText());
::GetString(buf, STR_JUST_RAW_STRING, lastof(buf));
return buf;
return ::GetString(STR_JUST_RAW_STRING);
}

@ -26,7 +26,7 @@ public:
* @return A string.
* @api -all
*/
virtual const std::string GetEncodedText() = 0;
virtual std::string GetEncodedText() = 0;
/**
* Convert a #ScriptText into a decoded normal string.
@ -44,7 +44,7 @@ class RawText : public Text {
public:
RawText(const std::string &text);
const std::string GetEncodedText() override { return this->text; }
std::string GetEncodedText() override { return this->text; }
private:
const std::string text;
};
@ -125,7 +125,7 @@ public:
/**
* @api -all
*/
const std::string GetEncodedText() override;
std::string GetEncodedText() override;
private:
using ScriptTextRef = ScriptObjectRef<ScriptText>;
@ -140,13 +140,11 @@ private:
/**
* Internal function for recursive calling this function over multiple
* instances, while writing in the same buffer.
* @param p The current position in the buffer.
* @param lastofp The last position valid in the buffer.
* @param output The output to write the encoded text to.
* @param param_count The number of parameters that are in the string.
* @param seen_ids The list of seen StringID.
* @return The new current position in the buffer.
*/
char *_GetEncodedText(char *p, char *lastofp, int &param_count, StringIDList &seen_ids);
void _GetEncodedText(std::back_insert_iterator<std::string> &output, int &param_count, StringIDList &seen_ids);
/**
* Set a parameter, where the value is the first item on the stack.

@ -1082,11 +1082,7 @@ struct SettingEntry : BaseSettingEntry {
void SetButtons(byte new_val);
StringID GetHelpText() const;
struct SetValueDParamsTempData {
char buffer[512];
};
void SetValueDParams(uint first_param, int32 value, std::unique_ptr<SetValueDParamsTempData> &tempdata) const;
void SetValueDParams(uint first_param, int32 value) const;
protected:
SettingEntry(const IntSettingDesc *setting);
@ -1456,19 +1452,17 @@ static const void *ResolveObject(const GameSettings *settings_ptr, const IntSett
* @param first_param First DParam to use
* @param value Setting value to set params for.
*/
void SettingEntry::SetValueDParams(uint first_param, int32 value, std::unique_ptr<SettingEntry::SetValueDParamsTempData> &tempdata) const
void SettingEntry::SetValueDParams(uint first_param, int32 value) const
{
if (this->setting->IsBoolSetting()) {
SetDParam(first_param++, value != 0 ? STR_CONFIG_SETTING_ON : STR_CONFIG_SETTING_OFF);
} else if (this->setting->flags & SF_DEC1SCALE) {
tempdata.reset(new SettingEntry::SetValueDParamsTempData());
double scale = std::exp2(((double)value) / 10);
int log = -std::min(0, (int)std::floor(std::log10(scale)) - 2);
auto tmp_params = MakeParameters(value, (int64)(scale * std::pow(10.f, (float)log)), log);
GetStringWithArgs(tempdata->buffer, this->setting->str_val, tmp_params, lastof(tempdata->buffer));
SetDParam(first_param++, STR_JUST_RAW_STRING);
SetDParamStr(first_param++, tempdata->buffer);
auto tmp_params = MakeParameters(value, (int64)(scale * std::pow(10.f, (float)log)), log);
SetDParamStr(first_param++, GetStringWithArgs(this->setting->str_val, tmp_params));
} else {
if ((this->setting->flags & SF_ENUM) != 0) {
StringID str = STR_UNDEFINED;
@ -1531,8 +1525,7 @@ void SettingEntry::DrawSetting(GameSettings *settings_ptr, int left, int right,
void SettingEntry::DrawSettingString(uint left, uint right, int y, bool highlight, int32 value) const
{
std::unique_ptr<SettingEntry::SetValueDParamsTempData> tempdata;
this->SetValueDParams(1, value, tempdata);
this->SetValueDParams(1, value);
int edge = DrawString(left, right, y, this->setting->str, highlight ? TC_WHITE : TC_LIGHT_BLUE);
if (this->setting->flags & SF_GUI_ADVISE_DEFAULT && value != this->setting->def && edge != 0) {
const Dimension warning_dimensions = GetSpriteSize(SPR_WARNING_SIGN);
@ -1558,8 +1551,7 @@ void CargoDestPerCargoSettingEntry::DrawSettingString(uint left, uint right, int
assert(this->setting->str == STR_CONFIG_SETTING_DISTRIBUTION_PER_CARGO);
SetDParam(0, CargoSpec::Get(this->cargo)->name);
SetDParam(1, STR_CONFIG_SETTING_VALUE);
std::unique_ptr<SettingEntry::SetValueDParamsTempData> tempdata;
this->SetValueDParams(2, value, tempdata);
this->SetValueDParams(2, value);
DrawString(left, right, y, STR_CONFIG_SETTING_DISTRIBUTION_PER_CARGO_PARAM, highlight ? TC_WHITE : TC_LIGHT_BLUE);
}
@ -2740,8 +2732,7 @@ struct GameSettingsWindow : Window {
DrawString(tr, STR_CONFIG_SETTING_TYPE);
tr.top += GetCharacterHeight(FS_NORMAL);
std::unique_ptr<SettingEntry::SetValueDParamsTempData> tempdata;
this->last_clicked->SetValueDParams(0, sd->def, tempdata);
this->last_clicked->SetValueDParams(0, sd->def);
DrawString(tr, STR_CONFIG_SETTING_DEFAULT_VALUE);
tr.top += GetCharacterHeight(FS_NORMAL) + WidgetDimensions::scaled.vsep_normal;

@ -74,7 +74,6 @@ void DrawShipDetails(const Vehicle *v, const Rect &r)
if (v->Next() != nullptr) {
CargoArray max_cargo{};
StringID subtype_text[NUM_CARGO];
char capacity[512];
memset(subtype_text, 0, sizeof(subtype_text));
@ -86,23 +85,18 @@ void DrawShipDetails(const Vehicle *v, const Rect &r)
}
}
GetString(capacity, STR_VEHICLE_DETAILS_TRAIN_ARTICULATED_RV_CAPACITY, lastof(capacity));
std::string capacity = GetString(STR_VEHICLE_DETAILS_TRAIN_ARTICULATED_RV_CAPACITY);
bool first = true;
for (CargoID i = 0; i < NUM_CARGO; i++) {
if (max_cargo[i] > 0) {
char buffer[128];
if (!first) capacity += ", ";
SetDParam(0, i);
SetDParam(1, max_cargo[i]);
GetString(buffer, STR_JUST_CARGO, lastof(buffer));
if (!first) strecat(capacity, ", ", lastof(capacity));
strecat(capacity, buffer, lastof(capacity));
GetString(StringBuilder(capacity), STR_JUST_CARGO);
if (subtype_text[i] != 0) {
GetString(buffer, subtype_text[i], lastof(buffer));
strecat(capacity, buffer, lastof(capacity));
GetString(StringBuilder(capacity), subtype_text[i]);
}
first = false;

@ -631,10 +631,8 @@ static void Load_SLXI()
};
auto version_error = [](StringID str, const char *feature, int64 p1, int64 p2) {
char buf[256];
auto tmp_params = MakeParameters(_sl_xv_version_label.empty() ? STR_EMPTY : STR_GAME_SAVELOAD_FROM_VERSION, _sl_xv_version_label, feature, p1, p2);
GetStringWithArgs(buf, str, tmp_params, lastof(buf));
SlError(STR_JUST_RAW_STRING, buf);
SlError(STR_JUST_RAW_STRING, GetStringWithArgs(str, tmp_params));
};
uint32 item_count = SlReadUint32();

@ -3147,14 +3147,11 @@ void SetSaveLoadError(StringID str)
}
/** Get the string representation of the error message */
const char *GetSaveLoadErrorString()
std::string GetSaveLoadErrorString()
{
SetDParam(0, _sl.error_str);
SetDParamStr(1, _sl.extra_msg);
static char err_str[512];
GetString(err_str, _sl.action == SLA_SAVE ? STR_ERROR_GAME_SAVE_FAILED : STR_ERROR_GAME_LOAD_FAILED, lastof(err_str));
return err_str;
return GetString(_sl.action == SLA_SAVE ? STR_ERROR_GAME_SAVE_FAILED : STR_ERROR_GAME_LOAD_FAILED);
}
/** Show a gui message when saving has failed */
@ -3198,7 +3195,7 @@ static SaveOrLoadResult SaveFileToDisk(bool threaded)
* cancelled due to a client disconnecting. */
if (_sl.error_str != STR_NETWORK_ERROR_LOSTCONNECTION) {
/* Skip the "colour" character */
DEBUG(sl, 0, "%s", GetSaveLoadErrorString() + 3);
DEBUG(sl, 0, "%s", strip_leading_colours(GetSaveLoadErrorString()));
asfp = SaveFileError;
}
@ -3644,7 +3641,7 @@ SaveOrLoadResult LoadWithFilter(LoadFilter *reader)
ClearSaveLoadState();
/* Skip the "colour" character */
DEBUG(sl, 0, "%s", GetSaveLoadErrorString() + 3);
DEBUG(sl, 0, "%s", strip_leading_colours(GetSaveLoadErrorString()));
return SL_REINIT;
}
@ -3744,7 +3741,7 @@ SaveOrLoadResult SaveOrLoad(const std::string &filename, SaveLoadOperation fop,
ClearSaveLoadState();
/* Skip the "colour" character */
if (fop != SLO_CHECK) DEBUG(sl, 0, "%s", GetSaveLoadErrorString() + 3);
if (fop != SLO_CHECK) DEBUG(sl, 0, "%s", strip_leading_colours(GetSaveLoadErrorString()));
/* A saver/loader exception!! reinitialize all variables to prevent crash! */
return (fop == SLO_LOAD) ? SL_REINIT : SL_ERROR;
@ -3758,23 +3755,22 @@ SaveOrLoadResult SaveOrLoad(const std::string &filename, SaveLoadOperation fop,
*/
void DoAutoOrNetsave(FiosNumberedSaveName &counter, bool threaded, FiosNumberedSaveName *lt_counter)
{
char buf[MAX_PATH];
std::string filename;
if (_settings_client.gui.keep_all_autosave) {
GenerateDefaultSaveName(buf, lastof(buf));
strecat(buf, counter.Extension().c_str(), lastof(buf));
filename = GenerateDefaultSaveName() + counter.Extension();
} else {
strecpy(buf, counter.Filename().c_str(), lastof(buf));
filename = counter.Filename();
if (lt_counter != nullptr && counter.GetLastNumber() == 0) {
std::string lt_path = lt_counter->FilenameUsingMaxSaves(_settings_client.gui.max_num_lt_autosaves);
DEBUG(sl, 2, "Renaming autosave '%s' to long-term file '%s'", buf, lt_path.c_str());
DEBUG(sl, 2, "Renaming autosave '%s' to long-term file '%s'", filename.c_str(), lt_path.c_str());
std::string dir = FioFindDirectory(AUTOSAVE_DIR);
FioRenameFile(dir + buf, dir + lt_path);
FioRenameFile(dir + filename, dir + lt_path);
}
}
DEBUG(sl, 2, "Autosaving to '%s'", buf);
if (SaveOrLoad(buf, SLO_SAVE, DFT_GAME_FILE, AUTOSAVE_DIR, threaded, SMF_ZSTD_OK) != SL_OK) {
DEBUG(sl, 2, "Autosaving to '%s'", filename.c_str());
if (SaveOrLoad(filename, SLO_SAVE, DFT_GAME_FILE, AUTOSAVE_DIR, threaded, SMF_ZSTD_OK) != SL_OK) {
ShowErrorMessage(STR_ERROR_AUTOSAVE_FAILED, INVALID_STRING_ID, WL_ERROR);
}
}
@ -3787,11 +3783,9 @@ void DoExitSave()
}
/**
* Fill the buffer with the default name for a savegame *or* screenshot.
* @param buf the buffer to write to.
* @param last the last element in the buffer.
* Get the default name for a savegame *or* screenshot.
*/
void GenerateDefaultSaveName(char *buf, const char *last)
std::string GenerateDefaultSaveName()
{
/* Check if we have a name for this map, which is the name of the first
* available company. When there's no company available we'll use
@ -3816,8 +3810,9 @@ void GenerateDefaultSaveName(char *buf, const char *last)
SetDParam(2, _date);
/* Get the correct string (special string for when there's not company) */
GetString(buf, !Company::IsValidID(cid) ? STR_SAVEGAME_NAME_SPECTATOR : STR_SAVEGAME_NAME_DEFAULT, last);
SanitizeFilename(buf);
std::string filename = GetString(!Company::IsValidID(cid) ? STR_SAVEGAME_NAME_SPECTATOR : STR_SAVEGAME_NAME_DEFAULT);
SanitizeFilename(filename);
return filename;
}
/**

@ -66,9 +66,9 @@ DECLARE_ENUM_AS_BIT_SET(SaveModeFlags);
extern FileToSaveLoad _file_to_saveload;
void GenerateDefaultSaveName(char *buf, const char *last);
std::string GenerateDefaultSaveName();
void SetSaveLoadError(StringID str);
const char *GetSaveLoadErrorString();
std::string GetSaveLoadErrorString();
SaveOrLoadResult SaveOrLoad(const std::string &filename, SaveLoadOperation fop, DetailedFileType dft, Subdirectory sb, bool threaded = true, SaveModeFlags flags = SMF_NONE);
void WaitTillSaved();
void ProcessAsyncSaveFinish();

@ -553,10 +553,8 @@ void UpdateAllStationVirtCoords()
void BaseStation::FillCachedName() const
{
char buf[MAX_LENGTH_STATION_NAME_CHARS * MAX_CHAR_LENGTH];
auto tmp_params = MakeParameters(this->index);
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()

@ -2774,12 +2774,11 @@ private:
const CargoSpec *cs;
bool newgrf_rating_used;
static const uint RATING_TOOLTIP_LINE_BUFF_SIZE = 512;
static const uint RATING_TOOLTIP_MAX_LINES = 9;
static const uint RATING_TOOLTIP_NEWGRF_INDENT = 20;
public:
char data[RATING_TOOLTIP_MAX_LINES + 1][RATING_TOOLTIP_LINE_BUFF_SIZE] {};
std::string data[RATING_TOOLTIP_MAX_LINES + 1]{};
StationRatingTooltipWindow(Window *parent, const Station *st, const CargoSpec *cs) : Window(&_station_rating_tooltip_desc)
{
@ -2813,7 +2812,7 @@ public:
const GoodsEntry *ge = &this->st->goods[this->cs->Index()];
SetDParam(0, this->cs->name);
GetString(this->data[0], STR_STATION_RATING_TOOLTIP_RATING_DETAILS, lastof(this->data[0]));
this->data[0] = GetString(STR_STATION_RATING_TOOLTIP_RATING_DETAILS);
if (!ge->HasRating()) {
this->data[1][0] = '\0';
@ -2831,7 +2830,7 @@ public:
if (_cheats.station_rating.value) {
total_rating = 255;
skip = true;
GetString(this->data[line_nr], STR_STATION_RATING_TOOLTIP_USING_CHEAT, lastof(this->data[line_nr]));
this->data[line_nr] = GetString(STR_STATION_RATING_TOOLTIP_USING_CHEAT);
line_nr++;
} else if (HasBit(cs->callback_mask, CBM_CARGO_STATION_RATING_CALC)) {
@ -2845,14 +2844,13 @@ public:
SetDParam(0, STR_STATION_RATING_TOOLTIP_NEWGRF_RATING_0 + (new_grf_rating <= 0 ? 0 : 1));
SetDParam(1, new_grf_rating);
GetString(this->data[line_nr], STR_STATION_RATING_TOOLTIP_NEWGRF_RATING, lastof(this->data[line_nr]));
this->data[line_nr] = GetString(STR_STATION_RATING_TOOLTIP_NEWGRF_RATING);
line_nr++;
const uint last_speed = ge->HasVehicleEverTriedLoading() && ge->IsSupplyAllowed() ? ge->last_speed : 0xFF;
SetDParam(0, std::min<uint>(last_speed, 0xFFu));
switch (ge->last_vehicle_type)
{
switch (ge->last_vehicle_type) {
case VEH_TRAIN:
SetDParam(1, STR_STATION_RATING_TOOLTIP_TRAIN);
break;
@ -2869,18 +2867,15 @@ public:
SetDParam(1, STR_STATION_RATING_TOOLTIP_INVALID);
break;
}
GetString(this->data[line_nr], STR_STATION_RATING_TOOLTIP_NEWGRF_SPEED, lastof(this->data[line_nr]));
this->data[line_nr] = GetString(STR_STATION_RATING_TOOLTIP_NEWGRF_SPEED);
line_nr++;
SetDParam(0, std::min(ge->max_waiting_cargo, 0xFFFFu));
GetString(this->data[line_nr],
STR_STATION_RATING_TOOLTIP_NEWGRF_WAITUNITS,
lastof(this->data[line_nr]));
this->data[line_nr] = GetString(STR_STATION_RATING_TOOLTIP_NEWGRF_WAITUNITS);
line_nr++;
SetDParam(0, ge->time_since_pickup * STATION_RATING_TICKS / (DAY_TICKS * _settings_game.economy.day_length_factor));
GetString(this->data[line_nr], STR_STATION_RATING_TOOLTIP_NEWGRF_WAITTIME, lastof(this->data[line_nr]));
this->data[line_nr] = GetString(STR_STATION_RATING_TOOLTIP_NEWGRF_WAITTIME);
line_nr++;
}
}
@ -2906,8 +2901,7 @@ public:
SetDParam(4, detailed ? STR_STATION_RATING_PERCENTAGE_COMMA : STR_EMPTY);
SetDParam(5, rounded_speed_rating);
switch (ge->last_vehicle_type)
{
switch (ge->last_vehicle_type) {
case VEH_TRAIN:
SetDParam(6, STR_STATION_RATING_TOOLTIP_TRAIN);
break;
@ -2924,8 +2918,7 @@ public:
SetDParam(6, STR_STATION_RATING_TOOLTIP_INVALID);
break;
}
GetString(this->data[line_nr], STR_STATION_RATING_TOOLTIP_SPEED, lastof(this->data[line_nr]));
this->data[line_nr] = GetString(STR_STATION_RATING_TOOLTIP_SPEED);
line_nr++;
total_rating += speed_rating;
@ -2954,11 +2947,7 @@ public:
SetDParam(4, ge->time_since_pickup * STATION_RATING_TICKS / (DAY_TICKS * _settings_game.economy.day_length_factor));
SetDParam(5, detailed ? STR_STATION_RATING_PERCENTAGE_COMMA : STR_EMPTY);
SetDParam(6, RoundRating(wait_time_rating));
GetString(this->data[line_nr],
(ge->last_vehicle_type == VEH_SHIP) ?
STR_STATION_RATING_TOOLTIP_WAITTIME_SHIP :
STR_STATION_RATING_TOOLTIP_WAITTIME,
lastof(this->data[line_nr]));
this->data[line_nr] = GetString((ge->last_vehicle_type == VEH_SHIP) ? STR_STATION_RATING_TOOLTIP_WAITTIME_SHIP : STR_STATION_RATING_TOOLTIP_WAITTIME);
line_nr++;
total_rating += wait_time_rating;
@ -2986,9 +2975,7 @@ public:
SetDParam(3, ge->max_waiting_cargo);
SetDParam(4, detailed ? STR_STATION_RATING_PERCENTAGE_COMMA : STR_EMPTY);
SetDParam(5, RoundRating(cargo_rating));
GetString(this->data[line_nr],
STR_STATION_RATING_TOOLTIP_WAITUNITS,
lastof(this->data[line_nr]));
this->data[line_nr] = GetString(STR_STATION_RATING_TOOLTIP_WAITUNITS);
line_nr++;
total_rating += cargo_rating;
@ -3004,7 +2991,7 @@ public:
SetDParam(2, (statue_rating > 0) ? STR_STATION_RATING_TOOLTIP_STATUE_YES : STR_STATION_RATING_TOOLTIP_STATUE_NO);
SetDParam(3, detailed ? STR_STATION_RATING_PERCENTAGE_COMMA : STR_EMPTY);
SetDParam(4, (statue_rating > 0) ? 10 : 0);
GetString(this->data[line_nr], STR_STATION_RATING_TOOLTIP_STATUE, lastof(this->data[line_nr]));
this->data[line_nr] = GetString(STR_STATION_RATING_TOOLTIP_STATUE);
line_nr++;
total_rating += statue_rating;
@ -3030,7 +3017,7 @@ public:
SetDParam(3, ge->last_age);
SetDParam(4, detailed ? STR_STATION_RATING_PERCENTAGE_COMMA : STR_EMPTY);
SetDParam(5, RoundRating(age_rating));
GetString(this->data[line_nr], STR_STATION_RATING_TOOLTIP_AGE, lastof(this->data[line_nr]));
this->data[line_nr] = GetString(STR_STATION_RATING_TOOLTIP_AGE);
line_nr++;
total_rating += age_rating;
@ -3041,7 +3028,7 @@ public:
if (detailed) {
SetDParam(0, ToPercent8(total_rating));
GetString(this->data[line_nr], STR_STATION_RATING_TOOLTIP_TOTAL_RATING, lastof(this->data[line_nr]));
this->data[line_nr] = GetString(STR_STATION_RATING_TOOLTIP_TOTAL_RATING);
line_nr++;
}
@ -3055,7 +3042,7 @@ public:
size->height = WidgetDimensions::scaled.framerect.Vertical() + 2;
for (uint i = 0; i <= RATING_TOOLTIP_MAX_LINES; i++) {
if (StrEmpty(this->data[i])) break;
if (this->data[i].empty()) break;
uint width = GetStringBoundingBox(this->data[i]).width + WidgetDimensions::scaled.framerect.Horizontal() + 2;
if (this->newgrf_rating_used && i >= 2 && i <= 4) {
@ -3084,15 +3071,14 @@ public:
y += GetCharacterHeight(FS_NORMAL) + WidgetDimensions::scaled.vsep_normal;
for (uint i = 1; i <= RATING_TOOLTIP_MAX_LINES; i++) {
if (StrEmpty(this->data[i])) break;
if (this->data[i].empty()) break;
int left = left0, right = right0;
if (this->newgrf_rating_used && i >= 2 && i <= 4) {
if (_current_text_dir == TD_RTL) {
right -= RATING_TOOLTIP_NEWGRF_INDENT;
}
else {
} else {
left += RATING_TOOLTIP_NEWGRF_INDENT;
}
}

@ -547,6 +547,20 @@ void str_strip_colours(char *str)
*dst = '\0';
}
/** Advances the pointer over any colour codes at the start of the string */
const char *strip_leading_colours(const char *str)
{
char32_t c;
do {
size_t len = Utf8Decode(&c, str);
if (c < SCC_BLUE || c > SCC_BLACK) break;
str += len;
} while (c != '\0');
return str;
}
std::string str_strip_all_scc(const char *str)
{
std::string out;
@ -849,6 +863,11 @@ size_t Utf8Encode(std::ostreambuf_iterator<char> &buf, WChar c)
return Utf8Encode<std::ostreambuf_iterator<char> &>(buf, c);
}
size_t Utf8Encode(std::back_insert_iterator<std::string> &buf, char32_t c)
{
return Utf8Encode<std::back_insert_iterator<std::string> &>(buf, c);
}
/**
* Properly terminate an UTF8 string to some maximum length
* @param s string to check if it needs additional trimming

@ -49,6 +49,14 @@ void StrMakeValidInPlace(char *str, StringValidationSettings settings = SVS_REPL
const char *str_fix_scc_encoded(char *str, const char *last) NOACCESS(2);
void str_strip_colours(char *str);
const char *strip_leading_colours(const char *str);
inline const char *strip_leading_colours(const std::string &str)
{
return strip_leading_colours(str.c_str());
}
std::string str_strip_all_scc(const char *str);
char *str_replace_wchar(char *str, const char *last, WChar find, WChar replace);
bool strtolower(char *str);
@ -99,25 +107,26 @@ static inline size_t ttd_strnlen(const char *str, size_t maxlen)
return t - str;
}
bool IsValidChar(WChar key, CharSetFilter afilter);
bool IsValidChar(char32_t key, CharSetFilter afilter);
size_t Utf8Decode(WChar *c, const char *s);
size_t Utf8Encode(char *buf, WChar c);
size_t Utf8Encode(std::ostreambuf_iterator<char> &buf, WChar c);
size_t Utf8Decode(char32_t *c, const char *s);
size_t Utf8Encode(char *buf, char32_t c);
size_t Utf8Encode(std::ostreambuf_iterator<char> &buf, char32_t c);
size_t Utf8Encode(std::back_insert_iterator<std::string> &buf, char32_t c);
size_t Utf8TrimString(char *s, size_t maxlen);
static inline WChar Utf8Consume(const char **s)
static inline char32_t Utf8Consume(const char **s)
{
WChar c;
char32_t c;
*s += Utf8Decode(&c, *s);
return c;
}
template <class Titr>
static inline WChar Utf8Consume(Titr &s)
static inline char32_t Utf8Consume(Titr &s)
{
WChar c;
char32_t c;
s += Utf8Decode(&c, &*s);
return c;
}
@ -127,7 +136,7 @@ static inline WChar Utf8Consume(Titr &s)
* @param c Unicode character.
* @return Length of UTF-8 encoding for character.
*/
static inline int8 Utf8CharLen(WChar c)
static inline int8_t Utf8CharLen(char32_t c)
{
if (c < 0x80) return 1;
if (c < 0x800) return 2;
@ -146,7 +155,7 @@ static inline int8 Utf8CharLen(WChar c)
* @param c char to query length of
* @return requested size
*/
static inline int8 Utf8EncodedCharLen(char c)
static inline int8_t Utf8EncodedCharLen(char c)
{
if (GB(c, 3, 5) == 0x1E) return 4;
if (GB(c, 4, 4) == 0x0E) return 3;
@ -214,7 +223,7 @@ static inline bool Utf16IsTrailSurrogate(uint c)
* @param trail Trail surrogate code point.
* @return Decoded Unicode character.
*/
static inline WChar Utf16DecodeSurrogate(uint lead, uint trail)
static inline char32_t Utf16DecodeSurrogate(uint lead, uint trail)
{
return 0x10000 + (((lead - 0xD800) << 10) | (trail - 0xDC00));
}
@ -224,7 +233,7 @@ static inline WChar Utf16DecodeSurrogate(uint lead, uint trail)
* @param c Pointer to one or two UTF-16 code points.
* @return Decoded Unicode character.
*/
static inline WChar Utf16DecodeChar(const uint16 *c)
static inline char32_t Utf16DecodeChar(const uint16_t *c)
{
if (Utf16IsLeadSurrogate(c[0])) {
return Utf16DecodeSurrogate(c[0], c[1]);
@ -239,7 +248,7 @@ static inline WChar Utf16DecodeChar(const uint16 *c)
* @return true iff the character is used to influence
* the text direction.
*/
static inline bool IsTextDirectionChar(WChar c)
static inline bool IsTextDirectionChar(char32_t c)
{
switch (c) {
case CHAR_TD_LRM:
@ -256,7 +265,7 @@ static inline bool IsTextDirectionChar(WChar c)
}
}
static inline bool IsPrintable(WChar c)
static inline bool IsPrintable(char32_t c)
{
if (c < 0x20) return false;
if (c < 0xE000) return true;
@ -271,7 +280,7 @@ static inline bool IsPrintable(WChar c)
* @return a boolean value whether 'c' is a whitespace character or not
* @see http://www.fileformat.info/info/unicode/category/Zs/list.htm
*/
static inline bool IsWhitespace(WChar c)
static inline bool IsWhitespace(char32_t c)
{
return c == 0x0020 /* SPACE */ || c == 0x3000; /* IDEOGRAPHIC SPACE */
}

File diff suppressed because it is too large Load Diff

@ -65,9 +65,7 @@ static inline StringID MakeStringID(StringTab tab, uint index)
return (tab << TAB_SIZE_BITS) + index;
}
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);
const char *GetStringPtr(StringID string);
uint32 GetStringGRFID(StringID string);

@ -10,7 +10,6 @@
#ifndef STRINGS_INTERNAL_H
#define STRINGS_INTERNAL_H
#include "strings_func.h"
#include "string_func.h"
#include "core/span_type.hpp"
#include "core/strong_typedef_type.hpp"
@ -346,6 +345,21 @@ public:
{
return (*this->string)[index];
}
std::string *GetTargetString()
{
return this->string;
}
};
void GetStringWithArgs(StringBuilder builder, StringID string, StringParameters &args, uint case_index = 0, bool game_script = false);
std::string GetStringWithArgs(StringID string, StringParameters &args);
void GetString(StringBuilder builder, StringID string);
/* Do not leak the StringBuilder to everywhere. */
void GenerateTownNameString(StringBuilder builder, size_t lang, uint32_t seed);
void GetTownName(StringBuilder builder, const struct Town *t);
void GRFTownNameGenerate(StringBuilder builder, uint32_t grfid, uint16_t gen, uint32_t seed);
#endif /* STRINGS_INTERNAL_H */

@ -493,7 +493,7 @@ class NIHVehicle : public NIHelper {
b = buffer + seprintf(buffer, lastof(buffer), " %s [%d, %d, %d], %u, ",
info.id == v->index ? "*" : " ", info.order_count, info.order_ticks, info.cumulative_ticks, info.id);
SetDParam(0, info.id);
b = GetString(b, STR_VEHICLE_NAME, lastof(buffer));
b = strecpy(b, GetString(STR_VEHICLE_NAME).c_str(), lastof(buffer), true);
b += seprintf(b, lastof(buffer), ", lateness: %d", Vehicle::Get(info.id)->lateness_counter);
output.print(buffer);
}

@ -48,7 +48,7 @@ bool Textbuf::CanDelChar(bool backspace)
* @param keycode Type of deletion, either WKC_BACKSPACE or WKC_DELETE
* @return Return true on successful change of Textbuf, or false otherwise
*/
bool Textbuf::DeleteChar(uint16 keycode)
bool Textbuf::DeleteChar(uint16_t keycode)
{
bool word = (keycode & WKC_CTRL) != 0;
@ -60,17 +60,17 @@ bool Textbuf::DeleteChar(uint16 keycode)
if (!CanDelChar(backspace)) return false;
char *s = this->buf + this->caretpos;
uint16 len = 0;
uint16_t len = 0;
if (word) {
/* Delete a complete word. */
if (backspace) {
/* Delete whitespace and word in front of the caret. */
len = this->caretpos - (uint16)this->char_iter->Prev(StringIterator::ITER_WORD);
len = this->caretpos - (uint16_t)this->char_iter->Prev(StringIterator::ITER_WORD);
s -= len;
} else {
/* Delete word and following whitespace following the caret. */
len = (uint16)this->char_iter->Next(StringIterator::ITER_WORD) - this->caretpos;
len = (uint16_t)this->char_iter->Next(StringIterator::ITER_WORD) - this->caretpos;
}
/* Update character count. */
for (const char *ss = s; ss < s + len; Utf8Consume(&ss)) {
@ -81,12 +81,12 @@ bool Textbuf::DeleteChar(uint16 keycode)
if (backspace) {
/* Delete the last code point in front of the caret. */
s = Utf8PrevChar(s);
WChar c;
len = (uint16)Utf8Decode(&c, s);
char32_t c;
len = (uint16_t)Utf8Decode(&c, s);
this->chars--;
} else {
/* Delete the complete character following the caret. */
len = (uint16)this->char_iter->Next(StringIterator::ITER_CHARACTER) - this->caretpos;
len = (uint16_t)this->char_iter->Next(StringIterator::ITER_CHARACTER) - this->caretpos;
/* Update character count. */
for (const char *ss = s; ss < s + len; Utf8Consume(&ss)) {
this->chars--;
@ -128,9 +128,9 @@ void Textbuf::DeleteAll()
* @param key Character to be inserted
* @return Return true on successful change of Textbuf, or false otherwise
*/
bool Textbuf::InsertChar(WChar key)
bool Textbuf::InsertChar(char32_t key)
{
uint16 len = (uint16)Utf8CharLen(key);
uint16_t len = (uint16_t)Utf8CharLen(key);
if (this->bytes + len <= this->max_bytes && this->chars + 1 <= this->max_chars) {
memmove(this->buf + this->caretpos + len, this->buf + this->caretpos, this->bytes - this->caretpos);
Utf8Encode(this->buf + this->caretpos, key);
@ -160,7 +160,7 @@ bool Textbuf::InsertChar(WChar key)
*/
bool Textbuf::InsertString(const char *str, bool marked, const char *caret, const char *insert_location, const char *replacement_end)
{
uint16 insertpos = (marked && this->marklength != 0) ? this->markpos : this->caretpos;
uint16_t insertpos = (marked && this->marklength != 0) ? this->markpos : this->caretpos;
if (insert_location != nullptr) {
insertpos = insert_location - this->buf;
if (insertpos > this->bytes) return false;
@ -174,8 +174,8 @@ bool Textbuf::InsertString(const char *str, bool marked, const char *caret, cons
if (str == nullptr) return false;
uint16 bytes = 0, chars = 0;
WChar c;
uint16_t bytes = 0, chars = 0;
char32_t c;
for (const char *ptr = str; (c = Utf8Consume(&ptr)) != '\0';) {
if (!IsValidChar(c, this->afilter)) break;
@ -235,7 +235,7 @@ bool Textbuf::InsertClipboard()
* @param to End of the text to delete.
* @param update Set to true if the internal state should be updated.
*/
void Textbuf::DeleteText(uint16 from, uint16 to, bool update)
void Textbuf::DeleteText(uint16_t from, uint16_t to, bool update)
{
uint c = 0;
const char *s = this->buf + from;
@ -299,7 +299,7 @@ void Textbuf::UpdateStringIter()
{
this->char_iter->SetString(this->buf);
size_t pos = this->char_iter->SetCurPosition(this->caretpos);
this->caretpos = pos == StringIterator::END ? 0 : (uint16)pos;
this->caretpos = pos == StringIterator::END ? 0 : (uint16_t)pos;
}
/** Update pixel width of the text. */
@ -331,7 +331,7 @@ void Textbuf::UpdateMarkedText()
* @param keycode Direction in which navigation occurs (WKC_CTRL |) WKC_LEFT, (WKC_CTRL |) WKC_RIGHT, WKC_END, WKC_HOME
* @return Return true on successful change of Textbuf, or false otherwise
*/
bool Textbuf::MovePos(uint16 keycode)
bool Textbuf::MovePos(uint16_t keycode)
{
switch (keycode) {
case WKC_LEFT:
@ -341,7 +341,7 @@ bool Textbuf::MovePos(uint16 keycode)
size_t pos = this->char_iter->Prev(keycode & WKC_CTRL ? StringIterator::ITER_WORD : StringIterator::ITER_CHARACTER);
if (pos == StringIterator::END) return true;
this->caretpos = (uint16)pos;
this->caretpos = (uint16_t)pos;
this->UpdateCaretPosition();
return true;
}
@ -353,7 +353,7 @@ bool Textbuf::MovePos(uint16 keycode)
size_t pos = this->char_iter->Next(keycode & WKC_CTRL ? StringIterator::ITER_WORD : StringIterator::ITER_CHARACTER);
if (pos == StringIterator::END) return true;
this->caretpos = (uint16)pos;
this->caretpos = (uint16_t)pos;
this->UpdateCaretPosition();
return true;
}
@ -383,7 +383,7 @@ bool Textbuf::MovePos(uint16 keycode)
* @param max_bytes maximum size in bytes, including terminating '\0'
* @param max_chars maximum size in chars, including terminating '\0'
*/
Textbuf::Textbuf(uint16 max_bytes, uint16 max_chars)
Textbuf::Textbuf(uint16_t max_bytes, uint16_t max_chars)
: buf(MallocT<char>(max_bytes)), char_iter(StringIterator::Create())
{
assert(max_bytes != 0);
@ -407,27 +407,26 @@ Textbuf::~Textbuf()
*/
void Textbuf::Assign(StringID string)
{
GetString(this->buf, string, &this->buf[this->max_bytes - 1]);
this->UpdateSize();
this->Assign(GetString(string));
}
/**
* Copy a string into the textbuffer.
* @param text Source.
*/
void Textbuf::Assign(const char *text)
void Textbuf::Assign(const std::string_view text)
{
strecpy(this->buf, text, &this->buf[this->max_bytes - 1]);
this->UpdateSize();
}
const char *last_of = &this->buf[this->max_bytes - 1];
strecpy(this->buf, text.data(), last_of);
StrMakeValidInPlace(this->buf, last_of, SVS_NONE);
/* Make sure the name isn't too long for the text buffer in the number of
* characters (not bytes). max_chars also counts the '\0' characters. */
while (Utf8StringLength(this->buf) + 1 > this->max_chars) {
*Utf8PrevChar(this->buf + strlen(this->buf)) = '\0';
}
/**
* Copy a string into the textbuffer.
* @param text Source.
*/
void Textbuf::Assign(const std::string &text)
{
this->Assign(text.c_str());
this->UpdateSize();
}
/**
@ -435,10 +434,20 @@ void Textbuf::Assign(const std::string &text)
*/
void Textbuf::Print(const char *format, ...)
{
const char *last_of = &this->buf[this->max_bytes - 1];
va_list va;
va_start(va, format);
vseprintf(this->buf, &this->buf[this->max_bytes - 1], format, va);
vseprintf(this->buf, last_of, format, va);
va_end(va);
StrMakeValidInPlace(this->buf, last_of, SVS_NONE);
/* Make sure the name isn't too long for the text buffer in the number of
* characters (not bytes). max_chars also counts the '\0' characters. */
while (Utf8StringLength(this->buf) + 1 > this->max_chars) {
*Utf8PrevChar(this->buf + strlen(this->buf)) = '\0';
}
this->UpdateSize();
}
@ -454,7 +463,7 @@ void Textbuf::UpdateSize()
this->chars = this->bytes = 1; // terminating zero
WChar c;
char32_t c;
while ((c = Utf8Consume(&buf)) != '\0') {
this->bytes += Utf8CharLen(c);
this->chars++;
@ -486,7 +495,7 @@ bool Textbuf::HandleCaret()
return false;
}
HandleKeyPressResult Textbuf::HandleKeyPress(WChar key, uint16 keycode)
HandleKeyPressResult Textbuf::HandleKeyPress(char32_t key, uint16_t keycode)
{
bool edited = false;

@ -30,37 +30,36 @@ enum HandleKeyPressResult
struct Textbuf {
CharSetFilter afilter; ///< Allowed characters
char * const buf; ///< buffer in which text is saved
uint16 max_bytes; ///< the maximum size of the buffer in bytes (including terminating '\0')
uint16 max_chars; ///< the maximum size of the buffer in characters (including terminating '\0')
uint16 bytes; ///< the current size of the string in bytes (including terminating '\0')
uint16 chars; ///< the current size of the string in characters (including terminating '\0')
uint16 pixels; ///< the current size of the string in pixels
uint16_t max_bytes; ///< the maximum size of the buffer in bytes (including terminating '\0')
uint16_t max_chars; ///< the maximum size of the buffer in characters (including terminating '\0')
uint16_t bytes; ///< the current size of the string in bytes (including terminating '\0')
uint16_t chars; ///< the current size of the string in characters (including terminating '\0')
uint16_t pixels; ///< the current size of the string in pixels
bool caret; ///< is the caret ("_") visible or not
uint16 caretpos; ///< the current position of the caret in the buffer, in bytes
uint16 caretxoffs; ///< the current position of the caret in pixels
uint16 markpos; ///< the start position of the marked area in the buffer, in bytes
uint16 markend; ///< the end position of the marked area in the buffer, in bytes
uint16 markxoffs; ///< the start position of the marked area in pixels
uint16 marklength; ///< the length of the marked area in pixels
explicit Textbuf(uint16 max_bytes, uint16 max_chars = UINT16_MAX);
uint16_t caretpos; ///< the current position of the caret in the buffer, in bytes
uint16_t caretxoffs; ///< the current position of the caret in pixels
uint16_t markpos; ///< the start position of the marked area in the buffer, in bytes
uint16_t markend; ///< the end position of the marked area in the buffer, in bytes
uint16_t markxoffs; ///< the start position of the marked area in pixels
uint16_t marklength; ///< the length of the marked area in pixels
explicit Textbuf(uint16_t max_bytes, uint16_t max_chars = UINT16_MAX);
~Textbuf();
void Assign(StringID string);
void Assign(const char *text);
void Assign(const std::string &text);
void Assign(const std::string_view text);
void CDECL Print(const char *format, ...) WARN_FORMAT(2, 3);
void DeleteAll();
bool InsertClipboard();
bool InsertChar(WChar key);
bool InsertChar(char32_t key);
bool InsertString(const char *str, bool marked, const char *caret = nullptr, const char *insert_location = nullptr, const char *replacement_end = nullptr);
bool DeleteChar(uint16 keycode);
bool MovePos(uint16 keycode);
bool DeleteChar(uint16_t keycode);
bool MovePos(uint16_t keycode);
HandleKeyPressResult HandleKeyPress(WChar key, uint16 keycode);
HandleKeyPressResult HandleKeyPress(char32_t key, uint16_t keycode);
bool HandleCaret();
void UpdateSize();
@ -74,7 +73,7 @@ private:
bool CanDelChar(bool backspace);
void DeleteText(uint16 from, uint16 to, bool update);
void DeleteText(uint16_t from, uint16_t to, bool update);
void UpdateStringIter();
void UpdateWidth();

@ -252,9 +252,7 @@ uint64 Town::LabelParam2() const
void Town::FillCachedName() const
{
char buf[MAX_LENGTH_TOWN_NAME_CHARS * MAX_CHAR_LENGTH];
char *end = GetTownName(buf, this, lastof(buf));
this->cached_name.assign(buf, end);
this->cached_name = GetTownName(this);
}
/**

@ -1346,8 +1346,7 @@ public:
if (!this->townnamevalid) {
this->townname_editbox.text.DeleteAll();
} else {
GetTownName(this->townname_editbox.text.buf, &this->params, this->townnameparts, &this->townname_editbox.text.buf[this->townname_editbox.text.max_bytes - 1]);
this->townname_editbox.text.UpdateSize();
this->townname_editbox.text.Assign(GetTownName(&this->params, this->townnameparts));
}
UpdateOSKOriginalText(this, WID_TF_TOWN_NAME_EDITBOX);
@ -1384,9 +1383,8 @@ public:
name = this->townname_editbox.text.buf;
} else {
/* If user changed the name, send it */
char buf[MAX_LENGTH_TOWN_NAME_CHARS * MAX_CHAR_LENGTH];
GetTownName(buf, &this->params, this->townnameparts, lastof(buf));
if (strcmp(buf, this->townname_editbox.text.buf) != 0) name = this->townname_editbox.text.buf;
std::string original_name = GetTownName(&this->params, this->townnameparts);
if (original_name != this->townname_editbox.text.buf) name = this->townname_editbox.text.buf;
}
bool success = DoCommandP(tile, this->town_size | this->city << 2 | this->town_layout << 3 | random << 6,
@ -1558,9 +1556,7 @@ public:
const GRFFile *gf = HouseSpec::Get(this->GetHouseAtOffset(house_set, 0))->grf_prop.grffile;
if (gf != nullptr) return GetGRFConfig(gf->grfid)->GetName();
static char name[DRAW_STRING_BUFFER];
GetString(name, STR_BASIC_HOUSE_SET_NAME, lastof(name));
return name;
return GetStringPtr(STR_BASIC_HOUSE_SET_NAME);
}
/**
@ -1812,8 +1808,7 @@ public:
}
case WID_HP_HOUSE_ACCEPTANCE: {
static char buff[DRAW_STRING_BUFFER] = "";
char *str = buff;
std::string buff;
CargoArray cargo{};
CargoTypes dummy = 0;
AddAcceptedHouseCargo(this->display_house, INVALID_TILE, cargo, &dummy);
@ -1823,10 +1818,10 @@ public:
SetDParam(0, cargo[i] < 8 ? STR_HOUSE_BUILD_CARGO_VALUE_EIGHTS : STR_HOUSE_BUILD_CARGO_VALUE_JUST_NAME);
SetDParam(1, cargo[i]);
SetDParam(2, CargoSpec::Get(i)->name);
str = GetString(str, str == buff ? STR_HOUSE_BUILD_CARGO_FIRST : STR_HOUSE_BUILD_CARGO_SEPARATED, lastof(buff));
GetString(StringBuilder(buff), buff.empty() ? STR_HOUSE_BUILD_CARGO_FIRST : STR_HOUSE_BUILD_CARGO_SEPARATED);
}
if (str == buff) GetString(buff, STR_JUST_NOTHING, lastof(buff));
SetDParamStr(0, buff);
if (buff.empty()) GetString(StringBuilder(buff), STR_JUST_NOTHING);
SetDParamStr(0, std::move(buff));
break;
}

File diff suppressed because it is too large Load Diff

@ -13,10 +13,9 @@
#include "core/random_func.hpp"
#include "townname_type.h"
char *GenerateTownNameString(char *buf, const char *last, size_t lang, uint32 seed);
char *GetTownName(char *buff, const TownNameParams *par, uint32 townnameparts, const char *last);
char *GetTownName(char *buff, const Town *t, const char *last);
bool VerifyTownName(uint32 r, const TownNameParams *par, TownNames *town_names = nullptr);
bool GenerateTownName(Randomizer &randomizer, uint32 *townnameparts, TownNames *town_names = nullptr);
std::string GetTownName(const TownNameParams *par, uint32_t townnameparts);
std::string GetTownName(const Town *t);
bool VerifyTownName(uint32_t r, const TownNameParams *par, TownNames *town_names = nullptr);
bool GenerateTownName(Randomizer &randomizer, uint32_t *townnameparts, TownNames *town_names = nullptr);
#endif /* TOWNNAME_FUNC_H */

@ -28,8 +28,8 @@ static constexpr uint BUILTIN_TOWNNAME_GENERATOR_COUNT = SPECSTR_TOWNNAME_LAST -
* Speeds things up a bit because these values are computed only once per name generation.
*/
struct TownNameParams {
uint32 grfid; ///< newgrf ID (0 if not used)
uint16 type; ///< town name style
uint32_t grfid; ///< newgrf ID (0 if not used)
uint16_t type; ///< town name style
/**
* Initializes this struct from language ID

@ -1205,10 +1205,8 @@ static void DrawInstructionString(const TraceRestrictProgram *prog, TraceRestric
SetDParam(1, selected ? STR_TRACE_RESTRICT_WHITE : STR_EMPTY);
} else {
auto insert_warning = [&](uint dparam_index, StringID warning) {
char buf[256];
auto tmp_params = MakeParameters(GetDParam(dparam_index));
char *end = GetStringWithArgs(buf, warning, tmp_params, lastof(buf));
_temp_special_strings[0].assign(buf, end);
_temp_special_strings[0] = GetStringWithArgs(warning, tmp_params);
SetDParam(dparam_index, SPECSTR_TEMP_START);
};

@ -425,16 +425,11 @@ void ShowNewGrfVehicleError(EngineID engine, StringID part1, StringID part2, GRF
if (!_networking) DoCommand(0, critical ? PM_PAUSED_ERROR : PM_PAUSED_NORMAL, 1, DC_EXEC, CMD_PAUSE);
}
/* debug output */
char buffer[512];
SetDParamStr(0, grfconfig->GetName());
GetString(buffer, part1, lastof(buffer));
DEBUG(grf, 0, "%s", buffer + 3);
DEBUG(grf, 0, "%s", strip_leading_colours(GetString(part1)));
SetDParam(1, engine);
GetString(buffer, part2, lastof(buffer));
DEBUG(grf, 0, "%s", buffer + 3);
DEBUG(grf, 0, "%s", strip_leading_colours(GetString(part2)));
}
/**
@ -4642,7 +4637,7 @@ void DumpVehicleStats(char *buffer, const char *last)
for (auto &it : cstatmap) {
buffer += seprintf(buffer, last, "%u: ", (uint) it.first);
SetDParam(0, it.first);
buffer = GetString(buffer, STR_COMPANY_NAME, last);
buffer = strecpy(buffer, GetString(STR_COMPANY_NAME).c_str(), last, true);
buffer += seprintf(buffer, last, "\n");
auto line = [&](vtypestats &vs, const char *type) {

@ -987,7 +987,6 @@ struct RefitWindow : public Window {
{
std::string &name = this->ship_part_names[v->index];
if (name.empty()) {
char buffer[128] = "";
const Vehicle *front = v->First();
uint offset = 0;
for (const Vehicle *u = front; u != v; u = u->Next()) offset++;
@ -997,14 +996,11 @@ struct RefitWindow : public Window {
assert(grffile != nullptr);
StartTextRefStackUsage(grffile, 6);
char *end = GetString(buffer, GetGRFStringID(grffile->grfid, 0xD000 + callback), lastof(buffer));
name = GetString(GetGRFStringID(grffile->grfid, 0xD000 + callback));
StopTextRefStackUsage();
name.assign(buffer, end - buffer);
} else {
SetDParam(0, offset + 1);
char *end = GetString(buffer, STR_REFIT_SHIP_PART, lastof(buffer));
name.assign(buffer, end - buffer);
name = GetString(STR_REFIT_SHIP_PART);
}
}
return name;
@ -3201,18 +3197,14 @@ struct VehicleDetailsWindow : Window {
std::vector<TraceRestrictSlotID> slots;
TraceRestrictGetVehicleSlots(v->index, slots);
char text_buffer[512];
char *buffer = text_buffer;
const char * const last = lastof(text_buffer);
SetDParam(0, slots.size());
buffer = GetString(buffer, STR_TRACE_RESTRICT_SLOT_LIST_HEADER, last);
std::string buffer = GetString(STR_TRACE_RESTRICT_SLOT_LIST_HEADER);
for (size_t i = 0; i < slots.size(); i++) {
if (i != 0) buffer = GetString(buffer, STR_TRACE_RESTRICT_SLOT_LIST_SEPARATOR, last);
buffer = strecpy(buffer, TraceRestrictSlot::Get(slots[i])->name.c_str(), last);
if (i != 0) GetString(StringBuilder(buffer), STR_TRACE_RESTRICT_SLOT_LIST_SEPARATOR);
buffer += TraceRestrictSlot::Get(slots[i])->name;
}
SetDParamStr(0, text_buffer);
DrawString(tr, STR_JUST_RAW_STRING);
DrawString(tr, buffer);
tr.top += GetCharacterHeight(FS_NORMAL);
}

@ -1950,15 +1950,16 @@ void ViewportSign::UpdatePosition(ZoomLevel maxzoom, int center, int top, String
this->top = top;
char buffer[DRAW_STRING_BUFFER];
std::string buffer;
GetString(buffer, str, lastof(buffer));
GetString(StringBuilder(buffer), str);
this->width_normal = WidgetDimensions::scaled.fullbevel.left + Align(GetStringBoundingBox(buffer).width, 2) + WidgetDimensions::scaled.fullbevel.right;
this->center = center;
/* zoomed out version */
if (str_small != STR_NULL) {
GetString(buffer, str_small, lastof(buffer));
buffer.clear();
GetString(StringBuilder(buffer), str_small);
}
this->width_small = WidgetDimensions::scaled.fullbevel.left + Align(GetStringBoundingBox(buffer, FS_SMALL).width, 2) + WidgetDimensions::scaled.fullbevel.right;

Loading…
Cancel
Save