# strings.cpp

Go to the documentation of this file.

    00001 /* $Id$ */
    00002
    00003 /*
    00004  * This file is part of OpenTTD.
    00005  * 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.
    00006  * 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.
    00007  * 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/>.
    00008  */
    00009
    00012 #include "stdafx.h"
    00013 #include "currency.h"
    00014 #include "station_base.h"
    00015 #include "town.h"
    00016 #include "screenshot.h"
    00017 #include "waypoint_base.h"
    00018 #include "depot_base.h"
    00019 #include "industry.h"
    00020 #include "newgrf_text.h"
    00021 #include "fileio_func.h"
    00022 #include "group.h"
    00023 #include "signs_base.h"
    00024 #include "cargotype.h"
    00025 #include "fontcache.h"
    00026 #include "gui.h"
    00027 #include "strings_func.h"
    00028 #include "rev.h"
    00029 #include "core/endian_func.hpp"
    00030 #include "date_func.h"
    00031 #include "vehicle_base.h"
    00032 #include "engine_base.h"
    00033 #include "language.h"
    00034 #include "townname_func.h"
    00035 #include "string_func.h"
    00036 #include "company_base.h"
    00037 #include "smallmap_gui.h"
    00038 #include "window_func.h"
    00039 #include "debug.h"
    00040 #include <stack>
    00041
    00042 #include "table/strings.h"
    00043 #include "table/control_codes.h"
    00044
    00045 char _config_language_file[MAX_PATH];
    00046 LanguageList _languages;
    00047 const LanguageMetadata *_current_language = NULL;
    00048
    00049 TextDirection _current_text_dir;
    00050 uint64 _decode_parameters[20];
    00051 WChar _parameter_type[20];
    00052
    00053 #ifdef WITH_ICU
    00054 Collator *_current_collator = NULL;
    00055 #endif /* WITH_ICU */
    00056
    00057 static char *StationGetSpecialString(char *buff, int x, const char *last);
    00058 static char *GetSpecialTownNameString(char *buff, int ind, uint32 seed, const char *last);
    00059 static char *GetSpecialNameString(char *buff, int ind, int64 *argv, const int64 *argve, const char *last, WChar *argt = NULL);
    00060
    00061 static char *FormatString(char *buff, const char *str, int64 *argv, const int64 *argve, uint casei, const char *last, WChar *argt = NULL, bool dry_run = false);
    00062
    00063 struct LanguagePack : public LanguagePackHeader {
    00064   char data[]; // list of strings
    00065 };
    00066
    00067 static char **_langpack_offs;
    00068 static LanguagePack *_langpack;
    00069 static uint _langtab_num[32];
    00070 static uint _langtab_start[32];
    00071 static bool _keep_gender_data = false;
    00072
    00073
    00084 static inline int64 GetInt64(int64 **argv, const int64 *argve, WChar **argt, WChar type = 0)
    00085 {
    00086   assert(*argv != NULL);
    00087   assert(*argv < argve);
    00088   if (*argt != NULL) {
    00089     assert(**argt == 0 || **argt == type);
    00090     **argt = type;
    00091     (*argt)++;
    00092   }
    00093   return *(*argv)++;
    00094 }
    00095
    00097 static inline int32 GetInt32(int64 **argv, const int64 *argve, WChar **argt, WChar type = 0)
    00098 {
    00099   return (int32)GetInt64(argv, argve, argt, type);
    00100 }
    00101
    00110 static inline int64 *GetArgvPtr(int64 **argv, int n, const int64 *argve, WChar **argt)
    00111 {
    00112   int64 *result;
    00113   assert(*argv != NULL);
    00114   assert((*argv + n) <= argve);
    00115   result = *argv;
    00116   (*argv) += n;
    00117   if (*argt != NULL) (*argt) += n;
    00118   return result;
    00119 }
    00120
    00121
    00122 const char *GetStringPtr(StringID string)
    00123 {
    00124   switch (GB(string, 11, 5)) {
    00125     /* GetGRFStringPtr doesn't handle 0xD4xx ids, we need to convert those to 0xD0xx. */
    00126     case 26: return GetStringPtr(GetGRFStringID(0, 0xD000 + GB(string, 0, 10)));
    00127     case 28: return GetGRFStringPtr(GB(string, 0, 11));
    00128     case 29: return GetGRFStringPtr(GB(string, 0, 11) + 0x0800);
    00129     case 30: return GetGRFStringPtr(GB(string, 0, 11) + 0x1000);
    00130     default: return _langpack_offs[_langtab_start[string >> 11] + (string & 0x7FF)];
    00131   }
    00132 }
    00133
    00147 char *GetStringWithArgs(char *buffr, uint string, int64 *argv, const int64 *argve, const char *last, WChar *argt)
    00148 {
    00149   if (GB(string, 0, 16) == 0) return GetStringWithArgs(buffr, STR_UNDEFINED, argv, argve, last, argt);
    00150
    00151   uint index = GB(string,  0, 11);
    00152   uint tab   = GB(string, 11,  5);
    00153
    00154   switch (tab) {
    00155     case 4:
    00156       if (index >= 0xC0) {
    00157         return GetSpecialTownNameString(buffr, index - 0xC0, GetInt32(&argv, argve, &argt), last);
    00158       }
    00159       break;
    00160
    00161     case 14:
    00162       if (index >= 0xE4) {
    00163         return GetSpecialNameString(buffr, index - 0xE4, argv, argve, last, argt);
    00164       }
    00165       break;
    00166
    00167     case 15:
    00168       /* Old table for custom names. This is no longer used */
    00169       error("Incorrect conversion of custom name string.");
    00170
    00171     case 26:
    00172       /* Include string within newgrf text (format code 81) */
    00173       if (HasBit(index, 10)) {
    00174         StringID string = GetGRFStringID(0, 0xD000 + GB(index, 0, 10));
    00175         return GetStringWithArgs(buffr, string, argv, argve, last, argt);
    00176       }
    00177       break;
    00178
    00179     case 28:
    00180       return FormatString(buffr, GetGRFStringPtr(index), argv, argve, GB(string, 24, 8), last, argt);
    00181
    00182     case 29:
    00183       return FormatString(buffr, GetGRFStringPtr(index + 0x0800), argv, argve, GB(string, 24, 8), last, argt);
    00184
    00185     case 30:
    00186       return FormatString(buffr, GetGRFStringPtr(index + 0x1000), argv, argve, GB(string, 24, 8), last, argt);
    00187
    00188     case 31:
    00189       NOT_REACHED();
    00190   }
    00191
    00192   if (index >= _langtab_num[tab]) {
    00193     error("String 0x%X is invalid. You are probably using an old version of the .lng file.\n", string);
    00194   }
    00195
    00196   return FormatString(buffr, GetStringPtr(GB(string, 0, 16)), argv, argve, GB(string, 24, 8), last, argt);
    00197 }
    00198
    00199 char *GetString(char *buffr, StringID string, const char *last)
    00200 {
    00201   memset(_parameter_type, 0, sizeof(_parameter_type));
    00202   return GetStringWithArgs(buffr, string, (int64*)_decode_parameters, (int64*)endof(_decode_parameters), last, _parameter_type);
    00203 }
    00204
    00205
    00206 char *InlineString(char *buf, StringID string)
    00207 {
    00208   buf += Utf8Encode(buf, SCC_STRING_ID);
    00209   buf += Utf8Encode(buf, string);
    00210   return buf;
    00211 }
    00212
    00213
    00219 void SetDParamStr(uint n, const char *str)
    00220 {
    00221   SetDParam(n, (uint64)(size_t)str);
    00222 }
    00223
    00228 void InjectDParam(uint amount)
    00229 {
    00230   assert((uint)amount < lengthof(_decode_parameters));
    00231   memmove(_decode_parameters + amount, _decode_parameters, sizeof(_decode_parameters) - amount * sizeof(uint64));
    00232 }
    00233
    00234 static char *FormatNumber(char *buff, int64 number, const char *last, const char *separator, int zerofill_from = 19)
    00235 {
    00236   uint64 divisor = 10000000000000000000ULL;
    00237
    00238   if (number < 0) {
    00239     buff += seprintf(buff, last, "-");
    00240     number = -number;
    00241   }
    00242
    00243   uint64 num = number;
    00244   uint64 tot = 0;
    00245   for (int i = 0; i < 20; i++) {
    00246     uint64 quot = 0;
    00247     if (num >= divisor) {
    00248       quot = num / divisor;
    00249       num = num % divisor;
    00250     }
    00251     if (tot |= quot || i >= zerofill_from) {
    00252       buff += seprintf(buff, last, "%i", (int)quot);
    00253       if ((i % 3) == 1 && i != 19) buff = strecpy(buff, separator, last);
    00254     }
    00255
    00256     divisor /= 10;
    00257   }
    00258
    00259   *buff = '\0';
    00260
    00261   return buff;
    00262 }
    00263
    00264 static char *FormatCommaNumber(char *buff, int64 number, const char *last)
    00265 {
    00266   const char *separator = _settings_game.locale.digit_group_separator;
    00267   if (separator == NULL) separator = _langpack->digit_group_separator;
    00268   return FormatNumber(buff, number, last, separator);
    00269 }
    00270
    00271 static char *FormatNoCommaNumber(char *buff, int64 number, const char *last)
    00272 {
    00273   return FormatNumber(buff, number, last, "");
    00274 }
    00275
    00276 static char *FormatZerofillNumber(char *buff, int64 number, int64 count, const char *last)
    00277 {
    00278   return FormatNumber(buff, number, last, "", 20 - count);
    00279 }
    00280
    00281 static char *FormatHexNumber(char *buff, uint64 number, const char *last)
    00282 {
    00283   return buff + seprintf(buff, last, "0x" OTTD_PRINTFHEX64, number);
    00284 }
    00285
    00293 static char *FormatBytes(char *buff, int64 number, const char *last)
    00294 {
    00295   assert(number >= 0);
    00296
    00297   /*                                    1   2^10  2^20  2^30  2^40  2^50  2^60 */
    00298   const char * const iec_prefixes[] = { "", "Ki", "Mi", "Gi", "Ti", "Pi", "Ei" };
    00299   uint id = 1;
    00300   while (number >= 1024 * 1024) {
    00301     number /= 1024;
    00302     id++;
    00303   }
    00304
    00305   const char *decimal_separator = _settings_game.locale.digit_decimal_separator;
    00306   if (decimal_separator == NULL) decimal_separator = _langpack->digit_decimal_separator;
    00307
    00308   if (number < 1024) {
    00309     id = 0;
    00310     buff += seprintf(buff, last, "%i", (int)number);
    00311   } else if (number < 1024 * 10) {
    00312     buff += seprintf(buff, last, "%i%s%02i", (int)number / 1024, decimal_separator, (int)(number % 1024) * 100 / 1024);
    00313   } else if (number < 1024 * 100) {
    00314     buff += seprintf(buff, last, "%i%s%01i", (int)number / 1024, decimal_separator, (int)(number % 1024) * 10 / 1024);
    00315   } else {
    00316     assert(number < 1024 * 1024);
    00317     buff += seprintf(buff, last, "%i", (int)number / 1024);
    00318   }
    00319
    00320   assert(id < lengthof(iec_prefixes));
    00321   buff += seprintf(buff, last, " %sB", iec_prefixes[id]);
    00322
    00323   return buff;
    00324 }
    00325
    00326 static char *FormatYmdString(char *buff, Date date, uint modifier, const char *last)
    00327 {
    00328   YearMonthDay ymd;
    00329   ConvertDateToYMD(date, &ymd);
    00330
    00331   int64 args[3] = { ymd.day + STR_ORDINAL_NUMBER_1ST - 1, STR_MONTH_ABBREV_JAN + ymd.month, ymd.year };
    00332   return FormatString(buff, GetStringPtr(STR_FORMAT_DATE_LONG), args, endof(args), modifier >> 24, last);
    00333 }
    00334
    00335 static char *FormatMonthAndYear(char *buff, Date date, uint modifier, const char *last)
    00336 {
    00337   YearMonthDay ymd;
    00338   ConvertDateToYMD(date, &ymd);
    00339
    00340   int64 args[2] = { STR_MONTH_JAN + ymd.month, ymd.year };
    00341   return FormatString(buff, GetStringPtr(STR_FORMAT_DATE_SHORT), args, endof(args), modifier >> 24, last);
    00342 }
    00343
    00344 static char *FormatTinyOrISODate(char *buff, Date date, StringID str, const char *last)
    00345 {
    00346   YearMonthDay ymd;
    00347   ConvertDateToYMD(date, &ymd);
    00348
    00349   char day[3];
    00350   char month[3];
    00351   /* We want to zero-pad the days and months */
    00352   snprintf(day,   lengthof(day),   "%02i", ymd.day);
    00353   snprintf(month, lengthof(month), "%02i", ymd.month + 1);
    00354
    00355   int64 args[3] = { (int64)(size_t)day, (int64)(size_t)month, ymd.year };
    00356   return FormatString(buff, GetStringPtr(str), args, endof(args), 0, last);
    00357 }
    00358
    00359 static char *FormatGenericCurrency(char *buff, const CurrencySpec *spec, Money number, bool compact, const char *last)
    00360 {
    00361   /* We are going to make number absolute for printing, so
    00362    * keep this piece of data as we need it later on */
    00363   bool negative = number < 0;
    00364   const char *multiplier = "";
    00365
    00366   number *= spec->rate;
    00367
    00368   /* convert from negative */
    00369   if (number < 0) {
    00370     if (buff + Utf8CharLen(SCC_RED) > last) return buff;
    00371     buff += Utf8Encode(buff, SCC_RED);
    00372     buff = strecpy(buff, "-", last);
    00373     number = -number;
    00374   }
    00375
    00376   /* Add prefix part, folowing symbol_pos specification.
    00377    * Here, it can can be either 0 (prefix) or 2 (both prefix anf suffix).
    00378    * The only remaining value is 1 (suffix), so everything that is not 1 */
    00379   if (spec->symbol_pos != 1) buff = strecpy(buff, spec->prefix, last);
    00380
    00381   /* for huge numbers, compact the number into k or M */
    00382   if (compact) {
    00383     /* Take care of the 'k' rounding. Having 1 000 000 k
    00384      * and 1 000 M is inconsistent, so always use 1 000 M. */
    00385     if (number >= 1000000000 - 500) {
    00386       number = (number + 500000) / 1000000;
    00387       multiplier = "M";
    00388     } else if (number >= 1000000) {
    00389       number = (number + 500) / 1000;
    00390       multiplier = "k";
    00391     }
    00392   }
    00393
    00394   const char *separator = _settings_game.locale.digit_group_separator_currency;
    00395   if (separator == NULL && !StrEmpty(_currency->separator)) separator = _currency->separator;
    00396   if (separator == NULL) separator = _langpack->digit_group_separator_currency;
    00397   buff = FormatNumber(buff, number, last, separator);
    00398   buff = strecpy(buff, multiplier, last);
    00399
    00400   /* Add suffix part, folowing symbol_pos specification.
    00401    * Here, it can can be either 1 (suffix) or 2 (both prefix anf suffix).
    00402    * The only remaining value is 1 (prefix), so everything that is not 0 */
    00403   if (spec->symbol_pos != 0) buff = strecpy(buff, spec->suffix, last);
    00404
    00405   if (negative) {
    00406     if (buff + Utf8CharLen(SCC_PREVIOUS_COLOUR) > last) return buff;
    00407     buff += Utf8Encode(buff, SCC_PREVIOUS_COLOUR);
    00408     *buff = '\0';
    00409   }
    00410
    00411   return buff;
    00412 }
    00413
    00420 static int DeterminePluralForm(int64 count, int plural_form)
    00421 {
    00422   /* The absolute value determines plurality */
    00423   uint64 n = abs(count);
    00424
    00425   switch (plural_form) {
    00426     default:
    00427       NOT_REACHED();
    00428
    00429     /* Two forms, singular used for one only
    00430      * Used in:
    00431      *   Danish, Dutch, English, German, Norwegian, Swedish, Estonian, Finnish,
    00432      *   Greek, Hebrew, Italian, Portuguese, Spanish, Esperanto */
    00433     case 0:
    00434       return n != 1;
    00435
    00436     /* Only one form
    00437      * Used in:
    00438      *   Hungarian, Japanese, Korean, Turkish */
    00439     case 1:
    00440       return 0;
    00441
    00442     /* Two forms, singular used for zero and one
    00443      * Used in:
    00444      *   French, Brazilian Portuguese */
    00445     case 2:
    00446       return n > 1;
    00447
    00448     /* Three forms, special case for 0 and ending in 1, except those ending in 11
    00449      * Used in:
    00450      *   Latvian */
    00451     case 3:
    00452       return n % 10 == 1 && n % 100 != 11 ? 0 : n != 0 ? 1 : 2;
    00453
    00454     /* Five forms, special case for one, two, 3 to 6 and 7 to 10
    00455      * Used in:
    00456      *   Gaelige (Irish) */
    00457     case 4:
    00458       return n == 1 ? 0 : n == 2 ? 1 : n < 7 ? 2 : n < 11 ? 3 : 4;
    00459
    00460     /* Three forms, special case for numbers ending in 1[2-9]
    00461      * Used in:
    00462      *   Lithuanian */
    00463     case 5:
    00464       return n % 10 == 1 && n % 100 != 11 ? 0 : n % 10 >= 2 && (n % 100 < 10 || n % 100 >= 20) ? 1 : 2;
    00465
    00466     /* Three forms, special cases for numbers ending in 1 and 2, 3, 4, except those ending in 1[1-4]
    00467      * Used in:
    00468      *   Croatian, Russian, Ukrainian */
    00469     case 6:
    00470       return n % 10 == 1 && n % 100 != 11 ? 0 : n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 10 || n % 100 >= 20) ? 1 : 2;
    00471
    00472     /* Three forms, special case for one and some numbers ending in 2, 3, or 4
    00473      * Used in:
    00474      *   Polish */
    00475     case 7:
    00476       return n == 1 ? 0 : n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 10 || n % 100 >= 20) ? 1 : 2;
    00477
    00478     /* Four forms, special case for one and all numbers ending in 02, 03, or 04
    00479      * Used in:
    00480      *   Slovenian */
    00481     case 8:
    00482       return n % 100 == 1 ? 0 : n % 100 == 2 ? 1 : n % 100 == 3 || n % 100 == 4 ? 2 : 3;
    00483
    00484     /* Two forms; singular used for everything ending in 1 but not in 11.
    00485      * Used in:
    00486      *   Icelandic */
    00487     case 9:
    00488       return n % 10 == 1 && n % 100 != 11 ? 0 : 1;
    00489
    00490     /* Three forms, special cases for one and 2, 3, or 4
    00491      * Used in:
    00492      *   Czech, Slovak */
    00493     case 10:
    00494       return n == 1 ? 0 : n >= 2 && n <= 4 ? 1 : 2;
    00495
    00496     /* Two forms, special 'hack' for Korean; singular for numbers ending
    00497      *   in a consonant and plural for numbers ending in a vowel.
    00498      * Korean doesn't have the concept of plural, but depending on how a
    00499      * number is pronounced it needs another version of a particle.
    00500      * As such the plural system is misused to give this distinction.
    00501      */
    00502     case 11:
    00503       switch (n % 10) {
    00504         case 0: // yeong
    00505         case 1: // il
    00506         case 3: // sam
    00507         case 6: // yuk
    00508         case 7: // chil
    00509         case 8: // pal
    00510           return 0;
    00511
    00512         case 2: // i
    00513         case 4: // sa
    00514         case 5: // o
    00515         case 9: // gu
    00516           return 1;
    00517
    00518         default:
    00519           NOT_REACHED();
    00520       }
    00521
    00522     /* Four forms: one, 0 and everything ending in 02..10, everything ending in 11..19.
    00523      * Used in:
    00524      *  Maltese */
    00525     case 12:
    00526       return (n == 1 ? 0 : n == 0 || (n % 100 > 1 && n % 100 < 11) ? 1 : (n % 100 > 10 && n % 100 < 20) ? 2 : 3);
    00527   }
    00528 }
    00529
    00530 static const char *ParseStringChoice(const char *b, uint form, char **dst, const char *last)
    00531 {
    00532   /* <NUM> {Length of each string} {each string} */
    00533   uint n = (byte)*b++;
    00534   uint pos, i, mypos = 0;
    00535
    00536   for (i = pos = 0; i != n; i++) {
    00537     uint len = (byte)*b++;
    00538     if (i == form) mypos = pos;
    00539     pos += len;
    00540   }
    00541
    00542   *dst += seprintf(*dst, last, "%s", b + mypos);
    00543   return b + pos;
    00544 }
    00545
    00547 struct UnitConversion {
    00548   int multiplier;
    00549   int shift;
    00550
    00557   int64 ToDisplay(int64 input, bool round = true) const
    00558   {
    00559     return ((input * this->multiplier) + (round && this->shift != 0 ? 1 << (this->shift - 1) : 0)) >> this->shift;
    00560   }
    00561
    00568   int64 FromDisplay(int64 input, bool round = true) const
    00569   {
    00570     return ((input << this->shift) + (round ? this->multiplier / 2 : 0)) / this->multiplier;
    00571   }
    00572 };
    00573
    00574 struct Units {
    00575   UnitConversion c_velocity;
    00576   StringID velocity;
    00577   UnitConversion c_power;
    00578   StringID power;
    00579   UnitConversion c_weight;
    00580   StringID s_weight;
    00581   StringID l_weight;
    00582   UnitConversion c_volume;
    00583   StringID s_volume;
    00584   StringID l_volume;
    00585   UnitConversion c_force;
    00586   StringID force;
    00587   UnitConversion c_height;
    00588   StringID height;
    00589 };
    00590
    00591 /* Unit conversions */
    00592 static const Units _units[] = {
    00593   { // Imperial (Original, mph, hp, metric ton, litre, kN, ft)
    00594     {   1,  0}, STR_UNITS_VELOCITY_IMPERIAL,
    00595     {   1,  0}, STR_UNITS_POWER_IMPERIAL,
    00596     {   1,  0}, STR_UNITS_WEIGHT_SHORT_METRIC, STR_UNITS_WEIGHT_LONG_METRIC,
    00597     {1000,  0}, STR_UNITS_VOLUME_SHORT_METRIC, STR_UNITS_VOLUME_LONG_METRIC,
    00598     {   1,  0}, STR_UNITS_FORCE_SI,
    00599     {   3,  0}, STR_UNITS_HEIGHT_IMPERIAL, // "Wrong" conversion factor for more nicer GUI values
    00600   },
    00601   { // Metric (km/h, hp, metric ton, litre, kN, metre)
    00602     { 103,  6}, STR_UNITS_VELOCITY_METRIC,
    00603     {4153, 12}, STR_UNITS_POWER_METRIC,
    00604     {   1,  0}, STR_UNITS_WEIGHT_SHORT_METRIC, STR_UNITS_WEIGHT_LONG_METRIC,
    00605     {1000,  0}, STR_UNITS_VOLUME_SHORT_METRIC, STR_UNITS_VOLUME_LONG_METRIC,
    00606     {   1,  0}, STR_UNITS_FORCE_SI,
    00607     {   1,  0}, STR_UNITS_HEIGHT_SI,
    00608   },
    00609   { // SI (m/s, kilowatt, kilogram, cubic metre, kilonewton, metre)
    00610     {1831, 12}, STR_UNITS_VELOCITY_SI,
    00611     {6109, 13}, STR_UNITS_POWER_SI,
    00612     {1000,  0}, STR_UNITS_WEIGHT_SHORT_SI, STR_UNITS_WEIGHT_LONG_SI,
    00613     {   1,  0}, STR_UNITS_VOLUME_SHORT_SI, STR_UNITS_VOLUME_LONG_SI,
    00614     {   1,  0}, STR_UNITS_FORCE_SI,
    00615     {   1,  0}, STR_UNITS_HEIGHT_SI,
    00616   },
    00617 };
    00618
    00624 uint ConvertSpeedToDisplaySpeed(uint speed)
    00625 {
    00626   /* For historical reasons we don't want to mess with the
    00627    * conversion for speed. So, don't round it and keep the
    00628    * original conversion factors instead of the real ones. */
    00629   return _units[_settings_game.locale.units].c_velocity.ToDisplay(speed, false);
    00630 }
    00631
    00637 uint ConvertDisplaySpeedToSpeed(uint speed)
    00638 {
    00639   return _units[_settings_game.locale.units].c_velocity.FromDisplay(speed);
    00640 }
    00641
    00653 static char *FormatString(char *buff, const char *str_arg, int64 *argv, const int64 *argve, uint casei, const char *last, WChar *argt, bool dry_run)
    00654 {
    00655   /* When there is no array with types there is no need to do a dry run. */
    00656   if (argt == NULL) dry_run = true;
    00657   if (UsingNewGRFTextStack() && !dry_run) {
    00658     /* Values from the NewGRF text stack are only copied to the normal
    00659      * argv array at the time they are encountered. That means that if
    00660      * another string command references a value later in the string it
    00661      * would fail. We solve that by running FormatString twice. The first
    00662      * pass makes sure the argv array is correctly filled and the second
    00663      * pass can reference later values without problems. */
    00664     struct TextRefStack *backup = CreateTextRefStackBackup();
    00665     FormatString(buff, str_arg, argv, argve, casei, last, argt, true);
    00666     RestoreTextRefStackBackup(backup);
    00667   } else if (!dry_run) {
    00668     FormatString(buff, str_arg, argv, argve, casei, last, argt, true);
    00669   }
    00670   WChar b;
    00671   int64 *argv_orig = argv;
    00672   WChar *argt_orig = argt;
    00673   uint modifier = 0;
    00674   char *buf_start = buff;
    00675   std::stack<const char *> str_stack;
    00676   str_stack.push(str_arg);
    00677
    00678   while (true) {
    00679     while (!str_stack.empty() && (b = Utf8Consume(&str_stack.top())) == '\0') {
    00680       str_stack.pop();
    00681     }
    00682     if (str_stack.empty()) break;
    00683     const char *&str = str_stack.top();
    00684
    00685     if (SCC_NEWGRF_FIRST <= b && b <= SCC_NEWGRF_LAST) {
    00686       /* We need to pass some stuff as it might be modified; oh boy. */
    00687       //todo: should argve be passed here too?
    00688       b = RemapNewGRFStringControlCode(b, buf_start, &buff, &str, argv);
    00689       if (b == 0) continue;
    00690     }
    00691
    00692     switch (b) {
    00693       case SCC_NEWGRF_STRINL: {
    00694         StringID substr = Utf8Consume(&str);
    00695         str_stack.push(GetStringPtr(substr));
    00696         break;
    00697       }
    00698
    00699       case SCC_NEWGRF_PRINT_STRING_ID: {
    00700         StringID substr = GetInt32(&argv, argve, &argt, SCC_NEWGRF_PRINT_STRING_ID);
    00701         str_stack.push(GetStringPtr(substr));
    00702         break;
    00703       }
    00704
    00705
    00706       case SCC_SETX: // {SETX}
    00707         if (buff + Utf8CharLen(SCC_SETX) + 1 < last) {
    00708           buff += Utf8Encode(buff, SCC_SETX);
    00709           *buff++ = *str++;
    00710         }
    00711         break;
    00712
    00713       case SCC_SETXY: // {SETXY}
    00714         if (buff + Utf8CharLen(SCC_SETXY) + 2 < last) {
    00715           buff += Utf8Encode(buff, SCC_SETXY);
    00716           *buff++ = *str++;
    00717           *buff++ = *str++;
    00718         }
    00719         break;
    00720
    00721       case SCC_STRING_ID: // {STRINL}
    00722         buff = GetStringWithArgs(buff, Utf8Consume(&str), argv, argve, last, argt);
    00723         break;
    00724
    00725       case SCC_RAW_STRING_POINTER: { // {RAW_STRING}
    00726         const char *str = (const char*)(size_t)GetInt64(&argv, argve, &argt);
    00727         buff = FormatString(buff, str, argv, argve, casei, last, argt);
    00728         break;
    00729       }
    00730
    00731       case SCC_DATE_LONG: // {DATE_LONG}
    00732         buff = FormatYmdString(buff, GetInt32(&argv, argve, &argt, SCC_DATE_LONG), modifier, last);
    00733         break;
    00734
    00735       case SCC_DATE_SHORT: // {DATE_SHORT}
    00736         buff = FormatMonthAndYear(buff, GetInt32(&argv, argve, &argt, SCC_DATE_SHORT), modifier, last);
    00737         break;
    00738
    00739       case SCC_VELOCITY: { // {VELOCITY}
    00740         int64 args[1];
    00741         assert(_settings_game.locale.units < lengthof(_units));
    00742         args[0] = ConvertSpeedToDisplaySpeed(GetInt64(&argv, argve, &argt, SCC_VELOCITY) * 10 / 16);
    00743         buff = FormatString(buff, GetStringPtr(_units[_settings_game.locale.units].velocity), args, endof(args), modifier >> 24, last);
    00744         modifier = 0;
    00745         break;
    00746       }
    00747
    00748       case SCC_HEIGHT: { // {HEIGHT}
    00749         int64 args[1] = {_units[_settings_game.locale.units].c_height.ToDisplay(GetInt64(&argv, argve, &argt))};
    00750         buff = FormatString(buff, GetStringPtr(_units[_settings_game.locale.units].height), args, endof(args), modifier >> 24, last);
    00751         modifier = 0;
    00752         break;
    00753       }
    00754
    00755       case SCC_CURRENCY_COMPACT: // {CURRCOMPACT}
    00756         buff = FormatGenericCurrency(buff, _currency, GetInt64(&argv, argve, &argt), true, last);
    00757         break;
    00758
    00759       case SCC_REVISION: // {REV}
    00760         buff = strecpy(buff, _openttd_revision, last);
    00761         break;
    00762
    00763       case SCC_CARGO_SHORT: { // {SHORTCARGO}
    00764         /* Short description of cargotypes. Layout:
    00765          * 8-bit = cargo type
    00766          * 16-bit = cargo count */
    00767         StringID cargo_str = CargoSpec::Get(GetInt32(&argv, argve, &argt, SCC_CARGO_SHORT))->units_volume;
    00768         switch (cargo_str) {
    00769           case STR_TONS: {
    00770             int64 args[1];
    00771             assert(_settings_game.locale.units < lengthof(_units));
    00772             args[0] = _units[_settings_game.locale.units].c_weight.ToDisplay(GetInt64(&argv, argve, &argt));
    00773             buff = FormatString(buff, GetStringPtr(_units[_settings_game.locale.units].l_weight), args, endof(args), modifier >> 24, last);
    00774             modifier = 0;
    00775             break;
    00776           }
    00777
    00778           case STR_LITERS: {
    00779             int64 args[1];
    00780             assert(_settings_game.locale.units < lengthof(_units));
    00781             args[0] = _units[_settings_game.locale.units].c_volume.ToDisplay(GetInt64(&argv, argve, &argt));
    00782             buff = FormatString(buff, GetStringPtr(_units[_settings_game.locale.units].l_volume), args, endof(args), modifier >> 24, last);
    00783             modifier = 0;
    00784             break;
    00785           }
    00786
    00787           default:
    00788             buff = GetStringWithArgs(buff, cargo_str, argv++, argve, last, argt++);
    00789             break;
    00790         }
    00791         break;
    00792       }
    00793
    00794       case SCC_STRING1: { // {STRING1}
    00795         /* String that consumes ONE argument */
    00796         uint str = modifier + GetInt32(&argv, argve, &argt, SCC_STRING1);
    00797         WChar *orig_argt = argt;
    00798         int64 *args = GetArgvPtr(&argv, 1, argve, &argt);
    00799         buff = GetStringWithArgs(buff, str, args, argve, last, orig_argt);
    00800         modifier = 0;
    00801         break;
    00802       }
    00803
    00804       case SCC_STRING2: { // {STRING2}
    00805         /* String that consumes TWO arguments */
    00806         uint str = modifier + GetInt32(&argv, argve, &argt, SCC_STRING2);
    00807         WChar *orig_argt = argt;
    00808         int64 *args = GetArgvPtr(&argv, 2, argve, &argt);
    00809         buff = GetStringWithArgs(buff, str, args, argve, last, orig_argt);
    00810         modifier = 0;
    00811         break;
    00812       }
    00813
    00814       case SCC_STRING3: { // {STRING3}
    00815         /* String that consumes THREE arguments */
    00816         uint str = modifier + GetInt32(&argv, argve, &argt, SCC_STRING3);
    00817         WChar *orig_argt = argt;
    00818         int64 *args = GetArgvPtr(&argv, 3, argve, &argt);
    00819         buff = GetStringWithArgs(buff, str, args, argve, last, orig_argt);
    00820         modifier = 0;
    00821         break;
    00822       }
    00823
    00824       case SCC_STRING4: { // {STRING4}
    00825         /* String that consumes FOUR arguments */
    00826         uint str = modifier + GetInt32(&argv, argve, &argt, SCC_STRING4);
    00827         WChar *orig_argt = argt;
    00828         int64 *args = GetArgvPtr(&argv, 4, argve, &argt);
    00829         buff = GetStringWithArgs(buff, str, args, argve, last, orig_argt);
    00830         modifier = 0;
    00831         break;
    00832       }
    00833
    00834       case SCC_STRING5: { // {STRING5}
    00835         /* String that consumes FIVE arguments */
    00836         uint str = modifier + GetInt32(&argv, argve, &argt, SCC_STRING5);
    00837         WChar *orig_argt = argt;
    00838         int64 *args = GetArgvPtr(&argv, 5, argve, &argt);
    00839         buff = GetStringWithArgs(buff, str, args, argve, last, orig_argt);
    00840         modifier = 0;
    00841         break;
    00842       }
    00843
    00844       case SCC_STATION_FEATURES: { // {STATIONFEATURES}
    00845         buff = StationGetSpecialString(buff, GetInt32(&argv, argve, &argt, SCC_STATION_FEATURES), last);
    00846         break;
    00847       }
    00848
    00849       case SCC_INDUSTRY_NAME: { // {INDUSTRY}
    00850         const Industry *i = Industry::Get(GetInt32(&argv, argve, &argt, SCC_INDUSTRY_NAME));
    00851         int64 args[2];
    00852
    00853         /* industry not valid anymore? */
    00854         assert(i != NULL);
    00855
    00856         /* First print the town name and the industry type name. */
    00857         args[0] = i->town->index;
    00858         args[1] = GetIndustrySpec(i->type)->name;
    00859         buff = FormatString(buff, GetStringPtr(STR_FORMAT_INDUSTRY_NAME), args, endof(args), modifier >> 24, last);
    00860         modifier = 0;
    00861         break;
    00862       }
    00863
    00864       case SCC_VOLUME: { // {VOLUME}
    00865         int64 args[1];
    00866         assert(_settings_game.locale.units < lengthof(_units));
    00867         args[0] = _units[_settings_game.locale.units].c_volume.ToDisplay(GetInt64(&argv, argve, &argt, SCC_VOLUME));
    00868         buff = FormatString(buff, GetStringPtr(_units[_settings_game.locale.units].l_volume), args, endof(args), modifier >> 24, last);
    00869         modifier = 0;
    00870         break;
    00871       }
    00872
    00873       case SCC_GENDER_LIST: { // {G 0 Der Die Das}
    00874         /* First read the meta data from the language file. */
    00875         byte offset = (byte)*str++;
    00876         assert(argv_orig + offset < argve);
    00877         int gender = 0;
    00878         if (!dry_run && argt != NULL && argt_orig[offset] != 0) {
    00879           /* Now we need to figure out what text to resolve, i.e.
    00880            * what do we need to draw? So get the actual raw string
    00881            * first using the control code to get said string. */
    00882           char input[4 + 1];
    00883           char *p = input + Utf8Encode(input, argt_orig[offset]);
    00884           *p = '\0';
    00885
    00886           /* Now do the string formatting. */
    00887           char buf[256];
    00888           bool old_kgd = _keep_gender_data;
    00889           _keep_gender_data = true;
    00890           p = FormatString(buf, input, argv_orig + offset, argve, 0, lastof(buf));
    00891           _keep_gender_data = old_kgd;
    00892           *p = '\0';
    00893
    00894           /* And determine the string. */
    00895           const char *s = buf;
    00896           WChar c = Utf8Consume(&s);
    00897           /* Does this string have a gender, if so, set it */
    00898           if (c == SCC_GENDER_INDEX) gender = (byte)s[0];
    00899         }
    00900         str = ParseStringChoice(str, gender, &buff, last);
    00901         break;
    00902       }
    00903
    00904       case SCC_DATE_TINY: { // {DATE_TINY}
    00905         buff = FormatTinyOrISODate(buff, GetInt32(&argv, argve, &argt, SCC_DATE_TINY), STR_FORMAT_DATE_TINY, last);
    00906         break;
    00907       }
    00908
    00909       case SCC_DATE_ISO: { // {DATE_ISO}
    00910         buff = FormatTinyOrISODate(buff, GetInt32(&argv, argve, &argt), STR_FORMAT_DATE_ISO, last);
    00911         break;
    00912       }
    00913
    00914       case SCC_CARGO: { // {CARGO}
    00915         /* First parameter is cargo type, second parameter is cargo count */
    00916         CargoID cargo = GetInt32(&argv, argve, &argt, SCC_CARGO);
    00917         StringID cargo_str = (cargo == CT_INVALID) ? STR_QUANTITY_N_A : CargoSpec::Get(cargo)->quantifier;
    00918         buff = GetStringWithArgs(buff, cargo_str, argv++, argve, last);
    00919         break;
    00920       }
    00921
    00922       case SCC_POWER: { // {POWER}
    00923         int64 args[1];
    00924         assert(_settings_game.locale.units < lengthof(_units));
    00925         args[0] = _units[_settings_game.locale.units].c_power.ToDisplay(GetInt64(&argv, argve, &argt));
    00926         buff = FormatString(buff, GetStringPtr(_units[_settings_game.locale.units].power), args, endof(args), modifier >> 24, last);
    00927         modifier = 0;
    00928         break;
    00929       }
    00930
    00931       case SCC_VOLUME_SHORT: { // {VOLUME_S}
    00932         int64 args[1];
    00933         assert(_settings_game.locale.units < lengthof(_units));
    00934         args[0] = _units[_settings_game.locale.units].c_volume.ToDisplay(GetInt64(&argv, argve, &argt));
    00935         buff = FormatString(buff, GetStringPtr(_units[_settings_game.locale.units].s_volume), args, endof(args), modifier >> 24, last);
    00936         modifier = 0;
    00937         break;
    00938       }
    00939
    00940       case SCC_WEIGHT: { // {WEIGHT}
    00941         int64 args[1];
    00942         assert(_settings_game.locale.units < lengthof(_units));
    00943         args[0] = _units[_settings_game.locale.units].c_weight.ToDisplay(GetInt64(&argv, argve, &argt, SCC_WEIGHT));
    00944         buff = FormatString(buff, GetStringPtr(_units[_settings_game.locale.units].l_weight), args, endof(args), modifier >> 24, last);
    00945         modifier = 0;
    00946         break;
    00947       }
    00948
    00949       case SCC_WEIGHT_SHORT: { // {WEIGHT_S}
    00950         int64 args[1];
    00951         assert(_settings_game.locale.units < lengthof(_units));
    00952         args[0] = _units[_settings_game.locale.units].c_weight.ToDisplay(GetInt64(&argv, argve, &argt));
    00953         buff = FormatString(buff, GetStringPtr(_units[_settings_game.locale.units].s_weight), args, endof(args), modifier >> 24, last);
    00954         modifier = 0;
    00955         break;
    00956       }
    00957
    00958       case SCC_FORCE: { // {FORCE}
    00959         int64 args[1];
    00960         assert(_settings_game.locale.units < lengthof(_units));
    00961         args[0] = _units[_settings_game.locale.units].c_force.ToDisplay(GetInt64(&argv, argve, &argt));
    00962         buff = FormatString(buff, GetStringPtr(_units[_settings_game.locale.units].force), args, endof(args), modifier >> 24, last);
    00963         modifier = 0;
    00964         break;
    00965       }
    00966
    00967       /* This sets up the gender for the string.
    00968        * We just ignore this one. It's used in {G 0 Der Die Das} to determine the case. */
    00969       case SCC_GENDER_INDEX: // {GENDER 0}
    00970         if (_keep_gender_data) {
    00971           buff += Utf8Encode(buff, SCC_GENDER_INDEX);
    00972           *buff++ = *str++;
    00973         } else {
    00974           str++;
    00975         }
    00976         break;
    00977
    00978       case SCC_STRING: {// {STRING}
    00979         uint str = modifier + GetInt32(&argv, argve, &argt, SCC_STRING);
    00980         /* WARNING. It's prohibited for the included string to consume any arguments.
    00981          * For included strings that consume argument, you should use STRING1, STRING2 etc.
    00982          * To debug stuff you can set argv to NULL and it will tell you */
    00983         buff = GetStringWithArgs(buff, str, argv, argve, last);
    00984         modifier = 0;
    00985         break;
    00986       }
    00987
    00988       case SCC_COMMA: // {COMMA}
    00989         buff = FormatCommaNumber(buff, GetInt64(&argv, argve, &argt, SCC_COMMA), last);
    00990         break;
    00991
    00992       case SCC_ARG_INDEX: { // Move argument pointer
    00993         byte offset = (byte)*str++;
    00994         argv = argv_orig + offset;
    00995         if (argt_orig != NULL) argt = argt_orig + offset;
    00996         break;
    00997       }
    00998
    00999       case SCC_PLURAL_LIST: { // {P}
    01000         int plural_form = *str++;          // contains the plural form for this string
    01001         byte idx = *str++;
    01002         assert(argv_orig + idx < argve);
    01003         int64 v = argv_orig[idx]; // contains the number that determines plural
    01004         str = ParseStringChoice(str, DeterminePluralForm(v, plural_form), &buff, last);
    01005         break;
    01006       }
    01007
    01008       case SCC_NUM: // {NUM}
    01009         buff = FormatNoCommaNumber(buff, GetInt64(&argv, argve, &argt, SCC_NUM), last);
    01010         break;
    01011
    01012       case SCC_ZEROFILL_NUM: { // {ZEROFILL_NUM}
    01013         int64 num = GetInt64(&argv, argve, &argt);
    01014         buff = FormatZerofillNumber(buff, num, GetInt64(&argv, argve, &argt), last);
    01015         break;
    01016       }
    01017
    01018       case SCC_HEX: // {HEX}
    01019         buff = FormatHexNumber(buff, (uint64)GetInt64(&argv, argve, &argt, SCC_HEX), last);
    01020         break;
    01021
    01022       case SCC_BYTES: // {BYTES}
    01023         buff = FormatBytes(buff, GetInt64(&argv, argve, &argt), last);
    01024         break;
    01025
    01026       case SCC_CURRENCY: // {CURRENCY}
    01027         buff = FormatGenericCurrency(buff, _currency, GetInt64(&argv, argve, &argt, SCC_CURRENCY), false, last);
    01028         break;
    01029
    01030       case SCC_WAYPOINT_NAME: { // {WAYPOINT}
    01031         Waypoint *wp = Waypoint::Get(GetInt32(&argv, argve, &argt, SCC_WAYPOINT_NAME));
    01032
    01033         assert(wp != NULL);
    01034
    01035         if (wp->name != NULL) {
    01036           buff = strecpy(buff, wp->name, last);
    01037         } else {
    01038           int64 args[2];
    01039           args[0] = wp->town->index;
    01040           args[1] = wp->town_cn + 1;
    01041           StringID str = ((wp->string_id == STR_SV_STNAME_BUOY) ? STR_FORMAT_BUOY_NAME : STR_FORMAT_WAYPOINT_NAME);
    01042           if (wp->town_cn != 0) str++;
    01043           buff = GetStringWithArgs(buff, str, args, endof(args), last);
    01044         }
    01045         break;
    01046       }
    01047
    01048       case SCC_STATION_NAME: { // {STATION}
    01049         StationID sid = GetInt32(&argv, argve, &argt, SCC_STATION_NAME);
    01050         const Station *st = Station::GetIfValid(sid);
    01051
    01052         if (st == NULL) {
    01053           /* The station doesn't exist anymore. The only place where we might
    01054            * be "drawing" an invalid station is in the case of cargo that is
    01055            * in transit. */
    01056           buff = GetStringWithArgs(buff, STR_UNKNOWN_STATION, NULL, NULL, last);
    01057           break;
    01058         }
    01059
    01060         if (st->name != NULL) {
    01061           buff = strecpy(buff, st->name, last);
    01062         } else {
    01063           StringID str = st->string_id;
    01064           if (st->indtype != IT_INVALID) {
    01065             /* Special case where the industry provides the name for the station */
    01066             const IndustrySpec *indsp = GetIndustrySpec(st->indtype);
    01067
    01068             /* Industry GRFs can change which might remove the station name and
    01069              * thus cause very strange things. Here we check for that before we
    01070              * actually set the station name. */
    01071             if (indsp->station_name != STR_NULL && indsp->station_name != STR_UNDEFINED) {
    01072               str = indsp->station_name;
    01073             }
    01074           }
    01075
    01076           int64 args[3];
    01077           args[0] = STR_TOWN_NAME;
    01078           args[1] = st->town->index;
    01079           args[2] = st->index;
    01080           buff = GetStringWithArgs(buff, str, args, endof(args), last);
    01081         }
    01082         break;
    01083       }
    01084
    01085       case SCC_DEPOT_NAME: { // {DEPOT}
    01086         VehicleType vt = (VehicleType)GetInt32(&argv, argve, &argt, SCC_DEPOT_NAME);
    01087         if (vt == VEH_AIRCRAFT) {
    01088           int64 args[] = { GetInt32(&argv, argve, &argt) };
    01089           buff = GetStringWithArgs(buff, STR_FORMAT_DEPOT_NAME_AIRCRAFT, args, endof(args), last);
    01090           break;
    01091         }
    01092
    01093         const Depot *d = Depot::Get(GetInt32(&argv, argve, &argt));
    01094         if (d->name != NULL) {
    01095           buff = strecpy(buff, d->name, last);
    01096         } else {
    01097           int64 args[] = { d->town->index, d->town_cn + 1 };
    01098           buff = GetStringWithArgs(buff, STR_FORMAT_DEPOT_NAME_TRAIN + 2 * vt + (d->town_cn == 0 ? 0 : 1), args, endof(args), last);
    01099         }
    01100         break;
    01101       }
    01102
    01103       case SCC_TOWN_NAME: { // {TOWN}
    01104         const Town *t = Town::Get(GetInt32(&argv, argve, &argt, SCC_TOWN_NAME));
    01105
    01106         assert(t != NULL);
    01107
    01108         if (t->name != NULL) {
    01109           buff = strecpy(buff, t->name, last);
    01110         } else {
    01111           buff = GetTownName(buff, t, last);
    01112         }
    01113         break;
    01114       }
    01115
    01116       case SCC_GROUP_NAME: { // {GROUP}
    01117         const Group *g = Group::Get(GetInt32(&argv, argve, &argt));
    01118
    01119         assert(g != NULL);
    01120
    01121         if (g->name != NULL) {
    01122           buff = strecpy(buff, g->name, last);
    01123         } else {
    01124           int64 args[1];
    01125
    01126           args[0] = g->index;
    01127           buff = GetStringWithArgs(buff, STR_FORMAT_GROUP_NAME, args, endof(args), last);
    01128         }
    01129         break;
    01130       }
    01131
    01132       case SCC_ENGINE_NAME: { // {ENGINE}
    01133         EngineID engine = (EngineID)GetInt32(&argv, argve, &argt, SCC_ENGINE_NAME);
    01134         const Engine *e = Engine::Get(engine);
    01135
    01136         assert(e != NULL);
    01137
    01138         if (e->name != NULL && e->IsEnabled()) {
    01139           buff = strecpy(buff, e->name, last);
    01140         } else {
    01141           buff = GetStringWithArgs(buff, e->info.string_id, NULL, NULL, last);
    01142         }
    01143         break;
    01144       }
    01145
    01146       case SCC_VEHICLE_NAME: { // {VEHICLE}
    01147         const Vehicle *v = Vehicle::Get(GetInt32(&argv, argve, &argt, SCC_VEHICLE_NAME));
    01148
    01149         assert(v != NULL);
    01150
    01151         if (v->name != NULL) {
    01152           buff = strecpy(buff, v->name, last);
    01153         } else {
    01154           int64 args[1];
    01155           args[0] = v->unitnumber;
    01156
    01157           StringID str;
    01158           switch (v->type) {
    01159             default: NOT_REACHED();
    01160             case VEH_TRAIN:    str = STR_SV_TRAIN_NAME; break;
    01161             case VEH_ROAD:     str = STR_SV_ROAD_VEHICLE_NAME; break;
    01162             case VEH_SHIP:     str = STR_SV_SHIP_NAME; break;
    01163             case VEH_AIRCRAFT: str = STR_SV_AIRCRAFT_NAME; break;
    01164           }
    01165
    01166           buff = GetStringWithArgs(buff, str, args, endof(args), last);
    01167         }
    01168         break;
    01169       }
    01170
    01171       case SCC_SIGN_NAME: { // {SIGN}
    01172         const Sign *si = Sign::Get(GetInt32(&argv, argve, &argt));
    01173         if (si->name != NULL) {
    01174           buff = strecpy(buff, si->name, last);
    01175         } else {
    01176           buff = GetStringWithArgs(buff, STR_DEFAULT_SIGN_NAME, NULL, NULL, last);
    01177         }
    01178         break;
    01179       }
    01180
    01181       case SCC_COMPANY_NAME: { // {COMPANY}
    01182         const Company *c = Company::Get((CompanyID)GetInt32(&argv, argve, &argt));
    01183
    01184         if (c->name != NULL) {
    01185           buff = strecpy(buff, c->name, last);
    01186         } else {
    01187           int64 args[1];
    01188           args[0] = c->name_2;
    01189           buff = GetStringWithArgs(buff, c->name_1, args, endof(args), last);
    01190         }
    01191         break;
    01192       }
    01193
    01194       case SCC_COMPANY_NUM: { // {COMPANYNUM}
    01195         CompanyID company = (CompanyID)GetInt32(&argv, argve, &argt);
    01196
    01197         /* Nothing is added for AI or inactive companies */
    01198         if (Company::IsValidHumanID(company)) {
    01199           int64 args[1];
    01200           args[0] = company + 1;
    01201           buff = GetStringWithArgs(buff, STR_FORMAT_COMPANY_NUM, args, endof(args), last);
    01202         }
    01203         break;
    01204       }
    01205
    01206       case SCC_PRESIDENT_NAME: { // {PRESIDENTNAME}
    01207         const Company *c = Company::Get((CompanyID)GetInt32(&argv, argve, &argt, SCC_PRESIDENT_NAME));
    01208
    01209         if (c->president_name != NULL) {
    01210           buff = strecpy(buff, c->president_name, last);
    01211         } else {
    01212           int64 args[1];
    01213           args[0] = c->president_name_2;
    01214           buff = GetStringWithArgs(buff, c->president_name_1, args, endof(args), last);
    01215         }
    01216         break;
    01217       }
    01218
    01219       case SCC_SETCASE: { // {SETCASE}
    01220         /* This is a pseudo command, it's outputted when someone does {STRING.ack}
    01221          * The modifier is added to all subsequent GetStringWithArgs that accept the modifier. */
    01222         modifier = (byte)*str++ << 24;
    01223         break;
    01224       }
    01225
    01226       case SCC_SWITCH_CASE: { // {Used to implement case switching}
    01227         /* <0x9E> <NUM CASES> <CASE1> <LEN1> <STRING1> <CASE2> <LEN2> <STRING2> <CASE3> <LEN3> <STRING3> <STRINGDEFAULT>
    01228          * Each LEN is printed using 2 bytes in big endian order. */
    01229         uint num = (byte)*str++;
    01230         while (num) {
    01231           if ((byte)str[0] == casei) {
    01232             /* Found the case, adjust str pointer and continue */
    01233             str += 3;
    01234             break;
    01235           }
    01236           /* Otherwise skip to the next case */
    01237           str += 3 + (str[1] << 8) + str[2];
    01238           num--;
    01239         }
    01240         break;
    01241       }
    01242
    01243       default:
    01244         if (buff + Utf8CharLen(b) < last) buff += Utf8Encode(buff, b);
    01245         break;
    01246     }
    01247   }
    01248   *buff = '\0';
    01249   return buff;
    01250 }
    01251
    01252
    01253 static char *StationGetSpecialString(char *buff, int x, const char *last)
    01254 {
    01255   if ((x & FACIL_TRAIN)      && (buff + Utf8CharLen(SCC_TRAIN) < last)) buff += Utf8Encode(buff, SCC_TRAIN);
    01256   if ((x & FACIL_TRUCK_STOP) && (buff + Utf8CharLen(SCC_LORRY) < last)) buff += Utf8Encode(buff, SCC_LORRY);
    01257   if ((x & FACIL_BUS_STOP)   && (buff + Utf8CharLen(SCC_BUS)   < last)) buff += Utf8Encode(buff, SCC_BUS);
    01258   if ((x & FACIL_DOCK)       && (buff + Utf8CharLen(SCC_SHIP)  < last)) buff += Utf8Encode(buff, SCC_SHIP);
    01259   if ((x & FACIL_AIRPORT)    && (buff + Utf8CharLen(SCC_PLANE) < last)) buff += Utf8Encode(buff, SCC_PLANE);
    01260   *buff = '\0';
    01261   return buff;
    01262 }
    01263
    01264 static char *GetSpecialTownNameString(char *buff, int ind, uint32 seed, const char *last)
    01265 {
    01266   return GenerateTownNameString(buff, last, ind, seed);
    01267 }
    01268
    01269 static const char * const _silly_company_names[] = {
    01270   "Bloggs Brothers",
    01271   "Tiny Transport Ltd.",
    01272   "Express Travel",
    01273   "Comfy-Coach & Co.",
    01274   "Crush & Bump Ltd.",
    01275   "Broken & Late Ltd.",
    01276   "Sam Speedy & Son",
    01277   "Supersonic Travel",
    01278   "Mike's Motors",
    01279   "Lightning International",
    01280   "Pannik & Loozit Ltd.",
    01281   "Inter-City Transport",
    01282   "Getout & Pushit Ltd."
    01283 };
    01284
    01285 static const char * const _surname_list[] = {
    01286   "Adams",
    01287   "Allan",
    01288   "Baker",
    01289   "Bigwig",
    01290   "Black",
    01291   "Bloggs",
    01292   "Brown",
    01293   "Campbell",
    01294   "Gordon",
    01295   "Hamilton",
    01296   "Hawthorn",
    01297   "Higgins",
    01298   "Green",
    01299   "Gribble",
    01300   "Jones",
    01301   "McAlpine",
    01302   "MacDonald",
    01303   "McIntosh",
    01304   "Muir",
    01305   "Murphy",
    01306   "Nelson",
    01307   "O'Donnell",
    01308   "Parker",
    01309   "Phillips",
    01310   "Pilkington",
    01311   "Quigley",
    01312   "Sharkey",
    01313   "Thomson",
    01314   "Watkins"
    01315 };
    01316
    01317 static const char * const _silly_surname_list[] = {
    01318   "Grumpy",
    01319   "Dozy",
    01320   "Speedy",
    01321   "Nosey",
    01322   "Dribble",
    01323   "Mushroom",
    01324   "Cabbage",
    01325   "Sniffle",
    01326   "Fishy",
    01327   "Swindle",
    01328   "Sneaky",
    01329   "Nutkins"
    01330 };
    01331
    01332 static const char _initial_name_letters[] = {
    01333   'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
    01334   'K', 'L', 'M', 'N', 'P', 'R', 'S', 'T', 'W',
    01335 };
    01336
    01337 static char *GenAndCoName(char *buff, uint32 arg, const char *last)
    01338 {
    01339   const char * const *base;
    01340   uint num;
    01341
    01342   if (_settings_game.game_creation.landscape == LT_TOYLAND) {
    01343     base = _silly_surname_list;
    01344     num  = lengthof(_silly_surname_list);
    01345   } else {
    01346     base = _surname_list;
    01347     num  = lengthof(_surname_list);
    01348   }
    01349
    01350   buff = strecpy(buff, base[num * GB(arg, 16, 8) >> 8], last);
    01351   buff = strecpy(buff, " & Co.", last);
    01352
    01353   return buff;
    01354 }
    01355
    01356 static char *GenPresidentName(char *buff, uint32 x, const char *last)
    01357 {
    01358   char initial[] = "?. ";
    01359   const char * const *base;
    01360   uint num;
    01361   uint i;
    01362
    01363   initial[0] = _initial_name_letters[sizeof(_initial_name_letters) * GB(x, 0, 8) >> 8];
    01364   buff = strecpy(buff, initial, last);
    01365
    01366   i = (sizeof(_initial_name_letters) + 35) * GB(x, 8, 8) >> 8;
    01367   if (i < sizeof(_initial_name_letters)) {
    01368     initial[0] = _initial_name_letters[i];
    01369     buff = strecpy(buff, initial, last);
    01370   }
    01371
    01372   if (_settings_game.game_creation.landscape == LT_TOYLAND) {
    01373     base = _silly_surname_list;
    01374     num  = lengthof(_silly_surname_list);
    01375   } else {
    01376     base = _surname_list;
    01377     num  = lengthof(_surname_list);
    01378   }
    01379
    01380   buff = strecpy(buff, base[num * GB(x, 16, 8) >> 8], last);
    01381
    01382   return buff;
    01383 }
    01384
    01385 static char *GetSpecialNameString(char *buff, int ind, int64 *argv, const int64 *argve, const char *last, WChar *argt)
    01386 {
    01387   switch (ind) {
    01388     case 1: // not used
    01389       return strecpy(buff, _silly_company_names[GetInt32(&argv, argve, &argt) & 0xFFFF], last);
    01390
    01391     case 2: // used for Foobar & Co company names
    01392       return GenAndCoName(buff, GetInt32(&argv, argve, &argt), last);
    01393
    01394     case 3: // President name
    01395       return GenPresidentName(buff, GetInt32(&argv, argve, &argt), last);
    01396   }
    01397
    01398   /* town name? */
    01399   if (IsInsideMM(ind - 6, 0, SPECSTR_TOWNNAME_LAST - SPECSTR_TOWNNAME_START + 1)) {
    01400     buff = GetSpecialTownNameString(buff, ind - 6, GetInt32(&argv, argve, &argt), last);
    01401     return strecpy(buff, " Transport", last);
    01402   }
    01403
    01404   /* language name? */
    01405   if (IsInsideMM(ind, (SPECSTR_LANGUAGE_START - 0x70E4), (SPECSTR_LANGUAGE_END - 0x70E4) + 1)) {
    01406     int i = ind - (SPECSTR_LANGUAGE_START - 0x70E4);
    01407     return strecpy(buff,
    01408       &_languages[i] == _current_language ? _current_language->own_name : _languages[i].name, last);
    01409   }
    01410
    01411   /* resolution size? */
    01412   if (IsInsideMM(ind, (SPECSTR_RESOLUTION_START - 0x70E4), (SPECSTR_RESOLUTION_END - 0x70E4) + 1)) {
    01413     int i = ind - (SPECSTR_RESOLUTION_START - 0x70E4);
    01414     buff += seprintf(
    01415       buff, last, "%ux%u", _resolutions[i].width, _resolutions[i].height
    01416     );
    01417     return buff;
    01418   }
    01419
    01420   /* screenshot format name? */
    01421   if (IsInsideMM(ind, (SPECSTR_SCREENSHOT_START - 0x70E4), (SPECSTR_SCREENSHOT_END - 0x70E4) + 1)) {
    01422     int i = ind - (SPECSTR_SCREENSHOT_START - 0x70E4);
    01423     return strecpy(buff, GetScreenshotFormatDesc(i), last);
    01424   }
    01425
    01426   NOT_REACHED();
    01427 }
    01428
    01429 #ifdef ENABLE_NETWORK
    01430 extern void SortNetworkLanguages();
    01431 #else /* ENABLE_NETWORK */
    01432 static inline void SortNetworkLanguages() {}
    01433 #endif /* ENABLE_NETWORK */
    01434
    01439 bool LanguagePackHeader::IsValid() const
    01440 {
    01441   return this->ident        == TO_LE32(LanguagePackHeader::IDENT) &&
    01442          this->version      == TO_LE32(LANGUAGE_PACK_VERSION) &&
    01443          this->plural_form  <  LANGUAGE_MAX_PLURAL &&
    01444          this->text_dir     <= 1 &&
    01445          this->newgrflangid < MAX_LANG &&
    01446          this->num_genders  < MAX_NUM_GENDERS &&
    01447          this->num_cases    < MAX_NUM_CASES &&
    01448          StrValid(this->name,                           lastof(this->name)) &&
    01449          StrValid(this->own_name,                       lastof(this->own_name)) &&
    01450          StrValid(this->isocode,                        lastof(this->isocode)) &&
    01451          StrValid(this->digit_group_separator,          lastof(this->digit_group_separator)) &&
    01452          StrValid(this->digit_group_separator_currency, lastof(this->digit_group_separator_currency)) &&
    01453          StrValid(this->digit_decimal_separator,        lastof(this->digit_decimal_separator));
    01454 }
    01455
    01456 bool ReadLanguagePack(const LanguageMetadata *lang)
    01457 {
    01458   /* Current language pack */
    01459   size_t len;
    01460   LanguagePack *lang_pack = (LanguagePack *)ReadFileToMem(lang->file, &len, 1U << 20);
    01461   if (lang_pack == NULL) return false;
    01462
    01463   /* End of read data (+ terminating zero added in ReadFileToMem()) */
    01464   const char *end = (char *)lang_pack + len + 1;
    01465
    01466   /* We need at least one byte of lang_pack->data */
    01467   if (end <= lang_pack->data || !lang_pack->IsValid()) {
    01468     free(lang_pack);
    01469     return false;
    01470   }
    01471
    01472 #if TTD_ENDIAN == TTD_BIG_ENDIAN
    01473   for (uint i = 0; i < 32; i++) {
    01474     lang_pack->offsets[i] = ReadLE16Aligned(&lang_pack->offsets[i]);
    01475   }
    01476 #endif /* TTD_ENDIAN == TTD_BIG_ENDIAN */
    01477
    01478   uint count = 0;
    01479   for (uint i = 0; i < 32; i++) {
    01480     uint num = lang_pack->offsets[i];
    01481     _langtab_start[i] = count;
    01482     _langtab_num[i] = num;
    01483     count += num;
    01484   }
    01485
    01486   /* Allocate offsets */
    01487   char **langpack_offs = MallocT<char *>(count);
    01488
    01489   /* Fill offsets */
    01490   char *s = lang_pack->data;
    01491   len = (byte)*s++;
    01492   for (uint i = 0; i < count; i++) {
    01493     if (s + len >= end) {
    01494       free(lang_pack);
    01495       free(langpack_offs);
    01496       return false;
    01497     }
    01498     if (len >= 0xC0) {
    01499       len = ((len & 0x3F) << 8) + (byte)*s++;
    01500       if (s + len >= end) {
    01501         free(lang_pack);
    01502         free(langpack_offs);
    01503         return false;
    01504       }
    01505     }
    01506     langpack_offs[i] = s;
    01507     s += len;
    01508     len = (byte)*s;
    01509     *s++ = '\0'; // zero terminate the string
    01510   }
    01511
    01512   free(_langpack);
    01513   _langpack = lang_pack;
    01514
    01515   free(_langpack_offs);
    01516   _langpack_offs = langpack_offs;
    01517
    01518   _current_language = lang;
    01519   _current_text_dir = (TextDirection)_current_language->text_dir;
    01520   const char *c_file = strrchr(_current_language->file, PATHSEPCHAR) + 1;
    01521   strecpy(_config_language_file, c_file, lastof(_config_language_file));
    01522   SetCurrentGrfLangID(_current_language->newgrflangid);
    01523
    01524 #ifdef WITH_ICU
    01525   /* Delete previous collator. */
    01526   if (_current_collator != NULL) {
    01527     delete _current_collator;
    01528     _current_collator = NULL;
    01529   }
    01530
    01531   /* Create a collator instance for our current locale. */
    01532   UErrorCode status = U_ZERO_ERROR;
    01533   _current_collator = Collator::createInstance(Locale(_current_language->isocode), status);
    01534   /* Sort number substrings by their numerical value. */
    01535   if (_current_collator != NULL) _current_collator->setAttribute(UCOL_NUMERIC_COLLATION, UCOL_ON, status);
    01536   /* Avoid using the collator if it is not correctly set. */
    01537   if (U_FAILURE(status)) {
    01538     delete _current_collator;
    01539     _current_collator = NULL;
    01540   }
    01541 #endif /* WITH_ICU */
    01542
    01543   /* Some lists need to be sorted again after a language change. */
    01544   InitializeSortedCargoSpecs();
    01545   SortIndustryTypes();
    01546   BuildIndustriesLegend();
    01547   SortNetworkLanguages();
    01548   InvalidateWindowClassesData(WC_BUILD_VEHICLE);      // Build vehicle window.
    01549   InvalidateWindowClassesData(WC_TRAINS_LIST);        // Train group window.
    01550   InvalidateWindowClassesData(WC_ROADVEH_LIST);       // Road vehicle group window.
    01551   InvalidateWindowClassesData(WC_SHIPS_LIST);         // Ship group window.
    01552   InvalidateWindowClassesData(WC_AIRCRAFT_LIST);      // Aircraft group window.
    01553   InvalidateWindowClassesData(WC_INDUSTRY_DIRECTORY); // Industry directory window.
    01554   InvalidateWindowClassesData(WC_STATION_LIST);       // Station list window.
    01555
    01556   return true;
    01557 }
    01558
    01559 /* Win32 implementation in win32.cpp.
    01560  * OS X implementation in os/macosx/macos.mm. */
    01561 #if !(defined(WIN32) || defined(__APPLE__))
    01562
    01570 const char *GetCurrentLocale(const char *param)
    01571 {
    01572   const char *env;
    01573
    01574   env = getenv("LANGUAGE");
    01575   if (env != NULL) return env;
    01576
    01577   env = getenv("LC_ALL");
    01578   if (env != NULL) return env;
    01579
    01580   if (param != NULL) {
    01581     env = getenv(param);
    01582     if (env != NULL) return env;
    01583   }
    01584
    01585   return getenv("LANG");
    01586 }
    01587 #else
    01588 const char *GetCurrentLocale(const char *param);
    01589 #endif /* !(defined(WIN32) || defined(__APPLE__)) */
    01590
    01591 int CDECL StringIDSorter(const StringID *a, const StringID *b)
    01592 {
    01593   char stra[512];
    01594   char strb[512];
    01595   GetString(stra, *a, lastof(stra));
    01596   GetString(strb, *b, lastof(strb));
    01597
    01598   return strcmp(stra, strb);
    01599 }
    01600
    01606 const LanguageMetadata *GetLanguage(byte newgrflangid)
    01607 {
    01608   for (const LanguageMetadata *lang = _languages.Begin(); lang != _languages.End(); lang++) {
    01609     if (newgrflangid == lang->newgrflangid) return lang;
    01610   }
    01611
    01612   return NULL;
    01613 }
    01614
    01621 static bool GetLanguageFileHeader(const char *file, LanguagePackHeader *hdr)
    01622 {
    01623   FILE *f = fopen(file, "rb");
    01624   if (f == NULL) return false;
    01625
    01626   size_t read = fread(hdr, sizeof(*hdr), 1, f);
    01627   fclose(f);
    01628
    01629   bool ret = read == 1 && hdr->IsValid();
    01630
    01631   /* Convert endianness for the windows language ID */
    01632   if (ret) hdr->winlangid = FROM_LE16(hdr->winlangid);
    01633   return ret;
    01634 }
    01635
    01640 static void GetLanguageList(const char *path)
    01641 {
    01642   DIR *dir = ttd_opendir(path);
    01643   if (dir != NULL) {
    01644     struct dirent *dirent;
    01645     while ((dirent = readdir(dir)) != NULL) {
    01646       const char *d_name    = FS2OTTD(dirent->d_name);
    01647       const char *extension = strrchr(d_name, '.');
    01648
    01649       /* Not a language file */
    01650       if (extension == NULL || strcmp(extension, ".lng") != 0) continue;
    01651
    01652       LanguageMetadata lmd;
    01653       seprintf(lmd.file, lastof(lmd.file), "%s%s", path, d_name);
    01654
    01655       /* Check whether the file is of the correct version */
    01656       if (!GetLanguageFileHeader(lmd.file, &lmd)) {
    01657         DEBUG(misc, 3, "%s is not a valid language file", lmd.file);
    01658       } else if (GetLanguage(lmd.newgrflangid) != NULL) {
    01659         DEBUG(misc, 3, "%s's language ID is already known", lmd.file);
    01660       } else {
    01661         *_languages.Append() = lmd;
    01662       }
    01663     }
    01664     closedir(dir);
    01665   }
    01666 }
    01667
    01672 void InitializeLanguagePacks()
    01673 {
    01674   Searchpath sp;
    01675
    01676   FOR_ALL_SEARCHPATHS(sp) {
    01677     char path[MAX_PATH];
    01678     FioAppendDirectory(path, lengthof(path), sp, LANG_DIR);
    01679     GetLanguageList(path);
    01680   }
    01681   if (_languages.Length() == 0) usererror("No available language packs (invalid versions?)");
    01682
    01683   /* Acquire the locale of the current system */
    01684   const char *lang = GetCurrentLocale("LC_MESSAGES");
    01685   if (lang == NULL) lang = "en_GB";
    01686
    01687   const LanguageMetadata *chosen_language   = NULL;
    01688   const LanguageMetadata *language_fallback = NULL;
    01689   const LanguageMetadata *en_GB_fallback    = _languages.Begin();
    01690
    01691   /* Find a proper language. */
    01692   for (const LanguageMetadata *lng = _languages.Begin(); lng != _languages.End(); lng++) {
    01693     /* We are trying to find a default language. The priority is by
    01694      * configuration file, local environment and last, if nothing found,
    01695      * english. */
    01696     const char *lang_file = strrchr(lng->file, PATHSEPCHAR) + 1;
    01697     if (strcmp(lang_file, _config_language_file) == 0) {
    01698       chosen_language = lng;
    01699       break;
    01700     }
    01701
    01702     if (strcmp (lng->isocode, "en_GB") == 0) en_GB_fallback    = lng;
    01703     if (strncmp(lng->isocode, lang, 5) == 0) chosen_language   = lng;
    01704     if (strncmp(lng->isocode, lang, 2) == 0) language_fallback = lng;
    01705   }
    01706
    01707   /* We haven't found the language in the config nor the one in the locale.
    01708    * Now we set it to one of the fallback languages */
    01709   if (chosen_language == NULL) {
    01710     chosen_language = (language_fallback != NULL) ? language_fallback : en_GB_fallback;
    01711   }
    01712
    01713   if (!ReadLanguagePack(chosen_language)) usererror("Can't read language pack '%s'", chosen_language->file);
    01714 }
    01715
    01720 const char *GetCurrentLanguageIsoCode()
    01721 {
    01722   return _langpack->isocode;
    01723 }
    01724
    01731 static bool FindMissingGlyphs(const char **str)
    01732 {
    01733 #ifdef WITH_FREETYPE
    01734   UninitFreeType();
    01735   InitFreeType();
    01736 #endif
    01737   const Sprite *question_mark[FS_END];
    01738   FontSize size;
    01739
    01740   for (size = FS_BEGIN; size < FS_END; size++) {
    01741     question_mark[size] = GetGlyph(size, '?');
    01742   }
    01743
    01744   for (uint i = 0; i != 32; i++) {
    01745     for (uint j = 0; j < _langtab_num[i]; j++) {
    01746       size = FS_NORMAL;
    01747       const char *text = _langpack_offs[_langtab_start[i] + j];
    01748       if (str != NULL) *str = text;
    01749       for (WChar c = Utf8Consume(&text); c != '\0'; c = Utf8Consume(&text)) {
    01750         if (c == SCC_SETX) {
    01751           /* SetX is, together with SetXY as special character that
    01752            * uses the next (two) characters as data points. We have
    01753            * to skip those, otherwise the UTF8 reading will go haywire. */
    01754           text++;
    01755         } else if (c == SCC_SETXY) {
    01756           text += 2;
    01757         } else if (c == SCC_TINYFONT) {
    01758           size = FS_SMALL;
    01759         } else if (c == SCC_BIGFONT) {
    01760           size = FS_LARGE;
    01761         } else if (IsPrintable(c) && !IsTextDirectionChar(c) && c != '?' && GetGlyph(size, c) == question_mark[size]) {
    01762           /* The character is printable, but not in the normal font. This is the case we were testing for. */
    01763           return true;
    01764         }
    01765       }
    01766     }
    01767   }
    01768   return false;
    01769 }
    01770
    01781 void CheckForMissingGlyphsInLoadedLanguagePack()
    01782 {
    01783   bool bad_font = FindMissingGlyphs(NULL);
    01784 #ifdef WITH_FREETYPE
    01785   if (bad_font) {
    01786     /* We found an unprintable character... lets try whether we can find
    01787      * a fallback font that can print the characters in the current language. */
    01788     FreeTypeSettings backup;
    01789     memcpy(&backup, &_freetype, sizeof(backup));
    01790
    01791     bad_font = !SetFallbackFont(&_freetype, _langpack->isocode, _langpack->winlangid, &FindMissingGlyphs);
    01792
    01793     memcpy(&_freetype, &backup, sizeof(backup));
    01794
    01795     if (bad_font) {
    01796       /* Our fallback font does miss characters too, so keep the
    01797        * user chosen font as that is more likely to be any good than
    01798        * the wild guess we made */
    01799       UninitFreeType();
    01800       InitFreeType();
    01801     }
    01802   }
    01803 #endif
    01804
    01805   if (bad_font) {
    01806     /* All attempts have failed. Display an error. As we do not want the string to be translated by
    01807      * the translators, we 'force' it into the binary and 'load' it via a BindCString. To do this
    01808      * properly we have to set the colour of the string, otherwise we end up with a lot of artefacts.
    01809      * The colour 'character' might change in the future, so for safety we just Utf8 Encode it into
    01810      * the string, which takes exactly three characters, so it replaces the "XXX" with the colour marker. */
    01811     static char *err_str = strdup("XXXThe current font is missing some of the characters used in the texts for this language. Read the readme to see how to solve this.");
    01812     Utf8Encode(err_str, SCC_YELLOW);
    01813     SetDParamStr(0, err_str);
    01814     ShowErrorMessage(STR_JUST_RAW_STRING, INVALID_STRING_ID, WL_WARNING);
    01815
    01816     /* Reset the font width */
    01817     LoadStringWidthTable();
    01818     return;
    01819   }
    01820
    01821   /* Update the font with cache */
    01822   LoadStringWidthTable();
    01823
    01824 #if !defined(WITH_ICU)
    01825   /*
    01826    * For right-to-left languages we need the ICU library. If
    01827    * we do not have support for that library we warn the user
    01828    * about it with a message. As we do not want the string to
    01829    * be translated by the translators, we 'force' it into the
    01830    * binary and 'load' it via a BindCString. To do this
    01831    * properly we have to set the colour of the string,
    01832    * otherwise we end up with a lot of artefacts. The colour
    01833    * 'character' might change in the future, so for safety
    01834    * we just Utf8 Encode it into the string, which takes
    01835    * exactly three characters, so it replaces the "XXX" with
    01836    * the colour marker.
    01837    */
    01838   if (_current_text_dir != TD_LTR) {
    01839     static char *err_str = strdup("XXXThis version of OpenTTD does not support right-to-left languages. Recompile with icu enabled.");
    01840     Utf8Encode(err_str, SCC_YELLOW);
    01841     SetDParamStr(0, err_str);
    01842     ShowErrorMessage(STR_JUST_RAW_STRING, INVALID_STRING_ID, WL_ERROR);
    01843   }
    01844 #endif
    01845 }