Changeset - r18941:8b8e5486e2f8
[Not reviewed]
master
0 4 0
frosch - 13 years ago 2012-01-15 15:49:01
frosch@openttd.org
(svn r23805) -Add: {STRING6} and {STRING7}.
4 files changed with 17 insertions and 44 deletions:
0 comments (0 inline, 0 general)
src/strgen/strgen_base.cpp
Show inline comments
 
@@ -534,192 +534,194 @@ static const CmdStruct *ParseCommandStri
 

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

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

	
 

	
 
	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);
 
				return NULL;
 
			}
 
			if (s - start == MAX_COMMAND_PARAM_SIZE) error("param command too long");
 
			*param++ = c;
 
		}
 
	}
 
	*param = '\0';
 

	
 
	*str = s;
 

	
 
	return cmd;
 
}
 

	
 
/**
 
 * Prepare reading.
 
 * @param data        The data to fill during reading.
 
 * @param file        The file we are reading.
 
 * @param master      Are we reading the master file?
 
 * @param translation Are we reading a translation?
 
 */
 
StringReader::StringReader(StringData &data, const char *file, bool master, bool translation) :
 
		data(data), file(strdup(file)), master(master), translation(translation)
 
{
 
}
 

	
 
/** Make sure the right reader gets freed. */
 
StringReader::~StringReader()
 
{
 
	free(file);
 
}
 

	
 
static void ExtractCommandString(ParsedCommandStruct *p, const char *s, bool warnings)
 
{
 
	char param[MAX_COMMAND_PARAM_SIZE];
 
	int argno;
 
	int argidx = 0;
 
	int casei;
 

	
 
	memset(p, 0, sizeof(*p));
 

	
 
	for (;;) {
 
		/* read until next command from a. */
 
		const CmdStruct *ar = ParseCommandString(&s, param, &argno, &casei);
 

	
 
		if (ar == NULL) break;
 

	
 
		/* Sanity checking */
 
		if (argno != -1 && ar->consumes == 0) strgen_fatal("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] != NULL && p->cmd[argidx] != ar) strgen_fatal("duplicate param idx %d", 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));
 
			p->pairs[p->np].a = ar;
 
			p->pairs[p->np].v = param[0] != '\0' ? strdup(param) : "";
 
			p->np++;
 
		}
 
	}
 
}
 

	
 

	
 
static const CmdStruct *TranslateCmdForCompare(const CmdStruct *a)
 
{
 
	if (a == NULL) return NULL;
 

	
 
	if (strcmp(a->cmd, "STRING1") == 0 ||
 
			strcmp(a->cmd, "STRING2") == 0 ||
 
			strcmp(a->cmd, "STRING3") == 0 ||
 
			strcmp(a->cmd, "STRING4") == 0 ||
 
			strcmp(a->cmd, "STRING5") == 0 ||
 
			strcmp(a->cmd, "STRING6") == 0 ||
 
			strcmp(a->cmd, "STRING7") == 0 ||
 
			strcmp(a->cmd, "RAW_STRING") == 0) {
 
		return FindCmd("STRING", 6);
 
	}
 

	
 
	return a;
 
}
 

	
 

	
 
static bool CheckCommandsMatch(char *a, char *b, const char *name)
 
{
 
	/* If we're not translating, i.e. we're compiling the base language,
 
	 * it is pointless to do all these checks as it'll always be correct.
 
	 * After all, all checks are based on the base language.
 
	 */
 
	if (!_translation) return true;
 

	
 
	ParsedCommandStruct templ;
 
	ParsedCommandStruct lang;
 
	bool result = true;
 

	
 
	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);
 
		result = false;
 
	}
 

	
 
	for (uint i = 0; i < templ.np; i++) {
 
		/* see if we find it in lang, and zero it out */
 
		bool found = false;
 
		for (uint j = 0; j < lang.np; j++) {
 
			if (templ.pairs[i].a == lang.pairs[j].a &&
 
					strcmp(templ.pairs[i].v, lang.pairs[j].v) == 0) {
 
				/* it was found in both. zero it out from lang so we don't find it again */
 
				lang.pairs[j].a = NULL;
 
				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);
 
			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,
 
				lang.cmd[i]  == NULL ? "<empty>" : TranslateCmdForCompare(lang.cmd[i])->cmd,
 
				templ.cmd[i] == NULL ? "<empty>" : templ.cmd[i]->cmd);
 
			result = false;
 
		}
 
	}
 

	
 
	return result;
 
}
 

	
 
void StringReader::HandleString(char *str)
 
{
 
	if (*str == '#') {
 
		if (str[1] == '#' && str[2] != '#') this->HandlePragma(str + 2);
 
		return;
 
	}
 

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

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

	
 
	char *t;
 
	/* Trim spaces.
 
	 * After this str points to the command name, and s points to the command contents */
 
	for (t = s; t > str && (t[-1] == ' ' || t[-1] == '\t'); t--) {}
 
	*t = 0;
 
	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);
 

	
 
		WChar c;
 
		Utf8Decode(&c, tmp);
 
		if (c <= 0x001F || // ASCII control character range
 
				(c >= 0xE000 && c <= 0xF8FF) || // Private range
 
				(c >= 0xFFF0 && c <= 0xFFFF)) { // Specials range
src/strings.cpp
Show inline comments
 
@@ -875,237 +875,203 @@ static char *FormatString(char *buff, co
 
				}
 
				str = ParseStringChoice(str, gender, &buff, last);
 
				break;
 
			}
 

	
 
			/* This sets up the gender for the string.
 
			 * We just ignore this one. It's used in {G 0 Der Die Das} to determine the case. */
 
			case SCC_GENDER_INDEX: // {GENDER 0}
 
				if (_keep_gender_data) {
 
					buff += Utf8Encode(buff, SCC_GENDER_INDEX);
 
					*buff++ = *str++;
 
				} else {
 
					str++;
 
				}
 
				break;
 

	
 
			case SCC_PLURAL_LIST: { // {P}
 
				int plural_form = *str++;          // contains the plural form for this string
 
				uint offset = orig_offset + (byte)*str++;
 
				int64 v = *args->GetPointerToOffset(offset); // contains the number that determines plural
 
				str = ParseStringChoice(str, DeterminePluralForm(v, plural_form), &buff, last);
 
				break;
 
			}
 

	
 
			case SCC_ARG_INDEX: { // Move argument pointer
 
				args->offset = orig_offset + (byte)*str++;
 
				break;
 
			}
 

	
 
			case SCC_SET_CASE: { // {SET_CASE}
 
				/* This is a pseudo command, it's outputted when someone does {STRING.ack}
 
				 * The modifier is added to all subsequent GetStringWithArgs that accept the modifier. */
 
				next_substr_case_index = (byte)*str++;
 
				break;
 
			}
 

	
 
			case SCC_SWITCH_CASE: { // {Used to implement case switching}
 
				/* <0x9E> <NUM CASES> <CASE1> <LEN1> <STRING1> <CASE2> <LEN2> <STRING2> <CASE3> <LEN3> <STRING3> <STRINGDEFAULT>
 
				 * Each LEN is printed using 2 bytes in big endian order. */
 
				uint num = (byte)*str++;
 
				while (num) {
 
					if ((byte)str[0] == case_index) {
 
						/* Found the case, adjust str pointer and continue */
 
						str += 3;
 
						break;
 
					}
 
					/* Otherwise skip to the next case */
 
					str += 3 + (str[1] << 8) + str[2];
 
					num--;
 
				}
 
				break;
 
			}
 

	
 
			case SCC_SETX: // {SETX}
 
				if (buff + Utf8CharLen(SCC_SETX) + 1 < last) {
 
					buff += Utf8Encode(buff, SCC_SETX);
 
					*buff++ = *str++;
 
				}
 
				break;
 

	
 
			case SCC_SETXY: // {SETXY}
 
				if (buff + Utf8CharLen(SCC_SETXY) + 2 < last) {
 
					buff += Utf8Encode(buff, SCC_SETXY);
 
					*buff++ = *str++;
 
					*buff++ = *str++;
 
				}
 
				break;
 

	
 
			case SCC_REVISION: // {REV}
 
				buff = strecpy(buff, _openttd_revision, last);
 
				break;
 

	
 
			case SCC_STRING_ID: // {STRINL}
 
				if (game_script) break;
 
				buff = GetStringWithArgs(buff, Utf8Consume(&str), args, last);
 
				break;
 

	
 
			case SCC_RAW_STRING_POINTER: { // {RAW_STRING}
 
				if (game_script) break;
 
				const char *str = (const char *)(size_t)args->GetInt64(SCC_RAW_STRING_POINTER);
 
				buff = FormatString(buff, str, args, last);
 
				break;
 
			}
 

	
 
			case SCC_STRING: {// {STRING}
 
				StringID str = args->GetInt32(SCC_STRING);
 
				if (game_script && GB(str, TAB_COUNT_OFFSET, TAB_COUNT_BITS) != GAME_TEXT_TAB) break;
 
				/* WARNING. It's prohibited for the included string to consume any arguments.
 
				 * For included strings that consume argument, you should use STRING1, STRING2 etc.
 
				 * To debug stuff you can set argv to NULL and it will tell you */
 
				StringParameters tmp_params(args->GetDataPointer(), args->num_param - args->offset, NULL);
 
				buff = GetStringWithArgs(buff, str, &tmp_params, last, next_substr_case_index, game_script);
 
				next_substr_case_index = 0;
 
				break;
 
			}
 

	
 
			case SCC_STRING1: { // {STRING1}
 
				/* String that consumes ONE argument */
 
				StringID str = args->GetInt32(SCC_STRING1);
 
				if (game_script && GB(str, TAB_COUNT_OFFSET, TAB_COUNT_BITS) != GAME_TEXT_TAB) break;
 
				StringParameters sub_args(*args, 1);
 
				buff = GetStringWithArgs(buff, str, &sub_args, last, next_substr_case_index, game_script);
 
				next_substr_case_index = 0;
 
				break;
 
			}
 

	
 
			case SCC_STRING2: { // {STRING2}
 
				/* String that consumes TWO arguments */
 
				StringID str = args->GetInt32(SCC_STRING2);
 
			case SCC_STRING1:
 
			case SCC_STRING2:
 
			case SCC_STRING3:
 
			case SCC_STRING4:
 
			case SCC_STRING5:
 
			case SCC_STRING6:
 
			case SCC_STRING7: { // {STRING1..7}
 
				/* Strings that consume arguments */
 
				StringID str = args->GetInt32(b);
 
				if (game_script && GB(str, TAB_COUNT_OFFSET, TAB_COUNT_BITS) != GAME_TEXT_TAB) break;
 
				StringParameters sub_args(*args, 2);
 
				buff = GetStringWithArgs(buff, str, &sub_args, last, next_substr_case_index, game_script);
 
				next_substr_case_index = 0;
 
				break;
 
			}
 

	
 
			case SCC_STRING3: { // {STRING3}
 
				/* String that consumes THREE arguments */
 
				StringID str = args->GetInt32(SCC_STRING3);
 
				if (game_script && GB(str, TAB_COUNT_OFFSET, TAB_COUNT_BITS) != GAME_TEXT_TAB) break;
 
				StringParameters sub_args(*args, 3);
 
				buff = GetStringWithArgs(buff, str, &sub_args, last, next_substr_case_index, game_script);
 
				next_substr_case_index = 0;
 
				break;
 
			}
 

	
 
			case SCC_STRING4: { // {STRING4}
 
				/* String that consumes FOUR arguments */
 
				StringID str = args->GetInt32(SCC_STRING4);
 
				if (game_script && GB(str, TAB_COUNT_OFFSET, TAB_COUNT_BITS) != GAME_TEXT_TAB) break;
 
				StringParameters sub_args(*args, 4);
 
				buff = GetStringWithArgs(buff, str, &sub_args, last, next_substr_case_index, game_script);
 
				next_substr_case_index = 0;
 
				break;
 
			}
 

	
 
			case SCC_STRING5: { // {STRING5}
 
				/* String that consumes FIVE arguments */
 
				StringID str = args->GetInt32(SCC_STRING5);
 
				if (game_script && GB(str, TAB_COUNT_OFFSET, TAB_COUNT_BITS) != GAME_TEXT_TAB) break;
 
				StringParameters sub_args(*args, 5);
 
				StringParameters sub_args(*args, b - SCC_STRING1 + 1);
 
				buff = GetStringWithArgs(buff, str, &sub_args, last, next_substr_case_index, game_script);
 
				next_substr_case_index = 0;
 
				break;
 
			}
 

	
 
			case SCC_COMMA: // {COMMA}
 
				buff = FormatCommaNumber(buff, args->GetInt64(SCC_COMMA), last);
 
				break;
 

	
 
			case SCC_DECIMAL: {// {DECIMAL}
 
				int64 number = args->GetInt64(SCC_DECIMAL);
 
				int digits = args->GetInt32(SCC_DECIMAL);
 
				buff = FormatCommaNumber(buff, number, last, digits);
 
				break;
 
			}
 

	
 
			case SCC_NUM: // {NUM}
 
				buff = FormatNoCommaNumber(buff, args->GetInt64(SCC_NUM), last);
 
				break;
 

	
 
			case SCC_ZEROFILL_NUM: { // {ZEROFILL_NUM}
 
				int64 num = args->GetInt64();
 
				buff = FormatZerofillNumber(buff, num, args->GetInt64(), last);
 
				break;
 
			}
 

	
 
			case SCC_HEX: // {HEX}
 
				buff = FormatHexNumber(buff, (uint64)args->GetInt64(SCC_HEX), last);
 
				break;
 

	
 
			case SCC_BYTES: // {BYTES}
 
				buff = FormatBytes(buff, args->GetInt64(), last);
 
				break;
 

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

	
 
				StringID cargo_str = CargoSpec::Get(cargo)->units_volume;
 
				int64 amount = 0;
 
				switch (cargo_str) {
 
					case STR_TONS:
 
						amount = _units[_settings_game.locale.units].c_weight.ToDisplay(args->GetInt64());
 
						break;
 

	
 
					case STR_LITERS:
 
						amount = _units[_settings_game.locale.units].c_volume.ToDisplay(args->GetInt64());
 
						break;
 

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

	
 
				buff = FormatCommaNumber(buff, amount, last);
 
				break;
 
			}
 

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

	
 
				StringID cargo_str = CargoSpec::Get(cargo)->units_volume;
 
				switch (cargo_str) {
 
					case STR_TONS: {
 
						assert(_settings_game.locale.units < lengthof(_units));
 
						int64 args_array[] = {_units[_settings_game.locale.units].c_weight.ToDisplay(args->GetInt64())};
 
						StringParameters tmp_params(args_array);
 
						buff = FormatString(buff, GetStringPtr(_units[_settings_game.locale.units].l_weight), &tmp_params, last);
 
						break;
 
					}
 

	
 
					case STR_LITERS: {
 
						assert(_settings_game.locale.units < lengthof(_units));
 
						int64 args_array[] = {_units[_settings_game.locale.units].c_volume.ToDisplay(args->GetInt64())};
 
						StringParameters tmp_params(args_array);
 
						buff = FormatString(buff, GetStringPtr(_units[_settings_game.locale.units].l_volume), &tmp_params, last);
 
						break;
 
					}
 

	
 
					default: {
 
						StringParameters tmp_params(*args, 1);
 
						buff = GetStringWithArgs(buff, cargo_str, &tmp_params, last);
 
						break;
 
					}
 
				}
 
				break;
 
			}
 

	
src/table/control_codes.h
Show inline comments
 
/* $Id$ */
 

	
 
/*
 
 * 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 control_codes.h Control codes that are embedded in the translation strings. */
 

	
 
#ifndef CONTROL_CODES_H
 
#define CONTROL_CODES_H
 

	
 
/**
 
 * List of string control codes used for string formatting, displaying, and
 
 * by strgen to generate the language files.
 
 */
 
enum StringControlCode {
 
	SCC_CONTROL_START = 0xE000,
 
	SCC_CONTROL_END   = 0xE1FF,
 

	
 
	SCC_SPRITE_START  = 0xE200,
 
	SCC_SPRITE_END    = SCC_SPRITE_START + 0xFF,
 

	
 
	/* Display control codes */
 
	SCC_SETX = SCC_CONTROL_START,
 
	SCC_SETXY,
 
	SCC_TINYFONT,  ///< Switch to small font
 
	SCC_BIGFONT,   ///< Switch to large font
 

	
 
	/* Formatting control codes */
 
	SCC_REVISION,
 
	SCC_COMPANY_NUM,
 
	SCC_STATION_FEATURES,
 
	SCC_INDUSTRY_NAME,
 
	SCC_WAYPOINT_NAME,
 
	SCC_STATION_NAME,
 
	SCC_DEPOT_NAME,
 
	SCC_TOWN_NAME,
 
	SCC_GROUP_NAME,
 
	SCC_VEHICLE_NAME,
 
	SCC_SIGN_NAME,
 
	SCC_COMPANY_NAME,
 
	SCC_PRESIDENT_NAME,
 
	SCC_ENGINE_NAME,
 

	
 
	SCC_CURRENCY_SHORT,
 
	SCC_CURRENCY_LONG,
 

	
 
	SCC_CARGO_LONG,
 
	SCC_CARGO_SHORT,
 
	SCC_CARGO_TINY,
 
	SCC_POWER,
 
	SCC_VOLUME_LONG,
 
	SCC_VOLUME_SHORT,
 
	SCC_WEIGHT_LONG,
 
	SCC_WEIGHT_SHORT,
 
	SCC_FORCE,
 
	SCC_VELOCITY,
 
	SCC_HEIGHT,
 

	
 
	SCC_DATE_TINY,
 
	SCC_DATE_SHORT,
 
	SCC_DATE_LONG,
 
	SCC_DATE_ISO,
 

	
 
	/* Must be consecutive */
 
	SCC_STRING1,
 
	SCC_STRING2,
 
	SCC_STRING3,
 
	SCC_STRING4,
 
	SCC_STRING5,
 
	SCC_STRING6,
 
	SCC_STRING7,
 

	
 
	SCC_ENCODED,
 

	
 
	SCC_STRING,
 
	SCC_COMMA,
 
	SCC_DECIMAL,
 
	SCC_NUM,
 
	SCC_ZEROFILL_NUM,
 
	SCC_HEX,
 
	SCC_BYTES,
 

	
 
	SCC_STRING_ID,
 
	SCC_RAW_STRING_POINTER,
 
	SCC_PLURAL_LIST,
 
	SCC_GENDER_LIST,
 
	SCC_GENDER_INDEX,
 
	SCC_ARG_INDEX,
 
	SCC_SET_CASE,
 
	SCC_SWITCH_CASE,
 

	
 
	/* Colour codes */
 
	SCC_BLUE,
 
	SCC_SILVER,
 
	SCC_GOLD,
 
	SCC_RED,
 
	SCC_PURPLE,
 
	SCC_LTBROWN,
 
	SCC_ORANGE,
 
	SCC_GREEN,
 
	SCC_YELLOW,
 
	SCC_DKGREEN,
 
	SCC_CREAM,
 
	SCC_BROWN,
 
	SCC_WHITE,
 
	SCC_LTBLUE,
 
	SCC_GRAY,
 
	SCC_DKBLUE,
 
	SCC_BLACK,
 
	SCC_PREVIOUS_COLOUR,
 

	
 
	/**
 
	 * The next variables are part of a NewGRF subsystem for creating text strings.
 
	 * It uses a "stack" of bytes and reads from there.
 
	 */
 
	SCC_NEWGRF_FIRST,
 
	SCC_NEWGRF_PRINT_DWORD_SIGNED = SCC_NEWGRF_FIRST, ///< Read 4 bytes from the stack
 
	SCC_NEWGRF_PRINT_WORD_SIGNED,                     ///< Read 2 bytes from the stack as signed value
 
	SCC_NEWGRF_PRINT_BYTE_SIGNED,                     ///< Read 1 byte from the stack as signed value
 
	SCC_NEWGRF_PRINT_WORD_UNSIGNED,                   ///< Read 2 bytes from the stack as unsigned value
 
	SCC_NEWGRF_PRINT_DWORD_CURRENCY,                  ///< Read 4 bytes from the stack as currency
 
	SCC_NEWGRF_PRINT_WORD_STRING_ID,                  ///< Read 2 bytes from the stack as String ID
 
	SCC_NEWGRF_PRINT_WORD_DATE_LONG,                  ///< Read 2 bytes from the stack as base 1920 date
 
	SCC_NEWGRF_PRINT_WORD_DATE_SHORT,                 ///< Read 2 bytes from the stack as base 1920 date
 
	SCC_NEWGRF_PRINT_WORD_SPEED,                      ///< Read 2 bytes from the stack as signed speed
 
	SCC_NEWGRF_PRINT_WORD_VOLUME_LONG,                ///< Read 2 bytes from the stack as long signed volume
 
	SCC_NEWGRF_PRINT_WORD_WEIGHT_LONG,                ///< Read 2 bytes from the stack as long unsigned weight
 
	SCC_NEWGRF_PRINT_WORD_STATION_NAME,               ///< Read 2 bytes from the stack as station name
 
	SCC_NEWGRF_PRINT_QWORD_CURRENCY,                  ///< Read 8 bytes from the stack as currency
 
	SCC_NEWGRF_PRINT_BYTE_HEX,                        ///< Read 1 byte from the stack and print it as hex
 
	SCC_NEWGRF_PRINT_WORD_HEX,                        ///< Read 2 bytes from the stack and print it as hex
 
	SCC_NEWGRF_PRINT_DWORD_HEX,                       ///< Read 4 bytes from the stack and print it as hex
 
	SCC_NEWGRF_PRINT_QWORD_HEX,                       ///< Read 8 bytes from the stack and print it as hex
 
	SCC_NEWGRF_PRINT_DWORD_DATE_LONG,                 ///< Read 4 bytes from the stack as base 0 date
 
	SCC_NEWGRF_PRINT_DWORD_DATE_SHORT,                ///< Read 4 bytes from the stack as base 0 date
 
	SCC_NEWGRF_PRINT_WORD_POWER,                      ///< Read 2 bytes from the stack as unsigned power
 
	SCC_NEWGRF_PRINT_WORD_VOLUME_SHORT,               ///< Read 2 bytes from the stack as short signed volume
 
	SCC_NEWGRF_PRINT_WORD_WEIGHT_SHORT,               ///< Read 2 bytes from the stack as short unsigned weight
 
	SCC_NEWGRF_PUSH_WORD,                             ///< Pushes 2 bytes onto the stack
 
	SCC_NEWGRF_UNPRINT,                               ///< "Unprints" the given number of bytes from the string
 
	SCC_NEWGRF_DISCARD_WORD,                          ///< Discard the next two bytes
 
	SCC_NEWGRF_ROTATE_TOP_4_WORDS,                    ///< Rotate the top 4 words of the stack (W4 W1 W2 W3)
 
	SCC_NEWGRF_LAST = SCC_NEWGRF_ROTATE_TOP_4_WORDS,
 

	
 
	SCC_NEWGRF_STRINL,                                ///< Inline another string at the current position, StringID is encoded in the string
 

	
 
	/* Special printable symbols.
 
	 * These are mapped to the original glyphs */
 
	SCC_LESS_THAN        = SCC_SPRITE_START + 0x3C,
 
	SCC_GREATER_THAN     = SCC_SPRITE_START + 0x3E,
 
	SCC_UP_ARROW         = SCC_SPRITE_START + 0xA0,
 
	SCC_DOWN_ARROW       = SCC_SPRITE_START + 0xAA,
 
	SCC_CHECKMARK        = SCC_SPRITE_START + 0xAC,
 
	SCC_CROSS            = SCC_SPRITE_START + 0xAD,
 
	SCC_RIGHT_ARROW      = SCC_SPRITE_START + 0xAF,
 
	SCC_TRAIN            = SCC_SPRITE_START + 0xB4,
 
	SCC_LORRY            = SCC_SPRITE_START + 0xB5,
 
	SCC_BUS              = SCC_SPRITE_START + 0xB6,
 
	SCC_PLANE            = SCC_SPRITE_START + 0xB7,
 
	SCC_SHIP             = SCC_SPRITE_START + 0xB8,
 
	SCC_SUPERSCRIPT_M1   = SCC_SPRITE_START + 0xB9,
 
	SCC_SMALL_UP_ARROW   = SCC_SPRITE_START + 0xBC,
 
	SCC_SMALL_DOWN_ARROW = SCC_SPRITE_START + 0xBD,
 
};
 

	
 
#endif /* CONTROL_CODES_H */
src/table/strgen_tables.h
Show inline comments
 
/* $Id$ */
 

	
 
/*
 
 * 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 table/strgen_tables.h Tables of commands for strgen */
 

	
 
#include "../core/enum_type.hpp"
 

	
 
enum CmdFlags {
 
	C_NONE      = 0x0, ///< Nothing special about this command
 
	C_DONTCOUNT = 0x1, ///< These commands aren't counted for comparison
 
	C_CASE      = 0x2, ///< These commands support cases
 
	C_GENDER    = 0x4, ///< These commands support genders
 
};
 
DECLARE_ENUM_AS_BIT_SET(CmdFlags)
 

	
 
struct Buffer;
 
typedef void (*ParseCmdProc)(Buffer *buffer, char *buf, int value);
 

	
 
struct CmdStruct {
 
	const char *cmd;
 
	ParseCmdProc proc;
 
	long value;
 
	uint8 consumes;
 
	CmdFlags flags;
 
};
 

	
 
extern void EmitSingleChar(Buffer *buffer, char *buf, int value);
 
extern void EmitPlural(Buffer *buffer, char *buf, int value);
 
extern void EmitGender(Buffer *buffer, char *buf, int value);
 

	
 
static const CmdStruct _cmd_structs[] = {
 
	/* Font size */
 
	{"TINY_FONT",         EmitSingleChar, SCC_TINYFONT,           0, C_NONE},
 
	{"BIG_FONT",          EmitSingleChar, SCC_BIGFONT,            0, C_NONE},
 

	
 
	/* Colours */
 
	{"BLUE",              EmitSingleChar, SCC_BLUE,               0, C_NONE},
 
	{"SILVER",            EmitSingleChar, SCC_SILVER,             0, C_NONE},
 
	{"GOLD",              EmitSingleChar, SCC_GOLD,               0, C_NONE},
 
	{"RED",               EmitSingleChar, SCC_RED,                0, C_NONE},
 
	{"PURPLE",            EmitSingleChar, SCC_PURPLE,             0, C_NONE},
 
	{"LTBROWN",           EmitSingleChar, SCC_LTBROWN,            0, C_NONE},
 
	{"ORANGE",            EmitSingleChar, SCC_ORANGE,             0, C_NONE},
 
	{"GREEN",             EmitSingleChar, SCC_GREEN,              0, C_NONE},
 
	{"YELLOW",            EmitSingleChar, SCC_YELLOW,             0, C_NONE},
 
	{"DKGREEN",           EmitSingleChar, SCC_DKGREEN,            0, C_NONE},
 
	{"CREAM",             EmitSingleChar, SCC_CREAM,              0, C_NONE},
 
	{"BROWN",             EmitSingleChar, SCC_BROWN,              0, C_NONE},
 
	{"WHITE",             EmitSingleChar, SCC_WHITE,              0, C_NONE},
 
	{"LTBLUE",            EmitSingleChar, SCC_LTBLUE,             0, C_NONE},
 
	{"GRAY",              EmitSingleChar, SCC_GRAY,               0, C_NONE},
 
	{"DKBLUE",            EmitSingleChar, SCC_DKBLUE,             0, C_NONE},
 
	{"BLACK",             EmitSingleChar, SCC_BLACK,              0, C_NONE},
 

	
 
	{"REV",               EmitSingleChar, SCC_REVISION,           0, C_NONE}, // openttd revision string
 

	
 
	{"STRING1",           EmitSingleChar, SCC_STRING1,            2, C_CASE | C_GENDER}, // included string that consumes the string id and ONE argument
 
	{"STRING2",           EmitSingleChar, SCC_STRING2,            3, C_CASE | C_GENDER}, // included string that consumes the string id and TWO arguments
 
	{"STRING3",           EmitSingleChar, SCC_STRING3,            4, C_CASE | C_GENDER}, // included string that consumes the string id and THREE arguments
 
	{"STRING4",           EmitSingleChar, SCC_STRING4,            5, C_CASE | C_GENDER}, // included string that consumes the string id and FOUR arguments
 
	{"STRING5",           EmitSingleChar, SCC_STRING5,            6, C_CASE | C_GENDER}, // included string that consumes the string id and FIVE arguments
 
	{"STRING6",           EmitSingleChar, SCC_STRING6,            7, C_CASE | C_GENDER}, // included string that consumes the string id and SIX arguments
 
	{"STRING7",           EmitSingleChar, SCC_STRING7,            8, C_CASE | C_GENDER}, // included string that consumes the string id and SEVEN arguments
 

	
 
	{"STATION_FEATURES",  EmitSingleChar, SCC_STATION_FEATURES,   1, C_NONE}, // station features string, icons of the features
 
	{"INDUSTRY",          EmitSingleChar, SCC_INDUSTRY_NAME,      1, C_CASE | C_GENDER}, // industry, takes an industry #, can have cases
 
	{"CARGO_LONG",        EmitSingleChar, SCC_CARGO_LONG,         2, C_NONE | C_GENDER},
 
	{"CARGO_SHORT",       EmitSingleChar, SCC_CARGO_SHORT,        2, C_NONE}, // short cargo description, only ### tons, or ### litres
 
	{"CARGO_TINY",        EmitSingleChar, SCC_CARGO_TINY,         2, C_NONE}, // tiny cargo description with only the amount, not a specifier for the amount or the actual cargo name
 
	{"POWER",             EmitSingleChar, SCC_POWER,              1, C_NONE},
 
	{"VOLUME_LONG",       EmitSingleChar, SCC_VOLUME_LONG,        1, C_NONE},
 
	{"VOLUME_SHORT",      EmitSingleChar, SCC_VOLUME_SHORT,       1, C_NONE},
 
	{"WEIGHT_LONG",       EmitSingleChar, SCC_WEIGHT_LONG,        1, C_NONE},
 
	{"WEIGHT_SHORT",      EmitSingleChar, SCC_WEIGHT_SHORT,       1, C_NONE},
 
	{"FORCE",             EmitSingleChar, SCC_FORCE,              1, C_NONE},
 
	{"VELOCITY",          EmitSingleChar, SCC_VELOCITY,           1, C_NONE},
 
	{"HEIGHT",            EmitSingleChar, SCC_HEIGHT,             1, C_NONE},
 

	
 
	{"P",                 EmitPlural,     0,                      0, C_DONTCOUNT}, // plural specifier
 
	{"G",                 EmitGender,     0,                      0, C_DONTCOUNT}, // gender specifier
 

	
 
	{"DATE_TINY",         EmitSingleChar, SCC_DATE_TINY,          1, C_NONE},
 
	{"DATE_SHORT",        EmitSingleChar, SCC_DATE_SHORT,         1, C_CASE},
 
	{"DATE_LONG",         EmitSingleChar, SCC_DATE_LONG,          1, C_CASE},
 
	{"DATE_ISO",          EmitSingleChar, SCC_DATE_ISO,           1, C_NONE},
 

	
 
	{"STRING",            EmitSingleChar, SCC_STRING,             1, C_CASE | C_GENDER},
 
	{"RAW_STRING",        EmitSingleChar, SCC_RAW_STRING_POINTER, 1, C_NONE | C_GENDER},
 

	
 
	/* Numbers */
 
	{"COMMA",             EmitSingleChar, SCC_COMMA,              1, C_NONE}, // Number with comma
 
	{"DECIMAL",           EmitSingleChar, SCC_DECIMAL,            2, C_NONE}, // Number with comma and fractional part. Second parameter is number of fractional digits, first parameter is number times 10**(second parameter).
 
	{"NUM",               EmitSingleChar, SCC_NUM,                1, C_NONE}, // Signed number
 
	{"ZEROFILL_NUM",      EmitSingleChar, SCC_ZEROFILL_NUM,       2, C_NONE}, // Unsigned number with zero fill, e.g. "02". First parameter is number, second minimum length
 
	{"BYTES",             EmitSingleChar, SCC_BYTES,              1, C_NONE}, // Unsigned number with "bytes", i.e. "1.02 MiB or 123 KiB"
 
	{"HEX",               EmitSingleChar, SCC_HEX,                1, C_NONE}, // Hexadecimally printed number
 

	
 
	{"CURRENCY_LONG",     EmitSingleChar, SCC_CURRENCY_LONG,      1, C_NONE},
 
	{"CURRENCY_SHORT",    EmitSingleChar, SCC_CURRENCY_SHORT,     1, C_NONE}, // compact currency
 

	
 
	{"WAYPOINT",          EmitSingleChar, SCC_WAYPOINT_NAME,      1, C_NONE | C_GENDER}, // waypoint name
 
	{"STATION",           EmitSingleChar, SCC_STATION_NAME,       1, C_NONE | C_GENDER},
 
	{"DEPOT",             EmitSingleChar, SCC_DEPOT_NAME,         2, C_NONE | C_GENDER},
 
	{"TOWN",              EmitSingleChar, SCC_TOWN_NAME,          1, C_NONE | C_GENDER},
 
	{"GROUP",             EmitSingleChar, SCC_GROUP_NAME,         1, C_NONE | C_GENDER},
 
	{"SIGN",              EmitSingleChar, SCC_SIGN_NAME,          1, C_NONE | C_GENDER},
 
	{"ENGINE",            EmitSingleChar, SCC_ENGINE_NAME,        1, C_NONE | C_GENDER},
 
	{"VEHICLE",           EmitSingleChar, SCC_VEHICLE_NAME,       1, C_NONE | C_GENDER},
 
	{"COMPANY",           EmitSingleChar, SCC_COMPANY_NAME,       1, C_NONE | C_GENDER},
 
	{"COMPANY_NUM",       EmitSingleChar, SCC_COMPANY_NUM,        1, C_NONE},
 
	{"PRESIDENT_NAME",    EmitSingleChar, SCC_PRESIDENT_NAME,     1, C_NONE | C_GENDER},
 

	
 
	{"",                  EmitSingleChar, '\n',                   0, C_DONTCOUNT},
 
	{"{",                 EmitSingleChar, '{',                    0, C_DONTCOUNT},
 
	{"UP_ARROW",          EmitSingleChar, SCC_UP_ARROW,           0, C_DONTCOUNT},
 
	{"SMALL_UP_ARROW",    EmitSingleChar, SCC_SMALL_UP_ARROW,     0, C_DONTCOUNT},
 
	{"SMALL_DOWN_ARROW",  EmitSingleChar, SCC_SMALL_DOWN_ARROW,   0, C_DONTCOUNT},
 
	{"TRAIN",             EmitSingleChar, SCC_TRAIN,              0, C_DONTCOUNT},
 
	{"LORRY",             EmitSingleChar, SCC_LORRY,              0, C_DONTCOUNT},
 
	{"BUS",               EmitSingleChar, SCC_BUS,                0, C_DONTCOUNT},
 
	{"PLANE",             EmitSingleChar, SCC_PLANE,              0, C_DONTCOUNT},
 
	{"SHIP",              EmitSingleChar, SCC_SHIP,               0, C_DONTCOUNT},
 
	{"NBSP",              EmitSingleChar, 0xA0,                   0, C_DONTCOUNT},
 
	{"CENT",              EmitSingleChar, 0xA2,                   0, C_DONTCOUNT},
 
	{"POUND_SIGN",        EmitSingleChar, 0xA3,                   0, C_DONTCOUNT},
 
	{"EURO",              EmitSingleChar, 0x20AC,                 0, C_DONTCOUNT},
 
	{"YEN_SIGN",          EmitSingleChar, 0xA5,                   0, C_DONTCOUNT},
 
	{"COPYRIGHT",         EmitSingleChar, 0xA9,                   0, C_DONTCOUNT},
 
	{"DOWN_ARROW",        EmitSingleChar, SCC_DOWN_ARROW,         0, C_DONTCOUNT},
 
	{"CHECKMARK",         EmitSingleChar, SCC_CHECKMARK,          0, C_DONTCOUNT},
 
	{"CROSS",             EmitSingleChar, SCC_CROSS,              0, C_DONTCOUNT},
 
	{"REGISTERED",        EmitSingleChar, 0xAE,                   0, C_DONTCOUNT},
 
	{"RIGHT_ARROW",       EmitSingleChar, SCC_RIGHT_ARROW,        0, C_DONTCOUNT},
 
	{"SMALL_LEFT_ARROW",  EmitSingleChar, SCC_LESS_THAN,          0, C_DONTCOUNT},
 
	{"SMALL_RIGHT_ARROW", EmitSingleChar, SCC_GREATER_THAN,       0, C_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, C_DONTCOUNT},
 
	{"RLM",               EmitSingleChar, CHAR_TD_RLM,            0, C_DONTCOUNT},
 
	{"LRE",               EmitSingleChar, CHAR_TD_LRE,            0, C_DONTCOUNT},
 
	{"RLE",               EmitSingleChar, CHAR_TD_RLE,            0, C_DONTCOUNT},
 
	{"LRO",               EmitSingleChar, CHAR_TD_LRO,            0, C_DONTCOUNT},
 
	{"RLO",               EmitSingleChar, CHAR_TD_RLO,            0, C_DONTCOUNT},
 
	{"PDF",               EmitSingleChar, CHAR_TD_PDF,            0, C_DONTCOUNT},
 
};
 

	
 
/** Description of a plural form */
 
struct PluralForm {
 
	int plural_count;        ///< The number of plural forms
 
	const char *description; ///< Human readable description of the form
 
};
 

	
 
/** All plural forms used */
 
static const PluralForm _plural_forms[] = {
 
	{ 2, "Two forms, singular used for 1 only" },
 
	{ 1, "Only one form" },
 
	{ 2, "Two forms, singular used for zero and 1" },
 
	{ 3, "Three forms, special case for 0 and ending in 1, except those ending in 11" },
0 comments (0 inline, 0 general)