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