OpenTTD Source  13.2.1
strings.cpp
Go to the documentation of this file.
1 /*
2  * This file is part of OpenTTD.
3  * 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.
4  * 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.
5  * 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/>.
6  */
7 
10 #include "stdafx.h"
11 #include "currency.h"
12 #include "station_base.h"
13 #include "town.h"
14 #include "waypoint_base.h"
15 #include "depot_base.h"
16 #include "industry.h"
17 #include "newgrf_text.h"
18 #include "fileio_func.h"
19 #include "signs_base.h"
20 #include "fontdetection.h"
21 #include "error.h"
22 #include "strings_func.h"
23 #include "rev.h"
24 #include "core/endian_func.hpp"
25 #include "date_func.h"
26 #include "vehicle_base.h"
27 #include "engine_base.h"
28 #include "language.h"
29 #include "townname_func.h"
30 #include "string_func.h"
31 #include "company_base.h"
32 #include "smallmap_gui.h"
33 #include "window_func.h"
34 #include "debug.h"
35 #include "game/game_text.hpp"
37 #include "newgrf_engine.h"
38 #include <stack>
39 
40 #include "table/strings.h"
41 #include "table/control_codes.h"
42 
43 #include "safeguards.h"
44 
45 std::string _config_language_file;
48 
50 
51 #ifdef WITH_ICU_I18N
52 std::unique_ptr<icu::Collator> _current_collator;
53 #endif /* WITH_ICU_I18N */
54 
55 static uint64 _global_string_params_data[20];
58 
61 {
62  assert(this->type != nullptr);
63  MemSetT(this->type, 0, this->num_param);
64 }
65 
66 
72 {
73  if (this->offset >= this->num_param) {
74  Debug(misc, 0, "Trying to read invalid string parameter");
75  return 0;
76  }
77  if (this->type != nullptr) {
78  if (this->type[this->offset] != 0 && this->type[this->offset] != type) {
79  Debug(misc, 0, "Trying to read string parameter with wrong type");
80  return 0;
81  }
82  this->type[this->offset] = type;
83  }
84  return this->data[this->offset++];
85 }
86 
95 void SetDParamMaxValue(uint n, uint64 max_value, uint min_count, FontSize size)
96 {
97  uint num_digits = 1;
98  while (max_value >= 10) {
99  num_digits++;
100  max_value /= 10;
101  }
102  SetDParamMaxDigits(n, std::max(min_count, num_digits), size);
103 }
104 
111 void SetDParamMaxDigits(uint n, uint count, FontSize size)
112 {
113  uint front = 0;
114  uint next = 0;
115  GetBroadestDigit(&front, &next, size);
116  uint64 val = count > 1 ? front : next;
117  for (; count > 1; count--) {
118  val = 10 * val + next;
119  }
120  SetDParam(n, val);
121 }
122 
129 void CopyInDParam(int offs, const uint64 *src, int num)
130 {
131  MemCpyT(_global_string_params.GetPointerToOffset(offs), src, num);
132 }
133 
140 void CopyOutDParam(uint64 *dst, int offs, int num)
141 {
142  MemCpyT(dst, _global_string_params.GetPointerToOffset(offs), num);
143 }
144 
153 void CopyOutDParam(uint64 *dst, const char **strings, StringID string, int num)
154 {
155  char buf[DRAW_STRING_BUFFER];
156  GetString(buf, string, lastof(buf));
157 
158  MemCpyT(dst, _global_string_params.GetPointerToOffset(0), num);
159  for (int i = 0; i < num; i++) {
160  if (_global_string_params.HasTypeInformation() && _global_string_params.GetTypeAtOffset(i) == SCC_RAW_STRING_POINTER) {
161  strings[i] = stredup((const char *)(size_t)_global_string_params.GetParam(i));
162  dst[i] = (size_t)strings[i];
163  } else {
164  strings[i] = nullptr;
165  }
166  }
167 }
168 
169 static char *StationGetSpecialString(char *buff, int x, const char *last);
170 static char *GetSpecialTownNameString(char *buff, int ind, uint32 seed, const char *last);
171 static char *GetSpecialNameString(char *buff, int ind, StringParameters *args, const char *last);
172 
173 static char *FormatString(char *buff, const char *str, StringParameters *args, const char *last, uint case_index = 0, bool game_script = false, bool dry_run = false);
174 
176  char data[]; // list of strings
177 };
178 
180  void operator()(LanguagePack *langpack)
181  {
182  /* LanguagePack is in fact reinterpreted char[], we need to reinterpret it back to free it properly. */
183  delete[] reinterpret_cast<char*>(langpack);
184  }
185 };
186 
188  std::unique_ptr<LanguagePack, LanguagePackDeleter> langpack;
189 
190  std::vector<char *> offsets;
191 
192  std::array<uint, TEXT_TAB_END> langtab_num;
193  std::array<uint, TEXT_TAB_END> langtab_start;
194 };
195 
196 static LoadedLanguagePack _langpack;
197 
198 static bool _scan_for_gender_data = false;
199 
200 
201 const char *GetStringPtr(StringID string)
202 {
203  switch (GetStringTab(string)) {
205  /* 0xD0xx and 0xD4xx IDs have been converted earlier. */
206  case TEXT_TAB_OLD_NEWGRF: NOT_REACHED();
208  default: return _langpack.offsets[_langpack.langtab_start[GetStringTab(string)] + GetStringIndex(string)];
209  }
210 }
211 
222 char *GetStringWithArgs(char *buffr, StringID string, StringParameters *args, const char *last, uint case_index, bool game_script)
223 {
224  if (string == 0) return GetStringWithArgs(buffr, STR_UNDEFINED, args, last);
225 
226  uint index = GetStringIndex(string);
227  StringTab tab = GetStringTab(string);
228 
229  switch (tab) {
230  case TEXT_TAB_TOWN:
231  if (index >= 0xC0 && !game_script) {
232  return GetSpecialTownNameString(buffr, index - 0xC0, args->GetInt32(), last);
233  }
234  break;
235 
236  case TEXT_TAB_SPECIAL:
237  if (index >= 0xE4 && !game_script) {
238  return GetSpecialNameString(buffr, index - 0xE4, args, last);
239  }
240  break;
241 
242  case TEXT_TAB_OLD_CUSTOM:
243  /* Old table for custom names. This is no longer used */
244  if (!game_script) {
245  error("Incorrect conversion of custom name string.");
246  }
247  break;
248 
250  return FormatString(buffr, GetGameStringPtr(index), args, last, case_index, true);
251 
252  case TEXT_TAB_OLD_NEWGRF:
253  NOT_REACHED();
254 
256  return FormatString(buffr, GetGRFStringPtr(index), args, last, case_index);
257 
258  default:
259  break;
260  }
261 
262  if (index >= _langpack.langtab_num[tab]) {
263  if (game_script) {
264  return GetStringWithArgs(buffr, STR_UNDEFINED, args, last);
265  }
266  error("String 0x%X is invalid. You are probably using an old version of the .lng file.\n", string);
267  }
268 
269  return FormatString(buffr, GetStringPtr(string), args, last, case_index);
270 }
271 
272 char *GetString(char *buffr, StringID string, const char *last)
273 {
274  _global_string_params.ClearTypeInformation();
275  _global_string_params.offset = 0;
276  return GetStringWithArgs(buffr, string, &_global_string_params, last);
277 }
278 
285 std::string GetString(StringID string)
286 {
287  char buffer[DRAW_STRING_BUFFER];
288  GetString(buffer, string, lastof(buffer));
289  return buffer;
290 }
291 
297 void SetDParamStr(uint n, const char *str)
298 {
299  SetDParam(n, (uint64)(size_t)str);
300 }
301 
308 void SetDParamStr(uint n, const std::string &str)
309 {
310  SetDParamStr(n, str.c_str());
311 }
312 
324 static char *FormatNumber(char *buff, int64 number, const char *last, const char *separator, int zerofill = 1, int fractional_digits = 0)
325 {
326  static const int max_digits = 20;
327  uint64 divisor = 10000000000000000000ULL;
328  zerofill += fractional_digits;
329  int thousands_offset = (max_digits - fractional_digits - 1) % 3;
330 
331  if (number < 0) {
332  buff += seprintf(buff, last, "-");
333  number = -number;
334  }
335 
336  uint64 num = number;
337  uint64 tot = 0;
338  for (int i = 0; i < max_digits; i++) {
339  if (i == max_digits - fractional_digits) {
340  const char *decimal_separator = _settings_game.locale.digit_decimal_separator.c_str();
341  if (StrEmpty(decimal_separator)) decimal_separator = _langpack.langpack->digit_decimal_separator;
342  buff += seprintf(buff, last, "%s", decimal_separator);
343  }
344 
345  uint64 quot = 0;
346  if (num >= divisor) {
347  quot = num / divisor;
348  num = num % divisor;
349  }
350  if ((tot |= quot) || i >= max_digits - zerofill) {
351  buff += seprintf(buff, last, "%i", (int)quot);
352  if ((i % 3) == thousands_offset && i < max_digits - 1 - fractional_digits) buff = strecpy(buff, separator, last);
353  }
354 
355  divisor /= 10;
356  }
357 
358  *buff = '\0';
359 
360  return buff;
361 }
362 
363 static char *FormatCommaNumber(char *buff, int64 number, const char *last, int fractional_digits = 0)
364 {
365  const char *separator = _settings_game.locale.digit_group_separator.c_str();
366  if (StrEmpty(separator)) separator = _langpack.langpack->digit_group_separator;
367  return FormatNumber(buff, number, last, separator, 1, fractional_digits);
368 }
369 
370 static char *FormatNoCommaNumber(char *buff, int64 number, const char *last)
371 {
372  return FormatNumber(buff, number, last, "");
373 }
374 
375 static char *FormatZerofillNumber(char *buff, int64 number, int64 count, const char *last)
376 {
377  return FormatNumber(buff, number, last, "", count);
378 }
379 
380 static char *FormatHexNumber(char *buff, uint64 number, const char *last)
381 {
382  return buff + seprintf(buff, last, "0x" OTTD_PRINTFHEX64, number);
383 }
384 
392 static char *FormatBytes(char *buff, int64 number, const char *last)
393 {
394  assert(number >= 0);
395 
396  /* 1 2^10 2^20 2^30 2^40 2^50 2^60 */
397  const char * const iec_prefixes[] = {"", "Ki", "Mi", "Gi", "Ti", "Pi", "Ei"};
398  uint id = 1;
399  while (number >= 1024 * 1024) {
400  number /= 1024;
401  id++;
402  }
403 
404  const char *decimal_separator = _settings_game.locale.digit_decimal_separator.c_str();
405  if (StrEmpty(decimal_separator)) decimal_separator = _langpack.langpack->digit_decimal_separator;
406 
407  if (number < 1024) {
408  id = 0;
409  buff += seprintf(buff, last, "%i", (int)number);
410  } else if (number < 1024 * 10) {
411  buff += seprintf(buff, last, "%i%s%02i", (int)number / 1024, decimal_separator, (int)(number % 1024) * 100 / 1024);
412  } else if (number < 1024 * 100) {
413  buff += seprintf(buff, last, "%i%s%01i", (int)number / 1024, decimal_separator, (int)(number % 1024) * 10 / 1024);
414  } else {
415  assert(number < 1024 * 1024);
416  buff += seprintf(buff, last, "%i", (int)number / 1024);
417  }
418 
419  assert(id < lengthof(iec_prefixes));
420  buff += seprintf(buff, last, NBSP "%sB", iec_prefixes[id]);
421 
422  return buff;
423 }
424 
425 static char *FormatYmdString(char *buff, Date date, const char *last, uint case_index)
426 {
427  YearMonthDay ymd;
428  ConvertDateToYMD(date, &ymd);
429 
430  int64 args[] = {ymd.day + STR_DAY_NUMBER_1ST - 1, STR_MONTH_ABBREV_JAN + ymd.month, ymd.year};
431  StringParameters tmp_params(args);
432  return FormatString(buff, GetStringPtr(STR_FORMAT_DATE_LONG), &tmp_params, last, case_index);
433 }
434 
435 static char *FormatMonthAndYear(char *buff, Date date, const char *last, uint case_index)
436 {
437  YearMonthDay ymd;
438  ConvertDateToYMD(date, &ymd);
439 
440  int64 args[] = {STR_MONTH_JAN + ymd.month, ymd.year};
441  StringParameters tmp_params(args);
442  return FormatString(buff, GetStringPtr(STR_FORMAT_DATE_SHORT), &tmp_params, last, case_index);
443 }
444 
445 static char *FormatTinyOrISODate(char *buff, Date date, StringID str, const char *last)
446 {
447  YearMonthDay ymd;
448  ConvertDateToYMD(date, &ymd);
449 
450  char day[3];
451  char month[3];
452  /* We want to zero-pad the days and months */
453  seprintf(day, lastof(day), "%02i", ymd.day);
454  seprintf(month, lastof(month), "%02i", ymd.month + 1);
455 
456  int64 args[] = {(int64)(size_t)day, (int64)(size_t)month, ymd.year};
457  StringParameters tmp_params(args);
458  return FormatString(buff, GetStringPtr(str), &tmp_params, last);
459 }
460 
461 static char *FormatGenericCurrency(char *buff, const CurrencySpec *spec, Money number, bool compact, const char *last)
462 {
463  /* We are going to make number absolute for printing, so
464  * keep this piece of data as we need it later on */
465  bool negative = number < 0;
466  const char *multiplier = "";
467 
468  number *= spec->rate;
469 
470  /* convert from negative */
471  if (number < 0) {
472  if (buff + Utf8CharLen(SCC_PUSH_COLOUR) > last) return buff;
473  buff += Utf8Encode(buff, SCC_PUSH_COLOUR);
474  if (buff + Utf8CharLen(SCC_RED) > last) return buff;
475  buff += Utf8Encode(buff, SCC_RED);
476  buff = strecpy(buff, "-", last);
477  number = -number;
478  }
479 
480  /* Add prefix part, following symbol_pos specification.
481  * Here, it can can be either 0 (prefix) or 2 (both prefix and suffix).
482  * The only remaining value is 1 (suffix), so everything that is not 1 */
483  if (spec->symbol_pos != 1) buff = strecpy(buff, spec->prefix.c_str(), last);
484 
485  /* for huge numbers, compact the number into k or M */
486  if (compact) {
487  /* Take care of the 'k' rounding. Having 1 000 000 k
488  * and 1 000 M is inconsistent, so always use 1 000 M. */
489  if (number >= 1000000000 - 500) {
490  number = (number + 500000) / 1000000;
491  multiplier = NBSP "M";
492  } else if (number >= 1000000) {
493  number = (number + 500) / 1000;
494  multiplier = NBSP "k";
495  }
496  }
497 
498  const char *separator = _settings_game.locale.digit_group_separator_currency.c_str();
499  if (StrEmpty(separator)) separator = _currency->separator.c_str();
500  if (StrEmpty(separator)) separator = _langpack.langpack->digit_group_separator_currency;
501  buff = FormatNumber(buff, number, last, separator);
502  buff = strecpy(buff, multiplier, last);
503 
504  /* Add suffix part, following symbol_pos specification.
505  * Here, it can can be either 1 (suffix) or 2 (both prefix and suffix).
506  * The only remaining value is 1 (prefix), so everything that is not 0 */
507  if (spec->symbol_pos != 0) buff = strecpy(buff, spec->suffix.c_str(), last);
508 
509  if (negative) {
510  if (buff + Utf8CharLen(SCC_POP_COLOUR) > last) return buff;
511  buff += Utf8Encode(buff, SCC_POP_COLOUR);
512  *buff = '\0';
513  }
514 
515  return buff;
516 }
517 
524 static int DeterminePluralForm(int64 count, int plural_form)
525 {
526  /* The absolute value determines plurality */
527  uint64 n = abs(count);
528 
529  switch (plural_form) {
530  default:
531  NOT_REACHED();
532 
533  /* Two forms: singular used for one only.
534  * Used in:
535  * Danish, Dutch, English, German, Norwegian, Swedish, Estonian, Finnish,
536  * Greek, Hebrew, Italian, Portuguese, Spanish, Esperanto */
537  case 0:
538  return n != 1 ? 1 : 0;
539 
540  /* Only one form.
541  * Used in:
542  * Hungarian, Japanese, Turkish */
543  case 1:
544  return 0;
545 
546  /* Two forms: singular used for 0 and 1.
547  * Used in:
548  * French, Brazilian Portuguese */
549  case 2:
550  return n > 1 ? 1 : 0;
551 
552  /* Three forms: special cases for 0, and numbers ending in 1 except when ending in 11.
553  * Note: Cases are out of order for hysterical reasons. '0' is last.
554  * Used in:
555  * Latvian */
556  case 3:
557  return n % 10 == 1 && n % 100 != 11 ? 0 : n != 0 ? 1 : 2;
558 
559  /* Five forms: special cases for 1, 2, 3 to 6, and 7 to 10.
560  * Used in:
561  * Gaelige (Irish) */
562  case 4:
563  return n == 1 ? 0 : n == 2 ? 1 : n < 7 ? 2 : n < 11 ? 3 : 4;
564 
565  /* Three forms: special cases for numbers ending in 1 except when ending in 11, and 2 to 9 except when ending in 12 to 19.
566  * Used in:
567  * Lithuanian */
568  case 5:
569  return n % 10 == 1 && n % 100 != 11 ? 0 : n % 10 >= 2 && (n % 100 < 10 || n % 100 >= 20) ? 1 : 2;
570 
571  /* Three forms: special cases for numbers ending in 1 except when ending in 11, and 2 to 4 except when ending in 12 to 14.
572  * Used in:
573  * Croatian, Russian, Ukrainian */
574  case 6:
575  return n % 10 == 1 && n % 100 != 11 ? 0 : n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 10 || n % 100 >= 20) ? 1 : 2;
576 
577  /* Three forms: special cases for 1, and numbers ending in 2 to 4 except when ending in 12 to 14.
578  * Used in:
579  * Polish */
580  case 7:
581  return n == 1 ? 0 : n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 10 || n % 100 >= 20) ? 1 : 2;
582 
583  /* Four forms: special cases for numbers ending in 01, 02, and 03 to 04.
584  * Used in:
585  * Slovenian */
586  case 8:
587  return n % 100 == 1 ? 0 : n % 100 == 2 ? 1 : n % 100 == 3 || n % 100 == 4 ? 2 : 3;
588 
589  /* Two forms: singular used for numbers ending in 1 except when ending in 11.
590  * Used in:
591  * Icelandic */
592  case 9:
593  return n % 10 == 1 && n % 100 != 11 ? 0 : 1;
594 
595  /* Three forms: special cases for 1, and 2 to 4
596  * Used in:
597  * Czech, Slovak */
598  case 10:
599  return n == 1 ? 0 : n >= 2 && n <= 4 ? 1 : 2;
600 
601  /* Two forms: cases for numbers ending with a consonant, and with a vowel.
602  * Korean doesn't have the concept of plural, but depending on how a
603  * number is pronounced it needs another version of a particle.
604  * As such the plural system is misused to give this distinction.
605  */
606  case 11:
607  switch (n % 10) {
608  case 0: // yeong
609  case 1: // il
610  case 3: // sam
611  case 6: // yuk
612  case 7: // chil
613  case 8: // pal
614  return 0;
615 
616  case 2: // i
617  case 4: // sa
618  case 5: // o
619  case 9: // gu
620  return 1;
621 
622  default:
623  NOT_REACHED();
624  }
625 
626  /* Four forms: special cases for 1, 0 and numbers ending in 02 to 10, and numbers ending in 11 to 19.
627  * Used in:
628  * Maltese */
629  case 12:
630  return (n == 1 ? 0 : n == 0 || (n % 100 > 1 && n % 100 < 11) ? 1 : (n % 100 > 10 && n % 100 < 20) ? 2 : 3);
631  /* Four forms: special cases for 1 and 11, 2 and 12, 3 .. 10 and 13 .. 19, other
632  * Used in:
633  * Scottish Gaelic */
634  case 13:
635  return ((n == 1 || n == 11) ? 0 : (n == 2 || n == 12) ? 1 : ((n > 2 && n < 11) || (n > 12 && n < 20)) ? 2 : 3);
636 
637  /* Three forms: special cases for 1, 0 and numbers ending in 01 to 19.
638  * Used in:
639  * Romanian */
640  case 14:
641  return n == 1 ? 0 : (n == 0 || (n % 100 > 0 && n % 100 < 20)) ? 1 : 2;
642  }
643 }
644 
645 static const char *ParseStringChoice(const char *b, uint form, char **dst, const char *last)
646 {
647  /* <NUM> {Length of each string} {each string} */
648  uint n = (byte)*b++;
649  uint pos, i, mypos = 0;
650 
651  for (i = pos = 0; i != n; i++) {
652  uint len = (byte)*b++;
653  if (i == form) mypos = pos;
654  pos += len;
655  }
656 
657  *dst += seprintf(*dst, last, "%s", b + mypos);
658  return b + pos;
659 }
660 
664  int shift;
665 
672  int64 ToDisplay(int64 input, bool round = true) const
673  {
674  return ((input * this->multiplier) + (round && this->shift != 0 ? 1 << (this->shift - 1) : 0)) >> this->shift;
675  }
676 
684  int64 FromDisplay(int64 input, bool round = true, int64 divider = 1) const
685  {
686  return ((input << this->shift) + (round ? (this->multiplier * divider) - 1 : 0)) / (this->multiplier * divider);
687  }
688 };
689 
691 struct Units {
694  unsigned int decimal_places;
695 };
696 
698 struct UnitsLong {
702 };
703 
705 static const Units _units_velocity[] = {
706  { { 1, 0}, STR_UNITS_VELOCITY_IMPERIAL, 0 },
707  { { 103, 6}, STR_UNITS_VELOCITY_METRIC, 0 },
708  { { 1831, 12}, STR_UNITS_VELOCITY_SI, 0 },
709  { {37888, 16}, STR_UNITS_VELOCITY_GAMEUNITS, 1 },
710 };
711 
713 static const Units _units_power[] = {
714  { { 1, 0}, STR_UNITS_POWER_IMPERIAL, 0 },
715  { {4153, 12}, STR_UNITS_POWER_METRIC, 0 },
716  { {6109, 13}, STR_UNITS_POWER_SI, 0 },
717 };
718 
720 static const Units _units_power_to_weight[] = {
721  { { 29, 5}, STR_UNITS_POWER_IMPERIAL_TO_WEIGHT_IMPERIAL, 1},
722  { { 1, 0}, STR_UNITS_POWER_IMPERIAL_TO_WEIGHT_METRIC, 1},
723  { { 1, 0}, STR_UNITS_POWER_IMPERIAL_TO_WEIGHT_SI, 1},
724  { { 59, 6}, STR_UNITS_POWER_METRIC_TO_WEIGHT_IMPERIAL, 1},
725  { { 65, 6}, STR_UNITS_POWER_METRIC_TO_WEIGHT_METRIC, 1},
726  { { 65, 6}, STR_UNITS_POWER_METRIC_TO_WEIGHT_SI, 1},
727  { { 173, 8}, STR_UNITS_POWER_SI_TO_WEIGHT_IMPERIAL, 1},
728  { { 3, 2}, STR_UNITS_POWER_SI_TO_WEIGHT_METRIC, 1},
729  { { 3, 2}, STR_UNITS_POWER_SI_TO_WEIGHT_SI, 1},
730 };
731 
733 static const UnitsLong _units_weight[] = {
734  { {4515, 12}, STR_UNITS_WEIGHT_SHORT_IMPERIAL, STR_UNITS_WEIGHT_LONG_IMPERIAL },
735  { { 1, 0}, STR_UNITS_WEIGHT_SHORT_METRIC, STR_UNITS_WEIGHT_LONG_METRIC },
736  { {1000, 0}, STR_UNITS_WEIGHT_SHORT_SI, STR_UNITS_WEIGHT_LONG_SI },
737 };
738 
740 static const UnitsLong _units_volume[] = {
741  { {4227, 4}, STR_UNITS_VOLUME_SHORT_IMPERIAL, STR_UNITS_VOLUME_LONG_IMPERIAL },
742  { {1000, 0}, STR_UNITS_VOLUME_SHORT_METRIC, STR_UNITS_VOLUME_LONG_METRIC },
743  { { 1, 0}, STR_UNITS_VOLUME_SHORT_SI, STR_UNITS_VOLUME_LONG_SI },
744 };
745 
747 static const Units _units_force[] = {
748  { {3597, 4}, STR_UNITS_FORCE_IMPERIAL, 0 },
749  { {3263, 5}, STR_UNITS_FORCE_METRIC, 0 },
750  { { 1, 0}, STR_UNITS_FORCE_SI, 0 },
751 };
752 
754 static const Units _units_height[] = {
755  { { 3, 0}, STR_UNITS_HEIGHT_IMPERIAL, 0 }, // "Wrong" conversion factor for more nicer GUI values
756  { { 1, 0}, STR_UNITS_HEIGHT_METRIC, 0 },
757  { { 1, 0}, STR_UNITS_HEIGHT_SI, 0 },
758 };
759 
766 {
767  /* For historical reasons we don't want to mess with the
768  * conversion for speed. So, don't round it and keep the
769  * original conversion factors instead of the real ones. */
771 }
772 
779 {
781 }
782 
789 {
790  return _units_velocity[_settings_game.locale.units_velocity].c.ToDisplay(speed * 10, false) / 16;
791 }
792 
799 {
800  return _units_velocity[_settings_game.locale.units_velocity].c.FromDisplay(speed * 16, true, 10);
801 }
810 static char *FormatString(char *buff, const char *str_arg, StringParameters *args, const char *last, uint case_index, bool game_script, bool dry_run)
811 {
812  uint orig_offset = args->offset;
813 
814  /* When there is no array with types there is no need to do a dry run. */
815  if (args->HasTypeInformation() && !dry_run) {
816  if (UsingNewGRFTextStack()) {
817  /* Values from the NewGRF text stack are only copied to the normal
818  * argv array at the time they are encountered. That means that if
819  * another string command references a value later in the string it
820  * would fail. We solve that by running FormatString twice. The first
821  * pass makes sure the argv array is correctly filled and the second
822  * pass can reference later values without problems. */
823  struct TextRefStack *backup = CreateTextRefStackBackup();
824  FormatString(buff, str_arg, args, last, case_index, game_script, true);
826  } else {
827  FormatString(buff, str_arg, args, last, case_index, game_script, true);
828  }
829  /* We have to restore the original offset here to to read the correct values. */
830  args->offset = orig_offset;
831  }
832  WChar b = '\0';
833  uint next_substr_case_index = 0;
834  char *buf_start = buff;
835  std::stack<const char *, std::vector<const char *>> str_stack;
836  str_stack.push(str_arg);
837 
838  for (;;) {
839  while (!str_stack.empty() && (b = Utf8Consume(&str_stack.top())) == '\0') {
840  str_stack.pop();
841  }
842  if (str_stack.empty()) break;
843  const char *&str = str_stack.top();
844 
845  if (SCC_NEWGRF_FIRST <= b && b <= SCC_NEWGRF_LAST) {
846  /* We need to pass some stuff as it might be modified. */
847  //todo: should argve be passed here too?
848  b = RemapNewGRFStringControlCode(b, buf_start, &buff, &str, (int64 *)args->GetDataPointer(), args->GetDataLeft(), dry_run);
849  if (b == 0) continue;
850  }
851 
852  switch (b) {
853  case SCC_ENCODED: {
854  uint64 sub_args_data[20];
855  WChar sub_args_type[20];
856  bool sub_args_need_free[20];
857  StringParameters sub_args(sub_args_data, 20, sub_args_type);
858 
859  sub_args.ClearTypeInformation();
860  memset(sub_args_need_free, 0, sizeof(sub_args_need_free));
861 
862  char *p;
863  uint32 stringid = strtoul(str, &p, 16);
864  if (*p != ':' && *p != '\0') {
865  while (*p != '\0') p++;
866  str = p;
867  buff = strecat(buff, "(invalid SCC_ENCODED)", last);
868  break;
869  }
870  if (stringid >= TAB_SIZE_GAMESCRIPT) {
871  while (*p != '\0') p++;
872  str = p;
873  buff = strecat(buff, "(invalid StringID)", last);
874  break;
875  }
876 
877  int i = 0;
878  while (*p != '\0' && i < 20) {
879  uint64 param;
880  const char *s = ++p;
881 
882  /* Find the next value */
883  bool instring = false;
884  bool escape = false;
885  for (;; p++) {
886  if (*p == '\\') {
887  escape = true;
888  continue;
889  }
890  if (*p == '"' && escape) {
891  escape = false;
892  continue;
893  }
894  escape = false;
895 
896  if (*p == '"') {
897  instring = !instring;
898  continue;
899  }
900  if (instring) {
901  continue;
902  }
903 
904  if (*p == ':') break;
905  if (*p == '\0') break;
906  }
907 
908  if (*s != '"') {
909  /* Check if we want to look up another string */
910  WChar l;
911  size_t len = Utf8Decode(&l, s);
912  bool lookup = (l == SCC_ENCODED);
913  if (lookup) s += len;
914 
915  param = strtoull(s, &p, 16);
916 
917  if (lookup) {
918  if (param >= TAB_SIZE_GAMESCRIPT) {
919  while (*p != '\0') p++;
920  str = p;
921  buff = strecat(buff, "(invalid sub-StringID)", last);
922  break;
923  }
924  param = MakeStringID(TEXT_TAB_GAMESCRIPT_START, param);
925  }
926 
927  sub_args.SetParam(i++, param);
928  } else {
929  char *g = stredup(s);
930  g[p - s] = '\0';
931 
932  sub_args_need_free[i] = true;
933  sub_args.SetParam(i++, (uint64)(size_t)g);
934  }
935  }
936  /* If we didn't error out, we can actually print the string. */
937  if (*str != '\0') {
938  str = p;
939  buff = GetStringWithArgs(buff, MakeStringID(TEXT_TAB_GAMESCRIPT_START, stringid), &sub_args, last, true);
940  }
941 
942  for (int i = 0; i < 20; i++) {
943  if (sub_args_need_free[i]) free((void *)sub_args.GetParam(i));
944  }
945  break;
946  }
947 
948  case SCC_NEWGRF_STRINL: {
949  StringID substr = Utf8Consume(&str);
950  str_stack.push(GetStringPtr(substr));
951  break;
952  }
953 
956  str_stack.push(GetStringPtr(substr));
957  case_index = next_substr_case_index;
958  next_substr_case_index = 0;
959  break;
960  }
961 
962 
963  case SCC_GENDER_LIST: { // {G 0 Der Die Das}
964  /* First read the meta data from the language file. */
965  uint offset = orig_offset + (byte)*str++;
966  int gender = 0;
967  if (!dry_run && args->GetTypeAtOffset(offset) != 0) {
968  /* Now we need to figure out what text to resolve, i.e.
969  * what do we need to draw? So get the actual raw string
970  * first using the control code to get said string. */
971  char input[4 + 1];
972  char *p = input + Utf8Encode(input, args->GetTypeAtOffset(offset));
973  *p = '\0';
974 
975  /* Now do the string formatting. */
976  char buf[256];
977  bool old_sgd = _scan_for_gender_data;
978  _scan_for_gender_data = true;
979  StringParameters tmp_params(args->GetPointerToOffset(offset), args->num_param - offset, nullptr);
980  p = FormatString(buf, input, &tmp_params, lastof(buf));
981  _scan_for_gender_data = old_sgd;
982  *p = '\0';
983 
984  /* And determine the string. */
985  const char *s = buf;
986  WChar c = Utf8Consume(&s);
987  /* Does this string have a gender, if so, set it */
988  if (c == SCC_GENDER_INDEX) gender = (byte)s[0];
989  }
990  str = ParseStringChoice(str, gender, &buff, last);
991  break;
992  }
993 
994  /* This sets up the gender for the string.
995  * We just ignore this one. It's used in {G 0 Der Die Das} to determine the case. */
996  case SCC_GENDER_INDEX: // {GENDER 0}
997  if (_scan_for_gender_data) {
998  buff += Utf8Encode(buff, SCC_GENDER_INDEX);
999  *buff++ = *str++;
1000  } else {
1001  str++;
1002  }
1003  break;
1004 
1005  case SCC_PLURAL_LIST: { // {P}
1006  int plural_form = *str++; // contains the plural form for this string
1007  uint offset = orig_offset + (byte)*str++;
1008  int64 v = *args->GetPointerToOffset(offset); // contains the number that determines plural
1009  str = ParseStringChoice(str, DeterminePluralForm(v, plural_form), &buff, last);
1010  break;
1011  }
1012 
1013  case SCC_ARG_INDEX: { // Move argument pointer
1014  args->offset = orig_offset + (byte)*str++;
1015  break;
1016  }
1017 
1018  case SCC_SET_CASE: { // {SET_CASE}
1019  /* This is a pseudo command, it's outputted when someone does {STRING.ack}
1020  * The modifier is added to all subsequent GetStringWithArgs that accept the modifier. */
1021  next_substr_case_index = (byte)*str++;
1022  break;
1023  }
1024 
1025  case SCC_SWITCH_CASE: { // {Used to implement case switching}
1026  /* <0x9E> <NUM CASES> <CASE1> <LEN1> <STRING1> <CASE2> <LEN2> <STRING2> <CASE3> <LEN3> <STRING3> <STRINGDEFAULT>
1027  * Each LEN is printed using 2 bytes in big endian order. */
1028  uint num = (byte)*str++;
1029  while (num) {
1030  if ((byte)str[0] == case_index) {
1031  /* Found the case, adjust str pointer and continue */
1032  str += 3;
1033  break;
1034  }
1035  /* Otherwise skip to the next case */
1036  str += 3 + (str[1] << 8) + str[2];
1037  num--;
1038  }
1039  break;
1040  }
1041 
1042  case SCC_REVISION: // {REV}
1043  buff = strecpy(buff, _openttd_revision, last);
1044  break;
1045 
1046  case SCC_RAW_STRING_POINTER: { // {RAW_STRING}
1047  if (game_script) break;
1048  const char *str = (const char *)(size_t)args->GetInt64(SCC_RAW_STRING_POINTER);
1049  buff = FormatString(buff, str, args, last);
1050  break;
1051  }
1052 
1053  case SCC_STRING: {// {STRING}
1054  StringID str = args->GetInt32(SCC_STRING);
1055  if (game_script && GetStringTab(str) != TEXT_TAB_GAMESCRIPT_START) break;
1056  /* WARNING. It's prohibited for the included string to consume any arguments.
1057  * For included strings that consume argument, you should use STRING1, STRING2 etc.
1058  * To debug stuff you can set argv to nullptr and it will tell you */
1059  StringParameters tmp_params(args->GetDataPointer(), args->GetDataLeft(), nullptr);
1060  buff = GetStringWithArgs(buff, str, &tmp_params, last, next_substr_case_index, game_script);
1061  next_substr_case_index = 0;
1062  break;
1063  }
1064 
1065  case SCC_STRING1:
1066  case SCC_STRING2:
1067  case SCC_STRING3:
1068  case SCC_STRING4:
1069  case SCC_STRING5:
1070  case SCC_STRING6:
1071  case SCC_STRING7: { // {STRING1..7}
1072  /* Strings that consume arguments */
1073  StringID str = args->GetInt32(b);
1074  if (game_script && GetStringTab(str) != TEXT_TAB_GAMESCRIPT_START) break;
1075  uint size = b - SCC_STRING1 + 1;
1076  if (game_script && size > args->GetDataLeft()) {
1077  buff = strecat(buff, "(too many parameters)", last);
1078  } else {
1079  StringParameters sub_args(*args, size);
1080  buff = GetStringWithArgs(buff, str, &sub_args, last, next_substr_case_index, game_script);
1081  }
1082  next_substr_case_index = 0;
1083  break;
1084  }
1085 
1086  case SCC_COMMA: // {COMMA}
1087  buff = FormatCommaNumber(buff, args->GetInt64(SCC_COMMA), last);
1088  break;
1089 
1090  case SCC_DECIMAL: {// {DECIMAL}
1091  int64 number = args->GetInt64(SCC_DECIMAL);
1092  int digits = args->GetInt32(SCC_DECIMAL);
1093  buff = FormatCommaNumber(buff, number, last, digits);
1094  break;
1095  }
1096 
1097  case SCC_NUM: // {NUM}
1098  buff = FormatNoCommaNumber(buff, args->GetInt64(SCC_NUM), last);
1099  break;
1100 
1101  case SCC_ZEROFILL_NUM: { // {ZEROFILL_NUM}
1102  int64 num = args->GetInt64();
1103  buff = FormatZerofillNumber(buff, num, args->GetInt64(), last);
1104  break;
1105  }
1106 
1107  case SCC_HEX: // {HEX}
1108  buff = FormatHexNumber(buff, (uint64)args->GetInt64(SCC_HEX), last);
1109  break;
1110 
1111  case SCC_BYTES: // {BYTES}
1112  buff = FormatBytes(buff, args->GetInt64(), last);
1113  break;
1114 
1115  case SCC_CARGO_TINY: { // {CARGO_TINY}
1116  /* Tiny description of cargotypes. Layout:
1117  * param 1: cargo type
1118  * param 2: cargo count */
1119  CargoID cargo = args->GetInt32(SCC_CARGO_TINY);
1120  if (cargo >= CargoSpec::GetArraySize()) break;
1121 
1122  StringID cargo_str = CargoSpec::Get(cargo)->units_volume;
1123  int64 amount = 0;
1124  switch (cargo_str) {
1125  case STR_TONS:
1127  break;
1128 
1129  case STR_LITERS:
1131  break;
1132 
1133  default: {
1134  amount = args->GetInt64();
1135  break;
1136  }
1137  }
1138 
1139  buff = FormatCommaNumber(buff, amount, last);
1140  break;
1141  }
1142 
1143  case SCC_CARGO_SHORT: { // {CARGO_SHORT}
1144  /* Short description of cargotypes. Layout:
1145  * param 1: cargo type
1146  * param 2: cargo count */
1147  CargoID cargo = args->GetInt32(SCC_CARGO_SHORT);
1148  if (cargo >= CargoSpec::GetArraySize()) break;
1149 
1150  StringID cargo_str = CargoSpec::Get(cargo)->units_volume;
1151  switch (cargo_str) {
1152  case STR_TONS: {
1154  int64 args_array[] = {_units_weight[_settings_game.locale.units_weight].c.ToDisplay(args->GetInt64())};
1155  StringParameters tmp_params(args_array);
1156  buff = FormatString(buff, GetStringPtr(_units_weight[_settings_game.locale.units_weight].l), &tmp_params, last);
1157  break;
1158  }
1159 
1160  case STR_LITERS: {
1162  int64 args_array[] = {_units_volume[_settings_game.locale.units_volume].c.ToDisplay(args->GetInt64())};
1163  StringParameters tmp_params(args_array);
1164  buff = FormatString(buff, GetStringPtr(_units_volume[_settings_game.locale.units_volume].l), &tmp_params, last);
1165  break;
1166  }
1167 
1168  default: {
1169  StringParameters tmp_params(*args, 1);
1170  buff = GetStringWithArgs(buff, cargo_str, &tmp_params, last);
1171  break;
1172  }
1173  }
1174  break;
1175  }
1176 
1177  case SCC_CARGO_LONG: { // {CARGO_LONG}
1178  /* First parameter is cargo type, second parameter is cargo count */
1179  CargoID cargo = args->GetInt32(SCC_CARGO_LONG);
1180  if (cargo != CT_INVALID && cargo >= CargoSpec::GetArraySize()) break;
1181 
1182  StringID cargo_str = (cargo == CT_INVALID) ? STR_QUANTITY_N_A : CargoSpec::Get(cargo)->quantifier;
1183  StringParameters tmp_args(*args, 1);
1184  buff = GetStringWithArgs(buff, cargo_str, &tmp_args, last);
1185  break;
1186  }
1187 
1188  case SCC_CARGO_LIST: { // {CARGO_LIST}
1189  CargoTypes cmask = args->GetInt64(SCC_CARGO_LIST);
1190  bool first = true;
1191 
1192  for (const auto &cs : _sorted_cargo_specs) {
1193  if (!HasBit(cmask, cs->Index())) continue;
1194 
1195  if (buff >= last - 2) break; // ',' and ' '
1196 
1197  if (first) {
1198  first = false;
1199  } else {
1200  /* Add a comma if this is not the first item */
1201  *buff++ = ',';
1202  *buff++ = ' ';
1203  }
1204 
1205  buff = GetStringWithArgs(buff, cs->name, args, last, next_substr_case_index, game_script);
1206  }
1207 
1208  /* If first is still true then no cargo is accepted */
1209  if (first) buff = GetStringWithArgs(buff, STR_JUST_NOTHING, args, last, next_substr_case_index, game_script);
1210 
1211  *buff = '\0';
1212  next_substr_case_index = 0;
1213 
1214  /* Make sure we detect any buffer overflow */
1215  assert(buff < last);
1216  break;
1217  }
1218 
1219  case SCC_CURRENCY_SHORT: // {CURRENCY_SHORT}
1220  buff = FormatGenericCurrency(buff, _currency, args->GetInt64(), true, last);
1221  break;
1222 
1223  case SCC_CURRENCY_LONG: // {CURRENCY_LONG}
1224  buff = FormatGenericCurrency(buff, _currency, args->GetInt64(SCC_CURRENCY_LONG), false, last);
1225  break;
1226 
1227  case SCC_DATE_TINY: // {DATE_TINY}
1228  buff = FormatTinyOrISODate(buff, args->GetInt32(SCC_DATE_TINY), STR_FORMAT_DATE_TINY, last);
1229  break;
1230 
1231  case SCC_DATE_SHORT: // {DATE_SHORT}
1232  buff = FormatMonthAndYear(buff, args->GetInt32(SCC_DATE_SHORT), last, next_substr_case_index);
1233  next_substr_case_index = 0;
1234  break;
1235 
1236  case SCC_DATE_LONG: // {DATE_LONG}
1237  buff = FormatYmdString(buff, args->GetInt32(SCC_DATE_LONG), last, next_substr_case_index);
1238  next_substr_case_index = 0;
1239  break;
1240 
1241  case SCC_DATE_ISO: // {DATE_ISO}
1242  buff = FormatTinyOrISODate(buff, args->GetInt32(), STR_FORMAT_DATE_ISO, last);
1243  break;
1244 
1245  case SCC_FORCE: { // {FORCE}
1247  int64 args_array[1] = {_units_force[_settings_game.locale.units_force].c.ToDisplay(args->GetInt64())};
1248  StringParameters tmp_params(args_array);
1249  buff = FormatString(buff, GetStringPtr(_units_force[_settings_game.locale.units_force].s), &tmp_params, last);
1250  break;
1251  }
1252 
1253  case SCC_HEIGHT: { // {HEIGHT}
1255  int64 args_array[] = {_units_height[_settings_game.locale.units_height].c.ToDisplay(args->GetInt64())};
1256  StringParameters tmp_params(args_array);
1257  buff = FormatString(buff, GetStringPtr(_units_height[_settings_game.locale.units_height].s), &tmp_params, last);
1258  break;
1259  }
1260 
1261  case SCC_POWER: { // {POWER}
1263  int64 args_array[1] = {_units_power[_settings_game.locale.units_power].c.ToDisplay(args->GetInt64())};
1264  StringParameters tmp_params(args_array);
1265  buff = FormatString(buff, GetStringPtr(_units_power[_settings_game.locale.units_power].s), &tmp_params, last);
1266  break;
1267  }
1268 
1269  case SCC_POWER_TO_WEIGHT: { // {POWER_TO_WEIGHT}
1271  assert(setting < lengthof(_units_power_to_weight));
1272 
1273  auto const &x = _units_power_to_weight[setting];
1274 
1275  int64 args_array[] = {x.c.ToDisplay(args->GetInt64()), x.decimal_places};
1276 
1277  StringParameters tmp_params(args_array);
1278  buff = FormatString(buff, GetStringPtr(x.s), &tmp_params, last);
1279  break;
1280  }
1281 
1282  case SCC_VELOCITY: { // {VELOCITY}
1284  unsigned int decimal_places = _units_velocity[_settings_game.locale.units_velocity].decimal_places;
1285  uint64 args_array[] = {ConvertKmhishSpeedToDisplaySpeed(args->GetInt64(SCC_VELOCITY)), decimal_places};
1286  StringParameters tmp_params(args_array, decimal_places ? 2 : 1, nullptr);
1287  buff = FormatString(buff, GetStringPtr(_units_velocity[_settings_game.locale.units_velocity].s), &tmp_params, last);
1288  break;
1289  }
1290 
1291  case SCC_VOLUME_SHORT: { // {VOLUME_SHORT}
1293  int64 args_array[1] = {_units_volume[_settings_game.locale.units_volume].c.ToDisplay(args->GetInt64())};
1294  StringParameters tmp_params(args_array);
1295  buff = FormatString(buff, GetStringPtr(_units_volume[_settings_game.locale.units_volume].s), &tmp_params, last);
1296  break;
1297  }
1298 
1299  case SCC_VOLUME_LONG: { // {VOLUME_LONG}
1301  int64 args_array[1] = {_units_volume[_settings_game.locale.units_volume].c.ToDisplay(args->GetInt64(SCC_VOLUME_LONG))};
1302  StringParameters tmp_params(args_array);
1303  buff = FormatString(buff, GetStringPtr(_units_volume[_settings_game.locale.units_volume].l), &tmp_params, last);
1304  break;
1305  }
1306 
1307  case SCC_WEIGHT_SHORT: { // {WEIGHT_SHORT}
1309  int64 args_array[1] = {_units_weight[_settings_game.locale.units_weight].c.ToDisplay(args->GetInt64())};
1310  StringParameters tmp_params(args_array);
1311  buff = FormatString(buff, GetStringPtr(_units_weight[_settings_game.locale.units_weight].s), &tmp_params, last);
1312  break;
1313  }
1314 
1315  case SCC_WEIGHT_LONG: { // {WEIGHT_LONG}
1317  int64 args_array[1] = {_units_weight[_settings_game.locale.units_weight].c.ToDisplay(args->GetInt64(SCC_WEIGHT_LONG))};
1318  StringParameters tmp_params(args_array);
1319  buff = FormatString(buff, GetStringPtr(_units_weight[_settings_game.locale.units_weight].l), &tmp_params, last);
1320  break;
1321  }
1322 
1323  case SCC_COMPANY_NAME: { // {COMPANY}
1324  const Company *c = Company::GetIfValid(args->GetInt32());
1325  if (c == nullptr) break;
1326 
1327  if (!c->name.empty()) {
1328  int64 args_array[] = {(int64)(size_t)c->name.c_str()};
1329  StringParameters tmp_params(args_array);
1330  buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last);
1331  } else {
1332  int64 args_array[] = {c->name_2};
1333  StringParameters tmp_params(args_array);
1334  buff = GetStringWithArgs(buff, c->name_1, &tmp_params, last);
1335  }
1336  break;
1337  }
1338 
1339  case SCC_COMPANY_NUM: { // {COMPANY_NUM}
1340  CompanyID company = (CompanyID)args->GetInt32();
1341 
1342  /* Nothing is added for AI or inactive companies */
1343  if (Company::IsValidHumanID(company)) {
1344  int64 args_array[] = {company + 1};
1345  StringParameters tmp_params(args_array);
1346  buff = GetStringWithArgs(buff, STR_FORMAT_COMPANY_NUM, &tmp_params, last);
1347  }
1348  break;
1349  }
1350 
1351  case SCC_DEPOT_NAME: { // {DEPOT}
1352  VehicleType vt = (VehicleType)args->GetInt32(SCC_DEPOT_NAME);
1353  if (vt == VEH_AIRCRAFT) {
1354  uint64 args_array[] = {(uint64)args->GetInt32()};
1355  WChar types_array[] = {SCC_STATION_NAME};
1356  StringParameters tmp_params(args_array, 1, types_array);
1357  buff = GetStringWithArgs(buff, STR_FORMAT_DEPOT_NAME_AIRCRAFT, &tmp_params, last);
1358  break;
1359  }
1360 
1361  const Depot *d = Depot::Get(args->GetInt32());
1362  if (!d->name.empty()) {
1363  int64 args_array[] = {(int64)(size_t)d->name.c_str()};
1364  StringParameters tmp_params(args_array);
1365  buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last);
1366  } else {
1367  int64 args_array[] = {d->town->index, d->town_cn + 1};
1368  StringParameters tmp_params(args_array);
1369  buff = GetStringWithArgs(buff, STR_FORMAT_DEPOT_NAME_TRAIN + 2 * vt + (d->town_cn == 0 ? 0 : 1), &tmp_params, last);
1370  }
1371  break;
1372  }
1373 
1374  case SCC_ENGINE_NAME: { // {ENGINE}
1375  int64 arg = args->GetInt64(SCC_ENGINE_NAME);
1376  const Engine *e = Engine::GetIfValid(static_cast<EngineID>(arg));
1377  if (e == nullptr) break;
1378 
1379  if (!e->name.empty() && e->IsEnabled()) {
1380  int64 args_array[] = {(int64)(size_t)e->name.c_str()};
1381  StringParameters tmp_params(args_array);
1382  buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last);
1383 
1384  break;
1385  }
1386 
1387  if (HasBit(e->info.callback_mask, CBM_VEHICLE_NAME)) {
1388  uint16 callback = GetVehicleCallback(CBID_VEHICLE_NAME, static_cast<uint32>(arg >> 32), 0, e->index, nullptr);
1389  /* Not calling ErrorUnknownCallbackResult due to being inside string processing. */
1390  if (callback != CALLBACK_FAILED && callback < 0x400) {
1391  const GRFFile *grffile = e->GetGRF();
1392  assert(grffile != nullptr);
1393 
1394  StartTextRefStackUsage(grffile, 6);
1395  uint64 tmp_dparam[6] = { 0 };
1396  WChar tmp_type[6] = { 0 };
1397  StringParameters tmp_params(tmp_dparam, 6, tmp_type);
1398  buff = GetStringWithArgs(buff, GetGRFStringID(grffile->grfid, 0xD000 + callback), &tmp_params, last);
1400 
1401  break;
1402  }
1403  }
1404 
1405  StringParameters tmp_params(nullptr, 0, nullptr);
1406  buff = GetStringWithArgs(buff, e->info.string_id, &tmp_params, last);
1407  break;
1408  }
1409 
1410  case SCC_GROUP_NAME: { // {GROUP}
1411  const Group *g = Group::GetIfValid(args->GetInt32());
1412  if (g == nullptr) break;
1413 
1414  if (!g->name.empty()) {
1415  int64 args_array[] = {(int64)(size_t)g->name.c_str()};
1416  StringParameters tmp_params(args_array);
1417  buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last);
1418  } else {
1419  int64 args_array[] = {g->index};
1420  StringParameters tmp_params(args_array);
1421 
1422  buff = GetStringWithArgs(buff, STR_FORMAT_GROUP_NAME, &tmp_params, last);
1423  }
1424  break;
1425  }
1426 
1427  case SCC_INDUSTRY_NAME: { // {INDUSTRY}
1428  const Industry *i = Industry::GetIfValid(args->GetInt32(SCC_INDUSTRY_NAME));
1429  if (i == nullptr) break;
1430 
1431  if (_scan_for_gender_data) {
1432  /* Gender is defined by the industry type.
1433  * STR_FORMAT_INDUSTRY_NAME may have the town first, so it would result in the gender of the town name */
1434  StringParameters tmp_params(nullptr, 0, nullptr);
1435  buff = FormatString(buff, GetStringPtr(GetIndustrySpec(i->type)->name), &tmp_params, last, next_substr_case_index);
1436  } else {
1437  /* First print the town name and the industry type name. */
1438  int64 args_array[2] = {i->town->index, GetIndustrySpec(i->type)->name};
1439  StringParameters tmp_params(args_array);
1440 
1441  buff = FormatString(buff, GetStringPtr(STR_FORMAT_INDUSTRY_NAME), &tmp_params, last, next_substr_case_index);
1442  }
1443  next_substr_case_index = 0;
1444  break;
1445  }
1446 
1447  case SCC_PRESIDENT_NAME: { // {PRESIDENT_NAME}
1448  const Company *c = Company::GetIfValid(args->GetInt32(SCC_PRESIDENT_NAME));
1449  if (c == nullptr) break;
1450 
1451  if (!c->president_name.empty()) {
1452  int64 args_array[] = {(int64)(size_t)c->president_name.c_str()};
1453  StringParameters tmp_params(args_array);
1454  buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last);
1455  } else {
1456  int64 args_array[] = {c->president_name_2};
1457  StringParameters tmp_params(args_array);
1458  buff = GetStringWithArgs(buff, c->president_name_1, &tmp_params, last);
1459  }
1460  break;
1461  }
1462 
1463  case SCC_STATION_NAME: { // {STATION}
1464  StationID sid = args->GetInt32(SCC_STATION_NAME);
1465  const Station *st = Station::GetIfValid(sid);
1466 
1467  if (st == nullptr) {
1468  /* The station doesn't exist anymore. The only place where we might
1469  * be "drawing" an invalid station is in the case of cargo that is
1470  * in transit. */
1471  StringParameters tmp_params(nullptr, 0, nullptr);
1472  buff = GetStringWithArgs(buff, STR_UNKNOWN_STATION, &tmp_params, last);
1473  break;
1474  }
1475 
1476  if (!st->name.empty()) {
1477  int64 args_array[] = {(int64)(size_t)st->name.c_str()};
1478  StringParameters tmp_params(args_array);
1479  buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last);
1480  } else {
1481  StringID str = st->string_id;
1482  if (st->indtype != IT_INVALID) {
1483  /* Special case where the industry provides the name for the station */
1484  const IndustrySpec *indsp = GetIndustrySpec(st->indtype);
1485 
1486  /* Industry GRFs can change which might remove the station name and
1487  * thus cause very strange things. Here we check for that before we
1488  * actually set the station name. */
1489  if (indsp->station_name != STR_NULL && indsp->station_name != STR_UNDEFINED) {
1490  str = indsp->station_name;
1491  }
1492  }
1493 
1494  uint64 args_array[] = {STR_TOWN_NAME, st->town->index, st->index};
1495  WChar types_array[] = {0, SCC_TOWN_NAME, SCC_NUM};
1496  StringParameters tmp_params(args_array, 3, types_array);
1497  buff = GetStringWithArgs(buff, str, &tmp_params, last);
1498  }
1499  break;
1500  }
1501 
1502  case SCC_TOWN_NAME: { // {TOWN}
1503  const Town *t = Town::GetIfValid(args->GetInt32(SCC_TOWN_NAME));
1504  if (t == nullptr) break;
1505 
1506  if (!t->name.empty()) {
1507  int64 args_array[] = {(int64)(size_t)t->name.c_str()};
1508  StringParameters tmp_params(args_array);
1509  buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last);
1510  } else {
1511  buff = GetTownName(buff, t, last);
1512  }
1513  break;
1514  }
1515 
1516  case SCC_WAYPOINT_NAME: { // {WAYPOINT}
1517  Waypoint *wp = Waypoint::GetIfValid(args->GetInt32(SCC_WAYPOINT_NAME));
1518  if (wp == nullptr) break;
1519 
1520  if (!wp->name.empty()) {
1521  int64 args_array[] = {(int64)(size_t)wp->name.c_str()};
1522  StringParameters tmp_params(args_array);
1523  buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last);
1524  } else {
1525  int64 args_array[] = {wp->town->index, wp->town_cn + 1};
1526  StringParameters tmp_params(args_array);
1527  StringID str = ((wp->string_id == STR_SV_STNAME_BUOY) ? STR_FORMAT_BUOY_NAME : STR_FORMAT_WAYPOINT_NAME);
1528  if (wp->town_cn != 0) str++;
1529  buff = GetStringWithArgs(buff, str, &tmp_params, last);
1530  }
1531  break;
1532  }
1533 
1534  case SCC_VEHICLE_NAME: { // {VEHICLE}
1535  const Vehicle *v = Vehicle::GetIfValid(args->GetInt32(SCC_VEHICLE_NAME));
1536  if (v == nullptr) break;
1537 
1538  if (!v->name.empty()) {
1539  int64 args_array[] = {(int64)(size_t)v->name.c_str()};
1540  StringParameters tmp_params(args_array);
1541  buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last);
1542  } else if (v->group_id != DEFAULT_GROUP) {
1543  /* The vehicle has no name, but is member of a group, so print group name */
1544  int64 args_array[] = {v->group_id, v->unitnumber};
1545  StringParameters tmp_params(args_array);
1546  buff = GetStringWithArgs(buff, STR_FORMAT_GROUP_VEHICLE_NAME, &tmp_params, last);
1547  } else {
1548  int64 args_array[] = {v->unitnumber};
1549  StringParameters tmp_params(args_array);
1550 
1551  StringID str;
1552  switch (v->type) {
1553  default: str = STR_INVALID_VEHICLE; break;
1554  case VEH_TRAIN: str = STR_SV_TRAIN_NAME; break;
1555  case VEH_ROAD: str = STR_SV_ROAD_VEHICLE_NAME; break;
1556  case VEH_SHIP: str = STR_SV_SHIP_NAME; break;
1557  case VEH_AIRCRAFT: str = STR_SV_AIRCRAFT_NAME; break;
1558  }
1559 
1560  buff = GetStringWithArgs(buff, str, &tmp_params, last);
1561  }
1562  break;
1563  }
1564 
1565  case SCC_SIGN_NAME: { // {SIGN}
1566  const Sign *si = Sign::GetIfValid(args->GetInt32());
1567  if (si == nullptr) break;
1568 
1569  if (!si->name.empty()) {
1570  int64 args_array[] = {(int64)(size_t)si->name.c_str()};
1571  StringParameters tmp_params(args_array);
1572  buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last);
1573  } else {
1574  StringParameters tmp_params(nullptr, 0, nullptr);
1575  buff = GetStringWithArgs(buff, STR_DEFAULT_SIGN_NAME, &tmp_params, last);
1576  }
1577  break;
1578  }
1579 
1580  case SCC_STATION_FEATURES: { // {STATIONFEATURES}
1581  buff = StationGetSpecialString(buff, args->GetInt32(SCC_STATION_FEATURES), last);
1582  break;
1583  }
1584 
1585  default:
1586  if (buff + Utf8CharLen(b) < last) buff += Utf8Encode(buff, b);
1587  break;
1588  }
1589  }
1590  *buff = '\0';
1591  return buff;
1592 }
1593 
1594 
1595 static char *StationGetSpecialString(char *buff, int x, const char *last)
1596 {
1597  if ((x & FACIL_TRAIN) && (buff + Utf8CharLen(SCC_TRAIN) < last)) buff += Utf8Encode(buff, SCC_TRAIN);
1598  if ((x & FACIL_TRUCK_STOP) && (buff + Utf8CharLen(SCC_LORRY) < last)) buff += Utf8Encode(buff, SCC_LORRY);
1599  if ((x & FACIL_BUS_STOP) && (buff + Utf8CharLen(SCC_BUS) < last)) buff += Utf8Encode(buff, SCC_BUS);
1600  if ((x & FACIL_DOCK) && (buff + Utf8CharLen(SCC_SHIP) < last)) buff += Utf8Encode(buff, SCC_SHIP);
1601  if ((x & FACIL_AIRPORT) && (buff + Utf8CharLen(SCC_PLANE) < last)) buff += Utf8Encode(buff, SCC_PLANE);
1602  *buff = '\0';
1603  return buff;
1604 }
1605 
1606 static char *GetSpecialTownNameString(char *buff, int ind, uint32 seed, const char *last)
1607 {
1608  return GenerateTownNameString(buff, last, ind, seed);
1609 }
1610 
1611 static const char * const _silly_company_names[] = {
1612  "Bloggs Brothers",
1613  "Tiny Transport Ltd.",
1614  "Express Travel",
1615  "Comfy-Coach & Co.",
1616  "Crush & Bump Ltd.",
1617  "Broken & Late Ltd.",
1618  "Sam Speedy & Son",
1619  "Supersonic Travel",
1620  "Mike's Motors",
1621  "Lightning International",
1622  "Pannik & Loozit Ltd.",
1623  "Inter-City Transport",
1624  "Getout & Pushit Ltd."
1625 };
1626 
1627 static const char * const _surname_list[] = {
1628  "Adams",
1629  "Allan",
1630  "Baker",
1631  "Bigwig",
1632  "Black",
1633  "Bloggs",
1634  "Brown",
1635  "Campbell",
1636  "Gordon",
1637  "Hamilton",
1638  "Hawthorn",
1639  "Higgins",
1640  "Green",
1641  "Gribble",
1642  "Jones",
1643  "McAlpine",
1644  "MacDonald",
1645  "McIntosh",
1646  "Muir",
1647  "Murphy",
1648  "Nelson",
1649  "O'Donnell",
1650  "Parker",
1651  "Phillips",
1652  "Pilkington",
1653  "Quigley",
1654  "Sharkey",
1655  "Thomson",
1656  "Watkins"
1657 };
1658 
1659 static const char * const _silly_surname_list[] = {
1660  "Grumpy",
1661  "Dozy",
1662  "Speedy",
1663  "Nosey",
1664  "Dribble",
1665  "Mushroom",
1666  "Cabbage",
1667  "Sniffle",
1668  "Fishy",
1669  "Swindle",
1670  "Sneaky",
1671  "Nutkins"
1672 };
1673 
1674 static const char _initial_name_letters[] = {
1675  'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
1676  'K', 'L', 'M', 'N', 'P', 'R', 'S', 'T', 'W',
1677 };
1678 
1679 static char *GenAndCoName(char *buff, uint32 arg, const char *last)
1680 {
1681  const char * const *base;
1682  uint num;
1683 
1684  if (_settings_game.game_creation.landscape == LT_TOYLAND) {
1685  base = _silly_surname_list;
1686  num = lengthof(_silly_surname_list);
1687  } else {
1688  base = _surname_list;
1689  num = lengthof(_surname_list);
1690  }
1691 
1692  buff = strecpy(buff, base[num * GB(arg, 16, 8) >> 8], last);
1693  buff = strecpy(buff, " & Co.", last);
1694 
1695  return buff;
1696 }
1697 
1698 static char *GenPresidentName(char *buff, uint32 x, const char *last)
1699 {
1700  char initial[] = "?. ";
1701  const char * const *base;
1702  uint num;
1703  uint i;
1704 
1705  initial[0] = _initial_name_letters[sizeof(_initial_name_letters) * GB(x, 0, 8) >> 8];
1706  buff = strecpy(buff, initial, last);
1707 
1708  i = (sizeof(_initial_name_letters) + 35) * GB(x, 8, 8) >> 8;
1709  if (i < sizeof(_initial_name_letters)) {
1710  initial[0] = _initial_name_letters[i];
1711  buff = strecpy(buff, initial, last);
1712  }
1713 
1714  if (_settings_game.game_creation.landscape == LT_TOYLAND) {
1715  base = _silly_surname_list;
1716  num = lengthof(_silly_surname_list);
1717  } else {
1718  base = _surname_list;
1719  num = lengthof(_surname_list);
1720  }
1721 
1722  buff = strecpy(buff, base[num * GB(x, 16, 8) >> 8], last);
1723 
1724  return buff;
1725 }
1726 
1727 static char *GetSpecialNameString(char *buff, int ind, StringParameters *args, const char *last)
1728 {
1729  switch (ind) {
1730  case 1: // not used
1731  return strecpy(buff, _silly_company_names[std::min<uint>(args->GetInt32() & 0xFFFF, lengthof(_silly_company_names) - 1)], last);
1732 
1733  case 2: // used for Foobar & Co company names
1734  return GenAndCoName(buff, args->GetInt32(), last);
1735 
1736  case 3: // President name
1737  return GenPresidentName(buff, args->GetInt32(), last);
1738  }
1739 
1740  /* town name? */
1741  if (IsInsideMM(ind - 6, 0, SPECSTR_TOWNNAME_LAST - SPECSTR_TOWNNAME_START + 1)) {
1742  buff = GetSpecialTownNameString(buff, ind - 6, args->GetInt32(), last);
1743  return strecpy(buff, " Transport", last);
1744  }
1745 
1746  NOT_REACHED();
1747 }
1748 
1754 {
1755  return this->ident == TO_LE32(LanguagePackHeader::IDENT) &&
1756  this->version == TO_LE32(LANGUAGE_PACK_VERSION) &&
1757  this->plural_form < LANGUAGE_MAX_PLURAL &&
1758  this->text_dir <= 1 &&
1759  this->newgrflangid < MAX_LANG &&
1760  this->num_genders < MAX_NUM_GENDERS &&
1761  this->num_cases < MAX_NUM_CASES &&
1762  StrValid(this->name, lastof(this->name)) &&
1763  StrValid(this->own_name, lastof(this->own_name)) &&
1764  StrValid(this->isocode, lastof(this->isocode)) &&
1768 }
1769 
1774 {
1775  /* "Less than 25% missing" is "sufficiently finished". */
1776  return 4 * this->missing < LANGUAGE_TOTAL_STRINGS;
1777 }
1778 
1785 {
1786  /* Current language pack */
1787  size_t len = 0;
1788  std::unique_ptr<LanguagePack, LanguagePackDeleter> lang_pack(reinterpret_cast<LanguagePack *>(ReadFileToMem(lang->file, len, 1U << 20).release()));
1789  if (!lang_pack) return false;
1790 
1791  /* End of read data (+ terminating zero added in ReadFileToMem()) */
1792  const char *end = (char *)lang_pack.get() + len + 1;
1793 
1794  /* We need at least one byte of lang_pack->data */
1795  if (end <= lang_pack->data || !lang_pack->IsValid()) {
1796  return false;
1797  }
1798 
1799 #if TTD_ENDIAN == TTD_BIG_ENDIAN
1800  for (uint i = 0; i < TEXT_TAB_END; i++) {
1801  lang_pack->offsets[i] = ReadLE16Aligned(&lang_pack->offsets[i]);
1802  }
1803 #endif /* TTD_ENDIAN == TTD_BIG_ENDIAN */
1804 
1805  std::array<uint, TEXT_TAB_END> tab_start, tab_num;
1806 
1807  uint count = 0;
1808  for (uint i = 0; i < TEXT_TAB_END; i++) {
1809  uint16 num = lang_pack->offsets[i];
1810  if (num > TAB_SIZE) return false;
1811 
1812  tab_start[i] = count;
1813  tab_num[i] = num;
1814  count += num;
1815  }
1816 
1817  /* Allocate offsets */
1818  std::vector<char *> offs(count);
1819 
1820  /* Fill offsets */
1821  char *s = lang_pack->data;
1822  len = (byte)*s++;
1823  for (uint i = 0; i < count; i++) {
1824  if (s + len >= end) return false;
1825 
1826  if (len >= 0xC0) {
1827  len = ((len & 0x3F) << 8) + (byte)*s++;
1828  if (s + len >= end) return false;
1829  }
1830  offs[i] = s;
1831  s += len;
1832  len = (byte)*s;
1833  *s++ = '\0'; // zero terminate the string
1834  }
1835 
1836  _langpack.langpack = std::move(lang_pack);
1837  _langpack.offsets = std::move(offs);
1838  _langpack.langtab_num = tab_num;
1839  _langpack.langtab_start = tab_start;
1840 
1841  _current_language = lang;
1843  const char *c_file = strrchr(_current_language->file, PATHSEPCHAR) + 1;
1844  _config_language_file = c_file;
1846 
1847 #ifdef _WIN32
1848  extern void Win32SetCurrentLocaleName(const char *iso_code);
1849  Win32SetCurrentLocaleName(_current_language->isocode);
1850 #endif
1851 
1852 #ifdef WITH_COCOA
1853  extern void MacOSSetCurrentLocaleName(const char *iso_code);
1855 #endif
1856 
1857 #ifdef WITH_ICU_I18N
1858  /* Create a collator instance for our current locale. */
1859  UErrorCode status = U_ZERO_ERROR;
1860  _current_collator.reset(icu::Collator::createInstance(icu::Locale(_current_language->isocode), status));
1861  /* Sort number substrings by their numerical value. */
1862  if (_current_collator) _current_collator->setAttribute(UCOL_NUMERIC_COLLATION, UCOL_ON, status);
1863  /* Avoid using the collator if it is not correctly set. */
1864  if (U_FAILURE(status)) {
1865  _current_collator.reset();
1866  }
1867 #endif /* WITH_ICU_I18N */
1868 
1869  /* Some lists need to be sorted again after a language change. */
1875  InvalidateWindowClassesData(WC_BUILD_VEHICLE); // Build vehicle window.
1876  InvalidateWindowClassesData(WC_TRAINS_LIST); // Train group window.
1877  InvalidateWindowClassesData(WC_ROADVEH_LIST); // Road vehicle group window.
1878  InvalidateWindowClassesData(WC_SHIPS_LIST); // Ship group window.
1879  InvalidateWindowClassesData(WC_AIRCRAFT_LIST); // Aircraft group window.
1880  InvalidateWindowClassesData(WC_INDUSTRY_DIRECTORY); // Industry directory window.
1881  InvalidateWindowClassesData(WC_STATION_LIST); // Station list window.
1882 
1883  return true;
1884 }
1885 
1886 /* Win32 implementation in win32.cpp.
1887  * OS X implementation in os/macosx/macos.mm. */
1888 #if !(defined(_WIN32) || defined(__APPLE__))
1889 
1897 const char *GetCurrentLocale(const char *param)
1898 {
1899  const char *env;
1900 
1901  env = std::getenv("LANGUAGE");
1902  if (env != nullptr) return env;
1903 
1904  env = std::getenv("LC_ALL");
1905  if (env != nullptr) return env;
1906 
1907  if (param != nullptr) {
1908  env = std::getenv(param);
1909  if (env != nullptr) return env;
1910  }
1911 
1912  return std::getenv("LANG");
1913 }
1914 #else
1915 const char *GetCurrentLocale(const char *param);
1916 #endif /* !(defined(_WIN32) || defined(__APPLE__)) */
1917 
1918 bool StringIDSorter(const StringID &a, const StringID &b)
1919 {
1920  char stra[512];
1921  char strb[512];
1922  GetString(stra, a, lastof(stra));
1923  GetString(strb, b, lastof(strb));
1924 
1925  return strnatcmp(stra, strb) < 0;
1926 }
1927 
1933 const LanguageMetadata *GetLanguage(byte newgrflangid)
1934 {
1935  for (const LanguageMetadata &lang : _languages) {
1936  if (newgrflangid == lang.newgrflangid) return &lang;
1937  }
1938 
1939  return nullptr;
1940 }
1941 
1948 static bool GetLanguageFileHeader(const char *file, LanguagePackHeader *hdr)
1949 {
1950  FILE *f = fopen(file, "rb");
1951  if (f == nullptr) return false;
1952 
1953  size_t read = fread(hdr, sizeof(*hdr), 1, f);
1954  fclose(f);
1955 
1956  bool ret = read == 1 && hdr->IsValid();
1957 
1958  /* Convert endianness for the windows language ID */
1959  if (ret) {
1960  hdr->missing = FROM_LE16(hdr->missing);
1961  hdr->winlangid = FROM_LE16(hdr->winlangid);
1962  }
1963  return ret;
1964 }
1965 
1970 static void GetLanguageList(const char *path)
1971 {
1972  DIR *dir = ttd_opendir(path);
1973  if (dir != nullptr) {
1974  struct dirent *dirent;
1975  while ((dirent = readdir(dir)) != nullptr) {
1976  std::string d_name = FS2OTTD(dirent->d_name);
1977  const char *extension = strrchr(d_name.c_str(), '.');
1978 
1979  /* Not a language file */
1980  if (extension == nullptr || strcmp(extension, ".lng") != 0) continue;
1981 
1982  LanguageMetadata lmd;
1983  seprintf(lmd.file, lastof(lmd.file), "%s%s", path, d_name.c_str());
1984 
1985  /* Check whether the file is of the correct version */
1986  if (!GetLanguageFileHeader(lmd.file, &lmd)) {
1987  Debug(misc, 3, "{} is not a valid language file", lmd.file);
1988  } else if (GetLanguage(lmd.newgrflangid) != nullptr) {
1989  Debug(misc, 3, "{}'s language ID is already known", lmd.file);
1990  } else {
1991  _languages.push_back(lmd);
1992  }
1993  }
1994  closedir(dir);
1995  }
1996 }
1997 
2003 {
2004  for (Searchpath sp : _valid_searchpaths) {
2005  std::string path = FioGetDirectory(sp, LANG_DIR);
2006  GetLanguageList(path.c_str());
2007  }
2008  if (_languages.size() == 0) usererror("No available language packs (invalid versions?)");
2009 
2010  /* Acquire the locale of the current system */
2011  const char *lang = GetCurrentLocale("LC_MESSAGES");
2012  if (lang == nullptr) lang = "en_GB";
2013 
2014  const LanguageMetadata *chosen_language = nullptr;
2015  const LanguageMetadata *language_fallback = nullptr;
2016  const LanguageMetadata *en_GB_fallback = _languages.data();
2017 
2018  /* Find a proper language. */
2019  for (const LanguageMetadata &lng : _languages) {
2020  /* We are trying to find a default language. The priority is by
2021  * configuration file, local environment and last, if nothing found,
2022  * English. */
2023  const char *lang_file = strrchr(lng.file, PATHSEPCHAR) + 1;
2024  if (_config_language_file == lang_file) {
2025  chosen_language = &lng;
2026  break;
2027  }
2028 
2029  if (strcmp (lng.isocode, "en_GB") == 0) en_GB_fallback = &lng;
2030 
2031  /* Only auto-pick finished translations */
2032  if (!lng.IsReasonablyFinished()) continue;
2033 
2034  if (strncmp(lng.isocode, lang, 5) == 0) chosen_language = &lng;
2035  if (strncmp(lng.isocode, lang, 2) == 0) language_fallback = &lng;
2036  }
2037 
2038  /* We haven't found the language in the config nor the one in the locale.
2039  * Now we set it to one of the fallback languages */
2040  if (chosen_language == nullptr) {
2041  chosen_language = (language_fallback != nullptr) ? language_fallback : en_GB_fallback;
2042  }
2043 
2044  if (!ReadLanguagePack(chosen_language)) usererror("Can't read language pack '%s'", chosen_language->file);
2045 }
2046 
2052 {
2053  return _langpack.langpack->isocode;
2054 }
2055 
2061 {
2062  InitFontCache(this->Monospace());
2063  const Sprite *question_mark[FS_END];
2064 
2065  for (FontSize size = this->Monospace() ? FS_MONO : FS_BEGIN; size < (this->Monospace() ? FS_END : FS_MONO); size++) {
2066  question_mark[size] = GetGlyph(size, '?');
2067  }
2068 
2069  this->Reset();
2070  for (const char *text = this->NextString(); text != nullptr; text = this->NextString()) {
2071  FontSize size = this->DefaultSize();
2072  for (WChar c = Utf8Consume(&text); c != '\0'; c = Utf8Consume(&text)) {
2073  if (c >= SCC_FIRST_FONT && c <= SCC_LAST_FONT) {
2074  size = (FontSize)(c - SCC_FIRST_FONT);
2075  } else if (!IsInsideMM(c, SCC_SPRITE_START, SCC_SPRITE_END) && IsPrintable(c) && !IsTextDirectionChar(c) && c != '?' && GetGlyph(size, c) == question_mark[size]) {
2076  /* The character is printable, but not in the normal font. This is the case we were testing for. */
2077  std::string size_name;
2078 
2079  switch (size) {
2080  case 0: size_name = "medium"; break;
2081  case 1: size_name = "small"; break;
2082  case 2: size_name = "large"; break;
2083  case 3: size_name = "mono"; break;
2084  default: NOT_REACHED();
2085  }
2086 
2087  Debug(fontcache, 0, "Font is missing glyphs to display char 0x{:X} in {} font size", (int)c, size_name);
2088  return true;
2089  }
2090  }
2091  }
2092  return false;
2093 }
2094 
2097  uint i;
2098  uint j;
2099 
2100  void Reset() override
2101  {
2102  this->i = 0;
2103  this->j = 0;
2104  }
2105 
2107  {
2108  return FS_NORMAL;
2109  }
2110 
2111  const char *NextString() override
2112  {
2113  if (this->i >= TEXT_TAB_END) return nullptr;
2114 
2115  const char *ret = _langpack.offsets[_langpack.langtab_start[this->i] + this->j];
2116 
2117  this->j++;
2118  while (this->i < TEXT_TAB_END && this->j >= _langpack.langtab_num[this->i]) {
2119  this->i++;
2120  this->j = 0;
2121  }
2122 
2123  return ret;
2124  }
2125 
2126  bool Monospace() override
2127  {
2128  return false;
2129  }
2130 
2131  void SetFontNames(FontCacheSettings *settings, const char *font_name, const void *os_data) override
2132  {
2133 #if defined(WITH_FREETYPE) || defined(_WIN32) || defined(WITH_COCOA)
2134  settings->small.font = font_name;
2135  settings->medium.font = font_name;
2136  settings->large.font = font_name;
2137 
2138  settings->small.os_handle = os_data;
2139  settings->medium.os_handle = os_data;
2140  settings->large.os_handle = os_data;
2141 #endif
2142  }
2143 };
2144 
2158 void CheckForMissingGlyphs(bool base_font, MissingGlyphSearcher *searcher)
2159 {
2160  static LanguagePackGlyphSearcher pack_searcher;
2161  if (searcher == nullptr) searcher = &pack_searcher;
2162  bool bad_font = !base_font || searcher->FindMissingGlyphs();
2163 #if defined(WITH_FREETYPE) || defined(_WIN32) || defined(WITH_COCOA)
2164  if (bad_font) {
2165  /* We found an unprintable character... lets try whether we can find
2166  * a fallback font that can print the characters in the current language. */
2167  bool any_font_configured = !_fcsettings.medium.font.empty();
2168  FontCacheSettings backup = _fcsettings;
2169 
2170  _fcsettings.mono.os_handle = nullptr;
2171  _fcsettings.medium.os_handle = nullptr;
2172 
2173  bad_font = !SetFallbackFont(&_fcsettings, _langpack.langpack->isocode, _langpack.langpack->winlangid, searcher);
2174 
2175  _fcsettings = backup;
2176 
2177  if (!bad_font && any_font_configured) {
2178  /* If the user configured a bad font, and we found a better one,
2179  * show that we loaded the better font instead of the configured one.
2180  * The colour 'character' might change in the
2181  * future, so for safety we just Utf8 Encode it into the string,
2182  * which takes exactly three characters, so it replaces the "XXX"
2183  * with the colour marker. */
2184  static char *err_str = stredup("XXXThe current font is missing some of the characters used in the texts for this language. Using system fallback font instead.");
2185  Utf8Encode(err_str, SCC_YELLOW);
2186  SetDParamStr(0, err_str);
2187  ShowErrorMessage(STR_JUST_RAW_STRING, INVALID_STRING_ID, WL_WARNING);
2188  }
2189 
2190  if (bad_font && base_font) {
2191  /* Our fallback font does miss characters too, so keep the
2192  * user chosen font as that is more likely to be any good than
2193  * the wild guess we made */
2194  InitFontCache(searcher->Monospace());
2195  }
2196  }
2197 #endif
2198 
2199  if (bad_font) {
2200  /* All attempts have failed. Display an error. As we do not want the string to be translated by
2201  * the translators, we 'force' it into the binary and 'load' it via a BindCString. To do this
2202  * properly we have to set the colour of the string, otherwise we end up with a lot of artifacts.
2203  * The colour 'character' might change in the future, so for safety we just Utf8 Encode it into
2204  * the string, which takes exactly three characters, so it replaces the "XXX" with the colour marker. */
2205  static char *err_str = stredup("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.");
2206  Utf8Encode(err_str, SCC_YELLOW);
2207  SetDParamStr(0, err_str);
2208  ShowErrorMessage(STR_JUST_RAW_STRING, INVALID_STRING_ID, WL_WARNING);
2209 
2210  /* Reset the font width */
2211  LoadStringWidthTable(searcher->Monospace());
2212  return;
2213  }
2214 
2215  /* Update the font with cache */
2216  LoadStringWidthTable(searcher->Monospace());
2217 
2218 #if !defined(WITH_ICU_LX) && !defined(WITH_UNISCRIBE) && !defined(WITH_COCOA)
2219  /*
2220  * For right-to-left languages we need the ICU library. If
2221  * we do not have support for that library we warn the user
2222  * about it with a message. As we do not want the string to
2223  * be translated by the translators, we 'force' it into the
2224  * binary and 'load' it via a BindCString. To do this
2225  * properly we have to set the colour of the string,
2226  * otherwise we end up with a lot of artifacts. The colour
2227  * 'character' might change in the future, so for safety
2228  * we just Utf8 Encode it into the string, which takes
2229  * exactly three characters, so it replaces the "XXX" with
2230  * the colour marker.
2231  */
2232  if (_current_text_dir != TD_LTR) {
2233  static char *err_str = stredup("XXXThis version of OpenTTD does not support right-to-left languages. Recompile with icu enabled.");
2234  Utf8Encode(err_str, SCC_YELLOW);
2235  SetDParamStr(0, err_str);
2236  ShowErrorMessage(STR_JUST_RAW_STRING, INVALID_STRING_ID, WL_ERROR);
2237  }
2238 #endif /* !WITH_ICU_LX */
2239 }
VEH_AIRCRAFT
@ VEH_AIRCRAFT
Aircraft vehicle type.
Definition: vehicle_type.h:27
LanguagePackHeader::IsReasonablyFinished
bool IsReasonablyFinished() const
Check whether a translation is sufficiently finished to offer it to the public.
Definition: strings.cpp:1773
LoadStringWidthTable
void LoadStringWidthTable(bool monospace)
Initialize _stringwidth_table cache.
Definition: gfx.cpp:1446
LanguagePackHeader::missing
uint16 missing
number of missing strings.
Definition: language.h:40
LanguagePackHeader::text_dir
byte text_dir
default direction of the text
Definition: language.h:42
MissingGlyphSearcher::FindMissingGlyphs
bool FindMissingGlyphs()
Check whether there are glyphs missing in the current language.
Definition: strings.cpp:2060
YearMonthDay::day
Day day
Day (1..31)
Definition: date_type.h:107
MAX_NUM_GENDERS
static const uint8 MAX_NUM_GENDERS
Maximum number of supported genders.
Definition: language.h:20
WC_ROADVEH_LIST
@ WC_ROADVEH_LIST
Road vehicle list; Window numbers:
Definition: window_type.h:307
IsInsideMM
static constexpr bool IsInsideMM(const T x, const size_t min, const size_t max) noexcept
Checks if a value is in an interval.
Definition: math_func.hpp:230
GetStringTab
static StringTab GetStringTab(StringID str)
Extract the StringTab from a StringID.
Definition: strings_func.h:23
LanguagePackHeader::version
uint32 version
32-bits of auto generated version info which is basically a hash of strings.h
Definition: language.h:28
MissingGlyphSearcher::DefaultSize
virtual FontSize DefaultSize()=0
Get the default (font) size of the string.
LanguagePack
Definition: strings.cpp:175
LanguageMetadata
Make sure the size is right.
Definition: language.h:93
Pool::PoolItem<&_depot_pool >::Get
static Titem * Get(size_t index)
Returns Titem with given index.
Definition: pool_type.hpp:337
SCC_NEWGRF_FIRST
@ SCC_NEWGRF_FIRST
The next variables are part of a NewGRF subsystem for creating text strings.
Definition: control_codes.h:124
_units_volume
static const UnitsLong _units_volume[]
Unit conversions for volume.
Definition: strings.cpp:740
WChar
char32_t WChar
Type for wide characters, i.e.
Definition: string_type.h:36
GenerateTownNameString
char * GenerateTownNameString(char *buf, const char *last, size_t lang, uint32 seed)
Generates town name from given seed.
Definition: townname.cpp:1052
CopyOutDParam
void CopyOutDParam(uint64 *dst, int offs, int num)
Copy num string parameters from the global string parameter array to the dst array.
Definition: strings.cpp:140
GetCurrentLanguageIsoCode
const char * GetCurrentLanguageIsoCode()
Get the ISO language code of the currently loaded language.
Definition: strings.cpp:2051
usererror
void CDECL usererror(const char *s,...)
Error handling for fatal user errors.
Definition: openttd.cpp:105
SCC_NEWGRF_STRINL
@ SCC_NEWGRF_STRINL
Inline another string at the current position, StringID is encoded in the string.
Definition: control_codes.h:157
GB
static uint GB(const T x, const uint8 s, const uint8 n)
Fetch n bits from x, started at bit s.
Definition: bitmath_func.hpp:32
MissingGlyphSearcher
A searcher for missing glyphs.
Definition: strings_func.h:243
ReconsiderGameScriptLanguage
void ReconsiderGameScriptLanguage()
Reconsider the game script language, so we use the right one.
Definition: game_text.cpp:345
LanguagePackHeader::plural_form
byte plural_form
plural form index
Definition: language.h:41
TEXT_TAB_END
@ TEXT_TAB_END
End of language files.
Definition: strings_type.h:38
endian_func.hpp
Pool::PoolItem<&_company_pool >::GetIfValid
static Titem * GetIfValid(size_t index)
Returns Titem with given index.
Definition: pool_type.hpp:348
MissingGlyphSearcher::NextString
virtual const char * NextString()=0
Get the next string to search through.
_languages
LanguageList _languages
The actual list of language meta data.
Definition: strings.cpp:46
WL_WARNING
@ WL_WARNING
Other information.
Definition: error.h:23
TEXT_TAB_NEWGRF_START
@ TEXT_TAB_NEWGRF_START
Start of NewGRF supplied strings.
Definition: strings_type.h:40
smallmap_gui.h
GameCreationSettings::landscape
byte landscape
the landscape we're currently in
Definition: settings_type.h:328
_sorted_cargo_specs
std::vector< const CargoSpec * > _sorted_cargo_specs
Cargo specifications sorted alphabetically by name.
Definition: cargotype.cpp:153
MakeStringID
static StringID MakeStringID(StringTab tab, uint index)
Create a StringID.
Definition: strings_func.h:47
company_base.h
LoadedLanguagePack::langtab_num
std::array< uint, TEXT_TAB_END > langtab_num
Offset into langpack offs.
Definition: strings.cpp:192
BaseStation::town
Town * town
The town this station is associated with.
Definition: base_station_base.h:61
FS_BEGIN
@ FS_BEGIN
First font.
Definition: gfx_type.h:209
FACIL_TRUCK_STOP
@ FACIL_TRUCK_STOP
Station with truck stops.
Definition: station_type.h:54
TD_LTR
@ TD_LTR
Text is written left-to-right by default.
Definition: strings_type.h:23
Station
Station data structure.
Definition: station_base.h:454
currency.h
CurrencySpec::symbol_pos
byte symbol_pos
The currency symbol is represented by two possible values, prefix and suffix Usage of one or the othe...
Definition: currency.h:87
BaseConsist::name
std::string name
Name of vehicle.
Definition: base_consist.h:19
Utf8CharLen
static int8 Utf8CharLen(WChar c)
Return the length of a UTF-8 encoded character.
Definition: string_func.h:116
Waypoint::town_cn
uint16 town_cn
The N-1th waypoint for this town (consecutive number)
Definition: waypoint_base.h:17
Pool::PoolItem::index
Tindex index
Index of this pool item.
Definition: pool_type.hpp:235
CargoSpec::Get
static CargoSpec * Get(size_t index)
Retrieve cargo details for the given cargo ID.
Definition: cargotype.h:118
StringTab
StringTab
StringTabs to group StringIDs.
Definition: strings_type.h:28
Vehicle::group_id
GroupID group_id
Index of group Pool array.
Definition: vehicle_base.h:341
Searchpath
Searchpath
Types of searchpaths OpenTTD might use.
Definition: fileio_type.h:131
SortIndustryTypes
void SortIndustryTypes()
Initialize the list of sorted industry types.
Definition: industry_gui.cpp:209
HasBit
static bool HasBit(const T x, const uint8 y)
Checks if a bit in a value is set.
Definition: bitmath_func.hpp:103
MissingGlyphSearcher::Reset
virtual void Reset()=0
Reset the search, i.e.
_global_string_params_type
static WChar _global_string_params_type[20]
Type of parameters stored in #_global_string_params.
Definition: strings.cpp:56
LocaleSettings::units_volume
byte units_volume
unit system for volume
Definition: settings_type.h:240
Waypoint
Representation of a waypoint.
Definition: waypoint_base.h:16
Utf8Encode
size_t Utf8Encode(T buf, WChar c)
Encode a unicode character and place it in the buffer.
Definition: string.cpp:635
LanguageList
std::vector< LanguageMetadata > LanguageList
Type for the list of language meta data.
Definition: language.h:98
vehicle_base.h
CompanyProperties::name
std::string name
Name of the company if the user changed it.
Definition: company_base.h:59
fileio_func.h
StartTextRefStackUsage
void StartTextRefStackUsage(const GRFFile *grffile, byte numEntries, const uint32 *values)
Start using the TTDP compatible string code parsing.
Definition: newgrf_text.cpp:821
Company::IsValidHumanID
static bool IsValidHumanID(size_t index)
Is this company a valid company, not controlled by a NoAI program?
Definition: company_base.h:149
UnitConversion::multiplier
int multiplier
Amount to multiply upon conversion.
Definition: strings.cpp:663
UnitsLong::c
UnitConversion c
Conversion.
Definition: strings.cpp:699
LanguagePackHeader::num_cases
uint8 num_cases
the number of cases of this language
Definition: language.h:54
town.h
UnitConversion::shift
int shift
Amount to shift upon conversion.
Definition: strings.cpp:664
LanguagePackGlyphSearcher::NextString
const char * NextString() override
Get the next string to search through.
Definition: strings.cpp:2111
IndustrySpec::station_name
StringID station_name
Default name for nearby station.
Definition: industrytype.h:132
StopTextRefStackUsage
void StopTextRefStackUsage()
Stop using the TTDP compatible string code parsing.
Definition: newgrf_text.cpp:838
Engine
Definition: engine_base.h:36
VEH_ROAD
@ VEH_ROAD
Road vehicle type.
Definition: vehicle_type.h:25
Vehicle
Vehicle data structure.
Definition: vehicle_base.h:224
LoadedLanguagePack
Definition: strings.cpp:187
Industry
Defines the internal data of a functional industry.
Definition: industry.h:66
CargoSpec::GetArraySize
static size_t GetArraySize()
Total number of cargospecs, both valid and invalid.
Definition: cargotype.h:108
ReadLanguagePack
bool ReadLanguagePack(const LanguageMetadata *lang)
Read a particular language.
Definition: strings.cpp:1784
Owner
Owner
Enum for all companies/owners.
Definition: company_type.h:18
UnitsLong
Information about a specific unit system with a long variant.
Definition: strings.cpp:698
LanguagePackGlyphSearcher::SetFontNames
void SetFontNames(FontCacheSettings *settings, const char *font_name, const void *os_data) override
Set the right font names.
Definition: strings.cpp:2131
GetVehicleCallback
uint16 GetVehicleCallback(CallbackID callback, uint32 param1, uint32 param2, EngineID engine, const Vehicle *v)
Evaluate a newgrf callback for vehicles.
Definition: newgrf_engine.cpp:1162
MemCpyT
static void MemCpyT(T *destination, const T *source, size_t num=1)
Type-safe version of memcpy().
Definition: mem_func.hpp:23
GetLanguageList
static void GetLanguageList(const char *path)
Gets a list of languages from the given directory.
Definition: strings.cpp:1970
StringParameters::GetTypeAtOffset
WChar GetTypeAtOffset(uint offset) const
Get the type of a specific element.
Definition: strings_func.h:151
SetDParam
static void SetDParam(uint n, uint64 v)
Set a string parameter v at index n in the global string parameter array.
Definition: strings_func.h:196
LocaleSettings::digit_decimal_separator
std::string digit_decimal_separator
decimal separator
Definition: settings_type.h:245
_units_height
static const Units _units_height[]
Unit conversions for height.
Definition: strings.cpp:754
NBSP
#define NBSP
A non-breaking space.
Definition: string_type.h:18
LanguagePackGlyphSearcher::i
uint i
Iterator for the primary language tables.
Definition: strings.cpp:2097
CompanyProperties::name_2
uint32 name_2
Parameter of name_1.
Definition: company_base.h:57
RestoreTextRefStackBackup
void RestoreTextRefStackBackup(struct TextRefStack *backup)
Restore a copy of the text stack to the used stack.
Definition: newgrf_text.cpp:797
ShowErrorMessage
void ShowErrorMessage(StringID summary_msg, StringID detailed_msg, WarningLevel wl, int x=0, int y=0, const GRFFile *textref_stack_grffile=nullptr, uint textref_stack_size=0, const uint32 *textref_stack=nullptr)
Display an error message in a window.
Definition: error_gui.cpp:377
BaseStation::string_id
StringID string_id
Default name (town area) of station.
Definition: base_station_base.h:58
GameSettings::game_creation
GameCreationSettings game_creation
settings used during the creation of a game (map)
Definition: settings_type.h:587
LanguagePackHeader::IDENT
static const uint32 IDENT
Identifier for OpenTTD language files, big endian for "LANG".
Definition: language.h:25
control_codes.h
TAB_SIZE
static const uint TAB_SIZE
Number of strings per StringTab.
Definition: strings_type.h:46
StringParameters::GetInt64
int64 GetInt64(WChar type=0)
Read an int64 from the argument array.
Definition: strings.cpp:71
CBM_VEHICLE_NAME
@ CBM_VEHICLE_NAME
Engine name.
Definition: newgrf_callbacks.h:300
GetStringWithArgs
char * GetStringWithArgs(char *buffr, StringID string, StringParameters *args, const char *last, uint case_index, bool game_script)
Get a parsed string with most special stringcodes replaced by the string parameters.
Definition: strings.cpp:222
Engine::GetGRF
const GRFFile * GetGRF() const
Retrieve the NewGRF the engine is tied to.
Definition: engine_base.h:154
Units
Information about a specific unit system.
Definition: strings.cpp:691
townname_func.h
Group
Group data.
Definition: group.h:74
UnitConversion::FromDisplay
int64 FromDisplay(int64 input, bool round=true, int64 divider=1) const
Convert the displayed value back into a value of OpenTTD's internal unit.
Definition: strings.cpp:684
ConvertDisplaySpeedToKmhishSpeed
uint ConvertDisplaySpeedToKmhishSpeed(uint speed)
Convert the given display speed to the km/h-ish speed.
Definition: strings.cpp:798
StrValid
bool StrValid(const char *str, const char *last)
Checks whether the given string is valid, i.e.
Definition: string.cpp:318
FACIL_BUS_STOP
@ FACIL_BUS_STOP
Station with bus stops.
Definition: station_type.h:55
EngineID
uint16 EngineID
Unique identification number of an engine.
Definition: engine_type.h:21
depot_base.h
SCC_NEWGRF_PRINT_WORD_STRING_ID
@ SCC_NEWGRF_PRINT_WORD_STRING_ID
81: Read 2 bytes from the stack as String ID
Definition: control_codes.h:130
FontCacheSettings
Settings for the four different fonts.
Definition: fontcache.h:212
LanguagePackHeader::newgrflangid
uint8 newgrflangid
newgrf language id
Definition: language.h:52
_units_velocity
static const Units _units_velocity[]
Unit conversions for velocity.
Definition: strings.cpp:705
DRAW_STRING_BUFFER
static const int DRAW_STRING_BUFFER
Size of the buffer used for drawing strings.
Definition: gfx_func.h:86
GetTownName
char * GetTownName(char *buff, const TownNameParams *par, uint32 townnameparts, const char *last)
Fills buffer with specified town name.
Definition: townname.cpp:49
newgrf_engine.h
FS_NORMAL
@ FS_NORMAL
Index of the normal font in the font tables.
Definition: gfx_type.h:203
RemapNewGRFStringControlCode
uint RemapNewGRFStringControlCode(uint scc, char *buf_start, char **buff, const char **str, int64 *argv, uint argv_size, bool modify_argv)
FormatString for NewGRF specific "magic" string control codes.
Definition: newgrf_text.cpp:858
FS2OTTD
std::string FS2OTTD(const std::wstring &name)
Convert to OpenTTD's encoding from a wide string.
Definition: win32.cpp:542
UnitConversion::ToDisplay
int64 ToDisplay(int64 input, bool round=true) const
Convert value from OpenTTD's internal unit into the displayed value.
Definition: strings.cpp:672
CurrencySpec::suffix
std::string suffix
Suffix to apply when formatting money in this currency.
Definition: currency.h:77
Industry::type
IndustryType type
type of industry.
Definition: industry.h:83
StringParameters::GetDataLeft
uint GetDataLeft() const
Return the amount of elements which can still be read.
Definition: strings_func.h:132
YearMonthDay::month
Month month
Month (0..11)
Definition: date_type.h:106
CargoSpec::units_volume
StringID units_volume
Name of a single unit of cargo of this type.
Definition: cargotype.h:73
WC_INDUSTRY_DIRECTORY
@ WC_INDUSTRY_DIRECTORY
Industry directory; Window numbers:
Definition: window_type.h:259
GetGameStringPtr
const char * GetGameStringPtr(uint id)
Get the string pointer of a particular game string.
Definition: game_text.cpp:308
FontCacheSubSetting::font
std::string font
The name of the font, or path to the font.
Definition: fontcache.h:204
UnitsLong::s
StringID s
String for the short variant of the unit.
Definition: strings.cpp:700
InitFontCache
void InitFontCache(bool monospace)
(Re)initialize the font cache related things, i.e.
Definition: fontcache.cpp:128
Date
int32 Date
The type to store our dates in.
Definition: date_type.h:14
StringParameters::offset
uint offset
Current offset in the data/type arrays.
Definition: strings_func.h:66
ReadFileToMem
std::unique_ptr< char[]> ReadFileToMem(const std::string &filename, size_t &lenp, size_t maxsize)
Load a file into memory.
Definition: fileio.cpp:1111
TAB_SIZE_GAMESCRIPT
static const uint TAB_SIZE_GAMESCRIPT
Number of strings for GameScripts.
Definition: strings_type.h:49
_settings_game
GameSettings _settings_game
Game settings of a running game or the scenario editor.
Definition: settings.cpp:54
Station::indtype
IndustryType indtype
Industry type to get the name from.
Definition: station_base.h:472
Depot::town_cn
uint16 town_cn
The N-1th depot for this town (consecutive number)
Definition: depot_base.h:24
LoadedLanguagePack::langtab_start
std::array< uint, TEXT_TAB_END > langtab_start
Offset into langpack offs.
Definition: strings.cpp:193
LanguagePackHeader::name
char name[32]
the international name of this language
Definition: language.h:29
ConvertDateToYMD
void ConvertDateToYMD(Date date, YearMonthDay *ymd)
Converts a Date to a Year, Month & Day.
Definition: date.cpp:94
BuildContentTypeStringList
void BuildContentTypeStringList()
Build array of all strings corresponding to the content types.
Definition: network_content_gui.cpp:1027
MAX_LANG
static const uint MAX_LANG
Maximum number of languages supported by the game, and the NewGRF specs.
Definition: strings_type.h:19
industry.h
safeguards.h
FontCacheSettings::medium
FontCacheSubSetting medium
The normal font size.
Definition: fontcache.h:214
GetGRFStringPtr
const char * GetGRFStringPtr(uint16 stringid)
Get a C-string from a stringid set by a newgrf.
Definition: newgrf_text.cpp:653
DEFAULT_GROUP
static const GroupID DEFAULT_GROUP
Ungrouped vehicles are in this group.
Definition: group_type.h:17
LanguagePackGlyphSearcher::DefaultSize
FontSize DefaultSize() override
Get the default (font) size of the string.
Definition: strings.cpp:2106
WC_SHIPS_LIST
@ WC_SHIPS_LIST
Ships list; Window numbers:
Definition: window_type.h:313
GetGRFStringID
StringID GetGRFStringID(uint32 grfid, StringID stringid)
Returns the index for this stringid associated with its grfID.
Definition: newgrf_text.cpp:601
StrEmpty
static bool StrEmpty(const char *s)
Check if a string buffer is empty.
Definition: string_func.h:67
settings
fluid_settings_t * settings
FluidSynth settings handle.
Definition: fluidsynth.cpp:21
fontdetection.h
StringParameters::type
WChar * type
Array with type information about the data. Can be nullptr when no type information is needed....
Definition: strings_func.h:63
MissingGlyphSearcher::Monospace
virtual bool Monospace()=0
Whether to search for a monospace font or not.
BaseStation::name
std::string name
Custom name.
Definition: base_station_base.h:57
EngineInfo::callback_mask
uint16 callback_mask
Bitmask of vehicle callbacks that have to be called.
Definition: engine_type.h:154
StringParameters::GetPointerToOffset
uint64 * GetPointerToOffset(uint offset) const
Get a pointer to a specific element in the data array.
Definition: strings_func.h:138
newgrf_text.h
CompanyProperties::president_name
std::string president_name
Name of the president if the user changed it.
Definition: company_base.h:63
LanguageMetadata::file
char file[MAX_PATH]
Name of the file we read this data from.
Definition: language.h:94
error.h
LocaleSettings::units_weight
byte units_weight
unit system for weight
Definition: settings_type.h:239
WC_TRAINS_LIST
@ WC_TRAINS_LIST
Trains list; Window numbers:
Definition: window_type.h:301
StringParameters::GetDataPointer
uint64 * GetDataPointer() const
Get a pointer to the current element in the data array.
Definition: strings_func.h:126
language.h
FACIL_DOCK
@ FACIL_DOCK
Station with a dock.
Definition: station_type.h:57
date_func.h
stdafx.h
VehicleType
VehicleType
Available vehicle types.
Definition: vehicle_type.h:21
IndustrySpec
Defines the data structure for constructing industry.
Definition: industrytype.h:107
LanguagePackHeader::digit_decimal_separator
char digit_decimal_separator[8]
Decimal separator.
Definition: language.h:39
LanguagePackHeader::own_name
char own_name[32]
the localized name of this language
Definition: language.h:30
CurrencySpec
Specification of a currency.
Definition: currency.h:72
StringParameters::num_param
uint num_param
Length of the data array.
Definition: strings_func.h:67
LanguagePackHeader::isocode
char isocode[16]
the ISO code for the language (not country code)
Definition: language.h:31
MacOSSetCurrentLocaleName
void MacOSSetCurrentLocaleName(const char *iso_code)
Store current language locale as a CoreFoundation locale.
Definition: string_osx.cpp:310
CompanyProperties::president_name_2
uint32 president_name_2
Parameter of president_name_1.
Definition: company_base.h:62
ConvertSpeedToDisplaySpeed
uint ConvertSpeedToDisplaySpeed(uint speed)
Convert the given (internal) speed to the display speed.
Definition: strings.cpp:765
Utf8Decode
size_t Utf8Decode(WChar *c, const char *s)
Decode and consume the next UTF-8 encoded character.
Definition: string.cpp:593
GetBroadestDigit
void GetBroadestDigit(uint *front, uint *next, FontSize size)
Determine the broadest digits for guessing the maximum width of a n-digit number.
Definition: gfx.cpp:1493
LanguagePackGlyphSearcher::Monospace
bool Monospace() override
Whether to search for a monospace font or not.
Definition: strings.cpp:2126
BuildIndustriesLegend
void BuildIndustriesLegend()
Fills an array for the industries legends.
Definition: smallmap_gui.cpp:169
LocaleSettings::units_force
byte units_force
unit system for force
Definition: settings_type.h:241
LanguagePackGlyphSearcher
Helper for searching through the language pack.
Definition: strings.cpp:2096
UnitsLong::l
StringID l
String for the long variant of the unit.
Definition: strings.cpp:701
_current_language
const LanguageMetadata * _current_language
The currently loaded language.
Definition: strings.cpp:47
FormatNumber
static char * FormatNumber(char *buff, int64 number, const char *last, const char *separator, int zerofill=1, int fractional_digits=0)
Format a number into a string.
Definition: strings.cpp:324
Industry::town
Town * town
Nearest town.
Definition: industry.h:68
_scan_for_gender_data
static bool _scan_for_gender_data
Are we scanning for the gender of the current string? (instead of formatting it)
Definition: strings.cpp:198
YearMonthDay::year
Year year
Year (0...)
Definition: date_type.h:105
string_func.h
CALLBACK_FAILED
static const uint CALLBACK_FAILED
Different values for Callback result evaluations.
Definition: newgrf_callbacks.h:408
_units_power
static const Units _units_power[]
Unit conversions for power.
Definition: strings.cpp:713
StringID
uint32 StringID
Numeric value that represents a string, independent of the selected language.
Definition: strings_type.h:16
LANG_DIR
@ LANG_DIR
Subdirectory for all translation files.
Definition: fileio_type.h:118
rev.h
Engine::name
std::string name
Custom name of engine.
Definition: engine_base.h:37
station_base.h
FormatBytes
static char * FormatBytes(char *buff, int64 number, const char *last)
Format a given number as a number of bytes with the SI prefix.
Definition: strings.cpp:392
StringParameters::data
uint64 * data
Array with the actual data.
Definition: strings_func.h:62
strings_func.h
FormatString
static char * FormatString(char *buff, const char *str, StringParameters *args, const char *last, uint case_index=0, bool game_script=false, bool dry_run=false)
Parse most format codes within a string and write the result to a buffer.
Definition: strings.cpp:810
ConvertKmhishSpeedToDisplaySpeed
uint ConvertKmhishSpeedToDisplaySpeed(uint speed)
Convert the given km/h-ish speed to the display speed.
Definition: strings.cpp:788
LanguagePackGlyphSearcher::j
uint j
Iterator for the secondary language tables.
Definition: strings.cpp:2098
StringParameters::GetInt32
int32 GetInt32(WChar type=0)
Read an int32 from the argument array.
Definition: strings_func.h:120
TextDirection
TextDirection
Directions a text can go to.
Definition: strings_type.h:22
Units::c
UnitConversion c
Conversion.
Definition: strings.cpp:692
GetCurrentLocale
const char * GetCurrentLocale(const char *param)
Determine the current charset based on the environment First check some default values,...
Definition: strings.cpp:1897
StringParameters
Definition: strings_func.h:60
LanguagePackGlyphSearcher::Reset
void Reset() override
Reset the search, i.e.
Definition: strings.cpp:2100
WC_BUILD_VEHICLE
@ WC_BUILD_VEHICLE
Build vehicle; Window numbers:
Definition: window_type.h:376
FACIL_TRAIN
@ FACIL_TRAIN
Station with train station.
Definition: station_type.h:53
SetFallbackFont
bool SetFallbackFont(struct FontCacheSettings *settings, const char *language_isocode, int winlangid, class MissingGlyphSearcher *callback)
We would like to have a fallback font as the current one doesn't contain all characters we need.
Definition: font_osx.cpp:70
LanguagePackHeader::IsValid
bool IsValid() const
Check whether the header is a valid header for OpenTTD.
Definition: strings.cpp:1753
LocaleSettings::units_power
byte units_power
unit system for power
Definition: settings_type.h:238
game_text.hpp
_units_power_to_weight
static const Units _units_power_to_weight[]
Unit conversions for power to weight.
Definition: strings.cpp:720
LocaleSettings::units_height
byte units_height
unit system for height
Definition: settings_type.h:242
SetDParamMaxValue
void SetDParamMaxValue(uint n, uint64 max_value, uint min_count, FontSize size)
Set DParam n to some number that is suitable for string size computations.
Definition: strings.cpp:95
InvalidateWindowClassesData
void InvalidateWindowClassesData(WindowClass cls, int data, bool gui_scope)
Mark window data of all windows of a given class as invalid (in need of re-computing) Note that by de...
Definition: window.cpp:3271
CargoSpec::quantifier
StringID quantifier
Text for multiple units of cargo of this type.
Definition: cargotype.h:74
DIR
Definition: win32.cpp:68
GetGlyph
static const Sprite * GetGlyph(FontSize size, WChar key)
Get the Sprite for a glyph.
Definition: fontcache.h:184
InitializeSortedCargoSpecs
void InitializeSortedCargoSpecs()
Initialize the list of sorted cargo specifications.
Definition: cargotype.cpp:189
CurrencySpec::rate
uint16 rate
The conversion rate compared to the base currency.
Definition: currency.h:73
TEXT_TAB_GAMESCRIPT_START
@ TEXT_TAB_GAMESCRIPT_START
Start of GameScript supplied strings.
Definition: strings_type.h:39
network_content_gui.h
_units_weight
static const UnitsLong _units_weight[]
Unit conversions for weight.
Definition: strings.cpp:733
FontCacheSettings::mono
FontCacheSubSetting mono
The mono space font used for license/readme viewers.
Definition: fontcache.h:216
GetString
std::string GetString(StringID string)
Resolve the given StringID into a std::string with all the associated DParam lookups and formatting.
Definition: strings.cpp:285
LanguagePackHeader::digit_group_separator_currency
char digit_group_separator_currency[8]
Thousand separator used for currencies.
Definition: language.h:37
waypoint_base.h
_units_force
static const Units _units_force[]
Unit conversions for force.
Definition: strings.cpp:747
LanguagePackHeader::winlangid
uint16 winlangid
Windows language ID: Windows cannot and will not convert isocodes to something it can use to determin...
Definition: language.h:51
Sign
Definition: signs_base.h:22
_global_string_params_data
static uint64 _global_string_params_data[20]
Global array of string parameters. To access, use SetDParam.
Definition: strings.cpp:55
StringParameters::ClearTypeInformation
void ClearTypeInformation()
Reset the type array.
Definition: strings.cpp:60
seprintf
int CDECL seprintf(char *str, const char *last, const char *format,...)
Safer implementation of snprintf; same as snprintf except:
Definition: string.cpp:554
Vehicle::unitnumber
UnitID unitnumber
unit number, for display purposes only
Definition: vehicle_base.h:305
Group::name
std::string name
Group Name.
Definition: group.h:75
CreateTextRefStackBackup
struct TextRefStack * CreateTextRefStackBackup()
Create a backup of the current NewGRF text stack.
Definition: newgrf_text.cpp:788
WL_ERROR
@ WL_ERROR
Errors (eg. saving/loading failed)
Definition: error.h:24
LocaleSettings::digit_group_separator_currency
std::string digit_group_separator_currency
thousand separator for currencies
Definition: settings_type.h:244
SetCurrentGrfLangID
void SetCurrentGrfLangID(byte language_id)
Equivalence Setter function between game and newgrf langID.
Definition: newgrf_text.cpp:672
FontCacheSubSetting::os_handle
const void * os_handle
Optional native OS font info. Only valid during font search.
Definition: fontcache.h:208
abs
static T abs(const T a)
Returns the absolute value of (scalar) variable.
Definition: math_func.hpp:21
stredup
char * stredup(const char *s, const char *last)
Create a duplicate of the given string.
Definition: string.cpp:138
LanguagePackHeader::num_genders
uint8 num_genders
the number of genders of this language
Definition: language.h:53
error
void CDECL error(const char *s,...)
Error handling for fatal non-user errors.
Definition: openttd.cpp:134
CompanyProperties::president_name_1
StringID president_name_1
Name of the president if the user did not change it.
Definition: company_base.h:61
LanguagePackDeleter
Definition: strings.cpp:179
window_func.h
CheckForMissingGlyphs
void CheckForMissingGlyphs(bool base_font, MissingGlyphSearcher *searcher)
Check whether the currently loaded language pack uses characters that the currently loaded font does ...
Definition: strings.cpp:2158
Debug
#define Debug(name, level, format_string,...)
Ouptut a line of debugging information.
Definition: debug.h:37
Depot
Definition: depot_base.h:19
Town
Town data structure.
Definition: town.h:50
lengthof
#define lengthof(x)
Return the length of an fixed size array.
Definition: stdafx.h:386
YearMonthDay
Data structure to convert between Date and triplet (year, month, and day).
Definition: date_type.h:104
SpecializedStation< Station, false >::GetIfValid
static Station * GetIfValid(size_t index)
Returns station if the index is a valid index for this station type.
Definition: base_station_base.h:227
GameSettings::locale
LocaleSettings locale
settings related to used currency/unit system in the current game
Definition: settings_type.h:599
OverflowSafeInt< int64 >
CargoID
byte CargoID
Cargo slots to indicate a cargo type within a game.
Definition: cargo_type.h:20
MemSetT
static void MemSetT(T *ptr, byte value, size_t num=1)
Type-safe version of memset().
Definition: mem_func.hpp:49
LanguagePackHeader::digit_group_separator
char digit_group_separator[8]
Thousand separator used for anything not currencies.
Definition: language.h:35
FS_MONO
@ FS_MONO
Index of the monospaced font in the font tables.
Definition: gfx_type.h:206
Engine::IsEnabled
bool IsEnabled() const
Checks whether the engine is a valid (non-articulated part of an) engine.
Definition: engine.cpp:143
engine_base.h
LanguagePackHeader::ident
uint32 ident
32-bits identifier
Definition: language.h:27
strnatcmp
int strnatcmp(const char *s1, const char *s2, bool ignore_garbage_at_front)
Compares two strings using case insensitive natural sort.
Definition: string.cpp:737
FontSize
FontSize
Available font sizes.
Definition: gfx_type.h:202
GetStringIndex
static uint GetStringIndex(StringID str)
Extract the StringIndex from a StringID.
Definition: strings_func.h:36
GetIndustrySpec
const IndustrySpec * GetIndustrySpec(IndustryType thistype)
Accessor for array _industry_specs.
Definition: industry_cmd.cpp:123
VEH_TRAIN
@ VEH_TRAIN
Train vehicle type.
Definition: vehicle_type.h:24
IndustrySpec::name
StringID name
Displayed name of the industry.
Definition: industrytype.h:127
LocaleSettings::units_velocity
byte units_velocity
unit system for velocity
Definition: settings_type.h:237
_config_language_file
std::string _config_language_file
The file (name) stored in the configuration.
Definition: strings.cpp:45
BaseVehicle::type
VehicleType type
Type of vehicle.
Definition: vehicle_type.h:52
StringParameters::HasTypeInformation
bool HasTypeInformation() const
Does this instance store information about the type of the parameters.
Definition: strings_func.h:145
FACIL_AIRPORT
@ FACIL_AIRPORT
Station with an airport.
Definition: station_type.h:56
Units::s
StringID s
String for the unit.
Definition: strings.cpp:693
strecpy
char * strecpy(char *dst, const char *src, const char *last)
Copies characters from one buffer to another.
Definition: string.cpp:113
EngineInfo::string_id
StringID string_id
Default name of engine.
Definition: engine_type.h:156
free
static void free(const void *ptr)
Version of the standard free that accepts const pointers.
Definition: stdafx.h:470
ttd_opendir
static DIR * ttd_opendir(const char *path)
A wrapper around opendir() which will convert the string from OPENTTD encoding to that of the filesys...
Definition: fileio_func.h:113
CT_INVALID
@ CT_INVALID
Invalid cargo type.
Definition: cargo_type.h:69
strecat
char * strecat(char *dst, const char *src, const char *last)
Appends characters from one string to another.
Definition: string.cpp:85
VEH_SHIP
@ VEH_SHIP
Ship vehicle type.
Definition: vehicle_type.h:26
_current_collator
std::unique_ptr< icu::Collator > _current_collator
Collator for the language currently in use.
Definition: strings.cpp:52
GetLanguage
const LanguageMetadata * GetLanguage(byte newgrflangid)
Get the language with the given NewGRF language ID.
Definition: strings.cpp:1933
Company
Definition: company_base.h:117
Town::name
std::string name
Custom town name. If empty, the town was not renamed and uses the generated name.
Definition: town.h:59
CurrencySpec::prefix
std::string prefix
Prefix to apply when formatting money in this currency.
Definition: currency.h:76
WC_AIRCRAFT_LIST
@ WC_AIRCRAFT_LIST
Aircraft list; Window numbers:
Definition: window_type.h:319
Sprite
Data structure describing a sprite.
Definition: spritecache.h:17
lastof
#define lastof(x)
Get the last element of an fixed size array.
Definition: stdafx.h:402
WC_STATION_LIST
@ WC_STATION_LIST
Station list; Window numbers:
Definition: window_type.h:295
MAX_NUM_CASES
static const uint8 MAX_NUM_CASES
Maximum number of supported cases.
Definition: language.h:21
SetDParamMaxDigits
void SetDParamMaxDigits(uint n, uint count, FontSize size)
Set DParam n to some number that is suitable for string size computations.
Definition: strings.cpp:111
_current_text_dir
TextDirection _current_text_dir
Text direction of the currently selected language.
Definition: strings.cpp:49
LocaleSettings::digit_group_separator
std::string digit_group_separator
thousand separator for non-currencies
Definition: settings_type.h:243
ConvertDisplaySpeedToSpeed
uint ConvertDisplaySpeedToSpeed(uint speed)
Convert the given display speed to the (internal) speed.
Definition: strings.cpp:778
CBID_VEHICLE_NAME
@ CBID_VEHICLE_NAME
Called to determine the engine name to show.
Definition: newgrf_callbacks.h:284
signs_base.h
UnitConversion
Helper for unit conversion.
Definition: strings.cpp:662
Units::decimal_places
unsigned int decimal_places
Number of decimal places embedded in the value. For example, 1 if the value is in tenths,...
Definition: strings.cpp:694
CopyInDParam
void CopyInDParam(int offs, const uint64 *src, int num)
Copy num string parameters from array src into the global string parameter array.
Definition: strings.cpp:129
IsTextDirectionChar
static bool IsTextDirectionChar(WChar c)
Is the given character a text direction character.
Definition: string_func.h:228
SetDParamStr
void SetDParamStr(uint n, const char *str)
This function is used to "bind" a C string to a OpenTTD dparam slot.
Definition: strings.cpp:297
GetLanguageFileHeader
static bool GetLanguageFileHeader(const char *file, LanguagePackHeader *hdr)
Reads the language file header and checks compatibility.
Definition: strings.cpp:1948
INVALID_STRING_ID
static const StringID INVALID_STRING_ID
Constant representing an invalid string (16bit in case it is used in savegames)
Definition: strings_type.h:17
GRFFile
Dynamic data of a loaded NewGRF.
Definition: newgrf.h:106
InitializeLanguagePacks
void InitializeLanguagePacks()
Make a list of the available language packs.
Definition: strings.cpp:2002
UsingNewGRFTextStack
bool UsingNewGRFTextStack()
Check whether the NewGRF text stack is in use.
Definition: newgrf_text.cpp:779
debug.h
DeterminePluralForm
static int DeterminePluralForm(int64 count, int plural_form)
Determine the "plural" index given a plural form and a number.
Definition: strings.cpp:524
LanguagePackHeader
Header of a language file.
Definition: language.h:24
CompanyProperties::name_1
StringID name_1
Name of the company if the user did not change it.
Definition: company_base.h:58
TextRefStack
Definition: newgrf_text.cpp:708