# strings.cpp

Go to the documentation of this file.

    00001 /* $Id: strings.cpp 15474 2009-02-14 01:29:18Z rubidium $ */
    00002
    00005 #include "stdafx.h"
    00006 #include "openttd.h"
    00007 #include "currency.h"
    00008 #include "spritecache.h"
    00009 #include "namegen_func.h"
    00010 #include "station_base.h"
    00011 #include "town.h"
    00012 #include "screenshot.h"
    00013 #include "waypoint.h"
    00014 #include "industry.h"
    00015 #include "newgrf_text.h"
    00016 #include "music.h"
    00017 #include "fileio_func.h"
    00018 #include "group.h"
    00019 #include "newgrf_townname.h"
    00020 #include "signs_base.h"
    00021 #include "cargotype.h"
    00022 #include "fontcache.h"
    00023 #include "gui.h"
    00024 #include "strings_func.h"
    00025 #include "rev.h"
    00026 #include "core/endian_func.hpp"
    00027 #include "date_func.h"
    00028 #include "vehicle_base.h"
    00029 #include "company_func.h"
    00030 #include "video/video_driver.hpp"
    00031 #include "engine_base.h"
    00032 #include "strgen/strgen.h"
    00033
    00034 #include "table/strings.h"
    00035 #include "table/control_codes.h"
    00036
    00037 DynamicLanguages _dynlang;
    00038 uint64 _decode_parameters[20];
    00039
    00040 static char *StationGetSpecialString(char *buff, int x, const char *last);
    00041 static char *GetSpecialTownNameString(char *buff, int ind, uint32 seed, const char *last);
    00042 static char *GetSpecialNameString(char *buff, int ind, const int64 *argv, const char *last);
    00043
    00044 static char *FormatString(char *buff, const char *str, const int64 *argv, uint casei, const char *last);
    00045
    00046 struct LanguagePack : public LanguagePackHeader {
    00047   char data[VARARRAY_SIZE]; // list of strings
    00048 };
    00049
    00050 static char **_langpack_offs;
    00051 static LanguagePack *_langpack;
    00052 static uint _langtab_num[32];   // Offset into langpack offs
    00053 static uint _langtab_start[32]; // Offset into langpack offs
    00054
    00055
    00057 static inline int64 GetInt64(const int64 **argv)
    00058 {
    00059   assert(argv);
    00060   return *(*argv)++;
    00061 }
    00062
    00064 static inline int32 GetInt32(const int64 **argv)
    00065 {
    00066   return (int32)GetInt64(argv);
    00067 }
    00068
    00070 static inline const int64 *GetArgvPtr(const int64 **argv, int n)
    00071 {
    00072   const int64 *result;
    00073   assert(*argv);
    00074   result = *argv;
    00075   (*argv) += n;
    00076   return result;
    00077 }
    00078
    00079
    00080 const char *GetStringPtr(StringID string)
    00081 {
    00082   switch (GB(string, 11, 5)) {
    00083     case 28: return GetGRFStringPtr(GB(string, 0, 11));
    00084     case 29: return GetGRFStringPtr(GB(string, 0, 11) + 0x0800);
    00085     case 30: return GetGRFStringPtr(GB(string, 0, 11) + 0x1000);
    00086     default: return _langpack_offs[_langtab_start[string >> 11] + (string & 0x7FF)];
    00087   }
    00088 }
    00089
    00100 static char *GetStringWithArgs(char *buffr, uint string, const int64 *argv, const char *last)
    00101 {
    00102   if (GB(string, 0, 16) == 0) return GetStringWithArgs(buffr, STR_UNDEFINED, argv, last);
    00103
    00104   uint index = GB(string,  0, 11);
    00105   uint tab   = GB(string, 11,  5);
    00106
    00107   switch (tab) {
    00108     case 4:
    00109       if (index >= 0xC0)
    00110         return GetSpecialTownNameString(buffr, index - 0xC0, GetInt32(&argv), last);
    00111       break;
    00112
    00113     case 14:
    00114       if (index >= 0xE4)
    00115         return GetSpecialNameString(buffr, index - 0xE4, argv, last);
    00116       break;
    00117
    00118     case 15:
    00119       /* Old table for custom names. This is no longer used */
    00120       error("Incorrect conversion of custom name string.");
    00121
    00122     case 26:
    00123       /* Include string within newgrf text (format code 81) */
    00124       if (HasBit(index, 10)) {
    00125         StringID string = GetGRFStringID(0, 0xD000 + GB(index, 0, 10));
    00126         return GetStringWithArgs(buffr, string, argv, last);
    00127       }
    00128       break;
    00129
    00130     case 28:
    00131       return FormatString(buffr, GetGRFStringPtr(index), argv, 0, last);
    00132
    00133     case 29:
    00134       return FormatString(buffr, GetGRFStringPtr(index + 0x0800), argv, 0, last);
    00135
    00136     case 30:
    00137       return FormatString(buffr, GetGRFStringPtr(index + 0x1000), argv, 0, last);
    00138
    00139     case 31:
    00140       NOT_REACHED();
    00141   }
    00142
    00143   if (index >= _langtab_num[tab]) {
    00144     error(
    00145       "String 0x%X is invalid. "
    00146       "Probably because an old version of the .lng file.\n", string
    00147     );
    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
    00176 void InjectDParam(uint amount)
    00177 {
    00178   assert((uint)amount < lengthof(_decode_parameters));
    00179   memmove(_decode_parameters + amount, _decode_parameters, sizeof(_decode_parameters) - amount * sizeof(uint64));
    00180 }
    00181
    00182 // TODO
    00183 static char *FormatCommaNumber(char *buff, int64 number, const char *last)
    00184 {
    00185   uint64 divisor = 10000000000000000000ULL;
    00186   uint64 quot;
    00187   int i;
    00188   uint64 tot;
    00189   uint64 num;
    00190
    00191   if (number < 0) {
    00192     *buff++ = '-';
    00193     number = -number;
    00194   }
    00195
    00196   num = number;
    00197
    00198   tot = 0;
    00199   for (i = 0; i < 20; i++) {
    00200     quot = 0;
    00201     if (num >= divisor) {
    00202       quot = num / divisor;
    00203       num = num % divisor;
    00204     }
    00205     if (tot |= quot || i == 19) {
    00206       *buff++ = '0' + quot;
    00207       if ((i % 3) == 1 && i != 19) *buff++ = ',';
    00208     }
    00209
    00210     divisor /= 10;
    00211   }
    00212
    00213   *buff = '\0';
    00214
    00215   return buff;
    00216 }
    00217
    00218 // TODO
    00219 static char *FormatNoCommaNumber(char *buff, int64 number, const char *last)
    00220 {
    00221   uint64 divisor = 10000000000000000000ULL;
    00222   uint64 quot;
    00223   int i;
    00224   uint64 tot;
    00225   uint64 num;
    00226
    00227   if (number < 0) {
    00228     buff = strecpy(buff, "-", last);
    00229     number = -number;
    00230   }
    00231
    00232   num = number;
    00233
    00234   tot = 0;
    00235   for (i = 0; i < 20; i++) {
    00236     quot = 0;
    00237     if (num >= divisor) {
    00238       quot = num / divisor;
    00239       num = num % divisor;
    00240     }
    00241     if (tot |= quot || i == 19) {
    00242       *buff++ = '0' + quot;
    00243     }
    00244
    00245     divisor /= 10;
    00246   }
    00247
    00248   *buff = '\0';
    00249
    00250   return buff;
    00251 }
    00252
    00253 static char *FormatHexNumber(char *buff, int64 number, const char *last)
    00254 {
    00255   return buff + seprintf(buff, last, "0x%x", (uint32)number);
    00256 }
    00257
    00265 static char *FormatBytes(char *buff, int64 number, const char *last)
    00266 {
    00267   assert(number >= 0);
    00268
    00269   /*                         0    2^10   2^20   2^30   2^40   2^50   2^60 */
    00270   const char *siUnits[] = { "B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB" };
    00271   uint id = 1;
    00272   while (number >= 1024 * 1024) {
    00273     number /= 1024;
    00274     id++;
    00275   }
    00276
    00277   if (number < 1024) {
    00278     id = 0;
    00279     buff += seprintf(buff, last, "%i", (int)number);
    00280   } else if (number < 1024 * 10) {
    00281     buff += seprintf(buff, last, "%i.%02i", (int)number / 1024, (int)(number % 1024) * 100 / 1024);
    00282   } else if (number < 1024 * 100) {
    00283     buff += seprintf(buff, last, "%i.%01i", (int)number / 1024, (int)(number % 1024) * 10 / 1024);
    00284   } else {
    00285     assert(number < 1024 * 1024);
    00286     buff += seprintf(buff, last, "%i", (int)number / 1024);
    00287   }
    00288
    00289   assert(id < lengthof(siUnits));
    00290   buff += seprintf(buff, last, " %s", siUnits[id]);
    00291
    00292   return buff;
    00293 }
    00294
    00295 static char *FormatYmdString(char *buff, Date date, const char *last)
    00296 {
    00297   YearMonthDay ymd;
    00298   ConvertDateToYMD(date, &ymd);
    00299
    00300   int64 args[3] = { ymd.day + STR_01AC_1ST - 1, STR_0162_JAN + ymd.month, ymd.year };
    00301   return FormatString(buff, GetStringPtr(STR_DATE_LONG), args, 0, last);
    00302 }
    00303
    00304 static char *FormatMonthAndYear(char *buff, Date date, const char *last)
    00305 {
    00306   YearMonthDay ymd;
    00307   ConvertDateToYMD(date, &ymd);
    00308
    00309   int64 args[2] = { STR_MONTH_JAN + ymd.month, ymd.year };
    00310   return FormatString(buff, GetStringPtr(STR_DATE_SHORT), args, 0, last);
    00311 }
    00312
    00313 static char *FormatTinyOrISODate(char *buff, Date date, StringID str, const char *last)
    00314 {
    00315   YearMonthDay ymd;
    00316   ConvertDateToYMD(date, &ymd);
    00317
    00318   char day[3];
    00319   char month[3];
    00320   /* We want to zero-pad the days and months */
    00321   snprintf(day,   lengthof(day),   "%02i", ymd.day);
    00322   snprintf(month, lengthof(month), "%02i", ymd.month + 1);
    00323
    00324   int64 args[3] = { (int64)(size_t)day, (int64)(size_t)month, ymd.year };
    00325   return FormatString(buff, GetStringPtr(str), args, 0, last);
    00326 }
    00327
    00328 static char *FormatGenericCurrency(char *buff, const CurrencySpec *spec, Money number, bool compact, const char *last)
    00329 {
    00330   /* We are going to make number absolute for printing, so
    00331    * keep this piece of data as we need it later on */
    00332   bool negative = number < 0;
    00333   const char *multiplier = "";
    00334   char buf[40];
    00335   char *p;
    00336   int j;
    00337
    00338   number *= spec->rate;
    00339
    00340   /* convert from negative */
    00341   if (number < 0) {
    00342     if (buff + Utf8CharLen(SCC_RED) > last) return buff;
    00343     buff += Utf8Encode(buff, SCC_RED);
    00344     buff = strecpy(buff, "-", last);
    00345     number = -number;
    00346   }
    00347
    00348   /* Add prefix part, folowing symbol_pos specification.
    00349    * Here, it can can be either 0 (prefix) or 2 (both prefix anf suffix).
    00350    * The only remaining value is 1 (suffix), so everything that is not 1 */
    00351   if (spec->symbol_pos != 1) buff = strecpy(buff, spec->prefix, last);
    00352
    00353   /* for huge numbers, compact the number into k or M */
    00354   if (compact) {
    00355     if (number >= 1000000000) {
    00356       number = (number + 500000) / 1000000;
    00357       multiplier = "M";
    00358     } else if (number >= 1000000) {
    00359       number = (number + 500) / 1000;
    00360       multiplier = "k";
    00361     }
    00362   }
    00363
    00364   /* convert to ascii number and add commas */
    00365   p = endof(buf);
    00366   *--p = '\0';
    00367   j = 4;
    00368   do {
    00369     if (--j == 0) {
    00370       *--p = spec->separator;
    00371       j = 3;
    00372     }
    00373     *--p = '0' + (char)(number % 10);
    00374   } while ((number /= 10) != 0);
    00375   buff = strecpy(buff, p, last);
    00376
    00377   buff = strecpy(buff, multiplier, last);
    00378
    00379   /* Add suffix part, folowing symbol_pos specification.
    00380    * Here, it can can be either 1 (suffix) or 2 (both prefix anf suffix).
    00381    * The only remaining value is 1 (prefix), so everything that is not 0 */
    00382   if (spec->symbol_pos != 0) buff = strecpy(buff, spec->suffix, last);
    00383
    00384   if (negative) {
    00385     if (buff + Utf8CharLen(SCC_PREVIOUS_COLOUR) > last) return buff;
    00386     buff += Utf8Encode(buff, SCC_PREVIOUS_COLOUR);
    00387     *buff = '\0';
    00388   }
    00389
    00390   return buff;
    00391 }
    00392
    00393 static int DeterminePluralForm(int64 count)
    00394 {
    00395   /* The absolute value determines plurality */
    00396   uint64 n = abs(count);
    00397
    00398   switch (_langpack->plural_form) {
    00399     default:
    00400       NOT_REACHED();
    00401
    00402     /* Two forms, singular used for one only
    00403      * Used in:
    00404      *   Danish, Dutch, English, German, Norwegian, Swedish, Estonian, Finnish,
    00405      *   Greek, Hebrew, Italian, Portuguese, Spanish, Esperanto */
    00406     case 0:
    00407       return n != 1;
    00408
    00409     /* Only one form
    00410      * Used in:
    00411      *   Hungarian, Japanese, Korean, Turkish */
    00412     case 1:
    00413       return 0;
    00414
    00415     /* Two forms, singular used for zero and one
    00416      * Used in:
    00417      *   French, Brazilian Portuguese */
    00418     case 2:
    00419       return n > 1;
    00420
    00421     /* Three forms, special case for zero
    00422      * Used in:
    00423      *   Latvian */
    00424     case 3:
    00425       return n % 10 == 1 && n % 100 != 11 ? 0 : n != 0 ? 1 : 2;
    00426
    00427     /* Three forms, special case for one and two
    00428      * Used in:
    00429      *   Gaelige (Irish) */
    00430     case 4:
    00431       return n == 1 ? 0 : n == 2 ? 1 : 2;
    00432
    00433     /* Three forms, special case for numbers ending in 1[2-9]
    00434      * Used in:
    00435      *   Lithuanian */
    00436     case 5:
    00437       return n % 10 == 1 && n % 100 != 11 ? 0 : n % 10 >= 2 && (n % 100 < 10 || n % 100 >= 20) ? 1 : 2;
    00438
    00439     /* Three forms, special cases for numbers ending in 1 and 2, 3, 4, except those ending in 1[1-4]
    00440      * Used in:
    00441      *   Croatian, Czech, Russian, Slovak, Ukrainian */
    00442     case 6:
    00443       return n % 10 == 1 && n % 100 != 11 ? 0 : n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 10 || n % 100 >= 20) ? 1 : 2;
    00444
    00445     /* Three forms, special case for one and some numbers ending in 2, 3, or 4
    00446      * Used in:
    00447      *   Polish */
    00448     case 7:
    00449       return n == 1 ? 0 : n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 10 || n % 100 >= 20) ? 1 : 2;
    00450
    00451     /* Four forms, special case for one and all numbers ending in 02, 03, or 04
    00452      * Used in:
    00453      *   Slovenian */
    00454     case 8:
    00455       return n % 100 == 1 ? 0 : n % 100 == 2 ? 1 : n % 100 == 3 || n % 100 == 4 ? 2 : 3;
    00456
    00457     /* Two forms; singular used for everything ending in 1 but not in 11.
    00458      * Used in:
    00459      *   Icelandic */
    00460     case 9:
    00461       return n % 10 == 1 && n % 100 != 11 ? 0 : 1;
    00462   }
    00463 }
    00464
    00465 static const char *ParseStringChoice(const char *b, uint form, char *dst, int *dstlen)
    00466 {
    00467   //<NUM> {Length of each string} {each string}
    00468   uint n = (byte)*b++;
    00469   uint pos, i, mylen = 0, mypos = 0;
    00470
    00471   for (i = pos = 0; i != n; i++) {
    00472     uint len = (byte)*b++;
    00473     if (i == form) {
    00474       mypos = pos;
    00475       mylen = len;
    00476     }
    00477     pos += len;
    00478   }
    00479   *dstlen = mylen;
    00480   memcpy(dst, b + mypos, mylen);
    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, const int64 *argv, uint casei, const char *last)
    00550 {
    00551   WChar b;
    00552   const 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, (int64*)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 = GetCargo(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 = GetIndustry(GetInt32(&argv));
    00698         int64 args[2];
    00699
    00700         /* industry not valid anymore? */
    00701         if (!i->IsValid()) break;
    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_INDUSTRY_FORMAT), 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 len;
    00723         int gender = 0;
    00724         if (s != NULL) {
    00725           wchar_t c = Utf8Consume(&s);
    00726           /* Switch case is always put before genders, so remove those bits */
    00727           if (c == SCC_SWITCH_CASE) {
    00728             /* Skip to the last (i.e. default) case */
    00729             for (uint num = (byte)*s++; num != 0; num--) s += 3 + (s[1] << 8) + s[2];
    00730
    00731             c = Utf8Consume(&s);
    00732           }
    00733           /* Does this string have a gender, if so, set it */
    00734           if (c == SCC_GENDER_INDEX) gender = (byte)s[0];
    00735         }
    00736         str = ParseStringChoice(str, gender, buff, &len);
    00737         buff += len;
    00738         break;
    00739       }
    00740
    00741       case SCC_DATE_TINY: { // {DATE_TINY}
    00742         buff = FormatTinyOrISODate(buff, GetInt32(&argv), STR_DATE_TINY, last);
    00743         break;
    00744       }
    00745
    00746       case SCC_DATE_ISO: { // {DATE_ISO}
    00747         buff = FormatTinyOrISODate(buff, GetInt32(&argv), STR_DATE_ISO, last);
    00748         break;
    00749       }
    00750
    00751       case SCC_CARGO: { // {CARGO}
    00752         /* Layout now is:
    00753          *   8bit   - cargo type
    00754          *   16-bit - cargo count */
    00755         CargoID cargo = GetInt32(&argv);
    00756         StringID cargo_str = (cargo == CT_INVALID) ? STR_8838_N_A : GetCargo(cargo)->quantifier;
    00757         buff = GetStringWithArgs(buff, cargo_str, argv++, last);
    00758         break;
    00759       }
    00760
    00761       case SCC_POWER: { // {POWER}
    00762         int64 args[1];
    00763         assert(_settings_game.locale.units < lengthof(units));
    00764         args[0] = GetInt32(&argv) * units[_settings_game.locale.units].p_m >> units[_settings_game.locale.units].p_s;
    00765         buff = FormatString(buff, GetStringPtr(units[_settings_game.locale.units].power), args, modifier >> 24, last);
    00766         modifier = 0;
    00767         break;
    00768       }
    00769
    00770       case SCC_VOLUME_SHORT: { // {VOLUME_S}
    00771         int64 args[1];
    00772         assert(_settings_game.locale.units < lengthof(units));
    00773         args[0] = GetInt32(&argv) * units[_settings_game.locale.units].v_m >> units[_settings_game.locale.units].v_s;
    00774         buff = FormatString(buff, GetStringPtr(units[_settings_game.locale.units].s_volume), args, modifier >> 24, last);
    00775         modifier = 0;
    00776         break;
    00777       }
    00778
    00779       case SCC_WEIGHT: { // {WEIGHT}
    00780         int64 args[1];
    00781         assert(_settings_game.locale.units < lengthof(units));
    00782         args[0] = GetInt32(&argv) * units[_settings_game.locale.units].w_m >> units[_settings_game.locale.units].w_s;
    00783         buff = FormatString(buff, GetStringPtr(units[_settings_game.locale.units].l_weight), args, modifier >> 24, last);
    00784         modifier = 0;
    00785         break;
    00786       }
    00787
    00788       case SCC_WEIGHT_SHORT: { // {WEIGHT_S}
    00789         int64 args[1];
    00790         assert(_settings_game.locale.units < lengthof(units));
    00791         args[0] = GetInt32(&argv) * units[_settings_game.locale.units].w_m >> units[_settings_game.locale.units].w_s;
    00792         buff = FormatString(buff, GetStringPtr(units[_settings_game.locale.units].s_weight), args, modifier >> 24, last);
    00793         modifier = 0;
    00794         break;
    00795       }
    00796
    00797       case SCC_FORCE: { // {FORCE}
    00798         int64 args[1];
    00799         assert(_settings_game.locale.units < lengthof(units));
    00800         args[0] = GetInt32(&argv) * units[_settings_game.locale.units].f_m >> units[_settings_game.locale.units].f_s;
    00801         buff = FormatString(buff, GetStringPtr(units[_settings_game.locale.units].force), args, modifier >> 24, last);
    00802         modifier = 0;
    00803         break;
    00804       }
    00805
    00806       case SCC_SKIP: // {SKIP}
    00807         argv++;
    00808         break;
    00809
    00810       /* This sets up the gender for the string.
    00811        * We just ignore this one. It's used in {G 0 Der Die Das} to determine the case. */
    00812       case SCC_GENDER_INDEX: // {GENDER 0}
    00813         str++;
    00814         break;
    00815
    00816       case SCC_STRING: {// {STRING}
    00817         uint str = modifier + GetInt32(&argv);
    00818         /* WARNING. It's prohibited for the included string to consume any arguments.
    00819          * For included strings that consume argument, you should use STRING1, STRING2 etc.
    00820          * To debug stuff you can set argv to NULL and it will tell you */
    00821         buff = GetStringWithArgs(buff, str, argv, last);
    00822         modifier = 0;
    00823         break;
    00824       }
    00825
    00826       case SCC_COMMA: // {COMMA}
    00827         buff = FormatCommaNumber(buff, GetInt64(&argv), last);
    00828         break;
    00829
    00830       case SCC_ARG_INDEX: // Move argument pointer
    00831         argv = argv_orig + (byte)*str++;
    00832         break;
    00833
    00834       case SCC_PLURAL_LIST: { // {P}
    00835         int64 v = argv_orig[(byte)*str++]; // contains the number that determines plural
    00836         int len;
    00837         str = ParseStringChoice(str, DeterminePluralForm(v), buff, &len);
    00838         buff += len;
    00839         break;
    00840       }
    00841
    00842       case SCC_NUM: // {NUM}
    00843         buff = FormatNoCommaNumber(buff, GetInt64(&argv), last);
    00844         break;
    00845
    00846       case SCC_HEX: // {HEX}
    00847         buff = FormatHexNumber(buff, GetInt64(&argv), last);
    00848         break;
    00849
    00850       case SCC_BYTES: // {BYTES}
    00851         buff = FormatBytes(buff, GetInt64(&argv), last);
    00852         break;
    00853
    00854       case SCC_CURRENCY: // {CURRENCY}
    00855         buff = FormatGenericCurrency(buff, _currency, GetInt64(&argv), false, last);
    00856         break;
    00857
    00858       case SCC_WAYPOINT_NAME: { // {WAYPOINT}
    00859         Waypoint *wp = GetWaypoint(GetInt32(&argv));
    00860
    00861         assert(wp->IsValid());
    00862
    00863         if (wp->name != NULL) {
    00864           buff = strecpy(buff, wp->name, last);
    00865         } else {
    00866           int64 temp[2];
    00867           temp[0] = wp->town_index;
    00868           temp[1] = wp->town_cn + 1;
    00869           StringID str = wp->town_cn == 0 ? STR_WAYPOINTNAME_CITY : STR_WAYPOINTNAME_CITY_SERIAL;
    00870
    00871           buff = GetStringWithArgs(buff, str, temp, last);
    00872         }
    00873         break;
    00874       }
    00875
    00876       case SCC_STATION_NAME: { // {STATION}
    00877         StationID sid = GetInt32(&argv);
    00878
    00879         if (!IsValidStationID(sid)) {
    00880           /* The station doesn't exist anymore. The only place where we might
    00881            * be "drawing" an invalid station is in the case of cargo that is
    00882            * in transit. */
    00883           buff = GetStringWithArgs(buff, STR_UNKNOWN_STATION, NULL, last);
    00884           break;
    00885         }
    00886
    00887         const Station *st = GetStation(sid);
    00888         if (st->name != NULL) {
    00889           buff = strecpy(buff, st->name, last);
    00890         } else {
    00891           StringID str = st->string_id;
    00892           if (st->indtype != IT_INVALID) {
    00893             /* Special case where the industry provides the name for the station */
    00894             const IndustrySpec *indsp = GetIndustrySpec(st->indtype);
    00895
    00896             /* Industry GRFs can change which might remove the station name and
    00897              * thus cause very strange things. Here we check for that before we
    00898              * actually set the station name. */
    00899             if (indsp->station_name != STR_NULL && indsp->station_name != STR_UNDEFINED) {
    00900               str = indsp->station_name;
    00901             }
    00902           }
    00903
    00904           int64 temp[3];
    00905           temp[0] = STR_TOWN;
    00906           temp[1] = st->town->index;
    00907           temp[2] = st->index;
    00908           buff = GetStringWithArgs(buff, str, temp, last);
    00909         }
    00910         break;
    00911       }
    00912
    00913       case SCC_TOWN_NAME: { // {TOWN}
    00914         const Town *t = GetTown(GetInt32(&argv));
    00915         int64 temp[1];
    00916
    00917         assert(t->IsValid());
    00918
    00919         temp[0] = t->townnameparts;
    00920         uint32 grfid = t->townnamegrfid;
    00921
    00922         if (t->name != NULL) {
    00923           buff = strecpy(buff, t->name, last);
    00924         } else if (grfid == 0) {
    00925           /* Original town name */
    00926           buff = GetStringWithArgs(buff, t->townnametype, temp, last);
    00927         } else {
    00928           /* Newgrf town name */
    00929           if (GetGRFTownName(grfid) != NULL) {
    00930             /* The grf is loaded */
    00931             buff = GRFTownNameGenerate(buff, t->townnamegrfid, t->townnametype, t->townnameparts, last);
    00932           } else {
    00933             /* Fallback to english original */
    00934             buff = GetStringWithArgs(buff, SPECSTR_TOWNNAME_ENGLISH, temp, last);
    00935           }
    00936         }
    00937         break;
    00938       }
    00939
    00940       case SCC_GROUP_NAME: { // {GROUP}
    00941         const Group *g = GetGroup(GetInt32(&argv));
    00942
    00943         assert(g->IsValid());
    00944
    00945         if (g->name != NULL) {
    00946           buff = strecpy(buff, g->name, last);
    00947         } else {
    00948           int64 args[1];
    00949
    00950           args[0] = g->index;
    00951           buff = GetStringWithArgs(buff, STR_GROUP_NAME_FORMAT, args, last);
    00952         }
    00953         break;
    00954       }
    00955
    00956       case SCC_ENGINE_NAME: { // {ENGINE}
    00957         EngineID engine = (EngineID)GetInt32(&argv);
    00958         const Engine *e = GetEngine(engine);
    00959
    00960         if (e->name != NULL) {
    00961           buff = strecpy(buff, e->name, last);
    00962         } else {
    00963           buff = GetStringWithArgs(buff, e->info.string_id, NULL, last);
    00964         }
    00965         break;
    00966       }
    00967
    00968       case SCC_VEHICLE_NAME: { // {VEHICLE}
    00969         const Vehicle *v = GetVehicle(GetInt32(&argv));
    00970
    00971         if (v->name != NULL) {
    00972           buff = strecpy(buff, v->name, last);
    00973         } else {
    00974           int64 args[1];
    00975           args[0] = v->unitnumber;
    00976
    00977           StringID str;
    00978           switch (v->type) {
    00979             default: NOT_REACHED();
    00980             case VEH_TRAIN:    str = STR_SV_TRAIN_NAME; break;
    00981             case VEH_ROAD:     str = STR_SV_ROADVEH_NAME; break;
    00982             case VEH_SHIP:     str = STR_SV_SHIP_NAME; break;
    00983             case VEH_AIRCRAFT: str = STR_SV_AIRCRAFT_NAME; break;
    00984           }
    00985
    00986           buff = GetStringWithArgs(buff, str, args, last);
    00987         }
    00988         break;
    00989       }
    00990
    00991       case SCC_SIGN_NAME: { // {SIGN}
    00992         const Sign *si = GetSign(GetInt32(&argv));
    00993         if (si->name != NULL) {
    00994           buff = strecpy(buff, si->name, last);
    00995         } else {
    00996           buff = GetStringWithArgs(buff, STR_280A_SIGN, NULL, last);
    00997         }
    00998         break;
    00999       }
    01000
    01001       case SCC_COMPANY_NAME: { // {COMPANY}
    01002         const Company *c = GetCompany((CompanyID)GetInt32(&argv));
    01003
    01004         if (c->name != NULL) {
    01005           buff = strecpy(buff, c->name, last);
    01006         } else {
    01007           int64 args[1];
    01008           args[0] = c->name_2;
    01009           buff = GetStringWithArgs(buff, c->name_1, args, last);
    01010         }
    01011         break;
    01012       }
    01013
    01014       case SCC_COMPANY_NUM: { // {COMPANYNUM}
    01015         CompanyID company = (CompanyID)GetInt32(&argv);
    01016
    01017         /* Nothing is added for AI or inactive companies */
    01018         if (IsValidCompanyID(company) && IsHumanCompany(company)) {
    01019           int64 args[1];
    01020           args[0] = company + 1;
    01021           buff = GetStringWithArgs(buff, STR_7002_COMPANY, args, last);
    01022         }
    01023         break;
    01024       }
    01025
    01026       case SCC_PRESIDENT_NAME: { // {PRESIDENTNAME}
    01027         const Company *c = GetCompany((CompanyID)GetInt32(&argv));
    01028
    01029         if (c->president_name != NULL) {
    01030           buff = strecpy(buff, c->president_name, last);
    01031         } else {
    01032           int64 args[1];
    01033           args[0] = c->president_name_2;
    01034           buff = GetStringWithArgs(buff, c->president_name_1, args, last);
    01035         }
    01036         break;
    01037       }
    01038
    01039       case SCC_SETCASE: { // {SETCASE}
    01040         /* This is a pseudo command, it's outputted when someone does {STRING.ack}
    01041          * The modifier is added to all subsequent GetStringWithArgs that accept the modifier. */
    01042         modifier = (byte)*str++ << 24;
    01043         break;
    01044       }
    01045
    01046       case SCC_SWITCH_CASE: { // {Used to implement case switching}
    01047         /* <0x9E> <NUM CASES> <CASE1> <LEN1> <STRING1> <CASE2> <LEN2> <STRING2> <CASE3> <LEN3> <STRING3> <STRINGDEFAULT>
    01048          * Each LEN is printed using 2 bytes in big endian order. */
    01049         uint num = (byte)*str++;
    01050         while (num) {
    01051           if ((byte)str[0] == casei) {
    01052             /* Found the case, adjust str pointer and continue */
    01053             str += 3;
    01054             break;
    01055           }
    01056           /* Otherwise skip to the next case */
    01057           str += 3 + (str[1] << 8) + str[2];
    01058           num--;
    01059         }
    01060         break;
    01061       }
    01062
    01063       default:
    01064         if (buff + Utf8CharLen(b) < last) buff += Utf8Encode(buff, b);
    01065         break;
    01066     }
    01067   }
    01068   *buff = '\0';
    01069   return buff;
    01070 }
    01071
    01072
    01073 static char *StationGetSpecialString(char *buff, int x, const char *last)
    01074 {
    01075   if ((x & FACIL_TRAIN)      && (buff + Utf8CharLen(SCC_TRAIN) < last)) buff += Utf8Encode(buff, SCC_TRAIN);
    01076   if ((x & FACIL_TRUCK_STOP) && (buff + Utf8CharLen(SCC_LORRY) < last)) buff += Utf8Encode(buff, SCC_LORRY);
    01077   if ((x & FACIL_BUS_STOP)   && (buff + Utf8CharLen(SCC_BUS)   < last)) buff += Utf8Encode(buff, SCC_BUS);
    01078   if ((x & FACIL_AIRPORT)    && (buff + Utf8CharLen(SCC_PLANE) < last)) buff += Utf8Encode(buff, SCC_PLANE);
    01079   if ((x & FACIL_DOCK)       && (buff + Utf8CharLen(SCC_SHIP)  < last)) buff += Utf8Encode(buff, SCC_SHIP);
    01080   *buff = '\0';
    01081   return buff;
    01082 }
    01083
    01084 static char *GetSpecialTownNameString(char *buff, int ind, uint32 seed, const char *last)
    01085 {
    01086   char name[512];
    01087
    01088   _town_name_generators[ind](name, seed, lastof(name));
    01089   return strecpy(buff, name, last);
    01090 }
    01091
    01092 static const char * const _silly_company_names[] = {
    01093   "Bloggs Brothers",
    01094   "Tiny Transport Ltd.",
    01095   "Express Travel",
    01096   "Comfy-Coach & Co.",
    01097   "Crush & Bump Ltd.",
    01098   "Broken & Late Ltd.",
    01099   "Sam Speedy & Son",
    01100   "Supersonic Travel",
    01101   "Mike's Motors",
    01102   "Lightning International",
    01103   "Pannik & Loozit Ltd.",
    01104   "Inter-City Transport",
    01105   "Getout & Pushit Ltd."
    01106 };
    01107
    01108 static const char * const _surname_list[] = {
    01109   "Adams",
    01110   "Allan",
    01111   "Baker",
    01112   "Bigwig",
    01113   "Black",
    01114   "Bloggs",
    01115   "Brown",
    01116   "Campbell",
    01117   "Gordon",
    01118   "Hamilton",
    01119   "Hawthorn",
    01120   "Higgins",
    01121   "Green",
    01122   "Gribble",
    01123   "Jones",
    01124   "McAlpine",
    01125   "MacDonald",
    01126   "McIntosh",
    01127   "Muir",
    01128   "Murphy",
    01129   "Nelson",
    01130   "O'Donnell",
    01131   "Parker",
    01132   "Phillips",
    01133   "Pilkington",
    01134   "Quigley",
    01135   "Sharkey",
    01136   "Thomson",
    01137   "Watkins"
    01138 };
    01139
    01140 static const char * const _silly_surname_list[] = {
    01141   "Grumpy",
    01142   "Dozy",
    01143   "Speedy",
    01144   "Nosey",
    01145   "Dribble",
    01146   "Mushroom",
    01147   "Cabbage",
    01148   "Sniffle",
    01149   "Fishy",
    01150   "Swindle",
    01151   "Sneaky",
    01152   "Nutkins"
    01153 };
    01154
    01155 static const char _initial_name_letters[] = {
    01156   'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
    01157   'K', 'L', 'M', 'N', 'P', 'R', 'S', 'T', 'W',
    01158 };
    01159
    01160 static char *GenAndCoName(char *buff, uint32 arg, const char *last)
    01161 {
    01162   const char * const *base;
    01163   uint num;
    01164
    01165   if (_settings_game.game_creation.landscape == LT_TOYLAND) {
    01166     base = _silly_surname_list;
    01167     num  = lengthof(_silly_surname_list);
    01168   } else {
    01169     base = _surname_list;
    01170     num  = lengthof(_surname_list);
    01171   }
    01172
    01173   buff = strecpy(buff, base[num * GB(arg, 16, 8) >> 8], last);
    01174   buff = strecpy(buff, " & Co.", last);
    01175
    01176   return buff;
    01177 }
    01178
    01179 static char *GenPresidentName(char *buff, uint32 x, const char *last)
    01180 {
    01181   char initial[] = "?. ";
    01182   const char * const *base;
    01183   uint num;
    01184   uint i;
    01185
    01186   initial[0] = _initial_name_letters[sizeof(_initial_name_letters) * GB(x, 0, 8) >> 8];
    01187   buff = strecpy(buff, initial, last);
    01188
    01189   i = (sizeof(_initial_name_letters) + 35) * GB(x, 8, 8) >> 8;
    01190   if (i < sizeof(_initial_name_letters)) {
    01191     initial[0] = _initial_name_letters[i];
    01192     buff = strecpy(buff, initial, last);
    01193   }
    01194
    01195   if (_settings_game.game_creation.landscape == LT_TOYLAND) {
    01196     base = _silly_surname_list;
    01197     num  = lengthof(_silly_surname_list);
    01198   } else {
    01199     base = _surname_list;
    01200     num  = lengthof(_surname_list);
    01201   }
    01202
    01203   buff = strecpy(buff, base[num * GB(x, 16, 8) >> 8], last);
    01204
    01205   return buff;
    01206 }
    01207
    01208 static char *GetSpecialNameString(char *buff, int ind, const int64 *argv, const char *last)
    01209 {
    01210   switch (ind) {
    01211     case 1: // not used
    01212       return strecpy(buff, _silly_company_names[GetInt32(&argv) & 0xFFFF], last);
    01213
    01214     case 2: // used for Foobar & Co company names
    01215       return GenAndCoName(buff, GetInt32(&argv), last);
    01216
    01217     case 3: // President name
    01218       return GenPresidentName(buff, GetInt32(&argv), last);
    01219
    01220     case 4: // song names
    01221       return strecpy(buff, _origin_songs_specs[GetInt32(&argv) - 1].song_name, last);
    01222   }
    01223
    01224   /* town name? */
    01225   if (IsInsideMM(ind - 6, 0, SPECSTR_TOWNNAME_LAST - SPECSTR_TOWNNAME_START + 1)) {
    01226     buff = GetSpecialTownNameString(buff, ind - 6, GetInt32(&argv), last);
    01227     return strecpy(buff, " Transport", last);
    01228   }
    01229
    01230   /* language name? */
    01231   if (IsInsideMM(ind, (SPECSTR_LANGUAGE_START - 0x70E4), (SPECSTR_LANGUAGE_END - 0x70E4) + 1)) {
    01232     int i = ind - (SPECSTR_LANGUAGE_START - 0x70E4);
    01233     return strecpy(buff,
    01234       i == _dynlang.curr ? _langpack->own_name : _dynlang.ent[i].name, last);
    01235   }
    01236
    01237   /* resolution size? */
    01238   if (IsInsideMM(ind, (SPECSTR_RESOLUTION_START - 0x70E4), (SPECSTR_RESOLUTION_END - 0x70E4) + 1)) {
    01239     int i = ind - (SPECSTR_RESOLUTION_START - 0x70E4);
    01240     buff += seprintf(
    01241       buff, last, "%dx%d", _resolutions[i].width, _resolutions[i].height
    01242     );
    01243     return buff;
    01244   }
    01245
    01246   /* screenshot format name? */
    01247   if (IsInsideMM(ind, (SPECSTR_SCREENSHOT_START - 0x70E4), (SPECSTR_SCREENSHOT_END - 0x70E4) + 1)) {
    01248     int i = ind - (SPECSTR_SCREENSHOT_START - 0x70E4);
    01249     return strecpy(buff, GetScreenshotFormatDesc(i), last);
    01250   }
    01251
    01252   assert(0);
    01253   return NULL;
    01254 }
    01255
    01256 #ifdef ENABLE_NETWORK
    01257 extern void SortNetworkLanguages();
    01258 #else /* ENABLE_NETWORK */
    01259 static inline void SortNetworkLanguages() {}
    01260 #endif /* ENABLE_NETWORK */
    01261
    01262 bool ReadLanguagePack(int lang_index)
    01263 {
    01264   int tot_count, i;
    01265   size_t len;
    01266   char **langpack_offs;
    01267   char *s;
    01268
    01269   LanguagePack *lang_pack = (LanguagePack*)ReadFileToMem(_dynlang.ent[lang_index].file, &len, 200000);
    01270
    01271   if (lang_pack == NULL) return false;
    01272   if (len < sizeof(LanguagePack) ||
    01273       lang_pack->ident != TO_LE32(LANGUAGE_PACK_IDENT) ||
    01274       lang_pack->version != TO_LE32(LANGUAGE_PACK_VERSION)) {
    01275     free(lang_pack);
    01276     return false;
    01277   }
    01278
    01279 #if TTD_ENDIAN == TTD_BIG_ENDIAN
    01280   for (i = 0; i != 32; i++) {
    01281     lang_pack->offsets[i] = ReadLE16Aligned(&lang_pack->offsets[i]);
    01282   }
    01283 #endif /* TTD_ENDIAN == TTD_BIG_ENDIAN */
    01284
    01285   tot_count = 0;
    01286   for (i = 0; i != 32; i++) {
    01287     uint num = lang_pack->offsets[i];
    01288     _langtab_start[i] = tot_count;
    01289     _langtab_num[i] = num;
    01290     tot_count += num;
    01291   }
    01292
    01293   /* Allocate offsets */
    01294   langpack_offs = MallocT<char*>(tot_count);
    01295
    01296   /* Fill offsets */
    01297   s = lang_pack->data;
    01298   for (i = 0; i != tot_count; i++) {
    01299     len = (byte)*s;
    01300     *s++ = '\0'; // zero terminate the string before.
    01301     if (len >= 0xC0) len = ((len & 0x3F) << 8) + (byte)*s++;
    01302     langpack_offs[i] = s;
    01303     s += len;
    01304   }
    01305
    01306   free(_langpack);
    01307   _langpack = lang_pack;
    01308
    01309   free(_langpack_offs);
    01310   _langpack_offs = langpack_offs;
    01311
    01312   const char *c_file = strrchr(_dynlang.ent[lang_index].file, PATHSEPCHAR) + 1;
    01313   strecpy(_dynlang.curr_file, c_file, lastof(_dynlang.curr_file));
    01314
    01315   _dynlang.curr = lang_index;
    01316   _dynlang.text_dir = (TextDirection)lang_pack->text_dir;
    01317   SetCurrentGrfLangID(_langpack->isocode);
    01318   SortNetworkLanguages();
    01319   return true;
    01320 }
    01321
    01322 /* Win32 implementation in win32.cpp. */
    01323 /* OS X implementation in os/macosx/macos.mm. */
    01324 #if !(defined(WIN32) || defined(__APPLE__))
    01325
    01331 const char *GetCurrentLocale(const char *param)
    01332 {
    01333   const char *env;
    01334
    01335   env = getenv("LANGUAGE");
    01336   if (env != NULL) return env;
    01337
    01338   env = getenv("LC_ALL");
    01339   if (env != NULL) return env;
    01340
    01341   if (param != NULL) {
    01342     env = getenv(param);
    01343     if (env != NULL) return env;
    01344   }
    01345
    01346   return getenv("LANG");
    01347 }
    01348 #else
    01349 const char *GetCurrentLocale(const char *param);
    01350 #endif /* !(defined(WIN32) || defined(__APPLE__)) */
    01351
    01352 int CDECL StringIDSorter(const void *a, const void *b)
    01353 {
    01354   const StringID va = *(const StringID*)a;
    01355   const StringID vb = *(const StringID*)b;
    01356   char stra[512];
    01357   char strb[512];
    01358   GetString(stra, va, lastof(stra));
    01359   GetString(strb, vb, lastof(strb));
    01360
    01361   return strcmp(stra, strb);
    01362 }
    01363
    01371 static bool UniqueLanguageFile(const Language *langs, uint max, const char *language)
    01372 {
    01373   for (uint i = 0; i < max; i++) {
    01374     const char *f_name = strrchr(langs[i].file, PATHSEPCHAR) + 1;
    01375     if (strcmp(f_name, language) == 0) return false; // duplicates
    01376   }
    01377
    01378   return true;
    01379 }
    01380
    01387 static bool GetLanguageFileHeader(const char *file, LanguagePack *hdr)
    01388 {
    01389   FILE *f = fopen(file, "rb");
    01390   if (f == NULL) return false;
    01391
    01392   size_t read = fread(hdr, sizeof(*hdr), 1, f);
    01393   fclose(f);
    01394
    01395   bool ret = read == 1 &&
    01396       hdr->ident == TO_LE32(LANGUAGE_PACK_IDENT) &&
    01397       hdr->version == TO_LE32(LANGUAGE_PACK_VERSION);
    01398
    01399   /* Convert endianness for the windows language ID */
    01400   if (ret) hdr->winlangid = FROM_LE16(hdr->winlangid);
    01401   return ret;
    01402 }
    01403
    01412 static int GetLanguageList(Language *langs, int start, int max, const char *path)
    01413 {
    01414   int i = start;
    01415
    01416   DIR *dir = ttd_opendir(path);
    01417   if (dir != NULL) {
    01418     struct dirent *dirent;
    01419     while ((dirent = readdir(dir)) != NULL && i < max) {
    01420       const char *d_name    = FS2OTTD(dirent->d_name);
    01421       const char *extension = strrchr(d_name, '.');
    01422
    01423       /* Not a language file */
    01424       if (extension == NULL || strcmp(extension, ".lng") != 0) continue;
    01425
    01426       /* Filter any duplicate language-files, first-come first-serve */
    01427       if (!UniqueLanguageFile(langs, i, d_name)) continue;
    01428
    01429       langs[i].file = str_fmt("%s%s", path, d_name);
    01430
    01431       /* Check whether the file is of the correct version */
    01432       LanguagePack hdr;
    01433       if (!GetLanguageFileHeader(langs[i].file, &hdr)) {
    01434         free(langs[i].file);
    01435         continue;
    01436       }
    01437
    01438       i++;
    01439     }
    01440     closedir(dir);
    01441   }
    01442   return i - start;
    01443 }
    01444
    01449 void InitializeLanguagePacks()
    01450 {
    01451   Searchpath sp;
    01452   Language files[MAX_LANG];
    01453   uint language_count = 0;
    01454
    01455   FOR_ALL_SEARCHPATHS(sp) {
    01456     char path[MAX_PATH];
    01457     FioAppendDirectory(path, lengthof(path), sp, LANG_DIR);
    01458     language_count += GetLanguageList(files, language_count, lengthof(files), path);
    01459   }
    01460   if (language_count == 0) usererror("No available language packs (invalid versions?)");
    01461
    01462   /* Acquire the locale of the current system */
    01463   const char *lang = GetCurrentLocale("LC_MESSAGES");
    01464   if (lang == NULL) lang = "en_GB";
    01465
    01466   int chosen_language   = -1;
    01467   int language_fallback = -1;
    01468   int en_GB_fallback    =  0;
    01469
    01470   DynamicLanguages *dl = &_dynlang;
    01471   dl->num = 0;
    01472   /* Fill the dynamic languages structures */
    01473   for (uint i = 0; i < language_count; i++) {
    01474     /* File read the language header */
    01475     LanguagePack hdr;
    01476     if (!GetLanguageFileHeader(files[i].file, &hdr)) continue;
    01477
    01478     dl->ent[dl->num].file = files[i].file;
    01479     dl->ent[dl->num].name = strdup(hdr.name);
    01480
    01481     /* We are trying to find a default language. The priority is by
    01482      * configuration file, local environment and last, if nothing found,
    01483      * english. If def equals -1, we have not picked a default language */
    01484     const char *lang_file = strrchr(dl->ent[dl->num].file, PATHSEPCHAR) + 1;
    01485     if (strcmp(lang_file, dl->curr_file) == 0) chosen_language = dl->num;
    01486
    01487     if (chosen_language == -1) {
    01488       if (strcmp (hdr.isocode, "en_GB") == 0) en_GB_fallback    = dl->num;
    01489       if (strncmp(hdr.isocode, lang, 5) == 0) chosen_language   = dl->num;
    01490       if (strncmp(hdr.isocode, lang, 2) == 0) language_fallback = dl->num;
    01491     }
    01492
    01493     dl->num++;
    01494   }
    01495
    01496   if (dl->num == 0) usererror("Invalid version of language packs");
    01497
    01498   /* We haven't found the language in the config nor the one in the locale.
    01499    * Now we set it to one of the fallback languages */
    01500   if (chosen_language == -1) {
    01501     chosen_language = (language_fallback != -1) ? language_fallback : en_GB_fallback;
    01502   }
    01503
    01504   if (!ReadLanguagePack(chosen_language)) usererror("Can't read language pack '%s'", dl->ent[chosen_language].file);
    01505 }
    01506
    01517 void CheckForMissingGlyphsInLoadedLanguagePack()
    01518 {
    01519 #ifdef WITH_FREETYPE
    01520   /* Reset to the original state; switching languages might cause us to
    01521    * automatically choose another font. This resets that choice. */
    01522   UninitFreeType();
    01523   InitFreeType();
    01524   bool retry = false;
    01525 #endif
    01526
    01527   for (;;) {
    01528     const Sprite *question_mark = GetGlyph(FS_NORMAL, '?');
    01529
    01530     for (uint i = 0; i != 32; i++) {
    01531       for (uint j = 0; j < _langtab_num[i]; j++) {
    01532         const char *string = _langpack_offs[_langtab_start[i] + j];
    01533         WChar c;
    01534         while ((c = Utf8Consume(&string)) != '\0') {
    01535           if (c == SCC_SETX) {
    01536             /*
    01537              * SetX is, together with SetXY as special character that
    01538              * uses the next (two) characters as data points. We have
    01539              * to skip those, otherwise the UTF8 reading will go
    01540              * haywire.
    01541              */
    01542             string++;
    01543           } else if (c == SCC_SETXY) {
    01544             string += 2;
    01545           } else if (IsPrintable(c) && c != '?' && GetGlyph(FS_NORMAL, c) == question_mark) {
    01546 #ifdef WITH_FREETYPE
    01547             if (!retry) {
    01548               /* We found an unprintable character... lets try whether we can
    01549                * find a fallback font that can print the characters in the
    01550                * current language. */
    01551               retry = true;
    01552
    01553               FreeTypeSettings backup;
    01554               memcpy(&backup, &_freetype, sizeof(backup));
    01555
    01556               bool success = SetFallbackFont(&_freetype, _langpack->isocode, _langpack->winlangid);
    01557               if (success) {
    01558                 UninitFreeType();
    01559                 InitFreeType();
    01560               }
    01561
    01562               memcpy(&_freetype, &backup, sizeof(backup));
    01563
    01564               if (success) continue;
    01565             } else {
    01566               /* Our fallback font does miss characters too, so keep the
    01567                * user chosen font as that is more likely to be any good than
    01568                * the wild guess we made */
    01569               UninitFreeType();
    01570               InitFreeType();
    01571             }
    01572 #endif
    01573             /*
    01574              * The character is printable, but not in the normal font.
    01575              * This is the case we were testing for. In this case we
    01576              * have to show the error. As we do not want the string to
    01577              * be translated by the translators, we 'force' it into the
    01578              * binary and 'load' it via a BindCString. To do this
    01579              * properly we have to set the colour of the string,
    01580              * otherwise we end up with a lot of artefacts. The colour
    01581              * 'character' might change in the future, so for safety
    01582              * we just Utf8 Encode it into the string, which takes
    01583              * exactly three characters, so it replaces the "XXX" with
    01584              * the colour marker.
    01585              */
    01586             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.");
    01587             Utf8Encode(err_str, SCC_YELLOW);
    01588             SetDParamStr(0, err_str);
    01589             ShowErrorMessage(INVALID_STRING_ID, STR_JUST_RAW_STRING, 0, 0);
    01590             return;
    01591           }
    01592         }
    01593       }
    01594     }
    01595     break;
    01596   }
    01597
    01598 #if !defined(WITH_ICU)
    01599   /*
    01600    * For right-to-left languages we need the ICU library. If
    01601    * we do not have support for that library we warn the user
    01602    * about it with a message. As we do not want the string to
    01603    * be translated by the translators, we 'force' it into the
    01604    * binary and 'load' it via a BindCString. To do this
    01605    * properly we have to set the colour of the string,
    01606    * otherwise we end up with a lot of artefacts. The colour
    01607    * 'character' might change in the future, so for safety
    01608    * we just Utf8 Encode it into the string, which takes
    01609    * exactly three characters, so it replaces the "XXX" with
    01610    * the colour marker.
    01611    */
    01612   if (_dynlang.text_dir != TD_LTR) {
    01613     static char *err_str = strdup("XXXThis version of OpenTTD does not support right-to-left languages. Recompile with icu enabled.");
    01614     Utf8Encode(err_str, SCC_YELLOW);
    01615     SetDParamStr(0, err_str);
    01616     ShowErrorMessage(INVALID_STRING_ID, STR_JUST_RAW_STRING, 0, 0);
    01617   }
    01618 #endif
    01619 }