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