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