strings.cpp

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