# strings.cpp

Go to the documentation of this file.

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