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-06-21 10:48:42 -04:00 committed by Wayne Stambaugh
parent 2bb695b767
commit 90ed0183c8
9 changed files with 57 additions and 97 deletions

View File

@ -44,6 +44,8 @@
#include <wx/utils.h>
#include <wx/stdpaths.h>
#include <pgm_base.h>
/**
* Global variables definitions.
@ -58,30 +60,40 @@ EDA_UNITS_T g_UserUnit;
EDA_COLOR_T g_GhostColor;
/**
* Function to use local notation or C standard notation for floating point numbers
* some countries use 1,5 and others (and C) 1.5
* so we switch from local to C and C to local when reading or writing files
* And other problem is a bug when cross compiling under linux:
* a printf print 1,5 and the read functions expects 1.5
* (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;
/* Class LOCALE_IO
* is a class that can be instantiated within a scope in which you are expecting
* exceptions to be thrown. Its constructor sets a "C" locale, to read/print files
* with fp numbers.
* Its destructor insures that the default locale is restored if an exception
* is thrown, or not.
*/
int LOCALE_IO::m_c_count = 0;
int LOCALE_IO::C_count;
void SetLocaleTo_C_standard()
LOCALE_IO::LOCALE_IO()
{
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 )
setlocale( LC_NUMERIC, "" ); // revert to the current locale
// use thread safe, atomic operation
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

@ -344,6 +344,7 @@ const wxString& PGM_BASE::GetEditorName( bool aCanShowFileChooser )
return m_editor_name;
}
const wxString PGM_BASE::AskUserForPreferredEditor( const wxString& aDefaultEditor )
{
// Create a mask representing the executable files in the current platform
@ -504,9 +505,6 @@ bool PGM_BASE::initPgm()
loadCommonSettings();
// Set locale option for separator used in float numbers
SetLocaleTo_Default();
#ifdef __WXMAC__
// Always show filters on Open dialog to be able to choose plugin
wxSystemOptions::SetOption( wxOSX_FILEDIALOG_ALWAYS_SHOW_TYPES, 1 );
@ -695,20 +693,14 @@ bool PGM_BASE::SetLanguage( bool first_time )
double dtst = 0.5;
wxString msg;
extern bool g_DisableFloatingPointLocalNotation; // See common.cpp
g_DisableFloatingPointLocalNotation = false;
msg << dtst;
double 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:
g_DisableFloatingPointLocalNotation = true;
SetLocaleTo_C_standard( );
}
setlocale( LC_ALL, "C" );
if( !m_locale->IsLoaded( dictionaryName ) )
m_locale->AddCatalog( dictionaryName );

View File

@ -64,6 +64,7 @@ void DIALOG_PLOT_SCHEMATIC::createPDFFile( bool aPlotAll, bool aPlotFrameRef )
wxString msg;
wxFileName plotFileName;
REPORTER& reporter = m_MessagesBox->Reporter();
LOCALE_IO toggle; // Switch the locale to standard C
// First page handling is different
bool first_page = true;
@ -106,7 +107,6 @@ void DIALOG_PLOT_SCHEMATIC::createPDFFile( bool aPlotAll, bool aPlotFrameRef )
}
// Open the plotter and do the first page
SetLocaleTo_C_standard();
setupPlotPagePDF( plotter, screen );
plotter->StartPlot();
first_page = false;
@ -150,7 +150,6 @@ void DIALOG_PLOT_SCHEMATIC::restoreEnvironment( PDF_PLOTTER* aPlotter,
{
aPlotter->EndPlot();
delete aPlotter;
SetLocaleTo_Default();
// Restore the previous sheet
m_parent->SetCurrentSheet( aOldsheetpath );

View File

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

View File

@ -1,7 +1,7 @@
/*
* 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) 2008-2015 Wayne Stambaugh <stambaughw@verizon.net>
* Copyright (C) 1992-2015 KiCad Developers, see AUTHORS.txt for contributors.
@ -176,70 +176,29 @@ extern EDA_UNITS_T g_UserUnit; ///< display units
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
* 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
* is thrown, or not.
*/
class LOCALE_IO
{
public:
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." ) );
}
LOCALE_IO();
~LOCALE_IO();
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;
};

View File

@ -140,7 +140,7 @@ public:
* been set.
*/
VTBL_ENTRY const wxString& GetEditorName( bool aCanShowFileChooser = true );
/**
* Shows a dialog that instructs the user to select a new preferred editor.
* @param aDefaultEditor Default full path for the default editor this dialog should

View File

@ -268,7 +268,8 @@ void PCB_EDIT_FRAME::ExportToGenCAD( wxCommandEvent& aEvent )
DisplayError( this, msg ); return;
}
SetLocaleTo_C_standard(); // No pesky decimal separators in gencad
// Switch the locale to standard C (needed to print floating point numbers)
LOCALE_IO toggle;
// Update some board data, to ensure a reliable gencad export
GetBoard()->ComputeBoundingBox();
@ -323,7 +324,6 @@ void PCB_EDIT_FRAME::ExportToGenCAD( wxCommandEvent& aEvent )
CreateRoutesSection( file, pcb );
fclose( file );
SetLocaleTo_Default(); // revert to the current locale
// Undo the footprints modifications (flipped footprints)
for( module = pcb->m_Modules; module; module = module->Next() )

View File

@ -538,7 +538,8 @@ bool Export_IDF3( BOARD* aPcb, const wxString& aFullFileName, bool aUseThou,
{
IDF3_BOARD idfBoard( IDF3::CAD_ELEC );
SetLocaleTo_C_standard();
// Switch the locale to standard C (needed to print floating point numbers)
LOCALE_IO toggle;
bool ok = true;
double scale = MM_PER_IU; // we must scale internal units to mm for IDF
@ -604,7 +605,5 @@ bool Export_IDF3( BOARD* aPcb, const wxString& aFullFileName, bool aUseThou,
ok = false;
}
SetLocaleTo_Default();
return ok;
}

View File

@ -1334,8 +1334,8 @@ bool PCB_EDIT_FRAME::ExportVRML_File( const wxString& aFullFileName, double aMMt
output_file.exceptions( std::ofstream::failbit );
output_file.open( TO_UTF8( aFullFileName ), std::ios_base::out );
// Switch the locale to standard C (needed to print floating point numbers like 1.3)
SetLocaleTo_C_standard();
// Switch the locale to standard C (needed to print floating point numbers)
LOCALE_IO toggle;
// Begin with the usual VRML boilerplate
wxString fn = aFullFileName;
@ -1403,7 +1403,6 @@ bool PCB_EDIT_FRAME::ExportVRML_File( const wxString& aFullFileName, double aMMt
// End of work
output_file.exceptions( std::ios_base::goodbit );
output_file.close();
SetLocaleTo_Default(); // revert to the current locale
return ok;
}