diff --git a/common/locale_io.cpp b/common/locale_io.cpp index 26a59f1978..eecd209ad3 100644 --- a/common/locale_io.cpp +++ b/common/locale_io.cpp @@ -1,7 +1,7 @@ /* * This program source code file is part of KiCad, a free EDA CAD application. * - * Copyright (C) 1992-2020 KiCad Developers, see AUTHORS.txt for contributors. + * Copyright (C) 1992-2021 KiCad Developers, see AUTHORS.txt for contributors. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -24,15 +24,74 @@ #include #include -std::atomic LOCALE_IO::m_c_count( 0 ); +// When reading/writing files, we need to swtich to setlocale( LC_NUMERIC, "C" ). +// Works fine to read/write files with floating point numbers. +// We can call setlocale( LC_NUMERIC, "C" ) or wxLocale( "C", "C", "C", false ) +// wxWidgets discourage a direct call to setlocale +// However, for us, calling wxLocale( "C", "C", "C", false ) has a unwanted effect: +// The I18N translations are no longer active, because the English dictionary is selected. +// To read files, this is not a major issues, but the resul can differ +// from using setlocale(xx, "C"). +// Previouly, we used only setlocale( LC_NUMERIC, "C" ) +// +// Known issues are +// on MSW +// using setlocale( LC_NUMERIC, "C" ) generates an alert message in debug mode, +// and this message ("Decimal separator mismatch") must be disabled. +// But calling wxLocale( "C", "C", "C", false ) works fine +// On unix: +// calling wxLocale( "C", "C", "C", false ) breaks env vars containing non ASCII7 chars. +// these env vars return a empty string from wxGetEnv() in many cases, and if such a +// var must be read after calling wxLocale( "C", "C", "C", false ), it looks like empty +// +// So use wxLocale on Windows and setlocale on unix +// set USE_WXLOCALE 0 to use setlocale, 1 to use wxLocale: +#if defined( _WIN32 ) +#define USE_WXLOCALE 1 +#else +#define USE_WXLOCALE 0 +#endif + +// On Windows, when using setlocale, a wx alert is generated +// in some cases (reading a bitmap for instance) +// So we disable alerts during the time a file is read or written +#if !USE_WXLOCALE +#if defined( _WIN32 ) && defined( DEBUG ) +// a wxAssertHandler_t function to filter wxWidgets alert messages when reading/writing a file +// when switching the locale to LC_NUMERIC, "C" +// It is used in class LOCALE_IO to hide a useless (in kicad) wxWidgets alert message +void KiAssertFilter( const wxString &file, int line, + const wxString &func, const wxString &cond, + const wxString &msg) +{ + if( !msg.Contains( "Decimal separator mismatch" ) ) + wxTheApp->OnAssertFailure( file.c_str(), line, func.c_str(), cond.c_str(), msg.c_str() ); +} +#endif +#endif + +std::atomic LOCALE_IO::m_c_count( 0 ); + LOCALE_IO::LOCALE_IO() : m_wxLocale( nullptr ) { // use thread safe, atomic operation if( m_c_count++ == 0 ) { - m_wxLocale = new wxLocale( "C", "C", "C", false ); +#if USE_WXLOCALE + #define C_LANG "C" + m_wxLocale = new wxLocale( C_LANG, C_LANG, C_LANG, false ); +#else + // Store the user locale name, to restore this locale later, in dtor + m_user_locale = setlocale( LC_NUMERIC, nullptr ); +#if defined( _WIN32 ) && defined( DEBUG ) + // Disable wxWidgets alerts + wxSetAssertHandler( KiAssertFilter ); +#endif + // Switch the locale to C locale, to read/write files with fp numbers + setlocale( LC_NUMERIC, "C" ); +#endif } } @@ -42,7 +101,16 @@ LOCALE_IO::~LOCALE_IO() // use thread safe, atomic operation if( --m_c_count == 0 ) { - delete m_wxLocale; // Deleting m_wxLocale restored previous locale + // revert to the user locale +#if USE_WXLOCALE + delete m_wxLocale; // Deleting m_wxLocale restored previous locale m_wxLocale = nullptr; +#else + setlocale( LC_NUMERIC, m_user_locale.c_str() ); +#if defined( _WIN32 ) && defined( DEBUG ) + // Enable wxWidgets alerts + wxSetDefaultAssertHandler(); +#endif +#endif } -} \ No newline at end of file +}