KiCad PCB EDA Suite
locale_io.cpp
Go to the documentation of this file.
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 
24 #include <locale_io.h>
25 #include <wx/intl.h>
26 #include <clocale>
27 
28 // When reading/writing files, we need to swtich to setlocale( LC_NUMERIC, "C" ).
29 // Works fine to read/write files with floating point numbers.
30 // We can call setlocale( LC_NUMERIC, "C" ) or wxLocale( "C", "C", "C", false )
31 // wxWidgets discourage a direct call to setlocale
32 // However, for us, calling wxLocale( "C", "C", "C", false ) has a unwanted effect:
33 // The I18N translations are no longer active, because the English dictionary is selected.
34 // To read files, this is not a major issues, but the resul can differ
35 // from using setlocale(xx, "C").
36 // Previouly, we used only setlocale( LC_NUMERIC, "C" )
37 //
38 // Known issues are
39 // on MSW
40 // using setlocale( LC_NUMERIC, "C" ) generates an alert message in debug mode,
41 // and this message ("Decimal separator mismatch") must be disabled.
42 // But calling wxLocale( "C", "C", "C", false ) works fine
43 // On unix:
44 // calling wxLocale( "C", "C", "C", false ) breaks env vars containing non ASCII7 chars.
45 // these env vars return a empty string from wxGetEnv() in many cases, and if such a
46 // var must be read after calling wxLocale( "C", "C", "C", false ), it looks like empty
47 //
48 // So use wxLocale on Windows and setlocale on unix
49 
50 
51 // set USE_WXLOCALE 0 to use setlocale, 1 to use wxLocale:
52 #if defined( _WIN32 )
53 #define USE_WXLOCALE 1
54 #else
55 #define USE_WXLOCALE 0
56 #endif
57 
58 // On Windows, when using setlocale, a wx alert is generated
59 // in some cases (reading a bitmap for instance)
60 // So we disable alerts during the time a file is read or written
61 #if !USE_WXLOCALE
62 #if defined( _WIN32 ) && defined( DEBUG )
63 // a wxAssertHandler_t function to filter wxWidgets alert messages when reading/writing a file
64 // when switching the locale to LC_NUMERIC, "C"
65 // It is used in class LOCALE_IO to hide a useless (in kicad) wxWidgets alert message
66 void KiAssertFilter( const wxString &file, int line,
67  const wxString &func, const wxString &cond,
68  const wxString &msg)
69 {
70  if( !msg.Contains( "Decimal separator mismatch" ) )
71  wxTheApp->OnAssertFailure( file.c_str(), line, func.c_str(), cond.c_str(), msg.c_str() );
72 }
73 #endif
74 #endif
75 
76 std::atomic<unsigned int> LOCALE_IO::m_c_count( 0 );
77 
78 LOCALE_IO::LOCALE_IO() : m_wxLocale( nullptr )
79 {
80  // use thread safe, atomic operation
81  if( m_c_count++ == 0 )
82  {
83 #if USE_WXLOCALE
84  #define C_LANG "C"
85  m_wxLocale = new wxLocale( C_LANG, C_LANG, C_LANG, false );
86 #else
87  // Store the user locale name, to restore this locale later, in dtor
88  m_user_locale = setlocale( LC_NUMERIC, nullptr );
89 #if defined( _WIN32 ) && defined( DEBUG )
90  // Disable wxWidgets alerts
91  wxSetAssertHandler( KiAssertFilter );
92 #endif
93  // Switch the locale to C locale, to read/write files with fp numbers
94  setlocale( LC_NUMERIC, "C" );
95 #endif
96  }
97 }
98 
99 
101 {
102  // use thread safe, atomic operation
103  if( --m_c_count == 0 )
104  {
105  // revert to the user locale
106 #if USE_WXLOCALE
107  delete m_wxLocale; // Deleting m_wxLocale restored previous locale
108  m_wxLocale = nullptr;
109 #else
110  setlocale( LC_NUMERIC, m_user_locale.c_str() );
111 #if defined( _WIN32 ) && defined( DEBUG )
112  // Enable wxWidgets alerts
113  wxSetDefaultAssertHandler();
114 #endif
115 #endif
116  }
117 }
wxLocale * m_wxLocale
Definition: locale_io.h:53
static std::atomic< unsigned int > m_c_count
Definition: locale_io.h:48
std::string m_user_locale
Definition: locale_io.h:52