# strings.cpp

Go to the documentation of this file.

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