strings.cpp

Go to the documentation of this file.
00001 /* $Id: strings.cpp 21845 2011-01-18 22:31:06Z rubidium $ */
00002 
00003 /*
00004  * This file is part of OpenTTD.
00005  * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
00006  * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00007  * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
00008  */
00009 
00012 #include "stdafx.h"
00013 #include "currency.h"
00014 #include "station_base.h"
00015 #include "town.h"
00016 #include "screenshot.h"
00017 #include "waypoint_base.h"
00018 #include "depot_base.h"
00019 #include "industry.h"
00020 #include "newgrf_text.h"
00021 #include "fileio_func.h"
00022 #include "group.h"
00023 #include "signs_base.h"
00024 #include "cargotype.h"
00025 #include "fontcache.h"
00026 #include "gui.h"
00027 #include "strings_func.h"
00028 #include "rev.h"
00029 #include "core/endian_func.hpp"
00030 #include "date_func.h"
00031 #include "vehicle_base.h"
00032 #include "engine_base.h"
00033 #include "language.h"
00034 #include "townname_func.h"
00035 #include "string_func.h"
00036 #include "company_base.h"
00037 #include "smallmap_gui.h"
00038 #include "window_func.h"
00039 #include "debug.h"
00040 
00041 #include "table/strings.h"
00042 #include "table/control_codes.h"
00043 
00044 char _config_language_file[MAX_PATH];             
00045 LanguageList _languages;                          
00046 const LanguageMetadata *_current_language = NULL; 
00047 
00048 TextDirection _current_text_dir; 
00049 uint64 _decode_parameters[20];   
00050 WChar _parameter_type[20];       
00051 
00052 #ifdef WITH_ICU
00053 Collator *_current_collator = NULL;               
00054 #endif /* WITH_ICU */
00055 
00056 static char *StationGetSpecialString(char *buff, int x, const char *last);
00057 static char *GetSpecialTownNameString(char *buff, int ind, uint32 seed, const char *last);
00058 static char *GetSpecialNameString(char *buff, int ind, int64 *argv, const int64 *argve, const char *last, WChar *argt = NULL);
00059 
00060 static char *FormatString(char *buff, const char *str, int64 *argv, const int64 *argve, uint casei, const char *last, WChar *argt = NULL, bool dry_run = false);
00061 
00062 struct LanguagePack : public LanguagePackHeader {
00063   char data[]; // list of strings
00064 };
00065 
00066 static char **_langpack_offs;
00067 static LanguagePack *_langpack;
00068 static uint _langtab_num[32];   
00069 static uint _langtab_start[32]; 
00070 static bool _keep_gender_data = false;  
00071 
00072 
00083 static inline int64 GetInt64(int64 **argv, const int64 *argve, WChar **argt, WChar type = 0)
00084 {
00085   assert(*argv != NULL);
00086   assert(*argv < argve);
00087   if (*argt != NULL) {
00088     assert(**argt == 0 || **argt == type);
00089     **argt = type;
00090     (*argt)++;
00091   }
00092   return *(*argv)++;
00093 }
00094 
00096 static inline int32 GetInt32(int64 **argv, const int64 *argve, WChar **argt, WChar type = 0)
00097 {
00098   return (int32)GetInt64(argv, argve, argt, type);
00099 }
00100 
00109 static inline int64 *GetArgvPtr(int64 **argv, int n, const int64 *argve, WChar **argt)
00110 {
00111   int64 *result;
00112   assert(*argv != NULL);
00113   assert((*argv + n) <= argve);
00114   result = *argv;
00115   (*argv) += n;
00116   if (*argt != NULL) (*argt) += n;
00117   return result;
00118 }
00119 
00120 
00121 const char *GetStringPtr(StringID string)
00122 {
00123   switch (GB(string, 11, 5)) {
00124     case 28: return GetGRFStringPtr(GB(string, 0, 11));
00125     case 29: return GetGRFStringPtr(GB(string, 0, 11) + 0x0800);
00126     case 30: return GetGRFStringPtr(GB(string, 0, 11) + 0x1000);
00127     default: return _langpack_offs[_langtab_start[string >> 11] + (string & 0x7FF)];
00128   }
00129 }
00130 
00144 char *GetStringWithArgs(char *buffr, uint string, int64 *argv, const int64 *argve, const char *last, WChar *argt)
00145 {
00146   if (GB(string, 0, 16) == 0) return GetStringWithArgs(buffr, STR_UNDEFINED, argv, argve, last, argt);
00147 
00148   uint index = GB(string,  0, 11);
00149   uint tab   = GB(string, 11,  5);
00150 
00151   switch (tab) {
00152     case 4:
00153       if (index >= 0xC0) {
00154         return GetSpecialTownNameString(buffr, index - 0xC0, GetInt32(&argv, argve, &argt), last);
00155       }
00156       break;
00157 
00158     case 14:
00159       if (index >= 0xE4) {
00160         return GetSpecialNameString(buffr, index - 0xE4, argv, argve, last, argt);
00161       }
00162       break;
00163 
00164     case 15:
00165       /* Old table for custom names. This is no longer used */
00166       error("Incorrect conversion of custom name string.");
00167 
00168     case 26:
00169       /* Include string within newgrf text (format code 81) */
00170       if (HasBit(index, 10)) {
00171         StringID string = GetGRFStringID(0, 0xD000 + GB(index, 0, 10));
00172         return GetStringWithArgs(buffr, string, argv, argve, last, argt);
00173       }
00174       break;
00175 
00176     case 28:
00177       return FormatString(buffr, GetGRFStringPtr(index), argv, argve, GB(string, 24, 8), last, argt);
00178 
00179     case 29:
00180       return FormatString(buffr, GetGRFStringPtr(index + 0x0800), argv, argve, GB(string, 24, 8), last, argt);
00181 
00182     case 30:
00183       return FormatString(buffr, GetGRFStringPtr(index + 0x1000), argv, argve, GB(string, 24, 8), last, argt);
00184 
00185     case 31:
00186       NOT_REACHED();
00187   }
00188 
00189   if (index >= _langtab_num[tab]) {
00190     error("String 0x%X is invalid. You are probably using an old version of the .lng file.\n", string);
00191   }
00192 
00193   return FormatString(buffr, GetStringPtr(GB(string, 0, 16)), argv, argve, GB(string, 24, 8), last, argt);
00194 }
00195 
00196 char *GetString(char *buffr, StringID string, const char *last)
00197 {
00198   memset(_parameter_type, 0, sizeof(_parameter_type));
00199   return GetStringWithArgs(buffr, string, (int64*)_decode_parameters, (int64*)endof(_decode_parameters), last, _parameter_type);
00200 }
00201 
00202 
00203 char *InlineString(char *buf, StringID string)
00204 {
00205   buf += Utf8Encode(buf, SCC_STRING_ID);
00206   buf += Utf8Encode(buf, string);
00207   return buf;
00208 }
00209 
00210 
00216 void SetDParamStr(uint n, const char *str)
00217 {
00218   SetDParam(n, (uint64)(size_t)str);
00219 }
00220 
00225 void InjectDParam(uint amount)
00226 {
00227   assert((uint)amount < lengthof(_decode_parameters));
00228   memmove(_decode_parameters + amount, _decode_parameters, sizeof(_decode_parameters) - amount * sizeof(uint64));
00229 }
00230 
00231 static char *FormatNumber(char *buff, int64 number, const char *last, const char *separator, int zerofill_from = 19)
00232 {
00233   uint64 divisor = 10000000000000000000ULL;
00234 
00235   if (number < 0) {
00236     buff += seprintf(buff, last, "-");
00237     number = -number;
00238   }
00239 
00240   uint64 num = number;
00241   uint64 tot = 0;
00242   for (int i = 0; i < 20; i++) {
00243     uint64 quot = 0;
00244     if (num >= divisor) {
00245       quot = num / divisor;
00246       num = num % divisor;
00247     }
00248     if (tot |= quot || i >= zerofill_from) {
00249       buff += seprintf(buff, last, "%i", (int)quot);
00250       if ((i % 3) == 1 && i != 19) buff = strecpy(buff, separator, last);
00251     }
00252 
00253     divisor /= 10;
00254   }
00255 
00256   *buff = '\0';
00257 
00258   return buff;
00259 }
00260 
00261 static char *FormatCommaNumber(char *buff, int64 number, const char *last)
00262 {
00263   const char *separator = _settings_game.locale.digit_group_separator;
00264   if (separator == NULL) separator = _langpack->digit_group_separator;
00265   return FormatNumber(buff, number, last, separator);
00266 }
00267 
00268 static char *FormatNoCommaNumber(char *buff, int64 number, const char *last)
00269 {
00270   return FormatNumber(buff, number, last, "");
00271 }
00272 
00273 static char *FormatZerofillNumber(char *buff, int64 number, int64 count, const char *last)
00274 {
00275   return FormatNumber(buff, number, last, "", 20 - count);
00276 }
00277 
00278 static char *FormatHexNumber(char *buff, uint64 number, const char *last)
00279 {
00280   return buff + seprintf(buff, last, "0x" OTTD_PRINTFHEX64, number);
00281 }
00282 
00290 static char *FormatBytes(char *buff, int64 number, const char *last)
00291 {
00292   assert(number >= 0);
00293 
00294   /*                                    1   2^10  2^20  2^30  2^40  2^50  2^60 */
00295   const char * const iec_prefixes[] = { "", "Ki", "Mi", "Gi", "Ti", "Pi", "Ei" };
00296   uint id = 1;
00297   while (number >= 1024 * 1024) {
00298     number /= 1024;
00299     id++;
00300   }
00301 
00302   const char *decimal_separator = _settings_game.locale.digit_decimal_separator;
00303   if (decimal_separator == NULL) decimal_separator = _langpack->digit_decimal_separator;
00304 
00305   if (number < 1024) {
00306     id = 0;
00307     buff += seprintf(buff, last, "%i", (int)number);
00308   } else if (number < 1024 * 10) {
00309     buff += seprintf(buff, last, "%i%s%02i", (int)number / 1024, decimal_separator, (int)(number % 1024) * 100 / 1024);
00310   } else if (number < 1024 * 100) {
00311     buff += seprintf(buff, last, "%i%s%01i", (int)number / 1024, decimal_separator, (int)(number % 1024) * 10 / 1024);
00312   } else {
00313     assert(number < 1024 * 1024);
00314     buff += seprintf(buff, last, "%i", (int)number / 1024);
00315   }
00316 
00317   assert(id < lengthof(iec_prefixes));
00318   buff += seprintf(buff, last, " %sB", iec_prefixes[id]);
00319 
00320   return buff;
00321 }
00322 
00323 static char *FormatYmdString(char *buff, Date date, uint modifier, const char *last)
00324 {
00325   YearMonthDay ymd;
00326   ConvertDateToYMD(date, &ymd);
00327 
00328   int64 args[3] = { ymd.day + STR_ORDINAL_NUMBER_1ST - 1, STR_MONTH_ABBREV_JAN + ymd.month, ymd.year };
00329   return FormatString(buff, GetStringPtr(STR_FORMAT_DATE_LONG), args, endof(args), modifier >> 24, last);
00330 }
00331 
00332 static char *FormatMonthAndYear(char *buff, Date date, uint modifier, const char *last)
00333 {
00334   YearMonthDay ymd;
00335   ConvertDateToYMD(date, &ymd);
00336 
00337   int64 args[2] = { STR_MONTH_JAN + ymd.month, ymd.year };
00338   return FormatString(buff, GetStringPtr(STR_FORMAT_DATE_SHORT), args, endof(args), modifier >> 24, last);
00339 }
00340 
00341 static char *FormatTinyOrISODate(char *buff, Date date, StringID str, const char *last)
00342 {
00343   YearMonthDay ymd;
00344   ConvertDateToYMD(date, &ymd);
00345 
00346   char day[3];
00347   char month[3];
00348   /* We want to zero-pad the days and months */
00349   snprintf(day,   lengthof(day),   "%02i", ymd.day);
00350   snprintf(month, lengthof(month), "%02i", ymd.month + 1);
00351 
00352   int64 args[3] = { (int64)(size_t)day, (int64)(size_t)month, ymd.year };
00353   return FormatString(buff, GetStringPtr(str), args, endof(args), 0, last);
00354 }
00355 
00356 static char *FormatGenericCurrency(char *buff, const CurrencySpec *spec, Money number, bool compact, const char *last)
00357 {
00358   /* We are going to make number absolute for printing, so
00359    * keep this piece of data as we need it later on */
00360   bool negative = number < 0;
00361   const char *multiplier = "";
00362 
00363   number *= spec->rate;
00364 
00365   /* convert from negative */
00366   if (number < 0) {
00367     if (buff + Utf8CharLen(SCC_RED) > last) return buff;
00368     buff += Utf8Encode(buff, SCC_RED);
00369     buff = strecpy(buff, "-", last);
00370     number = -number;
00371   }
00372 
00373   /* Add prefix part, folowing symbol_pos specification.
00374    * Here, it can can be either 0 (prefix) or 2 (both prefix anf suffix).
00375    * The only remaining value is 1 (suffix), so everything that is not 1 */
00376   if (spec->symbol_pos != 1) buff = strecpy(buff, spec->prefix, last);
00377 
00378   /* for huge numbers, compact the number into k or M */
00379   if (compact) {
00380     /* Take care of the 'k' rounding. Having 1 000 000 k
00381      * and 1 000 M is inconsistent, so always use 1 000 M. */
00382     if (number >= 1000000000 - 500) {
00383       number = (number + 500000) / 1000000;
00384       multiplier = "M";
00385     } else if (number >= 1000000) {
00386       number = (number + 500) / 1000;
00387       multiplier = "k";
00388     }
00389   }
00390 
00391   const char *separator = _settings_game.locale.digit_group_separator_currency;
00392   if (separator == NULL && !StrEmpty(_currency->separator)) separator = _currency->separator;
00393   if (separator == NULL) separator = _langpack->digit_group_separator_currency;
00394   buff = FormatNumber(buff, number, last, separator);
00395   buff = strecpy(buff, multiplier, last);
00396 
00397   /* Add suffix part, folowing symbol_pos specification.
00398    * Here, it can can be either 1 (suffix) or 2 (both prefix anf suffix).
00399    * The only remaining value is 1 (prefix), so everything that is not 0 */
00400   if (spec->symbol_pos != 0) buff = strecpy(buff, spec->suffix, last);
00401 
00402   if (negative) {
00403     if (buff + Utf8CharLen(SCC_PREVIOUS_COLOUR) > last) return buff;
00404     buff += Utf8Encode(buff, SCC_PREVIOUS_COLOUR);
00405     *buff = '\0';
00406   }
00407 
00408   return buff;
00409 }
00410 
00417 static int DeterminePluralForm(int64 count, int plural_form)
00418 {
00419   /* The absolute value determines plurality */
00420   uint64 n = abs(count);
00421 
00422   switch (plural_form) {
00423     default:
00424       NOT_REACHED();
00425 
00426     /* Two forms, singular used for one only
00427      * Used in:
00428      *   Danish, Dutch, English, German, Norwegian, Swedish, Estonian, Finnish,
00429      *   Greek, Hebrew, Italian, Portuguese, Spanish, Esperanto */
00430     case 0:
00431       return n != 1;
00432 
00433     /* Only one form
00434      * Used in:
00435      *   Hungarian, Japanese, Korean, Turkish */
00436     case 1:
00437       return 0;
00438 
00439     /* Two forms, singular used for zero and one
00440      * Used in:
00441      *   French, Brazilian Portuguese */
00442     case 2:
00443       return n > 1;
00444 
00445     /* Three forms, special case for 0 and ending in 1, except those ending in 11
00446      * Used in:
00447      *   Latvian */
00448     case 3:
00449       return n % 10 == 1 && n % 100 != 11 ? 0 : n != 0 ? 1 : 2;
00450 
00451     /* Five forms, special case for one, two, 3 to 6 and 7 to 10
00452      * Used in:
00453      *   Gaelige (Irish) */
00454     case 4:
00455       return n == 1 ? 0 : n == 2 ? 1 : n < 7 ? 2 : n < 11 ? 3 : 4;
00456 
00457     /* Three forms, special case for numbers ending in 1[2-9]
00458      * Used in:
00459      *   Lithuanian */
00460     case 5:
00461       return n % 10 == 1 && n % 100 != 11 ? 0 : n % 10 >= 2 && (n % 100 < 10 || n % 100 >= 20) ? 1 : 2;
00462 
00463     /* Three forms, special cases for numbers ending in 1 and 2, 3, 4, except those ending in 1[1-4]
00464      * Used in:
00465      *   Croatian, Russian, Ukrainian */
00466     case 6:
00467       return n % 10 == 1 && n % 100 != 11 ? 0 : n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 10 || n % 100 >= 20) ? 1 : 2;
00468 
00469     /* Three forms, special case for one and some numbers ending in 2, 3, or 4
00470      * Used in:
00471      *   Polish */
00472     case 7:
00473       return n == 1 ? 0 : n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 10 || n % 100 >= 20) ? 1 : 2;
00474 
00475     /* Four forms, special case for one and all numbers ending in 02, 03, or 04
00476      * Used in:
00477      *   Slovenian */
00478     case 8:
00479       return n % 100 == 1 ? 0 : n % 100 == 2 ? 1 : n % 100 == 3 || n % 100 == 4 ? 2 : 3;
00480 
00481     /* Two forms; singular used for everything ending in 1 but not in 11.
00482      * Used in:
00483      *   Icelandic */
00484     case 9:
00485       return n % 10 == 1 && n % 100 != 11 ? 0 : 1;
00486 
00487     /* Three forms, special cases for one and 2, 3, or 4
00488      * Used in:
00489      *   Czech, Slovak */
00490     case 10:
00491       return n == 1 ? 0 : n >= 2 && n <= 4 ? 1 : 2;
00492 
00493     /* Two forms, special 'hack' for Korean; singular for numbers ending
00494      *   in a consonant and plural for numbers ending in a vowel.
00495      * Korean doesn't have the concept of plural, but depending on how a
00496      * number is pronounced it needs another version of a particle.
00497      * As such the plural system is misused to give this distinction.
00498      */
00499     case 11:
00500       switch (n % 10) {
00501         case 0: // yeong
00502         case 1: // il
00503         case 3: // sam
00504         case 6: // yuk
00505         case 7: // chil
00506         case 8: // pal
00507           return 0;
00508 
00509         case 2: // i
00510         case 4: // sa
00511         case 5: // o
00512         case 9: // gu
00513           return 1;
00514 
00515         default:
00516           NOT_REACHED();
00517       }
00518 
00519     /* Four forms: one, 0 and everything ending in 02..10, everything ending in 11..19.
00520      * Used in:
00521      *  Maltese */
00522     case 12:
00523       return (n == 1 ? 0 : n == 0 || (n % 100 > 1 && n % 100 < 11) ? 1 : (n % 100 > 10 && n % 100 < 20) ? 2 : 3);
00524   }
00525 }
00526 
00527 static const char *ParseStringChoice(const char *b, uint form, char **dst, const char *last)
00528 {
00529   /* <NUM> {Length of each string} {each string} */
00530   uint n = (byte)*b++;
00531   uint pos, i, mypos = 0;
00532 
00533   for (i = pos = 0; i != n; i++) {
00534     uint len = (byte)*b++;
00535     if (i == form) mypos = pos;
00536     pos += len;
00537   }
00538 
00539   *dst += seprintf(*dst, last, "%s", b + mypos);
00540   return b + pos;
00541 }
00542 
00543 struct Units {
00544   int s_m;           
00545   int s_s;           
00546   StringID velocity; 
00547   int p_m;           
00548   int p_s;           
00549   StringID power;    
00550   int w_m;           
00551   int w_s;           
00552   StringID s_weight; 
00553   StringID l_weight; 
00554   int v_m;           
00555   int v_s;           
00556   StringID s_volume; 
00557   StringID l_volume; 
00558   int f_m;           
00559   int f_s;           
00560   StringID force;    
00561   int h_m;           
00562   int h_s;           
00563   StringID height;   
00564 };
00565 
00566 /* Unit conversions */
00567 static const Units units[] = {
00568   { // Imperial (Original, mph, hp, metric ton, litre, kN, ft)
00569        1,  0, STR_UNITS_VELOCITY_IMPERIAL,
00570        1,  0, STR_UNITS_POWER_IMPERIAL,
00571        1,  0, STR_UNITS_WEIGHT_SHORT_METRIC, STR_UNITS_WEIGHT_LONG_METRIC,
00572     1000,  0, STR_UNITS_VOLUME_SHORT_METRIC, STR_UNITS_VOLUME_LONG_METRIC,
00573        1,  0, STR_UNITS_FORCE_SI,
00574        3,  0, STR_UNITS_HEIGHT_IMPERIAL,
00575   },
00576   { // Metric (km/h, hp, metric ton, litre, kN, metre)
00577      103,  6, STR_UNITS_VELOCITY_METRIC,
00578        1,  0, STR_UNITS_POWER_METRIC,
00579        1,  0, STR_UNITS_WEIGHT_SHORT_METRIC, STR_UNITS_WEIGHT_LONG_METRIC,
00580     1000,  0, STR_UNITS_VOLUME_SHORT_METRIC, STR_UNITS_VOLUME_LONG_METRIC,
00581        1,  0, STR_UNITS_FORCE_SI,
00582        1,  0, STR_UNITS_HEIGHT_SI,
00583   },
00584   { // SI (m/s, kilowatt, kilogram, cubic metre, kilonewton, metre)
00585     1831, 12, STR_UNITS_VELOCITY_SI,
00586      764, 10, STR_UNITS_POWER_SI,
00587     1000,  0, STR_UNITS_WEIGHT_SHORT_SI, STR_UNITS_WEIGHT_LONG_SI,
00588        1,  0, STR_UNITS_VOLUME_SHORT_SI, STR_UNITS_VOLUME_LONG_SI,
00589        1,  0, STR_UNITS_FORCE_SI,
00590        1,  0, STR_UNITS_HEIGHT_SI,
00591   },
00592 };
00593 
00599 uint ConvertSpeedToDisplaySpeed(uint speed)
00600 {
00601   return (speed * units[_settings_game.locale.units].s_m) >> units[_settings_game.locale.units].s_s;
00602 }
00603 
00609 uint ConvertDisplaySpeedToSpeed(uint speed)
00610 {
00611   return ((speed << units[_settings_game.locale.units].s_s) + units[_settings_game.locale.units].s_m / 2) / units[_settings_game.locale.units].s_m;
00612 }
00613 
00625 static char *FormatString(char *buff, const char *str, int64 *argv, const int64 *argve, uint casei, const char *last, WChar *argt, bool dry_run)
00626 {
00627   /* When there is no array with types there is no need to do a dry run. */
00628   if (argt == NULL) dry_run = true;
00629   if (UsingNewGRFTextStack() && !dry_run) {
00630     /* Values from the NewGRF text stack are only copied to the normal
00631      * argv array at the time they are encountered. That means that if
00632      * another string command references a value later in the string it
00633      * would fail. We solve that by running FormatString twice. The first
00634      * pass makes sure the argv array is correctly filled and the second
00635      * pass can reference later values without problems. */
00636     struct TextRefStack *backup = CreateTextRefStackBackup();
00637     FormatString(buff, str, argv, argve, casei, last, argt, true);
00638     RestoreTextRefStackBackup(backup);
00639   } else if (!dry_run) {
00640     FormatString(buff, str, argv, argve, casei, last, argt, true);
00641   }
00642   WChar b;
00643   int64 *argv_orig = argv;
00644   WChar *argt_orig = argt;
00645   uint modifier = 0;
00646   char *buf_start = buff;
00647 
00648   while ((b = Utf8Consume(&str)) != '\0') {
00649     if (SCC_NEWGRF_FIRST <= b && b <= SCC_NEWGRF_LAST) {
00650       /* We need to pass some stuff as it might be modified; oh boy. */
00651       //todo: should argve be passed here too?
00652       b = RemapNewGRFStringControlCode(b, buf_start, &buff, &str, argv);
00653       if (b == 0) continue;
00654     }
00655 
00656     switch (b) {
00657       case SCC_SETX: // {SETX}
00658         if (buff + Utf8CharLen(SCC_SETX) + 1 < last) {
00659           buff += Utf8Encode(buff, SCC_SETX);
00660           *buff++ = *str++;
00661         }
00662         break;
00663 
00664       case SCC_SETXY: // {SETXY}
00665         if (buff + Utf8CharLen(SCC_SETXY) + 2 < last) {
00666           buff += Utf8Encode(buff, SCC_SETXY);
00667           *buff++ = *str++;
00668           *buff++ = *str++;
00669         }
00670         break;
00671 
00672       case SCC_STRING_ID: // {STRINL}
00673         buff = GetStringWithArgs(buff, Utf8Consume(&str), argv, argve, last, argt);
00674         break;
00675 
00676       case SCC_RAW_STRING_POINTER: { // {RAW_STRING}
00677         const char *str = (const char*)(size_t)GetInt64(&argv, argve, &argt);
00678         buff = FormatString(buff, str, argv, argve, casei, last, argt);
00679         break;
00680       }
00681 
00682       case SCC_DATE_LONG: // {DATE_LONG}
00683         buff = FormatYmdString(buff, GetInt32(&argv, argve, &argt, SCC_DATE_LONG), modifier, last);
00684         break;
00685 
00686       case SCC_DATE_SHORT: // {DATE_SHORT}
00687         buff = FormatMonthAndYear(buff, GetInt32(&argv, argve, &argt, SCC_DATE_SHORT), modifier, last);
00688         break;
00689 
00690       case SCC_VELOCITY: { // {VELOCITY}
00691         int64 args[1];
00692         assert(_settings_game.locale.units < lengthof(units));
00693         args[0] = ConvertSpeedToDisplaySpeed(GetInt32(&argv, argve, &argt, SCC_VELOCITY) * 10 / 16);
00694         buff = FormatString(buff, GetStringPtr(units[_settings_game.locale.units].velocity), args, endof(args), modifier >> 24, last);
00695         modifier = 0;
00696         break;
00697       }
00698 
00699       case SCC_HEIGHT: { // {HEIGHT}
00700         int64 args[1] = {GetInt32(&argv, argve, &argt) * units[_settings_game.locale.units].h_m >> units[_settings_game.locale.units].h_s};
00701         buff = FormatString(buff, GetStringPtr(units[_settings_game.locale.units].height), args, endof(args), modifier >> 24, last);
00702         modifier = 0;
00703         break;
00704       }
00705 
00706       case SCC_CURRENCY_COMPACT: // {CURRCOMPACT}
00707         buff = FormatGenericCurrency(buff, _currency, GetInt64(&argv, argve, &argt), true, last);
00708         break;
00709 
00710       case SCC_REVISION: // {REV}
00711         buff = strecpy(buff, _openttd_revision, last);
00712         break;
00713 
00714       case SCC_CARGO_SHORT: { // {SHORTCARGO}
00715         /* Short description of cargotypes. Layout:
00716          * 8-bit = cargo type
00717          * 16-bit = cargo count */
00718         StringID cargo_str = CargoSpec::Get(GetInt32(&argv, argve, &argt, SCC_CARGO_SHORT))->units_volume;
00719         switch (cargo_str) {
00720           case STR_TONS: {
00721             int64 args[1];
00722             assert(_settings_game.locale.units < lengthof(units));
00723             args[0] = GetInt32(&argv, argve, &argt) * units[_settings_game.locale.units].w_m >> units[_settings_game.locale.units].w_s;
00724             buff = FormatString(buff, GetStringPtr(units[_settings_game.locale.units].l_weight), args, endof(args), modifier >> 24, last);
00725             modifier = 0;
00726             break;
00727           }
00728 
00729           case STR_LITERS: {
00730             int64 args[1];
00731             assert(_settings_game.locale.units < lengthof(units));
00732             args[0] = GetInt32(&argv, argve, &argt) * units[_settings_game.locale.units].v_m >> units[_settings_game.locale.units].v_s;
00733             buff = FormatString(buff, GetStringPtr(units[_settings_game.locale.units].l_volume), args, endof(args), modifier >> 24, last);
00734             modifier = 0;
00735             break;
00736           }
00737 
00738           default:
00739             buff = GetStringWithArgs(buff, cargo_str, argv++, argve, last, argt++);
00740             break;
00741         }
00742         break;
00743       }
00744 
00745       case SCC_STRING1: { // {STRING1}
00746         /* String that consumes ONE argument */
00747         uint str = modifier + GetInt32(&argv, argve, &argt, SCC_STRING1);
00748         WChar *orig_argt = argt;
00749         int64 *args = GetArgvPtr(&argv, 1, argve, &argt);
00750         buff = GetStringWithArgs(buff, str, args, argve, last, orig_argt);
00751         modifier = 0;
00752         break;
00753       }
00754 
00755       case SCC_STRING2: { // {STRING2}
00756         /* String that consumes TWO arguments */
00757         uint str = modifier + GetInt32(&argv, argve, &argt, SCC_STRING2);
00758         WChar *orig_argt = argt;
00759         int64 *args = GetArgvPtr(&argv, 2, argve, &argt);
00760         buff = GetStringWithArgs(buff, str, args, argve, last, orig_argt);
00761         modifier = 0;
00762         break;
00763       }
00764 
00765       case SCC_STRING3: { // {STRING3}
00766         /* String that consumes THREE arguments */
00767         uint str = modifier + GetInt32(&argv, argve, &argt, SCC_STRING3);
00768         WChar *orig_argt = argt;
00769         int64 *args = GetArgvPtr(&argv, 3, argve, &argt);
00770         buff = GetStringWithArgs(buff, str, args, argve, last, orig_argt);
00771         modifier = 0;
00772         break;
00773       }
00774 
00775       case SCC_STRING4: { // {STRING4}
00776         /* String that consumes FOUR arguments */
00777         uint str = modifier + GetInt32(&argv, argve, &argt, SCC_STRING4);
00778         WChar *orig_argt = argt;
00779         int64 *args = GetArgvPtr(&argv, 4, argve, &argt);
00780         buff = GetStringWithArgs(buff, str, args, argve, last, orig_argt);
00781         modifier = 0;
00782         break;
00783       }
00784 
00785       case SCC_STRING5: { // {STRING5}
00786         /* String that consumes FIVE arguments */
00787         uint str = modifier + GetInt32(&argv, argve, &argt, SCC_STRING5);
00788         WChar *orig_argt = argt;
00789         int64 *args = GetArgvPtr(&argv, 5, argve, &argt);
00790         buff = GetStringWithArgs(buff, str, args, argve, last, orig_argt);
00791         modifier = 0;
00792         break;
00793       }
00794 
00795       case SCC_STATION_FEATURES: { // {STATIONFEATURES}
00796         buff = StationGetSpecialString(buff, GetInt32(&argv, argve, &argt, SCC_STATION_FEATURES), last);
00797         break;
00798       }
00799 
00800       case SCC_INDUSTRY_NAME: { // {INDUSTRY}
00801         const Industry *i = Industry::Get(GetInt32(&argv, argve, &argt, SCC_INDUSTRY_NAME));
00802         int64 args[2];
00803 
00804         /* industry not valid anymore? */
00805         assert(i != NULL);
00806 
00807         /* First print the town name and the industry type name. */
00808         args[0] = i->town->index;
00809         args[1] = GetIndustrySpec(i->type)->name;
00810         buff = FormatString(buff, GetStringPtr(STR_FORMAT_INDUSTRY_NAME), args, endof(args), modifier >> 24, last);
00811         modifier = 0;
00812         break;
00813       }
00814 
00815       case SCC_VOLUME: { // {VOLUME}
00816         int64 args[1];
00817         assert(_settings_game.locale.units < lengthof(units));
00818         args[0] = GetInt32(&argv, argve, &argt, SCC_VOLUME) * units[_settings_game.locale.units].v_m >> units[_settings_game.locale.units].v_s;
00819         buff = FormatString(buff, GetStringPtr(units[_settings_game.locale.units].l_volume), args, endof(args), modifier >> 24, last);
00820         modifier = 0;
00821         break;
00822       }
00823 
00824       case SCC_GENDER_LIST: { // {G 0 Der Die Das}
00825         /* First read the meta data from the language file. */
00826         byte offset = (byte)*str++;
00827         assert(argv_orig + offset < argve);
00828         int gender = 0;
00829         if (!dry_run && argt != NULL && argt_orig[offset] != 0) {
00830           /* Now we need to figure out what text to resolve, i.e.
00831            * what do we need to draw? So get the actual raw string
00832            * first using the control code to get said string. */
00833           char input[4 + 1];
00834           char *p = input + Utf8Encode(input, argt_orig[offset]);
00835           *p = '\0';
00836 
00837           /* Now do the string formatting. */
00838           char buf[256];
00839           bool old_kgd = _keep_gender_data;
00840           _keep_gender_data = true;
00841           p = FormatString(buf, input, argv_orig + offset, argve, 0, lastof(buf));
00842           _keep_gender_data = old_kgd;
00843           *p = '\0';
00844 
00845           /* And determine the string. */
00846           const char *s = buf;
00847           WChar c = Utf8Consume(&s);
00848           /* Does this string have a gender, if so, set it */
00849           if (c == SCC_GENDER_INDEX) gender = (byte)s[0];
00850         }
00851         str = ParseStringChoice(str, gender, &buff, last);
00852         break;
00853       }
00854 
00855       case SCC_DATE_TINY: { // {DATE_TINY}
00856         buff = FormatTinyOrISODate(buff, GetInt32(&argv, argve, &argt, SCC_DATE_TINY), STR_FORMAT_DATE_TINY, last);
00857         break;
00858       }
00859 
00860       case SCC_DATE_ISO: { // {DATE_ISO}
00861         buff = FormatTinyOrISODate(buff, GetInt32(&argv, argve, &argt), STR_FORMAT_DATE_ISO, last);
00862         break;
00863       }
00864 
00865       case SCC_CARGO: { // {CARGO}
00866         /* First parameter is cargo type, second parameter is cargo count */
00867         CargoID cargo = GetInt32(&argv, argve, &argt, SCC_CARGO);
00868         StringID cargo_str = (cargo == CT_INVALID) ? STR_QUANTITY_N_A : CargoSpec::Get(cargo)->quantifier;
00869         buff = GetStringWithArgs(buff, cargo_str, argv++, argve, last);
00870         break;
00871       }
00872 
00873       case SCC_POWER: { // {POWER}
00874         int64 args[1];
00875         assert(_settings_game.locale.units < lengthof(units));
00876         args[0] = GetInt32(&argv, argve, &argt) * units[_settings_game.locale.units].p_m >> units[_settings_game.locale.units].p_s;
00877         buff = FormatString(buff, GetStringPtr(units[_settings_game.locale.units].power), args, endof(args), modifier >> 24, last);
00878         modifier = 0;
00879         break;
00880       }
00881 
00882       case SCC_VOLUME_SHORT: { // {VOLUME_S}
00883         int64 args[1];
00884         assert(_settings_game.locale.units < lengthof(units));
00885         args[0] = GetInt32(&argv, argve, &argt) * units[_settings_game.locale.units].v_m >> units[_settings_game.locale.units].v_s;
00886         buff = FormatString(buff, GetStringPtr(units[_settings_game.locale.units].s_volume), args, endof(args), modifier >> 24, last);
00887         modifier = 0;
00888         break;
00889       }
00890 
00891       case SCC_WEIGHT: { // {WEIGHT}
00892         int64 args[1];
00893         assert(_settings_game.locale.units < lengthof(units));
00894         args[0] = GetInt32(&argv, argve, &argt, SCC_WEIGHT) * units[_settings_game.locale.units].w_m >> units[_settings_game.locale.units].w_s;
00895         buff = FormatString(buff, GetStringPtr(units[_settings_game.locale.units].l_weight), args, endof(args), modifier >> 24, last);
00896         modifier = 0;
00897         break;
00898       }
00899 
00900       case SCC_WEIGHT_SHORT: { // {WEIGHT_S}
00901         int64 args[1];
00902         assert(_settings_game.locale.units < lengthof(units));
00903         args[0] = GetInt32(&argv, argve, &argt) * units[_settings_game.locale.units].w_m >> units[_settings_game.locale.units].w_s;
00904         buff = FormatString(buff, GetStringPtr(units[_settings_game.locale.units].s_weight), args, endof(args), modifier >> 24, last);
00905         modifier = 0;
00906         break;
00907       }
00908 
00909       case SCC_FORCE: { // {FORCE}
00910         int64 args[1];
00911         assert(_settings_game.locale.units < lengthof(units));
00912         args[0] = GetInt32(&argv, argve, &argt) * units[_settings_game.locale.units].f_m >> units[_settings_game.locale.units].f_s;
00913         buff = FormatString(buff, GetStringPtr(units[_settings_game.locale.units].force), args, endof(args), modifier >> 24, last);
00914         modifier = 0;
00915         break;
00916       }
00917 
00918       /* This sets up the gender for the string.
00919        * We just ignore this one. It's used in {G 0 Der Die Das} to determine the case. */
00920       case SCC_GENDER_INDEX: // {GENDER 0}
00921         if (_keep_gender_data) {
00922           buff += Utf8Encode(buff, SCC_GENDER_INDEX);
00923           *buff++ = *str++;
00924         } else {
00925           str++;
00926         }
00927         break;
00928 
00929       case SCC_STRING: {// {STRING}
00930         uint str = modifier + GetInt32(&argv, argve, &argt, SCC_STRING);
00931         /* WARNING. It's prohibited for the included string to consume any arguments.
00932          * For included strings that consume argument, you should use STRING1, STRING2 etc.
00933          * To debug stuff you can set argv to NULL and it will tell you */
00934         buff = GetStringWithArgs(buff, str, argv, argve, last);
00935         modifier = 0;
00936         break;
00937       }
00938 
00939       case SCC_COMMA: // {COMMA}
00940         buff = FormatCommaNumber(buff, GetInt64(&argv, argve, &argt, SCC_COMMA), last);
00941         break;
00942 
00943       case SCC_ARG_INDEX: { // Move argument pointer
00944         byte offset = (byte)*str++;
00945         argv = argv_orig + offset;
00946         if (argt_orig != NULL) argt = argt_orig + offset;
00947         break;
00948       }
00949 
00950       case SCC_PLURAL_LIST: { // {P}
00951         int plural_form = *str++;          // contains the plural form for this string
00952         byte idx = *str++;
00953         assert(argv_orig + idx < argve);
00954         int64 v = argv_orig[idx]; // contains the number that determines plural
00955         str = ParseStringChoice(str, DeterminePluralForm(v, plural_form), &buff, last);
00956         break;
00957       }
00958 
00959       case SCC_NUM: // {NUM}
00960         buff = FormatNoCommaNumber(buff, GetInt64(&argv, argve, &argt, SCC_NUM), last);
00961         break;
00962 
00963       case SCC_ZEROFILL_NUM: { // {ZEROFILL_NUM}
00964         int64 num = GetInt64(&argv, argve, &argt);
00965         buff = FormatZerofillNumber(buff, num, GetInt64(&argv, argve, &argt), last);
00966         break;
00967       }
00968 
00969       case SCC_HEX: // {HEX}
00970         buff = FormatHexNumber(buff, (uint64)GetInt64(&argv, argve, &argt, SCC_HEX), last);
00971         break;
00972 
00973       case SCC_BYTES: // {BYTES}
00974         buff = FormatBytes(buff, GetInt64(&argv, argve, &argt), last);
00975         break;
00976 
00977       case SCC_CURRENCY: // {CURRENCY}
00978         buff = FormatGenericCurrency(buff, _currency, GetInt64(&argv, argve, &argt, SCC_CURRENCY), false, last);
00979         break;
00980 
00981       case SCC_WAYPOINT_NAME: { // {WAYPOINT}
00982         Waypoint *wp = Waypoint::Get(GetInt32(&argv, argve, &argt, SCC_WAYPOINT_NAME));
00983 
00984         assert(wp != NULL);
00985 
00986         if (wp->name != NULL) {
00987           buff = strecpy(buff, wp->name, last);
00988         } else {
00989           int64 args[2];
00990           args[0] = wp->town->index;
00991           args[1] = wp->town_cn + 1;
00992           StringID str = ((wp->string_id == STR_SV_STNAME_BUOY) ? STR_FORMAT_BUOY_NAME : STR_FORMAT_WAYPOINT_NAME);
00993           if (wp->town_cn != 0) str++;
00994           buff = GetStringWithArgs(buff, str, args, endof(args), last);
00995         }
00996         break;
00997       }
00998 
00999       case SCC_STATION_NAME: { // {STATION}
01000         StationID sid = GetInt32(&argv, argve, &argt, SCC_STATION_NAME);
01001         const Station *st = Station::GetIfValid(sid);
01002 
01003         if (st == NULL) {
01004           /* The station doesn't exist anymore. The only place where we might
01005            * be "drawing" an invalid station is in the case of cargo that is
01006            * in transit. */
01007           buff = GetStringWithArgs(buff, STR_UNKNOWN_STATION, NULL, NULL, last);
01008           break;
01009         }
01010 
01011         if (st->name != NULL) {
01012           buff = strecpy(buff, st->name, last);
01013         } else {
01014           StringID str = st->string_id;
01015           if (st->indtype != IT_INVALID) {
01016             /* Special case where the industry provides the name for the station */
01017             const IndustrySpec *indsp = GetIndustrySpec(st->indtype);
01018 
01019             /* Industry GRFs can change which might remove the station name and
01020              * thus cause very strange things. Here we check for that before we
01021              * actually set the station name. */
01022             if (indsp->station_name != STR_NULL && indsp->station_name != STR_UNDEFINED) {
01023               str = indsp->station_name;
01024             }
01025           }
01026 
01027           int64 args[3];
01028           args[0] = STR_TOWN_NAME;
01029           args[1] = st->town->index;
01030           args[2] = st->index;
01031           buff = GetStringWithArgs(buff, str, args, endof(args), last);
01032         }
01033         break;
01034       }
01035 
01036       case SCC_DEPOT_NAME: { // {DEPOT}
01037         VehicleType vt = (VehicleType)GetInt32(&argv, argve, &argt, SCC_DEPOT_NAME);
01038         if (vt == VEH_AIRCRAFT) {
01039           int64 args[] = { GetInt32(&argv, argve, &argt) };
01040           buff = GetStringWithArgs(buff, STR_FORMAT_DEPOT_NAME_AIRCRAFT, args, endof(args), last);
01041           break;
01042         }
01043 
01044         const Depot *d = Depot::Get(GetInt32(&argv, argve, &argt));
01045         if (d->name != NULL) {
01046           buff = strecpy(buff, d->name, last);
01047         } else {
01048           int64 args[] = { d->town->index, d->town_cn + 1 };
01049           buff = GetStringWithArgs(buff, STR_FORMAT_DEPOT_NAME_TRAIN + 2 * vt + (d->town_cn == 0 ? 0 : 1), args, endof(args), last);
01050         }
01051         break;
01052       }
01053 
01054       case SCC_TOWN_NAME: { // {TOWN}
01055         const Town *t = Town::Get(GetInt32(&argv, argve, &argt, SCC_TOWN_NAME));
01056 
01057         assert(t != NULL);
01058 
01059         if (t->name != NULL) {
01060           buff = strecpy(buff, t->name, last);
01061         } else {
01062           buff = GetTownName(buff, t, last);
01063         }
01064         break;
01065       }
01066 
01067       case SCC_GROUP_NAME: { // {GROUP}
01068         const Group *g = Group::Get(GetInt32(&argv, argve, &argt));
01069 
01070         assert(g != NULL);
01071 
01072         if (g->name != NULL) {
01073           buff = strecpy(buff, g->name, last);
01074         } else {
01075           int64 args[1];
01076 
01077           args[0] = g->index;
01078           buff = GetStringWithArgs(buff, STR_FORMAT_GROUP_NAME, args, endof(args), last);
01079         }
01080         break;
01081       }
01082 
01083       case SCC_ENGINE_NAME: { // {ENGINE}
01084         EngineID engine = (EngineID)GetInt32(&argv, argve, &argt, SCC_ENGINE_NAME);
01085         const Engine *e = Engine::Get(engine);
01086 
01087         assert(e != NULL);
01088 
01089         if (e->name != NULL && e->info.string_id != STR_NEWGRF_INVALID_ENGINE) {
01090           buff = strecpy(buff, e->name, last);
01091         } else {
01092           buff = GetStringWithArgs(buff, e->info.string_id, NULL, NULL, last);
01093         }
01094         break;
01095       }
01096 
01097       case SCC_VEHICLE_NAME: { // {VEHICLE}
01098         const Vehicle *v = Vehicle::Get(GetInt32(&argv, argve, &argt, SCC_VEHICLE_NAME));
01099 
01100         assert(v != NULL);
01101 
01102         if (v->name != NULL) {
01103           buff = strecpy(buff, v->name, last);
01104         } else {
01105           int64 args[1];
01106           args[0] = v->unitnumber;
01107 
01108           StringID str;
01109           switch (v->type) {
01110             default: NOT_REACHED();
01111             case VEH_TRAIN:    str = STR_SV_TRAIN_NAME; break;
01112             case VEH_ROAD:     str = STR_SV_ROAD_VEHICLE_NAME; break;
01113             case VEH_SHIP:     str = STR_SV_SHIP_NAME; break;
01114             case VEH_AIRCRAFT: str = STR_SV_AIRCRAFT_NAME; break;
01115           }
01116 
01117           buff = GetStringWithArgs(buff, str, args, endof(args), last);
01118         }
01119         break;
01120       }
01121 
01122       case SCC_SIGN_NAME: { // {SIGN}
01123         const Sign *si = Sign::Get(GetInt32(&argv, argve, &argt));
01124         if (si->name != NULL) {
01125           buff = strecpy(buff, si->name, last);
01126         } else {
01127           buff = GetStringWithArgs(buff, STR_DEFAULT_SIGN_NAME, NULL, NULL, last);
01128         }
01129         break;
01130       }
01131 
01132       case SCC_COMPANY_NAME: { // {COMPANY}
01133         const Company *c = Company::Get((CompanyID)GetInt32(&argv, argve, &argt));
01134 
01135         if (c->name != NULL) {
01136           buff = strecpy(buff, c->name, last);
01137         } else {
01138           int64 args[1];
01139           args[0] = c->name_2;
01140           buff = GetStringWithArgs(buff, c->name_1, args, endof(args), last);
01141         }
01142         break;
01143       }
01144 
01145       case SCC_COMPANY_NUM: { // {COMPANYNUM}
01146         CompanyID company = (CompanyID)GetInt32(&argv, argve, &argt);
01147 
01148         /* Nothing is added for AI or inactive companies */
01149         if (Company::IsValidHumanID(company)) {
01150           int64 args[1];
01151           args[0] = company + 1;
01152           buff = GetStringWithArgs(buff, STR_FORMAT_COMPANY_NUM, args, endof(args), last);
01153         }
01154         break;
01155       }
01156 
01157       case SCC_PRESIDENT_NAME: { // {PRESIDENTNAME}
01158         const Company *c = Company::Get((CompanyID)GetInt32(&argv, argve, &argt, SCC_PRESIDENT_NAME));
01159 
01160         if (c->president_name != NULL) {
01161           buff = strecpy(buff, c->president_name, last);
01162         } else {
01163           int64 args[1];
01164           args[0] = c->president_name_2;
01165           buff = GetStringWithArgs(buff, c->president_name_1, args, endof(args), last);
01166         }
01167         break;
01168       }
01169 
01170       case SCC_SETCASE: { // {SETCASE}
01171         /* This is a pseudo command, it's outputted when someone does {STRING.ack}
01172          * The modifier is added to all subsequent GetStringWithArgs that accept the modifier. */
01173         modifier = (byte)*str++ << 24;
01174         break;
01175       }
01176 
01177       case SCC_SWITCH_CASE: { // {Used to implement case switching}
01178         /* <0x9E> <NUM CASES> <CASE1> <LEN1> <STRING1> <CASE2> <LEN2> <STRING2> <CASE3> <LEN3> <STRING3> <STRINGDEFAULT>
01179          * Each LEN is printed using 2 bytes in big endian order. */
01180         uint num = (byte)*str++;
01181         while (num) {
01182           if ((byte)str[0] == casei) {
01183             /* Found the case, adjust str pointer and continue */
01184             str += 3;
01185             break;
01186           }
01187           /* Otherwise skip to the next case */
01188           str += 3 + (str[1] << 8) + str[2];
01189           num--;
01190         }
01191         break;
01192       }
01193 
01194       default:
01195         if (buff + Utf8CharLen(b) < last) buff += Utf8Encode(buff, b);
01196         break;
01197     }
01198   }
01199   *buff = '\0';
01200   return buff;
01201 }
01202 
01203 
01204 static char *StationGetSpecialString(char *buff, int x, const char *last)
01205 {
01206   if ((x & FACIL_TRAIN)      && (buff + Utf8CharLen(SCC_TRAIN) < last)) buff += Utf8Encode(buff, SCC_TRAIN);
01207   if ((x & FACIL_TRUCK_STOP) && (buff + Utf8CharLen(SCC_LORRY) < last)) buff += Utf8Encode(buff, SCC_LORRY);
01208   if ((x & FACIL_BUS_STOP)   && (buff + Utf8CharLen(SCC_BUS)   < last)) buff += Utf8Encode(buff, SCC_BUS);
01209   if ((x & FACIL_DOCK)       && (buff + Utf8CharLen(SCC_SHIP)  < last)) buff += Utf8Encode(buff, SCC_SHIP);
01210   if ((x & FACIL_AIRPORT)    && (buff + Utf8CharLen(SCC_PLANE) < last)) buff += Utf8Encode(buff, SCC_PLANE);
01211   *buff = '\0';
01212   return buff;
01213 }
01214 
01215 static char *GetSpecialTownNameString(char *buff, int ind, uint32 seed, const char *last)
01216 {
01217   return GenerateTownNameString(buff, last, ind, seed);
01218 }
01219 
01220 static const char * const _silly_company_names[] = {
01221   "Bloggs Brothers",
01222   "Tiny Transport Ltd.",
01223   "Express Travel",
01224   "Comfy-Coach & Co.",
01225   "Crush & Bump Ltd.",
01226   "Broken & Late Ltd.",
01227   "Sam Speedy & Son",
01228   "Supersonic Travel",
01229   "Mike's Motors",
01230   "Lightning International",
01231   "Pannik & Loozit Ltd.",
01232   "Inter-City Transport",
01233   "Getout & Pushit Ltd."
01234 };
01235 
01236 static const char * const _surname_list[] = {
01237   "Adams",
01238   "Allan",
01239   "Baker",
01240   "Bigwig",
01241   "Black",
01242   "Bloggs",
01243   "Brown",
01244   "Campbell",
01245   "Gordon",
01246   "Hamilton",
01247   "Hawthorn",
01248   "Higgins",
01249   "Green",
01250   "Gribble",
01251   "Jones",
01252   "McAlpine",
01253   "MacDonald",
01254   "McIntosh",
01255   "Muir",
01256   "Murphy",
01257   "Nelson",
01258   "O'Donnell",
01259   "Parker",
01260   "Phillips",
01261   "Pilkington",
01262   "Quigley",
01263   "Sharkey",
01264   "Thomson",
01265   "Watkins"
01266 };
01267 
01268 static const char * const _silly_surname_list[] = {
01269   "Grumpy",
01270   "Dozy",
01271   "Speedy",
01272   "Nosey",
01273   "Dribble",
01274   "Mushroom",
01275   "Cabbage",
01276   "Sniffle",
01277   "Fishy",
01278   "Swindle",
01279   "Sneaky",
01280   "Nutkins"
01281 };
01282 
01283 static const char _initial_name_letters[] = {
01284   'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
01285   'K', 'L', 'M', 'N', 'P', 'R', 'S', 'T', 'W',
01286 };
01287 
01288 static char *GenAndCoName(char *buff, uint32 arg, const char *last)
01289 {
01290   const char * const *base;
01291   uint num;
01292 
01293   if (_settings_game.game_creation.landscape == LT_TOYLAND) {
01294     base = _silly_surname_list;
01295     num  = lengthof(_silly_surname_list);
01296   } else {
01297     base = _surname_list;
01298     num  = lengthof(_surname_list);
01299   }
01300 
01301   buff = strecpy(buff, base[num * GB(arg, 16, 8) >> 8], last);
01302   buff = strecpy(buff, " & Co.", last);
01303 
01304   return buff;
01305 }
01306 
01307 static char *GenPresidentName(char *buff, uint32 x, const char *last)
01308 {
01309   char initial[] = "?. ";
01310   const char * const *base;
01311   uint num;
01312   uint i;
01313 
01314   initial[0] = _initial_name_letters[sizeof(_initial_name_letters) * GB(x, 0, 8) >> 8];
01315   buff = strecpy(buff, initial, last);
01316 
01317   i = (sizeof(_initial_name_letters) + 35) * GB(x, 8, 8) >> 8;
01318   if (i < sizeof(_initial_name_letters)) {
01319     initial[0] = _initial_name_letters[i];
01320     buff = strecpy(buff, initial, last);
01321   }
01322 
01323   if (_settings_game.game_creation.landscape == LT_TOYLAND) {
01324     base = _silly_surname_list;
01325     num  = lengthof(_silly_surname_list);
01326   } else {
01327     base = _surname_list;
01328     num  = lengthof(_surname_list);
01329   }
01330 
01331   buff = strecpy(buff, base[num * GB(x, 16, 8) >> 8], last);
01332 
01333   return buff;
01334 }
01335 
01336 static char *GetSpecialNameString(char *buff, int ind, int64 *argv, const int64 *argve, const char *last, WChar *argt)
01337 {
01338   switch (ind) {
01339     case 1: // not used
01340       return strecpy(buff, _silly_company_names[GetInt32(&argv, argve, &argt) & 0xFFFF], last);
01341 
01342     case 2: // used for Foobar & Co company names
01343       return GenAndCoName(buff, GetInt32(&argv, argve, &argt), last);
01344 
01345     case 3: // President name
01346       return GenPresidentName(buff, GetInt32(&argv, argve, &argt), last);
01347   }
01348 
01349   /* town name? */
01350   if (IsInsideMM(ind - 6, 0, SPECSTR_TOWNNAME_LAST - SPECSTR_TOWNNAME_START + 1)) {
01351     buff = GetSpecialTownNameString(buff, ind - 6, GetInt32(&argv, argve, &argt), last);
01352     return strecpy(buff, " Transport", last);
01353   }
01354 
01355   /* language name? */
01356   if (IsInsideMM(ind, (SPECSTR_LANGUAGE_START - 0x70E4), (SPECSTR_LANGUAGE_END - 0x70E4) + 1)) {
01357     int i = ind - (SPECSTR_LANGUAGE_START - 0x70E4);
01358     return strecpy(buff,
01359       &_languages[i] == _current_language ? _current_language->own_name : _languages[i].name, last);
01360   }
01361 
01362   /* resolution size? */
01363   if (IsInsideMM(ind, (SPECSTR_RESOLUTION_START - 0x70E4), (SPECSTR_RESOLUTION_END - 0x70E4) + 1)) {
01364     int i = ind - (SPECSTR_RESOLUTION_START - 0x70E4);
01365     buff += seprintf(
01366       buff, last, "%ux%u", _resolutions[i].width, _resolutions[i].height
01367     );
01368     return buff;
01369   }
01370 
01371   /* screenshot format name? */
01372   if (IsInsideMM(ind, (SPECSTR_SCREENSHOT_START - 0x70E4), (SPECSTR_SCREENSHOT_END - 0x70E4) + 1)) {
01373     int i = ind - (SPECSTR_SCREENSHOT_START - 0x70E4);
01374     return strecpy(buff, GetScreenshotFormatDesc(i), last);
01375   }
01376 
01377   NOT_REACHED();
01378 }
01379 
01380 #ifdef ENABLE_NETWORK
01381 extern void SortNetworkLanguages();
01382 #else /* ENABLE_NETWORK */
01383 static inline void SortNetworkLanguages() {}
01384 #endif /* ENABLE_NETWORK */
01385 
01390 bool LanguagePackHeader::IsValid() const
01391 {
01392   return this->ident        == TO_LE32(LanguagePackHeader::IDENT) &&
01393          this->version      == TO_LE32(LANGUAGE_PACK_VERSION) &&
01394          this->plural_form  <  LANGUAGE_MAX_PLURAL &&
01395          this->text_dir     <= 1 &&
01396          this->newgrflangid < MAX_LANG &&
01397          this->num_genders  < MAX_NUM_GENDERS &&
01398          this->num_cases    < MAX_NUM_CASES &&
01399          StrValid(this->name,                           lastof(this->name)) &&
01400          StrValid(this->own_name,                       lastof(this->own_name)) &&
01401          StrValid(this->isocode,                        lastof(this->isocode)) &&
01402          StrValid(this->digit_group_separator,          lastof(this->digit_group_separator)) &&
01403          StrValid(this->digit_group_separator_currency, lastof(this->digit_group_separator_currency)) &&
01404          StrValid(this->digit_decimal_separator,        lastof(this->digit_decimal_separator));
01405 }
01406 
01407 bool ReadLanguagePack(const LanguageMetadata *lang)
01408 {
01409   /* Current language pack */
01410   size_t len;
01411   LanguagePack *lang_pack = (LanguagePack *)ReadFileToMem(lang->file, &len, 200000);
01412   if (lang_pack == NULL) return false;
01413 
01414   /* End of read data (+ terminating zero added in ReadFileToMem()) */
01415   const char *end = (char *)lang_pack + len + 1;
01416 
01417   /* We need at least one byte of lang_pack->data */
01418   if (end <= lang_pack->data || !lang_pack->IsValid()) {
01419     free(lang_pack);
01420     return false;
01421   }
01422 
01423 #if TTD_ENDIAN == TTD_BIG_ENDIAN
01424   for (uint i = 0; i < 32; i++) {
01425     lang_pack->offsets[i] = ReadLE16Aligned(&lang_pack->offsets[i]);
01426   }
01427 #endif /* TTD_ENDIAN == TTD_BIG_ENDIAN */
01428 
01429   uint count = 0;
01430   for (uint i = 0; i < 32; i++) {
01431     uint num = lang_pack->offsets[i];
01432     _langtab_start[i] = count;
01433     _langtab_num[i] = num;
01434     count += num;
01435   }
01436 
01437   /* Allocate offsets */
01438   char **langpack_offs = MallocT<char *>(count);
01439 
01440   /* Fill offsets */
01441   char *s = lang_pack->data;
01442   len = (byte)*s++;
01443   for (uint i = 0; i < count; i++) {
01444     if (s + len >= end) {
01445       free(lang_pack);
01446       free(langpack_offs);
01447       return false;
01448     }
01449     if (len >= 0xC0) {
01450       len = ((len & 0x3F) << 8) + (byte)*s++;
01451       if (s + len >= end) {
01452         free(lang_pack);
01453         free(langpack_offs);
01454         return false;
01455       }
01456     }
01457     langpack_offs[i] = s;
01458     s += len;
01459     len = (byte)*s;
01460     *s++ = '\0'; // zero terminate the string
01461   }
01462 
01463   free(_langpack);
01464   _langpack = lang_pack;
01465 
01466   free(_langpack_offs);
01467   _langpack_offs = langpack_offs;
01468 
01469   _current_language = lang;
01470   _current_text_dir = (TextDirection)_current_language->text_dir;
01471   const char *c_file = strrchr(_current_language->file, PATHSEPCHAR) + 1;
01472   strecpy(_config_language_file, c_file, lastof(_config_language_file));
01473   SetCurrentGrfLangID(_current_language->newgrflangid);
01474 
01475 #ifdef WITH_ICU
01476   /* Delete previous collator. */
01477   if (_current_collator != NULL) {
01478     delete _current_collator;
01479     _current_collator = NULL;
01480   }
01481 
01482   /* Create a collator instance for our current locale. */
01483   UErrorCode status = U_ZERO_ERROR;
01484   _current_collator = Collator::createInstance(Locale(_current_language->isocode), status);
01485   /* Sort number substrings by their numerical value. */
01486   if (_current_collator != NULL) _current_collator->setAttribute(UCOL_NUMERIC_COLLATION, UCOL_ON, status);
01487   /* Avoid using the collator if it is not correctly set. */
01488   if (U_FAILURE(status)) {
01489     delete _current_collator;
01490     _current_collator = NULL;
01491   }
01492 #endif /* WITH_ICU */
01493 
01494   /* Some lists need to be sorted again after a language change. */
01495   InitializeSortedCargoSpecs();
01496   SortIndustryTypes();
01497   BuildIndustriesLegend();
01498   SortNetworkLanguages();
01499   InvalidateWindowClassesData(WC_BUILD_VEHICLE);      // Build vehicle window.
01500   InvalidateWindowClassesData(WC_TRAINS_LIST);        // Train group window.
01501   InvalidateWindowClassesData(WC_ROADVEH_LIST);       // Road vehicle group window.
01502   InvalidateWindowClassesData(WC_SHIPS_LIST);         // Ship group window.
01503   InvalidateWindowClassesData(WC_AIRCRAFT_LIST);      // Aircraft group window.
01504   InvalidateWindowClassesData(WC_INDUSTRY_DIRECTORY); // Industry directory window.
01505   InvalidateWindowClassesData(WC_STATION_LIST);       // Station list window.
01506 
01507   return true;
01508 }
01509 
01510 /* Win32 implementation in win32.cpp.
01511  * OS X implementation in os/macosx/macos.mm. */
01512 #if !(defined(WIN32) || defined(__APPLE__))
01513 
01521 const char *GetCurrentLocale(const char *param)
01522 {
01523   const char *env;
01524 
01525   env = getenv("LANGUAGE");
01526   if (env != NULL) return env;
01527 
01528   env = getenv("LC_ALL");
01529   if (env != NULL) return env;
01530 
01531   if (param != NULL) {
01532     env = getenv(param);
01533     if (env != NULL) return env;
01534   }
01535 
01536   return getenv("LANG");
01537 }
01538 #else
01539 const char *GetCurrentLocale(const char *param);
01540 #endif /* !(defined(WIN32) || defined(__APPLE__)) */
01541 
01542 int CDECL StringIDSorter(const StringID *a, const StringID *b)
01543 {
01544   char stra[512];
01545   char strb[512];
01546   GetString(stra, *a, lastof(stra));
01547   GetString(strb, *b, lastof(strb));
01548 
01549   return strcmp(stra, strb);
01550 }
01551 
01557 const LanguageMetadata *GetLanguage(byte newgrflangid)
01558 {
01559   for (const LanguageMetadata *lang = _languages.Begin(); lang != _languages.End(); lang++) {
01560     if (newgrflangid == lang->newgrflangid) return lang;
01561   }
01562 
01563   return NULL;
01564 }
01565 
01572 static bool GetLanguageFileHeader(const char *file, LanguagePackHeader *hdr)
01573 {
01574   FILE *f = fopen(file, "rb");
01575   if (f == NULL) return false;
01576 
01577   size_t read = fread(hdr, sizeof(*hdr), 1, f);
01578   fclose(f);
01579 
01580   bool ret = read == 1 && hdr->IsValid();
01581 
01582   /* Convert endianness for the windows language ID */
01583   if (ret) hdr->winlangid = FROM_LE16(hdr->winlangid);
01584   return ret;
01585 }
01586 
01591 static void GetLanguageList(const char *path)
01592 {
01593   DIR *dir = ttd_opendir(path);
01594   if (dir != NULL) {
01595     struct dirent *dirent;
01596     while ((dirent = readdir(dir)) != NULL) {
01597       const char *d_name    = FS2OTTD(dirent->d_name);
01598       const char *extension = strrchr(d_name, '.');
01599 
01600       /* Not a language file */
01601       if (extension == NULL || strcmp(extension, ".lng") != 0) continue;
01602 
01603       LanguageMetadata lmd;
01604       seprintf(lmd.file, lastof(lmd.file), "%s%s", path, d_name);
01605 
01606       /* Check whether the file is of the correct version */
01607       if (!GetLanguageFileHeader(lmd.file, &lmd)) {
01608         DEBUG(misc, 3, "%s is not a valid language file", lmd.file);
01609       } else if (GetLanguage(lmd.newgrflangid) != NULL) {
01610         DEBUG(misc, 3, "%s's language ID is already known", lmd.file);
01611       } else {
01612         *_languages.Append() = lmd;
01613       }
01614     }
01615     closedir(dir);
01616   }
01617 }
01618 
01623 void InitializeLanguagePacks()
01624 {
01625   Searchpath sp;
01626 
01627   FOR_ALL_SEARCHPATHS(sp) {
01628     char path[MAX_PATH];
01629     FioAppendDirectory(path, lengthof(path), sp, LANG_DIR);
01630     GetLanguageList(path);
01631   }
01632   if (_languages.Length() == 0) usererror("No available language packs (invalid versions?)");
01633 
01634   /* Acquire the locale of the current system */
01635   const char *lang = GetCurrentLocale("LC_MESSAGES");
01636   if (lang == NULL) lang = "en_GB";
01637 
01638   const LanguageMetadata *chosen_language   = NULL; 
01639   const LanguageMetadata *language_fallback = NULL; 
01640   const LanguageMetadata *en_GB_fallback    = _languages.Begin(); 
01641 
01642   /* Find a proper language. */
01643   for (const LanguageMetadata *lng = _languages.Begin(); lng != _languages.End(); lng++) {
01644     /* We are trying to find a default language. The priority is by
01645      * configuration file, local environment and last, if nothing found,
01646      * english. */
01647     const char *lang_file = strrchr(lng->file, PATHSEPCHAR) + 1;
01648     if (strcmp(lang_file, _config_language_file) == 0) {
01649       chosen_language = lng;
01650       break;
01651     }
01652 
01653     if (strcmp (lng->isocode, "en_GB") == 0) en_GB_fallback    = lng;
01654     if (strncmp(lng->isocode, lang, 5) == 0) chosen_language   = lng;
01655     if (strncmp(lng->isocode, lang, 2) == 0) language_fallback = lng;
01656   }
01657 
01658   /* We haven't found the language in the config nor the one in the locale.
01659    * Now we set it to one of the fallback languages */
01660   if (chosen_language == NULL) {
01661     chosen_language = (language_fallback != NULL) ? language_fallback : en_GB_fallback;
01662   }
01663 
01664   if (!ReadLanguagePack(chosen_language)) usererror("Can't read language pack '%s'", chosen_language->file);
01665 }
01666 
01671 const char *GetCurrentLanguageIsoCode()
01672 {
01673   return _langpack->isocode;
01674 }
01675 
01682 static bool FindMissingGlyphs(const char **str)
01683 {
01684 #ifdef WITH_FREETYPE
01685   UninitFreeType();
01686   InitFreeType();
01687 #endif
01688   const Sprite *question_mark[FS_END];
01689   FontSize size;
01690 
01691   for (size = FS_BEGIN; size < FS_END; size++) {
01692     question_mark[size] = GetGlyph(size, '?');
01693   }
01694 
01695   for (uint i = 0; i != 32; i++) {
01696     for (uint j = 0; j < _langtab_num[i]; j++) {
01697       size = FS_NORMAL;
01698       const char *text = _langpack_offs[_langtab_start[i] + j];
01699       if (str != NULL) *str = text;
01700       for (WChar c = Utf8Consume(&text); c != '\0'; c = Utf8Consume(&text)) {
01701         if (c == SCC_SETX) {
01702           /* SetX is, together with SetXY as special character that
01703            * uses the next (two) characters as data points. We have
01704            * to skip those, otherwise the UTF8 reading will go haywire. */
01705           text++;
01706         } else if (c == SCC_SETXY) {
01707           text += 2;
01708         } else if (c == SCC_TINYFONT) {
01709           size = FS_SMALL;
01710         } else if (c == SCC_BIGFONT) {
01711           size = FS_LARGE;
01712         } else if (IsPrintable(c) && !IsTextDirectionChar(c) && c != '?' && GetGlyph(size, c) == question_mark[size]) {
01713           /* The character is printable, but not in the normal font. This is the case we were testing for. */
01714           return true;
01715         }
01716       }
01717     }
01718   }
01719   return false;
01720 }
01721 
01732 void CheckForMissingGlyphsInLoadedLanguagePack()
01733 {
01734   bool bad_font = FindMissingGlyphs(NULL);
01735 #ifdef WITH_FREETYPE
01736   if (bad_font) {
01737     /* We found an unprintable character... lets try whether we can find
01738      * a fallback font that can print the characters in the current language. */
01739     FreeTypeSettings backup;
01740     memcpy(&backup, &_freetype, sizeof(backup));
01741 
01742     bad_font = !SetFallbackFont(&_freetype, _langpack->isocode, _langpack->winlangid, &FindMissingGlyphs);
01743 
01744     memcpy(&_freetype, &backup, sizeof(backup));
01745 
01746     if (bad_font) {
01747       /* Our fallback font does miss characters too, so keep the
01748         * user chosen font as that is more likely to be any good than
01749         * the wild guess we made */
01750       UninitFreeType();
01751       InitFreeType();
01752     }
01753   }
01754 #endif
01755 
01756   if (bad_font) {
01757     /* All attempts have failed. Display an error. As we do not want the string to be translated by
01758      * the translators, we 'force' it into the binary and 'load' it via a BindCString. To do this
01759      * properly we have to set the colour of the string, otherwise we end up with a lot of artefacts.
01760      * The colour 'character' might change in the future, so for safety we just Utf8 Encode it into
01761      * the string, which takes exactly three characters, so it replaces the "XXX" with the colour marker. */
01762     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.");
01763     Utf8Encode(err_str, SCC_YELLOW);
01764     SetDParamStr(0, err_str);
01765     ShowErrorMessage(STR_JUST_RAW_STRING, INVALID_STRING_ID, WL_WARNING);
01766 
01767     /* Reset the font width */
01768     LoadStringWidthTable();
01769     return;
01770   }
01771 
01772   /* Update the font with cache */
01773   LoadStringWidthTable();
01774 
01775 #if !defined(WITH_ICU)
01776   /*
01777    * For right-to-left languages we need the ICU library. If
01778    * we do not have support for that library we warn the user
01779    * about it with a message. As we do not want the string to
01780    * be translated by the translators, we 'force' it into the
01781    * binary and 'load' it via a BindCString. To do this
01782    * properly we have to set the colour of the string,
01783    * otherwise we end up with a lot of artefacts. The colour
01784    * 'character' might change in the future, so for safety
01785    * we just Utf8 Encode it into the string, which takes
01786    * exactly three characters, so it replaces the "XXX" with
01787    * the colour marker.
01788    */
01789   if (_current_text_dir != TD_LTR) {
01790     static char *err_str = strdup("XXXThis version of OpenTTD does not support right-to-left languages. Recompile with icu enabled.");
01791     Utf8Encode(err_str, SCC_YELLOW);
01792     SetDParamStr(0, err_str);
01793     ShowErrorMessage(STR_JUST_RAW_STRING, INVALID_STRING_ID, WL_ERROR);
01794   }
01795 #endif
01796 }

Generated on Thu Jan 20 22:57:41 2011 for OpenTTD by  doxygen 1.6.1