Properly handling getenv() returning "" not NULL

i18n code was checking for local-related environment variables
(e.g., "getenv("LANGUAGE")") coming back as a NULL if unset.

However, on my laptop, under Kubuntu 20.04 with GLIBC 2.31, a
"LANGUAGE" env. var. is set, but it's blank.

Tux Paint failed to attempt any fallback (e.g., checking "LANG")
in that situation, which was causing the description text corruption
that was corrected in a previous commit.

That commit also mistakenly suggested that the issue might've been a
difference with GCC versions, but the problem was deeper in Tux Paint's
code (in i18n.c), and was triggered by an unexpected environment.
This commit is contained in:
Bill Kendrick 2020-07-26 17:17:14 -07:00
parent ac755bf26c
commit 4ba4c11911
2 changed files with 56 additions and 26 deletions

View file

@ -8,7 +8,7 @@ http://www.tuxpaint.org/
$Id$ $Id$
2020.July.25 (0.9.25) 2020.July.26 (0.9.25)
* New Features * New Features
------------ ------------
* Export drawings: * Export drawings:
@ -34,15 +34,20 @@ $Id$
(Ref: https://github.com/haikuports/haikuports/issues/3045) (Ref: https://github.com/haikuports/haikuports/issues/3045)
Gerasim Troeglazov <3dEyes@gmail.com> Gerasim Troeglazov <3dEyes@gmail.com>
* Bug Fixes
---------
* Mended issue where stamp descriptions were not loading
when "getenv()" (e.g., "getenv("LANGUAGE")") returned an
empty string, rather than a NULL.
* Mended bug where corrupt text would appear as stamp
descriptions, if we failed to know what language to use
(see above).
* Misc * Misc
---- ----
* Improved safety when copying things into string buffers. * Improved safety when copying things into string buffers.
* [WIP] Mending issue where stamp descriptions are not loading,
and making things safer when a problem occurs.
(Using gcc 9.3.0 compiler, this was happening in 0.9.25 during
development, but also affected 0.9.24 and 0.9.23, which worked
fine under earlier versions of gcc.)
2020.April.24 (0.9.24) 2020.April.24 (0.9.24)
* New tools * New tools

View file

@ -986,6 +986,7 @@ static int set_current_language(const char *restrict loc, int * ptr_num_wished_l
char *oldloc; char *oldloc;
char *env_language; char *env_language;
char *env_language_lang; char *env_language_lang;
char *env;
int num_wished_langs = 0; int num_wished_langs = 0;
*ptr_num_wished_langs = 0; *ptr_num_wished_langs = 0;
@ -993,20 +994,50 @@ static int set_current_language(const char *restrict loc, int * ptr_num_wished_l
if (strlen(loc) > 0) if (strlen(loc) > 0)
{ {
/* Got command line or config file language */ /* Got command line or config file language */
DEBUG_PRINTF("Language via config: %s\n", loc);
mysetenv("LANGUAGE", loc); mysetenv("LANGUAGE", loc);
} }
else else
{ {
DEBUG_PRINTF("Language NOT set via config\n");
/* Find what language to use from env vars */ /* Find what language to use from env vars */
if (getenv("LANGUAGE") == NULL) env = getenv("LANGUAGE");
if (env == NULL || env[0] == '\0')
{ {
if (getenv("LC_ALL")) env = getenv("LC_ALL");
mysetenv("LANGUAGE", getenv("LC_ALL")); if (env != NULL && env[0] != '\0')
else if (getenv("LC_MESSAGES")) {
mysetenv("LANGUAGE", getenv("LC_MESSAGES")); DEBUG_PRINTF("Language via LC_ALL: %s\n", getenv("LC_ALL"));
else if (getenv("LANG")) mysetenv("LANGUAGE", getenv("LC_ALL"));
mysetenv("LANGUAGE", getenv("LANG")); }
else
{
env = getenv("LC_MESSAGES");
if (env != NULL && env[0] != '\0')
{
DEBUG_PRINTF("Language via LC_MESSAGES: %s\n", getenv("LC_MESSAGES"));
mysetenv("LANGUAGE", getenv("LC_MESSAGES"));
}
else
{
env = getenv("LANG");
if (env != NULL && env[0] != '\0')
{
DEBUG_PRINTF("Language via LANG: %s\n", getenv("LANG"));
mysetenv("LANGUAGE", getenv("LANG"));
}
else
{
DEBUG_PRINTF("No language set!\n");
}
}
}
} }
else
{
DEBUG_PRINTF("Language was set to '%s'\n", getenv("LANGUAGE"));
}
} }
oldloc = strdup(loc); oldloc = strdup(loc);
@ -1014,15 +1045,13 @@ static int set_current_language(const char *restrict loc, int * ptr_num_wished_l
/* First set the locale according to the environment, then try to overwrite with loc, /* First set the locale according to the environment, then try to overwrite with loc,
after that, ctype_utf8() call will test the compatibility with utf8 and try to load after that, ctype_utf8() call will test the compatibility with utf8 and try to load
a different locale if the resulting one is not compatible. */ a different locale if the resulting one is not compatible. */
#ifdef DEBUG DEBUG_PRINTF("Locale BEFORE is: %s\n", setlocale(LC_ALL, NULL)); //EP
printf("Locale BEFORE is: %s\n", setlocale(LC_ALL, NULL)); //EP
#endif
setlocale(LC_ALL, ""); setlocale(LC_ALL, "");
setlocale(LC_ALL, loc); setlocale(LC_ALL, loc);
ctype_utf8(); ctype_utf8();
#ifdef DEBUG
printf("Locale AFTER is: %s\n", setlocale(LC_ALL, NULL)); //EP DEBUG_PRINTF("Locale AFTER is: %s\n", setlocale(LC_ALL, NULL)); //EP
#endif
bindtextdomain("tuxpaint", LOCALEDIR); bindtextdomain("tuxpaint", LOCALEDIR);
/* Old version of glibc does not have bind_textdomain_codeset() */ /* Old version of glibc does not have bind_textdomain_codeset() */
@ -1134,9 +1163,7 @@ static int set_current_language(const char *restrict loc, int * ptr_num_wished_l
free(oldloc); free(oldloc);
#ifdef DEBUG DEBUG_PRINTF("lang_prefixes[%d] is \"%s\"\n", get_current_language(), lang_prefixes[get_current_language()]);
printf("lang_prefixes[%d] is \"%s\"\n", get_current_language(), lang_prefixes[get_current_language()]);
#endif
*ptr_num_wished_langs = num_wished_langs; *ptr_num_wished_langs = num_wished_langs;
@ -1157,10 +1184,8 @@ static int set_current_language(const char *restrict loc, int * ptr_num_wished_l
*/ */
int setup_i18n(const char *restrict lang, const char *restrict locale, int * num_wished_langs) int setup_i18n(const char *restrict lang, const char *restrict locale, int * num_wished_langs)
{ {
#ifdef DEBUG DEBUG_PRINTF("lang %p, locale %p\n", lang, locale);
printf("lang %p, locale %p\n", lang, locale); DEBUG_PRINTF("lang \"%s\", locale \"%s\"\n", lang, locale);
printf("lang \"%s\", locale \"%s\"\n", lang, locale);
#endif
if (locale) if (locale)
{ {