You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

117 lines
4.3 KiB

  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 1992-2021 KiCad Developers, see AUTHORS.txt for contributors.
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU General Public License
  8. * as published by the Free Software Foundation; either version 2
  9. * of the License, or (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program; if not, you may find one here:
  18. * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  19. * or you may search the http://www.gnu.org website for the version 2 license,
  20. * or you may write to the Free Software Foundation, Inc.,
  21. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  22. */
  23. #include <locale_io.h>
  24. #include <wx/intl.h>
  25. #include <clocale>
  26. // When reading/writing files, we need to swtich to setlocale( LC_NUMERIC, "C" ).
  27. // Works fine to read/write files with floating point numbers.
  28. // We can call setlocale( LC_NUMERIC, "C" ) or wxLocale( "C", "C", "C", false )
  29. // wxWidgets discourage a direct call to setlocale
  30. // However, for us, calling wxLocale( "C", "C", "C", false ) has a unwanted effect:
  31. // The I18N translations are no longer active, because the English dictionary is selected.
  32. // To read files, this is not a major issues, but the resul can differ
  33. // from using setlocale(xx, "C").
  34. // Previouly, we used only setlocale( LC_NUMERIC, "C" )
  35. //
  36. // Known issues are
  37. // on MSW
  38. // using setlocale( LC_NUMERIC, "C" ) generates an alert message in debug mode,
  39. // and this message ("Decimal separator mismatch") must be disabled.
  40. // But calling wxLocale( "C", "C", "C", false ) works fine
  41. // On unix:
  42. // calling wxLocale( "C", "C", "C", false ) breaks env vars containing non ASCII7 chars.
  43. // these env vars return a empty string from wxGetEnv() in many cases, and if such a
  44. // var must be read after calling wxLocale( "C", "C", "C", false ), it looks like empty
  45. //
  46. // So use wxLocale on Windows and setlocale on unix
  47. // set USE_WXLOCALE 0 to use setlocale, 1 to use wxLocale:
  48. #if defined( _WIN32 )
  49. #define USE_WXLOCALE 1
  50. #else
  51. #define USE_WXLOCALE 0
  52. #endif
  53. // On Windows, when using setlocale, a wx alert is generated
  54. // in some cases (reading a bitmap for instance)
  55. // So we disable alerts during the time a file is read or written
  56. #if !USE_WXLOCALE
  57. #if defined( _WIN32 ) && defined( DEBUG )
  58. // a wxAssertHandler_t function to filter wxWidgets alert messages when reading/writing a file
  59. // when switching the locale to LC_NUMERIC, "C"
  60. // It is used in class LOCALE_IO to hide a useless (in kicad) wxWidgets alert message
  61. void KiAssertFilter( const wxString &file, int line,
  62. const wxString &func, const wxString &cond,
  63. const wxString &msg)
  64. {
  65. if( !msg.Contains( "Decimal separator mismatch" ) )
  66. wxTheApp->OnAssertFailure( file.c_str(), line, func.c_str(), cond.c_str(), msg.c_str() );
  67. }
  68. #endif
  69. #endif
  70. std::atomic<unsigned int> LOCALE_IO::m_c_count( 0 );
  71. LOCALE_IO::LOCALE_IO() : m_wxLocale( nullptr )
  72. {
  73. // use thread safe, atomic operation
  74. if( m_c_count++ == 0 )
  75. {
  76. #if USE_WXLOCALE
  77. #define C_LANG "C"
  78. m_wxLocale = new wxLocale( C_LANG, C_LANG, C_LANG, false );
  79. #else
  80. // Store the user locale name, to restore this locale later, in dtor
  81. m_user_locale = setlocale( LC_NUMERIC, nullptr );
  82. #if defined( _WIN32 ) && defined( DEBUG )
  83. // Disable wxWidgets alerts
  84. wxSetAssertHandler( KiAssertFilter );
  85. #endif
  86. // Switch the locale to C locale, to read/write files with fp numbers
  87. setlocale( LC_NUMERIC, "C" );
  88. #endif
  89. }
  90. }
  91. LOCALE_IO::~LOCALE_IO()
  92. {
  93. // use thread safe, atomic operation
  94. if( --m_c_count == 0 )
  95. {
  96. // revert to the user locale
  97. #if USE_WXLOCALE
  98. delete m_wxLocale; // Deleting m_wxLocale restored previous locale
  99. m_wxLocale = nullptr;
  100. #else
  101. setlocale( LC_NUMERIC, m_user_locale.c_str() );
  102. #if defined( _WIN32 ) && defined( DEBUG )
  103. // Enable wxWidgets alerts
  104. wxSetDefaultAssertHandler();
  105. #endif
  106. #endif
  107. }
  108. }