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 
00612   int64 FromDisplay(int64 input, bool round = true, int64 divider = 1) const
00613   {
00614     return ((input << this->shift) + (round ? (this->multiplier * divider) - 1 : 0)) / (this->multiplier * divider);
00615   }
00616 };
00617 
00618 struct Units {
00619   UnitConversion c_velocity; 
00620   StringID velocity;         
00621   UnitConversion c_power;    
00622   StringID power;            
00623   UnitConversion c_weight;   
00624   StringID s_weight;         
00625   StringID l_weight;         
00626   UnitConversion c_volume;   
00627   StringID s_volume;         
00628   StringID l_volume;         
00629   UnitConversion c_force;    
00630   StringID force;            
00631   UnitConversion c_height;   
00632   StringID height;           
00633 };
00634 
00635 /* Unit conversions */
00636 static const Units _units[] = {
00637   { // Imperial (Original, mph, hp, metric ton, litre, kN, ft)
00638     {   1,  0}, STR_UNITS_VELOCITY_IMPERIAL,
00639     {   1,  0}, STR_UNITS_POWER_IMPERIAL,
00640     {   1,  0}, STR_UNITS_WEIGHT_SHORT_METRIC, STR_UNITS_WEIGHT_LONG_METRIC,
00641     {1000,  0}, STR_UNITS_VOLUME_SHORT_METRIC, STR_UNITS_VOLUME_LONG_METRIC,
00642     {   1,  0}, STR_UNITS_FORCE_SI,
00643     {   3,  0}, STR_UNITS_HEIGHT_IMPERIAL, // "Wrong" conversion factor for more nicer GUI values
00644   },
00645   { // Metric (km/h, hp, metric ton, litre, kN, metre)
00646     { 103,  6}, STR_UNITS_VELOCITY_METRIC,
00647     {4153, 12}, STR_UNITS_POWER_METRIC,
00648     {   1,  0}, STR_UNITS_WEIGHT_SHORT_METRIC, STR_UNITS_WEIGHT_LONG_METRIC,
00649     {1000,  0}, STR_UNITS_VOLUME_SHORT_METRIC, STR_UNITS_VOLUME_LONG_METRIC,
00650     {   1,  0}, STR_UNITS_FORCE_SI,
00651     {   1,  0}, STR_UNITS_HEIGHT_SI,
00652   },
00653   { // SI (m/s, kilowatt, kilogram, cubic metre, kilonewton, metre)
00654     {1831, 12}, STR_UNITS_VELOCITY_SI,
00655     {6109, 13}, STR_UNITS_POWER_SI,
00656     {1000,  0}, STR_UNITS_WEIGHT_SHORT_SI, STR_UNITS_WEIGHT_LONG_SI,
00657     {   1,  0}, STR_UNITS_VOLUME_SHORT_SI, STR_UNITS_VOLUME_LONG_SI,
00658     {   1,  0}, STR_UNITS_FORCE_SI,
00659     {   1,  0}, STR_UNITS_HEIGHT_SI,
00660   },
00661 };
00662 
00668 uint ConvertSpeedToDisplaySpeed(uint speed)
00669 {
00670   /* For historical reasons we don't want to mess with the
00671    * conversion for speed. So, don't round it and keep the
00672    * original conversion factors instead of the real ones. */
00673   return _units[_settings_game.locale.units].c_velocity.ToDisplay(speed, false);
00674 }
00675 
00681 uint ConvertDisplaySpeedToSpeed(uint speed)
00682 {
00683   return _units[_settings_game.locale.units].c_velocity.FromDisplay(speed);
00684 }
00685 
00691 uint ConvertKmhishSpeedToDisplaySpeed(uint speed)
00692 {
00693   return _units[_settings_game.locale.units].c_velocity.ToDisplay(speed * 10, false) / 16;
00694 }
00695 
00701 uint ConvertDisplaySpeedToKmhishSpeed(uint speed)
00702 {
00703   return _units[_settings_game.locale.units].c_velocity.FromDisplay(speed * 16, true, 10);
00704 }
00714 static char *FormatString(char *buff, const char *str_arg, StringParameters *args, const char *last, uint case_index, bool game_script, bool dry_run)
00715 {
00716   uint orig_offset = args->offset;
00717 
00718   /* When there is no array with types there is no need to do a dry run. */
00719   if (args->HasTypeInformation() && !dry_run) {
00720     if (UsingNewGRFTextStack()) {
00721       /* Values from the NewGRF text stack are only copied to the normal
00722        * argv array at the time they are encountered. That means that if
00723        * another string command references a value later in the string it
00724        * would fail. We solve that by running FormatString twice. The first
00725        * pass makes sure the argv array is correctly filled and the second
00726        * pass can reference later values without problems. */
00727       struct TextRefStack *backup = CreateTextRefStackBackup();
00728       FormatString(buff, str_arg, args, last, case_index, game_script, true);
00729       RestoreTextRefStackBackup(backup);
00730     } else {
00731       FormatString(buff, str_arg, args, last, case_index, game_script, true);
00732     }
00733     /* We have to restore the original offset here to to read the correct values. */
00734     args->offset = orig_offset;
00735   }
00736   WChar b;
00737   uint next_substr_case_index = 0;
00738   char *buf_start = buff;
00739   std::stack<const char *> str_stack;
00740   str_stack.push(str_arg);
00741 
00742   for (;;) {
00743     while (!str_stack.empty() && (b = Utf8Consume(&str_stack.top())) == '\0') {
00744       str_stack.pop();
00745     }
00746     if (str_stack.empty()) break;
00747     const char *&str = str_stack.top();
00748 
00749     if (SCC_NEWGRF_FIRST <= b && b <= SCC_NEWGRF_LAST) {
00750       /* We need to pass some stuff as it might be modified; oh boy. */
00751       //todo: should argve be passed here too?
00752       b = RemapNewGRFStringControlCode(b, buf_start, &buff, &str, (int64 *)args->GetDataPointer(), dry_run);
00753       if (b == 0) continue;
00754     }
00755 
00756     switch (b) {
00757       case SCC_ENCODED: {
00758         uint64 sub_args_data[20];
00759         WChar sub_args_type[20];
00760         bool sub_args_need_free[20];
00761         StringParameters sub_args(sub_args_data, 20, sub_args_type);
00762 
00763         sub_args.ClearTypeInformation();
00764         memset(sub_args_need_free, 0, sizeof(sub_args_need_free));
00765 
00766         uint16 stringid;
00767         const char *s = str;
00768         char *p;
00769         stringid = strtol(str, &p, 16);
00770         if (*p != ':' && *p != '\0') {
00771           while (*p != '\0') p++;
00772           str = p;
00773           buff = strecat(buff, "(invalid SCC_ENCODED)", last);
00774           break;
00775         }
00776         if (stringid >= TAB_SIZE) {
00777           while (*p != '\0') p++;
00778           str = p;
00779           buff = strecat(buff, "(invalid StringID)", last);
00780           break;
00781         }
00782 
00783         int i = 0;
00784         while (*p != '\0') {
00785           uint64 param;
00786           s = ++p;
00787 
00788           /* Find the next value */
00789           bool instring = false;
00790           bool escape = false;
00791           for (;; p++) {
00792             if (*p == '\\') {
00793               escape = true;
00794               continue;
00795             }
00796             if (*p == '"' && escape) {
00797               escape = false;
00798               continue;
00799             }
00800             escape = false;
00801 
00802             if (*p == '"') {
00803               instring = !instring;
00804               continue;
00805             }
00806             if (instring) {
00807               continue;
00808             }
00809 
00810             if (*p == ':') break;
00811             if (*p == '\0') break;
00812           }
00813 
00814           if (*s != '"') {
00815             /* Check if we want to look up another string */
00816             WChar l;
00817             size_t len = Utf8Decode(&l, s);
00818             bool lookup = (l == SCC_ENCODED);
00819             if (lookup) s += len;
00820 
00821             param = strtol(s, &p, 16);
00822 
00823             if (lookup) {
00824               if (param >= TAB_SIZE) {
00825                 while (*p != '\0') p++;
00826                 str = p;
00827                 buff = strecat(buff, "(invalid sub-StringID)", last);
00828                 break;
00829               }
00830               param = (GAME_TEXT_TAB << TAB_COUNT_OFFSET) + param;
00831             }
00832 
00833             sub_args.SetParam(i++, param);
00834           } else {
00835             char *g = strdup(s);
00836             g[p - s] = '\0';
00837 
00838             sub_args_need_free[i] = true;
00839             sub_args.SetParam(i++, (uint64)(size_t)g);
00840           }
00841         }
00842         /* We error'd out in the while, to error out in themain too */
00843         if (*str == '\0') break;
00844 
00845         str = p;
00846         buff = GetStringWithArgs(buff, (GAME_TEXT_TAB << TAB_COUNT_OFFSET) + stringid, &sub_args, last, true);
00847 
00848         for (int i = 0; i < 20; i++) {
00849           if (sub_args_need_free[i]) free((void *)sub_args.GetParam(i));
00850         }
00851         break;
00852       }
00853 
00854       case SCC_NEWGRF_STRINL: {
00855         StringID substr = Utf8Consume(&str);
00856         str_stack.push(GetStringPtr(substr));
00857         break;
00858       }
00859 
00860       case SCC_NEWGRF_PRINT_WORD_STRING_ID: {
00861         StringID substr = args->GetInt32(SCC_NEWGRF_PRINT_WORD_STRING_ID);
00862         str_stack.push(GetStringPtr(substr));
00863         case_index = next_substr_case_index;
00864         next_substr_case_index = 0;
00865         break;
00866       }
00867 
00868 
00869       case SCC_GENDER_LIST: { // {G 0 Der Die Das}
00870         /* First read the meta data from the language file. */
00871         uint offset = orig_offset + (byte)*str++;
00872         int gender = 0;
00873         if (!dry_run && args->GetTypeAtOffset(offset) != 0) {
00874           /* Now we need to figure out what text to resolve, i.e.
00875            * what do we need to draw? So get the actual raw string
00876            * first using the control code to get said string. */
00877           char input[4 + 1];
00878           char *p = input + Utf8Encode(input, args->GetTypeAtOffset(offset));
00879           *p = '\0';
00880 
00881           /* Now do the string formatting. */
00882           char buf[256];
00883           bool old_kgd = _keep_gender_data;
00884           _keep_gender_data = true;
00885           StringParameters tmp_params(args->GetPointerToOffset(offset), args->num_param - offset, NULL);
00886           p = FormatString(buf, input, &tmp_params, lastof(buf));
00887           _keep_gender_data = old_kgd;
00888           *p = '\0';
00889 
00890           /* And determine the string. */
00891           const char *s = buf;
00892           WChar c = Utf8Consume(&s);
00893           /* Does this string have a gender, if so, set it */
00894           if (c == SCC_GENDER_INDEX) gender = (byte)s[0];
00895         }
00896         str = ParseStringChoice(str, gender, &buff, last);
00897         break;
00898       }
00899 
00900       /* This sets up the gender for the string.
00901        * We just ignore this one. It's used in {G 0 Der Die Das} to determine the case. */
00902       case SCC_GENDER_INDEX: // {GENDER 0}
00903         if (_keep_gender_data) {
00904           buff += Utf8Encode(buff, SCC_GENDER_INDEX);
00905           *buff++ = *str++;
00906         } else {
00907           str++;
00908         }
00909         break;
00910 
00911       case SCC_PLURAL_LIST: { // {P}
00912         int plural_form = *str++;          // contains the plural form for this string
00913         uint offset = orig_offset + (byte)*str++;
00914         int64 v = *args->GetPointerToOffset(offset); // contains the number that determines plural
00915         str = ParseStringChoice(str, DeterminePluralForm(v, plural_form), &buff, last);
00916         break;
00917       }
00918 
00919       case SCC_ARG_INDEX: { // Move argument pointer
00920         args->offset = orig_offset + (byte)*str++;
00921         break;
00922       }
00923 
00924       case SCC_SET_CASE: { // {SET_CASE}
00925         /* This is a pseudo command, it's outputted when someone does {STRING.ack}
00926          * The modifier is added to all subsequent GetStringWithArgs that accept the modifier. */
00927         next_substr_case_index = (byte)*str++;
00928         break;
00929       }
00930 
00931       case SCC_SWITCH_CASE: { // {Used to implement case switching}
00932         /* <0x9E> <NUM CASES> <CASE1> <LEN1> <STRING1> <CASE2> <LEN2> <STRING2> <CASE3> <LEN3> <STRING3> <STRINGDEFAULT>
00933          * Each LEN is printed using 2 bytes in big endian order. */
00934         uint num = (byte)*str++;
00935         while (num) {
00936           if ((byte)str[0] == case_index) {
00937             /* Found the case, adjust str pointer and continue */
00938             str += 3;
00939             break;
00940           }
00941           /* Otherwise skip to the next case */
00942           str += 3 + (str[1] << 8) + str[2];
00943           num--;
00944         }
00945         break;
00946       }
00947 
00948       case SCC_SETX: // {SETX}
00949         if (buff + Utf8CharLen(SCC_SETX) + 1 < last) {
00950           buff += Utf8Encode(buff, SCC_SETX);
00951           *buff++ = *str++;
00952         }
00953         break;
00954 
00955       case SCC_SETXY: // {SETXY}
00956         if (buff + Utf8CharLen(SCC_SETXY) + 2 < last) {
00957           buff += Utf8Encode(buff, SCC_SETXY);
00958           *buff++ = *str++;
00959           *buff++ = *str++;
00960         }
00961         break;
00962 
00963       case SCC_REVISION: // {REV}
00964         buff = strecpy(buff, _openttd_revision, last);
00965         break;
00966 
00967       case SCC_STRING_ID: // {STRINL}
00968         if (game_script) break;
00969         buff = GetStringWithArgs(buff, Utf8Consume(&str), args, last);
00970         break;
00971 
00972       case SCC_RAW_STRING_POINTER: { // {RAW_STRING}
00973         if (game_script) break;
00974         const char *str = (const char *)(size_t)args->GetInt64(SCC_RAW_STRING_POINTER);
00975         buff = FormatString(buff, str, args, last);
00976         break;
00977       }
00978 
00979       case SCC_STRING: {// {STRING}
00980         StringID str = args->GetInt32(SCC_STRING);
00981         if (game_script && GB(str, TAB_COUNT_OFFSET, TAB_COUNT_BITS) != GAME_TEXT_TAB) break;
00982         /* WARNING. It's prohibited for the included string to consume any arguments.
00983          * For included strings that consume argument, you should use STRING1, STRING2 etc.
00984          * To debug stuff you can set argv to NULL and it will tell you */
00985         StringParameters tmp_params(args->GetDataPointer(), args->num_param - args->offset, NULL);
00986         buff = GetStringWithArgs(buff, str, &tmp_params, last, next_substr_case_index, game_script);
00987         next_substr_case_index = 0;
00988         break;
00989       }
00990 
00991       case SCC_STRING1:
00992       case SCC_STRING2:
00993       case SCC_STRING3:
00994       case SCC_STRING4:
00995       case SCC_STRING5:
00996       case SCC_STRING6:
00997       case SCC_STRING7: { // {STRING1..7}
00998         /* Strings that consume arguments */
00999         StringID str = args->GetInt32(b);
01000         if (game_script && GB(str, TAB_COUNT_OFFSET, TAB_COUNT_BITS) != GAME_TEXT_TAB) break;
01001         StringParameters sub_args(*args, b - SCC_STRING1 + 1);
01002         buff = GetStringWithArgs(buff, str, &sub_args, last, next_substr_case_index, game_script);
01003         next_substr_case_index = 0;
01004         break;
01005       }
01006 
01007       case SCC_COMMA: // {COMMA}
01008         buff = FormatCommaNumber(buff, args->GetInt64(SCC_COMMA), last);
01009         break;
01010 
01011       case SCC_DECIMAL: {// {DECIMAL}
01012         int64 number = args->GetInt64(SCC_DECIMAL);
01013         int digits = args->GetInt32(SCC_DECIMAL);
01014         buff = FormatCommaNumber(buff, number, last, digits);
01015         break;
01016       }
01017 
01018       case SCC_NUM: // {NUM}
01019         buff = FormatNoCommaNumber(buff, args->GetInt64(SCC_NUM), last);
01020         break;
01021 
01022       case SCC_ZEROFILL_NUM: { // {ZEROFILL_NUM}
01023         int64 num = args->GetInt64();
01024         buff = FormatZerofillNumber(buff, num, args->GetInt64(), last);
01025         break;
01026       }
01027 
01028       case SCC_HEX: // {HEX}
01029         buff = FormatHexNumber(buff, (uint64)args->GetInt64(SCC_HEX), last);
01030         break;
01031 
01032       case SCC_BYTES: // {BYTES}
01033         buff = FormatBytes(buff, args->GetInt64(), last);
01034         break;
01035 
01036       case SCC_CARGO_TINY: { // {CARGO_TINY}
01037         /* Tiny description of cargotypes. Layout:
01038          * param 1: cargo type
01039          * param 2: cargo count */
01040         CargoID cargo = args->GetInt32(SCC_CARGO_TINY);
01041         if (cargo >= CargoSpec::GetArraySize()) break;
01042 
01043         StringID cargo_str = CargoSpec::Get(cargo)->units_volume;
01044         int64 amount = 0;
01045         switch (cargo_str) {
01046           case STR_TONS:
01047             amount = _units[_settings_game.locale.units].c_weight.ToDisplay(args->GetInt64());
01048             break;
01049 
01050           case STR_LITERS:
01051             amount = _units[_settings_game.locale.units].c_volume.ToDisplay(args->GetInt64());
01052             break;
01053 
01054           default: {
01055             amount = args->GetInt64();
01056             break;
01057           }
01058         }
01059 
01060         buff = FormatCommaNumber(buff, amount, last);
01061         break;
01062       }
01063 
01064       case SCC_CARGO_SHORT: { // {CARGO_SHORT}
01065         /* Short description of cargotypes. Layout:
01066          * param 1: cargo type
01067          * param 2: cargo count */
01068         CargoID cargo = args->GetInt32(SCC_CARGO_SHORT);
01069         if (cargo >= CargoSpec::GetArraySize()) break;
01070 
01071         StringID cargo_str = CargoSpec::Get(cargo)->units_volume;
01072         switch (cargo_str) {
01073           case STR_TONS: {
01074             assert(_settings_game.locale.units < lengthof(_units));
01075             int64 args_array[] = {_units[_settings_game.locale.units].c_weight.ToDisplay(args->GetInt64())};
01076             StringParameters tmp_params(args_array);
01077             buff = FormatString(buff, GetStringPtr(_units[_settings_game.locale.units].l_weight), &tmp_params, last);
01078             break;
01079           }
01080 
01081           case STR_LITERS: {
01082             assert(_settings_game.locale.units < lengthof(_units));
01083             int64 args_array[] = {_units[_settings_game.locale.units].c_volume.ToDisplay(args->GetInt64())};
01084             StringParameters tmp_params(args_array);
01085             buff = FormatString(buff, GetStringPtr(_units[_settings_game.locale.units].l_volume), &tmp_params, last);
01086             break;
01087           }
01088 
01089           default: {
01090             StringParameters tmp_params(*args, 1);
01091             buff = GetStringWithArgs(buff, cargo_str, &tmp_params, last);
01092             break;
01093           }
01094         }
01095         break;
01096       }
01097 
01098       case SCC_CARGO_LONG: { // {CARGO_LONG}
01099         /* First parameter is cargo type, second parameter is cargo count */
01100         CargoID cargo = args->GetInt32(SCC_CARGO_LONG);
01101         if (cargo != CT_INVALID && cargo >= CargoSpec::GetArraySize()) break;
01102 
01103         StringID cargo_str = (cargo == CT_INVALID) ? STR_QUANTITY_N_A : CargoSpec::Get(cargo)->quantifier;
01104         StringParameters tmp_args(*args, 1);
01105         buff = GetStringWithArgs(buff, cargo_str, &tmp_args, last);
01106         break;
01107       }
01108 
01109       case SCC_CURRENCY_SHORT: // {CURRENCY_SHORT}
01110         buff = FormatGenericCurrency(buff, _currency, args->GetInt64(), true, last);
01111         break;
01112 
01113       case SCC_CURRENCY_LONG: // {CURRENCY_LONG}
01114         buff = FormatGenericCurrency(buff, _currency, args->GetInt64(SCC_CURRENCY_LONG), false, last);
01115         break;
01116 
01117       case SCC_DATE_TINY: // {DATE_TINY}
01118         buff = FormatTinyOrISODate(buff, args->GetInt32(SCC_DATE_TINY), STR_FORMAT_DATE_TINY, last);
01119         break;
01120 
01121       case SCC_DATE_SHORT: // {DATE_SHORT}
01122         buff = FormatMonthAndYear(buff, args->GetInt32(SCC_DATE_SHORT), last, next_substr_case_index);
01123         next_substr_case_index = 0;
01124         break;
01125 
01126       case SCC_DATE_LONG: // {DATE_LONG}
01127         buff = FormatYmdString(buff, args->GetInt32(SCC_DATE_LONG), last, next_substr_case_index);
01128         next_substr_case_index = 0;
01129         break;
01130 
01131       case SCC_DATE_ISO: // {DATE_ISO}
01132         buff = FormatTinyOrISODate(buff, args->GetInt32(), STR_FORMAT_DATE_ISO, last);
01133         break;
01134 
01135       case SCC_FORCE: { // {FORCE}
01136         assert(_settings_game.locale.units < lengthof(_units));
01137         int64 args_array[1] = {_units[_settings_game.locale.units].c_force.ToDisplay(args->GetInt64())};
01138         StringParameters tmp_params(args_array);
01139         buff = FormatString(buff, GetStringPtr(_units[_settings_game.locale.units].force), &tmp_params, last);
01140         break;
01141       }
01142 
01143       case SCC_HEIGHT: { // {HEIGHT}
01144         int64 args_array[] = {_units[_settings_game.locale.units].c_height.ToDisplay(args->GetInt64())};
01145         StringParameters tmp_params(args_array);
01146         buff = FormatString(buff, GetStringPtr(_units[_settings_game.locale.units].height), &tmp_params, last);
01147         break;
01148       }
01149 
01150       case SCC_POWER: { // {POWER}
01151         assert(_settings_game.locale.units < lengthof(_units));
01152         int64 args_array[1] = {_units[_settings_game.locale.units].c_power.ToDisplay(args->GetInt64())};
01153         StringParameters tmp_params(args_array);
01154         buff = FormatString(buff, GetStringPtr(_units[_settings_game.locale.units].power), &tmp_params, last);
01155         break;
01156       }
01157 
01158       case SCC_VELOCITY: { // {VELOCITY}
01159         assert(_settings_game.locale.units < lengthof(_units));
01160         int64 args_array[] = {ConvertKmhishSpeedToDisplaySpeed(args->GetInt64(SCC_VELOCITY))};
01161         StringParameters tmp_params(args_array);
01162         buff = FormatString(buff, GetStringPtr(_units[_settings_game.locale.units].velocity), &tmp_params, last);
01163         break;
01164       }
01165 
01166       case SCC_VOLUME_SHORT: { // {VOLUME_SHORT}
01167         assert(_settings_game.locale.units < lengthof(_units));
01168         int64 args_array[1] = {_units[_settings_game.locale.units].c_volume.ToDisplay(args->GetInt64())};
01169         StringParameters tmp_params(args_array);
01170         buff = FormatString(buff, GetStringPtr(_units[_settings_game.locale.units].s_volume), &tmp_params, last);
01171         break;
01172       }
01173 
01174       case SCC_VOLUME_LONG: { // {VOLUME_LONG}
01175         assert(_settings_game.locale.units < lengthof(_units));
01176         int64 args_array[1] = {_units[_settings_game.locale.units].c_volume.ToDisplay(args->GetInt64(SCC_VOLUME_LONG))};
01177         StringParameters tmp_params(args_array);
01178         buff = FormatString(buff, GetStringPtr(_units[_settings_game.locale.units].l_volume), &tmp_params, last);
01179         break;
01180       }
01181 
01182       case SCC_WEIGHT_SHORT: { // {WEIGHT_SHORT}
01183         assert(_settings_game.locale.units < lengthof(_units));
01184         int64 args_array[1] = {_units[_settings_game.locale.units].c_weight.ToDisplay(args->GetInt64())};
01185         StringParameters tmp_params(args_array);
01186         buff = FormatString(buff, GetStringPtr(_units[_settings_game.locale.units].s_weight), &tmp_params, last);
01187         break;
01188       }
01189 
01190       case SCC_WEIGHT_LONG: { // {WEIGHT_LONG}
01191         assert(_settings_game.locale.units < lengthof(_units));
01192         int64 args_array[1] = {_units[_settings_game.locale.units].c_weight.ToDisplay(args->GetInt64(SCC_WEIGHT_LONG))};
01193         StringParameters tmp_params(args_array);
01194         buff = FormatString(buff, GetStringPtr(_units[_settings_game.locale.units].l_weight), &tmp_params, last);
01195         break;
01196       }
01197 
01198       case SCC_COMPANY_NAME: { // {COMPANY}
01199         const Company *c = Company::GetIfValid(args->GetInt32());
01200         if (c == NULL) break;
01201 
01202         if (c->name != NULL) {
01203           int64 args_array[] = {(uint64)(size_t)c->name};
01204           StringParameters tmp_params(args_array);
01205           buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last);
01206         } else {
01207           int64 args_array[] = {c->name_2};
01208           StringParameters tmp_params(args_array);
01209           buff = GetStringWithArgs(buff, c->name_1, &tmp_params, last);
01210         }
01211         break;
01212       }
01213 
01214       case SCC_COMPANY_NUM: { // {COMPANY_NUM}
01215         CompanyID company = (CompanyID)args->GetInt32();
01216 
01217         /* Nothing is added for AI or inactive companies */
01218         if (Company::IsValidHumanID(company)) {
01219           int64 args_array[] = {company + 1};
01220           StringParameters tmp_params(args_array);
01221           buff = GetStringWithArgs(buff, STR_FORMAT_COMPANY_NUM, &tmp_params, last);
01222         }
01223         break;
01224       }
01225 
01226       case SCC_DEPOT_NAME: { // {DEPOT}
01227         VehicleType vt = (VehicleType)args->GetInt32(SCC_DEPOT_NAME);
01228         if (vt == VEH_AIRCRAFT) {
01229           uint64 args_array[] = {args->GetInt32()};
01230           WChar types_array[] = {SCC_STATION_NAME};
01231           StringParameters tmp_params(args_array, 1, types_array);
01232           buff = GetStringWithArgs(buff, STR_FORMAT_DEPOT_NAME_AIRCRAFT, &tmp_params, last);
01233           break;
01234         }
01235 
01236         const Depot *d = Depot::Get(args->GetInt32());
01237         if (d->name != NULL) {
01238           int64 args_array[] = {(uint64)(size_t)d->name};
01239           StringParameters tmp_params(args_array);
01240           buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last);
01241         } else {
01242           int64 args_array[] = {d->town->index, d->town_cn + 1};
01243           StringParameters tmp_params(args_array);
01244           buff = GetStringWithArgs(buff, STR_FORMAT_DEPOT_NAME_TRAIN + 2 * vt + (d->town_cn == 0 ? 0 : 1), &tmp_params, last);
01245         }
01246         break;
01247       }
01248 
01249       case SCC_ENGINE_NAME: { // {ENGINE}
01250         const Engine *e = Engine::GetIfValid(args->GetInt32(SCC_ENGINE_NAME));
01251         if (e == NULL) break;
01252 
01253         if (e->name != NULL && e->IsEnabled()) {
01254           int64 args_array[] = {(uint64)(size_t)e->name};
01255           StringParameters tmp_params(args_array);
01256           buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last);
01257         } else {
01258           StringParameters tmp_params(NULL, 0, NULL);
01259           buff = GetStringWithArgs(buff, e->info.string_id, &tmp_params, last);
01260         }
01261         break;
01262       }
01263 
01264       case SCC_GROUP_NAME: { // {GROUP}
01265         const Group *g = Group::GetIfValid(args->GetInt32());
01266         if (g == NULL) break;
01267 
01268         if (g->name != NULL) {
01269           int64 args_array[] = {(uint64)(size_t)g->name};
01270           StringParameters tmp_params(args_array);
01271           buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last);
01272         } else {
01273           int64 args_array[] = {g->index};
01274           StringParameters tmp_params(args_array);
01275 
01276           buff = GetStringWithArgs(buff, STR_FORMAT_GROUP_NAME, &tmp_params, last);
01277         }
01278         break;
01279       }
01280 
01281       case SCC_INDUSTRY_NAME: { // {INDUSTRY}
01282         const Industry *i = Industry::GetIfValid(args->GetInt32(SCC_INDUSTRY_NAME));
01283         if (i == NULL) break;
01284 
01285         /* First print the town name and the industry type name. */
01286         int64 args_array[2] = {i->town->index, GetIndustrySpec(i->type)->name};
01287         StringParameters tmp_params(args_array);
01288 
01289         buff = FormatString(buff, GetStringPtr(STR_FORMAT_INDUSTRY_NAME), &tmp_params, last, next_substr_case_index);
01290         next_substr_case_index = 0;
01291         break;
01292       }
01293 
01294       case SCC_PRESIDENT_NAME: { // {PRESIDENT_NAME}
01295         const Company *c = Company::GetIfValid(args->GetInt32(SCC_PRESIDENT_NAME));
01296         if (c == NULL) break;
01297 
01298         if (c->president_name != NULL) {
01299           int64 args_array[] = {(uint64)(size_t)c->president_name};
01300           StringParameters tmp_params(args_array);
01301           buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last);
01302         } else {
01303           int64 args_array[] = {c->president_name_2};
01304           StringParameters tmp_params(args_array);
01305           buff = GetStringWithArgs(buff, c->president_name_1, &tmp_params, last);
01306         }
01307         break;
01308       }
01309 
01310       case SCC_STATION_NAME: { // {STATION}
01311         StationID sid = args->GetInt32(SCC_STATION_NAME);
01312         const Station *st = Station::GetIfValid(sid);
01313 
01314         if (st == NULL) {
01315           /* The station doesn't exist anymore. The only place where we might
01316            * be "drawing" an invalid station is in the case of cargo that is
01317            * in transit. */
01318           StringParameters tmp_params(NULL, 0, NULL);
01319           buff = GetStringWithArgs(buff, STR_UNKNOWN_STATION, &tmp_params, last);
01320           break;
01321         }
01322 
01323         if (st->name != NULL) {
01324           int64 args_array[] = {(uint64)(size_t)st->name};
01325           StringParameters tmp_params(args_array);
01326           buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last);
01327         } else {
01328           StringID str = st->string_id;
01329           if (st->indtype != IT_INVALID) {
01330             /* Special case where the industry provides the name for the station */
01331             const IndustrySpec *indsp = GetIndustrySpec(st->indtype);
01332 
01333             /* Industry GRFs can change which might remove the station name and
01334              * thus cause very strange things. Here we check for that before we
01335              * actually set the station name. */
01336             if (indsp->station_name != STR_NULL && indsp->station_name != STR_UNDEFINED) {
01337               str = indsp->station_name;
01338             }
01339           }
01340 
01341           int64 args_array[] = {STR_TOWN_NAME, st->town->index, st->index};
01342           StringParameters tmp_params(args_array);
01343           buff = GetStringWithArgs(buff, str, &tmp_params, last);
01344         }
01345         break;
01346       }
01347 
01348       case SCC_TOWN_NAME: { // {TOWN}
01349         const Town *t = Town::GetIfValid(args->GetInt32(SCC_TOWN_NAME));
01350         if (t == NULL) break;
01351 
01352         if (t->name != NULL) {
01353           int64 args_array[] = {(uint64)(size_t)t->name};
01354           StringParameters tmp_params(args_array);
01355           buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last);
01356         } else {
01357           buff = GetTownName(buff, t, last);
01358         }
01359         break;
01360       }
01361 
01362       case SCC_WAYPOINT_NAME: { // {WAYPOINT}
01363         Waypoint *wp = Waypoint::GetIfValid(args->GetInt32(SCC_WAYPOINT_NAME));
01364         if (wp == NULL) break;
01365 
01366         if (wp->name != NULL) {
01367           int64 args_array[] = {(uint64)(size_t)wp->name};
01368           StringParameters tmp_params(args_array);
01369           buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last);
01370         } else {
01371           int64 args_array[] = {wp->town->index, wp->town_cn + 1};
01372           StringParameters tmp_params(args_array);
01373           StringID str = ((wp->string_id == STR_SV_STNAME_BUOY) ? STR_FORMAT_BUOY_NAME : STR_FORMAT_WAYPOINT_NAME);
01374           if (wp->town_cn != 0) str++;
01375           buff = GetStringWithArgs(buff, str, &tmp_params, last);
01376         }
01377         break;
01378       }
01379 
01380       case SCC_VEHICLE_NAME: { // {VEHICLE}
01381         const Vehicle *v = Vehicle::GetIfValid(args->GetInt32(SCC_VEHICLE_NAME));
01382         if (v == NULL) break;
01383 
01384         if (v->name != NULL) {
01385           int64 args_array[] = {(uint64)(size_t)v->name};
01386           StringParameters tmp_params(args_array);
01387           buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last);
01388         } else {
01389           int64 args_array[] = {v->unitnumber};
01390           StringParameters tmp_params(args_array);
01391 
01392           StringID str;
01393           switch (v->type) {
01394             default: NOT_REACHED();
01395             case VEH_TRAIN:    str = STR_SV_TRAIN_NAME; break;
01396             case VEH_ROAD:     str = STR_SV_ROAD_VEHICLE_NAME; break;
01397             case VEH_SHIP:     str = STR_SV_SHIP_NAME; break;
01398             case VEH_AIRCRAFT: str = STR_SV_AIRCRAFT_NAME; break;
01399           }
01400 
01401           buff = GetStringWithArgs(buff, str, &tmp_params, last);
01402         }
01403         break;
01404       }
01405 
01406       case SCC_SIGN_NAME: { // {SIGN}
01407         const Sign *si = Sign::GetIfValid(args->GetInt32());
01408         if (si == NULL) break;
01409 
01410         if (si->name != NULL) {
01411           int64 args_array[] = {(uint64)(size_t)si->name};
01412           StringParameters tmp_params(args_array);
01413           buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last);
01414         } else {
01415           StringParameters tmp_params(NULL, 0, NULL);
01416           buff = GetStringWithArgs(buff, STR_DEFAULT_SIGN_NAME, &tmp_params, last);
01417         }
01418         break;
01419       }
01420 
01421       case SCC_STATION_FEATURES: { // {STATIONFEATURES}
01422         buff = StationGetSpecialString(buff, args->GetInt32(SCC_STATION_FEATURES), last);
01423         break;
01424       }
01425 
01426       default:
01427         if (buff + Utf8CharLen(b) < last) buff += Utf8Encode(buff, b);
01428         break;
01429     }
01430   }
01431   *buff = '\0';
01432   return buff;
01433 }
01434 
01435 
01436 static char *StationGetSpecialString(char *buff, int x, const char *last)
01437 {
01438   if ((x & FACIL_TRAIN)      && (buff + Utf8CharLen(SCC_TRAIN) < last)) buff += Utf8Encode(buff, SCC_TRAIN);
01439   if ((x & FACIL_TRUCK_STOP) && (buff + Utf8CharLen(SCC_LORRY) < last)) buff += Utf8Encode(buff, SCC_LORRY);
01440   if ((x & FACIL_BUS_STOP)   && (buff + Utf8CharLen(SCC_BUS)   < last)) buff += Utf8Encode(buff, SCC_BUS);
01441   if ((x & FACIL_DOCK)       && (buff + Utf8CharLen(SCC_SHIP)  < last)) buff += Utf8Encode(buff, SCC_SHIP);
01442   if ((x & FACIL_AIRPORT)    && (buff + Utf8CharLen(SCC_PLANE) < last)) buff += Utf8Encode(buff, SCC_PLANE);
01443   *buff = '\0';
01444   return buff;
01445 }
01446 
01447 static char *GetSpecialTownNameString(char *buff, int ind, uint32 seed, const char *last)
01448 {
01449   return GenerateTownNameString(buff, last, ind, seed);
01450 }
01451 
01452 static const char * const _silly_company_names[] = {
01453   "Bloggs Brothers",
01454   "Tiny Transport Ltd.",
01455   "Express Travel",
01456   "Comfy-Coach & Co.",
01457   "Crush & Bump Ltd.",
01458   "Broken & Late Ltd.",
01459   "Sam Speedy & Son",
01460   "Supersonic Travel",
01461   "Mike's Motors",
01462   "Lightning International",
01463   "Pannik & Loozit Ltd.",
01464   "Inter-City Transport",
01465   "Getout & Pushit Ltd."
01466 };
01467 
01468 static const char * const _surname_list[] = {
01469   "Adams",
01470   "Allan",
01471   "Baker",
01472   "Bigwig",
01473   "Black",
01474   "Bloggs",
01475   "Brown",
01476   "Campbell",
01477   "Gordon",
01478   "Hamilton",
01479   "Hawthorn",
01480   "Higgins",
01481   "Green",
01482   "Gribble",
01483   "Jones",
01484   "McAlpine",
01485   "MacDonald",
01486   "McIntosh",
01487   "Muir",
01488   "Murphy",
01489   "Nelson",
01490   "O'Donnell",
01491   "Parker",
01492   "Phillips",
01493   "Pilkington",
01494   "Quigley",
01495   "Sharkey",
01496   "Thomson",
01497   "Watkins"
01498 };
01499 
01500 static const char * const _silly_surname_list[] = {
01501   "Grumpy",
01502   "Dozy",
01503   "Speedy",
01504   "Nosey",
01505   "Dribble",
01506   "Mushroom",
01507   "Cabbage",
01508   "Sniffle",
01509   "Fishy",
01510   "Swindle",
01511   "Sneaky",
01512   "Nutkins"
01513 };
01514 
01515 static const char _initial_name_letters[] = {
01516   'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
01517   'K', 'L', 'M', 'N', 'P', 'R', 'S', 'T', 'W',
01518 };
01519 
01520 static char *GenAndCoName(char *buff, uint32 arg, const char *last)
01521 {
01522   const char * const *base;
01523   uint num;
01524 
01525   if (_settings_game.game_creation.landscape == LT_TOYLAND) {
01526     base = _silly_surname_list;
01527     num  = lengthof(_silly_surname_list);
01528   } else {
01529     base = _surname_list;
01530     num  = lengthof(_surname_list);
01531   }
01532 
01533   buff = strecpy(buff, base[num * GB(arg, 16, 8) >> 8], last);
01534   buff = strecpy(buff, " & Co.", last);
01535 
01536   return buff;
01537 }
01538 
01539 static char *GenPresidentName(char *buff, uint32 x, const char *last)
01540 {
01541   char initial[] = "?. ";
01542   const char * const *base;
01543   uint num;
01544   uint i;
01545 
01546   initial[0] = _initial_name_letters[sizeof(_initial_name_letters) * GB(x, 0, 8) >> 8];
01547   buff = strecpy(buff, initial, last);
01548 
01549   i = (sizeof(_initial_name_letters) + 35) * GB(x, 8, 8) >> 8;
01550   if (i < sizeof(_initial_name_letters)) {
01551     initial[0] = _initial_name_letters[i];
01552     buff = strecpy(buff, initial, last);
01553   }
01554 
01555   if (_settings_game.game_creation.landscape == LT_TOYLAND) {
01556     base = _silly_surname_list;
01557     num  = lengthof(_silly_surname_list);
01558   } else {
01559     base = _surname_list;
01560     num  = lengthof(_surname_list);
01561   }
01562 
01563   buff = strecpy(buff, base[num * GB(x, 16, 8) >> 8], last);
01564 
01565   return buff;
01566 }
01567 
01568 static char *GetSpecialNameString(char *buff, int ind, StringParameters *args, const char *last)
01569 {
01570   switch (ind) {
01571     case 1: // not used
01572       return strecpy(buff, _silly_company_names[min(args->GetInt32() & 0xFFFF, lengthof(_silly_company_names) - 1)], last);
01573 
01574     case 2: // used for Foobar & Co company names
01575       return GenAndCoName(buff, args->GetInt32(), last);
01576 
01577     case 3: // President name
01578       return GenPresidentName(buff, args->GetInt32(), last);
01579   }
01580 
01581   /* town name? */
01582   if (IsInsideMM(ind - 6, 0, SPECSTR_TOWNNAME_LAST - SPECSTR_TOWNNAME_START + 1)) {
01583     buff = GetSpecialTownNameString(buff, ind - 6, args->GetInt32(), last);
01584     return strecpy(buff, " Transport", last);
01585   }
01586 
01587   /* language name? */
01588   if (IsInsideMM(ind, (SPECSTR_LANGUAGE_START - 0x70E4), (SPECSTR_LANGUAGE_END - 0x70E4) + 1)) {
01589     int i = ind - (SPECSTR_LANGUAGE_START - 0x70E4);
01590     return strecpy(buff,
01591       &_languages[i] == _current_language ? _current_language->own_name : _languages[i].name, last);
01592   }
01593 
01594   /* resolution size? */
01595   if (IsInsideMM(ind, (SPECSTR_RESOLUTION_START - 0x70E4), (SPECSTR_RESOLUTION_END - 0x70E4) + 1)) {
01596     int i = ind - (SPECSTR_RESOLUTION_START - 0x70E4);
01597     buff += seprintf(
01598       buff, last, "%ux%u", _resolutions[i].width, _resolutions[i].height
01599     );
01600     return buff;
01601   }
01602 
01603   /* screenshot format name? */
01604   if (IsInsideMM(ind, (SPECSTR_SCREENSHOT_START - 0x70E4), (SPECSTR_SCREENSHOT_END - 0x70E4) + 1)) {
01605     int i = ind - (SPECSTR_SCREENSHOT_START - 0x70E4);
01606     return strecpy(buff, GetScreenshotFormatDesc(i), last);
01607   }
01608 
01609   NOT_REACHED();
01610 }
01611 
01612 #ifdef ENABLE_NETWORK
01613 extern void SortNetworkLanguages();
01614 #else /* ENABLE_NETWORK */
01615 static inline void SortNetworkLanguages() {}
01616 #endif /* ENABLE_NETWORK */
01617 
01622 bool LanguagePackHeader::IsValid() const
01623 {
01624   return this->ident        == TO_LE32(LanguagePackHeader::IDENT) &&
01625          this->version      == TO_LE32(LANGUAGE_PACK_VERSION) &&
01626          this->plural_form  <  LANGUAGE_MAX_PLURAL &&
01627          this->text_dir     <= 1 &&
01628          this->newgrflangid < MAX_LANG &&
01629          this->num_genders  < MAX_NUM_GENDERS &&
01630          this->num_cases    < MAX_NUM_CASES &&
01631          StrValid(this->name,                           lastof(this->name)) &&
01632          StrValid(this->own_name,                       lastof(this->own_name)) &&
01633          StrValid(this->isocode,                        lastof(this->isocode)) &&
01634          StrValid(this->digit_group_separator,          lastof(this->digit_group_separator)) &&
01635          StrValid(this->digit_group_separator_currency, lastof(this->digit_group_separator_currency)) &&
01636          StrValid(this->digit_decimal_separator,        lastof(this->digit_decimal_separator));
01637 }
01638 
01644 bool ReadLanguagePack(const LanguageMetadata *lang)
01645 {
01646   /* Current language pack */
01647   size_t len;
01648   LanguagePack *lang_pack = (LanguagePack *)ReadFileToMem(lang->file, &len, 1U << 20);
01649   if (lang_pack == NULL) return false;
01650 
01651   /* End of read data (+ terminating zero added in ReadFileToMem()) */
01652   const char *end = (char *)lang_pack + len + 1;
01653 
01654   /* We need at least one byte of lang_pack->data */
01655   if (end <= lang_pack->data || !lang_pack->IsValid()) {
01656     free(lang_pack);
01657     return false;
01658   }
01659 
01660 #if TTD_ENDIAN == TTD_BIG_ENDIAN
01661   for (uint i = 0; i < TAB_COUNT; i++) {
01662     lang_pack->offsets[i] = ReadLE16Aligned(&lang_pack->offsets[i]);
01663   }
01664 #endif /* TTD_ENDIAN == TTD_BIG_ENDIAN */
01665 
01666   uint count = 0;
01667   for (uint i = 0; i < TAB_COUNT; i++) {
01668     uint num = lang_pack->offsets[i];
01669     _langtab_start[i] = count;
01670     _langtab_num[i] = num;
01671     count += num;
01672   }
01673 
01674   /* Allocate offsets */
01675   char **langpack_offs = MallocT<char *>(count);
01676 
01677   /* Fill offsets */
01678   char *s = lang_pack->data;
01679   len = (byte)*s++;
01680   for (uint i = 0; i < count; i++) {
01681     if (s + len >= end) {
01682       free(lang_pack);
01683       free(langpack_offs);
01684       return false;
01685     }
01686     if (len >= 0xC0) {
01687       len = ((len & 0x3F) << 8) + (byte)*s++;
01688       if (s + len >= end) {
01689         free(lang_pack);
01690         free(langpack_offs);
01691         return false;
01692       }
01693     }
01694     langpack_offs[i] = s;
01695     s += len;
01696     len = (byte)*s;
01697     *s++ = '\0'; // zero terminate the string
01698   }
01699 
01700   free(_langpack);
01701   _langpack = lang_pack;
01702 
01703   free(_langpack_offs);
01704   _langpack_offs = langpack_offs;
01705 
01706   _current_language = lang;
01707   _current_text_dir = (TextDirection)_current_language->text_dir;
01708   const char *c_file = strrchr(_current_language->file, PATHSEPCHAR) + 1;
01709   strecpy(_config_language_file, c_file, lastof(_config_language_file));
01710   SetCurrentGrfLangID(_current_language->newgrflangid);
01711 
01712 #ifdef WITH_ICU
01713   /* Delete previous collator. */
01714   if (_current_collator != NULL) {
01715     delete _current_collator;
01716     _current_collator = NULL;
01717   }
01718 
01719   /* Create a collator instance for our current locale. */
01720   UErrorCode status = U_ZERO_ERROR;
01721   _current_collator = Collator::createInstance(Locale(_current_language->isocode), status);
01722   /* Sort number substrings by their numerical value. */
01723   if (_current_collator != NULL) _current_collator->setAttribute(UCOL_NUMERIC_COLLATION, UCOL_ON, status);
01724   /* Avoid using the collator if it is not correctly set. */
01725   if (U_FAILURE(status)) {
01726     delete _current_collator;
01727     _current_collator = NULL;
01728   }
01729 #endif /* WITH_ICU */
01730 
01731   /* Some lists need to be sorted again after a language change. */
01732   ReconsiderGameScriptLanguage();
01733   InitializeSortedCargoSpecs();
01734   SortIndustryTypes();
01735   BuildIndustriesLegend();
01736   SortNetworkLanguages();
01737   InvalidateWindowClassesData(WC_BUILD_VEHICLE);      // Build vehicle window.
01738   InvalidateWindowClassesData(WC_TRAINS_LIST);        // Train group window.
01739   InvalidateWindowClassesData(WC_ROADVEH_LIST);       // Road vehicle group window.
01740   InvalidateWindowClassesData(WC_SHIPS_LIST);         // Ship group window.
01741   InvalidateWindowClassesData(WC_AIRCRAFT_LIST);      // Aircraft group window.
01742   InvalidateWindowClassesData(WC_INDUSTRY_DIRECTORY); // Industry directory window.
01743   InvalidateWindowClassesData(WC_STATION_LIST);       // Station list window.
01744 
01745   return true;
01746 }
01747 
01748 /* Win32 implementation in win32.cpp.
01749  * OS X implementation in os/macosx/macos.mm. */
01750 #if !(defined(WIN32) || defined(__APPLE__))
01751 
01759 const char *GetCurrentLocale(const char *param)
01760 {
01761   const char *env;
01762 
01763   env = getenv("LANGUAGE");
01764   if (env != NULL) return env;
01765 
01766   env = getenv("LC_ALL");
01767   if (env != NULL) return env;
01768 
01769   if (param != NULL) {
01770     env = getenv(param);
01771     if (env != NULL) return env;
01772   }
01773 
01774   return getenv("LANG");
01775 }
01776 #else
01777 const char *GetCurrentLocale(const char *param);
01778 #endif /* !(defined(WIN32) || defined(__APPLE__)) */
01779 
01780 int CDECL StringIDSorter(const StringID *a, const StringID *b)
01781 {
01782   char stra[512];
01783   char strb[512];
01784   GetString(stra, *a, lastof(stra));
01785   GetString(strb, *b, lastof(strb));
01786 
01787   return strcmp(stra, strb);
01788 }
01789 
01795 const LanguageMetadata *GetLanguage(byte newgrflangid)
01796 {
01797   for (const LanguageMetadata *lang = _languages.Begin(); lang != _languages.End(); lang++) {
01798     if (newgrflangid == lang->newgrflangid) return lang;
01799   }
01800 
01801   return NULL;
01802 }
01803 
01810 static bool GetLanguageFileHeader(const char *file, LanguagePackHeader *hdr)
01811 {
01812   FILE *f = fopen(file, "rb");
01813   if (f == NULL) return false;
01814 
01815   size_t read = fread(hdr, sizeof(*hdr), 1, f);
01816   fclose(f);
01817 
01818   bool ret = read == 1 && hdr->IsValid();
01819 
01820   /* Convert endianness for the windows language ID */
01821   if (ret) {
01822     hdr->missing = FROM_LE16(hdr->missing);
01823     hdr->winlangid = FROM_LE16(hdr->winlangid);
01824   }
01825   return ret;
01826 }
01827 
01832 static void GetLanguageList(const char *path)
01833 {
01834   DIR *dir = ttd_opendir(path);
01835   if (dir != NULL) {
01836     struct dirent *dirent;
01837     while ((dirent = readdir(dir)) != NULL) {
01838       const char *d_name    = FS2OTTD(dirent->d_name);
01839       const char *extension = strrchr(d_name, '.');
01840 
01841       /* Not a language file */
01842       if (extension == NULL || strcmp(extension, ".lng") != 0) continue;
01843 
01844       LanguageMetadata lmd;
01845       seprintf(lmd.file, lastof(lmd.file), "%s%s", path, d_name);
01846 
01847       /* Check whether the file is of the correct version */
01848       if (!GetLanguageFileHeader(lmd.file, &lmd)) {
01849         DEBUG(misc, 3, "%s is not a valid language file", lmd.file);
01850       } else if (GetLanguage(lmd.newgrflangid) != NULL) {
01851         DEBUG(misc, 3, "%s's language ID is already known", lmd.file);
01852       } else {
01853         *_languages.Append() = lmd;
01854       }
01855     }
01856     closedir(dir);
01857   }
01858 }
01859 
01864 void InitializeLanguagePacks()
01865 {
01866   Searchpath sp;
01867 
01868   FOR_ALL_SEARCHPATHS(sp) {
01869     char path[MAX_PATH];
01870     FioAppendDirectory(path, lengthof(path), sp, LANG_DIR);
01871     GetLanguageList(path);
01872   }
01873   if (_languages.Length() == 0) usererror("No available language packs (invalid versions?)");
01874 
01875   /* Acquire the locale of the current system */
01876   const char *lang = GetCurrentLocale("LC_MESSAGES");
01877   if (lang == NULL) lang = "en_GB";
01878 
01879   const LanguageMetadata *chosen_language   = NULL; 
01880   const LanguageMetadata *language_fallback = NULL; 
01881   const LanguageMetadata *en_GB_fallback    = _languages.Begin(); 
01882 
01883   /* Find a proper language. */
01884   for (const LanguageMetadata *lng = _languages.Begin(); lng != _languages.End(); lng++) {
01885     /* We are trying to find a default language. The priority is by
01886      * configuration file, local environment and last, if nothing found,
01887      * English. */
01888     const char *lang_file = strrchr(lng->file, PATHSEPCHAR) + 1;
01889     if (strcmp(lang_file, _config_language_file) == 0) {
01890       chosen_language = lng;
01891       break;
01892     }
01893 
01894     if (strcmp (lng->isocode, "en_GB") == 0) en_GB_fallback    = lng;
01895     if (strncmp(lng->isocode, lang, 5) == 0) chosen_language   = lng;
01896     if (strncmp(lng->isocode, lang, 2) == 0) language_fallback = lng;
01897   }
01898 
01899   /* We haven't found the language in the config nor the one in the locale.
01900    * Now we set it to one of the fallback languages */
01901   if (chosen_language == NULL) {
01902     chosen_language = (language_fallback != NULL) ? language_fallback : en_GB_fallback;
01903   }
01904 
01905   if (!ReadLanguagePack(chosen_language)) usererror("Can't read language pack '%s'", chosen_language->file);
01906 }
01907 
01912 const char *GetCurrentLanguageIsoCode()
01913 {
01914   return _langpack->isocode;
01915 }
01916 
01923 bool MissingGlyphSearcher::FindMissingGlyphs(const char **str)
01924 {
01925   InitFreeType(this->Monospace());
01926   const Sprite *question_mark[FS_END];
01927 
01928   for (FontSize size = this->Monospace() ? FS_MONO : FS_BEGIN; size < (this->Monospace() ? FS_END : FS_MONO); size++) {
01929     question_mark[size] = GetGlyph(size, '?');
01930   }
01931 
01932   this->Reset();
01933   for (const char *text = this->NextString(); text != NULL; text = this->NextString()) {
01934     FontSize size = this->DefaultSize();
01935     if (str != NULL) *str = text;
01936     for (WChar c = Utf8Consume(&text); c != '\0'; c = Utf8Consume(&text)) {
01937       if (c == SCC_SETX) {
01938         /* SetX is, together with SetXY as special character that
01939           * uses the next (two) characters as data points. We have
01940           * to skip those, otherwise the UTF8 reading will go haywire. */
01941         text++;
01942       } else if (c == SCC_SETXY) {
01943         text += 2;
01944       } else if (c == SCC_TINYFONT) {
01945         size = FS_SMALL;
01946       } else if (c == SCC_BIGFONT) {
01947         size = FS_LARGE;
01948       } else if (!IsInsideMM(c, SCC_SPRITE_START, SCC_SPRITE_END) && IsPrintable(c) && !IsTextDirectionChar(c) && c != '?' && GetGlyph(size, c) == question_mark[size]) {
01949         /* The character is printable, but not in the normal font. This is the case we were testing for. */
01950         return true;
01951       }
01952     }
01953   }
01954   return false;
01955 }
01956 
01958 class LanguagePackGlyphSearcher : public MissingGlyphSearcher {
01959   uint i; 
01960   uint j; 
01961 
01962   /* virtual */ void Reset()
01963   {
01964     this->i = 0;
01965     this->j = 0;
01966   }
01967 
01968   /* virtual */ FontSize DefaultSize()
01969   {
01970     return FS_NORMAL;
01971   }
01972 
01973   /* virtual */ const char *NextString()
01974   {
01975     if (this->i >= TAB_COUNT) return NULL;
01976 
01977     const char *ret = _langpack_offs[_langtab_start[i] + j];
01978 
01979     this->j++;
01980     while (this->j >= _langtab_num[this->i] && this->i < TAB_COUNT) {
01981       i++;
01982       j = 0;
01983     }
01984 
01985     return ret;
01986   }
01987 
01988   /* virtual */ bool Monospace()
01989   {
01990     return false;
01991   }
01992 
01993   /* virtual */ void SetFontNames(FreeTypeSettings *settings, const char *font_name)
01994   {
01995 #ifdef WITH_FREETYPE
01996     strecpy(settings->small_font,  font_name, lastof(settings->small_font));
01997     strecpy(settings->medium_font, font_name, lastof(settings->medium_font));
01998     strecpy(settings->large_font,  font_name, lastof(settings->large_font));
01999 #endif /* WITH_FREETYPE */
02000   }
02001 };
02002 
02016 void CheckForMissingGlyphs(bool base_font, MissingGlyphSearcher *searcher)
02017 {
02018   static LanguagePackGlyphSearcher pack_searcher;
02019   if (searcher == NULL) searcher = &pack_searcher;
02020   bool bad_font = !base_font || searcher->FindMissingGlyphs(NULL);
02021 #ifdef WITH_FREETYPE
02022   if (bad_font) {
02023     /* We found an unprintable character... lets try whether we can find
02024      * a fallback font that can print the characters in the current language. */
02025     FreeTypeSettings backup;
02026     memcpy(&backup, &_freetype, sizeof(backup));
02027 
02028     bad_font = !SetFallbackFont(&_freetype, _langpack->isocode, _langpack->winlangid, searcher);
02029 
02030     memcpy(&_freetype, &backup, sizeof(backup));
02031 
02032     if (bad_font && base_font) {
02033       /* Our fallback font does miss characters too, so keep the
02034        * user chosen font as that is more likely to be any good than
02035        * the wild guess we made */
02036       InitFreeType(searcher->Monospace());
02037     }
02038   }
02039 #endif
02040 
02041   if (bad_font) {
02042     /* All attempts have failed. Display an error. As we do not want the string to be translated by
02043      * the translators, we 'force' it into the binary and 'load' it via a BindCString. To do this
02044      * properly we have to set the colour of the string, otherwise we end up with a lot of artefacts.
02045      * The colour 'character' might change in the future, so for safety we just Utf8 Encode it into
02046      * the string, which takes exactly three characters, so it replaces the "XXX" with the colour marker. */
02047     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.");
02048     Utf8Encode(err_str, SCC_YELLOW);
02049     SetDParamStr(0, err_str);
02050     ShowErrorMessage(STR_JUST_RAW_STRING, INVALID_STRING_ID, WL_WARNING);
02051 
02052     /* Reset the font width */
02053     LoadStringWidthTable(searcher->Monospace());
02054     return;
02055   }
02056 
02057   /* Update the font with cache */
02058   LoadStringWidthTable(searcher->Monospace());
02059 
02060 #if !defined(WITH_ICU)
02061   /*
02062    * For right-to-left languages we need the ICU library. If
02063    * we do not have support for that library we warn the user
02064    * about it with a message. As we do not want the string to
02065    * be translated by the translators, we 'force' it into the
02066    * binary and 'load' it via a BindCString. To do this
02067    * properly we have to set the colour of the string,
02068    * otherwise we end up with a lot of artefacts. The colour
02069    * 'character' might change in the future, so for safety
02070    * we just Utf8 Encode it into the string, which takes
02071    * exactly three characters, so it replaces the "XXX" with
02072    * the colour marker.
02073    */
02074   if (_current_text_dir != TD_LTR) {
02075     static char *err_str = strdup("XXXThis version of OpenTTD does not support right-to-left languages. Recompile with icu enabled.");
02076     Utf8Encode(err_str, SCC_YELLOW);
02077     SetDParamStr(0, err_str);
02078     ShowErrorMessage(STR_JUST_RAW_STRING, INVALID_STRING_ID, WL_ERROR);
02079   }
02080 #endif
02081 }