Changeset - r27615:4608ed940341
[Not reviewed]
master
0 5 0
Rubidium - 17 months ago 2023-06-13 21:46:08
rubidium@openttd.org
Codechange: make creating temporary StringParameters easier
5 files changed with 76 insertions and 93 deletions:
0 comments (0 inline, 0 general)
src/industry_cmd.cpp
Show inline comments
 
@@ -2410,50 +2410,49 @@ static void UpdateIndustryStatistics(Ind
 
			std::rotate(std::rbegin(p.history), std::rbegin(p.history) + 1, std::rend(p.history));
 
			p.history[THIS_MONTH].production = 0;
 
			p.history[THIS_MONTH].transported = 0;
 
		}
 
	}
 
}
 

	
 
/**
 
 * Recompute #production_rate for current #prod_level.
 
 * This function is only valid when not using smooth economy.
 
 */
 
void Industry::RecomputeProductionMultipliers()
 
{
 
	const IndustrySpec *indspec = GetIndustrySpec(this->type);
 
	assert(indspec->UsesOriginalEconomy());
 

	
 
	/* Rates are rounded up, so e.g. oilrig always produces some passengers */
 
	for (auto &p : this->produced) {
 
		p.rate = ClampTo<uint8_t>(CeilDiv(indspec->production_rate[&p - this->produced.data()] * this->prod_level, PRODLEVEL_DEFAULT));
 
	}
 
}
 

	
 
void Industry::FillCachedName() const
 
{
 
	int64 args_array[] = { this->index };
 
	StringParameters tmp_params(args_array);
 
	auto tmp_params = MakeParameters(this->index);
 
	this->cached_name = GetStringWithArgs(STR_INDUSTRY_NAME, tmp_params);
 
}
 

	
 
void ClearAllIndustryCachedNames()
 
{
 
	for (Industry *ind : Industry::Iterate()) {
 
		ind->cached_name.clear();
 
	}
 
}
 

	
 
/**
 
 * Set the #probability and #min_number fields for the industry type \a it for a running game.
 
 * @param it Industry type.
 
 * @return At least one of the fields has changed value.
 
 */
 
bool IndustryTypeBuildData::GetIndustryTypeData(IndustryType it)
 
{
 
	byte min_number;
 
	uint32 probability = GetIndustryGamePlayProbability(it, &min_number);
 
	bool changed = min_number != this->min_number || probability != this->probability;
 
	this->min_number = min_number;
 
	this->probability = probability;
 
	return changed;
 
}
src/station_cmd.cpp
Show inline comments
 
@@ -440,50 +440,49 @@ void Station::UpdateVirtCoord()
 
 * Move the station main coordinate somewhere else.
 
 * @param new_xy new tile location of the sign
 
 */
 
void Station::MoveSign(TileIndex new_xy)
 
{
 
	if (this->xy == new_xy) return;
 

	
 
	_station_kdtree.Remove(this->index);
 

	
 
	this->BaseStation::MoveSign(new_xy);
 

	
 
	_station_kdtree.Insert(this->index);
 
}
 

	
 
/** Update the virtual coords needed to draw the station sign for all stations. */
 
void UpdateAllStationVirtCoords()
 
{
 
	for (BaseStation *st : BaseStation::Iterate()) {
 
		st->UpdateVirtCoord();
 
	}
 
}
 

	
 
void BaseStation::FillCachedName() const
 
{
 
	int64 args_array[] = { this->index };
 
	StringParameters tmp_params(args_array);
 
	auto tmp_params = MakeParameters(this->index);
 
	this->cached_name = GetStringWithArgs(Waypoint::IsExpected(this) ? STR_WAYPOINT_NAME : STR_STATION_NAME, tmp_params);
 
}
 

	
 
void ClearAllStationCachedNames()
 
{
 
	for (BaseStation *st : BaseStation::Iterate()) {
 
		st->cached_name.clear();
 
	}
 
}
 

	
 
/**
 
 * Get a mask of the cargo types that the station accepts.
 
 * @param st Station to query
 
 * @return the expected mask
 
 */
 
static CargoTypes GetAcceptanceMask(const Station *st)
 
{
 
	CargoTypes mask = 0;
 

	
 
	for (CargoID i = 0; i < NUM_CARGO; i++) {
 
		if (HasBit(st->goods[i].status, GoodsEntry::GES_ACCEPTANCE)) SetBit(mask, i);
 
	}
 
	return mask;
 
}
src/strings.cpp
Show inline comments
 
@@ -318,60 +318,60 @@ std::string GetString(StringID string)
 
	return GetStringWithArgs(string, _global_string_params);
 
}
 

	
 
/**
 
 * Get a parsed string with most special stringcodes replaced by the string parameters.
 
 * @param string The ID of the string to parse.
 
 * @param args   Arguments for the string.
 
 * @return The parsed string.
 
 */
 
std::string GetStringWithArgs(StringID string, StringParameters &args)
 
{
 
	std::string result;
 
	StringBuilder builder(result);
 
	GetStringWithArgs(builder, string, args);
 
	return result;
 
}
 

	
 
/**
 
 * This function is used to "bind" a C string to a OpenTTD dparam slot.
 
 * @param n slot of the string
 
 * @param str string to bind
 
 */
 
void SetDParamStr(size_t n, const char *str)
 
{
 
	SetDParam(n, (uint64)(size_t)str);
 
	_global_string_params.SetParam(n, str);
 
}
 

	
 
/**
 
 * This function is used to "bind" the C string of a std::string to a OpenTTD dparam slot.
 
 * The caller has to ensure that the std::string reference remains valid while the string is shown.
 
 * @param n slot of the string
 
 * @param str string to bind
 
 */
 
void SetDParamStr(size_t n, const std::string &str)
 
{
 
	SetDParamStr(n, str.c_str());
 
	_global_string_params.SetParam(n, str);
 
}
 

	
 
/**
 
 * Format a number into a string.
 
 * @param builder   the string builder to write to
 
 * @param number    the number to write down
 
 * @param last      the last element in the buffer
 
 * @param separator the thousands-separator to use
 
 * @param zerofill  minimum number of digits to print for the integer part. The number will be filled with zeros at the front if necessary.
 
 * @param fractional_digits number of fractional digits to display after a decimal separator. The decimal separator is inserted
 
 *                          in front of the \a fractional_digits last digit of \a number.
 
 */
 
static void FormatNumber(StringBuilder &builder, int64 number, const char *separator, int zerofill = 1, int fractional_digits = 0)
 
{
 
	static const int max_digits = 20;
 
	uint64 divisor = 10000000000000000000ULL;
 
	zerofill += fractional_digits;
 
	int thousands_offset = (max_digits - fractional_digits - 1) % 3;
 

	
 
	if (number < 0) {
 
		builder += '-';
 
		number = -number;
 
	}
 

	
 
@@ -440,71 +440,68 @@ static void FormatBytes(StringBuilder &b
 
	const char *decimal_separator = _settings_game.locale.digit_decimal_separator.c_str();
 
	if (StrEmpty(decimal_separator)) decimal_separator = _langpack.langpack->digit_decimal_separator;
 

	
 
	if (number < 1024) {
 
		id = 0;
 
		fmt::format_to(builder, "{}", number);
 
	} else if (number < 1024 * 10) {
 
		fmt::format_to(builder, "{}{}{:02}", number / 1024, decimal_separator, (number % 1024) * 100 / 1024);
 
	} else if (number < 1024 * 100) {
 
		fmt::format_to(builder, "{}{}{:01}", number / 1024, decimal_separator, (number % 1024) * 10 / 1024);
 
	} else {
 
		assert(number < 1024 * 1024);
 
		fmt::format_to(builder, "{}", number / 1024);
 
	}
 

	
 
	assert(id < lengthof(iec_prefixes));
 
	fmt::format_to(builder, NBSP "{}B", iec_prefixes[id]);
 
}
 

	
 
static void FormatYmdString(StringBuilder &builder, TimerGameCalendar::Date date, uint case_index)
 
{
 
	TimerGameCalendar::YearMonthDay ymd;
 
	TimerGameCalendar::ConvertDateToYMD(date, &ymd);
 

	
 
	int64 args[] = {ymd.day + STR_DAY_NUMBER_1ST - 1, STR_MONTH_ABBREV_JAN + ymd.month, ymd.year};
 
	StringParameters tmp_params(args);
 
	auto tmp_params = MakeParameters(ymd.day + STR_DAY_NUMBER_1ST - 1, STR_MONTH_ABBREV_JAN + ymd.month, ymd.year);
 
	FormatString(builder, GetStringPtr(STR_FORMAT_DATE_LONG), tmp_params, case_index);
 
}
 

	
 
static void FormatMonthAndYear(StringBuilder &builder, TimerGameCalendar::Date date, uint case_index)
 
{
 
	TimerGameCalendar::YearMonthDay ymd;
 
	TimerGameCalendar::ConvertDateToYMD(date, &ymd);
 

	
 
	int64 args[] = {STR_MONTH_JAN + ymd.month, ymd.year};
 
	StringParameters tmp_params(args);
 
	auto tmp_params = MakeParameters(STR_MONTH_JAN + ymd.month, ymd.year);
 
	FormatString(builder, GetStringPtr(STR_FORMAT_DATE_SHORT), tmp_params, case_index);
 
}
 

	
 
static void FormatTinyOrISODate(StringBuilder &builder, TimerGameCalendar::Date date, StringID str)
 
{
 
	TimerGameCalendar::YearMonthDay ymd;
 
	TimerGameCalendar::ConvertDateToYMD(date, &ymd);
 

	
 
	/* Day and month are zero-padded with ZEROFILL_NUM, hence the two 2s. */
 
	int64 args[] = {ymd.day, 2, ymd.month + 1, 2, ymd.year};
 
	StringParameters tmp_params(args);
 
	auto tmp_params = MakeParameters(ymd.day, 2, ymd.month + 1, 2, ymd.year);
 
	FormatString(builder, GetStringPtr(str), tmp_params);
 
}
 

	
 
static void FormatGenericCurrency(StringBuilder &builder, const CurrencySpec *spec, Money number, bool compact)
 
{
 
	/* We are going to make number absolute for printing, so
 
	 * keep this piece of data as we need it later on */
 
	bool negative = number < 0;
 
	const char *multiplier = "";
 

	
 
	number *= spec->rate;
 

	
 
	/* convert from negative */
 
	if (number < 0) {
 
		builder.Utf8Encode(SCC_PUSH_COLOUR);
 
		builder.Utf8Encode(SCC_RED);
 
		builder += '-';
 
		number = -number;
 
	}
 

	
 
	/* Add prefix part, following symbol_pos specification.
 
	 * Here, it can can be either 0 (prefix) or 2 (both prefix and suffix).
 
	 * The only remaining value is 1 (suffix), so everything that is not 1 */
 
	if (spec->symbol_pos != 1) builder += spec->prefix;
 
@@ -1192,58 +1189,56 @@ static void FormatString(StringBuilder &
 
						amount = _units_volume[_settings_game.locale.units_volume].c.ToDisplay(args.GetInt64());
 
						break;
 

	
 
					default: {
 
						amount = args.GetInt64();
 
						break;
 
					}
 
				}
 

	
 
				FormatCommaNumber(builder, amount);
 
				break;
 
			}
 

	
 
			case SCC_CARGO_SHORT: { // {CARGO_SHORT}
 
				/* Short description of cargotypes. Layout:
 
				 * param 1: cargo type
 
				 * param 2: cargo count */
 
				CargoID cargo = args.GetInt32();
 
				if (cargo >= CargoSpec::GetArraySize()) break;
 

	
 
				StringID cargo_str = CargoSpec::Get(cargo)->units_volume;
 
				switch (cargo_str) {
 
					case STR_TONS: {
 
						assert(_settings_game.locale.units_weight < lengthof(_units_weight));
 
						int64 args_array[] = {_units_weight[_settings_game.locale.units_weight].c.ToDisplay(args.GetInt64())};
 
						StringParameters tmp_params(args_array);
 
						auto tmp_params = MakeParameters(_units_weight[_settings_game.locale.units_weight].c.ToDisplay(args.GetInt64()));
 
						FormatString(builder, GetStringPtr(_units_weight[_settings_game.locale.units_weight].l), tmp_params);
 
						break;
 
					}
 

	
 
					case STR_LITERS: {
 
						assert(_settings_game.locale.units_volume < lengthof(_units_volume));
 
						int64 args_array[] = {_units_volume[_settings_game.locale.units_volume].c.ToDisplay(args.GetInt64())};
 
						StringParameters tmp_params(args_array);
 
						auto tmp_params = MakeParameters(_units_volume[_settings_game.locale.units_volume].c.ToDisplay(args.GetInt64()));
 
						FormatString(builder, GetStringPtr(_units_volume[_settings_game.locale.units_volume].l), tmp_params);
 
						break;
 
					}
 

	
 
					default: {
 
						StringParameters tmp_params(args, 1);
 
						GetStringWithArgs(builder, cargo_str, tmp_params);
 
						break;
 
					}
 
				}
 
				break;
 
			}
 

	
 
			case SCC_CARGO_LONG: { // {CARGO_LONG}
 
				/* First parameter is cargo type, second parameter is cargo count */
 
				CargoID cargo = args.GetInt32();
 
				if (IsValidCargoID(cargo) && cargo >= CargoSpec::GetArraySize()) break;
 

	
 
				StringID cargo_str = !IsValidCargoID(cargo) ? STR_QUANTITY_N_A : CargoSpec::Get(cargo)->quantifier;
 
				StringParameters tmp_args(args, 1);
 
				GetStringWithArgs(builder, cargo_str, tmp_args);
 
				break;
 
			}
 

	
 
@@ -1279,395 +1274,364 @@ static void FormatString(StringBuilder &
 
				FormatGenericCurrency(builder, _currency, args.GetInt64(), false);
 
				break;
 

	
 
			case SCC_DATE_TINY: // {DATE_TINY}
 
				FormatTinyOrISODate(builder, args.GetInt32(), STR_FORMAT_DATE_TINY);
 
				break;
 

	
 
			case SCC_DATE_SHORT: // {DATE_SHORT}
 
				FormatMonthAndYear(builder, args.GetInt32(), next_substr_case_index);
 
				next_substr_case_index = 0;
 
				break;
 

	
 
			case SCC_DATE_LONG: // {DATE_LONG}
 
				FormatYmdString(builder, args.GetInt32(), next_substr_case_index);
 
				next_substr_case_index = 0;
 
				break;
 

	
 
			case SCC_DATE_ISO: // {DATE_ISO}
 
				FormatTinyOrISODate(builder, args.GetInt32(), STR_FORMAT_DATE_ISO);
 
				break;
 

	
 
			case SCC_FORCE: { // {FORCE}
 
				assert(_settings_game.locale.units_force < lengthof(_units_force));
 
				const auto &x = _units_force[_settings_game.locale.units_force];
 
				int64 args_array[] = {x.c.ToDisplay(args.GetInt64()), x.decimal_places};
 
				StringParameters tmp_params(args_array);
 
				auto tmp_params = MakeParameters(x.c.ToDisplay(args.GetInt64()), x.decimal_places);
 
				FormatString(builder, GetStringPtr(x.s), tmp_params);
 
				break;
 
			}
 

	
 
			case SCC_HEIGHT: { // {HEIGHT}
 
				assert(_settings_game.locale.units_height < lengthof(_units_height));
 
				const auto &x = _units_height[_settings_game.locale.units_height];
 
				int64 args_array[] = {x.c.ToDisplay(args.GetInt64()), x.decimal_places};
 
				StringParameters tmp_params(args_array);
 
				auto tmp_params = MakeParameters(x.c.ToDisplay(args.GetInt64()), x.decimal_places);
 
				FormatString(builder, GetStringPtr(x.s), tmp_params);
 
				break;
 
			}
 

	
 
			case SCC_POWER: { // {POWER}
 
				assert(_settings_game.locale.units_power < lengthof(_units_power));
 
				const auto &x = _units_power[_settings_game.locale.units_power];
 
				int64 args_array[] = {x.c.ToDisplay(args.GetInt64()), x.decimal_places};
 
				StringParameters tmp_params(args_array);
 
				auto tmp_params = MakeParameters(x.c.ToDisplay(args.GetInt64()), x.decimal_places);
 
				FormatString(builder, GetStringPtr(x.s), tmp_params);
 
				break;
 
			}
 

	
 
			case SCC_POWER_TO_WEIGHT: { // {POWER_TO_WEIGHT}
 
				auto setting = _settings_game.locale.units_power * 3u + _settings_game.locale.units_weight;
 
				assert(setting < lengthof(_units_power_to_weight));
 
				const auto &x = _units_power_to_weight[setting];
 
				int64 args_array[] = {x.c.ToDisplay(args.GetInt64()), x.decimal_places};
 
				StringParameters tmp_params(args_array);
 
				auto tmp_params = MakeParameters(x.c.ToDisplay(args.GetInt64()), x.decimal_places);
 
				FormatString(builder, GetStringPtr(x.s), tmp_params);
 
				break;
 
			}
 

	
 
			case SCC_VELOCITY: { // {VELOCITY}
 
				int64 arg = args.GetInt64();
 
				// Unpack vehicle type from packed argument to get desired units.
 
				VehicleType vt = static_cast<VehicleType>(GB(arg, 56, 8));
 
				byte units = GetVelocityUnits(vt);
 
				assert(units < lengthof(_units_velocity));
 
				const auto &x = _units_velocity[units];
 
				int64 args_array[] = {ConvertKmhishSpeedToDisplaySpeed(GB(arg, 0, 56), vt), x.decimal_places};
 
				StringParameters tmp_params(args_array);
 
				auto tmp_params = MakeParameters(ConvertKmhishSpeedToDisplaySpeed(GB(arg, 0, 56), vt), x.decimal_places);
 
				FormatString(builder, GetStringPtr(x.s), tmp_params);
 
				break;
 
			}
 

	
 
			case SCC_VOLUME_SHORT: { // {VOLUME_SHORT}
 
				assert(_settings_game.locale.units_volume < lengthof(_units_volume));
 
				const auto &x = _units_volume[_settings_game.locale.units_volume];
 
				int64 args_array[] = {x.c.ToDisplay(args.GetInt64()), x.decimal_places};
 
				StringParameters tmp_params(args_array);
 
				auto tmp_params = MakeParameters(x.c.ToDisplay(args.GetInt64()), x.decimal_places);
 
				FormatString(builder, GetStringPtr(x.s), tmp_params);
 
				break;
 
			}
 

	
 
			case SCC_VOLUME_LONG: { // {VOLUME_LONG}
 
				assert(_settings_game.locale.units_volume < lengthof(_units_volume));
 
				const auto &x = _units_volume[_settings_game.locale.units_volume];
 
				int64 args_array[] = {x.c.ToDisplay(args.GetInt64()), x.decimal_places};
 
				StringParameters tmp_params(args_array);
 
				auto tmp_params = MakeParameters(x.c.ToDisplay(args.GetInt64()), x.decimal_places);
 
				FormatString(builder, GetStringPtr(x.l), tmp_params);
 
				break;
 
			}
 

	
 
			case SCC_WEIGHT_SHORT: { // {WEIGHT_SHORT}
 
				assert(_settings_game.locale.units_weight < lengthof(_units_weight));
 
				const auto &x = _units_weight[_settings_game.locale.units_weight];
 
				int64 args_array[] = {x.c.ToDisplay(args.GetInt64()), x.decimal_places};
 
				StringParameters tmp_params(args_array);
 
				auto tmp_params = MakeParameters(x.c.ToDisplay(args.GetInt64()), x.decimal_places);
 
				FormatString(builder, GetStringPtr(x.s), tmp_params);
 
				break;
 
			}
 

	
 
			case SCC_WEIGHT_LONG: { // {WEIGHT_LONG}
 
				assert(_settings_game.locale.units_weight < lengthof(_units_weight));
 
				const auto &x = _units_weight[_settings_game.locale.units_weight];
 
				int64 args_array[] = {x.c.ToDisplay(args.GetInt64()), x.decimal_places};
 
				StringParameters tmp_params(args_array);
 
				auto tmp_params = MakeParameters(x.c.ToDisplay(args.GetInt64()), x.decimal_places);
 
				FormatString(builder, GetStringPtr(x.l), tmp_params);
 
				break;
 
			}
 

	
 
			case SCC_COMPANY_NAME: { // {COMPANY}
 
				const Company *c = Company::GetIfValid(args.GetInt32());
 
				if (c == nullptr) break;
 

	
 
				if (!c->name.empty()) {
 
					int64 args_array[] = {(int64)(size_t)c->name.c_str()};
 
					StringParameters tmp_params(args_array);
 
					auto tmp_params = MakeParameters(c->name);
 
					GetStringWithArgs(builder, STR_JUST_RAW_STRING, tmp_params);
 
				} else {
 
					int64 args_array[] = {c->name_2};
 
					StringParameters tmp_params(args_array);
 
					auto tmp_params = MakeParameters(c->name_2);
 
					GetStringWithArgs(builder, c->name_1, tmp_params);
 
				}
 
				break;
 
			}
 

	
 
			case SCC_COMPANY_NUM: { // {COMPANY_NUM}
 
				CompanyID company = (CompanyID)args.GetInt32();
 

	
 
				/* Nothing is added for AI or inactive companies */
 
				if (Company::IsValidHumanID(company)) {
 
					int64 args_array[] = {company + 1};
 
					StringParameters tmp_params(args_array);
 
					auto tmp_params = MakeParameters(company + 1);
 
					GetStringWithArgs(builder, STR_FORMAT_COMPANY_NUM, tmp_params);
 
				}
 
				break;
 
			}
 

	
 
			case SCC_DEPOT_NAME: { // {DEPOT}
 
				VehicleType vt = (VehicleType)args.GetInt32();
 
				if (vt == VEH_AIRCRAFT) {
 
					uint64 args_array[] = {(uint64)args.GetInt32()};
 
					WChar types_array[] = {SCC_STATION_NAME};
 
					StringParameters tmp_params(args_array, 1, types_array);
 
					GetStringWithArgs(builder, STR_FORMAT_DEPOT_NAME_AIRCRAFT, tmp_params);
 
					break;
 
				}
 

	
 
				const Depot *d = Depot::Get(args.GetInt32());
 
				if (!d->name.empty()) {
 
					int64 args_array[] = {(int64)(size_t)d->name.c_str()};
 
					StringParameters tmp_params(args_array);
 
					auto tmp_params = MakeParameters(d->name);
 
					GetStringWithArgs(builder, STR_JUST_RAW_STRING, tmp_params);
 
				} else {
 
					int64 args_array[] = {d->town->index, d->town_cn + 1};
 
					StringParameters tmp_params(args_array);
 
					auto tmp_params = MakeParameters(d->town->index, d->town_cn + 1);
 
					GetStringWithArgs(builder, STR_FORMAT_DEPOT_NAME_TRAIN + 2 * vt + (d->town_cn == 0 ? 0 : 1), tmp_params);
 
				}
 
				break;
 
			}
 

	
 
			case SCC_ENGINE_NAME: { // {ENGINE}
 
				int64 arg = args.GetInt64();
 
				const Engine *e = Engine::GetIfValid(static_cast<EngineID>(arg));
 
				if (e == nullptr) break;
 

	
 
				if (!e->name.empty() && e->IsEnabled()) {
 
					int64 args_array[] = {(int64)(size_t)e->name.c_str()};
 
					StringParameters tmp_params(args_array);
 
					auto tmp_params = MakeParameters(e->name);
 
					GetStringWithArgs(builder, STR_JUST_RAW_STRING, tmp_params);
 

	
 
					break;
 
				}
 

	
 
				if (HasBit(e->info.callback_mask, CBM_VEHICLE_NAME)) {
 
					uint16 callback = GetVehicleCallback(CBID_VEHICLE_NAME, static_cast<uint32>(arg >> 32), 0, e->index, nullptr);
 
					/* Not calling ErrorUnknownCallbackResult due to being inside string processing. */
 
					if (callback != CALLBACK_FAILED && callback < 0x400) {
 
						const GRFFile *grffile = e->GetGRF();
 
						assert(grffile != nullptr);
 

	
 
						StartTextRefStackUsage(grffile, 6);
 
						uint64 tmp_dparam[6] = { 0 };
 
						WChar tmp_type[6] = { 0 };
 
						StringParameters tmp_params(tmp_dparam, 6, tmp_type);
 
						GetStringWithArgs(builder, GetGRFStringID(grffile->grfid, 0xD000 + callback), tmp_params);
 
						StopTextRefStackUsage();
 

	
 
						break;
 
					}
 
				}
 

	
 
				StringParameters tmp_params(nullptr, 0, nullptr);
 
				auto tmp_params = AllocatedStringParameters();
 
				GetStringWithArgs(builder, e->info.string_id, tmp_params);
 
				break;
 
			}
 

	
 
			case SCC_GROUP_NAME: { // {GROUP}
 
				const Group *g = Group::GetIfValid(args.GetInt32());
 
				if (g == nullptr) break;
 

	
 
				if (!g->name.empty()) {
 
					int64 args_array[] = {(int64)(size_t)g->name.c_str()};
 
					StringParameters tmp_params(args_array);
 
					auto tmp_params = MakeParameters(g->name);
 
					GetStringWithArgs(builder, STR_JUST_RAW_STRING, tmp_params);
 
				} else {
 
					int64 args_array[] = {g->index};
 
					StringParameters tmp_params(args_array);
 

	
 
					auto tmp_params = MakeParameters(g->index);
 
					GetStringWithArgs(builder, STR_FORMAT_GROUP_NAME, tmp_params);
 
				}
 
				break;
 
			}
 

	
 
			case SCC_INDUSTRY_NAME: { // {INDUSTRY}
 
				const Industry *i = Industry::GetIfValid(args.GetInt32());
 
				if (i == nullptr) break;
 

	
 
				static bool use_cache = true;
 
				if (use_cache) { // Use cached version if first call
 
					AutoRestoreBackup cache_backup(use_cache, false);
 
					builder += i->GetCachedName();
 
				} else if (_scan_for_gender_data) {
 
					/* Gender is defined by the industry type.
 
					 * STR_FORMAT_INDUSTRY_NAME may have the town first, so it would result in the gender of the town name */
 
					StringParameters tmp_params(nullptr, 0, nullptr);
 
					auto tmp_params = AllocatedStringParameters();
 
					FormatString(builder, GetStringPtr(GetIndustrySpec(i->type)->name), tmp_params, next_substr_case_index);
 
				} else {
 
					/* First print the town name and the industry type name. */
 
					int64 args_array[2] = {i->town->index, GetIndustrySpec(i->type)->name};
 
					StringParameters tmp_params(args_array);
 

	
 
					auto tmp_params = MakeParameters(i->town->index, GetIndustrySpec(i->type)->name);
 
					FormatString(builder, GetStringPtr(STR_FORMAT_INDUSTRY_NAME), tmp_params, next_substr_case_index);
 
				}
 
				next_substr_case_index = 0;
 
				break;
 
			}
 

	
 
			case SCC_PRESIDENT_NAME: { // {PRESIDENT_NAME}
 
				const Company *c = Company::GetIfValid(args.GetInt32());
 
				if (c == nullptr) break;
 

	
 
				if (!c->president_name.empty()) {
 
					int64 args_array[] = {(int64)(size_t)c->president_name.c_str()};
 
					StringParameters tmp_params(args_array);
 
					auto tmp_params = MakeParameters(c->president_name);
 
					GetStringWithArgs(builder, STR_JUST_RAW_STRING, tmp_params);
 
				} else {
 
					int64 args_array[] = {c->president_name_2};
 
					StringParameters tmp_params(args_array);
 
					auto tmp_params = MakeParameters(c->president_name_2);
 
					GetStringWithArgs(builder, c->president_name_1, tmp_params);
 
				}
 
				break;
 
			}
 

	
 
			case SCC_STATION_NAME: { // {STATION}
 
				StationID sid = args.GetInt32();
 
				const Station *st = Station::GetIfValid(sid);
 

	
 
				if (st == nullptr) {
 
					/* The station doesn't exist anymore. The only place where we might
 
					 * be "drawing" an invalid station is in the case of cargo that is
 
					 * in transit. */
 
					StringParameters tmp_params(nullptr, 0, nullptr);
 
					auto tmp_params = AllocatedStringParameters();
 
					GetStringWithArgs(builder, STR_UNKNOWN_STATION, tmp_params);
 
					break;
 
				}
 

	
 
				static bool use_cache = true;
 
				if (use_cache) { // Use cached version if first call
 
					AutoRestoreBackup cache_backup(use_cache, false);
 
					builder += st->GetCachedName();
 
				} else if (!st->name.empty()) {
 
					int64 args_array[] = {(int64)(size_t)st->name.c_str()};
 
					StringParameters tmp_params(args_array);
 
					auto tmp_params = MakeParameters(st->name);
 
					GetStringWithArgs(builder, STR_JUST_RAW_STRING, tmp_params);
 
				} else {
 
					StringID string_id = st->string_id;
 
					if (st->indtype != IT_INVALID) {
 
						/* Special case where the industry provides the name for the station */
 
						const IndustrySpec *indsp = GetIndustrySpec(st->indtype);
 

	
 
						/* Industry GRFs can change which might remove the station name and
 
						 * thus cause very strange things. Here we check for that before we
 
						 * actually set the station name. */
 
						if (indsp->station_name != STR_NULL && indsp->station_name != STR_UNDEFINED) {
 
							string_id = indsp->station_name;
 
						}
 
					}
 

	
 
					uint64 args_array[] = {STR_TOWN_NAME, st->town->index, st->index};
 
					WChar types_array[] = {0, SCC_TOWN_NAME, SCC_NUM};
 
					StringParameters tmp_params(args_array, 3, types_array);
 
					GetStringWithArgs(builder, string_id, tmp_params);
 
				}
 
				break;
 
			}
 

	
 
			case SCC_TOWN_NAME: { // {TOWN}
 
				const Town *t = Town::GetIfValid(args.GetInt32());
 
				if (t == nullptr) break;
 

	
 
				static bool use_cache = true;
 
				if (use_cache) { // Use cached version if first call
 
					AutoRestoreBackup cache_backup(use_cache, false);
 
					builder += t->GetCachedName();
 
				} else if (!t->name.empty()) {
 
					int64 args_array[] = {(int64)(size_t)t->name.c_str()};
 
					StringParameters tmp_params(args_array);
 
					auto tmp_params = MakeParameters(t->name);
 
					GetStringWithArgs(builder, STR_JUST_RAW_STRING, tmp_params);
 
				} else {
 
					GetTownName(builder, t);
 
				}
 
				break;
 
			}
 

	
 
			case SCC_WAYPOINT_NAME: { // {WAYPOINT}
 
				Waypoint *wp = Waypoint::GetIfValid(args.GetInt32());
 
				if (wp == nullptr) break;
 

	
 
				if (!wp->name.empty()) {
 
					int64 args_array[] = {(int64)(size_t)wp->name.c_str()};
 
					StringParameters tmp_params(args_array);
 
					auto tmp_params = MakeParameters(wp->name);
 
					GetStringWithArgs(builder, STR_JUST_RAW_STRING, tmp_params);
 
				} else {
 
					int64 args_array[] = {wp->town->index, wp->town_cn + 1};
 
					StringParameters tmp_params(args_array);
 
					auto tmp_params = MakeParameters(wp->town->index, wp->town_cn + 1);
 
					StringID string_id = ((wp->string_id == STR_SV_STNAME_BUOY) ? STR_FORMAT_BUOY_NAME : STR_FORMAT_WAYPOINT_NAME);
 
					if (wp->town_cn != 0) string_id++;
 
					GetStringWithArgs(builder, string_id, tmp_params);
 
				}
 
				break;
 
			}
 

	
 
			case SCC_VEHICLE_NAME: { // {VEHICLE}
 
				const Vehicle *v = Vehicle::GetIfValid(args.GetInt32());
 
				if (v == nullptr) break;
 

	
 
				if (!v->name.empty()) {
 
					int64 args_array[] = {(int64)(size_t)v->name.c_str()};
 
					StringParameters tmp_params(args_array);
 
					auto tmp_params = MakeParameters(v->name);
 
					GetStringWithArgs(builder, STR_JUST_RAW_STRING, tmp_params);
 
				} else if (v->group_id != DEFAULT_GROUP) {
 
					/* The vehicle has no name, but is member of a group, so print group name */
 
					int64 args_array[] = {v->group_id, v->unitnumber};
 
					StringParameters tmp_params(args_array);
 
					auto tmp_params = MakeParameters(v->group_id, v->unitnumber);
 
					GetStringWithArgs(builder, STR_FORMAT_GROUP_VEHICLE_NAME, tmp_params);
 
				} else {
 
					int64 args_array[] = {v->unitnumber};
 
					StringParameters tmp_params(args_array);
 
					auto tmp_params = MakeParameters(v->unitnumber);
 

	
 
					StringID string_id;
 
					switch (v->type) {
 
						default:           string_id = STR_INVALID_VEHICLE; break;
 
						case VEH_TRAIN:    string_id = STR_SV_TRAIN_NAME; break;
 
						case VEH_ROAD:     string_id = STR_SV_ROAD_VEHICLE_NAME; break;
 
						case VEH_SHIP:     string_id = STR_SV_SHIP_NAME; break;
 
						case VEH_AIRCRAFT: string_id = STR_SV_AIRCRAFT_NAME; break;
 
					}
 

	
 
					GetStringWithArgs(builder, string_id, tmp_params);
 
				}
 
				break;
 
			}
 

	
 
			case SCC_SIGN_NAME: { // {SIGN}
 
				const Sign *si = Sign::GetIfValid(args.GetInt32());
 
				if (si == nullptr) break;
 

	
 
				if (!si->name.empty()) {
 
					int64 args_array[] = {(int64)(size_t)si->name.c_str()};
 
					StringParameters tmp_params(args_array);
 
					auto tmp_params = MakeParameters(si->name);
 
					GetStringWithArgs(builder, STR_JUST_RAW_STRING, tmp_params);
 
				} else {
 
					StringParameters tmp_params(nullptr, 0, nullptr);
 
					auto tmp_params = AllocatedStringParameters();
 
					GetStringWithArgs(builder, STR_DEFAULT_SIGN_NAME, tmp_params);
 
				}
 
				break;
 
			}
 

	
 
			case SCC_STATION_FEATURES: { // {STATIONFEATURES}
 
				StationGetSpecialString(builder, args.GetInt32());
 
				break;
 
			}
 

	
 
			default:
 
				builder.Utf8Encode(b);
 
				break;
 
		}
 
	}
 
}
 

	
 

	
 
static void StationGetSpecialString(StringBuilder &builder, int x)
 
{
 
	if ((x & FACIL_TRAIN) != 0) builder.Utf8Encode(SCC_TRAIN);
 
	if ((x & FACIL_TRUCK_STOP) != 0) builder.Utf8Encode(SCC_LORRY);
 
	if ((x & FACIL_BUS_STOP) != 0) builder.Utf8Encode(SCC_BUS);
 
	if ((x & FACIL_DOCK) != 0) builder.Utf8Encode(SCC_SHIP);
src/strings_internal.h
Show inline comments
 
/*
 
 * This file is part of OpenTTD.
 
 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
 
 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 
 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
 
 */
 

	
 
/** @file strings_interal.h Types and functions related to the internal workings of formatting OpenTTD's strings. */
 

	
 
#ifndef STRINGS_INTERNAL_H
 
#define STRINGS_INTERNAL_H
 

	
 
#include "strings_func.h"
 
#include "string_func.h"
 

	
 
class StringParameters {
 
protected:
 
	StringParameters *parent; ///< If not nullptr, this instance references data from this parent instance.
 
	uint64 *data;             ///< Array with the actual data.
 
	WChar *type;              ///< Array with type information about the data. Can be nullptr when no type information is needed. See #StringControlCode.
 

	
 
public:
 
	size_t offset = 0; ///< Current offset in the data/type arrays.
 
	size_t num_param; ///< Length of the data array.
 
	WChar next_type = 0; ///< The type of the next data that is retrieved.
 

	
 
	/** Create a new StringParameters instance. */
 
	StringParameters(uint64 *data, size_t num_param, WChar *type) :
 
		parent(nullptr),
 
		data(data),
 
		type(type),
 
		num_param(num_param)
 
	{ }
 

	
 
	/** Create a new StringParameters instance. */
 
	template <size_t Tnum_param>
 
	StringParameters(int64 (&data)[Tnum_param]) :
 
		parent(nullptr),
 
		data((uint64 *)data),
 
		type(nullptr),
 
		offset(0),
 
		num_param(Tnum_param)
 
	{
 
		static_assert(sizeof(data[0]) == sizeof(uint64));
 
	}
 

	
 
	/**
 
	 * Create a new StringParameters instance that can reference part of the data of
 
	 * the given partent instance.
 
	 */
 
	StringParameters(StringParameters &parent, size_t size) :
 
		parent(&parent),
 
		data(parent.data + parent.offset),
 
		num_param(size)
 
	{
 
		assert(size <= parent.GetDataLeft());
 
		if (parent.type == nullptr) {
 
			this->type = nullptr;
 
		} else {
 
			this->type = parent.type + parent.offset;
 
		}
 
	}
 

	
 
	~StringParameters()
 
	{
 
		if (this->parent != nullptr) {
 
			this->parent->offset += this->num_param;
 
		}
 
	}
 

	
 
@@ -115,56 +104,89 @@ public:
 
		assert(offset < this->num_param);
 
		return &this->data[offset];
 
	}
 

	
 
	/** Does this instance store information about the type of the parameters. */
 
	bool HasTypeInformation() const
 
	{
 
		return this->type != nullptr;
 
	}
 

	
 
	/** Get the type of a specific element. */
 
	WChar GetTypeAtOffset(size_t offset) const
 
	{
 
		assert(offset < this->num_param);
 
		assert(this->HasTypeInformation());
 
		return this->type[offset];
 
	}
 

	
 
	void SetParam(size_t n, uint64 v)
 
	{
 
		assert(n < this->num_param);
 
		this->data[n] = v;
 
	}
 

	
 
	void SetParam(size_t n, const char *str) { this->SetParam(n, (uint64_t)(size_t)str); }
 
	void SetParam(size_t n, const std::string &str) { this->SetParam(n, str.c_str()); }
 
	void SetParam(size_t n, std::string &&str) = delete; // block passing temporaries to SetDParam
 

	
 
	uint64 GetParam(size_t n) const
 
	{
 
		assert(n < this->num_param);
 
		return this->data[n];
 
	}
 
};
 

	
 
/**
 
 * Extension of StringParameters with its own statically allocated buffer for
 
 * the parameters.
 
 */
 
class AllocatedStringParameters : public StringParameters {
 
	std::vector<uint64_t> params; ///< The actual parameters
 

	
 
public:
 
	AllocatedStringParameters(size_t parameters = 0) : StringParameters(nullptr, parameters, nullptr), params(parameters)
 
	{
 
		this->data = params.data();
 
	}
 
};
 

	
 
/**
 
 * Helper to create the StringParameters with its own buffer with the given
 
 * parameter values.
 
 * @param args The parameters to set for the to be created StringParameters.
 
 * @return The constructed StringParameters.
 
 */
 
template <typename... Args>
 
static auto MakeParameters(const Args&... args)
 
{
 
	AllocatedStringParameters parameters(sizeof...(args));
 
	size_t index = 0;
 
	(parameters.SetParam(index++, std::forward<const Args&>(args)), ...);
 
	return parameters;
 
}
 

	
 
/**
 
 * Equivalent to the std::back_insert_iterator in function, with some
 
 * convenience helpers for string concatenation.
 
 */
 
class StringBuilder {
 
	std::string *string;
 

	
 
public:
 
	/* Required type for this to be an output_iterator; mimics std::back_insert_iterator. */
 
	using value_type = void;
 
	using difference_type = void;
 
	using iterator_category = std::output_iterator_tag;
 
	using pointer = void;
 
	using reference = void;
 

	
 
	/**
 
	 * Create the builder of an external buffer.
 
	 * @param start The start location to write to.
 
	 * @param last  The last location to write to.
 
	 */
 
	StringBuilder(std::string &string) : string(&string) {}
 

	
 
	/* Required operators for this to be an output_iterator; mimics std::back_insert_iterator, which has no-ops. */
 
	StringBuilder &operator++() { return *this; }
 
	StringBuilder operator++(int) { return *this; }
src/townname.cpp
Show inline comments
 
@@ -27,50 +27,49 @@
 
 * @param t town for which we will be printing name later
 
 */
 
TownNameParams::TownNameParams(const Town *t) :
 
		grfid(t->townnamegrfid), // by default, use supplied data
 
		type(t->townnametype)
 
{
 
	if (t->townnamegrfid != 0 && GetGRFTownName(t->townnamegrfid) == nullptr) {
 
		/* Fallback to english original */
 
		this->grfid = 0;
 
		this->type = SPECSTR_TOWNNAME_ENGLISH;
 
		return;
 
	}
 
}
 

	
 

	
 
/**
 
 * Fills builder with specified town name.
 
 * @param builder       The string builder.
 
 * @param par           Town name parameters.
 
 * @param townnameparts 'Encoded' town name.
 
 */
 
static void GetTownName(StringBuilder &builder, const TownNameParams *par, uint32 townnameparts)
 
{
 
	if (par->grfid == 0) {
 
		int64 args_array[1] = { townnameparts };
 
		StringParameters tmp_params(args_array);
 
		auto tmp_params = MakeParameters(townnameparts);
 
		GetStringWithArgs(builder, par->type, tmp_params);
 
		return;
 
	}
 

	
 
	GRFTownNameGenerate(builder, par->grfid, par->type, townnameparts);
 
}
 

	
 
/**
 
 * Get the town name for the given parameters and parts.
 
 * @param par Town name parameters.
 
 * @param townnameparts 'Encoded' town name.
 
 * @return The town name.
 
 */
 
std::string GetTownName(const TownNameParams *par, uint32 townnameparts)
 
{
 
	std::string result;
 
	StringBuilder builder(result);
 
	GetTownName(builder, par, townnameparts);
 
	return result;
 
}
 

	
 
/**
 
 * Fills builder with town's name.
 
 * @param builder String builder.
0 comments (0 inline, 0 general)