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 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);
/**
@ -133,22 +139,17 @@ uint StringData::Version() const
const LangString *ls = this->strings[i].get();
if (ls != nullptr) {
const CmdStruct *cs;
const char *s;
std::string buf;
int argno;
int casei;
s = ls->name.c_str();
const char *s = ls->name.c_str();
hash ^= i * 0x717239;
hash = (hash & 1 ? hash >> 1 ^ 0xDEADBEEF : hash >> 1);
hash = VersionHashStr(hash, s + 1);
s = ls->english.c_str();
while ((cs = ParseCommandString(&s, buf, &argno, &casei)) != nullptr) {
if (cs->flags.Test(CmdFlag::DontCount)) continue;
ParsedCommandString cs;
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);
}
}
@ -237,23 +238,23 @@ void EmitSingleChar(Buffer *buffer, char *buf, int value)
/* The plural specifier looks like
* {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;
char *end;
while (*s == ' ' || *s == '\t') s++;
int v = std::strtol(s, &end, 0);
if (end == s) return false;
*value = v;
if (offset != nullptr && *end == ':') {
if (end == s) return {};
std::optional<int> offset;
if (*end == ':') {
/* Take the Nth within */
s = end + 1;
*offset = std::strtol(s, &end, 0);
if (end == s) return false;
offset = std::strtol(s, &end, 0);
if (end == s) return {};
}
*buf = end;
return true;
return {v, offset};
}
/* 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)
{
int argidx = _cur_argidx;
int offset = -1;
int expected = _plural_forms[_lang.plural_form].plural_count;
std::vector<const char *> words(std::max(expected, MAX_PLURALS), nullptr);
int nw = 0;
/* 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];
if (offset == -1) {
const CmdStruct *cmd = _cur_pcs.consuming_commands[*argidx];
if (!offset.has_value()) {
/* 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);
}
offset = cmd->default_plural_offset;
@ -358,21 +361,17 @@ void EmitPlural(Buffer *buffer, char *buf, int)
buffer->AppendUtf8(SCC_PLURAL_LIST);
buffer->AppendByte(_lang.plural_form);
buffer->AppendByte(TranslateArgumentIdx(argidx, offset));
buffer->AppendByte(TranslateArgumentIdx(*argidx, *offset));
EmitWordList(buffer, words, nw);
}
void EmitGender(Buffer *buffer, char *buf, int)
{
int argidx = _cur_argidx;
int offset = 0;
uint nw;
if (buf[0] == '=') {
buf++;
/* 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);
/* 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.
* 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)) {
StrgenFatal("Command '{}' can't have a gender", cmd == nullptr ? "<empty>" : cmd->cmd);
}
uint nw;
for (nw = 0; nw < MAX_NUM_GENDERS; nw++) {
words[nw] = ParseWord(&buf);
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));
buffer->AppendUtf8(SCC_GENDER_LIST);
buffer->AppendByte(TranslateArgumentIdx(argidx, offset));
buffer->AppendByte(TranslateArgumentIdx(*argidx, *offset));
EmitWordList(buffer, words, nw);
}
}
@ -424,59 +426,56 @@ static uint ResolveCaseName(const char *str, size_t len)
return case_idx + 1;
}
/* returns nullptr on eof
* else returns command struct */
static const CmdStruct *ParseCommandString(const char **str, std::string &param, int *argno, int *casei)
/* returns cmd == nullptr on eof */
static ParsedCommandString ParseCommandString(const char **str)
{
const char *s = *str, *start;
char c;
*argno = -1;
*casei = -1;
ParsedCommandString result;
const char *s = *str;
/* Scan to the next command, exit if there's no next command. */
for (; *s != '{'; s++) {
if (*s == '\0') return nullptr;
if (*s == '\0') return {};
}
s++; // Skip past the {
if (*s >= '0' && *s <= '9') {
char *end;
*argno = std::strtoul(s, &end, 0);
result.argno = std::strtoul(s, &end, 0);
if (*end != ':') StrgenFatal("missing arg #");
s = end + 1;
}
/* parse command name */
start = s;
const char *start = s;
char c;
do {
c = *s++;
} while (c != '}' && c != ' ' && c != '=' && c != '.' && c != 0);
const CmdStruct *cmd = FindCmd(start, s - start - 1);
if (cmd == nullptr) {
result.cmd = FindCmd(start, s - start - 1);
if (result.cmd == nullptr) {
std::string command(start, s - start - 1);
StrgenError("Undefined command '{}'", command);
return nullptr;
return {};
}
if (c == '.') {
const char *casep = s;
if (!cmd->flags.Test(CmdFlag::Case)) {
StrgenFatal("Command '{}' can't have a case", cmd->cmd);
if (!result.cmd->flags.Test(CmdFlag::Case)) {
StrgenFatal("Command '{}' can't have a case", result.cmd->cmd);
}
do {
c = *s++;
} while (c != '}' && c != ' ' && c != '\0');
*casei = ResolveCaseName(casep, s - casep - 1);
result.casei = ResolveCaseName(casep, s - casep - 1);
}
if (c == '\0') {
StrgenError("Missing }} from command '{}'", start);
return nullptr;
return {};
}
if (c != '}') {
@ -488,15 +487,15 @@ static const CmdStruct *ParseCommandString(const char **str, std::string &param,
if (c == '}') break;
if (c == '\0') {
StrgenError("Missing }} from command '{}'", start);
return nullptr;
return {};
}
param += c;
result.param += c;
}
}
*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)
{
int argno;
int argidx = 0;
int casei;
ParsedCommandStruct p;
int argidx = 0;
for (;;) {
/* read until next command from a. */
std::string param;
const CmdStruct *ar = ParseCommandString(&s, param, &argno, &casei);
auto cs = ParseCommandString(&s);
if (ar == nullptr) break;
if (cs.cmd == nullptr) break;
/* 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 (argno != -1) argidx = argno;
if (argidx < 0 || (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 (cs.cmd->consumes > 0) {
if (cs.argno.has_value()) argidx = *cs.argno;
if ((uint)argidx >= p.consuming_commands.max_size()) StrgenFatal("invalid 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;
} else if (!ar->flags.Test(CmdFlag::DontCount)) { // Ignore some of them
p.non_consuming_commands.emplace_back(ar, std::move(param));
p.consuming_commands[argidx++] = cs.cmd;
} else if (!cs.cmd->flags.Test(CmdFlag::DontCount)) { // Ignore some of them
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;
}
std::string param;
int argno;
int casei;
const CmdStruct *cs = ParseCommandString(&str, param, &argno, &casei);
if (cs == nullptr) break;
auto cs = ParseCommandString(&str);
auto *cmd = cs.cmd;
if (cmd == nullptr) break;
if (casei != -1) {
if (cs.casei.has_value()) {
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 */
if (cs->consumes > 0) {
if (cmd->consumes > 0) {
/* Check if we need to output a move-param command */
if (argno != -1 && argno != _cur_argidx) {
_cur_argidx = argno;
if (cs.argno.has_value() && *cs.argno != _cur_argidx) {
_cur_argidx = *cs.argno;
PutArgidxCommand(buffer);
}
/* Output the one from the master string... it's always accurate. */
cs = _cur_pcs.consuming_commands[_cur_argidx++];
if (cs == nullptr) {
cmd = _cur_pcs.consuming_commands[_cur_argidx++];
if (cmd == nullptr) {
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;
long value;
uint8_t consumes;
int8_t default_plural_offset;
std::optional<int> default_plural_offset;
CmdFlags flags;
};
@ -34,49 +34,49 @@ extern void EmitGender(Buffer *buffer, char *buf, int value);
static const CmdStruct _cmd_structs[] = {
/* Font size */
{"NORMAL_FONT", EmitSingleChar, SCC_NORMALFONT, 0, -1, {}},
{"TINY_FONT", EmitSingleChar, SCC_TINYFONT, 0, -1, {}},
{"BIG_FONT", EmitSingleChar, SCC_BIGFONT, 0, -1, {}},
{"MONO_FONT", EmitSingleChar, SCC_MONOFONT, 0, -1, {}},
{"NORMAL_FONT", EmitSingleChar, SCC_NORMALFONT, 0, std::nullopt, {}},
{"TINY_FONT", EmitSingleChar, SCC_TINYFONT, 0, std::nullopt, {}},
{"BIG_FONT", EmitSingleChar, SCC_BIGFONT, 0, std::nullopt, {}},
{"MONO_FONT", EmitSingleChar, SCC_MONOFONT, 0, std::nullopt, {}},
/* Colours */
{"BLUE", EmitSingleChar, SCC_BLUE, 0, -1, {CmdFlag::DontCount}},
{"SILVER", EmitSingleChar, SCC_SILVER, 0, -1, {CmdFlag::DontCount}},
{"GOLD", EmitSingleChar, SCC_GOLD, 0, -1, {CmdFlag::DontCount}},
{"RED", EmitSingleChar, SCC_RED, 0, -1, {CmdFlag::DontCount}},
{"PURPLE", EmitSingleChar, SCC_PURPLE, 0, -1, {CmdFlag::DontCount}},
{"LTBROWN", EmitSingleChar, SCC_LTBROWN, 0, -1, {CmdFlag::DontCount}},
{"ORANGE", EmitSingleChar, SCC_ORANGE, 0, -1, {CmdFlag::DontCount}},
{"GREEN", EmitSingleChar, SCC_GREEN, 0, -1, {CmdFlag::DontCount}},
{"YELLOW", EmitSingleChar, SCC_YELLOW, 0, -1, {CmdFlag::DontCount}},
{"DKGREEN", EmitSingleChar, SCC_DKGREEN, 0, -1, {CmdFlag::DontCount}},
{"CREAM", EmitSingleChar, SCC_CREAM, 0, -1, {CmdFlag::DontCount}},
{"BROWN", EmitSingleChar, SCC_BROWN, 0, -1, {CmdFlag::DontCount}},
{"WHITE", EmitSingleChar, SCC_WHITE, 0, -1, {CmdFlag::DontCount}},
{"LTBLUE", EmitSingleChar, SCC_LTBLUE, 0, -1, {CmdFlag::DontCount}},
{"GRAY", EmitSingleChar, SCC_GRAY, 0, -1, {CmdFlag::DontCount}},
{"DKBLUE", EmitSingleChar, SCC_DKBLUE, 0, -1, {CmdFlag::DontCount}},
{"BLACK", EmitSingleChar, SCC_BLACK, 0, -1, {CmdFlag::DontCount}},
{"COLOUR", EmitSingleChar, SCC_COLOUR, 1, -1, {}},
{"PUSH_COLOUR", EmitSingleChar, SCC_PUSH_COLOUR, 0, -1, {CmdFlag::DontCount}},
{"POP_COLOUR", EmitSingleChar, SCC_POP_COLOUR, 0, -1, {CmdFlag::DontCount}},
{"BLUE", EmitSingleChar, SCC_BLUE, 0, std::nullopt, {CmdFlag::DontCount}},
{"SILVER", EmitSingleChar, SCC_SILVER, 0, std::nullopt, {CmdFlag::DontCount}},
{"GOLD", EmitSingleChar, SCC_GOLD, 0, std::nullopt, {CmdFlag::DontCount}},
{"RED", EmitSingleChar, SCC_RED, 0, std::nullopt, {CmdFlag::DontCount}},
{"PURPLE", EmitSingleChar, SCC_PURPLE, 0, std::nullopt, {CmdFlag::DontCount}},
{"LTBROWN", EmitSingleChar, SCC_LTBROWN, 0, std::nullopt, {CmdFlag::DontCount}},
{"ORANGE", EmitSingleChar, SCC_ORANGE, 0, std::nullopt, {CmdFlag::DontCount}},
{"GREEN", EmitSingleChar, SCC_GREEN, 0, std::nullopt, {CmdFlag::DontCount}},
{"YELLOW", EmitSingleChar, SCC_YELLOW, 0, std::nullopt, {CmdFlag::DontCount}},
{"DKGREEN", EmitSingleChar, SCC_DKGREEN, 0, std::nullopt, {CmdFlag::DontCount}},
{"CREAM", EmitSingleChar, SCC_CREAM, 0, std::nullopt, {CmdFlag::DontCount}},
{"BROWN", EmitSingleChar, SCC_BROWN, 0, std::nullopt, {CmdFlag::DontCount}},
{"WHITE", EmitSingleChar, SCC_WHITE, 0, std::nullopt, {CmdFlag::DontCount}},
{"LTBLUE", EmitSingleChar, SCC_LTBLUE, 0, std::nullopt, {CmdFlag::DontCount}},
{"GRAY", EmitSingleChar, SCC_GRAY, 0, std::nullopt, {CmdFlag::DontCount}},
{"DKBLUE", EmitSingleChar, SCC_DKBLUE, 0, std::nullopt, {CmdFlag::DontCount}},
{"BLACK", EmitSingleChar, SCC_BLACK, 0, std::nullopt, {CmdFlag::DontCount}},
{"COLOUR", EmitSingleChar, SCC_COLOUR, 1, std::nullopt, {}},
{"PUSH_COLOUR", EmitSingleChar, SCC_PUSH_COLOUR, 0, std::nullopt, {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
{"STRING2", EmitSingleChar, SCC_STRING2, 3, -1, {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
{"STRING4", EmitSingleChar, SCC_STRING4, 5, -1, {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
{"STRING6", EmitSingleChar, SCC_STRING6, 7, -1, {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
{"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, std::nullopt, {CmdFlag::Case, CmdFlag::Gender}}, // included string that consumes the string id and TWO 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, std::nullopt, {CmdFlag::Case, CmdFlag::Gender}}, // included string that consumes the string id and FOUR 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, std::nullopt, {CmdFlag::Case, CmdFlag::Gender}}, // included string that consumes the string id and SIX 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
{"INDUSTRY", EmitSingleChar, SCC_INDUSTRY_NAME, 1, -1, {CmdFlag::Case, CmdFlag::Gender}}, // industry, takes an industry #, can have cases
{"STATION_FEATURES", EmitSingleChar, SCC_STATION_FEATURES, 1, std::nullopt, {}}, // station features string, icons of the features
{"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_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_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_TO_WEIGHT", EmitSingleChar, SCC_POWER_TO_WEIGHT, 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_MINUTES", EmitSingleChar, SCC_UNITS_YEARS_OR_MINUTES, 1, 0, {CmdFlag::Gender}},
{"P", EmitPlural, 0, 0, -1, {CmdFlag::DontCount}}, // plural specifier
{"G", EmitGender, 0, 0, -1, {CmdFlag::DontCount}}, // gender specifier
{"P", EmitPlural, 0, 0, std::nullopt, {CmdFlag::DontCount}}, // plural specifier
{"G", EmitGender, 0, 0, std::nullopt, {CmdFlag::DontCount}}, // gender specifier
{"DATE_TINY", EmitSingleChar, SCC_DATE_TINY, 1, -1, {}},
{"DATE_SHORT", EmitSingleChar, SCC_DATE_SHORT, 1, -1, {CmdFlag::Case}},
{"DATE_LONG", EmitSingleChar, SCC_DATE_LONG, 1, -1, {CmdFlag::Case}},
{"DATE_ISO", EmitSingleChar, SCC_DATE_ISO, 1, -1, {}},
{"DATE_TINY", EmitSingleChar, SCC_DATE_TINY, 1, std::nullopt, {}},
{"DATE_SHORT", EmitSingleChar, SCC_DATE_SHORT, 1, std::nullopt, {CmdFlag::Case}},
{"DATE_LONG", EmitSingleChar, SCC_DATE_LONG, 1, std::nullopt, {CmdFlag::Case}},
{"DATE_ISO", EmitSingleChar, SCC_DATE_ISO, 1, std::nullopt, {}},
{"STRING", EmitSingleChar, SCC_STRING, 1, -1, {CmdFlag::Case, CmdFlag::Gender}},
{"RAW_STRING", EmitSingleChar, SCC_RAW_STRING_POINTER, 1, -1, {CmdFlag::Gender}},
{"STRING", EmitSingleChar, SCC_STRING, 1, std::nullopt, {CmdFlag::Case, CmdFlag::Gender}},
{"RAW_STRING", EmitSingleChar, SCC_RAW_STRING_POINTER, 1, std::nullopt, {CmdFlag::Gender}},
/* Numbers */
{"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_SHORT", EmitSingleChar, SCC_CURRENCY_SHORT, 1, 0, {}}, // compact currency
{"WAYPOINT", EmitSingleChar, SCC_WAYPOINT_NAME, 1, -1, {CmdFlag::Gender}}, // waypoint name
{"STATION", EmitSingleChar, SCC_STATION_NAME, 1, -1, {CmdFlag::Gender}},
{"DEPOT", EmitSingleChar, SCC_DEPOT_NAME, 2, -1, {CmdFlag::Gender}},
{"TOWN", EmitSingleChar, SCC_TOWN_NAME, 1, -1, {CmdFlag::Gender}},
{"GROUP", EmitSingleChar, SCC_GROUP_NAME, 1, -1, {CmdFlag::Gender}},
{"SIGN", EmitSingleChar, SCC_SIGN_NAME, 1, -1, {CmdFlag::Gender}},
{"ENGINE", EmitSingleChar, SCC_ENGINE_NAME, 1, -1, {CmdFlag::Gender}},
{"VEHICLE", EmitSingleChar, SCC_VEHICLE_NAME, 1, -1, {CmdFlag::Gender}},
{"COMPANY", EmitSingleChar, SCC_COMPANY_NAME, 1, -1, {CmdFlag::Gender}},
{"COMPANY_NUM", EmitSingleChar, SCC_COMPANY_NUM, 1, -1, {}},
{"PRESIDENT_NAME", EmitSingleChar, SCC_PRESIDENT_NAME, 1, -1, {CmdFlag::Gender}},
{"WAYPOINT", EmitSingleChar, SCC_WAYPOINT_NAME, 1, std::nullopt, {CmdFlag::Gender}}, // waypoint name
{"STATION", EmitSingleChar, SCC_STATION_NAME, 1, std::nullopt, {CmdFlag::Gender}},
{"DEPOT", EmitSingleChar, SCC_DEPOT_NAME, 2, std::nullopt, {CmdFlag::Gender}},
{"TOWN", EmitSingleChar, SCC_TOWN_NAME, 1, std::nullopt, {CmdFlag::Gender}},
{"GROUP", EmitSingleChar, SCC_GROUP_NAME, 1, std::nullopt, {CmdFlag::Gender}},
{"SIGN", EmitSingleChar, SCC_SIGN_NAME, 1, std::nullopt, {CmdFlag::Gender}},
{"ENGINE", EmitSingleChar, SCC_ENGINE_NAME, 1, std::nullopt, {CmdFlag::Gender}},
{"VEHICLE", EmitSingleChar, SCC_VEHICLE_NAME, 1, std::nullopt, {CmdFlag::Gender}},
{"COMPANY", EmitSingleChar, SCC_COMPANY_NAME, 1, std::nullopt, {CmdFlag::Gender}},
{"COMPANY_NUM", EmitSingleChar, SCC_COMPANY_NUM, 1, std::nullopt, {}},
{"PRESIDENT_NAME", EmitSingleChar, SCC_PRESIDENT_NAME, 1, std::nullopt, {CmdFlag::Gender}},
{"SPACE", EmitSingleChar, ' ', 0, -1, {CmdFlag::DontCount}},
{"", EmitSingleChar, '\n', 0, -1, {CmdFlag::DontCount}},
{"{", EmitSingleChar, '{', 0, -1, {CmdFlag::DontCount}},
{"UP_ARROW", EmitSingleChar, SCC_UP_ARROW, 0, -1, {CmdFlag::DontCount}},
{"SMALL_UP_ARROW", EmitSingleChar, SCC_SMALL_UP_ARROW, 0, -1, {CmdFlag::DontCount}},
{"SMALL_DOWN_ARROW", EmitSingleChar, SCC_SMALL_DOWN_ARROW, 0, -1, {CmdFlag::DontCount}},
{"TRAIN", EmitSingleChar, SCC_TRAIN, 0, -1, {CmdFlag::DontCount}},
{"LORRY", EmitSingleChar, SCC_LORRY, 0, -1, {CmdFlag::DontCount}},
{"BUS", EmitSingleChar, SCC_BUS, 0, -1, {CmdFlag::DontCount}},
{"PLANE", EmitSingleChar, SCC_PLANE, 0, -1, {CmdFlag::DontCount}},
{"SHIP", EmitSingleChar, SCC_SHIP, 0, -1, {CmdFlag::DontCount}},
{"NBSP", EmitSingleChar, 0xA0, 0, -1, {CmdFlag::DontCount}},
{"COPYRIGHT", EmitSingleChar, 0xA9, 0, -1, {CmdFlag::DontCount}},
{"DOWN_ARROW", EmitSingleChar, SCC_DOWN_ARROW, 0, -1, {CmdFlag::DontCount}},
{"CHECKMARK", EmitSingleChar, SCC_CHECKMARK, 0, -1, {CmdFlag::DontCount}},
{"CROSS", EmitSingleChar, SCC_CROSS, 0, -1, {CmdFlag::DontCount}},
{"RIGHT_ARROW", EmitSingleChar, SCC_RIGHT_ARROW, 0, -1, {CmdFlag::DontCount}},
{"SMALL_LEFT_ARROW", EmitSingleChar, SCC_LESS_THAN, 0, -1, {CmdFlag::DontCount}},
{"SMALL_RIGHT_ARROW", EmitSingleChar, SCC_GREATER_THAN, 0, -1, {CmdFlag::DontCount}},
{"SPACE", EmitSingleChar, ' ', 0, std::nullopt, {CmdFlag::DontCount}},
{"", EmitSingleChar, '\n', 0, std::nullopt, {CmdFlag::DontCount}},
{"{", EmitSingleChar, '{', 0, std::nullopt, {CmdFlag::DontCount}},
{"UP_ARROW", EmitSingleChar, SCC_UP_ARROW, 0, std::nullopt, {CmdFlag::DontCount}},
{"SMALL_UP_ARROW", EmitSingleChar, SCC_SMALL_UP_ARROW, 0, std::nullopt, {CmdFlag::DontCount}},
{"SMALL_DOWN_ARROW", EmitSingleChar, SCC_SMALL_DOWN_ARROW, 0, std::nullopt, {CmdFlag::DontCount}},
{"TRAIN", EmitSingleChar, SCC_TRAIN, 0, std::nullopt, {CmdFlag::DontCount}},
{"LORRY", EmitSingleChar, SCC_LORRY, 0, std::nullopt, {CmdFlag::DontCount}},
{"BUS", EmitSingleChar, SCC_BUS, 0, std::nullopt, {CmdFlag::DontCount}},
{"PLANE", EmitSingleChar, SCC_PLANE, 0, std::nullopt, {CmdFlag::DontCount}},
{"SHIP", EmitSingleChar, SCC_SHIP, 0, std::nullopt, {CmdFlag::DontCount}},
{"NBSP", EmitSingleChar, 0xA0, 0, std::nullopt, {CmdFlag::DontCount}},
{"COPYRIGHT", EmitSingleChar, 0xA9, 0, std::nullopt, {CmdFlag::DontCount}},
{"DOWN_ARROW", EmitSingleChar, SCC_DOWN_ARROW, 0, std::nullopt, {CmdFlag::DontCount}},
{"CHECKMARK", EmitSingleChar, SCC_CHECKMARK, 0, std::nullopt, {CmdFlag::DontCount}},
{"CROSS", EmitSingleChar, SCC_CROSS, 0, std::nullopt, {CmdFlag::DontCount}},
{"RIGHT_ARROW", EmitSingleChar, SCC_RIGHT_ARROW, 0, std::nullopt, {CmdFlag::DontCount}},
{"SMALL_LEFT_ARROW", EmitSingleChar, SCC_LESS_THAN, 0, std::nullopt, {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:
* http://www.unicode.org/unicode/reports/tr9/#Directional_Formatting_Codes */
{"LRM", EmitSingleChar, CHAR_TD_LRM, 0, -1, {CmdFlag::DontCount}},
{"RLM", EmitSingleChar, CHAR_TD_RLM, 0, -1, {CmdFlag::DontCount}},
{"LRE", EmitSingleChar, CHAR_TD_LRE, 0, -1, {CmdFlag::DontCount}},
{"RLE", EmitSingleChar, CHAR_TD_RLE, 0, -1, {CmdFlag::DontCount}},
{"LRO", EmitSingleChar, CHAR_TD_LRO, 0, -1, {CmdFlag::DontCount}},
{"RLO", EmitSingleChar, CHAR_TD_RLO, 0, -1, {CmdFlag::DontCount}},
{"PDF", EmitSingleChar, CHAR_TD_PDF, 0, -1, {CmdFlag::DontCount}},
{"LRM", EmitSingleChar, CHAR_TD_LRM, 0, std::nullopt, {CmdFlag::DontCount}},
{"RLM", EmitSingleChar, CHAR_TD_RLM, 0, std::nullopt, {CmdFlag::DontCount}},
{"LRE", EmitSingleChar, CHAR_TD_LRE, 0, std::nullopt, {CmdFlag::DontCount}},
{"RLE", EmitSingleChar, CHAR_TD_RLE, 0, std::nullopt, {CmdFlag::DontCount}},
{"LRO", EmitSingleChar, CHAR_TD_LRO, 0, std::nullopt, {CmdFlag::DontCount}},
{"RLO", EmitSingleChar, CHAR_TD_RLO, 0, std::nullopt, {CmdFlag::DontCount}},
{"PDF", EmitSingleChar, CHAR_TD_PDF, 0, std::nullopt, {CmdFlag::DontCount}},
};
/** Description of a plural form */