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