# strings.cpp

Go to the documentation of this file.

    00001 /* $Id: strings.cpp 19223 2010-02-23 23:26:37Z 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 "industry.h"
    00019 #include "newgrf_text.h"
    00020 #include "fileio_func.h"
    00021 #include "group.h"
    00022 #include "signs_base.h"
    00023 #include "cargotype.h"
    00024 #include "fontcache.h"
    00025 #include "gui.h"
    00026 #include "strings_func.h"
    00027 #include "rev.h"
    00028 #include "core/endian_func.hpp"
    00029 #include "date_func.h"
    00030 #include "vehicle_base.h"
    00031 #include "engine_base.h"
    00032 #include "strgen/strgen.h"
    00033 #include "townname_func.h"
    00034 #include "string_func.h"
    00035 #include "company_base.h"
    00036
    00037 #include "table/strings.h"
    00038 #include "table/control_codes.h"
    00039
    00040 DynamicLanguages _dynlang;
    00041 uint64 _decode_parameters[20];
    00042
    00043 static char *StationGetSpecialString(char *buff, int x, const char *last);
    00044 static char *GetSpecialTownNameString(char *buff, int ind, uint32 seed, const char *last);
    00045 static char *GetSpecialNameString(char *buff, int ind, int64 *argv, const char *last);
    00046
    00047 static char *FormatString(char *buff, const char *str, int64 *argv, uint casei, const char *last);
    00048
    00049 struct LanguagePack : public LanguagePackHeader {
    00050   char data[]; // list of strings
    00051 };
    00052
    00053 static char **_langpack_offs;
    00054 static LanguagePack *_langpack;
    00055 static uint _langtab_num[32];   // Offset into langpack offs
    00056 static uint _langtab_start[32]; // Offset into langpack offs
    00057 static bool _keep_gender_data = false;
    00058
    00059
    00061 static inline int64 GetInt64(int64 **argv)
    00062 {
    00063   assert(argv);
    00064   return *(*argv)++;
    00065 }
    00066
    00068 static inline int32 GetInt32(int64 **argv)
    00069 {
    00070   return (int32)GetInt64(argv);
    00071 }
    00072
    00074 static inline int64 *GetArgvPtr(int64 **argv, int n)
    00075 {
    00076   int64 *result;
    00077   assert(*argv);
    00078   result = *argv;
    00079   (*argv) += n;
    00080   return result;
    00081 }
    00082
    00083
    00084 const char *GetStringPtr(StringID string)
    00085 {
    00086   switch (GB(string, 11, 5)) {
    00087     case 28: return GetGRFStringPtr(GB(string, 0, 11));
    00088     case 29: return GetGRFStringPtr(GB(string, 0, 11) + 0x0800);
    00089     case 30: return GetGRFStringPtr(GB(string, 0, 11) + 0x1000);
    00090     default: return _langpack_offs[_langtab_start[string >> 11] + (string & 0x7FF)];
    00091   }
    00092 }
    00093
    00104 char *GetStringWithArgs(char *buffr, uint string, int64 *argv, const char *last)
    00105 {
    00106   if (GB(string, 0, 16) == 0) return GetStringWithArgs(buffr, STR_UNDEFINED, argv, last);
    00107
    00108   uint index = GB(string,  0, 11);
    00109   uint tab   = GB(string, 11,  5);
    00110
    00111   switch (tab) {
    00112     case 4:
    00113       if (index >= 0xC0)
    00114         return GetSpecialTownNameString(buffr, index - 0xC0, GetInt32(&argv), last);
    00115       break;
    00116
    00117     case 14:
    00118       if (index >= 0xE4)
    00119         return GetSpecialNameString(buffr, index - 0xE4, argv, last);
    00120       break;
    00121
    00122     case 15:
    00123       /* Old table for custom names. This is no longer used */
    00124       error("Incorrect conversion of custom name string.");
    00125
    00126     case 26:
    00127       /* Include string within newgrf text (format code 81) */
    00128       if (HasBit(index, 10)) {
    00129         StringID string = GetGRFStringID(0, 0xD000 + GB(index, 0, 10));
    00130         return GetStringWithArgs(buffr, string, argv, last);
    00131       }
    00132       break;
    00133
    00134     case 28:
    00135       return FormatString(buffr, GetGRFStringPtr(index), argv, 0, last);
    00136
    00137     case 29:
    00138       return FormatString(buffr, GetGRFStringPtr(index + 0x0800), argv, 0, last);
    00139
    00140     case 30:
    00141       return FormatString(buffr, GetGRFStringPtr(index + 0x1000), argv, 0, last);
    00142
    00143     case 31:
    00144       NOT_REACHED();
    00145   }
    00146
    00147   if (index >= _langtab_num[tab]) {
    00148     error("String 0x%X is invalid. You are probably using an old version of the .lng file.\n", string);
    00149   }
    00150
    00151   return FormatString(buffr, GetStringPtr(GB(string, 0, 16)), argv, GB(string, 24, 8), last);
    00152 }
    00153
    00154 char *GetString(char *buffr, StringID string, const char *last)
    00155 {
    00156   return GetStringWithArgs(buffr, string, (int64*)_decode_parameters, last);
    00157 }
    00158
    00159
    00160 char *InlineString(char *buf, StringID string)
    00161 {
    00162   buf += Utf8Encode(buf, SCC_STRING_ID);
    00163   buf += Utf8Encode(buf, string);
    00164   return buf;
    00165 }
    00166
    00167
    00172 void SetDParamStr(uint n, const char *str)
    00173 {
    00174   SetDParam(n, (uint64)(size_t)str);
    00175 }
    00176
    00181 void InjectDParam(uint amount)
    00182 {
    00183   assert((uint)amount < lengthof(_decode_parameters));
    00184   memmove(_decode_parameters + amount, _decode_parameters, sizeof(_decode_parameters) - amount * sizeof(uint64));
    00185 }
    00186
    00187 static char *FormatNumber(char *buff, int64 number, const char *last, const char *separator, int zerofill_from = 19)
    00188 {
    00189   uint64 divisor = 10000000000000000000ULL;
    00190
    00191   if (number < 0) {
    00192     buff += seprintf(buff, last, "-");
    00193     number = -number;
    00194   }
    00195
    00196   uint64 num = number;
    00197   uint64 tot = 0;
    00198   for (int i = 0; i < 20; i++) {
    00199     uint64 quot = 0;
    00200     if (num >= divisor) {
    00201       quot = num / divisor;
    00202       num = num % divisor;
    00203     }
    00204     if (tot |= quot || i >= zerofill_from) {
    00205       buff += seprintf(buff, last, "%i", (int)quot);
    00206       if ((i % 3) == 1 && i != 19) buff = strecpy(buff, separator, last);
    00207     }
    00208
    00209     divisor /= 10;
    00210   }
    00211
    00212   *buff = '\0';
    00213
    00214   return buff;
    00215 }
    00216
    00217 static char *FormatCommaNumber(char *buff, int64 number, const char *last)
    00218 {
    00219   const char *separator = _settings_game.locale.digit_group_separator;
    00220   if (separator == NULL) separator = _langpack->digit_group_separator;
    00221   return FormatNumber(buff, number, last, separator);
    00222 }
    00223
    00224 static char *FormatNoCommaNumber(char *buff, int64 number, const char *last)
    00225 {
    00226   return FormatNumber(buff, number, last, "");
    00227 }
    00228
    00229 static char *FormatZerofillNumber(char *buff, int64 number, int64 count, const char *last)
    00230 {
    00231   return FormatNumber(buff, number, last, "", 20 - count);
    00232 }
    00233
    00234 static char *FormatHexNumber(char *buff, int64 number, const char *last)
    00235 {
    00236   return buff + seprintf(buff, last, "0x%x", (uint32)number);
    00237 }
    00238
    00246 static char *FormatBytes(char *buff, int64 number, const char *last)
    00247 {
    00248   assert(number >= 0);
    00249
    00250   /*                                    1   2^10  2^20  2^30  2^40  2^50  2^60 */
    00251   const char * const iec_prefixes[] = { "", "Ki", "Mi", "Gi", "Ti", "Pi", "Ei" };
    00252   uint id = 1;
    00253   while (number >= 1024 * 1024) {
    00254     number /= 1024;
    00255     id++;
    00256   }
    00257
    00258   const char *decimal_separator = _settings_game.locale.digit_decimal_separator;
    00259   if (decimal_separator == NULL) decimal_separator = _langpack->digit_decimal_separator;
    00260
    00261   if (number < 1024) {
    00262     id = 0;
    00263     buff += seprintf(buff, last, "%i", (int)number);
    00264   } else if (number < 1024 * 10) {
    00265     buff += seprintf(buff, last, "%i%s%02i", (int)number / 1024, decimal_separator, (int)(number % 1024) * 100 / 1024);
    00266   } else if (number < 1024 * 100) {
    00267     buff += seprintf(buff, last, "%i%s%01i", (int)number / 1024, decimal_separator, (int)(number % 1024) * 10 / 1024);
    00268   } else {
    00269     assert(number < 1024 * 1024);
    00270     buff += seprintf(buff, last, "%i", (int)number / 1024);
    00271   }
    00272
    00273   assert(id < lengthof(iec_prefixes));
    00274   buff += seprintf(buff, last, " %sB", iec_prefixes[id]);
    00275
    00276   return buff;
    00277 }
    00278
    00279 static char *FormatYmdString(char *buff, Date date, const char *last)
    00280 {
    00281   YearMonthDay ymd;
    00282   ConvertDateToYMD(date, &ymd);
    00283
    00284   int64 args[3] = { ymd.day + STR_ORDINAL_NUMBER_1ST - 1, STR_MONTH_ABBREV_JAN + ymd.month, ymd.year };
    00285   return FormatString(buff, GetStringPtr(STR_FORMAT_DATE_LONG), args, 0, last);
    00286 }
    00287
    00288 static char *FormatMonthAndYear(char *buff, Date date, const char *last)
    00289 {
    00290   YearMonthDay ymd;
    00291   ConvertDateToYMD(date, &ymd);
    00292
    00293   int64 args[2] = { STR_MONTH_JAN + ymd.month, ymd.year };
    00294   return FormatString(buff, GetStringPtr(STR_FORMAT_DATE_SHORT), args, 0, last);
    00295 }
    00296
    00297 static char *FormatTinyOrISODate(char *buff, Date date, StringID str, const char *last)
    00298 {
    00299   YearMonthDay ymd;
    00300   ConvertDateToYMD(date, &ymd);
    00301
    00302   char day[3];
    00303   char month[3];
    00304   /* We want to zero-pad the days and months */
    00305   snprintf(day,   lengthof(day),   "%02i", ymd.day);
    00306   snprintf(month, lengthof(month), "%02i", ymd.month + 1);
    00307
    00308   int64 args[3] = { (int64)(size_t)day, (int64)(size_t)month, ymd.year };
    00309   return FormatString(buff, GetStringPtr(str), args, 0, last);
    00310 }
    00311
    00312 static char *FormatGenericCurrency(char *buff, const CurrencySpec *spec, Money number, bool compact, const char *last)
    00313 {
    00314   /* We are going to make number absolute for printing, so
    00315    * keep this piece of data as we need it later on */
    00316   bool negative = number < 0;
    00317   const char *multiplier = "";
    00318
    00319   number *= spec->rate;
    00320
    00321   /* convert from negative */
    00322   if (number < 0) {
    00323     if (buff + Utf8CharLen(SCC_RED) > last) return buff;
    00324     buff += Utf8Encode(buff, SCC_RED);
    00325     buff = strecpy(buff, "-", last);
    00326     number = -number;
    00327   }
    00328
    00329   /* Add prefix part, folowing symbol_pos specification.
    00330    * Here, it can can be either 0 (prefix) or 2 (both prefix anf suffix).
    00331    * The only remaining value is 1 (suffix), so everything that is not 1 */
    00332   if (spec->symbol_pos != 1) buff = strecpy(buff, spec->prefix, last);
    00333
    00334   /* for huge numbers, compact the number into k or M */
    00335   if (compact) {
    00336     if (number >= 1000000000) {
    00337       number = (number + 500000) / 1000000;
    00338       multiplier = "M";
    00339     } else if (number >= 1000000) {
    00340       number = (number + 500) / 1000;
    00341       multiplier = "k";
    00342     }
    00343   }
    00344
    00345   const char *separator = _settings_game.locale.digit_group_separator_currency;
    00346   if (separator == NULL && !StrEmpty(_currency->separator)) separator = _currency->separator;
    00347   if (separator == NULL) separator = _langpack->digit_group_separator_currency;
    00348   buff = FormatNumber(buff, number, last, separator);
    00349   buff = strecpy(buff, multiplier, last);
    00350
    00351   /* Add suffix part, folowing symbol_pos specification.
    00352    * Here, it can can be either 1 (suffix) or 2 (both prefix anf suffix).
    00353    * The only remaining value is 1 (prefix), so everything that is not 0 */
    00354   if (spec->symbol_pos != 0) buff = strecpy(buff, spec->suffix, last);
    00355
    00356   if (negative) {
    00357     if (buff + Utf8CharLen(SCC_PREVIOUS_COLOUR) > last) return buff;
    00358     buff += Utf8Encode(buff, SCC_PREVIOUS_COLOUR);
    00359     *buff = '\0';
    00360   }
    00361
    00362   return buff;
    00363 }
    00364
    00365 static int DeterminePluralForm(int64 count)
    00366 {
    00367   /* The absolute value determines plurality */
    00368   uint64 n = abs(count);
    00369
    00370   switch (_langpack->plural_form) {
    00371     default:
    00372       NOT_REACHED();
    00373
    00374     /* Two forms, singular used for one only
    00375      * Used in:
    00376      *   Danish, Dutch, English, German, Norwegian, Swedish, Estonian, Finnish,
    00377      *   Greek, Hebrew, Italian, Portuguese, Spanish, Esperanto */
    00378     case 0:
    00379       return n != 1;
    00380
    00381     /* Only one form
    00382      * Used in:
    00383      *   Hungarian, Japanese, Korean, Turkish */
    00384     case 1:
    00385       return 0;
    00386
    00387     /* Two forms, singular used for zero and one
    00388      * Used in:
    00389      *   French, Brazilian Portuguese */
    00390     case 2:
    00391       return n > 1;
    00392
    00393     /* Three forms, special case for zero
    00394      * Used in:
    00395      *   Latvian */
    00396     case 3:
    00397       return n % 10 == 1 && n % 100 != 11 ? 0 : n != 0 ? 1 : 2;
    00398
    00399     /* Three forms, special case for one and two
    00400      * Used in:
    00401      *   Gaelige (Irish) */
    00402     case 4:
    00403       return n == 1 ? 0 : n == 2 ? 1 : 2;
    00404
    00405     /* Three forms, special case for numbers ending in 1[2-9]
    00406      * Used in:
    00407      *   Lithuanian */
    00408     case 5:
    00409       return n % 10 == 1 && n % 100 != 11 ? 0 : n % 10 >= 2 && (n % 100 < 10 || n % 100 >= 20) ? 1 : 2;
    00410
    00411     /* Three forms, special cases for numbers ending in 1 and 2, 3, 4, except those ending in 1[1-4]
    00412      * Used in:
    00413      *   Croatian, Russian, Slovak, Ukrainian */
    00414     case 6:
    00415       return n % 10 == 1 && n % 100 != 11 ? 0 : n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 10 || n % 100 >= 20) ? 1 : 2;
    00416
    00417     /* Three forms, special case for one and some numbers ending in 2, 3, or 4
    00418      * Used in:
    00419      *   Polish */
    00420     case 7:
    00421       return n == 1 ? 0 : n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 10 || n % 100 >= 20) ? 1 : 2;
    00422
    00423     /* Four forms, special case for one and all numbers ending in 02, 03, or 04
    00424      * Used in:
    00425      *   Slovenian */
    00426     case 8:
    00427       return n % 100 == 1 ? 0 : n % 100 == 2 ? 1 : n % 100 == 3 || n % 100 == 4 ? 2 : 3;
    00428
    00429     /* Two forms; singular used for everything ending in 1 but not in 11.
    00430      * Used in:
    00431      *   Icelandic */
    00432     case 9:
    00433       return n % 10 == 1 && n % 100 != 11 ? 0 : 1;
    00434
    00435     /* Three forms, special cases for one and 2, 3, or 4
    00436      * Used in:
    00437      *   Czech */
    00438     case 10:
    00439       return n == 1 ? 0 : n >= 2 && n <= 4 ? 1 : 2;
    00440
    00441     /* Two forms, special 'hack' for Korean; singular for numbers ending
    00442      *   in a consonant and plural for numbers ending in a vowel.
    00443      * Korean doesn't have the concept of plural, but depending on how a
    00444      * number is pronounced it needs another version of a particle.
    00445      * As such the plural system is misused to give this distinction.
    00446      */
    00447     case 11:
    00448       switch (n % 10) {
    00449         case 0: // yeong
    00450         case 1: // il
    00451         case 3: // sam
    00452         case 6: // yuk
    00453         case 7: // chil
    00454         case 8: // pal
    00455           return 0;
    00456
    00457         case 2: // i
    00458         case 4: // sa
    00459         case 5: // o
    00460         case 9: // gu
    00461           return 1;
    00462
    00463         default:
    00464           NOT_REACHED();
    00465       }
    00466   }
    00467 }
    00468
    00469 static const char *ParseStringChoice(const char *b, uint form, char **dst, const char *last)
    00470 {
    00471   /* <NUM> {Length of each string} {each string} */
    00472   uint n = (byte)*b++;
    00473   uint pos, i, mypos = 0;
    00474
    00475   for (i = pos = 0; i != n; i++) {
    00476     uint len = (byte)*b++;
    00477     if (i == form) mypos = pos;
    00478     pos += len;
    00479   }
    00480
    00481   *dst += seprintf(*dst, last, "%s", b + mypos);
    00482   return b + pos;
    00483 }
    00484
    00485 struct Units {
    00486   int s_m;
    00487   int s_s;
    00488   StringID velocity;
    00489   int p_m;
    00490   int p_s;
    00491   StringID power;
    00492   int w_m;
    00493   int w_s;
    00494   StringID s_weight;
    00495   StringID l_weight;
    00496   int v_m;
    00497   int v_s;
    00498   StringID s_volume;
    00499   StringID l_volume;
    00500   int f_m;
    00501   int f_s;
    00502   StringID force;
    00503 };
    00504
    00505 /* Unit conversions */
    00506 static const Units units[] = {
    00507   { // Imperial (Original, mph, hp, metric ton, litre, kN)
    00508        1,  0, STR_UNITS_VELOCITY_IMPERIAL,
    00509        1,  0, STR_UNITS_POWER_IMPERIAL,
    00510        1,  0, STR_UNITS_WEIGHT_SHORT_METRIC, STR_UNITS_WEIGHT_LONG_METRIC,
    00511     1000,  0, STR_UNITS_VOLUME_SHORT_METRIC, STR_UNITS_VOLUME_LONG_METRIC,
    00512        1,  0, STR_UNITS_FORCE_SI,
    00513   },
    00514   { // Metric (km/h, hp, metric ton, litre, kN)
    00515      103,  6, STR_UNITS_VELOCITY_METRIC,
    00516        1,  0, STR_UNITS_POWER_METRIC,
    00517        1,  0, STR_UNITS_WEIGHT_SHORT_METRIC, STR_UNITS_WEIGHT_LONG_METRIC,
    00518     1000,  0, STR_UNITS_VOLUME_SHORT_METRIC, STR_UNITS_VOLUME_LONG_METRIC,
    00519        1,  0, STR_UNITS_FORCE_SI,
    00520   },
    00521   { // SI (m/s, kilowatt, kilogram, cubic metres, kilonewton)
    00522     1831, 12, STR_UNITS_VELOCITY_SI,
    00523      764, 10, STR_UNITS_POWER_SI,
    00524     1000,  0, STR_UNITS_WEIGHT_SHORT_SI, STR_UNITS_WEIGHT_LONG_SI,
    00525        1,  0, STR_UNITS_VOLUME_SHORT_SI, STR_UNITS_VOLUME_LONG_SI,
    00526        1,  0, STR_UNITS_FORCE_SI,
    00527   },
    00528 };
    00529
    00535 uint ConvertSpeedToDisplaySpeed(uint speed)
    00536 {
    00537   return (speed * units[_settings_game.locale.units].s_m) >> units[_settings_game.locale.units].s_s;
    00538 }
    00539
    00545 uint ConvertDisplaySpeedToSpeed(uint speed)
    00546 {
    00547   return ((speed << units[_settings_game.locale.units].s_s) + units[_settings_game.locale.units].s_m / 2) / units[_settings_game.locale.units].s_m;
    00548 }
    00549
    00550 static char *FormatString(char *buff, const char *str, int64 *argv, uint casei, const char *last)
    00551 {
    00552   WChar b;
    00553   int64 *argv_orig = argv;
    00554   uint modifier = 0;
    00555
    00556   while ((b = Utf8Consume(&str)) != '\0') {
    00557     if (SCC_NEWGRF_FIRST <= b && b <= SCC_NEWGRF_LAST) {
    00558       /* We need to pass some stuff as it might be modified; oh boy. */
    00559       b = RemapNewGRFStringControlCode(b, &buff, &str, argv);
    00560       if (b == 0) continue;
    00561     }
    00562
    00563     switch (b) {
    00564       case SCC_SETX: // {SETX}
    00565         if (buff + Utf8CharLen(SCC_SETX) + 1 < last) {
    00566           buff += Utf8Encode(buff, SCC_SETX);
    00567           *buff++ = *str++;
    00568         }
    00569         break;
    00570
    00571       case SCC_SETXY: // {SETXY}
    00572         if (buff + Utf8CharLen(SCC_SETXY) + 2 < last) {
    00573           buff += Utf8Encode(buff, SCC_SETXY);
    00574           *buff++ = *str++;
    00575           *buff++ = *str++;
    00576         }
    00577         break;
    00578
    00579       case SCC_STRING_ID: // {STRINL}
    00580         buff = GetStringWithArgs(buff, Utf8Consume(&str), argv, last);
    00581         break;
    00582
    00583       case SCC_RAW_STRING_POINTER: { // {RAW_STRING}
    00584         const char *str = (const char*)(size_t)GetInt64(&argv);
    00585         buff = FormatString(buff, str, argv, casei, last);
    00586         break;
    00587       }
    00588
    00589       case SCC_DATE_LONG: // {DATE_LONG}
    00590         buff = FormatYmdString(buff, GetInt32(&argv), last);
    00591         break;
    00592
    00593       case SCC_DATE_SHORT: // {DATE_SHORT}
    00594         buff = FormatMonthAndYear(buff, GetInt32(&argv), last);
    00595         break;
    00596
    00597       case SCC_VELOCITY: {// {VELOCITY}
    00598         int64 args[1];
    00599         assert(_settings_game.locale.units < lengthof(units));
    00600         args[0] = ConvertSpeedToDisplaySpeed(GetInt32(&argv) * 10 / 16);
    00601         buff = FormatString(buff, GetStringPtr(units[_settings_game.locale.units].velocity), args, modifier >> 24, last);
    00602         modifier = 0;
    00603         break;
    00604       }
    00605
    00606       case SCC_CURRENCY_COMPACT: // {CURRCOMPACT}
    00607         buff = FormatGenericCurrency(buff, _currency, GetInt64(&argv), true, last);
    00608         break;
    00609
    00610       case SCC_REVISION: // {REV}
    00611         buff = strecpy(buff, _openttd_revision, last);
    00612         break;
    00613
    00614       case SCC_CARGO_SHORT: { // {SHORTCARGO}
    00615         /* Short description of cargotypes. Layout:
    00616          * 8-bit = cargo type
    00617          * 16-bit = cargo count */
    00618         StringID cargo_str = CargoSpec::Get(GetInt32(&argv))->units_volume;
    00619         switch (cargo_str) {
    00620           case STR_TONS: {
    00621             int64 args[1];
    00622             assert(_settings_game.locale.units < lengthof(units));
    00623             args[0] = GetInt32(&argv) * units[_settings_game.locale.units].w_m >> units[_settings_game.locale.units].w_s;
    00624             buff = FormatString(buff, GetStringPtr(units[_settings_game.locale.units].l_weight), args, modifier >> 24, last);
    00625             modifier = 0;
    00626             break;
    00627           }
    00628
    00629           case STR_LITERS: {
    00630             int64 args[1];
    00631             assert(_settings_game.locale.units < lengthof(units));
    00632             args[0] = GetInt32(&argv) * units[_settings_game.locale.units].v_m >> units[_settings_game.locale.units].v_s;
    00633             buff = FormatString(buff, GetStringPtr(units[_settings_game.locale.units].l_volume), args, modifier >> 24, last);
    00634             modifier = 0;
    00635             break;
    00636           }
    00637
    00638           default:
    00639             if (cargo_str >= 0xE000 && cargo_str < 0xF800) {
    00640               /* NewGRF strings from Action 4 use a different format here,
    00641                * of e.g. "x tonnes of coal", so process accordingly. */
    00642               buff = GetStringWithArgs(buff, cargo_str, argv++, last);
    00643             } else {
    00644               buff = FormatCommaNumber(buff, GetInt32(&argv), last);
    00645               buff = strecpy(buff, " ", last);
    00646               buff = strecpy(buff, GetStringPtr(cargo_str), last);
    00647             }
    00648             break;
    00649         }
    00650       } break;
    00651
    00652       case SCC_STRING1: { // {STRING1}
    00653         /* String that consumes ONE argument */
    00654         uint str = modifier + GetInt32(&argv);
    00655         buff = GetStringWithArgs(buff, str, GetArgvPtr(&argv, 1), last);
    00656         modifier = 0;
    00657         break;
    00658       }
    00659
    00660       case SCC_STRING2: { // {STRING2}
    00661         /* String that consumes TWO arguments */
    00662         uint str = modifier + GetInt32(&argv);
    00663         buff = GetStringWithArgs(buff, str, GetArgvPtr(&argv, 2), last);
    00664         modifier = 0;
    00665         break;
    00666       }
    00667
    00668       case SCC_STRING3: { // {STRING3}
    00669         /* String that consumes THREE arguments */
    00670         uint str = modifier + GetInt32(&argv);
    00671         buff = GetStringWithArgs(buff, str, GetArgvPtr(&argv, 3), last);
    00672         modifier = 0;
    00673         break;
    00674       }
    00675
    00676       case SCC_STRING4: { // {STRING4}
    00677         /* String that consumes FOUR arguments */
    00678         uint str = modifier + GetInt32(&argv);
    00679         buff = GetStringWithArgs(buff, str, GetArgvPtr(&argv, 4), last);
    00680         modifier = 0;
    00681         break;
    00682       }
    00683
    00684       case SCC_STRING5: { // {STRING5}
    00685         /* String that consumes FIVE arguments */
    00686         uint str = modifier + GetInt32(&argv);
    00687         buff = GetStringWithArgs(buff, str, GetArgvPtr(&argv, 5), last);
    00688         modifier = 0;
    00689         break;
    00690       }
    00691
    00692       case SCC_STATION_FEATURES: { // {STATIONFEATURES}
    00693         buff = StationGetSpecialString(buff, GetInt32(&argv), last);
    00694         break;
    00695       }
    00696
    00697       case SCC_INDUSTRY_NAME: { // {INDUSTRY}
    00698         const Industry *i = Industry::Get(GetInt32(&argv));
    00699         int64 args[2];
    00700
    00701         /* industry not valid anymore? */
    00702         assert(i != NULL);
    00703
    00704         /* First print the town name and the industry type name. */
    00705         args[0] = i->town->index;
    00706         args[1] = GetIndustrySpec(i->type)->name;
    00707         buff = FormatString(buff, GetStringPtr(STR_FORMAT_INDUSTRY_NAME), args, modifier >> 24, last);
    00708         modifier = 0;
    00709         break;
    00710       }
    00711
    00712       case SCC_VOLUME: { // {VOLUME}
    00713         int64 args[1];
    00714         assert(_settings_game.locale.units < lengthof(units));
    00715         args[0] = GetInt32(&argv) * units[_settings_game.locale.units].v_m >> units[_settings_game.locale.units].v_s;
    00716         buff = FormatString(buff, GetStringPtr(units[_settings_game.locale.units].l_volume), args, modifier >> 24, last);
    00717         modifier = 0;
    00718         break;
    00719       }
    00720
    00721       case SCC_GENDER_LIST: { // {G 0 Der Die Das}
    00722         /* First read the meta data from the language file. */
    00723         WChar fmt = SCC_CONTROL_START + (byte)*str++;
    00724         byte offset = (byte)*str++;
    00725
    00726         /* Now we need to figure out what text to resolve, i.e.
    00727          * what do we need to draw? So get the actual raw string
    00728          * first using the control code to get said string. */
    00729         char input[4 + 1];
    00730         char *p = input + Utf8Encode(input, fmt);
    00731         *p = '\0';
    00732
    00733         /* Now do the string formatting. */
    00734         char buf[256];
    00735         bool old_kgd = _keep_gender_data;
    00736         _keep_gender_data = true;
    00737         p = FormatString(buf, input, argv_orig + offset, 0, lastof(buf));
    00738         _keep_gender_data = old_kgd;
    00739         *p = '\0';
    00740
    00741         /* And determine the string. */
    00742         int gender = 0;
    00743         const char *s = buf;
    00744         WChar c = Utf8Consume(&s);
    00745         /* Does this string have a gender, if so, set it */
    00746         if (c == SCC_GENDER_INDEX) gender = (byte)s[0];
    00747         str = ParseStringChoice(str, gender, &buff, last);
    00748         break;
    00749       }
    00750
    00751       case SCC_DATE_TINY: { // {DATE_TINY}
    00752         buff = FormatTinyOrISODate(buff, GetInt32(&argv), STR_FORMAT_DATE_TINY, last);
    00753         break;
    00754       }
    00755
    00756       case SCC_DATE_ISO: { // {DATE_ISO}
    00757         buff = FormatTinyOrISODate(buff, GetInt32(&argv), STR_FORMAT_DATE_ISO, last);
    00758         break;
    00759       }
    00760
    00761       case SCC_CARGO: { // {CARGO}
    00762         /* First parameter is cargo type, second parameter is cargo count */
    00763         CargoID cargo = GetInt32(&argv);
    00764         StringID cargo_str = (cargo == CT_INVALID) ? STR_QUANTITY_N_A : CargoSpec::Get(cargo)->quantifier;
    00765         buff = GetStringWithArgs(buff, cargo_str, argv++, last);
    00766         break;
    00767       }
    00768
    00769       case SCC_POWER: { // {POWER}
    00770         int64 args[1];
    00771         assert(_settings_game.locale.units < lengthof(units));
    00772         args[0] = GetInt32(&argv) * units[_settings_game.locale.units].p_m >> units[_settings_game.locale.units].p_s;
    00773         buff = FormatString(buff, GetStringPtr(units[_settings_game.locale.units].power), args, modifier >> 24, last);
    00774         modifier = 0;
    00775         break;
    00776       }
    00777
    00778       case SCC_VOLUME_SHORT: { // {VOLUME_S}
    00779         int64 args[1];
    00780         assert(_settings_game.locale.units < lengthof(units));
    00781         args[0] = GetInt32(&argv) * units[_settings_game.locale.units].v_m >> units[_settings_game.locale.units].v_s;
    00782         buff = FormatString(buff, GetStringPtr(units[_settings_game.locale.units].s_volume), args, modifier >> 24, last);
    00783         modifier = 0;
    00784         break;
    00785       }
    00786
    00787       case SCC_WEIGHT: { // {WEIGHT}
    00788         int64 args[1];
    00789         assert(_settings_game.locale.units < lengthof(units));
    00790         args[0] = GetInt32(&argv) * units[_settings_game.locale.units].w_m >> units[_settings_game.locale.units].w_s;
    00791         buff = FormatString(buff, GetStringPtr(units[_settings_game.locale.units].l_weight), args, modifier >> 24, last);
    00792         modifier = 0;
    00793         break;
    00794       }
    00795
    00796       case SCC_WEIGHT_SHORT: { // {WEIGHT_S}
    00797         int64 args[1];
    00798         assert(_settings_game.locale.units < lengthof(units));
    00799         args[0] = GetInt32(&argv) * units[_settings_game.locale.units].w_m >> units[_settings_game.locale.units].w_s;
    00800         buff = FormatString(buff, GetStringPtr(units[_settings_game.locale.units].s_weight), args, modifier >> 24, last);
    00801         modifier = 0;
    00802         break;
    00803       }
    00804
    00805       case SCC_FORCE: { // {FORCE}
    00806         int64 args[1];
    00807         assert(_settings_game.locale.units < lengthof(units));
    00808         args[0] = GetInt32(&argv) * units[_settings_game.locale.units].f_m >> units[_settings_game.locale.units].f_s;
    00809         buff = FormatString(buff, GetStringPtr(units[_settings_game.locale.units].force), args, modifier >> 24, last);
    00810         modifier = 0;
    00811         break;
    00812       }
    00813
    00814       /* This sets up the gender for the string.
    00815        * We just ignore this one. It's used in {G 0 Der Die Das} to determine the case. */
    00816       case SCC_GENDER_INDEX: // {GENDER 0}
    00817         if (_keep_gender_data) {
    00818           buff += Utf8Encode(buff, SCC_GENDER_INDEX);
    00819           *buff++ = *str++;
    00820         } else {
    00821           str++;
    00822         }
    00823         break;
    00824
    00825       case SCC_STRING: {// {STRING}
    00826         uint str = modifier + GetInt32(&argv);
    00827         /* WARNING. It's prohibited for the included string to consume any arguments.
    00828          * For included strings that consume argument, you should use STRING1, STRING2 etc.
    00829          * To debug stuff you can set argv to NULL and it will tell you */
    00830         buff = GetStringWithArgs(buff, str, argv, last);
    00831         modifier = 0;
    00832         break;
    00833       }
    00834
    00835       case SCC_COMMA: // {COMMA}
    00836         buff = FormatCommaNumber(buff, GetInt64(&argv), last);
    00837         break;
    00838
    00839       case SCC_ARG_INDEX: // Move argument pointer
    00840         argv = argv_orig + (byte)*str++;
    00841         break;
    00842
    00843       case SCC_PLURAL_LIST: { // {P}
    00844         int64 v = argv_orig[(byte)*str++]; // contains the number that determines plural
    00845         str = ParseStringChoice(str, DeterminePluralForm(v), &buff, last);
    00846         break;
    00847       }
    00848
    00849       case SCC_NUM: // {NUM}
    00850         buff = FormatNoCommaNumber(buff, GetInt64(&argv), last);
    00851         break;
    00852
    00853       case SCC_ZEROFILL_NUM: { // {ZEROFILL_NUM}
    00854         int64 num = GetInt64(&argv);
    00855         buff = FormatZerofillNumber(buff, num, GetInt64(&argv), last);
    00856       } break;
    00857
    00858       case SCC_HEX: // {HEX}
    00859         buff = FormatHexNumber(buff, GetInt64(&argv), last);
    00860         break;
    00861
    00862       case SCC_BYTES: // {BYTES}
    00863         buff = FormatBytes(buff, GetInt64(&argv), last);
    00864         break;
    00865
    00866       case SCC_CURRENCY: // {CURRENCY}
    00867         buff = FormatGenericCurrency(buff, _currency, GetInt64(&argv), false, last);
    00868         break;
    00869
    00870       case SCC_WAYPOINT_NAME: { // {WAYPOINT}
    00871         Waypoint *wp = Waypoint::Get(GetInt32(&argv));
    00872
    00873         assert(wp != NULL);
    00874
    00875         if (wp->name != NULL) {
    00876           buff = strecpy(buff, wp->name, last);
    00877         } else {
    00878           int64 temp[2];
    00879           temp[0] = wp->town->index;
    00880           temp[1] = wp->town_cn + 1;
    00881           StringID str = ((wp->string_id == STR_SV_STNAME_BUOY) ? STR_FORMAT_BUOY_NAME : STR_FORMAT_WAYPOINT_NAME);
    00882           if (wp->town_cn != 0) str++;
    00883           buff = GetStringWithArgs(buff, str, temp, last);
    00884         }
    00885         break;
    00886       }
    00887
    00888       case SCC_STATION_NAME: { // {STATION}
    00889         StationID sid = GetInt32(&argv);
    00890         const Station *st = Station::GetIfValid(sid);
    00891
    00892         if (st == NULL) {
    00893           /* The station doesn't exist anymore. The only place where we might
    00894            * be "drawing" an invalid station is in the case of cargo that is
    00895            * in transit. */
    00896           buff = GetStringWithArgs(buff, STR_UNKNOWN_STATION, NULL, last);
    00897           break;
    00898         }
    00899
    00900         if (st->name != NULL) {
    00901           buff = strecpy(buff, st->name, last);
    00902         } else {
    00903           StringID str = st->string_id;
    00904           if (st->indtype != IT_INVALID) {
    00905             /* Special case where the industry provides the name for the station */
    00906             const IndustrySpec *indsp = GetIndustrySpec(st->indtype);
    00907
    00908             /* Industry GRFs can change which might remove the station name and
    00909              * thus cause very strange things. Here we check for that before we
    00910              * actually set the station name. */
    00911             if (indsp->station_name != STR_NULL && indsp->station_name != STR_UNDEFINED) {
    00912               str = indsp->station_name;
    00913             }
    00914           }
    00915
    00916           int64 temp[3];
    00917           temp[0] = STR_TOWN_NAME;
    00918           temp[1] = st->town->index;
    00919           temp[2] = st->index;
    00920           buff = GetStringWithArgs(buff, str, temp, last);
    00921         }
    00922         break;
    00923       }
    00924
    00925       case SCC_TOWN_NAME: { // {TOWN}
    00926         const Town *t = Town::Get(GetInt32(&argv));
    00927
    00928         assert(t != NULL);
    00929
    00930         if (t->name != NULL) {
    00931           buff = strecpy(buff, t->name, last);
    00932         } else {
    00933           buff = GetTownName(buff, t, last);
    00934         }
    00935         break;
    00936       }
    00937
    00938       case SCC_GROUP_NAME: { // {GROUP}
    00939         const Group *g = Group::Get(GetInt32(&argv));
    00940
    00941         assert(g != NULL);
    00942
    00943         if (g->name != NULL) {
    00944           buff = strecpy(buff, g->name, last);
    00945         } else {
    00946           int64 args[1];
    00947
    00948           args[0] = g->index;
    00949           buff = GetStringWithArgs(buff, STR_FORMAT_GROUP_NAME, args, last);
    00950         }
    00951         break;
    00952       }
    00953
    00954       case SCC_ENGINE_NAME: { // {ENGINE}
    00955         EngineID engine = (EngineID)GetInt32(&argv);
    00956         const Engine *e = Engine::Get(engine);
    00957
    00958         assert(e != NULL);
    00959
    00960         if (e->name != NULL) {
    00961           buff = strecpy(buff, e->name, last);
    00962         } else {
    00963           buff = GetStringWithArgs(buff, e->info.string_id, NULL, last);
    00964         }
    00965         break;
    00966       }
    00967
    00968       case SCC_VEHICLE_NAME: { // {VEHICLE}
    00969         const Vehicle *v = Vehicle::Get(GetInt32(&argv));
    00970
    00971         assert(v != NULL);
    00972
    00973         if (v->name != NULL) {
    00974           buff = strecpy(buff, v->name, last);
    00975         } else {
    00976           int64 args[1];
    00977           args[0] = v->unitnumber;
    00978
    00979           StringID str;
    00980           switch (v->type) {
    00981             default: NOT_REACHED();
    00982             case VEH_TRAIN:    str = STR_SV_TRAIN_NAME; break;
    00983             case VEH_ROAD:     str = STR_SV_ROAD_VEHICLE_NAME; break;
    00984             case VEH_SHIP:     str = STR_SV_SHIP_NAME; break;
    00985             case VEH_AIRCRAFT: str = STR_SV_AIRCRAFT_NAME; break;
    00986           }
    00987
    00988           buff = GetStringWithArgs(buff, str, args, last);
    00989         }
    00990         break;
    00991       }
    00992
    00993       case SCC_SIGN_NAME: { // {SIGN}
    00994         const Sign *si = Sign::Get(GetInt32(&argv));
    00995         if (si->name != NULL) {
    00996           buff = strecpy(buff, si->name, last);
    00997         } else {
    00998           buff = GetStringWithArgs(buff, STR_DEFAULT_SIGN_NAME, NULL, last);
    00999         }
    01000         break;
    01001       }
    01002
    01003       case SCC_COMPANY_NAME: { // {COMPANY}
    01004         const Company *c = Company::Get((CompanyID)GetInt32(&argv));
    01005
    01006         if (c->name != NULL) {
    01007           buff = strecpy(buff, c->name, last);
    01008         } else {
    01009           int64 args[1];
    01010           args[0] = c->name_2;
    01011           buff = GetStringWithArgs(buff, c->name_1, args, last);
    01012         }
    01013         break;
    01014       }
    01015
    01016       case SCC_COMPANY_NUM: { // {COMPANYNUM}
    01017         CompanyID company = (CompanyID)GetInt32(&argv);
    01018
    01019         /* Nothing is added for AI or inactive companies */
    01020         if (Company::IsValidHumanID(company)) {
    01021           int64 args[1];
    01022           args[0] = company + 1;
    01023           buff = GetStringWithArgs(buff, STR_FORMAT_COMPANY_NUM, args, last);
    01024         }
    01025         break;
    01026       }
    01027
    01028       case SCC_PRESIDENT_NAME: { // {PRESIDENTNAME}
    01029         const Company *c = Company::Get((CompanyID)GetInt32(&argv));
    01030
    01031         if (c->president_name != NULL) {
    01032           buff = strecpy(buff, c->president_name, last);
    01033         } else {
    01034           int64 args[1];
    01035           args[0] = c->president_name_2;
    01036           buff = GetStringWithArgs(buff, c->president_name_1, args, last);
    01037         }
    01038         break;
    01039       }
    01040
    01041       case SCC_SETCASE: { // {SETCASE}
    01042         /* This is a pseudo command, it's outputted when someone does {STRING.ack}
    01043          * The modifier is added to all subsequent GetStringWithArgs that accept the modifier. */
    01044         modifier = (byte)*str++ << 24;
    01045         break;
    01046       }
    01047
    01048       case SCC_SWITCH_CASE: { // {Used to implement case switching}
    01049         /* <0x9E> <NUM CASES> <CASE1> <LEN1> <STRING1> <CASE2> <LEN2> <STRING2> <CASE3> <LEN3> <STRING3> <STRINGDEFAULT>
    01050          * Each LEN is printed using 2 bytes in big endian order. */
    01051         uint num = (byte)*str++;
    01052         while (num) {
    01053           if ((byte)str[0] == casei) {
    01054             /* Found the case, adjust str pointer and continue */
    01055             str += 3;
    01056             break;
    01057           }
    01058           /* Otherwise skip to the next case */
    01059           str += 3 + (str[1] << 8) + str[2];
    01060           num--;
    01061         }
    01062         break;
    01063       }
    01064
    01065       default:
    01066         if (buff + Utf8CharLen(b) < last) buff += Utf8Encode(buff, b);
    01067         break;
    01068     }
    01069   }
    01070   *buff = '\0';
    01071   return buff;
    01072 }
    01073
    01074
    01075 static char *StationGetSpecialString(char *buff, int x, const char *last)
    01076 {
    01077   if ((x & FACIL_TRAIN)      && (buff + Utf8CharLen(SCC_TRAIN) < last)) buff += Utf8Encode(buff, SCC_TRAIN);
    01078   if ((x & FACIL_TRUCK_STOP) && (buff + Utf8CharLen(SCC_LORRY) < last)) buff += Utf8Encode(buff, SCC_LORRY);
    01079   if ((x & FACIL_BUS_STOP)   && (buff + Utf8CharLen(SCC_BUS)   < last)) buff += Utf8Encode(buff, SCC_BUS);
    01080   if ((x & FACIL_AIRPORT)    && (buff + Utf8CharLen(SCC_PLANE) < last)) buff += Utf8Encode(buff, SCC_PLANE);
    01081   if ((x & FACIL_DOCK)       && (buff + Utf8CharLen(SCC_SHIP)  < last)) buff += Utf8Encode(buff, SCC_SHIP);
    01082   *buff = '\0';
    01083   return buff;
    01084 }
    01085
    01086 static char *GetSpecialTownNameString(char *buff, int ind, uint32 seed, const char *last)
    01087 {
    01088   return GenerateTownNameString(buff, last, ind, seed);
    01089 }
    01090
    01091 static const char * const _silly_company_names[] = {
    01092   "Bloggs Brothers",
    01093   "Tiny Transport Ltd.",
    01094   "Express Travel",
    01095   "Comfy-Coach & Co.",
    01096   "Crush & Bump Ltd.",
    01097   "Broken & Late Ltd.",
    01098   "Sam Speedy & Son",
    01099   "Supersonic Travel",
    01100   "Mike's Motors",
    01101   "Lightning International",
    01102   "Pannik & Loozit Ltd.",
    01103   "Inter-City Transport",
    01104   "Getout & Pushit Ltd."
    01105 };
    01106
    01107 static const char * const _surname_list[] = {
    01108   "Adams",
    01109   "Allan",
    01110   "Baker",
    01111   "Bigwig",
    01112   "Black",
    01113   "Bloggs",
    01114   "Brown",
    01115   "Campbell",
    01116   "Gordon",
    01117   "Hamilton",
    01118   "Hawthorn",
    01119   "Higgins",
    01120   "Green",
    01121   "Gribble",
    01122   "Jones",
    01123   "McAlpine",
    01124   "MacDonald",
    01125   "McIntosh",
    01126   "Muir",
    01127   "Murphy",
    01128   "Nelson",
    01129   "O'Donnell",
    01130   "Parker",
    01131   "Phillips",
    01132   "Pilkington",
    01133   "Quigley",
    01134   "Sharkey",
    01135   "Thomson",
    01136   "Watkins"
    01137 };
    01138
    01139 static const char * const _silly_surname_list[] = {
    01140   "Grumpy",
    01141   "Dozy",
    01142   "Speedy",
    01143   "Nosey",
    01144   "Dribble",
    01145   "Mushroom",
    01146   "Cabbage",
    01147   "Sniffle",
    01148   "Fishy",
    01149   "Swindle",
    01150   "Sneaky",
    01151   "Nutkins"
    01152 };
    01153
    01154 static const char _initial_name_letters[] = {
    01155   'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
    01156   'K', 'L', 'M', 'N', 'P', 'R', 'S', 'T', 'W',
    01157 };
    01158
    01159 static char *GenAndCoName(char *buff, uint32 arg, const char *last)
    01160 {
    01161   const char * const *base;
    01162   uint num;
    01163
    01164   if (_settings_game.game_creation.landscape == LT_TOYLAND) {
    01165     base = _silly_surname_list;
    01166     num  = lengthof(_silly_surname_list);
    01167   } else {
    01168     base = _surname_list;
    01169     num  = lengthof(_surname_list);
    01170   }
    01171
    01172   buff = strecpy(buff, base[num * GB(arg, 16, 8) >> 8], last);
    01173   buff = strecpy(buff, " & Co.", last);
    01174
    01175   return buff;
    01176 }
    01177
    01178 static char *GenPresidentName(char *buff, uint32 x, const char *last)
    01179 {
    01180   char initial[] = "?. ";
    01181   const char * const *base;
    01182   uint num;
    01183   uint i;
    01184
    01185   initial[0] = _initial_name_letters[sizeof(_initial_name_letters) * GB(x, 0, 8) >> 8];
    01186   buff = strecpy(buff, initial, last);
    01187
    01188   i = (sizeof(_initial_name_letters) + 35) * GB(x, 8, 8) >> 8;
    01189   if (i < sizeof(_initial_name_letters)) {
    01190     initial[0] = _initial_name_letters[i];
    01191     buff = strecpy(buff, initial, last);
    01192   }
    01193
    01194   if (_settings_game.game_creation.landscape == LT_TOYLAND) {
    01195     base = _silly_surname_list;
    01196     num  = lengthof(_silly_surname_list);
    01197   } else {
    01198     base = _surname_list;
    01199     num  = lengthof(_surname_list);
    01200   }
    01201
    01202   buff = strecpy(buff, base[num * GB(x, 16, 8) >> 8], last);
    01203
    01204   return buff;
    01205 }
    01206
    01207 static char *GetSpecialNameString(char *buff, int ind, int64 *argv, const char *last)
    01208 {
    01209   switch (ind) {
    01210     case 1: // not used
    01211       return strecpy(buff, _silly_company_names[GetInt32(&argv) & 0xFFFF], last);
    01212
    01213     case 2: // used for Foobar & Co company names
    01214       return GenAndCoName(buff, GetInt32(&argv), last);
    01215
    01216     case 3: // President name
    01217       return GenPresidentName(buff, GetInt32(&argv), last);
    01218   }
    01219
    01220   /* town name? */
    01221   if (IsInsideMM(ind - 6, 0, SPECSTR_TOWNNAME_LAST - SPECSTR_TOWNNAME_START + 1)) {
    01222     buff = GetSpecialTownNameString(buff, ind - 6, GetInt32(&argv), last);
    01223     return strecpy(buff, " Transport", last);
    01224   }
    01225
    01226   /* language name? */
    01227   if (IsInsideMM(ind, (SPECSTR_LANGUAGE_START - 0x70E4), (SPECSTR_LANGUAGE_END - 0x70E4) + 1)) {
    01228     int i = ind - (SPECSTR_LANGUAGE_START - 0x70E4);
    01229     return strecpy(buff,
    01230       i == _dynlang.curr ? _langpack->own_name : _dynlang.ent[i].name, last);
    01231   }
    01232
    01233   /* resolution size? */
    01234   if (IsInsideMM(ind, (SPECSTR_RESOLUTION_START - 0x70E4), (SPECSTR_RESOLUTION_END - 0x70E4) + 1)) {
    01235     int i = ind - (SPECSTR_RESOLUTION_START - 0x70E4);
    01236     buff += seprintf(
    01237       buff, last, "%ux%u", _resolutions[i].width, _resolutions[i].height
    01238     );
    01239     return buff;
    01240   }
    01241
    01242   /* screenshot format name? */
    01243   if (IsInsideMM(ind, (SPECSTR_SCREENSHOT_START - 0x70E4), (SPECSTR_SCREENSHOT_END - 0x70E4) + 1)) {
    01244     int i = ind - (SPECSTR_SCREENSHOT_START - 0x70E4);
    01245     return strecpy(buff, GetScreenshotFormatDesc(i), last);
    01246   }
    01247
    01248   NOT_REACHED();
    01249 }
    01250
    01251 #ifdef ENABLE_NETWORK
    01252 extern void SortNetworkLanguages();
    01253 #else /* ENABLE_NETWORK */
    01254 static inline void SortNetworkLanguages() {}
    01255 #endif /* ENABLE_NETWORK */
    01256
    01257 bool ReadLanguagePack(int lang_index)
    01258 {
    01259   /* Current language pack */
    01260   size_t len;
    01261   LanguagePack *lang_pack = (LanguagePack *)ReadFileToMem(_dynlang.ent[lang_index].file, &len, 200000);
    01262   if (lang_pack == NULL) return false;
    01263
    01264   /* End of read data (+ terminating zero added in ReadFileToMem()) */
    01265   const char *end = (char *)lang_pack + len + 1;
    01266
    01267   /* We need at least one byte of lang_pack->data */
    01268   if (end <= lang_pack->data ||
    01269       lang_pack->ident != TO_LE32(LANGUAGE_PACK_IDENT) ||
    01270       lang_pack->version != TO_LE32(LANGUAGE_PACK_VERSION)) {
    01271     free(lang_pack);
    01272     return false;
    01273   }
    01274
    01275 #if TTD_ENDIAN == TTD_BIG_ENDIAN
    01276   for (uint i = 0; i < 32; i++) {
    01277     lang_pack->offsets[i] = ReadLE16Aligned(&lang_pack->offsets[i]);
    01278   }
    01279 #endif /* TTD_ENDIAN == TTD_BIG_ENDIAN */
    01280
    01281   uint count = 0;
    01282   for (uint i = 0; i < 32; i++) {
    01283     uint num = lang_pack->offsets[i];
    01284     _langtab_start[i] = count;
    01285     _langtab_num[i] = num;
    01286     count += num;
    01287   }
    01288
    01289   /* Allocate offsets */
    01290   char **langpack_offs = MallocT<char *>(count);
    01291
    01292   /* Fill offsets */
    01293   char *s = lang_pack->data;
    01294   len = (byte)*s++;
    01295   for (uint i = 0; i < count; i++) {
    01296     if (s + len >= end) {
    01297       free(lang_pack);
    01298       free(langpack_offs);
    01299       return false;
    01300     }
    01301     if (len >= 0xC0) {
    01302       len = ((len & 0x3F) << 8) + (byte)*s++;
    01303       if (s + len >= end) {
    01304         free(lang_pack);
    01305         free(langpack_offs);
    01306         return false;
    01307       }
    01308     }
    01309     langpack_offs[i] = s;
    01310     s += len;
    01311     len = (byte)*s;
    01312     *s++ = '\0'; // zero terminate the string
    01313   }
    01314
    01315   free(_langpack);
    01316   _langpack = lang_pack;
    01317
    01318   free(_langpack_offs);
    01319   _langpack_offs = langpack_offs;
    01320
    01321   const char *c_file = strrchr(_dynlang.ent[lang_index].file, PATHSEPCHAR) + 1;
    01322   strecpy(_dynlang.curr_file, c_file, lastof(_dynlang.curr_file));
    01323
    01324   _dynlang.curr = lang_index;
    01325   _dynlang.text_dir = (TextDirection)lang_pack->text_dir;
    01326   SetCurrentGrfLangID(_langpack->newgrflangid);
    01327   SortNetworkLanguages();
    01328   return true;
    01329 }
    01330
    01331 /* Win32 implementation in win32.cpp.
    01332  * OS X implementation in os/macosx/macos.mm. */
    01333 #if !(defined(WIN32) || defined(__APPLE__))
    01334
    01340 const char *GetCurrentLocale(const char *param)
    01341 {
    01342   const char *env;
    01343
    01344   env = getenv("LANGUAGE");
    01345   if (env != NULL) return env;
    01346
    01347   env = getenv("LC_ALL");
    01348   if (env != NULL) return env;
    01349
    01350   if (param != NULL) {
    01351     env = getenv(param);
    01352     if (env != NULL) return env;
    01353   }
    01354
    01355   return getenv("LANG");
    01356 }
    01357 #else
    01358 const char *GetCurrentLocale(const char *param);
    01359 #endif /* !(defined(WIN32) || defined(__APPLE__)) */
    01360
    01361 int CDECL StringIDSorter(const StringID *a, const StringID *b)
    01362 {
    01363   char stra[512];
    01364   char strb[512];
    01365   GetString(stra, *a, lastof(stra));
    01366   GetString(strb, *b, lastof(strb));
    01367
    01368   return strcmp(stra, strb);
    01369 }
    01370
    01378 static bool UniqueLanguageFile(const Language *langs, uint max, const char *language)
    01379 {
    01380   for (uint i = 0; i < max; i++) {
    01381     const char *f_name = strrchr(langs[i].file, PATHSEPCHAR) + 1;
    01382     if (strcmp(f_name, language) == 0) return false; // duplicates
    01383   }
    01384
    01385   return true;
    01386 }
    01387
    01394 static bool GetLanguageFileHeader(const char *file, LanguagePack *hdr)
    01395 {
    01396   FILE *f = fopen(file, "rb");
    01397   if (f == NULL) return false;
    01398
    01399   size_t read = fread(hdr, sizeof(*hdr), 1, f);
    01400   fclose(f);
    01401
    01402   bool ret = read == 1 &&
    01403       hdr->ident == TO_LE32(LANGUAGE_PACK_IDENT) &&
    01404       hdr->version == TO_LE32(LANGUAGE_PACK_VERSION);
    01405
    01406   /* Convert endianness for the windows language ID */
    01407   if (ret) hdr->winlangid = FROM_LE16(hdr->winlangid);
    01408   return ret;
    01409 }
    01410
    01419 static int GetLanguageList(Language *langs, int start, int max, const char *path)
    01420 {
    01421   int i = start;
    01422
    01423   DIR *dir = ttd_opendir(path);
    01424   if (dir != NULL) {
    01425     struct dirent *dirent;
    01426     while ((dirent = readdir(dir)) != NULL && i < max) {
    01427       const char *d_name    = FS2OTTD(dirent->d_name);
    01428       const char *extension = strrchr(d_name, '.');
    01429
    01430       /* Not a language file */
    01431       if (extension == NULL || strcmp(extension, ".lng") != 0) continue;
    01432
    01433       /* Filter any duplicate language-files, first-come first-serve */
    01434       if (!UniqueLanguageFile(langs, i, d_name)) continue;
    01435
    01436       langs[i].file = str_fmt("%s%s", path, d_name);
    01437
    01438       /* Check whether the file is of the correct version */
    01439       LanguagePack hdr;
    01440       if (!GetLanguageFileHeader(langs[i].file, &hdr)) {
    01441         free(langs[i].file);
    01442         continue;
    01443       }
    01444
    01445       i++;
    01446     }
    01447     closedir(dir);
    01448   }
    01449   return i - start;
    01450 }
    01451
    01456 void InitializeLanguagePacks()
    01457 {
    01458   Searchpath sp;
    01459   Language files[MAX_LANG];
    01460   uint language_count = 0;
    01461
    01462   FOR_ALL_SEARCHPATHS(sp) {
    01463     char path[MAX_PATH];
    01464     FioAppendDirectory(path, lengthof(path), sp, LANG_DIR);
    01465     language_count += GetLanguageList(files, language_count, lengthof(files), path);
    01466   }
    01467   if (language_count == 0) usererror("No available language packs (invalid versions?)");
    01468
    01469   /* Acquire the locale of the current system */
    01470   const char *lang = GetCurrentLocale("LC_MESSAGES");
    01471   if (lang == NULL) lang = "en_GB";
    01472
    01473   int chosen_language   = -1;
    01474   int language_fallback = -1;
    01475   int en_GB_fallback    =  0;
    01476
    01477   DynamicLanguages *dl = &_dynlang;
    01478   dl->num = 0;
    01479   /* Fill the dynamic languages structures */
    01480   for (uint i = 0; i < language_count; i++) {
    01481     /* File read the language header */
    01482     LanguagePack hdr;
    01483     if (!GetLanguageFileHeader(files[i].file, &hdr)) continue;
    01484
    01485     dl->ent[dl->num].file = files[i].file;
    01486     dl->ent[dl->num].name = strdup(hdr.name);
    01487
    01488     /* We are trying to find a default language. The priority is by
    01489      * configuration file, local environment and last, if nothing found,
    01490      * english. If def equals -1, we have not picked a default language */
    01491     const char *lang_file = strrchr(dl->ent[dl->num].file, PATHSEPCHAR) + 1;
    01492     if (strcmp(lang_file, dl->curr_file) == 0) chosen_language = dl->num;
    01493
    01494     if (chosen_language == -1) {
    01495       if (strcmp (hdr.isocode, "en_GB") == 0) en_GB_fallback    = dl->num;
    01496       if (strncmp(hdr.isocode, lang, 5) == 0) chosen_language   = dl->num;
    01497       if (strncmp(hdr.isocode, lang, 2) == 0) language_fallback = dl->num;
    01498     }
    01499
    01500     dl->num++;
    01501   }
    01502
    01503   if (dl->num == 0) usererror("Invalid version of language packs");
    01504
    01505   /* We haven't found the language in the config nor the one in the locale.
    01506    * Now we set it to one of the fallback languages */
    01507   if (chosen_language == -1) {
    01508     chosen_language = (language_fallback != -1) ? language_fallback : en_GB_fallback;
    01509   }
    01510
    01511   if (!ReadLanguagePack(chosen_language)) usererror("Can't read language pack '%s'", dl->ent[chosen_language].file);
    01512 }
    01513
    01518 const char *GetCurrentLanguageIsoCode()
    01519 {
    01520   return _langpack->isocode;
    01521 }
    01522
    01533 void CheckForMissingGlyphsInLoadedLanguagePack()
    01534 {
    01535 #ifdef WITH_FREETYPE
    01536   /* Reset to the original state; switching languages might cause us to
    01537    * automatically choose another font. This resets that choice. */
    01538   UninitFreeType();
    01539   InitFreeType();
    01540   bool retry = false;
    01541 #endif
    01542
    01543   for (;;) {
    01544     const Sprite *question_mark = GetGlyph(FS_NORMAL, '?');
    01545
    01546     for (uint i = 0; i != 32; i++) {
    01547       for (uint j = 0; j < _langtab_num[i]; j++) {
    01548         const char *string = _langpack_offs[_langtab_start[i] + j];
    01549         WChar c;
    01550         while ((c = Utf8Consume(&string)) != '\0') {
    01551           if (c == SCC_SETX) {
    01552             /*
    01553              * SetX is, together with SetXY as special character that
    01554              * uses the next (two) characters as data points. We have
    01555              * to skip those, otherwise the UTF8 reading will go
    01556              * haywire.
    01557              */
    01558             string++;
    01559           } else if (c == SCC_SETXY) {
    01560             string += 2;
    01561           } else if (IsPrintable(c) && c != '?' && GetGlyph(FS_NORMAL, c) == question_mark) {
    01562 #ifdef WITH_FREETYPE
    01563             if (!retry) {
    01564               /* We found an unprintable character... lets try whether we can
    01565                * find a fallback font that can print the characters in the
    01566                * current language. */
    01567               retry = true;
    01568
    01569               FreeTypeSettings backup;
    01570               memcpy(&backup, &_freetype, sizeof(backup));
    01571
    01572               bool success = SetFallbackFont(&_freetype, _langpack->isocode, _langpack->winlangid, string);
    01573               if (success) {
    01574                 UninitFreeType();
    01575                 InitFreeType();
    01576               }
    01577
    01578               memcpy(&_freetype, &backup, sizeof(backup));
    01579
    01580               if (success) continue;
    01581             } else {
    01582               /* Our fallback font does miss characters too, so keep the
    01583                * user chosen font as that is more likely to be any good than
    01584                * the wild guess we made */
    01585               UninitFreeType();
    01586               InitFreeType();
    01587             }
    01588 #endif
    01589             /*
    01590              * The character is printable, but not in the normal font.
    01591              * This is the case we were testing for. In this case we
    01592              * have to show the error. As we do not want the string to
    01593              * be translated by the translators, we 'force' it into the
    01594              * binary and 'load' it via a BindCString. To do this
    01595              * properly we have to set the colour of the string,
    01596              * otherwise we end up with a lot of artefacts. The colour
    01597              * 'character' might change in the future, so for safety
    01598              * we just Utf8 Encode it into the string, which takes
    01599              * exactly three characters, so it replaces the "XXX" with
    01600              * the colour marker.
    01601              */
    01602             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.");
    01603             Utf8Encode(err_str, SCC_YELLOW);
    01604             SetDParamStr(0, err_str);
    01605             ShowErrorMessage(STR_JUST_RAW_STRING, INVALID_STRING_ID, 0, 0);
    01606
    01607             /* Reset the font width */
    01608             LoadStringWidthTable();
    01609             return;
    01610           }
    01611         }
    01612       }
    01613     }
    01614     break;
    01615   }
    01616
    01617   /* Update the font with cache */
    01618   LoadStringWidthTable();
    01619
    01620 #if !defined(WITH_ICU)
    01621   /*
    01622    * For right-to-left languages we need the ICU library. If
    01623    * we do not have support for that library we warn the user
    01624    * about it with a message. As we do not want the string to
    01625    * be translated by the translators, we 'force' it into the
    01626    * binary and 'load' it via a BindCString. To do this
    01627    * properly we have to set the colour of the string,
    01628    * otherwise we end up with a lot of artefacts. The colour
    01629    * 'character' might change in the future, so for safety
    01630    * we just Utf8 Encode it into the string, which takes
    01631    * exactly three characters, so it replaces the "XXX" with
    01632    * the colour marker.
    01633    */
    01634   if (_dynlang.text_dir != TD_LTR) {
    01635     static char *err_str = strdup("XXXThis version of OpenTTD does not support right-to-left languages. Recompile with icu enabled.");
    01636     Utf8Encode(err_str, SCC_YELLOW);
    01637     SetDParamStr(0, err_str);
    01638     ShowErrorMessage(STR_JUST_RAW_STRING, INVALID_STRING_ID, 0, 0);
    01639   }
    01640 #endif
    01641 }