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