1
0
Fork 0

Codechange: Turn out parameters into return values.

pull/13876/head
frosch 2025-03-24 19:16:02 +01:00 committed by frosch
parent 77af1c89c8
commit b10433715d
2 changed files with 156 additions and 163 deletions

View File

@ -31,7 +31,13 @@ static const char *_cur_ident;
static ParsedCommandStruct _cur_pcs; static ParsedCommandStruct _cur_pcs;
static int _cur_argidx; static int _cur_argidx;
static const CmdStruct *ParseCommandString(const char **str, std::string &param, int *argno, int *casei); struct ParsedCommandString {
const CmdStruct *cmd = nullptr;
std::string param;
std::optional<int> argno;
std::optional<int> casei;
};
static ParsedCommandString ParseCommandString(const char **str);
static int TranslateArgumentIdx(int arg, int offset = 0); static int TranslateArgumentIdx(int arg, int offset = 0);
/** /**
@ -133,22 +139,17 @@ uint StringData::Version() const
const LangString *ls = this->strings[i].get(); const LangString *ls = this->strings[i].get();
if (ls != nullptr) { if (ls != nullptr) {
const CmdStruct *cs; const char *s = ls->name.c_str();
const char *s;
std::string buf;
int argno;
int casei;
s = ls->name.c_str();
hash ^= i * 0x717239; hash ^= i * 0x717239;
hash = (hash & 1 ? hash >> 1 ^ 0xDEADBEEF : hash >> 1); hash = (hash & 1 ? hash >> 1 ^ 0xDEADBEEF : hash >> 1);
hash = VersionHashStr(hash, s + 1); hash = VersionHashStr(hash, s + 1);
s = ls->english.c_str(); s = ls->english.c_str();
while ((cs = ParseCommandString(&s, buf, &argno, &casei)) != nullptr) { ParsedCommandString cs;
if (cs->flags.Test(CmdFlag::DontCount)) continue; while ((cs = ParseCommandString(&s)).cmd != nullptr) {
if (cs.cmd->flags.Test(CmdFlag::DontCount)) continue;
hash ^= (cs - _cmd_structs) * 0x1234567; hash ^= (cs.cmd - _cmd_structs) * 0x1234567;
hash = (hash & 1 ? hash >> 1 ^ 0xF00BAA4 : hash >> 1); hash = (hash & 1 ? hash >> 1 ^ 0xF00BAA4 : hash >> 1);
} }
} }
@ -237,23 +238,23 @@ void EmitSingleChar(Buffer *buffer, char *buf, int value)
/* The plural specifier looks like /* The plural specifier looks like
* {NUM} {PLURAL <ARG#> passenger passengers} then it picks either passenger/passengers depending on the count in NUM */ * {NUM} {PLURAL <ARG#> passenger passengers} then it picks either passenger/passengers depending on the count in NUM */
static bool ParseRelNum(char **buf, int *value, int *offset) static std::pair<std::optional<int>, std::optional<int>> ParseRelNum(char **buf)
{ {
const char *s = *buf; const char *s = *buf;
char *end; char *end;
while (*s == ' ' || *s == '\t') s++; while (*s == ' ' || *s == '\t') s++;
int v = std::strtol(s, &end, 0); int v = std::strtol(s, &end, 0);
if (end == s) return false; if (end == s) return {};
*value = v; std::optional<int> offset;
if (offset != nullptr && *end == ':') { if (*end == ':') {
/* Take the Nth within */ /* Take the Nth within */
s = end + 1; s = end + 1;
*offset = std::strtol(s, &end, 0); offset = std::strtol(s, &end, 0);
if (end == s) return false; if (end == s) return {};
} }
*buf = end; *buf = end;
return true; return {v, offset};
} }
/* Parse out the next word, or nullptr */ /* Parse out the next word, or nullptr */
@ -312,19 +313,21 @@ static void EmitWordList(Buffer *buffer, const std::vector<const char *> &words,
void EmitPlural(Buffer *buffer, char *buf, int) void EmitPlural(Buffer *buffer, char *buf, int)
{ {
int argidx = _cur_argidx;
int offset = -1;
int expected = _plural_forms[_lang.plural_form].plural_count; int expected = _plural_forms[_lang.plural_form].plural_count;
std::vector<const char *> words(std::max(expected, MAX_PLURALS), nullptr); std::vector<const char *> words(std::max(expected, MAX_PLURALS), nullptr);
int nw = 0; int nw = 0;
/* Parse out the number, if one exists. Otherwise default to prev arg. */ /* Parse out the number, if one exists. Otherwise default to prev arg. */
if (!ParseRelNum(&buf, &argidx, &offset)) argidx--; auto [argidx, offset] = ParseRelNum(&buf);
if (!argidx.has_value()) {
if (_cur_argidx == 0) StrgenFatal("Plural choice needs positional reference");
argidx = _cur_argidx - 1;
}
const CmdStruct *cmd = _cur_pcs.consuming_commands[argidx]; const CmdStruct *cmd = _cur_pcs.consuming_commands[*argidx];
if (offset == -1) { if (!offset.has_value()) {
/* Use default offset */ /* Use default offset */
if (cmd == nullptr || cmd->default_plural_offset < 0) { if (cmd == nullptr || !cmd->default_plural_offset.has_value()) {
StrgenFatal("Command '{}' has no (default) plural position", cmd == nullptr ? "<empty>" : cmd->cmd); StrgenFatal("Command '{}' has no (default) plural position", cmd == nullptr ? "<empty>" : cmd->cmd);
} }
offset = cmd->default_plural_offset; offset = cmd->default_plural_offset;
@ -358,21 +361,17 @@ void EmitPlural(Buffer *buffer, char *buf, int)
buffer->AppendUtf8(SCC_PLURAL_LIST); buffer->AppendUtf8(SCC_PLURAL_LIST);
buffer->AppendByte(_lang.plural_form); buffer->AppendByte(_lang.plural_form);
buffer->AppendByte(TranslateArgumentIdx(argidx, offset)); buffer->AppendByte(TranslateArgumentIdx(*argidx, *offset));
EmitWordList(buffer, words, nw); EmitWordList(buffer, words, nw);
} }
void EmitGender(Buffer *buffer, char *buf, int) void EmitGender(Buffer *buffer, char *buf, int)
{ {
int argidx = _cur_argidx;
int offset = 0;
uint nw;
if (buf[0] == '=') { if (buf[0] == '=') {
buf++; buf++;
/* This is a {G=DER} command */ /* This is a {G=DER} command */
nw = _lang.GetGenderIndex(buf); uint nw = _lang.GetGenderIndex(buf);
if (nw >= MAX_NUM_GENDERS) StrgenFatal("G argument '{}' invalid", buf); if (nw >= MAX_NUM_GENDERS) StrgenFatal("G argument '{}' invalid", buf);
/* now nw contains the gender index */ /* now nw contains the gender index */
@ -383,13 +382,16 @@ void EmitGender(Buffer *buffer, char *buf, int)
/* This is a {G 0 foo bar two} command. /* This is a {G 0 foo bar two} command.
* If no relative number exists, default to +0 */ * If no relative number exists, default to +0 */
ParseRelNum(&buf, &argidx, &offset); auto [argidx, offset] = ParseRelNum(&buf);
if (!argidx.has_value()) argidx = _cur_argidx;
if (!offset.has_value()) offset = 0;
const CmdStruct *cmd = _cur_pcs.consuming_commands[argidx]; const CmdStruct *cmd = _cur_pcs.consuming_commands[*argidx];
if (cmd == nullptr || !cmd->flags.Test(CmdFlag::Gender)) { if (cmd == nullptr || !cmd->flags.Test(CmdFlag::Gender)) {
StrgenFatal("Command '{}' can't have a gender", cmd == nullptr ? "<empty>" : cmd->cmd); StrgenFatal("Command '{}' can't have a gender", cmd == nullptr ? "<empty>" : cmd->cmd);
} }
uint nw;
for (nw = 0; nw < MAX_NUM_GENDERS; nw++) { for (nw = 0; nw < MAX_NUM_GENDERS; nw++) {
words[nw] = ParseWord(&buf); words[nw] = ParseWord(&buf);
if (words[nw] == nullptr) break; if (words[nw] == nullptr) break;
@ -398,7 +400,7 @@ void EmitGender(Buffer *buffer, char *buf, int)
assert(IsInsideBS(cmd->value, SCC_CONTROL_START, UINT8_MAX)); assert(IsInsideBS(cmd->value, SCC_CONTROL_START, UINT8_MAX));
buffer->AppendUtf8(SCC_GENDER_LIST); buffer->AppendUtf8(SCC_GENDER_LIST);
buffer->AppendByte(TranslateArgumentIdx(argidx, offset)); buffer->AppendByte(TranslateArgumentIdx(*argidx, *offset));
EmitWordList(buffer, words, nw); EmitWordList(buffer, words, nw);
} }
} }
@ -424,59 +426,56 @@ static uint ResolveCaseName(const char *str, size_t len)
return case_idx + 1; return case_idx + 1;
} }
/* returns nullptr on eof /* returns cmd == nullptr on eof */
* else returns command struct */ static ParsedCommandString ParseCommandString(const char **str)
static const CmdStruct *ParseCommandString(const char **str, std::string &param, int *argno, int *casei)
{ {
const char *s = *str, *start; ParsedCommandString result;
char c; const char *s = *str;
*argno = -1;
*casei = -1;
/* Scan to the next command, exit if there's no next command. */ /* Scan to the next command, exit if there's no next command. */
for (; *s != '{'; s++) { for (; *s != '{'; s++) {
if (*s == '\0') return nullptr; if (*s == '\0') return {};
} }
s++; // Skip past the { s++; // Skip past the {
if (*s >= '0' && *s <= '9') { if (*s >= '0' && *s <= '9') {
char *end; char *end;
*argno = std::strtoul(s, &end, 0); result.argno = std::strtoul(s, &end, 0);
if (*end != ':') StrgenFatal("missing arg #"); if (*end != ':') StrgenFatal("missing arg #");
s = end + 1; s = end + 1;
} }
/* parse command name */ /* parse command name */
start = s; const char *start = s;
char c;
do { do {
c = *s++; c = *s++;
} while (c != '}' && c != ' ' && c != '=' && c != '.' && c != 0); } while (c != '}' && c != ' ' && c != '=' && c != '.' && c != 0);
const CmdStruct *cmd = FindCmd(start, s - start - 1); result.cmd = FindCmd(start, s - start - 1);
if (cmd == nullptr) { if (result.cmd == nullptr) {
std::string command(start, s - start - 1); std::string command(start, s - start - 1);
StrgenError("Undefined command '{}'", command); StrgenError("Undefined command '{}'", command);
return nullptr; return {};
} }
if (c == '.') { if (c == '.') {
const char *casep = s; const char *casep = s;
if (!cmd->flags.Test(CmdFlag::Case)) { if (!result.cmd->flags.Test(CmdFlag::Case)) {
StrgenFatal("Command '{}' can't have a case", cmd->cmd); StrgenFatal("Command '{}' can't have a case", result.cmd->cmd);
} }
do { do {
c = *s++; c = *s++;
} while (c != '}' && c != ' ' && c != '\0'); } while (c != '}' && c != ' ' && c != '\0');
*casei = ResolveCaseName(casep, s - casep - 1); result.casei = ResolveCaseName(casep, s - casep - 1);
} }
if (c == '\0') { if (c == '\0') {
StrgenError("Missing }} from command '{}'", start); StrgenError("Missing }} from command '{}'", start);
return nullptr; return {};
} }
if (c != '}') { if (c != '}') {
@ -488,15 +487,15 @@ static const CmdStruct *ParseCommandString(const char **str, std::string &param,
if (c == '}') break; if (c == '}') break;
if (c == '\0') { if (c == '\0') {
StrgenError("Missing }} from command '{}'", start); StrgenError("Missing }} from command '{}'", start);
return nullptr; return {};
} }
param += c; result.param += c;
} }
} }
*str = s; *str = s;
return cmd; return result;
} }
/** /**
@ -513,30 +512,26 @@ StringReader::StringReader(StringData &data, const std::string &file, bool maste
ParsedCommandStruct ExtractCommandString(const char *s, bool) ParsedCommandStruct ExtractCommandString(const char *s, bool)
{ {
int argno;
int argidx = 0;
int casei;
ParsedCommandStruct p; ParsedCommandStruct p;
int argidx = 0;
for (;;) { for (;;) {
/* read until next command from a. */ /* read until next command from a. */
std::string param; auto cs = ParseCommandString(&s);
const CmdStruct *ar = ParseCommandString(&s, param, &argno, &casei);
if (ar == nullptr) break; if (cs.cmd == nullptr) break;
/* Sanity checking */ /* Sanity checking */
if (argno != -1 && ar->consumes == 0) StrgenFatal("Non consumer param can't have a paramindex"); if (cs.argno.has_value() && cs.cmd->consumes == 0) StrgenFatal("Non consumer param can't have a paramindex");
if (ar->consumes) { if (cs.cmd->consumes > 0) {
if (argno != -1) argidx = argno; if (cs.argno.has_value()) argidx = *cs.argno;
if (argidx < 0 || (uint)argidx >= p.consuming_commands.max_size()) StrgenFatal("invalid param idx {}", argidx); if ((uint)argidx >= p.consuming_commands.max_size()) StrgenFatal("invalid param idx {}", argidx);
if (p.consuming_commands[argidx] != nullptr && p.consuming_commands[argidx] != ar) StrgenFatal("duplicate param idx {}", argidx); if (p.consuming_commands[argidx] != nullptr && p.consuming_commands[argidx] != cs.cmd) StrgenFatal("duplicate param idx {}", argidx);
p.consuming_commands[argidx++] = ar; p.consuming_commands[argidx++] = cs.cmd;
} else if (!ar->flags.Test(CmdFlag::DontCount)) { // Ignore some of them } else if (!cs.cmd->flags.Test(CmdFlag::DontCount)) { // Ignore some of them
p.non_consuming_commands.emplace_back(ar, std::move(param)); p.non_consuming_commands.emplace_back(cs.cmd, std::move(cs.param));
} }
} }
@ -809,33 +804,31 @@ static void PutCommandString(Buffer *buffer, const char *str)
continue; continue;
} }
std::string param; auto cs = ParseCommandString(&str);
int argno; auto *cmd = cs.cmd;
int casei; if (cmd == nullptr) break;
const CmdStruct *cs = ParseCommandString(&str, param, &argno, &casei);
if (cs == nullptr) break;
if (casei != -1) { if (cs.casei.has_value()) {
buffer->AppendUtf8(SCC_SET_CASE); // {SET_CASE} buffer->AppendUtf8(SCC_SET_CASE); // {SET_CASE}
buffer->AppendByte(casei); buffer->AppendByte(*cs.casei);
} }
/* For params that consume values, we need to handle the argindex properly */ /* For params that consume values, we need to handle the argindex properly */
if (cs->consumes > 0) { if (cmd->consumes > 0) {
/* Check if we need to output a move-param command */ /* Check if we need to output a move-param command */
if (argno != -1 && argno != _cur_argidx) { if (cs.argno.has_value() && *cs.argno != _cur_argidx) {
_cur_argidx = argno; _cur_argidx = *cs.argno;
PutArgidxCommand(buffer); PutArgidxCommand(buffer);
} }
/* Output the one from the master string... it's always accurate. */ /* Output the one from the master string... it's always accurate. */
cs = _cur_pcs.consuming_commands[_cur_argidx++]; cmd = _cur_pcs.consuming_commands[_cur_argidx++];
if (cs == nullptr) { if (cmd == nullptr) {
StrgenFatal("{}: No argument exists at position {}", _cur_ident, _cur_argidx - 1); StrgenFatal("{}: No argument exists at position {}", _cur_ident, _cur_argidx - 1);
} }
} }
cs->proc(buffer, param.data(), cs->value); cmd->proc(buffer, cs.param.data(), cmd->value);
} }
} }

View File

@ -24,7 +24,7 @@ struct CmdStruct {
ParseCmdProc proc; ParseCmdProc proc;
long value; long value;
uint8_t consumes; uint8_t consumes;
int8_t default_plural_offset; std::optional<int> default_plural_offset;
CmdFlags flags; CmdFlags flags;
}; };
@ -34,49 +34,49 @@ extern void EmitGender(Buffer *buffer, char *buf, int value);
static const CmdStruct _cmd_structs[] = { static const CmdStruct _cmd_structs[] = {
/* Font size */ /* Font size */
{"NORMAL_FONT", EmitSingleChar, SCC_NORMALFONT, 0, -1, {}}, {"NORMAL_FONT", EmitSingleChar, SCC_NORMALFONT, 0, std::nullopt, {}},
{"TINY_FONT", EmitSingleChar, SCC_TINYFONT, 0, -1, {}}, {"TINY_FONT", EmitSingleChar, SCC_TINYFONT, 0, std::nullopt, {}},
{"BIG_FONT", EmitSingleChar, SCC_BIGFONT, 0, -1, {}}, {"BIG_FONT", EmitSingleChar, SCC_BIGFONT, 0, std::nullopt, {}},
{"MONO_FONT", EmitSingleChar, SCC_MONOFONT, 0, -1, {}}, {"MONO_FONT", EmitSingleChar, SCC_MONOFONT, 0, std::nullopt, {}},
/* Colours */ /* Colours */
{"BLUE", EmitSingleChar, SCC_BLUE, 0, -1, {CmdFlag::DontCount}}, {"BLUE", EmitSingleChar, SCC_BLUE, 0, std::nullopt, {CmdFlag::DontCount}},
{"SILVER", EmitSingleChar, SCC_SILVER, 0, -1, {CmdFlag::DontCount}}, {"SILVER", EmitSingleChar, SCC_SILVER, 0, std::nullopt, {CmdFlag::DontCount}},
{"GOLD", EmitSingleChar, SCC_GOLD, 0, -1, {CmdFlag::DontCount}}, {"GOLD", EmitSingleChar, SCC_GOLD, 0, std::nullopt, {CmdFlag::DontCount}},
{"RED", EmitSingleChar, SCC_RED, 0, -1, {CmdFlag::DontCount}}, {"RED", EmitSingleChar, SCC_RED, 0, std::nullopt, {CmdFlag::DontCount}},
{"PURPLE", EmitSingleChar, SCC_PURPLE, 0, -1, {CmdFlag::DontCount}}, {"PURPLE", EmitSingleChar, SCC_PURPLE, 0, std::nullopt, {CmdFlag::DontCount}},
{"LTBROWN", EmitSingleChar, SCC_LTBROWN, 0, -1, {CmdFlag::DontCount}}, {"LTBROWN", EmitSingleChar, SCC_LTBROWN, 0, std::nullopt, {CmdFlag::DontCount}},
{"ORANGE", EmitSingleChar, SCC_ORANGE, 0, -1, {CmdFlag::DontCount}}, {"ORANGE", EmitSingleChar, SCC_ORANGE, 0, std::nullopt, {CmdFlag::DontCount}},
{"GREEN", EmitSingleChar, SCC_GREEN, 0, -1, {CmdFlag::DontCount}}, {"GREEN", EmitSingleChar, SCC_GREEN, 0, std::nullopt, {CmdFlag::DontCount}},
{"YELLOW", EmitSingleChar, SCC_YELLOW, 0, -1, {CmdFlag::DontCount}}, {"YELLOW", EmitSingleChar, SCC_YELLOW, 0, std::nullopt, {CmdFlag::DontCount}},
{"DKGREEN", EmitSingleChar, SCC_DKGREEN, 0, -1, {CmdFlag::DontCount}}, {"DKGREEN", EmitSingleChar, SCC_DKGREEN, 0, std::nullopt, {CmdFlag::DontCount}},
{"CREAM", EmitSingleChar, SCC_CREAM, 0, -1, {CmdFlag::DontCount}}, {"CREAM", EmitSingleChar, SCC_CREAM, 0, std::nullopt, {CmdFlag::DontCount}},
{"BROWN", EmitSingleChar, SCC_BROWN, 0, -1, {CmdFlag::DontCount}}, {"BROWN", EmitSingleChar, SCC_BROWN, 0, std::nullopt, {CmdFlag::DontCount}},
{"WHITE", EmitSingleChar, SCC_WHITE, 0, -1, {CmdFlag::DontCount}}, {"WHITE", EmitSingleChar, SCC_WHITE, 0, std::nullopt, {CmdFlag::DontCount}},
{"LTBLUE", EmitSingleChar, SCC_LTBLUE, 0, -1, {CmdFlag::DontCount}}, {"LTBLUE", EmitSingleChar, SCC_LTBLUE, 0, std::nullopt, {CmdFlag::DontCount}},
{"GRAY", EmitSingleChar, SCC_GRAY, 0, -1, {CmdFlag::DontCount}}, {"GRAY", EmitSingleChar, SCC_GRAY, 0, std::nullopt, {CmdFlag::DontCount}},
{"DKBLUE", EmitSingleChar, SCC_DKBLUE, 0, -1, {CmdFlag::DontCount}}, {"DKBLUE", EmitSingleChar, SCC_DKBLUE, 0, std::nullopt, {CmdFlag::DontCount}},
{"BLACK", EmitSingleChar, SCC_BLACK, 0, -1, {CmdFlag::DontCount}}, {"BLACK", EmitSingleChar, SCC_BLACK, 0, std::nullopt, {CmdFlag::DontCount}},
{"COLOUR", EmitSingleChar, SCC_COLOUR, 1, -1, {}}, {"COLOUR", EmitSingleChar, SCC_COLOUR, 1, std::nullopt, {}},
{"PUSH_COLOUR", EmitSingleChar, SCC_PUSH_COLOUR, 0, -1, {CmdFlag::DontCount}}, {"PUSH_COLOUR", EmitSingleChar, SCC_PUSH_COLOUR, 0, std::nullopt, {CmdFlag::DontCount}},
{"POP_COLOUR", EmitSingleChar, SCC_POP_COLOUR, 0, -1, {CmdFlag::DontCount}}, {"POP_COLOUR", EmitSingleChar, SCC_POP_COLOUR, 0, std::nullopt, {CmdFlag::DontCount}},
{"REV", EmitSingleChar, SCC_REVISION, 0, -1, {}}, // openttd revision string {"REV", EmitSingleChar, SCC_REVISION, 0, std::nullopt, {}}, // openttd revision string
{"STRING1", EmitSingleChar, SCC_STRING1, 2, -1, {CmdFlag::Case, CmdFlag::Gender}}, // included string that consumes the string id and ONE argument {"STRING1", EmitSingleChar, SCC_STRING1, 2, std::nullopt, {CmdFlag::Case, CmdFlag::Gender}}, // included string that consumes the string id and ONE argument
{"STRING2", EmitSingleChar, SCC_STRING2, 3, -1, {CmdFlag::Case, CmdFlag::Gender}}, // included string that consumes the string id and TWO arguments {"STRING2", EmitSingleChar, SCC_STRING2, 3, std::nullopt, {CmdFlag::Case, CmdFlag::Gender}}, // included string that consumes the string id and TWO arguments
{"STRING3", EmitSingleChar, SCC_STRING3, 4, -1, {CmdFlag::Case, CmdFlag::Gender}}, // included string that consumes the string id and THREE arguments {"STRING3", EmitSingleChar, SCC_STRING3, 4, std::nullopt, {CmdFlag::Case, CmdFlag::Gender}}, // included string that consumes the string id and THREE arguments
{"STRING4", EmitSingleChar, SCC_STRING4, 5, -1, {CmdFlag::Case, CmdFlag::Gender}}, // included string that consumes the string id and FOUR arguments {"STRING4", EmitSingleChar, SCC_STRING4, 5, std::nullopt, {CmdFlag::Case, CmdFlag::Gender}}, // included string that consumes the string id and FOUR arguments
{"STRING5", EmitSingleChar, SCC_STRING5, 6, -1, {CmdFlag::Case, CmdFlag::Gender}}, // included string that consumes the string id and FIVE arguments {"STRING5", EmitSingleChar, SCC_STRING5, 6, std::nullopt, {CmdFlag::Case, CmdFlag::Gender}}, // included string that consumes the string id and FIVE arguments
{"STRING6", EmitSingleChar, SCC_STRING6, 7, -1, {CmdFlag::Case, CmdFlag::Gender}}, // included string that consumes the string id and SIX arguments {"STRING6", EmitSingleChar, SCC_STRING6, 7, std::nullopt, {CmdFlag::Case, CmdFlag::Gender}}, // included string that consumes the string id and SIX arguments
{"STRING7", EmitSingleChar, SCC_STRING7, 8, -1, {CmdFlag::Case, CmdFlag::Gender}}, // included string that consumes the string id and SEVEN arguments {"STRING7", EmitSingleChar, SCC_STRING7, 8, std::nullopt, {CmdFlag::Case, CmdFlag::Gender}}, // included string that consumes the string id and SEVEN arguments
{"STATION_FEATURES", EmitSingleChar, SCC_STATION_FEATURES, 1, -1, {}}, // station features string, icons of the features {"STATION_FEATURES", EmitSingleChar, SCC_STATION_FEATURES, 1, std::nullopt, {}}, // station features string, icons of the features
{"INDUSTRY", EmitSingleChar, SCC_INDUSTRY_NAME, 1, -1, {CmdFlag::Case, CmdFlag::Gender}}, // industry, takes an industry #, can have cases {"INDUSTRY", EmitSingleChar, SCC_INDUSTRY_NAME, 1, std::nullopt, {CmdFlag::Case, CmdFlag::Gender}}, // industry, takes an industry #, can have cases
{"CARGO_LONG", EmitSingleChar, SCC_CARGO_LONG, 2, 1, {CmdFlag::Gender}}, {"CARGO_LONG", EmitSingleChar, SCC_CARGO_LONG, 2, 1, {CmdFlag::Gender}},
{"CARGO_SHORT", EmitSingleChar, SCC_CARGO_SHORT, 2, 1, {CmdFlag::Gender}}, // short cargo description, only ### tons, or ### litres {"CARGO_SHORT", EmitSingleChar, SCC_CARGO_SHORT, 2, 1, {CmdFlag::Gender}}, // short cargo description, only ### tons, or ### litres
{"CARGO_TINY", EmitSingleChar, SCC_CARGO_TINY, 2, 1, {}}, // tiny cargo description with only the amount, not a specifier for the amount or the actual cargo name {"CARGO_TINY", EmitSingleChar, SCC_CARGO_TINY, 2, 1, {}}, // tiny cargo description with only the amount, not a specifier for the amount or the actual cargo name
{"CARGO_LIST", EmitSingleChar, SCC_CARGO_LIST, 1, -1, {CmdFlag::Case}}, {"CARGO_LIST", EmitSingleChar, SCC_CARGO_LIST, 1, std::nullopt, {CmdFlag::Case}},
{"POWER", EmitSingleChar, SCC_POWER, 1, 0, {}}, {"POWER", EmitSingleChar, SCC_POWER, 1, 0, {}},
{"POWER_TO_WEIGHT", EmitSingleChar, SCC_POWER_TO_WEIGHT, 1, 0, {}}, {"POWER_TO_WEIGHT", EmitSingleChar, SCC_POWER_TO_WEIGHT, 1, 0, {}},
{"VOLUME_LONG", EmitSingleChar, SCC_VOLUME_LONG, 1, 0, {}}, {"VOLUME_LONG", EmitSingleChar, SCC_VOLUME_LONG, 1, 0, {}},
@ -92,16 +92,16 @@ static const CmdStruct _cmd_structs[] = {
{"UNITS_YEARS_OR_PERIODS", EmitSingleChar, SCC_UNITS_YEARS_OR_PERIODS, 1, 0, {CmdFlag::Gender}}, {"UNITS_YEARS_OR_PERIODS", EmitSingleChar, SCC_UNITS_YEARS_OR_PERIODS, 1, 0, {CmdFlag::Gender}},
{"UNITS_YEARS_OR_MINUTES", EmitSingleChar, SCC_UNITS_YEARS_OR_MINUTES, 1, 0, {CmdFlag::Gender}}, {"UNITS_YEARS_OR_MINUTES", EmitSingleChar, SCC_UNITS_YEARS_OR_MINUTES, 1, 0, {CmdFlag::Gender}},
{"P", EmitPlural, 0, 0, -1, {CmdFlag::DontCount}}, // plural specifier {"P", EmitPlural, 0, 0, std::nullopt, {CmdFlag::DontCount}}, // plural specifier
{"G", EmitGender, 0, 0, -1, {CmdFlag::DontCount}}, // gender specifier {"G", EmitGender, 0, 0, std::nullopt, {CmdFlag::DontCount}}, // gender specifier
{"DATE_TINY", EmitSingleChar, SCC_DATE_TINY, 1, -1, {}}, {"DATE_TINY", EmitSingleChar, SCC_DATE_TINY, 1, std::nullopt, {}},
{"DATE_SHORT", EmitSingleChar, SCC_DATE_SHORT, 1, -1, {CmdFlag::Case}}, {"DATE_SHORT", EmitSingleChar, SCC_DATE_SHORT, 1, std::nullopt, {CmdFlag::Case}},
{"DATE_LONG", EmitSingleChar, SCC_DATE_LONG, 1, -1, {CmdFlag::Case}}, {"DATE_LONG", EmitSingleChar, SCC_DATE_LONG, 1, std::nullopt, {CmdFlag::Case}},
{"DATE_ISO", EmitSingleChar, SCC_DATE_ISO, 1, -1, {}}, {"DATE_ISO", EmitSingleChar, SCC_DATE_ISO, 1, std::nullopt, {}},
{"STRING", EmitSingleChar, SCC_STRING, 1, -1, {CmdFlag::Case, CmdFlag::Gender}}, {"STRING", EmitSingleChar, SCC_STRING, 1, std::nullopt, {CmdFlag::Case, CmdFlag::Gender}},
{"RAW_STRING", EmitSingleChar, SCC_RAW_STRING_POINTER, 1, -1, {CmdFlag::Gender}}, {"RAW_STRING", EmitSingleChar, SCC_RAW_STRING_POINTER, 1, std::nullopt, {CmdFlag::Gender}},
/* Numbers */ /* Numbers */
{"COMMA", EmitSingleChar, SCC_COMMA, 1, 0, {}}, // Number with comma {"COMMA", EmitSingleChar, SCC_COMMA, 1, 0, {}}, // Number with comma
@ -114,47 +114,47 @@ static const CmdStruct _cmd_structs[] = {
{"CURRENCY_LONG", EmitSingleChar, SCC_CURRENCY_LONG, 1, 0, {}}, {"CURRENCY_LONG", EmitSingleChar, SCC_CURRENCY_LONG, 1, 0, {}},
{"CURRENCY_SHORT", EmitSingleChar, SCC_CURRENCY_SHORT, 1, 0, {}}, // compact currency {"CURRENCY_SHORT", EmitSingleChar, SCC_CURRENCY_SHORT, 1, 0, {}}, // compact currency
{"WAYPOINT", EmitSingleChar, SCC_WAYPOINT_NAME, 1, -1, {CmdFlag::Gender}}, // waypoint name {"WAYPOINT", EmitSingleChar, SCC_WAYPOINT_NAME, 1, std::nullopt, {CmdFlag::Gender}}, // waypoint name
{"STATION", EmitSingleChar, SCC_STATION_NAME, 1, -1, {CmdFlag::Gender}}, {"STATION", EmitSingleChar, SCC_STATION_NAME, 1, std::nullopt, {CmdFlag::Gender}},
{"DEPOT", EmitSingleChar, SCC_DEPOT_NAME, 2, -1, {CmdFlag::Gender}}, {"DEPOT", EmitSingleChar, SCC_DEPOT_NAME, 2, std::nullopt, {CmdFlag::Gender}},
{"TOWN", EmitSingleChar, SCC_TOWN_NAME, 1, -1, {CmdFlag::Gender}}, {"TOWN", EmitSingleChar, SCC_TOWN_NAME, 1, std::nullopt, {CmdFlag::Gender}},
{"GROUP", EmitSingleChar, SCC_GROUP_NAME, 1, -1, {CmdFlag::Gender}}, {"GROUP", EmitSingleChar, SCC_GROUP_NAME, 1, std::nullopt, {CmdFlag::Gender}},
{"SIGN", EmitSingleChar, SCC_SIGN_NAME, 1, -1, {CmdFlag::Gender}}, {"SIGN", EmitSingleChar, SCC_SIGN_NAME, 1, std::nullopt, {CmdFlag::Gender}},
{"ENGINE", EmitSingleChar, SCC_ENGINE_NAME, 1, -1, {CmdFlag::Gender}}, {"ENGINE", EmitSingleChar, SCC_ENGINE_NAME, 1, std::nullopt, {CmdFlag::Gender}},
{"VEHICLE", EmitSingleChar, SCC_VEHICLE_NAME, 1, -1, {CmdFlag::Gender}}, {"VEHICLE", EmitSingleChar, SCC_VEHICLE_NAME, 1, std::nullopt, {CmdFlag::Gender}},
{"COMPANY", EmitSingleChar, SCC_COMPANY_NAME, 1, -1, {CmdFlag::Gender}}, {"COMPANY", EmitSingleChar, SCC_COMPANY_NAME, 1, std::nullopt, {CmdFlag::Gender}},
{"COMPANY_NUM", EmitSingleChar, SCC_COMPANY_NUM, 1, -1, {}}, {"COMPANY_NUM", EmitSingleChar, SCC_COMPANY_NUM, 1, std::nullopt, {}},
{"PRESIDENT_NAME", EmitSingleChar, SCC_PRESIDENT_NAME, 1, -1, {CmdFlag::Gender}}, {"PRESIDENT_NAME", EmitSingleChar, SCC_PRESIDENT_NAME, 1, std::nullopt, {CmdFlag::Gender}},
{"SPACE", EmitSingleChar, ' ', 0, -1, {CmdFlag::DontCount}}, {"SPACE", EmitSingleChar, ' ', 0, std::nullopt, {CmdFlag::DontCount}},
{"", EmitSingleChar, '\n', 0, -1, {CmdFlag::DontCount}}, {"", EmitSingleChar, '\n', 0, std::nullopt, {CmdFlag::DontCount}},
{"{", EmitSingleChar, '{', 0, -1, {CmdFlag::DontCount}}, {"{", EmitSingleChar, '{', 0, std::nullopt, {CmdFlag::DontCount}},
{"UP_ARROW", EmitSingleChar, SCC_UP_ARROW, 0, -1, {CmdFlag::DontCount}}, {"UP_ARROW", EmitSingleChar, SCC_UP_ARROW, 0, std::nullopt, {CmdFlag::DontCount}},
{"SMALL_UP_ARROW", EmitSingleChar, SCC_SMALL_UP_ARROW, 0, -1, {CmdFlag::DontCount}}, {"SMALL_UP_ARROW", EmitSingleChar, SCC_SMALL_UP_ARROW, 0, std::nullopt, {CmdFlag::DontCount}},
{"SMALL_DOWN_ARROW", EmitSingleChar, SCC_SMALL_DOWN_ARROW, 0, -1, {CmdFlag::DontCount}}, {"SMALL_DOWN_ARROW", EmitSingleChar, SCC_SMALL_DOWN_ARROW, 0, std::nullopt, {CmdFlag::DontCount}},
{"TRAIN", EmitSingleChar, SCC_TRAIN, 0, -1, {CmdFlag::DontCount}}, {"TRAIN", EmitSingleChar, SCC_TRAIN, 0, std::nullopt, {CmdFlag::DontCount}},
{"LORRY", EmitSingleChar, SCC_LORRY, 0, -1, {CmdFlag::DontCount}}, {"LORRY", EmitSingleChar, SCC_LORRY, 0, std::nullopt, {CmdFlag::DontCount}},
{"BUS", EmitSingleChar, SCC_BUS, 0, -1, {CmdFlag::DontCount}}, {"BUS", EmitSingleChar, SCC_BUS, 0, std::nullopt, {CmdFlag::DontCount}},
{"PLANE", EmitSingleChar, SCC_PLANE, 0, -1, {CmdFlag::DontCount}}, {"PLANE", EmitSingleChar, SCC_PLANE, 0, std::nullopt, {CmdFlag::DontCount}},
{"SHIP", EmitSingleChar, SCC_SHIP, 0, -1, {CmdFlag::DontCount}}, {"SHIP", EmitSingleChar, SCC_SHIP, 0, std::nullopt, {CmdFlag::DontCount}},
{"NBSP", EmitSingleChar, 0xA0, 0, -1, {CmdFlag::DontCount}}, {"NBSP", EmitSingleChar, 0xA0, 0, std::nullopt, {CmdFlag::DontCount}},
{"COPYRIGHT", EmitSingleChar, 0xA9, 0, -1, {CmdFlag::DontCount}}, {"COPYRIGHT", EmitSingleChar, 0xA9, 0, std::nullopt, {CmdFlag::DontCount}},
{"DOWN_ARROW", EmitSingleChar, SCC_DOWN_ARROW, 0, -1, {CmdFlag::DontCount}}, {"DOWN_ARROW", EmitSingleChar, SCC_DOWN_ARROW, 0, std::nullopt, {CmdFlag::DontCount}},
{"CHECKMARK", EmitSingleChar, SCC_CHECKMARK, 0, -1, {CmdFlag::DontCount}}, {"CHECKMARK", EmitSingleChar, SCC_CHECKMARK, 0, std::nullopt, {CmdFlag::DontCount}},
{"CROSS", EmitSingleChar, SCC_CROSS, 0, -1, {CmdFlag::DontCount}}, {"CROSS", EmitSingleChar, SCC_CROSS, 0, std::nullopt, {CmdFlag::DontCount}},
{"RIGHT_ARROW", EmitSingleChar, SCC_RIGHT_ARROW, 0, -1, {CmdFlag::DontCount}}, {"RIGHT_ARROW", EmitSingleChar, SCC_RIGHT_ARROW, 0, std::nullopt, {CmdFlag::DontCount}},
{"SMALL_LEFT_ARROW", EmitSingleChar, SCC_LESS_THAN, 0, -1, {CmdFlag::DontCount}}, {"SMALL_LEFT_ARROW", EmitSingleChar, SCC_LESS_THAN, 0, std::nullopt, {CmdFlag::DontCount}},
{"SMALL_RIGHT_ARROW", EmitSingleChar, SCC_GREATER_THAN, 0, -1, {CmdFlag::DontCount}}, {"SMALL_RIGHT_ARROW", EmitSingleChar, SCC_GREATER_THAN, 0, std::nullopt, {CmdFlag::DontCount}},
/* The following are directional formatting codes used to get the RTL strings right: /* The following are directional formatting codes used to get the RTL strings right:
* http://www.unicode.org/unicode/reports/tr9/#Directional_Formatting_Codes */ * http://www.unicode.org/unicode/reports/tr9/#Directional_Formatting_Codes */
{"LRM", EmitSingleChar, CHAR_TD_LRM, 0, -1, {CmdFlag::DontCount}}, {"LRM", EmitSingleChar, CHAR_TD_LRM, 0, std::nullopt, {CmdFlag::DontCount}},
{"RLM", EmitSingleChar, CHAR_TD_RLM, 0, -1, {CmdFlag::DontCount}}, {"RLM", EmitSingleChar, CHAR_TD_RLM, 0, std::nullopt, {CmdFlag::DontCount}},
{"LRE", EmitSingleChar, CHAR_TD_LRE, 0, -1, {CmdFlag::DontCount}}, {"LRE", EmitSingleChar, CHAR_TD_LRE, 0, std::nullopt, {CmdFlag::DontCount}},
{"RLE", EmitSingleChar, CHAR_TD_RLE, 0, -1, {CmdFlag::DontCount}}, {"RLE", EmitSingleChar, CHAR_TD_RLE, 0, std::nullopt, {CmdFlag::DontCount}},
{"LRO", EmitSingleChar, CHAR_TD_LRO, 0, -1, {CmdFlag::DontCount}}, {"LRO", EmitSingleChar, CHAR_TD_LRO, 0, std::nullopt, {CmdFlag::DontCount}},
{"RLO", EmitSingleChar, CHAR_TD_RLO, 0, -1, {CmdFlag::DontCount}}, {"RLO", EmitSingleChar, CHAR_TD_RLO, 0, std::nullopt, {CmdFlag::DontCount}},
{"PDF", EmitSingleChar, CHAR_TD_PDF, 0, -1, {CmdFlag::DontCount}}, {"PDF", EmitSingleChar, CHAR_TD_PDF, 0, std::nullopt, {CmdFlag::DontCount}},
}; };
/** Description of a plural form */ /** Description of a plural form */