strings.cpp

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