# strings.cpp

Go to the documentation of this file.

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