FS2_Open
Open source remastering of the Freespace 2 engine
localize.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) Volition, Inc. 1999. All rights reserved.
3  *
4  * All source code herein is the property of Volition, Inc. You may not sell
5  * or otherwise commercially exploit the source or things you created based on the
6  * source.
7  *
8 */
9 
10 
11 
12 
13 #include <ctype.h>
14 #include "cfile/cfile.h"
15 #include "localization/localize.h"
16 #include "osapi/osregistry.h"
17 #include "parse/encrypt.h"
18 #include "parse/parselo.h"
19 #include "playerman/player.h"
20 
21 
22 
23 
24 // ------------------------------------------------------------------------------------------------------------
25 // LOCALIZE DEFINES/VARS
26 //
27 
28 // general language/localization data ---------------------
29 
30 // current language
33 
34 // These are the original languages supported by FS2. The code expects these languages to be supported even if the tables don't
35 
37  { "English", "", {127,0,176,0,0}, 589986744}, // English
38  { "German", "gr", {164,0,176,0,0}, -1132430286 }, // German
39  { "French", "fr", {164,0,176,0,0}, 0 }, // French
40  { "Polish", "pl", {127,0,176,0,0}, -1131728960}, // Polish
41 };
42 
44 
45 // use these to replace *_BUILD, values before
46 // only 1 will be active at a time
47 int Lcl_fr = 0;
48 int Lcl_gr = 0;
49 int Lcl_pl = 0;
50 int Lcl_english = 1;
51 
52 
53 // executable string localization data --------------------
54 
55 // XSTR_SIZE is the total count of unique XSTR index numbers. An index is used to
56 // reference an entry in strings.tbl. This is used for translation of strings from
57 // the english version (in the code) to a foreign version (in the table). Thus, if you
58 // add a new string to the code, you must assign it a new index. Use the number below for
59 // that index and increase the number below by one.
60 #define XSTR_SIZE 1638
61 
62 
63 // struct to allow for strings.tbl-determined x offset
64 // offset is 0 for english, by default
65 typedef struct {
66  const char *str;
67  int offset_x; // string offset in 640
68  int offset_x_hi; // string offset in 1024
69 } lcl_xstr;
70 
71 //char *Xstr_table[XSTR_SIZE];
73 int Xstr_inited = 0;
74 
75 
76 // table/mission externalization stuff --------------------
77 #define PARSE_TEXT_BUF_SIZE PARSE_BUF_SIZE
78 #define PARSE_ID_BUF_SIZE 5
79 #define LCL_MAX_STRINGS 4500
81 
82 
83 // ------------------------------------------------------------------------------------------------------------
84 // LOCALIZE FORWARD DECLARATIONS
85 //
86 
87 // given a valid XSTR() tag piece of text, extract the string portion, return it in out, nonzero on success
88 int lcl_ext_get_text(const char *xstr, char *out);
89 int lcl_ext_get_text(const SCP_string &xstr, SCP_string &out);
90 
91 // given a valid XSTR() tag piece of text, extract the id# portion, return the value in out, nonzero on success
92 int lcl_ext_get_id(const char *xstr, int *out);
93 int lcl_ext_get_id(const SCP_string &xstr, int *out);
94 
95 // if the char is a valid char for a signed integer value string
97 
98 // parses the string.tbl and reports back only on the languages it found
99 void parse_stringstbl_quick(const char *filename);
100 
101 
102 // ------------------------------------------------------------------------------------------------------------
103 // LOCALIZE FUNCTIONS
104 //
105 
106 // initialize localization, if no language is passed - use the language specified in the registry
107 void lcl_init(int lang_init)
108 {
109  atexit(lcl_xstr_close);
110 
111  char lang_string[128];
112  const char *ret;
113  int lang, idx, i;
114 
115  // initialize encryption
116  encrypt_init();
117 
118  // setup English
119  Lcl_languages.push_back(Lcl_builtin_languages[FS2_OPEN_DEFAULT_LANGUAGE]);
120 
121  // check string.tbl to see which languages we support
122  try
123  {
124  parse_stringstbl_quick("strings.tbl");
125  }
126  catch (const parse::ParseException& e)
127  {
128  mprintf(("TABLES: Unable to parse '%s'! Error message = %s.\n", "strings.tbl", e.what()));
129  }
130 
132 
133  // if the only language we have at this point is English, we need to setup the builtin languages as we might be dealing with an old style strings.tbl
134  // which doesn't support anything beyond the builtin languages. Note, we start at i = 1 because we added English above.
135  if ((int)Lcl_languages.size() == 1) {
136  for (i=1; i<NUM_BUILTIN_LANGUAGES; i++) {
137  Lcl_languages.push_back(Lcl_builtin_languages[i]);
138  }
139  }
140 
141  // read the language from the registry
142  if(lang_init < 0){
143  memset(lang_string, 0, 128);
144  // default to DEFAULT_LANGUAGE (which should be English so we don't have to put German text
145  // in tstrings in the #default section)
146  ret = os_config_read_string(NULL, "Language", Lcl_languages[FS2_OPEN_DEFAULT_LANGUAGE].lang_name);
147 
148  if(ret == NULL){
149  Error(LOCATION, "Default language not found.");
150  }
151 
152  strcpy_s(lang_string, ret);
153 
154 
155  // look it up
156  lang = -1;
157  for(idx = 0; idx < (int)Lcl_languages.size(); idx++){
158  if(!stricmp(Lcl_languages[idx].lang_name, lang_string)){
159  lang = idx;
160  break;
161  }
162  }
163  if(lang < 0){
164  lang = 0;
165  }
166  } else {
167  Assert((lang_init >= 0) && (lang_init < (int)Lcl_languages.size()));
168  lang = lang_init;
169  }
170 
171  // set the language (this function takes care of setting up file pointers)
172  lcl_set_language(lang);
173 }
174 
175 // determine what language we're running in, see LCL_* defines above
177 {
178  return Lcl_current_lang;
179 }
180 
181 // parses the string.tbl to see which languages are supported. Doesn't read in any strings.
183 {
184  lang_info language;
185  int lang_idx;
186  int i;
187 
188  read_file_text(filename, CF_TYPE_TABLES);
189  reset_parse();
190 
191  if (optional_string("#Supported Languages")) {
192  while (required_string_either("#End","$Language:")) {
193  required_string("$Language:");
195  required_string("+Extension:");
197  required_string("+Special Character Index:");
198  stuff_ubyte(&language.special_char_indexes[0]);
199  for (i = 1; i < MAX_FONTS; ++i) {
200  // default to "none"/0 except for font03 which defaults to 176
201  // NOTE: fonts.tbl may override these values
202  if (i == FONT3) {
203  language.special_char_indexes[i] = 176;
204  } else {
205  language.special_char_indexes[i] = 0;
206  }
207  }
208 
209  lang_idx = -1;
210 
211  // see if we already have this language
212  for (i = 0; i < (int)Lcl_languages.size(); i++) {
213  if (!strcmp(Lcl_languages[i].lang_name, language.lang_name)) {
214  strcpy_s(Lcl_languages[i].lang_ext, language.lang_ext);
215  Lcl_languages[i].special_char_indexes[0] = language.special_char_indexes[0];
216  lang_idx = i;
217  break;
218  }
219  }
220 
221  // if we have a new language, add it.
222  if (lang_idx == -1) {
223  Lcl_languages.push_back(language);
224  }
225  }
226  }
227 }
228 
229 // Unified function for loading strings.tbl and tstrings.tbl (and their modular versions).
230 // The "external" parameter controls which format to load: true for tstrings.tbl, false for strings.tbl
231 void parse_stringstbl_common(const char *filename, const bool external)
232 {
233  char chr, buf[4096];
234  char language_tag[512];
235  int i, z, index;
236  char *p_offset = NULL;
237  int offset_lo = 0, offset_hi = 0;
238 
239  read_file_text(filename, CF_TYPE_TABLES);
240  reset_parse();
241 
242  // move down to the proper section
243  memset(language_tag, 0, sizeof(language_tag));
244  strcpy_s(language_tag, "#");
245  if (external && Lcl_current_lang == FS2_OPEN_DEFAULT_LANGUAGE){
246  strcat_s(language_tag, "default");
247  } else {
248  strcat_s(language_tag, Lcl_languages[Lcl_current_lang].lang_name);
249  }
250 
251  if ( skip_to_string(language_tag) != 1 ) {
252  mprintf(("Current language not found in %s\n", filename));
253  return;
254  }
255 
256  // parse all the strings in this section of the table
257  while ( !check_for_string("#") ) {
258  int num_offsets_on_this_line = 0;
259 
260  stuff_int(&index);
261  if (external) {
263  get_string(buf, sizeof(buf));
265  } else {
266  stuff_string(buf, F_RAW, sizeof(buf));
267  }
268 
269  if (external && (index < 0 || index >= LCL_MAX_STRINGS)) {
270  error_display(0, "Invalid tstrings table index specified (%i). Please increment LCL_MAX_STRINGS in localize.cpp.", index);
271  return;
272  } else if (!external && (index < 0 || index >= XSTR_SIZE)) {
273  Error(LOCATION, "Invalid strings table index specified (%i)", index);
274  }
275 
276  if (!external) {
277  i = strlen(buf);
278 
279  while (i--) {
280  if ( !isspace(buf[i]) )
281  break;
282  }
283 
284  // trim unnecessary end of string
285  if (i >= 0) {
286  // Assert(buf[i] == '"');
287  if (buf[i] != '"') {
288  // probably an offset on this entry
289 
290  // drop down a null terminator (prolly unnecessary)
291  buf[i+1] = 0;
292 
293  // back up over the potential offset
294  while ( !is_white_space(buf[i]) )
295  i--;
296 
297  // now back up over intervening spaces
298  while ( is_white_space(buf[i]) )
299  i--;
300 
301  num_offsets_on_this_line = 1;
302 
303  if (buf[i] != '"') {
304  // could have a 2nd offset value (one for 640, one for 1024)
305  // so back up again
306  while ( !is_white_space(buf[i]) )
307  i--;
308 
309  // now back up over intervening spaces
310  while ( is_white_space(buf[i]) )
311  i--;
312 
313  num_offsets_on_this_line = 2;
314  }
315 
316  p_offset = &buf[i+1]; // get ptr to string section with offset in it
317 
318  if (buf[i] != '"')
319  Error(LOCATION, "%s is corrupt", filename); // now its an error
320  }
321 
322  buf[i] = 0;
323  }
324 
325  // copy string into buf
326  z = 0;
327  for (i = 1; buf[i]; i++) {
328  chr = buf[i];
329 
330  if (chr == '\\') {
331  chr = buf[++i];
332 
333  if (chr == 'n')
334  chr = '\n';
335  else if (chr == 'r')
336  chr = '\r';
337  }
338 
339  buf[z++] = chr;
340  }
341 
342  // null terminator on buf
343  buf[z] = 0;
344  }
345 
346  // write into Xstr_table (for strings.tbl) or Lcl_ext_str (for tstrings.tbl)
347  if (Parsing_modular_table) {
348  if ( external && (Lcl_ext_str[index] != NULL) ) {
349  vm_free((void *) Lcl_ext_str[index]);
350  Lcl_ext_str[index] = NULL;
351  } else if ( !external && (Xstr_table[index].str != NULL) ) {
352  vm_free((void *) Xstr_table[index].str);
353  Xstr_table[index].str = NULL;
354  }
355  }
356 
357  if (external && (Lcl_ext_str[index] != NULL)) {
358  Warning(LOCATION, "Tstrings table index %d used more than once", index);
359  } else if (!external && (Xstr_table[index].str != NULL)) {
360  Warning(LOCATION, "Strings table index %d used more than once", index);
361  }
362 
363  if (external) {
364  Lcl_ext_str[index] = vm_strdup(buf);
365  } else {
366  Xstr_table[index].str = vm_strdup(buf);
367  }
368 
369  // the rest of this loop applies only to strings.tbl,
370  // so we can move on to the next line if we're reading from tstrings.tbl
371  if (external) {
372  continue;
373  }
374 
375  // read offset information, assume 0 if nonexistant
376  if (p_offset != NULL) {
377  if (sscanf(p_offset, "%d%d", &offset_lo, &offset_hi) < num_offsets_on_this_line) {
378  // whatever is in the file ain't a proper offset
379  Error(LOCATION, "%s is corrupt", filename);
380  }
381  }
382 
383  Xstr_table[index].offset_x = offset_lo;
384 
385  if (num_offsets_on_this_line == 2)
386  Xstr_table[index].offset_x_hi = offset_hi;
387  else
388  Xstr_table[index].offset_x_hi = offset_lo;
389 
390  // clear out our vars
391  p_offset = NULL;
392  offset_lo = 0;
393  offset_hi = 0;
394  }
395 }
396 
397 void parse_stringstbl(const char *filename)
398 {
399  parse_stringstbl_common(filename, false);
400 }
401 
402 void parse_tstringstbl(const char *filename)
403 {
404  parse_stringstbl_common(filename, true);
405 }
406 
407 // initialize the xstr table
409 {
410  int i;
411 
412 
413  for (i = 0; i < XSTR_SIZE; i++)
414  Xstr_table[i].str = NULL;
415 
416  for (i = 0; i < LCL_MAX_STRINGS; i++)
417  Lcl_ext_str[i] = NULL;
418 
419 
420  try
421  {
422  parse_stringstbl("strings.tbl");
423  }
424  catch (const parse::ParseException& e)
425  {
426  mprintf(("TABLES: Unable to parse '%s'! Error message = %s.\n", "strings.tbl", e.what()));
427  }
428 
430 
431 
432  try
433  {
434  parse_tstringstbl("tstrings.tbl");
435  }
436  catch (const parse::ParseException& e)
437  {
438  mprintf(("TABLES: Unable to parse '%s'! Error message = %s.\n", "tstrings.tbl", e.what()));
439  }
440 
442 
443 
444  Xstr_inited = 1;
445 }
446 
447 
448 // free Xstr table
450 {
451  int i;
452 
453  for (i=0; i<XSTR_SIZE; i++){
454  if (Xstr_table[i].str != NULL) {
455  vm_free((void *) Xstr_table[i].str);
456  Xstr_table[i].str = NULL;
457  }
458  }
459 
460  for (i=0; i<LCL_MAX_STRINGS; i++){
461  if (Lcl_ext_str[i] != NULL) {
462  vm_free((void *) Lcl_ext_str[i]);
463  Lcl_ext_str[i] = NULL;
464  }
465  }
466 }
467 
468 
469 // set our current language
470 void lcl_set_language(int lang)
471 {
472  Lcl_current_lang = lang;
473 
474  nprintf(("General", "Setting language to %s\n", Lcl_languages[lang].lang_name));
475 
476  Assertion((Lcl_current_lang >= 0) && (Lcl_current_lang < (int)Lcl_languages.size()), "Attempt to set language to an invalid language");
477 
478  // flag the proper language as being active
479  Lcl_special_chars = Lcl_languages[Lcl_current_lang].special_char_indexes[0];
480  Lcl_fr = 0;
481  Lcl_gr = 0;
482  Lcl_pl = 0;
483  Lcl_english = 0;
484  if (!strcmp(Lcl_languages[Lcl_current_lang].lang_name, Lcl_builtin_languages[LCL_ENGLISH].lang_name)) {
485  Lcl_english = 1;
486  } else if (!strcmp(Lcl_languages[Lcl_current_lang].lang_name, Lcl_builtin_languages[LCL_FRENCH].lang_name)) {
487  Lcl_fr = 1;
488  } else if (!strcmp(Lcl_languages[Lcl_current_lang].lang_name, Lcl_builtin_languages[LCL_GERMAN].lang_name)) {
489  Lcl_gr = 1;
490  } else if (!strcmp(Lcl_languages[Lcl_current_lang].lang_name, Lcl_builtin_languages[LCL_POLISH].lang_name)) {
491  Lcl_pl = 1;
492  }
493 }
494 
496 {
497  Assertion((font_num >= 0) && (font_num < MAX_FONTS), "Passed an invalid font index");
498  Assertion((Lcl_current_lang >= 0) && (Lcl_current_lang < (int)Lcl_languages.size()), "Current language is not valid, can't get font indexes");
499 
500  return Lcl_languages[Lcl_current_lang].special_char_indexes[font_num];
501 }
502 
503 // maybe add on an appropriate subdirectory when opening a localized file
504 void lcl_add_dir(char *current_path)
505 {
506  char last_char;
507  int path_len;
508 
509  // if the disk extension is 0 length, don't add enything
510  if (strlen(Lcl_languages[Lcl_current_lang].lang_ext) <= 0) {
511  return;
512  }
513 
514  // get the length of the string so far
515  path_len = strlen(current_path);
516  if (path_len <= 0) {
517  return;
518  }
519 
520  // get the current last char
521  last_char = current_path[path_len - 1];
522 
523  // if the last char is a slash, just copy in the disk extension
524  if (last_char == DIR_SEPARATOR_CHAR) {
525  strcat(current_path, Lcl_languages[Lcl_current_lang].lang_ext);
526  strcat(current_path, DIR_SEPARATOR_STR);
527  }
528  // otherwise add a slash, then copy in the disk extension
529  else {
530  strcat(current_path, DIR_SEPARATOR_STR);
531  strcat(current_path, Lcl_languages[Lcl_current_lang].lang_ext);
532  }
533 }
534 
535 // maybe add localized directory to full path with file name when opening a localized file
536 int lcl_add_dir_to_path_with_filename(char *current_path, size_t path_max)
537 {
538  // if the disk extension is 0 length, don't add anything
539  if (strlen(Lcl_languages[Lcl_current_lang].lang_ext) <= 0) {
540  return 1;
541  }
542 
543  size_t str_size = path_max + 1;
544 
545  char *temp = new char[str_size];
546  memset(temp, 0, str_size * sizeof(char));
547 
548  // find position of last slash and copy rest of filename (not counting slash) to temp
549  // mark end of current path with '\0', so strcat will work
550  char *last_slash = strrchr(current_path, DIR_SEPARATOR_CHAR);
551  if (last_slash == NULL) {
552  strncpy(temp, current_path, path_max);
553  current_path[0] = '\0';
554  } else {
555  strncpy(temp, last_slash+1, path_max);
556  last_slash[1] = '\0';
557  }
558 
559  // add extension
560  strcat_s(current_path, path_max, Lcl_languages[Lcl_current_lang].lang_ext);
561  strcat_s(current_path, path_max, DIR_SEPARATOR_STR );
562 
563  // copy rest of filename from temp
564  strcat_s(current_path, path_max, temp);
565 
566  delete [] temp;
567  return 1;
568 }
569 
570 
571 // externalization of table/mission files -----------------------
572 
573 void lcl_replace_stuff(char *text, size_t max_len)
574 {
575  if (Fred_running)
576  return;
577 
578  Assert(text); // Goober5000
579 
580  // delegate to SCP_string for the replacements
581  SCP_string temp_text = text;
582  lcl_replace_stuff(temp_text);
583 
584  // fill up the original string
585  size_t len = temp_text.copy(text, max_len);
586  text[len] = 0;
587 }
588 
589 // Goober5000 - replace stuff in the string, e.g. $callsign with player's callsign
590 // now will also replace $rank with rank, e.g. "Lieutenant"
591 // now will also replace $quote with double quotation marks
592 // now will also replace $semicolon with semicolon mark
593 // now will also replace $slash and $backslash
595 {
596  if (Fred_running)
597  return;
598 
599  if (Player != NULL)
600  {
601  replace_all(text, "$callsign", Player->callsign);
602  replace_all(text, "$rank", Ranks[Player->stats.rank].name);
603  }
604  replace_all(text, "$quote", "\"");
605  replace_all(text, "$semicolon", ";");
606  replace_all(text, "$slash", "/");
607  replace_all(text, "$backslash", "\\");
608 }
609 
610 void lcl_fred_replace_stuff(char *text, size_t max_len)
611 {
612  if (!Fred_running)
613  return;
614 
615  Assert(text); // Goober5000
616 
617  // delegate to SCP_string for the replacements
618  SCP_string temp_text = text;
619  lcl_fred_replace_stuff(temp_text);
620 
621  // fill up the original string
622  size_t len = temp_text.copy(text, max_len);
623  text[len] = 0;
624 }
625 
627 {
628  if (!Fred_running)
629  return;
630 
631  replace_all(text, "\"", "$quote");
632  replace_all(text, ";", "$semicolon");
633  replace_all(text, "/", "$slash");
634  replace_all(text, "\\", "$backslash");
635 }
636 
637 // get the localized version of the string. if none exists, return the original string
638 // valid input to this function includes :
639 // "this is some text"
640 // XSTR("wheeee", -1)
641 // XSTR("whee", 20)
642 // and these should cover all the externalized string cases
643 // fills in id if non-NULL. a value of -2 indicates it is not an external string
644 void lcl_ext_localize_sub(const char *in, char *out, size_t max_len, int *id)
645 {
646  char text_str[PARSE_BUF_SIZE]="";
647  int str_id;
648  size_t str_len;
649 
650  Assert(in);
651  Assert(out);
652 
653  // default (non-external string) value
654  if (id != NULL) {
655  *id = -2;
656  }
657 
658  str_len = strlen(in);
659 
660  // if the string is < 9 chars, it can't be an XSTR("",) tag, so just copy it
661  if (str_len < 9) {
662  if (str_len > max_len)
663  error_display(0, "Token too long: [%s]. Length = %i. Max is %i.\n", in, str_len, max_len);
664 
665  strncpy(out, in, max_len);
666 
667  if (id != NULL)
668  *id = -2;
669 
670  return;
671  }
672 
673  // otherwise, check to see if it's an XSTR() tag
674  if (strnicmp(in, "XSTR", 4)) {
675  // NOT an XSTR() tag
676  if (str_len > max_len)
677  error_display(0, "Token too long: [%s]. Length = %i. Max is %i.\n", in, str_len, max_len);
678 
679  strncpy(out, in, max_len);
680 
681  if (id != NULL)
682  *id = -2;
683 
684  return;
685  }
686 
687  // at this point we _know_ its an XSTR() tag, so split off the strings and id sections
688  if (!lcl_ext_get_text(in, text_str)) {
689  if (str_len > max_len)
690  error_display(0, "Token too long: [%s]. Length = %i. Max is %i.\n", in, str_len, max_len);
691 
692  strncpy(out, in, max_len);
693 
694  if (id != NULL)
695  *id = -1;
696 
697  return;
698  }
699  if (!lcl_ext_get_id(in, &str_id)) {
700  if (str_len > max_len)
701  error_display(0, "Token too long: [%s]. Length = %i. Max is %i.\n", in, str_len, max_len);
702 
703  strncpy(out, in, max_len);
704 
705  if (id != NULL)
706  *id = -1;
707 
708  return;
709  }
710 
711  // if the localization file is not open, or we're running in the default language, return the original string
712  if ( !Xstr_inited || (str_id < 0) || (Lcl_current_lang == FS2_OPEN_DEFAULT_LANGUAGE) ) {
713  if ( strlen(text_str) > max_len )
714  error_display(0, "Token too long: [%s]. Length = %i. Max is %i.\n", text_str, strlen(text_str), max_len);
715 
716  strncpy(out, text_str, max_len);
717 
718  if (id != NULL)
719  *id = str_id;
720 
721  return;
722  }
723 
724  // get the string if it exists
725  if ((str_id < LCL_MAX_STRINGS) && (Lcl_ext_str[str_id] != NULL)) {
726  // copy to the outgoing string
727  if ( strlen(Lcl_ext_str[str_id]) > max_len )
728  error_display(0, "Token too long: [%s]. Length = %i. Max is %i.\n", Lcl_ext_str[str_id], strlen(Lcl_ext_str[str_id]), max_len);
729 
730  strncpy(out, Lcl_ext_str[str_id], max_len);
731  }
732  // otherwise use what we have - probably should Int3() or assert here
733  else {
734  if ( strlen(text_str) > max_len )
735  error_display(0, "Token too long: [%s]. Length = %i. Max is %i.\n", text_str, strlen(text_str), max_len);
736 
737  if (str_id >= LCL_MAX_STRINGS)
738  error_display(0, "Invalid XSTR ID: [%d]. (Must be less than %d.)\n", str_id, LCL_MAX_STRINGS);
739 
740  strncpy(out, text_str, max_len);
741  }
742 
743  // set the id #
744  if (id != NULL) {
745  *id = str_id;
746  }
747 }
748 
749 // ditto for SCP_string
750 void lcl_ext_localize_sub(const SCP_string &in, SCP_string &out, int *id)
751 {
752  SCP_string text_str = "";
753  int str_id;
754 
755  // default (non-external string) value
756  if (id != NULL) {
757  *id = -2;
758  }
759 
760  // if the string is < 9 chars, it can't be an XSTR("",) tag, so just copy it
761  if (in.length() < 9) {
762  out = in;
763 
764  if (id != NULL)
765  *id = -2;
766 
767  return;
768  }
769 
770  // otherwise, check to see if it's an XSTR() tag
771  if (in.compare(0, 4, "XSTR")) {
772  // NOT an XSTR() tag
773  out = in;
774 
775  if (id != NULL)
776  *id = -2;
777 
778  return;
779  }
780 
781  // at this point we _know_ its an XSTR() tag, so split off the strings and id sections
782  if (!lcl_ext_get_text(in, text_str)) {
783  out = in;
784 
785  if (id != NULL)
786  *id = -1;
787 
788  return;
789  }
790  if (!lcl_ext_get_id(in, &str_id)) {
791  out = in;
792 
793  if (id != NULL)
794  *id = -1;
795 
796  return;
797  }
798 
799  // if the localization file is not open, or we're running in the default language, return the original string
800  if ( !Xstr_inited || (str_id < 0) || (Lcl_current_lang == FS2_OPEN_DEFAULT_LANGUAGE) ) {
801  out = text_str;
802 
803  if (id != NULL)
804  *id = str_id;
805 
806  return;
807  }
808 
809  // get the string if it exists
810  if ((str_id < LCL_MAX_STRINGS) && (Lcl_ext_str[str_id] != NULL)) {
811  // copy to the outgoing string
812  out = Lcl_ext_str[str_id];
813  }
814  // otherwise use what we have - probably should Int3() or assert here
815  else {
816  if (str_id >= LCL_MAX_STRINGS)
817  error_display(0, "Invalid XSTR ID: [%d]. (Must be less than %d.)\n", str_id, LCL_MAX_STRINGS);
818 
819  out = text_str;
820  }
821 
822  // set the id #
823  if (id != NULL){
824  *id = str_id;
825  }
826 }
827 
828 // Goober5000 - wrapper for lcl_ext_localize_sub; used because lcl_replace_stuff has to
829 // be called *after* the translation is done, and the original function returned in so
830 // many places that it would be messy to call lcl_replace_stuff everywhere
831 void lcl_ext_localize(const char *in, char *out, size_t max_len, int *id)
832 {
833  // do XSTR translation
834  lcl_ext_localize_sub(in, out, max_len, id);
835 
836  // do translation of $callsign, $rank, etc.
837  lcl_replace_stuff(out, max_len);
838 }
839 
840 // ditto for SCP_string
841 void lcl_ext_localize(const SCP_string &in, SCP_string &out, int *id)
842 {
843  // do XSTR translation
844  lcl_ext_localize_sub(in, out, id);
845 
846  // do translation of $callsign, $rank, etc.
847  lcl_replace_stuff(out);
848 }
849 
850 // translate the specified string based upon the current language
851 const char *XSTR(const char *str, int index)
852 {
853  if(!Xstr_inited)
854  {
855  Int3();
856  return str;
857  }
858 
859  // perform a lookup
860  if (index >= 0 && index < XSTR_SIZE)
861  {
862  // return translation of string
863  if (Xstr_table[index].str)
864  return Xstr_table[index].str;
865  }
866 
867  // can't translate; return original english string
868  return str;
869 }
870 
871 // retrieve the offset for a localized string
873 {
874  if (res == GR_640) {
875  return Xstr_table[index].offset_x;
876  } else {
877  return Xstr_table[index].offset_x_hi;
878  }
879 }
880 
881 
882 // ------------------------------------------------------------------------------------------------------------
883 // LOCALIZE FORWARD DEFINITIONS
884 //
885 
886 // given a valid XSTR() tag piece of text, extract the string portion, return it in out, nonzero on success
887 int lcl_ext_get_text(const char *xstr, char *out)
888 {
889  int str_start, str_end;
890  int str_len;
891  const char *p, *p2;
892 
893  Assert(xstr != NULL);
894  Assert(out != NULL);
895  str_len = strlen(xstr);
896 
897  // this is some crazy wack-ass code.
898  // look for the open quote
899  str_start = str_end = 0;
900  p = strstr(xstr, "\"");
901  if(p == NULL){
902  error_display(0, "Error parsing XSTR() tag %s\n", xstr);
903  return 0;
904  } else {
905  str_start = p - xstr + 1;
906  }
907  // make sure we're not about to walk past the end of the string
908  if((p - xstr) >= str_len){
909  error_display(0, "Error parsing XSTR() tag %s\n", xstr);
910  return 0;
911  }
912 
913  // look for the close quote
914  p2 = strstr(p+1, "\"");
915  if(p2 == NULL){
916  error_display(0, "Error parsing XSTR() tag %s\n", xstr);
917  return 0;
918  } else {
919  str_end = p2 - xstr;
920  }
921 
922  // check bounds
923  if (str_end - str_start > PARSE_BUF_SIZE - 1) {
924  error_display(0, "String cannot fit within XSTR buffer!\n\n%s\n", xstr);
925  return 0;
926  }
927 
928  // now that we know the boundaries of the actual string in the XSTR() tag, copy it
929  memcpy(out, xstr + str_start, str_end - str_start);
930 
931  // success
932  return 1;
933 }
934 
935 // given a valid XSTR() tag piece of text, extract the string portion, return it in out, nonzero on success
936 int lcl_ext_get_text(const SCP_string &xstr, SCP_string &out)
937 {
938  size_t open_quote_pos, close_quote_pos;
939 
940  // this is some crazy wack-ass code.
941  // look for the open quote
942  open_quote_pos = xstr.find('\"');
943  if (open_quote_pos == SCP_string::npos) {
944  error_display(0, "Error parsing XSTR() tag %s\n", xstr.c_str());
945  return 0;
946  }
947 
948  // look for the close quote
949  close_quote_pos = xstr.find('\"', open_quote_pos+1);
950  if (close_quote_pos == SCP_string::npos) {
951  error_display(0, "Error parsing XSTR() tag %s\n", xstr.c_str());
952  return 0;
953  }
954 
955  // now that we know the boundaries of the actual string in the XSTR() tag, copy it
956  out.assign(xstr, open_quote_pos + 1, close_quote_pos - open_quote_pos - 1);
957 
958  // success
959  return 1;
960 }
961 
962 // given a valid XSTR() tag piece of text, extract the id# portion, return the value in out, nonzero on success
963 int lcl_ext_get_id(const char *xstr, int *out)
964 {
965  const char *p, *pnext;
966  int str_len;
967 
968  Assert(xstr != NULL);
969  Assert(out != NULL);
970 
971  str_len = strlen(xstr);
972 
973  // find the first quote
974  p = strchr(xstr, '"');
975  if(p == NULL){
976  error_display(0, "Error parsing id# in XSTR() tag %s\n", xstr);
977  return 0;
978  }
979  // make sure we're not about to walk off the end of the string
980  if((p - xstr) >= str_len){
981  error_display(0, "Error parsing id# in XSTR() tag %s\n", xstr);
982  return 0;
983  }
984  p++;
985 
986  // continue searching until we find the close quote
987  while(true){
988  pnext = strchr(p, '"');
989  if(pnext == NULL){
990  error_display(0, "Error parsing id# in XSTR() tag %s\n", xstr);
991  return 0;
992  }
993 
994  // if the previous char is a \, we know its not the "end-of-string" quote
995  if(*(pnext - 1) != '\\'){
996  p = pnext;
997  break;
998  }
999 
1000  // continue
1001  p = pnext;
1002  }
1003 
1004  // search until we find a ,
1005  pnext = strchr(p, ',');
1006  if(pnext == NULL){
1007  error_display(0, "Error parsing id# in XSTR() tag %s\n", xstr);
1008  return 0;
1009  }
1010  // make sure we're not about to walk off the end of the string
1011  if((pnext - xstr) >= str_len){
1012  error_display(0, "Error parsing id# in XSTR() tag %s\n", xstr);
1013  return 0;
1014  }
1015 
1016  // now get the id string
1017  p = pnext+1;
1018  while (is_gray_space(*p))
1019  p++;
1020  pnext = strchr(p+1, ')');
1021  if(pnext == NULL){
1022  error_display(0, "Error parsing id# in XSTR() tag %s\n", xstr);
1023  return 0;
1024  }
1025  if(pnext - p >= PARSE_ID_BUF_SIZE){
1026  error_display(0, "XSTR() id# is too long in %s\n", xstr);
1027  return 0;
1028  }
1029  char buf[PARSE_ID_BUF_SIZE];
1030  strncpy(buf, p, pnext - p);
1031  buf[pnext - p] = 0;
1032 
1033  // get the value and we're done
1034  *out = atoi(buf);
1035 
1036  // success
1037  return 1;
1038 }
1039 
1040 // given a valid XSTR() tag piece of text, extract the id# portion, return the value in out, nonzero on success
1041 int lcl_ext_get_id(const SCP_string &xstr, int *out)
1042 {
1043  char id_buf[10];
1044  size_t p, pnext;
1045 
1046  // find the first quote
1047  p = xstr.find('\"');
1048  if (p == SCP_string::npos) {
1049  error_display(0, "Error parsing id# in XSTR() tag %s\n", xstr.c_str());
1050  return 0;
1051  }
1052  p++;
1053 
1054  // continue searching until we find the close quote
1055  while(1) {
1056  pnext = xstr.find('\"', p);
1057  if (pnext == SCP_string::npos) {
1058  error_display(0, "Error parsing id# in XSTR() tag %s\n", xstr.c_str());
1059  return 0;
1060  }
1061 
1062  // if the previous char is a \, we know its not the "end-of-string" quote
1063  if (xstr[pnext - 1] != '\\') {
1064  p = pnext;
1065  break;
1066  }
1067 
1068  // continue
1069  p = pnext;
1070  }
1071 
1072  // search until we find a ,
1073  pnext = xstr.find(',', p);
1074  if (pnext == SCP_string::npos) {
1075  error_display(0, "Error parsing id# in XSTR() tag %s\n", xstr.c_str());
1076  return 0;
1077  }
1078  pnext++;
1079 
1080  // find the close parenthesis
1081  p = pnext;
1082  pnext = xstr.find(')', p);
1083  if (pnext == SCP_string::npos) {
1084  error_display(0, "Error parsing id# in XSTR() tag %s\n", xstr.c_str());
1085  return 0;
1086  }
1087  pnext--;
1088 
1089  // get only the number
1090  while (is_white_space(xstr[p]) && p <= pnext)
1091  p++;
1092  while (is_white_space(xstr[pnext]) && p <= pnext)
1093  pnext--;
1094  if (p > pnext) {
1095  error_display(0, "Error parsing id# in XSTR() tag %s\n", xstr.c_str());
1096  return 0;
1097  }
1098 
1099  // now get the id string
1100  if ((pnext - p + 1) > 9) {
1101  error_display(0, "Error parsing id# in XSTR() tag %s\n", xstr.c_str());
1102  return 0;
1103  }
1104  memset(id_buf, 0, 10);
1105  xstr.copy(id_buf, pnext - p + 1, p);
1106 
1107  // get the value and we're done
1108  *out = atoi(id_buf);
1109 
1110  // success
1111  return 1;
1112 }
1113 
1114 // if the char is a valid char for a signed integer value
1116 {
1117  return ( (c == '-') || (c == '0') || (c == '1') || (c == '2') || (c == '3') || (c == '4') ||
1118  (c == '5') || (c == '6') || (c == '7') || (c == '8') || (c == '9') ) ? 1 : 0;
1119 }
1120 
1121 void lcl_get_language_name(char *lang_name)
1122 {
1123  Assert(Lcl_current_lang < (int)Lcl_languages.size());
1124 
1125  strcpy(lang_name, Lcl_languages[Lcl_current_lang].lang_name);
1126 }
1127 
1128 // ------------------------------------------------------------------
1129 // lcl_translate_wep_name_gr()
1130 //
1131 // For displaying weapon names in german version
1132 // since we can't actually just change them outright.
1133 //
1135 {
1136  if (!strcmp(name, "Morning Star")) {
1137  strcpy(name, "Morgenstern");
1138  } else if (!strcmp(name, "MorningStar")) {
1139  strcpy(name, "Morgenstern D");
1140  } else if (!strcmp(name, "UD-8 Kayser")) {
1141  strcpy(name, "Kayserstrahl");
1142  } else if (!strcmp(name, "UD-D Kayser")) {
1143  strcpy(name, "Kayserstrahl");
1144  }
1145 }
1146 
1147 // ------------------------------------------------------------------
1148 // lcl_translate_brief_icon_name_gr()
1149 //
1150 // For displaying ship names in german version
1151 // since we can't actually just change them outright.
1152 //
1154 {
1155  char *pos;
1156  char buf[128];
1157 
1158  if (!stricmp(name, "Subspace Portal")) {
1159  strcpy(name, "Subraum Portal");
1160 
1161  } else if (!stricmp(name, "Alpha Wing")) {
1162  strcpy(name, "Alpha");
1163 
1164  } else if (!stricmp(name, "Beta Wing")) {
1165  strcpy(name, "Beta");
1166 
1167  } else if (!stricmp(name, "Zeta Wing")) {
1168  strcpy(name, "Zeta");
1169 
1170  } else if (!stricmp(name, "Capella Node")) {
1171  strcpy(name, "Capella");
1172 
1173  } else if (!stricmp(name, "Hostile")) {
1174  strcpy(name, "Gegner");
1175 
1176  } else if (!stricmp(name, "Hostile Craft")) {
1177  strcpy(name, "Gegner");
1178 
1179  } else if (!stricmp(name, "Rebel Wing")) {
1180  strcpy(name, "Rebellen");
1181 
1182  } else if (!stricmp(name, "Rebel Fleet")) {
1183  strcpy(name, "Rebellenflotte");
1184 
1185  } else if (!stricmp(name, "Sentry Gun")) {
1186  strcpy(name, "Gesch\x81tz");
1187 
1188  } else if (!stricmp(name, "Cargo")) {
1189  strcpy(name, "Fracht");
1190 
1191  } else if (!stricmp(name, "Knossos Device")) {
1192  strcpy(name, "Knossosger\x84t");
1193 
1194  } else if (!stricmp(name, "Support")) {
1195  strcpy(name, "Versorger");
1196 
1197  } else if (!stricmp(name, "Unknown")) {
1198  strcpy(name, "Unbekannt");
1199 
1200  } else if (!stricmp(name, "Instructor")) {
1201  strcpy(name, "Ausbilder");
1202 
1203  } else if (!stricmp(name, "Jump Node")) {
1204  strcpy(name, "Sprungknoten");
1205 
1206  } else if (!stricmp(name, "Escort")) {
1207  strcpy(name, "Geleitschutz");
1208 
1209  } else if (!stricmp(name, "Asteroid Field")) {
1210  strcpy(name, "Asteroidenfeld");
1211 
1212  } else if (!stricmp(name, "Enif Station")) {
1213  strcpy(name, "Station Enif");
1214 
1215  } else if (!stricmp(name, "Rally Point")) {
1216  strcpy(name, "Sammelpunkt");
1217 
1218  } else if ((pos = strstr(name, "Transport")) != NULL) {
1219  pos += 9; // strlen of "transport"
1220  strcpy_s(buf, "Transporter");
1221  strcat_s(buf, pos);
1222  strcpy(name, buf);
1223 
1224  } else if ((pos = strstr(name, "Jump Node")) != NULL) {
1225  pos += 9; // strlen of "jump node"
1226  strcpy_s(buf, "Sprungknoten");
1227  strcat_s(buf, pos);
1228  strcpy(name, buf);
1229 
1230  } else if (!stricmp(name, "Orion under repair")) {
1231  strcpy(name, "Orion wird repariert");
1232 
1233  // SOTY-specific ones below!
1234 
1235  } else if (!stricmp(name, "Wayfarer Station")) {
1236  strcpy(name, "Station Wayfarer");
1237  } else if (!stricmp(name, "Enemy")) {
1238  strcpy(name, "Gegner");
1239  } else if (!stricmp(name, "Supply Depot")) {
1240  strcpy(name, "Nachschubdepot");
1241  } else if (!stricmp(name, "Fighter Escort")) {
1242  strcpy(name, "Jagdschutz");
1243  } else if (!stricmp(name, "Shivans")) {
1244  strcpy(name, "Shivaner");
1245  } else if (!stricmp(name, "NTF Base of Operations")) {
1246  strcpy(name, "NTF-Operationsbasis");
1247  } else if (!stricmp(name, "NTF Bombers")) {
1248  strcpy(name, "NTF-Bomber");
1249  } else if (!stricmp(name, "NTF Fighters")) {
1250  strcpy(name, "NTF-J\x84ger");
1251  } else if (!stricmp(name, "Sentry")) {
1252  strcpy(name, "Sperrgesch\x81tz");
1253  } else if (!stricmp(name, "Cargo Containers")) {
1254  strcpy(name, "Frachtbeh\x84lter");
1255  } else if (!stricmp(name, "NTF Reinforcements")) {
1256  strcpy(name, "NTF-Verst\x84rkungen");
1257  } else if (!stricmp(name, "NTF Base")) {
1258  strcpy(name, "NTF-St\x81tzpunkt");
1259  } else if (!stricmp(name, "Refugee Convoy")) {
1260  strcpy(name, "Fl\x81""chtlingskonvoi");
1261  } else if (!stricmp(name, "Food Convoy")) {
1262  strcpy(name, "Nachschubkonvoi");
1263  } else if (!stricmp(name, "Governor's Shuttle")) {
1264  strcpy(name, "F\x84hre des Gouverneurs");
1265  } else if (!stricmp(name, "GTVA Patrol")) {
1266  strcpy(name, "GTVA-Patrouille");
1267  } else if (!stricmp(name, "Escort fighters")) {
1268  strcpy(name, "Geleitschutz");
1269  } else if (!stricmp(name, "Nagada Outpost")) {
1270  strcpy(name, "Nagada-Aussenposten");
1271  } else if (!stricmp(name, "Fighters")) {
1272  strcpy(name, "J\x84ger");
1273  } else if (!stricmp(name, "Bombers")) {
1274  strcpy(name, "Bomber");
1275  } else if (!stricmp(name, "Enemy Destroyers")) {
1276  strcpy(name, "Feindliche Zerst\x94rer");
1277  } else if (!stricmp(name, "Ross 128 System")) {
1278  strcpy(name, "System Ross 128");
1279  } else if (!stricmp(name, "Knossos Station")) {
1280  strcpy(name, "Knossos-Station");
1281  } else if (!stricmp(name, "Transporters")) {
1282  strcpy(name, "Transporter");
1283  } else if (!stricmp(name, "Pirates?")) {
1284  strcpy(name, "Piraten?");
1285  } else if (!stricmp(name, "Escorts")) {
1286  strcpy(name, "Geleitschutz");
1287  } else if (!stricmp(name, "Shivan Fighters")) {
1288  strcpy(name, "J\x84ger");
1289  } else if (!stricmp(name, "Shivan Territory")) {
1290  strcpy(name, "Shivaner");
1291  }
1292 }
1293 
1294 // ------------------------------------------------------------------
1295 // lcl_translate_brief_icon_name_pl()
1296 //
1297 // For displaying ship names in polish version
1298 // since we can't actually just change them outright.
1299 //
1301 {
1302 char *pos;
1303 char buf[128];
1304 
1305  if (!stricmp(name, "Subspace Portal")) {
1306  strcpy(name, "Portal podprz.");
1307 
1308  } else if (!stricmp(name, "Alpha Wing")) {
1309  strcpy(name, "Alfa");
1310 
1311  } else if (!stricmp(name, "Beta Wing")) {
1312  strcpy(name, "Beta");
1313 
1314  } else if (!stricmp(name, "Zeta Wing")) {
1315  strcpy(name, "Zeta");
1316 
1317  } else if (!stricmp(name, "Capella Node")) {
1318  strcpy(name, "Capella");
1319 
1320  } else if (!stricmp(name, "Hostile")) {
1321  strcpy(name, "Wr\xF3g");
1322 
1323  } else if (!stricmp(name, "Hostile Craft")) {
1324  strcpy(name, "Wr\xF3g");
1325 
1326  } else if (!stricmp(name, "Rebel Wing")) {
1327  strcpy(name, "Rebelianci");
1328 
1329  } else if (!stricmp(name, "Rebel Fleet")) {
1330  strcpy(name, "Flota Rebelii");
1331 
1332  } else if (!stricmp(name, "Sentry Gun")) {
1333  strcpy(name, "Dzia\xB3o str.");
1334 
1335  } else if (!stricmp(name, "Cargo")) {
1336  strcpy(name, "\xA3\x61\x64unek");
1337 
1338  } else if (!stricmp(name, "Knossos Device")) {
1339  strcpy(name, "Urz. Knossos");
1340 
1341  } else if (!stricmp(name, "Support")) {
1342  strcpy(name, "Wsparcie");
1343 
1344  } else if (!stricmp(name, "Unknown")) {
1345  strcpy(name, "Nieznany");
1346 
1347  } else if (!stricmp(name, "Instructor")) {
1348  strcpy(name, "Instruktor");
1349 
1350  } else if (!stricmp(name, "Jump Node")) {
1351  strcpy(name, "W\xEAze\xB3 skokowy");
1352 
1353  } else if (!stricmp(name, "Escort")) {
1354  strcpy(name, "Eskorta");
1355 
1356  } else if (!stricmp(name, "Asteroid Field")) {
1357  strcpy(name, "Pole asteroid");
1358 
1359  } else if (!stricmp(name, "Enif Station")) {
1360  strcpy(name, "Stacja Enif");
1361 
1362  } else if (!stricmp(name, "Rally Point")) {
1363  strcpy(name, "Pkt zborny");
1364 
1365  } else if ((pos = strstr(name, "Transport")) != NULL) {
1366  pos += 9; // strlen of "transport"
1367  strcpy_s(buf, "Transportowiec");
1368  strcat_s(buf, pos);
1369  strcpy(name, buf);
1370 
1371  } else if ((pos = strstr(name, "Jump Node")) != NULL) {
1372  pos += 9; // strlen of "jump node"
1373  strcpy_s(buf, "W\xEAze\xB3 skokowy");
1374  strcat_s(buf, pos);
1375  strcpy(name, buf);
1376 
1377  } else if (!stricmp(name, "Orion under repair")) {
1378  strcpy(name, "Naprawiany Orion");
1379  }
1380 }
1381 
1382 // ------------------------------------------------------------------
1383 // lcl_translate_ship_name_gr()
1384 //
1385 // For displaying ship names in german version in the briefing
1386 // since we can't actually just change them outright.
1387 //
1389 {
1390  if (!strcmp(name, "GTDR Amazon Advanced")) {
1391  strcpy(name, "GTDR Amazon VII");
1392  }
1393 }
1394 
1395 // ------------------------------------------------------------------
1396 // lcl_translate_targetbox_name_gr()
1397 //
1398 // For displaying ship names in german version in the targetbox
1399 // since we can't actually just change them outright.
1400 //
1402 {
1403  char *pos;
1404  char buf[128];
1405 
1406  if ((pos = strstr(name, "Sentry")) != NULL) {
1407  pos += 6; // strlen of "sentry"
1408  strcpy_s(buf, "Sperrgesch\x81tz");
1409  strcat_s(buf, pos);
1410  strcpy(name, buf);
1411 
1412  } else if ((pos = strstr(name, "Support")) != NULL) {
1413  pos += 7; // strlen of "support"
1414  strcpy_s(buf, "Versorger");
1415  strcat_s(buf, pos);
1416  strcpy(name, buf);
1417 
1418  } else if ((pos = strstr(name, "Unknown")) != NULL) {
1419  pos += 7; // strlen of "unknown"
1420  strcpy_s(buf, "Unbekannt");
1421  strcat_s(buf, pos);
1422  strcpy(name, buf);
1423 
1424  } else if ((pos = strstr(name, "Drone")) != NULL) {
1425  pos += 5; // strlen of "drone"
1426  strcpy_s(buf, "Drohne");
1427  strcat_s(buf, pos);
1428  strcpy(name, buf);
1429 
1430  } else if ((pos = strstr(name, "Jump Node")) != NULL) {
1431  pos += 9; // strlen of "jump node"
1432  strcpy_s(buf, "Sprungknoten");
1433  strcat_s(buf, pos);
1434  strcpy(name, buf);
1435 
1436  } else if (!stricmp(name, "Instructor")) {
1437  strcpy(name, "Ausbilder");
1438 
1439  } else if (!stricmp(name, "NTF Vessel")) {
1440  strcpy(name, "NTF-Schiff");
1441 
1442  } else if (!stricmp(name, "Enif Station")) {
1443  strcpy(name, "Station Enif");
1444  }
1445 }
1446 
1447 // ------------------------------------------------------------------
1448 // lcl_translate_targetbox_name_pl()
1449 //
1450 // For displaying ship names in polish version in the targetbox
1451 // since we can't actually just change them outright.
1452 //
1454 {
1455  char *pos;
1456  char buf[128];
1457 
1458  if ((pos = strstr(name, "Sentry")) != NULL) {
1459  pos += 6; // strlen of "sentry"
1460  strcpy_s(buf, "Stra\xBFnik");
1461  strcat_s(buf, pos);
1462  strcpy(name, buf);
1463 
1464  } else if ((pos = strstr(name, "Support")) != NULL) {
1465  pos += 7; // strlen of "support"
1466  strcpy_s(buf, "Wsparcie");
1467  strcat_s(buf, pos);
1468  strcpy(name, buf);
1469 
1470  } else if ((pos = strstr(name, "Unknown")) != NULL) {
1471  pos += 7; // strlen of "unknown"
1472  strcpy_s(buf, "Nieznany");
1473  strcat_s(buf, pos);
1474  strcpy(name, buf);
1475 
1476  } else if ((pos = strstr(name, "Drone")) != NULL) {
1477  pos += 5; // strlen of "drone"
1478  strcpy_s(buf, "Sonda");
1479  strcat_s(buf, pos);
1480  strcpy(name, buf);
1481 
1482  } else if ((pos = strstr(name, "Jump Node")) != NULL) {
1483  pos += 9; // strlen of "jump node"
1484  strcpy_s(buf, "W\xEAze\xB3 skokowy");
1485  strcat_s(buf, pos);
1486  strcpy(name, buf);
1487 
1488  } else if (!stricmp(name, "Instructor")) {
1489  strcpy(name, "Instruktor");
1490 
1491  } else if (!stricmp(name, "NTF Vessel")) {
1492  strcpy(name, "Okr\xEAt NTF");
1493 
1494  } else if (!stricmp(name, "Enif Station")) {
1495  strcpy(name, "Stacja Enif");
1496  }
1497 }
1498 
1499 // this is just a hack to display translated names without actually changing the names,
1500 // which would break stuff
1501 // (this used to be in medals.cpp)
1503 {
1504  if (!strcmp(name, "Epsilon Pegasi Liberation")) {
1505  strcpy(name, "Epsilon Pegasi Befreiungsmedaille");
1506 
1507  } else if (!strcmp(name, "Imperial Order of Vasuda")) {
1508  strcpy(name, "Imperialer Orden von Vasuda ");
1509 
1510  } else if (!strcmp(name, "Distinguished Flying Cross")) {
1511  strcpy(name, "Fliegerkreuz Erster Klasse");
1512 
1513  } else if (!strcmp(name, "SOC Service Medallion")) {
1514  strcpy(name, "SEK-Dienstmedaille ");
1515 
1516  } else if (!strcmp(name, "Intelligence Cross")) {
1517  strcpy(name, "Geheimdienstkreuz am Bande");
1518 
1519  } else if (!strcmp(name, "Order of Galatea")) {
1520  strcpy(name, "Orden von Galatea ");
1521 
1522  } else if (!strcmp(name, "Meritorious Unit Commendation")) {
1523  strcpy(name, "Ehrenspange der Allianz");
1524 
1525  } else if (!strcmp(name, "Medal of Valor")) {
1526  strcpy(name, "Tapferkeitsmedaille ");
1527 
1528  } else if (!strcmp(name, "GTVA Legion of Honor")) {
1529  strcpy(name, "Orden der GTVA-Ehrenlegion");
1530 
1531  } else if (!strcmp(name, "Allied Defense Citation")) {
1532  strcpy(name, "Alliierte Abwehrspange ");
1533 
1534  } else if (!strcmp(name, "Nebula Campaign Victory Star")) {
1535  strcpy(name, "Nebel-Siegesstern");
1536 
1537  } else if (!strcmp(name, "NTF Campaign Victory Star")) {
1538  strcpy(name, "NTF-Siegesstern ");
1539 
1540  } else if (!strcmp(name, "Rank")) {
1541  strcpy(name, "Dienstgrad");
1542 
1543  } else if (!strcmp(name, "Wings")) {
1544  strcpy(name, "Fliegerspange");
1545 
1546  } else if (!strcmp(name, "Ace")) {
1547  strcpy(name, "Flieger-As");
1548 
1549  } else if (!strcmp(name, "Double Ace")) {
1550  strcpy(name, "Doppel-As ");
1551 
1552  } else if (!strcmp(name, "Triple Ace")) {
1553  strcpy(name, "Dreifach-As ");
1554 
1555  } else if (!strcmp(name, "SOC Unit Crest")) {
1556  strcpy(name, "SEK-Abzeichen ");
1557  }
1558 }
1559 
1560 // this is just a hack to display translated names without actually changing the names,
1561 // which would break stuff
1562 // (this used to be in medals.cpp)
1564 {
1565  if (!strcmp(name, "Epsilon Pegasi Liberation")) {
1566  strcpy(name, "Order Wyzwolenia Epsilon Pegasi");
1567 
1568  } else if (!strcmp(name, "Imperial Order of Vasuda")) {
1569  strcpy(name, "Imperialny Order Vasudy");
1570 
1571  } else if (!strcmp(name, "Distinguished Flying Cross")) {
1572  strcpy(name, "Krzy\xBF Wybitnego Pilota");
1573 
1574  } else if (!strcmp(name, "SOC Service Medallion")) {
1575  strcpy(name, "Krzy\xBF S\xB3u\xBF\x62 Specjalnych");
1576 
1577  } else if (!strcmp(name, "Intelligence Cross")) {
1578  strcpy(name, "Krzy\xBF Wywiadu");
1579 
1580  } else if (!strcmp(name, "Order of Galatea")) {
1581  strcpy(name, "Order Galatei");
1582 
1583  } else if (!strcmp(name, "Meritorious Unit Commendation")) {
1584  strcpy(name, "Medal Pochwalny");
1585 
1586  } else if (!strcmp(name, "Medal of Valor")) {
1587  strcpy(name, "Medal za Odwag\xEA");
1588 
1589  } else if (!strcmp(name, "GTVA Legion of Honor")) {
1590  strcpy(name, "Legia Honorowa GTVA");
1591 
1592  } else if (!strcmp(name, "Allied Defense Citation")) {
1593  strcpy(name, "Order za Obron\xEA Sojuszu");
1594 
1595  } else if (!strcmp(name, "Nebula Campaign Victory Star")) {
1596  strcpy(name, "Gwiazda Wiktorii Kampanii w Mg\xB3\x61wicy");
1597 
1598  } else if (!strcmp(name, "NTF Campaign Victory Star")) {
1599  strcpy(name, "Gwiazda Wiktorii Kampanii NTF");
1600 
1601  } else if (!strcmp(name, "Rank")) {
1602  strcpy(name, "Ranga");
1603 
1604  } else if (!strcmp(name, "Wings")) {
1605  strcpy(name, "Skrzyd\xB3\x61");
1606 
1607  } else if (!strcmp(name, "Ace")) {
1608  strcpy(name, "As");
1609 
1610  } else if (!strcmp(name, "Double Ace")) {
1611  strcpy(name, "Podw\xF3jny As");
1612 
1613  } else if (!strcmp(name, "Triple Ace")) {
1614  strcpy(name, "Potr\xF3jny As");
1615 
1616  } else if (!strcmp(name, "SOC Unit Crest")) {
1617  strcpy(name, "Tarcza S\xB3u\xBF\x62 Specjalnych");
1618  }
1619 }
#define LCL_MAX_STRINGS
Definition: localize.cpp:79
void lcl_translate_brief_icon_name_gr(char *name)
Definition: localize.cpp:1153
int i
Definition: multi_pxo.cpp:466
#define vm_free(ptr)
Definition: pstypes.h:548
#define PARSE_BUF_SIZE
Definition: parselo.h:47
char * Lcl_ext_str[LCL_MAX_STRINGS]
Definition: localize.cpp:80
int check_for_string(const char *pstr)
Definition: parselo.cpp:517
void drop_trailing_white_space(char *str)
Definition: parselo.cpp:93
GLuint index
Definition: Glext.h:5608
void lcl_translate_medal_name_gr(char *name)
Definition: localize.cpp:1502
int Xstr_inited
Definition: localize.cpp:73
int Fred_running
Definition: fred.cpp:44
void lcl_xstr_init()
Definition: localize.cpp:408
int replace_all(char *str, char *oldstr, char *newstr, uint max_len, int range)
Definition: parselo.cpp:3941
ubyte special_char_indexes[MAX_FONTS]
Definition: localize.h:37
void _cdecl void void _cdecl void _cdecl Warning(char *filename, int line, SCP_FORMAT_STRING const char *format,...) SCP_FORMAT_STRING_ARGS(3
Assert(pm!=NULL)
#define FS2_OPEN_DEFAULT_LANGUAGE
Definition: localize.h:28
SCP_vector< lang_info > Lcl_languages
Definition: localize.cpp:32
#define mprintf(args)
Definition: pstypes.h:238
char lang_name[LCL_LANG_NAME_LEN+1]
Definition: localize.h:35
#define DIR_SEPARATOR_CHAR
Definition: pstypes.h:43
void lcl_add_dir(char *current_path)
Definition: localize.cpp:504
int lcl_get_xstr_offset(int index, int res)
Definition: localize.cpp:872
int Lcl_pl
Definition: localize.cpp:49
const char * str
Definition: localize.cpp:66
void lcl_init(int lang_init)
Definition: localize.cpp:107
#define Assertion(expr, msg,...)
Definition: clang.h:41
const char * os_config_read_string(const char *section, const char *name, const char *default_value)
Definition: osregistry.cpp:322
std::basic_string< char, std::char_traits< char >, std::allocator< char > > SCP_string
Definition: vmallocator.h:21
void encrypt_init()
Definition: encrypt.cpp:453
#define Int3()
Definition: pstypes.h:292
int required_string_either(char *str1, char *str2)
Checks for one of two required strings.
Definition: parselo.cpp:673
GLuint in
Definition: Glext.h:9087
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: Glext.h:7308
char callsign[CALLSIGN_LEN+1]
Definition: player.h:91
int lcl_ext_get_id(const char *xstr, int *out)
Definition: localize.cpp:963
#define NUM_BUILTIN_LANGUAGES
Definition: localize.h:44
int lcl_add_dir_to_path_with_filename(char *current_path, size_t path_max)
Definition: localize.cpp:536
void parse_stringstbl(const char *filename)
Definition: localize.cpp:397
typedef int(SCP_EXT_CALLCONV *SCPDLL_PFVERSION)(SCPDLL_Version *)
#define nprintf(args)
Definition: pstypes.h:239
lcl_xstr Xstr_table[XSTR_SIZE]
Definition: localize.cpp:72
#define DIR_SEPARATOR_STR
Definition: pstypes.h:44
char * filename
#define strnicmp(s1, s2, n)
Definition: config.h:272
#define MAX_FONTS
Definition: font.h:17
void stuff_string(char *outstr, int type, int len, char *terminators)
Definition: parselo.cpp:1189
void parse_stringstbl_common(const char *filename, const bool external)
Definition: localize.cpp:231
#define CF_TYPE_TABLES
Definition: cfile.h:50
#define LCL_GERMAN
Definition: localize.h:24
#define LCL_ENGLISH
Definition: localize.h:23
GLdouble GLdouble z
Definition: Glext.h:5451
void lcl_translate_targetbox_name_gr(char *name)
Definition: localize.cpp:1401
#define GR_640
Definition: 2d.h:652
#define vm_strdup(ptr)
Definition: pstypes.h:549
int required_string(const char *pstr)
Definition: parselo.cpp:468
void lcl_replace_stuff(char *text, size_t max_len)
Definition: localize.cpp:573
int optional_string(const char *pstr)
Definition: parselo.cpp:539
#define PARSE_ID_BUF_SIZE
Definition: localize.cpp:78
int offset_x_hi
Definition: localize.cpp:68
void read_file_text(const char *filename, int mode, char *processed_text, char *raw_text)
Definition: parselo.cpp:1995
bool Parsing_modular_table
Definition: parselo.cpp:34
int idx
Definition: multiui.cpp:761
int get_string(char *str, int max)
Definition: parselo.cpp:1157
unsigned char ubyte
Definition: pstypes.h:62
#define LCL_POLISH
Definition: localize.h:26
#define XSTR_SIZE
Definition: localize.cpp:60
int lcl_ext_get_text(const char *xstr, char *out)
Definition: localize.cpp:887
#define NOX(s)
Definition: pstypes.h:473
void _cdecl void void _cdecl Error(const char *filename, int line, SCP_FORMAT_STRING const char *format,...) SCP_FORMAT_STRING_ARGS(3
ubyte lcl_get_font_index(int font_num)
Definition: localize.cpp:495
const char * XSTR(const char *str, int index)
Definition: localize.cpp:851
void reset_parse(char *text)
Definition: parselo.cpp:3305
GLuint const GLchar * name
Definition: Glext.h:5608
int offset_x
Definition: localize.cpp:67
void stuff_int(int *i)
Definition: parselo.cpp:2372
void lcl_translate_ship_name_gr(char *name)
Definition: localize.cpp:1388
int lcl_get_language()
Definition: localize.cpp:176
#define strcat_s(...)
Definition: safe_strings.h:68
player * Player
int Lcl_current_lang
Definition: localize.cpp:31
void lcl_xstr_close()
Definition: localize.cpp:449
int lcl_is_valid_numeric_char(char c)
Definition: localize.cpp:1115
GLfloat GLfloat p
Definition: Glext.h:8373
void parse_stringstbl_quick(const char *filename)
Definition: localize.cpp:182
#define LCL_LANG_NAME_LEN
Definition: localize.h:31
#define LOCATION
Definition: pstypes.h:245
int Lcl_english
Definition: localize.cpp:50
lang_info Lcl_builtin_languages[NUM_BUILTIN_LANGUAGES]
Definition: localize.cpp:36
hull_check pos
Definition: lua.cpp:5050
void error_display(int error_level, char *format,...)
Definition: parselo.cpp:308
void ignore_white_space()
Definition: parselo.cpp:77
int is_gray_space(char ch)
Definition: parselo.cpp:65
void lcl_translate_brief_icon_name_pl(char *name)
Definition: localize.cpp:1300
#define FONT3
Definition: font.h:67
rank_stuff Ranks[NUM_RANKS]
Definition: scoring.cpp:45
void lcl_ext_localize_sub(const char *in, char *out, size_t max_len, int *id)
Definition: localize.cpp:644
int parse_modular_table(const char *name_check, void(*parse_callback)(const char *filename), int path_type, int sort_type)
Definition: parselo.cpp:4205
GLenum GLsizei len
Definition: Glext.h:6283
char lang_ext[LCL_LANG_NAME_LEN+1]
Definition: localize.h:36
int temp
Definition: lua.cpp:4996
void stuff_ubyte(ubyte *i)
Definition: parselo.cpp:2646
#define LCL_FRENCH
Definition: localize.h:25
int is_white_space(char ch)
Definition: parselo.cpp:59
int Lcl_special_chars
Definition: localize.cpp:43
void lcl_ext_localize(const char *in, char *out, size_t max_len, int *id)
Definition: localize.cpp:831
int Lcl_fr
Definition: localize.cpp:47
void parse_tstringstbl(const char *filename)
Definition: localize.cpp:402
void lcl_fred_replace_stuff(char *text, size_t max_len)
Definition: localize.cpp:610
void lcl_translate_wep_name_gr(char *name)
Definition: localize.cpp:1134
void lcl_translate_medal_name_pl(char *name)
Definition: localize.cpp:1563
#define stricmp(s1, s2)
Definition: config.h:271
int skip_to_string(char *pstr, char *end)
Definition: parselo.cpp:375
void lcl_translate_targetbox_name_pl(char *name)
Definition: localize.cpp:1453
const GLubyte * c
Definition: Glext.h:8376
int Lcl_gr
Definition: localize.cpp:48
void lcl_get_language_name(char *lang_name)
Definition: localize.cpp:1121
GLuint res
Definition: Glext.h:9084
#define F_RAW
Definition: parselo.h:44
scoring_struct stats
Definition: player.h:127
#define strcpy_s(...)
Definition: safe_strings.h:67
char name[NAME_LENGTH]
Definition: scoring.h:66
void lcl_set_language(int lang)
Definition: localize.cpp:470