Fix an issue in LOCALE_IO class, used to switch to/back locale "C" when reading/writing files: the back to locale was broken, and created issues in countries using the ',' as fp separator, especially when the non default language was used.

It was reported in many bugs.
This commit is contained in:
jean-pierre charras 2016-05-10 09:11:09 +02:00
parent bfeb61abef
commit ec096cc1d2
6 changed files with 51 additions and 89 deletions

View File

@ -44,6 +44,8 @@
#include <wx/utils.h> #include <wx/utils.h>
#include <wx/stdpaths.h> #include <wx/stdpaths.h>
#include <pgm_base.h>
/** /**
* Global variables definitions. * Global variables definitions.
@ -58,30 +60,40 @@ EDA_UNITS_T g_UserUnit;
EDA_COLOR_T g_GhostColor; EDA_COLOR_T g_GhostColor;
/** /* Class LOCALE_IO
* Function to use local notation or C standard notation for floating point numbers * is a class that can be instantiated within a scope in which you are expecting
* some countries use 1,5 and others (and C) 1.5 * exceptions to be thrown. Its constructor sets a "C" locale, to read/print files
* so we switch from local to C and C to local when reading or writing files * with fp numbers.
* And other problem is a bug when cross compiling under linux: * Its destructor insures that the default locale is restored if an exception
* a printf print 1,5 and the read functions expects 1.5 * is thrown, or not.
* (depending on version print = 1.5 and read = 1,5 */
* Very annoying and we detect this and use a stupid but necessary workaround
*/
bool g_DisableFloatingPointLocalNotation = false;
int LOCALE_IO::m_c_count = 0;
int LOCALE_IO::C_count; LOCALE_IO::LOCALE_IO()
void SetLocaleTo_C_standard()
{ {
setlocale( LC_NUMERIC, "C" ); // Switch the locale to standard C wxASSERT_MSG( m_c_count >= 0, wxT( "LOCALE_IO::m_c_count mismanaged." ) );
// use thread safe, atomic operation
if( __sync_fetch_and_add( &m_c_count, 1 ) == 0 )
{
// Store the user locale name, to restore this locale later, in dtor
m_user_locale = setlocale( LC_ALL, 0 );
// Switch the locale to C locale, to read/write files with fp numbers
setlocale( LC_ALL, "C" );
}
} }
void SetLocaleTo_Default() LOCALE_IO::~LOCALE_IO()
{ {
if( !g_DisableFloatingPointLocalNotation ) // use thread safe, atomic operation
setlocale( LC_NUMERIC, "" ); // revert to the current locale if( __sync_sub_and_fetch( &m_c_count, 1 ) == 0 )
{
// revert to the user locale
setlocale( LC_ALL, m_user_locale.c_str() );
}
wxASSERT_MSG( m_c_count >= 0, wxT( "LOCALE_IO::m_c_count mismanaged." ) );
} }

View File

@ -351,6 +351,7 @@ const wxString& PGM_BASE::GetEditorName( bool aCanShowFileChooser )
return m_editor_name; return m_editor_name;
} }
const wxString PGM_BASE::AskUserForPreferredEditor( const wxString& aDefaultEditor ) const wxString PGM_BASE::AskUserForPreferredEditor( const wxString& aDefaultEditor )
{ {
// Create a mask representing the executable files in the current platform // Create a mask representing the executable files in the current platform
@ -511,9 +512,6 @@ bool PGM_BASE::initPgm()
loadCommonSettings(); loadCommonSettings();
// Set locale option for separator used in float numbers
SetLocaleTo_Default();
#ifdef __WXMAC__ #ifdef __WXMAC__
// Always show filters on Open dialog to be able to choose plugin // Always show filters on Open dialog to be able to choose plugin
wxSystemOptions::SetOption( wxOSX_FILEDIALOG_ALWAYS_SHOW_TYPES, 1 ); wxSystemOptions::SetOption( wxOSX_FILEDIALOG_ALWAYS_SHOW_TYPES, 1 );
@ -702,20 +700,14 @@ bool PGM_BASE::SetLanguage( bool first_time )
double dtst = 0.5; double dtst = 0.5;
wxString msg; wxString msg;
extern bool g_DisableFloatingPointLocalNotation; // See common.cpp
g_DisableFloatingPointLocalNotation = false;
msg << dtst; msg << dtst;
double result; double result;
msg.ToDouble( &result ); msg.ToDouble( &result );
if( result != dtst ) // string to double encode/decode does not work! Bug detected if( result != dtst )
{ // string to double encode/decode does not work! Bug detected:
// Disable floating point localization: // Disable floating point localization:
g_DisableFloatingPointLocalNotation = true; setlocale( LC_ALL, "C" );
SetLocaleTo_C_standard( );
}
if( !m_locale->IsLoaded( dictionaryName ) ) if( !m_locale->IsLoaded( dictionaryName ) )
m_locale->AddCatalog( dictionaryName ); m_locale->AddCatalog( dictionaryName );

View File

@ -66,6 +66,7 @@ void DIALOG_PLOT_SCHEMATIC::createPDFFile( bool aPlotAll, bool aPlotFrameRef )
wxString msg; wxString msg;
wxFileName plotFileName; wxFileName plotFileName;
REPORTER& reporter = m_MessagesBox->Reporter(); REPORTER& reporter = m_MessagesBox->Reporter();
LOCALE_IO toggle; // Switch the locale to standard C
for( unsigned i = 0; i < sheetList.size(); i++ ) for( unsigned i = 0; i < sheetList.size(); i++ )
{ {
@ -94,7 +95,6 @@ void DIALOG_PLOT_SCHEMATIC::createPDFFile( bool aPlotAll, bool aPlotFrameRef )
} }
// Open the plotter and do the first page // Open the plotter and do the first page
SetLocaleTo_C_standard();
setupPlotPagePDF( plotter, screen ); setupPlotPagePDF( plotter, screen );
plotter->StartPlot(); plotter->StartPlot();
} }
@ -134,7 +134,6 @@ void DIALOG_PLOT_SCHEMATIC::restoreEnvironment( PDF_PLOTTER* aPlotter,
{ {
aPlotter->EndPlot(); aPlotter->EndPlot();
delete aPlotter; delete aPlotter;
SetLocaleTo_Default();
// Restore the previous sheet // Restore the previous sheet
m_parent->SetCurrentSheet( aOldsheetpath ); m_parent->SetCurrentSheet( aOldsheetpath );

View File

@ -151,7 +151,8 @@ bool DIALOG_PLOT_SCHEMATIC::plotOneSheetPS( const wxString& aFileName,
return false; return false;
} }
SetLocaleTo_C_standard(); LOCALE_IO toggle; // Switch the locale to standard C
plotter->StartPlot(); plotter->StartPlot();
if( aPlotFrameRef ) if( aPlotFrameRef )
@ -168,7 +169,6 @@ bool DIALOG_PLOT_SCHEMATIC::plotOneSheetPS( const wxString& aFileName,
plotter->EndPlot(); plotter->EndPlot();
delete plotter; delete plotter;
SetLocaleTo_Default();
return true; return true;
} }

View File

@ -1,7 +1,7 @@
/* /*
* This program source code file is part of KiCad, a free EDA CAD application. * This program source code file is part of KiCad, a free EDA CAD application.
* *
* Copyright (C) 2014-2015 Jean-Pierre Charras, jp.charras at wanadoo.fr * Copyright (C) 2014-2016 Jean-Pierre Charras, jp.charras at wanadoo.fr
* Copyright (C) 2007-2015 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com> * Copyright (C) 2007-2015 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
* Copyright (C) 2008-2015 Wayne Stambaugh <stambaughw@verizon.net> * Copyright (C) 2008-2015 Wayne Stambaugh <stambaughw@verizon.net>
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors. * Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
@ -181,70 +181,29 @@ extern EDA_UNITS_T g_UserUnit; ///< display units
extern EDA_COLOR_T g_GhostColor; extern EDA_COLOR_T g_GhostColor;
/**
* Function SetLocaleTo_C_standard
* because KiCad is internationalized, switch internalization to "C" standard
* i.e. uses the . (dot) as separator in print/read float numbers
* (some countries (France, Germany ..) use , (comma) as separator)
* This function must be called before read or write ascii files using float
* numbers in data the SetLocaleTo_C_standard function must be called after
* reading or writing the file
*
* This is wrapper to the C setlocale( LC_NUMERIC, "C" ) function,
* but could make more easier an optional use of locale in KiCad
*/
void SetLocaleTo_C_standard();
/**
* Function SetLocaleTo_Default
* because KiCad is internationalized, switch internalization to default
* to use the default separator in print/read float numbers
* (. (dot) but some countries (France, Germany ..) use , (comma) as
* separator)
* This function must be called after a call to SetLocaleTo_C_standard
*
* This is wrapper to the C setlocale( LC_NUMERIC, "" ) function,
* but could make more easier an optional use of locale in KiCad
*/
void SetLocaleTo_Default();
/** /**
* Class LOCALE_IO * Class LOCALE_IO
* is a class that can be instantiated within a scope in which you are expecting * is a class that can be instantiated within a scope in which you are expecting
* exceptions to be thrown. Its constructor calls SetLocaleTo_C_Standard(). * exceptions to be thrown. Its constructor set a "C" laguage locale option,
* to read/print files with fp numbers.
* Its destructor insures that the default locale is restored if an exception * Its destructor insures that the default locale is restored if an exception
* is thrown, or not. * is thrown, or not.
*/ */
class LOCALE_IO class LOCALE_IO
{ {
public: public:
LOCALE_IO() LOCALE_IO();
{ ~LOCALE_IO();
wxASSERT_MSG( C_count >= 0, wxT( "LOCALE_IO::C_count mismanaged." ) );
// use thread safe, atomic operation
if( __sync_fetch_and_add( &C_count, 1 ) == 0 )
{
// printf( "setting C locale.\n" );
SetLocaleTo_C_standard();
}
}
~LOCALE_IO()
{
// use thread safe, atomic operation
if( __sync_sub_and_fetch( &C_count, 1 ) == 0 )
{
// printf( "restoring default locale.\n" );
SetLocaleTo_Default();
}
wxASSERT_MSG( C_count >= 0, wxT( "LOCALE_IO::C_count mismanaged." ) );
}
private: private:
static int C_count; // allow for nesting of LOCALE_IO instantiations void setUserLocale( const char* aUserLocale );
// allow for nesting of LOCALE_IO instantiations
static int m_c_count;
// The locale in use before switching to the "C" locale
// (the locale can be set by user, and is not always the system locale)
std::string m_user_locale;
}; };