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 }