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