# strings.cpp

Go to the documentation of this file.

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