# strings.cpp

Go to the documentation of this file.

    00001 /* $Id: strings.cpp 19653 2010-04-17 12:00:59Z 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, uint64 number, const char *last)
    00235 {
    00236   return buff + seprintf(buff, last, "0x" OTTD_PRINTFHEX64, 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 0 and ending in 1, except those ending in 11
    00394      * Used in:
    00395      *   Latvian */
    00396     case 3:
    00397       return n % 10 == 1 && n % 100 != 11 ? 0 : n != 0 ? 1 : 2;
    00398
    00399     /* Five forms, special case for one, two, 3 to 6 and 7 to 10
    00400      * Used in:
    00401      *   Gaelige (Irish) */
    00402     case 4:
    00403       return n == 1 ? 0 : n == 2 ? 1 : n < 7 ? 2 : n < 11 ? 3 : 4;
    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, 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, Slovak */
    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     /* Four forms: one, 0 and everything ending in 02..10, everything ending in 11..19.
    00468      * Used in:
    00469      *  Maltese */
    00470     case 12:
    00471       return (n == 1 ? 0 : n == 0 || (n % 100 > 1 && n % 100 < 11) ? 1 : (n % 100 > 10 && n % 100 < 20) ? 2 : 3);
    00472   }
    00473 }
    00474
    00475 static const char *ParseStringChoice(const char *b, uint form, char **dst, const char *last)
    00476 {
    00477   /* <NUM> {Length of each string} {each string} */
    00478   uint n = (byte)*b++;
    00479   uint pos, i, mypos = 0;
    00480
    00481   for (i = pos = 0; i != n; i++) {
    00482     uint len = (byte)*b++;
    00483     if (i == form) mypos = pos;
    00484     pos += len;
    00485   }
    00486
    00487   *dst += seprintf(*dst, last, "%s", b + mypos);
    00488   return b + pos;
    00489 }
    00490
    00491 struct Units {
    00492   int s_m;
    00493   int s_s;
    00494   StringID velocity;
    00495   int p_m;
    00496   int p_s;
    00497   StringID power;
    00498   int w_m;
    00499   int w_s;
    00500   StringID s_weight;
    00501   StringID l_weight;
    00502   int v_m;
    00503   int v_s;
    00504   StringID s_volume;
    00505   StringID l_volume;
    00506   int f_m;
    00507   int f_s;
    00508   StringID force;
    00509 };
    00510
    00511 /* Unit conversions */
    00512 static const Units units[] = {
    00513   { // Imperial (Original, mph, hp, metric ton, litre, kN)
    00514        1,  0, STR_UNITS_VELOCITY_IMPERIAL,
    00515        1,  0, STR_UNITS_POWER_IMPERIAL,
    00516        1,  0, STR_UNITS_WEIGHT_SHORT_METRIC, STR_UNITS_WEIGHT_LONG_METRIC,
    00517     1000,  0, STR_UNITS_VOLUME_SHORT_METRIC, STR_UNITS_VOLUME_LONG_METRIC,
    00518        1,  0, STR_UNITS_FORCE_SI,
    00519   },
    00520   { // Metric (km/h, hp, metric ton, litre, kN)
    00521      103,  6, STR_UNITS_VELOCITY_METRIC,
    00522        1,  0, STR_UNITS_POWER_METRIC,
    00523        1,  0, STR_UNITS_WEIGHT_SHORT_METRIC, STR_UNITS_WEIGHT_LONG_METRIC,
    00524     1000,  0, STR_UNITS_VOLUME_SHORT_METRIC, STR_UNITS_VOLUME_LONG_METRIC,
    00525        1,  0, STR_UNITS_FORCE_SI,
    00526   },
    00527   { // SI (m/s, kilowatt, kilogram, cubic metres, kilonewton)
    00528     1831, 12, STR_UNITS_VELOCITY_SI,
    00529      764, 10, STR_UNITS_POWER_SI,
    00530     1000,  0, STR_UNITS_WEIGHT_SHORT_SI, STR_UNITS_WEIGHT_LONG_SI,
    00531        1,  0, STR_UNITS_VOLUME_SHORT_SI, STR_UNITS_VOLUME_LONG_SI,
    00532        1,  0, STR_UNITS_FORCE_SI,
    00533   },
    00534 };
    00535
    00541 uint ConvertSpeedToDisplaySpeed(uint speed)
    00542 {
    00543   return (speed * units[_settings_game.locale.units].s_m) >> units[_settings_game.locale.units].s_s;
    00544 }
    00545
    00551 uint ConvertDisplaySpeedToSpeed(uint speed)
    00552 {
    00553   return ((speed << units[_settings_game.locale.units].s_s) + units[_settings_game.locale.units].s_m / 2) / units[_settings_game.locale.units].s_m;
    00554 }
    00555
    00556 static char *FormatString(char *buff, const char *str, int64 *argv, uint casei, const char *last)
    00557 {
    00558   WChar b;
    00559   int64 *argv_orig = argv;
    00560   uint modifier = 0;
    00561   char *buf_start = buff;
    00562
    00563   while ((b = Utf8Consume(&str)) != '\0') {
    00564     if (SCC_NEWGRF_FIRST <= b && b <= SCC_NEWGRF_LAST) {
    00565       /* We need to pass some stuff as it might be modified; oh boy. */
    00566       b = RemapNewGRFStringControlCode(b, buf_start, &buff, &str, argv);
    00567       if (b == 0) continue;
    00568     }
    00569
    00570     switch (b) {
    00571       case SCC_SETX: // {SETX}
    00572         if (buff + Utf8CharLen(SCC_SETX) + 1 < last) {
    00573           buff += Utf8Encode(buff, SCC_SETX);
    00574           *buff++ = *str++;
    00575         }
    00576         break;
    00577
    00578       case SCC_SETXY: // {SETXY}
    00579         if (buff + Utf8CharLen(SCC_SETXY) + 2 < last) {
    00580           buff += Utf8Encode(buff, SCC_SETXY);
    00581           *buff++ = *str++;
    00582           *buff++ = *str++;
    00583         }
    00584         break;
    00585
    00586       case SCC_STRING_ID: // {STRINL}
    00587         buff = GetStringWithArgs(buff, Utf8Consume(&str), argv, last);
    00588         break;
    00589
    00590       case SCC_RAW_STRING_POINTER: { // {RAW_STRING}
    00591         const char *str = (const char*)(size_t)GetInt64(&argv);
    00592         buff = FormatString(buff, str, argv, casei, last);
    00593         break;
    00594       }
    00595
    00596       case SCC_DATE_LONG: // {DATE_LONG}
    00597         buff = FormatYmdString(buff, GetInt32(&argv), last);
    00598         break;
    00599
    00600       case SCC_DATE_SHORT: // {DATE_SHORT}
    00601         buff = FormatMonthAndYear(buff, GetInt32(&argv), last);
    00602         break;
    00603
    00604       case SCC_VELOCITY: {// {VELOCITY}
    00605         int64 args[1];
    00606         assert(_settings_game.locale.units < lengthof(units));
    00607         args[0] = ConvertSpeedToDisplaySpeed(GetInt32(&argv) * 10 / 16);
    00608         buff = FormatString(buff, GetStringPtr(units[_settings_game.locale.units].velocity), args, modifier >> 24, last);
    00609         modifier = 0;
    00610         break;
    00611       }
    00612
    00613       case SCC_CURRENCY_COMPACT: // {CURRCOMPACT}
    00614         buff = FormatGenericCurrency(buff, _currency, GetInt64(&argv), true, last);
    00615         break;
    00616
    00617       case SCC_REVISION: // {REV}
    00618         buff = strecpy(buff, _openttd_revision, last);
    00619         break;
    00620
    00621       case SCC_CARGO_SHORT: { // {SHORTCARGO}
    00622         /* Short description of cargotypes. Layout:
    00623          * 8-bit = cargo type
    00624          * 16-bit = cargo count */
    00625         StringID cargo_str = CargoSpec::Get(GetInt32(&argv))->units_volume;
    00626         switch (cargo_str) {
    00627           case STR_TONS: {
    00628             int64 args[1];
    00629             assert(_settings_game.locale.units < lengthof(units));
    00630             args[0] = GetInt32(&argv) * units[_settings_game.locale.units].w_m >> units[_settings_game.locale.units].w_s;
    00631             buff = FormatString(buff, GetStringPtr(units[_settings_game.locale.units].l_weight), args, modifier >> 24, last);
    00632             modifier = 0;
    00633             break;
    00634           }
    00635
    00636           case STR_LITERS: {
    00637             int64 args[1];
    00638             assert(_settings_game.locale.units < lengthof(units));
    00639             args[0] = GetInt32(&argv) * units[_settings_game.locale.units].v_m >> units[_settings_game.locale.units].v_s;
    00640             buff = FormatString(buff, GetStringPtr(units[_settings_game.locale.units].l_volume), args, modifier >> 24, last);
    00641             modifier = 0;
    00642             break;
    00643           }
    00644
    00645           default:
    00646             if (cargo_str >= 0xE000 && cargo_str < 0xF800) {
    00647               /* NewGRF strings from Action 4 use a different format here,
    00648                * of e.g. "x tonnes of coal", so process accordingly. */
    00649               buff = GetStringWithArgs(buff, cargo_str, argv++, last);
    00650             } else {
    00651               buff = FormatCommaNumber(buff, GetInt32(&argv), last);
    00652               buff = strecpy(buff, " ", last);
    00653               buff = strecpy(buff, GetStringPtr(cargo_str), last);
    00654             }
    00655             break;
    00656         }
    00657       } break;
    00658
    00659       case SCC_STRING1: { // {STRING1}
    00660         /* String that consumes ONE argument */
    00661         uint str = modifier + GetInt32(&argv);
    00662         buff = GetStringWithArgs(buff, str, GetArgvPtr(&argv, 1), last);
    00663         modifier = 0;
    00664         break;
    00665       }
    00666
    00667       case SCC_STRING2: { // {STRING2}
    00668         /* String that consumes TWO arguments */
    00669         uint str = modifier + GetInt32(&argv);
    00670         buff = GetStringWithArgs(buff, str, GetArgvPtr(&argv, 2), last);
    00671         modifier = 0;
    00672         break;
    00673       }
    00674
    00675       case SCC_STRING3: { // {STRING3}
    00676         /* String that consumes THREE arguments */
    00677         uint str = modifier + GetInt32(&argv);
    00678         buff = GetStringWithArgs(buff, str, GetArgvPtr(&argv, 3), last);
    00679         modifier = 0;
    00680         break;
    00681       }
    00682
    00683       case SCC_STRING4: { // {STRING4}
    00684         /* String that consumes FOUR arguments */
    00685         uint str = modifier + GetInt32(&argv);
    00686         buff = GetStringWithArgs(buff, str, GetArgvPtr(&argv, 4), last);
    00687         modifier = 0;
    00688         break;
    00689       }
    00690
    00691       case SCC_STRING5: { // {STRING5}
    00692         /* String that consumes FIVE arguments */
    00693         uint str = modifier + GetInt32(&argv);
    00694         buff = GetStringWithArgs(buff, str, GetArgvPtr(&argv, 5), last);
    00695         modifier = 0;
    00696         break;
    00697       }
    00698
    00699       case SCC_STATION_FEATURES: { // {STATIONFEATURES}
    00700         buff = StationGetSpecialString(buff, GetInt32(&argv), last);
    00701         break;
    00702       }
    00703
    00704       case SCC_INDUSTRY_NAME: { // {INDUSTRY}
    00705         const Industry *i = Industry::Get(GetInt32(&argv));
    00706         int64 args[2];
    00707
    00708         /* industry not valid anymore? */
    00709         assert(i != NULL);
    00710
    00711         /* First print the town name and the industry type name. */
    00712         args[0] = i->town->index;
    00713         args[1] = GetIndustrySpec(i->type)->name;
    00714         buff = FormatString(buff, GetStringPtr(STR_FORMAT_INDUSTRY_NAME), args, modifier >> 24, last);
    00715         modifier = 0;
    00716         break;
    00717       }
    00718
    00719       case SCC_VOLUME: { // {VOLUME}
    00720         int64 args[1];
    00721         assert(_settings_game.locale.units < lengthof(units));
    00722         args[0] = GetInt32(&argv) * units[_settings_game.locale.units].v_m >> units[_settings_game.locale.units].v_s;
    00723         buff = FormatString(buff, GetStringPtr(units[_settings_game.locale.units].l_volume), args, modifier >> 24, last);
    00724         modifier = 0;
    00725         break;
    00726       }
    00727
    00728       case SCC_GENDER_LIST: { // {G 0 Der Die Das}
    00729         /* First read the meta data from the language file. */
    00730         WChar fmt = SCC_CONTROL_START + (byte)*str++;
    00731         byte offset = (byte)*str++;
    00732
    00733         /* Now we need to figure out what text to resolve, i.e.
    00734          * what do we need to draw? So get the actual raw string
    00735          * first using the control code to get said string. */
    00736         char input[4 + 1];
    00737         char *p = input + Utf8Encode(input, fmt);
    00738         *p = '\0';
    00739
    00740         /* Now do the string formatting. */
    00741         char buf[256];
    00742         bool old_kgd = _keep_gender_data;
    00743         _keep_gender_data = true;
    00744         p = FormatString(buf, input, argv_orig + offset, 0, lastof(buf));
    00745         _keep_gender_data = old_kgd;
    00746         *p = '\0';
    00747
    00748         /* And determine the string. */
    00749         int gender = 0;
    00750         const char *s = buf;
    00751         WChar c = Utf8Consume(&s);
    00752         /* Does this string have a gender, if so, set it */
    00753         if (c == SCC_GENDER_INDEX) gender = (byte)s[0];
    00754         str = ParseStringChoice(str, gender, &buff, last);
    00755         break;
    00756       }
    00757
    00758       case SCC_DATE_TINY: { // {DATE_TINY}
    00759         buff = FormatTinyOrISODate(buff, GetInt32(&argv), STR_FORMAT_DATE_TINY, last);
    00760         break;
    00761       }
    00762
    00763       case SCC_DATE_ISO: { // {DATE_ISO}
    00764         buff = FormatTinyOrISODate(buff, GetInt32(&argv), STR_FORMAT_DATE_ISO, last);
    00765         break;
    00766       }
    00767
    00768       case SCC_CARGO: { // {CARGO}
    00769         /* First parameter is cargo type, second parameter is cargo count */
    00770         CargoID cargo = GetInt32(&argv);
    00771         StringID cargo_str = (cargo == CT_INVALID) ? STR_QUANTITY_N_A : CargoSpec::Get(cargo)->quantifier;
    00772         buff = GetStringWithArgs(buff, cargo_str, argv++, last);
    00773         break;
    00774       }
    00775
    00776       case SCC_POWER: { // {POWER}
    00777         int64 args[1];
    00778         assert(_settings_game.locale.units < lengthof(units));
    00779         args[0] = GetInt32(&argv) * units[_settings_game.locale.units].p_m >> units[_settings_game.locale.units].p_s;
    00780         buff = FormatString(buff, GetStringPtr(units[_settings_game.locale.units].power), args, modifier >> 24, last);
    00781         modifier = 0;
    00782         break;
    00783       }
    00784
    00785       case SCC_VOLUME_SHORT: { // {VOLUME_S}
    00786         int64 args[1];
    00787         assert(_settings_game.locale.units < lengthof(units));
    00788         args[0] = GetInt32(&argv) * units[_settings_game.locale.units].v_m >> units[_settings_game.locale.units].v_s;
    00789         buff = FormatString(buff, GetStringPtr(units[_settings_game.locale.units].s_volume), args, modifier >> 24, last);
    00790         modifier = 0;
    00791         break;
    00792       }
    00793
    00794       case SCC_WEIGHT: { // {WEIGHT}
    00795         int64 args[1];
    00796         assert(_settings_game.locale.units < lengthof(units));
    00797         args[0] = GetInt32(&argv) * units[_settings_game.locale.units].w_m >> units[_settings_game.locale.units].w_s;
    00798         buff = FormatString(buff, GetStringPtr(units[_settings_game.locale.units].l_weight), args, modifier >> 24, last);
    00799         modifier = 0;
    00800         break;
    00801       }
    00802
    00803       case SCC_WEIGHT_SHORT: { // {WEIGHT_S}
    00804         int64 args[1];
    00805         assert(_settings_game.locale.units < lengthof(units));
    00806         args[0] = GetInt32(&argv) * units[_settings_game.locale.units].w_m >> units[_settings_game.locale.units].w_s;
    00807         buff = FormatString(buff, GetStringPtr(units[_settings_game.locale.units].s_weight), args, modifier >> 24, last);
    00808         modifier = 0;
    00809         break;
    00810       }
    00811
    00812       case SCC_FORCE: { // {FORCE}
    00813         int64 args[1];
    00814         assert(_settings_game.locale.units < lengthof(units));
    00815         args[0] = GetInt32(&argv) * units[_settings_game.locale.units].f_m >> units[_settings_game.locale.units].f_s;
    00816         buff = FormatString(buff, GetStringPtr(units[_settings_game.locale.units].force), args, modifier >> 24, last);
    00817         modifier = 0;
    00818         break;
    00819       }
    00820
    00821       /* This sets up the gender for the string.
    00822        * We just ignore this one. It's used in {G 0 Der Die Das} to determine the case. */
    00823       case SCC_GENDER_INDEX: // {GENDER 0}
    00824         if (_keep_gender_data) {
    00825           buff += Utf8Encode(buff, SCC_GENDER_INDEX);
    00826           *buff++ = *str++;
    00827         } else {
    00828           str++;
    00829         }
    00830         break;
    00831
    00832       case SCC_STRING: {// {STRING}
    00833         uint str = modifier + GetInt32(&argv);
    00834         /* WARNING. It's prohibited for the included string to consume any arguments.
    00835          * For included strings that consume argument, you should use STRING1, STRING2 etc.
    00836          * To debug stuff you can set argv to NULL and it will tell you */
    00837         buff = GetStringWithArgs(buff, str, argv, last);
    00838         modifier = 0;
    00839         break;
    00840       }
    00841
    00842       case SCC_COMMA: // {COMMA}
    00843         buff = FormatCommaNumber(buff, GetInt64(&argv), last);
    00844         break;
    00845
    00846       case SCC_ARG_INDEX: // Move argument pointer
    00847         argv = argv_orig + (byte)*str++;
    00848         break;
    00849
    00850       case SCC_PLURAL_LIST: { // {P}
    00851         int64 v = argv_orig[(byte)*str++]; // contains the number that determines plural
    00852         str = ParseStringChoice(str, DeterminePluralForm(v), &buff, last);
    00853         break;
    00854       }
    00855
    00856       case SCC_NUM: // {NUM}
    00857         buff = FormatNoCommaNumber(buff, GetInt64(&argv), last);
    00858         break;
    00859
    00860       case SCC_ZEROFILL_NUM: { // {ZEROFILL_NUM}
    00861         int64 num = GetInt64(&argv);
    00862         buff = FormatZerofillNumber(buff, num, GetInt64(&argv), last);
    00863       } break;
    00864
    00865       case SCC_HEX: // {HEX}
    00866         buff = FormatHexNumber(buff, (uint64)GetInt64(&argv), last);
    00867         break;
    00868
    00869       case SCC_BYTES: // {BYTES}
    00870         buff = FormatBytes(buff, GetInt64(&argv), last);
    00871         break;
    00872
    00873       case SCC_CURRENCY: // {CURRENCY}
    00874         buff = FormatGenericCurrency(buff, _currency, GetInt64(&argv), false, last);
    00875         break;
    00876
    00877       case SCC_WAYPOINT_NAME: { // {WAYPOINT}
    00878         Waypoint *wp = Waypoint::Get(GetInt32(&argv));
    00879
    00880         assert(wp != NULL);
    00881
    00882         if (wp->name != NULL) {
    00883           buff = strecpy(buff, wp->name, last);
    00884         } else {
    00885           int64 temp[2];
    00886           temp[0] = wp->town->index;
    00887           temp[1] = wp->town_cn + 1;
    00888           StringID str = ((wp->string_id == STR_SV_STNAME_BUOY) ? STR_FORMAT_BUOY_NAME : STR_FORMAT_WAYPOINT_NAME);
    00889           if (wp->town_cn != 0) str++;
    00890           buff = GetStringWithArgs(buff, str, temp, last);
    00891         }
    00892         break;
    00893       }
    00894
    00895       case SCC_STATION_NAME: { // {STATION}
    00896         StationID sid = GetInt32(&argv);
    00897         const Station *st = Station::GetIfValid(sid);
    00898
    00899         if (st == NULL) {
    00900           /* The station doesn't exist anymore. The only place where we might
    00901            * be "drawing" an invalid station is in the case of cargo that is
    00902            * in transit. */
    00903           buff = GetStringWithArgs(buff, STR_UNKNOWN_STATION, NULL, last);
    00904           break;
    00905         }
    00906
    00907         if (st->name != NULL) {
    00908           buff = strecpy(buff, st->name, last);
    00909         } else {
    00910           StringID str = st->string_id;
    00911           if (st->indtype != IT_INVALID) {
    00912             /* Special case where the industry provides the name for the station */
    00913             const IndustrySpec *indsp = GetIndustrySpec(st->indtype);
    00914
    00915             /* Industry GRFs can change which might remove the station name and
    00916              * thus cause very strange things. Here we check for that before we
    00917              * actually set the station name. */
    00918             if (indsp->station_name != STR_NULL && indsp->station_name != STR_UNDEFINED) {
    00919               str = indsp->station_name;
    00920             }
    00921           }
    00922
    00923           int64 temp[3];
    00924           temp[0] = STR_TOWN_NAME;
    00925           temp[1] = st->town->index;
    00926           temp[2] = st->index;
    00927           buff = GetStringWithArgs(buff, str, temp, last);
    00928         }
    00929         break;
    00930       }
    00931
    00932       case SCC_TOWN_NAME: { // {TOWN}
    00933         const Town *t = Town::Get(GetInt32(&argv));
    00934
    00935         assert(t != NULL);
    00936
    00937         if (t->name != NULL) {
    00938           buff = strecpy(buff, t->name, last);
    00939         } else {
    00940           buff = GetTownName(buff, t, last);
    00941         }
    00942         break;
    00943       }
    00944
    00945       case SCC_GROUP_NAME: { // {GROUP}
    00946         const Group *g = Group::Get(GetInt32(&argv));
    00947
    00948         assert(g != NULL);
    00949
    00950         if (g->name != NULL) {
    00951           buff = strecpy(buff, g->name, last);
    00952         } else {
    00953           int64 args[1];
    00954
    00955           args[0] = g->index;
    00956           buff = GetStringWithArgs(buff, STR_FORMAT_GROUP_NAME, args, last);
    00957         }
    00958         break;
    00959       }
    00960
    00961       case SCC_ENGINE_NAME: { // {ENGINE}
    00962         EngineID engine = (EngineID)GetInt32(&argv);
    00963         const Engine *e = Engine::Get(engine);
    00964
    00965         assert(e != NULL);
    00966
    00967         if (e->name != NULL) {
    00968           buff = strecpy(buff, e->name, last);
    00969         } else {
    00970           buff = GetStringWithArgs(buff, e->info.string_id, NULL, last);
    00971         }
    00972         break;
    00973       }
    00974
    00975       case SCC_VEHICLE_NAME: { // {VEHICLE}
    00976         const Vehicle *v = Vehicle::Get(GetInt32(&argv));
    00977
    00978         assert(v != NULL);
    00979
    00980         if (v->name != NULL) {
    00981           buff = strecpy(buff, v->name, last);
    00982         } else {
    00983           int64 args[1];
    00984           args[0] = v->unitnumber;
    00985
    00986           StringID str;
    00987           switch (v->type) {
    00988             default: NOT_REACHED();
    00989             case VEH_TRAIN:    str = STR_SV_TRAIN_NAME; break;
    00990             case VEH_ROAD:     str = STR_SV_ROAD_VEHICLE_NAME; break;
    00991             case VEH_SHIP:     str = STR_SV_SHIP_NAME; break;
    00992             case VEH_AIRCRAFT: str = STR_SV_AIRCRAFT_NAME; break;
    00993           }
    00994
    00995           buff = GetStringWithArgs(buff, str, args, last);
    00996         }
    00997         break;
    00998       }
    00999
    01000       case SCC_SIGN_NAME: { // {SIGN}
    01001         const Sign *si = Sign::Get(GetInt32(&argv));
    01002         if (si->name != NULL) {
    01003           buff = strecpy(buff, si->name, last);
    01004         } else {
    01005           buff = GetStringWithArgs(buff, STR_DEFAULT_SIGN_NAME, NULL, last);
    01006         }
    01007         break;
    01008       }
    01009
    01010       case SCC_COMPANY_NAME: { // {COMPANY}
    01011         const Company *c = Company::Get((CompanyID)GetInt32(&argv));
    01012
    01013         if (c->name != NULL) {
    01014           buff = strecpy(buff, c->name, last);
    01015         } else {
    01016           int64 args[1];
    01017           args[0] = c->name_2;
    01018           buff = GetStringWithArgs(buff, c->name_1, args, last);
    01019         }
    01020         break;
    01021       }
    01022
    01023       case SCC_COMPANY_NUM: { // {COMPANYNUM}
    01024         CompanyID company = (CompanyID)GetInt32(&argv);
    01025
    01026         /* Nothing is added for AI or inactive companies */
    01027         if (Company::IsValidHumanID(company)) {
    01028           int64 args[1];
    01029           args[0] = company + 1;
    01030           buff = GetStringWithArgs(buff, STR_FORMAT_COMPANY_NUM, args, last);
    01031         }
    01032         break;
    01033       }
    01034
    01035       case SCC_PRESIDENT_NAME: { // {PRESIDENTNAME}
    01036         const Company *c = Company::Get((CompanyID)GetInt32(&argv));
    01037
    01038         if (c->president_name != NULL) {
    01039           buff = strecpy(buff, c->president_name, last);
    01040         } else {
    01041           int64 args[1];
    01042           args[0] = c->president_name_2;
    01043           buff = GetStringWithArgs(buff, c->president_name_1, args, last);
    01044         }
    01045         break;
    01046       }
    01047
    01048       case SCC_SETCASE: { // {SETCASE}
    01049         /* This is a pseudo command, it's outputted when someone does {STRING.ack}
    01050          * The modifier is added to all subsequent GetStringWithArgs that accept the modifier. */
    01051         modifier = (byte)*str++ << 24;
    01052         break;
    01053       }
    01054
    01055       case SCC_SWITCH_CASE: { // {Used to implement case switching}
    01056         /* <0x9E> <NUM CASES> <CASE1> <LEN1> <STRING1> <CASE2> <LEN2> <STRING2> <CASE3> <LEN3> <STRING3> <STRINGDEFAULT>
    01057          * Each LEN is printed using 2 bytes in big endian order. */
    01058         uint num = (byte)*str++;
    01059         while (num) {
    01060           if ((byte)str[0] == casei) {
    01061             /* Found the case, adjust str pointer and continue */
    01062             str += 3;
    01063             break;
    01064           }
    01065           /* Otherwise skip to the next case */
    01066           str += 3 + (str[1] << 8) + str[2];
    01067           num--;
    01068         }
    01069         break;
    01070       }
    01071
    01072       default:
    01073         if (buff + Utf8CharLen(b) < last) buff += Utf8Encode(buff, b);
    01074         break;
    01075     }
    01076   }
    01077   *buff = '\0';
    01078   return buff;
    01079 }
    01080
    01081
    01082 static char *StationGetSpecialString(char *buff, int x, const char *last)
    01083 {
    01084   if ((x & FACIL_TRAIN)      && (buff + Utf8CharLen(SCC_TRAIN) < last)) buff += Utf8Encode(buff, SCC_TRAIN);
    01085   if ((x & FACIL_TRUCK_STOP) && (buff + Utf8CharLen(SCC_LORRY) < last)) buff += Utf8Encode(buff, SCC_LORRY);
    01086   if ((x & FACIL_BUS_STOP)   && (buff + Utf8CharLen(SCC_BUS)   < last)) buff += Utf8Encode(buff, SCC_BUS);
    01087   if ((x & FACIL_AIRPORT)    && (buff + Utf8CharLen(SCC_PLANE) < last)) buff += Utf8Encode(buff, SCC_PLANE);
    01088   if ((x & FACIL_DOCK)       && (buff + Utf8CharLen(SCC_SHIP)  < last)) buff += Utf8Encode(buff, SCC_SHIP);
    01089   *buff = '\0';
    01090   return buff;
    01091 }
    01092
    01093 static char *GetSpecialTownNameString(char *buff, int ind, uint32 seed, const char *last)
    01094 {
    01095   return GenerateTownNameString(buff, last, ind, seed);
    01096 }
    01097
    01098 static const char * const _silly_company_names[] = {
    01099   "Bloggs Brothers",
    01100   "Tiny Transport Ltd.",
    01101   "Express Travel",
    01102   "Comfy-Coach & Co.",
    01103   "Crush & Bump Ltd.",
    01104   "Broken & Late Ltd.",
    01105   "Sam Speedy & Son",
    01106   "Supersonic Travel",
    01107   "Mike's Motors",
    01108   "Lightning International",
    01109   "Pannik & Loozit Ltd.",
    01110   "Inter-City Transport",
    01111   "Getout & Pushit Ltd."
    01112 };
    01113
    01114 static const char * const _surname_list[] = {
    01115   "Adams",
    01116   "Allan",
    01117   "Baker",
    01118   "Bigwig",
    01119   "Black",
    01120   "Bloggs",
    01121   "Brown",
    01122   "Campbell",
    01123   "Gordon",
    01124   "Hamilton",
    01125   "Hawthorn",
    01126   "Higgins",
    01127   "Green",
    01128   "Gribble",
    01129   "Jones",
    01130   "McAlpine",
    01131   "MacDonald",
    01132   "McIntosh",
    01133   "Muir",
    01134   "Murphy",
    01135   "Nelson",
    01136   "O'Donnell",
    01137   "Parker",
    01138   "Phillips",
    01139   "Pilkington",
    01140   "Quigley",
    01141   "Sharkey",
    01142   "Thomson",
    01143   "Watkins"
    01144 };
    01145
    01146 static const char * const _silly_surname_list[] = {
    01147   "Grumpy",
    01148   "Dozy",
    01149   "Speedy",
    01150   "Nosey",
    01151   "Dribble",
    01152   "Mushroom",
    01153   "Cabbage",
    01154   "Sniffle",
    01155   "Fishy",
    01156   "Swindle",
    01157   "Sneaky",
    01158   "Nutkins"
    01159 };
    01160
    01161 static const char _initial_name_letters[] = {
    01162   'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
    01163   'K', 'L', 'M', 'N', 'P', 'R', 'S', 'T', 'W',
    01164 };
    01165
    01166 static char *GenAndCoName(char *buff, uint32 arg, const char *last)
    01167 {
    01168   const char * const *base;
    01169   uint num;
    01170
    01171   if (_settings_game.game_creation.landscape == LT_TOYLAND) {
    01172     base = _silly_surname_list;
    01173     num  = lengthof(_silly_surname_list);
    01174   } else {
    01175     base = _surname_list;
    01176     num  = lengthof(_surname_list);
    01177   }
    01178
    01179   buff = strecpy(buff, base[num * GB(arg, 16, 8) >> 8], last);
    01180   buff = strecpy(buff, " & Co.", last);
    01181
    01182   return buff;
    01183 }
    01184
    01185 static char *GenPresidentName(char *buff, uint32 x, const char *last)
    01186 {
    01187   char initial[] = "?. ";
    01188   const char * const *base;
    01189   uint num;
    01190   uint i;
    01191
    01192   initial[0] = _initial_name_letters[sizeof(_initial_name_letters) * GB(x, 0, 8) >> 8];
    01193   buff = strecpy(buff, initial, last);
    01194
    01195   i = (sizeof(_initial_name_letters) + 35) * GB(x, 8, 8) >> 8;
    01196   if (i < sizeof(_initial_name_letters)) {
    01197     initial[0] = _initial_name_letters[i];
    01198     buff = strecpy(buff, initial, last);
    01199   }
    01200
    01201   if (_settings_game.game_creation.landscape == LT_TOYLAND) {
    01202     base = _silly_surname_list;
    01203     num  = lengthof(_silly_surname_list);
    01204   } else {
    01205     base = _surname_list;
    01206     num  = lengthof(_surname_list);
    01207   }
    01208
    01209   buff = strecpy(buff, base[num * GB(x, 16, 8) >> 8], last);
    01210
    01211   return buff;
    01212 }
    01213
    01214 static char *GetSpecialNameString(char *buff, int ind, int64 *argv, const char *last)
    01215 {
    01216   switch (ind) {
    01217     case 1: // not used
    01218       return strecpy(buff, _silly_company_names[GetInt32(&argv) & 0xFFFF], last);
    01219
    01220     case 2: // used for Foobar & Co company names
    01221       return GenAndCoName(buff, GetInt32(&argv), last);
    01222
    01223     case 3: // President name
    01224       return GenPresidentName(buff, GetInt32(&argv), last);
    01225   }
    01226
    01227   /* town name? */
    01228   if (IsInsideMM(ind - 6, 0, SPECSTR_TOWNNAME_LAST - SPECSTR_TOWNNAME_START + 1)) {
    01229     buff = GetSpecialTownNameString(buff, ind - 6, GetInt32(&argv), last);
    01230     return strecpy(buff, " Transport", last);
    01231   }
    01232
    01233   /* language name? */
    01234   if (IsInsideMM(ind, (SPECSTR_LANGUAGE_START - 0x70E4), (SPECSTR_LANGUAGE_END - 0x70E4) + 1)) {
    01235     int i = ind - (SPECSTR_LANGUAGE_START - 0x70E4);
    01236     return strecpy(buff,
    01237       i == _dynlang.curr ? _langpack->own_name : _dynlang.ent[i].name, last);
    01238   }
    01239
    01240   /* resolution size? */
    01241   if (IsInsideMM(ind, (SPECSTR_RESOLUTION_START - 0x70E4), (SPECSTR_RESOLUTION_END - 0x70E4) + 1)) {
    01242     int i = ind - (SPECSTR_RESOLUTION_START - 0x70E4);
    01243     buff += seprintf(
    01244       buff, last, "%ux%u", _resolutions[i].width, _resolutions[i].height
    01245     );
    01246     return buff;
    01247   }
    01248
    01249   /* screenshot format name? */
    01250   if (IsInsideMM(ind, (SPECSTR_SCREENSHOT_START - 0x70E4), (SPECSTR_SCREENSHOT_END - 0x70E4) + 1)) {
    01251     int i = ind - (SPECSTR_SCREENSHOT_START - 0x70E4);
    01252     return strecpy(buff, GetScreenshotFormatDesc(i), last);
    01253   }
    01254
    01255   NOT_REACHED();
    01256 }
    01257
    01258 #ifdef ENABLE_NETWORK
    01259 extern void SortNetworkLanguages();
    01260 #else /* ENABLE_NETWORK */
    01261 static inline void SortNetworkLanguages() {}
    01262 #endif /* ENABLE_NETWORK */
    01263
    01264 bool ReadLanguagePack(int lang_index)
    01265 {
    01266   /* Current language pack */
    01267   size_t len;
    01268   LanguagePack *lang_pack = (LanguagePack *)ReadFileToMem(_dynlang.ent[lang_index].file, &len, 200000);
    01269   if (lang_pack == NULL) return false;
    01270
    01271   /* End of read data (+ terminating zero added in ReadFileToMem()) */
    01272   const char *end = (char *)lang_pack + len + 1;
    01273
    01274   /* We need at least one byte of lang_pack->data */
    01275   if (end <= lang_pack->data ||
    01276       lang_pack->ident != TO_LE32(LANGUAGE_PACK_IDENT) ||
    01277       lang_pack->version != TO_LE32(LANGUAGE_PACK_VERSION)) {
    01278     free(lang_pack);
    01279     return false;
    01280   }
    01281
    01282 #if TTD_ENDIAN == TTD_BIG_ENDIAN
    01283   for (uint i = 0; i < 32; i++) {
    01284     lang_pack->offsets[i] = ReadLE16Aligned(&lang_pack->offsets[i]);
    01285   }
    01286 #endif /* TTD_ENDIAN == TTD_BIG_ENDIAN */
    01287
    01288   uint count = 0;
    01289   for (uint i = 0; i < 32; i++) {
    01290     uint num = lang_pack->offsets[i];
    01291     _langtab_start[i] = count;
    01292     _langtab_num[i] = num;
    01293     count += num;
    01294   }
    01295
    01296   /* Allocate offsets */
    01297   char **langpack_offs = MallocT<char *>(count);
    01298
    01299   /* Fill offsets */
    01300   char *s = lang_pack->data;
    01301   len = (byte)*s++;
    01302   for (uint i = 0; i < count; i++) {
    01303     if (s + len >= end) {
    01304       free(lang_pack);
    01305       free(langpack_offs);
    01306       return false;
    01307     }
    01308     if (len >= 0xC0) {
    01309       len = ((len & 0x3F) << 8) + (byte)*s++;
    01310       if (s + len >= end) {
    01311         free(lang_pack);
    01312         free(langpack_offs);
    01313         return false;
    01314       }
    01315     }
    01316     langpack_offs[i] = s;
    01317     s += len;
    01318     len = (byte)*s;
    01319     *s++ = '\0'; // zero terminate the string
    01320   }
    01321
    01322   free(_langpack);
    01323   _langpack = lang_pack;
    01324
    01325   free(_langpack_offs);
    01326   _langpack_offs = langpack_offs;
    01327
    01328   const char *c_file = strrchr(_dynlang.ent[lang_index].file, PATHSEPCHAR) + 1;
    01329   strecpy(_dynlang.curr_file, c_file, lastof(_dynlang.curr_file));
    01330
    01331   _dynlang.curr = lang_index;
    01332   _dynlang.text_dir = (TextDirection)lang_pack->text_dir;
    01333   SetCurrentGrfLangID(_langpack->newgrflangid);
    01334   SortNetworkLanguages();
    01335   return true;
    01336 }
    01337
    01338 /* Win32 implementation in win32.cpp.
    01339  * OS X implementation in os/macosx/macos.mm. */
    01340 #if !(defined(WIN32) || defined(__APPLE__))
    01341
    01347 const char *GetCurrentLocale(const char *param)
    01348 {
    01349   const char *env;
    01350
    01351   env = getenv("LANGUAGE");
    01352   if (env != NULL) return env;
    01353
    01354   env = getenv("LC_ALL");
    01355   if (env != NULL) return env;
    01356
    01357   if (param != NULL) {
    01358     env = getenv(param);
    01359     if (env != NULL) return env;
    01360   }
    01361
    01362   return getenv("LANG");
    01363 }
    01364 #else
    01365 const char *GetCurrentLocale(const char *param);
    01366 #endif /* !(defined(WIN32) || defined(__APPLE__)) */
    01367
    01368 int CDECL StringIDSorter(const StringID *a, const StringID *b)
    01369 {
    01370   char stra[512];
    01371   char strb[512];
    01372   GetString(stra, *a, lastof(stra));
    01373   GetString(strb, *b, lastof(strb));
    01374
    01375   return strcmp(stra, strb);
    01376 }
    01377
    01385 static bool UniqueLanguageFile(const Language *langs, uint max, const char *language)
    01386 {
    01387   for (uint i = 0; i < max; i++) {
    01388     const char *f_name = strrchr(langs[i].file, PATHSEPCHAR) + 1;
    01389     if (strcmp(f_name, language) == 0) return false; // duplicates
    01390   }
    01391
    01392   return true;
    01393 }
    01394
    01401 static bool GetLanguageFileHeader(const char *file, LanguagePack *hdr)
    01402 {
    01403   FILE *f = fopen(file, "rb");
    01404   if (f == NULL) return false;
    01405
    01406   size_t read = fread(hdr, sizeof(*hdr), 1, f);
    01407   fclose(f);
    01408
    01409   bool ret = read == 1 &&
    01410       hdr->ident == TO_LE32(LANGUAGE_PACK_IDENT) &&
    01411       hdr->version == TO_LE32(LANGUAGE_PACK_VERSION);
    01412
    01413   /* Convert endianness for the windows language ID */
    01414   if (ret) hdr->winlangid = FROM_LE16(hdr->winlangid);
    01415   return ret;
    01416 }
    01417
    01426 static int GetLanguageList(Language *langs, int start, int max, const char *path)
    01427 {
    01428   int i = start;
    01429
    01430   DIR *dir = ttd_opendir(path);
    01431   if (dir != NULL) {
    01432     struct dirent *dirent;
    01433     while ((dirent = readdir(dir)) != NULL && i < max) {
    01434       const char *d_name    = FS2OTTD(dirent->d_name);
    01435       const char *extension = strrchr(d_name, '.');
    01436
    01437       /* Not a language file */
    01438       if (extension == NULL || strcmp(extension, ".lng") != 0) continue;
    01439
    01440       /* Filter any duplicate language-files, first-come first-serve */
    01441       if (!UniqueLanguageFile(langs, i, d_name)) continue;
    01442
    01443       langs[i].file = str_fmt("%s%s", path, d_name);
    01444
    01445       /* Check whether the file is of the correct version */
    01446       LanguagePack hdr;
    01447       if (!GetLanguageFileHeader(langs[i].file, &hdr)) {
    01448         free(langs[i].file);
    01449         continue;
    01450       }
    01451
    01452       i++;
    01453     }
    01454     closedir(dir);
    01455   }
    01456   return i - start;
    01457 }
    01458
    01463 void InitializeLanguagePacks()
    01464 {
    01465   Searchpath sp;
    01466   Language files[MAX_LANG];
    01467   uint language_count = 0;
    01468
    01469   FOR_ALL_SEARCHPATHS(sp) {
    01470     char path[MAX_PATH];
    01471     FioAppendDirectory(path, lengthof(path), sp, LANG_DIR);
    01472     language_count += GetLanguageList(files, language_count, lengthof(files), path);
    01473   }
    01474   if (language_count == 0) usererror("No available language packs (invalid versions?)");
    01475
    01476   /* Acquire the locale of the current system */
    01477   const char *lang = GetCurrentLocale("LC_MESSAGES");
    01478   if (lang == NULL) lang = "en_GB";
    01479
    01480   int chosen_language   = -1;
    01481   int language_fallback = -1;
    01482   int en_GB_fallback    =  0;
    01483
    01484   DynamicLanguages *dl = &_dynlang;
    01485   dl->num = 0;
    01486   /* Fill the dynamic languages structures */
    01487   for (uint i = 0; i < language_count; i++) {
    01488     /* File read the language header */
    01489     LanguagePack hdr;
    01490     if (!GetLanguageFileHeader(files[i].file, &hdr)) continue;
    01491
    01492     dl->ent[dl->num].file = files[i].file;
    01493     dl->ent[dl->num].name = strdup(hdr.name);
    01494
    01495     /* We are trying to find a default language. The priority is by
    01496      * configuration file, local environment and last, if nothing found,
    01497      * english. If def equals -1, we have not picked a default language */
    01498     const char *lang_file = strrchr(dl->ent[dl->num].file, PATHSEPCHAR) + 1;
    01499     if (strcmp(lang_file, dl->curr_file) == 0) chosen_language = dl->num;
    01500
    01501     if (chosen_language == -1) {
    01502       if (strcmp (hdr.isocode, "en_GB") == 0) en_GB_fallback    = dl->num;
    01503       if (strncmp(hdr.isocode, lang, 5) == 0) chosen_language   = dl->num;
    01504       if (strncmp(hdr.isocode, lang, 2) == 0) language_fallback = dl->num;
    01505     }
    01506
    01507     dl->num++;
    01508   }
    01509
    01510   if (dl->num == 0) usererror("Invalid version of language packs");
    01511
    01512   /* We haven't found the language in the config nor the one in the locale.
    01513    * Now we set it to one of the fallback languages */
    01514   if (chosen_language == -1) {
    01515     chosen_language = (language_fallback != -1) ? language_fallback : en_GB_fallback;
    01516   }
    01517
    01518   if (!ReadLanguagePack(chosen_language)) usererror("Can't read language pack '%s'", dl->ent[chosen_language].file);
    01519 }
    01520
    01525 const char *GetCurrentLanguageIsoCode()
    01526 {
    01527   return _langpack->isocode;
    01528 }
    01529
    01540 void CheckForMissingGlyphsInLoadedLanguagePack()
    01541 {
    01542 #ifdef WITH_FREETYPE
    01543   /* Reset to the original state; switching languages might cause us to
    01544    * automatically choose another font. This resets that choice. */
    01545   UninitFreeType();
    01546   InitFreeType();
    01547   bool retry = false;
    01548 #endif
    01549
    01550   for (;;) {
    01551     const Sprite *question_mark = GetGlyph(FS_NORMAL, '?');
    01552
    01553     for (uint i = 0; i != 32; i++) {
    01554       for (uint j = 0; j < _langtab_num[i]; j++) {
    01555         const char *string = _langpack_offs[_langtab_start[i] + j];
    01556         WChar c;
    01557         while ((c = Utf8Consume(&string)) != '\0') {
    01558           if (c == SCC_SETX) {
    01559             /*
    01560              * SetX is, together with SetXY as special character that
    01561              * uses the next (two) characters as data points. We have
    01562              * to skip those, otherwise the UTF8 reading will go
    01563              * haywire.
    01564              */
    01565             string++;
    01566           } else if (c == SCC_SETXY) {
    01567             string += 2;
    01568           } else if (IsPrintable(c) && c != '?' && GetGlyph(FS_NORMAL, c) == question_mark) {
    01569 #ifdef WITH_FREETYPE
    01570             if (!retry) {
    01571               /* We found an unprintable character... lets try whether we can
    01572                * find a fallback font that can print the characters in the
    01573                * current language. */
    01574               retry = true;
    01575
    01576               FreeTypeSettings backup;
    01577               memcpy(&backup, &_freetype, sizeof(backup));
    01578
    01579               bool success = SetFallbackFont(&_freetype, _langpack->isocode, _langpack->winlangid, string);
    01580               if (success) {
    01581                 UninitFreeType();
    01582                 InitFreeType();
    01583               }
    01584
    01585               memcpy(&_freetype, &backup, sizeof(backup));
    01586
    01587               if (success) continue;
    01588             } else {
    01589               /* Our fallback font does miss characters too, so keep the
    01590                * user chosen font as that is more likely to be any good than
    01591                * the wild guess we made */
    01592               UninitFreeType();
    01593               InitFreeType();
    01594             }
    01595 #endif
    01596             /*
    01597              * The character is printable, but not in the normal font.
    01598              * This is the case we were testing for. In this case we
    01599              * have to show the error. As we do not want the string to
    01600              * be translated by the translators, we 'force' it into the
    01601              * binary and 'load' it via a BindCString. To do this
    01602              * properly we have to set the colour of the string,
    01603              * otherwise we end up with a lot of artefacts. The colour
    01604              * 'character' might change in the future, so for safety
    01605              * we just Utf8 Encode it into the string, which takes
    01606              * exactly three characters, so it replaces the "XXX" with
    01607              * the colour marker.
    01608              */
    01609             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.");
    01610             Utf8Encode(err_str, SCC_YELLOW);
    01611             SetDParamStr(0, err_str);
    01612             ShowErrorMessage(STR_JUST_RAW_STRING, INVALID_STRING_ID, 0, 0);
    01613
    01614             /* Reset the font width */
    01615             LoadStringWidthTable();
    01616             return;
    01617           }
    01618         }
    01619       }
    01620     }
    01621     break;
    01622   }
    01623
    01624   /* Update the font with cache */
    01625   LoadStringWidthTable();
    01626
    01627 #if !defined(WITH_ICU)
    01628   /*
    01629    * For right-to-left languages we need the ICU library. If
    01630    * we do not have support for that library we warn the user
    01631    * about it with a message. As we do not want the string to
    01632    * be translated by the translators, we 'force' it into the
    01633    * binary and 'load' it via a BindCString. To do this
    01634    * properly we have to set the colour of the string,
    01635    * otherwise we end up with a lot of artefacts. The colour
    01636    * 'character' might change in the future, so for safety
    01637    * we just Utf8 Encode it into the string, which takes
    01638    * exactly three characters, so it replaces the "XXX" with
    01639    * the colour marker.
    01640    */
    01641   if (_dynlang.text_dir != TD_LTR) {
    01642     static char *err_str = strdup("XXXThis version of OpenTTD does not support right-to-left languages. Recompile with icu enabled.");
    01643     Utf8Encode(err_str, SCC_YELLOW);
    01644     SetDParamStr(0, err_str);
    01645     ShowErrorMessage(STR_JUST_RAW_STRING, INVALID_STRING_ID, 0, 0);
    01646   }
    01647 #endif
    01648 }