From d43bc73e763ed133fc625c25415b3c42ffb4f0f6 Mon Sep 17 00:00:00 2001 From: Kevin Date: Wed, 18 Nov 2015 17:33:54 +0100 Subject: [PATCH 1/5] [Linux] Implement platform_get_locale_language. --- src/platform/posix.c | 92 ++++++++++++++++++++++++-------------------- 1 file changed, 50 insertions(+), 42 deletions(-) diff --git a/src/platform/posix.c b/src/platform/posix.c index 98cffb1bd7..52e57f9e31 100644 --- a/src/platform/posix.c +++ b/src/platform/posix.c @@ -35,6 +35,7 @@ #include "../util/util.h" #include #include +#include #include // The name of the mutex used to prevent multiple instances of the game from running @@ -629,51 +630,58 @@ utf8 *platform_open_directory_browser(utf8 *title) } uint16 platform_get_locale_language(){ - /* - CHAR langCode[4]; + const char *langString = setlocale(LC_MESSAGES, ""); + if(langString != NULL){ + // The locale has the following form: + // language[_territory[.codeset]][@modifier] (see https://www.gnu.org/software/libc/manual/html_node/Locale-Names.html) + char pattern[32]; // longest on my system is 29 with codeset and modifier, so 32 for the pattern should be more than enough + //strip the codeset and modifier part + int length = strlen(langString); + { + for(int i = 0; i < length; ++i){ + if(langString[i] == '.' || langString[i] == '@'){ + length = i; + break; + } + } + } //end strip + strncpy(pattern,langString, length); //copy all until first '.' or '@' + pattern[length] = '\0'; + //find _ if present + const char *strip = strchr(pattern, '_'); + if(strip != NULL){ + pattern[strip - pattern] = '?'; // could also use '-', but '?' is more flexible. Maybe LanguagesDescriptors will change. pattern is now "language?territory" + } - if (GetLocaleInfo(LOCALE_USER_DEFAULT, - LOCALE_SABBREVLANGNAME, - (LPSTR)&langCode, - sizeof(langCode)) == 0){ - return LANGUAGE_UNDEFINED; - } + // Iterate through all available languages + for(int i = 1; i < LANGUAGE_COUNT; ++i){ + if(!fnmatch(pattern, LanguagesDescriptors[i].locale, 0)){ + return i; + } + } - if (strcmp(langCode, "ENG") == 0){ - return LANGUAGE_ENGLISH_UK; + //special cases :( + if(!fnmatch(pattern, "en_CA", 0)){ + return LANGUAGE_ENGLISH_US; + } + else if (!fnmatch(pattern, "zn_CA", 0)){ + return LANGUAGE_CHINESE_SIMPLIFIED; + } + else if (!fnmatch(pattern, "zn_TW", 0)){ + return LANGUAGE_CHINESE_TRADITIONAL; + } + + //no exact match found trying only language part + if(strip != NULL){ + pattern[strip - pattern] = '*'; + pattern[strip - pattern +1] = '\0'; // pattern is now "language*" + for(int i = 1; i < LANGUAGE_COUNT; ++i){ + if(!fnmatch(pattern, LanguagesDescriptors[i].locale, 0)){ + return i; + } + } + } } - else if (strcmp(langCode, "ENU") == 0){ - return LANGUAGE_ENGLISH_US; - } - else if (strcmp(langCode, "DEU") == 0){ - return LANGUAGE_GERMAN; - } - else if (strcmp(langCode, "NLD") == 0){ - return LANGUAGE_DUTCH; - } - else if (strcmp(langCode, "FRA") == 0){ - return LANGUAGE_FRENCH; - } - else if (strcmp(langCode, "HUN") == 0){ - return LANGUAGE_HUNGARIAN; - } - else if (strcmp(langCode, "PLK") == 0){ - return LANGUAGE_POLISH; - } - else if (strcmp(langCode, "ESP") == 0){ - return LANGUAGE_SPANISH; - } - else if (strcmp(langCode, "SVE") == 0){ - return LANGUAGE_SWEDISH; - } - else if (strcmp(langCode, "ITA") == 0){ - return LANGUAGE_ITALIAN; - } - else if (strcmp(langCode, "POR") == 0){ - return LANGUAGE_PORTUGUESE_BR; - } - */ - STUB(); return LANGUAGE_ENGLISH_UK; } From 3ece04dc8d46fec270af5f5e1107d942e379254d Mon Sep 17 00:00:00 2001 From: Kevin Date: Fri, 20 Nov 2015 17:29:36 +0100 Subject: [PATCH 2/5] [Linux] Implement platform_get_locale_measurement_format and platform_get_locale_temperature_format --- src/platform/posix.c | 40 ++++++++++------------------------------ 1 file changed, 10 insertions(+), 30 deletions(-) diff --git a/src/platform/posix.c b/src/platform/posix.c index 52e57f9e31..9c2fa98f2e 100644 --- a/src/platform/posix.c +++ b/src/platform/posix.c @@ -739,44 +739,24 @@ uint8 platform_get_locale_currency(){ } uint8 platform_get_locale_measurement_format(){ - /* - UINT measurement_system; - if (GetLocaleInfo(LOCALE_USER_DEFAULT, - LOCALE_IMEASURE | LOCALE_RETURN_NUMBER, - (LPSTR)&measurement_system, - sizeof(measurement_system)) == 0){ + //FIXME: LC_MEASUREMENT is GNU specific. + const char *langstring = setlocale(LC_MEASUREMENT, ""); + + //using https://en.wikipedia.org/wiki/Metrication#Chronology_and_status_of_conversion_by_country as reference + if(!fnmatch("*_US*", langstring, 0) || !fnmatch("*_MM*", langstring, 0) || !fnmatch("*_LR*", langstring, 0)){ return MEASUREMENT_FORMAT_IMPERIAL; } - switch (measurement_system){ - case 0: - return MEASUREMENT_FORMAT_METRIC; - case 1: - default: - return MEASUREMENT_FORMAT_IMPERIAL; - }*/ - STUB(); + return MEASUREMENT_FORMAT_METRIC; } uint8 platform_get_locale_temperature_format(){ - /* - // There does not seem to be a function to obtain this, just check the countries - UINT country; - if (GetLocaleInfo(LOCALE_USER_DEFAULT, - LOCALE_IMEASURE | LOCALE_RETURN_NUMBER, - (LPSTR)&country, - sizeof(country)) == 0){ - return TEMPERATURE_FORMAT_C; - } - switch (country){ - case CTRY_UNITED_STATES: - case CTRY_BELIZE: + const char *langstring = setlocale(LC_MEASUREMENT, ""); + + if(!fnmatch("*_US*", langstring, 0) || !fnmatch("*_BS*", langstring, 0) || !fnmatch("*_BZ*", langstring, 0) || !fnmatch("*_PW*", langstring, 0)){ return TEMPERATURE_FORMAT_F; - default: - return TEMPERATURE_FORMAT_C; } - */ - STUB(); + return TEMPERATURE_FORMAT_C; } From b4907ba70c63ea04b71b05a21200669b86e59bad Mon Sep 17 00:00:00 2001 From: Kevin Date: Sat, 21 Nov 2015 14:30:01 +0100 Subject: [PATCH 3/5] [Linux] Implement platform_get_locale_currency. Fix Chinese language codes. --- src/platform/posix.c | 55 +++++++++++++------------------------------- 1 file changed, 16 insertions(+), 39 deletions(-) diff --git a/src/platform/posix.c b/src/platform/posix.c index 9c2fa98f2e..27e96bb23a 100644 --- a/src/platform/posix.c +++ b/src/platform/posix.c @@ -664,10 +664,10 @@ uint16 platform_get_locale_language(){ if(!fnmatch(pattern, "en_CA", 0)){ return LANGUAGE_ENGLISH_US; } - else if (!fnmatch(pattern, "zn_CA", 0)){ + else if (!fnmatch(pattern, "zh_CN", 0)){ return LANGUAGE_CHINESE_SIMPLIFIED; } - else if (!fnmatch(pattern, "zn_TW", 0)){ + else if (!fnmatch(pattern, "zh_TW", 0)){ return LANGUAGE_CHINESE_TRADITIONAL; } @@ -694,47 +694,24 @@ time_t platform_file_get_modified_time(const utf8* path){ } uint8 platform_get_locale_currency(){ - /* - CHAR currCode[4]; + char *langstring = setlocale(LC_MONETARY, ""); + struct lconv *lc = localeconv(); - if (GetLocaleInfo(LOCALE_USER_DEFAULT, - LOCALE_SINTLSYMBOL, - (LPSTR)&currCode, - sizeof(currCode)) == 0){ - return CURRENCY_POUNDS; + //Only works if g_currency_specs contains the actual (local) symbol + for(int i = 0; i < CURRENCY_END; ++i){ + if(!strcmp(lc->currency_symbol, g_currency_specs[i].symbol)){ + return i; + } } - if (strcmp(currCode, "GBP") == 0){ - return CURRENCY_POUNDS; + //TODO: can be removed when g_currency_specs contains the actual symbols for won and rubel + if(!strncmp(lc->int_curr_symbol, "KRW", 3)){ + return CURRENCY_WON; } - else if (strcmp(currCode, "USD") == 0){ - return CURRENCY_DOLLARS; + else if(!strncmp(lc->int_curr_symbol, "RUB", 3)){ + return CURRENCY_ROUBLE; } - else if (strcmp(currCode, "EUR") == 0){ - return CURRENCY_EUROS; - } - else if (strcmp(currCode, "SEK") == 0){ - return CURRENCY_KRONA; - } - else if (strcmp(currCode, "DEM") == 0){ - return CURRENCY_DEUTSCHMARK; - } - else if (strcmp(currCode, "ITL") == 0){ - return CURRENCY_LIRA; - } - else if (strcmp(currCode, "JPY") == 0){ - return CURRENCY_YEN; - } - else if (strcmp(currCode, "ESP") == 0){ - return CURRENCY_PESETA; - } - else if (strcmp(currCode, "FRF") == 0){ - return CURRENCY_FRANC; - } - else if (strcmp(currCode, "NLG") == 0){ - return CURRENCY_GUILDERS; - } - */ - STUB(); + + //All other currencies are historic return CURRENCY_POUNDS; } From c0f7b0b1f325fa8357d42eb0fccaccae7e53b995 Mon Sep 17 00:00:00 2001 From: Kevin Date: Fri, 27 Nov 2015 22:47:59 +0100 Subject: [PATCH 4/5] [Linux] Fix platform_get_locale_currency with new ascii fallback --- src/platform/posix.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/platform/posix.c b/src/platform/posix.c index 27e96bb23a..b31f96198a 100644 --- a/src/platform/posix.c +++ b/src/platform/posix.c @@ -699,11 +699,12 @@ uint8 platform_get_locale_currency(){ //Only works if g_currency_specs contains the actual (local) symbol for(int i = 0; i < CURRENCY_END; ++i){ - if(!strcmp(lc->currency_symbol, g_currency_specs[i].symbol)){ + if(!strcmp(lc->currency_symbol, CurrencyDescriptors[i].symbol_unicode)){ return i; } } - //TODO: can be removed when g_currency_specs contains the actual symbols for won and rubel + //TODO: can be removed when CurrencyDescriptors contains the actual symbols for won and rubel + //Won should remain a special case, beacause some (or all?) systems use the full width won sign (e.g. Gentoo) if(!strncmp(lc->int_curr_symbol, "KRW", 3)){ return CURRENCY_WON; } From a18089145bf81c776eedcb8eeaf43dbdd0dea715 Mon Sep 17 00:00:00 2001 From: Kevin Date: Sat, 5 Dec 2015 22:25:25 +0100 Subject: [PATCH 5/5] [Linux] Check for null pointer in locale specific functions --- src/platform/posix.c | 46 ++++++++++++++++++++++++-------------------- 1 file changed, 25 insertions(+), 21 deletions(-) diff --git a/src/platform/posix.c b/src/platform/posix.c index b31f96198a..e988ccf756 100644 --- a/src/platform/posix.c +++ b/src/platform/posix.c @@ -695,23 +695,25 @@ time_t platform_file_get_modified_time(const utf8* path){ uint8 platform_get_locale_currency(){ char *langstring = setlocale(LC_MONETARY, ""); - struct lconv *lc = localeconv(); - //Only works if g_currency_specs contains the actual (local) symbol - for(int i = 0; i < CURRENCY_END; ++i){ - if(!strcmp(lc->currency_symbol, CurrencyDescriptors[i].symbol_unicode)){ - return i; + if(langstring != NULL){ + struct lconv *lc = localeconv(); + + //Only works if g_currency_specs contains the actual (local) symbol + for(int i = 0; i < CURRENCY_END; ++i){ + if(!strcmp(lc->currency_symbol, CurrencyDescriptors[i].symbol_unicode)){ + return i; + } + } + //TODO: can be removed when CurrencyDescriptors contains the actual symbols for won and rubel + //Won should remain a special case, beacause some (or all?) systems use the full width won sign (e.g. Gentoo) + if(!strncmp(lc->int_curr_symbol, "KRW", 3)){ + return CURRENCY_WON; + } + else if(!strncmp(lc->int_curr_symbol, "RUB", 3)){ + return CURRENCY_ROUBLE; } } - //TODO: can be removed when CurrencyDescriptors contains the actual symbols for won and rubel - //Won should remain a special case, beacause some (or all?) systems use the full width won sign (e.g. Gentoo) - if(!strncmp(lc->int_curr_symbol, "KRW", 3)){ - return CURRENCY_WON; - } - else if(!strncmp(lc->int_curr_symbol, "RUB", 3)){ - return CURRENCY_ROUBLE; - } - //All other currencies are historic return CURRENCY_POUNDS; } @@ -720,21 +722,23 @@ uint8 platform_get_locale_measurement_format(){ //FIXME: LC_MEASUREMENT is GNU specific. const char *langstring = setlocale(LC_MEASUREMENT, ""); - //using https://en.wikipedia.org/wiki/Metrication#Chronology_and_status_of_conversion_by_country as reference - if(!fnmatch("*_US*", langstring, 0) || !fnmatch("*_MM*", langstring, 0) || !fnmatch("*_LR*", langstring, 0)){ - return MEASUREMENT_FORMAT_IMPERIAL; + if(langstring != NULL){ + //using https://en.wikipedia.org/wiki/Metrication#Chronology_and_status_of_conversion_by_country as reference + if(!fnmatch("*_US*", langstring, 0) || !fnmatch("*_MM*", langstring, 0) || !fnmatch("*_LR*", langstring, 0)){ + return MEASUREMENT_FORMAT_IMPERIAL; + } } - return MEASUREMENT_FORMAT_METRIC; } uint8 platform_get_locale_temperature_format(){ const char *langstring = setlocale(LC_MEASUREMENT, ""); - if(!fnmatch("*_US*", langstring, 0) || !fnmatch("*_BS*", langstring, 0) || !fnmatch("*_BZ*", langstring, 0) || !fnmatch("*_PW*", langstring, 0)){ - return TEMPERATURE_FORMAT_F; + if(langstring != NULL){ + if(!fnmatch("*_US*", langstring, 0) || !fnmatch("*_BS*", langstring, 0) || !fnmatch("*_BZ*", langstring, 0) || !fnmatch("*_PW*", langstring, 0)){ + return TEMPERATURE_FORMAT_F; + } } - return TEMPERATURE_FORMAT_C; }