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