Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[no squash] Init & gettext cleanups #14130

Merged
merged 3 commits into from
Dec 29, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
155 changes: 75 additions & 80 deletions src/gettext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "util/string.h"
#include "log.h"

#ifdef _WIN32
#define setenv(n,v,o) _putenv_s(n,v)
#endif

#if USE_GETTEXT && defined(_MSC_VER)
#include <windows.h>
#include <map>
Expand All @@ -37,7 +41,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
static std::map<std::wstring, std::wstring> glb_supported_locales;

/******************************************************************************/
BOOL CALLBACK UpdateLocaleCallback(LPTSTR pStr)
static BOOL CALLBACK UpdateLocaleCallback(LPTSTR pStr)
{
char* endptr = 0;
int LOCALEID = strtol(pStr, &endptr,16);
Expand Down Expand Up @@ -78,7 +82,8 @@ BOOL CALLBACK UpdateLocaleCallback(LPTSTR pStr)
}

/******************************************************************************/
const char* MSVC_LocaleLookup(const char* raw_shortname) {
static const char* MSVC_LocaleLookup(const char* raw_shortname)
{

/* NULL is used to read locale only so we need to return it too */
if (raw_shortname == NULL) return NULL;
Expand All @@ -102,9 +107,9 @@ const char* MSVC_LocaleLookup(const char* raw_shortname) {

last_raw_value = shortname;

if (glb_supported_locales.find(utf8_to_wide(shortname)) != glb_supported_locales.end()) {
last_full_name = wide_to_utf8(
glb_supported_locales[utf8_to_wide(shortname)]);
auto key = utf8_to_wide(shortname);
if (glb_supported_locales.find(key) != glb_supported_locales.end()) {
last_full_name = wide_to_utf8(glb_supported_locales[key]);
return last_full_name.c_str();
}

Expand All @@ -114,6 +119,54 @@ const char* MSVC_LocaleLookup(const char* raw_shortname) {
return "";
}

static void MSVC_LocaleWorkaround()
{
errorstream << "MSVC localization workaround active. "
"Restarting " PROJECT_NAME_C " in a new environment!" << std::endl;

std::string parameters;
for (int i = 1; i < argc; i++) {
if (i > 1)
parameters += ' ';
parameters += porting::QuoteArgv(argv[i]);
}

char *ptr_parameters = nullptr;
if (!parameters.empty())
ptr_parameters = &parameters[0];

// Allow calling without an extension
std::string app_name = argv[0];
if (app_name.compare(app_name.size() - 4, 4, ".exe") != 0)
app_name += ".exe";

STARTUPINFO startup_info = {};
PROCESS_INFORMATION process_info = {};

bool success = CreateProcess(app_name.c_str(), ptr_parameters,
NULL, NULL, false, DETACHED_PROCESS | CREATE_UNICODE_ENVIRONMENT,
NULL, NULL, &startup_info, &process_info);

if (success) {
exit(0);
// NOTREACHED
} else {
char buffer[1024];

FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(),
MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT), buffer,
sizeof(buffer) - 1, NULL);

errorstream << "*******************************************************" << std::endl;
errorstream << "CMD: " << app_name << std::endl;
errorstream << "Failed to restart with current locale: " << std::endl;
errorstream << buffer;
errorstream << "Expect language to be broken!" << std::endl;
errorstream << "*******************************************************" << std::endl;
}
}
}

#endif

/******************************************************************************/
Expand All @@ -123,72 +176,26 @@ void init_gettext(const char *path, const std::string &configured_language,
#if USE_GETTEXT
// First, try to set user override environment
if (!configured_language.empty()) {
#ifndef _WIN32
// Add user specified locale to environment
// Set LANGUAGE which overrides all others, see
// <https://www.gnu.org/software/gettext/manual/html_node/Locale-Environment-Variables.html>
#ifndef _MSC_VER
setenv("LANGUAGE", configured_language.c_str(), 1);

#ifdef __ANDROID__
setenv("LANG", configured_language.c_str(), 1);
#endif

// Reload locale with changed environment
setlocale(LC_ALL, "");
#elif defined(_MSC_VER)
#else
std::string current_language;
const char *env_lang = getenv("LANGUAGE");
if (env_lang)
current_language = env_lang;

_putenv(("LANGUAGE=" + configured_language).c_str());
setenv("LANGUAGE", configured_language.c_str(), 1);
SetEnvironmentVariableA("LANGUAGE", configured_language.c_str());

#ifndef SERVER
// Hack to force gettext to see the right environment
if (current_language != configured_language) {
errorstream << "MSVC localization workaround active. "
"Restarting " PROJECT_NAME_C " in a new environment!" << std::endl;

std::string parameters;
for (int i = 1; i < argc; i++) {
if (i > 1)
parameters += ' ';
parameters += porting::QuoteArgv(argv[i]);
}

char *ptr_parameters = nullptr;
if (!parameters.empty())
ptr_parameters = &parameters[0];

// Allow calling without an extension
std::string app_name = argv[0];
if (app_name.compare(app_name.size() - 4, 4, ".exe") != 0)
app_name += ".exe";

STARTUPINFO startup_info = {};
PROCESS_INFORMATION process_info = {};

bool success = CreateProcess(app_name.c_str(), ptr_parameters,
NULL, NULL, false, DETACHED_PROCESS | CREATE_UNICODE_ENVIRONMENT,
NULL, NULL, &startup_info, &process_info);

if (success) {
exit(0);
// NOTREACHED
} else {
char buffer[1024];

FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(),
MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT), buffer,
sizeof(buffer) - 1, NULL);

errorstream << "*******************************************************" << std::endl;
errorstream << "CMD: " << app_name << std::endl;
errorstream << "Failed to restart with current locale: " << std::endl;
errorstream << buffer;
errorstream << "Expect language to be broken!" << std::endl;
errorstream << "*******************************************************" << std::endl;
}
}
if (current_language != configured_language)
MSVC_LocaleWorkaround();
#else
errorstream << "*******************************************************" << std::endl;
errorstream << "Can't apply locale workaround for server!" << std::endl;
Expand All @@ -197,15 +204,8 @@ void init_gettext(const char *path, const std::string &configured_language,
#endif

setlocale(LC_ALL, configured_language.c_str());
#else // Mingw
_putenv(("LANGUAGE=" + configured_language).c_str());
setlocale(LC_ALL, "");
#endif // ifndef _WIN32
}
else {
#ifdef __ANDROID__
setenv("LANG", porting::getLanguageAndroid().c_str(), 1);
#endif
#endif // ifdef _MSC_VER
} else {
/* set current system default locale */
setlocale(LC_ALL, "");
}
Expand All @@ -228,26 +228,21 @@ void init_gettext(const char *path, const std::string &configured_language,
bindtextdomain(name.c_str(), path);
textdomain(name.c_str());

#if defined(_WIN32)
// Set character encoding for Win32
char *tdomain = textdomain( (char *) NULL );
if( tdomain == NULL )
{
errorstream << "Warning: domainname parameter is the null pointer" <<
", default domain is not set" << std::endl;
tdomain = (char *) "messages";
}
/* char *codeset = */bind_textdomain_codeset( tdomain, "UTF-8" );
//errorstream << "Gettext debug: domainname = " << tdomain << "; codeset = "<< codeset << std::endl;
#endif // defined(_WIN32)
#ifdef _WIN32
// set character encoding
char *tdomain = textdomain(nullptr);
assert(tdomain);
if (tdomain)
bind_textdomain_codeset(tdomain, "UTF-8");
#endif

#else
/* set current system default locale */
setlocale(LC_ALL, "");
#endif // if USE_GETTEXT

/* no matter what locale is used we need number format to be "C" */
/* to ensure formspec parameters are evaluated correct! */
/* to ensure formspec parameters are evaluated correctly! */

setlocale(LC_NUMERIC, "C");
infostream << "Message locale is now set to: "
Expand Down
42 changes: 19 additions & 23 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ static void set_allowed_options(OptionList *allowed_options);

static void print_help(const OptionList &allowed_options);
static void print_allowed_options(const OptionList &allowed_options);
static void print_version();
static void print_version(std::ostream &os);
static void print_worldspecs(const std::vector<WorldSpec> &worldspecs,
std::ostream &os, bool print_name = true, bool print_path = true);
static void print_modified_quicktune_values();
Expand Down Expand Up @@ -143,6 +143,8 @@ int main(int argc, char *argv[])
g_logger.registerThread("Main");
g_logger.addOutputMaxLevel(&stderr_output, LL_ACTION);

porting::osSpecificInit();

Settings cmd_args;
get_env_opts(cmd_args);
bool cmd_args_ok = get_cmdline_opts(argc, argv, &cmd_args);
Expand All @@ -158,10 +160,13 @@ int main(int argc, char *argv[])

if (cmd_args.getFlag("version")) {
porting::attachOrCreateConsole();
print_version();
print_version(std::cout);
return 0;
}

// Debug handler
BEGIN_DEBUG_EXCEPTION_HANDLER

if (!setup_log_params(cmd_args))
return 1;

Expand All @@ -171,22 +176,13 @@ int main(int argc, char *argv[])
}

porting::signal_handler_init();

#ifdef __ANDROID__
porting::initAndroid();
porting::initializePathsAndroid();
#else
porting::initializePaths();
#endif

if (!create_userdata_path()) {
errorstream << "Cannot create user data directory" << std::endl;
return 1;
}

// Debug handler
BEGIN_DEBUG_EXCEPTION_HANDLER

// List gameids if requested
if (cmd_args.exists("gameid") && cmd_args.get("gameid") == "list") {
list_game_ids();
Expand Down Expand Up @@ -215,7 +211,6 @@ int main(int argc, char *argv[])
if (g_settings->getBool("enable_console"))
porting::attachOrCreateConsole();

#ifndef __ANDROID__
// Run unit tests
if (cmd_args.getFlag("run-unittests")) {
#if BUILD_UNITTESTS
Expand Down Expand Up @@ -245,7 +240,6 @@ int main(int argc, char *argv[])
return 1;
#endif
}
#endif // __ANDROID__

GameStartData game_params;
#ifdef SERVER
Expand Down Expand Up @@ -430,19 +424,20 @@ static void print_allowed_options(const OptionList &allowed_options)
}
}

static void print_version()
static void print_version(std::ostream &os)
{
std::cout << PROJECT_NAME_C " " << g_version_hash
os << PROJECT_NAME_C " " << g_version_hash
<< " (" << porting::getPlatformName() << ")" << std::endl;
#ifndef SERVER
std::cout << "Using Irrlicht " IRRLICHT_SDK_VERSION << std::endl;
os << "Using Irrlicht " IRRLICHT_SDK_VERSION << std::endl;
#endif
#if USE_LUAJIT
std::cout << "Using " << LUAJIT_VERSION << std::endl;
os << "Using " << LUAJIT_VERSION << std::endl;
#else
std::cout << "Using " << LUA_RELEASE << std::endl;
os << "Using " << LUA_RELEASE << std::endl;
#endif
std::cout << g_build_info << std::endl;
os << "Running on " << porting::get_sysinfo() << std::endl;
os << g_build_info << std::endl;
}

static void list_game_ids()
Expand Down Expand Up @@ -718,10 +713,11 @@ static void uninit_common()

static void startup_message()
{
infostream << PROJECT_NAME_C << " " << g_version_hash
<< "\nwith SER_FMT_VER_HIGHEST_READ="
<< (int)SER_FMT_VER_HIGHEST_READ << ", "
<< g_build_info << std::endl;
print_version(infostream);
infostream << "SER_FMT_VER_HIGHEST_READ=" <<
TOSTRING(SER_FMT_VER_HIGHEST_READ) <<
" LATEST_PROTOCOL_VERSION=" << TOSTRING(LATEST_PROTOCOL_VERSION)
<< std::endl;
}

static bool read_config_file(const Settings &cmd_args)
Expand Down