summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorrubidium <rubidium@openttd.org>2007-03-17 22:21:05 +0000
committerrubidium <rubidium@openttd.org>2007-03-17 22:21:05 +0000
commit7fb3b4f83e9348c87924dd258afdb51a724467b7 (patch)
treec3c942e6a51b78268b05e750417a6ee0b7118f2b /src
parentabf601a1eff12888b282e8278fce26edb18fcb2f (diff)
downloadopenttd-7fb3b4f83e9348c87924dd258afdb51a724467b7.tar.xz
(svn r9271) -Codechange: make the language pack initialisation a little more clear and extendable (more language paths).
Diffstat (limited to 'src')
-rw-r--r--src/fileio.cpp1
-rw-r--r--src/functions.h2
-rw-r--r--src/strings.cpp200
-rw-r--r--src/strings.h3
-rw-r--r--src/variables.h23
5 files changed, 140 insertions, 89 deletions
diff --git a/src/fileio.cpp b/src/fileio.cpp
index 3e718e6da..a578d05fe 100644
--- a/src/fileio.cpp
+++ b/src/fileio.cpp
@@ -362,6 +362,7 @@ void DeterminePaths(const char *exe)
/* Sets the search path for lng files to the custom one */
_paths.lang_dir = MallocT<char>(MAX_PATH);
ttd_strlcpy(_paths.lang_dir, CUSTOM_LANG_DIR, MAX_PATH);
+ AppendPathSeparator(_paths.lang_dir, MAX_PATH);
#else
_paths.lang_dir = str_fmt("%slang" PATHSEP, _paths.game_data_dir);
#endif
diff --git a/src/functions.h b/src/functions.h
index 2fb154b7f..2d3bcc998 100644
--- a/src/functions.h
+++ b/src/functions.h
@@ -205,8 +205,6 @@ void ShowSaveLoadDialog(int mode);
/* callback from drivers that is called if the game size changes dynamically */
void GameSizeChanged();
bool FileExists(const char *filename);
-bool ReadLanguagePack(int index);
-void InitializeLanguagePacks();
const char *GetCurrentLocale(const char *param);
void *ReadFileToMem(const char *filename, size_t *lenp, size_t maxsize);
diff --git a/src/strings.cpp b/src/strings.cpp
index 0dd6fcad8..fd4b5b0f8 100644
--- a/src/strings.cpp
+++ b/src/strings.cpp
@@ -27,6 +27,7 @@
/* for opendir/readdir/closedir */
# include "fios.h"
+DynamicLanguages _dynlang;
char _userstring[128];
static char *StationGetSpecialString(char *buff, int x, const char* last);
@@ -1068,16 +1069,12 @@ StringID RemapOldStringID(StringID s)
bool ReadLanguagePack(int lang_index)
{
int tot_count, i;
- LanguagePack *lang_pack;
size_t len;
char **langpack_offs;
char *s;
- {
- char *lang = str_fmt("%s%s", _paths.lang_dir, _dynlang.ent[lang_index].file);
- lang_pack = (LanguagePack*)ReadFileToMem(lang, &len, 200000);
- free(lang);
- }
+ LanguagePack *lang_pack = (LanguagePack*)ReadFileToMem(_dynlang.ent[lang_index].file, &len, 200000);
+
if (lang_pack == NULL) return false;
if (len < sizeof(LanguagePack) ||
lang_pack->ident != TO_LE32(LANGUAGE_PACK_IDENT) ||
@@ -1119,7 +1116,7 @@ bool ReadLanguagePack(int lang_index)
free(_langpack_offs);
_langpack_offs = langpack_offs;
- ttd_strlcpy(_dynlang.curr_file, _dynlang.ent[lang_index].file, sizeof(_dynlang.curr_file));
+ ttd_strlcpy(_dynlang.curr_file, _dynlang.ent[lang_index].file, lengthof(_dynlang.curr_file));
_dynlang.curr = lang_index;
SetCurrentGrfLangID(_langpack->isocode);
@@ -1152,96 +1149,145 @@ const char *GetCurrentLocale(const char *param)
static int CDECL LanguageCompareFunc(const void *a, const void *b)
{
- return strcmp(*(const char* const *)a, *(const char* const *)b);
+ const Language *cmp1 = (const Language*)a;
+ const Language *cmp2 = (const Language*)b;
+
+ return strcmp(cmp1->file, cmp2->file);
+}
+
+/**
+ * Checks whether the given language is already found.
+ * @param langs languages we've found so fa
+ * @param max the length of the language list
+ * @param language name of the language to check
+ * @return true if and only if a language file with the same name has not been found
+ */
+static bool UniqueLanguageFile(const Language *langs, uint max, const char *language)
+{
+ for (uint i = 0; i < max; i++) {
+ const char *f_name = strrchr(langs[i].file, PATHSEPCHAR);
+ if (strcmp(f_name, language) == 0) return false; // duplicates
+ }
+
+ return true;
+}
+
+/**
+ * Reads the language file header and checks compatability.
+ * @param file the file to read
+ * @param hdr the place to write the header information to
+ * @return true if and only if the language file is of a compatible version
+ */
+static bool GetLanguageFileHeader(const char *file, LanguagePack *hdr)
+{
+ FILE *f = fopen(file, "rb");
+ if (f == NULL) return false;
+
+ size_t read = fread(hdr, sizeof(*hdr), 1, f);
+ fclose(f);
+
+ return read == 1 &&
+ hdr->ident == TO_LE32(LANGUAGE_PACK_IDENT) &&
+ hdr->version == TO_LE32(LANGUAGE_PACK_VERSION);
}
-static int GetLanguageList(char **languages, int max)
+/**
+ * Gets a list of languages from the given directory.
+ * @param langs the list to write to
+ * @param start the initial offset in the list
+ * @param max the length of the language list
+ * @param path the base directory to search in
+ * @return the number of added languages
+ */
+static int GetLanguageList(Language *langs, int start, int max, const char *path)
{
- DIR *dir;
- struct dirent *dirent;
- int num = 0;
+ int i = start;
- dir = ttd_opendir(_paths.lang_dir);
+ DIR *dir = ttd_opendir(path);
if (dir != NULL) {
- while ((dirent = readdir(dir)) != NULL) {
- const char *d_name = FS2OTTD(dirent->d_name);
- const char *t = strrchr(d_name, '.');
+ struct dirent *dirent;
+ while ((dirent = readdir(dir)) != NULL && i < max) {
+ const char *d_name = FS2OTTD(dirent->d_name);
+ const char *extension = strrchr(d_name, '.');
- if (t != NULL && strcmp(t, ".lng") == 0) {
- languages[num++] = strdup(d_name);
- if (num == max) break;
+ /* Not a language file */
+ if (extension == NULL || strcmp(extension, ".lng") != 0) continue;
+
+ /* Filter any duplicate language-files, first-come first-serve */
+ if (!UniqueLanguageFile(langs, i, d_name)) continue;
+
+ langs[i].file = str_fmt("%s%s", path, d_name);
+
+ /* Check whether the file is of the correct version */
+ LanguagePack hdr;
+ if (!GetLanguageFileHeader(langs[i].file, &hdr)) {
+ free(langs[i].file);
+ continue;
}
+
+ i++;
}
closedir(dir);
}
-
- qsort(languages, num, sizeof(char*), LanguageCompareFunc);
- return num;
+ return i - start;
}
-// make a list of the available language packs. put the data in _dynlang struct.
+/**
+ * Make a list of the available language packs. put the data in
+ * _dynlang struct.
+ */
void InitializeLanguagePacks()
{
- DynamicLanguages *dl = &_dynlang;
- int i;
- int n;
- int m;
- int def;
- int def2;
- int fallback;
- LanguagePack hdr;
- FILE *in;
- char *files[MAX_LANG];
- const char* lang;
-
- lang = GetCurrentLocale("LC_MESSAGES");
- if (lang == NULL) lang = "en_GB";
+ Language files[MAX_LANG];
+ uint language_count = GetLanguageList(files, 0, lengthof(files), _paths.lang_dir);
+ if (language_count == 0) error("No available language packs (invalid versions?)");
- n = GetLanguageList(files, lengthof(files));
-
- def = -1;
- def2 = -1;
- fallback = 0;
-
- // go through the language files and make sure that they are valid.
- for (i = m = 0; i != n; i++) {
- size_t j;
-
- char *s = str_fmt("%s%s", _paths.lang_dir, files[i]);
- in = fopen(s, "rb");
- free(s);
- if (in == NULL ||
- (j = fread(&hdr, sizeof(hdr), 1, in), fclose(in), j) != 1 ||
- hdr.ident != TO_LE32(LANGUAGE_PACK_IDENT) ||
- hdr.version != TO_LE32(LANGUAGE_PACK_VERSION)) {
- free(files[i]);
- continue;
- }
+ /* Sort the language names alphabetically */
+ qsort(files, language_count, sizeof(Language), LanguageCompareFunc);
- dl->ent[m].file = files[i];
- dl->ent[m].name = strdup(hdr.name);
+ /* Acquire the locale of the current system */
+ const char *lang = GetCurrentLocale("LC_MESSAGES");
+ if (lang == NULL) lang = "en_GB";
- if (strcmp(hdr.isocode, "en_GB") == 0) fallback = m;
- if (strncmp(hdr.isocode, lang, 2) == 0) def2 = m;
- if (strncmp(hdr.isocode, lang, 5) == 0) def = m;
+ int chosen_language = -1; ///< Matching the language in the configuartion file or the current locale
+ int language_fallback = -1; ///< Using pt_PT for pt_BR locale when pt_BR is not available
+ int en_GB_fallback = 0; ///< Fallback when no locale-matching language has been found
- m++;
- }
- if (def == -1) def = (def2 != -1 ? def2 : fallback);
+ DynamicLanguages *dl = &_dynlang;
+ dl->num = 0;
+ /* Fill the dynamic languages structures */
+ for (uint i = 0; i < language_count; i++) {
+ /* File read the language header */
+ LanguagePack hdr;
+ if (!GetLanguageFileHeader(files[i].file, &hdr)) continue;
+
+ dl->ent[dl->num].file = files[i].file;
+ dl->ent[dl->num].name = strdup(hdr.name);
+ dl->dropdown[dl->num] = SPECSTR_LANGUAGE_START + dl->num;
+
+ /* We are trying to find a default language. The priority is by
+ * configuration file, local environment and last, if nothing found,
+ * english. If def equals -1, we have not picked a default language */
+ if (strcmp(dl->ent[dl->num].file, dl->curr_file) == 0) chosen_language = dl->num;
+
+ if (chosen_language == -1) {
+ if (strcmp (hdr.isocode, "en_GB") == 0) en_GB_fallback = dl->num;
+ if (strncmp(hdr.isocode, lang, 5) == 0) chosen_language = dl->num;
+ if (strncmp(hdr.isocode, lang, 2) == 0) language_fallback = dl->num;
+ }
- if (m == 0)
- error(n == 0 ? "No available language packs" : "Invalid version of language packs");
+ dl->num++;
+ }
+ /* Terminate the dropdown list */
+ dl->dropdown[dl->num] = INVALID_STRING_ID;
- dl->num = m;
- for (i = 0; i != dl->num; i++) dl->dropdown[i] = SPECSTR_LANGUAGE_START + i;
- dl->dropdown[i] = INVALID_STRING_ID;
+ if (dl->num == 0) error("Invalid version of language packs");
- for (i = 0; i != dl->num; i++)
- if (strcmp(dl->ent[i].file, dl->curr_file) == 0) {
- def = i;
- break;
- }
+ /* We haven't found the language in the config nor the one in the locale.
+ * Now we set it to one of the fallback languages */
+ if (chosen_language == -1) {
+ chosen_language = (language_fallback != -1) ? language_fallback : en_GB_fallback;
+ }
- if (!ReadLanguagePack(def))
- error("can't read language pack '%s'", dl->ent[def].file);
+ if (!ReadLanguagePack(chosen_language)) error("Can't read language pack '%s'", dl->ent[chosen_language].file);
}
diff --git a/src/strings.h b/src/strings.h
index fb2c3ed88..56893346c 100644
--- a/src/strings.h
+++ b/src/strings.h
@@ -11,4 +11,7 @@ extern char _userstring[128];
void InjectDParam(int amount);
int32 GetParamInt32();
+bool ReadLanguagePack(int index);
+void InitializeLanguagePacks();
+
#endif /* STRINGS_H */
diff --git a/src/variables.h b/src/variables.h
index ef5e9b73c..7f8771a87 100644
--- a/src/variables.h
+++ b/src/variables.h
@@ -315,19 +315,22 @@ VARDEF Vehicle *_place_clicked_vehicle;
VARDEF char _ini_videodriver[32], _ini_musicdriver[32], _ini_sounddriver[32];
-// Used for dynamic language support
+/** Information about a language */
+struct Language {
+ char *name; ///< The internal name of the language
+ char *file; ///< The name of the language as it appears on disk
+};
+
+/** Used for dynamic language support */
struct DynamicLanguages {
- int num; // number of languages
- int curr; // currently selected language index
- char curr_file[MAX_LANG]; // currently selected language file
- StringID dropdown[MAX_LANG + 1]; // used in settings dialog
- struct {
- char *name;
- char *file;
- } ent[MAX_LANG];
+ int num; ///< Number of languages
+ int curr; ///< Currently selected language index
+ char curr_file[MAX_PATH]; ///< Currently selected language file (needed for saving the filename of the loaded language
+ StringID dropdown[MAX_LANG + 1]; ///< List of languages in the settings gui
+ Language ent[MAX_LANG]; ///< Information about the languages
};
-VARDEF DynamicLanguages _dynlang;
+extern DynamicLanguages _dynlang; // defined in strings.cpp
VARDEF int _num_resolutions;
VARDEF uint16 _resolutions[32][2];