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 switch 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 result can differ
35// from using setlocale(xx, "C").
36// Previously, 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
66void 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
76std::atomic<unsigned int> LOCALE_IO::m_c_count( 0 );
77
78LOCALE_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:55
static std::atomic< unsigned int > m_c_count
Definition: locale_io.h:48
std::string m_user_locale
Definition: locale_io.h:52