Changeset - r27118:72b5ef4d66a8
[Not reviewed]
master
0 5 0
Rubidium - 17 months ago 2023-04-18 18:24:21
rubidium@openttd.org
Codechange: use string/fmt instead of print for strgen warnings/errors/fatals
5 files changed with 60 insertions and 88 deletions:
0 comments (0 inline, 0 general)
src/game/game_text.cpp
Show inline comments
 
@@ -23,42 +23,27 @@
 

	
 
#include <stdarg.h>
 
#include <memory>
 

	
 
#include "../safeguards.h"
 

	
 
void CDECL strgen_warning(const char *s, ...)
 
void CDECL StrgenWarningI(const std::string &msg)
 
{
 
	char buf[1024];
 
	va_list va;
 
	va_start(va, s);
 
	vseprintf(buf, lastof(buf), s, va);
 
	va_end(va);
 
	Debug(script, 0, "{}:{}: warning: {}", _file, _cur_line, buf);
 
	Debug(script, 0, "{}:{}: warning: {}", _file, _cur_line, msg);
 
	_warnings++;
 
}
 

	
 
void CDECL strgen_error(const char *s, ...)
 
void CDECL StrgenErrorI(const std::string &msg)
 
{
 
	char buf[1024];
 
	va_list va;
 
	va_start(va, s);
 
	vseprintf(buf, lastof(buf), s, va);
 
	va_end(va);
 
	Debug(script, 0, "{}:{}: error: {}", _file, _cur_line, buf);
 
	Debug(script, 0, "{}:{}: error: {}", _file, _cur_line, msg);
 
	_errors++;
 
}
 

	
 
void NORETURN CDECL strgen_fatal(const char *s, ...)
 
void CDECL StrgenFatalI(const std::string &msg)
 
{
 
	char buf[1024];
 
	va_list va;
 
	va_start(va, s);
 
	vseprintf(buf, lastof(buf), s, va);
 
	va_end(va);
 
	Debug(script, 0, "{}:{}: FATAL: {}", _file, _cur_line, buf);
 
	Debug(script, 0, "{}:{}: FATAL: {}", _file, _cur_line, msg);
 
	throw std::exception();
 
}
 

	
 
/**
 
 * Read all the raw language strings from the given file.
 
 * @param file The file to read from.
src/stdafx.h
Show inline comments
 
@@ -302,25 +302,22 @@
 
/* MSVCRT of course has to have a different syntax for long long *sigh* */
 
#if defined(_MSC_VER)
 
#   define OTTD_PRINTF64 "%I64d"
 
#   define OTTD_PRINTF64U "%I64u"
 
#   define OTTD_PRINTFHEX64 "%I64x"
 
#   define PRINTF_SIZE "%Iu"
 
#   define PRINTF_SIZEX "%IX"
 
#elif defined(__MINGW32__)
 
#   define OTTD_PRINTF64 "%I64d"
 
#   define OTTD_PRINTF64U "%I64llu"
 
#   define OTTD_PRINTFHEX64 "%I64x"
 
#   define PRINTF_SIZE "%Iu"
 
#   define PRINTF_SIZEX "%IX"
 
#else
 
#   define OTTD_PRINTF64 "%lld"
 
#   define OTTD_PRINTF64U "%llu"
 
#   define OTTD_PRINTFHEX64 "%llx"
 
#   define PRINTF_SIZE "%zu"
 
#   define PRINTF_SIZEX "%zX"
 
#endif
 

	
 
/*
 
 * When making a (pure) debug build, the compiler will by default disable
 
 * inlining of functions. This has a detremental effect on the performance of
 
 * debug builds, especially when more and more trivial (wrapper) functions get
src/strgen/strgen.cpp
Show inline comments
 
@@ -36,46 +36,31 @@
 
#ifdef _MSC_VER
 
# define LINE_NUM_FMT(s) "%s (%d): warning: %s (" s ")\n"
 
#else
 
# define LINE_NUM_FMT(s) "%s:%d: " s ": %s\n"
 
#endif
 

	
 
void CDECL strgen_warning(const char *s, ...)
 
void StrgenWarningI(const std::string &msg)
 
{
 
	char buf[1024];
 
	va_list va;
 
	va_start(va, s);
 
	vseprintf(buf, lastof(buf), s, va);
 
	va_end(va);
 
	if (_show_todo > 0) {
 
		fprintf(stderr, LINE_NUM_FMT("warning"), _file, _cur_line, buf);
 
		fprintf(stderr, LINE_NUM_FMT("warning"), _file, _cur_line, msg.c_str());
 
	} else {
 
		fprintf(stderr, LINE_NUM_FMT("info"), _file, _cur_line, buf);
 
		fprintf(stderr, LINE_NUM_FMT("info"), _file, _cur_line, msg.c_str());
 
	}
 
	_warnings++;
 
}
 

	
 
void CDECL strgen_error(const char *s, ...)
 
void StrgenErrorI(const std::string &msg)
 
{
 
	char buf[1024];
 
	va_list va;
 
	va_start(va, s);
 
	vseprintf(buf, lastof(buf), s, va);
 
	va_end(va);
 
	fprintf(stderr, LINE_NUM_FMT("error"), _file, _cur_line, buf);
 
	fprintf(stderr, LINE_NUM_FMT("error"), _file, _cur_line, msg.c_str());
 
	_errors++;
 
}
 

	
 
void NORETURN CDECL strgen_fatal(const char *s, ...)
 
void NORETURN StrgenFatalI(const std::string &msg)
 
{
 
	char buf[1024];
 
	va_list va;
 
	va_start(va, s);
 
	vseprintf(buf, lastof(buf), s, va);
 
	va_end(va);
 
	fprintf(stderr, LINE_NUM_FMT("FATAL"), _file, _cur_line, buf);
 
	fprintf(stderr, LINE_NUM_FMT("FATAL"), _file, _cur_line, msg.c_str());
 
#ifdef _MSC_VER
 
	fprintf(stderr, LINE_NUM_FMT("warning"), _file, _cur_line, "language is not compiled");
 
#endif
 
	throw std::exception();
 
}
 

	
src/strgen/strgen.h
Show inline comments
 
@@ -8,12 +8,13 @@
 
/** @file strgen.h Structures related to strgen. */
 

	
 
#ifndef STRGEN_H
 
#define STRGEN_H
 

	
 
#include "../language.h"
 
#include "../3rdparty/fmt/format.h"
 

	
 
/** Container for the different cases of a string. */
 
struct Case {
 
	int caseidx;  ///< The index of the case.
 
	char *string; ///< The translation of the case.
 
	Case *next;   ///< The next, chained, case.
 
@@ -149,15 +150,18 @@ struct ParsedCommandStruct {
 
	const CmdStruct *cmd[32]; // ordered by param #
 
};
 

	
 
const CmdStruct *TranslateCmdForCompare(const CmdStruct *a);
 
void ExtractCommandString(ParsedCommandStruct *p, const char *s, bool warnings);
 

	
 
void CDECL strgen_warning(const char *s, ...) WARN_FORMAT(1, 2);
 
void CDECL strgen_error(const char *s, ...) WARN_FORMAT(1, 2);
 
void NORETURN CDECL strgen_fatal(const char *s, ...) WARN_FORMAT(1, 2);
 
void StrgenWarningI(const std::string &msg);
 
void StrgenErrorI(const std::string &msg);
 
void NORETURN StrgenFatalI(const std::string &msg);
 
#define StrgenWarning(format_string, ...) StrgenWarningI(fmt::format(FMT_STRING(format_string), ## __VA_ARGS__))
 
#define StrgenError(format_string, ...) StrgenErrorI(fmt::format(FMT_STRING(format_string), ## __VA_ARGS__))
 
#define StrgenFatal(format_string, ...) StrgenFatalI(fmt::format(FMT_STRING(format_string), ## __VA_ARGS__))
 
char *ParseWord(char **buf);
 

	
 
extern const char *_file;
 
extern int _cur_line;
 
extern int _errors, _warnings, _show_todo;
 
extern LanguagePackHeader _lang;
src/strgen/strgen_base.cpp
Show inline comments
 
@@ -251,13 +251,13 @@ struct Buffer : std::vector<byte> {
 
		} else if (value < 0x110000) {
 
			this->push_back(0xF0 + GB(value, 18, 3));
 
			this->push_back(0x80 + GB(value, 12, 6));
 
			this->push_back(0x80 + GB(value,  6, 6));
 
			this->push_back(0x80 + GB(value,  0, 6));
 
		} else {
 
			strgen_warning("Invalid unicode value U+0x%X", value);
 
			StrgenWarning("Invalid unicode value U+{:#X}", value);
 
		}
 
	}
 
};
 

	
 
size_t Utf8Validate(const char *s)
 
{
 
@@ -283,13 +283,13 @@ size_t Utf8Validate(const char *s)
 
	return 0;
 
}
 

	
 

	
 
void EmitSingleChar(Buffer *buffer, char *buf, int value)
 
{
 
	if (*buf != '\0') strgen_warning("Ignoring trailing letters in command");
 
	if (*buf != '\0') StrgenWarning("Ignoring trailing letters in command");
 
	buffer->AppendUtf8(value);
 
}
 

	
 

	
 
/* The plural specifier looks like
 
 * {NUM} {PLURAL -1 passenger passengers} then it picks either passenger/passengers depending on the count in NUM */
 
@@ -385,33 +385,33 @@ void EmitPlural(Buffer *buffer, char *bu
 
	if (!ParseRelNum(&buf, &argidx, &offset)) argidx--;
 

	
 
	const CmdStruct *cmd = _cur_pcs.cmd[argidx];
 
	if (offset == -1) {
 
		/* Use default offset */
 
		if (cmd == nullptr || cmd->default_plural_offset < 0) {
 
			strgen_fatal("Command '%s' 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;
 
	}
 

	
 
	/* Parse each string */
 
	for (nw = 0; nw < MAX_PLURALS; nw++) {
 
		words[nw] = ParseWord(&buf);
 
		if (words[nw] == nullptr) break;
 
	}
 

	
 
	if (nw == 0) {
 
		strgen_fatal("%s: No plural words", _cur_ident);
 
		StrgenFatal("{}: No plural words", _cur_ident);
 
	}
 

	
 
	if (expected != nw) {
 
		if (_translated) {
 
			strgen_fatal("%s: Invalid number of plural forms. Expecting %d, found %d.", _cur_ident,
 
			StrgenFatal("{}: Invalid number of plural forms. Expecting {}, found {}.", _cur_ident,
 
				expected, nw);
 
		} else {
 
			if ((_show_todo & 2) != 0) strgen_warning("'%s' is untranslated. Tweaking english string to allow compilation for plural forms", _cur_ident);
 
			if ((_show_todo & 2) != 0) StrgenWarning("'{}' is untranslated. Tweaking english string to allow compilation for plural forms", _cur_ident);
 
			if (nw > expected) {
 
				nw = expected;
 
			} else {
 
				for (; nw < expected; nw++) {
 
					words[nw] = words[nw - 1];
 
				}
 
@@ -434,13 +434,13 @@ void EmitGender(Buffer *buffer, char *bu
 

	
 
	if (buf[0] == '=') {
 
		buf++;
 

	
 
		/* This is a {G=DER} command */
 
		nw = _lang.GetGenderIndex(buf);
 
		if (nw >= MAX_NUM_GENDERS) strgen_fatal("G argument '%s' invalid", buf);
 
		if (nw >= MAX_NUM_GENDERS) StrgenFatal("G argument '{}' invalid", buf);
 

	
 
		/* now nw contains the gender index */
 
		buffer->AppendUtf8(SCC_GENDER_INDEX);
 
		buffer->AppendByte(nw);
 
	} else {
 
		std::vector<const char *> words(MAX_NUM_GENDERS, nullptr);
 
@@ -448,20 +448,20 @@ void EmitGender(Buffer *buffer, char *bu
 
		/* This is a {G 0 foo bar two} command.
 
		 * If no relative number exists, default to +0 */
 
		ParseRelNum(&buf, &argidx, &offset);
 

	
 
		const CmdStruct *cmd = _cur_pcs.cmd[argidx];
 
		if (cmd == nullptr || (cmd->flags & C_GENDER) == 0) {
 
			strgen_fatal("Command '%s' can't have a gender", cmd == nullptr ? "<empty>" : cmd->cmd);
 
			StrgenFatal("Command '{}' can't have a gender", cmd == nullptr ? "<empty>" : cmd->cmd);
 
		}
 

	
 
		for (nw = 0; nw < MAX_NUM_GENDERS; nw++) {
 
			words[nw] = ParseWord(&buf);
 
			if (words[nw] == nullptr) break;
 
		}
 
		if (nw != _lang.num_genders) strgen_fatal("Bad # of arguments for gender command");
 
		if (nw != _lang.num_genders) StrgenFatal("Bad # of arguments for gender command");
 

	
 
		assert(IsInsideBS(cmd->value, SCC_CONTROL_START, UINT8_MAX));
 
		buffer->AppendUtf8(SCC_GENDER_LIST);
 
		buffer->AppendByte(TranslateArgumentIdx(argidx, offset));
 
		EmitWordList(buffer, words, nw);
 
	}
 
@@ -481,13 +481,13 @@ static uint ResolveCaseName(const char *
 
	char case_str[CASE_GENDER_LEN];
 
	len = std::min(lengthof(case_str) - 1, len);
 
	memcpy(case_str, str, len);
 
	case_str[len] = '\0';
 

	
 
	uint8 case_idx = _lang.GetCaseIndex(case_str);
 
	if (case_idx >= MAX_NUM_CASES) strgen_fatal("Invalid case-name '%s'", case_str);
 
	if (case_idx >= MAX_NUM_CASES) StrgenFatal("Invalid case-name '{}'", case_str);
 
	return case_idx + 1;
 
}
 

	
 

	
 
/* returns nullptr on eof
 
 * else returns command struct */
 
@@ -506,56 +506,57 @@ static const CmdStruct *ParseCommandStri
 
	s++; // Skip past the {
 

	
 
	if (*s >= '0' && *s <= '9') {
 
		char *end;
 

	
 
		*argno = strtoul(s, &end, 0);
 
		if (*end != ':') strgen_fatal("missing arg #");
 
		if (*end != ':') StrgenFatal("missing arg #");
 
		s = end + 1;
 
	}
 

	
 
	/* parse command name */
 
	start = s;
 
	do {
 
		c = *s++;
 
	} while (c != '}' && c != ' ' && c != '=' && c != '.' && c != 0);
 

	
 
	const CmdStruct *cmd = FindCmd(start, s - start - 1);
 
	if (cmd == nullptr) {
 
		strgen_error("Undefined command '%.*s'", (int)(s - start - 1), start);
 
		std::string command(start, s - start - 1);
 
		StrgenError("Undefined command '{}'", command);
 
		return nullptr;
 
	}
 

	
 
	if (c == '.') {
 
		const char *casep = s;
 

	
 
		if (!(cmd->flags & C_CASE)) {
 
			strgen_fatal("Command '%s' can't have a case", cmd->cmd);
 
			StrgenFatal("Command '{}' can't have a case", cmd->cmd);
 
		}
 

	
 
		do {
 
			c = *s++;
 
		} while (c != '}' && c != ' ' && c != '\0');
 
		*casei = ResolveCaseName(casep, s - casep - 1);
 
	}
 

	
 
	if (c == '\0') {
 
		strgen_error("Missing } from command '%s'", start);
 
		StrgenError("Missing }} from command '{}'", start);
 
		return nullptr;
 
	}
 

	
 

	
 
	if (c != '}') {
 
		if (c == '=') s--;
 
		/* copy params */
 
		start = s;
 
		for (;;) {
 
			c = *s++;
 
			if (c == '}') break;
 
			if (c == '\0') {
 
				strgen_error("Missing } from command '%s'", start);
 
				StrgenError("Missing }} from command '{}'", start);
 
				return nullptr;
 
			}
 
			if (s - start == MAX_COMMAND_PARAM_SIZE) error("param command too long");
 
			*param++ = c;
 
		}
 
	}
 
@@ -597,22 +598,22 @@ void ExtractCommandString(ParsedCommandS
 
		/* read until next command from a. */
 
		const CmdStruct *ar = ParseCommandString(&s, param, &argno, &casei);
 

	
 
		if (ar == nullptr) break;
 

	
 
		/* Sanity checking */
 
		if (argno != -1 && ar->consumes == 0) strgen_fatal("Non consumer param can't have a paramindex");
 
		if (argno != -1 && ar->consumes == 0) StrgenFatal("Non consumer param can't have a paramindex");
 

	
 
		if (ar->consumes) {
 
			if (argno != -1) argidx = argno;
 
			if (argidx < 0 || (uint)argidx >= lengthof(p->cmd)) strgen_fatal("invalid param idx %d", argidx);
 
			if (p->cmd[argidx] != nullptr && p->cmd[argidx] != ar) strgen_fatal("duplicate param idx %d", argidx);
 
			if (argidx < 0 || (uint)argidx >= lengthof(p->cmd)) StrgenFatal("invalid param idx {}", argidx);
 
			if (p->cmd[argidx] != nullptr && p->cmd[argidx] != ar) StrgenFatal("duplicate param idx {}", argidx);
 

	
 
			p->cmd[argidx++] = ar;
 
		} else if (!(ar->flags & C_DONTCOUNT)) { // Ignore some of them
 
			if (p->np >= lengthof(p->pairs)) strgen_fatal("too many commands in string, max " PRINTF_SIZE, lengthof(p->pairs));
 
			if (p->np >= lengthof(p->pairs)) StrgenFatal("too many commands in string, max {}", lengthof(p->pairs));
 
			p->pairs[p->np].a = ar;
 
			p->pairs[p->np].v = param[0] != '\0' ? stredup(param) : "";
 
			p->np++;
 
		}
 
	}
 
}
 
@@ -651,13 +652,13 @@ static bool CheckCommandsMatch(char *a, 
 

	
 
	ExtractCommandString(&templ, b, true);
 
	ExtractCommandString(&lang, a, true);
 

	
 
	/* For each string in templ, see if we find it in lang */
 
	if (templ.np != lang.np) {
 
		strgen_warning("%s: template string and language string have a different # of commands", name);
 
		StrgenWarning("{}: template string and language string have a different # of commands", name);
 
		result = false;
 
	}
 

	
 
	for (uint i = 0; i < templ.np; i++) {
 
		/* see if we find it in lang, and zero it out */
 
		bool found = false;
 
@@ -669,22 +670,22 @@ static bool CheckCommandsMatch(char *a, 
 
				found = true;
 
				break;
 
			}
 
		}
 

	
 
		if (!found) {
 
			strgen_warning("%s: command '%s' exists in template file but not in language file", name, templ.pairs[i].a->cmd);
 
			StrgenWarning("{}: command '{}' exists in template file but not in language file", name, templ.pairs[i].a->cmd);
 
			result = false;
 
		}
 
	}
 

	
 
	/* if we reach here, all non consumer commands match up.
 
	 * Check if the non consumer commands match up also. */
 
	for (uint i = 0; i < lengthof(templ.cmd); i++) {
 
		if (TranslateCmdForCompare(templ.cmd[i]) != lang.cmd[i]) {
 
			strgen_warning("%s: Param idx #%d '%s' doesn't match with template command '%s'", name, i,
 
			StrgenWarning("{}: Param idx #{} '{}' doesn't match with template command '{}'", name, i,
 
				lang.cmd[i]  == nullptr ? "<empty>" : TranslateCmdForCompare(lang.cmd[i])->cmd,
 
				templ.cmd[i] == nullptr ? "<empty>" : templ.cmd[i]->cmd);
 
			result = false;
 
		}
 
	}
 

	
 
@@ -700,13 +701,13 @@ void StringReader::HandleString(char *st
 

	
 
	/* Ignore comments & blank lines */
 
	if (*str == ';' || *str == ' ' || *str == '\0') return;
 

	
 
	char *s = strchr(str, ':');
 
	if (s == nullptr) {
 
		strgen_error("Line has no ':' delimiter");
 
		StrgenError("Line has no ':' delimiter");
 
		return;
 
	}
 

	
 
	char *t;
 
	/* Trim spaces.
 
	 * After this str points to the command name, and s points to the command contents */
 
@@ -715,21 +716,21 @@ void StringReader::HandleString(char *st
 
	s++;
 

	
 
	/* Check string is valid UTF-8 */
 
	const char *tmp;
 
	for (tmp = s; *tmp != '\0';) {
 
		size_t len = Utf8Validate(tmp);
 
		if (len == 0) strgen_fatal("Invalid UTF-8 sequence in '%s'", s);
 
		if (len == 0) StrgenFatal("Invalid UTF-8 sequence in '{}'", s);
 

	
 
		WChar c;
 
		Utf8Decode(&c, tmp);
 
		if (c <= 0x001F || // ASCII control character range
 
				c == 0x200B || // Zero width space
 
				(c >= 0xE000 && c <= 0xF8FF) || // Private range
 
				(c >= 0xFFF0 && c <= 0xFFFF)) { // Specials range
 
			strgen_fatal("Unwanted UTF-8 character U+%04X in sequence '%s'", c, s);
 
			StrgenFatal("Unwanted UTF-8 character U+{:04X} in sequence '{}'", (int)c, s);
 
		}
 

	
 
		tmp += len;
 
	}
 

	
 
	/* Check if the string has a case..
 
@@ -739,36 +740,36 @@ void StringReader::HandleString(char *st
 

	
 
	/* Check if this string already exists.. */
 
	LangString *ent = this->data.Find(str);
 

	
 
	if (this->master) {
 
		if (casep != nullptr) {
 
			strgen_error("Cases in the base translation are not supported.");
 
			StrgenError("Cases in the base translation are not supported.");
 
			return;
 
		}
 

	
 
		if (ent != nullptr) {
 
			strgen_error("String name '%s' is used multiple times", str);
 
			StrgenError("String name '{}' is used multiple times", str);
 
			return;
 
		}
 

	
 
		if (this->data.strings[this->data.next_string_id] != nullptr) {
 
			strgen_error("String ID 0x" PRINTF_SIZEX " for '%s' already in use by '%s'", this->data.next_string_id, str, this->data.strings[this->data.next_string_id]->name);
 
			StrgenError("String ID {:#X} for '{}' already in use by '{}'", this->data.next_string_id, str, this->data.strings[this->data.next_string_id]->name);
 
			return;
 
		}
 

	
 
		/* Allocate a new LangString */
 
		this->data.Add(str, new LangString(str, s, this->data.next_string_id++, _cur_line));
 
	} else {
 
		if (ent == nullptr) {
 
			strgen_warning("String name '%s' does not exist in master file", str);
 
			StrgenWarning("String name '{}' does not exist in master file", str);
 
			return;
 
		}
 

	
 
		if (ent->translated && casep == nullptr) {
 
			strgen_error("String name '%s' is used multiple times", str);
 
			StrgenError("String name '{}' is used multiple times", str);
 
			return;
 
		}
 

	
 
		/* make sure that the commands match */
 
		if (!CheckCommandsMatch(s, ent->english, str)) return;
 

	
 
@@ -786,16 +787,16 @@ void StringReader::HandleString(char *st
 

	
 
void StringReader::HandlePragma(char *str)
 
{
 
	if (!memcmp(str, "plural ", 7)) {
 
		_lang.plural_form = atoi(str + 7);
 
		if (_lang.plural_form >= lengthof(_plural_forms)) {
 
			strgen_fatal("Invalid pluralform %d", _lang.plural_form);
 
			StrgenFatal("Invalid pluralform {}", _lang.plural_form);
 
		}
 
	} else {
 
		strgen_fatal("unknown pragma '%s'", str);
 
		StrgenFatal("unknown pragma '{}'", str);
 
	}
 
}
 

	
 
static void rstrip(char *buf)
 
{
 
	size_t i = strlen(buf);
 
@@ -826,13 +827,13 @@ void StringReader::ParseFile()
 
		rstrip(buf);
 
		this->HandleString(buf);
 
		_cur_line++;
 
	}
 

	
 
	if (this->data.next_string_id == this->data.max_strings) {
 
		strgen_error("Too many strings, maximum allowed is " PRINTF_SIZE, this->data.max_strings);
 
		StrgenError("Too many strings, maximum allowed is {}", this->data.max_strings);
 
	}
 
}
 

	
 
/**
 
 * Write the header information.
 
 * @param data The data about the string.
 
@@ -852,21 +853,21 @@ void HeaderWriter::WriteHeader(const Str
 

	
 
static int TranslateArgumentIdx(int argidx, int offset)
 
{
 
	int sum;
 

	
 
	if (argidx < 0 || (uint)argidx >= lengthof(_cur_pcs.cmd)) {
 
		strgen_fatal("invalid argidx %d", argidx);
 
		StrgenFatal("invalid argidx {}", argidx);
 
	}
 
	const CmdStruct *cs = _cur_pcs.cmd[argidx];
 
	if (cs != nullptr && cs->consumes <= offset) {
 
		strgen_fatal("invalid argidx offset %d:%d", argidx, offset);
 
		StrgenFatal("invalid argidx offset {}:{}", argidx, offset);
 
	}
 

	
 
	if (_cur_pcs.cmd[argidx] == nullptr) {
 
		strgen_fatal("no command for this argidx %d", argidx);
 
		StrgenFatal("no command for this argidx {}", argidx);
 
	}
 

	
 
	for (int i = sum = 0; i < argidx; i++) {
 
		cs = _cur_pcs.cmd[i];
 

	
 
		sum += (cs != nullptr) ? cs->consumes : 1;
 
@@ -912,13 +913,13 @@ static void PutCommandString(Buffer *buf
 
				PutArgidxCommand(buffer);
 
			}
 

	
 
			/* Output the one from the master string... it's always accurate. */
 
			cs = _cur_pcs.cmd[_cur_argidx++];
 
			if (cs == nullptr) {
 
				strgen_fatal("%s: No argument exists at position %d", _cur_ident, _cur_argidx - 1);
 
				StrgenFatal("{}: No argument exists at position {}", _cur_ident, _cur_argidx - 1);
 
			}
 
		}
 

	
 
		cs->proc(buffer, param, cs->value);
 
	}
 
}
 
@@ -929,13 +930,13 @@ static void PutCommandString(Buffer *buf
 
 */
 
void LanguageWriter::WriteLength(uint length)
 
{
 
	char buffer[2];
 
	int offs = 0;
 
	if (length >= 0x4000) {
 
		strgen_fatal("string too long");
 
		StrgenFatal("string too long");
 
	}
 

	
 
	if (length >= 0xC0) {
 
		buffer[offs++] = (length >> 8) | 0xC0;
 
	}
 
	buffer[offs++] = length & 0xFF;
 
@@ -984,13 +985,13 @@ void LanguageWriter::WriteLang(const Str
 
			_cur_ident = ls->name;
 
			_cur_line = ls->line;
 

	
 
			/* Produce a message if a string doesn't have a translation. */
 
			if (_show_todo > 0 && ls->translated == nullptr) {
 
				if ((_show_todo & 2) != 0) {
 
					strgen_warning("'%s' is untranslated", ls->name);
 
					StrgenWarning("'{}' is untranslated", ls->name);
 
				}
 
				if ((_show_todo & 1) != 0) {
 
					const char *s = "<TODO> ";
 
					while (*s != '\0') buffer.AppendByte(*s++);
 
				}
 
			}
0 comments (0 inline, 0 general)